Bug 474501 - JSON literals shouldn't have prototype setters run during evaluation. r=brendan
authorJeff Walden <jwalden@mit.edu>
Fri, 30 Jan 2009 17:40:33 -0800
changeset 24501 9c1020fb138ae11446f3993b011286eb61a3e420
parent 24500 056d0d9757658e5d3976a276e63ddd82b5251fd3
child 24502 3cfef5bd1da4b05836525d49762597ebeb055b26
push id5074
push userrsayre@mozilla.com
push dateSat, 31 Jan 2009 19:45:42 +0000
treeherdermozilla-central@f1cade532f6f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbrendan
bugs474501
milestone1.9.2a1pre
Bug 474501 - JSON literals shouldn't have prototype setters run during evaluation. r=brendan
js/src/jsinterp.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsscope.h
--- a/js/src/jsinterp.cpp
+++ b/js/src/jsinterp.cpp
@@ -6189,18 +6189,20 @@ js_Interpret(JSContext *cx)
                 LOAD_ATOM(0);
                 id = ATOM_TO_JSID(atom);
 
                 /* Set the property named by obj[id] to rval. */
                 if (!js_CheckRedeclaration(cx, obj, id, JSPROP_INITIALIZER,
                                            NULL, NULL)) {
                     goto error;
                 }
-                if (!js_SetPropertyHelper(cx, obj, id, &rval, &entry))
+                if (!js_DefineNativeProperty(cx, obj, id, rval, NULL, NULL,
+                                             JSPROP_ENUMERATE, 0, 0, NULL, &entry)) {
                     goto error;
+                }
 #ifdef JS_TRACER
                 if (entry)
                     TRACE_1(SetPropMiss, entry);
 #endif
             } while (0);
 
             /* Common tail for property cache hit and miss cases. */
             regs.sp--;
@@ -6224,31 +6226,31 @@ js_Interpret(JSContext *cx)
              * an object initialiser, not an array initialiser).
              */
             if (!js_CheckRedeclaration(cx, obj, id, JSPROP_INITIALIZER, NULL,
                                        NULL)) {
                 goto error;
             }
 
             /*
-             * If rval is a hole, do not call OBJ_SET_PROPERTY. In this case,
+             * If rval is a hole, do not call OBJ_DEFINE_PROPERTY. In this case,
              * obj must be an array, so if the current op is the last element
              * initialiser, set the array length to one greater than id.
              */
             if (rval == JSVAL_HOLE) {
                 JS_ASSERT(OBJ_IS_ARRAY(cx, obj));
                 JS_ASSERT(JSID_IS_INT(id));
                 JS_ASSERT((jsuint) JSID_TO_INT(id) < ARRAY_INIT_LIMIT);
                 if ((JSOp) regs.pc[JSOP_INITELEM_LENGTH] == JSOP_ENDINIT &&
                     !js_SetLengthProperty(cx, obj,
                                           (jsuint) (JSID_TO_INT(id) + 1))) {
                     goto error;
                 }
             } else {
-                if (!OBJ_SET_PROPERTY(cx, obj, id, &rval))
+                if (!OBJ_DEFINE_PROPERTY(cx, obj, id, rval, NULL, NULL, JSPROP_ENUMERATE, NULL))
                     goto error;
             }
             regs.sp -= 2;
           END_CASE(JSOP_INITELEM)
 
 #if JS_HAS_SHARP_VARS
           BEGIN_CASE(JSOP_DEFSHARP)
             obj = fp->sharpArray;
@@ -6791,17 +6793,17 @@ js_Interpret(JSContext *cx)
              */
             i = obj->fslots[JSSLOT_ARRAY_LENGTH];
             if (i == ARRAY_INIT_LIMIT) {
                 JS_ReportErrorNumberUC(cx, js_GetErrorMessage, NULL,
                                        JSMSG_ARRAY_INIT_TOO_BIG);
                 goto error;
             }
             id = INT_TO_JSID(i);
