Chromium Code Reviews| Index: src/ic-arm.cc |
| =================================================================== |
| --- src/ic-arm.cc (revision 787) |
| +++ src/ic-arm.cc (working copy) |
| @@ -142,62 +142,17 @@ |
| } |
| -// Generate code to check if an object is a string. If the object is |
| -// a string, the map's instance type is left in the scratch1 register. |
| -static void GenerateStringCheck(MacroAssembler* masm, |
| - Register receiver, |
| - Register scratch1, |
| - Register scratch2, |
| - Label* smi, |
| - Label* non_string_object) { |
| - // Check that the receiver isn't a smi. |
| - __ tst(receiver, Operand(kSmiTagMask)); |
| - __ b(eq, smi); |
| - |
| - // Check that the object is a string. |
| - __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset)); |
| - __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset)); |
| - __ and_(scratch2, scratch1, Operand(kIsNotStringMask)); |
| - // The cast is to resolve the overload for the argument of 0x0. |
| - __ cmp(scratch2, Operand(static_cast<int32_t>(kStringTag))); |
| - __ b(ne, non_string_object); |
| -} |
| - |
| - |
| void LoadIC::GenerateStringLength(MacroAssembler* masm) { |
| // ----------- S t a t e ------------- |
| // -- r2 : name |
| // -- lr : return address |
| // -- [sp] : receiver |
| // ----------------------------------- |
| - Label miss, load_length, check_wrapper; |
| + Label miss; |
| __ ldr(r0, MemOperand(sp, 0)); |
| - // Check if the object is a string leaving the instance type in the |
| - // r1 register. |
| - GenerateStringCheck(masm, r0, r1, r3, &miss, &check_wrapper); |
| - |
| - // Load length directly from the string. |
| - __ bind(&load_length); |
| - __ and_(r1, r1, Operand(kStringSizeMask)); |
| - __ add(r1, r1, Operand(String::kHashShift)); |
| - __ ldr(r0, FieldMemOperand(r0, String::kLengthOffset)); |
| - __ mov(r0, Operand(r0, LSR, r1)); |
| - __ mov(r0, Operand(r0, LSL, kSmiTagSize)); |
| - __ Ret(); |
| - |
| - // Check if the object is a JSValue wrapper. |
| - __ bind(&check_wrapper); |
| - __ cmp(r1, Operand(JS_VALUE_TYPE)); |
| - __ b(ne, &miss); |
| - |
| - // Check if the wrapped value is a string and load the length |
| - // directly if it is. |
| - __ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset)); |
| - GenerateStringCheck(masm, r0, r1, r3, &miss, &miss); |
| - __ b(&load_length); |
| - |
| + StubCompiler::GenerateLoadStringLength2(masm, r0, r1, r3, &miss); |
| // Cache miss: Jump to runtime. |
| __ bind(&miss); |
| StubCompiler::GenerateLoadMiss(masm, Code::LOAD_IC); |
| @@ -500,7 +455,6 @@ |
| } |
| -// TODO(1224671): ICs for keyed load/store is not completed on ARM. |
| Object* KeyedLoadIC_Miss(Arguments args); |
| @@ -514,21 +468,69 @@ |
| // -- lr : return address |
| // -- sp[0] : key |
| // -- sp[4] : receiver |
| - __ ldm(ia, sp, r2.bit() | r3.bit()); |
| - __ stm(db_w, sp, r2.bit() | r3.bit()); |
| + __ ldm(ia, sp, r1.bit() | r3.bit()); |
| + __ stm(db_w, sp, r1.bit() | r3.bit()); |
|
iposva
2008/11/20 05:17:30
Why are you using r1 and r3 here and not r0 and r1
Feng Qian
2008/11/20 16:50:38
All r0 - r3 are available. I cannot remember why I
|
| __ TailCallRuntime(f, 2); |
| } |
| -// TODO(1224671): implement the fast case. |
| void KeyedLoadIC::GenerateGeneric(MacroAssembler* masm) { |
| // ---------- S t a t e -------------- |
| // -- lr : return address |
| // -- sp[0] : key |
| // -- sp[4] : receiver |
| + Label slow, fast; |
| - KeyedLoadIC::Generate(masm, ExternalReference(Runtime::kKeyedGetProperty)); |
| + // Get the key and receiver object from the stack. |
| + __ ldm(ia, sp, r0.bit() | r1.bit()); |
| + // Check that the key is a smi. |
| + __ tst(r0, Operand(kSmiTagMask)); |
| + __ b(ne, &slow); |
| + __ mov(r0, Operand(r0, ASR, kSmiTagSize)); |
| + // Check that the object isn't a smi. |
| + __ tst(r1, Operand(kSmiTagMask)); |
| + __ b(eq, &slow); |
| + |
| + // Check that the object is some kind of JS object EXCEPT JS Value type. |
| + // In the case that the object is a value-wrapper object, |
| + // we enter the runtime system to make sure that indexing into string |
| + // objects work as intended. |
| + ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE); |
| + __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| + __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); |
| + __ cmp(r2, Operand(JS_OBJECT_TYPE)); |
| + __ b(lt, &slow); |
| + |
| + // Get the elements array of the object. |
| + __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset)); |
| + // Check that the object is in fast mode (not dictionary). |
| + __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset)); |
| + __ cmp(r3, Operand(Factory::hash_table_map())); |
| + __ b(eq, &slow); |
| + // Check that the key (index) is within bounds. |
| + __ ldr(r3, FieldMemOperand(r1, Array::kLengthOffset)); |
| + __ cmp(r0, Operand(r3)); |
| + __ b(lo, &fast); |
| + |
| + // Slow case: Push extra copies of the arguments (2). |
| + __ bind(&slow); |
| + __ IncrementCounter(&Counters::keyed_load_generic_slow, 1, r0, r1); |
| + __ ldm(ia, sp, r0.bit() | r1.bit()); |
| + __ stm(db_w, sp, r0.bit() | r1.bit()); |
| + // Do tail-call to runtime routine. |
| + __ TailCallRuntime(ExternalReference(Runtime::kGetProperty), 2); |
| + |
| + // Fast case: Do the load. |
| + __ bind(&fast); |
| + __ add(r3, r1, Operand(Array::kHeaderSize - kHeapObjectTag)); |
| + __ ldr(r0, MemOperand(r3, r0, LSL, kPointerSizeLog2)); |
| + __ cmp(r0, Operand(Factory::the_hole_value())); |
| + // In case the loaded value is the_hole we have to consult GetProperty |
| + // to ensure the prototype chain is searched. |
| + __ b(eq, &slow); |
| + |
| + __ Ret(); |
| } |
| @@ -540,22 +542,120 @@ |
| // -- sp[0] : key |
| // -- sp[1] : receiver |
| - __ ldm(ia, sp, r2.bit() | r3.bit()); |
| - __ stm(db_w, sp, r0.bit() | r2.bit() | r3.bit()); |
| + __ ldm(ia, sp, r1.bit() | r3.bit()); |
| + __ stm(db_w, sp, r0.bit() | r1.bit() | r3.bit()); |
| __ TailCallRuntime(f, 3); |
| } |
| -// TODO(1224671): implement the fast case. |
| void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) { |
| // ---------- S t a t e -------------- |
| // -- r0 : value |
| // -- lr : return address |
| // -- sp[0] : key |
| // -- sp[1] : receiver |
| + Label slow, fast, array, extra, exit; |
| + // Get the key and the object from the stack. |
| + __ ldm(ia, sp, r1.bit() | r3.bit()); // r1 = key, r3 = receiver |
| + // Check that the key is a smi. |
| + __ tst(r1, Operand(kSmiTagMask)); |
| + __ b(ne, &slow); |
| + // Check that the object isn't a smi. |
| + __ tst(r3, Operand(kSmiTagMask)); |
| + __ b(eq, &slow); |
| + // Get the type of the object from its map. |
| + __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset)); |
| + __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset)); |
| + // Check if the object is a JS array or not. |
| + __ cmp(r2, Operand(JS_ARRAY_TYPE)); |
| + __ b(eq, &array); |
| + // Check that the object is some kind of JS object. |
| + __ cmp(r2, Operand(FIRST_JS_OBJECT_TYPE)); |
| + __ b(lt, &slow); |
| - KeyedStoreIC::Generate(masm, ExternalReference(Runtime::kSetProperty)); |
| + |
| + // Object case: Check key against length in the elements array. |
| + __ ldr(r3, FieldMemOperand(r3, JSObject::kElementsOffset)); |
| + // Check that the object is in fast mode (not dictionary). |
| + __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset)); |
| + __ cmp(r2, Operand(Factory::hash_table_map())); |
| + __ b(eq, &slow); |
| + // Untag the key (for checking against untagged length in the fixed array). |
| + __ mov(r1, Operand(r1, ASR, kSmiTagSize)); |
| + // Compute address to store into and check array bounds. |
| + __ add(r2, r3, Operand(Array::kHeaderSize - kHeapObjectTag)); |
| + __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2)); |
| + __ ldr(ip, FieldMemOperand(r3, Array::kLengthOffset)); |
| + __ cmp(r1, Operand(ip)); |
| + __ b(lo, &fast); |
| + |
| + |
| + // Slow case: Push extra copies of the arguments (3). |
| + __ bind(&slow); |
| + __ ldm(ia, sp, r1.bit() | r3.bit()); // r0 == value, r1 == key, r3 == object |
| + __ stm(db_w, sp, r0.bit() | r1.bit() | r3.bit()); |
| + // Do tail-call to runtime routine. |
| + __ TailCallRuntime(ExternalReference(Runtime::kSetProperty), 3); |
| + |
| + // Extra capacity case: Check if there is extra capacity to |
| + // perform the store and update the length. Used for adding one |
| + // element to the array by writing to array[array.length]. |
| + // r0 == value, r1 == key, r2 == elements, r3 == object |
| + __ bind(&extra); |
| + __ b(ne, &slow); // do not leave holes in the array |
| + __ mov(r1, Operand(r1, ASR, kSmiTagSize)); // untag |
| + __ ldr(ip, FieldMemOperand(r2, Array::kLengthOffset)); |
| + __ cmp(r1, Operand(ip)); |
| + __ b(hs, &slow); |
| + __ mov(r1, Operand(r1, LSL, kSmiTagSize)); // restore tag |
| + __ add(r1, r1, Operand(1 << kSmiTagSize)); // and increment |
| + __ str(r1, FieldMemOperand(r3, JSArray::kLengthOffset)); |
| + __ mov(r3, Operand(r2)); |
| + // NOTE: Computing the address to store into must take the fact |
| + // that the key has been incremented into account. |
| + int displacement = Array::kHeaderSize - kHeapObjectTag - |
| + ((1 << kSmiTagSize) * 2); |
| + __ add(r2, r2, Operand(displacement)); |
| + __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize)); |
| + __ b(&fast); |
| + |
| + |
| + // Array case: Get the length and the elements array from the JS |
| + // array. Check that the array is in fast mode; if it is the |
| + // length is always a smi. |
| + // r0 == value, r3 == object |
| + __ bind(&array); |
| + __ ldr(r2, FieldMemOperand(r3, JSObject::kElementsOffset)); |
| + __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset)); |
| + __ cmp(r1, Operand(Factory::hash_table_map())); |
| + __ b(eq, &slow); |
| + |
| + // Check the key against the length in the array, compute the |
| + // address to store into and fall through to fast case. |
| + __ ldr(r1, MemOperand(sp)); |
|
iposva
2008/11/20 05:17:30
Can you use a different register as temporary regi
Feng Qian
2008/11/20 16:50:38
Done.
|
| + // r0 == value, r1 == key, r2 == elements, r3 == object. |
| + __ ldr(ip, FieldMemOperand(r3, JSArray::kLengthOffset)); |
| + __ cmp(r1, Operand(ip)); |
| + __ b(hs, &extra); |
| + __ mov(r3, Operand(r2)); |
| + __ add(r2, r2, Operand(Array::kHeaderSize - kHeapObjectTag)); |
| + __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize)); |
| + |
| + |
| + // Fast case: Do the store. |
| + // r0 == value, r2 == address to store into, r3 == elements |
| + __ bind(&fast); |
| + __ str(r0, MemOperand(r2)); |
| + // Skip write barrier if the written value is a smi. |
| + __ tst(r0, Operand(kSmiTagMask)); |
| + __ b(eq, &exit); |
| + // Update write barrier for the elements array address. |
| + __ sub(r1, r2, Operand(r3)); |
| + __ RecordWrite(r3, r1, r2); |
| + |
| + __ bind(&exit); |
| + __ Ret(); |
| } |
| @@ -567,8 +667,8 @@ |
| // -- sp[1] : receiver |
| // ----------- S t a t e ------------- |
| - __ ldm(ia, sp, r2.bit() | r3.bit()); |
| - __ stm(db_w, sp, r0.bit() | r2.bit() | r3.bit()); |
| + __ ldm(ia, sp, r1.bit() | r3.bit()); |
| + __ stm(db_w, sp, r0.bit() | r1.bit() | r3.bit()); |
| // Perform tail call to the entry. |
| __ TailCallRuntime( |