v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
perf-jit.cc
Go to the documentation of this file.
1// Copyright 2016 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
29
31#include "src/flags/flags.h"
32
33// Only compile the {LinuxPerfJitLogger} on Linux.
34#if V8_OS_LINUX
35
36#include <fcntl.h>
37#include <sys/mman.h>
38#include <unistd.h>
39
40#include <memory>
41
50#include "src/utils/ostreams.h"
51
52#if V8_ENABLE_WEBASSEMBLY
54#endif // V8_ENABLE_WEBASSEMBLY
55
56namespace v8 {
57namespace internal {
58
59base::LazyRecursiveMutex& GetFileMutex() {
60 static base::LazyRecursiveMutex file_mutex;
61 return file_mutex;
62}
63
64struct PerfJitHeader {
65 uint32_t magic_;
66 uint32_t version_;
67 uint32_t size_;
68 uint32_t elf_mach_target_;
69 uint32_t reserved_;
70 uint32_t process_id_;
71 uint64_t time_stamp_;
72 uint64_t flags_;
73
74 static const uint32_t kMagic = 0x4A695444;
75 static const uint32_t kVersion = 1;
76};
77
78struct PerfJitBase {
79 enum PerfJitEvent {
80 kLoad = 0,
81 kMove = 1,
82 kDebugInfo = 2,
83 kClose = 3,
84 kUnwindingInfo = 4
85 };
86
87 uint32_t event_;
88 uint32_t size_;
89 uint64_t time_stamp_;
90};
91
92struct PerfJitCodeLoad : PerfJitBase {
93 uint32_t process_id_;
94 uint32_t thread_id_;
95 uint64_t vma_;
96 uint64_t code_address_;
97 uint64_t code_size_;
98 uint64_t code_id_;
99};
100
101struct PerfJitDebugEntry {
102 uint64_t address_;
103 int line_number_;
104 int column_;
105 // Followed by null-terminated name or \0xFF\0 if same as previous.
106};
107
108struct PerfJitCodeDebugInfo : PerfJitBase {
109 uint64_t address_;
110 uint64_t entry_count_;
111 // Followed by entry_count_ instances of PerfJitDebugEntry.
112};
113
114struct PerfJitCodeUnwindingInfo : PerfJitBase {
115 uint64_t unwinding_size_;
116 uint64_t eh_frame_hdr_size_;
117 uint64_t mapped_size_;
118 // Followed by size_ - sizeof(PerfJitCodeUnwindingInfo) bytes of data.
119};
120
121const char LinuxPerfJitLogger::kFilenameFormatString[] = "%s/jit-%d.dump";
122
123// Extra padding for the PID in the filename
124const int LinuxPerfJitLogger::kFilenameBufferPadding = 16;
125
126static const char kStringTerminator[] = {'\0'};
127
128// The following static variables are protected by
129// GetFileMutex().
130int LinuxPerfJitLogger::process_id_ = 0;
131uint64_t LinuxPerfJitLogger::reference_count_ = 0;
132void* LinuxPerfJitLogger::marker_address_ = nullptr;
133uint64_t LinuxPerfJitLogger::code_index_ = 0;
134FILE* LinuxPerfJitLogger::perf_output_handle_ = nullptr;
135
136void LinuxPerfJitLogger::OpenJitDumpFile() {
137 // Open the perf JIT dump file.
138 perf_output_handle_ = nullptr;
139
140 size_t bufferSize = strlen(v8_flags.perf_prof_path) +
141 sizeof(kFilenameFormatString) + kFilenameBufferPadding;
142 base::ScopedVector<char> perf_dump_name(bufferSize);
143 int size = SNPrintF(perf_dump_name, kFilenameFormatString,
144 v8_flags.perf_prof_path.value(), process_id_);
145 CHECK_NE(size, -1);
146
147 int fd = open(perf_dump_name.begin(), O_CREAT | O_TRUNC | O_RDWR, 0666);
148 if (fd == -1) return;
149
150 // If --perf-prof-delete-file is given, unlink the file right after opening
151 // it. This keeps the file handle to the file valid. This only works on Linux,
152 // which is the only platform supported for --perf-prof anyway.
153 if (v8_flags.perf_prof_delete_file)
154 CHECK_EQ(0, unlink(perf_dump_name.begin()));
155
156 marker_address_ = OpenMarkerFile(fd);
157 if (marker_address_ == nullptr) return;
158
159 perf_output_handle_ = fdopen(fd, "w+");
160 if (perf_output_handle_ == nullptr) return;
161
162 setvbuf(perf_output_handle_, nullptr, _IOFBF, kLogBufferSize);
163}
164
165void LinuxPerfJitLogger::CloseJitDumpFile() {
166 if (perf_output_handle_ == nullptr) return;
167 base::Fclose(perf_output_handle_);
168 perf_output_handle_ = nullptr;
169}
170
171void* LinuxPerfJitLogger::OpenMarkerFile(int fd) {
172 long page_size = sysconf(_SC_PAGESIZE); // NOLINT(runtime/int)
173 if (page_size == -1) return nullptr;
174
175 // Mmap the file so that there is a mmap record in the perf_data file.
176 //
177 // The map must be PROT_EXEC to ensure it is not ignored by perf record.
178 void* marker_address =
179 mmap(nullptr, page_size, PROT_READ | PROT_EXEC, MAP_PRIVATE, fd, 0);
180 return (marker_address == MAP_FAILED) ? nullptr : marker_address;
181}
182
183void LinuxPerfJitLogger::CloseMarkerFile(void* marker_address) {
184 if (marker_address == nullptr) return;
185 long page_size = sysconf(_SC_PAGESIZE); // NOLINT(runtime/int)
186 if (page_size == -1) return;
187 munmap(marker_address, page_size);
188}
189
190LinuxPerfJitLogger::LinuxPerfJitLogger(Isolate* isolate)
191 : CodeEventLogger(isolate) {
192 base::LockGuard<base::RecursiveMutex> guard_file(GetFileMutex().Pointer());
193 process_id_ = base::OS::GetCurrentProcessId();
194
195 reference_count_++;
196 // If this is the first logger, open the file and write the header.
197 if (reference_count_ == 1) {
198 OpenJitDumpFile();
199 if (perf_output_handle_ == nullptr) return;
200 LogWriteHeader();
201 }
202}
203
204LinuxPerfJitLogger::~LinuxPerfJitLogger() {
205 base::LockGuard<base::RecursiveMutex> guard_file(GetFileMutex().Pointer());
206
207 reference_count_--;
208 // If this was the last logger, close the file.
209 if (reference_count_ == 0) {
210 CloseJitDumpFile();
211 }
212}
213
214uint64_t LinuxPerfJitLogger::GetTimestamp() {
215 struct timespec ts;
216 int result = clock_gettime(CLOCK_MONOTONIC, &ts);
217 DCHECK_EQ(0, result);
218 USE(result);
219 static const uint64_t kNsecPerSec = 1000000000;
220 return (ts.tv_sec * kNsecPerSec) + ts.tv_nsec;
221}
222
223void LinuxPerfJitLogger::LogRecordedBuffer(
224 Tagged<AbstractCode> abstract_code,
225 MaybeDirectHandle<SharedFunctionInfo> maybe_sfi, const char* name,
226 size_t length) {
228 if (v8_flags.perf_basic_prof_only_functions) {
229 CodeKind code_kind = abstract_code->kind(isolate_);
230 if (!CodeKindIsJSFunction(code_kind)) {
231 return;
232 }
233 }
234
235 base::LockGuard<base::RecursiveMutex> guard_file(GetFileMutex().Pointer());
236
237 if (perf_output_handle_ == nullptr) return;
238
239 // We only support non-interpreted functions.
240 if (!IsCode(abstract_code, isolate_)) return;
241 Tagged<Code> code = Cast<Code>(abstract_code);
242
243 // Debug info has to be emitted first.
244 DirectHandle<SharedFunctionInfo> sfi;
245 if (v8_flags.perf_prof && maybe_sfi.ToHandle(&sfi)) {
246 // TODO(herhut): This currently breaks for js2wasm/wasm2js functions.
247 CodeKind kind = code->kind();
248 if (kind != CodeKind::JS_TO_WASM_FUNCTION &&
249 kind != CodeKind::WASM_TO_JS_FUNCTION) {
250 DCHECK_IMPLIES(IsScript(sfi->script()),
251 Cast<Script>(sfi->script())->has_line_ends());
252 LogWriteDebugInfo(code, sfi);
253 }
254 }
255
256 const char* code_name = name;
257 uint8_t* code_pointer = reinterpret_cast<uint8_t*>(code->instruction_start());
258
259 // Unwinding info comes right after debug info.
260 if (v8_flags.perf_prof_unwinding_info) LogWriteUnwindingInfo(code);
261
262 WriteJitCodeLoadEntry(code_pointer, code->instruction_size(), code_name,
263 length);
264}
265
266#if V8_ENABLE_WEBASSEMBLY
267void LinuxPerfJitLogger::LogRecordedBuffer(const wasm::WasmCode* code,
268 const char* name, size_t length) {
269 base::LockGuard<base::RecursiveMutex> guard_file(GetFileMutex().Pointer());
270
271 if (perf_output_handle_ == nullptr) return;
272
273 if (v8_flags.perf_prof_annotate_wasm) LogWriteDebugInfo(code);
274
275 WriteJitCodeLoadEntry(code->instructions().begin(),
276 code->instructions().length(), name, length);
277}
278#endif // V8_ENABLE_WEBASSEMBLY
279
280void LinuxPerfJitLogger::WriteJitCodeLoadEntry(const uint8_t* code_pointer,
281 uint32_t code_size,
282 const char* name,
283 size_t name_length) {
284 PerfJitCodeLoad code_load;
285 code_load.event_ = PerfJitCodeLoad::kLoad;
286 code_load.size_ =
287 static_cast<uint32_t>(sizeof(code_load) + name_length + 1 + code_size);
288 code_load.time_stamp_ = GetTimestamp();
289 code_load.process_id_ = static_cast<uint32_t>(process_id_);
290 code_load.thread_id_ = static_cast<uint32_t>(base::OS::GetCurrentThreadId());
291 code_load.vma_ = reinterpret_cast<uint64_t>(code_pointer);
292 code_load.code_address_ = reinterpret_cast<uint64_t>(code_pointer);
293 code_load.code_size_ = code_size;
294 code_load.code_id_ = code_index_;
295
296 code_index_++;
297
298 LogWriteBytes(reinterpret_cast<const char*>(&code_load), sizeof(code_load));
299 LogWriteBytes(name, name_length);
300 LogWriteBytes(kStringTerminator, sizeof(kStringTerminator));
301 LogWriteBytes(reinterpret_cast<const char*>(code_pointer), code_size);
302}
303
304namespace {
305
306constexpr char kUnknownScriptNameString[] = "<unknown>";
307constexpr size_t kUnknownScriptNameStringLen =
308 arraysize(kUnknownScriptNameString) - 1;
309
310namespace {
311base::Vector<const char> GetScriptName(Tagged<Object> maybeScript,
312 std::unique_ptr<char[]>* storage,
313 const DisallowGarbageCollection& no_gc) {
314 if (IsScript(maybeScript)) {
315 Tagged<Object> name_or_url =
316 Cast<Script>(maybeScript)->GetNameOrSourceURL();
317 if (IsSeqOneByteString(name_or_url)) {
318 Tagged<SeqOneByteString> str = Cast<SeqOneByteString>(name_or_url);
319 return {reinterpret_cast<char*>(str->GetChars(no_gc)),
320 static_cast<size_t>(str->length())};
321 } else if (IsString(name_or_url)) {
322 size_t length;
323 *storage = Cast<String>(name_or_url)->ToCString(&length);
324 return {storage->get(), length};
325 }
326 }
327 return {kUnknownScriptNameString, kUnknownScriptNameStringLen};
328}
329
330} // namespace
331
332SourcePositionInfo GetSourcePositionInfo(
333 Isolate* isolate, Tagged<Code> code,
334 DirectHandle<SharedFunctionInfo> function, SourcePosition pos) {
336 if (code->is_turbofanned()) {
337 return pos.FirstInfo(isolate, code);
338 } else {
339 return SourcePositionInfo(isolate, pos, function);
340 }
341}
342
343} // namespace
344
345void LinuxPerfJitLogger::LogWriteDebugInfo(
346 Tagged<Code> code, DirectHandle<SharedFunctionInfo> shared) {
347 // Line ends of all scripts have been initialized prior to this.
349 // The WasmToJS wrapper stubs have source position entries.
350 Tagged<SharedFunctionInfo> raw_shared = *shared;
351 if (!raw_shared->HasSourceCode()) return;
352
353 PerfJitCodeDebugInfo debug_info;
354 uint32_t size = sizeof(debug_info);
355
356 Tagged<TrustedByteArray> source_position_table =
357 code->SourcePositionTable(isolate_, raw_shared);
358 // Compute the entry count and get the names of all scripts.
359 // Avoid additional work if the script name is repeated. Multiple script
360 // names only occur for cross-script inlining.
361 uint32_t entry_count = 0;
362 Tagged<Object> last_script = Smi::zero();
363 size_t last_script_name_size = 0;
364 std::vector<base::Vector<const char>> script_names;
365 for (SourcePositionTableIterator iterator(source_position_table);
366 !iterator.done(); iterator.Advance()) {
367 SourcePositionInfo info(GetSourcePositionInfo(isolate_, code, shared,
368 iterator.source_position()));
369 Tagged<Object> current_script = *info.script;
370 if (current_script != last_script) {
371 std::unique_ptr<char[]> name_storage;
372 auto name = GetScriptName(raw_shared->script(), &name_storage, no_gc);
373 script_names.push_back(name);
374 // Add the size of the name after each entry.
375 last_script_name_size = name.size() + sizeof(kStringTerminator);
376 size += last_script_name_size;
377 last_script = current_script;
378 } else {
379 DCHECK_LT(0, last_script_name_size);
380 size += last_script_name_size;
381 }
382 entry_count++;
383 }
384 if (entry_count == 0) return;
385
386 debug_info.event_ = PerfJitCodeLoad::kDebugInfo;
387 debug_info.time_stamp_ = GetTimestamp();
388 debug_info.address_ = code->instruction_start();
389 debug_info.entry_count_ = entry_count;
390
391 // Add the sizes of fixed parts of entries.
392 size += entry_count * sizeof(PerfJitDebugEntry);
393
394 int padding = ((size + 7) & (~7)) - size;
395 debug_info.size_ = size + padding;
396 LogWriteBytes(reinterpret_cast<const char*>(&debug_info), sizeof(debug_info));
397
398 Address code_start = code->instruction_start();
399
400 last_script = Smi::zero();
401 int script_names_index = 0;
402 for (SourcePositionTableIterator iterator(source_position_table);
403 !iterator.done(); iterator.Advance()) {
404 SourcePositionInfo info(GetSourcePositionInfo(isolate_, code, shared,
405 iterator.source_position()));
406 PerfJitDebugEntry entry;
407 // The entry point of the function will be placed straight after the ELF
408 // header when processed by "perf inject". Adjust the position addresses
409 // accordingly.
410 entry.address_ = code_start + iterator.code_offset() + kElfHeaderSize;
411 entry.line_number_ = info.line + 1;
412 entry.column_ = info.column + 1;
413 LogWriteBytes(reinterpret_cast<const char*>(&entry), sizeof(entry));
414 Tagged<Object> current_script = *info.script;
415 auto name_string = script_names[script_names_index];
416 LogWriteBytes(name_string.begin(), name_string.size());
417 LogWriteBytes(kStringTerminator, sizeof(kStringTerminator));
418 if (current_script != last_script) {
419 if (last_script != Smi::zero()) script_names_index++;
420 last_script = current_script;
421 }
422 }
423 char padding_bytes[8] = {0};
424 LogWriteBytes(padding_bytes, padding);
425}
426
427#if V8_ENABLE_WEBASSEMBLY
428void LinuxPerfJitLogger::LogWriteDebugInfo(const wasm::WasmCode* code) {
429 if (code->IsAnonymous()) {
430 return;
431 }
432
433 wasm::WasmModuleSourceMap* source_map =
434 code->native_module()->GetWasmSourceMap();
435 wasm::WireBytesRef code_ref =
436 code->native_module()->module()->functions[code->index()].code;
437 uint32_t code_offset = code_ref.offset();
438 uint32_t code_end_offset = code_ref.end_offset();
439
440 uint32_t entry_count = 0;
441 uint32_t size = 0;
442
443 if (!source_map || !source_map->IsValid() ||
444 !source_map->HasSource(code_offset, code_end_offset)) {
445 return;
446 }
447
448 for (SourcePositionTableIterator iterator(code->source_positions());
449 !iterator.done(); iterator.Advance()) {
450 uint32_t offset = iterator.source_position().ScriptOffset() + code_offset;
451 if (!source_map->HasValidEntry(code_offset, offset)) continue;
452 entry_count++;
453 size += source_map->GetFilename(offset).size() + 1;
454 }
455
456 if (entry_count == 0) return;
457
458 PerfJitCodeDebugInfo debug_info;
459
460 debug_info.event_ = PerfJitCodeLoad::kDebugInfo;
461 debug_info.time_stamp_ = GetTimestamp();
462 debug_info.address_ =
463 reinterpret_cast<uintptr_t>(code->instructions().begin());
464 debug_info.entry_count_ = entry_count;
465
466 size += sizeof(debug_info);
467 // Add the sizes of fixed parts of entries.
468 size += entry_count * sizeof(PerfJitDebugEntry);
469
470 int padding = ((size + 7) & (~7)) - size;
471 debug_info.size_ = size + padding;
472 LogWriteBytes(reinterpret_cast<const char*>(&debug_info), sizeof(debug_info));
473
474 uintptr_t code_begin =
475 reinterpret_cast<uintptr_t>(code->instructions().begin());
476
477 for (SourcePositionTableIterator iterator(code->source_positions());
478 !iterator.done(); iterator.Advance()) {
479 uint32_t offset = iterator.source_position().ScriptOffset() + code_offset;
480 if (!source_map->HasValidEntry(code_offset, offset)) continue;
481 PerfJitDebugEntry entry;
482 // The entry point of the function will be placed straight after the ELF
483 // header when processed by "perf inject". Adjust the position addresses
484 // accordingly.
485 entry.address_ = code_begin + iterator.code_offset() + kElfHeaderSize;
486 entry.line_number_ =
487 static_cast<int>(source_map->GetSourceLine(offset)) + 1;
488 entry.column_ = 1;
489 LogWriteBytes(reinterpret_cast<const char*>(&entry), sizeof(entry));
490 std::string name_string = source_map->GetFilename(offset);
491 LogWriteBytes(name_string.c_str(), name_string.size());
492 LogWriteBytes(kStringTerminator, sizeof(kStringTerminator));
493 }
494
495 char padding_bytes[8] = {0};
496 LogWriteBytes(padding_bytes, padding);
497}
498#endif // V8_ENABLE_WEBASSEMBLY
499
500void LinuxPerfJitLogger::LogWriteUnwindingInfo(Tagged<Code> code) {
501 PerfJitCodeUnwindingInfo unwinding_info_header;
502 unwinding_info_header.event_ = PerfJitCodeLoad::kUnwindingInfo;
503 unwinding_info_header.time_stamp_ = GetTimestamp();
504 unwinding_info_header.eh_frame_hdr_size_ = EhFrameConstants::kEhFrameHdrSize;
505
506 if (code->has_unwinding_info()) {
507 unwinding_info_header.unwinding_size_ = code->unwinding_info_size();
508 unwinding_info_header.mapped_size_ = unwinding_info_header.unwinding_size_;
509 } else {
510 unwinding_info_header.unwinding_size_ = EhFrameConstants::kEhFrameHdrSize;
511 unwinding_info_header.mapped_size_ = 0;
512 }
513
514 int content_size = static_cast<int>(sizeof(unwinding_info_header) +
515 unwinding_info_header.unwinding_size_);
516 int padding_size = RoundUp(content_size, 8) - content_size;
517 unwinding_info_header.size_ = content_size + padding_size;
518
519 LogWriteBytes(reinterpret_cast<const char*>(&unwinding_info_header),
520 sizeof(unwinding_info_header));
521
522 if (code->has_unwinding_info()) {
523 LogWriteBytes(reinterpret_cast<const char*>(code->unwinding_info_start()),
524 code->unwinding_info_size());
525 } else {
526 OFStream perf_output_stream(perf_output_handle_);
527 EhFrameWriter::WriteEmptyEhFrame(perf_output_stream);
528 }
529
530 char padding_bytes[] = "\0\0\0\0\0\0\0\0";
531 DCHECK_LT(padding_size, static_cast<int>(sizeof(padding_bytes)));
532 LogWriteBytes(padding_bytes, padding_size);
533}
534
535void LinuxPerfJitLogger::LogWriteBytes(const char* bytes, size_t size) {
536 size_t rv = fwrite(bytes, 1, size, perf_output_handle_);
537 DCHECK_EQ(size, rv);
538 USE(rv);
539}
540
541void LinuxPerfJitLogger::LogWriteHeader() {
542 DCHECK_NOT_NULL(perf_output_handle_);
543 PerfJitHeader header;
544
545 header.magic_ = PerfJitHeader::kMagic;
546 header.version_ = PerfJitHeader::kVersion;
547 header.size_ = sizeof(header);
548 header.elf_mach_target_ = GetElfMach();
549 header.reserved_ = 0xDEADBEEF;
550 header.process_id_ = process_id_;
551 header.time_stamp_ = static_cast<uint64_t>(
552 V8::GetCurrentPlatform()->CurrentClockTimeMillisecondsHighResolution() *
553 base::Time::kMicrosecondsPerMillisecond);
554 header.flags_ = 0;
555
556 LogWriteBytes(reinterpret_cast<const char*>(&header), sizeof(header));
557}
558
559} // namespace internal
560} // namespace v8
561
562#endif // V8_OS_LINUX
Isolate * isolate_
const char * name
Definition builtins.cc:39
Builtins::Kind kind
Definition builtins.cc:40
SourcePosition pos
const int size_
Definition assembler.cc:132
JSRegExp::Flags flags_
Handle< SharedFunctionInfo > info
int32_t offset
SharedFunctionInfoRef shared
ZoneVector< RpoNumber > & result
LazyStaticInstance< RecursiveMutex, DefaultConstructTrait< RecursiveMutex >, ThreadSafeInitOnceTrait >::type LazyRecursiveMutex
Definition mutex.h:176
int SNPrintF(Vector< char > str, const char *format,...)
Definition strings.cc:20
int Fclose(FILE *stream)
Definition wrappers.h:22
uintptr_t Address
Definition memory.h:13
Node::Uses::const_iterator begin(const Node::Uses &uses)
Definition node.h:708
PerThreadAssertScopeDebugOnly< false, SAFEPOINTS_ASSERT, HEAP_ALLOCATION_ASSERT > DisallowGarbageCollection
V8_EXPORT_PRIVATE FlagValues v8_flags
constexpr bool CodeKindIsJSFunction(CodeKind kind)
Definition code-kind.h:72
refactor address components for immediate indexing make OptimizeMaglevOnNextCall optimize to turbofan instead of maglev filter for tracing turbofan compilation nullptr
Definition flags.cc:1263
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define CHECK_NE(lhs, rhs)
#define CHECK_EQ(lhs, rhs)
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define USE(...)
Definition macros.h:293
constexpr T RoundUp(T x, intptr_t m)
Definition macros.h:387
#define arraysize(array)
Definition macros.h:67