/// <summary> /// Execute the data stored in core /// This is the entry point of all DS code to be executed /// </summary> /// <param name="core"></param> /// <returns></returns> public ProtoCore.RuntimeCore ExecuteVM(ProtoCore.Core core) { ProtoCore.RuntimeCore runtimeCore = CreateRuntimeCore(core); runtimeCore.StartTimer(); try { foreach (ProtoCore.DSASM.CodeBlock codeblock in core.CodeBlockList) { // Comment Jun: // On first bounce, the stackframe depth is initialized to -1 in the Stackfame constructor. // Passing it to bounce() increments it so the first depth is always 0 ProtoCore.DSASM.StackFrame stackFrame = new ProtoCore.DSASM.StackFrame(core.GlobOffset); stackFrame.FramePointer = runtimeCore.RuntimeMemory.FramePointer; // Comment Jun: Tell the new bounce stackframe that this is an implicit bounce // Register TX is used for this. StackValue svCallConvention = StackValue.BuildCallingConversion((int)ProtoCore.DSASM.CallingConvention.BounceType.Implicit); stackFrame.TX = svCallConvention; // Initialize the entry point interpreter int locals = 0; // This is the global scope, there are no locals ProtoCore.DSASM.Interpreter interpreter = new ProtoCore.DSASM.Interpreter(runtimeCore); runtimeCore.CurrentExecutive.CurrentDSASMExec = interpreter.runtime; runtimeCore.CurrentExecutive.CurrentDSASMExec.Bounce(codeblock.codeBlockId, codeblock.instrStream.entrypoint, stackFrame, locals); } runtimeCore.NotifyExecutionEvent(ProtoCore.ExecutionStateEventArgs.State.ExecutionEnd); } catch { runtimeCore.NotifyExecutionEvent(ProtoCore.ExecutionStateEventArgs.State.ExecutionEnd); throw; } return(runtimeCore); }
public void Execute(ProtoCore.Core core, ProtoCore.Runtime.Context context) { try { core.NotifyExecutionEvent(ProtoCore.ExecutionStateEventArgs.State.kExecutionBegin); foreach (ProtoCore.DSASM.CodeBlock codeblock in core.CodeBlockList) { //ProtoCore.Runtime.Context context = new ProtoCore.Runtime.Context(); int locals = 0; // Comment Jun: // On first bounce, the stackframe depth is initialized to -1 in the Stackfame constructor. // Passing it to bounce() increments it so the first depth is always 0 ProtoCore.DSASM.StackFrame stackFrame = new ProtoCore.DSASM.StackFrame(core.GlobOffset); // Comment Jun: Tell the new bounce stackframe that this is an implicit bounce // Register TX is used for this. StackValue svCallConvention = StackValue.BuildCallingConversion((int)ProtoCore.DSASM.CallingConvention.BounceType.kImplicit); stackFrame.SetAt(ProtoCore.DSASM.StackFrame.AbsoluteIndex.kRegisterTX, svCallConvention); core.Bounce(codeblock.codeBlockId, codeblock.instrStream.entrypoint, context, stackFrame, locals, EventSink); } core.NotifyExecutionEvent(ProtoCore.ExecutionStateEventArgs.State.kExecutionEnd); } catch { core.NotifyExecutionEvent(ProtoCore.ExecutionStateEventArgs.State.kExecutionEnd); throw; } }
/// <summary> /// For a given list of formal parameters, get the function end points that resolve /// </summary> /// <param name="context"></param> /// <param name="formalParams"></param> /// <param name="replicationInstructions"></param> /// <param name="stackFrame"></param> /// <param name="core"></param> /// <param name="unresolvable">The number of argument sets that couldn't be resolved</param> /// <returns></returns> public Dictionary<FunctionEndPoint, int> GetExactMatchStatistics( Runtime.Context context, List<List<StackValue>> reducedFormalParams, StackFrame stackFrame, RuntimeCore runtimeCore, out int unresolvable) { List<ReplicationInstruction> replicationInstructions = new List<ReplicationInstruction>(); //We've already done the reduction before calling this unresolvable = 0; Dictionary<FunctionEndPoint, int> ret = new Dictionary<FunctionEndPoint, int>(); foreach (List<StackValue> formalParamSet in reducedFormalParams) { List<FunctionEndPoint> feps = GetExactTypeMatches(context, formalParamSet, replicationInstructions, stackFrame, runtimeCore); if (feps.Count == 0) { //We have an arugment set that couldn't be resolved unresolvable++; } foreach (FunctionEndPoint fep in feps) { if (ret.ContainsKey(fep)) ret[fep]++; else ret.Add(fep, 1); } } return ret; }
public DebugProperties() { DebugStackFrame = new Stack <DebugFrame>(); isResume = false; executingGraphNode = null; ActiveBreakPoints = new List <Instruction>(); AllbreakPoints = null; FRStack = new Stack <bool>(); FirstStackFrame = new StackFrame(1); DebugEntryPC = Constants.kInvalidIndex; CurrentBlockId = Constants.kInvalidIndex; StepOutReturnPC = Constants.kInvalidIndex; ReturnPCFromDispose = Constants.kInvalidIndex; IsPopmCall = false; }
public StackValue Evaluate(List<StackValue> args, StackFrame stackFrame) { // // Build the stackframe int classScopeCaller = (int)stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kClass).opdata; int returnAddr = (int)stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kReturnAddress).opdata; int blockDecl = (int)mProcNode.runtimeIndex; int blockCaller = (int)stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kFunctionCallerBlock).opdata; int framePointer = mRunTime.runtime.Core.Rmem.FramePointer; StackValue thisPtr = StackUtils.BuildPointer(-1); // Comment Jun: the caller type is the current type in the stackframe StackFrameType callerType = (StackFrameType)stackFrame.GetAt(StackFrame.AbsoluteIndex.kStackFrameType).opdata; StackFrameType type = StackFrameType.kTypeFunction; int depth = 0; List<StackValue> registers = new List<StackValue>(); // Comment Jun: Calling convention data is stored on the TX register StackValue svCallconvention = StackUtils.BuildNode(AddressType.CallingConvention, (long)ProtoCore.DSASM.CallingConvention.BounceType.kImplicit); mRunTime.runtime.TX = svCallconvention; StackValue svBlockDecl = StackUtils.BuildNode(AddressType.BlockIndex, blockDecl); mRunTime.runtime.SX = svBlockDecl; mRunTime.runtime.SaveRegisters(registers); ProtoCore.DSASM.StackFrame newStackFrame = new StackFrame(thisPtr, classScopeCaller, 1, returnAddr, blockDecl, blockCaller, callerType, type, depth, framePointer, registers); List<List<int>> replicationGuides = new List<List<int>>(); if (mRunTime.runtime.Core.Options.IDEDebugMode && mRunTime.runtime.Core.ExecMode != ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter) { mRunTime.runtime.Core.DebugProps.SetUpCallrForDebug(mRunTime.runtime.Core, mRunTime.runtime, mProcNode, returnAddr - 1, false, mCallSite, args, replicationGuides, newStackFrame); } StackValue rx = mCallSite.JILDispatchViaNewInterpreter(new Runtime.Context(), args, replicationGuides, newStackFrame, mRunTime.runtime.Core); if (mRunTime.runtime.Core.Options.IDEDebugMode && mRunTime.runtime.Core.ExecMode != ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter) { mRunTime.runtime.Core.DebugProps.RestoreCallrForNoBreak(mRunTime.runtime.Core, mProcNode); } return rx; }
/// <summary> /// ExecuteLive is called by the liverunner where a persistent RuntimeCore is provided /// ExecuteLive assumes only a single global scope /// </summary> /// <param name="core"></param> /// <param name="runtimeCore"></param> /// <param name="runningBlock"></param> /// <param name="staticContext"></param> /// <param name="runtimeContext"></param> /// <returns></returns> public ProtoCore.RuntimeCore ExecuteLive(ProtoCore.Core core, ProtoCore.RuntimeCore runtimeCore) { try { Executable exe = runtimeCore.DSExecutable; Validity.Assert(exe.CodeBlocks.Count == 1); CodeBlock codeBlock = runtimeCore.DSExecutable.CodeBlocks[0]; int codeBlockID = codeBlock.codeBlockId; // Comment Jun: // On first bounce, the stackframe depth is initialized to -1 in the Stackfame constructor. // Passing it to bounce() increments it so the first depth is always 0 ProtoCore.DSASM.StackFrame stackFrame = new ProtoCore.DSASM.StackFrame(core.GlobOffset); stackFrame.FramePointer = runtimeCore.RuntimeMemory.FramePointer; // Comment Jun: Tell the new bounce stackframe that this is an implicit bounce // Register TX is used for this. StackValue svCallConvention = StackValue.BuildCallingConversion((int)ProtoCore.DSASM.CallingConvention.BounceType.Implicit); stackFrame.TX = svCallConvention; // Initialize the entry point interpreter int locals = 0; // This is the global scope, there are no locals if (runtimeCore.CurrentExecutive.CurrentDSASMExec == null) { ProtoCore.DSASM.Interpreter interpreter = new ProtoCore.DSASM.Interpreter(runtimeCore); runtimeCore.CurrentExecutive.CurrentDSASMExec = interpreter.runtime; } runtimeCore.CurrentExecutive.CurrentDSASMExec.BounceUsingExecutive( runtimeCore.CurrentExecutive.CurrentDSASMExec, codeBlock.codeBlockId, runtimeCore.StartPC, stackFrame, locals); runtimeCore.NotifyExecutionEvent(ProtoCore.ExecutionStateEventArgs.State.ExecutionEnd); } catch { runtimeCore.NotifyExecutionEvent(ProtoCore.ExecutionStateEventArgs.State.ExecutionEnd); throw; } return(runtimeCore); }
/// <summary> /// Execute the data stored in core /// This is the entry point of all DS code to be executed /// </summary> /// <param name="core"></param> /// <param name="runningBlock"></param> /// <param name="staticContext"></param> /// <param name="runtimeContext"></param> public ProtoCore.RuntimeCore Execute( ProtoCore.Core core, int runningBlock, ProtoCore.CompileTime.Context staticContext, ProtoCore.Runtime.Context runtimeContext) { //========================Generate runtimecore here===============================// ProtoCore.RuntimeCore runtimeCore = core.__TempCoreHostForRefactoring; // Move these core setup to runtime core runtimeCore.RuntimeMemory.PushFrameForGlobals(core.GlobOffset); runtimeCore.RunningBlock = runningBlock; runtimeCore.RuntimeStatus.MessageHandler = core.BuildStatus.MessageHandler; try { runtimeCore.NotifyExecutionEvent(ProtoCore.ExecutionStateEventArgs.State.kExecutionBegin); foreach (ProtoCore.DSASM.CodeBlock codeblock in core.CodeBlockList) { // Comment Jun: // On first bounce, the stackframe depth is initialized to -1 in the Stackfame constructor. // Passing it to bounce() increments it so the first depth is always 0 ProtoCore.DSASM.StackFrame stackFrame = new ProtoCore.DSASM.StackFrame(core.GlobOffset); stackFrame.FramePointer = runtimeCore.RuntimeMemory.FramePointer; // Comment Jun: Tell the new bounce stackframe that this is an implicit bounce // Register TX is used for this. StackValue svCallConvention = StackValue.BuildCallingConversion((int)ProtoCore.DSASM.CallingConvention.BounceType.kImplicit); stackFrame.TX = svCallConvention; // Initialize the entry point interpreter int locals = 0; // This is the global scope, there are no locals ProtoCore.DSASM.Interpreter interpreter = new ProtoCore.DSASM.Interpreter(runtimeCore); runtimeCore.CurrentExecutive.CurrentDSASMExec = interpreter.runtime; runtimeCore.CurrentExecutive.CurrentDSASMExec.Bounce(codeblock.codeBlockId, codeblock.instrStream.entrypoint, runtimeContext, stackFrame, locals); } runtimeCore.NotifyExecutionEvent(ProtoCore.ExecutionStateEventArgs.State.kExecutionEnd); } catch { runtimeCore.NotifyExecutionEvent(ProtoCore.ExecutionStateEventArgs.State.kExecutionEnd); throw; } return(runtimeCore); }
/// <summary> /// For a given list of formal parameters, get the function end points that resolve /// </summary> /// <param name="context"></param> /// <param name="formalParams"></param> /// <param name="replicationInstructions"></param> /// <param name="stackFrame"></param> /// <param name="core"></param> /// <param name="unresolvable">The number of argument sets that couldn't be resolved</param> /// <returns></returns> public bool CanGetExactMatchStatics( Runtime.Context context, List<List<StackValue>> reducedFormalParams, StackFrame stackFrame, RuntimeCore runtimeCore, out HashSet<FunctionEndPoint> lookup) { lookup = new HashSet<FunctionEndPoint>(); foreach (List<StackValue> formalParamSet in reducedFormalParams) { List<FunctionEndPoint> feps = GetExactTypeMatches(context, formalParamSet, new List<ReplicationInstruction>(), stackFrame, runtimeCore); if (feps.Count == 0) { return false; } foreach (FunctionEndPoint fep in feps) { lookup.Add(fep); } } return true; }
/// <summary> /// Get a list of all the function end points that are type compliant, there maybe more than one due to pattern matches /// </summary> /// <returns></returns> public List<FunctionEndPoint> GetExactTypeMatches(ProtoCore.Runtime.Context context, List<StackValue> formalParams, List<ReplicationInstruction> replicationInstructions, StackFrame stackFrame, RuntimeCore runtimeCore) { List<FunctionEndPoint> ret = new List<FunctionEndPoint>(); List<List<StackValue>> allReducedParamSVs = Replicator.ComputeAllReducedParams(formalParams, replicationInstructions, runtimeCore); //@TODO(Luke): Need to add type statistics checks to the below if it is an array to stop int[] matching char[] //Now test the reduced Params over all of the available end points StackValue thisptr = stackFrame.ThisPtr; bool isInstance = thisptr.IsPointer && thisptr.opdata != Constants.kInvalidIndex; bool isGlobal = thisptr.IsPointer && thisptr.opdata == Constants.kInvalidIndex; foreach (FunctionEndPoint fep in FunctionEndPoints) { var proc = fep.procedureNode; // Member functions are overloaded with thisptr as the first // parameter, so if member function replicates on the left hand // side, the type matching should only be applied to overloaded // member functions, otherwise should only be applied to original // member functions. if (isInstance && context.IsReplicating != proc.IsAutoGeneratedThisProc) { continue; } else if (isGlobal && !proc.IsConstructor && !proc.IsStatic && proc.ClassID != Constants.kGlobalScope) { continue; } bool typesOK = true; foreach (List<StackValue> reducedParamSVs in allReducedParamSVs) { if (!fep.DoesTypeDeepMatch(reducedParamSVs, runtimeCore)) { typesOK = false; break; } } if (typesOK) ret.Add(fep); } return ret; }
public void SetUpCallrForDebug(RuntimeCore runtimeCore, DSASM.Executive exec, ProcedureNode fNode, int pc, bool isBaseCall = false, CallSite callsite = null, List <StackValue> arguments = null, List <List <ReplicationGuide> > replicationGuides = null, StackFrame stackFrame = null, List <StackValue> dotCallDimensions = null, bool hasDebugInfo = false, bool isMember = false, StackValue?thisPtr = null) { //ProtoCore.DSASM.Executive exec = core.CurrentExecutive.CurrentDSASMExec; DebugFrame debugFrame = new DebugFrame(); debugFrame.IsBaseCall = isBaseCall; debugFrame.Arguments = arguments; debugFrame.IsMemberFunction = isMember; debugFrame.ThisPtr = thisPtr; debugFrame.HasDebugInfo = hasDebugInfo; if (CoreUtils.IsDisposeMethod(fNode.Name)) { debugFrame.IsDisposeCall = true; ReturnPCFromDispose = DebugEntryPC; } if (RunMode == Runmode.StepNext) { debugFrame.FunctionStepOver = true; } bool isReplicating = false; bool isExternalFunction = false; // callsite is set to null for a base class constructor call in CALL if (callsite == null) { isReplicating = false; isExternalFunction = false; SetUpCallr(ref debugFrame, isReplicating, isExternalFunction, exec); DebugStackFrame.Push(debugFrame); return; } // Comment Jun: A dot call does not replicate and must be handled immediately if (fNode.Name == Constants.kDotMethodName) { isReplicating = false; isExternalFunction = false; debugFrame.IsDotCall = true; debugFrame.DotCallDimensions = dotCallDimensions; SetUpCallr(ref debugFrame, isReplicating, isExternalFunction, exec); DebugStackFrame.Push(debugFrame); return; } List <List <ReplicationInstruction> > replicationTrials; bool willReplicate = callsite.WillCallReplicate(new Context(), arguments, replicationGuides, stackFrame, runtimeCore, out replicationTrials); // the inline conditional built-in is handled separately as 'WillCallReplicate' is always true in this case if (fNode.Name.Equals(Constants.kInlineConditionalMethodName)) { // The inline conditional built-in is created only for associative blocks and needs to be handled separately as below InstructionStream istream = runtimeCore.DSExecutable.instrStreamList[CurrentBlockId]; Validity.Assert(istream.language == Language.Associative); { runtimeCore.DebugProps.InlineConditionOptions.isInlineConditional = true; runtimeCore.DebugProps.InlineConditionOptions.startPc = pc; runtimeCore.DebugProps.InlineConditionOptions.endPc = FindEndPCForAssocGraphNode(pc, istream, fNode, exec.Properties.executingGraphNode, runtimeCore.Options.ExecuteSSA); runtimeCore.DebugProps.InlineConditionOptions.instructionStream = runtimeCore.RunningBlock; debugFrame.IsInlineConditional = true; } // no replication case if (willReplicate && replicationTrials.Count == 1) { runtimeCore.DebugProps.InlineConditionOptions.ActiveBreakPoints.AddRange(runtimeCore.Breakpoints); isReplicating = false; isExternalFunction = false; } else // an inline conditional call that replicates { // Clear all breakpoints for outermost replicated call if (!DebugStackFrameContains(StackFrameFlagOptions.IsReplicating)) { ActiveBreakPoints.AddRange(runtimeCore.Breakpoints); runtimeCore.Breakpoints.Clear(); } isExternalFunction = false; isReplicating = true; } SetUpCallr(ref debugFrame, isReplicating, isExternalFunction, exec, 0); DebugStackFrame.Push(debugFrame); return; } // Prevent breaking inside a function that is external except for dot calls // by clearing all breakpoints from outermost external function call // This check takes precedence over the replication check else if (fNode.IsExternal && fNode.Name != Constants.kDotMethodName) { // Clear all breakpoints if (!DebugStackFrameContains(StackFrameFlagOptions.IsExternalFunction) && fNode.Name != Constants.kFunctionRangeExpression) { ActiveBreakPoints.AddRange(runtimeCore.Breakpoints); runtimeCore.Breakpoints.Clear(); } isExternalFunction = true; isReplicating = false; } // Find if function call will replicate or not and if so // prevent stepping in by removing all breakpoints from outermost replicated call else if (willReplicate) { // Clear all breakpoints for outermost replicated call if (!DebugStackFrameContains(StackFrameFlagOptions.IsReplicating)) { ActiveBreakPoints.AddRange(runtimeCore.Breakpoints); runtimeCore.Breakpoints.Clear(); } isReplicating = true; isExternalFunction = false; } // For all other function calls else { isReplicating = false; isExternalFunction = false; } SetUpCallr(ref debugFrame, isReplicating, isExternalFunction, exec); DebugStackFrame.Push(debugFrame); }
/// <summary> /// Get a list of all the function end points that are type compliant, there maybe more than one due to pattern matches /// </summary> /// <returns></returns> public List<FunctionEndPoint> GetExactTypeMatches(ProtoCore.Runtime.Context context, List<StackValue> formalParams, List<ReplicationInstruction> replicationInstructions, StackFrame stackFrame, Core core) { List<FunctionEndPoint> ret = new List<FunctionEndPoint>(); List<List<StackValue>> allReducedParamSVs = Replicator.ComputeAllReducedParams(formalParams, replicationInstructions, core); List<StackValue> reducedParamSVs = allReducedParamSVs[0]; //@TODO(Luke): Need to add type statistics checks to the below if it is an array to stop int[] matching char[] //Now test the reduced Params over all of the available end points foreach (FunctionEndPoint fep in FunctionEndPoints) { if (fep.DoesTypeDeepMatch(reducedParamSVs, core)) { //// The first line checks if the lhs of a dot operation was a class name //if (stackFrame.GetAt(StackFrame.AbsoluteIndex.kThisPtr).optype == AddressType.ClassIndex // && !fep.procedureNode.isConstructor // && !fep.procedureNode.isStatic) if ((stackFrame.GetAt(StackFrame.AbsoluteIndex.kThisPtr).optype == AddressType.Pointer && stackFrame.GetAt(StackFrame.AbsoluteIndex.kThisPtr).opdata == -1 && fep.procedureNode != null && !fep.procedureNode.isConstructor) && !fep.procedureNode.isStatic && (fep.procedureNode.classScope != -1)) { continue; } ret.Add(fep); } } return ret; }
public override StackValue Execute(ProtoCore.Runtime.Context c, List<StackValue> formalParameters, ProtoCore.DSASM.StackFrame stackFrame, RuntimeCore runtimeCore) { // ensure there is no data race, function resolution and execution happens in parallel // but for FFI we want it to be serial cause the code we are calling into may not cope // with parallelism. // // we are always looking and putting our function pointers in handler with each lang // so better lock for FFIHandler (being static) it will be good object to lock // lock (FFIHandlers) { Interpreter interpreter = new Interpreter(runtimeCore, true); // Setup the stack frame data StackValue svThisPtr = stackFrame.ThisPtr; int ci = activation.JILRecord.classIndex; int fi = activation.JILRecord.funcIndex; int returnAddr = stackFrame.ReturnPC; int blockDecl = stackFrame.FunctionBlock; int blockCaller = stackFrame.FunctionCallerBlock; int framePointer = runtimeCore.RuntimeMemory.FramePointer; int locals = activation.JILRecord.locals; FFIHandler handler = FFIHandlers[activation.ModuleType]; FFIActivationRecord r = activation; string className = ""; if (activation.JILRecord.classIndex > 0) { className = runtimeCore.DSExecutable.classTable.ClassNodes[activation.JILRecord.classIndex].Name; } List<ProtoCore.Type> argTypes = new List<Type>(r.ParameterTypes); ProcedureNode fNode = null; if (ProtoCore.DSASM.Constants.kInvalidIndex != ci) { fNode = interpreter.runtime.exe.classTable.ClassNodes[ci].ProcTable.Procedures[fi]; } // Check if this is a 'this' pointer function overload that was generated by the compiler if (null != fNode && fNode.IsAutoGeneratedThisProc) { int thisPtrIndex = 0; bool isStaticCall = svThisPtr.IsPointer && Constants.kInvalidPointer == svThisPtr.Pointer; if (isStaticCall) { stackFrame.ThisPtr = formalParameters[thisPtrIndex]; } argTypes.RemoveAt(thisPtrIndex); // Comment Jun: Execute() can handle a null this pointer. // But since we dont even need to to reach there if we dont have a valid this pointer, then just return null if (formalParameters[thisPtrIndex].IsNull) { runtimeCore.RuntimeStatus.LogWarning(ProtoCore.Runtime.WarningID.DereferencingNonPointer, Resources.kDeferencingNonPointer); return StackValue.Null; } // These are the op types allowed. Validity.Assert(formalParameters[thisPtrIndex].IsPointer || formalParameters[thisPtrIndex].IsDefaultArgument); svThisPtr = formalParameters[thisPtrIndex]; formalParameters.RemoveAt(thisPtrIndex); } FFIFunctionPointer functionPointer = handler.GetFunctionPointer(r.ModuleName, className, r.FunctionName, argTypes, r.ReturnType); mFunctionPointer = Validate(functionPointer) ? functionPointer : null; mFunctionPointer.IsDNI = activation.IsDNI; if (mFunctionPointer == null) { return ProtoCore.DSASM.StackValue.Null; } { interpreter.runtime.executingBlock = runtimeCore.RunningBlock; activation.JILRecord.globs = runtimeCore.DSExecutable.runtimeSymbols[runtimeCore.RunningBlock].GetGlobalSize(); // Params formalParameters.Reverse(); for (int i = 0; i < formalParameters.Count; i++) { interpreter.Push(formalParameters[i]); } List<StackValue> registers = new List<DSASM.StackValue>(); interpreter.runtime.SaveRegisters(registers); // Comment Jun: the depth is always 0 for a function call as we are reseting this for each function call // This is only incremented for every language block bounce int depth = 0; StackFrameType callerType = stackFrame.CallerStackFrameType; // FFI calls do not have execution states runtimeCore.RuntimeMemory.PushFrameForLocals(locals); StackFrame newStackFrame = new StackFrame(svThisPtr, ci, fi, returnAddr, blockDecl, blockCaller, callerType, StackFrameType.Function, depth, framePointer, registers, 0); runtimeCore.RuntimeMemory.PushStackFrame(newStackFrame); //is there a way the current stack be passed across and back into the managed runtime by FFI calling back into the language? //e.g. DCEnv* carrying all the stack information? look at how vmkit does this. // = jilMain.Run(ActivationRecord.JILRecord.pc, null, true); //double[] tempArray = GetUnderlyingArray<double>(jilMain.runtime.rmem.stack); Object ret = mFunctionPointer.Execute(c, interpreter); StackValue op; if (ret == null) { op = StackValue.Null; } else if (ret is StackValue) { op = (StackValue)ret; } else if (ret is Int64 || ret is int) { op = StackValue.BuildInt((Int64)ret); } else if (ret is double) { op = StackValue.BuildDouble((double)ret); } else { throw new ArgumentException(string.Format("FFI: incorrect return type {0} from external function {1}:{2}", activation.ReturnType.Name, activation.ModuleName, activation.FunctionName)); } // Clear the FFI stack frame // FFI stack frames have no local variables interpreter.runtime.rmem.FramePointer = (int)interpreter.runtime.rmem.GetAtRelative(StackFrame.FrameIndexFramePointer).IntegerValue; interpreter.runtime.rmem.PopFrame(StackFrame.StackFrameSize + formalParameters.Count); return op; } } }
/// <summary> /// ExecuteLive is called by the liverunner where a persistent RuntimeCore is provided /// ExecuteLive assumes only a single global scope /// </summary> /// <param name="core"></param> /// <param name="runtimeCore"></param> /// <param name="runningBlock"></param> /// <param name="staticContext"></param> /// <param name="runtimeContext"></param> /// <returns></returns> public ProtoCore.RuntimeCore ExecuteLive(ProtoCore.Core core, ProtoCore.RuntimeCore runtimeCore) { try { Executable exe = runtimeCore.DSExecutable; Validity.Assert(exe.CodeBlocks.Count == 1); CodeBlock codeBlock = runtimeCore.DSExecutable.CodeBlocks[0]; int codeBlockID = codeBlock.codeBlockId; // Comment Jun: // On first bounce, the stackframe depth is initialized to -1 in the Stackfame constructor. // Passing it to bounce() increments it so the first depth is always 0 ProtoCore.DSASM.StackFrame stackFrame = new ProtoCore.DSASM.StackFrame(core.GlobOffset); stackFrame.FramePointer = runtimeCore.RuntimeMemory.FramePointer; // Comment Jun: Tell the new bounce stackframe that this is an implicit bounce // Register TX is used for this. StackValue svCallConvention = StackValue.BuildCallingConversion((int)ProtoCore.DSASM.CallingConvention.BounceType.kImplicit); stackFrame.TX = svCallConvention; // Initialize the entry point interpreter int locals = 0; // This is the global scope, there are no locals if (runtimeCore.CurrentExecutive.CurrentDSASMExec == null) { ProtoCore.DSASM.Interpreter interpreter = new ProtoCore.DSASM.Interpreter(runtimeCore); runtimeCore.CurrentExecutive.CurrentDSASMExec = interpreter.runtime; } runtimeCore.CurrentExecutive.CurrentDSASMExec.BounceUsingExecutive( runtimeCore.CurrentExecutive.CurrentDSASMExec, codeBlock.codeBlockId, runtimeCore.StartPC, stackFrame, locals); runtimeCore.NotifyExecutionEvent(ProtoCore.ExecutionStateEventArgs.State.kExecutionEnd); } catch { runtimeCore.NotifyExecutionEvent(ProtoCore.ExecutionStateEventArgs.State.kExecutionEnd); throw; } return runtimeCore; }
private void BOUNCE_Handler(Instruction instruction) { // We disallow language blocks inside watch window currently - pratapa Validity.Assert(InterpreterMode.Expression != runtimeCore.Options.RunMode); int blockId = instruction.op1.BlockIndex; // Comment Jun: On a bounce, update the debug property to reflect this. // Before the explicit bounce, this was done in Execute() which is now no longer the case // as Execute is only called once during first bounce and succeeding bounce reuse the same interpreter runtimeCore.DebugProps.CurrentBlockId = blockId; // TODO(Jun/Jiong): Considering store the orig block id to stack frame runtimeCore.RunningBlock = blockId; runtimeCore.RuntimeMemory = rmem; if (runtimeCore.Options.RunMode != InterpreterMode.Expression) { runtimeCore.RuntimeMemory.PushConstructBlockId(blockId); } int ci = Constants.kInvalidIndex; int fi = Constants.kInvalidIndex; if (rmem.Stack.Count >= StackFrame.StackFrameSize) { StackValue sci = rmem.GetAtRelative(StackFrame.FrameIndexClassIndex); StackValue sfi = rmem.GetAtRelative(StackFrame.FrameIndexFunctionIndex); if (sci.IsClassIndex && sfi.IsFunctionIndex) { ci = sci.ClassIndex; fi = sfi.FunctionIndex; } } StackValue svThisPtr; if (rmem.CurrentStackFrame == null) { svThisPtr = StackValue.BuildPointer(Constants.kInvalidPointer); } else { svThisPtr = rmem.CurrentStackFrame.ThisPtr; } int returnAddr = pc + 1; Validity.Assert(Constants.kInvalidIndex != executingBlock); //int blockDecl = executingBlock; int blockDecl = rmem.GetAtRelative(StackFrame.FrameIndexFunctionBlockIndex).BlockIndex; int blockCaller = executingBlock; StackFrameType type = StackFrameType.LanguageBlock; int depth = (int)rmem.GetAtRelative(StackFrame.FrameIndexStackFrameDepth).IntegerValue; int framePointer = runtimeCore.RuntimeMemory.FramePointer; // Comment Jun: Use the register TX to store explicit/implicit bounce state bounceType = CallingConvention.BounceType.Explicit; TX = StackValue.BuildCallingConversion((int)CallingConvention.BounceType.Explicit); List<StackValue> registers = GetRegisters(); StackFrameType callerType = (fepRun) ? StackFrameType.Function : StackFrameType.LanguageBlock; if (runtimeCore.Options.IDEDebugMode && runtimeCore.Options.RunMode != InterpreterMode.Expression) { // Comment Jun: Temporarily disable debug mode on bounce //Validity.Assert(false); //Validity.Assert(runtimeCore.Breakpoints != null); //blockDecl = blockCaller = runtimeCore.DebugProps.CurrentBlockId; runtimeCore.DebugProps.SetUpBounce(this, blockCaller, returnAddr); StackFrame stackFrame = new StackFrame(svThisPtr, ci, fi, returnAddr, blockDecl, blockCaller, callerType, type, depth + 1, framePointer, 0, registers, 0); Language bounceLangauge = exe.instrStreamList[blockId].language; BounceExplicit(blockId, 0, bounceLangauge, stackFrame, runtimeCore.Breakpoints); } else //if (runtimeCore.Breakpoints == null) { StackFrame stackFrame = new StackFrame(svThisPtr, ci, fi, returnAddr, blockDecl, blockCaller, callerType, type, depth + 1, framePointer, 0, registers, 0); Language bounceLangauge = exe.instrStreamList[blockId].language; BounceExplicit(blockId, 0, bounceLangauge, stackFrame); } }
public StackValue Callr(int blockDeclId, int functionIndex, int classIndex, ref bool explicitCall, bool isDynamicCall = false, bool hasDebugInfo = false) { // This is curently unused but required for stack alignment var svDepth = rmem.Pop(); int depth = (int)svDepth.IntegerValue; ProcedureNode fNode = null; bool isCallingMemberFunction = Constants.kInvalidIndex != classIndex; if (isCallingMemberFunction) { fNode = exe.classTable.ClassNodes[classIndex].ProcTable.Procedures[functionIndex]; if (depth > 0 && fNode.IsConstructor) { string message = String.Format(Resources.KCallingConstructorOnInstance, fNode.Name); runtimeCore.RuntimeStatus.LogWarning(WarningID.CallingConstructorOnInstance, message); return StackValue.Null; } } else { // Global function fNode = exe.procedureTable[blockDeclId].Procedures[functionIndex]; } // Build the arg values list var arguments = new List<StackValue>(); // Retrive the param values from the stack int stackindex = rmem.Stack.Count - 1; List<StackValue> dotCallDimensions = new List<StackValue>(); if (fNode.Name.Equals(Constants.kDotMethodName)) { int firstDotArgIndex = stackindex - (Constants.kDotCallArgCount - 1); StackValue svLHS = rmem.Stack[firstDotArgIndex]; arguments.Add(svLHS); // Retrieve the indexed dimensions into the dot call int arrayDimIndex = stackindex - (Constants.kDotCallArgCount - Constants.kDotArgIndexArrayIndex - 1); StackValue svArrayPtrDimesions = rmem.Stack[arrayDimIndex]; Validity.Assert(svArrayPtrDimesions.IsArray); int arrayCountIndex = stackindex - (Constants.kDotCallArgCount - Constants.kDotArgIndexDimCount - 1); StackValue svDimensionCount = rmem.Stack[arrayCountIndex]; Validity.Assert(svDimensionCount.IsInteger); // If array dimension were provided then retrive the final pointer if (svDimensionCount.IntegerValue > 0) { var dimArray = rmem.Heap.ToHeapObject<DSArray>(svArrayPtrDimesions); Validity.Assert(dimArray.Count == svDimensionCount.IntegerValue); dotCallDimensions.AddRange(dimArray.Values); } } else { arguments = PopArgumentsFromStack(fNode.ArgumentTypes.Count); arguments.Reverse(); } var replicationGuides = new List<List<ReplicationGuide>>(); var atLevels = new List<AtLevel>(); Runtime.Context runtimeContext = new Runtime.Context(); // Comment Jun: These function do not require replication guides // TODO Jun: Move these conditions or refactor JIL code emission so these checks dont reside here (Post R1) if (Constants.kDotMethodName != fNode.Name && Constants.kFunctionRangeExpression != fNode.Name) { // Comment Jun: If this is a non-dot call, cache the guides first and retrieve them on the actual function call // TODO Jun: Ideally, cache the replication guides in the dynamic function node replicationGuides = GetCachedReplicationGuides(arguments.Count); atLevels = GetCachedAtLevels(arguments.Count); } // if is dynamic call, the final pointer has been resovled in the ProcessDynamicFunction function StackValue svThisPtr = StackValue.Null; if (depth > 0) { svThisPtr = rmem.Pop(); if (!svThisPtr.IsPointer) { string message = String.Format(Resources.kInvokeMethodOnInvalidObject, fNode.Name); runtimeCore.RuntimeStatus.LogWarning(WarningID.DereferencingNonPointer, message); return StackValue.Null; } } else { // There is no depth, but check if the function is a member function // If its a member function, the this pointer is required by the core to pass on to the FEP call if (isCallingMemberFunction && !fNode.IsConstructor && !fNode.IsStatic) { // A member function // Get the this pointer as this class instance would have already been cosntructed svThisPtr = rmem.CurrentStackFrame.ThisPtr; } else if (fNode.Name.Equals(Constants.kInlineConditionalMethodName)) { // The built-in inlinecondition function is global but it is treated as a conditional execution rather than a normal function call // This is why the class scope needs to be preserved such that the auto-generated language blocks in an inline conditional can still refer to member functions and properties svThisPtr = rmem.CurrentStackFrame.ThisPtr; } else { // Global svThisPtr = StackValue.BuildPointer(Constants.kInvalidPointer); } } if (svThisPtr.IsPointer && svThisPtr.Pointer != Constants.kInvalidIndex && svThisPtr.metaData.type != Constants.kInvalidIndex) { int runtimeClassIndex = svThisPtr.metaData.type; ClassNode runtimeClass = exe.classTable.ClassNodes[runtimeClassIndex]; if (runtimeClass.IsMyBase(classIndex)) { classIndex = runtimeClassIndex; } } // Build the stackframe //int thisPtr = (int)svThisPtr.opdata; int ci = classIndex; // Constants.kInvalidIndex; // Handled at FEP int fi = Constants.kInvalidIndex; // Handled at FEP int returnAddr = pc + 1; int blockDecl = blockDeclId; if (null != Properties.executingGraphNode) { exe.ExecutingGraphnode = Properties.executingGraphNode; } // Get the cached callsite, creates a new one for a first-time call CallSite callsite = runtimeCore.RuntimeData.GetCallSite( exe.ExecutingGraphnode, classIndex, fNode.Name, exe, runtimeCore.RunningBlock, runtimeCore.Options, runtimeCore.RuntimeStatus); Validity.Assert(null != callsite); List<StackValue> registers = GetRegisters(); // Get the execution states of the current stackframe int currentScopeClass = Constants.kInvalidIndex; int currentScopeFunction = Constants.kInvalidIndex; GetCallerInformation(out currentScopeClass, out currentScopeFunction); // Handle execution states at the FEP var stackFrame = new StackFrame(svThisPtr, ci, fi, returnAddr, blockDecl, runtimeCore.RunningBlock, fepRun ? StackFrameType.Function : StackFrameType.LanguageBlock, StackFrameType.Function, 0, rmem.FramePointer, blockDeclId, registers, 0); StackValue sv = StackValue.Null; if (runtimeCore.Options.IDEDebugMode && runtimeCore.Options.RunMode != InterpreterMode.Expression) { if (runtimeCore.ContinuationStruct.IsFirstCall) { runtimeCore.DebugProps.SetUpCallrForDebug( runtimeCore, this, fNode, pc, false, callsite, arguments, replicationGuides, stackFrame, dotCallDimensions, hasDebugInfo); } else { runtimeCore.DebugProps.SetUpCallrForDebug( runtimeCore, this, fNode, pc, false, callsite, runtimeCore.ContinuationStruct.InitialArguments, replicationGuides, stackFrame, runtimeCore.ContinuationStruct.InitialDotCallDimensions, hasDebugInfo); } } //Dispatch without recursion tracking explicitCall = false; IsExplicitCall = explicitCall; var argumentAtLevels = AtLevelHandler.GetArgumentAtLevelStructure(arguments, atLevels, runtimeCore); sv = callsite.JILDispatch(argumentAtLevels.Arguments, replicationGuides, argumentAtLevels.DominantStructure, stackFrame, runtimeCore, runtimeContext); if (sv.IsExplicitCall) { // // Set the interpreter properties for function calls // These are used when performing GC on return // The GC occurs: // 1. In this instruction for implicit calls // 2. In the return instruction // Properties.functionCallArguments = argumentAtLevels.Arguments; Properties.functionCallDotCallDimensions = dotCallDimensions; Properties.DominantStructure = argumentAtLevels.DominantStructure; explicitCall = true; IsExplicitCall = explicitCall; CallExplicit(sv.ExplicitCallEntry); } // If the function was called implicitly, The code below assumes this and must be executed if (!explicitCall) { // Restore debug properties after returning from a CALL/CALLR if (runtimeCore.Options.IDEDebugMode && runtimeCore.Options.RunMode != InterpreterMode.Expression) { runtimeCore.DebugProps.RestoreCallrForNoBreak(runtimeCore, fNode); } if (CoreUtils.IsDotMethod(fNode.Name)) { sv = IndexIntoArray(sv, dotCallDimensions); rmem.PopFrame(Constants.kDotCallArgCount); } } return sv; }
public StackValue JILDispatch( List<StackValue> arguments, List<List<ReplicationGuide>> replicationGuides, List<AtLevel> atLevels, StackFrame stackFrame, RuntimeCore runtimeCore, Context context) { #if DEBUG ArgumentSanityCheck(arguments); #endif // Dispatch method return DispatchNew(context, arguments, replicationGuides, atLevels, stackFrame, runtimeCore); }
//Dispatch private StackValue DispatchNew( Context context, List<StackValue> arguments, List<List<ReplicationGuide>> partialReplicationGuides, List<AtLevel> atLevels, StackFrame stackFrame, RuntimeCore runtimeCore) { // Update the CallsiteExecutionState with // TODO: Replace this with the real data UpdateCallsiteExecutionState(null, runtimeCore); Stopwatch sw = new Stopwatch(); sw.Start(); StringBuilder log = new StringBuilder(); log.AppendLine("Method name: " + methodName); #region Get Function Group //@PERF: Possible optimisation point here, to deal with static dispatches that don't need replication analysis //Handle resolution Pass 1: Name -> Method Group FunctionGroup funcGroup = GetFuncGroup(runtimeCore); if (funcGroup == null) { log.AppendLine("Function group not located"); log.AppendLine("Resolution failed in: " + sw.ElapsedMilliseconds); if (runtimeCore.Options.DumpFunctionResolverLogic) runtimeCore.DSExecutable.EventSink.PrintMessage(log.ToString()); return ReportFunctionGroupNotFound(runtimeCore, arguments); } //check accesibility of function group bool methodAccessible = IsFunctionGroupAccessible(runtimeCore, ref funcGroup); if (!methodAccessible) { return ReportMethodNotAccessible(runtimeCore); } //If we got here then the function group got resolved log.AppendLine("Function group resolved: " + funcGroup); #endregion arguments = GetArgumentsAtLevels(arguments, atLevels, runtimeCore).Select(a => a.Argument).ToList(); partialReplicationGuides = PerformRepGuideDemotion(arguments, partialReplicationGuides, runtimeCore); //Replication Control is an ordered list of the elements that we have to replicate over //Ordering implies containment, so element 0 is the outer most forloop, element 1 is nested within it etc. //Take the explicit replication guides and build the replication structure //Turn the replication guides into a guide -> List args data structure var partialInstructions = Replicator.BuildPartialReplicationInstructions(partialReplicationGuides); //Get the fep that are resolved List<FunctionEndPoint> resolvesFeps; List<ReplicationInstruction> replicationInstructions; arguments = PerformRepGuideForcedPromotion(arguments, partialReplicationGuides, runtimeCore); ComputeFeps(log, context, arguments, funcGroup, partialInstructions, partialReplicationGuides, stackFrame, runtimeCore, out resolvesFeps, out replicationInstructions); if (resolvesFeps.Count == 0) { log.AppendLine("Resolution Failed"); if (runtimeCore.Options.DumpFunctionResolverLogic) runtimeCore.DSExecutable.EventSink.PrintMessage(log.ToString()); return ReportMethodNotFoundForArguments(runtimeCore, arguments); } arguments.ForEach(x => runtimeCore.AddCallSiteGCRoot(CallSiteID, x)); StackValue ret = Execute(resolvesFeps, context, arguments, replicationInstructions, stackFrame, runtimeCore, funcGroup); runtimeCore.RemoveCallSiteGCRoot(CallSiteID); return ret; }
private FunctionEndPoint SelectFinalFep(Context context, List<FunctionEndPoint> functionEndPoint, List<StackValue> formalParameters, StackFrame stackFrame, RuntimeCore runtimeCore) { List<ReplicationInstruction> replicationControl = new List<ReplicationInstruction>(); //We're never going to replicate so create an empty structure to allow us to use //the existing utility methods //Filter for exact matches List<FunctionEndPoint> exactTypeMatchingCandindates = new List<FunctionEndPoint>(); foreach (FunctionEndPoint possibleFep in functionEndPoint) { if (possibleFep.DoesTypeDeepMatch(formalParameters, runtimeCore)) { exactTypeMatchingCandindates.Add(possibleFep); } } //There was an exact match, so dispath to it if (exactTypeMatchingCandindates.Count > 0) { FunctionEndPoint fep = null; if (exactTypeMatchingCandindates.Count == 1) { fep = exactTypeMatchingCandindates[0]; } else { fep = SelectFEPFromMultiple(stackFrame, runtimeCore, exactTypeMatchingCandindates, formalParameters); } return fep; } else { Dictionary<FunctionEndPoint, int> candidatesWithDistances = new Dictionary<FunctionEndPoint, int>(); Dictionary<FunctionEndPoint, int> candidatesWithCastDistances = new Dictionary<FunctionEndPoint, int>(); foreach (FunctionEndPoint fep in functionEndPoint) { //@TODO(Luke): Is this value for allow array promotion correct? int distance = fep.ComputeTypeDistance(formalParameters, runtimeCore.DSExecutable.classTable, runtimeCore, false); if (distance != (int) ProcedureDistance.kInvalidDistance) candidatesWithDistances.Add(fep, distance); } foreach (FunctionEndPoint fep in functionEndPoint) { int dist = fep.ComputeCastDistance(formalParameters, runtimeCore.DSExecutable.classTable, runtimeCore); candidatesWithCastDistances.Add(fep, dist); } List<FunctionEndPoint> candidateFunctions = GetCandidateFunctions(stackFrame, candidatesWithDistances); if (candidateFunctions.Count == 0) { runtimeCore.RuntimeStatus.LogWarning(WarningID.kAmbiguousMethodDispatch, Resources.kAmbigousMethodDispatch); return null; } FunctionEndPoint compliantTarget = GetCompliantTarget(context, formalParameters, replicationControl, stackFrame, runtimeCore, candidatesWithCastDistances, candidateFunctions, candidatesWithDistances); return compliantTarget; } }
//Inbound methods public StackValue JILDispatchViaNewInterpreter( Context context, List<StackValue> arguments, List<List<ReplicationGuide>> replicationGuides, List<AtLevel> atLevels, StackFrame stackFrame, RuntimeCore runtimeCore) { #if DEBUG ArgumentSanityCheck(arguments); #endif // Dispatch method context.IsImplicitCall = true; return DispatchNew(context, arguments, replicationGuides, atLevels, stackFrame, runtimeCore); }
private List<FunctionEndPoint> GetCandidateFunctions(StackFrame stackFrame, Dictionary<FunctionEndPoint, int> candidatesWithDistances) { List<FunctionEndPoint> candidateFunctions = new List<FunctionEndPoint>(); foreach (FunctionEndPoint fep in candidatesWithDistances.Keys) { if ((stackFrame.ThisPtr.IsPointer && stackFrame.ThisPtr.opdata == -1 && fep.procedureNode != null && !fep.procedureNode.IsConstructor) && !fep.procedureNode.IsStatic && (fep.procedureNode.ClassID != -1)) { continue; } candidateFunctions.Add(fep); } return candidateFunctions; }
private FunctionEndPoint GetCompliantTarget(Context context, List<StackValue> formalParams, List<ReplicationInstruction> replicationControl, StackFrame stackFrame, RuntimeCore runtimeCore, Dictionary<FunctionEndPoint, int> candidatesWithCastDistances, List<FunctionEndPoint> candidateFunctions, Dictionary<FunctionEndPoint, int> candidatesWithDistances) { FunctionEndPoint compliantTarget = null; //Produce an ordered list of the graph costs Dictionary<int, List<FunctionEndPoint>> conversionCostList = new Dictionary<int, List<FunctionEndPoint>>(); foreach (FunctionEndPoint fep in candidateFunctions) { int cost = candidatesWithDistances[fep]; if (conversionCostList.ContainsKey(cost)) conversionCostList[cost].Add(fep); else conversionCostList.Add(cost, new List<FunctionEndPoint> {fep}); } List<int> conversionCosts = new List<int>(conversionCostList.Keys); conversionCosts.Sort(); List<FunctionEndPoint> fepsToSplit = new List<FunctionEndPoint>(); foreach (int cost in conversionCosts) { foreach (FunctionEndPoint funcFep in conversionCostList[cost]) { if (funcFep.DoesPredicateMatch(context, formalParams, replicationControl)) { compliantTarget = funcFep; fepsToSplit.Add(funcFep); } } if (compliantTarget != null) break; } if (fepsToSplit.Count > 1) { int lowestCost = candidatesWithCastDistances[fepsToSplit[0]]; compliantTarget = fepsToSplit[0]; List<FunctionEndPoint> lowestCostFeps = new List<FunctionEndPoint>(); foreach (FunctionEndPoint fep in fepsToSplit) { if (candidatesWithCastDistances[fep] < lowestCost) { lowestCost = candidatesWithCastDistances[fep]; compliantTarget = fep; lowestCostFeps = new List<FunctionEndPoint>() { fep }; } else if (candidatesWithCastDistances[fep] == lowestCost) { lowestCostFeps.Add(fep); } } //We have multiple feps, e.g. form overriding if (lowestCostFeps.Count > 0) compliantTarget = SelectFEPFromMultiple(stackFrame, runtimeCore, lowestCostFeps, formalParams); } return compliantTarget; }
private FunctionEndPoint SelectFEPFromMultiple(StackFrame stackFrame, RuntimeCore runtimeCore, List<FunctionEndPoint> feps, List<StackValue> argumentsList) { StackValue svThisPtr = stackFrame.ThisPtr; Validity.Assert(svThisPtr.IsPointer, "this pointer wasn't a pointer. {89635B06-AD53-4170-ADA5-065EB2AE5858}"); int typeID = svThisPtr.metaData.type; //Test for exact match List<FunctionEndPoint> exactFeps = new List<FunctionEndPoint>(); foreach (FunctionEndPoint fep in feps) if (fep.ClassOwnerIndex == typeID) exactFeps.Add(fep); if (exactFeps.Count == 1) { return exactFeps[0]; } //Walk the class tree structure to find the method while (runtimeCore.DSExecutable.classTable.ClassNodes[typeID].Bases.Count > 0) { Validity.Assert(runtimeCore.DSExecutable.classTable.ClassNodes[typeID].Bases.Count == 1, "Multiple inheritence not yet supported {B93D8D7F-AB4D-4412-8483-33DE739C0ADA}"); typeID = runtimeCore.DSExecutable.classTable.ClassNodes[typeID].Bases[0]; foreach (FunctionEndPoint fep in feps) if (fep.ClassOwnerIndex == typeID) return fep; } //We weren't able to distinguish based on class hiearchy, try to sepearete based on array ranking List<int> numberOfArbitraryRanks = new List<int>(); foreach (FunctionEndPoint fep in feps) { int noArbitraries = 0; for (int i = 0; i < argumentsList.Count; i++) { if (fep.FormalParams[i].rank == Constants.kArbitraryRank) noArbitraries++; numberOfArbitraryRanks.Add(noArbitraries); } } int smallest = Int32.MaxValue; List<int> indeciesOfSmallest = new List<int>(); for (int i = 0; i < feps.Count; i++) { if (numberOfArbitraryRanks[i] < smallest) { smallest = numberOfArbitraryRanks[i]; indeciesOfSmallest.Clear(); indeciesOfSmallest.Add(i); } else if (numberOfArbitraryRanks[i] == smallest) indeciesOfSmallest.Add(i); } Validity.Assert(indeciesOfSmallest.Count > 0, "Couldn't find a fep when there should have been multiple: {EB589F55-F36B-404A-91DC-8D0EDC527E72}"); if (indeciesOfSmallest.Count == 1) return feps[indeciesOfSmallest[0]]; if (!CoreUtils.IsInternalMethod(feps[0].procedureNode.Name) || CoreUtils.IsGetterSetter(feps[0].procedureNode.Name)) { //If this has failed, we have multiple feps, which can't be distiquished by class hiearchy. Emit a warning and select one StringBuilder possibleFuncs = new StringBuilder(); possibleFuncs.Append(Resources.MultipleFunctionsFound); foreach (FunctionEndPoint fep in feps) possibleFuncs.AppendLine("\t" + fep.ToString()); possibleFuncs.AppendLine(string.Format(Resources.ErrorCode, "{DCE486C0-0975-49F9-BE2C-2E7D8CCD17DD}")); runtimeCore.RuntimeStatus.LogWarning(WarningID.kAmbiguousMethodDispatch, possibleFuncs.ToString()); } return feps[0]; }
public void PushStackFrame(StackFrame stackFrame, int localSize, int executionStates) { // TODO Jun: Performance // Push frame should only require adjusting the frame index instead of pushing dummy elements Validity.Assert(StackFrame.kStackFrameSize == stackFrame.Frame.Length); PushFrame(localSize); Push(stackFrame.Frame[(int)StackFrame.AbsoluteIndex.kFramePointer]); Push(stackFrame.Frame[(int)StackFrame.AbsoluteIndex.kRegisterTX]); Push(stackFrame.Frame[(int)StackFrame.AbsoluteIndex.kRegisterSX]); Push(stackFrame.Frame[(int)StackFrame.AbsoluteIndex.kRegisterRX]); Push(stackFrame.Frame[(int)StackFrame.AbsoluteIndex.kRegisterLX]); Push(stackFrame.Frame[(int)StackFrame.AbsoluteIndex.kRegisterFX]); Push(stackFrame.Frame[(int)StackFrame.AbsoluteIndex.kRegisterEX]); Push(stackFrame.Frame[(int)StackFrame.AbsoluteIndex.kRegisterDX]); Push(stackFrame.Frame[(int)StackFrame.AbsoluteIndex.kRegisterCX]); Push(stackFrame.Frame[(int)StackFrame.AbsoluteIndex.kRegisterBX]); Push(stackFrame.Frame[(int)StackFrame.AbsoluteIndex.kRegisterAX]); Push(stackFrame.Frame[(int)StackFrame.AbsoluteIndex.kExecutionStates]); Push(stackFrame.Frame[(int)StackFrame.AbsoluteIndex.kLocalVariables]); Push(stackFrame.Frame[(int)StackFrame.AbsoluteIndex.kStackFrameDepth]); Push(stackFrame.Frame[(int)StackFrame.AbsoluteIndex.kStackFrameType]); Push(stackFrame.Frame[(int)StackFrame.AbsoluteIndex.kCallerStackFrameType]); Push(stackFrame.Frame[(int)StackFrame.AbsoluteIndex.kFunctionCallerBlock]); Push(stackFrame.Frame[(int)StackFrame.AbsoluteIndex.kFunctionBlock]); Push(stackFrame.Frame[(int)StackFrame.AbsoluteIndex.kReturnAddress]); Push(stackFrame.Frame[(int)StackFrame.AbsoluteIndex.kFunction]); Push(stackFrame.Frame[(int)StackFrame.AbsoluteIndex.kClass]); Push(stackFrame.Frame[(int)StackFrame.AbsoluteIndex.kThisPtr]); FramePointer = Stack.Count; }
private StackValue Execute( List<FunctionEndPoint> functionEndPoint, Context c, List<StackValue> formalParameters, List<ReplicationInstruction> replicationInstructions, StackFrame stackFrame, RuntimeCore runtimeCore, FunctionGroup funcGroup) { SingleRunTraceData singleRunTraceData = (invokeCount < traceData.Count) ? traceData[invokeCount] : new SingleRunTraceData(); SingleRunTraceData newTraceData = new SingleRunTraceData(); StackValue ret; if (replicationInstructions.Count == 0) { c.IsReplicating = false; ret = ExecWithZeroRI(functionEndPoint, c, formalParameters, stackFrame, runtimeCore, funcGroup, singleRunTraceData, newTraceData); } else //replicated call { c.IsReplicating = true; ret = ExecWithRISlowPath(functionEndPoint, c, formalParameters, replicationInstructions, stackFrame, runtimeCore, funcGroup, singleRunTraceData, newTraceData); } //Do a trace save here if (invokeCount < traceData.Count) { traceData[invokeCount] = newTraceData; } else { traceData.Add(newTraceData); } invokeCount++; //We've completed this invocation return ret; }
private void BounceExplicit(int exeblock, int entry, Language language, StackFrame frame) { fepRun = false; rmem.PushStackFrame(frame); SetupExecutive(exeblock, entry); bool debugRun = (0 != (debugFlags & (int)DebugFlags.SPAWN_DEBUGGER)); if (!fepRun || fepRun && debugRun) { logVMMessage("Start JIL Execution - " + CoreUtils.GetLanguageString(language)); } }
/// <summary> /// Excecute an arbitrary depth replication using the full slow path algorithm /// </summary> /// <param name="functionEndPoint"> </param> /// <param name="c"></param> /// <param name="formalParameters"></param> /// <param name="replicationInstructions"></param> /// <param name="stackFrame"></param> /// <param name="core"></param> /// <returns></returns> private StackValue ExecWithRISlowPath( List<FunctionEndPoint> functionEndPoint, Context c, List<StackValue> formalParameters, List<ReplicationInstruction> replicationInstructions, StackFrame stackFrame, RuntimeCore runtimeCore, FunctionGroup funcGroup, SingleRunTraceData previousTraceData, SingleRunTraceData newTraceData) { if (runtimeCore.Options.ExecutionMode == ExecutionMode.Parallel) throw new NotImplementedException("Parallel mode disabled: {BF417AD5-9EA9-4292-ABBC-3526FC5A149E}"); //Recursion base case if (replicationInstructions.Count == 0) { return ExecWithZeroRI(functionEndPoint, c, formalParameters, stackFrame, runtimeCore, funcGroup, previousTraceData, newTraceData); } //Get the replication instruction that this call will deal with ReplicationInstruction ri = replicationInstructions[0]; if (ri.Zipped) { ZipAlgorithm algorithm = ri.ZipAlgorithm; //For each item in this plane, an array of the length of the minimum will be constructed //The size of the array will be the minimum size of the passed arrays List<int> repIndecies = ri.ZipIndecies; //this will hold the heap elements for all the arrays that are going to be replicated over List<StackValue[]> parameters = new List<StackValue[]>(); int retSize; switch (algorithm) { case ZipAlgorithm.Shortest: retSize = Int32.MaxValue; //Search to find the smallest break; case ZipAlgorithm.Longest: retSize = Int32.MinValue; //Search to find the largest break; default: throw new ReplicationCaseNotCurrentlySupported(Resources.AlgorithmNotSupported); } bool hasEmptyArg = false; foreach (int repIndex in repIndecies) { StackValue[] subParameters = null; if (formalParameters[repIndex].IsArray) { subParameters = runtimeCore.Heap.ToHeapObject<DSArray>(formalParameters[repIndex]).Values.ToArray(); } else { subParameters = new StackValue[] { formalParameters[repIndex] }; } parameters.Add(subParameters); if (subParameters.Length == 0) hasEmptyArg = true; switch (algorithm) { case ZipAlgorithm.Shortest: retSize = Math.Min(retSize, subParameters.Length); //We need the smallest array break; case ZipAlgorithm.Longest: retSize = Math.Max(retSize, subParameters.Length); //We need the longest array break; } } // If we're being asked to replicate across an empty list // then it's always going to be zero, as there will never be any // data to pass to that parameter. if (hasEmptyArg) retSize = 0; StackValue[] retSVs = new StackValue[retSize]; SingleRunTraceData retTrace = newTraceData; retTrace.NestedData = new List<SingleRunTraceData>(); //this will shadow the SVs as they are created //Populate out the size of the list with default values //@TODO:Luke perf optimisation here for (int i = 0; i < retSize; i++) retTrace.NestedData.Add(new SingleRunTraceData()); for (int i = 0; i < retSize; i++) { SingleRunTraceData lastExecTrace = new SingleRunTraceData(); if (previousTraceData.HasNestedData && i < previousTraceData.NestedData.Count) { //There was previous data that needs loading into the cache lastExecTrace = previousTraceData.NestedData[i]; } else { //We're off the edge of the previous trace window //So just pass in an empty block lastExecTrace = new SingleRunTraceData(); } //Build the call List<StackValue> newFormalParams = new List<StackValue>(); newFormalParams.AddRange(formalParameters); for (int repIi = 0; repIi < repIndecies.Count; repIi++) { switch (algorithm) { case ZipAlgorithm.Shortest: //If the shortest algorithm is selected this would newFormalParams[repIndecies[repIi]] = parameters[repIi][i]; break; case ZipAlgorithm.Longest: int length = parameters[repIi].Length; if (i < length) { newFormalParams[repIndecies[repIi]] = parameters[repIi][i]; } else { newFormalParams[repIndecies[repIi]] = parameters[repIi].Last(); } break; } } List<ReplicationInstruction> newRIs = new List<ReplicationInstruction>(); newRIs.AddRange(replicationInstructions); newRIs.RemoveAt(0); SingleRunTraceData cleanRetTrace = new SingleRunTraceData(); retSVs[i] = ExecWithRISlowPath(functionEndPoint, c, newFormalParams, newRIs, stackFrame, runtimeCore, funcGroup, lastExecTrace, cleanRetTrace); runtimeCore.AddCallSiteGCRoot(CallSiteID, retSVs[i]); retTrace.NestedData[i] = cleanRetTrace; } StackValue ret = runtimeCore.RuntimeMemory.Heap.AllocateArray(retSVs); return ret; } else { //With a cartesian product over an array, we are going to create an array of n //where the n is the product of the next item //We will call the subsequent reductions n times int cartIndex = ri.CartesianIndex; //this will hold the heap elements for all the arrays that are going to be replicated over bool supressArray = false; int retSize; StackValue[] parameters = null; if (formalParameters[cartIndex].IsArray) { DSArray array = runtimeCore.Heap.ToHeapObject<DSArray>(formalParameters[cartIndex]); parameters = array.Values.ToArray(); retSize = parameters.Length; } else { retSize = 1; supressArray = true; } StackValue[] retSVs = new StackValue[retSize]; SingleRunTraceData retTrace = newTraceData; retTrace.NestedData = new List<SingleRunTraceData>(); //this will shadow the SVs as they are created //Populate out the size of the list with default values //@TODO:Luke perf optimisation here for (int i = 0; i < retSize; i++) { retTrace.NestedData.Add(new SingleRunTraceData()); } if (supressArray) { List<ReplicationInstruction> newRIs = new List<ReplicationInstruction>(); newRIs.AddRange(replicationInstructions); newRIs.RemoveAt(0); List<StackValue> newFormalParams = new List<StackValue>(); newFormalParams.AddRange(formalParameters); return ExecWithRISlowPath(functionEndPoint, c, newFormalParams, newRIs, stackFrame, runtimeCore, funcGroup, previousTraceData, newTraceData); } //Now iterate over each of these options for (int i = 0; i < retSize; i++) { //Build the call List<StackValue> newFormalParams = new List<StackValue>(); newFormalParams.AddRange(formalParameters); if (parameters != null) { //It was an array pack the arg with the current value newFormalParams[cartIndex] = parameters[i]; } List<ReplicationInstruction> newRIs = new List<ReplicationInstruction>(); newRIs.AddRange(replicationInstructions); newRIs.RemoveAt(0); SingleRunTraceData lastExecTrace; if (previousTraceData.HasNestedData && i < previousTraceData.NestedData.Count) { //There was previous data that needs loading into the cache lastExecTrace = previousTraceData.NestedData[i]; } else if (previousTraceData.HasData && i == 0) { //We've moved up one dimension, and there was a previous run lastExecTrace = new SingleRunTraceData(); lastExecTrace.Data = previousTraceData.GetLeftMostData(); } else { //We're off the edge of the previous trace window //So just pass in an empty block lastExecTrace = new SingleRunTraceData(); } //previousTraceData = lastExecTrace; SingleRunTraceData cleanRetTrace = new SingleRunTraceData(); retSVs[i] = ExecWithRISlowPath(functionEndPoint, c, newFormalParams, newRIs, stackFrame, runtimeCore, funcGroup, lastExecTrace, cleanRetTrace); runtimeCore.AddCallSiteGCRoot(CallSiteID, retSVs[i]); retTrace.NestedData[i] = cleanRetTrace; } StackValue ret = runtimeCore.RuntimeMemory.Heap.AllocateArray(retSVs); return ret; } }
private void CALL_Handler(Instruction instruction) { PushInterpreterProps(Properties); int fi = instruction.op1.FunctionIndex; int ci = instruction.op2.ClassIndex; rmem.Pop(); StackValue svBlock = rmem.Pop(); int blockId = svBlock.BlockIndex; if (runtimeCore.Options.RunMode != InterpreterMode.Expression) { rmem.PushConstructBlockId(blockId); } ProcedureNode fNode; if (ci != Constants.kInvalidIndex) { fNode = exe.classTable.ClassNodes[ci].ProcTable.Procedures[fi]; } else { fNode = exe.procedureTable[blockId].Procedures[fi]; } // Disabling support for stepping into replicating function calls temporarily // This CALL instruction has a corresponding RETC instruction // and for debugger purposes for every RETURN/RETC where we restore the states, // we need a corresponding SetUpCallr to save the states. Therefore this call here - pratapa if (runtimeCore.Options.IDEDebugMode && runtimeCore.Options.RunMode != InterpreterMode.Expression) { runtimeCore.DebugProps.SetUpCallrForDebug(runtimeCore, this, fNode, pc, true); } StackValue svThisPointer = StackValue.BuildInvalid(); int pcoffset = 0; // It is to specially handle calling base constructor // from derive class and calling setter. // // For the first case, we want to call base constructor // but dont want to allocate memory from the heap again // (instruction ALLOC), so we want to skip the first // instruction in base constructor. Besides, at the end // of base constructor instruction RETC doesnt actually // returns from a function as here we just simulate // function call. if (instruction.op3.IsInteger && instruction.op3.IntegerValue >= 0) { // thisptr should be the pointer to the instance of derive class svThisPointer = rmem.GetAtRelative(StackFrame.FrameIndexThisPtr); // how many instruction offset? basically it should be 1 to skip ALLOCC pcoffset = (int)instruction.op3.IntegerValue; // To simulate CALLR. We have to retrive the param values from the // stack and reverse these values and save back to the stack. Otherwise // in base constructor all params will be in reverse order List<StackValue> argvalues = new List<StackValue>(); int stackindex = rmem.Stack.Count - 1; for (int idx = 0; idx < fNode.ArgumentTypes.Count; ++idx) { StackValue value = rmem.Stack[stackindex--]; argvalues.Add(value); // Probably it is useless in calling base constructor bool hasGuide = rmem.Stack[stackindex].IsReplicationGuide; if (hasGuide) { var replicationGuideList = new List<int>(); // Retrieve replication guides value = rmem.Stack[stackindex--]; int guides = value.ReplicationGuide; if (guides > 0) { for (int i = 0; i < guides; ++i) { value = rmem.Stack[stackindex--]; replicationGuideList.Add(value.ReplicationGuide); } } replicationGuideList.Reverse(); } } rmem.PopFrame(fNode.ArgumentTypes.Count); for (int idx = 0; idx < fNode.ArgumentTypes.Count; ++idx) { rmem.Push(argvalues[idx]); } } // TODO: Jun: To set these at compile time. They are being hardcoded to 0 temporarily as // class methods are always defined only at the global scope int blockDecl = 0; int blockCaller = 0; // Comment Jun: the caller type is the current type in the stackframe StackFrameType callerType = (fepRun) ? StackFrameType.Function : StackFrameType.LanguageBlock; StackValue svCallConvention = StackValue.BuildCallingConversion((int)CallingConvention.CallType.ExplicitBase); TX = svCallConvention; // On implicit call, the SX is set in JIL Fep // On explicit call, the SX should be directly set here List<StackValue> registers = GetRegisters(); // Comment Jun: the depth is always 0 for a function call as we are reseting this for each function call // This is only incremented for every language block bounce int depth = 0; StackFrameType type = StackFrameType.Function; StackFrame stackFrame = new StackFrame(svThisPointer, ci, fi, pc + 1, blockDecl, blockCaller, callerType, type, depth, rmem.FramePointer, blockDecl, registers, 0); rmem.PushFrameForLocals(fNode.LocalCount); rmem.PushStackFrame(stackFrame); // Now let's go to the function pc = fNode.PC + pcoffset; fepRunStack.Push(false); // A standard call instruction must reset the graphnodes for associative if (Language.Associative == executingLanguage) { UpdateMethodDependencyGraph(pc, fi, ci); } if (runtimeCore.Options.RunMode != InterpreterMode.Expression) { rmem.PopConstructBlockId(); } SetupGraphNodesInScope(); }
//Single function call /// <summary> /// Dispatch without replication /// </summary> private StackValue ExecWithZeroRI(List<FunctionEndPoint> functionEndPoint, Context c, List<StackValue> formalParameters, StackFrame stackFrame, RuntimeCore runtimeCore, FunctionGroup funcGroup, SingleRunTraceData previousTraceData, SingleRunTraceData newTraceData) { if (runtimeCore.CancellationPending) { throw new ExecutionCancelledException(); } //@PERF: Todo add a fast path here for the case where we have a homogenious array so we can directly dispatch FunctionEndPoint finalFep = SelectFinalFep(c, functionEndPoint, formalParameters, stackFrame, runtimeCore); if (functionEndPoint == null) { runtimeCore.RuntimeStatus.LogWarning(WarningID.kMethodResolutionFailure, string.Format(Resources.FunctionDispatchFailed, "{2EB39E1B-557C-4819-94D8-CF7C9F933E8A}")); return StackValue.Null; } if (runtimeCore.Options.IDEDebugMode && runtimeCore.Options.RunMode != InterpreterMode.kExpressionInterpreter) { DebugFrame debugFrame = runtimeCore.DebugProps.DebugStackFrame.Peek(); debugFrame.FinalFepChosen = finalFep; } List<StackValue> coercedParameters = finalFep.CoerceParameters(formalParameters, runtimeCore); // Correct block id where the function is defined. stackFrame.FunctionBlock = finalFep.BlockScope; //TraceCache -> TLS //Extract left most high-D pack ISerializable traceD = previousTraceData.GetLeftMostData(); if (traceD != null) { //There was data associated with the previous execution, push this into the TLS Dictionary<string, ISerializable> dataDict = new Dictionary<string, ISerializable>(); dataDict.Add(TRACE_KEY, traceD); TraceUtils.SetObjectToTLS(dataDict); } else { //There was no trace data for this run TraceUtils.ClearAllKnownTLSKeys(); } //EXECUTE StackValue ret = finalFep.Execute(c, coercedParameters, stackFrame, runtimeCore); if (ret.IsNull) { //wipe the trace cache TraceUtils.ClearTLSKey(TRACE_KEY); } //TLS -> TraceCache Dictionary<string, ISerializable> traceRet = TraceUtils.GetObjectFromTLS(); if (traceRet.ContainsKey(TRACE_KEY)) { var val = traceRet[TRACE_KEY]; newTraceData.Data = val; } // An explicit call requires return coercion at the return instruction if (!ret.IsExplicitCall) { ret = PerformReturnTypeCoerce(finalFep, runtimeCore, ret); } return ret; }
private StackValue CallrForMemberFunction(int blockIndex, int classIndex, int procIndex, bool hasDebugInfo, ref bool isExplicitCall) { var svDepth = rmem.Pop(); Validity.Assert(svDepth.IsInteger); var arrayDim = rmem.Pop(); Validity.Assert(arrayDim.IsArrayDimension); ClassNode classNode = exe.classTable.ClassNodes[classIndex]; ProcedureNode procNode = classNode.ProcTable.Procedures[procIndex]; // Get all arguments and replications var arguments = PopArgumentsFromStack(procNode.ArgumentTypes.Count); arguments.Reverse(); var repGuides = GetCachedReplicationGuides( arguments.Count + 1); var atLevels = GetCachedAtLevels(arguments.Count + 1); StackValue lhs = rmem.Pop(); StackValue thisObject = lhs; bool isValidThisPointer = true; if (lhs.IsArray) { isValidThisPointer = ArrayUtils.GetFirstNonArrayStackValue(lhs, ref thisObject, runtimeCore); arguments.Insert(0, lhs); } if (!isValidThisPointer || (!thisObject.IsPointer && !thisObject.IsArray)) { runtimeCore.RuntimeStatus.LogWarning(WarningID.DereferencingNonPointer, Resources.kDeferencingNonPointer); return StackValue.Null; } var registers = GetRegisters(); var stackFrame = new StackFrame(thisObject, classIndex, procIndex, pc + 1, 0, runtimeCore.RunningBlock, fepRun ? StackFrameType.Function : StackFrameType.LanguageBlock, StackFrameType.Function, 0, rmem.FramePointer, 0, registers, 0); var callsite = runtimeCore.RuntimeData.GetCallSite(exe.ExecutingGraphnode, classIndex, procNode.Name, exe, runtimeCore.RunningBlock, runtimeCore.Options, runtimeCore.RuntimeStatus); Validity.Assert(null != callsite); bool setDebugProperty = runtimeCore.Options.IDEDebugMode && runtimeCore.Options.RunMode != InterpreterMode.Expression && procNode != null; if (setDebugProperty) { runtimeCore.DebugProps.SetUpCallrForDebug( runtimeCore, this, procNode, pc, false, callsite, arguments, repGuides, stackFrame, null, hasDebugInfo); } var argumentAtLevels = AtLevelHandler.GetArgumentAtLevelStructure(arguments, atLevels, runtimeCore); StackValue sv = callsite.JILDispatch(argumentAtLevels.Arguments, repGuides, argumentAtLevels.DominantStructure, stackFrame, runtimeCore, new Runtime.Context()); isExplicitCall = sv.IsExplicitCall; if (isExplicitCall) { Properties.functionCallArguments = argumentAtLevels.Arguments; Properties.functionCallDotCallDimensions = new List<StackValue>(); Properties.DominantStructure = argumentAtLevels.DominantStructure; CallExplicit(sv.ExplicitCallEntry); } return sv; }
public override StackValue Execute(ProtoCore.Runtime.Context c, List <StackValue> formalParameters, ProtoCore.DSASM.StackFrame stackFrame, Core core) { ProtoCore.DSASM.Interpreter interpreter = new ProtoCore.DSASM.Interpreter(core, true); ProtoCore.DSASM.Executive oldDSASMExec = null; if (core.CurrentExecutive != null) { oldDSASMExec = core.CurrentExecutive.CurrentDSASMExec; core.CurrentExecutive.CurrentDSASMExec = interpreter.runtime; } // Assert for the block type activation.globs = core.DSExecutable.runtimeSymbols[core.RunningBlock].GetGlobalSize(); // // Comment Jun: // Storing execution states is relevant only if the current scope is a function, // as this mechanism is used to keep track of maintining execution states of recursive calls // This mechanism should also be ignored if the function call is non-recursive as it does not need to maintains state in that case int execStateSize = procedureNode.GraphNodeList.Count; stackFrame.ExecutionStateSize = execStateSize; for (int n = execStateSize - 1; n >= 0; --n) { AssociativeGraph.GraphNode gnode = procedureNode.GraphNodeList[n]; interpreter.Push(StackValue.BuildBoolean(gnode.isDirty)); } // Push Params formalParameters.Reverse(); for (int i = 0; i < formalParameters.Count; i++) { interpreter.Push(formalParameters[i]); } StackValue svThisPtr = stackFrame.ThisPtr; StackValue svBlockDecl = StackValue.BuildBlockIndex(stackFrame.FunctionBlock); // Jun: Make sure we have no empty or unaligned frame data Validity.Assert(DSASM.StackFrame.kStackFrameSize == stackFrame.Frame.Length); // Setup the stack frame data //int thisPtr = (int)stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kThisPtr).opdata; int ci = activation.classIndex; int fi = activation.funcIndex; int returnAddr = stackFrame.ReturnPC; int blockDecl = stackFrame.FunctionBlock; int blockCaller = stackFrame.FunctionCallerBlock; int framePointer = core.Rmem.FramePointer; int locals = activation.locals; // Update the running block to tell the execution engine which set of instruction to execute // TODO(Jun/Jiong): Considering store the orig block id to stack frame int origRunningBlock = core.RunningBlock; core.RunningBlock = (int)svBlockDecl.opdata; // Set SX register interpreter.runtime.SX = svBlockDecl; StackFrameType callerType = stackFrame.CallerStackFrameType; List <StackValue> registers = new List <DSASM.StackValue>(); StackValue svCallConvention; bool isDispose = CoreUtils.IsDisposeMethod(procedureNode.name); bool explicitCall = !c.IsReplicating && !c.IsImplicitCall && !isDispose; if (explicitCall) { svCallConvention = StackValue.BuildCallingConversion((int)ProtoCore.DSASM.CallingConvention.CallType.kExplicit); } else { svCallConvention = StackValue.BuildCallingConversion((int)ProtoCore.DSASM.CallingConvention.CallType.kImplicit); } stackFrame.TX = svCallConvention; interpreter.runtime.TX = svCallConvention; // Set SX register stackFrame.SX = svBlockDecl; interpreter.runtime.SX = svBlockDecl; // TODO Jun: // The stackframe carries the current set of registers // Determine if this can be done even for the non explicit call implementation registers.AddRange(stackFrame.GetRegisters()); // Comment Jun: the depth is always 0 for a function call as we are reseting this for each function call // This is only incremented for every language block bounce int depth = stackFrame.Depth; DSASM.StackFrameType type = stackFrame.StackFrameType; Validity.Assert(depth == 0); Validity.Assert(type == DSASM.StackFrameType.kTypeFunction); core.Rmem.PushStackFrame(svThisPtr, ci, fi, returnAddr, blockDecl, blockCaller, callerType, type, depth, framePointer, registers, locals, execStateSize); StackValue svRet; if (explicitCall) { svRet = ProtoCore.DSASM.StackValue.BuildExplicitCall(activation.pc); } else { svRet = interpreter.Run(core.RunningBlock, activation.pc, Language.kInvalid, core.Breakpoints); core.RunningBlock = origRunningBlock; } if (core.CurrentExecutive != null) { core.CurrentExecutive.CurrentDSASMExec = oldDSASMExec; } return(svRet); //DSASM.Mirror.ExecutionMirror.Unpack(svRet, core.heap, core); }
public override StackValue Execute(ProtoCore.Runtime.Context c, List <StackValue> formalParameters, ProtoCore.DSASM.StackFrame stackFrame, Core core) { ProtoCore.DSASM.Interpreter interpreter = new ProtoCore.DSASM.Interpreter(core, true); ProtoCore.DSASM.Executive oldDSASMExec = null; if (core.CurrentExecutive != null) { oldDSASMExec = core.CurrentExecutive.CurrentDSASMExec; core.CurrentExecutive.CurrentDSASMExec = interpreter.runtime; } // Assert for the block type activation.globs = core.DSExecutable.runtimeSymbols[core.RunningBlock].GetGlobalSize(); // Push Execution states int execStateSize = 0; if (null != stackFrame.ExecutionStates) { execStateSize = stackFrame.ExecutionStates.Length; // ExecutionStates are in lexical order // Push them in reverse order (similar to args) so they can be retrieved in sequence // Retrieveing the executing states occur on function return for (int n = execStateSize - 1; n >= 0; --n) { StackValue svState = stackFrame.ExecutionStates[n]; Validity.Assert(svState.IsBoolean); interpreter.Push(svState); } } // Push Params formalParameters.Reverse(); for (int i = 0; i < formalParameters.Count; i++) { interpreter.Push(formalParameters[i]); } StackValue svThisPtr = stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kThisPtr); StackValue svBlockDecl = stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kFunctionBlock); // Jun: Make sure we have no empty or unaligned frame data Validity.Assert(DSASM.StackFrame.kStackFrameSize == stackFrame.Frame.Length); // Setup the stack frame data //int thisPtr = (int)stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kThisPtr).opdata; int ci = activation.classIndex; int fi = activation.funcIndex; int returnAddr = (int)stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kReturnAddress).opdata; int blockDecl = (int)svBlockDecl.opdata; int blockCaller = (int)stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kFunctionCallerBlock).opdata; int framePointer = core.Rmem.FramePointer; int locals = activation.locals; // Update the running block to tell the execution engine which set of instruction to execute // TODO(Jun/Jiong): Considering store the orig block id to stack frame int origRunningBlock = core.RunningBlock; core.RunningBlock = (int)svBlockDecl.opdata; // Set SX register interpreter.runtime.SX = svBlockDecl; DSASM.StackFrameType callerType = (DSASM.StackFrameType)stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kCallerStackFrameType).opdata; List <StackValue> registers = new List <DSASM.StackValue>(); StackValue svCallConvention; bool isDispose = CoreUtils.IsDisposeMethod(procedureNode.name); bool explicitCall = !c.IsReplicating && !c.IsImplicitCall && !isDispose; if (explicitCall) { svCallConvention = StackValue.BuildCallingConversion((int)ProtoCore.DSASM.CallingConvention.CallType.kExplicit); } else { svCallConvention = StackValue.BuildCallingConversion((int)ProtoCore.DSASM.CallingConvention.CallType.kImplicit); } stackFrame.SetAt(DSASM.StackFrame.AbsoluteIndex.kRegisterTX, svCallConvention); interpreter.runtime.TX = svCallConvention; // Set SX register stackFrame.SetAt(DSASM.StackFrame.AbsoluteIndex.kRegisterSX, svBlockDecl); interpreter.runtime.SX = svBlockDecl; // TODO Jun: // The stackframe carries the current set of registers // Determine if this can be done even for the non explicit call implementation registers.AddRange(stackFrame.GetRegisters()); // Comment Jun: the depth is always 0 for a function call as we are reseting this for each function call // This is only incremented for every language block bounce int depth = (int)stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kStackFrameDepth).opdata; DSASM.StackFrameType type = (DSASM.StackFrameType)stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kStackFrameType).opdata; Validity.Assert(depth == 0); Validity.Assert(type == DSASM.StackFrameType.kTypeFunction); core.Rmem.PushStackFrame(svThisPtr, ci, fi, returnAddr, blockDecl, blockCaller, callerType, type, depth, framePointer, registers, locals, execStateSize); StackValue svRet; if (explicitCall) { svRet = ProtoCore.DSASM.StackValue.BuildExplicitCall(activation.pc); } else { if (core.ExecMode != DSASM.InterpreterMode.kExpressionInterpreter && core.Options.IDEDebugMode) { svRet = interpreter.Run(core.Breakpoints, core.RunningBlock, activation.pc, Language.kInvalid); } else { svRet = interpreter.Run(core.RunningBlock, activation.pc, Language.kInvalid); } core.RunningBlock = origRunningBlock; } if (core.CurrentExecutive != null) { core.CurrentExecutive.CurrentDSASMExec = oldDSASMExec; } return(svRet); //DSASM.Mirror.ExecutionMirror.Unpack(svRet, core.heap, core); }
public override StackValue Execute(ProtoCore.Runtime.Context c, List <StackValue> formalParameters, ProtoCore.DSASM.StackFrame stackFrame, Core core) { // ensure there is no data race, function resolution and execution happens in parallel // but for FFI we want it to be serial cause the code we are calling into may not cope // with parallelism. // // we are always looking and putting our function pointers in handler with each lang // so better lock for FFIHandler (being static) it will be good object to lock // lock (FFIHandlers) { ProtoCore.DSASM.Interpreter interpreter = new ProtoCore.DSASM.Interpreter(core, true); StackValue svThisPtr = stackFrame.GetAt(StackFrame.AbsoluteIndex.kThisPtr); StackValue svBlockDecl = stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kFunctionBlock); // Setup the stack frame data //int thisPtr = (int)stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kThisPtr).opdata; int ci = activation.JILRecord.classIndex; int fi = activation.JILRecord.funcIndex; int returnAddr = (int)stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kReturnAddress).opdata; int blockDecl = (int)svBlockDecl.opdata; int blockCaller = (int)stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kFunctionCallerBlock).opdata; int framePointer = core.Rmem.FramePointer; int locals = activation.JILRecord.locals; FFIHandler handler = FFIHandlers[activation.ModuleType]; FFIActivationRecord r = activation; string className = ""; if (activation.JILRecord.classIndex > 0) { className = core.DSExecutable.classTable.ClassNodes[activation.JILRecord.classIndex].name; } bool gcThisPtr = false; List <ProtoCore.Type> argTypes = new List <Type>(r.ParameterTypes); ProcedureNode fNode = null; if (ProtoCore.DSASM.Constants.kInvalidIndex != ci) { fNode = interpreter.runtime.exe.classTable.ClassNodes[ci].vtable.procList[fi]; } // Check if this is a 'this' pointer function overload that was generated by the compiler if (null != fNode && fNode.isAutoGeneratedThisProc) { int thisPtrIndex = 0; bool isStaticCall = svThisPtr.IsPointer && Constants.kInvalidPointer == (int)svThisPtr.opdata; if (isStaticCall) { thisPtrIndex = formalParameters.Count - 1; } argTypes.RemoveAt(thisPtrIndex); // Comment Jun: Execute() can handle a null this pointer. // But since we dont even need to to reach there if we dont have a valid this pointer, then just return null if (formalParameters[thisPtrIndex].IsNull) { core.RuntimeStatus.LogWarning(ProtoCore.RuntimeData.WarningID.kDereferencingNonPointer, ProtoCore.RuntimeData.WarningMessage.kDeferencingNonPointer); return(StackValue.Null); } // These are the op types allowed. Validity.Assert(formalParameters[thisPtrIndex].IsPointer || formalParameters[thisPtrIndex].IsDefaultArgument); svThisPtr = formalParameters[thisPtrIndex]; gcThisPtr = true; formalParameters.RemoveAt(thisPtrIndex); } FFIFunctionPointer functionPointer = handler.GetFunctionPointer(r.ModuleName, className, r.FunctionName, argTypes, r.ReturnType); mFunctionPointer = Validate(functionPointer) ? functionPointer : null; mFunctionPointer.IsDNI = activation.IsDNI; if (mFunctionPointer == null) { return(ProtoCore.DSASM.StackValue.Null); } List <object> ps = new List <object>(); //obsolete { interpreter.runtime.executingBlock = core.RunningBlock; activation.JILRecord.globs = core.DSExecutable.runtimeSymbols[core.RunningBlock].GetGlobalSize(); // Params formalParameters.Reverse(); for (int i = 0; i < formalParameters.Count; i++) { interpreter.Push(formalParameters[i]); } List <StackValue> registers = new List <DSASM.StackValue>(); interpreter.runtime.SaveRegisters(registers); // Comment Jun: the depth is always 0 for a function call as we are reseting this for each function call // This is only incremented for every language block bounce int depth = 0; StackFrameType callerType = (StackFrameType)stackFrame.GetAt(StackFrame.AbsoluteIndex.kCallerStackFrameType).opdata; // FFI calls do not have execution states core.Rmem.PushStackFrame(svThisPtr, ci, fi, returnAddr, blockDecl, blockCaller, callerType, ProtoCore.DSASM.StackFrameType.kTypeFunction, depth, framePointer, registers, locals, 0); //is there a way the current stack be passed across and back into the managed runtime by FFI calling back into the language? //e.g. DCEnv* carrying all the stack information? look at how vmkit does this. // = jilMain.Run(ActivationRecord.JILRecord.pc, null, true); //double[] tempArray = GetUnderlyingArray<double>(jilMain.runtime.rmem.stack); Object ret = mFunctionPointer.Execute(c, interpreter); StackValue op; if (ret == null) { op = StackValue.Null; } else if (ret is StackValue) { op = (StackValue)ret; } else if (ret is Int64 || ret is int) { op = StackValue.BuildInt((Int64)ret); } else if (ret is double) { op = StackValue.BuildDouble((double)ret); } else { throw new ArgumentException(string.Format("FFI: incorrect return type {0} from external function {1}:{2}", activation.ReturnType.Name, activation.ModuleName, activation.FunctionName)); } // gc the parameters if (gcThisPtr)// && core.Options.EnableThisPointerFunctionOverload) { // thisptr is sent as parameter, so need to gc it. // but when running in expression interpreter mode, do not GC because in DSASM.Executive.DecRefCounter() related GC functions, // the reference count will not be changed in expression interpreter mode. if (core.ExecMode != ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter) { interpreter.runtime.Core.Rmem.Heap.GCRelease(new StackValue[] { svThisPtr }, interpreter.runtime); } } interpreter.runtime.Core.Rmem.Heap.GCRelease(formalParameters.ToArray(), interpreter.runtime); // increment the reference counter of the return value interpreter.runtime.GCRetain(op); // Clear the FFI stack frame // FFI stack frames have no local variables interpreter.runtime.rmem.FramePointer = (int)interpreter.runtime.rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexFramePointer).opdata; interpreter.runtime.rmem.PopFrame(ProtoCore.DSASM.StackFrame.kStackFrameSize + formalParameters.Count); return(op); //DSASM.Mirror.ExecutionMirror.Unpack(op, core.heap, core); } } }
/// <summary> /// Execute the data stored in core /// This is the entry point of all DS code to be executed /// </summary> /// <param name="core"></param> /// <returns></returns> public ProtoCore.RuntimeCore ExecuteVM(ProtoCore.Core core) { ProtoCore.RuntimeCore runtimeCore = CreateRuntimeCore(core); runtimeCore.StartTimer(); try { foreach (ProtoCore.DSASM.CodeBlock codeblock in core.CodeBlockList) { // Comment Jun: // On first bounce, the stackframe depth is initialized to -1 in the Stackfame constructor. // Passing it to bounce() increments it so the first depth is always 0 ProtoCore.DSASM.StackFrame stackFrame = new ProtoCore.DSASM.StackFrame(core.GlobOffset); stackFrame.FramePointer = runtimeCore.RuntimeMemory.FramePointer; // Comment Jun: Tell the new bounce stackframe that this is an implicit bounce // Register TX is used for this. StackValue svCallConvention = StackValue.BuildCallingConversion((int)ProtoCore.DSASM.CallingConvention.BounceType.kImplicit); stackFrame.TX = svCallConvention; // Initialize the entry point interpreter int locals = 0; // This is the global scope, there are no locals ProtoCore.DSASM.Interpreter interpreter = new ProtoCore.DSASM.Interpreter(runtimeCore); runtimeCore.CurrentExecutive.CurrentDSASMExec = interpreter.runtime; runtimeCore.CurrentExecutive.CurrentDSASMExec.Bounce(codeblock.codeBlockId, codeblock.instrStream.entrypoint, stackFrame, locals); } runtimeCore.NotifyExecutionEvent(ProtoCore.ExecutionStateEventArgs.State.kExecutionEnd); } catch { runtimeCore.NotifyExecutionEvent(ProtoCore.ExecutionStateEventArgs.State.kExecutionEnd); throw; } return runtimeCore; }
private void ComputeFeps( StringBuilder log, Context context, List<StackValue> arguments, FunctionGroup funcGroup, List<ReplicationInstruction> instructions, List<List<ReplicationGuide>> partialReplicationGuides, StackFrame stackFrame, RuntimeCore runtimeCore, out List<FunctionEndPoint> resolvesFeps, out List<ReplicationInstruction> replicationInstructions) { //With replication guides only //Exact match //Match with single elements //Match with single elements with upcast //Try replication without type cast //Match with type conversion //Match with type conversion with upcast //Try replication + type casting //Try replication + type casting + Array promotion #region First Case: Replicate only according to the replication guides { log.AppendLine("Case 1: Exact Match"); FunctionEndPoint fep = Case1GetCompleteMatchFEP(context, arguments, funcGroup, instructions, stackFrame, runtimeCore, log); if (fep != null) { if (runtimeCore.Options.DumpFunctionResolverLogic) runtimeCore.DSExecutable.EventSink.PrintMessage(log.ToString()); resolvesFeps = new List<FunctionEndPoint>() { fep }; replicationInstructions = instructions; return; } } #endregion #region Case 1a: Replicate only according to the replication guides, but with a sub-typing match { log.AppendLine("Case 1a: Replication guides + auto-replication + no cases"); List<List<StackValue>> reducedParams = Replicator.ComputeAllReducedParams(arguments, instructions, runtimeCore); int resolutionFailures; Dictionary<FunctionEndPoint, int> lookups = funcGroup.GetExactMatchStatistics( context, reducedParams, stackFrame, runtimeCore, out resolutionFailures); if (resolutionFailures == 0) { log.AppendLine("Resolution succeeded against FEP Cluster"); foreach (FunctionEndPoint fep in lookups.Keys) log.AppendLine("\t - " + fep); List<FunctionEndPoint> feps = new List<FunctionEndPoint>(); feps.AddRange(lookups.Keys); if (runtimeCore.Options.DumpFunctionResolverLogic) runtimeCore.DSExecutable.EventSink.PrintMessage(log.ToString()); //Otherwise we have a cluster of FEPs that can be used to dispatch the array resolvesFeps = feps; replicationInstructions = instructions; return; } } #endregion var replicationTrials = Replicator.BuildReplicationCombinations(instructions, arguments, runtimeCore); #region Case 2: Replication with no type cast { log.AppendLine("Case 2: Beginning Auto-replication, no casts"); //Build the possible ways in which we might replicate foreach (List<ReplicationInstruction> repOption in replicationTrials) { List<List<StackValue>> reducedParams = Replicator.ComputeAllReducedParams(arguments, repOption, runtimeCore); int resolutionFailures; Dictionary<FunctionEndPoint, int> lookups = funcGroup.GetExactMatchStatistics( context, reducedParams, stackFrame, runtimeCore, out resolutionFailures); if (resolutionFailures > 0) continue; log.AppendLine("Resolution succeeded against FEP Cluster"); foreach (FunctionEndPoint fep in lookups.Keys) log.AppendLine("\t - " + fep); List<FunctionEndPoint> feps = new List<FunctionEndPoint>(); feps.AddRange(lookups.Keys); if (runtimeCore.Options.DumpFunctionResolverLogic) runtimeCore.DSExecutable.EventSink.PrintMessage(log.ToString()); //Otherwise we have a cluster of FEPs that can be used to dispatch the array resolvesFeps = feps; replicationInstructions = repOption; return; } } #endregion #region Case 3: Match with type conversion, but no array promotion { log.AppendLine("Case 3: Type conversion"); FunctionEndPoint compliantTarget = GetCompliantFEP(context, arguments, funcGroup, instructions, stackFrame, runtimeCore); if (compliantTarget != null) { log.AppendLine("Resolution Succeeded: " + compliantTarget); if (runtimeCore.Options.DumpFunctionResolverLogic) runtimeCore.DSExecutable.EventSink.PrintMessage(log.ToString()); resolvesFeps = new List<FunctionEndPoint>() { compliantTarget }; replicationInstructions = instructions; return; } } #endregion #region Case 4: Match with type conversion and replication log.AppendLine("Case 4: Replication + Type conversion"); { if (arguments.Any(arg => arg.IsArray)) { foreach (List<ReplicationInstruction> replicationOption in replicationTrials) { //@TODO: THis should use the proper reducer? FunctionEndPoint compliantTarget = GetCompliantFEP(context, arguments, funcGroup, replicationOption, stackFrame, runtimeCore); if (compliantTarget != null) { log.AppendLine("Resolution Succeeded: " + compliantTarget); if (runtimeCore.Options.DumpFunctionResolverLogic) runtimeCore.DSExecutable.EventSink.PrintMessage(log.ToString()); resolvesFeps = new List<FunctionEndPoint>() { compliantTarget }; replicationInstructions = replicationOption; return; } } } } #endregion #region Case 5: Match with type conversion, replication and array promotion log.AppendLine("Case 5: Replication + Type conversion + Array promotion"); { //Add as a first attempt a no-replication, but allowing up-promoting replicationTrials.Insert(0, new List<ReplicationInstruction>()); foreach (List<ReplicationInstruction> replicationOption in replicationTrials) { //@TODO: THis should use the proper reducer? FunctionEndPoint compliantTarget = GetCompliantFEP(context, arguments, funcGroup, replicationOption, stackFrame, runtimeCore, true); if (compliantTarget != null) { log.AppendLine("Resolution Succeeded: " + compliantTarget); if (runtimeCore.Options.DumpFunctionResolverLogic) runtimeCore.DSExecutable.EventSink.PrintMessage(log.ToString()); resolvesFeps = new List<FunctionEndPoint>() { compliantTarget }; replicationInstructions = replicationOption; return; } } } #endregion resolvesFeps = new List<FunctionEndPoint>(); replicationInstructions = instructions; }
public abstract StackValue Execute(ProtoCore.Runtime.Context c, List <StackValue> formalParameters, ProtoCore.DSASM.StackFrame stackFrame, RuntimeCore runtimeCore);
/// <summary> /// Get complete match attempts to locate a function endpoint where 1 FEP matches all of the requirements for dispatch /// </summary> /// <param name="context"></param> /// <param name="arguments"></param> /// <param name="funcGroup"></param> /// <param name="replicationControl"></param> /// <param name="stackFrame"></param> /// <param name="core"></param> /// <param name="log"></param> /// <returns></returns> private FunctionEndPoint Case1GetCompleteMatchFEP(Context context, List<StackValue> arguments, FunctionGroup funcGroup, List<ReplicationInstruction> replicationInstructions, StackFrame stackFrame, RuntimeCore runtimeCore, StringBuilder log) { //Exact match List<FunctionEndPoint> exactTypeMatchingCandindates = funcGroup.GetExactTypeMatches(context, arguments, replicationInstructions, stackFrame, runtimeCore); FunctionEndPoint fep = null; if (exactTypeMatchingCandindates.Count > 0) { if (exactTypeMatchingCandindates.Count == 1) { //Exact match fep = exactTypeMatchingCandindates[0]; log.AppendLine("1 exact match found - FEP selected" + fep); } else { //Exact match with upcast fep = SelectFEPFromMultiple(stackFrame, runtimeCore, exactTypeMatchingCandindates, arguments); log.AppendLine(exactTypeMatchingCandindates.Count + "exact matches found - FEP selected" + fep); } } return fep; }
public override StackValue Execute(ProtoCore.Runtime.Context c, List <StackValue> formalParameters, ProtoCore.DSASM.StackFrame stackFrame, RuntimeCore runtimeCore) { // ensure there is no data race, function resolution and execution happens in parallel // but for FFI we want it to be serial cause the code we are calling into may not cope // with parallelism. // // we are always looking and putting our function pointers in handler with each lang // so better lock for FFIHandler (being static) it will be good object to lock // lock (FFIHandlers) { Interpreter interpreter = new Interpreter(runtimeCore, true); // Setup the stack frame data StackValue svThisPtr = stackFrame.ThisPtr; int ci = activation.JILRecord.classIndex; int fi = activation.JILRecord.funcIndex; int returnAddr = stackFrame.ReturnPC; int blockDecl = stackFrame.FunctionBlock; int blockCaller = stackFrame.FunctionCallerBlock; int framePointer = runtimeCore.RuntimeMemory.FramePointer; int locals = activation.JILRecord.locals; FFIHandler handler = FFIHandlers[activation.ModuleType]; FFIActivationRecord r = activation; string className = ""; if (activation.JILRecord.classIndex > 0) { className = runtimeCore.DSExecutable.classTable.ClassNodes[activation.JILRecord.classIndex].Name; } List <ProtoCore.Type> argTypes = new List <Type>(r.ParameterTypes); ProcedureNode fNode = null; if (ProtoCore.DSASM.Constants.kInvalidIndex != ci) { fNode = interpreter.runtime.exe.classTable.ClassNodes[ci].ProcTable.Procedures[fi]; } // Check if this is a 'this' pointer function overload that was generated by the compiler if (null != fNode && fNode.IsAutoGeneratedThisProc) { int thisPtrIndex = 0; bool isStaticCall = svThisPtr.IsPointer && Constants.kInvalidPointer == svThisPtr.Pointer; if (isStaticCall) { stackFrame.ThisPtr = formalParameters[thisPtrIndex]; } argTypes.RemoveAt(thisPtrIndex); // Comment Jun: Execute() can handle a null this pointer. // But since we dont even need to to reach there if we dont have a valid this pointer, then just return null if (formalParameters[thisPtrIndex].IsNull) { runtimeCore.RuntimeStatus.LogWarning(ProtoCore.Runtime.WarningID.DereferencingNonPointer, Resources.kDeferencingNonPointer); return(StackValue.Null); } // These are the op types allowed. Validity.Assert(formalParameters[thisPtrIndex].IsPointer || formalParameters[thisPtrIndex].IsDefaultArgument); svThisPtr = formalParameters[thisPtrIndex]; formalParameters.RemoveAt(thisPtrIndex); } FFIFunctionPointer functionPointer = handler.GetFunctionPointer(r.ModuleName, className, r.FunctionName, argTypes, r.ReturnType); mFunctionPointer = Validate(functionPointer) ? functionPointer : null; mFunctionPointer.IsDNI = activation.IsDNI; if (mFunctionPointer == null) { return(ProtoCore.DSASM.StackValue.Null); } { interpreter.runtime.executingBlock = runtimeCore.RunningBlock; activation.JILRecord.globs = runtimeCore.DSExecutable.runtimeSymbols[runtimeCore.RunningBlock].GetGlobalSize(); // Params formalParameters.Reverse(); for (int i = 0; i < formalParameters.Count; i++) { interpreter.Push(formalParameters[i]); } List <StackValue> registers = interpreter.runtime.GetRegisters(); // Comment Jun: the depth is always 0 for a function call as we are reseting this for each function call // This is only incremented for every language block bounce int depth = 0; StackFrameType callerType = stackFrame.CallerStackFrameType; // FFI calls do not have execution states runtimeCore.RuntimeMemory.PushFrameForLocals(locals); StackFrame newStackFrame = new StackFrame(svThisPtr, ci, fi, returnAddr, blockDecl, blockCaller, callerType, StackFrameType.Function, depth, framePointer, 0, registers, 0); runtimeCore.RuntimeMemory.PushStackFrame(newStackFrame); //is there a way the current stack be passed across and back into the managed runtime by FFI calling back into the language? //e.g. DCEnv* carrying all the stack information? look at how vmkit does this. // = jilMain.Run(ActivationRecord.JILRecord.pc, null, true); //double[] tempArray = GetUnderlyingArray<double>(jilMain.runtime.rmem.stack); Object ret = mFunctionPointer.Execute(c, interpreter); StackValue op; if (ret == null) { op = StackValue.Null; } else if (ret is StackValue) { op = (StackValue)ret; } else if (ret is Int64 || ret is int) { op = StackValue.BuildInt((Int64)ret); } else if (ret is double) { op = StackValue.BuildDouble((double)ret); } else { throw new ArgumentException(string.Format("FFI: incorrect return type {0} from external function {1}:{2}", activation.ReturnType.Name, activation.ModuleName, activation.FunctionName)); } // Clear the FFI stack frame // FFI stack frames have no local variables interpreter.runtime.rmem.FramePointer = (int)interpreter.runtime.rmem.GetAtRelative(StackFrame.FrameIndexFramePointer).IntegerValue; interpreter.runtime.rmem.PopFrame(StackFrame.StackFrameSize + formalParameters.Count); return(op); } } }
/// <summary> /// Bounce to an existing executive /// </summary> /// <param name="exeblock"></param> /// <param name="entry"></param> /// <param name="context"></param> /// <param name="stackFrame"></param> /// <param name="locals"></param> /// <param name="fepRun"></param> /// <param name="exec"></param> /// <param name="breakpoints"></param> /// <returns></returns> public StackValue BounceUsingExecutive( DSASM.Executive executive, int exeblock, int entry, StackFrame stackFrame, int locals = 0, bool fepRun = false, DSASM.Executive exec = null, List<Instruction> breakpoints = null) { if (stackFrame != null) { rmem.PushFrameForLocals(locals); rmem.PushStackFrame(stackFrame); runtimeCore.DebugProps.SetUpBounce(exec, stackFrame.FunctionCallerBlock, stackFrame.ReturnPC); } executive.Execute(exeblock, entry, breakpoints); return executive.RX; }
/// <summary> /// Conservative guess as to whether this call will replicate or not /// This may give inaccurate answers if the node cluster doesn't actually exist /// </summary> /// <param name="context"></param> /// <param name="arguments"></param> /// <param name="stackFrame"></param> /// <param name="core"></param> /// <returns></returns> public bool WillCallReplicate(Context context, List<StackValue> arguments, List<List<ReplicationGuide>> partialReplicationGuides, StackFrame stackFrame, RuntimeCore runtimeCore, out List<List<ReplicationInstruction>> replicationTrials) { replicationTrials = new List<List<ReplicationInstruction>>(); if (partialReplicationGuides.Count > 0) { // Jun Comment: And at least one of them contains somthing for (int n = 0; n < partialReplicationGuides.Count; ++n) { if (partialReplicationGuides[n].Count > 0) { return true; } } } #region Get Function Group //@PERF: Possible optimisation point here, to deal with static dispatches that don't need replication analysis //Handle resolution Pass 1: Name -> Method Group FunctionGroup funcGroup; try { funcGroup = globalFunctionTable.GlobalFuncTable[classScope + 1][methodName]; } catch (KeyNotFoundException) { return false; } #endregion //Replication Control is an ordered list of the elements that we have to replicate over //Ordering implies containment, so element 0 is the outer most forloop, element 1 is nested within it etc. //Take the explicit replication guides and build the replication structure //Turn the replication guides into a guide -> List args data structure var instructions = Replicator.BuildPartialReplicationInstructions(partialReplicationGuides); #region First Case: Replicate only according to the replication guides { FunctionEndPoint fep = Case1GetCompleteMatchFEP(context, arguments, funcGroup, instructions, stackFrame, runtimeCore, new StringBuilder()); if (fep != null) { //found an exact match return false; } } #endregion #region Case 2: Replication with no type cast { //Build the possible ways in which we might replicate replicationTrials = Replicator.BuildReplicationCombinations(instructions, arguments, runtimeCore); foreach (List<ReplicationInstruction> replicationOption in replicationTrials) { List<List<StackValue>> reducedParams = Replicator.ComputeAllReducedParams(arguments, replicationOption, runtimeCore); int resolutionFailures; funcGroup.GetExactMatchStatistics(context, reducedParams, stackFrame, runtimeCore, out resolutionFailures); if (resolutionFailures > 0) continue; return true; //Replicates against cluster } } #endregion #region Case 3: Match with type conversion, but no array promotion { Dictionary<FunctionEndPoint, int> candidatesWithDistances = funcGroup.GetConversionDistances(context, arguments, instructions, runtimeCore.DSExecutable.classTable, runtimeCore); Dictionary<FunctionEndPoint, int> candidatesWithCastDistances = funcGroup.GetCastDistances(context, arguments, instructions, runtimeCore.DSExecutable.classTable, runtimeCore); List<FunctionEndPoint> candidateFunctions = GetCandidateFunctions(stackFrame, candidatesWithDistances); FunctionEndPoint compliantTarget = GetCompliantTarget(context, arguments, instructions, stackFrame, runtimeCore, candidatesWithCastDistances, candidateFunctions, candidatesWithDistances); if (compliantTarget != null) { return false; //Type conversion but no replication } } #endregion #region Case 5: Match with type conversion, replication and array promotion { //Build the possible ways in which we might replicate replicationTrials = Replicator.BuildReplicationCombinations(instructions, arguments, runtimeCore); //Add as a first attempt a no-replication, but allowing up-promoting replicationTrials.Insert(0, new List<ReplicationInstruction>() ); } #endregion return true; //It'll replicate if it suceeds }
public ExecutionMirror Execute(string code) { code = string.Format("{0} = {1};", Constants.kWatchResultVar, code); // TODO Jun: Move this initaliztion of the exe into a unified function //Core.ExprInterpreterExe = new Executable(); int blockId = ProtoCore.DSASM.Constants.kInvalidIndex; Core.Rmem.AlignStackForExprInterpreter(); //Initialize the watch stack and watchBaseOffset //The watchBaseOffset is used to indexing the watch variables and related temporary variables Core.watchBaseOffset = 0; Core.watchStack.Clear(); bool succeeded = Compile(code, out blockId); //Clear the warnings and errors so they will not continue impact the next compilation. //Fix IDE-662 Core.BuildStatus.Errors.Clear(); Core.BuildStatus.Warnings.Clear(); for (int i = 0; i < Core.watchBaseOffset; ++i) { Core.watchStack.Add(StackUtils.BuildNull()); } //Record the old function call depth //Fix IDE-523: part of error for watching non-existing member int oldFunctionCallDepth = Core.FunctionCallDepth; //Record the old start PC int oldStartPC = Core.startPC; if (succeeded) { //a2. Record the old start PC for restore instructions Core.startPC = Core.ExprInterpreterExe.instrStreamList[blockId].instrList.Count; Core.GenerateExprExeInstructions(blockId); //a3. Record the old running block int restoreBlock = Core.RunningBlock; Core.RunningBlock = blockId; //a4. Record the old debug entry PC and stack size of FileFepChosen int oldDebugEntryPC = Core.DebugProps.DebugEntryPC; //a5. Record the frame pointer for referencing to thisPtr Core.watchFramePointer = Core.Rmem.FramePointer; // The "Core.Bounce" below is gonna adjust the "FramePointer" // based on the current size of "Core.Rmem.Stack". All that is // good except that "Bounce" does not restore the previous value // of frame pointer after "bouncing back". Here we make a backup // of it and restore it right after the "Core.Bounce" call. // //Core.Executives[Core.CodeBlockList[Core.RunningBlock].language]. ProtoCore.Runtime.Context context = new ProtoCore.Runtime.Context(); try { ProtoCore.DSASM.StackFrame stackFrame = null; int locals = 0; StackValue sv = Core.Bounce(blockId, Core.startPC, context, stackFrame, locals, EventSink); // As Core.InterpreterProps stack member is pushed to every time the Expression Interpreter begins executing // it needs to be popped off at the end for stack alignment - pratapa Core.InterpreterProps.Pop(); } catch { } //r5. Restore frame pointer. Core.Rmem.FramePointer = Core.watchFramePointer; //r4. Restore the debug entry PC and stack size of FileFepChosen Core.DebugProps.DebugEntryPC = oldDebugEntryPC; //r3. Restore the running block Core.RunningBlock = restoreBlock; //r2. Restore the instructions in Core.ExprInterpreterExe int from = Core.startPC; int elems = Core.ExprInterpreterExe.iStreamCanvas.instrList.Count; Core.ExprInterpreterExe.instrStreamList[blockId].instrList.RemoveRange(from, elems); //Restore the start PC Core.startPC = oldStartPC; //Restore the function call depth //Fix IDE-523: part of error for watching non-existing member Core.FunctionCallDepth = oldFunctionCallDepth; //Clear the watchSymbolList foreach (SymbolNode node in Core.watchSymbolList) { if (ProtoCore.DSASM.Constants.kInvalidIndex == node.classScope) { Core.DSExecutable.runtimeSymbols[node.runtimeTableIndex].Remove(node); } else { Core.ClassTable.ClassNodes[node.classScope].symbols.Remove(node); } } } else { //Restore the start PC Core.startPC = oldStartPC; //Restore the function call depth //Fix IDE-523: part of error for watching non-existing member Core.FunctionCallDepth = oldFunctionCallDepth; //Clear the watchSymbolList foreach (SymbolNode node in Core.watchSymbolList) { if (ProtoCore.DSASM.Constants.kInvalidIndex == node.classScope) { Core.DSExecutable.runtimeSymbols[node.runtimeTableIndex].Remove(node); } else { Core.ClassTable.ClassNodes[node.classScope].symbols.Remove(node); } } // TODO: investigate why additional elements are added to the stack. Core.Rmem.RestoreStackForExprInterpreter(); throw new ProtoCore.Exceptions.CompileErrorsOccured(); } // TODO: investigate why additional elements are added to the stack. Core.Rmem.RestoreStackForExprInterpreter(); return(new ExecutionMirror(Core.CurrentExecutive.CurrentDSASMExec, Core)); }
public StackValue Evaluate(List<StackValue> args, StackFrame stackFrame) { // Build the stackframe var runtimeCore = interpreter.runtime.RuntimeCore; int classScopeCaller = stackFrame.ClassScope; int returnAddr = stackFrame.ReturnPC; int blockDecl = procNode.RuntimeIndex; int blockCaller = stackFrame.FunctionCallerBlock; int framePointer = runtimeCore.RuntimeMemory.FramePointer; StackValue thisPtr = StackValue.BuildPointer(Constants.kInvalidIndex); // Functoion has variable input parameter. This case only happen // for FFI functions whose last parameter's type is (params T[]). // In this case, we need to convert argument list from // // {a1, a2, ..., am, v1, v2, ..., vn} // // to // // {a1, a2, ..., am, {v1, v2, ..., vn}} if (procNode.IsVarArg) { int paramCount = procNode.ArgumentInfos.Count; Validity.Assert(paramCount >= 1); int varParamCount = args.Count - (paramCount - 1); var varParams = args.GetRange(paramCount - 1, varParamCount).ToArray(); args.RemoveRange(paramCount - 1, varParamCount); var packedParams = interpreter.runtime.rmem.Heap.AllocateArray(varParams); args.Add(packedParams); } bool isCallingMemberFunciton = procNode.ClassID != Constants.kInvalidIndex && !procNode.IsConstructor && !procNode.IsStatic; bool isValidThisPointer = true; if (isCallingMemberFunciton) { Validity.Assert(args.Count >= 1); thisPtr = args[0]; if (thisPtr.IsArray) { isValidThisPointer = ArrayUtils.GetFirstNonArrayStackValue(thisPtr, ref thisPtr, runtimeCore); } else { args.RemoveAt(0); } } if (!isValidThisPointer || (!thisPtr.IsPointer && !thisPtr.IsArray)) { runtimeCore.RuntimeStatus.LogWarning(WarningID.kDereferencingNonPointer, Resources.kDeferencingNonPointer); return StackValue.Null; } var callerType = stackFrame.StackFrameType; interpreter.runtime.TX = StackValue.BuildCallingConversion((int)ProtoCore.DSASM.CallingConvention.BounceType.kImplicit); StackValue svBlockDecl = StackValue.BuildBlockIndex(blockDecl); interpreter.runtime.SX = svBlockDecl; List<StackValue> registers = new List<StackValue>(); interpreter.runtime.SaveRegisters(registers); var newStackFrame = new StackFrame(thisPtr, classScopeCaller, 1, returnAddr, blockDecl, blockCaller, callerType, StackFrameType.kTypeFunction, 0, // depth framePointer, registers, null); bool isInDebugMode = runtimeCore.Options.IDEDebugMode && runtimeCore.Options.RunMode != InterpreterMode.kExpressionInterpreter; if (isInDebugMode) { runtimeCore.DebugProps.SetUpCallrForDebug( runtimeCore, interpreter.runtime, procNode, returnAddr - 1, false, callsite, args, new List<List<ProtoCore.ReplicationGuide>>(), newStackFrame); } StackValue rx = callsite.JILDispatchViaNewInterpreter( new Runtime.Context(), args, new List<List<ProtoCore.ReplicationGuide>>(), new List<AtLevel>(), newStackFrame, runtimeCore); if (isInDebugMode) { runtimeCore.DebugProps.RestoreCallrForNoBreak(runtimeCore, procNode); } return rx; }
private FunctionEndPoint GetCompliantFEP( Context context, List<StackValue> arguments, FunctionGroup funcGroup, List<ReplicationInstruction> replicationInstructions, StackFrame stackFrame, RuntimeCore runtimeCore, bool allowArrayPromotion = false) { Dictionary<FunctionEndPoint, int> candidatesWithDistances = funcGroup.GetConversionDistances( context, arguments, replicationInstructions, runtimeCore.DSExecutable.classTable, runtimeCore, allowArrayPromotion); Dictionary<FunctionEndPoint, int> candidatesWithCastDistances = funcGroup.GetCastDistances( context, arguments, replicationInstructions, runtimeCore.DSExecutable.classTable, runtimeCore); List<FunctionEndPoint> candidateFunctions = GetCandidateFunctions(stackFrame, candidatesWithDistances); FunctionEndPoint compliantTarget = GetCompliantTarget( context, arguments, replicationInstructions, stackFrame, runtimeCore, candidatesWithCastDistances, candidateFunctions, candidatesWithDistances); return compliantTarget; }