• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
DoJump()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 
DoBranch(Condition cc,Hint ignored)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 
Call()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 
DoBind()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 
Jump()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 
Jump(Result * arg)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 
Bind()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 
Bind(Result * arg)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