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

Unified Diff: runtime/vm/code_generator_ia32.cc

Issue 10317026: Inline type checks for complex uninstantiated types, e.g., List<T>. (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 | « runtime/vm/code_generator_ia32.h ('k') | runtime/vm/flow_graph_compiler_x64.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/code_generator_ia32.cc
===================================================================
--- runtime/vm/code_generator_ia32.cc (revision 7351)
+++ runtime/vm/code_generator_ia32.cc (working copy)
@@ -794,7 +794,8 @@
const bool requires_type_arguments = cls.HasTypeArguments();
if (requires_type_arguments) {
ASSERT(!function.IsImplicitStaticClosureFunction());
- GenerateInstantiatorTypeArguments(node->token_index());
+ const bool kPushInstantiator = false;
+ GenerateInstantiatorTypeArguments(node->token_index(), kPushInstantiator);
}
const Code& stub = Code::Handle(
StubCode::GetAllocationStubForClosure(function));
@@ -1278,9 +1279,11 @@
is_instance_lbl, is_not_instance_lbl);
}
} else {
- GenerateUninstantiatedTypeTest(type,
- token_index,
- is_instance_lbl);
+ return GenerateUninstantiatedTypeTest(type,
+ node_id,
+ token_index,
+ is_instance_lbl,
+ is_not_instance_lbl);
}
return SubtypeTestCache::null();
}
@@ -1374,17 +1377,19 @@
__ pushl(node_id_as_smi); // node-id.
__ pushl(EAX); // Push the instance.
__ PushObject(type); // Push the type.
- if (!type.IsInstantiated()) {
- GenerateInstantiatorTypeArguments(token_index);
+ if (type.IsInstantiated()) {
+ __ pushl(raw_null); // Null instantiator.
+ __ pushl(raw_null); // Null instantiator.
} else {
- __ pushl(raw_null); // Null instantiator.
+ const bool kPushInstantiator = true;
+ GenerateInstantiatorTypeArguments(token_index, kPushInstantiator);
}
__ LoadObject(EAX, test_cache);
__ pushl(EAX);
GenerateCallRuntime(node_id, token_index, kInstanceofRuntimeEntry);
// Pop the two parameters supplied to the runtime entry. The result of the
// instanceof runtime call will be left as the result of the operation.
- __ addl(ESP, Immediate(6 * kWordSize));
+ __ addl(ESP, Immediate(7 * kWordSize));
if (negate_result) {
__ popl(EDX);
__ CompareObject(EDX, bool_false);
@@ -1469,7 +1474,7 @@
const Immediate raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ LoadObject(EDX, type_test_cache);
- __ pushl(EDX); // Cache array.
+ __ pushl(EDX); // Subtype test cache.
__ pushl(EAX); // Instance.
__ pushl(raw_null); // Unused.
__ call(&StubCode::Subtype2TestCacheLabel());
@@ -1587,18 +1592,21 @@
// EAX: instance to test.
// Clobbers: EBX, EDX, ECX.
-void CodeGenerator::GenerateUninstantiatedTypeTest(
+RawSubtypeTestCache* CodeGenerator::GenerateUninstantiatedTypeTest(
const AbstractType& type,
+ intptr_t node_id,
intptr_t token_index,
- Label* is_instance_lbl) {
+ Label* is_instance_lbl,
+ Label* is_not_instance_lbl) {
ASSERT(!type.IsInstantiated());
// Skip check if destination is a dynamic type.
+ const Immediate raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
if (type.IsTypeParameter()) {
- const Immediate raw_null =
- Immediate(reinterpret_cast<intptr_t>(Object::null()));
// EAX must be preserved!
Label fall_through;
- GenerateInstantiatorTypeArguments(token_index);
+ const bool kPushInstantiator = false;
+ GenerateInstantiatorTypeArguments(token_index, kPushInstantiator);
// Type arguments are on stack.
__ popl(EBX);
// Check if type argument is dynamic.
@@ -1658,7 +1666,36 @@
// Test not conclusive.
__ Bind(&fall_through);
+ return SubtypeTestCache::null();
}
+ if (type.IsType()) {
+ Label fall_through;
+ __ testl(EAX, Immediate(kSmiTagMask)); // Is instance Smi?
+ __ j(ZERO, is_not_instance_lbl, Assembler::kNearJump);
+ // Uninstantiated type class is known at compile time, but the type
+ // arguments are determined at runtime by the instantiator.
+ const SubtypeTestCache& type_test_cache =
+ SubtypeTestCache::ZoneHandle(SubtypeTestCache::New());
+ __ LoadObject(EDX, type_test_cache);
+ __ pushl(EDX); // Subtype test cache.
+ __ pushl(EAX); // Instance.
+ const bool kPushInstantiator = false;
+ GenerateInstantiatorTypeArguments(token_index, kPushInstantiator);
+ __ call(&StubCode::Subtype3TestCacheLabel());
+ __ popl(EDX); // Discard type arguments.
+ __ popl(EAX); // Restore receiver.
+ __ popl(EDX); // Discard subtype test cache.
+ // Result is in ECX: null -> not found, otherwise Bool::True or Bool::False.
+ __ cmpl(ECX, raw_null);
+ __ j(EQUAL, &fall_through, Assembler::kNearJump);
+ const Bool& bool_true = Bool::ZoneHandle(Bool::True());
+ __ CompareObject(ECX, bool_true);
+ __ j(EQUAL, is_instance_lbl);
+ __ jmp(is_not_instance_lbl);
+ __ Bind(&fall_through);
+ return type_test_cache.raw();
+ }
+ return SubtypeTestCache::null();
}
@@ -1757,8 +1794,10 @@
__ PushObject(dst_type); // Push the type of the destination.
if (dst_type.IsInstantiated()) {
__ pushl(raw_null); // Null instantiator.
+ __ pushl(raw_null); // Null instantiator type argument.
} else {
- GenerateInstantiatorTypeArguments(token_index);
+ const bool kPushInstantiator = true;
+ GenerateInstantiatorTypeArguments(token_index, kPushInstantiator);
}
__ PushObject(dst_name); // Push the name of the destination.
__ LoadObject(EAX, test_cache);
@@ -1766,7 +1805,7 @@
GenerateCallRuntime(node_id, token_index, kTypeCheckRuntimeEntry);
// Pop the parameters supplied to the runtime entry. The result of the
// type check runtime call is the checked value.
- __ addl(ESP, Immediate(7 * kWordSize));
+ __ addl(ESP, Immediate(8 * kWordSize));
__ popl(EAX);
// EAX: value.
@@ -2363,7 +2402,13 @@
// Pushes the type arguments of the instantiator on the stack.
// Destroys EBX.
-void CodeGenerator::GenerateInstantiatorTypeArguments(intptr_t token_index) {
+void CodeGenerator::GenerateInstantiatorTypeArguments(intptr_t token_index,
+ bool push_instantiator) {
+ if (push_instantiator) {
+ const Immediate raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
+ __ pushl(raw_null); // Initial instantiator.
+ }
const Class& instantiator_class = Class::Handle(
parsed_function().function().owner());
if (instantiator_class.NumTypeParameters() == 0) {
@@ -2385,7 +2430,14 @@
outer_function = outer_function.parent_function();
}
if (!outer_function.IsFactory()) {
- __ popl(EBX); // Pop instantiator.
+ if (push_instantiator) {
+ __ popl(EBX); // Pop instantiator.
+ __ popl(ECX); // Discard null instantiator.
+ __ pushl(EBX); // Replace it with the real one.
+ } else {
+ __ popl(EBX); // Pop instantiator.
+ }
+ // EBX: instantiator.
// The instantiator is the receiver of the caller, which is not a factory.
// The receiver cannot be null; extract its AbstractTypeArguments object.
// Note that in the factory case, the instantiator is the first parameter
@@ -2424,7 +2476,8 @@
}
} else {
// The type arguments are uninstantiated.
- GenerateInstantiatorTypeArguments(token_index);
+ const bool kPushInstantiator = false;
+ GenerateInstantiatorTypeArguments(token_index, kPushInstantiator);
__ popl(EAX); // Pop instantiator.
// EAX is the instantiator AbstractTypeArguments object (or null).
// If the instantiator is null and if the type argument vector
« no previous file with comments | « runtime/vm/code_generator_ia32.h ('k') | runtime/vm/flow_graph_compiler_x64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698