| 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 731 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 742 : LAZY_ARGUMENTS_ALLOCATION; | 742 : LAZY_ARGUMENTS_ALLOCATION; |
| 743 } | 743 } |
| 744 | 744 |
| 745 | 745 |
| 746 Result CodeGenerator::StoreArgumentsObject(bool initial) { | 746 Result CodeGenerator::StoreArgumentsObject(bool initial) { |
| 747 ArgumentsAllocationMode mode = ArgumentsMode(); | 747 ArgumentsAllocationMode mode = ArgumentsMode(); |
| 748 ASSERT(mode != NO_ARGUMENTS_ALLOCATION); | 748 ASSERT(mode != NO_ARGUMENTS_ALLOCATION); |
| 749 | 749 |
| 750 Comment cmnt(masm_, "[ store arguments object"); | 750 Comment cmnt(masm_, "[ store arguments object"); |
| 751 if (mode == LAZY_ARGUMENTS_ALLOCATION && initial) { | 751 if (mode == LAZY_ARGUMENTS_ALLOCATION && initial) { |
| 752 // When using lazy arguments allocation, we store the hole value | 752 // When using lazy arguments allocation, we store the arguments marker value |
| 753 // as a sentinel indicating that the arguments object hasn't been | 753 // as a sentinel indicating that the arguments object hasn't been |
| 754 // allocated yet. | 754 // allocated yet. |
| 755 frame_->Push(Factory::the_hole_value()); | 755 frame_->Push(Factory::arguments_marker()); |
| 756 } else { | 756 } else { |
| 757 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); | 757 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); |
| 758 frame_->PushFunction(); | 758 frame_->PushFunction(); |
| 759 frame_->PushReceiverSlotAddress(); | 759 frame_->PushReceiverSlotAddress(); |
| 760 frame_->Push(Smi::FromInt(scope()->num_parameters())); | 760 frame_->Push(Smi::FromInt(scope()->num_parameters())); |
| 761 Result result = frame_->CallStub(&stub, 3); | 761 Result result = frame_->CallStub(&stub, 3); |
| 762 frame_->Push(&result); | 762 frame_->Push(&result); |
| 763 } | 763 } |
| 764 | 764 |
| 765 Variable* arguments = scope()->arguments(); | 765 Variable* arguments = scope()->arguments(); |
| 766 Variable* shadow = scope()->arguments_shadow(); | 766 Variable* shadow = scope()->arguments_shadow(); |
| 767 ASSERT(arguments != NULL && arguments->AsSlot() != NULL); | 767 ASSERT(arguments != NULL && arguments->AsSlot() != NULL); |
| 768 ASSERT(shadow != NULL && shadow->AsSlot() != NULL); | 768 ASSERT(shadow != NULL && shadow->AsSlot() != NULL); |
| 769 JumpTarget done; | 769 JumpTarget done; |
| 770 bool skip_arguments = false; | 770 bool skip_arguments = false; |
| 771 if (mode == LAZY_ARGUMENTS_ALLOCATION && !initial) { | 771 if (mode == LAZY_ARGUMENTS_ALLOCATION && !initial) { |
| 772 // We have to skip storing into the arguments slot if it has | 772 // We have to skip storing into the arguments slot if it has |
| 773 // already been written to. This can happen if the a function | 773 // already been written to. This can happen if the a function |
| 774 // has a local variable named 'arguments'. | 774 // has a local variable named 'arguments'. |
| 775 LoadFromSlot(arguments->AsSlot(), NOT_INSIDE_TYPEOF); | 775 LoadFromSlot(arguments->AsSlot(), NOT_INSIDE_TYPEOF); |
| 776 Result probe = frame_->Pop(); | 776 Result probe = frame_->Pop(); |
| 777 if (probe.is_constant()) { | 777 if (probe.is_constant()) { |
| 778 // We have to skip updating the arguments object if it has | 778 // We have to skip updating the arguments object if it has |
| 779 // been assigned a proper value. | 779 // been assigned a proper value. |
| 780 skip_arguments = !probe.handle()->IsTheHole(); | 780 skip_arguments = !probe.handle()->IsArgumentsMarker(); |
| 781 } else { | 781 } else { |
| 782 __ cmp(Operand(probe.reg()), Immediate(Factory::the_hole_value())); | 782 __ cmp(Operand(probe.reg()), Immediate(Factory::arguments_marker())); |
| 783 probe.Unuse(); | 783 probe.Unuse(); |
| 784 done.Branch(not_equal); | 784 done.Branch(not_equal); |
| 785 } | 785 } |
| 786 } | 786 } |
| 787 if (!skip_arguments) { | 787 if (!skip_arguments) { |
| 788 StoreToSlot(arguments->AsSlot(), NOT_CONST_INIT); | 788 StoreToSlot(arguments->AsSlot(), NOT_CONST_INIT); |
| 789 if (mode == LAZY_ARGUMENTS_ALLOCATION) done.Bind(); | 789 if (mode == LAZY_ARGUMENTS_ALLOCATION) done.Bind(); |
| 790 } | 790 } |
| 791 StoreToSlot(shadow->AsSlot(), NOT_CONST_INIT); | 791 StoreToSlot(shadow->AsSlot(), NOT_CONST_INIT); |
| 792 return frame_->Pop(); | 792 return frame_->Pop(); |
| (...skipping 2498 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3291 // Check if the arguments object has been lazily allocated | 3291 // Check if the arguments object has been lazily allocated |
| 3292 // already. If so, just use that instead of copying the arguments | 3292 // already. If so, just use that instead of copying the arguments |
| 3293 // from the stack. This also deals with cases where a local variable | 3293 // from the stack. This also deals with cases where a local variable |
| 3294 // named 'arguments' has been introduced. | 3294 // named 'arguments' has been introduced. |
| 3295 frame_->Dup(); | 3295 frame_->Dup(); |
| 3296 Result probe = frame_->Pop(); | 3296 Result probe = frame_->Pop(); |
| 3297 { VirtualFrame::SpilledScope spilled_scope; | 3297 { VirtualFrame::SpilledScope spilled_scope; |
| 3298 Label slow, done; | 3298 Label slow, done; |
| 3299 bool try_lazy = true; | 3299 bool try_lazy = true; |
| 3300 if (probe.is_constant()) { | 3300 if (probe.is_constant()) { |
| 3301 try_lazy = probe.handle()->IsTheHole(); | 3301 try_lazy = probe.handle()->IsArgumentsMarker(); |
| 3302 } else { | 3302 } else { |
| 3303 __ cmp(Operand(probe.reg()), Immediate(Factory::the_hole_value())); | 3303 __ cmp(Operand(probe.reg()), Immediate(Factory::arguments_marker())); |
| 3304 probe.Unuse(); | 3304 probe.Unuse(); |
| 3305 __ j(not_equal, &slow); | 3305 __ j(not_equal, &slow); |
| 3306 } | 3306 } |
| 3307 | 3307 |
| 3308 if (try_lazy) { | 3308 if (try_lazy) { |
| 3309 Label build_args; | 3309 Label build_args; |
| 3310 // Get rid of the arguments object probe. | 3310 // Get rid of the arguments object probe. |
| 3311 frame_->Drop(); // Can be called on a spilled frame. | 3311 frame_->Drop(); // Can be called on a spilled frame. |
| 3312 // Stack now has 3 elements on it. | 3312 // Stack now has 3 elements on it. |
| 3313 // Contents of stack at this point: | 3313 // Contents of stack at this point: |
| (...skipping 454 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3768 | 3768 |
| 3769 // Add a label for checking the size of the code used for returning. | 3769 // Add a label for checking the size of the code used for returning. |
| 3770 #ifdef DEBUG | 3770 #ifdef DEBUG |
| 3771 Label check_exit_codesize; | 3771 Label check_exit_codesize; |
| 3772 masm_->bind(&check_exit_codesize); | 3772 masm_->bind(&check_exit_codesize); |
| 3773 #endif | 3773 #endif |
| 3774 | 3774 |
| 3775 // Leave the frame and return popping the arguments and the | 3775 // Leave the frame and return popping the arguments and the |
| 3776 // receiver. | 3776 // receiver. |
| 3777 frame_->Exit(); | 3777 frame_->Exit(); |
| 3778 masm_->ret((scope()->num_parameters() + 1) * kPointerSize); | 3778 int arguments_bytes = (scope()->num_parameters() + 1) * kPointerSize; |
| 3779 __ Ret(arguments_bytes, ecx); |
| 3779 DeleteFrame(); | 3780 DeleteFrame(); |
| 3780 | 3781 |
| 3781 #ifdef ENABLE_DEBUGGER_SUPPORT | 3782 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 3782 // Check that the size of the code used for returning matches what is | 3783 // Check that the size of the code used for returning is large enough |
| 3783 // expected by the debugger. | 3784 // for the debugger's requirements. |
| 3784 ASSERT_EQ(Assembler::kJSReturnSequenceLength, | 3785 ASSERT(Assembler::kJSReturnSequenceLength <= |
| 3785 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); | 3786 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize)); |
| 3786 #endif | 3787 #endif |
| 3787 } | 3788 } |
| 3788 | 3789 |
| 3789 | 3790 |
| 3790 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { | 3791 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { |
| 3791 ASSERT(!in_spilled_code()); | 3792 ASSERT(!in_spilled_code()); |
| 3792 Comment cmnt(masm_, "[ WithEnterStatement"); | 3793 Comment cmnt(masm_, "[ WithEnterStatement"); |
| 3793 CodeForStatementPosition(node); | 3794 CodeForStatementPosition(node); |
| 3794 Load(node->expression()); | 3795 Load(node->expression()); |
| 3795 Result context; | 3796 Result context; |
| (...skipping 1269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5065 // Bail out quickly if we're not using lazy arguments allocation. | 5066 // Bail out quickly if we're not using lazy arguments allocation. |
| 5066 if (ArgumentsMode() != LAZY_ARGUMENTS_ALLOCATION) return; | 5067 if (ArgumentsMode() != LAZY_ARGUMENTS_ALLOCATION) return; |
| 5067 | 5068 |
| 5068 // ... or if the slot isn't a non-parameter arguments slot. | 5069 // ... or if the slot isn't a non-parameter arguments slot. |
| 5069 if (slot->type() == Slot::PARAMETER || !slot->is_arguments()) return; | 5070 if (slot->type() == Slot::PARAMETER || !slot->is_arguments()) return; |
| 5070 | 5071 |
| 5071 // If the loaded value is a constant, we know if the arguments | 5072 // If the loaded value is a constant, we know if the arguments |
| 5072 // object has been lazily loaded yet. | 5073 // object has been lazily loaded yet. |
| 5073 Result result = frame()->Pop(); | 5074 Result result = frame()->Pop(); |
| 5074 if (result.is_constant()) { | 5075 if (result.is_constant()) { |
| 5075 if (result.handle()->IsTheHole()) { | 5076 if (result.handle()->IsArgumentsMarker()) { |
| 5076 result = StoreArgumentsObject(false); | 5077 result = StoreArgumentsObject(false); |
| 5077 } | 5078 } |
| 5078 frame()->Push(&result); | 5079 frame()->Push(&result); |
| 5079 return; | 5080 return; |
| 5080 } | 5081 } |
| 5081 ASSERT(result.is_register()); | 5082 ASSERT(result.is_register()); |
| 5082 // The loaded value is in a register. If it is the sentinel that | 5083 // The loaded value is in a register. If it is the sentinel that |
| 5083 // indicates that we haven't loaded the arguments object yet, we | 5084 // indicates that we haven't loaded the arguments object yet, we |
| 5084 // need to do it now. | 5085 // need to do it now. |
| 5085 JumpTarget exit; | 5086 JumpTarget exit; |
| 5086 __ cmp(Operand(result.reg()), Immediate(Factory::the_hole_value())); | 5087 __ cmp(Operand(result.reg()), Immediate(Factory::arguments_marker())); |
| 5087 frame()->Push(&result); | 5088 frame()->Push(&result); |
| 5088 exit.Branch(not_equal); | 5089 exit.Branch(not_equal); |
| 5089 | 5090 |
| 5090 result = StoreArgumentsObject(false); | 5091 result = StoreArgumentsObject(false); |
| 5091 frame()->SetElementAt(0, &result); | 5092 frame()->SetElementAt(0, &result); |
| 5092 result.Unuse(); | 5093 result.Unuse(); |
| 5093 exit.Bind(); | 5094 exit.Bind(); |
| 5094 return; | 5095 return; |
| 5095 } | 5096 } |
| 5096 | 5097 |
| (...skipping 492 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5589 if (CompileTimeValue::IsCompileTimeValue(property->value())) break; | 5590 if (CompileTimeValue::IsCompileTimeValue(property->value())) break; |
| 5590 // else fall through. | 5591 // else fall through. |
| 5591 case ObjectLiteral::Property::COMPUTED: { | 5592 case ObjectLiteral::Property::COMPUTED: { |
| 5592 Handle<Object> key(property->key()->handle()); | 5593 Handle<Object> key(property->key()->handle()); |
| 5593 if (key->IsSymbol()) { | 5594 if (key->IsSymbol()) { |
| 5594 // Duplicate the object as the IC receiver. | 5595 // Duplicate the object as the IC receiver. |
| 5595 frame_->Dup(); | 5596 frame_->Dup(); |
| 5596 Load(property->value()); | 5597 Load(property->value()); |
| 5597 if (property->emit_store()) { | 5598 if (property->emit_store()) { |
| 5598 Result ignored = | 5599 Result ignored = |
| 5599 frame_->CallStoreIC(Handle<String>::cast(key), false); | 5600 frame_->CallStoreIC(Handle<String>::cast(key), false, |
| 5601 strict_mode_flag()); |
| 5600 // A test eax instruction following the store IC call would | 5602 // A test eax instruction following the store IC call would |
| 5601 // indicate the presence of an inlined version of the | 5603 // indicate the presence of an inlined version of the |
| 5602 // store. Add a nop to indicate that there is no such | 5604 // store. Add a nop to indicate that there is no such |
| 5603 // inlined version. | 5605 // inlined version. |
| 5604 __ nop(); | 5606 __ nop(); |
| 5605 } else { | 5607 } else { |
| 5606 frame_->Drop(2); | 5608 frame_->Drop(2); |
| 5607 } | 5609 } |
| 5608 break; | 5610 break; |
| 5609 } | 5611 } |
| (...skipping 498 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6108 NOT_INSIDE_TYPEOF, | 6110 NOT_INSIDE_TYPEOF, |
| 6109 &slow); | 6111 &slow); |
| 6110 frame_->Push(&fun); | 6112 frame_->Push(&fun); |
| 6111 if (arg_count > 0) { | 6113 if (arg_count > 0) { |
| 6112 frame_->PushElementAt(arg_count); | 6114 frame_->PushElementAt(arg_count); |
| 6113 } else { | 6115 } else { |
| 6114 frame_->Push(Factory::undefined_value()); | 6116 frame_->Push(Factory::undefined_value()); |
| 6115 } | 6117 } |
| 6116 frame_->PushParameterAt(-1); | 6118 frame_->PushParameterAt(-1); |
| 6117 | 6119 |
| 6120 // Push the strict mode flag. |
| 6121 frame_->Push(Smi::FromInt(strict_mode_flag())); |
| 6122 |
| 6118 // Resolve the call. | 6123 // Resolve the call. |
| 6119 result = | 6124 result = |
| 6120 frame_->CallRuntime(Runtime::kResolvePossiblyDirectEvalNoLookup, 3); | 6125 frame_->CallRuntime(Runtime::kResolvePossiblyDirectEvalNoLookup, 4); |
| 6121 | 6126 |
| 6122 done.Jump(&result); | 6127 done.Jump(&result); |
| 6123 slow.Bind(); | 6128 slow.Bind(); |
| 6124 } | 6129 } |
| 6125 | 6130 |
| 6126 // Prepare the stack for the call to ResolvePossiblyDirectEval by | 6131 // Prepare the stack for the call to ResolvePossiblyDirectEval by |
| 6127 // pushing the loaded function, the first argument to the eval | 6132 // pushing the loaded function, the first argument to the eval |
| 6128 // call and the receiver. | 6133 // call and the receiver. |
| 6129 frame_->PushElementAt(arg_count + 1); | 6134 frame_->PushElementAt(arg_count + 1); |
| 6130 if (arg_count > 0) { | 6135 if (arg_count > 0) { |
| 6131 frame_->PushElementAt(arg_count); | 6136 frame_->PushElementAt(arg_count); |
| 6132 } else { | 6137 } else { |
| 6133 frame_->Push(Factory::undefined_value()); | 6138 frame_->Push(Factory::undefined_value()); |
| 6134 } | 6139 } |
| 6135 frame_->PushParameterAt(-1); | 6140 frame_->PushParameterAt(-1); |
| 6136 | 6141 |
| 6142 // Push the strict mode flag. |
| 6143 frame_->Push(Smi::FromInt(strict_mode_flag())); |
| 6144 |
| 6137 // Resolve the call. | 6145 // Resolve the call. |
| 6138 result = frame_->CallRuntime(Runtime::kResolvePossiblyDirectEval, 3); | 6146 result = frame_->CallRuntime(Runtime::kResolvePossiblyDirectEval, 4); |
| 6139 | 6147 |
| 6140 // If we generated fast-case code bind the jump-target where fast | 6148 // If we generated fast-case code bind the jump-target where fast |
| 6141 // and slow case merge. | 6149 // and slow case merge. |
| 6142 if (done.is_linked()) done.Bind(&result); | 6150 if (done.is_linked()) done.Bind(&result); |
| 6143 | 6151 |
| 6144 // The runtime call returns a pair of values in eax (function) and | 6152 // The runtime call returns a pair of values in eax (function) and |
| 6145 // edx (receiver). Touch up the stack with the right values. | 6153 // edx (receiver). Touch up the stack with the right values. |
| 6146 Result receiver = allocator_->Allocate(edx); | 6154 Result receiver = allocator_->Allocate(edx); |
| 6147 frame_->SetElementAt(arg_count + 1, &result); | 6155 frame_->SetElementAt(arg_count + 1, &result); |
| 6148 frame_->SetElementAt(arg_count, &receiver); | 6156 frame_->SetElementAt(arg_count, &receiver); |
| (...skipping 506 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6655 ASSERT(temp.is_valid()); | 6663 ASSERT(temp.is_valid()); |
| 6656 // Check if the object is a JS array or not. | 6664 // Check if the object is a JS array or not. |
| 6657 __ CmpObjectType(value.reg(), JS_ARRAY_TYPE, temp.reg()); | 6665 __ CmpObjectType(value.reg(), JS_ARRAY_TYPE, temp.reg()); |
| 6658 value.Unuse(); | 6666 value.Unuse(); |
| 6659 temp.Unuse(); | 6667 temp.Unuse(); |
| 6660 destination()->Split(equal); | 6668 destination()->Split(equal); |
| 6661 } | 6669 } |
| 6662 | 6670 |
| 6663 | 6671 |
| 6664 void CodeGenerator::GenerateFastAsciiArrayJoin(ZoneList<Expression*>* args) { | 6672 void CodeGenerator::GenerateFastAsciiArrayJoin(ZoneList<Expression*>* args) { |
| 6673 Label bailout, done, one_char_separator, long_separator, |
| 6674 non_trivial_array, not_size_one_array, loop, loop_condition, |
| 6675 loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry; |
| 6676 |
| 6665 ASSERT(args->length() == 2); | 6677 ASSERT(args->length() == 2); |
| 6678 // We will leave the separator on the stack until the end of the function. |
| 6666 Load(args->at(1)); | 6679 Load(args->at(1)); |
| 6680 // Load this to eax (= array) |
| 6667 Load(args->at(0)); | 6681 Load(args->at(0)); |
| 6668 Result array_result = frame_->Pop(); | 6682 Result array_result = frame_->Pop(); |
| 6669 array_result.ToRegister(eax); | 6683 array_result.ToRegister(eax); |
| 6670 frame_->SpillAll(); | 6684 frame_->SpillAll(); |
| 6671 | 6685 |
| 6672 Label bailout; | |
| 6673 Label done; | |
| 6674 // All aliases of the same register have disjoint lifetimes. | 6686 // All aliases of the same register have disjoint lifetimes. |
| 6675 Register array = eax; | 6687 Register array = eax; |
| 6676 Register result_pos = no_reg; | 6688 Register elements = no_reg; // Will be eax. |
| 6677 | 6689 |
| 6678 Register index = edi; | 6690 Register index = edx; |
| 6679 | 6691 |
| 6680 Register current_string_length = ecx; // Will be ecx when live. | 6692 Register string_length = ecx; |
| 6681 | 6693 |
| 6682 Register current_string = edx; | 6694 Register string = esi; |
| 6683 | 6695 |
| 6684 Register scratch = ebx; | 6696 Register scratch = ebx; |
| 6685 | 6697 |
| 6686 Register scratch_2 = esi; | 6698 Register array_length = edi; |
| 6687 Register new_padding_chars = scratch_2; | 6699 Register result_pos = no_reg; // Will be edi. |
| 6688 | 6700 |
| 6689 Operand separator = Operand(esp, 4 * kPointerSize); // Already pushed. | 6701 // Separator operand is already pushed. |
| 6690 Operand elements = Operand(esp, 3 * kPointerSize); | 6702 Operand separator_operand = Operand(esp, 2 * kPointerSize); |
| 6691 Operand result = Operand(esp, 2 * kPointerSize); | 6703 Operand result_operand = Operand(esp, 1 * kPointerSize); |
| 6692 Operand padding_chars = Operand(esp, 1 * kPointerSize); | 6704 Operand array_length_operand = Operand(esp, 0); |
| 6693 Operand array_length = Operand(esp, 0); | 6705 __ sub(Operand(esp), Immediate(2 * kPointerSize)); |
| 6694 __ sub(Operand(esp), Immediate(4 * kPointerSize)); | 6706 __ cld(); |
| 6695 | 6707 // Check that the array is a JSArray |
| 6696 // Check that eax is a JSArray | |
| 6697 __ test(array, Immediate(kSmiTagMask)); | 6708 __ test(array, Immediate(kSmiTagMask)); |
| 6698 __ j(zero, &bailout); | 6709 __ j(zero, &bailout); |
| 6699 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch); | 6710 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch); |
| 6700 __ j(not_equal, &bailout); | 6711 __ j(not_equal, &bailout); |
| 6701 | 6712 |
| 6702 // Check that the array has fast elements. | 6713 // Check that the array has fast elements. |
| 6703 __ test_b(FieldOperand(scratch, Map::kBitField2Offset), | 6714 __ test_b(FieldOperand(scratch, Map::kBitField2Offset), |
| 6704 1 << Map::kHasFastElements); | 6715 1 << Map::kHasFastElements); |
| 6705 __ j(zero, &bailout); | 6716 __ j(zero, &bailout); |
| 6706 | 6717 |
| 6707 // If the array is empty, return the empty string. | 6718 // If the array has length zero, return the empty string. |
| 6708 __ mov(scratch, FieldOperand(array, JSArray::kLengthOffset)); | 6719 __ mov(array_length, FieldOperand(array, JSArray::kLengthOffset)); |
| 6709 __ sar(scratch, 1); | 6720 __ sar(array_length, 1); |
| 6710 Label non_trivial; | 6721 __ j(not_zero, &non_trivial_array); |
| 6711 __ j(not_zero, &non_trivial); | 6722 __ mov(result_operand, Factory::empty_string()); |
| 6712 __ mov(result, Factory::empty_string()); | 6723 __ jmp(&done); |
| 6713 __ jmp(&done); | 6724 |
| 6714 | 6725 // Save the array length. |
| 6715 __ bind(&non_trivial); | 6726 __ bind(&non_trivial_array); |
| 6716 __ mov(array_length, scratch); | 6727 __ mov(array_length_operand, array_length); |
| 6717 | 6728 |
| 6718 __ mov(scratch, FieldOperand(array, JSArray::kElementsOffset)); | 6729 // Save the FixedArray containing array's elements. |
| 6719 __ mov(elements, scratch); | |
| 6720 | |
| 6721 // End of array's live range. | 6730 // End of array's live range. |
| 6722 result_pos = array; | 6731 elements = array; |
| 6732 __ mov(elements, FieldOperand(array, JSArray::kElementsOffset)); |
| 6723 array = no_reg; | 6733 array = no_reg; |
| 6724 | 6734 |
| 6725 | 6735 |
| 6726 // Check that the separator is a flat ascii string. | 6736 // Check that all array elements are sequential ASCII strings, and |
| 6727 __ mov(current_string, separator); | 6737 // accumulate the sum of their lengths, as a smi-encoded value. |
| 6728 __ test(current_string, Immediate(kSmiTagMask)); | 6738 __ Set(index, Immediate(0)); |
| 6739 __ Set(string_length, Immediate(0)); |
| 6740 // Loop condition: while (index < length). |
| 6741 // Live loop registers: index, array_length, string, |
| 6742 // scratch, string_length, elements. |
| 6743 __ jmp(&loop_condition); |
| 6744 __ bind(&loop); |
| 6745 __ cmp(index, Operand(array_length)); |
| 6746 __ j(greater_equal, &done); |
| 6747 |
| 6748 __ mov(string, FieldOperand(elements, index, |
| 6749 times_pointer_size, |
| 6750 FixedArray::kHeaderSize)); |
| 6751 __ test(string, Immediate(kSmiTagMask)); |
| 6729 __ j(zero, &bailout); | 6752 __ j(zero, &bailout); |
| 6730 __ mov(scratch, FieldOperand(current_string, HeapObject::kMapOffset)); | 6753 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset)); |
| 6731 __ mov_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); | 6754 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); |
| 6732 __ and_(scratch, Immediate( | 6755 __ and_(scratch, Immediate( |
| 6733 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); | 6756 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); |
| 6734 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag); | 6757 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag); |
| 6735 __ j(not_equal, &bailout); | 6758 __ j(not_equal, &bailout); |
| 6736 // If the separator is the empty string, replace it with NULL. | 6759 __ add(string_length, |
| 6737 // The test for NULL is quicker than the empty string test, in a loop. | 6760 FieldOperand(string, SeqAsciiString::kLengthOffset)); |
| 6738 __ cmp(FieldOperand(current_string, SeqAsciiString::kLengthOffset), | 6761 __ j(overflow, &bailout); |
| 6739 Immediate(0)); | 6762 __ add(Operand(index), Immediate(1)); |
| 6740 Label separator_checked; | 6763 __ bind(&loop_condition); |
| 6741 __ j(not_zero, &separator_checked); | 6764 __ cmp(index, Operand(array_length)); |
| 6742 __ mov(separator, Immediate(0)); | 6765 __ j(less, &loop); |
| 6743 __ bind(&separator_checked); | 6766 |
| 6744 | 6767 // If array_length is 1, return elements[0], a string. |
| 6745 // Check that elements[0] is a flat ascii string, and copy it in new space. | 6768 __ cmp(array_length, 1); |
| 6746 __ mov(scratch, elements); | 6769 __ j(not_equal, ¬_size_one_array); |
| 6747 __ mov(current_string, FieldOperand(scratch, FixedArray::kHeaderSize)); | 6770 __ mov(scratch, FieldOperand(elements, FixedArray::kHeaderSize)); |
| 6748 __ test(current_string, Immediate(kSmiTagMask)); | 6771 __ mov(result_operand, scratch); |
| 6772 __ jmp(&done); |
| 6773 |
| 6774 __ bind(¬_size_one_array); |
| 6775 |
| 6776 // End of array_length live range. |
| 6777 result_pos = array_length; |
| 6778 array_length = no_reg; |
| 6779 |
| 6780 // Live registers: |
| 6781 // string_length: Sum of string lengths, as a smi. |
| 6782 // elements: FixedArray of strings. |
| 6783 |
| 6784 // Check that the separator is a flat ASCII string. |
| 6785 __ mov(string, separator_operand); |
| 6786 __ test(string, Immediate(kSmiTagMask)); |
| 6749 __ j(zero, &bailout); | 6787 __ j(zero, &bailout); |
| 6750 __ mov(scratch, FieldOperand(current_string, HeapObject::kMapOffset)); | 6788 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset)); |
| 6751 __ mov_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); | 6789 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); |
| 6752 __ and_(scratch, Immediate( | 6790 __ and_(scratch, Immediate( |
| 6753 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); | 6791 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); |
| 6754 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag); | 6792 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag); |
| 6755 __ j(not_equal, &bailout); | 6793 __ j(not_equal, &bailout); |
| 6756 | 6794 |
| 6757 // Allocate space to copy it. Round up the size to the alignment granularity. | 6795 // Add (separator length times array_length) - separator length |
| 6758 __ mov(current_string_length, | 6796 // to string_length. |
| 6759 FieldOperand(current_string, String::kLengthOffset)); | 6797 __ mov(scratch, separator_operand); |
| 6760 __ shr(current_string_length, 1); | 6798 __ mov(scratch, FieldOperand(scratch, SeqAsciiString::kLengthOffset)); |
| 6761 | 6799 __ sub(string_length, Operand(scratch)); // May be negative, temporarily. |
| 6800 __ imul(scratch, array_length_operand); |
| 6801 __ j(overflow, &bailout); |
| 6802 __ add(string_length, Operand(scratch)); |
| 6803 __ j(overflow, &bailout); |
| 6804 |
| 6805 __ shr(string_length, 1); |
| 6762 // Live registers and stack values: | 6806 // Live registers and stack values: |
| 6763 // current_string_length: length of elements[0]. | 6807 // string_length |
| 6764 | 6808 // elements |
| 6765 // New string result in new space = elements[0] | 6809 __ AllocateAsciiString(result_pos, string_length, scratch, |
| 6766 __ AllocateAsciiString(result_pos, current_string_length, scratch_2, | 6810 index, string, &bailout); |
| 6767 index, no_reg, &bailout); | 6811 __ mov(result_operand, result_pos); |
| 6768 __ mov(result, result_pos); | 6812 __ lea(result_pos, FieldOperand(result_pos, SeqAsciiString::kHeaderSize)); |
| 6769 | 6813 |
| 6770 // Adjust current_string_length to include padding bytes at end of string. | 6814 |
| 6771 // Keep track of the number of padding bytes. | 6815 __ mov(string, separator_operand); |
| 6772 __ mov(new_padding_chars, current_string_length); | 6816 __ cmp(FieldOperand(string, SeqAsciiString::kLengthOffset), |
| 6773 __ add(Operand(current_string_length), Immediate(kObjectAlignmentMask)); | 6817 Immediate(Smi::FromInt(1))); |
| 6774 __ and_(Operand(current_string_length), Immediate(~kObjectAlignmentMask)); | 6818 __ j(equal, &one_char_separator); |
| 6775 __ sub(new_padding_chars, Operand(current_string_length)); | 6819 __ j(greater, &long_separator); |
| 6776 __ neg(new_padding_chars); | 6820 |
| 6777 __ mov(padding_chars, new_padding_chars); | 6821 |
| 6778 | 6822 // Empty separator case |
| 6779 Label copy_loop_1_done; | 6823 __ mov(index, Immediate(0)); |
| 6780 Label copy_loop_1; | 6824 __ jmp(&loop_1_condition); |
| 6781 __ test(current_string_length, Operand(current_string_length)); | 6825 // Loop condition: while (index < length). |
| 6782 __ j(zero, ©_loop_1_done); | 6826 __ bind(&loop_1); |
| 6783 __ bind(©_loop_1); | 6827 // Each iteration of the loop concatenates one string to the result. |
| 6784 __ sub(Operand(current_string_length), Immediate(kPointerSize)); | 6828 // Live values in registers: |
| 6785 __ mov(scratch, FieldOperand(current_string, current_string_length, | 6829 // index: which element of the elements array we are adding to the result. |
| 6786 times_1, SeqAsciiString::kHeaderSize)); | 6830 // result_pos: the position to which we are currently copying characters. |
| 6787 __ mov(FieldOperand(result_pos, current_string_length, | 6831 // elements: the FixedArray of strings we are joining. |
| 6788 times_1, SeqAsciiString::kHeaderSize), | 6832 |
| 6789 scratch); | 6833 // Get string = array[index]. |
| 6790 __ j(not_zero, ©_loop_1); | 6834 __ mov(string, FieldOperand(elements, index, |
| 6791 __ bind(©_loop_1_done); | 6835 times_pointer_size, |
| 6792 | 6836 FixedArray::kHeaderSize)); |
| 6793 __ mov(index, Immediate(1)); | 6837 __ mov(string_length, |
| 6794 // Loop condition: while (index < length). | 6838 FieldOperand(string, String::kLengthOffset)); |
| 6795 Label loop; | 6839 __ shr(string_length, 1); |
| 6796 __ bind(&loop); | 6840 __ lea(string, |
| 6797 __ cmp(index, array_length); | 6841 FieldOperand(string, SeqAsciiString::kHeaderSize)); |
| 6798 __ j(greater_equal, &done); | 6842 __ CopyBytes(string, result_pos, string_length, scratch); |
| 6799 | 6843 __ add(Operand(index), Immediate(1)); |
| 6800 // If the separator is the empty string, signalled by NULL, skip it. | 6844 __ bind(&loop_1_condition); |
| 6801 Label separator_done; | 6845 __ cmp(index, array_length_operand); |
| 6802 __ mov(current_string, separator); | 6846 __ j(less, &loop_1); // End while (index < length). |
| 6803 __ test(current_string, Operand(current_string)); | 6847 __ jmp(&done); |
| 6804 __ j(zero, &separator_done); | 6848 |
| 6805 | 6849 |
| 6806 // Append separator to result. It is known to be a flat ascii string. | 6850 |
| 6807 __ AppendStringToTopOfNewSpace(current_string, current_string_length, | 6851 // One-character separator case |
| 6808 result_pos, scratch, scratch_2, result, | 6852 __ bind(&one_char_separator); |
| 6809 padding_chars, &bailout); | 6853 // Replace separator with its ascii character value. |
| 6810 __ bind(&separator_done); | 6854 __ mov_b(scratch, FieldOperand(string, SeqAsciiString::kHeaderSize)); |
| 6811 | 6855 __ mov_b(separator_operand, scratch); |
| 6812 // Add next element of array to the end of the result. | 6856 |
| 6813 // Get current_string = array[index]. | 6857 __ Set(index, Immediate(0)); |
| 6814 __ mov(scratch, elements); | 6858 // Jump into the loop after the code that copies the separator, so the first |
| 6815 __ mov(current_string, FieldOperand(scratch, index, | 6859 // element is not preceded by a separator |
| 6816 times_pointer_size, | 6860 __ jmp(&loop_2_entry); |
| 6817 FixedArray::kHeaderSize)); | 6861 // Loop condition: while (index < length). |
| 6818 // If current != flat ascii string drop result, return undefined. | 6862 __ bind(&loop_2); |
| 6819 __ test(current_string, Immediate(kSmiTagMask)); | 6863 // Each iteration of the loop concatenates one string to the result. |
| 6820 __ j(zero, &bailout); | 6864 // Live values in registers: |
| 6821 __ mov(scratch, FieldOperand(current_string, HeapObject::kMapOffset)); | 6865 // index: which element of the elements array we are adding to the result. |
| 6822 __ mov_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); | 6866 // result_pos: the position to which we are currently copying characters. |
| 6823 __ and_(scratch, Immediate( | 6867 |
| 6824 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); | 6868 // Copy the separator character to the result. |
| 6825 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag); | 6869 __ mov_b(scratch, separator_operand); |
| 6826 __ j(not_equal, &bailout); | 6870 __ mov_b(Operand(result_pos, 0), scratch); |
| 6827 | 6871 __ inc(result_pos); |
| 6828 // Append current to the result. | 6872 |
| 6829 __ AppendStringToTopOfNewSpace(current_string, current_string_length, | 6873 __ bind(&loop_2_entry); |
| 6830 result_pos, scratch, scratch_2, result, | 6874 // Get string = array[index]. |
| 6831 padding_chars, &bailout); | 6875 __ mov(string, FieldOperand(elements, index, |
| 6832 __ add(Operand(index), Immediate(1)); | 6876 times_pointer_size, |
| 6833 __ jmp(&loop); // End while (index < length). | 6877 FixedArray::kHeaderSize)); |
| 6878 __ mov(string_length, |
| 6879 FieldOperand(string, String::kLengthOffset)); |
| 6880 __ shr(string_length, 1); |
| 6881 __ lea(string, |
| 6882 FieldOperand(string, SeqAsciiString::kHeaderSize)); |
| 6883 __ CopyBytes(string, result_pos, string_length, scratch); |
| 6884 __ add(Operand(index), Immediate(1)); |
| 6885 |
| 6886 __ cmp(index, array_length_operand); |
| 6887 __ j(less, &loop_2); // End while (index < length). |
| 6888 __ jmp(&done); |
| 6889 |
| 6890 |
| 6891 // Long separator case (separator is more than one character). |
| 6892 __ bind(&long_separator); |
| 6893 |
| 6894 __ Set(index, Immediate(0)); |
| 6895 // Jump into the loop after the code that copies the separator, so the first |
| 6896 // element is not preceded by a separator |
| 6897 __ jmp(&loop_3_entry); |
| 6898 // Loop condition: while (index < length). |
| 6899 __ bind(&loop_3); |
| 6900 // Each iteration of the loop concatenates one string to the result. |
| 6901 // Live values in registers: |
| 6902 // index: which element of the elements array we are adding to the result. |
| 6903 // result_pos: the position to which we are currently copying characters. |
| 6904 |
| 6905 // Copy the separator to the result. |
| 6906 __ mov(string, separator_operand); |
| 6907 __ mov(string_length, |
| 6908 FieldOperand(string, String::kLengthOffset)); |
| 6909 __ shr(string_length, 1); |
| 6910 __ lea(string, |
| 6911 FieldOperand(string, SeqAsciiString::kHeaderSize)); |
| 6912 __ CopyBytes(string, result_pos, string_length, scratch); |
| 6913 |
| 6914 __ bind(&loop_3_entry); |
| 6915 // Get string = array[index]. |
| 6916 __ mov(string, FieldOperand(elements, index, |
| 6917 times_pointer_size, |
| 6918 FixedArray::kHeaderSize)); |
| 6919 __ mov(string_length, |
| 6920 FieldOperand(string, String::kLengthOffset)); |
| 6921 __ shr(string_length, 1); |
| 6922 __ lea(string, |
| 6923 FieldOperand(string, SeqAsciiString::kHeaderSize)); |
| 6924 __ CopyBytes(string, result_pos, string_length, scratch); |
| 6925 __ add(Operand(index), Immediate(1)); |
| 6926 |
| 6927 __ cmp(index, array_length_operand); |
| 6928 __ j(less, &loop_3); // End while (index < length). |
| 6929 __ jmp(&done); |
| 6930 |
| 6834 | 6931 |
| 6835 __ bind(&bailout); | 6932 __ bind(&bailout); |
| 6836 __ mov(result, Factory::undefined_value()); | 6933 __ mov(result_operand, Factory::undefined_value()); |
| 6837 __ bind(&done); | 6934 __ bind(&done); |
| 6838 __ mov(eax, result); | 6935 __ mov(eax, result_operand); |
| 6839 // Drop temp values from the stack, and restore context register. | 6936 // Drop temp values from the stack, and restore context register. |
| 6840 __ add(Operand(esp), Immediate(4 * kPointerSize)); | 6937 __ add(Operand(esp), Immediate(2 * kPointerSize)); |
| 6841 | 6938 |
| 6842 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 6939 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 6843 frame_->Drop(1); | 6940 frame_->Drop(1); |
| 6844 frame_->Push(&array_result); | 6941 frame_->Push(&array_result); |
| 6845 } | 6942 } |
| 6846 | 6943 |
| 6847 | 6944 |
| 6848 void CodeGenerator::GenerateIsRegExp(ZoneList<Expression*>* args) { | 6945 void CodeGenerator::GenerateIsRegExp(ZoneList<Expression*>* args) { |
| 6849 ASSERT(args->length() == 1); | 6946 ASSERT(args->length() == 1); |
| 6850 Load(args->at(0)); | 6947 Load(args->at(0)); |
| (...skipping 1019 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7870 // Test for -0.5. | 7967 // Test for -0.5. |
| 7871 // Load xmm2 with -0.5. | 7968 // Load xmm2 with -0.5. |
| 7872 __ mov(answer.reg(), Immediate(0xBF000000)); | 7969 __ mov(answer.reg(), Immediate(0xBF000000)); |
| 7873 __ movd(xmm2, Operand(answer.reg())); | 7970 __ movd(xmm2, Operand(answer.reg())); |
| 7874 __ cvtss2sd(xmm2, xmm2); | 7971 __ cvtss2sd(xmm2, xmm2); |
| 7875 // xmm2 now has -0.5. | 7972 // xmm2 now has -0.5. |
| 7876 __ ucomisd(xmm2, xmm1); | 7973 __ ucomisd(xmm2, xmm1); |
| 7877 __ j(not_equal, ¬_minus_half); | 7974 __ j(not_equal, ¬_minus_half); |
| 7878 | 7975 |
| 7879 // Calculates reciprocal of square root. | 7976 // Calculates reciprocal of square root. |
| 7880 // Note that 1/sqrt(x) = sqrt(1/x)) | 7977 // sqrtsd returns -0 when input is -0. ECMA spec requires +0. |
| 7881 __ divsd(xmm3, xmm0); | 7978 __ xorpd(xmm1, xmm1); |
| 7979 __ addsd(xmm1, xmm0); |
| 7980 __ sqrtsd(xmm1, xmm1); |
| 7981 __ divsd(xmm3, xmm1); |
| 7882 __ movsd(xmm1, xmm3); | 7982 __ movsd(xmm1, xmm3); |
| 7883 __ sqrtsd(xmm1, xmm1); | |
| 7884 __ jmp(&allocate_return); | 7983 __ jmp(&allocate_return); |
| 7885 | 7984 |
| 7886 // Test for 0.5. | 7985 // Test for 0.5. |
| 7887 __ bind(¬_minus_half); | 7986 __ bind(¬_minus_half); |
| 7888 // Load xmm2 with 0.5. | 7987 // Load xmm2 with 0.5. |
| 7889 // Since xmm3 is 1 and xmm2 is -0.5 this is simply xmm2 + xmm3. | 7988 // Since xmm3 is 1 and xmm2 is -0.5 this is simply xmm2 + xmm3. |
| 7890 __ addsd(xmm2, xmm3); | 7989 __ addsd(xmm2, xmm3); |
| 7891 // xmm2 now has 0.5. | 7990 // xmm2 now has 0.5. |
| 7892 __ ucomisd(xmm2, xmm1); | 7991 __ ucomisd(xmm2, xmm1); |
| 7893 call_runtime.Branch(not_equal); | 7992 call_runtime.Branch(not_equal); |
| 7894 // Calculates square root. | 7993 // Calculates square root. |
| 7895 __ movsd(xmm1, xmm0); | 7994 // sqrtsd returns -0 when input is -0. ECMA spec requires +0. |
| 7995 __ xorpd(xmm1, xmm1); |
| 7996 __ addsd(xmm1, xmm0); |
| 7896 __ sqrtsd(xmm1, xmm1); | 7997 __ sqrtsd(xmm1, xmm1); |
| 7897 | 7998 |
| 7898 JumpTarget done; | 7999 JumpTarget done; |
| 7899 Label failure, success; | 8000 Label failure, success; |
| 7900 __ bind(&allocate_return); | 8001 __ bind(&allocate_return); |
| 7901 // Make a copy of the frame to enable us to handle allocation | 8002 // Make a copy of the frame to enable us to handle allocation |
| 7902 // failure after the JumpTarget jump. | 8003 // failure after the JumpTarget jump. |
| 7903 VirtualFrame* clone = new VirtualFrame(frame()); | 8004 VirtualFrame* clone = new VirtualFrame(frame()); |
| 7904 __ AllocateHeapNumber(answer.reg(), exponent.reg(), | 8005 __ AllocateHeapNumber(answer.reg(), exponent.reg(), |
| 7905 base.reg(), &failure); | 8006 base.reg(), &failure); |
| (...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8132 destination()->Invert(); | 8233 destination()->Invert(); |
| 8133 LoadCondition(node->expression(), destination(), true); | 8234 LoadCondition(node->expression(), destination(), true); |
| 8134 // Swap the labels back. | 8235 // Swap the labels back. |
| 8135 destination()->Invert(); | 8236 destination()->Invert(); |
| 8136 | 8237 |
| 8137 } else if (op == Token::DELETE) { | 8238 } else if (op == Token::DELETE) { |
| 8138 Property* property = node->expression()->AsProperty(); | 8239 Property* property = node->expression()->AsProperty(); |
| 8139 if (property != NULL) { | 8240 if (property != NULL) { |
| 8140 Load(property->obj()); | 8241 Load(property->obj()); |
| 8141 Load(property->key()); | 8242 Load(property->key()); |
| 8142 Result answer = frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2); | 8243 frame_->Push(Smi::FromInt(strict_mode_flag())); |
| 8244 Result answer = frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 3); |
| 8143 frame_->Push(&answer); | 8245 frame_->Push(&answer); |
| 8144 return; | 8246 return; |
| 8145 } | 8247 } |
| 8146 | 8248 |
| 8147 Variable* variable = node->expression()->AsVariableProxy()->AsVariable(); | 8249 Variable* variable = node->expression()->AsVariableProxy()->AsVariable(); |
| 8148 if (variable != NULL) { | 8250 if (variable != NULL) { |
| 8251 // Delete of an unqualified identifier is disallowed in strict mode |
| 8252 // so this code can only be reached in non-strict mode. |
| 8253 ASSERT(strict_mode_flag() == kNonStrictMode); |
| 8149 Slot* slot = variable->AsSlot(); | 8254 Slot* slot = variable->AsSlot(); |
| 8150 if (variable->is_global()) { | 8255 if (variable->is_global()) { |
| 8151 LoadGlobal(); | 8256 LoadGlobal(); |
| 8152 frame_->Push(variable->name()); | 8257 frame_->Push(variable->name()); |
| 8258 frame_->Push(Smi::FromInt(kNonStrictMode)); |
| 8153 Result answer = frame_->InvokeBuiltin(Builtins::DELETE, | 8259 Result answer = frame_->InvokeBuiltin(Builtins::DELETE, |
| 8154 CALL_FUNCTION, 2); | 8260 CALL_FUNCTION, 3); |
| 8155 frame_->Push(&answer); | 8261 frame_->Push(&answer); |
| 8156 return; | 8262 return; |
| 8157 | 8263 |
| 8158 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { | 8264 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { |
| 8159 // Call the runtime to look up the context holding the named | 8265 // Call the runtime to delete from the context holding the named |
| 8160 // variable. Sync the virtual frame eagerly so we can push the | 8266 // variable. Sync the virtual frame eagerly so we can push the |
| 8161 // arguments directly into place. | 8267 // arguments directly into place. |
| 8162 frame_->SyncRange(0, frame_->element_count() - 1); | 8268 frame_->SyncRange(0, frame_->element_count() - 1); |
| 8163 frame_->EmitPush(esi); | 8269 frame_->EmitPush(esi); |
| 8164 frame_->EmitPush(Immediate(variable->name())); | 8270 frame_->EmitPush(Immediate(variable->name())); |
| 8165 Result context = frame_->CallRuntime(Runtime::kLookupContext, 2); | 8271 Result answer = frame_->CallRuntime(Runtime::kDeleteContextSlot, 2); |
| 8166 ASSERT(context.is_register()); | |
| 8167 frame_->EmitPush(context.reg()); | |
| 8168 context.Unuse(); | |
| 8169 frame_->EmitPush(Immediate(variable->name())); | |
| 8170 Result answer = frame_->InvokeBuiltin(Builtins::DELETE, | |
| 8171 CALL_FUNCTION, 2); | |
| 8172 frame_->Push(&answer); | 8272 frame_->Push(&answer); |
| 8173 return; | 8273 return; |
| 8174 } | 8274 } |
| 8175 | 8275 |
| 8176 // Default: Result of deleting non-global, not dynamically | 8276 // Default: Result of deleting non-global, not dynamically |
| 8177 // introduced variables is false. | 8277 // introduced variables is false. |
| 8178 frame_->Push(Factory::false_value()); | 8278 frame_->Push(Factory::false_value()); |
| 8179 | 8279 |
| 8180 } else { | 8280 } else { |
| 8181 // Default: Result of deleting expressions is true. | 8281 // Default: Result of deleting expressions is true. |
| (...skipping 1403 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9585 } | 9685 } |
| 9586 | 9686 |
| 9587 | 9687 |
| 9588 Result CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) { | 9688 Result CodeGenerator::EmitNamedStore(Handle<String> name, bool is_contextual) { |
| 9589 #ifdef DEBUG | 9689 #ifdef DEBUG |
| 9590 int expected_height = frame()->height() - (is_contextual ? 1 : 2); | 9690 int expected_height = frame()->height() - (is_contextual ? 1 : 2); |
| 9591 #endif | 9691 #endif |
| 9592 | 9692 |
| 9593 Result result; | 9693 Result result; |
| 9594 if (is_contextual || scope()->is_global_scope() || loop_nesting() == 0) { | 9694 if (is_contextual || scope()->is_global_scope() || loop_nesting() == 0) { |
| 9595 result = frame()->CallStoreIC(name, is_contextual); | 9695 result = frame()->CallStoreIC(name, is_contextual, strict_mode_flag()); |
| 9596 // A test eax instruction following the call signals that the inobject | 9696 // A test eax instruction following the call signals that the inobject |
| 9597 // property case was inlined. Ensure that there is not a test eax | 9697 // property case was inlined. Ensure that there is not a test eax |
| 9598 // instruction here. | 9698 // instruction here. |
| 9599 __ nop(); | 9699 __ nop(); |
| 9600 } else { | 9700 } else { |
| 9601 // Inline the in-object property case. | 9701 // Inline the in-object property case. |
| 9602 JumpTarget slow, done; | 9702 JumpTarget slow, done; |
| 9603 Label patch_site; | 9703 Label patch_site; |
| 9604 | 9704 |
| 9605 // Get the value and receiver from the stack. | 9705 // Get the value and receiver from the stack. |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9672 } | 9772 } |
| 9673 __ bind(&skip_write_barrier); | 9773 __ bind(&skip_write_barrier); |
| 9674 value.Unuse(); | 9774 value.Unuse(); |
| 9675 scratch.Unuse(); | 9775 scratch.Unuse(); |
| 9676 receiver.Unuse(); | 9776 receiver.Unuse(); |
| 9677 done.Jump(&result); | 9777 done.Jump(&result); |
| 9678 | 9778 |
| 9679 slow.Bind(&value, &receiver); | 9779 slow.Bind(&value, &receiver); |
| 9680 frame()->Push(&receiver); | 9780 frame()->Push(&receiver); |
| 9681 frame()->Push(&value); | 9781 frame()->Push(&value); |
| 9682 result = frame()->CallStoreIC(name, is_contextual); | 9782 result = frame()->CallStoreIC(name, is_contextual, strict_mode_flag()); |
| 9683 // Encode the offset to the map check instruction and the offset | 9783 // Encode the offset to the map check instruction and the offset |
| 9684 // to the write barrier store address computation in a test eax | 9784 // to the write barrier store address computation in a test eax |
| 9685 // instruction. | 9785 // instruction. |
| 9686 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site); | 9786 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site); |
| 9687 __ test(eax, | 9787 __ test(eax, |
| 9688 Immediate((delta_to_record_write << 16) | delta_to_patch_site)); | 9788 Immediate((delta_to_record_write << 16) | delta_to_patch_site)); |
| 9689 done.Bind(&result); | 9789 done.Bind(&result); |
| 9690 } | 9790 } |
| 9691 | 9791 |
| 9692 ASSERT_EQ(expected_height, frame()->height()); | 9792 ASSERT_EQ(expected_height, frame()->height()); |
| (...skipping 556 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10249 memcpy(base, desc.buffer, desc.instr_size); | 10349 memcpy(base, desc.buffer, desc.instr_size); |
| 10250 CPU::FlushICache(base, desc.instr_size); | 10350 CPU::FlushICache(base, desc.instr_size); |
| 10251 return FUNCTION_CAST<MemCopyFunction>(reinterpret_cast<Address>(base)); | 10351 return FUNCTION_CAST<MemCopyFunction>(reinterpret_cast<Address>(base)); |
| 10252 } | 10352 } |
| 10253 | 10353 |
| 10254 #undef __ | 10354 #undef __ |
| 10255 | 10355 |
| 10256 } } // namespace v8::internal | 10356 } } // namespace v8::internal |
| 10257 | 10357 |
| 10258 #endif // V8_TARGET_ARCH_IA32 | 10358 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |