Chromium Code Reviews| Index: runtime/vm/code_generator.cc |
| =================================================================== |
| --- runtime/vm/code_generator.cc (revision 7292) |
| +++ runtime/vm/code_generator.cc (working copy) |
| @@ -451,105 +451,69 @@ |
| const Instance& instance, |
| const AbstractType& type, |
| const AbstractTypeArguments& type_instantiator, |
| - const Bool& result) { |
| + const Bool& result, |
| + const SubtypeTestCache& new_cache) { |
| // Since the test is expensive, don't do it unless necessary. |
| // The list of disallowed cases will decrease as they are implemented in |
| // inlined assembly. |
| - if (!type.IsInstantiated()) return; |
| - if (Class::Handle(type.type_class()).HasTypeArguments()) { |
| - const AbstractTypeArguments& type_arguments = |
| - AbstractTypeArguments::Handle(type.arguments()); |
| - const bool is_raw_type = type_arguments.IsNull() || |
| - type_arguments.IsRaw(type_arguments.Length()); |
| - if (!is_raw_type) { |
| - // We cannot inline tests for instances with more than one type argument |
| - // or if its class has not been resolved (malformed type). |
| - if (type_arguments.Length() != 1) { |
| - // We can handle only one argument so far. |
| - return; |
| - } |
| - const AbstractType& tp_argument = |
| - AbstractType::ZoneHandle(type_arguments.TypeAt(0)); |
| - if (!tp_argument.IsType()) { |
| - // E.g, it is TypeParameter. |
| - return; |
| - } |
| - ASSERT(tp_argument.HasResolvedTypeClass()); |
| - } |
| - } |
| + if (new_cache.IsNull()) return; |
| AbstractTypeArguments& instance_type_arguments = |
| AbstractTypeArguments::Handle(); |
| const Class& instance_class = Class::Handle(instance.clazz()); |
| AbstractTypeArguments& original_instance_type_arguments = |
| AbstractTypeArguments::Handle(); |
| if (instance_class.HasTypeArguments()) { |
| + // Canonicalize type arguments. |
| original_instance_type_arguments = instance.GetTypeArguments(); |
| OptimizeTypeArguments(instance); |
| instance_type_arguments = instance.GetTypeArguments(); |
| } |
| - DartFrameIterator iterator; |
| - StackFrame* caller_frame = iterator.NextFrame(); |
| - ASSERT(caller_frame != NULL); |
| - const Code& code = Code::Handle(caller_frame->LookupDartCode()); |
| - ASSERT(!code.IsNull()); |
| - uword loc = code.GetTypeTestAtNodeId(node_id); |
| - if (loc != 0) { |
| - // Found type test cache. |
| - Array& cache = Array::Handle(CodePatcher::GetTypeTestArray(loc)); |
| - // TODO(srdjan): Prevent type test cache from growing too much, it has been |
| - // observed to grow to 100 elements. |
| - // Don't enter duplicate entries. |
| - // TODO(srdjan): Check instantiator type arguments as well. |
| - Object& last_instance_class = Object::Handle(); |
| - Object& last_instance_type_arguments = Object::Handle(); |
| - // Check for duplicate entries (can happen if we optimized type arguments |
| - // above). |
| - for (intptr_t i = 0; i < cache.Length(); |
| - i += SubTypeTestCache::kNumEntries) { |
| - last_instance_class = cache.At(i + SubTypeTestCache::kInstanceClass); |
| - last_instance_type_arguments = |
| - cache.At(i + SubTypeTestCache::kInstanceTypeArguments); |
| - if ((last_instance_class.raw() == instance_class.raw()) && |
| - (last_instance_type_arguments.raw() == |
| - instance_type_arguments.raw())) { |
| - if (FLAG_trace_type_checks && |
| - (original_instance_type_arguments.raw() == |
| - instance_type_arguments.raw())) { |
| + Class& last_instance_class = Class::Handle(); |
| + AbstractTypeArguments& last_instance_type_arguments = |
| + AbstractTypeArguments::Handle(); |
| + AbstractTypeArguments& last_instantiator_type_arguments = |
| + AbstractTypeArguments::Handle(); |
| + Bool& last_result = Bool::Handle(); |
| + intptr_t len = new_cache.NumberOfChecks(); |
| + for (intptr_t i = 0; i < len; ++i) { |
| + new_cache.GetCheck(i, &last_instance_class, |
| + &last_instance_type_arguments, |
|
regis
2012/05/03 20:59:11
Interesting indentation
srdjan
2012/05/03 21:51:08
Made it conventional.
|
| + &last_instantiator_type_arguments, |
| + &last_result); |
| + if ((last_instance_class.raw() == instance_class.raw()) && |
| + (last_instance_type_arguments.raw() == |
| + instance_type_arguments.raw())) { |
| + if (FLAG_trace_type_checks) { |
| + if (original_instance_type_arguments.raw() == |
| + instance_type_arguments.raw()) { |
| PrintTypeCheck("WARNING duplicate cache entry", instance, type, |
| type_instantiator, result); |
| } |
| - return; |
| } |
| + // A duplicate entry found, likely because the instance type arguments |
| + // were not cacnonicalized before. |
| + return; |
| } |
| - |
| - // Array must be null terminated. |
| - ASSERT(last_instance_class.IsNull()); |
| - ASSERT(!cache.IsNull()); |
| - // Cache is null terminate, i.e., the last entry contains all null elements. |
| - intptr_t old_len = cache.Length(); |
| - cache = cache.Grow(cache, old_len + SubTypeTestCache::kNumEntries); |
| - intptr_t last_start = old_len - SubTypeTestCache::kNumEntries; |
| - cache.SetAt(last_start + SubTypeTestCache::kInstanceClass, instance_class); |
| - cache.SetAt(last_start + SubTypeTestCache::kInstanceTypeArguments, |
| - instance_type_arguments); |
| - // TODO(srdjan): Store instantiator arguments instead of null. |
| - cache.SetAt(last_start + SubTypeTestCache::kInstantiatorTypeArguments, |
| - AbstractTypeArguments::Handle()); |
| - cache.SetAt(last_start + SubTypeTestCache::kTestResult , result); |
| - if (FLAG_trace_type_checks) { |
| - OS::Print(" Updated test cache: [0x%x %s, 0x%x %s]\n" |
| - " [0x%x %s] %s\n", |
| - instance_class.raw(), |
| - instance_class.ToCString(), |
| - instance_type_arguments.raw(), |
| - instance_type_arguments.ToCString(), |
| - type.type_class(), |
| - Class::Handle(type.type_class()).ToCString(), |
| - result.ToCString()); |
| - } |
| - CodePatcher::SetTypeTestArray(loc, cache); |
| } |
| + new_cache.AddCheck(instance_class, |
| + instance_type_arguments, |
| + AbstractTypeArguments::Handle(), |
| + result); |
| + if (FLAG_trace_type_checks) { |
| + OS::Print(" Updated test cache 0x%x ix:%d:\n" |
| + " [0x%x %s, 0x%x %s]\n" |
| + " [0x%x %s] %s\n", |
| + 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.
|
| + len, |
| + instance_class.raw(), |
| + instance_class.ToCString(), |
| + instance_type_arguments.raw(), |
| + instance_type_arguments.ToCString(), |
| + type.type_class(), |
| + Class::Handle(type.type_class()).ToCString(), |
| + result.ToCString()); |
| + } |
| } |
| @@ -560,8 +524,9 @@ |
| // Arg2: instance being checked. |
| // Arg3: type. |
| // Arg4: type arguments of the instantiator of the type. |
| +// Arg5: SubtypeTestCache. |
| // Return value: true or false, or may throw a type error in checked mode. |
| -DEFINE_RUNTIME_ENTRY(Instanceof, 5) { |
| +DEFINE_RUNTIME_ENTRY(Instanceof, 6) { |
| ASSERT(arguments.Count() == kInstanceofRuntimeEntry.argument_count()); |
| // TODO(regis): Get the token index from the PcDesc (via DartFrame). |
| intptr_t location = Smi::CheckedHandle(arguments.At(0)).Value(); |
| @@ -570,6 +535,8 @@ |
| const AbstractType& type = AbstractType::CheckedHandle(arguments.At(3)); |
| const AbstractTypeArguments& type_instantiator = |
| AbstractTypeArguments::CheckedHandle(arguments.At(4)); |
| + const SubtypeTestCache& cache = |
| + SubtypeTestCache::CheckedHandle(arguments.At(5)); |
| ASSERT(type.IsFinalized()); |
| Error& malformed_error = Error::Handle(); |
| const Bool& result = Bool::Handle( |
| @@ -587,7 +554,8 @@ |
| location, no_name, no_name, no_name, malformed_error_message); |
| UNREACHABLE(); |
| } |
| - UpdateTypeTestCache(node_id, instance, type, type_instantiator, result); |
| + UpdateTypeTestCache( |
| + node_id, instance, type, type_instantiator, result, cache); |
| arguments.SetReturn(result); |
| } |
| @@ -607,12 +575,13 @@ |
| // can therefore be assigned. |
| // Arg0: index of the token of the assignment (source location). |
| // Arg1: node-id of the assignemnt. |
| -// Arg1: instance being assigned. |
| -// Arg2: type being assigned to. |
| -// Arg3: type arguments of the instantiator of the type being assigned to. |
| -// Arg4: name of variable being assigned to. |
| +// Arg2: instance being assigned. |
| +// Arg3: type being assigned to. |
| +// Arg4: type arguments of the instantiator of the type being assigned to. |
| +// Arg5: name of variable being assigned to. |
| +// Arg6: SubtypeTestCache. |
| // Return value: instance if a subtype, otherwise throw a TypeError. |
| -DEFINE_RUNTIME_ENTRY(TypeCheck, 6) { |
| +DEFINE_RUNTIME_ENTRY(TypeCheck, 7) { |
| ASSERT(arguments.Count() == kTypeCheckRuntimeEntry.argument_count()); |
| // TODO(regis): Get the token index from the PcDesc (via DartFrame). |
| intptr_t location = Smi::CheckedHandle(arguments.At(0)).Value(); |
| @@ -622,6 +591,8 @@ |
| const AbstractTypeArguments& dst_type_instantiator = |
| AbstractTypeArguments::CheckedHandle(arguments.At(4)); |
| const String& dst_name = String::CheckedHandle(arguments.At(5)); |
| + const SubtypeTestCache& cache = |
| + SubtypeTestCache::CheckedHandle(arguments.At(6)); |
| ASSERT(!dst_type.IsDynamicType()); // No need to check assignment. |
| ASSERT(!dst_type.IsMalformed()); // Already checked in code generator. |
| ASSERT(!src_instance.IsNull()); // Already checked in inlined code. |
| @@ -655,7 +626,7 @@ |
| UNREACHABLE(); |
| } |
| UpdateTypeTestCache(node_id, src_instance, dst_type, dst_type_instantiator, |
| - Bool::ZoneHandle(Bool::True())); |
| + Bool::ZoneHandle(Bool::True()), cache); |
| arguments.SetReturn(src_instance); |
| } |