OLD | NEW |
| (Empty) |
1 // Copyright 2009 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 "scopes.h" | |
33 | |
34 namespace v8 { namespace internal { | |
35 | |
36 // ------------------------------------------------------------------------- | |
37 // VirtualFrame implementation. | |
38 | |
39 #define __ ACCESS_MASM(masm_) | |
40 | |
41 | |
42 // On entry to a function, the virtual frame already contains the | |
43 // receiver and the parameters. All initial frame elements are in | |
44 // memory. | |
45 VirtualFrame::VirtualFrame(CodeGenerator* cgen) | |
46 : cgen_(cgen), | |
47 masm_(cgen->masm()), | |
48 elements_(cgen->scope()->num_parameters() | |
49 + cgen->scope()->num_stack_slots() | |
50 + kPreallocatedElements), | |
51 parameter_count_(cgen->scope()->num_parameters()), | |
52 local_count_(0), | |
53 stack_pointer_(parameter_count_), // 0-based index of TOS. | |
54 frame_pointer_(kIllegalIndex) { | |
55 for (int i = 0; i < parameter_count_ + 1; i++) { | |
56 elements_.Add(FrameElement::MemoryElement()); | |
57 } | |
58 for (int i = 0; i < kNumRegisters; i++) { | |
59 register_locations_[i] = kIllegalIndex; | |
60 } | |
61 } | |
62 | |
63 | |
64 void VirtualFrame::SyncElementBelowStackPointer(int index) { | |
65 UNREACHABLE(); | |
66 } | |
67 | |
68 | |
69 void VirtualFrame::SyncElementByPushing(int index) { | |
70 UNREACHABLE(); | |
71 } | |
72 | |
73 | |
74 void VirtualFrame::MergeTo(VirtualFrame* expected) { | |
75 Comment cmnt(masm_, "[ Merge frame"); | |
76 // We should always be merging the code generator's current frame to an | |
77 // expected frame. | |
78 ASSERT(cgen_->frame() == this); | |
79 | |
80 // Adjust the stack pointer upward (toward the top of the virtual | |
81 // frame) if necessary. | |
82 if (stack_pointer_ < expected->stack_pointer_) { | |
83 int difference = expected->stack_pointer_ - stack_pointer_; | |
84 stack_pointer_ = expected->stack_pointer_; | |
85 __ sub(sp, sp, Operand(difference * kPointerSize)); | |
86 } | |
87 | |
88 MergeMoveRegistersToMemory(expected); | |
89 MergeMoveRegistersToRegisters(expected); | |
90 MergeMoveMemoryToRegisters(expected); | |
91 | |
92 // Fix any sync bit problems from the bottom-up, stopping when we | |
93 // hit the stack pointer or the top of the frame if the stack | |
94 // pointer is floating above the frame. | |
95 int limit = Min(stack_pointer_, elements_.length() - 1); | |
96 for (int i = 0; i <= limit; i++) { | |
97 FrameElement source = elements_[i]; | |
98 FrameElement target = expected->elements_[i]; | |
99 if (source.is_synced() && !target.is_synced()) { | |
100 elements_[i].clear_sync(); | |
101 } else if (!source.is_synced() && target.is_synced()) { | |
102 SyncElementAt(i); | |
103 } | |
104 } | |
105 | |
106 // Adjust the stack point downard if necessary. | |
107 if (stack_pointer_ > expected->stack_pointer_) { | |
108 int difference = stack_pointer_ - expected->stack_pointer_; | |
109 stack_pointer_ = expected->stack_pointer_; | |
110 __ add(sp, sp, Operand(difference * kPointerSize)); | |
111 } | |
112 | |
113 // At this point, the frames should be identical. | |
114 ASSERT(Equals(expected)); | |
115 } | |
116 | |
117 | |
118 void VirtualFrame::MergeMoveRegistersToMemory(VirtualFrame* expected) { | |
119 ASSERT(stack_pointer_ >= expected->stack_pointer_); | |
120 | |
121 // Move registers, constants, and copies to memory. Perform moves | |
122 // from the top downward in the frame in order to leave the backing | |
123 // stores of copies in registers. | |
124 // On ARM, all elements are in memory. | |
125 | |
126 #ifdef DEBUG | |
127 int start = Min(stack_pointer_, elements_.length() - 1); | |
128 for (int i = start; i >= 0; i--) { | |
129 ASSERT(elements_[i].is_memory()); | |
130 ASSERT(expected->elements_[i].is_memory()); | |
131 } | |
132 #endif | |
133 } | |
134 | |
135 | |
136 void VirtualFrame::MergeMoveRegistersToRegisters(VirtualFrame* expected) { | |
137 } | |
138 | |
139 | |
140 void VirtualFrame::MergeMoveMemoryToRegisters(VirtualFrame *expected) { | |
141 } | |
142 | |
143 | |
144 void VirtualFrame::Enter() { | |
145 Comment cmnt(masm_, "[ Enter JS frame"); | |
146 | |
147 #ifdef DEBUG | |
148 // Verify that r1 contains a JS function. The following code relies | |
149 // on r2 being available for use. | |
150 { Label map_check, done; | |
151 __ tst(r1, Operand(kSmiTagMask)); | |
152 __ b(ne, &map_check); | |
153 __ stop("VirtualFrame::Enter - r1 is not a function (smi check)."); | |
154 __ bind(&map_check); | |
155 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); | |
156 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); | |
157 __ cmp(r2, Operand(JS_FUNCTION_TYPE)); | |
158 __ b(eq, &done); | |
159 __ stop("VirtualFrame::Enter - r1 is not a function (map check)."); | |
160 __ bind(&done); | |
161 } | |
162 #endif // DEBUG | |
163 | |
164 // We are about to push four values to the frame. | |
165 Adjust(4); | |
166 __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit()); | |
167 // Adjust FP to point to saved FP. | |
168 frame_pointer_ = elements_.length() - 2; | |
169 __ add(fp, sp, Operand(2 * kPointerSize)); | |
170 cgen_->allocator()->Unuse(r1); | |
171 cgen_->allocator()->Unuse(lr); | |
172 } | |
173 | |
174 | |
175 void VirtualFrame::Exit() { | |
176 Comment cmnt(masm_, "[ Exit JS frame"); | |
177 // Drop the execution stack down to the frame pointer and restore the caller | |
178 // frame pointer and return address. | |
179 __ mov(sp, fp); | |
180 __ ldm(ia_w, sp, fp.bit() | lr.bit()); | |
181 } | |
182 | |
183 | |
184 void VirtualFrame::AllocateStackSlots(int count) { | |
185 ASSERT(height() == 0); | |
186 local_count_ = count; | |
187 Adjust(count); | |
188 if (count > 0) { | |
189 Comment cmnt(masm_, "[ Allocate space for locals"); | |
190 // Initialize stack slots with 'undefined' value. | |
191 __ mov(ip, Operand(Factory::undefined_value())); | |
192 for (int i = 0; i < count; i++) { | |
193 __ push(ip); | |
194 } | |
195 } | |
196 } | |
197 | |
198 | |
199 void VirtualFrame::SaveContextRegister() { | |
200 UNIMPLEMENTED(); | |
201 } | |
202 | |
203 | |
204 void VirtualFrame::RestoreContextRegister() { | |
205 UNIMPLEMENTED(); | |
206 } | |
207 | |
208 | |
209 void VirtualFrame::PushReceiverSlotAddress() { | |
210 UNIMPLEMENTED(); | |
211 } | |
212 | |
213 | |
214 int VirtualFrame::InvalidateFrameSlotAt(int index) { | |
215 UNIMPLEMENTED(); | |
216 return kIllegalIndex; | |
217 } | |
218 | |
219 | |
220 void VirtualFrame::TakeFrameSlotAt(int index) { | |
221 UNIMPLEMENTED(); | |
222 } | |
223 | |
224 | |
225 void VirtualFrame::StoreToFrameSlotAt(int index) { | |
226 UNIMPLEMENTED(); | |
227 } | |
228 | |
229 | |
230 void VirtualFrame::PushTryHandler(HandlerType type) { | |
231 // Grow the expression stack by handler size less one (the return address | |
232 // is already pushed by a call instruction). | |
233 Adjust(kHandlerSize - 1); | |
234 __ PushTryHandler(IN_JAVASCRIPT, type); | |
235 } | |
236 | |
237 | |
238 Result VirtualFrame::RawCallStub(CodeStub* stub) { | |
239 ASSERT(cgen_->HasValidEntryRegisters()); | |
240 __ CallStub(stub); | |
241 Result result = cgen_->allocator()->Allocate(r0); | |
242 ASSERT(result.is_valid()); | |
243 return result; | |
244 } | |
245 | |
246 | |
247 Result VirtualFrame::CallStub(CodeStub* stub, Result* arg) { | |
248 PrepareForCall(0, 0); | |
249 arg->Unuse(); | |
250 return RawCallStub(stub); | |
251 } | |
252 | |
253 | |
254 Result VirtualFrame::CallStub(CodeStub* stub, Result* arg0, Result* arg1) { | |
255 PrepareForCall(0, 0); | |
256 arg0->Unuse(); | |
257 arg1->Unuse(); | |
258 return RawCallStub(stub); | |
259 } | |
260 | |
261 | |
262 Result VirtualFrame::CallRuntime(Runtime::Function* f, int arg_count) { | |
263 PrepareForCall(arg_count, arg_count); | |
264 ASSERT(cgen_->HasValidEntryRegisters()); | |
265 __ CallRuntime(f, arg_count); | |
266 Result result = cgen_->allocator()->Allocate(r0); | |
267 ASSERT(result.is_valid()); | |
268 return result; | |
269 } | |
270 | |
271 | |
272 Result VirtualFrame::CallRuntime(Runtime::FunctionId id, int arg_count) { | |
273 PrepareForCall(arg_count, arg_count); | |
274 ASSERT(cgen_->HasValidEntryRegisters()); | |
275 __ CallRuntime(id, arg_count); | |
276 Result result = cgen_->allocator()->Allocate(r0); | |
277 ASSERT(result.is_valid()); | |
278 return result; | |
279 } | |
280 | |
281 | |
282 Result VirtualFrame::InvokeBuiltin(Builtins::JavaScript id, | |
283 InvokeJSFlags flags, | |
284 Result* arg_count_register, | |
285 int arg_count) { | |
286 ASSERT(arg_count_register->reg().is(r0)); | |
287 PrepareForCall(arg_count, arg_count); | |
288 arg_count_register->Unuse(); | |
289 __ InvokeBuiltin(id, flags); | |
290 Result result = cgen_->allocator()->Allocate(r0); | |
291 return result; | |
292 } | |
293 | |
294 | |
295 Result VirtualFrame::RawCallCodeObject(Handle<Code> code, | |
296 RelocInfo::Mode rmode) { | |
297 ASSERT(cgen_->HasValidEntryRegisters()); | |
298 __ Call(code, rmode); | |
299 Result result = cgen_->allocator()->Allocate(r0); | |
300 ASSERT(result.is_valid()); | |
301 return result; | |
302 } | |
303 | |
304 | |
305 Result VirtualFrame::CallCodeObject(Handle<Code> code, | |
306 RelocInfo::Mode rmode, | |
307 int dropped_args) { | |
308 int spilled_args = 0; | |
309 switch (code->kind()) { | |
310 case Code::CALL_IC: | |
311 spilled_args = dropped_args + 1; | |
312 break; | |
313 case Code::FUNCTION: | |
314 spilled_args = dropped_args + 1; | |
315 break; | |
316 case Code::KEYED_LOAD_IC: | |
317 ASSERT(dropped_args == 0); | |
318 spilled_args = 2; | |
319 break; | |
320 default: | |
321 // The other types of code objects are called with values | |
322 // in specific registers, and are handled in functions with | |
323 // a different signature. | |
324 UNREACHABLE(); | |
325 break; | |
326 } | |
327 PrepareForCall(spilled_args, dropped_args); | |
328 return RawCallCodeObject(code, rmode); | |
329 } | |
330 | |
331 | |
332 Result VirtualFrame::CallCodeObject(Handle<Code> code, | |
333 RelocInfo::Mode rmode, | |
334 Result* arg, | |
335 int dropped_args) { | |
336 int spilled_args = 0; | |
337 switch (code->kind()) { | |
338 case Code::LOAD_IC: | |
339 ASSERT(arg->reg().is(r2)); | |
340 ASSERT(dropped_args == 0); | |
341 spilled_args = 1; | |
342 break; | |
343 case Code::KEYED_STORE_IC: | |
344 ASSERT(arg->reg().is(r0)); | |
345 ASSERT(dropped_args == 0); | |
346 spilled_args = 2; | |
347 break; | |
348 default: | |
349 // No other types of code objects are called with values | |
350 // in exactly one register. | |
351 UNREACHABLE(); | |
352 break; | |
353 } | |
354 PrepareForCall(spilled_args, dropped_args); | |
355 arg->Unuse(); | |
356 return RawCallCodeObject(code, rmode); | |
357 } | |
358 | |
359 | |
360 Result VirtualFrame::CallCodeObject(Handle<Code> code, | |
361 RelocInfo::Mode rmode, | |
362 Result* arg0, | |
363 Result* arg1, | |
364 int dropped_args) { | |
365 int spilled_args = 1; | |
366 switch (code->kind()) { | |
367 case Code::STORE_IC: | |
368 ASSERT(arg0->reg().is(r0)); | |
369 ASSERT(arg1->reg().is(r2)); | |
370 ASSERT(dropped_args == 0); | |
371 spilled_args = 1; | |
372 break; | |
373 case Code::BUILTIN: | |
374 ASSERT(*code == Builtins::builtin(Builtins::JSConstructCall)); | |
375 ASSERT(arg0->reg().is(r0)); | |
376 ASSERT(arg1->reg().is(r1)); | |
377 spilled_args = dropped_args + 1; | |
378 break; | |
379 default: | |
380 // No other types of code objects are called with values | |
381 // in exactly two registers. | |
382 UNREACHABLE(); | |
383 break; | |
384 } | |
385 PrepareForCall(spilled_args, dropped_args); | |
386 arg0->Unuse(); | |
387 arg1->Unuse(); | |
388 return RawCallCodeObject(code, rmode); | |
389 } | |
390 | |
391 | |
392 void VirtualFrame::Drop(int count) { | |
393 ASSERT(height() >= count); | |
394 int num_virtual_elements = (elements_.length() - 1) - stack_pointer_; | |
395 | |
396 // Emit code to lower the stack pointer if necessary. | |
397 if (num_virtual_elements < count) { | |
398 int num_dropped = count - num_virtual_elements; | |
399 stack_pointer_ -= num_dropped; | |
400 __ add(sp, sp, Operand(num_dropped * kPointerSize)); | |
401 } | |
402 | |
403 // Discard elements from the virtual frame and free any registers. | |
404 for (int i = 0; i < count; i++) { | |
405 FrameElement dropped = elements_.RemoveLast(); | |
406 if (dropped.is_register()) { | |
407 Unuse(dropped.reg()); | |
408 } | |
409 } | |
410 } | |
411 | |
412 | |
413 Result VirtualFrame::Pop() { | |
414 UNIMPLEMENTED(); | |
415 Result invalid(cgen_); | |
416 return invalid; | |
417 } | |
418 | |
419 | |
420 void VirtualFrame::EmitPop(Register reg) { | |
421 ASSERT(stack_pointer_ == elements_.length() - 1); | |
422 stack_pointer_--; | |
423 elements_.RemoveLast(); | |
424 __ pop(reg); | |
425 } | |
426 | |
427 | |
428 void VirtualFrame::EmitPush(Register reg) { | |
429 ASSERT(stack_pointer_ == elements_.length() - 1); | |
430 elements_.Add(FrameElement::MemoryElement()); | |
431 stack_pointer_++; | |
432 __ push(reg); | |
433 } | |
434 | |
435 | |
436 #undef __ | |
437 | |
438 } } // namespace v8::internal | |
OLD | NEW |