Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 #if V8_TARGET_ARCH_ARM | 7 #if V8_TARGET_ARCH_ARM |
| 8 | 8 |
| 9 #include "src/codegen.h" | 9 #include "src/codegen.h" |
| 10 #include "src/debug.h" | 10 #include "src/debug.h" |
| 11 | 11 |
| 12 namespace v8 { | 12 namespace v8 { |
| 13 namespace internal { | 13 namespace internal { |
| 14 | 14 |
| 15 bool BreakLocationIterator::IsDebugBreakAtReturn() { | 15 bool BreakLocationIterator::IsDebugBreakAtReturn() { |
| 16 return Debug::IsDebugBreakAtReturn(rinfo()); | 16 return Debug::IsDebugBreakAtReturn(rinfo()); |
| 17 } | 17 } |
| 18 | 18 |
| 19 | 19 |
| 20 void BreakLocationIterator::SetDebugBreakAtReturn() { | 20 void BreakLocationIterator::SetDebugBreakAtReturn() { |
| 21 // Patch the code changing the return from JS function sequence from | 21 // Patch the code changing the return from JS function sequence from |
| 22 // mov sp, fp | 22 // mov sp, fp |
| 23 // ldmia sp!, {fp, lr} | 23 // ldmia sp!, {fp, lr} |
| 24 // add sp, sp, #4 | 24 // add sp, sp, #4 |
| 25 // bx lr | 25 // bx lr |
| 26 // to a call to the debug break return code. | 26 // to a call to the debug break return code. |
| 27 // ldr ip, [pc, #0] | 27 // ldr ip, [pc, #0] |
| 28 // blx ip | 28 // blx ip |
| 29 // <debug break return code entry point address> | 29 // <debug break return code entry point address> |
| 30 // bktp 0 | 30 // bkpt 0 |
| 31 CodePatcher patcher(rinfo()->pc(), Assembler::kJSReturnSequenceInstructions); | 31 CodePatcher patcher(rinfo()->pc(), Assembler::kJSReturnSequenceInstructions); |
| 32 patcher.masm()->ldr(v8::internal::ip, MemOperand(v8::internal::pc, 0)); | 32 patcher.masm()->ldr(v8::internal::ip, MemOperand(v8::internal::pc, 0)); |
| 33 patcher.masm()->blx(v8::internal::ip); | 33 patcher.masm()->blx(v8::internal::ip); |
| 34 patcher.Emit( | 34 patcher.Emit( |
| 35 debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry()); | 35 debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry()); |
| 36 patcher.masm()->bkpt(0); | 36 patcher.masm()->bkpt(0); |
| 37 } | 37 } |
| 38 | 38 |
| 39 | 39 |
| 40 // Restore the JS frame exit code. | 40 // Restore the JS frame exit code. |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 86 | 86 |
| 87 #define __ ACCESS_MASM(masm) | 87 #define __ ACCESS_MASM(masm) |
| 88 | 88 |
| 89 | 89 |
| 90 static void Generate_DebugBreakCallHelper(MacroAssembler* masm, | 90 static void Generate_DebugBreakCallHelper(MacroAssembler* masm, |
| 91 RegList object_regs, | 91 RegList object_regs, |
| 92 RegList non_object_regs) { | 92 RegList non_object_regs) { |
| 93 { | 93 { |
| 94 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); | 94 FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); |
| 95 | 95 |
| 96 // Load padding words on stack. | |
| 97 __ mov(ip, Operand(Smi::FromInt(LiveEdit::kFramePaddingValue))); | |
| 98 for (int i = 0; i < LiveEdit::kFramePaddingInitialSize; i++) { | |
| 99 __ push(ip); | |
| 100 } | |
| 101 __ mov(ip, Operand(Smi::FromInt(LiveEdit::kFramePaddingInitialSize))); | |
| 102 __ push(ip); | |
| 103 | |
| 96 // Store the registers containing live values on the expression stack to | 104 // Store the registers containing live values on the expression stack to |
| 97 // make sure that these are correctly updated during GC. Non object values | 105 // make sure that these are correctly updated during GC. Non object values |
| 98 // are stored as a smi causing it to be untouched by GC. | 106 // are stored as a smi causing it to be untouched by GC. |
| 99 ASSERT((object_regs & ~kJSCallerSaved) == 0); | 107 ASSERT((object_regs & ~kJSCallerSaved) == 0); |
| 100 ASSERT((non_object_regs & ~kJSCallerSaved) == 0); | 108 ASSERT((non_object_regs & ~kJSCallerSaved) == 0); |
| 101 ASSERT((object_regs & non_object_regs) == 0); | 109 ASSERT((object_regs & non_object_regs) == 0); |
| 102 if ((object_regs | non_object_regs) != 0) { | 110 if ((object_regs | non_object_regs) != 0) { |
| 103 for (int i = 0; i < kNumJSCallerSaved; i++) { | 111 for (int i = 0; i < kNumJSCallerSaved; i++) { |
| 104 int r = JSCallerSavedCode(i); | 112 int r = JSCallerSavedCode(i); |
| 105 Register reg = { r }; | 113 Register reg = { r }; |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 132 if ((non_object_regs & (1 << r)) != 0) { | 140 if ((non_object_regs & (1 << r)) != 0) { |
| 133 __ SmiUntag(reg); | 141 __ SmiUntag(reg); |
| 134 } | 142 } |
| 135 if (FLAG_debug_code && | 143 if (FLAG_debug_code && |
| 136 (((object_regs |non_object_regs) & (1 << r)) == 0)) { | 144 (((object_regs |non_object_regs) & (1 << r)) == 0)) { |
| 137 __ mov(reg, Operand(kDebugZapValue)); | 145 __ mov(reg, Operand(kDebugZapValue)); |
| 138 } | 146 } |
| 139 } | 147 } |
| 140 } | 148 } |
| 141 | 149 |
| 150 // Don't bother removing padding bytes pushed on the stack | |
| 151 // as the frame is going to be restored right away. | |
| 152 | |
|
Yang
2014/06/18 15:03:55
Are you sure this is correct? A brief comparison t
alph
2014/06/18 16:29:21
FrameAndConstantPoolScope destructor is called her
| |
| 142 // Leave the internal frame. | 153 // Leave the internal frame. |
| 143 } | 154 } |
| 144 | 155 |
| 145 // Now that the break point has been handled, resume normal execution by | 156 // Now that the break point has been handled, resume normal execution by |
| 146 // jumping to the target address intended by the caller and that was | 157 // jumping to the target address intended by the caller and that was |
| 147 // overwritten by the address of DebugBreakXXX. | 158 // overwritten by the address of DebugBreakXXX. |
| 148 ExternalReference after_break_target = | 159 ExternalReference after_break_target = |
| 149 ExternalReference::debug_after_break_target_address(masm->isolate()); | 160 ExternalReference::debug_after_break_target_address(masm->isolate()); |
| 150 __ mov(ip, Operand(after_break_target)); | 161 __ mov(ip, Operand(after_break_target)); |
| 151 __ ldr(ip, MemOperand(ip)); | 162 __ ldr(ip, MemOperand(ip)); |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 275 | 286 |
| 276 | 287 |
| 277 void DebugCodegen::GenerateSlotDebugBreak(MacroAssembler* masm) { | 288 void DebugCodegen::GenerateSlotDebugBreak(MacroAssembler* masm) { |
| 278 // In the places where a debug break slot is inserted no registers can contain | 289 // In the places where a debug break slot is inserted no registers can contain |
| 279 // object pointers. | 290 // object pointers. |
| 280 Generate_DebugBreakCallHelper(masm, 0, 0); | 291 Generate_DebugBreakCallHelper(masm, 0, 0); |
| 281 } | 292 } |
| 282 | 293 |
| 283 | 294 |
| 284 void DebugCodegen::GeneratePlainReturnLiveEdit(MacroAssembler* masm) { | 295 void DebugCodegen::GeneratePlainReturnLiveEdit(MacroAssembler* masm) { |
| 285 masm->Abort(kLiveEditFrameDroppingIsNotSupportedOnArm); | 296 __ Ret(); |
| 286 } | 297 } |
| 287 | 298 |
| 288 | 299 |
| 289 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) { | 300 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) { |
| 290 masm->Abort(kLiveEditFrameDroppingIsNotSupportedOnArm); | 301 ExternalReference restarter_frame_function_slot = |
| 302 ExternalReference::debug_restarter_frame_function_pointer_address( | |
| 303 masm->isolate()); | |
| 304 __ mov(ip, Operand(restarter_frame_function_slot)); | |
| 305 __ mov(r1, Operand::Zero()); | |
| 306 __ str(r1, MemOperand(ip, 0)); | |
| 307 | |
| 308 // We do not know our frame height, but set sp based on fp. | |
| 309 __ sub(sp, fp, Operand(kPointerSize)); | |
| 310 | |
| 311 __ Pop(lr, fp, r1); // Return address, Frame, Function. | |
| 312 | |
| 313 // Load context from the function. | |
| 314 __ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset)); | |
| 315 | |
| 316 // Get function code. | |
| 317 __ ldr(ip, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset)); | |
| 318 __ ldr(ip, FieldMemOperand(ip, SharedFunctionInfo::kCodeOffset)); | |
| 319 __ add(ip, ip, Operand(Code::kHeaderSize - kHeapObjectTag)); | |
| 320 | |
| 321 // Re-run JSFunction, r1 is function, cp is context. | |
| 322 __ Jump(ip); | |
| 291 } | 323 } |
| 292 | 324 |
| 293 | 325 |
| 294 const bool LiveEdit::kFrameDropperSupported = false; | 326 const bool LiveEdit::kFrameDropperSupported = true; |
| 295 | 327 |
| 296 #undef __ | 328 #undef __ |
| 297 | 329 |
| 298 } } // namespace v8::internal | 330 } } // namespace v8::internal |
| 299 | 331 |
| 300 #endif // V8_TARGET_ARCH_ARM | 332 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |