• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
35 namespace internal {
36 
37 // -------------------------------------------------------------------------
38 // VirtualFrame implementation.
39 
40 #define __ ACCESS_MASM(masm())
41 
42 
43 // On entry to a function, the virtual frame already contains the
44 // receiver and the parameters.  All initial frame elements are in
45 // memory.
VirtualFrame()46 VirtualFrame::VirtualFrame()
47     : elements_(parameter_count() + local_count() + kPreallocatedElements),
48       stack_pointer_(parameter_count()) {  // 0-based index of TOS.
49   for (int i = 0; i <= stack_pointer_; i++) {
50     elements_.Add(FrameElement::MemoryElement(NumberInfo::kUnknown));
51   }
52   for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
53     register_locations_[i] = kIllegalIndex;
54   }
55 }
56 
57 
SyncElementBelowStackPointer(int index)58 void VirtualFrame::SyncElementBelowStackPointer(int index) {
59   UNREACHABLE();
60 }
61 
62 
SyncElementByPushing(int index)63 void VirtualFrame::SyncElementByPushing(int index) {
64   UNREACHABLE();
65 }
66 
67 
SyncRange(int begin,int end)68 void VirtualFrame::SyncRange(int begin, int end) {
69   // All elements are in memory on ARM (ie, synced).
70 #ifdef DEBUG
71   for (int i = begin; i <= end; i++) {
72     ASSERT(elements_[i].is_synced());
73   }
74 #endif
75 }
76 
77 
MergeTo(VirtualFrame * expected)78 void VirtualFrame::MergeTo(VirtualFrame* expected) {
79   // ARM frames are currently always in memory.
80   ASSERT(Equals(expected));
81 }
82 
83 
MergeMoveRegistersToMemory(VirtualFrame * expected)84 void VirtualFrame::MergeMoveRegistersToMemory(VirtualFrame* expected) {
85   UNREACHABLE();
86 }
87 
88 
MergeMoveRegistersToRegisters(VirtualFrame * expected)89 void VirtualFrame::MergeMoveRegistersToRegisters(VirtualFrame* expected) {
90   UNREACHABLE();
91 }
92 
93 
MergeMoveMemoryToRegisters(VirtualFrame * expected)94 void VirtualFrame::MergeMoveMemoryToRegisters(VirtualFrame* expected) {
95   UNREACHABLE();
96 }
97 
98 
Enter()99 void VirtualFrame::Enter() {
100   Comment cmnt(masm(), "[ Enter JS frame");
101 
102 #ifdef DEBUG
103   // Verify that r1 contains a JS function.  The following code relies
104   // on r2 being available for use.
105   if (FLAG_debug_code) {
106     Label map_check, done;
107     __ tst(r1, Operand(kSmiTagMask));
108     __ b(ne, &map_check);
109     __ stop("VirtualFrame::Enter - r1 is not a function (smi check).");
110     __ bind(&map_check);
111     __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
112     __ b(eq, &done);
113     __ stop("VirtualFrame::Enter - r1 is not a function (map check).");
114     __ bind(&done);
115   }
116 #endif  // DEBUG
117 
118   // We are about to push four values to the frame.
119   Adjust(4);
120   __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());
121   // Adjust FP to point to saved FP.
122   __ add(fp, sp, Operand(2 * kPointerSize));
123   cgen()->allocator()->Unuse(r1);
124   cgen()->allocator()->Unuse(lr);
125 }
126 
127 
Exit()128 void VirtualFrame::Exit() {
129   Comment cmnt(masm(), "[ Exit JS frame");
130   // Record the location of the JS exit code for patching when setting
131   // break point.
132   __ RecordJSReturn();
133 
134   // Drop the execution stack down to the frame pointer and restore the caller
135   // frame pointer and return address.
136   __ mov(sp, fp);
137   __ ldm(ia_w, sp, fp.bit() | lr.bit());
138 }
139 
140 
AllocateStackSlots()141 void VirtualFrame::AllocateStackSlots() {
142   int count = local_count();
143   if (count > 0) {
144     Comment cmnt(masm(), "[ Allocate space for locals");
145     Adjust(count);
146     // Initialize stack slots with 'undefined' value.
147     __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
148     __ LoadRoot(r2, Heap::kStackLimitRootIndex);
149     if (count < kLocalVarBound) {
150       // For less locals the unrolled loop is more compact.
151       for (int i = 0; i < count; i++) {
152         __ push(ip);
153       }
154     } else {
155       // For more locals a loop in generated code is more compact.
156       Label alloc_locals_loop;
157       __ mov(r1, Operand(count));
158       __ bind(&alloc_locals_loop);
159       __ push(ip);
160       __ sub(r1, r1, Operand(1), SetCC);
161       __ b(ne, &alloc_locals_loop);
162     }
163   } else {
164     __ LoadRoot(r2, Heap::kStackLimitRootIndex);
165   }
166   // Check the stack for overflow or a break request.
167   // Put the lr setup instruction in the delay slot.  The kInstrSize is added
168   // to the implicit 8 byte offset that always applies to operations with pc
169   // and gives a return address 12 bytes down.
170   masm()->add(lr, pc, Operand(Assembler::kInstrSize));
171   masm()->cmp(sp, Operand(r2));
172   StackCheckStub stub;
173   // Call the stub if lower.
174   masm()->mov(pc,
175               Operand(reinterpret_cast<intptr_t>(stub.GetCode().location()),
176                       RelocInfo::CODE_TARGET),
177               LeaveCC,
178               lo);
179 }
180 
181 
182 
SaveContextRegister()183 void VirtualFrame::SaveContextRegister() {
184   UNIMPLEMENTED();
185 }
186 
187 
RestoreContextRegister()188 void VirtualFrame::RestoreContextRegister() {
189   UNIMPLEMENTED();
190 }
191 
192 
PushReceiverSlotAddress()193 void VirtualFrame::PushReceiverSlotAddress() {
194   UNIMPLEMENTED();
195 }
196 
197 
InvalidateFrameSlotAt(int index)198 int VirtualFrame::InvalidateFrameSlotAt(int index) {
199   UNIMPLEMENTED();
200   return kIllegalIndex;
201 }
202 
203 
TakeFrameSlotAt(int index)204 void VirtualFrame::TakeFrameSlotAt(int index) {
205   UNIMPLEMENTED();
206 }
207 
208 
StoreToFrameSlotAt(int index)209 void VirtualFrame::StoreToFrameSlotAt(int index) {
210   UNIMPLEMENTED();
211 }
212 
213 
PushTryHandler(HandlerType type)214 void VirtualFrame::PushTryHandler(HandlerType type) {
215   // Grow the expression stack by handler size less one (the return
216   // address in lr is already counted by a call instruction).
217   Adjust(kHandlerSize - 1);
218   __ PushTryHandler(IN_JAVASCRIPT, type);
219 }
220 
221 
CallRuntime(Runtime::Function * f,int arg_count)222 void VirtualFrame::CallRuntime(Runtime::Function* f, int arg_count) {
223   Forget(arg_count);
224   ASSERT(cgen()->HasValidEntryRegisters());
225   __ CallRuntime(f, arg_count);
226 }
227 
228 
CallRuntime(Runtime::FunctionId id,int arg_count)229 void VirtualFrame::CallRuntime(Runtime::FunctionId id, int arg_count) {
230   Forget(arg_count);
231   ASSERT(cgen()->HasValidEntryRegisters());
232   __ CallRuntime(id, arg_count);
233 }
234 
235 
236 #ifdef ENABLE_DEBUGGER_SUPPORT
DebugBreak()237 void VirtualFrame::DebugBreak() {
238   ASSERT(cgen()->HasValidEntryRegisters());
239   __ DebugBreak();
240 }
241 #endif
242 
243 
InvokeBuiltin(Builtins::JavaScript id,InvokeJSFlags flags,int arg_count)244 void VirtualFrame::InvokeBuiltin(Builtins::JavaScript id,
245                                  InvokeJSFlags flags,
246                                  int arg_count) {
247   Forget(arg_count);
248   __ InvokeBuiltin(id, flags);
249 }
250 
251 
CallCodeObject(Handle<Code> code,RelocInfo::Mode rmode,int dropped_args)252 void VirtualFrame::CallCodeObject(Handle<Code> code,
253                                   RelocInfo::Mode rmode,
254                                   int dropped_args) {
255   switch (code->kind()) {
256     case Code::CALL_IC:
257     case Code::FUNCTION:
258       break;
259     case Code::KEYED_LOAD_IC:
260     case Code::LOAD_IC:
261     case Code::KEYED_STORE_IC:
262     case Code::STORE_IC:
263       ASSERT(dropped_args == 0);
264       break;
265     case Code::BUILTIN:
266       ASSERT(*code == Builtins::builtin(Builtins::JSConstructCall));
267       break;
268     default:
269       UNREACHABLE();
270       break;
271   }
272   Forget(dropped_args);
273   ASSERT(cgen()->HasValidEntryRegisters());
274   __ Call(code, rmode);
275 }
276 
277 
Drop(int count)278 void VirtualFrame::Drop(int count) {
279   ASSERT(count >= 0);
280   ASSERT(height() >= count);
281   int num_virtual_elements = (element_count() - 1) - stack_pointer_;
282 
283   // Emit code to lower the stack pointer if necessary.
284   if (num_virtual_elements < count) {
285     int num_dropped = count - num_virtual_elements;
286     stack_pointer_ -= num_dropped;
287     __ add(sp, sp, Operand(num_dropped * kPointerSize));
288   }
289 
290   // Discard elements from the virtual frame and free any registers.
291   for (int i = 0; i < count; i++) {
292     FrameElement dropped = elements_.RemoveLast();
293     if (dropped.is_register()) {
294       Unuse(dropped.reg());
295     }
296   }
297 }
298 
299 
Pop()300 Result VirtualFrame::Pop() {
301   UNIMPLEMENTED();
302   return Result();
303 }
304 
305 
EmitPop(Register reg)306 void VirtualFrame::EmitPop(Register reg) {
307   ASSERT(stack_pointer_ == element_count() - 1);
308   stack_pointer_--;
309   elements_.RemoveLast();
310   __ pop(reg);
311 }
312 
313 
EmitPush(Register reg)314 void VirtualFrame::EmitPush(Register reg) {
315   ASSERT(stack_pointer_ == element_count() - 1);
316   elements_.Add(FrameElement::MemoryElement(NumberInfo::kUnknown));
317   stack_pointer_++;
318   __ push(reg);
319 }
320 
321 
EmitPushMultiple(int count,int src_regs)322 void VirtualFrame::EmitPushMultiple(int count, int src_regs) {
323   ASSERT(stack_pointer_ == element_count() - 1);
324   Adjust(count);
325   __ stm(db_w, sp, src_regs);
326 }
327 
328 
329 #undef __
330 
331 } }  // namespace v8::internal
332