/src/node/src/module_wrap.cc
Line | Count | Source (jump to first uncovered line) |
1 | | #include "module_wrap.h" |
2 | | |
3 | | #include "env.h" |
4 | | #include "memory_tracker-inl.h" |
5 | | #include "node_contextify.h" |
6 | | #include "node_errors.h" |
7 | | #include "node_external_reference.h" |
8 | | #include "node_internals.h" |
9 | | #include "node_process-inl.h" |
10 | | #include "node_watchdog.h" |
11 | | #include "util-inl.h" |
12 | | |
13 | | #include <sys/stat.h> // S_IFDIR |
14 | | |
15 | | #include <algorithm> |
16 | | |
17 | | namespace node { |
18 | | namespace loader { |
19 | | |
20 | | using errors::TryCatchScope; |
21 | | |
22 | | using node::contextify::ContextifyContext; |
23 | | using v8::Array; |
24 | | using v8::ArrayBufferView; |
25 | | using v8::Context; |
26 | | using v8::EscapableHandleScope; |
27 | | using v8::FixedArray; |
28 | | using v8::Function; |
29 | | using v8::FunctionCallbackInfo; |
30 | | using v8::FunctionTemplate; |
31 | | using v8::HandleScope; |
32 | | using v8::Int32; |
33 | | using v8::Integer; |
34 | | using v8::IntegrityLevel; |
35 | | using v8::Isolate; |
36 | | using v8::Local; |
37 | | using v8::MaybeLocal; |
38 | | using v8::MemorySpan; |
39 | | using v8::MicrotaskQueue; |
40 | | using v8::Module; |
41 | | using v8::ModuleRequest; |
42 | | using v8::Object; |
43 | | using v8::ObjectTemplate; |
44 | | using v8::PrimitiveArray; |
45 | | using v8::Promise; |
46 | | using v8::ScriptCompiler; |
47 | | using v8::ScriptOrigin; |
48 | | using v8::String; |
49 | | using v8::Symbol; |
50 | | using v8::UnboundModuleScript; |
51 | | using v8::Undefined; |
52 | | using v8::Value; |
53 | | |
54 | | ModuleWrap::ModuleWrap(Realm* realm, |
55 | | Local<Object> object, |
56 | | Local<Module> module, |
57 | | Local<String> url, |
58 | | Local<Object> context_object, |
59 | | Local<Value> synthetic_evaluation_step) |
60 | 0 | : BaseObject(realm, object), |
61 | 0 | module_(realm->isolate(), module), |
62 | 0 | module_hash_(module->GetIdentityHash()) { |
63 | 0 | realm->env()->hash_to_module_map.emplace(module_hash_, this); |
64 | |
|
65 | 0 | object->SetInternalField(kModuleSlot, module); |
66 | 0 | object->SetInternalField(kURLSlot, url); |
67 | 0 | object->SetInternalField(kSyntheticEvaluationStepsSlot, |
68 | 0 | synthetic_evaluation_step); |
69 | 0 | object->SetInternalField(kContextObjectSlot, context_object); |
70 | |
|
71 | 0 | if (!synthetic_evaluation_step->IsUndefined()) { |
72 | 0 | synthetic_ = true; |
73 | 0 | } |
74 | 0 | MakeWeak(); |
75 | 0 | module_.SetWeak(); |
76 | 0 | } |
77 | | |
78 | 0 | ModuleWrap::~ModuleWrap() { |
79 | 0 | auto range = env()->hash_to_module_map.equal_range(module_hash_); |
80 | 0 | for (auto it = range.first; it != range.second; ++it) { |
81 | 0 | if (it->second == this) { |
82 | 0 | env()->hash_to_module_map.erase(it); |
83 | 0 | break; |
84 | 0 | } |
85 | 0 | } |
86 | 0 | } |
87 | | |
88 | 0 | Local<Context> ModuleWrap::context() const { |
89 | 0 | Local<Value> obj = object()->GetInternalField(kContextObjectSlot).As<Value>(); |
90 | | // If this fails, there is likely a bug e.g. ModuleWrap::context() is accessed |
91 | | // before the ModuleWrap constructor completes. |
92 | 0 | CHECK(obj->IsObject()); |
93 | 0 | return obj.As<Object>()->GetCreationContextChecked(); |
94 | 0 | } |
95 | | |
96 | | ModuleWrap* ModuleWrap::GetFromModule(Environment* env, |
97 | 0 | Local<Module> module) { |
98 | 0 | auto range = env->hash_to_module_map.equal_range(module->GetIdentityHash()); |
99 | 0 | for (auto it = range.first; it != range.second; ++it) { |
100 | 0 | if (it->second->module_ == module) { |
101 | 0 | return it->second; |
102 | 0 | } |
103 | 0 | } |
104 | 0 | return nullptr; |
105 | 0 | } |
106 | | |
107 | 0 | v8::Maybe<bool> ModuleWrap::CheckUnsettledTopLevelAwait() { |
108 | 0 | Isolate* isolate = env()->isolate(); |
109 | 0 | Local<Context> context = env()->context(); |
110 | | |
111 | | // This must be invoked when the environment is shutting down, and the module |
112 | | // is kept alive by the module wrap via an internal field. |
113 | 0 | CHECK(env()->exiting()); |
114 | 0 | CHECK(!module_.IsEmpty()); |
115 | | |
116 | 0 | Local<Module> module = module_.Get(isolate); |
117 | | // It's a synthetic module, likely a facade wrapping CJS. |
118 | 0 | if (!module->IsSourceTextModule()) { |
119 | 0 | return v8::Just(true); |
120 | 0 | } |
121 | | |
122 | 0 | if (!module->IsGraphAsync()) { // There is no TLA, no need to check. |
123 | 0 | return v8::Just(true); |
124 | 0 | } |
125 | | |
126 | 0 | auto stalled_messages = |
127 | 0 | std::get<1>(module->GetStalledTopLevelAwaitMessages(isolate)); |
128 | 0 | if (stalled_messages.size() == 0) { |
129 | 0 | return v8::Just(true); |
130 | 0 | } |
131 | | |
132 | 0 | if (env()->options()->warnings) { |
133 | 0 | for (auto& message : stalled_messages) { |
134 | 0 | std::string reason = "Warning: Detected unsettled top-level await at "; |
135 | 0 | std::string info = |
136 | 0 | FormatErrorMessage(isolate, context, "", message, true); |
137 | 0 | reason += info; |
138 | 0 | FPrintF(stderr, "%s\n", reason); |
139 | 0 | } |
140 | 0 | } |
141 | |
|
142 | 0 | return v8::Just(false); |
143 | 0 | } |
144 | | |
145 | | // new ModuleWrap(url, context, source, lineOffset, columnOffset, cachedData) |
146 | | // new ModuleWrap(url, context, source, lineOffset, columOffset, |
147 | | // hostDefinedOption) new ModuleWrap(url, context, exportNames, |
148 | | // syntheticExecutionFunction) |
149 | 0 | void ModuleWrap::New(const FunctionCallbackInfo<Value>& args) { |
150 | 0 | CHECK(args.IsConstructCall()); |
151 | 0 | CHECK_GE(args.Length(), 3); |
152 | | |
153 | 0 | Realm* realm = Realm::GetCurrent(args); |
154 | 0 | Isolate* isolate = realm->isolate(); |
155 | |
|
156 | 0 | Local<Object> that = args.This(); |
157 | |
|
158 | 0 | CHECK(args[0]->IsString()); |
159 | 0 | Local<String> url = args[0].As<String>(); |
160 | |
|
161 | 0 | Local<Context> context; |
162 | 0 | ContextifyContext* contextify_context = nullptr; |
163 | 0 | if (args[1]->IsUndefined()) { |
164 | 0 | context = that->GetCreationContextChecked(); |
165 | 0 | } else { |
166 | 0 | CHECK(args[1]->IsObject()); |
167 | 0 | contextify_context = ContextifyContext::ContextFromContextifiedSandbox( |
168 | 0 | realm->env(), args[1].As<Object>()); |
169 | 0 | CHECK_NOT_NULL(contextify_context); |
170 | 0 | context = contextify_context->context(); |
171 | 0 | } |
172 | | |
173 | 0 | int line_offset = 0; |
174 | 0 | int column_offset = 0; |
175 | |
|
176 | 0 | bool synthetic = args[2]->IsArray(); |
177 | |
|
178 | 0 | Local<PrimitiveArray> host_defined_options = |
179 | 0 | PrimitiveArray::New(isolate, HostDefinedOptions::kLength); |
180 | 0 | Local<Symbol> id_symbol; |
181 | 0 | if (synthetic) { |
182 | | // new ModuleWrap(url, context, exportNames, syntheticExecutionFunction) |
183 | 0 | CHECK(args[3]->IsFunction()); |
184 | 0 | } else { |
185 | | // new ModuleWrap(url, context, source, lineOffset, columOffset, cachedData) |
186 | | // new ModuleWrap(url, context, source, lineOffset, columOffset, |
187 | | // hostDefinedOption) |
188 | 0 | CHECK(args[2]->IsString()); |
189 | 0 | CHECK(args[3]->IsNumber()); |
190 | 0 | line_offset = args[3].As<Int32>()->Value(); |
191 | 0 | CHECK(args[4]->IsNumber()); |
192 | 0 | column_offset = args[4].As<Int32>()->Value(); |
193 | 0 | if (args[5]->IsSymbol()) { |
194 | 0 | id_symbol = args[5].As<Symbol>(); |
195 | 0 | } else { |
196 | 0 | id_symbol = Symbol::New(isolate, url); |
197 | 0 | } |
198 | 0 | host_defined_options->Set(isolate, HostDefinedOptions::kID, id_symbol); |
199 | |
|
200 | 0 | if (that->SetPrivate(context, |
201 | 0 | realm->isolate_data()->host_defined_option_symbol(), |
202 | 0 | id_symbol) |
203 | 0 | .IsNothing()) { |
204 | 0 | return; |
205 | 0 | } |
206 | 0 | } |
207 | | |
208 | 0 | ShouldNotAbortOnUncaughtScope no_abort_scope(realm->env()); |
209 | 0 | TryCatchScope try_catch(realm->env()); |
210 | |
|
211 | 0 | Local<Module> module; |
212 | |
|
213 | 0 | { |
214 | 0 | Context::Scope context_scope(context); |
215 | 0 | if (synthetic) { |
216 | 0 | CHECK(args[2]->IsArray()); |
217 | 0 | Local<Array> export_names_arr = args[2].As<Array>(); |
218 | |
|
219 | 0 | uint32_t len = export_names_arr->Length(); |
220 | 0 | std::vector<Local<String>> export_names(len); |
221 | 0 | for (uint32_t i = 0; i < len; i++) { |
222 | 0 | Local<Value> export_name_val = |
223 | 0 | export_names_arr->Get(context, i).ToLocalChecked(); |
224 | 0 | CHECK(export_name_val->IsString()); |
225 | 0 | export_names[i] = export_name_val.As<String>(); |
226 | 0 | } |
227 | | |
228 | 0 | const MemorySpan<const Local<String>> span(export_names.begin(), |
229 | 0 | export_names.size()); |
230 | 0 | module = Module::CreateSyntheticModule( |
231 | 0 | isolate, url, span, SyntheticModuleEvaluationStepsCallback); |
232 | 0 | } else { |
233 | 0 | ScriptCompiler::CachedData* cached_data = nullptr; |
234 | 0 | if (args[5]->IsArrayBufferView()) { |
235 | 0 | Local<ArrayBufferView> cached_data_buf = args[5].As<ArrayBufferView>(); |
236 | 0 | uint8_t* data = |
237 | 0 | static_cast<uint8_t*>(cached_data_buf->Buffer()->Data()); |
238 | 0 | cached_data = |
239 | 0 | new ScriptCompiler::CachedData(data + cached_data_buf->ByteOffset(), |
240 | 0 | cached_data_buf->ByteLength()); |
241 | 0 | } |
242 | |
|
243 | 0 | Local<String> source_text = args[2].As<String>(); |
244 | 0 | ScriptOrigin origin(isolate, |
245 | 0 | url, |
246 | 0 | line_offset, |
247 | 0 | column_offset, |
248 | 0 | true, // is cross origin |
249 | 0 | -1, // script id |
250 | 0 | Local<Value>(), // source map URL |
251 | 0 | false, // is opaque (?) |
252 | 0 | false, // is WASM |
253 | 0 | true, // is ES Module |
254 | 0 | host_defined_options); |
255 | 0 | ScriptCompiler::Source source(source_text, origin, cached_data); |
256 | 0 | ScriptCompiler::CompileOptions options; |
257 | 0 | if (source.GetCachedData() == nullptr) { |
258 | 0 | options = ScriptCompiler::kNoCompileOptions; |
259 | 0 | } else { |
260 | 0 | options = ScriptCompiler::kConsumeCodeCache; |
261 | 0 | } |
262 | 0 | if (!ScriptCompiler::CompileModule(isolate, &source, options) |
263 | 0 | .ToLocal(&module)) { |
264 | 0 | if (try_catch.HasCaught() && !try_catch.HasTerminated()) { |
265 | 0 | CHECK(!try_catch.Message().IsEmpty()); |
266 | 0 | CHECK(!try_catch.Exception().IsEmpty()); |
267 | 0 | AppendExceptionLine(realm->env(), |
268 | 0 | try_catch.Exception(), |
269 | 0 | try_catch.Message(), |
270 | 0 | ErrorHandlingMode::MODULE_ERROR); |
271 | 0 | try_catch.ReThrow(); |
272 | 0 | } |
273 | 0 | return; |
274 | 0 | } |
275 | 0 | if (options == ScriptCompiler::kConsumeCodeCache && |
276 | 0 | source.GetCachedData()->rejected) { |
277 | 0 | THROW_ERR_VM_MODULE_CACHED_DATA_REJECTED( |
278 | 0 | realm, "cachedData buffer was rejected"); |
279 | 0 | try_catch.ReThrow(); |
280 | 0 | return; |
281 | 0 | } |
282 | | |
283 | 0 | if (that->Set(context, |
284 | 0 | realm->env()->source_map_url_string(), |
285 | 0 | module->GetUnboundModuleScript()->GetSourceMappingURL()) |
286 | 0 | .IsNothing()) { |
287 | 0 | return; |
288 | 0 | } |
289 | 0 | } |
290 | 0 | } |
291 | | |
292 | 0 | if (!that->Set(context, realm->isolate_data()->url_string(), url) |
293 | 0 | .FromMaybe(false)) { |
294 | 0 | return; |
295 | 0 | } |
296 | | |
297 | | // Use the extras object as an object whose GetCreationContext() will be the |
298 | | // original `context`, since the `Context` itself strictly speaking cannot |
299 | | // be stored in an internal field. |
300 | 0 | Local<Object> context_object = context->GetExtrasBindingObject(); |
301 | 0 | Local<Value> synthetic_evaluation_step = |
302 | 0 | synthetic ? args[3] : Undefined(realm->isolate()).As<v8::Value>(); |
303 | |
|
304 | 0 | ModuleWrap* obj = new ModuleWrap( |
305 | 0 | realm, that, module, url, context_object, synthetic_evaluation_step); |
306 | |
|
307 | 0 | obj->contextify_context_ = contextify_context; |
308 | |
|
309 | 0 | that->SetIntegrityLevel(context, IntegrityLevel::kFrozen); |
310 | 0 | args.GetReturnValue().Set(that); |
311 | 0 | } |
312 | | |
313 | | static Local<Object> createImportAttributesContainer( |
314 | | Realm* realm, |
315 | | Isolate* isolate, |
316 | | Local<FixedArray> raw_attributes, |
317 | 0 | const int elements_per_attribute) { |
318 | 0 | CHECK_EQ(raw_attributes->Length() % elements_per_attribute, 0); |
319 | 0 | Local<Object> attributes = |
320 | 0 | Object::New(isolate, v8::Null(isolate), nullptr, nullptr, 0); |
321 | 0 | for (int i = 0; i < raw_attributes->Length(); i += elements_per_attribute) { |
322 | 0 | attributes |
323 | 0 | ->Set(realm->context(), |
324 | 0 | raw_attributes->Get(realm->context(), i).As<String>(), |
325 | 0 | raw_attributes->Get(realm->context(), i + 1).As<Value>()) |
326 | 0 | .ToChecked(); |
327 | 0 | } |
328 | |
|
329 | 0 | return attributes; |
330 | 0 | } |
331 | | |
332 | | void ModuleWrap::GetModuleRequestsSync( |
333 | 0 | const FunctionCallbackInfo<Value>& args) { |
334 | 0 | Realm* realm = Realm::GetCurrent(args); |
335 | 0 | Isolate* isolate = args.GetIsolate(); |
336 | |
|
337 | 0 | Local<Object> that = args.This(); |
338 | |
|
339 | 0 | ModuleWrap* obj; |
340 | 0 | ASSIGN_OR_RETURN_UNWRAP(&obj, that); |
341 | | |
342 | 0 | CHECK(!obj->linked_); |
343 | | |
344 | 0 | Local<Module> module = obj->module_.Get(isolate); |
345 | 0 | Local<FixedArray> module_requests = module->GetModuleRequests(); |
346 | 0 | const int module_requests_length = module_requests->Length(); |
347 | |
|
348 | 0 | std::vector<Local<Value>> requests; |
349 | 0 | requests.reserve(module_requests_length); |
350 | | // call the dependency resolve callbacks |
351 | 0 | for (int i = 0; i < module_requests_length; i++) { |
352 | 0 | Local<ModuleRequest> module_request = |
353 | 0 | module_requests->Get(realm->context(), i).As<ModuleRequest>(); |
354 | 0 | Local<FixedArray> raw_attributes = module_request->GetImportAssertions(); |
355 | 0 | std::vector<Local<Value>> request = { |
356 | 0 | module_request->GetSpecifier(), |
357 | 0 | createImportAttributesContainer(realm, isolate, raw_attributes, 3), |
358 | 0 | }; |
359 | 0 | requests.push_back(Array::New(isolate, request.data(), request.size())); |
360 | 0 | } |
361 | |
|
362 | 0 | args.GetReturnValue().Set( |
363 | 0 | Array::New(isolate, requests.data(), requests.size())); |
364 | 0 | } |
365 | | |
366 | | void ModuleWrap::CacheResolvedWrapsSync( |
367 | 0 | const FunctionCallbackInfo<Value>& args) { |
368 | 0 | Isolate* isolate = args.GetIsolate(); |
369 | |
|
370 | 0 | CHECK_EQ(args.Length(), 3); |
371 | 0 | CHECK(args[0]->IsString()); |
372 | 0 | CHECK(args[1]->IsPromise()); |
373 | 0 | CHECK(args[2]->IsBoolean()); |
374 | | |
375 | 0 | ModuleWrap* dependent; |
376 | 0 | ASSIGN_OR_RETURN_UNWRAP(&dependent, args.This()); |
377 | | |
378 | 0 | Utf8Value specifier(isolate, args[0]); |
379 | 0 | dependent->resolve_cache_[specifier.ToString()].Reset(isolate, |
380 | 0 | args[1].As<Promise>()); |
381 | |
|
382 | 0 | if (args[2].As<v8::Boolean>()->Value()) { |
383 | 0 | dependent->linked_ = true; |
384 | 0 | } |
385 | 0 | } |
386 | | |
387 | 0 | void ModuleWrap::Link(const FunctionCallbackInfo<Value>& args) { |
388 | 0 | Realm* realm = Realm::GetCurrent(args); |
389 | 0 | Isolate* isolate = args.GetIsolate(); |
390 | |
|
391 | 0 | CHECK_EQ(args.Length(), 1); |
392 | 0 | CHECK(args[0]->IsFunction()); |
393 | | |
394 | 0 | Local<Object> that = args.This(); |
395 | |
|
396 | 0 | ModuleWrap* obj; |
397 | 0 | ASSIGN_OR_RETURN_UNWRAP(&obj, that); |
398 | | |
399 | 0 | if (obj->linked_) |
400 | 0 | return; |
401 | 0 | obj->linked_ = true; |
402 | |
|
403 | 0 | Local<Function> resolver_arg = args[0].As<Function>(); |
404 | |
|
405 | 0 | Local<Context> mod_context = obj->context(); |
406 | 0 | Local<Module> module = obj->module_.Get(isolate); |
407 | |
|
408 | 0 | Local<FixedArray> module_requests = module->GetModuleRequests(); |
409 | 0 | const int module_requests_length = module_requests->Length(); |
410 | 0 | MaybeStackBuffer<Local<Value>, 16> promises(module_requests_length); |
411 | | |
412 | | // call the dependency resolve callbacks |
413 | 0 | for (int i = 0; i < module_requests_length; i++) { |
414 | 0 | Local<ModuleRequest> module_request = |
415 | 0 | module_requests->Get(realm->context(), i).As<ModuleRequest>(); |
416 | 0 | Local<String> specifier = module_request->GetSpecifier(); |
417 | 0 | Utf8Value specifier_utf8(realm->isolate(), specifier); |
418 | 0 | std::string specifier_std(*specifier_utf8, specifier_utf8.length()); |
419 | |
|
420 | 0 | Local<FixedArray> raw_attributes = module_request->GetImportAssertions(); |
421 | 0 | Local<Object> attributes = |
422 | 0 | createImportAttributesContainer(realm, isolate, raw_attributes, 3); |
423 | |
|
424 | 0 | Local<Value> argv[] = { |
425 | 0 | specifier, |
426 | 0 | attributes, |
427 | 0 | }; |
428 | |
|
429 | 0 | MaybeLocal<Value> maybe_resolve_return_value = |
430 | 0 | resolver_arg->Call(mod_context, that, arraysize(argv), argv); |
431 | 0 | if (maybe_resolve_return_value.IsEmpty()) { |
432 | 0 | return; |
433 | 0 | } |
434 | 0 | Local<Value> resolve_return_value = |
435 | 0 | maybe_resolve_return_value.ToLocalChecked(); |
436 | 0 | if (!resolve_return_value->IsPromise()) { |
437 | 0 | THROW_ERR_VM_MODULE_LINK_FAILURE( |
438 | 0 | realm, "request for '%s' did not return promise", specifier_std); |
439 | 0 | return; |
440 | 0 | } |
441 | 0 | Local<Promise> resolve_promise = resolve_return_value.As<Promise>(); |
442 | 0 | obj->resolve_cache_[specifier_std].Reset(isolate, resolve_promise); |
443 | |
|
444 | 0 | promises[i] = resolve_promise; |
445 | 0 | } |
446 | | |
447 | 0 | args.GetReturnValue().Set( |
448 | 0 | Array::New(isolate, promises.out(), promises.length())); |
449 | 0 | } |
450 | | |
451 | 0 | void ModuleWrap::Instantiate(const FunctionCallbackInfo<Value>& args) { |
452 | 0 | Realm* realm = Realm::GetCurrent(args); |
453 | 0 | Isolate* isolate = args.GetIsolate(); |
454 | 0 | ModuleWrap* obj; |
455 | 0 | ASSIGN_OR_RETURN_UNWRAP(&obj, args.This()); |
456 | 0 | Local<Context> context = obj->context(); |
457 | 0 | Local<Module> module = obj->module_.Get(isolate); |
458 | 0 | TryCatchScope try_catch(realm->env()); |
459 | 0 | USE(module->InstantiateModule(context, ResolveModuleCallback)); |
460 | | |
461 | | // clear resolve cache on instantiate |
462 | 0 | obj->resolve_cache_.clear(); |
463 | |
|
464 | 0 | if (try_catch.HasCaught() && !try_catch.HasTerminated()) { |
465 | 0 | CHECK(!try_catch.Message().IsEmpty()); |
466 | 0 | CHECK(!try_catch.Exception().IsEmpty()); |
467 | 0 | AppendExceptionLine(realm->env(), |
468 | 0 | try_catch.Exception(), |
469 | 0 | try_catch.Message(), |
470 | 0 | ErrorHandlingMode::MODULE_ERROR); |
471 | 0 | try_catch.ReThrow(); |
472 | 0 | return; |
473 | 0 | } |
474 | 0 | } |
475 | | |
476 | 0 | void ModuleWrap::Evaluate(const FunctionCallbackInfo<Value>& args) { |
477 | 0 | Realm* realm = Realm::GetCurrent(args); |
478 | 0 | Isolate* isolate = realm->isolate(); |
479 | 0 | ModuleWrap* obj; |
480 | 0 | ASSIGN_OR_RETURN_UNWRAP(&obj, args.This()); |
481 | 0 | Local<Context> context = obj->context(); |
482 | 0 | Local<Module> module = obj->module_.Get(isolate); |
483 | |
|
484 | 0 | ContextifyContext* contextify_context = obj->contextify_context_; |
485 | 0 | MicrotaskQueue* microtask_queue = nullptr; |
486 | 0 | if (contextify_context != nullptr) |
487 | 0 | microtask_queue = contextify_context->microtask_queue(); |
488 | | |
489 | | // module.evaluate(timeout, breakOnSigint) |
490 | 0 | CHECK_EQ(args.Length(), 2); |
491 | | |
492 | 0 | CHECK(args[0]->IsNumber()); |
493 | 0 | int64_t timeout = args[0]->IntegerValue(realm->context()).FromJust(); |
494 | |
|
495 | 0 | CHECK(args[1]->IsBoolean()); |
496 | 0 | bool break_on_sigint = args[1]->IsTrue(); |
497 | |
|
498 | 0 | ShouldNotAbortOnUncaughtScope no_abort_scope(realm->env()); |
499 | 0 | TryCatchScope try_catch(realm->env()); |
500 | 0 | Isolate::SafeForTerminationScope safe_for_termination(isolate); |
501 | |
|
502 | 0 | bool timed_out = false; |
503 | 0 | bool received_signal = false; |
504 | 0 | MaybeLocal<Value> result; |
505 | 0 | auto run = [&]() { |
506 | 0 | MaybeLocal<Value> result = module->Evaluate(context); |
507 | 0 | if (!result.IsEmpty() && microtask_queue) |
508 | 0 | microtask_queue->PerformCheckpoint(isolate); |
509 | 0 | return result; |
510 | 0 | }; |
511 | 0 | if (break_on_sigint && timeout != -1) { |
512 | 0 | Watchdog wd(isolate, timeout, &timed_out); |
513 | 0 | SigintWatchdog swd(isolate, &received_signal); |
514 | 0 | result = run(); |
515 | 0 | } else if (break_on_sigint) { |
516 | 0 | SigintWatchdog swd(isolate, &received_signal); |
517 | 0 | result = run(); |
518 | 0 | } else if (timeout != -1) { |
519 | 0 | Watchdog wd(isolate, timeout, &timed_out); |
520 | 0 | result = run(); |
521 | 0 | } else { |
522 | 0 | result = run(); |
523 | 0 | } |
524 | |
|
525 | 0 | if (result.IsEmpty()) { |
526 | 0 | CHECK(try_catch.HasCaught()); |
527 | 0 | } |
528 | | |
529 | | // Convert the termination exception into a regular exception. |
530 | 0 | if (timed_out || received_signal) { |
531 | 0 | if (!realm->env()->is_main_thread() && realm->env()->is_stopping()) return; |
532 | 0 | isolate->CancelTerminateExecution(); |
533 | | // It is possible that execution was terminated by another timeout in |
534 | | // which this timeout is nested, so check whether one of the watchdogs |
535 | | // from this invocation is responsible for termination. |
536 | 0 | if (timed_out) { |
537 | 0 | THROW_ERR_SCRIPT_EXECUTION_TIMEOUT(realm->env(), timeout); |
538 | 0 | } else if (received_signal) { |
539 | 0 | THROW_ERR_SCRIPT_EXECUTION_INTERRUPTED(realm->env()); |
540 | 0 | } |
541 | 0 | } |
542 | | |
543 | 0 | if (try_catch.HasCaught()) { |
544 | 0 | if (!try_catch.HasTerminated()) |
545 | 0 | try_catch.ReThrow(); |
546 | 0 | return; |
547 | 0 | } |
548 | | |
549 | 0 | args.GetReturnValue().Set(result.ToLocalChecked()); |
550 | 0 | } |
551 | | |
552 | 0 | void ModuleWrap::InstantiateSync(const FunctionCallbackInfo<Value>& args) { |
553 | 0 | Realm* realm = Realm::GetCurrent(args); |
554 | 0 | Isolate* isolate = args.GetIsolate(); |
555 | 0 | ModuleWrap* obj; |
556 | 0 | ASSIGN_OR_RETURN_UNWRAP(&obj, args.This()); |
557 | 0 | Local<Context> context = obj->context(); |
558 | 0 | Local<Module> module = obj->module_.Get(isolate); |
559 | 0 | Environment* env = realm->env(); |
560 | |
|
561 | 0 | { |
562 | 0 | TryCatchScope try_catch(env); |
563 | 0 | USE(module->InstantiateModule(context, ResolveModuleCallback)); |
564 | | |
565 | | // clear resolve cache on instantiate |
566 | 0 | obj->resolve_cache_.clear(); |
567 | |
|
568 | 0 | if (try_catch.HasCaught() && !try_catch.HasTerminated()) { |
569 | 0 | CHECK(!try_catch.Message().IsEmpty()); |
570 | 0 | CHECK(!try_catch.Exception().IsEmpty()); |
571 | 0 | AppendExceptionLine(env, |
572 | 0 | try_catch.Exception(), |
573 | 0 | try_catch.Message(), |
574 | 0 | ErrorHandlingMode::MODULE_ERROR); |
575 | 0 | try_catch.ReThrow(); |
576 | 0 | return; |
577 | 0 | } |
578 | 0 | } |
579 | | |
580 | | // If --experimental-print-required-tla is true, proceeds to evaluation even |
581 | | // if it's async because we want to search for the TLA and help users locate |
582 | | // them. |
583 | 0 | if (module->IsGraphAsync() && !env->options()->print_required_tla) { |
584 | 0 | THROW_ERR_REQUIRE_ASYNC_MODULE(env); |
585 | 0 | return; |
586 | 0 | } |
587 | 0 | } |
588 | | |
589 | 0 | void ModuleWrap::EvaluateSync(const FunctionCallbackInfo<Value>& args) { |
590 | 0 | Realm* realm = Realm::GetCurrent(args); |
591 | 0 | Isolate* isolate = args.GetIsolate(); |
592 | 0 | ModuleWrap* obj; |
593 | 0 | ASSIGN_OR_RETURN_UNWRAP(&obj, args.This()); |
594 | 0 | Local<Context> context = obj->context(); |
595 | 0 | Local<Module> module = obj->module_.Get(isolate); |
596 | 0 | Environment* env = realm->env(); |
597 | |
|
598 | 0 | Local<Value> result; |
599 | 0 | { |
600 | 0 | TryCatchScope try_catch(env); |
601 | 0 | if (!module->Evaluate(context).ToLocal(&result)) { |
602 | 0 | if (try_catch.HasCaught()) { |
603 | 0 | if (!try_catch.HasTerminated()) { |
604 | 0 | try_catch.ReThrow(); |
605 | 0 | } |
606 | 0 | return; |
607 | 0 | } |
608 | 0 | } |
609 | 0 | } |
610 | | |
611 | 0 | CHECK(result->IsPromise()); |
612 | 0 | Local<Promise> promise = result.As<Promise>(); |
613 | 0 | if (promise->State() == Promise::PromiseState::kRejected) { |
614 | 0 | Local<Value> exception = promise->Result(); |
615 | 0 | Local<v8::Message> message = |
616 | 0 | v8::Exception::CreateMessage(isolate, exception); |
617 | 0 | AppendExceptionLine( |
618 | 0 | env, exception, message, ErrorHandlingMode::MODULE_ERROR); |
619 | 0 | isolate->ThrowException(exception); |
620 | 0 | return; |
621 | 0 | } |
622 | | |
623 | 0 | if (module->IsGraphAsync()) { |
624 | 0 | CHECK(env->options()->print_required_tla); |
625 | 0 | auto stalled_messages = |
626 | 0 | std::get<1>(module->GetStalledTopLevelAwaitMessages(isolate)); |
627 | 0 | if (stalled_messages.size() != 0) { |
628 | 0 | for (auto& message : stalled_messages) { |
629 | 0 | std::string reason = "Error: unexpected top-level await at "; |
630 | 0 | std::string info = |
631 | 0 | FormatErrorMessage(isolate, context, "", message, true); |
632 | 0 | reason += info; |
633 | 0 | FPrintF(stderr, "%s\n", reason); |
634 | 0 | } |
635 | 0 | } |
636 | 0 | THROW_ERR_REQUIRE_ASYNC_MODULE(env); |
637 | 0 | return; |
638 | 0 | } |
639 | | |
640 | 0 | CHECK_EQ(promise->State(), Promise::PromiseState::kFulfilled); |
641 | | |
642 | 0 | args.GetReturnValue().Set(module->GetModuleNamespace()); |
643 | 0 | } |
644 | | |
645 | 0 | void ModuleWrap::GetNamespaceSync(const FunctionCallbackInfo<Value>& args) { |
646 | 0 | Realm* realm = Realm::GetCurrent(args); |
647 | 0 | Isolate* isolate = args.GetIsolate(); |
648 | 0 | ModuleWrap* obj; |
649 | 0 | ASSIGN_OR_RETURN_UNWRAP(&obj, args.This()); |
650 | 0 | Local<Module> module = obj->module_.Get(isolate); |
651 | |
|
652 | 0 | switch (module->GetStatus()) { |
653 | 0 | case v8::Module::Status::kUninstantiated: |
654 | 0 | case v8::Module::Status::kInstantiating: |
655 | 0 | return realm->env()->ThrowError( |
656 | 0 | "cannot get namespace, module has not been instantiated"); |
657 | 0 | case v8::Module::Status::kEvaluating: |
658 | 0 | return THROW_ERR_REQUIRE_ASYNC_MODULE(realm->env()); |
659 | 0 | case v8::Module::Status::kInstantiated: |
660 | 0 | case v8::Module::Status::kEvaluated: |
661 | 0 | case v8::Module::Status::kErrored: |
662 | 0 | break; |
663 | 0 | default: |
664 | 0 | UNREACHABLE(); |
665 | 0 | } |
666 | | |
667 | 0 | if (module->IsGraphAsync()) { |
668 | 0 | return THROW_ERR_REQUIRE_ASYNC_MODULE(realm->env()); |
669 | 0 | } |
670 | 0 | Local<Value> result = module->GetModuleNamespace(); |
671 | 0 | args.GetReturnValue().Set(result); |
672 | 0 | } |
673 | | |
674 | 0 | void ModuleWrap::GetNamespace(const FunctionCallbackInfo<Value>& args) { |
675 | 0 | Realm* realm = Realm::GetCurrent(args); |
676 | 0 | Isolate* isolate = args.GetIsolate(); |
677 | 0 | ModuleWrap* obj; |
678 | 0 | ASSIGN_OR_RETURN_UNWRAP(&obj, args.This()); |
679 | | |
680 | 0 | Local<Module> module = obj->module_.Get(isolate); |
681 | |
|
682 | 0 | switch (module->GetStatus()) { |
683 | 0 | case v8::Module::Status::kUninstantiated: |
684 | 0 | case v8::Module::Status::kInstantiating: |
685 | 0 | return realm->env()->ThrowError( |
686 | 0 | "cannot get namespace, module has not been instantiated"); |
687 | 0 | case v8::Module::Status::kInstantiated: |
688 | 0 | case v8::Module::Status::kEvaluating: |
689 | 0 | case v8::Module::Status::kEvaluated: |
690 | 0 | case v8::Module::Status::kErrored: |
691 | 0 | break; |
692 | 0 | default: |
693 | 0 | UNREACHABLE(); |
694 | 0 | } |
695 | | |
696 | 0 | Local<Value> result = module->GetModuleNamespace(); |
697 | 0 | args.GetReturnValue().Set(result); |
698 | 0 | } |
699 | | |
700 | 0 | void ModuleWrap::GetStatus(const FunctionCallbackInfo<Value>& args) { |
701 | 0 | Isolate* isolate = args.GetIsolate(); |
702 | 0 | ModuleWrap* obj; |
703 | 0 | ASSIGN_OR_RETURN_UNWRAP(&obj, args.This()); |
704 | | |
705 | 0 | Local<Module> module = obj->module_.Get(isolate); |
706 | |
|
707 | 0 | args.GetReturnValue().Set(module->GetStatus()); |
708 | 0 | } |
709 | | |
710 | | void ModuleWrap::GetStaticDependencySpecifiers( |
711 | 0 | const FunctionCallbackInfo<Value>& args) { |
712 | 0 | Realm* realm = Realm::GetCurrent(args); |
713 | 0 | ModuleWrap* obj; |
714 | 0 | ASSIGN_OR_RETURN_UNWRAP(&obj, args.This()); |
715 | | |
716 | 0 | Local<Module> module = obj->module_.Get(realm->isolate()); |
717 | |
|
718 | 0 | Local<FixedArray> module_requests = module->GetModuleRequests(); |
719 | 0 | int count = module_requests->Length(); |
720 | |
|
721 | 0 | MaybeStackBuffer<Local<Value>, 16> specifiers(count); |
722 | |
|
723 | 0 | for (int i = 0; i < count; i++) { |
724 | 0 | Local<ModuleRequest> module_request = |
725 | 0 | module_requests->Get(realm->context(), i).As<ModuleRequest>(); |
726 | 0 | specifiers[i] = module_request->GetSpecifier(); |
727 | 0 | } |
728 | |
|
729 | 0 | args.GetReturnValue().Set( |
730 | 0 | Array::New(realm->isolate(), specifiers.out(), count)); |
731 | 0 | } |
732 | | |
733 | 0 | void ModuleWrap::GetError(const FunctionCallbackInfo<Value>& args) { |
734 | 0 | Isolate* isolate = args.GetIsolate(); |
735 | 0 | ModuleWrap* obj; |
736 | 0 | ASSIGN_OR_RETURN_UNWRAP(&obj, args.This()); |
737 | | |
738 | 0 | Local<Module> module = obj->module_.Get(isolate); |
739 | 0 | args.GetReturnValue().Set(module->GetException()); |
740 | 0 | } |
741 | | |
742 | | MaybeLocal<Module> ModuleWrap::ResolveModuleCallback( |
743 | | Local<Context> context, |
744 | | Local<String> specifier, |
745 | | Local<FixedArray> import_attributes, |
746 | 0 | Local<Module> referrer) { |
747 | 0 | Isolate* isolate = context->GetIsolate(); |
748 | 0 | Environment* env = Environment::GetCurrent(context); |
749 | 0 | if (env == nullptr) { |
750 | 0 | THROW_ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE(isolate); |
751 | 0 | return MaybeLocal<Module>(); |
752 | 0 | } |
753 | | |
754 | 0 | Utf8Value specifier_utf8(isolate, specifier); |
755 | 0 | std::string specifier_std(*specifier_utf8, specifier_utf8.length()); |
756 | |
|
757 | 0 | ModuleWrap* dependent = GetFromModule(env, referrer); |
758 | 0 | if (dependent == nullptr) { |
759 | 0 | THROW_ERR_VM_MODULE_LINK_FAILURE( |
760 | 0 | env, "request for '%s' is from invalid module", specifier_std); |
761 | 0 | return MaybeLocal<Module>(); |
762 | 0 | } |
763 | | |
764 | 0 | if (dependent->resolve_cache_.count(specifier_std) != 1) { |
765 | 0 | THROW_ERR_VM_MODULE_LINK_FAILURE( |
766 | 0 | env, "request for '%s' is not in cache", specifier_std); |
767 | 0 | return MaybeLocal<Module>(); |
768 | 0 | } |
769 | | |
770 | 0 | Local<Promise> resolve_promise = |
771 | 0 | dependent->resolve_cache_[specifier_std].Get(isolate); |
772 | |
|
773 | 0 | if (resolve_promise->State() != Promise::kFulfilled) { |
774 | 0 | THROW_ERR_VM_MODULE_LINK_FAILURE( |
775 | 0 | env, "request for '%s' is not yet fulfilled", specifier_std); |
776 | 0 | return MaybeLocal<Module>(); |
777 | 0 | } |
778 | | |
779 | 0 | Local<Object> module_object = resolve_promise->Result().As<Object>(); |
780 | 0 | if (module_object.IsEmpty() || !module_object->IsObject()) { |
781 | 0 | THROW_ERR_VM_MODULE_LINK_FAILURE( |
782 | 0 | env, "request for '%s' did not return an object", specifier_std); |
783 | 0 | return MaybeLocal<Module>(); |
784 | 0 | } |
785 | | |
786 | 0 | ModuleWrap* module; |
787 | 0 | ASSIGN_OR_RETURN_UNWRAP(&module, module_object, MaybeLocal<Module>()); |
788 | 0 | return module->module_.Get(isolate); |
789 | 0 | } |
790 | | |
791 | | static MaybeLocal<Promise> ImportModuleDynamically( |
792 | | Local<Context> context, |
793 | | Local<v8::Data> host_defined_options, |
794 | | Local<Value> resource_name, |
795 | | Local<String> specifier, |
796 | 0 | Local<FixedArray> import_attributes) { |
797 | 0 | Isolate* isolate = context->GetIsolate(); |
798 | 0 | Environment* env = Environment::GetCurrent(context); |
799 | 0 | if (env == nullptr) { |
800 | 0 | THROW_ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE(isolate); |
801 | 0 | return MaybeLocal<Promise>(); |
802 | 0 | } |
803 | 0 | Realm* realm = Realm::GetCurrent(context); |
804 | 0 | if (realm == nullptr) { |
805 | | // Fallback to the principal realm if it's in a vm context. |
806 | 0 | realm = env->principal_realm(); |
807 | 0 | } |
808 | |
|
809 | 0 | EscapableHandleScope handle_scope(isolate); |
810 | |
|
811 | 0 | Local<Function> import_callback = |
812 | 0 | realm->host_import_module_dynamically_callback(); |
813 | 0 | Local<Value> id; |
814 | |
|
815 | 0 | Local<FixedArray> options = host_defined_options.As<FixedArray>(); |
816 | | // Get referrer id symbol from the host-defined options. |
817 | | // If the host-defined options are empty, get the referrer id symbol |
818 | | // from the realm global object. |
819 | 0 | if (options->Length() == HostDefinedOptions::kLength) { |
820 | 0 | id = options->Get(context, HostDefinedOptions::kID).As<Symbol>(); |
821 | 0 | } else { |
822 | 0 | id = context->Global() |
823 | 0 | ->GetPrivate(context, env->host_defined_option_symbol()) |
824 | 0 | .ToLocalChecked(); |
825 | 0 | } |
826 | |
|
827 | 0 | Local<Object> attributes = |
828 | 0 | createImportAttributesContainer(realm, isolate, import_attributes, 2); |
829 | |
|
830 | 0 | Local<Value> import_args[] = { |
831 | 0 | id, |
832 | 0 | Local<Value>(specifier), |
833 | 0 | attributes, |
834 | 0 | resource_name, |
835 | 0 | }; |
836 | |
|
837 | 0 | Local<Value> result; |
838 | 0 | if (import_callback->Call( |
839 | 0 | context, |
840 | 0 | Undefined(isolate), |
841 | 0 | arraysize(import_args), |
842 | 0 | import_args).ToLocal(&result)) { |
843 | 0 | CHECK(result->IsPromise()); |
844 | 0 | return handle_scope.Escape(result.As<Promise>()); |
845 | 0 | } |
846 | | |
847 | 0 | return MaybeLocal<Promise>(); |
848 | 0 | } |
849 | | |
850 | | void ModuleWrap::SetImportModuleDynamicallyCallback( |
851 | 126k | const FunctionCallbackInfo<Value>& args) { |
852 | 126k | Isolate* isolate = args.GetIsolate(); |
853 | 126k | Realm* realm = Realm::GetCurrent(args); |
854 | 126k | HandleScope handle_scope(isolate); |
855 | | |
856 | 126k | CHECK_EQ(args.Length(), 1); |
857 | 126k | CHECK(args[0]->IsFunction()); |
858 | 126k | Local<Function> import_callback = args[0].As<Function>(); |
859 | 126k | realm->set_host_import_module_dynamically_callback(import_callback); |
860 | | |
861 | 126k | isolate->SetHostImportModuleDynamicallyCallback(ImportModuleDynamically); |
862 | 126k | } |
863 | | |
864 | | void ModuleWrap::HostInitializeImportMetaObjectCallback( |
865 | 0 | Local<Context> context, Local<Module> module, Local<Object> meta) { |
866 | 0 | Environment* env = Environment::GetCurrent(context); |
867 | 0 | if (env == nullptr) |
868 | 0 | return; |
869 | 0 | ModuleWrap* module_wrap = GetFromModule(env, module); |
870 | |
|
871 | 0 | if (module_wrap == nullptr) { |
872 | 0 | return; |
873 | 0 | } |
874 | 0 | Realm* realm = Realm::GetCurrent(context); |
875 | 0 | if (realm == nullptr) { |
876 | | // Fallback to the principal realm if it's in a vm context. |
877 | 0 | realm = env->principal_realm(); |
878 | 0 | } |
879 | |
|
880 | 0 | Local<Object> wrap = module_wrap->object(); |
881 | 0 | Local<Function> callback = |
882 | 0 | realm->host_initialize_import_meta_object_callback(); |
883 | 0 | Local<Value> id; |
884 | 0 | if (!wrap->GetPrivate(context, env->host_defined_option_symbol()) |
885 | 0 | .ToLocal(&id)) { |
886 | 0 | return; |
887 | 0 | } |
888 | 0 | DCHECK(id->IsSymbol()); |
889 | 0 | Local<Value> args[] = {id, meta, wrap}; |
890 | 0 | TryCatchScope try_catch(env); |
891 | 0 | USE(callback->Call( |
892 | 0 | context, Undefined(realm->isolate()), arraysize(args), args)); |
893 | 0 | if (try_catch.HasCaught() && !try_catch.HasTerminated()) { |
894 | 0 | try_catch.ReThrow(); |
895 | 0 | } |
896 | 0 | } |
897 | | |
898 | | void ModuleWrap::SetInitializeImportMetaObjectCallback( |
899 | 126k | const FunctionCallbackInfo<Value>& args) { |
900 | 126k | Realm* realm = Realm::GetCurrent(args); |
901 | 126k | Isolate* isolate = realm->isolate(); |
902 | | |
903 | 126k | CHECK_EQ(args.Length(), 1); |
904 | 126k | CHECK(args[0]->IsFunction()); |
905 | 126k | Local<Function> import_meta_callback = args[0].As<Function>(); |
906 | 126k | realm->set_host_initialize_import_meta_object_callback(import_meta_callback); |
907 | | |
908 | 126k | isolate->SetHostInitializeImportMetaObjectCallback( |
909 | 126k | HostInitializeImportMetaObjectCallback); |
910 | 126k | } |
911 | | |
912 | | MaybeLocal<Value> ModuleWrap::SyntheticModuleEvaluationStepsCallback( |
913 | 0 | Local<Context> context, Local<Module> module) { |
914 | 0 | Environment* env = Environment::GetCurrent(context); |
915 | 0 | Isolate* isolate = env->isolate(); |
916 | |
|
917 | 0 | ModuleWrap* obj = GetFromModule(env, module); |
918 | |
|
919 | 0 | TryCatchScope try_catch(env); |
920 | 0 | Local<Function> synthetic_evaluation_steps = |
921 | 0 | obj->object() |
922 | 0 | ->GetInternalField(kSyntheticEvaluationStepsSlot) |
923 | 0 | .As<Value>() |
924 | 0 | .As<Function>(); |
925 | 0 | obj->object()->SetInternalField( |
926 | 0 | kSyntheticEvaluationStepsSlot, Undefined(isolate)); |
927 | 0 | MaybeLocal<Value> ret = synthetic_evaluation_steps->Call(context, |
928 | 0 | obj->object(), 0, nullptr); |
929 | 0 | if (ret.IsEmpty()) { |
930 | 0 | CHECK(try_catch.HasCaught()); |
931 | 0 | } |
932 | 0 | if (try_catch.HasCaught() && !try_catch.HasTerminated()) { |
933 | 0 | CHECK(!try_catch.Message().IsEmpty()); |
934 | 0 | CHECK(!try_catch.Exception().IsEmpty()); |
935 | 0 | try_catch.ReThrow(); |
936 | 0 | return MaybeLocal<Value>(); |
937 | 0 | } |
938 | | |
939 | 0 | Local<Promise::Resolver> resolver; |
940 | 0 | if (!Promise::Resolver::New(context).ToLocal(&resolver)) { |
941 | 0 | return MaybeLocal<Value>(); |
942 | 0 | } |
943 | | |
944 | 0 | resolver->Resolve(context, Undefined(isolate)).ToChecked(); |
945 | 0 | return resolver->GetPromise(); |
946 | 0 | } |
947 | | |
948 | 0 | void ModuleWrap::SetSyntheticExport(const FunctionCallbackInfo<Value>& args) { |
949 | 0 | Isolate* isolate = args.GetIsolate(); |
950 | 0 | Local<Object> that = args.This(); |
951 | |
|
952 | 0 | ModuleWrap* obj; |
953 | 0 | ASSIGN_OR_RETURN_UNWRAP(&obj, that); |
954 | | |
955 | 0 | CHECK(obj->synthetic_); |
956 | | |
957 | 0 | CHECK_EQ(args.Length(), 2); |
958 | | |
959 | 0 | CHECK(args[0]->IsString()); |
960 | 0 | Local<String> export_name = args[0].As<String>(); |
961 | |
|
962 | 0 | Local<Value> export_value = args[1]; |
963 | |
|
964 | 0 | Local<Module> module = obj->module_.Get(isolate); |
965 | 0 | USE(module->SetSyntheticModuleExport(isolate, export_name, export_value)); |
966 | 0 | } |
967 | | |
968 | 0 | void ModuleWrap::CreateCachedData(const FunctionCallbackInfo<Value>& args) { |
969 | 0 | Isolate* isolate = args.GetIsolate(); |
970 | 0 | Local<Object> that = args.This(); |
971 | |
|
972 | 0 | ModuleWrap* obj; |
973 | 0 | ASSIGN_OR_RETURN_UNWRAP(&obj, that); |
974 | | |
975 | 0 | CHECK(!obj->synthetic_); |
976 | | |
977 | 0 | Local<Module> module = obj->module_.Get(isolate); |
978 | |
|
979 | 0 | CHECK_LT(module->GetStatus(), v8::Module::Status::kEvaluating); |
980 | | |
981 | 0 | Local<UnboundModuleScript> unbound_module_script = |
982 | 0 | module->GetUnboundModuleScript(); |
983 | 0 | std::unique_ptr<ScriptCompiler::CachedData> cached_data( |
984 | 0 | ScriptCompiler::CreateCodeCache(unbound_module_script)); |
985 | 0 | Environment* env = Environment::GetCurrent(args); |
986 | 0 | if (!cached_data) { |
987 | 0 | args.GetReturnValue().Set(Buffer::New(env, 0).ToLocalChecked()); |
988 | 0 | } else { |
989 | 0 | MaybeLocal<Object> buf = |
990 | 0 | Buffer::Copy(env, |
991 | 0 | reinterpret_cast<const char*>(cached_data->data), |
992 | 0 | cached_data->length); |
993 | 0 | args.GetReturnValue().Set(buf.ToLocalChecked()); |
994 | 0 | } |
995 | 0 | } |
996 | | |
997 | | void ModuleWrap::CreatePerIsolateProperties(IsolateData* isolate_data, |
998 | 126k | Local<ObjectTemplate> target) { |
999 | 126k | Isolate* isolate = isolate_data->isolate(); |
1000 | | |
1001 | 126k | Local<FunctionTemplate> tpl = NewFunctionTemplate(isolate, New); |
1002 | 126k | tpl->InstanceTemplate()->SetInternalFieldCount( |
1003 | 126k | ModuleWrap::kInternalFieldCount); |
1004 | | |
1005 | 126k | SetProtoMethod(isolate, tpl, "link", Link); |
1006 | 126k | SetProtoMethod(isolate, tpl, "getModuleRequestsSync", GetModuleRequestsSync); |
1007 | 126k | SetProtoMethod( |
1008 | 126k | isolate, tpl, "cacheResolvedWrapsSync", CacheResolvedWrapsSync); |
1009 | 126k | SetProtoMethod(isolate, tpl, "instantiateSync", InstantiateSync); |
1010 | 126k | SetProtoMethod(isolate, tpl, "evaluateSync", EvaluateSync); |
1011 | 126k | SetProtoMethod(isolate, tpl, "getNamespaceSync", GetNamespaceSync); |
1012 | 126k | SetProtoMethod(isolate, tpl, "instantiate", Instantiate); |
1013 | 126k | SetProtoMethod(isolate, tpl, "evaluate", Evaluate); |
1014 | 126k | SetProtoMethod(isolate, tpl, "setExport", SetSyntheticExport); |
1015 | 126k | SetProtoMethodNoSideEffect( |
1016 | 126k | isolate, tpl, "createCachedData", CreateCachedData); |
1017 | 126k | SetProtoMethodNoSideEffect(isolate, tpl, "getNamespace", GetNamespace); |
1018 | 126k | SetProtoMethodNoSideEffect(isolate, tpl, "getStatus", GetStatus); |
1019 | 126k | SetProtoMethodNoSideEffect(isolate, tpl, "getError", GetError); |
1020 | 126k | SetProtoMethodNoSideEffect(isolate, |
1021 | 126k | tpl, |
1022 | 126k | "getStaticDependencySpecifiers", |
1023 | 126k | GetStaticDependencySpecifiers); |
1024 | | |
1025 | 126k | SetConstructorFunction(isolate, target, "ModuleWrap", tpl); |
1026 | | |
1027 | 126k | SetMethod(isolate, |
1028 | 126k | target, |
1029 | 126k | "setImportModuleDynamicallyCallback", |
1030 | 126k | SetImportModuleDynamicallyCallback); |
1031 | 126k | SetMethod(isolate, |
1032 | 126k | target, |
1033 | 126k | "setInitializeImportMetaObjectCallback", |
1034 | 126k | SetInitializeImportMetaObjectCallback); |
1035 | 126k | } |
1036 | | |
1037 | | void ModuleWrap::CreatePerContextProperties(Local<Object> target, |
1038 | | Local<Value> unused, |
1039 | | Local<Context> context, |
1040 | 126k | void* priv) { |
1041 | 126k | Realm* realm = Realm::GetCurrent(context); |
1042 | 126k | Isolate* isolate = realm->isolate(); |
1043 | 126k | #define V(name) \ |
1044 | 761k | target \ |
1045 | 761k | ->Set(context, \ |
1046 | 761k | FIXED_ONE_BYTE_STRING(isolate, #name), \ |
1047 | 761k | Integer::New(isolate, Module::Status::name)) \ |
1048 | 761k | .FromJust() |
1049 | 126k | V(kUninstantiated); |
1050 | 126k | V(kInstantiating); |
1051 | 126k | V(kInstantiated); |
1052 | 126k | V(kEvaluating); |
1053 | 126k | V(kEvaluated); |
1054 | 126k | V(kErrored); |
1055 | 126k | #undef V |
1056 | 126k | } |
1057 | | |
1058 | | void ModuleWrap::RegisterExternalReferences( |
1059 | 0 | ExternalReferenceRegistry* registry) { |
1060 | 0 | registry->Register(New); |
1061 | |
|
1062 | 0 | registry->Register(Link); |
1063 | 0 | registry->Register(GetModuleRequestsSync); |
1064 | 0 | registry->Register(CacheResolvedWrapsSync); |
1065 | 0 | registry->Register(InstantiateSync); |
1066 | 0 | registry->Register(EvaluateSync); |
1067 | 0 | registry->Register(GetNamespaceSync); |
1068 | 0 | registry->Register(Instantiate); |
1069 | 0 | registry->Register(Evaluate); |
1070 | 0 | registry->Register(SetSyntheticExport); |
1071 | 0 | registry->Register(CreateCachedData); |
1072 | 0 | registry->Register(GetNamespace); |
1073 | 0 | registry->Register(GetStatus); |
1074 | 0 | registry->Register(GetError); |
1075 | 0 | registry->Register(GetStaticDependencySpecifiers); |
1076 | |
|
1077 | 0 | registry->Register(SetImportModuleDynamicallyCallback); |
1078 | 0 | registry->Register(SetInitializeImportMetaObjectCallback); |
1079 | 0 | } |
1080 | | } // namespace loader |
1081 | | } // namespace node |
1082 | | |
1083 | | NODE_BINDING_CONTEXT_AWARE_INTERNAL( |
1084 | | module_wrap, node::loader::ModuleWrap::CreatePerContextProperties) |
1085 | | NODE_BINDING_PER_ISOLATE_INIT( |
1086 | | module_wrap, node::loader::ModuleWrap::CreatePerIsolateProperties) |
1087 | | NODE_BINDING_EXTERNAL_REFERENCE( |
1088 | | module_wrap, node::loader::ModuleWrap::RegisterExternalReferences) |