/// <summary> /// Creates a new JavaScript Runtime. /// </summary> /// <param name="attributes"></param> /// <returns></returns> public BaristaRuntime CreateRuntime(JavaScriptRuntimeAttributes attributes = JavaScriptRuntimeAttributes.None) { var contextService = m_serviceProvider.GetRequiredService <IBaristaContextFactory>(); var runtimeHandle = m_engine.JsCreateRuntime(attributes, null); var result = m_runtimePool.GetOrAdd(runtimeHandle, () => { var rt = new BaristaRuntime(m_engine, contextService, runtimeHandle); //Do not wire up a runtime's BeforeCollect handler with the factory as this will //remove and dispose of the runtime on ANY garbage collect, which will eventually //crash the engine. //After a runtime handle is disposed, remove the handle from the pool. void afterDispose(object sender, EventArgs args) { rt.AfterDispose -= afterDispose; m_runtimePool.RemoveHandle(runtimeHandle); } rt.AfterDispose += afterDispose; return(rt); }); if (result == null) { throw new InvalidOperationException("Unable to create or retrieve a new Barista Runtime."); } return(result); }
public BaristaContext CreateContext(BaristaRuntime runtime) { if (runtime == null) { throw new ArgumentNullException(nameof(runtime)); } if (runtime.IsDisposed) { throw new ObjectDisposedException(nameof(runtime)); } var contextHandle = m_engine.JsCreateContext(runtime.Handle); return(m_contextPool.GetOrAdd(contextHandle, () => { var moduleRecordFactory = m_serviceProvider.GetRequiredService <IBaristaModuleRecordFactory>(); var valueFactoryBuilder = m_serviceProvider.GetRequiredService <IBaristaValueFactoryBuilder>(); var conversionStrategy = m_serviceProvider.GetRequiredService <IBaristaConversionStrategy>(); //For flexability, a promise task queue is not required. var promiseTaskQueue = m_serviceProvider.GetService <IPromiseTaskQueue>(); //Set the handle that will be called prior to the engine collecting the context. var context = new BaristaContext(m_engine, valueFactoryBuilder, conversionStrategy, moduleRecordFactory, promiseTaskQueue, contextHandle); void beforeCollect(object sender, BaristaObjectBeforeCollectEventArgs args) { context.BeforeCollect -= beforeCollect; m_contextPool.RemoveHandle(new JavaScriptContextSafeHandle(args.Handle)); } context.BeforeCollect += beforeCollect; return context; })); }
public JsArrayBuffer CreateArrayBuffer(string data) { if (data == null) { data = String.Empty; } JavaScriptValueSafeHandle externalArrayHandle; IntPtr ptrData = Marshal.StringToHGlobalUni(data); try { GCHandle freeCallbackHandle = default(GCHandle); JavaScriptObjectFinalizeCallback freeCallback = (ptr) => { Marshal.ZeroFreeGlobalAllocUnicode(ptrData); if (freeCallbackHandle.IsAllocated) { freeCallbackHandle.Free(); } }; freeCallbackHandle = GCHandle.Alloc(freeCallback); externalArrayHandle = m_engine.JsCreateExternalArrayBuffer(ptrData, (uint)data.Length, freeCallback, IntPtr.Zero); } catch (Exception) { //If anything goes wrong, free the unmanaged memory. //This is not a finally as if success, the memory will be freed automagially. Marshal.ZeroFreeGlobalAllocUnicode(ptrData); throw; } var result = m_valuePool.GetOrAdd(externalArrayHandle, () => { return(new JsManagedExternalArrayBuffer(m_engine, Context, externalArrayHandle, ptrData)); }); var resultArrayBuffer = result as JsArrayBuffer; if (resultArrayBuffer == null) { throw new InvalidOperationException($"Expected the result object to be a JsArrayBuffer, however the value was {result.GetType()}"); } return((JsArrayBuffer)result); }
private BaristaModuleRecord CreateBaristaModuleRecordInternal(BaristaContext context, string moduleName, JavaScriptValueSafeHandle specifier, BaristaModuleRecord parentModule = null, bool setAsHost = false, IBaristaModuleLoader moduleLoader = null) { JavaScriptModuleRecord moduleRecord = null; if (m_specifierModuleLookup.ContainsKey(specifier)) { moduleRecord = m_specifierModuleLookup[specifier]; } if (moduleRecord == null || moduleRecord.IsClosed || moduleRecord.IsInvalid) { if (m_specifierModuleLookup.ContainsKey(specifier)) { m_specifierModuleLookup.Remove(specifier); } moduleRecord = m_engine.JsInitializeModuleRecord(parentModule == null ? JavaScriptModuleRecord.Invalid : parentModule.Handle, specifier); } return(m_moduleReferencePool.GetOrAdd(moduleRecord, () => { //If a module loader hasn't be specified in the parameters, obtain one from DI. if (moduleLoader == null) { moduleLoader = m_serviceProvider.GetRequiredService <IBaristaModuleLoader>(); } var module = new BaristaModuleRecord(moduleName.ToString(), specifier, parentModule, m_engine, context, this, moduleLoader, moduleRecord); m_specifierModuleLookup.Add(specifier, moduleRecord); //If specified, indicate as host module. if (setAsHost == true) { m_engine.JsSetModuleHostInfo(moduleRecord, JavaScriptModuleHostInfoKind.HostDefined, specifier.DangerousGetHandle()); } void beforeCollect(object sender, BaristaObjectBeforeCollectEventArgs args) { context.BeforeCollect -= beforeCollect; m_moduleReferencePool.RemoveHandle(new JavaScriptModuleRecord(args.Handle)); if (sender is BaristaModuleRecord baristaModuleRecord) { m_specifierModuleLookup.Remove(baristaModuleRecord.Specifier); } } module.BeforeCollect += beforeCollect; return module; })); }