Fix JS_TraceChildren crash triggered by findReferences. Bug 708261, r=jimb.
authorJason Orendorff <jorendorff@mozilla.com>
Thu, 08 Dec 2011 14:23:31 -0600
changeset 83957 e7785a537e5dc4fd761d72c2db947f0c45051615
parent 83956 1bf5f690b3826f294fc1e9b6a3e9a5430106b439
child 83958 5eb308b7f2b217e5e66503ca6d676b283283b87c
push id519
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 00:38:35 +0000
treeherdermozilla-beta@788ea1ef610b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimb
bugs708261
milestone11.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Fix JS_TraceChildren crash triggered by findReferences. Bug 708261, r=jimb.
js/src/jsgcmark.cpp
js/src/tests/js1_8_5/extensions/findReferences-01.js
js/src/tests/js1_8_5/extensions/findReferences-02.js
--- a/js/src/jsgcmark.cpp
+++ b/js/src/jsgcmark.cpp
@@ -180,26 +180,16 @@ MarkObjectUnbarriered(JSTracer *trc, JSO
 {
     JS_ASSERT(trc);
     JS_ASSERT(obj);
     JS_SET_TRACING_NAME(trc, name);
     Mark(trc, obj);
 }
 
 void
-MarkObjectWithPrinterUnbarriered(JSTracer *trc, JSObject *obj, JSTraceNamePrinter printer,
-                                 const void *arg, size_t index)
-{
-    JS_ASSERT(trc);
-    JS_ASSERT(obj);
-    JS_SET_TRACING_DETAILS(trc, printer, arg, index);
-    Mark(trc, obj);
-}
-
-void
 MarkObject(JSTracer *trc, const MarkablePtr<JSObject> &obj, const char *name)
 {
     MarkObjectUnbarriered(trc, obj.value, name);
 }
 
 void
 MarkScriptUnbarriered(JSTracer *trc, JSScript *script, const char *name)
 {
@@ -670,40 +660,16 @@ MarkRootRange(JSTracer *trc, jsid *beg, 
 }
 
 void
 MarkRootRange(JSTracer *trc, size_t len, jsid *vec, const char *name)
 {
     MarkIdRangeUnbarriered(trc, len, vec, name);
 }
 
-static void
-PrintPropertyId(char *buf, size_t bufsize, jsid propid, const char *label)
-{
-    JS_ASSERT(!JSID_IS_VOID(propid));
-    if (JSID_IS_ATOM(propid)) {
-        size_t n = PutEscapedString(buf, bufsize, JSID_TO_ATOM(propid), 0);
-        if (n < bufsize)
-            JS_snprintf(buf + n, bufsize - n, " %s", label);
-    } else if (JSID_IS_INT(propid)) {
-        JS_snprintf(buf, bufsize, "%d %s", JSID_TO_INT(propid), label);
-    } else {
-        JS_snprintf(buf, bufsize, "<object> %s", label);
-    }
-}
-
-static void
-PrintPropertyGetterOrSetter(JSTracer *trc, char *buf, size_t bufsize)
-{
-    JS_ASSERT(trc->debugPrinter == PrintPropertyGetterOrSetter);
-    Shape *shape = (Shape *)trc->debugPrintArg;
-    PrintPropertyId(buf, bufsize, shape->propid(),
-                    trc->debugPrintIndex ? js_setter_str : js_getter_str); 
-}
-
 static inline void
 ScanValue(GCMarker *gcmarker, const Value &v)
 {
     if (v.isMarkable()) {
         JSGCTraceKind kind = v.gcKind();
         if (kind == JSTRACE_STRING) {
             PushMarkStack(gcmarker, v.toString());
         } else {
@@ -994,25 +960,20 @@ MarkChildren(JSTracer *trc, const Shape 
     MarkShapeChildrenAcyclic(trc, shape);
     if (shape->previous())
         MarkShape(trc, shape->previous(), "parent");
 }
 
 void
 MarkChildren(JSTracer *trc, BaseShape *base)
 {
-    if (base->hasGetterObject()) {
-        MarkObjectWithPrinterUnbarriered(trc, base->getterObject(),
-                                         PrintPropertyGetterOrSetter, base, 0);
-    }
-
-    if (base->hasSetterObject()) {
-        MarkObjectWithPrinterUnbarriered(trc, base->setterObject(),
-                                         PrintPropertyGetterOrSetter, base, 0);
-    }
+    if (base->hasGetterObject())
+        MarkObjectUnbarriered(trc, base->getterObject(), "getter");
+    if (base->hasSetterObject())
+        MarkObjectUnbarriered(trc, base->setterObject(), "setter");
 
     if (base->isOwned())
         MarkBaseShapeUnbarriered(trc, base->baseUnowned(), "base");
 
     if (JSObject *parent = base->getObjectParent())
         MarkObjectUnbarriered(trc, parent, "parent");
 }
 
--- a/js/src/tests/js1_8_5/extensions/findReferences-01.js
+++ b/js/src/tests/js1_8_5/extensions/findReferences-01.js
@@ -6,41 +6,41 @@ if (typeof findReferences == "function")
     function C() {}
     var o = new C;
     o.x = {};               // via ordinary property
     o[42] = {};             // via numeric property
     o.myself = o;           // self-references should be reported
     o.alsoMyself = o;       // multiple self-references should all be reported
 
     assertEq(referencesVia(o, 'type; type_proto', C.prototype), true);
-    assertEq(referencesVia(o, 'parent', this), true);
+    assertEq(referencesVia(o, 'shape; base; parent', this), true);
     assertEq(referencesVia(o, 'x', o.x), true);
     assertEq(referencesVia(o, '42', o[42]), true);
     assertEq(referencesVia(o, 'myself', o), true);
     assertEq(referencesVia(o, 'alsoMyself', o), true);
 
     function g() { return 42; }
     function s(v) { }
     var p = Object.defineProperty({}, 'a', { get:g, set:s });
-    assertEq(referencesVia(p, 'shape; a getter', g), true);
-    assertEq(referencesVia(p, 'shape; a setter', s), true);
+    assertEq(referencesVia(p, 'shape; base; getter', g), true);
+    assertEq(referencesVia(p, 'shape; base; setter', s), true);
 
     // If there are multiple objects with the same shape referring to a getter
     // or setter, findReferences should get all of them, even though the shape
     // gets 'marked' the first time we visit it.
     var q = Object.defineProperty({}, 'a', { get:g, set:s });
-    assertEq(referencesVia(p, 'shape; a getter', g), true);
-    assertEq(referencesVia(q, 'shape; a getter', g), true);
+    assertEq(referencesVia(p, 'shape; base; getter', g), true);
+    assertEq(referencesVia(q, 'shape; base; getter', g), true);
 
     // If we extend each object's shape chain, both should still be able to
     // reach the getter, even though the two shapes are each traversed twice.
     p.b = 9;
     q.b = 9;
-    assertEq(referencesVia(p, 'shape; a getter', g), true);
-    assertEq(referencesVia(q, 'shape; a getter', g), true);
+    assertEq(referencesVia(p, 'shape; parent; base; getter', g), true);
+    assertEq(referencesVia(q, 'shape; parent; base; getter', g), true);
 
     // These are really just ordinary own property references.
     assertEq(referencesVia(C, 'prototype', Object.getPrototypeOf(o)), true);
     assertEq(referencesVia(Object.getPrototypeOf(o), 'constructor', C), true);
 
     // Dense arrays should work, too.
     a = [];
     a[1] = o;
--- a/js/src/tests/js1_8_5/extensions/findReferences-02.js
+++ b/js/src/tests/js1_8_5/extensions/findReferences-02.js
@@ -8,21 +8,21 @@ if (typeof findReferences == "function")
      })();
 
     var o = ({});
 
     function returnFlat(x) { return function flat() { return x; }; }
     assertEq(referencesVia(returnFlat(o), 'upvars[0]', o), true);
 
     function returnHeavy(y) { eval(''); return function heavy() { return y; }; }
-    assertEq(referencesVia(returnHeavy(o), 'parent; y', o), true);
-    assertEq(referencesVia(returnHeavy(o), 'parent; parent', this), true);
+    assertEq(referencesVia(returnHeavy(o), 'fun_callscope; y', o), true);
+    assertEq(referencesVia(returnHeavy(o), 'fun_callscope; shape; base; parent', this), true);
 
     function returnBlock(z) { eval(''); let(w = z) { return function block() { return w; }; }; }
-    assertEq(referencesVia(returnBlock(o), 'parent; w', o), true);
+    assertEq(referencesVia(returnBlock(o), 'fun_callscope; w', o), true);
 
     function returnWithObj(v) { with(v) return function withObj() { return u; }; }
-    assertEq(referencesVia(returnWithObj(o), 'parent; type; type_proto', o), true);
+    assertEq(referencesVia(returnWithObj(o), 'fun_callscope; type; type_proto', o), true);
 
     reportCompare(true, true);
 } else {
     reportCompare(true, true, "test skipped: findReferences is not a function");
 }