| Index: runtime/vm/flow_graph_compiler_x64.cc
|
| ===================================================================
|
| --- runtime/vm/flow_graph_compiler_x64.cc (revision 27208)
|
| +++ runtime/vm/flow_graph_compiler_x64.cc (working copy)
|
| @@ -66,10 +66,9 @@
|
| // The real frame starts here.
|
| builder->MarkFrameStart();
|
|
|
| - // Callee's PC marker is not used anymore. Pass Function::null() to set to 0.
|
| + // Current PP, FP, and PC.
|
| + builder->AddPp(current->function(), slot_ix++);
|
| builder->AddPcMarker(Function::Handle(), slot_ix++);
|
| -
|
| - // Current FP and PC.
|
| builder->AddCallerFp(slot_ix++);
|
| builder->AddReturnAddress(current->function(), deopt_id(), slot_ix++);
|
|
|
| @@ -85,13 +84,14 @@
|
| builder->AddCopy(current->ValueAt(i), current->LocationAt(i), slot_ix++);
|
| }
|
|
|
| - // Current PC marker and caller FP.
|
| - builder->AddPcMarker(current->function(), slot_ix++);
|
| - builder->AddCallerFp(slot_ix++);
|
| -
|
| Environment* previous = current;
|
| current = current->outer();
|
| while (current != NULL) {
|
| + // PP, FP, and PC.
|
| + builder->AddPp(current->function(), slot_ix++);
|
| + builder->AddPcMarker(previous->function(), slot_ix++);
|
| + builder->AddCallerFp(slot_ix++);
|
| +
|
| // For any outer environment the deopt id is that of the call instruction
|
| // which is recorded in the outer environment.
|
| builder->AddReturnAddress(current->function(),
|
| @@ -115,10 +115,6 @@
|
| slot_ix++);
|
| }
|
|
|
| - // PC marker and caller FP.
|
| - builder->AddPcMarker(current->function(), slot_ix++);
|
| - builder->AddCallerFp(slot_ix++);
|
| -
|
| // Iterate on the outer environment.
|
| previous = current;
|
| current = current->outer();
|
| @@ -126,7 +122,11 @@
|
| // The previous pointer is now the outermost environment.
|
| ASSERT(previous != NULL);
|
|
|
| - // For the outermost environment, set caller PC.
|
| + // For the outermost environment, set caller PC, caller PP, and caller FP.
|
| + builder->AddCallerPp(slot_ix++);
|
| + // PC marker.
|
| + builder->AddPcMarker(previous->function(), slot_ix++);
|
| + builder->AddCallerFp(slot_ix++);
|
| builder->AddCallerPc(slot_ix++);
|
|
|
| // For the outermost environment, set the incoming arguments.
|
| @@ -151,7 +151,7 @@
|
|
|
| ASSERT(deopt_env() != NULL);
|
|
|
| - __ call(&StubCode::DeoptimizeLabel());
|
| + __ Call(&StubCode::DeoptimizeLabel(), PP);
|
| set_pc_offset(assem->CodeSize());
|
| __ int3();
|
| #undef __
|
| @@ -165,10 +165,8 @@
|
| 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);
|
| + __ CompareObject(bool_register, Object::Handle());
|
| __ j(EQUAL, &fall_through, Assembler::kNearJump);
|
| __ CompareObject(bool_register, Bool::True());
|
| __ j(EQUAL, is_true);
|
| @@ -187,22 +185,20 @@
|
| 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());
|
| + __ PushObject(Object::Handle());
|
| + __ Call(&StubCode::Subtype1TestCacheLabel(), PP);
|
| } else if (test_kind == kTestTypeTwoArgs) {
|
| ASSERT(type_arguments_reg == kNoRegister);
|
| - __ pushq(raw_null);
|
| - __ call(&StubCode::Subtype2TestCacheLabel());
|
| + __ PushObject(Object::Handle());
|
| + __ Call(&StubCode::Subtype2TestCacheLabel(), PP);
|
| } else if (test_kind == kTestTypeThreeArgs) {
|
| __ pushq(type_arguments_reg);
|
| - __ call(&StubCode::Subtype3TestCacheLabel());
|
| + __ Call(&StubCode::Subtype3TestCacheLabel(), PP);
|
| } else {
|
| UNREACHABLE();
|
| }
|
| @@ -347,11 +343,9 @@
|
| }
|
| if (type.IsFunctionType()) {
|
| // Check if instance is a closure.
|
| - const Immediate& raw_null =
|
| - Immediate(reinterpret_cast<intptr_t>(Object::null()));
|
| __ LoadClassById(R13, kClassIdReg);
|
| __ movq(R13, FieldAddress(R13, Class::signature_function_offset()));
|
| - __ cmpq(R13, raw_null);
|
| + __ CompareObject(R13, Object::Handle());
|
| __ j(NOT_EQUAL, is_instance_lbl);
|
| }
|
| // Custom checking for numbers (Smi, Mint, Bigint and Double).
|
| @@ -414,15 +408,13 @@
|
| __ Comment("UninstantiatedTypeTest");
|
| 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 TypeParameter& type_param = TypeParameter::Cast(type);
|
| // Load instantiator (or null) and instantiator type arguments on stack.
|
| __ movq(RDX, Address(RSP, 0)); // Get instantiator type arguments.
|
| // RDX: instantiator type arguments.
|
| // Check if type argument is dynamic.
|
| - __ cmpq(RDX, raw_null);
|
| + __ CompareObject(RDX, Object::Handle());
|
| __ j(EQUAL, is_instance_lbl);
|
| // Can handle only type arguments that are instances of TypeArguments.
|
| // (runtime checks canonicalize type arguments).
|
| @@ -435,7 +427,7 @@
|
| // Check if type argument is dynamic.
|
| __ CompareObject(RDI, Type::ZoneHandle(Type::DynamicType()));
|
| __ j(EQUAL, is_instance_lbl);
|
| - __ cmpq(RDI, raw_null);
|
| + __ CompareObject(RDI, Object::Handle());
|
| __ j(EQUAL, is_instance_lbl);
|
| const Type& object_type = Type::ZoneHandle(Type::ObjectType());
|
| __ CompareObject(RDI, object_type);
|
| @@ -575,8 +567,6 @@
|
| LocationSummary* locs) {
|
| ASSERT(type.IsFinalized() && !type.IsMalformed() && !type.IsMalbounded());
|
|
|
| - 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.
|
| @@ -590,7 +580,7 @@
|
| // 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);
|
| + __ CompareObject(RAX, Object::Handle());
|
| __ j(EQUAL, &is_not_instance);
|
| }
|
|
|
| @@ -669,10 +659,8 @@
|
| __ pushq(RCX); // Store instantiator.
|
| __ pushq(RDX); // Store instantiator type arguments.
|
| // A null object is always assignable and is returned as result.
|
| - const Immediate& raw_null =
|
| - Immediate(reinterpret_cast<intptr_t>(Object::null()));
|
| Label is_assignable, runtime_call;
|
| - __ cmpq(RAX, raw_null);
|
| + __ CompareObject(RAX, Object::Handle());
|
| __ j(EQUAL, &is_assignable);
|
|
|
| if (!FLAG_eliminate_type_checks || dst_type.IsMalformed()) {
|
| @@ -900,8 +888,6 @@
|
| __ j(POSITIVE, &loop, Assembler::kNearJump);
|
|
|
| // Copy or initialize optional named arguments.
|
| - const Immediate& raw_null =
|
| - Immediate(reinterpret_cast<intptr_t>(Object::null()));
|
| Label all_arguments_processed;
|
| #ifdef DEBUG
|
| const bool check_correct_named_args = true;
|
| @@ -978,7 +964,8 @@
|
| if (check_correct_named_args) {
|
| // Check that RDI now points to the null terminator in the arguments
|
| // descriptor.
|
| - __ cmpq(Address(RDI, 0), raw_null);
|
| + __ LoadObject(TMP, Object::Handle());
|
| + __ cmpq(Address(RDI, 0), TMP);
|
| __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump);
|
| }
|
| } else {
|
| @@ -1024,7 +1011,7 @@
|
| ICData::New(function, Symbols::Call(), Object::empty_array(),
|
| Isolate::kNoDeoptId, kNumArgsChecked));
|
| __ LoadObject(RBX, ic_data);
|
| - __ LeaveFrame(); // The arguments are still on the stack.
|
| + __ LeaveFrameWithPP(); // The arguments are still on the stack.
|
| __ jmp(&StubCode::CallNoSuchMethodFunctionLabel());
|
| // The noSuchMethod call may return to the caller, but not here.
|
| __ int3();
|
| @@ -1042,12 +1029,13 @@
|
| // R10 : arguments descriptor array.
|
| __ movq(RCX, FieldAddress(R10, ArgumentsDescriptor::count_offset()));
|
| __ SmiUntag(RCX);
|
| + __ LoadObject(R12, Object::Handle());
|
| Label null_args_loop, null_args_loop_condition;
|
| __ jmp(&null_args_loop_condition, Assembler::kNearJump);
|
| const Address original_argument_addr(
|
| RBP, RCX, TIMES_8, (kParamEndSlotFromFp + 1) * kWordSize);
|
| __ Bind(&null_args_loop);
|
| - __ movq(original_argument_addr, raw_null);
|
| + __ movq(original_argument_addr, R12);
|
| __ Bind(&null_args_loop_condition);
|
| __ decq(RCX);
|
| __ j(POSITIVE, &null_args_loop, Assembler::kNearJump);
|
| @@ -1072,20 +1060,43 @@
|
| __ movq(RAX, Address(RSP, 2 * kWordSize)); // Receiver.
|
| __ movq(RBX, Address(RSP, 1 * kWordSize)); // Value.
|
| __ StoreIntoObject(RAX, FieldAddress(RAX, offset), RBX);
|
| - const Immediate& raw_null =
|
| - Immediate(reinterpret_cast<intptr_t>(Object::null()));
|
| - __ movq(RAX, raw_null);
|
| + __ LoadObject(RAX, Object::Handle());
|
| __ ret();
|
| }
|
|
|
|
|
| void FlowGraphCompiler::EmitFrameEntry() {
|
| const Function& function = parsed_function().function();
|
| + Register new_pp = kNoRegister;
|
| + Register new_pc = kNoRegister;
|
| if (CanOptimizeFunction() &&
|
| function.is_optimizable() &&
|
| (!is_optimizing() || may_reoptimize())) {
|
| const Register function_reg = RDI;
|
| - __ LoadObject(function_reg, function);
|
| + new_pp = R13;
|
| + new_pc = R12;
|
| +
|
| + Label next;
|
| + __ nop(4); // Need a fixed size sequence on frame entry.
|
| + __ call(&next);
|
| + __ Bind(&next);
|
| +
|
| + const intptr_t object_pool_pc_dist =
|
| + Instructions::HeaderSize() - Instructions::object_pool_offset() +
|
| + __ CodeSize();
|
| + const intptr_t offset =
|
| + Assembler::kEntryPointToPcMarkerOffset - __ CodeSize();
|
| + __ popq(new_pc);
|
| + if (offset != 0) {
|
| + __ addq(new_pc, Immediate(offset));
|
| + }
|
| +
|
| + // Load callee's pool pointer.
|
| + __ movq(new_pp, Address(new_pc, -object_pool_pc_dist - offset));
|
| +
|
| + // Load function object using the callee's pool pointer.
|
| + __ LoadObjectFromPool(function_reg, function, new_pp);
|
| +
|
| // Patch point is after the eventually inlined function object.
|
| AddCurrentDescriptor(PcDescriptors::kEntryPatch,
|
| Isolate::kNoDeoptId,
|
| @@ -1101,8 +1112,30 @@
|
| Immediate(FLAG_optimization_counter_threshold));
|
| }
|
| ASSERT(function_reg == RDI);
|
| - __ j(GREATER_EQUAL, &StubCode::OptimizeFunctionLabel());
|
| + __ J(GREATER_EQUAL, &StubCode::OptimizeFunctionLabel(), R13);
|
| } else if (!flow_graph().IsCompiledForOsr()) {
|
| + // We have to load the PP here too because a load of an external label
|
| + // may be patched at the AddCurrentDescriptor below.
|
| + new_pp = R13;
|
| + new_pc = R12;
|
| +
|
| + Label next;
|
| + __ nop(4); // Need a fixed size sequence on frame entry.
|
| + __ call(&next);
|
| + __ Bind(&next);
|
| +
|
| + const intptr_t object_pool_pc_dist =
|
| + Instructions::HeaderSize() - Instructions::object_pool_offset() +
|
| + __ CodeSize();
|
| + const intptr_t offset =
|
| + Assembler::kEntryPointToPcMarkerOffset - __ CodeSize();
|
| + __ popq(new_pc);
|
| + if (offset != 0) {
|
| + __ addq(new_pc, Immediate(offset));
|
| + }
|
| +
|
| + // Load callee's pool pointer.
|
| + __ movq(new_pp, Address(new_pc, -object_pool_pc_dist - offset));
|
| AddCurrentDescriptor(PcDescriptors::kEntryPatch,
|
| Isolate::kNoDeoptId,
|
| 0); // No token position.
|
| @@ -1113,10 +1146,10 @@
|
| - flow_graph().num_stack_locals()
|
| - flow_graph().num_copied_params();
|
| ASSERT(extra_slots >= 0);
|
| - __ EnterOsrFrame(extra_slots * kWordSize);
|
| + __ EnterOsrFrame(extra_slots * kWordSize, new_pp, new_pc);
|
| } else {
|
| ASSERT(StackSize() >= 0);
|
| - __ EnterDartFrame(StackSize() * kWordSize);
|
| + __ EnterDartFrameWithInfo(StackSize() * kWordSize, new_pp, new_pc);
|
| }
|
| }
|
|
|
| @@ -1171,7 +1204,7 @@
|
| ICData::New(function, name, Object::empty_array(),
|
| Isolate::kNoDeoptId, kNumArgsChecked));
|
| __ LoadObject(RBX, ic_data);
|
| - __ LeaveFrame(); // The arguments are still on the stack.
|
| + __ LeaveFrameWithPP(); // The arguments are still on the stack.
|
| __ jmp(&StubCode::CallNoSuchMethodFunctionLabel());
|
| // The noSuchMethod call may return to the caller, but not here.
|
| __ int3();
|
| @@ -1189,9 +1222,7 @@
|
| if (!is_optimizing() && (num_locals > 0)) {
|
| __ Comment("Initialize spill slots");
|
| const intptr_t slot_base = parsed_function().first_stack_local_index();
|
| - const Immediate& raw_null =
|
| - Immediate(reinterpret_cast<intptr_t>(Object::null()));
|
| - __ movq(RAX, raw_null);
|
| + __ LoadObject(RAX, Object::Handle());
|
| for (intptr_t i = 0; i < num_locals; ++i) {
|
| // Subtract index i (locals lie at lower addresses than RBP).
|
| __ movq(Address(RBP, (slot_base - i) * kWordSize), RAX);
|
| @@ -1218,11 +1249,15 @@
|
| AddCurrentDescriptor(PcDescriptors::kPatchCode,
|
| Isolate::kNoDeoptId,
|
| 0); // No token position.
|
| - __ jmp(&StubCode::FixCallersTargetLabel());
|
| + // This is patched up to a point in FrameEntry where the PP for the
|
| + // current function is in R13 instead of PP.
|
| + __ JmpPatchable(&StubCode::FixCallersTargetLabel(), R13);
|
| +
|
| + // TOOD(zra): Is this descriptor used?
|
| AddCurrentDescriptor(PcDescriptors::kLazyDeoptJump,
|
| Isolate::kNoDeoptId,
|
| 0); // No token position.
|
| - __ jmp(&StubCode::DeoptimizeLazyLabel());
|
| + __ Jmp(&StubCode::DeoptimizeLazyLabel(), PP);
|
| }
|
|
|
|
|
| @@ -1230,7 +1265,7 @@
|
| const ExternalLabel* label,
|
| PcDescriptors::Kind kind,
|
| LocationSummary* locs) {
|
| - __ call(label);
|
| + __ Call(label, PP);
|
| AddCurrentDescriptor(kind, Isolate::kNoDeoptId, token_pos);
|
| RecordSafepoint(locs);
|
| }
|
| @@ -1241,7 +1276,7 @@
|
| const ExternalLabel* label,
|
| PcDescriptors::Kind kind,
|
| LocationSummary* locs) {
|
| - __ call(label);
|
| + __ CallPatchable(label);
|
| AddCurrentDescriptor(kind, deopt_id, token_pos);
|
| RecordSafepoint(locs);
|
| // Marks either the continuation point in unoptimized code or the
|
| @@ -1429,9 +1464,9 @@
|
| __ pushq(reg);
|
| __ PushObject(obj);
|
| if (is_optimizing()) {
|
| - __ call(&StubCode::OptimizedIdenticalWithNumberCheckLabel());
|
| + __ CallPatchable(&StubCode::OptimizedIdenticalWithNumberCheckLabel());
|
| } else {
|
| - __ call(&StubCode::UnoptimizedIdenticalWithNumberCheckLabel());
|
| + __ CallPatchable(&StubCode::UnoptimizedIdenticalWithNumberCheckLabel());
|
| }
|
| AddCurrentDescriptor(PcDescriptors::kRuntimeCall,
|
| Isolate::kNoDeoptId,
|
| @@ -1453,9 +1488,9 @@
|
| __ pushq(left);
|
| __ pushq(right);
|
| if (is_optimizing()) {
|
| - __ call(&StubCode::OptimizedIdenticalWithNumberCheckLabel());
|
| + __ CallPatchable(&StubCode::OptimizedIdenticalWithNumberCheckLabel());
|
| } else {
|
| - __ call(&StubCode::UnoptimizedIdenticalWithNumberCheckLabel());
|
| + __ CallPatchable(&StubCode::UnoptimizedIdenticalWithNumberCheckLabel());
|
| }
|
| AddCurrentDescriptor(PcDescriptors::kRuntimeCall,
|
| Isolate::kNoDeoptId,
|
| @@ -1473,12 +1508,11 @@
|
| // Fallthrough calls super equality.
|
| void FlowGraphCompiler::EmitSuperEqualityCallPrologue(Register result,
|
| Label* skip_call) {
|
| - const Immediate& raw_null =
|
| - Immediate(reinterpret_cast<intptr_t>(Object::null()));
|
| + __ LoadObject(TMP, Object::Handle());
|
| Label check_identity, fall_through;
|
| - __ cmpq(Address(RSP, 0 * kWordSize), raw_null);
|
| + __ cmpq(Address(RSP, 0 * kWordSize), TMP);
|
| __ j(EQUAL, &check_identity, Assembler::kNearJump);
|
| - __ cmpq(Address(RSP, 1 * kWordSize), raw_null);
|
| + __ cmpq(Address(RSP, 1 * kWordSize), TMP);
|
| __ j(NOT_EQUAL, &fall_through, Assembler::kNearJump);
|
|
|
| __ Bind(&check_identity);
|
| @@ -1615,7 +1649,6 @@
|
| }
|
|
|
|
|
| -
|
| void FlowGraphCompiler::EmitDoubleCompareBool(Condition true_condition,
|
| FpuRegister left,
|
| FpuRegister right,
|
|
|