/// <summary> /// Create the body of the ctor. /// </summary> private static MethodBody CreateCtorBody(XMethodDefinition calledMethod, FieldDefinition instanceField, ClassReference baseClass) { var body = new MethodBody(null); // Create code var ins = body.Instructions; var rthis = body.AllocateRegister(RCategory.Argument, RType.Object); // Call base ctor var baseCtorRef = new MethodReference(baseClass, "<init>", new Prototype(PrimitiveType.Void)); ins.Add(new Instruction(RCode.Invoke_direct, rthis) { Operand = baseCtorRef }); if (!calledMethod.IsStatic) { // load instance into field var rvalue = body.AllocateRegister(RCategory.Argument, RType.Object); ins.Add(new Instruction(RCode.Iput_object, rvalue, rthis) { Operand = instanceField }); } ins.Add(new Instruction(RCode.Return_void)); return(body); }
/// <summary> /// Default ctor /// </summary> public RegisterMapper(MethodBody body, InvocationFrame frame) { this.frame = frame; // Select all non-argument registers that are in use. Dictionary<Register, RegisterFlags> used; int maxOutgoingRegisters; bool largeInvokeInsFound; GetUsedArgumentRegisters(body, out used, out maxOutgoingRegisters, out largeInvokeInsFound); //var used = body.Registers.Where(x => (x.Category != RCategory.Argument) && body.Instructions.Uses(x)).ToList(); var sorted = used.OrderBy(x => x.Value).ThenBy(x => x.Key.Index).Select(x => x.Key).ToList(); AddKeepWithNext(sorted, body); // Collect argument registers var arguments = body.Registers.Where(x => x.Category == RCategory.Argument).ToList(); // Prepare various decisions //var maxOutgoingRegisters = body.Instructions.Max(x => x.Code.IsInvoke() ? x.Registers.Count : 0); var required = sorted.Count + arguments.Count; //var largeInvokeInsFound = body.Instructions.Any(x => x.Code.IsInvoke() && x.Registers.Count > 5); // Allocate Dex registers for each var index = 0; // Allocate spill registers (if needed) if ((required >= 16) || (largeInvokeInsFound && (required + maxOutgoingRegisters >= 16))) { spillRangeRegisters = new DexLib.Instructions.Register[MaxSpillRegisters]; for (var i = 0; i < MaxSpillRegisters; i++) { spillRangeRegisters[i] = new DexLib.Instructions.Register(index++); } } // Allocate Dex registers for each temp register. foreach (var r in sorted) { var dreg = new DexLib.Instructions.Register(index++); map[r] = dreg; dRegisterTypes[dreg] = r.Type; } // Allocate outgoing invocation frame (if needed) if ((required >= 16) || largeInvokeInsFound) { invokeRangeRegisters = new DexLib.Instructions.Register[maxOutgoingRegisters]; for (var i = 0; i < maxOutgoingRegisters; i++) { invokeRangeRegisters[i] = new DexLib.Instructions.Register(index++); } } // Allocate Dex registers for each argument foreach (var r in arguments) { var dreg = new DexLib.Instructions.Register(index++); map[r] = dreg; dRegisterTypes[dreg] = r.Type; } ArgumentCount = arguments.Count; }
/// <summary> /// Gets all registers of category!=Argument that are used in an instruction. /// </summary> private static void GetUsedArgumentRegisters(MethodBody body, out Dictionary <Register, RegisterFlags> used, out int maxOutgoingRegisters, out bool largeInvokeInsFound) { //maxOutgoingRegisters = body.Instructions.Max(x => x.Code.IsInvoke() ? x.Registers.Count : 0); //largeInvokeInsFound = body.Instructions.Any(x => x.Code.IsInvoke() && x.Registers.Count > 5); maxOutgoingRegisters = 0; largeInvokeInsFound = false; used = new Dictionary <Register, RegisterFlags>(); foreach (var ins in body.Instructions) { if (ins.Code.IsInvoke()) { maxOutgoingRegisters = Math.Max(maxOutgoingRegisters, ins.Registers.Count); if (ins.Registers.Count > 5) { largeInvokeInsFound = true; } } foreach (var reg in ins.Registers) { if (reg.Category != RCategory.Argument) { var lowestSize = GetLowestSize(ins, reg); RegisterFlags currentLowestSize; if (used.TryGetValue(reg, out currentLowestSize)) { if (lowestSize < currentLowestSize) { used[reg] = lowestSize; } } else { used.Add(reg, lowestSize); } } } } // Add second register of wide registers. Register prevReg = null; foreach (var reg in body.Registers) { if (prevReg != null) { if (reg.Type == RType.Wide2) { RegisterFlags flags; if (used.TryGetValue(prevReg, out flags)) { used[reg] = flags; } } } prevReg = reg; } }
/// <summary> /// Create the body of the equals method. /// </summary> private static MethodBody CreateEqualsBody(ISourceLocation sequencePoint, AssemblyCompiler compiler, DexTargetPackage targetPackage, XMethodDefinition equalsMethod, Prototype equalsPrototype, FieldDefinition instanceField, ClassReference delegateClass) { MethodBody body = new MethodBody(null); // This pointer and method argument. Register rthis = body.AllocateRegister(RCategory.Argument, RType.Object); Register rother = body.AllocateRegister(RCategory.Argument, RType.Object); // Create code. var ins = body.Instructions; // Temporary parameter result. Register result = body.AllocateRegister(RCategory.Temp, RType.Value); // Prepare the return instruction. Instruction returnInstruction = new Instruction(RCode.Return, result); // Check if other object can be casted. ins.Add(new Instruction(RCode.Instance_of, delegateClass, new[] { result, rother })); ins.Add(new Instruction(RCode.If_eqz, returnInstruction, new[] { result })); // compare instance members // Cast of the other object. ins.Add(new Instruction(RCode.Check_cast, delegateClass, new[] { rother })); // Get instance fields of this and other. var thisInstance = body.AllocateRegister(RCategory.Temp, RType.Object); var otherInstance = body.AllocateRegister(RCategory.Temp, RType.Object); // Load the instance fields. ins.Add(new Instruction(RCode.Iget_object, thisInstance, rthis) { Operand = instanceField }); ins.Add(new Instruction(RCode.Iget_object, otherInstance, rother) { Operand = instanceField }); // Compare the instance fields. ins.Add(new Instruction(RCode.If_eq, returnInstruction, new[] { thisInstance, otherInstance })); // compare instance members // Set result to false if not equal. ins.Add(new Instruction(RCode.Const, 0, new[] { result })); // Add return instructions ins.Add(returnInstruction); return(body); }
/// <summary> /// For each register in the given list, ensure that all keep-with-next registers are also added. /// </summary> private static void AddKeepWithNext(List <Register> registers, MethodBody body) { var i = 0; while (i < registers.Count) { var r = registers[i++]; if ((r.Flags & RFlags.KeepWithNext) == 0) { continue; } var next = body.Registers.First(x => x.Index == r.Index + 1); if (!registers.Contains(next)) { registers.Insert(i, next); } } }
/// <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> /// Create the body of the equals method. /// </summary> private static MethodBody CreateEqualsBody() { MethodBody body = new MethodBody(null); // This pointer and method argument. Register rthis = body.AllocateRegister(RCategory.Argument, RType.Object); Register rother = body.AllocateRegister(RCategory.Argument, RType.Object); // Create code. var ins = body.Instructions; // Temporary parameter result. Register result = body.AllocateRegister(RCategory.Temp, RType.Value); // Set result to false. ins.Add(new Instruction(RCode.Const, 0, new[] { result })); // Add return instructions ins.Add(new Instruction(RCode.Return, result)); return(body); }
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> /// Create the body of the equals method. /// </summary> private MethodBody CreateEqualsBody(ClassReference delegateInstance) { MethodBody body = new MethodBody(null); // This pointer and method argument. Register rthis = body.AllocateRegister(RCategory.Argument, RType.Object); Register rother = body.AllocateRegister(RCategory.Argument, RType.Object); // Create code. var ins = body.Instructions; // Temporary parameter result. Register result = body.AllocateRegister(RCategory.Temp, RType.Value); // Prepare the return instruction. Instruction returnFalseInstruction = new Instruction(RCode.Return, result); // Check if other object can be casted. ins.Add(new Instruction(RCode.Instance_of, delegateInstance, new[] { result, rother })); ins.Add(new Instruction(RCode.If_eqz, returnFalseInstruction, new[] { result })); // Set result to false on default. ins.Add(new Instruction(RCode.Const, 0, new[] { result })); // Cast of the other object. ins.Add(new Instruction(RCode.Check_cast, delegateInstance, new[] { rother })); // Get instance fields of this and other. var rThisValue = body.AllocateRegister(RCategory.Temp, RType.Object); var rOtherValue = body.AllocateRegister(RCategory.Temp, RType.Object); if (instanceField != null) { // Load the instance fields. ins.Add(new Instruction(RCode.Iget_object, rThisValue, rthis) {Operand = instanceField}); ins.Add(new Instruction(RCode.Iget_object, rOtherValue, rother) {Operand = instanceField}); // Compare the instance fields. ins.Add(new Instruction(RCode.If_ne, returnFalseInstruction, new[] {rThisValue, rOtherValue})); } foreach (var field in GenericTypeFields) { if (field.Type.Equals(FrameworkReferences.Class)) { // simply load and compare the fields. ins.Add(new Instruction(RCode.Iget_object, rThisValue, rthis) { Operand = field }); ins.Add(new Instruction(RCode.Iget_object, rOtherValue, rother) { Operand = field }); ins.Add(new Instruction(RCode.If_ne, returnFalseInstruction, new[] { rThisValue, rOtherValue })); } else // array { CreateCompareArrayInstructions(ins, body, rthis, rother, field, rThisValue, rOtherValue, returnFalseInstruction); } } // return true, if we made it so far ins.Add(new Instruction(RCode.Const, 1, new[] { result })); // Add return instructions ins.Add(returnFalseInstruction); return body; }
/// <summary> /// Create the body of the ctor. /// </summary> private MethodBody CreateCtorBody(Prototype prototype) { var body = new MethodBody(null); // Create code var ins = body.Instructions; var rthis = body.AllocateRegister(RCategory.Argument, RType.Object); // Add parameters var paramRegs = new List<Register> { rthis }; foreach (var p in prototype.Parameters) { if (p.Type.IsWide()) { var pair = body.AllocateWideRegister(RCategory.Argument); paramRegs.Add(pair.Item1); paramRegs.Add(pair.Item2); } else { var reg = body.AllocateRegister(RCategory.Argument, p.Type.IsPrimitive() ? RType.Value : RType.Object); paramRegs.Add(reg); } } // Call base ctor var baseCtorRef = new MethodReference(Class.SuperClass, "<init>", prototype); ins.Add(new Instruction(RCode.Invoke_direct, paramRegs.ToArray()) { Operand = baseCtorRef }); ins.Add(new Instruction(RCode.Return_void)); return body; }
/// <summary> /// Create the body of the ctor. /// </summary> private MethodBody CreateCtorBody() { var body = new MethodBody(null); // Create code var ins = body.Instructions; var rthis = body.AllocateRegister(RCategory.Argument, RType.Object); // Call base ctor var baseCtorRef = new MethodReference(delegateClass, "<init>", new Prototype(PrimitiveType.Void)); ins.Add(new Instruction(RCode.Invoke_direct, rthis) { Operand = baseCtorRef }); if (instanceField != null) { // load instance into field var rInstanceArg = body.AllocateRegister(RCategory.Argument, RType.Object); ins.Add(new Instruction(RCode.Iput_object, rInstanceArg, rthis) {Operand = instanceField}); } foreach (var field in GenericTypeFields) { var rArg = body.AllocateRegister(RCategory.Argument, RType.Object); ins.Add(new Instruction(RCode.Iput_object, rArg, rthis) { Operand = field }); } ins.Add(new Instruction(RCode.Return_void)); return body; }
/// <summary> /// Create the body of the equals method. /// </summary> private MethodBody CreateHashCodeBody(ClassReference delegateInstance) { MethodBody body = new MethodBody(null); // This pointer and method argument. Register rthis = body.AllocateRegister(RCategory.Argument, RType.Object); Register tempObj = body.AllocateRegister(RCategory.Temp, RType.Object); Register tempInt = body.AllocateRegister(RCategory.Temp, RType.Value); Register tempArray = body.AllocateRegister(RCategory.Temp, RType.Object); Register tempIdx = body.AllocateRegister(RCategory.Temp, RType.Value); Register tempArrayLength = body.AllocateRegister(RCategory.Temp, RType.Value); // Create code. var ins = body.Instructions; // Temporary parameter result. Register result = body.AllocateRegister(RCategory.Temp, RType.Value); var hashCodeMethod = compiler.GetDot42InternalType("Java.Lang", "System") .Resolve() .Methods.First(m => m.Name == "IdentityHashCode") .GetReference(targetPackage); // Check if other object can be casted. ins.Add(new Instruction(RCode.Const_class, delegateInstance, new[] { tempObj })); ins.Add(new Instruction(RCode.Invoke_static, hashCodeMethod, new[] { tempObj })); ins.Add(new Instruction(RCode.Move_result, null, new[] { result })); if (instanceField != null) { ins.Add(new Instruction(RCode.Mul_int_lit, 397, new[] { result, result })); ins.Add(new Instruction(RCode.Iget_object, tempObj, rthis) { Operand = instanceField }); ins.Add(new Instruction(RCode.Invoke_static, tempObj) { Operand = hashCodeMethod }); ins.Add(new Instruction(RCode.Move_result, tempInt)); ins.Add(new Instruction(RCode.Xor_int_2addr, result, tempInt)); } foreach (var field in GenericTypeFields) { if (field.Type.Equals(FrameworkReferences.Class)) { ins.Add(new Instruction(RCode.Iget_object, tempObj, rthis) { Operand = field }); ins.Add(new Instruction(RCode.Invoke_static, hashCodeMethod, new[] { tempObj })); ins.Add(new Instruction(RCode.Move_result, null, new[] { tempInt })); ins.Add(new Instruction(RCode.Xor_int_2addr, null, new[] { result, tempInt })); } else // array { ins.Add(new Instruction(RCode.Iget_object, tempArray, rthis) { Operand = field }); ins.Add(new Instruction(RCode.Array_length, tempArrayLength, rthis)); ins.Add(new Instruction(RCode.Const, tempIdx){ Operand = 0}); Instruction loop; ins.Add(loop = new Instruction()); ins.Add(new Instruction(RCode.Mul_int_lit, 397, new[] {result, result})); ins.Add(new Instruction(RCode.Aget_object, tempObj, tempArray, tempIdx)); ins.Add(new Instruction(RCode.Invoke_static, hashCodeMethod, new[] { tempObj })); ins.Add(new Instruction(RCode.Move_result, null, new[] { tempInt })); ins.Add(new Instruction(RCode.Xor_int_2addr, null, new[] { result, tempInt })); ins.Add(new Instruction(RCode.Add_int_lit8, 1, new[] { tempIdx, tempIdx })); ins.Add(new Instruction(RCode.If_ltz, tempIdx, tempArrayLength) { Operand = loop}); } } // Add return instructions ins.Add(new Instruction(RCode.Return, null, new[] { result })); return body; }
/// <summary> /// Create code to load a value from an annotation interface. /// </summary> /// <returns>The register(s) holding the value</returns> private static Register[] CreateLoadValueSequence( ISourceLocation seqp, MethodBody body, XTypeReference valueType, Register annotationReg, MethodDefinition getter, AssemblyCompiler compiler, DexTargetPackage targetPackage, out Instruction branchIfNotSet) { // NOTE: It would be better if we wouldn't get the values as object arrays // but as arrays of the actual type. // Apparently though the DexWriter will not write our attributes // if they contain arrays not of type object[]. Therefore the // conversion code below. // All in all it would be much cleaner if we could emit Ast code here // instead of RL code. List<Register> result = new List<Register>(); // get the array. Register regObject = body.AllocateRegister(RCategory.Temp, RType.Object); Register regIntVal = body.AllocateRegister(RCategory.Temp, RType.Value); body.Instructions.Add(seqp, RCode.Invoke_interface, getter, annotationReg); body.Instructions.Add(seqp, RCode.Move_result_object, regObject); // allocate result, initialize to default value. if (valueType.IsWide()) { Tuple<Register, Register> regs = body.AllocateWideRegister(RCategory.Temp); body.Instructions.Add(seqp, RCode.Const_wide, 0, regs.Item1); result.Add(regs.Item1); result.Add(regs.Item2); } else if (valueType.IsPrimitive) { Register reg = body.AllocateRegister(RCategory.Temp, RType.Value); body.Instructions.Add(seqp, RCode.Const, 0, reg); result.Add(reg); } else // object { Register reg = body.AllocateRegister(RCategory.Temp, RType.Object); body.Instructions.Add(seqp, RCode.Const, 0, reg); result.Add(reg); } // check if value is unset (array length 0) or null (array length 2) body.Instructions.Add(seqp, RCode.Array_length, regIntVal, regObject); branchIfNotSet = body.Instructions.Add(seqp, RCode.If_eqz, regIntVal); body.Instructions.Add(seqp, RCode.Rsub_int, 1, regIntVal, regIntVal); var branchOnNull = body.Instructions.Add(seqp, RCode.If_nez, regIntVal); // get the (boxed) value body.Instructions.Add(seqp, RCode.Const, 0, regIntVal); // convert to target type. if (valueType.IsArray) { Register regTmp = body.AllocateRegister(RCategory.Temp, RType.Object); Register regType = body.AllocateRegister(RCategory.Temp, RType.Object); var helper = compiler.GetDot42InternalType(InternalConstants.CompilerHelperName); var convertArray = helper.Resolve().Methods.First(p => p.Name == "ConvertArray" && p.Parameters.Count == 2) .GetReference(targetPackage); var underlying = valueType.ElementType.GetReference(targetPackage); body.Instructions.Add(seqp, RCode.Aget_object, regTmp, regObject, regIntVal); body.Instructions.Add(seqp, RCode.Const_class, underlying, regType); body.Instructions.Add(seqp, RCode.Invoke_static, convertArray, regTmp, regType); body.Instructions.Add(seqp, RCode.Move_result_object, result[0]); body.Instructions.Add(seqp, RCode.Check_cast, valueType.GetReference(targetPackage), result[0]); } else if (valueType.IsEnum()) { Register regTmp = body.AllocateRegister(RCategory.Temp, RType.Object); Register regType = body.AllocateRegister(RCategory.Temp, RType.Object); var getFromObject = compiler.GetDot42InternalType("Enum").Resolve() .Methods.Single(p=>p.Name == "GetFromObject") .GetReference(targetPackage); body.Instructions.Add(seqp, RCode.Aget_object, regTmp, regObject, regIntVal); body.Instructions.Add(seqp, RCode.Const_class, valueType.GetReference(targetPackage), regType); body.Instructions.Add(seqp, RCode.Invoke_static, getFromObject, regType, regTmp); body.Instructions.Add(seqp, valueType.MoveResult(), result[0]); body.Instructions.Add(seqp, RCode.Check_cast, valueType.GetReference(targetPackage), result[0]); } else if(!valueType.IsPrimitive) { body.Instructions.Add(seqp, RCode.Aget_object, result[0], regObject, regIntVal); body.Instructions.Add(seqp, RCode.Check_cast, valueType.GetReference(targetPackage), result[0]); } else { Register regTmp = body.AllocateRegister(RCategory.Temp, RType.Object); // unbox and store RCode afterConvert; var unbox = valueType.GetUnboxValueMethod(compiler, targetPackage, out afterConvert); body.Instructions.Add(seqp, RCode.Aget_object, regTmp, regObject, regIntVal); body.Instructions.Add(seqp, RCode.Invoke_static, unbox, regTmp); body.Instructions.Add(seqp, valueType.MoveResult(), result[0]); if (afterConvert != RCode.Nop) { body.Instructions.Add(seqp, afterConvert, result[0], result[0]); } } // nop will be removed at some stage later. var nop = body.Instructions.Add(seqp, RCode.Nop); branchOnNull.Operand = nop; return result.ToArray(); }
private MethodBody CreateCloneBody(MethodDefinition ctor, ClassDefinition @class) { MethodBody body = new MethodBody(null); var ins = body.Instructions; Register rthis = body.AllocateRegister(RCategory.Argument, RType.Object); Register rInvList = body.AllocateRegister(RCategory.Argument, RType.Object); Register rInvListLen = body.AllocateRegister(RCategory.Argument, RType.Value); Register result = body.AllocateRegister(RCategory.Temp, RType.Object); List<Register> ctorArgs = new List<Register> { result }; if (instanceField != null) { var rInstance = body.AllocateRegister(RCategory.Temp, RType.Object); ins.Add(new Instruction(RCode.Iget_object, instanceField, new[] {rInstance, rthis})); ctorArgs.Add(rInstance); } foreach (var field in GenericTypeFields) { var r = body.AllocateRegister(RCategory.Temp, RType.Object); ins.Add(new Instruction(RCode.Iget_object, field, new[] { r, rthis })); ctorArgs.Add(r); } ins.Add(new Instruction(RCode.New_instance, @class, new[] {result})); ins.Add(new Instruction(RCode.Invoke_direct, ctor, ctorArgs.ToArray())); var invListLengthReference = new FieldReference(multicastDelegateClass, "InvocationListLength", PrimitiveType.Int); var multicastDelegateArray = new ArrayType(multicastDelegateClass); var invListReference = new FieldReference(multicastDelegateClass, "InvocationList", multicastDelegateArray); ins.Add(new Instruction(RCode.Iput_object, invListReference, new []{ rInvList, result})); ins.Add(new Instruction(RCode.Iput, invListLengthReference, new[] { rInvListLen, result })); ins.Add(new Instruction(RCode.Return_object, null, new []{result})); return body; }
/// <summary> /// Create the body of the equals method. /// </summary> private static MethodBody CreateEqualsBody() { MethodBody body = new MethodBody(null); // This pointer and method argument. Register rthis = body.AllocateRegister(RCategory.Argument, RType.Object); Register rother = body.AllocateRegister(RCategory.Argument, RType.Object); // Create code. var ins = body.Instructions; // Temporary parameter result. Register result = body.AllocateRegister(RCategory.Temp, RType.Value); // Set result to false. ins.Add(new Instruction(RCode.Const, 0, new[] { result })); // Add return instructions ins.Add(new Instruction(RCode.Return, result)); return body; }
/// <summary> /// Create the body of the invoke method. /// </summary> private static MethodBody CreateInvokeBody(ISourceLocation sequencePoint, AssemblyCompiler compiler, DexTargetPackage targetPackage, XMethodDefinition calledMethod, XMethodDefinition invokeMethod, Prototype invokePrototype, Prototype calledMethodPrototype, FieldDefinition instanceField, ClassReference delegateClass) { var body = new MethodBody(null); var rthis = body.AllocateRegister(RCategory.Argument, RType.Object); foreach (var p in invokePrototype.Parameters) { if (p.Type.IsWide()) { body.AllocateWideRegister(RCategory.Argument); } else { var type = (p.Type is PrimitiveType) ? RType.Value : RType.Object; body.AllocateRegister(RCategory.Argument, type); } } var incomingMethodArgs = body.Registers.ToArray(); // Create code var ins = body.Instructions; Register instance = null; if (!calledMethod.IsStatic) { // load instance instance = body.AllocateRegister(RCategory.Temp, RType.Object); ins.Add(new Instruction(RCode.Iget_object, instance, rthis) { Operand = instanceField }); } // Invoke var calledMethodRef = calledMethod.GetReference(targetPackage); var inputArgs = calledMethod.IsStatic ? incomingMethodArgs.Skip(1).ToArray() : incomingMethodArgs; // Cast arguments (if needed) var outputArgs = new List<Register>(); if (!calledMethod.IsStatic) { outputArgs.Add(instance); } var parameterIndex = 0; for (var i = calledMethod.IsStatic ? 0 : 1; i < inputArgs.Length; ) { var invokeType = invokePrototype.Parameters[parameterIndex].Type; var inputIsWide = invokeType.IsWide(); var calledType = calledMethodPrototype.Parameters[parameterIndex].Type; if (!invokeType.Equals(calledType)) { // Add cast / unbox var source = inputIsWide ? new RegisterSpec(inputArgs[i], inputArgs[i + 1], invokeType) : new RegisterSpec(inputArgs[i], null, invokeType); var tmp = ins.Unbox(sequencePoint, source, calledMethod.Parameters[parameterIndex].ParameterType, compiler, targetPackage, body); outputArgs.Add(tmp.Result.Register); if (calledType.IsWide()) { outputArgs.Add(tmp.Result.Register2); } } else { outputArgs.Add(inputArgs[i]); if (calledType.IsWide()) { outputArgs.Add(inputArgs[i + 1]); } } i += inputIsWide ? 2 : 1; parameterIndex++; } // Actual call ins.Add(new Instruction(calledMethod.Invoke(calledMethod, null), calledMethodRef, outputArgs.ToArray())); // Collect return value var invokeReturnType = invokePrototype.ReturnType; var calledReturnType = calledMethodPrototype.ReturnType; var needsBoxing = !invokeReturnType.Equals(calledReturnType); Instruction returnInstruction; if (calledReturnType.IsWide()) { var r = body.AllocateWideRegister(RCategory.Temp); ins.Add(new Instruction(RCode.Move_result_wide, r.Item1)); if (needsBoxing) { // Box var source = new RegisterSpec(r.Item1, r.Item2, calledReturnType); var tmp = ins.Box(sequencePoint, source, calledMethod.ReturnType, targetPackage, body); returnInstruction = new Instruction(RCode.Return_object, tmp.Result.Register); } else { // Return wide returnInstruction = new Instruction(RCode.Return_wide, r.Item1); } } else if (calledMethod.ReturnType.IsVoid()) { // Void return returnInstruction = new Instruction(RCode.Return_void); } else if (calledReturnType is PrimitiveType) { // Single register return var r = body.AllocateRegister(RCategory.Temp, RType.Value); ins.Add(new Instruction(RCode.Move_result, r)); if (needsBoxing) { // Box var source = new RegisterSpec(r, null, invokeReturnType); var tmp = ins.Box(sequencePoint, source, calledMethod.ReturnType, targetPackage, body); returnInstruction = new Instruction(RCode.Return_object, tmp.Result.Register); } else { // Return returnInstruction = new Instruction(RCode.Return, r); } } else { var r = body.AllocateRegister(RCategory.Temp, RType.Object); ins.Add(new Instruction(RCode.Move_result_object, r)); if (needsBoxing) { // Box var source = new RegisterSpec(r, null, invokeReturnType); var tmp = ins.Box(sequencePoint, source, invokeMethod.ReturnType, targetPackage, body); returnInstruction = new Instruction(RCode.Return_object, tmp.Result.Register); } else { // Return returnInstruction = new Instruction(RCode.Return_object, r); } } // Call next delegate (if any) var next = body.AllocateRegister(RCategory.Temp, RType.Object); var multicastDelegateType = new ClassReference(targetPackage.NameConverter.GetConvertedFullName("System.MulticastDelegate")); var nextReference = new FieldReference(multicastDelegateType, "next", multicastDelegateType); ins.Add(new Instruction(RCode.Iget_object, nextReference, new[] { next, rthis })); // load this.next var afterCallNext = new Instruction(RCode.Nop); ins.Add(new Instruction(RCode.If_eqz, afterCallNext, new[] { next })); // if next == null, continue ins.Add(new Instruction(RCode.Check_cast, delegateClass, new[] { next })); var nextInvokeMethod = new MethodReference(delegateClass, "Invoke", invokePrototype); var nextInvokeArgs = new[] { next }.Concat(incomingMethodArgs.Skip(1)).ToArray(); ins.Add(new Instruction(RCode.Invoke_virtual, nextInvokeMethod, nextInvokeArgs)); ins.Add(afterCallNext); // Add return instructions ins.Add(returnInstruction); return body; }
private Register CallGetMethodInfo(MethodBody body, MethodReference methodRef) { // >> var method = TypeHelper.GetMethodInfo(typeof(CalledClass), methodName, new[] { paramType1, ...}, null, null); var ins = body.Instructions; Register classR = body.AllocateRegister(RCategory.Temp, RType.Object); Register methodNameR = body.AllocateRegister(RCategory.Temp, RType.Object); Register methodParamsR = body.AllocateRegister(RCategory.Temp, RType.Object); Register idxR = body.AllocateRegister(RCategory.Temp, RType.Value); var resultR = body.AllocateRegister(RCategory.Temp, RType.Object); var nullR = body.AllocateRegister(RCategory.Temp, RType.Object); var parameters = methodRef.Prototype.Parameters; ins.Add(new Instruction(RCode.Const_class, methodRef.Owner, new[] {classR})); ins.Add(new Instruction(RCode.Const_string, methodRef.Name, new[] { methodNameR })); ins.Add(new Instruction(RCode.Const, parameters.Count, new[] {idxR})); ins.Add(new Instruction(RCode.New_array, FrameworkReferences.ClassArray, new[] {methodParamsR, idxR})); for (int i = 0; i < parameters.Count; ++i) { ins.Add(new Instruction(RCode.Const, i, new[] {idxR})); ins.Add(new Instruction(RCode.Const_class, parameters[i].Type, new[] {resultR})); ins.Add(new Instruction(RCode.Aput_object, null, new[] { resultR, methodParamsR, idxR })); } ins.Add(new Instruction(RCode.Const, 0, new[] { nullR })); var xGetMethodInfo = compiler.GetDot42InternalType(InternalConstants.TypeHelperName).Resolve().Methods.First(m => m.Name == "GetMethodInfo"); var getMethodInfo = xGetMethodInfo.GetReference(targetPackage); // TODO: make this work with generic parameters as well. ins.Add(new Instruction(RCode.Invoke_virtual, getMethodInfo, new[] { classR, methodNameR, methodParamsR, nullR, nullR })); ins.Add(new Instruction(RCode.Move_result_object, null, new[] {resultR})); return resultR; }
private MethodBody CreateCctorBody() { MethodBody body = new MethodBody(null); Register methodInfoR = CallGetMethodInfo(body, calledMethod.GetReference(targetPackage)); var ins = body.Instructions; ins.Add(new Instruction(RCode.Sput_object, methodInfoField, new[] { methodInfoR })); ins.Add(new Instruction(RCode.Return_void, null)); return body; }
private MethodBody CreateGetMethodInfoImplBody() { // TODO: For methods taking generic parameters we want to lazy initialize a // non-static volatile MethodInfo register. MethodBody body = new MethodBody(null); var ins = body.Instructions; Register rthis = body.AllocateRegister(RCategory.Argument, RType.Object); Register result = body.AllocateRegister(RCategory.Temp, RType.Object); if(methodInfoField.IsStatic) ins.Add(new Instruction(RCode.Sget_object, methodInfoField, new[] { result })); else ins.Add(new Instruction(RCode.Iget_object, methodInfoField, new[] { result, rthis })); ins.Add(new Instruction(RCode.Return_object, null, new[] { result })); return body; }
private MethodBody CreateGetTargetImplBody() { MethodBody body = new MethodBody(null); var ins = body.Instructions; Register rthis = body.AllocateRegister(RCategory.Argument, RType.Object); Register result = body.AllocateRegister(RCategory.Temp, RType.Object); ins.Add(new Instruction(RCode.Iget_object, instanceField, new[] { result, rthis })); ins.Add(new Instruction(RCode.Return_object, null, new[] { result })); return body; }
/// <summary> /// Create the body of the invoke method. /// </summary> private static MethodBody CreateInvokeBody(ISourceLocation sequencePoint, AssemblyCompiler compiler, DexTargetPackage targetPackage, XMethodDefinition calledMethod, XMethodDefinition invokeMethod, Prototype invokePrototype, Prototype calledMethodPrototype, FieldDefinition instanceField, ClassReference delegateClass) { var body = new MethodBody(null); var rthis = body.AllocateRegister(RCategory.Argument, RType.Object); foreach (var p in invokePrototype.Parameters) { if (p.Type.IsWide()) { body.AllocateWideRegister(RCategory.Argument); } else { var type = (p.Type is PrimitiveType) ? RType.Value : RType.Object; body.AllocateRegister(RCategory.Argument, type); } } var incomingMethodArgs = body.Registers.ToArray(); // Create code var ins = body.Instructions; Register instance = null; if (!calledMethod.IsStatic) { // load instance instance = body.AllocateRegister(RCategory.Temp, RType.Object); ins.Add(new Instruction(RCode.Iget_object, instance, rthis) { Operand = instanceField }); } // Invoke var calledMethodRef = calledMethod.GetReference(targetPackage); var inputArgs = calledMethod.IsStatic ? incomingMethodArgs.Skip(1).ToArray() : incomingMethodArgs; // Cast arguments (if needed) var outputArgs = new List <Register>(); if (!calledMethod.IsStatic) { outputArgs.Add(instance); } var parameterIndex = 0; for (var i = calledMethod.IsStatic ? 0 : 1; i < inputArgs.Length;) { var invokeType = invokePrototype.Parameters[parameterIndex].Type; var inputIsWide = invokeType.IsWide(); var calledType = calledMethodPrototype.Parameters[parameterIndex].Type; if (!invokeType.Equals(calledType)) { // Add cast / unbox var source = inputIsWide ? new RegisterSpec(inputArgs[i], inputArgs[i + 1], invokeType) : new RegisterSpec(inputArgs[i], null, invokeType); var tmp = ins.Unbox(sequencePoint, source, calledMethod.Parameters[parameterIndex].ParameterType, compiler, targetPackage, body); outputArgs.Add(tmp.Result.Register); if (calledType.IsWide()) { outputArgs.Add(tmp.Result.Register2); } } else { outputArgs.Add(inputArgs[i]); if (calledType.IsWide()) { outputArgs.Add(inputArgs[i + 1]); } } i += inputIsWide ? 2 : 1; parameterIndex++; } // Actual call ins.Add(new Instruction(calledMethod.Invoke(calledMethod, null), calledMethodRef, outputArgs.ToArray())); // Collect return value var invokeReturnType = invokePrototype.ReturnType; var calledReturnType = calledMethodPrototype.ReturnType; var needsBoxing = !invokeReturnType.Equals(calledReturnType); Instruction returnInstruction; if (calledReturnType.IsWide()) { var r = body.AllocateWideRegister(RCategory.Temp); ins.Add(new Instruction(RCode.Move_result_wide, r.Item1)); if (needsBoxing) { // Box var source = new RegisterSpec(r.Item1, r.Item2, calledReturnType); var tmp = ins.Box(sequencePoint, source, calledMethod.ReturnType, targetPackage, body); returnInstruction = new Instruction(RCode.Return_object, tmp.Result.Register); } else { // Return wide returnInstruction = new Instruction(RCode.Return_wide, r.Item1); } } else if (calledMethod.ReturnType.IsVoid()) { // Void return returnInstruction = new Instruction(RCode.Return_void); } else if (calledReturnType is PrimitiveType) { // Single register return var r = body.AllocateRegister(RCategory.Temp, RType.Value); ins.Add(new Instruction(RCode.Move_result, r)); if (needsBoxing) { // Box var source = new RegisterSpec(r, null, invokeReturnType); var tmp = ins.Box(sequencePoint, source, calledMethod.ReturnType, targetPackage, body); returnInstruction = new Instruction(RCode.Return_object, tmp.Result.Register); } else { // Return returnInstruction = new Instruction(RCode.Return, r); } } else { var r = body.AllocateRegister(RCategory.Temp, RType.Object); ins.Add(new Instruction(RCode.Move_result_object, r)); if (needsBoxing) { // Box var source = new RegisterSpec(r, null, invokeReturnType); var tmp = ins.Box(sequencePoint, source, invokeMethod.ReturnType, targetPackage, body); returnInstruction = new Instruction(RCode.Return_object, tmp.Result.Register); } else { // Return returnInstruction = new Instruction(RCode.Return_object, r); } } // Call next delegate (if any) var next = body.AllocateRegister(RCategory.Temp, RType.Object); var multicastDelegateType = new ClassReference(targetPackage.NameConverter.GetConvertedFullName("System.MulticastDelegate")); var nextReference = new FieldReference(multicastDelegateType, "next", multicastDelegateType); ins.Add(new Instruction(RCode.Iget_object, nextReference, new[] { next, rthis })); // load this.next var afterCallNext = new Instruction(RCode.Nop); ins.Add(new Instruction(RCode.If_eqz, afterCallNext, new[] { next })); // if next == null, continue ins.Add(new Instruction(RCode.Check_cast, delegateClass, new[] { next })); var nextInvokeMethod = new MethodReference(delegateClass, "Invoke", invokePrototype); var nextInvokeArgs = new[] { next }.Concat(incomingMethodArgs.Skip(1)).ToArray(); ins.Add(new Instruction(RCode.Invoke_virtual, nextInvokeMethod, nextInvokeArgs)); ins.Add(afterCallNext); // Add return instructions ins.Add(returnInstruction); return(body); }
/// <summary> /// For each register in the given list, ensure that all keep-with-next registers are also added. /// </summary> private static void AddKeepWithNext(List<Register> registers, MethodBody body) { var i = 0; while (i < registers.Count) { var r = registers[i++]; if ((r.Flags & RFlags.KeepWithNext) == 0) continue; var next = body.Registers.First(x => x.Index == r.Index + 1); if (!registers.Contains(next)) { registers.Insert(i, next); } } }
/// <summary> /// Create the body of the invoke method. /// </summary> /// <param name="calledMethodPrototype"></param> private MethodBody CreateInvokeBody(Prototype calledMethodPrototype) { var body = new MethodBody(null); var rthis = body.AllocateRegister(RCategory.Argument, RType.Object); foreach (var p in invokePrototype.Parameters) { if (p.Type.IsWide()) { body.AllocateWideRegister(RCategory.Argument); } else { var type = (p.Type is PrimitiveType) ? RType.Value : RType.Object; body.AllocateRegister(RCategory.Argument, type); } } var incomingMethodArgs = body.Registers.ToArray(); // Create code var ins = body.Instructions; Register instanceReg = null; if (!calledMethod.IsStatic) { // load instance instanceReg = body.AllocateRegister(RCategory.Temp, RType.Object); ins.Add(new Instruction(RCode.Iget_object, instanceReg, rthis) { Operand = instanceField }); } List<Register> genericTypeParameterRegs = new List<Register>(); foreach(var field in GenericTypeFields) { var r = body.AllocateRegister(RCategory.Temp, RType.Object); ins.Add(new Instruction(RCode.Iget_object, r, rthis) { Operand = field }); genericTypeParameterRegs.Add(r); } // Invoke var calledMethodRef = calledMethod.GetReference(targetPackage); var inputArgs = calledMethod.IsStatic ? incomingMethodArgs.Skip(1).ToArray() : incomingMethodArgs; // Cast arguments (if needed) var outputArgs = new List<Register>(); if (!calledMethod.IsStatic) { outputArgs.Add(instanceReg); } var parameterIndex = 0; for (var i = calledMethod.IsStatic ? 0 : 1; i < inputArgs.Length; ) { var invokeType = invokePrototype.Parameters[parameterIndex].Type; var inputIsWide = invokeType.IsWide(); var calledType = calledMethodPrototype.Parameters[parameterIndex].Type; if (!invokeType.Equals(calledType)) { // Add cast / unbox var source = inputIsWide ? new RegisterSpec(inputArgs[i], inputArgs[i + 1], invokeType) : new RegisterSpec(inputArgs[i], null, invokeType); var tmp = ins.Unbox(sequencePoint, source, calledMethod.Parameters[parameterIndex].ParameterType, compiler, targetPackage, body); outputArgs.Add(tmp.Result.Register); if (calledType.IsWide()) { outputArgs.Add(tmp.Result.Register2); } } else { outputArgs.Add(inputArgs[i]); if (calledType.IsWide()) { outputArgs.Add(inputArgs[i + 1]); } } i += inputIsWide ? 2 : 1; parameterIndex++; } outputArgs.AddRange(genericTypeParameterRegs); // Actual call ins.Add(new Instruction(calledMethod.Invoke(calledMethod, null), calledMethodRef, outputArgs.ToArray())); // Collect return value var invokeReturnType = invokePrototype.ReturnType; var calledReturnType = calledMethodPrototype.ReturnType; var needsBoxing = !invokeReturnType.Equals(calledReturnType); Instruction returnInstruction; Instruction nextMoveResultInstruction = null; if (calledReturnType.IsWide()) { var r = body.AllocateWideRegister(RCategory.Temp); ins.Add(new Instruction(RCode.Move_result_wide, r.Item1)); if (needsBoxing) { // Box var source = new RegisterSpec(r.Item1, r.Item2, calledReturnType); var tmp = ins.Box(sequencePoint, source, calledMethod.ReturnType, targetPackage, body); returnInstruction = new Instruction(RCode.Return_object, tmp.Result.Register); nextMoveResultInstruction = new Instruction(RCode.Move_result_object, tmp.Result.Register); } else { // Return wide returnInstruction = new Instruction(RCode.Return_wide, r.Item1); nextMoveResultInstruction = new Instruction(RCode.Move_result_wide, r.Item1); } } else if (calledMethod.ReturnType.IsVoid()) { // Void return returnInstruction = new Instruction(RCode.Return_void); } else if (calledReturnType is PrimitiveType) { // Single register return var r = body.AllocateRegister(RCategory.Temp, RType.Value); ins.Add(new Instruction(RCode.Move_result, r)); if (needsBoxing) { // Box var source = new RegisterSpec(r, null, invokeReturnType); var tmp = ins.Box(sequencePoint, source, calledMethod.ReturnType, targetPackage, body); returnInstruction = new Instruction(RCode.Return_object, tmp.Result.Register); nextMoveResultInstruction = new Instruction(RCode.Move_result_object, tmp.Result.Register); } else { // Return returnInstruction = new Instruction(RCode.Return, r); nextMoveResultInstruction = new Instruction(RCode.Move_result, r); } } else { var r = body.AllocateRegister(RCategory.Temp, RType.Object); ins.Add(new Instruction(RCode.Move_result_object, r)); if (needsBoxing) { // Box var source = new RegisterSpec(r, null, invokeReturnType); var tmp = ins.Box(sequencePoint, source, invokeMethod.ReturnType, targetPackage, body); returnInstruction = new Instruction(RCode.Return_object, tmp.Result.Register); nextMoveResultInstruction = new Instruction(RCode.Move_result_object, tmp.Result.Register); } else { // Return returnInstruction = new Instruction(RCode.Return_object, r); nextMoveResultInstruction = new Instruction(RCode.Move_result_object, r); } } // Call delegate list var multicastDelegateType = new ClassReference(targetPackage.NameConverter.GetConvertedFullName("System.MulticastDelegate")); var invListLengthReference = new FieldReference(multicastDelegateType, "InvocationListLength", PrimitiveType.Int); var multicastDelegateArray = new ArrayType(multicastDelegateType); var invListReference = new FieldReference(multicastDelegateType, "InvocationList", multicastDelegateArray); var index = body.AllocateRegister(RCategory.Temp, RType.Value); var count = body.AllocateRegister(RCategory.Temp, RType.Value); var next = body.AllocateRegister(RCategory.Temp, RType.Object); var invList = body.AllocateRegister(RCategory.Temp, RType.Object); var done = new Instruction(RCode.Nop); var nextInvokeMethod = new MethodReference(delegateClass, "Invoke", invokePrototype); var nextInvokeArgs = new[] { next }.Concat(incomingMethodArgs.Skip(1)).ToArray(); ins.Add(new Instruction(RCode.Iget, invListLengthReference, new[] {count, rthis})); ins.Add(new Instruction(RCode.If_eqz, done, new[] { count })); ins.Add(new Instruction(RCode.Const, 0, new[] { index })); ins.Add(new Instruction(RCode.Iget_object, invListReference, new[] {invList, rthis})); var getNext = new Instruction(RCode.Aget_object, null, new[] { next, invList, index }); ins.Add(getNext); ins.Add(new Instruction(RCode.Check_cast, delegateClass, new [] { next })); ins.Add(new Instruction(RCode.Invoke_virtual, nextInvokeMethod, nextInvokeArgs)); if (nextMoveResultInstruction != null) ins.Add(nextMoveResultInstruction); ins.Add(new Instruction(RCode.Add_int_lit8, 1, new[] { index, index })); ins.Add(new Instruction(RCode.If_lt, getNext, new[] { index, count })); ins.Add(done); // Add return instructions ins.Add(returnInstruction); return body; }
private static void CreateCompareArrayInstructions(InstructionList ins, MethodBody body, Register rthis, Register rother, FieldDefinition field, Register rThisValue, Register rOtherValue, Instruction returnFalseInstruction) { Instruction done = new Instruction(RCode.Nop); // Load the instance fields. ins.Add(new Instruction(RCode.Iget_object, rThisValue, rthis) {Operand = field}); ins.Add(new Instruction(RCode.Iget_object, rOtherValue, rother) {Operand = field}); var rThisLen = body.AllocateRegister(RCategory.Temp, RType.Value); var rOtherLen = body.AllocateRegister(RCategory.Temp, RType.Value); // load length ins.Add(new Instruction(RCode.Array_length, rThisLen, rThisValue)); ins.Add(new Instruction(RCode.Array_length, rOtherLen, rOtherValue)); // Compare the length ins.Add(new Instruction(RCode.If_ne, returnFalseInstruction, new[] { rThisLen, rOtherLen })); ins.Add(new Instruction(RCode.If_eqz, done, new[] {rThisLen})); // now iterate over all elements in the array. var thisType = body.AllocateRegister(RCategory.Temp, RType.Object); var otherType = body.AllocateRegister(RCategory.Temp, RType.Object); var counter = body.AllocateRegister(RCategory.Temp, RType.Object); ins.Add(new Instruction(RCode.Const, 0, new[] {counter})); var loadThisVal = new Instruction(RCode.Aget_object, thisType, rThisValue, counter); ins.Add(loadThisVal); ins.Add(new Instruction(RCode.Aget_object, otherType, rOtherValue, counter)); // compare types. ins.Add(new Instruction(RCode.If_ne, returnFalseInstruction, new[] {thisType, otherType})); ins.Add(new Instruction(RCode.Add_int_lit8, 1, new[] {counter, counter})); ins.Add(new Instruction(RCode.If_ne, loadThisVal, new[] {counter, rThisLen})); ins.Add(done); }
/// <summary> /// Create the body of the ctor. /// </summary> private static MethodBody CreateCtorBody(XMethodDefinition calledMethod, FieldDefinition instanceField, ClassReference baseClass) { var body = new MethodBody(null); // Create code var ins = body.Instructions; var rthis = body.AllocateRegister(RCategory.Argument, RType.Object); // Call base ctor var baseCtorRef = new MethodReference(baseClass, "<init>", new Prototype(PrimitiveType.Void)); ins.Add(new Instruction(RCode.Invoke_direct, rthis) { Operand = baseCtorRef }); if (!calledMethod.IsStatic) { // load instance into field var rvalue = body.AllocateRegister(RCategory.Argument, RType.Object); ins.Add(new Instruction(RCode.Iput_object, rvalue, rthis) {Operand = instanceField}); } ins.Add(new Instruction(RCode.Return_void)); return body; }
/// <summary> /// Create the body of the equals method. /// </summary> private static MethodBody CreateEqualsCheckTypeOnlyBody(ClassReference delegateClass) { MethodBody body = new MethodBody(null); // This pointer and method argument. Register rthis = body.AllocateRegister(RCategory.Argument, RType.Object); Register rother = body.AllocateRegister(RCategory.Argument, RType.Object); // result register Register result = body.AllocateRegister(RCategory.Temp, RType.Value); var ins = body.Instructions; // Check if other object can be casted. ins.Add(new Instruction(RCode.Instance_of, delegateClass, new[] { result, rother })); // Add return instructions ins.Add(new Instruction(RCode.Return, result)); return body; }
/// <summary> /// Create the body of the equals method. /// </summary> private static MethodBody CreateEqualsBody(ISourceLocation sequencePoint, AssemblyCompiler compiler, DexTargetPackage targetPackage, XMethodDefinition equalsMethod, Prototype equalsPrototype, FieldDefinition instanceField, ClassReference delegateClass) { MethodBody body = new MethodBody(null); // This pointer and method argument. Register rthis = body.AllocateRegister(RCategory.Argument, RType.Object); Register rother = body.AllocateRegister(RCategory.Argument, RType.Object); // Create code. var ins = body.Instructions; // Temporary parameter result. Register result = body.AllocateRegister(RCategory.Temp, RType.Value); // Prepare the return instruction. Instruction returnInstruction = new Instruction(RCode.Return, result); // Check if other object can be casted. ins.Add(new Instruction(RCode.Instance_of, delegateClass, new[] { result, rother })); ins.Add(new Instruction(RCode.If_eqz, returnInstruction, new[] { result })); // compare instance members // Cast of the other object. ins.Add(new Instruction(RCode.Check_cast, delegateClass, new[] { rother })); // Get instance fields of this and other. var thisInstance = body.AllocateRegister(RCategory.Temp, RType.Object); var otherInstance = body.AllocateRegister(RCategory.Temp, RType.Object); // Load the instance fields. ins.Add(new Instruction(RCode.Iget_object, thisInstance, rthis) { Operand = instanceField }); ins.Add(new Instruction(RCode.Iget_object, otherInstance, rother) { Operand = instanceField }); // Compare the instance fields. ins.Add(new Instruction(RCode.If_eq, returnInstruction, new[] { thisInstance, otherInstance })); // compare instance members // Set result to false if not equal. ins.Add(new Instruction(RCode.Const, 0, new[] { result })); // Add return instructions ins.Add(returnInstruction); return body; }
/// <summary> /// Find all basic blocks in the given body. /// </summary> public static List<BasicBlock> Find(MethodBody body) { if (body.Instructions.Count == 0) return new List<BasicBlock>(); // Tuple<int, Instruction> var targetInstructions = body.Instructions.Select(x => x.Operand).OfType<Instruction>().ToList(); targetInstructions.AddRange(body.Instructions.Select(x => x.Operand).OfType<Instruction[]>().SelectMany(x => x)); targetInstructions.AddRange(body.Instructions.Select(x => x.Operand).OfType<Tuple<int, Instruction>[]>().SelectMany(x => x).Select(x => x.Item2)); targetInstructions.AddRange(body.Instructions.Where(x => x.Code.IsBranch() || x.Code.IsReturn()).Select(x => x.NextOrDefault)); targetInstructions.AddRange(body.Exceptions.Select(x => x.TryStart)); targetInstructions.AddRange(body.Exceptions.Select(x => x.TryEnd.Next)); targetInstructions.AddRange(body.Exceptions.SelectMany(x => x.Catches, (h, y) => y.Instruction)); targetInstructions.AddRange(body.Exceptions.Select(x => x.CatchAll)); targetInstructions.Add(body.Instructions[0]); // Get sorted list with duplicates removed. var startInstructions = targetInstructions.Where(x => x != null).Distinct().OrderBy(x => x.Index).ToList(); var result = new List<BasicBlock>(); for (var i = 0; i < startInstructions.Count; i++) { var entry = startInstructions[i]; var exit = (i + 1 < startInstructions.Count) ? startInstructions[i + 1].Previous : body.Instructions[body.Instructions.Count - 1]; result.Add(new BasicBlock(body.Instructions, entry, exit)); } return result; }
/// <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> /// Create code to load a value from an annotation interface. /// </summary> /// <returns>The register(s) holding the value</returns> private static Register[] CreateLoadValueSequence( ISourceLocation seqp, MethodBody body, TypeReference valueType, Register annotationReg, MethodDefinition getter) { if (valueType.IsWide()) { Tuple<Register, Register> regs = body.AllocateWideRegister(RCategory.Temp); body.Instructions.Add(seqp, RCode.Invoke_interface, getter, annotationReg); body.Instructions.Add(seqp, RCode.Move_result_wide, regs.Item1); return new[] { regs.Item1, regs.Item2 }; } if (valueType is PrimitiveType) { Register reg = body.AllocateRegister(RCategory.Temp, RType.Value); body.Instructions.Add(seqp, RCode.Invoke_interface, getter, annotationReg); body.Instructions.Add(seqp, RCode.Move_result, reg); return new[] { reg }; } else { Register reg = body.AllocateRegister(RCategory.Temp, RType.Object); body.Instructions.Add(seqp, RCode.Invoke_interface, getter, annotationReg); body.Instructions.Add(seqp, RCode.Move_result_object, reg); return new[] { reg }; } }
/// <summary> /// Gets all registers of category!=Argument that are used in an instruction. /// </summary> private static void GetUsedArgumentRegisters(MethodBody body, out Dictionary<Register, RegisterFlags> used, out int maxOutgoingRegisters, out bool largeInvokeInsFound) { //maxOutgoingRegisters = body.Instructions.Max(x => x.Code.IsInvoke() ? x.Registers.Count : 0); //largeInvokeInsFound = body.Instructions.Any(x => x.Code.IsInvoke() && x.Registers.Count > 5); maxOutgoingRegisters = 0; largeInvokeInsFound = false; used = new Dictionary<Register, RegisterFlags>(); foreach (var ins in body.Instructions) { if (ins.Code.IsInvoke()) { maxOutgoingRegisters = Math.Max(maxOutgoingRegisters, ins.Registers.Count); if (ins.Registers.Count > 5) { largeInvokeInsFound = true; } } foreach (var reg in ins.Registers) { if (reg.Category != RCategory.Argument) { var lowestSize = GetLowestSize(ins, reg); RegisterFlags currentLowestSize; if (used.TryGetValue(reg, out currentLowestSize)) { if (lowestSize < currentLowestSize) { used[reg] = lowestSize; } } else { used.Add(reg, lowestSize); } } } } // Add second register of wide registers. Register prevReg = null; foreach (var reg in body.Registers) { if (prevReg != null) { if (reg.Type == RType.Wide2) { RegisterFlags flags; if (used.TryGetValue(prevReg, out flags)) { used[reg] = flags; } } } prevReg = reg; } }
private static MethodDefinition CreateFactoryMethod(AssemblyCompiler compiler, DexTargetPackage targetPackage, CustomAttribute attribute, AttributeAnnotationMapping mapping) { var targetClass = mapping.AttributeClass; // is this really the right place for the factory methods? ISourceLocation seqp = null; var attributeTypeDef = attribute.AttributeType.Resolve(); // create method string methodName = CreateAttributeFactoryMethodName(targetClass); MethodDefinition method = new MethodDefinition(targetClass, methodName, new Prototype(mapping.AttributeClass)); method.AccessFlags = AccessFlags.Public | AccessFlags.Static | AccessFlags.Synthetic; targetClass.Methods.Add(method); // create method body MethodBody body = new MethodBody(null); // Allocate attribute Register attributeReg = body.AllocateRegister(RCategory.Temp, RType.Object); body.Instructions.Add(seqp, RCode.New_instance, mapping.AttributeClass, attributeReg); // collect ctor arguments List<Register> ctorArgRegs = new List<Register>() { attributeReg }; foreach (var p in attribute.ConstructorArguments) { XTypeReference xType = XBuilder.AsTypeReference(compiler.Module, p.Type); Register[] valueRegs = CreateInitializeValueInstructions(seqp, body, xType, p, compiler, targetPackage); ctorArgRegs.AddRange(valueRegs); } // Invoke ctor DexLib.MethodReference dctor = attribute.Constructor.GetReference(targetPackage, compiler.Module); body.Instructions.Add(seqp, RCode.Invoke_direct, dctor, ctorArgRegs.ToArray()); // set field values foreach (var p in attribute.Fields) { var field = GetField(attributeTypeDef, p.Name); var xField = XBuilder.AsFieldReference(compiler.Module, field); Register[] valueRegs = CreateInitializeValueInstructions(seqp, body, xField.FieldType, p.Argument, compiler, targetPackage); body.Instructions.Add(seqp, xField.FieldType.IPut(), xField.GetReference(targetPackage), valueRegs[0], attributeReg); } // set property values foreach (var p in attribute.Properties) { PropertyDefinition property = GetSettableProperty(attributeTypeDef, p.Name); XTypeReference xType = XBuilder.AsTypeReference(compiler.Module, property.PropertyType); Register[] valueRegs = CreateInitializeValueInstructions(seqp, body, xType, p.Argument, compiler, targetPackage); XMethodDefinition xSetMethod = XBuilder.AsMethodDefinition(compiler.Module, property.SetMethod); body.Instructions.Add(seqp, xSetMethod.Invoke(xSetMethod, null), xSetMethod.GetReference(targetPackage), new[] { attributeReg }.Concat(valueRegs).ToArray()); } // Return attribute body.Instructions.Add(seqp, RCode.Return_object, attributeReg); // Register method body targetPackage.Record(new CompiledMethod() { DexMethod = method, RLBody = body }); // Return method return method; }
/// <summary> /// Create a method definition for the builder method that builds a custom attribute from an annotation. /// </summary> private static MethodDefinition CreateBuildMethod( ISourceLocation seqp, Mono.Cecil.MethodDefinition ctor, List<Tuple<MethodDefinition, Mono.Cecil.TypeReference>> paramGetMethods, AssemblyCompiler compiler, DexTargetPackage targetPackage, ClassDefinition attributeClass, AttributeAnnotationInterface mapping) { // Create method definition string name = CreateBuildMethodName(attributeClass); TypeReference attributeTypeRef = ctor.DeclaringType.GetReference(targetPackage, compiler.Module); MethodDefinition method = new MethodDefinition(attributeClass, name, new Prototype(attributeTypeRef, new Parameter(mapping.AnnotationInterfaceClass, "ann"))); method.AccessFlags = AccessFlags.Public | AccessFlags.Static | AccessFlags.Synthetic; attributeClass.Methods.Add(method); // Create method body MethodBody body = new MethodBody(null); Register annotationReg = body.AllocateRegister(RCategory.Argument, RType.Object); //body.Instructions.Add(seqp, RCode.Check_cast, mapping.AnnotationInterfaceClass, annotationReg); // Allocate attribute Register attributeReg = body.AllocateRegister(RCategory.Temp, RType.Object); body.Instructions.Add(seqp, RCode.New_instance, attributeClass, attributeReg); // Get ctor arguments List<Register> ctorArgRegs = new List<Register>(); foreach (var p in paramGetMethods) { Instruction branchIfNotSet; // this can not happen, but lets keep the code below simple. XModel.XTypeReference xType = XBuilder.AsTypeReference(compiler.Module, p.Item2); Register[] valueRegs = CreateLoadValueSequence(seqp, body, xType, annotationReg, p.Item1, compiler, targetPackage, out branchIfNotSet); branchIfNotSet.Operand = body.Instructions.Add(seqp, RCode.Nop); ctorArgRegs.AddRange(valueRegs); } // Invoke ctor DexLib.MethodReference dctor = ctor.GetReference(targetPackage, compiler.Module); body.Instructions.Add(seqp, RCode.Invoke_direct, dctor, new[] { attributeReg }.Concat(ctorArgRegs).ToArray()); // Get field values foreach (var fieldMap in mapping.FieldToGetMethodMap) { var field = fieldMap.Key; XModel.XTypeReference xFieldType = XBuilder.AsTypeReference(compiler.Module, field.FieldType); MethodDefinition getter = fieldMap.Value; Instruction branchIfNotSet; Register[] valueRegs = CreateLoadValueSequence(seqp, body, xFieldType, annotationReg, getter, compiler, targetPackage, out branchIfNotSet); var put = body.Instructions.Add(seqp, xFieldType.IPut(), valueRegs[0], attributeReg); mapping.FixOperands.Add(Tuple.Create(put, (MemberReference)field)); branchIfNotSet.Operand = body.Instructions.Add(seqp, RCode.Nop); } // Get property values foreach (var propertyMap in mapping.PropertyToGetMethodMap) { PropertyDefinition property = propertyMap.Key; XTypeReference xType = XBuilder.AsTypeReference(compiler.Module, property.PropertyType); MethodDefinition getter = propertyMap.Value; Instruction branchIfNotSet; Register[] valueRegs = CreateLoadValueSequence(seqp, body, xType, annotationReg, getter, compiler, targetPackage, out branchIfNotSet); XModel.XMethodDefinition xSetMethod = XBuilder.AsMethodDefinition(compiler.Module, property.SetMethod); var set = body.Instructions.Add(seqp, xSetMethod.Invoke(xSetMethod, null), null, new[] { attributeReg }.Concat(valueRegs).ToArray()); mapping.FixOperands.Add(Tuple.Create(set, (MemberReference)property.SetMethod)); branchIfNotSet.Operand = body.Instructions.Add(seqp, RCode.Nop); } // Return attribute body.Instructions.Add(seqp, RCode.Return_object, attributeReg); // Register method body targetPackage.Record(new CompiledMethod() { DexMethod = method, RLBody = body }); // Return method return method; }
/// <summary> /// Create code to initialize a value from an attribute. /// </summary> /// <returns>The register(s) holding the value</returns> private static Register[] CreateInitializeValueInstructions(ISourceLocation seqp, MethodBody body, XTypeReference targetType, CustomAttributeArgument value, AssemblyCompiler compiler, DexTargetPackage targetPackage) { List<Register> result = new List<Register>(); // allocate result, initialize to default value. if (targetType.IsWide()) { Tuple<Register, Register> regs = body.AllocateWideRegister(RCategory.Temp); //body.Instructions.Add(seqp, RCode.Const_wide, 0, regs.Item1); result.Add(regs.Item1); result.Add(regs.Item2); } else if (targetType.IsPrimitive) { Register reg = body.AllocateRegister(RCategory.Temp, RType.Value); //body.Instructions.Add(seqp, RCode.Const, 0, reg); result.Add(reg); } else // object { Register reg = body.AllocateRegister(RCategory.Temp, RType.Object); //body.Instructions.Add(seqp, RCode.Const, 0, reg); result.Add(reg); } // load data if (value.Value == null) // must be a reference type { body.Instructions.Add(seqp, RCode.Const, 0, result[0]); body.Instructions.Add(seqp, RCode.Check_cast, targetType.GetReference(targetPackage), result[0]); return result.ToArray(); } var valueType = XBuilder.AsTypeReference(compiler.Module, value.Type); if (value.Value is CustomAttributeArgument) { // this happens if a type conversion is neccessary var nestedValue = (CustomAttributeArgument)value.Value; valueType = XBuilder.AsTypeReference(compiler.Module, nestedValue.Type); var rOrigValue = CreateInitializeValueInstructions(seqp, body, valueType, nestedValue, compiler, targetPackage); if (!nestedValue.Type.IsPrimitive) { body.Instructions.Add(seqp, RCode.Move_object, result[0], rOrigValue[0]); body.Instructions.Add(seqp, RCode.Check_cast, targetType.GetReference(targetPackage), result[0]); } else if(!targetType.IsPrimitive) { body.Instructions.Add(seqp, RCode.Invoke_static, valueType.GetBoxValueOfMethod(), rOrigValue); body.Instructions.Add(seqp, RCode.Move_result_object, result[0]); body.Instructions.Add(seqp, RCode.Check_cast, targetType.GetReference(targetPackage), result[0]); } else { throw new Exception(string.Format("type converstion in attribute {0}=>{1} not yet supported", valueType.FullName, targetType.FullName)); } } else if (valueType.IsArray) { var array = (CustomAttributeArgument[])value.Value; var elementType = valueType.ElementType; Register rIndex = body.AllocateRegister(RCategory.Temp, RType.Value); body.Instructions.Add(seqp, RCode.Const, array.Length, rIndex); body.Instructions.Add(seqp, RCode.New_array, valueType.GetReference(targetPackage), result[0], rIndex); // iterate through each value for (int i = 0; i < array.Length; i++) { Register rLoaded = CreateInitializeValueInstructions(seqp, body, elementType, array[i], compiler, targetPackage)[0]; body.Instructions.Add(seqp, RCode.Const, i, rIndex); body.Instructions.Add(seqp, valueType.APut(), rLoaded, result[0], rIndex); } } else if (targetType.IsEnum()) { var enumClass = (targetType.IsEnum()? targetType:valueType).GetReference(targetPackage) ; Register rEnumClass = body.AllocateRegister(RCategory.Temp, RType.Object); body.Instructions.Add(seqp, RCode.Const_class, enumClass, rEnumClass); long lVal = Convert.ToInt64(value.Value); if (lVal <= int.MaxValue && lVal >= int.MinValue) { Register regTmp = body.AllocateRegister(RCategory.Temp, RType.Value); body.Instructions.Add(seqp, RCode.Const, (int)lVal, regTmp); var get = compiler.GetDot42InternalType("Enum").Resolve() .Methods.Single(p => p.Name == "Get" && p.Parameters.Count == 2 && !p.Parameters[1].ParameterType.IsWide()) .GetReference(targetPackage); body.Instructions.Add(seqp, RCode.Invoke_static, get, rEnumClass, regTmp); body.Instructions.Add(seqp, targetType.MoveResult(), result[0]); } else { var regTmp = body.AllocateWideRegister(RCategory.Temp); body.Instructions.Add(seqp, RCode.Const, (long)lVal, regTmp.Item1); var get = compiler.GetDot42InternalType("Enum").Resolve() .Methods.Single(p => p.Name == "Get" && p.Parameters.Count == 2 && p.Parameters[1].ParameterType.IsWide()) .GetReference(targetPackage); body.Instructions.Add(seqp, RCode.Invoke_static, get, rEnumClass, regTmp.Item1); body.Instructions.Add(seqp, targetType.MoveResult(), result[0]); } body.Instructions.Add(seqp, RCode.Check_cast, targetType.GetReference(targetPackage), result[0]); } else if (valueType.IsSystemString()) { body.Instructions.Add(seqp, RCode.Const_string, (string)value.Value, result[0]); } else if (valueType.IsSystemType()) { var type = XBuilder.AsTypeReference(compiler.Module, (TypeReference)value.Value); // TODO: this might not work with typeof(void) on ART runtime. body.Instructions.Add(seqp, RCode.Const_class, type.GetReference(targetPackage), result[0]); } else if (!valueType.IsPrimitive) { // can this happen? throw new Exception("invalid value type in attribute: " + targetType.FullName); } else { if (targetType.IsSystemObject()) { // can this happen? or is this always handled above? // boxing required. var rUnboxed = CreateInitializeValueInstructions(seqp, body, valueType, value, compiler, targetPackage); body.Instructions.Add(seqp, RCode.Invoke_static, valueType.GetBoxValueOfMethod(), rUnboxed); body.Instructions.Add(seqp, RCode.Move_result_object, result[0]); } else if(targetType.IsDouble()) { body.Instructions.Add(seqp, RCode.Const_wide, Convert.ToDouble(value.Value), result[0]); } else if (targetType.IsWide() && valueType.IsUInt64()) { body.Instructions.Add(seqp, RCode.Const_wide, (long)Convert.ToUInt64(value.Value), result[0]); } else if (targetType.IsWide()) { body.Instructions.Add(seqp, RCode.Const_wide, Convert.ToInt64(value.Value), result[0]); } else if (targetType.IsFloat()) { body.Instructions.Add(seqp, RCode.Const, Convert.ToSingle(value.Value), result[0]); } else { body.Instructions.Add(seqp, RCode.Const, (int)Convert.ToInt64(value.Value), result[0]); } } return result.ToArray(); }
public RegisterUsageMap2(ControlFlowGraph2 graph) { _graph = graph; _usages = new Dictionary<Register, RegisterUsage>(); _body = graph.Body; _basicBlocks = graph.BasicBlocks; CollectBasicUsages(_basicBlocks, _usages); // TODO: seperate independant usages. }
public RegisterUsageMap2(MethodBody body) { _body = body; _usages = new Dictionary<Register, RegisterUsage>(); _basicBlocks = BasicBlock.Find(body); CollectBasicUsages(_basicBlocks, _usages); // TODO: seperate independant usages. }
/// <summary> /// Default ctor /// </summary> public RegisterMapper(MethodBody body, InvocationFrame frame) { this.frame = frame; // Select all non-argument registers that are in use. Dictionary <Register, RegisterFlags> used; int maxOutgoingRegisters; bool largeInvokeInsFound; GetUsedArgumentRegisters(body, out used, out maxOutgoingRegisters, out largeInvokeInsFound); //var used = body.Registers.Where(x => (x.Category != RCategory.Argument) && body.Instructions.Uses(x)).ToList(); var sorted = used.OrderBy(x => x.Value).ThenBy(x => x.Key.Index).Select(x => x.Key).ToList(); AddKeepWithNext(sorted, body); // Collect argument registers var arguments = body.Registers.Where(x => x.Category == RCategory.Argument).ToList(); // Prepare various decisions //var maxOutgoingRegisters = body.Instructions.Max(x => x.Code.IsInvoke() ? x.Registers.Count : 0); var required = sorted.Count + arguments.Count; //var largeInvokeInsFound = body.Instructions.Any(x => x.Code.IsInvoke() && x.Registers.Count > 5); // Allocate Dex registers for each var index = 0; // Allocate spill registers (if needed) if ((required >= 16) || (largeInvokeInsFound && (required + maxOutgoingRegisters >= 16))) { spillRangeRegisters = new DexLib.Instructions.Register[MaxSpillRegisters]; for (var i = 0; i < MaxSpillRegisters; i++) { spillRangeRegisters[i] = new DexLib.Instructions.Register(index++); } } // Allocate Dex registers for each temp register. foreach (var r in sorted) { var dreg = new DexLib.Instructions.Register(index++); map[r] = dreg; dRegisterTypes[dreg] = r.Type; } // Allocate outgoing invocation frame (if needed) if ((required >= 16) || largeInvokeInsFound) { invokeRangeRegisters = new DexLib.Instructions.Register[maxOutgoingRegisters]; for (var i = 0; i < maxOutgoingRegisters; i++) { invokeRangeRegisters[i] = new DexLib.Instructions.Register(index++); } } // Allocate Dex registers for each argument foreach (var r in arguments) { var dreg = new DexLib.Instructions.Register(index++); map[r] = dreg; dRegisterTypes[dreg] = r.Type; } ArgumentCount = arguments.Count; }
private void AddMethod(ClassDefinition @class, string methodName, Prototype prototype, AccessFlags accessFlags, MethodBody body) { var method = new MethodDefinition(@class, methodName, prototype); method.AccessFlags = accessFlags; @class.Methods.Add(method); targetPackage.Record(new CompiledMethod { DexMethod = method, RLBody = body}); }