Track heap objects.

R=danno@chromium.org

Review URL: https://chromiumcodereview.appspot.com/14996004

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14625 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
verwaest@chromium.org 2013-05-10 17:17:50 +00:00
parent d97fe8d4df
commit df57747fc4
16 changed files with 103 additions and 19 deletions

View File

@ -2334,7 +2334,9 @@ LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
LOperand* temp = needs_write_barrier_for_map ? TempRegister() : NULL; LOperand* temp = needs_write_barrier_for_map ? TempRegister() : NULL;
LStoreNamedField* result = new(zone()) LStoreNamedField(obj, val, temp); LStoreNamedField* result = new(zone()) LStoreNamedField(obj, val, temp);
if (FLAG_track_fields && instr->field_representation().IsSmi()) { if ((FLAG_track_fields && instr->field_representation().IsSmi()) ||
(FLAG_track_heap_object_fields &&
instr->field_representation().IsHeapObject())) {
return AssignEnvironment(result); return AssignEnvironment(result);
} }
return result; return result;

View File

@ -4229,6 +4229,12 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
if (!instr->hydrogen()->value()->range()->IsInSmiRange()) { if (!instr->hydrogen()->value()->range()->IsInSmiRange()) {
DeoptimizeIf(vs, instr->environment()); DeoptimizeIf(vs, instr->environment());
} }
} else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
Register value = ToRegister(instr->value());
if (!instr->hydrogen()->value()->type().IsHeapObject()) {
__ tst(value, Operand(kSmiTagMask));
DeoptimizeIf(eq, instr->environment());
}
} else if (FLAG_track_double_fields && representation.IsDouble()) { } else if (FLAG_track_double_fields && representation.IsDouble()) {
ASSERT(transition.is_null()); ASSERT(transition.is_null());
ASSERT(instr->is_in_object()); ASSERT(instr->is_in_object());

View File

@ -516,6 +516,8 @@ void StubCompiler::GenerateStoreTransition(MacroAssembler* masm,
if (FLAG_track_fields && representation.IsSmi()) { if (FLAG_track_fields && representation.IsSmi()) {
__ JumpIfNotSmi(value_reg, miss_restore_name); __ JumpIfNotSmi(value_reg, miss_restore_name);
} else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
__ JumpIfSmi(value_reg, miss_restore_name);
} else if (FLAG_track_double_fields && representation.IsDouble()) { } else if (FLAG_track_double_fields && representation.IsDouble()) {
Label do_store, heap_number; Label do_store, heap_number;
__ LoadRoot(scratch3, Heap::kHeapNumberMapRootIndex); __ LoadRoot(scratch3, Heap::kHeapNumberMapRootIndex);
@ -685,6 +687,8 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
ASSERT(!representation.IsNone()); ASSERT(!representation.IsNone());
if (FLAG_track_fields && representation.IsSmi()) { if (FLAG_track_fields && representation.IsSmi()) {
__ JumpIfNotSmi(value_reg, miss_label); __ JumpIfNotSmi(value_reg, miss_label);
} else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
__ JumpIfSmi(value_reg, miss_label);
} else if (FLAG_track_double_fields && representation.IsDouble()) { } else if (FLAG_track_double_fields && representation.IsDouble()) {
// Load the double storage. // Load the double storage.
if (index < 0) { if (index < 0) {

View File

@ -195,7 +195,9 @@ DEFINE_bool(clever_optimizations,
DEFINE_bool(pretenure_literals, true, "allocate literals in old space") DEFINE_bool(pretenure_literals, true, "allocate literals in old space")
DEFINE_bool(track_fields, true, "track fields with only smi values") DEFINE_bool(track_fields, true, "track fields with only smi values")
DEFINE_bool(track_double_fields, true, "track fields with double values") DEFINE_bool(track_double_fields, true, "track fields with double values")
DEFINE_bool(track_heap_object_fields, true, "track fields with heap values")
DEFINE_implication(track_double_fields, track_fields) DEFINE_implication(track_double_fields, track_fields)
DEFINE_implication(track_heap_object_fields, track_fields)
// Flags for data representation optimizations // Flags for data representation optimizations
DEFINE_bool(unbox_double_arrays, true, "automatically unbox arrays of doubles") DEFINE_bool(unbox_double_arrays, true, "automatically unbox arrays of doubles")

View File

@ -5218,6 +5218,10 @@ class HLoadNamedField: public HTemplateInstruction<2> {
set_representation(Representation::Tagged()); set_representation(Representation::Tagged());
} else if (FLAG_track_double_fields && field_representation.IsDouble()) { } else if (FLAG_track_double_fields && field_representation.IsDouble()) {
set_representation(field_representation); set_representation(field_representation);
} else if (FLAG_track_heap_object_fields &&
field_representation.IsHeapObject()) {
set_type(HType::NonPrimitive());
set_representation(Representation::Tagged());
} else { } else {
set_representation(Representation::Tagged()); set_representation(Representation::Tagged());
} }

View File

@ -4239,6 +4239,19 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
DeoptimizeIf(overflow, instr->environment()); DeoptimizeIf(overflow, instr->environment());
} }
} }
} else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
if (instr->value()->IsConstantOperand()) {
LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
if (IsInteger32(operand_value)) {
DeoptimizeIf(no_condition, instr->environment());
}
} else {
if (!instr->hydrogen()->value()->type().IsHeapObject()) {
Register value = ToRegister(instr->value());
__ test(value, Immediate(kSmiTagMask));
DeoptimizeIf(zero, instr->environment());
}
}
} else if (FLAG_track_double_fields && representation.IsDouble()) { } else if (FLAG_track_double_fields && representation.IsDouble()) {
ASSERT(transition.is_null()); ASSERT(transition.is_null());
ASSERT(instr->is_in_object()); ASSERT(instr->is_in_object());

View File

@ -2458,7 +2458,9 @@ LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
LStoreNamedField* result = LStoreNamedField* result =
new(zone()) LStoreNamedField(obj, val, temp, temp_map); new(zone()) LStoreNamedField(obj, val, temp, temp_map);
if (FLAG_track_fields && instr->field_representation().IsSmi()) { if ((FLAG_track_fields && instr->field_representation().IsSmi()) ||
(FLAG_track_heap_object_fields &&
instr->field_representation().IsHeapObject())) {
return AssignEnvironment(result); return AssignEnvironment(result);
} }
return result; return result;

View File

@ -826,6 +826,8 @@ void StubCompiler::GenerateStoreTransition(MacroAssembler* masm,
if (FLAG_track_fields && representation.IsSmi()) { if (FLAG_track_fields && representation.IsSmi()) {
__ JumpIfNotSmi(value_reg, miss_restore_name); __ JumpIfNotSmi(value_reg, miss_restore_name);
} else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
__ JumpIfSmi(value_reg, miss_restore_name);
} else if (FLAG_track_double_fields && representation.IsDouble()) { } else if (FLAG_track_double_fields && representation.IsDouble()) {
Label do_store, heap_number; Label do_store, heap_number;
__ AllocateHeapNumber(storage_reg, scratch1, scratch2, slow); __ AllocateHeapNumber(storage_reg, scratch1, scratch2, slow);
@ -996,6 +998,8 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
ASSERT(!representation.IsNone()); ASSERT(!representation.IsNone());
if (FLAG_track_fields && representation.IsSmi()) { if (FLAG_track_fields && representation.IsSmi()) {
__ JumpIfNotSmi(value_reg, miss_label); __ JumpIfNotSmi(value_reg, miss_label);
} else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
__ JumpIfSmi(value_reg, miss_label);
} else if (FLAG_track_double_fields && representation.IsDouble()) { } else if (FLAG_track_double_fields && representation.IsDouble()) {
// Load the double storage. // Load the double storage.
if (index < 0) { if (index < 0) {

View File

@ -3608,6 +3608,10 @@ bool Map::CanBeDeprecated() {
if (FLAG_track_double_fields && details.representation().IsDouble()) { if (FLAG_track_double_fields && details.representation().IsDouble()) {
return true; return true;
} }
if (FLAG_track_heap_object_fields &&
details.representation().IsHeapObject()) {
return true;
}
} }
return false; return false;
} }

View File

@ -2137,6 +2137,7 @@ const char* Representation::Mnemonic() const {
case kSmi: return "s"; case kSmi: return "s";
case kDouble: return "d"; case kDouble: return "d";
case kInteger32: return "i"; case kInteger32: return "i";
case kHeapObject: return "h";
case kExternal: return "x"; case kExternal: return "x";
default: default:
UNREACHABLE(); UNREACHABLE();
@ -2499,10 +2500,10 @@ MaybeObject* Map::GeneralizeRepresentation(int modify_index,
Representation new_representation) { Representation new_representation) {
Map* old_map = this; Map* old_map = this;
DescriptorArray* old_descriptors = old_map->instance_descriptors(); DescriptorArray* old_descriptors = old_map->instance_descriptors();
Representation old_reprepresentation = Representation old_representation =
old_descriptors->GetDetails(modify_index).representation(); old_descriptors->GetDetails(modify_index).representation();
if (old_reprepresentation.IsNone()) { if (old_representation.IsNone()) {
UNREACHABLE(); UNREACHABLE();
old_descriptors->SetRepresentation(modify_index, new_representation); old_descriptors->SetRepresentation(modify_index, new_representation);
return this; return this;
@ -2528,9 +2529,14 @@ MaybeObject* Map::GeneralizeRepresentation(int modify_index,
Representation updated_representation = Representation updated_representation =
updated_descriptors->GetDetails(modify_index).representation(); updated_descriptors->GetDetails(modify_index).representation();
if (new_representation.fits_into(updated_representation)) { if (new_representation.fits_into(updated_representation)) {
if (FLAG_trace_generalization) { if (FLAG_trace_generalization &&
PrintF("migrating to existing map %p -> %p\n", !(modify_index == 0 && new_representation.IsSmi())) {
static_cast<void*>(this), static_cast<void*>(updated)); PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
PrintF("migrating to existing map %p(%s) -> %p(%s)\n",
static_cast<void*>(this),
old_details.representation().Mnemonic(),
static_cast<void*>(updated),
updated_representation.Mnemonic());
} }
return updated; return updated;
} }
@ -2541,10 +2547,13 @@ MaybeObject* Map::GeneralizeRepresentation(int modify_index,
verbatim, valid, descriptors, old_descriptors); verbatim, valid, descriptors, old_descriptors);
if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors;
old_reprepresentation = old_representation =
new_descriptors->GetDetails(modify_index).representation(); new_descriptors->GetDetails(modify_index).representation();
new_representation = new_representation.generalize(old_reprepresentation); Representation updated_representation =
new_descriptors->SetRepresentation(modify_index, new_representation); new_representation.generalize(old_representation);
if (!updated_representation.Equals(old_representation)) {
new_descriptors->SetRepresentation(modify_index, updated_representation);
}
Map* split_map = root_map->FindLastMatchMap( Map* split_map = root_map->FindLastMatchMap(
verbatim, descriptors, new_descriptors); verbatim, descriptors, new_descriptors);
@ -2558,10 +2567,14 @@ MaybeObject* Map::GeneralizeRepresentation(int modify_index,
split_map->DeprecateTarget( split_map->DeprecateTarget(
old_descriptors->GetKey(descriptor), new_descriptors); old_descriptors->GetKey(descriptor), new_descriptors);
if (FLAG_trace_generalization) { if (FLAG_trace_generalization &&
PrintF("migrating to new map %p -> %p (%i steps)\n", !(modify_index == 0 && new_representation.IsSmi())) {
PrintF("migrating to new map %i: %p(%s) -> %p(%s) (%i steps)\n",
modify_index,
static_cast<void*>(this), static_cast<void*>(this),
old_representation.Mnemonic(),
static_cast<void*>(new_descriptors), static_cast<void*>(new_descriptors),
updated_representation.Mnemonic(),
descriptors - descriptor); descriptors - descriptor);
} }

View File

@ -1066,6 +1066,13 @@ class Object : public MaybeObject {
return Representation::Smi(); return Representation::Smi();
} else if (FLAG_track_double_fields && IsHeapNumber()) { } else if (FLAG_track_double_fields && IsHeapNumber()) {
return Representation::Double(); return Representation::Double();
} else if (FLAG_track_heap_object_fields && !IsUndefined()) {
// Don't track undefined as heapobject because it's also used as temporary
// value for computed fields that may turn out to be Smi. That combination
// will go tagged, so go tagged immediately.
// TODO(verwaest): Change once we track computed boilerplate fields.
ASSERT(IsHeapObject());
return Representation::HeapObject();
} else { } else {
return Representation::Tagged(); return Representation::Tagged();
} }
@ -1076,6 +1083,8 @@ class Object : public MaybeObject {
return IsSmi(); return IsSmi();
} else if (FLAG_track_double_fields && representation.IsDouble()) { } else if (FLAG_track_double_fields && representation.IsDouble()) {
return IsNumber(); return IsNumber();
} else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
return IsHeapObject();
} }
return true; return true;
} }

View File

@ -83,6 +83,7 @@ class Representation {
kSmi, kSmi,
kInteger32, kInteger32,
kDouble, kDouble,
kHeapObject,
kTagged, kTagged,
kExternal, kExternal,
kNumRepresentations kNumRepresentations
@ -95,6 +96,7 @@ class Representation {
static Representation Smi() { return Representation(kSmi); } static Representation Smi() { return Representation(kSmi); }
static Representation Integer32() { return Representation(kInteger32); } static Representation Integer32() { return Representation(kInteger32); }
static Representation Double() { return Representation(kDouble); } static Representation Double() { return Representation(kDouble); }
static Representation HeapObject() { return Representation(kHeapObject); }
static Representation External() { return Representation(kExternal); } static Representation External() { return Representation(kExternal); }
static Representation FromKind(Kind kind) { return Representation(kind); } static Representation FromKind(Kind kind) { return Representation(kind); }
@ -111,6 +113,7 @@ class Representation {
bool is_more_general_than(const Representation& other) const { bool is_more_general_than(const Representation& other) const {
ASSERT(kind_ != kExternal); ASSERT(kind_ != kExternal);
ASSERT(other.kind_ != kExternal); ASSERT(other.kind_ != kExternal);
if (IsHeapObject()) return other.IsDouble();
return kind_ > other.kind_; return kind_ > other.kind_;
} }
@ -119,11 +122,9 @@ class Representation {
} }
Representation generalize(Representation other) { Representation generalize(Representation other) {
if (is_more_general_than(other)) { if (other.fits_into(*this)) return *this;
return *this; if (other.is_more_general_than(*this)) return other;
} else { return Representation::Tagged();
return other;
}
} }
Kind kind() const { return static_cast<Kind>(kind_); } Kind kind() const { return static_cast<Kind>(kind_); }
@ -132,6 +133,7 @@ class Representation {
bool IsSmi() const { return kind_ == kSmi; } bool IsSmi() const { return kind_ == kSmi; }
bool IsInteger32() const { return kind_ == kInteger32; } bool IsInteger32() const { return kind_ == kInteger32; }
bool IsDouble() const { return kind_ == kDouble; } bool IsDouble() const { return kind_ == kDouble; }
bool IsHeapObject() const { return kind_ == kHeapObject; }
bool IsExternal() const { return kind_ == kExternal; } bool IsExternal() const { return kind_ == kExternal; }
bool IsSpecialization() const { bool IsSpecialization() const {
return kind_ == kInteger32 || kind_ == kDouble; return kind_ == kInteger32 || kind_ == kDouble;

View File

@ -3921,6 +3921,19 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
Register value = ToRegister(instr->value()); Register value = ToRegister(instr->value());
__ Integer32ToSmi(value, value); __ Integer32ToSmi(value, value);
} }
} else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
if (instr->value()->IsConstantOperand()) {
LConstantOperand* operand_value = LConstantOperand::cast(instr->value());
if (IsInteger32Constant(operand_value)) {
DeoptimizeIf(no_condition, instr->environment());
}
} else {
if (!instr->hydrogen()->value()->type().IsHeapObject()) {
Register value = ToRegister(instr->value());
Condition cc = masm()->CheckSmi(value);
DeoptimizeIf(cc, instr->environment());
}
}
} else if (FLAG_track_double_fields && representation.IsDouble()) { } else if (FLAG_track_double_fields && representation.IsDouble()) {
ASSERT(transition.is_null()); ASSERT(transition.is_null());
ASSERT(instr->is_in_object()); ASSERT(instr->is_in_object());

View File

@ -2273,7 +2273,9 @@ LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) {
needs_write_barrier_for_map) ? TempRegister() : NULL; needs_write_barrier_for_map) ? TempRegister() : NULL;
LStoreNamedField* result = new(zone()) LStoreNamedField(obj, val, temp); LStoreNamedField* result = new(zone()) LStoreNamedField(obj, val, temp);
if (FLAG_track_fields && instr->field_representation().IsSmi()) { if ((FLAG_track_fields && instr->field_representation().IsSmi()) ||
(FLAG_track_heap_object_fields &&
instr->field_representation().IsHeapObject())) {
return AssignEnvironment(result); return AssignEnvironment(result);
} }
return result; return result;

View File

@ -807,6 +807,8 @@ void StubCompiler::GenerateStoreTransition(MacroAssembler* masm,
if (FLAG_track_fields && representation.IsSmi()) { if (FLAG_track_fields && representation.IsSmi()) {
__ JumpIfNotSmi(value_reg, miss_restore_name); __ JumpIfNotSmi(value_reg, miss_restore_name);
} else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
__ JumpIfSmi(value_reg, miss_restore_name);
} else if (FLAG_track_double_fields && representation.IsDouble()) { } else if (FLAG_track_double_fields && representation.IsDouble()) {
Label do_store, heap_number; Label do_store, heap_number;
__ AllocateHeapNumber(storage_reg, scratch1, slow); __ AllocateHeapNumber(storage_reg, scratch1, slow);
@ -953,6 +955,8 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm,
ASSERT(!representation.IsNone()); ASSERT(!representation.IsNone());
if (FLAG_track_fields && representation.IsSmi()) { if (FLAG_track_fields && representation.IsSmi()) {
__ JumpIfNotSmi(value_reg, miss_label); __ JumpIfNotSmi(value_reg, miss_label);
} else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
__ JumpIfSmi(value_reg, miss_label);
} else if (FLAG_track_double_fields && representation.IsDouble()) { } else if (FLAG_track_double_fields && representation.IsDouble()) {
// Load the double storage. // Load the double storage.
if (index < 0) { if (index < 0) {

View File

@ -129,7 +129,7 @@ if (support_smi_only_arrays) {
// upon can hoisted, too. // upon can hoisted, too.
function testExactMapHoisting3(a) { function testExactMapHoisting3(a) {
var object = new Object(); var object = new Object();
a.foo = 0; a.foo = null;
a[0] = 0; a[0] = 0;
a[1] = 1; a[1] = 1;
var count = 3; var count = 3;