예제 #1
0
        public void EvalSource(string source, string filename)
        {
            if (filename == null)
            {
                filename = "eval";
            }
            if (string.IsNullOrEmpty(source))
            {
                return;
            }
            var ctx = _ctx.rawValue;

            DuktapeDLL.duk_push_string(ctx, source);
            DuktapeDLL.duk_push_string(ctx, filename);
            if (DuktapeDLL.duk_pcompile(ctx, 0) != 0)
            {
                DuktapeAux.PrintError(ctx, -1, filename);
                DuktapeDLL.duk_pop(ctx);
            }
            else
            {
                // Debug.LogFormat("check top {0}", DuktapeDLL.duk_get_top(ctx));
                if (DuktapeDLL.duk_pcall(ctx, 0) != DuktapeDLL.DUK_EXEC_SUCCESS)
                {
                    DuktapeAux.PrintError(ctx, -1, filename);
                }
                DuktapeDLL.duk_pop(ctx);
                // Debug.LogFormat("check top {0}", DuktapeDLL.duk_get_top(ctx));
            }
        }
 public static bool duk_get_type(IntPtr ctx, int idx, out Type o)
 {
     if (DuktapeDLL.duk_is_string(ctx, idx))
     {
         var name = DuktapeDLL.duk_get_string(ctx, idx);
         o = DuktapeAux.GetType(name);
         return(o != null);
     }
     else
     {
         uint refid_t;
         //TODO: 增加一个隐藏属性记录jsobject对应类型 (constructor, object)
         if (DuktapeDLL.duk_unity_get_type_refid(ctx, idx, out refid_t))
         {
             var vm = DuktapeVM.GetVM(ctx);
             o = vm.GetExportedType(refid_t);
             // Debug.Log($"get type from exported registry {o}:{refid}");
             return(o != null);
         }
         else
         {
             int refid;
             if (DuktapeDLL.duk_unity_get_refid(ctx, idx, out refid))
             {
                 var cache = DuktapeVM.GetObjectCache(ctx);
                 cache.TryGetTypedObject(refid, out o);
                 // Debug.Log($"get type from objectcache registry {o}:{refid}");
                 return(o != null);
             }
         }
     }
     o = null;
     return(false);
 }
예제 #3
0
        private static duk_ret_t cb_load_module(IntPtr ctx)
        {
            var module_id = DuktapeAux.duk_require_string(ctx, 0);

            DuktapeDLL.duk_get_prop_string(ctx, 2, "filename");
            var filename = DuktapeAux.duk_require_string(ctx, -1);
            var source   = GetVM(ctx)._fileResolver.ReadAllBytes(filename);

            // Debug.LogFormat("cb_load_module module_id:'{0}', filename:'{1}', resolved:'{2}'\n", module_id, filename, resolvedPath);
            do
            {
                if (source != null && source.Length > 0) // bytecode is unsupported
                {
                    if (source[0] != 0xbf)
                    {
                        DuktapeDLL.duk_unity_push_lstring(ctx, source, (uint)source.Length);
                    }
                    else
                    {
                        DuktapeDLL.duk_type_error(ctx, "cannot load module (bytecode): %s", module_id);
                    }
                    break;
                }
                DuktapeDLL.duk_type_error(ctx, "cannot load module: %s", module_id);
            } while (false);
            return(1);
        }
 public static bool duk_get_type(IntPtr ctx, int idx, out Type o)
 {
     if (DuktapeDLL.duk_is_string(ctx, idx))
     {
         var name = DuktapeDLL.duk_get_string(ctx, idx);
         o = DuktapeAux.GetType(name);
         return(o != null);
     }
     else
     {
         //TODO: 增加一个隐藏属性记录jsobject对应类型 (constructor, object)
         if (DuktapeDLL.duk_get_prop_string(ctx, idx, DuktapeVM.OBJ_PROP_EXPORTED_REFID))
         {
             var vm    = DuktapeVM.GetVM(ctx);
             var refid = DuktapeDLL.duk_get_uint(ctx, -1);
             DuktapeDLL.duk_pop(ctx);
             o = vm.GetExportedType(refid);
             // Debug.Log($"get type from exported registry {o}:{refid}");
             return(o != null);
         }
         else if (DuktapeDLL.duk_get_prop_string(ctx, idx, DuktapeVM.OBJ_PROP_NATIVE))
         {
             var cache = DuktapeVM.GetObjectCache(ctx);
             var refid = DuktapeDLL.duk_get_int(ctx, -1);
             DuktapeDLL.duk_pop(ctx);
             cache.TryGetTypedObject(refid, out o);
             // Debug.Log($"get type from objectcache registry {o}:{refid}");
             return(o != null);
         }
     }
     o = null;
     return(false);
 }
