@@ -123,12 +123,23 @@ ModuleWrap::ModuleWrap(Realm* realm, |
123 | 123 | object->SetInternalField(kSyntheticEvaluationStepsSlot, |
124 | 124 | synthetic_evaluation_step); |
125 | 125 | object->SetInternalField(kContextObjectSlot, context_object); |
| 126 | + object->SetInternalField(kLinkedRequestsSlot, |
| 127 | + v8::Undefined(realm->isolate())); |
126 | 128 |
|
127 | 129 | if (!synthetic_evaluation_step->IsUndefined()) { |
128 | 130 | synthetic_ = true; |
129 | 131 | } |
130 | 132 | MakeWeak(); |
131 | 133 | module_.SetWeak(); |
| 134 | + |
| 135 | + HandleScope scope(realm->isolate()); |
| 136 | + Local<Context> context = realm->context(); |
| 137 | + Local<FixedArray> requests = module->GetModuleRequests(); |
| 138 | + for (int i = 0; i < requests->Length(); i++) { |
| 139 | + ModuleCacheKey module_cache_key = ModuleCacheKey::From( |
| 140 | + context, requests->Get(context, i).As<ModuleRequest>()); |
| 141 | + resolve_cache_[module_cache_key] = i; |
| 142 | + } |
132 | 143 | } |
133 | 144 |
|
134 | 145 | ModuleWrap::~ModuleWrap() { |
@@ -149,6 +160,30 @@ Local<Context> ModuleWrap::context() const { |
149 | 160 | return obj.As<Object>()->GetCreationContextChecked(); |
150 | 161 | } |
151 | 162 |
|
| 163 | +ModuleWrap* ModuleWrap::GetLinkedRequest(uint32_t index) { |
| 164 | + DCHECK(IsLinked()); |
| 165 | + Isolate* isolate = env()->isolate(); |
| 166 | + EscapableHandleScope scope(isolate); |
| 167 | + Local<Data> linked_requests_data = |
| 168 | + object()->GetInternalField(kLinkedRequestsSlot); |
| 169 | + DCHECK(linked_requests_data->IsValue() && |
| 170 | + linked_requests_data.As<Value>()->IsArray()); |
| 171 | + Local<Array> requests = linked_requests_data.As<Array>(); |
| 172 | + |
| 173 | + CHECK_LT(index, requests->Length()); |
| 174 | + |
| 175 | + Local<Value> module_value; |
| 176 | + if (!requests->Get(context(), index).ToLocal(&module_value)) { |
| 177 | + return nullptr; |
| 178 | + } |
| 179 | + CHECK(module_value->IsObject()); |
| 180 | + Local<Object> module_object = module_value.As<Object>(); |
| 181 | + |
| 182 | + ModuleWrap* module_wrap; |
| 183 | + ASSIGN_OR_RETURN_UNWRAP(&module_wrap, module_object, nullptr); |
| 184 | + return module_wrap; |
| 185 | +} |
| 186 | + |
152 | 187 | ModuleWrap* ModuleWrap::GetFromModule(Environment* env, |
153 | 188 | Local<Module> module) { |
154 | 189 | auto range = env->hash_to_module_map.equal_range(module->GetIdentityHash()); |
@@ -542,34 +577,28 @@ void ModuleWrap::GetModuleRequests(const FunctionCallbackInfo<Value>& args) { |
542 | 577 | void ModuleWrap::Link(const FunctionCallbackInfo<Value>& args) { |
543 | 578 | Realm* realm = Realm::GetCurrent(args); |
544 | 579 | Isolate* isolate = args.GetIsolate(); |
545 | | - Local<Context> context = realm->context(); |
546 | 580 |
|
547 | 581 | ModuleWrap* dependent; |
548 | 582 | ASSIGN_OR_RETURN_UNWRAP(&dependent, args.This()); |
549 | 583 |
|
550 | 584 | CHECK_EQ(args.Length(), 1); |
551 | 585 |
|
| 586 | + Local<Data> linked_requests = |
| 587 | + args.This()->GetInternalField(kLinkedRequestsSlot); |
| 588 | + if (linked_requests->IsValue() && |
| 589 | + !linked_requests.As<Value>()->IsUndefined()) { |
| 590 | + // If the module is already linked, we should not link it again. |
| 591 | + THROW_ERR_VM_MODULE_LINK_FAILURE(realm->env(), "module is already linked"); |
| 592 | + return; |
| 593 | + } |
| 594 | + |
552 | 595 | Local<FixedArray> requests = |
553 | 596 | dependent->module_.Get(isolate)->GetModuleRequests(); |
554 | 597 | Local<Array> modules = args[0].As<Array>(); |
555 | 598 | CHECK_EQ(modules->Length(), static_cast<uint32_t>(requests->Length())); |
556 | 599 |
|
557 | | - std::vector<Global<Value>> modules_buffer; |
558 | | - if (FromV8Array(context, modules, &modules_buffer).IsNothing()) { |
559 | | - return; |
560 | | - } |
561 | | - |
562 | | - for (uint32_t i = 0; i < modules_buffer.size(); i++) { |
563 | | - Local<Object> module_object = modules_buffer[i].Get(isolate).As<Object>(); |
564 | | - |
565 | | - CHECK( |
566 | | - realm->isolate_data()->module_wrap_constructor_template()->HasInstance( |
567 | | - module_object)); |
568 | | - |
569 | | - ModuleCacheKey module_cache_key = ModuleCacheKey::From( |
570 | | - context, requests->Get(context, i).As<ModuleRequest>()); |
571 | | - dependent->resolve_cache_[module_cache_key].Reset(isolate, module_object); |
572 | | - } |
| 600 | + args.This()->SetInternalField(kLinkedRequestsSlot, modules); |
| 601 | + dependent->linked_ = true; |
573 | 602 | } |
574 | 603 |
|
575 | 604 | void ModuleWrap::Instantiate(const FunctionCallbackInfo<Value>& args) { |
@@ -582,9 +611,6 @@ void ModuleWrap::Instantiate(const FunctionCallbackInfo<Value>& args) { |
582 | 611 | TryCatchScope try_catch(realm->env()); |
583 | 612 | USE(module->InstantiateModule(context, ResolveModuleCallback)); |
584 | 613 |
|
585 | | - // clear resolve cache on instantiate |
586 | | - obj->resolve_cache_.clear(); |
587 | | - |
588 | 614 | if (try_catch.HasCaught() && !try_catch.HasTerminated()) { |
589 | 615 | CHECK(!try_catch.Message().IsEmpty()); |
590 | 616 | CHECK(!try_catch.Exception().IsEmpty()); |
@@ -731,9 +757,6 @@ void ModuleWrap::InstantiateSync(const FunctionCallbackInfo<Value>& args) { |
731 | 757 | TryCatchScope try_catch(env); |
732 | 758 | USE(module->InstantiateModule(context, ResolveModuleCallback)); |
733 | 759 |
|
734 | | - // clear resolve cache on instantiate |
735 | | - obj->resolve_cache_.clear(); |
736 | | - |
737 | 760 | if (try_catch.HasCaught() && !try_catch.HasTerminated()) { |
738 | 761 | CHECK(!try_catch.Message().IsEmpty()); |
739 | 762 | CHECK(!try_catch.Exception().IsEmpty()); |
@@ -940,45 +963,63 @@ void ModuleWrap::GetError(const FunctionCallbackInfo<Value>& args) { |
940 | 963 | args.GetReturnValue().Set(module->GetException()); |
941 | 964 | } |
942 | 965 |
|
| 966 | +// static |
943 | 967 | MaybeLocal<Module> ModuleWrap::ResolveModuleCallback( |
944 | 968 | Local<Context> context, |
945 | 969 | Local<String> specifier, |
946 | 970 | Local<FixedArray> import_attributes, |
947 | 971 | Local<Module> referrer) { |
| 972 | + ModuleWrap* resolved_module; |
| 973 | + if (!ResolveModule(context, specifier, import_attributes, referrer) |
| 974 | + .To(&resolved_module)) { |
| 975 | + return {}; |
| 976 | + } |
| 977 | + DCHECK_NOT_NULL(resolved_module); |
| 978 | + return resolved_module->module_.Get(context->GetIsolate()); |
| 979 | +} |
| 980 | + |
| 981 | +// static |
| 982 | +Maybe<ModuleWrap*> ModuleWrap::ResolveModule( |
| 983 | + Local<Context> context, |
| 984 | + Local<String> specifier, |
| 985 | + Local<FixedArray> import_attributes, |
| 986 | + Local<Module> referrer) { |
948 | 987 | Isolate* isolate = context->GetIsolate(); |
949 | 988 | Environment* env = Environment::GetCurrent(context); |
950 | 989 | if (env == nullptr) { |
951 | 990 | THROW_ERR_EXECUTION_ENVIRONMENT_NOT_AVAILABLE(isolate); |
952 | | - return MaybeLocal<Module>(); |
| 991 | + return Nothing<ModuleWrap*>(); |
953 | 992 | } |
| 993 | + // Check that the referrer is not yet been instantiated. |
| 994 | + DCHECK(referrer->GetStatus() <= Module::kInstantiated); |
954 | 995 |
|
955 | 996 | ModuleCacheKey cache_key = |
956 | 997 | ModuleCacheKey::From(context, specifier, import_attributes); |
957 | 998 |
|
958 | | - ModuleWrap* dependent = GetFromModule(env, referrer); |
| 999 | + ModuleWrap* dependent = ModuleWrap::GetFromModule(env, referrer); |
959 | 1000 | if (dependent == nullptr) { |
960 | 1001 | THROW_ERR_VM_MODULE_LINK_FAILURE( |
961 | 1002 | env, "request for '%s' is from invalid module", cache_key.specifier); |
962 | | - return MaybeLocal<Module>(); |
| 1003 | + return Nothing<ModuleWrap*>(); |
963 | 1004 | } |
964 | | - |
965 | | - if (dependent->resolve_cache_.count(cache_key) != 1) { |
| 1005 | + if (!dependent->IsLinked()) { |
966 | 1006 | THROW_ERR_VM_MODULE_LINK_FAILURE( |
967 | | - env, "request for '%s' is not in cache", cache_key.specifier); |
968 | | - return MaybeLocal<Module>(); |
| 1007 | + env, |
| 1008 | + "request for '%s' is from a module not been linked", |
| 1009 | + cache_key.specifier); |
| 1010 | + return Nothing<ModuleWrap*>(); |
969 | 1011 | } |
970 | 1012 |
|
971 | | - Local<Object> module_object = |
972 | | - dependent->resolve_cache_[cache_key].Get(isolate); |
973 | | - if (module_object.IsEmpty() || !module_object->IsObject()) { |
| 1013 | + auto it = dependent->resolve_cache_.find(cache_key); |
| 1014 | + if (it == dependent->resolve_cache_.end()) { |
974 | 1015 | THROW_ERR_VM_MODULE_LINK_FAILURE( |
975 | | - env, "request for '%s' did not return an object", cache_key.specifier); |
976 | | - return MaybeLocal<Module>(); |
| 1016 | + env, "request for '%s' is not in cache", cache_key.specifier); |
| 1017 | + return Nothing<ModuleWrap*>(); |
977 | 1018 | } |
978 | 1019 |
|
979 | | - ModuleWrap* module; |
980 | | - ASSIGN_OR_RETURN_UNWRAP(&module, module_object, MaybeLocal<Module>()); |
981 | | - return module->module_.Get(isolate); |
| 1020 | + ModuleWrap* module_wrap = dependent->GetLinkedRequest(it->second); |
| 1021 | + CHECK_NOT_NULL(module_wrap); |
| 1022 | + return Just(module_wrap); |
982 | 1023 | } |
983 | 1024 |
|
984 | 1025 | static MaybeLocal<Promise> ImportModuleDynamically( |
|