| 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 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 320 | 322 |
| 321 void ValueGraphVisitor::VisitLiteralNode(LiteralNode* node) { | 323 void ValueGraphVisitor::VisitLiteralNode(LiteralNode* node) { |
| 322 ReturnComputation(new ConstantVal(node->literal())); | 324 ReturnComputation(new ConstantVal(node->literal())); |
| 323 } | 325 } |
| 324 | 326 |
| 325 // Type nodes only occur as the right-hand side of instanceof comparisons, | 327 // Type nodes only occur as the right-hand side of instanceof comparisons, |
| 326 // and they are handled specially in that context. | 328 // and they are handled specially in that context. |
| 327 void EffectGraphVisitor::VisitTypeNode(TypeNode* node) { UNREACHABLE(); } | 329 void EffectGraphVisitor::VisitTypeNode(TypeNode* node) { UNREACHABLE(); } |
| 328 | 330 |
| 329 | 331 |
| 330 // Returns true if the type check can be skipped, for example, if the | 332 // Helper routine returning true if the static type of the given value is more |
| 331 // destination type is Dynamic or if the static type of the value is a subtype | 333 // specific than the given dst_type. |
| 332 // of the destination type. | 334 static bool IsStaticTypeMoreSpecific(Value* value, |
| 333 static bool CanSkipTypeCheck(Value* value, const AbstractType& dst_type) { | 335 const AbstractType& dst_type) { |
| 334 ASSERT(!dst_type.IsNull()); | 336 ASSERT(!dst_type.IsMalformed()); |
| 335 ASSERT(dst_type.IsFinalized()); | |
| 336 if (!FLAG_eliminate_type_checks) { | |
| 337 return false; | |
| 338 } | |
| 339 | 337 |
| 340 // Any expression is assignable to the Dynamic type and to the Object type. | 338 // Any type is more specific than the Dynamic type and than the Object type. |
| 341 // Skip the test. | 339 if (dst_type.IsDynamicType() || dst_type.IsObjectType()) { |
| 342 if (!dst_type.IsMalformed() && | |
| 343 (dst_type.IsDynamicType() || dst_type.IsObjectType())) { | |
| 344 return true; | 340 return true; |
| 345 } | 341 } |
| 346 | 342 |
| 347 // It is a compile-time error to explicitly return a value (including null) | 343 // It is a compile-time error to explicitly return a value (including null) |
| 348 // from a void function. However, functions that do not explicitly return a | 344 // from a void function. However, functions that do not explicitly return a |
| 349 // value, implicitly return null. This includes void functions. Therefore, we | 345 // value, implicitly return null. This includes void functions. Therefore, we |
| 350 // skip the type test here and trust the parser to only return null in void | 346 // skip the type test here and trust the parser to only return null in void |
| 351 // function. | 347 // function. |
| 352 if (dst_type.IsVoidType()) { | 348 if (dst_type.IsVoidType()) { |
| 349 // TODO(regis): Should we perform this null test at run-time? |
| 353 return true; | 350 return true; |
| 354 } | 351 } |
| 355 | 352 |
| 353 // Do not perform type check elimination if this optimization is turned off. |
| 354 if (!FLAG_eliminate_type_checks) { |
| 355 return false; |
| 356 } |
| 357 |
| 356 // If nothing is known about the value, as is the case for passed-in | 358 // If nothing is known about the value, as is the case for passed-in |
| 357 // parameters, the test cannot be eliminated. | 359 // parameters, and since dst_type is not one of the tested cases above, then |
| 360 // the type test cannot be eliminated. |
| 358 if (value == NULL) { | 361 if (value == NULL) { |
| 359 return false; | 362 return false; |
| 360 } | 363 } |
| 361 | 364 |
| 362 // Consider the static type of the value. | 365 // Consider the static type of the value. |
| 363 const AbstractType& static_type = AbstractType::Handle(value->StaticType()); | 366 const AbstractType& static_type = AbstractType::Handle(value->StaticType()); |
| 364 ASSERT(!static_type.IsMalformed()); | 367 ASSERT(!static_type.IsMalformed()); |
| 365 | 368 |
| 366 // If the static type of the value is void, the only allowed value is null, | 369 // If the static type of the value is void, the only allowed value is null, |
| 367 // which must be verified by the type test. | 370 // which must be verified by the type test. |
| 371 // TODO(regis): Eliminate the test if the value is constant null. |
| 368 if (static_type.IsVoidType()) { | 372 if (static_type.IsVoidType()) { |
| 369 // TODO(regis): Eliminate the test if the value is constant null. | |
| 370 return false; | 373 return false; |
| 371 } | 374 } |
| 372 | 375 |
| 373 // If the static type of the value is NullType, the type test is eliminated. | 376 // If the static type of the value is NullType, the type test is eliminated. |
| 377 // There are only three instances that can be of Class Null: |
| 378 // Object::null(), Object::sentinel(), and Object::transition_sentinel(). |
| 379 // The inline code and run time code performing the type check will never |
| 380 // encounter the 2 sentinel values. The type check of a sentinel value |
| 381 // will always be eliminated here, because these sentinel values can only |
| 382 // be encountered as constants, never as actual value of a heap object |
| 383 // being type checked. |
| 374 if (static_type.IsNullType()) { | 384 if (static_type.IsNullType()) { |
| 375 // There are only three instances that can be of Class Null: | |
| 376 // Object::null(), Object::sentinel(), and Object::transition_sentinel(). | |
| 377 // The inline code and run time code performing the type check will never | |
| 378 // encounter the 2 sentinel values. The type check of a sentinel value | |
| 379 // will always be eliminated here, because these sentinel values can only | |
| 380 // be encountered as constants, never as actual value of a heap object | |
| 381 // being type checked. | |
| 382 return true; | 385 return true; |
| 383 } | 386 } |
| 384 | 387 |
| 385 // The run time type of the value is guaranteed to be a subtype of the compile | 388 // The run time type of the value is guaranteed to be a subtype of the |
| 386 // time static type of the value. However, establishing here that the static | 389 // compile time static type of the value. However, establishing here that |
| 387 // type is a subtype of the destination type does not guarantee that the run | 390 // the static type is a subtype of the destination type does not guarantee |
| 388 // time type will also be a subtype of the destination type, because the | 391 // that the run time type will also be a subtype of the destination type, |
| 389 // subtype relation is not transitive. | 392 // because the subtype relation is not transitive. |
| 390 // However, the 'more specific than' relation is transitive and is used here. | 393 // However, the 'more specific than' relation is transitive and is used |
| 391 // In other words, if the static type of the value is more specific than the | 394 // here. In other words, if the static type of the value is more specific |
| 392 // destination type, the run time type of the value, which is guaranteed to | 395 // than the destination type, the run time type of the value, which is |
| 393 // be a subtype of the static type, is also guaranteed to be a subtype of the | 396 // guaranteed to be a subtype of the static type, is also guaranteed to be |
| 394 // destination type and the type check can therefore be eliminated. | 397 // a subtype of the destination type and the type check can therefore be |
| 398 // eliminated. |
| 395 Error& malformed_error = Error::Handle(); | 399 Error& malformed_error = Error::Handle(); |
| 396 if (static_type.IsMoreSpecificThan(dst_type, &malformed_error)) { | 400 return static_type.IsMoreSpecificThan(dst_type, &malformed_error); |
| 397 return true; | |
| 398 } | |
| 399 | |
| 400 return false; | |
| 401 } | 401 } |
| 402 | 402 |
| 403 | 403 |
| 404 // Returns true if the type check can be skipped, for example, if the |
| 405 // destination type is Dynamic or if the static type of the value is a subtype |
| 406 // of the destination type. |
| 407 bool EffectGraphVisitor::CanSkipTypeCheck(intptr_t token_pos, |
| 408 Value* value, |
| 409 const AbstractType& dst_type, |
| 410 const String& dst_name) { |
| 411 ASSERT(!dst_type.IsNull()); |
| 412 ASSERT(dst_type.IsFinalized()); |
| 413 |
| 414 // If the destination type is malformed, a dynamic type error must be thrown |
| 415 // at run time. |
| 416 if (dst_type.IsMalformed()) { |
| 417 return false; |
| 418 } |
| 419 |
| 420 const bool eliminated = IsStaticTypeMoreSpecific(value, dst_type); |
| 421 if (FLAG_eliminate_type_checks && FLAG_trace_type_check_elimination) { |
| 422 const Class& cls = Class::Handle( |
| 423 owner()->parsed_function().function().owner()); |
| 424 const Script& script = Script::Handle(cls.script()); |
| 425 const char* static_type_name = "unknown"; |
| 426 if (value != NULL) { |
| 427 const AbstractType& type = AbstractType::Handle(value->StaticType()); |
| 428 static_type_name = String::Handle(type.Name()).ToCString(); |
| 429 } |
| 430 Parser::PrintMessage(script, token_pos, "", |
| 431 "%s type check: static type '%s' is %s specific than " |
| 432 "type '%s' of '%s'.", |
| 433 eliminated ? "Eliminated" : "Generated", |
| 434 static_type_name, |
| 435 eliminated ? "more" : "not more", |
| 436 String::Handle(dst_type.Name()).ToCString(), |
| 437 dst_name.ToCString()); |
| 438 } |
| 439 return eliminated; |
| 440 } |
| 441 |
| 442 |
| 404 // <Expression> :: Assignable { expr: <Expression> | 443 // <Expression> :: Assignable { expr: <Expression> |
| 405 // type: AbstractType | 444 // type: AbstractType |
| 406 // dst_name: String } | 445 // dst_name: String } |
| 407 void EffectGraphVisitor::VisitAssignableNode(AssignableNode* node) { | 446 void EffectGraphVisitor::VisitAssignableNode(AssignableNode* node) { |
| 408 UNREACHABLE(); | 447 UNREACHABLE(); |
| 409 } | 448 } |
| 410 | 449 |
| 411 | 450 |
| 412 void ValueGraphVisitor::VisitAssignableNode(AssignableNode* node) { | 451 void ValueGraphVisitor::VisitAssignableNode(AssignableNode* node) { |
| 413 ValueGraphVisitor for_value(owner(), temp_index()); | 452 ValueGraphVisitor for_value(owner(), temp_index()); |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 582 dst_type, | 621 dst_type, |
| 583 dst_name); | 622 dst_name); |
| 584 } | 623 } |
| 585 | 624 |
| 586 | 625 |
| 587 // Used for type casts and to test assignments. | 626 // Used for type casts and to test assignments. |
| 588 Value* EffectGraphVisitor::BuildAssignableValue(intptr_t token_pos, | 627 Value* EffectGraphVisitor::BuildAssignableValue(intptr_t token_pos, |
| 589 Value* value, | 628 Value* value, |
| 590 const AbstractType& dst_type, | 629 const AbstractType& dst_type, |
| 591 const String& dst_name) { | 630 const String& dst_name) { |
| 592 if (CanSkipTypeCheck(value, dst_type)) { | 631 if (CanSkipTypeCheck(token_pos, value, dst_type, dst_name)) { |
| 593 return value; | 632 return value; |
| 594 } | 633 } |
| 595 return Bind(BuildAssertAssignable(token_pos, value, dst_type, dst_name)); | 634 return Bind(BuildAssertAssignable(token_pos, value, dst_type, dst_name)); |
| 596 } | 635 } |
| 597 | 636 |
| 598 | 637 |
| 599 void EffectGraphVisitor::BuildTypeTest(ComparisonNode* node) { | 638 void EffectGraphVisitor::BuildTypeTest(ComparisonNode* node) { |
| 600 ASSERT(Token::IsTypeTestOperator(node->kind())); | 639 ASSERT(Token::IsTypeTestOperator(node->kind())); |
| 601 EffectGraphVisitor for_left_value(owner(), temp_index()); | 640 EffectGraphVisitor for_left_value(owner(), temp_index()); |
| 602 node->left()->Visit(&for_left_value); | 641 node->left()->Visit(&for_left_value); |
| 603 Append(for_left_value); | 642 Append(for_left_value); |
| 604 } | 643 } |
| 605 | 644 |
| 606 | 645 |
| 607 void EffectGraphVisitor::BuildTypeCast(ComparisonNode* node) { | 646 void EffectGraphVisitor::BuildTypeCast(ComparisonNode* node) { |
| 608 ASSERT(Token::IsTypeCastOperator(node->kind())); | 647 ASSERT(Token::IsTypeCastOperator(node->kind())); |
| 609 const AbstractType& type = node->right()->AsTypeNode()->type(); | 648 const AbstractType& type = node->right()->AsTypeNode()->type(); |
| 610 ASSERT(type.IsFinalized()); // The type in a type cast may be malformed. | 649 ASSERT(type.IsFinalized()); // The type in a type cast may be malformed. |
| 611 ValueGraphVisitor for_value(owner(), temp_index()); | 650 ValueGraphVisitor for_value(owner(), temp_index()); |
| 612 node->left()->Visit(&for_value); | 651 node->left()->Visit(&for_value); |
| 613 Append(for_value); | 652 Append(for_value); |
| 614 const String& dst_name = String::ZoneHandle( | 653 const String& dst_name = String::ZoneHandle( |
| 615 String::NewSymbol(Exceptions::kCastExceptionDstName)); | 654 String::NewSymbol(Exceptions::kCastExceptionDstName)); |
| 616 if (!CanSkipTypeCheck(for_value.value(), type)) { | 655 if (!CanSkipTypeCheck(node->token_pos(), for_value.value(), type, dst_name)) { |
| 617 Do(BuildAssertAssignable( | 656 Do(BuildAssertAssignable( |
| 618 node->token_pos(), for_value.value(), type, dst_name)); | 657 node->token_pos(), for_value.value(), type, dst_name)); |
| 619 } | 658 } |
| 620 } | 659 } |
| 621 | 660 |
| 622 | 661 |
| 623 void ValueGraphVisitor::BuildTypeTest(ComparisonNode* node) { | 662 void ValueGraphVisitor::BuildTypeTest(ComparisonNode* node) { |
| 624 ASSERT(Token::IsTypeTestOperator(node->kind())); | 663 ASSERT(Token::IsTypeTestOperator(node->kind())); |
| 625 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); | 664 const Bool& bool_true = Bool::ZoneHandle(Bool::True()); |
| 626 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); | 665 const Bool& bool_false = Bool::ZoneHandle(Bool::False()); |
| (...skipping 1385 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2012 // Skip type checking of receiver and phase for constructor functions. | 2051 // Skip type checking of receiver and phase for constructor functions. |
| 2013 pos = 2; | 2052 pos = 2; |
| 2014 } else if (function.IsFactory() || function.IsDynamicFunction()) { | 2053 } else if (function.IsFactory() || function.IsDynamicFunction()) { |
| 2015 // Skip type checking of type arguments for factory functions. | 2054 // Skip type checking of type arguments for factory functions. |
| 2016 // Skip type checking of receiver for instance functions. | 2055 // Skip type checking of receiver for instance functions. |
| 2017 pos = 1; | 2056 pos = 1; |
| 2018 } | 2057 } |
| 2019 while (pos < num_params) { | 2058 while (pos < num_params) { |
| 2020 const LocalVariable& parameter = *scope->VariableAt(pos); | 2059 const LocalVariable& parameter = *scope->VariableAt(pos); |
| 2021 ASSERT(parameter.owner() == scope); | 2060 ASSERT(parameter.owner() == scope); |
| 2022 if (!CanSkipTypeCheck(NULL, parameter.type())) { | 2061 if (!CanSkipTypeCheck(parameter.token_pos(), |
| 2062 NULL, |
| 2063 parameter.type(), |
| 2064 parameter.name())) { |
| 2023 Value* load = Bind(BuildLoadLocal(parameter)); | 2065 Value* load = Bind(BuildLoadLocal(parameter)); |
| 2024 Do(BuildAssertAssignable(parameter.token_pos(), | 2066 Do(BuildAssertAssignable(parameter.token_pos(), |
| 2025 load, | 2067 load, |
| 2026 parameter.type(), | 2068 parameter.type(), |
| 2027 parameter.name())); | 2069 parameter.name())); |
| 2028 } | 2070 } |
| 2029 pos++; | 2071 pos++; |
| 2030 } | 2072 } |
| 2031 } | 2073 } |
| 2032 | 2074 |
| (...skipping 586 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2619 char* chars = reinterpret_cast<char*>( | 2661 char* chars = reinterpret_cast<char*>( |
| 2620 Isolate::Current()->current_zone()->Allocate(len)); | 2662 Isolate::Current()->current_zone()->Allocate(len)); |
| 2621 OS::SNPrint(chars, len, kFormat, function_name, reason); | 2663 OS::SNPrint(chars, len, kFormat, function_name, reason); |
| 2622 const Error& error = Error::Handle( | 2664 const Error& error = Error::Handle( |
| 2623 LanguageError::New(String::Handle(String::New(chars)))); | 2665 LanguageError::New(String::Handle(String::New(chars)))); |
| 2624 Isolate::Current()->long_jump_base()->Jump(1, error); | 2666 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 2625 } | 2667 } |
| 2626 | 2668 |
| 2627 | 2669 |
| 2628 } // namespace dart | 2670 } // namespace dart |
| OLD | NEW |