| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/flow_graph_builder.h" | 5 #include "vm/flow_graph_builder.h" |
| 6 | 6 |
| 7 #include "vm/ast_printer.h" | 7 #include "vm/ast_printer.h" |
| 8 #include "vm/bit_vector.h" | 8 #include "vm/bit_vector.h" |
| 9 #include "vm/code_descriptors.h" | 9 #include "vm/code_descriptors.h" |
| 10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 199 } | 199 } |
| 200 | 200 |
| 201 | 201 |
| 202 PushArgumentInstr* EffectGraphVisitor::PushArgument(Value* value) { | 202 PushArgumentInstr* EffectGraphVisitor::PushArgument(Value* value) { |
| 203 PushArgumentInstr* result = new PushArgumentInstr(value); | 203 PushArgumentInstr* result = new PushArgumentInstr(value); |
| 204 AddInstruction(result); | 204 AddInstruction(result); |
| 205 return result; | 205 return result; |
| 206 } | 206 } |
| 207 | 207 |
| 208 | 208 |
| 209 Computation* EffectGraphVisitor::BuildStoreLocal( | 209 Computation* EffectGraphVisitor::BuildStoreLocal(const LocalVariable* local, |
| 210 const LocalVariable& local, Value* value) { | 210 Value* value) { |
| 211 if (local.is_captured()) { | 211 if (local->is_captured()) { |
| 212 intptr_t delta = owner()->context_level() - | 212 intptr_t delta = owner()->context_level() - |
| 213 local.owner()->context_level(); | 213 local->owner()->context_level(); |
| 214 ASSERT(delta >= 0); | 214 ASSERT(delta >= 0); |
| 215 Value* context = Bind(new CurrentContextComp()); | 215 Value* context = Bind(new CurrentContextComp()); |
| 216 while (delta-- > 0) { | 216 while (delta-- > 0) { |
| 217 context = Bind(new LoadVMFieldComp( | 217 context = Bind(new LoadVMFieldComp( |
| 218 context, Context::parent_offset(), Type::ZoneHandle())); | 218 context, Context::parent_offset(), Type::ZoneHandle())); |
| 219 } | 219 } |
| 220 return new StoreVMFieldComp( | 220 return new StoreVMFieldComp( |
| 221 context, | 221 context, |
| 222 Context::variable_offset(local.index()), | 222 Context::variable_offset(local->index()), |
| 223 value, | 223 value, |
| 224 local.type()); | 224 local->type()); |
| 225 } else { | 225 } else { |
| 226 return new StoreLocalComp(local, value, owner()->context_level()); | 226 return new StoreLocalComp(local, value, owner()->context_level()); |
| 227 } | 227 } |
| 228 } | 228 } |
| 229 | 229 |
| 230 | 230 |
| 231 Computation* EffectGraphVisitor::BuildLoadLocal(const LocalVariable& local) { | 231 Computation* EffectGraphVisitor::BuildLoadLocal(const LocalVariable* local) { |
| 232 if (local.is_captured()) { | 232 if (local->is_captured()) { |
| 233 intptr_t delta = owner()->context_level() - | 233 intptr_t delta = owner()->context_level() - |
| 234 local.owner()->context_level(); | 234 local->owner()->context_level(); |
| 235 ASSERT(delta >= 0); | 235 ASSERT(delta >= 0); |
| 236 Value* context = Bind(new CurrentContextComp()); | 236 Value* context = Bind(new CurrentContextComp()); |
| 237 while (delta-- > 0) { | 237 while (delta-- > 0) { |
| 238 context = Bind(new LoadVMFieldComp( | 238 context = Bind(new LoadVMFieldComp( |
| 239 context, Context::parent_offset(), Type::ZoneHandle())); | 239 context, Context::parent_offset(), Type::ZoneHandle())); |
| 240 } | 240 } |
| 241 return new LoadVMFieldComp(context, | 241 return new LoadVMFieldComp(context, |
| 242 Context::variable_offset(local.index()), | 242 Context::variable_offset(local->index()), |
| 243 local.type()); | 243 local->type()); |
| 244 } else { | 244 } else { |
| 245 return new LoadLocalComp(local, owner()->context_level()); | 245 return new LoadLocalComp(local, owner()->context_level()); |
| 246 } | 246 } |
| 247 } | 247 } |
| 248 | 248 |
| 249 | 249 |
| 250 // Stores current context into the 'variable' | 250 // Stores current context into the 'variable' |
| 251 void EffectGraphVisitor::BuildStoreContext(const LocalVariable& variable) { | 251 void EffectGraphVisitor::BuildStoreContext(const LocalVariable* variable) { |
| 252 Value* context = Bind(new CurrentContextComp()); | 252 Value* context = Bind(new CurrentContextComp()); |
| 253 Do(BuildStoreLocal(variable, context)); | 253 Do(BuildStoreLocal(variable, context)); |
| 254 } | 254 } |
| 255 | 255 |
| 256 | 256 |
| 257 // Loads context saved in 'context_variable' into the current context. | 257 // Loads context saved in 'context_variable' into the current context. |
| 258 void EffectGraphVisitor::BuildLoadContext(const LocalVariable& variable) { | 258 void EffectGraphVisitor::BuildLoadContext(const LocalVariable* variable) { |
| 259 Value* load_saved_context = Bind(BuildLoadLocal(variable)); | 259 Value* load_saved_context = Bind(BuildLoadLocal(variable)); |
| 260 Do(new StoreContextComp(load_saved_context)); | 260 Do(new StoreContextComp(load_saved_context)); |
| 261 } | 261 } |
| 262 | 262 |
| 263 | 263 |
| 264 void TestGraphVisitor::ReturnValue(Value* value) { | 264 void TestGraphVisitor::ReturnValue(Value* value) { |
| 265 if (FLAG_enable_type_checks) { | 265 if (FLAG_enable_type_checks) { |
| 266 value = Bind(new AssertBooleanComp(condition_token_pos(), | 266 value = Bind(new AssertBooleanComp(condition_token_pos(), |
| 267 owner()->try_index(), | 267 owner()->try_index(), |
| 268 value)); | 268 value)); |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 367 return_value, | 367 return_value, |
| 368 dst_type, | 368 dst_type, |
| 369 dst_name); | 369 dst_name); |
| 370 } | 370 } |
| 371 } | 371 } |
| 372 | 372 |
| 373 intptr_t current_context_level = owner()->context_level(); | 373 intptr_t current_context_level = owner()->context_level(); |
| 374 ASSERT(current_context_level >= 0); | 374 ASSERT(current_context_level >= 0); |
| 375 if (owner()->parsed_function().saved_context_var() != NULL) { | 375 if (owner()->parsed_function().saved_context_var() != NULL) { |
| 376 // CTX on entry was saved, but not linked as context parent. | 376 // CTX on entry was saved, but not linked as context parent. |
| 377 BuildLoadContext(*owner()->parsed_function().saved_context_var()); | 377 BuildLoadContext(owner()->parsed_function().saved_context_var()); |
| 378 } else { | 378 } else { |
| 379 while (current_context_level-- > 0) { | 379 while (current_context_level-- > 0) { |
| 380 UnchainContext(); | 380 UnchainContext(); |
| 381 } | 381 } |
| 382 } | 382 } |
| 383 | 383 |
| 384 AddInstruction(new ReturnInstr(node->token_pos(), return_value)); | 384 AddInstruction(new ReturnInstr(node->token_pos(), return_value)); |
| 385 CloseFragment(); | 385 CloseFragment(); |
| 386 } | 386 } |
| 387 | 387 |
| (...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 540 for_right.Bind(new AssertBooleanComp(node->right()->token_pos(), | 540 for_right.Bind(new AssertBooleanComp(node->right()->token_pos(), |
| 541 owner()->try_index(), | 541 owner()->try_index(), |
| 542 right_value)); | 542 right_value)); |
| 543 } | 543 } |
| 544 Value* constant_true = for_right.Bind(new ConstantVal(bool_true)); | 544 Value* constant_true = for_right.Bind(new ConstantVal(bool_true)); |
| 545 Value* compare = | 545 Value* compare = |
| 546 for_right.Bind(new StrictCompareComp(Token::kEQ_STRICT, | 546 for_right.Bind(new StrictCompareComp(Token::kEQ_STRICT, |
| 547 right_value, | 547 right_value, |
| 548 constant_true)); | 548 constant_true)); |
| 549 for_right.Do(BuildStoreLocal( | 549 for_right.Do(BuildStoreLocal( |
| 550 *owner()->parsed_function().expression_temp_var(), | 550 owner()->parsed_function().expression_temp_var(), |
| 551 compare)); | 551 compare)); |
| 552 | 552 |
| 553 if (node->kind() == Token::kAND) { | 553 if (node->kind() == Token::kAND) { |
| 554 ValueGraphVisitor for_false(owner(), temp_index()); | 554 ValueGraphVisitor for_false(owner(), temp_index()); |
| 555 Value* constant_false = for_false.Bind(new ConstantVal(bool_false)); | 555 Value* constant_false = for_false.Bind(new ConstantVal(bool_false)); |
| 556 for_false.Do(BuildStoreLocal( | 556 for_false.Do(BuildStoreLocal( |
| 557 *owner()->parsed_function().expression_temp_var(), | 557 owner()->parsed_function().expression_temp_var(), |
| 558 constant_false)); | 558 constant_false)); |
| 559 Join(for_test, for_right, for_false); | 559 Join(for_test, for_right, for_false); |
| 560 } else { | 560 } else { |
| 561 ASSERT(node->kind() == Token::kOR); | 561 ASSERT(node->kind() == Token::kOR); |
| 562 ValueGraphVisitor for_true(owner(), temp_index()); | 562 ValueGraphVisitor for_true(owner(), temp_index()); |
| 563 Value* constant_true = for_true.Bind(new ConstantVal(bool_true)); | 563 Value* constant_true = for_true.Bind(new ConstantVal(bool_true)); |
| 564 for_true.Do(BuildStoreLocal( | 564 for_true.Do(BuildStoreLocal( |
| 565 *owner()->parsed_function().expression_temp_var(), | 565 owner()->parsed_function().expression_temp_var(), |
| 566 constant_true)); | 566 constant_true)); |
| 567 Join(for_test, for_true, for_right); | 567 Join(for_test, for_true, for_right); |
| 568 } | 568 } |
| 569 ReturnComputation( | 569 ReturnComputation( |
| 570 BuildLoadLocal(*owner()->parsed_function().expression_temp_var())); | 570 BuildLoadLocal(owner()->parsed_function().expression_temp_var())); |
| 571 return; | 571 return; |
| 572 } | 572 } |
| 573 EffectGraphVisitor::VisitBinaryOpNode(node); | 573 EffectGraphVisitor::VisitBinaryOpNode(node); |
| 574 } | 574 } |
| 575 | 575 |
| 576 | 576 |
| 577 void EffectGraphVisitor::BuildTypecheckArguments( | 577 void EffectGraphVisitor::BuildTypecheckArguments( |
| 578 intptr_t token_pos, | 578 intptr_t token_pos, |
| 579 Value** instantiator_result, | 579 Value** instantiator_result, |
| 580 Value** instantiator_type_arguments_result) { | 580 Value** instantiator_type_arguments_result) { |
| 581 Value* instantiator = NULL; | 581 Value* instantiator = NULL; |
| 582 Value* instantiator_type_arguments = NULL; | 582 Value* instantiator_type_arguments = NULL; |
| 583 const Class& instantiator_class = Class::Handle( | 583 const Class& instantiator_class = Class::Handle( |
| 584 owner()->parsed_function().function().owner()); | 584 owner()->parsed_function().function().owner()); |
| 585 // Since called only when type tested against is not instantiated. | 585 // Since called only when type tested against is not instantiated. |
| 586 ASSERT(instantiator_class.NumTypeParameters() > 0); | 586 ASSERT(instantiator_class.NumTypeParameters() > 0); |
| 587 instantiator = BuildInstantiator(); | 587 instantiator = BuildInstantiator(); |
| 588 if (instantiator == NULL) { | 588 if (instantiator == NULL) { |
| 589 // No instantiator when inside factory. | 589 // No instantiator when inside factory. |
| 590 instantiator = BuildNullValue(); | 590 instantiator = BuildNullValue(); |
| 591 instantiator_type_arguments = | 591 instantiator_type_arguments = |
| 592 BuildInstantiatorTypeArguments(token_pos, NULL); | 592 BuildInstantiatorTypeArguments(token_pos, NULL); |
| 593 } else { | 593 } else { |
| 594 // Preserve instantiator. | 594 // Preserve instantiator. |
| 595 const LocalVariable& expr_temp = | 595 const LocalVariable* expr_temp = |
| 596 *owner()->parsed_function().expression_temp_var(); | 596 owner()->parsed_function().expression_temp_var(); |
| 597 instantiator = Bind(BuildStoreLocal(expr_temp, instantiator)); | 597 instantiator = Bind(BuildStoreLocal(expr_temp, instantiator)); |
| 598 Value* loaded = Bind(BuildLoadLocal(expr_temp)); | 598 Value* loaded = Bind(BuildLoadLocal(expr_temp)); |
| 599 instantiator_type_arguments = | 599 instantiator_type_arguments = |
| 600 BuildInstantiatorTypeArguments(token_pos, loaded); | 600 BuildInstantiatorTypeArguments(token_pos, loaded); |
| 601 } | 601 } |
| 602 *instantiator_result = instantiator; | 602 *instantiator_result = instantiator; |
| 603 *instantiator_type_arguments_result = instantiator_type_arguments; | 603 *instantiator_type_arguments_result = instantiator_type_arguments; |
| 604 } | 604 } |
| 605 | 605 |
| 606 | 606 |
| (...skipping 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 880 void ValueGraphVisitor::VisitConditionalExprNode(ConditionalExprNode* node) { | 880 void ValueGraphVisitor::VisitConditionalExprNode(ConditionalExprNode* node) { |
| 881 TestGraphVisitor for_test(owner(), | 881 TestGraphVisitor for_test(owner(), |
| 882 temp_index(), | 882 temp_index(), |
| 883 node->condition()->token_pos()); | 883 node->condition()->token_pos()); |
| 884 node->condition()->Visit(&for_test); | 884 node->condition()->Visit(&for_test); |
| 885 | 885 |
| 886 ValueGraphVisitor for_true(owner(), temp_index()); | 886 ValueGraphVisitor for_true(owner(), temp_index()); |
| 887 node->true_expr()->Visit(&for_true); | 887 node->true_expr()->Visit(&for_true); |
| 888 ASSERT(for_true.is_open()); | 888 ASSERT(for_true.is_open()); |
| 889 for_true.Do(BuildStoreLocal( | 889 for_true.Do(BuildStoreLocal( |
| 890 *owner()->parsed_function().expression_temp_var(), for_true.value())); | 890 owner()->parsed_function().expression_temp_var(), for_true.value())); |
| 891 | 891 |
| 892 ValueGraphVisitor for_false(owner(), temp_index()); | 892 ValueGraphVisitor for_false(owner(), temp_index()); |
| 893 node->false_expr()->Visit(&for_false); | 893 node->false_expr()->Visit(&for_false); |
| 894 ASSERT(for_false.is_open()); | 894 ASSERT(for_false.is_open()); |
| 895 for_false.Do(BuildStoreLocal( | 895 for_false.Do(BuildStoreLocal( |
| 896 *owner()->parsed_function().expression_temp_var(), for_false.value())); | 896 owner()->parsed_function().expression_temp_var(), for_false.value())); |
| 897 | 897 |
| 898 Join(for_test, for_true, for_false); | 898 Join(for_test, for_true, for_false); |
| 899 ReturnComputation( | 899 ReturnComputation( |
| 900 BuildLoadLocal(*owner()->parsed_function().expression_temp_var())); | 900 BuildLoadLocal(owner()->parsed_function().expression_temp_var())); |
| 901 } | 901 } |
| 902 | 902 |
| 903 | 903 |
| 904 // <Statement> ::= If { condition: <Expression> | 904 // <Statement> ::= If { condition: <Expression> |
| 905 // true_branch: <Sequence> | 905 // true_branch: <Sequence> |
| 906 // false_branch: <Sequence> } | 906 // false_branch: <Sequence> } |
| 907 void EffectGraphVisitor::VisitIfNode(IfNode* node) { | 907 void EffectGraphVisitor::VisitIfNode(IfNode* node) { |
| 908 TestGraphVisitor for_test(owner(), | 908 TestGraphVisitor for_test(owner(), |
| 909 temp_index(), | 909 temp_index(), |
| 910 node->condition()->token_pos()); | 910 node->condition()->token_pos()); |
| (...skipping 494 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1405 node->closure()->Visit(&for_closure); | 1405 node->closure()->Visit(&for_closure); |
| 1406 Append(for_closure); | 1406 Append(for_closure); |
| 1407 PushArgumentInstr* push_closure = PushArgument(for_closure.value()); | 1407 PushArgumentInstr* push_closure = PushArgument(for_closure.value()); |
| 1408 | 1408 |
| 1409 ZoneGrowableArray<PushArgumentInstr*>* arguments = | 1409 ZoneGrowableArray<PushArgumentInstr*>* arguments = |
| 1410 new ZoneGrowableArray<PushArgumentInstr*>(node->arguments()->length()); | 1410 new ZoneGrowableArray<PushArgumentInstr*>(node->arguments()->length()); |
| 1411 arguments->Add(push_closure); | 1411 arguments->Add(push_closure); |
| 1412 BuildPushArguments(*node->arguments(), arguments); | 1412 BuildPushArguments(*node->arguments(), arguments); |
| 1413 | 1413 |
| 1414 // Save context around the call. | 1414 // Save context around the call. |
| 1415 BuildStoreContext(*owner()->parsed_function().expression_temp_var()); | 1415 BuildStoreContext(owner()->parsed_function().expression_temp_var()); |
| 1416 return new ClosureCallComp(node, owner()->try_index(), arguments); | 1416 return new ClosureCallComp(node, owner()->try_index(), arguments); |
| 1417 } | 1417 } |
| 1418 | 1418 |
| 1419 | 1419 |
| 1420 void EffectGraphVisitor::VisitClosureCallNode(ClosureCallNode* node) { | 1420 void EffectGraphVisitor::VisitClosureCallNode(ClosureCallNode* node) { |
| 1421 Do(BuildClosureCall(node)); | 1421 Do(BuildClosureCall(node)); |
| 1422 // Restore context from saved location. | 1422 // Restore context from saved location. |
| 1423 BuildLoadContext(*owner()->parsed_function().expression_temp_var()); | 1423 BuildLoadContext(owner()->parsed_function().expression_temp_var()); |
| 1424 } | 1424 } |
| 1425 | 1425 |
| 1426 | 1426 |
| 1427 void ValueGraphVisitor::VisitClosureCallNode(ClosureCallNode* node) { | 1427 void ValueGraphVisitor::VisitClosureCallNode(ClosureCallNode* node) { |
| 1428 Value* result = Bind(BuildClosureCall(node)); | 1428 Value* result = Bind(BuildClosureCall(node)); |
| 1429 // Restore context from temp. | 1429 // Restore context from temp. |
| 1430 BuildLoadContext(*owner()->parsed_function().expression_temp_var()); | 1430 BuildLoadContext(owner()->parsed_function().expression_temp_var()); |
| 1431 ReturnValue(result); | 1431 ReturnValue(result); |
| 1432 } | 1432 } |
| 1433 | 1433 |
| 1434 | 1434 |
| 1435 void EffectGraphVisitor::VisitCloneContextNode(CloneContextNode* node) { | 1435 void EffectGraphVisitor::VisitCloneContextNode(CloneContextNode* node) { |
| 1436 Value* context = Bind(new CurrentContextComp()); | 1436 Value* context = Bind(new CurrentContextComp()); |
| 1437 Value* clone = Bind(new CloneContextComp(node->token_pos(), | 1437 Value* clone = Bind(new CloneContextComp(node->token_pos(), |
| 1438 owner()->try_index(), | 1438 owner()->try_index(), |
| 1439 context)); | 1439 context)); |
| 1440 ReturnComputation(new StoreContextComp(clone)); | 1440 ReturnComputation(new StoreContextComp(clone)); |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1637 } | 1637 } |
| 1638 // The type arguments are uninstantiated. The generated pseudo code: | 1638 // The type arguments are uninstantiated. The generated pseudo code: |
| 1639 // t1 = InstantiatorTypeArguments(); | 1639 // t1 = InstantiatorTypeArguments(); |
| 1640 // t2 = ExtractConstructorTypeArguments(t1); | 1640 // t2 = ExtractConstructorTypeArguments(t1); |
| 1641 // t1 = ExtractConstructorInstantiator(t1); | 1641 // t1 = ExtractConstructorInstantiator(t1); |
| 1642 // t_n <- t2 | 1642 // t_n <- t2 |
| 1643 // t_n+1 <- t1 | 1643 // t_n+1 <- t1 |
| 1644 // Use expression_temp_var and node->allocated_object_var() locals to keep | 1644 // Use expression_temp_var and node->allocated_object_var() locals to keep |
| 1645 // intermediate results around (t1 and t2 above). | 1645 // intermediate results around (t1 and t2 above). |
| 1646 ASSERT(owner()->parsed_function().expression_temp_var() != NULL); | 1646 ASSERT(owner()->parsed_function().expression_temp_var() != NULL); |
| 1647 const LocalVariable& t1 = *owner()->parsed_function().expression_temp_var(); | 1647 const LocalVariable* t1 = owner()->parsed_function().expression_temp_var(); |
| 1648 const LocalVariable& t2 = node->allocated_object_var(); | 1648 const LocalVariable* t2 = node->allocated_object_var(); |
| 1649 Value* instantiator_type_arguments = BuildInstantiatorTypeArguments( | 1649 Value* instantiator_type_arguments = BuildInstantiatorTypeArguments( |
| 1650 node->token_pos(), NULL); | 1650 node->token_pos(), NULL); |
| 1651 ASSERT(instantiator_type_arguments->IsUse()); | 1651 ASSERT(instantiator_type_arguments->IsUse()); |
| 1652 Value* stored_instantiator = | 1652 Value* stored_instantiator = |
| 1653 Bind(BuildStoreLocal(t1, instantiator_type_arguments)); | 1653 Bind(BuildStoreLocal(t1, instantiator_type_arguments)); |
| 1654 // t1: instantiator type arguments. | 1654 // t1: instantiator type arguments. |
| 1655 | 1655 |
| 1656 Value* extract_type_arguments = Bind( | 1656 Value* extract_type_arguments = Bind( |
| 1657 new ExtractConstructorTypeArgumentsComp( | 1657 new ExtractConstructorTypeArgumentsComp( |
| 1658 node->token_pos(), | 1658 node->token_pos(), |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1730 Append(for_receiver); | 1730 Append(for_receiver); |
| 1731 arguments->Add(PushArgument(for_receiver.value())); | 1731 arguments->Add(PushArgument(for_receiver.value())); |
| 1732 | 1732 |
| 1733 ValueGraphVisitor for_value(owner(), temp_index()); | 1733 ValueGraphVisitor for_value(owner(), temp_index()); |
| 1734 node->value()->Visit(&for_value); | 1734 node->value()->Visit(&for_value); |
| 1735 Append(for_value); | 1735 Append(for_value); |
| 1736 | 1736 |
| 1737 Value* value = NULL; | 1737 Value* value = NULL; |
| 1738 if (result_is_needed) { | 1738 if (result_is_needed) { |
| 1739 value = Bind( | 1739 value = Bind( |
| 1740 BuildStoreLocal(*owner()->parsed_function().expression_temp_var(), | 1740 BuildStoreLocal(owner()->parsed_function().expression_temp_var(), |
| 1741 for_value.value())); | 1741 for_value.value())); |
| 1742 } else { | 1742 } else { |
| 1743 value = for_value.value(); | 1743 value = for_value.value(); |
| 1744 } | 1744 } |
| 1745 arguments->Add(PushArgument(value)); | 1745 arguments->Add(PushArgument(value)); |
| 1746 } | 1746 } |
| 1747 | 1747 |
| 1748 | 1748 |
| 1749 void EffectGraphVisitor::VisitInstanceSetterNode(InstanceSetterNode* node) { | 1749 void EffectGraphVisitor::VisitInstanceSetterNode(InstanceSetterNode* node) { |
| 1750 ZoneGrowableArray<PushArgumentInstr*>* arguments = | 1750 ZoneGrowableArray<PushArgumentInstr*>* arguments = |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1761 | 1761 |
| 1762 void ValueGraphVisitor::VisitInstanceSetterNode(InstanceSetterNode* node) { | 1762 void ValueGraphVisitor::VisitInstanceSetterNode(InstanceSetterNode* node) { |
| 1763 ZoneGrowableArray<PushArgumentInstr*>* arguments = | 1763 ZoneGrowableArray<PushArgumentInstr*>* arguments = |
| 1764 new ZoneGrowableArray<PushArgumentInstr*>(2); | 1764 new ZoneGrowableArray<PushArgumentInstr*>(2); |
| 1765 BuildInstanceSetterArguments(node, arguments, true); // Value used. | 1765 BuildInstanceSetterArguments(node, arguments, true); // Value used. |
| 1766 Do(new InstanceSetterComp(node->token_pos(), | 1766 Do(new InstanceSetterComp(node->token_pos(), |
| 1767 owner()->try_index(), | 1767 owner()->try_index(), |
| 1768 node->field_name(), | 1768 node->field_name(), |
| 1769 arguments)); | 1769 arguments)); |
| 1770 ReturnComputation( | 1770 ReturnComputation( |
| 1771 BuildLoadLocal(*owner()->parsed_function().expression_temp_var())); | 1771 BuildLoadLocal(owner()->parsed_function().expression_temp_var())); |
| 1772 } | 1772 } |
| 1773 | 1773 |
| 1774 | 1774 |
| 1775 void EffectGraphVisitor::VisitStaticGetterNode(StaticGetterNode* node) { | 1775 void EffectGraphVisitor::VisitStaticGetterNode(StaticGetterNode* node) { |
| 1776 const String& getter_name = | 1776 const String& getter_name = |
| 1777 String::Handle(Field::GetterName(node->field_name())); | 1777 String::Handle(Field::GetterName(node->field_name())); |
| 1778 const Function& getter_function = | 1778 const Function& getter_function = |
| 1779 Function::ZoneHandle(node->cls().LookupStaticFunction(getter_name)); | 1779 Function::ZoneHandle(node->cls().LookupStaticFunction(getter_name)); |
| 1780 ASSERT(!getter_function.IsNull()); | 1780 ASSERT(!getter_function.IsNull()); |
| 1781 ZoneGrowableArray<PushArgumentInstr*>* arguments = | 1781 ZoneGrowableArray<PushArgumentInstr*>* arguments = |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1839 // <Expression> ::= StoreLocal { local: LocalVariable | 1839 // <Expression> ::= StoreLocal { local: LocalVariable |
| 1840 // value: <Expression> } | 1840 // value: <Expression> } |
| 1841 void EffectGraphVisitor::VisitStoreLocalNode(StoreLocalNode* node) { | 1841 void EffectGraphVisitor::VisitStoreLocalNode(StoreLocalNode* node) { |
| 1842 ValueGraphVisitor for_value(owner(), temp_index()); | 1842 ValueGraphVisitor for_value(owner(), temp_index()); |
| 1843 node->value()->Visit(&for_value); | 1843 node->value()->Visit(&for_value); |
| 1844 Append(for_value); | 1844 Append(for_value); |
| 1845 Value* store_value = for_value.value(); | 1845 Value* store_value = for_value.value(); |
| 1846 if (FLAG_enable_type_checks) { | 1846 if (FLAG_enable_type_checks) { |
| 1847 store_value = BuildAssignableValue(node->value()->token_pos(), | 1847 store_value = BuildAssignableValue(node->value()->token_pos(), |
| 1848 store_value, | 1848 store_value, |
| 1849 node->local().type(), | 1849 node->local()->type(), |
| 1850 node->local().name()); | 1850 node->local()->name()); |
| 1851 } | 1851 } |
| 1852 Computation* store = BuildStoreLocal(node->local(), store_value); | 1852 Computation* store = BuildStoreLocal(node->local(), store_value); |
| 1853 ReturnComputation(store); | 1853 ReturnComputation(store); |
| 1854 } | 1854 } |
| 1855 | 1855 |
| 1856 | 1856 |
| 1857 void EffectGraphVisitor::VisitLoadInstanceFieldNode( | 1857 void EffectGraphVisitor::VisitLoadInstanceFieldNode( |
| 1858 LoadInstanceFieldNode* node) { | 1858 LoadInstanceFieldNode* node) { |
| 1859 ValueGraphVisitor for_instance(owner(), temp_index()); | 1859 ValueGraphVisitor for_instance(owner(), temp_index()); |
| 1860 node->instance()->Visit(&for_instance); | 1860 node->instance()->Visit(&for_instance); |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1963 index, | 1963 index, |
| 1964 value); | 1964 value); |
| 1965 ReturnComputation(store); | 1965 ReturnComputation(store); |
| 1966 } | 1966 } |
| 1967 | 1967 |
| 1968 | 1968 |
| 1969 void ValueGraphVisitor::VisitStoreIndexedNode(StoreIndexedNode* node) { | 1969 void ValueGraphVisitor::VisitStoreIndexedNode(StoreIndexedNode* node) { |
| 1970 Value *array, *index, *value; | 1970 Value *array, *index, *value; |
| 1971 BuildStoreIndexedValues(node, &array, &index, &value); | 1971 BuildStoreIndexedValues(node, &array, &index, &value); |
| 1972 Value* saved_value = Bind( | 1972 Value* saved_value = Bind( |
| 1973 BuildStoreLocal(*owner()->parsed_function().expression_temp_var(), | 1973 BuildStoreLocal(owner()->parsed_function().expression_temp_var(), |
| 1974 value)); | 1974 value)); |
| 1975 Do(new StoreIndexedComp(node->token_pos(), | 1975 Do(new StoreIndexedComp(node->token_pos(), |
| 1976 owner()->try_index(), | 1976 owner()->try_index(), |
| 1977 array, | 1977 array, |
| 1978 index, | 1978 index, |
| 1979 saved_value)); | 1979 saved_value)); |
| 1980 ReturnComputation( | 1980 ReturnComputation( |
| 1981 BuildLoadLocal(*owner()->parsed_function().expression_temp_var())); | 1981 BuildLoadLocal(owner()->parsed_function().expression_temp_var())); |
| 1982 } | 1982 } |
| 1983 | 1983 |
| 1984 | 1984 |
| 1985 bool EffectGraphVisitor::MustSaveRestoreContext(SequenceNode* node) const { | 1985 bool EffectGraphVisitor::MustSaveRestoreContext(SequenceNode* node) const { |
| 1986 return (node == owner()->parsed_function().node_sequence()) && | 1986 return (node == owner()->parsed_function().node_sequence()) && |
| 1987 (owner()->parsed_function().saved_context_var() != NULL); | 1987 (owner()->parsed_function().saved_context_var() != NULL); |
| 1988 } | 1988 } |
| 1989 | 1989 |
| 1990 | 1990 |
| 1991 void EffectGraphVisitor::UnchainContext() { | 1991 void EffectGraphVisitor::UnchainContext() { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2014 Bind(new AllocateContextComp(node->token_pos(), | 2014 Bind(new AllocateContextComp(node->token_pos(), |
| 2015 owner()->try_index(), | 2015 owner()->try_index(), |
| 2016 num_context_variables)); | 2016 num_context_variables)); |
| 2017 | 2017 |
| 2018 // If this node_sequence is the body of the function being compiled, and if | 2018 // If this node_sequence is the body of the function being compiled, and if |
| 2019 // this function is not a closure, do not link the current context as the | 2019 // this function is not a closure, do not link the current context as the |
| 2020 // parent of the newly allocated context, as it is not accessible. Instead, | 2020 // parent of the newly allocated context, as it is not accessible. Instead, |
| 2021 // save it in a pre-allocated variable and restore it on exit. | 2021 // save it in a pre-allocated variable and restore it on exit. |
| 2022 if (MustSaveRestoreContext(node)) { | 2022 if (MustSaveRestoreContext(node)) { |
| 2023 Value* current_context = Bind(new CurrentContextComp()); | 2023 Value* current_context = Bind(new CurrentContextComp()); |
| 2024 Do(BuildStoreLocal(*owner()->parsed_function().saved_context_var(), | 2024 Do(BuildStoreLocal(owner()->parsed_function().saved_context_var(), |
| 2025 current_context)); | 2025 current_context)); |
| 2026 Value* null_context = Bind(new ConstantVal(Object::ZoneHandle())); | 2026 Value* null_context = Bind(new ConstantVal(Object::ZoneHandle())); |
| 2027 Do(new StoreContextComp(null_context)); | 2027 Do(new StoreContextComp(null_context)); |
| 2028 } | 2028 } |
| 2029 | 2029 |
| 2030 Do(new ChainContextComp(allocated_context)); | 2030 Do(new ChainContextComp(allocated_context)); |
| 2031 owner()->set_context_level(scope->context_level()); | 2031 owner()->set_context_level(scope->context_level()); |
| 2032 | 2032 |
| 2033 // If this node_sequence is the body of the function being compiled, copy | 2033 // If this node_sequence is the body of the function being compiled, copy |
| 2034 // the captured parameters from the frame into the context. | 2034 // the captured parameters from the frame into the context. |
| 2035 if (node == owner()->parsed_function().node_sequence()) { | 2035 if (node == owner()->parsed_function().node_sequence()) { |
| 2036 ASSERT(scope->context_level() == 1); | 2036 ASSERT(scope->context_level() == 1); |
| 2037 const Function& function = owner()->parsed_function().function(); | 2037 const Function& function = owner()->parsed_function().function(); |
| 2038 const int num_params = function.NumberOfParameters(); | 2038 const int num_params = function.NumberOfParameters(); |
| 2039 int param_frame_index = (num_params == function.num_fixed_parameters()) ? | 2039 int param_frame_index = (num_params == function.num_fixed_parameters()) ? |
| 2040 (1 + num_params) : ParsedFunction::kFirstLocalSlotIndex; | 2040 (1 + num_params) : ParsedFunction::kFirstLocalSlotIndex; |
| 2041 for (int pos = 0; pos < num_params; param_frame_index--, pos++) { | 2041 for (int pos = 0; pos < num_params; param_frame_index--, pos++) { |
| 2042 const LocalVariable& parameter = *scope->VariableAt(pos); | 2042 const LocalVariable* parameter = scope->VariableAt(pos); |
| 2043 ASSERT(parameter.owner() == scope); | 2043 ASSERT(parameter->owner() == scope); |
| 2044 if (parameter.is_captured()) { | 2044 if (parameter->is_captured()) { |
| 2045 // Create a temporary local describing the original position. | 2045 // Create a temporary local describing the original position. |
| 2046 const String& temp_name = String::ZoneHandle(String::Concat( | 2046 const String& temp_name = String::ZoneHandle(String::Concat( |
| 2047 parameter.name(), String::Handle(Symbols::New("-orig")))); | 2047 parameter->name(), String::Handle(Symbols::New("-orig")))); |
| 2048 LocalVariable* temp_local = new LocalVariable( | 2048 LocalVariable* temp_local = new LocalVariable( |
| 2049 0, // Token index. | 2049 0, // Token index. |
| 2050 temp_name, | 2050 temp_name, |
| 2051 Type::ZoneHandle(Type::DynamicType())); // Type. | 2051 Type::ZoneHandle(Type::DynamicType())); // Type. |
| 2052 temp_local->set_index(param_frame_index); | 2052 temp_local->set_index(param_frame_index); |
| 2053 | 2053 |
| 2054 // Copy parameter from local frame to current context. | 2054 // Copy parameter from local frame to current context. |
| 2055 Value* load = Bind(BuildLoadLocal(*temp_local)); | 2055 Value* load = Bind(BuildLoadLocal(temp_local)); |
| 2056 Do(BuildStoreLocal(parameter, load)); | 2056 Do(BuildStoreLocal(parameter, load)); |
| 2057 // Write NULL to the source location to detect buggy accesses and | 2057 // Write NULL to the source location to detect buggy accesses and |
| 2058 // allow GC of passed value if it gets overwritten by a new value in | 2058 // allow GC of passed value if it gets overwritten by a new value in |
| 2059 // the function. | 2059 // the function. |
| 2060 Value* null_constant = Bind(new ConstantVal(Object::ZoneHandle())); | 2060 Value* null_constant = Bind(new ConstantVal(Object::ZoneHandle())); |
| 2061 Do(BuildStoreLocal(*temp_local, null_constant)); | 2061 Do(BuildStoreLocal(temp_local, null_constant)); |
| 2062 } | 2062 } |
| 2063 } | 2063 } |
| 2064 } | 2064 } |
| 2065 } | 2065 } |
| 2066 | 2066 |
| 2067 if (FLAG_enable_type_checks && | 2067 if (FLAG_enable_type_checks && |
| 2068 (node == owner()->parsed_function().node_sequence())) { | 2068 (node == owner()->parsed_function().node_sequence())) { |
| 2069 const Function& function = owner()->parsed_function().function(); | 2069 const Function& function = owner()->parsed_function().function(); |
| 2070 const int num_params = function.NumberOfParameters(); | 2070 const int num_params = function.NumberOfParameters(); |
| 2071 int pos = 0; | 2071 int pos = 0; |
| 2072 if (function.IsConstructor()) { | 2072 if (function.IsConstructor()) { |
| 2073 // Skip type checking of receiver and phase for constructor functions. | 2073 // Skip type checking of receiver and phase for constructor functions. |
| 2074 pos = 2; | 2074 pos = 2; |
| 2075 } else if (function.IsFactory() || function.IsDynamicFunction()) { | 2075 } else if (function.IsFactory() || function.IsDynamicFunction()) { |
| 2076 // Skip type checking of type arguments for factory functions. | 2076 // Skip type checking of type arguments for factory functions. |
| 2077 // Skip type checking of receiver for instance functions. | 2077 // Skip type checking of receiver for instance functions. |
| 2078 pos = 1; | 2078 pos = 1; |
| 2079 } | 2079 } |
| 2080 while (pos < num_params) { | 2080 while (pos < num_params) { |
| 2081 const LocalVariable& parameter = *scope->VariableAt(pos); | 2081 const LocalVariable* parameter = scope->VariableAt(pos); |
| 2082 ASSERT(parameter.owner() == scope); | 2082 ASSERT(parameter->owner() == scope); |
| 2083 if (!CanSkipTypeCheck(parameter.token_pos(), | 2083 if (!CanSkipTypeCheck(parameter->token_pos(), |
| 2084 NULL, | 2084 NULL, |
| 2085 parameter.type(), | 2085 parameter->type(), |
| 2086 parameter.name())) { | 2086 parameter->name())) { |
| 2087 Value* load = Bind(BuildLoadLocal(parameter)); | 2087 Value* load = Bind(BuildLoadLocal(parameter)); |
| 2088 Do(BuildAssertAssignable(parameter.token_pos(), | 2088 Do(BuildAssertAssignable(parameter->token_pos(), |
| 2089 load, | 2089 load, |
| 2090 parameter.type(), | 2090 parameter->type(), |
| 2091 parameter.name())); | 2091 parameter->name())); |
| 2092 } | 2092 } |
| 2093 pos++; | 2093 pos++; |
| 2094 } | 2094 } |
| 2095 } | 2095 } |
| 2096 | 2096 |
| 2097 intptr_t i = 0; | 2097 intptr_t i = 0; |
| 2098 while (is_open() && (i < node->length())) { | 2098 while (is_open() && (i < node->length())) { |
| 2099 EffectGraphVisitor for_effect(owner(), temp_index()); | 2099 EffectGraphVisitor for_effect(owner(), temp_index()); |
| 2100 node->NodeAt(i++)->Visit(&for_effect); | 2100 node->NodeAt(i++)->Visit(&for_effect); |
| 2101 Append(for_effect); | 2101 Append(for_effect); |
| 2102 if (!is_open()) { | 2102 if (!is_open()) { |
| 2103 // E.g., because of a JumpNode. | 2103 // E.g., because of a JumpNode. |
| 2104 break; | 2104 break; |
| 2105 } | 2105 } |
| 2106 } | 2106 } |
| 2107 | 2107 |
| 2108 if (is_open()) { | 2108 if (is_open()) { |
| 2109 if (MustSaveRestoreContext(node)) { | 2109 if (MustSaveRestoreContext(node)) { |
| 2110 ASSERT(num_context_variables > 0); | 2110 ASSERT(num_context_variables > 0); |
| 2111 BuildLoadContext(*owner()->parsed_function().saved_context_var()); | 2111 BuildLoadContext(owner()->parsed_function().saved_context_var()); |
| 2112 } else if (num_context_variables > 0) { | 2112 } else if (num_context_variables > 0) { |
| 2113 UnchainContext(); | 2113 UnchainContext(); |
| 2114 } | 2114 } |
| 2115 } | 2115 } |
| 2116 | 2116 |
| 2117 // No continue on sequence allowed. | 2117 // No continue on sequence allowed. |
| 2118 ASSERT((node->label() == NULL) || | 2118 ASSERT((node->label() == NULL) || |
| 2119 (node->label()->join_for_continue() == NULL)); | 2119 (node->label()->join_for_continue() == NULL)); |
| 2120 // If this node sequence is labeled, a break out of the sequence will have | 2120 // If this node sequence is labeled, a break out of the sequence will have |
| 2121 // taken care of unchaining the context. | 2121 // taken care of unchaining the context. |
| (...skipping 461 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2583 for (intptr_t i = 0; i < current->InputCount(); ++i) { | 2583 for (intptr_t i = 0; i < current->InputCount(); ++i) { |
| 2584 Value* v = current->InputAt(i); | 2584 Value* v = current->InputAt(i); |
| 2585 if (!v->IsUse()) continue; | 2585 if (!v->IsUse()) continue; |
| 2586 // Update expression stack. | 2586 // Update expression stack. |
| 2587 ASSERT(env->length() > var_count); | 2587 ASSERT(env->length() > var_count); |
| 2588 env->RemoveLast(); | 2588 env->RemoveLast(); |
| 2589 BindInstr* as_bind = v->AsUse()->definition()->AsBind(); | 2589 BindInstr* as_bind = v->AsUse()->definition()->AsBind(); |
| 2590 if ((as_bind != NULL) && as_bind->computation()->IsLoadLocal()) { | 2590 if ((as_bind != NULL) && as_bind->computation()->IsLoadLocal()) { |
| 2591 Computation* comp = as_bind->computation(); | 2591 Computation* comp = as_bind->computation(); |
| 2592 intptr_t index = | 2592 intptr_t index = |
| 2593 comp->AsLoadLocal()->local().BitIndexIn(fixed_parameter_count); | 2593 comp->AsLoadLocal()->local()->BitIndexIn(fixed_parameter_count); |
| 2594 current->SetInputAt(i, CopyValue((*env)[index])); | 2594 current->SetInputAt(i, CopyValue((*env)[index])); |
| 2595 } | 2595 } |
| 2596 if ((as_bind != NULL) && as_bind->computation()->IsStoreLocal()) { | 2596 if ((as_bind != NULL) && as_bind->computation()->IsStoreLocal()) { |
| 2597 // For each use of a StoreLocal: Replace it with the value from the | 2597 // For each use of a StoreLocal: Replace it with the value from the |
| 2598 // environment. | 2598 // environment. |
| 2599 Computation* comp = as_bind->computation(); | 2599 Computation* comp = as_bind->computation(); |
| 2600 intptr_t index = | 2600 intptr_t index = |
| 2601 comp->AsStoreLocal()->local().BitIndexIn(fixed_parameter_count); | 2601 comp->AsStoreLocal()->local()->BitIndexIn(fixed_parameter_count); |
| 2602 current->SetInputAt(i, CopyValue((*env)[index])); | 2602 current->SetInputAt(i, CopyValue((*env)[index])); |
| 2603 } | 2603 } |
| 2604 } | 2604 } |
| 2605 | 2605 |
| 2606 // Drop pushed arguments for calls. | 2606 // Drop pushed arguments for calls. |
| 2607 for (intptr_t j = 0; j < current->ArgumentCount(); j++) { | 2607 for (intptr_t j = 0; j < current->ArgumentCount(); j++) { |
| 2608 env->RemoveLast(); | 2608 env->RemoveLast(); |
| 2609 } | 2609 } |
| 2610 | 2610 |
| 2611 // 2b. Handle LoadLocal and StoreLocal. | 2611 // 2b. Handle LoadLocal and StoreLocal. |
| 2612 // For each LoadLocal: Remove it from the graph. | 2612 // For each LoadLocal: Remove it from the graph. |
| 2613 // For each StoreLocal: Remove it from the graph and update the environment. | 2613 // For each StoreLocal: Remove it from the graph and update the environment. |
| 2614 BindInstr* bind = current->AsBind(); | 2614 BindInstr* bind = current->AsBind(); |
| 2615 if (bind != NULL) { | 2615 if (bind != NULL) { |
| 2616 LoadLocalComp* load = bind->computation()->AsLoadLocal(); | 2616 LoadLocalComp* load = bind->computation()->AsLoadLocal(); |
| 2617 StoreLocalComp* store = bind->computation()->AsStoreLocal(); | 2617 StoreLocalComp* store = bind->computation()->AsStoreLocal(); |
| 2618 if ((load != NULL) || (store != NULL)) { | 2618 if ((load != NULL) || (store != NULL)) { |
| 2619 intptr_t index; | 2619 intptr_t index; |
| 2620 if (store != NULL) { | 2620 if (store != NULL) { |
| 2621 index = store->local().BitIndexIn(fixed_parameter_count); | 2621 index = store->local()->BitIndexIn(fixed_parameter_count); |
| 2622 // Update renaming environment. | 2622 // Update renaming environment. |
| 2623 (*env)[index] = store->value(); | 2623 (*env)[index] = store->value(); |
| 2624 } else { | 2624 } else { |
| 2625 // The graph construction ensures we do not have an unused LoadLocal | 2625 // The graph construction ensures we do not have an unused LoadLocal |
| 2626 // computation. | 2626 // computation. |
| 2627 ASSERT(bind->is_used()); | 2627 ASSERT(bind->is_used()); |
| 2628 index = load->local().BitIndexIn(fixed_parameter_count); | 2628 index = load->local()->BitIndexIn(fixed_parameter_count); |
| 2629 } | 2629 } |
| 2630 // Update expression stack and remove from graph. | 2630 // Update expression stack and remove from graph. |
| 2631 if (bind->is_used()) { | 2631 if (bind->is_used()) { |
| 2632 env->Add(CopyValue((*env)[index])); | 2632 env->Add(CopyValue((*env)[index])); |
| 2633 } | 2633 } |
| 2634 it.RemoveCurrentFromGraph(); | 2634 it.RemoveCurrentFromGraph(); |
| 2635 } else { | 2635 } else { |
| 2636 // Not a load or store. | 2636 // Not a load or store. |
| 2637 if (bind->is_used()) { | 2637 if (bind->is_used()) { |
| 2638 // Assign fresh SSA temporary and update expression stack. | 2638 // Assign fresh SSA temporary and update expression stack. |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2688 char* chars = reinterpret_cast<char*>( | 2688 char* chars = reinterpret_cast<char*>( |
| 2689 Isolate::Current()->current_zone()->Allocate(len)); | 2689 Isolate::Current()->current_zone()->Allocate(len)); |
| 2690 OS::SNPrint(chars, len, kFormat, function_name, reason); | 2690 OS::SNPrint(chars, len, kFormat, function_name, reason); |
| 2691 const Error& error = Error::Handle( | 2691 const Error& error = Error::Handle( |
| 2692 LanguageError::New(String::Handle(String::New(chars)))); | 2692 LanguageError::New(String::Handle(String::New(chars)))); |
| 2693 Isolate::Current()->long_jump_base()->Jump(1, error); | 2693 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 2694 } | 2694 } |
| 2695 | 2695 |
| 2696 | 2696 |
| 2697 } // namespace dart | 2697 } // namespace dart |
| OLD | NEW |