Bug 1395360 - Add ExecuteInNonSyntacticGlobal to jsfriendapi r=jorendorff
authorTed Campbell <tcampbell@mozilla.com>
Sat, 02 Sep 2017 13:00:20 -0400
changeset 429094 d731723c09f704c5063140644b5916615261307e
parent 429093 d89ac77cac51787685fe4c2a8a87776765593082
child 429095 f7475262b1cfe886391d2affc7bf9fef8e1cfea6
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs1395360
milestone57.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 1395360 - Add ExecuteInNonSyntacticGlobal to jsfriendapi r=jorendorff This API is for use by mozJSComponentLoader to load JSMs into a NonSyntacticVariablesObject with a shared global. MozReview-Commit-ID: LtGdY4ULy45
js/src/builtin/Eval.cpp
js/src/jsapi-tests/moz.build
js/src/jsapi-tests/testExecuteInJSMEnvironment.cpp
js/src/jsfriendapi.h
--- a/js/src/builtin/Eval.cpp
+++ b/js/src/builtin/Eval.cpp
@@ -486,8 +486,53 @@ js::ExecuteInGlobalAndReturnScope(JSCont
         return false;
 
     if (!ExecuteInNonSyntacticGlobalInternal(cx, global, scriptArg, varEnv, lexEnv))
         return false;
 
     envArg.set(lexEnv);
     return true;
 }
