diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc index 3e933b0868..08a940d017 100644 --- a/src/arm/lithium-arm.cc +++ b/src/arm/lithium-arm.cc @@ -2334,7 +2334,9 @@ LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) { LOperand* temp = needs_write_barrier_for_map ? TempRegister() : NULL; 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 result; diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index 97f4cf67c2..aff5a78bf1 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -4229,6 +4229,12 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { if (!instr->hydrogen()->value()->range()->IsInSmiRange()) { 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()) { ASSERT(transition.is_null()); ASSERT(instr->is_in_object()); diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc index 127bf3fdd9..5d10a7e73b 100644 --- a/src/arm/stub-cache-arm.cc +++ b/src/arm/stub-cache-arm.cc @@ -516,6 +516,8 @@ void StubCompiler::GenerateStoreTransition(MacroAssembler* masm, if (FLAG_track_fields && representation.IsSmi()) { __ 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()) { Label do_store, heap_number; __ LoadRoot(scratch3, Heap::kHeapNumberMapRootIndex); @@ -685,6 +687,8 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, ASSERT(!representation.IsNone()); if (FLAG_track_fields && representation.IsSmi()) { __ 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()) { // Load the double storage. if (index < 0) { diff --git a/src/flag-definitions.h b/src/flag-definitions.h index 62c1d19d18..9b1ed1d031 100644 --- a/src/flag-definitions.h +++ b/src/flag-definitions.h @@ -195,7 +195,9 @@ DEFINE_bool(clever_optimizations, DEFINE_bool(pretenure_literals, true, "allocate literals in old space") 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_heap_object_fields, true, "track fields with heap values") DEFINE_implication(track_double_fields, track_fields) +DEFINE_implication(track_heap_object_fields, track_fields) // Flags for data representation optimizations DEFINE_bool(unbox_double_arrays, true, "automatically unbox arrays of doubles") diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index 62c9815389..fea05e8961 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -5218,6 +5218,10 @@ class HLoadNamedField: public HTemplateInstruction<2> { set_representation(Representation::Tagged()); } else if (FLAG_track_double_fields && field_representation.IsDouble()) { set_representation(field_representation); + } else if (FLAG_track_heap_object_fields && + field_representation.IsHeapObject()) { + set_type(HType::NonPrimitive()); + set_representation(Representation::Tagged()); } else { set_representation(Representation::Tagged()); } diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index 6ec5ed9a5c..9ab2d412be 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -4239,6 +4239,19 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { 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()) { ASSERT(transition.is_null()); ASSERT(instr->is_in_object()); diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc index 45261e3fc7..1d41505b6d 100644 --- a/src/ia32/lithium-ia32.cc +++ b/src/ia32/lithium-ia32.cc @@ -2458,7 +2458,9 @@ LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) { LStoreNamedField* result = 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 result; diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc index 9623b9a520..4805d52e40 100644 --- a/src/ia32/stub-cache-ia32.cc +++ b/src/ia32/stub-cache-ia32.cc @@ -826,6 +826,8 @@ void StubCompiler::GenerateStoreTransition(MacroAssembler* masm, if (FLAG_track_fields && representation.IsSmi()) { __ 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()) { Label do_store, heap_number; __ AllocateHeapNumber(storage_reg, scratch1, scratch2, slow); @@ -996,6 +998,8 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, ASSERT(!representation.IsNone()); if (FLAG_track_fields && representation.IsSmi()) { __ 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()) { // Load the double storage. if (index < 0) { diff --git a/src/objects-inl.h b/src/objects-inl.h index 06a13df5a3..a9222227d2 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -3608,6 +3608,10 @@ bool Map::CanBeDeprecated() { if (FLAG_track_double_fields && details.representation().IsDouble()) { return true; } + if (FLAG_track_heap_object_fields && + details.representation().IsHeapObject()) { + return true; + } } return false; } diff --git a/src/objects.cc b/src/objects.cc index d127d1bb8a..dd6cb9f36a 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -2137,6 +2137,7 @@ const char* Representation::Mnemonic() const { case kSmi: return "s"; case kDouble: return "d"; case kInteger32: return "i"; + case kHeapObject: return "h"; case kExternal: return "x"; default: UNREACHABLE(); @@ -2499,10 +2500,10 @@ MaybeObject* Map::GeneralizeRepresentation(int modify_index, Representation new_representation) { Map* old_map = this; DescriptorArray* old_descriptors = old_map->instance_descriptors(); - Representation old_reprepresentation = + Representation old_representation = old_descriptors->GetDetails(modify_index).representation(); - if (old_reprepresentation.IsNone()) { + if (old_representation.IsNone()) { UNREACHABLE(); old_descriptors->SetRepresentation(modify_index, new_representation); return this; @@ -2528,9 +2529,14 @@ MaybeObject* Map::GeneralizeRepresentation(int modify_index, Representation updated_representation = updated_descriptors->GetDetails(modify_index).representation(); if (new_representation.fits_into(updated_representation)) { - if (FLAG_trace_generalization) { - PrintF("migrating to existing map %p -> %p\n", - static_cast(this), static_cast(updated)); + if (FLAG_trace_generalization && + !(modify_index == 0 && new_representation.IsSmi())) { + PropertyDetails old_details = old_descriptors->GetDetails(modify_index); + PrintF("migrating to existing map %p(%s) -> %p(%s)\n", + static_cast(this), + old_details.representation().Mnemonic(), + static_cast(updated), + updated_representation.Mnemonic()); } return updated; } @@ -2541,10 +2547,13 @@ MaybeObject* Map::GeneralizeRepresentation(int modify_index, verbatim, valid, descriptors, old_descriptors); if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; - old_reprepresentation = + old_representation = new_descriptors->GetDetails(modify_index).representation(); - new_representation = new_representation.generalize(old_reprepresentation); - new_descriptors->SetRepresentation(modify_index, new_representation); + Representation updated_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( verbatim, descriptors, new_descriptors); @@ -2558,10 +2567,14 @@ MaybeObject* Map::GeneralizeRepresentation(int modify_index, split_map->DeprecateTarget( old_descriptors->GetKey(descriptor), new_descriptors); - if (FLAG_trace_generalization) { - PrintF("migrating to new map %p -> %p (%i steps)\n", + if (FLAG_trace_generalization && + !(modify_index == 0 && new_representation.IsSmi())) { + PrintF("migrating to new map %i: %p(%s) -> %p(%s) (%i steps)\n", + modify_index, static_cast(this), + old_representation.Mnemonic(), static_cast(new_descriptors), + updated_representation.Mnemonic(), descriptors - descriptor); } diff --git a/src/objects.h b/src/objects.h index 1b4ed5b3b5..7dfc46291b 100644 --- a/src/objects.h +++ b/src/objects.h @@ -1066,6 +1066,13 @@ class Object : public MaybeObject { return Representation::Smi(); } else if (FLAG_track_double_fields && IsHeapNumber()) { 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 { return Representation::Tagged(); } @@ -1076,6 +1083,8 @@ class Object : public MaybeObject { return IsSmi(); } else if (FLAG_track_double_fields && representation.IsDouble()) { return IsNumber(); + } else if (FLAG_track_heap_object_fields && representation.IsHeapObject()) { + return IsHeapObject(); } return true; } diff --git a/src/property-details.h b/src/property-details.h index 62140fe962..674fc8869a 100644 --- a/src/property-details.h +++ b/src/property-details.h @@ -83,6 +83,7 @@ class Representation { kSmi, kInteger32, kDouble, + kHeapObject, kTagged, kExternal, kNumRepresentations @@ -95,6 +96,7 @@ class Representation { static Representation Smi() { return Representation(kSmi); } static Representation Integer32() { return Representation(kInteger32); } static Representation Double() { return Representation(kDouble); } + static Representation HeapObject() { return Representation(kHeapObject); } static Representation External() { return Representation(kExternal); } static Representation FromKind(Kind kind) { return Representation(kind); } @@ -111,6 +113,7 @@ class Representation { bool is_more_general_than(const Representation& other) const { ASSERT(kind_ != kExternal); ASSERT(other.kind_ != kExternal); + if (IsHeapObject()) return other.IsDouble(); return kind_ > other.kind_; } @@ -119,11 +122,9 @@ class Representation { } Representation generalize(Representation other) { - if (is_more_general_than(other)) { - return *this; - } else { - return other; - } + if (other.fits_into(*this)) return *this; + if (other.is_more_general_than(*this)) return other; + return Representation::Tagged(); } Kind kind() const { return static_cast(kind_); } @@ -132,6 +133,7 @@ class Representation { bool IsSmi() const { return kind_ == kSmi; } bool IsInteger32() const { return kind_ == kInteger32; } bool IsDouble() const { return kind_ == kDouble; } + bool IsHeapObject() const { return kind_ == kHeapObject; } bool IsExternal() const { return kind_ == kExternal; } bool IsSpecialization() const { return kind_ == kInteger32 || kind_ == kDouble; diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index f08c56e1f7..b357902975 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -3921,6 +3921,19 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) { Register value = ToRegister(instr->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()) { ASSERT(transition.is_null()); ASSERT(instr->is_in_object()); diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc index b8b02da37a..c89efd95af 100644 --- a/src/x64/lithium-x64.cc +++ b/src/x64/lithium-x64.cc @@ -2273,7 +2273,9 @@ LInstruction* LChunkBuilder::DoStoreNamedField(HStoreNamedField* instr) { needs_write_barrier_for_map) ? TempRegister() : NULL; 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 result; diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc index a7faf9b663..f0b362b947 100644 --- a/src/x64/stub-cache-x64.cc +++ b/src/x64/stub-cache-x64.cc @@ -807,6 +807,8 @@ void StubCompiler::GenerateStoreTransition(MacroAssembler* masm, if (FLAG_track_fields && representation.IsSmi()) { __ 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()) { Label do_store, heap_number; __ AllocateHeapNumber(storage_reg, scratch1, slow); @@ -953,6 +955,8 @@ void StubCompiler::GenerateStoreField(MacroAssembler* masm, ASSERT(!representation.IsNone()); if (FLAG_track_fields && representation.IsSmi()) { __ 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()) { // Load the double storage. if (index < 0) { diff --git a/test/mjsunit/elements-transition-hoisting.js b/test/mjsunit/elements-transition-hoisting.js index e5f4f661bf..40b25cd582 100644 --- a/test/mjsunit/elements-transition-hoisting.js +++ b/test/mjsunit/elements-transition-hoisting.js @@ -129,7 +129,7 @@ if (support_smi_only_arrays) { // upon can hoisted, too. function testExactMapHoisting3(a) { var object = new Object(); - a.foo = 0; + a.foo = null; a[0] = 0; a[1] = 1; var count = 3;