| Index: src/ppc/deoptimizer-ppc.cc
|
| diff --git a/src/mips/deoptimizer-mips.cc b/src/ppc/deoptimizer-ppc.cc
|
| similarity index 58%
|
| copy from src/mips/deoptimizer-mips.cc
|
| copy to src/ppc/deoptimizer-ppc.cc
|
| index 93e7a735d5676eed16c192ee2830a051cadba87b..80a322a20213ed3a8d34d2d1b3cf8b9f7056337b 100644
|
| --- a/src/mips/deoptimizer-mips.cc
|
| +++ b/src/ppc/deoptimizer-ppc.cc
|
| @@ -1,5 +1,7 @@
|
| -
|
| -// Copyright 2011 the V8 project authors. All rights reserved.
|
| +// Copyright 2012 the V8 project authors. All rights reserved.
|
| +//
|
| +// Copyright IBM Corp. 2012, 2013. All rights reserved.
|
| +//
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| @@ -13,15 +15,22 @@
|
| namespace v8 {
|
| namespace internal {
|
|
|
| +const int Deoptimizer::table_entry_size_ = 8;
|
| +
|
|
|
| int Deoptimizer::patch_size() {
|
| +#if V8_TARGET_ARCH_PPC64
|
| + const int kCallInstructionSizeInWords = 7;
|
| +#else
|
| const int kCallInstructionSizeInWords = 4;
|
| +#endif
|
| return kCallInstructionSizeInWords * Assembler::kInstrSize;
|
| }
|
|
|
|
|
| void Deoptimizer::PatchCodeForDeoptimization(Isolate* isolate, Code* code) {
|
| Address code_start_address = code->instruction_start();
|
| +
|
| // Invalidate the relocation information, as it will become invalid by the
|
| // code patching below, and is not needed any more.
|
| code->InvalidateRelocation();
|
| @@ -35,14 +44,14 @@ void Deoptimizer::PatchCodeForDeoptimization(Isolate* isolate, Code* code) {
|
| pointer = code->instruction_start();
|
| }
|
| CodePatcher patcher(pointer, 1);
|
| - patcher.masm()->break_(0xCC);
|
| + patcher.masm()->bkpt(0);
|
|
|
| DeoptimizationInputData* data =
|
| DeoptimizationInputData::cast(code->deoptimization_data());
|
| int osr_offset = data->OsrPcOffset()->value();
|
| if (osr_offset > 0) {
|
| CodePatcher osr_patcher(code->instruction_start() + osr_offset, 1);
|
| - osr_patcher.masm()->break_(0xCC);
|
| + osr_patcher.masm()->bkpt(0);
|
| }
|
| }
|
|
|
| @@ -60,17 +69,19 @@ void Deoptimizer::PatchCodeForDeoptimization(Isolate* isolate, Code* code) {
|
| if (deopt_data->Pc(i)->value() == -1) continue;
|
| Address call_address = code_start_address + deopt_data->Pc(i)->value();
|
| Address deopt_entry = GetDeoptimizationEntry(isolate, i, LAZY);
|
| - int call_size_in_bytes = MacroAssembler::CallSize(deopt_entry,
|
| - RelocInfo::NONE32);
|
| + // We need calls to have a predictable size in the unoptimized code, but
|
| + // this is optimized code, so we don't have to have a predictable size.
|
| + int call_size_in_bytes =
|
| + MacroAssembler::CallSizeNotPredictableCodeSize(deopt_entry,
|
| + kRelocInfo_NONEPTR);
|
| int call_size_in_words = call_size_in_bytes / Assembler::kInstrSize;
|
| ASSERT(call_size_in_bytes % Assembler::kInstrSize == 0);
|
| ASSERT(call_size_in_bytes <= patch_size());
|
| CodePatcher patcher(call_address, call_size_in_words);
|
| - patcher.masm()->Call(deopt_entry, RelocInfo::NONE32);
|
| + patcher.masm()->Call(deopt_entry, kRelocInfo_NONEPTR);
|
| ASSERT(prev_call_address == NULL ||
|
| call_address >= prev_call_address + patch_size());
|
| ASSERT(call_address + patch_size() <= code->instruction_end());
|
| -
|
| #ifdef DEBUG
|
| prev_call_address = call_address;
|
| #endif
|
| @@ -94,7 +105,8 @@ void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) {
|
|
|
| // Fill the frame content from the actual data on the frame.
|
| for (unsigned i = 0; i < input_->GetFrameSize(); i += kPointerSize) {
|
| - input_->SetFrameSlot(i, Memory::uint32_at(tos + i));
|
| + input_->SetFrameSlot(i, reinterpret_cast<intptr_t>(
|
| + Memory::Address_at(tos + i)));
|
| }
|
| }
|
|
|
| @@ -105,9 +117,8 @@ void Deoptimizer::SetPlatformCompiledStubRegisters(
|
| ExternalReference xref(&function, ExternalReference::BUILTIN_CALL, isolate_);
|
| intptr_t handler = reinterpret_cast<intptr_t>(xref.address());
|
| int params = descriptor->GetHandlerParameterCount();
|
| - output_frame->SetRegister(s0.code(), params);
|
| - output_frame->SetRegister(s1.code(), (params - 1) * kPointerSize);
|
| - output_frame->SetRegister(s2.code(), handler);
|
| + output_frame->SetRegister(r3.code(), params);
|
| + output_frame->SetRegister(r4.code(), handler);
|
| }
|
|
|
|
|
| @@ -120,14 +131,13 @@ void Deoptimizer::CopyDoubleRegisters(FrameDescription* output_frame) {
|
|
|
|
|
| bool Deoptimizer::HasAlignmentPadding(JSFunction* function) {
|
| - // There is no dynamic alignment padding on MIPS in the input frame.
|
| + // There is no dynamic alignment padding on PPC in the input frame.
|
| return false;
|
| }
|
|
|
|
|
| #define __ masm()->
|
|
|
| -
|
| // This code tries to be close to ia32 code so that any changes can be
|
| // easily ported.
|
| void Deoptimizer::EntryGenerator::Generate() {
|
| @@ -138,25 +148,25 @@ void Deoptimizer::EntryGenerator::Generate() {
|
| const int kNumberOfRegisters = Register::kNumRegisters;
|
|
|
| RegList restored_regs = kJSCallerSaved | kCalleeSaved;
|
| - RegList saved_regs = restored_regs | sp.bit() | ra.bit();
|
| + RegList saved_regs = restored_regs | sp.bit();
|
|
|
| const int kDoubleRegsSize =
|
| - kDoubleSize * FPURegister::kMaxNumAllocatableRegisters;
|
| + kDoubleSize * DoubleRegister::kMaxNumAllocatableRegisters;
|
|
|
| // Save all FPU registers before messing with them.
|
| - __ Subu(sp, sp, Operand(kDoubleRegsSize));
|
| - for (int i = 0; i < FPURegister::kMaxNumAllocatableRegisters; ++i) {
|
| - FPURegister fpu_reg = FPURegister::FromAllocationIndex(i);
|
| + __ subi(sp, sp, Operand(kDoubleRegsSize));
|
| + for (int i = 0; i < DoubleRegister::kMaxNumAllocatableRegisters; ++i) {
|
| + DoubleRegister fpu_reg = DoubleRegister::FromAllocationIndex(i);
|
| int offset = i * kDoubleSize;
|
| - __ sdc1(fpu_reg, MemOperand(sp, offset));
|
| + __ stfd(fpu_reg, MemOperand(sp, offset));
|
| }
|
|
|
| // Push saved_regs (needed to populate FrameDescription::registers_).
|
| // Leave gaps for other registers.
|
| - __ Subu(sp, sp, kNumberOfRegisters * kPointerSize);
|
| + __ subi(sp, sp, Operand(kNumberOfRegisters * kPointerSize));
|
| for (int16_t i = kNumberOfRegisters - 1; i >= 0; i--) {
|
| if ((saved_regs & (1 << i)) != 0) {
|
| - __ sw(ToRegister(i), MemOperand(sp, kPointerSize * i));
|
| + __ StoreP(ToRegister(i), MemOperand(sp, kPointerSize * i));
|
| }
|
| }
|
|
|
| @@ -164,185 +174,170 @@ void Deoptimizer::EntryGenerator::Generate() {
|
| (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize;
|
|
|
| // Get the bailout id from the stack.
|
| - __ lw(a2, MemOperand(sp, kSavedRegistersAreaSize));
|
| + __ LoadP(r5, MemOperand(sp, kSavedRegistersAreaSize));
|
|
|
| - // Get the address of the location in the code object (a3) (return
|
| + // Get the address of the location in the code object (r6) (return
|
| // address for lazy deoptimization) and compute the fp-to-sp delta in
|
| - // register t0.
|
| - __ mov(a3, ra);
|
| + // register r7.
|
| + __ mflr(r6);
|
| // Correct one word for bailout id.
|
| - __ Addu(t0, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize)));
|
| -
|
| - __ Subu(t0, fp, t0);
|
| + __ addi(r7, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize)));
|
| + __ sub(r7, fp, r7);
|
|
|
| // Allocate a new deoptimizer object.
|
| - // Pass four arguments in a0 to a3 and fifth & sixth arguments on stack.
|
| - __ PrepareCallCFunction(6, t1);
|
| - __ lw(a0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
| - __ li(a1, Operand(type())); // bailout type,
|
| - // a2: bailout id already loaded.
|
| - // a3: code address or 0 already loaded.
|
| - __ sw(t0, CFunctionArgumentOperand(5)); // Fp-to-sp delta.
|
| - __ li(t1, Operand(ExternalReference::isolate_address(isolate())));
|
| - __ sw(t1, CFunctionArgumentOperand(6)); // Isolate.
|
| + // Pass six arguments in r3 to r8.
|
| + __ PrepareCallCFunction(6, r8);
|
| + __ LoadP(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
| + __ li(r4, Operand(type())); // bailout type,
|
| + // r5: bailout id already loaded.
|
| + // r6: code address or 0 already loaded.
|
| + // r7: Fp-to-sp delta.
|
| + __ mov(r8, Operand(ExternalReference::isolate_address(isolate())));
|
| // Call Deoptimizer::New().
|
| {
|
| AllowExternalCallThatCantCauseGC scope(masm());
|
| __ CallCFunction(ExternalReference::new_deoptimizer_function(isolate()), 6);
|
| }
|
|
|
| - // Preserve "deoptimizer" object in register v0 and get the input
|
| - // frame descriptor pointer to a1 (deoptimizer->input_);
|
| - // Move deopt-obj to a0 for call to Deoptimizer::ComputeOutputFrames() below.
|
| - __ mov(a0, v0);
|
| - __ lw(a1, MemOperand(v0, Deoptimizer::input_offset()));
|
| + // Preserve "deoptimizer" object in register r3 and get the input
|
| + // frame descriptor pointer to r4 (deoptimizer->input_);
|
| + __ LoadP(r4, MemOperand(r3, Deoptimizer::input_offset()));
|
|
|
| // Copy core registers into FrameDescription::registers_[kNumRegisters].
|
| ASSERT(Register::kNumRegisters == kNumberOfRegisters);
|
| for (int i = 0; i < kNumberOfRegisters; i++) {
|
| int offset = (i * kPointerSize) + FrameDescription::registers_offset();
|
| - if ((saved_regs & (1 << i)) != 0) {
|
| - __ lw(a2, MemOperand(sp, i * kPointerSize));
|
| - __ sw(a2, MemOperand(a1, offset));
|
| - } else if (FLAG_debug_code) {
|
| - __ li(a2, kDebugZapValue);
|
| - __ sw(a2, MemOperand(a1, offset));
|
| - }
|
| + __ LoadP(r5, MemOperand(sp, i * kPointerSize));
|
| + __ StoreP(r5, MemOperand(r4, offset));
|
| }
|
|
|
| int double_regs_offset = FrameDescription::double_registers_offset();
|
| - // Copy FPU registers to
|
| + // Copy VFP registers to
|
| // double_registers_[DoubleRegister::kNumAllocatableRegisters]
|
| - for (int i = 0; i < FPURegister::NumAllocatableRegisters(); ++i) {
|
| + for (int i = 0; i < DoubleRegister::NumAllocatableRegisters(); ++i) {
|
| int dst_offset = i * kDoubleSize + double_regs_offset;
|
| int src_offset = i * kDoubleSize + kNumberOfRegisters * kPointerSize;
|
| - __ ldc1(f0, MemOperand(sp, src_offset));
|
| - __ sdc1(f0, MemOperand(a1, dst_offset));
|
| + __ lfd(d0, MemOperand(sp, src_offset));
|
| + __ stfd(d0, MemOperand(r4, dst_offset));
|
| }
|
|
|
| // Remove the bailout id and the saved registers from the stack.
|
| - __ Addu(sp, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize)));
|
| + __ addi(sp, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize)));
|
|
|
| - // Compute a pointer to the unwinding limit in register a2; that is
|
| + // Compute a pointer to the unwinding limit in register r5; that is
|
| // the first stack slot not part of the input frame.
|
| - __ lw(a2, MemOperand(a1, FrameDescription::frame_size_offset()));
|
| - __ Addu(a2, a2, sp);
|
| + __ LoadP(r5, MemOperand(r4, FrameDescription::frame_size_offset()));
|
| + __ add(r5, r5, sp);
|
|
|
| // Unwind the stack down to - but not including - the unwinding
|
| // limit and copy the contents of the activation frame to the input
|
| // frame description.
|
| - __ Addu(a3, a1, Operand(FrameDescription::frame_content_offset()));
|
| + __ addi(r6, r4, Operand(FrameDescription::frame_content_offset()));
|
| Label pop_loop;
|
| Label pop_loop_header;
|
| - __ BranchShort(&pop_loop_header);
|
| + __ b(&pop_loop_header);
|
| __ bind(&pop_loop);
|
| - __ pop(t0);
|
| - __ sw(t0, MemOperand(a3, 0));
|
| - __ addiu(a3, a3, sizeof(uint32_t));
|
| + __ pop(r7);
|
| + __ StoreP(r7, MemOperand(r6, 0));
|
| + __ addi(r6, r6, Operand(kPointerSize));
|
| __ bind(&pop_loop_header);
|
| - __ BranchShort(&pop_loop, ne, a2, Operand(sp));
|
| + __ cmp(r5, sp);
|
| + __ bne(&pop_loop);
|
|
|
| // Compute the output frame in the deoptimizer.
|
| - __ push(a0); // Preserve deoptimizer object across call.
|
| - // a0: deoptimizer object; a1: scratch.
|
| - __ PrepareCallCFunction(1, a1);
|
| + __ push(r3); // Preserve deoptimizer object across call.
|
| + // r3: deoptimizer object; r4: scratch.
|
| + __ PrepareCallCFunction(1, r4);
|
| // Call Deoptimizer::ComputeOutputFrames().
|
| {
|
| AllowExternalCallThatCantCauseGC scope(masm());
|
| __ CallCFunction(
|
| - ExternalReference::compute_output_frames_function(isolate()), 1);
|
| + ExternalReference::compute_output_frames_function(isolate()), 1);
|
| }
|
| - __ pop(a0); // Restore deoptimizer object (class Deoptimizer).
|
| + __ pop(r3); // Restore deoptimizer object (class Deoptimizer).
|
|
|
| // Replace the current (input) frame with the output frames.
|
| Label outer_push_loop, inner_push_loop,
|
| - outer_loop_header, inner_loop_header;
|
| - // Outer loop state: t0 = current "FrameDescription** output_",
|
| - // a1 = one past the last FrameDescription**.
|
| - __ lw(a1, MemOperand(a0, Deoptimizer::output_count_offset()));
|
| - __ lw(t0, MemOperand(a0, Deoptimizer::output_offset())); // t0 is output_.
|
| - __ sll(a1, a1, kPointerSizeLog2); // Count to offset.
|
| - __ addu(a1, t0, a1); // a1 = one past the last FrameDescription**.
|
| - __ jmp(&outer_loop_header);
|
| + outer_loop_header, inner_loop_header;
|
| + // Outer loop state: r7 = current "FrameDescription** output_",
|
| + // r4 = one past the last FrameDescription**.
|
| + __ lwz(r4, MemOperand(r3, Deoptimizer::output_count_offset()));
|
| + __ LoadP(r7, MemOperand(r3, Deoptimizer::output_offset())); // r7 is output_.
|
| + __ ShiftLeftImm(r4, r4, Operand(kPointerSizeLog2));
|
| + __ add(r4, r7, r4);
|
| + __ b(&outer_loop_header);
|
| +
|
| __ bind(&outer_push_loop);
|
| - // Inner loop state: a2 = current FrameDescription*, a3 = loop index.
|
| - __ lw(a2, MemOperand(t0, 0)); // output_[ix]
|
| - __ lw(a3, MemOperand(a2, FrameDescription::frame_size_offset()));
|
| - __ jmp(&inner_loop_header);
|
| + // Inner loop state: r5 = current FrameDescription*, r6 = loop index.
|
| + __ LoadP(r5, MemOperand(r7, 0)); // output_[ix]
|
| + __ LoadP(r6, MemOperand(r5, FrameDescription::frame_size_offset()));
|
| + __ b(&inner_loop_header);
|
| +
|
| __ bind(&inner_push_loop);
|
| - __ Subu(a3, a3, Operand(sizeof(uint32_t)));
|
| - __ Addu(t2, a2, Operand(a3));
|
| - __ lw(t3, MemOperand(t2, FrameDescription::frame_content_offset()));
|
| - __ push(t3);
|
| + __ addi(r6, r6, Operand(-sizeof(intptr_t)));
|
| + __ add(r9, r5, r6);
|
| + __ LoadP(r9, MemOperand(r9, FrameDescription::frame_content_offset()));
|
| + __ push(r9);
|
| +
|
| __ bind(&inner_loop_header);
|
| - __ BranchShort(&inner_push_loop, ne, a3, Operand(zero_reg));
|
| + __ cmpi(r6, Operand::Zero());
|
| + __ bne(&inner_push_loop); // test for gt?
|
|
|
| - __ Addu(t0, t0, Operand(kPointerSize));
|
| + __ addi(r7, r7, Operand(kPointerSize));
|
| __ bind(&outer_loop_header);
|
| - __ BranchShort(&outer_push_loop, lt, t0, Operand(a1));
|
| + __ cmp(r7, r4);
|
| + __ blt(&outer_push_loop);
|
|
|
| - __ lw(a1, MemOperand(a0, Deoptimizer::input_offset()));
|
| - for (int i = 0; i < FPURegister::kMaxNumAllocatableRegisters; ++i) {
|
| - const FPURegister fpu_reg = FPURegister::FromAllocationIndex(i);
|
| + __ LoadP(r4, MemOperand(r3, Deoptimizer::input_offset()));
|
| + for (int i = 0; i < DoubleRegister::kMaxNumAllocatableRegisters; ++i) {
|
| + const DoubleRegister dreg = DoubleRegister::FromAllocationIndex(i);
|
| int src_offset = i * kDoubleSize + double_regs_offset;
|
| - __ ldc1(fpu_reg, MemOperand(a1, src_offset));
|
| + __ lfd(dreg, MemOperand(r4, src_offset));
|
| }
|
|
|
| // Push state, pc, and continuation from the last output frame.
|
| - __ lw(t2, MemOperand(a2, FrameDescription::state_offset()));
|
| - __ push(t2);
|
| -
|
| - __ lw(t2, MemOperand(a2, FrameDescription::pc_offset()));
|
| - __ push(t2);
|
| - __ lw(t2, MemOperand(a2, FrameDescription::continuation_offset()));
|
| - __ push(t2);
|
| + __ LoadP(r9, MemOperand(r5, FrameDescription::state_offset()));
|
| + __ push(r9);
|
| + __ LoadP(r9, MemOperand(r5, FrameDescription::pc_offset()));
|
| + __ push(r9);
|
| + __ LoadP(r9, MemOperand(r5, FrameDescription::continuation_offset()));
|
| + __ push(r9);
|
|
|
| -
|
| - // Technically restoring 'at' should work unless zero_reg is also restored
|
| - // but it's safer to check for this.
|
| - ASSERT(!(at.bit() & restored_regs));
|
| // Restore the registers from the last output frame.
|
| - __ mov(at, a2);
|
| + ASSERT(!(ip.bit() & restored_regs));
|
| + __ mr(ip, r5);
|
| for (int i = kNumberOfRegisters - 1; i >= 0; i--) {
|
| int offset = (i * kPointerSize) + FrameDescription::registers_offset();
|
| if ((restored_regs & (1 << i)) != 0) {
|
| - __ lw(ToRegister(i), MemOperand(at, offset));
|
| + __ LoadP(ToRegister(i), MemOperand(ip, offset));
|
| }
|
| }
|
|
|
| __ InitializeRootRegister();
|
|
|
| - __ pop(at); // Get continuation, leave pc on stack.
|
| - __ pop(ra);
|
| - __ Jump(at);
|
| + __ pop(ip); // get continuation, leave pc on stack
|
| + __ pop(r0);
|
| + __ mtlr(r0);
|
| + __ Jump(ip);
|
| __ stop("Unreachable.");
|
| }
|
|
|
|
|
| -// Maximum size of a table entry generated below.
|
| -const int Deoptimizer::table_entry_size_ = 2 * Assembler::kInstrSize;
|
| -
|
| void Deoptimizer::TableEntryGenerator::GeneratePrologue() {
|
| Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm());
|
|
|
| // Create a sequence of deoptimization entries.
|
| // Note that registers are still live when jumping to an entry.
|
| - Label table_start, done;
|
| - __ bind(&table_start);
|
| + Label done;
|
| for (int i = 0; i < count(); i++) {
|
| - Label start;
|
| - __ bind(&start);
|
| - ASSERT(is_int16(i));
|
| - __ Branch(USE_DELAY_SLOT, &done); // Expose delay slot.
|
| - __ li(at, i); // In the delay slot.
|
| -
|
| - ASSERT_EQ(table_entry_size_, masm()->SizeOfCodeGeneratedSince(&start));
|
| + int start = masm()->pc_offset();
|
| + USE(start);
|
| + __ li(ip, Operand(i));
|
| + __ b(&done);
|
| + ASSERT(masm()->pc_offset() - start == table_entry_size_);
|
| }
|
| -
|
| - ASSERT_EQ(masm()->SizeOfCodeGeneratedSince(&table_start),
|
| - count() * table_entry_size_);
|
| __ bind(&done);
|
| - __ Push(at);
|
| + __ push(ip);
|
| }
|
|
|
|
|
| @@ -357,12 +352,16 @@ void FrameDescription::SetCallerFp(unsigned offset, intptr_t value) {
|
|
|
|
|
| void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) {
|
| +#if V8_OOL_CONSTANT_POOL
|
| + ASSERT(FLAG_enable_ool_constant_pool);
|
| + SetFrameSlot(offset, value);
|
| +#else
|
| // No out-of-line constant pool support.
|
| UNREACHABLE();
|
| +#endif
|
| }
|
|
|
|
|
| #undef __
|
|
|
| -
|
| } } // namespace v8::internal
|
|
|