Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #include "src/codegen.h" | 7 #include "src/codegen.h" |
| 8 #include "src/deoptimizer.h" | 8 #include "src/deoptimizer.h" |
| 9 #include "src/full-codegen.h" | 9 #include "src/full-codegen.h" |
| 10 #include "src/safepoint-table.h" | 10 #include "src/safepoint-table.h" |
| 11 | 11 |
| 12 | 12 |
| 13 namespace v8 { | 13 namespace v8 { |
| 14 namespace internal { | 14 namespace internal { |
| 15 | 15 |
| 16 | 16 |
| 17 int Deoptimizer::patch_size() { | 17 int Deoptimizer::patch_size() { |
| 18 // Size of the code used to patch lazy bailout points. | 18 // Size of the code used to patch lazy bailout points. |
| 19 // Patching is done by Deoptimizer::DeoptimizeFunction. | 19 // Patching is done by Deoptimizer::DeoptimizeFunction. |
| 20 return 4 * kInstructionSize; | 20 return 5 * kInstructionSize; |
| 21 } | 21 } |
| 22 | 22 |
| 23 | 23 |
| 24 | 24 |
| 25 void Deoptimizer::PatchCodeForDeoptimization(Isolate* isolate, Code* code) { | 25 void Deoptimizer::PatchCodeForDeoptimization(Isolate* isolate, Code* code) { |
| 26 // Invalidate the relocation information, as it will become invalid by the | 26 // Invalidate the relocation information, as it will become invalid by the |
| 27 // code patching below, and is not needed any more. | 27 // code patching below, and is not needed any more. |
| 28 code->InvalidateRelocation(); | 28 code->InvalidateRelocation(); |
| 29 | 29 |
| 30 // TODO(jkummerow): if (FLAG_zap_code_space), make the code object's | 30 // TODO(jkummerow): if (FLAG_zap_code_space), make the code object's |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 41 #endif | 41 #endif |
| 42 // For each LLazyBailout instruction insert a call to the corresponding | 42 // For each LLazyBailout instruction insert a call to the corresponding |
| 43 // deoptimization entry. | 43 // deoptimization entry. |
| 44 for (int i = 0; i < deopt_data->DeoptCount(); i++) { | 44 for (int i = 0; i < deopt_data->DeoptCount(); i++) { |
| 45 if (deopt_data->Pc(i)->value() == -1) continue; | 45 if (deopt_data->Pc(i)->value() == -1) continue; |
| 46 | 46 |
| 47 Address call_address = code_start_address + deopt_data->Pc(i)->value(); | 47 Address call_address = code_start_address + deopt_data->Pc(i)->value(); |
| 48 Address deopt_entry = GetDeoptimizationEntry(isolate, i, LAZY); | 48 Address deopt_entry = GetDeoptimizationEntry(isolate, i, LAZY); |
| 49 | 49 |
| 50 PatchingAssembler patcher(call_address, patch_size() / kInstructionSize); | 50 PatchingAssembler patcher(call_address, patch_size() / kInstructionSize); |
| 51 patcher.adr(ip1, 0); | |
| 51 patcher.ldr_pcrel(ip0, (2 * kInstructionSize) >> kLoadLiteralScaleLog2); | 52 patcher.ldr_pcrel(ip0, (2 * kInstructionSize) >> kLoadLiteralScaleLog2); |
| 52 patcher.blr(ip0); | 53 patcher.blr(ip0); |
|
ulan
2014/06/23 11:17:11
Did you mean br(ip0) here?
jbramley
2014/06/23 17:22:05
Yes! Thank you.
| |
| 53 patcher.dc64(reinterpret_cast<intptr_t>(deopt_entry)); | 54 patcher.dc64(reinterpret_cast<intptr_t>(deopt_entry)); |
| 54 | 55 |
| 55 ASSERT((prev_call_address == NULL) || | 56 ASSERT((prev_call_address == NULL) || |
| 56 (call_address >= prev_call_address + patch_size())); | 57 (call_address >= prev_call_address + patch_size())); |
| 57 ASSERT(call_address + patch_size() <= code->instruction_end()); | 58 ASSERT(call_address + patch_size() <= code->instruction_end()); |
| 58 #ifdef DEBUG | 59 #ifdef DEBUG |
| 59 prev_call_address = call_address; | 60 prev_call_address = call_address; |
| 60 #endif | 61 #endif |
| 61 } | 62 } |
| 62 } | 63 } |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 143 offset0 = (copy_to_input.PopLowestIndex().code() * reg_size) + dst_offset; | 144 offset0 = (copy_to_input.PopLowestIndex().code() * reg_size) + dst_offset; |
| 144 __ Str(scratch1, MemOperand(frame, offset0)); | 145 __ Str(scratch1, MemOperand(frame, offset0)); |
| 145 } | 146 } |
| 146 } | 147 } |
| 147 | 148 |
| 148 #undef __ | 149 #undef __ |
| 149 | 150 |
| 150 #define __ masm()-> | 151 #define __ masm()-> |
| 151 | 152 |
| 152 void Deoptimizer::EntryGenerator::Generate() { | 153 void Deoptimizer::EntryGenerator::Generate() { |
| 154 UseScratchRegisterScope temps(masm()); | |
| 155 | |
| 156 // The deopt entry jump must put the caller address in ip1. This can be done | |
| 157 // either in the level-one deopt table (GenerateDeoptJumpTable), or inline in | |
| 158 // the code (DeoptimizeBranch). | |
| 159 Register caller_address = temps.Acquire(ip1); | |
| 160 | |
| 153 GeneratePrologue(); | 161 GeneratePrologue(); |
| 154 | 162 |
| 155 // TODO(all): This code needs to be revisited. We probably only need to save | 163 // TODO(all): This code needs to be revisited. We probably only need to save |
| 156 // caller-saved registers here. Callee-saved registers can be stored directly | 164 // caller-saved registers here. Callee-saved registers can be stored directly |
| 157 // in the input frame. | 165 // in the input frame. |
| 158 | 166 |
| 159 // Save all allocatable floating point registers. | 167 // Save all allocatable floating point registers. |
| 160 CPURegList saved_fp_registers(CPURegister::kFPRegister, kDRegSizeInBits, | 168 CPURegList saved_fp_registers(CPURegister::kFPRegister, kDRegSizeInBits, |
| 161 FPRegister::kAllocatableFPRegisters); | 169 FPRegister::kAllocatableFPRegisters); |
| 162 __ PushCPURegList(saved_fp_registers); | 170 __ PushCPURegList(saved_fp_registers); |
| 163 | 171 |
| 164 // We save all the registers expcept jssp, sp and lr. | 172 // We save all allocatable registers plus fp. |
| 165 CPURegList saved_registers(CPURegister::kRegister, kXRegSizeInBits, 0, 27); | 173 CPURegList saved_registers(CPURegister::kRegister, kXRegSizeInBits, |
| 166 saved_registers.Combine(fp); | 174 Register::kAllocatableRegisters | fp.Bit()); |
| 167 __ PushCPURegList(saved_registers); | 175 __ PushCPURegList(saved_registers); |
| 168 | 176 |
| 169 const int kSavedRegistersAreaSize = | 177 const int kSavedRegistersAreaSize = |
| 170 (saved_registers.Count() * kXRegSize) + | 178 (saved_registers.Count() * kXRegSize) + |
| 171 (saved_fp_registers.Count() * kDRegSize); | 179 (saved_fp_registers.Count() * kDRegSize); |
| 172 | 180 |
| 173 // Floating point registers are saved on the stack above core registers. | 181 // Floating point registers are saved on the stack above core registers. |
| 174 const int kFPRegistersOffset = saved_registers.Count() * kXRegSize; | 182 const int kFPRegistersOffset = saved_registers.Count() * kXRegSize; |
| 175 | 183 |
| 176 // Get the bailout id from the stack. | 184 // Get the bailout id from the stack. |
| 177 Register bailout_id = x2; | 185 Register bailout_id = x2; |
| 178 __ Peek(bailout_id, kSavedRegistersAreaSize); | 186 __ Peek(bailout_id, kSavedRegistersAreaSize); |
| 179 | 187 |
| 180 Register code_object = x3; | 188 Register code_object = x3; |
| 181 Register fp_to_sp = x4; | 189 Register fp_to_sp = x4; |
| 182 // Get the address of the location in the code object. This is the return | 190 // Get the address of the location in the code object. This is the return |
| 183 // address for lazy deoptimization. | 191 // address for lazy deoptimization. |
| 184 __ Mov(code_object, lr); | 192 __ Mov(code_object, caller_address); |
| 185 // Compute the fp-to-sp delta, and correct one word for bailout id. | 193 // Compute the fp-to-sp delta, and correct one word for bailout id. |
| 186 __ Add(fp_to_sp, masm()->StackPointer(), | 194 __ Add(fp_to_sp, masm()->StackPointer(), |
| 187 kSavedRegistersAreaSize + (1 * kPointerSize)); | 195 kSavedRegistersAreaSize + (1 * kPointerSize)); |
| 188 __ Sub(fp_to_sp, fp, fp_to_sp); | 196 __ Sub(fp_to_sp, fp, fp_to_sp); |
| 189 | 197 |
| 190 // Allocate a new deoptimizer object. | 198 // Allocate a new deoptimizer object. |
| 191 __ Ldr(x0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); | 199 __ Ldr(x0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); |
| 192 __ Mov(x1, type()); | 200 __ Mov(x1, type()); |
| 193 // Following arguments are already loaded: | 201 // Following arguments are already loaded: |
| 194 // - x2: bailout id | 202 // - x2: bailout id |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 296 // TODO(all): ARM copies a lot (if not all) of the last output frame onto the | 304 // TODO(all): ARM copies a lot (if not all) of the last output frame onto the |
| 297 // stack, then pops it all into registers. Here, we try to load it directly | 305 // stack, then pops it all into registers. Here, we try to load it directly |
| 298 // into the relevant registers. Is this correct? If so, we should improve the | 306 // into the relevant registers. Is this correct? If so, we should improve the |
| 299 // ARM code. | 307 // ARM code. |
| 300 | 308 |
| 301 // TODO(all): This code needs to be revisited, We probably don't need to | 309 // TODO(all): This code needs to be revisited, We probably don't need to |
| 302 // restore all the registers as fullcodegen does not keep live values in | 310 // restore all the registers as fullcodegen does not keep live values in |
| 303 // registers (note that at least fp must be restored though). | 311 // registers (note that at least fp must be restored though). |
| 304 | 312 |
| 305 // Restore registers from the last output frame. | 313 // Restore registers from the last output frame. |
| 306 // Note that lr is not in the list of saved_registers and will be restored | 314 Register last_output_frame = temps.AcquireX(); |
| 307 // later. We can use it to hold the address of last output frame while | 315 ASSERT(!saved_registers.IncludesAliasOf(last_output_frame)); |
| 308 // reloading the other registers. | |
| 309 ASSERT(!saved_registers.IncludesAliasOf(lr)); | |
| 310 Register last_output_frame = lr; | |
| 311 __ Mov(last_output_frame, current_frame); | 316 __ Mov(last_output_frame, current_frame); |
| 312 | 317 |
| 313 // We don't need to restore x7 as it will be clobbered later to hold the | 318 // We don't need to restore x7 as it will be clobbered later to hold the |
| 314 // continuation address. | 319 // continuation address. |
| 315 Register continuation = x7; | 320 Register continuation = x7; |
| 316 saved_registers.Remove(continuation); | 321 saved_registers.Remove(continuation); |
| 317 | 322 |
| 318 while (!saved_registers.IsEmpty()) { | 323 while (!saved_registers.IsEmpty()) { |
| 319 // TODO(all): Look for opportunities to optimize this by using ldp. | 324 // TODO(all): Look for opportunities to optimize this by using ldp. |
| 320 CPURegister current_reg = saved_registers.PopLowestIndex(); | 325 CPURegister current_reg = saved_registers.PopLowestIndex(); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 376 | 381 |
| 377 void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) { | 382 void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) { |
| 378 // No out-of-line constant pool support. | 383 // No out-of-line constant pool support. |
| 379 UNREACHABLE(); | 384 UNREACHABLE(); |
| 380 } | 385 } |
| 381 | 386 |
| 382 | 387 |
| 383 #undef __ | 388 #undef __ |
| 384 | 389 |
| 385 } } // namespace v8::internal | 390 } } // namespace v8::internal |
| OLD | NEW |