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

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

Issue 10352012: Using SubtypeTestCache object instead of an array, that way we do not need to patch and can communi… (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 7 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/code_generator.h ('k') | runtime/vm/code_generator_ia32.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) 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/code_generator.h" 5 #include "vm/code_generator.h"
6 6
7 #include "vm/code_patcher.h" 7 #include "vm/code_patcher.h"
8 #include "vm/compiler.h" 8 #include "vm/compiler.h"
9 #include "vm/dart_api_impl.h" 9 #include "vm/dart_api_impl.h"
10 #include "vm/dart_entry.h" 10 #include "vm/dart_entry.h"
(...skipping 433 matching lines...) Expand 10 before | Expand all | Expand 10 after
444 // This updates the type test cache, an array containing 4-value elements 444 // This updates the type test cache, an array containing 4-value elements
445 // (instance class, instance type arguments, instantiator type arguments and 445 // (instance class, instance type arguments, instantiator type arguments and
446 // test_result). It can be applied to classes with type arguments in which 446 // test_result). It can be applied to classes with type arguments in which
447 // case it contains just the result of the class subtype test, not including 447 // case it contains just the result of the class subtype test, not including
448 // the evaluation of type arguments. 448 // the evaluation of type arguments.
449 // This operation is currently very slow (lookup of code is not efficient yet). 449 // This operation is currently very slow (lookup of code is not efficient yet).
450 static void UpdateTypeTestCache(intptr_t node_id, 450 static void UpdateTypeTestCache(intptr_t node_id,
451 const Instance& instance, 451 const Instance& instance,
452 const AbstractType& type, 452 const AbstractType& type,
453 const AbstractTypeArguments& type_instantiator, 453 const AbstractTypeArguments& type_instantiator,
454 const Bool& result) { 454 const Bool& result,
455 const SubtypeTestCache& new_cache) {
455 // Since the test is expensive, don't do it unless necessary. 456 // Since the test is expensive, don't do it unless necessary.
456 // The list of disallowed cases will decrease as they are implemented in 457 // The list of disallowed cases will decrease as they are implemented in
457 // inlined assembly. 458 // inlined assembly.
458 if (!type.IsInstantiated()) return; 459 if (new_cache.IsNull()) return;
459 if (Class::Handle(type.type_class()).HasTypeArguments()) {
460 const AbstractTypeArguments& type_arguments =
461 AbstractTypeArguments::Handle(type.arguments());
462 const bool is_raw_type = type_arguments.IsNull() ||
463 type_arguments.IsRaw(type_arguments.Length());
464 if (!is_raw_type) {
465 // We cannot inline tests for instances with more than one type argument
466 // or if its class has not been resolved (malformed type).
467 if (type_arguments.Length() != 1) {
468 // We can handle only one argument so far.
469 return;
470 }
471 const AbstractType& tp_argument =
472 AbstractType::ZoneHandle(type_arguments.TypeAt(0));
473 if (!tp_argument.IsType()) {
474 // E.g, it is TypeParameter.
475 return;
476 }
477 ASSERT(tp_argument.HasResolvedTypeClass());
478 }
479 }
480 AbstractTypeArguments& instance_type_arguments = 460 AbstractTypeArguments& instance_type_arguments =
481 AbstractTypeArguments::Handle(); 461 AbstractTypeArguments::Handle();
482 const Class& instance_class = Class::Handle(instance.clazz()); 462 const Class& instance_class = Class::Handle(instance.clazz());
483 AbstractTypeArguments& original_instance_type_arguments = 463 AbstractTypeArguments& original_instance_type_arguments =
484 AbstractTypeArguments::Handle(); 464 AbstractTypeArguments::Handle();
485 if (instance_class.HasTypeArguments()) { 465 if (instance_class.HasTypeArguments()) {
466 // Canonicalize type arguments.
486 original_instance_type_arguments = instance.GetTypeArguments(); 467 original_instance_type_arguments = instance.GetTypeArguments();
487 OptimizeTypeArguments(instance); 468 OptimizeTypeArguments(instance);
488 instance_type_arguments = instance.GetTypeArguments(); 469 instance_type_arguments = instance.GetTypeArguments();
489 } 470 }
490 471
491 DartFrameIterator iterator; 472 Class& last_instance_class = Class::Handle();
492 StackFrame* caller_frame = iterator.NextFrame(); 473 AbstractTypeArguments& last_instance_type_arguments =
493 ASSERT(caller_frame != NULL); 474 AbstractTypeArguments::Handle();
494 const Code& code = Code::Handle(caller_frame->LookupDartCode()); 475 AbstractTypeArguments& last_instantiator_type_arguments =
495 ASSERT(!code.IsNull()); 476 AbstractTypeArguments::Handle();
496 uword loc = code.GetTypeTestAtNodeId(node_id); 477 Bool& last_result = Bool::Handle();
497 if (loc != 0) { 478 intptr_t len = new_cache.NumberOfChecks();
498 // Found type test cache. 479 for (intptr_t i = 0; i < len; ++i) {
499 Array& cache = Array::Handle(CodePatcher::GetTypeTestArray(loc)); 480 new_cache.GetCheck(
500 // TODO(srdjan): Prevent type test cache from growing too much, it has been 481 i,
501 // observed to grow to 100 elements. 482 &last_instance_class,
502 // Don't enter duplicate entries. 483 &last_instance_type_arguments,
503 // TODO(srdjan): Check instantiator type arguments as well. 484 &last_instantiator_type_arguments,
504 Object& last_instance_class = Object::Handle(); 485 &last_result);
505 Object& last_instance_type_arguments = Object::Handle(); 486 if ((last_instance_class.raw() == instance_class.raw()) &&
506 // Check for duplicate entries (can happen if we optimized type arguments 487 (last_instance_type_arguments.raw() ==
507 // above). 488 instance_type_arguments.raw())) {
508 for (intptr_t i = 0; i < cache.Length(); 489 if (FLAG_trace_type_checks) {
509 i += SubTypeTestCache::kNumEntries) { 490 if (original_instance_type_arguments.raw() ==
510 last_instance_class = cache.At(i + SubTypeTestCache::kInstanceClass); 491 instance_type_arguments.raw()) {
511 last_instance_type_arguments =
512 cache.At(i + SubTypeTestCache::kInstanceTypeArguments);
513 if ((last_instance_class.raw() == instance_class.raw()) &&
514 (last_instance_type_arguments.raw() ==
515 instance_type_arguments.raw())) {
516 if (FLAG_trace_type_checks &&
517 (original_instance_type_arguments.raw() ==
518 instance_type_arguments.raw())) {
519 PrintTypeCheck("WARNING duplicate cache entry", instance, type, 492 PrintTypeCheck("WARNING duplicate cache entry", instance, type,
520 type_instantiator, result); 493 type_instantiator, result);
521 } 494 }
522 return;
523 } 495 }
496 // A duplicate entry found, likely because the instance type arguments
497 // were not cacnonicalized before.
498 return;
524 } 499 }
525 500 }
526 // Array must be null terminated. 501 new_cache.AddCheck(instance_class,
527 ASSERT(last_instance_class.IsNull()); 502 instance_type_arguments,
528 ASSERT(!cache.IsNull()); 503 AbstractTypeArguments::Handle(),
529 // Cache is null terminate, i.e., the last entry contains all null elements. 504 result);
530 intptr_t old_len = cache.Length(); 505 if (FLAG_trace_type_checks) {
531 cache = cache.Grow(cache, old_len + SubTypeTestCache::kNumEntries); 506 OS::Print(" Updated test cache 0x%x ix:%d:\n"
532 intptr_t last_start = old_len - SubTypeTestCache::kNumEntries; 507 " [0x%x %s, 0x%x %s]\n"
533 cache.SetAt(last_start + SubTypeTestCache::kInstanceClass, instance_class); 508 " [0x%x %s] %s\n",
534 cache.SetAt(last_start + SubTypeTestCache::kInstanceTypeArguments, 509 new_cache.raw(),
535 instance_type_arguments); 510 len,
536 // TODO(srdjan): Store instantiator arguments instead of null. 511 instance_class.raw(),
537 cache.SetAt(last_start + SubTypeTestCache::kInstantiatorTypeArguments, 512 instance_class.ToCString(),
538 AbstractTypeArguments::Handle()); 513 instance_type_arguments.raw(),
539 cache.SetAt(last_start + SubTypeTestCache::kTestResult , result); 514 instance_type_arguments.ToCString(),
540 if (FLAG_trace_type_checks) { 515 type.type_class(),
541 OS::Print(" Updated test cache: [0x%x %s, 0x%x %s]\n" 516 Class::Handle(type.type_class()).ToCString(),
542 " [0x%x %s] %s\n", 517 result.ToCString());
543 instance_class.raw(),
544 instance_class.ToCString(),
545 instance_type_arguments.raw(),
546 instance_type_arguments.ToCString(),
547 type.type_class(),
548 Class::Handle(type.type_class()).ToCString(),
549 result.ToCString());
550 }
551 CodePatcher::SetTypeTestArray(loc, cache);
552 } 518 }
553 } 519 }
554 520
555 521
556 // Check that the given instance is an instance of the given type. 522 // Check that the given instance is an instance of the given type.
557 // Tested instance may not be null, because the null test is inlined. 523 // Tested instance may not be null, because the null test is inlined.
558 // Arg0: index of the token of the instanceof test (source location). 524 // Arg0: index of the token of the instanceof test (source location).
559 // Arg1: node id of the instanceof node. 525 // Arg1: node id of the instanceof node.
560 // Arg2: instance being checked. 526 // Arg2: instance being checked.
561 // Arg3: type. 527 // Arg3: type.
562 // Arg4: type arguments of the instantiator of the type. 528 // Arg4: type arguments of the instantiator of the type.
529 // Arg5: SubtypeTestCache.
563 // Return value: true or false, or may throw a type error in checked mode. 530 // Return value: true or false, or may throw a type error in checked mode.
564 DEFINE_RUNTIME_ENTRY(Instanceof, 5) { 531 DEFINE_RUNTIME_ENTRY(Instanceof, 6) {
565 ASSERT(arguments.Count() == kInstanceofRuntimeEntry.argument_count()); 532 ASSERT(arguments.Count() == kInstanceofRuntimeEntry.argument_count());
566 // TODO(regis): Get the token index from the PcDesc (via DartFrame). 533 // TODO(regis): Get the token index from the PcDesc (via DartFrame).
567 intptr_t location = Smi::CheckedHandle(arguments.At(0)).Value(); 534 intptr_t location = Smi::CheckedHandle(arguments.At(0)).Value();
568 intptr_t node_id = Smi::CheckedHandle(arguments.At(1)).Value(); 535 intptr_t node_id = Smi::CheckedHandle(arguments.At(1)).Value();
569 const Instance& instance = Instance::CheckedHandle(arguments.At(2)); 536 const Instance& instance = Instance::CheckedHandle(arguments.At(2));
570 const AbstractType& type = AbstractType::CheckedHandle(arguments.At(3)); 537 const AbstractType& type = AbstractType::CheckedHandle(arguments.At(3));
571 const AbstractTypeArguments& type_instantiator = 538 const AbstractTypeArguments& type_instantiator =
572 AbstractTypeArguments::CheckedHandle(arguments.At(4)); 539 AbstractTypeArguments::CheckedHandle(arguments.At(4));
540 const SubtypeTestCache& cache =
541 SubtypeTestCache::CheckedHandle(arguments.At(5));
573 ASSERT(type.IsFinalized()); 542 ASSERT(type.IsFinalized());
574 Error& malformed_error = Error::Handle(); 543 Error& malformed_error = Error::Handle();
575 const Bool& result = Bool::Handle( 544 const Bool& result = Bool::Handle(
576 instance.IsInstanceOf(type, type_instantiator, &malformed_error) ? 545 instance.IsInstanceOf(type, type_instantiator, &malformed_error) ?
577 Bool::True() : Bool::False()); 546 Bool::True() : Bool::False());
578 if (FLAG_trace_type_checks) { 547 if (FLAG_trace_type_checks) {
579 PrintTypeCheck("InstanceOf", instance, type, type_instantiator, result); 548 PrintTypeCheck("InstanceOf", instance, type, type_instantiator, result);
580 } 549 }
581 if (!result.value() && !malformed_error.IsNull()) { 550 if (!result.value() && !malformed_error.IsNull()) {
582 // Throw a dynamic type error only if the instanceof test fails. 551 // Throw a dynamic type error only if the instanceof test fails.
583 String& malformed_error_message = String::Handle( 552 String& malformed_error_message = String::Handle(
584 String::New(malformed_error.ToErrorCString())); 553 String::New(malformed_error.ToErrorCString()));
585 const String& no_name = String::Handle(String::NewSymbol("")); 554 const String& no_name = String::Handle(String::NewSymbol(""));
586 Exceptions::CreateAndThrowTypeError( 555 Exceptions::CreateAndThrowTypeError(
587 location, no_name, no_name, no_name, malformed_error_message); 556 location, no_name, no_name, no_name, malformed_error_message);
588 UNREACHABLE(); 557 UNREACHABLE();
589 } 558 }
590 UpdateTypeTestCache(node_id, instance, type, type_instantiator, result); 559 UpdateTypeTestCache(
560 node_id, instance, type, type_instantiator, result, cache);
591 arguments.SetReturn(result); 561 arguments.SetReturn(result);
592 } 562 }
593 563
594 564
595 // For error reporting simplify type name, e.g, all integer types (Smi, Mint, 565 // For error reporting simplify type name, e.g, all integer types (Smi, Mint,
596 // Bigint) a re reported as 'int'. 566 // Bigint) a re reported as 'int'.
597 static RawString* GetSimpleTypeName(const Instance& value) { 567 static RawString* GetSimpleTypeName(const Instance& value) {
598 if (value.IsInteger()) { 568 if (value.IsInteger()) {
599 return String::NewSymbol("int"); 569 return String::NewSymbol("int");
600 } else { 570 } else {
601 return Type::Handle(value.GetType()).Name(); 571 return Type::Handle(value.GetType()).Name();
602 } 572 }
603 } 573 }
604 574
605 575
606 // Check that the type of the given instance is a subtype of the given type and 576 // Check that the type of the given instance is a subtype of the given type and
607 // can therefore be assigned. 577 // can therefore be assigned.
608 // Arg0: index of the token of the assignment (source location). 578 // Arg0: index of the token of the assignment (source location).
609 // Arg1: node-id of the assignemnt. 579 // Arg1: node-id of the assignemnt.
610 // Arg1: instance being assigned. 580 // Arg2: instance being assigned.
611 // Arg2: type being assigned to. 581 // Arg3: type being assigned to.
612 // Arg3: type arguments of the instantiator of the type being assigned to. 582 // Arg4: type arguments of the instantiator of the type being assigned to.
613 // Arg4: name of variable being assigned to. 583 // Arg5: name of variable being assigned to.
584 // Arg6: SubtypeTestCache.
614 // Return value: instance if a subtype, otherwise throw a TypeError. 585 // Return value: instance if a subtype, otherwise throw a TypeError.
615 DEFINE_RUNTIME_ENTRY(TypeCheck, 6) { 586 DEFINE_RUNTIME_ENTRY(TypeCheck, 7) {
616 ASSERT(arguments.Count() == kTypeCheckRuntimeEntry.argument_count()); 587 ASSERT(arguments.Count() == kTypeCheckRuntimeEntry.argument_count());
617 // TODO(regis): Get the token index from the PcDesc (via DartFrame). 588 // TODO(regis): Get the token index from the PcDesc (via DartFrame).
618 intptr_t location = Smi::CheckedHandle(arguments.At(0)).Value(); 589 intptr_t location = Smi::CheckedHandle(arguments.At(0)).Value();
619 intptr_t node_id = Smi::CheckedHandle(arguments.At(1)).Value(); 590 intptr_t node_id = Smi::CheckedHandle(arguments.At(1)).Value();
620 const Instance& src_instance = Instance::CheckedHandle(arguments.At(2)); 591 const Instance& src_instance = Instance::CheckedHandle(arguments.At(2));
621 const AbstractType& dst_type = AbstractType::CheckedHandle(arguments.At(3)); 592 const AbstractType& dst_type = AbstractType::CheckedHandle(arguments.At(3));
622 const AbstractTypeArguments& dst_type_instantiator = 593 const AbstractTypeArguments& dst_type_instantiator =
623 AbstractTypeArguments::CheckedHandle(arguments.At(4)); 594 AbstractTypeArguments::CheckedHandle(arguments.At(4));
624 const String& dst_name = String::CheckedHandle(arguments.At(5)); 595 const String& dst_name = String::CheckedHandle(arguments.At(5));
596 const SubtypeTestCache& cache =
597 SubtypeTestCache::CheckedHandle(arguments.At(6));
625 ASSERT(!dst_type.IsDynamicType()); // No need to check assignment. 598 ASSERT(!dst_type.IsDynamicType()); // No need to check assignment.
626 ASSERT(!dst_type.IsMalformed()); // Already checked in code generator. 599 ASSERT(!dst_type.IsMalformed()); // Already checked in code generator.
627 ASSERT(!src_instance.IsNull()); // Already checked in inlined code. 600 ASSERT(!src_instance.IsNull()); // Already checked in inlined code.
628 601
629 Error& malformed_error = Error::Handle(); 602 Error& malformed_error = Error::Handle();
630 const bool is_instance_of = src_instance.IsInstanceOf( 603 const bool is_instance_of = src_instance.IsInstanceOf(
631 dst_type, dst_type_instantiator, &malformed_error); 604 dst_type, dst_type_instantiator, &malformed_error);
632 605
633 if (FLAG_trace_type_checks) { 606 if (FLAG_trace_type_checks) {
634 PrintTypeCheck("TypeCheck", src_instance, dst_type, dst_type_instantiator, 607 PrintTypeCheck("TypeCheck", src_instance, dst_type, dst_type_instantiator,
(...skipping 13 matching lines...) Expand all
648 String& malformed_error_message = String::Handle(); 621 String& malformed_error_message = String::Handle();
649 if (!malformed_error.IsNull()) { 622 if (!malformed_error.IsNull()) {
650 ASSERT(FLAG_enable_type_checks); 623 ASSERT(FLAG_enable_type_checks);
651 malformed_error_message = String::New(malformed_error.ToErrorCString()); 624 malformed_error_message = String::New(malformed_error.ToErrorCString());
652 } 625 }
653 Exceptions::CreateAndThrowTypeError(location, src_type_name, dst_type_name, 626 Exceptions::CreateAndThrowTypeError(location, src_type_name, dst_type_name,
654 dst_name, malformed_error_message); 627 dst_name, malformed_error_message);
655 UNREACHABLE(); 628 UNREACHABLE();
656 } 629 }
657 UpdateTypeTestCache(node_id, src_instance, dst_type, dst_type_instantiator, 630 UpdateTypeTestCache(node_id, src_instance, dst_type, dst_type_instantiator,
658 Bool::ZoneHandle(Bool::True())); 631 Bool::ZoneHandle(Bool::True()), cache);
659 arguments.SetReturn(src_instance); 632 arguments.SetReturn(src_instance);
660 } 633 }
661 634
662 635
663 // Report that the type of the given object is not bool in conditional context. 636 // Report that the type of the given object is not bool in conditional context.
664 // Arg0: index of the token of the assignment (source location). 637 // Arg0: index of the token of the assignment (source location).
665 // Arg1: bad object. 638 // Arg1: bad object.
666 // Return value: none, throws a TypeError. 639 // Return value: none, throws a TypeError.
667 DEFINE_RUNTIME_ENTRY(ConditionTypeError, 2) { 640 DEFINE_RUNTIME_ENTRY(ConditionTypeError, 2) {
668 ASSERT(arguments.Count() == 641 ASSERT(arguments.Count() ==
(...skipping 902 matching lines...) Expand 10 before | Expand all | Expand 10 after
1571 } 1544 }
1572 } 1545 }
1573 } 1546 }
1574 // The cache is null terminated, therefore the loop above should never 1547 // The cache is null terminated, therefore the loop above should never
1575 // terminate by itself. 1548 // terminate by itself.
1576 UNREACHABLE(); 1549 UNREACHABLE();
1577 return Code::null(); 1550 return Code::null();
1578 } 1551 }
1579 1552
1580 } // namespace dart 1553 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/code_generator.h ('k') | runtime/vm/code_generator_ia32.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698