Chromium Code Reviews| Index: runtime/vm/flow_graph_compiler_x64.cc |
| diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc |
| index ae6d6105b9853aec50e4d1f5bd5014daa8f22ddf..aeac2a4d0f9f4518a5f16bdab829e53dcdb918e4 100644 |
| --- a/runtime/vm/flow_graph_compiler_x64.cc |
| +++ b/runtime/vm/flow_graph_compiler_x64.cc |
| @@ -205,7 +205,8 @@ void FlowGraphCompiler::GenerateBoolToJump(Register bool_register, |
| RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( |
| TypeTestStubKind test_kind, |
| Register instance_reg, |
| - Register type_arguments_reg, |
| + Register instantiator_type_arguments_reg, |
| + Register function_type_arguments_reg, |
| Register temp_reg, |
| Label* is_instance_lbl, |
| Label* is_not_instance_lbl) { |
| @@ -215,16 +216,21 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( |
| __ pushq(temp_reg); // Subtype test cache. |
| __ pushq(instance_reg); // Instance. |
| if (test_kind == kTestTypeOneArg) { |
| - ASSERT(type_arguments_reg == kNoRegister); |
| + ASSERT(instantiator_type_arguments_reg == kNoRegister); |
| + ASSERT(function_type_arguments_reg == kNoRegister); |
| + __ PushObject(Object::null_object()); |
| __ PushObject(Object::null_object()); |
|
siva
2017/04/10 22:04:55
Do you think it helps to comment as, here and othe
regis
2017/04/11 04:23:08
Done.
|
| __ Call(*StubCode::Subtype1TestCache_entry()); |
| } else if (test_kind == kTestTypeTwoArgs) { |
| - ASSERT(type_arguments_reg == kNoRegister); |
| + ASSERT(instantiator_type_arguments_reg == kNoRegister); |
| + ASSERT(function_type_arguments_reg == kNoRegister); |
| + __ PushObject(Object::null_object()); |
| __ PushObject(Object::null_object()); |
| __ Call(*StubCode::Subtype2TestCache_entry()); |
| - } else if (test_kind == kTestTypeThreeArgs) { |
| - __ pushq(type_arguments_reg); |
| - __ Call(*StubCode::Subtype3TestCache_entry()); |
| + } else if (test_kind == kTestTypeFourArgs) { |
| + __ pushq(instantiator_type_arguments_reg); |
| + __ pushq(function_type_arguments_reg); |
| + __ Call(*StubCode::Subtype4TestCache_entry()); |
| } else { |
| UNREACHABLE(); |
| } |
| @@ -232,6 +238,7 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub( |
| ASSERT(instance_reg != RCX); |
| ASSERT(temp_reg != RCX); |
| __ popq(instance_reg); // Discard. |
| + __ popq(instance_reg); // Discard. |
| __ popq(instance_reg); // Restore receiver. |
| __ popq(temp_reg); // Discard. |
|
siva
2017/04/10 22:04:55
Does it make sense to use
__ Drop(4, temp_reg);
he
regis
2017/04/11 04:23:08
Replaced first 2 popq with Drop(2), since we resto
|
| GenerateBoolToJump(RCX, is_instance_lbl, is_not_instance_lbl); |
| @@ -307,10 +314,12 @@ FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest( |
| } |
| } |
| // Regular subtype test cache involving instance's type arguments. |
| - const Register kTypeArgumentsReg = kNoRegister; |
| + const Register kInstantiatorTypeArgumentsReg = kNoRegister; |
| + const Register kFunctionTypeArgumentsReg = kNoRegister; |
| const Register kTempReg = R10; |
| return GenerateCallSubtypeTestStub(kTestTypeTwoArgs, kInstanceReg, |
| - kTypeArgumentsReg, kTempReg, |
| + kInstantiatorTypeArgumentsReg, |
| + kFunctionTypeArgumentsReg, kTempReg, |
| is_instance_lbl, is_not_instance_lbl); |
| } |
| @@ -417,10 +426,12 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup( |
| __ CompareImmediate(R13, Immediate(Smi::RawValue(type_class.id()))); |
| __ j(EQUAL, is_instance_lbl); |
| - const Register kTypeArgumentsReg = kNoRegister; |
| + const Register kInstantiatorTypeArgumentsReg = kNoRegister; |
| + const Register kFunctionTypeArgumentsReg = kNoRegister; |
| const Register kTempReg = R10; |
| return GenerateCallSubtypeTestStub(kTestTypeOneArg, kInstanceReg, |
| - kTypeArgumentsReg, kTempReg, |
| + kInstantiatorTypeArgumentsReg, |
| + kFunctionTypeArgumentsReg, kTempReg, |
| is_instance_lbl, is_not_instance_lbl); |
| } |
| @@ -438,14 +449,17 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( |
| // Skip check if destination is a dynamic type. |
| if (type.IsTypeParameter()) { |
| const TypeParameter& type_param = TypeParameter::Cast(type); |
| - // Load instantiator type arguments on stack. |
| - __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. |
| + __ movq(RDX, Address(RSP, 1 * kWordSize)); // Get instantiator type args. |
| + __ movq(RCX, Address(RSP, 0 * kWordSize)); // Get function type args. |
| // RDX: instantiator type arguments. |
| + // RCX: function type arguments. |
| + const Register kTypeArgumentsReg = |
| + type_param.IsClassTypeParameter() ? RDX : RCX; |
| // Check if type arguments are null, i.e. equivalent to vector of dynamic. |
| - __ CompareObject(RDX, Object::null_object()); |
| + __ CompareObject(kTypeArgumentsReg, Object::null_object()); |
| __ j(EQUAL, is_instance_lbl); |
| - __ movq(RDI, FieldAddress( |
| - RDX, TypeArguments::type_at_offset(type_param.index()))); |
| + __ movq(RDI, FieldAddress(kTypeArgumentsReg, TypeArguments::type_at_offset( |
| + type_param.index()))); |
| // RDI: Concrete type of type. |
| // Check if type argument is dynamic. |
| __ CompareObject(RDI, Object::dynamic_type()); |
| @@ -453,6 +467,7 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( |
| const Type& object_type = Type::ZoneHandle(zone(), Type::ObjectType()); |
| __ CompareObject(RDI, object_type); |
| __ j(EQUAL, is_instance_lbl); |
| + // TODO(regis): Optimize void type as well once allowed as type argument. |
| // For Smi check quickly against int and num interfaces. |
| Label not_smi; |
| @@ -467,29 +482,35 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( |
| __ jmp(&fall_through); |
| __ Bind(¬_smi); |
| - // RDX: instantiator type arguments. |
| // RAX: instance. |
| + // RDX: instantiator type arguments. |
| + // RCX: function type arguments. |
| const Register kInstanceReg = RAX; |
| - const Register kTypeArgumentsReg = RDX; |
| + const Register kInstantiatorTypeArgumentsReg = RDX; |
| + const Register kFunctionTypeArgumentsReg = RCX; |
| const Register kTempReg = R10; |
| const SubtypeTestCache& type_test_cache = SubtypeTestCache::ZoneHandle( |
| zone(), GenerateCallSubtypeTestStub( |
| - kTestTypeThreeArgs, kInstanceReg, kTypeArgumentsReg, |
| + kTestTypeFourArgs, kInstanceReg, |
| + kInstantiatorTypeArgumentsReg, kFunctionTypeArgumentsReg, |
| kTempReg, is_instance_lbl, is_not_instance_lbl)); |
| __ Bind(&fall_through); |
| return type_test_cache.raw(); |
| } |
| if (type.IsType()) { |
| const Register kInstanceReg = RAX; |
| - const Register kTypeArgumentsReg = RDX; |
| + const Register kInstantiatorTypeArgumentsReg = RDX; |
| + const Register kFunctionTypeArgumentsReg = RCX; |
| __ testq(kInstanceReg, Immediate(kSmiTagMask)); // Is instance Smi? |
| __ j(ZERO, is_not_instance_lbl); |
| - __ movq(kTypeArgumentsReg, Address(RSP, 0)); // Instantiator type args. |
| + __ movq(kInstantiatorTypeArgumentsReg, Address(RSP, 1 * kWordSize)); |
| + __ movq(kFunctionTypeArgumentsReg, Address(RSP, 0 * kWordSize)); |
| // Uninstantiated type class is known at compile time, but the type |
| - // arguments are determined at runtime by the instantiator. |
| + // arguments are determined at runtime by the instantiator(s). |
| const Register kTempReg = R10; |
| - return GenerateCallSubtypeTestStub(kTestTypeThreeArgs, kInstanceReg, |
| - kTypeArgumentsReg, kTempReg, |
| + return GenerateCallSubtypeTestStub(kTestTypeFourArgs, kInstanceReg, |
| + kInstantiatorTypeArgumentsReg, |
| + kFunctionTypeArgumentsReg, kTempReg, |
| is_instance_lbl, is_not_instance_lbl); |
| } |
| return SubtypeTestCache::null(); |
| @@ -499,9 +520,11 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest( |
| // Inputs: |
| // - RAX: instance to test against (preserved). |
| // - RDX: optional instantiator type arguments (preserved). |
| +// - RCX: optional function type arguments (preserved). |
| // Clobbers R10, R13. |
| // Returns: |
| -// - preserved instance in RAX and optional instantiator type arguments in RDX. |
| +// - preserved instance in RAX, optional instantiator type arguments in RDX, and |
| +// optional function type arguments in RCX. |
| // Note that this inlined code must be followed by the runtime_call code, as it |
| // may fall through to it. Otherwise, this inline code will jump to the label |
| // is_instance or to the label is_not_instance. |
| @@ -550,7 +573,7 @@ RawSubtypeTestCache* FlowGraphCompiler::GenerateInlineInstanceof( |
| // Inputs: |
| // - RAX: object. |
| // - RDX: instantiator type arguments or raw_null. |
| -// Clobbers RDX. |
| +// - RCX: function type arguments or raw_null. |
| // Returns: |
| // - true or false in RAX. |
| void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos, |
| @@ -560,8 +583,10 @@ void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos, |
| ASSERT(type.IsFinalized() && !type.IsMalformedOrMalbounded()); |
| ASSERT(!type.IsObjectType() && !type.IsDynamicType()); |
| - Label is_instance, is_not_instance; |
| __ pushq(RDX); // Store instantiator type arguments. |
| + __ pushq(RCX); // Store function type arguments. |
| + |
| + Label is_instance, is_not_instance; |
| // If type is instantiated and non-parameterized, we can inline code |
| // checking whether the tested instance is a Smi. |
| if (type.IsInstantiated()) { |
| @@ -585,17 +610,19 @@ void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos, |
| Label done; |
| if (!test_cache.IsNull()) { |
| // Generate runtime call. |
| - __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. |
| + __ movq(RDX, Address(RSP, 1 * kWordSize)); // Get instantiator type args. |
| + __ movq(RCX, Address(RSP, 0 * kWordSize)); // Get function type args. |
| __ PushObject(Object::null_object()); // Make room for the result. |
| __ pushq(RAX); // Push the instance. |
| __ PushObject(type); // Push the type. |
| __ pushq(RDX); // Instantiator type arguments. |
| + __ pushq(RCX); // Function type arguments. |
| __ LoadUniqueObject(RAX, test_cache); |
| __ pushq(RAX); |
| - GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 4, locs); |
| + GenerateRuntimeCall(token_pos, deopt_id, kInstanceofRuntimeEntry, 5, locs); |
| // Pop the parameters supplied to the runtime entry. The result of the |
| // instanceof runtime call will be left as the result of the operation. |
| - __ Drop(4); |
| + __ Drop(5); |
| __ popq(RAX); |
| __ jmp(&done, Assembler::kNearJump); |
| } |
| @@ -606,6 +633,7 @@ void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos, |
| __ Bind(&is_instance); |
| __ LoadObject(RAX, Bool::Get(true)); |
| __ Bind(&done); |
| + __ popq(RCX); // Remove pushed function type arguments. |
| __ popq(RDX); // Remove pushed instantiator type arguments. |
| } |
| @@ -617,6 +645,7 @@ void FlowGraphCompiler::GenerateInstanceOf(TokenPosition token_pos, |
| // Inputs: |
| // - RAX: object. |
| // - RDX: instantiator type arguments or raw_null. |
| +// - RCX: function type arguments or raw_null. |
| // Returns: |
| // - object in RAX for successful assignable check (or throws TypeError). |
| // Performance notes: positive checks must be quick, negative checks can be slow |
| @@ -633,6 +662,7 @@ void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos, |
| ASSERT(dst_type.IsMalformedOrMalbounded() || |
| (!dst_type.IsDynamicType() && !dst_type.IsObjectType())); |
| __ pushq(RDX); // Store instantiator type arguments. |
| + __ pushq(RCX); // Store function type arguments. |
| // A null object is always assignable and is returned as result. |
| Label is_assignable, runtime_call; |
| __ CompareObject(RAX, Object::null_object()); |
| @@ -650,6 +680,7 @@ void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos, |
| __ int3(); |
| __ Bind(&is_assignable); // For a null object. |
| + __ popq(RCX); // Remove pushed function type arguments. |
| __ popq(RDX); // Remove pushed instantiator type arguments. |
| return; |
| } |
| @@ -660,21 +691,24 @@ void FlowGraphCompiler::GenerateAssertAssignable(TokenPosition token_pos, |
| &runtime_call); |
| __ Bind(&runtime_call); |
| - __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments. |
| + __ movq(RDX, Address(RSP, 1 * kWordSize)); // Get instantiator type args. |
| + __ movq(RCX, Address(RSP, 0 * kWordSize)); // Get function type args. |
| __ PushObject(Object::null_object()); // Make room for the result. |
| __ pushq(RAX); // Push the source object. |
| __ PushObject(dst_type); // Push the type of the destination. |
| __ pushq(RDX); // Instantiator type arguments. |
| + __ pushq(RCX); // Function type arguments. |
| __ PushObject(dst_name); // Push the name of the destination. |
| __ LoadUniqueObject(RAX, test_cache); |
| __ pushq(RAX); |
| - GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 5, locs); |
| + GenerateRuntimeCall(token_pos, deopt_id, kTypeCheckRuntimeEntry, 6, locs); |
| // Pop the parameters supplied to the runtime entry. The result of the |
| // type check runtime call is the checked value. |
| - __ Drop(5); |
| + __ Drop(6); |
| __ popq(RAX); |
| __ Bind(&is_assignable); |
| + __ popq(RCX); // Remove pushed function type arguments. |
| __ popq(RDX); // Remove pushed instantiator type arguments. |
| } |