@@ -142,9 +142,17 @@ v8::Maybe<bool> ModuleWrap::CheckUnsettledTopLevelAwait() {
142142 return v8::Just (false );
143143}
144144
145- // new ModuleWrap(url, context, source, lineOffset, columnOffset, cachedData)
145+ Local<PrimitiveArray> ModuleWrap::GetHostDefinedOptions (
146+ Isolate* isolate, Local<Symbol> id_symbol) {
147+ Local<PrimitiveArray> host_defined_options =
148+ PrimitiveArray::New (isolate, HostDefinedOptions::kLength );
149+ host_defined_options->Set (isolate, HostDefinedOptions::kID , id_symbol);
150+ return host_defined_options;
151+ }
152+
153+ // new ModuleWrap(url, context, source, lineOffset, columnOffset[, cachedData]);
146154// new ModuleWrap(url, context, source, lineOffset, columOffset,
147- // hostDefinedOption)
155+ // idSymbol);
148156// new ModuleWrap(url, context, exportNames, evaluationCallback[, cjsModule])
149157void ModuleWrap::New (const FunctionCallbackInfo<Value>& args) {
150158 CHECK (args.IsConstructCall ());
@@ -183,9 +191,10 @@ void ModuleWrap::New(const FunctionCallbackInfo<Value>& args) {
183191 // cjsModule])
184192 CHECK (args[3 ]->IsFunction ());
185193 } else {
186- // new ModuleWrap(url, context, source, lineOffset, columOffset, cachedData)
194+ // new ModuleWrap(url, context, source, lineOffset, columOffset[,
195+ // cachedData]);
187196 // new ModuleWrap(url, context, source, lineOffset, columOffset,
188- // hostDefinedOption)
197+ // idSymbol);
189198 CHECK (args[2 ]->IsString ());
190199 CHECK (args[3 ]->IsNumber ());
191200 line_offset = args[3 ].As <Int32>()->Value ();
@@ -199,7 +208,7 @@ void ModuleWrap::New(const FunctionCallbackInfo<Value>& args) {
199208 } else {
200209 id_symbol = Symbol::New (isolate, url);
201210 }
202- host_defined_options-> Set (isolate, HostDefinedOptions:: kID , id_symbol);
211+ host_defined_options = GetHostDefinedOptions (isolate, id_symbol);
203212
204213 if (that->SetPrivate (context,
205214 realm->isolate_data ()->host_defined_option_symbol (),
@@ -234,50 +243,34 @@ void ModuleWrap::New(const FunctionCallbackInfo<Value>& args) {
234243 module = Module::CreateSyntheticModule (
235244 isolate, url, span, SyntheticModuleEvaluationStepsCallback);
236245 } else {
237- ScriptCompiler::CachedData* cached_data = nullptr ;
238- bool used_cache_from_user = false ;
246+ // When we are compiling for the default loader, this will be
247+ // std::nullopt, and CompileSourceTextModule() should use
248+ // on-disk cache.
249+ std::optional<v8::ScriptCompiler::CachedData*> user_cached_data;
250+ if (id_symbol !=
251+ realm->isolate_data ()->source_text_module_default_hdo ()) {
252+ user_cached_data = nullptr ;
253+ }
239254 if (args[5 ]->IsArrayBufferView ()) {
240- DCHECK (!can_use_builtin_cache); // We don't use this option internally.
241- used_cache_from_user = true ;
255+ CHECK (!can_use_builtin_cache); // We don't use this option internally.
242256 Local<ArrayBufferView> cached_data_buf = args[5 ].As <ArrayBufferView>();
243257 uint8_t * data =
244258 static_cast <uint8_t *>(cached_data_buf->Buffer ()->Data ());
245- cached_data =
259+ user_cached_data =
246260 new ScriptCompiler::CachedData (data + cached_data_buf->ByteOffset (),
247261 cached_data_buf->ByteLength ());
248262 }
249-
250263 Local<String> source_text = args[2 ].As <String>();
251- ScriptOrigin origin (isolate,
252- url,
253- line_offset,
254- column_offset,
255- true , // is cross origin
256- -1 , // script id
257- Local<Value>(), // source map URL
258- false , // is opaque (?)
259- false , // is WASM
260- true , // is ES Module
261- host_defined_options);
262-
263- CompileCacheEntry* cache_entry = nullptr ;
264- if (can_use_builtin_cache && realm->env ()->use_compile_cache ()) {
265- cache_entry = realm->env ()->compile_cache_handler ()->GetOrInsert (
266- source_text, url, CachedCodeType::kESM );
267- }
268- if (cache_entry != nullptr && cache_entry->cache != nullptr ) {
269- // source will take ownership of cached_data.
270- cached_data = cache_entry->CopyCache ();
271- }
272264
273- ScriptCompiler::Source source (source_text, origin, cached_data);
274- ScriptCompiler::CompileOptions options;
275- if (source.GetCachedData () == nullptr ) {
276- options = ScriptCompiler::kNoCompileOptions ;
277- } else {
278- options = ScriptCompiler::kConsumeCodeCache ;
279- }
280- if (!ScriptCompiler::CompileModule (isolate, &source, options)
265+ bool cache_rejected = false ;
266+ if (!CompileSourceTextModule (realm,
267+ source_text,
268+ url,
269+ line_offset,
270+ column_offset,
271+ host_defined_options,
272+ user_cached_data,
273+ &cache_rejected)
281274 .ToLocal (&module )) {
282275 if (try_catch.HasCaught () && !try_catch.HasTerminated ()) {
283276 CHECK (!try_catch.Message ().IsEmpty ());
@@ -291,18 +284,8 @@ void ModuleWrap::New(const FunctionCallbackInfo<Value>& args) {
291284 return ;
292285 }
293286
294- bool cache_rejected = false ;
295- if (options == ScriptCompiler::kConsumeCodeCache ) {
296- cache_rejected = source.GetCachedData ()->rejected ;
297- }
298-
299- if (cache_entry != nullptr ) {
300- realm->env ()->compile_cache_handler ()->MaybeSave (
301- cache_entry, module , cache_rejected);
302- }
303-
304- // If the cache comes from builtin compile cache, fail silently.
305- if (cache_rejected && used_cache_from_user) {
287+ if (user_cached_data.has_value () && user_cached_data.value () != nullptr &&
288+ cache_rejected) {
306289 THROW_ERR_VM_MODULE_CACHED_DATA_REJECTED (
307290 realm, " cachedData buffer was rejected" );
308291 try_catch.ReThrow ();
@@ -345,6 +328,71 @@ void ModuleWrap::New(const FunctionCallbackInfo<Value>& args) {
345328 args.GetReturnValue ().Set (that);
346329}
347330
331+ MaybeLocal<Module> ModuleWrap::CompileSourceTextModule (
332+ Realm* realm,
333+ Local<String> source_text,
334+ Local<String> url,
335+ int line_offset,
336+ int column_offset,
337+ Local<PrimitiveArray> host_defined_options,
338+ std::optional<ScriptCompiler::CachedData*> user_cached_data,
339+ bool * cache_rejected) {
340+ Isolate* isolate = realm->isolate ();
341+ EscapableHandleScope scope (isolate);
342+ ScriptOrigin origin (isolate,
343+ url,
344+ line_offset,
345+ column_offset,
346+ true , // is cross origin
347+ -1 , // script id
348+ Local<Value>(), // source map URL
349+ false , // is opaque (?)
350+ false , // is WASM
351+ true , // is ES Module
352+ host_defined_options);
353+ ScriptCompiler::CachedData* cached_data = nullptr ;
354+ CompileCacheEntry* cache_entry = nullptr ;
355+ // When compiling for the default loader, user_cached_data is std::nullptr.
356+ // When compiling for vm.Module, it's either nullptr or a pointer to the
357+ // cached data.
358+ if (user_cached_data.has_value ()) {
359+ cached_data = user_cached_data.value ();
360+ } else if (realm->env ()->use_compile_cache ()) {
361+ cache_entry = realm->env ()->compile_cache_handler ()->GetOrInsert (
362+ source_text, url, CachedCodeType::kESM );
363+ }
364+
365+ if (cache_entry != nullptr && cache_entry->cache != nullptr ) {
366+ // source will take ownership of cached_data.
367+ cached_data = cache_entry->CopyCache ();
368+ }
369+
370+ ScriptCompiler::Source source (source_text, origin, cached_data);
371+ ScriptCompiler::CompileOptions options;
372+ if (cached_data == nullptr ) {
373+ options = ScriptCompiler::kNoCompileOptions ;
374+ } else {
375+ options = ScriptCompiler::kConsumeCodeCache ;
376+ }
377+
378+ Local<Module> module ;
379+ if (!ScriptCompiler::CompileModule (isolate, &source, options)
380+ .ToLocal (&module )) {
381+ return scope.EscapeMaybe (MaybeLocal<Module>());
382+ }
383+
384+ if (options == ScriptCompiler::kConsumeCodeCache ) {
385+ *cache_rejected = source.GetCachedData ()->rejected ;
386+ }
387+
388+ if (cache_entry != nullptr ) {
389+ realm->env ()->compile_cache_handler ()->MaybeSave (
390+ cache_entry, module , *cache_rejected);
391+ }
392+
393+ return scope.Escape (module );
394+ }
395+
348396static Local<Object> createImportAttributesContainer (
349397 Realm* realm,
350398 Isolate* isolate,
0 commit comments