Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(183)

Unified Diff: src/objects.cc

Issue 392243002: Reimplement SetProperty using the LookupIterator (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/objects.h ('k') | src/objects-inl.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/objects.cc
diff --git a/src/objects.cc b/src/objects.cc
index b423560fdff5c394cdc81487709dd8c628d2e3a4..caae61444dd067ae3d379542c14d739d6d29600f 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -462,12 +462,9 @@ MaybeHandle<Object> Object::GetPropertyWithAccessor(Handle<Object> receiver,
}
-MaybeHandle<Object> Object::SetPropertyWithCallback(Handle<Object> receiver,
- Handle<Name> name,
- Handle<Object> value,
- Handle<JSObject> holder,
- Handle<Object> structure,
- StrictMode strict_mode) {
+MaybeHandle<Object> Object::SetPropertyWithAccessor(
+ Handle<Object> receiver, Handle<Name> name, Handle<Object> value,
+ Handle<JSObject> holder, Handle<Object> structure, StrictMode strict_mode) {
Isolate* isolate = name->GetIsolate();
// We should never get here to initialize a const with the hole
@@ -605,48 +602,33 @@ PropertyAttributes JSObject::GetPropertyAttributesWithFailedAccessCheck(
}
-static bool FindAllCanWriteHolder(LookupResult* result,
- Handle<Name> name,
- bool check_prototype) {
- if (result->IsInterceptor()) {
- result->holder()->LookupOwnRealNamedProperty(name, result);
- }
-
- while (result->IsProperty()) {
- if (result->type() == CALLBACKS) {
- Object* callback_obj = result->GetCallbackObject();
- if (callback_obj->IsAccessorInfo()) {
- if (AccessorInfo::cast(callback_obj)->all_can_write()) return true;
+static bool FindAllCanWriteHolder(LookupIterator* it) {
+ it->skip_interceptor();
+ it->skip_access_check();
+ for (; it->IsFound(); it->Next()) {
+ if (it->state() == LookupIterator::PROPERTY && it->HasProperty() &&
+ it->property_kind() == LookupIterator::ACCESSOR) {
+ Handle<Object> accessors = it->GetAccessors();
+ if (accessors->IsAccessorInfo()) {
+ if (AccessorInfo::cast(*accessors)->all_can_write()) return true;
}
}
- if (!check_prototype) break;
- result->holder()->LookupRealNamedPropertyInPrototypes(name, result);
}
return false;
}
MaybeHandle<Object> JSObject::SetPropertyWithFailedAccessCheck(
- Handle<JSObject> object,
- LookupResult* result,
- Handle<Name> name,
- Handle<Object> value,
- bool check_prototype,
- StrictMode strict_mode) {
- if (check_prototype && !result->IsProperty()) {
- object->LookupRealNamedPropertyInPrototypes(name, result);
- }
-
- if (FindAllCanWriteHolder(result, name, check_prototype)) {
- Handle<JSObject> holder(result->holder());
- Handle<Object> callbacks(result->GetCallbackObject(), result->isolate());
- return SetPropertyWithCallback(
- object, name, value, holder, callbacks, strict_mode);
+ LookupIterator* it, Handle<Object> value, StrictMode strict_mode) {
+ Handle<JSObject> checked = Handle<JSObject>::cast(it->GetHolder());
+ if (FindAllCanWriteHolder(it)) {
+ return SetPropertyWithAccessor(it->GetReceiver(), it->name(), value,
+ it->GetHolder(), it->GetAccessors(),
+ strict_mode);
}
- Isolate* isolate = object->GetIsolate();
- isolate->ReportFailedAccessCheck(object, v8::ACCESS_SET);
- RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
+ it->isolate()->ReportFailedAccessCheck(checked, v8::ACCESS_SET);
+ RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object);
return value;
}
@@ -1835,7 +1817,7 @@ void JSObject::AddFastProperty(Handle<JSObject> object,
if (value->IsJSFunction()) {
maybe_map = Map::CopyWithConstant(
handle(object->map()), name, value, attributes, flag);
- } else if (!object->TooManyFastProperties(store_mode)) {
+ } else if (!object->map()->TooManyFastProperties(store_mode)) {
Isolate* isolate = object->GetIsolate();
Representation representation = value->OptimalRepresentation();
maybe_map = Map::CopyWithField(
@@ -1969,23 +1951,6 @@ void JSObject::EnqueueChangeRecord(Handle<JSObject> object,
}
-MaybeHandle<Object> JSObject::SetPropertyPostInterceptor(
- Handle<JSObject> object,
- Handle<Name> name,
- Handle<Object> value,
- StrictMode strict_mode) {
- // Check own property, ignore interceptor.
- Isolate* isolate = object->GetIsolate();
- LookupResult result(isolate);
- object->LookupOwnRealNamedProperty(name, &result);
- if (!result.IsFound()) {
- object->map()->LookupTransition(*object, *name, &result);
- }
- return SetPropertyForResult(object, &result, name, value, strict_mode,
- MAY_BE_STORE_FROM_KEYED);
-}
-
-
static void ReplaceSlowProperty(Handle<JSObject> object,
Handle<Name> name,
Handle<Object> value,
@@ -2972,29 +2937,28 @@ MaybeHandle<Map> Map::CurrentMapForDeprecatedInternal(Handle<Map> old_map) {
}
-MaybeHandle<Object> JSObject::SetPropertyWithInterceptor(
- Handle<JSObject> object,
- Handle<Name> name,
- Handle<Object> value,
- StrictMode strict_mode) {
+MaybeHandle<Object> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
+ Handle<Object> value) {
// TODO(rossberg): Support symbols in the API.
- if (name->IsSymbol()) return value;
- Isolate* isolate = object->GetIsolate();
- Handle<String> name_string = Handle<String>::cast(name);
- Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor());
- if (!interceptor->setter()->IsUndefined()) {
- LOG(isolate,
- ApiNamedPropertyAccess("interceptor-named-set", *object, *name));
- PropertyCallbackArguments args(
- isolate, interceptor->data(), *object, *object);
- v8::NamedPropertySetterCallback setter =
- v8::ToCData<v8::NamedPropertySetterCallback>(interceptor->setter());
- v8::Handle<v8::Value> result = args.Call(
- setter, v8::Utils::ToLocal(name_string), v8::Utils::ToLocal(value));
- RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
- if (!result.IsEmpty()) return value;
- }
- return SetPropertyPostInterceptor(object, name, value, strict_mode);
+ if (it->name()->IsSymbol()) return value;
+
+ Handle<String> name_string = Handle<String>::cast(it->name());
+ Handle<JSObject> holder = it->GetHolder();
+ Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor());
+ if (interceptor->setter()->IsUndefined()) return MaybeHandle<Object>();
+
+ LOG(it->isolate(),
+ ApiNamedPropertyAccess("interceptor-named-set", *holder, *name_string));
+ PropertyCallbackArguments args(it->isolate(), interceptor->data(), *holder,
+ *holder);
+ v8::NamedPropertySetterCallback setter =
+ v8::ToCData<v8::NamedPropertySetterCallback>(interceptor->setter());
+ v8::Handle<v8::Value> result = args.Call(
+ setter, v8::Utils::ToLocal(name_string), v8::Utils::ToLocal(value));
+ RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object);
+ if (!result.IsEmpty()) return value;
+
+ return MaybeHandle<Object>();
}
@@ -3003,12 +2967,194 @@ MaybeHandle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object,
Handle<Object> value,
StrictMode strict_mode,
StoreFromKeyed store_mode) {
- LookupResult result(object->GetIsolate());
- object->LookupOwn(name, &result, true);
- if (!result.IsFound()) {
- object->map()->LookupTransition(JSObject::cast(*object), *name, &result);
+ LookupIterator it(object, name);
+ return Object::SetProperty(&it, value, strict_mode, store_mode);
+}
+
+
+MaybeHandle<Object> Object::SetProperty(LookupIterator* it,
+ Handle<Object> value,
+ StrictMode strict_mode,
+ StoreFromKeyed store_mode) {
+ // Make sure that the top context does not change when doing callbacks or
+ // interceptor calls.
+ AssertNoContextChange ncc(it->isolate());
+
+ bool done = false;
+ for (; it->IsFound(); it->Next()) {
+ switch (it->state()) {
+ case LookupIterator::NOT_FOUND:
+ UNREACHABLE();
+
+ case LookupIterator::ACCESS_CHECK:
+ // TODO(verwaest): Remove the distinction. This is mostly bogus since we
+ // don't know whether we'll want to fetch attributes or call a setter
+ // until we find the property.
+ if (it->HasAccess(v8::ACCESS_SET)) break;
+ return JSObject::SetPropertyWithFailedAccessCheck(it, value,
+ strict_mode);
+
+ case LookupIterator::JSPROXY:
+ if (it->HolderIsReceiver()) {
+ return JSProxy::SetPropertyWithHandler(it->GetJSProxy(),
+ it->GetReceiver(), it->name(),
+ value, strict_mode);
+ } else {
+ // TODO(verwaest): Use the MaybeHandle to indicate result.
+ bool has_result = false;
+ MaybeHandle<Object> maybe_result =
+ JSProxy::SetPropertyViaPrototypesWithHandler(
+ it->GetJSProxy(), it->GetReceiver(), it->name(), value,
+ strict_mode, &has_result);
+ if (has_result) return maybe_result;
+ done = true;
+ }
+ break;
+
+ case LookupIterator::INTERCEPTOR:
+ if (it->HolderIsReceiver()) {
+ MaybeHandle<Object> maybe_result =
+ JSObject::SetPropertyWithInterceptor(it, value);
+ if (!maybe_result.is_null()) return maybe_result;
+ if (it->isolate()->has_pending_exception()) return maybe_result;
+ } else {
+ Maybe<PropertyAttributes> maybe_attributes =
+ JSObject::GetPropertyAttributesWithInterceptor(
+ it->GetHolder(), it->GetReceiver(), it->name());
+ RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(it->isolate(), Object);
+ done = maybe_attributes.has_value;
+ if (done && (maybe_attributes.value & READ_ONLY) != 0) {
+ return WriteToReadOnlyProperty(it, value, strict_mode);
+ }
+ }
+ break;
+
+ case LookupIterator::PROPERTY:
+ if (!it->HasProperty()) break;
+ if (it->property_details().IsReadOnly()) {
+ return WriteToReadOnlyProperty(it, value, strict_mode);
+ }
+ switch (it->property_kind()) {
+ case LookupIterator::ACCESSOR:
+ if (it->HolderIsReceiver() ||
+ !it->GetAccessors()->IsDeclaredAccessorInfo()) {
+ return SetPropertyWithAccessor(it->GetReceiver(), it->name(),
+ value, it->GetHolder(),
+ it->GetAccessors(), strict_mode);
+ }
+ break;
+ case LookupIterator::DATA:
+ if (it->HolderIsReceiver()) return SetDataProperty(it, value);
+ }
+ done = true;
+ break;
+ }
+
+ if (done) break;
}
- return SetProperty(object, &result, name, value, strict_mode, store_mode);
+
+ return AddDataProperty(it, value, NONE, strict_mode, store_mode);
+}
+
+
+MaybeHandle<Object> Object::WriteToReadOnlyProperty(LookupIterator* it,
+ Handle<Object> value,
+ StrictMode strict_mode) {
+ if (strict_mode != STRICT) return value;
+
+ Handle<Object> args[] = {it->name(), it->GetReceiver()};
+ Handle<Object> error = it->factory()->NewTypeError(
+ "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args)));
+ return it->isolate()->Throw<Object>(error);
+}
+
+
+MaybeHandle<Object> Object::SetDataProperty(LookupIterator* it,
+ Handle<Object> value) {
+ // Proxies are handled on the WithHandler path. Other non-JSObjects cannot
+ // have own properties.
+ Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
+
+ // Store on the holder which may be hidden behind the receiver.
+ ASSERT(it->HolderIsReceiver());
+
+ // Old value for the observation change record.
+ // Fetch before transforming the object since the encoding may become
+ // incompatible with what's cached in |it|.
+ bool is_observed =
+ receiver->map()->is_observed() &&
+ !it->name().is_identical_to(it->factory()->hidden_string());
+ MaybeHandle<Object> maybe_old;
+ if (is_observed) maybe_old = it->GetDataValue();
+
+ // Possibly migrate to the most up-to-date map that will be able to store
+ // |value| under it->name().
+ it->PrepareForDataProperty(value);
+
+ // Write the property value.
+ it->WriteDataValue(value);
+
+ // Send the change record if there are observers.
+ if (is_observed && !value->SameValue(*maybe_old.ToHandleChecked())) {
+ JSObject::EnqueueChangeRecord(receiver, "update", it->name(),
+ maybe_old.ToHandleChecked());
+ }
+
+ return value;
+}
+
+
+MaybeHandle<Object> Object::AddDataProperty(LookupIterator* it,
+ Handle<Object> value,
+ PropertyAttributes attributes,
+ StrictMode strict_mode,
+ StoreFromKeyed store_mode) {
+ ASSERT(!it->GetReceiver()->IsJSProxy());
+ // Transitions to data properties of value wrappers are not observable.
+ if (!it->GetReceiver()->IsJSObject()) return value;
+ Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
+
+ // If the receiver is a JSGlobalProxy, store on the prototype (JSGlobalObject)
+ // instead. If the prototype is Null, the proxy is detached.
+ if (receiver->IsJSGlobalProxy()) {
+ // Trying to assign to a detached proxy.
+ PrototypeIterator iter(it->isolate(), receiver);
+ if (iter.IsAtEnd()) return value;
+ receiver =
+ Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter));
+ }
+
+ if (!receiver->map()->is_extensible()) {
+ if (strict_mode == SLOPPY) return value;
+
+ Handle<Object> args[1] = {it->name()};
+ Handle<Object> error = it->factory()->NewTypeError(
+ "object_not_extensible", HandleVector(args, ARRAY_SIZE(args)));
+ return it->isolate()->Throw<Object>(error);
+ }
+
+ // Possibly migrate to the most up-to-date map that will be able to store
+ // |value| under it->name() with |attributes|.
+ it->TransitionToDataProperty(value, attributes, store_mode);
+
+ // TODO(verwaest): Encapsulate dictionary handling better.
+ if (receiver->map()->is_dictionary_map()) {
+ // TODO(verwaest): Probably should ensure this is done beforehand.
+ it->InternalizeName();
+ JSObject::AddSlowProperty(receiver, it->name(), value, attributes);
+ } else {
+ // Write the property value.
+ it->WriteDataValue(value);
+ }
+
+ // Send the change record if there are observers.
+ if (receiver->map()->is_observed() &&
+ !it->name().is_identical_to(it->factory()->hidden_string())) {
+ JSObject::EnqueueChangeRecord(receiver, "add", it->name(),
+ it->factory()->the_hole_value());
+ }
+
+ return value;
}
@@ -3049,66 +3195,6 @@ MaybeHandle<Object> JSObject::SetElementWithCallbackSetterInPrototypes(
}
-MaybeHandle<Object> JSObject::SetPropertyViaPrototypes(
- Handle<JSObject> object,
- Handle<Name> name,
- Handle<Object> value,
- StrictMode strict_mode,
- bool* done) {
- Isolate* isolate = object->GetIsolate();
-
- *done = false;
- // We could not find an own property, so let's check whether there is an
- // accessor that wants to handle the property, or whether the property is
- // read-only on the prototype chain.
- LookupResult result(isolate);
- object->LookupRealNamedPropertyInPrototypes(name, &result);
- if (result.IsFound()) {
- switch (result.type()) {
- case NORMAL:
- case FIELD:
- case CONSTANT:
- *done = result.IsReadOnly();
- break;
- case INTERCEPTOR: {
- LookupIterator it(object, name, handle(result.holder()));
- PropertyAttributes attr = GetPropertyAttributes(&it);
- *done = !!(attr & READ_ONLY);
- break;
- }
- case CALLBACKS: {
- *done = true;
- if (!result.IsReadOnly()) {
- Handle<Object> callback_object(result.GetCallbackObject(), isolate);
- return SetPropertyWithCallback(object, name, value,
- handle(result.holder()),
- callback_object, strict_mode);
- }
- break;
- }
- case HANDLER: {
- Handle<JSProxy> proxy(result.proxy());
- return JSProxy::SetPropertyViaPrototypesWithHandler(
- proxy, object, name, value, strict_mode, done);
- }
- case NONEXISTENT:
- UNREACHABLE();
- break;
- }
- }
-
- // If we get here with *done true, we have encountered a read-only property.
- if (*done) {
- if (strict_mode == SLOPPY) return value;
- Handle<Object> args[] = { name, object };
- Handle<Object> error = isolate->factory()->NewTypeError(
- "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args)));
- return isolate->Throw<Object>(error);
- }
- return isolate->factory()->the_hole_value();
-}
-
-
void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) {
// Only supports adding slack to owned descriptors.
ASSERT(map->owns_descriptors());
@@ -3508,23 +3594,6 @@ void JSObject::LookupRealNamedPropertyInPrototypes(Handle<Name> name,
}
-MaybeHandle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object,
- LookupResult* result,
- Handle<Name> key,
- Handle<Object> value,
- StrictMode strict_mode,
- StoreFromKeyed store_mode) {
- if (result->IsHandler()) {
- return JSProxy::SetPropertyWithHandler(handle(result->proxy()), object, key,
- value, strict_mode);
- } else {
- return JSObject::SetPropertyForResult(Handle<JSObject>::cast(object),
- result, key, value, strict_mode,
- store_mode);
- }
-}
-
-
bool JSProxy::HasPropertyWithHandler(Handle<JSProxy> proxy, Handle<Name> name) {
Isolate* isolate = proxy->GetIsolate();
@@ -3546,12 +3615,11 @@ bool JSProxy::HasPropertyWithHandler(Handle<JSProxy> proxy, Handle<Name> name) {
}
-MaybeHandle<Object> JSProxy::SetPropertyWithHandler(
- Handle<JSProxy> proxy,
- Handle<JSReceiver> receiver,
- Handle<Name> name,
- Handle<Object> value,
- StrictMode strict_mode) {
+MaybeHandle<Object> JSProxy::SetPropertyWithHandler(Handle<JSProxy> proxy,
+ Handle<Object> receiver,
+ Handle<Name> name,
+ Handle<Object> value,
+ StrictMode strict_mode) {
Isolate* isolate = proxy->GetIsolate();
// TODO(rossberg): adjust once there is a story for symbols vs proxies.
@@ -3572,12 +3640,8 @@ MaybeHandle<Object> JSProxy::SetPropertyWithHandler(
MaybeHandle<Object> JSProxy::SetPropertyViaPrototypesWithHandler(
- Handle<JSProxy> proxy,
- Handle<JSReceiver> receiver,
- Handle<Name> name,
- Handle<Object> value,
- StrictMode strict_mode,
- bool* done) {
+ Handle<JSProxy> proxy, Handle<Object> receiver, Handle<Name> name,
+ Handle<Object> value, StrictMode strict_mode, bool* done) {
Isolate* isolate = proxy->GetIsolate();
Handle<Object> handler(proxy->handler(), isolate); // Trap might morph proxy.
@@ -3996,7 +4060,7 @@ void JSObject::ConvertAndSetOwnProperty(LookupResult* lookup,
Handle<Object> value,
PropertyAttributes attributes) {
Handle<JSObject> object(lookup->holder());
- if (object->TooManyFastProperties()) {
+ if (object->map()->TooManyFastProperties(Object::MAY_BE_STORE_FROM_KEYED)) {
JSObject::NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
}
@@ -4034,140 +4098,6 @@ void JSObject::SetPropertyToFieldWithAttributes(LookupResult* lookup,
}
-MaybeHandle<Object> JSObject::SetPropertyForResult(
- Handle<JSObject> object,
- LookupResult* lookup,
- Handle<Name> name,
- Handle<Object> value,
- StrictMode strict_mode,
- StoreFromKeyed store_mode) {
- ASSERT(!value->IsTheHole());
- Isolate* isolate = object->GetIsolate();
-
- // Make sure that the top context does not change when doing callbacks or
- // interceptor calls.
- AssertNoContextChange ncc(isolate);
-
- // Optimization for 2-byte strings often used as keys in a decompression
- // dictionary. We internalize these short keys to avoid constantly
- // reallocating them.
- if (name->IsString() && !name->IsInternalizedString() &&
- Handle<String>::cast(name)->length() <= 2) {
- name = isolate->factory()->InternalizeString(Handle<String>::cast(name));
- }
-
- // Check access rights if needed.
- if (object->IsAccessCheckNeeded()) {
- if (!isolate->MayNamedAccess(object, name, v8::ACCESS_SET)) {
- return SetPropertyWithFailedAccessCheck(object, lookup, name, value,
- true, strict_mode);
- }
- }
-
- if (object->IsJSGlobalProxy()) {
- PrototypeIterator iter(isolate, object);
- if (iter.IsAtEnd()) return value;
- ASSERT(PrototypeIterator::GetCurrent(iter)->IsJSGlobalObject());
- return SetPropertyForResult(
- Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), lookup,
- name, value, strict_mode, store_mode);
- }
-
- ASSERT(!lookup->IsFound() || lookup->holder() == *object ||
- lookup->holder()->map()->is_hidden_prototype());
-
- if (!lookup->IsProperty() && !object->IsJSContextExtensionObject()) {
- bool done = false;
- Handle<Object> result_object;
- ASSIGN_RETURN_ON_EXCEPTION(
- isolate, result_object,
- SetPropertyViaPrototypes(object, name, value, strict_mode, &done),
- Object);
- if (done) return result_object;
- }
-
- if (!lookup->IsFound()) {
- // Neither properties nor transitions found.
- return AddPropertyInternal(object, name, value, NONE, strict_mode,
- store_mode);
- }
-
- if (lookup->IsProperty() && lookup->IsReadOnly()) {
- if (strict_mode == STRICT) {
- Handle<Object> args[] = { name, object };
- Handle<Object> error = isolate->factory()->NewTypeError(
- "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args)));
- return isolate->Throw<Object>(error);
- } else {
- return value;
- }
- }
-
- Handle<Object> old_value = isolate->factory()->the_hole_value();
- bool is_observed = object->map()->is_observed() &&
- *name != isolate->heap()->hidden_string();
- if (is_observed && lookup->IsDataProperty()) {
- old_value = Object::GetPropertyOrElement(object, name).ToHandleChecked();
- }
-
- // This is a real property that is not read-only, or it is a
- // transition or null descriptor and there are no setters in the prototypes.
- MaybeHandle<Object> maybe_result = value;
- if (lookup->IsTransition()) {
- maybe_result = SetPropertyUsingTransition(handle(lookup->holder()), lookup,
- name, value, NONE);
- } else {
- switch (lookup->type()) {
- case NORMAL:
- SetNormalizedProperty(handle(lookup->holder()), lookup, value);
- break;
- case FIELD:
- SetPropertyToField(lookup, value);
- break;
- case CONSTANT:
- // Only replace the constant if necessary.
- if (*value == lookup->GetConstant()) return value;
- SetPropertyToField(lookup, value);
- break;
- case CALLBACKS: {
- Handle<Object> callback_object(lookup->GetCallbackObject(), isolate);
- return SetPropertyWithCallback(object, name, value,
- handle(lookup->holder()),
- callback_object, strict_mode);
- }
- case INTERCEPTOR:
- maybe_result = SetPropertyWithInterceptor(handle(lookup->holder()),
- name, value, strict_mode);
- break;
- case HANDLER:
- case NONEXISTENT:
- UNREACHABLE();
- }
- }
-
- Handle<Object> result;
- ASSIGN_RETURN_ON_EXCEPTION(isolate, result, maybe_result, Object);
-
- if (is_observed) {
- if (lookup->IsTransition()) {
- EnqueueChangeRecord(object, "add", name, old_value);
- } else {
- LookupResult new_lookup(isolate);
- object->LookupOwn(name, &new_lookup, true);
- if (new_lookup.IsDataProperty()) {
- Handle<Object> new_value =
- Object::GetPropertyOrElement(object, name).ToHandleChecked();
- if (!new_value->SameValue(*old_value)) {
- EnqueueChangeRecord(object, "update", name, old_value);
- }
- }
- }
- }
-
- return result;
-}
-
-
void JSObject::AddProperty(
Handle<JSObject> object,
Handle<Name> name,
@@ -4215,8 +4145,8 @@ MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
// Check access rights if needed.
if (object->IsAccessCheckNeeded()) {
if (!isolate->MayNamedAccess(object, name, v8::ACCESS_SET)) {
- return SetPropertyWithFailedAccessCheck(object, &lookup, name, value,
- false, SLOPPY);
+ LookupIterator it(object, name, LookupIterator::CHECK_OWN);
+ return SetPropertyWithFailedAccessCheck(&it, value, SLOPPY);
}
}
@@ -4288,13 +4218,9 @@ MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes(
handling == DONT_FORCE_FIELD) {
Handle<Object> result;
ASSIGN_RETURN_ON_EXCEPTION(
- isolate, result,
- JSObject::SetPropertyWithCallback(object,
- name,
- value,
- handle(lookup.holder()),
- callback,
- STRICT),
+ isolate, result, JSObject::SetPropertyWithAccessor(
+ object, name, value, handle(lookup.holder()),
+ callback, STRICT),
Object);
if (attributes != lookup.GetAttributes()) {
@@ -4363,7 +4289,7 @@ Maybe<PropertyAttributes> JSObject::GetPropertyAttributesWithInterceptor(
Handle<Object> receiver,
Handle<Name> name) {
// TODO(rossberg): Support symbols in the API.
- if (name->IsSymbol()) return Maybe<PropertyAttributes>(ABSENT);
+ if (name->IsSymbol()) return Maybe<PropertyAttributes>();
Isolate* isolate = holder->GetIsolate();
HandleScope scope(isolate);
@@ -7367,6 +7293,97 @@ Handle<Map> Map::CopyForFreeze(Handle<Map> map) {
}
+bool DescriptorArray::CanHoldValue(int descriptor, Object* value) {
+ PropertyDetails details = GetDetails(descriptor);
+ switch (details.type()) {
+ case FIELD:
+ return value->FitsRepresentation(details.representation()) &&
+ GetFieldType(descriptor)->NowContains(value);
+
+ case CONSTANT:
+ ASSERT(GetConstant(descriptor) != value ||
+ value->FitsRepresentation(details.representation()));
+ return GetConstant(descriptor) == value;
+
+ case CALLBACKS:
+ return false;
+
+ case NORMAL:
+ case INTERCEPTOR:
+ case HANDLER:
+ case NONEXISTENT:
+ break;
+ }
+
+ UNREACHABLE();
+ return false;
+}
+
+
+Handle<Map> Map::PrepareForDataProperty(Handle<Map> map, int descriptor,
+ Handle<Object> value) {
+ // Dictionaries can store any property value.
+ if (map->is_dictionary_map()) return map;
+
+ Handle<DescriptorArray> descriptors(map->instance_descriptors());
+
+ if (descriptors->CanHoldValue(descriptor, *value)) return map;
+
+ Isolate* isolate = map->GetIsolate();
+ Representation representation = value->OptimalRepresentation();
+ Handle<HeapType> type = value->OptimalType(isolate, representation);
+
+ return GeneralizeRepresentation(map, descriptor, representation, type,
+ FORCE_FIELD);
+}
+
+
+Handle<Map> Map::TransitionToDataProperty(Handle<Map> map, Handle<Name> name,
+ Handle<Object> value,
+ PropertyAttributes attributes,
+ StoreFromKeyed store_mode) {
+ // Cannot currently handle deprecated maps.
+ ASSERT(!map->is_deprecated());
+ // Dictionary maps can always have additional data properties.
+ if (map->is_dictionary_map()) return map;
+
+ int index = map->SearchTransition(*name);
+ if (index != TransitionArray::kNotFound) {
+ Handle<Map> transition(map->GetTransition(index));
+ int descriptor = transition->LastAdded();
+
+ // TODO(verwaest): Handle attributes better.
+ DescriptorArray* descriptors = transition->instance_descriptors();
+ if (descriptors->GetDetails(descriptor).attributes() != attributes) {
+ return CopyGeneralizeAllRepresentations(transition, descriptor,
+ FORCE_FIELD, attributes,
+ "attributes mismatch");
+ }
+
+ return Map::PrepareForDataProperty(transition, descriptor, value);
+ }
+
+ TransitionFlag flag = INSERT_TRANSITION;
+ MaybeHandle<Map> maybe_map;
+ if (value->IsJSFunction()) {
+ maybe_map = Map::CopyWithConstant(map, name, value, attributes, flag);
+ } else if (!map->TooManyFastProperties(store_mode)) {
+ Isolate* isolate = name->GetIsolate();
+ Representation representation = value->OptimalRepresentation();
+ Handle<HeapType> type = value->OptimalType(isolate, representation);
+ maybe_map =
+ Map::CopyWithField(map, name, type, attributes, representation, flag);
+ }
+
+ Handle<Map> result;
+ if (!maybe_map.ToHandle(&result)) {
+ return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES);
+ }
+
+ return result;
+}
+
+
Handle<Map> Map::CopyAddDescriptor(Handle<Map> map,
Descriptor* descriptor,
TransitionFlag flag) {
« no previous file with comments | « src/objects.h ('k') | src/objects-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698