| Index: src/x64/codegen-x64.cc
|
| diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc
|
| index 0fdef25c67b39c496e161329e1b2179b1e34de97..0411777aed96da8ee0c7c27873c36022ddf797e7 100644
|
| --- a/src/x64/codegen-x64.cc
|
| +++ b/src/x64/codegen-x64.cc
|
| @@ -4421,22 +4421,142 @@ void CodeGenerator::GenerateRegExpConstructResult(ZoneList<Expression*>* args) {
|
|
|
| class DeferredSearchCache: public DeferredCode {
|
| public:
|
| - DeferredSearchCache(Register dst, Register cache, Register key)
|
| - : dst_(dst), cache_(cache), key_(key) {
|
| + DeferredSearchCache(Register dst,
|
| + Register cache,
|
| + Register key,
|
| + Register scratch)
|
| + : dst_(dst), cache_(cache), key_(key), scratch_(scratch) {
|
| set_comment("[ DeferredSearchCache");
|
| }
|
|
|
| virtual void Generate();
|
|
|
| private:
|
| - Register dst_, cache_, key_;
|
| + Register dst_; // on invocation index of finger (as Smi), on exit
|
| + // holds value being looked up.
|
| + Register cache_; // instance of JSFunctionResultCache.
|
| + Register key_; // key being looked up.
|
| + Register scratch_;
|
| };
|
|
|
|
|
| +// Return a position of the element at |index| + |additional_offset|
|
| +// in FixedArray pointer to which is held in |array|. |index| is int32.
|
| +static Operand ArrayElement(Register array,
|
| + Register index,
|
| + int additional_offset = 0) {
|
| + int offset = FixedArray::kHeaderSize + additional_offset * kPointerSize;
|
| + return FieldOperand(array, index, times_pointer_size, offset);
|
| +}
|
| +
|
| +
|
| void DeferredSearchCache::Generate() {
|
| - __ push(cache_);
|
| + Label first_loop, search_further, second_loop, cache_miss;
|
| +
|
| + Immediate kEntriesIndexImm = Immediate(JSFunctionResultCache::kEntriesIndex);
|
| + Immediate kEntrySizeImm = Immediate(JSFunctionResultCache::kEntrySize);
|
| +
|
| + __ SmiToInteger32(dst_, dst_);
|
| + // Check the cache from finger to start of the cache.
|
| + __ bind(&first_loop);
|
| + __ subq(dst_, kEntrySizeImm);
|
| + __ cmpq(dst_, kEntriesIndexImm);
|
| + __ j(less, &search_further);
|
| +
|
| + __ cmpq(ArrayElement(cache_, dst_), key_);
|
| + __ j(not_equal, &first_loop);
|
| +
|
| + __ Integer32ToSmi(scratch_, dst_);
|
| + __ movq(FieldOperand(cache_, JSFunctionResultCache::kFingerOffset), scratch_);
|
| + __ movq(dst_, ArrayElement(cache_, dst_, 1));
|
| + __ jmp(exit_label());
|
| +
|
| + __ bind(&search_further);
|
| +
|
| + // Check the cache from end of cache up to finger.
|
| + __ movq(dst_, FieldOperand(cache_, JSFunctionResultCache::kCacheSizeOffset));
|
| + __ movq(scratch_, FieldOperand(cache_, JSFunctionResultCache::kFingerOffset));
|
| + __ SmiToInteger32(dst_, dst_);
|
| + __ SmiToInteger32(scratch_, scratch_);
|
| +
|
| + __ bind(&second_loop);
|
| + __ subq(dst_, kEntrySizeImm);
|
| + __ cmpq(dst_, scratch_);
|
| + __ j(less_equal, &cache_miss);
|
| +
|
| + __ cmpq(ArrayElement(cache_, dst_), key_);
|
| + __ j(not_equal, &second_loop);
|
| +
|
| + __ Integer32ToSmi(scratch_, dst_);
|
| + __ movq(FieldOperand(cache_, JSFunctionResultCache::kFingerOffset), scratch_);
|
| + __ movq(dst_, ArrayElement(cache_, dst_, 1));
|
| + __ jmp(exit_label());
|
| +
|
| + __ bind(&cache_miss);
|
| + __ push(cache_); // store a reference to cache
|
| + __ push(key_); // store a key
|
| + Handle<Object> receiver(Top::global_context()->global());
|
| + __ Push(receiver);
|
| __ push(key_);
|
| - __ CallRuntime(Runtime::kGetFromCache, 2);
|
| + // On x64 function must be in rdi.
|
| + __ movq(rdi, FieldOperand(cache_, JSFunctionResultCache::kFactoryOffset));
|
| + ParameterCount expected(1);
|
| + __ InvokeFunction(rdi, expected, CALL_FUNCTION);
|
| +
|
| + // Find a place to put new cached value into.
|
| + Label add_new_entry, update_cache;
|
| + __ movq(rcx, Operand(rsp, kPointerSize)); // restore the cache
|
| + // Possible optimization: cache size is constant for the given cache
|
| + // so technically we could use a constant here. However, if we have
|
| + // cache miss this optimization would hardly matter much.
|
| +
|
| + // Check if we could add new entry to cache.
|
| + __ movl(rbx, FieldOperand(rcx, FixedArray::kLengthOffset));
|
| + __ movq(r9, FieldOperand(rcx, JSFunctionResultCache::kCacheSizeOffset));
|
| + __ SmiToInteger32(r9, r9);
|
| + __ cmpq(rbx, r9);
|
| + __ j(greater, &add_new_entry);
|
| +
|
| + // Check if we could evict entry after finger.
|
| + __ movq(rdx, FieldOperand(rcx, JSFunctionResultCache::kFingerOffset));
|
| + __ SmiToInteger32(rdx, rdx);
|
| + __ addq(rdx, kEntrySizeImm);
|
| + Label forward;
|
| + __ cmpq(rbx, rdx);
|
| + __ j(greater, &forward);
|
| + // Need to wrap over the cache.
|
| + __ movq(rdx, kEntriesIndexImm);
|
| + __ bind(&forward);
|
| + __ Integer32ToSmi(r9, rdx);
|
| + __ jmp(&update_cache);
|
| +
|
| + __ bind(&add_new_entry);
|
| + // r9 holds cache size as int.
|
| + __ movq(rdx, r9);
|
| + __ Integer32ToSmi(r9, r9);
|
| + __ SmiAddConstant(rbx, r9, Smi::FromInt(JSFunctionResultCache::kEntrySize));
|
| + __ movq(FieldOperand(rcx, JSFunctionResultCache::kCacheSizeOffset), rbx);
|
| +
|
| + // Update the cache itself.
|
| + // rdx holds the index as int.
|
| + // r9 holds the index as smi.
|
| + __ bind(&update_cache);
|
| + __ pop(rbx); // restore the key
|
| + __ movq(FieldOperand(rcx, JSFunctionResultCache::kFingerOffset), r9);
|
| + // Store key.
|
| + __ movq(ArrayElement(rcx, rdx), rbx);
|
| + __ RecordWrite(rcx, 0, rbx, r9);
|
| +
|
| + // Store value.
|
| + __ pop(rcx); // restore the cache.
|
| + __ movq(rdx, FieldOperand(rcx, JSFunctionResultCache::kFingerOffset));
|
| + __ SmiAddConstant(rdx, rdx, Smi::FromInt(1));
|
| + __ movq(r9, rdx);
|
| + __ SmiToInteger32(rdx, rdx);
|
| + __ movq(rbx, rax);
|
| + __ movq(ArrayElement(rcx, rdx), rbx);
|
| + __ RecordWrite(rcx, 0, rbx, r9);
|
| +
|
| if (!dst_.is(rax)) {
|
| __ movq(dst_, rax);
|
| }
|
| @@ -4474,27 +4594,28 @@ void CodeGenerator::GenerateGetFromCache(ZoneList<Expression*>* args) {
|
| Result tmp = allocator()->Allocate();
|
| ASSERT(tmp.is_valid());
|
|
|
| + Result scratch = allocator()->Allocate();
|
| + ASSERT(scratch.is_valid());
|
| +
|
| DeferredSearchCache* deferred = new DeferredSearchCache(tmp.reg(),
|
| cache.reg(),
|
| - key.reg());
|
| + key.reg(),
|
| + scratch.reg());
|
|
|
| const int kFingerOffset =
|
| FixedArray::OffsetOfElementAt(JSFunctionResultCache::kFingerIndex);
|
| // tmp.reg() now holds finger offset as a smi.
|
| - ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
|
| __ movq(tmp.reg(), FieldOperand(cache.reg(), kFingerOffset));
|
| SmiIndex index =
|
| masm()->SmiToIndex(kScratchRegister, tmp.reg(), kPointerSizeLog2);
|
| __ cmpq(key.reg(), FieldOperand(cache.reg(),
|
| - index.reg,
|
| - index.scale,
|
| + index.reg, index.scale,
|
| FixedArray::kHeaderSize));
|
| + // Do NOT alter index.reg or tmp.reg() before cmpq below.
|
| deferred->Branch(not_equal);
|
| -
|
| __ movq(tmp.reg(), FieldOperand(cache.reg(),
|
| - index.reg,
|
| - index.scale,
|
| - kPointerSize + FixedArray::kHeaderSize));
|
| + index.reg, index.scale,
|
| + FixedArray::kHeaderSize + kPointerSize));
|
|
|
| deferred->BindExit();
|
| frame_->Push(&tmp);
|
|
|