예제 #1
0
        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);
                        }
                    }
                }
            }
        }
예제 #2
0
        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);
        }
예제 #3
0
        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);
        }
예제 #4
0
        /// <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);
        }
예제 #5
0
        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();
        }
예제 #6
0
        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);
        }
예제 #7
0
        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);
                }
            }
        }
예제 #8
0
        // 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_);
        }
예제 #9
0
        // 在主线程回调
        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();
            }
        }
예제 #10
0
 public static Extra.SourceMapHelper EnableSourceMap(this ScriptRuntime runtime, string workspace = null)
 {
     var helper = new Extra.SourceMapHelper();
     helper.OpenWorkspace(runtime, workspace);
     return helper;
 }
예제 #11
0
 private static void _FreeValueAction(ScriptRuntime rt, JSAction action)
 {
     JSApi.JS_FreeValueRT(rt, action.value);
 }
예제 #12
0
        /// <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();
            }
        }
예제 #13
0
 private static void OnRuntimeAfterDestroy(ScriptRuntime runtime)
 {
     _runtime = null;
 }
예제 #14
0
 public static ScriptRuntime CreateRuntime()
 {
     _runtime = new ScriptRuntime();
     _runtime.OnAfterDestroy += OnRuntimeAfterDestroy;
     return(_runtime);
 }
예제 #15
0
 private static void _FreeValueAction(ScriptRuntime rt, JSValue value)
 {
     JSApi.JS_FreeValueRT(rt, value);
 }