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 4209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4220 // targets only after all the state is pushed on the frame. | 4220 // targets only after all the state is pushed on the frame. |
4221 node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); | 4221 node->break_target()->set_direction(JumpTarget::FORWARD_ONLY); |
4222 node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); | 4222 node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY); |
4223 | 4223 |
4224 __ mov(eax, frame_->ElementAt(0)); // load the current count | 4224 __ mov(eax, frame_->ElementAt(0)); // load the current count |
4225 __ cmp(eax, frame_->ElementAt(1)); // compare to the array length | 4225 __ cmp(eax, frame_->ElementAt(1)); // compare to the array length |
4226 node->break_target()->Branch(above_equal); | 4226 node->break_target()->Branch(above_equal); |
4227 | 4227 |
4228 // Get the i'th entry of the array. | 4228 // Get the i'th entry of the array. |
4229 __ mov(edx, frame_->ElementAt(2)); | 4229 __ mov(edx, frame_->ElementAt(2)); |
4230 __ mov(ebx, Operand(edx, eax, times_2, | 4230 __ mov(ebx, FixedArrayElementOperand(edx, eax)); |
4231 FixedArray::kHeaderSize - kHeapObjectTag)); | |
4232 | 4231 |
4233 // Get the expected map from the stack or a zero map in the | 4232 // Get the expected map from the stack or a zero map in the |
4234 // permanent slow case eax: current iteration count ebx: i'th entry | 4233 // permanent slow case eax: current iteration count ebx: i'th entry |
4235 // of the enum cache | 4234 // of the enum cache |
4236 __ mov(edx, frame_->ElementAt(3)); | 4235 __ mov(edx, frame_->ElementAt(3)); |
4237 // Check if the expected map still matches that of the enumerable. | 4236 // Check if the expected map still matches that of the enumerable. |
4238 // If not, we have to filter the key. | 4237 // If not, we have to filter the key. |
4239 // eax: current iteration count | 4238 // eax: current iteration count |
4240 // ebx: i'th entry of the enum cache | 4239 // ebx: i'th entry of the enum cache |
4241 // edx: expected map value | 4240 // edx: expected map value |
(...skipping 2385 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6627 virtual void Generate(); | 6626 virtual void Generate(); |
6628 | 6627 |
6629 private: | 6628 private: |
6630 Register dst_; // on invocation Smi index of finger, on exit | 6629 Register dst_; // on invocation Smi index of finger, on exit |
6631 // holds value being looked up. | 6630 // holds value being looked up. |
6632 Register cache_; // instance of JSFunctionResultCache. | 6631 Register cache_; // instance of JSFunctionResultCache. |
6633 Register key_; // key being looked up. | 6632 Register key_; // key being looked up. |
6634 }; | 6633 }; |
6635 | 6634 |
6636 | 6635 |
6637 // Return a position of the element at |index_as_smi| + |additional_offset| | |
6638 // in FixedArray pointer to which is held in |array|. |index_as_smi| is Smi. | |
6639 static Operand ArrayElement(Register array, | |
6640 Register index_as_smi, | |
6641 int additional_offset = 0) { | |
6642 int offset = FixedArray::kHeaderSize + additional_offset * kPointerSize; | |
6643 return FieldOperand(array, index_as_smi, times_half_pointer_size, offset); | |
6644 } | |
6645 | |
6646 | |
6647 void DeferredSearchCache::Generate() { | 6636 void DeferredSearchCache::Generate() { |
6648 Label first_loop, search_further, second_loop, cache_miss; | 6637 Label first_loop, search_further, second_loop, cache_miss; |
6649 | 6638 |
6650 // Smi-tagging is equivalent to multiplying by 2. | 6639 // Smi-tagging is equivalent to multiplying by 2. |
6651 STATIC_ASSERT(kSmiTag == 0); | 6640 STATIC_ASSERT(kSmiTag == 0); |
6652 STATIC_ASSERT(kSmiTagSize == 1); | 6641 STATIC_ASSERT(kSmiTagSize == 1); |
6653 | 6642 |
6654 Smi* kEntrySizeSmi = Smi::FromInt(JSFunctionResultCache::kEntrySize); | 6643 Smi* kEntrySizeSmi = Smi::FromInt(JSFunctionResultCache::kEntrySize); |
6655 Smi* kEntriesIndexSmi = Smi::FromInt(JSFunctionResultCache::kEntriesIndex); | 6644 Smi* kEntriesIndexSmi = Smi::FromInt(JSFunctionResultCache::kEntriesIndex); |
6656 | 6645 |
6657 // Check the cache from finger to start of the cache. | 6646 // Check the cache from finger to start of the cache. |
6658 __ bind(&first_loop); | 6647 __ bind(&first_loop); |
6659 __ sub(Operand(dst_), Immediate(kEntrySizeSmi)); | 6648 __ sub(Operand(dst_), Immediate(kEntrySizeSmi)); |
6660 __ cmp(Operand(dst_), Immediate(kEntriesIndexSmi)); | 6649 __ cmp(Operand(dst_), Immediate(kEntriesIndexSmi)); |
6661 __ j(less, &search_further); | 6650 __ j(less, &search_further); |
6662 | 6651 |
6663 __ cmp(key_, ArrayElement(cache_, dst_)); | 6652 __ cmp(key_, CodeGenerator::FixedArrayElementOperand(cache_, dst_)); |
6664 __ j(not_equal, &first_loop); | 6653 __ j(not_equal, &first_loop); |
6665 | 6654 |
6666 __ mov(FieldOperand(cache_, JSFunctionResultCache::kFingerOffset), dst_); | 6655 __ mov(FieldOperand(cache_, JSFunctionResultCache::kFingerOffset), dst_); |
6667 __ mov(dst_, ArrayElement(cache_, dst_, 1)); | 6656 __ mov(dst_, CodeGenerator::FixedArrayElementOperand(cache_, dst_, 1)); |
6668 __ jmp(exit_label()); | 6657 __ jmp(exit_label()); |
6669 | 6658 |
6670 __ bind(&search_further); | 6659 __ bind(&search_further); |
6671 | 6660 |
6672 // Check the cache from end of cache up to finger. | 6661 // Check the cache from end of cache up to finger. |
6673 __ mov(dst_, FieldOperand(cache_, JSFunctionResultCache::kCacheSizeOffset)); | 6662 __ mov(dst_, FieldOperand(cache_, JSFunctionResultCache::kCacheSizeOffset)); |
6674 | 6663 |
6675 __ bind(&second_loop); | 6664 __ bind(&second_loop); |
6676 __ sub(Operand(dst_), Immediate(kEntrySizeSmi)); | 6665 __ sub(Operand(dst_), Immediate(kEntrySizeSmi)); |
6677 // Consider prefetching into some reg. | 6666 // Consider prefetching into some reg. |
6678 __ cmp(dst_, FieldOperand(cache_, JSFunctionResultCache::kFingerOffset)); | 6667 __ cmp(dst_, FieldOperand(cache_, JSFunctionResultCache::kFingerOffset)); |
6679 __ j(less_equal, &cache_miss); | 6668 __ j(less_equal, &cache_miss); |
6680 | 6669 |
6681 __ cmp(key_, ArrayElement(cache_, dst_)); | 6670 __ cmp(key_, CodeGenerator::FixedArrayElementOperand(cache_, dst_)); |
6682 __ j(not_equal, &second_loop); | 6671 __ j(not_equal, &second_loop); |
6683 | 6672 |
6684 __ mov(FieldOperand(cache_, JSFunctionResultCache::kFingerOffset), dst_); | 6673 __ mov(FieldOperand(cache_, JSFunctionResultCache::kFingerOffset), dst_); |
6685 __ mov(dst_, ArrayElement(cache_, dst_, 1)); | 6674 __ mov(dst_, CodeGenerator::FixedArrayElementOperand(cache_, dst_, 1)); |
6686 __ jmp(exit_label()); | 6675 __ jmp(exit_label()); |
6687 | 6676 |
6688 __ bind(&cache_miss); | 6677 __ bind(&cache_miss); |
6689 __ push(cache_); // store a reference to cache | 6678 __ push(cache_); // store a reference to cache |
6690 __ push(key_); // store a key | 6679 __ push(key_); // store a key |
6691 Handle<Object> receiver(Top::global_context()->global()); | 6680 Handle<Object> receiver(Top::global_context()->global()); |
6692 __ push(Immediate(receiver)); | 6681 __ push(Immediate(receiver)); |
6693 __ push(key_); | 6682 __ push(key_); |
6694 // On ia32 function must be in edi. | 6683 // On ia32 function must be in edi. |
6695 __ mov(edi, FieldOperand(cache_, JSFunctionResultCache::kFactoryOffset)); | 6684 __ mov(edi, FieldOperand(cache_, JSFunctionResultCache::kFactoryOffset)); |
(...skipping 27 matching lines...) Expand all Loading... |
6723 __ mov(edx, FieldOperand(ecx, JSFunctionResultCache::kCacheSizeOffset)); | 6712 __ mov(edx, FieldOperand(ecx, JSFunctionResultCache::kCacheSizeOffset)); |
6724 __ lea(ebx, Operand(edx, JSFunctionResultCache::kEntrySize << 1)); | 6713 __ lea(ebx, Operand(edx, JSFunctionResultCache::kEntrySize << 1)); |
6725 __ mov(FieldOperand(ecx, JSFunctionResultCache::kCacheSizeOffset), ebx); | 6714 __ mov(FieldOperand(ecx, JSFunctionResultCache::kCacheSizeOffset), ebx); |
6726 | 6715 |
6727 // Update the cache itself. | 6716 // Update the cache itself. |
6728 // edx holds the index. | 6717 // edx holds the index. |
6729 __ bind(&update_cache); | 6718 __ bind(&update_cache); |
6730 __ pop(ebx); // restore the key | 6719 __ pop(ebx); // restore the key |
6731 __ mov(FieldOperand(ecx, JSFunctionResultCache::kFingerOffset), edx); | 6720 __ mov(FieldOperand(ecx, JSFunctionResultCache::kFingerOffset), edx); |
6732 // Store key. | 6721 // Store key. |
6733 __ mov(ArrayElement(ecx, edx), ebx); | 6722 __ mov(CodeGenerator::FixedArrayElementOperand(ecx, edx), ebx); |
6734 __ RecordWrite(ecx, 0, ebx, edx); | 6723 __ RecordWrite(ecx, 0, ebx, edx); |
6735 | 6724 |
6736 // Store value. | 6725 // Store value. |
6737 __ pop(ecx); // restore the cache. | 6726 __ pop(ecx); // restore the cache. |
6738 __ mov(edx, FieldOperand(ecx, JSFunctionResultCache::kFingerOffset)); | 6727 __ mov(edx, FieldOperand(ecx, JSFunctionResultCache::kFingerOffset)); |
6739 __ add(Operand(edx), Immediate(Smi::FromInt(1))); | 6728 __ add(Operand(edx), Immediate(Smi::FromInt(1))); |
6740 __ mov(ebx, eax); | 6729 __ mov(ebx, eax); |
6741 __ mov(ArrayElement(ecx, edx), ebx); | 6730 __ mov(CodeGenerator::FixedArrayElementOperand(ecx, edx), ebx); |
6742 __ RecordWrite(ecx, 0, ebx, edx); | 6731 __ RecordWrite(ecx, 0, ebx, edx); |
6743 | 6732 |
6744 if (!dst_.is(eax)) { | 6733 if (!dst_.is(eax)) { |
6745 __ mov(dst_, eax); | 6734 __ mov(dst_, eax); |
6746 } | 6735 } |
6747 } | 6736 } |
6748 | 6737 |
6749 | 6738 |
6750 void CodeGenerator::GenerateGetFromCache(ZoneList<Expression*>* args) { | 6739 void CodeGenerator::GenerateGetFromCache(ZoneList<Expression*>* args) { |
6751 ASSERT_EQ(2, args->length()); | 6740 ASSERT_EQ(2, args->length()); |
(...skipping 26 matching lines...) Expand all Loading... |
6778 Result tmp = allocator()->Allocate(); | 6767 Result tmp = allocator()->Allocate(); |
6779 ASSERT(tmp.is_valid()); | 6768 ASSERT(tmp.is_valid()); |
6780 | 6769 |
6781 DeferredSearchCache* deferred = new DeferredSearchCache(tmp.reg(), | 6770 DeferredSearchCache* deferred = new DeferredSearchCache(tmp.reg(), |
6782 cache.reg(), | 6771 cache.reg(), |
6783 key.reg()); | 6772 key.reg()); |
6784 | 6773 |
6785 // tmp.reg() now holds finger offset as a smi. | 6774 // tmp.reg() now holds finger offset as a smi. |
6786 ASSERT(kSmiTag == 0 && kSmiTagSize == 1); | 6775 ASSERT(kSmiTag == 0 && kSmiTagSize == 1); |
6787 __ mov(tmp.reg(), FieldOperand(cache.reg(), | 6776 __ mov(tmp.reg(), FieldOperand(cache.reg(), |
6788 JSFunctionResultCache::kFingerOffset)); | 6777 JSFunctionResultCache::kFingerOffset)); |
6789 __ cmp(key.reg(), ArrayElement(cache.reg(), tmp.reg())); | 6778 __ cmp(key.reg(), FixedArrayElementOperand(cache.reg(), tmp.reg())); |
6790 deferred->Branch(not_equal); | 6779 deferred->Branch(not_equal); |
6791 | 6780 |
6792 __ mov(tmp.reg(), ArrayElement(cache.reg(), tmp.reg(), 1)); | 6781 __ mov(tmp.reg(), FixedArrayElementOperand(cache.reg(), tmp.reg(), 1)); |
6793 | 6782 |
6794 deferred->BindExit(); | 6783 deferred->BindExit(); |
6795 frame_->Push(&tmp); | 6784 frame_->Push(&tmp); |
6796 } | 6785 } |
6797 | 6786 |
6798 | 6787 |
6799 void CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) { | 6788 void CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) { |
6800 ASSERT_EQ(args->length(), 1); | 6789 ASSERT_EQ(args->length(), 1); |
6801 | 6790 |
6802 // Load the argument on the stack and call the stub. | 6791 // Load the argument on the stack and call the stub. |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6881 STATIC_ASSERT(kSmiTag == 0); | 6870 STATIC_ASSERT(kSmiTag == 0); |
6882 STATIC_ASSERT(kSmiTagSize == 1); | 6871 STATIC_ASSERT(kSmiTagSize == 1); |
6883 | 6872 |
6884 // Check that both indices are smis. | 6873 // Check that both indices are smis. |
6885 __ mov(tmp2.reg(), index1.reg()); | 6874 __ mov(tmp2.reg(), index1.reg()); |
6886 __ or_(tmp2.reg(), Operand(index2.reg())); | 6875 __ or_(tmp2.reg(), Operand(index2.reg())); |
6887 __ test(tmp2.reg(), Immediate(kSmiTagMask)); | 6876 __ test(tmp2.reg(), Immediate(kSmiTagMask)); |
6888 deferred->Branch(not_zero); | 6877 deferred->Branch(not_zero); |
6889 | 6878 |
6890 // Bring addresses into index1 and index2. | 6879 // Bring addresses into index1 and index2. |
6891 __ lea(index1.reg(), FieldOperand(tmp1.reg(), | 6880 __ lea(index1.reg(), FixedArrayElementOperand(tmp1.reg(), index1.reg())); |
6892 index1.reg(), | 6881 __ lea(index2.reg(), FixedArrayElementOperand(tmp1.reg(), index2.reg())); |
6893 times_half_pointer_size, // index1 is Smi | |
6894 FixedArray::kHeaderSize)); | |
6895 __ lea(index2.reg(), FieldOperand(tmp1.reg(), | |
6896 index2.reg(), | |
6897 times_half_pointer_size, // index2 is Smi | |
6898 FixedArray::kHeaderSize)); | |
6899 | 6882 |
6900 // Swap elements. | 6883 // Swap elements. |
6901 __ mov(object.reg(), Operand(index1.reg(), 0)); | 6884 __ mov(object.reg(), Operand(index1.reg(), 0)); |
6902 __ mov(tmp2.reg(), Operand(index2.reg(), 0)); | 6885 __ mov(tmp2.reg(), Operand(index2.reg(), 0)); |
6903 __ mov(Operand(index2.reg(), 0), object.reg()); | 6886 __ mov(Operand(index2.reg(), 0), object.reg()); |
6904 __ mov(Operand(index1.reg(), 0), tmp2.reg()); | 6887 __ mov(Operand(index1.reg(), 0), tmp2.reg()); |
6905 | 6888 |
6906 Label done; | 6889 Label done; |
6907 __ InNewSpace(tmp1.reg(), tmp2.reg(), equal, &done); | 6890 __ InNewSpace(tmp1.reg(), tmp2.reg(), equal, &done); |
6908 // Possible optimization: do a check that both values are Smis | 6891 // Possible optimization: do a check that both values are Smis |
(...skipping 1852 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8761 // Bind the deferred code patch site to be able to locate the fixed | 8744 // Bind the deferred code patch site to be able to locate the fixed |
8762 // array map comparison. When debugging, we patch this comparison to | 8745 // array map comparison. When debugging, we patch this comparison to |
8763 // always fail so that we will hit the IC call in the deferred code | 8746 // always fail so that we will hit the IC call in the deferred code |
8764 // which will allow the debugger to break for fast case stores. | 8747 // which will allow the debugger to break for fast case stores. |
8765 __ bind(deferred->patch_site()); | 8748 __ bind(deferred->patch_site()); |
8766 __ cmp(FieldOperand(tmp.reg(), HeapObject::kMapOffset), | 8749 __ cmp(FieldOperand(tmp.reg(), HeapObject::kMapOffset), |
8767 Immediate(Factory::fixed_array_map())); | 8750 Immediate(Factory::fixed_array_map())); |
8768 deferred->Branch(not_equal); | 8751 deferred->Branch(not_equal); |
8769 | 8752 |
8770 // Store the value. | 8753 // Store the value. |
8771 __ mov(Operand(tmp.reg(), | 8754 __ mov(FixedArrayElementOperand(tmp.reg(), key.reg()), result.reg()); |
8772 key.reg(), | |
8773 times_2, | |
8774 FixedArray::kHeaderSize - kHeapObjectTag), | |
8775 result.reg()); | |
8776 __ IncrementCounter(&Counters::keyed_store_inline, 1); | 8755 __ IncrementCounter(&Counters::keyed_store_inline, 1); |
8777 | 8756 |
8778 deferred->BindExit(); | 8757 deferred->BindExit(); |
8779 } else { | 8758 } else { |
8780 result = frame()->CallKeyedStoreIC(); | 8759 result = frame()->CallKeyedStoreIC(); |
8781 // Make sure that we do not have a test instruction after the | 8760 // Make sure that we do not have a test instruction after the |
8782 // call. A test instruction after the call is used to | 8761 // call. A test instruction after the call is used to |
8783 // indicate that we have generated an inline version of the | 8762 // indicate that we have generated an inline version of the |
8784 // keyed store. | 8763 // keyed store. |
8785 __ nop(); | 8764 __ nop(); |
(...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9067 // All sizes here are multiples of kPointerSize. | 9046 // All sizes here are multiples of kPointerSize. |
9068 int elements_size = (length_ > 0) ? FixedArray::SizeFor(length_) : 0; | 9047 int elements_size = (length_ > 0) ? FixedArray::SizeFor(length_) : 0; |
9069 int size = JSArray::kSize + elements_size; | 9048 int size = JSArray::kSize + elements_size; |
9070 | 9049 |
9071 // Load boilerplate object into ecx and check if we need to create a | 9050 // Load boilerplate object into ecx and check if we need to create a |
9072 // boilerplate. | 9051 // boilerplate. |
9073 Label slow_case; | 9052 Label slow_case; |
9074 __ mov(ecx, Operand(esp, 3 * kPointerSize)); | 9053 __ mov(ecx, Operand(esp, 3 * kPointerSize)); |
9075 __ mov(eax, Operand(esp, 2 * kPointerSize)); | 9054 __ mov(eax, Operand(esp, 2 * kPointerSize)); |
9076 ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0)); | 9055 ASSERT((kPointerSize == 4) && (kSmiTagSize == 1) && (kSmiTag == 0)); |
9077 __ mov(ecx, FieldOperand(ecx, eax, times_2, FixedArray::kHeaderSize)); | 9056 __ mov(ecx, CodeGenerator::FixedArrayElementOperand(ecx, eax)); |
9078 __ cmp(ecx, Factory::undefined_value()); | 9057 __ cmp(ecx, Factory::undefined_value()); |
9079 __ j(equal, &slow_case); | 9058 __ j(equal, &slow_case); |
9080 | 9059 |
9081 // Allocate both the JS array and the elements array in one big | 9060 // Allocate both the JS array and the elements array in one big |
9082 // allocation. This avoids multiple limit checks. | 9061 // allocation. This avoids multiple limit checks. |
9083 __ AllocateInNewSpace(size, eax, ebx, edx, &slow_case, TAG_OBJECT); | 9062 __ AllocateInNewSpace(size, eax, ebx, edx, &slow_case, TAG_OBJECT); |
9084 | 9063 |
9085 // Copy the JS array part. | 9064 // Copy the JS array part. |
9086 for (int i = 0; i < JSArray::kSize; i += kPointerSize) { | 9065 for (int i = 0; i < JSArray::kSize; i += kPointerSize) { |
9087 if ((i != JSArray::kElementsOffset) || (length_ == 0)) { | 9066 if ((i != JSArray::kElementsOffset) || (length_ == 0)) { |
(...skipping 4201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13289 | 13268 |
13290 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 13269 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
13291 // tagged as a small integer. | 13270 // tagged as a small integer. |
13292 __ bind(&runtime); | 13271 __ bind(&runtime); |
13293 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 13272 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
13294 } | 13273 } |
13295 | 13274 |
13296 #undef __ | 13275 #undef __ |
13297 | 13276 |
13298 } } // namespace v8::internal | 13277 } } // namespace v8::internal |
OLD | NEW |