Line data Source code
1 : // Copyright 2016 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/flags.h"
6 :
7 : #include "test/cctest/cctest.h"
8 :
9 : namespace {
10 :
11 : using v8::Context;
12 : using v8::HandleScope;
13 : using v8::Isolate;
14 : using v8::Local;
15 : using v8::MaybeLocal;
16 : using v8::Module;
17 : using v8::ScriptCompiler;
18 : using v8::ScriptOrigin;
19 : using v8::String;
20 : using v8::Value;
21 :
22 : ScriptOrigin ModuleOrigin(Local<v8::Value> resource_name, Isolate* isolate) {
23 : ScriptOrigin origin(resource_name, Local<v8::Integer>(), Local<v8::Integer>(),
24 : Local<v8::Boolean>(), Local<v8::Integer>(),
25 : Local<v8::Value>(), Local<v8::Boolean>(),
26 : Local<v8::Boolean>(), True(isolate));
27 : return origin;
28 : }
29 :
30 6 : MaybeLocal<Module> FailAlwaysResolveCallback(Local<Context> context,
31 : Local<String> specifier,
32 : Local<Module> referrer) {
33 6 : Isolate* isolate = context->GetIsolate();
34 12 : isolate->ThrowException(v8_str("boom"));
35 6 : return MaybeLocal<Module>();
36 : }
37 :
38 : static int g_count = 0;
39 12 : MaybeLocal<Module> FailOnSecondCallResolveCallback(Local<Context> context,
40 : Local<String> specifier,
41 : Local<Module> referrer) {
42 12 : Isolate* isolate = CcTest::isolate();
43 12 : if (g_count++ > 0) {
44 12 : isolate->ThrowException(v8_str("booom"));
45 6 : return MaybeLocal<Module>();
46 : }
47 6 : Local<String> source_text = v8_str("");
48 6 : ScriptOrigin origin = ModuleOrigin(v8_str("module.js"), isolate);
49 : ScriptCompiler::Source source(source_text, origin);
50 12 : return ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
51 : }
52 :
53 23724 : TEST(ModuleInstantiationFailures) {
54 6 : Isolate* isolate = CcTest::isolate();
55 6 : HandleScope scope(isolate);
56 12 : LocalContext env;
57 12 : v8::TryCatch try_catch(isolate);
58 :
59 : Local<String> source_text = v8_str(
60 : "import './foo.js';\n"
61 6 : "export {} from './bar.js';");
62 6 : ScriptOrigin origin = ModuleOrigin(v8_str("file.js"), CcTest::isolate());
63 : ScriptCompiler::Source source(source_text, origin);
64 : Local<Module> module =
65 6 : ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
66 6 : CHECK_EQ(Module::kUninstantiated, module->GetStatus());
67 6 : CHECK_EQ(2, module->GetModuleRequestsLength());
68 18 : CHECK(v8_str("./foo.js")->StrictEquals(module->GetModuleRequest(0)));
69 6 : v8::Location loc = module->GetModuleRequestLocation(0);
70 6 : CHECK_EQ(0, loc.GetLineNumber());
71 6 : CHECK_EQ(7, loc.GetColumnNumber());
72 :
73 18 : CHECK(v8_str("./bar.js")->StrictEquals(module->GetModuleRequest(1)));
74 6 : loc = module->GetModuleRequestLocation(1);
75 6 : CHECK_EQ(1, loc.GetLineNumber());
76 6 : CHECK_EQ(15, loc.GetColumnNumber());
77 :
78 : // Instantiation should fail.
79 : {
80 6 : v8::TryCatch inner_try_catch(isolate);
81 12 : CHECK(module->InstantiateModule(env.local(), FailAlwaysResolveCallback)
82 : .IsNothing());
83 6 : CHECK(inner_try_catch.HasCaught());
84 18 : CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom")));
85 6 : CHECK_EQ(Module::kErrored, module->GetStatus());
86 6 : Local<Value> exception = module->GetException();
87 12 : CHECK(exception->StrictEquals(v8_str("boom")));
88 : // TODO(neis): Check object identity.
89 : }
90 :
91 : // Start over again...
92 6 : module = ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
93 :
94 : // Instantiation should fail if a sub-module fails to resolve.
95 6 : g_count = 0;
96 : {
97 6 : v8::TryCatch inner_try_catch(isolate);
98 12 : CHECK(
99 : module->InstantiateModule(env.local(), FailOnSecondCallResolveCallback)
100 : .IsNothing());
101 6 : CHECK(inner_try_catch.HasCaught());
102 18 : CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("booom")));
103 6 : CHECK_EQ(Module::kErrored, module->GetStatus());
104 6 : Local<Value> exception = module->GetException();
105 12 : CHECK(exception->StrictEquals(v8_str("booom")));
106 : }
107 :
108 12 : CHECK(!try_catch.HasCaught());
109 6 : }
110 :
111 48 : static MaybeLocal<Module> CompileSpecifierAsModuleResolveCallback(
112 : Local<Context> context, Local<String> specifier, Local<Module> referrer) {
113 48 : ScriptOrigin origin = ModuleOrigin(v8_str("module.js"), CcTest::isolate());
114 : ScriptCompiler::Source source(specifier, origin);
115 48 : return ScriptCompiler::CompileModule(CcTest::isolate(), &source)
116 144 : .ToLocalChecked();
117 : }
118 :
119 23724 : TEST(ModuleEvaluation) {
120 6 : Isolate* isolate = CcTest::isolate();
121 6 : HandleScope scope(isolate);
122 12 : LocalContext env;
123 12 : v8::TryCatch try_catch(isolate);
124 :
125 : Local<String> source_text = v8_str(
126 : "import 'Object.expando = 5';"
127 6 : "import 'Object.expando *= 2';");
128 6 : ScriptOrigin origin = ModuleOrigin(v8_str("file.js"), CcTest::isolate());
129 : ScriptCompiler::Source source(source_text, origin);
130 : Local<Module> module =
131 6 : ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
132 6 : CHECK_EQ(Module::kUninstantiated, module->GetStatus());
133 12 : CHECK(module
134 : ->InstantiateModule(env.local(),
135 : CompileSpecifierAsModuleResolveCallback)
136 : .FromJust());
137 6 : CHECK_EQ(Module::kInstantiated, module->GetStatus());
138 12 : CHECK(!module->Evaluate(env.local()).IsEmpty());
139 6 : CHECK_EQ(Module::kEvaluated, module->GetStatus());
140 6 : ExpectInt32("Object.expando", 10);
141 :
142 12 : CHECK(!try_catch.HasCaught());
143 6 : }
144 :
145 23724 : TEST(ModuleEvaluationError) {
146 6 : Isolate* isolate = CcTest::isolate();
147 6 : HandleScope scope(isolate);
148 12 : LocalContext env;
149 12 : v8::TryCatch try_catch(isolate);
150 :
151 : Local<String> source_text =
152 6 : v8_str("Object.x = (Object.x || 0) + 1; throw 'boom';");
153 6 : ScriptOrigin origin = ModuleOrigin(v8_str("file.js"), CcTest::isolate());
154 : ScriptCompiler::Source source(source_text, origin);
155 : Local<Module> module =
156 6 : ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
157 6 : CHECK_EQ(Module::kUninstantiated, module->GetStatus());
158 12 : CHECK(module
159 : ->InstantiateModule(env.local(),
160 : CompileSpecifierAsModuleResolveCallback)
161 : .FromJust());
162 6 : CHECK_EQ(Module::kInstantiated, module->GetStatus());
163 :
164 : {
165 6 : v8::TryCatch inner_try_catch(isolate);
166 12 : CHECK(module->Evaluate(env.local()).IsEmpty());
167 6 : CHECK(inner_try_catch.HasCaught());
168 18 : CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom")));
169 6 : CHECK_EQ(Module::kErrored, module->GetStatus());
170 6 : Local<Value> exception = module->GetException();
171 12 : CHECK(exception->StrictEquals(v8_str("boom")));
172 6 : ExpectInt32("Object.x", 1);
173 : }
174 :
175 : {
176 6 : v8::TryCatch inner_try_catch(isolate);
177 12 : CHECK(module->Evaluate(env.local()).IsEmpty());
178 6 : CHECK(inner_try_catch.HasCaught());
179 18 : CHECK(inner_try_catch.Exception()->StrictEquals(v8_str("boom")));
180 6 : CHECK_EQ(Module::kErrored, module->GetStatus());
181 6 : Local<Value> exception = module->GetException();
182 12 : CHECK(exception->StrictEquals(v8_str("boom")));
183 6 : ExpectInt32("Object.x", 1);
184 : }
185 :
186 12 : CHECK(!try_catch.HasCaught());
187 6 : }
188 :
189 23724 : TEST(ModuleEvaluationCompletion1) {
190 6 : Isolate* isolate = CcTest::isolate();
191 6 : HandleScope scope(isolate);
192 12 : LocalContext env;
193 12 : v8::TryCatch try_catch(isolate);
194 :
195 : const char* sources[] = {
196 : "",
197 : "var a = 1",
198 : "import '42'",
199 : "export * from '42'",
200 : "export {} from '42'",
201 : "export {}",
202 : "var a = 1; export {a}",
203 : "export function foo() {}",
204 : "export class C extends null {}",
205 : "export let a = 1",
206 : "export default 1",
207 : "export default function foo() {}",
208 : "export default function () {}",
209 : "export default (function () {})",
210 : "export default class C extends null {}",
211 : "export default (class C extends null {})",
212 : "for (var i = 0; i < 5; ++i) {}",
213 6 : };
214 :
215 108 : for (auto src : sources) {
216 102 : Local<String> source_text = v8_str(src);
217 102 : ScriptOrigin origin = ModuleOrigin(v8_str("file.js"), CcTest::isolate());
218 : ScriptCompiler::Source source(source_text, origin);
219 : Local<Module> module =
220 102 : ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
221 102 : CHECK_EQ(Module::kUninstantiated, module->GetStatus());
222 204 : CHECK(module
223 : ->InstantiateModule(env.local(),
224 : CompileSpecifierAsModuleResolveCallback)
225 : .FromJust());
226 102 : CHECK_EQ(Module::kInstantiated, module->GetStatus());
227 204 : CHECK(module->Evaluate(env.local()).ToLocalChecked()->IsUndefined());
228 102 : CHECK_EQ(Module::kEvaluated, module->GetStatus());
229 204 : CHECK(module->Evaluate(env.local()).ToLocalChecked()->IsUndefined());
230 102 : CHECK_EQ(Module::kEvaluated, module->GetStatus());
231 : }
232 :
233 12 : CHECK(!try_catch.HasCaught());
234 6 : }
235 :
236 23724 : TEST(ModuleEvaluationCompletion2) {
237 6 : Isolate* isolate = CcTest::isolate();
238 6 : HandleScope scope(isolate);
239 12 : LocalContext env;
240 12 : v8::TryCatch try_catch(isolate);
241 :
242 : const char* sources[] = {
243 : "'gaga'; ",
244 : "'gaga'; var a = 1",
245 : "'gaga'; import '42'",
246 : "'gaga'; export * from '42'",
247 : "'gaga'; export {} from '42'",
248 : "'gaga'; export {}",
249 : "'gaga'; var a = 1; export {a}",
250 : "'gaga'; export function foo() {}",
251 : "'gaga'; export class C extends null {}",
252 : "'gaga'; export let a = 1",
253 : "'gaga'; export default 1",
254 : "'gaga'; export default function foo() {}",
255 : "'gaga'; export default function () {}",
256 : "'gaga'; export default (function () {})",
257 : "'gaga'; export default class C extends null {}",
258 : "'gaga'; export default (class C extends null {})",
259 6 : };
260 :
261 102 : for (auto src : sources) {
262 96 : Local<String> source_text = v8_str(src);
263 96 : ScriptOrigin origin = ModuleOrigin(v8_str("file.js"), CcTest::isolate());
264 : ScriptCompiler::Source source(source_text, origin);
265 : Local<Module> module =
266 96 : ScriptCompiler::CompileModule(isolate, &source).ToLocalChecked();
267 96 : CHECK_EQ(Module::kUninstantiated, module->GetStatus());
268 192 : CHECK(module
269 : ->InstantiateModule(env.local(),
270 : CompileSpecifierAsModuleResolveCallback)
271 : .FromJust());
272 96 : CHECK_EQ(Module::kInstantiated, module->GetStatus());
273 288 : CHECK(module->Evaluate(env.local())
274 : .ToLocalChecked()
275 : ->StrictEquals(v8_str("gaga")));
276 96 : CHECK_EQ(Module::kEvaluated, module->GetStatus());
277 192 : CHECK(module->Evaluate(env.local()).ToLocalChecked()->IsUndefined());
278 96 : CHECK_EQ(Module::kEvaluated, module->GetStatus());
279 : }
280 :
281 12 : CHECK(!try_catch.HasCaught());
282 6 : }
283 :
284 71154 : } // anonymous namespace
|