blob: e770cddb15ac0319745e97736f88acd8c2441d59 [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// 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
34namespace v8 {
35namespace internal {
36
37#define __ ACCESS_MASM(masm())
38
39// -------------------------------------------------------------------------
40// VirtualFrame implementation.
41
42// On entry to a function, the virtual frame already contains the receiver,
43// the parameters, and a return address. All frame elements are in memory.
44VirtualFrame::VirtualFrame()
45 : elements_(parameter_count() + local_count() + kPreallocatedElements),
46 stack_pointer_(parameter_count() + 1) { // 0-based index of TOS.
47 for (int i = 0; i <= stack_pointer_; i++) {
48 elements_.Add(FrameElement::MemoryElement());
49 }
50 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
51 register_locations_[i] = kIllegalIndex;
52 }
53}
54
55
56void VirtualFrame::SyncElementBelowStackPointer(int index) {
57 // Emit code to write elements below the stack pointer to their
58 // (already allocated) stack address.
59 ASSERT(index <= stack_pointer_);
60 FrameElement element = elements_[index];
61 ASSERT(!element.is_synced());
62 switch (element.type()) {
63 case FrameElement::INVALID:
64 break;
65
66 case FrameElement::MEMORY:
67 // This function should not be called with synced elements.
68 // (memory elements are always synced).
69 UNREACHABLE();
70 break;
71
72 case FrameElement::REGISTER:
73 __ mov(Operand(ebp, fp_relative(index)), element.reg());
74 break;
75
76 case FrameElement::CONSTANT:
77 if (cgen()->IsUnsafeSmi(element.handle())) {
Steve Blockd0582a62009-12-15 09:54:21 +000078 cgen()->StoreUnsafeSmiToLocal(fp_relative(index), element.handle());
Steve Blocka7e24c12009-10-30 11:49:00 +000079 } else {
80 __ Set(Operand(ebp, fp_relative(index)),
81 Immediate(element.handle()));
82 }
83 break;
84
85 case FrameElement::COPY: {
86 int backing_index = element.index();
87 FrameElement backing_element = elements_[backing_index];
88 if (backing_element.is_memory()) {
89 Result temp = cgen()->allocator()->Allocate();
90 ASSERT(temp.is_valid());
91 __ mov(temp.reg(), Operand(ebp, fp_relative(backing_index)));
92 __ mov(Operand(ebp, fp_relative(index)), temp.reg());
93 } else {
94 ASSERT(backing_element.is_register());
95 __ mov(Operand(ebp, fp_relative(index)), backing_element.reg());
96 }
97 break;
98 }
99 }
100 elements_[index].set_sync();
101}
102
103
104void VirtualFrame::SyncElementByPushing(int index) {
105 // Sync an element of the frame that is just above the stack pointer
106 // by pushing it.
107 ASSERT(index == stack_pointer_ + 1);
108 stack_pointer_++;
109 FrameElement element = elements_[index];
110
111 switch (element.type()) {
112 case FrameElement::INVALID:
113 __ push(Immediate(Smi::FromInt(0)));
114 break;
115
116 case FrameElement::MEMORY:
117 // No memory elements exist above the stack pointer.
118 UNREACHABLE();
119 break;
120
121 case FrameElement::REGISTER:
122 __ push(element.reg());
123 break;
124
125 case FrameElement::CONSTANT:
126 if (cgen()->IsUnsafeSmi(element.handle())) {
Steve Blockd0582a62009-12-15 09:54:21 +0000127 cgen()->PushUnsafeSmi(element.handle());
Steve Blocka7e24c12009-10-30 11:49:00 +0000128 } else {
129 __ push(Immediate(element.handle()));
130 }
131 break;
132
133 case FrameElement::COPY: {
134 int backing_index = element.index();
135 FrameElement backing = elements_[backing_index];
136 ASSERT(backing.is_memory() || backing.is_register());
137 if (backing.is_memory()) {
138 __ push(Operand(ebp, fp_relative(backing_index)));
139 } else {
140 __ push(backing.reg());
141 }
142 break;
143 }
144 }
145 elements_[index].set_sync();
146}
147
148
149// Clear the dirty bits for the range of elements in
150// [min(stack_pointer_ + 1,begin), end].
151void VirtualFrame::SyncRange(int begin, int end) {
152 ASSERT(begin >= 0);
153 ASSERT(end < element_count());
154 // Sync elements below the range if they have not been materialized
155 // on the stack.
156 int start = Min(begin, stack_pointer_ + 1);
157
Steve Blockd0582a62009-12-15 09:54:21 +0000158 // Emit normal push instructions for elements above stack pointer
Steve Block3ce2e202009-11-05 08:53:23 +0000159 // and use mov instructions if we are below stack pointer.
Steve Blocka7e24c12009-10-30 11:49:00 +0000160 for (int i = start; i <= end; i++) {
Steve Block3ce2e202009-11-05 08:53:23 +0000161 if (!elements_[i].is_synced()) {
162 if (i <= stack_pointer_) {
163 SyncElementBelowStackPointer(i);
164 } else {
165 SyncElementByPushing(i);
166 }
167 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000168 }
169}
170
171
172void VirtualFrame::MakeMergable() {
173 for (int i = 0; i < element_count(); i++) {
174 FrameElement element = elements_[i];
175
176 if (element.is_constant() || element.is_copy()) {
177 if (element.is_synced()) {
178 // Just spill.
179 elements_[i] = FrameElement::MemoryElement();
180 } else {
181 // Allocate to a register.
182 FrameElement backing_element; // Invalid if not a copy.
183 if (element.is_copy()) {
184 backing_element = elements_[element.index()];
185 }
186 Result fresh = cgen()->allocator()->Allocate();
187 ASSERT(fresh.is_valid()); // A register was spilled if all were in use.
188 elements_[i] =
189 FrameElement::RegisterElement(fresh.reg(),
190 FrameElement::NOT_SYNCED);
191 Use(fresh.reg(), i);
192
193 // Emit a move.
194 if (element.is_constant()) {
195 if (cgen()->IsUnsafeSmi(element.handle())) {
Steve Blockd0582a62009-12-15 09:54:21 +0000196 cgen()->MoveUnsafeSmi(fresh.reg(), element.handle());
Steve Blocka7e24c12009-10-30 11:49:00 +0000197 } else {
198 __ Set(fresh.reg(), Immediate(element.handle()));
199 }
200 } else {
201 ASSERT(element.is_copy());
202 // Copies are only backed by register or memory locations.
203 if (backing_element.is_register()) {
204 // The backing store may have been spilled by allocating,
205 // but that's OK. If it was, the value is right where we
206 // want it.
207 if (!fresh.reg().is(backing_element.reg())) {
208 __ mov(fresh.reg(), backing_element.reg());
209 }
210 } else {
211 ASSERT(backing_element.is_memory());
212 __ mov(fresh.reg(), Operand(ebp, fp_relative(element.index())));
213 }
214 }
215 }
216 // No need to set the copied flag --- there are no copies.
217 } else {
218 // Clear the copy flag of non-constant, non-copy elements.
219 // They cannot be copied because copies are not allowed.
220 // The copy flag is not relied on before the end of this loop,
221 // including when registers are spilled.
222 elements_[i].clear_copied();
223 }
224 }
225}
226
227
228void VirtualFrame::MergeTo(VirtualFrame* expected) {
229 Comment cmnt(masm(), "[ Merge frame");
230 // We should always be merging the code generator's current frame to an
231 // expected frame.
232 ASSERT(cgen()->frame() == this);
233
234 // Adjust the stack pointer upward (toward the top of the virtual
235 // frame) if necessary.
236 if (stack_pointer_ < expected->stack_pointer_) {
237 int difference = expected->stack_pointer_ - stack_pointer_;
238 stack_pointer_ = expected->stack_pointer_;
239 __ sub(Operand(esp), Immediate(difference * kPointerSize));
240 }
241
242 MergeMoveRegistersToMemory(expected);
243 MergeMoveRegistersToRegisters(expected);
244 MergeMoveMemoryToRegisters(expected);
245
246 // Adjust the stack pointer downward if necessary.
247 if (stack_pointer_ > expected->stack_pointer_) {
248 int difference = stack_pointer_ - expected->stack_pointer_;
249 stack_pointer_ = expected->stack_pointer_;
250 __ add(Operand(esp), Immediate(difference * kPointerSize));
251 }
252
253 // At this point, the frames should be identical.
254 ASSERT(Equals(expected));
255}
256
257
258void VirtualFrame::MergeMoveRegistersToMemory(VirtualFrame* expected) {
259 ASSERT(stack_pointer_ >= expected->stack_pointer_);
260
261 // Move registers, constants, and copies to memory. Perform moves
262 // from the top downward in the frame in order to leave the backing
263 // stores of copies in registers.
264 //
265 // Moving memory-backed copies to memory requires a spare register
266 // for the memory-to-memory moves. Since we are performing a merge,
267 // we use esi (which is already saved in the frame). We keep track
268 // of the index of the frame element esi is caching or kIllegalIndex
269 // if esi has not been disturbed.
270 int esi_caches = kIllegalIndex;
271 for (int i = element_count() - 1; i >= 0; i--) {
272 FrameElement target = expected->elements_[i];
273 if (target.is_register()) continue; // Handle registers later.
274 if (target.is_memory()) {
275 FrameElement source = elements_[i];
276 switch (source.type()) {
277 case FrameElement::INVALID:
278 // Not a legal merge move.
279 UNREACHABLE();
280 break;
281
282 case FrameElement::MEMORY:
283 // Already in place.
284 break;
285
286 case FrameElement::REGISTER:
287 Unuse(source.reg());
288 if (!source.is_synced()) {
289 __ mov(Operand(ebp, fp_relative(i)), source.reg());
290 }
291 break;
292
293 case FrameElement::CONSTANT:
294 if (!source.is_synced()) {
295 if (cgen()->IsUnsafeSmi(source.handle())) {
296 esi_caches = i;
Steve Blockd0582a62009-12-15 09:54:21 +0000297 cgen()->MoveUnsafeSmi(esi, source.handle());
Steve Blocka7e24c12009-10-30 11:49:00 +0000298 __ mov(Operand(ebp, fp_relative(i)), esi);
299 } else {
300 __ Set(Operand(ebp, fp_relative(i)), Immediate(source.handle()));
301 }
302 }
303 break;
304
305 case FrameElement::COPY:
306 if (!source.is_synced()) {
307 int backing_index = source.index();
308 FrameElement backing_element = elements_[backing_index];
309 if (backing_element.is_memory()) {
310 // If we have to spill a register, we spill esi.
311 if (esi_caches != backing_index) {
312 esi_caches = backing_index;
313 __ mov(esi, Operand(ebp, fp_relative(backing_index)));
314 }
315 __ mov(Operand(ebp, fp_relative(i)), esi);
316 } else {
317 ASSERT(backing_element.is_register());
318 __ mov(Operand(ebp, fp_relative(i)), backing_element.reg());
319 }
320 }
321 break;
322 }
323 }
324 elements_[i] = target;
325 }
326
327 if (esi_caches != kIllegalIndex) {
328 __ mov(esi, Operand(ebp, fp_relative(context_index())));
329 }
330}
331
332
333void VirtualFrame::MergeMoveRegistersToRegisters(VirtualFrame* expected) {
334 // We have already done X-to-memory moves.
335 ASSERT(stack_pointer_ >= expected->stack_pointer_);
336
337 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
338 // Move the right value into register i if it is currently in a register.
339 int index = expected->register_location(i);
340 int use_index = register_location(i);
341 // Skip if register i is unused in the target or else if source is
342 // not a register (this is not a register-to-register move).
343 if (index == kIllegalIndex || !elements_[index].is_register()) continue;
344
345 Register target = RegisterAllocator::ToRegister(i);
346 Register source = elements_[index].reg();
347 if (index != use_index) {
348 if (use_index == kIllegalIndex) { // Target is currently unused.
349 // Copy contents of source from source to target.
350 // Set frame element register to target.
351 Use(target, index);
352 Unuse(source);
353 __ mov(target, source);
354 } else {
355 // Exchange contents of registers source and target.
356 // Nothing except the register backing use_index has changed.
357 elements_[use_index].set_reg(source);
358 set_register_location(target, index);
359 set_register_location(source, use_index);
360 __ xchg(source, target);
361 }
362 }
363
364 if (!elements_[index].is_synced() &&
365 expected->elements_[index].is_synced()) {
366 __ mov(Operand(ebp, fp_relative(index)), target);
367 }
368 elements_[index] = expected->elements_[index];
369 }
370}
371
372
373void VirtualFrame::MergeMoveMemoryToRegisters(VirtualFrame* expected) {
374 // Move memory, constants, and copies to registers. This is the
375 // final step and since it is not done from the bottom up, but in
376 // register code order, we have special code to ensure that the backing
377 // elements of copies are in their correct locations when we
378 // encounter the copies.
379 for (int i = 0; i < RegisterAllocator::kNumRegisters; i++) {
380 int index = expected->register_location(i);
381 if (index != kIllegalIndex) {
382 FrameElement source = elements_[index];
383 FrameElement target = expected->elements_[index];
384 Register target_reg = RegisterAllocator::ToRegister(i);
385 ASSERT(target.reg().is(target_reg));
386 switch (source.type()) {
387 case FrameElement::INVALID: // Fall through.
388 UNREACHABLE();
389 break;
390 case FrameElement::REGISTER:
391 ASSERT(source.Equals(target));
392 // Go to next iteration. Skips Use(target_reg) and syncing
393 // below. It is safe to skip syncing because a target
394 // register frame element would only be synced if all source
395 // elements were.
396 continue;
397 break;
398 case FrameElement::MEMORY:
399 ASSERT(index <= stack_pointer_);
400 __ mov(target_reg, Operand(ebp, fp_relative(index)));
401 break;
402
403 case FrameElement::CONSTANT:
404 if (cgen()->IsUnsafeSmi(source.handle())) {
Steve Blockd0582a62009-12-15 09:54:21 +0000405 cgen()->MoveUnsafeSmi(target_reg, source.handle());
Steve Blocka7e24c12009-10-30 11:49:00 +0000406 } else {
407 __ Set(target_reg, Immediate(source.handle()));
408 }
409 break;
410
411 case FrameElement::COPY: {
412 int backing_index = source.index();
413 FrameElement backing = elements_[backing_index];
414 ASSERT(backing.is_memory() || backing.is_register());
415 if (backing.is_memory()) {
416 ASSERT(backing_index <= stack_pointer_);
417 // Code optimization if backing store should also move
418 // to a register: move backing store to its register first.
419 if (expected->elements_[backing_index].is_register()) {
420 FrameElement new_backing = expected->elements_[backing_index];
421 Register new_backing_reg = new_backing.reg();
422 ASSERT(!is_used(new_backing_reg));
423 elements_[backing_index] = new_backing;
424 Use(new_backing_reg, backing_index);
425 __ mov(new_backing_reg,
426 Operand(ebp, fp_relative(backing_index)));
427 __ mov(target_reg, new_backing_reg);
428 } else {
429 __ mov(target_reg, Operand(ebp, fp_relative(backing_index)));
430 }
431 } else {
432 __ mov(target_reg, backing.reg());
433 }
434 }
435 }
436 // Ensure the proper sync state.
437 if (target.is_synced() && !source.is_synced()) {
438 __ mov(Operand(ebp, fp_relative(index)), target_reg);
439 }
440 Use(target_reg, index);
441 elements_[index] = target;
442 }
443 }
444}
445
446
447void VirtualFrame::Enter() {
448 // Registers live on entry: esp, ebp, esi, edi.
449 Comment cmnt(masm(), "[ Enter JS frame");
450
451#ifdef DEBUG
Steve Block3ce2e202009-11-05 08:53:23 +0000452 if (FLAG_debug_code) {
453 // Verify that edi contains a JS function. The following code
454 // relies on eax being available for use.
455 __ test(edi, Immediate(kSmiTagMask));
456 __ Check(not_zero,
457 "VirtualFrame::Enter - edi is not a function (smi check).");
458 __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax);
459 __ Check(equal,
460 "VirtualFrame::Enter - edi is not a function (map check).");
461 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000462#endif
463
464 EmitPush(ebp);
465
466 __ mov(ebp, Operand(esp));
467
468 // Store the context in the frame. The context is kept in esi and a
469 // copy is stored in the frame. The external reference to esi
470 // remains.
471 EmitPush(esi);
472
473 // Store the function in the frame. The frame owns the register
474 // reference now (ie, it can keep it in edi or spill it later).
475 Push(edi);
476 SyncElementAt(element_count() - 1);
477 cgen()->allocator()->Unuse(edi);
478}
479
480
481void VirtualFrame::Exit() {
482 Comment cmnt(masm(), "[ Exit JS frame");
483 // Record the location of the JS exit code for patching when setting
484 // break point.
485 __ RecordJSReturn();
486
487 // Avoid using the leave instruction here, because it is too
488 // short. We need the return sequence to be a least the size of a
489 // call instruction to support patching the exit code in the
490 // debugger. See VisitReturnStatement for the full return sequence.
491 __ mov(esp, Operand(ebp));
492 stack_pointer_ = frame_pointer();
493 for (int i = element_count() - 1; i > stack_pointer_; i--) {
494 FrameElement last = elements_.RemoveLast();
495 if (last.is_register()) {
496 Unuse(last.reg());
497 }
498 }
499
500 EmitPop(ebp);
501}
502
503
504void VirtualFrame::AllocateStackSlots() {
505 int count = local_count();
506 if (count > 0) {
507 Comment cmnt(masm(), "[ Allocate space for locals");
508 // The locals are initialized to a constant (the undefined value), but
509 // we sync them with the actual frame to allocate space for spilling
510 // them later. First sync everything above the stack pointer so we can
511 // use pushes to allocate and initialize the locals.
512 SyncRange(stack_pointer_ + 1, element_count() - 1);
513 Handle<Object> undefined = Factory::undefined_value();
514 FrameElement initial_value =
515 FrameElement::ConstantElement(undefined, FrameElement::SYNCED);
516 Result temp = cgen()->allocator()->Allocate();
517 ASSERT(temp.is_valid());
518 __ Set(temp.reg(), Immediate(undefined));
519 for (int i = 0; i < count; i++) {
520 elements_.Add(initial_value);
521 stack_pointer_++;
522 __ push(temp.reg());
523 }
524 }
525}
526
527
528void VirtualFrame::SaveContextRegister() {
529 ASSERT(elements_[context_index()].is_memory());
530 __ mov(Operand(ebp, fp_relative(context_index())), esi);
531}
532
533
534void VirtualFrame::RestoreContextRegister() {
535 ASSERT(elements_[context_index()].is_memory());
536 __ mov(esi, Operand(ebp, fp_relative(context_index())));
537}
538
539
540void VirtualFrame::PushReceiverSlotAddress() {
541 Result temp = cgen()->allocator()->Allocate();
542 ASSERT(temp.is_valid());
543 __ lea(temp.reg(), ParameterAt(-1));
544 Push(&temp);
545}
546
547
548int VirtualFrame::InvalidateFrameSlotAt(int index) {
549 FrameElement original = elements_[index];
550
551 // Is this element the backing store of any copies?
552 int new_backing_index = kIllegalIndex;
553 if (original.is_copied()) {
554 // Verify it is copied, and find first copy.
555 for (int i = index + 1; i < element_count(); i++) {
556 if (elements_[i].is_copy() && elements_[i].index() == index) {
557 new_backing_index = i;
558 break;
559 }
560 }
561 }
562
563 if (new_backing_index == kIllegalIndex) {
564 // No copies found, return kIllegalIndex.
565 if (original.is_register()) {
566 Unuse(original.reg());
567 }
568 elements_[index] = FrameElement::InvalidElement();
569 return kIllegalIndex;
570 }
571
572 // This is the backing store of copies.
573 Register backing_reg;
574 if (original.is_memory()) {
575 Result fresh = cgen()->allocator()->Allocate();
576 ASSERT(fresh.is_valid());
577 Use(fresh.reg(), new_backing_index);
578 backing_reg = fresh.reg();
579 __ mov(backing_reg, Operand(ebp, fp_relative(index)));
580 } else {
581 // The original was in a register.
582 backing_reg = original.reg();
583 set_register_location(backing_reg, new_backing_index);
584 }
585 // Invalidate the element at index.
586 elements_[index] = FrameElement::InvalidElement();
587 // Set the new backing element.
588 if (elements_[new_backing_index].is_synced()) {
589 elements_[new_backing_index] =
590 FrameElement::RegisterElement(backing_reg, FrameElement::SYNCED);
591 } else {
592 elements_[new_backing_index] =
593 FrameElement::RegisterElement(backing_reg, FrameElement::NOT_SYNCED);
594 }
595 // Update the other copies.
596 for (int i = new_backing_index + 1; i < element_count(); i++) {
597 if (elements_[i].is_copy() && elements_[i].index() == index) {
598 elements_[i].set_index(new_backing_index);
599 elements_[new_backing_index].set_copied();
600 }
601 }
602 return new_backing_index;
603}
604
605
606void VirtualFrame::TakeFrameSlotAt(int index) {
607 ASSERT(index >= 0);
608 ASSERT(index <= element_count());
609 FrameElement original = elements_[index];
610 int new_backing_store_index = InvalidateFrameSlotAt(index);
611 if (new_backing_store_index != kIllegalIndex) {
612 elements_.Add(CopyElementAt(new_backing_store_index));
613 return;
614 }
615
616 switch (original.type()) {
617 case FrameElement::MEMORY: {
618 // Emit code to load the original element's data into a register.
619 // Push that register as a FrameElement on top of the frame.
620 Result fresh = cgen()->allocator()->Allocate();
621 ASSERT(fresh.is_valid());
622 FrameElement new_element =
623 FrameElement::RegisterElement(fresh.reg(),
624 FrameElement::NOT_SYNCED);
625 Use(fresh.reg(), element_count());
626 elements_.Add(new_element);
627 __ mov(fresh.reg(), Operand(ebp, fp_relative(index)));
628 break;
629 }
630 case FrameElement::REGISTER:
631 Use(original.reg(), element_count());
632 // Fall through.
633 case FrameElement::CONSTANT:
634 case FrameElement::COPY:
635 original.clear_sync();
636 elements_.Add(original);
637 break;
638 case FrameElement::INVALID:
639 UNREACHABLE();
640 break;
641 }
642}
643
644
645void VirtualFrame::StoreToFrameSlotAt(int index) {
646 // Store the value on top of the frame to the virtual frame slot at
647 // a given index. The value on top of the frame is left in place.
648 // This is a duplicating operation, so it can create copies.
649 ASSERT(index >= 0);
650 ASSERT(index < element_count());
651
652 int top_index = element_count() - 1;
653 FrameElement top = elements_[top_index];
654 FrameElement original = elements_[index];
655 if (top.is_copy() && top.index() == index) return;
656 ASSERT(top.is_valid());
657
658 InvalidateFrameSlotAt(index);
659
660 // InvalidateFrameSlotAt can potentially change any frame element, due
661 // to spilling registers to allocate temporaries in order to preserve
662 // the copy-on-write semantics of aliased elements. Reload top from
663 // the frame.
664 top = elements_[top_index];
665
666 if (top.is_copy()) {
667 // There are two cases based on the relative positions of the
668 // stored-to slot and the backing slot of the top element.
669 int backing_index = top.index();
670 ASSERT(backing_index != index);
671 if (backing_index < index) {
672 // 1. The top element is a copy of a slot below the stored-to
673 // slot. The stored-to slot becomes an unsynced copy of that
674 // same backing slot.
675 elements_[index] = CopyElementAt(backing_index);
676 } else {
677 // 2. The top element is a copy of a slot above the stored-to
678 // slot. The stored-to slot becomes the new (unsynced) backing
679 // slot and both the top element and the element at the former
680 // backing slot become copies of it. The sync state of the top
681 // and former backing elements is preserved.
682 FrameElement backing_element = elements_[backing_index];
683 ASSERT(backing_element.is_memory() || backing_element.is_register());
684 if (backing_element.is_memory()) {
685 // Because sets of copies are canonicalized to be backed by
686 // their lowest frame element, and because memory frame
687 // elements are backed by the corresponding stack address, we
688 // have to move the actual value down in the stack.
689 //
690 // TODO(209): considering allocating the stored-to slot to the
691 // temp register. Alternatively, allow copies to appear in
692 // any order in the frame and lazily move the value down to
693 // the slot.
694 Result temp = cgen()->allocator()->Allocate();
695 ASSERT(temp.is_valid());
696 __ mov(temp.reg(), Operand(ebp, fp_relative(backing_index)));
697 __ mov(Operand(ebp, fp_relative(index)), temp.reg());
698 } else {
699 set_register_location(backing_element.reg(), index);
700 if (backing_element.is_synced()) {
701 // If the element is a register, we will not actually move
702 // anything on the stack but only update the virtual frame
703 // element.
704 backing_element.clear_sync();
705 }
706 }
707 elements_[index] = backing_element;
708
709 // The old backing element becomes a copy of the new backing
710 // element.
711 FrameElement new_element = CopyElementAt(index);
712 elements_[backing_index] = new_element;
713 if (backing_element.is_synced()) {
714 elements_[backing_index].set_sync();
715 }
716
717 // All the copies of the old backing element (including the top
718 // element) become copies of the new backing element.
719 for (int i = backing_index + 1; i < element_count(); i++) {
720 if (elements_[i].is_copy() && elements_[i].index() == backing_index) {
721 elements_[i].set_index(index);
722 }
723 }
724 }
725 return;
726 }
727
728 // Move the top element to the stored-to slot and replace it (the
729 // top element) with a copy.
730 elements_[index] = top;
731 if (top.is_memory()) {
732 // TODO(209): consider allocating the stored-to slot to the temp
733 // register. Alternatively, allow copies to appear in any order
734 // in the frame and lazily move the value down to the slot.
735 FrameElement new_top = CopyElementAt(index);
736 new_top.set_sync();
737 elements_[top_index] = new_top;
738
739 // The sync state of the former top element is correct (synced).
740 // Emit code to move the value down in the frame.
741 Result temp = cgen()->allocator()->Allocate();
742 ASSERT(temp.is_valid());
743 __ mov(temp.reg(), Operand(esp, 0));
744 __ mov(Operand(ebp, fp_relative(index)), temp.reg());
745 } else if (top.is_register()) {
746 set_register_location(top.reg(), index);
747 // The stored-to slot has the (unsynced) register reference and
748 // the top element becomes a copy. The sync state of the top is
749 // preserved.
750 FrameElement new_top = CopyElementAt(index);
751 if (top.is_synced()) {
752 new_top.set_sync();
753 elements_[index].clear_sync();
754 }
755 elements_[top_index] = new_top;
756 } else {
757 // The stored-to slot holds the same value as the top but
758 // unsynced. (We do not have copies of constants yet.)
759 ASSERT(top.is_constant());
760 elements_[index].clear_sync();
761 }
762}
763
764
765void VirtualFrame::PushTryHandler(HandlerType type) {
766 ASSERT(cgen()->HasValidEntryRegisters());
767 // Grow the expression stack by handler size less one (the return
768 // address is already pushed by a call instruction).
769 Adjust(kHandlerSize - 1);
770 __ PushTryHandler(IN_JAVASCRIPT, type);
771}
772
773
774Result VirtualFrame::RawCallStub(CodeStub* stub) {
775 ASSERT(cgen()->HasValidEntryRegisters());
776 __ CallStub(stub);
777 Result result = cgen()->allocator()->Allocate(eax);
778 ASSERT(result.is_valid());
779 return result;
780}
781
782
783Result VirtualFrame::CallStub(CodeStub* stub, Result* arg) {
784 PrepareForCall(0, 0);
785 arg->ToRegister(eax);
786 arg->Unuse();
787 return RawCallStub(stub);
788}
789
790
791Result VirtualFrame::CallStub(CodeStub* stub, Result* arg0, Result* arg1) {
792 PrepareForCall(0, 0);
793
794 if (arg0->is_register() && arg0->reg().is(eax)) {
795 if (arg1->is_register() && arg1->reg().is(edx)) {
796 // Wrong registers.
797 __ xchg(eax, edx);
798 } else {
799 // Register edx is free for arg0, which frees eax for arg1.
800 arg0->ToRegister(edx);
801 arg1->ToRegister(eax);
802 }
803 } else {
804 // Register eax is free for arg1, which guarantees edx is free for
805 // arg0.
806 arg1->ToRegister(eax);
807 arg0->ToRegister(edx);
808 }
809
810 arg0->Unuse();
811 arg1->Unuse();
812 return RawCallStub(stub);
813}
814
815
816Result VirtualFrame::CallRuntime(Runtime::Function* f, int arg_count) {
817 PrepareForCall(arg_count, arg_count);
818 ASSERT(cgen()->HasValidEntryRegisters());
819 __ CallRuntime(f, arg_count);
820 Result result = cgen()->allocator()->Allocate(eax);
821 ASSERT(result.is_valid());
822 return result;
823}
824
825
826Result VirtualFrame::CallRuntime(Runtime::FunctionId id, int arg_count) {
827 PrepareForCall(arg_count, arg_count);
828 ASSERT(cgen()->HasValidEntryRegisters());
829 __ CallRuntime(id, arg_count);
830 Result result = cgen()->allocator()->Allocate(eax);
831 ASSERT(result.is_valid());
832 return result;
833}
834
835
836Result VirtualFrame::InvokeBuiltin(Builtins::JavaScript id,
837 InvokeFlag flag,
838 int arg_count) {
839 PrepareForCall(arg_count, arg_count);
840 ASSERT(cgen()->HasValidEntryRegisters());
841 __ InvokeBuiltin(id, flag);
842 Result result = cgen()->allocator()->Allocate(eax);
843 ASSERT(result.is_valid());
844 return result;
845}
846
847
848Result VirtualFrame::RawCallCodeObject(Handle<Code> code,
849 RelocInfo::Mode rmode) {
850 ASSERT(cgen()->HasValidEntryRegisters());
851 __ call(code, rmode);
852 Result result = cgen()->allocator()->Allocate(eax);
853 ASSERT(result.is_valid());
854 return result;
855}
856
857
858Result VirtualFrame::CallLoadIC(RelocInfo::Mode mode) {
859 // Name and receiver are on the top of the frame. The IC expects
860 // name in ecx and receiver on the stack. It does not drop the
861 // receiver.
862 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
863 Result name = Pop();
864 PrepareForCall(1, 0); // One stack arg, not callee-dropped.
865 name.ToRegister(ecx);
866 name.Unuse();
867 return RawCallCodeObject(ic, mode);
868}
869
870
871Result VirtualFrame::CallKeyedLoadIC(RelocInfo::Mode mode) {
872 // Key and receiver are on top of the frame. The IC expects them on
873 // the stack. It does not drop them.
874 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
875 PrepareForCall(2, 0); // Two stack args, neither callee-dropped.
876 return RawCallCodeObject(ic, mode);
877}
878
879
880Result VirtualFrame::CallStoreIC() {
881 // Name, value, and receiver are on top of the frame. The IC
882 // expects name in ecx, value in eax, and receiver on the stack. It
883 // does not drop the receiver.
884 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
885 Result name = Pop();
886 Result value = Pop();
887 PrepareForCall(1, 0); // One stack arg, not callee-dropped.
888
889 if (value.is_register() && value.reg().is(ecx)) {
890 if (name.is_register() && name.reg().is(eax)) {
891 // Wrong registers.
892 __ xchg(eax, ecx);
893 } else {
894 // Register eax is free for value, which frees ecx for name.
895 value.ToRegister(eax);
896 name.ToRegister(ecx);
897 }
898 } else {
899 // Register ecx is free for name, which guarantees eax is free for
900 // value.
901 name.ToRegister(ecx);
902 value.ToRegister(eax);
903 }
904
905 name.Unuse();
906 value.Unuse();
907 return RawCallCodeObject(ic, RelocInfo::CODE_TARGET);
908}
909
910
911Result VirtualFrame::CallKeyedStoreIC() {
912 // Value, key, and receiver are on the top of the frame. The IC
913 // expects value in eax and key and receiver on the stack. It does
914 // not drop the key and receiver.
915 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
916 // TODO(1222589): Make the IC grab the values from the stack.
917 Result value = Pop();
918 PrepareForCall(2, 0); // Two stack args, neither callee-dropped.
919 value.ToRegister(eax);
920 value.Unuse();
921 return RawCallCodeObject(ic, RelocInfo::CODE_TARGET);
922}
923
924
925Result VirtualFrame::CallCallIC(RelocInfo::Mode mode,
926 int arg_count,
927 int loop_nesting) {
928 // Arguments, receiver, and function name are on top of the frame.
929 // The IC expects them on the stack. It does not drop the function
930 // name slot (but it does drop the rest).
931 InLoopFlag in_loop = loop_nesting > 0 ? IN_LOOP : NOT_IN_LOOP;
932 Handle<Code> ic = cgen()->ComputeCallInitialize(arg_count, in_loop);
933 // Spill args, receiver, and function. The call will drop args and
934 // receiver.
935 PrepareForCall(arg_count + 2, arg_count + 1);
936 return RawCallCodeObject(ic, mode);
937}
938
939
940Result VirtualFrame::CallConstructor(int arg_count) {
941 // Arguments, receiver, and function are on top of the frame. The
942 // IC expects arg count in eax, function in edi, and the arguments
943 // and receiver on the stack.
944 Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall));
945 // Duplicate the function before preparing the frame.
946 PushElementAt(arg_count + 1);
947 Result function = Pop();
948 PrepareForCall(arg_count + 1, arg_count + 1); // Spill args and receiver.
949 function.ToRegister(edi);
950
951 // Constructors are called with the number of arguments in register
952 // eax for now. Another option would be to have separate construct
953 // call trampolines per different arguments counts encountered.
954 Result num_args = cgen()->allocator()->Allocate(eax);
955 ASSERT(num_args.is_valid());
956 __ Set(num_args.reg(), Immediate(arg_count));
957
958 function.Unuse();
959 num_args.Unuse();
960 return RawCallCodeObject(ic, RelocInfo::CONSTRUCT_CALL);
961}
962
963
964void VirtualFrame::Drop(int count) {
965 ASSERT(count >= 0);
966 ASSERT(height() >= count);
967 int num_virtual_elements = (element_count() - 1) - stack_pointer_;
968
969 // Emit code to lower the stack pointer if necessary.
970 if (num_virtual_elements < count) {
971 int num_dropped = count - num_virtual_elements;
972 stack_pointer_ -= num_dropped;
973 __ add(Operand(esp), Immediate(num_dropped * kPointerSize));
974 }
975
976 // Discard elements from the virtual frame and free any registers.
977 for (int i = 0; i < count; i++) {
978 FrameElement dropped = elements_.RemoveLast();
979 if (dropped.is_register()) {
980 Unuse(dropped.reg());
981 }
982 }
983}
984
985
986Result VirtualFrame::Pop() {
987 FrameElement element = elements_.RemoveLast();
988 int index = element_count();
989 ASSERT(element.is_valid());
990
991 bool pop_needed = (stack_pointer_ == index);
992 if (pop_needed) {
993 stack_pointer_--;
994 if (element.is_memory()) {
995 Result temp = cgen()->allocator()->Allocate();
996 ASSERT(temp.is_valid());
997 __ pop(temp.reg());
998 return temp;
999 }
1000
1001 __ add(Operand(esp), Immediate(kPointerSize));
1002 }
1003 ASSERT(!element.is_memory());
1004
1005 // The top element is a register, constant, or a copy. Unuse
1006 // registers and follow copies to their backing store.
1007 if (element.is_register()) {
1008 Unuse(element.reg());
1009 } else if (element.is_copy()) {
1010 ASSERT(element.index() < index);
1011 index = element.index();
1012 element = elements_[index];
1013 }
1014 ASSERT(!element.is_copy());
1015
1016 // The element is memory, a register, or a constant.
1017 if (element.is_memory()) {
1018 // Memory elements could only be the backing store of a copy.
1019 // Allocate the original to a register.
1020 ASSERT(index <= stack_pointer_);
1021 Result temp = cgen()->allocator()->Allocate();
1022 ASSERT(temp.is_valid());
1023 Use(temp.reg(), index);
1024 FrameElement new_element =
1025 FrameElement::RegisterElement(temp.reg(), FrameElement::SYNCED);
1026 // Preserve the copy flag on the element.
1027 if (element.is_copied()) new_element.set_copied();
1028 elements_[index] = new_element;
1029 __ mov(temp.reg(), Operand(ebp, fp_relative(index)));
1030 return Result(temp.reg());
1031 } else if (element.is_register()) {
1032 return Result(element.reg());
1033 } else {
1034 ASSERT(element.is_constant());
1035 return Result(element.handle());
1036 }
1037}
1038
1039
1040void VirtualFrame::EmitPop(Register reg) {
1041 ASSERT(stack_pointer_ == element_count() - 1);
1042 stack_pointer_--;
1043 elements_.RemoveLast();
1044 __ pop(reg);
1045}
1046
1047
1048void VirtualFrame::EmitPop(Operand operand) {
1049 ASSERT(stack_pointer_ == element_count() - 1);
1050 stack_pointer_--;
1051 elements_.RemoveLast();
1052 __ pop(operand);
1053}
1054
1055
1056void VirtualFrame::EmitPush(Register reg) {
1057 ASSERT(stack_pointer_ == element_count() - 1);
1058 elements_.Add(FrameElement::MemoryElement());
1059 stack_pointer_++;
1060 __ push(reg);
1061}
1062
1063
1064void VirtualFrame::EmitPush(Operand operand) {
1065 ASSERT(stack_pointer_ == element_count() - 1);
1066 elements_.Add(FrameElement::MemoryElement());
1067 stack_pointer_++;
1068 __ push(operand);
1069}
1070
1071
1072void VirtualFrame::EmitPush(Immediate immediate) {
1073 ASSERT(stack_pointer_ == element_count() - 1);
1074 elements_.Add(FrameElement::MemoryElement());
1075 stack_pointer_++;
1076 __ push(immediate);
1077}
1078
1079
1080#undef __
1081
1082} } // namespace v8::internal