| Index: src/ic/arm/ic-arm.cc
|
| diff --git a/src/ic/arm/ic-arm.cc b/src/ic/arm/ic-arm.cc
|
| index 70a5d84e93384e47729d71ea8c68286e49f47f9e..4ca8aa72e7a571a2b1c85372e5064845a7882adf 100644
|
| --- a/src/ic/arm/ic-arm.cc
|
| +++ b/src/ic/arm/ic-arm.cc
|
| @@ -158,12 +158,10 @@ static void GenerateKeyedLoadReceiverCheck(MacroAssembler* masm,
|
|
|
|
|
| // Loads an indexed element from a fast case array.
|
| -// If not_fast_array is NULL, doesn't perform the elements map check.
|
| static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver,
|
| Register key, Register elements,
|
| Register scratch1, Register scratch2,
|
| - Register result, Label* not_fast_array,
|
| - Label* out_of_range) {
|
| + Register result, Label* slow) {
|
| // Register use:
|
| //
|
| // receiver - holds the receiver on entry.
|
| @@ -172,8 +170,6 @@ static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver,
|
| // key - holds the smi key on entry.
|
| // Unchanged unless 'result' is the same register.
|
| //
|
| - // elements - holds the elements of the receiver on exit.
|
| - //
|
| // result - holds the result on exit if the load succeeded.
|
| // Allowed to be the the same as 'receiver' or 'key'.
|
| // Unchanged on bailout so 'receiver' and 'key' can be safely
|
| @@ -181,34 +177,59 @@ static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver,
|
| //
|
| // Scratch registers:
|
| //
|
| - // scratch1 - used to hold elements map and elements length.
|
| - // Holds the elements map if not_fast_array branch is taken.
|
| + // elements - holds the elements of the receiver and its prototypes.
|
| + //
|
| + // scratch1 - used to hold elements length, bit fields, base addresses.
|
| //
|
| - // scratch2 - used to hold the loaded value.
|
| + // scratch2 - used to hold maps, prototypes, and the loaded value.
|
| + Label check_prototypes, check_next_prototype;
|
| + Label done, in_bounds, return_undefined;
|
|
|
| __ ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
|
| - if (not_fast_array != NULL) {
|
| - // Check that the object is in fast mode and writable.
|
| - __ ldr(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
|
| - __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
|
| - __ cmp(scratch1, ip);
|
| - __ b(ne, not_fast_array);
|
| - } else {
|
| - __ AssertFastElements(elements);
|
| - }
|
| + __ AssertFastElements(elements);
|
| +
|
| // Check that the key (index) is within bounds.
|
| __ ldr(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset));
|
| __ cmp(key, Operand(scratch1));
|
| - __ b(hs, out_of_range);
|
| + __ b(lo, &in_bounds);
|
| + // Out-of-bounds. Check the prototype chain to see if we can just return
|
| + // 'undefined'.
|
| + __ cmp(key, Operand(0));
|
| + __ b(lt, slow); // Negative keys can't take the fast OOB path.
|
| + __ bind(&check_prototypes);
|
| + __ ldr(scratch2, FieldMemOperand(receiver, HeapObject::kMapOffset));
|
| + __ bind(&check_next_prototype);
|
| + __ ldr(scratch2, FieldMemOperand(scratch2, Map::kPrototypeOffset));
|
| + // scratch2: current prototype
|
| + __ CompareRoot(scratch2, Heap::kNullValueRootIndex);
|
| + __ b(eq, &return_undefined);
|
| + __ ldr(elements, FieldMemOperand(scratch2, JSObject::kElementsOffset));
|
| + __ ldr(scratch2, FieldMemOperand(scratch2, HeapObject::kMapOffset));
|
| + // elements: elements of current prototype
|
| + // scratch2: map of current prototype
|
| + __ CompareInstanceType(scratch2, scratch1, JS_OBJECT_TYPE);
|
| + __ b(lo, slow);
|
| + __ ldrb(scratch1, FieldMemOperand(scratch2, Map::kBitFieldOffset));
|
| + __ tst(scratch1, Operand((1 << Map::kIsAccessCheckNeeded) |
|
| + (1 << Map::kHasIndexedInterceptor)));
|
| + __ b(ne, slow);
|
| + __ CompareRoot(elements, Heap::kEmptyFixedArrayRootIndex);
|
| + __ b(ne, slow);
|
| + __ jmp(&check_next_prototype);
|
| +
|
| + __ bind(&return_undefined);
|
| + __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
|
| + __ jmp(&done);
|
| +
|
| + __ bind(&in_bounds);
|
| // Fast case: Do the load.
|
| __ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
|
| __ ldr(scratch2, MemOperand::PointerAddressFromSmiKey(scratch1, key));
|
| - __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
|
| - __ cmp(scratch2, ip);
|
| - // In case the loaded value is the_hole we have to consult GetProperty
|
| - // to ensure the prototype chain is searched.
|
| - __ b(eq, out_of_range);
|
| + __ CompareRoot(scratch2, Heap::kTheHoleValueRootIndex);
|
| + // In case the loaded value is the_hole we have to check the prototype chain.
|
| + __ b(eq, &check_prototypes);
|
| __ mov(result, scratch2);
|
| + __ bind(&done);
|
| }
|
|
|
|
|
| @@ -468,7 +489,7 @@ void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) {
|
| // Check the receiver's map to see if it has fast elements.
|
| __ CheckFastElements(r0, r3, &check_number_dictionary);
|
|
|
| - GenerateFastArrayLoad(masm, receiver, key, r0, r3, r4, r0, NULL, &slow);
|
| + GenerateFastArrayLoad(masm, receiver, key, r0, r3, r4, r0, &slow);
|
| __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1, r4, r3);
|
| __ Ret();
|
|
|
|
|