public override int GetSize(Compiler compiler, Instruction instruction) { // Get destination MethodReference destinationRef = instruction.Operand as MethodReference; string methodName = Util.GetFriendlyMethodName(destinationRef); // See below if (compiler.IsRuntimeMethod(methodName)) return 2; return 3; }
public override int GetSize(Compiler compiler, Instruction instruction) { // Get .ctor method from operand and get the class associated with it MethodReference ctor = instruction.Operand as MethodReference; TypeReference type = ctor.DeclaringType; // See below, if native type, this is just a CALL (3 or 2) // Else, this is a NEWOBJ (4) if (Util.IsNativeType(type)) { string methodName = Util.GetFriendlyMethodName(ctor); if (compiler.IsRuntimeMethod(methodName)) return 2; return 3; } else { return 4; } }
public override void Process(Compiler compiler, MethodData methodData, Instruction instruction) { // Get destination MethodReference destinationRef = instruction.Operand as MethodReference; string methodName = Util.GetFriendlyMethodName(destinationRef); // Check if it's a special method that should be caught here if (methodName == "ILVM_Asm_Execute2") { // IL code at this point will look like this // LOAD STRING "<assembly code>" // LOAD REGS // CALL ASM.EXECUTE // So we must check if two instructions before this the assembly code is loaded // else we need to throw an error Instruction ldstr = instruction.Previous.Previous; if (ldstr.OpCode != OpCodes.Ldstr) { throw new Exception("Assembly code needs to be directly in the call"); } else { // Prepare assembler string code = ldstr.Operand as string; Assembler asm = compiler.Assembler; int offset = asm.GetOffset(); // Since this is used as a "method" we need to place a return at the end asm.HandleCode(code); asm.HandleInstruction("ret"); int codeSize = asm.GetOffset() - offset; // Write instruction followed by asm offset and asm size methodData.AddInstruction(Ops.OP_RUNTIME_ASM); methodData.AddInstruction(offset); methodData.AddInstruction(codeSize); } return; } // If it's implemented in runtime, emit a special seperate instruction for this if (compiler.IsRuntimeMethod(methodName)) { // Write instruction followed by the runtime method ID methodData.AddInstruction(Ops.OP_RUNTIME_CALL); methodData.AddInstruction(compiler.GetRuntimeMethodID(methodName)); } else { // Get definition from reference MethodDefinition destination = destinationRef.Resolve(); // Lookup the method, if it isn't processed yet, process it int methodId = compiler.GetMethodID(destination); if (methodId == -1) methodId = compiler.ProcessMethod(destination); // If the method is not static, we pass "this" as argument, so we count 1 parameter extra int paramCount = destinationRef.Parameters.Count; if (!destination.IsStatic) paramCount++; // Write instruction followed by the method ID methodData.AddInstruction(instruction.OpCode.Value); methodData.AddInstruction(methodId); methodData.AddInstruction(paramCount); } }