Home | History | Annotate | Download | only in arm
      1 // Copyright 2008 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 #include "codegen-inl.h"
     31 #include "jump-target-inl.h"
     32 #include "register-allocator-inl.h"
     33 
     34 namespace v8 {
     35 namespace internal {
     36 
     37 // -------------------------------------------------------------------------
     38 // JumpTarget implementation.
     39 
     40 #define __ ACCESS_MASM(cgen()->masm())
     41 
     42 void JumpTarget::DoJump() {
     43   ASSERT(cgen()->has_valid_frame());
     44   // Live non-frame registers are not allowed at unconditional jumps
     45   // because we have no way of invalidating the corresponding results
     46   // which are still live in the C++ code.
     47   ASSERT(cgen()->HasValidEntryRegisters());
     48 
     49   if (is_bound()) {
     50     // Backward jump.  There already a frame expectation at the target.
     51     ASSERT(direction_ == BIDIRECTIONAL);
     52     cgen()->frame()->MergeTo(entry_frame_);
     53     cgen()->DeleteFrame();
     54   } else {
     55     // Use the current frame as the expected one at the target if necessary.
     56     if (entry_frame_ == NULL) {
     57       entry_frame_ = cgen()->frame();
     58       RegisterFile empty;
     59       cgen()->SetFrame(NULL, &empty);
     60     } else {
     61       cgen()->frame()->MergeTo(entry_frame_);
     62       cgen()->DeleteFrame();
     63     }
     64 
     65     // The predicate is_linked() should be made true.  Its implementation
     66     // detects the presence of a frame pointer in the reaching_frames_ list.
     67     if (!is_linked()) {
     68       reaching_frames_.Add(NULL);
     69       ASSERT(is_linked());
     70     }
     71   }
     72   __ jmp(&entry_label_);
     73 }
     74 
     75 
     76 void JumpTarget::DoBranch(Condition cc, Hint ignored) {
     77   ASSERT(cgen()->has_valid_frame());
     78 
     79   if (is_bound()) {
     80     ASSERT(direction_ == BIDIRECTIONAL);
     81     // Backward branch.  We have an expected frame to merge to on the
     82     // backward edge.
     83     cgen()->frame()->MergeTo(entry_frame_);
     84   } else {
     85     // Clone the current frame to use as the expected one at the target if
     86     // necessary.
     87     if (entry_frame_ == NULL) {
     88       entry_frame_ = new VirtualFrame(cgen()->frame());
     89     }
     90     // The predicate is_linked() should be made true.  Its implementation
     91     // detects the presence of a frame pointer in the reaching_frames_ list.
     92     if (!is_linked()) {
     93       reaching_frames_.Add(NULL);
     94       ASSERT(is_linked());
     95     }
     96   }
     97   __ b(cc, &entry_label_);
     98 }
     99 
    100 
    101 void JumpTarget::Call() {
    102   // Call is used to push the address of the catch block on the stack as
    103   // a return address when compiling try/catch and try/finally.  We
    104   // fully spill the frame before making the call.  The expected frame
    105   // at the label (which should be the only one) is the spilled current
    106   // frame plus an in-memory return address.  The "fall-through" frame
    107   // at the return site is the spilled current frame.
    108   ASSERT(cgen()->has_valid_frame());
    109   // There are no non-frame references across the call.
    110   ASSERT(cgen()->HasValidEntryRegisters());
    111   ASSERT(!is_linked());
    112 
    113   // Calls are always 'forward' so we use a copy of the current frame (plus
    114   // one for a return address) as the expected frame.
    115   ASSERT(entry_frame_ == NULL);
    116   VirtualFrame* target_frame = new VirtualFrame(cgen()->frame());
    117   target_frame->Adjust(1);
    118   entry_frame_ = target_frame;
    119 
    120   // The predicate is_linked() should now be made true.  Its implementation
    121   // detects the presence of a frame pointer in the reaching_frames_ list.
    122   reaching_frames_.Add(NULL);
    123   ASSERT(is_linked());
    124 
    125   __ bl(&entry_label_);
    126 }
    127 
    128 
    129 void JumpTarget::DoBind() {
    130   ASSERT(!is_bound());
    131 
    132   // Live non-frame registers are not allowed at the start of a basic
    133   // block.
    134   ASSERT(!cgen()->has_valid_frame() || cgen()->HasValidEntryRegisters());
    135 
    136   if (cgen()->has_valid_frame()) {
    137     // If there is a current frame we can use it on the fall through.
    138     if (entry_frame_ == NULL) {
    139       entry_frame_ = new VirtualFrame(cgen()->frame());
    140     } else {
    141       ASSERT(cgen()->frame()->Equals(entry_frame_));
    142     }
    143   } else {
    144     // If there is no current frame we must have an entry frame which we can
    145     // copy.
    146     ASSERT(entry_frame_ != NULL);
    147     RegisterFile empty;
    148     cgen()->SetFrame(new VirtualFrame(entry_frame_), &empty);
    149   }
    150 
    151   // The predicate is_linked() should be made false.  Its implementation
    152   // detects the presence (or absence) of frame pointers in the
    153   // reaching_frames_ list.  If we inserted a bogus frame to make
    154   // is_linked() true, remove it now.
    155   if (is_linked()) {
    156     reaching_frames_.Clear();
    157   }
    158 
    159   __ bind(&entry_label_);
    160 }
    161 
    162 
    163 void BreakTarget::Jump() {
    164   // On ARM we do not currently emit merge code for jumps, so we need to do
    165   // it explicitly here.  The only merging necessary is to drop extra
    166   // statement state from the stack.
    167   ASSERT(cgen()->has_valid_frame());
    168   int count = cgen()->frame()->height() - expected_height_;
    169   cgen()->frame()->Drop(count);
    170   DoJump();
    171 }
    172 
    173 
    174 void BreakTarget::Jump(Result* arg) {
    175   // On ARM we do not currently emit merge code for jumps, so we need to do
    176   // it explicitly here.  The only merging necessary is to drop extra
    177   // statement state from the stack.
    178   ASSERT(cgen()->has_valid_frame());
    179   int count = cgen()->frame()->height() - expected_height_;
    180   cgen()->frame()->Drop(count);
    181   cgen()->frame()->Push(arg);
    182   DoJump();
    183 }
    184 
    185 
    186 void BreakTarget::Bind() {
    187 #ifdef DEBUG
    188   // All the forward-reaching frames should have been adjusted at the
    189   // jumps to this target.
    190   for (int i = 0; i < reaching_frames_.length(); i++) {
    191     ASSERT(reaching_frames_[i] == NULL ||
    192            reaching_frames_[i]->height() == expected_height_);
    193   }
    194 #endif
    195   // Drop leftover statement state from the frame before merging, even
    196   // on the fall through.  This is so we can bind the return target
    197   // with state on the frame.
    198   if (cgen()->has_valid_frame()) {
    199     int count = cgen()->frame()->height() - expected_height_;
    200     // On ARM we do not currently emit merge code at binding sites, so we need
    201     // to do it explicitly here.  The only merging necessary is to drop extra
    202     // statement state from the stack.
    203     cgen()->frame()->Drop(count);
    204   }
    205 
    206   DoBind();
    207 }
    208 
    209 
    210 void BreakTarget::Bind(Result* arg) {
    211 #ifdef DEBUG
    212   // All the forward-reaching frames should have been adjusted at the
    213   // jumps to this target.
    214   for (int i = 0; i < reaching_frames_.length(); i++) {
    215     ASSERT(reaching_frames_[i] == NULL ||
    216            reaching_frames_[i]->height() == expected_height_ + 1);
    217   }
    218 #endif
    219   // Drop leftover statement state from the frame before merging, even
    220   // on the fall through.  This is so we can bind the return target
    221   // with state on the frame.
    222   if (cgen()->has_valid_frame()) {
    223     int count = cgen()->frame()->height() - expected_height_;
    224     // On ARM we do not currently emit merge code at binding sites, so we need
    225     // to do it explicitly here.  The only merging necessary is to drop extra
    226     // statement state from the stack.
    227     cgen()->frame()->ForgetElements(count);
    228     cgen()->frame()->Push(arg);
    229   }
    230   DoBind();
    231   *arg = cgen()->frame()->Pop();
    232 }
    233 
    234 
    235 #undef __
    236 
    237 
    238 } }  // namespace v8::internal
    239