internal long AddConstructor(JSConstructorCallback callback) { int callbackIdx = constructorCallbacks.Count; constructorCallbacks.Add(callback); return(Utils.TwoIntToLong(Idx, callbackIdx)); }
// #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); }