| Index: src/ia32/lithium-codegen-ia32.cc
|
| ===================================================================
|
| --- src/ia32/lithium-codegen-ia32.cc (revision 7031)
|
| +++ src/ia32/lithium-codegen-ia32.cc (working copy)
|
| @@ -43,13 +43,20 @@
|
| public:
|
| SafepointGenerator(LCodeGen* codegen,
|
| LPointerMap* pointers,
|
| - int deoptimization_index)
|
| + int deoptimization_index,
|
| + bool ensure_reloc_space = false)
|
| : codegen_(codegen),
|
| pointers_(pointers),
|
| - deoptimization_index_(deoptimization_index) { }
|
| + deoptimization_index_(deoptimization_index),
|
| + ensure_reloc_space_(ensure_reloc_space) { }
|
| virtual ~SafepointGenerator() { }
|
|
|
| virtual void Generate() {
|
| + // Ensure that we have enough space in the reloc info to patch
|
| + // this with calls when doing deoptimization.
|
| + if (ensure_reloc_space_) {
|
| + codegen_->EnsureRelocSpaceForDeoptimization();
|
| + }
|
| codegen_->RecordSafepoint(pointers_, deoptimization_index_);
|
| }
|
|
|
| @@ -57,6 +64,7 @@
|
| LCodeGen* codegen_;
|
| LPointerMap* pointers_;
|
| int deoptimization_index_;
|
| + bool ensure_reloc_space_;
|
| };
|
|
|
|
|
| @@ -70,6 +78,7 @@
|
| return GeneratePrologue() &&
|
| GenerateBody() &&
|
| GenerateDeferredCode() &&
|
| + GenerateRelocPadding() &&
|
| GenerateSafepointTable();
|
| }
|
|
|
| @@ -114,6 +123,16 @@
|
| }
|
|
|
|
|
| +bool LCodeGen::GenerateRelocPadding() {
|
| + int reloc_size = masm()->relocation_writer_size();
|
| + while (reloc_size < deoptimization_reloc_size.min_size) {
|
| + __ RecordComment(RelocInfo::kFillerCommentString, true);
|
| + reloc_size += RelocInfo::kMinRelocCommentSize;
|
| + }
|
| + return !is_aborted();
|
| +}
|
| +
|
| +
|
| bool LCodeGen::GeneratePrologue() {
|
| ASSERT(is_generating());
|
|
|
| @@ -155,8 +174,49 @@
|
| }
|
| }
|
|
|
| + // Possibly allocate a local context.
|
| + int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
|
| + if (heap_slots > 0) {
|
| + Comment(";;; Allocate local context");
|
| + // Argument to NewContext is the function, which is still in edi.
|
| + __ push(edi);
|
| + if (heap_slots <= FastNewContextStub::kMaximumSlots) {
|
| + FastNewContextStub stub(heap_slots);
|
| + __ CallStub(&stub);
|
| + } else {
|
| + __ CallRuntime(Runtime::kNewContext, 1);
|
| + }
|
| + RecordSafepoint(Safepoint::kNoDeoptimizationIndex);
|
| + // Context is returned in both eax and esi. It replaces the context
|
| + // passed to us. It's saved in the stack and kept live in esi.
|
| + __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
|
| +
|
| + // Copy parameters into context if necessary.
|
| + int num_parameters = scope()->num_parameters();
|
| + for (int i = 0; i < num_parameters; i++) {
|
| + Slot* slot = scope()->parameter(i)->AsSlot();
|
| + if (slot != NULL && slot->type() == Slot::CONTEXT) {
|
| + int parameter_offset = StandardFrameConstants::kCallerSPOffset +
|
| + (num_parameters - 1 - i) * kPointerSize;
|
| + // Load parameter from stack.
|
| + __ mov(eax, Operand(ebp, parameter_offset));
|
| + // Store it in the context.
|
| + int context_offset = Context::SlotOffset(slot->index());
|
| + __ mov(Operand(esi, context_offset), eax);
|
| + // Update the write barrier. This clobbers all involved
|
| + // registers, so we have to use a third register to avoid
|
| + // clobbering esi.
|
| + __ mov(ecx, esi);
|
| + __ RecordWrite(ecx, context_offset, eax, ebx);
|
| + }
|
| + }
|
| + Comment(";;; End allocate local context");
|
| + }
|
| +
|
| // Trace the call.
|
| if (FLAG_trace) {
|
| + // We have not executed any compiled code yet, so esi still holds the
|
| + // incoming context.
|
| __ CallRuntime(Runtime::kTraceEnter, 0);
|
| }
|
| return !is_aborted();
|
| @@ -325,6 +385,22 @@
|
| }
|
|
|
|
|
| +void LCodeGen::EnsureRelocSpaceForDeoptimization() {
|
| + // Since we patch the reloc info with RUNTIME_ENTRY calls every patch
|
| + // site will take up 2 bytes + any pc-jumps.
|
| + // We are conservative and always reserver 6 bytes in case where a
|
| + // simple pc-jump is not enough.
|
| + uint32_t pc_delta =
|
| + masm()->pc_offset() - deoptimization_reloc_size.last_pc_offset;
|
| + if (is_uintn(pc_delta, 6)) {
|
| + deoptimization_reloc_size.min_size += 2;
|
| + } else {
|
| + deoptimization_reloc_size.min_size += 6;
|
| + }
|
| + deoptimization_reloc_size.last_pc_offset = masm()->pc_offset();
|
| +}
|
| +
|
| +
|
| void LCodeGen::AddToTranslation(Translation* translation,
|
| LOperand* op,
|
| bool is_tagged) {
|
| @@ -367,11 +443,18 @@
|
|
|
| void LCodeGen::CallCode(Handle<Code> code,
|
| RelocInfo::Mode mode,
|
| - LInstruction* instr) {
|
| + LInstruction* instr,
|
| + bool adjusted) {
|
| ASSERT(instr != NULL);
|
| LPointerMap* pointers = instr->pointer_map();
|
| RecordPosition(pointers->position());
|
| +
|
| + if (!adjusted) {
|
| + __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| + }
|
| __ call(code, mode);
|
| +
|
| + EnsureRelocSpaceForDeoptimization();
|
| RegisterLazyDeoptimization(instr);
|
|
|
| // Signal that we don't inline smi code before these stubs in the
|
| @@ -383,15 +466,19 @@
|
| }
|
|
|
|
|
| -void LCodeGen::CallRuntime(const Runtime::Function* function,
|
| - int num_arguments,
|
| - LInstruction* instr) {
|
| +void LCodeGen::CallRuntime(const Runtime::Function* fun,
|
| + int argc,
|
| + LInstruction* instr,
|
| + bool adjusted) {
|
| ASSERT(instr != NULL);
|
| ASSERT(instr->HasPointerMap());
|
| LPointerMap* pointers = instr->pointer_map();
|
| RecordPosition(pointers->position());
|
|
|
| - __ CallRuntime(function, num_arguments);
|
| + if (!adjusted) {
|
| + __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| + }
|
| + __ CallRuntime(fun, argc);
|
| RegisterLazyDeoptimization(instr);
|
| }
|
|
|
| @@ -501,7 +588,8 @@
|
| Handle<DeoptimizationInputData> data =
|
| FACTORY->NewDeoptimizationInputData(length, TENURED);
|
|
|
| - data->SetTranslationByteArray(*translations_.CreateByteArray());
|
| + Handle<ByteArray> translations = translations_.CreateByteArray();
|
| + data->SetTranslationByteArray(*translations);
|
| data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
|
|
|
| Handle<FixedArray> literals =
|
| @@ -568,10 +656,6 @@
|
| safepoint.DefinePointerRegister(ToRegister(pointer));
|
| }
|
| }
|
| - if (kind & Safepoint::kWithRegisters) {
|
| - // Register esi always contains a pointer to the context.
|
| - safepoint.DefinePointerRegister(esi);
|
| - }
|
| }
|
|
|
|
|
| @@ -581,6 +665,12 @@
|
| }
|
|
|
|
|
| +void LCodeGen::RecordSafepoint(int deoptimization_index) {
|
| + LPointerMap empty_pointers(RelocInfo::kNoPosition);
|
| + RecordSafepoint(&empty_pointers, deoptimization_index);
|
| +}
|
| +
|
| +
|
| void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
|
| int arguments,
|
| int deoptimization_index) {
|
| @@ -635,6 +725,7 @@
|
|
|
|
|
| void LCodeGen::DoCallStub(LCallStub* instr) {
|
| + ASSERT(ToRegister(instr->context()).is(esi));
|
| ASSERT(ToRegister(instr->result()).is(eax));
|
| switch (instr->hydrogen()->major_key()) {
|
| case CodeStub::RegExpConstructResult: {
|
| @@ -995,6 +1086,13 @@
|
| }
|
|
|
|
|
| +void LCodeGen::DoPixelArrayLength(LPixelArrayLength* instr) {
|
| + Register result = ToRegister(instr->result());
|
| + Register array = ToRegister(instr->InputAt(0));
|
| + __ mov(result, FieldOperand(array, PixelArray::kLengthOffset));
|
| +}
|
| +
|
| +
|
| void LCodeGen::DoValueOf(LValueOf* instr) {
|
| Register input = ToRegister(instr->InputAt(0));
|
| Register result = ToRegister(instr->result());
|
| @@ -1023,7 +1121,7 @@
|
|
|
| void LCodeGen::DoThrow(LThrow* instr) {
|
| __ push(ToOperand(instr->InputAt(0)));
|
| - CallRuntime(Runtime::kThrow, 1, instr);
|
| + CallRuntime(Runtime::kThrow, 1, instr, false);
|
|
|
| if (FLAG_debug_code) {
|
| Comment("Unreachable code.");
|
| @@ -1050,35 +1148,36 @@
|
|
|
|
|
| void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
|
| - LOperand* left = instr->InputAt(0);
|
| - LOperand* right = instr->InputAt(1);
|
| + XMMRegister left = ToDoubleRegister(instr->InputAt(0));
|
| + XMMRegister right = ToDoubleRegister(instr->InputAt(1));
|
| + XMMRegister result = ToDoubleRegister(instr->result());
|
| // Modulo uses a fixed result register.
|
| - ASSERT(instr->op() == Token::MOD || left->Equals(instr->result()));
|
| + ASSERT(instr->op() == Token::MOD || left.is(result));
|
| switch (instr->op()) {
|
| case Token::ADD:
|
| - __ addsd(ToDoubleRegister(left), ToDoubleRegister(right));
|
| + __ addsd(left, right);
|
| break;
|
| case Token::SUB:
|
| - __ subsd(ToDoubleRegister(left), ToDoubleRegister(right));
|
| + __ subsd(left, right);
|
| break;
|
| case Token::MUL:
|
| - __ mulsd(ToDoubleRegister(left), ToDoubleRegister(right));
|
| + __ mulsd(left, right);
|
| break;
|
| case Token::DIV:
|
| - __ divsd(ToDoubleRegister(left), ToDoubleRegister(right));
|
| + __ divsd(left, right);
|
| break;
|
| case Token::MOD: {
|
| // Pass two doubles as arguments on the stack.
|
| __ PrepareCallCFunction(4, eax);
|
| - __ movdbl(Operand(esp, 0 * kDoubleSize), ToDoubleRegister(left));
|
| - __ movdbl(Operand(esp, 1 * kDoubleSize), ToDoubleRegister(right));
|
| + __ movdbl(Operand(esp, 0 * kDoubleSize), left);
|
| + __ movdbl(Operand(esp, 1 * kDoubleSize), right);
|
| __ CallCFunction(ExternalReference::double_fp_operation(Token::MOD), 4);
|
|
|
| // Return value is in st(0) on ia32.
|
| // Store it into the (fixed) result register.
|
| __ sub(Operand(esp), Immediate(kDoubleSize));
|
| __ fstp_d(Operand(esp, 0));
|
| - __ movdbl(ToDoubleRegister(instr->result()), Operand(esp, 0));
|
| + __ movdbl(result, Operand(esp, 0));
|
| __ add(Operand(esp), Immediate(kDoubleSize));
|
| break;
|
| }
|
| @@ -1095,7 +1194,7 @@
|
| ASSERT(ToRegister(instr->result()).is(eax));
|
|
|
| TypeRecordingBinaryOpStub stub(instr->op(), NO_OVERWRITE);
|
| - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
|
| }
|
|
|
|
|
| @@ -1208,6 +1307,7 @@
|
|
|
| void LCodeGen::DoDeferredStackCheck(LGoto* instr) {
|
| __ pushad();
|
| + __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
|
| RecordSafepointWithRegisters(
|
| instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
|
| @@ -1698,6 +1798,7 @@
|
|
|
| void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
|
| // Object and function are in fixed registers defined by the stub.
|
| + ASSERT(ToRegister(instr->context()).is(esi));
|
| InstanceofStub stub(InstanceofStub::kArgsInRegisters);
|
| CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
|
|
| @@ -1713,6 +1814,7 @@
|
|
|
|
|
| void LCodeGen::DoInstanceOfAndBranch(LInstanceOfAndBranch* instr) {
|
| + ASSERT(ToRegister(instr->context()).is(esi));
|
| int true_block = chunk_->LookupDestination(instr->true_block_id());
|
| int false_block = chunk_->LookupDestination(instr->false_block_id());
|
|
|
| @@ -1747,11 +1849,11 @@
|
| Register object = ToRegister(instr->InputAt(0));
|
| Register temp = ToRegister(instr->TempAt(0));
|
|
|
| - // A Smi is not instance of anything.
|
| + // A Smi is not an instance of anything.
|
| __ test(object, Immediate(kSmiTagMask));
|
| __ j(zero, &false_result, not_taken);
|
|
|
| - // This is the inlined call site instanceof cache. The two occourences of the
|
| + // This is the inlined call site instanceof cache. The two occurences of the
|
| // hole value will be patched to the last map/result pair generated by the
|
| // instanceof stub.
|
| NearLabel cache_miss;
|
| @@ -1763,10 +1865,10 @@
|
| __ mov(eax, FACTORY->the_hole_value()); // Patched to either true or false.
|
| __ jmp(&done);
|
|
|
| - // The inlined call site cache did not match. Check null and string before
|
| - // calling the deferred code.
|
| + // The inlined call site cache did not match. Check for null and string
|
| + // before calling the deferred code.
|
| __ bind(&cache_miss);
|
| - // Null is not instance of anything.
|
| + // Null is not an instance of anything.
|
| __ cmp(object, FACTORY->null_value());
|
| __ j(equal, &false_result);
|
|
|
| @@ -1806,20 +1908,15 @@
|
| Register temp = ToRegister(instr->TempAt(0));
|
| ASSERT(temp.is(edi));
|
| __ mov(InstanceofStub::right(), Immediate(instr->function()));
|
| - static const int kAdditionalDelta = 13;
|
| + static const int kAdditionalDelta = 16;
|
| int delta = masm_->SizeOfCodeGeneratedSince(map_check) + kAdditionalDelta;
|
| Label before_push_delta;
|
| __ bind(&before_push_delta);
|
| __ mov(temp, Immediate(delta));
|
| - __ mov(Operand(esp, EspIndexForPushAll(temp) * kPointerSize), temp);
|
| - __ call(stub.GetCode(), RelocInfo::CODE_TARGET);
|
| - ASSERT_EQ(kAdditionalDelta,
|
| - masm_->SizeOfCodeGeneratedSince(&before_push_delta));
|
| - RecordSafepointWithRegisters(
|
| - instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
|
| + __ StoreToSafepointRegisterSlot(temp, temp);
|
| + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
|
| // Put the result value into the eax slot and restore all registers.
|
| - __ mov(Operand(esp, EspIndexForPushAll(eax) * kPointerSize), eax);
|
| -
|
| + __ StoreToSafepointRegisterSlot(eax, eax);
|
| __ PopSafepointRegisters();
|
| }
|
|
|
| @@ -1848,7 +1945,7 @@
|
| Token::Value op = instr->op();
|
|
|
| Handle<Code> ic = CompareIC::GetUninitialized(op);
|
| - CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
| + CallCode(ic, RelocInfo::CODE_TARGET, instr, false);
|
|
|
| Condition condition = ComputeCompareCondition(op);
|
| if (op == Token::GT || op == Token::LTE) {
|
| @@ -1871,7 +1968,7 @@
|
| int false_block = chunk_->LookupDestination(instr->false_block_id());
|
|
|
| Handle<Code> ic = CompareIC::GetUninitialized(op);
|
| - CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
| + CallCode(ic, RelocInfo::CODE_TARGET, instr, false);
|
|
|
| // The compare stub expects compare condition and the input operands
|
| // reversed for GT and LTE.
|
| @@ -1886,9 +1983,12 @@
|
|
|
| void LCodeGen::DoReturn(LReturn* instr) {
|
| if (FLAG_trace) {
|
| - // Preserve the return value on the stack and rely on the runtime
|
| - // call to return the value in the same register.
|
| + // Preserve the return value on the stack and rely on the runtime call
|
| + // to return the value in the same register. We're leaving the code
|
| + // managed by the register allocator and tearing down the frame, it's
|
| + // safe to write to the context register.
|
| __ push(eax);
|
| + __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| __ CallRuntime(Runtime::kTraceExit, 1);
|
| }
|
| __ mov(esp, ebp);
|
| @@ -1957,6 +2057,7 @@
|
|
|
|
|
| void LCodeGen::DoLoadNamedGeneric(LLoadNamedGeneric* instr) {
|
| + ASSERT(ToRegister(instr->context()).is(esi));
|
| ASSERT(ToRegister(instr->object()).is(eax));
|
| ASSERT(ToRegister(instr->result()).is(eax));
|
|
|
| @@ -2010,22 +2111,33 @@
|
|
|
|
|
| void LCodeGen::DoLoadElements(LLoadElements* instr) {
|
| - ASSERT(instr->result()->Equals(instr->InputAt(0)));
|
| - Register reg = ToRegister(instr->InputAt(0));
|
| - __ mov(reg, FieldOperand(reg, JSObject::kElementsOffset));
|
| + Register result = ToRegister(instr->result());
|
| + Register input = ToRegister(instr->InputAt(0));
|
| + __ mov(result, FieldOperand(input, JSObject::kElementsOffset));
|
| if (FLAG_debug_code) {
|
| NearLabel done;
|
| - __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
|
| + __ cmp(FieldOperand(result, HeapObject::kMapOffset),
|
| Immediate(FACTORY->fixed_array_map()));
|
| __ j(equal, &done);
|
| - __ cmp(FieldOperand(reg, HeapObject::kMapOffset),
|
| + __ cmp(FieldOperand(result, HeapObject::kMapOffset),
|
| + Immediate(FACTORY->pixel_array_map()));
|
| + __ j(equal, &done);
|
| + __ cmp(FieldOperand(result, HeapObject::kMapOffset),
|
| Immediate(FACTORY->fixed_cow_array_map()));
|
| - __ Check(equal, "Check for fast elements failed.");
|
| + __ Check(equal, "Check for fast elements or pixel array failed.");
|
| __ bind(&done);
|
| }
|
| }
|
|
|
|
|
| +void LCodeGen::DoLoadPixelArrayExternalPointer(
|
| + LLoadPixelArrayExternalPointer* instr) {
|
| + Register result = ToRegister(instr->result());
|
| + Register input = ToRegister(instr->InputAt(0));
|
| + __ mov(result, FieldOperand(input, PixelArray::kExternalPointerOffset));
|
| +}
|
| +
|
| +
|
| void LCodeGen::DoAccessArgumentsAt(LAccessArgumentsAt* instr) {
|
| Register arguments = ToRegister(instr->arguments());
|
| Register length = ToRegister(instr->length());
|
| @@ -2059,7 +2171,19 @@
|
| }
|
|
|
|
|
| +void LCodeGen::DoLoadPixelArrayElement(LLoadPixelArrayElement* instr) {
|
| + Register external_pointer = ToRegister(instr->external_pointer());
|
| + Register key = ToRegister(instr->key());
|
| + Register result = ToRegister(instr->result());
|
| + ASSERT(result.is(external_pointer));
|
| +
|
| + // Load the result.
|
| + __ movzx_b(result, Operand(external_pointer, key, times_1, 0));
|
| +}
|
| +
|
| +
|
| void LCodeGen::DoLoadKeyedGeneric(LLoadKeyedGeneric* instr) {
|
| + ASSERT(ToRegister(instr->context()).is(esi));
|
| ASSERT(ToRegister(instr->object()).is(edx));
|
| ASSERT(ToRegister(instr->key()).is(eax));
|
|
|
| @@ -2118,24 +2242,36 @@
|
|
|
| void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
|
| Register receiver = ToRegister(instr->receiver());
|
| - ASSERT(ToRegister(instr->function()).is(edi));
|
| + Register function = ToRegister(instr->function());
|
| + Register length = ToRegister(instr->length());
|
| + Register elements = ToRegister(instr->elements());
|
| + Register scratch = ToRegister(instr->TempAt(0));
|
| + ASSERT(receiver.is(eax)); // Used for parameter count.
|
| + ASSERT(function.is(edi)); // Required by InvokeFunction.
|
| ASSERT(ToRegister(instr->result()).is(eax));
|
|
|
| - // If the receiver is null or undefined, we have to pass the
|
| - // global object as a receiver.
|
| - NearLabel global_receiver, receiver_ok;
|
| + // If the receiver is null or undefined, we have to pass the global object
|
| + // as a receiver.
|
| + NearLabel global_object, receiver_ok;
|
| __ cmp(receiver, FACTORY->null_value());
|
| - __ j(equal, &global_receiver);
|
| + __ j(equal, &global_object);
|
| __ cmp(receiver, FACTORY->undefined_value());
|
| - __ j(not_equal, &receiver_ok);
|
| - __ bind(&global_receiver);
|
| - __ mov(receiver, GlobalObjectOperand());
|
| - __ bind(&receiver_ok);
|
| + __ j(equal, &global_object);
|
|
|
| - Register length = ToRegister(instr->length());
|
| - Register elements = ToRegister(instr->elements());
|
| + // The receiver should be a JS object.
|
| + __ test(receiver, Immediate(kSmiTagMask));
|
| + DeoptimizeIf(equal, instr->environment());
|
| + __ CmpObjectType(receiver, FIRST_JS_OBJECT_TYPE, scratch);
|
| + DeoptimizeIf(below, instr->environment());
|
| + __ jmp(&receiver_ok);
|
|
|
| - Label invoke;
|
| + __ bind(&global_object);
|
| + // TODO(kmillikin): We have a hydrogen value for the global object. See
|
| + // if it's better to use it than to explicitly fetch it from the context
|
| + // here.
|
| + __ mov(receiver, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| + __ mov(receiver, ContextOperand(receiver, Context::GLOBAL_INDEX));
|
| + __ bind(&receiver_ok);
|
|
|
| // Copy the arguments to this function possibly from the
|
| // adaptor frame below it.
|
| @@ -2148,7 +2284,7 @@
|
|
|
| // Loop through the arguments pushing them onto the execution
|
| // stack.
|
| - Label loop;
|
| + NearLabel invoke, loop;
|
| // length is a small non-negative integer, due to the test above.
|
| __ test(length, Operand(length));
|
| __ j(zero, &invoke);
|
| @@ -2166,13 +2302,10 @@
|
| RegisterEnvironmentForDeoptimization(env);
|
| SafepointGenerator safepoint_generator(this,
|
| pointers,
|
| - env->deoptimization_index());
|
| - ASSERT(receiver.is(eax));
|
| + env->deoptimization_index(),
|
| + true);
|
| v8::internal::ParameterCount actual(eax);
|
| - __ InvokeFunction(edi, actual, CALL_FUNCTION, &safepoint_generator);
|
| -
|
| - // Restore context.
|
| - __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| + __ InvokeFunction(function, actual, CALL_FUNCTION, &safepoint_generator);
|
| }
|
|
|
|
|
| @@ -2188,7 +2321,7 @@
|
|
|
| void LCodeGen::DoContext(LContext* instr) {
|
| Register result = ToRegister(instr->result());
|
| - __ mov(result, esi);
|
| + __ mov(result, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| }
|
|
|
|
|
| @@ -2224,6 +2357,8 @@
|
| (scope()->num_heap_slots() > 0);
|
| if (change_context) {
|
| __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset));
|
| + } else {
|
| + __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| }
|
|
|
| // Set eax to arguments count if adaption is not needed. Assumes that eax
|
| @@ -2240,13 +2375,11 @@
|
| __ CallSelf();
|
| } else {
|
| __ call(FieldOperand(edi, JSFunction::kCodeEntryOffset));
|
| + EnsureRelocSpaceForDeoptimization();
|
| }
|
|
|
| // Setup deoptimization.
|
| RegisterLazyDeoptimization(instr);
|
| -
|
| - // Restore context.
|
| - __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| }
|
|
|
|
|
| @@ -2289,6 +2422,7 @@
|
| // Slow case: Call the runtime system to do the number allocation.
|
| __ bind(&slow);
|
|
|
| + __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
|
| RecordSafepointWithRegisters(
|
| instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
|
| @@ -2296,7 +2430,7 @@
|
| if (!tmp.is(eax)) __ mov(tmp, eax);
|
|
|
| // Restore input_reg after call to runtime.
|
| - __ mov(input_reg, Operand(esp, EspIndexForPushAll(input_reg) * kPointerSize));
|
| + __ LoadFromSafepointRegisterSlot(input_reg, input_reg);
|
|
|
| __ bind(&allocated);
|
| __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kExponentOffset));
|
| @@ -2304,7 +2438,7 @@
|
| __ mov(FieldOperand(tmp, HeapNumber::kExponentOffset), tmp2);
|
| __ mov(tmp2, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
|
| __ mov(FieldOperand(tmp, HeapNumber::kMantissaOffset), tmp2);
|
| - __ mov(Operand(esp, EspIndexForPushAll(input_reg) * kPointerSize), tmp);
|
| + __ StoreToSafepointRegisterSlot(input_reg, tmp);
|
|
|
| __ bind(&done);
|
| __ PopSafepointRegisters();
|
| @@ -2429,11 +2563,6 @@
|
| XMMRegister xmm_scratch = xmm0;
|
| XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
|
| ASSERT(ToDoubleRegister(instr->result()).is(input_reg));
|
| - ExternalReference negative_infinity =
|
| - ExternalReference::address_of_negative_infinity();
|
| - __ 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);
|
| @@ -2500,7 +2629,7 @@
|
| ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
|
| TranscendentalCacheStub stub(TranscendentalCache::LOG,
|
| TranscendentalCacheStub::UNTAGGED);
|
| - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
|
| }
|
|
|
|
|
| @@ -2508,7 +2637,7 @@
|
| ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
|
| TranscendentalCacheStub stub(TranscendentalCache::COS,
|
| TranscendentalCacheStub::UNTAGGED);
|
| - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
|
| }
|
|
|
|
|
| @@ -2516,7 +2645,7 @@
|
| ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
|
| TranscendentalCacheStub stub(TranscendentalCache::SIN,
|
| TranscendentalCacheStub::UNTAGGED);
|
| - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
|
| }
|
|
|
|
|
| @@ -2554,18 +2683,19 @@
|
|
|
|
|
| void LCodeGen::DoCallKeyed(LCallKeyed* instr) {
|
| + ASSERT(ToRegister(instr->context()).is(esi));
|
| + ASSERT(ToRegister(instr->key()).is(ecx));
|
| ASSERT(ToRegister(instr->result()).is(eax));
|
| - ASSERT(ToRegister(instr->InputAt(0)).is(ecx));
|
|
|
| int arity = instr->arity();
|
| Handle<Code> ic = Isolate::Current()->stub_cache()->
|
| ComputeKeyedCallInitialize(arity, NOT_IN_LOOP);
|
| CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
| - __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| }
|
|
|
|
|
| void LCodeGen::DoCallNamed(LCallNamed* instr) {
|
| + ASSERT(ToRegister(instr->context()).is(esi));
|
| ASSERT(ToRegister(instr->result()).is(eax));
|
|
|
| int arity = instr->arity();
|
| @@ -2573,22 +2703,22 @@
|
| ComputeCallInitialize(arity, NOT_IN_LOOP);
|
| __ mov(ecx, instr->name());
|
| CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
| - __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| }
|
|
|
|
|
| void LCodeGen::DoCallFunction(LCallFunction* instr) {
|
| + ASSERT(ToRegister(instr->context()).is(esi));
|
| ASSERT(ToRegister(instr->result()).is(eax));
|
|
|
| int arity = instr->arity();
|
| CallFunctionStub stub(arity, NOT_IN_LOOP, RECEIVER_MIGHT_BE_VALUE);
|
| CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| __ Drop(1);
|
| - __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| }
|
|
|
|
|
| void LCodeGen::DoCallGlobal(LCallGlobal* instr) {
|
| + ASSERT(ToRegister(instr->context()).is(esi));
|
| ASSERT(ToRegister(instr->result()).is(eax));
|
|
|
| int arity = instr->arity();
|
| @@ -2596,7 +2726,6 @@
|
| ComputeCallInitialize(arity, NOT_IN_LOOP);
|
| __ mov(ecx, instr->name());
|
| CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, instr);
|
| - __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| }
|
|
|
|
|
| @@ -2608,7 +2737,8 @@
|
|
|
|
|
| void LCodeGen::DoCallNew(LCallNew* instr) {
|
| - ASSERT(ToRegister(instr->InputAt(0)).is(edi));
|
| + ASSERT(ToRegister(instr->context()).is(esi));
|
| + ASSERT(ToRegister(instr->constructor()).is(edi));
|
| ASSERT(ToRegister(instr->result()).is(eax));
|
|
|
| Handle<Code> builtin(Isolate::Current()->builtins()->builtin(
|
| @@ -2619,7 +2749,7 @@
|
|
|
|
|
| void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
|
| - CallRuntime(instr->function(), instr->arity(), instr);
|
| + CallRuntime(instr->function(), instr->arity(), instr, false);
|
| }
|
|
|
|
|
| @@ -2654,12 +2784,14 @@
|
|
|
|
|
| void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
|
| + ASSERT(ToRegister(instr->context()).is(esi));
|
| ASSERT(ToRegister(instr->object()).is(edx));
|
| ASSERT(ToRegister(instr->value()).is(eax));
|
|
|
| __ mov(ecx, instr->name());
|
| Handle<Code> ic(Isolate::Current()->builtins()->builtin(
|
| - Builtins::StoreIC_Initialize));
|
| + info_->is_strict() ? Builtins::StoreIC_Initialize_Strict
|
| + : Builtins::StoreIC_Initialize));
|
| CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
| }
|
|
|
| @@ -2670,6 +2802,25 @@
|
| }
|
|
|
|
|
| +void LCodeGen::DoStorePixelArrayElement(LStorePixelArrayElement* instr) {
|
| + Register external_pointer = ToRegister(instr->external_pointer());
|
| + Register key = ToRegister(instr->key());
|
| + Register value = ToRegister(instr->value());
|
| + ASSERT(ToRegister(instr->TempAt(0)).is(eax));
|
| +
|
| + __ mov(eax, value);
|
| + { // Clamp the value to [0..255].
|
| + NearLabel done;
|
| + __ test(eax, Immediate(0xFFFFFF00));
|
| + __ j(zero, &done);
|
| + __ setcc(negative, eax); // 1 if negative, 0 if positive.
|
| + __ dec_b(eax); // 0 if negative, 255 if positive.
|
| + __ bind(&done);
|
| + }
|
| + __ mov_b(Operand(external_pointer, key, times_1, 0), eax);
|
| +}
|
| +
|
| +
|
| void LCodeGen::DoStoreKeyedFastElement(LStoreKeyedFastElement* instr) {
|
| Register value = ToRegister(instr->value());
|
| Register elements = ToRegister(instr->object());
|
| @@ -2703,12 +2854,14 @@
|
|
|
|
|
| void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
|
| + ASSERT(ToRegister(instr->context()).is(esi));
|
| ASSERT(ToRegister(instr->object()).is(edx));
|
| ASSERT(ToRegister(instr->key()).is(ecx));
|
| ASSERT(ToRegister(instr->value()).is(eax));
|
|
|
| Handle<Code> ic(Isolate::Current()->builtins()->builtin(
|
| - Builtins::KeyedStoreIC_Initialize));
|
| + info_->is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict
|
| + : Builtins::KeyedStoreIC_Initialize));
|
| CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
| }
|
|
|
| @@ -2779,19 +2932,20 @@
|
| __ test(result, Immediate(kStringRepresentationMask));
|
| __ j(not_zero, deferred->entry());
|
|
|
| - // Check for 1-byte or 2-byte string.
|
| + // Check for ASCII or two-byte string.
|
| __ bind(&flat_string);
|
| STATIC_ASSERT(kAsciiStringTag != 0);
|
| __ test(result, Immediate(kStringEncodingMask));
|
| __ j(not_zero, &ascii_string);
|
|
|
| - // 2-byte string.
|
| - // Load the 2-byte character code into the result register.
|
| + // Two-byte string.
|
| + // Load the two-byte character code into the result register.
|
| STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
|
| if (instr->index()->IsConstantOperand()) {
|
| __ movzx_w(result,
|
| FieldOperand(string,
|
| - SeqTwoByteString::kHeaderSize + 2 * const_index));
|
| + SeqTwoByteString::kHeaderSize +
|
| + (kUC16Size * const_index)));
|
| } else {
|
| __ movzx_w(result, FieldOperand(string,
|
| index,
|
| @@ -2839,6 +2993,7 @@
|
| __ SmiTag(index);
|
| __ push(index);
|
| }
|
| + __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| __ CallRuntimeSaveDoubles(Runtime::kStringCharCodeAt);
|
| RecordSafepointWithRegisters(
|
| instr->pointer_map(), 2, Safepoint::kNoDeoptimizationIndex);
|
| @@ -2846,7 +3001,7 @@
|
| __ AbortIfNotSmi(eax);
|
| }
|
| __ SmiUntag(eax);
|
| - __ mov(Operand(esp, EspIndexForPushAll(result) * kPointerSize), eax);
|
| + __ StoreToSafepointRegisterSlot(result, eax);
|
| __ PopSafepointRegisters();
|
| }
|
|
|
| @@ -2914,8 +3069,9 @@
|
| // TODO(3095996): Put a valid pointer value in the stack slot where the result
|
| // register is stored, as this register is in the pointer map, but contains an
|
| // integer value.
|
| - __ mov(Operand(esp, EspIndexForPushAll(reg) * kPointerSize), Immediate(0));
|
| + __ StoreToSafepointRegisterSlot(reg, Immediate(0));
|
|
|
| + __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
|
| RecordSafepointWithRegisters(
|
| instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
|
| @@ -2925,7 +3081,7 @@
|
| // number.
|
| __ bind(&done);
|
| __ movdbl(FieldOperand(reg, HeapNumber::kValueOffset), xmm0);
|
| - __ mov(Operand(esp, EspIndexForPushAll(reg) * kPointerSize), reg);
|
| + __ StoreToSafepointRegisterSlot(reg, reg);
|
| __ PopSafepointRegisters();
|
| }
|
|
|
| @@ -2963,10 +3119,11 @@
|
| __ Set(reg, Immediate(0));
|
|
|
| __ PushSafepointRegisters();
|
| + __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
|
| RecordSafepointWithRegisters(
|
| instr->pointer_map(), 0, Safepoint::kNoDeoptimizationIndex);
|
| - __ mov(Operand(esp, EspIndexForPushAll(reg) * kPointerSize), eax);
|
| + __ StoreToSafepointRegisterSlot(reg, eax);
|
| __ PopSafepointRegisters();
|
| }
|
|
|
| @@ -3378,21 +3535,22 @@
|
| FastCloneShallowArrayStub::Mode mode =
|
| FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS;
|
| FastCloneShallowArrayStub stub(mode, length);
|
| - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
|
| } else if (instr->hydrogen()->depth() > 1) {
|
| - CallRuntime(Runtime::kCreateArrayLiteral, 3, instr);
|
| + CallRuntime(Runtime::kCreateArrayLiteral, 3, instr, false);
|
| } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
|
| - CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr);
|
| + CallRuntime(Runtime::kCreateArrayLiteralShallow, 3, instr, false);
|
| } else {
|
| FastCloneShallowArrayStub::Mode mode =
|
| FastCloneShallowArrayStub::CLONE_ELEMENTS;
|
| FastCloneShallowArrayStub stub(mode, length);
|
| - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
|
| }
|
| }
|
|
|
|
|
| void LCodeGen::DoObjectLiteral(LObjectLiteral* instr) {
|
| + ASSERT(ToRegister(instr->context()).is(esi));
|
| // Setup the parameters to the stub/runtime call.
|
| __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
|
| __ push(FieldOperand(eax, JSFunction::kLiteralsOffset));
|
| @@ -3430,7 +3588,7 @@
|
| __ push(Immediate(Smi::FromInt(instr->hydrogen()->literal_index())));
|
| __ push(Immediate(instr->hydrogen()->pattern()));
|
| __ push(Immediate(instr->hydrogen()->flags()));
|
| - CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr);
|
| + CallRuntime(Runtime::kMaterializeRegExpLiteral, 4, instr, false);
|
| __ mov(ebx, eax);
|
|
|
| __ bind(&materialized);
|
| @@ -3442,7 +3600,7 @@
|
| __ bind(&runtime_allocate);
|
| __ push(ebx);
|
| __ push(Immediate(Smi::FromInt(size)));
|
| - CallRuntime(Runtime::kAllocateInNewSpace, 1, instr);
|
| + CallRuntime(Runtime::kAllocateInNewSpace, 1, instr, false);
|
| __ pop(ebx);
|
|
|
| __ bind(&allocated);
|
| @@ -3469,14 +3627,14 @@
|
| if (shared_info->num_literals() == 0 && !pretenure) {
|
| FastNewClosureStub stub;
|
| __ push(Immediate(shared_info));
|
| - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
|
| } else {
|
| - __ push(esi);
|
| + __ push(Operand(ebp, StandardFrameConstants::kContextOffset));
|
| __ push(Immediate(shared_info));
|
| __ push(Immediate(pretenure
|
| ? FACTORY->true_value()
|
| : FACTORY->false_value()));
|
| - CallRuntime(Runtime::kNewClosure, 3, instr);
|
| + CallRuntime(Runtime::kNewClosure, 3, instr, false);
|
| }
|
| }
|
|
|
| @@ -3488,7 +3646,7 @@
|
| } else {
|
| __ push(ToOperand(input));
|
| }
|
| - CallRuntime(Runtime::kTypeof, 1, instr);
|
| + CallRuntime(Runtime::kTypeof, 1, instr, false);
|
| }
|
|
|
|
|
| @@ -3679,9 +3837,15 @@
|
| LEnvironment* env = instr->deoptimization_environment();
|
| RecordPosition(pointers->position());
|
| RegisterEnvironmentForDeoptimization(env);
|
| + // Create safepoint generator that will also ensure enough space in the
|
| + // reloc info for patching in deoptimization (since this is invoking a
|
| + // builtin)
|
| SafepointGenerator safepoint_generator(this,
|
| pointers,
|
| - env->deoptimization_index());
|
| + env->deoptimization_index(),
|
| + true);
|
| + __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
|
| + __ push(Immediate(Smi::FromInt(strict_mode_flag())));
|
| __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, &safepoint_generator);
|
| }
|
|
|
| @@ -3694,7 +3858,7 @@
|
| __ j(above_equal, &done);
|
|
|
| StackCheckStub stub;
|
| - CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
|
| + CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr, false);
|
| __ bind(&done);
|
| }
|
|
|
|
|