Bug 1259877 - Update Debugger code to use js::Call rather than Invoke. r=jorendorff
authorJeff Walden <jwalden@mit.edu>
Mon, 21 Mar 2016 16:01:18 -0700
changeset 293102 7a299a5909505d317c9ee86a236c64caef988fcf
parent 293101 b9cef6b587ac59d69506afda47df0b5b493949ed
child 293103 a6fa04f4dee918095135374f540172ae161189ec
push id75096
push userjwalden@mit.edu
push dateThu, 14 Apr 2016 00:09:53 +0000
treeherdermozilla-inbound@1e6cb22a8971 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs1259877
milestone48.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 1259877 - Update Debugger code to use js::Call rather than Invoke. r=jorendorff
js/src/vm/Debugger.cpp
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -787,18 +787,17 @@ Debugger::slowPathOnLeaveFrame(JSContext
                 RootedValue completion(cx);
                 if (!dbg->newCompletionValue(cx, status, value, &completion)) {
                     status = dbg->handleUncaughtException(ac, false);
                     break;
                 }
 
                 /* Call the onPop handler. */
                 RootedValue rval(cx);
-                bool hookOk = Invoke(cx, ObjectValue(*frameobj), handler, 1, completion.address(),
-                                     &rval);
+                bool hookOk = js::Call(cx, handler, frameobj, completion, &rval);
                 RootedValue nextValue(cx);
                 JSTrapStatus nextStatus = dbg->parseResumptionValue(ac, hookOk, rval,
                                                                     frame, pc, &nextValue);
 
                 /*
                  * At this point, we are back in the debuggee compartment, and any error has
                  * been wrapped up as a completion value.
                  */
@@ -1168,19 +1167,20 @@ Debugger::handleUncaughtExceptionHelper(
     MOZ_ASSERT(EnterDebuggeeNoExecute::isLockedInStack(cx, *this));
 
     if (cx->isExceptionPending()) {
         if (callHook && uncaughtExceptionHook) {
             RootedValue exc(cx);
             if (!cx->getPendingException(&exc))
                 return JSTRAP_ERROR;
             cx->clearPendingException();
+
             RootedValue fval(cx, ObjectValue(*uncaughtExceptionHook));
             RootedValue rv(cx);
-            if (Invoke(cx, ObjectValue(*object), fval, 1, exc.address(), &rv)) {
+            if (js::Call(cx, fval, object, exc, &rv)) {
                 return vp ? parseResumptionValueHelper(ac, true, rv, thisVForCheck, frame, *vp, false)
                           : JSTRAP_CONTINUE;
             }
         }
 
         if (cx->isExceptionPending()) {
             /*
              * We want to report the pending exception, but we want to let the
@@ -1426,28 +1426,41 @@ Debugger::parseResumptionValue(Maybe<Aut
     Maybe<HandleValue> thisArg;
     if (frame.debuggerNeedsCheckPrimitiveReturn())
         thisArg.emplace(rootThis);
 
     return parseResumptionValueHelper(ac, ok, rv, thisArg, frame, vp, callHook);
 }
 
 static bool
-CallMethodIfPresent(JSContext* cx, HandleObject obj, const char* name, int argc, Value* argv,
+CallMethodIfPresent(JSContext* cx, HandleObject obj, const char* name, size_t argc, Value* argv,
                     MutableHandleValue rval)
 {
     rval.setUndefined();
     JSAtom* atom = Atomize(cx, name, strlen(name));
     if (!atom)
         return false;
 
     RootedId id(cx, AtomToId(atom));
     RootedValue fval(cx);
-    return GetProperty(cx, obj, obj, id, &fval) &&
-           (!IsCallable(fval) || Invoke(cx, ObjectValue(*obj), fval, argc, argv, rval));
+    if (!GetProperty(cx, obj, obj, id, &fval))
+        return false;
+
+    if (!IsCallable(fval))
+        return true;
+
+    InvokeArgs args(cx);
+    if (!args.init(argc))
+        return false;
+
+    for (size_t i = 0; i < argc; i++)
+        args[i].set(argv[i]);
+
+    rval.setObject(*obj); // overwritten by successful Call
+    return js::Call(cx, fval, rval, args, rval);
 }
 
 JSTrapStatus
 Debugger::fireDebuggerStatement(JSContext* cx, MutableHandleValue vp)
 {
     RootedObject hook(cx, getHook(OnDebuggerStatement));
     MOZ_ASSERT(hook);
     MOZ_ASSERT(hook->isCallable());
@@ -1455,18 +1468,19 @@ Debugger::fireDebuggerStatement(JSContex
     Maybe<AutoCompartment> ac;
     ac.emplace(cx, object);
 
     ScriptFrameIter iter(cx);
     RootedValue scriptFrame(cx);
     if (!getScriptFrame(cx, iter, &scriptFrame))
         return handleUncaughtException(ac, false);
 
+    RootedValue fval(cx, ObjectValue(*hook));
     RootedValue rv(cx);
-    bool ok = Invoke(cx, ObjectValue(*object), ObjectValue(*hook), 1, scriptFrame.address(), &rv);
+    bool ok = js::Call(cx, fval, object, scriptFrame, &rv);
     return parseResumptionValue(ac, ok, rv, iter.abstractFramePtr(), iter.pc(), vp);
 }
 
 JSTrapStatus
 Debugger::fireExceptionUnwind(JSContext* cx, MutableHandleValue vp)
 {
     RootedObject hook(cx, getHook(OnExceptionUnwind));
     MOZ_ASSERT(hook);
@@ -1475,26 +1489,26 @@ Debugger::fireExceptionUnwind(JSContext*
     RootedValue exc(cx);
     if (!cx->getPendingException(&exc))
         return JSTRAP_ERROR;
     cx->clearPendingException();
 
     Maybe<AutoCompartment> ac;
     ac.emplace(cx, object);
 
-    JS::AutoValueArray<2> argv(cx);
-    argv[0].setUndefined();
-    argv[1].set(exc);
+    RootedValue scriptFrame(cx);
+    RootedValue wrappedExc(cx, exc);
 
     ScriptFrameIter iter(cx);
-    if (!getScriptFrame(cx, iter, argv[0]) || !wrapDebuggeeValue(cx, argv[1]))
+    if (!getScriptFrame(cx, iter, &scriptFrame) || !wrapDebuggeeValue(cx, &wrappedExc))
         return handleUncaughtException(ac, false);
 
+    RootedValue fval(cx, ObjectValue(*hook));
     RootedValue rv(cx);
-    bool ok = Invoke(cx, ObjectValue(*object), ObjectValue(*hook), 2, argv.begin(), &rv);
+    bool ok = js::Call(cx, fval, object, scriptFrame, wrappedExc, &rv);
     JSTrapStatus st = parseResumptionValue(ac, ok, rv, iter.abstractFramePtr(), iter.pc(), vp);
     if (st == JSTRAP_CONTINUE)
         cx->setPendingException(exc);
     return st;
 }
 
 JSTrapStatus
 Debugger::fireEnterFrame(JSContext* cx, AbstractFramePtr frame, MutableHandleValue vp)
@@ -1505,18 +1519,19 @@ Debugger::fireEnterFrame(JSContext* cx, 
 
     Maybe<AutoCompartment> ac;
     ac.emplace(cx, object);
 
     RootedValue scriptFrame(cx);
     if (!getScriptFrame(cx, frame, &scriptFrame))
         return handleUncaughtException(ac, false);
 
+    RootedValue fval(cx, ObjectValue(*hook));
     RootedValue rv(cx);
-    bool ok = Invoke(cx, ObjectValue(*object), ObjectValue(*hook), 1, scriptFrame.address(), &rv);
+    bool ok = js::Call(cx, fval, object, scriptFrame, &rv);
 
     return parseResumptionValue(ac, ok, rv, MagicValue(JS_UNINITIALIZED_LEXICAL), frame, vp);
 }
 
 void
 Debugger::fireNewScript(JSContext* cx, Handle<DebuggerScriptReferent> scriptReferent)
 {
     RootedObject hook(cx, getHook(OnNewScript));
@@ -1527,19 +1542,20 @@ Debugger::fireNewScript(JSContext* cx, H
     ac.emplace(cx, object);
 
     JSObject* dsobj = wrapVariantReferent(cx, scriptReferent);
     if (!dsobj) {
         handleUncaughtException(ac, false);
         return;
     }
 
-    RootedValue scriptObject(cx, ObjectValue(*dsobj));
+    RootedValue fval(cx, ObjectValue(*hook));
+    RootedValue dsval(cx, ObjectValue(*dsobj));
     RootedValue rv(cx);
-    if (!Invoke(cx, ObjectValue(*object), ObjectValue(*hook), 1, scriptObject.address(), &rv))
+    if (!js::Call(cx, fval, object, dsval, &rv))
         handleUncaughtException(ac, true);
 }
 
 void
 Debugger::fireOnGarbageCollectionHook(JSContext* cx,
                                       const JS::dbg::GarbageCollectionEvent::Ptr& gcData)
 {
     MOZ_ASSERT(observedGC(gcData->majorGCNumber()));
@@ -1553,19 +1569,20 @@ Debugger::fireOnGarbageCollectionHook(JS
     ac.emplace(cx, object);
 
     JSObject* dataObj = gcData->toJSObject(cx);
     if (!dataObj) {
         handleUncaughtException(ac, false);
         return;
     }
 
+    RootedValue fval(cx, ObjectValue(*hook));
     RootedValue dataVal(cx, ObjectValue(*dataObj));
     RootedValue rv(cx);
-    if (!Invoke(cx, ObjectValue(*object), ObjectValue(*hook), 1, dataVal.address(), &rv))
+    if (!js::Call(cx, fval, object, dataVal, &rv))
         handleUncaughtException(ac, true);
 }
 
 template <typename HookIsEnabledFun /* bool (Debugger*) */,
           typename FireHookFun /* JSTrapStatus (Debugger*) */>
 /* static */ JSTrapStatus
 Debugger::dispatchHook(JSContext* cx, HookIsEnabledFun hookIsEnabled, FireHookFun fireHook)
 {
@@ -1779,20 +1796,19 @@ Debugger::onSingleStep(JSContext* cx, Mu
             continue;
 
         Debugger* dbg = Debugger::fromChildJSObject(frame);
         EnterDebuggeeNoExecute nx(cx, *dbg);
 
         Maybe<AutoCompartment> ac;
         ac.emplace(cx, dbg->object);
 
-        const Value& handler = frame->getReservedSlot(JSSLOT_DEBUGFRAME_ONSTEP_HANDLER);
+        RootedValue fval(cx, frame->getReservedSlot(JSSLOT_DEBUGFRAME_ONSTEP_HANDLER));
         RootedValue rval(cx);
-
-        bool ok = Invoke(cx, ObjectValue(*frame), handler, 0, nullptr, &rval);
+        bool ok = js::Call(cx, fval, frame, &rval);
         JSTrapStatus st = dbg->parseResumptionValue(ac, ok, rval, iter.abstractFramePtr(),
                                                     iter.pc(), vp);
         if (st != JSTRAP_CONTINUE)
             return st;
     }
 
     vp.setUndefined();
     if (exceptionPending)
@@ -1809,25 +1825,25 @@ Debugger::fireNewGlobalObject(JSContext*
 
     Maybe<AutoCompartment> ac;
     ac.emplace(cx, object);
 
     RootedValue wrappedGlobal(cx, ObjectValue(*global));
     if (!wrapDebuggeeValue(cx, &wrappedGlobal))
         return handleUncaughtException(ac, false);
 
-    RootedValue rv(cx);
-
     // onNewGlobalObject is infallible, and thus is only allowed to return
     // undefined as a resumption value. If it returns anything else, we throw.
     // And if that happens, or if the hook itself throws, we invoke the
     // uncaughtExceptionHook so that we never leave an exception pending on the
     // cx. This allows JS_NewGlobalObject to avoid handling failures from debugger
     // hooks.
-    bool ok = Invoke(cx, ObjectValue(*object), ObjectValue(*hook), 1, wrappedGlobal.address(), &rv);
+    RootedValue rv(cx);
+    RootedValue fval(cx, ObjectValue(*hook));
+    bool ok = js::Call(cx, fval, object, wrappedGlobal, &rv);
     if (ok && !rv.isUndefined()) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
                              JSMSG_DEBUG_RESUMPTION_VALUE_DISALLOWED);
         ok = false;
     }
     // NB: Even though we don't care about what goes into it, we have to pass vp
     // to handleUncaughtException so that it parses resumption values from the
     // uncaughtExceptionHook and tells the caller whether we should execute the
@@ -1985,19 +2001,19 @@ Debugger::firePromiseHook(JSContext* cx,
     ac.emplace(cx, object);
 
     RootedValue dbgObj(cx, ObjectValue(*promise));
     if (!wrapDebuggeeValue(cx, &dbgObj))
         return handleUncaughtException(ac, false);
 
     // Like onNewGlobalObject, the Promise hooks are infallible and the comments
     // in |Debugger::fireNewGlobalObject| apply here as well.
-
+    RootedValue fval(cx, ObjectValue(*hookObj));
     RootedValue rv(cx);
-    bool ok = Invoke(cx, ObjectValue(*object), ObjectValue(*hookObj), 1, dbgObj.address(), &rv);
+    bool ok = js::Call(cx, fval, object, dbgObj, &rv);
     if (ok && !rv.isUndefined()) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr,
                              JSMSG_DEBUG_RESUMPTION_VALUE_DISALLOWED);
         ok = false;
     }
 
     JSTrapStatus status = ok ? JSTRAP_CONTINUE
                              : handleUncaughtException(ac, vp, true);
@@ -8482,18 +8498,31 @@ ApplyOrCall(JSContext* cx, unsigned argc
              return false;
     }
 
     /*
      * Call the function. Use receiveCompletionValue to return to the debugger
      * compartment and populate args.rval().
      */
     LeaveDebuggeeNoExecute nnx(cx);
+
     RootedValue rval(cx);
-    bool ok = Invoke(cx, thisv, calleev, callArgc, callArgv, &rval);
+    bool ok;
+    {
+        InvokeArgs args(cx);
+
+        ok = args.init(callArgc);
+        if (ok) {
+            for (size_t i = 0; i < callArgc; i++)
+                args[i].set(callArgv[i]);
+
+            ok = js::Call(cx, calleev, thisv, args, &rval);
+        }
+    }
+
     return dbg->receiveCompletionValue(ac, ok, rval, args.rval());
 }
 
 static bool
 DebuggerObject_apply(JSContext* cx, unsigned argc, Value* vp)
 {
     return ApplyOrCall(cx, argc, vp, ApplyMode);
 }