Chromium Code Reviews| 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" |
| 11 #include "vm/flags.h" | 11 #include "vm/flags.h" |
| 12 #include "vm/il_printer.h" | 12 #include "vm/il_printer.h" |
| 13 #include "vm/intermediate_language.h" | 13 #include "vm/intermediate_language.h" |
| 14 #include "vm/longjump.h" | 14 #include "vm/longjump.h" |
| 15 #include "vm/object_store.h" | 15 #include "vm/object_store.h" |
| 16 #include "vm/os.h" | 16 #include "vm/os.h" |
| 17 #include "vm/parser.h" | 17 #include "vm/parser.h" |
| 18 #include "vm/resolver.h" | 18 #include "vm/resolver.h" |
| 19 #include "vm/stub_code.h" | 19 #include "vm/stub_code.h" |
| 20 | 20 |
| 21 namespace dart { | 21 namespace dart { |
| 22 | 22 |
| 23 DEFINE_FLAG(bool, eliminate_type_checks, true, | 23 DEFINE_FLAG(bool, eliminate_type_checks, true, |
| 24 "Eliminate type checks when allowed by static type analysis"); | 24 "Eliminate type checks when allowed by static type analysis."); |
| 25 DEFINE_FLAG(bool, print_ast, false, "Print abstract syntax tree."); | 25 DEFINE_FLAG(bool, print_ast, false, "Print abstract syntax tree."); |
| 26 DEFINE_FLAG(bool, print_flow_graph, false, "Print the IR flow graph."); | 26 DEFINE_FLAG(bool, print_flow_graph, false, "Print the IR flow graph."); |
| 27 DEFINE_FLAG(bool, trace_type_check_elimination, false, | |
| 28 "Trace type check elimination at compile time."); | |
| 27 #if defined(TARGET_ARCH_X64) | 29 #if defined(TARGET_ARCH_X64) |
| 28 DEFINE_FLAG(bool, use_ssa, true, "Use SSA form"); | 30 DEFINE_FLAG(bool, use_ssa, true, "Use SSA form"); |
| 29 #else | 31 #else |
| 30 DEFINE_FLAG(bool, use_ssa, false, "Use SSA form"); | 32 DEFINE_FLAG(bool, use_ssa, false, "Use SSA form"); |
| 31 #endif | 33 #endif |
| 32 DECLARE_FLAG(bool, enable_type_checks); | 34 DECLARE_FLAG(bool, enable_type_checks); |
| 33 | 35 |
| 34 | 36 |
| 35 FlowGraphBuilder::FlowGraphBuilder(const ParsedFunction& parsed_function) | 37 FlowGraphBuilder::FlowGraphBuilder(const ParsedFunction& parsed_function) |
| 36 : parsed_function_(parsed_function), | 38 : parsed_function_(parsed_function), |
| (...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 308 | 310 |
| 309 void ValueGraphVisitor::VisitLiteralNode(LiteralNode* node) { | 311 void ValueGraphVisitor::VisitLiteralNode(LiteralNode* node) { |
| 310 ReturnComputation(new ConstantVal(node->literal())); | 312 ReturnComputation(new ConstantVal(node->literal())); |
| 311 } | 313 } |
| 312 | 314 |
| 313 // Type nodes only occur as the right-hand side of instanceof comparisons, | 315 // Type nodes only occur as the right-hand side of instanceof comparisons, |
| 314 // and they are handled specially in that context. | 316 // and they are handled specially in that context. |
| 315 void EffectGraphVisitor::VisitTypeNode(TypeNode* node) { UNREACHABLE(); } | 317 void EffectGraphVisitor::VisitTypeNode(TypeNode* node) { UNREACHABLE(); } |
| 316 | 318 |
| 317 | 319 |
| 318 // Returns true if the type check can be skipped, for example, if the | 320 // Helper routine returning true if the static type of the given value is more |
| 319 // destination type is Dynamic or if the static type of the value is a subtype | 321 // specific than the given dst_type. |
| 320 // of the destination type. | 322 static bool IsStaticTypeMoreSpecific(Value* value, |
| 321 static bool CanSkipTypeCheck(Value* value, const AbstractType& dst_type) { | 323 const AbstractType& dst_type) { |
| 322 ASSERT(!dst_type.IsNull()); | 324 ASSERT(!dst_type.IsMalformed()); |
| 323 ASSERT(dst_type.IsFinalized()); | |
| 324 if (!FLAG_eliminate_type_checks) { | |
| 325 return false; | |
| 326 } | |
| 327 | 325 |
| 328 // Any expression is assignable to the Dynamic type and to the Object type. | 326 // Any type is more specific than the Dynamic type and than the Object type. |
| 329 // Skip the test. | 327 if (dst_type.IsDynamicType() || dst_type.IsObjectType()) { |
| 330 if (!dst_type.IsMalformed() && | |
| 331 (dst_type.IsDynamicType() || dst_type.IsObjectType())) { | |
| 332 return true; | 328 return true; |
| 333 } | 329 } |
| 334 | 330 |
| 335 // It is a compile-time error to explicitly return a value (including null) | 331 // It is a compile-time error to explicitly return a value (including null) |
| 336 // from a void function. However, functions that do not explicitly return a | 332 // from a void function. However, functions that do not explicitly return a |
| 337 // value, implicitly return null. This includes void functions. Therefore, we | 333 // value, implicitly return null. This includes void functions. Therefore, we |
| 338 // skip the type test here and trust the parser to only return null in void | 334 // skip the type test here and trust the parser to only return null in void |
| 339 // function. | 335 // function. |
| 340 if (dst_type.IsVoidType()) { | 336 if (dst_type.IsVoidType()) { |
| 337 // TODO(regis): Should we perform this null test at run-time? | |
| 341 return true; | 338 return true; |
| 342 } | 339 } |
| 343 | 340 |
| 341 // Do not perform type check elimination if this optimization is turned off. | |
| 342 if (!FLAG_eliminate_type_checks) { | |
| 343 return false; | |
| 344 } | |
| 345 | |
| 344 // If nothing is known about the value, as is the case for passed-in | 346 // If nothing is known about the value, as is the case for passed-in |
| 345 // parameters, the test cannot be eliminated. | 347 // parameters, the type test cannot be eliminated. |
|
srdjan
2012/07/07 23:06:04
The comment is confusing as it implies how the met
regis
2012/07/09 16:58:53
Moving this test to the caller would skip the test
| |
| 346 if (value == NULL) { | 348 if (value == NULL) { |
| 347 return false; | 349 return false; |
| 348 } | 350 } |
| 349 | 351 |
| 350 // Consider the static type of the value. | 352 // Consider the static type of the value. |
| 351 const AbstractType& static_type = AbstractType::Handle(value->StaticType()); | 353 const AbstractType& static_type = AbstractType::Handle(value->StaticType()); |
| 352 ASSERT(!static_type.IsMalformed()); | 354 ASSERT(!static_type.IsMalformed()); |
| 353 | 355 |
| 354 // If the static type of the value is void, the only allowed value is null, | 356 // If the static type of the value is void, the only allowed value is null, |
| 355 // which must be verified by the type test. | 357 // which must be verified by the type test. |
| 358 // TODO(regis): Eliminate the test if the value is constant null. | |
|
srdjan
2012/07/07 23:06:04
ditto
regis
2012/07/09 16:58:53
ditto
| |
| 356 if (static_type.IsVoidType()) { | 359 if (static_type.IsVoidType()) { |
| 357 // TODO(regis): Eliminate the test if the value is constant null. | |
| 358 return false; | 360 return false; |
| 359 } | 361 } |
| 360 | 362 |
| 361 // If the static type of the value is NullType, the type test is eliminated. | 363 // If the static type of the value is NullType, the type test is eliminated. |
| 364 // There are only three instances that can be of Class Null: | |
| 365 // Object::null(), Object::sentinel(), and Object::transition_sentinel(). | |
| 366 // The inline code and run time code performing the type check will never | |
| 367 // encounter the 2 sentinel values. The type check of a sentinel value | |
| 368 // will always be eliminated here, because these sentinel values can only | |
| 369 // be encountered as constants, never as actual value of a heap object | |
| 370 // being type checked. | |
| 362 if (static_type.IsNullType()) { | 371 if (static_type.IsNullType()) { |
| 363 // There are only three instances that can be of Class Null: | |
| 364 // Object::null(), Object::sentinel(), and Object::transition_sentinel(). | |
| 365 // The inline code and run time code performing the type check will never | |
| 366 // encounter the 2 sentinel values. The type check of a sentinel value | |
| 367 // will always be eliminated here, because these sentinel values can only | |
| 368 // be encountered as constants, never as actual value of a heap object | |
| 369 // being type checked. | |
| 370 return true; | 372 return true; |
| 371 } | 373 } |
| 372 | 374 |
| 373 // The run time type of the value is guaranteed to be a subtype of the compile | 375 // The run time type of the value is guaranteed to be a subtype of the |
| 374 // time static type of the value. However, establishing here that the static | 376 // compile time static type of the value. However, establishing here that |
| 375 // type is a subtype of the destination type does not guarantee that the run | 377 // the static type is a subtype of the destination type does not guarantee |
| 376 // time type will also be a subtype of the destination type, because the | 378 // that the run time type will also be a subtype of the destination type, |
| 377 // subtype relation is not transitive. | 379 // because the subtype relation is not transitive. |
| 378 // However, the 'more specific than' relation is transitive and is used here. | 380 // However, the 'more specific than' relation is transitive and is used |
| 379 // In other words, if the static type of the value is more specific than the | 381 // here. In other words, if the static type of the value is more specific |
| 380 // destination type, the run time type of the value, which is guaranteed to | 382 // than the destination type, the run time type of the value, which is |
| 381 // be a subtype of the static type, is also guaranteed to be a subtype of the | 383 // guaranteed to be a subtype of the static type, is also guaranteed to be |
| 382 // destination type and the type check can therefore be eliminated. | 384 // a subtype of the destination type and the type check can therefore be |
| 385 // eliminated. | |
| 383 Error& malformed_error = Error::Handle(); | 386 Error& malformed_error = Error::Handle(); |
| 384 if (static_type.IsMoreSpecificThan(dst_type, &malformed_error)) { | 387 return static_type.IsMoreSpecificThan(dst_type, &malformed_error); |
| 385 return true; | |
| 386 } | |
| 387 | |
| 388 return false; | |
| 389 } | 388 } |
| 390 | 389 |
| 391 | 390 |
| 391 // Returns true if the type check can be skipped, for example, if the | |
| 392 // destination type is Dynamic or if the static type of the value is a subtype | |
| 393 // of the destination type. | |
| 394 bool EffectGraphVisitor::CanSkipTypeCheck(intptr_t token_pos, | |
| 395 Value* value, | |
| 396 const AbstractType& dst_type, | |
| 397 const String& dst_name) { | |
| 398 ASSERT(!dst_type.IsNull()); | |
| 399 ASSERT(dst_type.IsFinalized()); | |
| 400 | |
| 401 // If the destination type is malformed, a dynamic type error must be thrown | |
| 402 // at run time. | |
| 403 if (dst_type.IsMalformed()) { | |
| 404 return false; | |
| 405 } | |
| 406 | |
| 407 const bool eliminated = IsStaticTypeMoreSpecific(value, dst_type); | |
| 408 if (FLAG_eliminate_type_checks && FLAG_trace_type_check_elimination) { | |
| 409 const Class& cls = Class::Handle( | |
| 410 owner()->parsed_function().function().owner()); | |
| 411 const Script& script = Script::Handle(cls.script()); | |
| 412 const char* static_type_name = "unknown"; | |
| 413 if (value != NULL) { | |
| 414 const AbstractType& type = AbstractType::Handle(value->StaticType()); | |
| 415 static_type_name = String::Handle(type.Name()).ToCString(); | |
| 416 } | |
| 417 Parser::PrintMessage(script, token_pos, "", | |
| 418 "%s type check: static type '%s' is %s specific than " | |
| 419 "type '%s' of '%s'.", | |
| 420 eliminated ? "Eliminated" : "Generated", | |
| 421 static_type_name, | |
| 422 eliminated ? "more" : "not more", | |
| 423 String::Handle(dst_type.Name()).ToCString(), | |
| 424 dst_name.ToCString()); | |
| 425 } | |
| 426 return eliminated; | |
| 427 } | |
| 428 | |
| 429 | |
| 392 // <Expression> :: Assignable { expr: <Expression> | 430 // <Expression> :: Assignable { expr: <Expression> |
| 393 // type: AbstractType | 431 // type: AbstractType |
| 394 // dst_name: String } | 432 // dst_name: String } |
| 395 void EffectGraphVisitor::VisitAssignableNode(AssignableNode* node) { | 433 void EffectGraphVisitor::VisitAssignableNode(AssignableNode* node) { |
| 396 UNREACHABLE(); | 434 UNREACHABLE(); |
| 397 } | 435 } |
| 398 | 436 |
| 399 | 437 |
| 400 void ValueGraphVisitor::VisitAssignableNode(AssignableNode* node) { | 438 void ValueGraphVisitor::VisitAssignableNode(AssignableNode* node) { |
| 401 ValueGraphVisitor for_value(owner(), temp_index()); | 439 ValueGraphVisitor for_value(owner(), temp_index()); |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 662 dst_type, | 700 dst_type, |
| 663 dst_name); | 701 dst_name); |
| 664 } | 702 } |
| 665 | 703 |
| 666 | 704 |
| 667 // Used for type casts and to test assignments. | 705 // Used for type casts and to test assignments. |
| 668 Value* EffectGraphVisitor::BuildAssignableValue(intptr_t token_pos, | 706 Value* EffectGraphVisitor::BuildAssignableValue(intptr_t token_pos, |
| 669 Value* value, | 707 Value* value, |
| 670 const AbstractType& dst_type, | 708 const AbstractType& dst_type, |
| 671 const String& dst_name) { | 709 const String& dst_name) { |
| 672 if (CanSkipTypeCheck(value, dst_type)) { | 710 if (CanSkipTypeCheck(token_pos, value, dst_type, dst_name)) { |
| 673 return value; | 711 return value; |
| 674 } | 712 } |
| 675 AssertAssignableComp* comp = BuildAssertAssignable(token_pos, | 713 AssertAssignableComp* comp = BuildAssertAssignable(token_pos, |
| 676 value, | 714 value, |
| 677 dst_type, | 715 dst_type, |
| 678 dst_name); | 716 dst_name); |
| 679 BindInstr* assert_assignable = new BindInstr(comp); | 717 BindInstr* assert_assignable = new BindInstr(comp); |
| 680 AddInstruction(assert_assignable); | 718 AddInstruction(assert_assignable); |
| 681 return new UseVal(assert_assignable); | 719 return new UseVal(assert_assignable); |
| 682 } | 720 } |
| 683 | 721 |
| 684 | 722 |
| 685 void EffectGraphVisitor::BuildTypeTest(ComparisonNode* node) { | 723 void EffectGraphVisitor::BuildTypeTest(ComparisonNode* node) { |
| 686 ASSERT(Token::IsTypeTestOperator(node->kind())); | 724 ASSERT(Token::IsTypeTestOperator(node->kind())); |
| 687 EffectGraphVisitor for_left_value(owner(), temp_index()); | 725 EffectGraphVisitor for_left_value(owner(), temp_index()); |
| 688 node->left()->Visit(&for_left_value); | 726 node->left()->Visit(&for_left_value); |
| 689 Append(for_left_value); | 727 Append(for_left_value); |
| 690 } | 728 } |
| 691 | 729 |
| 692 | 730 |
| 693 void EffectGraphVisitor::BuildTypeCast(ComparisonNode* node) { | 731 void EffectGraphVisitor::BuildTypeCast(ComparisonNode* node) { |
| 694 ASSERT(Token::IsTypeCastOperator(node->kind())); | 732 ASSERT(Token::IsTypeCastOperator(node->kind())); |
| 695 const AbstractType& type = node->right()->AsTypeNode()->type(); | 733 const AbstractType& type = node->right()->AsTypeNode()->type(); |
| 696 ASSERT(type.IsFinalized()); // The type in a type cast may be malformed. | 734 ASSERT(type.IsFinalized()); // The type in a type cast may be malformed. |
| 697 ValueGraphVisitor for_value(owner(), temp_index()); | 735 ValueGraphVisitor for_value(owner(), temp_index()); |
| 698 node->left()->Visit(&for_value); | 736 node->left()->Visit(&for_value); |
| 699 Append(for_value); | 737 Append(for_value); |
| 700 const String& dst_name = String::ZoneHandle( | 738 const String& dst_name = String::ZoneHandle( |
| 701 String::NewSymbol(Exceptions::kCastExceptionDstName)); | 739 String::NewSymbol(Exceptions::kCastExceptionDstName)); |
| 702 if (!CanSkipTypeCheck(for_value.value(), type)) { | 740 if (!CanSkipTypeCheck(node->token_pos(), for_value.value(), type, dst_name)) { |
| 703 AssertAssignableComp* assert_assignable = | 741 AssertAssignableComp* assert_assignable = |
| 704 BuildAssertAssignable(node->token_pos(), | 742 BuildAssertAssignable(node->token_pos(), |
| 705 for_value.value(), | 743 for_value.value(), |
| 706 type, | 744 type, |
| 707 dst_name); | 745 dst_name); |
| 708 AddInstruction(new DoInstr(assert_assignable)); | 746 AddInstruction(new DoInstr(assert_assignable)); |
| 709 } | 747 } |
| 710 } | 748 } |
| 711 | 749 |
| 712 | 750 |
| (...skipping 1470 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2183 // Skip type checking of receiver and phase for constructor functions. | 2221 // Skip type checking of receiver and phase for constructor functions. |
| 2184 pos = 2; | 2222 pos = 2; |
| 2185 } else if (function.IsFactory() || function.IsDynamicFunction()) { | 2223 } else if (function.IsFactory() || function.IsDynamicFunction()) { |
| 2186 // Skip type checking of type arguments for factory functions. | 2224 // Skip type checking of type arguments for factory functions. |
| 2187 // Skip type checking of receiver for instance functions. | 2225 // Skip type checking of receiver for instance functions. |
| 2188 pos = 1; | 2226 pos = 1; |
| 2189 } | 2227 } |
| 2190 while (pos < num_params) { | 2228 while (pos < num_params) { |
| 2191 const LocalVariable& parameter = *scope->VariableAt(pos); | 2229 const LocalVariable& parameter = *scope->VariableAt(pos); |
| 2192 ASSERT(parameter.owner() == scope); | 2230 ASSERT(parameter.owner() == scope); |
| 2193 if (!CanSkipTypeCheck(NULL, parameter.type())) { | 2231 if (!CanSkipTypeCheck(parameter.token_pos(), |
| 2232 NULL, | |
| 2233 parameter.type(), | |
| 2234 parameter.name())) { | |
| 2194 BindInstr* load = new BindInstr(BuildLoadLocal(parameter)); | 2235 BindInstr* load = new BindInstr(BuildLoadLocal(parameter)); |
| 2195 AddInstruction(load); | 2236 AddInstruction(load); |
| 2196 AssertAssignableComp* assert_assignable = | 2237 AssertAssignableComp* assert_assignable = |
| 2197 BuildAssertAssignable(parameter.token_pos(), | 2238 BuildAssertAssignable(parameter.token_pos(), |
| 2198 new UseVal(load), | 2239 new UseVal(load), |
| 2199 parameter.type(), | 2240 parameter.type(), |
| 2200 parameter.name()); | 2241 parameter.name()); |
| 2201 AddInstruction(new DoInstr(assert_assignable)); | 2242 AddInstruction(new DoInstr(assert_assignable)); |
| 2202 } | 2243 } |
| 2203 pos++; | 2244 pos++; |
| (...skipping 595 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2799 char* chars = reinterpret_cast<char*>( | 2840 char* chars = reinterpret_cast<char*>( |
| 2800 Isolate::Current()->current_zone()->Allocate(len)); | 2841 Isolate::Current()->current_zone()->Allocate(len)); |
| 2801 OS::SNPrint(chars, len, kFormat, function_name, reason); | 2842 OS::SNPrint(chars, len, kFormat, function_name, reason); |
| 2802 const Error& error = Error::Handle( | 2843 const Error& error = Error::Handle( |
| 2803 LanguageError::New(String::Handle(String::New(chars)))); | 2844 LanguageError::New(String::Handle(String::New(chars)))); |
| 2804 Isolate::Current()->long_jump_base()->Jump(1, error); | 2845 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 2805 } | 2846 } |
| 2806 | 2847 |
| 2807 | 2848 |
| 2808 } // namespace dart | 2849 } // namespace dart |
| OLD | NEW |