Пример #1
0
        internal long AddConstructor(JSConstructorCallback callback)
        {
            int callbackIdx = constructorCallbacks.Count;

            constructorCallbacks.Add(callback);
            return(Utils.TwoIntToLong(Idx, callbackIdx));
        }
Пример #2
0
        // #lizard forgives
        private int RegisterType(IntPtr isolate, Type type, bool includeNoPublic)
        {
            TypeRegisterInfo registerInfo = null;

            if (lazyStaticWrapLoaders.ContainsKey(type))
            {
                registerInfo = lazyStaticWrapLoaders[type]();
                lazyStaticWrapLoaders.Remove(type);
            }

            BindingFlags flag = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;

            if (includeNoPublic)
            {
                flag = flag | BindingFlags.NonPublic;
            }

            // baseType
            int baseTypeId = -1;

            if (type.BaseType != null)
            {
                baseTypeId = GetTypeId(isolate, type.BaseType);
            }

            Dictionary <MethodKey, List <MethodInfo> > slowBindingMethodGroup = new Dictionary <MethodKey, List <MethodInfo> >();
            Dictionary <string, ProperyMethods>        slowBindingProperties  = new Dictionary <string, ProperyMethods>();
            List <FieldInfo> slowBindingFields = new List <FieldInfo>();

            Dictionary <MethodKey, List <MethodInfo> > lazyBindingMethodGroup = new Dictionary <MethodKey, List <MethodInfo> >();
            Dictionary <string, ProperyMethods>        lazyBindingProperties  = new Dictionary <string, ProperyMethods>();
            List <FieldInfo> lazyBindingFields = new List <FieldInfo>();

            Func <MethodKey, MethodInfo, bool> AddMethodToSlowBindingGroup = (MethodKey methodKey, MethodInfo method) =>
            {
                if (method.IsGenericMethodDefinition)
                {
                    if (!Utils.IsSupportedMethod(method))
                    {
                        return(false);
                    }
                    var genericArguments          = method.GetGenericArguments();
                    var constraintedArgumentTypes = new Type[genericArguments.Length];
                    for (var j = 0; j < genericArguments.Length; j++)
                    {
                        constraintedArgumentTypes[j] = genericArguments[j].BaseType;
                    }
                    method = method.MakeGenericMethod(constraintedArgumentTypes);
                }

                if (method.IsSpecialName && method.Name.StartsWith("get_") && method.GetParameters().Length != 1) // getter of property
                {
                    string         propName = method.Name.Substring(4);
                    ProperyMethods properyMethods;
                    if (!slowBindingProperties.TryGetValue(propName, out properyMethods))
                    {
                        properyMethods = new ProperyMethods();
                        slowBindingProperties.Add(propName, properyMethods);
                    }
                    properyMethods.Getter = method;
                }
                else if (method.IsSpecialName && method.Name.StartsWith("set_") && method.GetParameters().Length != 2) // setter of property
                {
                    string         propName = method.Name.Substring(4);
                    ProperyMethods properyMethods;
                    if (!slowBindingProperties.TryGetValue(propName, out properyMethods))
                    {
                        properyMethods = new ProperyMethods();
                        slowBindingProperties.Add(propName, properyMethods);
                    }
                    properyMethods.Setter = method;
                }
                else
                {
                    List <MethodInfo> overloads;
                    if (!slowBindingMethodGroup.TryGetValue(methodKey, out overloads))
                    {
                        overloads = new List <MethodInfo>();
                        slowBindingMethodGroup.Add(methodKey, overloads);
                    }
                    overloads.Add(method);
                }

                return(true);
            };
            HashSet <string> readonlyStaticFields = new HashSet <string>();

            int typeId = -1;

            if (registerInfo == null)
            {
                // registerInfo is null, then all the member use the SlowBinding

                // constructors
                JSConstructorCallback constructorCallback = null;

                if (typeof(Delegate).IsAssignableFrom(type))
                {
                    DelegateConstructWrap delegateConstructWrap = new DelegateConstructWrap(type, jsEnv.GeneralGetterManager);
                    constructorCallback = delegateConstructWrap.Construct;
                }
                else
                {
                    bool hasNoParametersCtor = false;
                    var  constructorWraps    = type.GetConstructors(flag)
                                               .Select(m =>
                    {
                        if (m.GetParameters().Length == 0)
                        {
                            hasNoParametersCtor = true;
                        }
                        return(new OverloadReflectionWrap(m, jsEnv.GeneralGetterManager, jsEnv.GeneralSetterManager));
                    })
                                               .ToList();
                    if (type.IsValueType && !hasNoParametersCtor)
                    {
                        constructorWraps.Add(new OverloadReflectionWrap(type, jsEnv.GeneralGetterManager));
                    }
                    MethodReflectionWrap constructorReflectionWrap = new MethodReflectionWrap(".ctor", constructorWraps);
                    constructorCallback = constructorReflectionWrap.Construct;
                }

                typeId = PuertsDLL.RegisterClass(jsEnv.isolate, baseTypeId, type.AssemblyQualifiedName, constructorWrap, null, jsEnv.AddConstructor(constructorCallback));

                // methods and properties
                MethodInfo[] methods = Puerts.Utils.GetMethodAndOverrideMethod(type, flag);

                for (int i = 0; i < methods.Length; ++i)
                {
                    MethodInfo method = methods[i];

                    MethodKey methodKey = new MethodKey {
                        Name = method.Name, IsStatic = method.IsStatic
                    };

                    if (!method.IsConstructor)
                    {
                        AddMethodToSlowBindingGroup(methodKey, method);
                    }
                }

                // extensionMethods
                // 因为内存问题与crash问题移入宏中
#if PUERTS_REFLECT_ALL_EXTENSION || UNITY_EDITOR
                IEnumerable <MethodInfo> extensionMethods = Utils.GetExtensionMethodsOf(type);
                if (extensionMethods != null)
                {
                    var enumerator = extensionMethods.GetEnumerator();
                    while (enumerator.MoveNext())
                    {
                        MethodInfo method    = enumerator.Current;
                        MethodKey  methodKey = new MethodKey {
                            Name = method.Name, IsStatic = false, IsExtension = true
                        };

                        AddMethodToSlowBindingGroup(methodKey, method);
                    }
                }
#endif

                // fields
                var fields = type.GetFields(flag);

                foreach (var field in fields)
                {
                    slowBindingFields.Add(field);
                    if (field.IsStatic && (field.IsInitOnly || field.IsLiteral))
                    {
                        readonlyStaticFields.Add(field.Name);
                    }
                }
            }
            else
            {
                // otherwise when registerInfo is not null, most of member use FastBinding, some member with IsLazyMember=true use LazyBinding

                if (registerInfo.BlittableCopy)
                {
                    typeId = PuertsDLL.RegisterStruct(jsEnv.isolate, -1, type.AssemblyQualifiedName, registerInfo.Constructor,
                                                      null, jsEnv.Idx, System.Runtime.InteropServices.Marshal.SizeOf(type));
                }
                else
                {
                    typeId = PuertsDLL.RegisterClass(jsEnv.isolate, baseTypeId, type.AssemblyQualifiedName, registerInfo.Constructor, null, jsEnv.Idx);
                }

                foreach (var kv in registerInfo.Methods)
                {
                    PuertsDLL.RegisterFunction(jsEnv.isolate, typeId, kv.Key.Name, kv.Key.IsStatic, kv.Value, jsEnv.Idx);
                    if (kv.Key.Name == "ToString" && registerInfo.BlittableCopy)
                    {
                        PuertsDLL.RegisterFunction(jsEnv.isolate, typeId, "toString", false, kv.Value, jsEnv.Idx);
                    }
                }

                foreach (var kv in registerInfo.Properties)
                {
                    PuertsDLL.RegisterProperty(jsEnv.isolate, typeId, kv.Key, kv.Value.IsStatic, kv.Value.Getter, jsEnv.Idx, kv.Value.Setter, jsEnv.Idx, !readonlyStaticFields.Contains(kv.Key));
                }

                foreach (LazyMemberRegisterInfo lazyinfo in registerInfo.LazyMembers)
                {
                    switch (lazyinfo.Type)
                    {
                    case LazyMemberType.Method:
                        LazyMethodWrap lazyMethodWrap = new LazyMethodWrap(lazyinfo.Name, jsEnv, type);
                        long           callback       = jsEnv.AddCallback(lazyMethodWrap.Invoke);
                        PuertsDLL.RegisterFunction(jsEnv.isolate, typeId, lazyinfo.Name, lazyinfo.IsStatic, callbackWrap, callback);
                        if (lazyinfo.Name == "ToString" && registerInfo.BlittableCopy)
                        {
                            PuertsDLL.RegisterFunction(jsEnv.isolate, typeId, "toString", false, callbackWrap, jsEnv.Idx);
                        }
                        break;

                    case LazyMemberType.Constructor:
                        // TODO
                        break;

                    case LazyMemberType.Field:
                        LazyFieldWrap lazyFieldWrap = new LazyFieldWrap(lazyinfo.Name, jsEnv, type);
                        PuertsDLL.RegisterProperty(
                            jsEnv.isolate, typeId, lazyinfo.Name, lazyinfo.IsStatic,
                            callbackWrap, jsEnv.AddCallback(lazyFieldWrap.InvokeGetter),
                            lazyinfo.HasSetter ? callbackWrap : null, lazyinfo.HasSetter ? jsEnv.AddCallback(lazyFieldWrap.InvokeSetter) : 0,
                            !readonlyStaticFields.Contains(lazyinfo.Name)
                            );
                        break;

                    case LazyMemberType.Property:
                        LazyPropertyWrap getterLazyPropertyWrap = new LazyPropertyWrap("get_" + lazyinfo.Name, jsEnv, type);
                        LazyPropertyWrap setterLazyPropertyWrap = new LazyPropertyWrap("set_" + lazyinfo.Name, jsEnv, type);
                        PuertsDLL.RegisterProperty(
                            jsEnv.isolate, typeId, lazyinfo.Name, lazyinfo.IsStatic,
                            lazyinfo.HasGetter ? callbackWrap : null, lazyinfo.HasGetter ? jsEnv.AddCallback(getterLazyPropertyWrap.Invoke) : 0,
                            lazyinfo.HasSetter ? callbackWrap : null, lazyinfo.HasSetter ? jsEnv.AddCallback(setterLazyPropertyWrap.Invoke) : 0,
                            true
                            );
                        break;
                    }
                }

                //if (registerInfo.LazyMethods != null)
                //{
                //    // register all the methods marked as lazy
                //    foreach (var kv in registerInfo.LazyMethods)
                //    {
                //        //TODO: change to LazyBinding instead of SlowBinding
                //        MethodKey methodKey = kv.Key;
                //        MemberInfo[] members = type.GetMember(methodKey.Name, flag);

                //        var enumerator = members.GetEnumerator();
                //        while (enumerator.MoveNext())
                //        {
                //            AddMethodToSlowBindingGroup(methodKey, (MethodInfo)enumerator.Current);
                //        }
                //    }
                //}

                //if (registerInfo.LazyProperties != null)
                //{
                //    // register all the properties marked as lazy
                //    foreach (var kv in registerInfo.LazyProperties)
                //    {
                //        //TODO: change to LazyBinding instead of SlowBinding
                //        string name = kv.Key;

                //        MethodKey getMethodKey = new MethodKey { Name = "get_" + name, IsStatic = kv.Value.IsStatic };
                //        MethodInfo getMethod = type.GetMethod(getMethodKey.Name, flag);

                //        MethodKey setMethodKey = new MethodKey { Name = "set_" + name, IsStatic = kv.Value.IsStatic };
                //        MethodInfo setMethod = type.GetMethod(getMethodKey.Name, flag);

                //        if (getMethod != null)
                //        {
                //            AddMethodToSlowBindingGroup(getMethodKey, getMethod);
                //        }
                //        if (setMethod != null)
                //        {
                //            AddMethodToSlowBindingGroup(setMethodKey, setMethod);
                //        }
                //    }
                //}
            }

            foreach (var kv in slowBindingMethodGroup)
            {
                var overloadWraps = kv.Value.Select(m => new OverloadReflectionWrap(m, jsEnv.GeneralGetterManager, jsEnv.GeneralSetterManager, kv.Key.IsExtension)).ToList();
                MethodReflectionWrap methodReflectionWrap = new MethodReflectionWrap(kv.Key.Name, overloadWraps);
                PuertsDLL.RegisterFunction(jsEnv.isolate, typeId, kv.Key.Name, kv.Key.IsStatic, callbackWrap, jsEnv.AddCallback(methodReflectionWrap.Invoke));
            }
            foreach (var kv in slowBindingProperties)
            {
                V8FunctionCallback getter = null;
                long getterData           = 0;
                bool isStatic             = false;
                if (kv.Value.Getter != null)
                {
                    getter = callbackWrap;
                    MethodReflectionWrap methodReflectionWrap = new MethodReflectionWrap(kv.Value.Getter.Name, new List <OverloadReflectionWrap>()
                    {
                        new OverloadReflectionWrap(kv.Value.Getter, jsEnv.GeneralGetterManager, jsEnv.GeneralSetterManager)
                    });
                    getterData = jsEnv.AddCallback(methodReflectionWrap.Invoke);
                    isStatic   = kv.Value.Getter.IsStatic;
                }
                V8FunctionCallback setter = null;
                long setterData           = 0;
                if (kv.Value.Setter != null)
                {
                    setter = callbackWrap;
                    MethodReflectionWrap methodReflectionWrap = new MethodReflectionWrap(kv.Value.Setter.Name, new List <OverloadReflectionWrap>()
                    {
                        new OverloadReflectionWrap(kv.Value.Setter, jsEnv.GeneralGetterManager, jsEnv.GeneralSetterManager)
                    });
                    setterData = jsEnv.AddCallback(methodReflectionWrap.Invoke);
                    isStatic   = kv.Value.Setter.IsStatic;
                }
                PuertsDLL.RegisterProperty(jsEnv.isolate, typeId, kv.Key, isStatic, getter, getterData, setter, setterData, true);
            }
            foreach (var field in slowBindingFields)
            {
                var getterData = jsEnv.AddCallback(GenFieldGetter(type, field));

                V8FunctionCallback setter = null;
                long setterData           = 0;

                if (!field.IsInitOnly && !field.IsLiteral)
                {
                    setter     = callbackWrap;
                    setterData = jsEnv.AddCallback(GenFieldSetter(type, field));
                }

                PuertsDLL.RegisterProperty(jsEnv.isolate, typeId, field.Name, field.IsStatic, callbackWrap, getterData, setter, setterData, !readonlyStaticFields.Contains(field.Name));
            }

            var translateFunc = jsEnv.GeneralSetterManager.GetTranslateFunc(typeof(Type));
            PuertsDLL.RegisterProperty(jsEnv.isolate, typeId, "__p_innerType", true, callbackWrap, jsEnv.AddCallback((IntPtr isolate1, IntPtr info, IntPtr self, int argumentsLen) =>
            {
                translateFunc(isolate1, NativeValueApi.SetValueToResult, info, type);
            }), null, 0, true);

            if (type.IsEnum)
            {
                PuertsDLL.RegisterProperty(jsEnv.isolate, typeId, "__p_isEnum", true, returnTrue, 0, null, 0, false);
            }

            return(typeId);
        }