OLD | NEW |
---|---|
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 19 matching lines...) Expand all Loading... | |
30 #include "codegen-inl.h" | 30 #include "codegen-inl.h" |
31 #include "register-allocator-inl.h" | 31 #include "register-allocator-inl.h" |
32 #include "scopes.h" | 32 #include "scopes.h" |
33 #include "virtual-frame-inl.h" | 33 #include "virtual-frame-inl.h" |
34 | 34 |
35 namespace v8 { | 35 namespace v8 { |
36 namespace internal { | 36 namespace internal { |
37 | 37 |
38 #define __ ACCESS_MASM(masm()) | 38 #define __ ACCESS_MASM(masm()) |
39 | 39 |
40 void VirtualFrame::SyncElementBelowStackPointer(int index) { | 40 void VirtualFrame::PopToR1R0() { |
41 UNREACHABLE(); | 41 VirtualFrame where_to_go = *this; |
42 where_to_go.top_of_stack_state_ = R1_R0_TOS; | |
43 MergeTo(&where_to_go); | |
Søren Thygesen Gjesse
2010/04/07 10:46:51
Maybe add a comment here saying the r0/r1 TOS stat
Erik Corry
2010/04/07 12:49:17
Done.
| |
44 element_count_ -= 2; | |
45 top_of_stack_state_ = NO_TOS_REGISTERS; | |
42 } | 46 } |
43 | 47 |
44 | 48 |
45 void VirtualFrame::SyncElementByPushing(int index) { | 49 void VirtualFrame::PopToR1() { |
46 UNREACHABLE(); | 50 VirtualFrame where_to_go = *this; |
51 where_to_go.top_of_stack_state_ = R1_TOS; | |
52 MergeTo(&where_to_go); | |
53 element_count_ -= 1; | |
54 top_of_stack_state_ = NO_TOS_REGISTERS; | |
55 } | |
56 | |
57 | |
58 void VirtualFrame::PopToR0() { | |
59 VirtualFrame where_to_go = *this; | |
60 where_to_go.top_of_stack_state_ = R0_TOS; | |
61 MergeTo(&where_to_go); | |
62 element_count_ -= 1; | |
63 top_of_stack_state_ = NO_TOS_REGISTERS; | |
47 } | 64 } |
48 | 65 |
49 | 66 |
50 void VirtualFrame::MergeTo(VirtualFrame* expected) { | 67 void VirtualFrame::MergeTo(VirtualFrame* expected) { |
Kasper Lund
2010/04/07 08:09:50
Do you have good tests of this function? Full cove
Erik Corry
2010/04/07 12:49:17
No. The coverage tool for covering code generated
| |
51 // ARM frames are currently always in memory. | 68 if (Equals(expected)) return; |
52 ASSERT(Equals(expected)); | 69 switch (top_of_stack_state_ * 5 + expected->top_of_stack_state_) { |
Søren Thygesen Gjesse
2010/04/07 10:46:51
Maybe add a macro for (one_state * 5 + another_sta
Erik Corry
2010/04/07 12:49:17
On ARM multiplying by 5 should be the same speed a
| |
53 } | 70 case NO_TOS_REGISTERS * 5 + NO_TOS_REGISTERS: |
54 | 71 break; |
55 | 72 case NO_TOS_REGISTERS * 5 + R0_TOS: |
56 void VirtualFrame::MergeMoveRegistersToMemory(VirtualFrame* expected) { | 73 __ pop(r0); |
57 UNREACHABLE(); | 74 break; |
58 } | 75 case NO_TOS_REGISTERS * 5 + R1_TOS: |
59 | 76 __ pop(r1); |
60 | 77 break; |
61 void VirtualFrame::MergeMoveRegistersToRegisters(VirtualFrame* expected) { | 78 case NO_TOS_REGISTERS * 5 + R1_R0_TOS: |
62 UNREACHABLE(); | 79 __ pop(r0); |
63 } | 80 __ pop(r1); |
64 | 81 break; |
65 | 82 case NO_TOS_REGISTERS * 5 + R0_R1_TOS: |
66 void VirtualFrame::MergeMoveMemoryToRegisters(VirtualFrame* expected) { | 83 __ pop(r0); |
67 UNREACHABLE(); | 84 __ pop(r1); |
85 break; | |
86 case R0_TOS * 5 + NO_TOS_REGISTERS: | |
87 __ push(r0); | |
88 break; | |
89 case R0_TOS * 5 + R0_TOS: | |
90 break; | |
91 case R0_TOS * 5 + R1_TOS: | |
92 __ mov(r1, r0); | |
93 break; | |
94 case R0_TOS * 5 + R1_R0_TOS: | |
95 __ pop(r1); | |
96 break; | |
97 case R0_TOS * 5 + R0_R1_TOS: | |
98 __ mov(r1, r0); | |
99 __ pop(r0); | |
100 break; | |
101 case R1_TOS * 5 + NO_TOS_REGISTERS: | |
102 __ push(r1); | |
103 break; | |
104 case R1_TOS * 5 + R0_TOS: | |
105 __ mov(r0, r1); | |
106 break; | |
107 case R1_TOS * 5 + R1_TOS: | |
108 break; | |
109 case R1_TOS * 5 + R1_R0_TOS: | |
110 __ mov(r0, r1); | |
111 __ pop(r1); | |
112 break; | |
113 case R1_TOS * 5 + R0_R1_TOS: | |
114 __ pop(r0); | |
115 break; | |
116 case R1_R0_TOS * 5 + NO_TOS_REGISTERS: | |
117 __ push(r1); | |
118 __ push(r0); | |
119 break; | |
120 case R1_R0_TOS * 5 + R0_TOS: | |
121 __ push(r1); | |
122 break; | |
123 case R1_R0_TOS * 5 + R1_TOS: | |
124 __ push(r1); | |
125 __ mov(r1, r0); | |
126 break; | |
127 case R1_R0_TOS * 5 + R1_R0_TOS: | |
128 break; | |
129 case R1_R0_TOS * 5 + R0_R1_TOS: | |
Søren Thygesen Gjesse
2010/04/07 07:53:37
MacroAssembler::Swap?
Erik Corry
2010/04/07 12:49:17
Done.
| |
130 __ eor(r0, r0, Operand(r1)); | |
131 __ eor(r1, r1, Operand(r0)); | |
132 __ eor(r0, r0, Operand(r1)); | |
133 break; | |
134 case R0_R1_TOS * 5 + NO_TOS_REGISTERS: | |
135 __ push(r0); | |
136 __ push(r1); | |
137 break; | |
138 case R0_R1_TOS * 5 + R0_TOS: | |
139 __ push(r0); | |
140 __ mov(r0, r1); | |
141 break; | |
142 case R0_R1_TOS * 5 + R1_TOS: | |
143 __ push(r0); | |
144 break; | |
145 case R0_R1_TOS * 5 + R1_R0_TOS: | |
146 __ eor(r0, r0, Operand(r1)); | |
Kasper Lund
2010/04/07 08:09:50
Swap again.
Erik Corry
2010/04/07 12:49:17
Done.
| |
147 __ eor(r1, r1, Operand(r0)); | |
148 __ eor(r0, r0, Operand(r1)); | |
149 break; | |
150 case R0_R1_TOS * 5 + R0_R1_TOS: | |
151 break; | |
Søren Thygesen Gjesse
2010/04/07 10:46:51
default with UNREACHABLE()?
Erik Corry
2010/04/07 12:49:17
Done.
| |
152 } | |
153 ASSERT(register_allocation_map_ == expected->register_allocation_map_); | |
68 } | 154 } |
69 | 155 |
70 | 156 |
71 void VirtualFrame::Enter() { | 157 void VirtualFrame::Enter() { |
72 Comment cmnt(masm(), "[ Enter JS frame"); | 158 Comment cmnt(masm(), "[ Enter JS frame"); |
73 | 159 |
74 #ifdef DEBUG | 160 #ifdef DEBUG |
75 // Verify that r1 contains a JS function. The following code relies | 161 // Verify that r1 contains a JS function. The following code relies |
76 // on r2 being available for use. | 162 // on r2 being available for use. |
77 if (FLAG_debug_code) { | 163 if (FLAG_debug_code) { |
78 Label map_check, done; | 164 Label map_check, done; |
79 __ tst(r1, Operand(kSmiTagMask)); | 165 __ tst(r1, Operand(kSmiTagMask)); |
80 __ b(ne, &map_check); | 166 __ b(ne, &map_check); |
81 __ stop("VirtualFrame::Enter - r1 is not a function (smi check)."); | 167 __ stop("VirtualFrame::Enter - r1 is not a function (smi check)."); |
82 __ bind(&map_check); | 168 __ bind(&map_check); |
83 __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE); | 169 __ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE); |
84 __ b(eq, &done); | 170 __ b(eq, &done); |
85 __ stop("VirtualFrame::Enter - r1 is not a function (map check)."); | 171 __ stop("VirtualFrame::Enter - r1 is not a function (map check)."); |
86 __ bind(&done); | 172 __ bind(&done); |
87 } | 173 } |
88 #endif // DEBUG | 174 #endif // DEBUG |
89 | 175 |
90 // We are about to push four values to the frame. | 176 // We are about to push four values to the frame. |
91 Adjust(4); | 177 Adjust(4); |
92 __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit()); | 178 __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit()); |
93 // Adjust FP to point to saved FP. | 179 // Adjust FP to point to saved FP. |
94 __ add(fp, sp, Operand(2 * kPointerSize)); | 180 __ add(fp, sp, Operand(2 * kPointerSize)); |
95 cgen()->allocator()->Unuse(r1); | |
96 cgen()->allocator()->Unuse(lr); | |
97 } | 181 } |
98 | 182 |
99 | 183 |
100 void VirtualFrame::Exit() { | 184 void VirtualFrame::Exit() { |
101 Comment cmnt(masm(), "[ Exit JS frame"); | 185 Comment cmnt(masm(), "[ Exit JS frame"); |
102 // Record the location of the JS exit code for patching when setting | 186 // Record the location of the JS exit code for patching when setting |
103 // break point. | 187 // break point. |
104 __ RecordJSReturn(); | 188 __ RecordJSReturn(); |
105 | 189 |
106 // Drop the execution stack down to the frame pointer and restore the caller | 190 // Drop the execution stack down to the frame pointer and restore the caller |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
145 // Call the stub if lower. | 229 // Call the stub if lower. |
146 masm()->mov(pc, | 230 masm()->mov(pc, |
147 Operand(reinterpret_cast<intptr_t>(stub.GetCode().location()), | 231 Operand(reinterpret_cast<intptr_t>(stub.GetCode().location()), |
148 RelocInfo::CODE_TARGET), | 232 RelocInfo::CODE_TARGET), |
149 LeaveCC, | 233 LeaveCC, |
150 lo); | 234 lo); |
151 } | 235 } |
152 | 236 |
153 | 237 |
154 | 238 |
155 void VirtualFrame::SaveContextRegister() { | |
156 UNIMPLEMENTED(); | |
157 } | |
158 | |
159 | |
160 void VirtualFrame::RestoreContextRegister() { | |
161 UNIMPLEMENTED(); | |
162 } | |
163 | |
164 | |
165 void VirtualFrame::PushReceiverSlotAddress() { | 239 void VirtualFrame::PushReceiverSlotAddress() { |
166 UNIMPLEMENTED(); | 240 UNIMPLEMENTED(); |
167 } | 241 } |
168 | 242 |
169 | 243 |
170 int VirtualFrame::InvalidateFrameSlotAt(int index) { | |
171 UNIMPLEMENTED(); | |
172 return kIllegalIndex; | |
173 } | |
174 | |
175 | |
176 void VirtualFrame::TakeFrameSlotAt(int index) { | |
177 UNIMPLEMENTED(); | |
178 } | |
179 | |
180 | |
181 void VirtualFrame::StoreToFrameSlotAt(int index) { | |
182 UNIMPLEMENTED(); | |
183 } | |
184 | |
185 | |
186 void VirtualFrame::PushTryHandler(HandlerType type) { | 244 void VirtualFrame::PushTryHandler(HandlerType type) { |
187 // Grow the expression stack by handler size less one (the return | 245 // Grow the expression stack by handler size less one (the return |
188 // address in lr is already counted by a call instruction). | 246 // address in lr is already counted by a call instruction). |
189 Adjust(kHandlerSize - 1); | 247 Adjust(kHandlerSize - 1); |
190 __ PushTryHandler(IN_JAVASCRIPT, type); | 248 __ PushTryHandler(IN_JAVASCRIPT, type); |
191 } | 249 } |
192 | 250 |
193 | 251 |
194 void VirtualFrame::CallRuntime(Runtime::Function* f, int arg_count) { | 252 void VirtualFrame::CallRuntime(Runtime::Function* f, int arg_count) { |
195 Forget(arg_count); | 253 Forget(arg_count); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
239 break; | 297 break; |
240 default: | 298 default: |
241 UNREACHABLE(); | 299 UNREACHABLE(); |
242 break; | 300 break; |
243 } | 301 } |
244 Forget(dropped_args); | 302 Forget(dropped_args); |
245 ASSERT(cgen()->HasValidEntryRegisters()); | 303 ASSERT(cgen()->HasValidEntryRegisters()); |
246 __ Call(code, rmode); | 304 __ Call(code, rmode); |
247 } | 305 } |
248 | 306 |
249 | 307 |
Søren Thygesen Gjesse
2010/04/07 10:46:51
Lining up the states in a comment here could be he
Erik Corry
2010/04/07 12:49:17
Done.
| |
308 const bool VirtualFrame::kR0InUse[TOS_STATES] = | |
309 { false, true, false, true, true }; | |
310 const bool VirtualFrame::kR1InUse[TOS_STATES] = | |
311 { false, false, true, true, true }; | |
312 const int VirtualFrame::kVirtualElements[TOS_STATES] = { 0, 1, 1, 2, 2 }; | |
313 const VirtualFrame::TopOfStack VirtualFrame::kPopState[TOS_STATES] = | |
314 { NO_TOS_REGISTERS, NO_TOS_REGISTERS, NO_TOS_REGISTERS, R0_TOS, R1_TOS }; | |
315 const VirtualFrame::TopOfStack VirtualFrame::kPushState[TOS_STATES] = | |
316 { R0_TOS, R0_R1_TOS, R1_R0_TOS, R1_R0_TOS, R0_R1_TOS }; | |
317 const Register VirtualFrame::kTopRegister[TOS_STATES] = { r0, r0, r1, r1, r0 }; | |
318 const Register VirtualFrame::kBottomRegister[TOS_STATES] = | |
319 { r0, r0, r1, r0, r1 }; | |
320 const Register VirtualFrame::kAllocatedRegisters[ | |
321 VirtualFrame::kNumberOfAllocatedRegisters] = { r2, r3, r4, r5, r6 }; | |
322 | |
323 | |
324 bool VirtualFrame::SpilledScope::is_spilled_ = false; | |
325 | |
326 | |
250 void VirtualFrame::Drop(int count) { | 327 void VirtualFrame::Drop(int count) { |
251 ASSERT(count >= 0); | 328 ASSERT(count >= 0); |
252 ASSERT(height() >= count); | 329 ASSERT(height() >= count); |
253 int num_virtual_elements = (element_count() - 1) - stack_pointer_; | 330 // Discard elements from the virtual frame and free any registers. |
254 | 331 int num_virtual_elements = kVirtualElements[top_of_stack_state_]; |
255 // Emit code to lower the stack pointer if necessary. | 332 while (num_virtual_elements > 0) { |
256 if (num_virtual_elements < count) { | 333 Pop(); |
257 int num_dropped = count - num_virtual_elements; | 334 num_virtual_elements--; |
258 stack_pointer_ -= num_dropped; | 335 count--; |
259 __ add(sp, sp, Operand(num_dropped * kPointerSize)); | 336 if (count == 0) return; |
260 } | 337 } |
261 | 338 if (count == 0) return; |
262 // Discard elements from the virtual frame and free any registers. | 339 __ add(sp, sp, Operand(count * kPointerSize)); |
263 element_count_ -= count; | 340 element_count_ -= count; |
264 } | 341 } |
265 | 342 |
266 | 343 |
267 Result VirtualFrame::Pop() { | 344 void VirtualFrame::Pop() { |
268 UNIMPLEMENTED(); | 345 if (top_of_stack_state_ == NO_TOS_REGISTERS) { |
269 return Result(); | 346 __ add(sp, sp, Operand(kPointerSize)); |
347 } else { | |
348 top_of_stack_state_ = kPopState[top_of_stack_state_]; | |
349 } | |
350 element_count_--; | |
270 } | 351 } |
271 | 352 |
272 | 353 |
273 void VirtualFrame::EmitPop(Register reg) { | 354 void VirtualFrame::EmitPop(Register reg) { |
274 ASSERT(stack_pointer_ == element_count() - 1); | 355 ASSERT(!is_used(reg)); |
275 stack_pointer_--; | 356 if (top_of_stack_state_ == NO_TOS_REGISTERS) { |
357 __ pop(reg); | |
358 } else { | |
359 __ mov(reg, kTopRegister[top_of_stack_state_]); | |
360 top_of_stack_state_ = kPopState[top_of_stack_state_]; | |
361 } | |
276 element_count_--; | 362 element_count_--; |
277 __ pop(reg); | 363 } |
364 | |
365 | |
366 Register VirtualFrame::Peek() { | |
367 AssertIsNotSpilled(); | |
368 if (top_of_stack_state_ == NO_TOS_REGISTERS) { | |
369 top_of_stack_state_ = kPushState[top_of_stack_state_]; | |
370 Register answer = kTopRegister[top_of_stack_state_]; | |
371 __ pop(answer); | |
372 return answer; | |
373 } else { | |
374 return kTopRegister[top_of_stack_state_]; | |
375 } | |
376 } | |
377 | |
378 | |
379 Register VirtualFrame::PopToRegister(Register but_not_to_this_one) { | |
Søren Thygesen Gjesse
2010/04/07 10:46:51
Maybe assert that but_not_to_this_one is one of th
Erik Corry
2010/04/07 12:49:17
Done.
| |
380 AssertIsNotSpilled(); | |
381 element_count_--; | |
382 if (top_of_stack_state_ == NO_TOS_REGISTERS) { | |
383 if (but_not_to_this_one.is(r0)) { | |
384 __ pop(r1); | |
385 return r1; | |
386 } else { | |
387 __ pop(r0); | |
388 return r0; | |
389 } | |
390 } else { | |
Søren Thygesen Gjesse
2010/04/07 10:46:51
Isn't but_not_to_this_one ignored in the else part
Erik Corry
2010/04/07 12:49:17
Yes, because it never happens.
| |
391 Register answer = kTopRegister[top_of_stack_state_]; | |
392 top_of_stack_state_ = kPopState[top_of_stack_state_]; | |
Søren Thygesen Gjesse
2010/04/07 10:46:51
ASSERT(!answer.is(but_not_to_this_one));
Erik Corry
2010/04/07 12:49:17
Done.
| |
393 return answer; | |
394 } | |
278 } | 395 } |
279 | 396 |
280 | 397 |
281 void VirtualFrame::EmitPush(Register reg) { | 398 void VirtualFrame::EmitPush(Register reg) { |
282 ASSERT(stack_pointer_ == element_count() - 1); | |
283 element_count_++; | 399 element_count_++; |
284 stack_pointer_++; | 400 if (SpilledScope::is_spilled()) { |
285 __ push(reg); | 401 __ push(reg); |
402 return; | |
403 } | |
404 if (top_of_stack_state_ == NO_TOS_REGISTERS) { | |
405 if (reg.is(r0)) { | |
406 top_of_stack_state_ = R0_TOS; | |
407 return; | |
408 } | |
409 if (reg.is(r1)) { | |
410 top_of_stack_state_ = R1_TOS; | |
411 return; | |
412 } | |
413 } | |
Søren Thygesen Gjesse
2010/04/07 10:46:51
Maybe add some kind of helper function "EnsureOneF
Erik Corry
2010/04/07 12:49:17
Done.
| |
414 if (kVirtualElements[top_of_stack_state_] == kMaxTOSRegisters) { | |
415 __ push(kBottomRegister[top_of_stack_state_]); | |
416 } | |
417 top_of_stack_state_ = kPushState[top_of_stack_state_]; | |
418 Register dest = kTopRegister[top_of_stack_state_]; | |
419 if (!dest.is(reg)) { | |
420 __ mov(dest, reg); | |
421 } | |
422 } | |
423 | |
424 | |
425 Register VirtualFrame::GetTOSRegister() { | |
426 if (SpilledScope::is_spilled()) return r0; | |
427 | |
428 if (kVirtualElements[top_of_stack_state_] == kMaxTOSRegisters) { | |
429 Register answer = kBottomRegister[top_of_stack_state_]; | |
430 __ push(answer); | |
431 top_of_stack_state_ = kPushState[top_of_stack_state_]; | |
432 top_of_stack_state_ = kPopState[top_of_stack_state_]; | |
433 return answer; | |
434 } | |
435 | |
436 return kTopRegister[kPushState[top_of_stack_state_]]; | |
437 } | |
438 | |
439 | |
440 void VirtualFrame::EmitPush(MemOperand operand) { | |
441 element_count_++; | |
442 if (SpilledScope::is_spilled()) { | |
443 __ ldr(r0, operand); | |
444 __ push(r0); | |
445 return; | |
446 } | |
447 if (kVirtualElements[top_of_stack_state_] == kMaxTOSRegisters) { | |
448 __ push(kBottomRegister[top_of_stack_state_]); | |
449 } | |
450 top_of_stack_state_ = kPushState[top_of_stack_state_]; | |
451 __ ldr(kTopRegister[top_of_stack_state_], operand); | |
286 } | 452 } |
287 | 453 |
288 | 454 |
289 void VirtualFrame::EmitPushMultiple(int count, int src_regs) { | 455 void VirtualFrame::EmitPushMultiple(int count, int src_regs) { |
290 ASSERT(stack_pointer_ == element_count() - 1); | 456 ASSERT(SpilledScope::is_spilled()); |
291 Adjust(count); | 457 Adjust(count); |
292 __ stm(db_w, sp, src_regs); | 458 __ stm(db_w, sp, src_regs); |
293 } | 459 } |
294 | 460 |
295 | 461 |
296 #undef __ | 462 #undef __ |
297 | 463 |
298 } } // namespace v8::internal | 464 } } // namespace v8::internal |
OLD | NEW |