Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
disassembler.cc
Go to the documentation of this file.
1// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
6
9#include "vm/code_comments.h"
10#include "vm/code_patcher.h"
11#include "vm/dart_entry.h"
13#include "vm/globals.h"
14#include "vm/instructions.h"
15#include "vm/json_stream.h"
16#include "vm/log.h"
17#include "vm/os.h"
18
19namespace dart {
20
21#if !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
22
23#if !defined(DART_PRECOMPILED_RUNTIME)
24DECLARE_FLAG(bool, trace_inlining_intervals);
25#endif
26
27DEFINE_FLAG(bool, trace_source_positions, false, "Source position diagnostics");
29 include_inlining_info_in_disassembly,
30 true,
31 "Include inlining information when printing disassembly")
32
33void DisassembleToStdout::ConsumeInstruction(char* hex_buffer,
34 intptr_t hex_size,
35 char* human_buffer,
36 intptr_t human_size,
37 Object* object,
38 uword pc) {
39 const int kHexColumnWidth = 23;
40#if defined(TARGET_ARCH_IS_32_BIT)
41 THR_Print("0x%" Px32 " %s", static_cast<uint32_t>(pc), hex_buffer);
42#else
43 THR_Print("0x%" Px64 " %s", static_cast<uint64_t>(pc), hex_buffer);
44#endif
45 int hex_length = strlen(hex_buffer);
46 if (hex_length < kHexColumnWidth) {
47 for (int i = kHexColumnWidth - hex_length; i > 0; i--) {
48 THR_Print(" ");
49 }
50 }
51 THR_Print("%s", human_buffer);
52 if (object != nullptr) {
53 THR_Print(" %s", object->ToCString());
54 }
55 THR_Print("\n");
56}
57
58void DisassembleToStdout::Print(const char* format, ...) {
59 va_list args;
60 va_start(args, format);
62 va_end(args);
63}
64
66 intptr_t hex_size,
67 char* human_buffer,
68 intptr_t human_size,
69 Object* object,
70 uword pc) {
71 if (overflowed_) {
72 return;
73 }
74 intptr_t len;
75
76 // TODO(compiler): Update assembler tests for other architectures so there is
77 // coverage of encodings, not just mnemonics.
78#if defined(TARGET_ARCH_RISCV32) || defined(TARGET_ARCH_RISCV64) || \
79 defined(TARGET_ARCH_ARM)
80 len = strlen(hex_buffer);
81 if (remaining_ < len + 100) {
82 *buffer_++ = '.';
83 *buffer_++ = '.';
84 *buffer_++ = '.';
85 *buffer_++ = '\n';
86 *buffer_++ = '\0';
87 overflowed_ = true;
88 return;
89 }
90 memmove(buffer_, hex_buffer, len);
91 buffer_ += len;
92 remaining_ -= len;
93 *buffer_++ = ' ';
94 remaining_--;
95 *buffer_ = '\0';
96#endif
97
98 len = strlen(human_buffer);
99 if (remaining_ < len + 100) {
100 *buffer_++ = '.';
101 *buffer_++ = '.';
102 *buffer_++ = '.';
103 *buffer_++ = '\n';
104 *buffer_++ = '\0';
105 overflowed_ = true;
106 return;
107 }
108 memmove(buffer_, human_buffer, len);
109 buffer_ += len;
110 remaining_ -= len;
111 *buffer_++ = '\n';
112 remaining_--;
113 *buffer_ = '\0';
114}
115
116void DisassembleToMemory::Print(const char* format, ...) {
117 if (overflowed_) {
118 return;
119 }
120 va_list measure_args;
121 va_start(measure_args, format);
122 intptr_t len = Utils::VSNPrint(nullptr, 0, format, measure_args);
123 va_end(measure_args);
124 if (remaining_ < len + 100) {
125 *buffer_++ = '.';
126 *buffer_++ = '.';
127 *buffer_++ = '.';
128 *buffer_++ = '\n';
129 *buffer_++ = '\0';
130 overflowed_ = true;
131 return;
132 }
133 va_list print_args;
134 va_start(print_args, format);
135 intptr_t len2 = Utils::VSNPrint(buffer_, len, format, print_args);
136 va_end(print_args);
137 ASSERT(len == len2);
138 buffer_ += len;
139 remaining_ -= len;
140 *buffer_++ = '\n';
141 remaining_--;
142 *buffer_ = '\0';
143}
144
146 uword end,
147 DisassemblyFormatter* formatter,
148 const Code& code,
149 const CodeComments* comments) {
150 if (comments == nullptr) {
151 comments = code.IsNull() ? &Code::Comments::New(0) : &code.comments();
152 }
153 ASSERT(formatter != nullptr);
154 char hex_buffer[kHexadecimalBufferSize]; // Instruction in hexadecimal form.
155 char human_buffer[kUserReadableBufferSize]; // Human-readable instruction.
156 uword pc = start;
157 intptr_t comment_finger = 0;
158 GrowableArray<const Function*> inlined_functions;
159 GrowableArray<TokenPosition> token_positions;
160 while (pc < end) {
161 const intptr_t offset = pc - start;
162 const intptr_t old_comment_finger = comment_finger;
163 while (comment_finger < comments->Length() &&
164 comments->PCOffsetAt(comment_finger) <= offset) {
165 formatter->Print(" ;; %s\n", comments->CommentAt(comment_finger));
166 comment_finger++;
167 }
168 if (FLAG_include_inlining_info_in_disassembly &&
169 old_comment_finger != comment_finger && !code.IsNull()) {
170 char str[4000];
171 BufferFormatter f(str, sizeof(str));
172 // Comment emitted, emit inlining information.
173 code.GetInlinedFunctionsAtInstruction(offset, &inlined_functions,
174 &token_positions);
175 // Skip top scope function printing (last entry in 'inlined_functions').
176 bool first = true;
177 for (intptr_t i = 1; i < inlined_functions.length(); i++) {
178 const char* name = inlined_functions[i]->ToQualifiedCString();
179 if (first) {
180 f.Printf(" ;; Inlined [%s", name);
181 first = false;
182 } else {
183 f.Printf(" -> %s", name);
184 }
185 }
186 if (!first) {
187 f.AddString("]\n");
188 formatter->Print("%s", str);
189 }
190 }
191 int instruction_length;
192 Object* object;
193 DecodeInstruction(hex_buffer, sizeof(hex_buffer), human_buffer,
194 sizeof(human_buffer), &instruction_length, code, &object,
195 pc);
196 formatter->ConsumeInstruction(hex_buffer, sizeof(hex_buffer), human_buffer,
197 sizeof(human_buffer), object,
198 FLAG_disassemble_relative ? offset : pc);
199 pc += instruction_length;
200 }
201}
202
203void Disassembler::DisassembleCodeHelper(const char* function_fullname,
204 const char* function_info,
205 const Code& code,
206 bool optimized) {
207 Thread* thread = Thread::Current();
208 Zone* zone = thread->zone();
209 THR_Print("Code for %sfunction '%s' (%s) {\n", optimized ? "optimized " : "",
210 function_fullname, function_info);
211 code.Disassemble();
212 THR_Print("}\n");
213
214#if defined(TARGET_ARCH_IA32)
215 if (code.pointer_offsets_length() > 0) {
216 THR_Print("Pointer offsets for function: {\n");
217 // Pointer offsets are stored in descending order.
218 Object& obj = Object::Handle(zone);
219 for (intptr_t i = code.pointer_offsets_length() - 1; i >= 0; i--) {
220 const uword addr = code.GetPointerOffsetAt(i) + code.PayloadStart();
221 obj = LoadUnaligned(reinterpret_cast<ObjectPtr*>(addr));
222 THR_Print(" %d : %#" Px " '%s'\n", code.GetPointerOffsetAt(i), addr,
223 obj.ToCString());
224 }
225 THR_Print("}\n");
226 }
227#else
228 ASSERT(code.pointer_offsets_length() == 0);
229#endif
230
231 if (FLAG_precompiled_mode) {
232 // Global object pool emitted after it is finalized instead of per-function.
233 } else {
234 const ObjectPool& object_pool =
235 ObjectPool::Handle(zone, code.GetObjectPool());
236 if (!object_pool.IsNull() && object_pool.Length() > 0) {
237 object_pool.DebugPrint();
238 }
239 }
240
241 code.DumpSourcePositions(/*relative_addresses=*/FLAG_disassemble_relative);
242
243 const uword start = code.PayloadStart();
244 const uword base = FLAG_disassemble_relative ? 0 : start;
245
246 const PcDescriptors& descriptors =
247 PcDescriptors::Handle(zone, code.pc_descriptors());
248 if (descriptors.Length() > 0) {
249 TextBuffer buffer(100);
250 buffer.Printf("PC Descriptors for function '%s' {\n", function_fullname);
251 descriptors.WriteToBuffer(&buffer, base);
252 buffer.AddString("}\n");
253 THR_Print("%s", buffer.buffer());
254 }
255
256#if !defined(DART_PRECOMPILED_RUNTIME)
257 const Array& deopt_table = Array::Handle(zone, code.deopt_info_array());
258 if (!deopt_table.IsNull()) {
259 intptr_t deopt_table_length = DeoptTable::GetLength(deopt_table);
260 if (deopt_table_length > 0) {
261 THR_Print("DeoptInfo: {\n");
262 Smi& offset = Smi::Handle(zone);
263 TypedData& info = TypedData::Handle(zone);
264 Smi& reason_and_flags = Smi::Handle(zone);
265 for (intptr_t i = 0; i < deopt_table_length; ++i) {
266 DeoptTable::GetEntry(deopt_table, i, &offset, &info, &reason_and_flags);
267 const intptr_t reason =
268 DeoptTable::ReasonField::decode(reason_and_flags.Value());
269 ASSERT((0 <= reason) && (reason < ICData::kDeoptNumReasons));
270 THR_Print(
271 "%4" Pd ": 0x%" Px " %s (%s)\n", i, base + offset.Value(),
272 DeoptInfo::ToCString(deopt_table, info),
273 DeoptReasonToCString(static_cast<ICData::DeoptReasonId>(reason)));
274 }
275 THR_Print("}\n");
276 }
277 }
278#endif // !defined(DART_PRECOMPILED_RUNTIME)
279
280 const auto& stackmaps =
281 CompressedStackMaps::Handle(zone, code.compressed_stackmaps());
282 if (!stackmaps.IsNull() && stackmaps.payload_size() > 0) {
283 TextBuffer buffer(100);
284 buffer.Printf("StackMaps for function '%s' {\n", function_fullname);
285 stackmaps.WriteToBuffer(&buffer, base, "\n");
286 buffer.AddString("\n}\n");
287 THR_Print("%s", buffer.buffer());
288 }
289
290 LocalVarDescriptors& var_descriptors = LocalVarDescriptors::Handle(zone);
291 if (FLAG_print_variable_descriptors) {
292 var_descriptors = code.GetLocalVarDescriptors();
293 }
294 const intptr_t var_desc_length =
295 var_descriptors.IsNull() ? 0 : var_descriptors.Length();
296 if (var_desc_length > 0) {
297 THR_Print("Variable Descriptors for function '%s' {\n", function_fullname);
298 String& var_name = String::Handle(zone);
299 for (intptr_t i = 0; i < var_desc_length; i++) {
300 var_name = var_descriptors.GetName(i);
301 UntaggedLocalVarDescriptors::VarInfo var_info;
302 var_descriptors.GetInfo(i, &var_info);
303 const int8_t kind = var_info.kind();
305 THR_Print(" saved current CTX reg offset %d\n", var_info.index());
306 } else {
308 THR_Print(" context level %d scope %d", var_info.index(),
309 var_info.scope_id);
310 } else if (kind == UntaggedLocalVarDescriptors::kStackVar) {
311 THR_Print(" stack var '%s' offset %d", var_name.ToCString(),
312 var_info.index());
313 } else {
315 THR_Print(" context var '%s' level %d offset %d",
316 var_name.ToCString(), var_info.scope_id, var_info.index());
317 }
318 THR_Print(" (valid %s-%s)\n", var_info.begin_pos.ToCString(),
319 var_info.end_pos.ToCString());
320 }
321 }
322 THR_Print("}\n");
323 }
324
325 const ExceptionHandlers& handlers =
326 ExceptionHandlers::Handle(zone, code.exception_handlers());
327 if (handlers.num_entries() > 0 || handlers.has_async_handler()) {
328 TextBuffer buffer(100);
329 buffer.Printf("Exception Handlers for function '%s' {\n",
330 function_fullname);
331 handlers.WriteToBuffer(&buffer, base);
332 buffer.AddString("}\n");
333 THR_Print("%s", buffer.buffer());
334 }
335
336#if defined(DART_PRECOMPILED_RUNTIME) || defined(DART_PRECOMPILER)
337 if (FLAG_precompiled_mode &&
338 code.catch_entry_moves_maps() != Object::null()) {
339 THR_Print("Catch entry moves for function '%s' {\n", function_fullname);
340 CatchEntryMovesMapReader reader(
341 TypedData::Handle(code.catch_entry_moves_maps()));
342 reader.PrintEntries();
343 THR_Print("}\n");
344 }
345#endif // defined(DART_PRECOMPILED_RUNTIME) || defined(DART_PRECOMPILER)
346
347 {
348 THR_Print("Entry points for function '%s' {\n", function_fullname);
349 THR_Print(" [code+0x%02" Px "] %" Px " kNormal\n",
351 code.EntryPoint() - start + base);
352 THR_Print(
353 " [code+0x%02" Px "] %" Px " kMonomorphic\n",
355 code.MonomorphicEntryPoint() - start + base);
356 THR_Print(
357 " [code+0x%02" Px "] %" Px " kUnchecked\n",
359 code.UncheckedEntryPoint() - start + base);
360 THR_Print(" [code+0x%02" Px "] %" Px " kMonomorphicUnchecked\n",
363 code.MonomorphicUncheckedEntryPoint() - start + base);
364 THR_Print("}\n");
365 }
366
367#if defined(DART_PRECOMPILED_RUNTIME)
368 THR_Print("(Cannot show static call target functions in AOT runtime.)\n");
369#else
370 const auto& table = Array::Handle(zone, code.static_calls_target_table());
371 if (!table.IsNull()) {
372 StaticCallsTable static_calls(table);
373 if (static_calls.Length() > 0) {
374 THR_Print("Static call target functions {\n");
375 auto& cls = Class::Handle(zone);
376 auto& kind_type_and_offset = Smi::Handle(zone);
377 auto& function = Function::Handle(zone);
378 auto& object = Object::Handle(zone);
379 auto& code = Code::Handle(zone);
380 auto& dst_type = AbstractType::Handle(zone);
381 for (auto& call : static_calls) {
382 kind_type_and_offset = call.Get<Code::kSCallTableKindAndOffset>();
385
386 dst_type = AbstractType::null();
387 if (object.IsAbstractType()) {
388 dst_type = AbstractType::Cast(object).ptr();
389 } else if (object.IsCode()) {
390 code = Code::Cast(object).ptr();
391 }
392
393 auto kind = Code::KindField::decode(kind_type_and_offset.Value());
394 auto offset = Code::OffsetField::decode(kind_type_and_offset.Value());
395 auto entry_point =
396 Code::EntryPointField::decode(kind_type_and_offset.Value());
397
398 const char* s_entry_point =
399 entry_point == Code::kUncheckedEntry ? " <unchecked-entry>" : "";
400 const char* skind = nullptr;
401 switch (kind) {
403 skind = "pc-relative-call";
404 break;
406 skind = "pc-relative-tts-call";
407 break;
409 skind = "pc-relative-tail-call";
410 break;
412 skind = "call-via-code";
413 break;
414 default:
415 UNREACHABLE();
416 }
417 if (!dst_type.IsNull()) {
418 THR_Print(" 0x%" Px ": type testing stub %s, (%s)%s\n",
419 base + offset, dst_type.ToCString(), skind, s_entry_point);
420 } else if (function.IsNull()) {
421 cls ^= code.owner();
422 if (cls.IsNull()) {
423 THR_Print(
424 " 0x%" Px ": %s, (%s)%s\n", base + offset,
425 code.QualifiedName(NameFormattingParams(
427 skind, s_entry_point);
428 } else {
429 THR_Print(" 0x%" Px ": allocation stub for %s, (%s)%s\n",
430 base + offset, cls.ToCString(), skind, s_entry_point);
431 }
432 } else {
433 THR_Print(" 0x%" Px ": %s, (%s)%s\n", base + offset,
434 function.ToFullyQualifiedCString(), skind, s_entry_point);
435 }
436 }
437 THR_Print("}\n");
438 }
439 }
440#endif // defined(DART_PRECOMPILED_RUNTIME)
441
442#if !defined(DART_PRECOMPILED_RUNTIME)
443 if (optimized && FLAG_trace_inlining_intervals) {
444 code.DumpInlineIntervals();
445 }
446#endif
447
448 if (FLAG_trace_source_positions) {
449 code.DumpSourcePositions();
450 }
451}
452
454 const Code& code,
455 bool optimized) {
456 if (code.IsUnknownDartCode()) {
457 return;
458 }
459 if (Log::Current() == Log::NoOpLog()) {
460 // Output for this isolate will be shallowed, so don't bother generating it.
461 return;
462 }
463 TextBuffer buffer(128);
464 const char* function_fullname = function.ToFullyQualifiedCString();
465 buffer.Printf("%s", Function::KindToCString(function.kind()));
466 if (function.HasSavedArgumentsDescriptor()) {
467 const auto& args_desc_array = Array::Handle(function.saved_args_desc());
468 const ArgumentsDescriptor args_desc(args_desc_array);
469 buffer.AddString(", ");
470 args_desc.PrintTo(&buffer);
471 }
472 LogBlock lb;
473 DisassembleCodeHelper(function_fullname, buffer.buffer(), code, optimized);
474}
475
476void Disassembler::DisassembleStub(const char* name, const Code& code) {
477 if (Log::Current() == Log::NoOpLog()) {
478 // Output for this isolate will be shallowed, so don't bother generating it.
479 return;
480 }
481 LogBlock lb;
482 THR_Print("Code for stub '%s': {\n", name);
483 DisassembleToStdout formatter;
484 code.Disassemble(&formatter);
485 THR_Print("}\n");
486 const ObjectPool& object_pool = ObjectPool::Handle(code.object_pool());
487 if (FLAG_precompiled_mode) {
488 THR_Print("(No object pool for bare instructions.)\n");
489 } else if (!object_pool.IsNull() && object_pool.Length() > 0) {
490 object_pool.DebugPrint();
491 }
492}
493
494#else // !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
495
497 const Code& code,
498 bool optimized) {}
499#endif // !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
500
501#if !defined(PRODUCT)
503 intptr_t hex_size,
504 char* human_buffer,
505 intptr_t human_size,
506 Object* object,
507 uword pc) {
508 // Instructions are represented as four consecutive values in a JSON array.
509 // The first is the address of the instruction, the second is the hex string,
510 // of the code, and the third is a human readable string, and the fourth is
511 // the object loaded by the instruction.
512 jsarr_.AddValueF("%" Pp "", pc);
513 jsarr_.AddValue(hex_buffer);
514 jsarr_.AddValue(human_buffer);
515
516 if (object != nullptr) {
517 jsarr_.AddValue(*object);
518 } else {
519 jsarr_.AddValueNull(); // Not a reference to null.
520 }
521}
522
524 va_list measure_args;
525 va_start(measure_args, format);
526 intptr_t len = Utils::VSNPrint(nullptr, 0, format, measure_args);
527 va_end(measure_args);
528
529 char* p = reinterpret_cast<char*>(malloc(len + 1));
530 va_list print_args;
531 va_start(print_args, format);
532 intptr_t len2 = Utils::VSNPrint(p, len, format, print_args);
533 va_end(print_args);
534 ASSERT(len == len2);
535 for (intptr_t i = 0; i < len; i++) {
536 if (p[i] == '\n' || p[i] == '\r') {
537 p[i] = ' ';
538 }
539 }
540 // Instructions are represented as four consecutive values in a JSON array.
541 // Comments only use the third slot. See above comment for more information.
542 jsarr_.AddValueNull();
543 jsarr_.AddValueNull();
544 jsarr_.AddValue(p);
545 jsarr_.AddValueNull();
546 free(p);
547}
548#endif // !defined(PRODUCT)
549
550} // namespace dart
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
SI F table(const skcms_Curve *curve, F v)
#define UNREACHABLE()
Definition assert.h:248
void PrintTo(BaseTextBuffer *buffer, bool show_named_positions=false) const
intptr_t length() const
static constexpr ICData::DeoptReasonId decode(intptr_t value)
Definition bitfield.h:173
@ kPcRelativeCall
Definition object.h:6942
@ kPcRelativeTTSCall
Definition object.h:6943
@ kCallViaCode
Definition object.h:6945
@ kPcRelativeTailCall
Definition object.h:6944
static intptr_t entry_point_offset(EntryKind kind=EntryKind::kNormal)
Definition object.h:6766
@ kSCallTableFunctionTarget
Definition object.h:6956
@ kSCallTableCodeOrTypeTarget
Definition object.h:6955
@ kSCallTableKindAndOffset
Definition object.h:6954
@ kUncheckedEntry
Definition object.h:6950
static const char * ToCString(const Array &table, const TypedData &packed)
static void GetEntry(const Array &table, intptr_t index, Smi *offset, TypedData *info, Smi *reason_and_flags)
static intptr_t GetLength(const Array &table)
virtual void ConsumeInstruction(char *hex_buffer, intptr_t hex_size, char *human_buffer, intptr_t human_size, Object *object, uword pc)
virtual void Print(const char *format,...) PRINTF_ATTRIBUTE(2
virtual void ConsumeInstruction(char *hex_buffer, intptr_t hex_size, char *human_buffer, intptr_t human_size, Object *object, uword pc)
virtual void Print(const char *format,...) PRINTF_ATTRIBUTE(2
virtual void Print(const char *format,...) PRINTF_ATTRIBUTE(2
static void Disassemble(uword start, uword end, DisassemblyFormatter *formatter, const Code &code, const CodeComments *comments=nullptr)
static void DisassembleStub(const char *name, const Code &code)
static void DisassembleCode(const Function &function, const Code &code, bool optimized)
static void DecodeInstruction(char *hex_buffer, intptr_t hex_size, char *human_buffer, intptr_t human_size, int *out_instr_len, const Code &code, Object **object, uword pc)
virtual void ConsumeInstruction(char *hex_buffer, intptr_t hex_size, char *human_buffer, intptr_t human_size, Object *object, uword pc)=0
virtual void Print(const char *format,...) PRINTF_ATTRIBUTE(2
static const char * KindToCString(UntaggedFunction::Kind kind)
Definition object.cc:8477
void AddValueNull() const
void AddValue(bool b) const
void AddValueF(const char *format,...) const PRINTF_ATTRIBUTE(2
static Log * NoOpLog()
Definition log.cc:183
static Log * Current()
Definition log.cc:75
intptr_t Length() const
Definition object.h:5543
void DebugPrint() const
Definition object.cc:15782
@ kScrubbedName
Definition object.h:633
static ObjectPtr null()
Definition object.h:433
virtual const char * ToCString() const
Definition object.h:366
bool IsNull() const
Definition object.h:363
static Object & Handle()
Definition object.h:407
Zone * zone() const
static Thread * Current()
Definition thread.h:361
static int static int VSNPrint(char *str, size_t size, const char *format, va_list args)
#define THR_Print(format,...)
Definition log.h:20
#define THR_VPrint(format, args)
Definition log.h:23
#define ASSERT(E)
glong glong end
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
static const uint8_t buffer[]
uint32_t uint32_t * format
#define DECLARE_FLAG(type, name)
Definition flags.h:14
#define DEFINE_FLAG(type, name, default_value, comment)
Definition flags.h:16
Dart_NativeFunction function
Definition fuchsia.cc:51
const char *const name
void * malloc(size_t size)
Definition allocation.cc:19
@ kHeapObjectTag
uintptr_t uword
Definition globals.h:501
static T LoadUnaligned(const T *ptr)
Definition unaligned.h:14
ArrayOfTuplesView< Code::SCallTableEntry, std::tuple< Smi, Object, Function > > StaticCallsTable
Definition object.h:13520
const char * DeoptReasonToCString(ICData::DeoptReasonId deopt_reason)
call(args)
Definition dom.py:159
#define Pp
Definition globals.h:425
#define Px32
Definition globals.h:414
#define Px
Definition globals.h:410
#define Px64
Definition globals.h:418
#define Pd
Definition globals.h:408
Point offset