| Index: src/ia32/lithium-codegen-ia32.cc
|
| ===================================================================
|
| --- src/ia32/lithium-codegen-ia32.cc (revision 7006)
|
| +++ src/ia32/lithium-codegen-ia32.cc (working copy)
|
| @@ -37,6 +37,8 @@
|
| namespace internal {
|
|
|
|
|
| +// When invoking builtins, we need to record the safepoint in the middle of
|
| +// the invoke instruction sequence generated by the macro assembler.
|
| class SafepointGenerator : public PostCallGenerator {
|
| public:
|
| SafepointGenerator(LCodeGen* codegen,
|
| @@ -75,7 +77,7 @@
|
| void LCodeGen::FinishCode(Handle<Code> code) {
|
| ASSERT(is_done());
|
| code->set_stack_slots(StackSlotCount());
|
| - code->set_safepoint_table_start(safepoints_.GetCodeOffset());
|
| + code->set_safepoint_table_offset(safepoints_.GetCodeOffset());
|
| PopulateDeoptimizationData(code);
|
| }
|
|
|
| @@ -366,17 +368,11 @@
|
| void LCodeGen::CallCode(Handle<Code> code,
|
| RelocInfo::Mode mode,
|
| LInstruction* instr) {
|
| - if (instr != NULL) {
|
| - LPointerMap* pointers = instr->pointer_map();
|
| - RecordPosition(pointers->position());
|
| - __ call(code, mode);
|
| - RegisterLazyDeoptimization(instr);
|
| - } else {
|
| - LPointerMap no_pointers(0);
|
| - RecordPosition(no_pointers.position());
|
| - __ call(code, mode);
|
| - RecordSafepoint(&no_pointers, Safepoint::kNoDeoptimizationIndex);
|
| - }
|
| + ASSERT(instr != NULL);
|
| + LPointerMap* pointers = instr->pointer_map();
|
| + RecordPosition(pointers->position());
|
| + __ call(code, mode);
|
| + RegisterLazyDeoptimization(instr);
|
|
|
| // Signal that we don't inline smi code before these stubs in the
|
| // optimizing code generator.
|
| @@ -391,22 +387,12 @@
|
| int num_arguments,
|
| LInstruction* instr) {
|
| ASSERT(instr != NULL);
|
| + ASSERT(instr->HasPointerMap());
|
| LPointerMap* pointers = instr->pointer_map();
|
| - ASSERT(pointers != NULL);
|
| RecordPosition(pointers->position());
|
|
|
| __ CallRuntime(function, num_arguments);
|
| - // Runtime calls to Throw are not supposed to ever return at the
|
| - // call site, so don't register lazy deoptimization for these. We do
|
| - // however have to record a safepoint since throwing exceptions can
|
| - // cause garbage collections.
|
| - // BUG(3243555): register a lazy deoptimization point at throw. We need
|
| - // it to be able to inline functions containing a throw statement.
|
| - if (!instr->IsThrow()) {
|
| - RegisterLazyDeoptimization(instr);
|
| - } else {
|
| - RecordSafepoint(instr->pointer_map(), Safepoint::kNoDeoptimizationIndex);
|
| - }
|
| + RegisterLazyDeoptimization(instr);
|
| }
|
|
|
|
|
| @@ -566,37 +552,40 @@
|
| }
|
|
|
|
|
| -void LCodeGen::RecordSafepoint(LPointerMap* pointers,
|
| - int deoptimization_index) {
|
| +void LCodeGen::RecordSafepoint(
|
| + LPointerMap* pointers,
|
| + Safepoint::Kind kind,
|
| + int arguments,
|
| + int deoptimization_index) {
|
| const ZoneList<LOperand*>* operands = pointers->operands();
|
| Safepoint safepoint = safepoints_.DefineSafepoint(masm(),
|
| - deoptimization_index);
|
| + kind, arguments, deoptimization_index);
|
| for (int i = 0; i < operands->length(); i++) {
|
| LOperand* pointer = operands->at(i);
|
| if (pointer->IsStackSlot()) {
|
| safepoint.DefinePointerSlot(pointer->index());
|
| + } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) {
|
| + safepoint.DefinePointerRegister(ToRegister(pointer));
|
| }
|
| }
|
| + if (kind & Safepoint::kWithRegisters) {
|
| + // Register esi always contains a pointer to the context.
|
| + safepoint.DefinePointerRegister(esi);
|
| + }
|
| }
|
|
|
|
|
| +void LCodeGen::RecordSafepoint(LPointerMap* pointers,
|
| + int deoptimization_index) {
|
| + RecordSafepoint(pointers, Safepoint::kSimple, 0, deoptimization_index);
|
| +}
|
| +
|
| +
|
| void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
|
| int arguments,
|
| int deoptimization_index) {
|
| - const ZoneList<LOperand*>* operands = pointers->operands();
|
| - Safepoint safepoint =
|
| - safepoints_.DefineSafepointWithRegisters(
|
| - masm(), arguments, deoptimization_index);
|
| - for (int i = 0; i < operands->length(); i++) {
|
| - LOperand* pointer = operands->at(i);
|
| - if (pointer->IsStackSlot()) {
|
| - safepoint.DefinePointerSlot(pointer->index());
|
| - } else if (pointer->IsRegister()) {
|
| - safepoint.DefinePointerRegister(ToRegister(pointer));
|
| - }
|
| - }
|
| - // Register esi always contains a pointer to the context.
|
| - safepoint.DefinePointerRegister(esi);
|
| + RecordSafepoint(pointers, Safepoint::kWithRegisters, arguments,
|
| + deoptimization_index);
|
| }
|
|
|
|
|
| @@ -815,7 +804,7 @@
|
| __ test(left, Operand(left));
|
| __ j(not_zero, &done);
|
| if (right->IsConstantOperand()) {
|
| - if (ToInteger32(LConstantOperand::cast(right)) < 0) {
|
| + if (ToInteger32(LConstantOperand::cast(right)) <= 0) {
|
| DeoptimizeIf(no_condition, instr->environment());
|
| }
|
| } else {
|
| @@ -956,19 +945,31 @@
|
| if (BitCast<uint64_t, double>(v) == 0) {
|
| __ xorpd(res, res);
|
| } else {
|
| - int32_t v_int32 = static_cast<int32_t>(v);
|
| - if (static_cast<double>(v_int32) == v) {
|
| - __ push_imm32(v_int32);
|
| - __ cvtsi2sd(res, Operand(esp, 0));
|
| - __ add(Operand(esp), Immediate(kPointerSize));
|
| + Register temp = ToRegister(instr->TempAt(0));
|
| + uint64_t int_val = BitCast<uint64_t, double>(v);
|
| + int32_t lower = static_cast<int32_t>(int_val);
|
| + int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
|
| + if (Isolate::Current()->cpu_features()->IsSupported(SSE4_1)) {
|
| + CpuFeatures::Scope scope(SSE4_1);
|
| + if (lower != 0) {
|
| + __ Set(temp, Immediate(lower));
|
| + __ movd(res, Operand(temp));
|
| + __ Set(temp, Immediate(upper));
|
| + __ pinsrd(res, Operand(temp), 1);
|
| + } else {
|
| + __ xorpd(res, res);
|
| + __ Set(temp, Immediate(upper));
|
| + __ pinsrd(res, Operand(temp), 1);
|
| + }
|
| } else {
|
| - uint64_t int_val = BitCast<uint64_t, double>(v);
|
| - int32_t lower = static_cast<int32_t>(int_val);
|
| - int32_t upper = static_cast<int32_t>(int_val >> (kBitsPerInt));
|
| - __ push_imm32(upper);
|
| - __ push_imm32(lower);
|
| - __ movdbl(res, Operand(esp, 0));
|
| - __ add(Operand(esp), Immediate(2 * kPointerSize));
|
| + __ Set(temp, Immediate(upper));
|
| + __ movd(res, Operand(temp));
|
| + __ psllq(res, 32);
|
| + if (lower != 0) {
|
| + __ Set(temp, Immediate(lower));
|
| + __ movd(xmm0, Operand(temp));
|
| + __ por(res, xmm0);
|
| + }
|
| }
|
| }
|
| }
|
| @@ -1892,7 +1893,7 @@
|
| }
|
| __ mov(esp, ebp);
|
| __ pop(ebp);
|
| - __ ret((ParameterCount() + 1) * kPointerSize);
|
| + __ Ret((ParameterCount() + 1) * kPointerSize, ecx);
|
| }
|
|
|
|
|
| @@ -1908,18 +1909,41 @@
|
|
|
| void LCodeGen::DoStoreGlobal(LStoreGlobal* instr) {
|
| Register value = ToRegister(instr->InputAt(0));
|
| - __ mov(Operand::Cell(instr->hydrogen()->cell()), value);
|
| + Operand cell_operand = Operand::Cell(instr->hydrogen()->cell());
|
| +
|
| + // If the cell we are storing to contains the hole it could have
|
| + // been deleted from the property dictionary. In that case, we need
|
| + // to update the property details in the property dictionary to mark
|
| + // it as no longer deleted. We deoptimize in that case.
|
| + if (instr->hydrogen()->check_hole_value()) {
|
| + __ cmp(cell_operand, FACTORY->the_hole_value());
|
| + DeoptimizeIf(equal, instr->environment());
|
| + }
|
| +
|
| + // Store the value.
|
| + __ mov(cell_operand, value);
|
| }
|
|
|
|
|
| void LCodeGen::DoLoadContextSlot(LLoadContextSlot* instr) {
|
| - // TODO(antonm): load a context with a separate instruction.
|
| + Register context = ToRegister(instr->context());
|
| Register result = ToRegister(instr->result());
|
| - __ LoadContext(result, instr->context_chain_length());
|
| - __ mov(result, ContextOperand(result, instr->slot_index()));
|
| + __ mov(result, ContextOperand(context, instr->slot_index()));
|
| }
|
|
|
|
|
| +void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
|
| + Register context = ToRegister(instr->context());
|
| + Register value = ToRegister(instr->value());
|
| + __ mov(ContextOperand(context, instr->slot_index()), value);
|
| + if (instr->needs_write_barrier()) {
|
| + Register temp = ToRegister(instr->TempAt(0));
|
| + int offset = Context::SlotOffset(instr->slot_index());
|
| + __ RecordWrite(context, offset, value, temp);
|
| + }
|
| +}
|
| +
|
| +
|
| void LCodeGen::DoLoadNamedField(LLoadNamedField* instr) {
|
| Register object = ToRegister(instr->InputAt(0));
|
| Register result = ToRegister(instr->result());
|
| @@ -2024,7 +2048,10 @@
|
| ASSERT(result.is(elements));
|
|
|
| // Load the result.
|
| - __ mov(result, FieldOperand(elements, key, times_4, FixedArray::kHeaderSize));
|
| + __ mov(result, FieldOperand(elements,
|
| + key,
|
| + times_pointer_size,
|
| + FixedArray::kHeaderSize));
|
|
|
| // Check for the hole value.
|
| __ cmp(result, FACTORY->the_hole_value());
|
| @@ -2132,12 +2159,20 @@
|
|
|
| // Invoke the function.
|
| __ bind(&invoke);
|
| + ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
|
| + LPointerMap* pointers = instr->pointer_map();
|
| + LEnvironment* env = instr->deoptimization_environment();
|
| + RecordPosition(pointers->position());
|
| + RegisterEnvironmentForDeoptimization(env);
|
| + SafepointGenerator safepoint_generator(this,
|
| + pointers,
|
| + env->deoptimization_index());
|
| ASSERT(receiver.is(eax));
|
| v8::internal::ParameterCount actual(eax);
|
| - SafepointGenerator safepoint_generator(this,
|
| - instr->pointer_map(),
|
| - Safepoint::kNoDeoptimizationIndex);
|
| __ InvokeFunction(edi, actual, CALL_FUNCTION, &safepoint_generator);
|
| +
|
| + // Restore context.
|
| + __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| }
|
|
|
|
|
| @@ -2151,16 +2186,31 @@
|
| }
|
|
|
|
|
| +void LCodeGen::DoContext(LContext* instr) {
|
| + Register result = ToRegister(instr->result());
|
| + __ mov(result, esi);
|
| +}
|
| +
|
| +
|
| +void LCodeGen::DoOuterContext(LOuterContext* instr) {
|
| + Register context = ToRegister(instr->context());
|
| + Register result = ToRegister(instr->result());
|
| + __ mov(result, Operand(context, Context::SlotOffset(Context::CLOSURE_INDEX)));
|
| + __ mov(result, FieldOperand(result, JSFunction::kContextOffset));
|
| +}
|
| +
|
| +
|
| void LCodeGen::DoGlobalObject(LGlobalObject* instr) {
|
| + Register context = ToRegister(instr->context());
|
| Register result = ToRegister(instr->result());
|
| - __ mov(result, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
|
| + __ mov(result, Operand(context, Context::SlotOffset(Context::GLOBAL_INDEX)));
|
| }
|
|
|
|
|
| void LCodeGen::DoGlobalReceiver(LGlobalReceiver* instr) {
|
| + Register global = ToRegister(instr->global());
|
| Register result = ToRegister(instr->result());
|
| - __ mov(result, Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)));
|
| - __ mov(result, FieldOperand(result, GlobalObject::kGlobalReceiverOffset));
|
| + __ mov(result, FieldOperand(global, GlobalObject::kGlobalReceiverOffset));
|
| }
|
|
|
|
|
| @@ -2384,6 +2434,8 @@
|
| __ movdbl(xmm_scratch, Operand::StaticVariable(negative_infinity));
|
| __ ucomisd(xmm_scratch, input_reg);
|
| DeoptimizeIf(equal, instr->environment());
|
| + __ xorpd(xmm_scratch, xmm_scratch);
|
| + __ addsd(input_reg, xmm_scratch); // Convert -0 to +0.
|
| __ sqrtsd(input_reg, input_reg);
|
| }
|
|
|
| @@ -2631,13 +2683,20 @@
|
| ToInteger32(const_operand) * kPointerSize + FixedArray::kHeaderSize;
|
| __ mov(FieldOperand(elements, offset), value);
|
| } else {
|
| - __ mov(FieldOperand(elements, key, times_4, FixedArray::kHeaderSize),
|
| + __ mov(FieldOperand(elements,
|
| + key,
|
| + times_pointer_size,
|
| + FixedArray::kHeaderSize),
|
| value);
|
| }
|
|
|
| if (instr->hydrogen()->NeedsWriteBarrier()) {
|
| // Compute address of modified element and store it into key register.
|
| - __ lea(key, FieldOperand(elements, key, times_4, FixedArray::kHeaderSize));
|
| + __ lea(key,
|
| + FieldOperand(elements,
|
| + key,
|
| + times_pointer_size,
|
| + FixedArray::kHeaderSize));
|
| __ RecordWrite(elements, key, value);
|
| }
|
| }
|
| @@ -3406,7 +3465,7 @@
|
| // Use the fast case closure allocation code that allocates in new
|
| // space for nested functions that don't need literals cloning.
|
| Handle<SharedFunctionInfo> shared_info = instr->shared_info();
|
| - bool pretenure = !instr->hydrogen()->pretenure();
|
| + bool pretenure = instr->hydrogen()->pretenure();
|
| if (shared_info->num_literals() == 0 && !pretenure) {
|
| FastNewClosureStub stub;
|
| __ push(Immediate(shared_info));
|
| @@ -3548,6 +3607,53 @@
|
| }
|
|
|
|
|
| +void LCodeGen::DoIsConstructCall(LIsConstructCall* instr) {
|
| + Register result = ToRegister(instr->result());
|
| + NearLabel true_label;
|
| + NearLabel false_label;
|
| + NearLabel done;
|
| +
|
| + EmitIsConstructCall(result);
|
| + __ j(equal, &true_label);
|
| +
|
| + __ mov(result, FACTORY->false_value());
|
| + __ jmp(&done);
|
| +
|
| + __ bind(&true_label);
|
| + __ mov(result, FACTORY->true_value());
|
| +
|
| + __ bind(&done);
|
| +}
|
| +
|
| +
|
| +void LCodeGen::DoIsConstructCallAndBranch(LIsConstructCallAndBranch* instr) {
|
| + Register temp = ToRegister(instr->TempAt(0));
|
| + int true_block = chunk_->LookupDestination(instr->true_block_id());
|
| + int false_block = chunk_->LookupDestination(instr->false_block_id());
|
| +
|
| + EmitIsConstructCall(temp);
|
| + EmitBranch(true_block, false_block, equal);
|
| +}
|
| +
|
| +
|
| +void LCodeGen::EmitIsConstructCall(Register temp) {
|
| + // Get the frame pointer for the calling frame.
|
| + __ mov(temp, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
|
| +
|
| + // Skip the arguments adaptor frame if it exists.
|
| + NearLabel check_frame_marker;
|
| + __ cmp(Operand(temp, StandardFrameConstants::kContextOffset),
|
| + Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
|
| + __ j(not_equal, &check_frame_marker);
|
| + __ mov(temp, Operand(temp, StandardFrameConstants::kCallerFPOffset));
|
| +
|
| + // Check the marker in the calling frame.
|
| + __ bind(&check_frame_marker);
|
| + __ cmp(Operand(temp, StandardFrameConstants::kMarkerOffset),
|
| + Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
|
| +}
|
| +
|
| +
|
| void LCodeGen::DoLazyBailout(LLazyBailout* instr) {
|
| // No code for lazy bailout instruction. Used to capture environment after a
|
| // call for populating the safepoint data with deoptimization data.
|
| @@ -3568,10 +3674,14 @@
|
| } else {
|
| __ push(ToOperand(key));
|
| }
|
| - RecordPosition(instr->pointer_map()->position());
|
| + ASSERT(instr->HasPointerMap() && instr->HasDeoptimizationEnvironment());
|
| + LPointerMap* pointers = instr->pointer_map();
|
| + LEnvironment* env = instr->deoptimization_environment();
|
| + RecordPosition(pointers->position());
|
| + RegisterEnvironmentForDeoptimization(env);
|
| SafepointGenerator safepoint_generator(this,
|
| - instr->pointer_map(),
|
| - Safepoint::kNoDeoptimizationIndex);
|
| + pointers,
|
| + env->deoptimization_index());
|
| __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, &safepoint_generator);
|
| }
|
|
|
|
|