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
5#include "vm/compiler/frontend/kernel_binary_flowgraph.h"
6
7#include "vm/compiler/ffi/callback.h"
8#include "vm/compiler/frontend/bytecode_flow_graph_builder.h"
9#include "vm/compiler/frontend/bytecode_reader.h"
10#include "vm/compiler/frontend/flow_graph_builder.h" // For dart::FlowGraphBuilder::SimpleInstanceOfType.
11#include "vm/compiler/frontend/prologue_builder.h"
12#include "vm/compiler/jit/compiler.h"
13#include "vm/object_store.h"
14#include "vm/resolver.h"
15#include "vm/stack_frame.h"
16
17namespace dart {
18
19DECLARE_FLAG(bool, enable_interpreter);
20
21namespace kernel {
22
23#define Z (zone_)
24#define H (translation_helper_)
25#define T (type_translator_)
26#define I Isolate::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 Tag initializer_tag = ReadTag(); // read first part of initializer.
42 if (initializer_tag != kSomething) {
43 UNREACHABLE();
44 }
45
46 B->graph_entry_ = new (Z) GraphEntryInstr(*parsed_function(), B->osr_id_);
47
48 auto normal_entry = B->BuildFunctionEntry(B->graph_entry_);
49 B->graph_entry_->set_normal_entry(normal_entry);
50
51 Fragment body(normal_entry);
52 body += B->CheckStackOverflowInPrologue(field_helper.position_);
53 if (field_helper.IsConst()) {
54 // This will read the initializer.
55 body += Constant(
56 Instance::ZoneHandle(Z, constant_reader_.ReadConstantExpression()));
57 } else {
58 body += SetupCapturedParameters(parsed_function()->function());
59 body += BuildExpression(); // read initializer.
60 }
61 body += Return(TokenPosition::kNoSource);
62
63 PrologueInfo prologue_info(-1, -1);
64 if (B->IsCompiledForOsr()) {
65 B->graph_entry_->RelinkToOsrEntry(Z, B->last_used_block_id_ + 1);
66 }
67 return new (Z) FlowGraph(*parsed_function(), B->graph_entry_,
68 B->last_used_block_id_, prologue_info);
69}
70
71void StreamingFlowGraphBuilder::EvaluateConstFieldValue(const Field& field) {
72 ASSERT(field.is_const() && field.IsUninitialized());
73
74 FieldHelper field_helper(this);
75 field_helper.ReadUntilExcluding(FieldHelper::kInitializer);
76 Tag initializer_tag = ReadTag(); // read first part of initializer.
77
78 ASSERT(initializer_tag == kSomething);
79
80 Instance& value =
81 Instance::Handle(Z, constant_reader_.ReadConstantExpression());
82 field.SetStaticValue(value);
83}
84
85void StreamingFlowGraphBuilder::SetupDefaultParameterValues() {
86 intptr_t optional_parameter_count =
87 parsed_function()->function().NumOptionalParameters();
88 if (optional_parameter_count > 0) {
89 ZoneGrowableArray<const Instance*>* default_values =
90 new ZoneGrowableArray<const Instance*>(Z, optional_parameter_count);
91
92 AlternativeReadingScope alt(&reader_);
93 FunctionNodeHelper function_node_helper(this);
94 function_node_helper.ReadUntilExcluding(
95 FunctionNodeHelper::kPositionalParameters);
96
97 if (parsed_function()->function().HasOptionalNamedParameters()) {
98 // List of positional.
99 intptr_t list_length = ReadListLength(); // read list length.
100 for (intptr_t i = 0; i < list_length; ++i) {
101 SkipVariableDeclaration(); // read ith variable declaration.
102 }
103
104 // List of named.
105 list_length = ReadListLength(); // read list length.
106 ASSERT(optional_parameter_count == list_length);
107 ASSERT(!parsed_function()->function().HasOptionalPositionalParameters());
108 for (intptr_t i = 0; i < list_length; ++i) {
109 Instance* default_value;
110
111 // Read ith variable declaration
112 VariableDeclarationHelper helper(this);
113 helper.ReadUntilExcluding(VariableDeclarationHelper::kInitializer);
114 Tag tag = ReadTag(); // read (first part of) initializer.
115 if (tag == kSomething) {
116 // This will read the initializer.
117 default_value = &Instance::ZoneHandle(
118 Z, constant_reader_.ReadConstantExpression());
119 } else {
120 default_value = &Instance::ZoneHandle(Z, Instance::null());
121 }
122 default_values->Add(default_value);
123 }
124 } else {
125 // List of positional.
126 intptr_t list_length = ReadListLength(); // read list length.
127 ASSERT(list_length == function_node_helper.required_parameter_count_ +
128 optional_parameter_count);
129 ASSERT(parsed_function()->function().HasOptionalPositionalParameters());
130 for (intptr_t i = 0; i < function_node_helper.required_parameter_count_;
131 ++i) {
132 SkipVariableDeclaration(); // read ith variable declaration.
133 }
134 for (intptr_t i = 0; i < optional_parameter_count; ++i) {
135 Instance* default_value;
136
137 // Read ith variable declaration
138 VariableDeclarationHelper helper(this);
139 helper.ReadUntilExcluding(VariableDeclarationHelper::kInitializer);
140 Tag tag = ReadTag(); // read (first part of) initializer.
141 if (tag == kSomething) {
142 // This will read the initializer.
143 default_value = &Instance::ZoneHandle(
144 Z, constant_reader_.ReadConstantExpression());
145 } else {
146 default_value = &Instance::ZoneHandle(Z, Instance::null());
147 }
148 default_values->Add(default_value);
149 }
150
151 // List of named.
152 list_length = ReadListLength(); // read list length.
153 ASSERT(list_length == 0);
154 }
155 parsed_function()->set_default_parameter_values(default_values);
156 }
157}
158
159Fragment StreamingFlowGraphBuilder::BuildFieldInitializer(
160 const Field& field,
161 bool only_for_side_effects) {
162 ASSERT(Error::Handle(Z, H.thread()->sticky_error()).IsNull());
163 if (PeekTag() == kNullLiteral) {
164 SkipExpression(); // read past the null literal.
165 if (H.thread()->IsMutatorThread()) {
166 field.RecordStore(Object::null_object());
167 } else {
168 ASSERT(field.is_nullable(/* silence_assert = */ true));
169 }
170 return Fragment();
171 }
172
173 Fragment instructions;
174 if (!only_for_side_effects) {
175 instructions += LoadLocal(parsed_function()->receiver_var());
176 }
177 // All closures created inside BuildExpression will have
178 // field.RawOwner() as its owner.
179 closure_owner_ = field.RawOwner();
180 instructions += BuildExpression();
181 closure_owner_ = Object::null();
182 if (only_for_side_effects) {
183 instructions += Drop();
184 } else {
185 instructions += flow_graph_builder_->StoreInstanceFieldGuarded(
186 field, StoreInstanceFieldInstr::Kind::kInitializing);
187 }
188 return instructions;
189}
190
191Fragment StreamingFlowGraphBuilder::BuildLateFieldInitializer(
192 const Field& field,
193 bool has_initializer) {
194 if (has_initializer && PeekTag() == kNullLiteral) {
195 SkipExpression(); // read past the null literal.
196 if (H.thread()->IsMutatorThread()) {
197 field.RecordStore(Object::null_object());
198 } else {
199 ASSERT(field.is_nullable(/* silence_assert = */ true));
200 }
201 return Fragment();
202 }
203
204 Fragment instructions;
205 instructions += LoadLocal(parsed_function()->receiver_var());
206 instructions += flow_graph_builder_->Constant(Object::sentinel());
207 instructions += flow_graph_builder_->StoreInstanceField(
208 field, StoreInstanceFieldInstr::Kind::kInitializing);
209 return instructions;
210}
211
212Fragment StreamingFlowGraphBuilder::BuildInitializers(
213 const Class& parent_class) {
214 ASSERT(Error::Handle(Z, H.thread()->sticky_error()).IsNull());
215 Fragment instructions;
216
217 // Start by getting the position of the constructors initializer.
218 intptr_t initializers_offset = -1;
219 {
220 AlternativeReadingScope alt(&reader_);
221 SkipFunctionNode(); // read constructors function node.
222 initializers_offset = ReaderOffset();
223 }
224
225 bool is_redirecting_constructor = false;
226
227 // Field which will be initialized by the initializer with the given index.
228 GrowableArray<const Field*> initializer_fields(5);
229
230 // Check if this is a redirecting constructor and collect all fields which
231 // will be initialized by the constructor initializer list.
232 {
233 AlternativeReadingScope alt(&reader_, initializers_offset);
234
235 const intptr_t list_length =
236 ReadListLength(); // read initializers list length.
237 initializer_fields.EnsureLength(list_length, nullptr);
238
239 bool has_field_initializers = false;
240 for (intptr_t i = 0; i < list_length; ++i) {
241 if (PeekTag() == kRedirectingInitializer) {
242 is_redirecting_constructor = true;
243 } else if (PeekTag() == kFieldInitializer) {
244 has_field_initializers = true;
245 ReadTag();
246 ReadBool();
247 const NameIndex field_name = ReadCanonicalNameReference();
248 const Field& field =
249 Field::Handle(Z, H.LookupFieldByKernelField(field_name));
250 initializer_fields[i] = &field;
251 SkipExpression();
252 continue;
253 }
254 SkipInitializer();
255 }
256 ASSERT(!is_redirecting_constructor || !has_field_initializers);
257 }
258
259 // These come from:
260 //
261 // class A {
262 // var x = (expr);
263 // }
264 //
265 // We don't want to do that when this is a Redirecting Constructors though
266 // (i.e. has a single initializer being of type kRedirectingInitializer).
267 if (!is_redirecting_constructor) {
268 // Sort list of fields (represented as their kernel offsets) which will
269 // be initialized by the constructor initializer list. We will not emit
270 // StoreInstanceField instructions for those initializers though we will
271 // still evaluate initialization expression for its side effects.
272 GrowableArray<intptr_t> constructor_initialized_field_offsets(
273 initializer_fields.length());
274 for (auto field : initializer_fields) {
275 if (field != nullptr) {
276 constructor_initialized_field_offsets.Add(field->kernel_offset());
277 }
278 }
279
280 constructor_initialized_field_offsets.Sort(
281 [](const intptr_t* a, const intptr_t* b) {
282 return static_cast<int>(*a) - static_cast<int>(*b);
283 });
284 constructor_initialized_field_offsets.Add(-1);
285
286 ExternalTypedData& kernel_data = ExternalTypedData::Handle(Z);
287 Array& class_fields = Array::Handle(Z, parent_class.fields());
288 Field& class_field = Field::Handle(Z);
289 intptr_t next_constructor_initialized_field_index = 0;
290 for (intptr_t i = 0; i < class_fields.Length(); ++i) {
291 class_field ^= class_fields.At(i);
292 if (!class_field.is_static()) {
293 const intptr_t field_offset = class_field.kernel_offset();
294
295 // Check if this field will be initialized by the constructor
296 // initializer list.
297 // Note that both class_fields and the list of initialized fields
298 // are sorted by their kernel offset (by construction) -
299 // so we don't need to perform the search.
300 bool is_constructor_initialized = false;
301 const intptr_t constructor_initialized_field_offset =
302 constructor_initialized_field_offsets
303 [next_constructor_initialized_field_index];
304 if (constructor_initialized_field_offset == field_offset) {
305 next_constructor_initialized_field_index++;
306 is_constructor_initialized = true;
307 }
308
309 kernel_data = class_field.KernelData();
310 ASSERT(!kernel_data.IsNull());
311 AlternativeReadingScopeWithNewData alt(&reader_, &kernel_data,
312 field_offset);
313 FieldHelper field_helper(this);
314 field_helper.ReadUntilExcluding(FieldHelper::kInitializer);
315 const Tag initializer_tag = ReadTag();
316 if (class_field.is_late()) {
317 if (!is_constructor_initialized) {
318 instructions += BuildLateFieldInitializer(
319 Field::ZoneHandle(Z, class_field.raw()),
320 initializer_tag == kSomething);
321 }
322 } else if (initializer_tag == kSomething) {
323 EnterScope(field_offset);
324 // If this field is initialized in constructor then we can ignore the
325 // value produced by the field initializer. However we still need to
326 // execute it for its side effects.
327 instructions += BuildFieldInitializer(
328 Field::ZoneHandle(Z, class_field.raw()),
329 /*only_for_side_effects=*/is_constructor_initialized);
330 ExitScope(field_offset);
331 }
332 }
333 }
334 }
335
336 // These to come from:
337 // class A {
338 // var x;
339 // var y;
340 // A(this.x) : super(expr), y = (expr);
341 // }
342 {
343 AlternativeReadingScope alt(&reader_, initializers_offset);
344 intptr_t list_length = ReadListLength(); // read initializers list length.
345 for (intptr_t i = 0; i < list_length; ++i) {
346 Tag tag = ReadTag();
347 bool isSynthetic = ReadBool(); // read isSynthetic flag.
348 switch (tag) {
349 case kInvalidInitializer:
350 UNIMPLEMENTED();
351 return Fragment();
352 case kFieldInitializer: {
353 ReadCanonicalNameReference();
354 instructions += BuildFieldInitializer(
355 Field::ZoneHandle(Z, initializer_fields[i]->raw()),
356 /*only_for_size_effects=*/false);
357 break;
358 }
359 case kAssertInitializer: {
360 instructions += BuildStatement();
361 break;
362 }
363 case kSuperInitializer: {
364 TokenPosition position = ReadPosition(); // read position.
365 NameIndex canonical_target =
366 ReadCanonicalNameReference(); // read target_reference.
367
368 instructions += LoadLocal(parsed_function()->receiver_var());
369
370 // TODO(jensj): ASSERT(init->arguments()->types().length() == 0);
371 Array& argument_names = Array::ZoneHandle(Z);
372 intptr_t argument_count;
373 instructions += BuildArguments(
374 &argument_names, &argument_count,
375 /* positional_parameter_count = */ NULL); // read arguments.
376 argument_count += 1;
377
378 Class& parent_klass = GetSuperOrDie();
379
380 const Function& target = Function::ZoneHandle(
381 Z, H.LookupConstructorByKernelConstructor(
382 parent_klass, H.CanonicalNameString(canonical_target)));
383 instructions += StaticCall(
384 isSynthetic ? TokenPosition::kNoSource : position, target,
385 argument_count, argument_names, ICData::kStatic);
386 instructions += Drop();
387 break;
388 }
389 case kRedirectingInitializer: {
390 TokenPosition position = ReadPosition(); // read position.
391 NameIndex canonical_target =
392 ReadCanonicalNameReference(); // read target_reference.
393
394 instructions += LoadLocal(parsed_function()->receiver_var());
395
396 // TODO(jensj): ASSERT(init->arguments()->types().length() == 0);
397 Array& argument_names = Array::ZoneHandle(Z);
398 intptr_t argument_count;
399 instructions += BuildArguments(
400 &argument_names, &argument_count,
401 /* positional_parameter_count = */ NULL); // read arguments.
402 argument_count += 1;
403
404 const Function& target = Function::ZoneHandle(
405 Z, H.LookupConstructorByKernelConstructor(canonical_target));
406 instructions += StaticCall(
407 isSynthetic ? TokenPosition::kNoSource : position, target,
408 argument_count, argument_names, ICData::kStatic);
409 instructions += Drop();
410 break;
411 }
412 case kLocalInitializer: {
413 // The other initializers following this one might read the variable.
414 // This is used e.g. for evaluating the arguments to a super call
415 // first, run normal field initializers next and then make the actual
416 // super call:
417 //
418 // The frontend converts
419 //
420 // class A {
421 // var x;
422 // A(a, b) : super(a + b), x = 2*b {}
423 // }
424 //
425 // to
426 //
427 // class A {
428 // var x;
429 // A(a, b) : tmp = a + b, x = 2*b, super(tmp) {}
430 // }
431 //
432 // (This is strictly speaking not what one should do in terms of the
433 // specification but that is how it is currently implemented.)
434 LocalVariable* variable =
435 LookupVariable(ReaderOffset() + data_program_offset_);
436
437 // Variable declaration
438 VariableDeclarationHelper helper(this);
439 helper.ReadUntilExcluding(VariableDeclarationHelper::kInitializer);
440 ASSERT(!helper.IsConst());
441 Tag tag = ReadTag(); // read (first part of) initializer.
442 if (tag != kSomething) {
443 UNREACHABLE();
444 }
445
446 instructions += BuildExpression(); // read initializer.
447 instructions += StoreLocal(TokenPosition::kNoSource, variable);
448 instructions += Drop();
449 break;
450 }
451 default:
452 ReportUnexpectedTag("initializer", tag);
453 UNREACHABLE();
454 }
455 }
456 }
457 return instructions;
458}
459
460void StreamingFlowGraphBuilder::ReadDefaultFunctionTypeArguments(
461 const Function& function) {
462 if (!function.IsGeneric()) {
463 return;
464 }
465 AlternativeReadingScope alt(&reader_);
466 FunctionNodeHelper function_node_helper(this);
467 function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kTypeParameters);
468 intptr_t num_type_params = ReadListLength();
469 ASSERT(num_type_params == function.NumTypeParameters());
470 TypeArguments& default_types =
471 TypeArguments::Handle(Z, TypeArguments::New(num_type_params));
472 for (intptr_t i = 0; i < num_type_params; ++i) {
473 TypeParameterHelper helper(this);
474 helper.ReadUntilExcludingAndSetJustRead(TypeParameterHelper::kDefaultType);
475 if (ReadTag() == kSomething) {
476 default_types.SetTypeAt(i, T.BuildType());
477 } else {
478 default_types.SetTypeAt(i, Object::dynamic_type());
479 }
480 helper.Finish();
481 }
482 default_types = default_types.Canonicalize();
483 parsed_function()->SetDefaultFunctionTypeArguments(default_types);
484}
485
486Fragment StreamingFlowGraphBuilder::DebugStepCheckInPrologue(
487 const Function& dart_function,
488 TokenPosition position) {
489 if (!NeedsDebugStepCheck(dart_function, position)) {
490 return {};
491 }
492
493 // Place this check at the last parameter to ensure parameters
494 // are in scope in the debugger at method entry.
495 const int parameter_count = dart_function.NumParameters();
496 TokenPosition check_pos = TokenPosition::kNoSource;
497 if (parameter_count > 0) {
498 const LocalVariable& parameter =
499 *parsed_function()->ParameterVariable(parameter_count - 1);
500 check_pos = parameter.token_pos();
501 }
502 if (!check_pos.IsDebugPause()) {
503 // No parameters or synthetic parameters.
504 check_pos = position;
505 ASSERT(check_pos.IsDebugPause());
506 }
507
508 return DebugStepCheck(check_pos);
509}
510
511Fragment StreamingFlowGraphBuilder::SetAsyncStackTrace(
512 const Function& dart_function) {
513 if (!FLAG_causal_async_stacks ||
514 !(dart_function.IsAsyncClosure() || dart_function.IsAsyncGenClosure())) {
515 return {};
516 }
517
518 // The code we are building will be executed right after we enter
519 // the function and before any nested contexts are allocated.
520 ASSERT(B->context_depth_ ==
521 scopes()->yield_jump_variable->owner()->context_level());
522
523 Fragment instructions;
524 LocalScope* scope = parsed_function()->scope();
525
526 const Function& target = Function::ZoneHandle(
527 Z, I->object_store()->async_set_thread_stack_trace());
528 ASSERT(!target.IsNull());
529
530 // Fetch and load :async_stack_trace
531 LocalVariable* async_stack_trace_var =
532 scope->LookupVariable(Symbols::AsyncStackTraceVar(), false);
533 ASSERT((async_stack_trace_var != NULL) &&
534 async_stack_trace_var->is_captured());
535
536 Fragment code;
537 code += LoadLocal(async_stack_trace_var);
538 // Call _asyncSetThreadStackTrace
539 code += StaticCall(TokenPosition::kNoSource, target,
540 /* argument_count = */ 1, ICData::kStatic);
541 code += Drop();
542 return code;
543}
544
545Fragment StreamingFlowGraphBuilder::TypeArgumentsHandling(
546 const Function& dart_function) {
547 Fragment prologue = B->BuildDefaultTypeHandling(dart_function);
548
549 if (dart_function.IsClosureFunction() &&
550 dart_function.NumParentTypeParameters() > 0) {
551 LocalVariable* closure = parsed_function()->ParameterVariable(0);
552
553 // Function with yield points can not be generic itself but the outer
554 // function can be.
555 ASSERT(yield_continuations().is_empty() || !dart_function.IsGeneric());
556
557 LocalVariable* fn_type_args = parsed_function()->function_type_arguments();
558 ASSERT(fn_type_args != NULL && closure != NULL);
559
560 if (dart_function.IsGeneric()) {
561 prologue += LoadLocal(fn_type_args);
562
563 prologue += LoadLocal(closure);
564 prologue += LoadNativeField(Slot::Closure_function_type_arguments());
565
566 prologue += IntConstant(dart_function.NumParentTypeParameters());
567
568 prologue += IntConstant(dart_function.NumTypeParameters() +
569 dart_function.NumParentTypeParameters());
570
571 const Library& dart_internal =
572 Library::Handle(Z, Library::InternalLibrary());
573 const Function& prepend_function =
574 Function::ZoneHandle(Z, dart_internal.LookupFunctionAllowPrivate(
575 Symbols::PrependTypeArguments()));
576 ASSERT(!prepend_function.IsNull());
577
578 prologue += StaticCall(TokenPosition::kNoSource, prepend_function, 4,
579 ICData::kStatic);
580 prologue += StoreLocal(TokenPosition::kNoSource, fn_type_args);
581 prologue += Drop();
582 } else {
583 prologue += LoadLocal(closure);
584 prologue += LoadNativeField(Slot::Closure_function_type_arguments());
585 prologue += StoreLocal(TokenPosition::kNoSource, fn_type_args);
586 prologue += Drop();
587 }
588 }
589
590 return prologue;
591}
592
593Fragment StreamingFlowGraphBuilder::CompleteBodyWithYieldContinuations(
594 Fragment body) {
595 // The code we are building will be executed right after we enter
596 // the function and before any nested contexts are allocated.
597 // Reset current context_depth_ to match this.
598 const intptr_t current_context_depth = B->context_depth_;
599 B->context_depth_ = scopes()->yield_jump_variable->owner()->context_level();
600
601 // Prepend an entry corresponding to normal entry to the function.
602 yield_continuations().InsertAt(
603 0, YieldContinuation(new (Z) DropTempsInstr(0, NULL), kInvalidTryIndex));
604 yield_continuations()[0].entry->LinkTo(body.entry);
605
606 // Load :await_jump_var into a temporary.
607 Fragment dispatch;
608 dispatch += LoadLocal(scopes()->yield_jump_variable);
609 dispatch += StoreLocal(TokenPosition::kNoSource, scopes()->switch_variable);
610 dispatch += Drop();
611
612 const intptr_t continuation_count = yield_continuations().length();
613
614 IndirectGotoInstr* indirect_goto;
615 if (FLAG_async_igoto_threshold >= 0 &&
616 continuation_count >= FLAG_async_igoto_threshold) {
617 const auto& offsets = TypedData::ZoneHandle(
618 Z, TypedData::New(kTypedDataInt32ArrayCid, continuation_count,
619 Heap::kOld));
620
621 dispatch += Constant(offsets);
622 dispatch += LoadLocal(scopes()->switch_variable);
623
624 // Ideally this would just be LoadIndexedTypedData(kTypedDataInt32ArrayCid),
625 // but that doesn't work in unoptimised code.
626 // The optimiser will turn this into that in any case.
627 dispatch += InstanceCall(TokenPosition::kNoSource, Symbols::IndexToken(),
628 Token::kINDEX, /*argument_count=*/2);
629
630 Value* offset_from_start = Pop();
631
632 indirect_goto = new (Z) IndirectGotoInstr(&offsets, offset_from_start);
633 dispatch <<= indirect_goto;
634
635 for (intptr_t i = 0; i < continuation_count; i++) {
636 if (i >= 1) {
637 Fragment resumption;
638 // Every continuation after the first is not a normal entry but a
639 // resumption.
640 // Restore :current_context_var from :await_ctx_var.
641 // Note: after this point context_depth_ does not match current context
642 // depth so we should not access any local variables anymore.
643 resumption += LoadLocal(scopes()->yield_context_variable);
644 resumption += StoreLocal(TokenPosition::kNoSource,
645 parsed_function()->current_context_var());
646 resumption += Drop();
647
648 Instruction* next = yield_continuations()[i].entry->next();
649 yield_continuations()[i].entry->LinkTo(resumption.entry);
650 resumption <<= next;
651 }
652
653 IndirectEntryInstr* indirect_entry = B->BuildIndirectEntry(
654 /*indirect_id=*/i, yield_continuations()[i].try_index);
655 indirect_entry->LinkTo(yield_continuations()[i].entry->next());
656
657 TargetEntryInstr* target = B->BuildTargetEntry();
658 Fragment(target) + Goto(indirect_entry);
659
660 indirect_goto->AddSuccessor(target);
661 }
662 } else {
663 BlockEntryInstr* block = nullptr;
664 for (intptr_t i = 0; i < continuation_count; i++) {
665 if (i == 1) {
666 // This is not a normal entry but a resumption. Restore
667 // :current_context_var from :await_ctx_var.
668 // Note: after this point context_depth_ does not match current context
669 // depth so we should not access any local variables anymore.
670 dispatch += LoadLocal(scopes()->yield_context_variable);
671 dispatch += StoreLocal(TokenPosition::kNoSource,
672 parsed_function()->current_context_var());
673 dispatch += Drop();
674 }
675 if (i == (continuation_count - 1)) {
676 // We reached the last possibility, no need to build more ifs.
677 // Continue to the last continuation.
678 // Note: continuations start with nop DropTemps instruction
679 // which acts like an anchor, so we need to skip it.
680 block->set_try_index(yield_continuations()[i].try_index);
681 dispatch <<= yield_continuations()[i].entry->next();
682 break;
683 }
684
685 // Build comparison:
686 //
687 // if (:await_jump_var == i) {
688 // -> yield_continuations()[i]
689 // } else ...
690 //
691 TargetEntryInstr* then;
692 TargetEntryInstr* otherwise;
693 dispatch += LoadLocal(scopes()->switch_variable);
694 dispatch += IntConstant(i);
695 dispatch += B->BranchIfStrictEqual(&then, &otherwise);
696
697 // True branch is linked to appropriate continuation point.
698 // Note: continuations start with nop DropTemps instruction
699 // which acts like an anchor, so we need to skip it.
700 then->LinkTo(yield_continuations()[i].entry->next());
701 then->set_try_index(yield_continuations()[i].try_index);
702 // False branch will contain the next comparison.
703 dispatch = Fragment(dispatch.entry, otherwise);
704 block = otherwise;
705 }
706 }
707 B->context_depth_ = current_context_depth;
708 return dispatch;
709}
710
711Fragment StreamingFlowGraphBuilder::CheckStackOverflowInPrologue(
712 const Function& dart_function) {
713 if (dart_function.is_native()) return {};
714 return B->CheckStackOverflowInPrologue(dart_function.token_pos());
715}
716
717Fragment StreamingFlowGraphBuilder::SetupCapturedParameters(
718 const Function& dart_function) {
719 Fragment body;
720 const LocalScope* scope = parsed_function()->scope();
721 if (scope->num_context_variables() > 0) {
722 body += flow_graph_builder_->PushContext(scope);
723 LocalVariable* context = MakeTemporary();
724
725 // Copy captured parameters from the stack into the context.
726 LocalScope* scope = parsed_function()->scope();
727 intptr_t parameter_count = dart_function.NumParameters();
728 const ParsedFunction& pf = *flow_graph_builder_->parsed_function_;
729 const Function& function = pf.function();
730
731 for (intptr_t i = 0; i < parameter_count; ++i) {
732 LocalVariable* variable = pf.ParameterVariable(i);
733 if (variable->is_captured()) {
734 LocalVariable& raw_parameter = *pf.RawParameterVariable(i);
735 ASSERT((function.HasOptionalParameters() &&
736 raw_parameter.owner() == scope) ||
737 (!function.HasOptionalParameters() &&
738 raw_parameter.owner() == NULL));
739 ASSERT(!raw_parameter.is_captured());
740
741 // Copy the parameter from the stack to the context.
742 body += LoadLocal(context);
743 body += LoadLocal(&raw_parameter);
744 body += flow_graph_builder_->StoreInstanceField(
745 TokenPosition::kNoSource,
746 Slot::GetContextVariableSlotFor(thread(), *variable),
747 StoreInstanceFieldInstr::Kind::kInitializing);
748 }
749 }
750 body += Drop(); // The context.
751 }
752 return body;
753}
754
755// If we run in checked mode or strong mode, we have to check the type of the
756// passed arguments.
757//
758// TODO(#34162): If we're building an extra entry-point to skip
759// type checks, we should substitute Redefinition nodes for the AssertAssignable
760// instructions to ensure that the argument types are known.
761void StreamingFlowGraphBuilder::CheckArgumentTypesAsNecessary(
762 const Function& dart_function,
763 intptr_t type_parameters_offset,
764 Fragment* explicit_checks,
765 Fragment* implicit_checks,
766 Fragment* implicit_redefinitions) {
767 if (!dart_function.NeedsArgumentTypeChecks()) return;
768
769 // Check if parent function was annotated with no-dynamic-invocations.
770 const ProcedureAttributesMetadata attrs =
771 procedure_attributes_metadata_helper_.GetProcedureAttributes(
772 dart_function.kernel_offset());
773
774 AlternativeReadingScope _(&reader_);
775 SetOffset(type_parameters_offset);
776 B->BuildArgumentTypeChecks(
777 MethodCanSkipTypeChecksForNonCovariantArguments(dart_function, attrs)
778 ? TypeChecksToBuild::kCheckCovariantTypeParameterBounds
779 : TypeChecksToBuild::kCheckAllTypeParameterBounds,
780 explicit_checks, implicit_checks, implicit_redefinitions);
781}
782
783Fragment StreamingFlowGraphBuilder::ShortcutForUserDefinedEquals(
784 const Function& dart_function,
785 LocalVariable* first_parameter) {
786 // The specification defines the result of `a == b` to be:
787 //
788 // a) if either side is `null` then the result is `identical(a, b)`.
789 // b) else the result is `a.operator==(b)`
790 //
791 // For user-defined implementations of `operator==` we need therefore
792 // implement the handling of a).
793 //
794 // The default `operator==` implementation in `Object` is implemented in terms
795 // of identical (which we assume here!) which means that case a) is actually
796 // included in b). So we just use the normal implementation in the body.
797 Fragment body;
798 if ((dart_function.NumParameters() == 2) &&
799 (dart_function.name() == Symbols::EqualOperator().raw()) &&
800 (dart_function.Owner() != I->object_store()->object_class())) {
801 TargetEntryInstr* null_entry;
802 TargetEntryInstr* non_null_entry;
803
804 body += LoadLocal(first_parameter);
805 body += BranchIfNull(&null_entry, &non_null_entry);
806
807 // The argument was `null` and the receiver is not the null class (we only
808 // go into this branch for user-defined == operators) so we can return
809 // false.
810 Fragment null_fragment(null_entry);
811 null_fragment += Constant(Bool::False());
812 null_fragment += Return(dart_function.end_token_pos());
813
814 body = Fragment(body.entry, non_null_entry);
815 }
816 return body;
817}
818
819Fragment StreamingFlowGraphBuilder::BuildFunctionBody(
820 const Function& dart_function,
821 LocalVariable* first_parameter,
822 bool constructor) {
823 Fragment body;
824
825 // TODO(27590): Currently the [VariableDeclaration]s from the
826 // initializers will be visible inside the entire body of the constructor.
827 // We should make a separate scope for them.
828 if (constructor) {
829 body += BuildInitializers(Class::Handle(Z, dart_function.Owner()));
830 }
831
832 if (body.is_closed()) return body;
833
834 FunctionNodeHelper function_node_helper(this);
835 function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kBody);
836
837 const bool has_body = ReadTag() == kSomething; // read first part of body.
838
839 if (dart_function.is_native()) {
840 body += B->NativeFunctionBody(dart_function, first_parameter);
841 } else if (has_body) {
842 body += BuildStatement();
843 }
844
845 if (body.is_open()) {
846 body += NullConstant();
847 body += Return(dart_function.end_token_pos());
848 }
849
850 return body;
851}
852
853Fragment StreamingFlowGraphBuilder::BuildEveryTimePrologue(
854 const Function& dart_function,
855 TokenPosition token_position,
856 intptr_t type_parameters_offset) {
857 Fragment F;
858 F += CheckStackOverflowInPrologue(dart_function);
859 F += DebugStepCheckInPrologue(dart_function, token_position);
860 F += SetAsyncStackTrace(dart_function);
861 F += B->InitConstantParameters();
862 return F;
863}
864
865Fragment StreamingFlowGraphBuilder::BuildFirstTimePrologue(
866 const Function& dart_function,
867 LocalVariable* first_parameter,
868 intptr_t type_parameters_offset) {
869 Fragment F;
870 F += SetupCapturedParameters(dart_function);
871 F += ShortcutForUserDefinedEquals(dart_function, first_parameter);
872 return F;
873}
874
875Fragment StreamingFlowGraphBuilder::ClearRawParameters(
876 const Function& dart_function) {
877 const ParsedFunction& pf = *flow_graph_builder_->parsed_function_;
878 Fragment code;
879 for (intptr_t i = 0; i < dart_function.NumParameters(); ++i) {
880 LocalVariable* variable = pf.ParameterVariable(i);
881
882 if (!variable->is_captured()) continue;
883
884 // Captured 'this' is immutable, so within the outer method we don't need to
885 // load it from the context. Therefore we don't reset it to null.
886 if (pf.function().HasThisParameter() && pf.has_receiver_var() &&
887 variable == pf.receiver_var()) {
888 ASSERT(i == 0);
889 continue;
890 }
891
892 variable = pf.RawParameterVariable(i);
893 code += NullConstant();
894 code += StoreLocal(TokenPosition::kNoSource, variable);
895 code += Drop();
896 }
897 return code;
898}
899
900UncheckedEntryPointStyle StreamingFlowGraphBuilder::ChooseEntryPointStyle(
901 const Function& dart_function,
902 const Fragment& implicit_type_checks,
903 const Fragment& first_time_prologue,
904 const Fragment& every_time_prologue,
905 const Fragment& type_args_handling) {
906 ASSERT(!dart_function.IsImplicitClosureFunction());
907 if (!dart_function.MayHaveUncheckedEntryPoint() ||
908 implicit_type_checks.is_empty()) {
909 return UncheckedEntryPointStyle::kNone;
910 }
911
912 // Record which entry-point was taken into a variable and test it later if
913 // either:
914 //
915 // 1. There is a non-empty PrologueBuilder-prologue.
916 //
917 // 2. There is a non-empty "first-time" prologue.
918 //
919 // 3. The "every-time" prologue has more than two instructions (DebugStepCheck
920 // and CheckStackOverflow).
921 //
922 // TODO(#34162): For regular closures we can often avoid the
923 // PrologueBuilder-prologue on non-dynamic invocations.
924 if (!PrologueBuilder::HasEmptyPrologue(dart_function) ||
925 !type_args_handling.is_empty() || !first_time_prologue.is_empty() ||
926 !(every_time_prologue.entry == every_time_prologue.current ||
927 every_time_prologue.current->previous() == every_time_prologue.entry)) {
928 return UncheckedEntryPointStyle::kSharedWithVariable;
929 }
930
931 return UncheckedEntryPointStyle::kSeparate;
932}
933
934FlowGraph* StreamingFlowGraphBuilder::BuildGraphOfFunction(
935 bool is_constructor) {
936 const Function& dart_function = parsed_function()->function();
937
938 intptr_t type_parameters_offset = 0;
939 LocalVariable* first_parameter = nullptr;
940 TokenPosition token_position = TokenPosition::kNoSource;
941 {
942 AlternativeReadingScope alt(&reader_);
943 FunctionNodeHelper function_node_helper(this);
944 function_node_helper.ReadUntilExcluding(
945 FunctionNodeHelper::kTypeParameters);
946 type_parameters_offset = ReaderOffset();
947 function_node_helper.ReadUntilExcluding(
948 FunctionNodeHelper::kPositionalParameters);
949 intptr_t list_length = ReadListLength(); // read number of positionals.
950 if (list_length > 0) {
951 intptr_t first_parameter_offset = ReaderOffset() + data_program_offset_;
952 first_parameter = LookupVariable(first_parameter_offset);
953 }
954 token_position = function_node_helper.position_;
955 }
956
957 auto graph_entry = flow_graph_builder_->graph_entry_ =
958 new (Z) GraphEntryInstr(*parsed_function(), flow_graph_builder_->osr_id_);
959
960 auto normal_entry = flow_graph_builder_->BuildFunctionEntry(graph_entry);
961 graph_entry->set_normal_entry(normal_entry);
962
963 PrologueInfo prologue_info(-1, -1);
964 BlockEntryInstr* instruction_cursor =
965 flow_graph_builder_->BuildPrologue(normal_entry, &prologue_info);
966
967 // The 'every_time_prologue' runs first and is run when resuming from yield
968 // points.
969 const Fragment every_time_prologue = BuildEveryTimePrologue(
970 dart_function, token_position, type_parameters_offset);
971
972 // The 'first_time_prologue' run after 'every_time_prologue' and is *not* run
973 // when resuming from yield points.
974 const Fragment first_time_prologue = BuildFirstTimePrologue(
975 dart_function, first_parameter, type_parameters_offset);
976
977 // TODO(#34162): We can remove the default type handling (and
978 // shorten the prologue type handling sequence) for non-dynamic invocations of
979 // regular methods.
980 const Fragment type_args_handling = TypeArgumentsHandling(dart_function);
981
982 Fragment explicit_type_checks;
983 Fragment implicit_type_checks;
984 Fragment implicit_redefinitions;
985 CheckArgumentTypesAsNecessary(dart_function, type_parameters_offset,
986 &explicit_type_checks, &implicit_type_checks,
987 &implicit_redefinitions);
988
989 // The RawParameter variables should be set to null to avoid retaining more
990 // objects than necessary during GC.
991 const Fragment body =
992 ClearRawParameters(dart_function) + B->BuildNullAssertions() +
993 BuildFunctionBody(dart_function, first_parameter, is_constructor);
994
995 auto extra_entry_point_style = ChooseEntryPointStyle(
996 dart_function, implicit_type_checks, first_time_prologue,
997 every_time_prologue, type_args_handling);
998
999 Fragment function(instruction_cursor);
1000 if (yield_continuations().is_empty()) {
1001 FunctionEntryInstr* extra_entry = nullptr;
1002 switch (extra_entry_point_style) {
1003 case UncheckedEntryPointStyle::kNone: {
1004 function += every_time_prologue + first_time_prologue +
1005 type_args_handling + implicit_type_checks +
1006 explicit_type_checks + body;
1007 break;
1008 }
1009 case UncheckedEntryPointStyle::kSeparate: {
1010 ASSERT(instruction_cursor == normal_entry);
1011 ASSERT(first_time_prologue.is_empty());
1012 ASSERT(type_args_handling.is_empty());
1013
1014 const Fragment prologue_copy = BuildEveryTimePrologue(
1015 dart_function, token_position, type_parameters_offset);
1016
1017 extra_entry = B->BuildSeparateUncheckedEntryPoint(
1018 normal_entry,
1019 /*normal_prologue=*/every_time_prologue + implicit_type_checks,
1020 /*extra_prologue=*/prologue_copy,
1021 /*shared_prologue=*/explicit_type_checks,
1022 /*body=*/body);
1023 break;
1024 }
1025 case UncheckedEntryPointStyle::kSharedWithVariable: {
1026 Fragment prologue(normal_entry, instruction_cursor);
1027 prologue += every_time_prologue;
1028 prologue += first_time_prologue;
1029 prologue += type_args_handling;
1030 prologue += explicit_type_checks;
1031 extra_entry = B->BuildSharedUncheckedEntryPoint(
1032 /*shared_prologue_linked_in=*/prologue,
1033 /*skippable_checks=*/implicit_type_checks,
1034 /*redefinitions_if_skipped=*/implicit_redefinitions,
1035 /*body=*/body);
1036 break;
1037 }
1038 }
1039 if (extra_entry != nullptr) {
1040 B->RecordUncheckedEntryPoint(graph_entry, extra_entry);
1041 }
1042 } else {
1043 // If the function's body contains any yield points, build switch statement
1044 // that selects a continuation point based on the value of :await_jump_var.
1045 ASSERT(explicit_type_checks.is_empty());
1046
1047 // If the function is generic, type_args_handling might require access to
1048 // (possibly captured) 'this' for preparing default type arguments, in which
1049 // case we can't run it before the 'first_time_prologue'.
1050 ASSERT(!dart_function.IsGeneric());
1051
1052 // TODO(#34162): We can probably ignore the implicit checks
1053 // here as well since the arguments are passed from generated code.
1054 function += every_time_prologue + type_args_handling +
1055 CompleteBodyWithYieldContinuations(first_time_prologue +
1056 implicit_type_checks + body);
1057 }
1058
1059 // When compiling for OSR, use a depth first search to find the OSR
1060 // entry and make graph entry jump to it instead of normal entry.
1061 // Catch entries are always considered reachable, even if they
1062 // become unreachable after OSR.
1063 if (flow_graph_builder_->IsCompiledForOsr()) {
1064 graph_entry->RelinkToOsrEntry(Z,
1065 flow_graph_builder_->last_used_block_id_ + 1);
1066 }
1067 return new (Z)
1068 FlowGraph(*parsed_function(), graph_entry,
1069 flow_graph_builder_->last_used_block_id_, prologue_info);
1070}
1071
1072FlowGraph* StreamingFlowGraphBuilder::BuildGraph() {
1073 ASSERT(Error::Handle(Z, H.thread()->sticky_error()).IsNull());
1074 ASSERT(flow_graph_builder_ != nullptr);
1075
1076 const Function& function = parsed_function()->function();
1077
1078 // Setup a [ActiveClassScope] and a [ActiveMemberScope] which will be used
1079 // e.g. for type translation.
1080 const Class& klass =
1081 Class::Handle(zone_, parsed_function()->function().Owner());
1082 Function& outermost_function =
1083 Function::Handle(Z, function.GetOutermostFunction());
1084
1085 ActiveClassScope active_class_scope(active_class(), &klass);
1086 ActiveMemberScope active_member(active_class(), &outermost_function);
1087 ActiveTypeParametersScope active_type_params(active_class(), function, Z);
1088
1089 if (function.is_declared_in_bytecode()) {
1090 bytecode_metadata_helper_.ParseBytecodeFunction(parsed_function());
1091
1092 switch (function.kind()) {
1093 case FunctionLayout::kImplicitClosureFunction:
1094 return B->BuildGraphOfImplicitClosureFunction(function);
1095 case FunctionLayout::kImplicitGetter:
1096 case FunctionLayout::kImplicitSetter:
1097 return B->BuildGraphOfFieldAccessor(function);
1098 case FunctionLayout::kImplicitStaticGetter: {
1099 if (IsStaticFieldGetterGeneratedAsInitializer(function, Z)) {
1100 break;
1101 }
1102 return B->BuildGraphOfFieldAccessor(function);
1103 }
1104 case FunctionLayout::kDynamicInvocationForwarder:
1105 return B->BuildGraphOfDynamicInvocationForwarder(function);
1106 case FunctionLayout::kMethodExtractor:
1107 return B->BuildGraphOfMethodExtractor(function);
1108 case FunctionLayout::kNoSuchMethodDispatcher:
1109 return B->BuildGraphOfNoSuchMethodDispatcher(function);
1110 default:
1111 break;
1112 }
1113
1114 ASSERT(function.HasBytecode());
1115
1116 BytecodeFlowGraphBuilder bytecode_compiler(
1117 flow_graph_builder_, parsed_function(),
1118 &(flow_graph_builder_->ic_data_array_));
1119
1120 if (B->IsRecognizedMethodForFlowGraph(function)) {
1121 bytecode_compiler.CreateParameterVariables();
1122 return B->BuildGraphOfRecognizedMethod(function);
1123 }
1124
1125 return bytecode_compiler.BuildGraph();
1126 }
1127
1128 // Certain special functions could have a VM-internal bytecode
1129 // attached to them.
1130 ASSERT((!function.HasBytecode()) ||
1131 (function.kind() == FunctionLayout::kImplicitGetter) ||
1132 (function.kind() == FunctionLayout::kImplicitSetter) ||
1133 (function.kind() == FunctionLayout::kImplicitStaticGetter) ||
1134 (function.kind() == FunctionLayout::kMethodExtractor) ||
1135 (function.kind() == FunctionLayout::kInvokeFieldDispatcher) ||
1136 (function.kind() == FunctionLayout::kNoSuchMethodDispatcher));
1137
1138 ParseKernelASTFunction();
1139
1140 switch (function.kind()) {
1141 case FunctionLayout::kRegularFunction:
1142 case FunctionLayout::kGetterFunction:
1143 case FunctionLayout::kSetterFunction:
1144 case FunctionLayout::kClosureFunction:
1145 case FunctionLayout::kConstructor: {
1146 if (B->IsRecognizedMethodForFlowGraph(function)) {
1147 return B->BuildGraphOfRecognizedMethod(function);
1148 }
1149 return BuildGraphOfFunction(function.IsGenerativeConstructor());
1150 }
1151 case FunctionLayout::kImplicitGetter:
1152 case FunctionLayout::kImplicitStaticGetter:
1153 case FunctionLayout::kImplicitSetter: {
1154 const Field& field = Field::Handle(Z, function.accessor_field());
1155 if (field.is_const() && field.IsUninitialized()) {
1156 EvaluateConstFieldValue(field);
1157 }
1158 return B->BuildGraphOfFieldAccessor(function);
1159 }
1160 case FunctionLayout::kFieldInitializer:
1161 return BuildGraphOfFieldInitializer();
1162 case FunctionLayout::kDynamicInvocationForwarder:
1163 return B->BuildGraphOfDynamicInvocationForwarder(function);
1164 case FunctionLayout::kMethodExtractor:
1165 return flow_graph_builder_->BuildGraphOfMethodExtractor(function);
1166 case FunctionLayout::kNoSuchMethodDispatcher:
1167 return flow_graph_builder_->BuildGraphOfNoSuchMethodDispatcher(function);
1168 case FunctionLayout::kInvokeFieldDispatcher:
1169 return flow_graph_builder_->BuildGraphOfInvokeFieldDispatcher(function);
1170 case FunctionLayout::kImplicitClosureFunction:
1171 return flow_graph_builder_->BuildGraphOfImplicitClosureFunction(function);
1172 case FunctionLayout::kFfiTrampoline:
1173 return flow_graph_builder_->BuildGraphOfFfiTrampoline(function);
1174 case FunctionLayout::kSignatureFunction:
1175 case FunctionLayout::kIrregexpFunction:
1176 break;
1177 }
1178 UNREACHABLE();
1179 return NULL;
1180}
1181
1182void StreamingFlowGraphBuilder::ParseKernelASTFunction() {
1183 const Function& function = parsed_function()->function();
1184
1185 const intptr_t kernel_offset = function.kernel_offset();
1186 ASSERT(kernel_offset >= 0);
1187
1188 SetOffset(kernel_offset);
1189
1190 // Mark forwarding stubs.
1191 switch (function.kind()) {
1192 case FunctionLayout::kRegularFunction:
1193 case FunctionLayout::kImplicitClosureFunction:
1194 case FunctionLayout::kGetterFunction:
1195 case FunctionLayout::kSetterFunction:
1196 case FunctionLayout::kClosureFunction:
1197 case FunctionLayout::kConstructor:
1198 case FunctionLayout::kDynamicInvocationForwarder:
1199 ReadForwardingStubTarget(function);
1200 break;
1201 default:
1202 break;
1203 }
1204
1205 set_scopes(parsed_function()->EnsureKernelScopes());
1206
1207 switch (function.kind()) {
1208 case FunctionLayout::kRegularFunction:
1209 case FunctionLayout::kGetterFunction:
1210 case FunctionLayout::kSetterFunction:
1211 case FunctionLayout::kClosureFunction:
1212 case FunctionLayout::kConstructor:
1213 case FunctionLayout::kImplicitClosureFunction:
1214 ReadUntilFunctionNode();
1215 SetupDefaultParameterValues();
1216 ReadDefaultFunctionTypeArguments(function);
1217 break;
1218 case FunctionLayout::kImplicitGetter:
1219 case FunctionLayout::kImplicitStaticGetter:
1220 case FunctionLayout::kImplicitSetter:
1221 case FunctionLayout::kFieldInitializer:
1222 case FunctionLayout::kMethodExtractor:
1223 case FunctionLayout::kNoSuchMethodDispatcher:
1224 case FunctionLayout::kInvokeFieldDispatcher:
1225 case FunctionLayout::kFfiTrampoline:
1226 break;
1227 case FunctionLayout::kDynamicInvocationForwarder:
1228 if (PeekTag() != kField) {
1229 ReadUntilFunctionNode();
1230 SetupDefaultParameterValues();
1231 ReadDefaultFunctionTypeArguments(function);
1232 }
1233 break;
1234 case FunctionLayout::kSignatureFunction:
1235 case FunctionLayout::kIrregexpFunction:
1236 UNREACHABLE();
1237 break;
1238 }
1239}
1240
1241void StreamingFlowGraphBuilder::ReadForwardingStubTarget(
1242 const Function& function) {
1243 if (PeekTag() == kProcedure) {
1244 AlternativeReadingScope alt(&reader_);
1245 ProcedureHelper procedure_helper(this);
1246 procedure_helper.ReadUntilExcluding(ProcedureHelper::kFunction);
1247 if (procedure_helper.IsForwardingStub() && !procedure_helper.IsAbstract()) {
1248 const NameIndex target_name =
1249 procedure_helper.forwarding_stub_super_target_;
1250 ASSERT(target_name != NameIndex::kInvalidName);
1251 const String& name = function.IsSetterFunction()
1252 ? H.DartSetterName(target_name)
1253 : H.DartProcedureName(target_name);
1254 const Function* forwarding_target =
1255 &Function::ZoneHandle(Z, H.LookupMethodByMember(target_name, name));
1256 ASSERT(!forwarding_target->IsNull());
1257 parsed_function()->MarkForwardingStub(forwarding_target);
1258 }
1259 }
1260}
1261
1262Fragment StreamingFlowGraphBuilder::BuildStatementAt(intptr_t kernel_offset) {
1263 SetOffset(kernel_offset);
1264 return BuildStatement(); // read statement.
1265}
1266
1267Fragment StreamingFlowGraphBuilder::BuildExpression(TokenPosition* position) {
1268 uint8_t payload = 0;
1269 Tag tag = ReadTag(&payload); // read tag.
1270 switch (tag) {
1271 case kInvalidExpression:
1272 return BuildInvalidExpression(position);
1273 case kVariableGet:
1274 return BuildVariableGet(position);
1275 case kSpecializedVariableGet:
1276 return BuildVariableGet(payload, position);
1277 case kVariableSet:
1278 return BuildVariableSet(position);
1279 case kSpecializedVariableSet:
1280 return BuildVariableSet(payload, position);
1281 case kPropertyGet:
1282 return BuildPropertyGet(position);
1283 case kPropertySet:
1284 return BuildPropertySet(position);
1285 case kDirectPropertyGet:
1286 return BuildDirectPropertyGet(position);
1287 case kDirectPropertySet:
1288 return BuildDirectPropertySet(position);
1289 case kSuperPropertyGet:
1290 return BuildSuperPropertyGet(position);
1291 case kSuperPropertySet:
1292 return BuildSuperPropertySet(position);
1293 case kStaticGet:
1294 return BuildStaticGet(position);
1295 case kStaticSet:
1296 return BuildStaticSet(position);
1297 case kMethodInvocation:
1298 return BuildMethodInvocation(position);
1299 case kSuperMethodInvocation:
1300 return BuildSuperMethodInvocation(position);
1301 case kDirectMethodInvocation:
1302 return BuildDirectMethodInvocation(position);
1303 case kStaticInvocation:
1304 return BuildStaticInvocation(position);
1305 case kConstructorInvocation:
1306 return BuildConstructorInvocation(position);
1307 case kNot:
1308 return BuildNot(position);
1309 case kNullCheck:
1310 return BuildNullCheck(position);
1311 case kLogicalExpression:
1312 return BuildLogicalExpression(position);
1313 case kConditionalExpression:
1314 return BuildConditionalExpression(position);
1315 case kStringConcatenation:
1316 return BuildStringConcatenation(position);
1317 case kIsExpression:
1318 return BuildIsExpression(position);
1319 case kAsExpression:
1320 return BuildAsExpression(position);
1321 case kTypeLiteral:
1322 return BuildTypeLiteral(position);
1323 case kThisExpression:
1324 return BuildThisExpression(position);
1325 case kRethrow:
1326 return BuildRethrow(position);
1327 case kThrow:
1328 return BuildThrow(position);
1329 case kListLiteral:
1330 return BuildListLiteral(position);
1331 case kSetLiteral:
1332 // Set literals are currently desugared in the frontend and will not
1333 // reach the VM. See http://dartbug.com/35124 for discussion.
1334 UNREACHABLE();
1335 break;
1336 case kMapLiteral:
1337 return BuildMapLiteral(position);
1338 case kFunctionExpression:
1339 return BuildFunctionExpression();
1340 case kLet:
1341 return BuildLet(position);
1342 case kBlockExpression:
1343 return BuildBlockExpression();
1344 case kBigIntLiteral:
1345 return BuildBigIntLiteral(position);
1346 case kStringLiteral:
1347 return BuildStringLiteral(position);
1348 case kSpecializedIntLiteral:
1349 return BuildIntLiteral(payload, position);
1350 case kNegativeIntLiteral:
1351 return BuildIntLiteral(true, position);
1352 case kPositiveIntLiteral:
1353 return BuildIntLiteral(false, position);
1354 case kDoubleLiteral:
1355 return BuildDoubleLiteral(position);
1356 case kTrueLiteral:
1357 return BuildBoolLiteral(true, position);
1358 case kFalseLiteral:
1359 return BuildBoolLiteral(false, position);
1360 case kNullLiteral:
1361 return BuildNullLiteral(position);
1362 case kConstantExpression:
1363 return BuildConstantExpression(position, tag);
1364 case kInstantiation:
1365 return BuildPartialTearoffInstantiation(position);
1366 case kLoadLibrary:
1367 return BuildLibraryPrefixAction(position, Symbols::LoadLibrary());
1368 case kCheckLibraryIsLoaded:
1369 return BuildLibraryPrefixAction(position, Symbols::CheckLoaded());
1370 case kConstStaticInvocation:
1371 case kConstConstructorInvocation:
1372 case kConstListLiteral:
1373 case kConstSetLiteral:
1374 case kConstMapLiteral:
1375 case kSymbolLiteral:
1376 // Const invocations and const literals are removed by the
1377 // constant evaluator.
1378 case kListConcatenation:
1379 case kSetConcatenation:
1380 case kMapConcatenation:
1381 case kInstanceCreation:
1382 case kFileUriExpression:
1383 // Collection concatenation, instance creation operations and
1384 // in-expression URI changes are internal to the front end and
1385 // removed by the constant evaluator.
1386 default:
1387 ReportUnexpectedTag("expression", tag);
1388 UNREACHABLE();
1389 }
1390
1391 return Fragment();
1392}
1393
1394Fragment StreamingFlowGraphBuilder::BuildStatement() {
1395 Tag tag = ReadTag(); // read tag.
1396 switch (tag) {
1397 case kExpressionStatement:
1398 return BuildExpressionStatement();
1399 case kBlock:
1400 return BuildBlock();
1401 case kEmptyStatement:
1402 return BuildEmptyStatement();
1403 case kAssertBlock:
1404 return BuildAssertBlock();
1405 case kAssertStatement:
1406 return BuildAssertStatement();
1407 case kLabeledStatement:
1408 return BuildLabeledStatement();
1409 case kBreakStatement:
1410 return BuildBreakStatement();
1411 case kWhileStatement:
1412 return BuildWhileStatement();
1413 case kDoStatement:
1414 return BuildDoStatement();
1415 case kForStatement:
1416 return BuildForStatement();
1417 case kForInStatement:
1418 return BuildForInStatement(false);
1419 case kAsyncForInStatement:
1420 return BuildForInStatement(true);
1421 case kSwitchStatement:
1422 return BuildSwitchStatement();
1423 case kContinueSwitchStatement:
1424 return BuildContinueSwitchStatement();
1425 case kIfStatement:
1426 return BuildIfStatement();
1427 case kReturnStatement:
1428 return BuildReturnStatement();
1429 case kTryCatch:
1430 return BuildTryCatch();
1431 case kTryFinally:
1432 return BuildTryFinally();
1433 case kYieldStatement:
1434 return BuildYieldStatement();
1435 case kVariableDeclaration:
1436 return BuildVariableDeclaration();
1437 case kFunctionDeclaration:
1438 return BuildFunctionDeclaration();
1439 default:
1440 ReportUnexpectedTag("statement", tag);
1441 UNREACHABLE();
1442 }
1443 return Fragment();
1444}
1445
1446void StreamingFlowGraphBuilder::ReportUnexpectedTag(const char* variant,
1447 Tag tag) {
1448 if ((flow_graph_builder_ == NULL) || (parsed_function() == NULL)) {
1449 KernelReaderHelper::ReportUnexpectedTag(variant, tag);
1450 } else {
1451 H.ReportError(script_, TokenPosition::kNoSource,
1452 "Unexpected tag %d (%s) in %s, expected %s", tag,
1453 Reader::TagName(tag),
1454 parsed_function()->function().ToQualifiedCString(), variant);
1455 }
1456}
1457
1458Tag KernelReaderHelper::ReadTag(uint8_t* payload) {
1459 return reader_.ReadTag(payload);
1460}
1461
1462Tag KernelReaderHelper::PeekTag(uint8_t* payload) {
1463 return reader_.PeekTag(payload);
1464}
1465
1466Nullability KernelReaderHelper::ReadNullability() {
1467 return reader_.ReadNullability();
1468}
1469
1470Variance KernelReaderHelper::ReadVariance() {
1471 if (translation_helper_.info().kernel_binary_version() >= 34) {
1472 return reader_.ReadVariance();
1473 }
1474 return kCovariant;
1475}
1476
1477void StreamingFlowGraphBuilder::loop_depth_inc() {
1478 ++flow_graph_builder_->loop_depth_;
1479}
1480
1481void StreamingFlowGraphBuilder::loop_depth_dec() {
1482 --flow_graph_builder_->loop_depth_;
1483}
1484
1485intptr_t StreamingFlowGraphBuilder::for_in_depth() {
1486 return flow_graph_builder_->for_in_depth_;
1487}
1488
1489void StreamingFlowGraphBuilder::for_in_depth_inc() {
1490 ++flow_graph_builder_->for_in_depth_;
1491}
1492
1493void StreamingFlowGraphBuilder::for_in_depth_dec() {
1494 --flow_graph_builder_->for_in_depth_;
1495}
1496
1497void StreamingFlowGraphBuilder::catch_depth_inc() {
1498 ++flow_graph_builder_->catch_depth_;
1499}
1500
1501void StreamingFlowGraphBuilder::catch_depth_dec() {
1502 --flow_graph_builder_->catch_depth_;
1503}
1504
1505void StreamingFlowGraphBuilder::try_depth_inc() {
1506 ++flow_graph_builder_->try_depth_;
1507}
1508
1509void StreamingFlowGraphBuilder::try_depth_dec() {
1510 --flow_graph_builder_->try_depth_;
1511}
1512
1513intptr_t StreamingFlowGraphBuilder::block_expression_depth() {
1514 return flow_graph_builder_->block_expression_depth_;
1515}
1516
1517void StreamingFlowGraphBuilder::block_expression_depth_inc() {
1518 ++flow_graph_builder_->block_expression_depth_;
1519}
1520
1521void StreamingFlowGraphBuilder::block_expression_depth_dec() {
1522 --flow_graph_builder_->block_expression_depth_;
1523}
1524
1525intptr_t StreamingFlowGraphBuilder::CurrentTryIndex() {
1526 return flow_graph_builder_->CurrentTryIndex();
1527}
1528
1529intptr_t StreamingFlowGraphBuilder::AllocateTryIndex() {
1530 return flow_graph_builder_->AllocateTryIndex();
1531}
1532
1533LocalVariable* StreamingFlowGraphBuilder::CurrentException() {
1534 return flow_graph_builder_->CurrentException();
1535}
1536
1537LocalVariable* StreamingFlowGraphBuilder::CurrentStackTrace() {
1538 return flow_graph_builder_->CurrentStackTrace();
1539}
1540
1541CatchBlock* StreamingFlowGraphBuilder::catch_block() {
1542 return flow_graph_builder_->catch_block_;
1543}
1544
1545ActiveClass* StreamingFlowGraphBuilder::active_class() {
1546 return active_class_;
1547}
1548
1549ScopeBuildingResult* StreamingFlowGraphBuilder::scopes() {
1550 return flow_graph_builder_->scopes_;
1551}
1552
1553void StreamingFlowGraphBuilder::set_scopes(ScopeBuildingResult* scope) {
1554 flow_graph_builder_->scopes_ = scope;
1555}
1556
1557ParsedFunction* StreamingFlowGraphBuilder::parsed_function() {
1558 return flow_graph_builder_->parsed_function_;
1559}
1560
1561TryFinallyBlock* StreamingFlowGraphBuilder::try_finally_block() {
1562 return flow_graph_builder_->try_finally_block_;
1563}
1564
1565SwitchBlock* StreamingFlowGraphBuilder::switch_block() {
1566 return flow_graph_builder_->switch_block_;
1567}
1568
1569BreakableBlock* StreamingFlowGraphBuilder::breakable_block() {
1570 return flow_graph_builder_->breakable_block_;
1571}
1572
1573GrowableArray<YieldContinuation>&
1574StreamingFlowGraphBuilder::yield_continuations() {
1575 return flow_graph_builder_->yield_continuations_;
1576}
1577
1578Value* StreamingFlowGraphBuilder::stack() {
1579 return flow_graph_builder_->stack_;
1580}
1581
1582void StreamingFlowGraphBuilder::Push(Definition* definition) {
1583 flow_graph_builder_->Push(definition);
1584}
1585
1586Value* StreamingFlowGraphBuilder::Pop() {
1587 return flow_graph_builder_->Pop();
1588}
1589
1590Tag StreamingFlowGraphBuilder::PeekArgumentsFirstPositionalTag() {
1591 // read parts of arguments, then go back to before doing so.
1592 AlternativeReadingScope alt(&reader_);
1593 ReadUInt(); // read number of arguments.
1594
1595 SkipListOfDartTypes(); // Read list of types.
1596
1597 // List of positional.
1598 intptr_t list_length = ReadListLength(); // read list length.
1599 if (list_length > 0) {
1600 return ReadTag(); // read first tag.
1601 }
1602
1603 UNREACHABLE();
1604 return kNothing;
1605}
1606
1607const TypeArguments& StreamingFlowGraphBuilder::PeekArgumentsInstantiatedType(
1608 const Class& klass) {
1609 // read parts of arguments, then go back to before doing so.
1610 AlternativeReadingScope alt(&reader_);
1611 ReadUInt(); // read argument count.
1612 intptr_t list_length = ReadListLength(); // read types list length.
1613 return T.BuildInstantiatedTypeArguments(klass, list_length); // read types.
1614}
1615
1616intptr_t StreamingFlowGraphBuilder::PeekArgumentsCount() {
1617 return PeekUInt();
1618}
1619
1620LocalVariable* StreamingFlowGraphBuilder::LookupVariable(
1621 intptr_t kernel_offset) {
1622 return flow_graph_builder_->LookupVariable(kernel_offset);
1623}
1624
1625LocalVariable* StreamingFlowGraphBuilder::MakeTemporary() {
1626 return flow_graph_builder_->MakeTemporary();
1627}
1628
1629Function& StreamingFlowGraphBuilder::FindMatchingFunction(
1630 const Class& klass,
1631 const String& name,
1632 int type_args_len,
1633 int argument_count,
1634 const Array& argument_names) {
1635 // Search the superclass chain for the selector.
1636 ArgumentsDescriptor args_desc(
1637 Array::Handle(Z, ArgumentsDescriptor::NewBoxed(
1638 type_args_len, argument_count, argument_names)));
1639 Function& function =
1640 Function::Handle(Z, Resolver::ResolveDynamicForReceiverClassAllowPrivate(
1641 klass, name, args_desc, /*allow_add=*/false));
1642 return function;
1643}
1644
1645bool StreamingFlowGraphBuilder::NeedsDebugStepCheck(const Function& function,
1646 TokenPosition position) {
1647 return flow_graph_builder_->NeedsDebugStepCheck(function, position);
1648}
1649
1650bool StreamingFlowGraphBuilder::NeedsDebugStepCheck(Value* value,
1651 TokenPosition position) {
1652 return flow_graph_builder_->NeedsDebugStepCheck(value, position);
1653}
1654
1655void StreamingFlowGraphBuilder::InlineBailout(const char* reason) {
1656 flow_graph_builder_->InlineBailout(reason);
1657}
1658
1659Fragment StreamingFlowGraphBuilder::DebugStepCheck(TokenPosition position) {
1660 return flow_graph_builder_->DebugStepCheck(position);
1661}
1662
1663Fragment StreamingFlowGraphBuilder::LoadLocal(LocalVariable* variable) {
1664 return flow_graph_builder_->LoadLocal(variable);
1665}
1666
1667Fragment StreamingFlowGraphBuilder::Return(TokenPosition position,
1668 intptr_t yield_index) {
1669 return flow_graph_builder_->Return(position, /*omit_result_type_check=*/false,
1670 yield_index);
1671}
1672
1673Fragment StreamingFlowGraphBuilder::EvaluateAssertion() {
1674 return flow_graph_builder_->EvaluateAssertion();
1675}
1676
1677Fragment StreamingFlowGraphBuilder::RethrowException(TokenPosition position,
1678 int catch_try_index) {
1679 return flow_graph_builder_->RethrowException(position, catch_try_index);
1680}
1681
1682Fragment StreamingFlowGraphBuilder::ThrowNoSuchMethodError(
1683 const Function& target) {
1684 return flow_graph_builder_->ThrowNoSuchMethodError(target);
1685}
1686
1687Fragment StreamingFlowGraphBuilder::Constant(const Object& value) {
1688 return flow_graph_builder_->Constant(value);
1689}
1690
1691Fragment StreamingFlowGraphBuilder::IntConstant(int64_t value) {
1692 return flow_graph_builder_->IntConstant(value);
1693}
1694
1695Fragment StreamingFlowGraphBuilder::LoadStaticField(const Field& field,
1696 bool calls_initializer) {
1697 return flow_graph_builder_->LoadStaticField(field, calls_initializer);
1698}
1699
1700Fragment StreamingFlowGraphBuilder::RedefinitionWithType(
1701 const AbstractType& type) {
1702 return flow_graph_builder_->RedefinitionWithType(type);
1703}
1704
1705Fragment StreamingFlowGraphBuilder::CheckNull(
1706 TokenPosition position,
1707 LocalVariable* receiver,
1708 const String& function_name,
1709 bool clear_the_temp /* = true */) {
1710 return flow_graph_builder_->CheckNull(position, receiver, function_name,
1711 clear_the_temp);
1712}
1713
1714Fragment StreamingFlowGraphBuilder::StaticCall(TokenPosition position,
1715 const Function& target,
1716 intptr_t argument_count,
1717 ICData::RebindRule rebind_rule) {
1718 if (!target.AreValidArgumentCounts(0, argument_count, 0, nullptr)) {
1719 return flow_graph_builder_->ThrowNoSuchMethodError(target);
1720 }
1721 return flow_graph_builder_->StaticCall(position, target, argument_count,
1722 rebind_rule);
1723}
1724
1725Fragment StreamingFlowGraphBuilder::StaticCall(
1726 TokenPosition position,
1727 const Function& target,
1728 intptr_t argument_count,
1729 const Array& argument_names,
1730 ICData::RebindRule rebind_rule,
1731 const InferredTypeMetadata* result_type,
1732 intptr_t type_args_count,
1733 bool use_unchecked_entry) {
1734 if (!target.AreValidArguments(type_args_count, argument_count, argument_names,
1735 nullptr)) {
1736 return flow_graph_builder_->ThrowNoSuchMethodError(target);
1737 }
1738 return flow_graph_builder_->StaticCall(
1739 position, target, argument_count, argument_names, rebind_rule,
1740 result_type, type_args_count, use_unchecked_entry);
1741}
1742
1743Fragment StreamingFlowGraphBuilder::InstanceCall(
1744 TokenPosition position,
1745 const String& name,
1746 Token::Kind kind,
1747 intptr_t argument_count,
1748 intptr_t checked_argument_count) {
1749 const intptr_t kTypeArgsLen = 0;
1750 return flow_graph_builder_->InstanceCall(position, name, kind, kTypeArgsLen,
1751 argument_count, Array::null_array(),
1752 checked_argument_count);
1753}
1754
1755Fragment StreamingFlowGraphBuilder::InstanceCall(
1756 TokenPosition position,
1757 const String& name,
1758 Token::Kind kind,
1759 intptr_t type_args_len,
1760 intptr_t argument_count,
1761 const Array& argument_names,
1762 intptr_t checked_argument_count,
1763 const Function& interface_target,
1764 const Function& tearoff_interface_target,
1765 const InferredTypeMetadata* result_type,
1766 bool use_unchecked_entry,
1767 const CallSiteAttributesMetadata* call_site_attrs,
1768 bool receiver_is_not_smi) {
1769 return flow_graph_builder_->InstanceCall(
1770 position, name, kind, type_args_len, argument_count, argument_names,
1771 checked_argument_count, interface_target, tearoff_interface_target,
1772 result_type, use_unchecked_entry, call_site_attrs, receiver_is_not_smi);
1773}
1774
1775Fragment StreamingFlowGraphBuilder::ThrowException(TokenPosition position) {
1776 return flow_graph_builder_->ThrowException(position);
1777}
1778
1779Fragment StreamingFlowGraphBuilder::BooleanNegate() {
1780 return flow_graph_builder_->BooleanNegate();
1781}
1782
1783Fragment StreamingFlowGraphBuilder::TranslateInstantiatedTypeArguments(
1784 const TypeArguments& type_arguments) {
1785 return flow_graph_builder_->TranslateInstantiatedTypeArguments(
1786 type_arguments);
1787}
1788
1789Fragment StreamingFlowGraphBuilder::StrictCompare(TokenPosition position,
1790 Token::Kind kind,
1791 bool number_check) {
1792 return flow_graph_builder_->StrictCompare(position, kind, number_check);
1793}
1794
1795Fragment StreamingFlowGraphBuilder::AllocateObject(TokenPosition position,
1796 const Class& klass,
1797 intptr_t argument_count) {
1798 return flow_graph_builder_->AllocateObject(position, klass, argument_count);
1799}
1800
1801Fragment StreamingFlowGraphBuilder::AllocateContext(
1802 const ZoneGrowableArray<const Slot*>& context_slots) {
1803 return flow_graph_builder_->AllocateContext(context_slots);
1804}
1805
1806Fragment StreamingFlowGraphBuilder::LoadNativeField(const Slot& field) {
1807 return flow_graph_builder_->LoadNativeField(field);
1808}
1809
1810Fragment StreamingFlowGraphBuilder::StoreLocal(TokenPosition position,
1811 LocalVariable* variable) {
1812 return flow_graph_builder_->StoreLocal(position, variable);
1813}
1814
1815Fragment StreamingFlowGraphBuilder::StoreStaticField(TokenPosition position,
1816 const Field& field) {
1817 return flow_graph_builder_->StoreStaticField(position, field);
1818}
1819
1820Fragment StreamingFlowGraphBuilder::StringInterpolate(TokenPosition position) {
1821 return flow_graph_builder_->StringInterpolate(position);
1822}
1823
1824Fragment StreamingFlowGraphBuilder::StringInterpolateSingle(
1825 TokenPosition position) {
1826 return flow_graph_builder_->StringInterpolateSingle(position);
1827}
1828
1829Fragment StreamingFlowGraphBuilder::ThrowTypeError() {
1830 return flow_graph_builder_->ThrowTypeError();
1831}
1832
1833Fragment StreamingFlowGraphBuilder::LoadInstantiatorTypeArguments() {
1834 return flow_graph_builder_->LoadInstantiatorTypeArguments();
1835}
1836
1837Fragment StreamingFlowGraphBuilder::LoadFunctionTypeArguments() {
1838 return flow_graph_builder_->LoadFunctionTypeArguments();
1839}
1840
1841Fragment StreamingFlowGraphBuilder::InstantiateType(const AbstractType& type) {
1842 return flow_graph_builder_->InstantiateType(type);
1843}
1844
1845Fragment StreamingFlowGraphBuilder::CreateArray() {
1846 return flow_graph_builder_->CreateArray();
1847}
1848
1849Fragment StreamingFlowGraphBuilder::StoreIndexed(intptr_t class_id) {
1850 return flow_graph_builder_->StoreIndexed(class_id);
1851}
1852
1853Fragment StreamingFlowGraphBuilder::CheckStackOverflow(TokenPosition position) {
1854 return flow_graph_builder_->CheckStackOverflow(
1855 position, flow_graph_builder_->GetStackDepth(),
1856 flow_graph_builder_->loop_depth_);
1857}
1858
1859Fragment StreamingFlowGraphBuilder::CloneContext(
1860 const ZoneGrowableArray<const Slot*>& context_slots) {
1861 return flow_graph_builder_->CloneContext(context_slots);
1862}
1863
1864Fragment StreamingFlowGraphBuilder::TranslateFinallyFinalizers(
1865 TryFinallyBlock* outer_finally,
1866 intptr_t target_context_depth) {
1867 // TranslateFinallyFinalizers can move the readers offset.
1868 // Save the current position and restore it afterwards.
1869 AlternativeReadingScope alt(&reader_);
1870
1871 // Save context.
1872 TryFinallyBlock* const saved_finally_block = B->try_finally_block_;
1873 TryCatchBlock* const saved_try_catch_block = B->CurrentTryCatchBlock();
1874 const intptr_t saved_context_depth = B->context_depth_;
1875 const ProgramState state(B->breakable_block_, B->switch_block_,
1876 B->loop_depth_, B->for_in_depth_, B->try_depth_,
1877 B->catch_depth_, B->block_expression_depth_);
1878
1879 Fragment instructions;
1880
1881 // While translating the body of a finalizer we need to set the try-finally
1882 // block which is active when translating the body.
1883 while (B->try_finally_block_ != outer_finally) {
1884 ASSERT(B->try_finally_block_ != nullptr);
1885 // Adjust program context to finalizer's position.
1886 B->try_finally_block_->state().assignTo(B);
1887
1888 // Potentially restore the context to what is expected for the finally
1889 // block.
1890 instructions += B->AdjustContextTo(B->try_finally_block_->context_depth());
1891
1892 // The to-be-translated finalizer has to have the correct try-index (namely
1893 // the one outside the try-finally block).
1894 bool changed_try_index = false;
1895 intptr_t target_try_index = B->try_finally_block_->try_index();
1896 while (B->CurrentTryIndex() != target_try_index) {
1897 B->SetCurrentTryCatchBlock(B->CurrentTryCatchBlock()->outer());
1898 changed_try_index = true;
1899 }
1900 if (changed_try_index) {
1901 JoinEntryInstr* entry = BuildJoinEntry();
1902 instructions += Goto(entry);
1903 instructions = Fragment(instructions.entry, entry);
1904 }
1905
1906 intptr_t finalizer_kernel_offset =
1907 B->try_finally_block_->finalizer_kernel_offset();
1908 B->try_finally_block_ = B->try_finally_block_->outer();
1909 instructions += BuildStatementAt(finalizer_kernel_offset);
1910
1911 // We only need to make sure that if the finalizer ended normally, we
1912 // continue towards the next outer try-finally.
1913 if (!instructions.is_open()) break;
1914 }
1915
1916 if (instructions.is_open() && target_context_depth != -1) {
1917 // A target context depth of -1 indicates that the code after this
1918 // will not care about the context chain so we can leave it any way we
1919 // want after the last finalizer. That is used when returning.
1920 instructions += B->AdjustContextTo(target_context_depth);
1921 }
1922
1923 // Restore.
1924 B->try_finally_block_ = saved_finally_block;
1925 B->SetCurrentTryCatchBlock(saved_try_catch_block);
1926 B->context_depth_ = saved_context_depth;
1927 state.assignTo(B);
1928
1929 return instructions;
1930}
1931
1932Fragment StreamingFlowGraphBuilder::BranchIfTrue(
1933 TargetEntryInstr** then_entry,
1934 TargetEntryInstr** otherwise_entry,
1935 bool negate) {
1936 return flow_graph_builder_->BranchIfTrue(then_entry, otherwise_entry, negate);
1937}
1938
1939Fragment StreamingFlowGraphBuilder::BranchIfEqual(
1940 TargetEntryInstr** then_entry,
1941 TargetEntryInstr** otherwise_entry,
1942 bool negate) {
1943 return flow_graph_builder_->BranchIfEqual(then_entry, otherwise_entry,
1944 negate);
1945}
1946
1947Fragment StreamingFlowGraphBuilder::BranchIfNull(
1948 TargetEntryInstr** then_entry,
1949 TargetEntryInstr** otherwise_entry,
1950 bool negate) {
1951 return flow_graph_builder_->BranchIfNull(then_entry, otherwise_entry, negate);
1952}
1953
1954Fragment StreamingFlowGraphBuilder::CatchBlockEntry(const Array& handler_types,
1955 intptr_t handler_index,
1956 bool needs_stacktrace,
1957 bool is_synthesized) {
1958 return flow_graph_builder_->CatchBlockEntry(handler_types, handler_index,
1959 needs_stacktrace, is_synthesized);
1960}
1961
1962Fragment StreamingFlowGraphBuilder::TryCatch(int try_handler_index) {
1963 return flow_graph_builder_->TryCatch(try_handler_index);
1964}
1965
1966Fragment StreamingFlowGraphBuilder::Drop() {
1967 return flow_graph_builder_->Drop();
1968}
1969
1970Fragment StreamingFlowGraphBuilder::DropTempsPreserveTop(
1971 intptr_t num_temps_to_drop) {
1972 return flow_graph_builder_->DropTempsPreserveTop(num_temps_to_drop);
1973}
1974
1975Fragment StreamingFlowGraphBuilder::MakeTemp() {
1976 return flow_graph_builder_->MakeTemp();
1977}
1978
1979Fragment StreamingFlowGraphBuilder::NullConstant() {
1980 return flow_graph_builder_->NullConstant();
1981}
1982
1983JoinEntryInstr* StreamingFlowGraphBuilder::BuildJoinEntry() {
1984 return flow_graph_builder_->BuildJoinEntry();
1985}
1986
1987JoinEntryInstr* StreamingFlowGraphBuilder::BuildJoinEntry(intptr_t try_index) {
1988 return flow_graph_builder_->BuildJoinEntry(try_index);
1989}
1990
1991Fragment StreamingFlowGraphBuilder::Goto(JoinEntryInstr* destination) {
1992 return flow_graph_builder_->Goto(destination);
1993}
1994
1995Fragment StreamingFlowGraphBuilder::BuildImplicitClosureCreation(
1996 const Function& target) {
1997 return flow_graph_builder_->BuildImplicitClosureCreation(target);
1998}
1999
2000Fragment StreamingFlowGraphBuilder::CheckBoolean(TokenPosition position) {
2001 return flow_graph_builder_->CheckBoolean(position);
2002}
2003
2004Fragment StreamingFlowGraphBuilder::CheckArgumentType(
2005 LocalVariable* variable,
2006 const AbstractType& type) {
2007 return flow_graph_builder_->CheckAssignable(
2008 type, variable->name(), AssertAssignableInstr::kParameterCheck);
2009}
2010
2011Fragment StreamingFlowGraphBuilder::EnterScope(
2012 intptr_t kernel_offset,
2013 const LocalScope** scope /* = nullptr */) {
2014 return flow_graph_builder_->EnterScope(kernel_offset, scope);
2015}
2016
2017Fragment StreamingFlowGraphBuilder::ExitScope(intptr_t kernel_offset) {
2018 return flow_graph_builder_->ExitScope(kernel_offset);
2019}
2020
2021TestFragment StreamingFlowGraphBuilder::TranslateConditionForControl() {
2022 // Skip all negations and go directly to the expression.
2023 bool negate = false;
2024 while (PeekTag() == kNot) {
2025 SkipBytes(1);
2026 negate = !negate;
2027 }
2028
2029 TestFragment result;
2030 if (PeekTag() == kLogicalExpression) {
2031 // Handle '&&' and '||' operators specially to implement short circuit
2032 // evaluation.
2033 SkipBytes(1); // tag.
2034
2035 TestFragment left = TranslateConditionForControl();
2036 LogicalOperator op = static_cast<LogicalOperator>(ReadByte());
2037 TestFragment right = TranslateConditionForControl();
2038
2039 result.entry = left.entry;
2040 if (op == kAnd) {
2041 left.CreateTrueSuccessor(flow_graph_builder_)->LinkTo(right.entry);
2042 result.true_successor_addresses = right.true_successor_addresses;
2043 result.false_successor_addresses = left.false_successor_addresses;
2044 result.false_successor_addresses->AddArray(
2045 *right.false_successor_addresses);
2046 } else {
2047 ASSERT(op == kOr);
2048 left.CreateFalseSuccessor(flow_graph_builder_)->LinkTo(right.entry);
2049 result.true_successor_addresses = left.true_successor_addresses;
2050 result.true_successor_addresses->AddArray(
2051 *right.true_successor_addresses);
2052 result.false_successor_addresses = right.false_successor_addresses;
2053 }
2054 } else {
2055 // Other expressions.
2056 TokenPosition position = TokenPosition::kNoSource;
2057 Fragment instructions = BuildExpression(&position); // read expression.
2058
2059 // Check if the top of the stack is already a StrictCompare that
2060 // can be merged with a branch. Otherwise compare TOS with
2061 // true value and branch on that.
2062 BranchInstr* branch;
2063 if (stack()->definition()->IsStrictCompare() &&
2064 stack()->definition() == instructions.current) {
2065 StrictCompareInstr* compare = Pop()->definition()->AsStrictCompare();
2066 if (negate) {
2067 compare->NegateComparison();
2068 negate = false;
2069 }
2070 branch =
2071 new (Z) BranchInstr(compare, flow_graph_builder_->GetNextDeoptId());
2072 branch->comparison()->ClearTempIndex();
2073 ASSERT(instructions.current->previous() != nullptr);
2074 instructions.current = instructions.current->previous();
2075 } else {
2076 instructions += CheckBoolean(position);
2077 instructions += Constant(Bool::True());
2078 Value* right_value = Pop();
2079 Value* left_value = Pop();
2080 StrictCompareInstr* compare = new (Z) StrictCompareInstr(
2081 TokenPosition::kNoSource,
2082 negate ? Token::kNE_STRICT : Token::kEQ_STRICT, left_value,
2083 right_value, false, flow_graph_builder_->GetNextDeoptId());
2084 branch =
2085 new (Z) BranchInstr(compare, flow_graph_builder_->GetNextDeoptId());
2086 negate = false;
2087 }
2088 instructions <<= branch;
2089
2090 result = TestFragment(instructions.entry, branch);
2091 }
2092
2093 return result.Negate(negate);
2094}
2095
2096const TypeArguments& StreamingFlowGraphBuilder::BuildTypeArguments() {
2097 ReadUInt(); // read arguments count.
2098 intptr_t type_count = ReadListLength(); // read type count.
2099 return T.BuildTypeArguments(type_count); // read types.
2100}
2101
2102Fragment StreamingFlowGraphBuilder::BuildArguments(Array* argument_names,
2103 intptr_t* argument_count,
2104 intptr_t* positional_count) {
2105 intptr_t dummy;
2106 if (argument_count == NULL) argument_count = &dummy;
2107 *argument_count = ReadUInt(); // read arguments count.
2108
2109 // List of types.
2110 SkipListOfDartTypes(); // read list of types.
2111
2112 {
2113 AlternativeReadingScope _(&reader_);
2114 if (positional_count == NULL) positional_count = &dummy;
2115 *positional_count = ReadListLength(); // read length of expression list
2116 }
2117 return BuildArgumentsFromActualArguments(argument_names);
2118}
2119
2120Fragment StreamingFlowGraphBuilder::BuildArgumentsFromActualArguments(
2121 Array* argument_names) {
2122 Fragment instructions;
2123
2124 // List of positional.
2125 intptr_t list_length = ReadListLength(); // read list length.
2126 for (intptr_t i = 0; i < list_length; ++i) {
2127 instructions += BuildExpression(); // read ith expression.
2128 }
2129
2130 // List of named.
2131 list_length = ReadListLength(); // read list length.
2132 if (argument_names != NULL && list_length > 0) {
2133 *argument_names = Array::New(list_length, Heap::kOld);
2134 }
2135 for (intptr_t i = 0; i < list_length; ++i) {
2136 String& name =
2137 H.DartSymbolObfuscate(ReadStringReference()); // read ith name index.
2138 instructions += BuildExpression(); // read ith expression.
2139 if (argument_names != NULL) {
2140 argument_names->SetAt(i, name);
2141 }
2142 }
2143
2144 return instructions;
2145}
2146
2147Fragment StreamingFlowGraphBuilder::BuildInvalidExpression(
2148 TokenPosition* position) {
2149 // The frontend will take care of emitting normal errors (like
2150 // [NoSuchMethodError]s) and only emit [InvalidExpression]s in very special
2151 // situations (e.g. an invalid annotation).
2152 TokenPosition pos = ReadPosition();
2153 if (position != NULL) *position = pos;
2154 const String& message = H.DartString(ReadStringReference());
2155 // Invalid expression message has pointer to the source code, no need to
2156 // report it twice.
2157 H.ReportError(script(), TokenPosition::kNoSource, "%s", message.ToCString());
2158 return Fragment();
2159}
2160
2161Fragment StreamingFlowGraphBuilder::BuildVariableGet(TokenPosition* position) {
2162 const TokenPosition pos = ReadPosition();
2163 if (position != nullptr) *position = pos;
2164 intptr_t variable_kernel_position = ReadUInt(); // read kernel position.
2165 ReadUInt(); // read relative variable index.
2166 SkipOptionalDartType(); // read promoted type.
2167 return BuildVariableGetImpl(variable_kernel_position, pos);
2168}
2169
2170Fragment StreamingFlowGraphBuilder::BuildVariableGet(uint8_t payload,
2171 TokenPosition* position) {
2172 const TokenPosition pos = ReadPosition();
2173 if (position != nullptr) *position = pos;
2174 intptr_t variable_kernel_position = ReadUInt(); // read kernel position.
2175 return BuildVariableGetImpl(variable_kernel_position, pos);
2176}
2177
2178Fragment StreamingFlowGraphBuilder::BuildVariableGetImpl(
2179 intptr_t variable_kernel_position,
2180 TokenPosition position) {
2181 LocalVariable* variable = LookupVariable(variable_kernel_position);
2182 if (!variable->is_late()) {
2183 return LoadLocal(variable);
2184 }
2185
2186 // Late variable, so check whether it has been initialized already.
2187 Fragment instructions = LoadLocal(variable);
2188 TargetEntryInstr *is_uninitialized, *is_initialized;
2189 instructions += Constant(Object::sentinel());
2190 instructions += flow_graph_builder_->BranchIfStrictEqual(&is_uninitialized,
2191 &is_initialized);
2192 JoinEntryInstr* join = BuildJoinEntry();
2193
2194 {
2195 AlternativeReadingScope alt(&reader_, variable->late_init_offset());
2196 const bool has_initializer = (ReadTag() != kNothing);
2197
2198 if (has_initializer) {
2199 // If the variable isn't initialized, call the initializer and set it.
2200 Fragment initialize(is_uninitialized);
2201 initialize += BuildExpression();
2202 initialize += StoreLocal(position, variable);
2203 initialize += Drop();
2204 initialize += Goto(join);
2205 } else {
2206 // The variable has no initializer, so throw a LateInitializationError.
2207 Fragment initialize(is_uninitialized);
2208 initialize += flow_graph_builder_->ThrowLateInitializationError(
2209 position, variable->name());
2210 initialize += Goto(join);
2211 }
2212 }
2213
2214 {
2215 // Already initialized, so there's nothing to do.
2216 Fragment already_initialized(is_initialized);
2217 already_initialized += Goto(join);
2218 }
2219
2220 Fragment done = Fragment(instructions.entry, join);
2221 done += LoadLocal(variable);
2222 return done;
2223}
2224
2225Fragment StreamingFlowGraphBuilder::BuildVariableSet(TokenPosition* p) {
2226 TokenPosition position = ReadPosition(); // read position.
2227 if (p != NULL) *p = position;
2228
2229 intptr_t variable_kernel_position = ReadUInt(); // read kernel position.
2230 ReadUInt(); // read relative variable index.
2231 return BuildVariableSetImpl(position, variable_kernel_position);
2232}
2233
2234Fragment StreamingFlowGraphBuilder::BuildVariableSet(uint8_t payload,
2235 TokenPosition* p) {
2236 TokenPosition position = ReadPosition(); // read position.
2237 if (p != NULL) *p = position;
2238
2239 intptr_t variable_kernel_position = ReadUInt(); // read kernel position.
2240 return BuildVariableSetImpl(position, variable_kernel_position);
2241}
2242
2243Fragment StreamingFlowGraphBuilder::BuildVariableSetImpl(
2244 TokenPosition position,
2245 intptr_t variable_kernel_position) {
2246 Fragment instructions = BuildExpression(); // read expression.
2247 if (NeedsDebugStepCheck(stack(), position)) {
2248 instructions = DebugStepCheck(position) + instructions;
2249 }
2250
2251 LocalVariable* variable = LookupVariable(variable_kernel_position);
2252 if (variable->is_late() && variable->is_final()) {
2253 // Late final variable, so check whether it has been initialized.
2254 LocalVariable* expr_temp = MakeTemporary();
2255 instructions += LoadLocal(variable);
2256 TargetEntryInstr *is_uninitialized, *is_initialized;
2257 instructions += Constant(Object::sentinel());
2258 instructions += flow_graph_builder_->BranchIfStrictEqual(&is_uninitialized,
2259 &is_initialized);
2260 JoinEntryInstr* join = BuildJoinEntry();
2261
2262 {
2263 // The variable is uninitialized, so store the expression value.
2264 Fragment initialize(is_uninitialized);
2265 initialize += LoadLocal(expr_temp);
2266 initialize += StoreLocal(position, variable);
2267 initialize += Drop();
2268 initialize += Goto(join);
2269 }
2270
2271 {
2272 // Already initialized, so throw a LateInitializationError.
2273 Fragment already_initialized(is_initialized);
2274 already_initialized += flow_graph_builder_->ThrowLateInitializationError(
2275 position, variable->name());
2276 already_initialized += Goto(join);
2277 }
2278
2279 instructions = Fragment(instructions.entry, join);
2280 } else {
2281 instructions += StoreLocal(position, variable);
2282 }
2283
2284 return instructions;
2285}
2286
2287Fragment StreamingFlowGraphBuilder::BuildPropertyGet(TokenPosition* p) {
2288 const intptr_t offset = ReaderOffset() - 1; // Include the tag.
2289 const TokenPosition position = ReadPosition(); // read position.
2290 if (p != NULL) *p = position;
2291
2292 const DirectCallMetadata direct_call =
2293 direct_call_metadata_helper_.GetDirectTargetForPropertyGet(offset);
2294 const InferredTypeMetadata result_type =
2295 inferred_type_metadata_helper_.GetInferredType(offset);
2296
2297 Fragment instructions = BuildExpression(); // read receiver.
2298
2299 LocalVariable* receiver = NULL;
2300 if (direct_call.check_receiver_for_null_) {
2301 // Duplicate receiver for CheckNull before it is consumed by PushArgument.
2302 receiver = MakeTemporary();
2303 instructions += LoadLocal(receiver);
2304 }
2305
2306 const String& getter_name = ReadNameAsGetterName(); // read name.
2307
2308 const Function* interface_target = &Function::null_function();
2309 const Function* tearoff_interface_target = &Function::null_function();
2310 const NameIndex itarget_name =
2311 ReadInterfaceMemberNameReference(); // read interface_target_reference.
2312 if (!H.IsRoot(itarget_name) &&
2313 (H.IsGetter(itarget_name) || H.IsField(itarget_name))) {
2314 interface_target = &Function::ZoneHandle(
2315 Z,
2316 H.LookupMethodByMember(itarget_name, H.DartGetterName(itarget_name)));
2317 ASSERT(getter_name.raw() == interface_target->name());
2318 } else if (!H.IsRoot(itarget_name) && H.IsMethod(itarget_name)) {
2319 tearoff_interface_target = &Function::ZoneHandle(
2320 Z,
2321 H.LookupMethodByMember(itarget_name, H.DartMethodName(itarget_name)));
2322 }
2323
2324 if (direct_call.check_receiver_for_null_) {
2325 instructions += CheckNull(position, receiver, getter_name);
2326 }
2327
2328 const String* mangled_name = &getter_name;
2329 const Function* direct_call_target = &direct_call.target_;
2330 if (H.IsRoot(itarget_name)) {
2331 mangled_name = &String::ZoneHandle(
2332 Z, Function::CreateDynamicInvocationForwarderName(getter_name));
2333 if (!direct_call_target->IsNull()) {
2334 direct_call_target = &Function::ZoneHandle(
2335 direct_call.target_.GetDynamicInvocationForwarder(*mangled_name));
2336 }
2337 }
2338
2339 if (!direct_call_target->IsNull()) {
2340 ASSERT(CompilerState::Current().is_aot());
2341 instructions +=
2342 StaticCall(position, *direct_call_target, 1, Array::null_array(),
2343 ICData::kNoRebind, &result_type);
2344 } else {
2345 const intptr_t kTypeArgsLen = 0;
2346 const intptr_t kNumArgsChecked = 1;
2347 instructions +=
2348 InstanceCall(position, *mangled_name, Token::kGET, kTypeArgsLen, 1,
2349 Array::null_array(), kNumArgsChecked, *interface_target,
2350 *tearoff_interface_target, &result_type);
2351 }
2352
2353 if (direct_call.check_receiver_for_null_) {
2354 instructions += DropTempsPreserveTop(1); // Drop receiver, preserve result.
2355 }
2356
2357 return instructions;
2358}
2359
2360Fragment StreamingFlowGraphBuilder::BuildPropertySet(TokenPosition* p) {
2361 const intptr_t offset = ReaderOffset() - 1; // Include the tag.
2362
2363 const DirectCallMetadata direct_call =
2364 direct_call_metadata_helper_.GetDirectTargetForPropertySet(offset);
2365 const CallSiteAttributesMetadata call_site_attributes =
2366 call_site_attributes_metadata_helper_.GetCallSiteAttributes(offset);
2367 const InferredTypeMetadata inferred_type =
2368 inferred_type_metadata_helper_.GetInferredType(offset);
2369
2370 // True if callee can skip argument type checks.
2371 bool is_unchecked_call = inferred_type.IsSkipCheck();
2372 if (call_site_attributes.receiver_type != nullptr &&
2373 call_site_attributes.receiver_type->HasTypeClass() &&
2374 !Class::Handle(call_site_attributes.receiver_type->type_class())
2375 .IsGeneric()) {
2376 is_unchecked_call = true;
2377 }
2378
2379 Fragment instructions(MakeTemp());
2380 LocalVariable* variable = MakeTemporary();
2381
2382 const TokenPosition position = ReadPosition(); // read position.
2383 if (p != nullptr) *p = position;
2384
2385 if (PeekTag() == kThisExpression) {
2386 is_unchecked_call = true;
2387 }
2388 instructions += BuildExpression(); // read receiver.
2389
2390 LocalVariable* receiver = nullptr;
2391 if (direct_call.check_receiver_for_null_) {
2392 // Duplicate receiver for CheckNull before it is consumed by PushArgument.
2393 receiver = MakeTemporary();
2394 instructions += LoadLocal(receiver);
2395 }
2396
2397 const String& setter_name = ReadNameAsSetterName(); // read name.
2398
2399 instructions += BuildExpression(); // read value.
2400 instructions += StoreLocal(TokenPosition::kNoSource, variable);
2401
2402 const Function* interface_target = &Function::null_function();
2403 const NameIndex itarget_name =
2404 ReadInterfaceMemberNameReference(); // read interface_target_reference.
2405 if (!H.IsRoot(itarget_name)) {
2406 interface_target = &Function::ZoneHandle(
2407 Z,
2408 H.LookupMethodByMember(itarget_name, H.DartSetterName(itarget_name)));
2409 ASSERT(setter_name.raw() == interface_target->name());
2410 }
2411
2412 if (direct_call.check_receiver_for_null_) {
2413 instructions += CheckNull(position, receiver, setter_name);
2414 }
2415
2416 const String* mangled_name = &setter_name;
2417 const Function* direct_call_target = &direct_call.target_;
2418 if (H.IsRoot(itarget_name)) {
2419 mangled_name = &String::ZoneHandle(
2420 Z, Function::CreateDynamicInvocationForwarderName(setter_name));
2421 if (!direct_call_target->IsNull()) {
2422 direct_call_target = &Function::ZoneHandle(
2423 direct_call.target_.GetDynamicInvocationForwarder(*mangled_name));
2424 }
2425 }
2426
2427 if (!direct_call_target->IsNull()) {
2428 ASSERT(CompilerState::Current().is_aot());
2429 instructions +=
2430 StaticCall(position, *direct_call_target, 2, Array::null_array(),
2431 ICData::kNoRebind, /*result_type=*/nullptr,
2432 /*type_args_count=*/0,
2433 /*use_unchecked_entry=*/is_unchecked_call);
2434 } else {
2435 const intptr_t kTypeArgsLen = 0;
2436 const intptr_t kNumArgsChecked = 1;
2437
2438 instructions += InstanceCall(
2439 position, *mangled_name, Token::kSET, kTypeArgsLen, 2,
2440 Array::null_array(), kNumArgsChecked, *interface_target,
2441 Function::null_function(),
2442 /*result_type=*/nullptr,
2443 /*use_unchecked_entry=*/is_unchecked_call, &call_site_attributes);
2444 }
2445
2446 instructions += Drop(); // Drop result of the setter invocation.
2447
2448 if (direct_call.check_receiver_for_null_) {
2449 instructions += Drop(); // Drop receiver.
2450 }
2451
2452 return instructions;
2453}
2454
2455static Function& GetNoSuchMethodOrDie(Zone* zone, const Class& klass) {
2456 Function& nsm_function = Function::Handle(zone);
2457 Class& iterate_klass = Class::Handle(zone, klass.raw());
2458 while (!iterate_klass.IsNull()) {
2459 nsm_function = iterate_klass.LookupDynamicFunction(Symbols::NoSuchMethod());
2460 if (!nsm_function.IsNull() && nsm_function.NumParameters() == 2 &&
2461 nsm_function.NumTypeParameters() == 0) {
2462 break;
2463 }
2464 iterate_klass = iterate_klass.SuperClass();
2465 }
2466 // We are guaranteed to find noSuchMethod of class Object.
2467 ASSERT(!nsm_function.IsNull());
2468
2469 return nsm_function;
2470}
2471
2472// Note, that this will always mark `super` flag to true.
2473Fragment StreamingFlowGraphBuilder::BuildAllocateInvocationMirrorCall(
2474 TokenPosition position,
2475 const String& name,
2476 intptr_t num_type_arguments,
2477 intptr_t num_arguments,
2478 const Array& argument_names,
2479 LocalVariable* actuals_array,
2480 Fragment build_rest_of_actuals) {
2481 Fragment instructions;
2482
2483 // Populate array containing the actual arguments. Just add [this] here.
2484 instructions += LoadLocal(actuals_array); // array
2485 instructions += IntConstant(num_type_arguments == 0 ? 0 : 1); // index
2486 instructions += LoadLocal(parsed_function()->receiver_var()); // receiver
2487 instructions += StoreIndexed(kArrayCid);
2488 instructions += build_rest_of_actuals;
2489
2490 // First argument is receiver.
2491 instructions += LoadLocal(parsed_function()->receiver_var());
2492
2493 // Push the arguments for allocating the invocation mirror:
2494 // - the name.
2495 instructions += Constant(String::ZoneHandle(Z, name.raw()));
2496
2497 // - the arguments descriptor.
2498 const Array& args_descriptor =
2499 Array::Handle(Z, ArgumentsDescriptor::NewBoxed(
2500 num_type_arguments, num_arguments, argument_names));
2501 instructions += Constant(Array::ZoneHandle(Z, args_descriptor.raw()));
2502
2503 // - an array containing the actual arguments.
2504 instructions += LoadLocal(actuals_array);
2505
2506 // - [true] indicating this is a `super` NoSuchMethod.
2507 instructions += Constant(Bool::True());
2508
2509 const Class& mirror_class =
2510 Class::Handle(Z, Library::LookupCoreClass(Symbols::InvocationMirror()));
2511 ASSERT(!mirror_class.IsNull());
2512 const Function& allocation_function = Function::ZoneHandle(
2513 Z, mirror_class.LookupStaticFunction(
2514 Library::PrivateCoreLibName(Symbols::AllocateInvocationMirror())));
2515 ASSERT(!allocation_function.IsNull());
2516 instructions += StaticCall(position, allocation_function,
2517 /* argument_count = */ 4, ICData::kStatic);
2518 return instructions;
2519}
2520
2521Fragment StreamingFlowGraphBuilder::BuildSuperPropertyGet(TokenPosition* p) {
2522 const intptr_t offset = ReaderOffset() - 1; // Include the tag.
2523 const TokenPosition position = ReadPosition(); // read position.
2524 if (p != NULL) *p = position;
2525
2526 const InferredTypeMetadata result_type =
2527 inferred_type_metadata_helper_.GetInferredType(offset);
2528
2529 Class& klass = GetSuperOrDie();
2530
2531 StringIndex name_index = ReadStringReference(); // read name index.
2532 NameIndex library_reference =
2533 ((H.StringSize(name_index) >= 1) && H.CharacterAt(name_index, 0) == '_')
2534 ? ReadCanonicalNameReference() // read library index.
2535 : NameIndex();
2536 const String& getter_name = H.DartGetterName(library_reference, name_index);
2537 const String& method_name = H.DartMethodName(library_reference, name_index);
2538
2539 SkipInterfaceMemberNameReference(); // skip target_reference.
2540
2541 // Search the superclass chain for the selector looking for either getter or
2542 // method.
2543 Function& function = Function::Handle(Z);
2544 while (!klass.IsNull()) {
2545 function = klass.LookupDynamicFunction(method_name);
2546 if (!function.IsNull()) {
2547 Function& target =
2548 Function::ZoneHandle(Z, function.ImplicitClosureFunction());
2549 ASSERT(!target.IsNull());
2550 // Generate inline code for allocation closure object with context
2551 // which captures `this`.
2552 return BuildImplicitClosureCreation(target);
2553 }
2554 function = klass.LookupDynamicFunction(getter_name);
2555 if (!function.IsNull()) break;
2556 klass = klass.SuperClass();
2557 }
2558
2559 Fragment instructions;
2560 if (klass.IsNull()) {
2561 instructions +=
2562 Constant(TypeArguments::ZoneHandle(Z, TypeArguments::null()));
2563 instructions += IntConstant(1); // array size
2564 instructions += CreateArray();
2565 LocalVariable* actuals_array = MakeTemporary();
2566
2567 Class& parent_klass = GetSuperOrDie();
2568
2569 instructions += BuildAllocateInvocationMirrorCall(
2570 position, getter_name,
2571 /* num_type_arguments = */ 0,
2572 /* num_arguments = */ 1,
2573 /* argument_names = */ Object::empty_array(), actuals_array,
2574 /* build_rest_of_actuals = */ Fragment());
2575
2576 Function& nsm_function = GetNoSuchMethodOrDie(Z, parent_klass);
2577 instructions +=
2578 StaticCall(position, Function::ZoneHandle(Z, nsm_function.raw()),
2579 /* argument_count = */ 2, ICData::kNSMDispatch);
2580 instructions += DropTempsPreserveTop(1); // Drop array
2581 } else {
2582 ASSERT(!klass.IsNull());
2583 ASSERT(!function.IsNull());
2584
2585 instructions += LoadLocal(parsed_function()->receiver_var());
2586
2587 instructions +=
2588 StaticCall(position, Function::ZoneHandle(Z, function.raw()),
2589 /* argument_count = */ 1, Array::null_array(),
2590 ICData::kSuper, &result_type);
2591 }
2592
2593 return instructions;
2594}
2595
2596Fragment StreamingFlowGraphBuilder::BuildSuperPropertySet(TokenPosition* p) {
2597 const TokenPosition position = ReadPosition(); // read position.
2598 if (p != NULL) *p = position;
2599
2600 Class& klass = GetSuperOrDie();
2601
2602 const String& setter_name = ReadNameAsSetterName(); // read name.
2603
2604 Function& function =
2605 Function::Handle(Z, H.LookupDynamicFunction(klass, setter_name));
2606
2607 Fragment instructions(MakeTemp());
2608 LocalVariable* value = MakeTemporary(); // this holds RHS value
2609
2610 if (function.IsNull()) {
2611 instructions +=
2612 Constant(TypeArguments::ZoneHandle(Z, TypeArguments::null()));
2613 instructions += IntConstant(2); // array size
2614 instructions += CreateArray();
2615 LocalVariable* actuals_array = MakeTemporary();
2616
2617 Fragment build_rest_of_actuals;
2618 build_rest_of_actuals += LoadLocal(actuals_array); // array
2619 build_rest_of_actuals += IntConstant(1); // index
2620 build_rest_of_actuals += BuildExpression(); // value.
2621 build_rest_of_actuals += StoreLocal(position, value);
2622 build_rest_of_actuals += StoreIndexed(kArrayCid);
2623
2624 instructions += BuildAllocateInvocationMirrorCall(
2625 position, setter_name, /* num_type_arguments = */ 0,
2626 /* num_arguments = */ 2,
2627 /* argument_names = */ Object::empty_array(), actuals_array,
2628 build_rest_of_actuals);
2629
2630 SkipInterfaceMemberNameReference(); // skip target_reference.
2631
2632 Function& nsm_function = GetNoSuchMethodOrDie(Z, klass);
2633 instructions +=
2634 StaticCall(position, Function::ZoneHandle(Z, nsm_function.raw()),
2635 /* argument_count = */ 2, ICData::kNSMDispatch);
2636 instructions += Drop(); // Drop result of NoSuchMethod invocation
2637 instructions += Drop(); // Drop array
2638 } else {
2639 // receiver
2640 instructions += LoadLocal(parsed_function()->receiver_var());
2641
2642 instructions += BuildExpression(); // read value.
2643 instructions += StoreLocal(position, value);
2644
2645 SkipInterfaceMemberNameReference(); // skip target_reference.
2646
2647 instructions += StaticCall(
2648 position, Function::ZoneHandle(Z, function.raw()),
2649 /* argument_count = */ 2, Array::null_array(), ICData::kSuper,
2650 /*result_type=*/nullptr, /*type_args_len=*/0,
2651 /*use_unchecked_entry=*/true);
2652 instructions += Drop(); // Drop result of the setter invocation.
2653 }
2654
2655 return instructions;
2656}
2657
2658Fragment StreamingFlowGraphBuilder::BuildDirectPropertyGet(TokenPosition* p) {
2659 const intptr_t offset = ReaderOffset() - 1; // Include the tag.
2660 const TokenPosition position = ReadPosition(); // read position.
2661 if (p != NULL) *p = position;
2662
2663 const InferredTypeMetadata result_type =
2664 inferred_type_metadata_helper_.GetInferredType(offset);
2665
2666 const Tag receiver_tag = PeekTag(); // peek tag for receiver.
2667 Fragment instructions = BuildExpression(); // read receiver.
2668 const NameIndex kernel_name =
2669 ReadInterfaceMemberNameReference(); // read target_reference.
2670
2671 Function& target = Function::ZoneHandle(Z);
2672 if (H.IsProcedure(kernel_name)) {
2673 if (H.IsGetter(kernel_name)) {
2674 target =
2675 H.LookupMethodByMember(kernel_name, H.DartGetterName(kernel_name));
2676 } else if (receiver_tag == kThisExpression) {
2677 // Undo stack change for the BuildExpression.
2678 Pop();
2679
2680 target =
2681 H.LookupMethodByMember(kernel_name, H.DartMethodName(kernel_name));
2682 target = target.ImplicitClosureFunction();
2683 ASSERT(!target.IsNull());
2684
2685 // Generate inline code for allocating closure object with context which
2686 // captures `this`.
2687 return BuildImplicitClosureCreation(target);
2688 } else {
2689 // Need to create implicit closure (tear-off), receiver != this.
2690 // Ensure method extractor exists and call it directly.
2691 const Function& target_method = Function::ZoneHandle(
2692 Z,
2693 H.LookupMethodByMember(kernel_name, H.DartMethodName(kernel_name)));
2694 const String& getter_name = H.DartGetterName(kernel_name);
2695 target = target_method.GetMethodExtractor(getter_name);
2696 }
2697 } else {
2698 ASSERT(H.IsField(kernel_name));
2699 const String& getter_name = H.DartGetterName(kernel_name);
2700 target = H.LookupMethodByMember(kernel_name, getter_name);
2701 ASSERT(target.IsGetterFunction() || target.IsImplicitGetterFunction());
2702 }
2703
2704 // Static calls are marked as "no-rebind", which is currently safe because
2705 // DirectPropertyGet are only used in enums (index in toString) and enums
2706 // can't change their structure during hot reload.
2707 // If there are other sources of DirectPropertyGet in the future, this code
2708 // have to be adjusted.
2709 return instructions + StaticCall(position, target, 1, Array::null_array(),
2710 ICData::kNoRebind, &result_type);
2711}
2712
2713Fragment StreamingFlowGraphBuilder::BuildDirectPropertySet(TokenPosition* p) {
2714 const TokenPosition position = ReadPosition(); // read position.
2715 if (p != NULL) *p = position;
2716
2717 Fragment instructions(MakeTemp());
2718 LocalVariable* value = MakeTemporary();
2719
2720 instructions += BuildExpression(); // read receiver.
2721
2722 const NameIndex target_reference =
2723 ReadInterfaceMemberNameReference(); // read target_reference.
2724 const String& method_name = H.DartSetterName(target_reference);
2725 const Function& target = Function::ZoneHandle(
2726 Z, H.LookupMethodByMember(target_reference, method_name));
2727 ASSERT(target.IsSetterFunction() || target.IsImplicitSetterFunction());
2728
2729 instructions += BuildExpression(); // read value.
2730 instructions += StoreLocal(TokenPosition::kNoSource, value);
2731
2732 // Static calls are marked as "no-rebind", which is currently safe because
2733 // DirectPropertyGet are only used in enums (index in toString) and enums
2734 // can't change their structure during hot reload.
2735 // If there are other sources of DirectPropertyGet in the future, this code
2736 // have to be adjusted.
2737 instructions +=
2738 StaticCall(position, target, 2, Array::null_array(), ICData::kNoRebind,
2739 /* result_type = */ NULL);
2740
2741 return instructions + Drop();
2742}
2743
2744Fragment StreamingFlowGraphBuilder::BuildStaticGet(TokenPosition* p) {
2745 ASSERT(Error::Handle(Z, H.thread()->sticky_error()).IsNull());
2746 const intptr_t offset = ReaderOffset() - 1; // Include the tag.
2747
2748 TokenPosition position = ReadPosition(); // read position.
2749 if (p != NULL) *p = position;
2750
2751 const InferredTypeMetadata result_type =
2752 inferred_type_metadata_helper_.GetInferredType(offset);
2753
2754 NameIndex target = ReadCanonicalNameReference(); // read target_reference.
2755
2756 if (H.IsField(target)) {
2757 const Field& field =
2758 Field::ZoneHandle(Z, H.LookupFieldByKernelField(target));
2759 if (field.is_const()) {
2760 // Since the CFE inlines all references to const variables and fields,
2761 // it never emits a StaticGet of a const field.
2762 // This situation only arises because of the static const fields in
2763 // the ClassID class, which are generated internally in the VM
2764 // during loading. See also Class::InjectCIDFields.
2765 ASSERT(Class::Handle(field.Owner()).library() ==
2766 Library::InternalLibrary() &&
2767 Class::Handle(field.Owner()).Name() == Symbols::ClassID().raw());
2768 return Constant(Instance::ZoneHandle(Z, field.StaticValue()));
2769 } else {
2770 const Class& owner = Class::Handle(Z, field.Owner());
2771 const String& getter_name = H.DartGetterName(target);
2772 const Function& getter =
2773 Function::ZoneHandle(Z, owner.LookupStaticFunction(getter_name));
2774 if (!getter.IsNull() && field.NeedsGetter()) {
2775 return StaticCall(position, getter, 0, Array::null_array(),
2776 ICData::kStatic, &result_type);
2777 } else {
2778 if (result_type.IsConstant()) {
2779 return Constant(result_type.constant_value);
2780 }
2781 return LoadStaticField(field, /*calls_initializer=*/false);
2782 }
2783 }
2784 } else {
2785 const Function& function =
2786 Function::ZoneHandle(Z, H.LookupStaticMethodByKernelProcedure(target));
2787
2788 if (H.IsGetter(target)) {
2789 return StaticCall(position, function, 0, Array::null_array(),
2790 ICData::kStatic, &result_type);
2791 } else if (H.IsMethod(target)) {
2792 const auto& closure_function =
2793 Function::Handle(Z, function.ImplicitClosureFunction());
2794 const auto& static_closure =
2795 Instance::Handle(Z, closure_function.ImplicitStaticClosure());
2796 return Constant(Instance::ZoneHandle(Z, H.Canonicalize(static_closure)));
2797 } else {
2798 UNIMPLEMENTED();
2799 }
2800 }
2801
2802 return Fragment();
2803}
2804
2805Fragment StreamingFlowGraphBuilder::BuildStaticSet(TokenPosition* p) {
2806 TokenPosition position = ReadPosition(); // read position.
2807 if (p != NULL) *p = position;
2808
2809 NameIndex target = ReadCanonicalNameReference(); // read target_reference.
2810
2811 if (H.IsField(target)) {
2812 const Field& field =
2813 Field::ZoneHandle(Z, H.LookupFieldByKernelField(target));
2814 const Class& owner = Class::Handle(Z, field.Owner());
2815 const String& setter_name = H.DartSetterName(target);
2816 const Function& setter =
2817 Function::ZoneHandle(Z, owner.LookupStaticFunction(setter_name));
2818 Fragment instructions = BuildExpression(); // read expression.
2819 if (NeedsDebugStepCheck(stack(), position)) {
2820 instructions = DebugStepCheck(position) + instructions;
2821 }
2822 LocalVariable* variable = MakeTemporary();
2823 instructions += LoadLocal(variable);
2824 if (!setter.IsNull() && field.NeedsSetter()) {
2825 instructions += StaticCall(position, setter, 1, ICData::kStatic);
2826 instructions += Drop();
2827 } else {
2828 instructions += StoreStaticField(position, field);
2829 }
2830 return instructions;
2831 } else {
2832 ASSERT(H.IsProcedure(target));
2833
2834 // Evaluate the expression on the right hand side.
2835 Fragment instructions = BuildExpression(); // read expression.
2836 LocalVariable* variable = MakeTemporary();
2837
2838 // Prepare argument.
2839 instructions += LoadLocal(variable);
2840
2841 // Invoke the setter function.
2842 const Function& function =
2843 Function::ZoneHandle(Z, H.LookupStaticMethodByKernelProcedure(target));
2844 instructions += StaticCall(position, function, 1, ICData::kStatic);
2845
2846 // Drop the unused result & leave the stored value on the stack.
2847 return instructions + Drop();
2848 }
2849}
2850
2851Fragment StreamingFlowGraphBuilder::BuildMethodInvocation(TokenPosition* p) {
2852 const intptr_t offset = ReaderOffset() - 1; // Include the tag.
2853 const TokenPosition position = ReadPosition(); // read position.
2854 if (p != NULL) *p = position;
2855
2856 const DirectCallMetadata direct_call =
2857 direct_call_metadata_helper_.GetDirectTargetForMethodInvocation(offset);
2858 const InferredTypeMetadata result_type =
2859 inferred_type_metadata_helper_.GetInferredType(offset);
2860 const CallSiteAttributesMetadata call_site_attributes =
2861 call_site_attributes_metadata_helper_.GetCallSiteAttributes(offset);
2862
2863 const Tag receiver_tag = PeekTag(); // peek tag for receiver.
2864
2865 bool is_unchecked_closure_call = false;
2866 bool is_unchecked_call = result_type.IsSkipCheck();
2867 if (call_site_attributes.receiver_type != nullptr) {
2868 if (call_site_attributes.receiver_type->IsFunctionType()) {
2869 AlternativeReadingScope alt(&reader_);
2870 SkipExpression(); // skip receiver
2871 is_unchecked_closure_call =
2872 ReadNameAsMethodName().Equals(Symbols::Call());
2873 } else if (call_site_attributes.receiver_type->HasTypeClass() &&
2874 !call_site_attributes.receiver_type->IsDynamicType() &&
2875 !Class::Handle(call_site_attributes.receiver_type->type_class())
2876 .IsGeneric()) {
2877 is_unchecked_call = true;
2878 }
2879 }
2880
2881 Fragment instructions;
2882
2883 intptr_t type_args_len = 0;
2884 LocalVariable* type_arguments_temp = NULL;
2885 {
2886 AlternativeReadingScope alt(&reader_);
2887 SkipExpression(); // skip receiver
2888 SkipName(); // skip method name
2889 ReadUInt(); // read argument count.
2890 intptr_t list_length = ReadListLength(); // read types list length.
2891 if (list_length > 0) {
2892 const TypeArguments& type_arguments =
2893 T.BuildTypeArguments(list_length); // read types.
2894 instructions += TranslateInstantiatedTypeArguments(type_arguments);
2895 if (direct_call.check_receiver_for_null_ || is_unchecked_closure_call) {
2896 // Don't yet push type arguments if we need to check receiver for null.
2897 // In this case receiver will be duplicated so instead of pushing
2898 // type arguments here we need to push it between receiver_temp
2899 // and actual receiver. See the code below.
2900 type_arguments_temp = MakeTemporary();
2901 }
2902 }
2903 type_args_len = list_length;
2904 }
2905
2906 // Take note of whether the invocation is against the receiver of the current
2907 // function: in this case, we may skip some type checks in the callee.
2908 if (PeekTag() == kThisExpression) {
2909 is_unchecked_call = true;
2910 }
2911 instructions += BuildExpression(); // read receiver.
2912
2913 const String& name = ReadNameAsMethodName(); // read name.
2914 const Token::Kind token_kind =
2915 MethodTokenRecognizer::RecognizeTokenKind(name);
2916
2917 // Detect comparison with null.
2918 if ((token_kind == Token::kEQ || token_kind == Token::kNE) &&
2919 PeekArgumentsCount() == 1 &&
2920 (receiver_tag == kNullLiteral ||
2921 PeekArgumentsFirstPositionalTag() == kNullLiteral)) {
2922 ASSERT(type_args_len == 0);
2923 // "==" or "!=" with null on either side.
2924 instructions +=
2925 BuildArguments(NULL /* named */, NULL /* arg count */,
2926 NULL /* positional arg count */); // read arguments.
2927 SkipInterfaceMemberNameReference(); // read interface_target_reference.
2928 Token::Kind strict_cmp_kind =
2929 token_kind == Token::kEQ ? Token::kEQ_STRICT : Token::kNE_STRICT;
2930 return instructions +
2931 StrictCompare(position, strict_cmp_kind, /*number_check = */ true);
2932 }
2933
2934 LocalVariable* receiver_temp = NULL;
2935 if (direct_call.check_receiver_for_null_ || is_unchecked_closure_call) {
2936 // Duplicate receiver for CheckNull before it is consumed by PushArgument.
2937 receiver_temp = MakeTemporary();
2938 if (type_arguments_temp != NULL) {
2939 // If call has type arguments then push them before pushing the receiver.
2940 // The stack will contain:
2941 //
2942 // [type_arguments_temp][receiver_temp][type_arguments][receiver] ...
2943 //
2944 instructions += LoadLocal(type_arguments_temp);
2945 }
2946 instructions += LoadLocal(receiver_temp);
2947 }
2948
2949 intptr_t argument_count;
2950 intptr_t positional_argument_count;
2951 Array& argument_names = Array::ZoneHandle(Z);
2952 instructions +=
2953 BuildArguments(&argument_names, &argument_count,
2954 &positional_argument_count); // read arguments.
2955 ++argument_count; // include receiver
2956
2957 intptr_t checked_argument_count = 1;
2958 // If we have a special operation (e.g. +/-/==) we mark both arguments as
2959 // to be checked.
2960 if (token_kind != Token::kILLEGAL) {
2961 ASSERT(argument_count <= 2);
2962 checked_argument_count = argument_count;
2963 }
2964
2965 const Function* interface_target = &Function::null_function();
2966 const NameIndex itarget_name =
2967 ReadInterfaceMemberNameReference(); // read interface_target_reference.
2968 // TODO(dartbug.com/34497): Once front-end desugars calls via
2969 // fields/getters, filtering of field and getter interface targets here
2970 // can be turned into assertions.
2971 if (!H.IsRoot(itarget_name) && !H.IsField(itarget_name) &&
2972 !H.IsGetter(itarget_name)) {
2973 interface_target = &Function::ZoneHandle(
2974 Z, H.LookupMethodByMember(itarget_name,
2975 H.DartProcedureName(itarget_name)));
2976 ASSERT(name.raw() == interface_target->name());
2977 ASSERT(!interface_target->IsGetterFunction());
2978 }
2979
2980 // TODO(sjindel): Avoid the check for null on unchecked closure calls if TFA
2981 // allows.
2982 if (direct_call.check_receiver_for_null_ || is_unchecked_closure_call) {
2983 // Receiver temp is needed to load the function to call from the closure.
2984 instructions += CheckNull(position, receiver_temp, name,
2985 /*clear_temp=*/!is_unchecked_closure_call);
2986 }
2987
2988 const String* mangled_name = &name;
2989 // Do not mangle ==:
2990 // * operator == takes an Object so its either not checked or checked
2991 // at the entry because the parameter is marked covariant, neither of
2992 // those cases require a dynamic invocation forwarder.
2993 const Function* direct_call_target = &direct_call.target_;
2994 if (H.IsRoot(itarget_name) &&
2995 (name.raw() != Symbols::EqualOperator().raw())) {
2996 mangled_name = &String::ZoneHandle(
2997 Z, Function::CreateDynamicInvocationForwarderName(name));
2998 if (!direct_call_target->IsNull()) {
2999 direct_call_target = &Function::ZoneHandle(
3000 direct_call_target->GetDynamicInvocationForwarder(*mangled_name));
3001 }
3002 }
3003
3004 if (is_unchecked_closure_call) {
3005 // Lookup the function in the closure.
3006 instructions += LoadLocal(receiver_temp);
3007 instructions += LoadNativeField(Slot::Closure_function());
3008 if (parsed_function()->function().is_debuggable()) {
3009 ASSERT(!parsed_function()->function().is_native());
3010 instructions += DebugStepCheck(position);
3011 }
3012 instructions +=
3013 B->ClosureCall(position, type_args_len, argument_count, argument_names,
3014 /*use_unchecked_entry=*/true);
3015 } else if (!direct_call_target->IsNull()) {
3016 // Even if TFA infers a concrete receiver type, the static type of the
3017 // call-site may still be dynamic and we need to call the dynamic invocation
3018 // forwarder to ensure type-checks are performed.
3019 ASSERT(CompilerState::Current().is_aot());
3020 instructions +=
3021 StaticCall(position, *direct_call_target, argument_count,
3022 argument_names, ICData::kNoRebind, &result_type,
3023 type_args_len, /*use_unchecked_entry=*/is_unchecked_call);
3024 } else {
3025 instructions +=
3026 InstanceCall(position, *mangled_name, token_kind, type_args_len,
3027 argument_count, argument_names, checked_argument_count,
3028 *interface_target, Function::null_function(), &result_type,
3029 /*use_unchecked_entry=*/is_unchecked_call,
3030 &call_site_attributes, result_type.ReceiverNotInt());
3031 }
3032
3033 // Drop temporaries preserving result on the top of the stack.
3034 ASSERT((receiver_temp != NULL) || (type_arguments_temp == NULL));
3035 if (receiver_temp != NULL) {
3036 const intptr_t num_temps =
3037 (receiver_temp != NULL ? 1 : 0) + (type_arguments_temp != NULL ? 1 : 0);
3038 instructions += DropTempsPreserveTop(num_temps);
3039 }
3040
3041 // Later optimization passes assume that result of a x.[]=(...) call is not
3042 // used. We must guarantee this invariant because violation will lead to an
3043 // illegal IL once we replace x.[]=(...) with a sequence that does not
3044 // actually produce any value. See http://dartbug.com/29135 for more details.
3045 if (name.raw() == Symbols::AssignIndexToken().raw()) {
3046 instructions += Drop();
3047 instructions += NullConstant();
3048 }
3049
3050 return instructions;
3051}
3052
3053Fragment StreamingFlowGraphBuilder::BuildDirectMethodInvocation(
3054 TokenPosition* p) {
3055 const intptr_t offset = ReaderOffset() - 1; // Include the tag.
3056 TokenPosition position = ReadPosition(); // read offset.
3057 if (p != NULL) *p = position;
3058
3059 const InferredTypeMetadata result_type =
3060 inferred_type_metadata_helper_.GetInferredType(offset);
3061
3062 Tag receiver_tag = PeekTag(); // peek tag for receiver.
3063
3064 Fragment instructions;
3065 intptr_t type_args_len = 0;
3066 {
3067 AlternativeReadingScope alt(&reader_);
3068 SkipExpression(); // skip receiver
3069 ReadInterfaceMemberNameReference(); // skip target reference
3070 ReadUInt(); // read argument count.
3071 intptr_t list_length = ReadListLength(); // read types list length.
3072 if (list_length > 0) {
3073 const TypeArguments& type_arguments =
3074 T.BuildTypeArguments(list_length); // read types.
3075 instructions += TranslateInstantiatedTypeArguments(type_arguments);
3076 }
3077 type_args_len = list_length;
3078 }
3079
3080 instructions += BuildExpression(); // read receiver.
3081
3082 NameIndex kernel_name =
3083 ReadInterfaceMemberNameReference(); // read target_reference.
3084 const String& method_name = H.DartProcedureName(kernel_name);
3085 const Token::Kind token_kind =
3086 MethodTokenRecognizer::RecognizeTokenKind(method_name);
3087
3088 // Detect comparison with null.
3089 if ((token_kind == Token::kEQ || token_kind == Token::kNE) &&
3090 PeekArgumentsCount() == 1 &&
3091 (receiver_tag == kNullLiteral ||
3092 PeekArgumentsFirstPositionalTag() == kNullLiteral)) {
3093 ASSERT(type_args_len == 0);
3094 // "==" or "!=" with null on either side.
3095 instructions +=
3096 BuildArguments(NULL /* names */, NULL /* arg count */,
3097 NULL /* positional arg count */); // read arguments.
3098 Token::Kind strict_cmp_kind =
3099 token_kind == Token::kEQ ? Token::kEQ_STRICT : Token::kNE_STRICT;
3100 return instructions +
3101 StrictCompare(position, strict_cmp_kind, /*number_check = */ true);
3102 }
3103
3104 const Function& target =
3105 Function::ZoneHandle(Z, H.LookupMethodByMember(kernel_name, method_name));
3106
3107 Array& argument_names = Array::ZoneHandle(Z);
3108 intptr_t argument_count, positional_argument_count;
3109 instructions +=
3110 BuildArguments(&argument_names, &argument_count,
3111 &positional_argument_count); // read arguments.
3112 ++argument_count;
3113
3114 return instructions + StaticCall(position, target, argument_count,
3115 argument_names, ICData::kNoRebind,
3116 &result_type, type_args_len);
3117}
3118
3119Fragment StreamingFlowGraphBuilder::BuildSuperMethodInvocation(
3120 TokenPosition* p) {
3121 const intptr_t offset = ReaderOffset() - 1; // Include the tag.
3122 const TokenPosition position = ReadPosition(); // read position.
3123 if (p != NULL) *p = position;
3124
3125 const InferredTypeMetadata result_type =
3126 inferred_type_metadata_helper_.GetInferredType(offset);
3127
3128 intptr_t type_args_len = 0;
3129 {
3130 AlternativeReadingScope alt(&reader_);
3131 SkipName(); // skip method name
3132 ReadUInt(); // read argument count.
3133 type_args_len = ReadListLength(); // read types list length.
3134 }
3135
3136 Class& klass = GetSuperOrDie();
3137
3138 // Search the superclass chain for the selector.
3139 const String& method_name = ReadNameAsMethodName(); // read name.
3140
3141 // Figure out selector signature.
3142 intptr_t argument_count;
3143 Array& argument_names = Array::Handle(Z);
3144 {
3145 AlternativeReadingScope alt(&reader_);
3146 argument_count = ReadUInt();
3147 SkipListOfDartTypes();
3148
3149 SkipListOfExpressions();
3150 intptr_t named_list_length = ReadListLength();
3151 argument_names = Array::New(named_list_length, H.allocation_space());
3152 for (intptr_t i = 0; i < named_list_length; i++) {
3153 const String& arg_name = H.DartSymbolObfuscate(ReadStringReference());
3154 argument_names.SetAt(i, arg_name);
3155 SkipExpression();
3156 }
3157 }
3158
3159 Function& function = FindMatchingFunction(
3160 klass, method_name, type_args_len,
3161 argument_count + 1 /* account for 'this' */, argument_names);
3162
3163 if (function.IsNull()) {
3164 ReadUInt(); // argument count
3165 intptr_t type_list_length = ReadListLength();
3166
3167 Fragment instructions;
3168 instructions +=
3169 Constant(TypeArguments::ZoneHandle(Z, TypeArguments::null()));
3170 instructions += IntConstant(argument_count + 1 /* this */ +
3171 (type_list_length == 0 ? 0 : 1)); // array size
3172 instructions += CreateArray();
3173 LocalVariable* actuals_array = MakeTemporary();
3174
3175 // Call allocationInvocationMirror to get instance of Invocation.
3176 Fragment build_rest_of_actuals;
3177 intptr_t actuals_array_index = 0;
3178 if (type_list_length > 0) {
3179 const TypeArguments& type_arguments =
3180 T.BuildTypeArguments(type_list_length);
3181 build_rest_of_actuals += LoadLocal(actuals_array);
3182 build_rest_of_actuals += IntConstant(actuals_array_index);
3183 build_rest_of_actuals +=
3184 TranslateInstantiatedTypeArguments(type_arguments);
3185 build_rest_of_actuals += StoreIndexed(kArrayCid);
3186 ++actuals_array_index;
3187 }
3188
3189 ++actuals_array_index; // account for 'this'.
3190 // Read arguments
3191 intptr_t list_length = ReadListLength();
3192 intptr_t i = 0;
3193 while (i < list_length) {
3194 build_rest_of_actuals += LoadLocal(actuals_array); // array
3195 build_rest_of_actuals += IntConstant(actuals_array_index + i); // index
3196 build_rest_of_actuals += BuildExpression(); // value.
3197 build_rest_of_actuals += StoreIndexed(kArrayCid);
3198 ++i;
3199 }
3200 // Read named arguments
3201 intptr_t named_list_length = ReadListLength();
3202 if (named_list_length > 0) {
3203 ASSERT(argument_count == list_length + named_list_length);
3204 while ((i - list_length) < named_list_length) {
3205 SkipStringReference();
3206 build_rest_of_actuals += LoadLocal(actuals_array); // array
3207 build_rest_of_actuals += IntConstant(i + actuals_array_index); // index
3208 build_rest_of_actuals += BuildExpression(); // value.
3209 build_rest_of_actuals += StoreIndexed(kArrayCid);
3210 ++i;
3211 }
3212 }
3213 instructions += BuildAllocateInvocationMirrorCall(
3214 position, method_name, type_list_length,
3215 /* num_arguments = */ argument_count + 1, argument_names, actuals_array,
3216 build_rest_of_actuals);
3217
3218 SkipInterfaceMemberNameReference(); // skip target_reference.
3219
3220 Function& nsm_function = GetNoSuchMethodOrDie(Z, klass);
3221 instructions += StaticCall(TokenPosition::kNoSource,
3222 Function::ZoneHandle(Z, nsm_function.raw()),
3223 /* argument_count = */ 2, ICData::kNSMDispatch);
3224 instructions += DropTempsPreserveTop(1); // Drop actuals_array temp.
3225 return instructions;
3226 } else {
3227 Fragment instructions;
3228
3229 {
3230 AlternativeReadingScope alt(&reader_);
3231 ReadUInt(); // read argument count.
3232 intptr_t list_length = ReadListLength(); // read types list length.
3233 if (list_length > 0) {
3234 const TypeArguments& type_arguments =
3235 T.BuildTypeArguments(list_length); // read types.
3236 instructions += TranslateInstantiatedTypeArguments(type_arguments);
3237 }
3238 }
3239
3240 // receiver
3241 instructions += LoadLocal(parsed_function()->receiver_var());
3242
3243 Array& argument_names = Array::ZoneHandle(Z);
3244 intptr_t argument_count;
3245 instructions += BuildArguments(
3246 &argument_names, &argument_count,
3247 /* positional_argument_count = */ NULL); // read arguments.
3248 ++argument_count; // include receiver
3249 SkipInterfaceMemberNameReference(); // interfaceTargetReference
3250 return instructions +
3251 StaticCall(position, Function::ZoneHandle(Z, function.raw()),
3252 argument_count, argument_names, ICData::kSuper,
3253 &result_type, type_args_len,
3254 /*use_unchecked_entry_point=*/true);
3255 }
3256}
3257
3258Fragment StreamingFlowGraphBuilder::BuildStaticInvocation(TokenPosition* p) {
3259 const intptr_t offset = ReaderOffset() - 1; // Include the tag.
3260 TokenPosition position = ReadPosition(); // read position.
3261 if (p != NULL) *p = position;
3262
3263 const InferredTypeMetadata result_type =
3264 inferred_type_metadata_helper_.GetInferredType(offset);
3265
3266 NameIndex procedure_reference =
3267 ReadCanonicalNameReference(); // read procedure reference.
3268 intptr_t argument_count = PeekArgumentsCount();
3269 const Function& target = Function::ZoneHandle(
3270 Z, H.LookupStaticMethodByKernelProcedure(procedure_reference));
3271 const Class& klass = Class::ZoneHandle(Z, target.Owner());
3272 if (target.IsGenerativeConstructor() || target.IsFactory()) {
3273 // The VM requires a TypeArguments object as first parameter for
3274 // every factory constructor.
3275 ++argument_count;
3276 }
3277
3278 const auto recognized_kind = target.recognized_kind();
3279 if (recognized_kind == MethodRecognizer::kFfiAsFunctionInternal) {
3280 return BuildFfiAsFunctionInternal();
3281 } else if (CompilerState::Current().is_aot() &&
3282 recognized_kind == MethodRecognizer::kFfiNativeCallbackFunction) {
3283 return BuildFfiNativeCallbackFunction();
3284 }
3285
3286 Fragment instructions;
3287 LocalVariable* instance_variable = NULL;
3288
3289 const bool special_case_nop_async_stack_trace_helper =
3290 !FLAG_causal_async_stacks &&
3291 recognized_kind == MethodRecognizer::kAsyncStackTraceHelper;
3292
3293 const bool special_case_unchecked_cast =
3294 klass.IsTopLevel() && (klass.library() == Library::InternalLibrary()) &&
3295 (target.name() == Symbols::UnsafeCast().raw());
3296
3297 const bool special_case_identical =
3298 klass.IsTopLevel() && (klass.library() == Library::CoreLibrary()) &&
3299 (target.name() == Symbols::Identical().raw());
3300
3301 const bool special_case = special_case_identical ||
3302 special_case_unchecked_cast ||
3303 special_case_nop_async_stack_trace_helper;
3304
3305 // If we cross the Kernel -> VM core library boundary, a [StaticInvocation]
3306 // can appear, but the thing we're calling is not a static method, but a
3307 // factory constructor.
3308 // The `H.LookupStaticmethodByKernelProcedure` will potentially resolve to the
3309 // forwarded constructor.
3310 // In that case we'll make an instance and pass it as first argument.
3311 //
3312 // TODO(27590): Get rid of this after we're using core libraries compiled
3313 // into Kernel.
3314 intptr_t type_args_len = 0;
3315 if (target.IsGenerativeConstructor()) {
3316 if (klass.NumTypeArguments() > 0) {
3317 const TypeArguments& type_arguments =
3318 PeekArgumentsInstantiatedType(klass);
3319 instructions += TranslateInstantiatedTypeArguments(type_arguments);
3320 instructions += AllocateObject(position, klass, 1);
3321 } else {
3322 instructions += AllocateObject(position, klass, 0);
3323 }
3324
3325 instance_variable = MakeTemporary();
3326
3327 instructions += LoadLocal(instance_variable);
3328 } else if (target.IsFactory()) {
3329 // The VM requires currently a TypeArguments object as first parameter for
3330 // every factory constructor :-/ !
3331 //
3332 // TODO(27590): Get rid of this after we're using core libraries compiled
3333 // into Kernel.
3334 const TypeArguments& type_arguments = PeekArgumentsInstantiatedType(klass);
3335 instructions += TranslateInstantiatedTypeArguments(type_arguments);
3336 } else if (!special_case) {
3337 AlternativeReadingScope alt(&reader_);
3338 ReadUInt(); // read argument count.
3339 intptr_t list_length = ReadListLength(); // read types list length.
3340 if (list_length > 0) {
3341 const TypeArguments& type_arguments =
3342 T.BuildTypeArguments(list_length); // read types.
3343 instructions += TranslateInstantiatedTypeArguments(type_arguments);
3344 }
3345 type_args_len = list_length;
3346 }
3347
3348 Array& argument_names = Array::ZoneHandle(Z);
3349 instructions +=
3350 BuildArguments(&argument_names, NULL /* arg count */,
3351 NULL /* positional arg count */); // read arguments.
3352 ASSERT(!special_case ||
3353 target.AreValidArguments(type_args_len, argument_count, argument_names,
3354 NULL));
3355
3356 // Special case identical(x, y) call.
3357 // Note: similar optimization is performed in bytecode flow graph builder -
3358 // see BytecodeFlowGraphBuilder::BuildDirectCall().
3359 // TODO(27590) consider moving this into the inliner and force inline it
3360 // there.
3361 if (special_case_identical) {
3362 ASSERT(argument_count == 2);
3363 instructions +=
3364 StrictCompare(position, Token::kEQ_STRICT, /*number_check=*/true);
3365 } else if (special_case_nop_async_stack_trace_helper) {
3366 ASSERT(argument_count == 1);
3367 instructions += Drop();
3368 instructions += NullConstant();
3369 } else if (special_case_unchecked_cast) {
3370 // Simply do nothing: the result value is already pushed on the stack.
3371 } else {
3372 instructions += StaticCall(position, target, argument_count, argument_names,
3373 ICData::kStatic, &result_type, type_args_len);
3374 if (target.IsGenerativeConstructor()) {
3375 // Drop the result of the constructor call and leave [instance_variable]
3376 // on top-of-stack.
3377 instructions += Drop();
3378 }
3379 }
3380
3381 return instructions;
3382}
3383
3384Fragment StreamingFlowGraphBuilder::BuildConstructorInvocation(
3385 TokenPosition* p) {
3386 TokenPosition position = ReadPosition(); // read position.
3387 if (p != NULL) *p = position;
3388
3389 NameIndex kernel_name =
3390 ReadCanonicalNameReference(); // read target_reference.
3391
3392 Class& klass = Class::ZoneHandle(
3393 Z, H.LookupClassByKernelClass(H.EnclosingName(kernel_name)));
3394
3395 Fragment instructions;
3396
3397 if (klass.NumTypeArguments() > 0) {
3398 if (!klass.IsGeneric()) {
3399 Type& type = Type::ZoneHandle(Z, T.ReceiverType(klass).raw());
3400
3401 // TODO(27590): Can we move this code into [ReceiverType]?
3402 type ^= ClassFinalizer::FinalizeType(*active_class()->klass, type,
3403 ClassFinalizer::kFinalize);
3404 TypeArguments& canonicalized_type_arguments =
3405 TypeArguments::ZoneHandle(Z, type.arguments());
3406 canonicalized_type_arguments =
3407 canonicalized_type_arguments.Canonicalize();
3408 instructions += Constant(canonicalized_type_arguments);
3409 } else {
3410 const TypeArguments& type_arguments =
3411 PeekArgumentsInstantiatedType(klass);
3412 instructions += TranslateInstantiatedTypeArguments(type_arguments);
3413 }
3414
3415 instructions += AllocateObject(position, klass, 1);
3416 } else {
3417 instructions += AllocateObject(position, klass, 0);
3418 }
3419 LocalVariable* variable = MakeTemporary();
3420
3421 instructions += LoadLocal(variable);
3422
3423 Array& argument_names = Array::ZoneHandle(Z);
3424 intptr_t argument_count;
3425 instructions += BuildArguments(
3426 &argument_names, &argument_count,
3427 /* positional_argument_count = */ NULL); // read arguments.
3428
3429 const Function& target = Function::ZoneHandle(
3430 Z, H.LookupConstructorByKernelConstructor(klass, kernel_name));
3431 ++argument_count;
3432 instructions += StaticCall(position, target, argument_count, argument_names,
3433 ICData::kStatic, /* result_type = */ NULL);
3434 return instructions + Drop();
3435}
3436
3437Fragment StreamingFlowGraphBuilder::BuildNot(TokenPosition* position) {
3438 if (position != NULL) *position = TokenPosition::kNoSource;
3439
3440 TokenPosition operand_position = TokenPosition::kNoSource;
3441 Fragment instructions =
3442 BuildExpression(&operand_position); // read expression.
3443 instructions += CheckBoolean(operand_position);
3444 instructions += BooleanNegate();
3445 return instructions;
3446}
3447
3448Fragment StreamingFlowGraphBuilder::BuildNullCheck(TokenPosition* p) {
3449 const TokenPosition position = ReadPosition(); // read position.
3450 if (p != nullptr) *p = position;
3451
3452 TokenPosition operand_position = TokenPosition::kNoSource;
3453 Fragment instructions = BuildExpression(&operand_position);
3454 LocalVariable* expr_temp = MakeTemporary();
3455 instructions += CheckNull(position, expr_temp, String::null_string(),
3456 /* clear_the_temp = */ false);
3457
3458 return instructions;
3459}
3460
3461// Translate the logical expression (lhs && rhs or lhs || rhs) in a context
3462// where a value is required.
3463//
3464// Translation accumulates short-circuit exits from logical
3465// subexpressions in the side_exits. These exits are expected to store
3466// true and false into :expr_temp.
3467//
3468// The result of evaluating the last
3469// expression in chain would be stored in :expr_temp directly to avoid
3470// generating graph like:
3471//
3472// if (v) :expr_temp = true; else :expr_temp = false;
3473//
3474// Outer negations are stripped and instead negation is passed down via
3475// negated parameter.
3476Fragment StreamingFlowGraphBuilder::TranslateLogicalExpressionForValue(
3477 bool negated,
3478 TestFragment* side_exits) {
3479 TestFragment left = TranslateConditionForControl().Negate(negated);
3480 LogicalOperator op = static_cast<LogicalOperator>(ReadByte());
3481 if (negated) {
3482 op = (op == kAnd) ? kOr : kAnd;
3483 }
3484
3485 // Short circuit the control flow after the left hand side condition.
3486 if (op == kAnd) {
3487 side_exits->false_successor_addresses->AddArray(
3488 *left.false_successor_addresses);
3489 } else {
3490 side_exits->true_successor_addresses->AddArray(
3491 *left.true_successor_addresses);
3492 }
3493
3494 // Skip negations of the right hand side.
3495 while (PeekTag() == kNot) {
3496 SkipBytes(1);
3497 negated = !negated;
3498 }
3499
3500 Fragment right_value(op == kAnd
3501 ? left.CreateTrueSuccessor(flow_graph_builder_)
3502 : left.CreateFalseSuccessor(flow_graph_builder_));
3503
3504 if (PeekTag() == kLogicalExpression) {
3505 SkipBytes(1);
3506 // Handle nested logical expressions specially to avoid materializing
3507 // intermediate boolean values.
3508 right_value += TranslateLogicalExpressionForValue(negated, side_exits);
3509 } else {
3510 // Arbitrary expression on the right hand side. Translate it for value.
3511 TokenPosition position = TokenPosition::kNoSource;
3512 right_value += BuildExpression(&position); // read expression.
3513
3514 // Check if the top of the stack is known to be a non-nullable boolean.
3515 // Note that in strong mode we know that any value that reaches here
3516 // is at least a nullable boolean - so there is no need to compare
3517 // with true like in Dart 1.
3518 Definition* top = stack()->definition();
3519 const bool is_bool = top->IsStrictCompare() || top->IsBooleanNegate();
3520 if (!is_bool) {
3521 right_value += CheckBoolean(position);
3522 }
3523 if (negated) {
3524 right_value += BooleanNegate();
3525 }
3526 right_value += StoreLocal(TokenPosition::kNoSource,
3527 parsed_function()->expression_temp_var());
3528 right_value += Drop();
3529 }
3530
3531 return Fragment(left.entry, right_value.current);
3532}
3533
3534Fragment StreamingFlowGraphBuilder::BuildLogicalExpression(
3535 TokenPosition* position) {
3536 if (position != NULL) *position = TokenPosition::kNoSource;
3537
3538 TestFragment exits;
3539 exits.true_successor_addresses = new TestFragment::SuccessorAddressArray(2);
3540 exits.false_successor_addresses = new TestFragment::SuccessorAddressArray(2);
3541
3542 JoinEntryInstr* join = BuildJoinEntry();
3543 Fragment instructions =
3544 TranslateLogicalExpressionForValue(/*negated=*/false, &exits);
3545 instructions += Goto(join);
3546
3547 // Generate :expr_temp = true if needed and connect it to true side-exits.
3548 if (!exits.true_successor_addresses->is_empty()) {
3549 Fragment constant_fragment(exits.CreateTrueSuccessor(flow_graph_builder_));
3550 constant_fragment += Constant(Bool::Get(true));
3551 constant_fragment += StoreLocal(TokenPosition::kNoSource,
3552 parsed_function()->expression_temp_var());
3553 constant_fragment += Drop();
3554 constant_fragment += Goto(join);
3555 }
3556
3557 // Generate :expr_temp = false if needed and connect it to false side-exits.
3558 if (!exits.false_successor_addresses->is_empty()) {
3559 Fragment constant_fragment(exits.CreateFalseSuccessor(flow_graph_builder_));
3560 constant_fragment += Constant(Bool::Get(false));
3561 constant_fragment += StoreLocal(TokenPosition::kNoSource,
3562 parsed_function()->expression_temp_var());
3563 constant_fragment += Drop();
3564 constant_fragment += Goto(join);
3565 }
3566
3567 return Fragment(instructions.entry, join) +
3568 LoadLocal(parsed_function()->expression_temp_var());
3569}
3570
3571Fragment StreamingFlowGraphBuilder::BuildConditionalExpression(
3572 TokenPosition* position) {
3573 if (position != NULL) *position = TokenPosition::kNoSource;
3574
3575 TestFragment condition = TranslateConditionForControl(); // read condition.
3576
3577 Value* top = stack();
3578 Fragment then_fragment(condition.CreateTrueSuccessor(flow_graph_builder_));
3579 then_fragment += BuildExpression(); // read then.
3580 then_fragment += StoreLocal(TokenPosition::kNoSource,
3581 parsed_function()->expression_temp_var());
3582 then_fragment += Drop();
3583 ASSERT(stack() == top);
3584
3585 Fragment otherwise_fragment(
3586 condition.CreateFalseSuccessor(flow_graph_builder_));
3587 otherwise_fragment += BuildExpression(); // read otherwise.
3588 otherwise_fragment += StoreLocal(TokenPosition::kNoSource,
3589 parsed_function()->expression_temp_var());
3590 otherwise_fragment += Drop();
3591 ASSERT(stack() == top);
3592
3593 JoinEntryInstr* join = BuildJoinEntry();
3594 then_fragment += Goto(join);
3595 otherwise_fragment += Goto(join);
3596
3597 SkipOptionalDartType(); // read unused static type.
3598
3599 return Fragment(condition.entry, join) +
3600 LoadLocal(parsed_function()->expression_temp_var());
3601}
3602
3603Fragment StreamingFlowGraphBuilder::BuildStringConcatenation(TokenPosition* p) {
3604 TokenPosition position = ReadPosition(); // read position.
3605 if (p != NULL) *p = position;
3606
3607 intptr_t length = ReadListLength(); // read list length.
3608 // Note: there will be "length" expressions.
3609
3610 Fragment instructions;
3611 if (length == 1) {
3612 instructions += BuildExpression(); // read expression.
3613 instructions += StringInterpolateSingle(position);
3614 } else {
3615 // The type arguments for CreateArray.
3616 instructions += Constant(TypeArguments::ZoneHandle(Z));
3617 instructions += IntConstant(length);
3618 instructions += CreateArray();
3619 LocalVariable* array = MakeTemporary();
3620
3621 for (intptr_t i = 0; i < length; ++i) {
3622 instructions += LoadLocal(array);
3623 instructions += IntConstant(i);
3624 instructions += BuildExpression(); // read ith expression.
3625 instructions += StoreIndexed(kArrayCid);
3626 }
3627
3628 instructions += StringInterpolate(position);
3629 }
3630
3631 return instructions;
3632}
3633
3634Fragment StreamingFlowGraphBuilder::BuildIsExpression(TokenPosition* p) {
3635 TokenPosition position = ReadPosition(); // read position.
3636 if (p != NULL) *p = position;
3637
3638 if (translation_helper_.info().kernel_binary_version() >= 38) {
3639 // We do not use the library mode for the type test, which is indicated by
3640 // the flag kIsExpressionFlagForNonNullableByDefault.
3641 ReadFlags();
3642 }
3643
3644 Fragment instructions = BuildExpression(); // read operand.
3645
3646 const AbstractType& type = T.BuildType(); // read type.
3647
3648 // The VM does not like an instanceOf call with a dynamic type. We need to
3649 // special case this situation by detecting a top type.
3650 if (type.IsTopTypeForInstanceOf()) {
3651 // Evaluate the expression on the left but ignore its result.
3652 instructions += Drop();
3653
3654 // Let condition be always true.
3655 instructions += Constant(Bool::True());
3656 } else {
3657 // See if simple instanceOf is applicable.
3658 if (dart::SimpleInstanceOfType(type)) {
3659 instructions += Constant(type);
3660 instructions += InstanceCall(
3661 position, Library::PrivateCoreLibName(Symbols::_simpleInstanceOf()),
3662 Token::kIS, 2, 2); // 2 checked arguments.
3663 return instructions;
3664 }
3665
3666 if (!type.IsInstantiated(kCurrentClass)) {
3667 instructions += LoadInstantiatorTypeArguments();
3668 } else {
3669 instructions += NullConstant();
3670 }
3671
3672 if (!type.IsInstantiated(kFunctions)) {
3673 instructions += LoadFunctionTypeArguments();
3674 } else {
3675 instructions += NullConstant();
3676 }
3677
3678 instructions += Constant(type);
3679
3680 instructions += InstanceCall(
3681 position, Library::PrivateCoreLibName(Symbols::_instanceOf()),
3682 Token::kIS, 4);
3683 }
3684 return instructions;
3685}
3686
3687Fragment StreamingFlowGraphBuilder::BuildAsExpression(TokenPosition* p) {
3688 TokenPosition position = ReadPosition(); // read position.
3689 if (p != NULL) *p = position;
3690
3691 const uint8_t flags = ReadFlags(); // read flags.
3692 const bool is_type_error = (flags & kAsExpressionFlagTypeError) != 0;
3693
3694 Fragment instructions = BuildExpression(); // read operand.
3695
3696 const AbstractType& type = T.BuildType(); // read type.
3697 if (type.IsInstantiated() && type.IsTopTypeForSubtyping()) {
3698 // We already evaluated the operand on the left and just leave it there as
3699 // the result of the `obj as dynamic` expression.
3700 } else {
3701 // We do not care whether the 'as' cast as implicitly added by the frontend
3702 // or explicitly written by the user, in both cases we use an assert
3703 // assignable.
3704 instructions += LoadLocal(MakeTemporary());
3705 instructions += B->AssertAssignableLoadTypeArguments(
3706 position, type,
3707 is_type_error ? Symbols::Empty() : Symbols::InTypeCast(),
3708 AssertAssignableInstr::kInsertedByFrontend);
3709 instructions += Drop();
3710 }
3711 return instructions;
3712}
3713
3714Fragment StreamingFlowGraphBuilder::BuildTypeLiteral(TokenPosition* position) {
3715 if (position != NULL) *position = TokenPosition::kNoSource;
3716
3717 const AbstractType& type = T.BuildType(); // read type.
3718 Fragment instructions;
3719 if (type.IsInstantiated()) {
3720 instructions += Constant(type);
3721 } else {
3722 if (!type.IsInstantiated(kCurrentClass)) {
3723 instructions += LoadInstantiatorTypeArguments();
3724 } else {
3725 instructions += NullConstant();
3726 }
3727 if (!type.IsInstantiated(kFunctions)) {
3728 instructions += LoadFunctionTypeArguments();
3729 } else {
3730 instructions += NullConstant();
3731 }
3732 instructions += InstantiateType(type);
3733 }
3734 return instructions;
3735}
3736
3737Fragment StreamingFlowGraphBuilder::BuildThisExpression(
3738 TokenPosition* position) {
3739 if (position != NULL) *position = TokenPosition::kNoSource;
3740
3741 return LoadLocal(parsed_function()->receiver_var());
3742}
3743
3744Fragment StreamingFlowGraphBuilder::BuildRethrow(TokenPosition* p) {
3745 TokenPosition position = ReadPosition(); // read position.
3746 if (p != NULL) *p = position;
3747
3748 Fragment instructions = DebugStepCheck(position);
3749 instructions += LoadLocal(catch_block()->exception_var());
3750 instructions += LoadLocal(catch_block()->stack_trace_var());
3751 instructions += RethrowException(position, catch_block()->catch_try_index());
3752
3753 return instructions;
3754}
3755
3756Fragment StreamingFlowGraphBuilder::BuildThrow(TokenPosition* p) {
3757 TokenPosition position = ReadPosition(); // read position.
3758 if (p != NULL) *p = position;
3759
3760 Fragment instructions;
3761
3762 instructions += BuildExpression(); // read expression.
3763
3764 if (NeedsDebugStepCheck(stack(), position)) {
3765 instructions = DebugStepCheck(position) + instructions;
3766 }
3767 instructions += ThrowException(position);
3768 ASSERT(instructions.is_closed());
3769
3770 return instructions;
3771}
3772
3773Fragment StreamingFlowGraphBuilder::BuildListLiteral(TokenPosition* p) {
3774 TokenPosition position = ReadPosition(); // read position.
3775 if (p != NULL) *p = position;
3776
3777 const TypeArguments& type_arguments = T.BuildTypeArguments(1); // read type.
3778 intptr_t length = ReadListLength(); // read list length.
3779 // Note: there will be "length" expressions.
3780
3781 // The type argument for the factory call.
3782 Fragment instructions = TranslateInstantiatedTypeArguments(type_arguments);
3783 LocalVariable* type = MakeTemporary();
3784
3785 instructions += LoadLocal(type);
3786 if (length == 0) {
3787 instructions += Constant(Object::empty_array());
3788 } else {
3789 // The type arguments for CreateArray.
3790 instructions += LoadLocal(type);
3791 instructions += IntConstant(length);
3792 instructions += CreateArray();
3793
3794 LocalVariable* array = MakeTemporary();
3795 for (intptr_t i = 0; i < length; ++i) {
3796 instructions += LoadLocal(array);
3797 instructions += IntConstant(i);
3798 instructions += BuildExpression(); // read ith expression.
3799 instructions += StoreIndexed(kArrayCid);
3800 }
3801 }
3802
3803 const Class& factory_class =
3804 Class::Handle(Z, Library::LookupCoreClass(Symbols::List()));
3805 const Function& factory_method = Function::ZoneHandle(
3806 Z, factory_class.LookupFactory(
3807 Library::PrivateCoreLibName(Symbols::ListLiteralFactory())));
3808
3809 instructions += StaticCall(position, factory_method, 2, ICData::kStatic);
3810 instructions += DropTempsPreserveTop(1); // Instantiated type_arguments.
3811 return instructions;
3812}
3813
3814Fragment StreamingFlowGraphBuilder::BuildMapLiteral(TokenPosition* p) {
3815 TokenPosition position = ReadPosition(); // read position.
3816 if (p != NULL) *p = position;
3817
3818 const TypeArguments& type_arguments =
3819 T.BuildTypeArguments(2); // read key_type and value_type.
3820
3821 // The type argument for the factory call `new Map<K, V>._fromLiteral(List)`.
3822 Fragment instructions = TranslateInstantiatedTypeArguments(type_arguments);
3823
3824 intptr_t length = ReadListLength(); // read list length.
3825 // Note: there will be "length" map entries (i.e. key and value expressions).
3826
3827 if (length == 0) {
3828 instructions += Constant(Object::empty_array());
3829 } else {
3830 // The type arguments for `new List<X>(int len)`.
3831 instructions += Constant(TypeArguments::ZoneHandle(Z));
3832
3833 // We generate a list of tuples, i.e. [key1, value1, ..., keyN, valueN].
3834 instructions += IntConstant(2 * length);
3835 instructions += CreateArray();
3836
3837 LocalVariable* array = MakeTemporary();
3838 for (intptr_t i = 0; i < length; ++i) {
3839 instructions += LoadLocal(array);
3840 instructions += IntConstant(2 * i);
3841 instructions += BuildExpression(); // read ith key.
3842 instructions += StoreIndexed(kArrayCid);
3843
3844 instructions += LoadLocal(array);
3845 instructions += IntConstant(2 * i + 1);
3846 instructions += BuildExpression(); // read ith value.
3847 instructions += StoreIndexed(kArrayCid);
3848 }
3849 }
3850
3851 const Class& map_class =
3852 Class::Handle(Z, Library::LookupCoreClass(Symbols::Map()));
3853 const Function& factory_method = Function::ZoneHandle(
3854 Z, map_class.LookupFactory(
3855 Library::PrivateCoreLibName(Symbols::MapLiteralFactory())));
3856
3857 return instructions +
3858 StaticCall(position, factory_method, 2, ICData::kStatic);
3859}
3860
3861Fragment StreamingFlowGraphBuilder::BuildFunctionExpression() {
3862 ReadPosition(); // read position.
3863 return BuildFunctionNode(TokenPosition::kNoSource, StringIndex());
3864}
3865
3866Fragment StreamingFlowGraphBuilder::BuildLet(TokenPosition* position) {
3867 if (position != NULL) *position = TokenPosition::kNoSource;
3868
3869 Fragment instructions = BuildVariableDeclaration(); // read variable.
3870 instructions += BuildExpression(); // read body.
3871 return instructions;
3872}
3873
3874Fragment StreamingFlowGraphBuilder::BuildBlockExpression() {
3875 block_expression_depth_inc();
3876 const intptr_t offset = ReaderOffset() - 1; // Include the tag.
3877
3878 Fragment instructions;
3879
3880 instructions += EnterScope(offset);
3881 const intptr_t list_length = ReadListLength(); // read number of statements.
3882 for (intptr_t i = 0; i < list_length; ++i) {
3883 instructions += BuildStatement(); // read ith statement.
3884 }
3885 instructions += BuildExpression(); // read expression (inside scope).
3886 instructions += ExitScope(offset);
3887
3888 block_expression_depth_dec();
3889 return instructions;
3890}
3891
3892Fragment StreamingFlowGraphBuilder::BuildBigIntLiteral(
3893 TokenPosition* position) {
3894 if (position != NULL) *position = TokenPosition::kNoSource;
3895
3896 const String& value =
3897 H.DartString(ReadStringReference()); // read index into string table.
3898 const Integer& integer = Integer::ZoneHandle(Z, Integer::NewCanonical(value));
3899 if (integer.IsNull()) {
3900 H.ReportError(script_, TokenPosition::kNoSource,
3901 "Integer literal %s is out of range", value.ToCString());
3902 UNREACHABLE();
3903 }
3904 return Constant(integer);
3905}
3906
3907Fragment StreamingFlowGraphBuilder::BuildStringLiteral(
3908 TokenPosition* position) {
3909 if (position != NULL) *position = TokenPosition::kNoSource;
3910
3911 return Constant(H.DartSymbolPlain(
3912 ReadStringReference())); // read index into string table.
3913}
3914
3915Fragment StreamingFlowGraphBuilder::BuildIntLiteral(uint8_t payload,
3916 TokenPosition* position) {
3917 if (position != NULL) *position = TokenPosition::kNoSource;
3918
3919 int64_t value = static_cast<int32_t>(payload) - SpecializedIntLiteralBias;
3920 return IntConstant(value);
3921}
3922
3923Fragment StreamingFlowGraphBuilder::BuildIntLiteral(bool is_negative,
3924 TokenPosition* position) {
3925 if (position != NULL) *position = TokenPosition::kNoSource;
3926
3927 int64_t value = is_negative ? -static_cast<int64_t>(ReadUInt())
3928 : ReadUInt(); // read value.
3929 return IntConstant(value);
3930}
3931
3932Fragment StreamingFlowGraphBuilder::BuildDoubleLiteral(
3933 TokenPosition* position) {
3934 if (position != NULL) *position = TokenPosition::kNoSource;
3935
3936 Double& constant = Double::ZoneHandle(
3937 Z, Double::NewCanonical(ReadDouble())); // read double.
3938 return Constant(constant);
3939}
3940
3941Fragment StreamingFlowGraphBuilder::BuildBoolLiteral(bool value,
3942 TokenPosition* position) {
3943 if (position != NULL) *position = TokenPosition::kNoSource;
3944
3945 return Constant(Bool::Get(value));
3946}
3947
3948Fragment StreamingFlowGraphBuilder::BuildNullLiteral(TokenPosition* position) {
3949 if (position != NULL) *position = TokenPosition::kNoSource;
3950
3951 return Constant(Instance::ZoneHandle(Z, Instance::null()));
3952}
3953
3954Fragment StreamingFlowGraphBuilder::BuildFutureNullValue(
3955 TokenPosition* position) {
3956 if (position != NULL) *position = TokenPosition::kNoSource;
3957 const Class& future = Class::Handle(Z, I->object_store()->future_class());
3958 ASSERT(!future.IsNull());
3959 const Function& constructor =
3960 Function::ZoneHandle(Z, future.LookupFunction(Symbols::FutureValue()));
3961 ASSERT(!constructor.IsNull());
3962
3963 Fragment instructions;
3964 instructions += BuildNullLiteral(position);
3965 instructions += StaticCall(TokenPosition::kNoSource, constructor,
3966 /* argument_count = */ 1, ICData::kStatic);
3967 return instructions;
3968}
3969
3970Fragment StreamingFlowGraphBuilder::BuildConstantExpression(
3971 TokenPosition* position,
3972 Tag tag) {
3973 TokenPosition p = TokenPosition::kNoSource;
3974 if (tag == kConstantExpression) {
3975 p = ReadPosition();
3976 SkipDartType();
3977 }
3978 if (position != nullptr) *position = p;
3979 const intptr_t constant_offset = ReadUInt();
3980 Fragment result = Constant(
3981 Object::ZoneHandle(Z, constant_reader_.ReadConstant(constant_offset)));
3982 return result;
3983}
3984
3985Fragment StreamingFlowGraphBuilder::BuildPartialTearoffInstantiation(
3986 TokenPosition* position) {
3987 if (position != NULL) *position = TokenPosition::kNoSource;
3988
3989 // Create a copy of the closure.
3990
3991 Fragment instructions = BuildExpression();
3992 LocalVariable* original_closure = MakeTemporary();
3993
3994 instructions += AllocateObject(
3995 TokenPosition::kNoSource,
3996 Class::ZoneHandle(Z, I->object_store()->closure_class()), 0);
3997 LocalVariable* new_closure = MakeTemporary();
3998
3999 intptr_t num_type_args = ReadListLength();
4000 const TypeArguments& type_args = T.BuildTypeArguments(num_type_args);
4001 instructions += TranslateInstantiatedTypeArguments(type_args);
4002 LocalVariable* type_args_vec = MakeTemporary();
4003
4004 // Check the bounds.
4005 //
4006 // TODO(sjindel): We should be able to skip this check in many cases, e.g.
4007 // when the closure is coming from a tearoff of a top-level method or from a
4008 // local closure.
4009 instructions += LoadLocal(original_closure);
4010 instructions += LoadLocal(type_args_vec);
4011 const Library& dart_internal = Library::Handle(Z, Library::InternalLibrary());
4012 const Function& bounds_check_function = Function::ZoneHandle(
4013 Z, dart_internal.LookupFunctionAllowPrivate(
4014 Symbols::BoundsCheckForPartialInstantiation()));
4015 ASSERT(!bounds_check_function.IsNull());
4016 instructions += StaticCall(TokenPosition::kNoSource, bounds_check_function, 2,
4017 ICData::kStatic);
4018 instructions += Drop();
4019
4020 instructions += LoadLocal(new_closure);
4021 instructions += LoadLocal(type_args_vec);
4022 instructions += flow_graph_builder_->StoreInstanceField(
4023 TokenPosition::kNoSource, Slot::Closure_delayed_type_arguments(),
4024 StoreInstanceFieldInstr::Kind::kInitializing);
4025 instructions += Drop(); // Drop type args.
4026
4027 // Copy over the target function.
4028 instructions += LoadLocal(new_closure);
4029 instructions += LoadLocal(original_closure);
4030 instructions +=
4031 flow_graph_builder_->LoadNativeField(Slot::Closure_function());
4032 instructions += flow_graph_builder_->StoreInstanceField(
4033 TokenPosition::kNoSource, Slot::Closure_function(),
4034 StoreInstanceFieldInstr::Kind::kInitializing);
4035
4036 // Copy over the instantiator type arguments.
4037 instructions += LoadLocal(new_closure);
4038 instructions += LoadLocal(original_closure);
4039 instructions += flow_graph_builder_->LoadNativeField(
4040 Slot::Closure_instantiator_type_arguments());
4041 instructions += flow_graph_builder_->StoreInstanceField(
4042 TokenPosition::kNoSource, Slot::Closure_instantiator_type_arguments(),
4043 StoreInstanceFieldInstr::Kind::kInitializing);
4044
4045 // Copy over the function type arguments.
4046 instructions += LoadLocal(new_closure);
4047 instructions += LoadLocal(original_closure);
4048 instructions += flow_graph_builder_->LoadNativeField(
4049 Slot::Closure_function_type_arguments());
4050 instructions += flow_graph_builder_->StoreInstanceField(
4051 TokenPosition::kNoSource, Slot::Closure_function_type_arguments(),
4052 StoreInstanceFieldInstr::Kind::kInitializing);
4053
4054 // Copy over the context.
4055 instructions += LoadLocal(new_closure);
4056 instructions += LoadLocal(original_closure);
4057 instructions += flow_graph_builder_->LoadNativeField(Slot::Closure_context());
4058 instructions += flow_graph_builder_->StoreInstanceField(
4059 TokenPosition::kNoSource, Slot::Closure_context(),
4060 StoreInstanceFieldInstr::Kind::kInitializing);
4061
4062 instructions += DropTempsPreserveTop(1); // Drop old closure.
4063
4064 return instructions;
4065}
4066
4067Fragment StreamingFlowGraphBuilder::BuildLibraryPrefixAction(
4068 TokenPosition* position,
4069 const String& selector) {
4070 const intptr_t dependency_index = ReadUInt();
4071 const Library& current_library = Library::Handle(
4072 Z, Class::Handle(Z, parsed_function()->function().origin()).library());
4073 const Array& dependencies = Array::Handle(Z, current_library.dependencies());
4074 const LibraryPrefix& prefix =
4075 LibraryPrefix::CheckedZoneHandle(Z, dependencies.At(dependency_index));
4076 const Function& function =
4077 Function::ZoneHandle(Z, Library::Handle(Z, Library::CoreLibrary())
4078 .LookupFunctionAllowPrivate(selector));
4079 ASSERT(!function.IsNull());
4080 Fragment instructions;
4081 instructions += Constant(prefix);
4082 instructions +=
4083 StaticCall(TokenPosition::kNoSource, function, 1, ICData::kStatic);
4084 return instructions;
4085}
4086
4087Fragment StreamingFlowGraphBuilder::BuildExpressionStatement() {
4088 Fragment instructions = BuildExpression(); // read expression.
4089 instructions += Drop();
4090 return instructions;
4091}
4092
4093Fragment StreamingFlowGraphBuilder::BuildBlock() {
4094 intptr_t offset = ReaderOffset() - 1; // Include the tag.
4095
4096 Fragment instructions;
4097
4098 instructions += EnterScope(offset);
4099 intptr_t list_length = ReadListLength(); // read number of statements.
4100 for (intptr_t i = 0; i < list_length; ++i) {
4101 if (instructions.is_open()) {
4102 instructions += BuildStatement(); // read ith statement.
4103 } else {
4104 SkipStatement(); // read ith statement.
4105 }
4106 }
4107 instructions += ExitScope(offset);
4108
4109 return instructions;
4110}
4111
4112Fragment StreamingFlowGraphBuilder::BuildEmptyStatement() {
4113 return Fragment();
4114}
4115
4116Fragment StreamingFlowGraphBuilder::BuildAssertBlock() {
4117 if (!I->asserts()) {
4118 SkipStatementList();
4119 return Fragment();
4120 }
4121
4122 intptr_t offset = ReaderOffset() - 1; // Include the tag.
4123
4124 Fragment instructions;
4125
4126 instructions += EnterScope(offset);
4127 intptr_t list_length = ReadListLength(); // read number of statements.
4128 for (intptr_t i = 0; i < list_length; ++i) {
4129 if (instructions.is_open()) {
4130 instructions += BuildStatement(); // read ith statement.
4131 } else {
4132 SkipStatement(); // read ith statement.
4133 }
4134 }
4135 instructions += ExitScope(offset);
4136
4137 return instructions;
4138}
4139
4140Fragment StreamingFlowGraphBuilder::BuildAssertStatement() {
4141 if (!I->asserts()) {
4142 SetOffset(ReaderOffset() - 1); // Include the tag.
4143 SkipStatement(); // read this statement.
4144 return Fragment();
4145 }
4146
4147 TargetEntryInstr* then;
4148 TargetEntryInstr* otherwise;
4149
4150 Fragment instructions;
4151 // Asserts can be of the following two kinds:
4152 //
4153 // * `assert(expr)`
4154 // * `assert(() { ... })`
4155 //
4156 // The call to `_AssertionError._evaluateAssertion()` will take care of both
4157 // and returns a boolean.
4158 instructions += BuildExpression(); // read condition.
4159
4160 const TokenPosition condition_start_offset =
4161 ReadPosition(); // read condition start offset.
4162 const TokenPosition condition_end_offset =
4163 ReadPosition(); // read condition end offset.
4164
4165 instructions += EvaluateAssertion();
4166 instructions += CheckBoolean(condition_start_offset);
4167 instructions += Constant(Bool::True());
4168 instructions += BranchIfEqual(&then, &otherwise, false);
4169
4170 const Class& klass =
4171 Class::ZoneHandle(Z, Library::LookupCoreClass(Symbols::AssertionError()));
4172 ASSERT(!klass.IsNull());
4173 const Function& target = Function::ZoneHandle(
4174 Z, klass.LookupStaticFunctionAllowPrivate(Symbols::ThrowNew()));
4175 ASSERT(!target.IsNull());
4176
4177 // Build equivalent of `throw _AssertionError._throwNew(start, end, message)`
4178 // expression. We build throw (even through _throwNew already throws) because
4179 // call is not a valid last instruction for the block. Blocks can only
4180 // terminate with explicit control flow instructions (Branch, Goto, Return
4181 // or Throw).
4182 Fragment otherwise_fragment(otherwise);
4183 otherwise_fragment += IntConstant(condition_start_offset.Pos());
4184 otherwise_fragment += IntConstant(condition_end_offset.Pos());
4185 Tag tag = ReadTag(); // read (first part of) message.
4186 if (tag == kSomething) {
4187 otherwise_fragment += BuildExpression(); // read (rest of) message.
4188 } else {
4189 otherwise_fragment += Constant(Instance::ZoneHandle(Z)); // null.
4190 }
4191
4192 // Note: condition_start_offset points to the first token after the opening
4193 // paren, not the beginning of 'assert'.
4194 otherwise_fragment +=
4195 StaticCall(condition_start_offset, target, 3, ICData::kStatic);
4196 otherwise_fragment += ThrowException(TokenPosition::kNoSource);
4197 otherwise_fragment += Drop();
4198
4199 return Fragment(instructions.entry, then);
4200}
4201
4202Fragment StreamingFlowGraphBuilder::BuildLabeledStatement() {
4203 // There can be serveral cases:
4204 //
4205 // * the body contains a break
4206 // * the body doesn't contain a break
4207 //
4208 // * translating the body results in a closed fragment
4209 // * translating the body results in a open fragment
4210 //
4211 // => We will only know which case we are in after the body has been
4212 // traversed.
4213
4214 BreakableBlock block(flow_graph_builder_);
4215 Fragment instructions = BuildStatement(); // read body.
4216 if (block.HadJumper()) {
4217 if (instructions.is_open()) {
4218 instructions += Goto(block.destination());
4219 }
4220 return Fragment(instructions.entry, block.destination());
4221 } else {
4222 return instructions;
4223 }
4224}
4225
4226Fragment StreamingFlowGraphBuilder::BuildBreakStatement() {
4227 TokenPosition position = ReadPosition(); // read position.
4228 intptr_t target_index = ReadUInt(); // read target index.
4229
4230 TryFinallyBlock* outer_finally = NULL;
4231 intptr_t target_context_depth = -1;
4232 JoinEntryInstr* destination = breakable_block()->BreakDestination(
4233 target_index, &outer_finally, &target_context_depth);
4234
4235 Fragment instructions;
4236 // Break statement should pause before manipulation of context, which
4237 // will possibly cause debugger having incorrect context object.
4238 if (NeedsDebugStepCheck(parsed_function()->function(), position)) {
4239 instructions += DebugStepCheck(position);
4240 }
4241 instructions +=
4242 TranslateFinallyFinalizers(outer_finally, target_context_depth);
4243 if (instructions.is_open()) {
4244 instructions += Goto(destination);
4245 }
4246 return instructions;
4247}
4248
4249Fragment StreamingFlowGraphBuilder::BuildWhileStatement() {
4250 ASSERT(block_expression_depth() == 0); // no while in block-expr
4251 loop_depth_inc();
4252 const TokenPosition position = ReadPosition(); // read position.
4253 TestFragment condition = TranslateConditionForControl(); // read condition.
4254 const Fragment body = BuildStatement(); // read body
4255
4256 Fragment body_entry(condition.CreateTrueSuccessor(flow_graph_builder_));
4257 body_entry += body;
4258
4259 Instruction* entry;
4260 if (body_entry.is_open()) {
4261 JoinEntryInstr* join = BuildJoinEntry();
4262 body_entry += Goto(join);
4263
4264 Fragment loop(join);
4265 ASSERT(B->GetStackDepth() == 0);
4266 loop += CheckStackOverflow(position);
4267 loop.current->LinkTo(condition.entry);
4268
4269 entry = Goto(join).entry;
4270 } else {
4271 entry = condition.entry;
4272 }
4273
4274 loop_depth_dec();
4275 return Fragment(entry, condition.CreateFalseSuccessor(flow_graph_builder_));
4276}
4277
4278Fragment StreamingFlowGraphBuilder::BuildDoStatement() {
4279 ASSERT(block_expression_depth() == 0); // no do-while in block-expr
4280 loop_depth_inc();
4281 const TokenPosition position = ReadPosition(); // read position.
4282 Fragment body = BuildStatement(); // read body.
4283
4284 if (body.is_closed()) {
4285 SkipExpression(); // read condition.
4286 loop_depth_dec();
4287 return body;
4288 }
4289
4290 TestFragment condition = TranslateConditionForControl();
4291
4292 JoinEntryInstr* join = BuildJoinEntry();
4293 Fragment loop(join);
4294 ASSERT(B->GetStackDepth() == 0);
4295 loop += CheckStackOverflow(position);
4296 loop += body;
4297 loop <<= condition.entry;
4298
4299 condition.IfTrueGoto(flow_graph_builder_, join);
4300
4301 loop_depth_dec();
4302 return Fragment(
4303 new (Z) GotoInstr(join, CompilerState::Current().GetNextDeoptId()),
4304 condition.CreateFalseSuccessor(flow_graph_builder_));
4305}
4306
4307Fragment StreamingFlowGraphBuilder::BuildForStatement() {
4308 intptr_t offset = ReaderOffset() - 1; // Include the tag.
4309
4310 const TokenPosition position = ReadPosition(); // read position.
4311
4312 Fragment declarations;
4313
4314 loop_depth_inc();
4315
4316 const LocalScope* context_scope = nullptr;
4317 declarations += EnterScope(offset, &context_scope);
4318
4319 intptr_t list_length = ReadListLength(); // read number of variables.
4320 for (intptr_t i = 0; i < list_length; ++i) {
4321 declarations += BuildVariableDeclaration(); // read ith variable.
4322 }
4323
4324 Tag tag = ReadTag(); // Read first part of condition.
4325 TestFragment condition;
4326 BlockEntryInstr* body_entry;
4327 BlockEntryInstr* loop_exit;
4328 if (tag != kNothing) {
4329 condition = TranslateConditionForControl();
4330 body_entry = condition.CreateTrueSuccessor(flow_graph_builder_);
4331 loop_exit = condition.CreateFalseSuccessor(flow_graph_builder_);
4332 } else {
4333 body_entry = BuildJoinEntry();
4334 loop_exit = BuildJoinEntry();
4335 }
4336
4337 Fragment updates;
4338 list_length = ReadListLength(); // read number of updates.
4339 for (intptr_t i = 0; i < list_length; ++i) {
4340 updates += BuildExpression(); // read ith update.
4341 updates += Drop();
4342 }
4343
4344 Fragment body(body_entry);
4345 body += BuildStatement(); // read body.
4346
4347 if (body.is_open()) {
4348 // We allocated a fresh context before the loop which contains captured
4349 // [ForStatement] variables. Before jumping back to the loop entry we clone
4350 // the context object (at same depth) which ensures the next iteration of
4351 // the body gets a fresh set of [ForStatement] variables (with the old
4352 // (possibly updated) values).
4353 if (context_scope->num_context_variables() > 0) {
4354 body += CloneContext(context_scope->context_slots());
4355 }
4356
4357 body += updates;
4358 JoinEntryInstr* join = BuildJoinEntry();
4359 declarations += Goto(join);
4360 body += Goto(join);
4361
4362 Fragment loop(join);
4363 loop += CheckStackOverflow(position); // may have non-empty stack
4364 if (condition.entry != nullptr) {
4365 loop <<= condition.entry;
4366 } else {
4367 loop += Goto(body_entry->AsJoinEntry());
4368 }
4369 } else {
4370 if (condition.entry != nullptr) {
4371 declarations <<= condition.entry;
4372 } else {
4373 declarations += Goto(body_entry->AsJoinEntry());
4374 }
4375 }
4376
4377 Fragment loop(declarations.entry, loop_exit);
4378
4379 loop += ExitScope(offset);
4380
4381 loop_depth_dec();
4382
4383 return loop;
4384}
4385
4386Fragment StreamingFlowGraphBuilder::BuildForInStatement(bool async) {
4387 intptr_t offset = ReaderOffset() - 1; // Include the tag.
4388
4389 const TokenPosition position = ReadPosition(); // read position.
4390 TokenPosition body_position = ReadPosition(); // read body position.
4391 intptr_t variable_kernel_position = ReaderOffset() + data_program_offset_;
4392 SkipVariableDeclaration(); // read variable.
4393
4394 TokenPosition iterable_position = TokenPosition::kNoSource;
4395 Fragment instructions =
4396 BuildExpression(&iterable_position); // read iterable.
4397
4398 const String& iterator_getter =
4399 String::ZoneHandle(Z, Field::GetterSymbol(Symbols::Iterator()));
4400 instructions +=
4401 InstanceCall(iterable_position, iterator_getter, Token::kGET, 1);
4402 LocalVariable* iterator = scopes()->iterator_variables[for_in_depth()];
4403 instructions += StoreLocal(TokenPosition::kNoSource, iterator);
4404 instructions += Drop();
4405
4406 for_in_depth_inc();
4407 loop_depth_inc();
4408 Fragment condition = LoadLocal(iterator);
4409 condition +=
4410 InstanceCall(iterable_position, Symbols::MoveNext(), Token::kILLEGAL, 1);
4411 TargetEntryInstr* body_entry;
4412 TargetEntryInstr* loop_exit;
4413 condition += BranchIfTrue(&body_entry, &loop_exit, false);
4414
4415 Fragment body(body_entry);
4416 body += EnterScope(offset);
4417 body += LoadLocal(iterator);
4418 const String& current_getter =
4419 String::ZoneHandle(Z, Field::GetterSymbol(Symbols::Current()));
4420 body += InstanceCall(body_position, current_getter, Token::kGET, 1);
4421 body += StoreLocal(TokenPosition::kNoSource,
4422 LookupVariable(variable_kernel_position));
4423 body += Drop();
4424 body += BuildStatement(); // read body.
4425 body += ExitScope(offset);
4426
4427 if (body.is_open()) {
4428 JoinEntryInstr* join = BuildJoinEntry();
4429 instructions += Goto(join);
4430 body += Goto(join);
4431
4432 Fragment loop(join);
4433 loop += CheckStackOverflow(position); // may have non-empty stack
4434 loop += condition;
4435 } else {
4436 instructions += condition;
4437 }
4438
4439 loop_depth_dec();
4440 for_in_depth_dec();
4441 return Fragment(instructions.entry, loop_exit);
4442}
4443
4444Fragment StreamingFlowGraphBuilder::BuildSwitchStatement() {
4445 ReadPosition(); // read position.
4446 // We need the number of cases. So start by getting that, then go back.
4447 intptr_t offset = ReaderOffset();
4448 SkipExpression(); // temporarily skip condition
4449 int case_count = ReadListLength(); // read number of cases.
4450 SetOffset(offset);
4451
4452 SwitchBlock block(flow_graph_builder_, case_count);
4453
4454 // Instead of using a variable we should reuse the expression on the stack,
4455 // since it won't be assigned again, we don't need phi nodes.
4456 Fragment head_instructions = BuildExpression(); // read condition.
4457 head_instructions +=
4458 StoreLocal(TokenPosition::kNoSource, scopes()->switch_variable);
4459 head_instructions += Drop();
4460
4461 case_count = ReadListLength(); // read number of cases.
4462
4463 // Phase 1: Generate bodies and try to find out whether a body will be target
4464 // of a jump due to:
4465 // * `continue case_label`
4466 // * `case e1: case e2: body`
4467 Fragment* body_fragments = Z->Alloc<Fragment>(case_count);
4468 intptr_t* case_expression_offsets = Z->Alloc<intptr_t>(case_count);
4469 int default_case = -1;
4470
4471 for (intptr_t i = 0; i < case_count; ++i) {
4472 case_expression_offsets[i] = ReaderOffset();
4473 int expression_count = ReadListLength(); // read number of expressions.
4474 for (intptr_t j = 0; j < expression_count; ++j) {
4475 ReadPosition(); // read jth position.
4476 SkipExpression(); // read jth expression.
4477 }
4478 bool is_default = ReadBool(); // read is_default.
4479 if (is_default) default_case = i;
4480 Fragment& body_fragment = body_fragments[i] =
4481 BuildStatement(); // read body.
4482
4483 if (body_fragment.entry == NULL) {
4484 // Make a NOP in order to ensure linking works properly.
4485 body_fragment = NullConstant();
4486 body_fragment += Drop();
4487 }
4488
4489 // The Dart language specification mandates fall-throughs in [SwitchCase]es
4490 // to be runtime errors.
4491 if (!is_default && body_fragment.is_open() && (i < (case_count - 1))) {
4492 const Class& klass = Class::ZoneHandle(
4493 Z, Library::LookupCoreClass(Symbols::FallThroughError()));
4494 ASSERT(!klass.IsNull());
4495
4496 GrowableHandlePtrArray<const String> pieces(Z, 3);
4497 pieces.Add(Symbols::FallThroughError());
4498 pieces.Add(Symbols::Dot());
4499 pieces.Add(H.DartSymbolObfuscate("_create"));
4500
4501 const Function& constructor = Function::ZoneHandle(
4502 Z, klass.LookupConstructorAllowPrivate(String::ZoneHandle(
4503 Z, Symbols::FromConcatAll(H.thread(), pieces))));
4504 ASSERT(!constructor.IsNull());
4505 const String& url = H.DartSymbolPlain(
4506 parsed_function()->function().ToLibNamePrefixedQualifiedCString());
4507
4508 // Create instance of _FallThroughError
4509 body_fragment += AllocateObject(TokenPosition::kNoSource, klass, 0);
4510 LocalVariable* instance = MakeTemporary();
4511
4512 // Call _FallThroughError._create constructor.
4513 body_fragment += LoadLocal(instance); // this
4514 body_fragment += Constant(url); // url
4515 body_fragment += NullConstant(); // line
4516
4517 body_fragment +=
4518 StaticCall(TokenPosition::kNoSource, constructor, 3, ICData::kStatic);
4519 body_fragment += Drop();
4520
4521 // Throw the exception
4522 body_fragment += ThrowException(TokenPosition::kNoSource);
4523 body_fragment += Drop();
4524 }
4525
4526 // If there is an implicit fall-through we have one [SwitchCase] and
4527 // multiple expressions, e.g.
4528 //
4529 // switch(expr) {
4530 // case a:
4531 // case b:
4532 // <stmt-body>
4533 // }
4534 //
4535 // This means that the <stmt-body> will have more than 1 incoming edge (one
4536 // from `a == expr` and one from `a != expr && b == expr`). The
4537 // `block.Destination()` records the additional jump.
4538 if (expression_count > 1) {
4539 block.DestinationDirect(i);
4540 }
4541 }
4542
4543 intptr_t end_offset = ReaderOffset();
4544
4545 // Phase 2: Generate everything except the real bodies:
4546 // * jump directly to a body (if there is no jumper)
4547 // * jump to a wrapper block which jumps to the body (if there is a jumper)
4548 Fragment current_instructions = head_instructions;
4549 for (intptr_t i = 0; i < case_count; ++i) {
4550 SetOffset(case_expression_offsets[i]);
4551 int expression_count = ReadListLength(); // read length of expressions.
4552
4553 if (i == default_case) {
4554 ASSERT(i == (case_count - 1));
4555
4556 if (block.HadJumper(i)) {
4557 // There are several branches to the body, so we will make a goto to
4558 // the join block (and prepend a join instruction to the real body).
4559 JoinEntryInstr* join = block.DestinationDirect(i);
4560 current_instructions += Goto(join);
4561
4562 current_instructions = Fragment(current_instructions.entry, join);
4563 current_instructions += body_fragments[i];
4564 } else {
4565 current_instructions += body_fragments[i];
4566 }
4567 } else {
4568 JoinEntryInstr* body_join = NULL;
4569 if (block.HadJumper(i)) {
4570 body_join = block.DestinationDirect(i);
4571 body_fragments[i] = Fragment(body_join) + body_fragments[i];
4572 }
4573
4574 for (intptr_t j = 0; j < expression_count; ++j) {
4575 TargetEntryInstr* then;
4576 TargetEntryInstr* otherwise;
4577
4578 TokenPosition position = ReadPosition(); // read jth position.
4579 current_instructions += Constant(
4580 Instance::ZoneHandle(Z, constant_reader_.ReadConstantExpression()));
4581 current_instructions += LoadLocal(scopes()->switch_variable);
4582 current_instructions +=
4583 InstanceCall(position, Symbols::EqualOperator(), Token::kEQ,
4584 /*argument_count=*/2,
4585 /*checked_argument_count=*/2);
4586 current_instructions += BranchIfTrue(&then, &otherwise, false);
4587
4588 Fragment then_fragment(then);
4589
4590 if (body_join != NULL) {
4591 // There are several branches to the body, so we will make a goto to
4592 // the join block (the real body has already been prepended with a
4593 // join instruction).
4594 then_fragment += Goto(body_join);
4595 } else {
4596 // There is only a signle branch to the body, so we will just append
4597 // the body fragment.
4598 then_fragment += body_fragments[i];
4599 }
4600
4601 current_instructions = Fragment(otherwise);
4602 }
4603 }
4604 }
4605
4606 if (case_count > 0 && default_case < 0) {
4607 // There is no default, which means we have an open [current_instructions]
4608 // (which is a [TargetEntryInstruction] for the last "otherwise" branch).
4609 //
4610 // Furthermore the last [SwitchCase] can be open as well. If so, we need
4611 // to join these two.
4612 Fragment& last_body = body_fragments[case_count - 1];
4613 if (last_body.is_open()) {
4614 ASSERT(current_instructions.is_open());
4615 ASSERT(current_instructions.current->IsTargetEntry());
4616
4617 // Join the last "otherwise" branch and the last [SwitchCase] fragment.
4618 JoinEntryInstr* join = BuildJoinEntry();
4619 current_instructions += Goto(join);
4620 last_body += Goto(join);
4621
4622 current_instructions = Fragment(join);
4623 }
4624 } else {
4625 // All non-default cases will be closed (i.e. break/continue/throw/return)
4626 // So it is fine to just let more statements after the switch append to the
4627 // default case.
4628 }
4629
4630 SetOffset(end_offset);
4631 return Fragment(head_instructions.entry, current_instructions.current);
4632}
4633
4634Fragment StreamingFlowGraphBuilder::BuildContinueSwitchStatement() {
4635 TokenPosition position = ReadPosition(); // read position.
4636 intptr_t target_index = ReadUInt(); // read target index.
4637
4638 TryFinallyBlock* outer_finally = NULL;
4639 intptr_t target_context_depth = -1;
4640 JoinEntryInstr* entry = switch_block()->Destination(
4641 target_index, &outer_finally, &target_context_depth);
4642
4643 Fragment instructions;
4644 instructions +=
4645 TranslateFinallyFinalizers(outer_finally, target_context_depth);
4646 if (instructions.is_open()) {
4647 if (NeedsDebugStepCheck(parsed_function()->function(), position)) {
4648 instructions += DebugStepCheck(position);
4649 }
4650 instructions += Goto(entry);
4651 }
4652 return instructions;
4653}
4654
4655Fragment StreamingFlowGraphBuilder::BuildIfStatement() {
4656 ReadPosition(); // read position.
4657
4658 TestFragment condition = TranslateConditionForControl();
4659
4660 Fragment then_fragment(condition.CreateTrueSuccessor(flow_graph_builder_));
4661 then_fragment += BuildStatement(); // read then.
4662
4663 Fragment otherwise_fragment(
4664 condition.CreateFalseSuccessor(flow_graph_builder_));
4665 otherwise_fragment += BuildStatement(); // read otherwise.
4666
4667 if (then_fragment.is_open()) {
4668 if (otherwise_fragment.is_open()) {
4669 JoinEntryInstr* join = BuildJoinEntry();
4670 then_fragment += Goto(join);
4671 otherwise_fragment += Goto(join);
4672 return Fragment(condition.entry, join);
4673 } else {
4674 return Fragment(condition.entry, then_fragment.current);
4675 }
4676 } else if (otherwise_fragment.is_open()) {
4677 return Fragment(condition.entry, otherwise_fragment.current);
4678 } else {
4679 return Fragment(condition.entry, nullptr);
4680 }
4681}
4682
4683Fragment StreamingFlowGraphBuilder::BuildReturnStatement() {
4684 TokenPosition position = ReadPosition(); // read position.
4685 Tag tag = ReadTag(); // read first part of expression.
4686
4687 bool inside_try_finally = try_finally_block() != NULL;
4688
4689 Fragment instructions = tag == kNothing
4690 ? NullConstant()
4691 : BuildExpression(); // read rest of expression.
4692
4693 if (instructions.is_open()) {
4694 if (inside_try_finally) {
4695 ASSERT(scopes()->finally_return_variable != NULL);
4696 const Function& function = parsed_function()->function();
4697 if (NeedsDebugStepCheck(function, position)) {
4698 instructions += DebugStepCheck(position);
4699 }
4700 instructions += StoreLocal(position, scopes()->finally_return_variable);
4701 instructions += Drop();
4702 instructions += TranslateFinallyFinalizers(NULL, -1);
4703 if (instructions.is_open()) {
4704 instructions += LoadLocal(scopes()->finally_return_variable);
4705 instructions += Return(TokenPosition::kNoSource);
4706 }
4707 } else {
4708 instructions += Return(position);
4709 }
4710 } else {
4711 Pop();
4712 }
4713
4714 return instructions;
4715}
4716
4717Fragment StreamingFlowGraphBuilder::BuildTryCatch() {
4718 ASSERT(block_expression_depth() == 0); // no try-catch in block-expr
4719 InlineBailout("kernel::FlowgraphBuilder::VisitTryCatch");
4720
4721 intptr_t try_handler_index = AllocateTryIndex();
4722 Fragment try_body = TryCatch(try_handler_index);
4723 JoinEntryInstr* after_try = BuildJoinEntry();
4724
4725 // Fill in the body of the try.
4726 try_depth_inc();
4727 {
4728 TryCatchBlock block(flow_graph_builder_, try_handler_index);
4729 try_body += BuildStatement(); // read body.
4730 try_body += Goto(after_try);
4731 }
4732 try_depth_dec();
4733
4734 const int kNeedsStracktraceBit = 1 << 0;
4735 const int kIsSyntheticBit = 1 << 1;
4736
4737 uint8_t flags = ReadByte();
4738 bool needs_stacktrace =
4739 (flags & kNeedsStracktraceBit) == kNeedsStracktraceBit;
4740 bool is_synthetic = (flags & kIsSyntheticBit) == kIsSyntheticBit;
4741
4742 catch_depth_inc();
4743 intptr_t catch_count = ReadListLength(); // read number of catches.
4744 const Array& handler_types =
4745 Array::ZoneHandle(Z, Array::New(catch_count, Heap::kOld));
4746
4747 Fragment catch_body = CatchBlockEntry(handler_types, try_handler_index,
4748 needs_stacktrace, is_synthetic);
4749 // Fill in the body of the catch.
4750 for (intptr_t i = 0; i < catch_count; ++i) {
4751 intptr_t catch_offset = ReaderOffset(); // Catch has no tag.
4752 TokenPosition position = ReadPosition(); // read position.
4753 const AbstractType& type_guard = T.BuildType(); // read guard.
4754 handler_types.SetAt(i, type_guard);
4755
4756 Fragment catch_handler_body = EnterScope(catch_offset);
4757
4758 Tag tag = ReadTag(); // read first part of exception.
4759 if (tag == kSomething) {
4760 catch_handler_body += LoadLocal(CurrentException());
4761 catch_handler_body +=
4762 StoreLocal(TokenPosition::kNoSource,
4763 LookupVariable(ReaderOffset() + data_program_offset_));
4764 catch_handler_body += Drop();
4765 SkipVariableDeclaration(); // read exception.
4766 }
4767
4768 tag = ReadTag(); // read first part of stack trace.
4769 if (tag == kSomething) {
4770 catch_handler_body += LoadLocal(CurrentStackTrace());
4771 catch_handler_body +=
4772 StoreLocal(TokenPosition::kNoSource,
4773 LookupVariable(ReaderOffset() + data_program_offset_));
4774 catch_handler_body += Drop();
4775 SkipVariableDeclaration(); // read stack trace.
4776 }
4777
4778 {
4779 CatchBlock block(flow_graph_builder_, CurrentException(),
4780 CurrentStackTrace(), try_handler_index);
4781
4782 catch_handler_body += BuildStatement(); // read body.
4783
4784 // Note: ExitScope adjusts context_depth_ so even if catch_handler_body
4785 // is closed we still need to execute ExitScope for its side effect.
4786 catch_handler_body += ExitScope(catch_offset);
4787 if (catch_handler_body.is_open()) {
4788 catch_handler_body += Goto(after_try);
4789 }
4790 }
4791
4792 if (!type_guard.IsCatchAllType()) {
4793 catch_body += LoadLocal(CurrentException());
4794
4795 if (!type_guard.IsInstantiated(kCurrentClass)) {
4796 catch_body += LoadInstantiatorTypeArguments();
4797 } else {
4798 catch_body += NullConstant();
4799 }
4800
4801 if (!type_guard.IsInstantiated(kFunctions)) {
4802 catch_body += LoadFunctionTypeArguments();
4803 } else {
4804 catch_body += NullConstant();
4805 }
4806
4807 catch_body += Constant(type_guard);
4808
4809 catch_body += InstanceCall(
4810 position, Library::PrivateCoreLibName(Symbols::_instanceOf()),
4811 Token::kIS, 4);
4812
4813 TargetEntryInstr* catch_entry;
4814 TargetEntryInstr* next_catch_entry;
4815 catch_body += BranchIfTrue(&catch_entry, &next_catch_entry, false);
4816
4817 Fragment(catch_entry) + catch_handler_body;
4818 catch_body = Fragment(next_catch_entry);
4819 } else {
4820 catch_body += catch_handler_body;
4821 }
4822 }
4823
4824 // In case the last catch body was not handling the exception and branching to
4825 // after the try block, we will rethrow the exception (i.e. no default catch
4826 // handler).
4827 if (catch_body.is_open()) {
4828 catch_body += LoadLocal(CurrentException());
4829 catch_body += LoadLocal(CurrentStackTrace());
4830 catch_body += RethrowException(TokenPosition::kNoSource, try_handler_index);
4831 Drop();
4832 }
4833 catch_depth_dec();
4834
4835 return Fragment(try_body.entry, after_try);
4836}
4837
4838Fragment StreamingFlowGraphBuilder::BuildTryFinally() {
4839 ASSERT(block_expression_depth() == 0); // no try-finally in block-expr
4840 // Note on streaming:
4841 // We only stream this TryFinally if we can stream everything inside it,
4842 // so creating a "TryFinallyBlock" with a kernel binary offset instead of an
4843 // AST node isn't a problem.
4844
4845 InlineBailout("kernel::FlowgraphBuilder::VisitTryFinally");
4846
4847 // There are 5 different cases where we need to execute the finally block:
4848 //
4849 // a) 1/2/3th case: Special control flow going out of `node->body()`:
4850 //
4851 // * [BreakStatement] transfers control to a [LabeledStatement]
4852 // * [ContinueSwitchStatement] transfers control to a [SwitchCase]
4853 // * [ReturnStatement] returns a value
4854 //
4855 // => All three cases will automatically append all finally blocks
4856 // between the branching point and the destination (so we don't need to
4857 // do anything here).
4858 //
4859 // b) 4th case: Translating the body resulted in an open fragment (i.e. body
4860 // executes without any control flow out of it)
4861 //
4862 // => We are responsible for jumping out of the body to a new block (with
4863 // different try index) and execute the finalizer.
4864 //
4865 // c) 5th case: An exception occurred inside the body.
4866 //
4867 // => We are responsible for catching it, executing the finally block and
4868 // rethrowing the exception.
4869 intptr_t try_handler_index = AllocateTryIndex();
4870 Fragment try_body = TryCatch(try_handler_index);
4871 JoinEntryInstr* after_try = BuildJoinEntry();
4872
4873 intptr_t offset = ReaderOffset();
4874 SkipStatement(); // temporarily read body.
4875 intptr_t finalizer_offset = ReaderOffset();
4876 SetOffset(offset);
4877
4878 // Fill in the body of the try.
4879 try_depth_inc();
4880 {
4881 TryFinallyBlock tfb(flow_graph_builder_, finalizer_offset);
4882 TryCatchBlock tcb(flow_graph_builder_, try_handler_index);
4883 try_body += BuildStatement(); // read body.
4884 }
4885 try_depth_dec();
4886
4887 if (try_body.is_open()) {
4888 // Please note: The try index will be on level out of this block,
4889 // thereby ensuring if there's an exception in the finally block we
4890 // won't run it twice.
4891 JoinEntryInstr* finally_entry = BuildJoinEntry();
4892
4893 try_body += Goto(finally_entry);
4894
4895 Fragment finally_body(finally_entry);
4896 finally_body += BuildStatement(); // read finalizer.
4897 finally_body += Goto(after_try);
4898 }
4899
4900 // Fill in the body of the catch.
4901 catch_depth_inc();
4902 const Array& handler_types = Array::ZoneHandle(Z, Array::New(1, Heap::kOld));
4903 handler_types.SetAt(0, Object::dynamic_type());
4904 // Note: rethrow will actually force mark the handler as needing a stacktrace.
4905 Fragment finally_body = CatchBlockEntry(handler_types, try_handler_index,
4906 /* needs_stacktrace = */ false,
4907 /* is_synthesized = */ true);
4908 SetOffset(finalizer_offset);
4909 finally_body += BuildStatement(); // read finalizer
4910 if (finally_body.is_open()) {
4911 finally_body += LoadLocal(CurrentException());
4912 finally_body += LoadLocal(CurrentStackTrace());
4913 finally_body +=
4914 RethrowException(TokenPosition::kNoSource, try_handler_index);
4915 Drop();
4916 }
4917 catch_depth_dec();
4918
4919 return Fragment(try_body.entry, after_try);
4920}
4921
4922Fragment StreamingFlowGraphBuilder::BuildYieldStatement() {
4923 TokenPosition position = ReadPosition(); // read position.
4924 uint8_t flags = ReadByte(); // read flags.
4925
4926 ASSERT(flags == kNativeYieldFlags); // Must have been desugared.
4927
4928 // Setup yield/continue point:
4929 //
4930 // ...
4931 // :await_jump_var = index;
4932 // :await_ctx_var = :current_context_var
4933 // return <expr>
4934 //
4935 // Continuation<index>:
4936 // Drop(1)
4937 // ...
4938 //
4939 // BuildGraphOfFunction will create a dispatch that jumps to
4940 // Continuation<:await_jump_var> upon entry to the function.
4941 //
4942 const intptr_t new_yield_pos = yield_continuations().length() + 1;
4943 Fragment instructions = IntConstant(new_yield_pos);
4944 instructions +=
4945 StoreLocal(TokenPosition::kNoSource, scopes()->yield_jump_variable);
4946 instructions += Drop();
4947 instructions += LoadLocal(parsed_function()->current_context_var());
4948 instructions +=
4949 StoreLocal(TokenPosition::kNoSource, scopes()->yield_context_variable);
4950 instructions += Drop();
4951 instructions += BuildExpression(); // read expression.
4952 instructions += Return(position, new_yield_pos);
4953
4954 // Note: DropTempsInstr serves as an anchor instruction. It will not
4955 // be linked into the resulting graph.
4956 DropTempsInstr* anchor = new (Z) DropTempsInstr(0, NULL);
4957 yield_continuations().Add(YieldContinuation(anchor, CurrentTryIndex()));
4958
4959 Fragment continuation(instructions.entry, anchor);
4960
4961 if (parsed_function()->function().IsAsyncClosure() ||
4962 parsed_function()->function().IsAsyncGenClosure()) {
4963 // If function is async closure or async gen closure it takes three
4964 // parameters where the second and the third are exception and stack_trace.
4965 // Check if exception is non-null and rethrow it.
4966 //
4967 // :async_op([:result, :exception, :stack_trace]) {
4968 // ...
4969 // Continuation<index>:
4970 // if (:exception != null) rethrow(:exception, :stack_trace);
4971 // ...
4972 // }
4973 //
4974 LocalVariable* exception_var = parsed_function()->ParameterVariable(2);
4975 LocalVariable* stack_trace_var = parsed_function()->ParameterVariable(3);
4976 ASSERT(exception_var->name().raw() == Symbols::ExceptionParameter().raw());
4977 ASSERT(stack_trace_var->name().raw() ==
4978 Symbols::StackTraceParameter().raw());
4979
4980 TargetEntryInstr* no_error;
4981 TargetEntryInstr* error;
4982
4983 continuation += LoadLocal(exception_var);
4984 continuation += BranchIfNull(&no_error, &error);
4985
4986 Fragment rethrow(error);
4987 rethrow += LoadLocal(exception_var);
4988 rethrow += LoadLocal(stack_trace_var);
4989 rethrow += RethrowException(position, kInvalidTryIndex);
4990 Drop();
4991
4992 continuation = Fragment(continuation.entry, no_error);
4993 }
4994
4995 return continuation;
4996}
4997
4998Fragment StreamingFlowGraphBuilder::BuildVariableDeclaration() {
4999 intptr_t kernel_position_no_tag = ReaderOffset() + data_program_offset_;
5000 LocalVariable* variable = LookupVariable(kernel_position_no_tag);
5001
5002 VariableDeclarationHelper helper(this);
5003 helper.ReadUntilExcluding(VariableDeclarationHelper::kType);
5004 T.BuildType(); // read type.
5005 bool has_initializer = (ReadTag() != kNothing);
5006
5007 Fragment instructions;
5008 if (variable->is_late()) {
5009 // TODO(liama): Treat the field as non-late if the initializer is trivial.
5010 if (has_initializer) {
5011 SkipExpression();
5012 }
5013 instructions += Constant(Object::sentinel());
5014 } else if (!has_initializer) {
5015 instructions += NullConstant();
5016 } else if (helper.IsConst()) {
5017 // Read const initializer form current position.
5018 const Instance& constant_value =
5019 Instance::ZoneHandle(Z, constant_reader_.ReadConstantExpression());
5020 variable->SetConstValue(constant_value);
5021 instructions += Constant(constant_value);
5022 } else {
5023 // Initializer
5024 instructions += BuildExpression(); // read (actual) initializer.
5025 }
5026
5027 // Use position of equal sign if it exists. If the equal sign does not exist
5028 // use the position of the identifier.
5029 TokenPosition debug_position =
5030 Utils::Maximum(helper.position_, helper.equals_position_);
5031 if (NeedsDebugStepCheck(stack(), debug_position)) {
5032 instructions = DebugStepCheck(debug_position) + instructions;
5033 }
5034 instructions += StoreLocal(helper.position_, variable);
5035 instructions += Drop();
5036 return instructions;
5037}
5038
5039Fragment StreamingFlowGraphBuilder::BuildFunctionDeclaration() {
5040 TokenPosition position = ReadPosition(); // read position.
5041 intptr_t variable_offset = ReaderOffset() + data_program_offset_;
5042
5043 // read variable declaration.
5044 VariableDeclarationHelper helper(this);
5045 helper.ReadUntilExcluding(VariableDeclarationHelper::kEnd);
5046
5047 Fragment instructions = DebugStepCheck(position);
5048 instructions += BuildFunctionNode(position, helper.name_index_);
5049 instructions += StoreLocal(position, LookupVariable(variable_offset));
5050 instructions += Drop();
5051 return instructions;
5052}
5053
5054Fragment StreamingFlowGraphBuilder::BuildFunctionNode(
5055 TokenPosition parent_position,
5056 StringIndex name_index) {
5057 intptr_t offset = ReaderOffset();
5058
5059 FunctionNodeHelper function_node_helper(this);
5060 function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kTypeParameters);
5061 TokenPosition position = function_node_helper.position_;
5062
5063 bool declaration = name_index >= 0;
5064
5065 if (declaration) {
5066 position = parent_position;
5067 }
5068 if (!position.IsReal()) {
5069 // Positions has to be unique in regards to the parent.
5070 // A non-real at this point is probably -1, we cannot blindly use that
5071 // as others might use it too. Create a new dummy non-real TokenPosition.
5072 position = TokenPosition(offset).ToSynthetic();
5073 }
5074
5075 // The VM has a per-isolate table of functions indexed by the enclosing
5076 // function and token position.
5077 Function& function = Function::ZoneHandle(Z);
5078
5079 // NOTE: This is not TokenPosition in the general sense!
5080 function = I->LookupClosureFunction(parsed_function()->function(), position);
5081 if (function.IsNull()) {
5082 for (intptr_t i = 0; i < scopes()->function_scopes.length(); ++i) {
5083 if (scopes()->function_scopes[i].kernel_offset != offset) {
5084 continue;
5085 }
5086
5087 const String* name;
5088 if (declaration) {
5089 name = &H.DartSymbolObfuscate(name_index);
5090 } else {
5091 name = &Symbols::AnonymousClosure();
5092 }
5093 // NOTE: This is not TokenPosition in the general sense!
5094 if (!closure_owner_.IsNull()) {
5095 function = Function::NewClosureFunctionWithKind(
5096 FunctionLayout::kClosureFunction, *name,
5097 parsed_function()->function(), position, closure_owner_);
5098 } else {
5099 function = Function::NewClosureFunction(
5100 *name, parsed_function()->function(), position);
5101 }
5102
5103 function.set_is_debuggable(function_node_helper.dart_async_marker_ ==
5104 FunctionNodeHelper::kSync);
5105 switch (function_node_helper.dart_async_marker_) {
5106 case FunctionNodeHelper::kSyncStar:
5107 function.set_modifier(FunctionLayout::kSyncGen);
5108 break;
5109 case FunctionNodeHelper::kAsync:
5110 function.set_modifier(FunctionLayout::kAsync);
5111 function.set_is_inlinable(!FLAG_causal_async_stacks);
5112 break;
5113 case FunctionNodeHelper::kAsyncStar:
5114 function.set_modifier(FunctionLayout::kAsyncGen);
5115 function.set_is_inlinable(!FLAG_causal_async_stacks);
5116 break;
5117 default:
5118 // no special modifier
5119 break;
5120 }
5121 function.set_is_generated_body(function_node_helper.async_marker_ ==
5122 FunctionNodeHelper::kSyncYielding);
5123 if (function.IsAsyncClosure() || function.IsAsyncGenClosure()) {
5124 function.set_is_inlinable(!FLAG_causal_async_stacks &&
5125 !FLAG_lazy_async_stacks);
5126 }
5127
5128 function.set_end_token_pos(function_node_helper.end_position_);
5129 LocalScope* scope = scopes()->function_scopes[i].scope;
5130 const ContextScope& context_scope = ContextScope::Handle(
5131 Z, scope->PreserveOuterScope(flow_graph_builder_->context_depth_));
5132 function.set_context_scope(context_scope);
5133 function.set_kernel_offset(offset);
5134 type_translator_.SetupFunctionParameters(Class::Handle(Z), function,
5135 false, // is_method
5136 true, // is_closure
5137 &function_node_helper);
5138 // type_translator_.SetupUnboxingInfoMetadata is not called here at the
5139 // moment because closures do not have unboxed parameters and return value
5140 function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kEnd);
5141
5142 // Finalize function type.
5143 Type& signature_type = Type::Handle(Z, function.SignatureType());
5144 signature_type ^=
5145 ClassFinalizer::FinalizeType(*active_class()->klass, signature_type);
5146 function.SetSignatureType(signature_type);
5147
5148 I->AddClosureFunction(function);
5149 break;
5150 }
5151 }
5152
5153 function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kEnd);
5154
5155 Fragment instructions =
5156 flow_graph_builder_->AllocateClosure(TokenPosition::kNoSource, function);
5157 LocalVariable* closure = MakeTemporary();
5158
5159 // The function signature can have uninstantiated class type parameters.
5160 if (!function.HasInstantiatedSignature(kCurrentClass)) {
5161 instructions += LoadLocal(closure);
5162 instructions += LoadInstantiatorTypeArguments();
5163 instructions += flow_graph_builder_->StoreInstanceField(
5164 TokenPosition::kNoSource, Slot::Closure_instantiator_type_arguments(),
5165 StoreInstanceFieldInstr::Kind::kInitializing);
5166 }
5167
5168 // TODO(30455): We only need to save these if the closure uses any captured
5169 // type parameters.
5170 instructions += LoadLocal(closure);
5171 instructions += LoadFunctionTypeArguments();
5172 instructions += flow_graph_builder_->StoreInstanceField(
5173 TokenPosition::kNoSource, Slot::Closure_function_type_arguments(),
5174 StoreInstanceFieldInstr::Kind::kInitializing);
5175
5176 if (function.IsGeneric()) {
5177 // Only generic functions need to have properly initialized
5178 // delayed_type_arguments.
5179 instructions += LoadLocal(closure);
5180 instructions += Constant(Object::empty_type_arguments());
5181 instructions += flow_graph_builder_->StoreInstanceField(
5182 TokenPosition::kNoSource, Slot::Closure_delayed_type_arguments(),
5183 StoreInstanceFieldInstr::Kind::kInitializing);
5184 }
5185
5186 // Store the function and the context in the closure.
5187 instructions += LoadLocal(closure);
5188 instructions += Constant(function);
5189 instructions += flow_graph_builder_->StoreInstanceField(
5190 TokenPosition::kNoSource, Slot::Closure_function(),
5191 StoreInstanceFieldInstr::Kind::kInitializing);
5192
5193 instructions += LoadLocal(closure);
5194 instructions += LoadLocal(parsed_function()->current_context_var());
5195 instructions += flow_graph_builder_->StoreInstanceField(
5196 TokenPosition::kNoSource, Slot::Closure_context(),
5197 StoreInstanceFieldInstr::Kind::kInitializing);
5198
5199 return instructions;
5200}
5201
5202Fragment StreamingFlowGraphBuilder::BuildFfiAsFunctionInternal() {
5203 const intptr_t argc = ReadUInt(); // read argument count.
5204 ASSERT(argc == 1); // pointer
5205 const intptr_t list_length = ReadListLength(); // read types list length.
5206 ASSERT(list_length == 2); // dart signature, then native signature
5207 const TypeArguments& type_arguments =
5208 T.BuildTypeArguments(list_length); // read types.
5209 Fragment code;
5210 const intptr_t positional_count =
5211 ReadListLength(); // read positional argument count
5212 ASSERT(positional_count == 1);
5213 code += BuildExpression(); // build first positional argument (pointer)
5214 const intptr_t named_args_len =
5215 ReadListLength(); // skip (empty) named arguments list
5216 ASSERT(named_args_len == 0);
5217 code += B->BuildFfiAsFunctionInternalCall(type_arguments);
5218 return code;
5219}
5220
5221Fragment StreamingFlowGraphBuilder::BuildFfiNativeCallbackFunction() {
5222 // The call-site must look like this (guaranteed by the FE which inserts it):
5223 //
5224 // _nativeCallbackFunction<NativeSignatureType>(target, exceptionalReturn)
5225 //
5226 // The FE also guarantees that all three arguments are constants.
5227
5228 const intptr_t argc = ReadUInt(); // read argument count
5229 ASSERT(argc == 2); // target, exceptionalReturn
5230
5231 const intptr_t list_length = ReadListLength(); // read types list length
5232 ASSERT(list_length == 1); // native signature
5233 const TypeArguments& type_arguments =
5234 T.BuildTypeArguments(list_length); // read types.
5235 ASSERT(type_arguments.Length() == 1 && type_arguments.IsInstantiated());
5236 const Function& native_sig = Function::Handle(
5237 Z, Type::CheckedHandle(Z, type_arguments.TypeAt(0)).signature());
5238
5239 Fragment code;
5240 const intptr_t positional_count =
5241 ReadListLength(); // read positional argument count
5242 ASSERT(positional_count == 2);
5243
5244 // Read target expression and extract the target function.
5245 code += BuildExpression(); // build first positional argument (target)
5246 Definition* target_def = B->Peek();
5247 ASSERT(target_def->IsConstant());
5248 const Closure& target_closure =
5249 Closure::Cast(target_def->AsConstant()->value());
5250 ASSERT(!target_closure.IsNull());
5251 Function& target = Function::Handle(Z, target_closure.function());
5252 ASSERT(!target.IsNull() && target.IsImplicitClosureFunction());
5253 target = target.parent_function();
5254 code += Drop();
5255
5256 // Build second positional argument (exceptionalReturn).
5257 code += BuildExpression();
5258 Definition* exceptional_return_def = B->Peek();
5259 ASSERT(exceptional_return_def->IsConstant());
5260 const Instance& exceptional_return =
5261 Instance::Cast(exceptional_return_def->AsConstant()->value());
5262 code += Drop();
5263
5264 const intptr_t named_args_len =
5265 ReadListLength(); // skip (empty) named arguments list
5266 ASSERT(named_args_len == 0);
5267
5268 const Function& result =
5269 Function::ZoneHandle(Z, compiler::ffi::NativeCallbackFunction(
5270 native_sig, target, exceptional_return));
5271 code += Constant(result);
5272 return code;
5273}
5274
5275} // namespace kernel
5276} // namespace dart
5277