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

Unified Diff: runtime/vm/flow_graph_compiler_x64.cc

Issue 10477020: Move inlined type checking code to new compiler ia32. Sharing more and more code between ia32/x64 (… (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 6 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/flow_graph_compiler_x64.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/flow_graph_compiler_x64.cc
===================================================================
--- runtime/vm/flow_graph_compiler_x64.cc (revision 8286)
+++ runtime/vm/flow_graph_compiler_x64.cc (working copy)
@@ -60,6 +60,60 @@
#define __ assembler()->
+
+// Fall through if bool_register contains null.
+void FlowGraphCompiler::GenerateBoolToJump(Register bool_register,
+ Label* is_true,
+ Label* is_false) {
+ const Immediate raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
+ Label fall_through;
+ __ cmpq(bool_register, raw_null);
+ __ j(EQUAL, &fall_through, Assembler::kNearJump);
+ const Bool& bool_true = Bool::ZoneHandle(Bool::True());
+ __ CompareObject(bool_register, bool_true);
+ __ j(EQUAL, is_true);
+ __ jmp(is_false);
+ __ Bind(&fall_through);
+}
+
+
+RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub(
+ TypeTestStubKind test_kind,
+ Register instance_reg,
+ Register type_arguments_reg,
+ Register temp_reg,
+ Label* is_instance_lbl,
+ Label* is_not_instance_lbl) {
+ const SubtypeTestCache& type_test_cache =
+ SubtypeTestCache::ZoneHandle(SubtypeTestCache::New());
+ const Immediate raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
+ __ LoadObject(temp_reg, type_test_cache);
+ __ pushq(temp_reg); // Subtype test cache.
+ __ pushq(instance_reg); // Instance.
+ if (test_kind == kTestTypeOneArg) {
+ ASSERT(type_arguments_reg == kNoRegister);
+ __ pushq(raw_null);
+ __ call(&StubCode::Subtype1TestCacheLabel());
+ } else if (test_kind == kTestTypeTwoArgs) {
+ ASSERT(type_arguments_reg == kNoRegister);
+ __ pushq(raw_null);
+ __ call(&StubCode::Subtype2TestCacheLabel());
+ } else if (test_kind == kTestTypeThreeArgs) {
+ __ pushq(type_arguments_reg);
+ __ call(&StubCode::Subtype3TestCacheLabel());
+ } else {
+ UNREACHABLE();
+ }
+ // Result is in ECX: null -> not found, otherwise Bool::True or Bool::False.
+ __ popq(instance_reg); // Discard.
+ __ popq(instance_reg); // Restore receiver.
+ __ popq(temp_reg); // Discard.
+ GenerateBoolToJump(RCX, is_instance_lbl, is_not_instance_lbl);
+ return type_test_cache.raw();
+}
+
// Jumps to labels 'is_instance' or 'is_not_instance' respectively, if
// type test is conclusive, otherwise fallthrough if a type test could not
// be completed.
@@ -74,29 +128,25 @@
ASSERT(type.IsInstantiated());
const Class& type_class = Class::ZoneHandle(type.type_class());
ASSERT(type_class.HasTypeArguments());
+ const Register kInstanceReg = RAX;
// A Smi object cannot be the instance of a parameterized class.
- __ testq(RAX, Immediate(kSmiTagMask));
+ __ testq(kInstanceReg, Immediate(kSmiTagMask));
__ j(ZERO, is_not_instance_lbl);
const AbstractTypeArguments& type_arguments =
AbstractTypeArguments::ZoneHandle(type.arguments());
const bool is_raw_type = type_arguments.IsNull() ||
type_arguments.IsRaw(type_arguments.Length());
if (is_raw_type) {
+ const Register kClassIdReg = R10;
// Dynamic type argument, check only classes.
// List is a very common case.
- __ LoadClassId(R10, RAX);
+ __ LoadClassId(kClassIdReg, kInstanceReg);
if (!type_class.is_interface()) {
- __ cmpl(R10, Immediate(type_class.id()));
+ __ cmpl(kClassIdReg, Immediate(type_class.id()));
__ j(EQUAL, is_instance_lbl);
}
if (type.IsListInterface()) {
- Label unknown;
- GrowableArray<intptr_t> args;
- args.Add(kArray);
- args.Add(kGrowableObjectArray);
- args.Add(kImmutableArray);
- CheckClassIds(args, is_instance_lbl, &unknown);
- __ Bind(&unknown);
+ GenerateListTypeCheck(kClassIdReg, is_instance_lbl);
}
return GenerateSubtype1TestCacheLookup(
cid, token_index, type_class, is_instance_lbl, is_not_instance_lbl);
@@ -121,41 +171,26 @@
}
// Regular subtype test cache involving instance's type arguments.
- const SubtypeTestCache& type_test_cache =
- SubtypeTestCache::ZoneHandle(SubtypeTestCache::New());
- Label runtime_call;
- const Immediate raw_null =
- Immediate(reinterpret_cast<intptr_t>(Object::null()));
- __ LoadObject(R10, type_test_cache);
- __ pushq(R10); // Subtype test cache.
- __ pushq(RAX); // Instance.
- __ pushq(raw_null); // Unused.
- __ call(&StubCode::Subtype2TestCacheLabel());
- __ popq(RAX); // Discard.
- __ popq(RAX); // Restore receiver.
- __ popq(RDX); // Discard.
- // Result is in RCX: null -> not found, otherwise Bool::True or Bool::False.
-
- __ cmpq(RCX, raw_null);
- __ j(EQUAL, &runtime_call, Assembler::kNearJump);
- const Bool& bool_true = Bool::ZoneHandle(Bool::True());
- __ CompareObject(RCX, bool_true);
- __ j(EQUAL, is_instance_lbl);
- __ jmp(is_not_instance_lbl);
- __ Bind(&runtime_call);
- return type_test_cache.raw();
+ const Register kTypeArgumentsReg = kNoRegister;
+ const Register kTempReg = R10;
+ return GenerateCallSubtypeTestStub(kTestTypeTwoArgs,
+ kInstanceReg,
+ kTypeArgumentsReg,
+ kTempReg,
+ is_instance_lbl,
+ is_not_instance_lbl);
}
-// R10: instance class id to check.
-void FlowGraphCompiler::CheckClassIds(const GrowableArray<intptr_t>& class_ids,
- Label* is_instance_lbl,
- Label* is_not_instance_lbl) {
+void FlowGraphCompiler::CheckClassIds(Register class_id_reg,
+ const GrowableArray<intptr_t>& class_ids,
+ Label* is_equal_lbl,
+ Label* is_not_equal_lbl) {
for (intptr_t i = 0; i < class_ids.length(); i++) {
- __ cmpl(R10, Immediate(class_ids[i]));
- __ j(EQUAL, is_instance_lbl);
+ __ cmpl(class_id_reg, Immediate(class_ids[i]));
+ __ j(EQUAL, is_equal_lbl);
}
- __ jmp(is_not_instance_lbl);
+ __ jmp(is_not_equal_lbl);
}
@@ -191,17 +226,18 @@
// Compare if the classes are equal. Instance is not Smi.
__ Bind(&compare_classes);
- __ LoadClassId(R10, RAX);
+ const Register kClassIdReg = R10;
+ __ LoadClassId(kClassIdReg, RAX);
// If type is an interface, we can skip the class equality check.
if (!type_class.is_interface()) {
- __ cmpl(R10, Immediate(type_class.id()));
+ __ cmpl(kClassIdReg, Immediate(type_class.id()));
__ j(EQUAL, is_instance_lbl);
}
// Check for interfaces that cannot be implemented by user.
// (see ClassFinalizer::ResolveInterfaces for list of restricted interfaces).
// Bool interface can be implemented only by core class Bool.
if (type.IsBoolInterface()) {
- __ cmpl(R10, Immediate(kBool));
+ __ cmpl(kClassIdReg, Immediate(kBool));
__ j(EQUAL, is_instance_lbl);
__ jmp(is_not_instance_lbl);
return;
@@ -210,7 +246,7 @@
// Check if instance is a closure.
const Immediate raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
- __ LoadClassById(R13, R10);
+ __ LoadClassById(R13, kClassIdReg);
__ movq(R13, FieldAddress(R13, Class::signature_function_offset()));
__ cmpq(R13, raw_null);
__ j(NOT_EQUAL, is_instance_lbl);
@@ -221,29 +257,12 @@
// Note that instance is not Smi(checked above).
if (type.IsSubtypeOf(
Type::Handle(Type::NumberInterface()), &malformed_error)) {
- GrowableArray<intptr_t> args;
- if (type.IsNumberInterface()) {
- args.Add(kDouble);
- args.Add(kMint);
- args.Add(kBigint);
- } else if (type.IsIntInterface()) {
- args.Add(kMint);
- args.Add(kBigint);
- } else if (type.IsDoubleInterface()) {
- args.Add(kDouble);
- }
- CheckClassIds(args, is_instance_lbl, is_not_instance_lbl);
+ GenerateNumberTypeCheck(
+ kClassIdReg, type, is_instance_lbl, is_not_instance_lbl);
return;
}
if (type.IsStringInterface()) {
- GrowableArray<intptr_t> args;
- args.Add(kOneByteString);
- args.Add(kTwoByteString);
- args.Add(kFourByteString);
- args.Add(kExternalOneByteString);
- args.Add(kExternalTwoByteString);
- args.Add(kExternalFourByteString);
- CheckClassIds(args, is_instance_lbl, is_not_instance_lbl);
+ GenerateStringTypeCheck(kClassIdReg, is_instance_lbl, is_not_instance_lbl);
return;
}
// Otherwise fallthrough.
@@ -259,45 +278,31 @@
const Class& type_class,
Label* is_instance_lbl,
Label* is_not_instance_lbl) {
- const SubtypeTestCache& type_test_cache =
- SubtypeTestCache::ZoneHandle(SubtypeTestCache::New());
- const Bool& bool_true = Bool::ZoneHandle(Bool::True());
- const Immediate raw_null =
- Immediate(reinterpret_cast<intptr_t>(Object::null()));
- __ LoadClass(R10, RAX);
+ const Register kInstanceReg = RAX;
+ __ LoadClass(R10, kInstanceReg);
// Check immediate superclass equality.
__ movq(R13, FieldAddress(R10, Class::super_type_offset()));
__ movq(R13, FieldAddress(R13, Type::type_class_offset()));
__ CompareObject(R13, type_class);
__ j(EQUAL, is_instance_lbl);
- __ LoadObject(R10, type_test_cache);
- __ pushq(R10); // Cache array.
- __ pushq(RAX); // Instance.
- __ pushq(raw_null); // Unused
- __ call(&StubCode::Subtype1TestCacheLabel());
- __ popq(RAX); // Discard.
- __ popq(RAX); // Restore receiver.
- __ popq(RDX); // Discard.
- // Result is in RCX: null -> not found, otherwise Bool::True or Bool::False.
-
- Label runtime_call;
- __ cmpq(RCX, raw_null);
- __ j(EQUAL, &runtime_call, Assembler::kNearJump);
- __ CompareObject(RCX, bool_true);
- __ j(EQUAL, is_instance_lbl);
- __ jmp(is_not_instance_lbl);
- __ Bind(&runtime_call);
- return type_test_cache.raw();
+ const Register kTypeArgumentsReg = kNoRegister;
+ const Register kTempReg = R10;
+ return GenerateCallSubtypeTestStub(kTestTypeOneArg,
+ kInstanceReg,
+ kTypeArgumentsReg,
+ kTempReg,
+ is_instance_lbl,
+ is_not_instance_lbl);
}
// Generates inlined check if 'type' is a type parameter or type itsef
// RAX: instance (preserved).
RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
- const AbstractType& type,
intptr_t cid,
intptr_t token_index,
+ const AbstractType& type,
Label* is_instance_lbl,
Label* is_not_instance_lbl) {
ASSERT(!type.IsInstantiated());
@@ -323,6 +328,11 @@
__ j(EQUAL, is_instance_lbl);
__ cmpq(RDI, raw_null);
__ j(EQUAL, is_instance_lbl);
+ const Type& object_type =
+ Type::ZoneHandle(Isolate::Current()->object_store()->object_type());
+ __ CompareObject(RDI, object_type);
+ __ j(EQUAL, is_instance_lbl);
+
// For Smi check quickly against int and num interface types.
Label not_smi;
__ testq(RAX, Immediate(kSmiTagMask)); // Value is Smi?
@@ -331,56 +341,42 @@
__ j(EQUAL, is_instance_lbl);
__ CompareObject(RDI, Type::ZoneHandle(Type::NumberInterface()));
__ j(EQUAL, is_instance_lbl);
+ // Smi must be handled in runtime.
__ jmp(&fall_through);
+
__ Bind(&not_smi);
// RDX: instantiator type arguments.
// RAX: instance.
+ const Register kInstanceReg = RAX;
+ const Register kTypeArgumentsReg = RDX;
+ const Register kTempReg = R10;
const SubtypeTestCache& type_test_cache =
- SubtypeTestCache::ZoneHandle(SubtypeTestCache::New());
- __ LoadObject(R10, type_test_cache);
- __ pushq(R10); // Subtype test cache.
- __ pushq(RAX); // Instance
- __ pushq(RDX); // Instantiator type arguments.
- __ call(&StubCode::Subtype3TestCacheLabel());
- __ popq(RDX); // Discard type arguments.
- __ popq(RAX); // Restore receiver.
- __ popq(RDX); // Discard subtype test cache.
- // Result is in RCX: null -> not found, otherwise Bool::True or Bool::False.
- __ cmpq(RCX, raw_null);
- __ j(EQUAL, &fall_through, Assembler::kNearJump);
- const Bool& bool_true = Bool::ZoneHandle(Bool::True());
- __ CompareObject(RCX, bool_true);
- __ j(EQUAL, is_instance_lbl);
- __ jmp(is_not_instance_lbl);
+ SubtypeTestCache::ZoneHandle(
+ GenerateCallSubtypeTestStub(kTestTypeThreeArgs,
+ kInstanceReg,
+ kTypeArgumentsReg,
+ kTempReg,
+ is_instance_lbl,
+ is_not_instance_lbl));
+
__ Bind(&fall_through);
return type_test_cache.raw();
}
if (type.IsType()) {
- Label fall_through;
- __ testq(RAX, Immediate(kSmiTagMask)); // Is instance Smi?
+ const Register kInstanceReg = RAX;
+ const Register kTypeArgumentsReg = RDX;
+ __ testq(kInstanceReg, Immediate(kSmiTagMask)); // Is instance Smi?
__ j(ZERO, is_not_instance_lbl);
- __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments.
+ __ movq(kTypeArgumentsReg, Address(RSP, 0)); // Instantiator type args.
// 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(R10, type_test_cache);
- __ pushq(R10); // Subtype test cache.
- __ pushq(RAX); // Instance.
- __ pushq(RDX); // Instantiator type arguments.
- __ call(&StubCode::Subtype3TestCacheLabel());
- __ popq(RDX); // Discard type arguments.
- __ popq(RAX); // Restore receiver.
- __ popq(RDX); // Discard subtype test cache.
- // Result is in RCX: null -> not found, otherwise Bool::True or Bool::False.
- __ cmpq(RCX, raw_null);
- __ j(EQUAL, &fall_through, Assembler::kNearJump);
- const Bool& bool_true = Bool::ZoneHandle(Bool::True());
- __ CompareObject(RCX, bool_true);
- __ j(EQUAL, is_instance_lbl);
- __ jmp(is_not_instance_lbl);
- __ Bind(&fall_through);
- return type_test_cache.raw();
+ const Register kTempReg = R10;
+ return GenerateCallSubtypeTestStub(kTestTypeThreeArgs,
+ kInstanceReg,
+ kTypeArgumentsReg,
+ kTempReg,
+ is_instance_lbl,
+ is_not_instance_lbl);
}
return SubtypeTestCache::null();
}
@@ -426,9 +422,9 @@
is_instance_lbl, is_not_instance_lbl);
}
} else {
- return GenerateUninstantiatedTypeTest(type,
- cid,
+ return GenerateUninstantiatedTypeTest(cid,
token_index,
+ type,
is_instance_lbl,
is_not_instance_lbl);
}
« no previous file with comments | « runtime/vm/flow_graph_compiler_x64.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698