1b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// 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" 10b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 11b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochnamespace v8 { 12b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochnamespace internal { 13b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 14b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 15b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochint Deoptimizer::patch_size() { 16b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch const int kCallInstructionSizeInWords = 6; 17b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch return kCallInstructionSizeInWords * Assembler::kInstrSize; 18b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 19b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 20b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 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) { 28b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Address code_start_address = code->instruction_start(); 29b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Invalidate the relocation information, as it will become invalid by the 30b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // code patching below, and is not needed any more. 31b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch code->InvalidateRelocation(); 32b8a8cc1952d61a2f3a2568848933943a543b5d3eBen 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 54b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DeoptimizationInputData* deopt_data = 55b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DeoptimizationInputData::cast(code->deoptimization_data()); 56b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#ifdef DEBUG 57b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Address prev_call_address = NULL; 58b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#endif 59b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // For each LLazyBailout instruction insert a call to the corresponding 60b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // deoptimization entry. 61b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch for (int i = 0; i < deopt_data->DeoptCount(); i++) { 62b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if (deopt_data->Pc(i)->value() == -1) continue; 63b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Address call_address = code_start_address + deopt_data->Pc(i)->value(); 64b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Address deopt_entry = GetDeoptimizationEntry(isolate, i, LAZY); 65b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch int call_size_in_bytes = MacroAssembler::CallSize(deopt_entry, 66b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch RelocInfo::NONE32); 67b8a8cc1952d61a2f3a2568848933943a543b5d3eBen 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 || 73b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch call_address >= prev_call_address + patch_size()); 74b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(call_address + patch_size() <= code->instruction_end()); 75b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 76b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#ifdef DEBUG 77b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch prev_call_address = call_address; 78b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#endif 79b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 80b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 81b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 82b8a8cc1952d61a2f3a2568848933943a543b5d3eBen 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 101b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#define __ masm()-> 102b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 103b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 104b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// This code tries to be close to ia32 code so that any changes can be 105b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// easily ported. 106014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid Deoptimizer::TableEntryGenerator::Generate() { 107b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch GeneratePrologue(); 108b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 109b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Unlike on ARM we don't save all the registers, just the useful ones. 110b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // For the rest, there are gaps on the stack, so the offsets remain the same. 111b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch const int kNumberOfRegisters = Register::kNumRegisters; 112b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 113b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch RegList restored_regs = kJSCallerSaved | kCalleeSaved; 114b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch RegList saved_regs = restored_regs | sp.bit() | ra.bit(); 115b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 116014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch const int kDoubleRegsSize = kDoubleSize * DoubleRegister::kMaxNumRegisters; 117b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 118b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Save all FPU registers before messing with them. 119b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Dsubu(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; 125b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ sdc1(fpu_reg, MemOperand(sp, offset)); 126b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 127b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 128b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Push saved_regs (needed to populate FrameDescription::registers_). 129b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Leave gaps for other registers. 130b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Dsubu(sp, sp, kNumberOfRegisters * kPointerSize); 131b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch for (int16_t i = kNumberOfRegisters - 1; i >= 0; i--) { 132b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if ((saved_regs & (1 << i)) != 0) { 133b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ sd(ToRegister(i), MemOperand(sp, kPointerSize * i)); 134b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 135b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 136b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 137014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch __ li(a2, Operand(ExternalReference(Isolate::kCEntryFPAddress, isolate()))); 138014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch __ sd(fp, MemOperand(a2)); 139014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 140b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch const int kSavedRegistersAreaSize = 141b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch (kNumberOfRegisters * kPointerSize) + kDoubleRegsSize; 142b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 143b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Get the bailout id from the stack. 144b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ ld(a2, MemOperand(sp, kSavedRegistersAreaSize)); 145b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 146b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Get the address of the location in the code object (a3) (return 147b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // address for lazy deoptimization) and compute the fp-to-sp delta in 148b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // register a4. 149b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ mov(a3, ra); 150b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Correct one word for bailout id. 151b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Daddu(a4, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize))); 152b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 153b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Dsubu(a4, fp, a4); 154b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 155b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Allocate a new deoptimizer object. 156b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ PrepareCallCFunction(6, a5); 1573b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch // Pass six arguments, according to n64 ABI. 1583b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch __ mov(a0, zero_reg); 1593b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch Label context_check; 1603b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch __ ld(a1, MemOperand(fp, CommonFrameConstants::kContextOrFrameTypeOffset)); 1613b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch __ JumpIfSmi(a1, &context_check); 162b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ ld(a0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 1633b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch __ bind(&context_check); 1643b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch __ li(a1, Operand(type())); // Bailout type. 165b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // a2: bailout id already loaded. 166b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // a3: code address or 0 already loaded. 167109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch // a4: already has fp-to-sp delta. 168109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch __ li(a5, Operand(ExternalReference::isolate_address(isolate()))); 169109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch 170b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Call Deoptimizer::New(). 171b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch { 172b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch AllowExternalCallThatCantCauseGC scope(masm()); 173b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ CallCFunction(ExternalReference::new_deoptimizer_function(isolate()), 6); 174b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 175b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 176b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Preserve "deoptimizer" object in register v0 and get the input 177b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // frame descriptor pointer to a1 (deoptimizer->input_); 178b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Move deopt-obj to a0 for call to Deoptimizer::ComputeOutputFrames() below. 179b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ mov(a0, v0); 180b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ ld(a1, MemOperand(v0, Deoptimizer::input_offset())); 181b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 182b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Copy core registers into FrameDescription::registers_[kNumRegisters]. 183b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(Register::kNumRegisters == kNumberOfRegisters); 184b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch for (int i = 0; i < kNumberOfRegisters; i++) { 185b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch int offset = (i * kPointerSize) + FrameDescription::registers_offset(); 186b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if ((saved_regs & (1 << i)) != 0) { 187b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ ld(a2, MemOperand(sp, i * kPointerSize)); 188b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ sd(a2, MemOperand(a1, offset)); 189b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } else if (FLAG_debug_code) { 190b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ li(a2, kDebugZapValue); 191b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ sd(a2, MemOperand(a1, offset)); 192b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 193b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 194b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 195b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch int double_regs_offset = FrameDescription::double_registers_offset(); 196b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Copy FPU registers to 197b8a8cc1952d61a2f3a2568848933943a543b5d3eBen 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; 202b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ ldc1(f0, MemOperand(sp, src_offset)); 203b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ sdc1(f0, MemOperand(a1, dst_offset)); 204b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 205b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 206b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Remove the bailout id and the saved registers from the stack. 207b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Daddu(sp, sp, Operand(kSavedRegistersAreaSize + (1 * kPointerSize))); 208b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 209b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Compute a pointer to the unwinding limit in register a2; that is 210b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // the first stack slot not part of the input frame. 211b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ ld(a2, MemOperand(a1, FrameDescription::frame_size_offset())); 212b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Daddu(a2, a2, sp); 213b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 214b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Unwind the stack down to - but not including - the unwinding 215b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // limit and copy the contents of the activation frame to the input 216b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // frame description. 217b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Daddu(a3, a1, Operand(FrameDescription::frame_content_offset())); 218b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label pop_loop; 219b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label pop_loop_header; 220b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ BranchShort(&pop_loop_header); 221b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ bind(&pop_loop); 222b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ pop(a4); 223b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ sd(a4, MemOperand(a3, 0)); 224b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ daddiu(a3, a3, sizeof(uint64_t)); 225b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ bind(&pop_loop_header); 226b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ BranchShort(&pop_loop, ne, a2, Operand(sp)); 227b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Compute the output frame in the deoptimizer. 228b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ push(a0); // Preserve deoptimizer object across call. 229b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // a0: deoptimizer object; a1: scratch. 230b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ PrepareCallCFunction(1, a1); 231b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Call Deoptimizer::ComputeOutputFrames(). 232b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch { 233b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch AllowExternalCallThatCantCauseGC scope(masm()); 234b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ CallCFunction( 235b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch ExternalReference::compute_output_frames_function(isolate()), 1); 236b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 237b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ pop(a0); // Restore deoptimizer object (class Deoptimizer). 238b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 2393b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch __ ld(sp, MemOperand(a0, Deoptimizer::caller_frame_top_offset())); 2403b9bc31999c9787eb726ecdbfd5796bfdec32a18Ben Murdoch 241b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Replace the current (input) frame with the output frames. 242b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Label outer_push_loop, inner_push_loop, 243b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch outer_loop_header, inner_loop_header; 244b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Outer loop state: a4 = current "FrameDescription** output_", 245b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // a1 = one past the last FrameDescription**. 246b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ lw(a1, MemOperand(a0, Deoptimizer::output_count_offset())); 247b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ ld(a4, MemOperand(a0, Deoptimizer::output_offset())); // a4 is output_. 248109988c7ccb6f3fd1a58574fa3dfb88beaef6632Ben Murdoch __ Dlsa(a1, a4, a1, kPointerSizeLog2); 249014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch __ BranchShort(&outer_loop_header); 250b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ bind(&outer_push_loop); 251b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Inner loop state: a2 = current FrameDescription*, a3 = loop index. 252b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ ld(a2, MemOperand(a4, 0)); // output_[ix] 253b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ ld(a3, MemOperand(a2, FrameDescription::frame_size_offset())); 254014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch __ BranchShort(&inner_loop_header); 255b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ bind(&inner_push_loop); 256b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Dsubu(a3, a3, Operand(sizeof(uint64_t))); 257b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Daddu(a6, a2, Operand(a3)); 258b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ ld(a7, MemOperand(a6, FrameDescription::frame_content_offset())); 259b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ push(a7); 260b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ bind(&inner_loop_header); 261b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ BranchShort(&inner_push_loop, ne, a3, Operand(zero_reg)); 262b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 263b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Daddu(a4, a4, Operand(kPointerSize)); 264b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ bind(&outer_loop_header); 265b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ BranchShort(&outer_push_loop, lt, a4, Operand(a1)); 266b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 267b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ ld(a1, MemOperand(a0, Deoptimizer::input_offset())); 268014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch for (int i = 0; i < config->num_allocatable_double_registers(); ++i) { 269014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch int code = config->GetAllocatableDoubleCode(i); 270014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch const DoubleRegister fpu_reg = DoubleRegister::from_code(code); 271014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch int src_offset = code * kDoubleSize + double_regs_offset; 272b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ ldc1(fpu_reg, MemOperand(a1, src_offset)); 273b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 274b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 275b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Push state, pc, and continuation from the last output frame. 276b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ ld(a6, MemOperand(a2, FrameDescription::state_offset())); 277b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ push(a6); 278b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 279b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ ld(a6, MemOperand(a2, FrameDescription::pc_offset())); 280b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ push(a6); 281b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ ld(a6, MemOperand(a2, FrameDescription::continuation_offset())); 282b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ push(a6); 283b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 284b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 285b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Technically restoring 'at' should work unless zero_reg is also restored 286b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // but it's safer to check for this. 287b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch DCHECK(!(at.bit() & restored_regs)); 288b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Restore the registers from the last output frame. 289b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ mov(at, a2); 290b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch for (int i = kNumberOfRegisters - 1; i >= 0; i--) { 291b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch int offset = (i * kPointerSize) + FrameDescription::registers_offset(); 292b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch if ((restored_regs & (1 << i)) != 0) { 293b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ ld(ToRegister(i), MemOperand(at, offset)); 294b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 295b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 296b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 297b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ InitializeRootRegister(); 298b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 299b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ pop(at); // Get continuation, leave pc on stack. 300b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ pop(ra); 301b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ Jump(at); 302b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ stop("Unreachable."); 303b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 304b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 305b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 306b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Maximum size of a table entry generated below. 307014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochconst int Deoptimizer::table_entry_size_ = 2 * Assembler::kInstrSize; 308b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 309b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid Deoptimizer::TableEntryGenerator::GeneratePrologue() { 310b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm()); 311b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 312b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Create a sequence of deoptimization entries. 313b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch // Note that registers are still live when jumping to an entry. 314014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch Label table_start, done, done_special, trampoline_jump; 315b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch __ bind(&table_start); 316014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch int kMaxEntriesBranchReach = 317014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch (1 << (kImm16Bits - 2)) / (table_entry_size_ / Assembler::kInstrSize); 318014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 319014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch if (count() <= kMaxEntriesBranchReach) { 320014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // Common case. 321014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch for (int i = 0; i < count(); i++) { 322014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch Label start; 323014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch __ bind(&start); 324014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch DCHECK(is_int16(i)); 325014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch __ BranchShort(USE_DELAY_SLOT, &done); // Expose delay slot. 326014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch __ li(at, i); // In the delay slot. 327014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 328014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch DCHECK_EQ(table_entry_size_, masm()->SizeOfCodeGeneratedSince(&start)); 329b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch } 330b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 331014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch DCHECK_EQ(masm()->SizeOfCodeGeneratedSince(&table_start), 332014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch count() * table_entry_size_); 333014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch __ bind(&done); 334014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch __ Push(at); 335014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch } else { 336014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // Uncommon case, the branch cannot reach. 337014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // Create mini trampoline and adjust id constants to get proper value at 338014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // the end of table. 339014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch for (int i = kMaxEntriesBranchReach; i > 1; i--) { 340014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch Label start; 341014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch __ bind(&start); 342014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch DCHECK(is_int16(i)); 343014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch __ BranchShort(USE_DELAY_SLOT, &trampoline_jump); // Expose delay slot. 344014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch __ li(at, -i); // In the delay slot. 345014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch DCHECK_EQ(table_entry_size_, masm()->SizeOfCodeGeneratedSince(&start)); 346014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch } 347014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // Entry with id == kMaxEntriesBranchReach - 1. 348014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch __ bind(&trampoline_jump); 349014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch __ BranchShort(USE_DELAY_SLOT, &done_special); 350014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch __ li(at, -1); 351014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch 352014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch for (int i = kMaxEntriesBranchReach; i < count(); i++) { 353014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch Label start; 354014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch __ bind(&start); 355014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch DCHECK(is_int16(i)); 356014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch __ Branch(USE_DELAY_SLOT, &done); // Expose delay slot. 357014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch __ li(at, i); // In the delay slot. 358014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch } 359b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 360014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch DCHECK_EQ(masm()->SizeOfCodeGeneratedSince(&table_start), 361014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch count() * table_entry_size_); 362014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch __ bind(&done_special); 363014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch __ daddiu(at, at, kMaxEntriesBranchReach); 364014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch __ bind(&done); 365014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch __ Push(at); 366014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch } 367b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 368b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 369b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 370b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid FrameDescription::SetCallerPc(unsigned offset, intptr_t value) { 371b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch SetFrameSlot(offset, value); 372b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 373b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 374b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 375b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid FrameDescription::SetCallerFp(unsigned offset, intptr_t value) { 376b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch SetFrameSlot(offset, value); 377b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 378b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 379b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 380b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochvoid FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) { 381014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch // No embedded constant pool support. 382b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch UNREACHABLE(); 383b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch} 384b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 385b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 386b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#undef __ 387b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 388b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch 389014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch} // namespace internal 390014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch} // namespace v8 391