+
+JS_FRIEND_API(JSObject*)
+js::NewJSMEnvironment(JSContext* cx)
+{
+    RootedObject varEnv(cx, NonSyntacticVariablesObject::create(cx));
+    if (!varEnv)
+        return nullptr;
+
+    // Force LexicalEnvironmentObject to be created
+    MOZ_ASSERT(!cx->compartment()->getNonSyntacticLexicalEnvironment(varEnv));
+    if (!cx->compartment()->getOrCreateNonSyntacticLexicalEnvironment(cx, varEnv))
+        return nullptr;
+
+    return varEnv;
+}
+
+JS_FRIEND_API(bool)
+js::ExecuteInJSMEnvironment(JSContext* cx, HandleScript scriptArg, HandleObject varEnv)
+{
+    assertSameCompartment(cx, varEnv);
+    MOZ_ASSERT(cx->compartment()->getNonSyntacticLexicalEnvironment(varEnv));
+
+    RootedObject global(cx, &varEnv->global());
+    RootedObject lexEnv(cx, JS_ExtensibleLexicalEnvironment(varEnv));
+
+    return ExecuteInNonSyntacticGlobalInternal(cx, global, scriptArg, varEnv, lexEnv);
+}
+
+JS_FRIEND_API(JSObject*)
+js::GetJSMEnvironmentOfScriptedCaller(JSContext* cx)
+{
+    FrameIter iter(cx);
+    if (iter.done())
+        return nullptr;
+
+    // WASM frames don't always provide their environment, but we also shouldn't
+    // expect to see any calling into here.
+    MOZ_RELEASE_ASSERT(!iter.isWasm());
+
+    RootedObject env(cx, iter.environmentChain(cx));
+    while (env && !env->is<NonSyntacticVariablesObject>())
+        env = env->enclosingEnvironment();
+
+    return env;
+}
--- a/js/src/jsapi-tests/moz.build
+++ b/js/src/jsapi-tests/moz.build
@@ -24,16 +24,17 @@ UNIFIED_SOURCES += [
     'testDeepFreeze.cpp',
     'testDefineGetterSetterNonEnumerable.cpp',
     'testDefineProperty.cpp',
     'testDefinePropertyIgnoredAttributes.cpp',
     'testDeflateStringToUTF8Buffer.cpp',
     'testDifferentNewTargetInvokeConstructor.cpp',
     'testErrorCopying.cpp',
     'testException.cpp',
+    'testExecuteInJSMEnvironment.cpp',
     'testExternalArrayBuffer.cpp',
     'testExternalStrings.cpp',
     'testFindSCCs.cpp',
     'testForceLexicalInitialization.cpp',
     'testForOfIterator.cpp',
     'testForwardSetProperty.cpp',
     'testFreshGlobalEvalRedefinition.cpp',
     'testFunctionBinding.cpp',
new file mode 100644
--- /dev/null
+++ b/js/src/jsapi-tests/testExecuteInJSMEnvironment.cpp
@@ -0,0 +1,98 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "jsapi-tests/tests.h"
+#include "vm/EnvironmentObject.h"
+#include "vm/EnvironmentObject-inl.h"
+
+
+BEGIN_TEST(testExecuteInJSMEnvironment_Basic)
+{
+    static const char src[] =
+        "var output = input;\n"
+        "\n"
+        "a = 1;\n"
+        "var b = 2;\n"
+        "let c = 3;\n"
+        "this.d = 4;\n"
+        "eval('this.e = 5');\n"
+        "(0,eval)('this.f = 6');\n"
+        "(function() { this.g = 7; })();\n"
+        "function f_h() { this.h = 8; }; f_h();\n"
+        ;
+
+    JS::CompileOptions options(cx);
+    options.setFileAndLine(__FILE__, __LINE__);
+
+    JS::RootedScript script(cx);
+    CHECK(JS::CompileForNonSyntacticScope(cx, options, src, sizeof(src)-1, &script));
+
+    JS::RootedObject varEnv(cx, js::NewJSMEnvironment(cx));
+    JS::RootedObject lexEnv(cx, JS_ExtensibleLexicalEnvironment(varEnv));
+    CHECK(varEnv && varEnv->is<js::NonSyntacticVariablesObject>());
+    CHECK(lexEnv && js::IsExtensibleLexicalEnvironment(lexEnv));
+    CHECK(lexEnv->enclosingEnvironment() == varEnv);
+
+    JS::RootedValue vi(cx, JS::Int32Value(1000));
+    CHECK(JS_SetProperty(cx, varEnv, "input", vi));
+
+    CHECK(js::ExecuteInJSMEnvironment(cx, script, varEnv));
+
+    JS::RootedValue v(cx);
+    CHECK(JS_GetProperty(cx, varEnv, "output", &v) && v == vi);
+    CHECK(JS_GetProperty(cx, varEnv, "a", &v) && v == JS::Int32Value(1));
+    CHECK(JS_GetProperty(cx, varEnv, "b", &v) && v == JS::Int32Value(2));
+    CHECK(JS_GetProperty(cx, lexEnv, "c", &v) && v == JS::Int32Value(3));
+    CHECK(JS_GetProperty(cx, varEnv, "d", &v) && v == JS::Int32Value(4));
+    CHECK(JS_GetProperty(cx, varEnv, "e", &v) && v == JS::Int32Value(5));
+ // TODO: Bug 1396050 will fix this
+ // CHECK(JS_GetProperty(cx, varEnv, "f", &v) && v == JS::Int32Value(6));
+    CHECK(JS_GetProperty(cx, varEnv, "g", &v) && v == JS::Int32Value(7));
+    CHECK(JS_GetProperty(cx, varEnv, "h", &v) && v == JS::Int32Value(8));
+
+    return true;
+}
+END_TEST(testExecuteInJSMEnvironment_Basic);
+
+static bool
+test_callback(JSContext* cx, unsigned argc, JS::Value* vp)
+{
+    JS::RootedObject env(cx, js::GetJSMEnvironmentOfScriptedCaller(cx));
+    if (!env)
+        return false;
+
+    JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+    args.rval().setObject(*env);
+    return true;
+}
+
+static const JSFunctionSpec testFunctions[] = {
+    JS_FN("callback", test_callback, 0, 0),
+    JS_FS_END
+};
+
+BEGIN_TEST(testExecuteInJSMEnvironment_Callback)
+{
+    static const char src[] =
+        "var output = callback();\n"
+        ;
+
+    CHECK(JS_DefineFunctions(cx, global, testFunctions));
+
+    JS::CompileOptions options(cx);
+    options.setFileAndLine(__FILE__, __LINE__);
+
+    JS::RootedScript script(cx);
+    CHECK(JS::CompileForNonSyntacticScope(cx, options, src, sizeof(src)-1, &script));
+
+    JS::RootedObject nsvo(cx, js::NewJSMEnvironment(cx));
+    CHECK(nsvo);
+    CHECK(js::ExecuteInJSMEnvironment(cx, script, nsvo));
+
+    JS::RootedValue v(cx);
+    CHECK(JS_GetProperty(cx, nsvo, "output", &v) && v == JS::ObjectValue(*nsvo));
+
+    return true;
+}
+END_TEST(testExecuteInJSMEnvironment_Callback)
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -2883,16 +2883,27 @@ SetPropertyIgnoringNamedGetter(JSContext
                                JS::Handle<JS::PropertyDescriptor> ownDesc,
                                JS::ObjectOpResult& result);
 
 // This function is for one specific use case, please don't use this for anything else!
 extern JS_FRIEND_API(bool)
 ExecuteInGlobalAndReturnScope(JSContext* cx, JS::HandleObject obj, JS::HandleScript script,
                               JS::MutableHandleObject scope);
 
+// These functions are only for JSM component loader, please don't use this for anything else!
+extern JS_FRIEND_API(JSObject*)
+NewJSMEnvironment(JSContext* cx);
+
+extern JS_FRIEND_API(bool)
+ExecuteInJSMEnvironment(JSContext* cx, JS::HandleScript script, JS::HandleObject nsvo);
+
+extern JS_FRIEND_API(JSObject*)
+GetJSMEnvironmentOfScriptedCaller(JSContext* cx);
+
+
 #if defined(XP_WIN) && defined(_WIN64)
 // Parameters use void* types to avoid #including windows.h. The return value of
 // this function is returned from the exception handler.
 typedef long
 (*JitExceptionHandler)(void* exceptionRecord,  // PEXECTION_RECORD
                        void* context);         // PCONTEXT
 
 /**