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) {
|
||||
Comment cmnt(masm_, "[ GenerateSwapElements");
|
||||
|
||||
@ -4516,8 +4538,76 @@ void CodeGenerator::GenerateSwapElements(ZoneList<Expression*>* args) {
|
||||
Load(args->at(1));
|
||||
Load(args->at(2));
|
||||
|
||||
frame_->CallRuntime(Runtime::kSwapElements, 3);
|
||||
frame_->EmitPush(r0);
|
||||
Register index2 = r2;
|
||||
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 exit r0 is 0, positive or negative to indicate the result of
|
||||
// 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
|
||||
|
||||
#endif // V8_ARM_CODEGEN_ARM_H_
|
||||
|
@ -232,30 +232,23 @@ void MacroAssembler::LoadRoot(Register destination,
|
||||
}
|
||||
|
||||
|
||||
// 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,
|
||||
void MacroAssembler::RecordWriteHelper(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));
|
||||
if (FLAG_debug_code) {
|
||||
// Check that the object is not in new space.
|
||||
Label not_in_new_space;
|
||||
InNewSpace(object, scratch, ne, ¬_in_new_space);
|
||||
Abort("new-space object passed to RecordWriteHelper");
|
||||
bind(¬_in_new_space);
|
||||
}
|
||||
|
||||
// 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,
|
||||
// shift right 5) and then multiply by kIntSize (4, shift left 2).
|
||||
const int kRSetWordShift = 3;
|
||||
|
||||
Label fast, done;
|
||||
|
||||
// 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);
|
||||
Label fast;
|
||||
|
||||
// Compute the bit offset in the remembered set.
|
||||
// object: heap object pointer (with tag)
|
||||
@ -307,6 +300,38 @@ void MacroAssembler::RecordWrite(Register object, Register offset,
|
||||
mov(ip, Operand(1));
|
||||
orr(scratch, scratch, Operand(ip, LSL, offset));
|
||||
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);
|
||||
|
||||
|
@ -86,6 +86,20 @@ class MacroAssembler: public Assembler {
|
||||
Heap::RootListIndex index,
|
||||
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
|
||||
// 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
|
||||
|
@ -1082,8 +1082,8 @@ class RecordWriteStub : public CodeStub {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Minor key encoding in 12 bits of three registers (object, address and
|
||||
// scratch) OOOOAAAASSSS.
|
||||
// Minor key encoding in 12 bits. 4 bits for each of the three
|
||||
// registers (object, address and scratch) OOOOAAAASSSS.
|
||||
class ScratchBits: public BitField<uint32_t, 0, 4> {};
|
||||
class AddressBits: public BitField<uint32_t, 4, 4> {};
|
||||
class ObjectBits: public BitField<uint32_t, 8, 4> {};
|
||||
|
@ -50,6 +50,14 @@ MacroAssembler::MacroAssembler(void* buffer, int size)
|
||||
void MacroAssembler::RecordWriteHelper(Register object,
|
||||
Register addr,
|
||||
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;
|
||||
|
||||
// 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
|
||||
// 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;
|
||||
|
||||
// Skip barrier if writing a smi.
|
||||
|
@ -48,7 +48,9 @@ class MacroAssembler: public Assembler {
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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,
|
||||
Register addr,
|
||||
Register scratch);
|
||||
|
@ -1033,8 +1033,8 @@ class RecordWriteStub : public CodeStub {
|
||||
}
|
||||
#endif
|
||||
|
||||
// Minor key encoding in 12 bits of three registers (object, address and
|
||||
// scratch) OOOOAAAASSSS.
|
||||
// Minor key encoding in 12 bits. 4 bits for each of the three
|
||||
// registers (object, address and scratch) OOOOAAAASSSS.
|
||||
class ScratchBits : public BitField<uint32_t, 0, 4> {};
|
||||
class AddressBits : public BitField<uint32_t, 4, 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,
|
||||
Register addr,
|
||||
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;
|
||||
|
||||
// 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
|
||||
// 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;
|
||||
JumpIfSmi(value, &done);
|
||||
|
||||
|
@ -66,6 +66,9 @@ class MacroAssembler: public Assembler {
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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,
|
||||
Register addr,
|
||||
Register scratch);
|
||||
|
Loading…
Reference in New Issue
Block a user