mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Add initial support for Debug.prototype.uncaughtExceptionHook.
This commit is contained in:
parent
f98bcedaf3
commit
49262897d7
@ -115,25 +115,39 @@ CheckThisClass(JSContext *cx, Value *vp, Class *clasp, const char *fnname)
|
||||
|
||||
Debug::Debug(JSObject *dbg, JSObject *hooks, JSCompartment *compartment)
|
||||
: object(dbg), debuggeeCompartment(compartment), hooksObject(hooks),
|
||||
enabled(true), hasDebuggerHandler(false)
|
||||
uncaughtExceptionHook(NULL), enabled(true), hasDebuggerHandler(false)
|
||||
{
|
||||
}
|
||||
|
||||
JSTrapStatus
|
||||
Debug::fireUncaughtExceptionHook(JSContext *cx)
|
||||
Debug::handleUncaughtException(AutoCompartment &ac, Value *vp, bool callHook)
|
||||
{
|
||||
// FIXME
|
||||
JS_ReportPendingException(cx);
|
||||
JS_ClearPendingException(cx);
|
||||
JSContext *cx = ac.context;
|
||||
if (cx->isExceptionPending()) {
|
||||
if (callHook && uncaughtExceptionHook) {
|
||||
Value fval = ObjectValue(*uncaughtExceptionHook);
|
||||
Value exc = cx->getPendingException();
|
||||
Value rv;
|
||||
cx->clearPendingException();
|
||||
if (ExternalInvoke(cx, UndefinedValue(), fval, 1, &exc, &rv))
|
||||
return parseResumptionValue(ac, true, rv, vp, false);
|
||||
}
|
||||
|
||||
if (cx->isExceptionPending()) {
|
||||
JS_ReportPendingException(cx);
|
||||
cx->clearPendingException();
|
||||
}
|
||||
}
|
||||
return JSTRAP_ERROR;
|
||||
}
|
||||
|
||||
JSTrapStatus
|
||||
Debug::parseResumptionValue(AutoCompartment &ac, bool ok, const Value &rv, Value *vp)
|
||||
Debug::parseResumptionValue(AutoCompartment &ac, bool ok, const Value &rv, Value *vp,
|
||||
bool callHook)
|
||||
{
|
||||
vp->setUndefined();
|
||||
if (!ok)
|
||||
return fireUncaughtExceptionHook(ac.context);
|
||||
return handleUncaughtException(ac, vp, callHook);
|
||||
if (rv.isUndefined())
|
||||
return JSTRAP_CONTINUE;
|
||||
if (rv.isNull())
|
||||
@ -153,18 +167,18 @@ Debug::parseResumptionValue(AutoCompartment &ac, bool ok, const Value &rv, Value
|
||||
!shape->isDataDescriptor())
|
||||
{
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_DEBUG_BAD_RESUMPTION);
|
||||
return fireUncaughtExceptionHook(cx);
|
||||
return handleUncaughtException(ac, vp, callHook);
|
||||
}
|
||||
|
||||
if (!js_NativeGet(cx, obj, obj, shape, 0, vp))
|
||||
return fireUncaughtExceptionHook(cx);
|
||||
return handleUncaughtException(ac, vp, callHook);
|
||||
|
||||
// Throwing or returning objects is not yet supported. It requires
|
||||
// unwrapping.
|
||||
if (vp->isObject()) {
|
||||
vp->setUndefined();
|
||||
NotImplemented(cx);
|
||||
return fireUncaughtExceptionHook(cx);
|
||||
return handleUncaughtException(ac, vp, callHook);
|
||||
}
|
||||
|
||||
ac.leave();
|
||||
@ -281,8 +295,9 @@ void
|
||||
Debug::trace(JSTracer *trc, JSObject *obj)
|
||||
{
|
||||
if (Debug *dbg = (Debug *) obj->getPrivate()) {
|
||||
if (dbg->hooksObject)
|
||||
MarkObject(trc, *dbg->hooksObject, "hooks");
|
||||
MarkObject(trc, *dbg->hooksObject, "hooks");
|
||||
if (dbg->uncaughtExceptionHook)
|
||||
MarkObject(trc, *dbg->uncaughtExceptionHook, "hooks");
|
||||
}
|
||||
}
|
||||
|
||||
@ -325,7 +340,7 @@ JSBool
|
||||
Debug::getHooks(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
THISOBJ(cx, vp, Debug, "get hooks", thisobj, dbg);
|
||||
vp->setObjectOrNull(dbg->hooksObject);
|
||||
vp->setObject(*dbg->hooksObject);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -366,6 +381,26 @@ Debug::setEnabled(JSContext *cx, uintN argc, Value *vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
Debug::getUncaughtExceptionHook(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
THISOBJ(cx, vp, Debug, "get uncaughtExceptionHook", thisobj, dbg);
|
||||
vp->setObjectOrNull(dbg->uncaughtExceptionHook);
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
Debug::setUncaughtExceptionHook(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
REQUIRE_ARGC("Debug.set uncaughtExceptionHook", 1);
|
||||
THISOBJ(cx, vp, Debug, "set uncaughtExceptionHook", thisobj, dbg);
|
||||
if (!vp[2].isObjectOrNull())
|
||||
return ReportObjectRequired(cx);
|
||||
dbg->uncaughtExceptionHook = vp[2].toObjectOrNull();
|
||||
vp->setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
Debug::construct(JSContext *cx, uintN argc, Value *vp)
|
||||
{
|
||||
@ -415,6 +450,8 @@ Debug::construct(JSContext *cx, uintN argc, Value *vp)
|
||||
JSPropertySpec Debug::properties[] = {
|
||||
JS_PSGS("hooks", Debug::getHooks, Debug::setHooks, 0),
|
||||
JS_PSGS("enabled", Debug::getEnabled, Debug::setEnabled, 0),
|
||||
JS_PSGS("uncaughtExceptionHook", Debug::getUncaughtExceptionHook,
|
||||
Debug::setUncaughtExceptionHook, 0),
|
||||
JS_PS_END
|
||||
};
|
||||
|
||||
|
@ -56,15 +56,16 @@ class Debug {
|
||||
JSObject *object; // The Debug object. Strong reference.
|
||||
JSCompartment *debuggeeCompartment; // Weak reference.
|
||||
JSObject *hooksObject; // See Debug.prototype.hooks. Strong reference.
|
||||
|
||||
JSObject *uncaughtExceptionHook; // Strong reference.
|
||||
bool enabled;
|
||||
|
||||
// True if hooksObject had a debuggerHandler property when the hooks
|
||||
// property was set.
|
||||
bool hasDebuggerHandler;
|
||||
|
||||
JSTrapStatus fireUncaughtExceptionHook(JSContext *cx);
|
||||
JSTrapStatus parseResumptionValue(AutoCompartment &ac, bool ok, const Value &rv, Value *vp);
|
||||
JSTrapStatus handleUncaughtException(AutoCompartment &ac, Value *vp, bool callHook);
|
||||
JSTrapStatus parseResumptionValue(AutoCompartment &ac, bool ok, const Value &rv, Value *vp,
|
||||
bool callHook = true);
|
||||
|
||||
static void trace(JSTracer *trc, JSObject *obj);
|
||||
static void finalize(JSContext *cx, JSObject *obj);
|
||||
@ -74,6 +75,8 @@ class Debug {
|
||||
static JSBool setHooks(JSContext *cx, uintN argc, Value *vp);
|
||||
static JSBool getEnabled(JSContext *cx, uintN argc, Value *vp);
|
||||
static JSBool setEnabled(JSContext *cx, uintN argc, Value *vp);
|
||||
static JSBool getUncaughtExceptionHook(JSContext *cx, uintN argc, Value *vp);
|
||||
static JSBool setUncaughtExceptionHook(JSContext *cx, uintN argc, Value *vp);
|
||||
static JSBool construct(JSContext *cx, uintN argc, Value *vp);
|
||||
static JSPropertySpec properties[];
|
||||
|
||||
|
25
js/src/tests/js1_8_5/extensions/debug-object-18.js
Normal file
25
js/src/tests/js1_8_5/extensions/debug-object-18.js
Normal file
@ -0,0 +1,25 @@
|
||||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
// Uncaught exceptions in the debugger itself are delivered to the
|
||||
// uncaughtExceptionHook.
|
||||
|
||||
var g = newGlobal('new-compartment');
|
||||
var dbg = new Debug(g);
|
||||
var log;
|
||||
dbg.hooks = {
|
||||
debuggerHandler: function () {
|
||||
log += 'x';
|
||||
throw new TypeError("fail");
|
||||
}
|
||||
};
|
||||
dbg.uncaughtExceptionHook = function (exc) {
|
||||
assertEq(exc instanceof TypeError, true);
|
||||
log += '!';
|
||||
};
|
||||
|
||||
log = '';
|
||||
g.eval("debugger");
|
||||
assertEq(log, 'x!');
|
||||
|
||||
reportCompare(0, 0, 'ok');
|
34
js/src/tests/js1_8_5/extensions/debug-object-19.js
Normal file
34
js/src/tests/js1_8_5/extensions/debug-object-19.js
Normal file
@ -0,0 +1,34 @@
|
||||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
// uncaughtExceptionHook returns a resumption value.
|
||||
|
||||
var g = newGlobal('new-compartment');
|
||||
var dbg = new Debug(g);
|
||||
var rv;
|
||||
dbg.hooks = {debuggerHandler: function () { throw 15; }};
|
||||
dbg.uncaughtExceptionHook = function (exc) {
|
||||
assertEq(exc, 15);
|
||||
return rv;
|
||||
};
|
||||
|
||||
// case 1: undefined
|
||||
rv = undefined;
|
||||
g.eval("debugger");
|
||||
|
||||
// case 2: throw
|
||||
rv = {throw: 57};
|
||||
var result;
|
||||
try {
|
||||
g.eval("debugger");
|
||||
result = 'no exception thrown';
|
||||
} catch (exc) {
|
||||
result = 'caught ' + exc;
|
||||
}
|
||||
assertEq(result, 'caught 57');
|
||||
|
||||
// case 3: return
|
||||
rv = {return: 42};
|
||||
assertEq(g.eval("debugger;"), 42);
|
||||
|
||||
reportCompare(0, 0, 'ok');
|
32
js/src/tests/js1_8_5/extensions/debug-object-20.js
Normal file
32
js/src/tests/js1_8_5/extensions/debug-object-20.js
Normal file
@ -0,0 +1,32 @@
|
||||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/licenses/publicdomain/
|
||||
|
||||
// uncaughtExceptionHook resumption value other than undefined causes further
|
||||
// hooks to be skipped.
|
||||
|
||||
var g = newGlobal('new-compartment');
|
||||
var log;
|
||||
|
||||
function makeDebug(g, name) {
|
||||
var dbg = new Debug(g);
|
||||
dbg.hooks = {
|
||||
debuggerHandler: function () {
|
||||
log += name;
|
||||
throw new Error(name);
|
||||
}
|
||||
};
|
||||
dbg.uncaughtExceptionHook = function (exc) {
|
||||
assertEq(exc.message, name);
|
||||
return name == "2" ? {return: 42} : undefined;
|
||||
};
|
||||
}
|
||||
|
||||
var arr = [];
|
||||
for (var i = 0; i < 6; i++)
|
||||
arr[i] = makeDebug(g, "" + i);
|
||||
|
||||
log = '';
|
||||
assertEq(g.eval("debugger;"), 42);
|
||||
assertEq(log, "012");
|
||||
|
||||
reportCompare(0, 0, 'ok');
|
@ -58,3 +58,6 @@ skip-if(!xulRuntime.shell) script debug-object-14.js
|
||||
skip-if(!xulRuntime.shell) script debug-object-15.js
|
||||
skip-if(!xulRuntime.shell) script debug-object-16.js
|
||||
skip-if(!xulRuntime.shell) script debug-object-17.js
|
||||
skip-if(!xulRuntime.shell) script debug-object-18.js
|
||||
skip-if(!xulRuntime.shell) script debug-object-19.js
|
||||
skip-if(!xulRuntime.shell) script debug-object-20.js
|
||||
|
Loading…
Reference in New Issue
Block a user