Flutter Engine
The Flutter Engine
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
1301 return reader_.ReadNullability();
1302}
1303
1305 return reader_.ReadVariance();
1306}
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(
1479 args_desc));
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))
3354 ? InvocationMirror::Level::kTopLevel
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)),
3517 argument_count, InvocationMirror::Level::kConstructor,
3518 InvocationMirror::Kind::kMethod);
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)),
3557 argument_count, InvocationMirror::Level::kConstructor,
3558 InvocationMirror::Kind::kMethod);
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(
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 Fragment instructions = BuildExpression(); // read operand.
3962
3963 const AbstractType& type = T.BuildType(); // read type.
3964
3965 instructions += BuildIsTest(position, type);
3966 return instructions;
3967}
3968
3969Fragment StreamingFlowGraphBuilder::BuildAsExpression(TokenPosition* p) {
3970 TokenPosition position = ReadPosition(); // read position.
3971 if (p != nullptr) *p = position;
3972
3973 const uint8_t flags = ReadFlags(); // read flags.
3974 const bool is_unchecked_cast = (flags & kAsExpressionFlagUnchecked) != 0;
3975 const bool is_type_error = (flags & kAsExpressionFlagTypeError) != 0;
3976
3977 Fragment instructions = BuildExpression(); // read operand.
3978
3979 const AbstractType& type = T.BuildType(); // read type.
3980 if (is_unchecked_cast ||
3981 (type.IsInstantiated() && type.IsTopTypeForSubtyping())) {
3982 // We already evaluated the operand on the left and just leave it there as
3983 // the result of unchecked cast or `obj as dynamic` expression.
3984 } else {
3985 // We do not care whether the 'as' cast as implicitly added by the frontend
3986 // or explicitly written by the user, in both cases we use an assert
3987 // assignable.
3988 instructions += B->AssertAssignableLoadTypeArguments(
3989 position, type,
3990 is_type_error ? Symbols::Empty() : Symbols::InTypeCast(),
3991 AssertAssignableInstr::kInsertedByFrontend);
3992 }
3993 return instructions;
3994}
3995
3996Fragment StreamingFlowGraphBuilder::BuildTypeLiteral(TokenPosition* position) {
3997 TokenPosition pos = ReadPosition(); // read position.
3998 if (position != nullptr) *position = pos;
3999
4000 const AbstractType& type = T.BuildType(); // read type.
4001 Fragment instructions;
4002 if (type.IsInstantiated()) {
4003 instructions += Constant(type);
4004 } else {
4005 if (!type.IsInstantiated(kCurrentClass)) {
4006 instructions += LoadInstantiatorTypeArguments();
4007 } else {
4008 instructions += NullConstant();
4009 }
4010 if (!type.IsInstantiated(kFunctions)) {
4011 instructions += LoadFunctionTypeArguments();
4012 } else {
4013 instructions += NullConstant();
4014 }
4015 instructions += InstantiateType(type);
4016 }
4017 return instructions;
4018}
4019
4020Fragment StreamingFlowGraphBuilder::BuildThisExpression(
4021 TokenPosition* position) {
4022 ReadPosition(); // ignore file offset.
4023 if (position != nullptr) *position = TokenPosition::kNoSource;
4024
4025 return LoadLocal(parsed_function()->receiver_var());
4026}
4027
4028Fragment StreamingFlowGraphBuilder::BuildRethrow(TokenPosition* p) {
4029 TokenPosition position = ReadPosition(); // read position.
4030 if (p != nullptr) *p = position;
4031
4032 Fragment instructions = DebugStepCheck(position);
4033 instructions += LoadLocal(catch_block()->exception_var());
4034 instructions += LoadLocal(catch_block()->stack_trace_var());
4035 instructions += RethrowException(position, catch_block()->catch_try_index());
4036
4037 return instructions;
4038}
4039
4040Fragment StreamingFlowGraphBuilder::BuildThrow(TokenPosition* p) {
4041 TokenPosition position = ReadPosition(); // read position.
4042 if (p != nullptr) *p = position;
4043
4044 Fragment instructions;
4045
4046 const uint8_t flags = ReadByte();
4047 const bool is_synthetic_error_handler = (flags & kThrowForErrorHandling) != 0;
4048 if (is_synthetic_error_handler) {
4049 synthetic_error_handler_depth_inc();
4050 }
4051
4052 instructions += BuildExpression(); // read expression.
4053
4054 if (NeedsDebugStepCheck(stack(), position)) {
4055 instructions = DebugStepCheck(position) + instructions;
4056 }
4057 instructions += ThrowException(position);
4058 ASSERT(instructions.is_closed());
4059
4060 if (is_synthetic_error_handler) {
4061 synthetic_error_handler_depth_dec();
4062 }
4063
4064 return instructions;
4065}
4066
4067Fragment StreamingFlowGraphBuilder::BuildListLiteral(TokenPosition* p) {
4068 TokenPosition position = ReadPosition(); // read position.
4069 if (p != nullptr) *p = position;
4070
4071 const TypeArguments& type_arguments = T.BuildTypeArguments(1); // read type.
4072 intptr_t length = ReadListLength(); // read list length.
4073 // Note: there will be "length" expressions.
4074
4075 // The type argument for the factory call.
4076 Fragment instructions = TranslateInstantiatedTypeArguments(type_arguments);
4077
4078 // List literals up to 8 elements are lowered in the front-end
4079 // (pkg/vm/lib/transformations/list_literals_lowering.dart)
4080 const intptr_t kNumSpecializedListLiteralConstructors = 8;
4081 ASSERT(length > kNumSpecializedListLiteralConstructors);
4082
4083 LocalVariable* type = MakeTemporary();
4084 instructions += LoadLocal(type);
4085
4086 // The type arguments for CreateArray.
4087 instructions += LoadLocal(type);
4088 instructions += IntConstant(length);
4089 instructions += CreateArray();
4090
4091 LocalVariable* array = MakeTemporary();
4092 for (intptr_t i = 0; i < length; ++i) {
4093 instructions += LoadLocal(array);
4094 instructions += IntConstant(i);
4095 instructions += BuildExpression(); // read ith expression.
4096 instructions += StoreIndexed(kArrayCid);
4097 }
4098
4099 const Class& growable_list_class =
4100 Class::Handle(Z, Library::LookupCoreClass(Symbols::_GrowableList()));
4101 ASSERT(!growable_list_class.IsNull());
4102
4103 const Function& factory_method =
4104 Function::ZoneHandle(Z, growable_list_class.LookupFunctionAllowPrivate(
4105 Symbols::_GrowableListLiteralFactory()));
4106 ASSERT(!factory_method.IsNull());
4107
4108 instructions += StaticCall(position, factory_method, 2, ICData::kStatic);
4109 instructions += DropTempsPreserveTop(1); // Instantiated type_arguments.
4110 return instructions;
4111}
4112
4113Fragment StreamingFlowGraphBuilder::BuildMapLiteral(TokenPosition* p) {
4114 TokenPosition position = ReadPosition(); // read position.
4115 if (p != nullptr) *p = position;
4116
4117 const TypeArguments& type_arguments =
4118 T.BuildTypeArguments(2); // read key_type and value_type.
4119
4120 // The type argument for the factory call `new Map<K, V>._fromLiteral(List)`.
4121 Fragment instructions = TranslateInstantiatedTypeArguments(type_arguments);
4122
4123 intptr_t length = ReadListLength(); // read list length.
4124 // Note: there will be "length" map entries (i.e. key and value expressions).
4125
4126 if (length == 0) {
4127 instructions += Constant(Object::empty_array());
4128 } else {
4129 // The type arguments for `new List<X>(int len)`.
4130 instructions += Constant(TypeArguments::ZoneHandle(Z));
4131
4132 // We generate a list of tuples, i.e. [key1, value1, ..., keyN, valueN].
4133 instructions += IntConstant(2 * length);
4134 instructions += CreateArray();
4135
4136 LocalVariable* array = MakeTemporary();
4137 for (intptr_t i = 0; i < length; ++i) {
4138 instructions += LoadLocal(array);
4139 instructions += IntConstant(2 * i);
4140 instructions += BuildExpression(); // read ith key.
4141 instructions += StoreIndexed(kArrayCid);
4142
4143 instructions += LoadLocal(array);
4144 instructions += IntConstant(2 * i + 1);
4145 instructions += BuildExpression(); // read ith value.
4146 instructions += StoreIndexed(kArrayCid);
4147 }
4148 }
4149
4150 const Class& map_class =
4151 Class::Handle(Z, Library::LookupCoreClass(Symbols::Map()));
4152 Function& factory_method = Function::ZoneHandle(Z);
4153 if (map_class.EnsureIsFinalized(H.thread()) == Error::null()) {
4154 factory_method = map_class.LookupFactory(
4155 Library::PrivateCoreLibName(Symbols::MapLiteralFactory()));
4156 }
4157
4158 return instructions +
4159 StaticCall(position, factory_method, 2, ICData::kStatic);
4160}
4161
4162Fragment StreamingFlowGraphBuilder::BuildRecordLiteral(TokenPosition* p) {
4163 const TokenPosition position = ReadPosition(); // read position.
4164 if (p != nullptr) *p = position;
4165
4166 // Figure out record shape.
4167 const intptr_t positional_count = ReadListLength();
4168 intptr_t named_count = -1;
4169 const Array* field_names = &Object::empty_array();
4170 {
4171 AlternativeReadingScope alt(&reader_);
4172 for (intptr_t i = 0; i < positional_count; ++i) {
4174 }
4175 named_count = ReadListLength();
4176 if (named_count > 0) {
4177 Array& names = Array::ZoneHandle(Z, Array::New(named_count, Heap::kOld));
4178 for (intptr_t i = 0; i < named_count; ++i) {
4179 String& name =
4180 H.DartSymbolObfuscate(ReadStringReference()); // read ith name.
4181 SkipExpression(); // read ith expression.
4182 names.SetAt(i, name);
4183 }
4184 names.MakeImmutable();
4185 field_names = &names;
4186 }
4187 }
4188 const intptr_t num_fields = positional_count + named_count;
4189 const RecordShape shape =
4190 RecordShape::Register(thread(), num_fields, *field_names);
4191 Fragment instructions;
4192
4193 if (num_fields == 2 ||
4194 (num_fields == 3 && AllocateSmallRecordABI::kValue2Reg != kNoRegister)) {
4195 // Generate specialized allocation for a small number of fields.
4196 for (intptr_t i = 0; i < positional_count; ++i) {
4197 instructions += BuildExpression(); // read ith expression.
4198 }
4199 ReadListLength(); // read list length.
4200 for (intptr_t i = 0; i < named_count; ++i) {
4201 SkipStringReference(); // read ith name.
4202 instructions += BuildExpression(); // read ith expression.
4203 }
4204 SkipDartType(); // read recordType.
4205
4206 instructions += B->AllocateSmallRecord(position, shape);
4207
4208 return instructions;
4209 }
4210
4211 instructions += B->AllocateRecord(position, shape);
4212 LocalVariable* record = MakeTemporary();
4213
4214 // List of positional.
4215 intptr_t pos = 0;
4216 for (intptr_t i = 0; i < positional_count; ++i, ++pos) {
4217 instructions += LoadLocal(record);
4218 instructions += BuildExpression(); // read ith expression.
4219 instructions += B->StoreNativeField(
4220 Slot::GetRecordFieldSlot(thread(),
4223 }
4224
4225 // List of named.
4226 ReadListLength(); // read list length.
4227 for (intptr_t i = 0; i < named_count; ++i, ++pos) {
4228 SkipStringReference(); // read ith name.
4229 instructions += LoadLocal(record);
4230 instructions += BuildExpression(); // read ith expression.
4231 instructions += B->StoreNativeField(
4232 Slot::GetRecordFieldSlot(thread(),
4235 }
4236
4237 SkipDartType(); // read recordType.
4238
4239 return instructions;
4240}
4241
4242Fragment StreamingFlowGraphBuilder::BuildRecordFieldGet(TokenPosition* p,
4243 bool is_named) {
4244 const TokenPosition position = ReadPosition(); // read position.
4245 if (p != nullptr) *p = position;
4246
4247 Fragment instructions = BuildExpression(); // read receiver.
4248 const RecordType& record_type =
4249 RecordType::Cast(T.BuildType()); // read recordType.
4250
4251 intptr_t field_index = -1;
4252 const Array& field_names =
4253 Array::Handle(Z, record_type.GetFieldNames(H.thread()));
4254 const intptr_t num_positional_fields =
4255 record_type.NumFields() - field_names.Length();
4256 if (is_named) {
4257 const String& field_name = H.DartSymbolObfuscate(ReadStringReference());
4258 for (intptr_t i = 0, n = field_names.Length(); i < n; ++i) {
4259 if (field_names.At(i) == field_name.ptr()) {
4260 field_index = i;
4261 break;
4262 }
4263 }
4264 ASSERT(field_index >= 0 && field_index < field_names.Length());
4265 field_index += num_positional_fields;
4266 } else {
4267 field_index = ReadUInt();
4268 ASSERT(field_index < num_positional_fields);
4269 }
4270
4271 instructions += B->LoadNativeField(Slot::GetRecordFieldSlot(
4272 thread(), compiler::target::Record::field_offset(field_index)));
4273 return instructions;
4274}
4275
4276Fragment StreamingFlowGraphBuilder::BuildFunctionExpression() {
4277 const intptr_t offset = ReaderOffset() - 1; // Include the tag.
4278 ReadPosition(); // read position.
4279 return BuildFunctionNode(offset);
4280}
4281
4282Fragment StreamingFlowGraphBuilder::BuildLet(TokenPosition* p) {
4283 const TokenPosition position = ReadPosition(); // read position.
4284 if (p != nullptr) *p = position;
4285 Fragment instructions = BuildVariableDeclaration(nullptr); // read variable.
4286 instructions += BuildExpression(); // read body.
4287 return instructions;
4288}
4289
4290Fragment StreamingFlowGraphBuilder::BuildBlockExpression() {
4291 block_expression_depth_inc();
4292 const intptr_t offset = ReaderOffset() - 1; // Include the tag.
4293
4294 Fragment instructions;
4295
4296 instructions += EnterScope(offset);
4297
4298 ReadPosition(); // ignore file offset.
4299 const intptr_t list_length = ReadListLength(); // read number of statements.
4300 for (intptr_t i = 0; i < list_length; ++i) {
4301 instructions += BuildStatement(); // read ith statement.
4302 }
4303 instructions += BuildExpression(); // read expression (inside scope).
4304 instructions += ExitScope(offset);
4305
4306 block_expression_depth_dec();
4307 return instructions;
4308}
4309
4310Fragment StreamingFlowGraphBuilder::BuildBigIntLiteral(
4311 TokenPosition* position) {
4312 ReadPosition(); // ignore file offset.
4313 if (position != nullptr) *position = TokenPosition::kNoSource;
4314
4315 const String& value =
4316 H.DartString(ReadStringReference()); // read index into string table.
4317 const Integer& integer = Integer::ZoneHandle(Z, Integer::NewCanonical(value));
4318 if (integer.IsNull()) {
4319 const auto& script = Script::Handle(Z, Script());
4320 H.ReportError(script, TokenPosition::kNoSource,
4321 "Integer literal %s is out of range", value.ToCString());
4322 UNREACHABLE();
4323 }
4324 return Constant(integer);
4325}
4326
4327Fragment StreamingFlowGraphBuilder::BuildStringLiteral(
4328 TokenPosition* position) {
4329 ReadPosition(); // ignore file offset.
4330 if (position != nullptr) *position = TokenPosition::kNoSource;
4331
4332 return Constant(H.DartSymbolPlain(
4333 ReadStringReference())); // read index into string table.
4334}
4335
4336Fragment StreamingFlowGraphBuilder::BuildIntLiteral(uint8_t payload,
4337 TokenPosition* position) {
4338 ReadPosition(); // ignore file offset.
4339 if (position != nullptr) *position = TokenPosition::kNoSource;
4340
4341 int64_t value = static_cast<int32_t>(payload) - SpecializedIntLiteralBias;
4342 return IntConstant(value);
4343}
4344
4345Fragment StreamingFlowGraphBuilder::BuildIntLiteral(bool is_negative,
4346 TokenPosition* position) {
4347 ReadPosition(); // ignore file offset.
4348 if (position != nullptr) *position = TokenPosition::kNoSource;
4349
4350 int64_t value = is_negative ? -static_cast<int64_t>(ReadUInt())
4351 : ReadUInt(); // read value.
4352 return IntConstant(value);
4353}
4354
4355Fragment StreamingFlowGraphBuilder::BuildDoubleLiteral(
4356 TokenPosition* position) {
4357 ReadPosition(); // ignore file offset.
4358 if (position != nullptr) *position = TokenPosition::kNoSource;
4359
4360 Double& constant = Double::ZoneHandle(
4361 Z, Double::NewCanonical(ReadDouble())); // read double.
4362 return Constant(constant);
4363}
4364
4365Fragment StreamingFlowGraphBuilder::BuildBoolLiteral(bool value,
4366 TokenPosition* position) {
4367 ReadPosition(); // ignore file offset.
4368 if (position != nullptr) *position = TokenPosition::kNoSource;
4369
4370 return Constant(Bool::Get(value));
4371}
4372
4373Fragment StreamingFlowGraphBuilder::BuildNullLiteral(TokenPosition* position) {
4374 ReadPosition(); // ignore file offset.
4375 if (position != nullptr) *position = TokenPosition::kNoSource;
4376
4377 return Constant(Instance::ZoneHandle(Z, Instance::null()));
4378}
4379
4380Fragment StreamingFlowGraphBuilder::BuildFutureNullValue(
4381 TokenPosition* position) {
4382 if (position != nullptr) *position = TokenPosition::kNoSource;
4383 const Class& future = Class::Handle(Z, IG->object_store()->future_class());
4384 ASSERT(!future.IsNull());
4385 const auto& error = future.EnsureIsFinalized(thread());
4386 ASSERT(error == Error::null());
4387 Function& constructor = Function::ZoneHandle(
4388 Z, Resolver::ResolveFunction(Z, future, Symbols::FutureValue()));
4389 ASSERT(!constructor.IsNull());
4390
4391 Fragment instructions;
4392 instructions += BuildNullLiteral(position);
4393 instructions += StaticCall(TokenPosition::kNoSource, constructor,
4394 /* argument_count = */ 1, ICData::kStatic);
4395 return instructions;
4396}
4397
4398Fragment StreamingFlowGraphBuilder::BuildConstantExpression(
4399 TokenPosition* position,
4400 Tag tag) {
4401 TokenPosition p = TokenPosition::kNoSource;
4402 if (tag == kConstantExpression) {
4403 p = ReadPosition();
4404 SkipDartType();
4405 } else if (tag == kFileUriConstantExpression) {
4406 // TODO(alexmarkov): Use file offset together with file uri.
4407 ReadPosition();
4408 ReadUInt();
4409 SkipDartType();
4410 }
4411 if (position != nullptr) *position = p;
4412 const intptr_t constant_index = ReadUInt();
4413 Fragment result = Constant(
4414 Object::ZoneHandle(Z, constant_reader_.ReadConstant(constant_index)));
4415 return result;
4416}
4417
4418Fragment StreamingFlowGraphBuilder::BuildPartialTearoffInstantiation(
4419 TokenPosition* p) {
4420 const TokenPosition position = ReadPosition(); // read position.
4421 if (p != nullptr) *p = position;
4422
4423 // Create a copy of the closure.
4424
4425 Fragment instructions = BuildExpression();
4426 LocalVariable* original_closure = MakeTemporary();
4427
4428 // Load the target function and context and allocate the closure.
4429 instructions += LoadLocal(original_closure);
4430 instructions +=
4431 flow_graph_builder_->LoadNativeField(Slot::Closure_function());
4432 instructions += LoadLocal(original_closure);
4433 instructions += flow_graph_builder_->LoadNativeField(Slot::Closure_context());
4434 instructions += LoadLocal(original_closure);
4435 instructions += flow_graph_builder_->LoadNativeField(
4436 Slot::Closure_instantiator_type_arguments());
4437 instructions += flow_graph_builder_->AllocateClosure(
4438 position, /*has_instantiator_type_args=*/true, /*is_generic=*/false,
4439 /*is_tear_off=*/false);
4440 LocalVariable* new_closure = MakeTemporary();
4441
4442 intptr_t num_type_args = ReadListLength();
4443 const TypeArguments& type_args = T.BuildTypeArguments(num_type_args);
4444 instructions += TranslateInstantiatedTypeArguments(type_args);
4445 LocalVariable* type_args_vec = MakeTemporary("type_args");
4446
4447 // Check the bounds.
4448 //
4449 // TODO(sjindel): We should be able to skip this check in many cases, e.g.
4450 // when the closure is coming from a tearoff of a top-level method or from a
4451 // local closure.
4452 instructions += LoadLocal(original_closure);
4453 instructions += LoadLocal(type_args_vec);
4454 const Library& dart_internal = Library::Handle(Z, Library::InternalLibrary());
4455 const Function& bounds_check_function = Function::ZoneHandle(
4456 Z, dart_internal.LookupFunctionAllowPrivate(
4457 Symbols::BoundsCheckForPartialInstantiation()));
4458 ASSERT(!bounds_check_function.IsNull());
4459 instructions += StaticCall(TokenPosition::kNoSource, bounds_check_function, 2,
4460 ICData::kStatic);
4461 instructions += Drop();
4462
4463 instructions += LoadLocal(new_closure);
4464 instructions += LoadLocal(type_args_vec);
4465 instructions += flow_graph_builder_->StoreNativeField(
4466 Slot::Closure_delayed_type_arguments(),
4468 instructions += DropTemporary(&type_args_vec);
4469
4470 // Copy over the function type arguments.
4471 instructions += LoadLocal(new_closure);
4472 instructions += LoadLocal(original_closure);
4473 instructions += flow_graph_builder_->LoadNativeField(
4474 Slot::Closure_function_type_arguments());
4475 instructions += flow_graph_builder_->StoreNativeField(
4476 Slot::Closure_function_type_arguments(),
4478
4479 instructions += DropTempsPreserveTop(1); // Drop old closure.
4480
4481 return instructions;
4482}
4483
4484Fragment StreamingFlowGraphBuilder::BuildLibraryPrefixAction(
4485 TokenPosition* position,
4486 const String& selector) {
4487 const TokenPosition pos = ReadPosition(); // read position.
4488 if (position != nullptr) *position = pos;
4489
4490 const intptr_t dependency_index = ReadUInt();
4491 const Library& current_library = Library::Handle(
4492 Z, Class::Handle(Z, parsed_function()->function().Owner()).library());
4493 const Array& dependencies = Array::Handle(Z, current_library.dependencies());
4494 const LibraryPrefix& prefix =
4495 LibraryPrefix::CheckedZoneHandle(Z, dependencies.At(dependency_index));
4496 const Function& function =
4498 .LookupFunctionAllowPrivate(selector));
4499 ASSERT(!function.IsNull());
4500 Fragment instructions;
4501 instructions += Constant(prefix);
4502 instructions += StaticCall(pos, function, 1, ICData::kStatic);
4503 return instructions;
4504}
4505
4506Fragment StreamingFlowGraphBuilder::BuildAwaitExpression(
4507 TokenPosition* position) {
4508 ASSERT(parsed_function()->function().IsAsyncFunction() ||
4509 parsed_function()->function().IsAsyncGenerator());
4510 Fragment instructions;
4511
4512 const TokenPosition pos = ReadPosition(); // read file offset.
4513 if (position != nullptr) *position = pos;
4514
4515 instructions += BuildExpression(); // read operand.
4516
4518 if (ReadTag() == kSomething) {
4519 const AbstractType& type = T.BuildType(); // read runtime check type.
4520 if (!type.IsType() ||
4521 !Class::Handle(Z, type.type_class()).IsFutureClass()) {
4522 FATAL("Unexpected type for runtime check in await: %s", type.ToCString());
4523 }
4524 ASSERT(type.IsFinalized());
4525 const auto& type_args =
4526 TypeArguments::ZoneHandle(Z, Type::Cast(type).arguments());
4527 if (!type_args.IsNull()) {
4528 const auto& type_arg = AbstractType::Handle(Z, type_args.TypeAt(0));
4529 if (!type_arg.IsTopTypeForSubtyping()) {
4530 instructions += TranslateInstantiatedTypeArguments(type_args);
4532 }
4533 }
4534 }
4535
4536 if (NeedsDebugStepCheck(parsed_function()->function(), pos)) {
4537 instructions += DebugStepCheck(pos);
4538 }
4539 instructions += B->Suspend(pos, stub_id);
4540 return instructions;
4541}
4542
4543Fragment StreamingFlowGraphBuilder::BuildFileUriExpression(
4544 TokenPosition* position) {
4545 ReadUInt(); // read uri
4546
4547 const TokenPosition pos = ReadPosition(); // read position.
4548 if (position != nullptr) *position = pos;
4549
4550 return BuildExpression(position); // read expression.
4551}
4552
4553Fragment StreamingFlowGraphBuilder::BuildExpressionStatement(
4554 TokenPosition* position) {
4555 Fragment instructions = BuildExpression(position); // read expression.
4556 instructions += Drop();
4557 return instructions;
4558}
4559
4560Fragment StreamingFlowGraphBuilder::BuildBlock(TokenPosition* position) {
4561 intptr_t offset = ReaderOffset() - 1; // Include the tag.
4562
4563 Fragment instructions;
4564
4565 instructions += EnterScope(offset);
4566 const TokenPosition pos = ReadPosition(); // read file offset.
4567 if (position != nullptr) *position = pos;
4568
4569 ReadPosition(); // read file end offset.
4570
4571 intptr_t list_length = ReadListLength(); // read number of statements.
4572 for (intptr_t i = 0; i < list_length; ++i) {
4573 if (instructions.is_open()) {
4574 instructions += BuildStatement(); // read ith statement.
4575 } else {
4576 SkipStatement(); // read ith statement.
4577 }
4578 }
4579 instructions += ExitScope(offset);
4580
4581 return instructions;
4582}
4583
4584Fragment StreamingFlowGraphBuilder::BuildEmptyStatement() {
4585 return Fragment();
4586}
4587
4588Fragment StreamingFlowGraphBuilder::BuildAssertBlock(TokenPosition* position) {
4589 if (!IG->asserts()) {
4591 return Fragment();
4592 }
4593
4594 intptr_t offset = ReaderOffset() - 1; // Include the tag.
4595
4596 Fragment instructions;
4597
4598 instructions += EnterScope(offset);
4599 intptr_t list_length = ReadListLength(); // read number of statements.
4600 for (intptr_t i = 0; i < list_length; ++i) {
4601 if (instructions.is_open()) {
4602 // read ith statement.
4603 instructions += BuildStatement(i == 0 ? position : nullptr);
4604 } else {
4605 SkipStatement(); // read ith statement.
4606 }
4607 }
4608 instructions += ExitScope(offset);
4609
4610 return instructions;
4611}
4612
4613Fragment StreamingFlowGraphBuilder::BuildAssertStatement(
4614 TokenPosition* position) {
4615 if (!IG->asserts()) {
4616 SetOffset(ReaderOffset() - 1); // Include the tag.
4617 SkipStatement(); // read this statement.
4618 return Fragment();
4619 }
4620
4621 TargetEntryInstr* then;
4622 TargetEntryInstr* otherwise;
4623
4624 Fragment instructions;
4625 // Asserts can be of the following two kinds:
4626 //
4627 // * `assert(expr)`
4628 // * `assert(() { ... })`
4629 //
4630 // The call to `_AssertionError._evaluateAssertion()` will take care of both
4631 // and returns a boolean.
4632 instructions += BuildExpression(position); // read condition.
4633
4634 const TokenPosition condition_start_offset =
4635 ReadPosition(); // read condition start offset.
4636 const TokenPosition condition_end_offset =
4637 ReadPosition(); // read condition end offset.
4638
4639 instructions += EvaluateAssertion();
4640 instructions += RecordCoverage(condition_start_offset);
4641 instructions += CheckBoolean(condition_start_offset);
4642 instructions += Constant(Bool::True());
4643 instructions += BranchIfEqual(&then, &otherwise);
4644
4645 const Class& klass =
4646 Class::ZoneHandle(Z, Library::LookupCoreClass(Symbols::AssertionError()));
4647 ASSERT(!klass.IsNull());
4648
4649 // Build equivalent of `throw _AssertionError._throwNew(start, end, message)`
4650 // expression. We build throw (even through _throwNew already throws) because
4651 // call is not a valid last instruction for the block. Blocks can only
4652 // terminate with explicit control flow instructions (Branch, Goto, Return
4653 // or Throw).
4654 Fragment otherwise_fragment(otherwise);
4655 if (CompilerState::Current().is_aot()) {
4656 // When in AOT, figure out start line, end line, line fragment needed for
4657 // the message now, because it won't be available at runtime.
4658 const Function& target = Function::ZoneHandle(
4659 Z, klass.LookupStaticFunctionAllowPrivate(Symbols::ThrowNewSource()));
4660 ASSERT(!target.IsNull());
4661
4662 auto& script = Script::ZoneHandle(Z, Script());
4663
4664 auto& condition_text = String::ZoneHandle(Z);
4665 intptr_t from_line = -1, from_column = -1;
4666 if (script.GetTokenLocation(condition_start_offset, &from_line,
4667 &from_column)) {
4668 // Extract the assertion condition text (if source is available).
4669 intptr_t to_line, to_column;
4670 script.GetTokenLocation(condition_end_offset, &to_line, &to_column);
4671 condition_text =
4672 script.GetSnippet(from_line, from_column, to_line, to_column);
4673 condition_text = Symbols::New(thread(), condition_text);
4674 } else {
4675 condition_text = Symbols::OptimizedOut().ptr();
4676 }
4677
4678 otherwise_fragment += Constant(condition_text);
4679 otherwise_fragment += Constant(String::ZoneHandle(Z, script.url()));
4680 otherwise_fragment += IntConstant(from_line); // line
4681 otherwise_fragment += IntConstant(from_column); // pos
4682 Tag tag = ReadTag(); // read (first part of) message.
4683 if (tag == kSomething) {
4684 otherwise_fragment += BuildExpression(); // read (rest of) message.
4685 } else {
4686 otherwise_fragment += Constant(Instance::ZoneHandle(Z)); // null.
4687 }
4688 otherwise_fragment +=
4689 StaticCall(condition_start_offset, target, 5, ICData::kStatic);
4690 } else {
4691 const Function& target = Function::ZoneHandle(
4692 Z, klass.LookupStaticFunctionAllowPrivate(Symbols::ThrowNew()));
4693 ASSERT(!target.IsNull());
4694
4695 otherwise_fragment += IntConstant(condition_start_offset.Pos());
4696 otherwise_fragment += IntConstant(condition_end_offset.Pos());
4697 Tag tag = ReadTag(); // read (first part of) message.
4698 if (tag == kSomething) {
4699 otherwise_fragment += BuildExpression(); // read (rest of) message.
4700 } else {
4701 otherwise_fragment += Constant(Instance::ZoneHandle(Z)); // null.
4702 }
4703
4704 // Note: condition_start_offset points to the first token after the opening
4705 // paren, not the beginning of 'assert'.
4706 otherwise_fragment +=
4707 StaticCall(condition_start_offset, target, 3, ICData::kStatic);
4708 }
4709 otherwise_fragment += ThrowException(TokenPosition::kNoSource);
4710 otherwise_fragment += Drop();
4711
4712 return Fragment(instructions.entry, then);
4713}
4714
4715Fragment StreamingFlowGraphBuilder::BuildLabeledStatement(
4716 TokenPosition* position) {
4717 const TokenPosition pos = ReadPosition(); // read position.
4718 if (position != nullptr) *position = pos;
4719
4720 // There can be several cases:
4721 //
4722 // * the body contains a break
4723 // * the body doesn't contain a break
4724 //
4725 // * translating the body results in a closed fragment
4726 // * translating the body results in a open fragment
4727 //
4728 // => We will only know which case we are in after the body has been
4729 // traversed.
4730
4731 BreakableBlock block(flow_graph_builder_);
4732 Fragment instructions = BuildStatement(position); // read body.
4733 if (block.HadJumper()) {
4734 if (instructions.is_open()) {
4735 instructions += Goto(block.destination());
4736 }
4737 return Fragment(instructions.entry, block.destination());
4738 } else {
4739 return instructions;
4740 }
4741}
4742
4743Fragment StreamingFlowGraphBuilder::BuildBreakStatement(
4744 TokenPosition* position) {
4745 const TokenPosition pos = ReadPosition(); // read position.
4746 if (position != nullptr) *position = pos;
4747
4748 intptr_t target_index = ReadUInt(); // read target index.
4749
4750 TryFinallyBlock* outer_finally = nullptr;
4751 intptr_t target_context_depth = -1;
4752 JoinEntryInstr* destination = breakable_block()->BreakDestination(
4753 target_index, &outer_finally, &target_context_depth);
4754
4755 Fragment instructions;
4756 // Break statement should pause before manipulation of context, which
4757 // will possibly cause debugger having incorrect context object.
4758 if (NeedsDebugStepCheck(parsed_function()->function(), pos)) {
4759 instructions += DebugStepCheck(pos);
4760 }
4761 instructions +=
4762 TranslateFinallyFinalizers(outer_finally, target_context_depth);
4763 if (instructions.is_open()) {
4764 instructions += Goto(destination);
4765 }
4766 return instructions;
4767}
4768
4769Fragment StreamingFlowGraphBuilder::BuildWhileStatement(
4770 TokenPosition* position) {
4771 loop_depth_inc();
4772 const TokenPosition pos = ReadPosition(); // read position.
4773 if (position != nullptr) *position = pos;
4774
4775 TestFragment condition = TranslateConditionForControl(); // read condition.
4776 const Fragment body = BuildStatementWithBranchCoverage(); // read body
4777
4778 Fragment body_entry(condition.CreateTrueSuccessor(flow_graph_builder_));
4779 body_entry += body;
4780
4781 Instruction* entry;
4782 if (body_entry.is_open()) {
4783 JoinEntryInstr* join = BuildJoinEntry();
4784 body_entry += Goto(join);
4785
4786 Fragment loop(join);
4787 loop += CheckStackOverflow(pos); // may have non-empty stack
4788 loop.current->LinkTo(condition.entry);
4789
4790 entry = Goto(join).entry;
4791 } else {
4792 entry = condition.entry;
4793 }
4794
4795 loop_depth_dec();
4796 return Fragment(entry, condition.CreateFalseSuccessor(flow_graph_builder_));
4797}
4798
4799Fragment StreamingFlowGraphBuilder::BuildDoStatement(TokenPosition* position) {
4800 loop_depth_inc();
4801 const TokenPosition pos = ReadPosition(); // read position.
4802 if (position != nullptr) *position = pos;
4803
4804 Fragment body = BuildStatementWithBranchCoverage(); // read body.
4805
4806 if (body.is_closed()) {
4807 SkipExpression(); // read condition.
4808 loop_depth_dec();
4809 return body;
4810 }
4811
4812 TestFragment condition = TranslateConditionForControl();
4813
4814 JoinEntryInstr* join = BuildJoinEntry();
4815 Fragment loop(join);
4816 loop += CheckStackOverflow(pos); // may have non-empty stack
4817 loop += body;
4818 loop <<= condition.entry;
4819
4820 condition.IfTrueGoto(flow_graph_builder_, join);
4821
4822 loop_depth_dec();
4823 return Fragment(
4824 new (Z) GotoInstr(join, CompilerState::Current().GetNextDeoptId()),
4825 condition.CreateFalseSuccessor(flow_graph_builder_));
4826}
4827
4828Fragment StreamingFlowGraphBuilder::BuildForStatement(TokenPosition* position) {
4829 intptr_t offset = ReaderOffset() - 1; // Include the tag.
4830
4831 const TokenPosition pos = ReadPosition(); // read position.
4832 if (position != nullptr) *position = pos;
4833
4834 Fragment declarations;
4835
4836 loop_depth_inc();
4837
4838 const LocalScope* context_scope = nullptr;
4839 declarations += EnterScope(offset, &context_scope);
4840
4841 intptr_t list_length = ReadListLength(); // read number of variables.
4842 for (intptr_t i = 0; i < list_length; ++i) {
4843 declarations += BuildVariableDeclaration(nullptr); // read ith variable.
4844 }
4845
4846 Tag tag = ReadTag(); // Read first part of condition.
4847 TestFragment condition;
4848 BlockEntryInstr* body_entry;
4849 BlockEntryInstr* loop_exit;
4850 if (tag != kNothing) {
4851 condition = TranslateConditionForControl();
4852 body_entry = condition.CreateTrueSuccessor(flow_graph_builder_);
4853 loop_exit = condition.CreateFalseSuccessor(flow_graph_builder_);
4854 } else {
4855 body_entry = BuildJoinEntry();
4856 loop_exit = BuildJoinEntry();
4857 }
4858
4859 Fragment updates;
4860 list_length = ReadListLength(); // read number of updates.
4861 for (intptr_t i = 0; i < list_length; ++i) {
4862 updates += BuildExpression(); // read ith update.
4863 updates += Drop();
4864 }
4865
4866 Fragment body(body_entry);
4867 body += BuildStatementWithBranchCoverage(); // read body.
4868
4869 if (body.is_open()) {
4870 // We allocated a fresh context before the loop which contains captured
4871 // [ForStatement] variables. Before jumping back to the loop entry we clone
4872 // the context object (at same depth) which ensures the next iteration of
4873 // the body gets a fresh set of [ForStatement] variables (with the old
4874 // (possibly updated) values).
4875 if (context_scope->num_context_variables() > 0) {
4876 body += CloneContext(context_scope->context_slots());
4877 }
4878
4879 body += updates;
4880 JoinEntryInstr* join = BuildJoinEntry();
4881 declarations += Goto(join);
4882 body += Goto(join);
4883
4884 Fragment loop(join);
4885 loop += CheckStackOverflow(pos); // may have non-empty stack
4886 if (condition.entry != nullptr) {
4887 loop <<= condition.entry;
4888 } else {
4889 loop += Goto(body_entry->AsJoinEntry());
4890 }
4891 } else {
4892 if (condition.entry != nullptr) {
4893 declarations <<= condition.entry;
4894 } else {
4895 declarations += Goto(body_entry->AsJoinEntry());
4896 }
4897 }
4898
4899 Fragment loop(declarations.entry, loop_exit);
4900
4901 loop += ExitScope(offset);
4902
4903 loop_depth_dec();
4904
4905 return loop;
4906}
4907
4908Fragment StreamingFlowGraphBuilder::BuildSwitchStatement(
4909 TokenPosition* position) {
4910 const TokenPosition pos = ReadPosition(); // read position.
4911 if (position != nullptr) *position = pos;
4912 const bool is_exhaustive = ReadBool(); // read exhaustive flag.
4913
4914 // We need the number of cases. So start by getting that, then go back.
4915 const intptr_t offset = ReaderOffset();
4916 SkipExpression(); // temporarily skip condition
4917 SkipOptionalDartType(); // temporarily skip expression type
4918 intptr_t case_count = ReadListLength(); // read number of cases.
4920
4921 SwitchBlock block(flow_graph_builder_, case_count);
4922
4923 Fragment instructions = BuildExpression(); // read condition.
4924 const AbstractType* expression_type = &Object::dynamic_type();
4925 if (ReadTag() == kSomething) {
4926 expression_type = &T.BuildType(); // read expression type.
4927 }
4928 instructions +=
4929 StoreLocal(TokenPosition::kNoSource, scopes()->switch_variable);
4930 instructions += Drop();
4931
4932 case_count = ReadListLength(); // read number of cases.
4933
4934 SwitchHelper helper(Z, pos, is_exhaustive, *expression_type, &block,
4935 case_count);
4936
4937 // Build the case bodies and collect the expressions into the helper
4938 // for the next step.
4939 for (intptr_t i = 0; i < case_count; ++i) {
4940 helper.AddCaseBody(BuildSwitchCase(&helper, i));
4941 }
4942
4943 // Build the code to dispatch to the case bodies.
4944 switch (helper.SelectDispatchStrategy()) {
4946 UNREACHABLE();
4948 instructions += BuildLinearScanSwitch(&helper);
4949 break;
4951 instructions += BuildBinarySearchSwitch(&helper);
4952 break;
4954 instructions += BuildJumpTableSwitch(&helper);
4955 break;
4956 }
4957
4958 return instructions;
4959}
4960
4961Fragment StreamingFlowGraphBuilder::BuildSwitchCase(SwitchHelper* helper,
4962 intptr_t case_index) {
4963 // Generate case body and try to find out whether the body will be target
4964 // of a jump due to:
4965 // * `continue case_label`
4966 // * `case e1: case e2: body`
4967 //
4968 // Also collect switch expressions into helper.
4969
4970 ReadPosition(); // read file offset.
4971 const int expression_count = ReadListLength(); // read number of expressions.
4972 for (intptr_t j = 0; j < expression_count; ++j) {
4973 const TokenPosition pos = ReadPosition(); // read jth position.
4974 // read jth expression.
4975 const Instance& value =
4976 Instance::ZoneHandle(Z, constant_reader_.ReadConstantExpression());
4977 helper->AddExpression(case_index, pos, value);
4978 }
4979
4980 const bool is_default = ReadBool(); // read is_default.
4981 if (is_default) helper->set_default_case(case_index);
4982 Fragment body_fragment = BuildStatementWithBranchCoverage(); // read body.
4983
4984 if (body_fragment.entry == nullptr) {
4985 // Make a NOP in order to ensure linking works properly.
4986 body_fragment = NullConstant();
4987 body_fragment += Drop();
4988 }
4989
4990 // TODO(http://dartbug.com/50595): The CFE does not insert breaks for
4991 // unterminated cases which never reach the end of their control flow.
4992 // If the CFE inserts synthesized breaks, we can add an assert here instead.
4993 if (!is_default && body_fragment.is_open() &&
4994 (case_index < (helper->case_count() - 1))) {
4995 const auto& error =
4996 String::ZoneHandle(Z, Symbols::New(thread(), "Unreachable code."));
4997 body_fragment += Constant(error);
4998 body_fragment += ThrowException(TokenPosition::kNoSource);
4999 body_fragment += Drop();
5000 }
5001
5002 // If there is an implicit fall-through we have one [SwitchCase] and
5003 // multiple expressions, e.g.
5004 //
5005 // switch(expr) {
5006 // case a:
5007 // case b:
5008 // <stmt-body>
5009 // }
5010 //
5011 // This means that the <stmt-body> will have more than 1 incoming edge (one
5012 // from `a == expr` and one from `a != expr && b == expr`). The
5013 // `block.Destination()` records the additional jump.
5014 if (expression_count > 1) {
5015 helper->switch_block()->DestinationDirect(case_index);
5016 }
5017
5018 return body_fragment;
5019}
5020
5021Fragment StreamingFlowGraphBuilder::BuildLinearScanSwitch(
5022 SwitchHelper* helper) {
5023 // Build a switch using a sequence of equality tests.
5024 //
5025 // From a test:
5026 // * jump directly to a body, if there is no jumper.
5027 // * jump to a wrapper block which jumps to the body, if there is a jumper.
5028
5029 SwitchBlock* block = helper->switch_block();
5030 const intptr_t case_count = helper->case_count();
5031 const intptr_t default_case = helper->default_case();
5032 const GrowableArray<Fragment>& case_bodies = helper->case_bodies();
5033 Fragment current_instructions;
5034 intptr_t expression_index = 0;
5035
5036 for (intptr_t i = 0; i < case_count; ++i) {
5037 if (i == default_case) {
5038 ASSERT(i == (case_count - 1));
5039
5040 if (block->HadJumper(i)) {
5041 // There are several branches to the body, so we will make a goto to
5042 // the join block (and prepend a join instruction to the real body).
5043 JoinEntryInstr* join = block->DestinationDirect(i);
5044 current_instructions += Goto(join);
5045
5046 current_instructions = Fragment(current_instructions.entry, join);
5047 current_instructions += case_bodies[i];
5048 } else {
5049 current_instructions += case_bodies[i];
5050 }
5051 } else {
5052 JoinEntryInstr* body_join = nullptr;
5053 if (block->HadJumper(i)) {
5054 body_join = block->DestinationDirect(i);
5055 case_bodies[i] = Fragment(body_join) + case_bodies[i];
5056 }
5057
5058 const intptr_t expression_count = helper->case_expression_counts().At(i);
5059 for (intptr_t j = 0; j < expression_count; ++j) {
5060 TargetEntryInstr* then;
5061 TargetEntryInstr* otherwise;
5062
5063 const SwitchExpression& expression =
5064 helper->expressions().At(expression_index++);
5065 current_instructions += Constant(expression.value());
5066 current_instructions += LoadLocal(scopes()->switch_variable);
5067 current_instructions += InstanceCall(
5068 expression.position(), Symbols::EqualOperator(), Token::kEQ,
5069 /*argument_count=*/2,
5070 /*checked_argument_count=*/2);
5071 current_instructions += BranchIfTrue(&then, &otherwise, false);
5072
5073 Fragment then_fragment(then);
5074
5075 if (body_join != nullptr) {
5076 // There are several branches to the body, so we will make a goto to
5077 // the join block (the real body has already been prepended with a
5078 // join instruction).
5079 then_fragment += Goto(body_join);
5080 } else {
5081 // There is only a single branch to the body, so we will just append
5082 // the body fragment.
5083 then_fragment += case_bodies[i];
5084 }
5085
5086 current_instructions = Fragment(current_instructions.entry, otherwise);
5087 }
5088 }
5089 }
5090
5091 if (case_count > 0 && !helper->has_default()) {
5092 // There is no default, which means we have an open [current_instructions]
5093 // (which is a [TargetEntryInstruction] for the last "otherwise" branch).
5094 //
5095 // Furthermore the last [SwitchCase] can be open as well. If so, we need
5096 // to join these two.
5097 Fragment& last_body = case_bodies[case_count - 1];
5098 if (last_body.is_open()) {
5099 ASSERT(current_instructions.is_open());
5100 ASSERT(current_instructions.current->IsTargetEntry());
5101
5102 // Join the last "otherwise" branch and the last [SwitchCase] fragment.
5103 JoinEntryInstr* join = BuildJoinEntry();
5104 current_instructions += Goto(join);
5105 last_body += Goto(join);
5106
5107 current_instructions = Fragment(current_instructions.entry, join);
5108 }
5109 } else {
5110 // All non-default cases will be closed (i.e. break/continue/throw/return)
5111 // So it is fine to just let more statements after the switch append to the
5112 // default case.
5113 }
5114
5115 return current_instructions;
5116}
5117
5118Fragment StreamingFlowGraphBuilder::BuildOptimizedSwitchPrelude(
5119 SwitchHelper* helper,
5120 JoinEntryInstr* join) {
5121 const TokenPosition pos = helper->position();
5122 Fragment instructions;
5123
5124 if (helper->is_enum_switch()) {
5125 // For an enum switch, we need to load the enum index from the switch
5126 // variable.
5127
5128 instructions += LoadLocal(scopes()->switch_variable);
5129 const Field& enum_index_field =
5130 Field::ZoneHandle(Z, IG->object_store()->enum_index_field());
5131 instructions += B->LoadField(enum_index_field, /*calls_initializer=*/false);
5132 instructions += StoreLocal(pos, scopes()->switch_variable);
5133 instructions += Drop();
5134 }
5135
5136 return instructions;
5137}
5138
5139Fragment StreamingFlowGraphBuilder::BuildBinarySearchSwitch(
5140 SwitchHelper* helper) {
5141 // * We build a binary tree of conditional branches where each branch bisects
5142 // the remaining cases.
5143 // * At holes in the switch expression range we need to add additional
5144 // bound checks.
5145 // * At each leaf we add the body of the case or a goto, if the case has
5146 // jumpers.
5147 // * Leafs at the bounds of the switch expression range might need to
5148 // do a bound check.
5149
5150 SwitchBlock* block = helper->switch_block();
5151 const intptr_t case_count = helper->case_count();
5152 const intptr_t default_case = helper->default_case();
5153 const GrowableArray<Fragment>& case_bodies = helper->case_bodies();
5154 const intptr_t expression_count = helper->expressions().length();
5155 const GrowableArray<SwitchExpression*>& sorted_expressions =
5156 helper->sorted_expressions();
5157 TargetEntryInstr* then_entry;
5158 TargetEntryInstr* otherwise_entry;
5159
5160 // Entry to the default case or the exit of the switch, if there is no
5161 // default case.
5162 JoinEntryInstr* join;
5163 if (helper->has_default()) {
5164 join = block->DestinationDirect(default_case);
5165 } else {
5166 join = BuildJoinEntry();
5167 }
5168
5169 Fragment join_instructions(join);
5170 if (helper->has_default()) {
5171 join_instructions += case_bodies.At(default_case);
5172 }
5173
5174 Fragment current_instructions = BuildOptimizedSwitchPrelude(helper, join);
5175
5176 GrowableArray<SwitchRange> stack;
5177 stack.Add(SwitchRange::Branch(0, expression_count - 1, current_instructions));
5178
5179 while (!stack.is_empty()) {
5180 const SwitchRange range = stack.RemoveLast();
5181 Fragment branch_instructions = range.branch_instructions();
5182
5183 if (range.is_leaf()) {
5184 const intptr_t expression_index = range.min();
5185 const SwitchExpression& expression =
5186 *sorted_expressions.At(expression_index);
5187
5188 if (!range.is_bounds_checked() &&
5189 ((helper->RequiresLowerBoundCheck() && expression_index == 0) ||
5190 (helper->RequiresUpperBoundCheck() &&
5191 expression_index == expression_count - 1))) {
5192 // This leaf needs a bound check.
5193
5194 branch_instructions += LoadLocal(scopes()->switch_variable);
5195 branch_instructions += Constant(expression.integer());
5196 branch_instructions +=
5197 StrictCompare(expression.position(), Token::kEQ_STRICT,
5198 /*number_check=*/true);
5199 branch_instructions +=
5200 BranchIfTrue(&then_entry, &otherwise_entry, /*negate=*/false);
5201
5202 Fragment otherwise_instructions(otherwise_entry);
5203 otherwise_instructions += Goto(join);
5204
5205 stack.Add(SwitchRange::Leaf(expression_index, Fragment(then_entry),
5206 /*is_bounds_checked=*/true));
5207 } else {
5208 // We are at a leaf where we can add the body of the case or a goto to
5209 // [join].
5210
5211 const intptr_t case_index = expression.case_index();
5212
5213 if (case_index == default_case) {
5214 branch_instructions += Goto(join);
5215 } else {
5216 if (block->HadJumper(case_index)) {
5217 JoinEntryInstr* join = block->DestinationDirect(case_index);
5218 branch_instructions += Goto(join);
5219
5220 if (join->next() == nullptr) {
5221 // The first time we reach an expression that jumps to a case
5222 // body we emit the body.
5223 branch_instructions = Fragment(join);
5224 branch_instructions += case_bodies.At(case_index);
5225 }
5226 } else {
5227 branch_instructions += case_bodies.At(case_index);
5228 }
5229
5230 if (!helper->has_default() && case_index == case_count - 1) {
5231 if (branch_instructions.is_open()) {
5232 branch_instructions += Goto(join);
5233 }
5234 }
5235 }
5236
5237 ASSERT(branch_instructions.is_closed());
5238 }
5239 } else {
5240 // Add a conditional to bisect the range.
5241
5242 const intptr_t middle = range.min() + (range.max() - range.min()) / 2;
5243 const intptr_t next = middle + 1;
5244 const SwitchExpression& middle_expression =
5245 *sorted_expressions.At(middle);
5246 const SwitchExpression& next_expression = *sorted_expressions.At(next);
5247
5248 branch_instructions += LoadLocal(scopes()->switch_variable);
5249 branch_instructions += Constant(middle_expression.integer());
5250 branch_instructions +=
5251 B->IntRelationalOp(middle_expression.position(), Token::kLTE);
5252 branch_instructions +=
5253 BranchIfTrue(&then_entry, &otherwise_entry, /*negate=*/false);
5254
5255 Fragment lower_branch_instructions(then_entry);
5256 Fragment upper_branch_instructions(otherwise_entry);
5257
5258 if (next_expression.integer().AsInt64Value() >
5259 middle_expression.integer().AsInt64Value() + 1) {
5260 // The upper branch is not contiguous with the lower branch.
5261 // Before continuing in the upper branch we add a bound check.
5262
5263 upper_branch_instructions += LoadLocal(scopes()->switch_variable);
5264 upper_branch_instructions += Constant(next_expression.integer());
5265 upper_branch_instructions +=
5266 B->IntRelationalOp(next_expression.position(), Token::kGTE);
5267 upper_branch_instructions +=
5268 BranchIfTrue(&then_entry, &otherwise_entry, /*negate=*/false);
5269
5270 Fragment otherwise_instructions(otherwise_entry);
5271 otherwise_instructions += Goto(join);
5272
5273 upper_branch_instructions = Fragment(then_entry);
5274 }
5275
5276 stack.Add(
5277 SwitchRange::Branch(next, range.max(), upper_branch_instructions));
5278 stack.Add(
5279 SwitchRange::Branch(range.min(), middle, lower_branch_instructions));
5280 }
5281
5282 if (current_instructions.is_empty()) {
5283 current_instructions = branch_instructions;
5284 }
5285 }
5286
5287 return Fragment(current_instructions.entry, join_instructions.current);
5288}
5289
5290Fragment StreamingFlowGraphBuilder::BuildJumpTableSwitch(SwitchHelper* helper) {
5291 // * If input value is not integer or enum value, goto default case or
5292 // switch exit.
5293 // * If value is enum value, load its index.
5294 // * If input integer is outside of jump table range, goto default case
5295 // or switch exit.
5296 // * Jump to case with jump table.
5297 // * For each expression, add entry to jump to case.
5298 // * For each hole in the integer range, add entry to jump to default
5299 // cause or switch exit.
5300
5301 SwitchBlock* block = helper->switch_block();
5302 const TokenPosition pos = helper->position();
5303 const intptr_t case_count = helper->case_count();
5304 const intptr_t default_case = helper->default_case();
5305 const GrowableArray<Fragment>& case_bodies = helper->case_bodies();
5306 const Integer& expression_min = helper->expression_min();
5307 const Integer& expression_max = helper->expression_max();
5308 TargetEntryInstr* then_entry;
5309 TargetEntryInstr* otherwise_entry;
5310
5311 // Entry to the default case or the exit of the switch, if there is no
5312 // default case.
5313 JoinEntryInstr* join;
5314 if (helper->has_default()) {
5315 join = block->DestinationDirect(default_case);
5316 } else {
5317 join = BuildJoinEntry();
5318 }
5319
5320 Fragment join_instructions(join);
5321
5322 Fragment current_instructions = BuildOptimizedSwitchPrelude(helper, join);
5323
5324 if (helper->RequiresLowerBoundCheck()) {
5325 current_instructions += LoadLocal(scopes()->switch_variable);
5326 current_instructions += Constant(expression_min);
5327 current_instructions += B->IntRelationalOp(pos, Token::kGTE);
5328 current_instructions += BranchIfTrue(&then_entry, &otherwise_entry,
5329 /*negate=*/false);
5330 Fragment otherwise_instructions(otherwise_entry);
5331 otherwise_instructions += Goto(join);
5332
5333 current_instructions = Fragment(current_instructions.entry, then_entry);
5334 }
5335
5336 if (helper->RequiresUpperBoundCheck()) {
5337 current_instructions += LoadLocal(scopes()->switch_variable);
5338 current_instructions += Constant(expression_max);
5339 current_instructions += B->IntRelationalOp(pos, Token::kLTE);
5340 current_instructions += BranchIfTrue(&then_entry, &otherwise_entry,
5341 /*negate=*/false);
5342 Fragment otherwise_instructions(otherwise_entry);
5343 otherwise_instructions += Goto(join);
5344
5345 current_instructions = Fragment(current_instructions.entry, then_entry);
5346 }
5347
5348 current_instructions += LoadLocal(scopes()->switch_variable);
5349
5350 if (!expression_min.IsZero()) {
5351 // Adjust for the range of the jump table, which starts at 0.
5352 current_instructions += Constant(expression_min);
5353 current_instructions +=
5354 InstanceCall(pos, Symbols::Minus(), Token::kSUB, /*argument_count=*/2,
5355 /*checked_argument_count=*/2);
5356 }
5357
5358 const intptr_t table_size = helper->ExpressionRange();
5359 IndirectGotoInstr* indirect_goto = IndirectGoto(table_size);
5360 current_instructions <<= indirect_goto;
5361 current_instructions = current_instructions.closed();
5362
5363 GrowableArray<TargetEntryInstr*> table_entries(table_size);
5364 table_entries.FillWith(nullptr, 0, table_size);
5365
5366 // Generate the jump table entries for the switch cases.
5367 intptr_t expression_index = 0;
5368 for (intptr_t i = 0; i < case_count; ++i) {
5369 const int expression_count = helper->case_expression_counts().At(i);
5370
5371 // Generate jump table entries for each case expression.
5372 if (i != default_case) {
5373 for (intptr_t j = 0; j < expression_count; ++j) {
5374 const SwitchExpression& expression =
5375 helper->expressions().At(expression_index++);
5376 const intptr_t table_offset =
5377 expression.integer().AsInt64Value() - expression_min.AsInt64Value();
5378
5379 IndirectEntryInstr* indirect_entry =
5380 B->BuildIndirectEntry(table_offset, CurrentTryIndex());
5381 Fragment indirect_entry_instructions(indirect_entry);
5382 indirect_entry_instructions += Goto(block->DestinationDirect(i));
5383
5384 TargetEntryInstr* entry = B->BuildTargetEntry();
5385 Fragment entry_instructions(entry);
5386 entry_instructions += Goto(indirect_entry);
5387
5388 table_entries[table_offset] = entry;
5389 }
5390 }
5391
5392 // Connect the case body to its join entry.
5393 if (i == default_case) {
5394 join_instructions += case_bodies.At(i);
5395 } else {
5396 Fragment case_instructions(block->DestinationDirect(i));
5397 case_instructions += case_bodies.At(i);
5398
5399 if (i == case_count - 1) {
5400 // If the last case is not the default case and it is still open
5401 // close it by going to the exit of the switch.
5402 if (case_instructions.is_open()) {
5403 case_instructions += Goto(join);
5404 }
5405 }
5406
5407 ASSERT(case_instructions.is_closed());
5408 }
5409 }
5410
5411 // Generate the jump table entries for holes in the integer range.
5412 for (intptr_t i = 0; i < table_size; i++) {
5413 if (table_entries.At(i) == nullptr) {
5414 IndirectEntryInstr* indirect_entry =
5415 B->BuildIndirectEntry(i, CurrentTryIndex());
5416 Fragment indirect_entry_instructions(indirect_entry);
5417 indirect_entry_instructions += Goto(join);
5418
5419 TargetEntryInstr* entry = flow_graph_builder_->BuildTargetEntry();
5420 Fragment entry_instructions(entry);
5421 entry_instructions += Goto(indirect_entry);
5422
5423 table_entries[i] = entry;
5424 }
5425 }
5426
5427 // Add the jump table entries to the jump table.
5428 for (intptr_t i = 0; i < table_size; i++) {
5429 indirect_goto->AddSuccessor(table_entries.At(i));
5430 }
5431
5432 return Fragment(current_instructions.entry, join_instructions.current);
5433}
5434
5435Fragment StreamingFlowGraphBuilder::BuildContinueSwitchStatement(
5436 TokenPosition* position) {
5437 const TokenPosition pos = ReadPosition(); // read position.
5438 if (position != nullptr) *position = pos;
5439
5440 intptr_t target_index = ReadUInt(); // read target index.
5441
5442 TryFinallyBlock* outer_finally = nullptr;
5443 intptr_t target_context_depth = -1;
5444 JoinEntryInstr* entry = switch_block()->Destination(
5445 target_index, &outer_finally, &target_context_depth);
5446
5447 Fragment instructions;
5448 instructions +=
5449 TranslateFinallyFinalizers(outer_finally, target_context_depth);
5450 if (instructions.is_open()) {
5451 if (NeedsDebugStepCheck(parsed_function()->function(), pos)) {
5452 instructions += DebugStepCheck(pos);
5453 }
5454 instructions += Goto(entry);
5455 }
5456 return instructions;
5457}
5458
5459Fragment StreamingFlowGraphBuilder::BuildIfStatement(TokenPosition* position) {
5460 const TokenPosition pos = ReadPosition(); // read position.
5461 if (position != nullptr) *position = pos;
5462
5463 TestFragment condition = TranslateConditionForControl();
5464
5465 Fragment then_fragment(condition.CreateTrueSuccessor(flow_graph_builder_));
5466 then_fragment += BuildStatementWithBranchCoverage(); // read then.
5467
5468 Fragment otherwise_fragment(
5469 condition.CreateFalseSuccessor(flow_graph_builder_));
5470 otherwise_fragment += BuildStatementWithBranchCoverage(); // read otherwise.
5471
5472 if (then_fragment.is_open()) {
5473 if (otherwise_fragment.is_open()) {
5474 JoinEntryInstr* join = BuildJoinEntry();
5475 then_fragment += Goto(join);
5476 otherwise_fragment += Goto(join);
5477 return Fragment(condition.entry, join);
5478 } else {
5479 return Fragment(condition.entry, then_fragment.current);
5480 }
5481 } else if (otherwise_fragment.is_open()) {
5482 return Fragment(condition.entry, otherwise_fragment.current);
5483 } else {
5484 return Fragment(condition.entry, nullptr);
5485 }
5486}
5487
5488Fragment StreamingFlowGraphBuilder::BuildReturnStatement(
5489 TokenPosition* position) {
5490 const TokenPosition pos = ReadPosition(); // read position.
5491 if (position != nullptr) *position = pos;
5492
5493 Tag tag = ReadTag(); // read first part of expression.
5494
5495 bool inside_try_finally = try_finally_block() != nullptr;
5496
5497 Fragment instructions;
5498 if (parsed_function()->function().IsSyncGenerator()) {
5499 // Return false from sync* function to indicate the end of iteration.
5500 instructions += Constant(Bool::False());
5501 if (tag != kNothing) {
5502 ASSERT(PeekTag() == kNullLiteral);
5504 }
5505 } else {
5506 instructions +=
5507 (tag == kNothing ? NullConstant()
5508 : BuildExpression()); // read rest of expression.
5509 }
5510
5511 if (instructions.is_open()) {
5512 if (inside_try_finally) {
5513 LocalVariable* const finally_return_variable =
5514 scopes()->finally_return_variable;
5515 ASSERT(finally_return_variable != nullptr);
5516 const Function& function = parsed_function()->function();
5517 if (NeedsDebugStepCheck(function, pos)) {
5518 instructions += DebugStepCheck(pos);
5519 }
5520 instructions += StoreLocal(pos, finally_return_variable);
5521 instructions += Drop();
5522 const intptr_t target_context_depth =
5523 finally_return_variable->is_captured()
5524 ? finally_return_variable->owner()->context_level()
5525 : -1;
5526 instructions += TranslateFinallyFinalizers(nullptr, target_context_depth);
5527 if (instructions.is_open()) {
5528 const intptr_t saved_context_depth = B->context_depth_;
5529 if (finally_return_variable->is_captured()) {
5530 B->context_depth_ = target_context_depth;
5531 }
5532 instructions += LoadLocal(finally_return_variable);
5533 instructions += Return(TokenPosition::kNoSource);
5534 B->context_depth_ = saved_context_depth;
5535 }
5536 } else {
5537 instructions += Return(pos);
5538 }
5539 } else {
5540 Pop();
5541 }
5542
5543 return instructions;
5544}
5545
5546Fragment StreamingFlowGraphBuilder::BuildTryCatch(TokenPosition* position) {
5547 ASSERT(block_expression_depth() == 0); // no try-catch in block-expr
5548 InlineBailout("kernel::FlowgraphBuilder::VisitTryCatch");
5549
5550 const TokenPosition pos = ReadPosition(); // read position.
5551 if (position != nullptr) *position = pos;
5552
5553 intptr_t try_handler_index = AllocateTryIndex();
5554 Fragment try_body = TryCatch(try_handler_index);
5555 JoinEntryInstr* after_try = BuildJoinEntry();
5556
5557 // Fill in the body of the try.
5558 try_depth_inc();
5559 {
5560 TryCatchBlock block(flow_graph_builder_, try_handler_index);
5561 try_body += BuildStatementWithBranchCoverage(position); // read body.
5562 try_body += Goto(after_try);
5563 }
5564 try_depth_dec();
5565
5566 const int kNeedsStracktraceBit = 1 << 0;
5567 const int kIsSyntheticBit = 1 << 1;
5568
5569 uint8_t flags = ReadByte();
5570 bool needs_stacktrace =
5571 (flags & kNeedsStracktraceBit) == kNeedsStracktraceBit;
5572 bool is_synthetic = (flags & kIsSyntheticBit) == kIsSyntheticBit;
5573
5574 catch_depth_inc();
5575 intptr_t catch_count = ReadListLength(); // read number of catches.
5576 const Array& handler_types =
5577 Array::ZoneHandle(Z, Array::New(catch_count, Heap::kOld));
5578
5579 Fragment catch_body = CatchBlockEntry(handler_types, try_handler_index,
5580 needs_stacktrace, is_synthetic);
5581 // Fill in the body of the catch.
5582 for (intptr_t i = 0; i < catch_count; ++i) {
5583 intptr_t catch_offset = ReaderOffset(); // Catch has no tag.
5584 TokenPosition pos = ReadPosition(); // read position.
5585 const AbstractType& type_guard = T.BuildType(); // read guard.
5586 handler_types.SetAt(i, type_guard);
5587
5588 Fragment catch_handler_body = EnterScope(catch_offset);
5589
5590 Tag tag = ReadTag(); // read first part of exception.
5591 if (tag == kSomething) {
5592 catch_handler_body += LoadLocal(CurrentException());
5593 catch_handler_body +=
5594 StoreLocal(TokenPosition::kNoSource,
5595 LookupVariable(ReaderOffset() + data_program_offset_));
5596 catch_handler_body += Drop();
5597 SkipVariableDeclaration(); // read exception.
5598 }
5599
5600 tag = ReadTag(); // read first part of stack trace.
5601 if (tag == kSomething) {
5602 catch_handler_body += LoadLocal(CurrentStackTrace());
5603 catch_handler_body +=
5604 StoreLocal(TokenPosition::kNoSource,
5605 LookupVariable(ReaderOffset() + data_program_offset_));
5606 catch_handler_body += Drop();
5607 SkipVariableDeclaration(); // read stack trace.
5608 }
5609
5610 {
5611 CatchBlock block(flow_graph_builder_, CurrentException(),
5612 CurrentStackTrace(), try_handler_index);
5613
5614 catch_handler_body += BuildStatementWithBranchCoverage(); // read body.
5615
5616 // Note: ExitScope adjusts context_depth_ so even if catch_handler_body
5617 // is closed we still need to execute ExitScope for its side effect.
5618 catch_handler_body += ExitScope(catch_offset);
5619 if (catch_handler_body.is_open()) {
5620 catch_handler_body += Goto(after_try);
5621 }
5622 }
5623
5624 if (!type_guard.IsCatchAllType()) {
5625 catch_body += LoadLocal(CurrentException());
5626
5627 if (!type_guard.IsInstantiated(kCurrentClass)) {
5628 catch_body += LoadInstantiatorTypeArguments();
5629 } else {
5630 catch_body += NullConstant();
5631 }
5632
5633 if (!type_guard.IsInstantiated(kFunctions)) {
5634 catch_body += LoadFunctionTypeArguments();
5635 } else {
5636 catch_body += NullConstant();
5637 }
5638
5639 catch_body += Constant(type_guard);
5640
5641 catch_body +=
5642 InstanceCall(pos, Library::PrivateCoreLibName(Symbols::_instanceOf()),
5643 Token::kIS, 4);
5644
5645 TargetEntryInstr* catch_entry;
5646 TargetEntryInstr* next_catch_entry;
5647 catch_body += BranchIfTrue(&catch_entry, &next_catch_entry, false);
5648
5649 Fragment(catch_entry) + catch_handler_body;
5650 catch_body = Fragment(next_catch_entry);
5651 } else {
5652 catch_body += catch_handler_body;
5653 }
5654 }
5655
5656 // In case the last catch body was not handling the exception and branching to
5657 // after the try block, we will rethrow the exception (i.e. no default catch
5658 // handler).
5659 if (catch_body.is_open()) {
5660 catch_body += LoadLocal(CurrentException());
5661 catch_body += LoadLocal(CurrentStackTrace());
5662 catch_body += RethrowException(TokenPosition::kNoSource, try_handler_index);
5663 Drop();
5664 }
5665 catch_depth_dec();
5666
5667 return Fragment(try_body.entry, after_try);
5668}
5669
5670Fragment StreamingFlowGraphBuilder::BuildTryFinally(TokenPosition* position) {
5671 // Note on streaming:
5672 // We only stream this TryFinally if we can stream everything inside it,
5673 // so creating a "TryFinallyBlock" with a kernel binary offset instead of an
5674 // AST node isn't a problem.
5675
5676 InlineBailout("kernel::FlowgraphBuilder::VisitTryFinally");
5677
5678 const TokenPosition pos = ReadPosition(); // read position.
5679 if (position != nullptr) *position = pos;
5680
5681 // There are 5 different cases where we need to execute the finally block:
5682 //
5683 // a) 1/2/3th case: Special control flow going out of `node->body()`:
5684 //
5685 // * [BreakStatement] transfers control to a [LabeledStatement]
5686 // * [ContinueSwitchStatement] transfers control to a [SwitchCase]
5687 // * [ReturnStatement] returns a value
5688 //
5689 // => All three cases will automatically append all finally blocks
5690 // between the branching point and the destination (so we don't need to
5691 // do anything here).
5692 //
5693 // b) 4th case: Translating the body resulted in an open fragment (i.e. body
5694 // executes without any control flow out of it)
5695 //
5696 // => We are responsible for jumping out of the body to a new block (with
5697 // different try index) and execute the finalizer.
5698 //
5699 // c) 5th case: An exception occurred inside the body.
5700 //
5701 // => We are responsible for catching it, executing the finally block and
5702 // rethrowing the exception.
5703 intptr_t try_handler_index = AllocateTryIndex();
5704 Fragment try_body = TryCatch(try_handler_index);
5705 JoinEntryInstr* after_try = BuildJoinEntry();
5706
5707 intptr_t offset = ReaderOffset();
5708 SkipStatement(); // temporarily read body.
5709 intptr_t finalizer_offset = ReaderOffset();
5711
5712 // Fill in the body of the try.
5713 try_depth_inc();
5714 {
5715 TryFinallyBlock tfb(flow_graph_builder_, finalizer_offset);
5716 TryCatchBlock tcb(flow_graph_builder_, try_handler_index);
5717 try_body += BuildStatementWithBranchCoverage(position); // read body.
5718 }
5719 try_depth_dec();
5720
5721 if (try_body.is_open()) {
5722 // Please note: The try index will be on level out of this block,
5723 // thereby ensuring if there's an exception in the finally block we
5724 // won't run it twice.
5725 JoinEntryInstr* finally_entry = BuildJoinEntry();
5726
5727 try_body += Goto(finally_entry);
5728
5729 Fragment finally_body(finally_entry);
5730 finally_body += BuildStatementWithBranchCoverage(); // read finalizer.
5731 finally_body += Goto(after_try);
5732 }
5733
5734 // Fill in the body of the catch.
5735 catch_depth_inc();
5736
5737 const Array& handler_types = Array::ZoneHandle(Z, Array::New(1, Heap::kOld));
5738 handler_types.SetAt(0, Object::dynamic_type());
5739 // Note: rethrow will actually force mark the handler as needing a stacktrace.
5740 Fragment finally_body = CatchBlockEntry(handler_types, try_handler_index,
5741 /* needs_stacktrace = */ false,
5742 /* is_synthesized = */ true);
5743 SetOffset(finalizer_offset);
5744
5745 // Try/finally might occur in control flow collections with non-empty
5746 // expression stack (via desugaring of 'await for'). Note that catch-block
5747 // generated for finally always throws so there is no merge.
5748 // Save and reset expression stack around catch body in order to maintain
5749 // correct stack depth, as catch entry drops expression stack.
5750 Value* const saved_stack_top = stack();
5751 set_stack(nullptr);
5752
5753 finally_body += BuildStatementWithBranchCoverage(); // read finalizer
5754 if (finally_body.is_open()) {
5755 finally_body += LoadLocal(CurrentException());
5756 finally_body += LoadLocal(CurrentStackTrace());
5757 finally_body +=
5758 RethrowException(TokenPosition::kNoSource, try_handler_index);
5759 Drop();
5760 }
5761
5762 ASSERT(stack() == nullptr);
5763 set_stack(saved_stack_top);
5764 catch_depth_dec();
5765
5766 return Fragment(try_body.entry, after_try);
5767}
5768
5769Fragment StreamingFlowGraphBuilder::BuildYieldStatement(
5770 TokenPosition* position) {
5771 const TokenPosition pos = ReadPosition(); // read position.
5772 if (position != nullptr) *position = pos;
5773
5774 const uint8_t flags = ReadByte(); // read flags.
5775
5776 Fragment instructions;
5777 const bool is_yield_star = (flags & kYieldStatementFlagYieldStar) != 0;
5778
5779 // Load :suspend_state variable using low-level FP-relative load
5780 // in order to avoid confusing SSA construction (which cannot
5781 // track its value as it is modified implicitly by stubs).
5782 LocalVariable* suspend_state = parsed_function()->suspend_state_var();
5783 ASSERT(suspend_state != nullptr);
5784 instructions += IntConstant(0);
5785 instructions += B->LoadFpRelativeSlot(
5786 compiler::target::frame_layout.FrameSlotForVariable(suspend_state) *
5788 CompileType::Dynamic(), kTagged);
5789 instructions += LoadNativeField(Slot::SuspendState_function_data());
5790
5791 instructions += BuildExpression(); // read expression.
5792 if (NeedsDebugStepCheck(parsed_function()->function(), pos)) {
5793 instructions += DebugStepCheck(pos);
5794 }
5795
5796 if (parsed_function()->function().IsAsyncGenerator()) {
5797 // In the async* functions, generate the following code for yield <expr>:
5798 //
5799 // _AsyncStarStreamController controller = :suspend_state._functionData;
5800 // if (controller.add(<expr>)) {
5801 // return;
5802 // }
5803 // if (suspend()) {
5804 // return;
5805 // }
5806 //
5807 // Generate the following code for yield* <expr>:
5808 //
5809 // _AsyncStarStreamController controller = :suspend_state._functionData;
5810 // if (controller.addStream(<expr>)) {
5811 // return;
5812 // }
5813 // if (suspend()) {
5814 // return;
5815 // }
5816 //
5817
5818 auto& add_method = Function::ZoneHandle(Z);
5819 if (is_yield_star) {
5820 add_method =
5821 IG->object_store()->async_star_stream_controller_add_stream();
5822 } else {
5823 add_method = IG->object_store()->async_star_stream_controller_add();
5824 }
5825 instructions +=
5826 StaticCall(TokenPosition::kNoSource, add_method, 2, ICData::kNoRebind);
5827
5828 TargetEntryInstr *return1, *continue1;
5829 instructions += BranchIfTrue(&return1, &continue1, false);
5830 JoinEntryInstr* return_join = BuildJoinEntry();
5831 Fragment(return1) + Goto(return_join);
5832 instructions = Fragment(instructions.entry, continue1);
5833
5834 // Suspend and test value passed to the resumed async* body.
5835 instructions += NullConstant();
5836 instructions += B->Suspend(pos, SuspendInstr::StubId::kYieldAsyncStar);
5837
5838 TargetEntryInstr *return2, *continue2;
5839 instructions += BranchIfTrue(&return2, &continue2, false);
5840 Fragment(return2) + Goto(return_join);
5841 instructions = Fragment(instructions.entry, continue2);
5842
5843 Fragment do_return(return_join);
5844 do_return += TranslateFinallyFinalizers(nullptr, -1);
5845 do_return += NullConstant();
5846 do_return += Return(TokenPosition::kNoSource);
5847
5848 } else if (parsed_function()->function().IsSyncGenerator()) {
5849 // In the sync* functions, generate the following code for yield <expr>:
5850 //
5851 // _SyncStarIterator iterator = :suspend_state._functionData;
5852 // iterator._current = <expr>;
5853 // suspend();
5854 //
5855 // Generate the following code for yield* <expr>:
5856 //
5857 // _SyncStarIterator iterator = :suspend_state._functionData;
5858 // iterator._yieldStarIterable = <expr>;
5859 // suspend();
5860 //
5861 auto& field = Field::ZoneHandle(Z);
5862 if (is_yield_star) {
5863 field = IG->object_store()->sync_star_iterator_yield_star_iterable();
5864 } else {
5865 field = IG->object_store()->sync_star_iterator_current();
5866 }
5867 instructions += B->StoreFieldGuarded(field);
5868 instructions += B->Constant(Bool::True());
5869 instructions +=
5871 instructions += Drop();
5872 } else {
5873 UNREACHABLE();
5874 }
5875
5876 return instructions;
5877}
5878
5879Fragment StreamingFlowGraphBuilder::BuildVariableDeclaration(
5880 TokenPosition* position) {
5881 intptr_t kernel_position_no_tag = ReaderOffset() + data_program_offset_;
5882 LocalVariable* variable = LookupVariable(kernel_position_no_tag);
5883
5884 VariableDeclarationHelper helper(this);
5885 helper.ReadUntilExcluding(VariableDeclarationHelper::kType);
5886 T.BuildType(); // read type.
5887 bool has_initializer = (ReadTag() != kNothing);
5888
5889 Fragment instructions;
5890 if (variable->is_late()) {
5891 // TODO(liama): Treat the field as non-late if the initializer is trivial.
5892 if (has_initializer) {
5894 }
5895 instructions += Constant(Object::sentinel());
5896 } else if (!has_initializer) {
5897 instructions += NullConstant();
5898 } else {
5899 // Initializer
5900 instructions += BuildExpression(); // read (actual) initializer.
5901 }
5902
5903 // Use position of equal sign if it exists. If the equal sign does not exist
5904 // use the position of the identifier.
5905 const TokenPosition debug_position = helper.equals_position_.IsReal()
5906 ? helper.equals_position_
5907 : helper.position_;
5908 if (position != nullptr) *position = helper.position_;
5909 if (NeedsDebugStepCheck(stack(), debug_position) && !helper.IsHoisted()) {
5910 instructions = DebugStepCheck(debug_position) + instructions;
5911 }
5912 instructions += StoreLocal(helper.position_, variable);
5913 instructions += Drop();
5914 return instructions;
5915}
5916
5917Fragment StreamingFlowGraphBuilder::BuildFunctionDeclaration(
5918 TokenPosition* position) {
5919 const intptr_t offset = ReaderOffset() - 1; // Include the tag.
5920 const TokenPosition pos = ReadPosition();
5921 if (position != nullptr) *position = pos;
5922
5923 const intptr_t variable_offset = ReaderOffset() + data_program_offset_;
5925
5926 Fragment instructions = DebugStepCheck(pos);
5927 instructions += BuildFunctionNode(offset);
5928 instructions += StoreLocal(pos, LookupVariable(variable_offset));
5929 instructions += Drop();
5930 return instructions;
5931}
5932
5933Fragment StreamingFlowGraphBuilder::BuildFunctionNode(
5934 intptr_t func_decl_offset) {
5935 const intptr_t func_node_offset = ReaderOffset();
5936 const auto& member_function =
5937 Function::Handle(Z, parsed_function()->function().GetOutermostFunction());
5938 const Function& function = Function::ZoneHandle(
5940 thread(), func_decl_offset, member_function,
5941 parsed_function()->function(), closure_owner_));
5942
5943 if (function.context_scope() == ContextScope::null()) {
5944 SafepointWriteRwLocker ml(thread(),
5945 thread()->isolate_group()->program_lock());
5946 if (function.context_scope() == ContextScope::null()) {
5947 for (intptr_t i = 0; i < scopes()->function_scopes.length(); ++i) {
5948 if (scopes()->function_scopes[i].kernel_offset !=
5949 function.kernel_offset()) {
5950 continue;
5951 }
5952
5953 LocalScope* scope = scopes()->function_scopes[i].scope;
5954 const ContextScope& context_scope = ContextScope::Handle(
5955 Z, scope->PreserveOuterScope(function,
5956 flow_graph_builder_->context_depth_));
5957 function.set_context_scope(context_scope);
5958 }
5959 }
5960 }
5961
5962 ASSERT(function.kernel_offset() == func_node_offset);
5964
5965 Fragment instructions;
5966 instructions += Constant(function);
5967 if (scopes()->IsClosureWithEmptyContext(func_node_offset)) {
5968 instructions += NullConstant();
5969 } else {
5970 instructions += LoadLocal(parsed_function()->current_context_var());
5971 }
5972 // The function signature can have uninstantiated class type parameters.
5973 const bool has_instantiator_type_args =
5974 !function.HasInstantiatedSignature(kCurrentClass);
5975 if (has_instantiator_type_args) {
5976 instructions += LoadInstantiatorTypeArguments();
5977 }
5978 instructions += flow_graph_builder_->AllocateClosure(
5979 function.token_pos(), has_instantiator_type_args, function.IsGeneric(),
5980 /*is_tear_off=*/false);
5981 LocalVariable* closure = MakeTemporary();
5982
5983 // TODO(30455): We only need to save these if the closure uses any captured
5984 // type parameters.
5985 instructions += LoadLocal(closure);
5986 instructions += LoadFunctionTypeArguments();
5987 instructions += flow_graph_builder_->StoreNativeField(
5988 Slot::Closure_function_type_arguments(),
5990
5991 return instructions;
5992}
5993
5994Fragment StreamingFlowGraphBuilder::BuildNativeEffect() {
5995 const intptr_t argc = ReadUInt(); // Read argument count.
5996 ASSERT(argc == 1); // Native side effect to ignore.
5997 const intptr_t list_length = ReadListLength(); // Read types list length.
5998 ASSERT(list_length == 0);
5999
6000 const intptr_t positional_count =
6001 ReadListLength(); // Read positional argument count.
6002 ASSERT(positional_count == 1);
6003
6004 BuildExpression(); // Consume expression but don't save the fragment.
6005 Pop(); // Restore the stack.
6006
6007 const intptr_t named_args_len =
6008 ReadListLength(); // Skip empty named arguments.
6009 ASSERT(named_args_len == 0);
6010
6011 Fragment code;
6012 code += NullConstant(); // Return type is void.
6013 return code;
6014}
6015
6016Fragment StreamingFlowGraphBuilder::BuildReachabilityFence() {
6017 const intptr_t argc = ReadUInt(); // Read argument count.
6018 ASSERT(argc == 1); // LoadField, can be late.
6019 const intptr_t list_length = ReadListLength(); // Read types list length.
6020 ASSERT(list_length == 0);
6021
6022 const intptr_t positional_count = ReadListLength();
6023 ASSERT(positional_count == 1);
6024
6025 // The CFE transform only generates a subset of argument expressions:
6026 // either variable get or `this`. However, subsequent transforms can
6027 // generate different expressions, including: constant expressions.
6028 // So, build an arbitrary expression here instead.
6029 TokenPosition* position = nullptr;
6030 Fragment code = BuildExpression(position);
6031
6032 const intptr_t named_args_len = ReadListLength();
6033 ASSERT(named_args_len == 0);
6034
6035 code <<= new (Z) ReachabilityFenceInstr(Pop());
6036 code += NullConstant(); // Return type is void.
6037 return code;
6038}
6039
6040static void ReportIfNotNull(const char* error) {
6041 if (error != nullptr) {
6042 const auto& language_error = Error::Handle(
6043 LanguageError::New(String::Handle(String::New(error, Heap::kOld)),
6045 Report::LongJump(language_error);
6046 }
6047}
6048
6049Fragment StreamingFlowGraphBuilder::BuildLoadStoreAbiSpecificInt(
6050 bool is_store,
6051 bool at_index) {
6052 const intptr_t argument_count = ReadUInt(); // Read argument count.
6053 const intptr_t expected_argument_count = 2 // TypedDataBase, offset
6054 + (at_index ? 1 : 0) // index
6055 + (is_store ? 1 : 0); // value
6056 ASSERT_EQUAL(argument_count, expected_argument_count);
6057 const intptr_t list_length = ReadListLength();
6058 ASSERT_EQUAL(list_length, 1);
6059 // Read types.
6060 const TypeArguments& type_arguments = T.BuildTypeArguments(list_length);
6061 const AbstractType& type_argument =
6062 AbstractType::Handle(type_arguments.TypeAt(0));
6063
6064 // AbiSpecificTypes can have an incomplete mapping.
6065 const char* error = nullptr;
6066 const auto* native_type =
6069
6070 Fragment code;
6071 // Read positional argument count.
6072 const intptr_t positional_count = ReadListLength();
6073 ASSERT(positional_count == argument_count);
6074 code += BuildExpression(); // Argument 1: typedDataBase.
6075 code += BuildExpression(); // Argument 2: offsetInBytes
6076 if (at_index) {
6077 code += BuildExpression(); // Argument 3: index
6078 code += IntConstant(native_type->SizeInBytes());
6079 code += B->BinaryIntegerOp(Token::kMUL, kTagged, /* truncate= */ true);
6080 code += B->BinaryIntegerOp(Token::kADD, kTagged, /* truncate= */ true);
6081 }
6082 if (is_store) {
6083 code += BuildExpression(); // Argument 4: value
6084 }
6085
6086 // Skip (empty) named arguments list.
6087 const intptr_t named_args_len = ReadListLength();
6088 ASSERT(named_args_len == 0);
6089
6090 // This call site is not guaranteed to be optimized. So, do a call to the
6091 // correct force optimized function instead of compiling the body.
6093 if (is_store) {
6094 kind = compiler::ffi::FfiStore(*native_type);
6095 } else {
6096 kind = compiler::ffi::FfiLoad(*native_type);
6097 }
6099 const Library& ffi_library = Library::Handle(Z, Library::FfiLibrary());
6100 const Function& target = Function::ZoneHandle(
6101 Z, ffi_library.LookupFunctionAllowPrivate(
6103 ASSERT(!target.IsNull());
6104 Array& argument_names = Array::ZoneHandle(Z);
6105 const intptr_t static_call_arg_count = 2 + (is_store ? 1 : 0);
6106 code += StaticCall(TokenPosition::kNoSource, target, static_call_arg_count,
6107 argument_names, ICData::kStatic);
6108
6109 return code;
6110}
6111
6112Fragment StreamingFlowGraphBuilder::BuildFfiCall() {
6113 const intptr_t argc = ReadUInt(); // Read argument count.
6114 ASSERT(argc == 1); // Target pointer.
6115 const intptr_t list_length = ReadListLength(); // Read types list length.
6116 T.BuildTypeArguments(list_length); // Read types.
6117 // Read positional argument count.
6118 const intptr_t positional_count = ReadListLength();
6119 ASSERT(positional_count == argc);
6120
6121 Fragment code;
6122 // Push the target function pointer passed as Pointer object.
6123 code += BuildExpression();
6124 // This can only be Pointer, so the data field points to unmanaged memory.
6125 code += LoadNativeField(Slot::PointerBase_data(),
6127
6128 // Skip (empty) named arguments list.
6129 const intptr_t named_args_len = ReadListLength();
6130 ASSERT(named_args_len == 0);
6131
6132 const auto& native_type = FunctionType::ZoneHandle(
6133 Z, parsed_function()->function().FfiCSignature());
6134
6135 // AbiSpecificTypes can have an incomplete mapping.
6136 const char* error = nullptr;
6138 if (error != nullptr) {
6139 const auto& language_error = Error::Handle(
6140 LanguageError::New(String::Handle(String::New(error, Heap::kOld)),
6142 Report::LongJump(language_error);
6143 }
6144
6145 code += B->FfiCallFunctionBody(parsed_function()->function(), native_type,
6146 /*first_argument_parameter_offset=*/1);
6147
6148 ASSERT(code.is_closed());
6149
6150 NullConstant(); // Maintain stack balance.
6151
6152 return code;
6153}
6154
6155Fragment StreamingFlowGraphBuilder::BuildArgumentsCachableIdempotentCall(
6156 intptr_t* argument_count) {
6157 *argument_count = ReadUInt(); // read arguments count.
6158
6159 // List of types.
6160 const intptr_t types_list_length = ReadListLength();
6161 if (types_list_length != 0) {
6162 FATAL("Type arguments for vm:cachable-idempotent not (yet) supported.");
6163 }
6164
6165 Fragment code;
6166 // List of positional.
6167 intptr_t positional_list_length = ReadListLength();
6168 for (intptr_t i = 0; i < positional_list_length; ++i) {
6169 code += BuildExpression();
6170 Definition* target_def = B->Peek();
6171 if (!target_def->IsConstant()) {
6172 FATAL(
6173 "Arguments for vm:cachable-idempotent must be const, argument on "
6174 "index %" Pd " is not.",
6175 i);
6176 }
6177 }
6178
6179 // List of named.
6180 const intptr_t named_args_len = ReadListLength();
6181 if (named_args_len != 0) {
6182 FATAL("Named arguments for vm:cachable-idempotent not (yet) supported.");
6183 }
6184
6185 return code;
6186}
6187
6188Fragment StreamingFlowGraphBuilder::BuildCachableIdempotentCall(
6189 TokenPosition position,
6190 const Function& target) {
6191 // The call site must me fore optimized because the cache is untagged.
6192 if (!parsed_function()->function().ForceOptimize()) {
6193 FATAL(
6194 "vm:cachable-idempotent functions can only be called from "
6195 "vm:force-optimize functions.");
6196 }
6197 const auto& target_result_type = AbstractType::Handle(target.result_type());
6198 if (!target_result_type.IsIntType()) {
6199 FATAL("The return type vm:cachable-idempotent functions must be int.")
6200 }
6201
6202 Fragment code;
6203 Array& argument_names = Array::ZoneHandle(Z);
6204 intptr_t argument_count;
6205 code += BuildArgumentsCachableIdempotentCall(&argument_count);
6206
6207 code += flow_graph_builder_->CachableIdempotentCall(
6208 position, kUnboxedAddress, target, argument_count, argument_names,
6209 /*type_args_len=*/0);
6210
6211 return code;
6212}
6213
6214Fragment StreamingFlowGraphBuilder::BuildFfiNativeCallbackFunction(
6215 FfiCallbackKind kind) {
6216 // The call-site must look like this (guaranteed by the FE which inserts it):
6217 //
6218 // FfiCallbackKind::kIsolateLocalStaticCallback:
6219 // _nativeCallbackFunction<NativeSignatureType>(target, exceptionalReturn)
6220 //
6221 // FfiCallbackKind::kAsyncCallback:
6222 // _nativeAsyncCallbackFunction<NativeSignatureType>()
6223 //
6224 // FfiCallbackKind::kIsolateLocalClosureCallback:
6225 // _nativeIsolateLocalCallbackFunction<NativeSignatureType>(
6226 // exceptionalReturn)
6227 //
6228 // The FE also guarantees that the arguments are constants.
6229
6230 const bool has_target = kind == FfiCallbackKind::kIsolateLocalStaticCallback;
6231 const bool has_exceptional_return = kind != FfiCallbackKind::kAsyncCallback;
6232 const intptr_t expected_argc =
6233 static_cast<int>(has_target) + static_cast<int>(has_exceptional_return);
6234
6235 const intptr_t argc = ReadUInt(); // Read argument count.
6236 ASSERT(argc == expected_argc);
6237
6238 const intptr_t list_length = ReadListLength(); // Read types list length.
6239 ASSERT(list_length == 1); // The native signature.
6240 const TypeArguments& type_arguments =
6241 T.BuildTypeArguments(list_length); // Read types.
6242 ASSERT(type_arguments.Length() == 1 && type_arguments.IsInstantiated());
6243 const FunctionType& native_sig =
6244 FunctionType::CheckedHandle(Z, type_arguments.TypeAt(0));
6245
6246 Fragment code;
6247 const intptr_t positional_count =
6248 ReadListLength(); // Read positional argument count.
6249 ASSERT(positional_count == expected_argc);
6250
6251 // Read target expression and extract the target function.
6252 Function& target = Function::Handle(Z, Function::null());
6253 Instance& exceptional_return = Instance::ZoneHandle(Z, Instance::null());
6254
6255 if (has_target) {
6256 // Build target argument.
6257 code += BuildExpression();
6258 Definition* target_def = B->Peek();
6259 ASSERT(target_def->IsConstant());
6260 const Closure& target_closure =
6261 Closure::Cast(target_def->AsConstant()->value());
6262 ASSERT(!target_closure.IsNull());
6263 target = target_closure.function();
6264 ASSERT(!target.IsNull() && target.IsImplicitClosureFunction());
6265 target = target.parent_function();
6266 code += Drop();
6267 }
6268
6269 if (has_exceptional_return) {
6270 // Build exceptionalReturn argument.
6271 code += BuildExpression();
6272 Definition* exceptional_return_def = B->Peek();
6273 ASSERT(exceptional_return_def->IsConstant());
6274 exceptional_return ^= exceptional_return_def->AsConstant()->value().ptr();
6275 code += Drop();
6276 }
6277
6278 const intptr_t named_args_len =
6279 ReadListLength(); // Skip (empty) named arguments list.
6280 ASSERT(named_args_len == 0);
6281
6282 // AbiSpecificTypes can have an incomplete mapping.
6283 const char* error = nullptr;
6286
6287 const Function& result = Function::ZoneHandle(
6289 exceptional_return, kind));
6290 code += Constant(result);
6291
6292 return code;
6293}
6294
6295Fragment StreamingFlowGraphBuilder::BuildFfiNativeAddressOf() {
6296 const intptr_t argc = ReadUInt();
6297 ASSERT(argc == 1);
6298 const intptr_t types_length = ReadListLength();
6299 ASSERT(types_length == 1);
6300 T.BuildTypeArguments(types_length);
6301 const intptr_t positional_count = ReadListLength();
6302 ASSERT(positional_count == 1);
6303
6304 Fragment frag = BuildExpression();
6305 ASSERT(frag.entry->IsConstant());
6306 const auto& native_annotation =
6307 Instance::Cast(frag.entry->AsConstant()->value());
6308 Drop();
6309
6310 const auto& pointer_class =
6311 Class::ZoneHandle(Z, IG->object_store()->ffi_pointer_class());
6312 const auto& type_arguments =
6313 TypeArguments::ZoneHandle(Z, IG->object_store()->type_argument_never());
6314 Fragment code = Constant(type_arguments);
6315 code += AllocateObject(TokenPosition::kNoSource, pointer_class, 1);
6316 code += LoadLocal(MakeTemporary()); // Duplicate Pointer.
6317 // FfiNativeLookupAddress pushes an unboxed value, which is safe even in
6318 // unoptimized mode because then there is no reordering and we're consuming
6319 // the value directly.
6320 code += flow_graph_builder_->FfiNativeLookupAddress(native_annotation);
6321 code += flow_graph_builder_->StoreNativeField(
6322 Slot::PointerBase_data(), InnerPointerAccess::kCannotBeInnerPointer,
6324
6325 const intptr_t named_arg_count = ReadListLength();
6326 ASSERT(named_arg_count == 0);
6327 return code;
6328}
6329
6330} // namespace kernel
6331} // namespace dart
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)
#define F(x)
#define UNREACHABLE()
Definition: assert.h:248
#define ASSERT_EQUAL(expected, actual)
Definition: assert.h:309
#define RELEASE_ASSERT(cond)
Definition: assert.h:327
GLenum type
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:10959
static const Bool & False()
Definition: object.h:10799
static const Bool & Get(bool value)
Definition: object.h:10801
static const Bool & True()
Definition: object.h:10797
FunctionPtr LookupStaticFunction(const String &name) const
Definition: object.cc:6137
ErrorPtr EnsureIsFinalized(Thread *thread) const
Definition: object.cc:4924
ClassPtr SuperClass(ClassTable *class_table=nullptr) const
Definition: object.cc:3665
static FunctionPtr LookupClosureFunction(const Function &member_function, intptr_t kernel_offset)
static CompileType Dynamic()
static CompilerState & Current()
static DoublePtr NewCanonical(double d)
Definition: object.cc:23418
static constexpr CompilationMode CompilationModeFrom(bool is_optimizing)
Definition: flow_graph.h:585
intptr_t NumOptionalParameters() const
Definition: object.cc:8868
intptr_t NumTypeParameters() const
Definition: object.cc:8847
static StringPtr CreateDynamicInvocationForwarderName(const String &name)
Definition: object.cc:4205
intptr_t NumParameters() const
Definition: object.cc:8877
@ kOld
Definition: heap.h:39
static IntegerPtr NewCanonical(const String &str)
Definition: object.cc:22999
static LibraryPtr CoreLibrary()
Definition: object.cc:14787
static ClassPtr LookupCoreClass(const String &class_name)
Definition: object.cc:14689
static const String & PrivateCoreLibName(const String &member)
Definition: object.cc:14674
static LibraryPtr InternalLibrary()
Definition: object.cc:14803
static LibraryPtr FfiLibrary()
Definition: object.cc:14799
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:27898
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:176
static FunctionPtr ResolveFunction(Zone *zone, const Class &receiver_class, const String &function_name)
Definition: resolver.cc:167
static FunctionPtr ResolveDynamicForReceiverClassAllowPrivate(const Class &receiver_class, const String &function_name, const ArgumentsDescriptor &args_desc)
Definition: resolver.cc:158
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:23698
static const String & Empty()
Definition: symbols.h:688
static StringPtr New(Thread *thread, const char *cstr)
Definition: symbols.h:723
static const String & Minus()
Definition: symbols.h:618
static TokenPosition Synthetic(intptr_t value)
static TypeArgumentsPtr New(intptr_t len, Heap::Space space=Heap::kOld)
Definition: object.cc:7675
AbstractTypePtr TypeAt(intptr_t index) const
Definition: object.cc:7308
Definition * definition() const
Definition: il.h:103
static const NativeType * FromAbstractType(Zone *zone, const AbstractType &type, const char **error)
Definition: native_type.cc:549
static word field_offset(intptr_t index)
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 Constant(const Object &value)
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)
Definition: kernel_to_il.h:855
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)
Definition: kernel_to_il.h:711
static SwitchRange Leaf(intptr_t index, Fragment branch_instructions, bool is_bounds_checked=false)
Definition: kernel_to_il.h:962
static SwitchRange Branch(intptr_t min, intptr_t max, Fragment branch_instructions)
Definition: kernel_to_il.h:968
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
#define T
#define IG
#define Z
size_t length
Win32Message message
static bool is_bool(const Type &type)
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 constexpr intptr_t kWordSize
Definition: runtime_api.h:274
FrameLayout frame_layout
Definition: stack_frame.cc:76
static void ReportIfNotNull(const char *error)
static Function & GetNoSuchMethodOrDie(Thread *thread, Zone *zone, const Class &klass)
static constexpr int SpecializedIntLiteralBias
LogicalOperator
Definition: kernel.h:60
@ kYieldStatementFlagYieldStar
@ kSwitchDispatchLinearScan
Definition: kernel_to_il.h:921
@ kSwitchDispatchJumpTable
Definition: kernel_to_il.h:923
@ kSwitchDispatchBinarySearch
Definition: kernel_to_il.h:922
@ kInstanceInvocationFlagInvariant
@ kAsExpressionFlagUnchecked
@ kAsExpressionFlagTypeError
Definition: dart_vm.cc:33
static const char *const names[]
Definition: symbols.cc:24
const char *const name
InnerPointerAccess
Definition: il.h:6295
Nullability
Definition: object.h:1112
FfiCallbackKind
Definition: object.h:2984
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:27151
@ kNoRegister
Definition: constants_arm.h:99
static constexpr Representation kUnboxedAddress
Definition: locations.h:182
@ kFunctions
Definition: object.h:2251
@ kCurrentClass
Definition: object.h:2250
static Dart_Handle LoadLibrary(Thread *T, const ExternalTypedData &td)
const char *const function_name
def call(args)
Definition: dom.py:159
std::function< void()> closure
Definition: closure.h:14
dictionary dependencies
Definition: minify_sksl.py:17
#define Pd
Definition: globals.h:408
int compare(const void *untyped_lhs, const void *untyped_rhs)
Definition: skdiff.h:161
static SkString join(const CommandLineFlags::StringArray &)
Definition: skpbench.cpp:741
SeparatedVector2 offset
Definition: SkMD5.cpp:120
Definition: SkMD5.cpp:130
static constexpr Register kValue2Reg