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_to_il.h"
6
7#include "platform/assert.h"
8#include "vm/compiler/aot/precompiler.h"
9#include "vm/compiler/backend/il.h"
10#include "vm/compiler/backend/il_printer.h"
11#include "vm/compiler/backend/locations.h"
12#include "vm/compiler/ffi/abi.h"
13#include "vm/compiler/ffi/marshaller.h"
14#include "vm/compiler/ffi/recognized_method.h"
15#include "vm/compiler/frontend/kernel_binary_flowgraph.h"
16#include "vm/compiler/frontend/kernel_translation_helper.h"
17#include "vm/compiler/frontend/prologue_builder.h"
18#include "vm/compiler/jit/compiler.h"
19#include "vm/kernel_isolate.h"
20#include "vm/kernel_loader.h"
21#include "vm/longjump.h"
22#include "vm/native_entry.h"
23#include "vm/object_store.h"
24#include "vm/report.h"
25#include "vm/resolver.h"
26#include "vm/scopes.h"
27#include "vm/stack_frame.h"
28
29namespace dart {
30namespace kernel {
31
32#define Z (zone_)
33#define H (translation_helper_)
34#define T (type_translator_)
35#define I Isolate::Current()
36
37FlowGraphBuilder::FlowGraphBuilder(
38 ParsedFunction* parsed_function,
39 ZoneGrowableArray<const ICData*>* ic_data_array,
40 ZoneGrowableArray<intptr_t>* context_level_array,
41 InlineExitCollector* exit_collector,
42 bool optimizing,
43 intptr_t osr_id,
44 intptr_t first_block_id,
45 bool inlining_unchecked_entry)
46 : BaseFlowGraphBuilder(parsed_function,
47 first_block_id - 1,
48 osr_id,
49 context_level_array,
50 exit_collector,
51 inlining_unchecked_entry),
52 translation_helper_(Thread::Current()),
53 thread_(translation_helper_.thread()),
54 zone_(translation_helper_.zone()),
55 parsed_function_(parsed_function),
56 optimizing_(optimizing),
57 ic_data_array_(*ic_data_array),
58 next_function_id_(0),
59 loop_depth_(0),
60 try_depth_(0),
61 catch_depth_(0),
62 for_in_depth_(0),
63 block_expression_depth_(0),
64 graph_entry_(NULL),
65 scopes_(NULL),
66 breakable_block_(NULL),
67 switch_block_(NULL),
68 try_catch_block_(NULL),
69 try_finally_block_(NULL),
70 catch_block_(NULL) {
71 const Script& script =
72 Script::Handle(Z, parsed_function->function().script());
73 H.InitFromScript(script);
74}
75
76FlowGraphBuilder::~FlowGraphBuilder() {}
77
78Fragment FlowGraphBuilder::EnterScope(
79 intptr_t kernel_offset,
80 const LocalScope** context_scope /* = nullptr */) {
81 Fragment instructions;
82 const LocalScope* scope = scopes_->scopes.Lookup(kernel_offset);
83 if (scope->num_context_variables() > 0) {
84 instructions += PushContext(scope);
85 instructions += Drop();
86 }
87 if (context_scope != nullptr) {
88 *context_scope = scope;
89 }
90 return instructions;
91}
92
93Fragment FlowGraphBuilder::ExitScope(intptr_t kernel_offset) {
94 Fragment instructions;
95 const intptr_t context_size =
96 scopes_->scopes.Lookup(kernel_offset)->num_context_variables();
97 if (context_size > 0) {
98 instructions += PopContext();
99 }
100 return instructions;
101}
102
103Fragment FlowGraphBuilder::AdjustContextTo(int depth) {
104 ASSERT(depth <= context_depth_ && depth >= 0);
105 Fragment instructions;
106 if (depth < context_depth_) {
107 instructions += LoadContextAt(depth);
108 instructions += StoreLocal(TokenPosition::kNoSource,
109 parsed_function_->current_context_var());
110 instructions += Drop();
111 context_depth_ = depth;
112 }
113 return instructions;
114}
115
116Fragment FlowGraphBuilder::PushContext(const LocalScope* scope) {
117 ASSERT(scope->num_context_variables() > 0);
118 Fragment instructions = AllocateContext(scope->context_slots());
119 LocalVariable* context = MakeTemporary();
120 instructions += LoadLocal(context);
121 instructions += LoadLocal(parsed_function_->current_context_var());
122 instructions +=
123 StoreInstanceField(TokenPosition::kNoSource, Slot::Context_parent(),
124 StoreInstanceFieldInstr::Kind::kInitializing);
125 instructions += StoreLocal(TokenPosition::kNoSource,
126 parsed_function_->current_context_var());
127 ++context_depth_;
128 return instructions;
129}
130
131Fragment FlowGraphBuilder::PopContext() {
132 return AdjustContextTo(context_depth_ - 1);
133}
134
135Fragment FlowGraphBuilder::LoadInstantiatorTypeArguments() {
136 // TODO(27590): We could use `active_class_->IsGeneric()`.
137 Fragment instructions;
138 if (scopes_ != nullptr && scopes_->type_arguments_variable != nullptr) {
139#ifdef DEBUG
140 Function& function =
141 Function::Handle(Z, parsed_function_->function().raw());
142 while (function.IsClosureFunction()) {
143 function = function.parent_function();
144 }
145 ASSERT(function.IsFactory());
146#endif
147 instructions += LoadLocal(scopes_->type_arguments_variable);
148 } else if (parsed_function_->has_receiver_var() &&
149 active_class_.ClassNumTypeArguments() > 0) {
150 ASSERT(!parsed_function_->function().IsFactory());
151 instructions += LoadLocal(parsed_function_->receiver_var());
152 instructions += LoadNativeField(
153 Slot::GetTypeArgumentsSlotFor(thread_, *active_class_.klass));
154 } else {
155 instructions += NullConstant();
156 }
157 return instructions;
158}
159
160// This function is responsible for pushing a type arguments vector which
161// contains all type arguments of enclosing functions prepended to the type
162// arguments of the current function.
163Fragment FlowGraphBuilder::LoadFunctionTypeArguments() {
164 Fragment instructions;
165
166 const Function& function = parsed_function_->function();
167
168 if (function.IsGeneric() || function.HasGenericParent()) {
169 ASSERT(parsed_function_->function_type_arguments() != NULL);
170 instructions += LoadLocal(parsed_function_->function_type_arguments());
171 } else {
172 instructions += NullConstant();
173 }
174
175 return instructions;
176}
177
178Fragment FlowGraphBuilder::TranslateInstantiatedTypeArguments(
179 const TypeArguments& type_arguments) {
180 Fragment instructions;
181
182 if (type_arguments.IsNull() || type_arguments.IsInstantiated()) {
183 // There are no type references to type parameters so we can just take it.
184 instructions += Constant(type_arguments);
185 } else {
186 // The [type_arguments] vector contains a type reference to a type
187 // parameter we need to resolve it.
188 if (type_arguments.CanShareInstantiatorTypeArguments(
189 *active_class_.klass)) {
190 // If the instantiator type arguments are just passed on, we don't need to
191 // resolve the type parameters.
192 //
193 // This is for example the case here:
194 // class Foo<T> {
195 // newList() => new List<T>();
196 // }
197 // We just use the type argument vector from the [Foo] object and pass it
198 // directly to the `new List<T>()` factory constructor.
199 instructions += LoadInstantiatorTypeArguments();
200 } else if (type_arguments.CanShareFunctionTypeArguments(
201 parsed_function_->function())) {
202 instructions += LoadFunctionTypeArguments();
203 } else {
204 // Otherwise we need to resolve [TypeParameterType]s in the type
205 // expression based on the current instantiator type argument vector.
206 if (!type_arguments.IsInstantiated(kCurrentClass)) {
207 instructions += LoadInstantiatorTypeArguments();
208 } else {
209 instructions += NullConstant();
210 }
211 if (!type_arguments.IsInstantiated(kFunctions)) {
212 instructions += LoadFunctionTypeArguments();
213 } else {
214 instructions += NullConstant();
215 }
216 instructions += InstantiateTypeArguments(type_arguments);
217 }
218 }
219 return instructions;
220}
221
222Fragment FlowGraphBuilder::CatchBlockEntry(const Array& handler_types,
223 intptr_t handler_index,
224 bool needs_stacktrace,
225 bool is_synthesized) {
226 LocalVariable* exception_var = CurrentException();
227 LocalVariable* stacktrace_var = CurrentStackTrace();
228 LocalVariable* raw_exception_var = CurrentRawException();
229 LocalVariable* raw_stacktrace_var = CurrentRawStackTrace();
230
231 CatchBlockEntryInstr* entry = new (Z) CatchBlockEntryInstr(
232 is_synthesized, // whether catch block was synthesized by FE compiler
233 AllocateBlockId(), CurrentTryIndex(), graph_entry_, handler_types,
234 handler_index, needs_stacktrace, GetNextDeoptId(), exception_var,
235 stacktrace_var, raw_exception_var, raw_stacktrace_var);
236 graph_entry_->AddCatchEntry(entry);
237
238 Fragment instructions(entry);
239
240 // Auxiliary variables introduced by the try catch can be captured if we are
241 // inside a function with yield/resume points. In this case we first need
242 // to restore the context to match the context at entry into the closure.
243 const bool should_restore_closure_context =
244 CurrentException()->is_captured() || CurrentCatchContext()->is_captured();
245 LocalVariable* context_variable = parsed_function_->current_context_var();
246 if (should_restore_closure_context) {
247 ASSERT(parsed_function_->function().IsClosureFunction());
248
249 LocalVariable* closure_parameter = parsed_function_->ParameterVariable(0);
250 ASSERT(!closure_parameter->is_captured());
251 instructions += LoadLocal(closure_parameter);
252 instructions += LoadNativeField(Slot::Closure_context());
253 instructions += StoreLocal(TokenPosition::kNoSource, context_variable);
254 instructions += Drop();
255 }
256
257 if (exception_var->is_captured()) {
258 instructions += LoadLocal(context_variable);
259 instructions += LoadLocal(raw_exception_var);
260 instructions += StoreInstanceField(
261 TokenPosition::kNoSource,
262 Slot::GetContextVariableSlotFor(thread_, *exception_var));
263 }
264 if (stacktrace_var->is_captured()) {
265 instructions += LoadLocal(context_variable);
266 instructions += LoadLocal(raw_stacktrace_var);
267 instructions += StoreInstanceField(
268 TokenPosition::kNoSource,
269 Slot::GetContextVariableSlotFor(thread_, *stacktrace_var));
270 }
271
272 // :saved_try_context_var can be captured in the context of
273 // of the closure, in this case CatchBlockEntryInstr restores
274 // :current_context_var to point to closure context in the
275 // same way as normal function prologue does.
276 // Update current context depth to reflect that.
277 const intptr_t saved_context_depth = context_depth_;
278 ASSERT(!CurrentCatchContext()->is_captured() ||
279 CurrentCatchContext()->owner()->context_level() == 0);
280 context_depth_ = 0;
281 instructions += LoadLocal(CurrentCatchContext());
282 instructions += StoreLocal(TokenPosition::kNoSource,
283 parsed_function_->current_context_var());
284 instructions += Drop();
285 context_depth_ = saved_context_depth;
286
287 return instructions;
288}
289
290Fragment FlowGraphBuilder::TryCatch(int try_handler_index) {
291 // The body of the try needs to have it's own block in order to get a new try
292 // index.
293 //
294 // => We therefore create a block for the body (fresh try index) and another
295 // join block (with current try index).
296 Fragment body;
297 JoinEntryInstr* entry = new (Z)
298 JoinEntryInstr(AllocateBlockId(), try_handler_index, GetNextDeoptId());
299 body += LoadLocal(parsed_function_->current_context_var());
300 body += StoreLocal(TokenPosition::kNoSource, CurrentCatchContext());
301 body += Drop();
302 body += Goto(entry);
303 return Fragment(body.entry, entry);
304}
305
306Fragment FlowGraphBuilder::CheckStackOverflowInPrologue(
307 TokenPosition position) {
308 ASSERT(loop_depth_ == 0);
309 return BaseFlowGraphBuilder::CheckStackOverflowInPrologue(position);
310}
311
312Fragment FlowGraphBuilder::CloneContext(
313 const ZoneGrowableArray<const Slot*>& context_slots) {
314 LocalVariable* context_variable = parsed_function_->current_context_var();
315
316 Fragment instructions = LoadLocal(context_variable);
317
318 CloneContextInstr* clone_instruction = new (Z) CloneContextInstr(
319 TokenPosition::kNoSource, Pop(), context_slots, GetNextDeoptId());
320 instructions <<= clone_instruction;
321 Push(clone_instruction);
322
323 instructions += StoreLocal(TokenPosition::kNoSource, context_variable);
324 instructions += Drop();
325 return instructions;
326}
327
328Fragment FlowGraphBuilder::InstanceCall(
329 TokenPosition position,
330 const String& name,
331 Token::Kind kind,
332 intptr_t type_args_len,
333 intptr_t argument_count,
334 const Array& argument_names,
335 intptr_t checked_argument_count,
336 const Function& interface_target,
337 const Function& tearoff_interface_target,
338 const InferredTypeMetadata* result_type,
339 bool use_unchecked_entry,
340 const CallSiteAttributesMetadata* call_site_attrs,
341 bool receiver_is_not_smi) {
342 const intptr_t total_count = argument_count + (type_args_len > 0 ? 1 : 0);
343 InputsArray* arguments = GetArguments(total_count);
344 InstanceCallInstr* call = new (Z) InstanceCallInstr(
345 position, name, kind, arguments, type_args_len, argument_names,
346 checked_argument_count, ic_data_array_, GetNextDeoptId(),
347 interface_target, tearoff_interface_target);
348 if ((result_type != NULL) && !result_type->IsTrivial()) {
349 call->SetResultType(Z, result_type->ToCompileType(Z));
350 }
351 if (use_unchecked_entry) {
352 call->set_entry_kind(Code::EntryKind::kUnchecked);
353 }
354 if (call_site_attrs != nullptr && call_site_attrs->receiver_type != nullptr &&
355 call_site_attrs->receiver_type->IsInstantiated()) {
356 call->set_receivers_static_type(call_site_attrs->receiver_type);
357 } else if (!interface_target.IsNull()) {
358 const Class& owner = Class::Handle(Z, interface_target.Owner());
359 const AbstractType& type =
360 AbstractType::ZoneHandle(Z, owner.DeclarationType());
361 call->set_receivers_static_type(&type);
362 }
363 call->set_receiver_is_not_smi(receiver_is_not_smi);
364 Push(call);
365 if (result_type != nullptr && result_type->IsConstant()) {
366 Fragment instructions(call);
367 instructions += Drop();
368 instructions += Constant(result_type->constant_value);
369 return instructions;
370 }
371 return Fragment(call);
372}
373
374Fragment FlowGraphBuilder::FfiCall(
375 const compiler::ffi::CallMarshaller& marshaller) {
376 Fragment body;
377
378 FfiCallInstr* const call =
379 new (Z) FfiCallInstr(Z, GetNextDeoptId(), marshaller);
380
381 for (intptr_t i = call->InputCount() - 1; i >= 0; --i) {
382 call->SetInputAt(i, Pop());
383 }
384
385 Push(call);
386 body <<= call;
387
388 return body;
389}
390
391Fragment FlowGraphBuilder::ThrowException(TokenPosition position) {
392 Fragment instructions;
393 Value* exception = Pop();
394 instructions +=
395 Fragment(new (Z) ThrowInstr(position, GetNextDeoptId(), exception))
396 .closed();
397 // Use its side effect of leaving a constant on the stack (does not change
398 // the graph).
399 NullConstant();
400
401 return instructions;
402}
403
404Fragment FlowGraphBuilder::RethrowException(TokenPosition position,
405 int catch_try_index) {
406 Fragment instructions;
407 Value* stacktrace = Pop();
408 Value* exception = Pop();
409 instructions +=
410 Fragment(new (Z) ReThrowInstr(position, catch_try_index, GetNextDeoptId(),
411 exception, stacktrace))
412 .closed();
413 // Use its side effect of leaving a constant on the stack (does not change
414 // the graph).
415 NullConstant();
416
417 return instructions;
418}
419
420Fragment FlowGraphBuilder::LoadLocal(LocalVariable* variable) {
421 // Captured 'this' is immutable, so within the outer method we don't need to
422 // load it from the context.
423 const ParsedFunction* pf = parsed_function_;
424 if (pf->function().HasThisParameter() && pf->has_receiver_var() &&
425 variable == pf->receiver_var()) {
426 ASSERT(variable == pf->ParameterVariable(0));
427 variable = pf->RawParameterVariable(0);
428 }
429 if (variable->is_captured()) {
430 Fragment instructions;
431 instructions += LoadContextAt(variable->owner()->context_level());
432 instructions +=
433 LoadNativeField(Slot::GetContextVariableSlotFor(thread_, *variable));
434 return instructions;
435 } else {
436 return BaseFlowGraphBuilder::LoadLocal(variable);
437 }
438}
439
440Fragment FlowGraphBuilder::ThrowLateInitializationError(TokenPosition position,
441 const String& name) {
442 const Class& klass = Class::ZoneHandle(
443 Z, Library::LookupCoreClass(Symbols::LateInitializationError()));
444 ASSERT(!klass.IsNull());
445
446 const Function& throw_new =
447 Function::ZoneHandle(Z, klass.LookupStaticFunctionAllowPrivate(
448 H.DartSymbolObfuscate("_throwNew")));
449 ASSERT(!throw_new.IsNull());
450
451 Fragment instructions;
452
453 // Call _LateInitializationError._throwNew.
454 instructions += Constant(name);
455 instructions += StaticCall(position, throw_new,
456 /* argument_count = */ 1, ICData::kStatic);
457 instructions += Drop();
458
459 return instructions;
460}
461
462Fragment FlowGraphBuilder::StoreLateField(const Field& field,
463 LocalVariable* instance,
464 LocalVariable* setter_value) {
465 Fragment instructions;
466 TargetEntryInstr *is_uninitialized, *is_initialized;
467 const TokenPosition position = field.token_pos();
468 const bool is_static = field.is_static();
469 const bool is_final = field.is_final();
470
471 if (is_final) {
472 // Check whether the field has been initialized already.
473 if (is_static) {
474 instructions += LoadStaticField(field, /*calls_initializer=*/false);
475 } else {
476 instructions += LoadLocal(instance);
477 instructions += LoadField(field, /*calls_initializer=*/false);
478 }
479 instructions += Constant(Object::sentinel());
480 instructions += BranchIfStrictEqual(&is_uninitialized, &is_initialized);
481 JoinEntryInstr* join = BuildJoinEntry();
482
483 {
484 // If the field isn't initialized, do nothing.
485 Fragment initialize(is_uninitialized);
486 initialize += Goto(join);
487 }
488
489 {
490 // If the field is already initialized, throw a LateInitializationError.
491 Fragment already_initialized(is_initialized);
492 already_initialized += ThrowLateInitializationError(
493 position, String::ZoneHandle(Z, field.name()));
494 already_initialized += Goto(join);
495 }
496
497 instructions = Fragment(instructions.entry, join);
498 }
499
500 if (!is_static) {
501 instructions += LoadLocal(instance);
502 }
503 instructions += LoadLocal(setter_value);
504 if (is_static) {
505 instructions += StoreStaticField(position, field);
506 } else {
507 instructions += StoreInstanceFieldGuarded(field);
508 }
509
510 return instructions;
511}
512
513Fragment FlowGraphBuilder::NativeCall(const String* name,
514 const Function* function) {
515 InlineBailout("kernel::FlowGraphBuilder::NativeCall");
516 const intptr_t num_args =
517 function->NumParameters() + (function->IsGeneric() ? 1 : 0);
518 InputsArray* arguments = GetArguments(num_args);
519 NativeCallInstr* call =
520 new (Z) NativeCallInstr(name, function, FLAG_link_natives_lazily,
521 function->end_token_pos(), arguments);
522 Push(call);
523 return Fragment(call);
524}
525
526Fragment FlowGraphBuilder::Return(TokenPosition position,
527 bool omit_result_type_check,
528 intptr_t yield_index) {
529 Fragment instructions;
530 const Function& function = parsed_function_->function();
531
532 // Emit a type check of the return type in checked mode for all functions
533 // and in strong mode for native functions.
534 if (!omit_result_type_check && function.is_native()) {
535 const AbstractType& return_type =
536 AbstractType::Handle(Z, function.result_type());
537 instructions += CheckAssignable(return_type, Symbols::FunctionResult());
538 }
539
540 if (NeedsDebugStepCheck(function, position)) {
541 instructions += DebugStepCheck(position);
542 }
543
544 if (FLAG_causal_async_stacks &&
545 (function.IsAsyncClosure() || function.IsAsyncGenClosure())) {
546 // We are returning from an asynchronous closure. Before we do that, be
547 // sure to clear the thread's asynchronous stack trace.
548 const Function& target = Function::ZoneHandle(
549 Z, I->object_store()->async_clear_thread_stack_trace());
550 ASSERT(!target.IsNull());
551 instructions += StaticCall(TokenPosition::kNoSource, target,
552 /* argument_count = */ 0, ICData::kStatic);
553 instructions += Drop();
554 }
555
556 instructions += BaseFlowGraphBuilder::Return(position, yield_index);
557
558 return instructions;
559}
560
561Fragment FlowGraphBuilder::StaticCall(TokenPosition position,
562 const Function& target,
563 intptr_t argument_count,
564 ICData::RebindRule rebind_rule) {
565 return StaticCall(position, target, argument_count, Array::null_array(),
566 rebind_rule);
567}
568
569void FlowGraphBuilder::SetResultTypeForStaticCall(
570 StaticCallInstr* call,
571 const Function& target,
572 intptr_t argument_count,
573 const InferredTypeMetadata* result_type) {
574 if (call->InitResultType(Z)) {
575 ASSERT((result_type == NULL) || (result_type->cid == kDynamicCid) ||
576 (result_type->cid == call->result_cid()));
577 return;
578 }
579 if ((result_type != NULL) && !result_type->IsTrivial()) {
580 call->SetResultType(Z, result_type->ToCompileType(Z));
581 }
582}
583
584Fragment FlowGraphBuilder::StaticCall(TokenPosition position,
585 const Function& target,
586 intptr_t argument_count,
587 const Array& argument_names,
588 ICData::RebindRule rebind_rule,
589 const InferredTypeMetadata* result_type,
590 intptr_t type_args_count,
591 bool use_unchecked_entry) {
592 const intptr_t total_count = argument_count + (type_args_count > 0 ? 1 : 0);
593 InputsArray* arguments = GetArguments(total_count);
594 StaticCallInstr* call = new (Z)
595 StaticCallInstr(position, target, type_args_count, argument_names,
596 arguments, ic_data_array_, GetNextDeoptId(), rebind_rule);
597 SetResultTypeForStaticCall(call, target, argument_count, result_type);
598 if (use_unchecked_entry) {
599 call->set_entry_kind(Code::EntryKind::kUnchecked);
600 }
601 Push(call);
602 if (result_type != nullptr && result_type->IsConstant()) {
603 Fragment instructions(call);
604 instructions += Drop();
605 instructions += Constant(result_type->constant_value);
606 return instructions;
607 }
608 return Fragment(call);
609}
610
611Fragment FlowGraphBuilder::StringInterpolateSingle(TokenPosition position) {
612 const int kTypeArgsLen = 0;
613 const int kNumberOfArguments = 1;
614 const Array& kNoArgumentNames = Object::null_array();
615 const Class& cls =
616 Class::Handle(Library::LookupCoreClass(Symbols::StringBase()));
617 ASSERT(!cls.IsNull());
618 const Function& function = Function::ZoneHandle(
619 Z, Resolver::ResolveStatic(
620 cls, Library::PrivateCoreLibName(Symbols::InterpolateSingle()),
621 kTypeArgsLen, kNumberOfArguments, kNoArgumentNames));
622 Fragment instructions;
623 instructions +=
624 StaticCall(position, function, /* argument_count = */ 1, ICData::kStatic);
625 return instructions;
626}
627
628Fragment FlowGraphBuilder::ThrowTypeError() {
629 const Class& klass =
630 Class::ZoneHandle(Z, Library::LookupCoreClass(Symbols::TypeError()));
631 ASSERT(!klass.IsNull());
632 GrowableHandlePtrArray<const String> pieces(Z, 3);
633 pieces.Add(Symbols::TypeError());
634 pieces.Add(Symbols::Dot());
635 pieces.Add(H.DartSymbolObfuscate("_create"));
636
637 const Function& constructor = Function::ZoneHandle(
638 Z, klass.LookupConstructorAllowPrivate(
639 String::ZoneHandle(Z, Symbols::FromConcatAll(thread_, pieces))));
640 ASSERT(!constructor.IsNull());
641
642 const String& url = H.DartString(
643 parsed_function_->function().ToLibNamePrefixedQualifiedCString(),
644 Heap::kOld);
645
646 Fragment instructions;
647
648 // Create instance of _FallThroughError
649 instructions += AllocateObject(TokenPosition::kNoSource, klass, 0);
650 LocalVariable* instance = MakeTemporary();
651
652 // Call _TypeError._create constructor.
653 instructions += LoadLocal(instance); // this
654 instructions += Constant(url); // url
655 instructions += NullConstant(); // line
656 instructions += IntConstant(0); // column
657 instructions += Constant(H.DartSymbolPlain("Malformed type.")); // message
658
659 instructions += StaticCall(TokenPosition::kNoSource, constructor,
660 /* argument_count = */ 5, ICData::kStatic);
661 instructions += Drop();
662
663 // Throw the exception
664 instructions += ThrowException(TokenPosition::kNoSource);
665
666 return instructions;
667}
668
669Fragment FlowGraphBuilder::ThrowNoSuchMethodError(const Function& target) {
670 const Class& klass = Class::ZoneHandle(
671 Z, Library::LookupCoreClass(Symbols::NoSuchMethodError()));
672 ASSERT(!klass.IsNull());
673 const Function& throw_function = Function::ZoneHandle(
674 Z, klass.LookupStaticFunctionAllowPrivate(Symbols::ThrowNew()));
675 ASSERT(!throw_function.IsNull());
676
677 Fragment instructions;
678
679 const Class& owner = Class::Handle(Z, target.Owner());
680 AbstractType& receiver = AbstractType::ZoneHandle();
681 InvocationMirror::Kind kind = InvocationMirror::Kind::kMethod;
682 InvocationMirror::Level level;
683 if (owner.IsTopLevel()) {
684 level = InvocationMirror::Level::kTopLevel;
685 } else {
686 receiver = owner.RareType();
687 if (target.kind() == FunctionLayout::kConstructor) {
688 level = InvocationMirror::Level::kConstructor;
689 } else {
690 level = InvocationMirror::Level::kStatic;
691 }
692 }
693
694 // Call NoSuchMethodError._throwNew static function.
695 instructions += Constant(receiver); // receiver
696 instructions += Constant(String::ZoneHandle(Z, target.name())); // memberName
697 instructions += IntConstant(InvocationMirror::EncodeType(level, kind));
698 instructions += IntConstant(0); // type arguments length
699 instructions += NullConstant(); // type arguments
700 instructions += NullConstant(); // arguments
701 instructions += NullConstant(); // argumentNames
702
703 instructions += StaticCall(TokenPosition::kNoSource, throw_function,
704 /* argument_count = */ 7, ICData::kStatic);
705
706 // Properly close graph with a ThrowInstr, although it is not executed.
707 instructions += ThrowException(TokenPosition::kNoSource);
708 instructions += Drop();
709
710 return instructions;
711}
712
713LocalVariable* FlowGraphBuilder::LookupVariable(intptr_t kernel_offset) {
714 LocalVariable* local = scopes_->locals.Lookup(kernel_offset);
715 ASSERT(local != NULL);
716 return local;
717}
718
719FlowGraph* FlowGraphBuilder::BuildGraph() {
720 const Function& function = parsed_function_->function();
721
722#ifdef DEBUG
723 // If we attached the native name to the function after it's creation (namely
724 // after reading the constant table from the kernel blob), we must have done
725 // so before building flow graph for the functions (since FGB depends needs
726 // the native name to be there).
727 const Script& script = Script::Handle(Z, function.script());
728 const KernelProgramInfo& info =
729 KernelProgramInfo::Handle(script.kernel_program_info());
730 ASSERT(info.IsNull() ||
731 info.potential_natives() == GrowableObjectArray::null());
732#endif
733
734 auto& kernel_data = ExternalTypedData::Handle(Z);
735 intptr_t kernel_data_program_offset = 0;
736 if (!function.is_declared_in_bytecode()) {
737 kernel_data = function.KernelData();
738 kernel_data_program_offset = function.KernelDataProgramOffset();
739 }
740
741 // TODO(alexmarkov): refactor this - StreamingFlowGraphBuilder should not be
742 // used for bytecode functions.
743 StreamingFlowGraphBuilder streaming_flow_graph_builder(
744 this, kernel_data, kernel_data_program_offset);
745 return streaming_flow_graph_builder.BuildGraph();
746}
747
748Fragment FlowGraphBuilder::NativeFunctionBody(const Function& function,
749 LocalVariable* first_parameter) {
750 ASSERT(function.is_native());
751 ASSERT(!IsRecognizedMethodForFlowGraph(function));
752
753 Fragment body;
754 String& name = String::ZoneHandle(Z, function.native_name());
755 if (function.IsGeneric()) {
756 body += LoadLocal(parsed_function_->RawTypeArgumentsVariable());
757 }
758 for (intptr_t i = 0; i < function.NumParameters(); ++i) {
759 body += LoadLocal(parsed_function_->RawParameterVariable(i));
760 }
761 body += NativeCall(&name, &function);
762 // We typecheck results of native calls for type safety.
763 body +=
764 Return(TokenPosition::kNoSource, /* omit_result_type_check = */ false);
765 return body;
766}
767
768bool FlowGraphBuilder::IsRecognizedMethodForFlowGraph(
769 const Function& function) {
770 const MethodRecognizer::Kind kind = function.recognized_kind();
771
772 switch (kind) {
773 case MethodRecognizer::kTypedData_ByteDataView_factory:
774 case MethodRecognizer::kTypedData_Int8ArrayView_factory:
775 case MethodRecognizer::kTypedData_Uint8ArrayView_factory:
776 case MethodRecognizer::kTypedData_Uint8ClampedArrayView_factory:
777 case MethodRecognizer::kTypedData_Int16ArrayView_factory:
778 case MethodRecognizer::kTypedData_Uint16ArrayView_factory:
779 case MethodRecognizer::kTypedData_Int32ArrayView_factory:
780 case MethodRecognizer::kTypedData_Uint32ArrayView_factory:
781 case MethodRecognizer::kTypedData_Int64ArrayView_factory:
782 case MethodRecognizer::kTypedData_Uint64ArrayView_factory:
783 case MethodRecognizer::kTypedData_Float32ArrayView_factory:
784 case MethodRecognizer::kTypedData_Float64ArrayView_factory:
785 case MethodRecognizer::kTypedData_Float32x4ArrayView_factory:
786 case MethodRecognizer::kTypedData_Int32x4ArrayView_factory:
787 case MethodRecognizer::kTypedData_Float64x2ArrayView_factory:
788 case MethodRecognizer::kFfiLoadInt8:
789 case MethodRecognizer::kFfiLoadInt16:
790 case MethodRecognizer::kFfiLoadInt32:
791 case MethodRecognizer::kFfiLoadInt64:
792 case MethodRecognizer::kFfiLoadUint8:
793 case MethodRecognizer::kFfiLoadUint16:
794 case MethodRecognizer::kFfiLoadUint32:
795 case MethodRecognizer::kFfiLoadUint64:
796 case MethodRecognizer::kFfiLoadIntPtr:
797 case MethodRecognizer::kFfiLoadFloat:
798 case MethodRecognizer::kFfiLoadDouble:
799 case MethodRecognizer::kFfiLoadPointer:
800 case MethodRecognizer::kFfiStoreInt8:
801 case MethodRecognizer::kFfiStoreInt16:
802 case MethodRecognizer::kFfiStoreInt32:
803 case MethodRecognizer::kFfiStoreInt64:
804 case MethodRecognizer::kFfiStoreUint8:
805 case MethodRecognizer::kFfiStoreUint16:
806 case MethodRecognizer::kFfiStoreUint32:
807 case MethodRecognizer::kFfiStoreUint64:
808 case MethodRecognizer::kFfiStoreIntPtr:
809 case MethodRecognizer::kFfiStoreFloat:
810 case MethodRecognizer::kFfiStoreDouble:
811 case MethodRecognizer::kFfiStorePointer:
812 case MethodRecognizer::kFfiFromAddress:
813 case MethodRecognizer::kFfiGetAddress:
814 // This list must be kept in sync with BytecodeReaderHelper::NativeEntry in
815 // runtime/vm/compiler/frontend/bytecode_reader.cc and implemented in the
816 // bytecode interpreter in runtime/vm/interpreter.cc. Alternatively, these
817 // methods must work in their original form (a Dart body or native entry) in
818 // the bytecode interpreter.
819 case MethodRecognizer::kObjectEquals:
820 case MethodRecognizer::kStringBaseLength:
821 case MethodRecognizer::kStringBaseIsEmpty:
822 case MethodRecognizer::kGrowableArrayLength:
823 case MethodRecognizer::kObjectArrayLength:
824 case MethodRecognizer::kImmutableArrayLength:
825 case MethodRecognizer::kTypedListLength:
826 case MethodRecognizer::kTypedListViewLength:
827 case MethodRecognizer::kByteDataViewLength:
828 case MethodRecognizer::kByteDataViewOffsetInBytes:
829 case MethodRecognizer::kTypedDataViewOffsetInBytes:
830 case MethodRecognizer::kByteDataViewTypedData:
831 case MethodRecognizer::kTypedDataViewTypedData:
832 case MethodRecognizer::kClassIDgetID:
833 case MethodRecognizer::kGrowableArrayCapacity:
834 case MethodRecognizer::kListFactory:
835 case MethodRecognizer::kObjectArrayAllocate:
836 case MethodRecognizer::kCopyRangeFromUint8ListToOneByteString:
837 case MethodRecognizer::kLinkedHashMap_getIndex:
838 case MethodRecognizer::kLinkedHashMap_setIndex:
839 case MethodRecognizer::kLinkedHashMap_getData:
840 case MethodRecognizer::kLinkedHashMap_setData:
841 case MethodRecognizer::kLinkedHashMap_getHashMask:
842 case MethodRecognizer::kLinkedHashMap_setHashMask:
843 case MethodRecognizer::kLinkedHashMap_getUsedData:
844 case MethodRecognizer::kLinkedHashMap_setUsedData:
845 case MethodRecognizer::kLinkedHashMap_getDeletedKeys:
846 case MethodRecognizer::kLinkedHashMap_setDeletedKeys:
847 case MethodRecognizer::kFfiAbi:
848 case MethodRecognizer::kReachabilityFence:
849 case MethodRecognizer::kUtf8DecoderScan:
850 return true;
851 case MethodRecognizer::kAsyncStackTraceHelper:
852 return !FLAG_causal_async_stacks;
853 default:
854 return false;
855 }
856}
857
858FlowGraph* FlowGraphBuilder::BuildGraphOfRecognizedMethod(
859 const Function& function) {
860 ASSERT(IsRecognizedMethodForFlowGraph(function));
861
862 graph_entry_ =
863 new (Z) GraphEntryInstr(*parsed_function_, Compiler::kNoOSRDeoptId);
864
865 auto normal_entry = BuildFunctionEntry(graph_entry_);
866 graph_entry_->set_normal_entry(normal_entry);
867
868 PrologueInfo prologue_info(-1, -1);
869 BlockEntryInstr* instruction_cursor =
870 BuildPrologue(normal_entry, &prologue_info);
871
872 Fragment body(instruction_cursor);
873 body += CheckStackOverflowInPrologue(function.token_pos());
874
875 const MethodRecognizer::Kind kind = function.recognized_kind();
876 switch (kind) {
877 case MethodRecognizer::kTypedData_ByteDataView_factory:
878 body += BuildTypedDataViewFactoryConstructor(function, kByteDataViewCid);
879 break;
880 case MethodRecognizer::kTypedData_Int8ArrayView_factory:
881 body += BuildTypedDataViewFactoryConstructor(function,
882 kTypedDataInt8ArrayViewCid);
883 break;
884 case MethodRecognizer::kTypedData_Uint8ArrayView_factory:
885 body += BuildTypedDataViewFactoryConstructor(function,
886 kTypedDataUint8ArrayViewCid);
887 break;
888 case MethodRecognizer::kTypedData_Uint8ClampedArrayView_factory:
889 body += BuildTypedDataViewFactoryConstructor(
890 function, kTypedDataUint8ClampedArrayViewCid);
891 break;
892 case MethodRecognizer::kTypedData_Int16ArrayView_factory:
893 body += BuildTypedDataViewFactoryConstructor(function,
894 kTypedDataInt16ArrayViewCid);
895 break;
896 case MethodRecognizer::kTypedData_Uint16ArrayView_factory:
897 body += BuildTypedDataViewFactoryConstructor(
898 function, kTypedDataUint16ArrayViewCid);
899 break;
900 case MethodRecognizer::kTypedData_Int32ArrayView_factory:
901 body += BuildTypedDataViewFactoryConstructor(function,
902 kTypedDataInt32ArrayViewCid);
903 break;
904 case MethodRecognizer::kTypedData_Uint32ArrayView_factory:
905 body += BuildTypedDataViewFactoryConstructor(
906 function, kTypedDataUint32ArrayViewCid);
907 break;
908 case MethodRecognizer::kTypedData_Int64ArrayView_factory:
909 body += BuildTypedDataViewFactoryConstructor(function,
910 kTypedDataInt64ArrayViewCid);
911 break;
912 case MethodRecognizer::kTypedData_Uint64ArrayView_factory:
913 body += BuildTypedDataViewFactoryConstructor(
914 function, kTypedDataUint64ArrayViewCid);
915 break;
916 case MethodRecognizer::kTypedData_Float32ArrayView_factory:
917 body += BuildTypedDataViewFactoryConstructor(
918 function, kTypedDataFloat32ArrayViewCid);
919 break;
920 case MethodRecognizer::kTypedData_Float64ArrayView_factory:
921 body += BuildTypedDataViewFactoryConstructor(
922 function, kTypedDataFloat64ArrayViewCid);
923 break;
924 case MethodRecognizer::kTypedData_Float32x4ArrayView_factory:
925 body += BuildTypedDataViewFactoryConstructor(
926 function, kTypedDataFloat32x4ArrayViewCid);
927 break;
928 case MethodRecognizer::kTypedData_Int32x4ArrayView_factory:
929 body += BuildTypedDataViewFactoryConstructor(
930 function, kTypedDataInt32x4ArrayViewCid);
931 break;
932 case MethodRecognizer::kTypedData_Float64x2ArrayView_factory:
933 body += BuildTypedDataViewFactoryConstructor(
934 function, kTypedDataFloat64x2ArrayViewCid);
935 break;
936 case MethodRecognizer::kObjectEquals:
937 ASSERT(function.NumParameters() == 2);
938 body += LoadLocal(parsed_function_->RawParameterVariable(0));
939 body += LoadLocal(parsed_function_->RawParameterVariable(1));
940 body += StrictCompare(Token::kEQ_STRICT);
941 break;
942 case MethodRecognizer::kStringBaseLength:
943 case MethodRecognizer::kStringBaseIsEmpty:
944 ASSERT(function.NumParameters() == 1);
945 body += LoadLocal(parsed_function_->RawParameterVariable(0));
946 body += LoadNativeField(Slot::String_length());
947 if (kind == MethodRecognizer::kStringBaseIsEmpty) {
948 body += IntConstant(0);
949 body += StrictCompare(Token::kEQ_STRICT);
950 }
951 break;
952 case MethodRecognizer::kGrowableArrayLength:
953 ASSERT(function.NumParameters() == 1);
954 body += LoadLocal(parsed_function_->RawParameterVariable(0));
955 body += LoadNativeField(Slot::GrowableObjectArray_length());
956 break;
957 case MethodRecognizer::kObjectArrayLength:
958 case MethodRecognizer::kImmutableArrayLength:
959 ASSERT(function.NumParameters() == 1);
960 body += LoadLocal(parsed_function_->RawParameterVariable(0));
961 body += LoadNativeField(Slot::Array_length());
962 break;
963 case MethodRecognizer::kTypedListLength:
964 case MethodRecognizer::kTypedListViewLength:
965 case MethodRecognizer::kByteDataViewLength:
966 ASSERT(function.NumParameters() == 1);
967 body += LoadLocal(parsed_function_->RawParameterVariable(0));
968 body += LoadNativeField(Slot::TypedDataBase_length());
969 break;
970 case MethodRecognizer::kByteDataViewOffsetInBytes:
971 case MethodRecognizer::kTypedDataViewOffsetInBytes:
972 ASSERT(function.NumParameters() == 1);
973 body += LoadLocal(parsed_function_->RawParameterVariable(0));
974 body += LoadNativeField(Slot::TypedDataView_offset_in_bytes());
975 break;
976 case MethodRecognizer::kByteDataViewTypedData:
977 case MethodRecognizer::kTypedDataViewTypedData:
978 ASSERT(function.NumParameters() == 1);
979 body += LoadLocal(parsed_function_->RawParameterVariable(0));
980 body += LoadNativeField(Slot::TypedDataView_data());
981 break;
982 case MethodRecognizer::kClassIDgetID:
983 ASSERT(function.NumParameters() == 1);
984 body += LoadLocal(parsed_function_->RawParameterVariable(0));
985 body += LoadClassId();
986 break;
987 case MethodRecognizer::kGrowableArrayCapacity:
988 ASSERT(function.NumParameters() == 1);
989 body += LoadLocal(parsed_function_->RawParameterVariable(0));
990 body += LoadNativeField(Slot::GrowableObjectArray_data());
991 body += LoadNativeField(Slot::Array_length());
992 break;
993 case MethodRecognizer::kListFactory: {
994 ASSERT(function.IsFactory() && (function.NumParameters() == 2) &&
995 function.HasOptionalParameters());
996 // factory List<E>([int length]) {
997 // return (:arg_desc.positional_count == 2) ? new _List<E>(length)
998 // : new _GrowableList<E>(0);
999 // }
1000 const Library& core_lib = Library::Handle(Z, Library::CoreLibrary());
1001
1002 TargetEntryInstr *allocate_non_growable, *allocate_growable;
1003
1004 body += LoadArgDescriptor();
1005 body += LoadNativeField(Slot::ArgumentsDescriptor_positional_count());
1006 body += IntConstant(2);
1007 body += BranchIfStrictEqual(&allocate_non_growable, &allocate_growable);
1008
1009 JoinEntryInstr* join = BuildJoinEntry();
1010
1011 {
1012 const Class& cls = Class::Handle(
1013 Z, core_lib.LookupClass(
1014 Library::PrivateCoreLibName(Symbols::_List())));
1015 ASSERT(!cls.IsNull());
1016 const Function& func = Function::ZoneHandle(
1017 Z, cls.LookupFactoryAllowPrivate(Symbols::_ListFactory()));
1018 ASSERT(!func.IsNull());
1019
1020 Fragment allocate(allocate_non_growable);
1021 allocate += LoadLocal(parsed_function_->RawParameterVariable(0));
1022 allocate += LoadLocal(parsed_function_->RawParameterVariable(1));
1023 allocate +=
1024 StaticCall(TokenPosition::kNoSource, func, 2, ICData::kStatic);
1025 allocate += StoreLocal(TokenPosition::kNoSource,
1026 parsed_function_->expression_temp_var());
1027 allocate += Drop();
1028 allocate += Goto(join);
1029 }
1030
1031 {
1032 const Class& cls = Class::Handle(
1033 Z, core_lib.LookupClass(
1034 Library::PrivateCoreLibName(Symbols::_GrowableList())));
1035 ASSERT(!cls.IsNull());
1036 const Function& func = Function::ZoneHandle(
1037 Z, cls.LookupFactoryAllowPrivate(Symbols::_GrowableListFactory()));
1038 ASSERT(!func.IsNull());
1039
1040 Fragment allocate(allocate_growable);
1041 allocate += LoadLocal(parsed_function_->RawParameterVariable(0));
1042 allocate += IntConstant(0);
1043 allocate +=
1044 StaticCall(TokenPosition::kNoSource, func, 2, ICData::kStatic);
1045 allocate += StoreLocal(TokenPosition::kNoSource,
1046 parsed_function_->expression_temp_var());
1047 allocate += Drop();
1048 allocate += Goto(join);
1049 }
1050
1051 body = Fragment(body.entry, join);
1052 body += LoadLocal(parsed_function_->expression_temp_var());
1053 break;
1054 }
1055 case MethodRecognizer::kObjectArrayAllocate:
1056 ASSERT(function.IsFactory() && (function.NumParameters() == 2));
1057 body += LoadLocal(parsed_function_->RawParameterVariable(0));
1058 body += LoadLocal(parsed_function_->RawParameterVariable(1));
1059 body += CreateArray();
1060 break;
1061 case MethodRecognizer::kCopyRangeFromUint8ListToOneByteString:
1062 ASSERT(function.NumParameters() == 5);
1063 body += LoadLocal(parsed_function_->RawParameterVariable(0));
1064 body += LoadLocal(parsed_function_->RawParameterVariable(1));
1065 body += LoadLocal(parsed_function_->RawParameterVariable(2));
1066 body += LoadLocal(parsed_function_->RawParameterVariable(3));
1067 body += LoadLocal(parsed_function_->RawParameterVariable(4));
1068 body += MemoryCopy(kTypedDataUint8ArrayCid, kOneByteStringCid);
1069 body += NullConstant();
1070 break;
1071 case MethodRecognizer::kLinkedHashMap_getIndex:
1072 ASSERT(function.NumParameters() == 1);
1073 body += LoadLocal(parsed_function_->RawParameterVariable(0));
1074 body += LoadNativeField(Slot::LinkedHashMap_index());
1075 break;
1076 case MethodRecognizer::kLinkedHashMap_setIndex:
1077 ASSERT(function.NumParameters() == 2);
1078 body += LoadLocal(parsed_function_->RawParameterVariable(0));
1079 body += LoadLocal(parsed_function_->RawParameterVariable(1));
1080 body += StoreInstanceField(TokenPosition::kNoSource,
1081 Slot::LinkedHashMap_index());
1082 body += NullConstant();
1083 break;
1084 case MethodRecognizer::kLinkedHashMap_getData:
1085 ASSERT(function.NumParameters() == 1);
1086 body += LoadLocal(parsed_function_->RawParameterVariable(0));
1087 body += LoadNativeField(Slot::LinkedHashMap_data());
1088 break;
1089 case MethodRecognizer::kLinkedHashMap_setData:
1090 ASSERT(function.NumParameters() == 2);
1091 body += LoadLocal(parsed_function_->RawParameterVariable(0));
1092 body += LoadLocal(parsed_function_->RawParameterVariable(1));
1093 body += StoreInstanceField(TokenPosition::kNoSource,
1094 Slot::LinkedHashMap_data());
1095 body += NullConstant();
1096 break;
1097 case MethodRecognizer::kLinkedHashMap_getHashMask:
1098 ASSERT(function.NumParameters() == 1);
1099 body += LoadLocal(parsed_function_->RawParameterVariable(0));
1100 body += LoadNativeField(Slot::LinkedHashMap_hash_mask());
1101 break;
1102 case MethodRecognizer::kLinkedHashMap_setHashMask:
1103 ASSERT(function.NumParameters() == 2);
1104 body += LoadLocal(parsed_function_->RawParameterVariable(0));
1105 body += LoadLocal(parsed_function_->RawParameterVariable(1));
1106 body += StoreInstanceField(
1107 TokenPosition::kNoSource, Slot::LinkedHashMap_hash_mask(),
1108 StoreInstanceFieldInstr::Kind::kOther, kNoStoreBarrier);
1109 body += NullConstant();
1110 break;
1111 case MethodRecognizer::kLinkedHashMap_getUsedData:
1112 ASSERT(function.NumParameters() == 1);
1113 body += LoadLocal(parsed_function_->RawParameterVariable(0));
1114 body += LoadNativeField(Slot::LinkedHashMap_used_data());
1115 break;
1116 case MethodRecognizer::kLinkedHashMap_setUsedData:
1117 ASSERT(function.NumParameters() == 2);
1118 body += LoadLocal(parsed_function_->RawParameterVariable(0));
1119 body += LoadLocal(parsed_function_->RawParameterVariable(1));
1120 body += StoreInstanceField(
1121 TokenPosition::kNoSource, Slot::LinkedHashMap_used_data(),
1122 StoreInstanceFieldInstr::Kind::kOther, kNoStoreBarrier);
1123 body += NullConstant();
1124 break;
1125 case MethodRecognizer::kLinkedHashMap_getDeletedKeys:
1126 ASSERT(function.NumParameters() == 1);
1127 body += LoadLocal(parsed_function_->RawParameterVariable(0));
1128 body += LoadNativeField(Slot::LinkedHashMap_deleted_keys());
1129 break;
1130 case MethodRecognizer::kLinkedHashMap_setDeletedKeys:
1131 ASSERT(function.NumParameters() == 2);
1132 body += LoadLocal(parsed_function_->RawParameterVariable(0));
1133 body += LoadLocal(parsed_function_->RawParameterVariable(1));
1134 body += StoreInstanceField(
1135 TokenPosition::kNoSource, Slot::LinkedHashMap_deleted_keys(),
1136 StoreInstanceFieldInstr::Kind::kOther, kNoStoreBarrier);
1137 body += NullConstant();
1138 break;
1139 case MethodRecognizer::kAsyncStackTraceHelper:
1140 ASSERT(!FLAG_causal_async_stacks);
1141 body += NullConstant();
1142 break;
1143 case MethodRecognizer::kUtf8DecoderScan:
1144 ASSERT(function.NumParameters() == 5);
1145 body += LoadLocal(parsed_function_->RawParameterVariable(0)); // decoder
1146 body += LoadLocal(parsed_function_->RawParameterVariable(1)); // bytes
1147 body += LoadLocal(parsed_function_->RawParameterVariable(2)); // start
1148 body += CheckNullOptimized(TokenPosition::kNoSource,
1149 String::ZoneHandle(Z, function.name()));
1150 body += UnboxTruncate(kUnboxedIntPtr);
1151 body += LoadLocal(parsed_function_->RawParameterVariable(3)); // end
1152 body += CheckNullOptimized(TokenPosition::kNoSource,
1153 String::ZoneHandle(Z, function.name()));
1154 body += UnboxTruncate(kUnboxedIntPtr);
1155 body += LoadLocal(parsed_function_->RawParameterVariable(4)); // table
1156 body += Utf8Scan();
1157 body += Box(kUnboxedIntPtr);
1158 break;
1159 case MethodRecognizer::kReachabilityFence:
1160 ASSERT(function.NumParameters() == 1);
1161 body += LoadLocal(parsed_function_->RawParameterVariable(0));
1162 body += ReachabilityFence();
1163 body += NullConstant();
1164 break;
1165 case MethodRecognizer::kFfiAbi:
1166 ASSERT(function.NumParameters() == 0);
1167 body += IntConstant(static_cast<int64_t>(compiler::ffi::TargetAbi()));
1168 break;
1169 case MethodRecognizer::kFfiLoadInt8:
1170 case MethodRecognizer::kFfiLoadInt16:
1171 case MethodRecognizer::kFfiLoadInt32:
1172 case MethodRecognizer::kFfiLoadInt64:
1173 case MethodRecognizer::kFfiLoadUint8:
1174 case MethodRecognizer::kFfiLoadUint16:
1175 case MethodRecognizer::kFfiLoadUint32:
1176 case MethodRecognizer::kFfiLoadUint64:
1177 case MethodRecognizer::kFfiLoadIntPtr:
1178 case MethodRecognizer::kFfiLoadFloat:
1179 case MethodRecognizer::kFfiLoadDouble:
1180 case MethodRecognizer::kFfiLoadPointer: {
1181 const classid_t ffi_type_arg_cid =
1182 compiler::ffi::RecognizedMethodTypeArgCid(kind);
1183 const classid_t typed_data_cid =
1184 compiler::ffi::ElementTypedDataCid(ffi_type_arg_cid);
1185 const auto& native_rep = compiler::ffi::NativeType::FromTypedDataClassId(
1186 ffi_type_arg_cid, zone_);
1187
1188 ASSERT(function.NumParameters() == 2);
1189 LocalVariable* arg_pointer = parsed_function_->RawParameterVariable(0);
1190 LocalVariable* arg_offset = parsed_function_->RawParameterVariable(1);
1191
1192 body += LoadLocal(arg_offset);
1193 body += CheckNullOptimized(TokenPosition::kNoSource,
1194 String::ZoneHandle(Z, function.name()));
1195 LocalVariable* arg_offset_not_null = MakeTemporary();
1196
1197 body += LoadLocal(arg_pointer);
1198 body += CheckNullOptimized(TokenPosition::kNoSource,
1199 String::ZoneHandle(Z, function.name()));
1200 // No GC from here til LoadIndexed.
1201 body += LoadUntagged(compiler::target::PointerBase::data_field_offset());
1202 body += LoadLocal(arg_offset_not_null);
1203 body += UnboxTruncate(kUnboxedFfiIntPtr);
1204 body += LoadIndexedTypedData(typed_data_cid, /*index_scale=*/1,
1205 /*index_unboxed=*/true);
1206 if (kind == MethodRecognizer::kFfiLoadFloat ||
1207 kind == MethodRecognizer::kFfiLoadDouble) {
1208 if (kind == MethodRecognizer::kFfiLoadFloat) {
1209 body += FloatToDouble();
1210 }
1211 body += Box(kUnboxedDouble);
1212 } else {
1213 body += Box(native_rep.AsRepresentationOverApprox(zone_));
1214 if (kind == MethodRecognizer::kFfiLoadPointer) {
1215 const auto class_table = thread_->isolate()->class_table();
1216 ASSERT(class_table->HasValidClassAt(kFfiPointerCid));
1217 const auto& pointer_class =
1218 Class::ZoneHandle(H.zone(), class_table->At(kFfiPointerCid));
1219
1220 // We find the reified type to use for the pointer allocation.
1221 //
1222 // Call sites to this recognized method are guaranteed to pass a
1223 // Pointer<Pointer<X>> as RawParameterVariable(0). This function
1224 // will return a Pointer<X> object - for which we inspect the
1225 // reified type on the argument.
1226 //
1227 // The following is safe to do, as (1) we are guaranteed to have a
1228 // Pointer<Pointer<X>> as argument, and (2) the bound on the pointer
1229 // type parameter guarantees X is an interface type.
1230 ASSERT(function.NumTypeParameters() == 1);
1231 LocalVariable* address = MakeTemporary();
1232 body += LoadLocal(parsed_function_->RawParameterVariable(0));
1233 body += LoadNativeField(
1234 Slot::GetTypeArgumentsSlotFor(thread_, pointer_class));
1235 body += LoadNativeField(Slot::GetTypeArgumentsIndexSlot(
1236 thread_, Pointer::kNativeTypeArgPos));
1237 body += LoadNativeField(Slot::Type_arguments());
1238 body += AllocateObject(TokenPosition::kNoSource, pointer_class, 1);
1239 LocalVariable* pointer = MakeTemporary();
1240 body += LoadLocal(pointer);
1241 body += LoadLocal(address);
1242 body += UnboxTruncate(kUnboxedFfiIntPtr);
1243 body += ConvertUnboxedToUntagged(kUnboxedFfiIntPtr);
1244 body += StoreUntagged(compiler::target::Pointer::data_field_offset());
1245 body += DropTempsPreserveTop(1); // Drop [address] keep [pointer].
1246 }
1247 }
1248 body += DropTempsPreserveTop(1); // Drop [arg_offset].
1249 } break;
1250 case MethodRecognizer::kFfiStoreInt8:
1251 case MethodRecognizer::kFfiStoreInt16:
1252 case MethodRecognizer::kFfiStoreInt32:
1253 case MethodRecognizer::kFfiStoreInt64:
1254 case MethodRecognizer::kFfiStoreUint8:
1255 case MethodRecognizer::kFfiStoreUint16:
1256 case MethodRecognizer::kFfiStoreUint32:
1257 case MethodRecognizer::kFfiStoreUint64:
1258 case MethodRecognizer::kFfiStoreIntPtr:
1259 case MethodRecognizer::kFfiStoreFloat:
1260 case MethodRecognizer::kFfiStoreDouble:
1261 case MethodRecognizer::kFfiStorePointer: {
1262 const classid_t ffi_type_arg_cid =
1263 compiler::ffi::RecognizedMethodTypeArgCid(kind);
1264 const classid_t typed_data_cid =
1265 compiler::ffi::ElementTypedDataCid(ffi_type_arg_cid);
1266 const auto& native_rep = compiler::ffi::NativeType::FromTypedDataClassId(
1267 ffi_type_arg_cid, zone_);
1268
1269 LocalVariable* arg_pointer = parsed_function_->RawParameterVariable(0);
1270 LocalVariable* arg_offset = parsed_function_->RawParameterVariable(1);
1271 LocalVariable* arg_value = parsed_function_->RawParameterVariable(2);
1272
1273 if (kind == MethodRecognizer::kFfiStorePointer) {
1274 // Do type check before anything untagged is on the stack.
1275 const auto class_table = thread_->isolate()->class_table();
1276 ASSERT(class_table->HasValidClassAt(kFfiPointerCid));
1277 const auto& pointer_class =
1278 Class::ZoneHandle(H.zone(), class_table->At(kFfiPointerCid));
1279 const auto& pointer_type_args =
1280 TypeArguments::Handle(pointer_class.type_parameters());
1281 const auto& pointer_type_arg =
1282 AbstractType::ZoneHandle(pointer_type_args.TypeAt(0));
1283
1284 // But we type check it as a method on a generic class at runtime.
1285 body += LoadLocal(arg_value); // value.
1286 body += Constant(pointer_type_arg); // dst_type.
1287 // We pass the Pointer type argument as instantiator_type_args.
1288 //
1289 // Call sites to this recognized method are guaranteed to pass a
1290 // Pointer<Pointer<X>> as RawParameterVariable(0). This function
1291 // will takes a Pointer<X> object - for which we inspect the
1292 // reified type on the argument.
1293 //
1294 // The following is safe to do, as (1) we are guaranteed to have a
1295 // Pointer<Pointer<X>> as argument, and (2) the bound on the pointer
1296 // type parameter guarantees X is an interface type.
1297 body += LoadLocal(arg_pointer);
1298 body += CheckNullOptimized(TokenPosition::kNoSource,
1299 String::ZoneHandle(Z, function.name()));
1300 body += LoadNativeField(
1301 Slot::GetTypeArgumentsSlotFor(thread_, pointer_class));
1302 body += NullConstant(); // function_type_args.
1303 body += AssertAssignable(TokenPosition::kNoSource, Symbols::Empty());
1304 body += Drop();
1305 }
1306
1307 ASSERT(function.NumParameters() == 3);
1308 body += LoadLocal(arg_offset);
1309 body += CheckNullOptimized(TokenPosition::kNoSource,
1310 String::ZoneHandle(Z, function.name()));
1311 LocalVariable* arg_offset_not_null = MakeTemporary();
1312 body += LoadLocal(arg_value);
1313 body += CheckNullOptimized(TokenPosition::kNoSource,
1314 String::ZoneHandle(Z, function.name()));
1315 LocalVariable* arg_value_not_null = MakeTemporary();
1316
1317 body += LoadLocal(arg_pointer); // Pointer.
1318 body += CheckNullOptimized(TokenPosition::kNoSource,
1319 String::ZoneHandle(Z, function.name()));
1320 // No GC from here til StoreIndexed.
1321 body += LoadUntagged(compiler::target::PointerBase::data_field_offset());
1322 body += LoadLocal(arg_offset_not_null);
1323 body += UnboxTruncate(kUnboxedFfiIntPtr);
1324 body += LoadLocal(arg_value_not_null);
1325 if (kind == MethodRecognizer::kFfiStorePointer) {
1326 // This can only be Pointer, so it is always safe to LoadUntagged.
1327 body += LoadUntagged(compiler::target::Pointer::data_field_offset());
1328 body += ConvertUntaggedToUnboxed(kUnboxedFfiIntPtr);
1329 } else if (kind == MethodRecognizer::kFfiStoreFloat ||
1330 kind == MethodRecognizer::kFfiStoreDouble) {
1331 body += UnboxTruncate(kUnboxedDouble);
1332 if (kind == MethodRecognizer::kFfiStoreFloat) {
1333 body += DoubleToFloat();
1334 }
1335 } else {
1336 body += UnboxTruncate(native_rep.AsRepresentationOverApprox(zone_));
1337 }
1338 body += StoreIndexedTypedData(typed_data_cid, /*index_scale=*/1,
1339 /*index_unboxed=*/true);
1340 body += Drop(); // Drop [arg_value].
1341 body += Drop(); // Drop [arg_offset].
1342 body += NullConstant();
1343 } break;
1344 case MethodRecognizer::kFfiFromAddress: {
1345 const auto class_table = thread_->isolate()->class_table();
1346 ASSERT(class_table->HasValidClassAt(kFfiPointerCid));
1347 const auto& pointer_class =
1348 Class::ZoneHandle(H.zone(), class_table->At(kFfiPointerCid));
1349
1350 ASSERT(function.NumTypeParameters() == 1);
1351 ASSERT(function.NumParameters() == 1);
1352 body += LoadLocal(parsed_function_->RawTypeArgumentsVariable());
1353 body += AllocateObject(TokenPosition::kNoSource, pointer_class, 1);
1354 body += LoadLocal(MakeTemporary()); // Duplicate Pointer.
1355 body += LoadLocal(parsed_function_->RawParameterVariable(0)); // Address.
1356 body += CheckNullOptimized(TokenPosition::kNoSource,
1357 String::ZoneHandle(Z, function.name()));
1358 body += UnboxTruncate(kUnboxedFfiIntPtr);
1359 body += ConvertUnboxedToUntagged(kUnboxedFfiIntPtr);
1360 body += StoreUntagged(compiler::target::Pointer::data_field_offset());
1361 } break;
1362 case MethodRecognizer::kFfiGetAddress: {
1363 ASSERT(function.NumParameters() == 1);
1364 body += LoadLocal(parsed_function_->RawParameterVariable(0)); // Pointer.
1365 body += CheckNullOptimized(TokenPosition::kNoSource,
1366 String::ZoneHandle(Z, function.name()));
1367 // This can only be Pointer, so it is always safe to LoadUntagged.
1368 body += LoadUntagged(compiler::target::Pointer::data_field_offset());
1369 body += ConvertUntaggedToUnboxed(kUnboxedFfiIntPtr);
1370 body += Box(kUnboxedFfiIntPtr);
1371 } break;
1372 default: {
1373 UNREACHABLE();
1374 break;
1375 }
1376 }
1377
1378 body += Return(TokenPosition::kNoSource, /* omit_result_type_check = */ true);
1379
1380 return new (Z) FlowGraph(*parsed_function_, graph_entry_, last_used_block_id_,
1381 prologue_info);
1382}
1383
1384Fragment FlowGraphBuilder::BuildTypedDataViewFactoryConstructor(
1385 const Function& function,
1386 classid_t cid) {
1387 auto token_pos = function.token_pos();
1388 auto class_table = Thread::Current()->isolate()->class_table();
1389
1390 ASSERT(class_table->HasValidClassAt(cid));
1391 const auto& view_class = Class::ZoneHandle(H.zone(), class_table->At(cid));
1392
1393 ASSERT(function.IsFactory() && (function.NumParameters() == 4));
1394 LocalVariable* typed_data = parsed_function_->RawParameterVariable(1);
1395 LocalVariable* offset_in_bytes = parsed_function_->RawParameterVariable(2);
1396 LocalVariable* length = parsed_function_->RawParameterVariable(3);
1397
1398 Fragment body;
1399
1400 body += AllocateObject(token_pos, view_class, /*arg_count=*/0);
1401 LocalVariable* view_object = MakeTemporary();
1402
1403 body += LoadLocal(view_object);
1404 body += LoadLocal(typed_data);
1405 body += StoreInstanceField(token_pos, Slot::TypedDataView_data(),
1406 StoreInstanceFieldInstr::Kind::kInitializing);
1407
1408 body += LoadLocal(view_object);
1409 body += LoadLocal(offset_in_bytes);
1410 body += StoreInstanceField(token_pos, Slot::TypedDataView_offset_in_bytes(),
1411 StoreInstanceFieldInstr::Kind::kInitializing,
1412 kNoStoreBarrier);
1413
1414 body += LoadLocal(view_object);
1415 body += LoadLocal(length);
1416 body += StoreInstanceField(token_pos, Slot::TypedDataBase_length(),
1417 StoreInstanceFieldInstr::Kind::kInitializing,
1418 kNoStoreBarrier);
1419
1420 // Update the inner pointer.
1421 //
1422 // WARNING: Notice that we assume here no GC happens between those 4
1423 // instructions!
1424 body += LoadLocal(view_object);
1425 body += LoadLocal(typed_data);
1426 body += LoadUntagged(compiler::target::TypedDataBase::data_field_offset());
1427 body += ConvertUntaggedToUnboxed(kUnboxedIntPtr);
1428 body += LoadLocal(offset_in_bytes);
1429 body += UnboxSmiToIntptr();
1430 body += AddIntptrIntegers();
1431 body += ConvertUnboxedToUntagged(kUnboxedIntPtr);
1432 body += StoreUntagged(compiler::target::TypedDataBase::data_field_offset());
1433
1434 return body;
1435}
1436
1437static const LocalScope* MakeImplicitClosureScope(Zone* Z, const Class& klass) {
1438 ASSERT(!klass.IsNull());
1439 // Note that if klass is _Closure, DeclarationType will be _Closure,
1440 // and not the signature type.
1441 Type& klass_type = Type::ZoneHandle(Z, klass.DeclarationType());
1442
1443 LocalVariable* receiver_variable = new (Z)
1444 LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
1445 Symbols::This(), klass_type, /*param_type=*/nullptr);
1446
1447 receiver_variable->set_is_captured();
1448 // receiver_variable->set_is_final();
1449 LocalScope* scope = new (Z) LocalScope(NULL, 0, 0);
1450 scope->set_context_level(0);
1451 scope->AddVariable(receiver_variable);
1452 scope->AddContextVariable(receiver_variable);
1453 return scope;
1454}
1455
1456Fragment FlowGraphBuilder::BuildImplicitClosureCreation(
1457 const Function& target) {
1458 Fragment fragment;
1459 fragment += AllocateClosure(TokenPosition::kNoSource, target);
1460 LocalVariable* closure = MakeTemporary();
1461
1462 // The function signature can have uninstantiated class type parameters.
1463 if (!target.HasInstantiatedSignature(kCurrentClass)) {
1464 fragment += LoadLocal(closure);
1465 fragment += LoadInstantiatorTypeArguments();
1466 fragment += StoreInstanceField(
1467 TokenPosition::kNoSource, Slot::Closure_instantiator_type_arguments(),
1468 StoreInstanceFieldInstr::Kind::kInitializing);
1469 }
1470
1471 // The function signature cannot have uninstantiated function type parameters,
1472 // because the function cannot be local and have parent generic functions.
1473 ASSERT(target.HasInstantiatedSignature(kFunctions));
1474
1475 // Allocate a context that closes over `this`.
1476 // Note: this must be kept in sync with ScopeBuilder::BuildScopes.
1477 const LocalScope* implicit_closure_scope =
1478 MakeImplicitClosureScope(Z, Class::Handle(Z, target.Owner()));
1479 fragment += AllocateContext(implicit_closure_scope->context_slots());
1480 LocalVariable* context = MakeTemporary();
1481
1482 // Store the function and the context in the closure.
1483 fragment += LoadLocal(closure);
1484 fragment += Constant(target);
1485 fragment +=
1486 StoreInstanceField(TokenPosition::kNoSource, Slot::Closure_function(),
1487 StoreInstanceFieldInstr::Kind::kInitializing);
1488
1489 fragment += LoadLocal(closure);
1490 fragment += LoadLocal(context);
1491 fragment +=
1492 StoreInstanceField(TokenPosition::kNoSource, Slot::Closure_context(),
1493 StoreInstanceFieldInstr::Kind::kInitializing);
1494
1495 if (target.IsGeneric()) {
1496 // Only generic functions need to have properly initialized
1497 // delayed_type_arguments.
1498 fragment += LoadLocal(closure);
1499 fragment += Constant(Object::empty_type_arguments());
1500 fragment += StoreInstanceField(
1501 TokenPosition::kNoSource, Slot::Closure_delayed_type_arguments(),
1502 StoreInstanceFieldInstr::Kind::kInitializing);
1503 }
1504
1505 // The context is on top of the operand stack. Store `this`. The context
1506 // doesn't need a parent pointer because it doesn't close over anything
1507 // else.
1508 fragment += LoadLocal(parsed_function_->receiver_var());
1509 fragment += StoreInstanceField(
1510 TokenPosition::kNoSource,
1511 Slot::GetContextVariableSlotFor(
1512 thread_, *implicit_closure_scope->context_variables()[0]),
1513 StoreInstanceFieldInstr::Kind::kInitializing);
1514
1515 return fragment;
1516}
1517
1518Fragment FlowGraphBuilder::CheckVariableTypeInCheckedMode(
1519 const AbstractType& dst_type,
1520 const String& name_symbol) {
1521 return Fragment();
1522}
1523
1524bool FlowGraphBuilder::NeedsDebugStepCheck(const Function& function,
1525 TokenPosition position) {
1526 return position.IsDebugPause() && !function.is_native() &&
1527 function.is_debuggable();
1528}
1529
1530bool FlowGraphBuilder::NeedsDebugStepCheck(Value* value,
1531 TokenPosition position) {
1532 if (!position.IsDebugPause()) {
1533 return false;
1534 }
1535 Definition* definition = value->definition();
1536 if (definition->IsConstant() || definition->IsLoadStaticField()) {
1537 return true;
1538 }
1539 if (definition->IsAllocateObject()) {
1540 return !definition->AsAllocateObject()->closure_function().IsNull();
1541 }
1542 return definition->IsLoadLocal();
1543}
1544
1545Fragment FlowGraphBuilder::EvaluateAssertion() {
1546 const Class& klass =
1547 Class::ZoneHandle(Z, Library::LookupCoreClass(Symbols::AssertionError()));
1548 ASSERT(!klass.IsNull());
1549 const Function& target = Function::ZoneHandle(
1550 Z, klass.LookupStaticFunctionAllowPrivate(Symbols::EvaluateAssertion()));
1551 ASSERT(!target.IsNull());
1552 return StaticCall(TokenPosition::kNoSource, target, /* argument_count = */ 1,
1553 ICData::kStatic);
1554}
1555
1556Fragment FlowGraphBuilder::CheckBoolean(TokenPosition position) {
1557 Fragment instructions;
1558 LocalVariable* top_of_stack = MakeTemporary();
1559 instructions += LoadLocal(top_of_stack);
1560 instructions += AssertBool(position);
1561 instructions += Drop();
1562 return instructions;
1563}
1564
1565Fragment FlowGraphBuilder::CheckAssignable(const AbstractType& dst_type,
1566 const String& dst_name,
1567 AssertAssignableInstr::Kind kind) {
1568 Fragment instructions;
1569 if (!dst_type.IsTopTypeForSubtyping()) {
1570 LocalVariable* top_of_stack = MakeTemporary();
1571 instructions += LoadLocal(top_of_stack);
1572 instructions += AssertAssignableLoadTypeArguments(TokenPosition::kNoSource,
1573 dst_type, dst_name, kind);
1574 instructions += Drop();
1575 }
1576 return instructions;
1577}
1578
1579Fragment FlowGraphBuilder::AssertAssignableLoadTypeArguments(
1580 TokenPosition position,
1581 const AbstractType& dst_type,
1582 const String& dst_name,
1583 AssertAssignableInstr::Kind kind) {
1584 Fragment instructions;
1585
1586 instructions += Constant(AbstractType::ZoneHandle(dst_type.raw()));
1587
1588 if (!dst_type.IsInstantiated(kCurrentClass)) {
1589 instructions += LoadInstantiatorTypeArguments();
1590 } else {
1591 instructions += NullConstant();
1592 }
1593
1594 if (!dst_type.IsInstantiated(kFunctions)) {
1595 instructions += LoadFunctionTypeArguments();
1596 } else {
1597 instructions += NullConstant();
1598 }
1599
1600 instructions += AssertAssignable(position, dst_name, kind);
1601
1602 return instructions;
1603}
1604
1605Fragment FlowGraphBuilder::AssertSubtype(TokenPosition position,
1606 const AbstractType& sub_type_value,
1607 const AbstractType& super_type_value,
1608 const String& dst_name) {
1609 Fragment instructions;
1610
1611 instructions += LoadInstantiatorTypeArguments();
1612 instructions += LoadFunctionTypeArguments();
1613 instructions += Constant(AbstractType::ZoneHandle(sub_type_value.raw()));
1614 instructions += Constant(AbstractType::ZoneHandle(super_type_value.raw()));
1615
1616 Value* super_type = Pop();
1617 Value* sub_type = Pop();
1618 Value* function_type_args = Pop();
1619 Value* instantiator_type_args = Pop();
1620
1621 AssertSubtypeInstr* instr = new (Z)
1622 AssertSubtypeInstr(position, instantiator_type_args, function_type_args,
1623 sub_type, super_type, dst_name, GetNextDeoptId());
1624 instructions += Fragment(instr);
1625
1626 return instructions;
1627}
1628
1629void FlowGraphBuilder::BuildArgumentTypeChecks(
1630 TypeChecksToBuild mode,
1631 Fragment* explicit_checks,
1632 Fragment* implicit_checks,
1633 Fragment* implicit_redefinitions) {
1634 const Function& dart_function = parsed_function_->function();
1635
1636 const Function* forwarding_target = nullptr;
1637 if (parsed_function_->is_forwarding_stub()) {
1638 forwarding_target = parsed_function_->forwarding_stub_super_target();
1639 ASSERT(!forwarding_target->IsNull());
1640 }
1641
1642 TypeArguments& type_parameters = TypeArguments::Handle(Z);
1643 if (dart_function.IsFactory()) {
1644 type_parameters = Class::Handle(Z, dart_function.Owner()).type_parameters();
1645 } else {
1646 type_parameters = dart_function.type_parameters();
1647 }
1648 intptr_t num_type_params = type_parameters.Length();
1649 if (forwarding_target != nullptr) {
1650 type_parameters = forwarding_target->type_parameters();
1651 ASSERT(type_parameters.Length() == num_type_params);
1652 }
1653
1654 TypeParameter& type_param = TypeParameter::Handle(Z);
1655 String& name = String::Handle(Z);
1656 AbstractType& bound = AbstractType::Handle(Z);
1657 Fragment check_bounds;
1658 for (intptr_t i = 0; i < num_type_params; ++i) {
1659 type_param ^= type_parameters.TypeAt(i);
1660
1661 bound = type_param.bound();
1662 if (bound.IsTopTypeForSubtyping()) {
1663 continue;
1664 }
1665
1666 switch (mode) {
1667 case TypeChecksToBuild::kCheckAllTypeParameterBounds:
1668 break;
1669 case TypeChecksToBuild::kCheckCovariantTypeParameterBounds:
1670 if (!type_param.IsGenericCovariantImpl()) {
1671 continue;
1672 }
1673 break;
1674 case TypeChecksToBuild::kCheckNonCovariantTypeParameterBounds:
1675 if (type_param.IsGenericCovariantImpl()) {
1676 continue;
1677 }
1678 break;
1679 }
1680
1681 name = type_param.name();
1682
1683 ASSERT(type_param.IsFinalized());
1684 check_bounds +=
1685 AssertSubtype(TokenPosition::kNoSource, type_param, bound, name);
1686 }
1687
1688 // Type arguments passed through partial instantiation are guaranteed to be
1689 // bounds-checked at the point of partial instantiation, so we don't need to
1690 // check them again at the call-site.
1691 if (dart_function.IsClosureFunction() && !check_bounds.is_empty() &&
1692 FLAG_eliminate_type_checks) {
1693 LocalVariable* closure = parsed_function_->ParameterVariable(0);
1694 *implicit_checks += TestDelayedTypeArgs(closure, /*present=*/{},
1695 /*absent=*/check_bounds);
1696 } else {
1697 *implicit_checks += check_bounds;
1698 }
1699
1700 const intptr_t num_params = dart_function.NumParameters();
1701 for (intptr_t i = dart_function.NumImplicitParameters(); i < num_params;
1702 ++i) {
1703 LocalVariable* param = parsed_function_->ParameterVariable(i);
1704 const String& name = param->name();
1705 if (!param->needs_type_check()) {
1706 continue;
1707 }
1708 if (param->is_captured()) {
1709 param = parsed_function_->RawParameterVariable(i);
1710 }
1711
1712 const AbstractType* target_type = &param->type();
1713 if (forwarding_target != NULL) {
1714 // We add 1 to the parameter index to account for the receiver.
1715 target_type =
1716 &AbstractType::ZoneHandle(Z, forwarding_target->ParameterTypeAt(i));
1717 }
1718
1719 if (target_type->IsTopTypeForSubtyping()) continue;
1720
1721 const bool is_covariant = param->is_explicit_covariant_parameter();
1722 Fragment* checks = is_covariant ? explicit_checks : implicit_checks;
1723
1724 *checks += LoadLocal(param);
1725 *checks += CheckAssignable(*target_type, name,
1726 AssertAssignableInstr::kParameterCheck);
1727 *checks += Drop();
1728
1729 if (!is_covariant && implicit_redefinitions != nullptr && optimizing_) {
1730 // We generate slightly different code in optimized vs. un-optimized code,
1731 // which is ok since we don't allocate any deopt ids.
1732 AssertNoDeoptIdsAllocatedScope no_deopt_allocation(thread_);
1733
1734 *implicit_redefinitions += LoadLocal(param);
1735 *implicit_redefinitions += RedefinitionWithType(*target_type);
1736 *implicit_redefinitions += StoreLocal(TokenPosition::kNoSource, param);
1737 *implicit_redefinitions += Drop();
1738 }
1739 }
1740}
1741
1742BlockEntryInstr* FlowGraphBuilder::BuildPrologue(BlockEntryInstr* normal_entry,
1743 PrologueInfo* prologue_info) {
1744 const bool compiling_for_osr = IsCompiledForOsr();
1745
1746 kernel::PrologueBuilder prologue_builder(
1747 parsed_function_, last_used_block_id_, compiling_for_osr, IsInlining());
1748 BlockEntryInstr* instruction_cursor =
1749 prologue_builder.BuildPrologue(normal_entry, prologue_info);
1750
1751 last_used_block_id_ = prologue_builder.last_used_block_id();
1752
1753 return instruction_cursor;
1754}
1755
1756ArrayPtr FlowGraphBuilder::GetOptionalParameterNames(const Function& function) {
1757 if (!function.HasOptionalNamedParameters()) {
1758 return Array::null();
1759 }
1760
1761 const intptr_t num_fixed_params = function.num_fixed_parameters();
1762 const intptr_t num_opt_params = function.NumOptionalNamedParameters();
1763 const auto& names = Array::Handle(Z, Array::New(num_opt_params, Heap::kOld));
1764 auto& name = String::Handle(Z);
1765 for (intptr_t i = 0; i < num_opt_params; ++i) {
1766 name = function.ParameterNameAt(num_fixed_params + i);
1767 names.SetAt(i, name);
1768 }
1769 return names.raw();
1770}
1771
1772Fragment FlowGraphBuilder::PushExplicitParameters(
1773 const Function& function,
1774 const Function& target /* = Function::null_function()*/) {
1775 Fragment instructions;
1776 for (intptr_t i = function.NumImplicitParameters(),
1777 n = function.NumParameters();
1778 i < n; ++i) {
1779 Fragment push_param = LoadLocal(parsed_function_->ParameterVariable(i));
1780 if (!target.IsNull() && target.is_unboxed_parameter_at(i)) {
1781 Representation to;
1782 if (target.is_unboxed_integer_parameter_at(i)) {
1783 to = kUnboxedInt64;
1784 } else {
1785 ASSERT(target.is_unboxed_double_parameter_at(i));
1786 to = kUnboxedDouble;
1787 }
1788 const auto unbox = UnboxInstr::Create(to, Pop(), DeoptId::kNone,
1789 Instruction::kNotSpeculative);
1790 Push(unbox);
1791 push_param += Fragment(unbox);
1792 }
1793 instructions += push_param;
1794 }
1795 return instructions;
1796}
1797
1798FlowGraph* FlowGraphBuilder::BuildGraphOfMethodExtractor(
1799 const Function& method) {
1800 // A method extractor is the implicit getter for a method.
1801 const Function& function =
1802 Function::ZoneHandle(Z, method.extracted_method_closure());
1803
1804 graph_entry_ =
1805 new (Z) GraphEntryInstr(*parsed_function_, Compiler::kNoOSRDeoptId);
1806
1807 auto normal_entry = BuildFunctionEntry(graph_entry_);
1808 graph_entry_->set_normal_entry(normal_entry);
1809
1810 Fragment body(normal_entry);
1811 body += CheckStackOverflowInPrologue(method.token_pos());
1812 body += BuildImplicitClosureCreation(function);
1813 body += Return(TokenPosition::kNoSource);
1814
1815 // There is no prologue code for a method extractor.
1816 PrologueInfo prologue_info(-1, -1);
1817 return new (Z) FlowGraph(*parsed_function_, graph_entry_, last_used_block_id_,
1818 prologue_info);
1819}
1820
1821FlowGraph* FlowGraphBuilder::BuildGraphOfNoSuchMethodDispatcher(
1822 const Function& function) {
1823 // This function is specialized for a receiver class, a method name, and
1824 // the arguments descriptor at a call site.
1825
1826 graph_entry_ =
1827 new (Z) GraphEntryInstr(*parsed_function_, Compiler::kNoOSRDeoptId);
1828
1829 auto normal_entry = BuildFunctionEntry(graph_entry_);
1830 graph_entry_->set_normal_entry(normal_entry);
1831
1832 PrologueInfo prologue_info(-1, -1);
1833 BlockEntryInstr* instruction_cursor =
1834 BuildPrologue(normal_entry, &prologue_info);
1835
1836 // The backend will expect an array of default values for all the named
1837 // parameters, even if they are all known to be passed at the call site
1838 // because the call site matches the arguments descriptor. Use null for
1839 // the default values.
1840 const Array& descriptor_array =
1841 Array::ZoneHandle(Z, function.saved_args_desc());
1842 ArgumentsDescriptor descriptor(descriptor_array);
1843 ZoneGrowableArray<const Instance*>* default_values =
1844 new ZoneGrowableArray<const Instance*>(Z, descriptor.NamedCount());
1845 for (intptr_t i = 0; i < descriptor.NamedCount(); ++i) {
1846 default_values->Add(&Object::null_instance());
1847 }
1848 parsed_function_->set_default_parameter_values(default_values);
1849
1850 Fragment body(instruction_cursor);
1851 body += CheckStackOverflowInPrologue(function.token_pos());
1852
1853 // The receiver is the first argument to noSuchMethod, and it is the first
1854 // argument passed to the dispatcher function.
1855 body += LoadLocal(parsed_function_->ParameterVariable(0));
1856
1857 // The second argument to noSuchMethod is an invocation mirror. Push the
1858 // arguments for allocating the invocation mirror. First, the name.
1859 body += Constant(String::ZoneHandle(Z, function.name()));
1860
1861 // Second, the arguments descriptor.
1862 body += Constant(descriptor_array);
1863
1864 // Third, an array containing the original arguments. Create it and fill
1865 // it in.
1866 const intptr_t receiver_index = descriptor.TypeArgsLen() > 0 ? 1 : 0;
1867 body += Constant(TypeArguments::ZoneHandle(Z, TypeArguments::null()));
1868 body += IntConstant(receiver_index + descriptor.Size());
1869 body += CreateArray();
1870 LocalVariable* array = MakeTemporary();
1871 if (receiver_index > 0) {
1872 LocalVariable* type_args = parsed_function_->function_type_arguments();
1873 ASSERT(type_args != NULL);
1874 body += LoadLocal(array);
1875 body += IntConstant(0);
1876 body += LoadLocal(type_args);
1877 body += StoreIndexed(kArrayCid);
1878 }
1879 for (intptr_t i = 0; i < descriptor.PositionalCount(); ++i) {
1880 body += LoadLocal(array);
1881 body += IntConstant(receiver_index + i);
1882 body += LoadLocal(parsed_function_->ParameterVariable(i));
1883 body += StoreIndexed(kArrayCid);
1884 }
1885 String& name = String::Handle(Z);
1886 for (intptr_t i = 0; i < descriptor.NamedCount(); ++i) {
1887 intptr_t parameter_index = descriptor.PositionalCount() + i;
1888 name = descriptor.NameAt(i);
1889 name = Symbols::New(H.thread(), name);
1890 body += LoadLocal(array);
1891 body += IntConstant(receiver_index + descriptor.PositionAt(i));
1892 body += LoadLocal(parsed_function_->ParameterVariable(parameter_index));
1893 body += StoreIndexed(kArrayCid);
1894 }
1895
1896 // Fourth, false indicating this is not a super NoSuchMethod.
1897 body += Constant(Bool::False());
1898
1899 const Class& mirror_class =
1900 Class::Handle(Z, Library::LookupCoreClass(Symbols::InvocationMirror()));
1901 ASSERT(!mirror_class.IsNull());
1902 const Function& allocation_function = Function::ZoneHandle(
1903 Z, mirror_class.LookupStaticFunction(
1904 Library::PrivateCoreLibName(Symbols::AllocateInvocationMirror())));
1905 ASSERT(!allocation_function.IsNull());
1906 body += StaticCall(TokenPosition::kMinSource, allocation_function,
1907 /* argument_count = */ 4, ICData::kStatic);
1908
1909 const int kTypeArgsLen = 0;
1910 ArgumentsDescriptor two_arguments(
1911 Array::Handle(Z, ArgumentsDescriptor::NewBoxed(kTypeArgsLen, 2)));
1912 Function& no_such_method =
1913 Function::ZoneHandle(Z, Resolver::ResolveDynamicForReceiverClass(
1914 Class::Handle(Z, function.Owner()),
1915 Symbols::NoSuchMethod(), two_arguments));
1916 if (no_such_method.IsNull()) {
1917 // If noSuchMethod is not found on the receiver class, call
1918 // Object.noSuchMethod.
1919 no_such_method = Resolver::ResolveDynamicForReceiverClass(
1920 Class::Handle(Z, I->object_store()->object_class()),
1921 Symbols::NoSuchMethod(), two_arguments);
1922 }
1923 body += StaticCall(TokenPosition::kMinSource, no_such_method,
1924 /* argument_count = */ 2, ICData::kNSMDispatch);
1925 body += Return(TokenPosition::kNoSource);
1926
1927 return new (Z) FlowGraph(*parsed_function_, graph_entry_, last_used_block_id_,
1928 prologue_info);
1929}
1930
1931FlowGraph* FlowGraphBuilder::BuildGraphOfInvokeFieldDispatcher(
1932 const Function& function) {
1933 // Find the name of the field we should dispatch to.
1934 const Class& owner = Class::Handle(Z, function.Owner());
1935 ASSERT(!owner.IsNull());
1936 auto& field_name = String::Handle(Z, function.name());
1937 // If the field name has a dyn: tag, then remove it. We don't add dynamic
1938 // invocation forwarders for field getters used for invoking, we just use
1939 // the tag in the name of the invoke field dispatcher to detect dynamic calls.
1940 const bool is_dynamic_call =
1941 Function::IsDynamicInvocationForwarderName(field_name);
1942 if (is_dynamic_call) {
1943 field_name = Function::DemangleDynamicInvocationForwarderName(field_name);
1944 }
1945 const String& getter_name = String::ZoneHandle(
1946 Z, Symbols::New(thread_,
1947 String::Handle(Z, Field::GetterSymbol(field_name))));
1948
1949 // Determine if this is `class Closure { get call => this; }`
1950 const Class& closure_class =
1951 Class::Handle(Z, I->object_store()->closure_class());
1952 const bool is_closure_call = (owner.raw() == closure_class.raw()) &&
1953 field_name.Equals(Symbols::Call());
1954
1955 // Set default parameters & construct argument names array.
1956 //
1957 // The backend will expect an array of default values for all the named
1958 // parameters, even if they are all known to be passed at the call site
1959 // because the call site matches the arguments descriptor. Use null for
1960 // the default values.
1961 const Array& descriptor_array =
1962 Array::ZoneHandle(Z, function.saved_args_desc());
1963 ArgumentsDescriptor descriptor(descriptor_array);
1964 const Array& argument_names =
1965 Array::ZoneHandle(Z, Array::New(descriptor.NamedCount(), Heap::kOld));
1966 ZoneGrowableArray<const Instance*>* default_values =
1967 new ZoneGrowableArray<const Instance*>(Z, descriptor.NamedCount());
1968 String& string_handle = String::Handle(Z);
1969 for (intptr_t i = 0; i < descriptor.NamedCount(); ++i) {
1970 default_values->Add(&Object::null_instance());
1971 string_handle = descriptor.NameAt(i);
1972 argument_names.SetAt(i, string_handle);
1973 }
1974 parsed_function_->set_default_parameter_values(default_values);
1975
1976 graph_entry_ =
1977 new (Z) GraphEntryInstr(*parsed_function_, Compiler::kNoOSRDeoptId);
1978
1979 auto normal_entry = BuildFunctionEntry(graph_entry_);
1980 graph_entry_->set_normal_entry(normal_entry);
1981
1982 PrologueInfo prologue_info(-1, -1);
1983 BlockEntryInstr* instruction_cursor =
1984 BuildPrologue(normal_entry, &prologue_info);
1985
1986 Fragment body(instruction_cursor);
1987 body += CheckStackOverflowInPrologue(function.token_pos());
1988
1989 if (descriptor.TypeArgsLen() > 0) {
1990 LocalVariable* type_args = parsed_function_->function_type_arguments();
1991 ASSERT(type_args != NULL);
1992 body += LoadLocal(type_args);
1993 }
1994
1995 LocalVariable* closure = NULL;
1996 if (is_closure_call) {
1997 closure = parsed_function_->ParameterVariable(0);
1998
1999 // The closure itself is the first argument.
2000 body += LoadLocal(closure);
2001
2002 if (is_dynamic_call) {
2003 // TODO(dartbug.com/40813): Move checks that are currently compiled
2004 // in the closure body to here, using the dynamic versions of
2005 // AssertSubtype to typecheck the type arguments using the runtime types
2006 // available in the closure object.
2007 }
2008 } else {
2009 // Invoke the getter to get the field value.
2010 body += LoadLocal(parsed_function_->ParameterVariable(0));
2011 const intptr_t kTypeArgsLen = 0;
2012 const intptr_t kNumArgsChecked = 1;
2013 body += InstanceCall(TokenPosition::kMinSource, getter_name, Token::kGET,
2014 kTypeArgsLen, 1, Array::null_array(), kNumArgsChecked);
2015 }
2016
2017 // Push all arguments onto the stack.
2018 intptr_t pos = 1;
2019 for (; pos < descriptor.Count(); pos++) {
2020 body += LoadLocal(parsed_function_->ParameterVariable(pos));
2021 if (is_closure_call && is_dynamic_call) {
2022 // TODO(dartbug.com/40813): Move checks that are currently compiled
2023 // in the closure body to here, using the dynamic versions of
2024 // AssertAssignable to typecheck the parameters using the runtime types
2025 // available in the closure object.
2026 }
2027 }
2028
2029 if (is_closure_call) {
2030 // Lookup the function in the closure.
2031 body += LoadLocal(closure);
2032 body += LoadNativeField(Slot::Closure_function());
2033
2034 body += ClosureCall(TokenPosition::kNoSource, descriptor.TypeArgsLen(),
2035 descriptor.Count(), argument_names);
2036 } else {
2037 const intptr_t kNumArgsChecked = 1;
2038 body += InstanceCall(TokenPosition::kMinSource, Symbols::Call(),
2039 Token::kILLEGAL, descriptor.TypeArgsLen(),
2040 descriptor.Count(), argument_names, kNumArgsChecked);
2041 }
2042
2043 body += Return(TokenPosition::kNoSource);
2044
2045 return new (Z) FlowGraph(*parsed_function_, graph_entry_, last_used_block_id_,
2046 prologue_info);
2047}
2048
2049FlowGraph* FlowGraphBuilder::BuildGraphOfNoSuchMethodForwarder(
2050 const Function& function,
2051 bool is_implicit_closure_function,
2052 bool throw_no_such_method_error) {
2053 graph_entry_ =
2054 new (Z) GraphEntryInstr(*parsed_function_, Compiler::kNoOSRDeoptId);
2055
2056 auto normal_entry = BuildFunctionEntry(graph_entry_);
2057 graph_entry_->set_normal_entry(normal_entry);
2058
2059 PrologueInfo prologue_info(-1, -1);
2060 BlockEntryInstr* instruction_cursor =
2061 BuildPrologue(normal_entry, &prologue_info);
2062
2063 Fragment body(instruction_cursor);
2064 body += CheckStackOverflowInPrologue(function.token_pos());
2065
2066 // If we are inside the tearoff wrapper function (implicit closure), we need
2067 // to extract the receiver from the context. We just replace it directly on
2068 // the stack to simplify the rest of the code.
2069 if (is_implicit_closure_function && !function.is_static()) {
2070 if (parsed_function_->has_arg_desc_var()) {
2071 body += LoadArgDescriptor();
2072 body += LoadNativeField(Slot::ArgumentsDescriptor_size());
2073 body += LoadLocal(parsed_function_->current_context_var());
2074 body += LoadNativeField(Slot::GetContextVariableSlotFor(
2075 thread_, *parsed_function_->receiver_var()));
2076 body += StoreFpRelativeSlot(
2077 kWordSize * compiler::target::frame_layout.param_end_from_fp);
2078 } else {
2079 body += LoadLocal(parsed_function_->current_context_var());
2080 body += LoadNativeField(Slot::GetContextVariableSlotFor(
2081 thread_, *parsed_function_->receiver_var()));
2082 body += StoreFpRelativeSlot(
2083 kWordSize * (compiler::target::frame_layout.param_end_from_fp +
2084 function.NumParameters()));
2085 }
2086 }
2087
2088 if (function.NeedsArgumentTypeChecks()) {
2089 BuildArgumentTypeChecks(TypeChecksToBuild::kCheckAllTypeParameterBounds,
2090 &body, &body, nullptr);
2091 }
2092
2093 body += MakeTemp();
2094 LocalVariable* result = MakeTemporary();
2095
2096 // Do "++argument_count" if any type arguments were passed.
2097 LocalVariable* argument_count_var = parsed_function_->expression_temp_var();
2098 body += IntConstant(0);
2099 body += StoreLocal(TokenPosition::kNoSource, argument_count_var);
2100 body += Drop();
2101 if (function.IsGeneric()) {
2102 Fragment then;
2103 Fragment otherwise;
2104 otherwise += IntConstant(1);
2105 otherwise += StoreLocal(TokenPosition::kNoSource, argument_count_var);
2106 otherwise += Drop();
2107 body += TestAnyTypeArgs(then, otherwise);
2108 }
2109
2110 if (function.HasOptionalParameters()) {
2111 body += LoadArgDescriptor();
2112 body += LoadNativeField(Slot::ArgumentsDescriptor_size());
2113 } else {
2114 body += IntConstant(function.NumParameters());
2115 }
2116 body += LoadLocal(argument_count_var);
2117 body += SmiBinaryOp(Token::kADD, /* truncate= */ true);
2118 LocalVariable* argument_count = MakeTemporary();
2119
2120 // We are generating code like the following:
2121 //
2122 // var arguments = new Array<dynamic>(argument_count);
2123 //
2124 // int i = 0;
2125 // if (any type arguments are passed) {
2126 // arguments[0] = function_type_arguments;
2127 // ++i;
2128 // }
2129 //
2130 // for (; i < argument_count; ++i) {
2131 // arguments[i] = LoadFpRelativeSlot(
2132 // kWordSize * (frame_layout.param_end_from_fp + argument_count - i));
2133 // }
2134 body += Constant(TypeArguments::ZoneHandle(Z, TypeArguments::null()));
2135 body += LoadLocal(argument_count);
2136 body += CreateArray();
2137 LocalVariable* arguments = MakeTemporary();
2138
2139 {
2140 // int i = 0
2141 LocalVariable* index = parsed_function_->expression_temp_var();
2142 body += IntConstant(0);
2143 body += StoreLocal(TokenPosition::kNoSource, index);
2144 body += Drop();
2145
2146 // if (any type arguments are passed) {
2147 // arguments[0] = function_type_arguments;
2148 // i = 1;
2149 // }
2150 if (function.IsGeneric()) {
2151 Fragment store;
2152 store += LoadLocal(arguments);
2153 store += IntConstant(0);
2154 store += LoadFunctionTypeArguments();
2155 store += StoreIndexed(kArrayCid);
2156 store += IntConstant(1);
2157 store += StoreLocal(TokenPosition::kNoSource, index);
2158 store += Drop();
2159 body += TestAnyTypeArgs(store, Fragment());
2160 }
2161
2162 TargetEntryInstr* body_entry;
2163 TargetEntryInstr* loop_exit;
2164
2165 Fragment condition;
2166 // i < argument_count
2167 condition += LoadLocal(index);
2168 condition += LoadLocal(argument_count);
2169 condition += SmiRelationalOp(Token::kLT);
2170 condition += BranchIfTrue(&body_entry, &loop_exit, /*negate=*/false);
2171
2172 Fragment loop_body(body_entry);
2173
2174 // arguments[i] = LoadFpRelativeSlot(
2175 // kWordSize * (frame_layout.param_end_from_fp + argument_count - i));
2176 loop_body += LoadLocal(arguments);
2177 loop_body += LoadLocal(index);
2178 loop_body += LoadLocal(argument_count);
2179 loop_body += LoadLocal(index);
2180 loop_body += SmiBinaryOp(Token::kSUB, /*truncate=*/true);
2181 loop_body +=
2182 LoadFpRelativeSlot(compiler::target::kWordSize *
2183 compiler::target::frame_layout.param_end_from_fp,
2184 CompileType::Dynamic());
2185 loop_body += StoreIndexed(kArrayCid);
2186
2187 // ++i
2188 loop_body += LoadLocal(index);
2189 loop_body += IntConstant(1);
2190 loop_body += SmiBinaryOp(Token::kADD, /*truncate=*/true);
2191 loop_body += StoreLocal(TokenPosition::kNoSource, index);
2192 loop_body += Drop();
2193
2194 JoinEntryInstr* join = BuildJoinEntry();
2195 loop_body += Goto(join);
2196
2197 Fragment loop(join);
2198 loop += condition;
2199
2200 Instruction* entry =
2201 new (Z) GotoInstr(join, CompilerState::Current().GetNextDeoptId());
2202 body += Fragment(entry, loop_exit);
2203 }
2204
2205 // Load receiver.
2206 if (is_implicit_closure_function) {
2207 if (throw_no_such_method_error) {
2208 const Function& parent =
2209 Function::ZoneHandle(Z, function.parent_function());
2210 const Class& owner = Class::ZoneHandle(Z, parent.Owner());
2211 AbstractType& type = AbstractType::ZoneHandle(Z);
2212 type = Type::New(owner, TypeArguments::Handle(Z), owner.token_pos());
2213 type = ClassFinalizer::FinalizeType(owner, type);
2214 body += Constant(type);
2215 } else {
2216 body += LoadLocal(parsed_function_->current_context_var());
2217 body += LoadNativeField(Slot::GetContextVariableSlotFor(
2218 thread_, *parsed_function_->receiver_var()));
2219 }
2220 } else {
2221 body += LoadLocal(parsed_function_->ParameterVariable(0));
2222 }
2223
2224 body += Constant(String::ZoneHandle(Z, function.name()));
2225
2226 if (!parsed_function_->has_arg_desc_var()) {
2227 // If there is no variable for the arguments descriptor (this function's
2228 // signature doesn't require it), then we need to create one.
2229 Array& args_desc = Array::ZoneHandle(
2230 Z, ArgumentsDescriptor::NewBoxed(0, function.NumParameters()));
2231 body += Constant(args_desc);
2232 } else {
2233 body += LoadArgDescriptor();
2234 }
2235
2236 body += LoadLocal(arguments);
2237
2238 if (throw_no_such_method_error) {
2239 const Function& parent =
2240 Function::ZoneHandle(Z, function.parent_function());
2241 const Class& owner = Class::ZoneHandle(Z, parent.Owner());
2242 InvocationMirror::Level im_level = owner.IsTopLevel()
2243 ? InvocationMirror::kTopLevel
2244 : InvocationMirror::kStatic;
2245 InvocationMirror::Kind im_kind;
2246 if (function.IsImplicitGetterFunction() || function.IsGetterFunction()) {
2247 im_kind = InvocationMirror::kGetter;
2248 } else if (function.IsImplicitSetterFunction() ||
2249 function.IsSetterFunction()) {
2250 im_kind = InvocationMirror::kSetter;
2251 } else {
2252 im_kind = InvocationMirror::kMethod;
2253 }
2254 body += IntConstant(InvocationMirror::EncodeType(im_level, im_kind));
2255 } else {
2256 body += NullConstant();
2257 }
2258
2259 // Push the number of delayed type arguments.
2260 if (function.IsClosureFunction()) {
2261 LocalVariable* closure = parsed_function_->ParameterVariable(0);
2262 Fragment then;
2263 then += IntConstant(function.NumTypeParameters());
2264 then += StoreLocal(TokenPosition::kNoSource, argument_count_var);
2265 then += Drop();
2266 Fragment otherwise;
2267 otherwise += IntConstant(0);
2268 otherwise += StoreLocal(TokenPosition::kNoSource, argument_count_var);
2269 otherwise += Drop();
2270 body += TestDelayedTypeArgs(closure, then, otherwise);
2271 body += LoadLocal(argument_count_var);
2272 } else {
2273 body += IntConstant(0);
2274 }
2275
2276 const Class& mirror_class =
2277 Class::Handle(Z, Library::LookupCoreClass(Symbols::InvocationMirror()));
2278 ASSERT(!mirror_class.IsNull());
2279 const Function& allocation_function = Function::ZoneHandle(
2280 Z, mirror_class.LookupStaticFunction(Library::PrivateCoreLibName(
2281 Symbols::AllocateInvocationMirrorForClosure())));
2282 ASSERT(!allocation_function.IsNull());
2283 body += StaticCall(TokenPosition::kMinSource, allocation_function,
2284 /* argument_count = */ 5, ICData::kStatic);
2285
2286 if (throw_no_such_method_error) {
2287 const Class& klass = Class::ZoneHandle(
2288 Z, Library::LookupCoreClass(Symbols::NoSuchMethodError()));
2289 ASSERT(!klass.IsNull());
2290 const Function& throw_function = Function::ZoneHandle(
2291 Z,
2292 klass.LookupStaticFunctionAllowPrivate(Symbols::ThrowNewInvocation()));
2293 ASSERT(!throw_function.IsNull());
2294 body += StaticCall(TokenPosition::kNoSource, throw_function, 2,
2295 ICData::kStatic);
2296 } else {
2297 body += InstanceCall(
2298 TokenPosition::kNoSource, Symbols::NoSuchMethod(), Token::kILLEGAL,
2299 /*type_args_len=*/0, /*argument_count=*/2, Array::null_array(),
2300 /*checked_argument_count=*/1);
2301 }
2302 body += StoreLocal(TokenPosition::kNoSource, result);
2303 body += Drop();
2304
2305 body += Drop(); // arguments
2306 body += Drop(); // argument count
2307
2308 AbstractType& return_type = AbstractType::Handle(function.result_type());
2309 if (!return_type.IsTopTypeForSubtyping()) {
2310 body += AssertAssignableLoadTypeArguments(TokenPosition::kNoSource,
2311 return_type, Symbols::Empty());
2312 }
2313 body += Return(TokenPosition::kNoSource);
2314
2315 return new (Z) FlowGraph(*parsed_function_, graph_entry_, last_used_block_id_,
2316 prologue_info);
2317}
2318
2319Fragment FlowGraphBuilder::BuildDefaultTypeHandling(const Function& function) {
2320 if (function.IsGeneric()) {
2321 const TypeArguments& default_types =
2322 parsed_function_->DefaultFunctionTypeArguments();
2323
2324 if (!default_types.IsNull()) {
2325 Fragment then;
2326 Fragment otherwise;
2327
2328 otherwise += TranslateInstantiatedTypeArguments(default_types);
2329 otherwise += StoreLocal(TokenPosition::kNoSource,
2330 parsed_function_->function_type_arguments());
2331 otherwise += Drop();
2332 return TestAnyTypeArgs(then, otherwise);
2333 }
2334 }
2335 return Fragment();
2336}
2337
2338FunctionEntryInstr* FlowGraphBuilder::BuildSharedUncheckedEntryPoint(
2339 Fragment shared_prologue_linked_in,
2340 Fragment skippable_checks,
2341 Fragment redefinitions_if_skipped,
2342 Fragment body) {
2343 ASSERT(shared_prologue_linked_in.entry == graph_entry_->normal_entry());
2344 ASSERT(parsed_function_->has_entry_points_temp_var());
2345 Instruction* prologue_start = shared_prologue_linked_in.entry->next();
2346
2347 auto* join_entry = BuildJoinEntry();
2348
2349 Fragment normal_entry(shared_prologue_linked_in.entry);
2350 normal_entry +=
2351 IntConstant(static_cast<intptr_t>(UncheckedEntryPointStyle::kNone));
2352 normal_entry += StoreLocal(TokenPosition::kNoSource,
2353 parsed_function_->entry_points_temp_var());
2354 normal_entry += Drop();
2355 normal_entry += Goto(join_entry);
2356
2357 auto* extra_target_entry = BuildFunctionEntry(graph_entry_);
2358 Fragment extra_entry(extra_target_entry);
2359 extra_entry += IntConstant(
2360 static_cast<intptr_t>(UncheckedEntryPointStyle::kSharedWithVariable));
2361 extra_entry += StoreLocal(TokenPosition::kNoSource,
2362 parsed_function_->entry_points_temp_var());
2363 extra_entry += Drop();
2364 extra_entry += Goto(join_entry);
2365
2366 if (prologue_start != nullptr) {
2367 join_entry->LinkTo(prologue_start);
2368 } else {
2369 // Prologue is empty.
2370 shared_prologue_linked_in.current = join_entry;
2371 }
2372
2373 TargetEntryInstr *do_checks, *skip_checks;
2374 shared_prologue_linked_in +=
2375 LoadLocal(parsed_function_->entry_points_temp_var());
2376 shared_prologue_linked_in += BuildEntryPointsIntrospection();
2377 shared_prologue_linked_in +=
2378 LoadLocal(parsed_function_->entry_points_temp_var());
2379 shared_prologue_linked_in += IntConstant(
2380 static_cast<intptr_t>(UncheckedEntryPointStyle::kSharedWithVariable));
2381 shared_prologue_linked_in +=
2382 BranchIfEqual(&skip_checks, &do_checks, /*negate=*/false);
2383
2384 JoinEntryInstr* rest_entry = BuildJoinEntry();
2385
2386 Fragment(do_checks) + skippable_checks + Goto(rest_entry);
2387 Fragment(skip_checks) + redefinitions_if_skipped + Goto(rest_entry);
2388 Fragment(rest_entry) + body;
2389
2390 return extra_target_entry;
2391}
2392
2393FunctionEntryInstr* FlowGraphBuilder::BuildSeparateUncheckedEntryPoint(
2394 BlockEntryInstr* normal_entry,
2395 Fragment normal_prologue,
2396 Fragment extra_prologue,
2397 Fragment shared_prologue,
2398 Fragment body) {
2399 auto* join_entry = BuildJoinEntry();
2400 auto* extra_entry = BuildFunctionEntry(graph_entry_);
2401
2402 Fragment normal(normal_entry);
2403 normal += IntConstant(static_cast<intptr_t>(UncheckedEntryPointStyle::kNone));
2404 normal += BuildEntryPointsIntrospection();
2405 normal += normal_prologue;
2406 normal += Goto(join_entry);
2407
2408 Fragment extra(extra_entry);
2409 extra +=
2410 IntConstant(static_cast<intptr_t>(UncheckedEntryPointStyle::kSeparate));
2411 extra += BuildEntryPointsIntrospection();
2412 extra += extra_prologue;
2413 extra += Goto(join_entry);
2414
2415 Fragment(join_entry) + shared_prologue + body;
2416 return extra_entry;
2417}
2418
2419FlowGraph* FlowGraphBuilder::BuildGraphOfImplicitClosureFunction(
2420 const Function& function) {
2421 const Function& parent = Function::ZoneHandle(Z, function.parent_function());
2422 const String& func_name = String::ZoneHandle(Z, parent.name());
2423 const Class& owner = Class::ZoneHandle(Z, parent.Owner());
2424 Function& target = Function::ZoneHandle(Z, owner.LookupFunction(func_name));
2425
2426 if (!target.IsNull() && (target.raw() != parent.raw())) {
2427 DEBUG_ASSERT(Isolate::Current()->HasAttemptedReload());
2428 if ((target.is_static() != parent.is_static()) ||
2429 (target.kind() != parent.kind())) {
2430 target = Function::null();
2431 }
2432 }
2433
2434 if (target.IsNull() ||
2435 (parent.num_fixed_parameters() != target.num_fixed_parameters())) {
2436 return BuildGraphOfNoSuchMethodForwarder(function, true,
2437 parent.is_static());
2438 }
2439
2440 graph_entry_ =
2441 new (Z) GraphEntryInstr(*parsed_function_, Compiler::kNoOSRDeoptId);
2442
2443 auto normal_entry = BuildFunctionEntry(graph_entry_);
2444 graph_entry_->set_normal_entry(normal_entry);
2445
2446 PrologueInfo prologue_info(-1, -1);
2447 BlockEntryInstr* instruction_cursor =
2448 BuildPrologue(normal_entry, &prologue_info);
2449
2450 const Fragment prologue = CheckStackOverflowInPrologue(function.token_pos());
2451
2452 const Fragment default_type_handling = BuildDefaultTypeHandling(function);
2453
2454 // We're going to throw away the explicit checks because the target will
2455 // always check them.
2456 Fragment implicit_checks;
2457 if (function.NeedsArgumentTypeChecks()) {
2458 Fragment explicit_checks_unused;
2459 if (target.is_static()) {
2460 // Tearoffs of static methods needs to perform arguments checks since
2461 // static methods they forward to don't do it themselves.
2462 BuildArgumentTypeChecks(TypeChecksToBuild::kCheckAllTypeParameterBounds,
2463 &explicit_checks_unused, &implicit_checks,
2464 nullptr);
2465 } else {
2466 if (MethodCanSkipTypeChecksForNonCovariantArguments(
2467 parent, ProcedureAttributesMetadata())) {
2468 // Generate checks that are skipped inside a body of a function.
2469 BuildArgumentTypeChecks(
2470 TypeChecksToBuild::kCheckNonCovariantTypeParameterBounds,
2471 &explicit_checks_unused, &implicit_checks, nullptr);
2472 }
2473 }
2474 }
2475
2476 Fragment body;
2477
2478 intptr_t type_args_len = 0;
2479 if (function.IsGeneric()) {
2480 type_args_len = function.NumTypeParameters();
2481 ASSERT(parsed_function_->function_type_arguments() != NULL);
2482 body += LoadLocal(parsed_function_->function_type_arguments());
2483 }
2484
2485 // Push receiver.
2486 if (!target.is_static()) {
2487 // The context has a fixed shape: a single variable which is the
2488 // closed-over receiver.
2489 body += LoadLocal(parsed_function_->ParameterVariable(0));
2490 body += LoadNativeField(Slot::Closure_context());
2491 body += LoadNativeField(Slot::GetContextVariableSlotFor(
2492 thread_, *parsed_function_->receiver_var()));
2493 }
2494
2495 body += PushExplicitParameters(function);
2496
2497 // Forward parameters to the target.
2498 intptr_t argument_count = function.NumParameters() -
2499 function.NumImplicitParameters() +
2500 (target.is_static() ? 0 : 1);
2501 ASSERT(argument_count == target.NumParameters());
2502
2503 Array& argument_names =
2504 Array::ZoneHandle(Z, GetOptionalParameterNames(function));
2505
2506 body += StaticCall(TokenPosition::kNoSource, target, argument_count,
2507 argument_names, ICData::kNoRebind,
2508 /* result_type = */ NULL, type_args_len);
2509
2510 // Return the result.
2511 body += Return(function.end_token_pos());
2512
2513 // Setup multiple entrypoints if useful.
2514 FunctionEntryInstr* extra_entry = nullptr;
2515 if (function.MayHaveUncheckedEntryPoint()) {
2516 // The prologue for a closure will always have context handling (e.g.
2517 // setting up the receiver variable), but we don't need it on the unchecked
2518 // entry because the only time we reference this is for loading the
2519 // receiver, which we fetch directly from the context.
2520 if (PrologueBuilder::PrologueSkippableOnUncheckedEntry(function)) {
2521 // Use separate entry points since we can skip almost everything on the
2522 // static entry.
2523 extra_entry = BuildSeparateUncheckedEntryPoint(
2524 /*normal_entry=*/instruction_cursor,
2525 /*normal_prologue=*/prologue + default_type_handling +
2526 implicit_checks,
2527 /*extra_prologue=*/
2528 CheckStackOverflowInPrologue(function.token_pos()),
2529 /*shared_prologue=*/Fragment(),
2530 /*body=*/body);
2531 } else {
2532 Fragment shared_prologue(normal_entry, instruction_cursor);
2533 shared_prologue += prologue;
2534 extra_entry = BuildSharedUncheckedEntryPoint(
2535 /*shared_prologue_linked_in=*/shared_prologue,
2536 /*skippable_checks=*/default_type_handling + implicit_checks,
2537 /*redefinitions_if_skipped=*/Fragment(),
2538 /*body=*/body);
2539 }
2540 RecordUncheckedEntryPoint(graph_entry_, extra_entry);
2541 } else {
2542 Fragment function(instruction_cursor);
2543 function += prologue;
2544 function += default_type_handling;
2545 function += implicit_checks;
2546 function += body;
2547 }
2548
2549 return new (Z) FlowGraph(*parsed_function_, graph_entry_, last_used_block_id_,
2550 prologue_info);
2551}
2552
2553FlowGraph* FlowGraphBuilder::BuildGraphOfFieldAccessor(
2554 const Function& function) {
2555 ASSERT(function.IsImplicitGetterOrSetter() ||
2556 function.IsDynamicInvocationForwarder());
2557
2558 // Instead of building a dynamic invocation forwarder that checks argument
2559 // type and then invokes original setter we simply generate the type check
2560 // and inlined field store. Scope builder takes care of setting correct
2561 // type check mode in this case.
2562 const auto& target = Function::Handle(
2563 Z, function.IsDynamicInvocationForwarder() ? function.ForwardingTarget()
2564 : function.raw());
2565 ASSERT(target.IsImplicitGetterOrSetter());
2566
2567 const bool is_method = !function.IsStaticFunction();
2568 const bool is_setter = target.IsImplicitSetterFunction();
2569 const bool is_getter = target.IsImplicitGetterFunction() ||
2570 target.IsImplicitStaticGetterFunction();
2571 ASSERT(is_setter || is_getter);
2572
2573 const auto& field = Field::ZoneHandle(Z, target.accessor_field());
2574
2575 graph_entry_ =
2576 new (Z) GraphEntryInstr(*parsed_function_, Compiler::kNoOSRDeoptId);
2577
2578 auto normal_entry = BuildFunctionEntry(graph_entry_);
2579 graph_entry_->set_normal_entry(normal_entry);
2580
2581 Fragment body(normal_entry);
2582 if (is_setter) {
2583 auto const setter_value =
2584 parsed_function_->ParameterVariable(is_method ? 1 : 0);
2585 if (is_method) {
2586 body += LoadLocal(parsed_function_->ParameterVariable(0));
2587 }
2588 body += LoadLocal(setter_value);
2589
2590 // The dyn:* forwarder has to check the parameters that the
2591 // actual target will not check.
2592 // Though here we manually inline the target, so the dyn:* forwarder has to
2593 // check all parameters.
2594 const bool needs_type_check = function.IsDynamicInvocationForwarder() ||
2595 setter_value->needs_type_check();
2596 if (needs_type_check) {
2597 body += CheckAssignable(setter_value->type(), setter_value->name(),
2598 AssertAssignableInstr::kParameterCheck);
2599 }
2600 body += BuildNullAssertions();
2601 if (field.is_late()) {
2602 if (is_method) {
2603 body += Drop();
2604 }
2605 body += Drop();
2606 body += StoreLateField(
2607 field, is_method ? parsed_function_->ParameterVariable(0) : nullptr,
2608 setter_value);
2609 } else {
2610 if (is_method) {
2611 body += StoreInstanceFieldGuarded(
2612 field, StoreInstanceFieldInstr::Kind::kOther);
2613 } else {
2614 body += StoreStaticField(TokenPosition::kNoSource, field);
2615 }
2616 }
2617 body += NullConstant();
2618 } else if (is_getter && is_method) {
2619 ASSERT(!field.needs_load_guard()
2620 NOT_IN_PRODUCT(|| I->HasAttemptedReload()));
2621 body += LoadLocal(parsed_function_->ParameterVariable(0));
2622 body += LoadField(
2623 field, /*calls_initializer=*/field.NeedsInitializationCheckOnLoad());
2624 if (field.needs_load_guard()) {
2625#if defined(PRODUCT)
2626 UNREACHABLE();
2627#else
2628 body += CheckAssignable(AbstractType::Handle(Z, field.type()),
2629 Symbols::FunctionResult());
2630#endif
2631 }
2632 } else if (field.is_const()) {
2633 ASSERT(!field.IsUninitialized());
2634 body += Constant(Instance::ZoneHandle(Z, field.StaticValue()));
2635 } else {
2636 // Static fields
2637 // - with trivial initializer
2638 // - without initializer if they are not late
2639 // are initialized eagerly and do not have implicit getters.
2640 // Static fields with non-trivial initializer need getter to perform
2641 // lazy initialization. Late fields without initializer need getter
2642 // to make sure they are already initialized.
2643 ASSERT(field.has_nontrivial_initializer() ||
2644 (field.is_late() && !field.has_initializer()));
2645 body += LoadStaticField(field, /*calls_initializer=*/true);
2646 if (field.needs_load_guard()) {
2647#if defined(PRODUCT)
2648 UNREACHABLE();
2649#else
2650 ASSERT(Isolate::Current()->HasAttemptedReload());
2651 body += CheckAssignable(AbstractType::Handle(Z, field.type()),
2652 Symbols::FunctionResult());
2653#endif
2654 }
2655 }
2656 body += Return(TokenPosition::kNoSource);
2657
2658 PrologueInfo prologue_info(-1, -1);
2659 return new (Z) FlowGraph(*parsed_function_, graph_entry_, last_used_block_id_,
2660 prologue_info);
2661}
2662
2663FlowGraph* FlowGraphBuilder::BuildGraphOfDynamicInvocationForwarder(
2664 const Function& function) {
2665 auto& name = String::Handle(Z, function.name());
2666 name = Function::DemangleDynamicInvocationForwarderName(name);
2667 const auto& target = Function::ZoneHandle(Z, function.ForwardingTarget());
2668 ASSERT(!target.IsNull());
2669
2670 if (target.IsImplicitSetterFunction() || target.IsImplicitGetterFunction()) {
2671 return BuildGraphOfFieldAccessor(function);
2672 }
2673 if (target.IsMethodExtractor()) {
2674 return BuildGraphOfMethodExtractor(target);
2675 }
2676
2677 graph_entry_ = new (Z) GraphEntryInstr(*parsed_function_, osr_id_);
2678
2679 auto normal_entry = BuildFunctionEntry(graph_entry_);
2680 graph_entry_->set_normal_entry(normal_entry);
2681
2682 PrologueInfo prologue_info(-1, -1);
2683 auto instruction_cursor = BuildPrologue(normal_entry, &prologue_info);
2684
2685 Fragment body;
2686 if (!function.is_native()) {
2687 body += CheckStackOverflowInPrologue(function.token_pos());
2688 }
2689
2690 ASSERT(parsed_function_->scope()->num_context_variables() == 0);
2691
2692 // Should never build a dynamic invocation forwarder for equality
2693 // operator.
2694 ASSERT(function.name() != Symbols::EqualOperator().raw());
2695
2696 // Even if the caller did not pass argument vector we would still
2697 // call the target with instantiate-to-bounds type arguments.
2698 body += BuildDefaultTypeHandling(function);
2699
2700 // Build argument type checks that complement those that are emitted in the
2701 // target.
2702 BuildArgumentTypeChecks(
2703 TypeChecksToBuild::kCheckNonCovariantTypeParameterBounds, &body, &body,
2704 nullptr);
2705
2706 // Push all arguments and invoke the original method.
2707
2708 intptr_t type_args_len = 0;
2709 if (function.IsGeneric()) {
2710 type_args_len = function.NumTypeParameters();
2711 ASSERT(parsed_function_->function_type_arguments() != nullptr);
2712 body += LoadLocal(parsed_function_->function_type_arguments());
2713 }
2714
2715 // Push receiver.
2716 ASSERT(function.NumImplicitParameters() == 1);
2717 body += LoadLocal(parsed_function_->receiver_var());
2718 body += PushExplicitParameters(function, target);
2719
2720 const intptr_t argument_count = function.NumParameters();
2721 const auto& argument_names =
2722 Array::ZoneHandle(Z, GetOptionalParameterNames(function));
2723
2724 body += StaticCall(TokenPosition::kNoSource, target, argument_count,
2725 argument_names, ICData::kNoRebind, nullptr, type_args_len);
2726
2727 if (target.has_unboxed_integer_return()) {
2728 body += Box(kUnboxedInt64);
2729 } else if (target.has_unboxed_double_return()) {
2730 body += Box(kUnboxedDouble);
2731 }
2732
2733 // Later optimization passes assume that result of a x.[]=(...) call is not
2734 // used. We must guarantee this invariant because violation will lead to an
2735 // illegal IL once we replace x.[]=(...) with a sequence that does not
2736 // actually produce any value. See http://dartbug.com/29135 for more details.
2737 if (name.raw() == Symbols::AssignIndexToken().raw()) {
2738 body += Drop();
2739 body += NullConstant();
2740 }
2741
2742 body += Return(TokenPosition::kNoSource);
2743
2744 instruction_cursor->LinkTo(body.entry);
2745
2746 // When compiling for OSR, use a depth first search to find the OSR
2747 // entry and make graph entry jump to it instead of normal entry.
2748 // Catch entries are always considered reachable, even if they
2749 // become unreachable after OSR.
2750 if (IsCompiledForOsr()) {
2751 graph_entry_->RelinkToOsrEntry(Z, last_used_block_id_ + 1);
2752 }
2753 return new (Z) FlowGraph(*parsed_function_, graph_entry_, last_used_block_id_,
2754 prologue_info);
2755}
2756
2757Fragment FlowGraphBuilder::EnterHandleScope() {
2758 auto* instr = new (Z)
2759 EnterHandleScopeInstr(EnterHandleScopeInstr::Kind::kEnterHandleScope);
2760 Push(instr);
2761 return Fragment(instr);
2762}
2763
2764Fragment FlowGraphBuilder::GetTopHandleScope() {
2765 auto* instr = new (Z)
2766 EnterHandleScopeInstr(EnterHandleScopeInstr::Kind::kGetTopHandleScope);
2767 Push(instr);
2768 return Fragment(instr);
2769}
2770
2771Fragment FlowGraphBuilder::ExitHandleScope() {
2772 auto* instr = new (Z) ExitHandleScopeInstr();
2773 return Fragment(instr);
2774}
2775
2776Fragment FlowGraphBuilder::AllocateHandle(LocalVariable* api_local_scope) {
2777 Fragment code;
2778 if (api_local_scope != nullptr) {
2779 // Use the reference the scope we created in the trampoline.
2780 code += LoadLocal(api_local_scope);
2781 } else {
2782 // Or get a reference to the top handle scope.
2783 code += GetTopHandleScope();
2784 }
2785 Value* api_local_scope_value = Pop();
2786 auto* instr = new (Z) AllocateHandleInstr(api_local_scope_value);
2787 Push(instr);
2788 code <<= instr;
2789 return code;
2790}
2791
2792Fragment FlowGraphBuilder::RawStoreField(int32_t offset) {
2793 Fragment code;
2794 Value* value = Pop();
2795 Value* base = Pop();
2796 auto* instr = new (Z) RawStoreFieldInstr(base, value, offset);
2797 code <<= instr;
2798 return code;
2799}
2800
2801Fragment FlowGraphBuilder::WrapHandle(LocalVariable* api_local_scope) {
2802 Fragment code;
2803 LocalVariable* object = MakeTemporary();
2804 code += AllocateHandle(api_local_scope);
2805
2806 code += LoadLocal(MakeTemporary()); // Duplicate handle pointer.
2807 code += ConvertUnboxedToUntagged(kUnboxedIntPtr);
2808 code += LoadLocal(object);
2809 code += RawStoreField(compiler::target::LocalHandle::raw_offset());
2810
2811 code += DropTempsPreserveTop(1); // Drop object below handle.
2812 return code;
2813}
2814
2815Fragment FlowGraphBuilder::UnwrapHandle() {
2816 Fragment code;
2817 code += ConvertUnboxedToUntagged(kUnboxedIntPtr);
2818 code += IntConstant(compiler::target::LocalHandle::raw_offset());
2819 code += UnboxTruncate(kUnboxedIntPtr);
2820 code += LoadIndexedTypedData(kArrayCid, /*index_scale=*/1,
2821 /*index_unboxed=*/true);
2822 return code;
2823}
2824
2825Fragment FlowGraphBuilder::UnhandledException() {
2826 const auto class_table = thread_->isolate()->class_table();
2827 ASSERT(class_table->HasValidClassAt(kUnhandledExceptionCid));
2828 const auto& klass =
2829 Class::ZoneHandle(H.zone(), class_table->At(kUnhandledExceptionCid));
2830 ASSERT(!klass.IsNull());
2831 Fragment body;
2832 body += AllocateObject(TokenPosition::kNoSource, klass, 0);
2833 LocalVariable* error_instance = MakeTemporary();
2834
2835 body += LoadLocal(error_instance);
2836 body += LoadLocal(CurrentException());
2837 body += StoreInstanceField(
2838 TokenPosition::kNoSource, Slot::UnhandledException_exception(),
2839 StoreInstanceFieldInstr::Kind::kInitializing, kNoStoreBarrier);
2840
2841 body += LoadLocal(error_instance);
2842 body += LoadLocal(CurrentStackTrace());
2843 body += StoreInstanceField(
2844 TokenPosition::kNoSource, Slot::UnhandledException_stacktrace(),
2845 StoreInstanceFieldInstr::Kind::kInitializing, kNoStoreBarrier);
2846
2847 return body;
2848}
2849
2850Fragment FlowGraphBuilder::UnboxTruncate(Representation to) {
2851 auto* unbox = UnboxInstr::Create(to, Pop(), DeoptId::kNone,
2852 Instruction::kNotSpeculative);
2853 Push(unbox);
2854 return Fragment(unbox);
2855}
2856
2857Fragment FlowGraphBuilder::NativeReturn(
2858 const compiler::ffi::CallbackMarshaller& marshaller) {
2859 auto* instr = new (Z) NativeReturnInstr(TokenPosition::kNoSource, Pop(),
2860 marshaller, DeoptId::kNone);
2861 return Fragment(instr);
2862}
2863
2864Fragment FlowGraphBuilder::FfiPointerFromAddress(const Type& result_type) {
2865 LocalVariable* address = MakeTemporary();
2866 LocalVariable* result = parsed_function_->expression_temp_var();
2867
2868 Class& result_class = Class::ZoneHandle(Z, result_type.type_class());
2869 // This class might only be instantiated as a return type of ffi calls.
2870 result_class.EnsureIsFinalized(thread_);
2871
2872 TypeArguments& args = TypeArguments::ZoneHandle(Z, result_type.arguments());
2873
2874 // A kernel transform for FFI in the front-end ensures that type parameters
2875 // do not appear in the type arguments to a any Pointer classes in an FFI
2876 // signature.
2877 ASSERT(args.IsNull() || args.IsInstantiated());
2878 args = args.Canonicalize();
2879
2880 Fragment code;
2881 code += Constant(args);
2882 code += AllocateObject(TokenPosition::kNoSource, result_class, 1);
2883 LocalVariable* pointer = MakeTemporary();
2884 code += LoadLocal(pointer);
2885 code += LoadLocal(address);
2886 code += UnboxTruncate(kUnboxedFfiIntPtr);
2887 code += ConvertUnboxedToUntagged(kUnboxedFfiIntPtr);
2888 code += StoreUntagged(compiler::target::Pointer::data_field_offset());
2889 code += StoreLocal(TokenPosition::kNoSource, result);
2890 code += Drop(); // StoreLocal^
2891 code += Drop(); // address
2892 code += LoadLocal(result);
2893
2894 return code;
2895}
2896
2897Fragment FlowGraphBuilder::BitCast(Representation from, Representation to) {
2898 BitCastInstr* instr = new (Z) BitCastInstr(from, to, Pop());
2899 Push(instr);
2900 return Fragment(instr);
2901}
2902
2903Fragment FlowGraphBuilder::FfiConvertArgumentToDart(
2904 const compiler::ffi::BaseMarshaller& marshaller,
2905 intptr_t arg_index) {
2906 Fragment body;
2907 if (marshaller.IsPointer(arg_index)) {
2908 body += Box(kUnboxedFfiIntPtr);
2909 body += FfiPointerFromAddress(
2910 Type::CheckedHandle(Z, marshaller.CType(arg_index)));
2911 } else if (marshaller.IsHandle(arg_index)) {
2912 body += UnwrapHandle();
2913 } else if (marshaller.IsVoid(arg_index)) {
2914 body += Drop();
2915 body += NullConstant();
2916 } else {
2917 if (marshaller.RequiresBitCast(arg_index)) {
2918 body += BitCast(marshaller.RepInFfiCall(arg_index),
2919 marshaller.RepInDart(arg_index));
2920 }
2921
2922 body += Box(marshaller.RepInDart(arg_index));
2923 }
2924 return body;
2925}
2926
2927Fragment FlowGraphBuilder::FfiConvertArgumentToNative(
2928 const compiler::ffi::BaseMarshaller& marshaller,
2929 intptr_t arg_index,
2930 LocalVariable* api_local_scope) {
2931 Fragment body;
2932
2933 if (marshaller.IsPointer(arg_index)) {
2934 // This can only be Pointer, so it is always safe to LoadUntagged.
2935 body += LoadUntagged(compiler::target::Pointer::data_field_offset());
2936 body += ConvertUntaggedToUnboxed(kUnboxedFfiIntPtr);
2937 } else if (marshaller.IsHandle(arg_index)) {
2938 body += WrapHandle(api_local_scope);
2939 } else {
2940 body += UnboxTruncate(marshaller.RepInDart(arg_index));
2941 }
2942
2943 if (marshaller.RequiresBitCast(arg_index)) {
2944 body += BitCast(marshaller.RepInDart(arg_index),
2945 marshaller.RepInFfiCall(arg_index));
2946 }
2947
2948 return body;
2949}
2950
2951FlowGraph* FlowGraphBuilder::BuildGraphOfFfiTrampoline(
2952 const Function& function) {
2953 if (function.FfiCallbackTarget() != Function::null()) {
2954 return BuildGraphOfFfiCallback(function);
2955 } else {
2956 return BuildGraphOfFfiNative(function);
2957 }
2958}
2959
2960FlowGraph* FlowGraphBuilder::BuildGraphOfFfiNative(const Function& function) {
2961 const intptr_t kClosureParameterOffset = 0;
2962 const intptr_t kFirstArgumentParameterOffset = kClosureParameterOffset + 1;
2963
2964 graph_entry_ =
2965 new (Z) GraphEntryInstr(*parsed_function_, Compiler::kNoOSRDeoptId);
2966
2967 auto normal_entry = BuildFunctionEntry(graph_entry_);
2968 graph_entry_->set_normal_entry(normal_entry);
2969
2970 PrologueInfo prologue_info(-1, -1);
2971
2972 BlockEntryInstr* instruction_cursor =
2973 BuildPrologue(normal_entry, &prologue_info);
2974
2975 Fragment function_body(instruction_cursor);
2976 function_body += CheckStackOverflowInPrologue(function.token_pos());
2977
2978 const auto& marshaller = *new (Z) compiler::ffi::CallMarshaller(Z, function);
2979
2980 const bool signature_contains_handles = marshaller.ContainsHandles();
2981
2982 BuildArgumentTypeChecks(TypeChecksToBuild::kCheckAllTypeParameterBounds,
2983 &function_body, &function_body, &function_body);
2984
2985 // Null check arguments before we go into the try catch, so that we don't
2986 // catch our own null errors.
2987 const intptr_t num_args = marshaller.num_args();
2988 for (intptr_t i = 0; i < num_args; i++) {
2989 if (marshaller.IsHandle(i)) {
2990 continue;
2991 }
2992 function_body += LoadLocal(
2993 parsed_function_->ParameterVariable(kFirstArgumentParameterOffset + i));
2994 // Check for 'null'.
2995 // TODO(36780): Mention the param name instead of function reciever.
2996 function_body +=
2997 CheckNullOptimized(TokenPosition::kNoSource,
2998 String::ZoneHandle(Z, marshaller.function_name()));
2999 function_body += StoreLocal(
3000 TokenPosition::kNoSource,
3001 parsed_function_->ParameterVariable(kFirstArgumentParameterOffset + i));
3002 function_body += Drop();
3003 }
3004
3005 Fragment body;
3006 intptr_t try_handler_index = -1;
3007 LocalVariable* api_local_scope = nullptr;
3008 if (signature_contains_handles) {
3009 // Wrap in Try catch to transition from Native to Generated on a throw from
3010 // the dart_api.
3011 try_handler_index = AllocateTryIndex();
3012 body += TryCatch(try_handler_index);
3013 ++try_depth_;
3014
3015 body += EnterHandleScope();
3016 api_local_scope = MakeTemporary();
3017 }
3018
3019 // Unbox and push the arguments.
3020 for (intptr_t i = 0; i < marshaller.num_args(); i++) {
3021 body += LoadLocal(
3022 parsed_function_->ParameterVariable(kFirstArgumentParameterOffset + i));
3023 body += FfiConvertArgumentToNative(marshaller, i, api_local_scope);
3024 }
3025
3026 // Push the function pointer, which is stored (as Pointer object) in the
3027 // first slot of the context.
3028 body +=
3029 LoadLocal(parsed_function_->ParameterVariable(kClosureParameterOffset));
3030 body += LoadNativeField(Slot::Closure_context());
3031 body += LoadNativeField(Slot::GetContextVariableSlotFor(
3032 thread_, *MakeImplicitClosureScope(
3033 Z, Class::Handle(I->object_store()->ffi_pointer_class()))
3034 ->context_variables()[0]));
3035
3036 // This can only be Pointer, so it is always safe to LoadUntagged.
3037 body += LoadUntagged(compiler::target::Pointer::data_field_offset());
3038 body += ConvertUntaggedToUnboxed(kUnboxedFfiIntPtr);
3039 body += FfiCall(marshaller);
3040
3041 for (intptr_t i = 0; i < marshaller.num_args(); i++) {
3042 if (marshaller.IsPointer(i)) {
3043 body += LoadLocal(parsed_function_->ParameterVariable(
3044 kFirstArgumentParameterOffset + i));
3045 body += ReachabilityFence();
3046 }
3047 }
3048
3049 body += FfiConvertArgumentToDart(marshaller, compiler::ffi::kResultIndex);
3050
3051 if (signature_contains_handles) {
3052 body += DropTempsPreserveTop(1); // Drop api_local_scope.
3053 body += ExitHandleScope();
3054 }
3055
3056 body += Return(TokenPosition::kNoSource);
3057
3058 if (signature_contains_handles) {
3059 --try_depth_;
3060 }
3061
3062 function_body += body;
3063
3064 if (signature_contains_handles) {
3065 ++catch_depth_;
3066 Fragment catch_body =
3067 CatchBlockEntry(Array::empty_array(), try_handler_index,
3068 /*needs_stacktrace=*/true, /*is_synthesized=*/true);
3069
3070 // TODO(41984): If we want to pass in the handle scope, move it out
3071 // of the try catch.
3072 catch_body += ExitHandleScope();
3073
3074 catch_body += LoadLocal(CurrentException());
3075 catch_body += LoadLocal(CurrentStackTrace());
3076 catch_body += RethrowException(TokenPosition::kNoSource, try_handler_index);
3077 --catch_depth_;
3078 }
3079
3080 return new (Z) FlowGraph(*parsed_function_, graph_entry_, last_used_block_id_,
3081 prologue_info);
3082}
3083
3084FlowGraph* FlowGraphBuilder::BuildGraphOfFfiCallback(const Function& function) {
3085 const auto& marshaller =
3086 *new (Z) compiler::ffi::CallbackMarshaller(Z, function);
3087
3088 graph_entry_ =
3089 new (Z) GraphEntryInstr(*parsed_function_, Compiler::kNoOSRDeoptId);
3090
3091 auto* const native_entry = new (Z) NativeEntryInstr(
3092 marshaller, graph_entry_, AllocateBlockId(), CurrentTryIndex(),
3093 GetNextDeoptId(), function.FfiCallbackId());
3094
3095 graph_entry_->set_normal_entry(native_entry);
3096
3097 Fragment function_body(native_entry);
3098 function_body += CheckStackOverflowInPrologue(function.token_pos());
3099
3100 // Wrap the entire method in a big try/catch. This is important to ensure that
3101 // the VM does not crash if the callback throws an exception.
3102 const intptr_t try_handler_index = AllocateTryIndex();
3103 Fragment body = TryCatch(try_handler_index);
3104 ++try_depth_;
3105
3106 // Box and push the arguments.
3107 for (intptr_t i = 0; i < marshaller.num_args(); i++) {
3108 auto* parameter = new (Z) NativeParameterInstr(marshaller, i);
3109 Push(parameter);
3110 body <<= parameter;
3111 body += FfiConvertArgumentToDart(marshaller, i);
3112 }
3113
3114 // Call the target.
3115 //
3116 // TODO(36748): Determine the hot-reload semantics of callbacks and update the
3117 // rebind-rule accordingly.
3118 body += StaticCall(TokenPosition::kNoSource,
3119 Function::ZoneHandle(Z, function.FfiCallbackTarget()),
3120 marshaller.num_args(), Array::empty_array(),
3121 ICData::kNoRebind);
3122
3123 if (marshaller.IsVoid(compiler::ffi::kResultIndex)) {
3124 body += Drop();
3125 body += IntConstant(0);
3126 } else if (!marshaller.IsHandle(compiler::ffi::kResultIndex)) {
3127 body +=
3128 CheckNullOptimized(TokenPosition::kNoSource,
3129 String::ZoneHandle(Z, marshaller.function_name()));
3130 }
3131 body += FfiConvertArgumentToNative(marshaller, compiler::ffi::kResultIndex,
3132 /*api_local_scope=*/nullptr);
3133 body += NativeReturn(marshaller);
3134
3135 --try_depth_;
3136 function_body += body;
3137
3138 ++catch_depth_;
3139 Fragment catch_body = CatchBlockEntry(Array::empty_array(), try_handler_index,
3140 /*needs_stacktrace=*/false,
3141 /*is_synthesized=*/true);
3142
3143 // Return the "exceptional return" value given in 'fromFunction'.
3144 //
3145 // For pointer and void return types, the exceptional return is always null --
3146 // return 0 instead.
3147 if (marshaller.IsPointer(compiler::ffi::kResultIndex) ||
3148 marshaller.IsVoid(compiler::ffi::kResultIndex)) {
3149 ASSERT(function.FfiCallbackExceptionalReturn() == Object::null());
3150 catch_body += IntConstant(0);
3151 catch_body += UnboxTruncate(kUnboxedFfiIntPtr);
3152 } else if (marshaller.IsHandle(compiler::ffi::kResultIndex)) {
3153 catch_body += UnhandledException();
3154 catch_body += FfiConvertArgumentToNative(
3155 marshaller, compiler::ffi::kResultIndex, /*api_local_scope=*/nullptr);
3156 } else {
3157 catch_body += Constant(
3158 Instance::ZoneHandle(Z, function.FfiCallbackExceptionalReturn()));
3159 catch_body += FfiConvertArgumentToNative(
3160 marshaller, compiler::ffi::kResultIndex, /*api_local_scope=*/nullptr);
3161 }
3162
3163 catch_body += NativeReturn(marshaller);
3164 --catch_depth_;
3165
3166 PrologueInfo prologue_info(-1, -1);
3167 return new (Z) FlowGraph(*parsed_function_, graph_entry_, last_used_block_id_,
3168 prologue_info);
3169}
3170
3171void FlowGraphBuilder::SetCurrentTryCatchBlock(TryCatchBlock* try_catch_block) {
3172 try_catch_block_ = try_catch_block;
3173 SetCurrentTryIndex(try_catch_block == nullptr ? kInvalidTryIndex
3174 : try_catch_block->try_index());
3175}
3176
3177bool FlowGraphBuilder::NeedsNullAssertion(const AbstractType& type) {
3178 if (!type.IsNonNullable()) {
3179 return false;
3180 }
3181 if (type.IsTypeParameter()) {
3182 return NeedsNullAssertion(
3183 AbstractType::Handle(Z, TypeParameter::Cast(type).bound()));
3184 }
3185 if (type.IsFutureOrType()) {
3186 return NeedsNullAssertion(AbstractType::Handle(Z, type.UnwrapFutureOr()));
3187 }
3188 return true;
3189}
3190
3191Fragment FlowGraphBuilder::NullAssertion(LocalVariable* variable) {
3192 Fragment code;
3193 if (!NeedsNullAssertion(variable->type())) {
3194 return code;
3195 }
3196
3197 TargetEntryInstr* then;
3198 TargetEntryInstr* otherwise;
3199
3200 code += LoadLocal(variable);
3201 code += NullConstant();
3202 code += BranchIfEqual(&then, &otherwise);
3203
3204 if (throw_new_null_assertion_ == nullptr) {
3205 const Class& klass = Class::ZoneHandle(
3206 Z, Library::LookupCoreClass(Symbols::AssertionError()));
3207 ASSERT(!klass.IsNull());
3208 throw_new_null_assertion_ =
3209 &Function::ZoneHandle(Z, klass.LookupStaticFunctionAllowPrivate(
3210 Symbols::ThrowNewNullAssertion()));
3211 ASSERT(!throw_new_null_assertion_->IsNull());
3212 }
3213
3214 const Script& script =
3215 Script::Handle(Z, parsed_function_->function().script());
3216 intptr_t line = -1;
3217 intptr_t column = -1;
3218 script.GetTokenLocation(variable->token_pos(), &line, &column);
3219
3220 // Build equivalent of `throw _AssertionError._throwNewNullAssertion(name)`
3221 // expression. We build throw (even through _throwNewNullAssertion already
3222 // throws) because call is not a valid last instruction for the block.
3223 // Blocks can only terminate with explicit control flow instructions
3224 // (Branch, Goto, Return or Throw).
3225 Fragment null_code(then);
3226 null_code += Constant(variable->name());
3227 null_code += IntConstant(line);
3228 null_code += IntConstant(column);
3229 null_code += StaticCall(variable->token_pos(), *throw_new_null_assertion_, 3,
3230 ICData::kStatic);
3231 null_code += ThrowException(TokenPosition::kNoSource);
3232 null_code += Drop();
3233
3234 return Fragment(code.entry, otherwise);
3235}
3236
3237Fragment FlowGraphBuilder::BuildNullAssertions() {
3238 Fragment code;
3239 if (I->null_safety() || !I->asserts() || !FLAG_null_assertions) {
3240 return code;
3241 }
3242
3243 const Function& dart_function = parsed_function_->function();
3244 for (intptr_t i = dart_function.NumImplicitParameters(),
3245 n = dart_function.NumParameters();
3246 i < n; ++i) {
3247 LocalVariable* variable = parsed_function_->ParameterVariable(i);
3248 code += NullAssertion(variable);
3249 }
3250 return code;
3251}
3252
3253} // namespace kernel
3254
3255} // namespace dart
3256