| 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 381 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 392 void ValueGraphVisitor::VisitLiteralNode(LiteralNode* node) { | 392 void ValueGraphVisitor::VisitLiteralNode(LiteralNode* node) { |
| 393 ReturnComputation(new ConstantVal(node->literal())); | 393 ReturnComputation(new ConstantVal(node->literal())); |
| 394 } | 394 } |
| 395 | 395 |
| 396 | 396 |
| 397 // Type nodes only occur as the right-hand side of instanceof comparisons, | 397 // Type nodes only occur as the right-hand side of instanceof comparisons, |
| 398 // and they are handled specially in that context. | 398 // and they are handled specially in that context. |
| 399 void EffectGraphVisitor::VisitTypeNode(TypeNode* node) { UNREACHABLE(); } | 399 void EffectGraphVisitor::VisitTypeNode(TypeNode* node) { UNREACHABLE(); } |
| 400 | 400 |
| 401 | 401 |
| 402 // Helper routine returning true if the static type of the given value is more | 402 // Returns true if the type check can be skipped, for example, if the |
| 403 // specific than the given dst_type. | 403 // destination type is Dynamic or if the static type of the value is a subtype |
| 404 static bool IsStaticTypeMoreSpecific(Value* value, | 404 // of the destination type. |
| 405 const AbstractType& dst_type) { | 405 bool EffectGraphVisitor::CanSkipTypeCheck(intptr_t token_pos, |
| 406 ASSERT(!dst_type.IsMalformed()); | 406 Value* value, |
| 407 const AbstractType& dst_type, |
| 408 const String& dst_name) { |
| 409 ASSERT(!dst_type.IsNull()); |
| 410 ASSERT(dst_type.IsFinalized()); |
| 411 |
| 412 // If the destination type is malformed, a dynamic type error must be thrown |
| 413 // at run time. |
| 414 if (dst_type.IsMalformed()) { |
| 415 return false; |
| 416 } |
| 407 | 417 |
| 408 // Any type is more specific than the Dynamic type and than the Object type. | 418 // Any type is more specific than the Dynamic type and than the Object type. |
| 409 if (dst_type.IsDynamicType() || dst_type.IsObjectType()) { | 419 if (dst_type.IsDynamicType() || dst_type.IsObjectType()) { |
| 410 return true; | 420 return true; |
| 411 } | 421 } |
| 412 | 422 |
| 413 // Do not perform type check elimination if this optimization is turned off. | 423 // Do not perform type check elimination if this optimization is turned off. |
| 414 if (!FLAG_eliminate_type_checks) { | 424 if (!FLAG_eliminate_type_checks) { |
| 415 return false; | 425 return false; |
| 416 } | 426 } |
| 417 | 427 |
| 418 // If nothing is known about the value, as is the case for passed-in | 428 // If nothing is known about the value, as is the case for passed-in |
| 419 // parameters, and since dst_type is not one of the tested cases above, then | 429 // parameters, and since dst_type is not one of the tested cases above, then |
| 420 // the type test cannot be eliminated. | 430 // the type test cannot be eliminated. |
| 421 if (value == NULL) { | 431 if (value == NULL) { |
| 422 return false; | 432 return false; |
| 423 } | 433 } |
| 424 | 434 |
| 425 // If the value is the null constant, its type (NullType) is more specific | 435 const bool eliminated = value->StaticTypeIsMoreSpecificThan(dst_type); |
| 426 // than the destination type, even if the destination type is the void type, | 436 if (FLAG_trace_type_check_elimination) { |
| 427 // since a void function is allowed to return null. | 437 FlowGraphPrinter::PrintTypeCheck(owner()->parsed_function(), |
| 428 if (value->IsConstant() && value->AsConstant()->value().IsNull()) { | 438 token_pos, |
| 429 return true; | 439 value, |
| 430 } | 440 dst_type, |
| 431 | 441 dst_name, |
| 432 // Functions that do not explicitly return a value, implicitly return null, | 442 eliminated); |
| 433 // except generative constructors, which return the object being constructed. | |
| 434 // It is therefore acceptable for void functions to return null. | |
| 435 // In case of a null constant, we have already returned true above, else we | |
| 436 // return false here. | |
| 437 if (dst_type.IsVoidType()) { | |
| 438 return false; | |
| 439 } | |
| 440 | |
| 441 // Consider the static type of the value. | |
| 442 const AbstractType& static_type = AbstractType::Handle(value->StaticType()); | |
| 443 ASSERT(!static_type.IsMalformed()); | |
| 444 | |
| 445 // If the static type of the value is void, we are type checking the result of | |
| 446 // a void function, which was checked to be null at the return statement | |
| 447 // inside the function. | |
| 448 if (static_type.IsVoidType()) { | |
| 449 return true; | |
| 450 } | |
| 451 | |
| 452 // If the static type of the value is NullType, the type test is eliminated. | |
| 453 // There are only three instances that can be of Class Null: | |
| 454 // Object::null(), Object::sentinel(), and Object::transition_sentinel(). | |
| 455 // The inline code and run time code performing the type check will never | |
| 456 // encounter the 2 sentinel values. The type check of a sentinel value | |
| 457 // will always be eliminated here, because these sentinel values can only | |
| 458 // be encountered as constants, never as actual value of a heap object | |
| 459 // being type checked. | |
| 460 if (static_type.IsNullType()) { | |
| 461 return true; | |
| 462 } | |
| 463 | |
| 464 // The run time type of the value is guaranteed to be a subtype of the | |
| 465 // compile time static type of the value. However, establishing here that | |
| 466 // the static type is a subtype of the destination type does not guarantee | |
| 467 // that the run time type will also be a subtype of the destination type, | |
| 468 // because the subtype relation is not transitive. | |
| 469 // However, the 'more specific than' relation is transitive and is used | |
| 470 // here. In other words, if the static type of the value is more specific | |
| 471 // than the destination type, the run time type of the value, which is | |
| 472 // guaranteed to be a subtype of the static type, is also guaranteed to be | |
| 473 // a subtype of the destination type and the type check can therefore be | |
| 474 // eliminated. | |
| 475 return static_type.IsMoreSpecificThan(dst_type, NULL); | |
| 476 } | |
| 477 | |
| 478 | |
| 479 // Returns true if the type check can be skipped, for example, if the | |
| 480 // destination type is Dynamic or if the static type of the value is a subtype | |
| 481 // of the destination type. | |
| 482 bool EffectGraphVisitor::CanSkipTypeCheck(intptr_t token_pos, | |
| 483 Value* value, | |
| 484 const AbstractType& dst_type, | |
| 485 const String& dst_name) { | |
| 486 ASSERT(!dst_type.IsNull()); | |
| 487 ASSERT(dst_type.IsFinalized()); | |
| 488 | |
| 489 // If the destination type is malformed, a dynamic type error must be thrown | |
| 490 // at run time. | |
| 491 if (dst_type.IsMalformed()) { | |
| 492 return false; | |
| 493 } | |
| 494 | |
| 495 const bool eliminated = IsStaticTypeMoreSpecific(value, dst_type); | |
| 496 if (FLAG_eliminate_type_checks && FLAG_trace_type_check_elimination) { | |
| 497 const Class& cls = Class::Handle( | |
| 498 owner()->parsed_function().function().owner()); | |
| 499 const Script& script = Script::Handle(cls.script()); | |
| 500 const char* static_type_name = "unknown"; | |
| 501 if (value != NULL) { | |
| 502 const AbstractType& type = AbstractType::Handle(value->StaticType()); | |
| 503 static_type_name = String::Handle(type.UserVisibleName()).ToCString(); | |
| 504 } | |
| 505 Parser::PrintMessage(script, token_pos, "", | |
| 506 "%s type check: static type '%s' is %s specific than " | |
| 507 "type '%s' of '%s'.", | |
| 508 eliminated ? "Eliminated" : "Generated", | |
| 509 static_type_name, | |
| 510 eliminated ? "more" : "not more", | |
| 511 String::Handle(dst_type.UserVisibleName()).ToCString(), | |
| 512 dst_name.ToCString()); | |
| 513 } | 443 } |
| 514 return eliminated; | 444 return eliminated; |
| 515 } | 445 } |
| 516 | 446 |
| 517 | 447 |
| 518 // <Expression> :: Assignable { expr: <Expression> | 448 // <Expression> :: Assignable { expr: <Expression> |
| 519 // type: AbstractType | 449 // type: AbstractType |
| 520 // dst_name: String } | 450 // dst_name: String } |
| 521 void EffectGraphVisitor::VisitAssignableNode(AssignableNode* node) { | 451 void EffectGraphVisitor::VisitAssignableNode(AssignableNode* node) { |
| 522 UNREACHABLE(); | 452 UNREACHABLE(); |
| (...skipping 2227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2750 char* chars = reinterpret_cast<char*>( | 2680 char* chars = reinterpret_cast<char*>( |
| 2751 Isolate::Current()->current_zone()->Allocate(len)); | 2681 Isolate::Current()->current_zone()->Allocate(len)); |
| 2752 OS::SNPrint(chars, len, kFormat, function_name, reason); | 2682 OS::SNPrint(chars, len, kFormat, function_name, reason); |
| 2753 const Error& error = Error::Handle( | 2683 const Error& error = Error::Handle( |
| 2754 LanguageError::New(String::Handle(String::New(chars)))); | 2684 LanguageError::New(String::Handle(String::New(chars)))); |
| 2755 Isolate::Current()->long_jump_base()->Jump(1, error); | 2685 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 2756 } | 2686 } |
| 2757 | 2687 |
| 2758 | 2688 |
| 2759 } // namespace dart | 2689 } // namespace dart |
| OLD | NEW |