Chromium Code Reviews| Index: runtime/vm/flow_graph_compiler_x64.cc |
| =================================================================== |
| --- runtime/vm/flow_graph_compiler_x64.cc (revision 26726) |
| +++ 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. |
| @@ -138,7 +138,6 @@ |
| return deopt_info.raw(); |
| } |
| - |
|
Florian Schneider
2013/09/04 09:39:47
Accidental change?
zra
2013/09/04 21:00:41
Done.
|
| void CompilerDeoptInfoWithStub::GenerateCode(FlowGraphCompiler* compiler, |
| intptr_t stub_ix) { |
| // Calls do not need stubs, they share a deoptimization trampoline. |
| @@ -151,7 +150,7 @@ |
| ASSERT(deopt_env() != NULL); |
| - __ call(&StubCode::DeoptimizeLabel()); |
| + __ CallFromPool(&StubCode::DeoptimizeLabel()); |
| set_pc_offset(assem->CodeSize()); |
| __ int3(); |
| #undef __ |
| @@ -165,10 +164,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(Object::null())); |
| __ j(EQUAL, &fall_through, Assembler::kNearJump); |
| __ CompareObject(bool_register, Bool::True()); |
| __ j(EQUAL, is_true); |
| @@ -187,22 +184,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); |
| + __ LoadObject(temp_reg, type_test_cache, Assembler::kNotPatchable); |
| __ 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(Object::null())); |
| + __ CallFromPool(&StubCode::Subtype1TestCacheLabel()); |
|
Florian Schneider
2013/09/04 09:39:47
Are there any direct calls to ExternalLabel left?
zra
2013/09/04 21:00:41
Yes, there is at least the call in RuntimeEntry::C
|
| } else if (test_kind == kTestTypeTwoArgs) { |
| ASSERT(type_arguments_reg == kNoRegister); |
| - __ pushq(raw_null); |
| - __ call(&StubCode::Subtype2TestCacheLabel()); |
| + __ PushObject(Object::Handle(Object::null())); |
| + __ CallFromPool(&StubCode::Subtype2TestCacheLabel()); |
| } else if (test_kind == kTestTypeThreeArgs) { |
| __ pushq(type_arguments_reg); |
| - __ call(&StubCode::Subtype3TestCacheLabel()); |
| + __ CallFromPool(&StubCode::Subtype3TestCacheLabel()); |
| } else { |
| UNREACHABLE(); |
| } |
| @@ -347,11 +342,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(Object::null())); |
| __ j(NOT_EQUAL, is_instance_lbl); |
| } |
| // Custom checking for numbers (Smi, Mint, Bigint and Double). |
| @@ -414,15 +407,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(Object::null())); |
| __ j(EQUAL, is_instance_lbl); |
| // Can handle only type arguments that are instances of TypeArguments. |
| // (runtime checks canonicalize type arguments). |
| @@ -435,7 +426,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(Object::null())); |
| __ j(EQUAL, is_instance_lbl); |
| const Type& object_type = Type::ZoneHandle(Type::ObjectType()); |
| __ CompareObject(RDI, object_type); |
| @@ -575,8 +566,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 +579,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(Object::null())); |
| __ j(EQUAL, &is_not_instance); |
| } |
| @@ -610,7 +599,7 @@ |
| __ PushObject(type); // Push the type. |
| __ pushq(RCX); // TODO(srdjan): Pass instantiator instead of null. |
| __ pushq(RDX); // Instantiator type arguments. |
| - __ LoadObject(RAX, test_cache); |
| + __ LoadObject(RAX, test_cache, Assembler::kNotPatchable); |
| __ pushq(RAX); |
| GenerateCallRuntime(token_pos, |
| deopt_id, |
| @@ -621,21 +610,23 @@ |
| __ Drop(5); |
| if (negate_result) { |
| __ popq(RDX); |
| - __ LoadObject(RAX, Bool::True()); |
| + __ LoadObject(RAX, Bool::True(), Assembler::kNotPatchable); |
| __ cmpq(RDX, RAX); |
| __ j(NOT_EQUAL, &done, Assembler::kNearJump); |
| - __ LoadObject(RAX, Bool::False()); |
| + __ LoadObject(RAX, Bool::False(), Assembler::kNotPatchable); |
| } else { |
| __ popq(RAX); |
| } |
| __ jmp(&done, Assembler::kNearJump); |
| } |
| __ Bind(&is_not_instance); |
| - __ LoadObject(RAX, negate_result ? Bool::True() : Bool::False()); |
| + __ LoadObject(RAX, negate_result ? Bool::True() : Bool::False(), |
| + Assembler::kNotPatchable); |
| __ jmp(&done, Assembler::kNearJump); |
| __ Bind(&is_instance); |
| - __ LoadObject(RAX, negate_result ? Bool::False() : Bool::True()); |
| + __ LoadObject(RAX, negate_result ? Bool::False() : Bool::True(), |
| + Assembler::kNotPatchable); |
| __ Bind(&done); |
| __ popq(RDX); // Remove pushed instantiator type arguments. |
| __ popq(RCX); // Remove pushed instantiator. |
| @@ -668,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(Object::null())); |
| __ j(EQUAL, &is_assignable); |
| if (!FLAG_eliminate_type_checks || dst_type.IsMalformed()) { |
| @@ -723,7 +712,7 @@ |
| __ pushq(RCX); // Instantiator. |
| __ pushq(RDX); // Instantiator type arguments. |
| __ PushObject(dst_name); // Push the name of the destination. |
| - __ LoadObject(RAX, test_cache); |
| + __ LoadObject(RAX, test_cache, Assembler::kNotPatchable); |
| __ pushq(RAX); |
| GenerateCallRuntime(token_pos, deopt_id, kTypeCheckRuntimeEntry, locs); |
| // Pop the parameters supplied to the runtime entry. The result of the |
| @@ -768,7 +757,7 @@ |
| __ pushq(RAX); |
| *push_emitted = true; |
| } |
| - __ LoadObject(RAX, loc.constant()); |
| + __ LoadObject(RAX, loc.constant(), Assembler::kNotPatchable); |
| __ movq(dest, RAX); |
| } else if (loc.IsRegister()) { |
| if (*push_emitted && loc.reg() == RAX) { |
| @@ -898,8 +887,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; |
| @@ -961,7 +948,7 @@ |
| const Object& value = Object::ZoneHandle( |
| parsed_function().default_parameter_values().At( |
| param_pos - num_fixed_params)); |
| - __ LoadObject(RAX, value); |
| + __ LoadObject(RAX, value, Assembler::kNotPatchable); |
| __ Bind(&assign_optional_parameter); |
| // Assign RAX to fp[kFirstLocalSlotFromFp - param_pos]. |
| // We do not use the final allocation index of the variable here, i.e. |
| @@ -976,7 +963,9 @@ |
| 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(Object::null()), |
| + Assembler::kNotPatchable); |
| + __ cmpq(Address(RDI, 0), TMP); |
| __ j(EQUAL, &all_arguments_processed, Assembler::kNearJump); |
| } |
| } else { |
| @@ -995,7 +984,7 @@ |
| // Load RAX with default argument. |
| const Object& value = Object::ZoneHandle( |
| parsed_function().default_parameter_values().At(i)); |
| - __ LoadObject(RAX, value); |
| + __ LoadObject(RAX, value, Assembler::kNotPatchable); |
| // Assign RAX to fp[kFirstLocalSlotFromFp - param_pos]. |
| // We do not use the final allocation index of the variable here, i.e. |
| // scope->VariableAt(i)->index(), because captured variables still need |
| @@ -1021,8 +1010,8 @@ |
| const ICData& ic_data = ICData::ZoneHandle( |
| ICData::New(function, Symbols::Call(), Object::empty_array(), |
| Isolate::kNoDeoptId, kNumArgsChecked)); |
| - __ LoadObject(RBX, ic_data); |
| - __ LeaveFrame(); // The arguments are still on the stack. |
| + __ LoadObject(RBX, ic_data, Assembler::kNotPatchable); |
| + __ LeaveFrame(true); // The arguments are still on the stack. |
| __ jmp(&StubCode::CallNoSuchMethodFunctionLabel()); |
| // The noSuchMethod call may return to the caller, but not here. |
| __ int3(); |
| @@ -1040,12 +1029,13 @@ |
| // R10 : arguments descriptor array. |
| __ movq(RCX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); |
| __ SmiUntag(RCX); |
| + __ LoadObject(R12, Object::Handle(Object::null()), Assembler::kNotPatchable); |
| 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); |
| @@ -1070,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(Object::null()), Assembler::kNotPatchable); |
| __ 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. |
| + __ LoadObject(function_reg, function, Assembler::kNotPatchable, new_pp); |
| + |
| // Patch point is after the eventually inlined function object. |
| AddCurrentDescriptor(PcDescriptors::kEntryPatch, |
| Isolate::kNoDeoptId, |
| @@ -1099,8 +1112,30 @@ |
| Immediate(FLAG_optimization_counter_threshold)); |
| } |
| ASSERT(function_reg == RDI); |
| - __ j(GREATER_EQUAL, &StubCode::OptimizeFunctionLabel()); |
| + __ JumpFromPool(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. |
| @@ -1111,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); |
| + __ EnterDartFrame(StackSize() * kWordSize, new_pp, new_pc); |
| } |
| } |
| @@ -1168,8 +1203,8 @@ |
| const ICData& ic_data = ICData::ZoneHandle( |
| ICData::New(function, name, Object::empty_array(), |
| Isolate::kNoDeoptId, kNumArgsChecked)); |
| - __ LoadObject(RBX, ic_data); |
| - __ LeaveFrame(); // The arguments are still on the stack. |
| + __ LoadObject(RBX, ic_data, Assembler::kNotPatchable); |
| + __ LeaveFrame(true); // The arguments are still on the stack. |
| __ jmp(&StubCode::CallNoSuchMethodFunctionLabel()); |
| // The noSuchMethod call may return to the caller, but not here. |
| __ int3(); |
| @@ -1187,9 +1222,8 @@ |
| 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(Object::null()), |
| + Assembler::kNotPatchable); |
| 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); |
| @@ -1216,11 +1250,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. |
| + __ JumpPatchable(&StubCode::FixCallersTargetLabel(), R13); |
| + |
| + // TOOD(zra): Is this descriptor used? |
| AddCurrentDescriptor(PcDescriptors::kLazyDeoptJump, |
| Isolate::kNoDeoptId, |
| 0); // No token position. |
| - __ jmp(&StubCode::DeoptimizeLazyLabel()); |
| + __ JumpFromPool(&StubCode::DeoptimizeLazyLabel()); |
| } |
| @@ -1228,7 +1266,7 @@ |
| const ExternalLabel* label, |
| PcDescriptors::Kind kind, |
| LocationSummary* locs) { |
| - __ call(label); |
| + __ CallFromPool(label); |
| AddCurrentDescriptor(kind, Isolate::kNoDeoptId, token_pos); |
| RecordSafepoint(locs); |
| } |
| @@ -1239,7 +1277,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 |
| @@ -1290,7 +1328,7 @@ |
| // top-level function (parsed_function().function()) which could be |
| // reoptimized and which counter needs to be incremented. |
| // Pass the function explicitly, it is used in IC stub. |
| - __ LoadObject(RDI, parsed_function().function()); |
| + __ LoadObject(RDI, parsed_function().function(), Assembler::kNotPatchable); |
| __ LoadObject(RBX, ic_data); |
| GenerateDartCall(deopt_id, |
| token_pos, |
| @@ -1343,7 +1381,7 @@ |
| // RAX: class ID of the receiver (smi). |
| __ Bind(&load_cache); |
| - __ LoadObject(RBX, cache); |
| + __ LoadObject(RBX, cache, Assembler::kNotPatchable); |
| __ movq(RDI, FieldAddress(RBX, MegamorphicCache::buckets_offset())); |
| __ movq(RBX, FieldAddress(RBX, MegamorphicCache::mask_offset())); |
| // RDI: cache buckets array. |
| @@ -1375,8 +1413,8 @@ |
| __ movq(RAX, FieldAddress(RDI, RCX, TIMES_8, base + kWordSize)); |
| __ movq(RAX, FieldAddress(RAX, Function::code_offset())); |
| __ movq(RAX, FieldAddress(RAX, Code::instructions_offset())); |
| - __ LoadObject(RBX, ic_data); |
| - __ LoadObject(R10, arguments_descriptor); |
| + __ LoadObject(RBX, ic_data, Assembler::kNotPatchable); |
| + __ LoadObject(R10, arguments_descriptor, Assembler::kNotPatchable); |
| __ addq(RAX, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); |
| __ call(RAX); |
| AddCurrentDescriptor(PcDescriptors::kOther, Isolate::kNoDeoptId, token_pos); |
| @@ -1393,7 +1431,7 @@ |
| intptr_t deopt_id, |
| intptr_t token_pos, |
| LocationSummary* locs) { |
| - __ LoadObject(R10, arguments_descriptor); |
| + __ LoadObject(R10, arguments_descriptor, Assembler::kNotPatchable); |
| // Do not use the code from the function, but let the code be patched so that |
| // we can record the outgoing edges to other code. |
| GenerateDartCall(deopt_id, |
| @@ -1426,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, |
| @@ -1450,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, |
| @@ -1470,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(Object::null()), Assembler::kNotPatchable); |
| 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); |
| @@ -1483,11 +1520,11 @@ |
| __ cmpq(result, Address(RSP, 0 * kWordSize)); |
| Label is_false; |
| __ j(NOT_EQUAL, &is_false, Assembler::kNearJump); |
| - __ LoadObject(result, Bool::True()); |
| + __ LoadObject(result, Bool::True(), Assembler::kNotPatchable); |
| __ Drop(1); |
| __ jmp(skip_call); |
| __ Bind(&is_false); |
| - __ LoadObject(result, Bool::False()); |
| + __ LoadObject(result, Bool::False(), Assembler::kNotPatchable); |
| __ Drop(1); |
| __ jmp(skip_call); |
| __ Bind(&fall_through); |
| @@ -1570,7 +1607,7 @@ |
| const Array& arguments_descriptor = |
| Array::ZoneHandle(ArgumentsDescriptor::New(argument_count, |
| argument_names)); |
| - __ LoadObject(R10, arguments_descriptor); |
| + __ LoadObject(R10, arguments_descriptor, Assembler::kNotPatchable); |
| for (intptr_t i = 0; i < len; i++) { |
| const bool is_last_check = (i == (len - 1)); |
| Label next_test; |
| @@ -1612,7 +1649,6 @@ |
| } |
| - |
| void FlowGraphCompiler::EmitDoubleCompareBool(Condition true_condition, |
| FpuRegister left, |
| FpuRegister right, |
| @@ -1622,10 +1658,10 @@ |
| assembler()->j(PARITY_EVEN, &is_false, Assembler::kNearJump); // NaN false; |
| assembler()->j(true_condition, &is_true, Assembler::kNearJump); |
| assembler()->Bind(&is_false); |
| - assembler()->LoadObject(result, Bool::False()); |
| + assembler()->LoadObject(result, Bool::False(), Assembler::kNotPatchable); |
| assembler()->jmp(&done); |
| assembler()->Bind(&is_true); |
| - assembler()->LoadObject(result, Bool::True()); |
| + assembler()->LoadObject(result, Bool::True(), Assembler::kNotPatchable); |
| assembler()->Bind(&done); |
| } |
| @@ -1746,7 +1782,7 @@ |
| if (constant.IsSmi() && (Smi::Cast(constant).Value() == 0)) { |
| __ xorq(destination.reg(), destination.reg()); |
| } else { |
| - __ LoadObject(destination.reg(), constant); |
| + __ LoadObject(destination.reg(), constant, Assembler::kNotPatchable); |
| } |
| } else { |
| ASSERT(destination.IsStackSlot()); |