Commit d1c60571 authored by erik.corry@gmail.com's avatar erik.corry@gmail.com

ARM: Minor refactoring of RecordWrite, does not require the offset to

be in a register anymore. Code also updated to use the bitfield
instructions when available.  This is a commit of
http://codereview.chromium.org/2845003/show for Rodolph Perfetta.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4889 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 6702ace9
......@@ -268,8 +268,7 @@ void CodeGenerator::Generate(CompilationInfo* info) {
// Load the offset into r3.
int slot_offset =
FixedArray::kHeaderSize + slot->index() * kPointerSize;
__ mov(r3, Operand(slot_offset));
__ RecordWrite(r2, r3, r1);
__ RecordWrite(r2, Operand(slot_offset), r3, r1);
}
}
}
......@@ -3109,9 +3108,8 @@ void CodeGenerator::StoreToSlot(Slot* slot, InitState init_state) {
exit.Branch(eq);
// scratch is loaded with context when calling SlotOperand above.
int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
__ mov(r3, Operand(offset));
// r1 could be identical with tos, but that doesn't matter.
__ RecordWrite(scratch, r3, r1);
__ RecordWrite(scratch, Operand(offset), r3, r1);
}
// If we definitely did not jump over the assignment, we do not need
// to bind the exit label. Doing so can defeat peephole
......@@ -3464,8 +3462,7 @@ void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
__ str(r0, FieldMemOperand(r1, offset));
// Update the write barrier for the array address.
__ mov(r3, Operand(offset));
__ RecordWrite(r1, r3, r2);
__ RecordWrite(r1, Operand(offset), r3, r2);
}
ASSERT_EQ(original_height + 1, frame_->height());
}
......@@ -4279,8 +4276,7 @@ void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) {
// Store the value.
__ str(r0, FieldMemOperand(r1, JSValue::kValueOffset));
// Update the write barrier.
__ mov(r2, Operand(JSValue::kValueOffset - kHeapObjectTag));
__ RecordWrite(r1, r2, r3);
__ RecordWrite(r1, Operand(JSValue::kValueOffset - kHeapObjectTag), r2, r3);
// Leave.
leave.Bind();
frame_->EmitPush(r0);
......@@ -7207,7 +7203,7 @@ void NumberToStringStub::Generate(MacroAssembler* masm) {
void RecordWriteStub::Generate(MacroAssembler* masm) {
__ RecordWriteHelper(object_, offset_, scratch_);
__ RecordWriteHelper(object_, Operand(offset_), offset_, scratch_);
__ Ret();
}
......@@ -9453,17 +9449,15 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
RegExpImpl::kLastCaptureCountOffset));
// Store last subject and last input.
__ mov(r3, last_match_info_elements); // Moved up to reduce latency.
__ mov(r2, Operand(RegExpImpl::kLastSubjectOffset)); // Ditto.
__ str(subject,
FieldMemOperand(last_match_info_elements,
RegExpImpl::kLastSubjectOffset));
__ RecordWrite(r3, r2, r7);
__ RecordWrite(r3, Operand(RegExpImpl::kLastSubjectOffset), r2, r7);
__ str(subject,
FieldMemOperand(last_match_info_elements,
RegExpImpl::kLastInputOffset));
__ mov(r3, last_match_info_elements);
__ mov(r2, Operand(RegExpImpl::kLastInputOffset));
__ RecordWrite(r3, r2, r7);
__ RecordWrite(r3, Operand(RegExpImpl::kLastInputOffset), r2, r7);
// Get the static offsets vector filled by the native regexp code.
ExternalReference address_of_static_offsets_vector =
......
......@@ -102,8 +102,7 @@ void FastCodeGenerator::EmitThisPropertyStore(Handle<String> name) {
}
if (needs_write_barrier) {
__ mov(scratch1(), Operand(offset));
__ RecordWrite(scratch0(), scratch1(), scratch2());
__ RecordWrite(scratch0(), Operand(offset), scratch1(), scratch2());
}
if (destination().is(accumulator1())) {
......
......@@ -110,10 +110,10 @@ void FullCodeGenerator::Generate(CompilationInfo* info, Mode mode) {
__ mov(r1, Operand(Context::SlotOffset(slot->index())));
__ str(r0, MemOperand(cp, r1));
// Update the write barrier. This clobbers all involved
// registers, so we have use a third register to avoid
// registers, so we have to use two more registers to avoid
// clobbering cp.
__ mov(r2, Operand(cp));
__ RecordWrite(r2, r1, r0);
__ RecordWrite(r2, Operand(r1), r3, r0);
}
}
}
......@@ -666,8 +666,10 @@ void FullCodeGenerator::Move(Slot* dst,
__ str(src, location);
// Emit the write barrier code if the location is in the heap.
if (dst->type() == Slot::CONTEXT) {
__ mov(scratch2, Operand(Context::SlotOffset(dst->index())));
__ RecordWrite(scratch1, scratch2, src);
__ RecordWrite(scratch1,
Operand(Context::SlotOffset(dst->index())),
scratch2,
src);
}
}
......@@ -715,10 +717,9 @@ void FullCodeGenerator::EmitDeclaration(Variable* variable,
__ str(result_register(),
CodeGenerator::ContextOperand(cp, slot->index()));
int offset = Context::SlotOffset(slot->index());
__ mov(r2, Operand(offset));
// We know that we have written a function, which is not a smi.
__ mov(r1, Operand(cp));
__ RecordWrite(r1, r2, result_register());
__ RecordWrite(r1, Operand(offset), r2, result_register());
}
break;
......@@ -1252,8 +1253,7 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
// Update the write barrier for the array store with r0 as the scratch
// register.
__ mov(r2, Operand(offset));
__ RecordWrite(r1, r2, result_register());
__ RecordWrite(r1, Operand(offset), r2, result_register());
}
if (result_saved) {
......@@ -1493,8 +1493,7 @@ void FullCodeGenerator::EmitVariableAssignment(Variable* var,
// RecordWrite may destroy all its register arguments.
__ mov(r3, result_register());
int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
__ mov(r2, Operand(offset));
__ RecordWrite(r1, r2, r3);
__ RecordWrite(r1, Operand(offset), r2, r3);
break;
}
......@@ -2276,8 +2275,7 @@ void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
__ str(r0, FieldMemOperand(r1, JSValue::kValueOffset));
// Update the write barrier. Save the value as it will be
// overwritten by the write barrier code and is needed afterward.
__ mov(r2, Operand(JSValue::kValueOffset - kHeapObjectTag));
__ RecordWrite(r1, r2, r3);
__ RecordWrite(r1, Operand(JSValue::kValueOffset - kHeapObjectTag), r2, r3);
__ bind(&done);
Apply(context_, r0);
......
......@@ -1692,7 +1692,7 @@ void KeyedStoreIC::GenerateGeneric(MacroAssembler* masm) {
__ Ret(eq);
// Update write barrier for the elements array address.
__ sub(r4, r5, Operand(elements));
__ RecordWrite(elements, r4, r5);
__ RecordWrite(elements, Operand(r4), r5, r6);
__ Ret();
}
......
......@@ -270,6 +270,17 @@ void MacroAssembler::Sbfx(Register dst, Register src1, int lsb, int width,
}
void MacroAssembler::Bfc(Register dst, int lsb, int width, Condition cond) {
ASSERT(lsb < 32);
if (!CpuFeatures::IsSupported(ARMv7)) {
int mask = (1 << (width + lsb)) - 1 - ((1 << lsb) - 1);
bic(dst, dst, Operand(mask));
} else {
bfc(dst, lsb, width, cond);
}
}
void MacroAssembler::SmiJumpTable(Register index, Vector<Label*> targets) {
// Empty the const pool.
CheckConstPool(true, true);
......@@ -299,31 +310,32 @@ void MacroAssembler::StoreRoot(Register source,
void MacroAssembler::RecordWriteHelper(Register object,
Register offset,
Register scratch) {
Operand offset,
Register scratch0,
Register scratch1) {
if (FLAG_debug_code) {
// Check that the object is not in new space.
Label not_in_new_space;
InNewSpace(object, scratch, ne, &not_in_new_space);
InNewSpace(object, scratch1, ne, &not_in_new_space);
Abort("new-space object passed to RecordWriteHelper");
bind(&not_in_new_space);
}
mov(ip, Operand(Page::kPageAlignmentMask)); // Load mask only once.
// Calculate region number.
add(offset, object, Operand(offset)); // Add offset into the object.
and_(offset, offset, Operand(ip)); // Offset into page of the object.
mov(offset, Operand(offset, LSR, Page::kRegionSizeLog2));
// Add offset into the object.
add(scratch0, object, offset);
// Calculate page address.
bic(object, object, Operand(ip));
Bfc(object, 0, kPageSizeBits);
// Calculate region number.
Ubfx(scratch0, scratch0, Page::kRegionSizeLog2,
kPageSizeBits - Page::kRegionSizeLog2);
// Mark region dirty.
ldr(scratch, MemOperand(object, Page::kDirtyFlagOffset));
ldr(scratch1, MemOperand(object, Page::kDirtyFlagOffset));
mov(ip, Operand(1));
orr(scratch, scratch, Operand(ip, LSL, offset));
str(scratch, MemOperand(object, Page::kDirtyFlagOffset));
orr(scratch1, scratch1, Operand(ip, LSL, scratch0));
str(scratch1, MemOperand(object, Page::kDirtyFlagOffset));
}
......@@ -341,21 +353,23 @@ void MacroAssembler::InNewSpace(Register object,
// 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) {
void MacroAssembler::RecordWrite(Register object,
Operand offset,
Register scratch0,
Register scratch1) {
// 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));
ASSERT(!object.is(cp) && !scratch0.is(cp) && !scratch1.is(cp));
Label done;
// First, test that the object is not in the new space. We cannot set
// region marks for new space pages.
InNewSpace(object, scratch, eq, &done);
InNewSpace(object, scratch0, eq, &done);
// Record the actual write.
RecordWriteHelper(object, offset, scratch);
RecordWriteHelper(object, offset, scratch0, scratch1);
bind(&done);
......@@ -363,8 +377,8 @@ void MacroAssembler::RecordWrite(Register object, Register offset,
// turned on to provoke errors.
if (FLAG_debug_code) {
mov(object, Operand(BitCast<int32_t>(kZapValue)));
mov(offset, Operand(BitCast<int32_t>(kZapValue)));
mov(scratch, Operand(BitCast<int32_t>(kZapValue)));
mov(scratch0, Operand(BitCast<int32_t>(kZapValue)));
mov(scratch1, Operand(BitCast<int32_t>(kZapValue)));
}
}
......
......@@ -100,6 +100,7 @@ class MacroAssembler: public Assembler {
Condition cond = al);
void Sbfx(Register dst, Register src, int lsb, int width,
Condition cond = al);
void Bfc(Register dst, int lsb, int width, Condition cond = al);
void Call(Label* target);
void Move(Register dst, Handle<Object> value);
......@@ -127,13 +128,19 @@ class MacroAssembler: public Assembler {
// For the page containing |object| mark the region covering [object+offset]
// dirty. The object address must be in the first 8K of an allocated page.
void RecordWriteHelper(Register object, Register offset, Register scratch);
void RecordWriteHelper(Register object,
Operand offset,
Register scratch0,
Register scratch1);
// For the page containing |object| mark the region covering [object+offset]
// dirty. The object address must be in the first 8K of an allocated page.
// The 'scratch' register is used in the implementation and all 3 registers
// The 'scratch' registers are used in the implementation and all 3 registers
// are clobbered by the operation, as well as the ip register.
void RecordWrite(Register object, Register offset, Register scratch);
void RecordWrite(Register object,
Operand offset,
Register scratch0,
Register scratch1);
// Push two registers. Pushes leftmost register first (to highest address).
void Push(Register src1, Register src2, Condition cond = al) {
......
......@@ -336,9 +336,8 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
__ b(eq, &exit);
// Update the write barrier for the array address.
// Pass the value being stored in the now unused name_reg.
__ mov(name_reg, Operand(offset));
__ RecordWrite(receiver_reg, name_reg, scratch);
// Pass the now unused name_reg as a scratch register.
__ RecordWrite(receiver_reg, Operand(offset), name_reg, scratch);
} else {
// Write to the properties array.
int offset = index * kPointerSize + FixedArray::kHeaderSize;
......@@ -352,8 +351,7 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
// Update the write barrier for the array address.
// Ok to clobber receiver_reg and name_reg, since we return.
__ mov(name_reg, Operand(offset));
__ RecordWrite(scratch, name_reg, receiver_reg);
__ RecordWrite(scratch, Operand(offset), name_reg, receiver_reg);
}
// Return the value (register r0).
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment