| 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) {
|
|
|