| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 1bbcdf9 commit 6f3b16d
3 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -165,15 +165,6 @@ ModuleWrap::ModuleWrap(Realm* realm, | |||
| 165 | 165 | } | |
| 166 | 166 | MakeWeak(); | |
| 167 | 167 | module_.SetWeak(); | |
| 168 | - | ||
| 169 | - HandleScope scope(realm->isolate()); | ||
| 170 | - Local<Context> context = realm->context(); | ||
| 171 | - Local<FixedArray> requests = module->GetModuleRequests(); | ||
| 172 | - for (int i = 0; i < requests->Length(); i++) { | ||
| 173 | - ModuleCacheKey module_cache_key = ModuleCacheKey::From( | ||
| 174 | - context, requests->Get(context, i).As<ModuleRequest>()); | ||
| 175 | - resolve_cache_[module_cache_key] = i; | ||
| 176 | - } | ||
| 177 | 168 | } | |
| 178 | 169 | ||
| 179 | 170 | ModuleWrap::~ModuleWrap() { | |
@@ -194,30 +185,6 @@ Local<Context> ModuleWrap::context() const { | |||
| 194 | 185 | return obj.As<Object>()->GetCreationContextChecked(); | |
| 195 | 186 | } | |
| 196 | 187 | ||
| 197 | - ModuleWrap* ModuleWrap::GetLinkedRequest(uint32_t index) { | ||
| 198 | - DCHECK(IsLinked()); | ||
| 199 | - Isolate* isolate = env()->isolate(); | ||
| 200 | - EscapableHandleScope scope(isolate); | ||
| 201 | - Local<Data> linked_requests_data = | ||
| 202 | - object()->GetInternalField(kLinkedRequestsSlot); | ||
| 203 | - DCHECK(linked_requests_data->IsValue() && | ||
| 204 | - linked_requests_data.As<Value>()->IsArray()); | ||
| 205 | - Local<Array> requests = linked_requests_data.As<Array>(); | ||
| 206 | - | ||
| 207 | - CHECK_LT(index, requests->Length()); | ||
| 208 | - | ||
| 209 | - Local<Value> module_value; | ||
| 210 | - if (!requests->Get(context(), index).ToLocal(&module_value)) { | ||
| 211 | - return nullptr; | ||
| 212 | - } | ||
| 213 | - CHECK(module_value->IsObject()); | ||
| 214 | - Local<Object> module_object = module_value.As<Object>(); | ||
| 215 | - | ||
| 216 | - ModuleWrap* module_wrap; | ||
| 217 | - ASSIGN_OR_RETURN_UNWRAP(&module_wrap, module_object, nullptr); | ||
| 218 | - return module_wrap; | ||
| 219 | - } | ||
| 220 | - | ||
| 221 | 188 | ModuleWrap* ModuleWrap::GetFromModule(Environment* env, | |
| 222 | 189 | Local<Module> module) { | |
| 223 | 190 | auto range = env->hash_to_module_map.equal_range(module->GetIdentityHash()); | |
@@ -653,6 +620,7 @@ void ModuleWrap::GetModuleRequests(const FunctionCallbackInfo<Value>& args) { | |||
| 653 | 620 | // moduleWrap.link(moduleWraps) | |
| 654 | 621 | void ModuleWrap::Link(const FunctionCallbackInfo<Value>& args) { | |
| 655 | 622 | Isolate* isolate = args.GetIsolate(); | |
| 623 | + HandleScope handle_scope(isolate); | ||
| 656 | 624 | Realm* realm = Realm::GetCurrent(args); | |
| 657 | 625 | Local<Context> context = realm->context(); | |
| 658 | 626 | ||
@@ -664,33 +632,70 @@ void ModuleWrap::Link(const FunctionCallbackInfo<Value>& args) { | |||
| 664 | 632 | Local<FixedArray> requests = | |
| 665 | 633 | dependent->module_.Get(isolate)->GetModuleRequests(); | |
| 666 | 634 | Local<Array> modules = args[0].As<Array>(); | |
| 667 | - CHECK_EQ(modules->Length(), static_cast<uint32_t>(requests->Length())); | ||
| 668 | - | ||
| 669 | - for (int i = 0; i < requests->Length(); i++) { | ||
| 635 | + std::vector<Global<Value>> modules_vector; | ||
| 636 | + if (FromV8Array(context, modules, &modules_vector).IsEmpty()) { | ||
| 637 | + return; | ||
| 638 | + } | ||
| 639 | + size_t request_count = static_cast<size_t>(requests->Length()); | ||
| 640 | + CHECK_EQ(modules_vector.size(), request_count); | ||
| 641 | + std::vector<ModuleWrap*> linked_module_wraps(request_count); | ||
| 642 | + | ||
| 643 | + // Track the duplicated module requests. For example if a modulelooks like | ||
| 644 | + // this: | ||
| 645 | + // | ||
| 646 | + // import { foo } from 'mod' with { type: 'json' }; | ||
| 647 | + // import source ModSource from 'mod' with { type: 'json' }; | ||
| 648 | + // import { baz } from 'mod2'; | ||
| 649 | + // | ||
| 650 | + // The first two module requests are identical. The map would look like | ||
| 651 | + // { mod_key: 0, mod2_key: 2 } in this case, so that module request 0 and | ||
| 652 | + // module request 1 would be mapped to mod_key and both should resolve to the | ||
| 653 | + // module identified by module request 0 (the first one with this identity), | ||
| 654 | + // and module request 2 should resolve the module identified by index 2. | ||
| 655 | + std::unordered_map<ModuleCacheKey, size_t, ModuleCacheKey::Hash> | ||
| 656 | + module_request_map; | ||
| 657 | + | ||
| 658 | + for (size_t i = 0; i < request_count; i++) { | ||
| 659 | + // TODO(joyeecheung): merge this with the serializeKey() in module_map.js. | ||
| 660 | + // This currently doesn't sort the import attributes. | ||
| 661 | + Local<Value> module_value = modules_vector[i].Get(isolate); | ||
| 670 | 662 | ModuleCacheKey module_cache_key = ModuleCacheKey::From( | |
| 671 | 663 | context, requests->Get(context, i).As<ModuleRequest>()); | |
| 672 | - DCHECK(dependent->resolve_cache_.contains(module_cache_key)); | ||
| 673 | - | ||
| 674 | - Local<Value> module_i; | ||
| 675 | - Local<Value> module_cache_i; | ||
| 676 | - uint32_t coalesced_index = dependent->resolve_cache_[module_cache_key]; | ||
| 677 | - if (!modules->Get(context, i).ToLocal(&module_i) || | ||
| 678 | - !modules->Get(context, coalesced_index).ToLocal(&module_cache_i) || | ||
| 679 | - !module_i->StrictEquals(module_cache_i)) { | ||
| 680 | - // If the module is different from the one of the same request, throw an | ||
| 681 | - // error. | ||
| 682 | - THROW_ERR_MODULE_LINK_MISMATCH( | ||
| 683 | - realm->env(), | ||
| 684 | - "Module request '%s' at index %d must be linked " | ||
| 685 | - "to the same module requested at index %d", | ||
| 686 | - module_cache_key.ToString(), | ||
| 687 | - i, | ||
| 688 | - coalesced_index); | ||
| 689 | - return; | ||
| 664 | + auto it = module_request_map.find(module_cache_key); | ||
| 665 | + if (it == module_request_map.end()) { | ||
| 666 | + // This is the first request with this identity, record it - any mismatch | ||
| 667 | + // for this would only be found in subsequent requests, so no need to | ||
| 668 | + // check here. | ||
| 669 | + module_request_map[module_cache_key] = i; | ||
| 670 | + } else { // This identity has been seen before, check for mismatch. | ||
| 671 | + size_t first_seen_index = it->second; | ||
| 672 | + // Check that the module is the same as the one resolved by the first | ||
| 673 | + // request with this identity. | ||
| 674 | + Local<Value> first_seen_value = | ||
| 675 | + modules_vector[first_seen_index].Get(isolate); | ||
| 676 | + if (!module_value->StrictEquals(first_seen_value)) { | ||
| 677 | + // If the module is different from the one of the same request, throw an | ||
| 678 | + // error. | ||
| 679 | + THROW_ERR_MODULE_LINK_MISMATCH( | ||
| 680 | + realm->env(), | ||
| 681 | + "Module request '%s' at index %d must be linked " | ||
| 682 | + "to the same module requested at index %d", | ||
| 683 | + module_cache_key.ToString(), | ||
| 684 | + i, | ||
| 685 | + first_seen_index); | ||
| 686 | + return; | ||
| 687 | + } | ||
| 690 | 688 | } | |
| 689 | + | ||
| 690 | + CHECK(module_value->IsObject()); // Guaranteed by link methods in JS land. | ||
| 691 | + ModuleWrap* resolved = | ||
| 692 | + BaseObject::Unwrap<ModuleWrap>(module_value.As<Object>()); | ||
| 693 | + CHECK_NOT_NULL(resolved); // Guaranteed by link methods in JS land. | ||
| 694 | + linked_module_wraps[i] = resolved; | ||
| 691 | 695 | } | |
| 692 | 696 | ||
| 693 | 697 | args.This()->SetInternalField(kLinkedRequestsSlot, modules); | |
| 698 | + std::swap(dependent->linked_module_wraps_, linked_module_wraps); | ||
| 694 | 699 | dependent->linked_ = true; | |
| 695 | 700 | } | |
| 696 | 701 | ||
@@ -1012,11 +1017,10 @@ void ModuleWrap::HasAsyncGraph(Local<Name> property, | |||
| 1012 | 1017 | // static | |
| 1013 | 1018 | MaybeLocal<Module> ModuleWrap::ResolveModuleCallback( | |
| 1014 | 1019 | Local<Context> context, | |
| 1015 | - Local<String> specifier, | ||
| 1016 | - Local<FixedArray> import_attributes, | ||
| 1020 | + size_t module_request_index, | ||
| 1017 | 1021 | Local<Module> referrer) { | |
| 1018 | 1022 | ModuleWrap* resolved_module; | |
| 1019 | - if (!ResolveModule(context, specifier, import_attributes, referrer) | ||
| 1023 | + if (!ResolveModule(context, module_request_index, referrer) | ||
| 1020 | 1024 | .To(&resolved_module)) { | |
| 1021 | 1025 | return {}; | |
| 1022 | 1026 | } | |
@@ -1027,11 +1031,10 @@ MaybeLocal<Module> ModuleWrap::ResolveModuleCallback( | |||
| 1027 | 1031 | // static | |
| 1028 | 1032 | MaybeLocal<Object> ModuleWrap::ResolveSourceCallback( | |
| 1029 | 1033 | Local<Context> context, | |
| 1030 | - Local<String> specifier, | ||
| 1031 | - Local<FixedArray> import_attributes, | ||
| 1034 | + size_t module_request_index, | ||
| 1032 | 1035 | Local<Module> referrer) { | |
| 1033 | 1036 | ModuleWrap* resolved_module; | |
| 1034 | - if (!ResolveModule(context, specifier, import_attributes, referrer) | ||
| 1037 | + if (!ResolveModule(context, module_request_index, referrer) | ||
| 1035 | 1038 | .To(&resolved_module)) { | |
| 1036 | 1039 | return {}; | |
| 1037 | 1040 | } | |
@@ -1050,12 +1053,22 @@ MaybeLocal<Object> ModuleWrap::ResolveSourceCallback( | |||
| 1050 | 1053 | return module_source_object.As<Object>(); | |
| 1051 | 1054 | } | |
| 1052 | 1055 | ||
| 1056 | + static std::string GetSpecifierFromModuleRequest(Local<Context> context, | ||
| 1057 | + Local<Module> referrer, | ||
| 1058 | + size_t module_request_index) { | ||
| 1059 | + Local<ModuleRequest> raw_request = | ||
| 1060 | + referrer->GetModuleRequests() | ||
| 1061 | + ->Get(context, static_cast<int>(module_request_index)) | ||
| 1062 | + .As<ModuleRequest>(); | ||
| 1063 | + Local<String> specifier = raw_request->GetSpecifier(); | ||
| 1064 | + Utf8Value specifier_utf8(Isolate::GetCurrent(), specifier); | ||
| 1065 | + return specifier_utf8.ToString(); | ||
| 1066 | + } | ||
| 1067 | + | ||
| 1053 | 1068 | // static | |
| 1054 | - Maybe<ModuleWrap*> ModuleWrap::ResolveModule( | ||
| 1055 | - Local<Context> context, | ||
| 1056 | - Local<String> specifier, | ||
| 1057 | - Local<FixedArray> import_attributes, | ||
| 1058 | - Local<Module> referrer) { | ||
| 1069 | + Maybe<ModuleWrap*> ModuleWrap::ResolveModule(Local<Context> context, | ||
| 1070 | + size_t module_request_index, | ||
| 1071 | + Local<Module> referrer) { | ||
| 1059 | 1072 | Isolate* isolate = Isolate::GetCurrent(); | |
| 1060 | 1073 | Environment* env = Environment::GetCurrent(context); | |
| 1061 | 1074 | if (env == nullptr) { | |
@@ -1065,37 +1078,34 @@ Maybe<ModuleWrap*> ModuleWrap::ResolveModule( | |||
| 1065 | 1078 | // Check that the referrer is not yet been instantiated. | |
| 1066 | 1079 | DCHECK(referrer->GetStatus() <= Module::kInstantiated); | |
| 1067 | 1080 | ||
| 1068 | - ModuleCacheKey cache_key = | ||
| 1069 | - ModuleCacheKey::From(context, specifier, import_attributes); | ||
| 1070 | - | ||
| 1071 | 1081 | ModuleWrap* dependent = ModuleWrap::GetFromModule(env, referrer); | |
| 1072 | 1082 | if (dependent == nullptr) { | |
| 1083 | + std::string specifier = | ||
| 1084 | + GetSpecifierFromModuleRequest(context, referrer, module_request_index); | ||
| 1073 | 1085 | THROW_ERR_VM_MODULE_LINK_FAILURE( | |
| 1074 | - env, "request for '%s' is from invalid module", cache_key.specifier); | ||
| 1086 | + env, "request for '%s' is from invalid module", specifier); | ||
| 1075 | 1087 | return Nothing<ModuleWrap*>(); | |
| 1076 | 1088 | } | |
| 1077 | 1089 | if (!dependent->IsLinked()) { | |
| 1090 | + std::string specifier = | ||
| 1091 | + GetSpecifierFromModuleRequest(context, referrer, module_request_index); | ||
| 1078 | 1092 | THROW_ERR_VM_MODULE_LINK_FAILURE(env, | |
| 1079 | 1093 | "request for '%s' can not be resolved on " | |
| 1080 | 1094 | "module '%s' that is not linked", | |
| 1081 | - cache_key.specifier, | ||
| 1095 | + specifier, | ||
| 1082 | 1096 | dependent->url_); | |
| 1083 | 1097 | return Nothing<ModuleWrap*>(); | |
| 1084 | 1098 | } | |
| 1085 | 1099 | ||
| 1086 | - auto it = dependent->resolve_cache_.find(cache_key); | ||
| 1087 | - if (it == dependent->resolve_cache_.end()) { | ||
| 1088 | - THROW_ERR_VM_MODULE_LINK_FAILURE( | ||
| 1089 | - env, | ||
| 1090 | - "request for '%s' is not cached on module '%s'", | ||
| 1091 | - cache_key.specifier, | ||
| 1092 | - dependent->url_); | ||
| 1093 | - return Nothing<ModuleWrap*>(); | ||
| 1100 | + size_t linked_module_count = dependent->linked_module_wraps_.size(); | ||
| 1101 | + if (linked_module_count > 0) { | ||
| 1102 | + CHECK_LT(module_request_index, linked_module_count); | ||
| 1103 | + } else { | ||
| 1104 | + UNREACHABLE("Module resolution callback invoked for a module" | ||
| 1105 | + " without linked requests"); | ||
| 1094 | 1106 | } | |
| 1095 | 1107 | ||
| 1096 | - ModuleWrap* module_wrap = dependent->GetLinkedRequest(it->second); | ||
| 1097 | - CHECK_NOT_NULL(module_wrap); | ||
| 1098 | - return Just(module_wrap); | ||
| 1108 | + return Just(dependent->linked_module_wraps_[module_request_index]); | ||
| 1099 | 1109 | } | |
| 1100 | 1110 | ||
| 1101 | 1111 | static MaybeLocal<Promise> ImportModuleDynamicallyWithPhase( | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -93,16 +93,14 @@ struct ModuleCacheKey : public MemoryRetainer { | |||
| 93 | 93 | }; | |
| 94 | 94 | ||
| 95 | 95 | class ModuleWrap : public BaseObject { | |
| 96 | - using ResolveCache = | ||
| 97 | - std::unordered_map<ModuleCacheKey, uint32_t, ModuleCacheKey::Hash>; | ||
| 98 | - | ||
| 99 | 96 | public: | |
| 100 | 97 | enum InternalFields { | |
| 101 | 98 | kModuleSlot = BaseObject::kInternalFieldCount, | |
| 102 | 99 | kModuleSourceObjectSlot, | |
| 103 | 100 | kSyntheticEvaluationStepsSlot, | |
| 104 | 101 | kContextObjectSlot, // Object whose creation context is the target Context | |
| 105 | - kLinkedRequestsSlot, // Array of linked requests | ||
| 102 | + kLinkedRequestsSlot, // Array of linked requests, each is a ModuleWrap JS | ||
| 103 | + // wrapper object. | ||
| 106 | 104 | kInternalFieldCount | |
| 107 | 105 | }; | |
| 108 | 106 | ||
@@ -134,8 +132,6 @@ class ModuleWrap : public BaseObject { | |||
| 134 | 132 | ||
| 135 | 133 | bool IsLinked() const { return linked_; } | |
| 136 | 134 | ||
| 137 | - ModuleWrap* GetLinkedRequest(uint32_t index); | ||
| 138 | - | ||
| 139 | 135 | static v8::Local<v8::PrimitiveArray> GetHostDefinedOptions( | |
| 140 | 136 | v8::Isolate* isolate, v8::Local<v8::Symbol> symbol); | |
| 141 | 137 | ||
@@ -196,34 +192,34 @@ class ModuleWrap : public BaseObject { | |||
| 196 | 192 | ||
| 197 | 193 | static v8::MaybeLocal<v8::Module> ResolveModuleCallback( | |
| 198 | 194 | v8::Local<v8::Context> context, | |
| 199 | - v8::Local<v8::String> specifier, | ||
| 200 | - v8::Local<v8::FixedArray> import_attributes, | ||
| 195 | + size_t module_request_index, | ||
| 201 | 196 | v8::Local<v8::Module> referrer); | |
| 202 | 197 | static v8::MaybeLocal<v8::Object> ResolveSourceCallback( | |
| 203 | 198 | v8::Local<v8::Context> context, | |
| 204 | - v8::Local<v8::String> specifier, | ||
| 205 | - v8::Local<v8::FixedArray> import_attributes, | ||
| 199 | + size_t module_request_index, | ||
| 206 | 200 | v8::Local<v8::Module> referrer); | |
| 207 | 201 | static ModuleWrap* GetFromModule(node::Environment*, v8::Local<v8::Module>); | |
| 208 | 202 | ||
| 209 | 203 | // This method may throw a JavaScript exception, so the return type is | |
| 210 | 204 | // wrapped in a Maybe. | |
| 211 | - static v8::Maybe<ModuleWrap*> ResolveModule( | ||
| 212 | - v8::Local<v8::Context> context, | ||
| 213 | - v8::Local<v8::String> specifier, | ||
| 214 | - v8::Local<v8::FixedArray> import_attributes, | ||
| 215 | - v8::Local<v8::Module> referrer); | ||
| 205 | + static v8::Maybe<ModuleWrap*> ResolveModule(v8::Local<v8::Context> context, | ||
| 206 | + size_t module_request_index, | ||
| 207 | + v8::Local<v8::Module> referrer); | ||
| 216 | 208 | ||
| 217 | 209 | std::string url_; | |
| 218 | 210 | v8::Global<v8::Module> module_; | |
| 219 | - ResolveCache resolve_cache_; | ||
| 220 | 211 | contextify::ContextifyContext* contextify_context_ = nullptr; | |
| 221 | 212 | bool synthetic_ = false; | |
| 222 | 213 | bool linked_ = false; | |
| 223 | 214 | // This depends on the module to be instantiated so it begins with a | |
| 224 | 215 | // nullopt value. | |
| 225 | 216 | std::optional<bool> has_async_graph_ = std::nullopt; | |
| 226 | 217 | int module_hash_; | |
| 218 | + // Corresponds to the ModuleWrap* of the wrappers in kLinkedRequestsSlot. | ||
| 219 | + // These are populated during Link(), and are only valid after that as | ||
| 220 | + // convenient shortcuts, but do not hold the ModuleWraps alive. The actual | ||
| 221 | + // strong references come from the array in kLinkedRequestsSlot. | ||
| 222 | + std::vector<ModuleWrap*> linked_module_wraps_; | ||
| 227 | 223 | }; | |
| 228 | 224 | ||
| 229 | 225 | } // namespace loader | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -91,7 +91,7 @@ function testLinkMismatch() { | |||
| 91 | 91 | }, { | |
| 92 | 92 | code: 'ERR_MODULE_LINK_MISMATCH', | |
| 93 | 93 | // Test that ModuleCacheKey::ToString() is used in the error message. | |
| 94 | - message: `Module request 'ModuleCacheKey("bar")' at index 0 must be linked to the same module requested at index 1` | ||
| 94 | + message: `Module request 'ModuleCacheKey("bar")' at index 1 must be linked to the same module requested at index 0` | ||
| 95 | 95 | }); | |
| 96 | 96 | } | |
| 97 | 97 | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments