Object* value,
PropertyAttributes attributes,
StoreFromKeyed store_mode,
- ValueType value_type,
- TransitionFlag flag) {
+ ValueType value_type) {
ASSERT(!IsJSGlobalProxy());
ASSERT(DescriptorArray::kNotFound ==
map()->instance_descriptors()->Search(
// hidden strings) and is not a real identifier.
// Normalize the object if it will have too many fast properties.
Isolate* isolate = GetHeap()->isolate();
- if ((!name->IsSymbol() &&
- !IsIdentifier(isolate->unicode_cache(), name) &&
- name != isolate->heap()->hidden_string()) ||
- TooManyFastProperties(store_mode)) {
- MaybeObject* maybe_failure =
+ if ((!name->IsSymbol() && !IsIdentifier(isolate->unicode_cache(), name)
+ && name != isolate->heap()->hidden_string()) ||
+ (map()->unused_property_fields() == 0 &&
+ TooManyFastProperties(properties()->length(), store_mode))) {
+ Object* obj;
+ MaybeObject* maybe_obj =
NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
- if (maybe_failure->IsFailure()) return maybe_failure;
+ if (!maybe_obj->ToObject(&obj)) return maybe_obj;
+
return AddSlowProperty(name, value, attributes);
}
if (!maybe_values->To(&values)) return maybe_values;
}
+ TransitionFlag flag = INSERT_TRANSITION;
+
Heap* heap = isolate->heap();
Object* storage;
MaybeObject* JSObject::AddConstantProperty(
Name* name,
Object* constant,
- PropertyAttributes attributes,
- TransitionFlag initial_flag) {
+ PropertyAttributes attributes) {
// Allocate new instance descriptors with (name, constant) added
ConstantDescriptor d(name, constant, attributes);
// attributes.
attributes != NONE)
? OMIT_TRANSITION
- : initial_flag;
+ : INSERT_TRANSITION;
Map* new_map;
MaybeObject* maybe_new_map = map()->CopyAddDescriptor(&d, flag);
JSReceiver::StoreFromKeyed store_mode,
ExtensibilityCheck extensibility_check,
ValueType value_type,
- StoreMode mode,
- TransitionFlag transition_flag) {
+ StoreMode mode) {
ASSERT(!IsJSGlobalProxy());
Map* map_of_this = map();
Heap* heap = GetHeap();
// !value->IsTheHole() &&
// !value->IsConsString()) {
if (value->IsJSFunction()) {
- result = AddConstantProperty(name, value, attributes, transition_flag);
+ result = AddConstantProperty(name, value, attributes);
} else {
result = AddFastProperty(
- name, value, attributes, store_mode, value_type, transition_flag);
+ name, value, attributes, store_mode, value_type);
}
} else {
// Normalize the object to prevent very large instance descriptors.
}
+MaybeObject* JSObject::ConvertDescriptorToField(Name* name,
+ Object* new_value,
+ PropertyAttributes attributes,
+ TransitionFlag flag) {
+ if (map()->unused_property_fields() == 0 &&
+ TooManyFastProperties(properties()->length(), MAY_BE_STORE_FROM_KEYED)) {
+ Object* obj;
+ MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0);
+ if (!maybe_obj->ToObject(&obj)) return maybe_obj;
+ return ReplaceSlowProperty(name, new_value, attributes);
+ }
+
+ Representation representation = IsJSContextExtensionObject()
+ ? Representation::Tagged() : new_value->OptimalRepresentation();
+ int index = map()->NextFreePropertyIndex();
+ FieldDescriptor new_field(name, index, attributes, representation);
+
+ // Make a new map for the object.
+ Map* new_map;
+ MaybeObject* maybe_new_map = map()->CopyInsertDescriptor(&new_field, flag);
+ if (!maybe_new_map->To(&new_map)) return maybe_new_map;
+
+ // Make new properties array if necessary.
+ FixedArray* new_properties = NULL;
+ int new_unused_property_fields = map()->unused_property_fields() - 1;
+ if (map()->unused_property_fields() == 0) {
+ new_unused_property_fields = kFieldsAdded - 1;
+ MaybeObject* maybe_new_properties =
+ properties()->CopySize(properties()->length() + kFieldsAdded);
+ if (!maybe_new_properties->To(&new_properties)) return maybe_new_properties;
+ }
+
+ Heap* heap = GetHeap();
+ Object* storage;
+ MaybeObject* maybe_storage =
+ new_value->AllocateNewStorageFor(heap, representation);
+ if (!maybe_storage->To(&storage)) return maybe_storage;
+
+ // Update pointers to commit changes.
+ // Object points to the new map.
+ new_map->set_unused_property_fields(new_unused_property_fields);
+ set_map(new_map);
+ if (new_properties != NULL) {
+ set_properties(new_properties);
+ }
+ FastPropertyAtPut(index, storage);
+ return new_value;
+}
+
+
const char* Representation::Mnemonic() const {
switch (kind_) {
case kNone: return "v";
PropertyDetails details = new_descriptors->GetDetails(i);
if (details.type() != FIELD) continue;
PropertyDetails old_details = old_descriptors->GetDetails(i);
- if (old_details.type() == CALLBACKS) {
- ASSERT(details.representation().IsTagged());
- continue;
- }
ASSERT(old_details.type() == CONSTANT ||
old_details.type() == FIELD);
Object* value = old_details.type() == CONSTANT
PropertyDetails details = descriptors->GetDetails(descriptor);
if (details.type() == CALLBACKS || attributes != details.attributes()) {
- // AddProperty will either normalize the object, or create a new fast copy
- // of the map. If we get a fast copy of the map, all field representations
- // will be tagged since the transition is omitted.
- return lookup->holder()->AddProperty(
- *name, *value, attributes, kNonStrictMode,
- JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED,
- JSReceiver::OMIT_EXTENSIBILITY_CHECK,
- JSObject::FORCE_TAGGED, FORCE_FIELD, OMIT_TRANSITION);
+ return lookup->holder()->ConvertDescriptorToField(
+ *name, *value, attributes);
}
// Keep the target CONSTANT if the same value is stored.
}
-static MaybeObject* ConvertAndSetLocalProperty(
- LookupResult* lookup,
- Name* name,
- Object* value,
- PropertyAttributes attributes) {
- JSObject* object = lookup->holder();
- if (object->TooManyFastProperties()) {
- MaybeObject* maybe_failure = object->NormalizeProperties(
- CLEAR_INOBJECT_PROPERTIES, 0);
- if (maybe_failure->IsFailure()) return maybe_failure;
- }
-
- if (!object->HasFastProperties()) {
- return object->ReplaceSlowProperty(name, value, attributes);
- }
-
- int descriptor_index = lookup->GetDescriptorIndex();
- MaybeObject* maybe_failure = object->GeneralizeFieldRepresentation(
- descriptor_index, Representation::Tagged(), FORCE_FIELD);
- if (maybe_failure->IsFailure()) return maybe_failure;
-
- DescriptorArray* descriptors = object->map()->instance_descriptors();
- int index = descriptors->GetDetails(descriptor_index).field_index();
- object->FastPropertyAtPut(index, value);
- return value;
-}
-
-
MaybeObject* JSObject::SetLocalPropertyIgnoreAttributes(
Name* name_raw,
Object* value_raw,
if (value->IsUninitialized()) break;
result = SetPropertyToField(&lookup, name, value);
break;
- case INTERCEPTOR:
- self->LocalLookupRealNamedProperty(*name, &lookup);
- if (lookup.IsFound()) {
- if (lookup.IsPropertyCallbacks()) {
- result = ConvertAndSetLocalProperty(
- &lookup, *name, *value, attributes);
- } else if (lookup.IsNormal()) {
- result = self->ReplaceSlowProperty(*name, *value, attributes);
- } else {
- result = SetPropertyToField(&lookup, name, value);
- }
- } else {
- result = self->AddProperty(
- *name, *value, attributes, kNonStrictMode, MAY_BE_STORE_FROM_KEYED,
- extensibility_check, value_type, mode);
- }
- break;
case CALLBACKS:
- result = ConvertAndSetLocalProperty(&lookup, *name, *value, attributes);
+ case INTERCEPTOR:
+ // Override callback in clone
+ result = self->ConvertDescriptorToField(*name, *value, attributes);
break;
case TRANSITION:
result = SetPropertyUsingTransition(&lookup, name, value, attributes);
MUST_USE_RESULT MaybeObject* AddConstantProperty(
Name* name,
Object* constant,
- PropertyAttributes attributes,
- TransitionFlag flag);
+ PropertyAttributes attributes);
MUST_USE_RESULT MaybeObject* ReplaceSlowProperty(
Name* name,
MUST_USE_RESULT MaybeObject* TransitionElementsKind(ElementsKind to_kind);
MUST_USE_RESULT MaybeObject* UpdateAllocationSite(ElementsKind to_kind);
+ // Converts a descriptor of any other type to a real field, backed by the
+ // properties array.
+ MUST_USE_RESULT MaybeObject* ConvertDescriptorToField(
+ Name* name,
+ Object* new_value,
+ PropertyAttributes attributes,
+ TransitionFlag flag = OMIT_TRANSITION);
+
MUST_USE_RESULT MaybeObject* MigrateToMap(Map* new_map);
MUST_USE_RESULT MaybeObject* GeneralizeFieldRepresentation(
int modify_index,
Object* value,
PropertyAttributes attributes,
StoreFromKeyed store_mode = MAY_BE_STORE_FROM_KEYED,
- ValueType value_type = OPTIMAL_REPRESENTATION,
- TransitionFlag flag = INSERT_TRANSITION);
+ ValueType value_type = OPTIMAL_REPRESENTATION);
// Add a property to a slow-case object.
MUST_USE_RESULT MaybeObject* AddSlowProperty(Name* name,
StoreFromKeyed store_mode = MAY_BE_STORE_FROM_KEYED,
ExtensibilityCheck extensibility_check = PERFORM_EXTENSIBILITY_CHECK,
ValueType value_type = OPTIMAL_REPRESENTATION,
- StoreMode mode = ALLOW_AS_CONSTANT,
- TransitionFlag flag = INSERT_TRANSITION);
+ StoreMode mode = ALLOW_AS_CONSTANT);
// Convert the object to use the canonical dictionary
// representation. If the object is expected to have additional properties
// Maximal number of fast properties for the JSObject. Used to
// restrict the number of map transitions to avoid an explosion in
// the number of maps for objects used as dictionaries.
- inline bool TooManyFastProperties(
- StoreFromKeyed store_mode = MAY_BE_STORE_FROM_KEYED);
+ inline bool TooManyFastProperties(int properties, StoreFromKeyed store_mode);
// Maximal number of elements (numbered 0 .. kMaxElementCount - 1).
// Also maximal value of JSArray's length property.