Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
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:10854
intptr_t Length() const
Definition object.h:10808
static ArrayPtr MakeFixedLength(const GrowableObjectArray &growable_array, bool unique=false)
Definition object.cc:25014
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:173
static constexpr S encode(T value)
Definition bitfield.h:167
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:6215
intptr_t Length() const
Definition object.h:6214
static CodeSourceMapPtr New(intptr_t length)
Definition object.cc:15970
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:6289
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:16268
void set_has_async_handler(bool value) const
Definition object.cc:16209
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:16215
static constexpr intptr_t kInvalidPcOffset
Definition object.h:6547
static ExceptionHandlersPtr New(intptr_t num_handlers)
Definition object.cc:16288
const char * ToFullyQualifiedCString() const
Definition object.cc:9820
TokenPosition token_pos() const
Definition object.h:3426
TokenPosition end_token_pos() const
Definition object.h:3435
void Add(const Object &value, Heap::Space space=Heap::kNew) const
Definition object.cc:25070
intptr_t Length() const
Definition object.h:11046
ObjectPtr At(intptr_t index) const
Definition object.h:11059
@ kOld
Definition heap.h:39
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:15841
bool IsValidTokenPosition(TokenPosition token_pos) const
Definition object.cc:13303
bool GetTokenLocation(const TokenPosition &token_pos, intptr_t *line, intptr_t *column=nullptr) const
Definition object.cc:13330
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:11545
static TypedDataPtr New(intptr_t class_id, intptr_t len, Heap::Space space=Heap::kNew)
Definition object.cc:25666
static uint32_t Encode(intptr_t kind, intptr_t try_index, intptr_t yield_index)
static const char * KindToCString(Kind k)
static constexpr intptr_t kInvalidYieldIndex
static T AddWithWrapAround(T a, T b)
Definition utils.h:416
static T SubWithWrapAround(T a, T b)
Definition utils.h:425
#define THR_Print(format,...)
Definition log.h:20
#define ASSERT(E)
SkBitmap source
Definition examples.cpp:28
#define FATAL(error)
static const uint8_t buffer[]
Dart_NativeFunction function
Definition fuchsia.cc:51
size_t length
DART_EXPORT bool IsNull(Dart_Handle object)
uintptr_t uword
Definition globals.h:501
#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