예제 #5
0
        public void EvalMain(string filename, byte[] source)
        {
            if (source == null || source.Length == 0)
            {
                return;
            }
            if (source[0] == 0xbf)
            {
                //NOTE: module is not supported in bytecode mode
                EvalSource(filename, source);
            }
            else
            {
                if (filename == null)
                {
                    filename = "eval";
                }
                var ctx = _ctx.rawValue;
                var top = DuktapeDLL.duk_get_top(ctx);

                DuktapeDLL.duk_unity_push_lstring(ctx, source, (uint)source.Length);
                var err = DuktapeDLL.duk_module_node_peval_main(ctx, filename);
                // var err = DuktapeDLL.duk_peval(ctx);
                // var err = DuktapeDLL.duk_peval_string_noresult(ctx, source);
                // Debug.Log($"load main module: {filename} ({resolvedPath})");
                if (err != 0)
                {
                    DuktapeAux.PrintError(ctx, -1, filename);
                    // Debug.LogErrorFormat("eval main error: {0}\n{1}", DuktapeDLL.duk_safe_to_string(ctx, -1), filename);
                }
                DuktapeDLL.duk_set_top(ctx, top);
            }
        }
예제 #6
0
        public static int duk_addSearchPath(IntPtr ctx)
        {
            var path = DuktapeAux.duk_require_string(ctx, 0);

            DuktapeVM.GetVM(ctx).AddSearchPath(path);
            return(0);
        }
예제 #7
0
        public static int duk_dofile(IntPtr ctx)
        {
            var filename = DuktapeAux.duk_require_string(ctx, 0);

            DuktapeVM.GetVM(ctx).EvalFile(filename);
            return(0);
        }
예제 #8
0
        public bool InvokeMemberWithBooleanReturn(string name)
        {
            var member = GetMember(name);

            if (member != null)
            {
                var ctx = member.context.rawValue;
                if (ctx != IntPtr.Zero)
                {
                    member.Push(ctx);
                    this.Push(ctx);
                    var ret = DuktapeDLL.duk_pcall_method(ctx, 0);
                    if (ret != DuktapeDLL.DUK_EXEC_SUCCESS)
                    {
                        DuktapeAux.PrintError(ctx, -1);
                        DuktapeDLL.duk_pop(ctx);
                        throw new Exception("InvokeMemberWithBooleanReturn failed");
                    }

                    var o = DuktapeDLL.duk_get_boolean_default(ctx, -1, false);
                    DuktapeDLL.duk_pop(ctx);
                    return(o);
                }
            }

            return(false);
        }
예제 #9
0
        public static int GetType(IntPtr ctx)
        {
            string name;

            duk_get_primitive(ctx, 0, out name);
            //TODO: type 缓存; 从 jsobject hidden property 中读 refid
            var type = DuktapeAux.GetType(name);

            duk_push_classvalue(ctx, type);
            return(1);
        }
