public override void VisitCallInstruction(CallInstruction instruction) { var callExternal = _program.IsExternalType(instruction.TypeSpec); var methodArgs = PopMethodArgs(instruction); IValue thisVal = null; if (instruction.CallConv.IsInstance) { ControlState.EvaluationStack.PopValue(_program, instruction.TypeSpec.GetCilType(_program), out thisVal); } if (callExternal) { var result = CallExternalMethod(instruction, thisVal, methodArgs.ToArray(), null); if (!(instruction.ReturnType is CilTypeVoid)) { var resultVal = instruction.ReturnType.CreateValueFromRuntime(result, ManagedMemory, _program); ControlState.EvaluationStack.PushValue(resultVal); } ControlState.MoveToNextInstruction(); } else { var @class = _program.Classes.Single(c => c.Name.ToString() == instruction.TypeSpec.ClassName.ToString()); var method = @class.Methods.Single(m => m.Name == instruction.MethodName && AreArgumentsAssignable(instruction.SigArgs, m.Arguments)); var sigArgsWithThis = CompleteSigArgs(instruction, method); var argsWithThis = CompleteArgs(instruction, methodArgs, thisVal); var newMethodState = new CilMethodState(method, sigArgsWithThis, argsWithThis, _program); ControlState.MoveToNextInstruction(); ControlState.CallStack.Push(newMethodState); } }
public override void VisitNewObjectInstruction(NewObjectInstruction instruction) { var callExternal = _program.IsExternalType(instruction.TypeSpec); var methodArgs = PopMethodArgs(instruction); if (callExternal) { object thisObject = null; if (instruction.CallConv.IsInstance) { thisObject = GetRuntimeEmptyInstance(instruction, methodArgs, true); } var result = CallExternalMethod(instruction, null, methodArgs.ToArray(), thisObject); var resultVal = instruction.TypeSpec.GetCilType(_program).CreateValueFromRuntime(result, ManagedMemory, _program); ControlState.EvaluationStack.PushValue(resultVal); ControlState.MoveToNextInstruction(); } else { var @class = _program.Classes.Single(c => c.Name.ToString() == instruction.TypeSpec.ClassName.ToString()); var method = @class.Methods.Single(m => m.Name == instruction.MethodName && AreArgumentsAssignable(instruction.SigArgs, m.Arguments)); var emptyInstance = new CilClassInstance(@class, _program, ManagedMemory); var thisRef = ManagedMemory.Store(emptyInstance); ControlState.EvaluationStack.PushValue(thisRef); var sigArgsWithThis = CompleteSigArgs(instruction, method); var argsWithThis = CompleteArgs(instruction, methodArgs, thisRef); var newMethodState = new CilMethodState(method, sigArgsWithThis, argsWithThis, _program); ControlState.MoveToNextInstruction(); ControlState.CallStack.Push(newMethodState); } }
public override void VisitCallVirtualInstruction(CallVirtualInstruction instruction) { if (!instruction.CallConv.IsInstance) { throw new System.NotImplementedException(); } var methodArgs = PopMethodArgs(instruction); ControlState.EvaluationStack.PopValue(_program, instruction.TypeSpec.GetCilType(_program), out var thisVal); var callExternal = true; CilClassInstance thisClassInstance = null; CilObject thisObject = null; if (thisVal is CilValueReference thisValRef) { var thisObj = ManagedMemory.Load(thisValRef); if (thisObj is CilClassInstance) { thisClassInstance = thisObj as CilClassInstance; } else { thisObject = thisObj; callExternal = true; } } else { throw new System.NotImplementedException(); } CilMethod method = null; if (thisClassInstance != null) { var currentClass = thisClassInstance.Class; while (true) { var possibleMethod = currentClass.Methods.SingleOrDefault(m => m.Name == instruction.MethodName && AreArgumentsAssignable(instruction.SigArgs, m.Arguments)); if (possibleMethod != null) { method = possibleMethod; callExternal = false; break; } currentClass = currentClass.Extends; if (currentClass == null) { callExternal = true; break; } } } if (callExternal) { var result = CallExternalMethod(instruction, thisVal, methodArgs.ToArray(), null); if (!(instruction.ReturnType is CilTypeVoid)) { var resultVal = instruction.ReturnType.CreateValueFromRuntime(result, ManagedMemory, _program); ControlState.EvaluationStack.PushValue(resultVal); } ControlState.MoveToNextInstruction(); } else { var sigArgsWithThis = CompleteSigArgs(instruction, method); var argsWithThis = CompleteArgs(instruction, methodArgs, thisVal); var newMethodState = new CilMethodState(method, sigArgsWithThis, argsWithThis, _program); ControlState.MoveToNextInstruction(); ControlState.CallStack.Push(newMethodState); } }