Bug 1473255 - Restore caller realm in the interpreter after calling a JITted function. r=evilpie
authorJan de Mooij <jdemooij@mozilla.com>
Thu, 05 Jul 2018 09:28:13 +0200
changeset 425140 f490048b0495e8f2e6682ab2209d1172ea1cdbe7
parent 425139 a3947599d1af5dfda180fda7bca277669ac63b1f
child 425155 35ae03d7cf2db9da4ab5ca26254d81414833cada
push id104983
push userjandemooij@gmail.com
push dateThu, 05 Jul 2018 07:28:55 +0000
treeherdermozilla-inbound@f490048b0495 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersevilpie
bugs1473255
milestone63.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 1473255 - Restore caller realm in the interpreter after calling a JITted function. r=evilpie
js/src/jit-test/tests/realms/switch-realms-scripted.js
js/src/vm/Interpreter.cpp
--- a/js/src/jit-test/tests/realms/switch-realms-scripted.js
+++ b/js/src/jit-test/tests/realms/switch-realms-scripted.js
@@ -94,8 +94,20 @@ function testException2() {
         }
     } catch (e) {
         ex = e;
     }
     assertCorrectRealm();
     assertEq(ex, 101);
 }
 testException2();
+testException2();
+
+function testException3(x) {
+    var g = newGlobal({sameCompartmentAs: this});
+    g.f1 = function(x) { if (x === max + 2) throw 1; }
+    g.evaluate("function f2(x) { try { return f1(x); } catch(e) {} }");
+    var max = 15;
+    for (var i = 0; i < max; i++)
+        g.f2(x * max + i);
+}
+testException3(0);
+testException3(1);
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -8,16 +8,17 @@
  * JavaScript bytecode interpreter.
  */
 
 #include "vm/Interpreter-inl.h"
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/Maybe.h"
+#include "mozilla/ScopeExit.h"
 #include "mozilla/Sprintf.h"
 
 #include <string.h>
 
 #include "jslibmath.h"
 #include "jsnum.h"
 
 #include "builtin/Array.h"
@@ -1417,16 +1418,17 @@ js::HandleClosingGeneratorReturn(JSConte
     }
     return ok;
 }
 
 static HandleErrorContinuation
 HandleError(JSContext* cx, InterpreterRegs& regs)
 {
     MOZ_ASSERT(regs.fp()->script()->containsPC(regs.pc));
+    MOZ_ASSERT(cx->realm() == regs.fp()->script()->realm());
 
     if (regs.fp()->script()->hasScriptCounts()) {
         PCCounts* counts = regs.fp()->script()->getThrowCounts(regs.pc);
         // If we failed to allocate, then skip the increment and continue to
         // handle the exception.
         if (counts)
             counts->numExec()++;
     }
@@ -2252,16 +2254,17 @@ CASE(JSOP_RETRVAL)
             if (cx->realm() != callerScript->realm())
                 cx->leaveRealm(callerScript->realm());
             SET_SCRIPT(callerScript);
         }
 
   jit_return:
 
         MOZ_ASSERT(CodeSpec[*REGS.pc].format & JOF_INVOKE);
+        MOZ_ASSERT(cx->realm() == script->realm());
 
         /* Resume execution in the calling frame. */
         if (MOZ_LIKELY(interpReturnOK)) {
             TypeScript::Monitor(cx, script, REGS.pc, REGS.sp[-1]);
 
             ADVANCE_AND_DISPATCH(JSOP_CALL_LENGTH);
         }
 
@@ -3203,18 +3206,26 @@ CASE(JSOP_FUNCALL)
 
     {
         MOZ_ASSERT(maybeFun);
         ReservedRooted<JSFunction*> fun(&rootFunction0, maybeFun);
         ReservedRooted<JSScript*> funScript(&rootScript0, JSFunction::getOrCreateScript(cx, fun));
         if (!funScript)
             goto error;
 
-        if (cx->realm() != funScript->realm())
+        // Enter the callee's realm if this is a cross-realm call. Use
+        // MakeScopeExit to leave this realm on all error/JIT-return paths
+        // below.
+        const bool isCrossRealm = cx->realm() != funScript->realm();
+        if (isCrossRealm)
             cx->enterRealmOf(funScript);
+        auto leaveRealmGuard = mozilla::MakeScopeExit([isCrossRealm, cx, &script] {
+            if (isCrossRealm)
+                cx->leaveRealm(script->realm());
+        });
 
         if (construct) {
             bool createSingleton = ObjectGroup::useSingletonForNewObject(cx, script, REGS.pc);
             if (!MaybeCreateThisForConstructor(cx, funScript, args, createSingleton))
                 goto error;
         }
 
         TypeMonitorCall(cx, args, construct);
@@ -3235,16 +3246,17 @@ CASE(JSOP_FUNCALL)
                 break;
             }
         }
 
         funScript = fun->nonLazyScript();
 
         if (!activation.pushInlineFrame(args, funScript, construct))
             goto error;
+        leaveRealmGuard.release(); // We leave the callee's realm when we call popInlineFrame.
     }
 
     SET_SCRIPT(REGS.fp()->script());
 
     {
         TraceLoggerEvent event(TraceLogger_Scripts, script);
         TraceLogStartEvent(logger, event);
         TraceLogStartEvent(logger, TraceLogger_Interpreter);