1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 #include "mozilla/Utf8.h"  // mozilla::Utf8Unit
6 
7 #include "js/CompilationAndEvaluation.h"  // JS::Compile
8 #include "js/friend/JSMEnvironment.h"  // JS::ExecuteInJSMEnvironment, JS::GetJSMEnvironmentOfScriptedCaller, JS::NewJSMEnvironment
9 #include "js/PropertySpec.h"
10 #include "js/SourceText.h"  // JS::Source{Ownership,Text}
11 #include "jsapi-tests/tests.h"
12 #include "util/Text.h"
13 #include "vm/EnvironmentObject.h"
14 #include "vm/EnvironmentObject-inl.h"
15 
BEGIN_TEST(testExecuteInJSMEnvironment_Basic)16 BEGIN_TEST(testExecuteInJSMEnvironment_Basic) {
17   static const char src[] =
18       "var output = input;\n"
19       "\n"
20       "a = 1;\n"
21       "var b = 2;\n"
22       "let c = 3;\n"
23       "this.d = 4;\n"
24       "eval('this.e = 5');\n"
25       "(0,eval)('this.f = 6');\n"
26       "(function() { this.g = 7; })();\n"
27       "function f_h() { this.h = 8; }; f_h();\n";
28 
29   JS::CompileOptions options(cx);
30   options.setFileAndLine(__FILE__, __LINE__);
31   options.setNoScriptRval(true);
32   options.setNonSyntacticScope(true);
33 
34   JS::SourceText<mozilla::Utf8Unit> srcBuf;
35   CHECK(srcBuf.init(cx, src, js_strlen(src), JS::SourceOwnership::Borrowed));
36 
37   JS::RootedScript script(cx, JS::Compile(cx, options, srcBuf));
38   CHECK(script);
39 
40   JS::RootedObject varEnv(cx, JS::NewJSMEnvironment(cx));
41   JS::RootedObject lexEnv(cx, JS_ExtensibleLexicalEnvironment(varEnv));
42   CHECK(varEnv && varEnv->is<js::NonSyntacticVariablesObject>());
43   CHECK(lexEnv && js::IsExtensibleLexicalEnvironment(lexEnv));
44   CHECK(lexEnv->enclosingEnvironment() == varEnv);
45 
46   JS::RootedValue vi(cx, JS::Int32Value(1000));
47   CHECK(JS_SetProperty(cx, varEnv, "input", vi));
48 
49   CHECK(JS::ExecuteInJSMEnvironment(cx, script, varEnv));
50 
51   JS::RootedValue v(cx);
52   CHECK(JS_GetProperty(cx, varEnv, "output", &v) && v == vi);
53   CHECK(JS_GetProperty(cx, varEnv, "a", &v) && v == JS::Int32Value(1));
54   CHECK(JS_GetProperty(cx, varEnv, "b", &v) && v == JS::Int32Value(2));
55   CHECK(JS_GetProperty(cx, lexEnv, "c", &v) && v == JS::Int32Value(3));
56   CHECK(JS_GetProperty(cx, varEnv, "d", &v) && v == JS::Int32Value(4));
57   CHECK(JS_GetProperty(cx, varEnv, "e", &v) && v == JS::Int32Value(5));
58   // TODO: Bug 1396050 will fix this
59   // CHECK(JS_GetProperty(cx, varEnv, "f", &v) && v == JS::Int32Value(6));
60   CHECK(JS_GetProperty(cx, varEnv, "g", &v) && v == JS::Int32Value(7));
61   CHECK(JS_GetProperty(cx, varEnv, "h", &v) && v == JS::Int32Value(8));
62 
63   return true;
64 }
65 END_TEST(testExecuteInJSMEnvironment_Basic);
66 
test_callback(JSContext * cx,unsigned argc,JS::Value * vp)67 static bool test_callback(JSContext* cx, unsigned argc, JS::Value* vp) {
68   JS::RootedObject env(cx, JS::GetJSMEnvironmentOfScriptedCaller(cx));
69   if (!env) {
70     return false;
71   }
72 
73   JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
74   args.rval().setObject(*env);
75   return true;
76 }
77 
78 static const JSFunctionSpec testFunctions[] = {
79     JS_FN("callback", test_callback, 0, 0), JS_FS_END};
80 
BEGIN_TEST(testExecuteInJSMEnvironment_Callback)81 BEGIN_TEST(testExecuteInJSMEnvironment_Callback) {
82   static const char src[] = "var output = callback();\n";
83 
84   CHECK(JS_DefineFunctions(cx, global, testFunctions));
85 
86   JS::CompileOptions options(cx);
87   options.setFileAndLine(__FILE__, __LINE__);
88   options.setNoScriptRval(true);
89   options.setNonSyntacticScope(true);
90 
91   JS::SourceText<mozilla::Utf8Unit> srcBuf;
92   CHECK(srcBuf.init(cx, src, js_strlen(src), JS::SourceOwnership::Borrowed));
93 
94   JS::RootedScript script(cx, JS::Compile(cx, options, srcBuf));
95   CHECK(script);
96 
97   JS::RootedObject nsvo(cx, JS::NewJSMEnvironment(cx));
98   CHECK(nsvo);
99   CHECK(JS::ExecuteInJSMEnvironment(cx, script, nsvo));
100 
101   JS::RootedValue v(cx);
102   CHECK(JS_GetProperty(cx, nsvo, "output", &v) && v == JS::ObjectValue(*nsvo));
103 
104   return true;
105 }
106 END_TEST(testExecuteInJSMEnvironment_Callback)
107