Host.cs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. using Jint.Native;
  2. using Jint.Native.Global;
  3. using Jint.Native.Object;
  4. using Jint.Native.Promise;
  5. using Jint.Runtime.Descriptors;
  6. using Jint.Runtime.Environments;
  7. using Jint.Runtime.Interop;
  8. using Jint.Runtime.Modules;
  9. using Module = Jint.Runtime.Modules.Module;
  10. namespace Jint.Runtime;
  11. public class Host
  12. {
  13. private Engine? _engine;
  14. private readonly List<string> _supportedImportAttributes = ["type"];
  15. protected Engine Engine
  16. {
  17. get
  18. {
  19. if (_engine is null)
  20. {
  21. Throw.InvalidOperationException("Initialize has not been called");
  22. }
  23. return _engine!;
  24. }
  25. private set => _engine = value;
  26. }
  27. /// <summary>
  28. /// Initializes the host.
  29. /// </summary>
  30. public void Initialize(Engine engine)
  31. {
  32. Engine = engine;
  33. InitializeHostDefinedRealm();
  34. PostInitialize();
  35. }
  36. protected virtual void PostInitialize()
  37. {
  38. }
  39. /// <summary>
  40. /// https://tc39.es/ecma262/#sec-initializehostdefinedrealm
  41. /// </summary>
  42. protected virtual void InitializeHostDefinedRealm()
  43. {
  44. var realm = CreateRealm();
  45. var newContext = new ExecutionContext(
  46. scriptOrModule: null,
  47. lexicalEnvironment: realm.GlobalEnv,
  48. variableEnvironment: realm.GlobalEnv,
  49. privateEnvironment: null,
  50. realm: realm,
  51. function: null);
  52. Engine.EnterExecutionContext(newContext);
  53. }
  54. internal virtual GlobalEnvironment CreateGlobalEnvironment(ObjectInstance globalObject)
  55. {
  56. return JintEnvironment.NewGlobalEnvironment(Engine, globalObject, globalObject);
  57. }
  58. protected virtual ObjectInstance CreateGlobalObject(Realm realm)
  59. {
  60. var globalObject = new GlobalObject(Engine, realm);
  61. // Because the properties might need some of the built-in object
  62. // their configuration is delayed to a later step
  63. // trigger initialization
  64. globalObject.EnsureInitialized();
  65. return globalObject;
  66. }
  67. /// <summary>
  68. /// https://tc39.es/ecma262/#sec-createrealm
  69. /// </summary>
  70. protected internal virtual Realm CreateRealm()
  71. {
  72. var realmRec = new Realm();
  73. Engine._realmInConstruction = realmRec;
  74. CreateIntrinsics(realmRec);
  75. var globalObject = CreateGlobalObject(realmRec);
  76. var globalEnv = CreateGlobalEnvironment(globalObject);
  77. realmRec.GlobalEnv = globalEnv;
  78. realmRec.GlobalObject = globalObject;
  79. Engine._realmInConstruction = null!;
  80. return realmRec;
  81. }
  82. /// <summary>
  83. /// https://tc39.es/ecma262/#sec-createintrinsics
  84. /// </summary>
  85. protected virtual void CreateIntrinsics(Realm realmRec)
  86. {
  87. var intrinsics = new Intrinsics(Engine, realmRec);
  88. realmRec.Intrinsics = intrinsics;
  89. }
  90. /// <summary>
  91. /// https://tc39.es/ecma262/#sec-hostensurecancompilestrings
  92. /// </summary>
  93. public virtual void EnsureCanCompileStrings(Realm callerRealm, Realm evalRealm)
  94. {
  95. if (!Engine.Options.Host.StringCompilationAllowed)
  96. {
  97. Throw.JavaScriptException(callerRealm.Intrinsics.TypeError, "String compilation has been disabled in engine options");
  98. }
  99. }
  100. /// <summary>
  101. /// https://tc39.es/ecma262/#sec-GetImportedModule
  102. /// </summary>
  103. internal virtual Module GetImportedModule(IScriptOrModule? referrer, ModuleRequest request)
  104. {
  105. return Engine.Modules.Load(referrer?.Location, request);
  106. }
  107. /// <summary>
  108. /// https://tc39.es/ecma262/#sec-HostLoadImportedModule
  109. /// </summary>
  110. internal virtual void LoadImportedModule(IScriptOrModule? referrer, ModuleRequest moduleRequest, PromiseCapability payload)
  111. {
  112. var promise = Engine.RegisterPromise();
  113. try
  114. {
  115. // This should instead return the PromiseInstance returned by ModuleRecord.Evaluate (currently done in Engine.EvaluateModule), but until we have await this will do.
  116. Engine.Modules.Import(moduleRequest, referrer?.Location);
  117. promise.Resolve(JsValue.Undefined);
  118. }
  119. catch (JavaScriptException ex)
  120. {
  121. promise.Reject(ex.Error);
  122. }
  123. FinishLoadingImportedModule(referrer, moduleRequest, payload, (JsPromise) promise.Promise);
  124. }
  125. /// <summary>
  126. /// https://tc39.es/ecma262/#sec-FinishLoadingImportedModule
  127. /// </summary>
  128. internal virtual void FinishLoadingImportedModule(IScriptOrModule? referrer, ModuleRequest moduleRequest, PromiseCapability payload, JsPromise result)
  129. {
  130. var onFulfilled = new ClrFunction(Engine, "", (thisObj, args) =>
  131. {
  132. var moduleRecord = GetImportedModule(referrer, moduleRequest);
  133. try
  134. {
  135. var ns = Module.GetModuleNamespace(moduleRecord);
  136. payload.Resolve.Call(JsValue.Undefined, ns);
  137. }
  138. catch (JavaScriptException ex)
  139. {
  140. payload.Reject.Call(JsValue.Undefined, ex.Error);
  141. }
  142. return JsValue.Undefined;
  143. }, 0, PropertyFlag.Configurable);
  144. var onRejected = new ClrFunction(Engine, "", (thisObj, args) =>
  145. {
  146. var error = args.At(0);
  147. payload.Reject.Call(JsValue.Undefined, error);
  148. return JsValue.Undefined;
  149. }, 0, PropertyFlag.Configurable);
  150. PromiseOperations.PerformPromiseThen(Engine, result, onFulfilled, onRejected, payload);
  151. }
  152. /// <summary>
  153. /// https://tc39.es/ecma262/#sec-hostgetimportmetaproperties
  154. /// </summary>
  155. public virtual List<KeyValuePair<JsValue, JsValue>> GetImportMetaProperties(Module moduleRecord)
  156. {
  157. return new List<KeyValuePair<JsValue, JsValue>>();
  158. }
  159. /// <summary>
  160. /// https://tc39.es/ecma262/#sec-hostfinalizeimportmeta
  161. /// </summary>
  162. public virtual void FinalizeImportMeta(ObjectInstance importMeta, Module moduleRecord)
  163. {
  164. }
  165. /// <summary>
  166. /// https://tc39.es/proposal-shadowrealm/#sec-host-initialize-shadow-shadowrealm
  167. /// </summary>
  168. public virtual void InitializeShadowRealm(Realm realm)
  169. {
  170. }
  171. /// <summary>
  172. /// https://tc39.es/ecma262/#sec-hostmakejobcallback
  173. /// </summary>
  174. internal virtual JobCallback MakeJobCallBack(ICallable cleanupCallback)
  175. {
  176. return new JobCallback(cleanupCallback, null);
  177. }
  178. /// <summary>
  179. /// https://tc39.es/ecma262/#sec-hostenqueuepromisejob
  180. /// </summary>
  181. internal void HostEnqueuePromiseJob(Action job, Realm realm)
  182. {
  183. Engine.AddToEventLoop(job);
  184. }
  185. internal virtual List<string> GetSupportedImportAttributes()
  186. {
  187. return _supportedImportAttributes;
  188. }
  189. }
  190. internal sealed record JobCallback(ICallable Callback, object? HostDefined);