1// Copyright 2011 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/codegen.h" 6#include "src/deoptimizer.h" 7#include "src/full-codegen/full-codegen.h" 8#include "src/register-configuration.h" 9#include "src/safepoint-table.h" 10 11namespace v8 { 12namespace internal { 13 14 15int Deoptimizer::patch_size() { 16 const int kCallInstructionSizeInWords = 6; 17 return kCallInstructionSizeInWords * Assembler::kInstrSize; 18} 19 20 21void Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code) { 22 // Empty because there is no need for relocation information for the code 23 // patching in Deoptimizer::PatchCodeForDeoptimization below. 24} 25 26 27void Deoptimizer::PatchCodeForDeoptimization(Isolate* isolate, Code* code) { 28 Address code_start_address = code->instruction_start(); 29 // Invalidate the relocation information, as it will become invalid by the 30 // code patching below, and is not needed any more. 31 code->InvalidateRelocation(); 32 33 if (FLAG_zap_code_space) { 34 // Fail hard and early if we enter this code object again. 35 byte* pointer = code->FindCodeAgeSequence(); 36 if (pointer != NULL) { 37 pointer += kNoCodeAgeSequenceLength; 38 } else { 39 pointer = code->instruction_start(); 40 } 41 CodePatcher patcher(isolate, pointer, 1); 42 patcher.masm()->break_(0xCC); 43 44 DeoptimizationInputData* data = 45 DeoptimizationInputData::cast(code->deoptimization_data()); 46 int osr_offset = data->OsrPcOffset()->value(); 47 if (osr_offset > 0) { 48 CodePatcher osr_patcher(isolate, code->instruction_start() + osr_offset, 49 1); 50 osr_patcher.masm()->break_(0xCC); 51 } 52 } 53 54 DeoptimizationInputData* deopt_data = 55 DeoptimizationInputData::cast(code->deoptimization_data()); 56#ifdef DEBUG 57 Address prev_call_address = NULL; 58#endif 59 // For each LLazyBailout instruction insert a call to the corresponding 60 // deoptimization entry. 61 for (int i = 0; i < deopt_data->DeoptCount(); i++) { 62 if (deopt_data->Pc(i)->value() == -1) continue; 63 Address call_address = code_start_address + deopt_data->Pc(i)->value(); 64 Address deopt_entry = GetDeoptimizationEntry(isolate, i, LAZY); 65 int call_size_in_bytes = MacroAssembler::CallSize(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(isolate, 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 76#ifdef DEBUG 77 prev_call_address = call_address; 78#endif 79 } 80} 81 82 83void Deoptimizer::SetPlatformCompiledStubRegisters( 84 FrameDescription* output_frame, CodeStubDescriptor* descriptor) { 85 ApiFunction function(descriptor->deoptimization_handler()); 86 ExternalReference xref(&function, ExternalReference::BUILTIN_CALL, isolate_); 87 intptr_t handler = reinterpret_cast<intptr_t>(xref.address()); 88 int params = descriptor->GetHandlerParameterCount(); 89 output_frame->SetRegister(a0.code(), params); 90 output_frame->SetRegister(a1.code(), handler); 91} 92 93 94void Deoptimizer::CopyDoubleRegisters(FrameDescription* output_frame) { 95 for (int i = 0; i < DoubleRegister::kMaxNumRegisters; ++i) { 96 double double_value = input_->GetDoubleRegister(i); 97 output_frame->SetDoubleRegister(i, double_value); 98 } 99} 100 101#define __ masm()-> 102 103 104// This code tries to be close to ia32 code so that any changes can be 105// easily ported. 106void Deoptimizer::TableEntryGenerator::Generate() { 107 GeneratePrologue(); 108 109 // Unlike on ARM we don't save all the registers, just the useful ones. 110 // For the rest, there are gaps on the stack, so the offsets remain the same. 111 const int kNumberOfRegisters = Register::kNumRegisters; 112 113 RegList restored_regs = kJSCallerSaved | kCalleeSaved; 114 RegList saved_regs = restored_regs | sp.bit() | ra.bit(); 115 116 const int kDoubleRegsSize = kDoubleSize * DoubleRegister::kMaxNumRegisters; 117 118 // Save all FPU registers before messing with them. 119 __ Dsubu(sp, sp, Operand(kDoubleRegsSize)); 120 const RegisterConfiguration* config = RegisterConfiguration::Crankshaft(); 121 for (int i = 0; i < config->num_allocatable_double_registers(); ++i) { 122 int code = config->GetAllocatableDoubleCode(i); 123 const DoubleRegister fpu_reg = DoubleRegister::from_code(code); 124 int offset = code * kDoubleSize; 125 __ sdc1(fpu_reg, MemOperand(sp, offset)); 126 } 127 128 // Push saved_regs (needed to populate FrameDescription::registers_). 129 // Leave gaps for other registers. 130 __ Dsubu(sp, sp, kNumberOfRegisters * kPointerSize); 131 for (int16_t i = kNumberOfRegisters - 1; i >= 0; i--) { 132 if ((saved_regs & (1 << i)) != 0) { 133 __ sd(ToRegister(i), MemOperand(sp, kPointerSize * i)); 134 } 135 } 136 137 __ li(a2, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate()))); 138 __ sd(fp, MemOperand(a2)); 139 140 const int kSavedRegistersAreaSize = 141 (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize; 142 143 // Get the bailout id from the stack. 144 __ ld(a2, MemOperand(sp, kSavedRegistersAreaSize)); 145 146 // Get the address of the location in the code object (a3) (return 147 // address for lazy deoptimization) and compute the fp-to-sp delta in 148 // register a4. 149 __ mov(a3, ra); 150 // Correct one word for bailout id. 151 __ Daddu(a4, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize))); 152 153 __ Dsubu(a4, fp, a4); 154 155 // Allocate a new deoptimizer object. 156 __ PrepareCallCFunction(6, a5); 157 // Pass six arguments, according to n64 ABI. 158 __ mov(a0, zero_reg); 159 Label context_check; 160 __ ld(a1, MemOperand(fp, CommonFrameConstants::kContextOrFrameTypeOffset)); 161 __ JumpIfSmi(a1, &context_check); 162 __ ld(a0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 163 __ bind(&context_check); 164 __ li(a1, Operand(type())); // Bailout type. 165 // a2: bailout id already loaded. 166 // a3: code address or 0 already loaded. 167 // a4: already has fp-to-sp delta. 168 __ li(a5, Operand(ExternalReference::isolate_address(isolate()))); 169 170 // Call Deoptimizer::New(). 171 { 172 AllowExternalCallThatCantCauseGC scope(masm()); 173 __ CallCFunction(ExternalReference::new_deoptimizer_function(isolate()), 6); 174 } 175 176 // Preserve "deoptimizer" object in register v0 and get the input 177 // frame descriptor pointer to a1 (deoptimizer->input_); 178 // Move deopt-obj to a0 for call to Deoptimizer::ComputeOutputFrames() below. 179 __ mov(a0, v0); 180 __ ld(a1, MemOperand(v0, Deoptimizer::input_offset())); 181 182 // Copy core registers into FrameDescription::registers_[kNumRegisters]. 183 DCHECK(Register::kNumRegisters == kNumberOfRegisters); 184 for (int i = 0; i < kNumberOfRegisters; i++) { 185 int offset = (i * kPointerSize) + FrameDescription::registers_offset(); 186 if ((saved_regs & (1 << i)) != 0) { 187 __ ld(a2, MemOperand(sp, i * kPointerSize)); 188 __ sd(a2, MemOperand(a1, offset)); 189 } else if (FLAG_debug_code) { 190 __ li(a2, kDebugZapValue); 191 __ sd(a2, MemOperand(a1, offset)); 192 } 193 } 194 195 int double_regs_offset = FrameDescription::double_registers_offset(); 196 // Copy FPU registers to 197 // double_registers_[DoubleRegister::kNumAllocatableRegisters] 198 for (int i = 0; i < config->num_allocatable_double_registers(); ++i) { 199 int code = config->GetAllocatableDoubleCode(i); 200 int dst_offset = code * kDoubleSize + double_regs_offset; 201 int src_offset = code * kDoubleSize + kNumberOfRegisters * kPointerSize; 202 __ ldc1(f0, MemOperand(sp, src_offset)); 203 __ sdc1(f0, MemOperand(a1, dst_offset)); 204 } 205 206 // Remove the bailout id and the saved registers from the stack. 207 __ Daddu(sp, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize))); 208 209 // Compute a pointer to the unwinding limit in register a2; that is 210 // the first stack slot not part of the input frame. 211 __ ld(a2, MemOperand(a1, FrameDescription::frame_size_offset())); 212 __ Daddu(a2, a2, sp); 213 214 // Unwind the stack down to - but not including - the unwinding 215 // limit and copy the contents of the activation frame to the input 216 // frame description. 217 __ Daddu(a3, a1, Operand(FrameDescription::frame_content_offset())); 218 Label pop_loop; 219 Label pop_loop_header; 220 __ BranchShort(&pop_loop_header); 221 __ bind(&pop_loop); 222 __ pop(a4); 223 __ sd(a4, MemOperand(a3, 0)); 224 __ daddiu(a3, a3, sizeof(uint64_t)); 225 __ bind(&pop_loop_header); 226 __ BranchShort(&pop_loop, ne, a2, Operand(sp)); 227 // Compute the output frame in the deoptimizer. 228 __ push(a0); // Preserve deoptimizer object across call. 229 // a0: deoptimizer object; a1: scratch. 230 __ PrepareCallCFunction(1, a1); 231 // Call Deoptimizer::ComputeOutputFrames(). 232 { 233 AllowExternalCallThatCantCauseGC scope(masm()); 234 __ CallCFunction( 235 ExternalReference::compute_output_frames_function(isolate()), 1); 236 } 237 __ pop(a0); // Restore deoptimizer object (class Deoptimizer). 238 239 __ ld(sp, MemOperand(a0, Deoptimizer::caller_frame_top_offset())); 240 241 // Replace the current (input) frame with the output frames. 242 Label outer_push_loop, inner_push_loop, 243 outer_loop_header, inner_loop_header; 244 // Outer loop state: a4 = current "FrameDescription** output_", 245 // a1 = one past the last FrameDescription**. 246 __ lw(a1, MemOperand(a0, Deoptimizer::output_count_offset())); 247 __ ld(a4, MemOperand(a0, Deoptimizer::output_offset())); // a4 is output_. 248 __ Dlsa(a1, a4, a1, kPointerSizeLog2); 249 __ BranchShort(&outer_loop_header); 250 __ bind(&outer_push_loop); 251 // Inner loop state: a2 = current FrameDescription*, a3 = loop index. 252 __ ld(a2, MemOperand(a4, 0)); // output_[ix] 253 __ ld(a3, MemOperand(a2, FrameDescription::frame_size_offset())); 254 __ BranchShort(&inner_loop_header); 255 __ bind(&inner_push_loop); 256 __ Dsubu(a3, a3, Operand(sizeof(uint64_t))); 257 __ Daddu(a6, a2, Operand(a3)); 258 __ ld(a7, MemOperand(a6, FrameDescription::frame_content_offset())); 259 __ push(a7); 260 __ bind(&inner_loop_header); 261 __ BranchShort(&inner_push_loop, ne, a3, Operand(zero_reg)); 262 263 __ Daddu(a4, a4, Operand(kPointerSize)); 264 __ bind(&outer_loop_header); 265 __ BranchShort(&outer_push_loop, lt, a4, Operand(a1)); 266 267 __ ld(a1, MemOperand(a0, Deoptimizer::input_offset())); 268 for (int i = 0; i < config->num_allocatable_double_registers(); ++i) { 269 int code = config->GetAllocatableDoubleCode(i); 270 const DoubleRegister fpu_reg = DoubleRegister::from_code(code); 271 int src_offset = code * kDoubleSize + double_regs_offset; 272 __ ldc1(fpu_reg, MemOperand(a1, src_offset)); 273 } 274 275 // Push state, pc, and continuation from the last output frame. 276 __ ld(a6, MemOperand(a2, FrameDescription::state_offset())); 277 __ push(a6); 278 279 __ ld(a6, MemOperand(a2, FrameDescription::pc_offset())); 280 __ push(a6); 281 __ ld(a6, MemOperand(a2, FrameDescription::continuation_offset())); 282 __ push(a6); 283 284 285 // Technically restoring 'at' should work unless zero_reg is also restored 286 // but it's safer to check for this. 287 DCHECK(!(at.bit() & restored_regs)); 288 // Restore the registers from the last output frame. 289 __ mov(at, a2); 290 for (int i = kNumberOfRegisters - 1; i >= 0; i--) { 291 int offset = (i * kPointerSize) + FrameDescription::registers_offset(); 292 if ((restored_regs & (1 << i)) != 0) { 293 __ ld(ToRegister(i), MemOperand(at, offset)); 294 } 295 } 296 297 __ InitializeRootRegister(); 298 299 __ pop(at); // Get continuation, leave pc on stack. 300 __ pop(ra); 301 __ Jump(at); 302 __ stop("Unreachable."); 303} 304 305 306// Maximum size of a table entry generated below. 307const int Deoptimizer::table_entry_size_ = 2 * Assembler::kInstrSize; 308 309void Deoptimizer::TableEntryGenerator::GeneratePrologue() { 310 Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm()); 311 312 // Create a sequence of deoptimization entries. 313 // Note that registers are still live when jumping to an entry. 314 Label table_start, done, done_special, trampoline_jump; 315 __ bind(&table_start); 316 int kMaxEntriesBranchReach = 317 (1 << (kImm16Bits - 2)) / (table_entry_size_ / Assembler::kInstrSize); 318 319 if (count() <= kMaxEntriesBranchReach) { 320 // Common case. 321 for (int i = 0; i < count(); i++) { 322 Label start; 323 __ bind(&start); 324 DCHECK(is_int16(i)); 325 __ BranchShort(USE_DELAY_SLOT, &done); // Expose delay slot. 326 __ li(at, i); // In the delay slot. 327 328 DCHECK_EQ(table_entry_size_, masm()->SizeOfCodeGeneratedSince(&start)); 329 } 330 331 DCHECK_EQ(masm()->SizeOfCodeGeneratedSince(&table_start), 332 count() * table_entry_size_); 333 __ bind(&done); 334 __ Push(at); 335 } else { 336 // Uncommon case, the branch cannot reach. 337 // Create mini trampoline and adjust id constants to get proper value at 338 // the end of table. 339 for (int i = kMaxEntriesBranchReach; i > 1; i--) { 340 Label start; 341 __ bind(&start); 342 DCHECK(is_int16(i)); 343 __ BranchShort(USE_DELAY_SLOT, &trampoline_jump); // Expose delay slot. 344 __ li(at, -i); // In the delay slot. 345 DCHECK_EQ(table_entry_size_, masm()->SizeOfCodeGeneratedSince(&start)); 346 } 347 // Entry with id == kMaxEntriesBranchReach - 1. 348 __ bind(&trampoline_jump); 349 __ BranchShort(USE_DELAY_SLOT, &done_special); 350 __ li(at, -1); 351 352 for (int i = kMaxEntriesBranchReach; i < count(); i++) { 353 Label start; 354 __ bind(&start); 355 DCHECK(is_int16(i)); 356 __ Branch(USE_DELAY_SLOT, &done); // Expose delay slot. 357 __ li(at, i); // In the delay slot. 358 } 359 360 DCHECK_EQ(masm()->SizeOfCodeGeneratedSince(&table_start), 361 count() * table_entry_size_); 362 __ bind(&done_special); 363 __ daddiu(at, at, kMaxEntriesBranchReach); 364 __ bind(&done); 365 __ Push(at); 366 } 367} 368 369 370void FrameDescription::SetCallerPc(unsigned offset, intptr_t value) { 371 SetFrameSlot(offset, value); 372} 373 374 375void FrameDescription::SetCallerFp(unsigned offset, intptr_t value) { 376 SetFrameSlot(offset, value); 377} 378 379 380void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) { 381 // No embedded constant pool support. 382 UNREACHABLE(); 383} 384 385 386#undef __ 387 388 389} // namespace internal 390} // namespace v8 391