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