예제 #10
0
        public DuktapeVM(IO.ByteBufferAllocator allocator = null)
        {
            _instance            = this;
            _byteBufferAllocator = allocator;

            var ctx = DuktapeDLL.duk_create_heap_default();

            _ctx = new DuktapeContext(this, ctx);
            DuktapeAux.duk_open(ctx);
            DuktapeVM.duk_open_module(ctx);
            DuktapeDLL.duk_unity_open(ctx);
        }
예제 #11
0
        // 根据当前栈参数数量调用函数
        // 调用失败时抛异常, 成功时栈上保留返回值
        public void EndInvoke(IntPtr ctx)
        {
            var nargs = DuktapeDLL.duk_get_top(ctx) - _savedState;
            var ret   = DuktapeDLL.duk_pcall_method(ctx, nargs);

            if (ret != DuktapeDLL.DUK_EXEC_SUCCESS)
            {
                DuktapeAux.PrintError(ctx, -1);
                DuktapeDLL.duk_pop(ctx);
                throw new Exception("duktape delegate exception");
            }
        }
예제 #12
0
 // 获取全局函数并调用 (do not cache it)
 public void Invoke(string funcName)
 {
     DuktapeDLL.duk_push_global_object(_ctx);
     DuktapeDLL.duk_get_prop_string(_ctx, -1, funcName);
     if (DuktapeDLL.duk_is_function(_ctx, -1))
     {
         if (DuktapeDLL.duk_pcall(_ctx, 0) != DuktapeDLL.DUK_EXEC_SUCCESS)
         {
             DuktapeAux.PrintError(_ctx, -1);
         }
     }
     DuktapeDLL.duk_pop_2(_ctx);
 }
예제 #13
0
        // poolSize: 预分配内存
        public DuktapeVM(IO.ByteBufferAllocator allocator = null, int poolSize = 0)
        {
            _instance            = this;
            _byteBufferAllocator = allocator;
            _memAllocPoolSize    = poolSize >= 0 ? (uint)poolSize : 0;
            _memAllocPool        = _memAllocPoolSize != 0 ? Marshal.AllocHGlobal(poolSize) : IntPtr.Zero;
            var ctx = DuktapeDLL.duk_unity_create_heap(_memAllocPool, _memAllocPoolSize);

            _ctx = new DuktapeContext(this, ctx);
            DuktapeDLL.duk_unity_open(ctx);
            DuktapeAux.duk_open(ctx);
            DuktapeVM.duk_open_module(ctx);
        }
예제 #14
0
 public byte[] Compile(string filename, byte[] bytes)
 {
     try
     {
         // return _vm.DumpBytecode(filename, bytes);
         return(DuktapeAux.DumpBytecode(_ctx, filename, bytes));
     }
     catch (Exception exception)
     {
         Debug.LogError(exception);
         return(null);
     }
 }
예제 #15
0
        public object EvalSource(string filename, byte[] source)
        {
            object retValue = null;

            if (source == null || source.Length == 0)
            {
                return(retValue);
            }
            if (filename == null)
            {
                filename = "eval";
            }

            var ctx = _ctx.rawValue;

            if (source[0] == 0xbf)
            {
                // load bytecode...
                var buffer_ptr = DuktapeDLL.duk_push_fixed_buffer(ctx, (uint)source.Length);
                Marshal.Copy(source, 0, buffer_ptr, source.Length);
                DuktapeDLL.duk_load_function(ctx);
            }
            else
            {
                DuktapeDLL.duk_unity_push_lstring(ctx, source, (uint)source.Length);
                DuktapeDLL.duk_push_string(ctx, filename);
                if (DuktapeDLL.duk_pcompile(ctx, 0) != 0)
                {
                    DuktapeAux.PrintError(ctx, -1, filename);
                    DuktapeDLL.duk_pop(ctx);
                    throw new Exception("[duktape] source compile failed");
                }
            }

            // Debug.LogFormat("check top {0}", DuktapeDLL.duk_get_top(ctx));
            if (DuktapeDLL.duk_pcall(ctx, 0) != DuktapeDLL.DUK_EXEC_SUCCESS)
            {
                DuktapeAux.PrintError(ctx, -1, filename);
                DuktapeDLL.duk_pop(ctx);
                throw new Exception("[duktape] source eval failed");
            }
            DuktapeBinding.duk_get_var(ctx, -1, out retValue);
            DuktapeDLL.duk_pop(ctx);
            return(retValue);
            // Debug.LogFormat("check top {0}", DuktapeDLL.duk_get_top(ctx));
        }
