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:
ager@chromium.org 2010-05-04 11:06:59 +00:00
parent 528ab2bc7d
commit 6230f5397d
10 changed files with 220 additions and 27 deletions

View File

@ -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.

View File

@ -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_

View File

@ -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, &not_in_new_space);
// registers are cp. Abort("new-space object passed to RecordWriteHelper");
ASSERT(!object.is(cp) && !offset.is(cp) && !scratch.is(cp)); bind(&not_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);

View File

@ -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

View File

@ -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> {};

View File

@ -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, &not_in_new_space);
Abort("new-space object passed to RecordWriteHelper");
bind(&not_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.

View File

@ -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);

View File

@ -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> {};

View File

@ -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, &not_in_new_space);
Abort("new-space object passed to RecordWriteHelper");
bind(&not_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);

View File

@ -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);