Initialized representations of computed values to None.
R=danno@chromium.org Review URL: https://chromiumcodereview.appspot.com/14721009 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14982 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
27d01cf8b2
commit
16199c63d8
@ -5283,7 +5283,7 @@ class Internals {
|
||||
static const int kNullValueRootIndex = 7;
|
||||
static const int kTrueValueRootIndex = 8;
|
||||
static const int kFalseValueRootIndex = 9;
|
||||
static const int kEmptyStringRootIndex = 129;
|
||||
static const int kEmptyStringRootIndex = 130;
|
||||
|
||||
static const int kNodeClassIdOffset = 1 * kApiPointerSize;
|
||||
static const int kNodeFlagsOffset = 1 * kApiPointerSize + 3;
|
||||
|
@ -1086,11 +1086,13 @@ bool Genesis::InitializeGlobal(Handle<GlobalObject> inner_global,
|
||||
CHECK_NOT_EMPTY_HANDLE(isolate,
|
||||
JSObject::SetLocalPropertyIgnoreAttributes(
|
||||
result, factory->length_string(),
|
||||
factory->undefined_value(), DONT_ENUM));
|
||||
factory->undefined_value(), DONT_ENUM,
|
||||
Object::FORCE_TAGGED));
|
||||
CHECK_NOT_EMPTY_HANDLE(isolate,
|
||||
JSObject::SetLocalPropertyIgnoreAttributes(
|
||||
result, factory->callee_string(),
|
||||
factory->undefined_value(), DONT_ENUM));
|
||||
factory->undefined_value(), DONT_ENUM,
|
||||
Object::FORCE_TAGGED));
|
||||
|
||||
#ifdef DEBUG
|
||||
LookupResult lookup(isolate);
|
||||
|
@ -199,8 +199,10 @@ DEFINE_bool(pretenuring_call_new, false, "pretenure call new")
|
||||
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_bool(track_computed_fields, true, "track computed boilerplate fields")
|
||||
DEFINE_implication(track_double_fields, track_fields)
|
||||
DEFINE_implication(track_heap_object_fields, track_fields)
|
||||
DEFINE_implication(track_computed_fields, track_fields)
|
||||
|
||||
// Flags for data representation optimizations
|
||||
DEFINE_bool(unbox_double_arrays, true, "automatically unbox arrays of doubles")
|
||||
|
@ -2845,6 +2845,13 @@ bool Heap::CreateInitialObjects() {
|
||||
}
|
||||
set_the_hole_value(Oddball::cast(obj));
|
||||
|
||||
{ MaybeObject* maybe_obj = CreateOddball("uninitialized",
|
||||
Smi::FromInt(-1),
|
||||
Oddball::kUninitialized);
|
||||
if (!maybe_obj->ToObject(&obj)) return false;
|
||||
}
|
||||
set_uninitialized_value(Oddball::cast(obj));
|
||||
|
||||
{ MaybeObject* maybe_obj = CreateOddball("arguments_marker",
|
||||
Smi::FromInt(-4),
|
||||
Oddball::kArgumentMarker);
|
||||
|
@ -59,6 +59,7 @@ namespace internal {
|
||||
V(Oddball, null_value, NullValue) \
|
||||
V(Oddball, true_value, TrueValue) \
|
||||
V(Oddball, false_value, FalseValue) \
|
||||
V(Oddball, uninitialized_value, UninitializedValue) \
|
||||
V(Map, global_property_cell_map, GlobalPropertyCellMap) \
|
||||
V(Map, shared_function_info_map, SharedFunctionInfoMap) \
|
||||
V(Map, meta_map, MetaMap) \
|
||||
|
@ -312,8 +312,9 @@ void JSObject::JSObjectVerify() {
|
||||
Representation r = descriptors->GetDetails(i).representation();
|
||||
int field = descriptors->GetFieldIndex(i);
|
||||
Object* value = RawFastPropertyAt(field);
|
||||
if (r.IsSmi()) ASSERT(value->IsSmi());
|
||||
if (r.IsDouble()) ASSERT(value->IsHeapNumber());
|
||||
if (value->IsUninitialized()) continue;
|
||||
if (r.IsSmi()) ASSERT(value->IsSmi());
|
||||
if (r.IsHeapObject()) ASSERT(value->IsHeapObject());
|
||||
}
|
||||
}
|
||||
|
@ -292,6 +292,9 @@ MaybeObject* Object::AllocateNewStorageFor(Heap* heap,
|
||||
PretenureFlag tenure) {
|
||||
if (!FLAG_track_double_fields) return this;
|
||||
if (!representation.IsDouble()) return this;
|
||||
if (IsUninitialized()) {
|
||||
return heap->AllocateHeapNumber(0, tenure);
|
||||
}
|
||||
return heap->AllocateHeapNumber(Number(), tenure);
|
||||
}
|
||||
|
||||
@ -530,6 +533,11 @@ bool MaybeObject::IsTheHole() {
|
||||
}
|
||||
|
||||
|
||||
bool MaybeObject::IsUninitialized() {
|
||||
return !IsFailure() && ToObjectUnchecked()->IsUninitialized();
|
||||
}
|
||||
|
||||
|
||||
Failure* Failure::cast(MaybeObject* obj) {
|
||||
ASSERT(HAS_FAILURE_TAG(obj));
|
||||
return reinterpret_cast<Failure*>(obj);
|
||||
@ -845,6 +853,11 @@ bool Object::IsTheHole() {
|
||||
}
|
||||
|
||||
|
||||
bool Object::IsUninitialized() {
|
||||
return IsOddball() && Oddball::cast(this)->kind() == Oddball::kUninitialized;
|
||||
}
|
||||
|
||||
|
||||
bool Object::IsTrue() {
|
||||
return IsOddball() && Oddball::cast(this)->kind() == Oddball::kTrue;
|
||||
}
|
||||
@ -1541,7 +1554,7 @@ MaybeObject* JSObject::MigrateInstance() {
|
||||
// Converting any field to the most specific type will cause the
|
||||
// GeneralizeFieldRepresentation algorithm to create the most general existing
|
||||
// transition that matches the object. This achieves what is needed.
|
||||
return GeneralizeFieldRepresentation(0, Representation::Smi());
|
||||
return GeneralizeFieldRepresentation(0, Representation::None());
|
||||
}
|
||||
|
||||
|
||||
@ -2366,7 +2379,6 @@ void DescriptorArray::Set(int descriptor_number,
|
||||
// Range check.
|
||||
ASSERT(descriptor_number < number_of_descriptors());
|
||||
|
||||
ASSERT(!desc->GetDetails().representation().IsNone());
|
||||
NoIncrementalWriteBarrierSet(this,
|
||||
ToKeyIndex(descriptor_number),
|
||||
desc->GetKey());
|
||||
@ -2382,7 +2394,6 @@ void DescriptorArray::Set(int descriptor_number,
|
||||
void DescriptorArray::Set(int descriptor_number, Descriptor* desc) {
|
||||
// Range check.
|
||||
ASSERT(descriptor_number < number_of_descriptors());
|
||||
ASSERT(!desc->GetDetails().representation().IsNone());
|
||||
|
||||
set(ToKeyIndex(descriptor_number), desc->GetKey());
|
||||
set(ToValueIndex(descriptor_number), desc->GetValue());
|
||||
@ -3617,6 +3628,9 @@ bool Map::CanBeDeprecated() {
|
||||
int descriptor = LastAdded();
|
||||
for (int i = 0; i <= descriptor; i++) {
|
||||
PropertyDetails details = instance_descriptors()->GetDetails(i);
|
||||
if (FLAG_track_fields && details.representation().IsNone()) {
|
||||
return true;
|
||||
}
|
||||
if (FLAG_track_fields && details.representation().IsSmi()) {
|
||||
return true;
|
||||
}
|
||||
|
@ -1817,7 +1817,8 @@ static bool IsIdentifier(UnicodeCache* cache, Name* name) {
|
||||
MaybeObject* JSObject::AddFastProperty(Name* name,
|
||||
Object* value,
|
||||
PropertyAttributes attributes,
|
||||
StoreFromKeyed store_mode) {
|
||||
StoreFromKeyed store_mode,
|
||||
ValueType value_type) {
|
||||
ASSERT(!IsJSGlobalProxy());
|
||||
ASSERT(DescriptorArray::kNotFound ==
|
||||
map()->instance_descriptors()->Search(
|
||||
@ -1843,8 +1844,8 @@ MaybeObject* JSObject::AddFastProperty(Name* name,
|
||||
int index = map()->NextFreePropertyIndex();
|
||||
|
||||
// Allocate new instance descriptors with (name, index) added
|
||||
Representation representation = IsJSContextExtensionObject()
|
||||
? Representation::Tagged() : value->OptimalRepresentation();
|
||||
if (IsJSContextExtensionObject()) value_type = FORCE_TAGGED;
|
||||
Representation representation = value->OptimalRepresentation(value_type);
|
||||
|
||||
FieldDescriptor new_field(name, index, attributes, representation);
|
||||
|
||||
@ -1961,7 +1962,8 @@ MaybeObject* JSObject::AddProperty(Name* name,
|
||||
PropertyAttributes attributes,
|
||||
StrictModeFlag strict_mode,
|
||||
JSReceiver::StoreFromKeyed store_mode,
|
||||
ExtensibilityCheck extensibility_check) {
|
||||
ExtensibilityCheck extensibility_check,
|
||||
ValueType value_type) {
|
||||
ASSERT(!IsJSGlobalProxy());
|
||||
Map* map_of_this = map();
|
||||
Heap* heap = GetHeap();
|
||||
@ -1988,7 +1990,8 @@ MaybeObject* JSObject::AddProperty(Name* name,
|
||||
JSFunction::cast(value),
|
||||
attributes);
|
||||
} else {
|
||||
result = AddFastProperty(name, value, attributes, store_mode);
|
||||
result = AddFastProperty(
|
||||
name, value, attributes, store_mode, value_type);
|
||||
}
|
||||
} else {
|
||||
// Normalize the object to prevent very large instance descriptors.
|
||||
@ -2272,7 +2275,7 @@ bool Map::InstancesNeedRewriting(Map* target,
|
||||
int limit = NumberOfOwnDescriptors();
|
||||
for (int i = 0; i < limit; i++) {
|
||||
if (new_desc->GetDetails(i).representation().IsDouble() &&
|
||||
old_desc->GetDetails(i).representation().IsSmi()) {
|
||||
!old_desc->GetDetails(i).representation().IsDouble()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -2343,8 +2346,9 @@ MaybeObject* JSObject::MigrateToMap(Map* new_map) {
|
||||
? old_descriptors->GetValue(i)
|
||||
: RawFastPropertyAt(old_descriptors->GetFieldIndex(i));
|
||||
if (FLAG_track_double_fields &&
|
||||
old_details.representation().IsSmi() &&
|
||||
!old_details.representation().IsDouble() &&
|
||||
details.representation().IsDouble()) {
|
||||
if (old_details.representation().IsNone()) value = Smi::FromInt(0);
|
||||
// Objects must be allocated in the old object space, since the
|
||||
// overall number of HeapNumbers needed for the conversion might
|
||||
// exceed the capacity of new space, and we would fail repeatedly
|
||||
@ -2397,7 +2401,7 @@ MaybeObject* JSObject::GeneralizeFieldRepresentation(
|
||||
MaybeObject* maybe_new_map =
|
||||
map()->GeneralizeRepresentation(modify_index, new_representation);
|
||||
if (!maybe_new_map->To(&new_map)) return maybe_new_map;
|
||||
ASSERT(map() != new_map || new_map->FindRootMap()->is_deprecated());
|
||||
if (map() == new_map) return this;
|
||||
|
||||
return MigrateToMap(new_map);
|
||||
}
|
||||
@ -2574,10 +2578,21 @@ MaybeObject* Map::GeneralizeRepresentation(int modify_index,
|
||||
Representation old_representation =
|
||||
old_descriptors->GetDetails(modify_index).representation();
|
||||
|
||||
if (old_representation.IsNone()) {
|
||||
UNREACHABLE();
|
||||
// It's fine to transition from None to anything but double without any
|
||||
// modification to the object, because the default uninitialized value for
|
||||
// representation None can be overwritten by both smi and tagged values.
|
||||
// Doubles, however, would require a box allocation.
|
||||
if (old_representation.IsNone() &&
|
||||
!new_representation.IsNone() &&
|
||||
!new_representation.IsDouble()) {
|
||||
if (FLAG_trace_generalization) {
|
||||
PrintF("initializing representation %i: %p -> %s\n",
|
||||
modify_index,
|
||||
static_cast<void*>(this),
|
||||
new_representation.Mnemonic());
|
||||
}
|
||||
old_descriptors->SetRepresentation(modify_index, new_representation);
|
||||
return this;
|
||||
return old_map;
|
||||
}
|
||||
|
||||
int descriptors = old_map->NumberOfOwnDescriptors();
|
||||
@ -2603,7 +2618,7 @@ MaybeObject* Map::GeneralizeRepresentation(int modify_index,
|
||||
updated_descriptors->GetDetails(modify_index).representation();
|
||||
if (new_representation.fits_into(updated_representation)) {
|
||||
if (FLAG_trace_generalization &&
|
||||
!(modify_index == 0 && new_representation.IsSmi())) {
|
||||
!(modify_index == 0 && new_representation.IsNone())) {
|
||||
PropertyDetails old_details = old_descriptors->GetDetails(modify_index);
|
||||
PrintF("migrating to existing map %p(%s) -> %p(%s)\n",
|
||||
static_cast<void*>(this),
|
||||
@ -2641,7 +2656,7 @@ MaybeObject* Map::GeneralizeRepresentation(int modify_index,
|
||||
old_descriptors->GetKey(descriptor), new_descriptors);
|
||||
|
||||
if (FLAG_trace_generalization &&
|
||||
!(modify_index == 0 && new_representation.IsSmi())) {
|
||||
!(modify_index == 0 && new_representation.IsNone())) {
|
||||
PrintF("migrating to new map %i: %p(%s) -> %p(%s) (%i steps)\n",
|
||||
modify_index,
|
||||
static_cast<void*>(this),
|
||||
@ -3933,10 +3948,12 @@ Handle<Object> JSObject::SetLocalPropertyIgnoreAttributes(
|
||||
Handle<JSObject> object,
|
||||
Handle<Name> key,
|
||||
Handle<Object> value,
|
||||
PropertyAttributes attributes) {
|
||||
PropertyAttributes attributes,
|
||||
ValueType value_type) {
|
||||
CALL_HEAP_FUNCTION(
|
||||
object->GetIsolate(),
|
||||
object->SetLocalPropertyIgnoreAttributes(*key, *value, attributes),
|
||||
object->SetLocalPropertyIgnoreAttributes(
|
||||
*key, *value, attributes, value_type),
|
||||
Object);
|
||||
}
|
||||
|
||||
@ -3944,7 +3961,8 @@ Handle<Object> JSObject::SetLocalPropertyIgnoreAttributes(
|
||||
MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
|
||||
Name* name_raw,
|
||||
Object* value_raw,
|
||||
PropertyAttributes attributes) {
|
||||
PropertyAttributes attributes,
|
||||
ValueType value_type) {
|
||||
// Make sure that the top context does not change when doing callbacks or
|
||||
// interceptor calls.
|
||||
AssertNoContextChange ncc;
|
||||
@ -3970,13 +3988,16 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
|
||||
return JSObject::cast(proto)->SetLocalPropertyIgnoreAttributes(
|
||||
name_raw,
|
||||
value_raw,
|
||||
attributes);
|
||||
attributes,
|
||||
value_type);
|
||||
}
|
||||
|
||||
// Check for accessor in prototype chain removed here in clone.
|
||||
if (!lookup.IsFound()) {
|
||||
// Neither properties nor transitions found.
|
||||
return AddProperty(name_raw, value_raw, attributes, kNonStrictMode);
|
||||
return AddProperty(
|
||||
name_raw, value_raw, attributes, kNonStrictMode,
|
||||
MAY_BE_STORE_FROM_KEYED, PERFORM_EXTENSIBILITY_CHECK, value_type);
|
||||
}
|
||||
|
||||
// From this point on everything needs to be handlified.
|
||||
@ -4003,9 +4024,11 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
|
||||
}
|
||||
case FIELD: {
|
||||
Representation representation = lookup.representation();
|
||||
if (!value->FitsRepresentation(representation)) {
|
||||
Representation value_representation =
|
||||
value->OptimalRepresentation(value_type);
|
||||
if (!value_representation.fits_into(representation)) {
|
||||
MaybeObject* maybe_failure = self->GeneralizeFieldRepresentation(
|
||||
lookup.GetDescriptorIndex(), value->OptimalRepresentation());
|
||||
lookup.GetDescriptorIndex(), value_representation);
|
||||
if (maybe_failure->IsFailure()) return maybe_failure;
|
||||
DescriptorArray* desc = self->map()->instance_descriptors();
|
||||
int descriptor = lookup.GetDescriptorIndex();
|
||||
@ -4046,9 +4069,11 @@ MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
|
||||
if (details.type() == FIELD) {
|
||||
if (attributes == details.attributes()) {
|
||||
Representation representation = details.representation();
|
||||
if (!value->FitsRepresentation(representation)) {
|
||||
Representation value_representation =
|
||||
value->OptimalRepresentation(value_type);
|
||||
if (!value_representation.fits_into(representation)) {
|
||||
MaybeObject* maybe_map = transition_map->GeneralizeRepresentation(
|
||||
descriptor, value->OptimalRepresentation());
|
||||
descriptor, value_representation);
|
||||
if (!maybe_map->To(&transition_map)) return maybe_map;
|
||||
Object* back = transition_map->GetBackPointer();
|
||||
if (back->IsMap()) {
|
||||
|
@ -869,6 +869,7 @@ class MaybeObject BASE_EMBEDDED {
|
||||
inline bool IsOutOfMemory();
|
||||
inline bool IsException();
|
||||
INLINE(bool IsTheHole());
|
||||
INLINE(bool IsUninitialized());
|
||||
inline bool ToObject(Object** obj) {
|
||||
if (IsFailure()) return false;
|
||||
*obj = reinterpret_cast<Object*>(this);
|
||||
@ -1046,6 +1047,7 @@ class Object : public MaybeObject {
|
||||
INLINE(bool IsUndefined());
|
||||
INLINE(bool IsNull());
|
||||
INLINE(bool IsTheHole()); // Shadows MaybeObject's implementation.
|
||||
INLINE(bool IsUninitialized());
|
||||
INLINE(bool IsTrue());
|
||||
INLINE(bool IsFalse());
|
||||
inline bool IsArgumentsMarker();
|
||||
@ -1060,16 +1062,24 @@ class Object : public MaybeObject {
|
||||
bool ToInt32(int32_t* value);
|
||||
bool ToUint32(uint32_t* value);
|
||||
|
||||
inline Representation OptimalRepresentation() {
|
||||
if (FLAG_track_fields && IsSmi()) {
|
||||
// Indicates whether OptimalRepresentation can do its work, or whether it
|
||||
// always has to return Representation::Tagged().
|
||||
enum ValueType {
|
||||
OPTIMAL_REPRESENTATION,
|
||||
FORCE_TAGGED
|
||||
};
|
||||
|
||||
inline Representation OptimalRepresentation(
|
||||
ValueType type = OPTIMAL_REPRESENTATION) {
|
||||
if (!FLAG_track_fields) return Representation::Tagged();
|
||||
if (type == FORCE_TAGGED) return Representation::Tagged();
|
||||
if (IsSmi()) {
|
||||
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.
|
||||
} else if (FLAG_track_computed_fields && IsUninitialized()) {
|
||||
return Representation::None();
|
||||
} else if (FLAG_track_heap_object_fields) {
|
||||
ASSERT(IsHeapObject());
|
||||
return Representation::HeapObject();
|
||||
} else {
|
||||
@ -1078,7 +1088,9 @@ class Object : public MaybeObject {
|
||||
}
|
||||
|
||||
inline bool FitsRepresentation(Representation representation) {
|
||||
if (FLAG_track_fields && representation.IsSmi()) {
|
||||
if (FLAG_track_fields && representation.IsNone()) {
|
||||
return false;
|
||||
} else if (FLAG_track_fields && representation.IsSmi()) {
|
||||
return IsSmi();
|
||||
} else if (FLAG_track_double_fields && representation.IsDouble()) {
|
||||
return IsNumber();
|
||||
@ -1827,7 +1839,8 @@ class JSObject: public JSReceiver {
|
||||
Handle<JSObject> object,
|
||||
Handle<Name> key,
|
||||
Handle<Object> value,
|
||||
PropertyAttributes attributes);
|
||||
PropertyAttributes attributes,
|
||||
ValueType value_type = OPTIMAL_REPRESENTATION);
|
||||
|
||||
static inline Handle<String> ExpectedTransitionKey(Handle<Map> map);
|
||||
static inline Handle<Map> ExpectedTransitionTarget(Handle<Map> map);
|
||||
@ -1854,7 +1867,8 @@ class JSObject: public JSReceiver {
|
||||
MUST_USE_RESULT MaybeObject* SetLocalPropertyIgnoreAttributes(
|
||||
Name* key,
|
||||
Object* value,
|
||||
PropertyAttributes attributes);
|
||||
PropertyAttributes attributes,
|
||||
ValueType value_type = OPTIMAL_REPRESENTATION);
|
||||
|
||||
// Retrieve a value in a normalized object given a lookup result.
|
||||
// Handles the special representation of JS global objects.
|
||||
@ -2216,7 +2230,8 @@ class JSObject: public JSReceiver {
|
||||
Name* name,
|
||||
Object* value,
|
||||
PropertyAttributes attributes,
|
||||
StoreFromKeyed store_mode = MAY_BE_STORE_FROM_KEYED);
|
||||
StoreFromKeyed store_mode = MAY_BE_STORE_FROM_KEYED,
|
||||
ValueType value_type = OPTIMAL_REPRESENTATION);
|
||||
|
||||
// Add a property to a slow-case object.
|
||||
MUST_USE_RESULT MaybeObject* AddSlowProperty(Name* name,
|
||||
@ -2230,7 +2245,8 @@ class JSObject: public JSReceiver {
|
||||
PropertyAttributes attributes,
|
||||
StrictModeFlag strict_mode,
|
||||
StoreFromKeyed store_mode = MAY_BE_STORE_FROM_KEYED,
|
||||
ExtensibilityCheck extensibility_check = PERFORM_EXTENSIBILITY_CHECK);
|
||||
ExtensibilityCheck extensibility_check = PERFORM_EXTENSIBILITY_CHECK,
|
||||
ValueType value_type = OPTIMAL_REPRESENTATION);
|
||||
|
||||
// Convert the object to use the canonical dictionary
|
||||
// representation. If the object is expected to have additional properties
|
||||
@ -8483,7 +8499,8 @@ class Oddball: public HeapObject {
|
||||
static const byte kNull = 3;
|
||||
static const byte kArgumentMarker = 4;
|
||||
static const byte kUndefined = 5;
|
||||
static const byte kOther = 6;
|
||||
static const byte kUninitialized = 6;
|
||||
static const byte kOther = 7;
|
||||
|
||||
typedef FixedBodyDescriptor<kToStringOffset,
|
||||
kToNumberOffset + kPointerSize,
|
||||
|
@ -3593,7 +3593,7 @@ Expression* Parser::ParseArrayLiteral(bool* ok) {
|
||||
Handle<Object> boilerplate_value = GetBoilerplateValue(values->at(i));
|
||||
if (boilerplate_value->IsTheHole()) {
|
||||
is_holey = true;
|
||||
} else if (boilerplate_value->IsUndefined()) {
|
||||
} else if (boilerplate_value->IsUninitialized()) {
|
||||
is_simple = false;
|
||||
JSObject::SetOwnElement(
|
||||
array, i, handle(Smi::FromInt(0), isolate()), kNonStrictMode);
|
||||
@ -3693,7 +3693,7 @@ Handle<Object> Parser::GetBoilerplateValue(Expression* expression) {
|
||||
if (CompileTimeValue::IsCompileTimeValue(expression)) {
|
||||
return CompileTimeValue::GetValue(expression);
|
||||
}
|
||||
return isolate()->factory()->undefined_value();
|
||||
return isolate()->factory()->uninitialized_value();
|
||||
}
|
||||
|
||||
// Validation per 11.1.5 Object Initialiser
|
||||
@ -3804,13 +3804,17 @@ void Parser::BuildObjectLiteralConstantProperties(
|
||||
Handle<Object> key = property->key()->handle();
|
||||
Handle<Object> value = GetBoilerplateValue(property->value());
|
||||
|
||||
// Ensure objects with doubles are always treated as nested objects.
|
||||
// Ensure objects that may, at any point in time, contain fields with double
|
||||
// representation are always treated as nested objects. This is true for
|
||||
// computed fields (value is undefined), and smi and double literals
|
||||
// (value->IsNumber()).
|
||||
// TODO(verwaest): Remove once we can store them inline.
|
||||
if (FLAG_track_double_fields && value->IsNumber()) {
|
||||
if (FLAG_track_double_fields &&
|
||||
(value->IsNumber() || value->IsUninitialized())) {
|
||||
*may_store_doubles = true;
|
||||
}
|
||||
|
||||
is_simple_acc = is_simple_acc && !value->IsUndefined();
|
||||
is_simple_acc = is_simple_acc && !value->IsUninitialized();
|
||||
|
||||
// Keep track of the number of elements in the object literal and
|
||||
// the largest element index. If the largest element index is
|
||||
|
@ -113,7 +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();
|
||||
if (IsHeapObject()) return other.IsDouble() || other.IsNone();
|
||||
return kind_ > other.kind_;
|
||||
}
|
||||
|
||||
@ -213,6 +213,7 @@ class PropertyDetails BASE_EMBEDDED {
|
||||
}
|
||||
|
||||
Representation representation() {
|
||||
ASSERT(type() != NORMAL);
|
||||
return DecodeRepresentation(RepresentationField::decode(value_));
|
||||
}
|
||||
|
||||
|
@ -203,6 +203,8 @@ class LookupResult BASE_EMBEDDED {
|
||||
}
|
||||
|
||||
bool CanHoldValue(Handle<Object> value) {
|
||||
if (IsNormal()) return true;
|
||||
ASSERT(!IsTransition());
|
||||
return value->FitsRepresentation(details_.representation());
|
||||
}
|
||||
|
||||
|
@ -325,3 +325,83 @@ df3.first_double = 1.7;
|
||||
df3.second_function = some_function2;
|
||||
df1.first_double = 10;
|
||||
read_first_double(df1);
|
||||
|
||||
// Test boilerplates with computed values.
|
||||
function none_boilerplate(a) {
|
||||
return {"a_none":a};
|
||||
}
|
||||
%OptimizeFunctionOnNextCall(none_boilerplate);
|
||||
var none_double1 = none_boilerplate(1.7);
|
||||
var none_double2 = none_boilerplate(1.9);
|
||||
assertTrue(%HaveSameMap(none_double1, none_double2));
|
||||
assertEquals(1.7, none_double1.a_none);
|
||||
assertEquals(1.9, none_double2.a_none);
|
||||
none_double2.a_none = 3.5;
|
||||
var none_double1 = none_boilerplate(1.7);
|
||||
var none_double2 = none_boilerplate(3.5);
|
||||
|
||||
function none_to_smi(a) {
|
||||
return {"a_smi":a};
|
||||
}
|
||||
|
||||
var none_smi1 = none_to_smi(1);
|
||||
var none_smi2 = none_to_smi(2);
|
||||
%OptimizeFunctionOnNextCall(none_to_smi);
|
||||
var none_smi3 = none_to_smi(3);
|
||||
assertTrue(%HaveSameMap(none_smi1, none_smi2));
|
||||
assertTrue(%HaveSameMap(none_smi1, none_smi3));
|
||||
assertEquals(1, none_smi1.a_smi);
|
||||
assertEquals(2, none_smi2.a_smi);
|
||||
assertEquals(3, none_smi3.a_smi);
|
||||
|
||||
function none_to_double(a) {
|
||||
return {"a_double":a};
|
||||
}
|
||||
|
||||
var none_to_double1 = none_to_double(1.5);
|
||||
var none_to_double2 = none_to_double(2.8);
|
||||
%OptimizeFunctionOnNextCall(none_to_double);
|
||||
var none_to_double3 = none_to_double(3.7);
|
||||
assertTrue(%HaveSameMap(none_to_double1, none_to_double2));
|
||||
assertTrue(%HaveSameMap(none_to_double1, none_to_double3));
|
||||
assertEquals(1.5, none_to_double1.a_double);
|
||||
assertEquals(2.8, none_to_double2.a_double);
|
||||
assertEquals(3.7, none_to_double3.a_double);
|
||||
|
||||
function none_to_object(a) {
|
||||
return {"an_object":a};
|
||||
}
|
||||
|
||||
var none_to_object1 = none_to_object(true);
|
||||
var none_to_object2 = none_to_object(false);
|
||||
%OptimizeFunctionOnNextCall(none_to_object);
|
||||
var none_to_object3 = none_to_object(3.7);
|
||||
assertTrue(%HaveSameMap(none_to_object1, none_to_object2));
|
||||
assertTrue(%HaveSameMap(none_to_object1, none_to_object3));
|
||||
assertEquals(true, none_to_object1.an_object);
|
||||
assertEquals(false, none_to_object2.an_object);
|
||||
assertEquals(3.7, none_to_object3.an_object);
|
||||
|
||||
function double_to_object(a) {
|
||||
var o = {"d_to_h":1.8};
|
||||
o.d_to_h = a;
|
||||
return o;
|
||||
}
|
||||
|
||||
var dh1 = double_to_object(true);
|
||||
var dh2 = double_to_object(false);
|
||||
assertTrue(%HaveSameMap(dh1, dh2));
|
||||
assertEquals(true, dh1.d_to_h);
|
||||
assertEquals(false, dh2.d_to_h);
|
||||
|
||||
function smi_to_object(a) {
|
||||
var o = {"s_to_t":18};
|
||||
o.s_to_t = a;
|
||||
return o;
|
||||
}
|
||||
|
||||
var st1 = smi_to_object(true);
|
||||
var st2 = smi_to_object(false);
|
||||
assertTrue(%HaveSameMap(st1, st2));
|
||||
assertEquals(true, st1.s_to_t);
|
||||
assertEquals(false, st2.s_to_t);
|
||||
|
Loading…
Reference in New Issue
Block a user