| 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" |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 42 if (deopt_data->Pc(i)->value() == -1) continue; | 42 if (deopt_data->Pc(i)->value() == -1) continue; |
| 43 | 43 |
| 44 Address call_address = code_start_address + deopt_data->Pc(i)->value(); | 44 Address call_address = code_start_address + deopt_data->Pc(i)->value(); |
| 45 Address deopt_entry = GetDeoptimizationEntry(isolate, i, LAZY); | 45 Address deopt_entry = GetDeoptimizationEntry(isolate, i, LAZY); |
| 46 | 46 |
| 47 PatchingAssembler patcher(call_address, patch_size() / kInstructionSize); | 47 PatchingAssembler patcher(call_address, patch_size() / kInstructionSize); |
| 48 patcher.ldr_pcrel(ip0, (2 * kInstructionSize) >> kLoadLiteralScaleLog2); | 48 patcher.ldr_pcrel(ip0, (2 * kInstructionSize) >> kLoadLiteralScaleLog2); |
| 49 patcher.blr(ip0); | 49 patcher.blr(ip0); |
| 50 patcher.dc64(reinterpret_cast<intptr_t>(deopt_entry)); | 50 patcher.dc64(reinterpret_cast<intptr_t>(deopt_entry)); |
| 51 | 51 |
| 52 ASSERT((prev_call_address == NULL) || | 52 DCHECK((prev_call_address == NULL) || |
| 53 (call_address >= prev_call_address + patch_size())); | 53 (call_address >= prev_call_address + patch_size())); |
| 54 ASSERT(call_address + patch_size() <= code->instruction_end()); | 54 DCHECK(call_address + patch_size() <= code->instruction_end()); |
| 55 #ifdef DEBUG | 55 #ifdef DEBUG |
| 56 prev_call_address = call_address; | 56 prev_call_address = call_address; |
| 57 #endif | 57 #endif |
| 58 } | 58 } |
| 59 } | 59 } |
| 60 | 60 |
| 61 | 61 |
| 62 void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) { | 62 void Deoptimizer::FillInputFrame(Address tos, JavaScriptFrame* frame) { |
| 63 // Set the register values. The values are not important as there are no | 63 // Set the register values. The values are not important as there are no |
| 64 // callee saved registers in JavaScript frames, so all registers are | 64 // callee saved registers in JavaScript frames, so all registers are |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 243 __ Push(x7); | 243 __ Push(x7); |
| 244 __ Bind(&inner_loop_header); | 244 __ Bind(&inner_loop_header); |
| 245 __ Cbnz(x3, &inner_push_loop); | 245 __ Cbnz(x3, &inner_push_loop); |
| 246 | 246 |
| 247 __ Add(x0, x0, kPointerSize); | 247 __ Add(x0, x0, kPointerSize); |
| 248 __ Bind(&outer_loop_header); | 248 __ Bind(&outer_loop_header); |
| 249 __ Cmp(x0, x1); | 249 __ Cmp(x0, x1); |
| 250 __ B(lt, &outer_push_loop); | 250 __ B(lt, &outer_push_loop); |
| 251 | 251 |
| 252 __ Ldr(x1, MemOperand(x4, Deoptimizer::input_offset())); | 252 __ Ldr(x1, MemOperand(x4, Deoptimizer::input_offset())); |
| 253 ASSERT(!saved_fp_registers.IncludesAliasOf(crankshaft_fp_scratch) && | 253 DCHECK(!saved_fp_registers.IncludesAliasOf(crankshaft_fp_scratch) && |
| 254 !saved_fp_registers.IncludesAliasOf(fp_zero) && | 254 !saved_fp_registers.IncludesAliasOf(fp_zero) && |
| 255 !saved_fp_registers.IncludesAliasOf(fp_scratch)); | 255 !saved_fp_registers.IncludesAliasOf(fp_scratch)); |
| 256 int src_offset = FrameDescription::double_registers_offset(); | 256 int src_offset = FrameDescription::double_registers_offset(); |
| 257 while (!saved_fp_registers.IsEmpty()) { | 257 while (!saved_fp_registers.IsEmpty()) { |
| 258 const CPURegister reg = saved_fp_registers.PopLowestIndex(); | 258 const CPURegister reg = saved_fp_registers.PopLowestIndex(); |
| 259 __ Ldr(reg, MemOperand(x1, src_offset)); | 259 __ Ldr(reg, MemOperand(x1, src_offset)); |
| 260 src_offset += kDoubleSize; | 260 src_offset += kDoubleSize; |
| 261 } | 261 } |
| 262 | 262 |
| 263 // Push state from the last output frame. | 263 // Push state from the last output frame. |
| 264 __ Ldr(x6, MemOperand(current_frame, FrameDescription::state_offset())); | 264 __ Ldr(x6, MemOperand(current_frame, FrameDescription::state_offset())); |
| 265 __ Push(x6); | 265 __ Push(x6); |
| 266 | 266 |
| 267 // TODO(all): ARM copies a lot (if not all) of the last output frame onto the | 267 // TODO(all): ARM copies a lot (if not all) of the last output frame onto the |
| 268 // stack, then pops it all into registers. Here, we try to load it directly | 268 // stack, then pops it all into registers. Here, we try to load it directly |
| 269 // into the relevant registers. Is this correct? If so, we should improve the | 269 // into the relevant registers. Is this correct? If so, we should improve the |
| 270 // ARM code. | 270 // ARM code. |
| 271 | 271 |
| 272 // TODO(all): This code needs to be revisited, We probably don't need to | 272 // TODO(all): This code needs to be revisited, We probably don't need to |
| 273 // restore all the registers as fullcodegen does not keep live values in | 273 // restore all the registers as fullcodegen does not keep live values in |
| 274 // registers (note that at least fp must be restored though). | 274 // registers (note that at least fp must be restored though). |
| 275 | 275 |
| 276 // Restore registers from the last output frame. | 276 // Restore registers from the last output frame. |
| 277 // Note that lr is not in the list of saved_registers and will be restored | 277 // Note that lr is not in the list of saved_registers and will be restored |
| 278 // later. We can use it to hold the address of last output frame while | 278 // later. We can use it to hold the address of last output frame while |
| 279 // reloading the other registers. | 279 // reloading the other registers. |
| 280 ASSERT(!saved_registers.IncludesAliasOf(lr)); | 280 DCHECK(!saved_registers.IncludesAliasOf(lr)); |
| 281 Register last_output_frame = lr; | 281 Register last_output_frame = lr; |
| 282 __ Mov(last_output_frame, current_frame); | 282 __ Mov(last_output_frame, current_frame); |
| 283 | 283 |
| 284 // We don't need to restore x7 as it will be clobbered later to hold the | 284 // We don't need to restore x7 as it will be clobbered later to hold the |
| 285 // continuation address. | 285 // continuation address. |
| 286 Register continuation = x7; | 286 Register continuation = x7; |
| 287 saved_registers.Remove(continuation); | 287 saved_registers.Remove(continuation); |
| 288 | 288 |
| 289 while (!saved_registers.IsEmpty()) { | 289 while (!saved_registers.IsEmpty()) { |
| 290 // TODO(all): Look for opportunities to optimize this by using ldp. | 290 // TODO(all): Look for opportunities to optimize this by using ldp. |
| (...skipping 22 matching lines...) Expand all Loading... |
| 313 | 313 |
| 314 // Create a sequence of deoptimization entries. | 314 // Create a sequence of deoptimization entries. |
| 315 // Note that registers are still live when jumping to an entry. | 315 // Note that registers are still live when jumping to an entry. |
| 316 Label done; | 316 Label done; |
| 317 { | 317 { |
| 318 InstructionAccurateScope scope(masm()); | 318 InstructionAccurateScope scope(masm()); |
| 319 | 319 |
| 320 // The number of entry will never exceed kMaxNumberOfEntries. | 320 // The number of entry will never exceed kMaxNumberOfEntries. |
| 321 // As long as kMaxNumberOfEntries is a valid 16 bits immediate you can use | 321 // As long as kMaxNumberOfEntries is a valid 16 bits immediate you can use |
| 322 // a movz instruction to load the entry id. | 322 // a movz instruction to load the entry id. |
| 323 ASSERT(is_uint16(Deoptimizer::kMaxNumberOfEntries)); | 323 DCHECK(is_uint16(Deoptimizer::kMaxNumberOfEntries)); |
| 324 | 324 |
| 325 for (int i = 0; i < count(); i++) { | 325 for (int i = 0; i < count(); i++) { |
| 326 int start = masm()->pc_offset(); | 326 int start = masm()->pc_offset(); |
| 327 USE(start); | 327 USE(start); |
| 328 __ movz(entry_id, i); | 328 __ movz(entry_id, i); |
| 329 __ b(&done); | 329 __ b(&done); |
| 330 ASSERT(masm()->pc_offset() - start == table_entry_size_); | 330 DCHECK(masm()->pc_offset() - start == table_entry_size_); |
| 331 } | 331 } |
| 332 } | 332 } |
| 333 __ Bind(&done); | 333 __ Bind(&done); |
| 334 __ Push(entry_id); | 334 __ Push(entry_id); |
| 335 } | 335 } |
| 336 | 336 |
| 337 | 337 |
| 338 void FrameDescription::SetCallerPc(unsigned offset, intptr_t value) { | 338 void FrameDescription::SetCallerPc(unsigned offset, intptr_t value) { |
| 339 SetFrameSlot(offset, value); | 339 SetFrameSlot(offset, value); |
| 340 } | 340 } |
| 341 | 341 |
| 342 | 342 |
| 343 void FrameDescription::SetCallerFp(unsigned offset, intptr_t value) { | 343 void FrameDescription::SetCallerFp(unsigned offset, intptr_t value) { |
| 344 SetFrameSlot(offset, value); | 344 SetFrameSlot(offset, value); |
| 345 } | 345 } |
| 346 | 346 |
| 347 | 347 |
| 348 void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) { | 348 void FrameDescription::SetCallerConstantPool(unsigned offset, intptr_t value) { |
| 349 // No out-of-line constant pool support. | 349 // No out-of-line constant pool support. |
| 350 UNREACHABLE(); | 350 UNREACHABLE(); |
| 351 } | 351 } |
| 352 | 352 |
| 353 | 353 |
| 354 #undef __ | 354 #undef __ |
| 355 | 355 |
| 356 } } // namespace v8::internal | 356 } } // namespace v8::internal |
| OLD | NEW |