Index: src/arm/ic-arm.cc |
=================================================================== |
--- src/arm/ic-arm.cc (revision 4252) |
+++ src/arm/ic-arm.cc (working copy) |
@@ -65,12 +65,12 @@ |
// Check for the absence of an interceptor. |
// Load the map into t0. |
__ ldr(t0, FieldMemOperand(t1, JSObject::kMapOffset)); |
- // Test the has_named_interceptor bit in the map. |
- __ ldr(r3, FieldMemOperand(t0, Map::kInstanceAttributesOffset)); |
- __ tst(r3, Operand(1 << (Map::kHasNamedInterceptor + (3 * 8)))); |
- // Jump to miss if the interceptor bit is set. |
- __ b(ne, miss); |
+ // Bail out if the receiver has a named interceptor. |
+ __ ldrb(r3, FieldMemOperand(t0, Map::kBitFieldOffset)); |
+ __ tst(r3, Operand(1 << Map::kHasNamedInterceptor)); |
+ __ b(nz, miss); |
+ |
// Bail out if we have a JS global proxy object. |
__ ldrb(r3, FieldMemOperand(t0, Map::kInstanceTypeOffset)); |
__ cmp(r3, Operand(JS_GLOBAL_PROXY_TYPE)); |
@@ -144,6 +144,95 @@ |
} |
+static void GenerateNumberDictionaryLoad(MacroAssembler* masm, |
+ Label* miss, |
+ Register elements, |
+ Register key, |
+ Register t0, |
+ Register t1, |
+ Register t2) { |
+ // Register use: |
+ // |
+ // elements - holds the slow-case elements of the receiver and is unchanged. |
+ // |
+ // key - holds the smi key on entry and is unchanged if a branch is |
+ // performed to the miss label. |
+ // |
+ // Scratch registers: |
+ // |
+ // t0 - holds the untagged key on entry and holds the hash once computed. |
+ // Holds the result on exit if the load succeeded. |
+ // |
+ // t1 - used to hold the capacity mask of the dictionary |
+ // |
+ // t2 - used for the index into the dictionary. |
+ Label done; |
+ |
+ // Compute the hash code from the untagged key. This must be kept in sync |
+ // with ComputeIntegerHash in utils.h. |
+ // |
+ // hash = ~hash + (hash << 15); |
+ __ mvn(t1, Operand(t0)); |
+ __ add(t0, t1, Operand(t0, LSL, 15)); |
+ // hash = hash ^ (hash >> 12); |
+ __ eor(t0, t0, Operand(t0, LSR, 12)); |
+ // hash = hash + (hash << 2); |
+ __ add(t0, t0, Operand(t0, LSL, 2)); |
+ // hash = hash ^ (hash >> 4); |
+ __ eor(t0, t0, Operand(t0, LSR, 4)); |
+ // hash = hash * 2057; |
+ __ mov(t1, Operand(2057)); |
+ __ mul(t0, t0, t1); |
+ // hash = hash ^ (hash >> 16); |
+ __ eor(t0, t0, Operand(t0, LSR, 16)); |
+ |
+ // Compute the capacity mask. |
+ __ ldr(t1, FieldMemOperand(elements, NumberDictionary::kCapacityOffset)); |
+ __ mov(t1, Operand(t1, ASR, kSmiTagSize)); // convert smi to int |
+ __ sub(t1, t1, Operand(1)); |
+ |
+ // Generate an unrolled loop that performs a few probes before giving up. |
+ static const int kProbes = 4; |
+ for (int i = 0; i < kProbes; i++) { |
+ // Use t2 for index calculations and keep the hash intact in t0. |
+ __ mov(t2, t0); |
+ // Compute the masked index: (hash + i + i * i) & mask. |
+ if (i > 0) { |
+ __ add(t2, t2, Operand(NumberDictionary::GetProbeOffset(i))); |
+ } |
+ __ and_(t2, t2, Operand(t1)); |
+ |
+ // Scale the index by multiplying by the element size. |
+ ASSERT(NumberDictionary::kEntrySize == 3); |
+ __ add(t2, t2, Operand(t2, LSL, 1)); // t2 = t2 * 3 |
+ |
+ // Check if the key is identical to the name. |
+ __ add(t2, elements, Operand(t2, LSL, kPointerSizeLog2)); |
+ __ ldr(ip, FieldMemOperand(t2, NumberDictionary::kElementsStartOffset)); |
+ __ cmp(key, Operand(ip)); |
+ if (i != kProbes - 1) { |
+ __ b(eq, &done); |
+ } else { |
+ __ b(ne, miss); |
+ } |
+ } |
+ |
+ __ bind(&done); |
+ // Check that the value is a normal property. |
+ // t2: elements + (index * kPointerSize) |
+ const int kDetailsOffset = |
+ NumberDictionary::kElementsStartOffset + 2 * kPointerSize; |
+ __ ldr(t1, FieldMemOperand(t2, kDetailsOffset)); |
+ __ tst(t1, Operand(Smi::FromInt(PropertyDetails::TypeField::mask()))); |
+ __ b(ne, miss); |
+ |
+ // Get the value at the masked, scaled index and return. |
+ const int kValueOffset = |
+ NumberDictionary::kElementsStartOffset + kPointerSize; |
+ __ ldr(t0, FieldMemOperand(t2, kValueOffset)); |
+} |
+ |
+ |
void LoadIC::GenerateArrayLength(MacroAssembler* masm) { |
// ----------- S t a t e ------------- |
// -- r2 : name |
@@ -530,7 +619,7 @@ |
// -- sp[0] : key |
// -- sp[4] : receiver |
// ----------------------------------- |
- Label slow, fast, check_pixel_array; |
+ Label slow, fast, check_pixel_array, check_number_dictionary; |
// Get the key and receiver object from the stack. |
__ ldm(ia, sp, r0.bit() | r1.bit()); |
@@ -554,6 +643,8 @@ |
// Check that the key is a smi. |
__ BranchOnNotSmi(r0, &slow); |
+ // Save key in r2 in case we want it for the number dictionary case. |
+ __ mov(r2, r0); |
__ mov(r0, Operand(r0, ASR, kSmiTagSize)); |
// Get the elements array of the object. |
@@ -562,17 +653,26 @@ |
__ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset)); |
__ LoadRoot(ip, Heap::kFixedArrayMapRootIndex); |
__ cmp(r3, ip); |
- __ b(ne, &slow); |
+ __ b(ne, &check_pixel_array); |
// Check that the key (index) is within bounds. |
__ ldr(r3, FieldMemOperand(r1, Array::kLengthOffset)); |
__ cmp(r0, Operand(r3)); |
- __ b(lo, &fast); |
+ __ b(ge, &slow); |
+ // Fast case: Do the load. |
+ __ add(r3, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
+ __ ldr(r0, MemOperand(r3, r0, LSL, kPointerSizeLog2)); |
+ __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
+ __ cmp(r0, ip); |
+ // In case the loaded value is the_hole we have to consult GetProperty |
+ // to ensure the prototype chain is searched. |
+ __ b(eq, &slow); |
+ __ Ret(); |
// Check whether the elements is a pixel array. |
__ bind(&check_pixel_array); |
__ LoadRoot(ip, Heap::kPixelArrayMapRootIndex); |
__ cmp(r3, ip); |
- __ b(ne, &slow); |
+ __ b(ne, &check_number_dictionary); |
__ ldr(ip, FieldMemOperand(r1, PixelArray::kLengthOffset)); |
__ cmp(r0, ip); |
__ b(hs, &slow); |
@@ -581,22 +681,21 @@ |
__ mov(r0, Operand(r0, LSL, kSmiTagSize)); // Tag result as smi. |
__ Ret(); |
+ __ bind(&check_number_dictionary); |
+ // Check whether the elements is a number dictionary. |
+ // r0: untagged index |
+ // r1: elements |
+ // r2: key |
+ __ LoadRoot(ip, Heap::kHashTableMapRootIndex); |
+ __ cmp(r3, ip); |
+ __ b(ne, &slow); |
+ GenerateNumberDictionaryLoad(masm, &slow, r1, r2, r0, r3, r4); |
+ __ Ret(); |
+ |
// Slow case: Push extra copies of the arguments (2). |
__ bind(&slow); |
__ IncrementCounter(&Counters::keyed_load_generic_slow, 1, r0, r1); |
GenerateRuntimeGetProperty(masm); |
- |
- // Fast case: Do the load. |
- __ bind(&fast); |
- __ add(r3, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag)); |
- __ ldr(r0, MemOperand(r3, r0, LSL, kPointerSizeLog2)); |
- __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); |
- __ cmp(r0, ip); |
- // In case the loaded value is the_hole we have to consult GetProperty |
- // to ensure the prototype chain is searched. |
- __ b(eq, &slow); |
- |
- __ Ret(); |
} |