Support setting named properties on non-JSObjects.
BUG= R=ishell@chromium.org Review URL: https://codereview.chromium.org/407953002 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22518 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
837b758b5f
commit
3bba0204c0
@ -824,7 +824,7 @@ bool Debug::Load() {
|
|||||||
Handle<JSBuiltinsObject> builtin =
|
Handle<JSBuiltinsObject> builtin =
|
||||||
Handle<JSBuiltinsObject>(global->builtins(), isolate_);
|
Handle<JSBuiltinsObject>(global->builtins(), isolate_);
|
||||||
RETURN_ON_EXCEPTION_VALUE(
|
RETURN_ON_EXCEPTION_VALUE(
|
||||||
isolate_, JSReceiver::SetProperty(global, key, builtin, SLOPPY), false);
|
isolate_, Object::SetProperty(global, key, builtin, SLOPPY), false);
|
||||||
|
|
||||||
// Compile the JavaScript for the debugger in the debugger context.
|
// Compile the JavaScript for the debugger in the debugger context.
|
||||||
bool caught_exception =
|
bool caught_exception =
|
||||||
|
@ -2084,9 +2084,9 @@ Handle<JSObject> Factory::NewArgumentsObject(Handle<JSFunction> callee,
|
|||||||
ASSERT(!isolate()->has_pending_exception());
|
ASSERT(!isolate()->has_pending_exception());
|
||||||
Handle<JSObject> result = NewJSObjectFromMap(map);
|
Handle<JSObject> result = NewJSObjectFromMap(map);
|
||||||
Handle<Smi> value(Smi::FromInt(length), isolate());
|
Handle<Smi> value(Smi::FromInt(length), isolate());
|
||||||
JSReceiver::SetProperty(result, length_string(), value, STRICT).Assert();
|
Object::SetProperty(result, length_string(), value, STRICT).Assert();
|
||||||
if (!strict_mode_callee) {
|
if (!strict_mode_callee) {
|
||||||
JSReceiver::SetProperty(result, callee_string(), callee, STRICT).Assert();
|
Object::SetProperty(result, callee_string(), callee, STRICT).Assert();
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
44
src/ic.cc
44
src/ic.cc
@ -1195,11 +1195,12 @@ MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool LookupForWrite(Handle<JSObject> receiver,
|
static bool LookupForWrite(Handle<Object> object, Handle<String> name,
|
||||||
Handle<String> name,
|
Handle<Object> value, LookupResult* lookup, IC* ic) {
|
||||||
Handle<Object> value,
|
// Disable ICs for non-JSObjects for now.
|
||||||
LookupResult* lookup,
|
if (!object->IsJSObject()) return false;
|
||||||
IC* ic) {
|
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
|
||||||
|
|
||||||
Handle<JSObject> holder = receiver;
|
Handle<JSObject> holder = receiver;
|
||||||
receiver->Lookup(name, lookup);
|
receiver->Lookup(name, lookup);
|
||||||
if (lookup->IsFound()) {
|
if (lookup->IsFound()) {
|
||||||
@ -1268,11 +1269,10 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object,
|
|||||||
// TODO(verwaest): Let SetProperty do the migration, since storing a property
|
// TODO(verwaest): Let SetProperty do the migration, since storing a property
|
||||||
// might deprecate the current map again, if value does not fit.
|
// might deprecate the current map again, if value does not fit.
|
||||||
if (MigrateDeprecated(object) || object->IsJSProxy()) {
|
if (MigrateDeprecated(object) || object->IsJSProxy()) {
|
||||||
Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
|
|
||||||
Handle<Object> result;
|
Handle<Object> result;
|
||||||
ASSIGN_RETURN_ON_EXCEPTION(
|
ASSIGN_RETURN_ON_EXCEPTION(
|
||||||
isolate(), result,
|
isolate(), result,
|
||||||
JSReceiver::SetProperty(receiver, name, value, strict_mode()), Object);
|
Object::SetProperty(object, name, value, strict_mode()), Object);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1282,21 +1282,14 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object,
|
|||||||
return TypeError("non_object_property_store", object, name);
|
return TypeError("non_object_property_store", object, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The length property of string values is read-only. Throw in strict mode.
|
|
||||||
if (strict_mode() == STRICT && object->IsString() &&
|
|
||||||
String::Equals(isolate()->factory()->length_string(), name)) {
|
|
||||||
return TypeError("strict_read_only_property", object, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ignore other stores where the receiver is not a JSObject.
|
|
||||||
// TODO(1475): Must check prototype chains of object wrappers.
|
|
||||||
if (!object->IsJSObject()) return value;
|
|
||||||
|
|
||||||
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
|
|
||||||
|
|
||||||
// Check if the given name is an array index.
|
// Check if the given name is an array index.
|
||||||
uint32_t index;
|
uint32_t index;
|
||||||
if (name->AsArrayIndex(&index)) {
|
if (name->AsArrayIndex(&index)) {
|
||||||
|
// Ignore other stores where the receiver is not a JSObject.
|
||||||
|
// TODO(1475): Must check prototype chains of object wrappers.
|
||||||
|
if (!object->IsJSObject()) return value;
|
||||||
|
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
|
||||||
|
|
||||||
Handle<Object> result;
|
Handle<Object> result;
|
||||||
ASSIGN_RETURN_ON_EXCEPTION(
|
ASSIGN_RETURN_ON_EXCEPTION(
|
||||||
isolate(),
|
isolate(),
|
||||||
@ -1307,17 +1300,18 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Observed objects are always modified through the runtime.
|
// Observed objects are always modified through the runtime.
|
||||||
if (receiver->map()->is_observed()) {
|
if (object->IsHeapObject() &&
|
||||||
|
Handle<HeapObject>::cast(object)->map()->is_observed()) {
|
||||||
Handle<Object> result;
|
Handle<Object> result;
|
||||||
ASSIGN_RETURN_ON_EXCEPTION(
|
ASSIGN_RETURN_ON_EXCEPTION(
|
||||||
isolate(), result, JSReceiver::SetProperty(receiver, name, value,
|
isolate(), result,
|
||||||
strict_mode(), store_mode),
|
Object::SetProperty(object, name, value, strict_mode(), store_mode),
|
||||||
Object);
|
Object);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
LookupResult lookup(isolate());
|
LookupResult lookup(isolate());
|
||||||
bool can_store = LookupForWrite(receiver, name, value, &lookup, this);
|
bool can_store = LookupForWrite(object, name, value, &lookup, this);
|
||||||
if (!can_store &&
|
if (!can_store &&
|
||||||
strict_mode() == STRICT &&
|
strict_mode() == STRICT &&
|
||||||
!(lookup.IsProperty() && lookup.IsReadOnly()) &&
|
!(lookup.IsProperty() && lookup.IsReadOnly()) &&
|
||||||
@ -1331,7 +1325,7 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object,
|
|||||||
set_target(*stub);
|
set_target(*stub);
|
||||||
TRACE_IC("StoreIC", name);
|
TRACE_IC("StoreIC", name);
|
||||||
} else if (can_store) {
|
} else if (can_store) {
|
||||||
UpdateCaches(&lookup, receiver, name, value);
|
UpdateCaches(&lookup, Handle<JSObject>::cast(object), name, value);
|
||||||
} else if (lookup.IsNormal() ||
|
} else if (lookup.IsNormal() ||
|
||||||
(lookup.IsField() && lookup.CanHoldValue(value))) {
|
(lookup.IsField() && lookup.CanHoldValue(value))) {
|
||||||
Handle<Code> stub = generic_stub();
|
Handle<Code> stub = generic_stub();
|
||||||
@ -1343,7 +1337,7 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object,
|
|||||||
Handle<Object> result;
|
Handle<Object> result;
|
||||||
ASSIGN_RETURN_ON_EXCEPTION(
|
ASSIGN_RETURN_ON_EXCEPTION(
|
||||||
isolate(), result,
|
isolate(), result,
|
||||||
JSReceiver::SetProperty(receiver, name, value, strict_mode(), store_mode),
|
Object::SetProperty(object, name, value, strict_mode(), store_mode),
|
||||||
Object);
|
Object);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -885,12 +885,12 @@ MaybeHandle<JSArray> LiveEdit::GatherCompileInfo(Handle<Script> script,
|
|||||||
Handle<Smi> end_pos(Smi::FromInt(message_location.end_pos()), isolate);
|
Handle<Smi> end_pos(Smi::FromInt(message_location.end_pos()), isolate);
|
||||||
Handle<JSObject> script_obj =
|
Handle<JSObject> script_obj =
|
||||||
Script::GetWrapper(message_location.script());
|
Script::GetWrapper(message_location.script());
|
||||||
JSReceiver::SetProperty(rethrow_exception, start_pos_key, start_pos,
|
Object::SetProperty(rethrow_exception, start_pos_key, start_pos, SLOPPY)
|
||||||
SLOPPY).Assert();
|
.Assert();
|
||||||
JSReceiver::SetProperty(rethrow_exception, end_pos_key, end_pos, SLOPPY)
|
Object::SetProperty(rethrow_exception, end_pos_key, end_pos, SLOPPY)
|
||||||
|
.Assert();
|
||||||
|
Object::SetProperty(rethrow_exception, script_obj_key, script_obj, SLOPPY)
|
||||||
.Assert();
|
.Assert();
|
||||||
JSReceiver::SetProperty(rethrow_exception, script_obj_key, script_obj,
|
|
||||||
SLOPPY).Assert();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -471,6 +471,8 @@ MaybeHandle<Object> Object::SetPropertyWithAccessor(
|
|||||||
// value since a const declaration would conflict with the setter.
|
// value since a const declaration would conflict with the setter.
|
||||||
ASSERT(!structure->IsForeign());
|
ASSERT(!structure->IsForeign());
|
||||||
if (structure->IsExecutableAccessorInfo()) {
|
if (structure->IsExecutableAccessorInfo()) {
|
||||||
|
// Don't call executable accessor setters with non-JSObject receivers.
|
||||||
|
if (!receiver->IsJSObject()) return value;
|
||||||
// api style callbacks
|
// api style callbacks
|
||||||
ExecutableAccessorInfo* data = ExecutableAccessorInfo::cast(*structure);
|
ExecutableAccessorInfo* data = ExecutableAccessorInfo::cast(*structure);
|
||||||
if (!data->IsCompatibleReceiver(*receiver)) {
|
if (!data->IsCompatibleReceiver(*receiver)) {
|
||||||
@ -554,10 +556,9 @@ MaybeHandle<Object> Object::SetPropertyWithDefinedSetter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Handle<Object> argv[] = { value };
|
Handle<Object> argv[] = { value };
|
||||||
RETURN_ON_EXCEPTION(
|
RETURN_ON_EXCEPTION(isolate, Execution::Call(isolate, setter, receiver,
|
||||||
isolate,
|
ARRAY_SIZE(argv), argv, true),
|
||||||
Execution::Call(isolate, setter, receiver, ARRAY_SIZE(argv), argv),
|
Object);
|
||||||
Object);
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2959,13 +2960,12 @@ MaybeHandle<Object> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MaybeHandle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object,
|
MaybeHandle<Object> Object::SetProperty(Handle<Object> object,
|
||||||
Handle<Name> name,
|
Handle<Name> name, Handle<Object> value,
|
||||||
Handle<Object> value,
|
StrictMode strict_mode,
|
||||||
StrictMode strict_mode,
|
StoreFromKeyed store_mode) {
|
||||||
StoreFromKeyed store_mode) {
|
|
||||||
LookupIterator it(object, name);
|
LookupIterator it(object, name);
|
||||||
return Object::SetProperty(&it, value, strict_mode, store_mode);
|
return SetProperty(&it, value, strict_mode, store_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1483,6 +1483,13 @@ class Object {
|
|||||||
void Lookup(Handle<Name> name, LookupResult* result);
|
void Lookup(Handle<Name> name, LookupResult* result);
|
||||||
|
|
||||||
MUST_USE_RESULT static MaybeHandle<Object> GetProperty(LookupIterator* it);
|
MUST_USE_RESULT static MaybeHandle<Object> GetProperty(LookupIterator* it);
|
||||||
|
|
||||||
|
// Implementation of [[Put]], ECMA-262 5th edition, section 8.12.5.
|
||||||
|
MUST_USE_RESULT static MaybeHandle<Object> SetProperty(
|
||||||
|
Handle<Object> object, Handle<Name> key, Handle<Object> value,
|
||||||
|
StrictMode strict_mode,
|
||||||
|
StoreFromKeyed store_mode = MAY_BE_STORE_FROM_KEYED);
|
||||||
|
|
||||||
MUST_USE_RESULT static MaybeHandle<Object> SetProperty(
|
MUST_USE_RESULT static MaybeHandle<Object> SetProperty(
|
||||||
LookupIterator* it, Handle<Object> value, StrictMode strict_mode,
|
LookupIterator* it, Handle<Object> value, StrictMode strict_mode,
|
||||||
StoreFromKeyed store_mode);
|
StoreFromKeyed store_mode);
|
||||||
@ -1941,13 +1948,6 @@ class JSReceiver: public HeapObject {
|
|||||||
|
|
||||||
DECLARE_CAST(JSReceiver)
|
DECLARE_CAST(JSReceiver)
|
||||||
|
|
||||||
// Implementation of [[Put]], ECMA-262 5th edition, section 8.12.5.
|
|
||||||
MUST_USE_RESULT static MaybeHandle<Object> SetProperty(
|
|
||||||
Handle<JSReceiver> object,
|
|
||||||
Handle<Name> key,
|
|
||||||
Handle<Object> value,
|
|
||||||
StrictMode strict_mode,
|
|
||||||
StoreFromKeyed store_mode = MAY_BE_STORE_FROM_KEYED);
|
|
||||||
MUST_USE_RESULT static MaybeHandle<Object> SetElement(
|
MUST_USE_RESULT static MaybeHandle<Object> SetElement(
|
||||||
Handle<JSReceiver> object,
|
Handle<JSReceiver> object,
|
||||||
uint32_t index,
|
uint32_t index,
|
||||||
@ -2023,14 +2023,6 @@ class JSReceiver: public HeapObject {
|
|||||||
KeyCollectionType type);
|
KeyCollectionType type);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MUST_USE_RESULT static MaybeHandle<Object> SetProperty(
|
|
||||||
Handle<JSReceiver> receiver,
|
|
||||||
LookupResult* result,
|
|
||||||
Handle<Name> key,
|
|
||||||
Handle<Object> value,
|
|
||||||
StrictMode strict_mode,
|
|
||||||
StoreFromKeyed store_from_keyed);
|
|
||||||
|
|
||||||
DISALLOW_IMPLICIT_CONSTRUCTORS(JSReceiver);
|
DISALLOW_IMPLICIT_CONSTRUCTORS(JSReceiver);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2231,8 +2231,7 @@ RUNTIME_FUNCTION(Runtime_InitializeVarGlobal) {
|
|||||||
Handle<GlobalObject> global(isolate->context()->global_object());
|
Handle<GlobalObject> global(isolate->context()->global_object());
|
||||||
Handle<Object> result;
|
Handle<Object> result;
|
||||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||||
isolate, result,
|
isolate, result, Object::SetProperty(global, name, value, strict_mode));
|
||||||
JSReceiver::SetProperty(global, name, value, strict_mode));
|
|
||||||
return *result;
|
return *result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5026,18 +5025,17 @@ MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate,
|
|||||||
isolate, name_object, Execution::ToString(isolate, key), Object);
|
isolate, name_object, Execution::ToString(isolate, key), Object);
|
||||||
}
|
}
|
||||||
Handle<Name> name = Handle<Name>::cast(name_object);
|
Handle<Name> name = Handle<Name>::cast(name_object);
|
||||||
return JSReceiver::SetProperty(Handle<JSProxy>::cast(object), name, value,
|
return Object::SetProperty(Handle<JSProxy>::cast(object), name, value,
|
||||||
strict_mode);
|
strict_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the object isn't a JavaScript object, we ignore the store.
|
|
||||||
if (!object->IsJSObject()) return value;
|
|
||||||
|
|
||||||
Handle<JSObject> js_object = Handle<JSObject>::cast(object);
|
|
||||||
|
|
||||||
// Check if the given key is an array index.
|
// Check if the given key is an array index.
|
||||||
uint32_t index;
|
uint32_t index;
|
||||||
if (key->ToArrayIndex(&index)) {
|
if (key->ToArrayIndex(&index)) {
|
||||||
|
// TODO(verwaest): Support non-JSObject receivers.
|
||||||
|
if (!object->IsJSObject()) return value;
|
||||||
|
Handle<JSObject> js_object = Handle<JSObject>::cast(object);
|
||||||
|
|
||||||
// In Firefox/SpiderMonkey, Safari and Opera you can access the characters
|
// In Firefox/SpiderMonkey, Safari and Opera you can access the characters
|
||||||
// of a string using [] notation. We need to support this too in
|
// of a string using [] notation. We need to support this too in
|
||||||
// JavaScript.
|
// JavaScript.
|
||||||
@ -5068,6 +5066,9 @@ MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate,
|
|||||||
if (key->IsName()) {
|
if (key->IsName()) {
|
||||||
Handle<Name> name = Handle<Name>::cast(key);
|
Handle<Name> name = Handle<Name>::cast(key);
|
||||||
if (name->AsArrayIndex(&index)) {
|
if (name->AsArrayIndex(&index)) {
|
||||||
|
// TODO(verwaest): Support non-JSObject receivers.
|
||||||
|
if (!object->IsJSObject()) return value;
|
||||||
|
Handle<JSObject> js_object = Handle<JSObject>::cast(object);
|
||||||
if (js_object->HasExternalArrayElements()) {
|
if (js_object->HasExternalArrayElements()) {
|
||||||
if (!value->IsNumber() && !value->IsUndefined()) {
|
if (!value->IsNumber() && !value->IsUndefined()) {
|
||||||
ASSIGN_RETURN_ON_EXCEPTION(
|
ASSIGN_RETURN_ON_EXCEPTION(
|
||||||
@ -5078,7 +5079,7 @@ MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate,
|
|||||||
true, SET_PROPERTY);
|
true, SET_PROPERTY);
|
||||||
} else {
|
} else {
|
||||||
if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
|
if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
|
||||||
return JSReceiver::SetProperty(js_object, name, value, strict_mode);
|
return Object::SetProperty(object, name, value, strict_mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5089,11 +5090,13 @@ MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate,
|
|||||||
Handle<String> name = Handle<String>::cast(converted);
|
Handle<String> name = Handle<String>::cast(converted);
|
||||||
|
|
||||||
if (name->AsArrayIndex(&index)) {
|
if (name->AsArrayIndex(&index)) {
|
||||||
|
// TODO(verwaest): Support non-JSObject receivers.
|
||||||
|
if (!object->IsJSObject()) return value;
|
||||||
|
Handle<JSObject> js_object = Handle<JSObject>::cast(object);
|
||||||
return JSObject::SetElement(js_object, index, value, NONE, strict_mode,
|
return JSObject::SetElement(js_object, index, value, NONE, strict_mode,
|
||||||
true, SET_PROPERTY);
|
true, SET_PROPERTY);
|
||||||
} else {
|
|
||||||
return JSReceiver::SetProperty(js_object, name, value, strict_mode);
|
|
||||||
}
|
}
|
||||||
|
return Object::SetProperty(object, name, value, strict_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -9267,7 +9270,7 @@ RUNTIME_FUNCTION(Runtime_StoreLookupSlot) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RETURN_FAILURE_ON_EXCEPTION(
|
RETURN_FAILURE_ON_EXCEPTION(
|
||||||
isolate, JSReceiver::SetProperty(object, name, value, strict_mode));
|
isolate, Object::SetProperty(object, name, value, strict_mode));
|
||||||
|
|
||||||
return *value;
|
return *value;
|
||||||
}
|
}
|
||||||
|
@ -77,20 +77,14 @@ function test(object, prototype) {
|
|||||||
%OptimizeFunctionOnNextCall(nonstrict);
|
%OptimizeFunctionOnNextCall(nonstrict);
|
||||||
result = undefined;
|
result = undefined;
|
||||||
nonstrict(object);
|
nonstrict(object);
|
||||||
// TODO(1475): Support storing to primitive values.
|
assertEquals("object", typeof result);
|
||||||
// This should return "object" once storing to primitive values is
|
|
||||||
// supported.
|
|
||||||
assertEquals("undefined", typeof result);
|
|
||||||
|
|
||||||
strict(object);
|
strict(object);
|
||||||
strict(object);
|
strict(object);
|
||||||
%OptimizeFunctionOnNextCall(strict);
|
%OptimizeFunctionOnNextCall(strict);
|
||||||
result = undefined;
|
result = undefined;
|
||||||
strict(object);
|
strict(object);
|
||||||
// TODO(1475): Support storing to primitive values.
|
assertEquals(object, result);
|
||||||
// This should return "object" once storing to primitive values is
|
|
||||||
// supported.
|
|
||||||
assertEquals("undefined", typeof result);
|
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user