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

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

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

Powered by Google App Engine
This is Rietveld 408576698