blob: 7270280055eb8d35b623468f03b378da86bee44b [file] [log] [blame]
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00001// Copyright 2010 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 "register-allocator-inl.h"
32#include "virtual-frame-inl.h"
33
34namespace v8 {
35namespace internal {
36
37void VirtualFrame::SetElementAt(int index, Result* value) {
38 int frame_index = element_count() - index - 1;
39 ASSERT(frame_index >= 0);
40 ASSERT(frame_index < element_count());
41 ASSERT(value->is_valid());
42 FrameElement original = elements_[frame_index];
43
44 // Early exit if the element is the same as the one being set.
45 bool same_register = original.is_register()
46 && value->is_register()
47 && original.reg().is(value->reg());
48 bool same_constant = original.is_constant()
49 && value->is_constant()
50 && original.handle().is_identical_to(value->handle());
51 if (same_register || same_constant) {
52 value->Unuse();
53 return;
54 }
55
56 InvalidateFrameSlotAt(frame_index);
57
58 if (value->is_register()) {
59 if (is_used(value->reg())) {
60 // The register already appears on the frame. Either the existing
61 // register element, or the new element at frame_index, must be made
62 // a copy.
63 int i = register_location(value->reg());
64
65 if (i < frame_index) {
66 // The register FrameElement is lower in the frame than the new copy.
67 elements_[frame_index] = CopyElementAt(i);
68 } else {
69 // There was an early bailout for the case of setting a
70 // register element to itself.
71 ASSERT(i != frame_index);
72 elements_[frame_index] = elements_[i];
73 elements_[i] = CopyElementAt(frame_index);
74 if (elements_[frame_index].is_synced()) {
75 elements_[i].set_sync();
76 }
77 elements_[frame_index].clear_sync();
78 set_register_location(value->reg(), frame_index);
79 for (int j = i + 1; j < element_count(); j++) {
80 if (elements_[j].is_copy() && elements_[j].index() == i) {
81 elements_[j].set_index(frame_index);
82 }
83 }
84 }
85 } else {
86 // The register value->reg() was not already used on the frame.
87 Use(value->reg(), frame_index);
88 elements_[frame_index] =
89 FrameElement::RegisterElement(value->reg(),
90 FrameElement::NOT_SYNCED,
91 value->type_info());
92 }
93 } else {
94 ASSERT(value->is_constant());
95 elements_[frame_index] =
96 FrameElement::ConstantElement(value->handle(),
97 FrameElement::NOT_SYNCED);
98 }
99 value->Unuse();
100}
101
102
103// Create a duplicate of an existing valid frame element.
104// We can pass an optional number type information that will override the
105// existing information about the backing element. The new information must
106// not conflict with the existing type information and must be equally or
107// more precise. The default parameter value kUninitialized means that there
108// is no additional information.
109FrameElement VirtualFrame::CopyElementAt(int index, TypeInfo info) {
110 ASSERT(index >= 0);
111 ASSERT(index < element_count());
112
113 FrameElement target = elements_[index];
114 FrameElement result;
115
116 switch (target.type()) {
117 case FrameElement::CONSTANT:
118 // We do not copy constants and instead return a fresh unsynced
119 // constant.
120 result = FrameElement::ConstantElement(target.handle(),
121 FrameElement::NOT_SYNCED);
122 break;
123
124 case FrameElement::COPY:
125 // We do not allow copies of copies, so we follow one link to
126 // the actual backing store of a copy before making a copy.
127 index = target.index();
128 ASSERT(elements_[index].is_memory() || elements_[index].is_register());
129 // Fall through.
130
131 case FrameElement::MEMORY: // Fall through.
132 case FrameElement::REGISTER: {
133 // All copies are backed by memory or register locations.
134 result.set_type(FrameElement::COPY);
135 result.clear_copied();
136 result.clear_sync();
137 result.set_index(index);
138 elements_[index].set_copied();
139 // Update backing element's number information.
140 TypeInfo existing = elements_[index].type_info();
141 ASSERT(!existing.IsUninitialized());
142 // Assert that the new type information (a) does not conflict with the
143 // existing one and (b) is equally or more precise.
144 ASSERT((info.ToInt() & existing.ToInt()) == existing.ToInt());
145 ASSERT((info.ToInt() | existing.ToInt()) == info.ToInt());
146
147 elements_[index].set_type_info(!info.IsUninitialized()
148 ? info
149 : existing);
150 break;
151 }
152 case FrameElement::INVALID:
153 // We should not try to copy invalid elements.
154 UNREACHABLE();
155 break;
156 }
157 return result;
158}
159
160
161// Modify the state of the virtual frame to match the actual frame by adding
162// extra in-memory elements to the top of the virtual frame. The extra
163// elements will be externally materialized on the actual frame (eg, by
164// pushing an exception handler). No code is emitted.
165void VirtualFrame::Adjust(int count) {
166 ASSERT(count >= 0);
167 ASSERT(stack_pointer_ == element_count() - 1);
168
169 for (int i = 0; i < count; i++) {
170 elements_.Add(FrameElement::MemoryElement(TypeInfo::Unknown()));
171 }
172 stack_pointer_ += count;
173}
174
175
176void VirtualFrame::ForgetElements(int count) {
177 ASSERT(count >= 0);
178 ASSERT(element_count() >= count);
179
180 for (int i = 0; i < count; i++) {
181 FrameElement last = elements_.RemoveLast();
182 if (last.is_register()) {
183 // A hack to properly count register references for the code
184 // generator's current frame and also for other frames. The
185 // same code appears in PrepareMergeTo.
186 if (cgen()->frame() == this) {
187 Unuse(last.reg());
188 } else {
189 set_register_location(last.reg(), kIllegalIndex);
190 }
191 }
192 }
193}
194
195
196// Make the type of the element at a given index be MEMORY.
197void VirtualFrame::SpillElementAt(int index) {
198 if (!elements_[index].is_valid()) return;
199
200 SyncElementAt(index);
201 // Number type information is preserved.
202 // Copies get their number information from their backing element.
203 TypeInfo info;
204 if (!elements_[index].is_copy()) {
205 info = elements_[index].type_info();
206 } else {
207 info = elements_[elements_[index].index()].type_info();
208 }
209 // The element is now in memory. Its copied flag is preserved.
210 FrameElement new_element = FrameElement::MemoryElement(info);
211 if (elements_[index].is_copied()) {
212 new_element.set_copied();
213 }
214 if (elements_[index].is_untagged_int32()) {
215 new_element.set_untagged_int32(true);
216 }
217 if (elements_[index].is_register()) {
218 Unuse(elements_[index].reg());
219 }
220 elements_[index] = new_element;
221}
222
223
224// Clear the dirty bit for the element at a given index.
225void VirtualFrame::SyncElementAt(int index) {
226 if (index <= stack_pointer_) {
227 if (!elements_[index].is_synced()) SyncElementBelowStackPointer(index);
228 } else if (index == stack_pointer_ + 1) {
229 SyncElementByPushing(index);
230 } else {
231 SyncRange(stack_pointer_ + 1, index);
232 }
233}
234
235
236void VirtualFrame::PrepareMergeTo(VirtualFrame* expected) {
237 // Perform state changes on this frame that will make merge to the
238 // expected frame simpler or else increase the likelihood that his
239 // frame will match another.
240 for (int i = 0; i < element_count(); i++) {
241 FrameElement source = elements_[i];
242 FrameElement target = expected->elements_[i];
243
244 if (!target.is_valid() ||
245 (target.is_memory() && !source.is_memory() && source.is_synced())) {
246 // No code needs to be generated to invalidate valid elements.
247 // No code needs to be generated to move values to memory if
248 // they are already synced. We perform those moves here, before
249 // merging.
250 if (source.is_register()) {
251 // If the frame is the code generator's current frame, we have
252 // to decrement both the frame-internal and global register
253 // counts.
254 if (cgen()->frame() == this) {
255 Unuse(source.reg());
256 } else {
257 set_register_location(source.reg(), kIllegalIndex);
258 }
259 }
260 elements_[i] = target;
261 } else if (target.is_register() && !target.is_synced() &&
262 !source.is_memory()) {
263 // If an element's target is a register that doesn't need to be
264 // synced, and the element is not in memory, then the sync state
265 // of the element is irrelevant. We clear the sync bit.
266 ASSERT(source.is_valid());
267 elements_[i].clear_sync();
268 }
269 }
270}
271
272
273void VirtualFrame::PrepareForCall(int spilled_args, int dropped_args) {
274 ASSERT(height() >= dropped_args);
275 ASSERT(height() >= spilled_args);
276 ASSERT(dropped_args <= spilled_args);
277
278 SyncRange(0, element_count() - 1);
279 // Spill registers.
280 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
281 if (is_used(i)) {
282 SpillElementAt(register_location(i));
283 }
284 }
285
286 // Spill the arguments.
287 for (int i = element_count() - spilled_args; i < element_count(); i++) {
288 if (!elements_[i].is_memory()) {
289 SpillElementAt(i);
290 }
291 }
292
293 // Forget the frame elements that will be popped by the call.
294 Forget(dropped_args);
295}
296
297
ager@chromium.org357bf652010-04-12 11:30:10 +0000298// If there are any registers referenced only by the frame, spill one.
299Register VirtualFrame::SpillAnyRegister() {
300 // Find the leftmost (ordered by register number) register whose only
301 // reference is in the frame.
302 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
303 if (is_used(i) && cgen()->allocator()->count(i) == 1) {
304 SpillElementAt(register_location(i));
305 ASSERT(!cgen()->allocator()->is_used(i));
306 return RegisterAllocator::ToRegister(i);
307 }
308 }
309 return no_reg;
310}
311
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000312} } // namespace v8::internal