OLD | NEW |
---|---|
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
174 #endif | 174 #endif |
175 | 175 |
176 if (info->mode() == CompilationInfo::PRIMARY) { | 176 if (info->mode() == CompilationInfo::PRIMARY) { |
177 frame_->Enter(); | 177 frame_->Enter(); |
178 // tos: code slot | 178 // tos: code slot |
179 | 179 |
180 // Allocate space for locals and initialize them. This also checks | 180 // Allocate space for locals and initialize them. This also checks |
181 // for stack overflow. | 181 // for stack overflow. |
182 frame_->AllocateStackSlots(); | 182 frame_->AllocateStackSlots(); |
183 | 183 |
184 VirtualFrame::SpilledScope spilled_scope; | 184 VirtualFrame::SpilledScope spilled_scope(frame_); |
185 int heap_slots = scope()->num_heap_slots(); | 185 int heap_slots = scope()->num_heap_slots(); |
186 if (heap_slots > 0) { | 186 if (heap_slots > 0) { |
187 // Allocate local context. | 187 // Allocate local context. |
188 // Get outer context and create a new context based on it. | 188 // Get outer context and create a new context based on it. |
189 __ ldr(r0, frame_->Function()); | 189 __ ldr(r0, frame_->Function()); |
190 frame_->EmitPush(r0); | 190 frame_->EmitPush(r0); |
191 if (heap_slots <= FastNewContextStub::kMaximumSlots) { | 191 if (heap_slots <= FastNewContextStub::kMaximumSlots) { |
192 FastNewContextStub stub(heap_slots); | 192 FastNewContextStub stub(heap_slots); |
193 frame_->CallStub(&stub, 1); | 193 frame_->CallStub(&stub, 1); |
194 } else { | 194 } else { |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
267 if (scope()->is_function_scope() && scope()->function() != NULL) { | 267 if (scope()->is_function_scope() && scope()->function() != NULL) { |
268 __ mov(ip, Operand(Factory::the_hole_value())); | 268 __ mov(ip, Operand(Factory::the_hole_value())); |
269 frame_->EmitPush(ip); | 269 frame_->EmitPush(ip); |
270 StoreToSlot(scope()->function()->slot(), NOT_CONST_INIT); | 270 StoreToSlot(scope()->function()->slot(), NOT_CONST_INIT); |
271 } | 271 } |
272 } else { | 272 } else { |
273 // When used as the secondary compiler for splitting, r1, cp, | 273 // When used as the secondary compiler for splitting, r1, cp, |
274 // fp, and lr have been pushed on the stack. Adjust the virtual | 274 // fp, and lr have been pushed on the stack. Adjust the virtual |
275 // frame to match this state. | 275 // frame to match this state. |
276 frame_->Adjust(4); | 276 frame_->Adjust(4); |
277 allocator_->Unuse(r1); | |
278 allocator_->Unuse(lr); | |
279 | 277 |
280 // Bind all the bailout labels to the beginning of the function. | 278 // Bind all the bailout labels to the beginning of the function. |
281 List<CompilationInfo::Bailout*>* bailouts = info->bailouts(); | 279 List<CompilationInfo::Bailout*>* bailouts = info->bailouts(); |
282 for (int i = 0; i < bailouts->length(); i++) { | 280 for (int i = 0; i < bailouts->length(); i++) { |
283 __ bind(bailouts->at(i)->label()); | 281 __ bind(bailouts->at(i)->label()); |
284 } | 282 } |
285 } | 283 } |
286 | 284 |
287 // Initialize the function return target after the locals are set | 285 // Initialize the function return target after the locals are set |
288 // up, because it needs the expected frame height from the frame. | 286 // up, because it needs the expected frame height from the frame. |
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
498 // code as we unwind the C++ stack. | 496 // code as we unwind the C++ stack. |
499 // | 497 // |
500 // It's possible to have both a stack overflow and a valid frame | 498 // It's possible to have both a stack overflow and a valid frame |
501 // state (eg, a subexpression overflowed, visiting it returned | 499 // state (eg, a subexpression overflowed, visiting it returned |
502 // with a dummied frame state, and visiting this expression | 500 // with a dummied frame state, and visiting this expression |
503 // returned with a normal-looking state). | 501 // returned with a normal-looking state). |
504 if (HasStackOverflow() && | 502 if (HasStackOverflow() && |
505 has_valid_frame() && | 503 has_valid_frame() && |
506 !has_cc() && | 504 !has_cc() && |
507 frame_->height() == original_height) { | 505 frame_->height() == original_height) { |
506 frame_->SpillAll(); | |
508 true_target->Jump(); | 507 true_target->Jump(); |
509 } | 508 } |
510 } | 509 } |
511 if (force_cc && frame_ != NULL && !has_cc()) { | 510 if (force_cc && frame_ != NULL && !has_cc()) { |
512 // Convert the TOS value to a boolean in the condition code register. | 511 // Convert the TOS value to a boolean in the condition code register. |
513 ToBoolean(true_target, false_target); | 512 ToBoolean(true_target, false_target); |
514 } | 513 } |
515 ASSERT(!force_cc || !has_valid_frame() || has_cc()); | 514 ASSERT(!force_cc || !has_valid_frame() || has_cc()); |
516 ASSERT(!has_valid_frame() || | 515 ASSERT(!has_valid_frame() || |
517 (has_cc() && frame_->height() == original_height) || | 516 (has_cc() && frame_->height() == original_height) || |
518 (!has_cc() && frame_->height() == original_height + 1)); | 517 (!has_cc() && frame_->height() == original_height + 1)); |
519 } | 518 } |
520 | 519 |
521 | 520 |
522 void CodeGenerator::Load(Expression* expr) { | 521 void CodeGenerator::Load(Expression* expr) { |
523 #ifdef DEBUG | 522 #ifdef DEBUG |
524 int original_height = frame_->height(); | 523 int original_height = frame_->height(); |
525 #endif | 524 #endif |
526 JumpTarget true_target; | 525 JumpTarget true_target; |
527 JumpTarget false_target; | 526 JumpTarget false_target; |
528 LoadCondition(expr, &true_target, &false_target, false); | 527 LoadCondition(expr, &true_target, &false_target, false); |
529 | 528 |
530 if (has_cc()) { | 529 if (has_cc()) { |
531 // Convert cc_reg_ into a boolean value. | 530 // Convert cc_reg_ into a boolean value. |
531 VirtualFrame::SpilledScope scope(frame_); | |
532 JumpTarget loaded; | 532 JumpTarget loaded; |
533 JumpTarget materialize_true; | 533 JumpTarget materialize_true; |
534 materialize_true.Branch(cc_reg_); | 534 materialize_true.Branch(cc_reg_); |
535 __ LoadRoot(r0, Heap::kFalseValueRootIndex); | 535 __ LoadRoot(r0, Heap::kFalseValueRootIndex); |
536 frame_->EmitPush(r0); | 536 frame_->EmitPush(r0); |
537 loaded.Jump(); | 537 loaded.Jump(); |
538 materialize_true.Bind(); | 538 materialize_true.Bind(); |
539 __ LoadRoot(r0, Heap::kTrueValueRootIndex); | 539 __ LoadRoot(r0, Heap::kTrueValueRootIndex); |
540 frame_->EmitPush(r0); | 540 frame_->EmitPush(r0); |
541 loaded.Bind(); | 541 loaded.Bind(); |
542 cc_reg_ = al; | 542 cc_reg_ = al; |
543 } | 543 } |
544 | 544 |
545 if (true_target.is_linked() || false_target.is_linked()) { | 545 if (true_target.is_linked() || false_target.is_linked()) { |
546 VirtualFrame::SpilledScope scope(frame_); | |
546 // We have at least one condition value that has been "translated" | 547 // We have at least one condition value that has been "translated" |
547 // into a branch, thus it needs to be loaded explicitly. | 548 // into a branch, thus it needs to be loaded explicitly. |
548 JumpTarget loaded; | 549 JumpTarget loaded; |
549 if (frame_ != NULL) { | 550 if (frame_ != NULL) { |
550 loaded.Jump(); // Don't lose the current TOS. | 551 loaded.Jump(); // Don't lose the current TOS. |
551 } | 552 } |
552 bool both = true_target.is_linked() && false_target.is_linked(); | 553 bool both = true_target.is_linked() && false_target.is_linked(); |
553 // Load "true" if necessary. | 554 // Load "true" if necessary. |
554 if (true_target.is_linked()) { | 555 if (true_target.is_linked()) { |
555 true_target.Bind(); | 556 true_target.Bind(); |
(...skipping 14 matching lines...) Expand all Loading... | |
570 // A value is loaded on all paths reaching this point. | 571 // A value is loaded on all paths reaching this point. |
571 loaded.Bind(); | 572 loaded.Bind(); |
572 } | 573 } |
573 ASSERT(has_valid_frame()); | 574 ASSERT(has_valid_frame()); |
574 ASSERT(!has_cc()); | 575 ASSERT(!has_cc()); |
575 ASSERT(frame_->height() == original_height + 1); | 576 ASSERT(frame_->height() == original_height + 1); |
576 } | 577 } |
577 | 578 |
578 | 579 |
579 void CodeGenerator::LoadGlobal() { | 580 void CodeGenerator::LoadGlobal() { |
580 VirtualFrame::SpilledScope spilled_scope; | 581 VirtualFrame::SpilledScope spilled_scope(frame_); |
581 __ ldr(r0, GlobalObject()); | 582 __ ldr(r0, GlobalObject()); |
582 frame_->EmitPush(r0); | 583 frame_->EmitPush(r0); |
583 } | 584 } |
584 | 585 |
585 | 586 |
586 void CodeGenerator::LoadGlobalReceiver(Register scratch) { | 587 void CodeGenerator::LoadGlobalReceiver(Register scratch) { |
587 VirtualFrame::SpilledScope spilled_scope; | 588 VirtualFrame::SpilledScope spilled_scope(frame_); |
588 __ ldr(scratch, ContextOperand(cp, Context::GLOBAL_INDEX)); | 589 __ ldr(scratch, ContextOperand(cp, Context::GLOBAL_INDEX)); |
589 __ ldr(scratch, | 590 __ ldr(scratch, |
590 FieldMemOperand(scratch, GlobalObject::kGlobalReceiverOffset)); | 591 FieldMemOperand(scratch, GlobalObject::kGlobalReceiverOffset)); |
591 frame_->EmitPush(scratch); | 592 frame_->EmitPush(scratch); |
592 } | 593 } |
593 | 594 |
594 | 595 |
595 void CodeGenerator::LoadTypeofExpression(Expression* expr) { | 596 void CodeGenerator::LoadTypeofExpression(Expression* expr) { |
596 // Special handling of identifiers as subexpressions of typeof. | 597 // Special handling of identifiers as subexpressions of typeof. |
597 VirtualFrame::SpilledScope spilled_scope; | 598 VirtualFrame::SpilledScope spilled_scope(frame_); |
598 Variable* variable = expr->AsVariableProxy()->AsVariable(); | 599 Variable* variable = expr->AsVariableProxy()->AsVariable(); |
599 if (variable != NULL && !variable->is_this() && variable->is_global()) { | 600 if (variable != NULL && !variable->is_this() && variable->is_global()) { |
600 // For a global variable we build the property reference | 601 // For a global variable we build the property reference |
601 // <global>.<variable> and perform a (regular non-contextual) property | 602 // <global>.<variable> and perform a (regular non-contextual) property |
602 // load to make sure we do not get reference errors. | 603 // load to make sure we do not get reference errors. |
603 Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX); | 604 Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX); |
604 Literal key(variable->name()); | 605 Literal key(variable->name()); |
605 Property property(&global, &key, RelocInfo::kNoPosition); | 606 Property property(&global, &key, RelocInfo::kNoPosition); |
606 Reference ref(this, &property); | 607 Reference ref(this, &property); |
607 ref.GetValueAndSpill(); | 608 ref.GetValue(); |
608 } else if (variable != NULL && variable->slot() != NULL) { | 609 } else if (variable != NULL && variable->slot() != NULL) { |
609 // For a variable that rewrites to a slot, we signal it is the immediate | 610 // For a variable that rewrites to a slot, we signal it is the immediate |
610 // subexpression of a typeof. | 611 // subexpression of a typeof. |
611 LoadFromSlot(variable->slot(), INSIDE_TYPEOF); | 612 LoadFromSlot(variable->slot(), INSIDE_TYPEOF); |
612 frame_->SpillAll(); | 613 frame_->SpillAll(); |
613 } else { | 614 } else { |
614 // Anything else can be handled normally. | 615 // Anything else can be handled normally. |
615 LoadAndSpill(expr); | 616 LoadAndSpill(expr); |
616 } | 617 } |
617 } | 618 } |
618 | 619 |
619 | 620 |
620 Reference::Reference(CodeGenerator* cgen, | 621 Reference::Reference(CodeGenerator* cgen, |
621 Expression* expression, | 622 Expression* expression, |
622 bool persist_after_get) | 623 bool persist_after_get) |
623 : cgen_(cgen), | 624 : cgen_(cgen), |
624 expression_(expression), | 625 expression_(expression), |
625 type_(ILLEGAL), | 626 type_(ILLEGAL), |
626 persist_after_get_(persist_after_get) { | 627 persist_after_get_(persist_after_get) { |
627 cgen->LoadReference(this); | 628 cgen->LoadReference(this); |
628 } | 629 } |
629 | 630 |
630 | 631 |
631 Reference::~Reference() { | 632 Reference::~Reference() { |
632 ASSERT(is_unloaded() || is_illegal()); | 633 ASSERT(is_unloaded() || is_illegal()); |
633 } | 634 } |
634 | 635 |
635 | 636 |
636 void CodeGenerator::LoadReference(Reference* ref) { | 637 void CodeGenerator::LoadReference(Reference* ref) { |
637 VirtualFrame::SpilledScope spilled_scope; | 638 VirtualFrame::SpilledScope spilled_scope(frame_); |
638 Comment cmnt(masm_, "[ LoadReference"); | 639 Comment cmnt(masm_, "[ LoadReference"); |
639 Expression* e = ref->expression(); | 640 Expression* e = ref->expression(); |
640 Property* property = e->AsProperty(); | 641 Property* property = e->AsProperty(); |
641 Variable* var = e->AsVariableProxy()->AsVariable(); | 642 Variable* var = e->AsVariableProxy()->AsVariable(); |
642 | 643 |
643 if (property != NULL) { | 644 if (property != NULL) { |
644 // The expression is either a property or a variable proxy that rewrites | 645 // The expression is either a property or a variable proxy that rewrites |
645 // to a property. | 646 // to a property. |
646 LoadAndSpill(property->obj()); | 647 LoadAndSpill(property->obj()); |
647 if (property->key()->IsPropertyName()) { | 648 if (property->key()->IsPropertyName()) { |
(...skipping 14 matching lines...) Expand all Loading... | |
662 } | 663 } |
663 } else { | 664 } else { |
664 // Anything else is a runtime error. | 665 // Anything else is a runtime error. |
665 LoadAndSpill(e); | 666 LoadAndSpill(e); |
666 frame_->CallRuntime(Runtime::kThrowReferenceError, 1); | 667 frame_->CallRuntime(Runtime::kThrowReferenceError, 1); |
667 } | 668 } |
668 } | 669 } |
669 | 670 |
670 | 671 |
671 void CodeGenerator::UnloadReference(Reference* ref) { | 672 void CodeGenerator::UnloadReference(Reference* ref) { |
672 VirtualFrame::SpilledScope spilled_scope; | 673 int size = ref->size(); |
674 ref->set_unloaded(); | |
675 if (size == 0) return; | |
676 | |
673 // Pop a reference from the stack while preserving TOS. | 677 // Pop a reference from the stack while preserving TOS. |
678 VirtualFrame::RegisterAllocationScope scope(this); | |
674 Comment cmnt(masm_, "[ UnloadReference"); | 679 Comment cmnt(masm_, "[ UnloadReference"); |
675 int size = ref->size(); | |
676 if (size > 0) { | 680 if (size > 0) { |
677 frame_->EmitPop(r0); | 681 Register tos = frame_->PopToRegister(); |
678 frame_->Drop(size); | 682 frame_->Drop(size); |
679 frame_->EmitPush(r0); | 683 frame_->EmitPush(tos); |
680 } | 684 } |
681 ref->set_unloaded(); | |
682 } | 685 } |
683 | 686 |
684 | 687 |
685 // ECMA-262, section 9.2, page 30: ToBoolean(). Convert the given | 688 // ECMA-262, section 9.2, page 30: ToBoolean(). Convert the given |
686 // register to a boolean in the condition code register. The code | 689 // register to a boolean in the condition code register. The code |
687 // may jump to 'false_target' in case the register converts to 'false'. | 690 // may jump to 'false_target' in case the register converts to 'false'. |
688 void CodeGenerator::ToBoolean(JumpTarget* true_target, | 691 void CodeGenerator::ToBoolean(JumpTarget* true_target, |
689 JumpTarget* false_target) { | 692 JumpTarget* false_target) { |
690 VirtualFrame::SpilledScope spilled_scope; | 693 VirtualFrame::SpilledScope spilled_scope(frame_); |
691 // Note: The generated code snippet does not change stack variables. | 694 // Note: The generated code snippet does not change stack variables. |
692 // Only the condition code should be set. | 695 // Only the condition code should be set. |
693 frame_->EmitPop(r0); | 696 frame_->EmitPop(r0); |
694 | 697 |
695 // Fast case checks | 698 // Fast case checks |
696 | 699 |
697 // Check if the value is 'false'. | 700 // Check if the value is 'false'. |
698 __ LoadRoot(ip, Heap::kFalseValueRootIndex); | 701 __ LoadRoot(ip, Heap::kFalseValueRootIndex); |
699 __ cmp(r0, ip); | 702 __ cmp(r0, ip); |
700 false_target->Branch(eq); | 703 false_target->Branch(eq); |
(...skipping 21 matching lines...) Expand all Loading... | |
722 __ LoadRoot(ip, Heap::kFalseValueRootIndex); | 725 __ LoadRoot(ip, Heap::kFalseValueRootIndex); |
723 __ cmp(r0, ip); | 726 __ cmp(r0, ip); |
724 | 727 |
725 cc_reg_ = ne; | 728 cc_reg_ = ne; |
726 } | 729 } |
727 | 730 |
728 | 731 |
729 void CodeGenerator::GenericBinaryOperation(Token::Value op, | 732 void CodeGenerator::GenericBinaryOperation(Token::Value op, |
730 OverwriteMode overwrite_mode, | 733 OverwriteMode overwrite_mode, |
731 int constant_rhs) { | 734 int constant_rhs) { |
732 VirtualFrame::SpilledScope spilled_scope; | 735 VirtualFrame::SpilledScope spilled_scope(frame_); |
733 // sp[0] : y | 736 // sp[0] : y |
734 // sp[1] : x | 737 // sp[1] : x |
735 // result : r0 | 738 // result : r0 |
736 | 739 |
737 // Stub is entered with a call: 'return address' is in lr. | 740 // Stub is entered with a call: 'return address' is in lr. |
738 switch (op) { | 741 switch (op) { |
739 case Token::ADD: // fall through. | 742 case Token::ADD: // fall through. |
740 case Token::SUB: // fall through. | 743 case Token::SUB: // fall through. |
741 case Token::MUL: | 744 case Token::MUL: |
742 case Token::DIV: | 745 case Token::DIV: |
(...skipping 18 matching lines...) Expand all Loading... | |
761 break; | 764 break; |
762 | 765 |
763 default: | 766 default: |
764 // Other cases should have been handled before this point. | 767 // Other cases should have been handled before this point. |
765 UNREACHABLE(); | 768 UNREACHABLE(); |
766 break; | 769 break; |
767 } | 770 } |
768 } | 771 } |
769 | 772 |
770 | 773 |
774 void CodeGenerator::VirtualFrameBinaryOperation(Token::Value op, | |
775 OverwriteMode overwrite_mode, | |
776 int constant_rhs) { | |
777 // top of virtual frame: y | |
778 // 2nd elt. on virtual frame : x | |
779 // result : top of virtual frame | |
780 | |
781 // Stub is entered with a call: 'return address' is in lr. | |
782 switch (op) { | |
783 case Token::ADD: // fall through. | |
Søren Thygesen Gjesse
2010/04/07 10:46:51
Either repeat this "fall through" comment all the
Erik Corry
2010/04/07 12:49:17
Removed.
| |
784 case Token::SUB: // fall through. | |
785 case Token::MUL: | |
786 case Token::DIV: | |
787 case Token::MOD: | |
788 case Token::BIT_OR: | |
789 case Token::BIT_AND: | |
790 case Token::BIT_XOR: | |
791 case Token::SHL: | |
792 case Token::SHR: | |
793 case Token::SAR: { | |
794 frame_->PopToR1R0(); // Pop y to r0 and x to r1. | |
795 { | |
796 VirtualFrame::SpilledScope spilled_scope(frame_); | |
797 GenericBinaryOpStub stub(op, overwrite_mode, constant_rhs); | |
798 frame_->CallStub(&stub, 0); | |
799 } | |
800 frame_->EmitPush(r0); | |
801 break; | |
802 } | |
803 | |
804 case Token::COMMA: { | |
Søren Thygesen Gjesse
2010/04/07 10:46:51
Am I missing something here, or shouldn't we make
Erik Corry
2010/04/07 12:49:17
Yes we should. I can't imagine that the , operato
| |
805 Register scratch = VirtualFrame::scratch0(); | |
806 frame_->EmitPop(scratch); | |
807 // simply discard left value | |
Kasper Lund
2010/04/07 08:09:50
// Simply discard left value.
Erik Corry
2010/04/07 12:49:17
Done.
| |
808 frame_->Drop(); | |
809 frame_->EmitPush(scratch); | |
810 break; | |
811 } | |
812 | |
813 default: | |
814 // Other cases should have been handled before this point. | |
815 UNREACHABLE(); | |
816 break; | |
817 } | |
818 } | |
819 | |
820 | |
771 class DeferredInlineSmiOperation: public DeferredCode { | 821 class DeferredInlineSmiOperation: public DeferredCode { |
772 public: | 822 public: |
773 DeferredInlineSmiOperation(Token::Value op, | 823 DeferredInlineSmiOperation(Token::Value op, |
774 int value, | 824 int value, |
775 bool reversed, | 825 bool reversed, |
776 OverwriteMode overwrite_mode) | 826 OverwriteMode overwrite_mode, |
827 Register tos = r0) | |
Kasper Lund
2010/04/07 08:09:50
I would try to avoid these default arguments. Mayb
Erik Corry
2010/04/07 12:49:17
Default argument removed.
| |
777 : op_(op), | 828 : op_(op), |
778 value_(value), | 829 value_(value), |
779 reversed_(reversed), | 830 reversed_(reversed), |
780 overwrite_mode_(overwrite_mode) { | 831 overwrite_mode_(overwrite_mode), |
832 tos_register_(tos) { | |
781 set_comment("[ DeferredInlinedSmiOperation"); | 833 set_comment("[ DeferredInlinedSmiOperation"); |
782 } | 834 } |
783 | 835 |
784 virtual void Generate(); | 836 virtual void Generate(); |
785 | 837 |
786 private: | 838 private: |
787 Token::Value op_; | 839 Token::Value op_; |
788 int value_; | 840 int value_; |
789 bool reversed_; | 841 bool reversed_; |
790 OverwriteMode overwrite_mode_; | 842 OverwriteMode overwrite_mode_; |
843 Register tos_register_; | |
791 }; | 844 }; |
792 | 845 |
793 | 846 |
794 void DeferredInlineSmiOperation::Generate() { | 847 void DeferredInlineSmiOperation::Generate() { |
795 switch (op_) { | 848 switch (op_) { |
796 case Token::ADD: { | 849 case Token::ADD: { |
797 // Revert optimistic add. | 850 // Revert optimistic add. |
798 if (reversed_) { | 851 if (reversed_) { |
799 __ sub(r0, r0, Operand(Smi::FromInt(value_))); | 852 __ sub(r0, tos_register_, Operand(Smi::FromInt(value_))); |
800 __ mov(r1, Operand(Smi::FromInt(value_))); | 853 __ mov(r1, Operand(Smi::FromInt(value_))); |
801 } else { | 854 } else { |
802 __ sub(r1, r0, Operand(Smi::FromInt(value_))); | 855 __ sub(r1, tos_register_, Operand(Smi::FromInt(value_))); |
803 __ mov(r0, Operand(Smi::FromInt(value_))); | 856 __ mov(r0, Operand(Smi::FromInt(value_))); |
804 } | 857 } |
805 break; | 858 break; |
806 } | 859 } |
807 | 860 |
808 case Token::SUB: { | 861 case Token::SUB: { |
809 // Revert optimistic sub. | 862 // Revert optimistic sub. |
810 if (reversed_) { | 863 if (reversed_) { |
811 __ rsb(r0, r0, Operand(Smi::FromInt(value_))); | 864 __ rsb(r0, tos_register_, Operand(Smi::FromInt(value_))); |
812 __ mov(r1, Operand(Smi::FromInt(value_))); | 865 __ mov(r1, Operand(Smi::FromInt(value_))); |
813 } else { | 866 } else { |
814 __ add(r1, r0, Operand(Smi::FromInt(value_))); | 867 __ add(r1, tos_register_, Operand(Smi::FromInt(value_))); |
815 __ mov(r0, Operand(Smi::FromInt(value_))); | 868 __ mov(r0, Operand(Smi::FromInt(value_))); |
816 } | 869 } |
817 break; | 870 break; |
818 } | 871 } |
819 | 872 |
820 // For these operations there is no optimistic operation that needs to be | 873 // For these operations there is no optimistic operation that needs to be |
821 // reverted. | 874 // reverted. |
822 case Token::MUL: | 875 case Token::MUL: |
823 case Token::MOD: | 876 case Token::MOD: |
824 case Token::BIT_OR: | 877 case Token::BIT_OR: |
825 case Token::BIT_XOR: | 878 case Token::BIT_XOR: |
826 case Token::BIT_AND: { | 879 case Token::BIT_AND: { |
827 if (reversed_) { | 880 if (reversed_) { |
881 if (!tos_register_.is(r0)) { | |
Kasper Lund
2010/04/07 08:09:50
How about adding a special Move macro to the macro
Erik Corry
2010/04/07 12:49:17
Done. That was a nice cleanup in unrelated code t
| |
882 __ mov(r0, Operand(tos_register_)); | |
883 } | |
828 __ mov(r1, Operand(Smi::FromInt(value_))); | 884 __ mov(r1, Operand(Smi::FromInt(value_))); |
829 } else { | 885 } else { |
830 __ mov(r1, Operand(r0)); | 886 if (!tos_register_.is(r1)) { |
887 __ mov(r1, Operand(tos_register_)); | |
888 } | |
831 __ mov(r0, Operand(Smi::FromInt(value_))); | 889 __ mov(r0, Operand(Smi::FromInt(value_))); |
832 } | 890 } |
833 break; | 891 break; |
834 } | 892 } |
835 | 893 |
836 case Token::SHL: | 894 case Token::SHL: |
837 case Token::SHR: | 895 case Token::SHR: |
838 case Token::SAR: { | 896 case Token::SAR: { |
839 if (!reversed_) { | 897 if (!reversed_) { |
840 __ mov(r1, Operand(r0)); | 898 if (!tos_register_.is(r1)) { |
899 __ mov(r1, Operand(tos_register_)); | |
900 } | |
841 __ mov(r0, Operand(Smi::FromInt(value_))); | 901 __ mov(r0, Operand(Smi::FromInt(value_))); |
842 } else { | 902 } else { |
843 UNREACHABLE(); // Should have been handled in SmiOperation. | 903 UNREACHABLE(); // Should have been handled in SmiOperation. |
844 } | 904 } |
845 break; | 905 break; |
846 } | 906 } |
847 | 907 |
848 default: | 908 default: |
849 // Other cases should have been handled before this point. | 909 // Other cases should have been handled before this point. |
850 UNREACHABLE(); | 910 UNREACHABLE(); |
851 break; | 911 break; |
852 } | 912 } |
853 | 913 |
854 GenericBinaryOpStub stub(op_, overwrite_mode_, value_); | 914 GenericBinaryOpStub stub(op_, overwrite_mode_, value_); |
855 __ CallStub(&stub); | 915 __ CallStub(&stub); |
916 // The generic stub returns its value in r0, but that's not | |
917 // necessarily what we want. We want whatever the inlined code | |
918 // expected, which is that the answer is in the same register as | |
919 // the operand was. | |
920 if (!tos_register_.is(r0)) { | |
921 __ mov(tos_register_, Operand(r0)); | |
922 } | |
856 } | 923 } |
857 | 924 |
858 | 925 |
859 static bool PopCountLessThanEqual2(unsigned int x) { | 926 static bool PopCountLessThanEqual2(unsigned int x) { |
860 x &= x - 1; | 927 x &= x - 1; |
861 return (x & (x - 1)) == 0; | 928 return (x & (x - 1)) == 0; |
862 } | 929 } |
863 | 930 |
864 | 931 |
865 // Returns the index of the lowest bit set. | 932 // Returns the index of the lowest bit set. |
866 static int BitPosition(unsigned x) { | 933 static int BitPosition(unsigned x) { |
867 int bit_posn = 0; | 934 int bit_posn = 0; |
868 while ((x & 0xf) == 0) { | 935 while ((x & 0xf) == 0) { |
869 bit_posn += 4; | 936 bit_posn += 4; |
870 x >>= 4; | 937 x >>= 4; |
871 } | 938 } |
872 while ((x & 1) == 0) { | 939 while ((x & 1) == 0) { |
873 bit_posn++; | 940 bit_posn++; |
874 x >>= 1; | 941 x >>= 1; |
875 } | 942 } |
876 return bit_posn; | 943 return bit_posn; |
877 } | 944 } |
878 | 945 |
879 | 946 |
947 void CodeGenerator::VirtualFrameSmiOperation(Token::Value op, | |
948 Handle<Object> value, | |
949 bool reversed, | |
950 OverwriteMode mode) { | |
951 int int_value = Smi::cast(*value)->value(); | |
952 | |
953 bool something_to_inline; | |
954 switch (op) { | |
955 case Token::ADD: | |
956 case Token::SUB: | |
957 case Token::BIT_AND: | |
958 case Token::BIT_OR: | |
959 case Token::BIT_XOR: { | |
960 something_to_inline = true; | |
961 break; | |
962 } | |
963 case Token::SHL: | |
964 case Token::SHR: | |
965 case Token::SAR: { | |
966 if (reversed) { | |
967 something_to_inline = false; | |
968 } else { | |
969 something_to_inline = true; | |
970 } | |
971 break; | |
972 } | |
973 case Token::MOD: { | |
974 if (reversed || int_value < 2 || !IsPowerOf2(int_value)) { | |
975 something_to_inline = false; | |
976 } else { | |
977 something_to_inline = true; | |
978 } | |
979 break; | |
980 } | |
981 case Token::MUL: { | |
982 if (!IsEasyToMultiplyBy(int_value)) { | |
983 something_to_inline = false; | |
984 } else { | |
985 something_to_inline = true; | |
986 } | |
987 break; | |
988 } | |
989 default: { | |
990 something_to_inline = false; | |
991 break; | |
992 } | |
993 } | |
994 | |
995 if (!something_to_inline) { | |
996 if (!reversed) { | |
997 // Move the lhs to r1. | |
998 frame_->PopToR1(); | |
999 // Flush any other registers to the stack. | |
1000 frame_->SpillAll(); | |
1001 // Tell the virtual frame that TOS is in r1 (no code emitted). | |
1002 frame_->EmitPush(r1); | |
1003 // We know that r0 is free. | |
1004 __ mov(r0, Operand(value)); | |
1005 // Push r0 on the virtual frame (no code emitted). | |
1006 frame_->EmitPush(r0); | |
1007 // This likes having r1 and r0 on top of the stack. It pushes | |
1008 // the answer on the virtual frame. | |
1009 VirtualFrameBinaryOperation(op, mode, int_value); | |
1010 } else { | |
1011 // Move the rhs to r0. | |
1012 frame_->PopToR0(); | |
1013 // Flush any other registers to the stack. | |
1014 frame_->SpillAll(); | |
1015 // We know that r1 is free. | |
1016 __ mov(r1, Operand(value)); | |
1017 // Tell the virtual frame that TOS is in r1 (no code emitted). | |
1018 frame_->EmitPush(r1); | |
1019 // Push r0 on the virtual frame (no code emitted). | |
1020 frame_->EmitPush(r0); | |
1021 // This likes having r1 and r0 on top of the stack. It pushes | |
1022 // the answer on the virtual frame. | |
1023 VirtualFrameBinaryOperation(op, mode, kUnknownIntValue); | |
1024 } | |
1025 return; | |
1026 } | |
1027 | |
1028 | |
Kasper Lund
2010/04/07 08:09:50
Too much whitespace.
Erik Corry
2010/04/07 12:49:17
Done.
| |
1029 // We move the top of stack to a register (normally no move is invoved). | |
1030 Register tos = frame_->PopToRegister(); | |
1031 // All other registers are spilled. The deferred code expects one argument | |
1032 // in a register and all other values are flushed to the stack. The | |
1033 // answer is returned in the same register that the top of stack argument was | |
1034 // in. | |
1035 frame_->SpillAll(); | |
1036 | |
1037 switch (op) { | |
1038 case Token::ADD: { | |
1039 DeferredCode* deferred = | |
1040 new DeferredInlineSmiOperation(op, int_value, reversed, mode, tos); | |
1041 | |
1042 __ add(tos, tos, Operand(value), SetCC); | |
1043 deferred->Branch(vs); | |
1044 __ tst(tos, Operand(kSmiTagMask)); | |
1045 deferred->Branch(ne); | |
1046 deferred->BindExit(); | |
1047 frame_->EmitPush(tos); | |
1048 break; | |
1049 } | |
1050 | |
1051 case Token::SUB: { | |
1052 DeferredCode* deferred = | |
1053 new DeferredInlineSmiOperation(op, int_value, reversed, mode, tos); | |
1054 | |
1055 if (reversed) { | |
1056 __ rsb(tos, tos, Operand(value), SetCC); | |
1057 } else { | |
1058 __ sub(tos, tos, Operand(value), SetCC); | |
1059 } | |
1060 deferred->Branch(vs); | |
1061 __ tst(tos, Operand(kSmiTagMask)); | |
1062 deferred->Branch(ne); | |
1063 deferred->BindExit(); | |
1064 frame_->EmitPush(tos); | |
1065 break; | |
1066 } | |
1067 | |
1068 | |
1069 case Token::BIT_OR: | |
1070 case Token::BIT_XOR: | |
1071 case Token::BIT_AND: { | |
1072 DeferredCode* deferred = | |
1073 new DeferredInlineSmiOperation(op, int_value, reversed, mode, tos); | |
1074 __ tst(tos, Operand(kSmiTagMask)); | |
1075 deferred->Branch(ne); | |
1076 switch (op) { | |
1077 case Token::BIT_OR: __ orr(tos, tos, Operand(value)); break; | |
1078 case Token::BIT_XOR: __ eor(tos, tos, Operand(value)); break; | |
1079 case Token::BIT_AND: __ and_(tos, tos, Operand(value)); break; | |
1080 default: UNREACHABLE(); | |
1081 } | |
1082 deferred->BindExit(); | |
1083 frame_->EmitPush(tos); | |
1084 break; | |
1085 } | |
1086 | |
1087 case Token::SHL: | |
1088 case Token::SHR: | |
1089 case Token::SAR: { | |
1090 ASSERT(!reversed); | |
1091 int shift_value = int_value & 0x1f; // least significant 5 bits | |
1092 DeferredCode* deferred = | |
1093 new DeferredInlineSmiOperation(op, shift_value, false, mode, tos); | |
1094 __ tst(tos, Operand(kSmiTagMask)); | |
1095 deferred->Branch(ne); | |
Søren Thygesen Gjesse
2010/04/07 10:46:51
Wouldn't it be better to use VirtualFrame::scratch
Erik Corry
2010/04/07 12:49:17
Done.
| |
1096 __ mov(r2, Operand(tos, ASR, kSmiTagSize)); // remove tags | |
1097 switch (op) { | |
1098 case Token::SHL: { | |
1099 if (shift_value != 0) { | |
1100 __ mov(r2, Operand(r2, LSL, shift_value)); | |
1101 } | |
1102 // check that the *unsigned* result fits in a smi | |
1103 __ add(r3, r2, Operand(0x40000000), SetCC); | |
1104 deferred->Branch(mi); | |
1105 break; | |
1106 } | |
1107 case Token::SHR: { | |
1108 // LSR by immediate 0 means shifting 32 bits. | |
1109 if (shift_value != 0) { | |
1110 __ mov(r2, Operand(r2, LSR, shift_value)); | |
1111 } | |
1112 // check that the *unsigned* result fits in a smi | |
1113 // neither of the two high-order bits can be set: | |
1114 // - 0x80000000: high bit would be lost when smi tagging | |
1115 // - 0x40000000: this number would convert to negative when | |
1116 // smi tagging these two cases can only happen with shifts | |
1117 // by 0 or 1 when handed a valid smi | |
1118 __ and_(r3, r2, Operand(0xc0000000), SetCC); | |
1119 deferred->Branch(ne); | |
1120 break; | |
1121 } | |
1122 case Token::SAR: { | |
1123 if (shift_value != 0) { | |
1124 // ASR by immediate 0 means shifting 32 bits. | |
1125 __ mov(r2, Operand(r2, ASR, shift_value)); | |
1126 } | |
1127 break; | |
1128 } | |
1129 default: UNREACHABLE(); | |
1130 } | |
1131 __ mov(tos, Operand(r2, LSL, kSmiTagSize)); | |
1132 deferred->BindExit(); | |
1133 frame_->EmitPush(tos); | |
1134 break; | |
1135 } | |
1136 | |
1137 case Token::MOD: { | |
1138 ASSERT(!reversed); | |
1139 ASSERT(int_value >= 2); | |
1140 ASSERT(IsPowerOf2(int_value)); | |
1141 DeferredCode* deferred = | |
1142 new DeferredInlineSmiOperation(op, int_value, reversed, mode, tos); | |
1143 unsigned mask = (0x80000000u | kSmiTagMask); | |
1144 __ tst(tos, Operand(mask)); | |
1145 deferred->Branch(ne); // Go to deferred code on non-Smis and negative. | |
1146 mask = (int_value << kSmiTagSize) - 1; | |
1147 __ and_(tos, tos, Operand(mask)); | |
1148 deferred->BindExit(); | |
1149 frame_->EmitPush(tos); | |
1150 break; | |
1151 } | |
1152 | |
1153 case Token::MUL: { | |
1154 ASSERT(IsEasyToMultiplyBy(int_value)); | |
1155 DeferredCode* deferred = | |
1156 new DeferredInlineSmiOperation(op, int_value, reversed, mode, tos); | |
1157 unsigned max_smi_that_wont_overflow = Smi::kMaxValue / int_value; | |
1158 max_smi_that_wont_overflow <<= kSmiTagSize; | |
1159 unsigned mask = 0x80000000u; | |
1160 while ((mask & max_smi_that_wont_overflow) == 0) { | |
1161 mask |= mask >> 1; | |
1162 } | |
1163 mask |= kSmiTagMask; | |
1164 // This does a single mask that checks for a too high value in a | |
1165 // conservative way and for a non-Smi. It also filters out negative | |
1166 // numbers, unfortunately, but since this code is inline we prefer | |
1167 // brevity to comprehensiveness. | |
1168 __ tst(tos, Operand(mask)); | |
1169 deferred->Branch(ne); | |
1170 MultiplyByKnownInt(masm_, tos, tos, int_value); | |
1171 deferred->BindExit(); | |
1172 frame_->EmitPush(tos); | |
1173 break; | |
1174 } | |
1175 | |
1176 default: | |
1177 UNREACHABLE(); | |
1178 break; | |
1179 } | |
1180 } | |
1181 | |
1182 | |
880 void CodeGenerator::SmiOperation(Token::Value op, | 1183 void CodeGenerator::SmiOperation(Token::Value op, |
881 Handle<Object> value, | 1184 Handle<Object> value, |
882 bool reversed, | 1185 bool reversed, |
883 OverwriteMode mode) { | 1186 OverwriteMode mode) { |
884 VirtualFrame::SpilledScope spilled_scope; | 1187 VirtualFrame::SpilledScope spilled_scope(frame_); |
885 // NOTE: This is an attempt to inline (a bit) more of the code for | 1188 // NOTE: This is an attempt to inline (a bit) more of the code for |
886 // some possible smi operations (like + and -) when (at least) one | 1189 // some possible smi operations (like + and -) when (at least) one |
887 // of the operands is a literal smi. With this optimization, the | 1190 // of the operands is a literal smi. With this optimization, the |
888 // performance of the system is increased by ~15%, and the generated | 1191 // performance of the system is increased by ~15%, and the generated |
889 // code size is increased by ~1% (measured on a combination of | 1192 // code size is increased by ~1% (measured on a combination of |
890 // different benchmarks). | 1193 // different benchmarks). |
891 | 1194 |
892 // sp[0] : operand | 1195 // sp[0] : operand |
893 | 1196 |
894 int int_value = Smi::cast(*value)->value(); | 1197 int int_value = Smi::cast(*value)->value(); |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1057 } | 1360 } |
1058 | 1361 |
1059 exit.Bind(); | 1362 exit.Bind(); |
1060 } | 1363 } |
1061 | 1364 |
1062 | 1365 |
1063 void CodeGenerator::Comparison(Condition cc, | 1366 void CodeGenerator::Comparison(Condition cc, |
1064 Expression* left, | 1367 Expression* left, |
1065 Expression* right, | 1368 Expression* right, |
1066 bool strict) { | 1369 bool strict) { |
1067 if (left != NULL) LoadAndSpill(left); | 1370 VirtualFrame::RegisterAllocationScope scope(this); |
1068 if (right != NULL) LoadAndSpill(right); | |
1069 | 1371 |
1070 VirtualFrame::SpilledScope spilled_scope; | 1372 if (left != NULL) Load(left); |
1373 if (right != NULL) Load(right); | |
1374 | |
1071 // sp[0] : y | 1375 // sp[0] : y |
1072 // sp[1] : x | 1376 // sp[1] : x |
1073 // result : cc register | 1377 // result : cc register |
1074 | 1378 |
1075 // Strict only makes sense for equality comparisons. | 1379 // Strict only makes sense for equality comparisons. |
1076 ASSERT(!strict || cc == eq); | 1380 ASSERT(!strict || cc == eq); |
1077 | 1381 |
1078 JumpTarget exit; | 1382 Register lhs; |
1079 JumpTarget smi; | 1383 Register rhs; |
1384 | |
1385 // We load the top two stack positions into registers chosen by the virtual | |
1386 // frame. This should keep the register shuffling to a minimum. | |
1080 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. | 1387 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. |
1081 if (cc == gt || cc == le) { | 1388 if (cc == gt || cc == le) { |
1082 cc = ReverseCondition(cc); | 1389 cc = ReverseCondition(cc); |
1083 frame_->EmitPop(r1); | 1390 lhs = frame_->PopToRegister(); |
1084 frame_->EmitPop(r0); | 1391 rhs = frame_->PopToRegister(lhs); // Don't pop to the same register again! |
1085 } else { | 1392 } else { |
1086 frame_->EmitPop(r0); | 1393 rhs = frame_->PopToRegister(); |
1087 frame_->EmitPop(r1); | 1394 lhs = frame_->PopToRegister(rhs); // Don't pop to the same register again! |
1088 } | 1395 } |
1089 __ orr(r2, r0, Operand(r1)); | 1396 |
1397 ASSERT(rhs.is(r0) || rhs.is(r1)); | |
1398 ASSERT(lhs.is(r0) || lhs.is(r1)); | |
1399 | |
1400 // Now we have the two sides in r0 and r1. We flush any other registers | |
1401 // because the stub doesn't know about register allocation. | |
1402 frame_->SpillAll(); | |
1403 __ orr(r2, lhs, Operand(rhs)); | |
Søren Thygesen Gjesse
2010/04/07 10:46:51
VirtualFrame::scratchX()?
Erik Corry
2010/04/07 12:49:17
Done.
| |
1090 __ tst(r2, Operand(kSmiTagMask)); | 1404 __ tst(r2, Operand(kSmiTagMask)); |
1405 JumpTarget smi; | |
1091 smi.Branch(eq); | 1406 smi.Branch(eq); |
1092 | 1407 |
1093 // Perform non-smi comparison by stub. | 1408 // Perform non-smi comparison by stub. |
1094 // CompareStub takes arguments in r0 and r1, returns <0, >0 or 0 in r0. | 1409 // CompareStub takes arguments in r0 and r1, returns <0, >0 or 0 in r0. |
1095 // We call with 0 args because there are 0 on the stack. | 1410 // We call with 0 args because there are 0 on the stack. |
1411 if (!rhs.is(r0)) { | |
Søren Thygesen Gjesse
2010/04/07 07:53:37
Should this be MacroAssembler::Swap?
Erik Corry
2010/04/07 12:49:17
Done.
| |
1412 __ eor(rhs, rhs, Operand(lhs)); | |
Kasper Lund
2010/04/07 08:09:50
Add macro SwapRegisters or at least a comment here
Erik Corry
2010/04/07 12:49:17
Done.
| |
1413 __ eor(lhs, lhs, Operand(rhs)); | |
1414 __ eor(rhs, rhs, Operand(lhs)); | |
1415 } | |
1416 | |
1096 CompareStub stub(cc, strict); | 1417 CompareStub stub(cc, strict); |
1097 frame_->CallStub(&stub, 0); | 1418 frame_->CallStub(&stub, 0); |
1098 __ cmp(r0, Operand(0)); | 1419 __ cmp(r0, Operand(0)); |
1420 JumpTarget exit; | |
1099 exit.Jump(); | 1421 exit.Jump(); |
1100 | 1422 |
1101 // Do smi comparisons by pointer comparison. | 1423 // Do smi comparisons by pointer comparison. |
1102 smi.Bind(); | 1424 smi.Bind(); |
1103 __ cmp(r1, Operand(r0)); | 1425 __ cmp(lhs, Operand(rhs)); |
1104 | 1426 |
1105 exit.Bind(); | 1427 exit.Bind(); |
1106 cc_reg_ = cc; | 1428 cc_reg_ = cc; |
1107 } | 1429 } |
1108 | 1430 |
1109 | 1431 |
1110 // Call the function on the stack with the given arguments. | 1432 // Call the function on the stack with the given arguments. |
1111 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, | 1433 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, |
1112 CallFunctionFlags flags, | 1434 CallFunctionFlags flags, |
1113 int position) { | 1435 int position) { |
1114 VirtualFrame::SpilledScope spilled_scope; | 1436 VirtualFrame::SpilledScope spilled_scope(frame_); |
1115 // Push the arguments ("left-to-right") on the stack. | 1437 // Push the arguments ("left-to-right") on the stack. |
1116 int arg_count = args->length(); | 1438 int arg_count = args->length(); |
1117 for (int i = 0; i < arg_count; i++) { | 1439 for (int i = 0; i < arg_count; i++) { |
1118 LoadAndSpill(args->at(i)); | 1440 LoadAndSpill(args->at(i)); |
1119 } | 1441 } |
1120 | 1442 |
1121 // Record the position for debugging purposes. | 1443 // Record the position for debugging purposes. |
1122 CodeForSourcePosition(position); | 1444 CodeForSourcePosition(position); |
1123 | 1445 |
1124 // Use the shared code stub to call the function. | 1446 // Use the shared code stub to call the function. |
1125 InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP; | 1447 InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP; |
1126 CallFunctionStub call_function(arg_count, in_loop, flags); | 1448 CallFunctionStub call_function(arg_count, in_loop, flags); |
1127 frame_->CallStub(&call_function, arg_count + 1); | 1449 frame_->CallStub(&call_function, arg_count + 1); |
1128 | 1450 |
1129 // Restore context and pop function from the stack. | 1451 // Restore context and pop function from the stack. |
1130 __ ldr(cp, frame_->Context()); | 1452 __ ldr(cp, frame_->Context()); |
1131 frame_->Drop(); // discard the TOS | 1453 frame_->Drop(); // discard the TOS |
1132 } | 1454 } |
1133 | 1455 |
1134 | 1456 |
1135 void CodeGenerator::Branch(bool if_true, JumpTarget* target) { | 1457 void CodeGenerator::Branch(bool if_true, JumpTarget* target) { |
1136 VirtualFrame::SpilledScope spilled_scope; | 1458 VirtualFrame::SpilledScope spilled_scope(frame_); |
1137 ASSERT(has_cc()); | 1459 ASSERT(has_cc()); |
1138 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_); | 1460 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_); |
1139 target->Branch(cc); | 1461 target->Branch(cc); |
1140 cc_reg_ = al; | 1462 cc_reg_ = al; |
1141 } | 1463 } |
1142 | 1464 |
1143 | 1465 |
1144 void CodeGenerator::CheckStack() { | 1466 void CodeGenerator::CheckStack() { |
1145 VirtualFrame::SpilledScope spilled_scope; | 1467 VirtualFrame::SpilledScope spilled_scope(frame_); |
1146 Comment cmnt(masm_, "[ check stack"); | 1468 Comment cmnt(masm_, "[ check stack"); |
1147 __ LoadRoot(ip, Heap::kStackLimitRootIndex); | 1469 __ LoadRoot(ip, Heap::kStackLimitRootIndex); |
1148 // Put the lr setup instruction in the delay slot. kInstrSize is added to | 1470 // Put the lr setup instruction in the delay slot. kInstrSize is added to |
1149 // the implicit 8 byte offset that always applies to operations with pc and | 1471 // the implicit 8 byte offset that always applies to operations with pc and |
1150 // gives a return address 12 bytes down. | 1472 // gives a return address 12 bytes down. |
1151 masm_->add(lr, pc, Operand(Assembler::kInstrSize)); | 1473 masm_->add(lr, pc, Operand(Assembler::kInstrSize)); |
1152 masm_->cmp(sp, Operand(ip)); | 1474 masm_->cmp(sp, Operand(ip)); |
1153 StackCheckStub stub; | 1475 StackCheckStub stub; |
1154 // Call the stub if lower. | 1476 // Call the stub if lower. |
1155 masm_->mov(pc, | 1477 masm_->mov(pc, |
1156 Operand(reinterpret_cast<intptr_t>(stub.GetCode().location()), | 1478 Operand(reinterpret_cast<intptr_t>(stub.GetCode().location()), |
1157 RelocInfo::CODE_TARGET), | 1479 RelocInfo::CODE_TARGET), |
1158 LeaveCC, | 1480 LeaveCC, |
1159 lo); | 1481 lo); |
1160 } | 1482 } |
1161 | 1483 |
1162 | 1484 |
1163 void CodeGenerator::VisitStatements(ZoneList<Statement*>* statements) { | 1485 void CodeGenerator::VisitStatements(ZoneList<Statement*>* statements) { |
1164 #ifdef DEBUG | 1486 #ifdef DEBUG |
1165 int original_height = frame_->height(); | 1487 int original_height = frame_->height(); |
1166 #endif | 1488 #endif |
1167 VirtualFrame::SpilledScope spilled_scope; | 1489 VirtualFrame::SpilledScope spilled_scope(frame_); |
1168 for (int i = 0; frame_ != NULL && i < statements->length(); i++) { | 1490 for (int i = 0; frame_ != NULL && i < statements->length(); i++) { |
1169 VisitAndSpill(statements->at(i)); | 1491 VisitAndSpill(statements->at(i)); |
1170 } | 1492 } |
1171 ASSERT(!has_valid_frame() || frame_->height() == original_height); | 1493 ASSERT(!has_valid_frame() || frame_->height() == original_height); |
1172 } | 1494 } |
1173 | 1495 |
1174 | 1496 |
1175 void CodeGenerator::VisitBlock(Block* node) { | 1497 void CodeGenerator::VisitBlock(Block* node) { |
1176 #ifdef DEBUG | 1498 #ifdef DEBUG |
1177 int original_height = frame_->height(); | 1499 int original_height = frame_->height(); |
1178 #endif | 1500 #endif |
1179 VirtualFrame::SpilledScope spilled_scope; | 1501 VirtualFrame::SpilledScope spilled_scope(frame_); |
1180 Comment cmnt(masm_, "[ Block"); | 1502 Comment cmnt(masm_, "[ Block"); |
1181 CodeForStatementPosition(node); | 1503 CodeForStatementPosition(node); |
1182 node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); | 1504 node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); |
1183 VisitStatementsAndSpill(node->statements()); | 1505 VisitStatementsAndSpill(node->statements()); |
1184 if (node->break_target()->is_linked()) { | 1506 if (node->break_target()->is_linked()) { |
1185 node->break_target()->Bind(); | 1507 node->break_target()->Bind(); |
1186 } | 1508 } |
1187 node->break_target()->Unuse(); | 1509 node->break_target()->Unuse(); |
1188 ASSERT(!has_valid_frame() || frame_->height() == original_height); | 1510 ASSERT(!has_valid_frame() || frame_->height() == original_height); |
1189 } | 1511 } |
1190 | 1512 |
1191 | 1513 |
1192 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 1514 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
1193 VirtualFrame::SpilledScope spilled_scope; | 1515 VirtualFrame::SpilledScope spilled_scope(frame_); |
1194 frame_->EmitPush(cp); | 1516 frame_->EmitPush(cp); |
1195 __ mov(r0, Operand(pairs)); | 1517 __ mov(r0, Operand(pairs)); |
1196 frame_->EmitPush(r0); | 1518 frame_->EmitPush(r0); |
1197 __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0))); | 1519 __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0))); |
1198 frame_->EmitPush(r0); | 1520 frame_->EmitPush(r0); |
1199 frame_->CallRuntime(Runtime::kDeclareGlobals, 3); | 1521 frame_->CallRuntime(Runtime::kDeclareGlobals, 3); |
1200 // The result is discarded. | 1522 // The result is discarded. |
1201 } | 1523 } |
1202 | 1524 |
1203 | 1525 |
1204 void CodeGenerator::VisitDeclaration(Declaration* node) { | 1526 void CodeGenerator::VisitDeclaration(Declaration* node) { |
1205 #ifdef DEBUG | 1527 #ifdef DEBUG |
1206 int original_height = frame_->height(); | 1528 int original_height = frame_->height(); |
1207 #endif | 1529 #endif |
1208 VirtualFrame::SpilledScope spilled_scope; | 1530 VirtualFrame::SpilledScope spilled_scope(frame_); |
1209 Comment cmnt(masm_, "[ Declaration"); | 1531 Comment cmnt(masm_, "[ Declaration"); |
1210 Variable* var = node->proxy()->var(); | 1532 Variable* var = node->proxy()->var(); |
1211 ASSERT(var != NULL); // must have been resolved | 1533 ASSERT(var != NULL); // must have been resolved |
1212 Slot* slot = var->slot(); | 1534 Slot* slot = var->slot(); |
1213 | 1535 |
1214 // If it was not possible to allocate the variable at compile time, | 1536 // If it was not possible to allocate the variable at compile time, |
1215 // we need to "declare" it at runtime to make sure it actually | 1537 // we need to "declare" it at runtime to make sure it actually |
1216 // exists in the local context. | 1538 // exists in the local context. |
1217 if (slot != NULL && slot->type() == Slot::LOOKUP) { | 1539 if (slot != NULL && slot->type() == Slot::LOOKUP) { |
1218 // Variables with a "LOOKUP" slot were introduced as non-locals | 1540 // Variables with a "LOOKUP" slot were introduced as non-locals |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1267 frame_->Drop(); | 1589 frame_->Drop(); |
1268 } | 1590 } |
1269 ASSERT(frame_->height() == original_height); | 1591 ASSERT(frame_->height() == original_height); |
1270 } | 1592 } |
1271 | 1593 |
1272 | 1594 |
1273 void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) { | 1595 void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) { |
1274 #ifdef DEBUG | 1596 #ifdef DEBUG |
1275 int original_height = frame_->height(); | 1597 int original_height = frame_->height(); |
1276 #endif | 1598 #endif |
1277 VirtualFrame::SpilledScope spilled_scope; | 1599 VirtualFrame::SpilledScope spilled_scope(frame_); |
1278 Comment cmnt(masm_, "[ ExpressionStatement"); | 1600 Comment cmnt(masm_, "[ ExpressionStatement"); |
1279 CodeForStatementPosition(node); | 1601 CodeForStatementPosition(node); |
1280 Expression* expression = node->expression(); | 1602 Expression* expression = node->expression(); |
1281 expression->MarkAsStatement(); | 1603 expression->MarkAsStatement(); |
1282 LoadAndSpill(expression); | 1604 LoadAndSpill(expression); |
1283 frame_->Drop(); | 1605 frame_->Drop(); |
1284 ASSERT(frame_->height() == original_height); | 1606 ASSERT(frame_->height() == original_height); |
1285 } | 1607 } |
1286 | 1608 |
1287 | 1609 |
1288 void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) { | 1610 void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) { |
1289 #ifdef DEBUG | 1611 #ifdef DEBUG |
1290 int original_height = frame_->height(); | 1612 int original_height = frame_->height(); |
1291 #endif | 1613 #endif |
1292 VirtualFrame::SpilledScope spilled_scope; | 1614 VirtualFrame::SpilledScope spilled_scope(frame_); |
1293 Comment cmnt(masm_, "// EmptyStatement"); | 1615 Comment cmnt(masm_, "// EmptyStatement"); |
1294 CodeForStatementPosition(node); | 1616 CodeForStatementPosition(node); |
1295 // nothing to do | 1617 // nothing to do |
1296 ASSERT(frame_->height() == original_height); | 1618 ASSERT(frame_->height() == original_height); |
1297 } | 1619 } |
1298 | 1620 |
1299 | 1621 |
1300 void CodeGenerator::VisitIfStatement(IfStatement* node) { | 1622 void CodeGenerator::VisitIfStatement(IfStatement* node) { |
1301 #ifdef DEBUG | 1623 #ifdef DEBUG |
1302 int original_height = frame_->height(); | 1624 int original_height = frame_->height(); |
1303 #endif | 1625 #endif |
1304 VirtualFrame::SpilledScope spilled_scope; | 1626 VirtualFrame::SpilledScope spilled_scope(frame_); |
1305 Comment cmnt(masm_, "[ IfStatement"); | 1627 Comment cmnt(masm_, "[ IfStatement"); |
1306 // Generate different code depending on which parts of the if statement | 1628 // Generate different code depending on which parts of the if statement |
1307 // are present or not. | 1629 // are present or not. |
1308 bool has_then_stm = node->HasThenStatement(); | 1630 bool has_then_stm = node->HasThenStatement(); |
1309 bool has_else_stm = node->HasElseStatement(); | 1631 bool has_else_stm = node->HasElseStatement(); |
1310 | 1632 |
1311 CodeForStatementPosition(node); | 1633 CodeForStatementPosition(node); |
1312 | 1634 |
1313 JumpTarget exit; | 1635 JumpTarget exit; |
1314 if (has_then_stm && has_else_stm) { | 1636 if (has_then_stm && has_else_stm) { |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1380 | 1702 |
1381 // end | 1703 // end |
1382 if (exit.is_linked()) { | 1704 if (exit.is_linked()) { |
1383 exit.Bind(); | 1705 exit.Bind(); |
1384 } | 1706 } |
1385 ASSERT(!has_valid_frame() || frame_->height() == original_height); | 1707 ASSERT(!has_valid_frame() || frame_->height() == original_height); |
1386 } | 1708 } |
1387 | 1709 |
1388 | 1710 |
1389 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) { | 1711 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) { |
1390 VirtualFrame::SpilledScope spilled_scope; | 1712 VirtualFrame::SpilledScope spilled_scope(frame_); |
1391 Comment cmnt(masm_, "[ ContinueStatement"); | 1713 Comment cmnt(masm_, "[ ContinueStatement"); |
1392 CodeForStatementPosition(node); | 1714 CodeForStatementPosition(node); |
1393 node->target()->continue_target()->Jump(); | 1715 node->target()->continue_target()->Jump(); |
1394 } | 1716 } |
1395 | 1717 |
1396 | 1718 |
1397 void CodeGenerator::VisitBreakStatement(BreakStatement* node) { | 1719 void CodeGenerator::VisitBreakStatement(BreakStatement* node) { |
1398 VirtualFrame::SpilledScope spilled_scope; | 1720 VirtualFrame::SpilledScope spilled_scope(frame_); |
1399 Comment cmnt(masm_, "[ BreakStatement"); | 1721 Comment cmnt(masm_, "[ BreakStatement"); |
1400 CodeForStatementPosition(node); | 1722 CodeForStatementPosition(node); |
1401 node->target()->break_target()->Jump(); | 1723 node->target()->break_target()->Jump(); |
1402 } | 1724 } |
1403 | 1725 |
1404 | 1726 |
1405 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { | 1727 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { |
1406 VirtualFrame::SpilledScope spilled_scope; | 1728 VirtualFrame::SpilledScope spilled_scope(frame_); |
1407 Comment cmnt(masm_, "[ ReturnStatement"); | 1729 Comment cmnt(masm_, "[ ReturnStatement"); |
1408 | 1730 |
1409 CodeForStatementPosition(node); | 1731 CodeForStatementPosition(node); |
1410 LoadAndSpill(node->expression()); | 1732 LoadAndSpill(node->expression()); |
1411 if (function_return_is_shadowed_) { | 1733 if (function_return_is_shadowed_) { |
1412 frame_->EmitPop(r0); | 1734 frame_->EmitPop(r0); |
1413 function_return_.Jump(); | 1735 function_return_.Jump(); |
1414 } else { | 1736 } else { |
1415 // Pop the result from the frame and prepare the frame for | 1737 // Pop the result from the frame and prepare the frame for |
1416 // returning thus making it easier to merge. | 1738 // returning thus making it easier to merge. |
1417 frame_->EmitPop(r0); | 1739 frame_->EmitPop(r0); |
1418 frame_->PrepareForReturn(); | 1740 frame_->PrepareForReturn(); |
1419 | 1741 |
1420 function_return_.Jump(); | 1742 function_return_.Jump(); |
1421 } | 1743 } |
1422 } | 1744 } |
1423 | 1745 |
1424 | 1746 |
1425 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { | 1747 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { |
1426 #ifdef DEBUG | 1748 #ifdef DEBUG |
1427 int original_height = frame_->height(); | 1749 int original_height = frame_->height(); |
1428 #endif | 1750 #endif |
1429 VirtualFrame::SpilledScope spilled_scope; | 1751 VirtualFrame::SpilledScope spilled_scope(frame_); |
1430 Comment cmnt(masm_, "[ WithEnterStatement"); | 1752 Comment cmnt(masm_, "[ WithEnterStatement"); |
1431 CodeForStatementPosition(node); | 1753 CodeForStatementPosition(node); |
1432 LoadAndSpill(node->expression()); | 1754 LoadAndSpill(node->expression()); |
1433 if (node->is_catch_block()) { | 1755 if (node->is_catch_block()) { |
1434 frame_->CallRuntime(Runtime::kPushCatchContext, 1); | 1756 frame_->CallRuntime(Runtime::kPushCatchContext, 1); |
1435 } else { | 1757 } else { |
1436 frame_->CallRuntime(Runtime::kPushContext, 1); | 1758 frame_->CallRuntime(Runtime::kPushContext, 1); |
1437 } | 1759 } |
1438 #ifdef DEBUG | 1760 #ifdef DEBUG |
1439 JumpTarget verified_true; | 1761 JumpTarget verified_true; |
1440 __ cmp(r0, Operand(cp)); | 1762 __ cmp(r0, Operand(cp)); |
1441 verified_true.Branch(eq); | 1763 verified_true.Branch(eq); |
1442 __ stop("PushContext: r0 is expected to be the same as cp"); | 1764 __ stop("PushContext: r0 is expected to be the same as cp"); |
1443 verified_true.Bind(); | 1765 verified_true.Bind(); |
1444 #endif | 1766 #endif |
1445 // Update context local. | 1767 // Update context local. |
1446 __ str(cp, frame_->Context()); | 1768 __ str(cp, frame_->Context()); |
1447 ASSERT(frame_->height() == original_height); | 1769 ASSERT(frame_->height() == original_height); |
1448 } | 1770 } |
1449 | 1771 |
1450 | 1772 |
1451 void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) { | 1773 void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) { |
1452 #ifdef DEBUG | 1774 #ifdef DEBUG |
1453 int original_height = frame_->height(); | 1775 int original_height = frame_->height(); |
1454 #endif | 1776 #endif |
1455 VirtualFrame::SpilledScope spilled_scope; | 1777 VirtualFrame::SpilledScope spilled_scope(frame_); |
1456 Comment cmnt(masm_, "[ WithExitStatement"); | 1778 Comment cmnt(masm_, "[ WithExitStatement"); |
1457 CodeForStatementPosition(node); | 1779 CodeForStatementPosition(node); |
1458 // Pop context. | 1780 // Pop context. |
1459 __ ldr(cp, ContextOperand(cp, Context::PREVIOUS_INDEX)); | 1781 __ ldr(cp, ContextOperand(cp, Context::PREVIOUS_INDEX)); |
1460 // Update context local. | 1782 // Update context local. |
1461 __ str(cp, frame_->Context()); | 1783 __ str(cp, frame_->Context()); |
1462 ASSERT(frame_->height() == original_height); | 1784 ASSERT(frame_->height() == original_height); |
1463 } | 1785 } |
1464 | 1786 |
1465 | 1787 |
1466 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { | 1788 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { |
1467 #ifdef DEBUG | 1789 #ifdef DEBUG |
1468 int original_height = frame_->height(); | 1790 int original_height = frame_->height(); |
1469 #endif | 1791 #endif |
1470 VirtualFrame::SpilledScope spilled_scope; | 1792 VirtualFrame::SpilledScope spilled_scope(frame_); |
1471 Comment cmnt(masm_, "[ SwitchStatement"); | 1793 Comment cmnt(masm_, "[ SwitchStatement"); |
1472 CodeForStatementPosition(node); | 1794 CodeForStatementPosition(node); |
1473 node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); | 1795 node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); |
1474 | 1796 |
1475 LoadAndSpill(node->tag()); | 1797 LoadAndSpill(node->tag()); |
1476 | 1798 |
1477 JumpTarget next_test; | 1799 JumpTarget next_test; |
1478 JumpTarget fall_through; | 1800 JumpTarget fall_through; |
1479 JumpTarget default_entry; | 1801 JumpTarget default_entry; |
1480 JumpTarget default_exit(JumpTarget::BIDIRECTIONAL); | 1802 JumpTarget default_exit(JumpTarget::BIDIRECTIONAL); |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1549 } | 1871 } |
1550 node->break_target()->Unuse(); | 1872 node->break_target()->Unuse(); |
1551 ASSERT(!has_valid_frame() || frame_->height() == original_height); | 1873 ASSERT(!has_valid_frame() || frame_->height() == original_height); |
1552 } | 1874 } |
1553 | 1875 |
1554 | 1876 |
1555 void CodeGenerator::VisitDoWhileStatement(DoWhileStatement* node) { | 1877 void CodeGenerator::VisitDoWhileStatement(DoWhileStatement* node) { |
1556 #ifdef DEBUG | 1878 #ifdef DEBUG |
1557 int original_height = frame_->height(); | 1879 int original_height = frame_->height(); |
1558 #endif | 1880 #endif |
1559 VirtualFrame::SpilledScope spilled_scope; | 1881 VirtualFrame::SpilledScope spilled_scope(frame_); |
1560 Comment cmnt(masm_, "[ DoWhileStatement"); | 1882 Comment cmnt(masm_, "[ DoWhileStatement"); |
1561 CodeForStatementPosition(node); | 1883 CodeForStatementPosition(node); |
1562 node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); | 1884 node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); |
1563 JumpTarget body(JumpTarget::BIDIRECTIONAL); | 1885 JumpTarget body(JumpTarget::BIDIRECTIONAL); |
1564 | 1886 |
1565 // Label the top of the loop for the backward CFG edge. If the test | 1887 // Label the top of the loop for the backward CFG edge. If the test |
1566 // is always true we can use the continue target, and if the test is | 1888 // is always true we can use the continue target, and if the test is |
1567 // always false there is no need. | 1889 // always false there is no need. |
1568 ConditionAnalysis info = AnalyzeCondition(node->cond()); | 1890 ConditionAnalysis info = AnalyzeCondition(node->cond()); |
1569 switch (info) { | 1891 switch (info) { |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1622 node->break_target()->Bind(); | 1944 node->break_target()->Bind(); |
1623 } | 1945 } |
1624 ASSERT(!has_valid_frame() || frame_->height() == original_height); | 1946 ASSERT(!has_valid_frame() || frame_->height() == original_height); |
1625 } | 1947 } |
1626 | 1948 |
1627 | 1949 |
1628 void CodeGenerator::VisitWhileStatement(WhileStatement* node) { | 1950 void CodeGenerator::VisitWhileStatement(WhileStatement* node) { |
1629 #ifdef DEBUG | 1951 #ifdef DEBUG |
1630 int original_height = frame_->height(); | 1952 int original_height = frame_->height(); |
1631 #endif | 1953 #endif |
1632 VirtualFrame::SpilledScope spilled_scope; | 1954 VirtualFrame::SpilledScope spilled_scope(frame_); |
1633 Comment cmnt(masm_, "[ WhileStatement"); | 1955 Comment cmnt(masm_, "[ WhileStatement"); |
1634 CodeForStatementPosition(node); | 1956 CodeForStatementPosition(node); |
1635 | 1957 |
1636 // If the test is never true and has no side effects there is no need | 1958 // If the test is never true and has no side effects there is no need |
1637 // to compile the test or body. | 1959 // to compile the test or body. |
1638 ConditionAnalysis info = AnalyzeCondition(node->cond()); | 1960 ConditionAnalysis info = AnalyzeCondition(node->cond()); |
1639 if (info == ALWAYS_FALSE) return; | 1961 if (info == ALWAYS_FALSE) return; |
1640 | 1962 |
1641 node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); | 1963 node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); |
1642 | 1964 |
(...skipping 28 matching lines...) Expand all Loading... | |
1671 node->break_target()->Bind(); | 1993 node->break_target()->Bind(); |
1672 } | 1994 } |
1673 ASSERT(!has_valid_frame() || frame_->height() == original_height); | 1995 ASSERT(!has_valid_frame() || frame_->height() == original_height); |
1674 } | 1996 } |
1675 | 1997 |
1676 | 1998 |
1677 void CodeGenerator::VisitForStatement(ForStatement* node) { | 1999 void CodeGenerator::VisitForStatement(ForStatement* node) { |
1678 #ifdef DEBUG | 2000 #ifdef DEBUG |
1679 int original_height = frame_->height(); | 2001 int original_height = frame_->height(); |
1680 #endif | 2002 #endif |
1681 VirtualFrame::SpilledScope spilled_scope; | 2003 VirtualFrame::SpilledScope spilled_scope(frame_); |
1682 Comment cmnt(masm_, "[ ForStatement"); | 2004 Comment cmnt(masm_, "[ ForStatement"); |
1683 CodeForStatementPosition(node); | 2005 CodeForStatementPosition(node); |
1684 if (node->init() != NULL) { | 2006 if (node->init() != NULL) { |
1685 VisitAndSpill(node->init()); | 2007 VisitAndSpill(node->init()); |
1686 } | 2008 } |
1687 | 2009 |
1688 // If the test is never true there is no need to compile the test or | 2010 // If the test is never true there is no need to compile the test or |
1689 // body. | 2011 // body. |
1690 ConditionAnalysis info = AnalyzeCondition(node->cond()); | 2012 ConditionAnalysis info = AnalyzeCondition(node->cond()); |
1691 if (info == ALWAYS_FALSE) return; | 2013 if (info == ALWAYS_FALSE) return; |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1746 node->break_target()->Bind(); | 2068 node->break_target()->Bind(); |
1747 } | 2069 } |
1748 ASSERT(!has_valid_frame() || frame_->height() == original_height); | 2070 ASSERT(!has_valid_frame() || frame_->height() == original_height); |
1749 } | 2071 } |
1750 | 2072 |
1751 | 2073 |
1752 void CodeGenerator::VisitForInStatement(ForInStatement* node) { | 2074 void CodeGenerator::VisitForInStatement(ForInStatement* node) { |
1753 #ifdef DEBUG | 2075 #ifdef DEBUG |
1754 int original_height = frame_->height(); | 2076 int original_height = frame_->height(); |
1755 #endif | 2077 #endif |
1756 VirtualFrame::SpilledScope spilled_scope; | 2078 VirtualFrame::SpilledScope spilled_scope(frame_); |
1757 Comment cmnt(masm_, "[ ForInStatement"); | 2079 Comment cmnt(masm_, "[ ForInStatement"); |
1758 CodeForStatementPosition(node); | 2080 CodeForStatementPosition(node); |
1759 | 2081 |
1760 JumpTarget primitive; | 2082 JumpTarget primitive; |
1761 JumpTarget jsobject; | 2083 JumpTarget jsobject; |
1762 JumpTarget fixed_array; | 2084 JumpTarget fixed_array; |
1763 JumpTarget entry(JumpTarget::BIDIRECTIONAL); | 2085 JumpTarget entry(JumpTarget::BIDIRECTIONAL); |
1764 JumpTarget end_del_check; | 2086 JumpTarget end_del_check; |
1765 JumpTarget exit; | 2087 JumpTarget exit; |
1766 | 2088 |
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1982 node->continue_target()->Unuse(); | 2304 node->continue_target()->Unuse(); |
1983 node->break_target()->Unuse(); | 2305 node->break_target()->Unuse(); |
1984 ASSERT(frame_->height() == original_height); | 2306 ASSERT(frame_->height() == original_height); |
1985 } | 2307 } |
1986 | 2308 |
1987 | 2309 |
1988 void CodeGenerator::VisitTryCatchStatement(TryCatchStatement* node) { | 2310 void CodeGenerator::VisitTryCatchStatement(TryCatchStatement* node) { |
1989 #ifdef DEBUG | 2311 #ifdef DEBUG |
1990 int original_height = frame_->height(); | 2312 int original_height = frame_->height(); |
1991 #endif | 2313 #endif |
1992 VirtualFrame::SpilledScope spilled_scope; | 2314 VirtualFrame::SpilledScope spilled_scope(frame_); |
1993 Comment cmnt(masm_, "[ TryCatchStatement"); | 2315 Comment cmnt(masm_, "[ TryCatchStatement"); |
1994 CodeForStatementPosition(node); | 2316 CodeForStatementPosition(node); |
1995 | 2317 |
1996 JumpTarget try_block; | 2318 JumpTarget try_block; |
1997 JumpTarget exit; | 2319 JumpTarget exit; |
1998 | 2320 |
1999 try_block.Call(); | 2321 try_block.Call(); |
2000 // --- Catch block --- | 2322 // --- Catch block --- |
2001 frame_->EmitPush(r0); | 2323 frame_->EmitPush(r0); |
2002 | 2324 |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2103 | 2425 |
2104 exit.Bind(); | 2426 exit.Bind(); |
2105 ASSERT(!has_valid_frame() || frame_->height() == original_height); | 2427 ASSERT(!has_valid_frame() || frame_->height() == original_height); |
2106 } | 2428 } |
2107 | 2429 |
2108 | 2430 |
2109 void CodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* node) { | 2431 void CodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* node) { |
2110 #ifdef DEBUG | 2432 #ifdef DEBUG |
2111 int original_height = frame_->height(); | 2433 int original_height = frame_->height(); |
2112 #endif | 2434 #endif |
2113 VirtualFrame::SpilledScope spilled_scope; | 2435 VirtualFrame::SpilledScope spilled_scope(frame_); |
2114 Comment cmnt(masm_, "[ TryFinallyStatement"); | 2436 Comment cmnt(masm_, "[ TryFinallyStatement"); |
2115 CodeForStatementPosition(node); | 2437 CodeForStatementPosition(node); |
2116 | 2438 |
2117 // State: Used to keep track of reason for entering the finally | 2439 // State: Used to keep track of reason for entering the finally |
2118 // block. Should probably be extended to hold information for | 2440 // block. Should probably be extended to hold information for |
2119 // break/continue from within the try block. | 2441 // break/continue from within the try block. |
2120 enum { FALLING, THROWING, JUMPING }; | 2442 enum { FALLING, THROWING, JUMPING }; |
2121 | 2443 |
2122 JumpTarget try_block; | 2444 JumpTarget try_block; |
2123 JumpTarget finally_block; | 2445 JumpTarget finally_block; |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2287 exit.Bind(); | 2609 exit.Bind(); |
2288 } | 2610 } |
2289 ASSERT(!has_valid_frame() || frame_->height() == original_height); | 2611 ASSERT(!has_valid_frame() || frame_->height() == original_height); |
2290 } | 2612 } |
2291 | 2613 |
2292 | 2614 |
2293 void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { | 2615 void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { |
2294 #ifdef DEBUG | 2616 #ifdef DEBUG |
2295 int original_height = frame_->height(); | 2617 int original_height = frame_->height(); |
2296 #endif | 2618 #endif |
2297 VirtualFrame::SpilledScope spilled_scope; | 2619 VirtualFrame::SpilledScope spilled_scope(frame_); |
2298 Comment cmnt(masm_, "[ DebuggerStatament"); | 2620 Comment cmnt(masm_, "[ DebuggerStatament"); |
2299 CodeForStatementPosition(node); | 2621 CodeForStatementPosition(node); |
2300 #ifdef ENABLE_DEBUGGER_SUPPORT | 2622 #ifdef ENABLE_DEBUGGER_SUPPORT |
2301 frame_->DebugBreak(); | 2623 frame_->DebugBreak(); |
2302 #endif | 2624 #endif |
2303 // Ignore the return value. | 2625 // Ignore the return value. |
2304 ASSERT(frame_->height() == original_height); | 2626 ASSERT(frame_->height() == original_height); |
2305 } | 2627 } |
2306 | 2628 |
2307 | 2629 |
2308 void CodeGenerator::InstantiateFunction( | 2630 void CodeGenerator::InstantiateFunction( |
2309 Handle<SharedFunctionInfo> function_info) { | 2631 Handle<SharedFunctionInfo> function_info) { |
2310 VirtualFrame::SpilledScope spilled_scope; | 2632 VirtualFrame::SpilledScope spilled_scope(frame_); |
2311 __ mov(r0, Operand(function_info)); | 2633 __ mov(r0, Operand(function_info)); |
2312 // Use the fast case closure allocation code that allocates in new | 2634 // Use the fast case closure allocation code that allocates in new |
2313 // space for nested functions that don't need literals cloning. | 2635 // space for nested functions that don't need literals cloning. |
2314 if (scope()->is_function_scope() && function_info->num_literals() == 0) { | 2636 if (scope()->is_function_scope() && function_info->num_literals() == 0) { |
2315 FastNewClosureStub stub; | 2637 FastNewClosureStub stub; |
2316 frame_->EmitPush(r0); | 2638 frame_->EmitPush(r0); |
2317 frame_->CallStub(&stub, 1); | 2639 frame_->CallStub(&stub, 1); |
2318 frame_->EmitPush(r0); | 2640 frame_->EmitPush(r0); |
2319 } else { | 2641 } else { |
2320 // Create a new closure. | 2642 // Create a new closure. |
2321 frame_->EmitPush(cp); | 2643 frame_->EmitPush(cp); |
2322 frame_->EmitPush(r0); | 2644 frame_->EmitPush(r0); |
2323 frame_->CallRuntime(Runtime::kNewClosure, 2); | 2645 frame_->CallRuntime(Runtime::kNewClosure, 2); |
2324 frame_->EmitPush(r0); | 2646 frame_->EmitPush(r0); |
2325 } | 2647 } |
2326 } | 2648 } |
2327 | 2649 |
2328 | 2650 |
2329 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { | 2651 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { |
2330 #ifdef DEBUG | 2652 #ifdef DEBUG |
2331 int original_height = frame_->height(); | 2653 int original_height = frame_->height(); |
2332 #endif | 2654 #endif |
2333 VirtualFrame::SpilledScope spilled_scope; | 2655 VirtualFrame::SpilledScope spilled_scope(frame_); |
2334 Comment cmnt(masm_, "[ FunctionLiteral"); | 2656 Comment cmnt(masm_, "[ FunctionLiteral"); |
2335 | 2657 |
2336 // Build the function info and instantiate it. | 2658 // Build the function info and instantiate it. |
2337 Handle<SharedFunctionInfo> function_info = | 2659 Handle<SharedFunctionInfo> function_info = |
2338 Compiler::BuildFunctionInfo(node, script(), this); | 2660 Compiler::BuildFunctionInfo(node, script(), this); |
2339 // Check for stack-overflow exception. | 2661 // Check for stack-overflow exception. |
2340 if (HasStackOverflow()) { | 2662 if (HasStackOverflow()) { |
2341 ASSERT(frame_->height() == original_height); | 2663 ASSERT(frame_->height() == original_height); |
2342 return; | 2664 return; |
2343 } | 2665 } |
2344 InstantiateFunction(function_info); | 2666 InstantiateFunction(function_info); |
2345 ASSERT(frame_->height() == original_height + 1); | 2667 ASSERT(frame_->height() == original_height + 1); |
2346 } | 2668 } |
2347 | 2669 |
2348 | 2670 |
2349 void CodeGenerator::VisitSharedFunctionInfoLiteral( | 2671 void CodeGenerator::VisitSharedFunctionInfoLiteral( |
2350 SharedFunctionInfoLiteral* node) { | 2672 SharedFunctionInfoLiteral* node) { |
2351 #ifdef DEBUG | 2673 #ifdef DEBUG |
2352 int original_height = frame_->height(); | 2674 int original_height = frame_->height(); |
2353 #endif | 2675 #endif |
2354 VirtualFrame::SpilledScope spilled_scope; | 2676 VirtualFrame::SpilledScope spilled_scope(frame_); |
2355 Comment cmnt(masm_, "[ SharedFunctionInfoLiteral"); | 2677 Comment cmnt(masm_, "[ SharedFunctionInfoLiteral"); |
2356 InstantiateFunction(node->shared_function_info()); | 2678 InstantiateFunction(node->shared_function_info()); |
2357 ASSERT(frame_->height() == original_height + 1); | 2679 ASSERT(frame_->height() == original_height + 1); |
2358 } | 2680 } |
2359 | 2681 |
2360 | 2682 |
2361 void CodeGenerator::VisitConditional(Conditional* node) { | 2683 void CodeGenerator::VisitConditional(Conditional* node) { |
2362 #ifdef DEBUG | 2684 #ifdef DEBUG |
2363 int original_height = frame_->height(); | 2685 int original_height = frame_->height(); |
2364 #endif | 2686 #endif |
2365 VirtualFrame::SpilledScope spilled_scope; | 2687 VirtualFrame::SpilledScope spilled_scope(frame_); |
2366 Comment cmnt(masm_, "[ Conditional"); | 2688 Comment cmnt(masm_, "[ Conditional"); |
2367 JumpTarget then; | 2689 JumpTarget then; |
2368 JumpTarget else_; | 2690 JumpTarget else_; |
2369 LoadConditionAndSpill(node->condition(), &then, &else_, true); | 2691 LoadConditionAndSpill(node->condition(), &then, &else_, true); |
2370 if (has_valid_frame()) { | 2692 if (has_valid_frame()) { |
2371 Branch(false, &else_); | 2693 Branch(false, &else_); |
2372 } | 2694 } |
2373 if (has_valid_frame() || then.is_linked()) { | 2695 if (has_valid_frame() || then.is_linked()) { |
2374 then.Bind(); | 2696 then.Bind(); |
2375 LoadAndSpill(node->then_expression()); | 2697 LoadAndSpill(node->then_expression()); |
2376 } | 2698 } |
2377 if (else_.is_linked()) { | 2699 if (else_.is_linked()) { |
2378 JumpTarget exit; | 2700 JumpTarget exit; |
2379 if (has_valid_frame()) exit.Jump(); | 2701 if (has_valid_frame()) exit.Jump(); |
2380 else_.Bind(); | 2702 else_.Bind(); |
2381 LoadAndSpill(node->else_expression()); | 2703 LoadAndSpill(node->else_expression()); |
2382 if (exit.is_linked()) exit.Bind(); | 2704 if (exit.is_linked()) exit.Bind(); |
2383 } | 2705 } |
2384 ASSERT(frame_->height() == original_height + 1); | 2706 ASSERT(frame_->height() == original_height + 1); |
2385 } | 2707 } |
2386 | 2708 |
2387 | 2709 |
2388 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { | 2710 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { |
2389 VirtualFrame::SpilledScope spilled_scope; | |
2390 if (slot->type() == Slot::LOOKUP) { | 2711 if (slot->type() == Slot::LOOKUP) { |
2712 VirtualFrame::SpilledScope spilled_scope(frame_); | |
2391 ASSERT(slot->var()->is_dynamic()); | 2713 ASSERT(slot->var()->is_dynamic()); |
2392 | 2714 |
2393 JumpTarget slow; | 2715 JumpTarget slow; |
2394 JumpTarget done; | 2716 JumpTarget done; |
2395 | 2717 |
2396 // Generate fast-case code for variables that might be shadowed by | 2718 // Generate fast-case code for variables that might be shadowed by |
2397 // eval-introduced variables. Eval is used a lot without | 2719 // eval-introduced variables. Eval is used a lot without |
2398 // introducing variables. In those cases, we do not want to | 2720 // introducing variables. In those cases, we do not want to |
2399 // perform a runtime call for all variables in the scope | 2721 // perform a runtime call for all variables in the scope |
2400 // containing the eval. | 2722 // containing the eval. |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2438 if (typeof_state == INSIDE_TYPEOF) { | 2760 if (typeof_state == INSIDE_TYPEOF) { |
2439 frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 2761 frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
2440 } else { | 2762 } else { |
2441 frame_->CallRuntime(Runtime::kLoadContextSlot, 2); | 2763 frame_->CallRuntime(Runtime::kLoadContextSlot, 2); |
2442 } | 2764 } |
2443 | 2765 |
2444 done.Bind(); | 2766 done.Bind(); |
2445 frame_->EmitPush(r0); | 2767 frame_->EmitPush(r0); |
2446 | 2768 |
2447 } else { | 2769 } else { |
2448 // Special handling for locals allocated in registers. | 2770 Register scratch = VirtualFrame::scratch0(); |
2449 __ ldr(r0, SlotOperand(slot, r2)); | 2771 frame_->EmitPush(SlotOperand(slot, scratch)); |
2450 frame_->EmitPush(r0); | |
2451 if (slot->var()->mode() == Variable::CONST) { | 2772 if (slot->var()->mode() == Variable::CONST) { |
2452 // Const slots may contain 'the hole' value (the constant hasn't been | 2773 // Const slots may contain 'the hole' value (the constant hasn't been |
2453 // initialized yet) which needs to be converted into the 'undefined' | 2774 // initialized yet) which needs to be converted into the 'undefined' |
2454 // value. | 2775 // value. |
2455 Comment cmnt(masm_, "[ Unhole const"); | 2776 Comment cmnt(masm_, "[ Unhole const"); |
2456 frame_->EmitPop(r0); | 2777 frame_->EmitPop(scratch); |
2457 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 2778 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
2458 __ cmp(r0, ip); | 2779 __ cmp(scratch, ip); |
2459 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq); | 2780 __ LoadRoot(scratch, Heap::kUndefinedValueRootIndex, eq); |
2460 frame_->EmitPush(r0); | 2781 frame_->EmitPush(scratch); |
2461 } | 2782 } |
2462 } | 2783 } |
2463 } | 2784 } |
2464 | 2785 |
2465 | 2786 |
2466 void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) { | 2787 void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) { |
2467 ASSERT(slot != NULL); | 2788 ASSERT(slot != NULL); |
2468 if (slot->type() == Slot::LOOKUP) { | 2789 if (slot->type() == Slot::LOOKUP) { |
2790 VirtualFrame::SpilledScope spilled_scope(frame_); | |
2469 ASSERT(slot->var()->is_dynamic()); | 2791 ASSERT(slot->var()->is_dynamic()); |
2470 | 2792 |
2471 // For now, just do a runtime call. | 2793 // For now, just do a runtime call. |
2472 frame_->EmitPush(cp); | 2794 frame_->EmitPush(cp); |
2473 __ mov(r0, Operand(slot->var()->name())); | 2795 __ mov(r0, Operand(slot->var()->name())); |
2474 frame_->EmitPush(r0); | 2796 frame_->EmitPush(r0); |
2475 | 2797 |
2476 if (init_state == CONST_INIT) { | 2798 if (init_state == CONST_INIT) { |
2477 // Same as the case for a normal store, but ignores attribute | 2799 // Same as the case for a normal store, but ignores attribute |
2478 // (e.g. READ_ONLY) of context slot so that we can initialize | 2800 // (e.g. READ_ONLY) of context slot so that we can initialize |
(...skipping 13 matching lines...) Expand all Loading... | |
2492 frame_->CallRuntime(Runtime::kInitializeConstContextSlot, 3); | 2814 frame_->CallRuntime(Runtime::kInitializeConstContextSlot, 3); |
2493 } else { | 2815 } else { |
2494 frame_->CallRuntime(Runtime::kStoreContextSlot, 3); | 2816 frame_->CallRuntime(Runtime::kStoreContextSlot, 3); |
2495 } | 2817 } |
2496 // Storing a variable must keep the (new) value on the expression | 2818 // Storing a variable must keep the (new) value on the expression |
2497 // stack. This is necessary for compiling assignment expressions. | 2819 // stack. This is necessary for compiling assignment expressions. |
2498 frame_->EmitPush(r0); | 2820 frame_->EmitPush(r0); |
2499 | 2821 |
2500 } else { | 2822 } else { |
2501 ASSERT(!slot->var()->is_dynamic()); | 2823 ASSERT(!slot->var()->is_dynamic()); |
2824 Register scratch = VirtualFrame::scratch0(); | |
2825 VirtualFrame::RegisterAllocationScope scope(this); | |
2502 | 2826 |
2827 // The frame must be spilled when branching to this target. | |
2503 JumpTarget exit; | 2828 JumpTarget exit; |
2829 | |
2504 if (init_state == CONST_INIT) { | 2830 if (init_state == CONST_INIT) { |
2505 ASSERT(slot->var()->mode() == Variable::CONST); | 2831 ASSERT(slot->var()->mode() == Variable::CONST); |
2506 // Only the first const initialization must be executed (the slot | 2832 // Only the first const initialization must be executed (the slot |
2507 // still contains 'the hole' value). When the assignment is | 2833 // still contains 'the hole' value). When the assignment is |
2508 // executed, the code is identical to a normal store (see below). | 2834 // executed, the code is identical to a normal store (see below). |
2509 Comment cmnt(masm_, "[ Init const"); | 2835 Comment cmnt(masm_, "[ Init const"); |
2510 __ ldr(r2, SlotOperand(slot, r2)); | 2836 __ ldr(scratch, SlotOperand(slot, scratch)); |
2511 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); | 2837 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
2512 __ cmp(r2, ip); | 2838 __ cmp(scratch, ip); |
2839 frame_->SpillAll(); | |
2513 exit.Branch(ne); | 2840 exit.Branch(ne); |
2514 } | 2841 } |
2515 | 2842 |
2516 // We must execute the store. Storing a variable must keep the | 2843 // We must execute the store. Storing a variable must keep the |
2517 // (new) value on the stack. This is necessary for compiling | 2844 // (new) value on the stack. This is necessary for compiling |
2518 // assignment expressions. | 2845 // assignment expressions. |
2519 // | 2846 // |
2520 // Note: We will reach here even with slot->var()->mode() == | 2847 // Note: We will reach here even with slot->var()->mode() == |
2521 // Variable::CONST because of const declarations which will | 2848 // Variable::CONST because of const declarations which will |
2522 // initialize consts to 'the hole' value and by doing so, end up | 2849 // initialize consts to 'the hole' value and by doing so, end up |
2523 // calling this code. r2 may be loaded with context; used below in | 2850 // calling this code. r2 may be loaded with context; used below in |
2524 // RecordWrite. | 2851 // RecordWrite. |
2525 frame_->EmitPop(r0); | 2852 Register tos = frame_->Peek(); |
2526 __ str(r0, SlotOperand(slot, r2)); | 2853 __ str(tos, SlotOperand(slot, scratch)); |
2527 frame_->EmitPush(r0); | |
2528 if (slot->type() == Slot::CONTEXT) { | 2854 if (slot->type() == Slot::CONTEXT) { |
2529 // Skip write barrier if the written value is a smi. | 2855 // Skip write barrier if the written value is a smi. |
2530 __ tst(r0, Operand(kSmiTagMask)); | 2856 __ tst(tos, Operand(kSmiTagMask)); |
2857 VirtualFrame::SpilledScope spilled_scope(frame_); | |
2531 exit.Branch(eq); | 2858 exit.Branch(eq); |
2532 // r2 is loaded with context when calling SlotOperand above. | 2859 // scratch is loaded with context when calling SlotOperand above. |
2533 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; | 2860 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; |
Søren Thygesen Gjesse
2010/04/07 10:46:51
VirtualFrame::scratchX()?
Erik Corry
2010/04/07 12:49:17
We are in a spilled scope here.
| |
2534 __ mov(r3, Operand(offset)); | 2861 __ mov(r3, Operand(offset)); |
2535 __ RecordWrite(r2, r3, r1); | 2862 __ RecordWrite(scratch, r3, r1); |
Søren Thygesen Gjesse
2010/04/07 10:46:51
What about r1 here, will tos always be r0? If so a
Erik Corry
2010/04/07 12:49:17
r1 is a scratch register, but we don't use tos any
| |
2536 } | 2863 } |
2537 // If we definitely did not jump over the assignment, we do not need | 2864 // If we definitely did not jump over the assignment, we do not need |
2538 // to bind the exit label. Doing so can defeat peephole | 2865 // to bind the exit label. Doing so can defeat peephole |
2539 // optimization. | 2866 // optimization. |
2540 if (init_state == CONST_INIT || slot->type() == Slot::CONTEXT) { | 2867 if (init_state == CONST_INIT || slot->type() == Slot::CONTEXT) { |
2868 frame_->SpillAll(); | |
2541 exit.Bind(); | 2869 exit.Bind(); |
2542 } | 2870 } |
2543 } | 2871 } |
2544 } | 2872 } |
2545 | 2873 |
2546 | 2874 |
2547 void CodeGenerator::LoadFromGlobalSlotCheckExtensions(Slot* slot, | 2875 void CodeGenerator::LoadFromGlobalSlotCheckExtensions(Slot* slot, |
2548 TypeofState typeof_state, | 2876 TypeofState typeof_state, |
2549 Register tmp, | 2877 Register tmp, |
2550 Register tmp2, | 2878 Register tmp2, |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2610 | 2938 |
2611 // Drop the global object. The result is in r0. | 2939 // Drop the global object. The result is in r0. |
2612 frame_->Drop(); | 2940 frame_->Drop(); |
2613 } | 2941 } |
2614 | 2942 |
2615 | 2943 |
2616 void CodeGenerator::VisitSlot(Slot* node) { | 2944 void CodeGenerator::VisitSlot(Slot* node) { |
2617 #ifdef DEBUG | 2945 #ifdef DEBUG |
2618 int original_height = frame_->height(); | 2946 int original_height = frame_->height(); |
2619 #endif | 2947 #endif |
2620 VirtualFrame::SpilledScope spilled_scope; | |
2621 Comment cmnt(masm_, "[ Slot"); | 2948 Comment cmnt(masm_, "[ Slot"); |
2622 LoadFromSlot(node, NOT_INSIDE_TYPEOF); | 2949 LoadFromSlot(node, NOT_INSIDE_TYPEOF); |
2623 ASSERT(frame_->height() == original_height + 1); | 2950 ASSERT(frame_->height() == original_height + 1); |
2624 } | 2951 } |
2625 | 2952 |
2626 | 2953 |
2627 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { | 2954 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { |
2628 #ifdef DEBUG | 2955 #ifdef DEBUG |
2629 int original_height = frame_->height(); | 2956 int original_height = frame_->height(); |
2630 #endif | 2957 #endif |
2631 VirtualFrame::SpilledScope spilled_scope; | |
2632 Comment cmnt(masm_, "[ VariableProxy"); | 2958 Comment cmnt(masm_, "[ VariableProxy"); |
2633 | 2959 |
2634 Variable* var = node->var(); | 2960 Variable* var = node->var(); |
2635 Expression* expr = var->rewrite(); | 2961 Expression* expr = var->rewrite(); |
2636 if (expr != NULL) { | 2962 if (expr != NULL) { |
2637 Visit(expr); | 2963 Visit(expr); |
2638 } else { | 2964 } else { |
2639 ASSERT(var->is_global()); | 2965 ASSERT(var->is_global()); |
2640 Reference ref(this, node); | 2966 Reference ref(this, node); |
2641 ref.GetValueAndSpill(); | 2967 ref.GetValue(); |
2642 } | 2968 } |
2643 ASSERT(frame_->height() == original_height + 1); | 2969 ASSERT(frame_->height() == original_height + 1); |
2644 } | 2970 } |
2645 | 2971 |
2646 | 2972 |
2647 void CodeGenerator::VisitLiteral(Literal* node) { | 2973 void CodeGenerator::VisitLiteral(Literal* node) { |
2648 #ifdef DEBUG | 2974 #ifdef DEBUG |
2649 int original_height = frame_->height(); | 2975 int original_height = frame_->height(); |
2650 #endif | 2976 #endif |
2651 VirtualFrame::SpilledScope spilled_scope; | |
2652 Comment cmnt(masm_, "[ Literal"); | 2977 Comment cmnt(masm_, "[ Literal"); |
2653 __ mov(r0, Operand(node->handle())); | 2978 Register reg = frame_->GetTOSRegister(); |
2654 frame_->EmitPush(r0); | 2979 __ mov(reg, Operand(node->handle())); |
2980 frame_->EmitPush(reg); | |
2655 ASSERT(frame_->height() == original_height + 1); | 2981 ASSERT(frame_->height() == original_height + 1); |
2656 } | 2982 } |
2657 | 2983 |
2658 | 2984 |
2659 void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) { | 2985 void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) { |
2660 #ifdef DEBUG | 2986 #ifdef DEBUG |
2661 int original_height = frame_->height(); | 2987 int original_height = frame_->height(); |
2662 #endif | 2988 #endif |
2663 VirtualFrame::SpilledScope spilled_scope; | 2989 VirtualFrame::SpilledScope spilled_scope(frame_); |
2664 Comment cmnt(masm_, "[ RexExp Literal"); | 2990 Comment cmnt(masm_, "[ RexExp Literal"); |
2665 | 2991 |
2666 // Retrieve the literal array and check the allocated entry. | 2992 // Retrieve the literal array and check the allocated entry. |
2667 | 2993 |
2668 // Load the function of this activation. | 2994 // Load the function of this activation. |
2669 __ ldr(r1, frame_->Function()); | 2995 __ ldr(r1, frame_->Function()); |
2670 | 2996 |
2671 // Load the literals array of the function. | 2997 // Load the literals array of the function. |
2672 __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset)); | 2998 __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset)); |
2673 | 2999 |
(...skipping 23 matching lines...) Expand all Loading... | |
2697 // Push the literal. | 3023 // Push the literal. |
2698 frame_->EmitPush(r2); | 3024 frame_->EmitPush(r2); |
2699 ASSERT(frame_->height() == original_height + 1); | 3025 ASSERT(frame_->height() == original_height + 1); |
2700 } | 3026 } |
2701 | 3027 |
2702 | 3028 |
2703 void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { | 3029 void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { |
2704 #ifdef DEBUG | 3030 #ifdef DEBUG |
2705 int original_height = frame_->height(); | 3031 int original_height = frame_->height(); |
2706 #endif | 3032 #endif |
2707 VirtualFrame::SpilledScope spilled_scope; | 3033 VirtualFrame::SpilledScope spilled_scope(frame_); |
2708 Comment cmnt(masm_, "[ ObjectLiteral"); | 3034 Comment cmnt(masm_, "[ ObjectLiteral"); |
2709 | 3035 |
2710 // Load the function of this activation. | 3036 // Load the function of this activation. |
2711 __ ldr(r3, frame_->Function()); | 3037 __ ldr(r3, frame_->Function()); |
2712 // Literal array. | 3038 // Literal array. |
2713 __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset)); | 3039 __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset)); |
2714 // Literal index. | 3040 // Literal index. |
2715 __ mov(r2, Operand(Smi::FromInt(node->literal_index()))); | 3041 __ mov(r2, Operand(Smi::FromInt(node->literal_index()))); |
2716 // Constant properties. | 3042 // Constant properties. |
2717 __ mov(r1, Operand(node->constant_properties())); | 3043 __ mov(r1, Operand(node->constant_properties())); |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2778 } | 3104 } |
2779 } | 3105 } |
2780 ASSERT(frame_->height() == original_height + 1); | 3106 ASSERT(frame_->height() == original_height + 1); |
2781 } | 3107 } |
2782 | 3108 |
2783 | 3109 |
2784 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { | 3110 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { |
2785 #ifdef DEBUG | 3111 #ifdef DEBUG |
2786 int original_height = frame_->height(); | 3112 int original_height = frame_->height(); |
2787 #endif | 3113 #endif |
2788 VirtualFrame::SpilledScope spilled_scope; | 3114 VirtualFrame::SpilledScope spilled_scope(frame_); |
2789 Comment cmnt(masm_, "[ ArrayLiteral"); | 3115 Comment cmnt(masm_, "[ ArrayLiteral"); |
2790 | 3116 |
2791 // Load the function of this activation. | 3117 // Load the function of this activation. |
2792 __ ldr(r2, frame_->Function()); | 3118 __ ldr(r2, frame_->Function()); |
2793 // Load the literals array of the function. | 3119 // Load the literals array of the function. |
2794 __ ldr(r2, FieldMemOperand(r2, JSFunction::kLiteralsOffset)); | 3120 __ ldr(r2, FieldMemOperand(r2, JSFunction::kLiteralsOffset)); |
2795 __ mov(r1, Operand(Smi::FromInt(node->literal_index()))); | 3121 __ mov(r1, Operand(Smi::FromInt(node->literal_index()))); |
2796 __ mov(r0, Operand(node->constant_elements())); | 3122 __ mov(r0, Operand(node->constant_elements())); |
2797 frame_->EmitPushMultiple(3, r2.bit() | r1.bit() | r0.bit()); | 3123 frame_->EmitPushMultiple(3, r2.bit() | r1.bit() | r0.bit()); |
2798 int length = node->values()->length(); | 3124 int length = node->values()->length(); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2837 __ RecordWrite(r1, r3, r2); | 3163 __ RecordWrite(r1, r3, r2); |
2838 } | 3164 } |
2839 ASSERT(frame_->height() == original_height + 1); | 3165 ASSERT(frame_->height() == original_height + 1); |
2840 } | 3166 } |
2841 | 3167 |
2842 | 3168 |
2843 void CodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* node) { | 3169 void CodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* node) { |
2844 #ifdef DEBUG | 3170 #ifdef DEBUG |
2845 int original_height = frame_->height(); | 3171 int original_height = frame_->height(); |
2846 #endif | 3172 #endif |
2847 VirtualFrame::SpilledScope spilled_scope; | 3173 VirtualFrame::SpilledScope spilled_scope(frame_); |
2848 // Call runtime routine to allocate the catch extension object and | 3174 // Call runtime routine to allocate the catch extension object and |
2849 // assign the exception value to the catch variable. | 3175 // assign the exception value to the catch variable. |
2850 Comment cmnt(masm_, "[ CatchExtensionObject"); | 3176 Comment cmnt(masm_, "[ CatchExtensionObject"); |
2851 LoadAndSpill(node->key()); | 3177 LoadAndSpill(node->key()); |
2852 LoadAndSpill(node->value()); | 3178 LoadAndSpill(node->value()); |
2853 frame_->CallRuntime(Runtime::kCreateCatchExtensionObject, 2); | 3179 frame_->CallRuntime(Runtime::kCreateCatchExtensionObject, 2); |
2854 frame_->EmitPush(r0); | 3180 frame_->EmitPush(r0); |
2855 ASSERT(frame_->height() == original_height + 1); | 3181 ASSERT(frame_->height() == original_height + 1); |
2856 } | 3182 } |
2857 | 3183 |
2858 | 3184 |
2859 void CodeGenerator::VisitAssignment(Assignment* node) { | 3185 void CodeGenerator::VisitAssignment(Assignment* node) { |
3186 VirtualFrame::RegisterAllocationScope scope(this); | |
2860 #ifdef DEBUG | 3187 #ifdef DEBUG |
2861 int original_height = frame_->height(); | 3188 int original_height = frame_->height(); |
2862 #endif | 3189 #endif |
2863 VirtualFrame::SpilledScope spilled_scope; | |
2864 Comment cmnt(masm_, "[ Assignment"); | 3190 Comment cmnt(masm_, "[ Assignment"); |
2865 | 3191 |
2866 { Reference target(this, node->target(), node->is_compound()); | 3192 { Reference target(this, node->target(), node->is_compound()); |
2867 if (target.is_illegal()) { | 3193 if (target.is_illegal()) { |
2868 // Fool the virtual frame into thinking that we left the assignment's | 3194 // Fool the virtual frame into thinking that we left the assignment's |
2869 // value on the frame. | 3195 // value on the frame. |
2870 __ mov(r0, Operand(Smi::FromInt(0))); | 3196 Register tos = frame_->GetTOSRegister(); |
2871 frame_->EmitPush(r0); | 3197 __ mov(tos, Operand(Smi::FromInt(0))); |
3198 frame_->EmitPush(tos); | |
2872 ASSERT(frame_->height() == original_height + 1); | 3199 ASSERT(frame_->height() == original_height + 1); |
2873 return; | 3200 return; |
2874 } | 3201 } |
2875 | 3202 |
2876 if (node->op() == Token::ASSIGN || | 3203 if (node->op() == Token::ASSIGN || |
2877 node->op() == Token::INIT_VAR || | 3204 node->op() == Token::INIT_VAR || |
2878 node->op() == Token::INIT_CONST) { | 3205 node->op() == Token::INIT_CONST) { |
2879 LoadAndSpill(node->value()); | 3206 Load(node->value()); |
2880 | 3207 |
2881 } else { // Assignment is a compound assignment. | 3208 } else { // Assignment is a compound assignment. |
2882 // Get the old value of the lhs. | 3209 // Get the old value of the lhs. |
2883 target.GetValueAndSpill(); | 3210 target.GetValue(); |
2884 Literal* literal = node->value()->AsLiteral(); | 3211 Literal* literal = node->value()->AsLiteral(); |
2885 bool overwrite = | 3212 bool overwrite = |
2886 (node->value()->AsBinaryOperation() != NULL && | 3213 (node->value()->AsBinaryOperation() != NULL && |
2887 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); | 3214 node->value()->AsBinaryOperation()->ResultOverwriteAllowed()); |
2888 if (literal != NULL && literal->handle()->IsSmi()) { | 3215 if (literal != NULL && literal->handle()->IsSmi()) { |
2889 SmiOperation(node->binary_op(), | 3216 VirtualFrameSmiOperation(node->binary_op(), |
Søren Thygesen Gjesse
2010/04/07 07:53:37
VirtualFrameSmiOperation -> VirtualFrameSmiCompoun
Erik Corry
2010/04/07 12:49:17
I think that's too long. The non-virtual frame ba
| |
2890 literal->handle(), | 3217 literal->handle(), |
2891 false, | 3218 false, |
2892 overwrite ? OVERWRITE_RIGHT : NO_OVERWRITE); | 3219 overwrite ? OVERWRITE_RIGHT : NO_OVERWRITE); |
2893 frame_->EmitPush(r0); | |
2894 | |
2895 } else { | 3220 } else { |
2896 LoadAndSpill(node->value()); | 3221 Load(node->value()); |
2897 GenericBinaryOperation(node->binary_op(), | 3222 VirtualFrameBinaryOperation(node->binary_op(), |
2898 overwrite ? OVERWRITE_RIGHT : NO_OVERWRITE); | 3223 overwrite ? OVERWRITE_RIGHT : NO_OVERWRITE); |
2899 frame_->EmitPush(r0); | |
2900 } | 3224 } |
2901 } | 3225 } |
2902 Variable* var = node->target()->AsVariableProxy()->AsVariable(); | 3226 Variable* var = node->target()->AsVariableProxy()->AsVariable(); |
2903 if (var != NULL && | 3227 if (var != NULL && |
2904 (var->mode() == Variable::CONST) && | 3228 (var->mode() == Variable::CONST) && |
2905 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) { | 3229 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) { |
2906 // Assignment ignored - leave the value on the stack. | 3230 // Assignment ignored - leave the value on the stack. |
2907 UnloadReference(&target); | 3231 UnloadReference(&target); |
2908 } else { | 3232 } else { |
2909 CodeForSourcePosition(node->position()); | 3233 CodeForSourcePosition(node->position()); |
2910 if (node->op() == Token::INIT_CONST) { | 3234 if (node->op() == Token::INIT_CONST) { |
2911 // Dynamic constant initializations must use the function context | 3235 // Dynamic constant initializations must use the function context |
2912 // and initialize the actual constant declared. Dynamic variable | 3236 // and initialize the actual constant declared. Dynamic variable |
2913 // initializations are simply assignments and use SetValue. | 3237 // initializations are simply assignments and use SetValue. |
2914 target.SetValue(CONST_INIT); | 3238 target.SetValue(CONST_INIT); |
2915 } else { | 3239 } else { |
2916 target.SetValue(NOT_CONST_INIT); | 3240 target.SetValue(NOT_CONST_INIT); |
2917 } | 3241 } |
2918 } | 3242 } |
2919 } | 3243 } |
2920 ASSERT(frame_->height() == original_height + 1); | 3244 ASSERT(frame_->height() == original_height + 1); |
2921 } | 3245 } |
2922 | 3246 |
2923 | 3247 |
2924 void CodeGenerator::VisitThrow(Throw* node) { | 3248 void CodeGenerator::VisitThrow(Throw* node) { |
2925 #ifdef DEBUG | 3249 #ifdef DEBUG |
2926 int original_height = frame_->height(); | 3250 int original_height = frame_->height(); |
2927 #endif | 3251 #endif |
2928 VirtualFrame::SpilledScope spilled_scope; | 3252 VirtualFrame::SpilledScope spilled_scope(frame_); |
2929 Comment cmnt(masm_, "[ Throw"); | 3253 Comment cmnt(masm_, "[ Throw"); |
2930 | 3254 |
2931 LoadAndSpill(node->exception()); | 3255 LoadAndSpill(node->exception()); |
2932 CodeForSourcePosition(node->position()); | 3256 CodeForSourcePosition(node->position()); |
2933 frame_->CallRuntime(Runtime::kThrow, 1); | 3257 frame_->CallRuntime(Runtime::kThrow, 1); |
2934 frame_->EmitPush(r0); | 3258 frame_->EmitPush(r0); |
2935 ASSERT(frame_->height() == original_height + 1); | 3259 ASSERT(frame_->height() == original_height + 1); |
2936 } | 3260 } |
2937 | 3261 |
2938 | 3262 |
2939 void CodeGenerator::VisitProperty(Property* node) { | 3263 void CodeGenerator::VisitProperty(Property* node) { |
2940 #ifdef DEBUG | 3264 #ifdef DEBUG |
2941 int original_height = frame_->height(); | 3265 int original_height = frame_->height(); |
2942 #endif | 3266 #endif |
2943 VirtualFrame::SpilledScope spilled_scope; | 3267 VirtualFrame::SpilledScope spilled_scope(frame_); |
2944 Comment cmnt(masm_, "[ Property"); | 3268 Comment cmnt(masm_, "[ Property"); |
2945 | 3269 |
2946 { Reference property(this, node); | 3270 { Reference property(this, node); |
2947 property.GetValueAndSpill(); | 3271 property.GetValue(); |
2948 } | 3272 } |
2949 ASSERT(frame_->height() == original_height + 1); | 3273 ASSERT(frame_->height() == original_height + 1); |
2950 } | 3274 } |
2951 | 3275 |
2952 | 3276 |
2953 void CodeGenerator::VisitCall(Call* node) { | 3277 void CodeGenerator::VisitCall(Call* node) { |
2954 #ifdef DEBUG | 3278 #ifdef DEBUG |
2955 int original_height = frame_->height(); | 3279 int original_height = frame_->height(); |
2956 #endif | 3280 #endif |
2957 VirtualFrame::SpilledScope spilled_scope; | 3281 VirtualFrame::SpilledScope spilled_scope(frame_); |
2958 Comment cmnt(masm_, "[ Call"); | 3282 Comment cmnt(masm_, "[ Call"); |
2959 | 3283 |
2960 Expression* function = node->expression(); | 3284 Expression* function = node->expression(); |
2961 ZoneList<Expression*>* args = node->arguments(); | 3285 ZoneList<Expression*>* args = node->arguments(); |
2962 | 3286 |
2963 // Standard function call. | 3287 // Standard function call. |
2964 // Check if the function is a variable or a property. | 3288 // Check if the function is a variable or a property. |
2965 Variable* var = function->AsVariableProxy()->AsVariable(); | 3289 Variable* var = function->AsVariableProxy()->AsVariable(); |
2966 Property* property = function->AsProperty(); | 3290 Property* property = function->AsProperty(); |
2967 | 3291 |
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3138 frame_->EmitPush(r0); | 3462 frame_->EmitPush(r0); |
3139 } | 3463 } |
3140 ASSERT(frame_->height() == original_height + 1); | 3464 ASSERT(frame_->height() == original_height + 1); |
3141 } | 3465 } |
3142 | 3466 |
3143 | 3467 |
3144 void CodeGenerator::VisitCallNew(CallNew* node) { | 3468 void CodeGenerator::VisitCallNew(CallNew* node) { |
3145 #ifdef DEBUG | 3469 #ifdef DEBUG |
3146 int original_height = frame_->height(); | 3470 int original_height = frame_->height(); |
3147 #endif | 3471 #endif |
3148 VirtualFrame::SpilledScope spilled_scope; | 3472 VirtualFrame::SpilledScope spilled_scope(frame_); |
3149 Comment cmnt(masm_, "[ CallNew"); | 3473 Comment cmnt(masm_, "[ CallNew"); |
3150 | 3474 |
3151 // According to ECMA-262, section 11.2.2, page 44, the function | 3475 // According to ECMA-262, section 11.2.2, page 44, the function |
3152 // expression in new calls must be evaluated before the | 3476 // expression in new calls must be evaluated before the |
3153 // arguments. This is different from ordinary calls, where the | 3477 // arguments. This is different from ordinary calls, where the |
3154 // actual function to call is resolved after the arguments have been | 3478 // actual function to call is resolved after the arguments have been |
3155 // evaluated. | 3479 // evaluated. |
3156 | 3480 |
3157 // Compute function to call and use the global object as the | 3481 // Compute function to call and use the global object as the |
3158 // receiver. There is no need to use the global proxy here because | 3482 // receiver. There is no need to use the global proxy here because |
(...skipping 19 matching lines...) Expand all Loading... | |
3178 Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall)); | 3502 Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall)); |
3179 frame_->CallCodeObject(ic, RelocInfo::CONSTRUCT_CALL, arg_count + 1); | 3503 frame_->CallCodeObject(ic, RelocInfo::CONSTRUCT_CALL, arg_count + 1); |
3180 | 3504 |
3181 // Discard old TOS value and push r0 on the stack (same as Pop(), push(r0)). | 3505 // Discard old TOS value and push r0 on the stack (same as Pop(), push(r0)). |
3182 __ str(r0, frame_->Top()); | 3506 __ str(r0, frame_->Top()); |
3183 ASSERT(frame_->height() == original_height + 1); | 3507 ASSERT(frame_->height() == original_height + 1); |
3184 } | 3508 } |
3185 | 3509 |
3186 | 3510 |
3187 void CodeGenerator::GenerateClassOf(ZoneList<Expression*>* args) { | 3511 void CodeGenerator::GenerateClassOf(ZoneList<Expression*>* args) { |
3188 VirtualFrame::SpilledScope spilled_scope; | 3512 VirtualFrame::SpilledScope spilled_scope(frame_); |
3189 ASSERT(args->length() == 1); | 3513 ASSERT(args->length() == 1); |
3190 JumpTarget leave, null, function, non_function_constructor; | 3514 JumpTarget leave, null, function, non_function_constructor; |
3191 | 3515 |
3192 // Load the object into r0. | 3516 // Load the object into r0. |
3193 LoadAndSpill(args->at(0)); | 3517 LoadAndSpill(args->at(0)); |
3194 frame_->EmitPop(r0); | 3518 frame_->EmitPop(r0); |
3195 | 3519 |
3196 // If the object is a smi, we return null. | 3520 // If the object is a smi, we return null. |
3197 __ tst(r0, Operand(kSmiTagMask)); | 3521 __ tst(r0, Operand(kSmiTagMask)); |
3198 null.Branch(eq); | 3522 null.Branch(eq); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3238 null.Bind(); | 3562 null.Bind(); |
3239 __ LoadRoot(r0, Heap::kNullValueRootIndex); | 3563 __ LoadRoot(r0, Heap::kNullValueRootIndex); |
3240 frame_->EmitPush(r0); | 3564 frame_->EmitPush(r0); |
3241 | 3565 |
3242 // All done. | 3566 // All done. |
3243 leave.Bind(); | 3567 leave.Bind(); |
3244 } | 3568 } |
3245 | 3569 |
3246 | 3570 |
3247 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { | 3571 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { |
3248 VirtualFrame::SpilledScope spilled_scope; | 3572 VirtualFrame::SpilledScope spilled_scope(frame_); |
3249 ASSERT(args->length() == 1); | 3573 ASSERT(args->length() == 1); |
3250 JumpTarget leave; | 3574 JumpTarget leave; |
3251 LoadAndSpill(args->at(0)); | 3575 LoadAndSpill(args->at(0)); |
3252 frame_->EmitPop(r0); // r0 contains object. | 3576 frame_->EmitPop(r0); // r0 contains object. |
3253 // if (object->IsSmi()) return the object. | 3577 // if (object->IsSmi()) return the object. |
3254 __ tst(r0, Operand(kSmiTagMask)); | 3578 __ tst(r0, Operand(kSmiTagMask)); |
3255 leave.Branch(eq); | 3579 leave.Branch(eq); |
3256 // It is a heap object - get map. If (!object->IsJSValue()) return the object. | 3580 // It is a heap object - get map. If (!object->IsJSValue()) return the object. |
3257 __ CompareObjectType(r0, r1, r1, JS_VALUE_TYPE); | 3581 __ CompareObjectType(r0, r1, r1, JS_VALUE_TYPE); |
3258 leave.Branch(ne); | 3582 leave.Branch(ne); |
3259 // Load the value. | 3583 // Load the value. |
3260 __ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset)); | 3584 __ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset)); |
3261 leave.Bind(); | 3585 leave.Bind(); |
3262 frame_->EmitPush(r0); | 3586 frame_->EmitPush(r0); |
3263 } | 3587 } |
3264 | 3588 |
3265 | 3589 |
3266 void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) { | 3590 void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) { |
3267 VirtualFrame::SpilledScope spilled_scope; | 3591 VirtualFrame::SpilledScope spilled_scope(frame_); |
3268 ASSERT(args->length() == 2); | 3592 ASSERT(args->length() == 2); |
3269 JumpTarget leave; | 3593 JumpTarget leave; |
3270 LoadAndSpill(args->at(0)); // Load the object. | 3594 LoadAndSpill(args->at(0)); // Load the object. |
3271 LoadAndSpill(args->at(1)); // Load the value. | 3595 LoadAndSpill(args->at(1)); // Load the value. |
3272 frame_->EmitPop(r0); // r0 contains value | 3596 frame_->EmitPop(r0); // r0 contains value |
3273 frame_->EmitPop(r1); // r1 contains object | 3597 frame_->EmitPop(r1); // r1 contains object |
3274 // if (object->IsSmi()) return object. | 3598 // if (object->IsSmi()) return object. |
3275 __ tst(r1, Operand(kSmiTagMask)); | 3599 __ tst(r1, Operand(kSmiTagMask)); |
3276 leave.Branch(eq); | 3600 leave.Branch(eq); |
3277 // It is a heap object - get map. If (!object->IsJSValue()) return the object. | 3601 // It is a heap object - get map. If (!object->IsJSValue()) return the object. |
3278 __ CompareObjectType(r1, r2, r2, JS_VALUE_TYPE); | 3602 __ CompareObjectType(r1, r2, r2, JS_VALUE_TYPE); |
3279 leave.Branch(ne); | 3603 leave.Branch(ne); |
3280 // Store the value. | 3604 // Store the value. |
3281 __ str(r0, FieldMemOperand(r1, JSValue::kValueOffset)); | 3605 __ str(r0, FieldMemOperand(r1, JSValue::kValueOffset)); |
3282 // Update the write barrier. | 3606 // Update the write barrier. |
3283 __ mov(r2, Operand(JSValue::kValueOffset - kHeapObjectTag)); | 3607 __ mov(r2, Operand(JSValue::kValueOffset - kHeapObjectTag)); |
3284 __ RecordWrite(r1, r2, r3); | 3608 __ RecordWrite(r1, r2, r3); |
3285 // Leave. | 3609 // Leave. |
3286 leave.Bind(); | 3610 leave.Bind(); |
3287 frame_->EmitPush(r0); | 3611 frame_->EmitPush(r0); |
3288 } | 3612 } |
3289 | 3613 |
3290 | 3614 |
3291 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { | 3615 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { |
3292 VirtualFrame::SpilledScope spilled_scope; | 3616 VirtualFrame::SpilledScope spilled_scope(frame_); |
3293 ASSERT(args->length() == 1); | 3617 ASSERT(args->length() == 1); |
3294 LoadAndSpill(args->at(0)); | 3618 LoadAndSpill(args->at(0)); |
3295 frame_->EmitPop(r0); | 3619 frame_->EmitPop(r0); |
3296 __ tst(r0, Operand(kSmiTagMask)); | 3620 __ tst(r0, Operand(kSmiTagMask)); |
3297 cc_reg_ = eq; | 3621 cc_reg_ = eq; |
3298 } | 3622 } |
3299 | 3623 |
3300 | 3624 |
3301 void CodeGenerator::GenerateLog(ZoneList<Expression*>* args) { | 3625 void CodeGenerator::GenerateLog(ZoneList<Expression*>* args) { |
3302 VirtualFrame::SpilledScope spilled_scope; | 3626 VirtualFrame::SpilledScope spilled_scope(frame_); |
3303 // See comment in CodeGenerator::GenerateLog in codegen-ia32.cc. | 3627 // See comment in CodeGenerator::GenerateLog in codegen-ia32.cc. |
3304 ASSERT_EQ(args->length(), 3); | 3628 ASSERT_EQ(args->length(), 3); |
3305 #ifdef ENABLE_LOGGING_AND_PROFILING | 3629 #ifdef ENABLE_LOGGING_AND_PROFILING |
3306 if (ShouldGenerateLog(args->at(0))) { | 3630 if (ShouldGenerateLog(args->at(0))) { |
3307 LoadAndSpill(args->at(1)); | 3631 LoadAndSpill(args->at(1)); |
3308 LoadAndSpill(args->at(2)); | 3632 LoadAndSpill(args->at(2)); |
3309 __ CallRuntime(Runtime::kLog, 2); | 3633 __ CallRuntime(Runtime::kLog, 2); |
3310 } | 3634 } |
3311 #endif | 3635 #endif |
3312 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); | 3636 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); |
3313 frame_->EmitPush(r0); | 3637 frame_->EmitPush(r0); |
3314 } | 3638 } |
3315 | 3639 |
3316 | 3640 |
3317 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { | 3641 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { |
3318 VirtualFrame::SpilledScope spilled_scope; | 3642 VirtualFrame::SpilledScope spilled_scope(frame_); |
3319 ASSERT(args->length() == 1); | 3643 ASSERT(args->length() == 1); |
3320 LoadAndSpill(args->at(0)); | 3644 LoadAndSpill(args->at(0)); |
3321 frame_->EmitPop(r0); | 3645 frame_->EmitPop(r0); |
3322 __ tst(r0, Operand(kSmiTagMask | 0x80000000u)); | 3646 __ tst(r0, Operand(kSmiTagMask | 0x80000000u)); |
3323 cc_reg_ = eq; | 3647 cc_reg_ = eq; |
3324 } | 3648 } |
3325 | 3649 |
3326 | 3650 |
3327 // Generates the Math.pow method - currently just calls runtime. | 3651 // Generates the Math.pow method - currently just calls runtime. |
3328 void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) { | 3652 void CodeGenerator::GenerateMathPow(ZoneList<Expression*>* args) { |
(...skipping 11 matching lines...) Expand all Loading... | |
3340 Load(args->at(0)); | 3664 Load(args->at(0)); |
3341 frame_->CallRuntime(Runtime::kMath_sqrt, 1); | 3665 frame_->CallRuntime(Runtime::kMath_sqrt, 1); |
3342 frame_->EmitPush(r0); | 3666 frame_->EmitPush(r0); |
3343 } | 3667 } |
3344 | 3668 |
3345 | 3669 |
3346 // This should generate code that performs a charCodeAt() call or returns | 3670 // This should generate code that performs a charCodeAt() call or returns |
3347 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. | 3671 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. |
3348 // It is not yet implemented on ARM, so it always goes to the slow case. | 3672 // It is not yet implemented on ARM, so it always goes to the slow case. |
3349 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { | 3673 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { |
3350 VirtualFrame::SpilledScope spilled_scope; | 3674 VirtualFrame::SpilledScope spilled_scope(frame_); |
3351 ASSERT(args->length() == 2); | 3675 ASSERT(args->length() == 2); |
3352 Comment(masm_, "[ GenerateFastCharCodeAt"); | 3676 Comment(masm_, "[ GenerateFastCharCodeAt"); |
3353 | 3677 |
3354 LoadAndSpill(args->at(0)); | 3678 LoadAndSpill(args->at(0)); |
3355 LoadAndSpill(args->at(1)); | 3679 LoadAndSpill(args->at(1)); |
3356 frame_->EmitPop(r0); // Index. | 3680 frame_->EmitPop(r0); // Index. |
3357 frame_->EmitPop(r1); // String. | 3681 frame_->EmitPop(r1); // String. |
3358 | 3682 |
3359 Label slow, end, not_a_flat_string, ascii_string, try_again_with_new_string; | 3683 Label slow, end, not_a_flat_string, ascii_string, try_again_with_new_string; |
3360 | 3684 |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3458 slow_case.Bind(); | 3782 slow_case.Bind(); |
3459 frame_->EmitPush(r0); | 3783 frame_->EmitPush(r0); |
3460 frame_->CallRuntime(Runtime::kCharFromCode, 1); | 3784 frame_->CallRuntime(Runtime::kCharFromCode, 1); |
3461 frame_->EmitPush(r0); | 3785 frame_->EmitPush(r0); |
3462 | 3786 |
3463 exit.Bind(); | 3787 exit.Bind(); |
3464 } | 3788 } |
3465 | 3789 |
3466 | 3790 |
3467 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { | 3791 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { |
3468 VirtualFrame::SpilledScope spilled_scope; | 3792 VirtualFrame::SpilledScope spilled_scope(frame_); |
3469 ASSERT(args->length() == 1); | 3793 ASSERT(args->length() == 1); |
3470 LoadAndSpill(args->at(0)); | 3794 LoadAndSpill(args->at(0)); |
3471 JumpTarget answer; | 3795 JumpTarget answer; |
3472 // We need the CC bits to come out as not_equal in the case where the | 3796 // We need the CC bits to come out as not_equal in the case where the |
3473 // object is a smi. This can't be done with the usual test opcode so | 3797 // object is a smi. This can't be done with the usual test opcode so |
3474 // we use XOR to get the right CC bits. | 3798 // we use XOR to get the right CC bits. |
3475 frame_->EmitPop(r0); | 3799 frame_->EmitPop(r0); |
3476 __ and_(r1, r0, Operand(kSmiTagMask)); | 3800 __ and_(r1, r0, Operand(kSmiTagMask)); |
3477 __ eor(r1, r1, Operand(kSmiTagMask), SetCC); | 3801 __ eor(r1, r1, Operand(kSmiTagMask), SetCC); |
3478 answer.Branch(ne); | 3802 answer.Branch(ne); |
3479 // It is a heap object - get the map. Check if the object is a JS array. | 3803 // It is a heap object - get the map. Check if the object is a JS array. |
3480 __ CompareObjectType(r0, r1, r1, JS_ARRAY_TYPE); | 3804 __ CompareObjectType(r0, r1, r1, JS_ARRAY_TYPE); |
3481 answer.Bind(); | 3805 answer.Bind(); |
3482 cc_reg_ = eq; | 3806 cc_reg_ = eq; |
3483 } | 3807 } |
3484 | 3808 |
3485 | 3809 |
3486 void CodeGenerator::GenerateIsRegExp(ZoneList<Expression*>* args) { | 3810 void CodeGenerator::GenerateIsRegExp(ZoneList<Expression*>* args) { |
3487 VirtualFrame::SpilledScope spilled_scope; | 3811 VirtualFrame::SpilledScope spilled_scope(frame_); |
3488 ASSERT(args->length() == 1); | 3812 ASSERT(args->length() == 1); |
3489 LoadAndSpill(args->at(0)); | 3813 LoadAndSpill(args->at(0)); |
3490 JumpTarget answer; | 3814 JumpTarget answer; |
3491 // We need the CC bits to come out as not_equal in the case where the | 3815 // We need the CC bits to come out as not_equal in the case where the |
3492 // object is a smi. This can't be done with the usual test opcode so | 3816 // object is a smi. This can't be done with the usual test opcode so |
3493 // we use XOR to get the right CC bits. | 3817 // we use XOR to get the right CC bits. |
3494 frame_->EmitPop(r0); | 3818 frame_->EmitPop(r0); |
3495 __ and_(r1, r0, Operand(kSmiTagMask)); | 3819 __ and_(r1, r0, Operand(kSmiTagMask)); |
3496 __ eor(r1, r1, Operand(kSmiTagMask), SetCC); | 3820 __ eor(r1, r1, Operand(kSmiTagMask), SetCC); |
3497 answer.Branch(ne); | 3821 answer.Branch(ne); |
3498 // It is a heap object - get the map. Check if the object is a regexp. | 3822 // It is a heap object - get the map. Check if the object is a regexp. |
3499 __ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE); | 3823 __ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE); |
3500 answer.Bind(); | 3824 answer.Bind(); |
3501 cc_reg_ = eq; | 3825 cc_reg_ = eq; |
3502 } | 3826 } |
3503 | 3827 |
3504 | 3828 |
3505 void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) { | 3829 void CodeGenerator::GenerateIsObject(ZoneList<Expression*>* args) { |
3506 // This generates a fast version of: | 3830 // This generates a fast version of: |
3507 // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp') | 3831 // (typeof(arg) === 'object' || %_ClassOf(arg) == 'RegExp') |
3508 VirtualFrame::SpilledScope spilled_scope; | 3832 VirtualFrame::SpilledScope spilled_scope(frame_); |
3509 ASSERT(args->length() == 1); | 3833 ASSERT(args->length() == 1); |
3510 LoadAndSpill(args->at(0)); | 3834 LoadAndSpill(args->at(0)); |
3511 frame_->EmitPop(r1); | 3835 frame_->EmitPop(r1); |
3512 __ tst(r1, Operand(kSmiTagMask)); | 3836 __ tst(r1, Operand(kSmiTagMask)); |
3513 false_target()->Branch(eq); | 3837 false_target()->Branch(eq); |
3514 | 3838 |
3515 __ LoadRoot(ip, Heap::kNullValueRootIndex); | 3839 __ LoadRoot(ip, Heap::kNullValueRootIndex); |
3516 __ cmp(r1, ip); | 3840 __ cmp(r1, ip); |
3517 true_target()->Branch(eq); | 3841 true_target()->Branch(eq); |
3518 | 3842 |
3519 Register map_reg = r2; | 3843 Register map_reg = r2; |
3520 __ ldr(map_reg, FieldMemOperand(r1, HeapObject::kMapOffset)); | 3844 __ ldr(map_reg, FieldMemOperand(r1, HeapObject::kMapOffset)); |
3521 // Undetectable objects behave like undefined when tested with typeof. | 3845 // Undetectable objects behave like undefined when tested with typeof. |
3522 __ ldrb(r1, FieldMemOperand(map_reg, Map::kBitFieldOffset)); | 3846 __ ldrb(r1, FieldMemOperand(map_reg, Map::kBitFieldOffset)); |
3523 __ and_(r1, r1, Operand(1 << Map::kIsUndetectable)); | 3847 __ and_(r1, r1, Operand(1 << Map::kIsUndetectable)); |
3524 __ cmp(r1, Operand(1 << Map::kIsUndetectable)); | 3848 __ cmp(r1, Operand(1 << Map::kIsUndetectable)); |
3525 false_target()->Branch(eq); | 3849 false_target()->Branch(eq); |
3526 | 3850 |
3527 __ ldrb(r1, FieldMemOperand(map_reg, Map::kInstanceTypeOffset)); | 3851 __ ldrb(r1, FieldMemOperand(map_reg, Map::kInstanceTypeOffset)); |
3528 __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE)); | 3852 __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE)); |
3529 false_target()->Branch(lt); | 3853 false_target()->Branch(lt); |
3530 __ cmp(r1, Operand(LAST_JS_OBJECT_TYPE)); | 3854 __ cmp(r1, Operand(LAST_JS_OBJECT_TYPE)); |
3531 cc_reg_ = le; | 3855 cc_reg_ = le; |
3532 } | 3856 } |
3533 | 3857 |
3534 | 3858 |
3535 void CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) { | 3859 void CodeGenerator::GenerateIsFunction(ZoneList<Expression*>* args) { |
3536 // This generates a fast version of: | 3860 // This generates a fast version of: |
3537 // (%_ClassOf(arg) === 'Function') | 3861 // (%_ClassOf(arg) === 'Function') |
3538 VirtualFrame::SpilledScope spilled_scope; | 3862 VirtualFrame::SpilledScope spilled_scope(frame_); |
3539 ASSERT(args->length() == 1); | 3863 ASSERT(args->length() == 1); |
3540 LoadAndSpill(args->at(0)); | 3864 LoadAndSpill(args->at(0)); |
3541 frame_->EmitPop(r0); | 3865 frame_->EmitPop(r0); |
3542 __ tst(r0, Operand(kSmiTagMask)); | 3866 __ tst(r0, Operand(kSmiTagMask)); |
3543 false_target()->Branch(eq); | 3867 false_target()->Branch(eq); |
3544 Register map_reg = r2; | 3868 Register map_reg = r2; |
3545 __ CompareObjectType(r0, map_reg, r1, JS_FUNCTION_TYPE); | 3869 __ CompareObjectType(r0, map_reg, r1, JS_FUNCTION_TYPE); |
3546 cc_reg_ = eq; | 3870 cc_reg_ = eq; |
3547 } | 3871 } |
3548 | 3872 |
3549 | 3873 |
3550 void CodeGenerator::GenerateIsUndetectableObject(ZoneList<Expression*>* args) { | 3874 void CodeGenerator::GenerateIsUndetectableObject(ZoneList<Expression*>* args) { |
3551 VirtualFrame::SpilledScope spilled_scope; | 3875 VirtualFrame::SpilledScope spilled_scope(frame_); |
3552 ASSERT(args->length() == 1); | 3876 ASSERT(args->length() == 1); |
3553 LoadAndSpill(args->at(0)); | 3877 LoadAndSpill(args->at(0)); |
3554 frame_->EmitPop(r0); | 3878 frame_->EmitPop(r0); |
3555 __ tst(r0, Operand(kSmiTagMask)); | 3879 __ tst(r0, Operand(kSmiTagMask)); |
3556 false_target()->Branch(eq); | 3880 false_target()->Branch(eq); |
3557 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); | 3881 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset)); |
3558 __ ldrb(r1, FieldMemOperand(r1, Map::kBitFieldOffset)); | 3882 __ ldrb(r1, FieldMemOperand(r1, Map::kBitFieldOffset)); |
3559 __ tst(r1, Operand(1 << Map::kIsUndetectable)); | 3883 __ tst(r1, Operand(1 << Map::kIsUndetectable)); |
3560 cc_reg_ = ne; | 3884 cc_reg_ = ne; |
3561 } | 3885 } |
3562 | 3886 |
3563 | 3887 |
3564 void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) { | 3888 void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) { |
3565 VirtualFrame::SpilledScope spilled_scope; | 3889 VirtualFrame::SpilledScope spilled_scope(frame_); |
3566 ASSERT(args->length() == 0); | 3890 ASSERT(args->length() == 0); |
3567 | 3891 |
3568 // Get the frame pointer for the calling frame. | 3892 // Get the frame pointer for the calling frame. |
3569 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); | 3893 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); |
3570 | 3894 |
3571 // Skip the arguments adaptor frame if it exists. | 3895 // Skip the arguments adaptor frame if it exists. |
3572 Label check_frame_marker; | 3896 Label check_frame_marker; |
3573 __ ldr(r1, MemOperand(r2, StandardFrameConstants::kContextOffset)); | 3897 __ ldr(r1, MemOperand(r2, StandardFrameConstants::kContextOffset)); |
3574 __ cmp(r1, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); | 3898 __ cmp(r1, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
3575 __ b(ne, &check_frame_marker); | 3899 __ b(ne, &check_frame_marker); |
3576 __ ldr(r2, MemOperand(r2, StandardFrameConstants::kCallerFPOffset)); | 3900 __ ldr(r2, MemOperand(r2, StandardFrameConstants::kCallerFPOffset)); |
3577 | 3901 |
3578 // Check the marker in the calling frame. | 3902 // Check the marker in the calling frame. |
3579 __ bind(&check_frame_marker); | 3903 __ bind(&check_frame_marker); |
3580 __ ldr(r1, MemOperand(r2, StandardFrameConstants::kMarkerOffset)); | 3904 __ ldr(r1, MemOperand(r2, StandardFrameConstants::kMarkerOffset)); |
3581 __ cmp(r1, Operand(Smi::FromInt(StackFrame::CONSTRUCT))); | 3905 __ cmp(r1, Operand(Smi::FromInt(StackFrame::CONSTRUCT))); |
3582 cc_reg_ = eq; | 3906 cc_reg_ = eq; |
3583 } | 3907 } |
3584 | 3908 |
3585 | 3909 |
3586 void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) { | 3910 void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) { |
3587 VirtualFrame::SpilledScope spilled_scope; | 3911 VirtualFrame::SpilledScope spilled_scope(frame_); |
3588 ASSERT(args->length() == 0); | 3912 ASSERT(args->length() == 0); |
3589 | 3913 |
3590 Label exit; | 3914 Label exit; |
3591 | 3915 |
3592 // Get the number of formal parameters. | 3916 // Get the number of formal parameters. |
3593 __ mov(r0, Operand(Smi::FromInt(scope()->num_parameters()))); | 3917 __ mov(r0, Operand(Smi::FromInt(scope()->num_parameters()))); |
3594 | 3918 |
3595 // Check if the calling frame is an arguments adaptor frame. | 3919 // Check if the calling frame is an arguments adaptor frame. |
3596 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); | 3920 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset)); |
3597 __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset)); | 3921 __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset)); |
3598 __ cmp(r3, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); | 3922 __ cmp(r3, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
3599 __ b(ne, &exit); | 3923 __ b(ne, &exit); |
3600 | 3924 |
3601 // Arguments adaptor case: Read the arguments length from the | 3925 // Arguments adaptor case: Read the arguments length from the |
3602 // adaptor frame. | 3926 // adaptor frame. |
3603 __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 3927 __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
3604 | 3928 |
3605 __ bind(&exit); | 3929 __ bind(&exit); |
3606 frame_->EmitPush(r0); | 3930 frame_->EmitPush(r0); |
3607 } | 3931 } |
3608 | 3932 |
3609 | 3933 |
3610 void CodeGenerator::GenerateArguments(ZoneList<Expression*>* args) { | 3934 void CodeGenerator::GenerateArguments(ZoneList<Expression*>* args) { |
3611 VirtualFrame::SpilledScope spilled_scope; | 3935 VirtualFrame::SpilledScope spilled_scope(frame_); |
3612 ASSERT(args->length() == 1); | 3936 ASSERT(args->length() == 1); |
3613 | 3937 |
3614 // Satisfy contract with ArgumentsAccessStub: | 3938 // Satisfy contract with ArgumentsAccessStub: |
3615 // Load the key into r1 and the formal parameters count into r0. | 3939 // Load the key into r1 and the formal parameters count into r0. |
3616 LoadAndSpill(args->at(0)); | 3940 LoadAndSpill(args->at(0)); |
3617 frame_->EmitPop(r1); | 3941 frame_->EmitPop(r1); |
3618 __ mov(r0, Operand(Smi::FromInt(scope()->num_parameters()))); | 3942 __ mov(r0, Operand(Smi::FromInt(scope()->num_parameters()))); |
3619 | 3943 |
3620 // Call the shared stub to get to arguments[key]. | 3944 // Call the shared stub to get to arguments[key]. |
3621 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); | 3945 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); |
3622 frame_->CallStub(&stub, 0); | 3946 frame_->CallStub(&stub, 0); |
3623 frame_->EmitPush(r0); | 3947 frame_->EmitPush(r0); |
3624 } | 3948 } |
3625 | 3949 |
3626 | 3950 |
3627 void CodeGenerator::GenerateRandomPositiveSmi(ZoneList<Expression*>* args) { | 3951 void CodeGenerator::GenerateRandomPositiveSmi(ZoneList<Expression*>* args) { |
3628 VirtualFrame::SpilledScope spilled_scope; | 3952 VirtualFrame::SpilledScope spilled_scope(frame_); |
3629 ASSERT(args->length() == 0); | 3953 ASSERT(args->length() == 0); |
3630 __ Call(ExternalReference::random_positive_smi_function().address(), | 3954 __ Call(ExternalReference::random_positive_smi_function().address(), |
3631 RelocInfo::RUNTIME_ENTRY); | 3955 RelocInfo::RUNTIME_ENTRY); |
3632 frame_->EmitPush(r0); | 3956 frame_->EmitPush(r0); |
3633 } | 3957 } |
3634 | 3958 |
3635 | 3959 |
3636 void CodeGenerator::GenerateStringAdd(ZoneList<Expression*>* args) { | 3960 void CodeGenerator::GenerateStringAdd(ZoneList<Expression*>* args) { |
3637 ASSERT_EQ(2, args->length()); | 3961 ASSERT_EQ(2, args->length()); |
3638 | 3962 |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3707 void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) { | 4031 void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) { |
3708 ASSERT_EQ(args->length(), 1); | 4032 ASSERT_EQ(args->length(), 1); |
3709 // Load the argument on the stack and jump to the runtime. | 4033 // Load the argument on the stack and jump to the runtime. |
3710 Load(args->at(0)); | 4034 Load(args->at(0)); |
3711 frame_->CallRuntime(Runtime::kMath_cos, 1); | 4035 frame_->CallRuntime(Runtime::kMath_cos, 1); |
3712 frame_->EmitPush(r0); | 4036 frame_->EmitPush(r0); |
3713 } | 4037 } |
3714 | 4038 |
3715 | 4039 |
3716 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { | 4040 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { |
3717 VirtualFrame::SpilledScope spilled_scope; | 4041 VirtualFrame::SpilledScope spilled_scope(frame_); |
3718 ASSERT(args->length() == 2); | 4042 ASSERT(args->length() == 2); |
3719 | 4043 |
3720 // Load the two objects into registers and perform the comparison. | 4044 // Load the two objects into registers and perform the comparison. |
3721 LoadAndSpill(args->at(0)); | 4045 LoadAndSpill(args->at(0)); |
3722 LoadAndSpill(args->at(1)); | 4046 LoadAndSpill(args->at(1)); |
3723 frame_->EmitPop(r0); | 4047 frame_->EmitPop(r0); |
3724 frame_->EmitPop(r1); | 4048 frame_->EmitPop(r1); |
3725 __ cmp(r0, Operand(r1)); | 4049 __ cmp(r0, Operand(r1)); |
3726 cc_reg_ = eq; | 4050 cc_reg_ = eq; |
3727 } | 4051 } |
3728 | 4052 |
3729 | 4053 |
3730 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { | 4054 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { |
3731 #ifdef DEBUG | 4055 #ifdef DEBUG |
3732 int original_height = frame_->height(); | 4056 int original_height = frame_->height(); |
3733 #endif | 4057 #endif |
3734 VirtualFrame::SpilledScope spilled_scope; | 4058 VirtualFrame::SpilledScope spilled_scope(frame_); |
3735 if (CheckForInlineRuntimeCall(node)) { | 4059 if (CheckForInlineRuntimeCall(node)) { |
3736 ASSERT((has_cc() && frame_->height() == original_height) || | 4060 ASSERT((has_cc() && frame_->height() == original_height) || |
3737 (!has_cc() && frame_->height() == original_height + 1)); | 4061 (!has_cc() && frame_->height() == original_height + 1)); |
3738 return; | 4062 return; |
3739 } | 4063 } |
3740 | 4064 |
3741 ZoneList<Expression*>* args = node->arguments(); | 4065 ZoneList<Expression*>* args = node->arguments(); |
3742 Comment cmnt(masm_, "[ CallRuntime"); | 4066 Comment cmnt(masm_, "[ CallRuntime"); |
3743 Runtime::Function* function = node->function(); | 4067 Runtime::Function* function = node->function(); |
3744 | 4068 |
(...skipping 25 matching lines...) Expand all Loading... | |
3770 frame_->EmitPush(r0); | 4094 frame_->EmitPush(r0); |
3771 } | 4095 } |
3772 ASSERT(frame_->height() == original_height + 1); | 4096 ASSERT(frame_->height() == original_height + 1); |
3773 } | 4097 } |
3774 | 4098 |
3775 | 4099 |
3776 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { | 4100 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { |
3777 #ifdef DEBUG | 4101 #ifdef DEBUG |
3778 int original_height = frame_->height(); | 4102 int original_height = frame_->height(); |
3779 #endif | 4103 #endif |
3780 VirtualFrame::SpilledScope spilled_scope; | 4104 VirtualFrame::SpilledScope spilled_scope(frame_); |
3781 Comment cmnt(masm_, "[ UnaryOperation"); | 4105 Comment cmnt(masm_, "[ UnaryOperation"); |
3782 | 4106 |
3783 Token::Value op = node->op(); | 4107 Token::Value op = node->op(); |
3784 | 4108 |
3785 if (op == Token::NOT) { | 4109 if (op == Token::NOT) { |
3786 LoadConditionAndSpill(node->expression(), | 4110 LoadConditionAndSpill(node->expression(), |
3787 false_target(), | 4111 false_target(), |
3788 true_target(), | 4112 true_target(), |
3789 true); | 4113 true); |
3790 // LoadCondition may (and usually does) leave a test and branch to | 4114 // LoadCondition may (and usually does) leave a test and branch to |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3901 ASSERT(!has_valid_frame() || | 4225 ASSERT(!has_valid_frame() || |
3902 (has_cc() && frame_->height() == original_height) || | 4226 (has_cc() && frame_->height() == original_height) || |
3903 (!has_cc() && frame_->height() == original_height + 1)); | 4227 (!has_cc() && frame_->height() == original_height + 1)); |
3904 } | 4228 } |
3905 | 4229 |
3906 | 4230 |
3907 void CodeGenerator::VisitCountOperation(CountOperation* node) { | 4231 void CodeGenerator::VisitCountOperation(CountOperation* node) { |
3908 #ifdef DEBUG | 4232 #ifdef DEBUG |
3909 int original_height = frame_->height(); | 4233 int original_height = frame_->height(); |
3910 #endif | 4234 #endif |
3911 VirtualFrame::SpilledScope spilled_scope; | 4235 VirtualFrame::SpilledScope spilled_scope(frame_); |
3912 Comment cmnt(masm_, "[ CountOperation"); | 4236 Comment cmnt(masm_, "[ CountOperation"); |
3913 | 4237 |
3914 bool is_postfix = node->is_postfix(); | 4238 bool is_postfix = node->is_postfix(); |
3915 bool is_increment = node->op() == Token::INC; | 4239 bool is_increment = node->op() == Token::INC; |
3916 | 4240 |
3917 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); | 4241 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); |
3918 bool is_const = (var != NULL && var->mode() == Variable::CONST); | 4242 bool is_const = (var != NULL && var->mode() == Variable::CONST); |
3919 | 4243 |
3920 // Postfix: Make room for the result. | 4244 // Postfix: Make room for the result. |
3921 if (is_postfix) { | 4245 if (is_postfix) { |
3922 __ mov(r0, Operand(0)); | 4246 __ mov(r0, Operand(0)); |
3923 frame_->EmitPush(r0); | 4247 frame_->EmitPush(r0); |
3924 } | 4248 } |
3925 | 4249 |
3926 // A constant reference is not saved to, so a constant reference is not a | 4250 // A constant reference is not saved to, so a constant reference is not a |
3927 // compound assignment reference. | 4251 // compound assignment reference. |
3928 { Reference target(this, node->expression(), !is_const); | 4252 { Reference target(this, node->expression(), !is_const); |
3929 if (target.is_illegal()) { | 4253 if (target.is_illegal()) { |
3930 // Spoof the virtual frame to have the expected height (one higher | 4254 // Spoof the virtual frame to have the expected height (one higher |
3931 // than on entry). | 4255 // than on entry). |
3932 if (!is_postfix) { | 4256 if (!is_postfix) { |
3933 __ mov(r0, Operand(Smi::FromInt(0))); | 4257 __ mov(r0, Operand(Smi::FromInt(0))); |
3934 frame_->EmitPush(r0); | 4258 frame_->EmitPush(r0); |
3935 } | 4259 } |
3936 ASSERT(frame_->height() == original_height + 1); | 4260 ASSERT(frame_->height() == original_height + 1); |
3937 return; | 4261 return; |
3938 } | 4262 } |
3939 target.GetValueAndSpill(); | 4263 target.GetValue(); |
3940 frame_->EmitPop(r0); | 4264 frame_->EmitPop(r0); |
3941 | 4265 |
3942 JumpTarget slow; | 4266 JumpTarget slow; |
3943 JumpTarget exit; | 4267 JumpTarget exit; |
3944 | 4268 |
3945 // Load the value (1) into register r1. | 4269 // Load the value (1) into register r1. |
3946 __ mov(r1, Operand(Smi::FromInt(1))); | 4270 __ mov(r1, Operand(Smi::FromInt(1))); |
3947 | 4271 |
3948 // Check for smi operand. | 4272 // Check for smi operand. |
3949 __ tst(r0, Operand(kSmiTagMask)); | 4273 __ tst(r0, Operand(kSmiTagMask)); |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4110 ASSERT(!has_valid_frame() && !has_cc() && !is_false.is_linked()); | 4434 ASSERT(!has_valid_frame() && !has_cc() && !is_false.is_linked()); |
4111 } | 4435 } |
4112 } | 4436 } |
4113 } | 4437 } |
4114 | 4438 |
4115 | 4439 |
4116 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { | 4440 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { |
4117 #ifdef DEBUG | 4441 #ifdef DEBUG |
4118 int original_height = frame_->height(); | 4442 int original_height = frame_->height(); |
4119 #endif | 4443 #endif |
4120 VirtualFrame::SpilledScope spilled_scope; | |
4121 Comment cmnt(masm_, "[ BinaryOperation"); | 4444 Comment cmnt(masm_, "[ BinaryOperation"); |
4122 | 4445 |
4123 if (node->op() == Token::AND || node->op() == Token::OR) { | 4446 if (node->op() == Token::AND || node->op() == Token::OR) { |
4447 VirtualFrame::SpilledScope spilled_scope(frame_); | |
4124 GenerateLogicalBooleanOperation(node); | 4448 GenerateLogicalBooleanOperation(node); |
4125 } else { | 4449 } else { |
4126 // Optimize for the case where (at least) one of the expressions | 4450 // Optimize for the case where (at least) one of the expressions |
4127 // is a literal small integer. | 4451 // is a literal small integer. |
4128 Literal* lliteral = node->left()->AsLiteral(); | 4452 Literal* lliteral = node->left()->AsLiteral(); |
4129 Literal* rliteral = node->right()->AsLiteral(); | 4453 Literal* rliteral = node->right()->AsLiteral(); |
4130 // NOTE: The code below assumes that the slow cases (calls to runtime) | 4454 // NOTE: The code below assumes that the slow cases (calls to runtime) |
4131 // never return a constant/immutable object. | 4455 // never return a constant/immutable object. |
4132 bool overwrite_left = | 4456 bool overwrite_left = |
4133 (node->left()->AsBinaryOperation() != NULL && | 4457 (node->left()->AsBinaryOperation() != NULL && |
4134 node->left()->AsBinaryOperation()->ResultOverwriteAllowed()); | 4458 node->left()->AsBinaryOperation()->ResultOverwriteAllowed()); |
4135 bool overwrite_right = | 4459 bool overwrite_right = |
4136 (node->right()->AsBinaryOperation() != NULL && | 4460 (node->right()->AsBinaryOperation() != NULL && |
4137 node->right()->AsBinaryOperation()->ResultOverwriteAllowed()); | 4461 node->right()->AsBinaryOperation()->ResultOverwriteAllowed()); |
4138 | 4462 |
4139 if (rliteral != NULL && rliteral->handle()->IsSmi()) { | 4463 if (rliteral != NULL && rliteral->handle()->IsSmi()) { |
4140 LoadAndSpill(node->left()); | 4464 VirtualFrame::RegisterAllocationScope scope(this); |
4141 SmiOperation(node->op(), | 4465 Load(node->left()); |
4142 rliteral->handle(), | 4466 VirtualFrameSmiOperation( |
4143 false, | 4467 node->op(), |
4144 overwrite_right ? OVERWRITE_RIGHT : NO_OVERWRITE); | 4468 rliteral->handle(), |
4145 | 4469 false, |
4470 overwrite_right ? OVERWRITE_RIGHT : NO_OVERWRITE); | |
4146 } else if (lliteral != NULL && lliteral->handle()->IsSmi()) { | 4471 } else if (lliteral != NULL && lliteral->handle()->IsSmi()) { |
4147 LoadAndSpill(node->right()); | 4472 VirtualFrame::RegisterAllocationScope scope(this); |
4148 SmiOperation(node->op(), | 4473 Load(node->right()); |
4149 lliteral->handle(), | 4474 VirtualFrameSmiOperation(node->op(), |
4150 true, | 4475 lliteral->handle(), |
4151 overwrite_left ? OVERWRITE_LEFT : NO_OVERWRITE); | 4476 true, |
4152 | 4477 overwrite_left ? OVERWRITE_LEFT : NO_OVERWRITE); |
4153 } else { | 4478 } else { |
4479 VirtualFrame::RegisterAllocationScope scope(this); | |
4154 OverwriteMode overwrite_mode = NO_OVERWRITE; | 4480 OverwriteMode overwrite_mode = NO_OVERWRITE; |
4155 if (overwrite_left) { | 4481 if (overwrite_left) { |
4156 overwrite_mode = OVERWRITE_LEFT; | 4482 overwrite_mode = OVERWRITE_LEFT; |
4157 } else if (overwrite_right) { | 4483 } else if (overwrite_right) { |
4158 overwrite_mode = OVERWRITE_RIGHT; | 4484 overwrite_mode = OVERWRITE_RIGHT; |
4159 } | 4485 } |
4160 LoadAndSpill(node->left()); | 4486 Load(node->left()); |
4161 LoadAndSpill(node->right()); | 4487 Load(node->right()); |
4162 GenericBinaryOperation(node->op(), overwrite_mode); | 4488 VirtualFrameBinaryOperation(node->op(), overwrite_mode); |
4163 } | 4489 } |
4164 frame_->EmitPush(r0); | |
4165 } | 4490 } |
4166 ASSERT(!has_valid_frame() || | 4491 ASSERT(!has_valid_frame() || |
4167 (has_cc() && frame_->height() == original_height) || | 4492 (has_cc() && frame_->height() == original_height) || |
4168 (!has_cc() && frame_->height() == original_height + 1)); | 4493 (!has_cc() && frame_->height() == original_height + 1)); |
4169 } | 4494 } |
4170 | 4495 |
4171 | 4496 |
4172 void CodeGenerator::VisitThisFunction(ThisFunction* node) { | 4497 void CodeGenerator::VisitThisFunction(ThisFunction* node) { |
4173 #ifdef DEBUG | 4498 #ifdef DEBUG |
4174 int original_height = frame_->height(); | 4499 int original_height = frame_->height(); |
4175 #endif | 4500 #endif |
4176 VirtualFrame::SpilledScope spilled_scope; | 4501 VirtualFrame::SpilledScope spilled_scope(frame_); |
4177 __ ldr(r0, frame_->Function()); | 4502 __ ldr(r0, frame_->Function()); |
4178 frame_->EmitPush(r0); | 4503 frame_->EmitPush(r0); |
4179 ASSERT(frame_->height() == original_height + 1); | 4504 ASSERT(frame_->height() == original_height + 1); |
4180 } | 4505 } |
4181 | 4506 |
4182 | 4507 |
4183 void CodeGenerator::VisitCompareOperation(CompareOperation* node) { | 4508 void CodeGenerator::VisitCompareOperation(CompareOperation* node) { |
4184 #ifdef DEBUG | 4509 #ifdef DEBUG |
4185 int original_height = frame_->height(); | 4510 int original_height = frame_->height(); |
4186 #endif | 4511 #endif |
4187 VirtualFrame::SpilledScope spilled_scope; | |
4188 Comment cmnt(masm_, "[ CompareOperation"); | 4512 Comment cmnt(masm_, "[ CompareOperation"); |
4189 | 4513 |
4514 VirtualFrame::RegisterAllocationScope nonspilled_scope(this); | |
4515 | |
4190 // Get the expressions from the node. | 4516 // Get the expressions from the node. |
4191 Expression* left = node->left(); | 4517 Expression* left = node->left(); |
4192 Expression* right = node->right(); | 4518 Expression* right = node->right(); |
4193 Token::Value op = node->op(); | 4519 Token::Value op = node->op(); |
4194 | 4520 |
4195 // To make null checks efficient, we check if either left or right is the | 4521 // To make null checks efficient, we check if either left or right is the |
4196 // literal 'null'. If so, we optimize the code by inlining a null check | 4522 // literal 'null'. If so, we optimize the code by inlining a null check |
4197 // instead of calling the (very) general runtime routine for checking | 4523 // instead of calling the (very) general runtime routine for checking |
4198 // equality. | 4524 // equality. |
4199 if (op == Token::EQ || op == Token::EQ_STRICT) { | 4525 if (op == Token::EQ || op == Token::EQ_STRICT) { |
4200 bool left_is_null = | 4526 bool left_is_null = |
4201 left->AsLiteral() != NULL && left->AsLiteral()->IsNull(); | 4527 left->AsLiteral() != NULL && left->AsLiteral()->IsNull(); |
4202 bool right_is_null = | 4528 bool right_is_null = |
4203 right->AsLiteral() != NULL && right->AsLiteral()->IsNull(); | 4529 right->AsLiteral() != NULL && right->AsLiteral()->IsNull(); |
4204 // The 'null' value can only be equal to 'null' or 'undefined'. | 4530 // The 'null' value can only be equal to 'null' or 'undefined'. |
4205 if (left_is_null || right_is_null) { | 4531 if (left_is_null || right_is_null) { |
4206 LoadAndSpill(left_is_null ? right : left); | 4532 Load(left_is_null ? right : left); |
4207 frame_->EmitPop(r0); | 4533 Register tos = frame_->PopToRegister(); |
4534 // JumpTargets can't cope with register allocation yet. | |
4535 frame_->SpillAll(); | |
4208 __ LoadRoot(ip, Heap::kNullValueRootIndex); | 4536 __ LoadRoot(ip, Heap::kNullValueRootIndex); |
4209 __ cmp(r0, ip); | 4537 __ cmp(tos, ip); |
4210 | 4538 |
4211 // The 'null' value is only equal to 'undefined' if using non-strict | 4539 // The 'null' value is only equal to 'undefined' if using non-strict |
4212 // comparisons. | 4540 // comparisons. |
4213 if (op != Token::EQ_STRICT) { | 4541 if (op != Token::EQ_STRICT) { |
4214 true_target()->Branch(eq); | 4542 true_target()->Branch(eq); |
4215 | 4543 |
4216 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); | 4544 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); |
4217 __ cmp(r0, Operand(ip)); | 4545 __ cmp(tos, Operand(ip)); |
4218 true_target()->Branch(eq); | 4546 true_target()->Branch(eq); |
4219 | 4547 |
4220 __ tst(r0, Operand(kSmiTagMask)); | 4548 __ tst(tos, Operand(kSmiTagMask)); |
4221 false_target()->Branch(eq); | 4549 false_target()->Branch(eq); |
4222 | 4550 |
4223 // It can be an undetectable object. | 4551 // It can be an undetectable object. |
4224 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset)); | 4552 __ ldr(tos, FieldMemOperand(tos, HeapObject::kMapOffset)); |
4225 __ ldrb(r0, FieldMemOperand(r0, Map::kBitFieldOffset)); | 4553 __ ldrb(tos, FieldMemOperand(tos, Map::kBitFieldOffset)); |
4226 __ and_(r0, r0, Operand(1 << Map::kIsUndetectable)); | 4554 __ and_(tos, tos, Operand(1 << Map::kIsUndetectable)); |
4227 __ cmp(r0, Operand(1 << Map::kIsUndetectable)); | 4555 __ cmp(tos, Operand(1 << Map::kIsUndetectable)); |
4228 } | 4556 } |
4229 | 4557 |
4230 cc_reg_ = eq; | 4558 cc_reg_ = eq; |
4231 ASSERT(has_cc() && frame_->height() == original_height); | 4559 ASSERT(has_cc() && frame_->height() == original_height); |
4232 return; | 4560 return; |
4233 } | 4561 } |
4234 } | 4562 } |
4235 | 4563 |
4236 // To make typeof testing for natives implemented in JavaScript really | 4564 // To make typeof testing for natives implemented in JavaScript really |
4237 // efficient, we generate special code for expressions of the form: | 4565 // efficient, we generate special code for expressions of the form: |
4238 // 'typeof <expression> == <string>'. | 4566 // 'typeof <expression> == <string>'. |
4239 UnaryOperation* operation = left->AsUnaryOperation(); | 4567 UnaryOperation* operation = left->AsUnaryOperation(); |
4240 if ((op == Token::EQ || op == Token::EQ_STRICT) && | 4568 if ((op == Token::EQ || op == Token::EQ_STRICT) && |
4241 (operation != NULL && operation->op() == Token::TYPEOF) && | 4569 (operation != NULL && operation->op() == Token::TYPEOF) && |
4242 (right->AsLiteral() != NULL && | 4570 (right->AsLiteral() != NULL && |
4243 right->AsLiteral()->handle()->IsString())) { | 4571 right->AsLiteral()->handle()->IsString())) { |
4244 Handle<String> check(String::cast(*right->AsLiteral()->handle())); | 4572 Handle<String> check(String::cast(*right->AsLiteral()->handle())); |
4245 | 4573 |
4246 // Load the operand, move it to register r1. | 4574 // Load the operand, move it to register r0 or r1. |
Søren Thygesen Gjesse
2010/04/07 07:53:37
This comment implies that PopToRegister will alway
Erik Corry
2010/04/07 12:49:17
We didn't actually use the fact that it is always
| |
4247 LoadTypeofExpression(operation->expression()); | 4575 LoadTypeofExpression(operation->expression()); |
4248 frame_->EmitPop(r1); | 4576 Register tos = frame_->PopToRegister(); |
4577 | |
4578 // JumpTargets can't cope with register allocation yet. | |
4579 frame_->SpillAll(); | |
4580 | |
4581 Register scratch = VirtualFrame::scratch0(); | |
4249 | 4582 |
4250 if (check->Equals(Heap::number_symbol())) { | 4583 if (check->Equals(Heap::number_symbol())) { |
4251 __ tst(r1, Operand(kSmiTagMask)); | 4584 __ tst(tos, Operand(kSmiTagMask)); |
4252 true_target()->Branch(eq); | 4585 true_target()->Branch(eq); |
4253 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); | 4586 __ ldr(tos, FieldMemOperand(tos, HeapObject::kMapOffset)); |
4254 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); | 4587 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex); |
4255 __ cmp(r1, ip); | 4588 __ cmp(tos, ip); |
4256 cc_reg_ = eq; | 4589 cc_reg_ = eq; |
4257 | 4590 |
4258 } else if (check->Equals(Heap::string_symbol())) { | 4591 } else if (check->Equals(Heap::string_symbol())) { |
4259 __ tst(r1, Operand(kSmiTagMask)); | 4592 __ tst(tos, Operand(kSmiTagMask)); |
4260 false_target()->Branch(eq); | 4593 false_target()->Branch(eq); |
4261 | 4594 |
4262 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); | 4595 __ ldr(tos, FieldMemOperand(tos, HeapObject::kMapOffset)); |
4263 | 4596 |
4264 // It can be an undetectable string object. | 4597 // It can be an undetectable string object. |
4265 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset)); | 4598 __ ldrb(scratch, FieldMemOperand(tos, Map::kBitFieldOffset)); |
4266 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable)); | 4599 __ and_(scratch, scratch, Operand(1 << Map::kIsUndetectable)); |
4267 __ cmp(r2, Operand(1 << Map::kIsUndetectable)); | 4600 __ cmp(scratch, Operand(1 << Map::kIsUndetectable)); |
4268 false_target()->Branch(eq); | 4601 false_target()->Branch(eq); |
4269 | 4602 |
4270 __ ldrb(r2, FieldMemOperand(r1, Map::kInstanceTypeOffset)); | 4603 __ ldrb(scratch, FieldMemOperand(tos, Map::kInstanceTypeOffset)); |
4271 __ cmp(r2, Operand(FIRST_NONSTRING_TYPE)); | 4604 __ cmp(scratch, Operand(FIRST_NONSTRING_TYPE)); |
4272 cc_reg_ = lt; | 4605 cc_reg_ = lt; |
4273 | 4606 |
4274 } else if (check->Equals(Heap::boolean_symbol())) { | 4607 } else if (check->Equals(Heap::boolean_symbol())) { |
4275 __ LoadRoot(ip, Heap::kTrueValueRootIndex); | 4608 __ LoadRoot(ip, Heap::kTrueValueRootIndex); |
4276 __ cmp(r1, ip); | 4609 __ cmp(tos, ip); |
4277 true_target()->Branch(eq); | 4610 true_target()->Branch(eq); |
4278 __ LoadRoot(ip, Heap::kFalseValueRootIndex); | 4611 __ LoadRoot(ip, Heap::kFalseValueRootIndex); |
4279 __ cmp(r1, ip); | 4612 __ cmp(tos, ip); |
4280 cc_reg_ = eq; | 4613 cc_reg_ = eq; |
4281 | 4614 |
4282 } else if (check->Equals(Heap::undefined_symbol())) { | 4615 } else if (check->Equals(Heap::undefined_symbol())) { |
4283 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); | 4616 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); |
4284 __ cmp(r1, ip); | 4617 __ cmp(tos, ip); |
4285 true_target()->Branch(eq); | 4618 true_target()->Branch(eq); |
4286 | 4619 |
4287 __ tst(r1, Operand(kSmiTagMask)); | 4620 __ tst(tos, Operand(kSmiTagMask)); |
4288 false_target()->Branch(eq); | 4621 false_target()->Branch(eq); |
4289 | 4622 |
4290 // It can be an undetectable object. | 4623 // It can be an undetectable object. |
4291 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset)); | 4624 __ ldr(tos, FieldMemOperand(tos, HeapObject::kMapOffset)); |
4292 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset)); | 4625 __ ldrb(scratch, FieldMemOperand(tos, Map::kBitFieldOffset)); |
4293 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable)); | 4626 __ and_(scratch, scratch, Operand(1 << Map::kIsUndetectable)); |
4294 __ cmp(r2, Operand(1 << Map::kIsUndetectable)); | 4627 __ cmp(scratch, Operand(1 << Map::kIsUndetectable)); |
4295 | 4628 |
4296 cc_reg_ = eq; | 4629 cc_reg_ = eq; |
4297 | 4630 |
4298 } else if (check->Equals(Heap::function_symbol())) { | 4631 } else if (check->Equals(Heap::function_symbol())) { |
4299 __ tst(r1, Operand(kSmiTagMask)); | 4632 __ tst(tos, Operand(kSmiTagMask)); |
4300 false_target()->Branch(eq); | 4633 false_target()->Branch(eq); |
4301 Register map_reg = r2; | 4634 Register map_reg = scratch; |
4302 __ CompareObjectType(r1, map_reg, r1, JS_FUNCTION_TYPE); | 4635 __ CompareObjectType(tos, map_reg, tos, JS_FUNCTION_TYPE); |
4303 true_target()->Branch(eq); | 4636 true_target()->Branch(eq); |
4304 // Regular expressions are callable so typeof == 'function'. | 4637 // Regular expressions are callable so typeof == 'function'. |
4305 __ CompareInstanceType(map_reg, r1, JS_REGEXP_TYPE); | 4638 __ CompareInstanceType(map_reg, tos, JS_REGEXP_TYPE); |
4306 cc_reg_ = eq; | 4639 cc_reg_ = eq; |
4307 | 4640 |
4308 } else if (check->Equals(Heap::object_symbol())) { | 4641 } else if (check->Equals(Heap::object_symbol())) { |
4309 __ tst(r1, Operand(kSmiTagMask)); | 4642 __ tst(tos, Operand(kSmiTagMask)); |
4310 false_target()->Branch(eq); | 4643 false_target()->Branch(eq); |
4311 | 4644 |
4312 __ LoadRoot(ip, Heap::kNullValueRootIndex); | 4645 __ LoadRoot(ip, Heap::kNullValueRootIndex); |
4313 __ cmp(r1, ip); | 4646 __ cmp(tos, ip); |
4314 true_target()->Branch(eq); | 4647 true_target()->Branch(eq); |
4315 | 4648 |
4316 Register map_reg = r2; | 4649 Register map_reg = scratch; |
4317 __ CompareObjectType(r1, map_reg, r1, JS_REGEXP_TYPE); | 4650 __ CompareObjectType(tos, map_reg, tos, JS_REGEXP_TYPE); |
4318 false_target()->Branch(eq); | 4651 false_target()->Branch(eq); |
4319 | 4652 |
4320 // It can be an undetectable object. | 4653 // It can be an undetectable object. |
4321 __ ldrb(r1, FieldMemOperand(map_reg, Map::kBitFieldOffset)); | 4654 __ ldrb(tos, FieldMemOperand(map_reg, Map::kBitFieldOffset)); |
4322 __ and_(r1, r1, Operand(1 << Map::kIsUndetectable)); | 4655 __ and_(tos, tos, Operand(1 << Map::kIsUndetectable)); |
4323 __ cmp(r1, Operand(1 << Map::kIsUndetectable)); | 4656 __ cmp(tos, Operand(1 << Map::kIsUndetectable)); |
4324 false_target()->Branch(eq); | 4657 false_target()->Branch(eq); |
4325 | 4658 |
4326 __ ldrb(r1, FieldMemOperand(map_reg, Map::kInstanceTypeOffset)); | 4659 __ ldrb(tos, FieldMemOperand(map_reg, Map::kInstanceTypeOffset)); |
4327 __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE)); | 4660 __ cmp(tos, Operand(FIRST_JS_OBJECT_TYPE)); |
4328 false_target()->Branch(lt); | 4661 false_target()->Branch(lt); |
4329 __ cmp(r1, Operand(LAST_JS_OBJECT_TYPE)); | 4662 __ cmp(tos, Operand(LAST_JS_OBJECT_TYPE)); |
4330 cc_reg_ = le; | 4663 cc_reg_ = le; |
4331 | 4664 |
4332 } else { | 4665 } else { |
4333 // Uncommon case: typeof testing against a string literal that is | 4666 // Uncommon case: typeof testing against a string literal that is |
4334 // never returned from the typeof operator. | 4667 // never returned from the typeof operator. |
4335 false_target()->Jump(); | 4668 false_target()->Jump(); |
4336 } | 4669 } |
4337 ASSERT(!has_valid_frame() || | 4670 ASSERT(!has_valid_frame() || |
4338 (has_cc() && frame_->height() == original_height)); | 4671 (has_cc() && frame_->height() == original_height)); |
4339 return; | 4672 return; |
(...skipping 18 matching lines...) Expand all Loading... | |
4358 | 4691 |
4359 case Token::GTE: | 4692 case Token::GTE: |
4360 Comparison(ge, left, right); | 4693 Comparison(ge, left, right); |
4361 break; | 4694 break; |
4362 | 4695 |
4363 case Token::EQ_STRICT: | 4696 case Token::EQ_STRICT: |
4364 Comparison(eq, left, right, true); | 4697 Comparison(eq, left, right, true); |
4365 break; | 4698 break; |
4366 | 4699 |
4367 case Token::IN: { | 4700 case Token::IN: { |
4701 VirtualFrame::SpilledScope scope(frame_); | |
4368 LoadAndSpill(left); | 4702 LoadAndSpill(left); |
4369 LoadAndSpill(right); | 4703 LoadAndSpill(right); |
4370 frame_->InvokeBuiltin(Builtins::IN, CALL_JS, 2); | 4704 frame_->InvokeBuiltin(Builtins::IN, CALL_JS, 2); |
4371 frame_->EmitPush(r0); | 4705 frame_->EmitPush(r0); |
4372 break; | 4706 break; |
4373 } | 4707 } |
4374 | 4708 |
4375 case Token::INSTANCEOF: { | 4709 case Token::INSTANCEOF: { |
4710 VirtualFrame::SpilledScope scope(frame_); | |
4376 LoadAndSpill(left); | 4711 LoadAndSpill(left); |
4377 LoadAndSpill(right); | 4712 LoadAndSpill(right); |
4378 InstanceofStub stub; | 4713 InstanceofStub stub; |
4379 frame_->CallStub(&stub, 2); | 4714 frame_->CallStub(&stub, 2); |
4380 // At this point if instanceof succeeded then r0 == 0. | 4715 // At this point if instanceof succeeded then r0 == 0. |
4381 __ tst(r0, Operand(r0)); | 4716 __ tst(r0, Operand(r0)); |
4382 cc_reg_ = eq; | 4717 cc_reg_ = eq; |
4383 break; | 4718 break; |
4384 } | 4719 } |
4385 | 4720 |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4497 switch (type_) { | 4832 switch (type_) { |
4498 case SLOT: { | 4833 case SLOT: { |
4499 Comment cmnt(masm, "[ Store to Slot"); | 4834 Comment cmnt(masm, "[ Store to Slot"); |
4500 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | 4835 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); |
4501 cgen_->StoreToSlot(slot, init_state); | 4836 cgen_->StoreToSlot(slot, init_state); |
4502 cgen_->UnloadReference(this); | 4837 cgen_->UnloadReference(this); |
4503 break; | 4838 break; |
4504 } | 4839 } |
4505 | 4840 |
4506 case NAMED: { | 4841 case NAMED: { |
4842 VirtualFrame::SpilledScope scope(frame); | |
4507 Comment cmnt(masm, "[ Store to named Property"); | 4843 Comment cmnt(masm, "[ Store to named Property"); |
4508 // Call the appropriate IC code. | 4844 // Call the appropriate IC code. |
4509 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 4845 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
4510 Handle<String> name(GetName()); | 4846 Handle<String> name(GetName()); |
4511 | 4847 |
4512 frame->EmitPop(r0); | 4848 frame->EmitPop(r0); |
4513 frame->EmitPop(r1); | 4849 frame->EmitPop(r1); |
4514 __ mov(r2, Operand(name)); | 4850 __ mov(r2, Operand(name)); |
4515 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); | 4851 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); |
4516 frame->EmitPush(r0); | 4852 frame->EmitPush(r0); |
4517 set_unloaded(); | 4853 set_unloaded(); |
4518 break; | 4854 break; |
4519 } | 4855 } |
4520 | 4856 |
4521 case KEYED: { | 4857 case KEYED: { |
4858 VirtualFrame::SpilledScope scope(frame); | |
4522 Comment cmnt(masm, "[ Store to keyed Property"); | 4859 Comment cmnt(masm, "[ Store to keyed Property"); |
4523 Property* property = expression_->AsProperty(); | 4860 Property* property = expression_->AsProperty(); |
4524 ASSERT(property != NULL); | 4861 ASSERT(property != NULL); |
4525 cgen_->CodeForSourcePosition(property->position()); | 4862 cgen_->CodeForSourcePosition(property->position()); |
4526 | 4863 |
4527 // Call IC code. | 4864 // Call IC code. |
4528 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | 4865 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); |
4529 frame->EmitPop(r0); // value | 4866 frame->EmitPop(r0); // value |
4530 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); | 4867 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0); |
4531 frame->EmitPush(r0); | 4868 frame->EmitPush(r0); |
(...skipping 3411 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
7943 | 8280 |
7944 // Just jump to runtime to add the two strings. | 8281 // Just jump to runtime to add the two strings. |
7945 __ bind(&string_add_runtime); | 8282 __ bind(&string_add_runtime); |
7946 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | 8283 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); |
7947 } | 8284 } |
7948 | 8285 |
7949 | 8286 |
7950 #undef __ | 8287 #undef __ |
7951 | 8288 |
7952 } } // namespace v8::internal | 8289 } } // namespace v8::internal |
OLD | NEW |