[INFER] Clone function first for SETMETHOD on non-shadowable shapes, bug 642894.
authorBrian Hackett <bhackett1024@gmail.com>
Wed, 08 Jun 2011 11:04:00 -0700
changeset 75155 94ae102189f061a9afb553363b7414c54351b845
parent 75153 a53db4f2d235f538b283d85bfba2163816e13e30
child 75156 8816703032a6e7eff2ff9482b5cca7834624350e
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
bugs642894
milestone7.0a1
[INFER] Clone function first for SETMETHOD on non-shadowable shapes, bug 642894.
js/src/jit-test/tests/basic/bug642894.js
js/src/jsobj.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/bug642894.js
@@ -0,0 +1,9 @@
+
+function foo() {
+  var x = {};
+  x.__proto__ = function() { return 0 }
+  return x;
+}
+var a = foo();
+var b = foo();
+assertEq(a.__proto__ === b.__proto__, false);
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -5975,16 +5975,35 @@ JSObject::reportNotExtensible(JSContext 
 bool
 JSObject::callMethod(JSContext *cx, jsid id, uintN argc, Value *argv, Value *vp)
 {
     Value fval;
     return js_GetMethod(cx, this, id, JSGET_NO_METHOD_BARRIER, &fval) &&
            ExternalInvoke(cx, ObjectValue(*this), fval, argc, argv, vp);
 }
 
+static bool
+CloneFunctionForSetMethod(JSContext *cx, Value *vp)
+{
+    JSObject *funobj = &vp->toObject();
+    JSFunction *fun = funobj->getFunctionPrivate();
+
+    /*
+     * If fun is already different from the original JSFunction, it does not
+     * need to be cloned again.
+     */
+    if (fun == funobj) {
+        funobj = CloneFunctionObject(cx, fun, fun->parent, true);
+        if (!funobj)
+            return false;
+        vp->setObject(*funobj);
+    }
+    return true;
+}
+
 JSBool
 js_SetPropertyHelper(JSContext *cx, JSObject *obj, jsid id, uintN defineHow,
                      Value *vp, JSBool strict)
 {
     JSObject *pobj;
     JSProperty *prop;
     const Shape *shape;
     uintN attrs, flags;
@@ -6070,16 +6089,22 @@ js_SetPropertyHelper(JSContext *cx, JSOb
         }
 
         attrs = shape->attributes();
         if (pobj != obj) {
             /*
              * We found id in a prototype object: prepare to share or shadow.
              */
             if (!shape->shadowable()) {
+                if (defineHow & DNP_SET_METHOD) {
+                    JS_ASSERT(!shape->isMethod());
+                    if (!CloneFunctionForSetMethod(cx, vp))
+                        return false;
+                }
+
                 if (defineHow & DNP_CACHE_RESULT)
                     JS_PROPERTY_CACHE(cx).fill(cx, obj, 0, pobj, shape);
 
                 if (shape->hasDefaultSetter() && !shape->hasGetterValue())
                     return JS_TRUE;
 
                 return shape->set(cx, obj, strict, vp);
             }
@@ -6131,25 +6156,18 @@ js_SetPropertyHelper(JSContext *cx, JSOb
              * cache, as the interpreter has no fast path for these unusual
              * cases.
              */
             bool identical = shape->isMethod() && shape->methodObject() == vp->toObject();
             if (!identical) {
                 shape = obj->methodShapeChange(cx, *shape);
                 if (!shape)
                     return false;
-
-                JSObject *funobj = &vp->toObject();
-                JSFunction *fun = funobj->getFunctionPrivate();
-                if (fun == funobj) {
-                    funobj = CloneFunctionObject(cx, fun, fun->parent, true);
-                    if (!funobj)
-                        return JS_FALSE;
-                    vp->setObject(*funobj);
-                }
+                if (!CloneFunctionForSetMethod(cx, vp))
+                    return false;
             }
             return identical || js_NativeSet(cx, obj, shape, false, strict, vp);
         }
     }
 
     added = false;
     if (!shape) {
         if (!obj->isExtensible()) {