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; } }
public StackValue Callr(int functionIndex, int classIndex, int depth, ref bool explicitCall, bool isDynamicCall = false, bool hasDebugInfo = false) { isGlobScope = false; ProcedureNode fNode = null; // Comment Jun: this is curently unused but required for stack alignment if (!isDynamicCall) { StackValue svType = rmem.Pop(); runtimeVerify(AddressType.StaticType == svType.optype); int lhsStaticType = (int)svType.metaData.type; } // Pop off number of dimensions indexed into this function call // f()[0][1] -> 2 dimensions StackValue svDim = rmem.Pop(); runtimeVerify(AddressType.ArrayDim == svDim.optype); int fCallDimensions = (int)svDim.opdata; // Jun Comment: The block where the function was declared in StackValue svBlockDeclaration = rmem.Pop(); runtimeVerify(AddressType.BlockIndex == svBlockDeclaration.optype); int blockDeclId = (int)svBlockDeclaration.opdata; // Jun Comment: The block where the function is called from Validity.Assert(ProtoCore.DSASM.Constants.kInvalidIndex != core.RunningBlock); StackValue svBlockCaller = StackValue.BuildBlockIndex(core.RunningBlock); bool isMember = ProtoCore.DSASM.Constants.kInvalidIndex != classIndex; if (isMember) { // Constructor or member function fNode = exe.classTable.ClassNodes[classIndex].vtable.procList[functionIndex]; if (depth > 0) { if (fNode.isConstructor) { string message = String.Format(ProtoCore.RuntimeData.WarningMessage.KCallingConstructorOnInstance, fNode.name); core.RuntimeStatus.LogWarning(ProtoCore.RuntimeData.WarningID.kCallingConstructorOnInstance, message); isGlobScope = true; StackValue nullSv = StackValue.Null; return nullSv; } } } else { // Global function fNode = exe.procedureTable[blockDeclId].procList[functionIndex]; } // Build the arg values list List<StackValue> arguments = new List<StackValue>(); List<ProtoCore.ReplicationGuide> replicationGuideList = null; List<List<ProtoCore.ReplicationGuide>> replicationGuides = new List<List<ProtoCore.ReplicationGuide>>(); // Retrive the param values from the stack int stackindex = rmem.Stack.Count - 1; int argtype_i = fNode.argTypeList.Count - 1; int argFrameSize = 0; List<StackValue> dotCallDimensions = new List<StackValue>(); if (fNode.name == ProtoCore.DSASM.Constants.kDotMethodName) { int firstDotArgIndex = stackindex - (ProtoCore.DSASM.Constants.kDotCallArgCount - 1); StackValue svLHS = rmem.Stack[firstDotArgIndex]; arguments.Add(svLHS); argFrameSize = ProtoCore.DSASM.Constants.kDotArgCount; int functionArgsIndex = stackindex - (ProtoCore.DSASM.Constants.kDotCallArgCount - ProtoCore.DSASM.Constants.kDotArgIndexArgCount - 1); StackValue svArrayPtrFunctionArgs = rmem.Stack[functionArgsIndex]; GCRetain(svArrayPtrFunctionArgs); // Retrieve the indexed dimensions into the dot call int arrayDimIndex = stackindex - (ProtoCore.DSASM.Constants.kDotCallArgCount - ProtoCore.DSASM.Constants.kDotArgIndexArrayIndex - 1); StackValue svArrayPtrDimesions = rmem.Stack[arrayDimIndex]; Validity.Assert(svArrayPtrDimesions.optype == AddressType.ArrayPointer); int arrayCountIndex = stackindex - (ProtoCore.DSASM.Constants.kDotCallArgCount - ProtoCore.DSASM.Constants.kDotArgIndexDimCount - 1); StackValue svDimensionCount = rmem.Stack[arrayCountIndex]; Validity.Assert(svDimensionCount.optype == AddressType.Int); // If array dimension were provided then retrive the final pointer if (svDimensionCount.opdata > 0) { HeapElement he = rmem.Heap.Heaplist[(int)svArrayPtrDimesions.opdata]; Validity.Assert(he.VisibleSize == svDimensionCount.opdata); for (int n = 0; n < he.VisibleSize; ++n) { dotCallDimensions.Add(he.Stack[n] /*(int)he.Stack[n].opdata*/); } } } else { for (int p = 0; p < fNode.argTypeList.Count; ++p) { // Must iterate through the args in the stack in reverse as its unknown how many replication guides were pushed StackValue value = rmem.Stack[stackindex--]; ++argFrameSize; arguments.Add(value); if (fNode.name != ProtoCore.DSASM.Constants.kDotArgMethodName) { bool hasGuide = (AddressType.ReplicationGuide == rmem.Stack[stackindex].optype); if (hasGuide) { replicationGuideList = new List<ProtoCore.ReplicationGuide>(); // Retrieve replication guides value = rmem.Stack[stackindex--]; ++argFrameSize; runtimeVerify(AddressType.ReplicationGuide == value.optype); int guides = (int)value.opdata; if (guides > 0) { for (int i = 0; i < guides; ++i) { // Get the replicationguide number from the stack value = rmem.Stack[stackindex--]; Validity.Assert(value.optype == AddressType.Int); int guideNumber = (int)value.opdata; // Get the replication guide property from the stack value = rmem.Stack[stackindex--]; Validity.Assert(value.optype == AddressType.Boolean); bool isLongest = (int)value.opdata == 1 ? true : false; ProtoCore.ReplicationGuide guide = new ReplicationGuide(guideNumber, isLongest); replicationGuideList.Add(guide); ++argFrameSize; } } replicationGuideList.Reverse(); replicationGuides.Add(replicationGuideList); } } } // Pop off frame information rmem.Pop(argFrameSize); } replicationGuides.Reverse(); arguments.Reverse(); Runtime.Context runtimeContext = new Runtime.Context(); #if __PROTOTYPE_ARRAYUPDATE_FUNCTIONCALL // // Comment Jun: Retrieve the indices used to index in an argument // // List<List<int>> indexIntoList // foreach arg in functionNode.args // // Iterate over the symbols in the executing graph node // foreach symbol in executingGraphNode.dependents // List<int> argIndexInto = GetSymbolIndexedIntoList(symbol) // indexIntoList.push(argIndexInto) // end // context.indexlist = indexIntoList // sv = JILDispatch.callsite(function, args, context, ...) // end // if (null != Properties.executingGraphNode && null != Properties.executingGraphNode.dependentList && Properties.executingGraphNode.dependentList.Count > 0 ) { // Save the LHS of this graphnode runtimeContext.ArrayPointer = Properties.executingGraphNode.ArrayPointer; // Iterate over the symbols in the executing graph node for (int n = 0; n < Properties.executingGraphNode.dependentList.Count; n++) { List<int> indexIntoList = new List<int>(); { // Check if the current dependent was indexed into ProtoCore.DSASM.SymbolNode argSymbol = Properties.executingGraphNode.dependentList[n].updateNodeRefList[0].nodeList[0].symbol; if (symbolArrayIndexMap.ContainsKey(argSymbol.name)) { indexIntoList = symbolArrayIndexMap[argSymbol.name]; } } runtimeContext.IndicesIntoArgMap.Add(indexIntoList); } } #endif // 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 (ProtoCore.DSASM.Constants.kDotMethodName != fNode.name && ProtoCore.DSASM.Constants.kDotArgMethodName != fNode.name && ProtoCore.DSASM.Constants.kFunctionRangeExpression != fNode.name) { // Comment Jun: If this is a non-dotarg 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(core, arguments.Count); } bool isCallingDotArgCall = fNode.name == ProtoCore.DSASM.Constants.kDotArgMethodName; if (isCallingDotArgCall) { // Comment Jun: (Sept 8 2012) Check with Yuke what the intention of this is to the dotarg arguments for (int i = 0; i < arguments.Count; ++i) { GCRetain(arguments[i]); } } // if is dynamic call, the final pointer has been resovled in the ProcessDynamicFunction function StackValue svThisPtr = StackValue.Null; if (depth > 0) { // locals are not yet in the stack so there is no need to account for that in this stack frame if (isDynamicCall) { svThisPtr = rmem.Pop(); } else { svThisPtr = GetFinalPointer(depth); } // if (svThisPtr.optype != AddressType.Pointer) { string message = String.Format(ProtoCore.RuntimeData.WarningMessage.kInvokeMethodOnInvalidObject, fNode.name); core.RuntimeStatus.LogWarning(ProtoCore.RuntimeData.WarningID.kDereferencingNonPointer, message); isGlobScope = true; 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 (isMember && !fNode.isConstructor && !fNode.isStatic) { // A member function // Get the this pointer as this class instance would have already been cosntructed svThisPtr = rmem.GetAtRelative(rmem.GetStackIndex(ProtoCore.DSASM.StackFrame.kFrameIndexThisPtr)); } else { // Global svThisPtr = ProtoCore.DSASM.StackValue.BuildPointer(ProtoCore.DSASM.Constants.kInvalidPointer); } } if (svThisPtr.optype == AddressType.Pointer && svThisPtr.opdata != Constants.kInvalidIndex && svThisPtr.metaData.type != Constants.kInvalidIndex) { int runtimeClassIndex = (int)svThisPtr.metaData.type; ClassNode runtimeClass = core.ClassTable.ClassNodes[runtimeClassIndex]; if (runtimeClass.IsMyBase(classIndex)) { classIndex = runtimeClassIndex; } } // Build the stackframe //int thisPtr = (int)svThisPtr.opdata; int ci = classIndex; // ProtoCore.DSASM.Constants.kInvalidIndex; // Handled at FEP int fi = ProtoCore.DSASM.Constants.kInvalidIndex; // Handled at FEP int returnAddr = pc + 1; int blockDecl = (int)svBlockDeclaration.opdata; int blockCaller = (int)svBlockCaller.opdata; int framePointer = ProtoCore.DSASM.Constants.kInvalidIndex; framePointer = rmem.FramePointer; bool isInDotArgCall = false; int currentClassIndex = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexClass).opdata; int currentFunctionIndex = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexFunction).opdata; bool isGlobalScope = ProtoCore.DSASM.Constants.kGlobalScope == currentClassIndex && ProtoCore.DSASM.Constants.kGlobalScope == currentFunctionIndex; if (core.ExecMode != InterpreterMode.kExpressionInterpreter) { if (ProtoCore.DSASM.Constants.kGlobalScope != currentFunctionIndex) { int currentFunctionDeclBlock = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexFunctionBlock).opdata; ProcedureNode currentProcCall = GetProcedureNode(currentFunctionDeclBlock, currentClassIndex, currentFunctionIndex); isInDotArgCall = currentProcCall.name == ProtoCore.DSASM.Constants.kDotArgMethodName; } } if (isGlobalScope || !isInDotArgCall) { if (null != Properties.executingGraphNode) { core.ExecutingGraphnode = Properties.executingGraphNode; } } // Get the cached callsite, creates a new one for a first-time call ProtoCore.CallSite callsite = core.GetCallSite(core.ExecutingGraphnode, classIndex, fNode.name); Validity.Assert(null != callsite); StackFrameType type = StackFrameType.kTypeFunction; int blockDepth = 0; List<StackValue> registers = new List<StackValue>(); SaveRegisters(registers); // Comment Jun: the caller type is the current type in the stackframe StackFrameType callerType = (fepRun) ? StackFrameType.kTypeFunction : StackFrameType.kTypeLanguage; // Get the execution states of the current stackframe int currentScopeClass = ProtoCore.DSASM.Constants.kInvalidIndex; int currentScopeFunction = ProtoCore.DSASM.Constants.kInvalidIndex; GetCallerInformation(out currentScopeClass, out currentScopeFunction); List<bool> execStates = new List<bool>(); // // 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 // if (currentScopeFunction != ProtoCore.DSASM.Constants.kGlobalScope) { // Get the instruction stream where the current function resides in StackValue svCurrentFunctionBlockDecl = rmem.GetAtRelative(rmem.GetStackIndex(ProtoCore.DSASM.StackFrame.kFrameIndexFunctionBlock)); Validity.Assert(svCurrentFunctionBlockDecl.optype == AddressType.BlockIndex); AssociativeGraph.DependencyGraph depgraph = exe.instrStreamList[(int)svCurrentFunctionBlockDecl.opdata].dependencyGraph; // Allow only if this is a recursive call // It is recursive if the current function scope is equal to the function to call bool isRecursive = fNode.classScope == currentScopeClass && fNode.procId == currentScopeFunction; if (isRecursive) { // Get the graphnodes of the function from the instruction stream and retrive the execution states execStates = depgraph.GetExecutionStatesAtScope(currentScopeClass, currentScopeFunction); } } // Build the stackfram for the functioncall ProtoCore.DSASM.StackFrame stackFrame = new StackFrame(svThisPtr, ci, fi, returnAddr, blockDecl, blockCaller, callerType, type, blockDepth, framePointer, registers, execStates); FunctionCounter counter = FindCounter(functionIndex, classIndex, fNode.name); StackValue sv = StackValue.Null; if (core.Options.RecursionChecking) { //Do the recursion check before call if (counter.times < ProtoCore.DSASM.Constants.kRecursionTheshold) //&& counter.sharedCounter < ProtoCore.DSASM.Constants.kRepetationTheshold) { // Build a context object in JILDispatch and call the Dispatch if (counter.times == 0) { counter.times++; core.calledInFunction = true; } else if (counter.times >= 1) { if (fNode.name.ToCharArray()[0] != '%' && fNode.name.ToCharArray()[0] != '_' && !fNode.name.Equals(ProtoCore.DSASM.Constants.kDotMethodName) && core.calledInFunction) { counter.times++; } } if (core.Options.IDEDebugMode && core.ExecMode != InterpreterMode.kExpressionInterpreter) { bool isBaseCall = false; core.DebugProps.SetUpCallrForDebug(core, this, fNode, pc, isBaseCall, callsite, arguments, replicationGuides, stackFrame, dotCallDimensions, hasDebugInfo); } sv = callsite.JILDispatch(arguments, replicationGuides, stackFrame, core, runtimeContext); } else { FindRecursivePoints(); string message = String.Format(ProtoCore.RuntimeData.WarningMessage.kMethodStackOverflow, core.recursivePoint[0].name); core.RuntimeStatus.LogWarning(RuntimeData.WarningID.kInvalidRecursion, message); core.recursivePoint = new List<FunctionCounter>(); core.funcCounterTable = new List<FunctionCounter>(); sv = StackValue.Null; } } else { if (core.Options.IDEDebugMode && core.ExecMode != InterpreterMode.kExpressionInterpreter) { bool isBaseCall = false; if (core.ContinuationStruct.IsFirstCall) { core.DebugProps.SetUpCallrForDebug(core, this, fNode, pc, isBaseCall, callsite, arguments, replicationGuides, stackFrame, dotCallDimensions, hasDebugInfo); } else { core.DebugProps.SetUpCallrForDebug(core, this, fNode, pc, isBaseCall, callsite, core.ContinuationStruct.InitialArguments, replicationGuides, stackFrame, core.ContinuationStruct.InitialDotCallDimensions, hasDebugInfo); } } SX = svBlockDeclaration; stackFrame.SetAt(StackFrame.AbsoluteIndex.kRegisterSX, svBlockDeclaration); //Dispatch without recursion tracking explicitCall = false; isExplicitCall = explicitCall; #if __DEBUG_REPLICATE // TODO: This if block is currently executed only for a replicating function call in Debug Mode (including each of its continuations) // This condition will no longer be required once the same Dispatch function can decide whether to perform a fast dispatch (parallel mode) // OR a Serial/Debug mode dispatch, in which case this same block should work for Serial mode execution w/o the Debug mode check - pratapa if (core.Options.IDEDebugMode) { DebugFrame debugFrame = core.DebugProps.DebugStackFrame.Peek(); //if (debugFrame.IsReplicating || core.ContinuationStruct.IsContinuation) if (debugFrame.IsReplicating) { FunctionEndPoint fep = null; ContinuationStructure cs = core.ContinuationStruct; if (core.Options.ExecutionMode == ProtoCore.ExecutionMode.Serial || core.Options.IDEDebugMode) { // This needs to be done only for the initial argument arrays (ie before the first replicating call) - pratapa if(core.ContinuationStruct.IsFirstCall) { core.ContinuationStruct.InitialDepth = depth; core.ContinuationStruct.InitialPC = pc; core.ContinuationStruct.InitialArguments = arguments; core.ContinuationStruct.InitialDotCallDimensions = dotCallDimensions; for (int i = 0; i < arguments.Count; ++i) { GCUtils.GCRetain(arguments[i], core); } // Hardcoded core.ContinuationStruct.NextDispatchArgs.Add(StackValue.BuildInt(1)); } // The Resolve function is currently hard-coded as a place holder to test debugging replication - pratapa fep = callsite.ResolveForReplication(new ProtoCore.Runtime.Context(), arguments, replicationGuides, stackFrame, core, cs); // TODO: Refactor following steps into new function (ExecWithZeroRI + JILFep.Execute) to be called from here - pratapa // Get final FEP by calling SelectFinalFep() // Update DebugProps with final FEP // Call finalFEP.CoerceParameters() // Setup stackframe // Push Stackframe sv = callsite.ExecuteContinuation(fep, stackFrame, core); core.ContinuationStruct = cs; core.ContinuationStruct.IsFirstCall = true; } } else sv = callsite.JILDispatch(arguments, replicationGuides, stackFrame, core); } else #endif sv = callsite.JILDispatch(arguments, replicationGuides, stackFrame, core, runtimeContext); if (sv.optype == AddressType.ExplicitCall) { // // 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 = arguments; Properties.functionCallDotCallDimensions = dotCallDimensions; explicitCall = true; isExplicitCall = explicitCall; int entryPC = (int)sv.opdata; CallExplicit(entryPC); } #if __PROTOTYPE_ARRAYUPDATE_FUNCTIONCALL else { if (null != Properties.executingGraphNode) { Properties.executingGraphNode.ArrayPointer = sv; } } #endif } // 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 (core.Options.IDEDebugMode && core.ExecMode != InterpreterMode.kExpressionInterpreter) { core.DebugProps.RestoreCallrForNoBreak(core, fNode); } GCDotMethods(fNode.name, ref sv, dotCallDimensions, arguments); DecRefCounter(sv); if (sv.optype == AddressType.ArrayPointer) { // GCReleasePool.Add(sv); } isGlobScope = true; if (fNode.name.ToCharArray()[0] != '%' && fNode.name.ToCharArray()[0] != '_') { core.calledInFunction = false; //@TODO(Gemeng, Luke): Remove me //Console.WriteLine("flag changed \t" + core.calledInFunction); } } 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(); // 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); }
//Single function call /// <summary> /// Dispatch without replication /// </summary> private StackValue ExecWithZeroRI(List<FunctionEndPoint> functionEndPoint, ProtoCore.Runtime.Context c, List<StackValue> formalParameters, StackFrame stackFrame, Core core, FunctionGroup funcGroup, SingleRunTraceData previousTraceData, SingleRunTraceData newTraceData) { if(core.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, core); if (functionEndPoint == null) { core.RuntimeStatus.LogWarning(ProtoCore.RuntimeData.WarningID.kMethodResolutionFailure, "Function dispatch could not be completed {2EB39E1B-557C-4819-94D8-CF7C9F933E8A}"); return StackValue.Null; } if (core.Options.IDEDebugMode && core.ExecMode != ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter) { DebugFrame debugFrame = core.DebugProps.DebugStackFrame.Peek(); debugFrame.FinalFepChosen = finalFep; } List<StackValue> coercedParameters = finalFep.CoerceParameters(formalParameters, core); // Correct block id where the function is defined. StackValue funcBlock = stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kFunctionBlock); funcBlock.opdata = finalFep.BlockScope; stackFrame.SetAt(DSASM.StackFrame.AbsoluteIndex.kFunctionBlock, funcBlock); //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, core); 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, core, ret); } return ret; }
private StackValue CallrForMemberFunction(int classIndex, int procIndex, bool hasDebugInfo, ref bool isExplicitCall) { var arrayDim = rmem.Pop(); Validity.Assert(arrayDim.IsArrayDimension()); var blockIndex = rmem.Pop(); Validity.Assert(blockIndex.IsBlockIndex()); ClassNode classNode = exe.classTable.ClassNodes[classIndex]; ProcedureNode procNode = classNode.vtable.procList[procIndex]; // Get all arguments and replications var arguments = new List<StackValue>(); var repGuides = new List<List<ReplicationGuide>>(); PopArgumentsFromStack(procNode.argTypeList.Count, ref arguments, ref repGuides); arguments.Reverse(); repGuides = GetCachedReplicationGuides(core, arguments.Count + 1); StackValue lhs = rmem.Pop(); StackValue thisObject = lhs; if (StackUtils.IsArray(lhs)) { ArrayUtils.GetFirstNonArrayStackValue(lhs, ref thisObject, core); arguments.Insert(0, lhs); } if (!thisObject.IsObject() && !thisObject.IsArray()) { core.RuntimeStatus.LogWarning(WarningID.kDereferencingNonPointer, WarningMessage.kDeferencingNonPointer); return StackValue.Null; } var registers = new List<StackValue>(); SaveRegisters(registers); var stackFrame = new StackFrame(thisObject, // thisptr classIndex, // function class index procIndex, // function index pc + 1, // return address 0, // member function always declared in block 0 */ core.RunningBlock, // caller block fepRun ? StackFrameType.kTypeFunction : StackFrameType.kTypeLanguage, StackFrameType.kTypeFunction, // frame type 0, // block depth rmem.FramePointer, registers, new List<bool>()); var callsite = core.GetCallSite(core.ExecutingGraphnode, classIndex, procNode.name); Validity.Assert(null != callsite); bool setDebugProperty = core.Options.IDEDebugMode && core.ExecMode != InterpreterMode.kExpressionInterpreter && procNode != null; if (setDebugProperty) { core.DebugProps.SetUpCallrForDebug(core, this, procNode, pc, false, callsite, arguments, repGuides, stackFrame, null, hasDebugInfo); } SX = StackValue.BuildBlockIndex(0); stackFrame.SetAt(StackFrame.AbsoluteIndex.kRegisterSX, SX); StackValue sv = callsite.JILDispatch(arguments, repGuides, stackFrame, core, new Runtime.Context()); isExplicitCall = sv.IsExplicitCall(); if (isExplicitCall) { Properties.functionCallArguments = arguments; Properties.functionCallDotCallDimensions = new List<StackValue>(); int entryPC = (int)sv.opdata; CallExplicit(entryPC); } return sv; }
/// <summary> /// Dispatch without replication /// </summary> private StackValue ExecWithZeroRI(List<FunctionEndPoint> functionEndPoint, ProtoCore.Runtime.Context c, List<StackValue> formalParameters, StackFrame stackFrame, Core core, FunctionGroup funcGroup) { //@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, core); /*functionEndPoint = ResolveFunctionEndPointWithoutReplication(c,funcGroup, formalParameters, stackFrame, core);*/ if (functionEndPoint == null) { core.RuntimeStatus.LogWarning(ProtoCore.RuntimeData.WarningID.kMethodResolutionFailure, "Function dispatch could not be completed {2EB39E1B-557C-4819-94D8-CF7C9F933E8A}"); return StackUtils.BuildNull(); } if (core.Options.IDEDebugMode && core.ExecMode != ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter) { DebugFrame debugFrame = core.DebugProps.DebugStackFrame.Peek(); debugFrame.FinalFepChosen = finalFep; } //@TODO(Luke): Should this coerce? List<StackValue> coercedParameters = finalFep.CoerceParameters(formalParameters, core); // Correct block id where the function is defined. StackValue funcBlock = stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kFunctionBlock); funcBlock.opdata = finalFep.BlockScope; stackFrame.SetAt(DSASM.StackFrame.AbsoluteIndex.kFunctionBlock, funcBlock); StackValue ret = finalFep.Execute(c, coercedParameters, stackFrame, core); // An explicit call requires return coercion at the return instruction if (ret.optype != AddressType.ExplicitCall) { ret = PerformReturnTypeCoerce(finalFep, core, ret); } return ret; }
public StackValue ExecuteContinuation(FunctionEndPoint jilFep, StackFrame stackFrame, Core core) { // Pushing a dummy stackframe onto the Stack for the current fep int ci = -1; int fi = 0; // Hardcoded for Increment as member function if (jilFep.procedureNode == null) { ci = 14; jilFep.procedureNode = core.DSExecutable.classTable.ClassNodes[ci].vtable.procList[fi]; } Validity.Assert(jilFep.procedureNode != null); if (core.Options.IDEDebugMode) { DebugFrame debugFrame = core.DebugProps.DebugStackFrame.Peek(); debugFrame.FinalFepChosen = jilFep; } ProtoCore.DSASM.StackValue svThisPtr = stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kThisPtr); ProtoCore.DSASM.StackValue svBlockDecl = stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kFunctionBlock); int blockCaller = (int)stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kFunctionCallerBlock).opdata; int depth = (int)stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kStackFrameDepth).opdata; DSASM.StackFrameType type = (DSASM.StackFrameType)stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kStackFrameType).opdata; int locals = 0; int returnAddr = (int)stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kReturnAddress).opdata; int framePointer = core.Rmem.FramePointer; DSASM.StackFrameType callerType = (DSASM.StackFrameType)stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kCallerStackFrameType).opdata; StackValue svCallConvention = ProtoCore.DSASM.StackUtils.BuildNode(ProtoCore.DSASM.AddressType.CallingConvention, (long)ProtoCore.DSASM.CallingConvention.CallType.kExplicit); // Set TX register stackFrame.SetAt(DSASM.StackFrame.AbsoluteIndex.kRegisterTX, svCallConvention); // Set SX register stackFrame.SetAt(DSASM.StackFrame.AbsoluteIndex.kRegisterSX, svBlockDecl); List<ProtoCore.DSASM.StackValue> registers = new List<DSASM.StackValue>(); registers.AddRange(stackFrame.GetRegisters()); core.Rmem.PushStackFrame(svThisPtr, ci, fi, returnAddr, (int)svBlockDecl.opdata, blockCaller, callerType, type, depth, framePointer, registers, locals, 0); return StackUtils.BuildNode(AddressType.ExplicitCall, jilFep.procedureNode.pc); }