Reimplement SetProperty using the LookupIterator
BUG= R=ishell@chromium.org Review URL: https://codereview.chromium.org/392243002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22482 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
9d2609fe98
commit
7e29b64e27
@ -1547,7 +1547,7 @@ void Debug::PrepareStep(StepAction step_action,
|
||||
if (is_load_or_store) {
|
||||
// Remember source position and frame to handle step in getter/setter. If
|
||||
// there is a custom getter/setter it will be handled in
|
||||
// Object::Get/SetPropertyWithCallback, otherwise the step action will be
|
||||
// Object::Get/SetPropertyWithAccessor, otherwise the step action will be
|
||||
// propagated on the next Debug::Break.
|
||||
thread_local_.last_statement_position_ =
|
||||
debug_info->code()->SourceStatementPosition(frame->pc());
|
||||
|
@ -1281,6 +1281,8 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object,
|
||||
Handle<String> name,
|
||||
Handle<Object> value,
|
||||
JSReceiver::StoreFromKeyed store_mode) {
|
||||
// TODO(verwaest): Let SetProperty do the migration, since storing a property
|
||||
// might deprecate the current map again, if value does not fit.
|
||||
if (MigrateDeprecated(object) || object->IsJSProxy()) {
|
||||
Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
|
||||
Handle<Object> result;
|
||||
@ -1757,6 +1759,8 @@ KeyedAccessStoreMode KeyedStoreIC::GetStoreMode(Handle<JSObject> receiver,
|
||||
MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
|
||||
Handle<Object> key,
|
||||
Handle<Object> value) {
|
||||
// TODO(verwaest): Let SetProperty do the migration, since storing a property
|
||||
// might deprecate the current map again, if value does not fit.
|
||||
if (MigrateDeprecated(object)) {
|
||||
Handle<Object> result;
|
||||
ASSIGN_RETURN_ON_EXCEPTION(
|
||||
|
@ -144,6 +144,78 @@ bool LookupIterator::HasProperty() {
|
||||
}
|
||||
|
||||
|
||||
void LookupIterator::PrepareForDataProperty(Handle<Object> value) {
|
||||
ASSERT(has_property_);
|
||||
ASSERT(HolderIsReceiver());
|
||||
if (property_encoding_ == DICTIONARY) return;
|
||||
holder_map_ = Map::PrepareForDataProperty(holder_map_, number_, value);
|
||||
JSObject::MigrateToMap(GetHolder(), holder_map_);
|
||||
// Reload property information.
|
||||
if (holder_map_->is_dictionary_map()) {
|
||||
property_encoding_ = DICTIONARY;
|
||||
} else {
|
||||
property_encoding_ = DESCRIPTOR;
|
||||
}
|
||||
CHECK(HasProperty());
|
||||
}
|
||||
|
||||
|
||||
void LookupIterator::TransitionToDataProperty(
|
||||
Handle<Object> value, PropertyAttributes attributes,
|
||||
Object::StoreFromKeyed store_mode) {
|
||||
ASSERT(!has_property_ || !HolderIsReceiver());
|
||||
|
||||
// Can only be called when the receiver is a JSObject. JSProxy has to be
|
||||
// handled via a trap. Adding properties to primitive values is not
|
||||
// observable.
|
||||
Handle<JSObject> receiver = Handle<JSObject>::cast(GetReceiver());
|
||||
|
||||
// Properties have to be added to context extension objects through
|
||||
// SetOwnPropertyIgnoreAttributes.
|
||||
ASSERT(!receiver->IsJSContextExtensionObject());
|
||||
|
||||
if (receiver->IsJSGlobalProxy()) {
|
||||
PrototypeIterator iter(isolate(), receiver);
|
||||
receiver =
|
||||
Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter));
|
||||
}
|
||||
|
||||
maybe_holder_ = receiver;
|
||||
holder_map_ = Map::TransitionToDataProperty(handle(receiver->map()), name_,
|
||||
value, attributes, store_mode);
|
||||
JSObject::MigrateToMap(receiver, holder_map_);
|
||||
|
||||
// Reload the information.
|
||||
state_ = NOT_FOUND;
|
||||
configuration_ = CHECK_OWN_REAL;
|
||||
state_ = LookupInHolder();
|
||||
ASSERT(IsFound());
|
||||
HasProperty();
|
||||
}
|
||||
|
||||
|
||||
bool LookupIterator::HolderIsReceiver() const {
|
||||
ASSERT(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY);
|
||||
DisallowHeapAllocation no_gc;
|
||||
Handle<Object> receiver = GetReceiver();
|
||||
if (!receiver->IsJSReceiver()) return false;
|
||||
Object* current = *receiver;
|
||||
JSReceiver* holder = *maybe_holder_.ToHandleChecked();
|
||||
// JSProxy do not occur as hidden prototypes.
|
||||
if (current->IsJSProxy()) {
|
||||
return JSReceiver::cast(current) == holder;
|
||||
}
|
||||
PrototypeIterator iter(isolate(), current,
|
||||
PrototypeIterator::START_AT_RECEIVER);
|
||||
do {
|
||||
if (JSReceiver::cast(iter.GetCurrent()) == holder) return true;
|
||||
ASSERT(!current->IsJSProxy());
|
||||
iter.Advance();
|
||||
} while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Handle<Object> LookupIterator::FetchValue() const {
|
||||
Object* result = NULL;
|
||||
switch (property_encoding_) {
|
||||
@ -181,4 +253,29 @@ Handle<Object> LookupIterator::GetDataValue() const {
|
||||
}
|
||||
|
||||
|
||||
void LookupIterator::WriteDataValue(Handle<Object> value) {
|
||||
ASSERT(is_guaranteed_to_have_holder());
|
||||
ASSERT(has_property_);
|
||||
if (property_encoding_ == DICTIONARY) {
|
||||
Handle<JSObject> holder = GetHolder();
|
||||
NameDictionary* property_dictionary = holder->property_dictionary();
|
||||
if (holder->IsGlobalObject()) {
|
||||
Handle<PropertyCell> cell(
|
||||
PropertyCell::cast(property_dictionary->ValueAt(number_)));
|
||||
PropertyCell::SetValueInferType(cell, value);
|
||||
} else {
|
||||
property_dictionary->ValueAtPut(number_, *value);
|
||||
}
|
||||
} else if (property_details_.type() == v8::internal::FIELD) {
|
||||
GetHolder()->WriteToField(number_, *value);
|
||||
} else {
|
||||
ASSERT_EQ(v8::internal::CONSTANT, property_details_.type());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LookupIterator::InternalizeName() {
|
||||
if (name_->IsUniqueName()) return;
|
||||
name_ = factory()->InternalizeString(Handle<String>::cast(name_));
|
||||
}
|
||||
} } // namespace v8::internal
|
||||
|
15
src/lookup.h
15
src/lookup.h
@ -92,11 +92,13 @@ class LookupIterator V8_FINAL BASE_EMBEDDED {
|
||||
Handle<Object> GetReceiver() const {
|
||||
return Handle<Object>::cast(maybe_receiver_.ToHandleChecked());
|
||||
}
|
||||
Handle<Map> holder_map() const { return holder_map_; }
|
||||
Handle<JSObject> GetHolder() const {
|
||||
ASSERT(IsFound() && state_ != JSPROXY);
|
||||
return Handle<JSObject>::cast(maybe_holder_.ToHandleChecked());
|
||||
}
|
||||
Handle<JSReceiver> GetRoot() const;
|
||||
bool HolderIsReceiver() const;
|
||||
|
||||
/* Dynamically reduce the trapped types. */
|
||||
void skip_interceptor() {
|
||||
@ -116,6 +118,10 @@ class LookupIterator V8_FINAL BASE_EMBEDDED {
|
||||
// below can be used. It ensures that we are able to provide a definite
|
||||
// answer, and loads extra information about the property.
|
||||
bool HasProperty();
|
||||
void PrepareForDataProperty(Handle<Object> value);
|
||||
void TransitionToDataProperty(Handle<Object> value,
|
||||
PropertyAttributes attributes,
|
||||
Object::StoreFromKeyed store_mode);
|
||||
PropertyKind property_kind() const {
|
||||
ASSERT(has_property_);
|
||||
return property_kind_;
|
||||
@ -124,11 +130,18 @@ class LookupIterator V8_FINAL BASE_EMBEDDED {
|
||||
ASSERT(has_property_);
|
||||
return property_details_;
|
||||
}
|
||||
int descriptor_number() const {
|
||||
ASSERT(has_property_);
|
||||
ASSERT_EQ(DESCRIPTOR, property_encoding_);
|
||||
return number_;
|
||||
}
|
||||
Handle<Object> GetAccessors() const;
|
||||
Handle<Object> GetDataValue() const;
|
||||
void WriteDataValue(Handle<Object> value);
|
||||
|
||||
void InternalizeName();
|
||||
|
||||
/* JSPROXY */
|
||||
|
||||
Handle<JSProxy> GetJSProxy() const {
|
||||
return Handle<JSProxy>::cast(maybe_holder_.ToHandleChecked());
|
||||
}
|
||||
|
@ -2079,23 +2079,12 @@ bool JSObject::HasFastProperties() {
|
||||
}
|
||||
|
||||
|
||||
bool JSObject::TooManyFastProperties(StoreFromKeyed store_mode) {
|
||||
// Allow extra fast properties if the object has more than
|
||||
// kFastPropertiesSoftLimit in-object properties. When this is the case, it is
|
||||
// very unlikely that the object is being used as a dictionary and there is a
|
||||
// good chance that allowing more map transitions will be worth it.
|
||||
Map* map = this->map();
|
||||
if (map->unused_property_fields() != 0) return false;
|
||||
|
||||
int inobject = map->inobject_properties();
|
||||
|
||||
int limit;
|
||||
if (store_mode == CERTAINLY_NOT_STORE_FROM_KEYED) {
|
||||
limit = Max(inobject, kMaxFastProperties);
|
||||
} else {
|
||||
limit = Max(inobject, kFastPropertiesSoftLimit);
|
||||
}
|
||||
return properties()->length() > limit;
|
||||
bool Map::TooManyFastProperties(StoreFromKeyed store_mode) {
|
||||
if (unused_property_fields() != 0) return false;
|
||||
int minimum = store_mode == CERTAINLY_NOT_STORE_FROM_KEYED ? 128 : 12;
|
||||
int limit = Max(minimum, inobject_properties());
|
||||
int external = NumberOfFields() - inobject_properties();
|
||||
return external > limit;
|
||||
}
|
||||
|
||||
|
||||
|
651
src/objects.cc
651
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);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
|
111
src/objects.h
111
src/objects.h
@ -1375,6 +1375,13 @@ class Object {
|
||||
HEAP_OBJECT_TYPE_LIST(IS_TYPE_FUNCTION_DECL)
|
||||
#undef IS_TYPE_FUNCTION_DECL
|
||||
|
||||
// A non-keyed store is of the form a.x = foo or a["x"] = foo whereas
|
||||
// a keyed store is of the form a[expression] = foo.
|
||||
enum StoreFromKeyed {
|
||||
MAY_BE_STORE_FROM_KEYED,
|
||||
CERTAINLY_NOT_STORE_FROM_KEYED
|
||||
};
|
||||
|
||||
INLINE(bool IsFixedArrayBase() const);
|
||||
INLINE(bool IsExternal() const);
|
||||
INLINE(bool IsAccessorInfo() const);
|
||||
@ -1476,6 +1483,16 @@ class Object {
|
||||
void Lookup(Handle<Name> name, LookupResult* result);
|
||||
|
||||
MUST_USE_RESULT static MaybeHandle<Object> GetProperty(LookupIterator* it);
|
||||
MUST_USE_RESULT static MaybeHandle<Object> SetProperty(
|
||||
LookupIterator* it, Handle<Object> value, StrictMode strict_mode,
|
||||
StoreFromKeyed store_mode);
|
||||
MUST_USE_RESULT static MaybeHandle<Object> WriteToReadOnlyProperty(
|
||||
LookupIterator* it, Handle<Object> value, StrictMode strict_mode);
|
||||
MUST_USE_RESULT static MaybeHandle<Object> SetDataProperty(
|
||||
LookupIterator* it, Handle<Object> value);
|
||||
MUST_USE_RESULT static MaybeHandle<Object> AddDataProperty(
|
||||
LookupIterator* it, Handle<Object> value, PropertyAttributes attributes,
|
||||
StrictMode strict_mode, StoreFromKeyed store_mode);
|
||||
MUST_USE_RESULT static inline MaybeHandle<Object> GetPropertyOrElement(
|
||||
Handle<Object> object,
|
||||
Handle<Name> key);
|
||||
@ -1492,12 +1509,9 @@ class Object {
|
||||
Handle<Name> name,
|
||||
Handle<JSObject> holder,
|
||||
Handle<Object> structure);
|
||||
MUST_USE_RESULT static MaybeHandle<Object> SetPropertyWithCallback(
|
||||
Handle<Object> receiver,
|
||||
Handle<Name> name,
|
||||
Handle<Object> value,
|
||||
Handle<JSObject> holder,
|
||||
Handle<Object> structure,
|
||||
MUST_USE_RESULT static MaybeHandle<Object> SetPropertyWithAccessor(
|
||||
Handle<Object> receiver, Handle<Name> name, Handle<Object> value,
|
||||
Handle<JSObject> holder, Handle<Object> structure,
|
||||
StrictMode strict_mode);
|
||||
|
||||
MUST_USE_RESULT static MaybeHandle<Object> GetPropertyWithDefinedGetter(
|
||||
@ -1918,13 +1932,6 @@ class JSReceiver: public HeapObject {
|
||||
FORCE_DELETION
|
||||
};
|
||||
|
||||
// A non-keyed store is of the form a.x = foo or a["x"] = foo whereas
|
||||
// a keyed store is of the form a[expression] = foo.
|
||||
enum StoreFromKeyed {
|
||||
MAY_BE_STORE_FROM_KEYED,
|
||||
CERTAINLY_NOT_STORE_FROM_KEYED
|
||||
};
|
||||
|
||||
// Internal properties (e.g. the hidden properties dictionary) might
|
||||
// be added even though the receiver is non-extensible.
|
||||
enum ExtensibilityCheck {
|
||||
@ -2136,18 +2143,7 @@ class JSObject: public JSReceiver {
|
||||
uint32_t limit);
|
||||
|
||||
MUST_USE_RESULT static MaybeHandle<Object> SetPropertyWithInterceptor(
|
||||
Handle<JSObject> object,
|
||||
Handle<Name> name,
|
||||
Handle<Object> value,
|
||||
StrictMode strict_mode);
|
||||
|
||||
MUST_USE_RESULT static MaybeHandle<Object> SetPropertyForResult(
|
||||
Handle<JSObject> object,
|
||||
LookupResult* result,
|
||||
Handle<Name> name,
|
||||
Handle<Object> value,
|
||||
StrictMode strict_mode,
|
||||
StoreFromKeyed store_mode = MAY_BE_STORE_FROM_KEYED);
|
||||
LookupIterator* it, Handle<Object> value);
|
||||
|
||||
// SetLocalPropertyIgnoreAttributes converts callbacks to fields. We need to
|
||||
// grant an exemption to ExecutableAccessor callbacks in some cases.
|
||||
@ -2573,12 +2569,6 @@ class JSObject: public JSReceiver {
|
||||
|
||||
Object* SlowReverseLookup(Object* value);
|
||||
|
||||
// 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);
|
||||
|
||||
// Maximal number of elements (numbered 0 .. kMaxElementCount - 1).
|
||||
// Also maximal value of JSArray's length property.
|
||||
static const uint32_t kMaxElementCount = 0xffffffffu;
|
||||
@ -2606,8 +2596,6 @@ class JSObject: public JSReceiver {
|
||||
// "global.Object" and not to arbitrary other JSObject maps.
|
||||
static const int kInitialGlobalObjectUnusedPropertiesCount = 4;
|
||||
|
||||
static const int kFastPropertiesSoftLimit = 12;
|
||||
static const int kMaxFastProperties = 128;
|
||||
static const int kMaxInstanceSize = 255 * kPointerSize;
|
||||
// When extending the backing storage for property values, we increase
|
||||
// its size by more than the 1 entry necessary, so sequentially adding fields
|
||||
@ -2734,21 +2722,6 @@ class JSObject: public JSReceiver {
|
||||
StrictMode strict_mode,
|
||||
bool check_prototype = true);
|
||||
|
||||
// Searches the prototype chain for property 'name'. If it is found and
|
||||
// has a setter, invoke it and set '*done' to true. If it is found and is
|
||||
// read-only, reject and set '*done' to true. Otherwise, set '*done' to
|
||||
// false. Can throw and return an empty handle with '*done==true'.
|
||||
MUST_USE_RESULT static MaybeHandle<Object> SetPropertyViaPrototypes(
|
||||
Handle<JSObject> object,
|
||||
Handle<Name> name,
|
||||
Handle<Object> value,
|
||||
StrictMode strict_mode,
|
||||
bool* done);
|
||||
MUST_USE_RESULT static MaybeHandle<Object> SetPropertyPostInterceptor(
|
||||
Handle<JSObject> object,
|
||||
Handle<Name> name,
|
||||
Handle<Object> value,
|
||||
StrictMode strict_mode);
|
||||
MUST_USE_RESULT static MaybeHandle<Object> SetPropertyUsingTransition(
|
||||
Handle<JSObject> object,
|
||||
LookupResult* lookup,
|
||||
@ -2756,12 +2729,7 @@ class JSObject: public JSReceiver {
|
||||
Handle<Object> value,
|
||||
PropertyAttributes attributes);
|
||||
MUST_USE_RESULT static MaybeHandle<Object> SetPropertyWithFailedAccessCheck(
|
||||
Handle<JSObject> object,
|
||||
LookupResult* result,
|
||||
Handle<Name> name,
|
||||
Handle<Object> value,
|
||||
bool check_prototype,
|
||||
StrictMode strict_mode);
|
||||
LookupIterator* it, Handle<Object> value, StrictMode strict_mode);
|
||||
|
||||
// Add a property to an object.
|
||||
MUST_USE_RESULT static MaybeHandle<Object> AddPropertyInternal(
|
||||
@ -3452,6 +3420,8 @@ class DescriptorArray: public FixedArray {
|
||||
FixedArray* new_cache,
|
||||
Object* new_index_cache);
|
||||
|
||||
bool CanHoldValue(int descriptor, Object* value);
|
||||
|
||||
// Accessors for fetching instance descriptor at descriptor number.
|
||||
inline Name* GetKey(int descriptor_number);
|
||||
inline Object** GetKeySlot(int descriptor_number);
|
||||
@ -6334,6 +6304,10 @@ class Map: public HeapObject {
|
||||
StoreMode store_mode,
|
||||
const char* reason);
|
||||
|
||||
static Handle<Map> PrepareForDataProperty(Handle<Map> old_map,
|
||||
int descriptor_number,
|
||||
Handle<Object> value);
|
||||
|
||||
static Handle<Map> Normalize(Handle<Map> map, PropertyNormalizationMode mode);
|
||||
|
||||
// Returns the constructor name (the name (possibly, inferred name) of the
|
||||
@ -6526,6 +6500,15 @@ class Map: public HeapObject {
|
||||
static Handle<Map> CopyForObserved(Handle<Map> map);
|
||||
|
||||
static Handle<Map> CopyForFreeze(Handle<Map> map);
|
||||
// Maximal number of fast properties. 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);
|
||||
static Handle<Map> TransitionToDataProperty(Handle<Map> map,
|
||||
Handle<Name> name,
|
||||
Handle<Object> value,
|
||||
PropertyAttributes attributes,
|
||||
StoreFromKeyed store_mode);
|
||||
|
||||
inline void AppendDescriptor(Descriptor* desc);
|
||||
|
||||
@ -6834,6 +6817,9 @@ class Map: public HeapObject {
|
||||
Handle<Object> prototype,
|
||||
Handle<Map> target_map);
|
||||
|
||||
static const int kFastPropertiesSoftLimit = 12;
|
||||
static const int kMaxFastProperties = 128;
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(Map);
|
||||
};
|
||||
|
||||
@ -9968,12 +9954,8 @@ class JSProxy: public JSReceiver {
|
||||
// otherwise set it to false.
|
||||
MUST_USE_RESULT
|
||||
static MaybeHandle<Object> 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);
|
||||
|
||||
static PropertyAttributes GetPropertyAttributesWithHandler(
|
||||
Handle<JSProxy> proxy,
|
||||
@ -9983,6 +9965,9 @@ class JSProxy: public JSReceiver {
|
||||
Handle<JSProxy> proxy,
|
||||
Handle<JSReceiver> receiver,
|
||||
uint32_t index);
|
||||
MUST_USE_RESULT static MaybeHandle<Object> SetPropertyWithHandler(
|
||||
Handle<JSProxy> proxy, Handle<Object> receiver, Handle<Name> name,
|
||||
Handle<Object> value, StrictMode strict_mode);
|
||||
|
||||
// Turn the proxy into an (empty) JSObject.
|
||||
static void Fix(Handle<JSProxy> proxy);
|
||||
@ -10022,12 +10007,6 @@ class JSProxy: public JSReceiver {
|
||||
private:
|
||||
friend class JSReceiver;
|
||||
|
||||
MUST_USE_RESULT static MaybeHandle<Object> SetPropertyWithHandler(
|
||||
Handle<JSProxy> proxy,
|
||||
Handle<JSReceiver> receiver,
|
||||
Handle<Name> name,
|
||||
Handle<Object> value,
|
||||
StrictMode strict_mode);
|
||||
MUST_USE_RESULT static inline MaybeHandle<Object> SetElementWithHandler(
|
||||
Handle<JSProxy> proxy,
|
||||
Handle<JSReceiver> receiver,
|
||||
|
@ -581,8 +581,8 @@ RUNTIME_FUNCTION(StoreInterceptorProperty) {
|
||||
ASSERT(receiver->HasNamedInterceptor());
|
||||
Handle<Object> result;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, result, JSObject::SetPropertyWithInterceptor(
|
||||
receiver, name, value, ic.strict_mode()));
|
||||
isolate, result,
|
||||
JSObject::SetProperty(receiver, name, value, ic.strict_mode()));
|
||||
return *result;
|
||||
}
|
||||
|
||||
|
@ -1322,7 +1322,9 @@ function ObjectIsSealed(obj) {
|
||||
for (var i = 0; i < names.length; i++) {
|
||||
var name = names[i];
|
||||
var desc = GetOwnPropertyJS(obj, name);
|
||||
if (desc.isConfigurable()) return false;
|
||||
if (desc.isConfigurable()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -423,11 +423,8 @@ TEST(ExistsInPrototype) {
|
||||
// Sanity check to make sure that the holder of the interceptor
|
||||
// really is the prototype object.
|
||||
{ ExistsInPrototypeContext context;
|
||||
context.Check("this.x = 87; this.x",
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
EXPECT_RESULT, Number::New(CcTest::isolate(), 87));
|
||||
context.Check("this.x = 87; this.x", 0, 0, 1, EXPECT_RESULT,
|
||||
Number::New(CcTest::isolate(), 87));
|
||||
}
|
||||
|
||||
{ ExistsInPrototypeContext context;
|
||||
|
Loading…
Reference in New Issue
Block a user