Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: src/ia32/virtual-frame-ia32.cc

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

Powered by Google App Engine
This is Rietveld 408576698