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