| Index: src/ic/arm64/ic-arm64.cc
|
| diff --git a/src/ic/arm64/ic-arm64.cc b/src/ic/arm64/ic-arm64.cc
|
| index a01015c1864c559523435b06d213760625e6ad3c..2c1642bba77731bc7b38b9210beb619a83274acc 100644
|
| --- a/src/ic/arm64/ic-arm64.cc
|
| +++ b/src/ic/arm64/ic-arm64.cc
|
| @@ -151,63 +151,77 @@ 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.
|
| //
|
| -// receiver - holds the receiver on entry.
|
| -// Unchanged unless 'result' is the same register.
|
| +// receiver - holds the receiver on entry.
|
| +// Unchanged unless 'result' is the same register.
|
| //
|
| -// key - holds the smi key on entry.
|
| -// Unchanged unless 'result' is the same register.
|
| +// key - holds the smi key on entry.
|
| +// Unchanged unless 'result' is the same register.
|
| //
|
| -// elements - holds the elements of the receiver on exit.
|
| +// elements - holds the elements of the receiver and its prototypes. Clobbered.
|
| //
|
| -// elements_map - holds the elements map on exit if the not_fast_array branch is
|
| -// taken. Otherwise, this is used as a scratch register.
|
| -//
|
| -// 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
|
| -// used by further computation.
|
| +// 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
|
| +// used by further computation.
|
| static void GenerateFastArrayLoad(MacroAssembler* masm, Register receiver,
|
| Register key, Register elements,
|
| - Register elements_map, Register scratch2,
|
| - Register result, Label* not_fast_array,
|
| - Label* slow) {
|
| - DCHECK(!AreAliased(receiver, key, elements, elements_map, scratch2));
|
| + Register scratch1, Register scratch2,
|
| + Register result, Label* slow) {
|
| + DCHECK(!AreAliased(receiver, key, elements, scratch1, scratch2));
|
| +
|
| + Label check_prototypes, check_next_prototype;
|
| + Label done, in_bounds, return_undefined;
|
|
|
| // Check for fast array.
|
| __ Ldr(elements, FieldMemOperand(receiver, JSObject::kElementsOffset));
|
| - if (not_fast_array != NULL) {
|
| - // Check that the object is in fast mode and writable.
|
| - __ Ldr(elements_map, FieldMemOperand(elements, HeapObject::kMapOffset));
|
| - __ JumpIfNotRoot(elements_map, Heap::kFixedArrayMapRootIndex,
|
| - not_fast_array);
|
| - } else {
|
| - __ AssertFastElements(elements);
|
| - }
|
| -
|
| - // The elements_map register is only used for the not_fast_array path, which
|
| - // was handled above. From this point onward it is a scratch register.
|
| - Register scratch1 = elements_map;
|
| + __ AssertFastElements(elements);
|
|
|
| // Check that the key (index) is within bounds.
|
| __ Ldr(scratch1, FieldMemOperand(elements, FixedArray::kLengthOffset));
|
| __ Cmp(key, scratch1);
|
| - __ B(hs, slow);
|
| -
|
| + __ B(lo, &in_bounds);
|
| +
|
| + // Out of bounds. Check the prototype chain to see if we can just return
|
| + // 'undefined'.
|
| + __ Cmp(key, Operand(Smi::FromInt(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
|
| + __ JumpIfRoot(scratch2, Heap::kNullValueRootIndex, &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));
|
| + __ Tbnz(scratch1, Map::kIsAccessCheckNeeded, slow);
|
| + __ Tbnz(scratch1, Map::kHasIndexedInterceptor, slow);
|
| + __ JumpIfNotRoot(elements, Heap::kEmptyFixedArrayRootIndex, slow);
|
| + __ B(&check_next_prototype);
|
| +
|
| + __ Bind(&return_undefined);
|
| + __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
|
| + __ B(&done);
|
| +
|
| + __ Bind(&in_bounds);
|
| // Fast case: Do the load.
|
| __ Add(scratch1, elements, FixedArray::kHeaderSize - kHeapObjectTag);
|
| __ SmiUntag(scratch2, key);
|
| __ Ldr(scratch2, MemOperand(scratch1, scratch2, LSL, kPointerSizeLog2));
|
|
|
| - // In case the loaded value is the_hole we have to consult GetProperty
|
| - // to ensure the prototype chain is searched.
|
| - __ JumpIfRoot(scratch2, Heap::kTheHoleValueRootIndex, slow);
|
| + // In case the loaded value is the_hole we have to check the prototype chain.
|
| + __ JumpIfRoot(scratch2, Heap::kTheHoleValueRootIndex, &check_prototypes);
|
|
|
| // Move the value to the result register.
|
| // 'result' can alias with 'receiver' or 'key' but these two must be
|
| // preserved if we jump to 'slow'.
|
| __ Mov(result, scratch2);
|
| + __ Bind(&done);
|
| }
|
|
|
|
|
| @@ -480,7 +494,7 @@ static void GenerateKeyedLoadWithSmiKey(MacroAssembler* masm, Register key,
|
| __ CheckFastElements(scratch1, scratch2, &check_number_dictionary);
|
|
|
| GenerateFastArrayLoad(masm, receiver, key, scratch3, scratch2, scratch1,
|
| - result, NULL, slow);
|
| + result, slow);
|
| __ IncrementCounter(isolate->counters()->keyed_load_generic_smi(), 1,
|
| scratch1, scratch2);
|
| __ Ret();
|
|
|