Bug 1920009 - Fix fragment titles being read by talkback after dismissal from menu...
[gecko.git] / js / src / jsapi-tests / testCompileScript.cpp
blobff7432b14b1da26a0bd121416f3c805b390d825c
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/. */
5 #include "mozilla/RefPtr.h" // RefPtr
6 #include "mozilla/ScopeExit.h" // MakeScopeExit
7 #include "mozilla/Utf8.h" // mozilla::Utf8Unit
9 #include "frontend/CompilationStencil.h" // JS::Stencil
10 #include "js/CompileOptions.h" // JS::CompileOptions, JS::InstantiateOptions
11 #include "js/experimental/CompileScript.h" // JS::NewFrontendContext
12 #include "js/SourceText.h" // JS::Source{Ownership,Text}
13 #include "jsapi-tests/tests.h"
14 #include "vm/ErrorReporting.h"
15 #include "vm/JSONPrinter.h" // js::JSONPrinter
17 using namespace JS;
19 template <typename T>
20 static void dump(const T& data) {
21 js::Fprinter printer(stderr);
22 js::JSONPrinter json(printer, true);
24 data->dump(json);
25 printer.put("\n");
28 BEGIN_TEST(testCompileScript) {
29 CHECK(testCompile());
30 CHECK(testNonsyntacticCompile());
31 CHECK(testCompileModule());
32 CHECK(testPrepareForInstantiate());
34 return true;
37 bool testCompile() {
38 static constexpr std::string_view src = "42\n";
39 static constexpr std::u16string_view src_16 = u"42\n";
41 static_assert(src.length() == src_16.length(),
42 "Source buffers must be same length");
44 JS::CompileOptions options(cx);
46 JS::FrontendContext* fc = JS::NewFrontendContext();
47 CHECK(fc);
48 auto destroyFc =
49 mozilla::MakeScopeExit([fc] { JS::DestroyFrontendContext(fc); });
51 { // 16-bit characters
52 JS::SourceText<char16_t> buf16;
53 CHECK(buf16.init(cx, src_16.data(), src_16.length(),
54 JS::SourceOwnership::Borrowed));
56 RefPtr<JS::Stencil> stencil =
57 CompileGlobalScriptToStencil(fc, options, buf16);
58 CHECK(stencil);
59 CHECK(stencil->scriptExtra.size() == 1);
60 CHECK(stencil->scriptExtra[0].extent.sourceStart == 0);
61 CHECK(stencil->scriptExtra[0].extent.sourceEnd == 3);
62 CHECK(stencil->scriptData.size() == 1);
63 CHECK(stencil->scriptData[0].hasSharedData()); // has generated bytecode
64 CHECK(stencil->scriptData[0].gcThingsLength == 1);
67 { // 8-bit characters
68 JS::SourceText<mozilla::Utf8Unit> buf8;
69 CHECK(
70 buf8.init(cx, src.data(), src.length(), JS::SourceOwnership::Borrowed));
72 RefPtr<JS::Stencil> stencil =
73 CompileGlobalScriptToStencil(fc, options, buf8);
74 CHECK(stencil);
75 CHECK(stencil->scriptExtra.size() == 1);
76 CHECK(stencil->scriptExtra[0].extent.sourceStart == 0);
77 CHECK(stencil->scriptExtra[0].extent.sourceEnd == 3);
78 CHECK(stencil->scriptData.size() == 1);
79 CHECK(stencil->scriptData[0].hasSharedData()); // has generated bytecode
80 CHECK(stencil->scriptData[0].gcThingsLength == 1);
83 { // propagates failures
84 static constexpr std::string_view badSrc = "{ a: 1, b: 3\n";
85 JS::SourceText<mozilla::Utf8Unit> srcBuf;
86 CHECK(srcBuf.init(cx, badSrc.data(), badSrc.length(),
87 JS::SourceOwnership::Borrowed));
89 RefPtr<JS::Stencil> stencil =
90 CompileGlobalScriptToStencil(fc, options, srcBuf);
91 CHECK(!stencil);
92 CHECK(fc->maybeError().isSome());
93 const js::CompileError& error = fc->maybeError().ref();
94 CHECK(JSEXN_SYNTAXERR == error.exnType);
95 CHECK(error.lineno == 1);
96 CHECK(error.column.oneOriginValue() == 10);
99 return true;
102 bool testNonsyntacticCompile() {
103 const char* chars =
104 "function f() { return x; }"
105 "f();";
107 JS::SourceText<mozilla::Utf8Unit> srcBuf;
108 CHECK(srcBuf.init(cx, chars, strlen(chars), JS::SourceOwnership::Borrowed));
110 JS::CompileOptions options(cx);
111 options.setNonSyntacticScope(true);
113 JS::FrontendContext* fc = JS::NewFrontendContext();
114 CHECK(fc);
115 auto destroyFc =
116 mozilla::MakeScopeExit([fc] { JS::DestroyFrontendContext(fc); });
118 RefPtr<JS::Stencil> stencil =
119 CompileGlobalScriptToStencil(fc, options, srcBuf);
120 CHECK(stencil);
122 JS::InstantiateOptions instantiateOptions(options);
123 JS::RootedScript script(
124 cx, JS::InstantiateGlobalStencil(cx, instantiateOptions, stencil));
125 CHECK(script);
126 CHECK(script->hasNonSyntacticScope());
128 return true;
131 bool testCompileModule() {
132 static constexpr std::string_view src = "import 'a'; 42\n";
133 static constexpr std::u16string_view src_16 = u"import 'a'; 42\n";
135 static_assert(src.length() == src_16.length(),
136 "Source buffers must be same length");
138 JS::CompileOptions options(cx);
140 JS::FrontendContext* fc = JS::NewFrontendContext();
141 CHECK(fc);
142 auto destroyFc =
143 mozilla::MakeScopeExit([fc] { JS::DestroyFrontendContext(fc); });
145 { // 16-bit characters
146 JS::SourceText<char16_t> buf16;
147 CHECK(buf16.init(cx, src_16.data(), src_16.length(),
148 JS::SourceOwnership::Borrowed));
150 RefPtr<JS::Stencil> stencil =
151 CompileModuleScriptToStencil(fc, options, buf16);
152 CHECK(stencil);
153 CHECK(stencil->isModule());
154 CHECK(stencil->scriptExtra.size() == 1);
155 CHECK(stencil->scriptExtra[0].extent.sourceStart == 0);
156 CHECK(stencil->scriptExtra[0].extent.sourceEnd == 15);
157 CHECK(stencil->scriptData.size() == 1);
158 CHECK(stencil->scriptData[0].hasSharedData()); // has generated bytecode
159 CHECK(stencil->scriptData[0].gcThingsLength == 1);
162 { // 8-bit characters
163 JS::SourceText<mozilla::Utf8Unit> buf8;
164 CHECK(
165 buf8.init(cx, src.data(), src.length(), JS::SourceOwnership::Borrowed));
167 RefPtr<JS::Stencil> stencil =
168 CompileModuleScriptToStencil(fc, options, buf8);
169 CHECK(stencil);
170 CHECK(stencil->scriptExtra.size() == 1);
171 CHECK(stencil->scriptExtra[0].extent.sourceStart == 0);
172 CHECK(stencil->scriptExtra[0].extent.sourceEnd == 15);
173 CHECK(stencil->scriptData.size() == 1);
174 CHECK(stencil->scriptData[0].hasSharedData()); // has generated bytecode
175 CHECK(stencil->scriptData[0].gcThingsLength == 1);
178 { // propagates failures
179 static constexpr std::string_view badSrc = "{ a: 1, b: 3\n";
180 JS::SourceText<mozilla::Utf8Unit> srcBuf;
181 CHECK(srcBuf.init(cx, badSrc.data(), badSrc.length(),
182 JS::SourceOwnership::Borrowed));
184 RefPtr<JS::Stencil> stencil =
185 CompileModuleScriptToStencil(fc, options, srcBuf);
186 CHECK(!stencil);
187 CHECK(fc->maybeError().isSome());
188 const js::CompileError& error = fc->maybeError().ref();
189 CHECK(JSEXN_SYNTAXERR == error.exnType);
190 CHECK(error.lineno == 1);
191 CHECK(error.column.oneOriginValue() == 10);
194 return true;
197 bool testPrepareForInstantiate() {
198 static constexpr std::u16string_view src_16 =
199 u"function f() { return {'field': 42};}; f()['field']\n";
201 JS::CompileOptions options(cx);
203 JS::SourceText<char16_t> buf16;
204 CHECK(buf16.init(cx, src_16.data(), src_16.length(),
205 JS::SourceOwnership::Borrowed));
207 JS::FrontendContext* fc = JS::NewFrontendContext();
208 CHECK(fc);
209 auto destroyFc =
210 mozilla::MakeScopeExit([fc] { JS::DestroyFrontendContext(fc); });
212 RefPtr<JS::Stencil> stencil =
213 CompileGlobalScriptToStencil(fc, options, buf16);
214 CHECK(stencil);
215 CHECK(stencil->scriptData.size() == 2);
216 CHECK(stencil->scopeData.size() == 1); // function f
217 CHECK(stencil->parserAtomData.size() == 1); // 'field'
219 JS::InstantiationStorage storage;
220 CHECK(JS::PrepareForInstantiate(fc, *stencil, storage));
221 CHECK(storage.isValid());
222 // TODO storage.gcOutput_ is private, so there isn't a good way to check the
223 // scriptData and scopeData capacities
225 return true;
227 END_TEST(testCompileScript);