Home | History | Annotate | Download | only in arm
      1 // Copyright 2012 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #include "v8.h"
     29 
     30 #if V8_TARGET_ARCH_ARM
     31 
     32 #include "codegen.h"
     33 #include "debug.h"
     34 
     35 namespace v8 {
     36 namespace internal {
     37 
     38 #ifdef ENABLE_DEBUGGER_SUPPORT
     39 bool BreakLocationIterator::IsDebugBreakAtReturn() {
     40   return Debug::IsDebugBreakAtReturn(rinfo());
     41 }
     42 
     43 
     44 void BreakLocationIterator::SetDebugBreakAtReturn() {
     45   // Patch the code changing the return from JS function sequence from
     46   //   mov sp, fp
     47   //   ldmia sp!, {fp, lr}
     48   //   add sp, sp, #4
     49   //   bx lr
     50   // to a call to the debug break return code.
     51   //   ldr ip, [pc, #0]
     52   //   blx ip
     53   //   <debug break return code entry point address>
     54   //   bktp 0
     55   CodePatcher patcher(rinfo()->pc(), Assembler::kJSReturnSequenceInstructions);
     56   patcher.masm()->ldr(v8::internal::ip, MemOperand(v8::internal::pc, 0));
     57   patcher.masm()->blx(v8::internal::ip);
     58   patcher.Emit(
     59       debug_info_->GetIsolate()->debug()->debug_break_return()->entry());
     60   patcher.masm()->bkpt(0);
     61 }
     62 
     63 
     64 // Restore the JS frame exit code.
     65 void BreakLocationIterator::ClearDebugBreakAtReturn() {
     66   rinfo()->PatchCode(original_rinfo()->pc(),
     67                      Assembler::kJSReturnSequenceInstructions);
     68 }
     69 
     70 
     71 // A debug break in the frame exit code is identified by the JS frame exit code
     72 // having been patched with a call instruction.
     73 bool Debug::IsDebugBreakAtReturn(RelocInfo* rinfo) {
     74   ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()));
     75   return rinfo->IsPatchedReturnSequence();
     76 }
     77 
     78 
     79 bool BreakLocationIterator::IsDebugBreakAtSlot() {
     80   ASSERT(IsDebugBreakSlot());
     81   // Check whether the debug break slot instructions have been patched.
     82   return rinfo()->IsPatchedDebugBreakSlotSequence();
     83 }
     84 
     85 
     86 void BreakLocationIterator::SetDebugBreakAtSlot() {
     87   ASSERT(IsDebugBreakSlot());
     88   // Patch the code changing the debug break slot code from
     89   //   mov r2, r2
     90   //   mov r2, r2
     91   //   mov r2, r2
     92   // to a call to the debug break slot code.
     93   //   ldr ip, [pc, #0]
     94   //   blx ip
     95   //   <debug break slot code entry point address>
     96   CodePatcher patcher(rinfo()->pc(), Assembler::kDebugBreakSlotInstructions);
     97   patcher.masm()->ldr(v8::internal::ip, MemOperand(v8::internal::pc, 0));
     98   patcher.masm()->blx(v8::internal::ip);
     99   patcher.Emit(
    100       debug_info_->GetIsolate()->debug()->debug_break_slot()->entry());
    101 }
    102 
    103 
    104 void BreakLocationIterator::ClearDebugBreakAtSlot() {
    105   ASSERT(IsDebugBreakSlot());
    106   rinfo()->PatchCode(original_rinfo()->pc(),
    107                      Assembler::kDebugBreakSlotInstructions);
    108 }
    109 
    110 const bool Debug::FramePaddingLayout::kIsSupported = false;
    111 
    112 
    113 #define __ ACCESS_MASM(masm)
    114 
    115 
    116 static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
    117                                           RegList object_regs,
    118                                           RegList non_object_regs) {
    119   {
    120     FrameScope scope(masm, StackFrame::INTERNAL);
    121 
    122     // Store the registers containing live values on the expression stack to
    123     // make sure that these are correctly updated during GC. Non object values
    124     // are stored as a smi causing it to be untouched by GC.
    125     ASSERT((object_regs & ~kJSCallerSaved) == 0);
    126     ASSERT((non_object_regs & ~kJSCallerSaved) == 0);
    127     ASSERT((object_regs & non_object_regs) == 0);
    128     if ((object_regs | non_object_regs) != 0) {
    129       for (int i = 0; i < kNumJSCallerSaved; i++) {
    130         int r = JSCallerSavedCode(i);
    131         Register reg = { r };
    132         if ((non_object_regs & (1 << r)) != 0) {
    133           if (FLAG_debug_code) {
    134             __ tst(reg, Operand(0xc0000000));
    135             __ Assert(eq, kUnableToEncodeValueAsSmi);
    136           }
    137           __ SmiTag(reg);
    138         }
    139       }
    140       __ stm(db_w, sp, object_regs | non_object_regs);
    141     }
    142 
    143 #ifdef DEBUG
    144     __ RecordComment("// Calling from debug break to runtime - come in - over");
    145 #endif
    146     __ mov(r0, Operand::Zero());  // no arguments
    147     __ mov(r1, Operand(ExternalReference::debug_break(masm->isolate())));
    148 
    149     CEntryStub ceb(1);
    150     __ CallStub(&ceb);
    151 
    152     // Restore the register values from the expression stack.
    153     if ((object_regs | non_object_regs) != 0) {
    154       __ ldm(ia_w, sp, object_regs | non_object_regs);
    155       for (int i = 0; i < kNumJSCallerSaved; i++) {
    156         int r = JSCallerSavedCode(i);
    157         Register reg = { r };
    158         if ((non_object_regs & (1 << r)) != 0) {
    159           __ SmiUntag(reg);
    160         }
    161         if (FLAG_debug_code &&
    162             (((object_regs |non_object_regs) & (1 << r)) == 0)) {
    163           __ mov(reg, Operand(kDebugZapValue));
    164         }
    165       }
    166     }
    167 
    168     // Leave the internal frame.
    169   }
    170 
    171   // Now that the break point has been handled, resume normal execution by
    172   // jumping to the target address intended by the caller and that was
    173   // overwritten by the address of DebugBreakXXX.
    174   ExternalReference after_break_target =
    175       ExternalReference(Debug_Address::AfterBreakTarget(), masm->isolate());
    176   __ mov(ip, Operand(after_break_target));
    177   __ ldr(ip, MemOperand(ip));
    178   __ Jump(ip);
    179 }
    180 
    181 
    182 void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) {
    183   // Calling convention for IC load (from ic-arm.cc).
    184   // ----------- S t a t e -------------
    185   //  -- r2    : name
    186   //  -- lr    : return address
    187   //  -- r0    : receiver
    188   //  -- [sp]  : receiver
    189   // -----------------------------------
    190   // Registers r0 and r2 contain objects that need to be pushed on the
    191   // expression stack of the fake JS frame.
    192   Generate_DebugBreakCallHelper(masm, r0.bit() | r2.bit(), 0);
    193 }
    194 
    195 
    196 void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) {
    197   // Calling convention for IC store (from ic-arm.cc).
    198   // ----------- S t a t e -------------
    199   //  -- r0    : value
    200   //  -- r1    : receiver
    201   //  -- r2    : name
    202   //  -- lr    : return address
    203   // -----------------------------------
    204   // Registers r0, r1, and r2 contain objects that need to be pushed on the
    205   // expression stack of the fake JS frame.
    206   Generate_DebugBreakCallHelper(masm, r0.bit() | r1.bit() | r2.bit(), 0);
    207 }
    208 
    209 
    210 void Debug::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
    211   // ---------- S t a t e --------------
    212   //  -- lr     : return address
    213   //  -- r0     : key
    214   //  -- r1     : receiver
    215   Generate_DebugBreakCallHelper(masm, r0.bit() | r1.bit(), 0);
    216 }
    217 
    218 
    219 void Debug::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
    220   // ---------- S t a t e --------------
    221   //  -- r0     : value
    222   //  -- r1     : key
    223   //  -- r2     : receiver
    224   //  -- lr     : return address
    225   Generate_DebugBreakCallHelper(masm, r0.bit() | r1.bit() | r2.bit(), 0);
    226 }
    227 
    228 
    229 void Debug::GenerateCompareNilICDebugBreak(MacroAssembler* masm) {
    230   // Register state for CompareNil IC
    231   // ----------- S t a t e -------------
    232   //  -- r0    : value
    233   // -----------------------------------
    234   Generate_DebugBreakCallHelper(masm, r0.bit(), 0);
    235 }
    236 
    237 
    238 void Debug::GenerateCallICDebugBreak(MacroAssembler* masm) {
    239   // Calling convention for IC call (from ic-arm.cc)
    240   // ----------- S t a t e -------------
    241   //  -- r2     : name
    242   // -----------------------------------
    243   Generate_DebugBreakCallHelper(masm, r2.bit(), 0);
    244 }
    245 
    246 
    247 void Debug::GenerateReturnDebugBreak(MacroAssembler* masm) {
    248   // In places other than IC call sites it is expected that r0 is TOS which
    249   // is an object - this is not generally the case so this should be used with
    250   // care.
    251   Generate_DebugBreakCallHelper(masm, r0.bit(), 0);
    252 }
    253 
    254 
    255 void Debug::GenerateCallFunctionStubDebugBreak(MacroAssembler* masm) {
    256   // Register state for CallFunctionStub (from code-stubs-arm.cc).
    257   // ----------- S t a t e -------------
    258   //  -- r1 : function
    259   // -----------------------------------
    260   Generate_DebugBreakCallHelper(masm, r1.bit(), 0);
    261 }
    262 
    263 
    264 void Debug::GenerateCallFunctionStubRecordDebugBreak(MacroAssembler* masm) {
    265   // Register state for CallFunctionStub (from code-stubs-arm.cc).
    266   // ----------- S t a t e -------------
    267   //  -- r1 : function
    268   //  -- r2 : cache cell for call target
    269   // -----------------------------------
    270   Generate_DebugBreakCallHelper(masm, r1.bit() | r2.bit(), 0);
    271 }
    272 
    273 
    274 void Debug::GenerateCallConstructStubDebugBreak(MacroAssembler* masm) {
    275   // Calling convention for CallConstructStub (from code-stubs-arm.cc)
    276   // ----------- S t a t e -------------
    277   //  -- r0     : number of arguments (not smi)
    278   //  -- r1     : constructor function
    279   // -----------------------------------
    280   Generate_DebugBreakCallHelper(masm, r1.bit(), r0.bit());
    281 }
    282 
    283 
    284 void Debug::GenerateCallConstructStubRecordDebugBreak(MacroAssembler* masm) {
    285   // Calling convention for CallConstructStub (from code-stubs-arm.cc)
    286   // ----------- S t a t e -------------
    287   //  -- r0     : number of arguments (not smi)
    288   //  -- r1     : constructor function
    289   //  -- r2     : cache cell for call target
    290   // -----------------------------------
    291   Generate_DebugBreakCallHelper(masm, r1.bit() | r2.bit(), r0.bit());
    292 }
    293 
    294 
    295 void Debug::GenerateSlot(MacroAssembler* masm) {
    296   // Generate enough nop's to make space for a call instruction. Avoid emitting
    297   // the constant pool in the debug break slot code.
    298   Assembler::BlockConstPoolScope block_const_pool(masm);
    299   Label check_codesize;
    300   __ bind(&check_codesize);
    301   __ RecordDebugBreakSlot();
    302   for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) {
    303     __ nop(MacroAssembler::DEBUG_BREAK_NOP);
    304   }
    305   ASSERT_EQ(Assembler::kDebugBreakSlotInstructions,
    306             masm->InstructionsGeneratedSince(&check_codesize));
    307 }
    308 
    309 
    310 void Debug::GenerateSlotDebugBreak(MacroAssembler* masm) {
    311   // In the places where a debug break slot is inserted no registers can contain
    312   // object pointers.
    313   Generate_DebugBreakCallHelper(masm, 0, 0);
    314 }
    315 
    316 
    317 void Debug::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
    318   masm->Abort(kLiveEditFrameDroppingIsNotSupportedOnArm);
    319 }
    320 
    321 
    322 void Debug::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
    323   masm->Abort(kLiveEditFrameDroppingIsNotSupportedOnArm);
    324 }
    325 
    326 const bool Debug::kFrameDropperSupported = false;
    327 
    328 #undef __
    329 
    330 
    331 
    332 #endif  // ENABLE_DEBUGGER_SUPPORT
    333 
    334 } }  // namespace v8::internal
    335 
    336 #endif  // V8_TARGET_ARCH_ARM
    337