Revision: 11729
Author: [email protected]
Date: Wed Jun 6 04:05:28 2012
Log: Optimize write barrier of map-only elements transitions
[email protected]
Review URL: https://chromiumcodereview.appspot.com/10544005
http://code.google.com/p/v8/source/detail?r=11729
Modified:
/branches/bleeding_edge/src/assembler.cc
/branches/bleeding_edge/src/assembler.h
/branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc
/branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc
/branches/bleeding_edge/src/ia32/macro-assembler-ia32.h
=======================================
--- /branches/bleeding_edge/src/assembler.cc Wed Apr 18 00:02:21 2012
+++ /branches/bleeding_edge/src/assembler.cc Wed Jun 6 04:05:28 2012
@@ -1131,6 +1131,12 @@
FUNCTION_ADDR(math_log_double),
BUILTIN_FP_CALL));
}
+
+
+ExternalReference ExternalReference::page_flags(Page* page) {
+ return ExternalReference(reinterpret_cast<Address>(page) +
+ MemoryChunk::kFlagsOffset);
+}
// Helper function to compute x^y, where y is known to be an
=======================================
--- /branches/bleeding_edge/src/assembler.h Thu Apr 12 02:23:26 2012
+++ /branches/bleeding_edge/src/assembler.h Wed Jun 6 04:05:28 2012
@@ -656,6 +656,8 @@
static ExternalReference math_tan_double_function(Isolate* isolate);
static ExternalReference math_log_double_function(Isolate* isolate);
+ static ExternalReference page_flags(Page* page);
+
Address address() const {return reinterpret_cast<Address>(address_);}
#ifdef ENABLE_DEBUGGER_SUPPORT
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Mon Jun 4
07:42:58 2012
+++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Wed Jun 6
04:05:28 2012
@@ -3573,18 +3573,25 @@
ElementsKind to_kind = to_map->elements_kind();
Label not_applicable;
+ bool is_simple_map_transition =
+ IsSimpleMapChangeTransition(from_kind, to_kind);
+ Label::Distance branch_distance =
+ is_simple_map_transition ? Label::kNear : Label::kFar;
__ cmp(FieldOperand(object_reg, HeapObject::kMapOffset), from_map);
- __ j(not_equal, ¬_applicable);
- __ mov(new_map_reg, to_map);
- if (IsSimpleMapChangeTransition(from_kind, to_kind)) {
+ __ j(not_equal, ¬_applicable, branch_distance);
+ if (is_simple_map_transition) {
Register object_reg = ToRegister(instr->object());
- __ mov(FieldOperand(object_reg, HeapObject::kMapOffset), new_map_reg);
+ Handle<Map> map = instr->hydrogen()->transitioned_map();
+ __ mov(FieldOperand(object_reg, HeapObject::kMapOffset),
+ Immediate(map));
// Write barrier.
ASSERT_NE(instr->temp_reg(), NULL);
- __ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg,
- ToRegister(instr->temp_reg()), kDontSaveFPRegs);
+ __ RecordWriteForMap(object_reg, to_map, new_map_reg,
+ ToRegister(instr->temp_reg()),
+ kDontSaveFPRegs);
} else if (IsFastSmiElementsKind(from_kind) &&
IsFastDoubleElementsKind(to_kind)) {
+ __ mov(new_map_reg, to_map);
Register fixed_object_reg = ToRegister(instr->temp_reg());
ASSERT(fixed_object_reg.is(edx));
ASSERT(new_map_reg.is(ebx));
@@ -3593,6 +3600,7 @@
RelocInfo::CODE_TARGET, instr);
} else if (IsFastDoubleElementsKind(from_kind) &&
IsFastObjectElementsKind(to_kind)) {
+ __ mov(new_map_reg, to_map);
Register fixed_object_reg = ToRegister(instr->temp_reg());
ASSERT(fixed_object_reg.is(edx));
ASSERT(new_map_reg.is(ebx));
=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Wed May 23
07:24:29 2012
+++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.cc Wed Jun 6
04:05:28 2012
@@ -235,6 +235,70 @@
mov(dst, Immediate(BitCast<int32_t>(kZapValue)));
}
}
+
+
+void MacroAssembler::RecordWriteForMap(
+ Register object,
+ Handle<Map> map,
+ Register scratch1,
+ Register scratch2,
+ SaveFPRegsMode save_fp) {
+ // First, check if a write barrier is even needed. The tests below
+ // catch stores of Smis.
+ Label done;
+
+ Register address = scratch1;
+ Register value = scratch2;
+ if (emit_debug_code()) {
+ Label ok;
+ lea(address, FieldOperand(object, HeapObject::kMapOffset));
+ test_b(address, (1 << kPointerSizeLog2) - 1);
+ j(zero, &ok, Label::kNear);
+ int3();
+ bind(&ok);
+ }
+
+ ASSERT(!object.is(value));
+ ASSERT(!object.is(address));
+ ASSERT(!value.is(address));
+ if (emit_debug_code()) {
+ AbortIfSmi(object);
+ }
+
+ if (!FLAG_incremental_marking) {
+ return;
+ }
+
+ // A single check of the map's pages interesting flag suffices, since it
is
+ // only set during incremental collection, and then it's also guaranteed
that
+ // the from object's page's interesting flag is also set. This
optimization
+ // relies on the fact that maps can never be in new space.
+ ASSERT(!isolate()->heap()->InNewSpace(*map));
+ CheckPageFlagForMap(map,
+ MemoryChunk::kPointersToHereAreInterestingMask,
+ zero,
+ &done,
+ Label::kNear);
+
+ // Delay the initialization of |address| and |value| for the stub until
it's
+ // known that the will be needed. Up until this point their value are not
+ // needed since they are embedded in the operands of instructions that
need
+ // them.
+ lea(address, FieldOperand(object, HeapObject::kMapOffset));
+ mov(value, Immediate(map));
+ RecordWriteStub stub(object, value, address, OMIT_REMEMBERED_SET,
save_fp);
+ CallStub(&stub);
+
+ bind(&done);
+
+ // Clobber clobbered input registers when running with the debug-code
flag
+ // turned on to provoke errors.
+ if (emit_debug_code()) {
+ mov(value, Immediate(BitCast<int32_t>(kZapValue)));
+ mov(scratch1, Immediate(BitCast<int32_t>(kZapValue)));
+ mov(scratch2, Immediate(BitCast<int32_t>(kZapValue)));
+ }
+}
void MacroAssembler::RecordWrite(Register object,
@@ -2616,6 +2680,28 @@
}
j(cc, condition_met, condition_met_distance);
}
+
+
+void MacroAssembler::CheckPageFlagForMap(
+ Handle<Map> map,
+ int mask,
+ Condition cc,
+ Label* condition_met,
+ Label::Distance condition_met_distance) {
+ ASSERT(cc == zero || cc == not_zero);
+ Page* page = Page::FromAddress(map->address());
+ ExternalReference reference(ExternalReference::page_flags(page));
+ // The inlined static address check of the page's flags relies
+ // on maps never being compacted.
+ ASSERT(!isolate()->heap()->mark_compact_collector()->
+ IsOnEvacuationCandidate(*map));
+ if (mask < (1 << kBitsPerByte)) {
+ test_b(Operand::StaticVariable(reference), static_cast<uint8_t>(mask));
+ } else {
+ test(Operand::StaticVariable(reference), Immediate(mask));
+ }
+ j(cc, condition_met, condition_met_distance);
+}
void MacroAssembler::JumpIfBlack(Register object,
=======================================
--- /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h Wed May 23
07:24:29 2012
+++ /branches/bleeding_edge/src/ia32/macro-assembler-ia32.h Wed Jun 6
04:05:28 2012
@@ -90,6 +90,13 @@
Label* condition_met,
Label::Distance condition_met_distance = Label::kFar);
+ void CheckPageFlagForMap(
+ Handle<Map> map,
+ int mask,
+ Condition cc,
+ Label* condition_met,
+ Label::Distance condition_met_distance = Label::kFar);
+
// Check if object is in new space. Jumps if the object is not in new
space.
// The register scratch can be object itself, but scratch will be
clobbered.
void JumpIfNotInNewSpace(Register object,
@@ -194,6 +201,16 @@
RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
SmiCheck smi_check = INLINE_SMI_CHECK);
+ // For page containing |object| mark the region covering the object's map
+ // dirty. |object| is the object being stored into, |map| is the Map
object
+ // that was stored.
+ void RecordWriteForMap(
+ Register object,
+ Handle<Map> map,
+ Register scratch1,
+ Register scratch2,
+ SaveFPRegsMode save_fp);
+
#ifdef ENABLE_DEBUGGER_SUPPORT
//
---------------------------------------------------------------------------
// Debugger Support
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev