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