Example #1
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;
            }

            MethodInfo[] methods = type.GetMethods(flag);
            Dictionary <MethodKey, List <MethodInfo> > methodGroup   = new Dictionary <MethodKey, List <MethodInfo> >();
            Dictionary <string, ProperyMethods>        propertyGroup = new Dictionary <string, ProperyMethods>();

            for (int i = 0; i < methods.Length; ++i)
            {
                MethodInfo method = methods[i];
                if (method.IsConstructor || method.IsGenericMethodDefinition)
                {
                    continue;
                }

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

                if (registerInfo != null && registerInfo.Methods.ContainsKey(methodKey))
                {
                    continue;
                }

                if (method.IsSpecialName && method.Name.StartsWith("get_") && method.GetParameters().Length != 1) // getter of property
                {
                    string propName = method.Name.Substring(4);
                    if (registerInfo != null && registerInfo.Properties.ContainsKey(propName))
                    {
                        continue;
                    }
                    ProperyMethods properyMethods;
                    if (!propertyGroup.TryGetValue(propName, out properyMethods))
                    {
                        properyMethods = new ProperyMethods();
                        propertyGroup.Add(propName, properyMethods);
                    }
                    properyMethods.Getter = method;
                    continue;
                }
                else if (method.IsSpecialName && method.Name.StartsWith("set_") && method.GetParameters().Length != 2) // setter of property
                {
                    string propName = method.Name.Substring(4);
                    if (registerInfo != null && registerInfo.Properties.ContainsKey(propName))
                    {
                        continue;
                    }
                    ProperyMethods properyMethods;
                    if (!propertyGroup.TryGetValue(propName, out properyMethods))
                    {
                        properyMethods = new ProperyMethods();
                        propertyGroup.Add(propName, properyMethods);
                    }
                    properyMethods.Setter = method;
                    continue;
                }

                List <MethodInfo> overloads;
                if (!methodGroup.TryGetValue(methodKey, out overloads))
                {
                    overloads = new List <MethodInfo>();
                    methodGroup.Add(methodKey, overloads);
                }
                overloads.Add(method);
            }

            ConstructorCallback constructorCallback = null;

            if (typeof(Delegate).IsAssignableFrom(type))
            {
                DelegateConstructWrap delegateConstructWrap = new DelegateConstructWrap(type, jsEnv.GeneralGetterManager);
                constructorCallback = delegateConstructWrap.Construct;
            }
            else
            {
                var constructorWraps = type.GetConstructors(flag)
                                       .Select(m => new OverloadReflectionWrap(m, jsEnv.GeneralGetterManager, jsEnv.GeneralSetterManager)).ToList();
                MethodReflectionWrap constructorReflectionWrap = new MethodReflectionWrap(".ctor", constructorWraps);
                constructorCallback = constructorReflectionWrap.Construct;
            }

            int baseTypeId = -1;

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

            int typeId = -1;

            if (registerInfo == null)
            {
                typeId = PuertsDLL.RegisterClass(jsEnv.isolate, baseTypeId, type.AssemblyQualifiedName, constructorWrap, null, jsEnv.AddConstructor(constructorCallback));
            }
            else
            {
                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);
                }

                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);
                }
            }

            //int typeId = PuertsDLL.RegisterClass(jsEngine, type.AssemblyQualifiedName, null, null, Utils.TwoIntToLong(idx, 0));

            foreach (var kv in methodGroup)
            {
                MethodReflectionWrap methodReflectionWrap = new MethodReflectionWrap(kv.Key.Name, kv.Value.Select(m => new OverloadReflectionWrap(m, jsEnv.GeneralGetterManager, jsEnv.GeneralSetterManager)).ToList());
                PuertsDLL.RegisterFunction(jsEnv.isolate, typeId, kv.Key.Name, kv.Key.IsStatic, callbackWrap, jsEnv.AddCallback(methodReflectionWrap.Invoke));
            }

            foreach (var kv in propertyGroup)
            {
                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);
            }

            foreach (var field in type.GetFields(flag))
            {
                if (registerInfo != null && registerInfo.Properties.ContainsKey(field.Name))
                {
                    continue;
                }
                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);
            }

            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);

            return(typeId);
        }
Example #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>();

            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
                ConstructorCallback 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));
                }

                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 wraps = kv.Value.Select(m => new OverloadReflectionWrap(m, jsEnv.GeneralGetterManager, jsEnv.GeneralSetterManager, kv.Key.IsExtension)).ToList();
                MethodReflectionWrap methodReflectionWrap = new MethodReflectionWrap(kv.Key.Name, wraps);
                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);
        }