예제 #16
0
        // 函数对象以及nargs数的参数必须由调用者保证已经入栈, 然后才能调用 _InternalCall
        // 调用完成后栈顶为函数返回值, 或异常对象
        public void _InternalPCall(IntPtr ctx, int nargs)
        {
            if (_argv != null)
            {
                var length = _argv.Length;
                nargs += length;
                for (var i = 0; i < length; i++)
                {
                    _argv[i].Push(ctx);
                }
            }
            var ret = DuktapeDLL.duk_pcall(ctx, nargs);

            if (ret != DuktapeDLL.DUK_EXEC_SUCCESS)
            {
                DuktapeAux.PrintError(ctx, -1);
                // throw new Exception(err);
            }
        }
예제 #17
0
        public void EvalSource(string filename, byte[] source)
        {
            if (source == null || source.Length == 0)
            {
                return;
            }
            if (filename == null)
            {
                filename = "eval";
            }
            var ctx = _ctx.rawValue;

            do
            {
                if (source[0] == 0xbf)
                {
                    // load bytecode...
                    var buffer_ptr = DuktapeDLL.duk_push_fixed_buffer(ctx, (uint)source.Length);
                    Marshal.Copy(source, 0, buffer_ptr, source.Length);
                    DuktapeDLL.duk_load_function(ctx);
                }
                else
                {
                    DuktapeDLL.duk_unity_push_lstring(ctx, source, (uint)source.Length);
                    DuktapeDLL.duk_push_string(ctx, filename);
                    if (DuktapeDLL.duk_pcompile(ctx, 0) != 0)
                    {
                        DuktapeAux.PrintError(ctx, -1, filename);
                        DuktapeDLL.duk_pop(ctx);
                        break;
                    }
                }
                // Debug.LogFormat("check top {0}", DuktapeDLL.duk_get_top(ctx));
                if (DuktapeDLL.duk_pcall(ctx, 0) != DuktapeDLL.DUK_EXEC_SUCCESS)
                {
                    DuktapeAux.PrintError(ctx, -1, filename);
                }
                DuktapeDLL.duk_pop(ctx);
                // Debug.LogFormat("check top {0}", DuktapeDLL.duk_get_top(ctx));
            } while (false);
        }
예제 #18
0
        public void InvokeMember(string name)
        {
            var member = GetMember(name);

            if (member != null)
            {
                var ctx = member.context.rawValue;
                if (ctx != IntPtr.Zero)
                {
                    member.Push(ctx);
                    this.Push(ctx);
                    var ret = DuktapeDLL.duk_pcall_method(ctx, 0);
                    if (ret != DuktapeDLL.DUK_EXEC_SUCCESS)
                    {
                        DuktapeAux.PrintError(ctx, -1);
                        // throw new Exception(err);
                    }
                    DuktapeDLL.duk_pop(ctx);
                }
            }
        }
예제 #19
0
        public void EvalMain(string filename)
        {
            filename = EnsureExtension(filename);
            var ctx          = _ctx.rawValue;
            var top          = DuktapeDLL.duk_get_top(ctx);
            var resolvedPath = ResolvePath(filename);
            var source       = _fileManager.ReadAllText(resolvedPath);

            DuktapeDLL.duk_push_string(ctx, source);
            var err = DuktapeDLL.duk_module_node_peval_main(ctx, filename);

            // var err = DuktapeDLL.duk_peval(ctx);
            // var err = DuktapeDLL.duk_peval_string_noresult(ctx, source);
            // Debug.Log($"load main module: {filename} ({resolvedPath})");
            if (err != 0)
            {
                DuktapeAux.PrintError(ctx, -1, filename);
                // Debug.LogErrorFormat("eval main error: {0}\n{1}", DuktapeDLL.duk_safe_to_string(ctx, -1), filename);
            }
            DuktapeDLL.duk_set_top(ctx, top);
        }
