144f0eee88ff00398ff7f715fab053374d808c90dSteve Block// Copyright 2011 the V8 project authors. All rights reserved. 2b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// found in the LICENSE file. 4b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 5b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/codegen.h" 6b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/deoptimizer.h" 7014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/full-codegen/full-codegen.h" 8014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch#include "src/register-configuration.h" 9b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/safepoint-table.h" 10f7060e27768c550ace7ec48ad8c093466db52dfaLeon Clarke 113100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescunamespace v8 { 123100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescunamespace internal { 133100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu 143100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu 1544f0eee88ff00398ff7f715fab053374d808c90dSteve Blockint Deoptimizer::patch_size() { 163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const int kCallInstructionSizeInWords = 4; 1744f0eee88ff00398ff7f715fab053374d808c90dSteve Block return kCallInstructionSizeInWords * Assembler::kInstrSize; 183100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu} 193100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu 203100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu 21958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Berniervoid Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(Handle<Code> code) { 22958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier // Empty because there is no need for relocation information for the code 23958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier // patching in Deoptimizer::PatchCodeForDeoptimization below. 24958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier} 25958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier 26958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier 27b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Deoptimizer::PatchCodeForDeoptimization(Isolate* isolate, Code* code) { 283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Address code_start_address = code->instruction_start(); 293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Invalidate the relocation information, as it will become invalid by the 303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // code patching below, and is not needed any more. 313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch code->InvalidateRelocation(); 323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 33b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (FLAG_zap_code_space) { 34b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Fail hard and early if we enter this code object again. 35b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch byte* pointer = code->FindCodeAgeSequence(); 36b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (pointer != NULL) { 37b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch pointer += kNoCodeAgeSequenceLength; 38b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } else { 39b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch pointer = code->instruction_start(); 40b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 41014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch CodePatcher patcher(isolate, pointer, 1); 42b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch patcher.masm()->break_(0xCC); 43b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 44b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DeoptimizationInputData* data = 45b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DeoptimizationInputData::cast(code->deoptimization_data()); 46b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch int osr_offset = data->OsrPcOffset()->value(); 47b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (osr_offset > 0) { 48014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch CodePatcher osr_patcher(isolate, code->instruction_start() + osr_offset, 49014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 1); 50b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch osr_patcher.masm()->break_(0xCC); 51b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 52b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 53b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch DeoptimizationInputData* deopt_data = 553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch DeoptimizationInputData::cast(code->deoptimization_data()); 563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#ifdef DEBUG 573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Address prev_call_address = NULL; 583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#endif 59b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // For each LLazyBailout instruction insert a call to the corresponding 60b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // deoptimization entry. 613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch for (int i = 0; i < deopt_data->DeoptCount(); i++) { 623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if (deopt_data->Pc(i)->value() == -1) continue; 633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Address call_address = code_start_address + deopt_data->Pc(i)->value(); 64b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Address deopt_entry = GetDeoptimizationEntry(isolate, i, LAZY); 653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch int call_size_in_bytes = MacroAssembler::CallSize(deopt_entry, 66b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch RelocInfo::NONE32); 673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch int call_size_in_words = call_size_in_bytes / Assembler::kInstrSize; 68b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(call_size_in_bytes % Assembler::kInstrSize == 0); 69b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(call_size_in_bytes <= patch_size()); 70014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch CodePatcher patcher(isolate, call_address, call_size_in_words); 71b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch patcher.masm()->Call(deopt_entry, RelocInfo::NONE32); 72b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(prev_call_address == NULL || 733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch call_address >= prev_call_address + patch_size()); 74b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(call_address + patch_size() <= code->instruction_end()); 753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#ifdef DEBUG 773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch prev_call_address = call_address; 783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#endif 793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch} 813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 83b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Deoptimizer::SetPlatformCompiledStubRegisters( 84b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch FrameDescription* output_frame, CodeStubDescriptor* descriptor) { 85b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ApiFunction function(descriptor->deoptimization_handler()); 86b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ExternalReference xref(&function, ExternalReference::BUILTIN_CALL, isolate_); 87b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch intptr_t handler = reinterpret_cast<intptr_t>(xref.address()); 88b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch int params = descriptor->GetHandlerParameterCount(); 89958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier output_frame->SetRegister(a0.code(), params); 90958fae7ec3f466955f8e5b50fa5b8d38b9e91675Emily Bernier output_frame->SetRegister(a1.code(), handler); 91b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 92b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 93b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 94b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Deoptimizer::CopyDoubleRegisters(FrameDescription* output_frame) { 95b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch for (int i = 0; i < DoubleRegister::kMaxNumRegisters; ++i) { 9662ed631aa0ff23db68a47fd423efa9c019ff2c9eBen Murdoch Float64 double_value = input_->GetDoubleRegister(i); 97b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch output_frame->SetDoubleRegister(i, double_value); 98b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 99b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 100b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 1013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#define __ masm()-> 1023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 1033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 1043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// This code tries to be close to ia32 code so that any changes can be 1053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// easily ported. 106014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Deoptimizer::TableEntryGenerator::Generate() { 1073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch GeneratePrologue(); 1083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 1093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Unlike on ARM we don't save all the registers, just the useful ones. 1103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // For the rest, there are gaps on the stack, so the offsets remain the same. 1113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const int kNumberOfRegisters = Register::kNumRegisters; 1123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 1133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch RegList restored_regs = kJSCallerSaved | kCalleeSaved; 1143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch RegList saved_regs = restored_regs | sp.bit() | ra.bit(); 1153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 116014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch const int kDoubleRegsSize = kDoubleSize * DoubleRegister::kMaxNumRegisters; 1173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 1183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Save all FPU registers before messing with them. 1193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Subu(sp, sp, Operand(kDoubleRegsSize)); 12013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch const RegisterConfiguration* config = RegisterConfiguration::Crankshaft(); 121014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch for (int i = 0; i < config->num_allocatable_double_registers(); ++i) { 122014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch int code = config->GetAllocatableDoubleCode(i); 123014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch const DoubleRegister fpu_reg = DoubleRegister::from_code(code); 124014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch int offset = code * kDoubleSize; 1253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sdc1(fpu_reg, MemOperand(sp, offset)); 1263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 1273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 1283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Push saved_regs (needed to populate FrameDescription::registers_). 1293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Leave gaps for other registers. 1303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Subu(sp, sp, kNumberOfRegisters * kPointerSize); 1313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch for (int16_t i = kNumberOfRegisters - 1; i >= 0; i--) { 1323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if ((saved_regs & (1 << i)) != 0) { 1333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sw(ToRegister(i), MemOperand(sp, kPointerSize * i)); 1343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 1353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 1363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 137014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch __ li(a2, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate()))); 138014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch __ sw(fp, MemOperand(a2)); 139014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 1403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch const int kSavedRegistersAreaSize = 1413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize; 1423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 1433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Get the bailout id from the stack. 1443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ lw(a2, MemOperand(sp, kSavedRegistersAreaSize)); 1453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 146b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Get the address of the location in the code object (a3) (return 1473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // address for lazy deoptimization) and compute the fp-to-sp delta in 1483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // register t0. 149b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ mov(a3, ra); 150b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Correct one word for bailout id. 151b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Addu(t0, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize))); 1523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 1533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Subu(t0, fp, t0); 1543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 1553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Allocate a new deoptimizer object. 1563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ PrepareCallCFunction(6, t1); 1573b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch // Pass four arguments in a0 to a3 and fifth & sixth arguments on stack. 1583b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch __ mov(a0, zero_reg); 1593b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch Label context_check; 1603b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch __ lw(a1, MemOperand(fp, CommonFrameConstants::kContextOrFrameTypeOffset)); 1613b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch __ JumpIfSmi(a1, &context_check); 1623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ lw(a0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 1633b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch __ bind(&context_check); 1643b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch __ li(a1, Operand(type())); // Bailout type. 1653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // a2: bailout id already loaded. 1663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // a3: code address or 0 already loaded. 1673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sw(t0, CFunctionArgumentOperand(5)); // Fp-to-sp delta. 168b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ li(t1, Operand(ExternalReference::isolate_address(isolate()))); 1693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sw(t1, CFunctionArgumentOperand(6)); // Isolate. 1703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Call Deoptimizer::New(). 1713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { 1723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch AllowExternalCallThatCantCauseGC scope(masm()); 173b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ CallCFunction(ExternalReference::new_deoptimizer_function(isolate()), 6); 1743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 1753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 1763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Preserve "deoptimizer" object in register v0 and get the input 1773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // frame descriptor pointer to a1 (deoptimizer->input_); 1783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Move deopt-obj to a0 for call to Deoptimizer::ComputeOutputFrames() below. 1793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(a0, v0); 1803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ lw(a1, MemOperand(v0, Deoptimizer::input_offset())); 1813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 1823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Copy core registers into FrameDescription::registers_[kNumRegisters]. 183b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(Register::kNumRegisters == kNumberOfRegisters); 1843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch for (int i = 0; i < kNumberOfRegisters; i++) { 1853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch int offset = (i * kPointerSize) + FrameDescription::registers_offset(); 1863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if ((saved_regs & (1 << i)) != 0) { 1873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ lw(a2, MemOperand(sp, i * kPointerSize)); 1883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sw(a2, MemOperand(a1, offset)); 1893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } else if (FLAG_debug_code) { 1903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ li(a2, kDebugZapValue); 1913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sw(a2, MemOperand(a1, offset)); 1923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 1933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 1943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 195b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch int double_regs_offset = FrameDescription::double_registers_offset(); 1963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Copy FPU registers to 1973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // double_registers_[DoubleRegister::kNumAllocatableRegisters] 198014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch for (int i = 0; i < config->num_allocatable_double_registers(); ++i) { 199014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch int code = config->GetAllocatableDoubleCode(i); 200014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch int dst_offset = code * kDoubleSize + double_regs_offset; 201014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch int src_offset = code * kDoubleSize + kNumberOfRegisters * kPointerSize; 2023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ ldc1(f0, MemOperand(sp, src_offset)); 2033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sdc1(f0, MemOperand(a1, dst_offset)); 2043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 2053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 206b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Remove the bailout id and the saved registers from the stack. 207b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Addu(sp, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize))); 2083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Compute a pointer to the unwinding limit in register a2; that is 2103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // the first stack slot not part of the input frame. 2113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ lw(a2, MemOperand(a1, FrameDescription::frame_size_offset())); 2123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Addu(a2, a2, sp); 2133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Unwind the stack down to - but not including - the unwinding 2153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // limit and copy the contents of the activation frame to the input 2163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // frame description. 2173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Addu(a3, a1, Operand(FrameDescription::frame_content_offset())); 2183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Label pop_loop; 219b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label pop_loop_header; 220b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ BranchShort(&pop_loop_header); 2213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&pop_loop); 2223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ pop(t0); 2233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ sw(t0, MemOperand(a3, 0)); 224b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ addiu(a3, a3, sizeof(uint32_t)); 225b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ bind(&pop_loop_header); 226b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ BranchShort(&pop_loop, ne, a2, Operand(sp)); 2273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Compute the output frame in the deoptimizer. 2293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(a0); // Preserve deoptimizer object across call. 2303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // a0: deoptimizer object; a1: scratch. 2313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ PrepareCallCFunction(1, a1); 2323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Call Deoptimizer::ComputeOutputFrames(). 2333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch { 2343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch AllowExternalCallThatCantCauseGC scope(masm()); 2353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ CallCFunction( 236b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ExternalReference::compute_output_frames_function(isolate()), 1); 2373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 2383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ pop(a0); // Restore deoptimizer object (class Deoptimizer). 2393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2403b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch __ lw(sp, MemOperand(a0, Deoptimizer::caller_frame_top_offset())); 2413b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 2423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Replace the current (input) frame with the output frames. 243b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label outer_push_loop, inner_push_loop, 244b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch outer_loop_header, inner_loop_header; 245b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Outer loop state: t0 = current "FrameDescription** output_", 2463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // a1 = one past the last FrameDescription**. 2473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ lw(a1, MemOperand(a0, Deoptimizer::output_count_offset())); 248b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ lw(t0, MemOperand(a0, Deoptimizer::output_offset())); // t0 is output_. 249109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch __ Lsa(a1, t0, a1, kPointerSizeLog2); 250014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch __ BranchShort(&outer_loop_header); 2513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&outer_push_loop); 2523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Inner loop state: a2 = current FrameDescription*, a3 = loop index. 253b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ lw(a2, MemOperand(t0, 0)); // output_[ix] 2543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ lw(a3, MemOperand(a2, FrameDescription::frame_size_offset())); 255014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch __ BranchShort(&inner_loop_header); 2563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&inner_push_loop); 2573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Subu(a3, a3, Operand(sizeof(uint32_t))); 2583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Addu(t2, a2, Operand(a3)); 2593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ lw(t3, MemOperand(t2, FrameDescription::frame_content_offset())); 2603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(t3); 261b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ bind(&inner_loop_header); 262b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ BranchShort(&inner_push_loop, ne, a3, Operand(zero_reg)); 2633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 264b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Addu(t0, t0, Operand(kPointerSize)); 265b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ bind(&outer_loop_header); 266b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ BranchShort(&outer_push_loop, lt, t0, Operand(a1)); 2673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 268b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ lw(a1, MemOperand(a0, Deoptimizer::input_offset())); 269014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch for (int i = 0; i < config->num_allocatable_double_registers(); ++i) { 270014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch int code = config->GetAllocatableDoubleCode(i); 271014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch const DoubleRegister fpu_reg = DoubleRegister::from_code(code); 272014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch int src_offset = code * kDoubleSize + double_regs_offset; 273b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ ldc1(fpu_reg, MemOperand(a1, src_offset)); 274b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 2753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Push state, pc, and continuation from the last output frame. 277b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ lw(t2, MemOperand(a2, FrameDescription::state_offset())); 278b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ push(t2); 2793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ lw(t2, MemOperand(a2, FrameDescription::pc_offset())); 2813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(t2); 2823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ lw(t2, MemOperand(a2, FrameDescription::continuation_offset())); 2833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ push(t2); 2843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Technically restoring 'at' should work unless zero_reg is also restored 2873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // but it's safer to check for this. 288b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(!(at.bit() & restored_regs)); 2893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch // Restore the registers from the last output frame. 2903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ mov(at, a2); 2913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch for (int i = kNumberOfRegisters - 1; i >= 0; i--) { 2923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch int offset = (i * kPointerSize) + FrameDescription::registers_offset(); 2933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if ((restored_regs & (1 << i)) != 0) { 2943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ lw(ToRegister(i), MemOperand(at, offset)); 2953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 2963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 2973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ InitializeRootRegister(); 2993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 3003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ pop(at); // Get continuation, leave pc on stack. 3013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ pop(ra); 3023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ Jump(at); 3033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ stop("Unreachable."); 30444f0eee88ff00398ff7f715fab053374d808c90dSteve Block} 3053100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu 3063100271588b61cbc1dc472a3f2f105d2eed8497fAndrei Popescu 3073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// Maximum size of a table entry generated below. 308b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochconst int Deoptimizer::table_entry_size_ = 2 * Assembler::kInstrSize; 3093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 31044f0eee88ff00398ff7f715fab053374d808c90dSteve Blockvoid Deoptimizer::TableEntryGenerator::GeneratePrologue() { 3113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm()); 3123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 313b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Create a sequence of deoptimization entries. 314b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Note that registers are still live when jumping to an entry. 315b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label table_start, done, done_special, trampoline_jump; 3163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch __ bind(&table_start); 317b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch int kMaxEntriesBranchReach = (1 << (kImm16Bits - 2))/ 318b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch (table_entry_size_ / Assembler::kInstrSize); 319b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 320b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (count() <= kMaxEntriesBranchReach) { 321b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Common case. 322b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch for (int i = 0; i < count(); i++) { 323b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label start; 324b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ bind(&start); 325b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(is_int16(i)); 326014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch __ BranchShort(USE_DELAY_SLOT, &done); // Expose delay slot. 327b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ li(at, i); // In the delay slot. 328b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 329b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK_EQ(table_entry_size_, masm()->SizeOfCodeGeneratedSince(&start)); 3303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 331b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 332b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK_EQ(masm()->SizeOfCodeGeneratedSince(&table_start), 333b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch count() * table_entry_size_); 334b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ bind(&done); 335b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Push(at); 336b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } else { 337b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Uncommon case, the branch cannot reach. 338b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Create mini trampoline and adjust id constants to get proper value at 339b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // the end of table. 340b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch for (int i = kMaxEntriesBranchReach; i > 1; i--) { 341b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label start; 342b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ bind(&start); 343b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(is_int16(i)); 344014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch __ BranchShort(USE_DELAY_SLOT, &trampoline_jump); // Expose delay slot. 345b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ li(at, - i); // In the delay slot. 346b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK_EQ(table_entry_size_, masm()->SizeOfCodeGeneratedSince(&start)); 347b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 348b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Entry with id == kMaxEntriesBranchReach - 1. 349b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ bind(&trampoline_jump); 350014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch __ BranchShort(USE_DELAY_SLOT, &done_special); 351b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ li(at, -1); 352b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 353b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch for (int i = kMaxEntriesBranchReach ; i < count(); i++) { 354b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label start; 355b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ bind(&start); 356b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(is_int16(i)); 357014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch __ BranchShort(USE_DELAY_SLOT, &done); // Expose delay slot. 358b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ li(at, i); // In the delay slot. 3593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 3603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 361b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK_EQ(masm()->SizeOfCodeGeneratedSince(&table_start), 362b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch count() * table_entry_size_); 363b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ bind(&done_special); 364b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ addiu(at, at, kMaxEntriesBranchReach); 365b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ bind(&done); 366b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Push(at); 3673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch } 368b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 3693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 370b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 371b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid FrameDescription::SetCallerPc(unsigned offset, intptr_t value) { 372b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch SetFrameSlot(offset, value); 37344f0eee88ff00398ff7f715fab053374d808c90dSteve Block} 37444f0eee88ff00398ff7f715fab053374d808c90dSteve Block 375b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 376b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid FrameDescription::SetCallerFp(unsigned offset, intptr_t value) { 377b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch SetFrameSlot(offset, value); 378b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 379b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 380b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 381b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) { 382014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // No embedded constant pool support. 383b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch UNREACHABLE(); 384b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 385b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 386b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 3873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch#undef __ 3883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 38944f0eee88ff00398ff7f715fab053374d808c90dSteve Block 390014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch} // namespace internal 391014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch} // namespace v8 392