Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(215)

Side by Side Diff: runtime/vm/kernel_to_il.cc

Issue 2411823003: VM support for running Kernel binaries. (Closed)
Patch Set: Address comments Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/vm/kernel_to_il.h ('k') | runtime/vm/object.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 <map>
6 #include <set>
7 #include <string>
8
9 #include "vm/kernel_to_il.h"
10
11 #include "vm/compiler.h"
12 #include "vm/intermediate_language.h"
13 #include "vm/kernel_reader.h"
14 #include "vm/longjump.h"
15 #include "vm/method_recognizer.h"
16 #include "vm/object_store.h"
17 #include "vm/report.h"
18 #include "vm/resolver.h"
19 #include "vm/stack_frame.h"
20
21 namespace dart {
22
23 DECLARE_FLAG(bool, support_externalizable_strings);
24
25 namespace kernel {
26
27 #define Z (zone_)
28 #define H (translation_helper_)
29 #define T (type_translator_)
30 #define I Isolate::Current()
31
32
33 void ScopeBuilder::EnterScope(TreeNode* node) {
34 scope_ = new (Z) LocalScope(scope_, depth_.function_, depth_.loop_);
35 result_->scopes.Insert(node, scope_);
36 }
37
38
39 void ScopeBuilder::ExitScope() { scope_ = scope_->parent(); }
40
41
42 LocalVariable* ScopeBuilder::MakeVariable(const dart::String& name) {
43 return new (Z)
44 LocalVariable(TokenPosition::kNoSource, name, Object::dynamic_type());
45 }
46
47
48 LocalVariable* ScopeBuilder::MakeVariable(const dart::String& name,
49 const Type& type) {
50 return new (Z) LocalVariable(TokenPosition::kNoSource, name, type);
51 }
52
53
54 void ScopeBuilder::AddParameters(FunctionNode* function, intptr_t pos) {
55 List<VariableDeclaration>& positional = function->positional_parameters();
56 for (intptr_t i = 0; i < positional.length(); ++i) {
57 AddParameter(positional[i], pos++);
58 }
59 List<VariableDeclaration>& named = function->named_parameters();
60 for (intptr_t i = 0; i < named.length(); ++i) {
61 AddParameter(named[i], pos++);
62 }
63 }
64
65
66 void ScopeBuilder::AddParameter(VariableDeclaration* declaration,
67 intptr_t pos) {
68 // TODO(27590): Handle final.
69 LocalVariable* variable = MakeVariable(H.DartSymbol(declaration->name()));
70 scope_->InsertParameterAt(pos, variable);
71 result_->locals.Insert(declaration, variable);
72
73 // The default value may contain 'let' bindings for which the constant
74 // evaluator needs scope bindings.
75 Expression* defaultValue = declaration->initializer();
76 if (defaultValue != NULL) {
77 defaultValue->AcceptExpressionVisitor(this);
78 }
79 }
80
81
82 void ScopeBuilder::AddExceptionVariable(
83 GrowableArray<LocalVariable*>* variables, const char* prefix,
84 intptr_t nesting_depth) {
85 LocalVariable* v = NULL;
86
87 // If we are inside a function with yield points then Kernel transformer
88 // could have lifted some of the auxiliary exception variables into the
89 // context to preserve them across yield points because they might
90 // be needed for rethrow.
91 // Check if it did and capture such variables instead of introducing
92 // new local ones.
93 // Note: function that wrap kSyncYielding function does not contain
94 // its own try/catches.
95 if (current_function_node_->async_marker() == FunctionNode::kSyncYielding) {
96 ASSERT(current_function_scope_->parent() != NULL);
97 v = current_function_scope_->parent()->LocalLookupVariable(
98 GenerateName(prefix, nesting_depth - 1));
99 if (v != NULL) {
100 scope_->CaptureVariable(v);
101 }
102 }
103
104 // No need to create variables for try/catch-statements inside
105 // nested functions.
106 if (depth_.function_ > 0) return;
107 if (variables->length() >= nesting_depth) return;
108
109 // If variable was not lifted by the transformer introduce a new
110 // one into the current function scope.
111 if (v == NULL) {
112 v = MakeVariable(GenerateName(prefix, nesting_depth - 1));
113
114 // If transformer did not lift the variable then there is no need
115 // to lift it into the context when we encouter a YieldStatement.
116 v->set_is_forced_stack();
117 current_function_scope_->AddVariable(v);
118 }
119
120 variables->Add(v);
121 }
122
123
124 void ScopeBuilder::AddTryVariables() {
125 AddExceptionVariable(&result_->catch_context_variables,
126 ":saved_try_context_var", depth_.try_);
127 }
128
129
130 void ScopeBuilder::AddCatchVariables() {
131 AddExceptionVariable(&result_->exception_variables, ":exception",
132 depth_.catch_);
133 AddExceptionVariable(&result_->stack_trace_variables, ":stack_trace",
134 depth_.catch_);
135 }
136
137
138 void ScopeBuilder::AddIteratorVariable() {
139 if (depth_.function_ > 0) return;
140 if (result_->iterator_variables.length() >= depth_.for_in_) return;
141
142 ASSERT(result_->iterator_variables.length() == depth_.for_in_ - 1);
143 LocalVariable* iterator =
144 MakeVariable(GenerateName(":iterator", depth_.for_in_ - 1));
145 current_function_scope_->AddVariable(iterator);
146 result_->iterator_variables.Add(iterator);
147 }
148
149
150 void ScopeBuilder::LookupVariable(VariableDeclaration* declaration) {
151 LocalVariable* variable = result_->locals.Lookup(declaration);
152 if (variable == NULL) {
153 // We have not seen a declaration of the variable, so it must be the
154 // case that we are compiling a nested function and the variable is
155 // declared in an outer scope. In that case, look it up in the scope by
156 // name and add it to the variable map to simplify later lookup.
157 ASSERT(current_function_scope_->parent() != NULL);
158 const dart::String& name = H.DartSymbol(declaration->name());
159 variable = current_function_scope_->parent()->LookupVariable(name, true);
160 ASSERT(variable != NULL);
161 result_->locals.Insert(declaration, variable);
162 }
163 if (variable->owner()->function_level() < scope_->function_level()) {
164 // We call `LocalScope->CaptureVariable(variable)` in two scenarios for two
165 // different reasons:
166 // Scenario 1:
167 // We need to know which variables defined in this function
168 // are closed over by nested closures in order to ensure we will
169 // create a [Context] object of appropriate size and store captured
170 // variables there instead of the stack.
171 // Scenario 2:
172 // We need to find out which variables defined in enclosing functions
173 // are closed over by this function/closure or nested closures. This
174 // is necessary in order to build a fat flattened [ContextScope]
175 // object.
176 scope_->CaptureVariable(variable);
177 } else {
178 ASSERT(variable->owner()->function_level() == scope_->function_level());
179 }
180 }
181
182
183 void ScopeBuilder::LookupCapturedVariableByName(LocalVariable** variable,
184 const dart::String& name) {
185 if (*variable == NULL) {
186 *variable = scope_->LookupVariable(name, true);
187 ASSERT(*variable != NULL);
188 scope_->CaptureVariable(*variable);
189 }
190 }
191
192
193 const dart::String& ScopeBuilder::GenerateName(const char* prefix,
194 intptr_t suffix) {
195 char name[64];
196 OS::SNPrint(name, 64, "%s%" Pd "", prefix, suffix);
197 return H.DartSymbol(name);
198 }
199
200
201 void ScopeBuilder::AddVariable(VariableDeclaration* declaration) {
202 // TODO(27590): Handle final and const, including function declarations.
203 const dart::String& name = declaration->name()->is_empty()
204 ? GenerateName(":var", name_index_++)
205 : H.DartSymbol(declaration->name());
206 LocalVariable* variable = MakeVariable(name);
207 scope_->AddVariable(variable);
208 result_->locals.Insert(declaration, variable);
209 }
210
211
212 static bool IsStaticInitializer(const Function& function, Zone* zone) {
213 return (function.kind() == RawFunction::kImplicitStaticFinalGetter) &&
214 dart::String::Handle(zone, function.name())
215 .StartsWith(Symbols::InitPrefix());
216 }
217
218
219 ScopeBuildingResult* ScopeBuilder::BuildScopes() {
220 if (result_ != NULL) return result_;
221
222 ASSERT(scope_ == NULL && depth_.loop_ == 0 && depth_.function_ == 0);
223 result_ = new (Z) ScopeBuildingResult();
224
225 ParsedFunction* parsed_function = parsed_function_;
226 const dart::Function& function = parsed_function->function();
227
228 LocalScope* enclosing_scope = NULL;
229 if (function.IsLocalFunction()) {
230 enclosing_scope = LocalScope::RestoreOuterScope(
231 ContextScope::Handle(Z, function.context_scope()));
232 }
233 current_function_scope_ = scope_ = new (Z) LocalScope(enclosing_scope, 0, 0);
234 scope_->AddVariable(parsed_function->EnsureExpressionTemp());
235 scope_->AddVariable(parsed_function->current_context_var());
236 parsed_function->SetNodeSequence(
237 new SequenceNode(TokenPosition::kNoSource, scope_));
238
239 switch (function.kind()) {
240 case RawFunction::kClosureFunction:
241 case RawFunction::kRegularFunction:
242 case RawFunction::kGetterFunction:
243 case RawFunction::kSetterFunction:
244 case RawFunction::kConstructor: {
245 FunctionNode* node;
246 if (node_->IsProcedure()) {
247 node = Procedure::Cast(node_)->function();
248 } else if (node_->IsConstructor()) {
249 node = Constructor::Cast(node_)->function();
250 } else {
251 node = FunctionNode::Cast(node_);
252 }
253 current_function_node_ = node;
254
255 intptr_t pos = 0;
256 if (function.IsClosureFunction()) {
257 LocalVariable* variable = MakeVariable(Symbols::ClosureParameter());
258 scope_->InsertParameterAt(pos++, variable);
259 } else if (!function.is_static()) {
260 // We use [is_static] instead of [IsStaticFunction] because the latter
261 // returns `false` for constructors.
262 dart::Class& klass = dart::Class::Handle(Z, function.Owner());
263 Type& klass_type = H.GetCanonicalType(klass);
264 LocalVariable* variable = MakeVariable(Symbols::This(), klass_type);
265 scope_->InsertParameterAt(pos++, variable);
266 result_->this_variable = variable;
267
268 // We visit instance field initializers because they might contain
269 // [Let] expressions and we need to have a mapping.
270 if (node_->IsConstructor()) {
271 Class* klass = Class::Cast(Constructor::Cast(node_)->parent());
272
273 for (intptr_t i = 0; i < klass->fields().length(); i++) {
274 Field* field = klass->fields()[i];
275 if (!field->IsStatic() && (field->initializer() != NULL)) {
276 EnterScope(field);
277 field->initializer()->AcceptExpressionVisitor(this);
278 ExitScope();
279 }
280 }
281 }
282 } else if (function.IsFactory()) {
283 LocalVariable* variable = MakeVariable(
284 Symbols::TypeArgumentsParameter(), AbstractType::dynamic_type());
285 scope_->InsertParameterAt(pos++, variable);
286 result_->type_arguments_variable = variable;
287 }
288 AddParameters(node, pos);
289
290 // We generate a syntethic body for implicit closure functions - which
291 // will forward the call to the real function.
292 // -> see BuildGraphOfImplicitClosureFunction
293 if (!function.IsImplicitClosureFunction()) {
294 node_->AcceptVisitor(this);
295 }
296 break;
297 }
298 case RawFunction::kImplicitGetter:
299 case RawFunction::kImplicitStaticFinalGetter:
300 case RawFunction::kImplicitSetter: {
301 ASSERT(node_->IsField());
302 if (IsStaticInitializer(function, Z)) {
303 node_->AcceptVisitor(this);
304 break;
305 }
306 bool is_setter = function.IsImplicitSetterFunction();
307 bool is_method = !function.IsStaticFunction();
308 intptr_t pos = 0;
309 if (is_method) {
310 dart::Class& klass = dart::Class::Handle(Z, function.Owner());
311 Type& klass_type = H.GetCanonicalType(klass);
312 LocalVariable* variable = MakeVariable(Symbols::This(), klass_type);
313 scope_->InsertParameterAt(pos++, variable);
314 result_->this_variable = variable;
315 }
316 if (is_setter) {
317 result_->setter_value = MakeVariable(Symbols::Value());
318 scope_->InsertParameterAt(pos++, result_->setter_value);
319 }
320 break;
321 }
322 case RawFunction::kMethodExtractor: {
323 // Add a receiver parameter. Though it is captured, we emit code to
324 // explicitly copy it to a fixed offset in a freshly-allocated context
325 // instead of using the generic code for regular functions.
326 // Therefore, it isn't necessary to mark it as captured here.
327 dart::Class& klass = dart::Class::Handle(Z, function.Owner());
328 Type& klass_type = H.GetCanonicalType(klass);
329 LocalVariable* variable = MakeVariable(Symbols::This(), klass_type);
330 scope_->InsertParameterAt(0, variable);
331 result_->this_variable = variable;
332 break;
333 }
334 case RawFunction::kNoSuchMethodDispatcher:
335 case RawFunction::kInvokeFieldDispatcher:
336 for (intptr_t i = 0; i < function.NumParameters(); ++i) {
337 LocalVariable* variable = MakeVariable(
338 dart::String::ZoneHandle(Z, function.ParameterNameAt(i)));
339 scope_->InsertParameterAt(i, variable);
340 }
341 break;
342 case RawFunction::kSignatureFunction:
343 case RawFunction::kIrregexpFunction:
344 UNREACHABLE();
345 }
346
347 parsed_function->AllocateVariables();
348
349 return result_;
350 }
351
352
353 void ScopeBuilder::VisitThisExpression(ThisExpression* node) {
354 HandleSpecialLoad(&result_->this_variable, Symbols::This());
355 }
356
357
358 void ScopeBuilder::VisitTypeParameterType(TypeParameterType* node) {
359 Function& function = Function::Handle(Z, parsed_function_->function().raw());
360 while (function.IsClosureFunction()) {
361 function = function.parent_function();
362 }
363
364 if (function.IsFactory()) {
365 // The type argument vector is passed as the very first argument to the
366 // factory constructor function.
367 HandleSpecialLoad(&result_->type_arguments_variable,
368 Symbols::TypeArgumentsParameter());
369 } else {
370 // The type argument vector is stored on the instance object. We therefore
371 // need to capture `this`.
372 HandleSpecialLoad(&result_->this_variable, Symbols::This());
373 }
374 }
375
376
377 void ScopeBuilder::VisitVariableGet(VariableGet* node) {
378 LookupVariable(node->variable());
379 }
380
381
382 void ScopeBuilder::VisitVariableSet(VariableSet* node) {
383 LookupVariable(node->variable());
384 node->VisitChildren(this);
385 }
386
387
388 void ScopeBuilder::HandleLocalFunction(TreeNode* parent,
389 FunctionNode* function) {
390 LocalScope* saved_function_scope = current_function_scope_;
391 FunctionNode* saved_function_node = current_function_node_;
392 ScopeBuilder::DepthState saved_depth_state = depth_;
393 depth_ = DepthState(depth_.function_ + 1);
394 EnterScope(parent);
395 current_function_scope_ = scope_;
396 current_function_node_ = function;
397 if (depth_.function_ == 1) {
398 FunctionScope function_scope = {function, scope_};
399 result_->function_scopes.Add(function_scope);
400 }
401 AddParameters(function);
402 VisitFunctionNode(function);
403 ExitScope();
404 depth_ = saved_depth_state;
405 current_function_scope_ = saved_function_scope;
406 current_function_node_ = saved_function_node;
407 }
408
409
410 void ScopeBuilder::HandleSpecialLoad(LocalVariable** variable,
411 const dart::String& symbol) {
412 if (current_function_scope_->parent() != NULL) {
413 // We are building the scope tree of a closure function and saw [node]. We
414 // lazily populate the variable using the parent function scope.
415 if (*variable == NULL) {
416 *variable =
417 current_function_scope_->parent()->LookupVariable(symbol, true);
418 ASSERT(*variable != NULL);
419 }
420 }
421
422 if ((current_function_scope_->parent() != NULL) ||
423 (scope_->function_level() > 0)) {
424 // Every scope we use the [variable] from needs to be notified of the usage
425 // in order to ensure that preserving the context scope on that particular
426 // use-site also includes the [variable].
427 scope_->CaptureVariable(*variable);
428 }
429 }
430
431
432 void ScopeBuilder::VisitFunctionExpression(FunctionExpression* node) {
433 HandleLocalFunction(node, node->function());
434 }
435
436
437 void ScopeBuilder::VisitLet(Let* node) {
438 EnterScope(node);
439 node->VisitChildren(this);
440 ExitScope();
441 }
442
443
444 void ScopeBuilder::VisitBlock(Block* node) {
445 EnterScope(node);
446 node->VisitChildren(this);
447 ExitScope();
448 }
449
450
451 void ScopeBuilder::VisitVariableDeclaration(VariableDeclaration* node) {
452 AddVariable(node);
453 node->VisitChildren(this);
454 }
455
456
457 void ScopeBuilder::VisitFunctionDeclaration(FunctionDeclaration* node) {
458 VisitVariableDeclaration(node->variable());
459 HandleLocalFunction(node, node->function());
460 }
461
462
463 void ScopeBuilder::VisitWhileStatement(WhileStatement* node) {
464 ++depth_.loop_;
465 node->VisitChildren(this);
466 --depth_.loop_;
467 }
468
469
470 void ScopeBuilder::VisitDoStatement(DoStatement* node) {
471 ++depth_.loop_;
472 node->VisitChildren(this);
473 --depth_.loop_;
474 }
475
476
477 void ScopeBuilder::VisitForStatement(ForStatement* node) {
478 EnterScope(node);
479 List<VariableDeclaration>& variables = node->variables();
480 for (intptr_t i = 0; i < variables.length(); ++i) {
481 VisitVariableDeclaration(variables[i]);
482 }
483 ++depth_.loop_;
484 if (node->condition() != NULL) {
485 node->condition()->AcceptExpressionVisitor(this);
486 }
487 node->body()->AcceptStatementVisitor(this);
488 List<Expression>& updates = node->updates();
489 for (intptr_t i = 0; i < updates.length(); ++i) {
490 updates[i]->AcceptExpressionVisitor(this);
491 }
492 --depth_.loop_;
493 ExitScope();
494 }
495
496
497 void ScopeBuilder::VisitForInStatement(ForInStatement* node) {
498 node->iterable()->AcceptExpressionVisitor(this);
499 ++depth_.for_in_;
500 AddIteratorVariable();
501 ++depth_.loop_;
502 EnterScope(node);
503 VisitVariableDeclaration(node->variable());
504 node->body()->AcceptStatementVisitor(this);
505 ExitScope();
506 --depth_.loop_;
507 --depth_.for_in_;
508 }
509
510
511 void ScopeBuilder::AddSwitchVariable() {
512 if ((depth_.function_ == 0) && (result_->switch_variable == NULL)) {
513 LocalVariable* variable = MakeVariable(Symbols::SwitchExpr());
514 current_function_scope_->AddVariable(variable);
515 result_->switch_variable = variable;
516 }
517 }
518
519
520 void ScopeBuilder::VisitSwitchStatement(SwitchStatement* node) {
521 AddSwitchVariable();
522 node->VisitChildren(this);
523 }
524
525
526 void ScopeBuilder::VisitReturnStatement(ReturnStatement* node) {
527 if ((depth_.function_ == 0) && (depth_.finally_ > 0) &&
528 (result_->finally_return_variable == NULL)) {
529 const dart::String& name = H.DartSymbol(":try_finally_return_value");
530 LocalVariable* variable = MakeVariable(name);
531 current_function_scope_->AddVariable(variable);
532 result_->finally_return_variable = variable;
533 }
534 node->VisitChildren(this);
535 }
536
537
538 void ScopeBuilder::VisitTryCatch(TryCatch* node) {
539 ++depth_.try_;
540 AddTryVariables();
541 node->body()->AcceptStatementVisitor(this);
542 --depth_.try_;
543
544 ++depth_.catch_;
545 AddCatchVariables();
546 List<Catch>& catches = node->catches();
547 for (intptr_t i = 0; i < catches.length(); ++i) {
548 Catch* ketch = catches[i];
549 EnterScope(ketch);
550 if (ketch->exception() != NULL) {
551 VisitVariableDeclaration(ketch->exception());
552 }
553 if (ketch->stack_trace() != NULL) {
554 VisitVariableDeclaration(ketch->stack_trace());
555 }
556 ketch->body()->AcceptStatementVisitor(this);
557 ExitScope();
558 }
559 --depth_.catch_;
560 }
561
562
563 void ScopeBuilder::VisitTryFinally(TryFinally* node) {
564 ++depth_.try_;
565 ++depth_.finally_;
566 AddTryVariables();
567 node->body()->AcceptStatementVisitor(this);
568 --depth_.finally_;
569 --depth_.try_;
570
571 ++depth_.catch_;
572 AddCatchVariables();
573 node->finalizer()->AcceptStatementVisitor(this);
574 --depth_.catch_;
575 }
576
577
578 void ScopeBuilder::VisitFunctionNode(FunctionNode* node) {
579 List<TypeParameter>& type_parameters = node->type_parameters();
580 for (intptr_t i = 0; i < type_parameters.length(); ++i) {
581 VisitTypeParameter(type_parameters[i]);
582 }
583 // Do not visit the positional and named parameters, because they've
584 // already been added to the scope.
585 if (node->body() != NULL) {
586 node->body()->AcceptStatementVisitor(this);
587 }
588
589 // Ensure that :await_jump_var and :await_ctx_var are captured.
590 if (node->async_marker() == FunctionNode::kSyncYielding) {
591 {
592 LocalVariable* temp = NULL;
593 LookupCapturedVariableByName(
594 (depth_.function_ == 0) ? &result_->yield_jump_variable : &temp,
595 Symbols::AwaitJumpVar());
596 }
597 {
598 LocalVariable* temp = NULL;
599 LookupCapturedVariableByName(
600 (depth_.function_ == 0) ? &result_->yield_context_variable : &temp,
601 Symbols::AwaitContextVar());
602 }
603 }
604 }
605
606
607 void ScopeBuilder::VisitYieldStatement(YieldStatement* node) {
608 ASSERT(node->is_native());
609 if (depth_.function_ == 0) {
610 AddSwitchVariable();
611 // Promote all currently visible local variables into the context.
612 // TODO(27590) CaptureLocalVariables promotes to many variables into
613 // the scope. Mark those variables as stack_local.
614 // TODO(27590) we don't need to promote those variables that are
615 // not used across yields.
616 scope_->CaptureLocalVariables(current_function_scope_);
617 }
618 }
619
620
621 void ScopeBuilder::VisitAssertStatement(AssertStatement* node) {
622 if (I->asserts()) {
623 RecursiveVisitor::VisitAssertStatement(node);
624 }
625 }
626
627
628 void ScopeBuilder::VisitConstructor(Constructor* node) {
629 // Field initializers that come from non-static field declarations are
630 // compiled as if they appear in the constructor initializer list. This is
631 // important for closure-valued field initializers because the VM expects the
632 // corresponding closure functions to appear as if they were nested inside the
633 // constructor.
634 List<Field>& fields = Class::Cast(node->parent())->fields();
635 for (intptr_t i = 0; i < fields.length(); ++i) {
636 Field* field = fields[i];
637 Expression* initializer = field->initializer();
638 if (!field->IsStatic() && (initializer != NULL)) {
639 initializer->AcceptExpressionVisitor(this);
640 }
641 }
642 node->VisitChildren(this);
643 }
644
645
646 class BreakableBlock {
647 public:
648 BreakableBlock(FlowGraphBuilder* builder, LabeledStatement* statement)
649 : builder_(builder),
650 labeled_statement_(statement),
651 outer_(builder->breakable_block_),
652 destination_(NULL),
653 outer_finally_(builder->try_finally_block_),
654 context_depth_(builder->context_depth_) {
655 builder_->breakable_block_ = this;
656 }
657 ~BreakableBlock() { builder_->breakable_block_ = outer_; }
658
659 bool HadJumper() { return destination_ != NULL; }
660
661 JoinEntryInstr* destination() { return destination_; }
662
663 JoinEntryInstr* BreakDestination(LabeledStatement* label,
664 TryFinallyBlock** outer_finally,
665 intptr_t* context_depth) {
666 BreakableBlock* block = builder_->breakable_block_;
667 while (block->labeled_statement_ != label) {
668 block = block->outer_;
669 }
670 ASSERT(block != NULL);
671 *outer_finally = block->outer_finally_;
672 *context_depth = block->context_depth_;
673 return block->EnsureDestination();
674 }
675
676 private:
677 JoinEntryInstr* EnsureDestination() {
678 if (destination_ == NULL) {
679 destination_ = builder_->BuildJoinEntry();
680 }
681 return destination_;
682 }
683
684 FlowGraphBuilder* builder_;
685 LabeledStatement* labeled_statement_;
686 BreakableBlock* outer_;
687 JoinEntryInstr* destination_;
688 TryFinallyBlock* outer_finally_;
689 intptr_t context_depth_;
690 };
691
692
693 class SwitchBlock {
694 public:
695 SwitchBlock(FlowGraphBuilder* builder, SwitchStatement* switch_stmt)
696 : builder_(builder),
697 outer_(builder->switch_block_),
698 outer_finally_(builder->try_finally_block_),
699 switch_statement_(switch_stmt),
700 context_depth_(builder->context_depth_) {
701 builder_->switch_block_ = this;
702 }
703 ~SwitchBlock() { builder_->switch_block_ = outer_; }
704
705 bool HadJumper(SwitchCase* switch_case) {
706 return destinations_.Lookup(switch_case) != NULL;
707 }
708
709 JoinEntryInstr* Destination(SwitchCase* label,
710 TryFinallyBlock** outer_finally = NULL,
711 intptr_t* context_depth = NULL) {
712 // Find corresponding [SwitchStatement].
713 SwitchBlock* block = this;
714 while (true) {
715 block->EnsureSwitchCaseMapping();
716 if (block->Contains(label)) break;
717 block = block->outer_;
718 }
719
720 // Set the outer finally block.
721 if (outer_finally != NULL) {
722 *outer_finally = block->outer_finally_;
723 *context_depth = block->context_depth_;
724 }
725
726 // Ensure there's [JoinEntryInstr] for that [SwitchCase].
727 return block->EnsureDestination(label);
728 }
729
730 private:
731 typedef std::set<SwitchCase*> DestinationSwitches;
732
733 JoinEntryInstr* EnsureDestination(SwitchCase* switch_case) {
734 JoinEntryInstr* cached_inst = destinations_.Lookup(switch_case);
735 if (cached_inst == NULL) {
736 JoinEntryInstr* inst = builder_->BuildJoinEntry();
737 destinations_.Insert(switch_case, inst);
738 return inst;
739 }
740 return cached_inst;
741 }
742
743 void EnsureSwitchCaseMapping() {
744 if (destination_switches_.begin() == destination_switches_.end()) {
745 List<SwitchCase>& cases = switch_statement_->cases();
746 for (intptr_t i = 0; i < cases.length(); i++) {
747 destination_switches_.insert(cases[i]);
748 }
749 }
750 }
751
752 bool Contains(SwitchCase* sc) {
753 return destination_switches_.find(sc) != destination_switches_.end();
754 }
755
756 FlowGraphBuilder* builder_;
757 SwitchBlock* outer_;
758
759 Map<SwitchCase, JoinEntryInstr*> destinations_;
760 DestinationSwitches destination_switches_;
761
762 TryFinallyBlock* outer_finally_;
763 SwitchStatement* switch_statement_;
764 intptr_t context_depth_;
765 };
766
767
768 class TryFinallyBlock {
769 public:
770 TryFinallyBlock(FlowGraphBuilder* builder, Statement* finalizer)
771 : builder_(builder),
772 outer_(builder->try_finally_block_),
773 finalizer_(finalizer),
774 context_depth_(builder->context_depth_),
775 // Finalizers are executed outside of the try block hence
776 // try depth of finalizers are one less than current try
777 // depth.
778 try_depth_(builder->try_depth_ - 1) {
779 builder_->try_finally_block_ = this;
780 }
781 ~TryFinallyBlock() { builder_->try_finally_block_ = outer_; }
782
783 Statement* finalizer() const { return finalizer_; }
784 intptr_t context_depth() const { return context_depth_; }
785 intptr_t try_depth() const { return try_depth_; }
786 TryFinallyBlock* outer() const { return outer_; }
787
788 private:
789 FlowGraphBuilder* const builder_;
790 TryFinallyBlock* const outer_;
791 Statement* const finalizer_;
792 const intptr_t context_depth_;
793 const intptr_t try_depth_;
794 };
795
796
797 class TryCatchBlock {
798 public:
799 explicit TryCatchBlock(FlowGraphBuilder* builder,
800 intptr_t try_handler_index = -1)
801 : builder_(builder),
802 outer_(builder->try_catch_block_),
803 try_index_(try_handler_index) {
804 if (try_index_ == -1) try_index_ = builder->AllocateTryIndex();
805 builder->try_catch_block_ = this;
806 }
807 ~TryCatchBlock() { builder_->try_catch_block_ = outer_; }
808
809 intptr_t TryIndex() { return try_index_; }
810
811 private:
812 FlowGraphBuilder* builder_;
813 TryCatchBlock* outer_;
814 intptr_t try_index_;
815 };
816
817
818 class CatchBlock {
819 public:
820 CatchBlock(FlowGraphBuilder* builder, LocalVariable* exception_var,
821 LocalVariable* stack_trace_var, intptr_t catch_try_index)
822 : builder_(builder),
823 outer_(builder->catch_block_),
824 exception_var_(exception_var),
825 stack_trace_var_(stack_trace_var),
826 catch_try_index_(catch_try_index) {
827 builder_->catch_block_ = this;
828 }
829 ~CatchBlock() { builder_->catch_block_ = outer_; }
830
831 LocalVariable* exception_var() { return exception_var_; }
832 LocalVariable* stack_trace_var() { return stack_trace_var_; }
833 intptr_t catch_try_index() { return catch_try_index_; }
834
835 private:
836 FlowGraphBuilder* builder_;
837 CatchBlock* outer_;
838 LocalVariable* exception_var_;
839 LocalVariable* stack_trace_var_;
840 intptr_t catch_try_index_;
841 };
842
843
844 Fragment& Fragment::operator+=(const Fragment& other) {
845 if (entry == NULL) {
846 entry = other.entry;
847 current = other.current;
848 } else if (current != NULL && other.entry != NULL) {
849 current->LinkTo(other.entry);
850 current = other.current;
851 }
852 return *this;
853 }
854
855
856 Fragment& Fragment::operator<<=(Instruction* next) {
857 if (entry == NULL) {
858 entry = current = next;
859 } else if (current != NULL) {
860 current->LinkTo(next);
861 current = next;
862 }
863 return *this;
864 }
865
866
867 Fragment Fragment::closed() {
868 ASSERT(entry != NULL);
869 return Fragment(entry, NULL);
870 }
871
872
873 Fragment operator+(const Fragment& first, const Fragment& second) {
874 Fragment result = first;
875 result += second;
876 return result;
877 }
878
879
880 Fragment operator<<(const Fragment& fragment, Instruction* next) {
881 Fragment result = fragment;
882 result <<= next;
883 return result;
884 }
885
886
887 RawInstance* TranslationHelper::Canonicalize(const Instance& instance) {
888 if (instance.IsNull()) return instance.raw();
889
890 const char* error_str = NULL;
891 RawInstance* result = instance.CheckAndCanonicalize(thread(), &error_str);
892 if (result == Object::null()) {
893 ReportError("Invalid const object %s", error_str);
894 }
895 return result;
896 }
897
898
899 const dart::String& TranslationHelper::DartString(const char* content,
900 Heap::Space space) {
901 return dart::String::ZoneHandle(Z, dart::String::New(content, space));
902 }
903
904
905 dart::String& TranslationHelper::DartString(String* content,
906 Heap::Space space) {
907 return dart::String::ZoneHandle(
908 Z, dart::String::FromUTF8(content->buffer(), content->size(), space));
909 }
910
911
912 const dart::String& TranslationHelper::DartSymbol(const char* content) const {
913 return dart::String::ZoneHandle(Z, Symbols::New(thread_, content));
914 }
915
916
917 dart::String& TranslationHelper::DartSymbol(String* content) const {
918 return dart::String::ZoneHandle(
919 Z, dart::Symbols::FromUTF8(thread_, content->buffer(), content->size()));
920 }
921
922
923 const dart::String& TranslationHelper::DartClassName(
924 kernel::Class* kernel_klass) {
925 if (kernel_klass->name() != NULL) {
926 ASSERT(kernel_klass->IsNormalClass());
927 dart::String& name = DartString(kernel_klass->name());
928 return ManglePrivateName(kernel_klass->parent(), &name);
929 } else {
930 // Mixin class names are not mangled.
931 ASSERT(kernel_klass->IsMixinClass());
932
933 // We construct the string from right to left:
934 // "Base&Mixin1&Mixin2&...&MixinN"
935 dart::String& partial = dart::String::Handle(Z, dart::String::New(""));
936 dart::String& amp = dart::String::Handle(Z, dart::String::New("&"));
937 dart::String& tmp = dart::String::Handle(Z);
938 while (kernel_klass->name() == NULL) {
939 ASSERT(kernel_klass->IsMixinClass());
940
941 MixinClass* kernel_mixin_class = MixinClass::Cast(kernel_klass);
942 InterfaceType* base_type = kernel_mixin_class->first();
943 InterfaceType* mixin_type = kernel_mixin_class->second();
944
945 String* mixin_name = NormalClass::Cast(mixin_type->klass())->name();
946
947 tmp = dart::String::FromUTF8(mixin_name->buffer(), mixin_name->size());
948
949 partial = dart::String::Concat(amp, partial);
950 partial = dart::String::Concat(tmp, partial);
951
952 kernel_klass = base_type->klass();
953 }
954
955 tmp = dart::String::FromUTF8(kernel_klass->name()->buffer(),
956 kernel_klass->name()->size());
957
958 partial = dart::String::Concat(amp, partial);
959 partial = dart::String::Concat(tmp, partial);
960
961 partial = dart::Symbols::New(thread_, partial);
962 return partial;
963 }
964 }
965
966
967 const dart::String& TranslationHelper::DartConstructorName(Constructor* node) {
968 Class* klass = Class::Cast(node->parent());
969 return DartFactoryName(klass, node->name());
970 }
971
972
973 const dart::String& TranslationHelper::DartProcedureName(Procedure* procedure) {
974 if (procedure->kind() == Procedure::kSetter) {
975 return DartSetterName(procedure->name());
976 } else if (procedure->kind() == Procedure::kGetter) {
977 return DartGetterName(procedure->name());
978 } else if (procedure->kind() == Procedure::kFactory) {
979 return DartFactoryName(Class::Cast(procedure->parent()), procedure->name());
980 } else {
981 return DartMethodName(procedure->name());
982 }
983 }
984
985
986 const dart::String& TranslationHelper::DartSetterName(Name* kernel_name) {
987 // The names flowing into [content] are coming from the Kernel file:
988 // * user-defined setters: `fieldname=`
989 // * property-set expressions: `fieldname`
990 //
991 // The VM uses `get:fieldname` and `set:fieldname`.
992 //
993 // => In order to be consistent, we remove the `=` always and adopt the VM
994 // conventions.
995 String* content = kernel_name->string();
996 ASSERT(content->size() > 0);
997 intptr_t skip = 0;
998 if (content->buffer()[content->size() - 1] == '=') {
999 skip = 1;
1000 }
1001 dart::String& name = dart::String::ZoneHandle(
1002 Z, dart::String::FromUTF8(content->buffer(), content->size() - skip));
1003 ManglePrivateName(kernel_name->library(), &name, false);
1004 name = dart::Field::SetterSymbol(name);
1005 return name;
1006 }
1007
1008
1009 const dart::String& TranslationHelper::DartGetterName(Name* kernel_name) {
1010 dart::String& name = DartString(kernel_name->string());
1011 ManglePrivateName(kernel_name->library(), &name, false);
1012 name = dart::Field::GetterSymbol(name);
1013 return name;
1014 }
1015
1016
1017 const dart::String& TranslationHelper::DartFieldName(Name* kernel_name) {
1018 dart::String& name = DartString(kernel_name->string());
1019 return ManglePrivateName(kernel_name->library(), &name);
1020 }
1021
1022
1023 const dart::String& TranslationHelper::DartInitializerName(Name* kernel_name) {
1024 // The [DartFieldName] will take care of mangling the name.
1025 dart::String& name =
1026 dart::String::Handle(Z, DartFieldName(kernel_name).raw());
1027 name = Symbols::FromConcat(thread_, Symbols::InitPrefix(), name);
1028 return name;
1029 }
1030
1031
1032 const dart::String& TranslationHelper::DartMethodName(Name* kernel_name) {
1033 dart::String& name = DartString(kernel_name->string());
1034 return ManglePrivateName(kernel_name->library(), &name);
1035 }
1036
1037
1038 const dart::String& TranslationHelper::DartFactoryName(Class* klass,
1039 Name* method_name) {
1040 // [DartMethodName] will mangle the name.
1041 dart::String& name =
1042 dart::String::Handle(Z, DartMethodName(method_name).raw());
1043
1044 // We build a String which looks like <classname>.<constructor-name>.
1045 // [DartClassName] will mangle the name.
1046 dart::String& temp = dart::String::Handle(Z, DartClassName(klass).raw());
1047 temp = dart::String::Concat(temp, Symbols::Dot());
1048 temp = dart::String::Concat(temp, name);
1049 return dart::String::ZoneHandle(Z, dart::Symbols::New(thread_, temp));
1050 }
1051
1052
1053 dart::RawLibrary* TranslationHelper::LookupLibraryByKernelLibrary(
1054 Library* kernel_library) {
1055 const dart::String& library_name = DartSymbol(kernel_library->import_uri());
1056 ASSERT(!library_name.IsNull());
1057 dart::RawLibrary* library =
1058 dart::Library::LookupLibrary(thread_, library_name);
1059 ASSERT(library != Object::null());
1060 return library;
1061 }
1062
1063
1064 dart::RawClass* TranslationHelper::LookupClassByKernelClass(
1065 Class* kernel_klass) {
1066 dart::RawClass* klass = NULL;
1067
1068 const dart::String& class_name = DartClassName(kernel_klass);
1069 Library* kernel_library = Library::Cast(kernel_klass->parent());
1070 dart::Library& library =
1071 dart::Library::Handle(Z, LookupLibraryByKernelLibrary(kernel_library));
1072 klass = library.LookupClassAllowPrivate(class_name);
1073
1074 ASSERT(klass != Object::null());
1075 return klass;
1076 }
1077
1078
1079 dart::RawField* TranslationHelper::LookupFieldByKernelField(
1080 Field* kernel_field) {
1081 TreeNode* node = kernel_field->parent();
1082
1083 dart::Class& klass = dart::Class::Handle(Z);
1084 if (node->IsClass()) {
1085 klass = LookupClassByKernelClass(Class::Cast(node));
1086 } else {
1087 ASSERT(node->IsLibrary());
1088 dart::Library& library = dart::Library::Handle(
1089 Z, LookupLibraryByKernelLibrary(Library::Cast(node)));
1090 klass = library.toplevel_class();
1091 }
1092 dart::RawField* field =
1093 klass.LookupFieldAllowPrivate(DartSymbol(kernel_field->name()->string()));
1094 ASSERT(field != Object::null());
1095 return field;
1096 }
1097
1098
1099 dart::RawFunction* TranslationHelper::LookupStaticMethodByKernelProcedure(
1100 Procedure* procedure) {
1101 ASSERT(procedure->IsStatic());
1102 const dart::String& procedure_name = DartProcedureName(procedure);
1103
1104 // The parent is either a library or a class (in which case the procedure is a
1105 // static method).
1106 TreeNode* parent = procedure->parent();
1107 if (parent->IsClass()) {
1108 dart::Class& klass =
1109 dart::Class::Handle(Z, LookupClassByKernelClass(Class::Cast(parent)));
1110 dart::RawFunction* raw_function =
1111 klass.LookupFunctionAllowPrivate(procedure_name);
1112 ASSERT(raw_function != Object::null());
1113
1114 // TODO(27590): We can probably get rid of this after no longer using
1115 // core libraries from the source.
1116 dart::Function& function = dart::Function::ZoneHandle(Z, raw_function);
1117 if (function.IsRedirectingFactory()) {
1118 ClassFinalizer::ResolveRedirectingFactory(klass, function);
1119 function = function.RedirectionTarget();
1120 }
1121 return function.raw();
1122 } else {
1123 ASSERT(parent->IsLibrary());
1124 dart::Library& library = dart::Library::Handle(
1125 Z, LookupLibraryByKernelLibrary(Library::Cast(parent)));
1126 dart::RawFunction* function =
1127 library.LookupFunctionAllowPrivate(procedure_name);
1128 ASSERT(function != Object::null());
1129 return function;
1130 }
1131 }
1132
1133
1134 dart::RawFunction* TranslationHelper::LookupConstructorByKernelConstructor(
1135 Constructor* constructor) {
1136 Class* kernel_klass = Class::Cast(constructor->parent());
1137 dart::Class& klass =
1138 dart::Class::Handle(Z, LookupClassByKernelClass(kernel_klass));
1139 return LookupConstructorByKernelConstructor(klass, constructor);
1140 }
1141
1142
1143 dart::RawFunction* TranslationHelper::LookupConstructorByKernelConstructor(
1144 const dart::Class& owner, Constructor* constructor) {
1145 dart::RawFunction* function =
1146 owner.LookupConstructorAllowPrivate(DartConstructorName(constructor));
1147 ASSERT(function != Object::null());
1148 return function;
1149 }
1150
1151
1152 dart::Type& TranslationHelper::GetCanonicalType(const dart::Class& klass) {
1153 ASSERT(!klass.IsNull());
1154 // Note that if cls is _Closure, the returned type will be _Closure,
1155 // and not the signature type.
1156 Type& type = Type::ZoneHandle(Z, klass.CanonicalType());
1157 if (!type.IsNull()) {
1158 return type;
1159 }
1160 type = Type::New(klass, TypeArguments::Handle(Z, klass.type_parameters()),
1161 klass.token_pos());
1162 if (klass.is_type_finalized()) {
1163 type ^= ClassFinalizer::FinalizeType(
1164 klass, type, ClassFinalizer::kCanonicalizeWellFormed);
1165 // Note that the receiver type may now be a malbounded type.
1166 klass.SetCanonicalType(type);
1167 }
1168 return type;
1169 }
1170
1171
1172 void TranslationHelper::ReportError(const char* format, ...) {
1173 const Script& null_script = Script::Handle(Z);
1174
1175 va_list args;
1176 va_start(args, format);
1177 Report::MessageV(Report::kError, null_script, TokenPosition::kNoSource,
1178 Report::AtLocation, format, args);
1179 va_end(args);
1180 UNREACHABLE();
1181 }
1182
1183
1184 void TranslationHelper::ReportError(const Error& prev_error, const char* format,
1185 ...) {
1186 const Script& null_script = Script::Handle(Z);
1187
1188 va_list args;
1189 va_start(args, format);
1190 Report::LongJumpV(prev_error, null_script, TokenPosition::kNoSource, format,
1191 args);
1192 va_end(args);
1193 UNREACHABLE();
1194 }
1195
1196
1197 dart::String& TranslationHelper::ManglePrivateName(Library* kernel_library,
1198 dart::String* name_to_modify,
1199 bool symbolize) {
1200 if (name_to_modify->Length() >= 1 && name_to_modify->CharAt(0) == '_') {
1201 const dart::Library& library =
1202 dart::Library::Handle(Z, LookupLibraryByKernelLibrary(kernel_library));
1203 *name_to_modify = library.PrivateName(*name_to_modify);
1204 } else if (symbolize) {
1205 *name_to_modify = Symbols::New(thread_, *name_to_modify);
1206 }
1207 return *name_to_modify;
1208 }
1209
1210
1211 const Array& TranslationHelper::ArgumentNames(List<NamedExpression>* named) {
1212 if (named->length() == 0) return Array::ZoneHandle(Z);
1213
1214 const Array& names = Array::ZoneHandle(Z, Array::New(named->length()));
1215 for (intptr_t i = 0; i < named->length(); ++i) {
1216 names.SetAt(i, DartSymbol((*named)[i]->name()));
1217 }
1218 return names;
1219 }
1220
1221
1222 Instance& ConstantEvaluator::EvaluateExpression(Expression* expression) {
1223 expression->AcceptExpressionVisitor(this);
1224 // We return a new `ZoneHandle` here on purpose: The intermediate language
1225 // instructions do not make a copy of the handle, so we do it.
1226 return dart::Instance::ZoneHandle(Z, result_.raw());
1227 }
1228
1229
1230 Object& ConstantEvaluator::EvaluateExpressionSafe(Expression* expression) {
1231 LongJumpScope jump;
1232 if (setjmp(*jump.Set()) == 0) {
1233 return EvaluateExpression(expression);
1234 } else {
1235 Thread* thread = Thread::Current();
1236 Error& error = Error::Handle(Z);
1237 error = thread->sticky_error();
1238 thread->clear_sticky_error();
1239 return error;
1240 }
1241 }
1242
1243
1244 Instance& ConstantEvaluator::EvaluateConstructorInvocation(
1245 ConstructorInvocation* node) {
1246 VisitConstructorInvocation(node);
1247 // We return a new `ZoneHandle` here on purpose: The intermediate language
1248 // instructions do not make a copy of the handle, so we do it.
1249 return dart::Instance::ZoneHandle(Z, result_.raw());
1250 }
1251
1252
1253 Instance& ConstantEvaluator::EvaluateListLiteral(ListLiteral* node) {
1254 VisitListLiteral(node);
1255 // We return a new `ZoneHandle` here on purpose: The intermediate language
1256 // instructions do not make a copy of the handle, so we do it.
1257 return dart::Instance::ZoneHandle(Z, result_.raw());
1258 }
1259
1260
1261 Instance& ConstantEvaluator::EvaluateMapLiteral(MapLiteral* node) {
1262 VisitMapLiteral(node);
1263 // We return a new `ZoneHandle` here on purpose: The intermediate language
1264 // instructions do not make a copy of the handle, so we do it.
1265 return dart::Instance::ZoneHandle(Z, result_.raw());
1266 }
1267
1268
1269 void ConstantEvaluator::VisitBigintLiteral(BigintLiteral* node) {
1270 const dart::String& value = H.DartString(node->value());
1271 result_ = Integer::New(value, Heap::kOld);
1272 result_ = H.Canonicalize(result_);
1273 }
1274
1275
1276 void ConstantEvaluator::VisitBoolLiteral(BoolLiteral* node) {
1277 result_ = dart::Bool::Get(node->value()).raw();
1278 }
1279
1280
1281 void ConstantEvaluator::VisitDoubleLiteral(DoubleLiteral* node) {
1282 result_ = dart::Double::New(H.DartString(node->value()), Heap::kOld);
1283 result_ = H.Canonicalize(result_);
1284 }
1285
1286
1287 void ConstantEvaluator::VisitIntLiteral(IntLiteral* node) {
1288 result_ = dart::Integer::New(node->value(), Heap::kOld);
1289 result_ = H.Canonicalize(result_);
1290 }
1291
1292
1293 void ConstantEvaluator::VisitNullLiteral(NullLiteral* node) {
1294 result_ = dart::Instance::null();
1295 }
1296
1297
1298 void ConstantEvaluator::VisitStringLiteral(StringLiteral* node) {
1299 result_ = H.DartSymbol(node->value()).raw();
1300 }
1301
1302
1303 void ConstantEvaluator::VisitTypeLiteral(TypeLiteral* node) {
1304 const AbstractType& type = T.TranslateType(node->type());
1305 if (type.IsMalformed()) {
1306 H.ReportError("Malformed type literal in constant expression.");
1307 }
1308 result_ = type.raw();
1309 }
1310
1311
1312 RawObject* ConstantEvaluator::EvaluateConstConstructorCall(
1313 const dart::Class& type_class, const TypeArguments& type_arguments,
1314 const Function& constructor, const Object& argument) {
1315 // Factories have one extra argument: the type arguments.
1316 // Constructors have 1 extra arguments: receiver.
1317 const int kNumArgs = 1;
1318 const int kNumExtraArgs = 1;
1319 const int num_arguments = kNumArgs + kNumExtraArgs;
1320 const Array& arg_values =
1321 Array::Handle(Z, Array::New(num_arguments, Heap::kOld));
1322 Instance& instance = Instance::Handle(Z);
1323 if (!constructor.IsFactory()) {
1324 instance = Instance::New(type_class, Heap::kOld);
1325 if (!type_arguments.IsNull()) {
1326 ASSERT(type_arguments.IsInstantiated());
1327 instance.SetTypeArguments(
1328 TypeArguments::Handle(Z, type_arguments.Canonicalize()));
1329 }
1330 arg_values.SetAt(0, instance);
1331 } else {
1332 // Prepend type_arguments to list of arguments to factory.
1333 ASSERT(type_arguments.IsZoneHandle());
1334 arg_values.SetAt(0, type_arguments);
1335 }
1336 arg_values.SetAt((0 + kNumExtraArgs), argument);
1337 const Array& args_descriptor = Array::Handle(
1338 Z, ArgumentsDescriptor::New(num_arguments, Object::empty_array()));
1339 const Object& result = Object::Handle(
1340 Z, DartEntry::InvokeFunction(constructor, arg_values, args_descriptor));
1341 ASSERT(!result.IsError());
1342 if (constructor.IsFactory()) {
1343 // The factory method returns the allocated object.
1344 instance ^= result.raw();
1345 }
1346 return H.Canonicalize(instance);
1347 }
1348
1349
1350 void ConstantEvaluator::VisitSymbolLiteral(SymbolLiteral* node) {
1351 const dart::String& symbol_value = H.DartSymbol(node->value());
1352
1353 const dart::Class& symbol_class =
1354 dart::Class::ZoneHandle(Z, I->object_store()->symbol_class());
1355 ASSERT(!symbol_class.IsNull());
1356 const dart::Function& symbol_constructor = Function::ZoneHandle(
1357 Z, symbol_class.LookupConstructor(Symbols::SymbolCtor()));
1358 ASSERT(!symbol_constructor.IsNull());
1359 result_ ^= EvaluateConstConstructorCall(
1360 symbol_class, TypeArguments::Handle(Z), symbol_constructor, symbol_value);
1361 }
1362
1363
1364 void ConstantEvaluator::VisitListLiteral(ListLiteral* node) {
1365 DartType* types[] = {node->type()};
1366 const TypeArguments& type_arguments = T.TranslateTypeArguments(types, 1);
1367
1368 intptr_t length = node->expressions().length();
1369 const Array& const_list =
1370 Array::ZoneHandle(Z, Array::New(length, Heap::kOld));
1371 const_list.SetTypeArguments(type_arguments);
1372 for (intptr_t i = 0; i < length; i++) {
1373 const Instance& expression = EvaluateExpression(node->expressions()[i]);
1374 const_list.SetAt(i, expression);
1375 }
1376 const_list.MakeImmutable();
1377 result_ = H.Canonicalize(const_list);
1378 }
1379
1380
1381 void ConstantEvaluator::VisitMapLiteral(MapLiteral* node) {
1382 DartType* types[] = {node->key_type(), node->value_type()};
1383 const TypeArguments& type_arguments = T.TranslateTypeArguments(types, 2);
1384
1385 intptr_t length = node->entries().length();
1386
1387 Array& const_kv_array =
1388 Array::ZoneHandle(Z, Array::New(2 * length, Heap::kOld));
1389 for (intptr_t i = 0; i < length; i++) {
1390 const_kv_array.SetAt(2 * i + 0,
1391 EvaluateExpression(node->entries()[i]->key()));
1392 const_kv_array.SetAt(2 * i + 1,
1393 EvaluateExpression(node->entries()[i]->value()));
1394 }
1395
1396 const_kv_array.MakeImmutable();
1397 const_kv_array ^= H.Canonicalize(const_kv_array);
1398
1399 const dart::Class& map_class = dart::Class::Handle(
1400 Z, dart::Library::LookupCoreClass(Symbols::ImmutableMap()));
1401 ASSERT(!map_class.IsNull());
1402 ASSERT(map_class.NumTypeArguments() == 2);
1403
1404 const dart::Field& field = dart::Field::Handle(
1405 Z, map_class.LookupInstanceFieldAllowPrivate(H.DartSymbol("_kvPairs")));
1406 ASSERT(!field.IsNull());
1407
1408 // NOTE: This needs to be kept in sync with `runtime/lib/immutable_map.dart`!
1409 result_ = Instance::New(map_class, Heap::kOld);
1410 ASSERT(!result_.IsNull());
1411 result_.SetTypeArguments(type_arguments);
1412 result_.SetField(field, const_kv_array);
1413 result_ = H.Canonicalize(result_);
1414 }
1415
1416
1417 void ConstantEvaluator::VisitConstructorInvocation(
1418 ConstructorInvocation* node) {
1419 Arguments* kernel_arguments = node->arguments();
1420
1421 const Function& constructor = Function::Handle(
1422 Z, H.LookupConstructorByKernelConstructor(node->target()));
1423 dart::Class& klass = dart::Class::Handle(Z, constructor.Owner());
1424
1425 // Build the type arguments vector (if necessary).
1426 const TypeArguments* type_arguments =
1427 TranslateTypeArguments(constructor, &klass, kernel_arguments);
1428
1429 // Prepare either the instance or the type argument vector for the constructor
1430 // call.
1431 Instance* receiver = NULL;
1432 const TypeArguments* type_arguments_argument = NULL;
1433 if (!constructor.IsFactory()) {
1434 receiver = &Instance::ZoneHandle(Z, Instance::New(klass, Heap::kOld));
1435 if (type_arguments != NULL) {
1436 receiver->SetTypeArguments(*type_arguments);
1437 }
1438 } else {
1439 type_arguments_argument = type_arguments;
1440 }
1441
1442 const Object& result = RunFunction(constructor, kernel_arguments, receiver,
1443 type_arguments_argument);
1444 if (constructor.IsFactory()) {
1445 // Factories return the new object.
1446 result_ ^= result.raw();
1447 result_ = H.Canonicalize(result_);
1448 } else {
1449 ASSERT(!receiver->IsNull());
1450 result_ = H.Canonicalize(*receiver);
1451 }
1452 }
1453
1454
1455 void ConstantEvaluator::VisitMethodInvocation(MethodInvocation* node) {
1456 Arguments* kernel_arguments = node->arguments();
1457
1458 // Dart does not support generic methods yet.
1459 ASSERT(kernel_arguments->types().length() == 0);
1460
1461 const dart::Instance& receiver = EvaluateExpression(node->receiver());
1462 dart::Class& klass = dart::Class::Handle(
1463 Z, isolate_->class_table()->At(receiver.GetClassId()));
1464 ASSERT(!klass.IsNull());
1465
1466 // Search the superclass chain for the selector.
1467 // TODO(27590): Can we assume this will never be a no-such-method error?
1468 dart::Function& function = dart::Function::Handle(Z);
1469 const dart::String& method_name = H.DartMethodName(node->name());
1470 while (!klass.IsNull()) {
1471 function = klass.LookupDynamicFunctionAllowPrivate(method_name);
1472 if (!function.IsNull()) break;
1473 klass = klass.SuperClass();
1474 }
1475 ASSERT(!function.IsNull());
1476
1477 // Run the method and canonicalize the result.
1478 const Object& result = RunFunction(function, kernel_arguments, &receiver);
1479 result_ ^= result.raw();
1480 result_ = H.Canonicalize(result_);
1481 }
1482
1483
1484 void ConstantEvaluator::VisitStaticGet(StaticGet* node) {
1485 Member* member = node->target();
1486 if (member->IsField()) {
1487 Field* kernel_field = Field::Cast(member);
1488 const dart::Field& field =
1489 dart::Field::Handle(Z, H.LookupFieldByKernelField(kernel_field));
1490 if (field.StaticValue() == Object::sentinel().raw() ||
1491 field.StaticValue() == Object::transition_sentinel().raw()) {
1492 field.EvaluateInitializer();
1493 result_ = field.StaticValue();
1494 result_ = H.Canonicalize(result_);
1495 field.SetStaticValue(result_, true);
1496 } else {
1497 result_ = field.StaticValue();
1498 }
1499 } else if (member->IsProcedure()) {
1500 Procedure* procedure = Procedure::Cast(member);
1501 const Function& target = Function::ZoneHandle(
1502 Z, H.LookupStaticMethodByKernelProcedure(procedure));
1503
1504 if (procedure->kind() == Procedure::kMethod) {
1505 ASSERT(procedure->IsStatic());
1506 Function& closure_function =
1507 Function::ZoneHandle(Z, target.ImplicitClosureFunction());
1508 closure_function.set_kernel_function(target.kernel_function());
1509 result_ = closure_function.ImplicitStaticClosure();
1510 result_ = H.Canonicalize(result_);
1511 } else if (procedure->kind() == Procedure::kGetter) {
1512 UNIMPLEMENTED();
1513 } else {
1514 UNIMPLEMENTED();
1515 }
1516 }
1517 }
1518
1519
1520 void ConstantEvaluator::VisitVariableGet(VariableGet* node) {
1521 // When we see a [VariableGet] the corresponding [VariableDeclaration] must've
1522 // been executed already. It therefore must have a constant object associated
1523 // with it.
1524 LocalVariable* variable = builder_->LookupVariable(node->variable());
1525 ASSERT(variable->IsConst());
1526 result_ = variable->ConstValue()->raw();
1527 }
1528
1529
1530 void ConstantEvaluator::VisitLet(Let* node) {
1531 VariableDeclaration* variable = node->variable();
1532 LocalVariable* local = builder_->LookupVariable(variable);
1533 local->SetConstValue(EvaluateExpression(variable->initializer()));
1534 node->body()->AcceptExpressionVisitor(this);
1535 }
1536
1537
1538 void ConstantEvaluator::VisitStaticInvocation(StaticInvocation* node) {
1539 const Function& function = Function::ZoneHandle(
1540 Z, H.LookupStaticMethodByKernelProcedure(node->procedure()));
1541 dart::Class& klass = dart::Class::Handle(Z, function.Owner());
1542
1543 // Build the type arguments vector (if necessary).
1544 const TypeArguments* type_arguments =
1545 TranslateTypeArguments(function, &klass, node->arguments());
1546
1547 const Object& result =
1548 RunFunction(function, node->arguments(), NULL, type_arguments);
1549 result_ ^= result.raw();
1550 result_ = H.Canonicalize(result_);
1551 }
1552
1553
1554 void ConstantEvaluator::VisitStringConcatenation(StringConcatenation* node) {
1555 intptr_t length = node->expressions().length();
1556
1557 bool all_string = true;
1558 const Array& strings = Array::Handle(Z, Array::New(length));
1559 for (intptr_t i = 0; i < length; i++) {
1560 EvaluateExpression(node->expressions()[i]);
1561 strings.SetAt(i, result_);
1562 all_string = all_string && result_.IsString();
1563 }
1564 if (all_string) {
1565 result_ = dart::String::ConcatAll(strings, Heap::kOld);
1566 result_ = H.Canonicalize(result_);
1567 } else {
1568 // Get string interpolation function.
1569 const dart::Class& cls = dart::Class::Handle(
1570 Z, dart::Library::LookupCoreClass(Symbols::StringBase()));
1571 ASSERT(!cls.IsNull());
1572 const Function& func = Function::Handle(
1573 Z, cls.LookupStaticFunction(
1574 dart::Library::PrivateCoreLibName(Symbols::Interpolate())));
1575 ASSERT(!func.IsNull());
1576
1577 // Build argument array to pass to the interpolation function.
1578 const Array& interpolate_arg = Array::Handle(Z, Array::New(1, Heap::kOld));
1579 interpolate_arg.SetAt(0, strings);
1580
1581 // Run and canonicalize.
1582 const Object& result =
1583 RunFunction(func, interpolate_arg, Array::null_array());
1584 result_ = H.Canonicalize(dart::String::Cast(result));
1585 }
1586 }
1587
1588
1589 void ConstantEvaluator::VisitConditionalExpression(
1590 ConditionalExpression* node) {
1591 EvaluateExpression(node->condition());
1592 if (Bool::Cast(result_).value()) {
1593 EvaluateExpression(node->then());
1594 } else {
1595 EvaluateExpression(node->otherwise());
1596 }
1597 }
1598
1599
1600 void ConstantEvaluator::VisitLogicalExpression(LogicalExpression* node) {
1601 if (node->op() == LogicalExpression::kAnd) {
1602 EvaluateExpression(node->left());
1603 if (Bool::Cast(result_).value()) {
1604 EvaluateExpression(node->right());
1605 }
1606 } else {
1607 ASSERT(node->op() == LogicalExpression::kOr);
1608 EvaluateExpression(node->left());
1609 if (!Bool::Cast(result_).value()) {
1610 EvaluateExpression(node->right());
1611 }
1612 }
1613 }
1614
1615
1616 void ConstantEvaluator::VisitNot(Not* node) {
1617 EvaluateExpression(node->expression());
1618 ASSERT(result_.IsBool());
1619 result_ =
1620 Bool::Cast(result_).value() ? Bool::False().raw() : Bool::True().raw();
1621 }
1622
1623
1624 const TypeArguments* ConstantEvaluator::TranslateTypeArguments(
1625 const Function& target, dart::Class* target_klass,
1626 Arguments* kernel_arguments) {
1627 List<DartType>& kernel_type_arguments = kernel_arguments->types();
1628
1629 const TypeArguments* type_arguments = NULL;
1630 if (kernel_type_arguments.length() > 0) {
1631 type_arguments = &T.TranslateInstantiatedTypeArguments(
1632 *target_klass, kernel_type_arguments.raw_array(),
1633 kernel_type_arguments.length());
1634
1635 if (!(type_arguments->IsNull() || type_arguments->IsInstantiated())) {
1636 H.ReportError("Type must be constant in const constructor.");
1637 }
1638 } else if (target.IsFactory() && type_arguments == NULL) {
1639 // All factories take a type arguments vector as first argument (independent
1640 // of whether the class is generic or not).
1641 type_arguments = &TypeArguments::ZoneHandle(Z, TypeArguments::null());
1642 }
1643 return type_arguments;
1644 }
1645
1646
1647 const Object& ConstantEvaluator::RunFunction(const Function& function,
1648 Arguments* kernel_arguments,
1649 const Instance* receiver,
1650 const TypeArguments* type_args) {
1651 // We do not support generic methods yet.
1652 ASSERT((receiver == NULL) || (type_args == NULL));
1653 intptr_t extra_arguments =
1654 (receiver != NULL ? 1 : 0) + (type_args != NULL ? 1 : 0);
1655
1656 // Build up arguments.
1657 const Array& arguments = Array::ZoneHandle(
1658 Z, Array::New(extra_arguments + kernel_arguments->count()));
1659 const Array& names =
1660 Array::ZoneHandle(Z, Array::New(kernel_arguments->named().length()));
1661 intptr_t pos = 0;
1662 if (receiver != NULL) {
1663 arguments.SetAt(pos++, *receiver);
1664 }
1665 if (type_args != NULL) {
1666 arguments.SetAt(pos++, *type_args);
1667 }
1668 for (intptr_t i = 0; i < kernel_arguments->positional().length(); i++) {
1669 EvaluateExpression(kernel_arguments->positional()[i]);
1670 arguments.SetAt(pos++, result_);
1671 }
1672 for (intptr_t i = 0; i < kernel_arguments->named().length(); i++) {
1673 NamedExpression* named_expression = kernel_arguments->named()[i];
1674 EvaluateExpression(named_expression->expression());
1675 arguments.SetAt(pos++, result_);
1676 names.SetAt(i, H.DartSymbol(named_expression->name()));
1677 }
1678 return RunFunction(function, arguments, names);
1679 }
1680
1681
1682 const Object& ConstantEvaluator::RunFunction(const Function& function,
1683 const Array& arguments,
1684 const Array& names) {
1685 const Array& args_descriptor =
1686 Array::Handle(Z, ArgumentsDescriptor::New(arguments.Length(), names));
1687 const Object& result = Object::Handle(
1688 Z, DartEntry::InvokeFunction(function, arguments, args_descriptor));
1689 if (result.IsError()) {
1690 H.ReportError(Error::Cast(result), "error evaluating constant constructor");
1691 }
1692 return result;
1693 }
1694
1695
1696 FlowGraphBuilder::FlowGraphBuilder(
1697 TreeNode* node, ParsedFunction* parsed_function,
1698 const ZoneGrowableArray<const ICData*>& ic_data_array,
1699 InlineExitCollector* exit_collector, intptr_t osr_id,
1700 intptr_t first_block_id)
1701 : zone_(Thread::Current()->zone()),
1702 translation_helper_(Thread::Current(), zone_,
1703 Thread::Current()->isolate()),
1704 node_(node),
1705 parsed_function_(parsed_function),
1706 osr_id_(osr_id),
1707 ic_data_array_(ic_data_array),
1708 exit_collector_(exit_collector),
1709 next_block_id_(first_block_id),
1710 next_function_id_(0),
1711 context_depth_(0),
1712 loop_depth_(0),
1713 try_depth_(0),
1714 catch_depth_(0),
1715 for_in_depth_(0),
1716 stack_(NULL),
1717 pending_argument_count_(0),
1718 graph_entry_(NULL),
1719 scopes_(NULL),
1720 breakable_block_(NULL),
1721 switch_block_(NULL),
1722 try_finally_block_(NULL),
1723 try_catch_block_(NULL),
1724 next_used_try_index_(0),
1725 catch_block_(NULL),
1726 type_translator_(&translation_helper_, &active_class_),
1727 constant_evaluator_(this, zone_, &translation_helper_,
1728 &type_translator_) {}
1729
1730
1731 FlowGraphBuilder::~FlowGraphBuilder() {}
1732
1733
1734 Fragment FlowGraphBuilder::TranslateFinallyFinalizers(
1735 TryFinallyBlock* outer_finally, intptr_t target_context_depth) {
1736 TryFinallyBlock* const saved_block = try_finally_block_;
1737 const intptr_t saved_depth = context_depth_;
1738 const intptr_t saved_try_depth = try_depth_;
1739
1740 Fragment instructions;
1741
1742 // While translating the body of a finalizer we need to set the try-finally
1743 // block which is active when translating the body.
1744 while (try_finally_block_ != outer_finally) {
1745 // Set correct try depth (in case there are nested try statements).
1746 try_depth_ = try_finally_block_->try_depth();
1747
1748 // Potentially restore the context to what is expected for the finally
1749 // block.
1750 instructions += AdjustContextTo(try_finally_block_->context_depth());
1751
1752 Statement* finalizer = try_finally_block_->finalizer();
1753 try_finally_block_ = try_finally_block_->outer();
1754
1755 // This will potentially have exceptional cases as described in
1756 // [VisitTryFinally] and will handle them.
1757 instructions += TranslateStatement(finalizer);
1758
1759 // We only need to make sure that if the finalizer ended normally, we
1760 // continue towards the next outer try-finally.
1761 if (!instructions.is_open()) break;
1762 }
1763
1764 if (instructions.is_open() && target_context_depth != -1) {
1765 // A target context depth of -1 indicates that we the code after this
1766 // will not care about the context chain so we can leave it any way we
1767 // want after the last finalizer. That is used when returning.
1768 instructions += AdjustContextTo(target_context_depth);
1769 }
1770
1771 try_finally_block_ = saved_block;
1772 context_depth_ = saved_depth;
1773 try_depth_ = saved_try_depth;
1774
1775 return instructions;
1776 }
1777
1778
1779 Fragment FlowGraphBuilder::EnterScope(TreeNode* node, bool* new_context) {
1780 Fragment instructions;
1781 const intptr_t context_size =
1782 scopes_->scopes.Lookup(node)->num_context_variables();
1783 if (context_size > 0) {
1784 instructions += PushContext(context_size);
1785 instructions += Drop();
1786 if (new_context != NULL) {
1787 *new_context = true;
1788 }
1789 }
1790 return instructions;
1791 }
1792
1793
1794 Fragment FlowGraphBuilder::ExitScope(TreeNode* node) {
1795 Fragment instructions;
1796 const intptr_t context_size =
1797 scopes_->scopes.Lookup(node)->num_context_variables();
1798 if (context_size > 0) {
1799 instructions += PopContext();
1800 }
1801 return instructions;
1802 }
1803
1804
1805 Fragment FlowGraphBuilder::LoadContextAt(int depth) {
1806 intptr_t delta = context_depth_ - depth;
1807 ASSERT(delta >= 0);
1808 Fragment instructions = LoadLocal(parsed_function_->current_context_var());
1809 while (delta-- > 0) {
1810 instructions += LoadField(Context::parent_offset());
1811 }
1812 return instructions;
1813 }
1814
1815
1816 Fragment FlowGraphBuilder::AdjustContextTo(int depth) {
1817 ASSERT(depth <= context_depth_ && depth >= 0);
1818 Fragment instructions;
1819 if (depth < context_depth_) {
1820 instructions += LoadContextAt(depth);
1821 instructions += StoreLocal(parsed_function_->current_context_var());
1822 instructions += Drop();
1823 context_depth_ = depth;
1824 }
1825 return instructions;
1826 }
1827
1828
1829 Fragment FlowGraphBuilder::PushContext(int size) {
1830 ASSERT(size > 0);
1831 Fragment instructions = AllocateContext(size);
1832 LocalVariable* context = MakeTemporary();
1833 instructions += LoadLocal(context);
1834 instructions += LoadLocal(parsed_function_->current_context_var());
1835 instructions += StoreInstanceField(Context::parent_offset());
1836 instructions += StoreLocal(parsed_function_->current_context_var());
1837 ++context_depth_;
1838 return instructions;
1839 }
1840
1841
1842 Fragment FlowGraphBuilder::PopContext() {
1843 return AdjustContextTo(context_depth_ - 1);
1844 }
1845
1846
1847 Fragment FlowGraphBuilder::LoadInstantiatorTypeArguments() {
1848 // TODO(27590): We could use `active_class_->IsGeneric()`.
1849 Fragment instructions;
1850 if (scopes_->type_arguments_variable != NULL) {
1851 #ifdef DEBUG
1852 Function& function =
1853 Function::Handle(Z, parsed_function_->function().raw());
1854 while (function.IsClosureFunction()) {
1855 function = function.parent_function();
1856 }
1857 ASSERT(function.IsFactory());
1858 #endif
1859 instructions += LoadLocal(scopes_->type_arguments_variable);
1860 } else if (scopes_->this_variable != NULL &&
1861 active_class_.kernel_class != NULL &&
1862 active_class_.kernel_class->type_parameters().length() > 0) {
1863 ASSERT(!parsed_function_->function().IsFactory());
1864 intptr_t type_arguments_field_offset =
1865 active_class_.klass->type_arguments_field_offset();
1866 ASSERT(type_arguments_field_offset != dart::Class::kNoTypeArguments);
1867
1868 instructions += LoadLocal(scopes_->this_variable);
1869 instructions += LoadField(type_arguments_field_offset);
1870 } else {
1871 instructions += NullConstant();
1872 }
1873 return instructions;
1874 }
1875
1876
1877 Fragment FlowGraphBuilder::InstantiateTypeArguments(
1878 const TypeArguments& type_arguments) {
1879 InstantiateTypeArgumentsInstr* instr = new (Z) InstantiateTypeArgumentsInstr(
1880 TokenPosition::kNoSource, type_arguments, *active_class_.klass, Pop());
1881 Push(instr);
1882 return Fragment(instr);
1883 }
1884
1885
1886 Fragment FlowGraphBuilder::TranslateInstantiatedTypeArguments(
1887 const TypeArguments& type_arguments) {
1888 Fragment instructions;
1889
1890 if (type_arguments.IsNull() || type_arguments.IsInstantiated()) {
1891 // There are no type references to type parameters so we can just take it.
1892 instructions += Constant(type_arguments);
1893 } else {
1894 // The [type_arguments] vector contains a type reference to a type
1895 // parameter we need to resolve it.
1896 const bool use_instantiator =
1897 type_arguments.IsUninstantiatedIdentity() ||
1898 type_arguments.CanShareInstantiatorTypeArguments(*active_class_.klass);
1899 if (use_instantiator) {
1900 // If the instantiator type arguments are just passed on, we don't need to
1901 // resolve the type parameters.
1902 //
1903 // This is for example the case here:
1904 // class Foo<T> {
1905 // newList() => new List<T>();
1906 // }
1907 // We just use the type argument vector from the [Foo] object and pass it
1908 // directly to the `new List<T>()` factory constructor.
1909 instructions += LoadInstantiatorTypeArguments();
1910 } else {
1911 // Otherwise we need to resolve [TypeParameterType]s in the type
1912 // expression based on the current instantiator type argument vector.
1913 instructions += LoadInstantiatorTypeArguments();
1914 instructions += InstantiateTypeArguments(type_arguments);
1915 }
1916 }
1917 return instructions;
1918 }
1919
1920
1921 Fragment FlowGraphBuilder::AllocateContext(int size) {
1922 AllocateContextInstr* allocate =
1923 new (Z) AllocateContextInstr(TokenPosition::kNoSource, size);
1924 Push(allocate);
1925 return Fragment(allocate);
1926 }
1927
1928
1929 Fragment FlowGraphBuilder::AllocateObject(const dart::Class& klass,
1930 intptr_t argument_count) {
1931 ArgumentArray arguments = GetArguments(argument_count);
1932 AllocateObjectInstr* allocate =
1933 new (Z) AllocateObjectInstr(TokenPosition::kNoSource, klass, arguments);
1934 Push(allocate);
1935 return Fragment(allocate);
1936 }
1937
1938
1939 Fragment FlowGraphBuilder::AllocateObject(const dart::Class& klass,
1940 const Function& closure_function) {
1941 ArgumentArray arguments = new (Z) ZoneGrowableArray<PushArgumentInstr*>(Z, 0);
1942 AllocateObjectInstr* allocate =
1943 new (Z) AllocateObjectInstr(TokenPosition::kNoSource, klass, arguments);
1944 allocate->set_closure_function(closure_function);
1945 Push(allocate);
1946 return Fragment(allocate);
1947 }
1948
1949
1950 Fragment FlowGraphBuilder::BooleanNegate() {
1951 BooleanNegateInstr* negate = new (Z) BooleanNegateInstr(Pop());
1952 Push(negate);
1953 return Fragment(negate);
1954 }
1955
1956
1957 Fragment FlowGraphBuilder::StrictCompare(Token::Kind kind,
1958 bool number_check /* = false */) {
1959 Value* right = Pop();
1960 Value* left = Pop();
1961 StrictCompareInstr* compare = new (Z) StrictCompareInstr(
1962 TokenPosition::kNoSource, kind, left, right, number_check);
1963 Push(compare);
1964 return Fragment(compare);
1965 }
1966
1967
1968 Fragment FlowGraphBuilder::BranchIfTrue(TargetEntryInstr** then_entry,
1969 TargetEntryInstr** otherwise_entry,
1970 bool negate) {
1971 Fragment instructions = Constant(Bool::True());
1972 return instructions + BranchIfEqual(then_entry, otherwise_entry, negate);
1973 }
1974
1975
1976 Fragment FlowGraphBuilder::BranchIfNull(TargetEntryInstr** then_entry,
1977 TargetEntryInstr** otherwise_entry,
1978 bool negate) {
1979 Fragment instructions = NullConstant();
1980 return instructions + BranchIfEqual(then_entry, otherwise_entry, negate);
1981 }
1982
1983 Fragment FlowGraphBuilder::BranchIfEqual(TargetEntryInstr** then_entry,
1984 TargetEntryInstr** otherwise_entry,
1985 bool negate) {
1986 Value* right_value = Pop();
1987 Value* left_value = Pop();
1988 StrictCompareInstr* compare = new (Z) StrictCompareInstr(
1989 TokenPosition::kNoSource, negate ? Token::kNE_STRICT : Token::kEQ_STRICT,
1990 left_value, right_value, false);
1991 BranchInstr* branch = new (Z) BranchInstr(compare);
1992 *then_entry = *branch->true_successor_address() = BuildTargetEntry();
1993 *otherwise_entry = *branch->false_successor_address() = BuildTargetEntry();
1994 return Fragment(branch).closed();
1995 }
1996
1997
1998 Fragment FlowGraphBuilder::BranchIfStrictEqual(
1999 TargetEntryInstr** then_entry, TargetEntryInstr** otherwise_entry) {
2000 Value* rhs = Pop();
2001 Value* lhs = Pop();
2002 StrictCompareInstr* compare = new (Z) StrictCompareInstr(
2003 TokenPosition::kNoSource, Token::kEQ_STRICT, lhs, rhs, false);
2004 BranchInstr* branch = new (Z) BranchInstr(compare);
2005 *then_entry = *branch->true_successor_address() = BuildTargetEntry();
2006 *otherwise_entry = *branch->false_successor_address() = BuildTargetEntry();
2007 return Fragment(branch).closed();
2008 }
2009
2010
2011 Fragment FlowGraphBuilder::CatchBlockEntry(const Array& handler_types,
2012 intptr_t handler_index) {
2013 ASSERT(CurrentException()->is_captured() ==
2014 CurrentStackTrace()->is_captured());
2015 const bool should_restore_closure_context =
2016 CurrentException()->is_captured() ||
2017 CurrentCatchContext()->is_captured();
2018 CatchBlockEntryInstr* entry = new (Z) CatchBlockEntryInstr(
2019 AllocateBlockId(), CurrentTryIndex(), graph_entry_, handler_types,
2020 handler_index, *CurrentException(), *CurrentStackTrace(),
2021 /* needs_stacktrace = */ true, Thread::Current()->GetNextDeoptId(),
2022 should_restore_closure_context);
2023 graph_entry_->AddCatchEntry(entry);
2024 Fragment instructions(entry);
2025
2026 // :saved_try_context_var can be captured in the context of
2027 // of the closure, in this case CatchBlockEntryInstr restores
2028 // :current_context_var to point to closure context in the
2029 // same way as normal function prologue does.
2030 // Update current context depth to reflect that.
2031 const intptr_t saved_context_depth = context_depth_;
2032 ASSERT(!CurrentCatchContext()->is_captured() ||
2033 CurrentCatchContext()->owner()->context_level() == 0);
2034 context_depth_ = 0;
2035 instructions += LoadLocal(CurrentCatchContext());
2036 instructions += StoreLocal(parsed_function_->current_context_var());
2037 instructions += Drop();
2038 context_depth_ = saved_context_depth;
2039
2040 return instructions;
2041 }
2042
2043
2044 Fragment FlowGraphBuilder::TryCatch(int try_handler_index) {
2045 // The body of the try needs to have it's own block in order to get a new try
2046 // index.
2047 //
2048 // => We therefore create a block for the body (fresh try index) and another
2049 // join block (with current try index).
2050 Fragment body;
2051 JoinEntryInstr* entry =
2052 new (Z) JoinEntryInstr(AllocateBlockId(), try_handler_index);
2053 body += LoadLocal(parsed_function_->current_context_var());
2054 body += StoreLocal(CurrentCatchContext());
2055 body += Drop();
2056 body += Goto(entry);
2057 return Fragment(body.entry, entry);
2058 }
2059
2060
2061 Fragment FlowGraphBuilder::CheckStackOverflowInPrologue() {
2062 if (IsInlining()) {
2063 // If we are inlining don't actually attach the stack check. We must still
2064 // create the stack check in order to allocate a deopt id.
2065 CheckStackOverflow();
2066 return Fragment();
2067 }
2068 return CheckStackOverflow();
2069 }
2070
2071
2072 Fragment FlowGraphBuilder::CheckStackOverflow() {
2073 return Fragment(
2074 new (Z) CheckStackOverflowInstr(TokenPosition::kNoSource, loop_depth_));
2075 }
2076
2077
2078 Fragment FlowGraphBuilder::CloneContext() {
2079 LocalVariable* context_variable = parsed_function_->current_context_var();
2080
2081 Fragment instructions = LoadLocal(context_variable);
2082
2083 CloneContextInstr* clone_instruction =
2084 new (Z) CloneContextInstr(TokenPosition::kNoSource, Pop());
2085 instructions <<= clone_instruction;
2086 Push(clone_instruction);
2087
2088 instructions += StoreLocal(context_variable);
2089 instructions += Drop();
2090 return instructions;
2091 }
2092
2093
2094 Fragment FlowGraphBuilder::Constant(const Object& value) {
2095 ASSERT(value.IsNotTemporaryScopedHandle());
2096 ConstantInstr* constant = new (Z) ConstantInstr(value);
2097 Push(constant);
2098 return Fragment(constant);
2099 }
2100
2101
2102 Fragment FlowGraphBuilder::CreateArray() {
2103 Value* element_count = Pop();
2104 CreateArrayInstr* array = new (Z) CreateArrayInstr(TokenPosition::kNoSource,
2105 Pop(), // Element type.
2106 element_count);
2107 Push(array);
2108 return Fragment(array);
2109 }
2110
2111
2112 Fragment FlowGraphBuilder::Goto(JoinEntryInstr* destination) {
2113 return Fragment(new (Z) GotoInstr(destination)).closed();
2114 }
2115
2116
2117 Fragment FlowGraphBuilder::IntConstant(int64_t value) {
2118 return Fragment(
2119 Constant(Integer::ZoneHandle(Z, Integer::New(value, Heap::kOld))));
2120 }
2121
2122
2123 Fragment FlowGraphBuilder::InstanceCall(const dart::String& name,
2124 Token::Kind kind,
2125 intptr_t argument_count,
2126 intptr_t num_args_checked) {
2127 return InstanceCall(name, kind, argument_count, Array::null_array(),
2128 num_args_checked);
2129 }
2130
2131
2132 Fragment FlowGraphBuilder::InstanceCall(const dart::String& name,
2133 Token::Kind kind,
2134 intptr_t argument_count,
2135 const Array& argument_names,
2136 intptr_t num_args_checked) {
2137 ArgumentArray arguments = GetArguments(argument_count);
2138 InstanceCallInstr* call = new (Z)
2139 InstanceCallInstr(TokenPosition::kNoSource, name, kind, arguments,
2140 argument_names, num_args_checked, ic_data_array_);
2141 Push(call);
2142 return Fragment(call);
2143 }
2144
2145
2146 Fragment FlowGraphBuilder::ClosureCall(int argument_count,
2147 const Array& argument_names) {
2148 Value* function = Pop();
2149 ArgumentArray arguments = GetArguments(argument_count);
2150 ClosureCallInstr* call = new (Z) ClosureCallInstr(
2151 function, arguments, argument_names, TokenPosition::kNoSource);
2152 Push(call);
2153 return Fragment(call);
2154 }
2155
2156
2157 Fragment FlowGraphBuilder::ThrowException() {
2158 Fragment instructions;
2159 instructions += Drop();
2160 instructions +=
2161 Fragment(new (Z) ThrowInstr(TokenPosition::kNoSource)).closed();
2162 // Use it's side effect of leaving a constant on the stack (does not change
2163 // the graph).
2164 NullConstant();
2165
2166 pending_argument_count_ -= 1;
2167
2168 return instructions;
2169 }
2170
2171
2172 Fragment FlowGraphBuilder::RethrowException(int catch_try_index) {
2173 Fragment instructions;
2174 instructions += Drop();
2175 instructions += Drop();
2176 instructions +=
2177 Fragment(new (Z) ReThrowInstr(TokenPosition::kNoSource, catch_try_index))
2178 .closed();
2179 // Use it's side effect of leaving a constant on the stack (does not change
2180 // the graph).
2181 NullConstant();
2182
2183 pending_argument_count_ -= 2;
2184
2185 return instructions;
2186 }
2187
2188
2189 Fragment FlowGraphBuilder::LoadClassId() {
2190 LoadClassIdInstr* load = new (Z) LoadClassIdInstr(Pop());
2191 Push(load);
2192 return Fragment(load);
2193 }
2194
2195
2196 Fragment FlowGraphBuilder::LoadField(const dart::Field& field) {
2197 LoadFieldInstr* load = new (Z)
2198 LoadFieldInstr(Pop(), &field, AbstractType::ZoneHandle(Z, field.type()),
2199 TokenPosition::kNoSource);
2200 Push(load);
2201 return Fragment(load);
2202 }
2203
2204
2205 Fragment FlowGraphBuilder::LoadField(intptr_t offset, intptr_t class_id) {
2206 LoadFieldInstr* load = new (Z) LoadFieldInstr(
2207 Pop(), offset, AbstractType::ZoneHandle(Z), TokenPosition::kNoSource);
2208 load->set_result_cid(class_id);
2209 Push(load);
2210 return Fragment(load);
2211 }
2212
2213
2214 Fragment FlowGraphBuilder::LoadNativeField(MethodRecognizer::Kind kind,
2215 intptr_t offset, const Type& type,
2216 intptr_t class_id,
2217 bool is_immutable) {
2218 LoadFieldInstr* load =
2219 new (Z) LoadFieldInstr(Pop(), offset, type, TokenPosition::kNoSource);
2220 load->set_recognized_kind(kind);
2221 load->set_result_cid(class_id);
2222 load->set_is_immutable(is_immutable);
2223 Push(load);
2224 return Fragment(load);
2225 }
2226
2227
2228 Fragment FlowGraphBuilder::LoadLocal(LocalVariable* variable) {
2229 Fragment instructions;
2230 if (variable->is_captured()) {
2231 instructions += LoadContextAt(variable->owner()->context_level());
2232 instructions += LoadField(Context::variable_offset(variable->index()));
2233 } else {
2234 LoadLocalInstr* load =
2235 new (Z) LoadLocalInstr(*variable, TokenPosition::kNoSource);
2236 instructions <<= load;
2237 Push(load);
2238 }
2239 return instructions;
2240 }
2241
2242
2243 Fragment FlowGraphBuilder::InitStaticField(const dart::Field& field) {
2244 InitStaticFieldInstr* init = new (Z) InitStaticFieldInstr(Pop(), field);
2245 return Fragment(init);
2246 }
2247
2248
2249 Fragment FlowGraphBuilder::LoadStaticField() {
2250 LoadStaticFieldInstr* load =
2251 new (Z) LoadStaticFieldInstr(Pop(), TokenPosition::kNoSource);
2252 Push(load);
2253 return Fragment(load);
2254 }
2255
2256
2257 Fragment FlowGraphBuilder::NullConstant() {
2258 return Constant(Instance::ZoneHandle(Z, Instance::null()));
2259 }
2260
2261
2262 Fragment FlowGraphBuilder::NativeCall(const dart::String* name,
2263 const Function* function) {
2264 InlineBailout("kernel::FlowGraphBuilder::NativeCall");
2265 NativeCallInstr* call = new (Z) NativeCallInstr(
2266 name, function, FLAG_link_natives_lazily, TokenPosition::kNoSource);
2267 Push(call);
2268 return Fragment(call);
2269 }
2270
2271
2272 Fragment FlowGraphBuilder::PushArgument() {
2273 PushArgumentInstr* argument = new (Z) PushArgumentInstr(Pop());
2274 Push(argument);
2275
2276 argument->set_temp_index(argument->temp_index() - 1);
2277 ++pending_argument_count_;
2278
2279 return Fragment(argument);
2280 }
2281
2282
2283 Fragment FlowGraphBuilder::Return() {
2284 Value* value = Pop();
2285 ASSERT(stack_ == NULL);
2286 ReturnInstr* return_instr =
2287 new (Z) ReturnInstr(TokenPosition::kNoSource, value);
2288 if (exit_collector_ != NULL) exit_collector_->AddExit(return_instr);
2289 return Fragment(return_instr).closed();
2290 }
2291
2292
2293 Fragment FlowGraphBuilder::StaticCall(const Function& target,
2294 intptr_t argument_count) {
2295 return StaticCall(target, argument_count, Array::null_array());
2296 }
2297
2298
2299 static intptr_t GetResultCidOfListFactory(Zone* zone,
2300 const Function& function,
2301 intptr_t argument_count) {
2302 if (!function.IsFactory()) {
2303 return kDynamicCid;
2304 }
2305
2306 const dart::Class& owner = dart::Class::Handle(zone, function.Owner());
2307 if ((owner.library() != dart::Library::CoreLibrary()) &&
2308 (owner.library() != dart::Library::TypedDataLibrary())) {
2309 return kDynamicCid;
2310 }
2311
2312 if ((owner.Name() == Symbols::List().raw()) &&
2313 (function.name() == Symbols::ListFactory().raw())) {
2314 ASSERT(argument_count == 1 || argument_count == 2);
2315 return (argument_count == 1) ? kGrowableObjectArrayCid : kArrayCid;
2316 }
2317 return FactoryRecognizer::ResultCid(function);
2318 }
2319
2320
2321 Fragment FlowGraphBuilder::StaticCall(const Function& target,
2322 intptr_t argument_count,
2323 const Array& argument_names) {
2324 ArgumentArray arguments = GetArguments(argument_count);
2325 StaticCallInstr* call =
2326 new (Z) StaticCallInstr(TokenPosition::kNoSource, target, argument_names,
2327 arguments, ic_data_array_);
2328 const intptr_t list_cid =
2329 GetResultCidOfListFactory(Z, target, argument_count);
2330 if (list_cid != kDynamicCid) {
2331 call->set_result_cid(list_cid);
2332 call->set_is_known_list_constructor(true);
2333 } else if (target.recognized_kind() != MethodRecognizer::kUnknown) {
2334 call->set_result_cid(MethodRecognizer::ResultCid(target));
2335 }
2336 Push(call);
2337 return Fragment(call);
2338 }
2339
2340
2341 Fragment FlowGraphBuilder::StoreIndexed(intptr_t class_id) {
2342 Value* value = Pop();
2343 Value* index = Pop();
2344 // TODO(27590): Omit store barrier when possible (e.g., storing
2345 // some constants).
2346 StoreIndexedInstr* store = new (Z) StoreIndexedInstr(
2347 Pop(), // Array.
2348 index, value, kEmitStoreBarrier, Instance::ElementSizeFor(class_id),
2349 class_id, Thread::kNoDeoptId, TokenPosition::kNoSource);
2350 Push(store);
2351 return Fragment(store);
2352 }
2353
2354
2355 Fragment FlowGraphBuilder::StoreInstanceField(const dart::Field& field) {
2356 Value* value = Pop();
2357 // TODO(27590): Omit store barrier when possible (e.g., storing
2358 // some constants).
2359 StoreInstanceFieldInstr* store = new (Z) StoreInstanceFieldInstr(
2360 field, Pop(), value, kEmitStoreBarrier, TokenPosition::kNoSource);
2361 return Fragment(store);
2362 }
2363
2364
2365 Fragment FlowGraphBuilder::StoreInstanceField(intptr_t offset) {
2366 Value* value = Pop();
2367 StoreInstanceFieldInstr* store = new (Z) StoreInstanceFieldInstr(
2368 offset, Pop(), value, kEmitStoreBarrier, TokenPosition::kNoSource);
2369 return Fragment(store);
2370 }
2371
2372
2373 Fragment FlowGraphBuilder::StoreLocal(LocalVariable* variable) {
2374 Fragment instructions;
2375 if (variable->is_captured()) {
2376 LocalVariable* value = MakeTemporary();
2377 instructions += LoadContextAt(variable->owner()->context_level());
2378 instructions += LoadLocal(value);
2379 instructions +=
2380 StoreInstanceField(Context::variable_offset(variable->index()));
2381 } else {
2382 StoreLocalInstr* store =
2383 new (Z) StoreLocalInstr(*variable, Pop(), TokenPosition::kNoSource);
2384 instructions <<= store;
2385 Push(store);
2386 }
2387 return instructions;
2388 }
2389
2390
2391 Fragment FlowGraphBuilder::StoreStaticField(const dart::Field& field) {
2392 return Fragment(
2393 new (Z) StoreStaticFieldInstr(field, Pop(), TokenPosition::kNoSource));
2394 }
2395
2396
2397 Fragment FlowGraphBuilder::StringInterpolate() {
2398 Value* array = Pop();
2399 StringInterpolateInstr* interpolate =
2400 new (Z) StringInterpolateInstr(array, TokenPosition::kNoSource);
2401 Push(interpolate);
2402 return Fragment(interpolate);
2403 }
2404
2405
2406 Fragment FlowGraphBuilder::ThrowTypeError() {
2407 const dart::Class& klass = dart::Class::ZoneHandle(
2408 Z, dart::Library::LookupCoreClass(Symbols::TypeError()));
2409 ASSERT(!klass.IsNull());
2410 const dart::Function& constructor = dart::Function::ZoneHandle(
2411 Z,
2412 klass.LookupConstructorAllowPrivate(H.DartSymbol("_TypeError._create")));
2413 ASSERT(!constructor.IsNull());
2414
2415 const dart::String& url = H.DartString(
2416 parsed_function_->function().ToLibNamePrefixedQualifiedCString(),
2417 Heap::kOld);
2418
2419 Fragment instructions;
2420
2421 // Create instance of _FallThroughError
2422 instructions += AllocateObject(klass, 0);
2423 LocalVariable* instance = MakeTemporary();
2424
2425 // Call _AssertionError._create constructor.
2426 instructions += LoadLocal(instance);
2427 instructions += PushArgument(); // this
2428
2429 instructions += Constant(url);
2430 instructions += PushArgument(); // url
2431
2432 instructions += NullConstant();
2433 instructions += PushArgument(); // line
2434
2435 instructions += IntConstant(0);
2436 instructions += PushArgument(); // column
2437
2438 instructions += Constant(H.DartSymbol("Malformed type."));
2439 instructions += PushArgument(); // message
2440
2441 instructions += StaticCall(constructor, 5);
2442 instructions += Drop();
2443
2444 // Throw the exception
2445 instructions += PushArgument();
2446 instructions += ThrowException();
2447
2448 return instructions;
2449 }
2450
2451
2452 Fragment FlowGraphBuilder::ThrowNoSuchMethodError() {
2453 const dart::Class& klass = dart::Class::ZoneHandle(
2454 Z, dart::Library::LookupCoreClass(Symbols::NoSuchMethodError()));
2455 ASSERT(!klass.IsNull());
2456 const dart::Function& throw_function = dart::Function::ZoneHandle(
2457 Z, klass.LookupStaticFunctionAllowPrivate(Symbols::ThrowNew()));
2458 ASSERT(!throw_function.IsNull());
2459
2460 Fragment instructions;
2461
2462 // Call NoSuchMethodError._throwNew static function.
2463 instructions += NullConstant();
2464 instructions += PushArgument(); // receiver
2465
2466 instructions += Constant(H.DartString("<unknown>", Heap::kOld));
2467 instructions += PushArgument(); // memberName
2468
2469 instructions += IntConstant(-1);
2470 instructions += PushArgument(); // invocation_type
2471
2472 instructions += NullConstant();
2473 instructions += PushArgument(); // arguments
2474
2475 instructions += NullConstant();
2476 instructions += PushArgument(); // argumentNames
2477
2478 instructions += NullConstant();
2479 instructions += PushArgument(); // existingArgumentNames
2480
2481 instructions += StaticCall(throw_function, 6);
2482 // Leave "result" on the stack since callers expect it to be there (even
2483 // though the function will result in an exception).
2484
2485 return instructions;
2486 }
2487
2488
2489 dart::RawFunction* FlowGraphBuilder::LookupMethodByMember(
2490 Member* target, const dart::String& method_name) {
2491 Class* kernel_klass = Class::Cast(target->parent());
2492 dart::Class& klass =
2493 dart::Class::Handle(Z, H.LookupClassByKernelClass(kernel_klass));
2494
2495 dart::RawFunction* function = klass.LookupFunctionAllowPrivate(method_name);
2496 ASSERT(function != Object::null());
2497 return function;
2498 }
2499
2500
2501 LocalVariable* FlowGraphBuilder::MakeTemporary() {
2502 char name[64];
2503 intptr_t index = stack_->definition()->temp_index();
2504 OS::SNPrint(name, 64, ":temp%" Pd, index);
2505 LocalVariable* variable = new (Z) LocalVariable(
2506 TokenPosition::kNoSource, H.DartSymbol(name), Object::dynamic_type());
2507 // Set the index relative to the base of the expression stack including
2508 // outgoing arguments.
2509 variable->set_index(parsed_function_->first_stack_local_index() -
2510 parsed_function_->num_stack_locals() -
2511 pending_argument_count_ - index);
2512
2513 // The value has uses as if it were a local variable. Mark the definition
2514 // as used so that its temp index will not be cleared (causing it to never
2515 // be materialized in the expression stack).
2516 stack_->definition()->set_ssa_temp_index(0);
2517
2518 return variable;
2519 }
2520
2521
2522 intptr_t FlowGraphBuilder::CurrentTryIndex() {
2523 if (try_catch_block_ == NULL) {
2524 return CatchClauseNode::kInvalidTryIndex;
2525 } else {
2526 return try_catch_block_->TryIndex();
2527 }
2528 }
2529
2530
2531 dart::LocalVariable* FlowGraphBuilder::LookupVariable(
2532 VariableDeclaration* var) {
2533 LocalVariable* local = scopes_->locals.Lookup(var);
2534 ASSERT(local != NULL);
2535 return local;
2536 }
2537
2538
2539 void FlowGraphBuilder::SetTempIndex(Definition* definition) {
2540 definition->set_temp_index(
2541 stack_ == NULL ? 0 : stack_->definition()->temp_index() + 1);
2542 }
2543
2544
2545 void FlowGraphBuilder::Push(Definition* definition) {
2546 SetTempIndex(definition);
2547 Value::AddToList(new (Z) Value(definition), &stack_);
2548 }
2549
2550
2551 Value* FlowGraphBuilder::Pop() {
2552 ASSERT(stack_ != NULL);
2553 Value* value = stack_;
2554 stack_ = value->next_use();
2555 if (stack_ != NULL) stack_->set_previous_use(NULL);
2556
2557 value->set_next_use(NULL);
2558 value->set_previous_use(NULL);
2559 value->definition()->ClearSSATempIndex();
2560 return value;
2561 }
2562
2563
2564 Fragment FlowGraphBuilder::Drop() {
2565 ASSERT(stack_ != NULL);
2566 Fragment instructions;
2567 Definition* definition = stack_->definition();
2568 // The SSA renaming implementation doesn't like [LoadLocal]s without a
2569 // tempindex.
2570 if (definition->HasSSATemp() || definition->IsLoadLocal()) {
2571 instructions <<= new (Z) DropTempsInstr(1, NULL);
2572 } else {
2573 definition->ClearTempIndex();
2574 }
2575
2576 Pop();
2577 return instructions;
2578 }
2579
2580
2581 // TODO(27590): This method should be shared with
2582 // runtime/vm/object.cc:RecognizeArithmeticOp.
2583 Token::Kind FlowGraphBuilder::MethodKind(const dart::String& name) {
2584 ASSERT(name.IsSymbol());
2585 if (name.raw() == Symbols::Plus().raw()) {
2586 return Token::kADD;
2587 } else if (name.raw() == Symbols::Minus().raw()) {
2588 return Token::kSUB;
2589 } else if (name.raw() == Symbols::Star().raw()) {
2590 return Token::kMUL;
2591 } else if (name.raw() == Symbols::Slash().raw()) {
2592 return Token::kDIV;
2593 } else if (name.raw() == Symbols::TruncDivOperator().raw()) {
2594 return Token::kTRUNCDIV;
2595 } else if (name.raw() == Symbols::Percent().raw()) {
2596 return Token::kMOD;
2597 } else if (name.raw() == Symbols::BitOr().raw()) {
2598 return Token::kBIT_OR;
2599 } else if (name.raw() == Symbols::Ampersand().raw()) {
2600 return Token::kBIT_AND;
2601 } else if (name.raw() == Symbols::Caret().raw()) {
2602 return Token::kBIT_XOR;
2603 } else if (name.raw() == Symbols::LeftShiftOperator().raw()) {
2604 return Token::kSHL;
2605 } else if (name.raw() == Symbols::RightShiftOperator().raw()) {
2606 return Token::kSHR;
2607 } else if (name.raw() == Symbols::Tilde().raw()) {
2608 return Token::kBIT_NOT;
2609 } else if (name.raw() == Symbols::UnaryMinus().raw()) {
2610 return Token::kNEGATE;
2611 } else if (name.raw() == Symbols::EqualOperator().raw()) {
2612 return Token::kEQ;
2613 } else if (name.raw() == Symbols::Token(Token::kNE).raw()) {
2614 return Token::kNE;
2615 } else if (name.raw() == Symbols::LAngleBracket().raw()) {
2616 return Token::kLT;
2617 } else if (name.raw() == Symbols::RAngleBracket().raw()) {
2618 return Token::kGT;
2619 } else if (name.raw() == Symbols::LessEqualOperator().raw()) {
2620 return Token::kLTE;
2621 } else if (name.raw() == Symbols::GreaterEqualOperator().raw()) {
2622 return Token::kGTE;
2623 } else if (dart::Field::IsGetterName(name)) {
2624 return Token::kGET;
2625 } else if (dart::Field::IsSetterName(name)) {
2626 return Token::kSET;
2627 }
2628 return Token::kILLEGAL;
2629 }
2630
2631
2632 void FlowGraphBuilder::InlineBailout(const char* reason) {
2633 bool is_inlining = exit_collector_ != NULL;
2634 if (is_inlining) {
2635 parsed_function_->function().set_is_inlinable(false);
2636 parsed_function_->Bailout("kernel::FlowGraphBuilder", reason);
2637 }
2638 }
2639
2640
2641 FlowGraph* FlowGraphBuilder::BuildGraph() {
2642 const dart::Function& function = parsed_function_->function();
2643
2644 if (function.IsConstructorClosureFunction()) return NULL;
2645
2646 dart::Class& klass =
2647 dart::Class::Handle(zone_, parsed_function_->function().Owner());
2648
2649 // Find out if there is an enclosing kernel class (which will be used to
2650 // resolve type parameters).
2651 Class* kernel_klass = NULL;
2652 dart::Function& topmost = dart::Function::Handle(Z, function.raw());
2653 while (topmost.parent_function() != Object::null()) {
2654 topmost = topmost.parent_function();
2655 }
2656 TreeNode* topmost_node = static_cast<TreeNode*>(topmost.kernel_function());
2657 if (topmost_node != NULL) {
2658 // Going up the closure->parent chain needs to result in a Procedure or
2659 // Constructor.
2660 TreeNode* parent = NULL;
2661 if (topmost_node->IsProcedure()) {
2662 parent = Procedure::Cast(topmost_node)->parent();
2663 } else if (topmost_node->IsConstructor()) {
2664 parent = Constructor::Cast(topmost_node)->parent();
2665 } else if (topmost_node->IsField()) {
2666 parent = Field::Cast(topmost_node)->parent();
2667 }
2668 if (parent != NULL && parent->IsClass()) kernel_klass = Class::Cast(parent);
2669 }
2670
2671 // Mark that we are using [klass]/[kernell_klass] as active class. Resolving
2672 // of type parameters will get resolved via [kernell_klass] unless we are
2673 // nested inside a static factory in which case we will use [member].
2674 ActiveClassScope active_class_scope(&active_class_, kernel_klass, &klass);
2675 Member* member = topmost_node != NULL && topmost_node->IsMember()
2676 ? Member::Cast(topmost_node)
2677 : NULL;
2678 ActiveMemberScope active_member(&active_class_, member);
2679
2680 // The IR builder will create its own local variables and scopes, and it
2681 // will not need an AST. The code generator will assume that there is a
2682 // local variable stack slot allocated for the current context and (I
2683 // think) that the runtime will expect it to be at a fixed offset which
2684 // requires allocating an unused expression temporary variable.
2685 scopes_ = parsed_function_->EnsureKernelScopes();
2686
2687 switch (function.kind()) {
2688 case RawFunction::kClosureFunction:
2689 case RawFunction::kRegularFunction:
2690 case RawFunction::kGetterFunction:
2691 case RawFunction::kSetterFunction: {
2692 FunctionNode* kernel_function = node_->IsProcedure()
2693 ? Procedure::Cast(node_)->function()
2694 : FunctionNode::Cast(node_);
2695 ActiveFunctionScope active_function_scope(&active_class_,
2696 kernel_function);
2697 return function.IsImplicitClosureFunction()
2698 ? BuildGraphOfImplicitClosureFunction(kernel_function,
2699 function)
2700 : BuildGraphOfFunction(kernel_function);
2701 }
2702 case RawFunction::kConstructor: {
2703 bool is_factory = function.IsFactory();
2704 if (is_factory) {
2705 Procedure* procedure = Procedure::Cast(node_);
2706 FunctionNode* function = procedure->function();
2707 ActiveFunctionScope active_function_scope(&active_class_, function);
2708 return BuildGraphOfFunction(function, NULL);
2709 } else {
2710 Constructor* constructor = Constructor::Cast(node_);
2711 FunctionNode* function = constructor->function();
2712 ActiveFunctionScope active_function_scope(&active_class_, function);
2713 return BuildGraphOfFunction(function, constructor);
2714 }
2715 }
2716 case RawFunction::kImplicitGetter:
2717 case RawFunction::kImplicitStaticFinalGetter:
2718 case RawFunction::kImplicitSetter: {
2719 Field* field = Field::Cast(node_);
2720 return IsStaticInitializer(function, Z)
2721 ? BuildGraphOfStaticFieldInitializer(field)
2722 : BuildGraphOfFieldAccessor(field, scopes_->setter_value);
2723 }
2724 case RawFunction::kMethodExtractor:
2725 return BuildGraphOfMethodExtractor(function);
2726 case RawFunction::kNoSuchMethodDispatcher:
2727 return BuildGraphOfNoSuchMethodDispatcher(function);
2728 case RawFunction::kInvokeFieldDispatcher:
2729 return BuildGraphOfInvokeFieldDispatcher(function);
2730 case RawFunction::kSignatureFunction:
2731 case RawFunction::kIrregexpFunction:
2732 break;
2733 }
2734 UNREACHABLE();
2735 return NULL;
2736 }
2737
2738
2739 FlowGraph* FlowGraphBuilder::BuildGraphOfFunction(FunctionNode* function,
2740 Constructor* constructor) {
2741 const Function& dart_function = parsed_function_->function();
2742 TargetEntryInstr* normal_entry = BuildTargetEntry();
2743 graph_entry_ = new (Z)
2744 GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId);
2745
2746 SetupDefaultParameterValues(function);
2747
2748 Fragment body;
2749 if (!dart_function.is_native()) body += CheckStackOverflowInPrologue();
2750 intptr_t context_size =
2751 parsed_function_->node_sequence()->scope()->num_context_variables();
2752 if (context_size > 0) {
2753 body += PushContext(context_size);
2754 LocalVariable* context = MakeTemporary();
2755
2756 // Copy captured parameters from the stack into the context.
2757 LocalScope* scope = parsed_function_->node_sequence()->scope();
2758 intptr_t parameter_count = dart_function.NumParameters();
2759 intptr_t parameter_index = parsed_function_->first_parameter_index();
2760 for (intptr_t i = 0; i < parameter_count; ++i, --parameter_index) {
2761 LocalVariable* variable = scope->VariableAt(i);
2762 if (variable->is_captured()) {
2763 // There is no LocalVariable describing the on-stack parameter so
2764 // create one directly.
2765 LocalVariable* parameter =
2766 new (Z) LocalVariable(TokenPosition::kNoSource,
2767 Symbols::TempParam(), Object::dynamic_type());
2768 parameter->set_index(parameter_index);
2769 // Mark the stack variable so it will be ignored by the code for
2770 // try/catch.
2771 parameter->set_is_captured_parameter(true);
2772
2773 // Copy the parameter from the stack to the context. Overwrite it
2774 // with a null constant on the stack so the original value is
2775 // eligible for garbage collection.
2776 body += LoadLocal(context);
2777 body += LoadLocal(parameter);
2778 body += StoreInstanceField(Context::variable_offset(variable->index()));
2779 body += NullConstant();
2780 body += StoreLocal(parameter);
2781 body += Drop();
2782 }
2783 }
2784 body += Drop(); // The context.
2785 }
2786 if (constructor != NULL) {
2787 // TODO(27590): Currently the [VariableDeclaration]s from the
2788 // initializers will be visible inside the entire body of the constructor.
2789 // We should make a separate scope for them.
2790 Class* kernel_klass = Class::Cast(constructor->parent());
2791 body += TranslateInitializers(kernel_klass, &constructor->initializers());
2792 }
2793
2794 // The specification defines the result of `a == b` to be:
2795 //
2796 // a) if either side is `null` then the result is `identical(a, b)`.
2797 // b) else the result is `a.operator==(b)`
2798 //
2799 // For user-defined implementations of `operator==` we need therefore
2800 // implement the handling of a).
2801 //
2802 // The default `operator==` implementation in `Object` is implemented in terms
2803 // of identical (which we assume here!) which means that case a) is actually
2804 // included in b). So we just use the normal implementation in the body.
2805 if ((dart_function.NumParameters() == 2) &&
2806 (dart_function.name() == Symbols::EqualOperator().raw()) &&
2807 (dart_function.Owner() != I->object_store()->object_class())) {
2808 LocalVariable* parameter =
2809 LookupVariable(function->positional_parameters()[0]);
2810
2811 TargetEntryInstr* null_entry;
2812 TargetEntryInstr* non_null_entry;
2813
2814 body += LoadLocal(parameter);
2815 body += BranchIfNull(&null_entry, &non_null_entry);
2816
2817 // The argument was `null` and the receiver is not the null class (we only
2818 // go into this branch for user-defined == operators) so we can return
2819 // false.
2820 Fragment null_fragment(null_entry);
2821 null_fragment += Constant(Bool::False());
2822 null_fragment += Return();
2823
2824 body = Fragment(body.entry, non_null_entry);
2825 }
2826
2827 if (dart_function.is_native()) {
2828 body += NativeFunctionBody(function, dart_function);
2829 } else if (function->body() != NULL) {
2830 body += TranslateStatement(function->body());
2831 }
2832 if (body.is_open()) {
2833 body += NullConstant();
2834 body += Return();
2835 }
2836
2837 // If functions body contains any yield points build switch statement that
2838 // selects a continuation point based on the value of :await_jump_var.
2839 if (!yield_continuations_.is_empty()) {
2840 // The code we are building will be executed right after we enter
2841 // the function and before any nested contexts are allocated.
2842 // Reset current context_depth_ to match this.
2843 intptr_t current_context_depth = context_depth_;
2844 context_depth_ = scopes_->yield_jump_variable->owner()->context_level();
2845
2846 // Prepend an entry corresponding to normal entry to the function.
2847 yield_continuations_.InsertAt(
2848 0, YieldContinuation(new (Z) DropTempsInstr(0, NULL),
2849 CatchClauseNode::kInvalidTryIndex));
2850 yield_continuations_[0].entry->LinkTo(body.entry);
2851
2852 // Build a switch statement.
2853 Fragment dispatch;
2854
2855 // Load :await_jump_var into a temporary.
2856 dispatch += LoadLocal(scopes_->yield_jump_variable);
2857 dispatch += StoreLocal(scopes_->switch_variable);
2858 dispatch += Drop();
2859
2860 BlockEntryInstr* block = NULL;
2861 for (intptr_t i = 0; i < yield_continuations_.length(); i++) {
2862 if (i == 1) {
2863 // This is not a normal entry but a resumption. Restore
2864 // :current_context_var from :await_ctx_var.
2865 // Note: after this point context_depth_ does not match current context
2866 // depth so we should not access any local variables anymore.
2867 dispatch += LoadLocal(scopes_->yield_context_variable);
2868 dispatch += StoreLocal(parsed_function_->current_context_var());
2869 dispatch += Drop();
2870 }
2871 if (i == (yield_continuations_.length() - 1)) {
2872 // We reached the last possility, no need to build more ifs.
2873 // Coninue to the last continuation.
2874 // Note: continuations start with nop DropTemps instruction
2875 // which acts like an anchor, so we need to skip it.
2876 block->set_try_index(yield_continuations_[i].try_index);
2877 dispatch <<= yield_continuations_[i].entry->next();
2878 break;
2879 }
2880
2881 // Build comparison:
2882 //
2883 // if (:await_ctx_var == i) {
2884 // -> yield_continuations_[i]
2885 // } else ...
2886 //
2887 TargetEntryInstr* then;
2888 TargetEntryInstr* otherwise;
2889 dispatch += LoadLocal(scopes_->switch_variable);
2890 dispatch += IntConstant(i);
2891 dispatch += BranchIfStrictEqual(&then, &otherwise);
2892
2893 // True branch is linked to appropriate continuation point.
2894 // Note: continuations start with nop DropTemps instruction
2895 // which acts like an anchor, so we need to skip it.
2896 then->LinkTo(yield_continuations_[i].entry->next());
2897 then->set_try_index(yield_continuations_[i].try_index);
2898
2899 // False branch will contain the next comparison.
2900 dispatch = Fragment(dispatch.entry, otherwise);
2901 block = otherwise;
2902 }
2903 body = dispatch;
2904
2905 context_depth_ = current_context_depth;
2906 }
2907 normal_entry->LinkTo(body.entry);
2908
2909 return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1);
2910 }
2911
2912
2913 Fragment FlowGraphBuilder::NativeFunctionBody(FunctionNode* kernel_function,
2914 const Function& function) {
2915 ASSERT(function.is_native());
2916 // We explicitly build the graph for native functions in the same way that the
2917 // from-source backend does. We should find a way to have a single component
2918 // to build these graphs so that this code is not duplicated.
2919
2920 Fragment body;
2921 MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(function);
2922 switch (kind) {
2923 case MethodRecognizer::kObjectEquals:
2924 body += LoadLocal(scopes_->this_variable);
2925 body += LoadLocal(
2926 LookupVariable(kernel_function->positional_parameters()[0]));
2927 body += StrictCompare(Token::kEQ_STRICT);
2928 break;
2929 case MethodRecognizer::kStringBaseLength:
2930 case MethodRecognizer::kStringBaseIsEmpty:
2931 // Depending on FLAG_support_externalizable_strings, treat string length
2932 // loads as mutable so that the class check that precedes them will not be
2933 // hoisted. This is unsafe because string externalization can change the
2934 // class.
2935 body += LoadLocal(scopes_->this_variable);
2936 body += LoadNativeField(MethodRecognizer::kStringBaseLength,
2937 dart::String::length_offset(),
2938 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid,
2939 !FLAG_support_externalizable_strings);
2940 if (kind == MethodRecognizer::kStringBaseIsEmpty) {
2941 body += IntConstant(0);
2942 body += StrictCompare(Token::kEQ_STRICT);
2943 }
2944 break;
2945 case MethodRecognizer::kGrowableArrayLength:
2946 body += LoadLocal(scopes_->this_variable);
2947 body += LoadNativeField(kind, GrowableObjectArray::length_offset(),
2948 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid);
2949 break;
2950 case MethodRecognizer::kObjectArrayLength:
2951 case MethodRecognizer::kImmutableArrayLength:
2952 body += LoadLocal(scopes_->this_variable);
2953 body +=
2954 LoadNativeField(kind, Array::length_offset(),
2955 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid, true);
2956 break;
2957 case MethodRecognizer::kTypedDataLength:
2958 body += LoadLocal(scopes_->this_variable);
2959 body +=
2960 LoadNativeField(kind, TypedData::length_offset(),
2961 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid, true);
2962 break;
2963 case MethodRecognizer::kClassIDgetID:
2964 body += LoadLocal(
2965 LookupVariable(kernel_function->positional_parameters()[0]));
2966 body += LoadClassId();
2967 break;
2968 case MethodRecognizer::kGrowableArrayCapacity:
2969 body += LoadLocal(scopes_->this_variable);
2970 body += LoadField(Array::data_offset(), kArrayCid);
2971 body += LoadNativeField(MethodRecognizer::kObjectArrayLength,
2972 Array::length_offset(),
2973 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid);
2974 break;
2975 case MethodRecognizer::kObjectArrayAllocate:
2976 body += LoadLocal(scopes_->type_arguments_variable);
2977 body += LoadLocal(
2978 LookupVariable(kernel_function->positional_parameters()[0]));
2979 body += CreateArray();
2980 break;
2981 case MethodRecognizer::kBigint_getDigits:
2982 body += LoadLocal(scopes_->this_variable);
2983 body += LoadNativeField(kind, Bigint::digits_offset(),
2984 Object::dynamic_type(), kTypedDataUint32ArrayCid);
2985 break;
2986 case MethodRecognizer::kBigint_getUsed:
2987 body += LoadLocal(scopes_->this_variable);
2988 body += LoadNativeField(kind, Bigint::used_offset(),
2989 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid);
2990 break;
2991 case MethodRecognizer::kLinkedHashMap_getIndex:
2992 body += LoadLocal(scopes_->this_variable);
2993 body += LoadNativeField(kind, LinkedHashMap::index_offset(),
2994 Object::dynamic_type(), kDynamicCid);
2995 break;
2996 case MethodRecognizer::kLinkedHashMap_setIndex:
2997 body += LoadLocal(scopes_->this_variable);
2998 body += LoadLocal(
2999 LookupVariable(kernel_function->positional_parameters()[0]));
3000 body += StoreInstanceField(LinkedHashMap::index_offset());
3001 body += NullConstant();
3002 break;
3003 case MethodRecognizer::kLinkedHashMap_getData:
3004 body += LoadLocal(scopes_->this_variable);
3005 body += LoadNativeField(kind, LinkedHashMap::data_offset(),
3006 Object::dynamic_type(), kArrayCid);
3007 break;
3008 case MethodRecognizer::kLinkedHashMap_setData:
3009 body += LoadLocal(scopes_->this_variable);
3010 body += LoadLocal(
3011 LookupVariable(kernel_function->positional_parameters()[0]));
3012 body += StoreInstanceField(LinkedHashMap::data_offset());
3013 body += NullConstant();
3014 break;
3015 case MethodRecognizer::kLinkedHashMap_getHashMask:
3016 body += LoadLocal(scopes_->this_variable);
3017 body += LoadNativeField(kind, LinkedHashMap::hash_mask_offset(),
3018 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid);
3019 break;
3020 case MethodRecognizer::kLinkedHashMap_setHashMask:
3021 body += LoadLocal(scopes_->this_variable);
3022 body += LoadLocal(
3023 LookupVariable(kernel_function->positional_parameters()[0]));
3024 // TODO(27590): This store does not need a store barrier.
3025 body += StoreInstanceField(LinkedHashMap::hash_mask_offset());
3026 body += NullConstant();
3027 break;
3028 case MethodRecognizer::kLinkedHashMap_getUsedData:
3029 body += LoadLocal(scopes_->this_variable);
3030 body += LoadNativeField(kind, LinkedHashMap::used_data_offset(),
3031 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid);
3032 break;
3033 case MethodRecognizer::kLinkedHashMap_setUsedData:
3034 body += LoadLocal(scopes_->this_variable);
3035 body += LoadLocal(
3036 LookupVariable(kernel_function->positional_parameters()[0]));
3037 // TODO(27590): This store does not need a store barrier.
3038 body += StoreInstanceField(LinkedHashMap::used_data_offset());
3039 body += NullConstant();
3040 break;
3041 case MethodRecognizer::kLinkedHashMap_getDeletedKeys:
3042 body += LoadLocal(scopes_->this_variable);
3043 body += LoadNativeField(kind, LinkedHashMap::deleted_keys_offset(),
3044 Type::ZoneHandle(Z, Type::SmiType()), kSmiCid);
3045 break;
3046 case MethodRecognizer::kLinkedHashMap_setDeletedKeys:
3047 body += LoadLocal(scopes_->this_variable);
3048 body += LoadLocal(
3049 LookupVariable(kernel_function->positional_parameters()[0]));
3050 // TODO(27590): This store does not need a store barrier.
3051 body += StoreInstanceField(LinkedHashMap::deleted_keys_offset());
3052 body += NullConstant();
3053 break;
3054 case MethodRecognizer::kBigint_getNeg:
3055 body += LoadLocal(scopes_->this_variable);
3056 body += LoadNativeField(kind, Bigint::neg_offset(),
3057 Type::ZoneHandle(Z, Type::BoolType()), kBoolCid);
3058 break;
3059 default: {
3060 dart::String& name = dart::String::ZoneHandle(Z, function.native_name());
3061 body += NativeCall(&name, &function);
3062 break;
3063 }
3064 }
3065 return body + Return();
3066 }
3067
3068
3069 FlowGraph* FlowGraphBuilder::BuildGraphOfFieldAccessor(
3070 Field* kernel_field, LocalVariable* setter_value) {
3071 const dart::Function& function = parsed_function_->function();
3072
3073 bool is_setter = function.IsImplicitSetterFunction();
3074 bool is_method = !function.IsStaticFunction();
3075 dart::Field& field =
3076 dart::Field::ZoneHandle(Z, H.LookupFieldByKernelField(kernel_field));
3077
3078 TargetEntryInstr* normal_entry = BuildTargetEntry();
3079 graph_entry_ = new (Z)
3080 GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId);
3081
3082 // TODO(27590): Add support for FLAG_use_field_guards.
3083 Fragment body(normal_entry);
3084 if (is_setter) {
3085 if (is_method) {
3086 body += LoadLocal(scopes_->this_variable);
3087 body += LoadLocal(setter_value);
3088 body += StoreInstanceField(field);
3089 } else {
3090 body += LoadLocal(setter_value);
3091 body += StoreStaticField(field);
3092 }
3093 body += NullConstant();
3094 } else if (is_method) {
3095 body += LoadLocal(scopes_->this_variable);
3096 body += LoadField(field);
3097 } else if (field.is_const()) {
3098 // If the parser needs to know the value of an uninitialized constant field
3099 // it will set the value to the transition sentinel (used to detect circular
3100 // initialization) and then call the implicit getter. Thus, the getter
3101 // cannot contain the InitStaticField instruction that normal static getters
3102 // contain because it would detect spurious circular initialization when it
3103 // checks for the transition sentinel.
3104 Expression* initializer = kernel_field->initializer();
3105 ASSERT(initializer != NULL);
3106 body += Constant(constant_evaluator_.EvaluateExpression(initializer));
3107 } else {
3108 // The field always has an initializer because static fields without
3109 // initializers are initialized eagerly and do not have implicit getters.
3110 ASSERT(field.has_initializer());
3111 body += Constant(field);
3112 body += InitStaticField(field);
3113 body += Constant(field);
3114 body += LoadStaticField();
3115 }
3116 body += Return();
3117
3118 return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1);
3119 }
3120
3121
3122 FlowGraph* FlowGraphBuilder::BuildGraphOfStaticFieldInitializer(
3123 Field* kernel_field) {
3124 ASSERT(kernel_field->IsStatic());
3125
3126 Expression* initializer = kernel_field->initializer();
3127
3128 TargetEntryInstr* normal_entry = BuildTargetEntry();
3129 graph_entry_ = new (Z)
3130 GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId);
3131
3132 Fragment body(normal_entry);
3133 body += CheckStackOverflowInPrologue();
3134 if (kernel_field->IsConst()) {
3135 body += Constant(constant_evaluator_.EvaluateExpression(initializer));
3136 } else {
3137 body += TranslateExpression(initializer);
3138 }
3139 body += Return();
3140
3141 return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1);
3142 }
3143
3144
3145 Fragment FlowGraphBuilder::BuildImplicitClosureCreation(
3146 const Function& target) {
3147 Fragment fragment;
3148 const dart::Class& closure_class =
3149 dart::Class::ZoneHandle(Z, I->object_store()->closure_class());
3150 fragment += AllocateObject(closure_class, target);
3151 LocalVariable* closure = MakeTemporary();
3152
3153 // Allocate a context that closes over `this`.
3154 fragment += AllocateContext(1);
3155 LocalVariable* context = MakeTemporary();
3156
3157 // Store the function and the context in the closure.
3158 fragment += LoadLocal(closure);
3159 fragment += Constant(target);
3160 fragment += StoreInstanceField(Closure::function_offset());
3161
3162 fragment += LoadLocal(closure);
3163 fragment += LoadLocal(context);
3164 fragment += StoreInstanceField(Closure::context_offset());
3165
3166 // The context is on top of the operand stack. Store `this`. The context
3167 // doesn't need a parent pointer because it doesn't close over anything
3168 // else.
3169 fragment += LoadLocal(scopes_->this_variable);
3170 fragment += StoreInstanceField(Context::variable_offset(0));
3171
3172 return fragment;
3173 }
3174
3175
3176 FlowGraph* FlowGraphBuilder::BuildGraphOfMethodExtractor(
3177 const Function& method) {
3178 // A method extractor is the implicit getter for a method.
3179 const Function& function =
3180 Function::ZoneHandle(Z, method.extracted_method_closure());
3181
3182 TargetEntryInstr* normal_entry = BuildTargetEntry();
3183 graph_entry_ = new (Z)
3184 GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId);
3185 Fragment body(normal_entry);
3186 body += CheckStackOverflowInPrologue();
3187 body += BuildImplicitClosureCreation(function);
3188 body += Return();
3189
3190 return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1);
3191 }
3192
3193
3194 FlowGraph* FlowGraphBuilder::BuildGraphOfImplicitClosureFunction(
3195 FunctionNode* kernel_function, const Function& function) {
3196 const Function& target = Function::ZoneHandle(Z, function.parent_function());
3197
3198 TargetEntryInstr* normal_entry = BuildTargetEntry();
3199 graph_entry_ = new (Z)
3200 GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId);
3201 SetupDefaultParameterValues(kernel_function);
3202
3203 Fragment body(normal_entry);
3204 body += CheckStackOverflowInPrologue();
3205
3206 // Load all the arguments.
3207 if (!target.is_static()) {
3208 // The context has a fixed shape: a single variable which is the
3209 // closed-over receiver.
3210 body += LoadLocal(parsed_function_->current_context_var());
3211 body += LoadField(Context::variable_offset(0));
3212 body += PushArgument();
3213 }
3214 intptr_t positional_argument_count =
3215 kernel_function->positional_parameters().length();
3216 for (intptr_t i = 0; i < positional_argument_count; i++) {
3217 body +=
3218 LoadLocal(LookupVariable(kernel_function->positional_parameters()[i]));
3219 body += PushArgument();
3220 }
3221 intptr_t named_argument_count = kernel_function->named_parameters().length();
3222 Array& argument_names = Array::ZoneHandle(Z);
3223 if (named_argument_count > 0) {
3224 argument_names = Array::New(named_argument_count);
3225 for (intptr_t i = 0; i < named_argument_count; i++) {
3226 VariableDeclaration* variable = kernel_function->named_parameters()[i];
3227 body += LoadLocal(LookupVariable(variable));
3228 body += PushArgument();
3229 argument_names.SetAt(i, H.DartSymbol(variable->name()));
3230 }
3231 }
3232 // Forward them to the target.
3233 intptr_t argument_count = positional_argument_count + named_argument_count;
3234 if (!target.is_static()) ++argument_count;
3235 body += StaticCall(target, argument_count, argument_names);
3236
3237 // Return the result.
3238 body += Return();
3239
3240 return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1);
3241 }
3242
3243
3244 FlowGraph* FlowGraphBuilder::BuildGraphOfNoSuchMethodDispatcher(
3245 const Function& function) {
3246 // This function is specialized for a receiver class, a method name, and
3247 // the arguments descriptor at a call site.
3248
3249 TargetEntryInstr* normal_entry = BuildTargetEntry();
3250 graph_entry_ = new (Z)
3251 GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId);
3252
3253 // The backend will expect an array of default values for all the named
3254 // parameters, even if they are all known to be passed at the call site
3255 // because the call site matches the arguments descriptor. Use null for
3256 // the default values.
3257 const Array& descriptor_array =
3258 Array::ZoneHandle(Z, function.saved_args_desc());
3259 ArgumentsDescriptor descriptor(descriptor_array);
3260 ZoneGrowableArray<const Instance*>* default_values =
3261 new ZoneGrowableArray<const Instance*>(Z, descriptor.NamedCount());
3262 for (intptr_t i = 0; i < descriptor.NamedCount(); ++i) {
3263 default_values->Add(&Object::null_instance());
3264 }
3265 parsed_function_->set_default_parameter_values(default_values);
3266
3267 Fragment body(normal_entry);
3268 body += CheckStackOverflowInPrologue();
3269
3270 // The receiver is the first argument to noSuchMethod, and it is the first
3271 // argument passed to the dispatcher function.
3272 LocalScope* scope = parsed_function_->node_sequence()->scope();
3273 body += LoadLocal(scope->VariableAt(0));
3274 body += PushArgument();
3275
3276 // The second argument to noSuchMethod is an invocation mirror. Push the
3277 // arguments for allocating the invocation mirror. First, the name.
3278 body += Constant(dart::String::ZoneHandle(Z, function.name()));
3279 body += PushArgument();
3280
3281 // Second, the arguments descriptor.
3282 body += Constant(descriptor_array);
3283 body += PushArgument();
3284
3285 // Third, an array containing the original arguments. Create it and fill
3286 // it in.
3287 body += Constant(TypeArguments::ZoneHandle(Z, TypeArguments::null()));
3288 body += IntConstant(descriptor.Count());
3289 body += CreateArray();
3290 LocalVariable* array = MakeTemporary();
3291 for (intptr_t i = 0; i < descriptor.PositionalCount(); ++i) {
3292 body += LoadLocal(array);
3293 body += IntConstant(i);
3294 body += LoadLocal(scope->VariableAt(i));
3295 body += StoreIndexed(kArrayCid);
3296 body += Drop();
3297 }
3298 dart::String& name = dart::String::Handle(Z);
3299 for (intptr_t i = 0; i < descriptor.NamedCount(); ++i) {
3300 intptr_t parameter_index = descriptor.PositionalCount() + i;
3301 name = descriptor.NameAt(i);
3302 name = dart::Symbols::New(H.thread(), name);
3303 body += LoadLocal(array);
3304 body += IntConstant(descriptor.PositionAt(i));
3305 body += LoadLocal(scope->VariableAt(parameter_index));
3306 body += StoreIndexed(kArrayCid);
3307 body += Drop();
3308 }
3309 body += PushArgument();
3310
3311 // Fourth, false indicating this is not a super NoSuchMethod.
3312 body += Constant(Bool::False());
3313 body += PushArgument();
3314
3315 const dart::Class& mirror_class = dart::Class::Handle(
3316 Z, dart::Library::LookupCoreClass(Symbols::InvocationMirror()));
3317 ASSERT(!mirror_class.IsNull());
3318 const Function& allocation_function = Function::ZoneHandle(
3319 Z, mirror_class.LookupStaticFunction(dart::Library::PrivateCoreLibName(
3320 Symbols::AllocateInvocationMirror())));
3321 ASSERT(!allocation_function.IsNull());
3322 body += StaticCall(allocation_function, 4);
3323 body += PushArgument(); // For the call to noSuchMethod.
3324
3325 ArgumentsDescriptor two_arguments(
3326 Array::Handle(Z, ArgumentsDescriptor::New(2)));
3327 Function& no_such_method =
3328 Function::ZoneHandle(Z, Resolver::ResolveDynamicForReceiverClass(
3329 dart::Class::Handle(Z, function.Owner()),
3330 Symbols::NoSuchMethod(), two_arguments));
3331 if (no_such_method.IsNull()) {
3332 // If noSuchMethod is not found on the receiver class, call
3333 // Object.noSuchMethod.
3334 no_such_method = Resolver::ResolveDynamicForReceiverClass(
3335 dart::Class::Handle(Z, I->object_store()->object_class()),
3336 Symbols::NoSuchMethod(), two_arguments);
3337 }
3338 body += StaticCall(no_such_method, 2);
3339 body += Return();
3340
3341 return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1);
3342 }
3343
3344
3345 FlowGraph* FlowGraphBuilder::BuildGraphOfInvokeFieldDispatcher(
3346 const Function& function) {
3347 // Find the name of the field we should dispatch to.
3348 const dart::Class& owner = dart::Class::Handle(Z, function.Owner());
3349 ASSERT(!owner.IsNull());
3350 const dart::String& field_name = dart::String::Handle(Z, function.name());
3351 const dart::String& getter_name = dart::String::ZoneHandle(
3352 Z,
3353 Symbols::New(H.thread(), dart::String::Handle(
3354 Z, dart::Field::GetterSymbol(field_name))));
3355
3356 // Determine if this is `class Closure { get call => this; }`
3357 const dart::Class& closure_class =
3358 dart::Class::Handle(Z, I->object_store()->closure_class());
3359 const bool is_closure_call = (owner.raw() == closure_class.raw()) &&
3360 field_name.Equals(Symbols::Call());
3361
3362 // Set default parameters & construct argument names array.
3363 //
3364 // The backend will expect an array of default values for all the named
3365 // parameters, even if they are all known to be passed at the call site
3366 // because the call site matches the arguments descriptor. Use null for
3367 // the default values.
3368 const Array& descriptor_array =
3369 Array::ZoneHandle(Z, function.saved_args_desc());
3370 ArgumentsDescriptor descriptor(descriptor_array);
3371 const Array& argument_names =
3372 Array::ZoneHandle(Z, Array::New(descriptor.NamedCount(), Heap::kOld));
3373 ZoneGrowableArray<const Instance*>* default_values =
3374 new ZoneGrowableArray<const Instance*>(Z, descriptor.NamedCount());
3375 dart::String& string_handle = dart::String::Handle(Z);
3376 for (intptr_t i = 0; i < descriptor.NamedCount(); ++i) {
3377 default_values->Add(&Object::null_instance());
3378 string_handle = descriptor.NameAt(i);
3379 argument_names.SetAt(i, string_handle);
3380 }
3381 parsed_function_->set_default_parameter_values(default_values);
3382
3383 TargetEntryInstr* normal_entry = BuildTargetEntry();
3384 graph_entry_ = new (Z)
3385 GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId);
3386
3387 Fragment body(normal_entry);
3388 body += CheckStackOverflowInPrologue();
3389
3390 LocalScope* scope = parsed_function_->node_sequence()->scope();
3391
3392 LocalVariable* closure = NULL;
3393 if (is_closure_call) {
3394 closure = scope->VariableAt(0);
3395
3396 // The closure itself is the first argument.
3397 body += LoadLocal(closure);
3398 } else {
3399 // Invoke the getter to get the field value.
3400 body += LoadLocal(scope->VariableAt(0));
3401 body += PushArgument();
3402 body += InstanceCall(getter_name, Token::kGET, 1);
3403 }
3404
3405 body += PushArgument();
3406
3407 // Push all arguments onto the stack.
3408 intptr_t pos = 1;
3409 for (; pos < descriptor.Count(); pos++) {
3410 body += LoadLocal(scope->VariableAt(pos));
3411 body += PushArgument();
3412 }
3413
3414 if (is_closure_call) {
3415 // Lookup the function in the closure.
3416 body += LoadLocal(closure);
3417 body += LoadField(Closure::function_offset());
3418
3419 body += ClosureCall(descriptor.Count(), argument_names);
3420 } else {
3421 body += InstanceCall(Symbols::Call(), Token::kILLEGAL, descriptor.Count(),
3422 argument_names);
3423 }
3424
3425 body += Return();
3426
3427 return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1);
3428 }
3429
3430
3431 void FlowGraphBuilder::SetupDefaultParameterValues(FunctionNode* function) {
3432 intptr_t num_optional_parameters =
3433 parsed_function_->function().NumOptionalParameters();
3434 if (num_optional_parameters > 0) {
3435 ZoneGrowableArray<const Instance*>* default_values =
3436 new ZoneGrowableArray<const Instance*>(Z, num_optional_parameters);
3437
3438 if (parsed_function_->function().HasOptionalNamedParameters()) {
3439 ASSERT(!parsed_function_->function().HasOptionalPositionalParameters());
3440 for (intptr_t i = 0; i < num_optional_parameters; i++) {
3441 VariableDeclaration* variable = function->named_parameters()[i];
3442 Instance* default_value;
3443 if (variable->initializer() != NULL) {
3444 default_value =
3445 &constant_evaluator_.EvaluateExpression(variable->initializer());
3446 } else {
3447 default_value = &Instance::ZoneHandle(Z, Instance::null());
3448 }
3449 default_values->Add(default_value);
3450 }
3451 } else {
3452 ASSERT(parsed_function_->function().HasOptionalPositionalParameters());
3453 intptr_t required = function->required_parameter_count();
3454 for (intptr_t i = 0; i < num_optional_parameters; i++) {
3455 VariableDeclaration* variable =
3456 function->positional_parameters()[required + i];
3457 Instance* default_value;
3458 if (variable->initializer() != NULL) {
3459 default_value =
3460 &constant_evaluator_.EvaluateExpression(variable->initializer());
3461 } else {
3462 default_value = &Instance::ZoneHandle(Z, Instance::null());
3463 }
3464 default_values->Add(default_value);
3465 }
3466 }
3467 parsed_function_->set_default_parameter_values(default_values);
3468 }
3469 }
3470
3471
3472 TargetEntryInstr* FlowGraphBuilder::BuildTargetEntry() {
3473 return new (Z) TargetEntryInstr(AllocateBlockId(), CurrentTryIndex());
3474 }
3475
3476
3477 JoinEntryInstr* FlowGraphBuilder::BuildJoinEntry() {
3478 return new (Z) JoinEntryInstr(AllocateBlockId(), CurrentTryIndex());
3479 }
3480
3481
3482 Fragment FlowGraphBuilder::TranslateInitializers(
3483 Class* kernel_klass, List<Initializer>* initializers) {
3484 Fragment instructions;
3485
3486 // These come from:
3487 // class A {
3488 // var x = (expr);
3489 // }
3490 for (intptr_t i = 0; i < kernel_klass->fields().length(); i++) {
3491 Field* kernel_field = kernel_klass->fields()[i];
3492 Expression* init = kernel_field->initializer();
3493 if (!kernel_field->IsStatic() && init != NULL) {
3494 dart::Field& field =
3495 dart::Field::ZoneHandle(Z, H.LookupFieldByKernelField(kernel_field));
3496
3497 EnterScope(kernel_field);
3498 // TODO(27590): Support FLAG_use_field_guards.
3499 instructions += LoadLocal(scopes_->this_variable);
3500 instructions += TranslateExpression(init);
3501 instructions += StoreInstanceField(field);
3502 ExitScope(kernel_field);
3503 }
3504 }
3505
3506 // These to come from:
3507 // class A {
3508 // var x;
3509 // var y;
3510 // A(this.x) : super(expr), y = (expr);
3511 // }
3512 for (intptr_t i = 0; i < initializers->length(); i++) {
3513 Initializer* initializer = (*initializers)[i];
3514 if (initializer->IsFieldInitializer()) {
3515 FieldInitializer* init = FieldInitializer::Cast(initializer);
3516 dart::Field& field =
3517 dart::Field::ZoneHandle(Z, H.LookupFieldByKernelField(init->field()));
3518
3519 // TODO(27590): Support FLAG_use_field_guards.
3520 instructions += LoadLocal(scopes_->this_variable);
3521 instructions += TranslateExpression(init->value());
3522 instructions += StoreInstanceField(field);
3523 } else if (initializer->IsSuperInitializer()) {
3524 SuperInitializer* init = SuperInitializer::Cast(initializer);
3525
3526 instructions += LoadLocal(scopes_->this_variable);
3527 instructions += PushArgument();
3528
3529 ASSERT(init->arguments()->types().length() == 0);
3530 Array& argument_names = Array::ZoneHandle(Z);
3531 instructions += TranslateArguments(init->arguments(), &argument_names);
3532
3533 const Function& target = Function::ZoneHandle(
3534 Z, H.LookupConstructorByKernelConstructor(init->target()));
3535 intptr_t argument_count = init->arguments()->count() + 1;
3536 instructions += StaticCall(target, argument_count, argument_names);
3537 instructions += Drop();
3538 } else if (initializer->IsRedirectingInitializer()) {
3539 RedirectingInitializer* init = RedirectingInitializer::Cast(initializer);
3540
3541 instructions += LoadLocal(scopes_->this_variable);
3542 instructions += PushArgument();
3543
3544 ASSERT(init->arguments()->types().length() == 0);
3545 Array& argument_names = Array::ZoneHandle(Z);
3546 instructions += TranslateArguments(init->arguments(), &argument_names);
3547
3548 const Function& target = Function::ZoneHandle(
3549 Z, H.LookupConstructorByKernelConstructor(init->target()));
3550 intptr_t argument_count = init->arguments()->count() + 1;
3551 instructions += StaticCall(target, argument_count, argument_names);
3552 instructions += Drop();
3553 } else if (initializer->IsLocalInitializer()) {
3554 // The other initializers following this one might read the variable. This
3555 // is used e.g. for evaluating the arguments to a super call first, run
3556 // normal field initializers next and then make the actual super call:
3557 //
3558 // The frontend converts
3559 //
3560 // class A {
3561 // var x;
3562 // A(a, b) : super(a + b), x = 2*b {}
3563 // }
3564 //
3565 // to
3566 //
3567 // class A {
3568 // var x;
3569 // A(a, b) : tmp = a + b, x = 2*b, super(tmp) {}
3570 // }
3571 //
3572 // (This is strictly speaking not what one should do in terms of the
3573 // specification but that is how it is currently implemented.)
3574 LocalInitializer* init = LocalInitializer::Cast(initializer);
3575
3576 VariableDeclaration* declaration = init->variable();
3577 LocalVariable* variable = LookupVariable(declaration);
3578 Expression* initializer = init->variable()->initializer();
3579 ASSERT(initializer != NULL);
3580 ASSERT(!declaration->IsConst());
3581
3582 instructions += TranslateExpression(initializer);
3583 instructions += StoreLocal(variable);
3584 instructions += Drop();
3585
3586 fragment_ = instructions;
3587 } else {
3588 UNIMPLEMENTED();
3589 }
3590 }
3591 return instructions;
3592 }
3593
3594
3595 Fragment FlowGraphBuilder::TranslateStatement(Statement* statement) {
3596 #ifdef DEBUG
3597 intptr_t original_context_depth = context_depth_;
3598 #endif
3599 statement->AcceptStatementVisitor(this);
3600 DEBUG_ASSERT(context_depth_ == original_context_depth);
3601 return fragment_;
3602 }
3603
3604
3605 Fragment FlowGraphBuilder::TranslateCondition(Expression* expression,
3606 bool* negate) {
3607 *negate = expression->IsNot();
3608 if (*negate) {
3609 return TranslateExpression(Not::Cast(expression)->expression());
3610 }
3611 return TranslateExpression(expression);
3612 }
3613
3614
3615 Fragment FlowGraphBuilder::TranslateExpression(Expression* expression) {
3616 expression->AcceptExpressionVisitor(this);
3617 return fragment_;
3618 }
3619
3620
3621 ArgumentArray FlowGraphBuilder::GetArguments(int count) {
3622 ArgumentArray arguments =
3623 new (Z) ZoneGrowableArray<PushArgumentInstr*>(Z, count);
3624 arguments->SetLength(count);
3625 for (intptr_t i = count - 1; i >= 0; --i) {
3626 ASSERT(stack_->definition()->IsPushArgument());
3627 ASSERT(!stack_->definition()->HasSSATemp());
3628 arguments->data()[i] = stack_->definition()->AsPushArgument();
3629 Drop();
3630 }
3631 pending_argument_count_ -= count;
3632 ASSERT(pending_argument_count_ >= 0);
3633 return arguments;
3634 }
3635
3636
3637 void FlowGraphBuilder::VisitInvalidExpression(InvalidExpression* node) {
3638 // TODO(27590): Once we have better error information we might need to
3639 // make some invalid expressions not NSM errors but type/compile-time/...
3640 // errors.
3641 fragment_ = ThrowNoSuchMethodError();
3642 }
3643
3644
3645 void FlowGraphBuilder::VisitNullLiteral(NullLiteral* node) {
3646 fragment_ = Constant(Instance::ZoneHandle(Z, Instance::null()));
3647 }
3648
3649
3650 void FlowGraphBuilder::VisitBoolLiteral(BoolLiteral* node) {
3651 fragment_ = Constant(Bool::Get(node->value()));
3652 }
3653
3654
3655 void FlowGraphBuilder::VisitIntLiteral(IntLiteral* node) {
3656 fragment_ = IntConstant(node->value());
3657 }
3658
3659
3660 void FlowGraphBuilder::VisitBigintLiteral(BigintLiteral* node) {
3661 const dart::String& value = H.DartString(node->value());
3662 fragment_ = Constant(Integer::ZoneHandle(Z, Integer::New(value, Heap::kOld)));
3663 }
3664
3665
3666 void FlowGraphBuilder::VisitDoubleLiteral(DoubleLiteral* node) {
3667 fragment_ = Constant(constant_evaluator_.EvaluateExpression(node));
3668 }
3669
3670
3671 void FlowGraphBuilder::VisitStringLiteral(StringLiteral* node) {
3672 fragment_ = Constant(H.DartSymbol(node->value()));
3673 }
3674
3675
3676 void FlowGraphBuilder::VisitSymbolLiteral(SymbolLiteral* node) {
3677 fragment_ = Constant(constant_evaluator_.EvaluateExpression(node));
3678 }
3679
3680
3681 AbstractType& DartTypeTranslator::TranslateType(DartType* node) {
3682 node->AcceptDartTypeVisitor(this);
3683
3684 // We return a new `ZoneHandle` here on purpose: The intermediate language
3685 // instructions do not make a copy of the handle, so we do it.
3686 return dart::AbstractType::ZoneHandle(Z, result_.raw());
3687 }
3688
3689
3690 AbstractType& DartTypeTranslator::TranslateTypeWithoutFinalization(
3691 DartType* node) {
3692 bool saved_finalize = finalize_;
3693 finalize_ = false;
3694 H.SetFinalize(false);
3695 AbstractType& result = TranslateType(node);
3696 finalize_ = saved_finalize;
3697 H.SetFinalize(saved_finalize);
3698 return result;
3699 }
3700
3701
3702 void DartTypeTranslator::VisitInvalidType(InvalidType* node) {
3703 result_ = ClassFinalizer::NewFinalizedMalformedType(
3704 Error::Handle(Z), // No previous error.
3705 dart::Script::Handle(Z, dart::Script::null()), TokenPosition::kNoSource,
3706 "[InvalidType] in Kernel IR.");
3707 }
3708
3709
3710 void DartTypeTranslator::VisitFunctionType(FunctionType* node) {
3711 // TODO(27590): Fix function types which are composed of malformed types.
3712 // We might need to convert them to dynamic types instead of making the
3713 // function type malformed.
3714 const Function& signature_function = Function::ZoneHandle(
3715 Z, Function::NewSignatureFunction(*active_class_->klass,
3716 TokenPosition::kNoSource));
3717
3718 node->return_type()->AcceptDartTypeVisitor(this);
3719 if (result_.IsMalformed()) return;
3720 signature_function.set_result_type(result_);
3721
3722 const intptr_t positional_count = node->positional_parameters().length();
3723 const intptr_t named_count = node->named_parameters().length();
3724 const intptr_t all_count = positional_count + named_count;
3725 const intptr_t required_count = node->required_parameter_count();
3726
3727 // The additional first parameter is the receiver type (set to dynamic).
3728 signature_function.set_num_fixed_parameters(1 + required_count);
3729 signature_function.SetNumOptionalParameters(
3730 all_count - required_count, positional_count > required_count);
3731
3732 const Array& parameter_types =
3733 Array::Handle(Z, Array::New(1 + all_count, Heap::kOld));
3734 signature_function.set_parameter_types(parameter_types);
3735 const Array& parameter_names =
3736 Array::Handle(Z, Array::New(1 + all_count, Heap::kOld));
3737 signature_function.set_parameter_names(parameter_names);
3738
3739 intptr_t pos = 0;
3740 parameter_types.SetAt(pos, AbstractType::dynamic_type());
3741 parameter_names.SetAt(pos, H.DartSymbol("_receiver_"));
3742 pos++;
3743 for (intptr_t i = 0; i < positional_count; i++, pos++) {
3744 node->positional_parameters()[i]->AcceptDartTypeVisitor(this);
3745 if (result_.IsMalformed()) return;
3746 parameter_types.SetAt(pos, result_);
3747 parameter_names.SetAt(pos, H.DartSymbol("noname"));
3748 }
3749 for (intptr_t i = 0; i < named_count; i++, pos++) {
3750 Tuple<String, DartType>* tuple = node->named_parameters()[i];
3751 tuple->second()->AcceptDartTypeVisitor(this);
3752 if (result_.IsMalformed()) return;
3753 parameter_types.SetAt(pos, result_);
3754 parameter_names.SetAt(pos, H.DartSymbol(tuple->first()));
3755 }
3756
3757 Type& signature_type =
3758 Type::ZoneHandle(Z, signature_function.SignatureType());
3759
3760 if (finalize_) {
3761 signature_type ^= ClassFinalizer::FinalizeType(
3762 *active_class_->klass, signature_type, ClassFinalizer::kCanonicalize);
3763 }
3764 signature_function.SetSignatureType(signature_type);
3765
3766 result_ = signature_type.raw();
3767 }
3768
3769
3770 void DartTypeTranslator::VisitTypeParameterType(TypeParameterType* node) {
3771 ASSERT(active_class_->kernel_class != NULL);
3772
3773 List<TypeParameter>* parameters =
3774 &active_class_->kernel_class->type_parameters();
3775 if ((active_class_->member != NULL) && active_class_->member->IsProcedure()) {
3776 Procedure* procedure = Procedure::Cast(active_class_->member);
3777 if ((procedure->function() != NULL) &&
3778 (procedure->function()->type_parameters().length() > 0)) {
3779 //
3780 // WARNING: This is a little hackish:
3781 //
3782 // We have a static factory constructor. The kernel IR gives the factory
3783 // constructor function it's own type parameters (which are equal in name
3784 // and number to the ones of the enclosing class).
3785 // I.e.,
3786 //
3787 // class A<T> {
3788 // factory A.x() { return new B<T>(); }
3789 // }
3790 //
3791 // is basically translated to this:
3792 //
3793 // class A<T> {
3794 // static A.x<T'>() { return new B<T'>(); }
3795 // }
3796 //
3797 parameters = &procedure->function()->type_parameters();
3798 }
3799 }
3800
3801 for (intptr_t i = 0; i < parameters->length(); i++) {
3802 TypeParameter* type_parameter = (*parameters)[i];
3803 if (node->parameter() == type_parameter) {
3804 // The index of the type parameter in [parameters] is
3805 // the same index into the `klass->type_parameters()` array.
3806 result_ ^= dart::TypeArguments::Handle(
3807 Z, active_class_->klass->type_parameters())
3808 .TypeAt(i);
3809 return;
3810 }
3811 }
3812
3813 UNREACHABLE();
3814 }
3815
3816
3817 void DartTypeTranslator::VisitInterfaceType(InterfaceType* node) {
3818 // NOTE: That an interface type like `T<A, B>` is considered to be
3819 // malformed iff `T` is malformed.
3820 // => We therefore ignore errors in `A` or `B`.
3821 const TypeArguments& type_arguments = TranslateTypeArguments(
3822 node->type_arguments().raw_array(), node->type_arguments().length());
3823
3824 const dart::Class& klass =
3825 dart::Class::Handle(Z, H.LookupClassByKernelClass(node->klass()));
3826
3827 result_ = Type::New(klass, type_arguments, TokenPosition::kNoSource);
3828 result_.SetIsResolved();
3829 if (finalize_) {
3830 result_ = ClassFinalizer::FinalizeType(klass, result_,
3831 ClassFinalizer::kCanonicalize);
3832 }
3833 }
3834
3835
3836 void DartTypeTranslator::VisitDynamicType(DynamicType* node) {
3837 result_ = Object::dynamic_type().raw();
3838 }
3839
3840
3841 void DartTypeTranslator::VisitVoidType(VoidType* node) {
3842 result_ = Object::void_type().raw();
3843 }
3844
3845
3846 const TypeArguments& DartTypeTranslator::TranslateTypeArguments(
3847 DartType** dart_types, intptr_t length) {
3848 bool only_dynamic = true;
3849 for (intptr_t i = 0; i < length; i++) {
3850 if (!dart_types[i]->IsDynamicType()) {
3851 only_dynamic = false;
3852 break;
3853 }
3854 }
3855 TypeArguments& type_arguments = TypeArguments::ZoneHandle(Z);
3856 if (!only_dynamic) {
3857 type_arguments = TypeArguments::New(length);
3858 for (intptr_t i = 0; i < length; i++) {
3859 dart_types[i]->AcceptDartTypeVisitor(this);
3860 if (result_.IsMalformed()) {
3861 type_arguments = TypeArguments::null();
3862 return type_arguments;
3863 }
3864 type_arguments.SetTypeAt(i, result_);
3865 }
3866 if (finalize_) {
3867 type_arguments = type_arguments.Canonicalize();
3868 }
3869 }
3870 return type_arguments;
3871 }
3872
3873
3874 const TypeArguments& DartTypeTranslator::TranslateInstantiatedTypeArguments(
3875 const dart::Class& receiver_class, DartType** receiver_type_arguments,
3876 intptr_t length) {
3877 const TypeArguments& type_arguments =
3878 TranslateTypeArguments(receiver_type_arguments, length);
3879 if (type_arguments.IsNull()) return type_arguments;
3880
3881 // We make a temporary [Type] object and use `ClassFinalizer::FinalizeType` to
3882 // finalize the argument types.
3883 // (This can for example make the [type_arguments] vector larger)
3884 Type& type = Type::Handle(
3885 Z, Type::New(receiver_class, type_arguments, TokenPosition::kNoSource));
3886 if (finalize_) {
3887 type ^= ClassFinalizer::FinalizeType(
3888 *active_class_->klass, type, ClassFinalizer::kCanonicalizeWellFormed);
3889 }
3890
3891 const TypeArguments& instantiated_type_arguments =
3892 TypeArguments::ZoneHandle(Z, type.arguments());
3893 return instantiated_type_arguments;
3894 }
3895
3896
3897 const Type& DartTypeTranslator::ReceiverType(const dart::Class& klass) {
3898 ASSERT(!klass.IsNull());
3899 ASSERT(!klass.IsTypedefClass());
3900 // Note that if klass is _Closure, the returned type will be _Closure,
3901 // and not the signature type.
3902 Type& type = Type::ZoneHandle(Z, klass.CanonicalType());
3903 if (!type.IsNull()) {
3904 return type;
3905 }
3906 type = Type::New(klass, TypeArguments::Handle(Z, klass.type_parameters()),
3907 klass.token_pos());
3908 return type;
3909 }
3910
3911
3912 void FlowGraphBuilder::VisitTypeLiteral(TypeLiteral* node) {
3913 const AbstractType& type = T.TranslateType(node->type());
3914 if (type.IsMalformed()) H.ReportError("Malformed type literal");
3915
3916 fragment_ = Constant(type);
3917 }
3918
3919
3920 void FlowGraphBuilder::VisitVariableGet(VariableGet* node) {
3921 fragment_ = LoadLocal(LookupVariable(node->variable()));
3922 }
3923
3924
3925 void FlowGraphBuilder::VisitVariableSet(VariableSet* node) {
3926 Fragment instructions = TranslateExpression(node->expression());
3927 // The IR should not include assignments to final or const variables.
3928 // This is https://github.com/dart-lang/rasta/issues/83.
3929 //
3930 // TODO(27590): simply ASSERT that the variable is not const or final
3931 // when that issue is fixed.
3932 fragment_ = instructions +
3933 ((node->variable()->IsFinal() || node->variable()->IsConst())
3934 ? Drop() + ThrowNoSuchMethodError()
3935 : StoreLocal(LookupVariable(node->variable())));
3936 }
3937
3938
3939 void FlowGraphBuilder::VisitStaticGet(StaticGet* node) {
3940 Member* target = node->target();
3941 if (target->IsField()) {
3942 Field* kernel_field = Field::Cast(target);
3943 const dart::Field& field =
3944 dart::Field::ZoneHandle(Z, H.LookupFieldByKernelField(kernel_field));
3945 if (kernel_field->IsConst()) {
3946 fragment_ = Constant(constant_evaluator_.EvaluateExpression(node));
3947 } else {
3948 const dart::Class& owner = dart::Class::Handle(Z, field.Owner());
3949 const dart::String& getter_name = H.DartGetterName(kernel_field->name());
3950 const Function& getter =
3951 Function::ZoneHandle(Z, owner.LookupStaticFunction(getter_name));
3952 if (getter.IsNull() || !field.has_initializer()) {
3953 Fragment instructions = Constant(field);
3954 fragment_ = instructions + LoadStaticField();
3955 } else {
3956 // TODO(27590): figure out how to trigger this case and add tests.
3957 fragment_ = StaticCall(getter, 0);
3958 }
3959 }
3960 } else {
3961 Procedure* procedure = Procedure::Cast(target);
3962 const Function& target = Function::ZoneHandle(
3963 Z, H.LookupStaticMethodByKernelProcedure(procedure));
3964
3965 if (procedure->kind() == Procedure::kGetter) {
3966 fragment_ = StaticCall(target, 0);
3967 } else if (procedure->kind() == Procedure::kMethod) {
3968 ASSERT(procedure->IsStatic());
3969 Function& closure_function =
3970 Function::ZoneHandle(Z, target.ImplicitClosureFunction());
3971 closure_function.set_kernel_function(target.kernel_function());
3972 const Instance& closure =
3973 Instance::ZoneHandle(Z, closure_function.ImplicitStaticClosure());
3974 fragment_ = Constant(closure);
3975 } else {
3976 UNIMPLEMENTED();
3977 }
3978 }
3979 }
3980
3981
3982 void FlowGraphBuilder::VisitStaticSet(StaticSet* node) {
3983 Member* target = node->target();
3984 if (target->IsField()) {
3985 Field* kernel_field = Field::Cast(target);
3986 const dart::Field& field =
3987 dart::Field::ZoneHandle(Z, H.LookupFieldByKernelField(kernel_field));
3988 Fragment instructions = TranslateExpression(node->expression());
3989 LocalVariable* variable = MakeTemporary();
3990 instructions += LoadLocal(variable);
3991 fragment_ = instructions + StoreStaticField(field);
3992 } else {
3993 ASSERT(target->IsProcedure());
3994
3995 // Evaluate the expression on the right hand side.
3996 Fragment instructions = TranslateExpression(node->expression());
3997 LocalVariable* variable = MakeTemporary();
3998
3999 // Prepare argument.
4000 instructions += LoadLocal(variable);
4001 instructions += PushArgument();
4002
4003 // Invoke the setter function.
4004 Procedure* procedure = Procedure::Cast(target);
4005 const Function& target = Function::ZoneHandle(
4006 Z, H.LookupStaticMethodByKernelProcedure(procedure));
4007 instructions += StaticCall(target, 1);
4008
4009 // Drop the unused result & leave the stored value on the stack.
4010 fragment_ = instructions + Drop();
4011 }
4012 }
4013
4014
4015 void FlowGraphBuilder::VisitPropertyGet(PropertyGet* node) {
4016 Fragment instructions = TranslateExpression(node->receiver());
4017 instructions += PushArgument();
4018 const dart::String& getter_name = H.DartGetterName(node->name());
4019 fragment_ = instructions + InstanceCall(getter_name, Token::kGET, 1);
4020 }
4021
4022
4023 void FlowGraphBuilder::VisitPropertySet(PropertySet* node) {
4024 Fragment instructions(NullConstant());
4025 LocalVariable* variable = MakeTemporary();
4026 instructions += TranslateExpression(node->receiver());
4027 instructions += PushArgument();
4028 instructions += TranslateExpression(node->value());
4029 instructions += StoreLocal(variable);
4030 instructions += PushArgument();
4031
4032 const dart::String& setter_name = H.DartSetterName(node->name());
4033 instructions += InstanceCall(setter_name, Token::kSET, 2);
4034 fragment_ = instructions + Drop();
4035 }
4036
4037
4038 void FlowGraphBuilder::VisitDirectPropertyGet(DirectPropertyGet* node) {
4039 Function& target = Function::ZoneHandle(Z);
4040 if (node->target()->IsProcedure()) {
4041 Procedure* kernel_procedure = Procedure::Cast(node->target());
4042 Name* kernel_name = kernel_procedure->name();
4043 if (kernel_procedure->kind() == Procedure::kGetter) {
4044 target =
4045 LookupMethodByMember(kernel_procedure, H.DartGetterName(kernel_name));
4046 } else {
4047 target =
4048 LookupMethodByMember(kernel_procedure, H.DartMethodName(kernel_name));
4049 target = target.ImplicitClosureFunction();
4050 ASSERT(!target.IsNull());
4051 fragment_ = BuildImplicitClosureCreation(target);
4052 return;
4053 }
4054 } else {
4055 ASSERT(node->target()->IsField());
4056 const dart::String& getter_name = H.DartGetterName(node->target()->name());
4057 target = LookupMethodByMember(node->target(), getter_name);
4058 ASSERT(target.IsGetterFunction() || target.IsImplicitGetterFunction());
4059 }
4060
4061 Fragment instructions = TranslateExpression(node->receiver());
4062 instructions += PushArgument();
4063 fragment_ = instructions + StaticCall(target, 1);
4064 }
4065
4066
4067 void FlowGraphBuilder::VisitDirectPropertySet(DirectPropertySet* node) {
4068 const dart::String& method_name = H.DartSetterName(node->target()->name());
4069 const Function& target = Function::ZoneHandle(
4070 Z, LookupMethodByMember(node->target(), method_name));
4071 ASSERT(target.IsSetterFunction() || target.IsImplicitSetterFunction());
4072
4073 Fragment instructions(NullConstant());
4074 LocalVariable* value = MakeTemporary();
4075 instructions += TranslateExpression(node->receiver());
4076 instructions += PushArgument();
4077 instructions += TranslateExpression(node->value());
4078 instructions += StoreLocal(value);
4079 instructions += PushArgument();
4080 instructions += StaticCall(target, 2);
4081
4082 fragment_ = instructions + Drop();
4083 }
4084
4085
4086 void FlowGraphBuilder::VisitStaticInvocation(StaticInvocation* node) {
4087 const Function& target = Function::ZoneHandle(
4088 Z, H.LookupStaticMethodByKernelProcedure(node->procedure()));
4089 const dart::Class& klass = dart::Class::ZoneHandle(Z, target.Owner());
4090 intptr_t argument_count = node->arguments()->count();
4091 if (target.IsGenerativeConstructor() || target.IsFactory()) {
4092 // The VM requires a TypeArguments object as first parameter for
4093 // every factory constructor.
4094 ++argument_count;
4095 }
4096 List<NamedExpression>& named = node->arguments()->named();
4097 const Array& argument_names = H.ArgumentNames(&named);
4098
4099 Fragment instructions;
4100 if (!target.AreValidArguments(argument_count, argument_names, NULL)) {
4101 // An argument mismatch for a static invocation really should not occur
4102 // in the IR. This is issue https://github.com/dart-lang/rasta/issues/76.
4103 //
4104 // TODO(27590): Change this to an ASSERT when that issue is fixed.
4105 List<Expression>& positional = node->arguments()->positional();
4106 for (intptr_t i = 0; i < positional.length(); ++i) {
4107 instructions += TranslateExpression(positional[i]);
4108 instructions += Drop();
4109 }
4110
4111 for (intptr_t i = 0; i < named.length(); ++i) {
4112 instructions += TranslateExpression(named[i]->expression());
4113 instructions += Drop();
4114 }
4115
4116 fragment_ = instructions + ThrowNoSuchMethodError();
4117 return;
4118 }
4119
4120 LocalVariable* instance_variable = NULL;
4121
4122 // If we cross the Kernel -> VM core library boundary, a [StaticInvocation]
4123 // can appear, but the thing we're calling is not a static method, but a
4124 // factory constructor.
4125 // The `H.LookupStaticmethodByKernelProcedure` will potentially resolve to the
4126 // forwarded constructor.
4127 // In that case we'll make an instance and pass it as first argument.
4128 //
4129 // TODO(27590): Get rid of this after we're using core libraries compiled
4130 // into Kernel.
4131 if (target.IsGenerativeConstructor()) {
4132 if (klass.NumTypeArguments() > 0) {
4133 List<DartType>& kernel_type_arguments = node->arguments()->types();
4134 const TypeArguments& type_arguments =
4135 T.TranslateInstantiatedTypeArguments(
4136 klass, kernel_type_arguments.raw_array(),
4137 kernel_type_arguments.length());
4138 instructions += TranslateInstantiatedTypeArguments(type_arguments);
4139 instructions += PushArgument();
4140 instructions += AllocateObject(klass, 1);
4141 } else {
4142 instructions += AllocateObject(klass, 0);
4143 }
4144
4145 instance_variable = MakeTemporary();
4146
4147 instructions += LoadLocal(instance_variable);
4148 instructions += PushArgument();
4149 } else if (target.IsFactory()) {
4150 // The VM requires currently a TypeArguments object as first parameter for
4151 // every factory constructor :-/ !
4152 //
4153 // TODO(27590): Get rid of this after we're using core libraries compiled
4154 // into Kernel.
4155 List<DartType>& kernel_type_arguments = node->arguments()->types();
4156
4157 const TypeArguments& type_arguments = T.TranslateInstantiatedTypeArguments(
4158 klass, kernel_type_arguments.raw_array(),
4159 kernel_type_arguments.length());
4160
4161 instructions += TranslateInstantiatedTypeArguments(type_arguments);
4162 instructions += PushArgument();
4163 } else {
4164 ASSERT(node->arguments()->types().length() == 0);
4165 }
4166
4167 // Special case identical(x, y) call.
4168 // TODO(27590) consider moving this into the inliner and force inline it
4169 // there.
4170 if (klass.IsTopLevel() && (klass.library() == dart::Library::CoreLibrary()) &&
4171 (target.name() == Symbols::Identical().raw())) {
4172 ASSERT(argument_count == 2);
4173
4174 List<Expression>& positional = node->arguments()->positional();
4175 for (intptr_t i = 0; i < positional.length(); ++i) {
4176 instructions += TranslateExpression(positional[i]);
4177 }
4178 instructions += StrictCompare(Token::kEQ_STRICT, /*number_check=*/true);
4179 } else {
4180 instructions += TranslateArguments(node->arguments(), NULL);
4181 instructions += StaticCall(target, argument_count, argument_names);
4182
4183 if (target.IsGenerativeConstructor()) {
4184 // Drop the result of the constructor call and leave [instance_variable]
4185 // on top-of-stack.
4186 instructions += Drop();
4187 }
4188 }
4189
4190 fragment_ = instructions;
4191 }
4192
4193
4194 static bool IsNumberLiteral(Node* node) {
4195 return node->IsIntLiteral() || node->IsDoubleLiteral();
4196 }
4197
4198
4199 void FlowGraphBuilder::VisitMethodInvocation(MethodInvocation* node) {
4200 const dart::String& name = H.DartMethodName(node->name());
4201 const intptr_t argument_count = node->arguments()->count() + 1;
4202 const Token::Kind token_kind = MethodKind(name);
4203 if (IsNumberLiteral(node->receiver())) {
4204 if ((argument_count == 1) && (token_kind == Token::kNEGATE)) {
4205 const Object& result = constant_evaluator_.EvaluateExpressionSafe(node);
4206 if (!result.IsError()) {
4207 fragment_ = Constant(result);
4208 return;
4209 }
4210 } else if ((argument_count == 2) &&
4211 Token::IsBinaryArithmeticOperator(token_kind) &&
4212 IsNumberLiteral(node->arguments()->positional()[0])) {
4213 const Object& result = constant_evaluator_.EvaluateExpressionSafe(node);
4214 if (!result.IsError()) {
4215 fragment_ = Constant(result);
4216 return;
4217 }
4218 }
4219 }
4220
4221 Fragment instructions = TranslateExpression(node->receiver());
4222 instructions += PushArgument();
4223
4224 // Dart does not support generic methods yet.
4225 ASSERT(node->arguments()->types().length() == 0);
4226
4227 Array& argument_names = Array::ZoneHandle(Z);
4228 instructions += TranslateArguments(node->arguments(), &argument_names);
4229
4230 intptr_t num_args_checked = 1;
4231 // If we have a special operation (e.g. +/-/==) we mark both arguments as
4232 // to be checked.
4233 if (token_kind != Token::kILLEGAL) {
4234 ASSERT(argument_count <= 2);
4235 num_args_checked = argument_count;
4236 }
4237
4238 fragment_ = instructions + InstanceCall(name, token_kind, argument_count,
4239 argument_names, num_args_checked);
4240 }
4241
4242
4243 void FlowGraphBuilder::VisitDirectMethodInvocation(
4244 DirectMethodInvocation* node) {
4245 const dart::String& method_name = H.DartMethodName(node->target()->name());
4246 const Function& target = Function::ZoneHandle(
4247 Z, LookupMethodByMember(node->target(), method_name));
4248
4249 intptr_t argument_count = node->arguments()->count() + 1;
4250 Array& argument_names = Array::ZoneHandle(Z);
4251
4252 ASSERT(node->arguments()->types().length() == 0);
4253 Fragment instructions = TranslateExpression(node->receiver());
4254 instructions += PushArgument();
4255 instructions += TranslateArguments(node->arguments(), &argument_names);
4256 fragment_ = instructions + StaticCall(target, argument_count, argument_names);
4257 }
4258
4259
4260 void FlowGraphBuilder::VisitConstructorInvocation(ConstructorInvocation* node) {
4261 if (node->is_const()) {
4262 fragment_ =
4263 Constant(constant_evaluator_.EvaluateConstructorInvocation(node));
4264 return;
4265 }
4266
4267 Class* kernel_class = Class::Cast(node->target()->parent());
4268
4269 dart::Class& klass =
4270 dart::Class::ZoneHandle(Z, H.LookupClassByKernelClass(kernel_class));
4271
4272 Fragment instructions;
4273 if (klass.NumTypeArguments() > 0) {
4274 List<DartType>& kernel_type_arguments = node->arguments()->types();
4275 const TypeArguments& type_arguments = T.TranslateInstantiatedTypeArguments(
4276 klass, kernel_type_arguments.raw_array(),
4277 kernel_type_arguments.length());
4278
4279 if (type_arguments.IsNull() || type_arguments.IsInstantiated()) {
4280 instructions += TranslateInstantiatedTypeArguments(type_arguments);
4281 } else {
4282 if (!klass.IsGeneric()) {
4283 Type& type = Type::ZoneHandle(Z, T.ReceiverType(klass).raw());
4284
4285 // TODO(27590): Can we move this code into [ReceiverType]?
4286 type ^= ClassFinalizer::FinalizeType(*active_class_.klass, type,
4287 ClassFinalizer::kFinalize);
4288 ASSERT(!type.IsMalformedOrMalbounded());
4289
4290 TypeArguments& canonicalized_type_arguments =
4291 TypeArguments::ZoneHandle(Z, type.arguments());
4292 canonicalized_type_arguments =
4293 canonicalized_type_arguments.Canonicalize();
4294 instructions += Constant(canonicalized_type_arguments);
4295 } else {
4296 instructions += TranslateInstantiatedTypeArguments(type_arguments);
4297 }
4298 }
4299
4300 instructions += PushArgument();
4301 instructions += AllocateObject(klass, 1);
4302 } else {
4303 instructions += AllocateObject(klass, 0);
4304 }
4305 LocalVariable* variable = MakeTemporary();
4306
4307 instructions += LoadLocal(variable);
4308 instructions += PushArgument();
4309
4310 Array& argument_names = Array::ZoneHandle(Z);
4311 instructions += TranslateArguments(node->arguments(), &argument_names);
4312
4313 const Function& target = Function::ZoneHandle(
4314 Z, H.LookupConstructorByKernelConstructor(klass, node->target()));
4315 intptr_t argument_count = node->arguments()->count() + 1;
4316 instructions += StaticCall(target, argument_count, argument_names);
4317 fragment_ = instructions + Drop();
4318 }
4319
4320
4321 void FlowGraphBuilder::VisitIsExpression(IsExpression* node) {
4322 Fragment instructions = TranslateExpression(node->operand());
4323
4324 // The VM does not like an instanceOf call with a dynamic type. We need to
4325 // special case this situation.
4326 const Type& object_type = Type::Handle(Z, Type::ObjectType());
4327 const AbstractType& type = T.TranslateType(node->type());
4328 if (type.IsMalformed()) {
4329 instructions += Drop();
4330 instructions += ThrowTypeError();
4331 fragment_ = instructions;
4332 return;
4333 }
4334
4335 if (type.IsInstantiated() &&
4336 object_type.IsSubtypeOf(type, NULL, NULL, Heap::kOld)) {
4337 // Evaluate the expression on the left but ignore it's result.
4338 instructions += Drop();
4339
4340 // Let condition be always true.
4341 instructions += Constant(Bool::True());
4342 } else {
4343 instructions += PushArgument();
4344
4345 if (!type.IsInstantiated()) {
4346 instructions += LoadInstantiatorTypeArguments();
4347 } else {
4348 instructions += NullConstant();
4349 }
4350 instructions += PushArgument(); // Type arguments.
4351
4352 instructions += Constant(type);
4353 instructions += PushArgument(); // Type.
4354
4355 instructions += Constant(Bool::False());
4356 instructions += PushArgument(); // Negate?.
4357
4358 instructions +=
4359 InstanceCall(dart::Library::PrivateCoreLibName(Symbols::_instanceOf()),
4360 Token::kIS, 4);
4361 }
4362
4363 fragment_ = instructions;
4364 }
4365
4366
4367 void FlowGraphBuilder::VisitAsExpression(AsExpression* node) {
4368 Fragment instructions = TranslateExpression(node->operand());
4369
4370 // The VM does not like an Object_as call with a dynamic type. We need to
4371 // special case this situation.
4372 const Type& object_type = Type::Handle(Z, Type::ObjectType());
4373 const AbstractType& type = T.TranslateType(node->type());
4374 if (type.IsMalformed()) {
4375 instructions += Drop();
4376 instructions += ThrowTypeError();
4377 fragment_ = instructions;
4378 return;
4379 }
4380
4381 if (type.IsInstantiated() &&
4382 object_type.IsSubtypeOf(type, NULL, NULL, Heap::kOld)) {
4383 // We already evaluated the operand on the left and just leave it there as
4384 // the result of the `obj as dynamic` expression.
4385 } else {
4386 instructions += PushArgument();
4387
4388 if (!type.IsInstantiated()) {
4389 instructions += LoadInstantiatorTypeArguments();
4390 } else {
4391 instructions += NullConstant();
4392 }
4393 instructions += PushArgument(); // Type arguments.
4394
4395 instructions += Constant(type);
4396 instructions += PushArgument(); // Type.
4397
4398 instructions += InstanceCall(
4399 dart::Library::PrivateCoreLibName(Symbols::_as()), Token::kAS, 3);
4400 }
4401
4402 fragment_ = instructions;
4403 }
4404
4405
4406 void FlowGraphBuilder::VisitConditionalExpression(ConditionalExpression* node) {
4407 bool negate;
4408 Fragment instructions = TranslateCondition(node->condition(), &negate);
4409
4410 TargetEntryInstr* then_entry;
4411 TargetEntryInstr* otherwise_entry;
4412 instructions += BranchIfTrue(&then_entry, &otherwise_entry, negate);
4413
4414 Value* top = stack_;
4415 Fragment then_fragment(then_entry);
4416 then_fragment += TranslateExpression(node->then());
4417 then_fragment += StoreLocal(parsed_function_->expression_temp_var());
4418 then_fragment += Drop();
4419
4420 ASSERT(stack_ == top);
4421 Fragment otherwise_fragment(otherwise_entry);
4422 otherwise_fragment += TranslateExpression(node->otherwise());
4423 otherwise_fragment += StoreLocal(parsed_function_->expression_temp_var());
4424 otherwise_fragment += Drop();
4425
4426 JoinEntryInstr* join = BuildJoinEntry();
4427 then_fragment += Goto(join);
4428 otherwise_fragment += Goto(join);
4429
4430 fragment_ = Fragment(instructions.entry, join) +
4431 LoadLocal(parsed_function_->expression_temp_var());
4432 }
4433
4434
4435 void FlowGraphBuilder::VisitLogicalExpression(LogicalExpression* node) {
4436 bool negate;
4437 Fragment instructions = TranslateCondition(node->left(), &negate);
4438 TargetEntryInstr* right_entry;
4439 TargetEntryInstr* constant_entry;
4440
4441 if (node->op() == LogicalExpression::kAnd) {
4442 instructions += BranchIfTrue(&right_entry, &constant_entry, negate);
4443 } else {
4444 instructions += BranchIfTrue(&constant_entry, &right_entry, negate);
4445 }
4446
4447 Value* top = stack_;
4448 Fragment right_fragment(right_entry);
4449 right_fragment += TranslateCondition(node->right(), &negate);
4450 right_fragment += Constant(Bool::True());
4451 right_fragment +=
4452 StrictCompare(negate ? Token::kNE_STRICT : Token::kEQ_STRICT);
4453 right_fragment += StoreLocal(parsed_function_->expression_temp_var());
4454 right_fragment += Drop();
4455
4456 ASSERT(top == stack_);
4457 Fragment constant_fragment(constant_entry);
4458 constant_fragment +=
4459 Constant(Bool::Get(node->op() == LogicalExpression::kOr));
4460 constant_fragment += StoreLocal(parsed_function_->expression_temp_var());
4461 constant_fragment += Drop();
4462
4463 JoinEntryInstr* join = BuildJoinEntry();
4464 right_fragment += Goto(join);
4465 constant_fragment += Goto(join);
4466
4467 fragment_ = Fragment(instructions.entry, join) +
4468 LoadLocal(parsed_function_->expression_temp_var());
4469 }
4470
4471
4472 void FlowGraphBuilder::VisitNot(Not* node) {
4473 Fragment instructions = TranslateExpression(node->expression());
4474 fragment_ = instructions + BooleanNegate();
4475 }
4476
4477
4478 void FlowGraphBuilder::VisitThisExpression(ThisExpression* node) {
4479 fragment_ = LoadLocal(scopes_->this_variable);
4480 }
4481
4482
4483 void FlowGraphBuilder::VisitStringConcatenation(StringConcatenation* node) {
4484 List<Expression>& expressions = node->expressions();
4485
4486 Fragment instructions;
4487
4488 // The type arguments for CreateArray.
4489 instructions += Constant(TypeArguments::ZoneHandle(Z));
4490 instructions += IntConstant(expressions.length());
4491 instructions += CreateArray();
4492 LocalVariable* array = MakeTemporary();
4493
4494 for (intptr_t i = 0; i < node->expressions().length(); i++) {
4495 instructions += LoadLocal(array);
4496 instructions += IntConstant(i);
4497 instructions += TranslateExpression(node->expressions()[i]);
4498 instructions += StoreIndexed(kArrayCid);
4499 instructions += Drop();
4500 }
4501
4502 instructions += StringInterpolate();
4503
4504 fragment_ = instructions;
4505 }
4506
4507
4508 void FlowGraphBuilder::VisitListLiteral(ListLiteral* node) {
4509 if (node->is_const()) {
4510 fragment_ = Constant(constant_evaluator_.EvaluateListLiteral(node));
4511 return;
4512 }
4513
4514 DartType* types[] = {node->type()};
4515 const TypeArguments& type_arguments = T.TranslateTypeArguments(types, 1);
4516
4517 // The type argument for the factory call.
4518 Fragment instructions = TranslateInstantiatedTypeArguments(type_arguments);
4519 instructions += PushArgument();
4520 List<Expression>& expressions = node->expressions();
4521 if (expressions.length() == 0) {
4522 instructions += Constant(Object::empty_array());
4523 } else {
4524 // The type arguments for CreateArray.
4525 instructions += Constant(TypeArguments::ZoneHandle(Z));
4526 instructions += IntConstant(expressions.length());
4527 instructions += CreateArray();
4528
4529 LocalVariable* array = MakeTemporary();
4530 for (intptr_t i = 0; i < expressions.length(); ++i) {
4531 instructions += LoadLocal(array);
4532 instructions += IntConstant(i);
4533 instructions += TranslateExpression(expressions[i]);
4534 instructions += StoreIndexed(kArrayCid);
4535 instructions += Drop();
4536 }
4537 }
4538 instructions += PushArgument(); // The array.
4539
4540 const dart::Class& factory_class =
4541 dart::Class::Handle(Z, dart::Library::LookupCoreClass(Symbols::List()));
4542 const Function& factory_method = Function::ZoneHandle(
4543 Z, factory_class.LookupFactory(
4544 dart::Library::PrivateCoreLibName(Symbols::ListLiteralFactory())));
4545 fragment_ = instructions + StaticCall(factory_method, 2);
4546 }
4547
4548
4549 void FlowGraphBuilder::VisitMapLiteral(MapLiteral* node) {
4550 if (node->is_const()) {
4551 fragment_ = Constant(constant_evaluator_.EvaluateMapLiteral(node));
4552 return;
4553 }
4554
4555 const dart::Class& map_class =
4556 dart::Class::Handle(Z, dart::Library::LookupCoreClass(Symbols::Map()));
4557 const Function& factory_method = Function::ZoneHandle(
4558 Z, map_class.LookupFactory(
4559 dart::Library::PrivateCoreLibName(Symbols::MapLiteralFactory())));
4560
4561 DartType* types[] = {node->key_type(), node->value_type()};
4562 const TypeArguments& type_arguments = T.TranslateTypeArguments(types, 2);
4563
4564 // The type argument for the factory call `new Map<K, V>._fromLiteral(List)`.
4565 Fragment instructions = TranslateInstantiatedTypeArguments(type_arguments);
4566 instructions += PushArgument();
4567
4568 List<MapEntry>& entries = node->entries();
4569 if (entries.length() == 0) {
4570 instructions += Constant(Object::empty_array());
4571 } else {
4572 // The type arguments for `new List<X>(int len)`.
4573 instructions += Constant(TypeArguments::ZoneHandle(Z));
4574
4575 // We generate a list of tuples, i.e. [key1, value1, ..., keyN, valueN].
4576 instructions += IntConstant(2 * entries.length());
4577 instructions += CreateArray();
4578
4579 LocalVariable* array = MakeTemporary();
4580 for (intptr_t i = 0; i < entries.length(); ++i) {
4581 instructions += LoadLocal(array);
4582 instructions += IntConstant(2 * i);
4583 instructions += TranslateExpression(entries[i]->key());
4584 instructions += StoreIndexed(kArrayCid);
4585 instructions += Drop();
4586
4587 instructions += LoadLocal(array);
4588 instructions += IntConstant(2 * i + 1);
4589 instructions += TranslateExpression(entries[i]->value());
4590 instructions += StoreIndexed(kArrayCid);
4591 instructions += Drop();
4592 }
4593 }
4594 instructions += PushArgument(); // The array.
4595
4596 fragment_ = instructions + StaticCall(factory_method, 2);
4597 }
4598
4599
4600 void FlowGraphBuilder::VisitFunctionExpression(FunctionExpression* node) {
4601 fragment_ = TranslateFunctionNode(node->function(), node);
4602 }
4603
4604
4605 void FlowGraphBuilder::VisitLet(Let* node) {
4606 Fragment instructions = TranslateStatement(node->variable());
4607 instructions += TranslateExpression(node->body());
4608 fragment_ = instructions;
4609 }
4610
4611
4612 void FlowGraphBuilder::VisitThrow(Throw* node) {
4613 Fragment instructions;
4614
4615 instructions += TranslateExpression(node->expression());
4616 instructions += PushArgument();
4617 instructions += ThrowException();
4618 ASSERT(instructions.is_closed());
4619
4620 fragment_ = instructions;
4621 }
4622
4623
4624 void FlowGraphBuilder::VisitRethrow(Rethrow* node) {
4625 Fragment instructions;
4626
4627 instructions += LoadLocal(catch_block_->exception_var());
4628 instructions += PushArgument();
4629 instructions += LoadLocal(catch_block_->stack_trace_var());
4630 instructions += PushArgument();
4631 instructions += RethrowException(catch_block_->catch_try_index());
4632
4633 fragment_ = instructions;
4634 }
4635
4636
4637 void FlowGraphBuilder::VisitBlockExpression(BlockExpression* node) {
4638 Fragment instructions = TranslateStatement(node->body());
4639 instructions += TranslateExpression(node->value());
4640 fragment_ = instructions;
4641 }
4642
4643
4644 Fragment FlowGraphBuilder::TranslateArguments(Arguments* node,
4645 Array* argument_names) {
4646 Fragment instructions;
4647
4648 List<Expression>& positional = node->positional();
4649 for (intptr_t i = 0; i < positional.length(); ++i) {
4650 instructions += TranslateExpression(positional[i]);
4651 instructions += PushArgument();
4652 }
4653
4654 List<NamedExpression>& named = node->named();
4655 if (argument_names != NULL) {
4656 *argument_names = H.ArgumentNames(&named).raw();
4657 }
4658 for (intptr_t i = 0; i < named.length(); ++i) {
4659 NamedExpression* named_expression = named[i];
4660 instructions += TranslateExpression(named_expression->expression());
4661 instructions += PushArgument();
4662 }
4663 return instructions;
4664 }
4665
4666
4667 void FlowGraphBuilder::VisitInvalidStatement(InvalidStatement* node) {
4668 H.ReportError("Invalid statements not implemented yet!");
4669 }
4670
4671
4672 void FlowGraphBuilder::VisitEmptyStatement(EmptyStatement* node) {
4673 fragment_ = Fragment();
4674 }
4675
4676
4677 void FlowGraphBuilder::VisitBlock(Block* node) {
4678 Fragment instructions;
4679
4680 instructions += EnterScope(node);
4681 List<Statement>& statements = node->statements();
4682 for (intptr_t i = 0; i < statements.length(); ++i) {
4683 instructions += TranslateStatement(statements[i]);
4684 }
4685 instructions += ExitScope(node);
4686
4687 fragment_ = instructions;
4688 }
4689
4690
4691 void FlowGraphBuilder::VisitReturnStatement(ReturnStatement* node) {
4692 bool inside_try_finally = try_finally_block_ != NULL;
4693
4694 Fragment instructions = node->expression() == NULL
4695 ? NullConstant()
4696 : TranslateExpression(node->expression());
4697 if (inside_try_finally) {
4698 ASSERT(scopes_->finally_return_variable != NULL);
4699 instructions += StoreLocal(scopes_->finally_return_variable);
4700 instructions += Drop();
4701 instructions += TranslateFinallyFinalizers(NULL, -1);
4702 if (instructions.is_open()) {
4703 instructions += LoadLocal(scopes_->finally_return_variable);
4704 instructions += Return();
4705 }
4706 } else {
4707 instructions += Return();
4708 }
4709 fragment_ = instructions;
4710 }
4711
4712
4713 void FlowGraphBuilder::VisitExpressionStatement(ExpressionStatement* node) {
4714 Fragment instructions = TranslateExpression(node->expression());
4715 instructions += Drop();
4716 fragment_ = instructions;
4717 }
4718
4719
4720 void FlowGraphBuilder::VisitVariableDeclaration(VariableDeclaration* node) {
4721 LocalVariable* variable = LookupVariable(node);
4722 Expression* initializer = node->initializer();
4723
4724 Fragment instructions;
4725 if (initializer == NULL) {
4726 instructions += NullConstant();
4727 } else {
4728 if (node->IsConst()) {
4729 const Instance& constant_value =
4730 constant_evaluator_.EvaluateExpression(initializer);
4731 variable->SetConstValue(constant_value);
4732 instructions += Constant(constant_value);
4733 } else {
4734 instructions += TranslateExpression(initializer);
4735 }
4736 }
4737 instructions += StoreLocal(variable);
4738 instructions += Drop();
4739 fragment_ = instructions;
4740 }
4741
4742
4743 void FlowGraphBuilder::VisitFunctionDeclaration(FunctionDeclaration* node) {
4744 Fragment instructions = TranslateFunctionNode(node->function(), node);
4745 instructions += StoreLocal(LookupVariable(node->variable()));
4746 instructions += Drop();
4747 fragment_ = instructions;
4748 }
4749
4750
4751 void FlowGraphBuilder::VisitIfStatement(IfStatement* node) {
4752 bool negate;
4753 Fragment instructions = TranslateCondition(node->condition(), &negate);
4754 TargetEntryInstr* then_entry;
4755 TargetEntryInstr* otherwise_entry;
4756 instructions += BranchIfTrue(&then_entry, &otherwise_entry, negate);
4757
4758 Fragment then_fragment(then_entry);
4759 then_fragment += TranslateStatement(node->then());
4760
4761 Fragment otherwise_fragment(otherwise_entry);
4762 otherwise_fragment += TranslateStatement(node->otherwise());
4763
4764 if (then_fragment.is_open()) {
4765 if (otherwise_fragment.is_open()) {
4766 JoinEntryInstr* join = BuildJoinEntry();
4767 then_fragment += Goto(join);
4768 otherwise_fragment += Goto(join);
4769 fragment_ = Fragment(instructions.entry, join);
4770 } else {
4771 fragment_ = Fragment(instructions.entry, then_fragment.current);
4772 }
4773 } else if (otherwise_fragment.is_open()) {
4774 fragment_ = Fragment(instructions.entry, otherwise_fragment.current);
4775 } else {
4776 fragment_ = instructions.closed();
4777 }
4778 }
4779
4780
4781 void FlowGraphBuilder::VisitWhileStatement(WhileStatement* node) {
4782 ++loop_depth_;
4783 bool negate;
4784 Fragment condition = TranslateCondition(node->condition(), &negate);
4785 TargetEntryInstr* body_entry;
4786 TargetEntryInstr* loop_exit;
4787 condition += BranchIfTrue(&body_entry, &loop_exit, negate);
4788
4789 Fragment body(body_entry);
4790 body += TranslateStatement(node->body());
4791
4792 Instruction* entry;
4793 if (body.is_open()) {
4794 JoinEntryInstr* join = BuildJoinEntry();
4795 body += Goto(join);
4796
4797 Fragment loop(join);
4798 loop += CheckStackOverflow();
4799 loop += condition;
4800 entry = new (Z) GotoInstr(join);
4801 } else {
4802 entry = condition.entry;
4803 }
4804
4805
4806 fragment_ = Fragment(entry, loop_exit);
4807 --loop_depth_;
4808 }
4809
4810
4811 void FlowGraphBuilder::VisitDoStatement(DoStatement* node) {
4812 ++loop_depth_;
4813 Fragment body = TranslateStatement(node->body());
4814
4815 if (body.is_closed()) {
4816 fragment_ = body;
4817 --loop_depth_;
4818 return;
4819 }
4820
4821 bool negate;
4822 JoinEntryInstr* join = BuildJoinEntry();
4823 Fragment loop(join);
4824 loop += CheckStackOverflow();
4825 loop += body;
4826 loop += TranslateCondition(node->condition(), &negate);
4827 TargetEntryInstr* loop_repeat;
4828 TargetEntryInstr* loop_exit;
4829 loop += BranchIfTrue(&loop_repeat, &loop_exit, negate);
4830
4831 Fragment repeat(loop_repeat);
4832 repeat += Goto(join);
4833
4834 fragment_ = Fragment(new (Z) GotoInstr(join), loop_exit);
4835 --loop_depth_;
4836 }
4837
4838
4839 void FlowGraphBuilder::VisitForStatement(ForStatement* node) {
4840 Fragment declarations;
4841
4842 bool new_context = false;
4843 declarations += EnterScope(node, &new_context);
4844
4845 List<VariableDeclaration>& variables = node->variables();
4846 for (intptr_t i = 0; i < variables.length(); ++i) {
4847 declarations += TranslateStatement(variables[i]);
4848 }
4849
4850 ++loop_depth_;
4851 bool negate = false;
4852 Fragment condition = node->condition() == NULL
4853 ? Constant(Bool::True())
4854 : TranslateCondition(node->condition(), &negate);
4855 TargetEntryInstr* body_entry;
4856 TargetEntryInstr* loop_exit;
4857 condition += BranchIfTrue(&body_entry, &loop_exit, negate);
4858
4859 Fragment body(body_entry);
4860 body += TranslateStatement(node->body());
4861
4862 if (body.is_open()) {
4863 // We allocated a fresh context before the loop which contains captured
4864 // [ForStatement] variables. Before jumping back to the loop entry we clone
4865 // the context object (at same depth) which ensures the next iteration of
4866 // the body gets a fresh set of [ForStatement] variables (with the old
4867 // (possibly updated) values).
4868 if (new_context) body += CloneContext();
4869
4870 List<Expression>& updates = node->updates();
4871 for (intptr_t i = 0; i < updates.length(); ++i) {
4872 body += TranslateExpression(updates[i]);
4873 body += Drop();
4874 }
4875 JoinEntryInstr* join = BuildJoinEntry();
4876 declarations += Goto(join);
4877 body += Goto(join);
4878
4879 Fragment loop(join);
4880 loop += CheckStackOverflow();
4881 loop += condition;
4882 } else {
4883 declarations += condition;
4884 }
4885
4886 Fragment loop(declarations.entry, loop_exit);
4887 --loop_depth_;
4888
4889 loop += ExitScope(node);
4890
4891 fragment_ = loop;
4892 }
4893
4894
4895 void FlowGraphBuilder::VisitForInStatement(ForInStatement* node) {
4896 Fragment instructions = TranslateExpression(node->iterable());
4897 instructions += PushArgument();
4898
4899 const dart::String& iterator_getter = dart::String::ZoneHandle(
4900 Z, dart::Field::GetterSymbol(Symbols::Iterator()));
4901 instructions += InstanceCall(iterator_getter, Token::kGET, 1);
4902 LocalVariable* iterator = scopes_->iterator_variables[for_in_depth_];
4903 instructions += StoreLocal(iterator);
4904 instructions += Drop();
4905
4906 ++for_in_depth_;
4907 ++loop_depth_;
4908 Fragment condition = LoadLocal(iterator);
4909 condition += PushArgument();
4910 condition += InstanceCall(Symbols::MoveNext(), Token::kILLEGAL, 1);
4911 TargetEntryInstr* body_entry;
4912 TargetEntryInstr* loop_exit;
4913 condition += BranchIfTrue(&body_entry, &loop_exit);
4914
4915 Fragment body(body_entry);
4916 body += EnterScope(node);
4917 body += LoadLocal(iterator);
4918 body += PushArgument();
4919 const dart::String& current_getter = dart::String::ZoneHandle(
4920 Z, dart::Field::GetterSymbol(Symbols::Current()));
4921 body += InstanceCall(current_getter, Token::kGET, 1);
4922 body += StoreLocal(LookupVariable(node->variable()));
4923 body += Drop();
4924 body += TranslateStatement(node->body());
4925 body += ExitScope(node);
4926
4927 if (body.is_open()) {
4928 JoinEntryInstr* join = BuildJoinEntry();
4929 instructions += Goto(join);
4930 body += Goto(join);
4931
4932 Fragment loop(join);
4933 loop += CheckStackOverflow();
4934 loop += condition;
4935 } else {
4936 instructions += condition;
4937 }
4938
4939 fragment_ = Fragment(instructions.entry, loop_exit);
4940 --loop_depth_;
4941 --for_in_depth_;
4942 }
4943
4944
4945 void FlowGraphBuilder::VisitLabeledStatement(LabeledStatement* node) {
4946 // There can be serveral cases:
4947 //
4948 // * the body contains a break
4949 // * the body doesn't contain a break
4950 //
4951 // * translating the body results in a closed fragment
4952 // * translating the body results in a open fragment
4953 //
4954 // => We will only know which case we are in after the body has been
4955 // traversed.
4956
4957 BreakableBlock block(this, node);
4958 Fragment instructions = TranslateStatement(node->body());
4959 if (block.HadJumper()) {
4960 if (instructions.is_open()) {
4961 instructions += Goto(block.destination());
4962 }
4963 fragment_ = Fragment(instructions.entry, block.destination());
4964 } else {
4965 fragment_ = instructions;
4966 }
4967 }
4968
4969
4970 void FlowGraphBuilder::VisitBreakStatement(BreakStatement* node) {
4971 TryFinallyBlock* outer_finally = NULL;
4972 intptr_t target_context_depth = -1;
4973 JoinEntryInstr* destination = breakable_block_->BreakDestination(
4974 node->target(), &outer_finally, &target_context_depth);
4975
4976 Fragment instructions;
4977 instructions +=
4978 TranslateFinallyFinalizers(outer_finally, target_context_depth);
4979 if (instructions.is_open()) {
4980 instructions += Goto(destination);
4981 }
4982 fragment_ = instructions;
4983 }
4984
4985
4986 void FlowGraphBuilder::VisitSwitchStatement(SwitchStatement* node) {
4987 SwitchBlock block(this, node);
4988
4989 // Instead of using a variable we should reuse the expression on the stack,
4990 // since it won't be assigned again, we don't need phi nodes.
4991 Fragment head_instructions = TranslateExpression(node->condition());
4992 head_instructions += StoreLocal(scopes_->switch_variable);
4993 head_instructions += Drop();
4994
4995 // Phase 1: Generate bodies and try to find out whether a body will be target
4996 // of a jump due to:
4997 // * `continue case_label`
4998 // * `case e1: case e2: body`
4999 Fragment* body_fragments = new Fragment[node->cases().length()];
5000
5001 intptr_t num_cases = node->cases().length();
5002 for (intptr_t i = 0; i < num_cases; i++) {
5003 SwitchCase* switch_case = node->cases()[i];
5004 Fragment& body_fragment = body_fragments[i] =
5005 TranslateStatement(switch_case->body());
5006
5007 if (body_fragment.entry == NULL) {
5008 // Make a NOP in order to ensure linking works properly.
5009 body_fragment = NullConstant();
5010 body_fragment += Drop();
5011 }
5012
5013 // The Dart language specification mandates fall-throughs in [SwitchCase]es
5014 // to be runtime errors.
5015 if (!switch_case->is_default() && body_fragment.is_open() &&
5016 (i < (node->cases().length() - 1))) {
5017 const dart::Class& klass = dart::Class::ZoneHandle(
5018 Z, dart::Library::LookupCoreClass(Symbols::FallThroughError()));
5019 ASSERT(!klass.IsNull());
5020 const dart::Function& constructor = dart::Function::ZoneHandle(
5021 Z, klass.LookupConstructorAllowPrivate(
5022 H.DartSymbol("FallThroughError._create")));
5023 ASSERT(!constructor.IsNull());
5024 const dart::String& url = H.DartString(
5025 parsed_function_->function().ToLibNamePrefixedQualifiedCString(),
5026 Heap::kOld);
5027
5028 // Create instance of _FallThroughError
5029 body_fragment += AllocateObject(klass, 0);
5030 LocalVariable* instance = MakeTemporary();
5031
5032 // Call _AssertionError._create constructor.
5033 body_fragment += LoadLocal(instance);
5034 body_fragment += PushArgument(); // this
5035
5036 body_fragment += Constant(url);
5037 body_fragment += PushArgument(); // url
5038
5039 body_fragment += NullConstant();
5040 body_fragment += PushArgument(); // line
5041
5042 body_fragment += StaticCall(constructor, 3);
5043 body_fragment += Drop();
5044
5045 // Throw the exception
5046 body_fragment += PushArgument();
5047 body_fragment += ThrowException();
5048 body_fragment += Drop();
5049 }
5050
5051 // If there is an implicit fall-through we have one [SwitchCase] and
5052 // multiple expressions, e.g.
5053 //
5054 // switch(expr) {
5055 // case a:
5056 // case b:
5057 // <stmt-body>
5058 // }
5059 //
5060 // This means that the <stmt-body> will have more than 1 incoming edge (one
5061 // from `a == expr` and one from `a != expr && b == expr`). The
5062 // `block.Destination()` records the additional jump.
5063 if (switch_case->expressions().length() > 1) {
5064 block.Destination(switch_case);
5065 }
5066 }
5067
5068 // Phase 2: Generate everything except the real bodies:
5069 // * jump directly to a body (if there is no jumper)
5070 // * jump to a wrapper block which jumps to the body (if there is a jumper)
5071 Fragment current_instructions = head_instructions;
5072 for (intptr_t i = 0; i < num_cases; i++) {
5073 SwitchCase* switch_case = node->cases()[i];
5074
5075 if (switch_case->is_default()) {
5076 ASSERT(i == (node->cases().length() - 1));
5077
5078 // Evaluate the conditions for the default [SwitchCase] just for the
5079 // purpose of potentially triggering a compile-time error.
5080 for (intptr_t k = 0; k < switch_case->expressions().length(); k++) {
5081 constant_evaluator_.EvaluateExpression(switch_case->expressions()[k]);
5082 }
5083
5084 if (block.HadJumper(switch_case)) {
5085 // There are several branches to the body, so we will make a goto to
5086 // the join block (and prepend a join instruction to the real body).
5087 JoinEntryInstr* join = block.Destination(switch_case);
5088 current_instructions += Goto(join);
5089
5090 current_instructions = Fragment(current_instructions.entry, join);
5091 current_instructions += body_fragments[i];
5092 } else {
5093 current_instructions += body_fragments[i];
5094 }
5095 } else {
5096 JoinEntryInstr* body_join = NULL;
5097 if (block.HadJumper(switch_case)) {
5098 body_join = block.Destination(switch_case);
5099 body_fragments[i] = Fragment(body_join) + body_fragments[i];
5100 }
5101
5102 for (intptr_t j = 0; j < switch_case->expressions().length(); j++) {
5103 TargetEntryInstr* then;
5104 TargetEntryInstr* otherwise;
5105
5106 current_instructions += Constant(constant_evaluator_.EvaluateExpression(
5107 switch_case->expressions()[j]));
5108 current_instructions += PushArgument();
5109 current_instructions += LoadLocal(scopes_->switch_variable);
5110 current_instructions += PushArgument();
5111 current_instructions +=
5112 InstanceCall(Symbols::EqualOperator(), Token::kEQ,
5113 /*argument_count=*/2,
5114 /*num_args_checked=*/2);
5115 current_instructions += BranchIfTrue(&then, &otherwise);
5116
5117 Fragment then_fragment(then);
5118
5119 if (body_join != NULL) {
5120 // There are several branches to the body, so we will make a goto to
5121 // the join block (the real body has already been prepended with a
5122 // join instruction).
5123 then_fragment += Goto(body_join);
5124 } else {
5125 // There is only a signle branch to the body, so we will just append
5126 // the body fragment.
5127 then_fragment += body_fragments[i];
5128 }
5129
5130 current_instructions = Fragment(otherwise);
5131 }
5132 }
5133 }
5134
5135 bool has_no_default =
5136 num_cases > 0 && !node->cases()[num_cases - 1]->is_default();
5137 if (has_no_default) {
5138 // There is no default, which means we have an open [current_instructions]
5139 // (which is a [TargetEntryInstruction] for the last "otherwise" branch).
5140 //
5141 // Furthermore the last [SwitchCase] can be open as well. If so, we need
5142 // to join these two.
5143 Fragment& last_body = body_fragments[node->cases().length() - 1];
5144 if (last_body.is_open()) {
5145 ASSERT(current_instructions.is_open());
5146 ASSERT(current_instructions.current->IsTargetEntry());
5147
5148 // Join the last "otherwise" branch and the last [SwitchCase] fragment.
5149 JoinEntryInstr* join = BuildJoinEntry();
5150 current_instructions += Goto(join);
5151 last_body += Goto(join);
5152
5153 current_instructions = Fragment(join);
5154 }
5155 } else {
5156 // All non-default cases will be closed (i.e. break/continue/throw/return)
5157 // So it is fine to just let more statements after the switch append to the
5158 // default case.
5159 }
5160
5161 delete[] body_fragments;
5162
5163 fragment_ = Fragment(head_instructions.entry, current_instructions.current);
5164 }
5165
5166
5167 void FlowGraphBuilder::VisitContinueSwitchStatement(
5168 ContinueSwitchStatement* node) {
5169 TryFinallyBlock* outer_finally = NULL;
5170 intptr_t target_context_depth = -1;
5171 JoinEntryInstr* entry = switch_block_->Destination(
5172 node->target(), &outer_finally, &target_context_depth);
5173
5174 Fragment instructions;
5175 instructions +=
5176 TranslateFinallyFinalizers(outer_finally, target_context_depth);
5177 if (instructions.is_open()) {
5178 instructions += Goto(entry);
5179 }
5180 fragment_ = instructions;
5181 }
5182
5183
5184 void FlowGraphBuilder::VisitAssertStatement(AssertStatement* node) {
5185 if (!I->asserts()) {
5186 fragment_ = Fragment();
5187 return;
5188 }
5189
5190 TargetEntryInstr* then;
5191 TargetEntryInstr* otherwise;
5192
5193 bool negate;
5194 Fragment instructions;
5195 instructions += TranslateCondition(node->condition(), &negate);
5196 instructions += BranchIfTrue(&then, &otherwise, negate);
5197
5198 const dart::Class& klass = dart::Class::ZoneHandle(
5199 Z, dart::Library::LookupCoreClass(Symbols::AssertionError()));
5200 ASSERT(!klass.IsNull());
5201 const dart::Function& constructor = dart::Function::ZoneHandle(
5202 Z, klass.LookupConstructorAllowPrivate(
5203 H.DartSymbol("_AssertionError._create")));
5204 ASSERT(!constructor.IsNull());
5205
5206 const dart::String& url = H.DartString(
5207 parsed_function_->function().ToLibNamePrefixedQualifiedCString(),
5208 Heap::kOld);
5209
5210 // Create instance of _AssertionError
5211 Fragment otherwise_fragment(otherwise);
5212 otherwise_fragment += AllocateObject(klass, 0);
5213 LocalVariable* instance = MakeTemporary();
5214
5215 // Call _AssertionError._create constructor.
5216 otherwise_fragment += LoadLocal(instance);
5217 otherwise_fragment += PushArgument(); // this
5218
5219 otherwise_fragment +=
5220 node->message() != NULL
5221 ? TranslateExpression(node->message())
5222 : Constant(H.DartString("<no message>", Heap::kOld));
5223 otherwise_fragment += PushArgument(); // message
5224
5225 otherwise_fragment += Constant(url);
5226 otherwise_fragment += PushArgument(); // url
5227
5228 otherwise_fragment += IntConstant(0);
5229 otherwise_fragment += PushArgument(); // line
5230
5231 otherwise_fragment += IntConstant(0);
5232 otherwise_fragment += PushArgument(); // column
5233
5234 otherwise_fragment += StaticCall(constructor, 5);
5235 otherwise_fragment += Drop();
5236
5237 // Throw _AssertionError exception.
5238 otherwise_fragment += PushArgument();
5239 otherwise_fragment += ThrowException();
5240 otherwise_fragment += Drop();
5241
5242 fragment_ = Fragment(instructions.entry, then);
5243 }
5244
5245
5246 void FlowGraphBuilder::VisitTryFinally(TryFinally* node) {
5247 InlineBailout("kernel::FlowgraphBuilder::VisitTryFinally");
5248
5249 // There are 5 different cases where we need to execute the finally block:
5250 //
5251 // a) 1/2/3th case: Special control flow going out of `node->body()`:
5252 //
5253 // * [BreakStatement] transfers control to a [LabledStatement]
5254 // * [ContinueSwitchStatement] transfers control to a [SwitchCase]
5255 // * [ReturnStatement] returns a value
5256 //
5257 // => All three cases will automatically append all finally blocks
5258 // between the branching point and the destination (so we don't need to
5259 // do anything here).
5260 //
5261 // b) 4th case: Translating the body resulted in an open fragment (i.e. body
5262 // executes without any control flow out of it)
5263 //
5264 // => We are responsible for jumping out of the body to a new block (with
5265 // different try index) and execute the finalizer.
5266 //
5267 // c) 5th case: An exception occured inside the body.
5268 //
5269 // => We are responsible for catching it, executing the finally block and
5270 // rethrowing the exception.
5271 intptr_t try_handler_index = AllocateTryIndex();
5272 Fragment try_body = TryCatch(try_handler_index);
5273 JoinEntryInstr* after_try = BuildJoinEntry();
5274
5275 // Fill in the body of the try.
5276 ++try_depth_;
5277 {
5278 TryCatchBlock tcb(this, try_handler_index);
5279 TryFinallyBlock tfb(this, node->finalizer());
5280 try_body += TranslateStatement(node->body());
5281 }
5282 --try_depth_;
5283
5284 if (try_body.is_open()) {
5285 // Please note: The try index will be on level out of this block,
5286 // thereby ensuring if there's an exception in the finally block we
5287 // won't run it twice.
5288 JoinEntryInstr* finally_entry = BuildJoinEntry();
5289
5290 try_body += Goto(finally_entry);
5291
5292 Fragment finally_body(finally_entry);
5293 finally_body += TranslateStatement(node->finalizer());
5294 finally_body += Goto(after_try);
5295 }
5296
5297 // Fill in the body of the catch.
5298 ++catch_depth_;
5299 const Array& handler_types = Array::ZoneHandle(Z, Array::New(1, Heap::kOld));
5300 handler_types.SetAt(0, Object::dynamic_type());
5301 Fragment finally_body = CatchBlockEntry(handler_types, try_handler_index);
5302 finally_body += TranslateStatement(node->finalizer());
5303 if (finally_body.is_open()) {
5304 finally_body += LoadLocal(CurrentException());
5305 finally_body += PushArgument();
5306 finally_body += LoadLocal(CurrentStackTrace());
5307 finally_body += PushArgument();
5308 finally_body += RethrowException(try_handler_index);
5309 Drop();
5310 }
5311 --catch_depth_;
5312
5313 fragment_ = Fragment(try_body.entry, after_try);
5314 }
5315
5316
5317 void FlowGraphBuilder::VisitTryCatch(class TryCatch* node) {
5318 InlineBailout("kernel::FlowgraphBuilder::VisitTryCatch");
5319
5320 intptr_t try_handler_index = AllocateTryIndex();
5321 Fragment try_body = TryCatch(try_handler_index);
5322 JoinEntryInstr* after_try = BuildJoinEntry();
5323
5324 // Fill in the body of the try.
5325 ++try_depth_;
5326 {
5327 TryCatchBlock block(this, try_handler_index);
5328 try_body += TranslateStatement(node->body());
5329 try_body += Goto(after_try);
5330 }
5331 --try_depth_;
5332
5333 ++catch_depth_;
5334 const Array& handler_types =
5335 Array::ZoneHandle(Z, Array::New(node->catches().length(), Heap::kOld));
5336 Fragment catch_body = CatchBlockEntry(handler_types, try_handler_index);
5337 // Fill in the body of the catch.
5338 for (intptr_t i = 0; i < node->catches().length(); i++) {
5339 Catch* catch_clause = node->catches()[i];
5340
5341 Fragment catch_handler_body;
5342
5343 catch_handler_body += EnterScope(catch_clause);
5344
5345 if (catch_clause->exception() != NULL) {
5346 catch_handler_body += LoadLocal(CurrentException());
5347 catch_handler_body +=
5348 StoreLocal(LookupVariable(catch_clause->exception()));
5349 catch_handler_body += Drop();
5350 }
5351 if (catch_clause->stack_trace() != NULL) {
5352 catch_handler_body += LoadLocal(CurrentStackTrace());
5353 catch_handler_body +=
5354 StoreLocal(LookupVariable(catch_clause->stack_trace()));
5355 catch_handler_body += Drop();
5356 }
5357 AbstractType* type_guard = NULL;
5358 if (catch_clause->guard() != NULL &&
5359 !catch_clause->guard()->IsDynamicType()) {
5360 type_guard = &T.TranslateType(catch_clause->guard());
5361 handler_types.SetAt(i, *type_guard);
5362 } else {
5363 handler_types.SetAt(i, Object::dynamic_type());
5364 }
5365
5366 {
5367 CatchBlock block(this, CurrentException(), CurrentStackTrace(),
5368 try_handler_index);
5369
5370 catch_handler_body += TranslateStatement(catch_clause->body());
5371
5372 // Note: ExitScope adjusts context_depth_ so even if catch_handler_body
5373 // is closed we still need to execute ExitScope for its side effect.
5374 catch_handler_body += ExitScope(catch_clause);
5375 if (catch_handler_body.is_open()) {
5376 catch_handler_body += Goto(after_try);
5377 }
5378 }
5379
5380 if (type_guard != NULL) {
5381 if (type_guard->IsMalformed()) {
5382 catch_body += ThrowTypeError();
5383 catch_body += Drop();
5384 } else {
5385 catch_body += LoadLocal(CurrentException());
5386 catch_body += PushArgument(); // exception
5387 catch_body += NullConstant();
5388 catch_body += PushArgument(); // type arguments
5389 catch_body += Constant(*type_guard);
5390 catch_body += PushArgument(); // guard type
5391 catch_body += Constant(Object::bool_false());
5392 catch_body += PushArgument(); // negate
5393 catch_body += InstanceCall(
5394 dart::Library::PrivateCoreLibName(Symbols::_instanceOf()),
5395 Token::kIS, 4);
5396
5397 TargetEntryInstr* catch_entry;
5398 TargetEntryInstr* next_catch_entry;
5399 catch_body += BranchIfTrue(&catch_entry, &next_catch_entry);
5400
5401 Fragment(catch_entry) + catch_handler_body;
5402 catch_body = Fragment(next_catch_entry);
5403 }
5404 } else {
5405 catch_body += catch_handler_body;
5406 }
5407 }
5408
5409 // In case the last catch body was not handling the exception and branching to
5410 // after the try block, we will rethrow the exception (i.e. no default catch
5411 // handler).
5412 if (catch_body.is_open()) {
5413 catch_body += LoadLocal(CurrentException());
5414 catch_body += PushArgument();
5415 catch_body += LoadLocal(CurrentStackTrace());
5416 catch_body += PushArgument();
5417 catch_body += RethrowException(try_handler_index);
5418 Drop();
5419 }
5420 --catch_depth_;
5421
5422 fragment_ = Fragment(try_body.entry, after_try);
5423 }
5424
5425
5426 void FlowGraphBuilder::VisitYieldStatement(YieldStatement* node) {
5427 ASSERT(node->is_native()); // Must have been desugared.
5428 // Setup yield/continue point:
5429 //
5430 // ...
5431 // :await_jump_var = index;
5432 // :await_ctx_var = :current_context_var
5433 // return <expr>
5434 //
5435 // Continuation<index>:
5436 // Drop(1)
5437 // ...
5438 //
5439 // BuildGraphOfFunction will create a dispatch that jumps to
5440 // Continuation<:await_jump_var> upon entry to the function.
5441 //
5442 Fragment instructions = IntConstant(yield_continuations_.length() + 1);
5443 instructions += StoreLocal(scopes_->yield_jump_variable);
5444 instructions += Drop();
5445 instructions += LoadLocal(parsed_function_->current_context_var());
5446 instructions += StoreLocal(scopes_->yield_context_variable);
5447 instructions += Drop();
5448 instructions += TranslateExpression(node->expression());
5449 instructions += Return();
5450
5451 // Note: DropTempsInstr serves as an anchor instruction. It will not
5452 // be linked into the resulting graph.
5453 DropTempsInstr* anchor = new (Z) DropTempsInstr(0, NULL);
5454 yield_continuations_.Add(YieldContinuation(anchor, CurrentTryIndex()));
5455
5456 Fragment continuation(instructions.entry, anchor);
5457
5458 // TODO(27590): we need a better way to detect if we need to check for an
5459 // exception after yield or not.
5460 if (parsed_function_->function().NumOptionalPositionalParameters() == 3) {
5461 // If function takes three parameters then the second and the third
5462 // are exception and stack_trace. Check if exception is non-null
5463 // and rethrow it.
5464 //
5465 // :async_op([:result, :exception, :stack_trace]) {
5466 // ...
5467 // Continuation<index>:
5468 // if (:exception != null) rethrow(:exception, :stack_trace);
5469 // ...
5470 // }
5471 //
5472 LocalScope* scope = parsed_function_->node_sequence()->scope();
5473 LocalVariable* exception_var = scope->VariableAt(2);
5474 LocalVariable* stack_trace_var = scope->VariableAt(3);
5475 ASSERT(exception_var->name().raw() == Symbols::ExceptionParameter().raw());
5476 ASSERT(stack_trace_var->name().raw() ==
5477 Symbols::StackTraceParameter().raw());
5478
5479 TargetEntryInstr* no_error;
5480 TargetEntryInstr* error;
5481
5482 continuation += LoadLocal(exception_var);
5483 continuation += BranchIfNull(&no_error, &error);
5484
5485 Fragment rethrow(error);
5486 rethrow += LoadLocal(exception_var);
5487 rethrow += PushArgument();
5488 rethrow += LoadLocal(stack_trace_var);
5489 rethrow += PushArgument();
5490 rethrow += RethrowException(CatchClauseNode::kInvalidTryIndex);
5491 Drop();
5492
5493
5494 continuation = Fragment(continuation.entry, no_error);
5495 }
5496
5497 fragment_ = continuation;
5498 }
5499
5500
5501 Fragment FlowGraphBuilder::TranslateFunctionNode(FunctionNode* node,
5502 TreeNode* parent) {
5503 // The VM has a per-isolate table of functions indexed by the enclosing
5504 // function and token position. We don't have token positions, so we've
5505 // simply numbered the immediately-nested functions with respect to the
5506 // parent.
5507 Function& function = Function::ZoneHandle(Z);
5508 for (intptr_t i = 0; i < scopes_->function_scopes.length(); ++i) {
5509 if (scopes_->function_scopes[i].function != node) continue;
5510
5511 function = I->LookupClosureFunction(parsed_function_->function(),
5512 TokenPosition(i));
5513 if (function.IsNull()) {
5514 const dart::String* name;
5515 if (parent->IsFunctionExpression()) {
5516 name = &Symbols::AnonymousClosure();
5517 } else {
5518 ASSERT(parent->IsFunctionDeclaration());
5519 name = &H.DartSymbol(
5520 FunctionDeclaration::Cast(parent)->variable()->name());
5521 }
5522 function = Function::NewClosureFunction(
5523 *name, parsed_function_->function(), TokenPosition(i));
5524 function.set_is_debuggable(false);
5525 LocalScope* scope = scopes_->function_scopes[i].scope;
5526 const ContextScope& context_scope =
5527 ContextScope::Handle(Z, scope->PreserveOuterScope(context_depth_));
5528 function.set_context_scope(context_scope);
5529 function.set_kernel_function(node);
5530 KernelReader::SetupFunctionParameters(H, T, dart::Class::Handle(Z),
5531 function, node,
5532 false, // is_method
5533 true); // is_closure
5534 // Finalize function type.
5535 Type& signature_type = Type::Handle(Z, function.SignatureType());
5536 signature_type ^= ClassFinalizer::FinalizeType(
5537 *active_class_.klass, signature_type, ClassFinalizer::kCanonicalize);
5538 function.SetSignatureType(signature_type);
5539
5540 I->AddClosureFunction(function);
5541 }
5542 break;
5543 }
5544
5545 const dart::Class& closure_class =
5546 dart::Class::ZoneHandle(Z, I->object_store()->closure_class());
5547 ASSERT(!closure_class.IsNull());
5548 Fragment instructions = AllocateObject(closure_class, function);
5549 LocalVariable* closure = MakeTemporary();
5550
5551 // TODO(27590): Generic closures need type arguments.
5552
5553 // Store the function and the context in the closure.
5554 instructions += LoadLocal(closure);
5555 instructions += Constant(function);
5556 instructions += StoreInstanceField(Closure::function_offset());
5557
5558 instructions += LoadLocal(closure);
5559 instructions += LoadLocal(parsed_function_->current_context_var());
5560 instructions += StoreInstanceField(Closure::context_offset());
5561
5562 return instructions;
5563 }
5564
5565
5566 } // namespace kernel
5567 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/kernel_to_il.h ('k') | runtime/vm/object.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698