Proxies: Fix receiver for setters inherited from proxies.
authorrossberg@chromium.org <rossberg@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 29 May 2012 14:00:56 +0000 (14:00 +0000)
committerrossberg@chromium.org <rossberg@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 29 May 2012 14:00:56 +0000 (14:00 +0000)
R=mstarzinger@chromium.org
BUG=v8:1543
TEST=

Review URL: https://chromiumcodereview.appspot.com/10451064

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@11677 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/objects.cc
src/objects.h
test/mjsunit/harmony/proxies.js

index ba460cf..d734fbd 100644 (file)
@@ -248,13 +248,14 @@ MaybeObject* JSProxy::GetElementWithHandler(Object* receiver,
 }
 
 
-MaybeObject* JSProxy::SetElementWithHandler(uint32_t index,
+MaybeObject* JSProxy::SetElementWithHandler(JSReceiver* receiver,
+                                            uint32_t index,
                                             Object* value,
                                             StrictModeFlag strict_mode) {
   String* name;
   MaybeObject* maybe = GetHeap()->Uint32ToString(index);
   if (!maybe->To<String>(&name)) return maybe;
-  return SetPropertyWithHandler(name, value, NONE, strict_mode);
+  return SetPropertyWithHandler(receiver, name, value, NONE, strict_mode);
 }
 
 
@@ -2085,7 +2086,7 @@ MaybeObject* JSObject::SetElementWithCallbackSetterInPrototypes(
         return maybe;
       }
       return JSProxy::cast(pt)->SetPropertyWithHandlerIfDefiningSetter(
-          name, value, NONE, strict_mode, found);
+          this, name, value, NONE, strict_mode, found);
     }
     if (!JSObject::cast(pt)->HasDictionaryElements()) {
       continue;
@@ -2140,7 +2141,7 @@ MaybeObject* JSObject::SetPropertyWithCallbackSetterInPrototypes(
       Handle<Object> hvalue(value);
       MaybeObject* result =
           accessor_result.proxy()->SetPropertyWithHandlerIfDefiningSetter(
-              name, value, attributes, strict_mode, &found);
+              this, name, value, attributes, strict_mode, &found);
       if (found) return result;
       // The proxy does not define the property as an accessor.
       // Consequently, it has no effect on setting the receiver.
@@ -2624,7 +2625,7 @@ MaybeObject* JSReceiver::SetProperty(LookupResult* result,
                                      StrictModeFlag strict_mode) {
   if (result->IsFound() && result->type() == HANDLER) {
     return result->proxy()->SetPropertyWithHandler(
-        key, value, attributes, strict_mode);
+        this, key, value, attributes, strict_mode);
   } else {
     return JSObject::cast(this)->SetPropertyForResult(
         result, key, value, attributes, strict_mode);
@@ -2648,13 +2649,14 @@ bool JSProxy::HasPropertyWithHandler(String* name_raw) {
 
 
 MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
+    JSReceiver* receiver_raw,
     String* name_raw,
     Object* value_raw,
     PropertyAttributes attributes,
     StrictModeFlag strict_mode) {
   Isolate* isolate = GetIsolate();
   HandleScope scope(isolate);
-  Handle<Object> receiver(this);
+  Handle<JSReceiver> receiver(receiver_raw);
   Handle<Object> name(name_raw);
   Handle<Object> value(value_raw);
 
@@ -2667,6 +2669,7 @@ MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandler(
 
 
 MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandlerIfDefiningSetter(
+    JSReceiver* receiver_raw,
     String* name_raw,
     Object* value_raw,
     PropertyAttributes attributes,
@@ -2674,6 +2677,7 @@ MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandlerIfDefiningSetter(
     bool* found) {
   *found = true;  // except where defined otherwise...
   Isolate* isolate = GetHeap()->isolate();
+  Handle<JSReceiver> receiver(receiver_raw);
   Handle<JSProxy> proxy(this);
   Handle<Object> handler(this->handler());  // Trap might morph proxy.
   Handle<String> name(name_raw);
@@ -2715,7 +2719,7 @@ MUST_USE_RESULT MaybeObject* JSProxy::SetPropertyWithHandlerIfDefiningSetter(
     if (!setter->IsUndefined()) {
       // We have a setter -- invoke it.
       // TODO(rossberg): nicer would be to cast to some JSCallable here...
-      return proxy->SetPropertyWithDefinedSetter(
+      return receiver->SetPropertyWithDefinedSetter(
           JSReceiver::cast(*setter), *value);
     } else {
       Handle<String> get_name = isolate->factory()->LookupAsciiSymbol("get_");
@@ -9657,7 +9661,7 @@ MaybeObject* JSReceiver::SetElement(uint32_t index,
                                     bool check_proto) {
   if (IsJSProxy()) {
     return JSProxy::cast(this)->SetElementWithHandler(
-        index, value, strict_mode);
+        this, index, value, strict_mode);
   } else {
     return JSObject::cast(this)->SetElement(
         index, value, attributes, strict_mode, check_proto);
index e9dfe6c..e2d7185 100644 (file)
@@ -7708,11 +7708,13 @@ class JSProxy: public JSReceiver {
       uint32_t index);
 
   MUST_USE_RESULT MaybeObject* SetPropertyWithHandler(
+      JSReceiver* receiver,
       String* name,
       Object* value,
       PropertyAttributes attributes,
       StrictModeFlag strict_mode);
   MUST_USE_RESULT MaybeObject* SetElementWithHandler(
+      JSReceiver* receiver,
       uint32_t index,
       Object* value,
       StrictModeFlag strict_mode);
@@ -7720,6 +7722,7 @@ class JSProxy: public JSReceiver {
   // If the handler defines an accessor property, invoke its setter
   // (or throw if only a getter exists) and set *found to true. Otherwise false.
   MUST_USE_RESULT MaybeObject* SetPropertyWithHandlerIfDefiningSetter(
+      JSReceiver* receiver,
       String* name,
       Object* value,
       PropertyAttributes attributes,
index 8b12b38..bb1ebf2 100644 (file)
@@ -572,6 +572,7 @@ TestSetThrow(Proxy.create({
 }))
 
 
+var rec
 var key
 var val
 
@@ -611,6 +612,7 @@ function TestSetForDerived2(create, handler) {
 
   assertEquals(46, o.p_setter = 46)
   assertEquals("p_setter", key)
+  assertSame(o, rec)
   assertEquals(46, val)  // written to parent
   assertFalse(Object.prototype.hasOwnProperty.call(o, "p_setter"))
 
@@ -641,8 +643,14 @@ TestSetForDerived({
     switch (k) {
       case "p_writable": return {writable: true, configurable: true}
       case "p_nonwritable": return {writable: false, configurable: true}
-      case "p_setter":return {set: function(x) { val = x }, configurable: true}
-      case "p_nosetter": return {get: function() { return 1 }, configurable: true}
+      case "p_setter":return {
+        set: function(x) { rec = this; val = x },
+        configurable: true
+      }
+      case "p_nosetter": return {
+        get: function() { return 1 },
+        configurable: true
+      }
       case "p_nonconf":return {}
       case "p_throw": throw "myexn"
       case "p_setterthrow": return {set: function(x) { throw "myexn" }}