blob: 3315f8381c0031b12973ebd67995fa9b4c3a5307 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// 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
34namespace v8 {
35namespace internal {
36
37// -------------------------------------------------------------------------
38// JumpTarget implementation.
39
40#define __ ACCESS_MASM(cgen()->masm())
41
42void 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
76void 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
101void 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
129void 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
163void 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
174void 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
186void 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
210void 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