public ScriptContext(ScriptRuntime runtime) { _isValid = true; _runtime = runtime; _ctx = JSApi.JS_NewContext(_runtime); JSApi.JS_AddIntrinsicOperators(_ctx); _atoms = new AtomCache(_ctx); _moduleCache = JSApi.JS_NewObject(_ctx); _globalObject = JSApi.JS_GetGlobalObject(_ctx); _numberConstructor = JSApi.JS_GetProperty(_ctx, _globalObject, JSApi.JS_ATOM_Number); _stringConstructor = JSApi.JS_GetProperty(_ctx, _globalObject, JSApi.JS_ATOM_String); _operatorCreate = JSApi.JS_UNDEFINED; var operators = JSApi.JS_GetProperty(_ctx, _globalObject, JSApi.JS_ATOM_Operators); if (!operators.IsNullish()) { if (operators.IsException()) { _ctx.print_exception(); } else { var create = JSApi.JS_GetProperty(_ctx, operators, GetAtom("create")); JSApi.JS_FreeValue(_ctx, operators); if (create.IsException()) { _ctx.print_exception(); } else { if (JSApi.JS_IsFunction(_ctx, create) == 1) { _operatorCreate = create; } else { JSApi.JS_FreeValue(_ctx, create); } } } } }
public static bool IsEditorRuntime(ScriptRuntime runtime) { var result = false; _rwlock.EnterWriteLock(); var len = _runtimeRefs.Count; for (int i = 0; i < len; ++i) { var runtimeRef = _runtimeRefs[i]; if (runtimeRef.target == runtime) { result = true; break; } } _rwlock.ExitWriteLock(); return(result); }
public static ScriptRuntime GetRuntime(JSRuntime rt) { ScriptRuntime runtime = null; if (rt.IsValid()) { var id = (int)JSApi.JS_GetRuntimeOpaque(rt); if (id > 0) { var index = id - 1; _rwlock.EnterReadLock(); var slot = _runtimeRefs[index]; runtime = slot.target; _rwlock.ExitReadLock(); } } return(runtime); }
/// <summary> /// (内部使用) 获取第一个有效的前台运行时 /// </summary> public static ScriptRuntime GetRuntime() { ScriptRuntime target = null; _rwlock.EnterWriteLock(); var len = _runtimeRefs.Count; for (int i = 0; i < len; ++i) { var runtimeRef = _runtimeRefs[i]; var runtime = runtimeRef.target; if (runtime != null && !runtime.isWorker && runtime.isRunning && runtime.isValid) { target = runtime; break; } } _rwlock.ExitWriteLock(); return(target); }
private void Start(JSContext ctx, JSValue value, string scriptPath) { var parent = ScriptEngine.GetRuntime(ctx); var runtime = parent.CreateWorker(); if (runtime == null) { throw new NullReferenceException(); } _self = JSApi.JS_DupValue(ctx, value); _parentRuntime = parent; _parentRuntime.OnDestroy += OnParentDestroy; _runtime = runtime; _runtime.OnAfterDestroy += OnWorkerAfterDestroy; RegisterGlobalObjects(); _runtime.EvalMain(scriptPath); _thread = new Thread(new ThreadStart(Run)); _thread.Priority = ThreadPriority.Lowest; _thread.IsBackground = true; _thread.Start(); }
public static ScriptRuntime CreateRuntime(bool isEditorRuntime) { if (!JSApi.IsValid()) { throw new InvalidOperationException("quickjs library is not matched, you need to rebuild it for current platform"); } _rwlock.EnterWriteLock(); ScriptRuntimeRef freeEntry; int slotIndex; if (_freeSlot < 0) { freeEntry = new ScriptRuntimeRef(); slotIndex = _runtimeRefs.Count; _runtimeRefs.Add(freeEntry); freeEntry.next = -1; } else { slotIndex = _freeSlot; freeEntry = _runtimeRefs[slotIndex]; _freeSlot = freeEntry.next; freeEntry.next = -1; } var runtime = new ScriptRuntime(slotIndex + 1); freeEntry.target = runtime; freeEntry.isEditorRuntime = isEditorRuntime; runtime.OnAfterDestroy += OnRuntimeAfterDestroy; _rwlock.ExitWriteLock(); RuntimeCreated?.Invoke(runtime); return(runtime); }
public unsafe object EvalMain(byte[] source, string module_id, string fullPath, Type expectedReturnType) { var tagValue = ScriptRuntime.TryReadByteCodeTagValue(source); if (tagValue == ScriptRuntime.BYTECODE_ES6_MODULE_TAG) { throw new Exception("es6 module bytecode as main is unsupported"); } object csValue = null; var dirname = PathUtils.GetDirectoryName(module_id); var filename_bytes = TextUtils.GetNullTerminatedBytes(module_id); var module_id_atom = GetAtom(module_id); var dirname_atom = GetAtom(dirname); var full_path_atom = GetAtom(fullPath); var exports_obj = JSApi.JS_NewObject(_ctx); var require_obj = JSApi.JS_DupValue(_ctx, _require); var module_obj = _new_commonjs_script_module(null, module_id, fullPath, exports_obj, false); var module_id_obj = JSApi.JS_AtomToString(_ctx, module_id_atom); var filename_obj = JSApi.JS_AtomToString(_ctx, full_path_atom); var dirname_obj = JSApi.JS_AtomToString(_ctx, dirname_atom); var require_argv = new JSValue[5] { exports_obj, require_obj, module_obj, filename_obj, dirname_obj }; JSApi.JS_SetProperty(_ctx, require_obj, GetAtom("moduleId"), JSApi.JS_DupValue(_ctx, module_id_obj)); JSApi.JS_SetProperty(_ctx, require_obj, GetAtom("main"), JSApi.JS_DupValue(_ctx, module_obj)); if (tagValue == ScriptRuntime.BYTECODE_COMMONJS_MODULE_TAG) { // bytecode fixed(byte *intput_ptr = source) { var bytecodeFunc = JSApi.JS_ReadObject(_ctx, intput_ptr + sizeof(uint), source.Length - sizeof(uint), JSApi.JS_READ_OBJ_BYTECODE); if (bytecodeFunc.tag == JSApi.JS_TAG_FUNCTION_BYTECODE) { var func_val = JSApi.JS_EvalFunction(_ctx, bytecodeFunc); // it's CallFree (bytecodeFunc) if (JSApi.JS_IsFunction(_ctx, func_val) != 1) { JSApi.JS_FreeValue(_ctx, func_val); FreeValues(require_argv); throw new Exception("failed to eval bytecode module"); } var rval = JSApi.JS_Call(_ctx, func_val, JSApi.JS_UNDEFINED); JSApi.JS_FreeValue(_ctx, func_val); if (rval.IsException()) { _ctx.print_exception(); JSApi.JS_FreeValue(_ctx, rval); FreeValues(require_argv); throw new Exception("failed to eval bytecode module"); } // success Values.js_get_var(_ctx, rval, expectedReturnType, out csValue); JSApi.JS_FreeValue(_ctx, rval); JSApi.JS_SetProperty(_ctx, module_obj, GetAtom("loaded"), JSApi.JS_NewBool(_ctx, true)); FreeValues(require_argv); return(csValue); } JSApi.JS_FreeValue(_ctx, bytecodeFunc); FreeValues(require_argv); throw new Exception("failed to eval bytecode module"); } } else { // source var input_bytes = TextUtils.GetShebangNullTerminatedCommonJSBytes(source); fixed(byte *input_ptr = input_bytes) fixed(byte *resolved_id_ptr = filename_bytes) { var input_len = (size_t)(input_bytes.Length - 1); var func_val = JSApi.JS_Eval(_ctx, input_ptr, input_len, resolved_id_ptr, JSEvalFlags.JS_EVAL_TYPE_GLOBAL | JSEvalFlags.JS_EVAL_FLAG_STRICT); if (func_val.IsException()) { FreeValues(require_argv); _ctx.print_exception(); throw new Exception("failed to eval module"); } if (JSApi.JS_IsFunction(_ctx, func_val) == 1) { var rval = JSApi.JS_Call(_ctx, func_val, JSApi.JS_UNDEFINED, require_argv.Length, require_argv); if (rval.IsException()) { JSApi.JS_FreeValue(_ctx, func_val); FreeValues(require_argv); _ctx.print_exception(); throw new Exception("failed to eval module"); } Values.js_get_var(_ctx, rval, expectedReturnType, out csValue); JSApi.JS_FreeValue(_ctx, rval); } JSApi.JS_FreeValue(_ctx, func_val); JSApi.JS_SetProperty(_ctx, module_obj, GetAtom("loaded"), JSApi.JS_NewBool(_ctx, true)); FreeValues(require_argv); return(csValue); } } }
// this method will consume the module_obj refcount public unsafe JSValue LoadModuleFromSource(byte[] source, string resolved_id, JSValue module_obj) { var context = this; var ctx = _ctx; var dirname = PathUtils.GetDirectoryName(resolved_id); var resolved_id_bytes = Utils.TextUtils.GetNullTerminatedBytes(resolved_id); var filename_obj = JSApi.JS_GetProperty(ctx, module_obj, context.GetAtom("filename")); var module_id_atom = context.GetAtom(resolved_id); var dirname_atom = context.GetAtom(dirname); var require_obj = JSApi.JSB_NewCFunction(ctx, ScriptRuntime.module_require, context.GetAtom("require"), 1, JSCFunctionEnum.JS_CFUNC_generic, 0); var main_mod_obj = context._dup_commonjs_main_module(); var dirname_obj = JSApi.JS_AtomToString(ctx, dirname_atom); var exports_obj = JSApi.JS_GetProperty(ctx, module_obj, context.GetAtom("exports")); JSApi.JS_SetProperty(ctx, require_obj, context.GetAtom("moduleId"), JSApi.JS_AtomToString(ctx, module_id_atom)); JSApi.JS_SetProperty(ctx, require_obj, context.GetAtom("main"), main_mod_obj); var require_argv = new JSValue[5] { exports_obj, require_obj, module_obj, filename_obj, dirname_obj, }; var tagValue = ScriptRuntime.TryReadByteCodeTagValue(source); if (tagValue == ScriptRuntime.BYTECODE_COMMONJS_MODULE_TAG) { // bytecode fixed(byte *intput_ptr = source) { var bytecodeFunc = JSApi.JS_ReadObject(ctx, intput_ptr + sizeof(uint), source.Length - sizeof(uint), JSApi.JS_READ_OBJ_BYTECODE); if (bytecodeFunc.tag == JSApi.JS_TAG_FUNCTION_BYTECODE) { var func_val = JSApi.JS_EvalFunction(ctx, bytecodeFunc); // it's CallFree (bytecodeFunc) if (JSApi.JS_IsFunction(ctx, func_val) != 1) { JSApi.JS_FreeValue(ctx, func_val); JSApi.JS_FreeValue(ctx, require_argv); return(JSApi.JS_ThrowInternalError(ctx, "failed to require bytecode module")); } var rval = JSApi.JS_Call(ctx, func_val, JSApi.JS_UNDEFINED, require_argv.Length, require_argv); JSApi.JS_FreeValue(ctx, func_val); if (rval.IsException()) { JSApi.JS_FreeValue(ctx, require_argv); return(rval); } // success JSApi.JS_FreeValue(ctx, rval); } else { JSApi.JS_FreeValue(ctx, bytecodeFunc); JSApi.JS_FreeValue(ctx, require_argv); return(JSApi.JS_ThrowInternalError(ctx, "failed to require bytecode module")); } } } else { // source var input_bytes = TextUtils.GetShebangNullTerminatedCommonJSBytes(source); fixed(byte *input_ptr = input_bytes) fixed(byte *resolved_id_ptr = resolved_id_bytes) { var input_len = (size_t)(input_bytes.Length - 1); var func_val = JSApi.JS_Eval(ctx, input_ptr, input_len, resolved_id_ptr, JSEvalFlags.JS_EVAL_TYPE_GLOBAL | JSEvalFlags.JS_EVAL_FLAG_STRICT); if (func_val.IsException()) { JSApi.JS_FreeValue(ctx, require_argv); return(func_val); } if (JSApi.JS_IsFunction(ctx, func_val) == 1) { var rval = JSApi.JS_Call(ctx, func_val, JSApi.JS_UNDEFINED, require_argv.Length, require_argv); if (rval.IsException()) { JSApi.JS_FreeValue(ctx, func_val); JSApi.JS_FreeValue(ctx, require_argv); return(rval); } JSApi.JS_FreeValue(ctx, rval); } JSApi.JS_FreeValue(ctx, func_val); } } JSApi.JS_SetProperty(ctx, module_obj, context.GetAtom("loaded"), JSApi.JS_NewBool(ctx, true)); var exports_ = JSApi.JS_GetProperty(ctx, module_obj, context.GetAtom("exports")); JSApi.JS_FreeValue(ctx, require_argv); return(exports_); }
// 在主线程回调 private static unsafe void _PostMessage(ScriptRuntime runtime, JSAction action) { var worker = action.worker; try { if (worker._runtime.isRunning && worker._parentRuntime.isRunning) { var context = runtime.GetMainContext(); var ctx = (JSContext)context; var onmessage = JSApi.JS_GetProperty(ctx, worker._self, context.GetAtom("onmessage")); if (onmessage.IsException()) { var exceptionString = ctx.GetExceptionString(); var logger = runtime.GetLogger(); if (logger != null) { logger.Write(LogLevel.Error, exceptionString); } } else { if (JSApi.JS_IsFunction(ctx, onmessage) == 1) { // read object => jsvalue JSValue data; fixed(byte *buf = action.buffer.data) { data = JSApi.JS_ReadObject(ctx, buf, action.buffer.readableBytes, 0); } if (data.IsException()) { var exceptionString = ctx.GetExceptionString(); var logger = runtime.GetLogger(); if (logger != null) { logger.Write(LogLevel.Error, exceptionString); } } else { var argv = stackalloc JSValue[1] { data }; var rval = JSApi.JS_Call(ctx, onmessage, worker._self, 1, argv); JSApi.JS_FreeValue(ctx, rval); } } else { // not function } JSApi.JS_FreeValue(ctx, onmessage); } } } finally { action.buffer.Release(); } }
public static Extra.SourceMapHelper EnableSourceMap(this ScriptRuntime runtime, string workspace = null) { var helper = new Extra.SourceMapHelper(); helper.OpenWorkspace(runtime, workspace); return helper; }
private static void _FreeValueAction(ScriptRuntime rt, JSAction action) { JSApi.JS_FreeValueRT(rt, action.value); }
/// <summary> /// master 处理 worker 发送的消息 (在master线程回调) /// </summary> private static unsafe void _MasterOnMessage(ScriptRuntime runtime, JSAction action) { var args = (JSWorkerArgs)action.args; var buffer = args.buffer; try { var worker = args.worker; if (worker._runtime.isRunning && worker._parentRuntime.isRunning) { var context = runtime.GetMainContext(); var ctx = (JSContext)context; var onmessage = JSApi.JS_GetProperty(ctx, worker._self, context.GetAtom("onmessage")); if (onmessage.IsException()) { var exceptionString = ctx.GetExceptionString(); var logger = runtime.GetLogger(); if (logger != null) { logger.Write(LogLevel.Error, exceptionString); } } else { if (JSApi.JS_IsFunction(ctx, onmessage) == 1) { // read object => jsvalue JSValue data; fixed(byte *buf = buffer.data) { data = JSApi.JS_ReadObject(ctx, buf, buffer.readableBytes, JSApi.JS_READ_OBJ_REFERENCE); } do { if (!data.IsException()) { var evt = JSApi.JS_NewObject(ctx); if (!evt.IsException()) { JSApi.JS_SetProperty(ctx, evt, context.GetAtom("data"), data); var argv = stackalloc JSValue[1] { evt }; var rval = JSApi.JS_Call(ctx, onmessage, worker._self, 1, argv); JSApi.JS_FreeValue(ctx, rval); JSApi.JS_FreeValue(ctx, evt); break; } else { JSApi.JS_FreeValue(ctx, data); } } var exceptionString = ctx.GetExceptionString(); var logger = runtime.GetLogger(); if (logger != null) { logger.Write(LogLevel.Error, exceptionString); } } while (false); } else { // not function } JSApi.JS_FreeValue(ctx, onmessage); } } } finally { buffer.Release(); } }
private static void OnRuntimeAfterDestroy(ScriptRuntime runtime) { _runtime = null; }
public static ScriptRuntime CreateRuntime() { _runtime = new ScriptRuntime(); _runtime.OnAfterDestroy += OnRuntimeAfterDestroy; return(_runtime); }
private static void _FreeValueAction(ScriptRuntime rt, JSValue value) { JSApi.JS_FreeValueRT(rt, value); }