Bug 799272: Implement Debugger.Object.prototype.unwrap. r=luke
authorJim Blandy <jimb@mozilla.com>
Sat, 13 Oct 2012 16:04:16 -0700
changeset 110185 147285c880287c930ba2d1afb197d0da7837b4d7
parent 110184 708db1ae8d66f218b3dea706729846d69737daef
child 110186 f67e5b827cdf0817f8721cbdc05c14210f6d2e21
push id16389
push userjblandy@mozilla.com
push dateSat, 13 Oct 2012 23:08:52 +0000
treeherdermozilla-inbound@801ed9c31fd5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs799272
milestone19.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
Bug 799272: Implement Debugger.Object.prototype.unwrap. r=luke
js/src/jit-test/tests/debug/Object-unwrap-01.js
js/src/jit-test/tests/debug/Object-unwrap-02.js
js/src/vm/Debugger.cpp
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Object-unwrap-01.js
@@ -0,0 +1,23 @@
+// Check Debugger.Object.prototype.unwrap surfaces.
+
+load(libdir + 'asserts.js');
+
+var dbg = new Debugger();
+var g = newGlobal();
+var gw = dbg.addDebuggee(g);
+
+assertEq(Object.getOwnPropertyDescriptor(gw, 'unwrap'), undefined);
+var d = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(gw), 'unwrap');
+assertEq(d.enumerable, false);
+assertEq(d.configurable, true);
+assertEq(d.writable, true);
+
+assertEq(typeof gw.unwrap, "function");
+assertEq(gw.unwrap.length, 0);
+assertEq(gw.unwrap.name, "unwrap");
+
+// It can be called.
+gw.unwrap();
+
+// You shouldn't be able to apply the accessor to the prototype.
+assertThrowsInstanceOf(function () { Debugger.Object.prototype.unwrap(); }, TypeError);
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/debug/Object-unwrap-02.js
@@ -0,0 +1,23 @@
+// Debugger.Object.prototype.unwrap unwraps Debugger.Objects referring to
+// cross-compartment wrappers.
+
+var dbg = new Debugger();
+
+var g1 = newGlobal();
+var dg1 = dbg.addDebuggee(g1);
+assertEq(dg1.unwrap(), dg1);
+
+var g2 = newGlobal();
+var dg2 = dbg.addDebuggee(g2);
+
+var dg1g2 = dg1.makeDebuggeeValue(g2);
+assertEq(dg1g2.global, dg1);
+assertEq(dg1g2.unwrap(), dg2);
+
+// Try an ordinary object, not a global.
+var g2o = g2.Object();
+var dg2o = dg2.makeDebuggeeValue(g2o);
+var dg1g2o = dg1.makeDebuggeeValue(g2o);
+assertEq(dg1g2o.global, dg1);
+assertEq(dg1g2o.unwrap(), dg2o);
+assertEq(dg1g2o.unwrap().unwrap(), dg2o);
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -4273,16 +4273,42 @@ DebuggerObject_evalInGlobalWithBindings(
     THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "evalInGlobalWithBindings", args, dbg, referent);
     if (!RequireGlobalObject(cx, args.thisv(), referent))
         return false;
 
     return DebuggerGenericEval(cx, "Debugger.Object.prototype.evalInGlobalWithBindings",
                                args[0], &args[1], vp, dbg, referent, NULL);
 }
 
+static JSBool
+DebuggerObject_unwrap(JSContext *cx, unsigned argc, Value *vp)
+{
+    THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "unwrap", args, dbg, referent);
+    JSObject *unwrapped = UnwrapOneChecked(cx, referent);
+    if (!unwrapped) {
+        // If we were terminated, then pass that along.
+        if (!cx->isExceptionPending())
+            return false;
+
+        // If the unwrap operation threw an exception, assume it's a
+        // security exception, and return null. It seems like the wrappers
+        // in use in Firefox just call JS_ReportError, so we have no way to
+        // distinguish genuine should-not-unwrap errors from other kinds of
+        // errors.
+        cx->clearPendingException();
+        vp->setNull();
+        return true;
+    }
+
+    *vp = ObjectValue(*unwrapped);
+    if (!dbg->wrapDebuggeeValue(cx, vp))
+        return false;
+    return true;
+}
+
 static JSPropertySpec DebuggerObject_properties[] = {
     JS_PSG("proto", DebuggerObject_getProto, 0),
     JS_PSG("class", DebuggerObject_getClass, 0),
     JS_PSG("callable", DebuggerObject_getCallable, 0),
     JS_PSG("name", DebuggerObject_getName, 0),
     JS_PSG("displayName", DebuggerObject_getDisplayName, 0),
     JS_PSG("parameterNames", DebuggerObject_getParameterNames, 0),
     JS_PSG("script", DebuggerObject_getScript, 0),
@@ -4303,16 +4329,17 @@ static JSFunctionSpec DebuggerObject_met
     JS_FN("isSealed", DebuggerObject_isSealed, 0, 0),
     JS_FN("isFrozen", DebuggerObject_isFrozen, 0, 0),
     JS_FN("isExtensible", DebuggerObject_isExtensible, 0, 0),
     JS_FN("apply", DebuggerObject_apply, 0, 0),
     JS_FN("call", DebuggerObject_call, 0, 0),
     JS_FN("makeDebuggeeValue", DebuggerObject_makeDebuggeeValue, 1, 0),
     JS_FN("evalInGlobal", DebuggerObject_evalInGlobal, 1, 0),
     JS_FN("evalInGlobalWithBindings", DebuggerObject_evalInGlobalWithBindings, 2, 0),
+    JS_FN("unwrap", DebuggerObject_unwrap, 0, 0),
     JS_FS_END
 };
 
 
 /*** Debugger.Environment ************************************************************************/
 
 static void
 DebuggerEnv_trace(JSTracer *trc, RawObject obj)