Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
kernel_binary_flowgraph.cc
Go to the documentation of this file.
1// Copyright (c) 2016, 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
10#include "vm/compiler/frontend/flow_graph_builder.h" // For dart::FlowGraphBuilder::SimpleInstanceOfType.
13#include "vm/kernel_binary.h"
14#include "vm/kernel_loader.h"
15#include "vm/object_store.h"
16#include "vm/resolver.h"
17#include "vm/stack_frame.h"
18
19namespace dart {
20namespace kernel {
21
22#define Z (zone_)
23#define H (translation_helper_)
24#define T (type_translator_)
25#define I Isolate::Current()
26#define IG IsolateGroup::Current()
27#define B (flow_graph_builder_)
28
29Class& StreamingFlowGraphBuilder::GetSuperOrDie() {
30 Class& klass = Class::Handle(Z, parsed_function()->function().Owner());
31 ASSERT(!klass.IsNull());
32 klass = klass.SuperClass();
33 ASSERT(!klass.IsNull());
34 return klass;
35}
36
37FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfFieldInitializer() {
38 FieldHelper field_helper(this);
39 field_helper.ReadUntilExcluding(FieldHelper::kInitializer);
40
41 // Constants are directly accessed at use sites of Dart code. In C++ - if
42 // we need to access static constants - we do so directly using the kernel
43 // evaluation instead of invoking the initializer function in Dart code.
44 //
45 // If the field is marked as @pragma('vm:entry-point') then the embedder might
46 // invoke the getter, so we'll generate the initializer function.
47 ASSERT(!field_helper.IsConst() ||
48 Field::Handle(Z, parsed_function()->function().accessor_field())
50 Error::null());
51
52 Tag initializer_tag = ReadTag(); // read first part of initializer.
53 if (initializer_tag != kSomething) {
55 }
56
57 B->graph_entry_ = new (Z) GraphEntryInstr(*parsed_function(), B->osr_id_);
58
59 auto normal_entry = B->BuildFunctionEntry(B->graph_entry_);
60 B->graph_entry_->set_normal_entry(normal_entry);
61
62 Fragment body(normal_entry);
63 body += B->CheckStackOverflowInPrologue(field_helper.position_);
64 body += SetupCapturedParameters(parsed_function()->function());
65 body += BuildExpression(); // read initializer.
66 body += Return(TokenPosition::kNoSource);
67
68 PrologueInfo prologue_info(-1, -1);
69 if (B->IsCompiledForOsr()) {
70 B->graph_entry_->RelinkToOsrEntry(Z, B->last_used_block_id_ + 1);
71 }
72 return new (Z) FlowGraph(
73 *parsed_function(), B->graph_entry_, B->last_used_block_id_,
74 prologue_info,
75 FlowGraph::CompilationModeFrom(flow_graph_builder_->optimizing_));
76}
77
78void StreamingFlowGraphBuilder::SetupDefaultParameterValues() {
79 intptr_t optional_parameter_count =
80 parsed_function()->function().NumOptionalParameters();
81 if (optional_parameter_count > 0) {
82 ZoneGrowableArray<const Instance*>* default_values =
83 new ZoneGrowableArray<const Instance*>(Z, optional_parameter_count);
84
85 AlternativeReadingScope alt(&reader_);
86 FunctionNodeHelper function_node_helper(this);
87 function_node_helper.ReadUntilExcluding(
89
90 if (parsed_function()->function().HasOptionalNamedParameters()) {
91 // List of positional.
92 intptr_t list_length = ReadListLength(); // read list length.
93 for (intptr_t i = 0; i < list_length; ++i) {
94 SkipVariableDeclaration(); // read ith variable declaration.
95 }
96
97 // List of named.
98 list_length = ReadListLength(); // read list length.
99 ASSERT(optional_parameter_count == list_length);
100 ASSERT(!parsed_function()->function().HasOptionalPositionalParameters());
101 for (intptr_t i = 0; i < list_length; ++i) {
102 Instance* default_value;
103
104 // Read ith variable declaration
105 VariableDeclarationHelper helper(this);
106 helper.ReadUntilExcluding(VariableDeclarationHelper::kInitializer);
107 Tag tag = ReadTag(); // read (first part of) initializer.
108 if (tag == kSomething) {
109 // This will read the initializer.
110 default_value = &Instance::ZoneHandle(
111 Z, constant_reader_.ReadConstantExpression());
112 } else {
113 default_value = &Instance::ZoneHandle(Z, Instance::null());
114 }
115 default_values->Add(default_value);
116 }
117 } else {
118 // List of positional.
119 intptr_t list_length = ReadListLength(); // read list length.
120 ASSERT(list_length == function_node_helper.required_parameter_count_ +
121 optional_parameter_count);
122 ASSERT(parsed_function()->function().HasOptionalPositionalParameters());
123 for (intptr_t i = 0; i < function_node_helper.required_parameter_count_;
124 ++i) {
125 SkipVariableDeclaration(); // read ith variable declaration.
126 }
127 for (intptr_t i = 0; i < optional_parameter_count; ++i) {
128 Instance* default_value;
129
130 // Read ith variable declaration
131 VariableDeclarationHelper helper(this);
132 helper.ReadUntilExcluding(VariableDeclarationHelper::kInitializer);
133 Tag tag = ReadTag(); // read (first part of) initializer.
134 if (tag == kSomething) {
135 // This will read the initializer.
136 default_value = &Instance::ZoneHandle(
137 Z, constant_reader_.ReadConstantExpression());
138 } else {
139 default_value = &Instance::ZoneHandle(Z, Instance::null());
140 }
141 default_values->Add(default_value);
142 }
143
144 // List of named.
145 list_length = ReadListLength(); // read list length.
146 ASSERT(list_length == 0);
147 }
148 parsed_function()->set_default_parameter_values(default_values);
149 }
150}
151
152Fragment StreamingFlowGraphBuilder::BuildFieldInitializer(
153 const Field& field,
154 bool only_for_side_effects) {
155 ASSERT(Error::Handle(Z, H.thread()->sticky_error()).IsNull());
156 if (PeekTag() == kNullLiteral) {
157 SkipExpression(); // read past the null literal.
158 if (H.thread()->IsDartMutatorThread()) {
159 ASSERT(field.IsOriginal());
160 LeaveCompilerScope cs(H.thread());
161 field.RecordStore(Object::null_object());
162 } else {
163 ASSERT(field.is_nullable_unsafe());
164 }
165 return Fragment();
166 }
167
168 Fragment instructions;
169 if (!only_for_side_effects) {
170 instructions += LoadLocal(parsed_function()->receiver_var());
171 }
172 // All closures created inside BuildExpression will have
173 // field.RawOwner() as its owner.
174 closure_owner_ = field.RawOwner();
175 instructions += BuildExpression();
176 closure_owner_ = Object::null();
177 if (only_for_side_effects) {
178 instructions += Drop();
179 } else {
180 instructions += flow_graph_builder_->StoreFieldGuarded(
182 }
183 return instructions;
184}
185
186Fragment StreamingFlowGraphBuilder::BuildLateFieldInitializer(
187 const Field& field,
188 bool has_initializer) {
189 if (has_initializer && PeekTag() == kNullLiteral) {
190 SkipExpression(); // read past the null literal.
191 if (H.thread()->IsDartMutatorThread()) {
192 LeaveCompilerScope cs(H.thread());
193 field.RecordStore(Object::null_object());
194 } else {
195 ASSERT(field.is_nullable_unsafe());
196 }
197 return Fragment();
198 }
199
200 Fragment instructions;
201 instructions += LoadLocal(parsed_function()->receiver_var());
202 instructions += flow_graph_builder_->Constant(Object::sentinel());
203 instructions += flow_graph_builder_->StoreField(
205 return instructions;
206}
207
208Fragment StreamingFlowGraphBuilder::BuildInitializers(
209 const Class& parent_class) {
210 ASSERT(Error::Handle(Z, H.thread()->sticky_error()).IsNull());
211 Fragment instructions;
212
213 // Start by getting the position of the constructors initializer.
214 intptr_t initializers_offset = -1;
215 {
216 AlternativeReadingScope alt(&reader_);
217 SkipFunctionNode(); // read constructors function node.
218 initializers_offset = ReaderOffset();
219 }
220
221 bool is_redirecting_constructor = false;
222
223 // Field which will be initialized by the initializer with the given index.
224 GrowableArray<const Field*> initializer_fields(5);
225
226 // Check if this is a redirecting constructor and collect all fields which
227 // will be initialized by the constructor initializer list.
228 {
229 AlternativeReadingScope alt(&reader_, initializers_offset);
230
231 const intptr_t list_length =
232 ReadListLength(); // read initializers list length.
233 initializer_fields.EnsureLength(list_length, nullptr);
234
235 bool has_field_initializers = false;
236 for (intptr_t i = 0; i < list_length; ++i) {
237 if (PeekTag() == kRedirectingInitializer) {
238 is_redirecting_constructor = true;
239 } else if (PeekTag() == kFieldInitializer) {
240 has_field_initializers = true;
241 ReadTag();
242 ReadBool();
243 ReadPosition();
244 const NameIndex field_name = ReadCanonicalNameReference();
245 const Field& field =
246 Field::Handle(Z, H.LookupFieldByKernelField(field_name));
247 initializer_fields[i] = &field;
249 continue;
250 }
252 }
253 ASSERT(!is_redirecting_constructor || !has_field_initializers);
254 }
255
256 // These come from:
257 //
258 // class A {
259 // var x = (expr);
260 // }
261 //
262 // We don't want to do that when this is a Redirecting Constructors though
263 // (i.e. has a single initializer being of type kRedirectingInitializer).
264 if (!is_redirecting_constructor) {
265 // Sort list of fields (represented as their kernel offsets) which will
266 // be initialized by the constructor initializer list. We will not emit
267 // StoreField instructions for those initializers though we will
268 // still evaluate initialization expression for its side effects.
269 GrowableArray<intptr_t> constructor_initialized_field_offsets(
270 initializer_fields.length());
271 for (auto field : initializer_fields) {
272 if (field != nullptr) {
273 constructor_initialized_field_offsets.Add(field->kernel_offset());
274 }
275 }
276
277 constructor_initialized_field_offsets.Sort(
278 [](const intptr_t* a, const intptr_t* b) {
279 return static_cast<int>(*a) - static_cast<int>(*b);
280 });
281 constructor_initialized_field_offsets.Add(-1);
282
283 auto& kernel_data = TypedDataView::Handle(Z);
284 Array& class_fields = Array::Handle(Z, parent_class.fields());
285 Field& class_field = Field::Handle(Z);
286 intptr_t next_constructor_initialized_field_index = 0;
287 for (intptr_t i = 0; i < class_fields.Length(); ++i) {
288 class_field ^= class_fields.At(i);
289 if (!class_field.is_static()) {
290 const intptr_t field_offset = class_field.kernel_offset();
291
292 // Check if this field will be initialized by the constructor
293 // initializer list.
294 // Note that both class_fields and the list of initialized fields
295 // are sorted by their kernel offset (by construction) -
296 // so we don't need to perform the search.
297 bool is_constructor_initialized = false;
298 const intptr_t constructor_initialized_field_offset =
299 constructor_initialized_field_offsets
300 [next_constructor_initialized_field_index];
301 if (constructor_initialized_field_offset == field_offset) {
302 next_constructor_initialized_field_index++;
303 is_constructor_initialized = true;
304 }
305
306 kernel_data = class_field.KernelLibrary();
307 ASSERT(!kernel_data.IsNull());
308 AlternativeReadingScopeWithNewData alt(&reader_, &kernel_data,
309 field_offset);
310 FieldHelper field_helper(this);
311 field_helper.ReadUntilExcluding(FieldHelper::kInitializer);
312 const Tag initializer_tag = ReadTag();
313 if (class_field.is_late()) {
314 if (!is_constructor_initialized) {
315 instructions += BuildLateFieldInitializer(
316 Field::ZoneHandle(Z, class_field.ptr()),
317 initializer_tag == kSomething);
318 }
319 } else if (initializer_tag == kSomething) {
320 EnterScope(field_offset);
321 // If this field is initialized in constructor then we can ignore the
322 // value produced by the field initializer. However we still need to
323 // execute it for its side effects.
324 instructions += BuildFieldInitializer(
325 Field::ZoneHandle(Z, class_field.ptr()),
326 /*only_for_side_effects=*/is_constructor_initialized);
327 ExitScope(field_offset);
328 }
329 }
330 }
331 }
332
333 // These to come from:
334 // class A {
335 // var x;
336 // var y;
337 // A(this.x) : super(expr), y = (expr);
338 // }
339 {
340 AlternativeReadingScope alt(&reader_, initializers_offset);
341 intptr_t list_length = ReadListLength(); // read initializers list length.
342 for (intptr_t i = 0; i < list_length; ++i) {
343 Tag tag = ReadTag();
344 bool isSynthetic = ReadBool(); // read isSynthetic flag.
345 switch (tag) {
346 case kInvalidInitializer:
348 return Fragment();
349 case kFieldInitializer: {
350 ReadPosition(); // read position.
352 instructions += BuildFieldInitializer(
353 Field::ZoneHandle(Z, initializer_fields[i]->ptr()),
354 /*only_for_size_effects=*/false);
355 break;
356 }
357 case kAssertInitializer: {
358 instructions += BuildStatement();
359 break;
360 }
361 case kSuperInitializer: {
362 TokenPosition position = ReadPosition(); // read position.
363 NameIndex canonical_target =
364 ReadCanonicalNameReference(); // read target_reference.
365
366 instructions += LoadLocal(parsed_function()->receiver_var());
367
368 // TODO(jensj): ASSERT(init->arguments()->types().length() == 0);
369 Array& argument_names = Array::ZoneHandle(Z);
370 intptr_t argument_count;
371 instructions += BuildArguments(
372 &argument_names, &argument_count,
373 /* positional_parameter_count = */ nullptr); // read arguments.
374 argument_count += 1;
375
376 Class& parent_klass = GetSuperOrDie();
377
378 const Function& target = Function::ZoneHandle(
379 Z, H.LookupConstructorByKernelConstructor(
380 parent_klass, H.CanonicalNameString(canonical_target)));
381 instructions += StaticCall(
382 isSynthetic ? TokenPosition::kNoSource : position, target,
383 argument_count, argument_names, ICData::kStatic);
384 instructions += Drop();
385 break;
386 }
387 case kRedirectingInitializer: {
388 TokenPosition position = ReadPosition(); // read position.
389 NameIndex canonical_target =
390 ReadCanonicalNameReference(); // read target_reference.
391
392 instructions += LoadLocal(parsed_function()->receiver_var());
393
394 // TODO(jensj): ASSERT(init->arguments()->types().length() == 0);
395 Array& argument_names = Array::ZoneHandle(Z);
396 intptr_t argument_count;
397 instructions += BuildArguments(
398 &argument_names, &argument_count,
399 /* positional_parameter_count = */ nullptr); // read arguments.
400 argument_count += 1;
401
402 const Function& target = Function::ZoneHandle(
403 Z, H.LookupConstructorByKernelConstructor(canonical_target));
404 instructions += StaticCall(
405 isSynthetic ? TokenPosition::kNoSource : position, target,
406 argument_count, argument_names, ICData::kStatic);
407 instructions += Drop();
408 break;
409 }
410 case kLocalInitializer: {
411 // The other initializers following this one might read the variable.
412 // This is used e.g. for evaluating the arguments to a super call
413 // first, run normal field initializers next and then make the actual
414 // super call:
415 //
416 // The frontend converts
417 //
418 // class A {
419 // var x;
420 // A(a, b) : super(a + b), x = 2*b {}
421 // }
422 //
423 // to
424 //
425 // class A {
426 // var x;
427 // A(a, b) : tmp = a + b, x = 2*b, super(tmp) {}
428 // }
429 //
430 // (This is strictly speaking not what one should do in terms of the
431 // specification but that is how it is currently implemented.)
432 LocalVariable* variable =
433 LookupVariable(ReaderOffset() + data_program_offset_);
434
435 // Variable declaration
436 VariableDeclarationHelper helper(this);
437 helper.ReadUntilExcluding(VariableDeclarationHelper::kInitializer);
438 ASSERT(!helper.IsConst());
439 Tag tag = ReadTag(); // read (first part of) initializer.
440 if (tag != kSomething) {
441 UNREACHABLE();
442 }
443
444 instructions += BuildExpression(); // read initializer.
445 instructions += StoreLocal(TokenPosition::kNoSource, variable);
446 instructions += Drop();
447 break;
448 }
449 default:
450 ReportUnexpectedTag("initializer", tag);
451 UNREACHABLE();
452 }
453 }
454 }
455 return instructions;
456}
457
458Fragment StreamingFlowGraphBuilder::DebugStepCheckInPrologue(
459 const Function& dart_function,
460 TokenPosition position) {
461 if (!NeedsDebugStepCheck(dart_function, position)) {
462 return {};
463 }
464
465 // Place this check at the last parameter to ensure parameters
466 // are in scope in the debugger at method entry.
467 const int parameter_count = dart_function.NumParameters();
468 TokenPosition check_pos = TokenPosition::kNoSource;
469 if (parameter_count > 0) {
470 const LocalVariable& parameter =
471 *parsed_function()->ParameterVariable(parameter_count - 1);
472 check_pos = parameter.token_pos();
473 }
474 if (!check_pos.IsDebugPause()) {
475 // No parameters or synthetic parameters.
476 check_pos = position;
477 ASSERT(check_pos.IsDebugPause());
478 }
479
480 return DebugStepCheck(check_pos);
481}
482
483Fragment StreamingFlowGraphBuilder::TypeArgumentsHandling(
484 const Function& dart_function) {
485 Fragment prologue = B->BuildDefaultTypeHandling(dart_function);
486
487 if (dart_function.IsClosureFunction() &&
488 dart_function.NumParentTypeArguments() > 0) {
489 LocalVariable* closure = parsed_function()->ParameterVariable(0);
490 LocalVariable* fn_type_args = parsed_function()->function_type_arguments();
491 ASSERT(fn_type_args != nullptr && closure != nullptr);
492
493 if (dart_function.IsGeneric()) {
494 prologue += LoadLocal(fn_type_args);
495
496 prologue += LoadLocal(closure);
497 prologue += LoadNativeField(Slot::Closure_function_type_arguments());
498
499 prologue += IntConstant(dart_function.NumParentTypeArguments());
500
501 prologue += IntConstant(dart_function.NumTypeArguments());
502
503 const auto& prepend_function =
504 flow_graph_builder_->PrependTypeArgumentsFunction();
505
506 prologue += StaticCall(TokenPosition::kNoSource, prepend_function, 4,
507 ICData::kStatic);
508 prologue += StoreLocal(TokenPosition::kNoSource, fn_type_args);
509 prologue += Drop();
510 } else {
511 prologue += LoadLocal(closure);
512 prologue += LoadNativeField(Slot::Closure_function_type_arguments());
513 prologue += StoreLocal(TokenPosition::kNoSource, fn_type_args);
514 prologue += Drop();
515 }
516 }
517
518 return prologue;
519}
520
521Fragment StreamingFlowGraphBuilder::CheckStackOverflowInPrologue(
522 const Function& dart_function) {
523 if (dart_function.is_native()) return {};
524 return B->CheckStackOverflowInPrologue(dart_function.token_pos());
525}
526
527Fragment StreamingFlowGraphBuilder::SetupCapturedParameters(
528 const Function& dart_function) {
529 Fragment body;
530 const LocalScope* scope = parsed_function()->scope();
531 if (scope->num_context_variables() > 0) {
532 body += flow_graph_builder_->PushContext(scope);
533 LocalVariable* context = MakeTemporary();
534
535 // Copy captured parameters from the stack into the context.
536 LocalScope* scope = parsed_function()->scope();
537 intptr_t parameter_count = dart_function.NumParameters();
538 const ParsedFunction& pf = *flow_graph_builder_->parsed_function_;
539 const Function& function = pf.function();
540
541 for (intptr_t i = 0; i < parameter_count; ++i) {
542 LocalVariable* variable = pf.ParameterVariable(i);
543 if (variable->is_captured()) {
544 LocalVariable& raw_parameter = *pf.RawParameterVariable(i);
545 ASSERT((function.MakesCopyOfParameters() &&
546 raw_parameter.owner() == scope) ||
547 (!function.MakesCopyOfParameters() &&
548 raw_parameter.owner() == nullptr));
549 ASSERT(!raw_parameter.is_captured());
550
551 // Copy the parameter from the stack to the context.
552 body += LoadLocal(context);
553 body += LoadLocal(&raw_parameter);
554 body += flow_graph_builder_->StoreNativeField(
555 Slot::GetContextVariableSlotFor(thread(), *variable),
557 }
558 }
559 body += Drop(); // The context.
560 }
561 return body;
562}
563
564Fragment StreamingFlowGraphBuilder::InitSuspendableFunction(
565 const Function& dart_function,
566 const AbstractType* emitted_value_type) {
567 Fragment body;
568 if (dart_function.IsAsyncFunction()) {
569 ASSERT(emitted_value_type != nullptr);
570 auto& type_args = TypeArguments::ZoneHandle(Z, TypeArguments::New(1));
571 type_args.SetTypeAt(0, *emitted_value_type);
572 type_args = Class::Handle(Z, IG->object_store()->future_class())
573 .GetInstanceTypeArguments(H.thread(), type_args);
574 body += TranslateInstantiatedTypeArguments(type_args);
575 body += B->Call1ArgStub(TokenPosition::kNoSource,
577 body += Drop();
578 } else if (dart_function.IsAsyncGenerator()) {
579 ASSERT(emitted_value_type != nullptr);
580 auto& type_args = TypeArguments::ZoneHandle(Z, TypeArguments::New(1));
581 type_args.SetTypeAt(0, *emitted_value_type);
582 type_args = Class::Handle(Z, IG->object_store()->stream_class())
583 .GetInstanceTypeArguments(H.thread(), type_args);
584 body += TranslateInstantiatedTypeArguments(type_args);
585 body += B->Call1ArgStub(TokenPosition::kNoSource,
587 body += Drop();
588 body += NullConstant();
589 body += B->Suspend(TokenPosition::kNoSource,
591 body += Drop();
592 } else if (dart_function.IsSyncGenerator()) {
593 ASSERT(emitted_value_type != nullptr);
594 auto& type_args = TypeArguments::ZoneHandle(Z, TypeArguments::New(1));
595 type_args.SetTypeAt(0, *emitted_value_type);
596 type_args = Class::Handle(Z, IG->object_store()->iterable_class())
597 .GetInstanceTypeArguments(H.thread(), type_args);
598 body += TranslateInstantiatedTypeArguments(type_args);
599 body += B->Call1ArgStub(TokenPosition::kNoSource,
601 body += Drop();
602 body += NullConstant();
603 body += B->Suspend(TokenPosition::kNoSource,
605 body += Drop();
606 // Clone context if there are any captured parameter variables, so
607 // each invocation of .iterator would get its own copy of parameters.
608 const LocalScope* scope = parsed_function()->scope();
609 if (scope->num_context_variables() > 0) {
610 body += CloneContext(scope->context_slots());
611 }
612 } else {
613 ASSERT(emitted_value_type == nullptr);
614 }
615 return body;
616}
617
618Fragment StreamingFlowGraphBuilder::ShortcutForUserDefinedEquals(
619 const Function& dart_function,
620 LocalVariable* first_parameter) {
621 // The specification defines the result of `a == b` to be:
622 //
623 // a) if either side is `null` then the result is `identical(a, b)`.
624 // b) else the result is `a.operator==(b)`
625 //
626 // For user-defined implementations of `operator==` we need therefore
627 // implement the handling of a).
628 //
629 // The default `operator==` implementation in `Object` is implemented in terms
630 // of identical (which we assume here!) which means that case a) is actually
631 // included in b). So we just use the normal implementation in the body.
632 Fragment body;
633 if ((dart_function.NumParameters() == 2) &&
634 (dart_function.name() == Symbols::EqualOperator().ptr()) &&
635 (dart_function.Owner() != IG->object_store()->object_class())) {
636 TargetEntryInstr* null_entry;
637 TargetEntryInstr* non_null_entry;
638
639 body += LoadLocal(first_parameter);
640 body += BranchIfNull(&null_entry, &non_null_entry);
641
642 // The argument was `null` and the receiver is not the null class (we only
643 // go into this branch for user-defined == operators) so we can return
644 // false.
645 Fragment null_fragment(null_entry);
646 null_fragment += Constant(Bool::False());
647 null_fragment += Return(dart_function.end_token_pos());
648
649 body = Fragment(body.entry, non_null_entry);
650 }
651 return body;
652}
653
654Fragment StreamingFlowGraphBuilder::BuildFunctionBody(
655 const Function& dart_function,
656 LocalVariable* first_parameter,
657 bool constructor) {
658 Fragment body;
659
660 // TODO(27590): Currently the [VariableDeclaration]s from the
661 // initializers will be visible inside the entire body of the constructor.
662 // We should make a separate scope for them.
663 if (constructor) {
664 body += BuildInitializers(Class::Handle(Z, dart_function.Owner()));
665 }
666
667 if (body.is_closed()) return body;
668
669 FunctionNodeHelper function_node_helper(this);
670 function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kBody);
671
672 const bool has_body = ReadTag() == kSomething; // read first part of body.
673
674 if (dart_function.is_old_native()) {
675 body += B->NativeFunctionBody(dart_function, first_parameter);
676 } else if (dart_function.is_ffi_native()) {
677 body += B->FfiNativeFunctionBody(dart_function);
678 } else if (dart_function.is_external()) {
679 body += ThrowNoSuchMethodError(TokenPosition::kNoSource, dart_function,
680 /*incompatible_arguments=*/false);
681 body += ThrowException(TokenPosition::kNoSource); // Close graph.
682 } else if (has_body) {
683 body += BuildStatement();
684 }
685
686 if (body.is_open()) {
687 if (parsed_function()->function().IsSyncGenerator()) {
688 // Return false from sync* function to indicate the end of iteration.
689 body += Constant(Bool::False());
690 } else {
691 body += NullConstant();
692 }
693 body += Return(dart_function.end_token_pos());
694 }
695
696 return body;
697}
698
699Fragment StreamingFlowGraphBuilder::BuildRegularFunctionPrologue(
700 const Function& dart_function,
701 TokenPosition token_position,
702 LocalVariable* first_parameter) {
703 Fragment F;
704 F += CheckStackOverflowInPrologue(dart_function);
705 F += DebugStepCheckInPrologue(dart_function, token_position);
706 F += B->InitConstantParameters();
707 F += SetupCapturedParameters(dart_function);
708 F += ShortcutForUserDefinedEquals(dart_function, first_parameter);
709 return F;
710}
711
712Fragment StreamingFlowGraphBuilder::ClearRawParameters(
713 const Function& dart_function) {
714 const ParsedFunction& pf = *flow_graph_builder_->parsed_function_;
715 Fragment code;
716 for (intptr_t i = 0; i < dart_function.NumParameters(); ++i) {
717 LocalVariable* variable = pf.ParameterVariable(i);
718
719 if (!variable->is_captured()) continue;
720
721 // Captured 'this' is immutable, so within the outer method we don't need to
722 // load it from the context. Therefore we don't reset it to null.
723 if (pf.function().HasThisParameter() && pf.has_receiver_var() &&
724 variable == pf.receiver_var()) {
725 ASSERT(i == 0);
726 continue;
727 }
728
729 variable = pf.RawParameterVariable(i);
730 code += NullConstant();
731 code += StoreLocal(TokenPosition::kNoSource, variable);
732 code += Drop();
733 }
734 return code;
735}
736
737UncheckedEntryPointStyle StreamingFlowGraphBuilder::ChooseEntryPointStyle(
738 const Function& dart_function,
739 const Fragment& implicit_type_checks,
740 const Fragment& regular_function_prologue,
741 const Fragment& type_args_handling) {
742 ASSERT(!dart_function.IsImplicitClosureFunction());
743 if (!dart_function.MayHaveUncheckedEntryPoint() ||
744 implicit_type_checks.is_empty()) {
746 }
747
748 // Record which entry-point was taken into a variable and test it later if
749 // either:
750 //
751 // 1. There is a non-empty PrologueBuilder-prologue.
752 //
753 // 2. The regular function prologue has more than two instructions
754 // (DebugStepCheck and CheckStackOverflow).
755 //
756 if (!PrologueBuilder::HasEmptyPrologue(dart_function) ||
757 !type_args_handling.is_empty()) {
759 }
760 Instruction* instr = regular_function_prologue.entry;
761 if (instr != nullptr && instr->IsCheckStackOverflow()) {
762 instr = instr->next();
763 }
764 if (instr != nullptr && instr->IsDebugStepCheck()) {
765 instr = instr->next();
766 }
767 if (instr != nullptr) {
769 }
770
772}
773
774FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfFunction(
775 bool is_constructor) {
776 const Function& dart_function = parsed_function()->function();
777
778 LocalVariable* first_parameter = nullptr;
779 TokenPosition token_position = TokenPosition::kNoSource;
780 const AbstractType* emitted_value_type = nullptr;
781 {
782 AlternativeReadingScope alt(&reader_);
783 FunctionNodeHelper function_node_helper(this);
784 function_node_helper.ReadUntilExcluding(
786 {
787 AlternativeReadingScope alt2(&reader_);
788 intptr_t list_length = ReadListLength(); // read number of positionals.
789 if (list_length > 0) {
790 intptr_t first_parameter_offset = ReaderOffset() + data_program_offset_;
791 first_parameter = LookupVariable(first_parameter_offset);
792 }
793 }
794 token_position = function_node_helper.position_;
795 if (dart_function.IsSuspendableFunction()) {
796 function_node_helper.ReadUntilExcluding(
798 if (ReadTag() == kSomething) {
799 emitted_value_type = &T.BuildType(); // read emitted value type.
800 } else {
801 UNREACHABLE();
802 }
803 }
804 }
805
806 auto graph_entry = flow_graph_builder_->graph_entry_ =
807 new (Z) GraphEntryInstr(*parsed_function(), flow_graph_builder_->osr_id_);
808
809 auto normal_entry = flow_graph_builder_->BuildFunctionEntry(graph_entry);
810 graph_entry->set_normal_entry(normal_entry);
811
812 PrologueInfo prologue_info(-1, -1);
813 BlockEntryInstr* instruction_cursor =
814 flow_graph_builder_->BuildPrologue(normal_entry, &prologue_info);
815
816 const Fragment regular_prologue = BuildRegularFunctionPrologue(
817 dart_function, token_position, first_parameter);
818
819 // TODO(#34162): We can remove the default type handling (and
820 // shorten the prologue type handling sequence) for non-dynamic invocations of
821 // regular methods.
822 const Fragment type_args_handling = TypeArgumentsHandling(dart_function);
823
824 Fragment implicit_type_checks;
825 if (dart_function.NeedsTypeArgumentTypeChecks()) {
826 B->BuildTypeArgumentTypeChecks(
828 &implicit_type_checks);
829 }
830
831 Fragment explicit_type_checks;
832 Fragment implicit_redefinitions;
833 if (dart_function.NeedsArgumentTypeChecks()) {
834 B->BuildArgumentTypeChecks(&explicit_type_checks, &implicit_type_checks,
835 &implicit_redefinitions);
836 }
837
838 // The RawParameter variables should be set to null to avoid retaining more
839 // objects than necessary during GC.
840 const Fragment body =
841 ClearRawParameters(dart_function) +
842 InitSuspendableFunction(dart_function, emitted_value_type) +
843 BuildFunctionBody(dart_function, first_parameter, is_constructor);
844
845 auto extra_entry_point_style =
846 ChooseEntryPointStyle(dart_function, implicit_type_checks,
847 regular_prologue, type_args_handling);
848
849 Fragment function(instruction_cursor);
850 FunctionEntryInstr* extra_entry = nullptr;
851 switch (extra_entry_point_style) {
853 function += regular_prologue + type_args_handling + implicit_type_checks +
854 explicit_type_checks + body;
855 break;
856 }
858 ASSERT(instruction_cursor == normal_entry);
859 ASSERT(type_args_handling.is_empty());
860
861 const Fragment prologue_copy = BuildRegularFunctionPrologue(
862 dart_function, token_position, first_parameter);
863
864 extra_entry = B->BuildSeparateUncheckedEntryPoint(
865 normal_entry,
866 /*normal_prologue=*/regular_prologue + implicit_type_checks,
867 /*extra_prologue=*/prologue_copy,
868 /*shared_prologue=*/explicit_type_checks,
869 /*body=*/body);
870 break;
871 }
873 Fragment prologue(normal_entry, instruction_cursor);
874 prologue += regular_prologue;
875 prologue += type_args_handling;
876 prologue += explicit_type_checks;
877 extra_entry = B->BuildSharedUncheckedEntryPoint(
878 /*shared_prologue_linked_in=*/prologue,
879 /*skippable_checks=*/implicit_type_checks,
880 /*redefinitions_if_skipped=*/implicit_redefinitions,
881 /*body=*/body);
882 break;
883 }
884 }
885 if (extra_entry != nullptr) {
886 B->RecordUncheckedEntryPoint(graph_entry, extra_entry);
887 }
888
889 // When compiling for OSR, use a depth first search to find the OSR
890 // entry and make graph entry jump to it instead of normal entry.
891 // Catch entries are always considered reachable, even if they
892 // become unreachable after OSR.
893 if (flow_graph_builder_->IsCompiledForOsr()) {
894 graph_entry->RelinkToOsrEntry(Z,
895 flow_graph_builder_->last_used_block_id_ + 1);
896 }
897 return new (Z) FlowGraph(
898 *parsed_function(), graph_entry, flow_graph_builder_->last_used_block_id_,
899 prologue_info,
900 FlowGraph::CompilationModeFrom(flow_graph_builder_->optimizing_));
901}
902
904 ASSERT(Error::Handle(Z, H.thread()->sticky_error()).IsNull());
905 ASSERT(flow_graph_builder_ != nullptr);
906
907 const Function& function = parsed_function()->function();
908
909 // Setup an [ActiveClassScope] and an [ActiveMemberScope] which will be used
910 // e.g. for type translation.
911 const Class& klass =
912 Class::Handle(zone_, parsed_function()->function().Owner());
913 Function& outermost_function =
914 Function::Handle(Z, function.GetOutermostFunction());
915
916 ActiveClassScope active_class_scope(active_class(), &klass);
917 ActiveMemberScope active_member(active_class(), &outermost_function);
918 FunctionType& signature = FunctionType::Handle(Z, function.signature());
919 ActiveTypeParametersScope active_type_params(active_class(), function,
920 &signature, Z);
921
922 ParseKernelASTFunction();
923
924 switch (function.kind()) {
925 case UntaggedFunction::kRegularFunction:
926 case UntaggedFunction::kGetterFunction:
927 case UntaggedFunction::kSetterFunction:
928 case UntaggedFunction::kClosureFunction:
929 case UntaggedFunction::kConstructor: {
931 return B->BuildGraphOfRecognizedMethod(function);
932 }
933 return BuildGraphOfFunction(function.IsGenerativeConstructor());
934 }
935 case UntaggedFunction::kImplicitGetter:
936 case UntaggedFunction::kImplicitStaticGetter:
937 case UntaggedFunction::kImplicitSetter: {
938 return B->BuildGraphOfFieldAccessor(function);
939 }
940 case UntaggedFunction::kFieldInitializer:
941 return BuildGraphOfFieldInitializer();
942 case UntaggedFunction::kDynamicInvocationForwarder:
943 return B->BuildGraphOfDynamicInvocationForwarder(function);
944 case UntaggedFunction::kMethodExtractor:
945 return flow_graph_builder_->BuildGraphOfMethodExtractor(function);
946 case UntaggedFunction::kNoSuchMethodDispatcher:
947 return flow_graph_builder_->BuildGraphOfNoSuchMethodDispatcher(function);
948 case UntaggedFunction::kInvokeFieldDispatcher:
949 return flow_graph_builder_->BuildGraphOfInvokeFieldDispatcher(function);
950 case UntaggedFunction::kImplicitClosureFunction:
951 return flow_graph_builder_->BuildGraphOfImplicitClosureFunction(function);
952 case UntaggedFunction::kFfiTrampoline:
953 return flow_graph_builder_->BuildGraphOfFfiTrampoline(function);
954 case UntaggedFunction::kRecordFieldGetter:
955 return flow_graph_builder_->BuildGraphOfRecordFieldGetter(function);
956 case UntaggedFunction::kIrregexpFunction:
957 break;
958 }
959 UNREACHABLE();
960 return nullptr;
961}
962
963void StreamingFlowGraphBuilder::ParseKernelASTFunction() {
964 const Function& function = parsed_function()->function();
965
966 const intptr_t kernel_offset = function.kernel_offset();
967 ASSERT(kernel_offset >= 0);
968
969 SetOffset(kernel_offset);
970
971 // Mark forwarding stubs.
972 switch (function.kind()) {
973 case UntaggedFunction::kRegularFunction:
974 case UntaggedFunction::kImplicitClosureFunction:
975 case UntaggedFunction::kGetterFunction:
976 case UntaggedFunction::kSetterFunction:
977 case UntaggedFunction::kClosureFunction:
978 case UntaggedFunction::kConstructor:
979 case UntaggedFunction::kDynamicInvocationForwarder:
980 ReadForwardingStubTarget(function);
981 break;
982 default:
983 break;
984 }
985
986 set_scopes(parsed_function()->EnsureKernelScopes());
987
988 switch (function.kind()) {
989 case UntaggedFunction::kRegularFunction:
990 case UntaggedFunction::kGetterFunction:
991 case UntaggedFunction::kSetterFunction:
992 case UntaggedFunction::kClosureFunction:
993 case UntaggedFunction::kConstructor:
994 case UntaggedFunction::kImplicitClosureFunction:
996 SetupDefaultParameterValues();
997 break;
998 case UntaggedFunction::kImplicitGetter:
999 case UntaggedFunction::kImplicitStaticGetter:
1000 case UntaggedFunction::kImplicitSetter:
1001 case UntaggedFunction::kFieldInitializer:
1002 case UntaggedFunction::kMethodExtractor:
1003 case UntaggedFunction::kNoSuchMethodDispatcher:
1004 case UntaggedFunction::kInvokeFieldDispatcher:
1005 case UntaggedFunction::kFfiTrampoline:
1006 case UntaggedFunction::kRecordFieldGetter:
1007 break;
1008 case UntaggedFunction::kDynamicInvocationForwarder:
1009 if (PeekTag() != kField) {
1011 SetupDefaultParameterValues();
1012 }
1013 break;
1014 case UntaggedFunction::kIrregexpFunction:
1015 UNREACHABLE();
1016 break;
1017 }
1018}
1019
1020void StreamingFlowGraphBuilder::ReadForwardingStubTarget(
1021 const Function& function) {
1022 if (PeekTag() == kProcedure) {
1023 AlternativeReadingScope alt(&reader_);
1024 ProcedureHelper procedure_helper(this);
1025 procedure_helper.ReadUntilExcluding(ProcedureHelper::kFunction);
1026 if (procedure_helper.IsForwardingStub() && !procedure_helper.IsAbstract()) {
1027 const NameIndex target_name =
1028 procedure_helper.concrete_forwarding_stub_target_;
1029 ASSERT(target_name != NameIndex::kInvalidName);
1030 const String& name = function.IsSetterFunction()
1031 ? H.DartSetterName(target_name)
1032 : H.DartProcedureName(target_name);
1033 const Function* forwarding_target =
1034 &Function::ZoneHandle(Z, H.LookupMethodByMember(target_name, name));
1035 ASSERT(!forwarding_target->IsNull());
1036 parsed_function()->MarkForwardingStub(forwarding_target);
1037 }
1038 }
1039}
1040
1042 SetOffset(kernel_offset);
1043 return BuildStatement(); // read statement.
1044}
1045
1046Fragment StreamingFlowGraphBuilder::BuildExpression(TokenPosition* position) {
1047 ++num_ast_nodes_;
1048 uint8_t payload = 0;
1049 Tag tag = ReadTag(&payload); // read tag.
1050 switch (tag) {
1051 case kInvalidExpression:
1052 return BuildInvalidExpression(position);
1053 case kVariableGet:
1054 return BuildVariableGet(position);
1055 case kSpecializedVariableGet:
1056 return BuildVariableGet(payload, position);
1057 case kVariableSet:
1058 return BuildVariableSet(position);
1059 case kSpecializedVariableSet:
1060 return BuildVariableSet(payload, position);
1061 case kInstanceGet:
1062 return BuildInstanceGet(position);
1063 case kDynamicGet:
1064 return BuildDynamicGet(position);
1065 case kInstanceTearOff:
1066 return BuildInstanceTearOff(position);
1067 case kFunctionTearOff:
1068 // Removed by lowering kernel transformation.
1069 UNREACHABLE();
1070 break;
1071 case kInstanceSet:
1072 return BuildInstanceSet(position);
1073 case kDynamicSet:
1074 return BuildDynamicSet(position);
1075 case kAbstractSuperPropertyGet:
1076 // Abstract super property getters must be converted into super property
1077 // getters during mixin transformation.
1078 UNREACHABLE();
1079 break;
1080 case kAbstractSuperPropertySet:
1081 // Abstract super property setters must be converted into super property
1082 // setters during mixin transformation.
1083 UNREACHABLE();
1084 break;
1085 case kSuperPropertyGet:
1086 return BuildSuperPropertyGet(position);
1087 case kSuperPropertySet:
1088 return BuildSuperPropertySet(position);
1089 case kStaticGet:
1090 return BuildStaticGet(position);
1091 case kStaticSet:
1092 return BuildStaticSet(position);
1093 case kInstanceInvocation:
1094 return BuildMethodInvocation(position, /*is_dynamic=*/false);
1095 case kDynamicInvocation:
1096 return BuildMethodInvocation(position, /*is_dynamic=*/true);
1097 case kLocalFunctionInvocation:
1098 return BuildLocalFunctionInvocation(position);
1099 case kFunctionInvocation:
1100 return BuildFunctionInvocation(position);
1101 case kEqualsCall:
1102 return BuildEqualsCall(position);
1103 case kEqualsNull:
1104 return BuildEqualsNull(position);
1105 case kAbstractSuperMethodInvocation:
1106 // Abstract super method invocations must be converted into super
1107 // method invocations during mixin transformation.
1108 UNREACHABLE();
1109 break;
1110 case kSuperMethodInvocation:
1111 return BuildSuperMethodInvocation(position);
1112 case kStaticInvocation:
1113 return BuildStaticInvocation(position);
1114 case kConstructorInvocation:
1115 return BuildConstructorInvocation(position);
1116 case kNot:
1117 return BuildNot(position);
1118 case kNullCheck:
1119 return BuildNullCheck(position);
1120 case kLogicalExpression:
1121 return BuildLogicalExpression(position);
1122 case kConditionalExpression:
1123 return BuildConditionalExpression(position);
1124 case kStringConcatenation:
1125 return BuildStringConcatenation(position);
1126 case kIsExpression:
1127 return BuildIsExpression(position);
1128 case kAsExpression:
1129 return BuildAsExpression(position);
1130 case kTypeLiteral:
1131 return BuildTypeLiteral(position);
1132 case kThisExpression:
1133 return BuildThisExpression(position);
1134 case kRethrow:
1135 return BuildRethrow(position);
1136 case kThrow:
1137 return BuildThrow(position);
1138 case kListLiteral:
1139 return BuildListLiteral(position);
1140 case kSetLiteral:
1141 // Set literals are currently desugared in the frontend and will not
1142 // reach the VM. See http://dartbug.com/35124 for discussion.
1143 UNREACHABLE();
1144 break;
1145 case kMapLiteral:
1146 return BuildMapLiteral(position);
1147 case kRecordLiteral:
1148 return BuildRecordLiteral(position);
1149 case kRecordIndexGet:
1150 return BuildRecordFieldGet(position, /*is_named=*/false);
1151 case kRecordNameGet:
1152 return BuildRecordFieldGet(position, /*is_named=*/true);
1153 case kFunctionExpression:
1154 return BuildFunctionExpression();
1155 case kLet:
1156 return BuildLet(position);
1157 case kBlockExpression:
1158 return BuildBlockExpression();
1159 case kBigIntLiteral:
1160 return BuildBigIntLiteral(position);
1161 case kStringLiteral:
1162 return BuildStringLiteral(position);
1163 case kSpecializedIntLiteral:
1164 return BuildIntLiteral(payload, position);
1165 case kNegativeIntLiteral:
1166 return BuildIntLiteral(true, position);
1167 case kPositiveIntLiteral:
1168 return BuildIntLiteral(false, position);
1169 case kDoubleLiteral:
1170 return BuildDoubleLiteral(position);
1171 case kTrueLiteral:
1172 return BuildBoolLiteral(true, position);
1173 case kFalseLiteral:
1174 return BuildBoolLiteral(false, position);
1175 case kNullLiteral:
1176 return BuildNullLiteral(position);
1177 case kConstantExpression:
1178 case kFileUriConstantExpression:
1179 return BuildConstantExpression(position, tag);
1180 case kInstantiation:
1181 return BuildPartialTearoffInstantiation(position);
1182 case kLoadLibrary:
1183 return BuildLibraryPrefixAction(position, Symbols::LoadLibrary());
1184 case kCheckLibraryIsLoaded:
1185 return BuildLibraryPrefixAction(position, Symbols::CheckLoaded());
1186 case kAwaitExpression:
1187 return BuildAwaitExpression(position);
1188 case kFileUriExpression:
1189 return BuildFileUriExpression(position);
1190 case kConstStaticInvocation:
1191 case kConstConstructorInvocation:
1192 case kConstListLiteral:
1193 case kConstSetLiteral:
1194 case kConstMapLiteral:
1195 case kSymbolLiteral:
1196 case kListConcatenation:
1197 case kSetConcatenation:
1198 case kMapConcatenation:
1199 case kInstanceCreation:
1200 case kStaticTearOff:
1201 case kSwitchExpression:
1202 case kPatternAssignment:
1203 // These nodes are internal to the front end and
1204 // removed by the constant evaluator.
1205 default:
1206 ReportUnexpectedTag("expression", tag);
1207 UNREACHABLE();
1208 }
1209
1210 return Fragment();
1211}
1212
1213Fragment StreamingFlowGraphBuilder::BuildStatement(TokenPosition* position) {
1214 ++num_ast_nodes_;
1215 Tag tag = ReadTag(); // read tag.
1216 switch (tag) {
1217 case kExpressionStatement:
1218 return BuildExpressionStatement(position);
1219 case kBlock:
1220 return BuildBlock(position);
1221 case kEmptyStatement:
1222 return BuildEmptyStatement();
1223 case kAssertBlock:
1224 return BuildAssertBlock(position);
1225 case kAssertStatement:
1226 return BuildAssertStatement(position);
1227 case kLabeledStatement:
1228 return BuildLabeledStatement(position);
1229 case kBreakStatement:
1230 return BuildBreakStatement(position);
1231 case kWhileStatement:
1232 return BuildWhileStatement(position);
1233 case kDoStatement:
1234 return BuildDoStatement(position);
1235 case kForStatement:
1236 return BuildForStatement(position);
1237 case kSwitchStatement:
1238 return BuildSwitchStatement(position);
1239 case kContinueSwitchStatement:
1240 return BuildContinueSwitchStatement(position);
1241 case kIfStatement:
1242 return BuildIfStatement(position);
1243 case kReturnStatement:
1244 return BuildReturnStatement(position);
1245 case kTryCatch:
1246 return BuildTryCatch(position);
1247 case kTryFinally:
1248 return BuildTryFinally(position);
1249 case kYieldStatement:
1250 return BuildYieldStatement(position);
1251 case kVariableDeclaration:
1252 return BuildVariableDeclaration(position);
1253 case kFunctionDeclaration:
1254 return BuildFunctionDeclaration(position);
1255 case kForInStatement:
1256 case kAsyncForInStatement:
1257 case kIfCaseStatement:
1258 case kPatternSwitchStatement:
1259 case kPatternVariableDeclaration:
1260 // These nodes are internal to the front end and
1261 // removed by the constant evaluator.
1262 default:
1263 ReportUnexpectedTag("statement", tag);
1264 UNREACHABLE();
1265 }
1266 return Fragment();
1267}
1268
1269Fragment StreamingFlowGraphBuilder::BuildStatementWithBranchCoverage(
1270 TokenPosition* position) {
1271 TokenPosition pos = TokenPosition::kNoSource;
1272 Fragment statement = BuildStatement(&pos);
1273 if (position != nullptr) *position = pos;
1274 Fragment covered_statement = flow_graph_builder_->RecordBranchCoverage(pos);
1275 covered_statement += statement;
1276 return covered_statement;
1277}
1278
1280 Tag tag) {
1281 if ((flow_graph_builder_ == nullptr) || (parsed_function() == nullptr)) {
1283 } else {
1284 const auto& script = Script::Handle(Z, Script());
1285 H.ReportError(script, TokenPosition::kNoSource,
1286 "Unexpected tag %d (%s) in %s, expected %s", tag,
1287 Reader::TagName(tag),
1288 parsed_function()->function().ToQualifiedCString(), variant);
1289 }
1290}
1291
1293 return reader_.ReadTag(payload);
1294}
1295
1297 return reader_.PeekTag(payload);
1298}
1299
1303
1307
1308void StreamingFlowGraphBuilder::loop_depth_inc() {
1309 ++flow_graph_builder_->loop_depth_;
1310}
1311
1312void StreamingFlowGraphBuilder::loop_depth_dec() {
1313 --flow_graph_builder_->loop_depth_;
1314}
1315
1316void StreamingFlowGraphBuilder::catch_depth_inc() {
1317 ++flow_graph_builder_->catch_depth_;
1318}
1319
1320void StreamingFlowGraphBuilder::catch_depth_dec() {
1321 --flow_graph_builder_->catch_depth_;
1322}
1323
1324void StreamingFlowGraphBuilder::try_depth_inc() {
1325 ++flow_graph_builder_->try_depth_;
1326}
1327
1328void StreamingFlowGraphBuilder::try_depth_dec() {
1329 --flow_graph_builder_->try_depth_;
1330}
1331
1332intptr_t StreamingFlowGraphBuilder::block_expression_depth() {
1333 return flow_graph_builder_->block_expression_depth_;
1334}
1335
1336void StreamingFlowGraphBuilder::block_expression_depth_inc() {
1337 ++flow_graph_builder_->block_expression_depth_;
1338}
1339
1340void StreamingFlowGraphBuilder::block_expression_depth_dec() {
1341 --flow_graph_builder_->block_expression_depth_;
1342}
1343
1344void StreamingFlowGraphBuilder::synthetic_error_handler_depth_inc() {
1345 ++synthetic_error_handler_depth_;
1346}
1347
1348void StreamingFlowGraphBuilder::synthetic_error_handler_depth_dec() {
1349 --synthetic_error_handler_depth_;
1350}
1351
1352intptr_t StreamingFlowGraphBuilder::CurrentTryIndex() {
1353 return flow_graph_builder_->CurrentTryIndex();
1354}
1355
1356intptr_t StreamingFlowGraphBuilder::AllocateTryIndex() {
1357 return flow_graph_builder_->AllocateTryIndex();
1358}
1359
1360LocalVariable* StreamingFlowGraphBuilder::CurrentException() {
1361 return flow_graph_builder_->CurrentException();
1362}
1363
1364LocalVariable* StreamingFlowGraphBuilder::CurrentStackTrace() {
1365 return flow_graph_builder_->CurrentStackTrace();
1366}
1367
1368CatchBlock* StreamingFlowGraphBuilder::catch_block() {
1369 return flow_graph_builder_->catch_block_;
1370}
1371
1372ActiveClass* StreamingFlowGraphBuilder::active_class() {
1373 return active_class_;
1374}
1375
1376ScopeBuildingResult* StreamingFlowGraphBuilder::scopes() {
1377 return flow_graph_builder_->scopes_;
1378}
1379
1380void StreamingFlowGraphBuilder::set_scopes(ScopeBuildingResult* scope) {
1381 flow_graph_builder_->scopes_ = scope;
1382}
1383
1384ParsedFunction* StreamingFlowGraphBuilder::parsed_function() {
1385 return flow_graph_builder_->parsed_function_;
1386}
1387
1388TryFinallyBlock* StreamingFlowGraphBuilder::try_finally_block() {
1389 return flow_graph_builder_->try_finally_block_;
1390}
1391
1392SwitchBlock* StreamingFlowGraphBuilder::switch_block() {
1393 return flow_graph_builder_->switch_block_;
1394}
1395
1396BreakableBlock* StreamingFlowGraphBuilder::breakable_block() {
1397 return flow_graph_builder_->breakable_block_;
1398}
1399
1400Value* StreamingFlowGraphBuilder::stack() {
1401 return flow_graph_builder_->stack_;
1402}
1403
1404void StreamingFlowGraphBuilder::set_stack(Value* top) {
1405 flow_graph_builder_->stack_ = top;
1406}
1407
1408void StreamingFlowGraphBuilder::Push(Definition* definition) {
1409 flow_graph_builder_->Push(definition);
1410}
1411
1412Value* StreamingFlowGraphBuilder::Pop() {
1413 return flow_graph_builder_->Pop();
1414}
1415
1416Tag StreamingFlowGraphBuilder::PeekArgumentsFirstPositionalTag() {
1417 // read parts of arguments, then go back to before doing so.
1418 AlternativeReadingScope alt(&reader_);
1419 ReadUInt(); // read number of arguments.
1420
1421 SkipListOfDartTypes(); // Read list of types.
1422
1423 // List of positional.
1424 intptr_t list_length = ReadListLength(); // read list length.
1425 if (list_length > 0) {
1426 return ReadTag(); // read first tag.
1427 }
1428
1429 UNREACHABLE();
1430 return kNothing;
1431}
1432
1433const TypeArguments& StreamingFlowGraphBuilder::PeekArgumentsInstantiatedType(
1434 const Class& klass) {
1435 // read parts of arguments, then go back to before doing so.
1436 AlternativeReadingScope alt(&reader_);
1437 ReadUInt(); // read argument count.
1438 intptr_t list_length = ReadListLength(); // read types list length.
1439 return T.BuildInstantiatedTypeArguments(klass, list_length); // read types.
1440}
1441
1442intptr_t StreamingFlowGraphBuilder::PeekArgumentsCount() {
1443 return PeekUInt();
1444}
1445
1446TokenPosition StreamingFlowGraphBuilder::ReadPosition() {
1447 TokenPosition position = KernelReaderHelper::ReadPosition();
1448 if (synthetic_error_handler_depth_ > 0 && position.IsReal()) {
1449 position = TokenPosition::Synthetic(position.Pos());
1450 }
1451 return position;
1452}
1453
1454LocalVariable* StreamingFlowGraphBuilder::LookupVariable(
1455 intptr_t kernel_offset) {
1456 return flow_graph_builder_->LookupVariable(kernel_offset);
1457}
1458
1459LocalVariable* StreamingFlowGraphBuilder::MakeTemporary(const char* suffix) {
1460 return flow_graph_builder_->MakeTemporary(suffix);
1461}
1462
1463Fragment StreamingFlowGraphBuilder::DropTemporary(LocalVariable** variable) {
1464 return flow_graph_builder_->DropTemporary(variable);
1465}
1466
1467Function& StreamingFlowGraphBuilder::FindMatchingFunction(
1468 const Class& klass,
1469 const String& name,
1470 int type_args_len,
1471 int argument_count,
1472 const Array& argument_names) {
1473 // Search the superclass chain for the selector.
1474 ArgumentsDescriptor args_desc(
1476 type_args_len, argument_count, argument_names)));
1477 return Function::Handle(Z,
1479 klass, name, args_desc, /*allow_add=*/false));
1480}
1481
1482bool StreamingFlowGraphBuilder::NeedsDebugStepCheck(const Function& function,
1483 TokenPosition position) {
1484 return flow_graph_builder_->NeedsDebugStepCheck(function, position);
1485}
1486
1487bool StreamingFlowGraphBuilder::NeedsDebugStepCheck(Value* value,
1488 TokenPosition position) {
1489 return flow_graph_builder_->NeedsDebugStepCheck(value, position);
1490}
1491
1492void StreamingFlowGraphBuilder::InlineBailout(const char* reason) {
1493 flow_graph_builder_->InlineBailout(reason);
1494}
1495
1496Fragment StreamingFlowGraphBuilder::DebugStepCheck(TokenPosition position) {
1497 return flow_graph_builder_->DebugStepCheck(position);
1498}
1499
1500Fragment StreamingFlowGraphBuilder::LoadLocal(LocalVariable* variable) {
1501 return flow_graph_builder_->LoadLocal(variable);
1502}
1503
1504IndirectGotoInstr* StreamingFlowGraphBuilder::IndirectGoto(
1505 intptr_t target_count) {
1506 return flow_graph_builder_->IndirectGoto(target_count);
1507}
1508
1509Fragment StreamingFlowGraphBuilder::Return(TokenPosition position) {
1510 return flow_graph_builder_->Return(position,
1511 /*omit_result_type_check=*/false);
1512}
1513
1514Fragment StreamingFlowGraphBuilder::EvaluateAssertion() {
1515 return flow_graph_builder_->EvaluateAssertion();
1516}
1517
1518Fragment StreamingFlowGraphBuilder::RethrowException(TokenPosition position,
1519 int catch_try_index) {
1520 return flow_graph_builder_->RethrowException(position, catch_try_index);
1521}
1522
1523Fragment StreamingFlowGraphBuilder::ThrowNoSuchMethodError(
1524 TokenPosition position,
1525 const Function& target,
1526 bool incompatible_arguments) {
1527 return flow_graph_builder_->ThrowNoSuchMethodError(position, target,
1528 incompatible_arguments);
1529}
1530
1531Fragment StreamingFlowGraphBuilder::Constant(const Object& value) {
1532 return flow_graph_builder_->Constant(value);
1533}
1534
1535Fragment StreamingFlowGraphBuilder::IntConstant(int64_t value) {
1536 return flow_graph_builder_->IntConstant(value);
1537}
1538
1539Fragment StreamingFlowGraphBuilder::LoadStaticField(const Field& field,
1540 bool calls_initializer) {
1541 return flow_graph_builder_->LoadStaticField(field, calls_initializer);
1542}
1543
1544Fragment StreamingFlowGraphBuilder::RedefinitionWithType(
1545 const AbstractType& type) {
1546 return flow_graph_builder_->RedefinitionWithType(type);
1547}
1548
1549Fragment StreamingFlowGraphBuilder::CheckNull(TokenPosition position,
1550 LocalVariable* receiver,
1551 const String& function_name) {
1552 return flow_graph_builder_->CheckNull(position, receiver, function_name);
1553}
1554
1555Fragment StreamingFlowGraphBuilder::StaticCall(TokenPosition position,
1556 const Function& target,
1557 intptr_t argument_count,
1558 ICData::RebindRule rebind_rule) {
1559 if (!target.AreValidArgumentCounts(0, argument_count, 0, nullptr)) {
1560 Fragment instructions;
1561 instructions += DropArguments(argument_count, /*type_args_count=*/0);
1562 instructions += ThrowNoSuchMethodError(position, target,
1563 /*incompatible_arguments=*/true);
1564 return instructions;
1565 }
1566 return flow_graph_builder_->StaticCall(position, target, argument_count,
1567 rebind_rule);
1568}
1569
1570Fragment StreamingFlowGraphBuilder::StaticCall(
1571 TokenPosition position,
1572 const Function& target,
1573 intptr_t argument_count,
1574 const Array& argument_names,
1575 ICData::RebindRule rebind_rule,
1576 const InferredTypeMetadata* result_type,
1577 intptr_t type_args_count,
1578 bool use_unchecked_entry) {
1579 if (!target.AreValidArguments(type_args_count, argument_count, argument_names,
1580 nullptr)) {
1581 Fragment instructions;
1582 instructions += DropArguments(argument_count, type_args_count);
1583 instructions += ThrowNoSuchMethodError(position, target,
1584 /*incompatible_arguments=*/true);
1585 return instructions;
1586 }
1587 return flow_graph_builder_->StaticCall(
1588 position, target, argument_count, argument_names, rebind_rule,
1589 result_type, type_args_count, use_unchecked_entry);
1590}
1591
1592Fragment StreamingFlowGraphBuilder::StaticCallMissing(
1593 TokenPosition position,
1594 const String& selector,
1595 intptr_t argument_count,
1598 Fragment instructions;
1599 instructions += DropArguments(argument_count, /*type_args_count=*/0);
1600 instructions += flow_graph_builder_->ThrowNoSuchMethodError(
1601 position, selector, level, kind);
1602 return instructions;
1603}
1604
1605Fragment StreamingFlowGraphBuilder::InstanceCall(
1606 TokenPosition position,
1607 const String& name,
1608 Token::Kind kind,
1609 intptr_t argument_count,
1610 intptr_t checked_argument_count) {
1611 const intptr_t kTypeArgsLen = 0;
1612 return flow_graph_builder_->InstanceCall(position, name, kind, kTypeArgsLen,
1613 argument_count, Array::null_array(),
1614 checked_argument_count);
1615}
1616
1617Fragment StreamingFlowGraphBuilder::InstanceCall(
1618 TokenPosition position,
1619 const String& name,
1620 Token::Kind kind,
1621 intptr_t type_args_len,
1622 intptr_t argument_count,
1623 const Array& argument_names,
1624 intptr_t checked_argument_count,
1625 const Function& interface_target,
1626 const Function& tearoff_interface_target,
1627 const InferredTypeMetadata* result_type,
1628 bool use_unchecked_entry,
1629 const CallSiteAttributesMetadata* call_site_attrs,
1630 bool receiver_is_not_smi,
1631 bool is_call_on_this) {
1632 return flow_graph_builder_->InstanceCall(
1633 position, name, kind, type_args_len, argument_count, argument_names,
1634 checked_argument_count, interface_target, tearoff_interface_target,
1635 result_type, use_unchecked_entry, call_site_attrs, receiver_is_not_smi,
1636 is_call_on_this);
1637}
1638
1639Fragment StreamingFlowGraphBuilder::ThrowException(TokenPosition position) {
1640 return flow_graph_builder_->ThrowException(position);
1641}
1642
1643Fragment StreamingFlowGraphBuilder::BooleanNegate() {
1644 return flow_graph_builder_->BooleanNegate();
1645}
1646
1647Fragment StreamingFlowGraphBuilder::TranslateInstantiatedTypeArguments(
1648 const TypeArguments& type_arguments) {
1649 return flow_graph_builder_->TranslateInstantiatedTypeArguments(
1650 type_arguments);
1651}
1652
1653Fragment StreamingFlowGraphBuilder::StrictCompare(TokenPosition position,
1654 Token::Kind kind,
1655 bool number_check) {
1656 return flow_graph_builder_->StrictCompare(position, kind, number_check);
1657}
1658
1659Fragment StreamingFlowGraphBuilder::AllocateObject(TokenPosition position,
1660 const Class& klass,
1661 intptr_t argument_count) {
1662 return flow_graph_builder_->AllocateObject(position, klass, argument_count);
1663}
1664
1665Fragment StreamingFlowGraphBuilder::AllocateContext(
1666 const ZoneGrowableArray<const Slot*>& context_slots) {
1667 return flow_graph_builder_->AllocateContext(context_slots);
1668}
1669
1670Fragment StreamingFlowGraphBuilder::LoadNativeField(
1671 const Slot& field,
1672 InnerPointerAccess loads_inner_pointer) {
1673 return flow_graph_builder_->LoadNativeField(field, loads_inner_pointer);
1674}
1675
1676Fragment StreamingFlowGraphBuilder::StoreLocal(TokenPosition position,
1677 LocalVariable* variable) {
1678 return flow_graph_builder_->StoreLocal(position, variable);
1679}
1680
1681Fragment StreamingFlowGraphBuilder::StoreStaticField(TokenPosition position,
1682 const Field& field) {
1683 return flow_graph_builder_->StoreStaticField(position, field);
1684}
1685
1686Fragment StreamingFlowGraphBuilder::StringInterpolate(TokenPosition position) {
1687 return flow_graph_builder_->StringInterpolate(position);
1688}
1689
1690Fragment StreamingFlowGraphBuilder::StringInterpolateSingle(
1691 TokenPosition position) {
1692 return flow_graph_builder_->StringInterpolateSingle(position);
1693}
1694
1695Fragment StreamingFlowGraphBuilder::ThrowTypeError() {
1696 return flow_graph_builder_->ThrowTypeError();
1697}
1698
1699Fragment StreamingFlowGraphBuilder::LoadInstantiatorTypeArguments() {
1700 return flow_graph_builder_->LoadInstantiatorTypeArguments();
1701}
1702
1703Fragment StreamingFlowGraphBuilder::LoadFunctionTypeArguments() {
1704 return flow_graph_builder_->LoadFunctionTypeArguments();
1705}
1706
1707Fragment StreamingFlowGraphBuilder::InstantiateType(const AbstractType& type) {
1708 return flow_graph_builder_->InstantiateType(type);
1709}
1710
1711Fragment StreamingFlowGraphBuilder::CreateArray() {
1712 return flow_graph_builder_->CreateArray();
1713}
1714
1715Fragment StreamingFlowGraphBuilder::StoreIndexed(intptr_t class_id) {
1716 return flow_graph_builder_->StoreIndexed(class_id);
1717}
1718
1719Fragment StreamingFlowGraphBuilder::CheckStackOverflow(TokenPosition position) {
1720 return flow_graph_builder_->CheckStackOverflow(
1721 position, flow_graph_builder_->GetStackDepth(),
1722 flow_graph_builder_->loop_depth_);
1723}
1724
1725Fragment StreamingFlowGraphBuilder::CloneContext(
1726 const ZoneGrowableArray<const Slot*>& context_slots) {
1727 return flow_graph_builder_->CloneContext(context_slots);
1728}
1729
1730Fragment StreamingFlowGraphBuilder::TranslateFinallyFinalizers(
1731 TryFinallyBlock* outer_finally,
1732 intptr_t target_context_depth) {
1733 // TranslateFinallyFinalizers can move the readers offset.
1734 // Save the current position and restore it afterwards.
1735 AlternativeReadingScope alt(&reader_);
1736
1737 // Save context.
1738 TryFinallyBlock* const saved_finally_block = B->try_finally_block_;
1739 TryCatchBlock* const saved_try_catch_block = B->CurrentTryCatchBlock();
1740 const intptr_t saved_context_depth = B->context_depth_;
1741 const ProgramState state(B->breakable_block_, B->switch_block_,
1742 B->loop_depth_, B->try_depth_, B->catch_depth_,
1743 B->block_expression_depth_);
1744
1745 Fragment instructions;
1746
1747 // While translating the body of a finalizer we need to set the try-finally
1748 // block which is active when translating the body.
1749 while (B->try_finally_block_ != outer_finally) {
1750 ASSERT(B->try_finally_block_ != nullptr);
1751 // Adjust program context to finalizer's position.
1752 B->try_finally_block_->state().assignTo(B);
1753
1754 // Potentially restore the context to what is expected for the finally
1755 // block.
1756 instructions += B->AdjustContextTo(B->try_finally_block_->context_depth());
1757
1758 // The to-be-translated finalizer has to have the correct try-index (namely
1759 // the one outside the try-finally block).
1760 bool changed_try_index = false;
1761 intptr_t target_try_index = B->try_finally_block_->try_index();
1762 while (B->CurrentTryIndex() != target_try_index) {
1763 B->SetCurrentTryCatchBlock(B->CurrentTryCatchBlock()->outer());
1764 changed_try_index = true;
1765 }
1766 if (changed_try_index) {
1767 JoinEntryInstr* entry = BuildJoinEntry();
1768 instructions += Goto(entry);
1769 instructions = Fragment(instructions.entry, entry);
1770 }
1771
1772 intptr_t finalizer_kernel_offset =
1773 B->try_finally_block_->finalizer_kernel_offset();
1774 B->try_finally_block_ = B->try_finally_block_->outer();
1775 instructions += BuildStatementAt(finalizer_kernel_offset);
1776
1777 // We only need to make sure that if the finalizer ended normally, we
1778 // continue towards the next outer try-finally.
1779 if (!instructions.is_open()) break;
1780 }
1781
1782 if (instructions.is_open() && target_context_depth != -1) {
1783 // A target context depth of -1 indicates that the code after this
1784 // will not care about the context chain so we can leave it any way we
1785 // want after the last finalizer. That is used when returning.
1786 instructions += B->AdjustContextTo(target_context_depth);
1787 }
1788
1789 // Restore.
1790 B->try_finally_block_ = saved_finally_block;
1791 B->SetCurrentTryCatchBlock(saved_try_catch_block);
1792 B->context_depth_ = saved_context_depth;
1793 state.assignTo(B);
1794
1795 return instructions;
1796}
1797
1798Fragment StreamingFlowGraphBuilder::BranchIfTrue(
1799 TargetEntryInstr** then_entry,
1800 TargetEntryInstr** otherwise_entry,
1801 bool negate) {
1802 return flow_graph_builder_->BranchIfTrue(then_entry, otherwise_entry, negate);
1803}
1804
1805Fragment StreamingFlowGraphBuilder::BranchIfEqual(
1806 TargetEntryInstr** then_entry,
1807 TargetEntryInstr** otherwise_entry,
1808 bool negate) {
1809 return flow_graph_builder_->BranchIfEqual(then_entry, otherwise_entry,
1810 negate);
1811}
1812
1813Fragment StreamingFlowGraphBuilder::BranchIfNull(
1814 TargetEntryInstr** then_entry,
1815 TargetEntryInstr** otherwise_entry,
1816 bool negate) {
1817 return flow_graph_builder_->BranchIfNull(then_entry, otherwise_entry, negate);
1818}
1819
1820Fragment StreamingFlowGraphBuilder::CatchBlockEntry(const Array& handler_types,
1821 intptr_t handler_index,
1822 bool needs_stacktrace,
1823 bool is_synthesized) {
1824 return flow_graph_builder_->CatchBlockEntry(handler_types, handler_index,
1825 needs_stacktrace, is_synthesized);
1826}
1827
1828Fragment StreamingFlowGraphBuilder::TryCatch(int try_handler_index) {
1829 return flow_graph_builder_->TryCatch(try_handler_index);
1830}
1831
1832Fragment StreamingFlowGraphBuilder::Drop() {
1833 return flow_graph_builder_->Drop();
1834}
1835
1836Fragment StreamingFlowGraphBuilder::DropArguments(intptr_t argument_count,
1837 intptr_t type_args_count) {
1838 Fragment instructions;
1839 for (intptr_t i = 0; i < argument_count; i++) {
1840 instructions += Drop();
1841 }
1842 if (type_args_count != 0) {
1843 instructions += Drop();
1844 }
1845 return instructions;
1846}
1847
1848Fragment StreamingFlowGraphBuilder::DropTempsPreserveTop(
1849 intptr_t num_temps_to_drop) {
1850 return flow_graph_builder_->DropTempsPreserveTop(num_temps_to_drop);
1851}
1852
1853Fragment StreamingFlowGraphBuilder::MakeTemp() {
1854 return flow_graph_builder_->MakeTemp();
1855}
1856
1857Fragment StreamingFlowGraphBuilder::NullConstant() {
1858 return flow_graph_builder_->NullConstant();
1859}
1860
1861JoinEntryInstr* StreamingFlowGraphBuilder::BuildJoinEntry() {
1862 return flow_graph_builder_->BuildJoinEntry();
1863}
1864
1865JoinEntryInstr* StreamingFlowGraphBuilder::BuildJoinEntry(intptr_t try_index) {
1866 return flow_graph_builder_->BuildJoinEntry(try_index);
1867}
1868
1869Fragment StreamingFlowGraphBuilder::Goto(JoinEntryInstr* destination) {
1870 return flow_graph_builder_->Goto(destination);
1871}
1872
1873Fragment StreamingFlowGraphBuilder::CheckBoolean(TokenPosition position) {
1874 return flow_graph_builder_->CheckBoolean(position);
1875}
1876
1877Fragment StreamingFlowGraphBuilder::CheckArgumentType(
1878 LocalVariable* variable,
1879 const AbstractType& type) {
1880 return flow_graph_builder_->CheckAssignable(
1881 type, variable->name(), AssertAssignableInstr::kParameterCheck);
1882}
1883
1884Fragment StreamingFlowGraphBuilder::RecordCoverage(TokenPosition position) {
1885 return flow_graph_builder_->RecordCoverage(position);
1886}
1887
1888Fragment StreamingFlowGraphBuilder::EnterScope(
1889 intptr_t kernel_offset,
1890 const LocalScope** scope /* = nullptr */) {
1891 return flow_graph_builder_->EnterScope(kernel_offset, scope);
1892}
1893
1894Fragment StreamingFlowGraphBuilder::ExitScope(intptr_t kernel_offset) {
1895 return flow_graph_builder_->ExitScope(kernel_offset);
1896}
1897
1898TestFragment StreamingFlowGraphBuilder::TranslateConditionForControl() {
1899 // Skip all negations and go directly to the expression.
1900 bool negate = false;
1901 while (PeekTag() == kNot) {
1902 SkipBytes(1);
1903 ReadPosition();
1904 negate = !negate;
1905 }
1906
1907 TestFragment result;
1908 if (PeekTag() == kLogicalExpression) {
1909 // Handle '&&' and '||' operators specially to implement short circuit
1910 // evaluation.
1911 SkipBytes(1); // tag.
1912 ReadPosition();
1913
1914 TestFragment left = TranslateConditionForControl();
1915 LogicalOperator op = static_cast<LogicalOperator>(ReadByte());
1916 TestFragment right = TranslateConditionForControl();
1917
1918 result.entry = left.entry;
1919 if (op == kAnd) {
1920 left.CreateTrueSuccessor(flow_graph_builder_)->LinkTo(right.entry);
1921 result.true_successor_addresses = right.true_successor_addresses;
1922 result.false_successor_addresses = left.false_successor_addresses;
1923 result.false_successor_addresses->AddArray(
1924 *right.false_successor_addresses);
1925 } else {
1926 ASSERT(op == kOr);
1927 left.CreateFalseSuccessor(flow_graph_builder_)->LinkTo(right.entry);
1928 result.true_successor_addresses = left.true_successor_addresses;
1929 result.true_successor_addresses->AddArray(
1930 *right.true_successor_addresses);
1931 result.false_successor_addresses = right.false_successor_addresses;
1932 }
1933 } else {
1934 // Other expressions.
1935 TokenPosition position = TokenPosition::kNoSource;
1936 Fragment instructions = BuildExpression(&position); // read expression.
1937
1938 // Check if the top of the stack is already a StrictCompare that
1939 // can be merged with a branch. Otherwise compare TOS with
1940 // true value and branch on that.
1941 BranchInstr* branch;
1942 if (stack()->definition()->IsStrictCompare() &&
1943 stack()->definition() == instructions.current) {
1944 StrictCompareInstr* compare = Pop()->definition()->AsStrictCompare();
1945 if (negate) {
1946 compare->NegateComparison();
1947 negate = false;
1948 }
1949 branch =
1950 new (Z) BranchInstr(compare, flow_graph_builder_->GetNextDeoptId());
1951 branch->comparison()->ClearTempIndex();
1952 ASSERT(instructions.current->previous() != nullptr);
1953 instructions.current = instructions.current->previous();
1954 } else {
1955 if (NeedsDebugStepCheck(stack(), position)) {
1956 instructions = DebugStepCheck(position) + instructions;
1957 }
1958 instructions += CheckBoolean(position);
1959 instructions += Constant(Bool::True());
1960 Value* right_value = Pop();
1961 Value* left_value = Pop();
1962 StrictCompareInstr* compare = new (Z) StrictCompareInstr(
1963 InstructionSource(), negate ? Token::kNE_STRICT : Token::kEQ_STRICT,
1964 left_value, right_value, false,
1965 flow_graph_builder_->GetNextDeoptId());
1966 branch =
1967 new (Z) BranchInstr(compare, flow_graph_builder_->GetNextDeoptId());
1968 negate = false;
1969 }
1970 instructions <<= branch;
1971
1972 result = TestFragment(instructions.entry, branch);
1973 }
1974
1975 return result.Negate(negate);
1976}
1977
1978const TypeArguments& StreamingFlowGraphBuilder::BuildTypeArguments() {
1979 ReadUInt(); // read arguments count.
1980 intptr_t type_count = ReadListLength(); // read type count.
1981 return T.BuildTypeArguments(type_count); // read types.
1982}
1983
1984Fragment StreamingFlowGraphBuilder::BuildArguments(Array* argument_names,
1985 intptr_t* argument_count,
1986 intptr_t* positional_count) {
1987 intptr_t dummy;
1988 if (argument_count == nullptr) argument_count = &dummy;
1989 *argument_count = ReadUInt(); // read arguments count.
1990
1991 // List of types.
1992 SkipListOfDartTypes(); // read list of types.
1993
1994 {
1995 AlternativeReadingScope _(&reader_);
1996 if (positional_count == nullptr) positional_count = &dummy;
1997 *positional_count = ReadListLength(); // read length of expression list
1998 }
1999 return BuildArgumentsFromActualArguments(argument_names);
2000}
2001
2002Fragment StreamingFlowGraphBuilder::BuildArgumentsFromActualArguments(
2003 Array* argument_names) {
2004 Fragment instructions;
2005
2006 // List of positional.
2007 intptr_t list_length = ReadListLength(); // read list length.
2008 for (intptr_t i = 0; i < list_length; ++i) {
2009 instructions += BuildExpression(); // read ith expression.
2010 }
2011
2012 // List of named.
2013 list_length = ReadListLength(); // read list length.
2014 if (argument_names != nullptr && list_length > 0) {
2015 *argument_names = Array::New(list_length, Heap::kOld);
2016 }
2017 for (intptr_t i = 0; i < list_length; ++i) {
2018 String& name =
2019 H.DartSymbolObfuscate(ReadStringReference()); // read ith name index.
2020 instructions += BuildExpression(); // read ith expression.
2021 if (argument_names != nullptr) {
2022 argument_names->SetAt(i, name);
2023 }
2024 }
2025
2026 return instructions;
2027}
2028
2029Fragment StreamingFlowGraphBuilder::BuildInvalidExpression(
2030 TokenPosition* position) {
2031 // The frontend will take care of emitting normal errors (like
2032 // [NoSuchMethodError]s) and only emit [InvalidExpression]s in very special
2033 // situations (e.g. an invalid annotation).
2034 TokenPosition pos = ReadPosition();
2035 if (position != nullptr) *position = pos;
2036 const String& message = H.DartString(ReadStringReference());
2037 Tag tag = ReadTag(); // read (first part of) expression.
2038 if (tag == kSomething) {
2039 SkipExpression(); // read (rest of) expression.
2040 }
2041
2042 // Invalid expression message has pointer to the source code, no need to
2043 // report it twice.
2044 const auto& script = Script::Handle(Z, Script());
2045 H.ReportError(script, TokenPosition::kNoSource, "%s", message.ToCString());
2046 return Fragment();
2047}
2048
2049Fragment StreamingFlowGraphBuilder::BuildVariableGet(TokenPosition* position) {
2050 const TokenPosition pos = ReadPosition();
2051 if (position != nullptr) *position = pos;
2052 intptr_t variable_kernel_position = ReadUInt(); // read kernel position.
2053 ReadUInt(); // read relative variable index.
2054 SkipOptionalDartType(); // read promoted type.
2055 return BuildVariableGetImpl(variable_kernel_position, pos);
2056}
2057
2058Fragment StreamingFlowGraphBuilder::BuildVariableGet(uint8_t payload,
2059 TokenPosition* position) {
2060 const TokenPosition pos = ReadPosition();
2061 if (position != nullptr) *position = pos;
2062 intptr_t variable_kernel_position = ReadUInt(); // read kernel position.
2063 return BuildVariableGetImpl(variable_kernel_position, pos);
2064}
2065
2066Fragment StreamingFlowGraphBuilder::BuildVariableGetImpl(
2067 intptr_t variable_kernel_position,
2068 TokenPosition position) {
2069 LocalVariable* variable = LookupVariable(variable_kernel_position);
2070 if (!variable->is_late()) {
2071 return LoadLocal(variable);
2072 }
2073
2074 // Late variable, so check whether it has been initialized already.
2075 Fragment instructions = LoadLocal(variable);
2076 TargetEntryInstr* is_uninitialized;
2077 TargetEntryInstr* is_initialized;
2078 instructions += Constant(Object::sentinel());
2079 instructions += flow_graph_builder_->BranchIfStrictEqual(&is_uninitialized,
2080 &is_initialized);
2081 JoinEntryInstr* join = BuildJoinEntry();
2082
2083 {
2084 AlternativeReadingScope alt(&reader_, variable->late_init_offset());
2085 const bool has_initializer = (ReadTag() != kNothing);
2086
2087 if (has_initializer) {
2088 // If the variable isn't initialized, call the initializer and set it.
2089 Fragment initialize(is_uninitialized);
2090 initialize += BuildExpression();
2091 if (variable->is_final()) {
2092 // Late final variable, so check whether it has been assigned
2093 // during initialization.
2094 initialize += LoadLocal(variable);
2095 TargetEntryInstr* is_uninitialized_after_init;
2096 TargetEntryInstr* is_initialized_after_init;
2097 initialize += Constant(Object::sentinel());
2098 initialize += flow_graph_builder_->BranchIfStrictEqual(
2099 &is_uninitialized_after_init, &is_initialized_after_init);
2100 {
2101 // The variable is uninitialized, so store the initializer result.
2102 Fragment store_result(is_uninitialized_after_init);
2103 store_result += StoreLocal(position, variable);
2104 store_result += Drop();
2105 store_result += Goto(join);
2106 }
2107
2108 {
2109 // Already initialized, so throw a LateInitializationError.
2110 Fragment already_assigned(is_initialized_after_init);
2111 already_assigned += flow_graph_builder_->ThrowLateInitializationError(
2112 position, "_throwLocalAssignedDuringInitialization",
2113 variable->name());
2114 already_assigned += Goto(join);
2115 }
2116 } else {
2117 // Late non-final variable. Store the initializer result.
2118 initialize += StoreLocal(position, variable);
2119 initialize += Drop();
2120 initialize += Goto(join);
2121 }
2122 } else {
2123 // The variable has no initializer, so throw a late initialization error.
2124 Fragment initialize(is_uninitialized);
2125 initialize += flow_graph_builder_->ThrowLateInitializationError(
2126 position, "_throwLocalNotInitialized", variable->name());
2127 initialize += Goto(join);
2128 }
2129 }
2130
2131 {
2132 // Already initialized, so there's nothing to do.
2133 Fragment already_initialized(is_initialized);
2134 already_initialized += Goto(join);
2135 }
2136
2137 Fragment done = Fragment(instructions.entry, join);
2138 done += LoadLocal(variable);
2139 return done;
2140}
2141
2142Fragment StreamingFlowGraphBuilder::BuildVariableSet(TokenPosition* p) {
2143 TokenPosition position = ReadPosition(); // read position.
2144 if (p != nullptr) *p = position;
2145
2146 intptr_t variable_kernel_position = ReadUInt(); // read kernel position.
2147 ReadUInt(); // read relative variable index.
2148 return BuildVariableSetImpl(position, variable_kernel_position);
2149}
2150
2151Fragment StreamingFlowGraphBuilder::BuildVariableSet(uint8_t payload,
2152 TokenPosition* p) {
2153 TokenPosition position = ReadPosition(); // read position.
2154 if (p != nullptr) *p = position;
2155
2156 intptr_t variable_kernel_position = ReadUInt(); // read kernel position.
2157 return BuildVariableSetImpl(position, variable_kernel_position);
2158}
2159
2160Fragment StreamingFlowGraphBuilder::BuildVariableSetImpl(
2161 TokenPosition position,
2162 intptr_t variable_kernel_position) {
2163 Fragment instructions = BuildExpression(); // read expression.
2164 if (NeedsDebugStepCheck(stack(), position)) {
2165 instructions = DebugStepCheck(position) + instructions;
2166 }
2167
2168 LocalVariable* variable = LookupVariable(variable_kernel_position);
2169 if (variable->is_late() && variable->is_final()) {
2170 // Late final variable, so check whether it has been initialized.
2171 LocalVariable* expr_temp = MakeTemporary();
2172 instructions += LoadLocal(variable);
2173 TargetEntryInstr* is_uninitialized;
2174 TargetEntryInstr* is_initialized;
2175 instructions += Constant(Object::sentinel());
2176 instructions += flow_graph_builder_->BranchIfStrictEqual(&is_uninitialized,
2177 &is_initialized);
2178 JoinEntryInstr* join = BuildJoinEntry();
2179
2180 {
2181 // The variable is uninitialized, so store the expression value.
2182 Fragment initialize(is_uninitialized);
2183 initialize += LoadLocal(expr_temp);
2184 initialize += StoreLocal(position, variable);
2185 initialize += Drop();
2186 initialize += Goto(join);
2187 }
2188
2189 {
2190 // Already initialized, so throw a LateInitializationError.
2191 Fragment already_initialized(is_initialized);
2192 already_initialized += flow_graph_builder_->ThrowLateInitializationError(
2193 position, "_throwLocalAlreadyInitialized", variable->name());
2194 already_initialized += Goto(join);
2195 }
2196
2197 instructions = Fragment(instructions.entry, join);
2198 } else {
2199 instructions += StoreLocal(position, variable);
2200 }
2201
2202 return instructions;
2203}
2204
2205Fragment StreamingFlowGraphBuilder::BuildInstanceGet(TokenPosition* p) {
2206 const intptr_t offset = ReaderOffset() - 1; // Include the tag.
2207 ReadByte(); // read kind.
2208 const TokenPosition position = ReadPosition(); // read position.
2209 if (p != nullptr) *p = position;
2210
2211 const DirectCallMetadata direct_call =
2212 direct_call_metadata_helper_.GetDirectTargetForPropertyGet(offset);
2213 const InferredTypeMetadata result_type =
2214 inferred_type_metadata_helper_.GetInferredType(offset);
2215
2216 Fragment instructions = BuildExpression(); // read receiver.
2217 const String& getter_name = ReadNameAsGetterName(); // read name.
2218 SkipDartType(); // read result_type.
2219 const NameIndex itarget_name =
2220 ReadInterfaceMemberNameReference(); // read interface_target_reference.
2221 ASSERT(!H.IsRoot(itarget_name) && H.IsGetter(itarget_name));
2222 const auto& interface_target = Function::ZoneHandle(
2223 Z, H.LookupMethodByMember(itarget_name, H.DartGetterName(itarget_name)));
2224 ASSERT(getter_name.ptr() == interface_target.name());
2225
2226 if (direct_call.check_receiver_for_null_) {
2227 auto receiver = MakeTemporary();
2228 instructions += CheckNull(position, receiver, getter_name);
2229 }
2230
2231 if (!direct_call.target_.IsNull()) {
2232 ASSERT(CompilerState::Current().is_aot());
2233 instructions +=
2234 StaticCall(position, direct_call.target_, 1, Array::null_array(),
2235 ICData::kNoRebind, &result_type);
2236 } else {
2237 const intptr_t kTypeArgsLen = 0;
2238 const intptr_t kNumArgsChecked = 1;
2239 instructions +=
2240 InstanceCall(position, getter_name, Token::kGET, kTypeArgsLen, 1,
2241 Array::null_array(), kNumArgsChecked, interface_target,
2242 Function::null_function(), &result_type);
2243 }
2244
2245 return instructions;
2246}
2247
2248Fragment StreamingFlowGraphBuilder::BuildDynamicGet(TokenPosition* p) {
2249 const intptr_t offset = ReaderOffset() - 1; // Include the tag.
2250 ReadByte(); // read kind.
2251 const TokenPosition position = ReadPosition(); // read position.
2252 if (p != nullptr) *p = position;
2253
2254 const DirectCallMetadata direct_call =
2255 direct_call_metadata_helper_.GetDirectTargetForPropertyGet(offset);
2256 const InferredTypeMetadata result_type =
2257 inferred_type_metadata_helper_.GetInferredType(offset);
2258
2259 Fragment instructions = BuildExpression(); // read receiver.
2260 const String& getter_name = ReadNameAsGetterName(); // read name.
2261 const auto& mangled_name = String::ZoneHandle(
2263 const Function* direct_call_target = &direct_call.target_;
2264 if (!direct_call_target->IsNull()) {
2265 direct_call_target = &Function::ZoneHandle(
2266 direct_call.target_.GetDynamicInvocationForwarder(mangled_name));
2267 }
2268
2269 if (direct_call.check_receiver_for_null_) {
2270 auto receiver = MakeTemporary();
2271 instructions += CheckNull(position, receiver, getter_name);
2272 }
2273
2274 if (!direct_call_target->IsNull()) {
2275 ASSERT(CompilerState::Current().is_aot());
2276 instructions +=
2277 StaticCall(position, *direct_call_target, 1, Array::null_array(),
2278 ICData::kNoRebind, &result_type);
2279 } else {
2280 const intptr_t kTypeArgsLen = 0;
2281 const intptr_t kNumArgsChecked = 1;
2282 instructions += InstanceCall(position, mangled_name, Token::kGET,
2283 kTypeArgsLen, 1, Array::null_array(),
2284 kNumArgsChecked, Function::null_function(),
2285 Function::null_function(), &result_type);
2286 }
2287
2288 return instructions;
2289}
2290
2291Fragment StreamingFlowGraphBuilder::BuildInstanceTearOff(TokenPosition* p) {
2292 const intptr_t offset = ReaderOffset() - 1; // Include the tag.
2293 ReadByte(); // read kind.
2294 const TokenPosition position = ReadPosition(); // read position.
2295 if (p != nullptr) *p = position;
2296
2297 const DirectCallMetadata direct_call =
2298 direct_call_metadata_helper_.GetDirectTargetForPropertyGet(offset);
2299 const InferredTypeMetadata result_type =
2300 inferred_type_metadata_helper_.GetInferredType(offset);
2301
2302 Fragment instructions = BuildExpression(); // read receiver.
2303 const String& getter_name = ReadNameAsGetterName(); // read name.
2304 SkipDartType(); // read result_type.
2305 const NameIndex itarget_name =
2306 ReadInterfaceMemberNameReference(); // read interface_target_reference.
2307 ASSERT(!H.IsRoot(itarget_name) && H.IsMethod(itarget_name));
2308 const auto& tearoff_interface_target = Function::ZoneHandle(
2309 Z, H.LookupMethodByMember(itarget_name, H.DartMethodName(itarget_name)));
2310
2311 if (direct_call.check_receiver_for_null_) {
2312 const auto receiver = MakeTemporary();
2313 instructions += CheckNull(position, receiver, getter_name);
2314 }
2315
2316 if (!direct_call.target_.IsNull()) {
2317 ASSERT(CompilerState::Current().is_aot());
2318 instructions +=
2319 StaticCall(position, direct_call.target_, 1, Array::null_array(),
2320 ICData::kNoRebind, &result_type);
2321 } else {
2322 const intptr_t kTypeArgsLen = 0;
2323 const intptr_t kNumArgsChecked = 1;
2324 instructions += InstanceCall(position, getter_name, Token::kGET,
2325 kTypeArgsLen, 1, Array::null_array(),
2326 kNumArgsChecked, Function::null_function(),
2327 tearoff_interface_target, &result_type);
2328 }
2329
2330 return instructions;
2331}
2332
2333Fragment StreamingFlowGraphBuilder::BuildInstanceSet(TokenPosition* p) {
2334 const intptr_t offset = ReaderOffset() - 1; // Include the tag.
2335 ReadByte(); // read kind.
2336
2337 const DirectCallMetadata direct_call =
2338 direct_call_metadata_helper_.GetDirectTargetForPropertySet(offset);
2339 const CallSiteAttributesMetadata call_site_attributes =
2340 call_site_attributes_metadata_helper_.GetCallSiteAttributes(offset);
2341 const InferredTypeMetadata inferred_type =
2342 inferred_type_metadata_helper_.GetInferredType(offset);
2343
2344 // True if callee can skip argument type checks.
2345 bool is_unchecked_call = inferred_type.IsSkipCheck();
2346 if (call_site_attributes.receiver_type != nullptr &&
2347 call_site_attributes.receiver_type->HasTypeClass() &&
2348 !Class::Handle(call_site_attributes.receiver_type->type_class())
2349 .IsGeneric()) {
2350 is_unchecked_call = true;
2351 }
2352
2353 Fragment instructions(MakeTemp());
2354 LocalVariable* variable = MakeTemporary();
2355
2356 const TokenPosition position = ReadPosition(); // read position.
2357 if (p != nullptr) *p = position;
2358
2359 const bool is_call_on_this = PeekTag() == kThisExpression;
2360 if (is_call_on_this) {
2361 is_unchecked_call = true;
2362 }
2363 instructions += BuildExpression(); // read receiver.
2364
2365 LocalVariable* receiver = nullptr;
2366 if (direct_call.check_receiver_for_null_) {
2367 receiver = MakeTemporary();
2368 }
2369
2370 const String& setter_name = ReadNameAsSetterName(); // read name.
2371
2372 instructions += BuildExpression(); // read value.
2373 instructions += StoreLocal(TokenPosition::kNoSource, variable);
2374
2375 const NameIndex itarget_name =
2376 ReadInterfaceMemberNameReference(); // read interface_target_reference.
2377 ASSERT(!H.IsRoot(itarget_name));
2378 const auto& interface_target = Function::ZoneHandle(
2379 Z, H.LookupMethodByMember(itarget_name, H.DartSetterName(itarget_name)));
2380 ASSERT(setter_name.ptr() == interface_target.name());
2381
2382 if (direct_call.check_receiver_for_null_) {
2383 instructions += CheckNull(position, receiver, setter_name);
2384 }
2385
2386 if (!direct_call.target_.IsNull()) {
2387 ASSERT(CompilerState::Current().is_aot());
2388 instructions +=
2389 StaticCall(position, direct_call.target_, 2, Array::null_array(),
2390 ICData::kNoRebind, /*result_type=*/nullptr,
2391 /*type_args_count=*/0,
2392 /*use_unchecked_entry=*/is_unchecked_call);
2393 } else {
2394 const intptr_t kTypeArgsLen = 0;
2395 const intptr_t kNumArgsChecked = 1;
2396
2397 instructions += InstanceCall(
2398 position, setter_name, Token::kSET, kTypeArgsLen, 2,
2399 Array::null_array(), kNumArgsChecked, interface_target,
2400 Function::null_function(),
2401 /*result_type=*/nullptr,
2402 /*use_unchecked_entry=*/is_unchecked_call, &call_site_attributes,
2403 /*receiver_not_smi=*/false, is_call_on_this);
2404 }
2405
2406 instructions += Drop(); // Drop result of the setter invocation.
2407
2408 return instructions;
2409}
2410
2411Fragment StreamingFlowGraphBuilder::BuildDynamicSet(TokenPosition* p) {
2412 const intptr_t offset = ReaderOffset() - 1; // Include the tag.
2413 ReadByte(); // read kind.
2414
2415 const DirectCallMetadata direct_call =
2416 direct_call_metadata_helper_.GetDirectTargetForPropertySet(offset);
2417 const InferredTypeMetadata inferred_type =
2418 inferred_type_metadata_helper_.GetInferredType(offset);
2419
2420 // True if callee can skip argument type checks.
2421 const bool is_unchecked_call = inferred_type.IsSkipCheck();
2422
2423 Fragment instructions(MakeTemp());
2424 LocalVariable* variable = MakeTemporary();
2425
2426 const TokenPosition position = ReadPosition(); // read position.
2427 if (p != nullptr) *p = position;
2428
2429 instructions += BuildExpression(); // read receiver.
2430
2431 LocalVariable* receiver = nullptr;
2432 if (direct_call.check_receiver_for_null_) {
2433 receiver = MakeTemporary();
2434 }
2435
2436 const String& setter_name = ReadNameAsSetterName(); // read name.
2437
2438 instructions += BuildExpression(); // read value.
2439 instructions += StoreLocal(TokenPosition::kNoSource, variable);
2440
2441 if (direct_call.check_receiver_for_null_) {
2442 instructions += CheckNull(position, receiver, setter_name);
2443 }
2444
2445 const Function* direct_call_target = &direct_call.target_;
2446 const auto& mangled_name = String::ZoneHandle(
2448 if (!direct_call_target->IsNull()) {
2449 direct_call_target = &Function::ZoneHandle(
2450 direct_call.target_.GetDynamicInvocationForwarder(mangled_name));
2451 }
2452
2453 if (!direct_call_target->IsNull()) {
2454 ASSERT(CompilerState::Current().is_aot());
2455 instructions +=
2456 StaticCall(position, *direct_call_target, 2, Array::null_array(),
2457 ICData::kNoRebind, /*result_type=*/nullptr,
2458 /*type_args_count=*/0,
2459 /*use_unchecked_entry=*/is_unchecked_call);
2460 } else {
2461 const intptr_t kTypeArgsLen = 0;
2462 const intptr_t kNumArgsChecked = 1;
2463
2464 instructions += InstanceCall(
2465 position, mangled_name, Token::kSET, kTypeArgsLen, 2,
2466 Array::null_array(), kNumArgsChecked, Function::null_function(),
2467 Function::null_function(),
2468 /*result_type=*/nullptr,
2469 /*use_unchecked_entry=*/is_unchecked_call, /*call_site_attrs=*/nullptr);
2470 }
2471
2472 instructions += Drop(); // Drop result of the setter invocation.
2473
2474 return instructions;
2475}
2476
2478 Zone* zone,
2479 const Class& klass) {
2480 Function& nsm_function = Function::Handle(zone);
2481 Class& iterate_klass = Class::Handle(zone, klass.ptr());
2482 if (!iterate_klass.IsNull() &&
2483 iterate_klass.EnsureIsFinalized(thread) == Error::null()) {
2484 while (!iterate_klass.IsNull()) {
2485 nsm_function = Resolver::ResolveDynamicFunction(zone, iterate_klass,
2486 Symbols::NoSuchMethod());
2487 if (!nsm_function.IsNull() && nsm_function.NumParameters() == 2 &&
2488 nsm_function.NumTypeParameters() == 0) {
2489 break;
2490 }
2491 iterate_klass = iterate_klass.SuperClass();
2492 }
2493 }
2494 // We are guaranteed to find noSuchMethod of class Object.
2495 ASSERT(!nsm_function.IsNull());
2496
2497 return nsm_function;
2498}
2499
2500// Note, that this will always mark `super` flag to true.
2501Fragment StreamingFlowGraphBuilder::BuildAllocateInvocationMirrorCall(
2502 TokenPosition position,
2503 const String& name,
2504 intptr_t num_type_arguments,
2505 intptr_t num_arguments,
2506 const Array& argument_names,
2507 LocalVariable* actuals_array,
2508 Fragment build_rest_of_actuals) {
2509 Fragment instructions;
2510
2511 // Populate array containing the actual arguments. Just add [this] here.
2512 instructions += LoadLocal(actuals_array); // array
2513 instructions += IntConstant(num_type_arguments == 0 ? 0 : 1); // index
2514 instructions += LoadLocal(parsed_function()->receiver_var()); // receiver
2515 instructions += StoreIndexed(kArrayCid);
2516 instructions += build_rest_of_actuals;
2517
2518 // First argument is receiver.
2519 instructions += LoadLocal(parsed_function()->receiver_var());
2520
2521 // Push the arguments for allocating the invocation mirror:
2522 // - the name.
2523 instructions += Constant(String::ZoneHandle(Z, name.ptr()));
2524
2525 // - the arguments descriptor.
2526 const Array& args_descriptor =
2528 num_type_arguments, num_arguments, argument_names));
2529 instructions += Constant(Array::ZoneHandle(Z, args_descriptor.ptr()));
2530
2531 // - an array containing the actual arguments.
2532 instructions += LoadLocal(actuals_array);
2533
2534 // - [true] indicating this is a `super` NoSuchMethod.
2535 instructions += Constant(Bool::True());
2536
2537 const Class& mirror_class =
2538 Class::Handle(Z, Library::LookupCoreClass(Symbols::InvocationMirror()));
2539 ASSERT(!mirror_class.IsNull());
2540 const auto& error = mirror_class.EnsureIsFinalized(thread());
2541 ASSERT(error == Error::null());
2542 const Function& allocation_function = Function::ZoneHandle(
2543 Z, mirror_class.LookupStaticFunction(
2544 Library::PrivateCoreLibName(Symbols::AllocateInvocationMirror())));
2545 ASSERT(!allocation_function.IsNull());
2546 instructions += StaticCall(position, allocation_function,
2547 /* argument_count = */ 4, ICData::kStatic);
2548 return instructions;
2549}
2550
2551Fragment StreamingFlowGraphBuilder::BuildSuperPropertyGet(TokenPosition* p) {
2552 const intptr_t offset = ReaderOffset() - 1; // Include the tag.
2553 const TokenPosition position = ReadPosition(); // read position.
2554 if (p != nullptr) *p = position;
2555
2556 const InferredTypeMetadata result_type =
2557 inferred_type_metadata_helper_.GetInferredType(offset);
2558
2559 Class& klass = GetSuperOrDie();
2560
2561 StringIndex name_index = ReadStringReference(); // read name index.
2562 NameIndex library_reference =
2563 ((H.StringSize(name_index) >= 1) && H.CharacterAt(name_index, 0) == '_')
2564 ? ReadCanonicalNameReference() // read library index.
2565 : NameIndex();
2566 const String& getter_name = H.DartGetterName(library_reference, name_index);
2567 const String& method_name = H.DartMethodName(library_reference, name_index);
2568
2569 SkipInterfaceMemberNameReference(); // skip target_reference.
2570
2571 // Search the superclass chain for the selector looking for either getter or
2572 // method.
2573 Function& function = Function::Handle(Z);
2574 if (!klass.IsNull() && klass.EnsureIsFinalized(thread()) == Error::null()) {
2575 while (!klass.IsNull()) {
2576 function = Resolver::ResolveDynamicFunction(Z, klass, method_name);
2577 if (!function.IsNull()) {
2578 Function& target =
2579 Function::ZoneHandle(Z, function.ImplicitClosureFunction());
2580 ASSERT(!target.IsNull());
2581 // Generate inline code for allocation closure object
2582 // which captures `this`.
2583 return B->BuildImplicitClosureCreation(position, target);
2584 }
2585 function = Resolver::ResolveDynamicFunction(Z, klass, getter_name);
2586 if (!function.IsNull()) break;
2587 klass = klass.SuperClass();
2588 }
2589 }
2590
2591 Fragment instructions;
2592 if (klass.IsNull()) {
2593 instructions +=
2595 instructions += IntConstant(1); // array size
2596 instructions += CreateArray();
2597 LocalVariable* actuals_array = MakeTemporary();
2598
2599 Class& parent_klass = GetSuperOrDie();
2600
2601 instructions += BuildAllocateInvocationMirrorCall(
2602 position, getter_name,
2603 /* num_type_arguments = */ 0,
2604 /* num_arguments = */ 1,
2605 /* argument_names = */ Object::empty_array(), actuals_array,
2606 /* build_rest_of_actuals = */ Fragment());
2607
2608 Function& nsm_function = GetNoSuchMethodOrDie(thread(), Z, parent_klass);
2609 instructions +=
2610 StaticCall(position, Function::ZoneHandle(Z, nsm_function.ptr()),
2611 /* argument_count = */ 2, ICData::kNSMDispatch);
2612 instructions += DropTempsPreserveTop(1); // Drop array
2613 } else {
2614 ASSERT(!klass.IsNull());
2615 ASSERT(!function.IsNull());
2616
2617 instructions += LoadLocal(parsed_function()->receiver_var());
2618
2619 instructions +=
2620 StaticCall(position, Function::ZoneHandle(Z, function.ptr()),
2621 /* argument_count = */ 1, Array::null_array(),
2622 ICData::kSuper, &result_type);
2623 }
2624
2625 return instructions;
2626}
2627
2628Fragment StreamingFlowGraphBuilder::BuildSuperPropertySet(TokenPosition* p) {
2629 const TokenPosition position = ReadPosition(); // read position.
2630 if (p != nullptr) *p = position;
2631
2632 Class& klass = GetSuperOrDie();
2633
2634 const String& setter_name = ReadNameAsSetterName(); // read name.
2635
2636 Function& function = Function::Handle(Z);
2637 if (klass.EnsureIsFinalized(thread()) == Error::null()) {
2638 function = Resolver::ResolveDynamicFunction(Z, klass, setter_name);
2639 }
2640
2641 Fragment instructions(MakeTemp());
2642 LocalVariable* value = MakeTemporary(); // this holds RHS value
2643
2644 if (function.IsNull()) {
2645 instructions +=
2647 instructions += IntConstant(2); // array size
2648 instructions += CreateArray();
2649 LocalVariable* actuals_array = MakeTemporary();
2650
2651 Fragment build_rest_of_actuals;
2652 build_rest_of_actuals += LoadLocal(actuals_array); // array
2653 build_rest_of_actuals += IntConstant(1); // index
2654 build_rest_of_actuals += BuildExpression(); // value.
2655 build_rest_of_actuals += StoreLocal(position, value);
2656 build_rest_of_actuals += StoreIndexed(kArrayCid);
2657
2658 instructions += BuildAllocateInvocationMirrorCall(
2659 position, setter_name, /* num_type_arguments = */ 0,
2660 /* num_arguments = */ 2,
2661 /* argument_names = */ Object::empty_array(), actuals_array,
2662 build_rest_of_actuals);
2663
2664 SkipInterfaceMemberNameReference(); // skip target_reference.
2665
2666 Function& nsm_function = GetNoSuchMethodOrDie(thread(), Z, klass);
2667 instructions +=
2668 StaticCall(position, Function::ZoneHandle(Z, nsm_function.ptr()),
2669 /* argument_count = */ 2, ICData::kNSMDispatch);
2670 instructions += Drop(); // Drop result of NoSuchMethod invocation
2671 instructions += Drop(); // Drop array
2672 } else {
2673 // receiver
2674 instructions += LoadLocal(parsed_function()->receiver_var());
2675
2676 instructions += BuildExpression(); // read value.
2677 instructions += StoreLocal(position, value);
2678
2679 SkipInterfaceMemberNameReference(); // skip target_reference.
2680
2681 instructions += StaticCall(
2682 position, Function::ZoneHandle(Z, function.ptr()),
2683 /* argument_count = */ 2, Array::null_array(), ICData::kSuper,
2684 /*result_type=*/nullptr, /*type_args_len=*/0,
2685 /*use_unchecked_entry=*/true);
2686 instructions += Drop(); // Drop result of the setter invocation.
2687 }
2688
2689 return instructions;
2690}
2691
2692Fragment StreamingFlowGraphBuilder::BuildStaticGet(TokenPosition* p) {
2693 ASSERT(Error::Handle(Z, H.thread()->sticky_error()).IsNull());
2694 const intptr_t offset = ReaderOffset() - 1; // Include the tag.
2695
2696 TokenPosition position = ReadPosition(); // read position.
2697 if (p != nullptr) *p = position;
2698
2699 const InferredTypeMetadata result_type =
2700 inferred_type_metadata_helper_.GetInferredType(offset);
2701
2702 NameIndex target = ReadCanonicalNameReference(); // read target_reference.
2703 ASSERT(H.IsGetter(target));
2704
2705 const Field& field = Field::ZoneHandle(
2706 Z, H.LookupFieldByKernelGetterOrSetter(target, /*required=*/false));
2707 if (!field.IsNull()) {
2708 if (field.is_const()) {
2709 // Since the CFE inlines all references to const variables and fields,
2710 // it never emits a StaticGet of a const field.
2711 // This situation only arises because of the static const fields in
2712 // the ClassID class, which are generated internally in the VM
2713 // during loading. See also Class::InjectCIDFields.
2714 ASSERT(Class::Handle(field.Owner()).library() ==
2716 Class::Handle(field.Owner()).Name() == Symbols::ClassID().ptr());
2717 return Constant(Instance::ZoneHandle(
2718 Z, Instance::RawCast(field.StaticConstFieldValue())));
2719 } else if (field.is_final() && field.has_trivial_initializer()) {
2720 // Final fields with trivial initializers are effectively constant.
2721 return Constant(Instance::ZoneHandle(
2722 Z, Instance::RawCast(field.StaticConstFieldValue())));
2723 } else {
2724 const Class& owner = Class::Handle(Z, field.Owner());
2725 const String& getter_name = H.DartGetterName(target);
2726 const Function& getter =
2727 Function::ZoneHandle(Z, owner.LookupStaticFunction(getter_name));
2728 if (!getter.IsNull() && field.NeedsGetter()) {
2729 return StaticCall(position, getter, 0, Array::null_array(),
2730 ICData::kStatic, &result_type);
2731 } else {
2732 if (result_type.IsConstant()) {
2733 return Constant(result_type.constant_value);
2734 }
2735 return LoadStaticField(field, /*calls_initializer=*/false);
2736 }
2737 }
2738 }
2739
2740 const Function& function = Function::ZoneHandle(
2741 Z, H.LookupStaticMethodByKernelProcedure(target, /*required=*/false));
2742 if (!function.IsNull()) {
2743 if (H.IsGetter(target)) {
2744 return StaticCall(position, function, 0, Array::null_array(),
2745 ICData::kStatic, &result_type);
2746 } else if (H.IsMethod(target)) {
2747 const auto& closure_function =
2748 Function::Handle(Z, function.ImplicitClosureFunction());
2749 const auto& static_closure =
2750 Instance::Handle(Z, closure_function.ImplicitStaticClosure());
2751 return Constant(Instance::ZoneHandle(Z, H.Canonicalize(static_closure)));
2752 } else {
2753 UNIMPLEMENTED();
2754 }
2755 }
2756
2757 return StaticCallMissing(
2758 position, H.DartSymbolPlain(H.CanonicalNameString(target)),
2759 /* argument_count */ 0,
2760 H.IsLibrary(H.EnclosingName(target)) ? InvocationMirror::Level::kTopLevel
2761 : InvocationMirror::Level::kStatic,
2762 InvocationMirror::Kind::kGetter);
2763}
2764
2765Fragment StreamingFlowGraphBuilder::BuildStaticSet(TokenPosition* p) {
2766 TokenPosition position = ReadPosition(); // read position.
2767 if (p != nullptr) *p = position;
2768
2769 NameIndex target = ReadCanonicalNameReference(); // read target_reference.
2770 ASSERT(H.IsSetter(target));
2771
2772 // Evaluate the expression on the right hand side.
2773 Fragment instructions = BuildExpression(); // read expression.
2774
2775 // Look up the target as a setter first and, if not present, as a field
2776 // second. This order is needed to avoid looking up a final field as the
2777 // target.
2778 const Function& function = Function::ZoneHandle(
2779 Z, H.LookupStaticMethodByKernelProcedure(target, /*required=*/false));
2780
2781 if (!function.IsNull()) {
2782 LocalVariable* variable = MakeTemporary();
2783
2784 // Prepare argument.
2785 instructions += LoadLocal(variable);
2786
2787 // Invoke the setter function.
2788 instructions += StaticCall(position, function, 1, ICData::kStatic);
2789
2790 // Drop the unused result & leave the stored value on the stack.
2791 return instructions + Drop();
2792 }
2793
2794 const Field& field = Field::ZoneHandle(
2795 Z, H.LookupFieldByKernelGetterOrSetter(target, /*required=*/false));
2796 if (!field.IsNull()) {
2797 if (NeedsDebugStepCheck(stack(), position)) {
2798 instructions = DebugStepCheck(position) + instructions;
2799 }
2800 LocalVariable* variable = MakeTemporary();
2801 instructions += LoadLocal(variable);
2802 instructions += StoreStaticField(position, field);
2803 return instructions;
2804 }
2805
2806 instructions += StaticCallMissing(
2807 position, H.DartSymbolPlain(H.CanonicalNameString(target)),
2808 /* argument_count */ 1,
2809 H.IsLibrary(H.EnclosingName(target)) ? InvocationMirror::Level::kTopLevel
2810 : InvocationMirror::Level::kStatic,
2811 InvocationMirror::Kind::kSetter);
2812 return instructions;
2813}
2814
2815Fragment StreamingFlowGraphBuilder::BuildMethodInvocation(TokenPosition* p,
2816 bool is_dynamic) {
2817 const intptr_t offset = ReaderOffset() - 1; // Include the tag.
2818 ReadByte(); // read kind.
2819
2820 // read flags.
2821 const uint8_t flags = ReadFlags();
2822 const bool is_invariant = (flags & kInstanceInvocationFlagInvariant) != 0;
2823
2824 const TokenPosition position = ReadPosition(); // read position.
2825 if (p != nullptr) *p = position;
2826
2827 const DirectCallMetadata direct_call =
2828 direct_call_metadata_helper_.GetDirectTargetForMethodInvocation(offset);
2829 const InferredTypeMetadata result_type =
2830 inferred_type_metadata_helper_.GetInferredType(offset);
2831 const CallSiteAttributesMetadata call_site_attributes =
2832 call_site_attributes_metadata_helper_.GetCallSiteAttributes(offset);
2833
2834 const Tag receiver_tag = PeekTag(); // peek tag for receiver.
2835
2836 bool is_unchecked_call = is_invariant || result_type.IsSkipCheck();
2837 if (!is_dynamic && (call_site_attributes.receiver_type != nullptr) &&
2838 call_site_attributes.receiver_type->HasTypeClass() &&
2839 !call_site_attributes.receiver_type->IsDynamicType() &&
2840 !Class::Handle(call_site_attributes.receiver_type->type_class())
2841 .IsGeneric()) {
2842 is_unchecked_call = true;
2843 }
2844
2845 Fragment instructions;
2846
2847 intptr_t type_args_len = 0;
2848 {
2849 AlternativeReadingScope alt(&reader_);
2850 SkipExpression(); // skip receiver
2851 SkipName(); // skip method name
2852 ReadUInt(); // read argument count.
2853 intptr_t list_length = ReadListLength(); // read types list length.
2854 if (list_length > 0) {
2855 const TypeArguments& type_arguments =
2856 T.BuildTypeArguments(list_length); // read types.
2857 instructions += TranslateInstantiatedTypeArguments(type_arguments);
2858 }
2859 type_args_len = list_length;
2860 }
2861
2862 // Take note of whether the invocation is against the receiver of the current
2863 // function: in this case, we may skip some type checks in the callee.
2864 const bool is_call_on_this = (PeekTag() == kThisExpression) && !is_dynamic;
2865 if (is_call_on_this) {
2866 is_unchecked_call = true;
2867 }
2868 instructions += BuildExpression(); // read receiver.
2869
2870 const String& name = ReadNameAsMethodName(); // read name.
2871 const Token::Kind token_kind =
2873
2874 // Detect comparison with null.
2875 if ((token_kind == Token::kEQ || token_kind == Token::kNE) &&
2876 PeekArgumentsCount() == 1 &&
2877 (receiver_tag == kNullLiteral ||
2878 PeekArgumentsFirstPositionalTag() == kNullLiteral)) {
2879 ASSERT(type_args_len == 0);
2880 // "==" or "!=" with null on either side.
2881 instructions +=
2882 BuildArguments(nullptr /* named */, nullptr /* arg count */,
2883 nullptr /* positional arg count */); // read arguments.
2884 SkipInterfaceMemberNameReference(); // read interface_target_reference.
2885 Token::Kind strict_cmp_kind =
2886 token_kind == Token::kEQ ? Token::kEQ_STRICT : Token::kNE_STRICT;
2887 return instructions +
2888 StrictCompare(position, strict_cmp_kind, /*number_check = */ true);
2889 }
2890
2891 LocalVariable* receiver_temp = nullptr;
2892 if (direct_call.check_receiver_for_null_) {
2893 receiver_temp = MakeTemporary();
2894 }
2895
2896 intptr_t argument_count;
2897 intptr_t positional_argument_count;
2898 Array& argument_names = Array::ZoneHandle(Z);
2899 instructions +=
2900 BuildArguments(&argument_names, &argument_count,
2901 &positional_argument_count); // read arguments.
2902 ++argument_count; // include receiver
2903
2904 intptr_t checked_argument_count = 1;
2905 // If we have a special operation (e.g. +/-/==) we mark both arguments as
2906 // to be checked.
2907 if (token_kind != Token::kILLEGAL) {
2908 ASSERT(argument_count <= 2);
2909 checked_argument_count = argument_count;
2910 }
2911
2912 if (!is_dynamic) {
2913 SkipDartType(); // read function_type.
2914 }
2915
2916 const Function* interface_target = &Function::null_function();
2917 // read interface_target_reference.
2918 const NameIndex itarget_name =
2919 is_dynamic ? NameIndex() : ReadInterfaceMemberNameReference();
2920 // TODO(dartbug.com/34497): Once front-end desugars calls via
2921 // fields/getters, filtering of field and getter interface targets here
2922 // can be turned into assertions.
2923 if (!H.IsRoot(itarget_name) && !H.IsGetter(itarget_name)) {
2924 interface_target = &Function::ZoneHandle(
2925 Z, H.LookupMethodByMember(itarget_name,
2926 H.DartProcedureName(itarget_name)));
2927 ASSERT(name.ptr() == interface_target->name());
2928 ASSERT(!interface_target->IsGetterFunction());
2929 }
2930
2931 if (direct_call.check_receiver_for_null_) {
2932 instructions += CheckNull(position, receiver_temp, name);
2933 }
2934
2935 const String* mangled_name = &name;
2936 // Do not mangle ==:
2937 // * operator == takes an Object so its either not checked or checked
2938 // at the entry because the parameter is marked covariant, neither of
2939 // those cases require a dynamic invocation forwarder.
2940 const Function* direct_call_target = &direct_call.target_;
2941 if (H.IsRoot(itarget_name) &&
2942 (name.ptr() != Symbols::EqualOperator().ptr())) {
2943 mangled_name = &String::ZoneHandle(
2945 if (!direct_call_target->IsNull()) {
2946 direct_call_target = &Function::ZoneHandle(
2947 direct_call_target->GetDynamicInvocationForwarder(*mangled_name));
2948 }
2949 }
2950
2951 if (!direct_call_target->IsNull()) {
2952 // Even if TFA infers a concrete receiver type, the static type of the
2953 // call-site may still be dynamic and we need to call the dynamic invocation
2954 // forwarder to ensure type-checks are performed.
2955 ASSERT(CompilerState::Current().is_aot());
2956 instructions +=
2957 StaticCall(position, *direct_call_target, argument_count,
2958 argument_names, ICData::kNoRebind, &result_type,
2959 type_args_len, /*use_unchecked_entry=*/is_unchecked_call);
2960 } else {
2961 instructions += InstanceCall(
2962 position, *mangled_name, token_kind, type_args_len, argument_count,
2963 argument_names, checked_argument_count, *interface_target,
2964 Function::null_function(), &result_type,
2965 /*use_unchecked_entry=*/is_unchecked_call, &call_site_attributes,
2966 result_type.ReceiverNotInt(), is_call_on_this);
2967 }
2968
2969 // Later optimization passes assume that result of a x.[]=(...) call is not
2970 // used. We must guarantee this invariant because violation will lead to an
2971 // illegal IL once we replace x.[]=(...) with a sequence that does not
2972 // actually produce any value. See http://dartbug.com/29135 for more details.
2973 if (name.ptr() == Symbols::AssignIndexToken().ptr()) {
2974 instructions += Drop();
2975 instructions += NullConstant();
2976 }
2977
2978 return instructions;
2979}
2980
2981Fragment StreamingFlowGraphBuilder::BuildLocalFunctionInvocation(
2982 TokenPosition* p) {
2983 const intptr_t offset = ReaderOffset() - 1; // Include the tag.
2984 const TokenPosition position = ReadPosition();
2985 if (p != nullptr) *p = position;
2986
2987 const InferredTypeMetadata result_type =
2988 inferred_type_metadata_helper_.GetInferredType(offset);
2989
2990 // read variable kernel position.
2991 const intptr_t variable_kernel_position = ReadUInt();
2992 ReadUInt(); // read relative variable index.
2993
2994 LocalVariable* variable = LookupVariable(variable_kernel_position);
2995 ASSERT(!variable->is_late());
2996
2997 auto& target_function = Function::ZoneHandle(Z);
2998 {
2999 AlternativeReadingScope alt(
3000 &reader_, variable_kernel_position - data_program_offset_);
3002 // FunctionNode follows the variable declaration.
3003 const intptr_t function_node_kernel_offset = ReaderOffset();
3004
3007 parsed_function()->function().GetOutermostFunction()),
3008 function_node_kernel_offset);
3009 RELEASE_ASSERT(!target_function.IsNull());
3010 }
3011
3012 Fragment instructions;
3013
3014 // Type arguments.
3015 intptr_t type_args_len = 0;
3016 {
3017 AlternativeReadingScope alt(&reader_);
3018 ReadUInt(); // read argument count.
3019 intptr_t list_length = ReadListLength(); // read types list length.
3020 if (list_length > 0) {
3021 const TypeArguments& type_arguments =
3022 T.BuildTypeArguments(list_length); // read types.
3023 instructions += TranslateInstantiatedTypeArguments(type_arguments);
3024 }
3025 type_args_len = list_length;
3026 }
3027
3028 // Receiver (closure).
3029 instructions += LoadLocal(variable);
3030
3031 intptr_t argument_count;
3032 intptr_t positional_argument_count;
3033 Array& argument_names = Array::ZoneHandle(Z);
3034 instructions +=
3035 BuildArguments(&argument_names, &argument_count,
3036 &positional_argument_count); // read arguments.
3037 ++argument_count; // include receiver
3038
3039 SkipDartType(); // read function_type.
3040
3041 // Lookup the function in the closure.
3042 instructions += LoadLocal(variable);
3043 if (!FLAG_precompiled_mode) {
3044 instructions += LoadNativeField(Slot::Closure_function());
3045 }
3046 if (parsed_function()->function().is_debuggable()) {
3047 ASSERT(!parsed_function()->function().is_native());
3048 instructions += DebugStepCheck(position);
3049 }
3050 instructions += B->ClosureCall(target_function, position, type_args_len,
3051 argument_count, argument_names, &result_type);
3052 return instructions;
3053}
3054
3055Fragment StreamingFlowGraphBuilder::BuildFunctionInvocation(TokenPosition* p) {
3056 const intptr_t offset = ReaderOffset() - 1; // Include the tag.
3057 const FunctionAccessKind function_access_kind =
3058 static_cast<FunctionAccessKind>(ReadByte()); // read kind.
3059 const TokenPosition position = ReadPosition(); // read position.
3060 if (p != nullptr) *p = position;
3061
3062 const DirectCallMetadata direct_call =
3063 direct_call_metadata_helper_.GetDirectTargetForFunctionInvocation(offset);
3064 const InferredTypeMetadata result_type =
3065 inferred_type_metadata_helper_.GetInferredType(offset);
3066
3067 RELEASE_ASSERT((function_access_kind == FunctionAccessKind::kFunction) ||
3068 (function_access_kind == FunctionAccessKind::kFunctionType));
3069 const bool is_unchecked_closure_call =
3070 (function_access_kind == FunctionAccessKind::kFunctionType);
3071 Fragment instructions;
3072
3073 instructions += BuildExpression(); // read receiver.
3074 LocalVariable* receiver_temp = MakeTemporary();
3075
3076 // Type arguments.
3077 intptr_t type_args_len = 0;
3078 {
3079 AlternativeReadingScope alt(&reader_);
3080 ReadUInt(); // read argument count.
3081 intptr_t list_length = ReadListLength(); // read types list length.
3082 if (list_length > 0) {
3083 const TypeArguments& type_arguments =
3084 T.BuildTypeArguments(list_length); // read types.
3085 instructions += TranslateInstantiatedTypeArguments(type_arguments);
3086 }
3087 type_args_len = list_length;
3088 }
3089
3090 // Receiver (closure).
3091 instructions += LoadLocal(receiver_temp);
3092
3093 intptr_t argument_count;
3094 intptr_t positional_argument_count;
3095 Array& argument_names = Array::ZoneHandle(Z);
3096 instructions +=
3097 BuildArguments(&argument_names, &argument_count,
3098 &positional_argument_count); // read arguments.
3099 ++argument_count; // include receiver
3100
3101 SkipDartType(); // read function_type.
3102
3103 if (is_unchecked_closure_call) {
3104 instructions += CheckNull(position, receiver_temp, Symbols::call());
3105 // Lookup the function in the closure.
3106 instructions += LoadLocal(receiver_temp);
3107 if (!FLAG_precompiled_mode) {
3108 instructions += LoadNativeField(Slot::Closure_function());
3109 }
3110 if (parsed_function()->function().is_debuggable()) {
3111 ASSERT(!parsed_function()->function().is_native());
3112 instructions += DebugStepCheck(position);
3113 }
3114 instructions +=
3115 B->ClosureCall(direct_call.target_, position, type_args_len,
3116 argument_count, argument_names, &result_type);
3117 } else {
3118 instructions += InstanceCall(
3119 position, Symbols::DynamicCall(), Token::kILLEGAL, type_args_len,
3120 argument_count, argument_names, 1, Function::null_function(),
3121 Function::null_function(), &result_type,
3122 /*use_unchecked_entry=*/false, /*call_site_attrs=*/nullptr,
3123 result_type.ReceiverNotInt());
3124 }
3125 instructions += DropTempsPreserveTop(1);
3126 return instructions;
3127}
3128
3129Fragment StreamingFlowGraphBuilder::BuildEqualsCall(TokenPosition* p) {
3130 const intptr_t offset = ReaderOffset() - 1; // Include the tag.
3131 const TokenPosition position = ReadPosition(); // read position.
3132 if (p != nullptr) *p = position;
3133
3134 const DirectCallMetadata direct_call =
3135 direct_call_metadata_helper_.GetDirectTargetForMethodInvocation(offset);
3136 ASSERT(!direct_call.check_receiver_for_null_);
3137 const InferredTypeMetadata result_type =
3138 inferred_type_metadata_helper_.GetInferredType(offset);
3139 const CallSiteAttributesMetadata call_site_attributes =
3140 call_site_attributes_metadata_helper_.GetCallSiteAttributes(offset);
3141
3142 Fragment instructions;
3143 instructions += BuildExpression(); // read left.
3144 instructions += BuildExpression(); // read right.
3145 SkipDartType(); // read function_type.
3146
3147 const NameIndex itarget_name =
3148 ReadInterfaceMemberNameReference(); // read interface_target_reference.
3149 const auto& interface_target = Function::ZoneHandle(
3150 Z,
3151 H.LookupMethodByMember(itarget_name, H.DartProcedureName(itarget_name)));
3152 ASSERT(interface_target.name() == Symbols::EqualOperator().ptr());
3153
3154 const intptr_t kTypeArgsLen = 0;
3155 const intptr_t kNumArgs = 2;
3156 const intptr_t kNumCheckedArgs = 2;
3157
3158 if (!direct_call.target_.IsNull()) {
3159 ASSERT(CompilerState::Current().is_aot());
3160 instructions +=
3161 StaticCall(position, direct_call.target_, kNumArgs, Array::null_array(),
3162 ICData::kNoRebind, &result_type, kTypeArgsLen,
3163 /*use_unchecked_entry=*/true);
3164 } else {
3165 instructions += InstanceCall(
3166 position, Symbols::EqualOperator(), Token::kEQ, kTypeArgsLen, kNumArgs,
3167 Array::null_array(), kNumCheckedArgs, interface_target,
3168 Function::null_function(), &result_type,
3169 /*use_unchecked_entry=*/true, &call_site_attributes,
3170 result_type.ReceiverNotInt());
3171 }
3172
3173 return instructions;
3174}
3175
3176Fragment StreamingFlowGraphBuilder::BuildEqualsNull(TokenPosition* p) {
3177 const TokenPosition position = ReadPosition(); // read position.
3178 if (p != nullptr) *p = position;
3179 Fragment instructions;
3180 instructions += BuildExpression(); // read expression.
3181 instructions += NullConstant();
3182 if (parsed_function()->function().is_debuggable()) {
3183 instructions += DebugStepCheck(position);
3184 }
3185 instructions +=
3186 StrictCompare(position, Token::kEQ_STRICT, /*number_check=*/false);
3187 return instructions;
3188}
3189
3190Fragment StreamingFlowGraphBuilder::BuildSuperMethodInvocation(
3191 TokenPosition* p) {
3192 const intptr_t offset = ReaderOffset() - 1; // Include the tag.
3193 const TokenPosition position = ReadPosition(); // read position.
3194 if (p != nullptr) *p = position;
3195
3196 const InferredTypeMetadata result_type =
3197 inferred_type_metadata_helper_.GetInferredType(offset);
3198
3199 intptr_t type_args_len = 0;
3200 {
3201 AlternativeReadingScope alt(&reader_);
3202 SkipName(); // skip method name
3203 ReadUInt(); // read argument count.
3204 type_args_len = ReadListLength(); // read types list length.
3205 }
3206
3207 Class& klass = GetSuperOrDie();
3208
3209 // Search the superclass chain for the selector.
3210 const String& method_name = ReadNameAsMethodName(); // read name.
3211
3212 // Figure out selector signature.
3213 intptr_t argument_count;
3214 Array& argument_names = Array::Handle(Z);
3215 {
3216 AlternativeReadingScope alt(&reader_);
3219
3221 intptr_t named_list_length = ReadListLength();
3222 argument_names = Array::New(named_list_length, H.allocation_space());
3223 for (intptr_t i = 0; i < named_list_length; i++) {
3224 const String& arg_name = H.DartSymbolObfuscate(ReadStringReference());
3225 argument_names.SetAt(i, arg_name);
3227 }
3228 }
3229
3230 Function& function = FindMatchingFunction(
3231 klass, method_name, type_args_len,
3232 argument_count + 1 /* account for 'this' */, argument_names);
3233
3234 if (function.IsNull()) {
3235 ReadUInt(); // argument count
3236 intptr_t type_list_length = ReadListLength();
3237
3238 Fragment instructions;
3239 instructions +=
3241 instructions += IntConstant(argument_count + 1 /* this */ +
3242 (type_list_length == 0 ? 0 : 1)); // array size
3243 instructions += CreateArray();
3244 LocalVariable* actuals_array = MakeTemporary();
3245
3246 // Call allocationInvocationMirror to get instance of Invocation.
3247 Fragment build_rest_of_actuals;
3248 intptr_t actuals_array_index = 0;
3249 if (type_list_length > 0) {
3250 const TypeArguments& type_arguments =
3251 T.BuildTypeArguments(type_list_length);
3252 build_rest_of_actuals += LoadLocal(actuals_array);
3253 build_rest_of_actuals += IntConstant(actuals_array_index);
3254 build_rest_of_actuals +=
3255 TranslateInstantiatedTypeArguments(type_arguments);
3256 build_rest_of_actuals += StoreIndexed(kArrayCid);
3257 ++actuals_array_index;
3258 }
3259
3260 ++actuals_array_index; // account for 'this'.
3261 // Read arguments
3262 intptr_t list_length = ReadListLength();
3263 intptr_t i = 0;
3264 while (i < list_length) {
3265 build_rest_of_actuals += LoadLocal(actuals_array); // array
3266 build_rest_of_actuals += IntConstant(actuals_array_index + i); // index
3267 build_rest_of_actuals += BuildExpression(); // value.
3268 build_rest_of_actuals += StoreIndexed(kArrayCid);
3269 ++i;
3270 }
3271 // Read named arguments
3272 intptr_t named_list_length = ReadListLength();
3273 if (named_list_length > 0) {
3274 ASSERT(argument_count == list_length + named_list_length);
3275 while ((i - list_length) < named_list_length) {
3277 build_rest_of_actuals += LoadLocal(actuals_array); // array
3278 build_rest_of_actuals += IntConstant(i + actuals_array_index); // index
3279 build_rest_of_actuals += BuildExpression(); // value.
3280 build_rest_of_actuals += StoreIndexed(kArrayCid);
3281 ++i;
3282 }
3283 }
3284 instructions += BuildAllocateInvocationMirrorCall(
3285 position, method_name, type_list_length,
3286 /* num_arguments = */ argument_count + 1, argument_names, actuals_array,
3287 build_rest_of_actuals);
3288
3289 SkipInterfaceMemberNameReference(); // skip target_reference.
3290
3291 Function& nsm_function = GetNoSuchMethodOrDie(thread(), Z, klass);
3292 instructions += StaticCall(TokenPosition::kNoSource,
3293 Function::ZoneHandle(Z, nsm_function.ptr()),
3294 /* argument_count = */ 2, ICData::kNSMDispatch);
3295 instructions += DropTempsPreserveTop(1); // Drop actuals_array temp.
3296 return instructions;
3297 } else {
3298 Fragment instructions;
3299
3300 {
3301 AlternativeReadingScope alt(&reader_);
3302 ReadUInt(); // read argument count.
3303 intptr_t list_length = ReadListLength(); // read types list length.
3304 if (list_length > 0) {
3305 const TypeArguments& type_arguments =
3306 T.BuildTypeArguments(list_length); // read types.
3307 instructions += TranslateInstantiatedTypeArguments(type_arguments);
3308 }
3309 }
3310
3311 // receiver
3312 instructions += LoadLocal(parsed_function()->receiver_var());
3313
3314 Array& argument_names = Array::ZoneHandle(Z);
3315 intptr_t argument_count;
3316 instructions += BuildArguments(
3317 &argument_names, &argument_count,
3318 /* positional_argument_count = */ nullptr); // read arguments.
3319 ++argument_count; // include receiver
3320 SkipInterfaceMemberNameReference(); // interfaceTargetReference
3321 return instructions +
3322 StaticCall(position, Function::ZoneHandle(Z, function.ptr()),
3323 argument_count, argument_names, ICData::kSuper,
3324 &result_type, type_args_len,
3325 /*use_unchecked_entry_point=*/true);
3326 }
3327}
3328
3329Fragment StreamingFlowGraphBuilder::BuildStaticInvocation(TokenPosition* p) {
3330 const intptr_t offset = ReaderOffset() - 1; // Include the tag.
3331 TokenPosition position = ReadPosition(); // read position.
3332 if (p != nullptr) *p = position;
3333
3334 const InferredTypeMetadata result_type =
3335 inferred_type_metadata_helper_.GetInferredType(offset);
3336
3337 NameIndex procedure_reference =
3338 ReadCanonicalNameReference(); // read procedure reference.
3339 intptr_t argument_count = PeekArgumentsCount();
3340 const Function& target =
3341 Function::ZoneHandle(Z, H.LookupStaticMethodByKernelProcedure(
3342 procedure_reference, /*required=*/false));
3343
3344 if (target.IsNull()) {
3345 Fragment instructions;
3346 Array& argument_names = Array::ZoneHandle(Z);
3347 instructions +=
3348 BuildArguments(&argument_names, nullptr /* arg count */,
3349 nullptr /* positional arg count */); // read arguments.
3350 instructions += StaticCallMissing(
3351 position, H.DartSymbolPlain(H.CanonicalNameString(procedure_reference)),
3353 H.IsLibrary(H.EnclosingName(procedure_reference))
3355 : InvocationMirror::Level::kStatic,
3356 InvocationMirror::Kind::kMethod);
3357 return instructions;
3358 }
3359
3360 const Class& klass = Class::ZoneHandle(Z, target.Owner());
3361 if (target.IsGenerativeConstructor() || target.IsFactory()) {
3362 // The VM requires a TypeArguments object as first parameter for
3363 // every factory constructor.
3365 }
3366
3367 if (target.IsCachableIdempotent()) {
3368 return BuildCachableIdempotentCall(position, target);
3369 }
3370
3371 const auto recognized_kind = target.recognized_kind();
3372 switch (recognized_kind) {
3373 case MethodRecognizer::kNativeEffect:
3374 return BuildNativeEffect();
3375 case MethodRecognizer::kReachabilityFence:
3376 return BuildReachabilityFence();
3377 case MethodRecognizer::kFfiCall:
3378 return BuildFfiCall();
3379 case MethodRecognizer::kFfiNativeCallbackFunction:
3380 return BuildFfiNativeCallbackFunction(
3382 case MethodRecognizer::kFfiNativeAddressOf:
3383 return BuildFfiNativeAddressOf();
3384 case MethodRecognizer::kFfiNativeIsolateLocalCallbackFunction:
3385 return BuildFfiNativeCallbackFunction(
3387 case MethodRecognizer::kFfiNativeAsyncCallbackFunction:
3388 return BuildFfiNativeCallbackFunction(FfiCallbackKind::kAsyncCallback);
3389 case MethodRecognizer::kFfiLoadAbiSpecificInt:
3390 return BuildLoadStoreAbiSpecificInt(/*is_store=*/false,
3391 /*at_index=*/false);
3392 case MethodRecognizer::kFfiLoadAbiSpecificIntAtIndex:
3393 return BuildLoadStoreAbiSpecificInt(/*is_store=*/false,
3394 /*at_index=*/true);
3395 case MethodRecognizer::kFfiStoreAbiSpecificInt:
3396 return BuildLoadStoreAbiSpecificInt(/*is_store=*/true,
3397 /*at_index=*/false);
3398 case MethodRecognizer::kFfiStoreAbiSpecificIntAtIndex:
3399 return BuildLoadStoreAbiSpecificInt(/*is_store=*/true, /*at_index=*/true);
3400 default:
3401 break;
3402 }
3403
3404 Fragment instructions;
3405 LocalVariable* instance_variable = nullptr;
3406
3407 const bool special_case_unchecked_cast =
3408 klass.IsTopLevel() && (klass.library() == Library::InternalLibrary()) &&
3409 (target.name() == Symbols::UnsafeCast().ptr());
3410
3411 const bool special_case_identical =
3412 klass.IsTopLevel() && (klass.library() == Library::CoreLibrary()) &&
3413 (target.name() == Symbols::Identical().ptr());
3414
3415 const bool special_case =
3416 special_case_identical || special_case_unchecked_cast;
3417
3418 // If we cross the Kernel -> VM core library boundary, a [StaticInvocation]
3419 // can appear, but the thing we're calling is not a static method, but a
3420 // factory constructor.
3421 // The `H.LookupStaticmethodByKernelProcedure` will potentially resolve to the
3422 // forwarded constructor.
3423 // In that case we'll make an instance and pass it as first argument.
3424 //
3425 // TODO(27590): Get rid of this after we're using core libraries compiled
3426 // into Kernel.
3427 intptr_t type_args_len = 0;
3428 if (target.IsGenerativeConstructor()) {
3429 if (klass.NumTypeArguments() > 0) {
3430 const TypeArguments& type_arguments =
3431 PeekArgumentsInstantiatedType(klass);
3432 instructions += TranslateInstantiatedTypeArguments(type_arguments);
3433 instructions += AllocateObject(position, klass, 1);
3434 } else {
3435 instructions += AllocateObject(position, klass, 0);
3436 }
3437
3438 instance_variable = MakeTemporary();
3439
3440 instructions += LoadLocal(instance_variable);
3441 } else if (target.IsFactory()) {
3442 // The VM requires currently a TypeArguments object as first parameter for
3443 // every factory constructor :-/ !
3444 //
3445 // TODO(27590): Get rid of this after we're using core libraries compiled
3446 // into Kernel.
3447 const TypeArguments& type_arguments = PeekArgumentsInstantiatedType(klass);
3448 instructions += TranslateInstantiatedTypeArguments(type_arguments);
3449 } else if (!special_case) {
3450 AlternativeReadingScope alt(&reader_);
3451 ReadUInt(); // read argument count.
3452 intptr_t list_length = ReadListLength(); // read types list length.
3453 if (list_length > 0) {
3454 const TypeArguments& type_arguments =
3455 T.BuildTypeArguments(list_length); // read types.
3456 instructions += TranslateInstantiatedTypeArguments(type_arguments);
3457 }
3458 type_args_len = list_length;
3459 }
3460
3461 Array& argument_names = Array::ZoneHandle(Z);
3462 instructions +=
3463 BuildArguments(&argument_names, nullptr /* arg count */,
3464 nullptr /* positional arg count */); // read arguments.
3465 ASSERT(!special_case ||
3466 target.AreValidArguments(type_args_len, argument_count, argument_names,
3467 nullptr));
3468
3469 // Special case identical(x, y) call.
3470 // TODO(27590) consider moving this into the inliner and force inline it
3471 // there.
3472 if (special_case_identical) {
3473 ASSERT(argument_count == 2);
3474 instructions +=
3475 StrictCompare(position, Token::kEQ_STRICT, /*number_check=*/true);
3476 } else if (special_case_unchecked_cast) {
3477 // Simply do nothing: the result value is already pushed on the stack.
3478 } else {
3479 instructions += StaticCall(position, target, argument_count, argument_names,
3480 ICData::kStatic, &result_type, type_args_len);
3481 if (target.IsGenerativeConstructor()) {
3482 // Drop the result of the constructor call and leave [instance_variable]
3483 // on top-of-stack.
3484 instructions += Drop();
3485 }
3486
3487 // After reaching debugger(), we automatically do one single-step.
3488 // Ensure this doesn't cause us to exit the current scope.
3489 if (recognized_kind == MethodRecognizer::kDebugger) {
3490 instructions += DebugStepCheck(position);
3491 }
3492 }
3493
3494 return instructions;
3495}
3496
3497Fragment StreamingFlowGraphBuilder::BuildConstructorInvocation(
3498 TokenPosition* p) {
3499 TokenPosition position = ReadPosition(); // read position.
3500 if (p != nullptr) *p = position;
3501
3502 NameIndex kernel_name =
3503 ReadCanonicalNameReference(); // read target_reference.
3504
3505 Class& klass = Class::ZoneHandle(
3506 Z, H.LookupClassByKernelClass(H.EnclosingName(kernel_name),
3507 /*required=*/false));
3508 Fragment instructions;
3509 if (klass.IsNull()) {
3510 Array& argument_names = Array::ZoneHandle(Z);
3511 intptr_t argument_count;
3512 instructions += BuildArguments(
3513 &argument_names, &argument_count,
3514 /* positional_argument_count = */ nullptr); // read arguments.
3515 instructions += StaticCallMissing(
3516 position, H.DartSymbolPlain(H.CanonicalNameString(kernel_name)),
3519 return instructions;
3520 }
3521 const auto& error = klass.EnsureIsFinalized(H.thread());
3522 ASSERT(error == Error::null());
3523
3524 if (klass.NumTypeArguments() > 0) {
3525 if (!klass.IsGeneric()) {
3526 const TypeArguments& type_arguments = TypeArguments::ZoneHandle(
3527 Z, klass.GetDeclarationInstanceTypeArguments());
3528 instructions += Constant(type_arguments);
3529 } else {
3530 const TypeArguments& type_arguments =
3531 PeekArgumentsInstantiatedType(klass);
3532 instructions += TranslateInstantiatedTypeArguments(type_arguments);
3533 }
3534
3535 instructions += AllocateObject(position, klass, 1);
3536 } else {
3537 instructions += AllocateObject(position, klass, 0);
3538 }
3539 LocalVariable* variable = MakeTemporary();
3540
3541 instructions += LoadLocal(variable);
3542
3543 Array& argument_names = Array::ZoneHandle(Z);
3544 intptr_t argument_count;
3545 instructions += BuildArguments(
3546 &argument_names, &argument_count,
3547 /* positional_argument_count = */ nullptr); // read arguments.
3548
3549 const Function& target =
3550 Function::ZoneHandle(Z, H.LookupConstructorByKernelConstructor(
3551 klass, kernel_name, /*required=*/false));
3553
3554 if (target.IsNull()) {
3555 instructions += StaticCallMissing(
3556 position, H.DartSymbolPlain(H.CanonicalNameString(kernel_name)),
3559 } else {
3560 instructions += StaticCall(position, target, argument_count, argument_names,
3561 ICData::kStatic, /* result_type = */ nullptr);
3562 }
3563 return instructions + Drop();
3564}
3565
3566Fragment StreamingFlowGraphBuilder::BuildNot(TokenPosition* p) {
3567 TokenPosition position = ReadPosition();
3568 if (p != nullptr) *p = position;
3569
3570 TokenPosition operand_position = TokenPosition::kNoSource;
3571 Fragment instructions =
3572 BuildExpression(&operand_position); // read expression.
3573 instructions += CheckBoolean(operand_position);
3574 instructions += BooleanNegate();
3575 return instructions;
3576}
3577
3578Fragment StreamingFlowGraphBuilder::BuildNullCheck(TokenPosition* p) {
3579 const TokenPosition position = ReadPosition(); // read position.
3580 if (p != nullptr) *p = position;
3581
3582 TokenPosition operand_position = TokenPosition::kNoSource;
3583 Fragment instructions = BuildExpression(&operand_position);
3584 LocalVariable* expr_temp = MakeTemporary();
3585 instructions += CheckNull(position, expr_temp, String::null_string());
3586
3587 return instructions;
3588}
3589
3590// Translate the logical expression (lhs && rhs or lhs || rhs) in a context
3591// where a value is required.
3592//
3593// Translation accumulates short-circuit exits from logical
3594// subexpressions in the side_exits. These exits are expected to store
3595// true and false into :expr_temp.
3596//
3597// The result of evaluating the last
3598// expression in chain would be stored in :expr_temp directly to avoid
3599// generating graph like:
3600//
3601// if (v) :expr_temp = true; else :expr_temp = false;
3602//
3603// Outer negations are stripped and instead negation is passed down via
3604// negated parameter.
3605Fragment StreamingFlowGraphBuilder::TranslateLogicalExpressionForValue(
3606 bool negated,
3607 TestFragment* side_exits) {
3608 TestFragment left = TranslateConditionForControl().Negate(negated);
3609 LogicalOperator op = static_cast<LogicalOperator>(ReadByte());
3610 if (negated) {
3611 op = (op == kAnd) ? kOr : kAnd;
3612 }
3613
3614 // Short circuit the control flow after the left hand side condition.
3615 if (op == kAnd) {
3616 side_exits->false_successor_addresses->AddArray(
3617 *left.false_successor_addresses);
3618 } else {
3619 side_exits->true_successor_addresses->AddArray(
3620 *left.true_successor_addresses);
3621 }
3622
3623 // Skip negations of the right hand side.
3624 while (PeekTag() == kNot) {
3625 SkipBytes(1);
3626 ReadPosition();
3627 negated = !negated;
3628 }
3629
3630 Fragment right_value(op == kAnd
3631 ? left.CreateTrueSuccessor(flow_graph_builder_)
3632 : left.CreateFalseSuccessor(flow_graph_builder_));
3633
3634 if (PeekTag() == kLogicalExpression) {
3635 SkipBytes(1);
3636 ReadPosition();
3637 // Handle nested logical expressions specially to avoid materializing
3638 // intermediate boolean values.
3639 right_value += TranslateLogicalExpressionForValue(negated, side_exits);
3640 } else {
3641 // Arbitrary expression on the right hand side. Translate it for value.
3642 TokenPosition position = TokenPosition::kNoSource;
3643 right_value += BuildExpression(&position); // read expression.
3644
3645 // Check if the top of the stack is known to be a non-nullable boolean.
3646 // Note that in strong mode we know that any value that reaches here
3647 // is at least a nullable boolean - so there is no need to compare
3648 // with true like in Dart 1.
3649 Definition* top = stack()->definition();
3650 const bool is_bool = top->IsStrictCompare() || top->IsBooleanNegate();
3651 if (!is_bool) {
3652 right_value += CheckBoolean(position);
3653 }
3654 if (negated) {
3655 right_value += BooleanNegate();
3656 }
3657 right_value += StoreLocal(TokenPosition::kNoSource,
3658 parsed_function()->expression_temp_var());
3659 right_value += Drop();
3660 }
3661
3662 return Fragment(left.entry, right_value.current);
3663}
3664
3665Fragment StreamingFlowGraphBuilder::BuildLogicalExpression(TokenPosition* p) {
3666 TokenPosition position = ReadPosition();
3667 if (p != nullptr) *p = position;
3668
3669 TestFragment exits;
3670 exits.true_successor_addresses = new TestFragment::SuccessorAddressArray(2);
3671 exits.false_successor_addresses = new TestFragment::SuccessorAddressArray(2);
3672
3673 JoinEntryInstr* join = BuildJoinEntry();
3674 Fragment instructions =
3675 TranslateLogicalExpressionForValue(/*negated=*/false, &exits);
3676 instructions += Goto(join);
3677
3678 // Generate :expr_temp = true if needed and connect it to true side-exits.
3679 if (!exits.true_successor_addresses->is_empty()) {
3680 Fragment constant_fragment(exits.CreateTrueSuccessor(flow_graph_builder_));
3681 constant_fragment += Constant(Bool::Get(true));
3682 constant_fragment += StoreLocal(TokenPosition::kNoSource,
3683 parsed_function()->expression_temp_var());
3684 constant_fragment += Drop();
3685 constant_fragment += Goto(join);
3686 }
3687
3688 // Generate :expr_temp = false if needed and connect it to false side-exits.
3689 if (!exits.false_successor_addresses->is_empty()) {
3690 Fragment constant_fragment(exits.CreateFalseSuccessor(flow_graph_builder_));
3691 constant_fragment += Constant(Bool::Get(false));
3692 constant_fragment += StoreLocal(TokenPosition::kNoSource,
3693 parsed_function()->expression_temp_var());
3694 constant_fragment += Drop();
3695 constant_fragment += Goto(join);
3696 }
3697
3698 return Fragment(instructions.entry, join) +
3699 LoadLocal(parsed_function()->expression_temp_var());
3700}
3701
3702Fragment StreamingFlowGraphBuilder::BuildConditionalExpression(
3703 TokenPosition* p) {
3704 TokenPosition position = ReadPosition();
3705 if (p != nullptr) *p = position;
3706
3707 TestFragment condition = TranslateConditionForControl(); // read condition.
3708
3709 Value* top = stack();
3710 Fragment then_fragment(condition.CreateTrueSuccessor(flow_graph_builder_));
3711 then_fragment += BuildExpression(); // read then.
3712 then_fragment += StoreLocal(TokenPosition::kNoSource,
3713 parsed_function()->expression_temp_var());
3714 then_fragment += Drop();
3715 ASSERT(stack() == top);
3716
3717 Fragment otherwise_fragment(
3718 condition.CreateFalseSuccessor(flow_graph_builder_));
3719 otherwise_fragment += BuildExpression(); // read otherwise.
3720 otherwise_fragment += StoreLocal(TokenPosition::kNoSource,
3721 parsed_function()->expression_temp_var());
3722 otherwise_fragment += Drop();
3723 ASSERT(stack() == top);
3724
3725 JoinEntryInstr* join = BuildJoinEntry();
3726 then_fragment += Goto(join);
3727 otherwise_fragment += Goto(join);
3728
3729 SkipOptionalDartType(); // read unused static type.
3730
3731 return Fragment(condition.entry, join) +
3732 LoadLocal(parsed_function()->expression_temp_var());
3733}
3734
3735void StreamingFlowGraphBuilder::FlattenStringConcatenation(
3736 PiecesCollector* collector) {
3737 const auto length = ReadListLength();
3738 for (intptr_t i = 0; i < length; ++i) {
3739 const auto offset = reader_.offset();
3740 switch (PeekTag()) {
3741 case kStringLiteral: {
3742 ReadTag();
3743 ReadPosition();
3744 const String& s = H.DartSymbolPlain(ReadStringReference());
3745 // Skip empty strings.
3746 if (!s.Equals("")) {
3747 collector->Add({-1, &s});
3748 }
3749 break;
3750 }
3751 case kStringConcatenation: {
3752 // Flatten by hoisting nested expressions up into the outer concat.
3753 ReadTag();
3754 ReadPosition();
3755 FlattenStringConcatenation(collector);
3756 break;
3757 }
3758 default: {
3759 collector->Add({offset, nullptr});
3761 }
3762 }
3763 }
3764}
3765
3766Fragment StreamingFlowGraphBuilder::BuildStringConcatenation(TokenPosition* p) {
3767 TokenPosition position = ReadPosition();
3768 if (p != nullptr) {
3769 *p = position;
3770 }
3771
3772 // Collect and flatten all pieces of this and any nested StringConcats.
3773 // The result is a single sequence of pieces, potentially flattened to
3774 // a single String.
3775 // The collector will hold concatenated strings and Reader offsets of
3776 // non-string pieces.
3777 PiecesCollector collector(Z, &H);
3778 FlattenStringConcatenation(&collector);
3779 collector.FlushRun();
3780
3781 if (collector.pieces.length() == 1) {
3782 // No need to Interp. a single string, so return string as a Constant:
3783 if (collector.pieces[0].literal != nullptr) {
3784 return Constant(*collector.pieces[0].literal);
3785 }
3786 // A single non-string piece is handle by StringInterpolateSingle:
3787 AlternativeReadingScope scope(&reader_, collector.pieces[0].offset);
3788 Fragment instructions;
3789 instructions += BuildExpression();
3790 instructions += StringInterpolateSingle(position);
3791 return instructions;
3792 }
3793
3794 Fragment instructions;
3795 instructions += Constant(TypeArguments::ZoneHandle(Z));
3796 instructions += IntConstant(collector.pieces.length());
3797 instructions += CreateArray();
3798 LocalVariable* array = MakeTemporary();
3799 for (intptr_t i = 0; i < collector.pieces.length(); ++i) {
3800 // All pieces are now either a concat'd string or an expression we can
3801 // read at a given offset.
3802 if (collector.pieces[i].literal != nullptr) {
3803 instructions += LoadLocal(array);
3804 instructions += IntConstant(i);
3805 instructions += Constant(*collector.pieces[i].literal);
3806 } else {
3807 AlternativeReadingScope scope(&reader_, collector.pieces[i].offset);
3808 instructions += LoadLocal(array);
3809 instructions += IntConstant(i);
3810 instructions += BuildExpression();
3811 }
3812 instructions += StoreIndexed(kArrayCid);
3813 }
3814
3815 instructions += StringInterpolate(position);
3816
3817 return instructions;
3818}
3819
3820Fragment StreamingFlowGraphBuilder::BuildIsTest(TokenPosition position,
3821 const AbstractType& type) {
3822 Fragment instructions;
3823 // The VM does not like an instanceOf call with a dynamic type. We need to
3824 // special case this situation by detecting a top type.
3825 if (type.IsTopTypeForInstanceOf()) {
3826 // Evaluate the expression on the left but ignore its result.
3827 instructions += Drop();
3828
3829 // Let condition be always true.
3830 instructions += Constant(Bool::True());
3831 } else {
3832 // See if simple instanceOf is applicable.
3834 instructions += Constant(type);
3835 instructions += InstanceCall(
3836 position, Library::PrivateCoreLibName(Symbols::_simpleInstanceOf()),
3837 Token::kIS, 2, 2); // 2 checked arguments.
3838 return instructions;
3839 }
3840
3841 if (type.IsRecordType()) {
3842 instructions += BuildRecordIsTest(position, RecordType::Cast(type));
3843 return instructions;
3844 }
3845
3846 if (!type.IsInstantiated(kCurrentClass)) {
3847 instructions += LoadInstantiatorTypeArguments();
3848 } else {
3849 instructions += NullConstant();
3850 }
3851
3852 if (!type.IsInstantiated(kFunctions)) {
3853 instructions += LoadFunctionTypeArguments();
3854 } else {
3855 instructions += NullConstant();
3856 }
3857
3858 instructions += Constant(type);
3859
3860 instructions += InstanceCall(
3861 position, Library::PrivateCoreLibName(Symbols::_instanceOf()),
3862 Token::kIS, 4);
3863 }
3864 return instructions;
3865}
3866
3867Fragment StreamingFlowGraphBuilder::BuildRecordIsTest(TokenPosition position,
3868 const RecordType& type) {
3869 // Type of a record instance depends on the runtime types of all
3870 // its fields, so subtype test cache cannot be used for testing
3871 // record types and runtime call is used.
3872 // So it is more efficient to test each record field separately
3873 // without going to runtime.
3874
3875 Fragment instructions;
3876 JoinEntryInstr* is_true = BuildJoinEntry();
3877 JoinEntryInstr* is_false = BuildJoinEntry();
3878 LocalVariable* instance = MakeTemporary();
3879
3880 // Test if instance is null.
3881 if (type.IsNullable()) {
3882 TargetEntryInstr* is_null;
3883 TargetEntryInstr* not_null;
3884
3885 instructions += LoadLocal(instance);
3886 instructions += BranchIfNull(&is_null, &not_null);
3887 Fragment(is_null) + Goto(is_true);
3888 instructions.current = not_null;
3889 }
3890
3891 // Test if instance is record.
3892 {
3893 TargetEntryInstr* is_record;
3894 TargetEntryInstr* not_record;
3895
3896 instructions += LoadLocal(instance);
3897 instructions += B->LoadClassId();
3898 instructions += IntConstant(kRecordCid);
3899 instructions += BranchIfEqual(&is_record, &not_record);
3900 Fragment(not_record) + Goto(is_false);
3901 instructions.current = is_record;
3902 }
3903
3904 // Test record shape.
3905 {
3906 TargetEntryInstr* same_shape;
3907 TargetEntryInstr* different_shape;
3908
3909 instructions += LoadLocal(instance);
3910 instructions += LoadNativeField(Slot::Record_shape());
3911 instructions += IntConstant(type.shape().AsInt());
3912 instructions += BranchIfEqual(&same_shape, &different_shape);
3913 Fragment(different_shape) + Goto(is_false);
3914 instructions.current = same_shape;
3915 }
3916
3917 // Test each record field
3918 for (intptr_t i = 0, n = type.NumFields(); i < n; ++i) {
3919 TargetEntryInstr* success;
3920 TargetEntryInstr* failure;
3921
3922 instructions += LoadLocal(instance);
3923 instructions += LoadNativeField(Slot::GetRecordFieldSlot(
3924 H.thread(), compiler::target::Record::field_offset(i)));
3925 instructions +=
3926 BuildIsTest(position, AbstractType::ZoneHandle(Z, type.FieldTypeAt(i)));
3927 instructions += Constant(Bool::True());
3928 instructions += BranchIfEqual(&success, &failure);
3929 Fragment(failure) + Goto(is_false);
3930 instructions.current = success;
3931 }
3932
3933 instructions += Goto(is_true);
3934
3935 JoinEntryInstr* join = BuildJoinEntry();
3936 LocalVariable* expr_temp = parsed_function()->expression_temp_var();
3937
3938 instructions.current = is_true;
3939 instructions += Constant(Bool::True());
3940 instructions += StoreLocal(TokenPosition::kNoSource, expr_temp);
3941 instructions += Drop();
3942 instructions += Goto(join);
3943
3944 instructions.current = is_false;
3945 instructions += Constant(Bool::False());
3946 instructions += StoreLocal(TokenPosition::kNoSource, expr_temp);
3947 instructions += Drop();
3948 instructions += Goto(join);
3949
3950 instructions.current = join;
3951 instructions += Drop(); // Instance.
3952 instructions += LoadLocal(expr_temp);
3953
3954 return instructions;
3955}
3956
3957Fragment StreamingFlowGraphBuilder::BuildIsExpression(TokenPosition* p) {
3958 TokenPosition position = ReadPosition(); // read position.
3959 if (p != nullptr) *p = position;
3960
3961 ReadFlags();
3962
3963 Fragment instructions = BuildExpression(); // read operand.
3964
3965 const AbstractType& type = T.BuildType(); // read type.
3966
3967 instructions += BuildIsTest(position, type);
3968 return instructions;
3969}
3970
3971Fragment StreamingFlowGraphBuilder::BuildAsExpression(TokenPosition* p) {
3972 TokenPosition position = ReadPosition(); // read position.
3973 if (p != nullptr) *p = position;
3974
3975 const uint8_t flags = ReadFlags(); // read flags.
3976 const bool is_unchecked_cast = (flags & kAsExpressionFlagUnchecked) != 0;
3977 const bool is_type_error = (flags & kAsExpressionFlagTypeError) != 0;
3978
3979 Fragment instructions = BuildExpression(); // read operand.
3980
3981 const AbstractType& type = T.BuildType(); // read type.
3982 if (is_unchecked_cast ||
3983 (type.IsInstantiated() && type.IsTopTypeForSubtyping())) {
3984 // We already evaluated the operand on the left and just leave it there as
3985 // the result of unchecked cast or `obj as dynamic` expression.
3986 } else {
3987 // We do not care whether the 'as' cast as implicitly added by the frontend
3988 // or explicitly written by the user, in both cases we use an assert
3989 // assignable.
3990 instructions += B->AssertAssignableLoadTypeArguments(
3991 position, type,
3992 is_type_error ? Symbols::Empty() : Symbols::InTypeCast(),
3993 AssertAssignableInstr::kInsertedByFrontend);
3994 }
3995 return instructions;
3996}
3997
3998Fragment StreamingFlowGraphBuilder::BuildTypeLiteral(TokenPosition* position) {
3999 TokenPosition pos = ReadPosition(); // read position.
4000 if (position != nullptr) *position = pos;
4001
4002 const AbstractType& type = T.BuildType(); // read type.
4003 Fragment instructions;
4004 if (type.IsInstantiated()) {
4005 instructions += Constant(type);
4006 } else {
4007 if (!type.IsInstantiated(kCurrentClass)) {
4008 instructions += LoadInstantiatorTypeArguments();
4009 } else {
4010 instructions += NullConstant();
4011 }
4012 if (!type.IsInstantiated(kFunctions)) {
4013 instructions += LoadFunctionTypeArguments();
4014 } else {
4015 instructions += NullConstant();
4016 }
4017 instructions += InstantiateType(type);
4018 }
4019 return instructions;
4020}
4021
4022Fragment StreamingFlowGraphBuilder::BuildThisExpression(
4023 TokenPosition* position) {
4024 ReadPosition(); // ignore file offset.
4025 if (position != nullptr) *position = TokenPosition::kNoSource;
4026
4027 return LoadLocal(parsed_function()->receiver_var());
4028}
4029
4030Fragment StreamingFlowGraphBuilder::BuildRethrow(TokenPosition* p) {
4031 TokenPosition position = ReadPosition(); // read position.
4032 if (p != nullptr) *p = position;
4033
4034 Fragment instructions = DebugStepCheck(position);
4035 instructions += LoadLocal(catch_block()->exception_var());
4036 instructions += LoadLocal(catch_block()->stack_trace_var());
4037 instructions += RethrowException(position, catch_block()->catch_try_index());
4038
4039 return instructions;
4040}
4041
4042Fragment StreamingFlowGraphBuilder::BuildThrow(TokenPosition* p) {
4043 TokenPosition position = ReadPosition(); // read position.
4044 if (p != nullptr) *p = position;
4045
4046 Fragment instructions;
4047
4048 const uint8_t flags = ReadByte();
4049 const bool is_synthetic_error_handler = (flags & kThrowForErrorHandling) != 0;
4050 if (is_synthetic_error_handler) {
4051 synthetic_error_handler_depth_inc();
4052 }
4053
4054 instructions += BuildExpression(); // read expression.
4055
4056 if (NeedsDebugStepCheck(stack(), position)) {
4057 instructions = DebugStepCheck(position) + instructions;
4058 }
4059 instructions += ThrowException(position);
4060 ASSERT(instructions.is_closed());
4061
4062 if (is_synthetic_error_handler) {
4063 synthetic_error_handler_depth_dec();
4064 }
4065
4066 return instructions;
4067}
4068
4069Fragment StreamingFlowGraphBuilder::BuildListLiteral(TokenPosition* p) {
4070 TokenPosition position = ReadPosition(); // read position.
4071 if (p != nullptr) *p = position;
4072
4073 const TypeArguments& type_arguments = T.BuildTypeArguments(1); // read type.
4074 intptr_t length = ReadListLength(); // read list length.
4075 // Note: there will be "length" expressions.
4076
4077 // The type argument for the factory call.
4078 Fragment instructions = TranslateInstantiatedTypeArguments(type_arguments);
4079
4080 // List literals up to 8 elements are lowered in the front-end
4081 // (pkg/vm/lib/transformations/list_literals_lowering.dart)
4082 const intptr_t kNumSpecializedListLiteralConstructors = 8;
4083 ASSERT(length > kNumSpecializedListLiteralConstructors);
4084
4085 LocalVariable* type = MakeTemporary();
4086 instructions += LoadLocal(type);
4087
4088 // The type arguments for CreateArray.
4089 instructions += LoadLocal(type);
4090 instructions += IntConstant(length);
4091 instructions += CreateArray();
4092
4093 LocalVariable* array = MakeTemporary();
4094 for (intptr_t i = 0; i < length; ++i) {
4095 instructions += LoadLocal(array);
4096 instructions += IntConstant(i);
4097 instructions += BuildExpression(); // read ith expression.
4098 instructions += StoreIndexed(kArrayCid);
4099 }
4100
4101 const Class& growable_list_class =
4102 Class::Handle(Z, Library::LookupCoreClass(Symbols::_GrowableList()));
4103 ASSERT(!growable_list_class.IsNull());
4104
4105 const Function& factory_method =
4106 Function::ZoneHandle(Z, growable_list_class.LookupFunctionAllowPrivate(
4107 Symbols::_GrowableListLiteralFactory()));
4108 ASSERT(!factory_method.IsNull());
4109
4110 instructions += StaticCall(position, factory_method, 2, ICData::kStatic);
4111 instructions += DropTempsPreserveTop(1); // Instantiated type_arguments.
4112 return instructions;
4113}
4114
4115Fragment StreamingFlowGraphBuilder::BuildMapLiteral(TokenPosition* p) {
4116 TokenPosition position = ReadPosition(); // read position.
4117 if (p != nullptr) *p = position;
4118
4119 const TypeArguments& type_arguments =
4120 T.BuildTypeArguments(2); // read key_type and value_type.
4121
4122 // The type argument for the factory call `new Map<K, V>._fromLiteral(List)`.
4123 Fragment instructions = TranslateInstantiatedTypeArguments(type_arguments);
4124
4125 intptr_t length = ReadListLength(); // read list length.
4126 // Note: there will be "length" map entries (i.e. key and value expressions).
4127
4128 if (length == 0) {
4129 instructions += Constant(Object::empty_array());
4130 } else {
4131 // The type arguments for `new List<X>(int len)`.
4132 instructions += Constant(TypeArguments::ZoneHandle(Z));
4133
4134 // We generate a list of tuples, i.e. [key1, value1, ..., keyN, valueN].
4135 instructions += IntConstant(2 * length);
4136 instructions += CreateArray();
4137
4138 LocalVariable* array = MakeTemporary();
4139 for (intptr_t i = 0; i < length; ++i) {
4140 instructions += LoadLocal(array);
4141 instructions += IntConstant(2 * i);
4142 instructions += BuildExpression(); // read ith key.
4143 instructions += StoreIndexed(kArrayCid);
4144
4145 instructions += LoadLocal(array);
4146 instructions += IntConstant(2 * i + 1);
4147 instructions += BuildExpression(); // read ith value.
4148 instructions += StoreIndexed(kArrayCid);
4149 }
4150 }
4151
4152 const Class& map_class =
4153 Class::Handle(Z, Library::LookupCoreClass(Symbols::Map()));
4154 Function& factory_method = Function::ZoneHandle(Z);
4155 if (map_class.EnsureIsFinalized(H.thread()) == Error::null()) {
4156 factory_method = map_class.LookupFactory(
4157 Library::PrivateCoreLibName(Symbols::MapLiteralFactory()));
4158 }
4159
4160 return instructions +
4161 StaticCall(position, factory_method, 2, ICData::kStatic);
4162}
4163
4164Fragment StreamingFlowGraphBuilder::BuildRecordLiteral(TokenPosition* p) {
4165 const TokenPosition position = ReadPosition(); // read position.
4166 if (p != nullptr) *p = position;
4167
4168 // Figure out record shape.
4169 const intptr_t positional_count = ReadListLength();
4170 intptr_t named_count = -1;
4171 const Array* field_names = &Object::empty_array();
4172 {
4173 AlternativeReadingScope alt(&reader_);
4174 for (intptr_t i = 0; i < positional_count; ++i) {
4176 }
4177 named_count = ReadListLength();
4178 if (named_count > 0) {
4179 Array& names = Array::ZoneHandle(Z, Array::New(named_count, Heap::kOld));
4180 for (intptr_t i = 0; i < named_count; ++i) {
4181 String& name =
4182 H.DartSymbolObfuscate(ReadStringReference()); // read ith name.
4183 SkipExpression(); // read ith expression.
4184 names.SetAt(i, name);
4185 }
4186 names.MakeImmutable();
4187 field_names = &names;
4188 }
4189 }
4190 const intptr_t num_fields = positional_count + named_count;
4191 const RecordShape shape =
4192 RecordShape::Register(thread(), num_fields, *field_names);
4193 Fragment instructions;
4194
4195 if (num_fields == 2 ||
4196 (num_fields == 3 && AllocateSmallRecordABI::kValue2Reg != kNoRegister)) {
4197 // Generate specialized allocation for a small number of fields.
4198 for (intptr_t i = 0; i < positional_count; ++i) {
4199 instructions += BuildExpression(); // read ith expression.
4200 }
4201 ReadListLength(); // read list length.
4202 for (intptr_t i = 0; i < named_count; ++i) {
4203 SkipStringReference(); // read ith name.
4204 instructions += BuildExpression(); // read ith expression.
4205 }
4206 SkipDartType(); // read recordType.
4207
4208 instructions += B->AllocateSmallRecord(position, shape);
4209
4210 return instructions;
4211 }
4212
4213 instructions += B->AllocateRecord(position, shape);
4214 LocalVariable* record = MakeTemporary();
4215
4216 // List of positional.
4217 intptr_t pos = 0;
4218 for (intptr_t i = 0; i < positional_count; ++i, ++pos) {
4219 instructions += LoadLocal(record);
4220 instructions += BuildExpression(); // read ith expression.
4221 instructions += B->StoreNativeField(
4222 Slot::GetRecordFieldSlot(thread(),
4223 compiler::target::Record::field_offset(pos)),
4225 }
4226
4227 // List of named.
4228 ReadListLength(); // read list length.
4229 for (intptr_t i = 0; i < named_count; ++i, ++pos) {
4230 SkipStringReference(); // read ith name.
4231 instructions += LoadLocal(record);
4232 instructions += BuildExpression(); // read ith expression.
4233 instructions += B->StoreNativeField(
4234 Slot::GetRecordFieldSlot(thread(),
4235 compiler::target::Record::field_offset(pos)),
4237 }
4238
4239 SkipDartType(); // read recordType.
4240
4241 return instructions;
4242}
4243
4244Fragment StreamingFlowGraphBuilder::BuildRecordFieldGet(TokenPosition* p,
4245 bool is_named) {
4246 const TokenPosition position = ReadPosition(); // read position.
4247 if (p != nullptr) *p = position;
4248
4249 Fragment instructions = BuildExpression(); // read receiver.
4250 const RecordType& record_type =
4251 RecordType::Cast(T.BuildType()); // read recordType.
4252
4253 intptr_t field_index = -1;
4254 const Array& field_names =
4255 Array::Handle(Z, record_type.GetFieldNames(H.thread()));
4256 const intptr_t num_positional_fields =
4257 record_type.NumFields() - field_names.Length();
4258 if (is_named) {
4259 const String& field_name = H.DartSymbolObfuscate(ReadStringReference());
4260 for (intptr_t i = 0, n = field_names.Length(); i < n; ++i) {
4261 if (field_names.At(i) == field_name.ptr()) {
4262 field_index = i;
4263 break;
4264 }
4265 }
4266 ASSERT(field_index >= 0 && field_index < field_names.Length());
4267 field_index += num_positional_fields;
4268 } else {
4269 field_index = ReadUInt();
4270 ASSERT(field_index < num_positional_fields);
4271 }
4272
4273 instructions += B->LoadNativeField(Slot::GetRecordFieldSlot(
4274 thread(), compiler::target::Record::field_offset(field_index)));
4275 return instructions;
4276}
4277
4278Fragment StreamingFlowGraphBuilder::BuildFunctionExpression() {
4279 const intptr_t offset = ReaderOffset() - 1; // Include the tag.
4280 ReadPosition(); // read position.
4281 return BuildFunctionNode(offset);
4282}
4283
4284Fragment StreamingFlowGraphBuilder::BuildLet(TokenPosition* p) {
4285 const TokenPosition position = ReadPosition(); // read position.
4286 if (p != nullptr) *p = position;
4287 Fragment instructions = BuildVariableDeclaration(nullptr); // read variable.
4288 instructions += BuildExpression(); // read body.
4289 return instructions;
4290}
4291
4292Fragment StreamingFlowGraphBuilder::BuildBlockExpression() {
4293 block_expression_depth_inc();
4294 const intptr_t offset = ReaderOffset() - 1; // Include the tag.
4295
4296 Fragment instructions;
4297
4298 instructions += EnterScope(offset);
4299
4300 ReadPosition(); // ignore file offset.
4301 const intptr_t list_length = ReadListLength(); // read number of statements.
4302 for (intptr_t i = 0; i < list_length; ++i) {
4303 instructions += BuildStatement(); // read ith statement.
4304 }
4305 instructions += BuildExpression(); // read expression (inside scope).
4306 instructions += ExitScope(offset);
4307
4308 block_expression_depth_dec();
4309 return instructions;
4310}
4311
4312Fragment StreamingFlowGraphBuilder::BuildBigIntLiteral(
4313 TokenPosition* position) {
4314 ReadPosition(); // ignore file offset.
4315 if (position != nullptr) *position = TokenPosition::kNoSource;
4316
4317 const String& value =
4318 H.DartString(ReadStringReference()); // read index into string table.
4319 const Integer& integer = Integer::ZoneHandle(Z, Integer::NewCanonical(value));
4320 if (integer.IsNull()) {
4321 const auto& script = Script::Handle(Z, Script());
4322 H.ReportError(script, TokenPosition::kNoSource,
4323 "Integer literal %s is out of range", value.ToCString());
4324 UNREACHABLE();
4325 }
4326 return Constant(integer);
4327}
4328
4329Fragment StreamingFlowGraphBuilder::BuildStringLiteral(
4330 TokenPosition* position) {
4331 ReadPosition(); // ignore file offset.
4332 if (position != nullptr) *position = TokenPosition::kNoSource;
4333
4334 return Constant(H.DartSymbolPlain(
4335 ReadStringReference())); // read index into string table.
4336}
4337
4338Fragment StreamingFlowGraphBuilder::BuildIntLiteral(uint8_t payload,
4339 TokenPosition* position) {
4340 ReadPosition(); // ignore file offset.
4341 if (position != nullptr) *position = TokenPosition::kNoSource;
4342
4343 int64_t value = static_cast<int32_t>(payload) - SpecializedIntLiteralBias;
4344 return IntConstant(value);
4345}
4346
4347Fragment StreamingFlowGraphBuilder::BuildIntLiteral(bool is_negative,
4348 TokenPosition* position) {
4349 ReadPosition(); // ignore file offset.
4350 if (position != nullptr) *position = TokenPosition::kNoSource;
4351
4352 int64_t value = is_negative ? -static_cast<int64_t>(ReadUInt())
4353 : ReadUInt(); // read value.
4354 return IntConstant(value);
4355}
4356
4357Fragment StreamingFlowGraphBuilder::BuildDoubleLiteral(
4358 TokenPosition* position) {
4359 ReadPosition(); // ignore file offset.
4360 if (position != nullptr) *position = TokenPosition::kNoSource;
4361
4362 Double& constant = Double::ZoneHandle(
4363 Z, Double::NewCanonical(ReadDouble())); // read double.
4364 return Constant(constant);
4365}
4366
4367Fragment StreamingFlowGraphBuilder::BuildBoolLiteral(bool value,
4368 TokenPosition* position) {
4369 ReadPosition(); // ignore file offset.
4370 if (position != nullptr) *position = TokenPosition::kNoSource;
4371
4372 return Constant(Bool::Get(value));
4373}
4374
4375Fragment StreamingFlowGraphBuilder::BuildNullLiteral(TokenPosition* position) {
4376 ReadPosition(); // ignore file offset.
4377 if (position != nullptr) *position = TokenPosition::kNoSource;
4378
4379 return Constant(Instance::ZoneHandle(Z, Instance::null()));
4380}
4381
4382Fragment StreamingFlowGraphBuilder::BuildFutureNullValue(
4383 TokenPosition* position) {
4384 if (position != nullptr) *position = TokenPosition::kNoSource;
4385 const Class& future = Class::Handle(Z, IG->object_store()->future_class());
4386 ASSERT(!future.IsNull());
4387 const auto& error = future.EnsureIsFinalized(thread());
4388 ASSERT(error == Error::null());
4389 Function& constructor = Function::ZoneHandle(
4390 Z, Resolver::ResolveFunction(Z, future, Symbols::FutureValue()));
4391 ASSERT(!constructor.IsNull());
4392
4393 Fragment instructions;
4394 instructions += BuildNullLiteral(position);
4395 instructions += StaticCall(TokenPosition::kNoSource, constructor,
4396 /* argument_count = */ 1, ICData::kStatic);
4397 return instructions;
4398}
4399
4400Fragment StreamingFlowGraphBuilder::BuildConstantExpression(
4401 TokenPosition* position,
4402 Tag tag) {
4403 TokenPosition p = TokenPosition::kNoSource;
4404 if (tag == kConstantExpression) {
4405 p = ReadPosition();
4406 SkipDartType();
4407 } else if (tag == kFileUriConstantExpression) {
4408 // TODO(alexmarkov): Use file offset together with file uri.
4409 ReadPosition();
4410 ReadUInt();
4411 SkipDartType();
4412 }
4413 if (position != nullptr) *position = p;
4414 const intptr_t constant_index = ReadUInt();
4415 Fragment result = Constant(
4416 Object::ZoneHandle(Z, constant_reader_.ReadConstant(constant_index)));
4417 return result;
4418}
4419
4420Fragment StreamingFlowGraphBuilder::BuildPartialTearoffInstantiation(
4421 TokenPosition* p) {
4422 const TokenPosition position = ReadPosition(); // read position.
4423 if (p != nullptr) *p = position;
4424
4425 // Create a copy of the closure.
4426
4427 Fragment instructions = BuildExpression();
4428 LocalVariable* original_closure = MakeTemporary();
4429
4430 // Load the target function and context and allocate the closure.
4431 instructions += LoadLocal(original_closure);
4432 instructions +=
4433 flow_graph_builder_->LoadNativeField(Slot::Closure_function());
4434 instructions += LoadLocal(original_closure);
4435 instructions += flow_graph_builder_->LoadNativeField(Slot::Closure_context());
4436 instructions += LoadLocal(original_closure);
4437 instructions += flow_graph_builder_->LoadNativeField(
4438 Slot::Closure_instantiator_type_arguments());
4439 instructions += flow_graph_builder_->AllocateClosure(
4440 position, /*has_instantiator_type_args=*/true, /*is_generic=*/false,
4441 /*is_tear_off=*/false);
4442 LocalVariable* new_closure = MakeTemporary();
4443
4444 intptr_t num_type_args = ReadListLength();
4445 const TypeArguments& type_args = T.BuildTypeArguments(num_type_args);
4446 instructions += TranslateInstantiatedTypeArguments(type_args);
4447 LocalVariable* type_args_vec = MakeTemporary("type_args");
4448
4449 // Check the bounds.
4450 //
4451 // TODO(sjindel): We should be able to skip this check in many cases, e.g.
4452 // when the closure is coming from a tearoff of a top-level method or from a
4453 // local closure.
4454 instructions += LoadLocal(original_closure);
4455 instructions += LoadLocal(type_args_vec);
4456 const Library& dart_internal = Library::Handle(Z, Library::InternalLibrary());
4457 const Function& bounds_check_function = Function::ZoneHandle(
4458 Z, dart_internal.LookupFunctionAllowPrivate(
4459 Symbols::BoundsCheckForPartialInstantiation()));
4460 ASSERT(!bounds_check_function.IsNull());
4461 instructions += StaticCall(TokenPosition::kNoSource, bounds_check_function, 2,
4462 ICData::kStatic);
4463 instructions += Drop();
4464
4465 instructions += LoadLocal(new_closure);
4466 instructions += LoadLocal(type_args_vec);
4467 instructions += flow_graph_builder_->StoreNativeField(
4468 Slot::Closure_delayed_type_arguments(),
4470 instructions += DropTemporary(&type_args_vec);
4471
4472 // Copy over the function type arguments.
4473 instructions += LoadLocal(new_closure);
4474 instructions += LoadLocal(original_closure);
4475 instructions += flow_graph_builder_->LoadNativeField(
4476 Slot::Closure_function_type_arguments());
4477 instructions += flow_graph_builder_->StoreNativeField(
4478 Slot::Closure_function_type_arguments(),
4480
4481 instructions += DropTempsPreserveTop(1); // Drop old closure.
4482
4483 return instructions;
4484}
4485
4486Fragment StreamingFlowGraphBuilder::BuildLibraryPrefixAction(
4487 TokenPosition* position,
4488 const String& selector) {
4489 const TokenPosition pos = ReadPosition(); // read position.
4490 if (position != nullptr) *position = pos;
4491
4492 const intptr_t dependency_index = ReadUInt();
4493 const Library& current_library = Library::Handle(
4494 Z, Class::Handle(Z, parsed_function()->function().Owner()).library());
4495 const Array& dependencies = Array::Handle(Z, current_library.dependencies());
4496 const LibraryPrefix& prefix =
4497 LibraryPrefix::CheckedZoneHandle(Z, dependencies.At(dependency_index));
4498 const Function& function =
4500 .LookupFunctionAllowPrivate(selector));
4501 ASSERT(!function.IsNull());
4502 Fragment instructions;
4503 instructions += Constant(prefix);
4504 instructions += StaticCall(pos, function, 1, ICData::kStatic);
4505 return instructions;
4506}
4507
4508Fragment StreamingFlowGraphBuilder::BuildAwaitExpression(
4509 TokenPosition* position) {
4510 ASSERT(parsed_function()->function().IsAsyncFunction() ||
4511 parsed_function()->function().IsAsyncGenerator());
4512 Fragment instructions;
4513
4514 const TokenPosition pos = ReadPosition(); // read file offset.
4515 if (position != nullptr) *position = pos;
4516
4517 instructions += BuildExpression(); // read operand.
4518
4520 if (ReadTag() == kSomething) {
4521 const AbstractType& type = T.BuildType(); // read runtime check type.
4522 if (!type.IsType() ||
4523 !Class::Handle(Z, type.type_class()).IsFutureClass()) {
4524 FATAL("Unexpected type for runtime check in await: %s", type.ToCString());
4525 }
4526 ASSERT(type.IsFinalized());
4527 const auto& type_args =
4528 TypeArguments::ZoneHandle(Z, Type::Cast(type).arguments());
4529 if (!type_args.IsNull()) {
4530 const auto& type_arg = AbstractType::Handle(Z, type_args.TypeAt(0));
4531 if (!type_arg.IsTopTypeForSubtyping()) {
4532 instructions += TranslateInstantiatedTypeArguments(type_args);
4534 }
4535 }
4536 }
4537
4538 if (NeedsDebugStepCheck(parsed_function()->function(), pos)) {
4539 instructions += DebugStepCheck(pos);
4540 }
4541 instructions += B->Suspend(pos, stub_id);
4542 return instructions;
4543}
4544
4545Fragment StreamingFlowGraphBuilder::BuildFileUriExpression(
4546 TokenPosition* position) {
4547 ReadUInt(); // read uri
4548
4549 const TokenPosition pos = ReadPosition(); // read position.
4550 if (position != nullptr) *position = pos;
4551
4552 return BuildExpression(position); // read expression.
4553}
4554
4555Fragment StreamingFlowGraphBuilder::BuildExpressionStatement(
4556 TokenPosition* position) {
4557 Fragment instructions = BuildExpression(position); // read expression.
4558 instructions += Drop();
4559 return instructions;
4560}
4561
4562Fragment StreamingFlowGraphBuilder::BuildBlock(TokenPosition* position) {
4563 intptr_t offset = ReaderOffset() - 1; // Include the tag.
4564
4565 Fragment instructions;
4566
4567 instructions += EnterScope(offset);
4568 const TokenPosition pos = ReadPosition(); // read file offset.
4569 if (position != nullptr) *position = pos;
4570
4571 ReadPosition(); // read file end offset.
4572
4573 intptr_t list_length = ReadListLength(); // read number of statements.
4574 for (intptr_t i = 0; i < list_length; ++i) {
4575 if (instructions.is_open()) {
4576 instructions += BuildStatement(); // read ith statement.
4577 } else {
4578 SkipStatement(); // read ith statement.
4579 }
4580 }
4581 instructions += ExitScope(offset);
4582
4583 return instructions;
4584}
4585
4586Fragment StreamingFlowGraphBuilder::BuildEmptyStatement() {
4587 return Fragment();
4588}
4589
4590Fragment StreamingFlowGraphBuilder::BuildAssertBlock(TokenPosition* position) {
4591 if (!IG->asserts()) {
4593 return Fragment();
4594 }
4595
4596 intptr_t offset = ReaderOffset() - 1; // Include the tag.
4597
4598 Fragment instructions;
4599
4600 instructions += EnterScope(offset);
4601 intptr_t list_length = ReadListLength(); // read number of statements.
4602 for (intptr_t i = 0; i < list_length; ++i) {
4603 if (instructions.is_open()) {
4604 // read ith statement.
4605 instructions += BuildStatement(i == 0 ? position : nullptr);
4606 } else {
4607 SkipStatement(); // read ith statement.
4608 }
4609 }
4610 instructions += ExitScope(offset);
4611
4612 return instructions;
4613}
4614
4615Fragment StreamingFlowGraphBuilder::BuildAssertStatement(
4616 TokenPosition* position) {
4617 if (!IG->asserts()) {
4618 SetOffset(ReaderOffset() - 1); // Include the tag.
4619 SkipStatement(); // read this statement.
4620 return Fragment();
4621 }
4622
4623 TargetEntryInstr* then;
4624 TargetEntryInstr* otherwise;
4625
4626 Fragment instructions;
4627 // Asserts can be of the following two kinds:
4628 //
4629 // * `assert(expr)`
4630 // * `assert(() { ... })`
4631 //
4632 // The call to `_AssertionError._evaluateAssertion()` will take care of both
4633 // and returns a boolean.
4634 instructions += BuildExpression(position); // read condition.
4635
4636 const TokenPosition condition_start_offset =
4637 ReadPosition(); // read condition start offset.
4638 const TokenPosition condition_end_offset =
4639 ReadPosition(); // read condition end offset.
4640
4641 instructions += EvaluateAssertion();
4642 instructions += RecordCoverage(condition_start_offset);
4643 instructions += CheckBoolean(condition_start_offset);
4644 instructions += Constant(Bool::True());
4645 instructions += BranchIfEqual(&then, &otherwise);
4646
4647 const Class& klass =
4648 Class::ZoneHandle(Z, Library::LookupCoreClass(Symbols::AssertionError()));
4649 ASSERT(!klass.IsNull());
4650
4651 // Build equivalent of `throw _AssertionError._throwNew(start, end, message)`
4652 // expression. We build throw (even through _throwNew already throws) because
4653 // call is not a valid last instruction for the block. Blocks can only
4654 // terminate with explicit control flow instructions (Branch, Goto, Return
4655 // or Throw).
4656 Fragment otherwise_fragment(otherwise);
4657 if (CompilerState::Current().is_aot()) {
4658 // When in AOT, figure out start line, end line, line fragment needed for
4659 // the message now, because it won't be available at runtime.
4660 const Function& target = Function::ZoneHandle(
4661 Z, klass.LookupStaticFunctionAllowPrivate(Symbols::ThrowNewSource()));
4662 ASSERT(!target.IsNull());
4663
4664 auto& script = Script::ZoneHandle(Z, Script());
4665
4666 auto& condition_text = String::ZoneHandle(Z);
4667 intptr_t from_line = -1, from_column = -1;
4668 if (script.GetTokenLocation(condition_start_offset, &from_line,
4669 &from_column)) {
4670 // Extract the assertion condition text (if source is available).
4671 intptr_t to_line, to_column;
4672 script.GetTokenLocation(condition_end_offset, &to_line, &to_column);
4673 condition_text =
4674 script.GetSnippet(from_line, from_column, to_line, to_column);
4675 condition_text = Symbols::New(thread(), condition_text);
4676 } else {
4677 condition_text = Symbols::OptimizedOut().ptr();
4678 }
4679
4680 otherwise_fragment += Constant(condition_text);
4681 otherwise_fragment += Constant(String::ZoneHandle(Z, script.url()));
4682 otherwise_fragment += IntConstant(from_line); // line
4683 otherwise_fragment += IntConstant(from_column); // pos
4684 Tag tag = ReadTag(); // read (first part of) message.
4685 if (tag == kSomething) {
4686 otherwise_fragment += BuildExpression(); // read (rest of) message.
4687 } else {
4688 otherwise_fragment += Constant(Instance::ZoneHandle(Z)); // null.
4689 }
4690 otherwise_fragment +=
4691 StaticCall(condition_start_offset, target, 5, ICData::kStatic);
4692 } else {
4693 const Function& target = Function::ZoneHandle(
4694 Z, klass.LookupStaticFunctionAllowPrivate(Symbols::ThrowNew()));
4695 ASSERT(!target.IsNull());
4696
4697 otherwise_fragment += IntConstant(condition_start_offset.Pos());
4698 otherwise_fragment += IntConstant(condition_end_offset.Pos());
4699 Tag tag = ReadTag(); // read (first part of) message.
4700 if (tag == kSomething) {
4701 otherwise_fragment += BuildExpression(); // read (rest of) message.
4702 } else {
4703 otherwise_fragment += Constant(Instance::ZoneHandle(Z)); // null.
4704 }
4705
4706 // Note: condition_start_offset points to the first token after the opening
4707 // paren, not the beginning of 'assert'.
4708 otherwise_fragment +=
4709 StaticCall(condition_start_offset, target, 3, ICData::kStatic);
4710 }
4711 otherwise_fragment += ThrowException(TokenPosition::kNoSource);
4712 otherwise_fragment += Drop();
4713
4714 return Fragment(instructions.entry, then);
4715}
4716
4717Fragment StreamingFlowGraphBuilder::BuildLabeledStatement(
4718 TokenPosition* position) {
4719 const TokenPosition pos = ReadPosition(); // read position.
4720 if (position != nullptr) *position = pos;
4721
4722 // There can be several cases:
4723 //
4724 // * the body contains a break
4725 // * the body doesn't contain a break
4726 //
4727 // * translating the body results in a closed fragment
4728 // * translating the body results in a open fragment
4729 //
4730 // => We will only know which case we are in after the body has been
4731 // traversed.
4732
4733 BreakableBlock block(flow_graph_builder_);
4734 Fragment instructions = BuildStatement(position); // read body.
4735 if (block.HadJumper()) {
4736 if (instructions.is_open()) {
4737 instructions += Goto(block.destination());
4738 }
4739 return Fragment(instructions.entry, block.destination());
4740 } else {
4741 return instructions;
4742 }
4743}
4744
4745Fragment StreamingFlowGraphBuilder::BuildBreakStatement(
4746 TokenPosition* position) {
4747 const TokenPosition pos = ReadPosition(); // read position.
4748 if (position != nullptr) *position = pos;
4749
4750 intptr_t target_index = ReadUInt(); // read target index.
4751
4752 TryFinallyBlock* outer_finally = nullptr;
4753 intptr_t target_context_depth = -1;
4754 JoinEntryInstr* destination = breakable_block()->BreakDestination(
4755 target_index, &outer_finally, &target_context_depth);
4756
4757 Fragment instructions;
4758 // Break statement should pause before manipulation of context, which
4759 // will possibly cause debugger having incorrect context object.
4760 if (NeedsDebugStepCheck(parsed_function()->function(), pos)) {
4761 instructions += DebugStepCheck(pos);
4762 }
4763 instructions +=
4764 TranslateFinallyFinalizers(outer_finally, target_context_depth);
4765 if (instructions.is_open()) {
4766 instructions += Goto(destination);
4767 }
4768 return instructions;
4769}
4770
4771Fragment StreamingFlowGraphBuilder::BuildWhileStatement(
4772 TokenPosition* position) {
4773 loop_depth_inc();
4774 const TokenPosition pos = ReadPosition(); // read position.
4775 if (position != nullptr) *position = pos;
4776
4777 TestFragment condition = TranslateConditionForControl(); // read condition.
4778 const Fragment body = BuildStatementWithBranchCoverage(); // read body
4779
4780 Fragment body_entry(condition.CreateTrueSuccessor(flow_graph_builder_));
4781 body_entry += body;
4782
4783 Instruction* entry;
4784 if (body_entry.is_open()) {
4785 JoinEntryInstr* join = BuildJoinEntry();
4786 body_entry += Goto(join);
4787
4788 Fragment loop(join);
4789 loop += CheckStackOverflow(pos); // may have non-empty stack
4790 loop.current->LinkTo(condition.entry);
4791
4792 entry = Goto(join).entry;
4793 } else {
4794 entry = condition.entry;
4795 }
4796
4797 loop_depth_dec();
4798 return Fragment(entry, condition.CreateFalseSuccessor(flow_graph_builder_));
4799}
4800
4801Fragment StreamingFlowGraphBuilder::BuildDoStatement(TokenPosition* position) {
4802 loop_depth_inc();
4803 const TokenPosition pos = ReadPosition(); // read position.
4804 if (position != nullptr) *position = pos;
4805
4806 Fragment body = BuildStatementWithBranchCoverage(); // read body.
4807
4808 if (body.is_closed()) {
4809 SkipExpression(); // read condition.
4810 loop_depth_dec();
4811 return body;
4812 }
4813
4814 TestFragment condition = TranslateConditionForControl();
4815
4816 JoinEntryInstr* join = BuildJoinEntry();
4817 Fragment loop(join);
4818 loop += CheckStackOverflow(pos); // may have non-empty stack
4819 loop += body;
4820 loop <<= condition.entry;
4821
4822 condition.IfTrueGoto(flow_graph_builder_, join);
4823
4824 loop_depth_dec();
4825 return Fragment(
4826 new (Z) GotoInstr(join, CompilerState::Current().GetNextDeoptId()),
4827 condition.CreateFalseSuccessor(flow_graph_builder_));
4828}
4829
4830Fragment StreamingFlowGraphBuilder::BuildForStatement(TokenPosition* position) {
4831 intptr_t offset = ReaderOffset() - 1; // Include the tag.
4832
4833 const TokenPosition pos = ReadPosition(); // read position.
4834 if (position != nullptr) *position = pos;
4835
4836 Fragment declarations;
4837
4838 loop_depth_inc();
4839
4840 const LocalScope* context_scope = nullptr;
4841 declarations += EnterScope(offset, &context_scope);
4842
4843 intptr_t list_length = ReadListLength(); // read number of variables.
4844 for (intptr_t i = 0; i < list_length; ++i) {
4845 declarations += BuildVariableDeclaration(nullptr); // read ith variable.
4846 }
4847
4848 Tag tag = ReadTag(); // Read first part of condition.
4849 TestFragment condition;
4850 BlockEntryInstr* body_entry;
4851 BlockEntryInstr* loop_exit;
4852 if (tag != kNothing) {
4853 condition = TranslateConditionForControl();
4854 body_entry = condition.CreateTrueSuccessor(flow_graph_builder_);
4855 loop_exit = condition.CreateFalseSuccessor(flow_graph_builder_);
4856 } else {
4857 body_entry = BuildJoinEntry();
4858 loop_exit = BuildJoinEntry();
4859 }
4860
4861 Fragment updates;
4862 list_length = ReadListLength(); // read number of updates.
4863 for (intptr_t i = 0; i < list_length; ++i) {
4864 updates += BuildExpression(); // read ith update.
4865 updates += Drop();
4866 }
4867
4868 Fragment body(body_entry);
4869 body += BuildStatementWithBranchCoverage(); // read body.
4870
4871 if (body.is_open()) {
4872 // We allocated a fresh context before the loop which contains captured
4873 // [ForStatement] variables. Before jumping back to the loop entry we clone
4874 // the context object (at same depth) which ensures the next iteration of
4875 // the body gets a fresh set of [ForStatement] variables (with the old
4876 // (possibly updated) values).
4877 if (context_scope->num_context_variables() > 0) {
4878 body += CloneContext(context_scope->context_slots());
4879 }
4880
4881 body += updates;
4882 JoinEntryInstr* join = BuildJoinEntry();
4883 declarations += Goto(join);
4884 body += Goto(join);
4885
4886 Fragment loop(join);
4887 loop += CheckStackOverflow(pos); // may have non-empty stack
4888 if (condition.entry != nullptr) {
4889 loop <<= condition.entry;
4890 } else {
4891 loop += Goto(body_entry->AsJoinEntry());
4892 }
4893 } else {
4894 if (condition.entry != nullptr) {
4895 declarations <<= condition.entry;
4896 } else {
4897 declarations += Goto(body_entry->AsJoinEntry());
4898 }
4899 }
4900
4901 Fragment loop(declarations.entry, loop_exit);
4902
4903 loop += ExitScope(offset);
4904
4905 loop_depth_dec();
4906
4907 return loop;
4908}
4909
4910Fragment StreamingFlowGraphBuilder::BuildSwitchStatement(
4911 TokenPosition* position) {
4912 const TokenPosition pos = ReadPosition(); // read position.
4913 if (position != nullptr) *position = pos;
4914 const bool is_exhaustive = ReadBool(); // read exhaustive flag.
4915
4916 // We need the number of cases. So start by getting that, then go back.
4917 const intptr_t offset = ReaderOffset();
4918 SkipExpression(); // temporarily skip condition
4919 SkipOptionalDartType(); // temporarily skip expression type
4920 intptr_t case_count = ReadListLength(); // read number of cases.
4922
4923 SwitchBlock block(flow_graph_builder_, case_count);
4924
4925 Fragment instructions = BuildExpression(); // read condition.
4926 const AbstractType* expression_type = &Object::dynamic_type();
4927 if (ReadTag() == kSomething) {
4928 expression_type = &T.BuildType(); // read expression type.
4929 }
4930 instructions +=
4931 StoreLocal(TokenPosition::kNoSource, scopes()->switch_variable);
4932 instructions += Drop();
4933
4934 case_count = ReadListLength(); // read number of cases.
4935
4936 SwitchHelper helper(Z, pos, is_exhaustive, *expression_type, &block,
4937 case_count);
4938
4939 // Build the case bodies and collect the expressions into the helper
4940 // for the next step.
4941 for (intptr_t i = 0; i < case_count; ++i) {
4942 helper.AddCaseBody(BuildSwitchCase(&helper, i));
4943 }
4944
4945 // Build the code to dispatch to the case bodies.
4946 switch (helper.SelectDispatchStrategy()) {
4948 UNREACHABLE();
4950 instructions += BuildLinearScanSwitch(&helper);
4951 break;
4953 instructions += BuildBinarySearchSwitch(&helper);
4954 break;
4956 instructions += BuildJumpTableSwitch(&helper);
4957 break;
4958 }
4959
4960 return instructions;
4961}
4962
4963Fragment StreamingFlowGraphBuilder::BuildSwitchCase(SwitchHelper* helper,
4964 intptr_t case_index) {
4965 // Generate case body and try to find out whether the body will be target
4966 // of a jump due to:
4967 // * `continue case_label`
4968 // * `case e1: case e2: body`
4969 //
4970 // Also collect switch expressions into helper.
4971
4972 ReadPosition(); // read file offset.
4973 const int expression_count = ReadListLength(); // read number of expressions.
4974 for (intptr_t j = 0; j < expression_count; ++j) {
4975 const TokenPosition pos = ReadPosition(); // read jth position.
4976 // read jth expression.
4977 const Instance& value =
4978 Instance::ZoneHandle(Z, constant_reader_.ReadConstantExpression());
4979 helper->AddExpression(case_index, pos, value);
4980 }
4981
4982 const bool is_default = ReadBool(); // read is_default.
4983 if (is_default) helper->set_default_case(case_index);
4984 Fragment body_fragment = BuildStatementWithBranchCoverage(); // read body.
4985
4986 if (body_fragment.entry == nullptr) {
4987 // Make a NOP in order to ensure linking works properly.
4988 body_fragment = NullConstant();
4989 body_fragment += Drop();
4990 }
4991
4992 // TODO(http://dartbug.com/50595): The CFE does not insert breaks for
4993 // unterminated cases which never reach the end of their control flow.
4994 // If the CFE inserts synthesized breaks, we can add an assert here instead.
4995 if (!is_default && body_fragment.is_open() &&
4996 (case_index < (helper->case_count() - 1))) {
4997 const auto& error =
4998 String::ZoneHandle(Z, Symbols::New(thread(), "Unreachable code."));
4999 body_fragment += Constant(error);
5000 body_fragment += ThrowException(TokenPosition::kNoSource);
5001 body_fragment += Drop();
5002 }
5003
5004 // If there is an implicit fall-through we have one [SwitchCase] and
5005 // multiple expressions, e.g.
5006 //
5007 // switch(expr) {
5008 // case a:
5009 // case b:
5010 // <stmt-body>
5011 // }
5012 //
5013 // This means that the <stmt-body> will have more than 1 incoming edge (one
5014 // from `a == expr` and one from `a != expr && b == expr`). The
5015 // `block.Destination()` records the additional jump.
5016 if (expression_count > 1) {
5017 helper->switch_block()->DestinationDirect(case_index);
5018 }
5019
5020 return body_fragment;
5021}
5022
5023Fragment StreamingFlowGraphBuilder::BuildLinearScanSwitch(
5024 SwitchHelper* helper) {
5025 // Build a switch using a sequence of equality tests.
5026 //
5027 // From a test:
5028 // * jump directly to a body, if there is no jumper.
5029 // * jump to a wrapper block which jumps to the body, if there is a jumper.
5030
5031 SwitchBlock* block = helper->switch_block();
5032 const intptr_t case_count = helper->case_count();
5033 const intptr_t default_case = helper->default_case();
5034 const GrowableArray<Fragment>& case_bodies = helper->case_bodies();
5035 Fragment current_instructions;
5036 intptr_t expression_index = 0;
5037
5038 for (intptr_t i = 0; i < case_count; ++i) {
5039 if (i == default_case) {
5040 ASSERT(i == (case_count - 1));
5041
5042 if (block->HadJumper(i)) {
5043 // There are several branches to the body, so we will make a goto to
5044 // the join block (and prepend a join instruction to the real body).
5045 JoinEntryInstr* join = block->DestinationDirect(i);
5046 current_instructions += Goto(join);
5047
5048 current_instructions = Fragment(current_instructions.entry, join);
5049 current_instructions += case_bodies[i];
5050 } else {
5051 current_instructions += case_bodies[i];
5052 }
5053 } else {
5054 JoinEntryInstr* body_join = nullptr;
5055 if (block->HadJumper(i)) {
5056 body_join = block->DestinationDirect(i);
5057 case_bodies[i] = Fragment(body_join) + case_bodies[i];
5058 }
5059
5060 const intptr_t expression_count = helper->case_expression_counts().At(i);
5061 for (intptr_t j = 0; j < expression_count; ++j) {
5062 TargetEntryInstr* then;
5063 TargetEntryInstr* otherwise;
5064
5065 const SwitchExpression& expression =
5066 helper->expressions().At(expression_index++);
5067 current_instructions += Constant(expression.value());
5068 current_instructions += LoadLocal(scopes()->switch_variable);
5069 current_instructions += InstanceCall(
5070 expression.position(), Symbols::EqualOperator(), Token::kEQ,
5071 /*argument_count=*/2,
5072 /*checked_argument_count=*/2);
5073 current_instructions += BranchIfTrue(&then, &otherwise, false);
5074
5075 Fragment then_fragment(then);
5076
5077 if (body_join != nullptr) {
5078 // There are several branches to the body, so we will make a goto to
5079 // the join block (the real body has already been prepended with a
5080 // join instruction).
5081 then_fragment += Goto(body_join);
5082 } else {
5083 // There is only a single branch to the body, so we will just append
5084 // the body fragment.
5085 then_fragment += case_bodies[i];
5086 }
5087
5088 current_instructions = Fragment(current_instructions.entry, otherwise);
5089 }
5090 }
5091 }
5092
5093 if (case_count > 0 && !helper->has_default()) {
5094 // There is no default, which means we have an open [current_instructions]
5095 // (which is a [TargetEntryInstruction] for the last "otherwise" branch).
5096 //
5097 // Furthermore the last [SwitchCase] can be open as well. If so, we need
5098 // to join these two.
5099 Fragment& last_body = case_bodies[case_count - 1];
5100 if (last_body.is_open()) {
5101 ASSERT(current_instructions.is_open());
5102 ASSERT(current_instructions.current->IsTargetEntry());
5103
5104 // Join the last "otherwise" branch and the last [SwitchCase] fragment.
5105 JoinEntryInstr* join = BuildJoinEntry();
5106 current_instructions += Goto(join);
5107 last_body += Goto(join);
5108
5109 current_instructions = Fragment(current_instructions.entry, join);
5110 }
5111 } else {
5112 // All non-default cases will be closed (i.e. break/continue/throw/return)
5113 // So it is fine to just let more statements after the switch append to the
5114 // default case.
5115 }
5116
5117 return current_instructions;
5118}
5119
5120Fragment StreamingFlowGraphBuilder::BuildOptimizedSwitchPrelude(
5121 SwitchHelper* helper,
5122 JoinEntryInstr* join) {
5123 const TokenPosition pos = helper->position();
5124 Fragment instructions;
5125
5126 if (helper->is_enum_switch()) {
5127 // For an enum switch, we need to load the enum index from the switch
5128 // variable.
5129
5130 instructions += LoadLocal(scopes()->switch_variable);
5131 const Field& enum_index_field =
5132 Field::ZoneHandle(Z, IG->object_store()->enum_index_field());
5133 instructions += B->LoadField(enum_index_field, /*calls_initializer=*/false);
5134 instructions += StoreLocal(pos, scopes()->switch_variable);
5135 instructions += Drop();
5136 }
5137
5138 return instructions;
5139}
5140
5141Fragment StreamingFlowGraphBuilder::BuildBinarySearchSwitch(
5142 SwitchHelper* helper) {
5143 // * We build a binary tree of conditional branches where each branch bisects
5144 // the remaining cases.
5145 // * At holes in the switch expression range we need to add additional
5146 // bound checks.
5147 // * At each leaf we add the body of the case or a goto, if the case has
5148 // jumpers.
5149 // * Leafs at the bounds of the switch expression range might need to
5150 // do a bound check.
5151
5152 SwitchBlock* block = helper->switch_block();
5153 const intptr_t case_count = helper->case_count();
5154 const intptr_t default_case = helper->default_case();
5155 const GrowableArray<Fragment>& case_bodies = helper->case_bodies();
5156 const intptr_t expression_count = helper->expressions().length();
5157 const GrowableArray<SwitchExpression*>& sorted_expressions =
5158 helper->sorted_expressions();
5159 TargetEntryInstr* then_entry;
5160 TargetEntryInstr* otherwise_entry;
5161
5162 // Entry to the default case or the exit of the switch, if there is no
5163 // default case.
5164 JoinEntryInstr* join;
5165 if (helper->has_default()) {
5166 join = block->DestinationDirect(default_case);
5167 } else {
5168 join = BuildJoinEntry();
5169 }
5170
5171 Fragment join_instructions(join);
5172 if (helper->has_default()) {
5173 join_instructions += case_bodies.At(default_case);
5174 }
5175
5176 Fragment current_instructions = BuildOptimizedSwitchPrelude(helper, join);
5177
5178 GrowableArray<SwitchRange> stack;
5179 stack.Add(SwitchRange::Branch(0, expression_count - 1, current_instructions));
5180
5181 while (!stack.is_empty()) {
5182 const SwitchRange range = stack.RemoveLast();
5183 Fragment branch_instructions = range.branch_instructions();
5184
5185 if (range.is_leaf()) {
5186 const intptr_t expression_index = range.min();
5187 const SwitchExpression& expression =
5188 *sorted_expressions.At(expression_index);
5189
5190 if (!range.is_bounds_checked() &&
5191 ((helper->RequiresLowerBoundCheck() && expression_index == 0) ||
5192 (helper->RequiresUpperBoundCheck() &&
5193 expression_index == expression_count - 1))) {
5194 // This leaf needs a bound check.
5195
5196 branch_instructions += LoadLocal(scopes()->switch_variable);
5197 branch_instructions += Constant(expression.integer());
5198 branch_instructions +=
5199 StrictCompare(expression.position(), Token::kEQ_STRICT,
5200 /*number_check=*/true);
5201 branch_instructions +=
5202 BranchIfTrue(&then_entry, &otherwise_entry, /*negate=*/false);
5203
5204 Fragment otherwise_instructions(otherwise_entry);
5205 otherwise_instructions += Goto(join);
5206
5207 stack.Add(SwitchRange::Leaf(expression_index, Fragment(then_entry),
5208 /*is_bounds_checked=*/true));
5209 } else {
5210 // We are at a leaf where we can add the body of the case or a goto to
5211 // [join].
5212
5213 const intptr_t case_index = expression.case_index();
5214
5215 if (case_index == default_case) {
5216 branch_instructions += Goto(join);
5217 } else {
5218 if (block->HadJumper(case_index)) {
5219 JoinEntryInstr* join = block->DestinationDirect(case_index);
5220 branch_instructions += Goto(join);
5221
5222 if (join->next() == nullptr) {
5223 // The first time we reach an expression that jumps to a case
5224 // body we emit the body.
5225 branch_instructions = Fragment(join);
5226 branch_instructions += case_bodies.At(case_index);
5227 }
5228 } else {
5229 branch_instructions += case_bodies.At(case_index);
5230 }
5231
5232 if (!helper->has_default() && case_index == case_count - 1) {
5233 if (branch_instructions.is_open()) {
5234 branch_instructions += Goto(join);
5235 }
5236 }
5237 }
5238
5239 ASSERT(branch_instructions.is_closed());
5240 }
5241 } else {
5242 // Add a conditional to bisect the range.
5243
5244 const intptr_t middle = range.min() + (range.max() - range.min()) / 2;
5245 const intptr_t next = middle + 1;
5246 const SwitchExpression& middle_expression =
5247 *sorted_expressions.At(middle);
5248 const SwitchExpression& next_expression = *sorted_expressions.At(next);
5249
5250 branch_instructions += LoadLocal(scopes()->switch_variable);
5251 branch_instructions += Constant(middle_expression.integer());
5252 branch_instructions +=
5253 B->IntRelationalOp(middle_expression.position(), Token::kLTE);
5254 branch_instructions +=
5255 BranchIfTrue(&then_entry, &otherwise_entry, /*negate=*/false);
5256
5257 Fragment lower_branch_instructions(then_entry);
5258 Fragment upper_branch_instructions(otherwise_entry);
5259
5260 if (next_expression.integer().AsInt64Value() >
5261 middle_expression.integer().AsInt64Value() + 1) {
5262 // The upper branch is not contiguous with the lower branch.
5263 // Before continuing in the upper branch we add a bound check.
5264
5265 upper_branch_instructions += LoadLocal(scopes()->switch_variable);
5266 upper_branch_instructions += Constant(next_expression.integer());
5267 upper_branch_instructions +=
5268 B->IntRelationalOp(next_expression.position(), Token::kGTE);
5269 upper_branch_instructions +=
5270 BranchIfTrue(&then_entry, &otherwise_entry, /*negate=*/false);
5271
5272 Fragment otherwise_instructions(otherwise_entry);
5273 otherwise_instructions += Goto(join);
5274
5275 upper_branch_instructions = Fragment(then_entry);
5276 }
5277
5278 stack.Add(
5279 SwitchRange::Branch(next, range.max(), upper_branch_instructions));
5280 stack.Add(
5281 SwitchRange::Branch(range.min(), middle, lower_branch_instructions));
5282 }
5283
5284 if (current_instructions.is_empty()) {
5285 current_instructions = branch_instructions;
5286 }
5287 }
5288
5289 return Fragment(current_instructions.entry, join_instructions.current);
5290}
5291
5292Fragment StreamingFlowGraphBuilder::BuildJumpTableSwitch(SwitchHelper* helper) {
5293 // * If input value is not integer or enum value, goto default case or
5294 // switch exit.
5295 // * If value is enum value, load its index.
5296 // * If input integer is outside of jump table range, goto default case
5297 // or switch exit.
5298 // * Jump to case with jump table.
5299 // * For each expression, add entry to jump to case.
5300 // * For each hole in the integer range, add entry to jump to default
5301 // cause or switch exit.
5302
5303 SwitchBlock* block = helper->switch_block();
5304 const TokenPosition pos = helper->position();
5305 const intptr_t case_count = helper->case_count();
5306 const intptr_t default_case = helper->default_case();
5307 const GrowableArray<Fragment>& case_bodies = helper->case_bodies();
5308 const Integer& expression_min = helper->expression_min();
5309 const Integer& expression_max = helper->expression_max();
5310 TargetEntryInstr* then_entry;
5311 TargetEntryInstr* otherwise_entry;
5312
5313 // Entry to the default case or the exit of the switch, if there is no
5314 // default case.
5315 JoinEntryInstr* join;
5316 if (helper->has_default()) {
5317 join = block->DestinationDirect(default_case);
5318 } else {
5319 join = BuildJoinEntry();
5320 }
5321
5322 Fragment join_instructions(join);
5323
5324 Fragment current_instructions = BuildOptimizedSwitchPrelude(helper, join);
5325
5326 if (helper->RequiresLowerBoundCheck()) {
5327 current_instructions += LoadLocal(scopes()->switch_variable);
5328 current_instructions += Constant(expression_min);
5329 current_instructions += B->IntRelationalOp(pos, Token::kGTE);
5330 current_instructions += BranchIfTrue(&then_entry, &otherwise_entry,
5331 /*negate=*/false);
5332 Fragment otherwise_instructions(otherwise_entry);
5333 otherwise_instructions += Goto(join);
5334
5335 current_instructions = Fragment(current_instructions.entry, then_entry);
5336 }
5337
5338 if (helper->RequiresUpperBoundCheck()) {
5339 current_instructions += LoadLocal(scopes()->switch_variable);
5340 current_instructions += Constant(expression_max);
5341 current_instructions += B->IntRelationalOp(pos, Token::kLTE);
5342 current_instructions += BranchIfTrue(&then_entry, &otherwise_entry,
5343 /*negate=*/false);
5344 Fragment otherwise_instructions(otherwise_entry);
5345 otherwise_instructions += Goto(join);
5346
5347 current_instructions = Fragment(current_instructions.entry, then_entry);
5348 }
5349
5350 current_instructions += LoadLocal(scopes()->switch_variable);
5351
5352 if (!expression_min.IsZero()) {
5353 // Adjust for the range of the jump table, which starts at 0.
5354 current_instructions += Constant(expression_min);
5355 current_instructions +=
5356 InstanceCall(pos, Symbols::Minus(), Token::kSUB, /*argument_count=*/2,
5357 /*checked_argument_count=*/2);
5358 }
5359
5360 const intptr_t table_size = helper->ExpressionRange();
5361 IndirectGotoInstr* indirect_goto = IndirectGoto(table_size);
5362 current_instructions <<= indirect_goto;
5363 current_instructions = current_instructions.closed();
5364
5365 GrowableArray<TargetEntryInstr*> table_entries(table_size);
5366 table_entries.FillWith(nullptr, 0, table_size);
5367
5368 // Generate the jump table entries for the switch cases.
5369 intptr_t expression_index = 0;
5370 for (intptr_t i = 0; i < case_count; ++i) {
5371 const int expression_count = helper->case_expression_counts().At(i);
5372
5373 // Generate jump table entries for each case expression.
5374 if (i != default_case) {
5375 for (intptr_t j = 0; j < expression_count; ++j) {
5376 const SwitchExpression& expression =
5377 helper->expressions().At(expression_index++);
5378 const intptr_t table_offset =
5379 expression.integer().AsInt64Value() - expression_min.AsInt64Value();
5380
5381 IndirectEntryInstr* indirect_entry =
5382 B->BuildIndirectEntry(table_offset, CurrentTryIndex());
5383 Fragment indirect_entry_instructions(indirect_entry);
5384 indirect_entry_instructions += Goto(block->DestinationDirect(i));
5385
5386 TargetEntryInstr* entry = B->BuildTargetEntry();
5387 Fragment entry_instructions(entry);
5388 entry_instructions += Goto(indirect_entry);
5389
5390 table_entries[table_offset] = entry;
5391 }
5392 }
5393
5394 // Connect the case body to its join entry.
5395 if (i == default_case) {
5396 join_instructions += case_bodies.At(i);
5397 } else {
5398 Fragment case_instructions(block->DestinationDirect(i));
5399 case_instructions += case_bodies.At(i);
5400
5401 if (i == case_count - 1) {
5402 // If the last case is not the default case and it is still open
5403 // close it by going to the exit of the switch.
5404 if (case_instructions.is_open()) {
5405 case_instructions += Goto(join);
5406 }
5407 }
5408
5409 ASSERT(case_instructions.is_closed());
5410 }
5411 }
5412
5413 // Generate the jump table entries for holes in the integer range.
5414 for (intptr_t i = 0; i < table_size; i++) {
5415 if (table_entries.At(i) == nullptr) {
5416 IndirectEntryInstr* indirect_entry =
5417 B->BuildIndirectEntry(i, CurrentTryIndex());
5418 Fragment indirect_entry_instructions(indirect_entry);
5419 indirect_entry_instructions += Goto(join);
5420
5421 TargetEntryInstr* entry = flow_graph_builder_->BuildTargetEntry();
5422 Fragment entry_instructions(entry);
5423 entry_instructions += Goto(indirect_entry);
5424
5425 table_entries[i] = entry;
5426 }
5427 }
5428
5429 // Add the jump table entries to the jump table.
5430 for (intptr_t i = 0; i < table_size; i++) {
5431 indirect_goto->AddSuccessor(table_entries.At(i));
5432 }
5433
5434 return Fragment(current_instructions.entry, join_instructions.current);
5435}
5436
5437Fragment StreamingFlowGraphBuilder::BuildContinueSwitchStatement(
5438 TokenPosition* position) {
5439 const TokenPosition pos = ReadPosition(); // read position.
5440 if (position != nullptr) *position = pos;
5441
5442 intptr_t target_index = ReadUInt(); // read target index.
5443
5444 TryFinallyBlock* outer_finally = nullptr;
5445 intptr_t target_context_depth = -1;
5446 JoinEntryInstr* entry = switch_block()->Destination(
5447 target_index, &outer_finally, &target_context_depth);
5448
5449 Fragment instructions;
5450 instructions +=
5451 TranslateFinallyFinalizers(outer_finally, target_context_depth);
5452 if (instructions.is_open()) {
5453 if (NeedsDebugStepCheck(parsed_function()->function(), pos)) {
5454 instructions += DebugStepCheck(pos);
5455 }
5456 instructions += Goto(entry);
5457 }
5458 return instructions;
5459}
5460
5461Fragment StreamingFlowGraphBuilder::BuildIfStatement(TokenPosition* position) {
5462 const TokenPosition pos = ReadPosition(); // read position.
5463 if (position != nullptr) *position = pos;
5464
5465 TestFragment condition = TranslateConditionForControl();
5466
5467 Fragment then_fragment(condition.CreateTrueSuccessor(flow_graph_builder_));
5468 then_fragment += BuildStatementWithBranchCoverage(); // read then.
5469
5470 Fragment otherwise_fragment(
5471 condition.CreateFalseSuccessor(flow_graph_builder_));
5472 otherwise_fragment += BuildStatementWithBranchCoverage(); // read otherwise.
5473
5474 if (then_fragment.is_open()) {
5475 if (otherwise_fragment.is_open()) {
5476 JoinEntryInstr* join = BuildJoinEntry();
5477 then_fragment += Goto(join);
5478 otherwise_fragment += Goto(join);
5479 return Fragment(condition.entry, join);
5480 } else {
5481 return Fragment(condition.entry, then_fragment.current);
5482 }
5483 } else if (otherwise_fragment.is_open()) {
5484 return Fragment(condition.entry, otherwise_fragment.current);
5485 } else {
5486 return Fragment(condition.entry, nullptr);
5487 }
5488}
5489
5490Fragment StreamingFlowGraphBuilder::BuildReturnStatement(
5491 TokenPosition* position) {
5492 const TokenPosition pos = ReadPosition(); // read position.
5493 if (position != nullptr) *position = pos;
5494
5495 Tag tag = ReadTag(); // read first part of expression.
5496
5497 bool inside_try_finally = try_finally_block() != nullptr;
5498
5499 Fragment instructions;
5500 if (parsed_function()->function().IsSyncGenerator()) {
5501 // Return false from sync* function to indicate the end of iteration.
5502 instructions += Constant(Bool::False());
5503 if (tag != kNothing) {
5504 ASSERT(PeekTag() == kNullLiteral);
5506 }
5507 } else {
5508 instructions +=
5509 (tag == kNothing ? NullConstant()
5510 : BuildExpression()); // read rest of expression.
5511 }
5512
5513 if (instructions.is_open()) {
5514 if (inside_try_finally) {
5515 LocalVariable* const finally_return_variable =
5516 scopes()->finally_return_variable;
5517 ASSERT(finally_return_variable != nullptr);
5518 const Function& function = parsed_function()->function();
5519 if (NeedsDebugStepCheck(function, pos)) {
5520 instructions += DebugStepCheck(pos);
5521 }
5522 instructions += StoreLocal(pos, finally_return_variable);
5523 instructions += Drop();
5524 const intptr_t target_context_depth =
5525 finally_return_variable->is_captured()
5526 ? finally_return_variable->owner()->context_level()
5527 : -1;
5528 instructions += TranslateFinallyFinalizers(nullptr, target_context_depth);
5529 if (instructions.is_open()) {
5530 const intptr_t saved_context_depth = B->context_depth_;
5531 if (finally_return_variable->is_captured()) {
5532 B->context_depth_ = target_context_depth;
5533 }
5534 instructions += LoadLocal(finally_return_variable);
5535 instructions += Return(TokenPosition::kNoSource);
5536 B->context_depth_ = saved_context_depth;
5537 }
5538 } else {
5539 instructions += Return(pos);
5540 }
5541 } else {
5542 Pop();
5543 }
5544
5545 return instructions;
5546}
5547
5548Fragment StreamingFlowGraphBuilder::BuildTryCatch(TokenPosition* position) {
5549 ASSERT(block_expression_depth() == 0); // no try-catch in block-expr
5550 InlineBailout("kernel::FlowgraphBuilder::VisitTryCatch");
5551
5552 const TokenPosition pos = ReadPosition(); // read position.
5553 if (position != nullptr) *position = pos;
5554
5555 intptr_t try_handler_index = AllocateTryIndex();
5556 Fragment try_body = TryCatch(try_handler_index);
5557 JoinEntryInstr* after_try = BuildJoinEntry();
5558
5559 // Fill in the body of the try.
5560 try_depth_inc();
5561 {
5562 TryCatchBlock block(flow_graph_builder_, try_handler_index);
5563 try_body += BuildStatementWithBranchCoverage(position); // read body.
5564 try_body += Goto(after_try);
5565 }
5566 try_depth_dec();
5567
5568 const int kNeedsStracktraceBit = 1 << 0;
5569 const int kIsSyntheticBit = 1 << 1;
5570
5571 uint8_t flags = ReadByte();
5572 bool needs_stacktrace =
5573 (flags & kNeedsStracktraceBit) == kNeedsStracktraceBit;
5574 bool is_synthetic = (flags & kIsSyntheticBit) == kIsSyntheticBit;
5575
5576 catch_depth_inc();
5577 intptr_t catch_count = ReadListLength(); // read number of catches.
5578 const Array& handler_types =
5579 Array::ZoneHandle(Z, Array::New(catch_count, Heap::kOld));
5580
5581 Fragment catch_body = CatchBlockEntry(handler_types, try_handler_index,
5582 needs_stacktrace, is_synthetic);
5583 // Fill in the body of the catch.
5584 for (intptr_t i = 0; i < catch_count; ++i) {
5585 intptr_t catch_offset = ReaderOffset(); // Catch has no tag.
5586 TokenPosition pos = ReadPosition(); // read position.
5587 const AbstractType& type_guard = T.BuildType(); // read guard.
5588 handler_types.SetAt(i, type_guard);
5589
5590 Fragment catch_handler_body = EnterScope(catch_offset);
5591
5592 Tag tag = ReadTag(); // read first part of exception.
5593 if (tag == kSomething) {
5594 catch_handler_body += LoadLocal(CurrentException());
5595 catch_handler_body +=
5596 StoreLocal(TokenPosition::kNoSource,
5597 LookupVariable(ReaderOffset() + data_program_offset_));
5598 catch_handler_body += Drop();
5599 SkipVariableDeclaration(); // read exception.
5600 }
5601
5602 tag = ReadTag(); // read first part of stack trace.
5603 if (tag == kSomething) {
5604 catch_handler_body += LoadLocal(CurrentStackTrace());
5605 catch_handler_body +=
5606 StoreLocal(TokenPosition::kNoSource,
5607 LookupVariable(ReaderOffset() + data_program_offset_));
5608 catch_handler_body += Drop();
5609 SkipVariableDeclaration(); // read stack trace.
5610 }
5611
5612 {
5613 CatchBlock block(flow_graph_builder_, CurrentException(),
5614 CurrentStackTrace(), try_handler_index);
5615
5616 catch_handler_body += BuildStatementWithBranchCoverage(); // read body.
5617
5618 // Note: ExitScope adjusts context_depth_ so even if catch_handler_body
5619 // is closed we still need to execute ExitScope for its side effect.
5620 catch_handler_body += ExitScope(catch_offset);
5621 if (catch_handler_body.is_open()) {
5622 catch_handler_body += Goto(after_try);
5623 }
5624 }
5625
5626 if (!type_guard.IsCatchAllType()) {
5627 catch_body += LoadLocal(CurrentException());
5628
5629 if (!type_guard.IsInstantiated(kCurrentClass)) {
5630 catch_body += LoadInstantiatorTypeArguments();
5631 } else {
5632 catch_body += NullConstant();
5633 }
5634
5635 if (!type_guard.IsInstantiated(kFunctions)) {
5636 catch_body += LoadFunctionTypeArguments();
5637 } else {
5638 catch_body += NullConstant();
5639 }
5640
5641 catch_body += Constant(type_guard);
5642
5643 catch_body +=
5644 InstanceCall(pos, Library::PrivateCoreLibName(Symbols::_instanceOf()),
5645 Token::kIS, 4);
5646
5647 TargetEntryInstr* catch_entry;
5648 TargetEntryInstr* next_catch_entry;
5649 catch_body += BranchIfTrue(&catch_entry, &next_catch_entry, false);
5650
5651 Fragment(catch_entry) + catch_handler_body;
5652 catch_body = Fragment(next_catch_entry);
5653 } else {
5654 catch_body += catch_handler_body;
5655 }
5656 }
5657
5658 // In case the last catch body was not handling the exception and branching to
5659 // after the try block, we will rethrow the exception (i.e. no default catch
5660 // handler).
5661 if (catch_body.is_open()) {
5662 catch_body += LoadLocal(CurrentException());
5663 catch_body += LoadLocal(CurrentStackTrace());
5664 catch_body += RethrowException(TokenPosition::kNoSource, try_handler_index);
5665 Drop();
5666 }
5667 catch_depth_dec();
5668
5669 return Fragment(try_body.entry, after_try);
5670}
5671
5672Fragment StreamingFlowGraphBuilder::BuildTryFinally(TokenPosition* position) {
5673 // Note on streaming:
5674 // We only stream this TryFinally if we can stream everything inside it,
5675 // so creating a "TryFinallyBlock" with a kernel binary offset instead of an
5676 // AST node isn't a problem.
5677
5678 InlineBailout("kernel::FlowgraphBuilder::VisitTryFinally");
5679
5680 const TokenPosition pos = ReadPosition(); // read position.
5681 if (position != nullptr) *position = pos;
5682
5683 // There are 5 different cases where we need to execute the finally block:
5684 //
5685 // a) 1/2/3th case: Special control flow going out of `node->body()`:
5686 //
5687 // * [BreakStatement] transfers control to a [LabeledStatement]
5688 // * [ContinueSwitchStatement] transfers control to a [SwitchCase]
5689 // * [ReturnStatement] returns a value
5690 //
5691 // => All three cases will automatically append all finally blocks
5692 // between the branching point and the destination (so we don't need to
5693 // do anything here).
5694 //
5695 // b) 4th case: Translating the body resulted in an open fragment (i.e. body
5696 // executes without any control flow out of it)
5697 //
5698 // => We are responsible for jumping out of the body to a new block (with
5699 // different try index) and execute the finalizer.
5700 //
5701 // c) 5th case: An exception occurred inside the body.
5702 //
5703 // => We are responsible for catching it, executing the finally block and
5704 // rethrowing the exception.
5705 intptr_t try_handler_index = AllocateTryIndex();
5706 Fragment try_body = TryCatch(try_handler_index);
5707 JoinEntryInstr* after_try = BuildJoinEntry();
5708
5709 intptr_t offset = ReaderOffset();
5710 SkipStatement(); // temporarily read body.
5711 intptr_t finalizer_offset = ReaderOffset();
5713
5714 // Fill in the body of the try.
5715 try_depth_inc();
5716 {
5717 TryFinallyBlock tfb(flow_graph_builder_, finalizer_offset);
5718 TryCatchBlock tcb(flow_graph_builder_, try_handler_index);
5719 try_body += BuildStatementWithBranchCoverage(position); // read body.
5720 }
5721 try_depth_dec();
5722
5723 if (try_body.is_open()) {
5724 // Please note: The try index will be on level out of this block,
5725 // thereby ensuring if there's an exception in the finally block we
5726 // won't run it twice.
5727 JoinEntryInstr* finally_entry = BuildJoinEntry();
5728
5729 try_body += Goto(finally_entry);
5730
5731 Fragment finally_body(finally_entry);
5732 finally_body += BuildStatementWithBranchCoverage(); // read finalizer.
5733 finally_body += Goto(after_try);
5734 }
5735
5736 // Fill in the body of the catch.
5737 catch_depth_inc();
5738
5739 const Array& handler_types = Array::ZoneHandle(Z, Array::New(1, Heap::kOld));
5740 handler_types.SetAt(0, Object::dynamic_type());
5741 // Note: rethrow will actually force mark the handler as needing a stacktrace.
5742 Fragment finally_body = CatchBlockEntry(handler_types, try_handler_index,
5743 /* needs_stacktrace = */ false,
5744 /* is_synthesized = */ true);
5745 SetOffset(finalizer_offset);
5746
5747 // Try/finally might occur in control flow collections with non-empty
5748 // expression stack (via desugaring of 'await for'). Note that catch-block
5749 // generated for finally always throws so there is no merge.
5750 // Save and reset expression stack around catch body in order to maintain
5751 // correct stack depth, as catch entry drops expression stack.
5752 Value* const saved_stack_top = stack();
5753 set_stack(nullptr);
5754
5755 finally_body += BuildStatementWithBranchCoverage(); // read finalizer
5756 if (finally_body.is_open()) {
5757 finally_body += LoadLocal(CurrentException());
5758 finally_body += LoadLocal(CurrentStackTrace());
5759 finally_body +=
5760 RethrowException(TokenPosition::kNoSource, try_handler_index);
5761 Drop();
5762 }
5763
5764 ASSERT(stack() == nullptr);
5765 set_stack(saved_stack_top);
5766 catch_depth_dec();
5767
5768 return Fragment(try_body.entry, after_try);
5769}
5770
5771Fragment StreamingFlowGraphBuilder::BuildYieldStatement(
5772 TokenPosition* position) {
5773 const TokenPosition pos = ReadPosition(); // read position.
5774 if (position != nullptr) *position = pos;
5775
5776 const uint8_t flags = ReadByte(); // read flags.
5777
5778 Fragment instructions;
5779 const bool is_yield_star = (flags & kYieldStatementFlagYieldStar) != 0;
5780
5781 // Load :suspend_state variable using low-level FP-relative load
5782 // in order to avoid confusing SSA construction (which cannot
5783 // track its value as it is modified implicitly by stubs).
5784 LocalVariable* suspend_state = parsed_function()->suspend_state_var();
5785 ASSERT(suspend_state != nullptr);
5786 instructions += IntConstant(0);
5787 instructions += B->LoadFpRelativeSlot(
5788 compiler::target::frame_layout.FrameSlotForVariable(suspend_state) *
5789 compiler::target::kWordSize,
5790 CompileType::Dynamic(), kTagged);
5791 instructions += LoadNativeField(Slot::SuspendState_function_data());
5792
5793 instructions += BuildExpression(); // read expression.
5794 if (NeedsDebugStepCheck(parsed_function()->function(), pos)) {
5795 instructions += DebugStepCheck(pos);
5796 }
5797
5798 if (parsed_function()->function().IsAsyncGenerator()) {
5799 // In the async* functions, generate the following code for yield <expr>:
5800 //
5801 // _AsyncStarStreamController controller = :suspend_state._functionData;
5802 // if (controller.add(<expr>)) {
5803 // return;
5804 // }
5805 // if (suspend()) {
5806 // return;
5807 // }
5808 //
5809 // Generate the following code for yield* <expr>:
5810 //
5811 // _AsyncStarStreamController controller = :suspend_state._functionData;
5812 // if (controller.addStream(<expr>)) {
5813 // return;
5814 // }
5815 // if (suspend()) {
5816 // return;
5817 // }
5818 //
5819
5820 auto& add_method = Function::ZoneHandle(Z);
5821 if (is_yield_star) {
5822 add_method =
5823 IG->object_store()->async_star_stream_controller_add_stream();
5824 } else {
5825 add_method = IG->object_store()->async_star_stream_controller_add();
5826 }
5827 instructions +=
5828 StaticCall(TokenPosition::kNoSource, add_method, 2, ICData::kNoRebind);
5829
5830 TargetEntryInstr *return1, *continue1;
5831 instructions += BranchIfTrue(&return1, &continue1, false);
5832 JoinEntryInstr* return_join = BuildJoinEntry();
5833 Fragment(return1) + Goto(return_join);
5834 instructions = Fragment(instructions.entry, continue1);
5835
5836 // Suspend and test value passed to the resumed async* body.
5837 instructions += NullConstant();
5838 instructions += B->Suspend(pos, SuspendInstr::StubId::kYieldAsyncStar);
5839
5840 TargetEntryInstr *return2, *continue2;
5841 instructions += BranchIfTrue(&return2, &continue2, false);
5842 Fragment(return2) + Goto(return_join);
5843 instructions = Fragment(instructions.entry, continue2);
5844
5845 Fragment do_return(return_join);
5846 do_return += TranslateFinallyFinalizers(nullptr, -1);
5847 do_return += NullConstant();
5848 do_return += Return(TokenPosition::kNoSource);
5849
5850 } else if (parsed_function()->function().IsSyncGenerator()) {
5851 // In the sync* functions, generate the following code for yield <expr>:
5852 //
5853 // _SyncStarIterator iterator = :suspend_state._functionData;
5854 // iterator._current = <expr>;
5855 // suspend();
5856 //
5857 // Generate the following code for yield* <expr>:
5858 //
5859 // _SyncStarIterator iterator = :suspend_state._functionData;
5860 // iterator._yieldStarIterable = <expr>;
5861 // suspend();
5862 //
5863 auto& field = Field::ZoneHandle(Z);
5864 if (is_yield_star) {
5865 field = IG->object_store()->sync_star_iterator_yield_star_iterable();
5866 } else {
5867 field = IG->object_store()->sync_star_iterator_current();
5868 }
5869 instructions += B->StoreFieldGuarded(field);
5870 instructions += B->Constant(Bool::True());
5871 instructions +=
5873 instructions += Drop();
5874 } else {
5875 UNREACHABLE();
5876 }
5877
5878 return instructions;
5879}
5880
5881Fragment StreamingFlowGraphBuilder::BuildVariableDeclaration(
5882 TokenPosition* position) {
5883 intptr_t kernel_position_no_tag = ReaderOffset() + data_program_offset_;
5884 LocalVariable* variable = LookupVariable(kernel_position_no_tag);
5885
5886 VariableDeclarationHelper helper(this);
5887 helper.ReadUntilExcluding(VariableDeclarationHelper::kType);
5888 T.BuildType(); // read type.
5889 bool has_initializer = (ReadTag() != kNothing);
5890
5891 Fragment instructions;
5892 if (variable->is_late()) {
5893 // TODO(liama): Treat the field as non-late if the initializer is trivial.
5894 if (has_initializer) {
5896 }
5897 instructions += Constant(Object::sentinel());
5898 } else if (!has_initializer) {
5899 instructions += NullConstant();
5900 } else {
5901 // Initializer
5902 instructions += BuildExpression(); // read (actual) initializer.
5903 }
5904
5905 // Use position of equal sign if it exists. If the equal sign does not exist
5906 // use the position of the identifier.
5907 const TokenPosition debug_position = helper.equals_position_.IsReal()
5908 ? helper.equals_position_
5909 : helper.position_;
5910 if (position != nullptr) *position = helper.position_;
5911 if (NeedsDebugStepCheck(stack(), debug_position) && !helper.IsHoisted()) {
5912 instructions = DebugStepCheck(debug_position) + instructions;
5913 }
5914 instructions += StoreLocal(helper.position_, variable);
5915 instructions += Drop();
5916 return instructions;
5917}
5918
5919Fragment StreamingFlowGraphBuilder::BuildFunctionDeclaration(
5920 TokenPosition* position) {
5921 const intptr_t offset = ReaderOffset() - 1; // Include the tag.
5922 const TokenPosition pos = ReadPosition();
5923 if (position != nullptr) *position = pos;
5924
5925 const intptr_t variable_offset = ReaderOffset() + data_program_offset_;
5927
5928 Fragment instructions = DebugStepCheck(pos);
5929 instructions += BuildFunctionNode(offset);
5930 instructions += StoreLocal(pos, LookupVariable(variable_offset));
5931 instructions += Drop();
5932 return instructions;
5933}
5934
5935Fragment StreamingFlowGraphBuilder::BuildFunctionNode(
5936 intptr_t func_decl_offset) {
5937 const intptr_t func_node_offset = ReaderOffset();
5938 const auto& member_function =
5939 Function::Handle(Z, parsed_function()->function().GetOutermostFunction());
5940 const Function& function = Function::ZoneHandle(
5942 thread(), func_decl_offset, member_function,
5943 parsed_function()->function(), closure_owner_));
5944
5945 if (function.context_scope() == ContextScope::null()) {
5946 SafepointWriteRwLocker ml(thread(),
5947 thread()->isolate_group()->program_lock());
5948 if (function.context_scope() == ContextScope::null()) {
5949 for (intptr_t i = 0; i < scopes()->function_scopes.length(); ++i) {
5950 if (scopes()->function_scopes[i].kernel_offset !=
5951 function.kernel_offset()) {
5952 continue;
5953 }
5954
5955 LocalScope* scope = scopes()->function_scopes[i].scope;
5956 const ContextScope& context_scope = ContextScope::Handle(
5957 Z, scope->PreserveOuterScope(function,
5958 flow_graph_builder_->context_depth_));
5959 function.set_context_scope(context_scope);
5960 }
5961 }
5962 }
5963
5964 ASSERT(function.kernel_offset() == func_node_offset);
5966
5967 Fragment instructions;
5968 instructions += Constant(function);
5969 if (scopes()->IsClosureWithEmptyContext(func_node_offset)) {
5970 instructions += NullConstant();
5971 } else {
5972 instructions += LoadLocal(parsed_function()->current_context_var());
5973 }
5974 // The function signature can have uninstantiated class type parameters.
5975 const bool has_instantiator_type_args =
5976 !function.HasInstantiatedSignature(kCurrentClass);
5977 if (has_instantiator_type_args) {
5978 instructions += LoadInstantiatorTypeArguments();
5979 }
5980 instructions += flow_graph_builder_->AllocateClosure(
5981 function.token_pos(), has_instantiator_type_args, function.IsGeneric(),
5982 /*is_tear_off=*/false);
5983 LocalVariable* closure = MakeTemporary();
5984
5985 // TODO(30455): We only need to save these if the closure uses any captured
5986 // type parameters.
5987 instructions += LoadLocal(closure);
5988 instructions += LoadFunctionTypeArguments();
5989 instructions += flow_graph_builder_->StoreNativeField(
5990 Slot::Closure_function_type_arguments(),
5992
5993 return instructions;
5994}
5995
5996Fragment StreamingFlowGraphBuilder::BuildNativeEffect() {
5997 const intptr_t argc = ReadUInt(); // Read argument count.
5998 ASSERT(argc == 1); // Native side effect to ignore.
5999 const intptr_t list_length = ReadListLength(); // Read types list length.
6000 ASSERT(list_length == 0);
6001
6002 const intptr_t positional_count =
6003 ReadListLength(); // Read positional argument count.
6004 ASSERT(positional_count == 1);
6005
6006 BuildExpression(); // Consume expression but don't save the fragment.
6007 Pop(); // Restore the stack.
6008
6009 const intptr_t named_args_len =
6010 ReadListLength(); // Skip empty named arguments.
6011 ASSERT(named_args_len == 0);
6012
6013 Fragment code;
6014 code += NullConstant(); // Return type is void.
6015 return code;
6016}
6017
6018Fragment StreamingFlowGraphBuilder::BuildReachabilityFence() {
6019 const intptr_t argc = ReadUInt(); // Read argument count.
6020 ASSERT(argc == 1); // LoadField, can be late.
6021 const intptr_t list_length = ReadListLength(); // Read types list length.
6022 ASSERT(list_length == 0);
6023
6024 const intptr_t positional_count = ReadListLength();
6025 ASSERT(positional_count == 1);
6026
6027 // The CFE transform only generates a subset of argument expressions:
6028 // either variable get or `this`. However, subsequent transforms can
6029 // generate different expressions, including: constant expressions.
6030 // So, build an arbitrary expression here instead.
6031 TokenPosition* position = nullptr;
6032 Fragment code = BuildExpression(position);
6033
6034 const intptr_t named_args_len = ReadListLength();
6035 ASSERT(named_args_len == 0);
6036
6037 code <<= new (Z) ReachabilityFenceInstr(Pop());
6038 code += NullConstant(); // Return type is void.
6039 return code;
6040}
6041
6042static void ReportIfNotNull(const char* error) {
6043 if (error != nullptr) {
6044 const auto& language_error = Error::Handle(
6045 LanguageError::New(String::Handle(String::New(error, Heap::kOld)),
6047 Report::LongJump(language_error);
6048 }
6049}
6050
6051Fragment StreamingFlowGraphBuilder::BuildLoadStoreAbiSpecificInt(
6052 bool is_store,
6053 bool at_index) {
6054 const intptr_t argument_count = ReadUInt(); // Read argument count.
6055 const intptr_t expected_argument_count = 2 // TypedDataBase, offset
6056 + (at_index ? 1 : 0) // index
6057 + (is_store ? 1 : 0); // value
6058 ASSERT_EQUAL(argument_count, expected_argument_count);
6059 const intptr_t list_length = ReadListLength();
6060 ASSERT_EQUAL(list_length, 1);
6061 // Read types.
6062 const TypeArguments& type_arguments = T.BuildTypeArguments(list_length);
6063 const AbstractType& type_argument =
6064 AbstractType::Handle(type_arguments.TypeAt(0));
6065
6066 // AbiSpecificTypes can have an incomplete mapping.
6067 const char* error = nullptr;
6068 const auto* native_type =
6071
6072 Fragment code;
6073 // Read positional argument count.
6074 const intptr_t positional_count = ReadListLength();
6075 ASSERT(positional_count == argument_count);
6076 code += BuildExpression(); // Argument 1: typedDataBase.
6077 code += BuildExpression(); // Argument 2: offsetInBytes
6078 if (at_index) {
6079 code += BuildExpression(); // Argument 3: index
6080 code += IntConstant(native_type->SizeInBytes());
6081 code += B->BinaryIntegerOp(Token::kMUL, kTagged, /* truncate= */ true);
6082 code += B->BinaryIntegerOp(Token::kADD, kTagged, /* truncate= */ true);
6083 }
6084 if (is_store) {
6085 code += BuildExpression(); // Argument 4: value
6086 }
6087
6088 // Skip (empty) named arguments list.
6089 const intptr_t named_args_len = ReadListLength();
6090 ASSERT(named_args_len == 0);
6091
6092 // This call site is not guaranteed to be optimized. So, do a call to the
6093 // correct force optimized function instead of compiling the body.
6095 if (is_store) {
6096 kind = compiler::ffi::FfiStore(*native_type);
6097 } else {
6098 kind = compiler::ffi::FfiLoad(*native_type);
6099 }
6101 const Library& ffi_library = Library::Handle(Z, Library::FfiLibrary());
6102 const Function& target = Function::ZoneHandle(
6103 Z, ffi_library.LookupFunctionAllowPrivate(
6105 ASSERT(!target.IsNull());
6106 Array& argument_names = Array::ZoneHandle(Z);
6107 const intptr_t static_call_arg_count = 2 + (is_store ? 1 : 0);
6108 code += StaticCall(TokenPosition::kNoSource, target, static_call_arg_count,
6109 argument_names, ICData::kStatic);
6110
6111 return code;
6112}
6113
6114Fragment StreamingFlowGraphBuilder::BuildFfiCall() {
6115 const intptr_t argc = ReadUInt(); // Read argument count.
6116 ASSERT(argc == 1); // Target pointer.
6117 const intptr_t list_length = ReadListLength(); // Read types list length.
6118 T.BuildTypeArguments(list_length); // Read types.
6119 // Read positional argument count.
6120 const intptr_t positional_count = ReadListLength();
6121 ASSERT(positional_count == argc);
6122
6123 Fragment code;
6124 // Push the target function pointer passed as Pointer object.
6125 code += BuildExpression();
6126 // This can only be Pointer, so the data field points to unmanaged memory.
6127 code += LoadNativeField(Slot::PointerBase_data(),
6129
6130 // Skip (empty) named arguments list.
6131 const intptr_t named_args_len = ReadListLength();
6132 ASSERT(named_args_len == 0);
6133
6134 const auto& native_type = FunctionType::ZoneHandle(
6135 Z, parsed_function()->function().FfiCSignature());
6136
6137 // AbiSpecificTypes can have an incomplete mapping.
6138 const char* error = nullptr;
6140 if (error != nullptr) {
6141 const auto& language_error = Error::Handle(
6142 LanguageError::New(String::Handle(String::New(error, Heap::kOld)),
6144 Report::LongJump(language_error);
6145 }
6146
6147 code += B->FfiCallFunctionBody(parsed_function()->function(), native_type,
6148 /*first_argument_parameter_offset=*/1);
6149
6150 ASSERT(code.is_closed());
6151
6152 NullConstant(); // Maintain stack balance.
6153
6154 return code;
6155}
6156
6157Fragment StreamingFlowGraphBuilder::BuildArgumentsCachableIdempotentCall(
6158 intptr_t* argument_count) {
6159 *argument_count = ReadUInt(); // read arguments count.
6160
6161 // List of types.
6162 const intptr_t types_list_length = ReadListLength();
6163 if (types_list_length != 0) {
6164 FATAL("Type arguments for vm:cachable-idempotent not (yet) supported.");
6165 }
6166
6167 Fragment code;
6168 // List of positional.
6169 intptr_t positional_list_length = ReadListLength();
6170 for (intptr_t i = 0; i < positional_list_length; ++i) {
6171 code += BuildExpression();
6172 Definition* target_def = B->Peek();
6173 if (!target_def->IsConstant()) {
6174 FATAL(
6175 "Arguments for vm:cachable-idempotent must be const, argument on "
6176 "index %" Pd " is not.",
6177 i);
6178 }
6179 }
6180
6181 // List of named.
6182 const intptr_t named_args_len = ReadListLength();
6183 if (named_args_len != 0) {
6184 FATAL("Named arguments for vm:cachable-idempotent not (yet) supported.");
6185 }
6186
6187 return code;
6188}
6189
6190Fragment StreamingFlowGraphBuilder::BuildCachableIdempotentCall(
6191 TokenPosition position,
6192 const Function& target) {
6193 // The call site must me fore optimized because the cache is untagged.
6194 if (!parsed_function()->function().ForceOptimize()) {
6195 FATAL(
6196 "vm:cachable-idempotent functions can only be called from "
6197 "vm:force-optimize functions.");
6198 }
6199 const auto& target_result_type = AbstractType::Handle(target.result_type());
6200 if (!target_result_type.IsIntType()) {
6201 FATAL("The return type vm:cachable-idempotent functions must be int.")
6202 }
6203
6204 Fragment code;
6205 Array& argument_names = Array::ZoneHandle(Z);
6206 intptr_t argument_count;
6207 code += BuildArgumentsCachableIdempotentCall(&argument_count);
6208
6209 code += flow_graph_builder_->CachableIdempotentCall(
6210 position, kUnboxedAddress, target, argument_count, argument_names,
6211 /*type_args_len=*/0);
6212
6213 return code;
6214}
6215
6216Fragment StreamingFlowGraphBuilder::BuildFfiNativeCallbackFunction(
6217 FfiCallbackKind kind) {
6218 // The call-site must look like this (guaranteed by the FE which inserts it):
6219 //
6220 // FfiCallbackKind::kIsolateLocalStaticCallback:
6221 // _nativeCallbackFunction<NativeSignatureType>(target, exceptionalReturn)
6222 //
6223 // FfiCallbackKind::kAsyncCallback:
6224 // _nativeAsyncCallbackFunction<NativeSignatureType>()
6225 //
6226 // FfiCallbackKind::kIsolateLocalClosureCallback:
6227 // _nativeIsolateLocalCallbackFunction<NativeSignatureType>(
6228 // exceptionalReturn)
6229 //
6230 // The FE also guarantees that the arguments are constants.
6231
6232 const bool has_target = kind == FfiCallbackKind::kIsolateLocalStaticCallback;
6233 const bool has_exceptional_return = kind != FfiCallbackKind::kAsyncCallback;
6234 const intptr_t expected_argc =
6235 static_cast<int>(has_target) + static_cast<int>(has_exceptional_return);
6236
6237 const intptr_t argc = ReadUInt(); // Read argument count.
6238 ASSERT(argc == expected_argc);
6239
6240 const intptr_t list_length = ReadListLength(); // Read types list length.
6241 ASSERT(list_length == 1); // The native signature.
6242 const TypeArguments& type_arguments =
6243 T.BuildTypeArguments(list_length); // Read types.
6244 ASSERT(type_arguments.Length() == 1 && type_arguments.IsInstantiated());
6245 const FunctionType& native_sig =
6246 FunctionType::CheckedHandle(Z, type_arguments.TypeAt(0));
6247
6248 Fragment code;
6249 const intptr_t positional_count =
6250 ReadListLength(); // Read positional argument count.
6251 ASSERT(positional_count == expected_argc);
6252
6253 // Read target expression and extract the target function.
6254 Function& target = Function::Handle(Z, Function::null());
6255 Instance& exceptional_return = Instance::ZoneHandle(Z, Instance::null());
6256
6257 if (has_target) {
6258 // Build target argument.
6259 code += BuildExpression();
6260 Definition* target_def = B->Peek();
6261 ASSERT(target_def->IsConstant());
6262 const Closure& target_closure =
6263 Closure::Cast(target_def->AsConstant()->value());
6264 ASSERT(!target_closure.IsNull());
6265 target = target_closure.function();
6266 ASSERT(!target.IsNull() && target.IsImplicitClosureFunction());
6267 target = target.parent_function();
6268 code += Drop();
6269 }
6270
6271 if (has_exceptional_return) {
6272 // Build exceptionalReturn argument.
6273 code += BuildExpression();
6274 Definition* exceptional_return_def = B->Peek();
6275 ASSERT(exceptional_return_def->IsConstant());
6276 exceptional_return ^= exceptional_return_def->AsConstant()->value().ptr();
6277 code += Drop();
6278 }
6279
6280 const intptr_t named_args_len =
6281 ReadListLength(); // Skip (empty) named arguments list.
6282 ASSERT(named_args_len == 0);
6283
6284 // AbiSpecificTypes can have an incomplete mapping.
6285 const char* error = nullptr;
6288
6289 const Function& result = Function::ZoneHandle(
6291 exceptional_return, kind));
6292 code += Constant(result);
6293
6294 return code;
6295}
6296
6297Fragment StreamingFlowGraphBuilder::BuildFfiNativeAddressOf() {
6298 const intptr_t argc = ReadUInt();
6299 ASSERT(argc == 1);
6300 const intptr_t types_length = ReadListLength();
6301 ASSERT(types_length == 1);
6302 T.BuildTypeArguments(types_length);
6303 const intptr_t positional_count = ReadListLength();
6304 ASSERT(positional_count == 1);
6305
6306 Fragment frag = BuildExpression();
6307 ASSERT(frag.entry->IsConstant());
6308 const auto& native_annotation =
6309 Instance::Cast(frag.entry->AsConstant()->value());
6310 Drop();
6311
6312 const auto& pointer_class =
6313 Class::ZoneHandle(Z, IG->object_store()->ffi_pointer_class());
6314 const auto& type_arguments =
6315 TypeArguments::ZoneHandle(Z, IG->object_store()->type_argument_never());
6316 Fragment code = Constant(type_arguments);
6317 code += AllocateObject(TokenPosition::kNoSource, pointer_class, 1);
6318 code += LoadLocal(MakeTemporary()); // Duplicate Pointer.
6319 // FfiNativeLookupAddress pushes an unboxed value, which is safe even in
6320 // unoptimized mode because then there is no reordering and we're consuming
6321 // the value directly.
6322 code += flow_graph_builder_->FfiNativeLookupAddress(native_annotation);
6323 code += flow_graph_builder_->StoreNativeField(
6324 Slot::PointerBase_data(), InnerPointerAccess::kCannotBeInnerPointer,
6326
6327 const intptr_t named_arg_count = ReadListLength();
6328 ASSERT(named_arg_count == 0);
6329 return code;
6330}
6331
6332} // namespace kernel
6333} // namespace dart
static bool compare(const SkBitmap &ref, const SkIRect &iref, const SkBitmap &test, const SkIRect &itest)
Definition BlurTest.cpp:100
static void done(const char *config, const char *src, const char *srcOptions, const char *name)
Definition DM.cpp:263
SkPoint pos
static float next(float f)
static bool left(const SkPoint &p0, const SkPoint &p1)
static bool right(const SkPoint &p0, const SkPoint &p1)
#define F(x)
#define IG
#define UNREACHABLE()
Definition assert.h:248
#define ASSERT_EQUAL(expected, actual)
Definition assert.h:309
#define RELEASE_ASSERT(cond)
Definition assert.h:327
#define Z
static ArrayPtr NewBoxed(intptr_t type_args_len, intptr_t num_arguments, const Array &optional_arguments_names, Heap::Space space=Heap::kOld)
Definition dart_entry.h:83
static ArrayPtr New(intptr_t len, Heap::Space space=Heap::kNew)
Definition object.h:10933
static const Bool & False()
Definition object.h:10778
static const Bool & Get(bool value)
Definition object.h:10780
static const Bool & True()
Definition object.h:10776
FunctionPtr LookupStaticFunction(const String &name) const
Definition object.cc:6192
ErrorPtr EnsureIsFinalized(Thread *thread) const
Definition object.cc:4979
ClassPtr SuperClass(ClassTable *class_table=nullptr) const
Definition object.cc:3715
static FunctionPtr LookupClosureFunction(const Function &member_function, intptr_t kernel_offset)
static CompileType Dynamic()
static CompilerState & Current()
void ClearTempIndex()
Definition il.h:2482
static DoublePtr NewCanonical(double d)
Definition object.cc:23497
static constexpr CompilationMode CompilationModeFrom(bool is_optimizing)
Definition flow_graph.h:587
intptr_t NumOptionalParameters() const
Definition object.cc:8926
intptr_t kernel_offset() const
Definition object.h:3530
intptr_t NumTypeParameters() const
Definition object.cc:8905
static StringPtr CreateDynamicInvocationForwarderName(const String &name)
Definition object.cc:4255
intptr_t NumParameters() const
Definition object.cc:8935
@ kOld
Definition heap.h:39
static IntegerPtr NewCanonical(const String &str)
Definition object.cc:23078
static LibraryPtr CoreLibrary()
Definition object.cc:14834
static ClassPtr LookupCoreClass(const String &class_name)
Definition object.cc:14736
static const String & PrivateCoreLibName(const String &member)
Definition object.cc:14721
static LibraryPtr InternalLibrary()
Definition object.cc:14850
static LibraryPtr FfiLibrary()
Definition object.cc:14846
TokenPosition token_pos() const
Definition scopes.h:117
static const char * KindToFunctionNameCString(Kind kind)
static Token::Kind RecognizeTokenKind(const String &name)
static ObjectPtr null()
Definition object.h:433
ObjectPtr ptr() const
Definition object.h:332
bool IsNull() const
Definition object.h:363
static Object & Handle()
Definition object.h:407
static ObjectPtr RawCast(ObjectPtr obj)
Definition object.h:325
static Object & ZoneHandle()
Definition object.h:419
LocalVariable * expression_temp_var() const
Definition parser.h:151
const Function & function() const
Definition parser.h:73
LocalScope * scope() const
Definition parser.h:76
void set_default_parameter_values(ZoneGrowableArray< const Instance * > *list)
Definition parser.h:109
void MarkForwardingStub(const Function *forwarding_target)
Definition parser.h:207
LocalVariable * ParameterVariable(intptr_t i) const
Definition parser.h:239
LocalVariable * suspend_state_var() const
Definition parser.h:103
LocalVariable * function_type_arguments() const
Definition parser.h:88
static RecordShape Register(Thread *thread, intptr_t num_fields, const Array &field_names)
Definition object.cc:27980
static DART_NORETURN void LongJump(const Error &error)
Definition report.cc:86
static FunctionPtr ResolveDynamicFunction(Zone *zone, const Class &receiver_class, const String &function_name)
Definition resolver.cc:189
static FunctionPtr ResolveFunction(Zone *zone, const Class &receiver_class, const String &function_name)
Definition resolver.cc:180
static FunctionPtr ResolveDynamicForReceiverClassAllowPrivate(const Class &receiver_class, const String &function_name, const ArgumentsDescriptor &args_desc, bool allow_add)
Definition resolver.cc:170
static const Slot & GetContextVariableSlotFor(Thread *thread, const LocalVariable &var)
Definition slot.cc:292
static const Slot & GetRecordFieldSlot(Thread *thread, intptr_t offset_in_bytes)
Definition slot.cc:324
static StringPtr New(const char *cstr, Heap::Space space=Heap::kNew)
Definition object.cc:23777
static const String & Empty()
Definition symbols.h:687
static StringPtr New(Thread *thread, const char *cstr)
Definition symbols.h:722
static const String & Minus()
Definition symbols.h:617
static TokenPosition Synthetic(intptr_t value)
static TypeArgumentsPtr New(intptr_t len, Heap::Space space=Heap::kOld)
Definition object.cc:7733
AbstractTypePtr TypeAt(intptr_t index) const
Definition object.cc:7366
Definition * definition() const
Definition il.h:103
static const NativeType * FromAbstractType(Zone *zone, const AbstractType &type, const char **error)
Fragment StoreNativeField(TokenPosition position, const Slot &slot, InnerPointerAccess stores_inner_pointer, StoreFieldInstr::Kind kind=StoreFieldInstr::Kind::kOther, StoreBarrierType emit_store_barrier=kEmitStoreBarrier, compiler::Assembler::MemoryOrder memory_order=compiler::Assembler::kRelaxedNonAtomic)
Fragment ThrowException(TokenPosition position)
Fragment DebugStepCheck(TokenPosition position)
Fragment StoreField(const Field &field, StoreFieldInstr::Kind kind=StoreFieldInstr::Kind::kOther, StoreBarrierType emit_store_barrier=kEmitStoreBarrier)
Fragment CheckNull(TokenPosition position, LocalVariable *receiver, const String &function_name)
Fragment StoreStaticField(TokenPosition position, const Field &field)
Fragment InstantiateType(const AbstractType &type)
Fragment RecordBranchCoverage(TokenPosition position)
Fragment StoreLocal(LocalVariable *variable)
Fragment DropTempsPreserveTop(intptr_t num_temps_to_drop)
FunctionEntryInstr * BuildFunctionEntry(GraphEntryInstr *graph_entry)
Fragment LoadNativeField(const Slot &native_field, InnerPointerAccess loads_inner_pointer, bool calls_initializer=false)
Fragment StoreFieldGuarded(const Field &field, StoreFieldInstr::Kind kind=StoreFieldInstr::Kind::kOther)
Fragment LoadStaticField(const Field &field, bool calls_initializer)
Fragment BranchIfTrue(TargetEntryInstr **then_entry, TargetEntryInstr **otherwise_entry, bool negate=false)
Fragment BranchIfEqual(TargetEntryInstr **then_entry, TargetEntryInstr **otherwise_entry, bool negate=false)
Fragment RedefinitionWithType(const AbstractType &type)
Fragment RecordCoverage(TokenPosition position)
LocalVariable * MakeTemporary(const char *suffix=nullptr)
Fragment CheckStackOverflow(TokenPosition position, intptr_t stack_depth, intptr_t loop_depth)
Fragment AllocateClosure(TokenPosition position, bool has_instantiator_type_args, bool is_generic, bool is_tear_off)
Fragment StrictCompare(TokenPosition position, Token::Kind kind, bool number_check=false)
Fragment AllocateObject(TokenPosition position, const Class &klass, intptr_t argument_count)
Fragment StoreIndexed(classid_t class_id)
Fragment BranchIfNull(TargetEntryInstr **then_entry, TargetEntryInstr **otherwise_entry, bool negate=false)
Fragment DropTemporary(LocalVariable **temp)
Fragment Goto(JoinEntryInstr *destination)
Fragment AllocateContext(const ZoneGrowableArray< const Slot * > &scope)
Fragment BranchIfStrictEqual(TargetEntryInstr **then_entry, TargetEntryInstr **otherwise_entry)
JoinEntryInstr * BreakDestination(intptr_t label_index, TryFinallyBlock **outer_finally, intptr_t *context_depth)
CallSiteAttributesMetadata GetCallSiteAttributes(intptr_t node_offset)
InstancePtr ReadConstant(intptr_t constant_index)
DirectCallMetadata GetDirectTargetForPropertyGet(intptr_t node_offset)
DirectCallMetadata GetDirectTargetForFunctionInvocation(intptr_t node_offset)
DirectCallMetadata GetDirectTargetForMethodInvocation(intptr_t node_offset)
DirectCallMetadata GetDirectTargetForPropertySet(intptr_t node_offset)
static bool IsRecognizedMethodForFlowGraph(const Function &function)
InferredTypeMetadata GetInferredType(intptr_t node_offset, bool read_constant=true)
static FunctionPtr GetClosureFunction(Thread *thread, intptr_t func_decl_offset, const Function &member_function, const Function &parent_function, const Object &closure_owner)
Tag ReadTag(uint8_t *payload=nullptr)
virtual void ReportUnexpectedTag(const char *variant, Tag tag)
Tag PeekTag(uint8_t *payload=nullptr)
static constexpr int kInvalidName
Definition kernel.h:21
static bool HasEmptyPrologue(const Function &function)
intptr_t offset() const
Nullability ReadNullability()
Tag ReadTag(uint8_t *payload=nullptr)
static const char * TagName(Tag tag)
Tag PeekTag(uint8_t *payload=nullptr)
GrowableArray< FunctionScope > function_scopes
void ReportUnexpectedTag(const char *variant, Tag tag) override
Fragment BuildStatementAt(intptr_t kernel_offset)
JoinEntryInstr * Destination(intptr_t target_index, TryFinallyBlock **outer_finally=nullptr, intptr_t *context_depth=nullptr)
static SwitchRange Leaf(intptr_t index, Fragment branch_instructions, bool is_bounds_checked=false)
static SwitchRange Branch(intptr_t min, intptr_t max, Fragment branch_instructions)
ZoneGrowableArray< TargetEntryInstr ** > SuccessorAddressArray
TestFragment Negate(bool negate)
#define UNIMPLEMENTED
#define ASSERT(E)
VkInstance instance
Definition main.cc:48
static bool b
struct MyStruct s
struct MyStruct a[10]
#define FATAL(error)
AtkStateType state
FlutterSemanticsFlag flags
const uint8_t uint32_t uint32_t GError ** error
uint8_t value
GAsyncResult * result
uint32_t * target
Dart_NativeFunction function
Definition fuchsia.cc:51
int argument_count
Definition fuchsia.cc:52
size_t length
Win32Message message
MethodRecognizer::Kind FfiStore(const NativeType &native_type)
FunctionPtr NativeCallbackFunction(const FunctionType &c_signature, const Function &dart_target, const Instance &exceptional_return, FfiCallbackKind kind)
Definition callback.cc:36
MethodRecognizer::Kind FfiLoad(const NativeType &native_type)
const NativeFunctionType * NativeFunctionTypeFromFunctionType(Zone *zone, const FunctionType &c_signature, const char **error)
Definition marshaller.cc:34
static void ReportIfNotNull(const char *error)
static Function & GetNoSuchMethodOrDie(Thread *thread, Zone *zone, const Class &klass)
static constexpr int SpecializedIntLiteralBias
@ kYieldStatementFlagYieldStar
@ kSwitchDispatchLinearScan
@ kSwitchDispatchBinarySearch
@ kInstanceInvocationFlagInvariant
static const char *const names[]
Definition symbols.cc:24
const char *const name
InnerPointerAccess
Definition il.h:6246
Nullability
Definition object.h:1112
FfiCallbackKind
Definition object.h:2964
bool SimpleInstanceOfType(const AbstractType &type)
DART_WARN_UNUSED_RESULT ErrorPtr VerifyEntryPoint(const Library &lib, const Object &member, const Object &annotated, std::initializer_list< EntryPointPragma > allowed_kinds)
Definition object.cc:27227
@ kNoRegister
static constexpr Representation kUnboxedAddress
Definition locations.h:182
@ kFunctions
Definition object.h:2231
@ kCurrentClass
Definition object.h:2230
const char *const function_name
std::function< void()> closure
Definition closure.h:14
SINT Vec< 2 *N, T > join(const Vec< N, T > &lo, const Vec< N, T > &hi)
Definition SkVx.h:242
#define Pd
Definition globals.h:408
#define T
Point offset
Definition SkMD5.cpp:120
Definition SkMD5.cpp:130
static constexpr Register kValue2Reg