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 15 matching lines...) Expand all Loading... |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 |
28 #include "v8.h" | 28 #include "v8.h" |
29 | 29 |
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 | 33 |
34 namespace v8 { namespace internal { | 34 namespace v8 { namespace internal { |
35 | 35 |
36 #define __ ACCESS_MASM(masm_) | 36 #define __ ACCESS_MASM(masm()) |
37 | 37 |
38 // ------------------------------------------------------------------------- | 38 // ------------------------------------------------------------------------- |
39 // VirtualFrame implementation. | 39 // VirtualFrame implementation. |
40 | 40 |
41 // On entry to a function, the virtual frame already contains the receiver, | 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. | 42 // the parameters, and a return address. All frame elements are in memory. |
43 VirtualFrame::VirtualFrame(CodeGenerator* cgen) | 43 VirtualFrame::VirtualFrame() |
44 : cgen_(cgen), | 44 : elements_(parameter_count() + local_count() + kPreallocatedElements), |
45 masm_(cgen->masm()), | 45 stack_pointer_(parameter_count() + 1) { // 0-based index of TOS. |
46 elements_(cgen->scope()->num_parameters() | 46 for (int i = 0; i <= stack_pointer_; i++) { |
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()); | 47 elements_.Add(FrameElement::MemoryElement()); |
55 } | 48 } |
56 for (int i = 0; i < kNumRegisters; i++) { | 49 for (int i = 0; i < kNumRegisters; i++) { |
57 register_locations_[i] = kIllegalIndex; | 50 register_locations_[i] = kIllegalIndex; |
58 } | 51 } |
59 } | 52 } |
60 | 53 |
61 | 54 |
62 void VirtualFrame::SyncElementBelowStackPointer(int index) { | 55 void VirtualFrame::SyncElementBelowStackPointer(int index) { |
63 // Emit code to write elements below the stack pointer to their | 56 // Emit code to write elements below the stack pointer to their |
64 // (already allocated) stack address. | 57 // (already allocated) stack address. |
65 ASSERT(index <= stack_pointer_); | 58 ASSERT(index <= stack_pointer_); |
66 FrameElement element = elements_[index]; | 59 FrameElement element = elements_[index]; |
67 ASSERT(!element.is_synced()); | 60 ASSERT(!element.is_synced()); |
68 switch (element.type()) { | 61 switch (element.type()) { |
69 case FrameElement::INVALID: | 62 case FrameElement::INVALID: |
70 break; | 63 break; |
71 | 64 |
72 case FrameElement::MEMORY: | 65 case FrameElement::MEMORY: |
73 // This function should not be called with synced elements. | 66 // This function should not be called with synced elements. |
74 // (memory elements are always synced). | 67 // (memory elements are always synced). |
75 UNREACHABLE(); | 68 UNREACHABLE(); |
76 break; | 69 break; |
77 | 70 |
78 case FrameElement::REGISTER: | 71 case FrameElement::REGISTER: |
79 __ mov(Operand(ebp, fp_relative(index)), element.reg()); | 72 __ mov(Operand(ebp, fp_relative(index)), element.reg()); |
80 break; | 73 break; |
81 | 74 |
82 case FrameElement::CONSTANT: | 75 case FrameElement::CONSTANT: |
83 if (cgen_->IsUnsafeSmi(element.handle())) { | 76 if (cgen()->IsUnsafeSmi(element.handle())) { |
84 Result temp = cgen_->allocator()->Allocate(); | 77 Result temp = cgen()->allocator()->Allocate(); |
85 ASSERT(temp.is_valid()); | 78 ASSERT(temp.is_valid()); |
86 cgen_->LoadUnsafeSmi(temp.reg(), element.handle()); | 79 cgen()->LoadUnsafeSmi(temp.reg(), element.handle()); |
87 __ mov(Operand(ebp, fp_relative(index)), temp.reg()); | 80 __ mov(Operand(ebp, fp_relative(index)), temp.reg()); |
88 } else { | 81 } else { |
89 __ Set(Operand(ebp, fp_relative(index)), | 82 __ Set(Operand(ebp, fp_relative(index)), |
90 Immediate(element.handle())); | 83 Immediate(element.handle())); |
91 } | 84 } |
92 break; | 85 break; |
93 | 86 |
94 case FrameElement::COPY: { | 87 case FrameElement::COPY: { |
95 int backing_index = element.index(); | 88 int backing_index = element.index(); |
96 FrameElement backing_element = elements_[backing_index]; | 89 FrameElement backing_element = elements_[backing_index]; |
97 if (backing_element.is_memory()) { | 90 if (backing_element.is_memory()) { |
98 Result temp = cgen_->allocator()->Allocate(); | 91 Result temp = cgen()->allocator()->Allocate(); |
99 ASSERT(temp.is_valid()); | 92 ASSERT(temp.is_valid()); |
100 __ mov(temp.reg(), Operand(ebp, fp_relative(backing_index))); | 93 __ mov(temp.reg(), Operand(ebp, fp_relative(backing_index))); |
101 __ mov(Operand(ebp, fp_relative(index)), temp.reg()); | 94 __ mov(Operand(ebp, fp_relative(index)), temp.reg()); |
102 } else { | 95 } else { |
103 ASSERT(backing_element.is_register()); | 96 ASSERT(backing_element.is_register()); |
104 __ mov(Operand(ebp, fp_relative(index)), backing_element.reg()); | 97 __ mov(Operand(ebp, fp_relative(index)), backing_element.reg()); |
105 } | 98 } |
106 break; | 99 break; |
107 } | 100 } |
108 } | 101 } |
(...skipping 16 matching lines...) Expand all Loading... |
125 case FrameElement::MEMORY: | 118 case FrameElement::MEMORY: |
126 // No memory elements exist above the stack pointer. | 119 // No memory elements exist above the stack pointer. |
127 UNREACHABLE(); | 120 UNREACHABLE(); |
128 break; | 121 break; |
129 | 122 |
130 case FrameElement::REGISTER: | 123 case FrameElement::REGISTER: |
131 __ push(element.reg()); | 124 __ push(element.reg()); |
132 break; | 125 break; |
133 | 126 |
134 case FrameElement::CONSTANT: | 127 case FrameElement::CONSTANT: |
135 if (cgen_->IsUnsafeSmi(element.handle())) { | 128 if (cgen()->IsUnsafeSmi(element.handle())) { |
136 Result temp = cgen_->allocator()->Allocate(); | 129 Result temp = cgen()->allocator()->Allocate(); |
137 ASSERT(temp.is_valid()); | 130 ASSERT(temp.is_valid()); |
138 cgen_->LoadUnsafeSmi(temp.reg(), element.handle()); | 131 cgen()->LoadUnsafeSmi(temp.reg(), element.handle()); |
139 __ push(temp.reg()); | 132 __ push(temp.reg()); |
140 } else { | 133 } else { |
141 __ push(Immediate(element.handle())); | 134 __ push(Immediate(element.handle())); |
142 } | 135 } |
143 break; | 136 break; |
144 | 137 |
145 case FrameElement::COPY: { | 138 case FrameElement::COPY: { |
146 int backing_index = element.index(); | 139 int backing_index = element.index(); |
147 FrameElement backing = elements_[backing_index]; | 140 FrameElement backing = elements_[backing_index]; |
148 ASSERT(backing.is_memory() || backing.is_register()); | 141 ASSERT(backing.is_memory() || backing.is_register()); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
193 if (element.is_constant() || element.is_copy()) { | 186 if (element.is_constant() || element.is_copy()) { |
194 if (element.is_synced()) { | 187 if (element.is_synced()) { |
195 // Just spill. | 188 // Just spill. |
196 elements_[i] = FrameElement::MemoryElement(); | 189 elements_[i] = FrameElement::MemoryElement(); |
197 } else { | 190 } else { |
198 // Allocate to a register. | 191 // Allocate to a register. |
199 FrameElement backing_element; // Invalid if not a copy. | 192 FrameElement backing_element; // Invalid if not a copy. |
200 if (element.is_copy()) { | 193 if (element.is_copy()) { |
201 backing_element = elements_[element.index()]; | 194 backing_element = elements_[element.index()]; |
202 } | 195 } |
203 Result fresh = cgen_->allocator()->Allocate(); | 196 Result fresh = cgen()->allocator()->Allocate(); |
204 ASSERT(fresh.is_valid()); | 197 ASSERT(fresh.is_valid()); |
205 elements_[i] = | 198 elements_[i] = |
206 FrameElement::RegisterElement(fresh.reg(), | 199 FrameElement::RegisterElement(fresh.reg(), |
207 FrameElement::NOT_SYNCED); | 200 FrameElement::NOT_SYNCED); |
208 Use(fresh.reg(), i); | 201 Use(fresh.reg(), i); |
209 | 202 |
210 // Emit a move. | 203 // Emit a move. |
211 if (element.is_constant()) { | 204 if (element.is_constant()) { |
212 if (cgen_->IsUnsafeSmi(element.handle())) { | 205 if (cgen()->IsUnsafeSmi(element.handle())) { |
213 cgen_->LoadUnsafeSmi(fresh.reg(), element.handle()); | 206 cgen()->LoadUnsafeSmi(fresh.reg(), element.handle()); |
214 } else { | 207 } else { |
215 __ Set(fresh.reg(), Immediate(element.handle())); | 208 __ Set(fresh.reg(), Immediate(element.handle())); |
216 } | 209 } |
217 } else { | 210 } else { |
218 ASSERT(element.is_copy()); | 211 ASSERT(element.is_copy()); |
219 // Copies are only backed by register or memory locations. | 212 // Copies are only backed by register or memory locations. |
220 if (backing_element.is_register()) { | 213 if (backing_element.is_register()) { |
221 // The backing store may have been spilled by allocating, | 214 // The backing store may have been spilled by allocating, |
222 // but that's OK. If it was, the value is right where we | 215 // but that's OK. If it was, the value is right where we |
223 // want it. | 216 // want it. |
(...skipping 14 matching lines...) Expand all Loading... |
238 // the high water mark. They cannot be copied because copes are | 231 // the high water mark. They cannot be copied because copes are |
239 // always higher than their backing store and copies are not | 232 // always higher than their backing store and copies are not |
240 // allowed above the water mark. | 233 // allowed above the water mark. |
241 elements_[i].clear_copied(); | 234 elements_[i].clear_copied(); |
242 } | 235 } |
243 } | 236 } |
244 } | 237 } |
245 | 238 |
246 | 239 |
247 void VirtualFrame::MergeTo(VirtualFrame* expected) { | 240 void VirtualFrame::MergeTo(VirtualFrame* expected) { |
248 Comment cmnt(masm_, "[ Merge frame"); | 241 Comment cmnt(masm(), "[ Merge frame"); |
249 // We should always be merging the code generator's current frame to an | 242 // We should always be merging the code generator's current frame to an |
250 // expected frame. | 243 // expected frame. |
251 ASSERT(cgen_->frame() == this); | 244 ASSERT(cgen()->frame() == this); |
252 | 245 |
253 // Adjust the stack pointer upward (toward the top of the virtual | 246 // Adjust the stack pointer upward (toward the top of the virtual |
254 // frame) if necessary. | 247 // frame) if necessary. |
255 if (stack_pointer_ < expected->stack_pointer_) { | 248 if (stack_pointer_ < expected->stack_pointer_) { |
256 int difference = expected->stack_pointer_ - stack_pointer_; | 249 int difference = expected->stack_pointer_ - stack_pointer_; |
257 stack_pointer_ = expected->stack_pointer_; | 250 stack_pointer_ = expected->stack_pointer_; |
258 __ sub(Operand(esp), Immediate(difference * kPointerSize)); | 251 __ sub(Operand(esp), Immediate(difference * kPointerSize)); |
259 } | 252 } |
260 | 253 |
261 MergeMoveRegistersToMemory(expected); | 254 MergeMoveRegistersToMemory(expected); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
304 | 297 |
305 case FrameElement::REGISTER: | 298 case FrameElement::REGISTER: |
306 Unuse(source.reg()); | 299 Unuse(source.reg()); |
307 if (!source.is_synced()) { | 300 if (!source.is_synced()) { |
308 __ mov(Operand(ebp, fp_relative(i)), source.reg()); | 301 __ mov(Operand(ebp, fp_relative(i)), source.reg()); |
309 } | 302 } |
310 break; | 303 break; |
311 | 304 |
312 case FrameElement::CONSTANT: | 305 case FrameElement::CONSTANT: |
313 if (!source.is_synced()) { | 306 if (!source.is_synced()) { |
314 if (cgen_->IsUnsafeSmi(source.handle())) { | 307 if (cgen()->IsUnsafeSmi(source.handle())) { |
315 esi_caches = i; | 308 esi_caches = i; |
316 cgen_->LoadUnsafeSmi(esi, source.handle()); | 309 cgen()->LoadUnsafeSmi(esi, source.handle()); |
317 __ mov(Operand(ebp, fp_relative(i)), esi); | 310 __ mov(Operand(ebp, fp_relative(i)), esi); |
318 } else { | 311 } else { |
319 __ Set(Operand(ebp, fp_relative(i)), Immediate(source.handle())); | 312 __ Set(Operand(ebp, fp_relative(i)), Immediate(source.handle())); |
320 } | 313 } |
321 } | 314 } |
322 break; | 315 break; |
323 | 316 |
324 case FrameElement::COPY: | 317 case FrameElement::COPY: |
325 if (!source.is_synced()) { | 318 if (!source.is_synced()) { |
326 int backing_index = source.index(); | 319 int backing_index = source.index(); |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
410 case FrameElement::REGISTER: | 403 case FrameElement::REGISTER: |
411 ASSERT(source.reg().is(target_reg)); | 404 ASSERT(source.reg().is(target_reg)); |
412 continue; // Go to next iteration. Skips Use(target_reg) below. | 405 continue; // Go to next iteration. Skips Use(target_reg) below. |
413 break; | 406 break; |
414 case FrameElement::MEMORY: | 407 case FrameElement::MEMORY: |
415 ASSERT(index <= stack_pointer_); | 408 ASSERT(index <= stack_pointer_); |
416 __ mov(target_reg, Operand(ebp, fp_relative(index))); | 409 __ mov(target_reg, Operand(ebp, fp_relative(index))); |
417 break; | 410 break; |
418 | 411 |
419 case FrameElement::CONSTANT: | 412 case FrameElement::CONSTANT: |
420 if (cgen_->IsUnsafeSmi(source.handle())) { | 413 if (cgen()->IsUnsafeSmi(source.handle())) { |
421 cgen_->LoadUnsafeSmi(target_reg, source.handle()); | 414 cgen()->LoadUnsafeSmi(target_reg, source.handle()); |
422 } else { | 415 } else { |
423 __ Set(target_reg, Immediate(source.handle())); | 416 __ Set(target_reg, Immediate(source.handle())); |
424 } | 417 } |
425 break; | 418 break; |
426 | 419 |
427 case FrameElement::COPY: { | 420 case FrameElement::COPY: { |
428 int backing_index = source.index(); | 421 int backing_index = source.index(); |
429 FrameElement backing = elements_[backing_index]; | 422 FrameElement backing = elements_[backing_index]; |
430 ASSERT(backing.is_memory() || backing.is_register()); | 423 ASSERT(backing.is_memory() || backing.is_register()); |
431 if (backing.is_memory()) { | 424 if (backing.is_memory()) { |
(...skipping 24 matching lines...) Expand all Loading... |
456 } | 449 } |
457 Use(target_reg, index); | 450 Use(target_reg, index); |
458 elements_[index] = target; | 451 elements_[index] = target; |
459 } | 452 } |
460 } | 453 } |
461 } | 454 } |
462 | 455 |
463 | 456 |
464 void VirtualFrame::Enter() { | 457 void VirtualFrame::Enter() { |
465 // Registers live on entry: esp, ebp, esi, edi. | 458 // Registers live on entry: esp, ebp, esi, edi. |
466 Comment cmnt(masm_, "[ Enter JS frame"); | 459 Comment cmnt(masm(), "[ Enter JS frame"); |
467 | 460 |
468 #ifdef DEBUG | 461 #ifdef DEBUG |
469 // Verify that edi contains a JS function. The following code | 462 // Verify that edi contains a JS function. The following code |
470 // relies on eax being available for use. | 463 // relies on eax being available for use. |
471 __ test(edi, Immediate(kSmiTagMask)); | 464 __ test(edi, Immediate(kSmiTagMask)); |
472 __ Check(not_zero, | 465 __ Check(not_zero, |
473 "VirtualFrame::Enter - edi is not a function (smi check)."); | 466 "VirtualFrame::Enter - edi is not a function (smi check)."); |
474 __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax); | 467 __ CmpObjectType(edi, JS_FUNCTION_TYPE, eax); |
475 __ Check(equal, | 468 __ Check(equal, |
476 "VirtualFrame::Enter - edi is not a function (map check)."); | 469 "VirtualFrame::Enter - edi is not a function (map check)."); |
477 #endif | 470 #endif |
478 | 471 |
479 EmitPush(ebp); | 472 EmitPush(ebp); |
480 | 473 |
481 frame_pointer_ = stack_pointer_; | |
482 __ mov(ebp, Operand(esp)); | 474 __ mov(ebp, Operand(esp)); |
483 | 475 |
484 // Store the context in the frame. The context is kept in esi and a | 476 // Store the context in the frame. The context is kept in esi and a |
485 // copy is stored in the frame. The external reference to esi | 477 // copy is stored in the frame. The external reference to esi |
486 // remains. | 478 // remains. |
487 EmitPush(esi); | 479 EmitPush(esi); |
488 | 480 |
489 // Store the function in the frame. The frame owns the register | 481 // Store the function in the frame. The frame owns the register |
490 // reference now (ie, it can keep it in edi or spill it later). | 482 // reference now (ie, it can keep it in edi or spill it later). |
491 Push(edi); | 483 Push(edi); |
492 SyncElementAt(elements_.length() - 1); | 484 SyncElementAt(elements_.length() - 1); |
493 cgen_->allocator()->Unuse(edi); | 485 cgen()->allocator()->Unuse(edi); |
494 } | 486 } |
495 | 487 |
496 | 488 |
497 void VirtualFrame::Exit() { | 489 void VirtualFrame::Exit() { |
498 Comment cmnt(masm_, "[ Exit JS frame"); | 490 Comment cmnt(masm(), "[ Exit JS frame"); |
499 // Record the location of the JS exit code for patching when setting | 491 // Record the location of the JS exit code for patching when setting |
500 // break point. | 492 // break point. |
501 __ RecordJSReturn(); | 493 __ RecordJSReturn(); |
502 | 494 |
503 // Avoid using the leave instruction here, because it is too | 495 // Avoid using the leave instruction here, because it is too |
504 // short. We need the return sequence to be a least the size of a | 496 // short. We need the return sequence to be a least the size of a |
505 // call instruction to support patching the exit code in the | 497 // call instruction to support patching the exit code in the |
506 // debugger. See VisitReturnStatement for the full return sequence. | 498 // debugger. See VisitReturnStatement for the full return sequence. |
507 __ mov(esp, Operand(ebp)); | 499 __ mov(esp, Operand(ebp)); |
508 stack_pointer_ = frame_pointer_; | 500 stack_pointer_ = frame_pointer(); |
509 for (int i = elements_.length() - 1; i > stack_pointer_; i--) { | 501 for (int i = elements_.length() - 1; i > stack_pointer_; i--) { |
510 FrameElement last = elements_.RemoveLast(); | 502 FrameElement last = elements_.RemoveLast(); |
511 if (last.is_register()) { | 503 if (last.is_register()) { |
512 Unuse(last.reg()); | 504 Unuse(last.reg()); |
513 } | 505 } |
514 } | 506 } |
515 | 507 |
516 frame_pointer_ = kIllegalIndex; | |
517 EmitPop(ebp); | 508 EmitPop(ebp); |
518 } | 509 } |
519 | 510 |
520 | 511 |
521 void VirtualFrame::AllocateStackSlots(int count) { | 512 void VirtualFrame::AllocateStackSlots() { |
522 ASSERT(height() == 0); | 513 ASSERT(height() == 0); |
523 local_count_ = count; | |
524 | 514 |
| 515 int count = local_count(); |
525 if (count > 0) { | 516 if (count > 0) { |
526 Comment cmnt(masm_, "[ Allocate space for locals"); | 517 Comment cmnt(masm(), "[ Allocate space for locals"); |
527 // The locals are initialized to a constant (the undefined value), but | 518 // The locals are initialized to a constant (the undefined value), but |
528 // we sync them with the actual frame to allocate space for spilling | 519 // we sync them with the actual frame to allocate space for spilling |
529 // them later. First sync everything above the stack pointer so we can | 520 // them later. First sync everything above the stack pointer so we can |
530 // use pushes to allocate and initialize the locals. | 521 // use pushes to allocate and initialize the locals. |
531 SyncRange(stack_pointer_ + 1, elements_.length() - 1); | 522 SyncRange(stack_pointer_ + 1, elements_.length() - 1); |
532 Handle<Object> undefined = Factory::undefined_value(); | 523 Handle<Object> undefined = Factory::undefined_value(); |
533 FrameElement initial_value = | 524 FrameElement initial_value = |
534 FrameElement::ConstantElement(undefined, FrameElement::SYNCED); | 525 FrameElement::ConstantElement(undefined, FrameElement::SYNCED); |
535 Result temp = cgen_->allocator()->Allocate(); | 526 Result temp = cgen()->allocator()->Allocate(); |
536 ASSERT(temp.is_valid()); | 527 ASSERT(temp.is_valid()); |
537 __ Set(temp.reg(), Immediate(undefined)); | 528 __ Set(temp.reg(), Immediate(undefined)); |
538 for (int i = 0; i < count; i++) { | 529 for (int i = 0; i < count; i++) { |
539 elements_.Add(initial_value); | 530 elements_.Add(initial_value); |
540 stack_pointer_++; | 531 stack_pointer_++; |
541 __ push(temp.reg()); | 532 __ push(temp.reg()); |
542 } | 533 } |
543 } | 534 } |
544 } | 535 } |
545 | 536 |
546 | 537 |
547 void VirtualFrame::SaveContextRegister() { | 538 void VirtualFrame::SaveContextRegister() { |
548 ASSERT(elements_[context_index()].is_memory()); | 539 ASSERT(elements_[context_index()].is_memory()); |
549 __ mov(Operand(ebp, fp_relative(context_index())), esi); | 540 __ mov(Operand(ebp, fp_relative(context_index())), esi); |
550 } | 541 } |
551 | 542 |
552 | 543 |
553 void VirtualFrame::RestoreContextRegister() { | 544 void VirtualFrame::RestoreContextRegister() { |
554 ASSERT(elements_[context_index()].is_memory()); | 545 ASSERT(elements_[context_index()].is_memory()); |
555 __ mov(esi, Operand(ebp, fp_relative(context_index()))); | 546 __ mov(esi, Operand(ebp, fp_relative(context_index()))); |
556 } | 547 } |
557 | 548 |
558 | 549 |
559 void VirtualFrame::PushReceiverSlotAddress() { | 550 void VirtualFrame::PushReceiverSlotAddress() { |
560 Result temp = cgen_->allocator()->Allocate(); | 551 Result temp = cgen()->allocator()->Allocate(); |
561 ASSERT(temp.is_valid()); | 552 ASSERT(temp.is_valid()); |
562 __ lea(temp.reg(), ParameterAt(-1)); | 553 __ lea(temp.reg(), ParameterAt(-1)); |
563 Push(&temp); | 554 Push(&temp); |
564 } | 555 } |
565 | 556 |
566 | 557 |
567 int VirtualFrame::InvalidateFrameSlotAt(int index) { | 558 int VirtualFrame::InvalidateFrameSlotAt(int index) { |
568 FrameElement original = elements_[index]; | 559 FrameElement original = elements_[index]; |
569 | 560 |
570 // Is this element the backing store of any copies? | 561 // Is this element the backing store of any copies? |
(...skipping 13 matching lines...) Expand all Loading... |
584 if (original.is_register()) { | 575 if (original.is_register()) { |
585 Unuse(original.reg()); | 576 Unuse(original.reg()); |
586 } | 577 } |
587 elements_[index] = FrameElement::InvalidElement(); | 578 elements_[index] = FrameElement::InvalidElement(); |
588 return kIllegalIndex; | 579 return kIllegalIndex; |
589 } | 580 } |
590 | 581 |
591 // This is the backing store of copies. | 582 // This is the backing store of copies. |
592 Register backing_reg; | 583 Register backing_reg; |
593 if (original.is_memory()) { | 584 if (original.is_memory()) { |
594 Result fresh = cgen_->allocator()->Allocate(); | 585 Result fresh = cgen()->allocator()->Allocate(); |
595 ASSERT(fresh.is_valid()); | 586 ASSERT(fresh.is_valid()); |
596 Use(fresh.reg(), new_backing_index); | 587 Use(fresh.reg(), new_backing_index); |
597 backing_reg = fresh.reg(); | 588 backing_reg = fresh.reg(); |
598 __ mov(backing_reg, Operand(ebp, fp_relative(index))); | 589 __ mov(backing_reg, Operand(ebp, fp_relative(index))); |
599 } else { | 590 } else { |
600 // The original was in a register. | 591 // The original was in a register. |
601 backing_reg = original.reg(); | 592 backing_reg = original.reg(); |
602 register_locations_[backing_reg.code()] = new_backing_index; | 593 register_locations_[backing_reg.code()] = new_backing_index; |
603 } | 594 } |
604 // Invalidate the element at index. | 595 // Invalidate the element at index. |
(...skipping 24 matching lines...) Expand all Loading... |
629 int new_backing_store_index = InvalidateFrameSlotAt(index); | 620 int new_backing_store_index = InvalidateFrameSlotAt(index); |
630 if (new_backing_store_index != kIllegalIndex) { | 621 if (new_backing_store_index != kIllegalIndex) { |
631 elements_.Add(CopyElementAt(new_backing_store_index)); | 622 elements_.Add(CopyElementAt(new_backing_store_index)); |
632 return; | 623 return; |
633 } | 624 } |
634 | 625 |
635 switch (original.type()) { | 626 switch (original.type()) { |
636 case FrameElement::MEMORY: { | 627 case FrameElement::MEMORY: { |
637 // Emit code to load the original element's data into a register. | 628 // Emit code to load the original element's data into a register. |
638 // Push that register as a FrameElement on top of the frame. | 629 // Push that register as a FrameElement on top of the frame. |
639 Result fresh = cgen_->allocator()->Allocate(); | 630 Result fresh = cgen()->allocator()->Allocate(); |
640 ASSERT(fresh.is_valid()); | 631 ASSERT(fresh.is_valid()); |
641 FrameElement new_element = | 632 FrameElement new_element = |
642 FrameElement::RegisterElement(fresh.reg(), | 633 FrameElement::RegisterElement(fresh.reg(), |
643 FrameElement::NOT_SYNCED); | 634 FrameElement::NOT_SYNCED); |
644 Use(fresh.reg(), elements_.length()); | 635 Use(fresh.reg(), elements_.length()); |
645 elements_.Add(new_element); | 636 elements_.Add(new_element); |
646 __ mov(fresh.reg(), Operand(ebp, fp_relative(index))); | 637 __ mov(fresh.reg(), Operand(ebp, fp_relative(index))); |
647 break; | 638 break; |
648 } | 639 } |
649 case FrameElement::REGISTER: | 640 case FrameElement::REGISTER: |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
703 if (backing_element.is_memory()) { | 694 if (backing_element.is_memory()) { |
704 // Because sets of copies are canonicalized to be backed by | 695 // Because sets of copies are canonicalized to be backed by |
705 // their lowest frame element, and because memory frame | 696 // their lowest frame element, and because memory frame |
706 // elements are backed by the corresponding stack address, we | 697 // elements are backed by the corresponding stack address, we |
707 // have to move the actual value down in the stack. | 698 // have to move the actual value down in the stack. |
708 // | 699 // |
709 // TODO(209): considering allocating the stored-to slot to the | 700 // TODO(209): considering allocating the stored-to slot to the |
710 // temp register. Alternatively, allow copies to appear in | 701 // temp register. Alternatively, allow copies to appear in |
711 // any order in the frame and lazily move the value down to | 702 // any order in the frame and lazily move the value down to |
712 // the slot. | 703 // the slot. |
713 Result temp = cgen_->allocator()->Allocate(); | 704 Result temp = cgen()->allocator()->Allocate(); |
714 ASSERT(temp.is_valid()); | 705 ASSERT(temp.is_valid()); |
715 __ mov(temp.reg(), Operand(ebp, fp_relative(backing_index))); | 706 __ mov(temp.reg(), Operand(ebp, fp_relative(backing_index))); |
716 __ mov(Operand(ebp, fp_relative(index)), temp.reg()); | 707 __ mov(Operand(ebp, fp_relative(index)), temp.reg()); |
717 } else { | 708 } else { |
718 register_locations_[backing_element.reg().code()] = index; | 709 register_locations_[backing_element.reg().code()] = index; |
719 if (backing_element.is_synced()) { | 710 if (backing_element.is_synced()) { |
720 // If the element is a register, we will not actually move | 711 // If the element is a register, we will not actually move |
721 // anything on the stack but only update the virtual frame | 712 // anything on the stack but only update the virtual frame |
722 // element. | 713 // element. |
723 backing_element.clear_sync(); | 714 backing_element.clear_sync(); |
(...skipping 26 matching lines...) Expand all Loading... |
750 if (top.is_memory()) { | 741 if (top.is_memory()) { |
751 // TODO(209): consider allocating the stored-to slot to the temp | 742 // TODO(209): consider allocating the stored-to slot to the temp |
752 // register. Alternatively, allow copies to appear in any order | 743 // register. Alternatively, allow copies to appear in any order |
753 // in the frame and lazily move the value down to the slot. | 744 // in the frame and lazily move the value down to the slot. |
754 FrameElement new_top = CopyElementAt(index); | 745 FrameElement new_top = CopyElementAt(index); |
755 new_top.set_sync(); | 746 new_top.set_sync(); |
756 elements_[top_index] = new_top; | 747 elements_[top_index] = new_top; |
757 | 748 |
758 // The sync state of the former top element is correct (synced). | 749 // The sync state of the former top element is correct (synced). |
759 // Emit code to move the value down in the frame. | 750 // Emit code to move the value down in the frame. |
760 Result temp = cgen_->allocator()->Allocate(); | 751 Result temp = cgen()->allocator()->Allocate(); |
761 ASSERT(temp.is_valid()); | 752 ASSERT(temp.is_valid()); |
762 __ mov(temp.reg(), Operand(esp, 0)); | 753 __ mov(temp.reg(), Operand(esp, 0)); |
763 __ mov(Operand(ebp, fp_relative(index)), temp.reg()); | 754 __ mov(Operand(ebp, fp_relative(index)), temp.reg()); |
764 } else if (top.is_register()) { | 755 } else if (top.is_register()) { |
765 register_locations_[top.reg().code()] = index; | 756 register_locations_[top.reg().code()] = index; |
766 // The stored-to slot has the (unsynced) register reference and | 757 // The stored-to slot has the (unsynced) register reference and |
767 // the top element becomes a copy. The sync state of the top is | 758 // the top element becomes a copy. The sync state of the top is |
768 // preserved. | 759 // preserved. |
769 FrameElement new_top = CopyElementAt(index); | 760 FrameElement new_top = CopyElementAt(index); |
770 if (top.is_synced()) { | 761 if (top.is_synced()) { |
771 new_top.set_sync(); | 762 new_top.set_sync(); |
772 elements_[index].clear_sync(); | 763 elements_[index].clear_sync(); |
773 } | 764 } |
774 elements_[top_index] = new_top; | 765 elements_[top_index] = new_top; |
775 } else { | 766 } else { |
776 // The stored-to slot holds the same value as the top but | 767 // The stored-to slot holds the same value as the top but |
777 // unsynced. (We do not have copies of constants yet.) | 768 // unsynced. (We do not have copies of constants yet.) |
778 ASSERT(top.is_constant()); | 769 ASSERT(top.is_constant()); |
779 elements_[index].clear_sync(); | 770 elements_[index].clear_sync(); |
780 } | 771 } |
781 } | 772 } |
782 | 773 |
783 | 774 |
784 void VirtualFrame::PushTryHandler(HandlerType type) { | 775 void VirtualFrame::PushTryHandler(HandlerType type) { |
785 ASSERT(cgen_->HasValidEntryRegisters()); | 776 ASSERT(cgen()->HasValidEntryRegisters()); |
786 // Grow the expression stack by handler size less two (the return address | 777 // Grow the expression stack by handler size less two (the return address |
787 // is already pushed by a call instruction, and PushTryHandler from the | 778 // is already pushed by a call instruction, and PushTryHandler from the |
788 // macro assembler will leave the top of stack in the eax register to be | 779 // macro assembler will leave the top of stack in the eax register to be |
789 // pushed separately). | 780 // pushed separately). |
790 Adjust(kHandlerSize - 2); | 781 Adjust(kHandlerSize - 2); |
791 __ PushTryHandler(IN_JAVASCRIPT, type); | 782 __ PushTryHandler(IN_JAVASCRIPT, type); |
792 // TODO(1222589): remove the reliance of PushTryHandler on a cached TOS | 783 // TODO(1222589): remove the reliance of PushTryHandler on a cached TOS |
793 EmitPush(eax); | 784 EmitPush(eax); |
794 } | 785 } |
795 | 786 |
796 | 787 |
797 Result VirtualFrame::RawCallStub(CodeStub* stub) { | 788 Result VirtualFrame::RawCallStub(CodeStub* stub) { |
798 ASSERT(cgen_->HasValidEntryRegisters()); | 789 ASSERT(cgen()->HasValidEntryRegisters()); |
799 __ CallStub(stub); | 790 __ CallStub(stub); |
800 Result result = cgen_->allocator()->Allocate(eax); | 791 Result result = cgen()->allocator()->Allocate(eax); |
801 ASSERT(result.is_valid()); | 792 ASSERT(result.is_valid()); |
802 return result; | 793 return result; |
803 } | 794 } |
804 | 795 |
805 | 796 |
806 Result VirtualFrame::CallStub(CodeStub* stub, Result* arg) { | 797 Result VirtualFrame::CallStub(CodeStub* stub, Result* arg) { |
807 PrepareForCall(0, 0); | 798 PrepareForCall(0, 0); |
808 arg->ToRegister(eax); | 799 arg->ToRegister(eax); |
809 arg->Unuse(); | 800 arg->Unuse(); |
810 return RawCallStub(stub); | 801 return RawCallStub(stub); |
(...skipping 20 matching lines...) Expand all Loading... |
831 } | 822 } |
832 | 823 |
833 arg0->Unuse(); | 824 arg0->Unuse(); |
834 arg1->Unuse(); | 825 arg1->Unuse(); |
835 return RawCallStub(stub); | 826 return RawCallStub(stub); |
836 } | 827 } |
837 | 828 |
838 | 829 |
839 Result VirtualFrame::CallRuntime(Runtime::Function* f, int arg_count) { | 830 Result VirtualFrame::CallRuntime(Runtime::Function* f, int arg_count) { |
840 PrepareForCall(arg_count, arg_count); | 831 PrepareForCall(arg_count, arg_count); |
841 ASSERT(cgen_->HasValidEntryRegisters()); | 832 ASSERT(cgen()->HasValidEntryRegisters()); |
842 __ CallRuntime(f, arg_count); | 833 __ CallRuntime(f, arg_count); |
843 Result result = cgen_->allocator()->Allocate(eax); | 834 Result result = cgen()->allocator()->Allocate(eax); |
844 ASSERT(result.is_valid()); | 835 ASSERT(result.is_valid()); |
845 return result; | 836 return result; |
846 } | 837 } |
847 | 838 |
848 | 839 |
849 Result VirtualFrame::CallRuntime(Runtime::FunctionId id, int arg_count) { | 840 Result VirtualFrame::CallRuntime(Runtime::FunctionId id, int arg_count) { |
850 PrepareForCall(arg_count, arg_count); | 841 PrepareForCall(arg_count, arg_count); |
851 ASSERT(cgen_->HasValidEntryRegisters()); | 842 ASSERT(cgen()->HasValidEntryRegisters()); |
852 __ CallRuntime(id, arg_count); | 843 __ CallRuntime(id, arg_count); |
853 Result result = cgen_->allocator()->Allocate(eax); | 844 Result result = cgen()->allocator()->Allocate(eax); |
854 ASSERT(result.is_valid()); | 845 ASSERT(result.is_valid()); |
855 return result; | 846 return result; |
856 } | 847 } |
857 | 848 |
858 | 849 |
859 Result VirtualFrame::InvokeBuiltin(Builtins::JavaScript id, | 850 Result VirtualFrame::InvokeBuiltin(Builtins::JavaScript id, |
860 InvokeFlag flag, | 851 InvokeFlag flag, |
861 int arg_count) { | 852 int arg_count) { |
862 PrepareForCall(arg_count, arg_count); | 853 PrepareForCall(arg_count, arg_count); |
863 ASSERT(cgen_->HasValidEntryRegisters()); | 854 ASSERT(cgen()->HasValidEntryRegisters()); |
864 __ InvokeBuiltin(id, flag); | 855 __ InvokeBuiltin(id, flag); |
865 Result result = cgen_->allocator()->Allocate(eax); | 856 Result result = cgen()->allocator()->Allocate(eax); |
866 ASSERT(result.is_valid()); | 857 ASSERT(result.is_valid()); |
867 return result; | 858 return result; |
868 } | 859 } |
869 | 860 |
870 | 861 |
871 Result VirtualFrame::RawCallCodeObject(Handle<Code> code, | 862 Result VirtualFrame::RawCallCodeObject(Handle<Code> code, |
872 RelocInfo::Mode rmode) { | 863 RelocInfo::Mode rmode) { |
873 ASSERT(cgen_->HasValidEntryRegisters()); | 864 ASSERT(cgen()->HasValidEntryRegisters()); |
874 __ call(code, rmode); | 865 __ call(code, rmode); |
875 Result result = cgen_->allocator()->Allocate(eax); | 866 Result result = cgen()->allocator()->Allocate(eax); |
876 ASSERT(result.is_valid()); | 867 ASSERT(result.is_valid()); |
877 return result; | 868 return result; |
878 } | 869 } |
879 | 870 |
880 | 871 |
881 Result VirtualFrame::CallLoadIC(RelocInfo::Mode mode) { | 872 Result VirtualFrame::CallLoadIC(RelocInfo::Mode mode) { |
882 // Name and receiver are on the top of the frame. The IC expects | 873 // Name and receiver are on the top of the frame. The IC expects |
883 // name in ecx and receiver on the stack. It does not drop the | 874 // name in ecx and receiver on the stack. It does not drop the |
884 // receiver. | 875 // receiver. |
885 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 876 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
945 } | 936 } |
946 | 937 |
947 | 938 |
948 Result VirtualFrame::CallCallIC(RelocInfo::Mode mode, | 939 Result VirtualFrame::CallCallIC(RelocInfo::Mode mode, |
949 int arg_count, | 940 int arg_count, |
950 int loop_nesting) { | 941 int loop_nesting) { |
951 // Arguments, receiver, and function name are on top of the frame. | 942 // Arguments, receiver, and function name are on top of the frame. |
952 // The IC expects them on the stack. It does not drop the function | 943 // The IC expects them on the stack. It does not drop the function |
953 // name slot (but it does drop the rest). | 944 // name slot (but it does drop the rest). |
954 Handle<Code> ic = (loop_nesting > 0) | 945 Handle<Code> ic = (loop_nesting > 0) |
955 ? cgen_->ComputeCallInitializeInLoop(arg_count) | 946 ? cgen()->ComputeCallInitializeInLoop(arg_count) |
956 : cgen_->ComputeCallInitialize(arg_count); | 947 : cgen()->ComputeCallInitialize(arg_count); |
957 // Spill args, receiver, and function. The call will drop args and | 948 // Spill args, receiver, and function. The call will drop args and |
958 // receiver. | 949 // receiver. |
959 PrepareForCall(arg_count + 2, arg_count + 1); | 950 PrepareForCall(arg_count + 2, arg_count + 1); |
960 return RawCallCodeObject(ic, mode); | 951 return RawCallCodeObject(ic, mode); |
961 } | 952 } |
962 | 953 |
963 | 954 |
964 Result VirtualFrame::CallConstructor(int arg_count) { | 955 Result VirtualFrame::CallConstructor(int arg_count) { |
965 // Arguments, receiver, and function are on top of the frame. The | 956 // Arguments, receiver, and function are on top of the frame. The |
966 // IC expects arg count in eax, function in edi, and the arguments | 957 // IC expects arg count in eax, function in edi, and the arguments |
967 // and receiver on the stack. | 958 // and receiver on the stack. |
968 Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall)); | 959 Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall)); |
969 // Duplicate the function before preparing the frame. | 960 // Duplicate the function before preparing the frame. |
970 PushElementAt(arg_count + 1); | 961 PushElementAt(arg_count + 1); |
971 Result function = Pop(); | 962 Result function = Pop(); |
972 PrepareForCall(arg_count + 1, arg_count + 1); // Spill args and receiver. | 963 PrepareForCall(arg_count + 1, arg_count + 1); // Spill args and receiver. |
973 function.ToRegister(edi); | 964 function.ToRegister(edi); |
974 | 965 |
975 // Constructors are called with the number of arguments in register | 966 // Constructors are called with the number of arguments in register |
976 // eax for now. Another option would be to have separate construct | 967 // eax for now. Another option would be to have separate construct |
977 // call trampolines per different arguments counts encountered. | 968 // call trampolines per different arguments counts encountered. |
978 Result num_args = cgen_->allocator()->Allocate(eax); | 969 Result num_args = cgen()->allocator()->Allocate(eax); |
979 ASSERT(num_args.is_valid()); | 970 ASSERT(num_args.is_valid()); |
980 __ Set(num_args.reg(), Immediate(arg_count)); | 971 __ Set(num_args.reg(), Immediate(arg_count)); |
981 | 972 |
982 function.Unuse(); | 973 function.Unuse(); |
983 num_args.Unuse(); | 974 num_args.Unuse(); |
984 return RawCallCodeObject(ic, RelocInfo::CONSTRUCT_CALL); | 975 return RawCallCodeObject(ic, RelocInfo::CONSTRUCT_CALL); |
985 } | 976 } |
986 | 977 |
987 | 978 |
988 void VirtualFrame::Drop(int count) { | 979 void VirtualFrame::Drop(int count) { |
(...skipping 19 matching lines...) Expand all Loading... |
1008 | 999 |
1009 Result VirtualFrame::Pop() { | 1000 Result VirtualFrame::Pop() { |
1010 FrameElement element = elements_.RemoveLast(); | 1001 FrameElement element = elements_.RemoveLast(); |
1011 int index = elements_.length(); | 1002 int index = elements_.length(); |
1012 ASSERT(element.is_valid()); | 1003 ASSERT(element.is_valid()); |
1013 | 1004 |
1014 bool pop_needed = (stack_pointer_ == index); | 1005 bool pop_needed = (stack_pointer_ == index); |
1015 if (pop_needed) { | 1006 if (pop_needed) { |
1016 stack_pointer_--; | 1007 stack_pointer_--; |
1017 if (element.is_memory()) { | 1008 if (element.is_memory()) { |
1018 Result temp = cgen_->allocator()->Allocate(); | 1009 Result temp = cgen()->allocator()->Allocate(); |
1019 ASSERT(temp.is_valid()); | 1010 ASSERT(temp.is_valid()); |
1020 temp.set_static_type(element.static_type()); | 1011 temp.set_static_type(element.static_type()); |
1021 __ pop(temp.reg()); | 1012 __ pop(temp.reg()); |
1022 return temp; | 1013 return temp; |
1023 } | 1014 } |
1024 | 1015 |
1025 __ add(Operand(esp), Immediate(kPointerSize)); | 1016 __ add(Operand(esp), Immediate(kPointerSize)); |
1026 } | 1017 } |
1027 ASSERT(!element.is_memory()); | 1018 ASSERT(!element.is_memory()); |
1028 | 1019 |
1029 // The top element is a register, constant, or a copy. Unuse | 1020 // The top element is a register, constant, or a copy. Unuse |
1030 // registers and follow copies to their backing store. | 1021 // registers and follow copies to their backing store. |
1031 if (element.is_register()) { | 1022 if (element.is_register()) { |
1032 Unuse(element.reg()); | 1023 Unuse(element.reg()); |
1033 } else if (element.is_copy()) { | 1024 } else if (element.is_copy()) { |
1034 ASSERT(element.index() < index); | 1025 ASSERT(element.index() < index); |
1035 index = element.index(); | 1026 index = element.index(); |
1036 element = elements_[index]; | 1027 element = elements_[index]; |
1037 } | 1028 } |
1038 ASSERT(!element.is_copy()); | 1029 ASSERT(!element.is_copy()); |
1039 | 1030 |
1040 // The element is memory, a register, or a constant. | 1031 // The element is memory, a register, or a constant. |
1041 if (element.is_memory()) { | 1032 if (element.is_memory()) { |
1042 // Memory elements could only be the backing store of a copy. | 1033 // Memory elements could only be the backing store of a copy. |
1043 // Allocate the original to a register. | 1034 // Allocate the original to a register. |
1044 ASSERT(index <= stack_pointer_); | 1035 ASSERT(index <= stack_pointer_); |
1045 Result temp = cgen_->allocator()->Allocate(); | 1036 Result temp = cgen()->allocator()->Allocate(); |
1046 ASSERT(temp.is_valid()); | 1037 ASSERT(temp.is_valid()); |
1047 Use(temp.reg(), index); | 1038 Use(temp.reg(), index); |
1048 FrameElement new_element = | 1039 FrameElement new_element = |
1049 FrameElement::RegisterElement(temp.reg(), FrameElement::SYNCED); | 1040 FrameElement::RegisterElement(temp.reg(), FrameElement::SYNCED); |
1050 // Preserve the copy flag on the element. | 1041 // Preserve the copy flag on the element. |
1051 if (element.is_copied()) new_element.set_copied(); | 1042 if (element.is_copied()) new_element.set_copied(); |
1052 new_element.set_static_type(element.static_type()); | 1043 new_element.set_static_type(element.static_type()); |
1053 elements_[index] = new_element; | 1044 elements_[index] = new_element; |
1054 __ mov(temp.reg(), Operand(ebp, fp_relative(index))); | 1045 __ mov(temp.reg(), Operand(ebp, fp_relative(index))); |
1055 return Result(temp.reg(), element.static_type()); | 1046 return Result(temp.reg(), element.static_type()); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1098 ASSERT(stack_pointer_ == elements_.length() - 1); | 1089 ASSERT(stack_pointer_ == elements_.length() - 1); |
1099 elements_.Add(FrameElement::MemoryElement()); | 1090 elements_.Add(FrameElement::MemoryElement()); |
1100 stack_pointer_++; | 1091 stack_pointer_++; |
1101 __ push(immediate); | 1092 __ push(immediate); |
1102 } | 1093 } |
1103 | 1094 |
1104 | 1095 |
1105 #undef __ | 1096 #undef __ |
1106 | 1097 |
1107 } } // namespace v8::internal | 1098 } } // namespace v8::internal |
OLD | NEW |