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

Unified Diff: runtime/vm/code_generator.cc

Issue 10227006: (Redoing the change 6946) Progress toward inlined type checks for classes with type arguments: fact… (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | runtime/vm/code_generator_ia32.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/code_generator.cc
===================================================================
--- runtime/vm/code_generator.cc (revision 6973)
+++ runtime/vm/code_generator.cc (working copy)
@@ -320,6 +320,151 @@
}
+// Helper routine for tracing a type check.
+static void PrintTypeCheck(const char* message,
+ const Instance& instance,
+ const AbstractType&type,
+ const AbstractTypeArguments& type_instantiator,
+ const Bool& result) {
+ const Type& instance_type = Type::Handle(instance.GetType());
+ ASSERT(instance_type.IsInstantiated());
+ if (type.IsInstantiated()) {
+ OS::Print("%s: '%s' %s '%s'.\n",
+ message,
+ String::Handle(instance_type.Name()).ToCString(),
+ (result.raw() == Bool::True()) ? "is" : "is !",
+ String::Handle(type.Name()).ToCString());
+ } else {
+ // Instantiate type before printing.
+ const AbstractType& instantiated_type =
+ AbstractType::Handle(type.InstantiateFrom(type_instantiator));
+ OS::Print("%s: '%s' %s '%s' instantiated from '%s'.\n",
+ message,
+ String::Handle(instance_type.Name()).ToCString(),
+ (result.raw() == Bool::True()) ? "is" : "is !",
+ String::Handle(instantiated_type.Name()).ToCString(),
+ String::Handle(type.Name()).ToCString());
+ }
+ StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames);
+ StackFrame* caller_frame = GetTopDartFrame(&iterator, false);
+ ASSERT(caller_frame != NULL);
+ const Function& function = Function::Handle(
+ caller_frame->LookupDartFunction());
+ OS::Print(" -> Function %s\n", function.ToFullyQualifiedCString());
+}
+
+
+// Converts InstantiatedTypeArguments to TypeArguments and stores it
+// into the instance. The assembly code can handle only type arguments of
+// class TypeArguments. Because of the overhead, do it only when needed.
+static void OptimizeTypeArguments(const Instance& instance) {
+ const Class& type_class = Class::ZoneHandle(instance.clazz());
+ if (type_class.HasTypeArguments()) {
+ const AbstractTypeArguments& type_arguments =
+ AbstractTypeArguments::Handle(instance.GetTypeArguments());
+ if (!type_arguments.IsNull() &&
+ type_arguments.IsInstantiatedTypeArguments()) {
+ TypeArguments& new_type_arguments =
+ TypeArguments::Handle(TypeArguments::New(type_arguments.Length()));
+ for (int i = 0; i < type_arguments.Length(); i++) {
+ const AbstractType& type_at =
+ AbstractType::Handle(type_arguments.TypeAt(i));
+ if (type_at.IsInstantiatedType()) {
+ // TODO(srdjan): cannot canonicalize TypeArguments that contain
+ // InstantiatedType.
+ return;
+ } else if (!type_at.IsType()) {
+ // type_at cannot be TypeParameter at runtime.
+ UNREACHABLE();
+ }
+ new_type_arguments.SetTypeAt(i, type_at);
+ }
+ new_type_arguments ^= new_type_arguments.Canonicalize();
+ instance.SetTypeArguments(new_type_arguments);
+ }
+ }
+}
+
+
+// This updates the type test cache, an array containing tuples (instance class,
+// test result_. It can be applied to classes with type arguments in which
+// case it contains just the result of the class subtype test, not including
+// the evaluation of type arguments.
+// Note that the 'result' contains the whole type test (including type
+// arguments), but the type test cache contains only the result of the
+// class test. Therefore we may need to recompute the 'result'.
+// This operation is currently very slow (lookup of code is not efficient yet).
+static void UpdateTypeTestCache(intptr_t node_id,
+ const Instance& instance,
+ const AbstractType& type,
+ const AbstractTypeArguments& type_instantiator,
+ const Bool& result) {
+ // 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;
+ // TODO(srdjan): Implement assembly code for checking type arguments then
+ // remove this check.
+ 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) {
+ return;
+ }
+ }
+ StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames);
+ StackFrame* caller_frame = GetTopDartFrame(&iterator, false);
+ 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& value = Array::Handle(CodePatcher::GetTypeTestArray(loc));
+ // TODO(srdjan): Prevent type test cache from growing too much, it has been
+ // observed to grow to 100 elements.
+ const Class& instance_class = Class::Handle(instance.clazz());
+ // Don't enter duplicate entries.
+ Class& last_checked = Class::Handle();
+ for (intptr_t i = 0; i < value.Length(); i += 2) {
+ last_checked ^= value.At(i);
+ if (last_checked.raw() == instance_class.raw()) {
+ if (FLAG_trace_type_checks) {
+ PrintTypeCheck("WARING duplicate cache entry", instance, type,
+ type_instantiator, result);
+ }
+ return;
+ }
+ }
+
+ // Array must be null terminated.
+ ASSERT(last_checked.IsNull());
+
+ // Check if the result for cache needs to be recomputed.
+ const Class& cls = Class::Handle(type.type_class());
+ Bool& class_test_result = Bool::Handle(result.raw());
+ if (!result.value() && cls.HasTypeArguments()) {
+ Error& malformed_error = Error::Handle();
+ if (instance_class.IsSubtypeOf(TypeArguments::Handle(),
+ cls,
+ TypeArguments::Handle(),
+ &malformed_error)) {
+ class_test_result = Bool::True();
+ }
+ }
+ ASSERT(!value.IsNull());
+ intptr_t old_len = value.Length();
+ value = value.Grow(value, old_len + 2);
+ value.SetAt(old_len - 2, instance_class);
+ value.SetAt(old_len - 1, class_test_result);
+ CodePatcher::SetTypeTestArray(loc, value);
+ OptimizeTypeArguments(instance);
+ }
+}
+
+
// Check that the given instance is an instance of the given type.
// Tested instance may not be null, because the null test is inlined.
// Arg0: index of the token of the instanceof test (source location).
@@ -343,28 +488,7 @@
instance.IsInstanceOf(type, type_instantiator, &malformed_error) ?
Bool::True() : Bool::False());
if (FLAG_trace_type_checks) {
- const Type& instance_type = Type::Handle(instance.GetType());
- ASSERT(instance_type.IsInstantiated());
- if (type.IsInstantiated()) {
- OS::Print("InstanceOf: '%s' %s '%s'.\n",
- String::Handle(instance_type.Name()).ToCString(),
- (result.raw() == Bool::True()) ? "is" : "is !",
- String::Handle(type.Name()).ToCString());
- } else {
- // Instantiate type before printing.
- const AbstractType& instantiated_type =
- AbstractType::Handle(type.InstantiateFrom(type_instantiator));
- OS::Print("InstanceOf: '%s' %s '%s' instantiated from '%s'.\n",
- String::Handle(instance_type.Name()).ToCString(),
- (result.raw() == Bool::True()) ? "is" : "is !",
- String::Handle(instantiated_type.Name()).ToCString(),
- String::Handle(type.Name()).ToCString());
- }
- StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames);
- StackFrame* caller_frame = GetTopDartFrame(&iterator, false);
- const Function& function = Function::Handle(
- caller_frame->LookupDartFunction());
- OS::Print(" -> Function %s\n", function.ToFullyQualifiedCString());
+ PrintTypeCheck("InstanceOf", instance, type, type_instantiator, result);
}
if (!result.value() && !malformed_error.IsNull()) {
// Throw a dynamic type error only if the instanceof test fails.
@@ -375,39 +499,7 @@
location, no_name, no_name, no_name, malformed_error_message);
UNREACHABLE();
}
- // Update cache: add class of instance and result.
- if (type.IsInstantiated() &&
- !Class::Handle(type.type_class()).HasTypeArguments()) {
- StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames);
- StackFrame* caller_frame = GetTopDartFrame(&iterator, false);
- const Code& code = Code::Handle(caller_frame->LookupDartCode());
- ASSERT(!code.IsNull());
- uword loc = code.GetTypeTestAtNodeId(node_id);
- // TODO(srdjan): Check when 'loc' can be 0, once implemented everywhere.
- if (loc != 0) {
- // Found type test cache.
- Array& value = Array::Handle(CodePatcher::GetTypeTestArray(loc));
- const Class& instance_class = Class::Handle(instance.clazz());
-
-#if defined(DEBUG)
- // Check for duplicate entries.
- Class& last_checked = Class::Handle();
- for (intptr_t i = 0; i < value.Length(); i += 2) {
- last_checked ^= value.At(i);
- ASSERT(last_checked.raw() != instance_class.raw());
- }
- // Array must be null terminated.
- ASSERT(last_checked.IsNull());
-#endif
-
- ASSERT(!value.IsNull());
- intptr_t old_len = value.Length();
- value = value.Grow(value, old_len + 2);
- value.SetAt(old_len - 2, instance_class);
- value.SetAt(old_len - 1, result);
- CodePatcher::SetTypeTestArray(loc, value);
- }
- }
+ UpdateTypeTestCache(node_id, instance, type, type_instantiator, result);
arguments.SetReturn(result);
}
@@ -451,31 +543,8 @@
dst_type, dst_type_instantiator, &malformed_error);
if (FLAG_trace_type_checks) {
- const Type& src_type = Type::Handle(src_instance.GetType());
- ASSERT(src_type.IsInstantiated());
- if (dst_type.IsInstantiated()) {
- OS::Print("TypeCheck: type '%s' %s a subtype of type '%s' of '%s'.\n",
- String::Handle(src_type.Name()).ToCString(),
- is_instance_of ? "is" : "is not",
- String::Handle(dst_type.Name()).ToCString(),
- dst_name.ToCString());
- } else {
- // Instantiate dst_type before printing.
- const AbstractType& instantiated_dst_type = AbstractType::Handle(
- dst_type.InstantiateFrom(dst_type_instantiator));
- OS::Print("TypeCheck: type '%s' %s a subtype of type '%s' of '%s' "
- "instantiated from '%s'.\n",
- String::Handle(src_type.Name()).ToCString(),
- is_instance_of ? "is" : "is not",
- String::Handle(instantiated_dst_type.Name()).ToCString(),
- dst_name.ToCString(),
- String::Handle(dst_type.Name()).ToCString());
- }
- StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames);
- StackFrame* caller_frame = GetTopDartFrame(&iterator, false);
- const Function& function = Function::Handle(
- caller_frame->LookupDartFunction());
- OS::Print(" -> Function %s\n", function.ToFullyQualifiedCString());
+ PrintTypeCheck("TypeCheck", src_instance, dst_type, dst_type_instantiator,
+ Bool::Handle(is_instance_of ? Bool::True() : Bool::False()));
}
if (!is_instance_of) {
String& src_type_name = String::Handle(GetSimpleTypeName(src_instance));
@@ -497,38 +566,8 @@
dst_name, malformed_error_message);
UNREACHABLE();
}
- // Update cache: add class of instance and result.
- if (dst_type.IsInstantiated() &&
- !Class::Handle(dst_type.type_class()).HasTypeArguments()) {
- StackFrameIterator iterator(StackFrameIterator::kDontValidateFrames);
- StackFrame* caller_frame = GetTopDartFrame(&iterator, false);
- 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& value = Array::Handle(CodePatcher::GetTypeTestArray(loc));
- const Class& src_instance_class = Class::Handle(src_instance.clazz());
-
-#if defined(DEBUG)
- // Check for duplicate entries.
- Class& last_checked = Class::Handle();
- for (intptr_t i = 0; i < value.Length(); i += 2) {
- last_checked ^= value.At(i);
- ASSERT(last_checked.raw() != src_instance_class.raw());
- }
- // Array must be null terminated.
- ASSERT(last_checked.IsNull());
-#endif
-
- ASSERT(!value.IsNull());
- intptr_t old_len = value.Length();
- value = value.Grow(value, old_len + 2);
- value.SetAt(old_len - 2, src_instance_class);
- value.SetAt(old_len - 1, Bool::ZoneHandle(Bool::True()));
- CodePatcher::SetTypeTestArray(loc, value);
- }
- }
+ UpdateTypeTestCache(node_id, src_instance, dst_type, dst_type_instantiator,
+ Bool::ZoneHandle(Bool::True()));
arguments.SetReturn(src_instance);
}
« no previous file with comments | « no previous file | runtime/vm/code_generator_ia32.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698