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
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(i, &last_instance_class,
500 // TODO(srdjan): Prevent type test cache from growing too much, it has been 481 &last_instance_type_arguments,
regis 2012/05/03 20:59:11 Interesting indentation
srdjan 2012/05/03 21:51:08 Made it conventional.
501 // observed to grow to 100 elements. 482 &last_instantiator_type_arguments,
502 // Don't enter duplicate entries. 483 &last_result);
503 // TODO(srdjan): Check instantiator type arguments as well. 484 if ((last_instance_class.raw() == instance_class.raw()) &&
504 Object& last_instance_class = Object::Handle(); 485 (last_instance_type_arguments.raw() ==
505 Object& last_instance_type_arguments = Object::Handle(); 486 instance_type_arguments.raw())) {
506 // Check for duplicate entries (can happen if we optimized type arguments 487 if (FLAG_trace_type_checks) {
507 // above). 488 if (original_instance_type_arguments.raw() ==
508 for (intptr_t i = 0; i < cache.Length(); 489 instance_type_arguments.raw()) {
509 i += SubTypeTestCache::kNumEntries) {
510 last_instance_class = cache.At(i + SubTypeTestCache::kInstanceClass);
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, 490 PrintTypeCheck("WARNING duplicate cache entry", instance, type,
520 type_instantiator, result); 491 type_instantiator, result);
521 } 492 }
522 return;
523 } 493 }
494 // A duplicate entry found, likely because the instance type arguments
495 // were not cacnonicalized before.
496 return;
524 } 497 }
525 498 }
526 // Array must be null terminated. 499 new_cache.AddCheck(instance_class,
527 ASSERT(last_instance_class.IsNull()); 500 instance_type_arguments,
528 ASSERT(!cache.IsNull()); 501 AbstractTypeArguments::Handle(),
529 // Cache is null terminate, i.e., the last entry contains all null elements. 502 result);
530 intptr_t old_len = cache.Length(); 503 if (FLAG_trace_type_checks) {
531 cache = cache.Grow(cache, old_len + SubTypeTestCache::kNumEntries); 504 OS::Print(" Updated test cache 0x%x ix:%d:\n"
532 intptr_t last_start = old_len - SubTypeTestCache::kNumEntries; 505 " [0x%x %s, 0x%x %s]\n"
533 cache.SetAt(last_start + SubTypeTestCache::kInstanceClass, instance_class); 506 " [0x%x %s] %s\n",
534 cache.SetAt(last_start + SubTypeTestCache::kInstanceTypeArguments, 507 new_cache.raw(),
regis 2012/05/03 20:59:11 indentation
regis 2012/05/03 20:59:11 indentation
srdjan 2012/05/03 21:51:08 Done.
srdjan 2012/05/03 21:51:08 Done.
535 instance_type_arguments); 508 len,
536 // TODO(srdjan): Store instantiator arguments instead of null. 509 instance_class.raw(),
537 cache.SetAt(last_start + SubTypeTestCache::kInstantiatorTypeArguments, 510 instance_class.ToCString(),
538 AbstractTypeArguments::Handle()); 511 instance_type_arguments.raw(),
539 cache.SetAt(last_start + SubTypeTestCache::kTestResult , result); 512 instance_type_arguments.ToCString(),
540 if (FLAG_trace_type_checks) { 513 type.type_class(),
541 OS::Print(" Updated test cache: [0x%x %s, 0x%x %s]\n" 514 Class::Handle(type.type_class()).ToCString(),
542 " [0x%x %s] %s\n", 515 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 } 516 }
553 } 517 }
554 518
555 519
556 // Check that the given instance is an instance of the given type. 520 // 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. 521 // Tested instance may not be null, because the null test is inlined.
558 // Arg0: index of the token of the instanceof test (source location). 522 // Arg0: index of the token of the instanceof test (source location).
559 // Arg1: node id of the instanceof node. 523 // Arg1: node id of the instanceof node.
560 // Arg2: instance being checked. 524 // Arg2: instance being checked.
561 // Arg3: type. 525 // Arg3: type.
562 // Arg4: type arguments of the instantiator of the type. 526 // Arg4: type arguments of the instantiator of the type.
527 // Arg5: SubtypeTestCache.
563 // Return value: true or false, or may throw a type error in checked mode. 528 // Return value: true or false, or may throw a type error in checked mode.
564 DEFINE_RUNTIME_ENTRY(Instanceof, 5) { 529 DEFINE_RUNTIME_ENTRY(Instanceof, 6) {
565 ASSERT(arguments.Count() == kInstanceofRuntimeEntry.argument_count()); 530 ASSERT(arguments.Count() == kInstanceofRuntimeEntry.argument_count());
566 // TODO(regis): Get the token index from the PcDesc (via DartFrame). 531 // TODO(regis): Get the token index from the PcDesc (via DartFrame).
567 intptr_t location = Smi::CheckedHandle(arguments.At(0)).Value(); 532 intptr_t location = Smi::CheckedHandle(arguments.At(0)).Value();
568 intptr_t node_id = Smi::CheckedHandle(arguments.At(1)).Value(); 533 intptr_t node_id = Smi::CheckedHandle(arguments.At(1)).Value();
569 const Instance& instance = Instance::CheckedHandle(arguments.At(2)); 534 const Instance& instance = Instance::CheckedHandle(arguments.At(2));
570 const AbstractType& type = AbstractType::CheckedHandle(arguments.At(3)); 535 const AbstractType& type = AbstractType::CheckedHandle(arguments.At(3));
571 const AbstractTypeArguments& type_instantiator = 536 const AbstractTypeArguments& type_instantiator =
572 AbstractTypeArguments::CheckedHandle(arguments.At(4)); 537 AbstractTypeArguments::CheckedHandle(arguments.At(4));
538 const SubtypeTestCache& cache =
539 SubtypeTestCache::CheckedHandle(arguments.At(5));
573 ASSERT(type.IsFinalized()); 540 ASSERT(type.IsFinalized());
574 Error& malformed_error = Error::Handle(); 541 Error& malformed_error = Error::Handle();
575 const Bool& result = Bool::Handle( 542 const Bool& result = Bool::Handle(
576 instance.IsInstanceOf(type, type_instantiator, &malformed_error) ? 543 instance.IsInstanceOf(type, type_instantiator, &malformed_error) ?
577 Bool::True() : Bool::False()); 544 Bool::True() : Bool::False());
578 if (FLAG_trace_type_checks) { 545 if (FLAG_trace_type_checks) {
579 PrintTypeCheck("InstanceOf", instance, type, type_instantiator, result); 546 PrintTypeCheck("InstanceOf", instance, type, type_instantiator, result);
580 } 547 }
581 if (!result.value() && !malformed_error.IsNull()) { 548 if (!result.value() && !malformed_error.IsNull()) {
582 // Throw a dynamic type error only if the instanceof test fails. 549 // Throw a dynamic type error only if the instanceof test fails.
583 String& malformed_error_message = String::Handle( 550 String& malformed_error_message = String::Handle(
584 String::New(malformed_error.ToErrorCString())); 551 String::New(malformed_error.ToErrorCString()));
585 const String& no_name = String::Handle(String::NewSymbol("")); 552 const String& no_name = String::Handle(String::NewSymbol(""));
586 Exceptions::CreateAndThrowTypeError( 553 Exceptions::CreateAndThrowTypeError(
587 location, no_name, no_name, no_name, malformed_error_message); 554 location, no_name, no_name, no_name, malformed_error_message);
588 UNREACHABLE(); 555 UNREACHABLE();
589 } 556 }
590 UpdateTypeTestCache(node_id, instance, type, type_instantiator, result); 557 UpdateTypeTestCache(
558 node_id, instance, type, type_instantiator, result, cache);
591 arguments.SetReturn(result); 559 arguments.SetReturn(result);
592 } 560 }
593 561
594 562
595 // For error reporting simplify type name, e.g, all integer types (Smi, Mint, 563 // For error reporting simplify type name, e.g, all integer types (Smi, Mint,
596 // Bigint) a re reported as 'int'. 564 // Bigint) a re reported as 'int'.
597 static RawString* GetSimpleTypeName(const Instance& value) { 565 static RawString* GetSimpleTypeName(const Instance& value) {
598 if (value.IsInteger()) { 566 if (value.IsInteger()) {
599 return String::NewSymbol("int"); 567 return String::NewSymbol("int");
600 } else { 568 } else {
601 return Type::Handle(value.GetType()).Name(); 569 return Type::Handle(value.GetType()).Name();
602 } 570 }
603 } 571 }
604 572
605 573
606 // Check that the type of the given instance is a subtype of the given type and 574 // Check that the type of the given instance is a subtype of the given type and
607 // can therefore be assigned. 575 // can therefore be assigned.
608 // Arg0: index of the token of the assignment (source location). 576 // Arg0: index of the token of the assignment (source location).
609 // Arg1: node-id of the assignemnt. 577 // Arg1: node-id of the assignemnt.
610 // Arg1: instance being assigned. 578 // Arg2: instance being assigned.
611 // Arg2: type being assigned to. 579 // Arg3: type being assigned to.
612 // Arg3: type arguments of the instantiator of the type being assigned to. 580 // Arg4: type arguments of the instantiator of the type being assigned to.
613 // Arg4: name of variable being assigned to. 581 // Arg5: name of variable being assigned to.
582 // Arg6: SubtypeTestCache.
614 // Return value: instance if a subtype, otherwise throw a TypeError. 583 // Return value: instance if a subtype, otherwise throw a TypeError.
615 DEFINE_RUNTIME_ENTRY(TypeCheck, 6) { 584 DEFINE_RUNTIME_ENTRY(TypeCheck, 7) {
616 ASSERT(arguments.Count() == kTypeCheckRuntimeEntry.argument_count()); 585 ASSERT(arguments.Count() == kTypeCheckRuntimeEntry.argument_count());
617 // TODO(regis): Get the token index from the PcDesc (via DartFrame). 586 // TODO(regis): Get the token index from the PcDesc (via DartFrame).
618 intptr_t location = Smi::CheckedHandle(arguments.At(0)).Value(); 587 intptr_t location = Smi::CheckedHandle(arguments.At(0)).Value();
619 intptr_t node_id = Smi::CheckedHandle(arguments.At(1)).Value(); 588 intptr_t node_id = Smi::CheckedHandle(arguments.At(1)).Value();
620 const Instance& src_instance = Instance::CheckedHandle(arguments.At(2)); 589 const Instance& src_instance = Instance::CheckedHandle(arguments.At(2));
621 const AbstractType& dst_type = AbstractType::CheckedHandle(arguments.At(3)); 590 const AbstractType& dst_type = AbstractType::CheckedHandle(arguments.At(3));
622 const AbstractTypeArguments& dst_type_instantiator = 591 const AbstractTypeArguments& dst_type_instantiator =
623 AbstractTypeArguments::CheckedHandle(arguments.At(4)); 592 AbstractTypeArguments::CheckedHandle(arguments.At(4));
624 const String& dst_name = String::CheckedHandle(arguments.At(5)); 593 const String& dst_name = String::CheckedHandle(arguments.At(5));
594 const SubtypeTestCache& cache =
595 SubtypeTestCache::CheckedHandle(arguments.At(6));
625 ASSERT(!dst_type.IsDynamicType()); // No need to check assignment. 596 ASSERT(!dst_type.IsDynamicType()); // No need to check assignment.
626 ASSERT(!dst_type.IsMalformed()); // Already checked in code generator. 597 ASSERT(!dst_type.IsMalformed()); // Already checked in code generator.
627 ASSERT(!src_instance.IsNull()); // Already checked in inlined code. 598 ASSERT(!src_instance.IsNull()); // Already checked in inlined code.
628 599
629 Error& malformed_error = Error::Handle(); 600 Error& malformed_error = Error::Handle();
630 const bool is_instance_of = src_instance.IsInstanceOf( 601 const bool is_instance_of = src_instance.IsInstanceOf(
631 dst_type, dst_type_instantiator, &malformed_error); 602 dst_type, dst_type_instantiator, &malformed_error);
632 603
633 if (FLAG_trace_type_checks) { 604 if (FLAG_trace_type_checks) {
634 PrintTypeCheck("TypeCheck", src_instance, dst_type, dst_type_instantiator, 605 PrintTypeCheck("TypeCheck", src_instance, dst_type, dst_type_instantiator,
(...skipping 13 matching lines...) Expand all
648 String& malformed_error_message = String::Handle(); 619 String& malformed_error_message = String::Handle();
649 if (!malformed_error.IsNull()) { 620 if (!malformed_error.IsNull()) {
650 ASSERT(FLAG_enable_type_checks); 621 ASSERT(FLAG_enable_type_checks);
651 malformed_error_message = String::New(malformed_error.ToErrorCString()); 622 malformed_error_message = String::New(malformed_error.ToErrorCString());
652 } 623 }
653 Exceptions::CreateAndThrowTypeError(location, src_type_name, dst_type_name, 624 Exceptions::CreateAndThrowTypeError(location, src_type_name, dst_type_name,
654 dst_name, malformed_error_message); 625 dst_name, malformed_error_message);
655 UNREACHABLE(); 626 UNREACHABLE();
656 } 627 }
657 UpdateTypeTestCache(node_id, src_instance, dst_type, dst_type_instantiator, 628 UpdateTypeTestCache(node_id, src_instance, dst_type, dst_type_instantiator,
658 Bool::ZoneHandle(Bool::True())); 629 Bool::ZoneHandle(Bool::True()), cache);
659 arguments.SetReturn(src_instance); 630 arguments.SetReturn(src_instance);
660 } 631 }
661 632
662 633
663 // Report that the type of the given object is not bool in conditional context. 634 // 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). 635 // Arg0: index of the token of the assignment (source location).
665 // Arg1: bad object. 636 // Arg1: bad object.
666 // Return value: none, throws a TypeError. 637 // Return value: none, throws a TypeError.
667 DEFINE_RUNTIME_ENTRY(ConditionTypeError, 2) { 638 DEFINE_RUNTIME_ENTRY(ConditionTypeError, 2) {
668 ASSERT(arguments.Count() == 639 ASSERT(arguments.Count() ==
(...skipping 902 matching lines...) Expand 10 before | Expand all | Expand 10 after
1571 } 1542 }
1572 } 1543 }
1573 } 1544 }
1574 // The cache is null terminated, therefore the loop above should never 1545 // The cache is null terminated, therefore the loop above should never
1575 // terminate by itself. 1546 // terminate by itself.
1576 UNREACHABLE(); 1547 UNREACHABLE();
1577 return Code::null(); 1548 return Code::null();
1578 } 1549 }
1579 1550
1580 } // namespace dart 1551 } // namespace dart
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698