-            if (!OBJ_SET_PROPERTY(cx, obj, id, &rval))
+            if (!OBJ_DEFINE_PROPERTY(cx, obj, id, rval, NULL, NULL, JSPROP_ENUMERATE, NULL))
                 goto error;
             regs.sp--;
           END_CASE(JSOP_ARRAYPUSH)
 #endif /* JS_HAS_GENERATORS */
 
 #if JS_THREADED_INTERP
           L_JSOP_BACKPATCH:
           L_JSOP_BACKPATCH_POP:
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3402,17 +3402,18 @@ js_DefineProperty(JSContext *cx, JSObjec
                     LOCKED_OBJ_WRITE_BARRIER(cx, obj, (sprop)->slot, *(vp));  \
             }                                                                 \
         }                                                                     \
     JS_END_MACRO
 
 JSBool
 js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
                         JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
-                        uintN flags, intN shortid, JSProperty **propp)
+                        uintN flags, intN shortid, JSProperty **propp,
+                        JSPropCacheEntry** entryp /* = NULL */)
 {
     JSClass *clasp;
     JSScope *scope;
     JSScopeProperty *sprop;
 
     /* Convert string indices to integers if appropriate. */
     CHECK_FOR_STRING_INDEX(id);
 
@@ -3498,16 +3499,23 @@ js_DefineNativeProperty(JSContext *cx, J
     if (SPROP_HAS_VALID_SLOT(sprop, scope))
         LOCKED_OBJ_WRITE_BARRIER(cx, obj, sprop->slot, value);
 
     /* XXXbe called with lock held */
     ADD_PROPERTY_HELPER(cx, clasp, obj, scope, sprop, &value,
                         js_RemoveScopeProperty(cx, scope, id);
                         goto bad);
 
+    if (entryp) {
+        JS_ASSERT_NOT_EXECUTING_TRACE(cx);
+        if (!(attrs & JSPROP_SHARED))
+            js_FillPropertyCache(cx, obj, OBJ_SHAPE(obj), 0, 0, obj, sprop, entryp);
+        else
+            PCMETER(JS_PROPERTY_CACHE(cx).nofills++);
+    }
     if (propp)
         *propp = (JSProperty *) sprop;
     else
         JS_UNLOCK_OBJ(cx, obj);
     return JS_TRUE;
 
 bad:
     JS_UNLOCK_OBJ(cx, obj);
@@ -4111,17 +4119,17 @@ js_SetPropertyHelper(JSContext *cx, JSOb
                     *entryp = NULL;
                 }
 
                 if (SPROP_HAS_STUB_SETTER(sprop) &&
                     !(sprop->attrs & JSPROP_GETTER)) {
                     return JS_TRUE;
                 }
 
-                return !!SPROP_SET(cx, sprop, obj, pobj, vp);
+                return SPROP_SET(cx, sprop, obj, pobj, vp);
             }
 
             /* Restore attrs to the ECMA default for new properties. */
             attrs = JSPROP_ENUMERATE;
 
             /*
              * Preserve the shortid, getter, and setter when shadowing any
              * property that has a shortid.  An old API convention requires
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -544,17 +544,18 @@ js_ChangeNativePropertyAttrs(JSContext *
 extern JSBool
 js_DefineProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
                   JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
                   JSProperty **propp);
 
 extern JSBool
 js_DefineNativeProperty(JSContext *cx, JSObject *obj, jsid id, jsval value,
                         JSPropertyOp getter, JSPropertyOp setter, uintN attrs,
-                        uintN flags, intN shortid, JSProperty **propp);
+                        uintN flags, intN shortid, JSProperty **propp,
+                        JSPropCacheEntry** entryp = NULL);
 
 /*
  * Unlike js_DefineProperty, propp must be non-null. On success, and if id was
  * found, return true with *objp non-null and locked, and with a held property
  * stored in *propp. If successful but id was not found, return true with both
  * *objp and *propp null. Therefore all callers who receive a non-null *propp
  * must later call OBJ_DROP_PROPERTY(cx, *objp, *propp).
  */
--- a/js/src/jsscope.h
+++ b/js/src/jsscope.h
@@ -323,39 +323,52 @@ struct JSScopeProperty {
 #define SPROP_INVALID_SLOT              0xffffffff
 
 #define SLOT_IN_SCOPE(slot,scope)         ((slot) < (scope)->map.freeslot)
 #define SPROP_HAS_VALID_SLOT(sprop,scope) SLOT_IN_SCOPE((sprop)->slot, scope)
 
 #define SPROP_HAS_STUB_GETTER(sprop)    (!(sprop)->getter)
 #define SPROP_HAS_STUB_SETTER(sprop)    (!(sprop)->setter)
 
-/*
- * NB: SPROP_GET must not be called if SPROP_HAS_STUB_GETTER(sprop).
- */
-#define SPROP_GET(cx,sprop,obj,obj2,vp)                                       \
-    (((sprop)->attrs & JSPROP_GETTER)                                         \
-     ? js_InternalGetOrSet(cx, obj, (sprop)->id,                              \
-                           OBJECT_TO_JSVAL((sprop)->getter), JSACC_READ,      \
-                           0, 0, vp)                                          \
-     : (sprop)->getter(cx, OBJ_THIS_OBJECT(cx,obj), SPROP_USERID(sprop), vp))
+static JS_INLINE JSBool
+SPROP_GET(JSContext* cx, JSScopeProperty* sprop, JSObject* obj, JSObject* obj2,
+          jsval* vp)
+{
+    JS_ASSERT(!SPROP_HAS_STUB_GETTER(sprop));
+
+    if (sprop->attrs & JSPROP_GETTER) {
+        return js_InternalGetOrSet(cx, obj, sprop->id,
+                                   OBJECT_TO_JSVAL(sprop->getter), JSACC_READ,
+                                   0, 0, vp);
+    }
+
+    return sprop->getter(cx, OBJ_THIS_OBJECT(cx, obj), SPROP_USERID(sprop), vp);
+}
 
-/*
- * NB: SPROP_SET must not be called if (SPROP_HAS_STUB_SETTER(sprop) &&
- * !(sprop->attrs & JSPROP_GETTER)).
- */
-#define SPROP_SET(cx,sprop,obj,obj2,vp)                                       \
-    (((sprop)->attrs & JSPROP_SETTER)                                         \
-     ? js_InternalGetOrSet(cx, obj, (sprop)->id,                              \
-                           OBJECT_TO_JSVAL((sprop)->setter), JSACC_WRITE,     \
-                           1, vp, vp)                                         \
-     : ((sprop)->attrs & JSPROP_GETTER)                                       \
-     ? (JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,                    \
-                             JSMSG_GETTER_ONLY, NULL), JS_FALSE)              \
-     : (sprop)->setter(cx, OBJ_THIS_OBJECT(cx,obj), SPROP_USERID(sprop), vp))
+static JS_INLINE JSBool
+SPROP_SET(JSContext* cx, JSScopeProperty* sprop, JSObject* obj, JSObject* obj2,
+          jsval* vp)
+{
+    JS_ASSERT(!(SPROP_HAS_STUB_SETTER(sprop) &&
+                !(sprop->attrs & JSPROP_GETTER)));
+
+    if ((sprop)->attrs & JSPROP_SETTER) {
+        return js_InternalGetOrSet(cx, obj, (sprop)->id,
+                                   OBJECT_TO_JSVAL((sprop)->setter),
+                                   JSACC_WRITE, 1, vp, vp);
+    }
+
+    if ((sprop)->attrs & JSPROP_GETTER) {
+        JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,
+                             JSMSG_GETTER_ONLY, NULL);
+        return JS_FALSE;
+    }
+
+    return sprop->setter(cx, OBJ_THIS_OBJECT(cx, obj), SPROP_USERID(sprop), vp);
+}
 
 /* Macro for common expression to test for shared permanent attributes. */
 #define SPROP_IS_SHARED_PERMANENT(sprop)                                      \
     ((~(sprop)->attrs & (JSPROP_SHARED | JSPROP_PERMANENT)) == 0)
 
 extern JSScope *
 js_GetMutableScope(JSContext *cx, JSObject *obj);