private void EmitDirectCall(Operand addressOp, ReadOnlyArray <Operand> args) { if (machine.Profiling) { il.Arguments.LoadMachine(); if (addressOp.Value == 0) { il.Load(0); } else { il.Load(machine.UnpackRoutineAddress(addressOp.Value)); } il.Load(false); il.Call(Reflection <CompiledZMachine> .GetMethod("Profiler_Call", Types.Array <int, bool>(), @public: false)); } if (addressOp.Value == 0) { il.Load(0); EmitReturn(); } else { var address = machine.UnpackRoutineAddress(addressOp.Value); var routineCall = machine.GetRoutineCall(address); var index = calls.Count; calls.Add(routineCall); // load routine call il.Arguments.LoadCalls(); il.Load(index); il.Emit(OpCodes.Ldelem_Ref); foreach (var arg in args) { EmitLoadOperand(arg); } // The memory, stack and stack pointer are the last arguments passed in // case any operands manipulate them. il.Arguments.LoadMemory(); il.Arguments.LoadStack(); il.Arguments.LoadSP(); il.Call(ZRoutineCall.GetInvokeMethod(args.Length)); } }
internal ZRoutineCall GetRoutineCall(int address) { ZRoutineCall routineCall; if (!addressToRoutineCallMap.TryGetValue(address, out routineCall)) { cacheMiss++; var routine = GetRoutineByAddress(address); routineCall = new ZRoutineCall(routine, machine: this); addressToRoutineCallMap.Add(address, routineCall); } if (this.precompile && !compiling) { compiling = true; routineCall.Compile(); compiling = false; } return(routineCall); }
private void EmitCalculatedCall(Operand addressOp, ReadOnlyArray <Operand> args, bool reuse) { using (var address = il.NewLocal <int>()) { if (!reuse) { EmitLoadVariable((byte)addressOp.Value); } address.Store(); // is this address 0? var nonZeroCall = il.NewLabel(); var done = il.NewLabel(); address.Load(); nonZeroCall.BranchIf(Condition.True); if (machine.Profiling) { il.Arguments.LoadMachine(); il.Load(0); il.Load(true); var profilerCall = Reflection <CompiledZMachine> .GetMethod("Profiler_Call", Types.Array <int, bool>(), @public : false); il.Call(profilerCall); } // discard any SP operands... int spOperands = 0; for (int i = 0; i < args.Length; i++) { if (args[i].IsStackVariable) { spOperands++; } } if (spOperands > 0) { il.Arguments.LoadSP(); il.Math.Subtract(spOperands); il.Arguments.StoreSP(); } il.Load(0); done.Branch(); nonZeroCall.Mark(); if (machine.Profiling) { il.Arguments.LoadMachine(); address.Load(); UnpackRoutineAddress(); il.Load(true); il.Call(Reflection <CompiledZMachine> .GetMethod("Profiler_Call", Types.Array <int, bool>(), @public: false)); } il.Arguments.LoadMachine(); address.Load(); UnpackRoutineAddress(); il.Call(Reflection <CompiledZMachine> .GetMethod("GetRoutineCall", Types.Array <int>(), @public: false)); foreach (var arg in args) { EmitLoadOperand(arg); } // The stack and stack pointer are the last arguments passed in // case any operands manipulate them. il.Arguments.LoadMemory(); il.Arguments.LoadStack(); il.Arguments.LoadSP(); il.Call(ZRoutineCall.GetInvokeMethod(args.Length)); done.Mark(); } }