예제 #20
0
        private static duk_ret_t cb_resolve_module(IntPtr ctx)
        {
            var module_id  = EnsureExtension(DuktapeAux.duk_require_string(ctx, 0));
            var parent_id  = DuktapeAux.duk_require_string(ctx, 1);
            var resolve_to = module_id;

            // Debug.LogFormat("cb_resolve_module module_id:'{0}', parent_id:'{1}'\n", module_id, parent_id);

            if (module_id.StartsWith("./") || module_id.StartsWith("../") || module_id.Contains("/./") || module_id.Contains("/../"))
            {
                // 显式相对路径直接从 parent 模块路径拼接
                var parent_path = PathUtils.GetDirectoryName(parent_id);
                try
                {
                    resolve_to = PathUtils.ExtractPath(PathUtils.Combine(parent_path, module_id), '/');
                }
                catch
                {
                    // 不能提升到源代码目录外面
                    DuktapeDLL.duk_type_error(ctx, "invalid module path (out of sourceRoot): %s", module_id);
                    return(1);
                }
            }
            // Debug.LogFormat("resolve_cb(1): id:{0}', parent-id:'{1}', resolve-to:'{2}'", module_id, parent_id, resolve_to);
            // if (GetVM(ctx).ResolvePath(resolve_to) == null)
            // {
            //     DuktapeDLL.duk_type_error(ctx, "cannot find module: %s", module_id);
            //     return 1;
            // }

            if (resolve_to != null)
            {
                DuktapeDLL.duk_push_string(ctx, resolve_to);
            }
            else
            {
                DuktapeDLL.duk_type_error(ctx, "cannot find module: %s", module_id);
            }
            return(1);
        }
예제 #21
0
        private static duk_ret_t cb_load_module(IntPtr ctx)
        {
            var module_id = DuktapeAux.duk_require_string(ctx, 0);

            DuktapeDLL.duk_get_prop_string(ctx, 2, "filename");
            var filename     = DuktapeAux.duk_require_string(ctx, -1);
            var resolvedPath = GetVM(ctx).ResolvePath(filename);
            // Debug.LogFormat("cb_load_module module_id:'{0}', filename:'{1}', resolved:'{2}'\n", module_id, filename, resolvedPath);

            var source = GetVM(ctx)._fileManager.ReadAllText(resolvedPath);

            if (source != null)
            {
                DuktapeDLL.duk_push_string(ctx, source);
            }
            else
            {
                DuktapeDLL.duk_type_error(ctx, "cannot load module: %s", module_id);
            }

            return(1);
        }
예제 #22
0
 public static byte[] DumpBytecode(IntPtr ctx, string filename, byte[] source)
 {
     if (ctx == IntPtr.Zero)
     {
         throw new InvalidOperationException();
     }
     if (source == null || source.Length == 0)
     {
         return(null);
     }
     if (source[0] == 0xbf)
     {
         return(source);
     }
     if (filename == null)
     {
         filename = "eval";
     }
     DuktapeDLL.duk_unity_push_lstring(ctx, source, (uint)source.Length);
     DuktapeDLL.duk_push_string(ctx, filename);
     if (DuktapeDLL.duk_pcompile(ctx, 0) != 0)
     {
         DuktapeAux.PrintError(ctx, -1, filename);
         DuktapeDLL.duk_pop(ctx);
         return(null);
     }
     else
     {
         DuktapeDLL.duk_dump_function(ctx);
         uint buffer_size;
         var  buffer_ptr = DuktapeDLL.duk_unity_require_buffer_data(ctx, -1, out buffer_size);
         var  bytes      = new byte[buffer_size];
         Marshal.Copy(buffer_ptr, bytes, 0, (int)buffer_size);
         DuktapeDLL.duk_pop(ctx);
         return(bytes);
     }
 }
