[INFER] Write barrier for sets to length on non-array objects in array natives, bug 619338.
authorBrian Hackett <bhackett1024@gmail.com>
Wed, 22 Dec 2010 22:03:22 -0800
changeset 74688 6b5c2cb89388d73a1ac320a32b92ae410d5feb9b
parent 74687 b1a613d3b6e3c607fa20b46d87ab3b6fe02a7d51
child 74689 32d51249b97cab20aafb2b66f7105492ff472b1d
push id2
push userbsmedberg@mozilla.com
push dateFri, 19 Aug 2011 14:38:13 +0000
bugs619338
milestone2.0b8pre
[INFER] Write barrier for sets to length on non-array objects in array natives, bug 619338.
js/src/jit-test/tests/basic/arrayNatives.js
js/src/jsarray.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/basic/arrayNatives.js
@@ -0,0 +1,18 @@
+
+/* Array natives applied to non-arrays. */
+
+var oa = {};
+Array.pop(oa);
+assertEq(oa.length, 0);
+
+var ob = {};
+Array.push(ob, "twelve");
+assertEq(ob.length, 1);
+
+var oc = {};
+Array.shift(oc);
+assertEq(oc.length, 0);
+
+var od = {};
+Array.unshift(od, "eight");
+assertEq(od.length, 1);
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -561,16 +561,24 @@ SetOrDeleteArrayElement(JSContext *cx, J
 JSBool
 js_SetLengthProperty(JSContext *cx, JSObject *obj, jsdouble length)
 {
     Value v;
     jsid id;
 
     v.setNumber(length);
     id = ATOM_TO_JSID(cx->runtime->atomState.lengthAtom);
+
+    /*
+     * Arrays are already known to have lengths (if the length overflows, it will
+     * be caught by setArrayLength).
+     */
+    if (!obj->isArray())
+        cx->addTypePropertyId(obj->getType(), id, v);
+
     /* We don't support read-only array length yet. */
     return obj->setProperty(cx, id, &v, false);
 }
 
 JSBool
 js_HasLengthProperty(JSContext *cx, JSObject *obj, jsuint *lengthp)
 {
     JSErrorReporter older = JS_SetErrorReporter(cx, NULL);
@@ -2026,21 +2034,19 @@ array_push_slowly(JSContext *cx, JSObjec
         return JS_FALSE;
     if (!InitArrayElements(cx, obj, length, argc, argv))
         return JS_FALSE;
 
     /* Per ECMA-262, return the new array length. */
     jsdouble newlength = length + jsdouble(argc);
     rval->setNumber(newlength);
 
-    /* watch for length overflowing to a double, and report to type inference. */
-    if (!rval->isInt32()) {
+    /* watch for length overflowing to a double. */
+    if (!rval->isInt32())
         cx->markTypeCallerOverflow();
-        cx->addTypeProperty(obj->getType(), "length", *rval);
-    }
 
     return js_SetLengthProperty(cx, obj, newlength);
 }
 
 static JSBool
 array_push1_dense(JSContext* cx, JSObject* obj, const Value &v, Value *rval)
 {
     uint32 length = obj->getArrayLength();
@@ -2298,40 +2304,49 @@ array_unshift(JSContext *cx, uintN argc,
 
         newlen += argc;
     }
     if (!js_SetLengthProperty(cx, obj, newlen))
         return JS_FALSE;
 
     /* Follow Perl by returning the new array length. */
     vp->setNumber(newlen);
+
+    /* watch for length overflowing to a double. */
+    if (!vp->isInt32())
+        cx->markTypeCallerOverflow();
+
     return JS_TRUE;
 }
 
 static JSBool
 array_splice(JSContext *cx, uintN argc, Value *vp)
 {
     jsuint length, begin, end, count, delta, last;
     JSBool hole;
 
     JSObject *obj = ComputeThisFromVp(cx, vp);
 
     /* Get the type of the result object. */
     TypeObject *type;
     if (obj && obj->isArray()) {
+        /*
+         * :FIXME: This is getting a type whose prototype is that of the
+         * argument, even if it is the Array.prototype on a different
+         * global than the current frame.
+         */
         type = obj->getType();
     } else {
         /*
          * Make a new type object for the return value.  This is an unexpected
          * result of the call so mark it at the callsite.
          */
-        type = cx->getTypeCallerInitObject(true);
+        type = cx->getTypeNewObject(JSProto_Array);
         if (!type)
             return JS_FALSE;
-        cx->markTypeObjectUnknownProperties(type);
         cx->markTypeCallerUnexpected((jstype) type);
     }
 
     if (cx->isTypeCallerMonitored())
         cx->markTypeObjectUnknownProperties(type);
 
     /*
      * Create a new array value to return.  Our ECMA v2 proposal specs
@@ -2633,26 +2648,26 @@ array_slice(JSContext *cx, uintN argc, V
     }
 
     if (begin > end)
         begin = end;
 
     /* Get the type object for the returned array. */
     TypeObject *type;
     if (obj->isArray()) {
+        /* :FIXME: Same issue as array_splice. */
         type = obj->getType();
     } else {
         /*
          * Make a new type object for the return value.  This is an unexpected
          * result of the call so mark it at the callsite.
          */
-        type = cx->getTypeCallerInitObject(true);
+        type = cx->getTypeNewObject(JSProto_Array);
         if (!type)
             return JS_FALSE;
-        cx->markTypeObjectUnknownProperties(type);
         cx->markTypeCallerUnexpected((jstype) type);
     }
 
     if (cx->isTypeCallerMonitored())
         cx->markTypeObjectUnknownProperties(type);
 
     if (obj->isDenseArray() && end <= obj->getDenseArrayCapacity() &&
         !js_PrototypeHasIndexedProperties(cx, obj)) {
@@ -3014,18 +3029,21 @@ array_some(JSContext *cx, uintN argc, Va
 
 static JSBool
 array_every(JSContext *cx, uintN argc, Value *vp)
 {
     return array_extra(cx, EVERY, argc, vp);
 }
 #endif
 
-// TODO: these handlers only deal with receiver types of arrays.
-// need to generalize to other array-like objects (strings, what else?).
+/*
+ * These handlers deal with objects of type other than arrays, except for updates
+ * of the 'length' property. Sets of length on non-arrays and overflowing length
+ * on arrays are both handled by write barriers within the natives.
+ */
 
 static void array_TypeSort(JSContext *cx, JSTypeFunction *jsfun, JSTypeCallsite *jssite)
 {
 #ifdef JS_TYPE_INFERENCE
     TypeCallsite *site = Valueify(jssite);
 
     site->forceThisTypes(cx);