Exemple #1
0
        private static void EmitPointerToObjectGeneric(ILProcessor body, TypeReference originalReturnType,
                                                       TypeReference newReturnType,
                                                       TypeRewriteContext enclosingType, Instruction loadPointer, bool extraDerefForNonValueTypes,
                                                       bool unboxValueType)
        {
            var imports = enclosingType.AssemblyContext.Imports;

            body.Append(loadPointer);

            body.Emit(extraDerefForNonValueTypes ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
            body.Emit(unboxValueType ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
            body.Emit(OpCodes.Call, imports.Module.ImportReference(new GenericInstanceMethod(imports.Il2CppPointerToGeneric)
            {
                GenericArguments = { newReturnType }
            }));
        }
Exemple #2
0
        private static void EmitObjectToPointerGeneric(ILProcessor body, TypeReference originalType,
                                                       TypeReference newType, TypeRewriteContext enclosingType, int argumentIndex,
                                                       bool valueTypeArgument0IsAPointer, bool allowNullable, bool unboxNonBlittableType)
        {
            var imports = enclosingType.AssemblyContext.Imports;

            body.Emit(OpCodes.Ldtoken, newType);
            body.Emit(OpCodes.Call, enclosingType.NewType.Module.ImportReference(imports.Type.Methods.Single(it => it.Name == nameof(Type.GetTypeFromHandle))));
            body.Emit(OpCodes.Callvirt, enclosingType.NewType.Module.ImportReference(imports.Type.Methods.Single(it => it.Name == typeof(Type).GetProperty(nameof(Type.IsValueType)) !.GetMethod !.Name)));

            var finalNop     = body.Create(OpCodes.Nop);
            var valueTypeNop = body.Create(OpCodes.Nop);
            var stringNop    = body.Create(OpCodes.Nop);

            body.Emit(OpCodes.Brtrue, valueTypeNop);

            body.Emit(OpCodes.Ldarg, argumentIndex);
            body.Emit(OpCodes.Box, newType);
            body.Emit(OpCodes.Dup);
            body.Emit(OpCodes.Isinst, imports.String);
            body.Emit(OpCodes.Brtrue_S, stringNop);

            body.Emit(OpCodes.Isinst, imports.Il2CppObjectBase);
            body.Emit(OpCodes.Call, allowNullable ? imports.Il2CppObjectBaseToPointer : imports.Il2CppObjectBaseToPointerNotNull);
            if (unboxNonBlittableType)
            {
                body.Emit(OpCodes.Dup);
                body.Emit(OpCodes.Brfalse_S, finalNop); // return null immediately
                body.Emit(OpCodes.Dup);
                body.Emit(OpCodes.Call, imports.ObjectGetClass);
                body.Emit(OpCodes.Call, imports.ClassIsValueType);
                body.Emit(OpCodes.Brfalse_S, finalNop); // return reference types immediately
                body.Emit(OpCodes.Call, imports.ObjectUnbox);
            }

            body.Emit(OpCodes.Br, finalNop);

            body.Append(stringNop);
            body.Emit(OpCodes.Isinst, imports.String);
            body.Emit(OpCodes.Call, imports.StringToNative);
            body.Emit(OpCodes.Br_S, finalNop);

            body.Append(valueTypeNop);
            body.Emit(OpCodes.Ldarga, argumentIndex);

            body.Append(finalNop);
        }
Exemple #3
0
        private static void ComputeSpecifics(TypeRewriteContext typeContext)
        {
            if (typeContext.ComputedTypeSpecifics != TypeRewriteContext.TypeSpecifics.NotComputed)
            {
                return;
            }
            typeContext.ComputedTypeSpecifics = TypeRewriteContext.TypeSpecifics.Computing;

            foreach (var originalField in typeContext.OriginalType.Fields)
            {
                if (originalField.IsStatic)
                {
                    continue;
                }

                var fieldType = originalField.FieldType;
                if (fieldType.IsPrimitive || fieldType.IsPointer)
                {
                    continue;
                }
                if (fieldType.FullName == "System.String" || fieldType.FullName == "System.Object" || fieldType.IsArray || fieldType.IsByReference || fieldType.IsGenericParameter || fieldType.IsGenericInstance)
                {
                    typeContext.ComputedTypeSpecifics = TypeRewriteContext.TypeSpecifics.NonBlittableStruct;
                    return;
                }

                var fieldTypeContext = typeContext.AssemblyContext.GlobalContext.GetNewTypeForOriginal(fieldType.Resolve());
                ComputeSpecifics(fieldTypeContext);
                if (fieldTypeContext.ComputedTypeSpecifics != TypeRewriteContext.TypeSpecifics.BlittableStruct)
                {
                    typeContext.ComputedTypeSpecifics = TypeRewriteContext.TypeSpecifics.NonBlittableStruct;
                    return;
                }
            }

            typeContext.ComputedTypeSpecifics = TypeRewriteContext.TypeSpecifics.BlittableStruct;
        }
        private static void GenerateStaticProxy(AssemblyRewriteContext assemblyContext, TypeRewriteContext typeContext)
        {
            var oldType = typeContext.OriginalType;
            var newType = typeContext.NewType;

            if (oldType.IsEnum)
            {
                return;
            }

            var staticCtorMethod = new MethodDefinition(".cctor",
                                                        MethodAttributes.Static | MethodAttributes.Private | MethodAttributes.SpecialName |
                                                        MethodAttributes.HideBySig | MethodAttributes.RTSpecialName, assemblyContext.Imports.Void);

            newType.Methods.Add(staticCtorMethod);

            var ctorBuilder = staticCtorMethod.Body.GetILProcessor();

            if (newType.IsNested)
            {
                ctorBuilder.Emit(OpCodes.Ldsfld, assemblyContext.GlobalContext.GetNewTypeForOriginal(oldType.DeclaringType).ClassPointerFieldRef);
                ctorBuilder.Emit(OpCodes.Ldstr, oldType.Name);
                ctorBuilder.Emit(OpCodes.Call, assemblyContext.Imports.GetIl2CppNestedClass);
            }
            else
            {
                ctorBuilder.Emit(OpCodes.Ldstr, oldType.Module.Name);
                ctorBuilder.Emit(OpCodes.Ldstr, oldType.Namespace);
                ctorBuilder.Emit(OpCodes.Ldstr, oldType.Name);
                ctorBuilder.Emit(OpCodes.Call, assemblyContext.Imports.GetIl2CppGlobalClass);
            }

            if (oldType.HasGenericParameters)
            {
                var il2CppTypeTypeRewriteContext = assemblyContext.GlobalContext.GetAssemblyByName("mscorlib").GetTypeByName("System.Type");
                var il2CppSystemTypeRef          = newType.Module.ImportReference(il2CppTypeTypeRewriteContext.NewType);

                var il2CppTypeHandleTypeRewriteContext = assemblyContext.GlobalContext.GetAssemblyByName("mscorlib").GetTypeByName("System.RuntimeTypeHandle");
                var il2CppSystemTypeHandleRef          = newType.Module.ImportReference(il2CppTypeHandleTypeRewriteContext.NewType);

                ctorBuilder.Emit(OpCodes.Call, assemblyContext.Imports.GetIl2CppTypeFromClass);
                ctorBuilder.Emit(OpCodes.Call, new MethodReference("internal_from_handle", il2CppSystemTypeRef, il2CppSystemTypeRef)
                {
                    Parameters = { new ParameterDefinition(assemblyContext.Imports.IntPtr) }
                });

                ctorBuilder.EmitLdcI4(oldType.GenericParameters.Count);

                ctorBuilder.Emit(OpCodes.Newarr, il2CppSystemTypeRef);

                for (var i = 0; i < oldType.GenericParameters.Count; i++)
                {
                    ctorBuilder.Emit(OpCodes.Dup);
                    ctorBuilder.EmitLdcI4(i);

                    var param    = oldType.GenericParameters[i];
                    var storeRef = new GenericInstanceType(assemblyContext.Imports.Il2CppClassPointerStore)
                    {
                        GenericArguments = { param }
                    };
                    var fieldRef = new FieldReference(nameof(Il2CppClassPointerStore <object> .NativeClassPtr), assemblyContext.Imports.IntPtr, storeRef);
                    ctorBuilder.Emit(OpCodes.Ldsfld, fieldRef);

                    ctorBuilder.Emit(OpCodes.Call, assemblyContext.Imports.GetIl2CppTypeFromClass);

                    ctorBuilder.Emit(OpCodes.Call, new MethodReference("internal_from_handle", il2CppSystemTypeRef, il2CppSystemTypeRef)
                    {
                        Parameters = { new ParameterDefinition(assemblyContext.Imports.IntPtr) }
                    });
                    ctorBuilder.Emit(OpCodes.Stelem_Ref);
                }

                var il2CppTypeArray = new GenericInstanceType(assemblyContext.Imports.Il2CppReferenceArray)
                {
                    GenericArguments = { il2CppSystemTypeRef }
                };
                ctorBuilder.Emit(OpCodes.Newobj, new MethodReference(".ctor", assemblyContext.Imports.Void, il2CppTypeArray)
                {
                    HasThis = true, Parameters = { new ParameterDefinition(new ArrayType(assemblyContext.Imports.Il2CppReferenceArray.GenericParameters[0])) }
                });
                ctorBuilder.Emit(OpCodes.Call, new MethodReference(nameof(Type.MakeGenericType), il2CppSystemTypeRef, il2CppSystemTypeRef)
                {
                    HasThis = true, Parameters = { new ParameterDefinition(il2CppTypeArray) }
                });

                ctorBuilder.Emit(OpCodes.Call, new MethodReference(typeof(Type).GetProperty(nameof(Type.TypeHandle)) !.GetMethod !.Name, il2CppSystemTypeHandleRef, il2CppSystemTypeRef)
                {
                    HasThis = true
                });
        private static (TypeRewriteContext?, int) FindBestMatchType(TypeRewriteContext obfType, AssemblyRewriteContext cleanAssembly, TypeRewriteContext?enclosingCleanType)
        {
            var inheritanceDepthOfOriginal = 0;
            var currentBase = obfType.OriginalType.BaseType;

            while (true)
            {
                if (currentBase == null)
                {
                    break;
                }
                var currentBaseContext = obfType.AssemblyContext.GlobalContext.TryGetNewTypeForOriginal(currentBase.Resolve());
                if (currentBaseContext == null || !currentBaseContext.OriginalNameWasObfuscated)
                {
                    break;
                }

                inheritanceDepthOfOriginal++;
                currentBase = currentBaseContext.OriginalType.BaseType;
            }

            var bestPenalty = int.MinValue;
            TypeRewriteContext?bestMatch = null;

            var source = enclosingCleanType?.OriginalType.NestedTypes.Select(it => cleanAssembly.GlobalContext.GetNewTypeForOriginal(it)) ??
                         cleanAssembly.Types.Where(it => it.NewType.DeclaringType == null);

            foreach (var candidateCleanType in source)
            {
                if (obfType.OriginalType.HasMethods != candidateCleanType.OriginalType.HasMethods)
                {
                    continue;
                }

                if (obfType.OriginalType.HasFields != candidateCleanType.OriginalType.HasFields)
                {
                    continue;
                }

                if (obfType.OriginalType.IsEnum)
                {
                    if (obfType.OriginalType.Fields.Count != candidateCleanType.OriginalType.Fields.Count)
                    {
                        continue;
                    }
                }

                int currentPenalty = 0;

                var tryBase         = candidateCleanType.OriginalType.BaseType;
                var actualBaseDepth = 0;
                while (tryBase != null)
                {
                    if (tryBase?.Name == currentBase?.Name && tryBase?.Namespace == currentBase?.Namespace)
                    {
                        break;
                    }

                    tryBase = tryBase?.Resolve().BaseType;
                    actualBaseDepth++;
                }

                if (tryBase == null && currentBase != null)
                {
                    continue;
                }

                var baseDepthDifference = Math.Abs(actualBaseDepth - inheritanceDepthOfOriginal);
                if (baseDepthDifference > 1)
                {
                    continue;                         // heuristic optimization
                }
                currentPenalty -= baseDepthDifference * 50;

                currentPenalty -= Math.Abs(candidateCleanType.OriginalType.Fields.Count - obfType.OriginalType.Fields.Count) * 5;

                currentPenalty -= Math.Abs(obfType.OriginalType.NestedTypes.Count - candidateCleanType.OriginalType.NestedTypes.Count) * 10;

                currentPenalty -= Math.Abs(obfType.OriginalType.Properties.Count - candidateCleanType.OriginalType.Properties.Count) * 5;

                currentPenalty -= Math.Abs(obfType.OriginalType.Interfaces.Count - candidateCleanType.OriginalType.Interfaces.Count) * 35;

                var options = obfType.AssemblyContext.GlobalContext.Options;

                foreach (var obfuscatedField in obfType.OriginalType.Fields)
                {
                    if (obfuscatedField.Name.IsObfuscated(options))
                    {
                        var bestFieldScore = candidateCleanType.OriginalType.Fields.Max(it => TypeMatchWeight(obfuscatedField.FieldType, it.FieldType, options));
                        currentPenalty += bestFieldScore * (bestFieldScore < 0 ? 10 : 2);
                        continue;
                    }

                    if (candidateCleanType.OriginalType.Fields.Any(it => it.Name == obfuscatedField.Name))
                    {
                        currentPenalty += 10;
                    }
                }

                foreach (var obfuscatedMethod in obfType.OriginalType.Methods)
                {
                    if (obfuscatedMethod.Name.Contains(".ctor"))
                    {
                        continue;
                    }

                    if (obfuscatedMethod.Name.IsObfuscated(options))
                    {
                        var bestMethodScore = candidateCleanType.OriginalType.Methods.Max(it => MethodSignatureMatchWeight(obfuscatedMethod, it, options));
                        currentPenalty += bestMethodScore * (bestMethodScore < 0 ? 10 : 1);

                        continue;
                    }

                    if (candidateCleanType.OriginalType.Methods.Any(it => it.Name == obfuscatedMethod.Name))
                    {
                        currentPenalty += obfuscatedMethod.Name.Length / 10 * 5 + 1;
                    }
                }

                if (currentPenalty == bestPenalty)
                {
                    bestMatch = null;
                }
                else if (currentPenalty > bestPenalty)
                {
                    bestPenalty = currentPenalty;
                    bestMatch   = candidateCleanType;
                }
            }

            // if (bestPenalty < -100)
            // bestMatch = null;

            return(bestMatch, bestPenalty);
        }
        public static bool TranslateMethod(MethodDefinition original, MethodDefinition target, TypeRewriteContext typeRewriteContext, AssemblyKnownImports imports)
        {
            if (!original.HasBody)
            {
                return(true);
            }

            var globalContext = typeRewriteContext.AssemblyContext.GlobalContext;

            foreach (var variableDefinition in original.Body.Variables)
            {
                var variableType = Pass80UnstripMethods.ResolveTypeInNewAssemblies(globalContext, variableDefinition.VariableType, imports);
                if (variableType == null)
                {
                    return(false);
                }
                target.Body.Variables.Add(new VariableDefinition(variableType));
            }

            var targetBuilder = target.Body.GetILProcessor();

            foreach (var bodyInstruction in original.Body.Instructions)
            {
                if (bodyInstruction.OpCode.OperandType == OperandType.InlineField)
                {
                    var fieldArg      = (FieldReference)bodyInstruction.Operand;
                    var fieldDeclarer = Pass80UnstripMethods.ResolveTypeInNewAssembliesRaw(globalContext, fieldArg.DeclaringType, imports);
                    if (fieldDeclarer == null)
                    {
                        return(false);
                    }
                    var newField = fieldDeclarer.Resolve().Fields.SingleOrDefault(it => it.Name == fieldArg.Name);
                    if (newField != null)
                    {
                        targetBuilder.Emit(bodyInstruction.OpCode, imports.Module.ImportReference(newField));
                    }
                    else
                    {
                        if (bodyInstruction.OpCode == OpCodes.Ldfld || bodyInstruction.OpCode == OpCodes.Ldsfld)
                        {
                            var getterMethod = fieldDeclarer.Resolve().Properties.SingleOrDefault(it => it.Name == fieldArg.Name)?.GetMethod;
                            if (getterMethod == null)
                            {
                                return(false);
                            }

                            targetBuilder.Emit(OpCodes.Call, imports.Module.ImportReference(getterMethod));
                        }
                        else if (bodyInstruction.OpCode == OpCodes.Stfld || bodyInstruction.OpCode == OpCodes.Stsfld)
                        {
                            var setterMethod = fieldDeclarer.Resolve().Properties.SingleOrDefault(it => it.Name == fieldArg.Name)?.SetMethod;
                            if (setterMethod == null)
                            {
                                return(false);
                            }

                            targetBuilder.Emit(OpCodes.Call, imports.Module.ImportReference(setterMethod));
                        }
                        else
                        {
                            return(false);
                        }
                    }
                }
                else if (bodyInstruction.OpCode.OperandType == OperandType.InlineMethod)
                {
                    var methodArg      = (MethodReference)bodyInstruction.Operand;
                    var methodDeclarer = Pass80UnstripMethods.ResolveTypeInNewAssemblies(globalContext, methodArg.DeclaringType, imports);
                    if (methodDeclarer == null)
                    {
                        return(false);                        // todo: generic methods
                    }
                    var newReturnType = Pass80UnstripMethods.ResolveTypeInNewAssemblies(globalContext, methodArg.ReturnType, imports);
                    if (newReturnType == null)
                    {
                        return(false);
                    }

                    var newMethod = new MethodReference(methodArg.Name, newReturnType, methodDeclarer);
                    newMethod.HasThis = methodArg.HasThis;
                    foreach (var methodArgParameter in methodArg.Parameters)
                    {
                        var newParamType = Pass80UnstripMethods.ResolveTypeInNewAssemblies(globalContext, methodArgParameter.ParameterType, imports);
                        if (newParamType == null)
                        {
                            return(false);
                        }

                        var newParam = new ParameterDefinition(methodArgParameter.Name, methodArgParameter.Attributes, newParamType);
                        newMethod.Parameters.Add(newParam);
                    }

                    targetBuilder.Emit(bodyInstruction.OpCode, imports.Module.ImportReference(newMethod));
                }
                else if (bodyInstruction.OpCode.OperandType == OperandType.InlineType)
                {
                    var targetType = (TypeReference)bodyInstruction.Operand;
                    if (targetType is GenericParameter genericParam)
                    {
                        if (genericParam.Owner is TypeReference paramOwner)
                        {
                            var newTypeOwner = Pass80UnstripMethods.ResolveTypeInNewAssemblies(globalContext, paramOwner, imports);
                            if (newTypeOwner == null)
                            {
                                return(false);
                            }
                            targetType = newTypeOwner.GenericParameters.Single(it => it.Name == targetType.Name);
                        }
                        else
                        {
                            targetType = target.GenericParameters.Single(it => it.Name == targetType.Name);
                        }
                    }
                    else
                    {
                        targetType = Pass80UnstripMethods.ResolveTypeInNewAssemblies(globalContext, targetType, imports);
                        if (targetType == null)
                        {
                            return(false);
                        }
                    }

                    if (bodyInstruction.OpCode == OpCodes.Castclass && !targetType.IsValueType)
                    {
                        targetBuilder.Emit(OpCodes.Call, imports.Module.ImportReference(new GenericInstanceMethod(imports.Il2CppObjectCast)
                        {
                            GenericArguments = { targetType }
                        }));
                    }
                    else if (bodyInstruction.OpCode == OpCodes.Isinst && !targetType.IsValueType)
                    {
                        targetBuilder.Emit(OpCodes.Call, imports.Module.ImportReference(new GenericInstanceMethod(imports.Il2CppObjectTryCast)
                        {
                            GenericArguments = { targetType }
                        }));
                    }
                    else
                    {
                        targetBuilder.Emit(bodyInstruction.OpCode, targetType);
                    }
                }
                else if (bodyInstruction.OpCode.OperandType == OperandType.InlineSig)
                {
                    // todo: rewrite sig if this ever happens in unity types
                    return(false);
                }
                else if (bodyInstruction.OpCode.OperandType == OperandType.InlineTok)
                {
                    var targetTok = (TypeReference)bodyInstruction.Operand;
                    if (targetTok is GenericParameter genericParam)
                    {
                        if (genericParam.Owner is TypeReference paramOwner)
                        {
                            var newTypeOwner = Pass80UnstripMethods.ResolveTypeInNewAssemblies(globalContext, paramOwner, imports);
                            if (newTypeOwner == null)
                            {
                                return(false);
                            }
                            targetTok = newTypeOwner.GenericParameters.Single(it => it.Name == targetTok.Name);
                        }
                        else
                        {
                            targetTok = target.GenericParameters.Single(it => it.Name == targetTok.Name);
                        }
                    }
                    else
                    {
                        targetTok = Pass80UnstripMethods.ResolveTypeInNewAssemblies(globalContext, targetTok, imports);
                        if (targetTok == null)
                        {
                            return(false);
                        }
                    }

                    targetBuilder.Emit(OpCodes.Call, imports.Module.ImportReference(new GenericInstanceMethod(imports.LdTokUnstrippedImpl)
                    {
                        GenericArguments = { targetTok }
                    }));
                }
                else
                {
                    targetBuilder.Append(bodyInstruction);
                }
            }

            return(true);
        }
Exemple #7
0
        private static void EmitObjectStoreGeneric(ILProcessor body, TypeReference originalType, TypeReference newType, TypeRewriteContext enclosingType, int argumentIndex)
        {
            // input stack: target address
            // output: nothing

            var imports = enclosingType.AssemblyContext.Imports;

            body.Emit(OpCodes.Ldtoken, newType);
            body.Emit(OpCodes.Call, enclosingType.NewType.Module.ImportReference(imports.Type.Methods.Single(it => it.Name == nameof(Type.GetTypeFromHandle))));
            body.Emit(OpCodes.Dup);
            body.Emit(OpCodes.Callvirt, enclosingType.NewType.Module.ImportReference(imports.Type.Methods.Single(it => it.Name == typeof(Type).GetProperty(nameof(Type.IsValueType)) !.GetMethod !.Name)));

            var finalNop        = body.Create(OpCodes.Nop);
            var stringNop       = body.Create(OpCodes.Nop);
            var valueTypeNop    = body.Create(OpCodes.Nop);
            var storePointerNop = body.Create(OpCodes.Nop);

            body.Emit(OpCodes.Brtrue, valueTypeNop);

            body.Emit(OpCodes.Callvirt, enclosingType.NewType.Module.ImportReference(imports.Type.Methods.Single(it => it.Name == typeof(Type).GetProperty(nameof(Type.FullName)) !.GetMethod !.Name)));
            body.Emit(OpCodes.Ldstr, "System.String");
            body.Emit(OpCodes.Call, enclosingType.NewType.Module.ImportReference(TargetTypeSystemHandler.String.Methods.Single(it => it.Name == nameof(String.Equals) && it.IsStatic && it.Parameters.Count == 2)));
            body.Emit(OpCodes.Brtrue_S, stringNop);

            body.Emit(OpCodes.Ldarg, argumentIndex);
            body.Emit(OpCodes.Box, newType);
            body.Emit(OpCodes.Isinst, imports.Il2CppObjectBase);
            body.Emit(OpCodes.Call, imports.Il2CppObjectBaseToPointer);
            body.Emit(OpCodes.Dup);
            body.Emit(OpCodes.Brfalse_S, storePointerNop);

            body.Emit(OpCodes.Dup);
            body.Emit(OpCodes.Call, imports.ObjectGetClass);
            body.Emit(OpCodes.Call, imports.ClassIsValueType);
            body.Emit(OpCodes.Brfalse_S, storePointerNop);

            body.Emit(OpCodes.Dup);
            var tempLocal = new VariableDefinition(imports.IntPtr);

            body.Body.Variables.Add(tempLocal);
            body.Emit(OpCodes.Stloc, tempLocal);
            body.Emit(OpCodes.Call, imports.ObjectUnbox);
            body.Emit(OpCodes.Ldloc, tempLocal);
            body.Emit(OpCodes.Call, imports.ObjectGetClass);
            body.Emit(OpCodes.Ldc_I4_0);
            body.Emit(OpCodes.Conv_U);
            body.Emit(OpCodes.Call, imports.ValueSizeGet);
            body.Emit(OpCodes.Cpblk);
            body.Emit(OpCodes.Br_S, finalNop);

            body.Append(storePointerNop);
            body.Emit(OpCodes.Stind_I);
            body.Emit(OpCodes.Br_S, finalNop);

            body.Append(stringNop);
            body.Emit(OpCodes.Ldarg, argumentIndex);
            body.Emit(OpCodes.Box, newType);
            body.Emit(OpCodes.Isinst, imports.String);
            body.Emit(OpCodes.Call, imports.StringToNative);
            body.Emit(OpCodes.Stind_I);
            body.Emit(OpCodes.Br_S, finalNop);

            body.Append(valueTypeNop);
            body.Emit(OpCodes.Pop); // pop extra typeof(T)
            body.Emit(OpCodes.Ldarg, argumentIndex);
            body.Emit(OpCodes.Stobj, newType);

            body.Append(finalNop);
        }
Exemple #8
0
        public static void EmitObjectStore(this ILProcessor body, TypeReference originalType, TypeReference newType, TypeRewriteContext enclosingType, int argumentIndex)
        {
            // input stack: target address
            // output: nothing
            if (originalType is GenericParameter)
            {
                EmitObjectStoreGeneric(body, originalType, newType, enclosingType, argumentIndex);
                return;
            }

            var imports = enclosingType.AssemblyContext.Imports;

            if (originalType.FullName == "System.String")
            {
                body.Emit(OpCodes.Ldarg, argumentIndex);
                body.Emit(OpCodes.Call, imports.StringToNative);
                body.Emit(OpCodes.Stobj, imports.IntPtr);
            }
            else if (originalType.IsValueType)
            {
                var typeSpecifics = enclosingType.AssemblyContext.GlobalContext.JudgeSpecificsByOriginalType(originalType);
                if (typeSpecifics == TypeRewriteContext.TypeSpecifics.BlittableStruct)
                {
                    body.Emit(OpCodes.Ldarg, argumentIndex);
                    body.Emit(OpCodes.Stobj, newType);
                }
                else
                {
                    body.Emit(OpCodes.Ldarg, argumentIndex);
                    body.Emit(OpCodes.Call, imports.Il2CppObjectBaseToPointer);
                    body.Emit(OpCodes.Call, imports.ObjectUnbox);
                    var classPointerTypeRef = new GenericInstanceType(imports.Il2CppClassPointerStore)
                    {
                        GenericArguments = { newType }
                    };
                    var classPointerFieldRef = new FieldReference(nameof(Il2CppClassPointerStore <int> .NativeClassPtr), imports.IntPtr, classPointerTypeRef);
                    body.Emit(OpCodes.Ldsfld, enclosingType.NewType.Module.ImportReference(classPointerFieldRef));
                    body.Emit(OpCodes.Ldc_I4_0);
                    body.Emit(OpCodes.Call, imports.ValueSizeGet);
                    body.Emit(OpCodes.Cpblk);
                }
            }
            else
            {
                body.Emit(OpCodes.Ldarg, argumentIndex);
                body.Emit(OpCodes.Call, imports.Il2CppObjectBaseToPointer);
                body.Emit(OpCodes.Stobj, imports.IntPtr);
            }
        }
Exemple #9
0
        private static void EmitPointerToObjectGeneric(ILProcessor body, TypeReference originalReturnType,
                                                       TypeReference newReturnType,
                                                       TypeRewriteContext enclosingType, Instruction loadPointer, bool extraDerefForNonValueTypes,
                                                       bool unboxValueType)
        {
            var imports = enclosingType.AssemblyContext.Imports;

            body.Append(loadPointer);

            body.Emit(OpCodes.Ldtoken, newReturnType);
            body.Emit(OpCodes.Call, enclosingType.NewType.Module.ImportReference(imports.Type.Methods.Single(it => it.Name == nameof(Type.GetTypeFromHandle))));
            body.Emit(OpCodes.Dup);
            body.Emit(OpCodes.Callvirt, enclosingType.NewType.Module.ImportReference(imports.Type.Methods.Single(it => it.Name == typeof(Type).GetProperty(nameof(Type.IsValueType)) !.GetMethod !.Name)));

            var finalNop         = body.Create(OpCodes.Nop);
            var valueTypeNop     = body.Create(OpCodes.Nop);
            var stringNop        = body.Create(OpCodes.Nop);
            var normalRefTypeNop = body.Create(OpCodes.Nop);

            body.Emit(OpCodes.Brtrue, valueTypeNop);

            body.Emit(OpCodes.Callvirt, enclosingType.NewType.Module.ImportReference(imports.Type.Methods.Single(it => it.Name == typeof(Type).GetProperty(nameof(Type.FullName)) !.GetMethod !.Name)));
            body.Emit(OpCodes.Ldstr, "System.String");
            body.Emit(OpCodes.Call, enclosingType.NewType.Module.ImportReference(TargetTypeSystemHandler.String.Methods.Single(it => it.Name == nameof(String.Equals) && it.IsStatic && it.Parameters.Count == 2)));
            body.Emit(OpCodes.Brtrue_S, stringNop);

            if (!unboxValueType)
            {
                var loadClassPointer = body.Create(OpCodes.Ldsfld,
                                                   new FieldReference(nameof(Il2CppClassPointerStore <int> .NativeClassPtr), imports.IntPtr,
                                                                      enclosingType.NewType.Module.ImportReference(
                                                                          new GenericInstanceType(imports.Il2CppClassPointerStore)
                {
                    GenericArguments = { newReturnType }
                })));

                body.Append(loadClassPointer);
                body.Emit(OpCodes.Call, imports.ClassIsValueType);
                body.Emit(OpCodes.Brfalse, normalRefTypeNop);

                body.Emit(OpCodes.Pop); // pop object pointer
                body.Append(loadClassPointer);
                body.Append(loadPointer);
                body.Emit(OpCodes.Call, imports.ObjectBox);

                body.Append(normalRefTypeNop);
            }

            var createRealObject = body.Create(OpCodes.Newobj,
                                               new MethodReference(".ctor", imports.Void, imports.Il2CppObjectBase)
            {
                Parameters = { new ParameterDefinition(imports.IntPtr) }, HasThis = true
            });

            if (extraDerefForNonValueTypes)
            {
                body.Emit(OpCodes.Ldind_I);
            }
            body.Emit(OpCodes.Dup);
            body.Emit(OpCodes.Brtrue_S, createRealObject);
            body.Emit(OpCodes.Pop);
            body.Emit(OpCodes.Ldnull);
            body.Emit(OpCodes.Br, finalNop);

            body.Append(createRealObject);
            body.Emit(OpCodes.Call, enclosingType.NewType.Module.ImportReference(new GenericInstanceMethod(imports.Il2CppObjectCast)
            {
                GenericArguments = { newReturnType }
            }));
            body.Emit(OpCodes.Br, finalNop);

            body.Append(stringNop);
            if (extraDerefForNonValueTypes)
            {
                body.Emit(OpCodes.Ldind_I);
            }
            body.Emit(OpCodes.Call, imports.StringFromNative);
            body.Emit(OpCodes.Isinst, newReturnType); // satisfy the verifier
            body.Emit(OpCodes.Br_S, finalNop);

            body.Append(valueTypeNop);
            body.Emit(OpCodes.Pop); // pop extra typeof(T)
            if (unboxValueType)
            {
                body.Emit(OpCodes.Call, imports.ObjectUnbox);
            }
            body.Emit(OpCodes.Ldobj, newReturnType);

            body.Append(finalNop);
        }
Exemple #10
0
        public static void EmitPointerToObject(this ILProcessor body, TypeReference originalReturnType, TypeReference convertedReturnType, TypeRewriteContext enclosingType, Instruction loadPointer, bool extraDerefForNonValueTypes, bool unboxValueType)
        {
            // input stack: not used
            // output stack: converted result

            if (originalReturnType is GenericParameter)
            {
                EmitPointerToObjectGeneric(body, originalReturnType, convertedReturnType, enclosingType, loadPointer, extraDerefForNonValueTypes, unboxValueType);
                return;
            }

            var imports = enclosingType.AssemblyContext.Imports;

            if (originalReturnType.FullName == "System.Void")
            {
                // do nothing
            }
            else if (originalReturnType.IsValueType)
            {
                if (convertedReturnType.IsValueType)
                {
                    body.Append(loadPointer);
                    if (unboxValueType)
                    {
                        body.Emit(OpCodes.Call, imports.ObjectUnbox);
                    }
                    body.Emit(OpCodes.Ldobj, convertedReturnType);
                }
                else
                {
                    if (!unboxValueType)
                    {
                        var classPointerTypeRef = new GenericInstanceType(imports.Il2CppClassPointerStore)
                        {
                            GenericArguments = { convertedReturnType }
                        };
                        var classPointerFieldRef =
                            new FieldReference(nameof(Il2CppClassPointerStore <int> .NativeClassPtr), imports.IntPtr,
                                               classPointerTypeRef);
                        body.Emit(OpCodes.Ldsfld, enclosingType.NewType.Module.ImportReference(classPointerFieldRef));
                        body.Append(loadPointer);
                        body.Emit(OpCodes.Call, imports.ObjectBox);
                    }
                    else // already boxed
                    {
                        body.Append(loadPointer);
                    }

                    body.Emit(OpCodes.Newobj,
                              new MethodReference(".ctor", imports.Void, convertedReturnType)
                    {
                        Parameters = { new ParameterDefinition(imports.IntPtr) }, HasThis = true
                    });
                }
            }
            else if (originalReturnType.FullName == "System.String")
            {
                body.Append(loadPointer);
                if (extraDerefForNonValueTypes)
                {
                    body.Emit(OpCodes.Ldind_I);
                }
                body.Emit(OpCodes.Call, imports.StringFromNative);
            }
            else if (originalReturnType.IsArray && originalReturnType.GetElementType().IsGenericParameter)
            {
                body.Append(loadPointer);
                var actualReturnType = imports.Il2CppArrayBaseSelfSubst;
                var methodRef        = new MethodReference(nameof(Il2CppArrayBase <int> .WrapNativeGenericArrayPointer),
                                                           actualReturnType,
                                                           convertedReturnType)
                {
                    HasThis = false, Parameters = { new ParameterDefinition(imports.IntPtr) }
                };
                body.Emit(OpCodes.Call, methodRef);
            }
            else
            {
                var createRealObject = body.Create(OpCodes.Newobj,
                                                   new MethodReference(".ctor", imports.Void, convertedReturnType)
                {
                    Parameters = { new ParameterDefinition(imports.IntPtr) }, HasThis = true
                });
                var endNop = body.Create(OpCodes.Nop);

                body.Append(loadPointer);
                if (extraDerefForNonValueTypes)
                {
                    body.Emit(OpCodes.Ldind_I);
                }
                body.Emit(OpCodes.Dup);
                body.Emit(OpCodes.Brtrue_S, createRealObject);
                body.Emit(OpCodes.Pop);
                body.Emit(OpCodes.Ldnull);
                body.Emit(OpCodes.Br, endNop);

                body.Append(createRealObject);
                body.Append(endNop);
            }
        }
Exemple #11
0
        public static void EmitObjectToPointer(this ILProcessor body, TypeReference originalType, TypeReference newType, TypeRewriteContext enclosingType, int argumentIndex, bool valueTypeArgument0IsAPointer, bool allowNullable, bool unboxNonBlittableType, out VariableDefinition refVariable)
        {
            // input stack: not used
            // output stack: IntPtr to either Il2CppObject or IL2CPP value type
            refVariable = null;

            if (originalType is GenericParameter)
            {
                EmitObjectToPointerGeneric(body, originalType, newType, enclosingType, argumentIndex, valueTypeArgument0IsAPointer, allowNullable, unboxNonBlittableType);
                return;
            }

            var imports = enclosingType.AssemblyContext.Imports;

            if (originalType is ByReferenceType)
            {
                if (newType.GetElementType().IsValueType)
                {
                    body.Emit(OpCodes.Ldarg, argumentIndex);
                    body.Emit(OpCodes.Conv_I);
                }
                else if (originalType.GetElementType().IsValueType)
                {
                    body.Emit(OpCodes.Ldarg, argumentIndex);
                    body.Emit(OpCodes.Ldind_Ref);
                    body.Emit(OpCodes.Call, imports.Il2CppObjectBaseToPointerNotNull);
                }
                else
                {
                    var pointerVar = new VariableDefinition(imports.IntPtr);
                    refVariable = pointerVar;
                    body.Body.Variables.Add(pointerVar);
                    body.Emit(OpCodes.Ldarg, argumentIndex);
                    body.Emit(OpCodes.Ldind_Ref);
                    if (originalType.FullName == "System.String")
                    {
                        body.Emit(OpCodes.Call, imports.StringToNative);
                    }
                    else
                    {
                        body.Emit(OpCodes.Call, imports.Il2CppObjectBaseToPointer);
                    }
                    body.Emit(OpCodes.Stloc, pointerVar);
                    body.Emit(OpCodes.Ldloca, pointerVar);
                    body.Emit(OpCodes.Conv_I);
                }
            }
            else if (originalType.IsValueType)
            {
                if (newType.IsValueType)
                {
                    if (argumentIndex == 0 && valueTypeArgument0IsAPointer)
                    {
                        body.Emit(OpCodes.Ldarg_0);
                    }
                    else
                    {
                        body.Emit(OpCodes.Ldarga, argumentIndex);
                    }
                }
                else
                {
                    body.Emit(OpCodes.Ldarg, argumentIndex);
                    body.Emit(OpCodes.Call, imports.Il2CppObjectBaseToPointerNotNull);
                    if (unboxNonBlittableType)
                    {
                        body.Emit(OpCodes.Call, imports.ObjectUnbox);
                    }
                }
            }
            else if (originalType.FullName == "System.String")
            {
                body.Emit(OpCodes.Ldarg, argumentIndex);
                body.Emit(OpCodes.Call, imports.StringToNative);
            }
            else
            {
                body.Emit(OpCodes.Ldarg, argumentIndex);
                body.Emit(OpCodes.Call, allowNullable ? imports.Il2CppObjectBaseToPointer : imports.Il2CppObjectBaseToPointerNotNull);
            }
        }
        public static void GenerateInvokerMethodBody(MethodDefinition newMethod, FieldDefinition delegateField, TypeDefinition delegateType, TypeRewriteContext enclosingType, AssemblyKnownImports imports)
        {
            var body = newMethod.Body.GetILProcessor();

            body.Emit(OpCodes.Ldsfld, delegateField);
            if (newMethod.HasThis)
            {
                body.Emit(OpCodes.Ldarg_0);
                body.Emit(OpCodes.Call, imports.Il2CppObjectBaseToPointerNotNull);
            }

            var argOffset = newMethod.HasThis ? 1 : 0;

            for (var i = 0; i < newMethod.Parameters.Count; i++)
            {
                var param     = newMethod.Parameters[i];
                var paramType = param.ParameterType;
                if (paramType.IsValueType || paramType.IsByReference && paramType.GetElementType().IsValueType)
                {
                    body.Emit(OpCodes.Ldarg, i + argOffset);
                }
                else
                {
                    body.EmitObjectToPointer(param.ParameterType, param.ParameterType, enclosingType, i + argOffset, false, true, true, out var refVar);
                    if (refVar != null)
                    {
                        LogSupport.Warning($"Method {newMethod} has a reference-typed ref parameter, this will be ignored");
                    }
                }
            }

            body.Emit(OpCodes.Call, delegateType.Methods.Single(it => it.Name == "Invoke"));
            if (!newMethod.ReturnType.IsValueType)
            {
                var pointerVar = new VariableDefinition(imports.IntPtr);
                newMethod.Body.Variables.Add(pointerVar);
                body.Emit(OpCodes.Stloc, pointerVar);
                var loadInstr = body.Create(OpCodes.Ldloc, pointerVar);
                body.EmitPointerToObject(newMethod.ReturnType, newMethod.ReturnType, enclosingType, loadInstr, false, false);
            }
            body.Emit(OpCodes.Ret);
        }