| 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 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 132 owner_->set_state(this); | 132 owner_->set_state(this); |
| 133 } | 133 } |
| 134 | 134 |
| 135 | 135 |
| 136 CodeGenState::~CodeGenState() { | 136 CodeGenState::~CodeGenState() { |
| 137 ASSERT(owner_->state() == this); | 137 ASSERT(owner_->state() == this); |
| 138 owner_->set_state(previous_); | 138 owner_->set_state(previous_); |
| 139 } | 139 } |
| 140 | 140 |
| 141 | 141 |
| 142 // ----------------------------------------------------------------------------- | 142 // ------------------------------------------------------------------------- |
| 143 // CodeGenerator implementation. | 143 // CodeGenerator implementation. |
| 144 | 144 |
| 145 CodeGenerator::CodeGenerator(MacroAssembler* masm) | 145 CodeGenerator::CodeGenerator(MacroAssembler* masm) |
| 146 : deferred_(8), | 146 : deferred_(8), |
| 147 masm_(masm), | 147 masm_(masm), |
| 148 info_(NULL), | 148 info_(NULL), |
| 149 frame_(NULL), | 149 frame_(NULL), |
| 150 allocator_(NULL), | 150 allocator_(NULL), |
| 151 state_(NULL), | 151 state_(NULL), |
| 152 loop_nesting_(0), | 152 loop_nesting_(0), |
| 153 function_return_is_shadowed_(false), | 153 function_return_is_shadowed_(false), |
| 154 in_spilled_code_(false) { | 154 in_spilled_code_(false) { |
| 155 } | 155 } |
| 156 | 156 |
| 157 | 157 |
| 158 // Calling conventions: |
| 159 // rbp: caller's frame pointer |
| 160 // rsp: stack pointer |
| 161 // rdi: called JS function |
| 162 // rsi: callee's context |
| 163 |
| 158 void CodeGenerator::Generate(CompilationInfo* info) { | 164 void CodeGenerator::Generate(CompilationInfo* info) { |
| 159 // Record the position for debugging purposes. | 165 // Record the position for debugging purposes. |
| 160 CodeForFunctionPosition(info->function()); | 166 CodeForFunctionPosition(info->function()); |
| 161 Comment cmnt(masm_, "[ function compiled by virtual frame code generator"); | 167 Comment cmnt(masm_, "[ function compiled by virtual frame code generator"); |
| 162 | 168 |
| 163 // Initialize state. | 169 // Initialize state. |
| 164 info_ = info; | 170 info_ = info; |
| 165 ASSERT(allocator_ == NULL); | 171 ASSERT(allocator_ == NULL); |
| 166 RegisterAllocator register_allocator(this); | 172 RegisterAllocator register_allocator(this); |
| 167 allocator_ = ®ister_allocator; | 173 allocator_ = ®ister_allocator; |
| 168 ASSERT(frame_ == NULL); | 174 ASSERT(frame_ == NULL); |
| 169 frame_ = new VirtualFrame(); | 175 frame_ = new VirtualFrame(); |
| 170 set_in_spilled_code(false); | 176 set_in_spilled_code(false); |
| 171 | 177 |
| 172 // Adjust for function-level loop nesting. | 178 // Adjust for function-level loop nesting. |
| 173 ASSERT_EQ(0, loop_nesting_); | 179 ASSERT_EQ(0, loop_nesting_); |
| 174 loop_nesting_ += info->loop_nesting(); | 180 loop_nesting_ = info->loop_nesting(); |
| 175 | 181 |
| 176 JumpTarget::set_compiling_deferred_code(false); | 182 JumpTarget::set_compiling_deferred_code(false); |
| 177 | 183 |
| 178 #ifdef DEBUG | 184 #ifdef DEBUG |
| 179 if (strlen(FLAG_stop_at) > 0 && | 185 if (strlen(FLAG_stop_at) > 0 && |
| 180 info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { | 186 info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) { |
| 181 frame_->SpillAll(); | 187 frame_->SpillAll(); |
| 182 __ int3(); | 188 __ int3(); |
| 183 } | 189 } |
| 184 #endif | 190 #endif |
| (...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 425 // always at a function context. However it is safe to dereference be- | 431 // always at a function context. However it is safe to dereference be- |
| 426 // cause the function context of a function context is itself. Before | 432 // cause the function context of a function context is itself. Before |
| 427 // deleting this mov we should try to create a counter-example first, | 433 // deleting this mov we should try to create a counter-example first, |
| 428 // though...) | 434 // though...) |
| 429 __ movq(tmp, ContextOperand(context, Context::FCONTEXT_INDEX)); | 435 __ movq(tmp, ContextOperand(context, Context::FCONTEXT_INDEX)); |
| 430 return ContextOperand(tmp, index); | 436 return ContextOperand(tmp, index); |
| 431 } | 437 } |
| 432 | 438 |
| 433 default: | 439 default: |
| 434 UNREACHABLE(); | 440 UNREACHABLE(); |
| 435 return Operand(rsp, 0); | 441 return Operand(rax); |
| 436 } | 442 } |
| 437 } | 443 } |
| 438 | 444 |
| 439 | 445 |
| 440 Operand CodeGenerator::ContextSlotOperandCheckExtensions(Slot* slot, | 446 Operand CodeGenerator::ContextSlotOperandCheckExtensions(Slot* slot, |
| 441 Result tmp, | 447 Result tmp, |
| 442 JumpTarget* slow) { | 448 JumpTarget* slow) { |
| 443 ASSERT(slot->type() == Slot::CONTEXT); | 449 ASSERT(slot->type() == Slot::CONTEXT); |
| 444 ASSERT(tmp.is_register()); | 450 ASSERT(tmp.is_register()); |
| 445 Register context = rsi; | 451 Register context = rsi; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 462 slow->Branch(not_equal, not_taken); | 468 slow->Branch(not_equal, not_taken); |
| 463 __ movq(tmp.reg(), ContextOperand(context, Context::FCONTEXT_INDEX)); | 469 __ movq(tmp.reg(), ContextOperand(context, Context::FCONTEXT_INDEX)); |
| 464 return ContextOperand(tmp.reg(), slot->index()); | 470 return ContextOperand(tmp.reg(), slot->index()); |
| 465 } | 471 } |
| 466 | 472 |
| 467 | 473 |
| 468 // Emit code to load the value of an expression to the top of the | 474 // Emit code to load the value of an expression to the top of the |
| 469 // frame. If the expression is boolean-valued it may be compiled (or | 475 // frame. If the expression is boolean-valued it may be compiled (or |
| 470 // partially compiled) into control flow to the control destination. | 476 // partially compiled) into control flow to the control destination. |
| 471 // If force_control is true, control flow is forced. | 477 // If force_control is true, control flow is forced. |
| 472 void CodeGenerator::LoadCondition(Expression* x, | 478 void CodeGenerator::LoadCondition(Expression* expr, |
| 473 ControlDestination* dest, | 479 ControlDestination* dest, |
| 474 bool force_control) { | 480 bool force_control) { |
| 475 ASSERT(!in_spilled_code()); | 481 ASSERT(!in_spilled_code()); |
| 476 int original_height = frame_->height(); | 482 int original_height = frame_->height(); |
| 477 | 483 |
| 478 { CodeGenState new_state(this, dest); | 484 { CodeGenState new_state(this, dest); |
| 479 Visit(x); | 485 Visit(expr); |
| 480 | 486 |
| 481 // If we hit a stack overflow, we may not have actually visited | 487 // If we hit a stack overflow, we may not have actually visited |
| 482 // the expression. In that case, we ensure that we have a | 488 // the expression. In that case, we ensure that we have a |
| 483 // valid-looking frame state because we will continue to generate | 489 // valid-looking frame state because we will continue to generate |
| 484 // code as we unwind the C++ stack. | 490 // code as we unwind the C++ stack. |
| 485 // | 491 // |
| 486 // It's possible to have both a stack overflow and a valid frame | 492 // It's possible to have both a stack overflow and a valid frame |
| 487 // state (eg, a subexpression overflowed, visiting it returned | 493 // state (eg, a subexpression overflowed, visiting it returned |
| 488 // with a dummied frame state, and visiting this expression | 494 // with a dummied frame state, and visiting this expression |
| 489 // returned with a normal-looking state). | 495 // returned with a normal-looking state). |
| 490 if (HasStackOverflow() && | 496 if (HasStackOverflow() && |
| 491 !dest->is_used() && | 497 !dest->is_used() && |
| 492 frame_->height() == original_height) { | 498 frame_->height() == original_height) { |
| 493 dest->Goto(true); | 499 dest->Goto(true); |
| 494 } | 500 } |
| 495 } | 501 } |
| 496 | 502 |
| 497 if (force_control && !dest->is_used()) { | 503 if (force_control && !dest->is_used()) { |
| 498 // Convert the TOS value into flow to the control destination. | 504 // Convert the TOS value into flow to the control destination. |
| 499 // TODO(X64): Make control flow to control destinations work. | |
| 500 ToBoolean(dest); | 505 ToBoolean(dest); |
| 501 } | 506 } |
| 502 | 507 |
| 503 ASSERT(!(force_control && !dest->is_used())); | 508 ASSERT(!(force_control && !dest->is_used())); |
| 504 ASSERT(dest->is_used() || frame_->height() == original_height + 1); | 509 ASSERT(dest->is_used() || frame_->height() == original_height + 1); |
| 505 } | 510 } |
| 506 | 511 |
| 507 | 512 |
| 508 void CodeGenerator::LoadAndSpill(Expression* expression) { | 513 void CodeGenerator::LoadAndSpill(Expression* expression) { |
| 509 // TODO(x64): No architecture specific code. Move to shared location. | |
| 510 ASSERT(in_spilled_code()); | 514 ASSERT(in_spilled_code()); |
| 511 set_in_spilled_code(false); | 515 set_in_spilled_code(false); |
| 512 Load(expression); | 516 Load(expression); |
| 513 frame_->SpillAll(); | 517 frame_->SpillAll(); |
| 514 set_in_spilled_code(true); | 518 set_in_spilled_code(true); |
| 515 } | 519 } |
| 516 | 520 |
| 517 | 521 |
| 518 void CodeGenerator::Load(Expression* expr) { | 522 void CodeGenerator::Load(Expression* expr) { |
| 519 #ifdef DEBUG | 523 #ifdef DEBUG |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 645 frame_->Push(Factory::the_hole_value()); | 649 frame_->Push(Factory::the_hole_value()); |
| 646 } else { | 650 } else { |
| 647 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); | 651 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); |
| 648 frame_->PushFunction(); | 652 frame_->PushFunction(); |
| 649 frame_->PushReceiverSlotAddress(); | 653 frame_->PushReceiverSlotAddress(); |
| 650 frame_->Push(Smi::FromInt(scope()->num_parameters())); | 654 frame_->Push(Smi::FromInt(scope()->num_parameters())); |
| 651 Result result = frame_->CallStub(&stub, 3); | 655 Result result = frame_->CallStub(&stub, 3); |
| 652 frame_->Push(&result); | 656 frame_->Push(&result); |
| 653 } | 657 } |
| 654 | 658 |
| 655 | |
| 656 Variable* arguments = scope()->arguments()->var(); | 659 Variable* arguments = scope()->arguments()->var(); |
| 657 Variable* shadow = scope()->arguments_shadow()->var(); | 660 Variable* shadow = scope()->arguments_shadow()->var(); |
| 658 ASSERT(arguments != NULL && arguments->slot() != NULL); | 661 ASSERT(arguments != NULL && arguments->slot() != NULL); |
| 659 ASSERT(shadow != NULL && shadow->slot() != NULL); | 662 ASSERT(shadow != NULL && shadow->slot() != NULL); |
| 660 JumpTarget done; | 663 JumpTarget done; |
| 661 bool skip_arguments = false; | 664 bool skip_arguments = false; |
| 662 if (mode == LAZY_ARGUMENTS_ALLOCATION && !initial) { | 665 if (mode == LAZY_ARGUMENTS_ALLOCATION && !initial) { |
| 663 // We have to skip storing into the arguments slot if it has | 666 // We have to skip storing into the arguments slot if it has |
| 664 // already been written to. This can happen if the a function | 667 // already been written to. This can happen if the a function |
| 665 // has a local variable named 'arguments'. | 668 // has a local variable named 'arguments'. |
| 666 LoadFromSlot(scope()->arguments()->var()->slot(), NOT_INSIDE_TYPEOF); | 669 LoadFromSlot(arguments->slot(), NOT_INSIDE_TYPEOF); |
| 667 Result probe = frame_->Pop(); | 670 Result probe = frame_->Pop(); |
| 668 if (probe.is_constant()) { | 671 if (probe.is_constant()) { |
| 669 // We have to skip updating the arguments object if it has been | 672 // We have to skip updating the arguments object if it has |
| 670 // assigned a proper value. | 673 // been assigned a proper value. |
| 671 skip_arguments = !probe.handle()->IsTheHole(); | 674 skip_arguments = !probe.handle()->IsTheHole(); |
| 672 } else { | 675 } else { |
| 673 __ CompareRoot(probe.reg(), Heap::kTheHoleValueRootIndex); | 676 __ CompareRoot(probe.reg(), Heap::kTheHoleValueRootIndex); |
| 674 probe.Unuse(); | 677 probe.Unuse(); |
| 675 done.Branch(not_equal); | 678 done.Branch(not_equal); |
| 676 } | 679 } |
| 677 } | 680 } |
| 678 if (!skip_arguments) { | 681 if (!skip_arguments) { |
| 679 StoreToSlot(arguments->slot(), NOT_CONST_INIT); | 682 StoreToSlot(arguments->slot(), NOT_CONST_INIT); |
| 680 if (mode == LAZY_ARGUMENTS_ALLOCATION) done.Bind(); | 683 if (mode == LAZY_ARGUMENTS_ALLOCATION) done.Bind(); |
| 681 } | 684 } |
| 682 StoreToSlot(shadow->slot(), NOT_CONST_INIT); | 685 StoreToSlot(shadow->slot(), NOT_CONST_INIT); |
| 683 return frame_->Pop(); | 686 return frame_->Pop(); |
| 684 } | 687 } |
| 685 | 688 |
| 686 //------------------------------------------------------------------------------ | 689 //------------------------------------------------------------------------------ |
| 687 // CodeGenerator implementation of variables, lookups, and stores. | 690 // CodeGenerator implementation of variables, lookups, and stores. |
| 688 | 691 |
| 689 //------------------------------------------------------------------------------ | |
| 690 // CodeGenerator implementation of variables, lookups, and stores. | |
| 691 | |
| 692 Reference::Reference(CodeGenerator* cgen, | 692 Reference::Reference(CodeGenerator* cgen, |
| 693 Expression* expression, | 693 Expression* expression, |
| 694 bool persist_after_get) | 694 bool persist_after_get) |
| 695 : cgen_(cgen), | 695 : cgen_(cgen), |
| 696 expression_(expression), | 696 expression_(expression), |
| 697 type_(ILLEGAL), | 697 type_(ILLEGAL), |
| 698 persist_after_get_(persist_after_get) { | 698 persist_after_get_(persist_after_get) { |
| 699 cgen->LoadReference(this); | 699 cgen->LoadReference(this); |
| 700 } | 700 } |
| 701 | 701 |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 838 Label* operand_conversion_failure, | 838 Label* operand_conversion_failure, |
| 839 Register heap_number_map); | 839 Register heap_number_map); |
| 840 // As above, but we know the operands to be numbers. In that case, | 840 // As above, but we know the operands to be numbers. In that case, |
| 841 // conversion can't fail. | 841 // conversion can't fail. |
| 842 static void LoadNumbersAsIntegers(MacroAssembler* masm); | 842 static void LoadNumbersAsIntegers(MacroAssembler* masm); |
| 843 }; | 843 }; |
| 844 | 844 |
| 845 | 845 |
| 846 const char* GenericBinaryOpStub::GetName() { | 846 const char* GenericBinaryOpStub::GetName() { |
| 847 if (name_ != NULL) return name_; | 847 if (name_ != NULL) return name_; |
| 848 const int len = 100; | 848 const int kMaxNameLength = 100; |
| 849 name_ = Bootstrapper::AllocateAutoDeletedArray(len); | 849 name_ = Bootstrapper::AllocateAutoDeletedArray(kMaxNameLength); |
| 850 if (name_ == NULL) return "OOM"; | 850 if (name_ == NULL) return "OOM"; |
| 851 const char* op_name = Token::Name(op_); | 851 const char* op_name = Token::Name(op_); |
| 852 const char* overwrite_name; | 852 const char* overwrite_name; |
| 853 switch (mode_) { | 853 switch (mode_) { |
| 854 case NO_OVERWRITE: overwrite_name = "Alloc"; break; | 854 case NO_OVERWRITE: overwrite_name = "Alloc"; break; |
| 855 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; | 855 case OVERWRITE_RIGHT: overwrite_name = "OverwriteRight"; break; |
| 856 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; | 856 case OVERWRITE_LEFT: overwrite_name = "OverwriteLeft"; break; |
| 857 default: overwrite_name = "UnknownOverwrite"; break; | 857 default: overwrite_name = "UnknownOverwrite"; break; |
| 858 } | 858 } |
| 859 | 859 |
| 860 OS::SNPrintF(Vector<char>(name_, len), | 860 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), |
| 861 "GenericBinaryOpStub_%s_%s%s_%s%s_%s_%s", | 861 "GenericBinaryOpStub_%s_%s%s_%s%s_%s_%s", |
| 862 op_name, | 862 op_name, |
| 863 overwrite_name, | 863 overwrite_name, |
| 864 (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "", | 864 (flags_ & NO_SMI_CODE_IN_STUB) ? "_NoSmiInStub" : "", |
| 865 args_in_registers_ ? "RegArgs" : "StackArgs", | 865 args_in_registers_ ? "RegArgs" : "StackArgs", |
| 866 args_reversed_ ? "_R" : "", | 866 args_reversed_ ? "_R" : "", |
| 867 static_operands_type_.ToString(), | 867 static_operands_type_.ToString(), |
| 868 BinaryOpIC::GetName(runtime_operands_type_)); | 868 BinaryOpIC::GetName(runtime_operands_type_)); |
| 869 return name_; | 869 return name_; |
| 870 } | 870 } |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1131 // Use intptr_t to detect overflow of 32-bit int. | 1131 // Use intptr_t to detect overflow of 32-bit int. |
| 1132 if (Smi::IsValid(static_cast<intptr_t>(left) - right)) { | 1132 if (Smi::IsValid(static_cast<intptr_t>(left) - right)) { |
| 1133 answer_object = Smi::FromInt(left - right); | 1133 answer_object = Smi::FromInt(left - right); |
| 1134 } | 1134 } |
| 1135 break; | 1135 break; |
| 1136 case Token::MUL: { | 1136 case Token::MUL: { |
| 1137 double answer = static_cast<double>(left) * right; | 1137 double answer = static_cast<double>(left) * right; |
| 1138 if (answer >= Smi::kMinValue && answer <= Smi::kMaxValue) { | 1138 if (answer >= Smi::kMinValue && answer <= Smi::kMaxValue) { |
| 1139 // If the product is zero and the non-zero factor is negative, | 1139 // If the product is zero and the non-zero factor is negative, |
| 1140 // the spec requires us to return floating point negative zero. | 1140 // the spec requires us to return floating point negative zero. |
| 1141 if (answer != 0 || (left + right) >= 0) { | 1141 if (answer != 0 || (left >= 0 && right >= 0)) { |
| 1142 answer_object = Smi::FromInt(static_cast<int>(answer)); | 1142 answer_object = Smi::FromInt(static_cast<int>(answer)); |
| 1143 } | 1143 } |
| 1144 } | 1144 } |
| 1145 } | 1145 } |
| 1146 break; | 1146 break; |
| 1147 case Token::DIV: | 1147 case Token::DIV: |
| 1148 case Token::MOD: | 1148 case Token::MOD: |
| 1149 break; | 1149 break; |
| 1150 case Token::BIT_OR: | 1150 case Token::BIT_OR: |
| 1151 answer_object = Smi::FromInt(left | right); | 1151 answer_object = Smi::FromInt(left | right); |
| (...skipping 486 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1638 | 1638 |
| 1639 virtual void Generate(); | 1639 virtual void Generate(); |
| 1640 | 1640 |
| 1641 private: | 1641 private: |
| 1642 Register dst_; | 1642 Register dst_; |
| 1643 Smi* value_; | 1643 Smi* value_; |
| 1644 OverwriteMode overwrite_mode_; | 1644 OverwriteMode overwrite_mode_; |
| 1645 }; | 1645 }; |
| 1646 | 1646 |
| 1647 | 1647 |
| 1648 | |
| 1649 void DeferredInlineSmiSub::Generate() { | 1648 void DeferredInlineSmiSub::Generate() { |
| 1650 GenericBinaryOpStub igostub(Token::SUB, overwrite_mode_, NO_SMI_CODE_IN_STUB); | 1649 GenericBinaryOpStub igostub(Token::SUB, overwrite_mode_, NO_SMI_CODE_IN_STUB); |
| 1651 igostub.GenerateCall(masm_, dst_, value_); | 1650 igostub.GenerateCall(masm_, dst_, value_); |
| 1652 if (!dst_.is(rax)) __ movq(dst_, rax); | 1651 if (!dst_.is(rax)) __ movq(dst_, rax); |
| 1653 } | 1652 } |
| 1654 | 1653 |
| 1655 | 1654 |
| 1656 Result CodeGenerator::ConstantSmiBinaryOperation(BinaryOperation* expr, | 1655 Result CodeGenerator::ConstantSmiBinaryOperation(BinaryOperation* expr, |
| 1657 Result* operand, | 1656 Result* operand, |
| 1658 Handle<Object> value, | 1657 Handle<Object> value, |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1703 } | 1702 } |
| 1704 | 1703 |
| 1705 case Token::SUB: { | 1704 case Token::SUB: { |
| 1706 if (reversed) { | 1705 if (reversed) { |
| 1707 Result constant_operand(value); | 1706 Result constant_operand(value); |
| 1708 answer = LikelySmiBinaryOperation(expr, &constant_operand, operand, | 1707 answer = LikelySmiBinaryOperation(expr, &constant_operand, operand, |
| 1709 overwrite_mode); | 1708 overwrite_mode); |
| 1710 } else { | 1709 } else { |
| 1711 operand->ToRegister(); | 1710 operand->ToRegister(); |
| 1712 frame_->Spill(operand->reg()); | 1711 frame_->Spill(operand->reg()); |
| 1712 answer = *operand; |
| 1713 DeferredCode* deferred = new DeferredInlineSmiSub(operand->reg(), | 1713 DeferredCode* deferred = new DeferredInlineSmiSub(operand->reg(), |
| 1714 smi_value, | 1714 smi_value, |
| 1715 overwrite_mode); | 1715 overwrite_mode); |
| 1716 JumpIfNotSmiUsingTypeInfo(operand->reg(), operand->type_info(), | 1716 JumpIfNotSmiUsingTypeInfo(operand->reg(), operand->type_info(), |
| 1717 deferred); | 1717 deferred); |
| 1718 // A smi currently fits in a 32-bit Immediate. | 1718 // A smi currently fits in a 32-bit Immediate. |
| 1719 __ SmiSubConstant(operand->reg(), | 1719 __ SmiSubConstant(operand->reg(), |
| 1720 operand->reg(), | 1720 operand->reg(), |
| 1721 smi_value, | 1721 smi_value, |
| 1722 deferred->entry_label()); | 1722 deferred->entry_label()); |
| 1723 deferred->BindExit(); | 1723 deferred->BindExit(); |
| 1724 answer = *operand; | 1724 operand->Unuse(); |
| 1725 } | 1725 } |
| 1726 break; | 1726 break; |
| 1727 } | 1727 } |
| 1728 | 1728 |
| 1729 case Token::SAR: | 1729 case Token::SAR: |
| 1730 if (reversed) { | 1730 if (reversed) { |
| 1731 Result constant_operand(value); | 1731 Result constant_operand(value); |
| 1732 answer = LikelySmiBinaryOperation(expr, &constant_operand, operand, | 1732 answer = LikelySmiBinaryOperation(expr, &constant_operand, operand, |
| 1733 overwrite_mode); | 1733 overwrite_mode); |
| 1734 } else { | 1734 } else { |
| (...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1925 answer = LikelySmiBinaryOperation(expr, operand, &constant_operand, | 1925 answer = LikelySmiBinaryOperation(expr, operand, &constant_operand, |
| 1926 overwrite_mode); | 1926 overwrite_mode); |
| 1927 } | 1927 } |
| 1928 break; | 1928 break; |
| 1929 } | 1929 } |
| 1930 } | 1930 } |
| 1931 ASSERT(answer.is_valid()); | 1931 ASSERT(answer.is_valid()); |
| 1932 return answer; | 1932 return answer; |
| 1933 } | 1933 } |
| 1934 | 1934 |
| 1935 |
| 1935 static bool CouldBeNaN(const Result& result) { | 1936 static bool CouldBeNaN(const Result& result) { |
| 1936 if (result.type_info().IsSmi()) return false; | 1937 if (result.type_info().IsSmi()) return false; |
| 1937 if (result.type_info().IsInteger32()) return false; | 1938 if (result.type_info().IsInteger32()) return false; |
| 1938 if (!result.is_constant()) return true; | 1939 if (!result.is_constant()) return true; |
| 1939 if (!result.handle()->IsHeapNumber()) return false; | 1940 if (!result.handle()->IsHeapNumber()) return false; |
| 1940 return isnan(HeapNumber::cast(*result.handle())->value()); | 1941 return isnan(HeapNumber::cast(*result.handle())->value()); |
| 1941 } | 1942 } |
| 1942 | 1943 |
| 1943 | 1944 |
| 1944 // Convert from signed to unsigned comparison to match the way EFLAGS are set | 1945 // Convert from signed to unsigned comparison to match the way EFLAGS are set |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2172 Smi::FromInt(1)); | 2173 Smi::FromInt(1)); |
| 2173 __ bind(&characters_were_different); | 2174 __ bind(&characters_were_different); |
| 2174 } | 2175 } |
| 2175 temp2.Unuse(); | 2176 temp2.Unuse(); |
| 2176 left_side.Unuse(); | 2177 left_side.Unuse(); |
| 2177 right_side.Unuse(); | 2178 right_side.Unuse(); |
| 2178 dest->Split(cc); | 2179 dest->Split(cc); |
| 2179 } | 2180 } |
| 2180 } else { | 2181 } else { |
| 2181 // Neither side is a constant Smi, constant 1-char string, or constant null. | 2182 // Neither side is a constant Smi, constant 1-char string, or constant null. |
| 2182 // If either side is a non-smi constant, skip the smi check. | 2183 // If either side is a non-smi constant, or known to be a heap number, |
| 2184 // skip the smi check. |
| 2183 bool known_non_smi = | 2185 bool known_non_smi = |
| 2184 (left_side.is_constant() && !left_side.handle()->IsSmi()) || | 2186 (left_side.is_constant() && !left_side.handle()->IsSmi()) || |
| 2185 (right_side.is_constant() && !right_side.handle()->IsSmi()) || | 2187 (right_side.is_constant() && !right_side.handle()->IsSmi()) || |
| 2186 left_side.type_info().IsDouble() || | 2188 left_side.type_info().IsDouble() || |
| 2187 right_side.type_info().IsDouble(); | 2189 right_side.type_info().IsDouble(); |
| 2188 | 2190 |
| 2189 NaNInformation nan_info = | 2191 NaNInformation nan_info = |
| 2190 (CouldBeNaN(left_side) && CouldBeNaN(right_side)) ? | 2192 (CouldBeNaN(left_side) && CouldBeNaN(right_side)) ? |
| 2191 kBothCouldBeNaN : | 2193 kBothCouldBeNaN : |
| 2192 kCantBothBeNaN; | 2194 kCantBothBeNaN; |
| 2193 | 2195 |
| 2194 // Inline number comparison handling any combination of smi's and heap | 2196 // Inline number comparison handling any combination of smi's and heap |
| 2195 // numbers if: | 2197 // numbers if: |
| 2196 // code is in a loop | 2198 // code is in a loop |
| 2197 // the compare operation is different from equal | 2199 // the compare operation is different from equal |
| 2198 // compare is not a for-loop comparison | 2200 // compare is not a for-loop comparison |
| 2199 // The reason for excluding equal is that it will most likely be done | 2201 // The reason for excluding equal is that it will most likely be done |
| 2200 // with smi's (not heap numbers) and the code to comparing smi's is inlined | 2202 // with smi's (not heap numbers) and the code to comparing smi's is inlined |
| 2201 // separately. The same reason applies for for-loop comparison which will | 2203 // separately. The same reason applies for for-loop comparison which will |
| 2202 // also most likely be smi comparisons. | 2204 // also most likely be smi comparisons. |
| 2203 bool is_loop_condition = (node->AsExpression() != NULL) | 2205 bool is_loop_condition = (node->AsExpression() != NULL) |
| 2204 && node->AsExpression()->is_loop_condition(); | 2206 && node->AsExpression()->is_loop_condition(); |
| 2205 bool inline_number_compare = | 2207 bool inline_number_compare = |
| 2206 loop_nesting() > 0 && cc != equal && !is_loop_condition; | 2208 loop_nesting() > 0 && cc != equal && !is_loop_condition; |
| 2207 | 2209 |
| 2210 // Left and right needed in registers for the following code. |
| 2208 left_side.ToRegister(); | 2211 left_side.ToRegister(); |
| 2209 right_side.ToRegister(); | 2212 right_side.ToRegister(); |
| 2210 | 2213 |
| 2211 if (known_non_smi) { | 2214 if (known_non_smi) { |
| 2212 // Inlined equality check: | 2215 // Inlined equality check: |
| 2213 // If at least one of the objects is not NaN, then if the objects | 2216 // If at least one of the objects is not NaN, then if the objects |
| 2214 // are identical, they are equal. | 2217 // are identical, they are equal. |
| 2215 if (nan_info == kCantBothBeNaN && cc == equal) { | 2218 if (nan_info == kCantBothBeNaN && cc == equal) { |
| 2216 __ cmpq(left_side.reg(), right_side.reg()); | 2219 __ cmpq(left_side.reg(), right_side.reg()); |
| 2217 dest->true_target()->Branch(equal); | 2220 dest->true_target()->Branch(equal); |
| 2218 } | 2221 } |
| 2219 | 2222 |
| 2220 // Inlined number comparison: | 2223 // Inlined number comparison: |
| 2221 if (inline_number_compare) { | 2224 if (inline_number_compare) { |
| 2222 GenerateInlineNumberComparison(&left_side, &right_side, cc, dest); | 2225 GenerateInlineNumberComparison(&left_side, &right_side, cc, dest); |
| 2223 } | 2226 } |
| 2224 | 2227 |
| 2228 // End of in-line compare, call out to the compare stub. Don't include |
| 2229 // number comparison in the stub if it was inlined. |
| 2225 CompareStub stub(cc, strict, nan_info, !inline_number_compare); | 2230 CompareStub stub(cc, strict, nan_info, !inline_number_compare); |
| 2226 Result answer = frame_->CallStub(&stub, &left_side, &right_side); | 2231 Result answer = frame_->CallStub(&stub, &left_side, &right_side); |
| 2227 __ testq(answer.reg(), answer.reg()); // Sets both zero and sign flag. | 2232 __ testq(answer.reg(), answer.reg()); // Sets both zero and sign flag. |
| 2228 answer.Unuse(); | 2233 answer.Unuse(); |
| 2229 dest->Split(cc); | 2234 dest->Split(cc); |
| 2230 } else { | 2235 } else { |
| 2231 // Here we split control flow to the stub call and inlined cases | 2236 // Here we split control flow to the stub call and inlined cases |
| 2232 // before finally splitting it to the control destination. We use | 2237 // before finally splitting it to the control destination. We use |
| 2233 // a jump target and branching to duplicate the virtual frame at | 2238 // a jump target and branching to duplicate the virtual frame at |
| 2234 // the first split. We manually handle the off-frame references | 2239 // the first split. We manually handle the off-frame references |
| (...skipping 10 matching lines...) Expand all Loading... |
| 2245 if (nan_info == kCantBothBeNaN && cc == equal) { | 2250 if (nan_info == kCantBothBeNaN && cc == equal) { |
| 2246 __ cmpq(left_side.reg(), right_side.reg()); | 2251 __ cmpq(left_side.reg(), right_side.reg()); |
| 2247 dest->true_target()->Branch(equal); | 2252 dest->true_target()->Branch(equal); |
| 2248 } | 2253 } |
| 2249 | 2254 |
| 2250 // Inlined number comparison: | 2255 // Inlined number comparison: |
| 2251 if (inline_number_compare) { | 2256 if (inline_number_compare) { |
| 2252 GenerateInlineNumberComparison(&left_side, &right_side, cc, dest); | 2257 GenerateInlineNumberComparison(&left_side, &right_side, cc, dest); |
| 2253 } | 2258 } |
| 2254 | 2259 |
| 2260 // End of in-line compare, call out to the compare stub. Don't include |
| 2261 // number comparison in the stub if it was inlined. |
| 2255 CompareStub stub(cc, strict, nan_info, !inline_number_compare); | 2262 CompareStub stub(cc, strict, nan_info, !inline_number_compare); |
| 2256 Result answer = frame_->CallStub(&stub, &left_side, &right_side); | 2263 Result answer = frame_->CallStub(&stub, &left_side, &right_side); |
| 2257 __ testq(answer.reg(), answer.reg()); // Sets both zero and sign flags. | 2264 __ testq(answer.reg(), answer.reg()); // Sets both zero and sign flags. |
| 2258 answer.Unuse(); | 2265 answer.Unuse(); |
| 2259 dest->true_target()->Branch(cc); | 2266 dest->true_target()->Branch(cc); |
| 2260 dest->false_target()->Jump(); | 2267 dest->false_target()->Jump(); |
| 2261 | 2268 |
| 2262 is_smi.Bind(); | 2269 is_smi.Bind(); |
| 2263 left_side = Result(left_reg); | 2270 left_side = Result(left_reg); |
| 2264 right_side = Result(right_reg); | 2271 right_side = Result(right_reg); |
| (...skipping 432 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2697 | 2704 |
| 2698 void CodeGenerator::CheckStack() { | 2705 void CodeGenerator::CheckStack() { |
| 2699 DeferredStackCheck* deferred = new DeferredStackCheck; | 2706 DeferredStackCheck* deferred = new DeferredStackCheck; |
| 2700 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); | 2707 __ CompareRoot(rsp, Heap::kStackLimitRootIndex); |
| 2701 deferred->Branch(below); | 2708 deferred->Branch(below); |
| 2702 deferred->BindExit(); | 2709 deferred->BindExit(); |
| 2703 } | 2710 } |
| 2704 | 2711 |
| 2705 | 2712 |
| 2706 void CodeGenerator::VisitAndSpill(Statement* statement) { | 2713 void CodeGenerator::VisitAndSpill(Statement* statement) { |
| 2707 // TODO(X64): No architecture specific code. Move to shared location. | |
| 2708 ASSERT(in_spilled_code()); | 2714 ASSERT(in_spilled_code()); |
| 2709 set_in_spilled_code(false); | 2715 set_in_spilled_code(false); |
| 2710 Visit(statement); | 2716 Visit(statement); |
| 2711 if (frame_ != NULL) { | 2717 if (frame_ != NULL) { |
| 2712 frame_->SpillAll(); | 2718 frame_->SpillAll(); |
| 2713 } | 2719 } |
| 2714 set_in_spilled_code(true); | 2720 set_in_spilled_code(true); |
| 2715 } | 2721 } |
| 2716 | 2722 |
| 2717 | 2723 |
| 2718 void CodeGenerator::VisitStatementsAndSpill(ZoneList<Statement*>* statements) { | 2724 void CodeGenerator::VisitStatementsAndSpill(ZoneList<Statement*>* statements) { |
| 2725 #ifdef DEBUG |
| 2726 int original_height = frame_->height(); |
| 2727 #endif |
| 2719 ASSERT(in_spilled_code()); | 2728 ASSERT(in_spilled_code()); |
| 2720 set_in_spilled_code(false); | 2729 set_in_spilled_code(false); |
| 2721 VisitStatements(statements); | 2730 VisitStatements(statements); |
| 2722 if (frame_ != NULL) { | 2731 if (frame_ != NULL) { |
| 2723 frame_->SpillAll(); | 2732 frame_->SpillAll(); |
| 2724 } | 2733 } |
| 2725 set_in_spilled_code(true); | 2734 set_in_spilled_code(true); |
| 2735 |
| 2736 ASSERT(!has_valid_frame() || frame_->height() == original_height); |
| 2726 } | 2737 } |
| 2727 | 2738 |
| 2728 | 2739 |
| 2729 void CodeGenerator::VisitStatements(ZoneList<Statement*>* statements) { | 2740 void CodeGenerator::VisitStatements(ZoneList<Statement*>* statements) { |
| 2741 #ifdef DEBUG |
| 2742 int original_height = frame_->height(); |
| 2743 #endif |
| 2730 ASSERT(!in_spilled_code()); | 2744 ASSERT(!in_spilled_code()); |
| 2731 for (int i = 0; has_valid_frame() && i < statements->length(); i++) { | 2745 for (int i = 0; has_valid_frame() && i < statements->length(); i++) { |
| 2732 Visit(statements->at(i)); | 2746 Visit(statements->at(i)); |
| 2733 } | 2747 } |
| 2748 ASSERT(!has_valid_frame() || frame_->height() == original_height); |
| 2734 } | 2749 } |
| 2735 | 2750 |
| 2736 | 2751 |
| 2737 void CodeGenerator::VisitBlock(Block* node) { | 2752 void CodeGenerator::VisitBlock(Block* node) { |
| 2738 ASSERT(!in_spilled_code()); | 2753 ASSERT(!in_spilled_code()); |
| 2739 Comment cmnt(masm_, "[ Block"); | 2754 Comment cmnt(masm_, "[ Block"); |
| 2740 CodeForStatementPosition(node); | 2755 CodeForStatementPosition(node); |
| 2741 node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); | 2756 node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); |
| 2742 VisitStatements(node->statements()); | 2757 VisitStatements(node->statements()); |
| 2743 if (node->break_target()->is_linked()) { | 2758 if (node->break_target()->is_linked()) { |
| (...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2959 } | 2974 } |
| 2960 | 2975 |
| 2961 | 2976 |
| 2962 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { | 2977 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { |
| 2963 ASSERT(!in_spilled_code()); | 2978 ASSERT(!in_spilled_code()); |
| 2964 Comment cmnt(masm_, "[ ReturnStatement"); | 2979 Comment cmnt(masm_, "[ ReturnStatement"); |
| 2965 | 2980 |
| 2966 CodeForStatementPosition(node); | 2981 CodeForStatementPosition(node); |
| 2967 Load(node->expression()); | 2982 Load(node->expression()); |
| 2968 Result return_value = frame_->Pop(); | 2983 Result return_value = frame_->Pop(); |
| 2984 masm()->WriteRecordedPositions(); |
| 2969 if (function_return_is_shadowed_) { | 2985 if (function_return_is_shadowed_) { |
| 2970 function_return_.Jump(&return_value); | 2986 function_return_.Jump(&return_value); |
| 2971 } else { | 2987 } else { |
| 2972 frame_->PrepareForReturn(); | 2988 frame_->PrepareForReturn(); |
| 2973 if (function_return_.is_bound()) { | 2989 if (function_return_.is_bound()) { |
| 2974 // If the function return label is already bound we reuse the | 2990 // If the function return label is already bound we reuse the |
| 2975 // code by jumping to the return site. | 2991 // code by jumping to the return site. |
| 2976 function_return_.Jump(&return_value); | 2992 function_return_.Jump(&return_value); |
| 2977 } else { | 2993 } else { |
| 2978 function_return_.Bind(&return_value); | 2994 function_return_.Bind(&return_value); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 2996 // Add a label for checking the size of the code used for returning. | 3012 // Add a label for checking the size of the code used for returning. |
| 2997 #ifdef DEBUG | 3013 #ifdef DEBUG |
| 2998 Label check_exit_codesize; | 3014 Label check_exit_codesize; |
| 2999 masm_->bind(&check_exit_codesize); | 3015 masm_->bind(&check_exit_codesize); |
| 3000 #endif | 3016 #endif |
| 3001 | 3017 |
| 3002 // Leave the frame and return popping the arguments and the | 3018 // Leave the frame and return popping the arguments and the |
| 3003 // receiver. | 3019 // receiver. |
| 3004 frame_->Exit(); | 3020 frame_->Exit(); |
| 3005 masm_->ret((scope()->num_parameters() + 1) * kPointerSize); | 3021 masm_->ret((scope()->num_parameters() + 1) * kPointerSize); |
| 3022 DeleteFrame(); |
| 3023 |
| 3006 #ifdef ENABLE_DEBUGGER_SUPPORT | 3024 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 3007 // Add padding that will be overwritten by a debugger breakpoint. | 3025 // Add padding that will be overwritten by a debugger breakpoint. |
| 3008 // frame_->Exit() generates "movq rsp, rbp; pop rbp; ret k" | 3026 // frame_->Exit() generates "movq rsp, rbp; pop rbp; ret k" |
| 3009 // with length 7 (3 + 1 + 3). | 3027 // with length 7 (3 + 1 + 3). |
| 3010 const int kPadding = Assembler::kJSReturnSequenceLength - 7; | 3028 const int kPadding = Assembler::kJSReturnSequenceLength - 7; |
| 3011 for (int i = 0; i < kPadding; ++i) { | 3029 for (int i = 0; i < kPadding; ++i) { |
| 3012 masm_->int3(); | 3030 masm_->int3(); |
| 3013 } | 3031 } |
| 3014 // Check that the size of the code used for returning matches what is | 3032 // Check that the size of the code used for returning matches what is |
| 3015 // expected by the debugger. | 3033 // expected by the debugger. |
| 3016 ASSERT_EQ(Assembler::kJSReturnSequenceLength, | 3034 ASSERT_EQ(Assembler::kJSReturnSequenceLength, |
| 3017 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); | 3035 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); |
| 3018 #endif | 3036 #endif |
| 3019 DeleteFrame(); | |
| 3020 } | 3037 } |
| 3021 | 3038 |
| 3022 | 3039 |
| 3023 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { | 3040 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { |
| 3024 ASSERT(!in_spilled_code()); | 3041 ASSERT(!in_spilled_code()); |
| 3025 Comment cmnt(masm_, "[ WithEnterStatement"); | 3042 Comment cmnt(masm_, "[ WithEnterStatement"); |
| 3026 CodeForStatementPosition(node); | 3043 CodeForStatementPosition(node); |
| 3027 Load(node->expression()); | 3044 Load(node->expression()); |
| 3028 Result context; | 3045 Result context; |
| 3029 if (node->is_catch_block()) { | 3046 if (node->is_catch_block()) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 3048 Comment cmnt(masm_, "[ WithExitStatement"); | 3065 Comment cmnt(masm_, "[ WithExitStatement"); |
| 3049 CodeForStatementPosition(node); | 3066 CodeForStatementPosition(node); |
| 3050 // Pop context. | 3067 // Pop context. |
| 3051 __ movq(rsi, ContextOperand(rsi, Context::PREVIOUS_INDEX)); | 3068 __ movq(rsi, ContextOperand(rsi, Context::PREVIOUS_INDEX)); |
| 3052 // Update context local. | 3069 // Update context local. |
| 3053 frame_->SaveContextRegister(); | 3070 frame_->SaveContextRegister(); |
| 3054 } | 3071 } |
| 3055 | 3072 |
| 3056 | 3073 |
| 3057 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { | 3074 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { |
| 3058 // TODO(X64): This code is completely generic and should be moved somewhere | |
| 3059 // where it can be shared between architectures. | |
| 3060 ASSERT(!in_spilled_code()); | 3075 ASSERT(!in_spilled_code()); |
| 3061 Comment cmnt(masm_, "[ SwitchStatement"); | 3076 Comment cmnt(masm_, "[ SwitchStatement"); |
| 3062 CodeForStatementPosition(node); | 3077 CodeForStatementPosition(node); |
| 3063 node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); | 3078 node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); |
| 3064 | 3079 |
| 3065 // Compile the switch value. | 3080 // Compile the switch value. |
| 3066 Load(node->tag()); | 3081 Load(node->tag()); |
| 3067 | 3082 |
| 3068 ZoneList<CaseClause*>* cases = node->cases(); | 3083 ZoneList<CaseClause*>* cases = node->cases(); |
| 3069 int length = cases->length(); | 3084 int length = cases->length(); |
| (...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3341 if (node->continue_target()->is_linked()) { | 3356 if (node->continue_target()->is_linked()) { |
| 3342 node->continue_target()->Bind(); | 3357 node->continue_target()->Bind(); |
| 3343 } | 3358 } |
| 3344 if (has_valid_frame()) { | 3359 if (has_valid_frame()) { |
| 3345 // The break target is the fall-through (body is a backward | 3360 // The break target is the fall-through (body is a backward |
| 3346 // jump from here and thus an invalid fall-through). | 3361 // jump from here and thus an invalid fall-through). |
| 3347 ControlDestination dest(&body, node->break_target(), false); | 3362 ControlDestination dest(&body, node->break_target(), false); |
| 3348 LoadCondition(node->cond(), &dest, true); | 3363 LoadCondition(node->cond(), &dest, true); |
| 3349 } | 3364 } |
| 3350 } else { | 3365 } else { |
| 3351 // If we have chosen not to recompile the test at the | 3366 // If we have chosen not to recompile the test at the bottom, |
| 3352 // bottom, jump back to the one at the top. | 3367 // jump back to the one at the top. |
| 3353 if (has_valid_frame()) { | 3368 if (has_valid_frame()) { |
| 3354 node->continue_target()->Jump(); | 3369 node->continue_target()->Jump(); |
| 3355 } | 3370 } |
| 3356 } | 3371 } |
| 3357 break; | 3372 break; |
| 3358 case ALWAYS_FALSE: | 3373 case ALWAYS_FALSE: |
| 3359 UNREACHABLE(); | 3374 UNREACHABLE(); |
| 3360 break; | 3375 break; |
| 3361 } | 3376 } |
| 3362 | 3377 |
| (...skipping 541 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3904 node->break_target()->Bind(); | 3919 node->break_target()->Bind(); |
| 3905 frame_->Drop(5); | 3920 frame_->Drop(5); |
| 3906 | 3921 |
| 3907 // Exit. | 3922 // Exit. |
| 3908 exit.Bind(); | 3923 exit.Bind(); |
| 3909 | 3924 |
| 3910 node->continue_target()->Unuse(); | 3925 node->continue_target()->Unuse(); |
| 3911 node->break_target()->Unuse(); | 3926 node->break_target()->Unuse(); |
| 3912 } | 3927 } |
| 3913 | 3928 |
| 3929 |
| 3914 void CodeGenerator::VisitTryCatchStatement(TryCatchStatement* node) { | 3930 void CodeGenerator::VisitTryCatchStatement(TryCatchStatement* node) { |
| 3915 ASSERT(!in_spilled_code()); | 3931 ASSERT(!in_spilled_code()); |
| 3916 VirtualFrame::SpilledScope spilled_scope; | 3932 VirtualFrame::SpilledScope spilled_scope; |
| 3917 Comment cmnt(masm_, "[ TryCatchStatement"); | 3933 Comment cmnt(masm_, "[ TryCatchStatement"); |
| 3918 CodeForStatementPosition(node); | 3934 CodeForStatementPosition(node); |
| 3919 | 3935 |
| 3920 JumpTarget try_block; | 3936 JumpTarget try_block; |
| 3921 JumpTarget exit; | 3937 JumpTarget exit; |
| 3922 | 3938 |
| 3923 try_block.Call(); | 3939 try_block.Call(); |
| (...skipping 8160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 12084 #undef __ | 12100 #undef __ |
| 12085 | 12101 |
| 12086 void RecordWriteStub::Generate(MacroAssembler* masm) { | 12102 void RecordWriteStub::Generate(MacroAssembler* masm) { |
| 12087 masm->RecordWriteHelper(object_, addr_, scratch_); | 12103 masm->RecordWriteHelper(object_, addr_, scratch_); |
| 12088 masm->ret(0); | 12104 masm->ret(0); |
| 12089 } | 12105 } |
| 12090 | 12106 |
| 12091 } } // namespace v8::internal | 12107 } } // namespace v8::internal |
| 12092 | 12108 |
| 12093 #endif // V8_TARGET_ARCH_X64 | 12109 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |