Support setting named properties on non-JSObjects.
authorverwaest@chromium.org <verwaest@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 22 Jul 2014 08:28:49 +0000 (08:28 +0000)
committerverwaest@chromium.org <verwaest@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 22 Jul 2014 08:28:49 +0000 (08:28 +0000)
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

src/debug.cc
src/factory.cc
src/ic.cc
src/liveedit.cc
src/objects.cc
src/objects.h
src/runtime.cc
test/mjsunit/value-wrapper-accessor.js

index 52e671d..e908126 100644 (file)
@@ -824,7 +824,7 @@ bool Debug::Load() {
   Handle<JSBuiltinsObject> builtin =
       Handle<JSBuiltinsObject>(global->builtins(), isolate_);
   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.
   bool caught_exception =
index 4bdb657..afcc84d 100644 (file)
@@ -2084,9 +2084,9 @@ Handle<JSObject> Factory::NewArgumentsObject(Handle<JSFunction> callee,
   ASSERT(!isolate()->has_pending_exception());
   Handle<JSObject> result = NewJSObjectFromMap(map);
   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) {
-    JSReceiver::SetProperty(result, callee_string(), callee, STRICT).Assert();
+    Object::SetProperty(result, callee_string(), callee, STRICT).Assert();
   }
   return result;
 }
index ca3970b..829db7d 100644 (file)
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -1195,11 +1195,12 @@ MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
 }
 
 
-static bool LookupForWrite(Handle<JSObject> receiver,
-                           Handle<String> name,
-                           Handle<Object> value,
-                           LookupResult* lookup,
-                           IC* ic) {
+static bool LookupForWrite(Handle<Object> object, Handle<String> name,
+                           Handle<Object> value, LookupResult* lookup, IC* ic) {
+  // Disable ICs for non-JSObjects for now.
+  if (!object->IsJSObject()) return false;
+  Handle<JSObject> receiver = Handle<JSObject>::cast(object);
+
   Handle<JSObject> holder = receiver;
   receiver->Lookup(name, lookup);
   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
   // 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;
     ASSIGN_RETURN_ON_EXCEPTION(
         isolate(), result,
-        JSReceiver::SetProperty(receiver, name, value, strict_mode()), Object);
+        Object::SetProperty(object, name, value, strict_mode()), Object);
     return result;
   }
 
@@ -1282,21 +1282,14 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object,
     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.
   uint32_t 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;
     ASSIGN_RETURN_ON_EXCEPTION(
         isolate(),
@@ -1307,17 +1300,18 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object,
   }
 
   // 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;
     ASSIGN_RETURN_ON_EXCEPTION(
-        isolate(), result, JSReceiver::SetProperty(receiver, name, value,
-                                                   strict_mode(), store_mode),
+        isolate(), result,
+        Object::SetProperty(object, name, value, strict_mode(), store_mode),
         Object);
     return result;
   }
 
   LookupResult lookup(isolate());
-  bool can_store = LookupForWrite(receiver, name, value, &lookup, this);
+  bool can_store = LookupForWrite(object, name, value, &lookup, this);
   if (!can_store &&
       strict_mode() == STRICT &&
       !(lookup.IsProperty() && lookup.IsReadOnly()) &&
@@ -1331,7 +1325,7 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object,
       set_target(*stub);
       TRACE_IC("StoreIC", name);
     } else if (can_store) {
-      UpdateCaches(&lookup, receiver, name, value);
+      UpdateCaches(&lookup, Handle<JSObject>::cast(object), name, value);
     } else if (lookup.IsNormal() ||
                (lookup.IsField() && lookup.CanHoldValue(value))) {
       Handle<Code> stub = generic_stub();
@@ -1343,7 +1337,7 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object,
   Handle<Object> result;
   ASSIGN_RETURN_ON_EXCEPTION(
       isolate(), result,
-      JSReceiver::SetProperty(receiver, name, value, strict_mode(), store_mode),
+      Object::SetProperty(object, name, value, strict_mode(), store_mode),
       Object);
   return result;
 }
index 1b7b4df..37c5892 100644 (file)
@@ -885,12 +885,12 @@ MaybeHandle<JSArray> LiveEdit::GatherCompileInfo(Handle<Script> script,
       Handle<Smi> end_pos(Smi::FromInt(message_location.end_pos()), isolate);
       Handle<JSObject> script_obj =
           Script::GetWrapper(message_location.script());
-      JSReceiver::SetProperty(rethrow_exception, start_pos_key, start_pos,
-                              SLOPPY).Assert();
-      JSReceiver::SetProperty(rethrow_exception, end_pos_key, end_pos, SLOPPY)
+      Object::SetProperty(rethrow_exception, start_pos_key, start_pos, SLOPPY)
+          .Assert();
+      Object::SetProperty(rethrow_exception, end_pos_key, end_pos, SLOPPY)
+          .Assert();
+      Object::SetProperty(rethrow_exception, script_obj_key, script_obj, SLOPPY)
           .Assert();
-      JSReceiver::SetProperty(rethrow_exception, script_obj_key, script_obj,
-                              SLOPPY).Assert();
     }
   }
 
index abd0187..9939927 100644 (file)
@@ -471,6 +471,8 @@ MaybeHandle<Object> Object::SetPropertyWithAccessor(
   // value since a const declaration would conflict with the setter.
   ASSERT(!structure->IsForeign());
   if (structure->IsExecutableAccessorInfo()) {
+    // Don't call executable accessor setters with non-JSObject receivers.
+    if (!receiver->IsJSObject()) return value;
     // api style callbacks
     ExecutableAccessorInfo* data = ExecutableAccessorInfo::cast(*structure);
     if (!data->IsCompatibleReceiver(*receiver)) {
@@ -554,10 +556,9 @@ MaybeHandle<Object> Object::SetPropertyWithDefinedSetter(
   }
 
   Handle<Object> argv[] = { value };
-  RETURN_ON_EXCEPTION(
-      isolate,
-      Execution::Call(isolate, setter, receiver, ARRAY_SIZE(argv), argv),
-      Object);
+  RETURN_ON_EXCEPTION(isolate, Execution::Call(isolate, setter, receiver,
+                                               ARRAY_SIZE(argv), argv, true),
+                      Object);
   return value;
 }
 
@@ -2959,13 +2960,12 @@ MaybeHandle<Object> JSObject::SetPropertyWithInterceptor(LookupIterator* it,
 }
 
 
-MaybeHandle<Object> JSReceiver::SetProperty(Handle<JSReceiver> object,
-                                            Handle<Name> name,
-                                            Handle<Object> value,
-                                            StrictMode strict_mode,
-                                            StoreFromKeyed store_mode) {
+MaybeHandle<Object> Object::SetProperty(Handle<Object> object,
+                                        Handle<Name> name, Handle<Object> value,
+                                        StrictMode strict_mode,
+                                        StoreFromKeyed store_mode) {
   LookupIterator it(object, name);
-  return Object::SetProperty(&it, value, strict_mode, store_mode);
+  return SetProperty(&it, value, strict_mode, store_mode);
 }
 
 
index b0e7fae..46787bf 100644 (file)
@@ -1483,6 +1483,13 @@ class Object {
   void Lookup(Handle<Name> name, LookupResult* result);
 
   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(
       LookupIterator* it, Handle<Object> value, StrictMode strict_mode,
       StoreFromKeyed store_mode);
@@ -1941,13 +1948,6 @@ class JSReceiver: public HeapObject {
 
   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(
       Handle<JSReceiver> object,
       uint32_t index,
@@ -2023,14 +2023,6 @@ class JSReceiver: public HeapObject {
       KeyCollectionType type);
 
  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);
 };
 
index aa453e1..abf9c4e 100644 (file)
@@ -2231,8 +2231,7 @@ RUNTIME_FUNCTION(Runtime_InitializeVarGlobal) {
   Handle<GlobalObject> global(isolate->context()->global_object());
   Handle<Object> result;
   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
-      isolate, result,
-      JSReceiver::SetProperty(global, name, value, strict_mode));
+      isolate, result, Object::SetProperty(global, name, value, strict_mode));
   return *result;
 }
 
@@ -5026,18 +5025,17 @@ MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate,
           isolate, name_object, Execution::ToString(isolate, key), Object);
     }
     Handle<Name> name = Handle<Name>::cast(name_object);
-    return JSReceiver::SetProperty(Handle<JSProxy>::cast(object), name, value,
-                                   strict_mode);
+    return Object::SetProperty(Handle<JSProxy>::cast(object), name, value,
+                               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.
   uint32_t 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
     // of a string using [] notation.  We need to support this too in
     // JavaScript.
@@ -5068,6 +5066,9 @@ MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate,
   if (key->IsName()) {
     Handle<Name> name = Handle<Name>::cast(key);
     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 (!value->IsNumber() && !value->IsUndefined()) {
           ASSIGN_RETURN_ON_EXCEPTION(
@@ -5078,7 +5079,7 @@ MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate,
                                   true, SET_PROPERTY);
     } else {
       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);
 
   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,
                                 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(
-      isolate, JSReceiver::SetProperty(object, name, value, strict_mode));
+      isolate, Object::SetProperty(object, name, value, strict_mode));
 
   return *value;
 }
index f951456..79db407 100644 (file)
@@ -77,20 +77,14 @@ function test(object, prototype) {
     %OptimizeFunctionOnNextCall(nonstrict);
     result = undefined;
     nonstrict(object);
-    // TODO(1475): Support storing to primitive values.
-    // This should return "object" once storing to primitive values is
-    // supported.
-    assertEquals("undefined", typeof result);
+    assertEquals("object", typeof result);
 
     strict(object);
     strict(object);
     %OptimizeFunctionOnNextCall(strict);
     result = undefined;
     strict(object);
-    // TODO(1475): Support storing to primitive values.
-    // This should return "object" once storing to primitive values is
-    // supported.
-    assertEquals("undefined", typeof result);
+    assertEquals(object, result);
   })();
 }