예제 #23
0
        private IEnumerator _InitializeStep(IDuktapeListener listener, int step)
        {
            var ctx = DuktapeDLL.duk_create_heap_default();

            _ctx = new DuktapeContext(this, ctx);
            DuktapeAux.duk_open(ctx);
            DuktapeVM.duk_open_module(ctx);
            DuktapeDLL.duk_unity_open(ctx);
            DuktapeDLL.duk_push_global_object(ctx);
            DuktapeJSBuiltins.reg(ctx);
            listener?.OnTypesBinding(this);
            var exportedTypes = this.GetType().Assembly.GetExportedTypes();
            var bindingTypes  = new List <Type>(exportedTypes.Length);
            var ctxAsArgs     = new object[] { ctx };

            for (int i = 0, size = exportedTypes.Length; i < size; i++)
            {
                var type = exportedTypes[i];
#if UNITY_EDITOR
                if (type.IsDefined(typeof(JSAutoRunAttribute), false))
                {
                    try
                    {
                        var run = type.GetMethod("Run", BindingFlags.Static | BindingFlags.Public);
                        if (run != null)
                        {
                            run.Invoke(null, null);
                        }
                    }
                    catch (Exception exception)
                    {
                        Debug.LogWarning($"JSAutoRun failed: {exception}");
                    }
                    continue;
                }
#endif
                var attributes = type.GetCustomAttributes(typeof(JSBindingAttribute), false);
                if (attributes.Length == 1)
                {
                    var jsBinding = attributes[0] as JSBindingAttribute;
                    if (jsBinding.Version == 0 || jsBinding.Version == VERSION)
                    {
                        bindingTypes.Add(type);
                    }
                    else
                    {
                        if (listener != null)
                        {
                            listener.OnBindingError(this, type);
                        }
                    }
                }
            }

            var numRegInvoked = bindingTypes.Count;
            for (var i = 0; i < numRegInvoked; ++i)
            {
                var type = bindingTypes[i];
                var reg  = type.GetMethod("reg");
                if (reg != null)
                {
                    reg.Invoke(null, ctxAsArgs);
                    if (listener != null)
                    {
                        listener.OnProgress(this, i, numRegInvoked);
                    }

                    if (i % step == 0)
                    {
                        yield return(null);
                    }
                }
            }
            if (listener != null)
            {
                listener.OnBinded(this, numRegInvoked);
            }
            // Debug.LogFormat("exported {0} classes", _exported.Count);

            // 设置导出类的继承链
            foreach (var kv in _exported)
            {
                var type     = kv.Key;
                var baseType = type.BaseType;
                if (baseType == null)
                {
                    // Debug.Log($"baseType is null, for {type}");
                    continue;
                }
                var fn = kv.Value;
                fn.PushPrototype(ctx);
                if (PushChainedPrototypeOf(ctx, baseType))
                {
                    // Debug.LogFormat($"set {type} super {baseType}");
                    DuktapeDLL.duk_set_prototype(ctx, -2);
                }
                else
                {
                    Debug.LogWarning($"fail to push prototype, for {type}: {baseType}");
                }
                DuktapeDLL.duk_pop(ctx);
            }

            DuktapeJSBuiltins.postreg(ctx);
            DuktapeDLL.duk_pop(ctx); // pop global

            _updateTimer = DuktapeRunner.SetInterval(this.OnUpdate, 100f);

            if (listener != null)
            {
                listener.OnLoaded(this);
            }
        }
예제 #24
0
 public byte[] DumpBytecode(string filename, byte[] source)
 {
     return(_ctx != null?DuktapeAux.DumpBytecode(_ctx.rawValue, filename, source) : null);
 }