Port inline swapping of elements for the sort function in array.js
from ia32 to arm. Original change: http://codereview.chromium.org/1709008 Review URL: http://codereview.chromium.org/1944001 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4575 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
528ab2bc7d
commit
6230f5397d
@ -4507,6 +4507,28 @@ void CodeGenerator::GenerateNumberToString(ZoneList<Expression*>* args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class DeferredSwapElements: public DeferredCode {
|
||||||
|
public:
|
||||||
|
DeferredSwapElements(Register object, Register index1, Register index2)
|
||||||
|
: object_(object), index1_(index1), index2_(index2) {
|
||||||
|
set_comment("[ DeferredSwapElements");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Generate();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Register object_, index1_, index2_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void DeferredSwapElements::Generate() {
|
||||||
|
__ push(object_);
|
||||||
|
__ push(index1_);
|
||||||
|
__ push(index2_);
|
||||||
|
__ CallRuntime(Runtime::kSwapElements, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void CodeGenerator::GenerateSwapElements(ZoneList<Expression*>* args) {
|
void CodeGenerator::GenerateSwapElements(ZoneList<Expression*>* args) {
|
||||||
Comment cmnt(masm_, "[ GenerateSwapElements");
|
Comment cmnt(masm_, "[ GenerateSwapElements");
|
||||||
|
|
||||||
@ -4516,8 +4538,76 @@ void CodeGenerator::GenerateSwapElements(ZoneList<Expression*>* args) {
|
|||||||
Load(args->at(1));
|
Load(args->at(1));
|
||||||
Load(args->at(2));
|
Load(args->at(2));
|
||||||
|
|
||||||
frame_->CallRuntime(Runtime::kSwapElements, 3);
|
Register index2 = r2;
|
||||||
frame_->EmitPush(r0);
|
Register index1 = r1;
|
||||||
|
Register object = r0;
|
||||||
|
Register tmp1 = r3;
|
||||||
|
Register tmp2 = r4;
|
||||||
|
|
||||||
|
frame_->EmitPop(index2);
|
||||||
|
frame_->EmitPop(index1);
|
||||||
|
frame_->EmitPop(object);
|
||||||
|
|
||||||
|
DeferredSwapElements* deferred =
|
||||||
|
new DeferredSwapElements(object, index1, index2);
|
||||||
|
|
||||||
|
// Fetch the map and check if array is in fast case.
|
||||||
|
// Check that object doesn't require security checks and
|
||||||
|
// has no indexed interceptor.
|
||||||
|
__ CompareObjectType(object, tmp1, tmp2, FIRST_JS_OBJECT_TYPE);
|
||||||
|
deferred->Branch(lt);
|
||||||
|
__ ldrb(tmp2, FieldMemOperand(tmp1, Map::kBitFieldOffset));
|
||||||
|
__ tst(tmp2, Operand(KeyedLoadIC::kSlowCaseBitFieldMask));
|
||||||
|
deferred->Branch(nz);
|
||||||
|
|
||||||
|
// Check the object's elements are in fast case.
|
||||||
|
__ ldr(tmp1, FieldMemOperand(object, JSObject::kElementsOffset));
|
||||||
|
__ ldr(tmp2, FieldMemOperand(tmp1, HeapObject::kMapOffset));
|
||||||
|
__ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
|
||||||
|
__ cmp(tmp2, ip);
|
||||||
|
deferred->Branch(ne);
|
||||||
|
|
||||||
|
// Smi-tagging is equivalent to multiplying by 2.
|
||||||
|
STATIC_ASSERT(kSmiTag == 0);
|
||||||
|
STATIC_ASSERT(kSmiTagSize == 1);
|
||||||
|
|
||||||
|
// Check that both indices are smis.
|
||||||
|
__ mov(tmp2, index1);
|
||||||
|
__ orr(tmp2, tmp2, index2);
|
||||||
|
__ tst(tmp2, Operand(kSmiTagMask));
|
||||||
|
deferred->Branch(nz);
|
||||||
|
|
||||||
|
// Bring the offsets into the fixed array in tmp1 into index1 and
|
||||||
|
// index2.
|
||||||
|
__ mov(tmp2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
|
||||||
|
__ add(index1, tmp2, Operand(index1, LSL, kPointerSizeLog2 - kSmiTagSize));
|
||||||
|
__ add(index2, tmp2, Operand(index2, LSL, kPointerSizeLog2 - kSmiTagSize));
|
||||||
|
|
||||||
|
// Swap elements.
|
||||||
|
Register tmp3 = object;
|
||||||
|
object = no_reg;
|
||||||
|
__ ldr(tmp3, MemOperand(tmp1, index1));
|
||||||
|
__ ldr(tmp2, MemOperand(tmp1, index2));
|
||||||
|
__ str(tmp3, MemOperand(tmp1, index2));
|
||||||
|
__ str(tmp2, MemOperand(tmp1, index1));
|
||||||
|
|
||||||
|
Label done;
|
||||||
|
__ InNewSpace(tmp1, tmp2, eq, &done);
|
||||||
|
// Possible optimization: do a check that both values are Smis
|
||||||
|
// (or them and test against Smi mask.)
|
||||||
|
|
||||||
|
__ mov(tmp2, tmp1);
|
||||||
|
RecordWriteStub recordWrite1(tmp1, index1, tmp3);
|
||||||
|
__ CallStub(&recordWrite1);
|
||||||
|
|
||||||
|
RecordWriteStub recordWrite2(tmp2, index2, tmp3);
|
||||||
|
__ CallStub(&recordWrite2);
|
||||||
|
|
||||||
|
__ bind(&done);
|
||||||
|
|
||||||
|
deferred->BindExit();
|
||||||
|
__ LoadRoot(tmp1, Heap::kUndefinedValueRootIndex);
|
||||||
|
frame_->EmitPush(tmp1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -6503,6 +6593,12 @@ void NumberToStringStub::Generate(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RecordWriteStub::Generate(MacroAssembler* masm) {
|
||||||
|
__ RecordWriteHelper(object_, offset_, scratch_);
|
||||||
|
__ Ret();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// On entry r0 (rhs) and r1 (lhs) are the values to be compared.
|
// On entry r0 (rhs) and r1 (lhs) are the values to be compared.
|
||||||
// On exit r0 is 0, positive or negative to indicate the result of
|
// On exit r0 is 0, positive or negative to indicate the result of
|
||||||
// the comparison.
|
// the comparison.
|
||||||
|
@ -904,6 +904,43 @@ class NumberToStringStub: public CodeStub {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class RecordWriteStub : public CodeStub {
|
||||||
|
public:
|
||||||
|
RecordWriteStub(Register object, Register offset, Register scratch)
|
||||||
|
: object_(object), offset_(offset), scratch_(scratch) { }
|
||||||
|
|
||||||
|
void Generate(MacroAssembler* masm);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Register object_;
|
||||||
|
Register offset_;
|
||||||
|
Register scratch_;
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
void Print() {
|
||||||
|
PrintF("RecordWriteStub (object reg %d), (offset reg %d),"
|
||||||
|
" (scratch reg %d)\n",
|
||||||
|
object_.code(), offset_.code(), scratch_.code());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Minor key encoding in 12 bits. 4 bits for each of the three
|
||||||
|
// registers (object, offset and scratch) OOOOAAAASSSS.
|
||||||
|
class ScratchBits: public BitField<uint32_t, 0, 4> {};
|
||||||
|
class OffsetBits: public BitField<uint32_t, 4, 4> {};
|
||||||
|
class ObjectBits: public BitField<uint32_t, 8, 4> {};
|
||||||
|
|
||||||
|
Major MajorKey() { return RecordWrite; }
|
||||||
|
|
||||||
|
int MinorKey() {
|
||||||
|
// Encode the registers.
|
||||||
|
return ObjectBits::encode(object_.code()) |
|
||||||
|
OffsetBits::encode(offset_.code()) |
|
||||||
|
ScratchBits::encode(scratch_.code());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
} } // namespace v8::internal
|
} } // namespace v8::internal
|
||||||
|
|
||||||
#endif // V8_ARM_CODEGEN_ARM_H_
|
#endif // V8_ARM_CODEGEN_ARM_H_
|
||||||
|
@ -232,30 +232,23 @@ void MacroAssembler::LoadRoot(Register destination,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Will clobber 4 registers: object, offset, scratch, ip. The
|
void MacroAssembler::RecordWriteHelper(Register object,
|
||||||
// register 'object' contains a heap object pointer. The heap object
|
Register offset,
|
||||||
// tag is shifted away.
|
Register scratch) {
|
||||||
void MacroAssembler::RecordWrite(Register object, Register offset,
|
if (FLAG_debug_code) {
|
||||||
Register scratch) {
|
// Check that the object is not in new space.
|
||||||
// The compiled code assumes that record write doesn't change the
|
Label not_in_new_space;
|
||||||
// context register, so we check that none of the clobbered
|
InNewSpace(object, scratch, ne, ¬_in_new_space);
|
||||||
// registers are cp.
|
Abort("new-space object passed to RecordWriteHelper");
|
||||||
ASSERT(!object.is(cp) && !offset.is(cp) && !scratch.is(cp));
|
bind(¬_in_new_space);
|
||||||
|
}
|
||||||
|
|
||||||
// This is how much we shift the remembered set bit offset to get the
|
// This is how much we shift the remembered set bit offset to get the
|
||||||
// offset of the word in the remembered set. We divide by kBitsPerInt (32,
|
// offset of the word in the remembered set. We divide by kBitsPerInt (32,
|
||||||
// shift right 5) and then multiply by kIntSize (4, shift left 2).
|
// shift right 5) and then multiply by kIntSize (4, shift left 2).
|
||||||
const int kRSetWordShift = 3;
|
const int kRSetWordShift = 3;
|
||||||
|
|
||||||
Label fast, done;
|
Label fast;
|
||||||
|
|
||||||
// First, test that the object is not in the new space. We cannot set
|
|
||||||
// remembered set bits in the new space.
|
|
||||||
// object: heap object pointer (with tag)
|
|
||||||
// offset: offset to store location from the object
|
|
||||||
and_(scratch, object, Operand(ExternalReference::new_space_mask()));
|
|
||||||
cmp(scratch, Operand(ExternalReference::new_space_start()));
|
|
||||||
b(eq, &done);
|
|
||||||
|
|
||||||
// Compute the bit offset in the remembered set.
|
// Compute the bit offset in the remembered set.
|
||||||
// object: heap object pointer (with tag)
|
// object: heap object pointer (with tag)
|
||||||
@ -307,6 +300,38 @@ void MacroAssembler::RecordWrite(Register object, Register offset,
|
|||||||
mov(ip, Operand(1));
|
mov(ip, Operand(1));
|
||||||
orr(scratch, scratch, Operand(ip, LSL, offset));
|
orr(scratch, scratch, Operand(ip, LSL, offset));
|
||||||
str(scratch, MemOperand(object));
|
str(scratch, MemOperand(object));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MacroAssembler::InNewSpace(Register object,
|
||||||
|
Register scratch,
|
||||||
|
Condition cc,
|
||||||
|
Label* branch) {
|
||||||
|
ASSERT(cc == eq || cc == ne);
|
||||||
|
and_(scratch, object, Operand(ExternalReference::new_space_mask()));
|
||||||
|
cmp(scratch, Operand(ExternalReference::new_space_start()));
|
||||||
|
b(cc, branch);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Will clobber 4 registers: object, offset, scratch, ip. The
|
||||||
|
// register 'object' contains a heap object pointer. The heap object
|
||||||
|
// tag is shifted away.
|
||||||
|
void MacroAssembler::RecordWrite(Register object, Register offset,
|
||||||
|
Register scratch) {
|
||||||
|
// The compiled code assumes that record write doesn't change the
|
||||||
|
// context register, so we check that none of the clobbered
|
||||||
|
// registers are cp.
|
||||||
|
ASSERT(!object.is(cp) && !offset.is(cp) && !scratch.is(cp));
|
||||||
|
|
||||||
|
Label done;
|
||||||
|
|
||||||
|
// First, test that the object is not in the new space. We cannot set
|
||||||
|
// remembered set bits in the new space.
|
||||||
|
InNewSpace(object, scratch, eq, &done);
|
||||||
|
|
||||||
|
// Record the actual write.
|
||||||
|
RecordWriteHelper(object, offset, scratch);
|
||||||
|
|
||||||
bind(&done);
|
bind(&done);
|
||||||
|
|
||||||
|
@ -86,6 +86,20 @@ class MacroAssembler: public Assembler {
|
|||||||
Heap::RootListIndex index,
|
Heap::RootListIndex index,
|
||||||
Condition cond = al);
|
Condition cond = al);
|
||||||
|
|
||||||
|
|
||||||
|
// Check if object is in new space.
|
||||||
|
// scratch can be object itself, but it will be clobbered.
|
||||||
|
void InNewSpace(Register object,
|
||||||
|
Register scratch,
|
||||||
|
Condition cc, // eq for new space, ne otherwise
|
||||||
|
Label* branch);
|
||||||
|
|
||||||
|
|
||||||
|
// Set the remebered set bit for an offset into an
|
||||||
|
// object. RecordWriteHelper only works if the object is not in new
|
||||||
|
// space.
|
||||||
|
void RecordWriteHelper(Register object, Register offset, Register scracth);
|
||||||
|
|
||||||
// Sets the remembered set bit for [address+offset], where address is the
|
// Sets the remembered set bit for [address+offset], where address is the
|
||||||
// address of the heap object 'object'. The address must be in the first 8K
|
// address of the heap object 'object'. The address must be in the first 8K
|
||||||
// of an allocated page. The 'scratch' register is used in the
|
// of an allocated page. The 'scratch' register is used in the
|
||||||
|
@ -1082,8 +1082,8 @@ class RecordWriteStub : public CodeStub {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Minor key encoding in 12 bits of three registers (object, address and
|
// Minor key encoding in 12 bits. 4 bits for each of the three
|
||||||
// scratch) OOOOAAAASSSS.
|
// registers (object, address and scratch) OOOOAAAASSSS.
|
||||||
class ScratchBits: public BitField<uint32_t, 0, 4> {};
|
class ScratchBits: public BitField<uint32_t, 0, 4> {};
|
||||||
class AddressBits: public BitField<uint32_t, 4, 4> {};
|
class AddressBits: public BitField<uint32_t, 4, 4> {};
|
||||||
class ObjectBits: public BitField<uint32_t, 8, 4> {};
|
class ObjectBits: public BitField<uint32_t, 8, 4> {};
|
||||||
|
@ -50,6 +50,14 @@ MacroAssembler::MacroAssembler(void* buffer, int size)
|
|||||||
void MacroAssembler::RecordWriteHelper(Register object,
|
void MacroAssembler::RecordWriteHelper(Register object,
|
||||||
Register addr,
|
Register addr,
|
||||||
Register scratch) {
|
Register scratch) {
|
||||||
|
if (FLAG_debug_code) {
|
||||||
|
// Check that the object is not in new space.
|
||||||
|
Label not_in_new_space;
|
||||||
|
InNewSpace(object, scratch, not_equal, ¬_in_new_space);
|
||||||
|
Abort("new-space object passed to RecordWriteHelper");
|
||||||
|
bind(¬_in_new_space);
|
||||||
|
}
|
||||||
|
|
||||||
Label fast;
|
Label fast;
|
||||||
|
|
||||||
// Compute the page start address from the heap object pointer, and reuse
|
// Compute the page start address from the heap object pointer, and reuse
|
||||||
@ -134,7 +142,7 @@ void MacroAssembler::RecordWrite(Register object, int offset,
|
|||||||
|
|
||||||
// First, check if a remembered set write is even needed. The tests below
|
// First, check if a remembered set write is even needed. The tests below
|
||||||
// catch stores of Smis and stores into young gen (which does not have space
|
// catch stores of Smis and stores into young gen (which does not have space
|
||||||
// for the remembered set bits.
|
// for the remembered set bits).
|
||||||
Label done;
|
Label done;
|
||||||
|
|
||||||
// Skip barrier if writing a smi.
|
// Skip barrier if writing a smi.
|
||||||
|
@ -48,7 +48,9 @@ class MacroAssembler: public Assembler {
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// GC Support
|
// GC Support
|
||||||
|
|
||||||
|
// Set the remebered set bit for an address which points into an
|
||||||
|
// object. RecordWriteHelper only works if the object is not in new
|
||||||
|
// space.
|
||||||
void RecordWriteHelper(Register object,
|
void RecordWriteHelper(Register object,
|
||||||
Register addr,
|
Register addr,
|
||||||
Register scratch);
|
Register scratch);
|
||||||
|
@ -1033,8 +1033,8 @@ class RecordWriteStub : public CodeStub {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Minor key encoding in 12 bits of three registers (object, address and
|
// Minor key encoding in 12 bits. 4 bits for each of the three
|
||||||
// scratch) OOOOAAAASSSS.
|
// registers (object, address and scratch) OOOOAAAASSSS.
|
||||||
class ScratchBits : public BitField<uint32_t, 0, 4> {};
|
class ScratchBits : public BitField<uint32_t, 0, 4> {};
|
||||||
class AddressBits : public BitField<uint32_t, 4, 4> {};
|
class AddressBits : public BitField<uint32_t, 4, 4> {};
|
||||||
class ObjectBits : public BitField<uint32_t, 8, 4> {};
|
class ObjectBits : public BitField<uint32_t, 8, 4> {};
|
||||||
|
@ -75,6 +75,14 @@ void MacroAssembler::StackLimitCheck(Label* on_stack_overflow) {
|
|||||||
void MacroAssembler::RecordWriteHelper(Register object,
|
void MacroAssembler::RecordWriteHelper(Register object,
|
||||||
Register addr,
|
Register addr,
|
||||||
Register scratch) {
|
Register scratch) {
|
||||||
|
if (FLAG_debug_code) {
|
||||||
|
// Check that the object is not in new space.
|
||||||
|
Label not_in_new_space;
|
||||||
|
InNewSpace(object, scratch, not_equal, ¬_in_new_space);
|
||||||
|
Abort("new-space object passed to RecordWriteHelper");
|
||||||
|
bind(¬_in_new_space);
|
||||||
|
}
|
||||||
|
|
||||||
Label fast;
|
Label fast;
|
||||||
|
|
||||||
// Compute the page start address from the heap object pointer, and reuse
|
// Compute the page start address from the heap object pointer, and reuse
|
||||||
@ -157,7 +165,7 @@ void MacroAssembler::RecordWrite(Register object,
|
|||||||
|
|
||||||
// First, check if a remembered set write is even needed. The tests below
|
// First, check if a remembered set write is even needed. The tests below
|
||||||
// catch stores of Smis and stores into young gen (which does not have space
|
// catch stores of Smis and stores into young gen (which does not have space
|
||||||
// for the remembered set bits.
|
// for the remembered set bits).
|
||||||
Label done;
|
Label done;
|
||||||
JumpIfSmi(value, &done);
|
JumpIfSmi(value, &done);
|
||||||
|
|
||||||
|
@ -66,6 +66,9 @@ class MacroAssembler: public Assembler {
|
|||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// GC Support
|
// GC Support
|
||||||
|
|
||||||
|
// Set the remebered set bit for an address which points into an
|
||||||
|
// object. RecordWriteHelper only works if the object is not in new
|
||||||
|
// space.
|
||||||
void RecordWriteHelper(Register object,
|
void RecordWriteHelper(Register object,
|
||||||
Register addr,
|
Register addr,
|
||||||
Register scratch);
|
Register scratch);
|
||||||
|
Loading…
Reference in New Issue
Block a user