public override void Process(Compiler compiler, MethodData methodData, Instruction instruction) { // Get .ctor method from operand and get the class associated with it MethodReference ctor = instruction.Operand as MethodReference; TypeReference type = ctor.DeclaringType; // If the object type is native, we ignore the IL object and don't emit a NEWOBJ // After that, we call the .CTOR which will be in runtime // The .CTOR in runtime will also initialize this object if(Util.IsNativeType(type)) { // Create call to .CTOR Instruction call = Instruction.Create(OpCodes.Call, ctor); compiler.HandleInstruction(call, methodData); return; } // Write opcode and class ID int classID = compiler.GetTypeDataFromType(type.Resolve()).Id; methodData.AddInstruction(instruction.OpCode.Value); methodData.AddInstruction(classID); // Write CALL to .ctor // Count one extra parameter for the "this" object MethodDefinition methodDef = ctor.Resolve(); int ctorID = compiler.GetMethodID(methodDef); if (ctorID == -1) ctorID = compiler.ProcessMethod(methodDef); methodData.AddInstruction(ctorID); methodData.AddInstruction(ctor.Parameters.Count); }
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); } }