Engine.Modules.cs 6.7 KB

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