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

Unified Diff: runtime/vm/flow_graph_compiler_x64.cc

Issue 10636038: Minimize differences between ia32 and x64 sources to facilitate maintenance. (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 9088)
+++ runtime/vm/flow_graph_compiler_x64.cc (working copy)
@@ -9,9 +9,6 @@
#include "lib/error.h"
#include "vm/ast_printer.h"
-#include "vm/code_descriptors.h"
-#include "vm/code_generator.h"
-#include "vm/disassembler.h"
#include "vm/il_printer.h"
#include "vm/locations.h"
#include "vm/object_store.h"
@@ -20,10 +17,10 @@
namespace dart {
-DEFINE_FLAG(bool, print_scopes, false, "Print scopes of local variables.");
-DEFINE_FLAG(bool, trace_functions, false, "Trace entry of each function.");
DECLARE_FLAG(bool, enable_type_checks);
DECLARE_FLAG(bool, print_ast);
+DECLARE_FLAG(bool, print_scopes);
+DECLARE_FLAG(bool, trace_functions);
void DeoptimizationStub::GenerateCode(FlowGraphCompiler* compiler) {
@@ -49,7 +46,6 @@
#define __ assembler()->
-
// Fall through if bool_register contains null.
void FlowGraphCompiler::GenerateBoolToJump(Register bool_register,
Label* is_true,
@@ -66,6 +62,7 @@
}
+// Clobbers RCX.
RawSubtypeTestCache* FlowGraphCompiler::GenerateCallSubtypeTestStub(
TypeTestStubKind test_kind,
Register instance_reg,
@@ -94,7 +91,9 @@
} else {
UNREACHABLE();
}
- // Result is in ECX: null -> not found, otherwise Bool::True or Bool::False.
+ // Result is in RCX: null -> not found, otherwise Bool::True or Bool::False.
+ ASSERT(instance_reg != RCX);
+ ASSERT(temp_reg != RCX);
__ popq(instance_reg); // Discard.
__ popq(instance_reg); // Restore receiver.
__ popq(temp_reg); // Discard.
@@ -102,10 +101,12 @@
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.
-// RAX: instance (must survive),
+// RAX: instance (must survive).
+// Clobbers R10.
RawSubtypeTestCache*
FlowGraphCompiler::GenerateInstantiatedTypeWithArgumentsTest(
intptr_t cid,
@@ -156,7 +157,6 @@
}
}
}
-
// Regular subtype test cache involving instance's type arguments.
const Register kTypeArgumentsReg = kNoRegister;
const Register kTempReg = R10;
@@ -181,10 +181,10 @@
}
-
// Testing against an instantiated type with no arguments, without
// SubtypeTestCache.
// RAX: instance to test against (preserved).
+// Clobbers R10, R13.
void FlowGraphCompiler::GenerateInstantiatedTypeNoArgumentsTest(
intptr_t cid,
intptr_t token_pos,
@@ -192,12 +192,13 @@
Label* is_instance_lbl,
Label* is_not_instance_lbl) {
ASSERT(type.IsInstantiated());
- const Class& type_class = Class::ZoneHandle(type.type_class());
+ const Class& type_class = Class::Handle(type.type_class());
ASSERT(!type_class.HasTypeArguments());
+ const Register kInstanceReg = RAX;
Label compare_classes;
- __ testq(RAX, Immediate(kSmiTagMask));
- __ j(NOT_ZERO, &compare_classes);
+ __ testq(kInstanceReg, Immediate(kSmiTagMask));
+ __ j(NOT_ZERO, &compare_classes, Assembler::kNearJump);
// Instance is Smi, check directly.
const Class& smi_class = Class::Handle(Smi::Class());
// TODO(regis): We should introduce a SmiType.
@@ -210,19 +211,17 @@
} else {
__ jmp(is_not_instance_lbl);
}
-
- // Compare if the classes are equal. Instance is not Smi.
+ // Compare if the classes are equal.
__ Bind(&compare_classes);
const Register kClassIdReg = R10;
- __ LoadClassId(kClassIdReg, RAX);
+ __ LoadClassId(kClassIdReg, kInstanceReg);
// If type is an interface, we can skip the class equality check.
if (!type_class.is_interface()) {
__ 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.
+ // (see ClassFinalizer::ResolveInterfaces for list of restricted interfaces).
if (type.IsBoolInterface()) {
__ cmpl(kClassIdReg, Immediate(kBool));
__ j(EQUAL, is_instance_lbl);
@@ -258,7 +257,11 @@
// Uses SubtypeTestCache to store instance class and result.
// RAX: instance to test.
+// Clobbers R10, R13.
// Immediate class test already done.
+// TODO(srdjan): Implement a quicker subtype check, as type test
+// arrays can grow too high, but they may be useful when optimizing
+// code (type-feedback).
RawSubtypeTestCache* FlowGraphCompiler::GenerateSubtype1TestCacheLookup(
intptr_t cid,
intptr_t token_pos,
@@ -267,6 +270,7 @@
Label* is_not_instance_lbl) {
const Register kInstanceReg = RAX;
__ LoadClass(R10, kInstanceReg);
+ // R10: instance class.
// Check immediate superclass equality.
__ movq(R13, FieldAddress(R10, Class::super_type_offset()));
__ movq(R13, FieldAddress(R13, Type::type_class_offset()));
@@ -286,6 +290,7 @@
// Generates inlined check if 'type' is a type parameter or type itsef
// RAX: instance (preserved).
+// Clobbers RDI, RDX, R10.
RawSubtypeTestCache* FlowGraphCompiler::GenerateUninstantiatedTypeTest(
intptr_t cid,
intptr_t token_pos,
@@ -293,6 +298,7 @@
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()) {
@@ -309,8 +315,8 @@
__ j(NOT_EQUAL, &fall_through);
__ movq(RDI,
FieldAddress(RDX, TypeArguments::type_at_offset(type.Index())));
- // RDI: Concrete type.
- // Check if it is Dynamic,
+ // RDI: Concrete type of type.
+ // Check if type argument is dynamic.
__ CompareObject(RDI, Type::ZoneHandle(Type::DynamicType()));
__ j(EQUAL, is_instance_lbl);
__ cmpq(RDI, raw_null);
@@ -319,7 +325,7 @@
__ CompareObject(RDI, object_type);
__ j(EQUAL, is_instance_lbl);
- // For Smi check quickly against int and num interface types.
+ // For Smi check quickly against int and num interfaces.
Label not_smi;
__ testq(RAX, Immediate(kSmiTagMask)); // Value is Smi?
__ j(NOT_ZERO, &not_smi, Assembler::kNearJump);
@@ -344,7 +350,6 @@
kTempReg,
is_instance_lbl,
is_not_instance_lbl));
-
__ Bind(&fall_through);
return type_test_cache.raw();
}
@@ -371,9 +376,9 @@
// Inputs:
// - RAX: instance to test against (preserved).
// - RDX: optional instantiator type arguments (preserved).
-// Destroys RCX.
+// Clobbers R10, R13.
// Returns:
-// - unchanged object in RAX and optional instantiator type arguments in RDX.
+// - preserved instance in RAX and optional instantiator type arguments in RDX.
// 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.
@@ -418,6 +423,89 @@
}
+// If instanceof type test cannot be performed successfully at compile time and
+// therefore eliminated, optimize it by adding inlined tests for:
+// - NULL -> return false.
+// - Smi -> compile time subtype check (only if dst class is not parameterized).
+// - Class equality (only if class is not parameterized).
+// Inputs:
+// - RAX: object.
+// - RDX: instantiator type arguments or raw_null.
+// - RCX: instantiator or raw_null.
+// Clobbers RCX and RDX.
+// Returns:
+// - true or false in RAX.
+void FlowGraphCompiler::GenerateInstanceOf(intptr_t cid,
+ intptr_t token_pos,
+ intptr_t try_index,
+ const AbstractType& type,
+ bool negate_result) {
+ ASSERT(type.IsFinalized() && !type.IsMalformed());
+
+ const Immediate raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
+ Label is_instance, is_not_instance;
+ __ pushq(RCX); // Store instantiator on stack.
+ __ pushq(RDX); // Store instantiator type arguments.
+ // If type is instantiated and non-parameterized, we can inline code
+ // checking whether the tested instance is a Smi.
+ if (type.IsInstantiated()) {
+ // A null object is only an instance of Object and Dynamic, which has
+ // already been checked above (if the type is instantiated). So we can
+ // return false here if the instance is null (and if the type is
+ // instantiated).
+ // We can only inline this null check if the type is instantiated at compile
+ // time, since an uninstantiated type at compile time could be Object or
+ // Dynamic at run time.
+ __ cmpq(RAX, raw_null);
+ __ j(EQUAL, &is_not_instance);
+ }
+
+ // Generate inline instanceof test.
+ SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
+ test_cache = GenerateInlineInstanceof(cid, token_pos, type,
+ &is_instance, &is_not_instance);
+
+ // Generate runtime call.
+ __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments.
+ __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator.
+ __ PushObject(Object::ZoneHandle()); // Make room for the result.
+ __ pushq(Immediate(Smi::RawValue(token_pos))); // Source location.
+ __ pushq(Immediate(Smi::RawValue(cid))); // Computation id.
+ __ pushq(RAX); // Push the instance.
+ __ PushObject(type); // Push the type.
+ __ pushq(RCX); // TODO(srdjan): Pass instantiator instead of null.
+ __ pushq(RDX); // Instantiator type arguments.
+ __ LoadObject(RAX, test_cache);
+ __ pushq(RAX);
+ GenerateCallRuntime(cid, token_pos, try_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.
+ __ Drop(7);
+ Label done;
+ if (negate_result) {
+ __ popq(RDX);
+ __ LoadObject(RAX, bool_true());
+ __ cmpq(RDX, RAX);
+ __ j(NOT_EQUAL, &done, Assembler::kNearJump);
+ __ LoadObject(RAX, bool_false());
+ } else {
+ __ popq(RAX);
+ }
+ __ jmp(&done, Assembler::kNearJump);
+
+ __ Bind(&is_not_instance);
+ __ LoadObject(RAX, negate_result ? bool_true() : bool_false());
+ __ jmp(&done, Assembler::kNearJump);
+
+ __ Bind(&is_instance);
+ __ LoadObject(RAX, negate_result ? bool_false() : bool_true());
+ __ Bind(&done);
+ __ popq(RDX); // Remove pushed instantiator type arguments.
+ __ popq(RCX); // Remove pushed instantiator.
+}
+
+
// Optimize assignable type check by adding inlined tests for:
// - NULL -> return NULL.
// - Smi -> compile time subtype check (only if dst class is not parameterized).
@@ -476,6 +564,7 @@
SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
test_cache = GenerateInlineInstanceof(cid, token_pos, dst_type,
&is_assignable, &runtime_call);
+
__ Bind(&runtime_call);
__ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments.
__ movq(RCX, Address(RSP, kWordSize)); // Get instantiator.
@@ -504,129 +593,6 @@
}
-void FlowGraphCompiler::LoadValue(Register dst, Value* value) {
- if (value->IsConstant()) {
- ConstantVal* constant = value->AsConstant();
- if (constant->value().IsSmi()) {
- int64_t imm = reinterpret_cast<int64_t>(constant->value().raw());
- __ movq(dst, Immediate(imm));
- } else {
- __ LoadObject(dst, value->AsConstant()->value());
- }
- } else {
- ASSERT(value->IsUse());
- __ popq(dst);
- }
-}
-
-
-intptr_t FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label,
- const ICData& ic_data,
- const Array& arguments_descriptor,
- intptr_t argument_count) {
- __ LoadObject(RBX, ic_data);
- __ LoadObject(R10, arguments_descriptor);
-
- __ call(target_label);
- const intptr_t descr_offset = assembler()->CodeSize();
- __ Drop(argument_count);
- return descr_offset;
-}
-
-intptr_t FlowGraphCompiler::EmitStaticCall(const Function& function,
- const Array& arguments_descriptor,
- intptr_t argument_count) {
- __ LoadObject(RBX, function);
- __ LoadObject(R10, arguments_descriptor);
- __ call(&StubCode::CallStaticFunctionLabel());
- const intptr_t descr_offset = assembler()->CodeSize();
- __ Drop(argument_count);
- return descr_offset;
-}
-
-
-// Optimize instanceof type test by adding inlined tests for:
-// - NULL -> return false.
-// - Smi -> compile time subtype check (only if dst class is not parameterized).
-// - Class equality (only if class is not parameterized).
-// Inputs:
-// - RAX: object.
-// - RDX: instantiator type arguments or raw_null.
-// - RCX: instantiator or raw_null.
-// Destroys RCX and RDX.
-// Returns:
-// - true or false in RAX.
-void FlowGraphCompiler::GenerateInstanceOf(intptr_t cid,
- intptr_t token_pos,
- intptr_t try_index,
- const AbstractType& type,
- bool negate_result) {
- ASSERT(type.IsFinalized() && !type.IsMalformed());
-
- const Immediate raw_null =
- Immediate(reinterpret_cast<intptr_t>(Object::null()));
- Label is_instance, is_not_instance;
- __ pushq(RCX); // Store instantiator on stack.
- __ pushq(RDX); // Store instantiator type arguments.
- // If type is instantiated and non-parameterized, we can inline code
- // checking whether the tested instance is a Smi.
- if (type.IsInstantiated()) {
- // A null object is only an instance of Object and Dynamic, which has
- // already been checked above (if the type is instantiated). So we can
- // return false here if the instance is null (and if the type is
- // instantiated).
- // We can only inline this null check if the type is instantiated at compile
- // time, since an uninstantiated type at compile time could be Object or
- // Dynamic at run time.
- __ cmpq(RAX, raw_null);
- __ j(EQUAL, &is_not_instance);
- }
-
- // Generate inline instanceof test.
- SubtypeTestCache& test_cache = SubtypeTestCache::ZoneHandle();
- test_cache = GenerateInlineInstanceof(cid, token_pos, type,
- &is_instance, &is_not_instance);
-
- // Generate runtime call.
- __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments.
- __ movq(RCX, Address(RSP, kWordSize)); // Get instantiator.
- __ PushObject(Object::ZoneHandle()); // Make room for the result.
- __ pushq(Immediate(Smi::RawValue(token_pos))); // Source location.
- __ pushq(Immediate(Smi::RawValue(cid))); // Computation id.
- __ pushq(RAX); // Push the instance.
- __ PushObject(type); // Push the type.
- __ pushq(RCX); // TODO(srdjan): Pass instantiator instead of null.
- __ pushq(RDX); // Instantiator type arguments.
- __ LoadObject(RAX, test_cache);
- __ pushq(RAX);
- GenerateCallRuntime(cid, token_pos, try_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.
- __ Drop(7);
- Label done;
- if (negate_result) {
- __ popq(RDX);
- __ LoadObject(RAX, bool_true());
- __ cmpq(RDX, RAX);
- __ j(NOT_EQUAL, &done, Assembler::kNearJump);
- __ LoadObject(RAX, bool_false());
- } else {
- __ popq(RAX);
- }
- __ jmp(&done, Assembler::kNearJump);
-
- __ Bind(&is_not_instance);
- __ LoadObject(RAX, negate_result ? bool_true() : bool_false());
- __ jmp(&done, Assembler::kNearJump);
-
- __ Bind(&is_instance);
- __ LoadObject(RAX, negate_result ? bool_false() : bool_true());
- __ Bind(&done);
- __ popq(RDX); // Remove pushed instantiator type arguments.
- __ popq(RCX); // Remove pushed instantiator.
-}
-
-
void FlowGraphCompiler::EmitInstructionPrologue(Instruction* instr) {
LocationSummary* locs = instr->locs();
ASSERT(locs != NULL);
@@ -641,7 +607,6 @@
}
-// Copied from CodeGenerator::CopyParameters (CodeGenerator will be deprecated).
void FlowGraphCompiler::CopyParameters() {
const Function& function = parsed_function().function();
const bool is_native_instance_closure =
@@ -676,6 +641,7 @@
// fp[1 + num_args - (num_pos_args - 1)].
__ subq(RBX, RCX);
__ leaq(RBX, Address(RBP, RBX, TIMES_4, 2 * kWordSize));
+
// Let RDI point to the last copied positional argument, i.e. to
// fp[ParsedFunction::kFirstLocalSlotIndex - (num_pos_args - 1)].
const int index =
@@ -905,8 +871,9 @@
void FlowGraphCompiler::CompileGraph() {
InitCompiler();
if (TryIntrinsify()) {
- // Make it patchable: code must have a minimum code size, nop(2) increases
- // the minimum code size appropriately.
+ // Although this intrinsified code will never be patched, it must satisfy
+ // CodePatcher::CodeIsPatchable, which verifies that this code has a minimum
+ // code size, and nop(2) increases the minimum code size appropriately.
__ nop(2);
__ int3();
__ jmp(&StubCode::FixCallersTargetLabel());
@@ -919,7 +886,6 @@
const int num_copied_params = parsed_function().copied_parameter_count();
const int local_count = parsed_function().stack_local_count();
AssemblerMacros::EnterDartFrame(assembler(), (StackSize() * kWordSize));
-
// We check the number of passed arguments when we have to copy them due to
// the presence of optional named parameters.
// No such checking code is generated if only fixed parameters are declared,
@@ -950,10 +916,11 @@
} else {
CopyParameters();
}
-
- // Initialize locals to null.
+ // Initialize (non-argument) stack allocated locals to null.
if (local_count > 0) {
- __ movq(RAX, Immediate(reinterpret_cast<intptr_t>(Object::null())));
+ const Immediate raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
+ __ movq(RAX, raw_null);
const int base = parsed_function().first_stack_local_index();
for (int i = 0; i < local_count; ++i) {
// Subtract index i (locals lie at lower addresses than RBP).
@@ -997,7 +964,6 @@
}
-// Infrastructure copied from class CodeGenerator.
void FlowGraphCompiler::GenerateCall(intptr_t token_pos,
intptr_t try_index,
const ExternalLabel* label,
@@ -1018,6 +984,32 @@
}
+intptr_t FlowGraphCompiler::EmitInstanceCall(ExternalLabel* target_label,
+ const ICData& ic_data,
+ const Array& arguments_descriptor,
+ intptr_t argument_count) {
+ __ LoadObject(RBX, ic_data);
+ __ LoadObject(R10, arguments_descriptor);
+
+ __ call(target_label);
+ const intptr_t descr_offset = assembler()->CodeSize();
+ __ Drop(argument_count);
+ return descr_offset;
+}
+
+
+intptr_t FlowGraphCompiler::EmitStaticCall(const Function& function,
+ const Array& arguments_descriptor,
+ intptr_t argument_count) {
+ __ LoadObject(RBX, function);
+ __ LoadObject(R10, arguments_descriptor);
+ __ call(&StubCode::CallStaticFunctionLabel());
+ const intptr_t descr_offset = assembler()->CodeSize();
+ __ Drop(argument_count);
+ return descr_offset;
+}
+
+
// Checks class id of instance against all 'class_ids'. Jump to 'deopt' label
// if no match or instance is Smi.
void FlowGraphCompiler::EmitClassChecksNoSmi(const ICData& ic_data,
« 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