Engine.Modules.cs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. using Esprima;
  2. using Jint.Native;
  3. using Jint.Native.Object;
  4. using Jint.Native.Promise;
  5. using Jint.Runtime;
  6. using Jint.Runtime.Interpreter;
  7. using Jint.Runtime.Modules;
  8. namespace Jint
  9. {
  10. public partial class Engine
  11. {
  12. internal IModuleLoader ModuleLoader { get; set; } = null!;
  13. private readonly Dictionary<string, ModuleRecord> _modules = new(StringComparer.Ordinal);
  14. private readonly Dictionary<string, ModuleBuilder> _builders = new(StringComparer.Ordinal);
  15. /// <summary>
  16. /// https://tc39.es/ecma262/#sec-getactivescriptormodule
  17. /// </summary>
  18. internal IScriptOrModule? GetActiveScriptOrModule()
  19. {
  20. return _executionContexts?.GetActiveScriptOrModule();
  21. }
  22. internal ModuleRecord LoadModule(string? referencingModuleLocation, ModuleRequest request)
  23. {
  24. var specifier = request.Specifier;
  25. var moduleResolution = ModuleLoader.Resolve(referencingModuleLocation, request);
  26. if (_modules.TryGetValue(moduleResolution.Key, out var module))
  27. {
  28. return module;
  29. }
  30. if (_builders.TryGetValue(specifier, out var moduleBuilder))
  31. {
  32. module = LoadFromBuilder(specifier, moduleBuilder, moduleResolution);
  33. }
  34. else
  35. {
  36. module = LoadFromModuleLoader(moduleResolution);
  37. }
  38. if (module is SourceTextModuleRecord sourceTextModule)
  39. {
  40. DebugHandler.OnBeforeEvaluate(sourceTextModule._source);
  41. }
  42. return module;
  43. }
  44. private BuilderModuleRecord LoadFromBuilder(string specifier, ModuleBuilder moduleBuilder, ResolvedSpecifier moduleResolution)
  45. {
  46. var parsedModule = moduleBuilder.Parse();
  47. var module = new BuilderModuleRecord(this, Realm, parsedModule, null, false);
  48. _modules[moduleResolution.Key] = module;
  49. moduleBuilder.BindExportedValues(module);
  50. _builders.Remove(specifier);
  51. return module;
  52. }
  53. private ModuleRecord LoadFromModuleLoader(ResolvedSpecifier moduleResolution)
  54. {
  55. var module = ModuleLoader.LoadModule(this, moduleResolution);
  56. _modules[moduleResolution.Key] = module;
  57. return module;
  58. }
  59. public void AddModule(string specifier, string code)
  60. {
  61. var moduleBuilder = new ModuleBuilder(this, specifier);
  62. moduleBuilder.AddSource(code);
  63. AddModule(specifier, moduleBuilder);
  64. }
  65. public void AddModule(string specifier, Action<ModuleBuilder> buildModule)
  66. {
  67. var moduleBuilder = new ModuleBuilder(this, specifier);
  68. buildModule(moduleBuilder);
  69. AddModule(specifier, moduleBuilder);
  70. }
  71. public void AddModule(string specifier, ModuleBuilder moduleBuilder)
  72. {
  73. _builders.Add(specifier, moduleBuilder);
  74. }
  75. public ObjectInstance ImportModule(string specifier)
  76. {
  77. return ImportModule(specifier, referencingModuleLocation: null);
  78. }
  79. internal ObjectInstance ImportModule(string specifier, string? referencingModuleLocation)
  80. {
  81. return ImportModule(new ModuleRequest(specifier, []), referencingModuleLocation);
  82. }
  83. internal ObjectInstance ImportModule(ModuleRequest request, string? referencingModuleLocation)
  84. {
  85. var moduleResolution = ModuleLoader.Resolve(referencingModuleLocation, request);
  86. if (!_modules.TryGetValue(moduleResolution.Key, out var module))
  87. {
  88. module = LoadModule(referencingModuleLocation: null, request);
  89. }
  90. if (module is not CyclicModuleRecord cyclicModule)
  91. {
  92. LinkModule(request.Specifier, module);
  93. EvaluateModule(request.Specifier, module);
  94. }
  95. else if (cyclicModule.Status == ModuleStatus.Unlinked)
  96. {
  97. LinkModule(request.Specifier, cyclicModule);
  98. if (cyclicModule.Status == ModuleStatus.Linked)
  99. {
  100. ExecuteWithConstraints(true, () => EvaluateModule(request.Specifier, cyclicModule));
  101. }
  102. if (cyclicModule.Status != ModuleStatus.Evaluated)
  103. {
  104. ExceptionHelper.ThrowNotSupportedException($"Error while evaluating module: Module is in an invalid state: '{cyclicModule.Status}'");
  105. }
  106. }
  107. RunAvailableContinuations();
  108. return ModuleRecord.GetModuleNamespace(module);
  109. }
  110. private static void LinkModule(string specifier, ModuleRecord module)
  111. {
  112. module.Link();
  113. }
  114. private JsValue EvaluateModule(string specifier, ModuleRecord module)
  115. {
  116. var ownsContext = _activeEvaluationContext is null;
  117. _activeEvaluationContext ??= new EvaluationContext(this);
  118. JsValue evaluationResult;
  119. try
  120. {
  121. evaluationResult = module.Evaluate();
  122. }
  123. finally
  124. {
  125. if (ownsContext)
  126. {
  127. _activeEvaluationContext = null!;
  128. }
  129. }
  130. // This should instead be returned and resolved in ImportModule(specifier) only so Host.ImportModuleDynamically can use this promise
  131. if (evaluationResult is not JsPromise promise)
  132. {
  133. ExceptionHelper.ThrowInvalidOperationException($"Error while evaluating module: Module evaluation did not return a promise: {evaluationResult.Type}");
  134. }
  135. else if (promise.State == PromiseState.Rejected)
  136. {
  137. var location = module is CyclicModuleRecord cyclicModuleRecord
  138. ? cyclicModuleRecord.AbnormalCompletionLocation
  139. : Location.From(new Position(), new Position());
  140. var node = EsprimaExtensions.CreateLocationNode(location);
  141. ExceptionHelper.ThrowJavaScriptException(this, promise.Value, node.Location);
  142. }
  143. else if (promise.State != PromiseState.Fulfilled)
  144. {
  145. ExceptionHelper.ThrowInvalidOperationException($"Error while evaluating module: Module evaluation did not return a fulfilled promise: {promise.State}");
  146. }
  147. return evaluationResult;
  148. }
  149. }
  150. }