1// Copyright 2012 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "src/v8.h" 6 7#include "src/codegen.h" 8#include "src/deoptimizer.h" 9#include "src/full-codegen.h" 10#include "src/safepoint-table.h" 11 12namespace v8 { 13namespace internal { 14 15const int Deoptimizer::table_entry_size_ = 8; 16 17 18int Deoptimizer::patch_size() { 19 const int kCallInstructionSizeInWords = 3; 20 return kCallInstructionSizeInWords * Assembler::kInstrSize; 21} 22 23 24void Deoptimizer::PatchCodeForDeoptimization(Isolate* isolate, Code* code) { 25 Address code_start_address = code->instruction_start(); 26 // Invalidate the relocation information, as it will become invalid by the 27 // code patching below, and is not needed any more. 28 code->InvalidateRelocation(); 29 30 if (FLAG_zap_code_space) { 31 // Fail hard and early if we enter this code object again. 32 byte* pointer = code->FindCodeAgeSequence(); 33 if (pointer != NULL) { 34 pointer += kNoCodeAgeSequenceLength; 35 } else { 36 pointer = code->instruction_start(); 37 } 38 CodePatcher patcher(pointer, 1); 39 patcher.masm()->bkpt(0); 40 41 DeoptimizationInputData* data = 42 DeoptimizationInputData::cast(code->deoptimization_data()); 43 int osr_offset = data->OsrPcOffset()->value(); 44 if (osr_offset > 0) { 45 CodePatcher osr_patcher(code->instruction_start() + osr_offset, 1); 46 osr_patcher.masm()->bkpt(0); 47 } 48 } 49 50 DeoptimizationInputData* deopt_data = 51 DeoptimizationInputData::cast(code->deoptimization_data()); 52#ifdef DEBUG 53 Address prev_call_address = NULL; 54#endif 55 // For each LLazyBailout instruction insert a call to the corresponding 56 // deoptimization entry. 57 for (int i = 0; i < deopt_data->DeoptCount(); i++) { 58 if (deopt_data->Pc(i)->value() == -1) continue; 59 Address call_address = code_start_address + deopt_data->Pc(i)->value(); 60 Address deopt_entry = GetDeoptimizationEntry(isolate, i, LAZY); 61 // We need calls to have a predictable size in the unoptimized code, but 62 // this is optimized code, so we don't have to have a predictable size. 63 int call_size_in_bytes = 64 MacroAssembler::CallSizeNotPredictableCodeSize(isolate, 65 deopt_entry, 66 RelocInfo::NONE32); 67 int call_size_in_words = call_size_in_bytes / Assembler::kInstrSize; 68 DCHECK(call_size_in_bytes % Assembler::kInstrSize == 0); 69 DCHECK(call_size_in_bytes <= patch_size()); 70 CodePatcher patcher(call_address, call_size_in_words); 71 patcher.masm()->Call(deopt_entry, RelocInfo::NONE32); 72 DCHECK(prev_call_address == NULL || 73 call_address >= prev_call_address + patch_size()); 74 DCHECK(call_address + patch_size() <= code->instruction_end()); 75#ifdef DEBUG 76 prev_call_address = call_address; 77#endif 78 } 79} 80 81 82void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) { 83 // Set the register values. The values are not important as there are no 84 // callee saved registers in JavaScript frames, so all registers are 85 // spilled. Registers fp and sp are set to the correct values though. 86 87 for (int i = 0; i < Register::kNumRegisters; i++) { 88 input_->SetRegister(i, i * 4); 89 } 90 input_->SetRegister(sp.code(), reinterpret_cast<intptr_t>(frame->sp())); 91 input_->SetRegister(fp.code(), reinterpret_cast<intptr_t>(frame->fp())); 92 for (int i = 0; i < DoubleRegister::NumAllocatableRegisters(); i++) { 93 input_->SetDoubleRegister(i, 0.0); 94 } 95 96 // Fill the frame content from the actual data on the frame. 97 for (unsigned i = 0; i < input_->GetFrameSize(); i += kPointerSize) { 98 input_->SetFrameSlot(i, Memory::uint32_at(tos + i)); 99 } 100} 101 102 103void Deoptimizer::SetPlatformCompiledStubRegisters( 104 FrameDescription* output_frame, CodeStubDescriptor* descriptor) { 105 ApiFunction function(descriptor->deoptimization_handler()); 106 ExternalReference xref(&function, ExternalReference::BUILTIN_CALL, isolate_); 107 intptr_t handler = reinterpret_cast<intptr_t>(xref.address()); 108 int params = descriptor->GetHandlerParameterCount(); 109 output_frame->SetRegister(r0.code(), params); 110 output_frame->SetRegister(r1.code(), handler); 111} 112 113 114void Deoptimizer::CopyDoubleRegisters(FrameDescription* output_frame) { 115 for (int i = 0; i < DwVfpRegister::kMaxNumRegisters; ++i) { 116 double double_value = input_->GetDoubleRegister(i); 117 output_frame->SetDoubleRegister(i, double_value); 118 } 119} 120 121 122bool Deoptimizer::HasAlignmentPadding(JSFunction* function) { 123 // There is no dynamic alignment padding on ARM in the input frame. 124 return false; 125} 126 127 128#define __ masm()-> 129 130// This code tries to be close to ia32 code so that any changes can be 131// easily ported. 132void Deoptimizer::EntryGenerator::Generate() { 133 GeneratePrologue(); 134 135 // Save all general purpose registers before messing with them. 136 const int kNumberOfRegisters = Register::kNumRegisters; 137 138 // Everything but pc, lr and ip which will be saved but not restored. 139 RegList restored_regs = kJSCallerSaved | kCalleeSaved | ip.bit(); 140 141 const int kDoubleRegsSize = 142 kDoubleSize * DwVfpRegister::kMaxNumAllocatableRegisters; 143 144 // Save all allocatable VFP registers before messing with them. 145 DCHECK(kDoubleRegZero.code() == 14); 146 DCHECK(kScratchDoubleReg.code() == 15); 147 148 // Check CPU flags for number of registers, setting the Z condition flag. 149 __ CheckFor32DRegs(ip); 150 151 // Push registers d0-d13, and possibly d16-d31, on the stack. 152 // If d16-d31 are not pushed, decrease the stack pointer instead. 153 __ vstm(db_w, sp, d16, d31, ne); 154 __ sub(sp, sp, Operand(16 * kDoubleSize), LeaveCC, eq); 155 __ vstm(db_w, sp, d0, d13); 156 157 // Push all 16 registers (needed to populate FrameDescription::registers_). 158 // TODO(1588) Note that using pc with stm is deprecated, so we should perhaps 159 // handle this a bit differently. 160 __ stm(db_w, sp, restored_regs | sp.bit() | lr.bit() | pc.bit()); 161 162 const int kSavedRegistersAreaSize = 163 (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize; 164 165 // Get the bailout id from the stack. 166 __ ldr(r2, MemOperand(sp, kSavedRegistersAreaSize)); 167 168 // Get the address of the location in the code object (r3) (return 169 // address for lazy deoptimization) and compute the fp-to-sp delta in 170 // register r4. 171 __ mov(r3, lr); 172 // Correct one word for bailout id. 173 __ add(r4, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize))); 174 __ sub(r4, fp, r4); 175 176 // Allocate a new deoptimizer object. 177 // Pass four arguments in r0 to r3 and fifth argument on stack. 178 __ PrepareCallCFunction(6, r5); 179 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 180 __ mov(r1, Operand(type())); // bailout type, 181 // r2: bailout id already loaded. 182 // r3: code address or 0 already loaded. 183 __ str(r4, MemOperand(sp, 0 * kPointerSize)); // Fp-to-sp delta. 184 __ mov(r5, Operand(ExternalReference::isolate_address(isolate()))); 185 __ str(r5, MemOperand(sp, 1 * kPointerSize)); // Isolate. 186 // Call Deoptimizer::New(). 187 { 188 AllowExternalCallThatCantCauseGC scope(masm()); 189 __ CallCFunction(ExternalReference::new_deoptimizer_function(isolate()), 6); 190 } 191 192 // Preserve "deoptimizer" object in register r0 and get the input 193 // frame descriptor pointer to r1 (deoptimizer->input_); 194 __ ldr(r1, MemOperand(r0, Deoptimizer::input_offset())); 195 196 // Copy core registers into FrameDescription::registers_[kNumRegisters]. 197 DCHECK(Register::kNumRegisters == kNumberOfRegisters); 198 for (int i = 0; i < kNumberOfRegisters; i++) { 199 int offset = (i * kPointerSize) + FrameDescription::registers_offset(); 200 __ ldr(r2, MemOperand(sp, i * kPointerSize)); 201 __ str(r2, MemOperand(r1, offset)); 202 } 203 204 // Copy VFP registers to 205 // double_registers_[DoubleRegister::kMaxNumAllocatableRegisters] 206 int double_regs_offset = FrameDescription::double_registers_offset(); 207 for (int i = 0; i < DwVfpRegister::kMaxNumAllocatableRegisters; ++i) { 208 int dst_offset = i * kDoubleSize + double_regs_offset; 209 int src_offset = i * kDoubleSize + kNumberOfRegisters * kPointerSize; 210 __ vldr(d0, sp, src_offset); 211 __ vstr(d0, r1, dst_offset); 212 } 213 214 // Remove the bailout id and the saved registers from the stack. 215 __ add(sp, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize))); 216 217 // Compute a pointer to the unwinding limit in register r2; that is 218 // the first stack slot not part of the input frame. 219 __ ldr(r2, MemOperand(r1, FrameDescription::frame_size_offset())); 220 __ add(r2, r2, sp); 221 222 // Unwind the stack down to - but not including - the unwinding 223 // limit and copy the contents of the activation frame to the input 224 // frame description. 225 __ add(r3, r1, Operand(FrameDescription::frame_content_offset())); 226 Label pop_loop; 227 Label pop_loop_header; 228 __ b(&pop_loop_header); 229 __ bind(&pop_loop); 230 __ pop(r4); 231 __ str(r4, MemOperand(r3, 0)); 232 __ add(r3, r3, Operand(sizeof(uint32_t))); 233 __ bind(&pop_loop_header); 234 __ cmp(r2, sp); 235 __ b(ne, &pop_loop); 236 237 // Compute the output frame in the deoptimizer. 238 __ push(r0); // Preserve deoptimizer object across call. 239 // r0: deoptimizer object; r1: scratch. 240 __ PrepareCallCFunction(1, r1); 241 // Call Deoptimizer::ComputeOutputFrames(). 242 { 243 AllowExternalCallThatCantCauseGC scope(masm()); 244 __ CallCFunction( 245 ExternalReference::compute_output_frames_function(isolate()), 1); 246 } 247 __ pop(r0); // Restore deoptimizer object (class Deoptimizer). 248 249 // Replace the current (input) frame with the output frames. 250 Label outer_push_loop, inner_push_loop, 251 outer_loop_header, inner_loop_header; 252 // Outer loop state: r4 = current "FrameDescription** output_", 253 // r1 = one past the last FrameDescription**. 254 __ ldr(r1, MemOperand(r0, Deoptimizer::output_count_offset())); 255 __ ldr(r4, MemOperand(r0, Deoptimizer::output_offset())); // r4 is output_. 256 __ add(r1, r4, Operand(r1, LSL, 2)); 257 __ jmp(&outer_loop_header); 258 __ bind(&outer_push_loop); 259 // Inner loop state: r2 = current FrameDescription*, r3 = loop index. 260 __ ldr(r2, MemOperand(r4, 0)); // output_[ix] 261 __ ldr(r3, MemOperand(r2, FrameDescription::frame_size_offset())); 262 __ jmp(&inner_loop_header); 263 __ bind(&inner_push_loop); 264 __ sub(r3, r3, Operand(sizeof(uint32_t))); 265 __ add(r6, r2, Operand(r3)); 266 __ ldr(r6, MemOperand(r6, FrameDescription::frame_content_offset())); 267 __ push(r6); 268 __ bind(&inner_loop_header); 269 __ cmp(r3, Operand::Zero()); 270 __ b(ne, &inner_push_loop); // test for gt? 271 __ add(r4, r4, Operand(kPointerSize)); 272 __ bind(&outer_loop_header); 273 __ cmp(r4, r1); 274 __ b(lt, &outer_push_loop); 275 276 // Check CPU flags for number of registers, setting the Z condition flag. 277 __ CheckFor32DRegs(ip); 278 279 __ ldr(r1, MemOperand(r0, Deoptimizer::input_offset())); 280 int src_offset = FrameDescription::double_registers_offset(); 281 for (int i = 0; i < DwVfpRegister::kMaxNumRegisters; ++i) { 282 if (i == kDoubleRegZero.code()) continue; 283 if (i == kScratchDoubleReg.code()) continue; 284 285 const DwVfpRegister reg = DwVfpRegister::from_code(i); 286 __ vldr(reg, r1, src_offset, i < 16 ? al : ne); 287 src_offset += kDoubleSize; 288 } 289 290 // Push state, pc, and continuation from the last output frame. 291 __ ldr(r6, MemOperand(r2, FrameDescription::state_offset())); 292 __ push(r6); 293 __ ldr(r6, MemOperand(r2, FrameDescription::pc_offset())); 294 __ push(r6); 295 __ ldr(r6, MemOperand(r2, FrameDescription::continuation_offset())); 296 __ push(r6); 297 298 // Push the registers from the last output frame. 299 for (int i = kNumberOfRegisters - 1; i >= 0; i--) { 300 int offset = (i * kPointerSize) + FrameDescription::registers_offset(); 301 __ ldr(r6, MemOperand(r2, offset)); 302 __ push(r6); 303 } 304 305 // Restore the registers from the stack. 306 __ ldm(ia_w, sp, restored_regs); // all but pc registers. 307 __ pop(ip); // remove sp 308 __ pop(ip); // remove lr 309 310 __ InitializeRootRegister(); 311 312 __ pop(ip); // remove pc 313 __ pop(ip); // get continuation, leave pc on stack 314 __ pop(lr); 315 __ Jump(ip); 316 __ stop("Unreachable."); 317} 318 319 320void Deoptimizer::TableEntryGenerator::GeneratePrologue() { 321 // Create a sequence of deoptimization entries. 322 // Note that registers are still live when jumping to an entry. 323 Label done; 324 for (int i = 0; i < count(); i++) { 325 int start = masm()->pc_offset(); 326 USE(start); 327 __ mov(ip, Operand(i)); 328 __ b(&done); 329 DCHECK(masm()->pc_offset() - start == table_entry_size_); 330 } 331 __ bind(&done); 332 __ push(ip); 333} 334 335 336void FrameDescription::SetCallerPc(unsigned offset, intptr_t value) { 337 SetFrameSlot(offset, value); 338} 339 340 341void FrameDescription::SetCallerFp(unsigned offset, intptr_t value) { 342 SetFrameSlot(offset, value); 343} 344 345 346void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) { 347 DCHECK(FLAG_enable_ool_constant_pool); 348 SetFrameSlot(offset, value); 349} 350 351 352#undef __ 353 354} } // namespace v8::internal 355