Chromium Code Reviews| 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 |