Lazy resolution of standard classes changes the shape of Object.prototype (610697, r=mrbkap).
authorBrendan Eich <brendan@mozilla.org>
Tue, 09 Nov 2010 12:09:07 -0800
changeset 57753 c146eeb9fecc942e2ed9a8513f83e37d4493fc91
parent 57752 4e9b098ccf87ce74adc3393473ee935df8a85b45
child 57754 e2f64f43c7e1ec2c0328b18e7644192da297a29d
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewersmrbkap
bugs610697
milestone2.0b8pre
Lazy resolution of standard classes changes the shape of Object.prototype (610697, r=mrbkap).
js/src/jsfun.cpp
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -2919,19 +2919,40 @@ js_DefineFunction(JSContext *cx, JSObjec
          * internal flag using the same bit, JSFUN_EXPR_CLOSURE -- see jsfun.h
          * for more on this.
          */
         attrs &= ~JSFUN_STUB_GSOPS;
         gsop = PropertyStub;
     } else {
         gsop = NULL;
     }
+
+    /*
+     * Historically, all objects have a parent slot and all native functions
+     * defined by the JS_DefineFunction* APIs funnel here and bind parent to
+     * obj. But this prematurely deoptimizes by flagging, e.g. Date.prototype,
+     * as a "delegate" (a proto or parent of some other object), which in turn
+     * causes shadowingShapeChange events and shape regeneration for common
+     * method names that are also (and already) bound on, say, Object.prototype
+     * (e.g., toString).
+     *
+     * Until we get rid of parent, avoid flagging standard class prototype
+     * objects as delegates prematurely when defining their methods, instead
+     * parenting each method to the proto's global. We keep API compatibility
+     * for all obj parameters that are not of a standard (cached-proto-key)
+     * class, since some embedding clients count on parent being obj.
+     */
+    JSObject *parent = (JSCLASS_CACHED_PROTO_KEY(obj->clasp) != JSProto_Null)
+                       ? obj->getGlobal()
+                       : obj;
+
     fun = js_NewFunction(cx, NULL, native, nargs,
                          attrs & (JSFUN_FLAGS_MASK | JSFUN_TRCINFO),
-                         obj, JSID_IS_ATOM(id) ? JSID_TO_ATOM(id) : NULL);
+                         parent,
+                         JSID_IS_ATOM(id) ? JSID_TO_ATOM(id) : NULL);
     if (!fun)
         return NULL;
     if (!obj->defineProperty(cx, id, ObjectValue(*fun), gsop, gsop, attrs & ~JSFUN_FLAGS_MASK))
         return NULL;
     return fun;
 }
 
 #if (JSV2F_CONSTRUCT & JSV2F_SEARCH_STACK)