Flutter Engine
The Flutter Engine
code_descriptors.cc
Go to the documentation of this file.
1// Copyright (c) 2012, 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
7#include "platform/utils.h"
9#include "vm/flags.h"
10#include "vm/log.h"
11#include "vm/object.h"
12#include "vm/object_store.h"
13#include "vm/zone_text_buffer.h"
14
15namespace dart {
16
18 Zone* zone,
19 const GrowableArray<const Function*>* inline_id_to_function)
20 : function_(Function::Handle(
21 zone,
22 FLAG_check_token_positions && (inline_id_to_function != nullptr)
23 ? inline_id_to_function->At(0)->ptr()
24 : Function::null())),
25 script_(Script::Handle(
26 zone,
27 function_.IsNull() ? Script::null() : function_.script())),
28 encoded_data_(zone, kInitialStreamSize),
29 prev_pc_offset(0),
30 prev_deopt_id(0),
31 prev_token_pos(0) {}
32
34 intptr_t pc_offset,
35 intptr_t deopt_id,
36 const TokenPosition token_pos,
37 intptr_t try_index,
38 intptr_t yield_index) {
39 // yield index 0 is reserved for normal entry.
40 RELEASE_ASSERT(yield_index != 0);
41
42 ASSERT((kind == UntaggedPcDescriptors::kRuntimeCall) ||
43 (kind == UntaggedPcDescriptors::kBSSRelocation) ||
44 (kind == UntaggedPcDescriptors::kOther) ||
46 (deopt_id != DeoptId::kNone));
47
48 // When precompiling, we only use pc descriptors for exceptions,
49 // relocations and yield indices.
50 if (!FLAG_precompiled_mode || try_index != -1 ||
52 kind == UntaggedPcDescriptors::kBSSRelocation) {
53 const int32_t kind_and_metadata =
55 yield_index);
56
57 encoded_data_.WriteSLEB128(kind_and_metadata);
58 encoded_data_.WriteSLEB128(pc_offset - prev_pc_offset);
59 prev_pc_offset = pc_offset;
60
61 if (!FLAG_precompiled_mode) {
62 if (FLAG_check_token_positions && token_pos.IsReal()) {
63 if (!function_.IsNull() &&
64 !token_pos.IsWithin(function_.token_pos(),
65 function_.end_token_pos())) {
66 FATAL("Token position %s for PC descriptor %s at offset 0x%" Px
67 " invalid for function %s (%s, %s)",
68 token_pos.ToCString(),
70 function_.ToFullyQualifiedCString(),
71 function_.token_pos().ToCString(),
72 function_.end_token_pos().ToCString());
73 }
74 if (!script_.IsNull() && !script_.IsValidTokenPosition(token_pos)) {
75 FATAL("Token position %s for PC descriptor %s at offset 0x%" Px
76 " invalid for script %s of function %s",
77 token_pos.ToCString(),
79 script_.ToCString(), function_.ToFullyQualifiedCString());
80 }
81 }
82 const int32_t encoded_pos = token_pos.Serialize();
83 encoded_data_.WriteSLEB128(deopt_id - prev_deopt_id);
84 encoded_data_.WriteSLEB128(
85 Utils::SubWithWrapAround(encoded_pos, prev_token_pos));
86 prev_deopt_id = deopt_id;
87 prev_token_pos = encoded_pos;
88 }
89 }
90}
91
92PcDescriptorsPtr DescriptorList::FinalizePcDescriptors(uword entry_point) {
93 if (encoded_data_.bytes_written() == 0) {
94 return Object::empty_descriptors().ptr();
95 }
96 return PcDescriptors::New(encoded_data_.buffer(),
97 encoded_data_.bytes_written());
98}
99
102 intptr_t spill_slot_bit_count) {
103 ASSERT(bitmap != nullptr);
104 ASSERT(pc_offset > last_pc_offset_);
105 ASSERT(spill_slot_bit_count >= 0 && spill_slot_bit_count <= bitmap->Length());
106 const uword pc_delta = pc_offset - last_pc_offset_;
107 const uword non_spill_slot_bit_count =
108 bitmap->Length() - spill_slot_bit_count;
109 encoded_bytes_.WriteLEB128(pc_delta);
110 encoded_bytes_.WriteLEB128(spill_slot_bit_count);
111 encoded_bytes_.WriteLEB128(non_spill_slot_bit_count);
112 bitmap->AppendAsBytesTo(&encoded_bytes_);
113 last_pc_offset_ = pc_offset;
114}
115
116CompressedStackMapsPtr CompressedStackMapsBuilder::Finalize() const {
117 if (encoded_bytes_.bytes_written() == 0) {
118 return Object::empty_compressed_stackmaps().ptr();
119 }
120 return CompressedStackMaps::NewInlined(encoded_bytes_.buffer(),
121 encoded_bytes_.bytes_written());
122}
123
125 uword entry_point) const {
126 intptr_t num_handlers = Length();
127 if (num_handlers == 0) {
128 return has_async_handler_ ? Object::empty_async_exception_handlers().ptr()
129 : Object::empty_exception_handlers().ptr();
130 }
131 const ExceptionHandlers& handlers =
133 handlers.set_has_async_handler(has_async_handler_);
134 for (intptr_t i = 0; i < num_handlers; i++) {
135 // Assert that every element in the array has been initialized.
136 if (list_[i].handler_types == nullptr) {
137 // Unreachable handler, entry not computed.
138 // Initialize it to some meaningful value.
139 const bool has_catch_all = false;
140 // Check it is uninitialized.
141 ASSERT((list_[i].outer_try_index == -1) &&
142 (list_[i].pc_offset == ExceptionHandlers::kInvalidPcOffset));
143 handlers.SetHandlerInfo(i, list_[i].outer_try_index, list_[i].pc_offset,
144 list_[i].needs_stacktrace, has_catch_all,
145 list_[i].is_generated);
146 handlers.SetHandledTypes(i, Array::empty_array());
147 } else {
148 const bool has_catch_all = ContainsCatchAllType(*list_[i].handler_types);
149 handlers.SetHandlerInfo(i, list_[i].outer_try_index, list_[i].pc_offset,
150 list_[i].needs_stacktrace, has_catch_all,
151 list_[i].is_generated);
152 handlers.SetHandledTypes(i, *list_[i].handler_types);
153 }
154 }
155 return handlers.ptr();
156}
157
158#if !defined(DART_PRECOMPILED_RUNTIME)
160 public:
161 TrieNode() : move_(), entry_state_offset_(-1) {}
162 TrieNode(CatchEntryMove move, intptr_t index)
163 : move_(move), entry_state_offset_(index) {}
164
165 intptr_t Offset() { return entry_state_offset_; }
166
168 children_.Add(node);
169 return node;
170 }
171
173 for (intptr_t i = 0; i < children_.length(); i++) {
174 if (children_[i]->move_ == next) return children_[i];
175 }
176 return nullptr;
177 }
178
179 private:
180 CatchEntryMove move_;
181 const intptr_t entry_state_offset_;
182 GrowableArray<TrieNode*> children_;
183};
184
186 : zone_(Thread::Current()->zone()),
187 root_(new TrieNode()),
188 current_pc_offset_(0),
189 stream_(zone_, 64) {}
190
192 moves_.Add(move);
193}
194
196 moves_.Clear();
197 current_pc_offset_ = pc_offset;
198}
199
201 intptr_t suffix_length = 0;
202 TrieNode* suffix = root_;
203 // Find the largest common suffix, get the last node of the path.
204 for (intptr_t i = moves_.length() - 1; i >= 0; i--) {
205 TrieNode* n = suffix->Follow(moves_[i]);
206 if (n == nullptr) break;
207 suffix_length++;
208 suffix = n;
209 }
210 intptr_t length = moves_.length() - suffix_length;
211 intptr_t current_offset = stream_.bytes_written();
212
213 typedef ZoneWriteStream::Raw<sizeof(intptr_t), intptr_t> Writer;
214 Writer::Write(&stream_, current_pc_offset_);
215 Writer::Write(&stream_, length);
216 Writer::Write(&stream_, suffix_length);
217 Writer::Write(&stream_, suffix->Offset());
218
219 // Write the unshared part, adding it to the trie.
220 TrieNode* node = suffix;
221 for (intptr_t i = length - 1; i >= 0; i--) {
222 moves_[i].WriteTo(&stream_);
223
224 TrieNode* child = new (zone_) TrieNode(moves_[i], current_offset);
225 node->Insert(child);
226 node = child;
227 }
228}
229
232 kTypedDataInt8ArrayCid, stream_.bytes_written(), Heap::kOld));
233 NoSafepointScope no_safepoint;
234 uint8_t* dest = reinterpret_cast<uint8_t*>(td.DataAddr(0));
235 uint8_t* src = stream_.buffer();
236 for (intptr_t i = 0; i < stream_.bytes_written(); i++) {
237 dest[i] = src[i];
238 }
239 return td.ptr();
240}
241#endif // !defined(DART_PRECOMPILED_RUNTIME)
242
244 int32_t* arg1,
245 int32_t* arg2) {
246 ASSERT(stream != nullptr && arg1 != nullptr);
247 const int32_t n = stream->Read<int32_t>();
248 const uint8_t op = OpField::decode(n);
249 *arg1 = ArgField::decode(n);
250 if (*arg1 > kMaxArgValue) {
251 *arg1 |= kSignBits;
252 }
253#if defined(DART_PRECOMPILER)
254 // The special handling for non-symbolic stack trace mode only needs to
255 // happen in the precompiler, because those CSMs are not serialized in
256 // precompiled snapshots.
257 if (op == kChangePosition && FLAG_dwarf_stack_traces_mode) {
258 const int32_t m = stream->Read<int32_t>();
259 if (arg2 != nullptr) {
260 *arg2 = m;
261 }
262 }
263#endif
264 return op;
265}
266
268 uint8_t op,
269 int32_t arg1,
270 int32_t arg2) {
271 ASSERT(stream != nullptr);
272 ASSERT(arg1 >= kMinArgValue && arg1 <= kMaxArgValue);
273 if (arg1 < 0) {
274 arg1 &= ~kSignBits;
275 }
276 const int32_t n = OpField::encode(op) | ArgField::encode(arg1);
277 stream->Write(n);
278#if defined(DART_PRECOMPILER)
279 if (op == kChangePosition && FLAG_dwarf_stack_traces_mode) {
280 // For non-symbolic stack traces, the CodeSourceMaps are not serialized,
281 // so we need not worry about increasing snapshot size by including more
282 // information here.
283 stream->Write(arg2);
284 }
285#endif
286}
287
289 TokenPosition::kDartCodePrologue;
290
292 Zone* zone,
293 bool stack_traces_only,
294 const GrowableArray<intptr_t>& caller_inline_id,
295 const GrowableArray<TokenPosition>& inline_id_to_token_pos,
296 const GrowableArray<const Function*>& inline_id_to_function)
297 : zone_(zone),
298 buffered_pc_offset_(0),
299 buffered_inline_id_stack_(),
300 buffered_token_pos_stack_(),
301 written_pc_offset_(0),
302 written_inline_id_stack_(),
303 written_token_pos_stack_(),
304 caller_inline_id_(caller_inline_id),
305 inline_id_to_token_pos_(inline_id_to_token_pos),
306 inline_id_to_function_(inline_id_to_function),
307 inlined_functions_(
309 script_(Script::Handle(zone, Script::null())),
310 stream_(zone, 64),
311 stack_traces_only_(stack_traces_only) {
312 buffered_inline_id_stack_.Add(0);
313 buffered_token_pos_stack_.Add(kInitialPosition);
314 written_inline_id_stack_.Add(0);
315 written_token_pos_stack_.Add(kInitialPosition);
316}
317
318void CodeSourceMapBuilder::FlushBuffer() {
319 // 1. Flush the inlining stack.
320 //
321 // The top-most position where the buffered and written stack match.
322 intptr_t common_index;
323 for (common_index = buffered_inline_id_stack_.length() - 1; common_index >= 0;
324 common_index--) {
325 intptr_t buffered_id = buffered_inline_id_stack_[common_index];
326 if (common_index < written_inline_id_stack_.length()) {
327 intptr_t written_id = written_inline_id_stack_[common_index];
328 if (buffered_id == written_id) {
329 break;
330 }
331 }
332 }
333 if (common_index < 0) {
334 // The base, which is the root function, should _always_ match.
335 UNREACHABLE();
336 }
337 while (written_inline_id_stack_.length() > common_index + 1) {
338 WritePop();
339 }
340 for (intptr_t j = common_index + 1; j < buffered_inline_id_stack_.length();
341 j++) {
342 const auto& buffered_pos = buffered_token_pos_stack_[j - 1];
343 const auto& written_pos = written_token_pos_stack_[j - 1];
344 if (buffered_pos != written_pos) {
345 WriteChangePosition(buffered_pos);
346 }
347 WritePush(buffered_inline_id_stack_[j]);
348 }
349
350 ASSERT_EQUAL(buffered_token_pos_stack_.length(),
351 written_token_pos_stack_.length());
352
353 // 2. Flush the current token position.
354 intptr_t top = buffered_token_pos_stack_.length() - 1;
355 const auto& buffered_pos = buffered_token_pos_stack_[top];
356 const auto& written_pos = written_token_pos_stack_[top];
357 if (buffered_pos != written_pos) {
358 WriteChangePosition(buffered_pos);
359 }
360
361 // 3. Flush the current PC offset.
362 if (buffered_pc_offset_ != written_pc_offset_) {
363 WriteAdvancePC(buffered_pc_offset_ - written_pc_offset_);
364 }
365}
366
367void CodeSourceMapBuilder::StartInliningInterval(
368 int32_t pc_offset,
369 const InstructionSource& source) {
370 if (!source.token_pos.IsReal() && !source.token_pos.IsSynthetic()) {
371 // Only record inlining intervals for token positions that might need
372 // to be checked against the appropriate function and/or script.
373 return;
374 }
375
376 if (buffered_inline_id_stack_.Last() == source.inlining_id) {
377 // No change in function stack.
378 return;
379 }
380
381 if (source.inlining_id < 0) {
382 // Inlining ID is unset for this source, so assume the current inlining ID.
383 return;
384 }
385
386 if (!stack_traces_only_) {
387 FlushBuffer();
388 }
389
390 // Find a minimal set of pops and pushes to bring us to the new function
391 // stack.
392
393 // Pop to a common ancestor.
394 intptr_t common_parent = source.inlining_id;
395 while (!IsOnBufferedStack(common_parent)) {
396 common_parent = caller_inline_id_[common_parent];
397 }
398 while (buffered_inline_id_stack_.Last() != common_parent) {
399 BufferPop();
400 }
401
402 // Push to the new top-of-stack function.
403 GrowableArray<intptr_t> to_push;
404 for (intptr_t id = source.inlining_id; id != common_parent;
405 id = caller_inline_id_[id]) {
406 to_push.Add(id);
407 }
408 for (intptr_t i = to_push.length() - 1; i >= 0; i--) {
409 intptr_t callee_id = to_push[i];
410 // We should never push the root function or its "caller".
411 ASSERT(callee_id > 0);
412 BufferChangePosition(inline_id_to_token_pos_[callee_id - 1]);
413 BufferPush(callee_id);
414 }
415 if (FLAG_check_token_positions) {
416 // Only update the cached script_ on inlining interval changes, since it's
417 // a non-trivial computation.
418 script_ = inline_id_to_function_[source.inlining_id]->script();
419 }
420}
421
423 const InstructionSource& source) {
424 ASSERT(written_pc_offset_ == 0 && buffered_pc_offset_ == 0);
425 ASSERT(stream_.bytes_written() == 0);
426 WriteChangePosition(source.token_pos);
427 WriteAdvancePC(0);
428}
429
431 int32_t pc_offset,
432 const InstructionSource& source) {
433 StartInliningInterval(pc_offset, source);
434}
435
437 const InstructionSource& source) {
438 if (pc_offset == buffered_pc_offset_) {
439 return; // Empty intermediate instruction.
440 }
441 StartInliningInterval(pc_offset, source);
442 if (source.token_pos != buffered_token_pos_stack_.Last()) {
443 if (!stack_traces_only_) {
444 FlushBuffer();
445 }
446 BufferChangePosition(source.token_pos);
447 }
448 BufferAdvancePC(pc_offset - buffered_pc_offset_);
449}
450
452 int32_t pc_offset,
453 const InstructionSource& source) {
454 const uint8_t kCanThrow =
455 UntaggedPcDescriptors::kIcCall | UntaggedPcDescriptors::kUnoptStaticCall |
456 UntaggedPcDescriptors::kRuntimeCall | UntaggedPcDescriptors::kOther;
457 if ((kind & kCanThrow) != 0) {
458 StartInliningInterval(pc_offset, source);
459 BufferChangePosition(source.token_pos);
460 BufferAdvancePC(pc_offset - buffered_pc_offset_);
461 FlushBuffer();
462 }
463}
464
467 intptr_t name_index) {
468 StartInliningInterval(pc_offset, source);
469 BufferChangePosition(source.token_pos);
470 BufferAdvancePC(pc_offset - buffered_pc_offset_);
471 FlushBuffer();
472 WriteNullCheck(name_index);
473}
474
475intptr_t CodeSourceMapBuilder::GetFunctionId(intptr_t inline_id) {
476 const Function& function = *inline_id_to_function_[inline_id];
477 for (intptr_t i = 0; i < inlined_functions_.Length(); i++) {
478 if (inlined_functions_.At(i) == function.ptr()) {
479 return i;
480 }
481 }
482 RELEASE_ASSERT(!function.IsNull());
483 inlined_functions_.Add(function, Heap::kOld);
484 return inlined_functions_.Length() - 1;
485}
486
488 const InstructionSource& source) {
489 if (source.inlining_id <= 0) return source.token_pos;
490
491 intptr_t id = source.inlining_id;
492 while (caller_inline_id_[id] != 0) {
493 id = caller_inline_id_[id];
494 }
495 return inline_id_to_token_pos_[id - 1];
496}
497
499 if (inlined_functions_.Length() == 0) {
500 return Object::empty_array().ptr();
501 }
502 return Array::MakeFixedLength(inlined_functions_);
503}
504
506 if (!stack_traces_only_) {
507 FlushBuffer();
508 }
509 intptr_t length = stream_.bytes_written();
510 const auto& map = CodeSourceMap::Handle(zone_, CodeSourceMap::New(length));
511 NoSafepointScope no_safepoint;
512 if (length > 0) {
513 ASSERT(stream_.buffer() != nullptr);
514 memmove(map.Data(), stream_.buffer(), length);
515 }
516 return map.ptr();
517}
518
519void CodeSourceMapBuilder::BufferChangePosition(TokenPosition pos) {
520 if (FLAG_check_token_positions && pos.IsReal()) {
521 const intptr_t inline_id = buffered_inline_id_stack_.Last();
522 const auto& function = *inline_id_to_function_[inline_id];
523 if (function.end_token_pos().IsReal() &&
524 !pos.IsWithin(function.token_pos(), function.end_token_pos())) {
525 TextBuffer buffer(256);
526 buffer.Printf("Token position %s is invalid for function %s (%s, %s)",
527 pos.ToCString(), function.ToFullyQualifiedCString(),
528 function.token_pos().ToCString(),
529 function.end_token_pos().ToCString());
530 if (inline_id > 0) {
531 buffer.Printf(" while compiling function %s",
532 inline_id_to_function_[0]->ToFullyQualifiedCString());
533 }
534 FATAL("%s", buffer.buffer());
535 }
536 script_ = function.script();
537 if (!script_.IsNull() && !script_.IsValidTokenPosition(pos)) {
538 TextBuffer buffer(256);
539 buffer.Printf("Token position %s is invalid for script %s of function %s",
540 pos.ToCString(), script_.ToCString(),
541 function.ToFullyQualifiedCString());
542 if (inline_id != 0) {
543 buffer.Printf(" inlined into function %s",
544 inline_id_to_function_[0]->ToFullyQualifiedCString());
545 }
546 FATAL("%s", buffer.buffer());
547 }
548 }
549 buffered_token_pos_stack_.Last() = pos;
550}
551
552void CodeSourceMapBuilder::WriteChangePosition(const TokenPosition pos) {
553 const TokenPosition& last_written = written_token_pos_stack_.Last();
554 intptr_t position_or_line =
555 Utils::SubWithWrapAround(pos.Serialize(), last_written.Serialize());
556 intptr_t column = TokenPosition::kNoSource.Serialize();
557#if defined(DART_PRECOMPILER)
558 if (FLAG_precompiled_mode) {
559 // Don't use the raw position value directly in precompiled mode. Instead,
560 // use the value of kNoSource as a fallback when no line or column
561 // information is found.
562 position_or_line = TokenPosition::kNoSource.Serialize();
563 const intptr_t inline_id = written_inline_id_stack_.Last();
564 ASSERT(inline_id < inline_id_to_function_.length());
565 script_ = inline_id_to_function_[inline_id]->script();
566 script_.GetTokenLocation(pos, &position_or_line, &column);
567 intptr_t old_line = TokenPosition::kNoSource.Serialize();
568 script_.GetTokenLocation(last_written, &old_line);
569 position_or_line =
570 Utils::SubWithWrapAround<int32_t>(position_or_line, old_line);
571 }
572#endif
574 position_or_line, column);
575 written_token_pos_stack_.Last() = pos;
576}
577
579 int32_t pc_offset,
580 GrowableArray<const Function*>* function_stack,
581 GrowableArray<TokenPosition>* token_positions) {
582 function_stack->Clear();
583 token_positions->Clear();
584
585 NoSafepointScope no_safepoint;
586 ReadStream stream(map_.Data(), map_.Length());
587
588 int32_t current_pc_offset = 0;
589 function_stack->Add(&root_);
590 token_positions->Add(InitialPosition());
591
592 while (stream.PendingBytes() > 0) {
593 int32_t arg;
594 const uint8_t opcode = CodeSourceMapOps::Read(&stream, &arg);
595 switch (opcode) {
597 const TokenPosition& old_token = token_positions->Last();
598 token_positions->Last() = TokenPosition::Deserialize(
599 Utils::AddWithWrapAround(arg, old_token.Serialize()));
600 break;
601 }
603 current_pc_offset += arg;
604 if (current_pc_offset > pc_offset) {
605 return;
606 }
607 break;
608 }
610 function_stack->Add(
611 &Function::Handle(Function::RawCast(functions_.At(arg))));
612 token_positions->Add(InitialPosition());
613 break;
614 }
616 // We never pop the root function.
617 ASSERT(function_stack->length() > 1);
618 ASSERT(token_positions->length() > 1);
619 function_stack->RemoveLast();
620 token_positions->RemoveLast();
621 break;
622 }
624 break;
625 }
626 default:
627 UNREACHABLE();
628 }
629 }
630}
631
632#ifndef PRODUCT
633void CodeSourceMapReader::PrintJSONInlineIntervals(JSONObject* jsobj) {
634 {
635 JSONArray inlined_functions(jsobj, "_inlinedFunctions");
637 for (intptr_t i = 0; i < functions_.Length(); i++) {
638 function ^= functions_.At(i);
639 ASSERT(!function.IsNull());
640 inlined_functions.AddValue(function);
641 }
642 }
643
644 GrowableArray<intptr_t> function_stack;
645 JSONArray inline_intervals(jsobj, "_inlinedIntervals");
646 NoSafepointScope no_safepoint;
647 ReadStream stream(map_.Data(), map_.Length());
648
649 int32_t current_pc_offset = 0;
650 function_stack.Add(0);
651
652 while (stream.PendingBytes() > 0) {
653 int32_t arg;
654 const uint8_t opcode = CodeSourceMapOps::Read(&stream, &arg);
655 switch (opcode) {
657 break;
658 }
660 // Format: [start, end, inline functions...]
661 JSONArray inline_interval(&inline_intervals);
662 inline_interval.AddValue(static_cast<intptr_t>(current_pc_offset));
663 inline_interval.AddValue(
664 static_cast<intptr_t>(current_pc_offset + arg - 1));
665 for (intptr_t i = 0; i < function_stack.length(); i++) {
666 inline_interval.AddValue(function_stack[i]);
667 }
668 current_pc_offset += arg;
669 break;
670 }
672 function_stack.Add(arg);
673 break;
674 }
676 // We never pop the root function.
677 ASSERT(function_stack.length() > 1);
678 function_stack.RemoveLast();
679 break;
680 }
682 break;
683 }
684 default:
685 UNREACHABLE();
686 }
687 }
688}
689#endif // !PRODUCT
690
692 GrowableArray<const Function*> function_stack;
693 GrowableArray<TokenPosition> token_positions;
694 LogBlock lb;
695 NoSafepointScope no_safepoint;
696 ReadStream stream(map_.Data(), map_.Length());
697
698 int32_t current_pc_offset = 0;
699 function_stack.Add(&root_);
700 token_positions.Add(InitialPosition());
701
702 THR_Print("Inline intervals for function '%s' {\n",
704 while (stream.PendingBytes() > 0) {
705 int32_t arg;
706 const uint8_t opcode = CodeSourceMapOps::Read(&stream, &arg);
707 switch (opcode) {
709 const TokenPosition& old_token = token_positions.Last();
710 token_positions.Last() = TokenPosition::Deserialize(
711 Utils::AddWithWrapAround(arg, old_token.Serialize()));
712 break;
713 }
715 THR_Print("%" Px "-%" Px ": ", start + current_pc_offset,
716 start + current_pc_offset + arg - 1);
717 for (intptr_t i = 0; i < function_stack.length(); i++) {
718 THR_Print("%s", function_stack[i]->ToCString());
719 if (token_positions[i].IsReal()) {
720 THR_Print(" @%" Pd, token_positions[i].Pos());
721 }
722 }
723 THR_Print("\n");
724 current_pc_offset += arg;
725 break;
726 }
728 function_stack.Add(
729 &Function::Handle(Function::RawCast(functions_.At(arg))));
730 token_positions.Add(InitialPosition());
731 break;
732 }
734 // We never pop the root function.
735 ASSERT(function_stack.length() > 1);
736 ASSERT(token_positions.length() > 1);
737 function_stack.RemoveLast();
738 token_positions.RemoveLast();
739 break;
740 }
742 break;
743 }
744 default:
745 UNREACHABLE();
746 }
747 }
748 THR_Print("}\n");
749}
750
752 GrowableArray<const Function*> function_stack;
753 GrowableArray<TokenPosition> token_positions;
754 LogBlock lb;
755 NoSafepointScope no_safepoint;
756 ReadStream stream(map_.Data(), map_.Length());
757
758 int32_t current_pc_offset = 0;
759 function_stack.Add(&root_);
760 token_positions.Add(InitialPosition());
761
762 THR_Print("Source positions for function '%s' {\n",
764 while (stream.PendingBytes() > 0) {
765 int32_t arg;
766 const uint8_t opcode = CodeSourceMapOps::Read(&stream, &arg);
767 switch (opcode) {
769 const TokenPosition& old_token =
770 token_positions[token_positions.length() - 1];
771 token_positions[token_positions.length() - 1] =
773 Utils::AddWithWrapAround(arg, old_token.Serialize()));
774 break;
775 }
777 THR_Print("%" Px "-%" Px ": ", start + current_pc_offset,
778 start + current_pc_offset + arg - 1);
779 for (intptr_t i = 0; i < function_stack.length(); i++) {
780 THR_Print("%s@%s", function_stack[i]->ToCString(),
781 token_positions[i].ToCString());
782 }
783 THR_Print("\n");
784 current_pc_offset += arg;
785 break;
786 }
788 function_stack.Add(
789 &Function::Handle(Function::RawCast(functions_.At(arg))));
790 token_positions.Add(InitialPosition());
791 break;
792 }
794 // We never pop the root function.
795 ASSERT(function_stack.length() > 1);
796 ASSERT(token_positions.length() > 1);
797 function_stack.RemoveLast();
798 token_positions.RemoveLast();
799 break;
800 }
802 THR_Print("%" Px "-%" Px ": null check PP#%" Pd32 "\n",
803 start + current_pc_offset, start + current_pc_offset, arg);
804 break;
805 }
806 default:
807 UNREACHABLE();
808 }
809 }
810 THR_Print("}\n");
811}
812
814 NoSafepointScope no_safepoint;
815 ReadStream stream(map_.Data(), map_.Length());
816
817 int32_t current_pc_offset = 0;
818
819 while (stream.PendingBytes() > 0) {
820 int32_t arg;
821 const uint8_t opcode = CodeSourceMapOps::Read(&stream, &arg);
822 switch (opcode) {
824 break;
825 }
827 current_pc_offset += arg;
828 RELEASE_ASSERT(current_pc_offset <= pc_offset);
829 break;
830 }
832 break;
833 }
835 break;
836 }
838 if (current_pc_offset == pc_offset) {
839 return arg;
840 }
841 break;
842 }
843 default:
844 UNREACHABLE();
845 }
846 }
847
848 UNREACHABLE();
849 return -1;
850}
851
852} // namespace dart
SkPoint pos
static float next(float f)
#define UNREACHABLE()
Definition: assert.h:248
#define ASSERT_EQUAL(expected, actual)
Definition: assert.h:309
#define RELEASE_ASSERT(cond)
Definition: assert.h:327
ObjectPtr At(intptr_t index) const
Definition: object.h:10875
intptr_t Length() const
Definition: object.h:10829
static ArrayPtr MakeFixedLength(const GrowableObjectArray &growable_array, bool unique=false)
Definition: object.cc:24935
void Add(const T &value)
intptr_t length() const
C::only_if_signed< T, void > WriteSLEB128(T value)
Definition: datastream.h:514
DART_FORCE_INLINE intptr_t bytes_written() const
Definition: datastream.h:338
C::only_if_unsigned< T, void > WriteLEB128(T value)
Definition: datastream.h:489
static constexpr T decode(S value)
Definition: bitfield.h:171
static constexpr S encode(T value)
Definition: bitfield.h:165
TrieNode(CatchEntryMove move, intptr_t index)
TrieNode * Follow(CatchEntryMove next)
void NewMapping(intptr_t pc_offset)
void Append(const CatchEntryMove &move)
TokenPosition RootPosition(const InstructionSource &source)
void EndCodeSourceRange(int32_t pc_offset, const InstructionSource &source)
void WriteFunctionEntrySourcePosition(const InstructionSource &source)
CodeSourceMapBuilder(Zone *zone, bool stack_traces_only, const GrowableArray< intptr_t > &caller_inline_id, const GrowableArray< TokenPosition > &inline_id_to_token_pos, const GrowableArray< const Function * > &inline_id_to_function)
void NoteNullCheck(int32_t pc_offset, const InstructionSource &source, intptr_t name_index)
static const TokenPosition & kInitialPosition
void BeginCodeSourceRange(int32_t pc_offset, const InstructionSource &source)
void NoteDescriptor(UntaggedPcDescriptors::Kind kind, int32_t pc_offset, const InstructionSource &source)
intptr_t GetNullCheckNameIndexAt(int32_t pc_offset)
void DumpInlineIntervals(uword start)
void GetInlinedFunctionsAt(int32_t pc_offset, GrowableArray< const Function * > *function_stack, GrowableArray< TokenPosition > *token_positions)
void DumpSourcePositions(uword start)
uint8_t * Data() const
Definition: object.h:6242
intptr_t Length() const
Definition: object.h:6241
static CodeSourceMapPtr New(intptr_t length)
Definition: object.cc:15923
CompressedStackMapsPtr Finalize() const
void AddEntry(intptr_t pc_offset, BitmapBuilder *bitmap, intptr_t spill_slot_bit_count)
static CompressedStackMapsPtr NewInlined(const void *payload, intptr_t size)
Definition: object.h:6316
static constexpr intptr_t kNone
Definition: deopt_id.h:27
void AddDescriptor(UntaggedPcDescriptors::Kind kind, intptr_t pc_offset, intptr_t deopt_id, TokenPosition token_pos, intptr_t try_index, intptr_t yield_index)
PcDescriptorsPtr FinalizePcDescriptors(uword entry_point)
DescriptorList(Zone *zone, const GrowableArray< const Function * > *inline_id_to_function=nullptr)
ExceptionHandlersPtr FinalizeExceptionHandlers(uword entry_point) const
static bool ContainsCatchAllType(const Array &array)
void SetHandledTypes(intptr_t try_index, const Array &handled_types) const
Definition: object.cc:16221
void set_has_async_handler(bool value) const
Definition: object.cc:16162
void SetHandlerInfo(intptr_t try_index, intptr_t outer_try_index, uword handler_pc_offset, bool needs_stacktrace, bool has_catch_all, bool is_generated) const
Definition: object.cc:16168
static constexpr intptr_t kInvalidPcOffset
Definition: object.h:6574
static ExceptionHandlersPtr New(intptr_t num_handlers)
Definition: object.cc:16241
const char * ToFullyQualifiedCString() const
Definition: object.cc:9762
TokenPosition token_pos() const
Definition: object.h:3446
TokenPosition end_token_pos() const
Definition: object.h:3455
void Add(const Object &value, Heap::Space space=Heap::kNew) const
Definition: object.cc:24991
intptr_t Length() const
Definition: object.h:11072
ObjectPtr At(intptr_t index) const
Definition: object.h:11085
@ kOld
Definition: heap.h:39
uint8_t * buffer() const
Definition: datastream.h:615
ObjectPtr ptr() const
Definition: object.h:332
virtual const char * ToCString() const
Definition: object.h:366
bool IsNull() const
Definition: object.h:363
static Object & Handle()
Definition: object.h:407
static ObjectPtr RawCast(ObjectPtr obj)
Definition: object.h:325
static PcDescriptorsPtr New(const void *delta_encoded_data, intptr_t size)
Definition: object.cc:15794
bool IsValidTokenPosition(TokenPosition token_pos) const
Definition: object.cc:13256
bool GetTokenLocation(const TokenPosition &token_pos, intptr_t *line, intptr_t *column=nullptr) const
Definition: object.cc:13283
const char * ToCString() const
int32_t Serialize() const
static TokenPosition Deserialize(int32_t value)
bool IsWithin(const TokenPosition &a, const TokenPosition &b) const
void * DataAddr(intptr_t byte_offset) const
Definition: object.h:11571
static TypedDataPtr New(intptr_t class_id, intptr_t len, Heap::Space space=Heap::kNew)
Definition: object.cc:25587
static uint32_t Encode(intptr_t kind, intptr_t try_index, intptr_t yield_index)
Definition: raw_object.h:2087
static const char * KindToCString(Kind k)
Definition: raw_object.cc:771
static constexpr intptr_t kInvalidYieldIndex
Definition: raw_object.h:2081
static T AddWithWrapAround(T a, T b)
Definition: utils.h:431
static T SubWithWrapAround(T a, T b)
Definition: utils.h:440
#define THR_Print(format,...)
Definition: log.h:20
#define ASSERT(E)
SkBitmap source
Definition: examples.cpp:28
#define FATAL(error)
Dart_NativeFunction function
Definition: fuchsia.cc:51
size_t length
Definition: bitmap.py:1
Definition: dart_vm.cc:33
@ kOld
Definition: heap_test.cc:892
DART_EXPORT bool IsNull(Dart_Handle object)
uintptr_t uword
Definition: globals.h:501
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
AsciiTrie::TrieNode TrieNode
Definition: ascii_trie.cc:10
SI auto map(std::index_sequence< I... >, Fn &&fn, const Args &... args) -> skvx::Vec< sizeof...(I), decltype(fn(args[0]...))>
Definition: SkVx.h:680
dest
Definition: zip.py:79
#define Px
Definition: globals.h:410
#define Pd
Definition: globals.h:408
#define Pd32
Definition: globals.h:412
static constexpr uint8_t kAdvancePC
static constexpr uint8_t kNullCheck
static uint8_t Read(ReadStream *stream, int32_t *arg1, int32_t *arg2=nullptr)
static void Write(BaseWriteStream *stream, uint8_t op, int32_t arg1=0, int32_t arg2=0)
static constexpr uint8_t kPopFunction
static constexpr uint8_t kPushFunction
static constexpr uint8_t kChangePosition
const uintptr_t id