Host.cs 7.5 KB

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