@@ -133,12 +133,23 @@ ModuleWrap::ModuleWrap(Realm* realm, |
133 | 133 | object->SetInternalField(kSyntheticEvaluationStepsSlot, |
134 | 134 | synthetic_evaluation_step); |
135 | 135 | object->SetInternalField(kContextObjectSlot, context_object); |
| 136 | + object->SetInternalField(kLinkedRequestsSlot, |
| 137 | + v8::Undefined(realm->isolate())); |
136 | 138 |
|
137 | 139 | if (!synthetic_evaluation_step->IsUndefined()) { |
138 | 140 | synthetic_ = true; |
139 | 141 | } |
140 | 142 | MakeWeak(); |
141 | 143 | module_.SetWeak(); |
| 144 | + |
| 145 | + HandleScope scope(realm->isolate()); |
| 146 | + Local<Context> context = realm->context(); |
| 147 | + Local<FixedArray> requests = module->GetModuleRequests(); |
| 148 | + for (int i = 0; i < requests->Length(); i++) { |
| 149 | + ModuleCacheKey module_cache_key = ModuleCacheKey::From( |
| 150 | + context, requests->Get(context, i).As<ModuleRequest>()); |
| 151 | + resolve_cache_[module_cache_key] = i; |
| 152 | + } |
142 | 153 | } |
143 | 154 |
|
144 | 155 | ModuleWrap::~ModuleWrap() { |
@@ -159,6 +170,30 @@ Local<Context> ModuleWrap::context() const { |
159 | 170 | return obj.As<Object>()->GetCreationContextChecked(); |
160 | 171 | } |
161 | 172 |
|
| 173 | +ModuleWrap* ModuleWrap::GetLinkedRequest(uint32_t index) { |
| 174 | + DCHECK(IsLinked()); |
| 175 | + Isolate* isolate = env()->isolate(); |
| 176 | + EscapableHandleScope scope(isolate); |
| 177 | + Local<Data> linked_requests_data = |
| 178 | + object()->GetInternalField(kLinkedRequestsSlot); |
| 179 | + DCHECK(linked_requests_data->IsValue() && |
| 180 | + linked_requests_data.As<Value>()->IsArray()); |
| 181 | + Local<Array> requests = linked_requests_data.As<Array>(); |
| 182 | + |
| 183 | + CHECK_LT(index, requests->Length()); |
| 184 | + |
| 185 | + Local<Value> module_value; |
| 186 | + if (!requests->Get(context(), index).ToLocal(&module_value)) { |
| 187 | + return nullptr; |
| 188 | + } |
| 189 | + CHECK(module_value->IsObject()); |
| 190 | + Local<Object> module_object = module_value.As<Object>(); |
| 191 | + |
| 192 | + ModuleWrap* module_wrap; |
| 193 | + ASSIGN_OR_RETURN_UNWRAP(&module_wrap, module_object, nullptr); |
| 194 | + return module_wrap; |
| 195 | +} |
| 196 | + |
162 | 197 | ModuleWrap* ModuleWrap::GetFromModule(Environment* env, |
163 | 198 | Local<Module> module) { |
164 | 199 | auto range = env->hash_to_module_map.equal_range(module->GetIdentityHash()); |
@@ -571,34 +606,28 @@ void ModuleWrap::GetModuleRequests(const FunctionCallbackInfo<Value>& args) { |
571 | 606 | void ModuleWrap::Link(const FunctionCallbackInfo<Value>& args) { |
572 | 607 | Realm* realm = Realm::GetCurrent(args); |
573 | 608 | Isolate* isolate = args.GetIsolate(); |
574 | | - Local<Context> context = realm->context(); |
575 | 609 |
|
576 | 610 | ModuleWrap* dependent; |
577 | 611 | ASSIGN_OR_RETURN_UNWRAP(&dependent, args.This()); |
578 | 612 |
|
579 | 613 | CHECK_EQ(args.Length(), 1); |
580 | 614 |
|
| 615 | + Local<Data> linked_requests = |
| 616 | + args.This()->GetInternalField(kLinkedRequestsSlot); |
| 617 | + if (linked_requests->IsValue() && |
| 618 | + !linked_requests.As<Value>()->IsUndefined()) { |
| 619 | + // If the module is already linked, we should not link it again. |
| 620 | + THROW_ERR_VM_MODULE_LINK_FAILURE(realm->env(), "module is already linked"); |
| 621 | + return; |
| 622 | + } |
| 623 | + |
581 | 624 | Local<FixedArray> requests = |
582 | 625 | dependent->module_.Get(isolate)->GetModuleRequests(); |
583 | 626 | Local<Array> modules = args[0].As<Array>(); |
584 | 627 | CHECK_EQ(modules->Length(), static_cast<uint32_t>(requests->Length())); |
585 | 628 |
|
586 | | - std::vector<Global<Value>> modules_buffer; |
587 | | - if (FromV8Array(context, modules, &modules_buffer).IsNothing()) { |
588 | | - return; |
589 | | - } |
590 | | - |
591 | | - for (uint32_t i = 0; i < modules_buffer.size(); i++) { |
592 | | - Local<Object> module_object = modules_buffer[i].Get(isolate).As<Object>(); |
593 | | - |
594 | | - CHECK( |
595 | | - realm->isolate_data()->module_wrap_constructor_template()->HasInstance( |
596 | | - module_object)); |
597 | | - |
598 | | - ModuleCacheKey module_cache_key = ModuleCacheKey::From( |
599 | | - context, requests->Get(context, i).As<ModuleRequest>()); |
600 | | - dependent->resolve_cache_[module_cache_key].Reset(isolate, module_object); |
601 | | - } |
| 629 | + args.This()->SetInternalField(kLinkedRequestsSlot, modules); |
| 630 | + dependent->linked_ = true; |
602 | 631 | } |
603 | 632 |
|
604 | 633 | void ModuleWrap::Instantiate(const FunctionCallbackInfo<Value>& args) { |
@@ -612,9 +641,6 @@ void ModuleWrap::Instantiate(const FunctionCallbackInfo<Value>& args) { |
612 | 641 | USE(module->InstantiateModule( |
613 | 642 | context, ResolveModuleCallback, ResolveSourceCallback)); |
614 | 643 |
|
615 | | - // clear resolve cache on instantiate |
616 | | - obj->resolve_cache_.clear(); |
617 | | - |
618 | 644 | if (try_catch.HasCaught() && !try_catch.HasTerminated()) { |
619 | 645 | CHECK(!try_catch.Message().IsEmpty()); |
620 | 646 | CHECK(!try_catch.Exception().IsEmpty()); |
@@ -722,9 +748,6 @@ void ModuleWrap::InstantiateSync(const FunctionCallbackInfo<Value>& args) { |
722 | 748 | USE(module->InstantiateModule( |
723 | 749 | context, ResolveModuleCallback, ResolveSourceCallback)); |
724 | 750 |
|
725 | | - // clear resolve cache on instantiate |
726 | | - obj->resolve_cache_.clear(); |
727 | | - |
728 | 751 | if (try_catch.HasCaught() && !try_catch.HasTerminated()) { |
729 | 752 | CHECK(!try_catch.Message().IsEmpty()); |
730 | 753 | CHECK(!try_catch.Exception().IsEmpty()); |
@@ -965,48 +988,51 @@ void ModuleWrap::GetError(const FunctionCallbackInfo<Value>& args) { |
965 | 988 | args.GetReturnValue().Set(module->GetException()); |
966 | 989 | } |
967 | 990 |
|
| 991 | +// static |
968 | 992 | MaybeLocal<Module> ModuleWrap::ResolveModuleCallback( |
969 | 993 | Local<Context> context, |
970 | 994 | Local<String> specifier, |
971 | 995 | Local<FixedArray> import_attributes, |
972 | 996 | Local<Module> referrer) { |
973 | | - Isolate* isolate = context->GetIsolate(); |
974 | | - Environment* env = Environment::GetCurrent(context); |
975 | | - if (env == nullptr) { |
976 | | - THROW_ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE(isolate); |
977 | | - return MaybeLocal<Module>(); |
978 | | - } |
979 | | - |
980 | | - ModuleCacheKey cache_key = |
981 | | - ModuleCacheKey::From(context, specifier, import_attributes); |
982 | | - |
983 | | - ModuleWrap* dependent = GetFromModule(env, referrer); |
984 | | - if (dependent == nullptr) { |
985 | | - THROW_ERR_VM_MODULE_LINK_FAILURE( |
986 | | - env, "request for '%s' is from invalid module", cache_key.specifier); |
987 | | - return MaybeLocal<Module>(); |
| 997 | + ModuleWrap* resolved_module; |
| 998 | + if (!ResolveModule(context, specifier, import_attributes, referrer) |
| 999 | + .To(&resolved_module)) { |
| 1000 | + return {}; |
988 | 1001 | } |
| 1002 | + DCHECK_NOT_NULL(resolved_module); |
| 1003 | + return resolved_module->module_.Get(context->GetIsolate()); |
| 1004 | +} |
989 | 1005 |
|
990 | | - if (dependent->resolve_cache_.count(cache_key) != 1) { |
991 | | - THROW_ERR_VM_MODULE_LINK_FAILURE( |
992 | | - env, "request for '%s' is not in cache", cache_key.specifier); |
993 | | - return MaybeLocal<Module>(); |
| 1006 | +// static |
| 1007 | +MaybeLocal<Object> ModuleWrap::ResolveSourceCallback( |
| 1008 | + Local<Context> context, |
| 1009 | + Local<String> specifier, |
| 1010 | + Local<FixedArray> import_attributes, |
| 1011 | + Local<Module> referrer) { |
| 1012 | + ModuleWrap* resolved_module; |
| 1013 | + if (!ResolveModule(context, specifier, import_attributes, referrer) |
| 1014 | + .To(&resolved_module)) { |
| 1015 | + return {}; |
994 | 1016 | } |
| 1017 | + DCHECK_NOT_NULL(resolved_module); |
995 | 1018 |
|
996 | | - Local<Object> module_object = |
997 | | - dependent->resolve_cache_[cache_key].Get(isolate); |
998 | | - if (module_object.IsEmpty() || !module_object->IsObject()) { |
999 | | - THROW_ERR_VM_MODULE_LINK_FAILURE( |
1000 | | - env, "request for '%s' did not return an object", cache_key.specifier); |
1001 | | - return MaybeLocal<Module>(); |
| 1019 | + Local<Value> module_source_object = |
| 1020 | + resolved_module->object() |
| 1021 | + ->GetInternalField(ModuleWrap::kModuleSourceObjectSlot) |
| 1022 | + .As<Value>(); |
| 1023 | + if (module_source_object->IsUndefined()) { |
| 1024 | + Local<String> url = resolved_module->object() |
| 1025 | + ->GetInternalField(ModuleWrap::kURLSlot) |
| 1026 | + .As<String>(); |
| 1027 | + THROW_ERR_SOURCE_PHASE_NOT_DEFINED(context->GetIsolate(), url); |
| 1028 | + return {}; |
1002 | 1029 | } |
1003 | | - |
1004 | | - ModuleWrap* module; |
1005 | | - ASSIGN_OR_RETURN_UNWRAP(&module, module_object, MaybeLocal<Module>()); |
1006 | | - return module->module_.Get(isolate); |
| 1030 | + CHECK(module_source_object->IsObject()); |
| 1031 | + return module_source_object.As<Object>(); |
1007 | 1032 | } |
1008 | 1033 |
|
1009 | | -MaybeLocal<Object> ModuleWrap::ResolveSourceCallback( |
| 1034 | +// static |
| 1035 | +Maybe<ModuleWrap*> ModuleWrap::ResolveModule( |
1010 | 1036 | Local<Context> context, |
1011 | 1037 | Local<String> specifier, |
1012 | 1038 | Local<FixedArray> import_attributes, |
@@ -1015,46 +1041,38 @@ MaybeLocal<Object> ModuleWrap::ResolveSourceCallback( |
1015 | 1041 | Environment* env = Environment::GetCurrent(context); |
1016 | 1042 | if (env == nullptr) { |
1017 | 1043 | THROW_ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE(isolate); |
1018 | | - return MaybeLocal<Object>(); |
| 1044 | + return Nothing<ModuleWrap*>(); |
1019 | 1045 | } |
| 1046 | + // Check that the referrer is not yet been instantiated. |
| 1047 | + DCHECK(referrer->GetStatus() <= Module::kInstantiated); |
1020 | 1048 |
|
1021 | 1049 | ModuleCacheKey cache_key = |
1022 | 1050 | ModuleCacheKey::From(context, specifier, import_attributes); |
1023 | 1051 |
|
1024 | | - ModuleWrap* dependent = GetFromModule(env, referrer); |
| 1052 | + ModuleWrap* dependent = ModuleWrap::GetFromModule(env, referrer); |
1025 | 1053 | if (dependent == nullptr) { |
1026 | 1054 | THROW_ERR_VM_MODULE_LINK_FAILURE( |
1027 | 1055 | env, "request for '%s' is from invalid module", cache_key.specifier); |
1028 | | - return MaybeLocal<Object>(); |
| 1056 | + return Nothing<ModuleWrap*>(); |
1029 | 1057 | } |
1030 | | - |
1031 | | - if (dependent->resolve_cache_.count(cache_key) != 1) { |
| 1058 | + if (!dependent->IsLinked()) { |
1032 | 1059 | THROW_ERR_VM_MODULE_LINK_FAILURE( |
1033 | | - env, "request for '%s' is not in cache", cache_key.specifier); |
1034 | | - return MaybeLocal<Object>(); |
| 1060 | + env, |
| 1061 | + "request for '%s' is from a module not been linked", |
| 1062 | + cache_key.specifier); |
| 1063 | + return Nothing<ModuleWrap*>(); |
1035 | 1064 | } |
1036 | 1065 |
|
1037 | | - Local<Object> module_object = |
1038 | | - dependent->resolve_cache_[cache_key].Get(isolate); |
1039 | | - if (module_object.IsEmpty() || !module_object->IsObject()) { |
| 1066 | + auto it = dependent->resolve_cache_.find(cache_key); |
| 1067 | + if (it == dependent->resolve_cache_.end()) { |
1040 | 1068 | THROW_ERR_VM_MODULE_LINK_FAILURE( |
1041 | | - env, "request for '%s' did not return an object", cache_key.specifier); |
1042 | | - return MaybeLocal<Object>(); |
| 1069 | + env, "request for '%s' is not in cache", cache_key.specifier); |
| 1070 | + return Nothing<ModuleWrap*>(); |
1043 | 1071 | } |
1044 | 1072 |
|
1045 | | - ModuleWrap* module; |
1046 | | - ASSIGN_OR_RETURN_UNWRAP(&module, module_object, MaybeLocal<Object>()); |
1047 | | - |
1048 | | - Local<Value> module_source_object = |
1049 | | - module->object()->GetInternalField(kModuleSourceObjectSlot).As<Value>(); |
1050 | | - if (module_source_object->IsUndefined()) { |
1051 | | - Local<String> url = |
1052 | | - module->object()->GetInternalField(kURLSlot).As<String>(); |
1053 | | - THROW_ERR_SOURCE_PHASE_NOT_DEFINED(isolate, url); |
1054 | | - return MaybeLocal<Object>(); |
1055 | | - } |
1056 | | - CHECK(module_source_object->IsObject()); |
1057 | | - return module_source_object.As<Object>(); |
| 1073 | + ModuleWrap* module_wrap = dependent->GetLinkedRequest(it->second); |
| 1074 | + CHECK_NOT_NULL(module_wrap); |
| 1075 | + return Just(module_wrap); |
1058 | 1076 | } |
1059 | 1077 |
|
1060 | 1078 | static MaybeLocal<Promise> ImportModuleDynamicallyWithPhase( |
|