/// <summary> /// Convert the given method into optimized Ast format. /// </summary> internal protected static AstNode CreateOptimizedAst(AssemblyCompiler compiler, MethodSource source, bool generateSetNextInstructionCode, StopAstConversion debugStop = StopAstConversion.None, AstOptimizationStep debugStopOptimizing = AstOptimizationStep.None ) { // Build AST DecompilerContext context; AstBlock ast; if (source.IsDotNet) { context = new DecompilerContext(source.Method); var astBuilder = new IL2Ast.AstBuilder(source.ILMethod, true, context); var children = astBuilder.Build(); ast = new AstBlock(children.Select(x => x.SourceLocation).FirstOrDefault(), children); if ((source.ILMethod.IsConstructor) && (source.Method.DeclaringType.Fields.Any(x => x.FieldType.IsEnum() || x.Name.EndsWith(NameConstants.Atomic.FieldUpdaterPostfix)))) { // Ensure all fields are initialized AddFieldInitializationCode(compiler, source, ast); } if (source.Method.NeedsGenericInstanceTypeParameter && (source.Name == ".ctor")) { // Add code to save the generic instance type parameter into the generic instance field. AddGenericInstanceFieldInitializationCode(source, ast, compiler.Module.TypeSystem); } } else if (source.IsJava) { var astBuilder = new Java2Ast.AstBuilder(compiler.Module, source.JavaMethod, source.Method.DeclaringType, true); context = new DecompilerContext(source.Method); ast = astBuilder.Build(); } else if (source.IsAst) { context = new DecompilerContext(source.Method); ast = source.Ast; } else { throw new NotSupportedException("Unknown source"); } if (debugStop == StopAstConversion.AfterILConversion) return ast; // Optimize AST var astOptimizer = new AstOptimizer(context, ast); astOptimizer.Optimize(debugStopOptimizing); if (debugStop == StopAstConversion.AfterOptimizing) return ast; // Optimize AST towards the target TargetConverters.Convert(context, ast, source, compiler, debugStop); if(generateSetNextInstructionCode) SetNextInstructionGenerator.Convert(ast, source, compiler); // Return return return ast; }
public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler) { foreach (var block in ast.GetSelfAndChildrenRecursive<AstBlock>()) { for (int i = 0; i < block.Body.Count; ++i) { var expr = block.Body[i] as AstExpression; if(expr == null) continue; var interlockedPairs = expr.GetExpressionPairs(p => p.Code == AstCode.Call && ((XMethodReference) p.Operand).DeclaringType.FullName == "System.Threading.Interlocked") .ToList(); if(interlockedPairs.Count == 0) continue; if (interlockedPairs.Count > 1) throw new CompilerException("The Interlocked converter can not handle more than one interlocked call per statement. Try splittig the statement up."); var interlockedCall = interlockedPairs.First().Expression; // first parameter should be a reference to a field, // (but be lenient if we don't find what we expect) var targetExpr = interlockedCall.Arguments[0]; XFieldReference field = null; if (targetExpr.InferredType.IsByReference) { field = targetExpr.Operand as XFieldReference; if (field != null) { // check if we have an atomic updater var updater = field.DeclaringType.Resolve().Fields .FirstOrDefault(f => f.Name == field.Name + NameConstants.Atomic.FieldUpdaterPostfix); if (updater != null) { var method = (XMethodReference) interlockedCall.Operand; var methodName = method.Name.Split('$')[0]; // retrieve original name. if (InterlockedUsingUpdater(interlockedCall, methodName, field, updater, targetExpr, interlockedPairs.First().Parent, compiler)) continue; } } } FailsafeInterlockedUsingLocking(field, expr, targetExpr, block, i, compiler, currentMethod); } } }
/// <summary> /// Optimize expressions /// </summary> public static void Convert(AstNode ast, MethodSource currentMethod, XTypeSystem typeSystem) { // Expand typeof foreach (var pair in ast.GetExpressionPairs()) { var node = pair.Expression; switch (node.Code) { case AstCode.Ldfld: //case AstCode.Ldsfld: // NOT YET { var field = (XFieldReference) node.Operand; UnboxIfGeneric(field.FieldType, node, typeSystem); } break; case AstCode.Stfld: { var field = (XFieldReference)node.Operand; BoxIfGeneric(field.FieldType, node.Arguments[1]); } break; case AstCode.Call: case AstCode.Calli: case AstCode.Callvirt: { var method = (XMethodReference)node.Operand; if ((!method.ReturnType.IsVoid()) && (pair.Parent != null)) { UnboxIfGeneric(method.ReturnType, node, typeSystem); } } break; case AstCode.Ret: { if (node.Arguments.Count > 0) { var expectedType = currentMethod.Method.ReturnType; BoxIfGeneric(expectedType, node.Arguments[0]); } } break; case AstCode.ByRefArray: case AstCode.ByRefOutArray: { if (node.Arguments.Count > 1) { var originalType = (XTypeReference) node.Arguments[1].Operand; UnboxByRefIfGeneric(originalType, node.StoreByRefExpression, typeSystem); } } break; } } }
public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler) { // only work on MoveNext of IAsyncStateMachine implementations. if (currentMethod.Name != "MoveNext" && currentMethod.Name != "IAsyncStateMachine_MoveNext") return; var declaringType = currentMethod.Method.DeclaringType.Resolve(); if (declaringType.Interfaces.All(i => i.FullName != "System.Runtime.CompilerServices.IAsyncStateMachine")) return; foreach(var block in ast.GetSelfAndChildrenRecursive<AstBlock>()) FixBlock(block); }
public SourceLocation(MethodSource source, SourceFile file, int line, int column) : this(new DynamicSourceLocation (source, file, line, column)) { Module = file.Module.Name; FileName = file.FileName; Method = source.Name; if (line != -1) Name = source.Name + ':' + line; else Name = source.Name; Line = line; Column = column; }
/// <summary> /// Convert the given method into optimized Ast format. /// </summary> protected static AstNode CreateOptimizedAst(AssemblyCompiler compiler, MethodSource source) { // Build AST DecompilerContext context; AstBlock ast; if (source.IsDotNet) { context = new DecompilerContext(source.Method); var astBuilder = new IL2Ast.AstBuilder(source.ILMethod, true, context); var children = astBuilder.Build(); ast = new AstBlock(children.Select(x => x.SourceLocation).FirstOrDefault(), children); if ((source.ILMethod.IsConstructor) && (source.Method.DeclaringType.Fields.Any(x => x.FieldType.IsEnum()))) { // Ensure all fields are initialized AddFieldInitializationCode(source, ast); } if (source.Method.NeedsGenericInstanceTypeParameter && (source.Name == ".ctor")) { // Add code to safe the generic instance type parameter into the generic instance field. AddGenericInstanceFieldInitializationCode(ast); } } else if (source.IsJava) { var astBuilder = new Java2Ast.AstBuilder(compiler.Module, source.JavaMethod, source.Method.DeclaringType, true); context = new DecompilerContext(source.Method); ast = astBuilder.Build(); } else if (source.IsAst) { context = new DecompilerContext(source.Method); ast = source.Ast; } else { throw new NotSupportedException("Unknown source"); } // Optimize AST var astOptimizer = new AstOptimizer(context, ast); astOptimizer.Optimize(); // Optimize AST towards the target TargetConverters.Convert(context, ast, source, compiler); // Return return return ast; }
/// <summary> /// Compile this method to dex code. /// </summary> public void Compile(AssemblyCompiler compiler, DexTargetPackage targetPackage) { if (Body == null) { throw new ArgumentException("Body expected"); } if (dexMethod == null) { throw new ArgumentException("dexMethod expected"); } CompiledMethod compiledMethod; var source = new MethodSource(this, Body); DexMethodBodyCompiler.TranslateToRL(compiler, targetPackage, source, dexMethod, out compiledMethod); compiledMethod.DexMethod = dexMethod; }
/// <summary> /// Perform all dot42 related Ast conversions. /// </summary> public static void Convert(DecompilerContext context, AstBlock ast, MethodSource currentMethod, AssemblyCompiler compiler) { if (ast.IsOptimizedForTarget) { return; } #if DEBUG //Debugger.Launch(); if ((currentMethod.Method != null) && (currentMethod.Method.Name.Equals("runTest", StringComparison.OrdinalIgnoreCase))) { //Debugger.Launch(); } #endif IntPtrConverter.Convert(ast, compiler); TypeOfConverter.Convert(ast, compiler); BranchOptimizer.Convert(ast); CompoundAssignmentConverter.Convert(ast); ByReferenceParamConverter.Convert(context, ast, compiler); CompareUnorderedConverter.Convert(ast); EnumConverter.Convert(ast, compiler); EnumOptimizer.Convert(ast, compiler); // Keep this order NullableConverter.Convert(ast, compiler); PrimitiveAddressOfConverter.Convert(ast, currentMethod, compiler); StructCallConverter.Convert(ast, compiler); // end InitializeStructVariablesConverter.Convert(ast); DelegateConverter.Convert(ast); LdcWideConverter.Convert(ast); LdLocWithConversionConverter.Convert(ast); ConvertAfterLoadConversionConverter.Convert(ast); ConvertBeforeStoreConversionConverter.Convert(ast); CleanupConverter.Convert(ast); GenericsConverter.Convert(ast); // Expand cast expressions CastConverter.Convert(ast, currentMethod, compiler); // Expand generic instance information GenericInstanceConverter.Convert(ast, currentMethod, compiler); }
/// <summary> /// Validates this object and throws a <see cref="NotSupportedException"/> in /// the case of an unsupported kernel configuration. /// </summary> public void Validate() { if (MethodSource == null) { throw new NotSupportedException( ErrorMessages.InvalidEntryPointWithoutDotNetMethod); } if (!MethodSource.IsStatic && !MethodSource.IsNotCapturingLambda()) { throw new NotSupportedException( ErrorMessages.InvalidEntryPointInstanceKernelMethod); } if (IndexType == IndexType.None) { throw new NotSupportedException( RuntimeErrorMessages.NotSupportedKernel); } }
/// <summary> /// Perform all dot42 related Ast conversions. /// </summary> public static void Convert(DecompilerContext context, AstBlock ast, MethodSource currentMethod, AssemblyCompiler compiler) { if (ast.IsOptimizedForTarget) return; #if DEBUG //Debugger.Launch(); if ((currentMethod.Method != null) && (currentMethod.Method.Name.Equals("runTest", StringComparison.OrdinalIgnoreCase))) { //Debugger.Launch(); } #endif IntPtrConverter.Convert(ast, compiler); TypeOfConverter.Convert(ast, compiler); BranchOptimizer.Convert(ast); CompoundAssignmentConverter.Convert(ast); ByReferenceParamConverter.Convert(context, ast, compiler); CompareUnorderedConverter.Convert(ast); EnumConverter.Convert(ast, compiler); EnumOptimizer.Convert(ast, compiler); // Keep this order NullableConverter.Convert(ast, compiler); PrimitiveAddressOfConverter.Convert(ast, currentMethod, compiler); StructCallConverter.Convert(ast, compiler); // end InitializeStructVariablesConverter.Convert(ast); DelegateConverter.Convert(ast); LdcWideConverter.Convert(ast); LdLocWithConversionConverter.Convert(ast); ConvertAfterLoadConversionConverter.Convert(ast); ConvertBeforeStoreConversionConverter.Convert(ast); CleanupConverter.Convert(ast); GenericsConverter.Convert(ast); // Expand cast expressions CastConverter.Convert(ast, currentMethod, compiler); // Expand generic instance information GenericInstanceConverter.Convert(ast, currentMethod, compiler); }
/// <summary> /// Generate method code /// </summary> public void GenerateCode(ClassDefinition declaringClass, DexTargetPackage targetPackage) { if (dmethod == null) { return; } // Create body (if any) if (!method.HasCode) { return; } if (compiler.DxClassfileMethodBodyCompiler != null) { var dxBody = compiler.DxClassfileMethodBodyCompiler.GetMethodBody(dmethod, xMethod); if (dxBody == null) { throw new Exception("unable to get method body through 'dx': " + dmethod); } dmethod.Body = dxBody; dmethod.Owner.SetSourceFile(dxBody.Owner.Owner.SourceFile); return; } var cachedBody = compiler.MethodBodyCompilerCache.GetFromCache(dmethod, xMethod, compiler, targetPackage); if (cachedBody != null) { dmethod.Body = cachedBody.Body; // important to fix the owners source file as early as possible, // so it can't be changed later. Else we would have to recreate // all cached method bodies debug infos. dmethod.Owner.SetSourceFile(cachedBody.ClassSourceFile); return; } //ExpandSequencePoints(method.Body); var source = new MethodSource(xMethod, method); DexMethodBodyCompiler.TranslateToRL(compiler, targetPackage, source, dmethod, false, out compiledMethod); }
public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler) { // only work on MoveNext of IAsyncStateMachine implementations. if (currentMethod.Name != "MoveNext" && currentMethod.Name != "IAsyncStateMachine_MoveNext") { return; } var declaringType = currentMethod.Method.DeclaringType.Resolve(); if (declaringType.Interfaces.All(i => i.FullName != "System.Runtime.CompilerServices.IAsyncStateMachine")) { return; } foreach (var block in ast.GetSelfAndChildrenRecursive <AstBlock>()) { FixBlock(block); } }
/// <summary> /// Create a method body for the given method. /// </summary> internal static MethodBody TranslateToRL(AssemblyCompiler compiler, DexTargetPackage targetPackage, MethodSource source, MethodDefinition dmethod, bool generateSetNextInstructionCode, out CompiledMethod compiledMethod) { try { #if DEBUG //Debugger.Launch(); if ((source.Method != null) && (source.Method.Name == "test6")) { //Debugger.Launch(); } #endif // Create Ast var optimizedAst = CreateOptimizedAst(compiler, source, generateSetNextInstructionCode); // Generate RL code var rlBody = new MethodBody(source); var rlGenerator = new AstCompilerVisitor(compiler, source, targetPackage, dmethod, rlBody); optimizedAst.Accept(rlGenerator, null); rlGenerator.Complete(); // Should we add return_void? if (source.ReturnsVoid) { var instructions = rlBody.Instructions; if ((instructions.Count == 0) || (instructions.Last().Code != RCode.Return_void && instructions.Last().Code != RCode.Throw)) { instructions.Add(new RL.Instruction(RCode.Return_void) { SequencePoint = source.GetLastSourceLine() }); } } // Record results compiledMethod = targetPackage.Record(source, rlBody, rlGenerator.Frame); return rlBody; } catch (Exception ex) { // Forward exception with more information var msg = string.Format("Error while compiling {0} in {1}: {2}", source.FullName, source.DeclaringTypeFullName, ex.Message); throw new CompilerException(msg, ex); } }
/// <summary> /// Optimize expressions /// </summary> public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler) { var typeSystem = compiler.Module.TypeSystem; foreach (var node in ast.GetSelfAndChildrenRecursive <AstExpression>()) { switch (node.Code) { case AstCode.InstanceOf: ConvertInstanceOf(compiler, node, typeSystem); break; case AstCode.Isinst: ConvertIsInst(compiler, node, typeSystem); break; case AstCode.Castclass: ConvertCastclass(compiler, node, typeSystem); break; case AstCode.Call: ConvertAsNativeIFormattable(node, typeSystem); break; case AstCode.Callvirt: ConvertCallvirtIEnumerable(compiler, node, typeSystem); break; // TODO: this might better be handled in RLBuilder.ConvertTypeBeforeStore() case AstCode.Ret: ConvertRetOrStfldOrStsfld(compiler, currentMethod.Method.ReturnType, node, typeSystem); break; // TODO: this appears to be handled in RLBuilder.ConvertTypeBeforeStore(), // but is not. why? case AstCode.Stfld: case AstCode.Stsfld: ConvertRetOrStfldOrStsfld(compiler, ((XFieldReference)node.Operand).FieldType, node, typeSystem); break; } } }
/// <summary> /// Generate an Return opcode. /// </summary> internal static RCode Return(this AstExpression expr, MethodSource currentMethod) { if (currentMethod.ReturnsDexWide) { return(RCode.Return_wide); } if (currentMethod.ReturnsVoid) { return(RCode.Return_void); } if (currentMethod.ReturnsDexValue) { return(RCode.Return); } if (currentMethod.ReturnsDexObject) { return(RCode.Return_object); } throw new ArgumentException("Unknown type in return " + currentMethod.FullName); }
/// <summary> /// Add initialization code to the given constructor for non-initialized struct fields. /// </summary> private static void AddFieldInitializationCode(MethodSource ctor, AstBlock ast) { List <XFieldDefinition> fieldsToInitialize; var declaringType = ctor.Method.DeclaringType; var fieldsThatMayNeedInitialization = declaringType.Fields.Where(x => x.IsReachable && x.FieldType.IsEnum()); var index = 0; if (ctor.Method.IsStatic) { fieldsToInitialize = fieldsThatMayNeedInitialization.Where(x => x.IsStatic && !IsInitialized(ast, x)).ToList(); foreach (var field in fieldsToInitialize) { var defaultExpr = new AstExpression(ast.SourceLocation, AstCode.DefaultValue, field.FieldType); var initExpr = new AstExpression(ast.SourceLocation, AstCode.Stsfld, field, defaultExpr); ast.Body.Insert(index++, initExpr); } } else { // If there is a this ctor being called, we do not have to initialize here. var thisCalls = ast.GetSelfAndChildrenRecursive <AstExpression>(x => (x.Code == AstCode.Call) && ((XMethodReference)x.Operand).DeclaringType.IsSame(declaringType)); if (thisCalls.Any(x => ((XMethodReference)x.Operand).Name == ".ctor")) { return; } fieldsToInitialize = fieldsThatMayNeedInitialization.Where(x => !x.IsStatic && !IsInitialized(ast, x)).ToList(); if (fieldsToInitialize.Any()) { var baseCall = FindFirstBaseCtorCall(ast, declaringType); var initExpressions = new List <AstExpression>(); foreach (var field in fieldsToInitialize) { var thisExpr = new AstExpression(ast.SourceLocation, AstCode.Ldthis, null); var defaultExpr = new AstExpression(ast.SourceLocation, AstCode.DefaultValue, field.FieldType); initExpressions.Add(new AstExpression(ast.SourceLocation, AstCode.Stfld, field, thisExpr, defaultExpr)); } InsertAfter(ast, baseCall, initExpressions); } } }
protected SourceLocation FindFile(ScriptingContext context, string filename, int line) { SourceFile file = Session.FindFile(filename); if (file == null) { throw new ScriptingException("Cannot find source file `{0}'.", filename); } MethodSource source = file.FindMethod(line); if (source == null) { throw new ScriptingException( "Cannot find method corresponding to line {0} in `{1}'.", line, file.Name); } return(new SourceLocation(source, file, line)); }
/// <summary> /// Optimize expressions /// </summary> public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler) { foreach (var node in ast.GetExpressions(x => (x.Code == AstCode.Call) || (x.Code == AstCode.Calli) || (x.Code == AstCode.Callvirt))) { var method = (XMethodReference)node.Operand; XMethodDefinition methodDef; if (method.TryResolve(out methodDef) && methodDef.IsConstructor && methodDef.DeclaringType.IsPrimitive && (node.Arguments.Count == 2)) { // primitive.ctor(addressof_primitive, value) -> primitive.cast(value) var locVar = node.Arguments[0].Operand; node.Arguments.RemoveAt(0); node.SetCode(AstCode.Stloc).SetType(node.Arguments[0].GetResultType()).Operand = locVar; } else { for (var i = 0; i < node.Arguments.Count; i++) { ProcessArgument(node, method, i, currentMethod, compiler.Module); } } } }
/// <summary> /// Optimize expressions /// </summary> public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler) { var typeSystem = compiler.Module.TypeSystem; // Expand instanceof foreach (var node in ast.GetSelfAndChildrenRecursive <AstExpression>(x => x.Code == AstCode.InstanceOf)) { ConvertInstanceOf(compiler, node, typeSystem); } // Expand isinst foreach (var node in ast.GetSelfAndChildrenRecursive <AstExpression>(x => x.Code == AstCode.Isinst)) { ConvertIsInst(compiler, node, typeSystem); } // Expand Castclass foreach (var node in ast.GetSelfAndChildrenRecursive <AstExpression>(x => x.Code == AstCode.Castclass)) { ConvertCastclass(compiler, node, typeSystem); } }
/// <summary> /// Optimize expressions /// </summary> public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler) { var typeSystem = compiler.Module.TypeSystem; // Expand instanceof foreach (var node in ast.GetSelfAndChildrenRecursive<AstExpression>(x => x.Code == AstCode.InstanceOf)) { ConvertInstanceOf(compiler, node, typeSystem); } // Expand isinst foreach (var node in ast.GetSelfAndChildrenRecursive<AstExpression>(x => x.Code == AstCode.Isinst)) { ConvertIsInst(compiler, node, typeSystem); } // Expand Castclass foreach (var node in ast.GetSelfAndChildrenRecursive<AstExpression>(x => x.Code == AstCode.Castclass)) { ConvertCastclass(compiler, node, typeSystem); } }
private readonly Stack <FinallyBlockState> tryCatchStack = new Stack <FinallyBlockState>(); // holds the current finally target. /// <summary> /// Default ctor /// </summary> internal AstCompilerVisitor(AssemblyCompiler compiler, MethodSource source, DexTargetPackage targetPackage, MethodDefinition method, MethodBody body) { this.compiler = compiler; currentMethod = source; this.targetPackage = targetPackage; currentDexMethod = method; this.body = body; frame = new AstInvocationFrame(targetPackage, method, source, body); instructions = body.Instructions; // Base class class ctor for structs if (source.IsDotNet && (source.Name == ".ctor") && (source.ILMethod.DeclaringType.IsValueType)) { var ilMethod = source.ILMethod; if (!HasBaseOrThisClassCtorCall(ilMethod)) { // Add a call to the base class ctor now var seqp = SequencePointWrapper.Wrap(ilMethod.Body.Instructions.Select(x => x.SequencePoint(ilMethod.Body)).FirstOrDefault()); var baseCtor = new MethodReference(method.Owner.SuperClass, "<init>", new Prototype(PrimitiveType.Void)); this.Add(seqp, RCode.Invoke_direct, baseCtor, frame.ThisArgument); } } // Store any genericInstance argument /*if (source.Method.NeedsGenericInstanceTypeParameter && (source.Name == ".ctor")) * { * var owner = method.Owner; * var ilMethod = source.ILMethod; * var giField = owner.GenericInstanceField; * if (giField == null) * { * throw new CompilerException(string.Format("Expected GenericInstance field in {0}", ilMethod.FullName)); * } * var seqp = SequencePointWrapper.Wrap(ilMethod.Body.Instructions.Select(x => x.SequencePoint).FirstOrDefault()); * this.Add(seqp, RCode.Iput_object, giField, frame.GenericInstanceTypeArgument, frame.ThisArgument); * }*/ }
/// <summary> /// Add initialization code to the given constructor for non-initialized struct fields. /// </summary> private static void AddFieldInitializationCode(MethodSource ctor, AstBlock ast) { List<XFieldDefinition> fieldsToInitialize; var declaringType = ctor.Method.DeclaringType; var fieldsThatMayNeedInitialization = declaringType.Fields.Where(x => x.IsReachable && x.FieldType.IsEnum()); var index = 0; if (ctor.Method.IsStatic) { fieldsToInitialize = fieldsThatMayNeedInitialization.Where(x => x.IsStatic && !IsInitialized(ast, x)).ToList(); foreach (var field in fieldsToInitialize) { var defaultExpr = new AstExpression(ast.SourceLocation, AstCode.DefaultValue, field.FieldType); var initExpr = new AstExpression(ast.SourceLocation, AstCode.Stsfld, field, defaultExpr); ast.Body.Insert(index++, initExpr); } } else { // If there is a this ctor being called, we do not have to initialize here. var thisCalls = ast.GetSelfAndChildrenRecursive<AstExpression>(x => (x.Code == AstCode.Call) && ((XMethodReference) x.Operand).DeclaringType.IsSame(declaringType)); if (thisCalls.Any(x => ((XMethodReference) x.Operand).Name == ".ctor")) return; fieldsToInitialize = fieldsThatMayNeedInitialization.Where(x => !x.IsStatic && !IsInitialized(ast, x)).ToList(); if (fieldsToInitialize.Any()) { var baseCall = FindFirstBaseCtorCall(ast, declaringType); var initExpressions = new List<AstExpression>(); foreach (var field in fieldsToInitialize) { var thisExpr = new AstExpression(ast.SourceLocation, AstCode.Ldthis, null); var defaultExpr = new AstExpression(ast.SourceLocation, AstCode.DefaultValue, field.FieldType); initExpressions.Add(new AstExpression(ast.SourceLocation, AstCode.Stfld, field, thisExpr, defaultExpr)); } InsertAfter(ast, baseCall, initExpressions); } } }
void print_address_func(long address) { TargetAddress maddress = new TargetAddress( memory.AddressDomain, address); if (current_method != null) { try { MethodSource method = current_method.GetTrampoline( memory, maddress); if (method != null) { output_func(method.Name); return; } } catch (TargetException) { } } Symbol name = null; if (process != null) { name = process.SymbolTableManager.SimpleLookup(maddress, false); } if (name == null) { output_func(address); } else { output_func(String.Format("0x{0:x}:{1}", address, name.ToString())); } }
/// <summary> /// Optimize expressions /// </summary> public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler) { var typeSystem = compiler.Module.TypeSystem; foreach (var node in ast.GetSelfAndChildrenRecursive<AstExpression>()) { switch (node.Code) { case AstCode.InstanceOf: ConvertInstanceOf(compiler, node, typeSystem); break; case AstCode.Isinst: ConvertIsInst(compiler, node, typeSystem); break; case AstCode.Castclass: ConvertCastclass(compiler, node, typeSystem); break; case AstCode.Call: ConvertAsNativeIFormattable(node, typeSystem); break; case AstCode.Callvirt: ConvertCallvirtIEnumerable(compiler, node, typeSystem); break; // TODO: this might better be handled in RLBuilder.ConvertTypeBeforeStore() case AstCode.Ret: ConvertRetOrStfldOrStsfld(compiler, currentMethod.Method.ReturnType, node, typeSystem); break; // TODO: this appears to be handled in RLBuilder.ConvertTypeBeforeStore(), // but is not. why? case AstCode.Stfld: case AstCode.Stsfld: ConvertRetOrStfldOrStsfld(compiler, ((XFieldReference)node.Operand).FieldType, node, typeSystem); break; } } }
/// <summary> /// Generate an Return opcode. /// </summary> internal static RCode Return(this AstExpression expr, MethodSource currentMethod) { if (currentMethod.ReturnsDexWide) return RCode.Return_wide; if (currentMethod.ReturnsVoid) return RCode.Return_void; if (currentMethod.ReturnsDexValue) return RCode.Return; if (currentMethod.ReturnsDexObject) return RCode.Return_object; throw new ArgumentException("Unknown type in return " + currentMethod.FullName); }
/// <summary> /// Create an expression that loads the given type at runtime. /// </summary> private static AstExpression LoadTypeForGenericInstance(ISourceLocation seqp, MethodSource currentMethod, XTypeReference type, AssemblyCompiler compiler, XTypeDefinition typeHelperType, XTypeSystem typeSystem, TypeConversion typeConversion, XGenericInstanceType typeGenericArguments = null) { if (type.IsArray) { // Array type var arrayType = (XArrayType)type; // Load element type var prefix = LoadTypeForGenericInstance(seqp, currentMethod, ((XArrayType)type).ElementType, compiler, typeHelperType, typeSystem, typeConversion); // Convert to array type if (arrayType.Dimensions.Count() == 1) { var giCreateArray = typeHelperType.Methods.Single(x => (x.Name == "Array") && (x.Parameters.Count == 1)); return(new AstExpression(seqp, AstCode.Call, giCreateArray, prefix) { ExpectedType = typeSystem.Type }); } else { var giCreateArray = typeHelperType.Methods.Single(x => (x.Name == "Array") && (x.Parameters.Count == 2)); var dimensionsExpr = new AstExpression(seqp, AstCode.Ldc_I4, arrayType.Dimensions.Count()) { ExpectedType = typeSystem.Int }; return(new AstExpression(seqp, AstCode.Call, giCreateArray, prefix, dimensionsExpr) { ExpectedType = typeSystem.Type }); } } var gp = type as XGenericParameter; if (gp != null) { AstExpression loadExpr; if (gp.Owner is XTypeReference) { // Class type parameter var owner = (XTypeReference)gp.Owner; if (owner.GetElementType().Resolve().HasDexImportAttribute()) { // Imported type return(new AstExpression(seqp, AstCode.TypeOf, typeSystem.Object) { ExpectedType = typeSystem.Type }); } if (currentMethod.IsClassCtor) { // Class ctor's cannot have type information. // Return Object instead if (currentMethod.IsDotNet && !currentMethod.ILMethod.DeclaringType.HasSuppressMessageAttribute("StaticConstructorUsesGenericParameter")) { var msg = "Class (static) constructor of '{0}' tries to use generic parameter. This will always yield Object. " + "You can suppress this warning with a [SuppressMessage(\"dot42\", \"StaticConstructorUsesGenericParameter\")] " + "attribute on the class."; if (seqp != null && seqp.Document != null) { DLog.Warning(DContext.CompilerCodeGenerator, seqp.Document, seqp.StartColumn, seqp.StartLine, msg, currentMethod.DeclaringTypeFullName); } else { DLog.Warning(DContext.CompilerCodeGenerator, msg, currentMethod.DeclaringTypeFullName); } } return(new AstExpression(seqp, AstCode.TypeOf, typeSystem.Object) { ExpectedType = typeSystem.Type }); } loadExpr = currentMethod.IsStatic ? LoadStaticClassGenericArgument(seqp, typeSystem, currentMethod.Method, gp.Position) : LoadInstanceClassGenericArgument(seqp, typeSystem, currentMethod.Method.DeclaringType, gp.Position); } else { // Method type parameter var owner = (XMethodReference)gp.Owner; if (owner.GetElementMethod().Resolve().DeclaringType.HasDexImportAttribute()) { // Imported type return(LoadTypeForGenericInstance(seqp, currentMethod, type.Module.TypeSystem.Object, compiler, typeHelperType, typeSystem, typeConversion)); } loadExpr = LoadMethodGenericArgument(seqp, typeSystem, currentMethod.Method, gp.Position); } if (typeConversion == TypeConversion.EnsureRuntimeType) { return(EnsureGenericRuntimeType(loadExpr, typeSystem, typeHelperType)); } else { return(loadExpr); } } if (type is XTypeSpecification) { var typeSpec = (XTypeSpecification)type; var git = type as XGenericInstanceType; var baseType = LoadTypeForGenericInstance(seqp, currentMethod, typeSpec.ElementType, compiler, typeHelperType, typeSystem, typeConversion, git); if (typeConversion != TypeConversion.EnsureTrueOrMarkerType || typeSpec.GetElementType().IsNullableT()) { return(baseType); } // Use the element type and make a generic proxy with the generic arguments. var parameters = CreateGenericInstanceCallArguments(seqp, git, currentMethod, compiler); if (parameters.Count == 1 && parameters[0].GetResultType().IsArray) { // array type call. var method = typeHelperType.Methods.Single(m => m.Name == "GetGenericInstanceType" && m.Parameters.Count == 2 && m.Parameters[1].ParameterType.IsArray); return(new AstExpression(seqp, AstCode.Call, method, baseType, parameters[0])); } else { parameters.Insert(0, baseType); var method = typeHelperType.Methods.Single(m => m.Name == "GetGenericInstanceType" && m.Parameters.Count == parameters.Count && !m.Parameters[1].ParameterType.IsArray); return(new AstExpression(seqp, AstCode.Call, method, parameters.ToArray())); } } if (typeConversion == TypeConversion.EnsureTrueOrMarkerType && type.GetElementType().IsNullableT()) { if (typeGenericArguments != null) { var underlying = typeGenericArguments.GenericArguments[0]; var code = underlying.IsPrimitive ? AstCode.BoxedTypeOf : AstCode.NullableTypeOf; return(new AstExpression(seqp, code, underlying) { ExpectedType = typeSystem.Type }); } // if typeGenericArguments is null, this is a generic definition, e.g. typeof(Nullable<>). } // Plain type reference or definition return(new AstExpression(seqp, AstCode.TypeOf, type) { ExpectedType = typeSystem.Type }); }
public static bool ValidForRestriction(this MethodSource source, SourceRestrictions restriction) { return((MethodSource)((int)restriction & (int)source) == source); }
/// <summary> /// Optimize expressions /// </summary> public static void Convert(AstNode ast, MethodSource currentMethod, XTypeSystem typeSystem) { // Expand typeof foreach (var pair in ast.GetExpressionPairs()) { var node = pair.Expression; switch (node.Code) { case AstCode.Ldfld: //case AstCode.Ldsfld: // NOT YET { var field = (XFieldReference) node.Operand; UnboxIfGeneric(field.FieldType, node, typeSystem); } break; case AstCode.Stfld: { var field = (XFieldReference)node.Operand; BoxIfGeneric(field.FieldType, node.Arguments[1]); } break; case AstCode.Call: case AstCode.Calli: case AstCode.Callvirt: { var method = (XMethodReference)node.Operand; if ((!method.ReturnType.IsVoid()) && (pair.Parent != null)) { UnboxIfGeneric(method.ReturnType, node, typeSystem); } } break; case AstCode.Ret: { if (node.Arguments.Count > 0) { var expectedType = currentMethod.Method.ReturnType; BoxIfGeneric(expectedType, node.Arguments[0]); } } break; case AstCode.Box: { var type = (XTypeReference)node.Operand; // Honestly, the whole Generics code seems to be quite // complex. I hope this fix does not break anything else. // Also: is there any sense in having two codes 'box' and 'boxtogeneric'? // The Rosyln compiler apparently uses 'box' instructions to satisfy // generic constraints. Not sure if this is the right place to handle // this. // What we want to achive is to perform this conversion code only if the // expected type is assignable from any of the constraints. As we do not // have an 'IsAssignableFrom' logic for XTypes, a simpler check must suffice. if (type.IsGenericParameter && ((XGenericParameter)type).Constraints.Any() && node.ExpectedType != null && !node.ExpectedType.IsPrimitive && !node.ExpectedType.IsGenericParameter) { // or just enter the required cast here??? node.Code = AstCode.BoxToGeneric; node.InferredType = node.ExpectedType; } } break; case AstCode.ByRefArray: case AstCode.ByRefOutArray: { if (node.Arguments.Count > 1) { var originalType = (XTypeReference) node.Arguments[1].Operand; UnboxByRefIfGeneric(originalType, node.StoreByRefExpression, typeSystem); } } break; } } }
/// <summary> /// Create a frame for the given method /// </summary> internal AstInvocationFrame(DexTargetPackage targetPackage, MethodDefinition method, MethodSource source, MethodBody body) { this.targetPackage = targetPackage; this.body = body; this.body = body; Debug.Assert(!body.Registers.Any()); var prototypeParamOffset = 0; var prototype = method.Prototype; if (source.IsDotNet) { var ilMethod = source.ILMethod; // Allocate this if (!method.IsStatic) { thisArgument = (ArgumentRegisterSpec)Allocate(method.Owner, true, RCategory.Argument, ilMethod.Body.ThisParameter); arguments.Add(thisArgument); } else if (ilMethod.IsAndroidExtension() && !ilMethod.IsStatic) { prototypeParamOffset++; var type = ilMethod.DeclaringType.GetReference(targetPackage, source.Method.Module); thisArgument = (ArgumentRegisterSpec)Allocate(type, true, RCategory.Argument, ilMethod.Body.ThisParameter); arguments.Add(thisArgument); } // Allocate arguments var paramCount = ilMethod.Parameters.Count; for (var i = 0; i < paramCount; i++) { var p = ilMethod.Parameters[i]; var type = prototype.Parameters[prototypeParamOffset++].Type; arguments.Add((ArgumentRegisterSpec)Allocate(type, false, RCategory.Argument, p)); } } else if (source.IsJava) { var javaMethod = source.JavaMethod; // Allocate this var code = javaMethod.Attributes.OfType <CodeAttribute>().First(); if (!method.IsStatic) { thisArgument = (ArgumentRegisterSpec)Allocate(method.Owner, true, RCategory.Argument, code.ThisParameter); arguments.Add(thisArgument); } // Allocate arguments foreach (var p in code.Parameters) { var type = prototype.Parameters[prototypeParamOffset++].Type; arguments.Add((ArgumentRegisterSpec)Allocate(type, false, RCategory.Argument, p.Item2)); } } else if (source.IsAst) { // Allocate this if (!method.IsStatic) { thisArgument = (ArgumentRegisterSpec)Allocate(method.Owner, true, RCategory.Argument, null); arguments.Add(thisArgument); } // Allocate arguments foreach (var p in ((XSyntheticMethodDefinition)source.Method).AstParameters) { var type = prototype.Parameters[prototypeParamOffset++].Type; arguments.Add((ArgumentRegisterSpec)Allocate(type, false, RCategory.Argument, p)); } } else { throw new ArgumentException("Unknown source"); } // Add GenericInstanceType parameter (if any) if (source.Method.NeedsGenericInstanceTypeParameter) { GenericInstanceTypeArguments = new List <ArgumentRegisterSpec>(); foreach (var param in prototype.GenericInstanceTypeParameters) { var r = (ArgumentRegisterSpec)Allocate(param.Type, false, RCategory.Argument, null); GenericInstanceTypeArguments.Add(r); arguments.Add(r); } } // Add GenericInstanceMethod parameter (if any) if (source.Method.NeedsGenericInstanceMethodParameter) { GenericInstanceMethodArguments = new List <ArgumentRegisterSpec>(); foreach (var param in prototype.GenericInstanceMethodParameters) { var r = (ArgumentRegisterSpec)Allocate(param.Type, false, RCategory.Argument, null); GenericInstanceMethodArguments.Add(r); arguments.Add(r); } } // Check register count var expected = prototype.Parameters.Sum(x => x.Type.IsWide() ? 2 : 1); if (!method.IsStatic) { expected++; } if (expected != body.Registers.Count()) { throw new ArgumentException(string.Format("Expected {0} registers, found {1} (in {2})", expected, body.Registers.Count(), method)); } }
/// <summary> /// Optimize expressions /// </summary> public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler) { foreach (var node in ast.GetExpressions(x => (x.Code == AstCode.Call) || (x.Code == AstCode.Calli) || (x.Code == AstCode.Callvirt))) { var method = (XMethodReference)node.Operand; bool processed = false; XMethodDefinition methodDef; if (method.TryResolve(out methodDef) && methodDef.DeclaringType.IsPrimitive) { if (methodDef.IsConstructor && (node.Arguments.Count == 2)) { // primitive.ctor(addressof_primitive, value) -> primitive.cast(value) var locVar = node.Arguments[0].Operand; node.Arguments.RemoveAt(0); node.SetCode(AstCode.Stloc).SetType(node.Arguments[0].GetResultType()).Operand = locVar; processed = true; } else if (methodDef.Name == "GetHashCode" && node.Arguments.Count == 1 && methodDef.HasThis) { // we try to avoid boxing. var arg = node.Arguments[0]; switch (arg.Code) { case AstCode.AddressOf: arg = arg.Arguments[0]; break; case AstCode.Ldloca: arg.SetCode(AstCode.Ldloc); arg.SetType(arg.InferredType.ElementType); break; case AstCode.Ldflda: arg.SetCode(AstCode.Ldfld); arg.SetType(arg.InferredType.ElementType); break; case AstCode.Ldsflda: arg.SetCode(AstCode.Ldsfld); arg.SetType(arg.InferredType.ElementType); break; case AstCode.Ldelema: arg.SetCode(AstCode.Ldelem_Any); arg.SetType(arg.InferredType.ElementType); break; } var type = arg.GetResultType(); if (type.IsBoolean() || type.IsFloat() || type.IsDouble() || type.IsInt64() || type.IsUInt64()) { var ch = compiler.GetDot42InternalType("CompilerHelper").Resolve(); // these need special handling var replMethod = ch.Methods.FirstOrDefault(m => m.Name == "GetHashCode" && m.IsStatic && m.Parameters[0].ParameterType.IsSame(type, true)); if (replMethod != null) { node.Operand = replMethod; node.SetCode(AstCode.Call); node.Arguments.Clear(); node.Arguments.Add(arg); } } else { // for the other primitive types, we just return the value itself. node.CopyFrom(arg); node.ExpectedType = compiler.Module.TypeSystem.Int; } processed = true; } } if (!processed) { for (var i = 0; i < node.Arguments.Count; i++) { ProcessArgument(node, method, i, currentMethod, compiler.Module); } } } }
public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler) { foreach (var block in ast.GetSelfAndChildrenRecursive <AstBlock>()) { for (int i = 0; i < block.Body.Count; ++i) { var expr = block.Body[i] as AstExpression; if (expr == null) { continue; } var interlockedPairs = expr.GetExpressionPairs(p => p.Code == AstCode.Call && ((XMethodReference)p.Operand).DeclaringType.FullName == "System.Threading.Interlocked") .ToList(); if (interlockedPairs.Count == 0) { continue; } if (interlockedPairs.Count > 1) { throw new CompilerException("The Interlocked converter can not handle more than one interlocked call per statement. Try splittig the statement up."); } var interlockedCall = interlockedPairs.First().Expression; // first parameter should be a reference to a field, // (but be lenient if we don't find what we expect) var targetExpr = interlockedCall.Arguments[0]; XFieldReference field = null; if (targetExpr.InferredType.IsByReference) { field = targetExpr.Operand as XFieldReference; if (field != null) { // check if we have an atomic updater var updater = field.DeclaringType.Resolve().Fields .FirstOrDefault(f => f.Name == field.Name + NameConstants.Atomic.FieldUpdaterPostfix); if (updater != null) { var method = (XMethodReference)interlockedCall.Operand; var methodName = method.Name.Split('$')[0]; // retrieve original name. if (InterlockedUsingUpdater(interlockedCall, methodName, field, updater, targetExpr, interlockedPairs.First().Parent, compiler)) { continue; } } } } FailsafeInterlockedUsingLocking(field, expr, targetExpr, block, i, compiler, currentMethod); } } }
public static void Convert(AstBlock ast, MethodSource currentMethod, AssemblyCompiler compiler) { var setInstructionTarget = new AstGeneratedVariable(DebuggerConstants.SetNextInstructionVariableName, null, true) { Type = compiler.Module.TypeSystem.Bool }; int labelCount = 0; var initExpr = new AstExpression(AstNode.NoSource, AstCode.Stloc, setInstructionTarget, new AstExpression(AstNode.NoSource, AstCode.Ldnull, null) .SetType(compiler.Module.TypeSystem.Int)); int lastBaseCtorCall = -1; // can't jump before base-class constructor call. if (currentMethod.IsCtor) { lastBaseCtorCall = FindLastCtorCall(ast); } ISourceLocation currentLoc = null; foreach (var block in ast.GetSelfAndChildrenRecursive <AstBlock>()) { if (block.EntryGoto != null) // only handle simple cases atm. { return; } var body = block.Body; AstLabel label = null; int firstValidExpression = -1; bool lastExprWasCall = false; var startIdx = lastBaseCtorCall == -1?0:lastBaseCtorCall + 1; lastBaseCtorCall = -1; for (int idx = startIdx; idx < body.Count; ++idx) { var expr = body[idx] as AstExpression; if (expr == null) { continue; } if (expr.SourceLocation == null) { continue; } if (expr.SourceLocation.Equals(currentLoc) && !lastExprWasCall) { continue; } currentLoc = expr.SourceLocation; lastExprWasCall = expr.Code.IsCall(); if (firstValidExpression == -1) { firstValidExpression = idx; continue; } AddJumpInstruction(body, currentLoc, setInstructionTarget, ref idx, ref label, firstValidExpression, initExpr, ref labelCount); } //if (!lastExprWasRet && firstValidExpression != -1) //{ // int idx = body.Count; // AddJumpInstruction(body, currentLoc, setInstructionTarget, ref idx, // ref label, firstValidExpression, initExpr, ref labelCount); //} } }
/// <summary> /// Get a compiled method info for the given method. /// Create if needed. /// </summary> private CompiledMethod GetOrCreateCompileMethod(MethodSource method) { return(GetOrCreateCompileMethod(method.Method)); }
private static void FailsafeInterlockedUsingLocking(XFieldReference field, AstExpression expr, AstExpression targetExpr, AstBlock block, int idx, AssemblyCompiler compiler, MethodSource currentMethod) { if (currentMethod.IsDotNet && !currentMethod.ILMethod.DeclaringType.HasSuppressMessageAttribute("InterlockedFallback")) { bool isStatic = field != null && field.Resolve().IsStatic; DLog.Warning(DContext.CompilerCodeGenerator, "Emulating Interlocked call using failsafe locking mechanism in {0}{1}. Consider using AtomicXXX classes instead. You can suppress this message with an [SuppressMessage(\"dot42\", \"InterlockedFallback\")] attribute on the class.", currentMethod.Method.FullName, !isStatic ? "" : " because a static field is referenced"); } // replace with: // Monitor.Enter(); // try { <original expression> } finally { Monitor.Exit(); } // // note that the lock is larger than it has to be, since it also sourrounds // the parameter evaluation. // It must sourround the storing and loading of the reference parameters though. var typeSystem = compiler.Module.TypeSystem; var monitorType = compiler.GetDot42InternalType("System.Threading", "Monitor"); var enterMethod = monitorType.Resolve().Methods.Single(p => p.Name == "Enter"); var exitMethod = monitorType.Resolve().Methods.Single(p => p.Name == "Exit"); AstExpression loadLockTarget = null; if (field != null) { if (field.Resolve().IsStatic) { // lock on the field's class typedef. // but always the element type, not on a generic instance (until Dot42 implements proper generic static field handling) loadLockTarget = new AstExpression(expr.SourceLocation, AstCode.LdClass, field.DeclaringType.GetElementType()) .SetType(typeSystem.Type); } else { // lock on the fields object loadLockTarget = targetExpr.Arguments[0]; } } if (loadLockTarget == null) { // something went wrong. use a global lock. DLog.Warning(DContext.CompilerCodeGenerator, "unable to infer target of Interlocked call. using global lock."); var interlockedType = compiler.GetDot42InternalType("System.Threading", "Interlocked"); loadLockTarget = new AstExpression(expr.SourceLocation, AstCode.LdClass, interlockedType) .SetType(typeSystem.Type); } var lockVar = new AstGeneratedVariable("lockTarget$", "") { Type = typeSystem.Object }; var storeLockVar = new AstExpression(expr.SourceLocation, AstCode.Stloc, lockVar, loadLockTarget); var loadLockVar = new AstExpression(expr.SourceLocation, AstCode.Ldloc, lockVar); var enterCall = new AstExpression(expr.SourceLocation, AstCode.Call, enterMethod, storeLockVar); var replacementBlock = new AstBlock(expr.SourceLocation); replacementBlock.Body.Add(enterCall); var tryCatch = new AstTryCatchBlock(expr.SourceLocation) { TryBlock = new AstBlock(expr.SourceLocation, expr), FinallyBlock = new AstBlock(expr.SourceLocation, new AstExpression(block.SourceLocation, AstCode.Call, exitMethod, loadLockVar)) }; replacementBlock.Body.Add(tryCatch); if (block.EntryGoto == expr) { block.EntryGoto = enterCall; } block.Body[idx] = replacementBlock; }
/// <summary> /// Perform all dot42 related Ast conversions. /// </summary> public static void Convert(DecompilerContext context, AstBlock ast, MethodSource currentMethod, AssemblyCompiler compiler, StopAstConversion stop = StopAstConversion.None) { if (ast.IsOptimizedForTarget) return; #if DEBUG //Debugger.Launch(); if ((currentMethod.Method != null) && (currentMethod.Method.Name.Equals("runTest", StringComparison.OrdinalIgnoreCase))) { //Debugger.Launch(); } #endif IntPtrConverter.Convert(ast, compiler); if (stop == StopAstConversion.AfterIntPtrConverter) return; TypeOfConverter.Convert(ast, compiler); if (stop == StopAstConversion.AfterTypeOfConverter) return; // TODO: check if we actually need this optimizer, as we have a more throughoutful // optimizer as the last step. BranchOptimizer.Convert(ast); if (stop == StopAstConversion.AfterBranchOptimizer) return; CompoundAssignmentConverter.Convert(ast); if (stop == StopAstConversion.AfterCompoundAssignmentConverter) return; // keep this order FixAsyncStateMachine.Convert(ast, currentMethod, compiler); if (stop == StopAstConversion.AfterFixAsyncStateMachine) return; InterlockedConverter.Convert(ast, currentMethod, compiler); if (stop == StopAstConversion.AfterInterlockedConverter) return; ByReferenceParamConverter.Convert(context, ast, compiler); if (stop == StopAstConversion.AfterByReferenceParamConverter) return; // end CompareUnorderedConverter.Convert(ast); if (stop == StopAstConversion.AfterCompareUnorderedConverter) return; EnumConverter.Convert(ast, compiler); if (stop == StopAstConversion.AfterEnumConverter) return; EnumOptimizer.Convert(ast, compiler); if (stop == StopAstConversion.AfterEnumOptimizer) return; // Keep this order NullableConverter.Convert(ast, compiler); if (stop == StopAstConversion.AfterNullableConverter) return; PrimitiveAddressOfConverter.Convert(ast, currentMethod, compiler); if (stop == StopAstConversion.AfterPrimitiveAddressOfConverter) return; StructCallConverter.Convert(ast, compiler); if (stop == StopAstConversion.AfterStructCallConverter) return; // end InitializeStructVariablesConverter.Convert(ast); if (stop == StopAstConversion.AfterInitializeStructVariablesConverter) return; DelegateConverter.Convert(ast); if (stop == StopAstConversion.AfterDelegateConverter) return; LdcWideConverter.Convert(ast); if (stop == StopAstConversion.AfterLdcWideConverter) return; LdLocWithConversionConverter.Convert(ast); if (stop == StopAstConversion.AfterLdLocWithConversionConverter) return; ConvertAfterLoadConversionConverter.Convert(ast); if (stop == StopAstConversion.AfterConvertAfterLoadConversionConverter) return; ConvertBeforeStoreConversionConverter.Convert(ast); if (stop == StopAstConversion.AfterConvertBeforeStoreConversionConverter) return; CleanupConverter.Convert(ast); if (stop == StopAstConversion.AfterCleanupConverter) return; GenericsConverter.Convert(ast, currentMethod, compiler.Module.TypeSystem); if (stop == StopAstConversion.AfterGenericsConverter) return; // Expand cast expressions CastConverter.Convert(ast, currentMethod, compiler); if (stop == StopAstConversion.AfterCastConverter) return; // Expand generic instance information GenericInstanceConverter.Convert(ast, currentMethod, compiler); if (stop == StopAstConversion.AfterGenericInstanceConverter) return; // run the branch optimizer again. (do we need the first invocation?) BranchOptimizer2.Convert(ast, compiler); if (stop == StopAstConversion.AfterBranchOptimizer2) return; }
public DynamicSourceLocation(MethodSource source, SourceFile file, int line, int column) { if (source.IsManaged) { this.function = source.Function; this.module = function.Module; } else { this.module = source.Module; this.source = source; } this.file = file; this.line = line; this.column = column; }
/// <summary> /// Generate method code /// </summary> public virtual void GenerateCode(ClassDefinition declaringClass, DexTargetPackage targetPackage) { if (dmethod == null) return; // Create body (if any) if (method.HasBody) { ExpandSequencePoints(method.Body); var source = new MethodSource(xMethod, method); DexMethodBodyCompiler.TranslateToRL(compiler, targetPackage, source, dmethod, out compiledMethod); } }
public void PrintMethods(MethodSource[] methods) { for (int i = 0; i < methods.Length; i++) { interpreter.Print ("{0,4} {1}", i+1, methods [i].Name); } }
public static bool AllowsSource(this SourceRestrictions restriction, MethodSource source) { return(source.ValidForRestriction(restriction)); }
/// <summary> /// Optimize expressions /// </summary> public static void Convert(AstNode ast, MethodSource currentMethod, XTypeSystem typeSystem) { // Expand typeof foreach (var pair in ast.GetExpressionPairs()) { var node = pair.Expression; switch (node.Code) { case AstCode.Ldfld: //case AstCode.Ldsfld: // NOT YET { var field = (XFieldReference)node.Operand; UnboxIfGeneric(field.FieldType, node, typeSystem); } break; case AstCode.Stfld: { var field = (XFieldReference)node.Operand; BoxIfGeneric(field.FieldType, node.Arguments[1]); } break; case AstCode.Call: case AstCode.Calli: case AstCode.Callvirt: { var method = (XMethodReference)node.Operand; if ((!method.ReturnType.IsVoid()) && (pair.Parent != null)) { UnboxIfGeneric(method.ReturnType, node, typeSystem); } } break; case AstCode.Ret: { if (node.Arguments.Count > 0) { var expectedType = currentMethod.Method.ReturnType; BoxIfGeneric(expectedType, node.Arguments[0]); } } break; case AstCode.Box: { var type = (XTypeReference)node.Operand; // Honestly, the whole Generics code seems to be quite // complex. I hope this fix does not break anything else. // Also: is there any sense in having two codes 'box' and 'boxtogeneric'? // The Rosyln compiler apparently uses 'box' instructions to satisfy // generic constraints. Not sure if this is the right place to handle // this. // What we want to achive is to perform this conversion code only if the // expected type is assignable from any of the constraints. As we do not // have an 'IsAssignableFrom' logic for XTypes, a simpler check must suffice. if (type.IsGenericParameter && ((XGenericParameter)type).Constraints.Any() && node.ExpectedType != null && !node.ExpectedType.IsPrimitive && !node.ExpectedType.IsGenericParameter) { // or just enter the required cast here??? node.Code = AstCode.BoxToGeneric; node.InferredType = node.ExpectedType; } } break; case AstCode.ByRefArray: case AstCode.ByRefOutArray: { if (node.Arguments.Count > 1) { var originalType = (XTypeReference)node.Arguments[1].Operand; UnboxByRefIfGeneric(originalType, node.StoreByRefExpression, typeSystem); } } break; } } }
/// <summary> /// Build expressions that are used when calling a .NET method with generic instance parameters, one expression for /// each required parameter. /// </summary> private static IList<AstExpression> CreateGenericInstanceCallArguments(ISourceLocation seqp, XReference member, MethodSource currentMethod, AssemblyCompiler compiler) { // Prepare var genericInstance = member as IXGenericInstance; if (genericInstance == null) { #if DEBUG //Debugger.Launch(); #endif throw new CompilerException(string.Format("{0} is not a generic instance", member)); } var count = genericInstance.GenericArguments.Count; var typeHelperType = compiler.GetDot42InternalType(InternalConstants.TypeHelperName).Resolve(); // Foreach type argument var typeExpressions = new List<AstExpression>(); for (var i = 0; i < count; i++) { var argType = genericInstance.GenericArguments[i]; var typeExpr = LoadTypeForGenericInstance(seqp, currentMethod, argType, compiler, typeHelperType, compiler.Module.TypeSystem, TypeConversion.EnsureTrueOrMarkerType); typeExpressions.Add(typeExpr); } bool isMethod = member is XMethodReference; bool buildArray = count > (isMethod ? InternalConstants.GenericMethodParametersAsArrayThreshold : InternalConstants.GenericTypeParametersAsArrayThreshold); if (buildArray) { //TODO: when we can determine that all expressions just load our classes generic instance (array) field, // and extract all values in sequence, we should shortcut and just return a load of the field, // instead of unpacking and re-packing each value, putting pressure on the garbage collector // in the process. This is not a huge problem any longer, as we do not use arrays as often // as we used to. Nevertheless, where arrays are used, possible re-use should be faily common, // e.g. when instatiating nested classes or invoking static methods. var elementType = compiler.Module.TypeSystem.Type; return new [] { new AstExpression(seqp, AstCode.InitArrayFromArguments, new XArrayType(elementType), typeExpressions) { ExpectedType = new XArrayType(elementType) }}; } else { return typeExpressions; } }
void ProcessArgument(AstExpression callNode, XMethodReference methodRef, int argumentIndex, MethodSource currentMethod, XModule assembly) { var node = callNode.Arguments[argumentIndex]; // Should we do something? switch (node.Code) { case AstCode.Ldloca: // Parameter case AstCode.AddressOf: // Local variable case AstCode.Ldflda: // Instance field case AstCode.Ldsflda: // Static field case AstCode.Ldelema: // Array break; case AstCode.Ldloc: if (!node.MatchThis() || !currentMethod.IsDotNet) { return; } break; default: return; } // Process argument var method = methodRef.Resolve(); var argIsThis = !method.IsStatic && (argumentIndex == 0); var parameterIndex = method.IsStatic ? argumentIndex : argumentIndex - 1; var parameter = argIsThis ? null : method.Parameters[parameterIndex]; var argType = argIsThis ? method.DeclaringType : parameter.ParameterType; //var argAttrs = argIsThis ? ParameterAttributes.None : parameter.Attributes; var argIsByRef = argType.IsByReference; var argIsOut = argIsThis ? false : argIsByRef && (parameter.Kind == XParameterKind.Output); // argIsByRef && argAttrs.HasFlag(ParameterAttributes.Out); var argIsGenByRefParam = argIsByRef && argType.ElementType.IsGenericParameter; switch (node.Code) { case AstCode.Ldloca: // Parameter { var variable = ((AstVariable)node.Operand); if (variable.Type.IsPrimitive || argIsByRef) { // Box first var ldloc = new AstExpression(node.SourceLocation, AstCode.Ldloc, node.Operand) { InferredType = variable.Type }; if (argIsByRef) { var stloc = new AstExpression(node.SourceLocation, AstCode.Stloc, node.Operand) { InferredType = variable.Type }; stloc.Arguments.Add(GetValueOutOfByRefArray(node, variable.Type, argIsGenByRefParam, assembly)); ConvertToByRefArray(node, variable.Type, ldloc, stloc, argIsOut, argIsGenByRefParam, argType.ElementType, assembly); } else { ConvertToBox(node, variable.Type, ldloc); } } else if (variable.Type.IsGenericParameter) { // Convert to ldarg var ldloc = new AstExpression(node.SourceLocation, AstCode.Ldloc, node.Operand) { InferredType = variable.Type }; callNode.Arguments[argumentIndex] = ldloc; } } break; case AstCode.Ldloc: // this { var variable = ((AstVariable)node.Operand); if (argIsThis && (variable.Type.IsByReference)) { node.SetType(variable.Type.ElementType); } else if (argIsByRef) { var ldclone = new AstExpression(node); var stExpr = new AstExpression(node.SourceLocation, AstCode.Nop, null); var elementType = variable.Type; if (elementType.IsByReference) { elementType = elementType.ElementType; } ConvertToByRefArray(node, elementType, ldclone, stExpr, argIsOut, argIsGenByRefParam, argType.ElementType, assembly); } } break; case AstCode.AddressOf: // Local variable { var arg = node.Arguments[0]; var type = arg.GetResultType(); var typeDef = type.Resolve(); if (typeDef.IsPrimitive) { if (argIsByRef) { throw new CompilerException("Unsupported use of AddressOf by byref argument"); } else { ConvertToBox(node, type, arg); } } } break; case AstCode.Ldflda: // Instance field case AstCode.Ldsflda: // Static field { var fieldRef = (XFieldReference)node.Operand; var field = fieldRef.Resolve(); if (field.FieldType.IsPrimitive || argIsByRef) { // Box first var ldfldCode = (node.Code == AstCode.Ldflda) ? AstCode.Ldfld : AstCode.Ldsfld; var ldfld = new AstExpression(node.SourceLocation, ldfldCode, node.Operand) { InferredType = field.FieldType }; ldfld.Arguments.AddRange(node.Arguments); if (argIsByRef) { var stfldCode = (node.Code == AstCode.Ldflda) ? AstCode.Stfld : AstCode.Stsfld; var stfld = new AstExpression(node.SourceLocation, stfldCode, node.Operand) { InferredType = field.FieldType }; stfld.Arguments.AddRange(node.Arguments); // instance stfld.Arguments.Add(GetValueOutOfByRefArray(node, field.FieldType, argIsGenByRefParam, assembly)); // value ConvertToByRefArray(node, field.FieldType, ldfld, stfld, argIsOut, argIsGenByRefParam, argType.ElementType, assembly); } else { ConvertToBox(node, field.FieldType, ldfld); } } } break; case AstCode.Ldelema: // Array element { var array = node.Arguments[0]; var arrayType = array.GetResultType(); var type = arrayType.ElementType; if (type.IsPrimitive || argIsByRef) { // Box first var ldElemCode = type.GetLdElemCode(); var ldelem = new AstExpression(node.SourceLocation, ldElemCode, node.Operand) { InferredType = type }; ldelem.Arguments.AddRange(node.Arguments); if (argIsByRef) { var stelemCode = type.GetStElemCode(); var stelem = new AstExpression(node.SourceLocation, stelemCode, node.Operand) { InferredType = type }; stelem.Arguments.AddRange(node.Arguments); stelem.Arguments.Add(GetValueOutOfByRefArray(node, type, argIsGenByRefParam, assembly)); ConvertToByRefArray(node, type, ldelem, stelem, argIsOut, argIsGenByRefParam, argType.ElementType, assembly); } else { ConvertToBox(node, type, ldelem); } } } break; } }
/// <summary> /// Create an expression that loads the given type at runtime. /// </summary> private static AstExpression LoadTypeForGenericInstance(ISourceLocation seqp, MethodSource currentMethod, XTypeReference type, AssemblyCompiler compiler, XTypeDefinition typeHelperType, XTypeSystem typeSystem, TypeConversion typeConversion, XGenericInstanceType typeGenericArguments=null) { if (type.IsArray) { // Array type var arrayType = (XArrayType)type; // Load element type var prefix = LoadTypeForGenericInstance(seqp, currentMethod, ((XArrayType)type).ElementType, compiler, typeHelperType, typeSystem, typeConversion); // Convert to array type if (arrayType.Dimensions.Count() == 1) { var giCreateArray = typeHelperType.Methods.Single(x => (x.Name == "Array") && (x.Parameters.Count == 1)); return new AstExpression(seqp, AstCode.Call, giCreateArray, prefix) { ExpectedType = typeSystem.Type }; } else { var giCreateArray = typeHelperType.Methods.Single(x => (x.Name == "Array") && (x.Parameters.Count == 2)); var dimensionsExpr = new AstExpression(seqp, AstCode.Ldc_I4, arrayType.Dimensions.Count()) { ExpectedType = typeSystem.Int }; return new AstExpression(seqp, AstCode.Call, giCreateArray, prefix, dimensionsExpr) { ExpectedType = typeSystem.Type }; } } var gp = type as XGenericParameter; if (gp != null) { AstExpression loadExpr; if (gp.Owner is XTypeReference) { // Class type parameter var owner = (XTypeReference)gp.Owner; if (owner.GetElementType().Resolve().HasDexImportAttribute()) { // Imported type return new AstExpression(seqp, AstCode.TypeOf, typeSystem.Object) { ExpectedType = typeSystem.Type }; } if (currentMethod.IsClassCtor) { // Class ctor's cannot have type information. // Return Object instead if(currentMethod.IsDotNet && !currentMethod.ILMethod.DeclaringType.HasSuppressMessageAttribute("StaticConstructorUsesGenericParameter")) { var msg = "Class (static) constructor of '{0}' tries to use generic parameter. This will always yield Object. " + "You can suppress this warning with a [SuppressMessage(\"dot42\", \"StaticConstructorUsesGenericParameter\")] " + "attribute on the class."; if(seqp != null && seqp.Document != null) DLog.Warning(DContext.CompilerCodeGenerator, seqp.Document, seqp.StartColumn,seqp.StartLine, msg, currentMethod.DeclaringTypeFullName); else DLog.Warning(DContext.CompilerCodeGenerator, msg, currentMethod.DeclaringTypeFullName); } return new AstExpression(seqp, AstCode.TypeOf, typeSystem.Object) { ExpectedType = typeSystem.Type }; } loadExpr = currentMethod.IsStatic ? LoadStaticClassGenericArgument(seqp, typeSystem, currentMethod.Method, gp.Position) : LoadInstanceClassGenericArgument(seqp, typeSystem, currentMethod.Method.DeclaringType, gp.Position); } else { // Method type parameter var owner = (XMethodReference)gp.Owner; if (owner.GetElementMethod().Resolve().DeclaringType.HasDexImportAttribute()) { // Imported type return LoadTypeForGenericInstance(seqp, currentMethod, type.Module.TypeSystem.Object, compiler, typeHelperType, typeSystem, typeConversion); } loadExpr = LoadMethodGenericArgument(seqp, typeSystem, currentMethod.Method, gp.Position); } if (typeConversion == TypeConversion.EnsureRuntimeType) return EnsureGenericRuntimeType(loadExpr, typeSystem, typeHelperType); else return loadExpr; } if (type is XTypeSpecification) { var typeSpec = (XTypeSpecification)type; var git = type as XGenericInstanceType; var baseType = LoadTypeForGenericInstance(seqp, currentMethod, typeSpec.ElementType, compiler, typeHelperType, typeSystem, typeConversion, git); if (typeConversion != TypeConversion.EnsureTrueOrMarkerType || typeSpec.GetElementType().IsNullableT()) return baseType; // Use the element type and make a generic proxy with the generic arguments. var parameters = CreateGenericInstanceCallArguments(seqp, git, currentMethod, compiler); if (parameters.Count == 1 && parameters[0].GetResultType().IsArray) { // array type call. var method = typeHelperType.Methods.Single(m => m.Name == "GetGenericInstanceType" && m.Parameters.Count == 2 && m.Parameters[1].ParameterType.IsArray); return new AstExpression(seqp, AstCode.Call, method, baseType, parameters[0]); } else { parameters.Insert(0, baseType); var method = typeHelperType.Methods.Single(m => m.Name == "GetGenericInstanceType" && m.Parameters.Count == parameters.Count && !m.Parameters[1].ParameterType.IsArray); return new AstExpression(seqp, AstCode.Call, method, parameters.ToArray()); } } if (typeConversion == TypeConversion.EnsureTrueOrMarkerType && type.GetElementType().IsNullableT()) { if (typeGenericArguments != null) { var underlying = typeGenericArguments.GenericArguments[0]; var code = underlying.IsPrimitive ? AstCode.BoxedTypeOf : AstCode.NullableTypeOf; return new AstExpression(seqp, code, underlying) { ExpectedType = typeSystem.Type }; } // if typeGenericArguments is null, this is a generic definition, e.g. typeof(Nullable<>). } // Plain type reference or definition return new AstExpression(seqp, AstCode.TypeOf, type) { ExpectedType = typeSystem.Type }; }
internal MethodBody(MethodSource method) { this.method = method; }
/// <summary> /// Optimize expressions /// </summary> public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler) { var typeSystem = compiler.Module.TypeSystem; // Expand typeof foreach (var node in ast.GetSelfAndChildrenRecursive<AstExpression>(x => x.Code == AstCode.TypeOf)) { var type = (XTypeReference) node.Operand; var typeHelperType = compiler.GetDot42InternalType(InternalConstants.TypeHelperName).Resolve(); var loadExpr = LoadTypeForGenericInstance(node.SourceLocation, currentMethod, type, compiler, typeHelperType, typeSystem, TypeConversion.EnsureTrueOrMarkerType); node.CopyFrom(loadExpr); } // Expand instanceOf foreach (var node in ast.GetSelfAndChildrenRecursive<AstExpression>(x => x.Code == AstCode.SimpleInstanceOf)) { var type = (XTypeReference)node.Operand; var gp = type as XGenericParameter; if (gp == null) continue; var typeHelperType = compiler.GetDot42InternalType(InternalConstants.TypeHelperName).Resolve(); var loadExpr = LoadTypeForGenericInstance(node.SourceLocation, currentMethod, type, compiler, typeHelperType, typeSystem, TypeConversion.EnsureRuntimeType); //// both types are boxed, no need for conversion. var typeType = compiler.GetDot42InternalType("System", "Type").Resolve(); var isInstanceOfType = typeType.Methods.Single(n => n.Name == "JavaIsInstance" && n.Parameters.Count == 1); var call = new AstExpression(node.SourceLocation, AstCode.Call, isInstanceOfType, loadExpr, node.Arguments[0]); node.CopyFrom(call); } // Expand newarr foreach (var node in ast.GetSelfAndChildrenRecursive<AstExpression>(x => x.Code == AstCode.Newarr)) { var type = (XTypeReference)node.Operand; if (!type.IsDefinitionOrReferenceOrPrimitive()) { // Resolve type to a Class<?> var typeHelperType = compiler.GetDot42InternalType(InternalConstants.TypeHelperName).Resolve(); // while having primitive arrays for primitive types would be nice, a lot of boxing and unboxing // would be needed. only for-primitive-specialized generic classes we could optimize this. var ldType = LoadTypeForGenericInstance(node.SourceLocation, currentMethod, type, compiler, typeHelperType, typeSystem, TypeConversion.EnsureRuntimeType); var newInstanceExpr = new AstExpression(node.SourceLocation, AstCode.ArrayNewInstance, null, ldType, node.Arguments[0]) { ExpectedType = typeSystem.Object }; var arrayType = new XArrayType(type); var cast = new AstExpression(node.SourceLocation, AstCode.SimpleCastclass, arrayType, newInstanceExpr) { ExpectedType = arrayType }; node.CopyFrom(cast); } } // Add generic instance call arguments foreach (var node in ast.GetSelfAndChildrenRecursive<AstExpression>(x => x.Code.IsCall())) { var method = (XMethodReference)node.Operand; if (method.DeclaringType.IsArray) continue; XMethodDefinition methodDef; if (!method.TryResolve(out methodDef)) continue; if (methodDef.HasDexNativeAttribute()) continue; if (methodDef.NeedsGenericInstanceTypeParameter) { // Add generic instance type parameter value var arg = CreateGenericInstanceCallArguments(node.SourceLocation, method.DeclaringType, currentMethod, compiler); node.Arguments.AddRange(arg); node.GenericInstanceArgCount += arg.Count; } if (methodDef.NeedsGenericInstanceMethodParameter) { // Add generic instance method parameter var arg = CreateGenericInstanceCallArguments(node.SourceLocation, method, currentMethod, compiler); node.Arguments.AddRange(arg); node.GenericInstanceArgCount += arg.Count; } } // Add generic instance Delegate arguments for static methods. foreach (var node in ast.GetSelfAndChildrenRecursive<AstExpression>(x => x.Code == AstCode.Delegate)) { var delegateInfo = (Tuple<XTypeDefinition, XMethodReference>)node.Operand; var genMethodDef = delegateInfo.Item2 as IXGenericInstance; var genTypeDef = delegateInfo.Item2.DeclaringType as IXGenericInstance; // Add generic instance type parameter value, if method is static if (genTypeDef != null && delegateInfo.Item2.Resolve().IsStatic) { var arg = CreateGenericInstanceCallArguments(node.SourceLocation, delegateInfo.Item2.DeclaringType, currentMethod, compiler); node.Arguments.AddRange(arg); node.GenericInstanceArgCount += arg.Count; } // add generic method type parameter value. if (genMethodDef != null) { var arg = CreateGenericInstanceCallArguments(node.SourceLocation, delegateInfo.Item2, currentMethod, compiler); node.Arguments.AddRange(arg); node.GenericInstanceArgCount += arg.Count; } } // Convert NewObj when needed foreach (var node in ast.GetSelfAndChildrenRecursive<AstExpression>(x => x.Code == AstCode.Newobj)) { var ctorRef = (XMethodReference)node.Operand; var declaringType = ctorRef.DeclaringType; if (declaringType.IsArray) { // New multi dimensional array // Get element type var elemType = ((XArrayType) declaringType).ElementType; var typeExpr = new AstExpression(node.SourceLocation, AstCode.TypeOf, elemType); // Create dimensions array var intArrayType = new XArrayType(typeSystem.Int); var dimArrayExpr = new AstExpression(node.SourceLocation, AstCode.InitArrayFromArguments, intArrayType, node.Arguments).SetType(intArrayType); // Call java.lang.reflect.Array.newInstance(type, int[]) var newInstanceExpr = new AstExpression(node.SourceLocation, AstCode.ArrayNewInstance2, null, typeExpr, dimArrayExpr).SetType(typeSystem.Object); // Cast to correct type var cast = new AstExpression(node.SourceLocation, AstCode.SimpleCastclass, declaringType, newInstanceExpr).SetType(declaringType); // Replace node node.CopyFrom(cast); } else { // Normal "new object" XMethodDefinition ctorDef; if (ctorRef.TryResolve(out ctorDef) && ctorDef.NeedsGenericInstanceTypeParameter) { // Add generic instance type parameter value var arg = CreateGenericInstanceCallArguments(node.SourceLocation, ctorRef.DeclaringType, currentMethod, compiler); node.Arguments.AddRange(arg); node.GenericInstanceArgCount += arg.Count; } } } }
/// <summary> /// Returns the hash code of this object. /// </summary> /// <returns>The hash code of this object.</returns> public override int GetHashCode() => MethodSource.GetHashCode() ^ IndexType.GetHashCode();
internal BreakpointHandle ResolveBreakpoint(Breakpoint breakpoint) { if (!module.IsLoaded) return null; if ((function == null) && (source == null)) { if (file != null) { source = file.FindMethod (line); } else { throw new TargetException (TargetError.LocationInvalid); } if ((source != null) && source.IsManaged) function = source.Function; } if (function != null) return function.GetBreakpointHandle (breakpoint, line, column); if ((source == null) || source.IsManaged) throw new TargetException (TargetError.LocationInvalid); TargetAddress address = GetAddress (); if (!address.IsNull) return new AddressBreakpointHandle (breakpoint, address); return null; }
protected override bool DoResolve(ScriptingContext context) { int line = -1; int pos = Argument.IndexOf (':'); if (pos >= 0) { string filename = Argument.Substring (0, pos); try { line = (int) UInt32.Parse (Argument.Substring (pos+1)); } catch { throw new ScriptingException ("Expected filename:line"); } return FindFile (context, filename, line); } if (Argument == "") { StackFrame frame = context.CurrentFrame; if (frame.SourceAddress == null) return false; if (frame.SourceLocation != null) location = frame.SourceLocation; else address = frame.SourceAddress; return true; } try { line = (int) UInt32.Parse (Argument); } catch { } if (line != -1) { location = context.CurrentLocation; if (location.FileName == null) throw new ScriptingException ( "Location doesn't have any source code."); return FindFile (context, location.FileName, line); } MethodExpression mexpr; try { Expression expr = ParseExpression (context); if (expr == null) return false; mexpr = expr.ResolveMethod (context, type); } catch { mexpr = null; } if (mexpr != null) { TargetFunctionType func; try { func = mexpr.EvaluateMethod (context, type, null); } catch { func = null; } if (func != null) method = func.GetSourceCode (); location = mexpr.EvaluateSource (context); } else location = context.FindMethod (Argument); if (location == null) throw new ScriptingException ( "Location doesn't have any source code."); return true; }
public SourceLocation(MethodSource source, SourceFile file, int line) : this(source, file, line, -1) { }
/// <summary> /// Build expressions that are used when calling a .NET method with generic instance parameters, one expression for /// each required parameter. /// </summary> private static IList <AstExpression> CreateGenericInstanceCallArguments(ISourceLocation seqp, XReference member, MethodSource currentMethod, AssemblyCompiler compiler) { // Prepare var genericInstance = member as IXGenericInstance; if (genericInstance == null) { #if DEBUG //Debugger.Launch(); #endif throw new CompilerException(string.Format("{0} is not a generic instance", member)); } var count = genericInstance.GenericArguments.Count; var typeHelperType = compiler.GetDot42InternalType(InternalConstants.TypeHelperName).Resolve(); // Foreach type argument var typeExpressions = new List <AstExpression>(); for (var i = 0; i < count; i++) { var argType = genericInstance.GenericArguments[i]; var typeExpr = LoadTypeForGenericInstance(seqp, currentMethod, argType, compiler, typeHelperType, compiler.Module.TypeSystem, TypeConversion.EnsureTrueOrMarkerType); typeExpressions.Add(typeExpr); } bool isMethod = member is XMethodReference; bool buildArray = count > (isMethod ? InternalConstants.GenericMethodParametersAsArrayThreshold : InternalConstants.GenericTypeParametersAsArrayThreshold); if (buildArray) { //TODO: when we can determine that all expressions just load our classes generic instance (array) field, // and extract all values in sequence, we should shortcut and just return a load of the field, // instead of unpacking and re-packing each value, putting pressure on the garbage collector // in the process. This is not a huge problem any longer, as we do not use arrays as often // as we used to. Nevertheless, where arrays are used, possible re-use should be faily common, // e.g. when instatiating nested classes or invoking static methods. var elementType = compiler.Module.TypeSystem.Type; return(new [] { new AstExpression(seqp, AstCode.InitArrayFromArguments, new XArrayType(elementType), typeExpressions) { ExpectedType = new XArrayType(elementType) } }); } else { return(typeExpressions); } }
public static void Convert(AstBlock ast, MethodSource currentMethod, AssemblyCompiler compiler) { var setInstructionTarget = new AstGeneratedVariable(DebuggerConstants.SetNextInstructionVariableName, null, true) { Type = compiler.Module.TypeSystem.Bool }; int labelCount = 0; var initExpr = new AstExpression(AstNode.NoSource, AstCode.Stloc, setInstructionTarget, new AstExpression(AstNode.NoSource, AstCode.Ldnull, null) .SetType(compiler.Module.TypeSystem.Int)); int lastBaseCtorCall = -1; // can't jump before base-class constructor call. if (currentMethod.IsCtor) lastBaseCtorCall = FindLastCtorCall(ast); ISourceLocation currentLoc = null; foreach (var block in ast.GetSelfAndChildrenRecursive<AstBlock>()) { if (block.EntryGoto != null) // only handle simple cases atm. return; var body = block.Body; AstLabel label = null; int firstValidExpression = -1; bool lastExprWasCall = false; var startIdx = lastBaseCtorCall == -1?0:lastBaseCtorCall + 1; lastBaseCtorCall = -1; for (int idx = startIdx; idx < body.Count; ++idx) { var expr = body[idx] as AstExpression; if(expr == null) continue; if (expr.SourceLocation == null) continue; if (expr.SourceLocation.Equals(currentLoc) && !lastExprWasCall) continue; currentLoc = expr.SourceLocation; lastExprWasCall = expr.Code.IsCall(); if (firstValidExpression == -1) { firstValidExpression = idx; continue; } AddJumpInstruction(body, currentLoc, setInstructionTarget, ref idx, ref label, firstValidExpression, initExpr, ref labelCount); } //if (!lastExprWasRet && firstValidExpression != -1) //{ // int idx = body.Count; // AddJumpInstruction(body, currentLoc, setInstructionTarget, ref idx, // ref label, firstValidExpression, initExpr, ref labelCount); //} } }
/// <summary> /// Optimize expressions /// </summary> public static void Convert(AstNode ast, MethodSource currentMethod, AssemblyCompiler compiler) { var typeSystem = compiler.Module.TypeSystem; // Expand typeof foreach (var node in ast.GetSelfAndChildrenRecursive <AstExpression>(x => x.Code == AstCode.TypeOf)) { var type = (XTypeReference)node.Operand; var typeHelperType = compiler.GetDot42InternalType(InternalConstants.TypeHelperName).Resolve(); var loadExpr = LoadTypeForGenericInstance(node.SourceLocation, currentMethod, type, compiler, typeHelperType, typeSystem, TypeConversion.EnsureTrueOrMarkerType); node.CopyFrom(loadExpr); } // Expand instanceOf foreach (var node in ast.GetSelfAndChildrenRecursive <AstExpression>(x => x.Code == AstCode.SimpleInstanceOf)) { var type = (XTypeReference)node.Operand; var gp = type as XGenericParameter; if (gp == null) { continue; } var typeHelperType = compiler.GetDot42InternalType(InternalConstants.TypeHelperName).Resolve(); var loadExpr = LoadTypeForGenericInstance(node.SourceLocation, currentMethod, type, compiler, typeHelperType, typeSystem, TypeConversion.EnsureRuntimeType); //// both types are boxed, no need for conversion. var typeType = compiler.GetDot42InternalType("System", "Type").Resolve(); var isInstanceOfType = typeType.Methods.Single(n => n.Name == "JavaIsInstance" && n.Parameters.Count == 1); var call = new AstExpression(node.SourceLocation, AstCode.Call, isInstanceOfType, loadExpr, node.Arguments[0]); node.CopyFrom(call); } // Expand newarr foreach (var node in ast.GetSelfAndChildrenRecursive <AstExpression>(x => x.Code == AstCode.Newarr)) { var type = (XTypeReference)node.Operand; if (!type.IsDefinitionOrReferenceOrPrimitive()) { // Resolve type to a Class<?> var typeHelperType = compiler.GetDot42InternalType(InternalConstants.TypeHelperName).Resolve(); // while having primitive arrays for primitive types would be nice, a lot of boxing and unboxing // would be needed. only for-primitive-specialized generic classes we could optimize this. var ldType = LoadTypeForGenericInstance(node.SourceLocation, currentMethod, type, compiler, typeHelperType, typeSystem, TypeConversion.EnsureRuntimeType); var newInstanceExpr = new AstExpression(node.SourceLocation, AstCode.ArrayNewInstance, null, ldType, node.Arguments[0]) { ExpectedType = typeSystem.Object }; var arrayType = new XArrayType(type); var cast = new AstExpression(node.SourceLocation, AstCode.SimpleCastclass, arrayType, newInstanceExpr) { ExpectedType = arrayType }; node.CopyFrom(cast); } } // Add generic instance call arguments foreach (var node in ast.GetSelfAndChildrenRecursive <AstExpression>(x => x.Code.IsCall())) { var method = (XMethodReference)node.Operand; if (method.DeclaringType.IsArray) { continue; } XMethodDefinition methodDef; if (!method.TryResolve(out methodDef)) { continue; } if (methodDef.HasDexNativeAttribute()) { continue; } if (methodDef.NeedsGenericInstanceTypeParameter) { // Add generic instance type parameter value var arg = CreateGenericInstanceCallArguments(node.SourceLocation, method.DeclaringType, currentMethod, compiler); node.Arguments.AddRange(arg); node.GenericInstanceArgCount += arg.Count; } if (methodDef.NeedsGenericInstanceMethodParameter) { // Add generic instance method parameter var arg = CreateGenericInstanceCallArguments(node.SourceLocation, method, currentMethod, compiler); node.Arguments.AddRange(arg); node.GenericInstanceArgCount += arg.Count; } } // Add generic instance Delegate arguments for static methods. foreach (var node in ast.GetSelfAndChildrenRecursive <AstExpression>(x => x.Code == AstCode.Delegate)) { var delegateInfo = (Tuple <XTypeDefinition, XMethodReference>)node.Operand; var genMethodDef = delegateInfo.Item2 as IXGenericInstance; var genTypeDef = delegateInfo.Item2.DeclaringType as IXGenericInstance; // Add generic instance type parameter value, if method is static if (genTypeDef != null && delegateInfo.Item2.Resolve().IsStatic) { var arg = CreateGenericInstanceCallArguments(node.SourceLocation, delegateInfo.Item2.DeclaringType, currentMethod, compiler); node.Arguments.AddRange(arg); node.GenericInstanceArgCount += arg.Count; } // add generic method type parameter value. if (genMethodDef != null) { var arg = CreateGenericInstanceCallArguments(node.SourceLocation, delegateInfo.Item2, currentMethod, compiler); node.Arguments.AddRange(arg); node.GenericInstanceArgCount += arg.Count; } } // Convert NewObj when needed foreach (var node in ast.GetSelfAndChildrenRecursive <AstExpression>(x => x.Code == AstCode.Newobj)) { var ctorRef = (XMethodReference)node.Operand; var declaringType = ctorRef.DeclaringType; if (declaringType.IsArray) { // New multi dimensional array // Get element type var elemType = ((XArrayType)declaringType).ElementType; var typeExpr = new AstExpression(node.SourceLocation, AstCode.TypeOf, elemType); // Create dimensions array var intArrayType = new XArrayType(typeSystem.Int); var dimArrayExpr = new AstExpression(node.SourceLocation, AstCode.InitArrayFromArguments, intArrayType, node.Arguments).SetType(intArrayType); // Call java.lang.reflect.Array.newInstance(type, int[]) var newInstanceExpr = new AstExpression(node.SourceLocation, AstCode.ArrayNewInstance2, null, typeExpr, dimArrayExpr).SetType(typeSystem.Object); // Cast to correct type var cast = new AstExpression(node.SourceLocation, AstCode.SimpleCastclass, declaringType, newInstanceExpr).SetType(declaringType); // Replace node node.CopyFrom(cast); } else { // Normal "new object" XMethodDefinition ctorDef; if (ctorRef.TryResolve(out ctorDef) && ctorDef.NeedsGenericInstanceTypeParameter) { // Add generic instance type parameter value var arg = CreateGenericInstanceCallArguments(node.SourceLocation, ctorRef.DeclaringType, currentMethod, compiler); node.Arguments.AddRange(arg); node.GenericInstanceArgCount += arg.Count; } } } }
public SourceLocation(MethodSource source) : this(source, source.SourceFile, -1, -1) { }
/// <summary> /// Generate an Invoke opcode. /// </summary> internal static RCode Invoke(this XMethodDefinition targetMethod, XMethodReference targetMethodRef, MethodSource currentMethod, bool isSpecial = false) { if (targetMethod != null) { if (targetMethod.DeclaringType.IsDelegate()) { return RCode.Invoke_interface; } if (targetMethod.IsStatic || targetMethod.IsAndroidExtension) { return RCode.Invoke_static; } if ((currentMethod != null) && targetMethod.UseInvokeSuper(currentMethod.Method)) { return RCode.Invoke_super; } if (isSpecial && !targetMethod.IsConstructor && (currentMethod != null) && targetMethod.DeclaringType.IsBaseOf(currentMethod.Method.DeclaringType)) { return RCode.Invoke_super; } if (targetMethod.UseInvokeInterface) { return RCode.Invoke_interface; } if (targetMethod.IsDirect) { return RCode.Invoke_direct; } if (targetMethod.DeclaringType.IsInterface) { return RCode.Invoke_interface; } } if (targetMethodRef != null) { if (!targetMethodRef.HasThis) { return RCode.Invoke_static; } switch (targetMethodRef.Name) { case "<init>": case "<clinit>": case ".ctor": case ".cctor": return RCode.Invoke_direct; } } return RCode.Invoke_virtual; }
/// <summary> /// Create a method body for the given method. /// </summary> internal static MethodBody TranslateToRL(AssemblyCompiler compiler, DexTargetPackage targetPackage, MethodSource source, DexLib.MethodDefinition dmethod, out CompiledMethod compiledMethod) { try { #if DEBUG //Debugger.Launch(); if ((source.Method != null) && (source.Method.Name == "test6")) { //Debugger.Launch(); } #endif // Create Ast var optimizedAst = CreateOptimizedAst(compiler, source); // Generate RL code var rlBody = new MethodBody(source); var rlGenerator = new AstCompilerVisitor(compiler, source, targetPackage, dmethod, rlBody); optimizedAst.Accept(rlGenerator, null); // Should we add return_void? if (source.ReturnsVoid) { var instructions = rlBody.Instructions; if ((instructions.Count == 0) || (instructions.Last().Code != RCode.Return_void)) { instructions.Add(new RL.Instruction(RCode.Return_void) { SequencePoint = source.GetLastSourceLine() }); } } // Record results compiledMethod = targetPackage.Record(source, rlBody, rlGenerator.Frame); return(rlBody); } catch (Exception ex) { // Forward exception with more information var msg = string.Format("Error while compiling {0} in {1}: {2}", source.FullName, source.DeclaringTypeFullName, ex.Message); throw new CompilerException(msg, ex); } }
/// <summary> /// Create a frame for the given method /// </summary> internal AstInvocationFrame(DexTargetPackage targetPackage, MethodDefinition method, MethodSource source, MethodBody body) { this.targetPackage = targetPackage; this.body = body; this.body = body; Debug.Assert(!body.Registers.Any()); var prototypeParamOffset = 0; var prototype = method.Prototype; if (source.IsDotNet) { var ilMethod = source.ILMethod; // Allocate this if (!method.IsStatic) { thisArgument = (ArgumentRegisterSpec) Allocate(method.Owner, true, RCategory.Argument, ilMethod.Body.ThisParameter); arguments.Add(thisArgument); } else if (ilMethod.IsAndroidExtension() && !ilMethod.IsStatic) { prototypeParamOffset++; var type = ilMethod.DeclaringType.GetReference(targetPackage, source.Method.Module); thisArgument = (ArgumentRegisterSpec) Allocate(type, true, RCategory.Argument, ilMethod.Body.ThisParameter); arguments.Add(thisArgument); } // Allocate arguments var paramCount = ilMethod.Parameters.Count; for (var i = 0; i < paramCount; i++) { var p = ilMethod.Parameters[i]; var type = prototype.Parameters[prototypeParamOffset++].Type; arguments.Add((ArgumentRegisterSpec) Allocate(type, false, RCategory.Argument, p)); } } else if (source.IsJava) { var javaMethod = source.JavaMethod; // Allocate this var code = javaMethod.Attributes.OfType<CodeAttribute>().First(); if (!method.IsStatic) { thisArgument = (ArgumentRegisterSpec)Allocate(method.Owner, true, RCategory.Argument, code.ThisParameter); arguments.Add(thisArgument); } // Allocate arguments foreach (var p in code.Parameters) { var type = prototype.Parameters[prototypeParamOffset++].Type; arguments.Add((ArgumentRegisterSpec)Allocate(type, false, RCategory.Argument, p.Item2)); } } else if (source.IsAst) { // Allocate this if (!method.IsStatic) { thisArgument = (ArgumentRegisterSpec)Allocate(method.Owner, true, RCategory.Argument, null); arguments.Add(thisArgument); } // Allocate arguments foreach (var p in ((XSyntheticMethodDefinition)source.Method).AstParameters) { var type = prototype.Parameters[prototypeParamOffset++].Type; arguments.Add((ArgumentRegisterSpec)Allocate(type, false, RCategory.Argument, p)); } } else { throw new ArgumentException("Unknown source"); } // Add GenericInstanceType parameter (if any) if (source.Method.NeedsGenericInstanceTypeParameter) { var type = prototype.GenericInstanceTypeParameter.Type; GenericInstanceTypeArgument = (ArgumentRegisterSpec) Allocate(type, false, RCategory.Argument, null); arguments.Add(GenericInstanceTypeArgument); } // Add GenericInstanceMethod parameter (if any) if (source.Method.NeedsGenericInstanceMethodParameter) { var type = prototype.GenericInstanceMethodParameter.Type; GenericInstanceMethodArgument = (ArgumentRegisterSpec) Allocate(type, false, RCategory.Argument, null); arguments.Add(GenericInstanceMethodArgument); } // Check register count var expected = prototype.Parameters.Sum(x => x.Type.IsWide() ? 2 : 1); if (!method.IsStatic) expected++; if (expected != body.Registers.Count()) { throw new ArgumentException(string.Format("Expected {0} registers, found {1} (in {2})", expected, body.Registers.Count(), method)); } }
/// <summary> /// Perform all dot42 related Ast conversions. /// </summary> public static void Convert(DecompilerContext context, AstBlock ast, MethodSource currentMethod, AssemblyCompiler compiler, StopAstConversion stop = StopAstConversion.None) { if (ast.IsOptimizedForTarget) { return; } #if DEBUG //Debugger.Launch(); if ((currentMethod.Method != null) && (currentMethod.Method.Name.Equals("runTest", StringComparison.OrdinalIgnoreCase))) { //Debugger.Launch(); } #endif IntPtrConverter.Convert(ast, compiler); if (stop == StopAstConversion.AfterIntPtrConverter) { return; } TypeOfConverter.Convert(ast, compiler); if (stop == StopAstConversion.AfterTypeOfConverter) { return; } // TODO: check if we actually need this optimizer, as we have a more throughoutful // optimizer as the last step. BranchOptimizer.Convert(ast); if (stop == StopAstConversion.AfterBranchOptimizer) { return; } CompoundAssignmentConverter.Convert(ast); if (stop == StopAstConversion.AfterCompoundAssignmentConverter) { return; } // keep this order FixAsyncStateMachine.Convert(ast, currentMethod, compiler); if (stop == StopAstConversion.AfterFixAsyncStateMachine) { return; } InterlockedConverter.Convert(ast, currentMethod, compiler); if (stop == StopAstConversion.AfterInterlockedConverter) { return; } ByReferenceParamConverter.Convert(context, ast, compiler); if (stop == StopAstConversion.AfterByReferenceParamConverter) { return; } // end CompareUnorderedConverter.Convert(ast); if (stop == StopAstConversion.AfterCompareUnorderedConverter) { return; } EnumConverter.Convert(ast, compiler); if (stop == StopAstConversion.AfterEnumConverter) { return; } EnumOptimizer.Convert(ast, compiler); if (stop == StopAstConversion.AfterEnumOptimizer) { return; } // Keep this order NullableConverter.Convert(ast, compiler); if (stop == StopAstConversion.AfterNullableConverter) { return; } PrimitiveAddressOfConverter.Convert(ast, currentMethod, compiler); if (stop == StopAstConversion.AfterPrimitiveAddressOfConverter) { return; } StructCallConverter.Convert(ast, compiler); if (stop == StopAstConversion.AfterStructCallConverter) { return; } // end InitializeStructVariablesConverter.Convert(ast); if (stop == StopAstConversion.AfterInitializeStructVariablesConverter) { return; } DelegateConverter.Convert(ast); if (stop == StopAstConversion.AfterDelegateConverter) { return; } LdcWideConverter.Convert(ast); if (stop == StopAstConversion.AfterLdcWideConverter) { return; } LdLocWithConversionConverter.Convert(ast); if (stop == StopAstConversion.AfterLdLocWithConversionConverter) { return; } ConvertAfterLoadConversionConverter.Convert(ast); if (stop == StopAstConversion.AfterConvertAfterLoadConversionConverter) { return; } ConvertBeforeStoreConversionConverter.Convert(ast); if (stop == StopAstConversion.AfterConvertBeforeStoreConversionConverter) { return; } CleanupConverter.Convert(ast); if (stop == StopAstConversion.AfterCleanupConverter) { return; } GenericsConverter.Convert(ast, currentMethod, compiler.Module.TypeSystem); if (stop == StopAstConversion.AfterGenericsConverter) { return; } // Expand cast expressions CastConverter.Convert(ast, currentMethod, compiler); if (stop == StopAstConversion.AfterCastConverter) { return; } // Expand generic instance information GenericInstanceConverter.Convert(ast, currentMethod, compiler); if (stop == StopAstConversion.AfterGenericInstanceConverter) { return; } // run the branch optimizer again. (do we need the first invocation?) BranchOptimizer2.Convert(ast, compiler); if (stop == StopAstConversion.AfterBranchOptimizer2) { return; } }
void ProcessArgument(AstExpression callNode, XMethodReference methodRef, int argumentIndex, MethodSource currentMethod, XModule assembly) { var node = callNode.Arguments[argumentIndex]; // Should we do something? switch (node.Code) { case AstCode.Ldloca: // Parameter case AstCode.AddressOf: // Local variable case AstCode.Ldflda: // Instance field case AstCode.Ldsflda: // Static field case AstCode.Ldelema: // Array break; case AstCode.Ldloc: if (!node.MatchThis() || !currentMethod.IsDotNet) return; break; default: return; } // Process argument var method = methodRef.Resolve(); var argIsThis = !method.IsStatic && (argumentIndex == 0); var parameterIndex = method.IsStatic ? argumentIndex : argumentIndex - 1; var parameter = argIsThis ? null : method.Parameters[parameterIndex]; var argType = argIsThis ? method.DeclaringType : parameter.ParameterType; //var argAttrs = argIsThis ? ParameterAttributes.None : parameter.Attributes; var argIsByRef = argType.IsByReference; var argIsOut = argIsThis ? false : argIsByRef && (parameter.Kind == XParameterKind.Output); // argIsByRef && argAttrs.HasFlag(ParameterAttributes.Out); var argIsGenByRefParam = argIsByRef && argType.ElementType.IsGenericParameter; switch (node.Code) { case AstCode.Ldloca: // Parameter { var variable = ((AstVariable)node.Operand); if (variable.Type.IsPrimitive || argIsByRef) { // Box first var ldloc = new AstExpression(node.SourceLocation, AstCode.Ldloc, node.Operand) { InferredType = variable.Type }; if (argIsByRef) { var stloc = new AstExpression(node.SourceLocation, AstCode.Stloc, node.Operand) { InferredType = variable.Type }; stloc.Arguments.Add(GetValueOutOfByRefArray(node, variable.Type, argIsGenByRefParam, assembly)); ConvertToByRefArray(node, variable.Type, ldloc, stloc, argIsOut, argIsGenByRefParam, assembly); } else { ConvertToBox(node, variable.Type, ldloc); } } else if (variable.Type.IsGenericParameter) { // Convert to ldarg var ldloc = new AstExpression(node.SourceLocation, AstCode.Ldloc, node.Operand) { InferredType = variable.Type }; callNode.Arguments[argumentIndex] = ldloc; } } break; case AstCode.Ldloc: // this { var variable = ((AstVariable)node.Operand); if (argIsThis && (variable.Type.IsByReference)) { node.SetType(variable.Type.ElementType); } else if (argIsByRef) { var ldclone = new AstExpression(node); var stExpr = new AstExpression(node.SourceLocation, AstCode.Nop, null); var elementType = variable.Type; if (elementType.IsByReference) elementType = elementType.ElementType; ConvertToByRefArray(node, elementType, ldclone, stExpr, argIsOut, argIsGenByRefParam, assembly); } } break; case AstCode.AddressOf: // Local variable { var arg = node.Arguments[0]; var type = arg.GetResultType(); var typeDef = type.Resolve(); if (typeDef.IsPrimitive) { if (argIsByRef) { throw new CompilerException("Unsupported use of AddressOf by byref argument"); } else { ConvertToBox(node, type, arg); } } } break; case AstCode.Ldflda: // Instance field case AstCode.Ldsflda: // Static field { var fieldRef = (XFieldReference)node.Operand; var field = fieldRef.Resolve(); if (field.FieldType.IsPrimitive || argIsByRef) { // Box first var ldfldCode = (node.Code == AstCode.Ldflda) ? AstCode.Ldfld : AstCode.Ldsfld; var ldfld = new AstExpression(node.SourceLocation, ldfldCode, node.Operand) { InferredType = field.FieldType }; ldfld.Arguments.AddRange(node.Arguments); if (argIsByRef) { var stfldCode = (node.Code == AstCode.Ldflda) ? AstCode.Stfld : AstCode.Stsfld; var stfld = new AstExpression(node.SourceLocation, stfldCode, node.Operand) { InferredType = field.FieldType }; stfld.Arguments.AddRange(node.Arguments); // instance stfld.Arguments.Add(GetValueOutOfByRefArray(node, field.FieldType, argIsGenByRefParam, assembly)); // value ConvertToByRefArray(node, field.FieldType, ldfld, stfld, argIsOut, argIsGenByRefParam, assembly); } else { ConvertToBox(node, field.FieldType, ldfld); } } } break; case AstCode.Ldelema: // Array element { var array = node.Arguments[0]; var arrayType = array.GetResultType(); var type = arrayType.ElementType; if (type.IsPrimitive || argIsByRef) { // Box first var ldElemCode = type.GetLdElemCode(); var ldelem = new AstExpression(node.SourceLocation, ldElemCode, node.Operand) { InferredType = type }; ldelem.Arguments.AddRange(node.Arguments); if (argIsByRef) { var stelemCode = type.GetStElemCode(); var stelem = new AstExpression(node.SourceLocation, stelemCode, node.Operand) { InferredType = type }; stelem.Arguments.AddRange(node.Arguments); stelem.Arguments.Add(GetValueOutOfByRefArray(node, type, argIsGenByRefParam, assembly)); ConvertToByRefArray(node, type, ldelem, stelem, argIsOut, argIsGenByRefParam, assembly); } else { ConvertToBox(node, type, ldelem); } } } break; } }