Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(64)

Side by Side Diff: runtime/vm/class_finalizer.cc

Issue 13653005: Prevent expensive and unnecessary error formatting in the case a bound check is (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/class_finalizer.h ('k') | runtime/vm/object.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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/class_finalizer.h" 5 #include "vm/class_finalizer.h"
6 6
7 #include "vm/flags.h" 7 #include "vm/flags.h"
8 #include "vm/heap.h" 8 #include "vm/heap.h"
9 #include "vm/isolate.h" 9 #include "vm/isolate.h"
10 #include "vm/longjump.h" 10 #include "vm/longjump.h"
(...skipping 489 matching lines...) Expand 10 before | Expand all | Expand 10 after
500 // i.e. cls_args = [String, double], offset = 2, length = 2. 500 // i.e. cls_args = [String, double], offset = 2, length = 2.
501 // Output: arguments = [int, double, String, double] 501 // Output: arguments = [int, double, String, double]
502 void ClassFinalizer::FinalizeTypeArguments( 502 void ClassFinalizer::FinalizeTypeArguments(
503 const Class& cls, 503 const Class& cls,
504 const AbstractTypeArguments& arguments, 504 const AbstractTypeArguments& arguments,
505 FinalizationKind finalization, 505 FinalizationKind finalization,
506 Error* bound_error) { 506 Error* bound_error) {
507 ASSERT(arguments.Length() >= cls.NumTypeArguments()); 507 ASSERT(arguments.Length() >= cls.NumTypeArguments());
508 if (!cls.is_finalized()) { 508 if (!cls.is_finalized()) {
509 FinalizeTypeParameters(cls); 509 FinalizeTypeParameters(cls);
510 ResolveUpperBounds(cls);
510 } 511 }
511 AbstractType& super_type = AbstractType::Handle(cls.super_type()); 512 AbstractType& super_type = AbstractType::Handle(cls.super_type());
512 if (!super_type.IsNull()) { 513 if (!super_type.IsNull()) {
513 const Class& super_class = Class::Handle(super_type.type_class()); 514 const Class& super_class = Class::Handle(super_type.type_class());
514 AbstractTypeArguments& super_type_args = AbstractTypeArguments::Handle(); 515 AbstractTypeArguments& super_type_args = AbstractTypeArguments::Handle();
515 if (super_type.IsBeingFinalized()) { 516 if (super_type.IsBeingFinalized()) {
516 // This type references itself via its type arguments. This is legal, but 517 // This type references itself via its type arguments. This is legal, but
517 // we must avoid endless recursion. We therefore map the innermost 518 // we must avoid endless recursion. We therefore map the innermost
518 // super type to dynamic. 519 // super type to dynamic.
519 // Note that a direct self-reference via the super class chain is illegal 520 // Note that a direct self-reference via the super class chain is illegal
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
567 // Check the type argument vector 'arguments' against the corresponding bounds 568 // Check the type argument vector 'arguments' against the corresponding bounds
568 // of the type parameters of class 'cls' and, recursively, of its superclasses. 569 // of the type parameters of class 'cls' and, recursively, of its superclasses.
569 // Replace a type argument that cannot be checked at compile time by a 570 // Replace a type argument that cannot be checked at compile time by a
570 // BoundedType, thereby postponing the bound check to run time. 571 // BoundedType, thereby postponing the bound check to run time.
571 // Return a bound error if a type argument is not within bound at compile time. 572 // Return a bound error if a type argument is not within bound at compile time.
572 void ClassFinalizer::CheckTypeArgumentBounds( 573 void ClassFinalizer::CheckTypeArgumentBounds(
573 const Class& cls, 574 const Class& cls,
574 const AbstractTypeArguments& arguments, 575 const AbstractTypeArguments& arguments,
575 Error* bound_error) { 576 Error* bound_error) {
576 if (!cls.is_finalized()) { 577 if (!cls.is_finalized()) {
577 ResolveAndFinalizeUpperBounds(cls); 578 FinalizeUpperBounds(cls);
578 } 579 }
579 // Note that when finalizing a type, we need to verify the bounds in both 580 // Note that when finalizing a type, we need to verify the bounds in both
580 // production mode and checked mode, because the finalized type may be written 581 // production mode and checked mode, because the finalized type may be written
581 // to a snapshot. It would be wrong to ignore bounds when generating the 582 // to a snapshot. It would be wrong to ignore bounds when generating the
582 // snapshot in production mode and then use the unchecked type in checked mode 583 // snapshot in production mode and then use the unchecked type in checked mode
583 // after reading it from the snapshot. 584 // after reading it from the snapshot.
584 // However, we do not immediately report a bound error, which would be wrong 585 // However, we do not immediately report a bound error, which would be wrong
585 // in production mode, but simply postpone the bound checking to runtime. 586 // in production mode, but simply postpone the bound checking to runtime.
586 const intptr_t num_type_params = cls.NumTypeParameters(); 587 const intptr_t num_type_params = cls.NumTypeParameters();
587 const intptr_t offset = cls.NumTypeArguments() - num_type_params; 588 const intptr_t offset = cls.NumTypeArguments() - num_type_params;
(...skipping 12 matching lines...) Expand all
600 } 601 }
601 cls_type_param = cls_type_params.TypeAt(i); 602 cls_type_param = cls_type_params.TypeAt(i);
602 const TypeParameter& type_param = TypeParameter::Cast(cls_type_param); 603 const TypeParameter& type_param = TypeParameter::Cast(cls_type_param);
603 ASSERT(type_param.IsFinalized()); 604 ASSERT(type_param.IsFinalized());
604 declared_bound = type_param.bound(); 605 declared_bound = type_param.bound();
605 if (!declared_bound.IsObjectType() && !declared_bound.IsDynamicType()) { 606 if (!declared_bound.IsObjectType() && !declared_bound.IsDynamicType()) {
606 Error& malformed_error = Error::Handle(); 607 Error& malformed_error = Error::Handle();
607 // Note that the bound may be malformed, in which case the bound check 608 // Note that the bound may be malformed, in which case the bound check
608 // will return an error and the bound check will be postponed to run time. 609 // will return an error and the bound check will be postponed to run time.
609 // Note also that the bound may still be unfinalized. 610 // Note also that the bound may still be unfinalized.
610 if (!declared_bound.IsFinalized()) {
611 ASSERT(declared_bound.IsBeingFinalized());
612 // The bound refers to type parameters, creating a cycle; postpone
613 // bound check to run time, when the bound will be finalized.
614 // TODO(regis): Do we need to instantiate an uninstantiated bound here?
615 type_arg = BoundedType::New(type_arg, declared_bound, type_param);
616 arguments.SetTypeAt(offset + i, type_arg);
617 continue;
618 }
619 if (declared_bound.IsInstantiated()) { 611 if (declared_bound.IsInstantiated()) {
620 instantiated_bound = declared_bound.raw(); 612 instantiated_bound = declared_bound.raw();
621 } else { 613 } else {
622 instantiated_bound = 614 instantiated_bound =
623 declared_bound.InstantiateFrom(arguments, &malformed_error); 615 declared_bound.InstantiateFrom(arguments, &malformed_error);
624 } 616 }
617 if (!instantiated_bound.IsFinalized()) {
618 // The bound refers to type parameters, creating a cycle; postpone
619 // bound check to run time, when the bound will be finalized.
620 // The bound may not necessarily be 'IsBeingFinalized' yet, as is the
621 // case with a pair of type parameters of the same class referring to
622 // each other via their bounds.
623 type_arg = BoundedType::New(type_arg, instantiated_bound, type_param);
624 arguments.SetTypeAt(offset + i, type_arg);
625 continue;
626 }
625 // TODO(regis): We could simplify this code if we could differentiate 627 // TODO(regis): We could simplify this code if we could differentiate
626 // between a failed bound check and a bound check that is undecidable at 628 // between a failed bound check and a bound check that is undecidable at
627 // compile time. 629 // compile time.
628 // Shortcut the special case where we check a type parameter against its 630 // Shortcut the special case where we check a type parameter against its
629 // declared upper bound. 631 // declared upper bound.
632 bool below_bound = true;
630 if (malformed_error.IsNull() && 633 if (malformed_error.IsNull() &&
631 (!type_arg.Equals(type_param) || 634 (!type_arg.Equals(type_param) ||
632 !instantiated_bound.Equals(declared_bound))) { 635 !instantiated_bound.Equals(declared_bound))) {
633 type_param.CheckBound(type_arg, instantiated_bound, &malformed_error); 636 // Pass NULL to prevent expensive and unnecessary error formatting in
637 // the case the bound check is postponed to run time.
638 below_bound = type_param.CheckBound(type_arg, instantiated_bound, NULL);
634 } 639 }
635 if (!malformed_error.IsNull()) { 640 if (!malformed_error.IsNull() || !below_bound) {
636 if (!type_arg.IsInstantiated() || 641 if (!type_arg.IsInstantiated() ||
637 !instantiated_bound.IsInstantiated()) { 642 !instantiated_bound.IsInstantiated()) {
638 type_arg = BoundedType::New(type_arg, instantiated_bound, type_param); 643 type_arg = BoundedType::New(type_arg, instantiated_bound, type_param);
639 arguments.SetTypeAt(offset + i, type_arg); 644 arguments.SetTypeAt(offset + i, type_arg);
640 } else if (bound_error->IsNull()) { 645 } else if (bound_error->IsNull()) {
646 if (malformed_error.IsNull()) {
647 // Call CheckBound again to format error message.
648 type_param.CheckBound(type_arg,
649 instantiated_bound,
650 &malformed_error);
651 }
652 ASSERT(!malformed_error.IsNull());
641 *bound_error = malformed_error.raw(); 653 *bound_error = malformed_error.raw();
642 } 654 }
643 } 655 }
644 } 656 }
645 } 657 }
646 AbstractType& super_type = AbstractType::Handle(cls.super_type()); 658 AbstractType& super_type = AbstractType::Handle(cls.super_type());
647 if (!super_type.IsNull()) { 659 if (!super_type.IsNull()) {
648 const Class& super_class = Class::Handle(super_type.type_class()); 660 const Class& super_class = Class::Handle(super_type.type_class());
649 CheckTypeArgumentBounds(super_class, arguments, bound_error); 661 CheckTypeArgumentBounds(super_class, arguments, bound_error);
650 } 662 }
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
710 parameterized_type.set_is_being_finalized(); 722 parameterized_type.set_is_being_finalized();
711 723
712 // The type class does not need to be finalized in order to finalize the type, 724 // The type class does not need to be finalized in order to finalize the type,
713 // however, it must at least be resolved (this was done as part of resolving 725 // however, it must at least be resolved (this was done as part of resolving
714 // the type itself, a precondition to calling FinalizeType). 726 // the type itself, a precondition to calling FinalizeType).
715 // Also, the interfaces of the type class must be resolved and the type 727 // Also, the interfaces of the type class must be resolved and the type
716 // parameters of the type class must be finalized. 728 // parameters of the type class must be finalized.
717 Class& type_class = Class::Handle(parameterized_type.type_class()); 729 Class& type_class = Class::Handle(parameterized_type.type_class());
718 if (!type_class.is_finalized()) { 730 if (!type_class.is_finalized()) {
719 FinalizeTypeParameters(type_class); 731 FinalizeTypeParameters(type_class);
732 ResolveUpperBounds(type_class);
720 } 733 }
721 734
722 // Finalize the current type arguments of the type, which are still the 735 // Finalize the current type arguments of the type, which are still the
723 // parsed type arguments. 736 // parsed type arguments.
724 AbstractTypeArguments& arguments = 737 AbstractTypeArguments& arguments =
725 AbstractTypeArguments::Handle(parameterized_type.arguments()); 738 AbstractTypeArguments::Handle(parameterized_type.arguments());
726 if (!arguments.IsNull()) { 739 if (!arguments.IsNull()) {
727 intptr_t num_arguments = arguments.Length(); 740 intptr_t num_arguments = arguments.Length();
728 AbstractType& type_argument = AbstractType::Handle(); 741 AbstractType& type_argument = AbstractType::Handle();
729 for (intptr_t i = 0; i < num_arguments; i++) { 742 for (intptr_t i = 0; i < num_arguments; i++) {
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after
971 !function.is_static() && 984 !function.is_static() &&
972 !function.IsMethodExtractor()) { 985 !function.IsMethodExtractor()) {
973 return super_class.raw(); 986 return super_class.raw();
974 } 987 }
975 super_class = super_class.SuperClass(); 988 super_class = super_class.SuperClass();
976 } 989 }
977 return Class::null(); 990 return Class::null();
978 } 991 }
979 992
980 993
981 // Resolve and finalize the upper bounds of the type parameters of class cls. 994 // Resolve the upper bounds of the type parameters of class cls.
982 void ClassFinalizer::ResolveAndFinalizeUpperBounds(const Class& cls) { 995 void ClassFinalizer::ResolveUpperBounds(const Class& cls) {
983 const intptr_t num_type_params = cls.NumTypeParameters(); 996 const intptr_t num_type_params = cls.NumTypeParameters();
984 TypeParameter& type_param = TypeParameter::Handle(); 997 TypeParameter& type_param = TypeParameter::Handle();
985 AbstractType& bound = AbstractType::Handle(); 998 AbstractType& bound = AbstractType::Handle();
986 const AbstractTypeArguments& type_params = 999 const AbstractTypeArguments& type_params =
987 AbstractTypeArguments::Handle(cls.type_parameters()); 1000 AbstractTypeArguments::Handle(cls.type_parameters());
988 ASSERT((type_params.IsNull() && (num_type_params == 0)) || 1001 ASSERT((type_params.IsNull() && (num_type_params == 0)) ||
989 (type_params.Length() == num_type_params)); 1002 (type_params.Length() == num_type_params));
1003 // In a first pass, resolve all bounds. This guarantees that finalization
1004 // of mutually referencing bounds will not encounter an unresolved bound.
1005 for (intptr_t i = 0; i < num_type_params; i++) {
1006 type_param ^= type_params.TypeAt(i);
1007 bound = type_param.bound();
1008 ResolveType(cls, bound, kCanonicalize);
1009 }
1010 }
1011
1012
1013 // Finalize the upper bounds of the type parameters of class cls.
1014 void ClassFinalizer::FinalizeUpperBounds(const Class& cls) {
1015 const intptr_t num_type_params = cls.NumTypeParameters();
1016 TypeParameter& type_param = TypeParameter::Handle();
1017 AbstractType& bound = AbstractType::Handle();
1018 const AbstractTypeArguments& type_params =
1019 AbstractTypeArguments::Handle(cls.type_parameters());
1020 ASSERT((type_params.IsNull() && (num_type_params == 0)) ||
1021 (type_params.Length() == num_type_params));
990 for (intptr_t i = 0; i < num_type_params; i++) { 1022 for (intptr_t i = 0; i < num_type_params; i++) {
991 type_param ^= type_params.TypeAt(i); 1023 type_param ^= type_params.TypeAt(i);
992 bound = type_param.bound(); 1024 bound = type_param.bound();
993 if (bound.IsFinalized() || bound.IsBeingFinalized()) { 1025 if (bound.IsFinalized() || bound.IsBeingFinalized()) {
994 // A bound involved in F-bounded quantification may form a cycle. 1026 // A bound involved in F-bounded quantification may form a cycle.
995 continue; 1027 continue;
996 } 1028 }
997 ResolveType(cls, bound, kCanonicalize);
998 bound = FinalizeType(cls, bound, kCanonicalize); 1029 bound = FinalizeType(cls, bound, kCanonicalize);
999 type_param.set_bound(bound); 1030 type_param.set_bound(bound);
1000 } 1031 }
1001 } 1032 }
1002 1033
1003 1034
1004 void ClassFinalizer::ResolveAndFinalizeMemberTypes(const Class& cls) { 1035 void ClassFinalizer::ResolveAndFinalizeMemberTypes(const Class& cls) {
1005 // Note that getters and setters are explicitly listed as such in the list of 1036 // Note that getters and setters are explicitly listed as such in the list of
1006 // functions of a class, so we do not need to consider fields as implicitly 1037 // functions of a class, so we do not need to consider fields as implicitly
1007 // generating getters and setters. 1038 // generating getters and setters.
(...skipping 354 matching lines...) Expand 10 before | Expand all | Expand 10 after
1362 FinalizeClass(super_class); 1393 FinalizeClass(super_class);
1363 } 1394 }
1364 if (cls.mixin() != Type::null()) { 1395 if (cls.mixin() != Type::null()) {
1365 // Copy instance methods and fields from the mixin class. 1396 // Copy instance methods and fields from the mixin class.
1366 // This has to happen before the check whether the methods of 1397 // This has to happen before the check whether the methods of
1367 // the class conflict with inherited methods. 1398 // the class conflict with inherited methods.
1368 ApplyMixin(cls); 1399 ApplyMixin(cls);
1369 } 1400 }
1370 // Finalize type parameters before finalizing the super type. 1401 // Finalize type parameters before finalizing the super type.
1371 FinalizeTypeParameters(cls); 1402 FinalizeTypeParameters(cls);
1403 ResolveUpperBounds(cls);
1372 // Finalize super type. 1404 // Finalize super type.
1373 AbstractType& super_type = AbstractType::Handle(cls.super_type()); 1405 AbstractType& super_type = AbstractType::Handle(cls.super_type());
1374 if (!super_type.IsNull()) { 1406 if (!super_type.IsNull()) {
1375 // In case of a bound error in the super type in production mode, the 1407 // In case of a bound error in the super type in production mode, the
1376 // finalized super type will be a BoundedType with a malformed bound. 1408 // finalized super type will be a BoundedType with a malformed bound.
1377 // It should not be a problem if the class is written to a snapshot and 1409 // It should not be a problem if the class is written to a snapshot and
1378 // later executed in checked mode. Note that the finalized type argument 1410 // later executed in checked mode. Note that the finalized type argument
1379 // vector of any type of the base class will contain a BoundedType for the 1411 // vector of any type of the base class will contain a BoundedType for the
1380 // out of bound type argument. 1412 // out of bound type argument.
1381 super_type = FinalizeType(cls, super_type, kCanonicalizeWellFormed); 1413 super_type = FinalizeType(cls, super_type, kCanonicalizeWellFormed);
1382 cls.set_super_type(super_type); 1414 cls.set_super_type(super_type);
1383 } 1415 }
1384 if (cls.IsSignatureClass()) { 1416 if (cls.IsSignatureClass()) {
1385 // Check for illegal self references. 1417 // Check for illegal self references.
1386 GrowableArray<intptr_t> visited_aliases; 1418 GrowableArray<intptr_t> visited_aliases;
1387 if (!IsAliasCycleFree(cls, &visited_aliases)) { 1419 if (!IsAliasCycleFree(cls, &visited_aliases)) {
1388 const String& name = String::Handle(cls.Name()); 1420 const String& name = String::Handle(cls.Name());
1389 const Script& script = Script::Handle(cls.script()); 1421 const Script& script = Script::Handle(cls.script());
1390 ReportError(script, cls.token_pos(), 1422 ReportError(script, cls.token_pos(),
1391 "typedef '%s' illegally refers to itself", 1423 "typedef '%s' illegally refers to itself",
1392 name.ToCString()); 1424 name.ToCString());
1393 } 1425 }
1394 cls.Finalize(); 1426 cls.Finalize();
1395 // Signature classes extend Object. No need to add this class to the direct 1427 // Signature classes extend Object. No need to add this class to the direct
1396 // subclasses of Object. 1428 // subclasses of Object.
1397 ASSERT(super_type.IsNull() || super_type.IsObjectType()); 1429 ASSERT(super_type.IsNull() || super_type.IsObjectType());
1398 1430
1399 // The type parameters of signature classes may have bounds. 1431 // The type parameters of signature classes may have bounds.
1400 ResolveAndFinalizeUpperBounds(cls); 1432 FinalizeUpperBounds(cls);
1401 1433
1402 // Resolve and finalize the result and parameter types of the signature 1434 // Resolve and finalize the result and parameter types of the signature
1403 // function of this signature class. 1435 // function of this signature class.
1404 const Function& sig_function = Function::Handle(cls.signature_function()); 1436 const Function& sig_function = Function::Handle(cls.signature_function());
1405 ResolveAndFinalizeSignature(cls, sig_function); 1437 ResolveAndFinalizeSignature(cls, sig_function);
1406 1438
1407 // Resolve and finalize the signature type of this signature class. 1439 // Resolve and finalize the signature type of this signature class.
1408 const Type& sig_type = Type::Handle(cls.SignatureType()); 1440 const Type& sig_type = Type::Handle(cls.SignatureType());
1409 FinalizeType(cls, sig_type, kCanonicalizeWellFormed); 1441 FinalizeType(cls, sig_type, kCanonicalizeWellFormed);
1410 return; 1442 return;
(...skipping 30 matching lines...) Expand all
1441 String::Handle(interface_type.Name()).ToCString(), 1473 String::Handle(interface_type.Name()).ToCString(),
1442 String::Handle(cls.Name()).ToCString()); 1474 String::Handle(cls.Name()).ToCString());
1443 } 1475 }
1444 } 1476 }
1445 } 1477 }
1446 // Mark as finalized before resolving type parameter upper bounds and member 1478 // Mark as finalized before resolving type parameter upper bounds and member
1447 // types in order to break cycles. 1479 // types in order to break cycles.
1448 cls.Finalize(); 1480 cls.Finalize();
1449 // Finalize bounds even if running in production mode, so that a snapshot 1481 // Finalize bounds even if running in production mode, so that a snapshot
1450 // contains them. 1482 // contains them.
1451 ResolveAndFinalizeUpperBounds(cls); 1483 FinalizeUpperBounds(cls);
1452 ResolveAndFinalizeMemberTypes(cls); 1484 ResolveAndFinalizeMemberTypes(cls);
1453 // Run additional checks after all types are finalized. 1485 // Run additional checks after all types are finalized.
1454 if (cls.is_const()) { 1486 if (cls.is_const()) {
1455 CheckForLegalConstClass(cls); 1487 CheckForLegalConstClass(cls);
1456 } 1488 }
1457 // Add this class to the direct subclasses of the superclass, unless the 1489 // Add this class to the direct subclasses of the superclass, unless the
1458 // superclass is Object. 1490 // superclass is Object.
1459 if (!super_type.IsNull() && !super_type.IsObjectType()) { 1491 if (!super_type.IsNull() && !super_type.IsObjectType()) {
1460 ASSERT(!super_class.IsNull()); 1492 ASSERT(!super_class.IsNull());
1461 super_class.AddDirectSubclass(cls); 1493 super_class.AddDirectSubclass(cls);
(...skipping 473 matching lines...) Expand 10 before | Expand all | Expand 10 after
1935 void ClassFinalizer::ReportError(const char* format, ...) { 1967 void ClassFinalizer::ReportError(const char* format, ...) {
1936 va_list args; 1968 va_list args;
1937 va_start(args, format); 1969 va_start(args, format);
1938 const Error& error = Error::Handle( 1970 const Error& error = Error::Handle(
1939 Parser::FormatError(Script::Handle(), -1, "Error", format, args)); 1971 Parser::FormatError(Script::Handle(), -1, "Error", format, args));
1940 va_end(args); 1972 va_end(args);
1941 ReportError(error); 1973 ReportError(error);
1942 } 1974 }
1943 1975
1944 } // namespace dart 1976 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/class_finalizer.h ('k') | runtime/vm/object.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698