Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 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 | 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 <set> | 5 #include <set> |
| 6 | 6 |
| 7 #include "vm/kernel_to_il.h" | 7 #include "vm/kernel_to_il.h" |
| 8 | 8 |
| 9 #include "vm/compiler.h" | 9 #include "vm/compiler.h" |
| 10 #include "vm/intermediate_language.h" | 10 #include "vm/intermediate_language.h" |
| (...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 322 | 322 |
| 323 LocalVariable* context_var = parsed_function->current_context_var(); | 323 LocalVariable* context_var = parsed_function->current_context_var(); |
| 324 context_var->set_is_forced_stack(); | 324 context_var->set_is_forced_stack(); |
| 325 scope_->AddVariable(context_var); | 325 scope_->AddVariable(context_var); |
| 326 | 326 |
| 327 parsed_function->SetNodeSequence( | 327 parsed_function->SetNodeSequence( |
| 328 new SequenceNode(TokenPosition::kNoSource, scope_)); | 328 new SequenceNode(TokenPosition::kNoSource, scope_)); |
| 329 | 329 |
| 330 switch (function.kind()) { | 330 switch (function.kind()) { |
| 331 case RawFunction::kClosureFunction: | 331 case RawFunction::kClosureFunction: |
| 332 case RawFunction::kConvertedClosureFunction: | |
| 332 case RawFunction::kRegularFunction: | 333 case RawFunction::kRegularFunction: |
| 333 case RawFunction::kGetterFunction: | 334 case RawFunction::kGetterFunction: |
| 334 case RawFunction::kSetterFunction: | 335 case RawFunction::kSetterFunction: |
| 335 case RawFunction::kConstructor: { | 336 case RawFunction::kConstructor: { |
| 336 FunctionNode* node; | 337 FunctionNode* node; |
| 337 if (node_->IsProcedure()) { | 338 if (node_->IsProcedure()) { |
| 338 node = Procedure::Cast(node_)->function(); | 339 node = Procedure::Cast(node_)->function(); |
| 339 } else if (node_->IsConstructor()) { | 340 } else if (node_->IsConstructor()) { |
| 340 node = Constructor::Cast(node_)->function(); | 341 node = Constructor::Cast(node_)->function(); |
| 341 } else { | 342 } else { |
| 342 node = FunctionNode::Cast(node_); | 343 node = FunctionNode::Cast(node_); |
| 343 } | 344 } |
| 344 current_function_node_ = node; | 345 current_function_node_ = node; |
| 345 | 346 |
| 346 intptr_t pos = 0; | 347 intptr_t pos = 0; |
| 347 if (function.IsClosureFunction()) { | 348 if (function.IsClosureFunction()) { |
| 348 LocalVariable* variable = MakeVariable( | 349 LocalVariable* variable = MakeVariable( |
| 349 TokenPosition::kNoSource, TokenPosition::kNoSource, | 350 TokenPosition::kNoSource, TokenPosition::kNoSource, |
| 350 Symbols::ClosureParameter(), AbstractType::dynamic_type()); | 351 Symbols::ClosureParameter(), AbstractType::dynamic_type()); |
| 351 variable->set_is_forced_stack(); | 352 variable->set_is_forced_stack(); |
| 352 scope_->InsertParameterAt(pos++, variable); | 353 scope_->InsertParameterAt(pos++, variable); |
| 354 } else if (function.IsConvertedClosureFunction()) { | |
| 355 // Do nothing. The explicit context parameter is already included into | |
| 356 // the parameter list of the parent function. | |
| 353 } else if (!function.is_static()) { | 357 } else if (!function.is_static()) { |
| 354 // We use [is_static] instead of [IsStaticFunction] because the latter | 358 // We use [is_static] instead of [IsStaticFunction] because the latter |
| 355 // returns `false` for constructors. | 359 // returns `false` for constructors. |
| 356 dart::Class& klass = dart::Class::Handle(Z, function.Owner()); | 360 dart::Class& klass = dart::Class::Handle(Z, function.Owner()); |
| 357 Type& klass_type = H.GetCanonicalType(klass); | 361 Type& klass_type = H.GetCanonicalType(klass); |
| 358 LocalVariable* variable = | 362 LocalVariable* variable = |
| 359 MakeVariable(TokenPosition::kNoSource, TokenPosition::kNoSource, | 363 MakeVariable(TokenPosition::kNoSource, TokenPosition::kNoSource, |
| 360 Symbols::This(), klass_type); | 364 Symbols::This(), klass_type); |
| 361 scope_->InsertParameterAt(pos++, variable); | 365 scope_->InsertParameterAt(pos++, variable); |
| 362 result_->this_variable = variable; | 366 result_->this_variable = variable; |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 377 } | 381 } |
| 378 } else if (function.IsFactory()) { | 382 } else if (function.IsFactory()) { |
| 379 LocalVariable* variable = MakeVariable( | 383 LocalVariable* variable = MakeVariable( |
| 380 TokenPosition::kNoSource, TokenPosition::kNoSource, | 384 TokenPosition::kNoSource, TokenPosition::kNoSource, |
| 381 Symbols::TypeArgumentsParameter(), AbstractType::dynamic_type()); | 385 Symbols::TypeArgumentsParameter(), AbstractType::dynamic_type()); |
| 382 scope_->InsertParameterAt(pos++, variable); | 386 scope_->InsertParameterAt(pos++, variable); |
| 383 result_->type_arguments_variable = variable; | 387 result_->type_arguments_variable = variable; |
| 384 } | 388 } |
| 385 AddParameters(node, pos); | 389 AddParameters(node, pos); |
| 386 | 390 |
| 387 // We generate a syntethic body for implicit closure functions - which | 391 // We generate a syntethic body for implicit closure functions and |
| 388 // will forward the call to the real function. | 392 // converted |
| 393 // closure functions - which will forward the call to the real function. | |
| 389 // -> see BuildGraphOfImplicitClosureFunction | 394 // -> see BuildGraphOfImplicitClosureFunction |
| 390 if (!function.IsImplicitClosureFunction()) { | 395 // -> see BuildGraphOfConvertedClosureFunction |
| 396 | |
| 397 if (!function.IsImplicitClosureFunction() && | |
| 398 !function.IsConvertedClosureFunction()) { | |
| 391 // TODO(jensj): HACK: Push the begin token to after any parameters to | 399 // TODO(jensj): HACK: Push the begin token to after any parameters to |
| 392 // avoid crash when breaking on definition line of async method in | 400 // avoid crash when breaking on definition line of async method in |
| 393 // debugger. It seems that another scope needs to be added | 401 // debugger. It seems that another scope needs to be added |
| 394 // in which captures are made, but I can't make that work. | 402 // in which captures are made, but I can't make that work. |
| 395 // This 'solution' doesn't crash, but I cannot see the parameters at | 403 // This 'solution' doesn't crash, but I cannot see the parameters at |
| 396 // that particular breakpoint either. | 404 // that particular breakpoint either. |
| 397 // Also push the end token to after the "}" to avoid crashing on | 405 // Also push the end token to after the "}" to avoid crashing on |
| 398 // stepping past the last line (to the "}" character). | 406 // stepping past the last line (to the "}" character). |
| 399 if (node->body() != NULL && node->body()->position().IsReal()) { | 407 if (node->body() != NULL && node->body()->position().IsReal()) { |
| 400 scope_->set_begin_token_pos(node->body()->position()); | 408 scope_->set_begin_token_pos(node->body()->position()); |
| (...skipping 2793 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3194 | 3202 |
| 3195 // The IR builder will create its own local variables and scopes, and it | 3203 // The IR builder will create its own local variables and scopes, and it |
| 3196 // will not need an AST. The code generator will assume that there is a | 3204 // will not need an AST. The code generator will assume that there is a |
| 3197 // local variable stack slot allocated for the current context and (I | 3205 // local variable stack slot allocated for the current context and (I |
| 3198 // think) that the runtime will expect it to be at a fixed offset which | 3206 // think) that the runtime will expect it to be at a fixed offset which |
| 3199 // requires allocating an unused expression temporary variable. | 3207 // requires allocating an unused expression temporary variable. |
| 3200 scopes_ = parsed_function_->EnsureKernelScopes(); | 3208 scopes_ = parsed_function_->EnsureKernelScopes(); |
| 3201 | 3209 |
| 3202 switch (function.kind()) { | 3210 switch (function.kind()) { |
| 3203 case RawFunction::kClosureFunction: | 3211 case RawFunction::kClosureFunction: |
| 3212 case RawFunction::kConvertedClosureFunction: | |
| 3204 case RawFunction::kRegularFunction: | 3213 case RawFunction::kRegularFunction: |
| 3205 case RawFunction::kGetterFunction: | 3214 case RawFunction::kGetterFunction: |
| 3206 case RawFunction::kSetterFunction: { | 3215 case RawFunction::kSetterFunction: { |
| 3207 FunctionNode* kernel_function = node_->IsProcedure() | 3216 FunctionNode* kernel_function = node_->IsProcedure() |
| 3208 ? Procedure::Cast(node_)->function() | 3217 ? Procedure::Cast(node_)->function() |
| 3209 : FunctionNode::Cast(node_); | 3218 : FunctionNode::Cast(node_); |
| 3210 ActiveFunctionScope active_function_scope(&active_class_, | 3219 ActiveFunctionScope active_function_scope(&active_class_, |
| 3211 kernel_function); | 3220 kernel_function); |
| 3212 return function.IsImplicitClosureFunction() | 3221 if (function.IsImplicitClosureFunction()) { |
| 3213 ? BuildGraphOfImplicitClosureFunction(kernel_function, | 3222 return BuildGraphOfImplicitClosureFunction(kernel_function, function); |
| 3214 function) | 3223 } else if (function.IsConvertedClosureFunction()) { |
| 3215 : BuildGraphOfFunction(kernel_function); | 3224 return BuildGraphOfConvertedClosureFunction(kernel_function, function); |
| 3225 } else { | |
| 3226 return BuildGraphOfFunction(kernel_function); | |
| 3227 } | |
| 3216 } | 3228 } |
| 3217 case RawFunction::kConstructor: { | 3229 case RawFunction::kConstructor: { |
| 3218 bool is_factory = function.IsFactory(); | 3230 bool is_factory = function.IsFactory(); |
| 3219 if (is_factory) { | 3231 if (is_factory) { |
| 3220 Procedure* procedure = Procedure::Cast(node_); | 3232 Procedure* procedure = Procedure::Cast(node_); |
| 3221 FunctionNode* function = procedure->function(); | 3233 FunctionNode* function = procedure->function(); |
| 3222 ActiveFunctionScope active_function_scope(&active_class_, function); | 3234 ActiveFunctionScope active_function_scope(&active_class_, function); |
| 3223 return BuildGraphOfFunction(function, NULL); | 3235 return BuildGraphOfFunction(function, NULL); |
| 3224 } else { | 3236 } else { |
| 3225 Constructor* constructor = Constructor::Cast(node_); | 3237 Constructor* constructor = Constructor::Cast(node_); |
| (...skipping 795 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4021 body += StaticCall(TokenPosition::kNoSource, target, argument_count, | 4033 body += StaticCall(TokenPosition::kNoSource, target, argument_count, |
| 4022 argument_names); | 4034 argument_names); |
| 4023 | 4035 |
| 4024 // Return the result. | 4036 // Return the result. |
| 4025 body += Return(kernel_function->end_position()); | 4037 body += Return(kernel_function->end_position()); |
| 4026 | 4038 |
| 4027 return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1); | 4039 return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1); |
| 4028 } | 4040 } |
| 4029 | 4041 |
| 4030 | 4042 |
| 4043 // This method follows the logic similar to that of | |
| 4044 // FlowGraphBuilder::BuildGraphOfImplicitClosureFunction. For additional | |
| 4045 // details on converted closure functions, please, see the comment on the method | |
| 4046 // Function::ConvertedClosureFunction. | |
| 4047 FlowGraph* FlowGraphBuilder::BuildGraphOfConvertedClosureFunction( | |
| 4048 FunctionNode* kernel_function, | |
| 4049 const Function& function) { | |
| 4050 const Function& target = Function::ZoneHandle(Z, function.parent_function()); | |
| 4051 | |
| 4052 TargetEntryInstr* normal_entry = BuildTargetEntry(); | |
| 4053 graph_entry_ = new (Z) | |
| 4054 GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId); | |
| 4055 SetupDefaultParameterValues(kernel_function); | |
| 4056 | |
| 4057 Fragment body(normal_entry); | |
| 4058 body += CheckStackOverflowInPrologue(); | |
| 4059 | |
| 4060 // Load all the arguments. | |
| 4061 ASSERT(target.is_static()); | |
| 4062 // The first argument is the value that the target function is converted over. | |
| 4063 // It is stored in the context field of the Closure class instance. The | |
| 4064 // instance is passed as the first argument to the call. | |
| 4065 body += LoadLocal(parsed_function_->node_sequence()->scope()->VariableAt(0)); | |
| 4066 body += LoadField(Closure::context_offset()); | |
| 4067 body += PushArgument(); | |
| 4068 | |
| 4069 // The rest of the parameters are the same for the method of the Closure class | |
| 4070 // being invoked and the top-level target function. | |
| 4071 intptr_t positional_argument_count = | |
| 4072 kernel_function->positional_parameters().length(); | |
| 4073 for (intptr_t i = 1; i < positional_argument_count; i++) { | |
| 4074 body += | |
| 4075 LoadLocal(LookupVariable(kernel_function->positional_parameters()[i])); | |
| 4076 body += PushArgument(); | |
| 4077 } | |
| 4078 intptr_t named_argument_count = kernel_function->named_parameters().length(); | |
| 4079 Array& argument_names = Array::ZoneHandle(Z); | |
| 4080 if (named_argument_count > 0) { | |
| 4081 argument_names = Array::New(named_argument_count); | |
| 4082 for (intptr_t i = 0; i < named_argument_count; i++) { | |
| 4083 VariableDeclaration* variable = kernel_function->named_parameters()[i]; | |
| 4084 body += LoadLocal(LookupVariable(variable)); | |
| 4085 body += PushArgument(); | |
| 4086 argument_names.SetAt(i, H.DartSymbol(variable->name())); | |
| 4087 } | |
| 4088 } | |
| 4089 // Forward them to the target. | |
| 4090 intptr_t argument_count = positional_argument_count + named_argument_count; | |
| 4091 body += StaticCall(TokenPosition::kNoSource, target, argument_count, | |
| 4092 argument_names); | |
| 4093 | |
| 4094 // Return the result. | |
| 4095 body += Return(kernel_function->end_position()); | |
| 4096 | |
| 4097 return new (Z) FlowGraph(*parsed_function_, graph_entry_, next_block_id_ - 1); | |
| 4098 } | |
| 4099 | |
| 4100 | |
| 4031 FlowGraph* FlowGraphBuilder::BuildGraphOfNoSuchMethodDispatcher( | 4101 FlowGraph* FlowGraphBuilder::BuildGraphOfNoSuchMethodDispatcher( |
| 4032 const Function& function) { | 4102 const Function& function) { |
| 4033 // This function is specialized for a receiver class, a method name, and | 4103 // This function is specialized for a receiver class, a method name, and |
| 4034 // the arguments descriptor at a call site. | 4104 // the arguments descriptor at a call site. |
| 4035 | 4105 |
| 4036 TargetEntryInstr* normal_entry = BuildTargetEntry(); | 4106 TargetEntryInstr* normal_entry = BuildTargetEntry(); |
| 4037 graph_entry_ = new (Z) | 4107 graph_entry_ = new (Z) |
| 4038 GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId); | 4108 GraphEntryInstr(*parsed_function_, normal_entry, Compiler::kNoOSRDeoptId); |
| 4039 | 4109 |
| 4040 // The backend will expect an array of default values for all the named | 4110 // The backend will expect an array of default values for all the named |
| (...skipping 683 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4724 void DartTypeTranslator::VisitDynamicType(DynamicType* node) { | 4794 void DartTypeTranslator::VisitDynamicType(DynamicType* node) { |
| 4725 result_ = Object::dynamic_type().raw(); | 4795 result_ = Object::dynamic_type().raw(); |
| 4726 } | 4796 } |
| 4727 | 4797 |
| 4728 | 4798 |
| 4729 void DartTypeTranslator::VisitVoidType(VoidType* node) { | 4799 void DartTypeTranslator::VisitVoidType(VoidType* node) { |
| 4730 result_ = Object::void_type().raw(); | 4800 result_ = Object::void_type().raw(); |
| 4731 } | 4801 } |
| 4732 | 4802 |
| 4733 | 4803 |
| 4804 void DartTypeTranslator::VisitVectorType(VectorType* node) { | |
| 4805 result_ = Object::vector_type().raw(); | |
| 4806 } | |
| 4807 | |
| 4808 | |
| 4734 void DartTypeTranslator::VisitBottomType(BottomType* node) { | 4809 void DartTypeTranslator::VisitBottomType(BottomType* node) { |
| 4735 result_ = | 4810 result_ = |
| 4736 dart::Class::Handle(Z, I->object_store()->null_class()).CanonicalType(); | 4811 dart::Class::Handle(Z, I->object_store()->null_class()).CanonicalType(); |
| 4737 } | 4812 } |
| 4738 | 4813 |
| 4739 | 4814 |
| 4740 const TypeArguments& DartTypeTranslator::TranslateTypeArguments( | 4815 const TypeArguments& DartTypeTranslator::TranslateTypeArguments( |
| 4741 DartType** dart_types, | 4816 DartType** dart_types, |
| 4742 intptr_t length) { | 4817 intptr_t length) { |
| 4743 bool only_dynamic = true; | 4818 bool only_dynamic = true; |
| (...skipping 908 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5652 fragment_ = instructions; | 5727 fragment_ = instructions; |
| 5653 } | 5728 } |
| 5654 | 5729 |
| 5655 | 5730 |
| 5656 void FlowGraphBuilder::VisitRethrow(Rethrow* node) { | 5731 void FlowGraphBuilder::VisitRethrow(Rethrow* node) { |
| 5657 fragment_ = | 5732 fragment_ = |
| 5658 streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset()); | 5733 streaming_flow_graph_builder_->BuildExpressionAt(node->kernel_offset()); |
| 5659 } | 5734 } |
| 5660 | 5735 |
| 5661 | 5736 |
| 5737 void FlowGraphBuilder::VisitVectorCreation(VectorCreation* node) { | |
| 5738 ASSERT(node->value() > 0); | |
|
jensj
2017/05/18 11:19:06
STREAM_EXPRESSION_IF_POSSIBLE(node); ? (the same f
Dmitry Stefantsov
2017/05/18 12:18:53
Yep, that explains why the code worked without the
| |
| 5739 Fragment instructions = AllocateContext(node->value()); | |
| 5740 fragment_ = instructions; | |
| 5741 } | |
| 5742 | |
| 5743 | |
| 5744 void FlowGraphBuilder::VisitVectorGet(VectorGet* node) { | |
| 5745 Fragment instructions; | |
| 5746 | |
| 5747 instructions += TranslateExpression(node->vector_expression()); | |
| 5748 instructions += LoadField(Context::variable_offset(node->index())); | |
| 5749 | |
| 5750 fragment_ = instructions; | |
| 5751 } | |
| 5752 | |
| 5753 | |
| 5754 void FlowGraphBuilder::VisitVectorSet(VectorSet* node) { | |
| 5755 Fragment instructions; | |
| 5756 | |
| 5757 instructions += TranslateExpression(node->vector_expression()); | |
| 5758 instructions += TranslateExpression(node->value()); | |
| 5759 LocalVariable* result = MakeTemporary(); | |
| 5760 | |
| 5761 Value* value = Pop(); | |
| 5762 StoreInstanceFieldInstr* store = new (Z) | |
| 5763 StoreInstanceFieldInstr(Context::variable_offset(node->index()), Pop(), | |
| 5764 value, kNoStoreBarrier, TokenPosition::kNoSource); | |
| 5765 instructions <<= store; | |
| 5766 | |
| 5767 // Result of a vector-set operation is its rhs. It is useful, especially for | |
| 5768 // assignment chains. | |
| 5769 instructions += LoadLocal(result); | |
| 5770 | |
| 5771 fragment_ = instructions; | |
| 5772 } | |
| 5773 | |
| 5774 | |
| 5775 void FlowGraphBuilder::VisitVectorCopy(VectorCopy* node) { | |
| 5776 Fragment instructions; | |
| 5777 | |
| 5778 instructions += TranslateExpression(node->vector_expression()); | |
| 5779 CloneContextInstr* clone_instruction = | |
| 5780 new (Z) CloneContextInstr(TokenPosition::kNoSource, Pop()); | |
| 5781 instructions <<= clone_instruction; | |
| 5782 Push(clone_instruction); | |
| 5783 | |
| 5784 fragment_ = instructions; | |
| 5785 } | |
| 5786 | |
| 5787 | |
| 5788 void FlowGraphBuilder::VisitClosureCreation(ClosureCreation* node) { | |
| 5789 Fragment instructions; | |
| 5790 | |
| 5791 Function& function = Function::ZoneHandle( | |
| 5792 Z, H.LookupStaticMethodByKernelProcedure(node->top_level_function())); | |
| 5793 function = function.ConvertedClosureFunction(); | |
| 5794 ASSERT(!function.IsNull()); | |
| 5795 | |
| 5796 const dart::Class& closure_class = | |
| 5797 dart::Class::ZoneHandle(Z, I->object_store()->closure_class()); | |
| 5798 instructions += AllocateObject(closure_class, function); | |
| 5799 LocalVariable* closure = MakeTemporary(); | |
| 5800 | |
| 5801 instructions += TranslateExpression(node->context_vector()); | |
| 5802 LocalVariable* context = MakeTemporary(); | |
| 5803 | |
| 5804 instructions += LoadLocal(closure); | |
| 5805 instructions += Constant(function); | |
| 5806 instructions += | |
| 5807 StoreInstanceField(TokenPosition::kNoSource, Closure::function_offset()); | |
| 5808 | |
| 5809 instructions += LoadLocal(closure); | |
| 5810 instructions += LoadLocal(context); | |
| 5811 instructions += | |
| 5812 StoreInstanceField(TokenPosition::kNoSource, Closure::context_offset()); | |
| 5813 | |
| 5814 instructions += Drop(); | |
| 5815 | |
| 5816 fragment_ = instructions; | |
| 5817 } | |
| 5818 | |
| 5819 | |
| 5662 Fragment FlowGraphBuilder::TranslateArguments(Arguments* node, | 5820 Fragment FlowGraphBuilder::TranslateArguments(Arguments* node, |
| 5663 Array* argument_names) { | 5821 Array* argument_names) { |
| 5664 Fragment instructions; | 5822 Fragment instructions; |
| 5665 | 5823 |
| 5666 List<Expression>& positional = node->positional(); | 5824 List<Expression>& positional = node->positional(); |
| 5667 for (intptr_t i = 0; i < positional.length(); ++i) { | 5825 for (intptr_t i = 0; i < positional.length(); ++i) { |
| 5668 instructions += TranslateExpression(positional[i]); | 5826 instructions += TranslateExpression(positional[i]); |
| 5669 instructions += PushArgument(); | 5827 instructions += PushArgument(); |
| 5670 } | 5828 } |
| 5671 | 5829 |
| (...skipping 1143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6815 thread->clear_sticky_error(); | 6973 thread->clear_sticky_error(); |
| 6816 return error.raw(); | 6974 return error.raw(); |
| 6817 } | 6975 } |
| 6818 } | 6976 } |
| 6819 | 6977 |
| 6820 | 6978 |
| 6821 } // namespace kernel | 6979 } // namespace kernel |
| 6822 } // namespace dart | 6980 } // namespace dart |
| 6823 | 6981 |
| 6824 #endif // !defined(DART_PRECOMPILED_RUNTIME) | 6982 #endif // !defined(DART_PRECOMPILED_RUNTIME) |
| OLD | NEW |