public Executive(Core core, bool isFep = false) { isExplicitCall = false; Validity.Assert(core != null); this.core = core; enableLogging = core.Options.Verbose; exe = core.DSExecutable; istream = null; fepRun = isFep; //executingGraphNode = null; //nodeExecutedSameTimes = new List<AssociativeGraph.GraphNode>(); Properties = new InterpreterProperties(); allSSA = new List<AssociativeGraph.GraphNode>(); rmem = core.Rmem; // Execute DS View VM Log // debugFlags = (int)DebugFlags.ENABLE_LOG; bounceType = CallingConvention.BounceType.kImplicit; // Execute DS Debug watch //debugFlags = (int)DebugFlags.ENABLE_LOG | (int)DebugFlags.SPAWN_DEBUGGER; }
private void RETURN_Handler(Instruction instruction) { isGlobScope = true; runtimeVerify(rmem.ValidateStackFrame()); int ptr = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexThisPtr).opdata; int ci = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexClass).opdata; int fi = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexFunction).opdata; int blockId = (int)SX.opdata; StackValue svBlockDecl = rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexRegisterSX); Validity.Assert(AddressType.BlockIndex == svBlockDecl.optype); blockId = (int)svBlockDecl.opdata; ProcedureNode procNode = GetProcedureNode(blockId, ci, fi); if (core.Options.ExecuteSSA) { if (core.Options.GCTempVarsOnDebug && core.Options.IDEDebugMode) { // GC anonymous variables in the return stmt if (null != Properties.executingGraphNode && !Properties.executingGraphNode.IsSSANode()) { GCAnonymousSymbols(Properties.executingGraphNode.symbolListWithinExpression); Properties.executingGraphNode.symbolListWithinExpression.Clear(); } } } pc = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexReturnAddress).opdata; executingBlock = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexFunctionCallerBlock).opdata; if (core.ExecMode != ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter) { ReturnSiteGC(blockId, ci, fi); } RestoreFromCall(); core.RunningBlock = executingBlock; // If we're returning from a block to a function, the instruction stream needs to be restored. StackValue sv = rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexRegisterTX); Validity.Assert(AddressType.CallingConvention == sv.optype); CallingConvention.CallType callType = (CallingConvention.CallType)sv.opdata; bool explicitCall = CallingConvention.CallType.kExplicit == callType; isExplicitCall = explicitCall; List<bool> execStateRestore = new List<bool>(); if (!core.Options.IDEDebugMode || core.ExecMode == InterpreterMode.kExpressionInterpreter) { // Get stack frame size int localCount = 0; int paramCount = 0; GetLocalAndParamCount(blockId, ci, fi, out localCount, out paramCount); // Retrieve the execution execution states int execstates = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexExecutionStates).opdata; if (execstates > 0) { int offset = ProtoCore.DSASM.StackFrame.kStackFrameSize + localCount + paramCount; for (int n = 0; n < execstates; ++n) { int relativeIndex = -offset - n - 1; StackValue svState = rmem.GetAtRelative(relativeIndex); Validity.Assert(svState.optype == AddressType.Boolean); execStateRestore.Add(svState.opdata == 0 ? false : true); } } // Pop the stackframe rmem.FramePointer = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexFramePointer).opdata; // Get the size of the stackframe and all variable size contents (local, args and exec states) int stackFrameSize = ProtoCore.DSASM.StackFrame.kStackFrameSize + localCount + paramCount + execstates; rmem.PopFrame(stackFrameSize); if (core.ExecMode != InterpreterMode.kExpressionInterpreter) { // Restoring the registers require the current frame pointer of the stack frame RestoreRegistersFromStackFrame(); bounceType = (ProtoCore.DSASM.CallingConvention.BounceType)TX.opdata; } } terminate = !explicitCall; // Comment Jun: Dispose calls are always implicit and need to terminate // TODO Jun: This instruction should not know about dispose bool isDispose = CoreUtils.IsDisposeMethod(procNode.name); if (isDispose) { terminate = true; } // Let the return graphNode always be active if (null != Properties.executingGraphNode) { Properties.executingGraphNode.isDirty = true; } Properties = PopInterpreterProps(); if (explicitCall) { bool wasDebugPropsPopped = false; if (!isDispose) { wasDebugPropsPopped = DebugReturn(procNode, pc); } // This condition should only be reached in the following cases: // 1. Debug StepOver or External Function call in non-replicating mode // 2. Normal execution in Serial (explicit call), non-replicating mode if (!wasDebugPropsPopped) { RX = CallSite.PerformReturnTypeCoerce(procNode, core, RX); // Comment Jun: For explicit calls, we need to manually GC decrement the arguments passed into the function // These arguments were GC incremented on callr for (int i = 0; i < Properties.functionCallArguments.Count; ++i) { GCUtils.GCRelease(Properties.functionCallArguments[i], core); } StackValue svRet = RX; GCDotMethods(procNode.name, ref svRet, Properties.functionCallDotCallDimensions, Properties.functionCallArguments); DecRefCounter(svRet); RX = svRet; } } // Restore the execution states if (execStateRestore.Count > 0) { // Now that the stack frame is popped off, we can retrieve the returned scope // Get graphnodes at the current scope after the return int currentScopeClass = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexClass).opdata; int currentScopeFunction = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexFunction).opdata; bool isReturningFromRecursiveCall = procNode.procId == currentScopeFunction; if (isReturningFromRecursiveCall) { // Since there are execution states retrieved from the stack frame, // this means that we must be returning to a function and not the global scope Validity.Assert(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; List<AssociativeGraph.GraphNode> graphNodesInScope = depgraph.GetGraphNodesAtScope(currentScopeClass, currentScopeFunction); Validity.Assert(execStateRestore.Count == graphNodesInScope.Count); for (int n = 0; n < execStateRestore.Count; ++n) { graphNodesInScope[n].isDirty = execStateRestore[n]; } } } return; }
private void THROW_Handler(Instruction instruction) { #if ENABLE_EXCEPTION_HANDLING runtimeVerify(ProtoCore.DSASM.AddressType.BlockIndex == instruction.op1.optype); int blockId = (int)instruction.op1.opdata; runtimeVerify(ProtoCore.DSASM.AddressType.ClassIndex == instruction.op2.optype); int classScope = (int)instruction.op2.opdata; runtimeVerify(ProtoCore.DSASM.AddressType.FunctionIndex == instruction.op3.optype); int functionScope = (int)instruction.op3.opdata; StackValue exceptionValue = LX; ProtoCore.Exceptions.ExceptionContext context = new Exceptions.ExceptionContext(); context.pc = pc; context.codeBlockId = blockId; context.functionScope = functionScope; context.classScope = classScope; switch (exceptionValue.optype) { case AddressType.Int: context.typeUID = (int)ProtoCore.PrimitiveType.kTypeInt; break; case AddressType.Double: context.typeUID = (int)ProtoCore.PrimitiveType.kTypeDouble; break; case AddressType.Boolean: context.typeUID = (int)ProtoCore.PrimitiveType.kTypeBool; break; case AddressType.Pointer: context.typeUID = (int)exceptionValue.metaData.type; break; default: context.typeUID = (int)ProtoCore.PrimitiveType.kTypeVar; break; } // Walk through exception chain, a.k.a. 1st hand exception // handling core.ExceptionHandlingManager.HandleFirstHandException(context); // The exception can be handled in current scope, so simply jmp to // the corresponding catch block int newpc = ProtoCore.DSASM.Constants.kInvalidIndex; if (core.ExceptionHandlingManager.CanHandleIt(ref newpc)) { pc = newpc; core.ExceptionHandlingManager.SetHandled(); } else { RX = LX; } if (core.ExceptionHandlingManager.IsStackUnwinding) { while (core.stackActiveExceptionRegistration.Count > 1) { StackValue svType = rmem.GetAtRelative(StackFrame.kFrameIndexStackFrameType); StackFrameType type = (StackFrameType)svType.opdata; if (StackFrameType.kTypeLanguage == type) { RestoreFromBounce(); rmem.FramePointer = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexFramePointer).opdata; rmem.PopFrame(ProtoCore.DSASM.StackFrame.kStackFrameSize); // Restoring the registers require the current frame pointer of the stack frame RestoreRegistersFromStackFrame(); bounceType = (ProtoCore.DSASM.CallingConvention.BounceType)TX.opdata; core.ExceptionHandlingManager.CurrentActiveRegistration = core.stackActiveExceptionRegistration.Pop(); #region __MERGE_WITH_STACKUNWIND // The excecution of last langage block is interrupted // abnormally because of stack unwinding, so we need to // run GC to reclaim those allocated memory. GCCodeBlock(core.RunningBlock); newpc = ProtoCore.DSASM.Constants.kInvalidIndex; if (core.ExceptionHandlingManager.CanHandleIt(ref newpc)) { LX = RX; pc = newpc; core.ExceptionHandlingManager.SetHandled(); break; } // else cannot handle in this scope, so in the next // loop of Execute(), current executive will be ; // ended and returns to the last scope, continues // stack unwinding int origRunningBlock = executingBlock; core.RunningBlock = origRunningBlock; #endregion } else { RestoreFromCall(); int ci = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexClass).opdata; int fi = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexFunction).opdata; int localCount = 0; int paramCount = 0; GetLocalAndParamCount(executingBlock, ci, fi, out localCount, out paramCount); rmem.FramePointer = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexFramePointer).opdata; rmem.PopFrame(ProtoCore.DSASM.StackFrame.kStackFrameSize + localCount + paramCount); } } } return; #else throw new NotImplementedException(); #endif }
private void RETC_Handler(Instruction instruction) { runtimeVerify(rmem.ValidateStackFrame()); RX = rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexThisPtr); int ci = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexClass).opdata; int fi = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexFunction).opdata; pc = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexReturnAddress).opdata; // block id is used in ReturnSiteGC to get the procedure node if it is not a member function // not meaningful here, because we are inside a constructor int blockId = (int)SX.opdata; if (core.ExecMode != ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter) { ReturnSiteGC(blockId, ci, fi); } RestoreFromCall(); core.RunningBlock = executingBlock; // If we're returning from a block to a function, the instruction stream needs to be restored. StackValue sv = rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexRegisterTX); Validity.Assert(AddressType.CallingConvention == sv.optype); CallingConvention.CallType callType = (CallingConvention.CallType)sv.opdata; bool explicitCall = CallingConvention.CallType.kExplicit == callType || CallingConvention.CallType.kExplicitBase == callType; isExplicitCall = explicitCall; if (!core.Options.IDEDebugMode || core.ExecMode == InterpreterMode.kExpressionInterpreter) { int localCount = 0; int paramCount = 0; GetLocalAndParamCount(blockId, ci, fi, out localCount, out paramCount); rmem.FramePointer = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexFramePointer).opdata; rmem.PopFrame(ProtoCore.DSASM.StackFrame.kStackFrameSize + localCount + paramCount); if (core.ExecMode != InterpreterMode.kExpressionInterpreter) { // Restoring the registers require the current frame pointer of the stack frame RestoreRegistersFromStackFrame(); bounceType = (ProtoCore.DSASM.CallingConvention.BounceType)TX.opdata; } } terminate = !explicitCall; Properties = PopInterpreterProps(); ProcedureNode procNode = GetProcedureNode(blockId, ci, fi); if (explicitCall) { //RX = CallSite.PerformReturnTypeCoerce(procNode, core, RX); bool wasDebugPropsPopped = DebugReturn(procNode, pc); // Comment Jun: For explicit calls, we need to manually GC decrement the arguments. // These arguments were GC incremented on callr if (!wasDebugPropsPopped) //if (!core.Options.IDEDebugMode || core.ExecMode == ExecutionMode.kExpressionInterpreter) { for (int i = 0; i < Properties.functionCallArguments.Count; ++i) { GCUtils.GCRelease(Properties.functionCallArguments[i], core); } } if (CallingConvention.CallType.kExplicitBase != callType) { //if (!core.Options.IDEDebugMode || core.ExecMode == ExecutionMode.kExpressionInterpreter) if (!wasDebugPropsPopped) { DecRefCounter(RX); } } } return; }
private void RETB_Handler(Instruction instruction) { if (core.ExecMode != InterpreterMode.kExpressionInterpreter) { core.Rmem.PopConstructBlockId(); } if (!core.Options.IsDeltaExecution || (core.Options.IsDeltaExecution && 0 != core.RunningBlock)) { GCCodeBlock(core.RunningBlock); } if (ProtoCore.DSASM.CallingConvention.BounceType.kExplicit == bounceType) { RestoreFromBounce(); core.RunningBlock = executingBlock; } if (ProtoCore.DSASM.CallingConvention.BounceType.kImplicit == bounceType) { pc = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexReturnAddress).opdata; terminate = true; } ProtoCore.DSASM.StackFrameType type = StackFrameType.kTypeLanguage; // Comment Jun: Just want to see if this is the global rerb, in which case we dont retrieve anything //if (executingBlock > 0) { StackValue svCallerType = rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexCallerStackFrameType); type = (ProtoCore.DSASM.StackFrameType)svCallerType.opdata; } // Pop the frame as we are adding stackframes for language blocks as well - pratapa // Do not do this for the final Retb //if (core.RunningBlock != 0) if (!core.Options.IDEDebugMode || core.ExecMode == InterpreterMode.kExpressionInterpreter) { rmem.FramePointer = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexFramePointer).opdata; rmem.PopFrame(ProtoCore.DSASM.StackFrame.kStackFrameSize); if (bounceType == CallingConvention.BounceType.kExplicit) { // Restoring the registers require the current frame pointer of the stack frame RestoreRegistersFromStackFrame(); bounceType = (ProtoCore.DSASM.CallingConvention.BounceType)TX.opdata; #if ENABLE_EXCEPTION_HANDLING core.ExceptionHandlingManager.CurrentActiveRegistration = core.stackActiveExceptionRegistration.Pop(); if (core.ExceptionHandlingManager.IsStackUnwinding) { #region __MERGE_WITH_STACKUNWIND // The excecution of last langage block is interrupted // abnormally because of stack unwinding, so we need to // run GC to reclaim those allocated memory. GCCodeBlock(core.RunningBlock); int newpc = ProtoCore.DSASM.Constants.kInvalidIndex; if (core.ExceptionHandlingManager.CanHandleIt(ref newpc)) { LX = RX; pc = newpc; core.ExceptionHandlingManager.SetHandled(); } // else cannot handle in this scope, so in the next // loop of Execute(), current executive will be ; // ended and returns to the last scope, continues // stack unwinding int origRunningBlock = executingBlock; core.RunningBlock = origRunningBlock; #endregion } else { DecRefCounter(RX); } #else DecRefCounter(RX); #endif } } else { DecRefCounter(RX); } if (type == StackFrameType.kTypeFunction) { // Comment Jun: // Consider moving this to a restore to function method // If this language block was called explicitly, only then do we need to restore the instruction stream if (bounceType == CallingConvention.BounceType.kExplicit) { // If we're returning from a block to a function, the instruction stream needs to be restored. StackValue sv = rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexRegisterTX); Validity.Assert(AddressType.CallingConvention == sv.optype); CallingConvention.CallType callType = (CallingConvention.CallType)sv.opdata; if (CallingConvention.CallType.kExplicit == callType) { int callerblock = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexFunctionBlock).opdata; istream = exe.instrStreamList[callerblock]; } } } Properties = PopInterpreterProps(); return; }
private void BOUNCE_Handler(Instruction instruction) { // We disallow language blocks inside watch window currently - pratapa Validity.Assert(DSASM.InterpreterMode.kExpressionInterpreter != Core.ExecMode); runtimeVerify(ProtoCore.DSASM.AddressType.BlockIndex == instruction.op1.optype); int blockId = (int)instruction.op1.opdata; // 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 core.DebugProps.CurrentBlockId = blockId; runtimeVerify(ProtoCore.DSASM.AddressType.Int == instruction.op2.optype); int entrypoint = (int)instruction.op2.opdata; ProtoCore.Runtime.Context context = new ProtoCore.Runtime.Context(); // TODO(Jun/Jiong): Considering store the orig block id to stack frame int origRunningBlock = core.RunningBlock; core.RunningBlock = blockId; core.Rmem = rmem; if (core.ExecMode != InterpreterMode.kExpressionInterpreter) { core.Rmem.PushConstructBlockId(blockId); } #if ENABLE_EXCEPTION_HANDLING core.stackActiveExceptionRegistration.Push(core.ExceptionHandlingManager.CurrentActiveRegistration); #endif int ci = ProtoCore.DSASM.Constants.kInvalidIndex; int fi = ProtoCore.DSASM.Constants.kInvalidIndex; if (rmem.Stack.Count >= ProtoCore.DSASM.StackFrame.kStackFrameSize) { StackValue sci = rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexClass); StackValue sfi = rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexFunction); if (sci.optype == AddressType.Int && sfi.optype == AddressType.Int) { ci = (int)sci.opdata; fi = (int)sfi.opdata; } } #if ENABLE_EXCEPTION_HANDLING core.ExceptionHandlingManager.SwitchContextTo(blockId, fi, ci, pc); #endif StackValue svThisPtr = ProtoCore.DSASM.StackValue.BuildPointer(ProtoCore.DSASM.Constants.kInvalidPointer); int returnAddr = pc + 1; Validity.Assert(ProtoCore.DSASM.Constants.kInvalidIndex != executingBlock); //int blockDecl = executingBlock; int blockDecl = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexFunctionBlock).opdata; int blockCaller = executingBlock; StackFrameType type = StackFrameType.kTypeLanguage; int depth = (int)rmem.GetAtRelative(StackFrame.kFrameIndexStackFrameDepth).opdata; int framePointer = core.Rmem.FramePointer; // Comment Jun: Use the register TX to store explicit/implicit bounce state bounceType = ProtoCore.DSASM.CallingConvention.BounceType.kExplicit; TX = StackValue.BuildCallingConversion((int)ProtoCore.DSASM.CallingConvention.BounceType.kExplicit); List<StackValue> registers = new List<StackValue>(); SaveRegisters(registers); StackFrameType callerType = (fepRun) ? StackFrameType.kTypeFunction : StackFrameType.kTypeLanguage; if (core.Options.IDEDebugMode && core.ExecMode != InterpreterMode.kExpressionInterpreter) { // Comment Jun: Temporarily disable debug mode on bounce //Validity.Assert(false); //Validity.Assert(core.Breakpoints != null); //blockDecl = blockCaller = core.DebugProps.CurrentBlockId; core.DebugProps.SetUpBounce(this, blockCaller, returnAddr); StackFrame stackFrame = new StackFrame(svThisPtr, ci, fi, returnAddr, blockDecl, blockCaller, callerType, type, depth + 1, framePointer, registers, null); ProtoCore.Language bounceLangauge = exe.instrStreamList[blockId].language; BounceExplicit(blockId, 0, bounceLangauge, stackFrame, core.Breakpoints); } else //if (core.Breakpoints == null) { StackFrame stackFrame = new StackFrame(svThisPtr, ci, fi, returnAddr, blockDecl, blockCaller, callerType, type, depth + 1, framePointer, registers, null); ProtoCore.Language bounceLangauge = exe.instrStreamList[blockId].language; BounceExplicit(blockId, 0, bounceLangauge, stackFrame); } return; }
// This will be called only at the time of creation of the main interpreter in the explicit case OR // for every implicit function call (like in replication) OR // for every implicit bounce (like in dynamic lang block in inline condition) OR // for a Debug Resume from a breakpoint public void Execute(int exeblock, int entry, List<Instruction> breakpoints, Language language = Language.kInvalid) { // TODO Jun: Call RestoreFromBounce here? StackValue svType = rmem.GetAtRelative(StackFrame.kFrameIndexStackFrameType); StackFrameType type = (StackFrameType)svType.opdata; if (StackFrameType.kTypeLanguage == type || StackFrameType.kTypeFunction == type) { ResumeRegistersFromStack(); bounceType = (ProtoCore.DSASM.CallingConvention.BounceType)TX.opdata; } SetupExecutive(exeblock, entry, language, breakpoints); bool debugRun = (0 != (debugFlags & (int)DebugFlags.SPAWN_DEBUGGER)); if (!fepRun || fepRun && debugRun) { logVMMessage("Start JIL Execution - " + CoreUtils.GetLanguageString(language)); } core.DebugProps.isResume = false; while (!terminate) { // This will be true only for inline conditions in Associative blocks if (core.DebugProps.InlineConditionOptions.isInlineConditional == true && core.DebugProps.InlineConditionOptions.instructionStream == exeblock && core.DebugProps.InlineConditionOptions.endPc == pc) { // turn off inline conditional flag { core.DebugProps.InlineConditionOptions.isInlineConditional = false; core.DebugProps.InlineConditionOptions.startPc = Constants.kInvalidIndex; core.DebugProps.InlineConditionOptions.endPc = Constants.kInvalidIndex; core.DebugProps.InlineConditionOptions.instructionStream = 0; } // if no longer inside a replicated/external function call, restore breakpoints if (!core.DebugProps.DebugStackFrameContains(DebugProperties.StackFrameFlagOptions.IsReplicating) && !core.DebugProps.DebugStackFrameContains(DebugProperties.StackFrameFlagOptions.IsExternalFunction)) { if (core.DebugProps.InlineConditionOptions.ActiveBreakPoints.Count > 0) { core.Breakpoints.Clear(); core.Breakpoints.AddRange(core.DebugProps.InlineConditionOptions.ActiveBreakPoints); core.DebugProps.InlineConditionOptions.ActiveBreakPoints.Clear(); } } } List<Instruction> instructions = istream.instrList; // Execute the instruction! Instruction executeInstruction = instructions[pc]; Exec(instructions[pc]); bool restoreInstructionStream = executeInstruction.opCode == OpCode.CALLR || executeInstruction.opCode == OpCode.RETURN || executeInstruction.opCode == OpCode.RETC; if (restoreInstructionStream && isExplicitCall) { // The instruction stream list is updated on callr instructions = istream.instrList; exeblock = executingBlock; core.DebugProps.CurrentBlockId = exeblock; } // Disabling support for stepping into replicating function calls temporarily - pratapa // Check if the current instruction is a return from a function call or constructor DebugFrame tempFrame = null; if (!isExplicitCall && (instructions[core.DebugProps.DebugEntryPC].opCode == OpCode.RETURN || instructions[core.DebugProps.DebugEntryPC].opCode == OpCode.RETC)) { int ci, fi; bool isReplicating; DebugFrame debugFrame = null; DebugReturnFromFunctionCall(pc, ref exeblock, out ci, out fi, out isReplicating, out debugFrame); instructions = istream.instrList; executingBlock = exeblock; core.DebugProps.CurrentBlockId = exeblock; } else if (executeInstruction.opCode == OpCode.RETB) { tempFrame = core.DebugProps.DebugStackFrame.Peek(); RestoreDebugPropsOnReturnFromLangBlock(ref exeblock, ref instructions); // TODO: If return from previous lang block calls "_Dispose", and we have stepped into it, // we need to restore the calling stackframe - pratapa if (tempFrame.IsDisposeCall) { // TODO: If we have stepped inside _Dispose and are resuming from it - pratapa if (!terminate) { // 1. Call everything after GC in OpCode.RETB // 2. Call RestoreDebugPropsOnReturnFromLangBlock() for caller lang block // 3. Return address from _Dispose is one more than the correct value and therefore needs to be fixed } // TODO: This works assuming debugging inside _Dispose functions is disabled // ie stepping over _Dispose - pratapa core.DebugProps.DebugEntryPC = core.DebugProps.ReturnPCFromDispose; break; } else { core.DebugProps.DebugEntryPC = pc; } // Comment Jun: On explictit bounce, only on retb we update the executing block // as the block scope has already change by returning to the caller block executingBlock = exeblock; core.RunningBlock = exeblock; } else { core.DebugProps.DebugEntryPC = pc; } DebugFrame frame = core.DebugProps.DebugStackFrame.Peek(); if (frame.IsInlineConditional) { // The reference count of RX has been decreased in RETB // instruction for inline conditional statement. GCRetain(RX); RestoreDebugPropsOnReturnFromBuiltIns(ref exeblock, ref instructions); core.DebugProps.DebugEntryPC = pc; } core.Rmem = rmem; bool terminateExec = HandleBreakpoint(breakpoints, instructions, pc, exeblock); if (terminateExec) { break; } } if (!fepRun || fepRun && debugRun) { logVMMessage("End JIL Execution - " + CoreUtils.GetLanguageString(language)); } }
void RestoreDebugPropsOnReturnFromLangBlock(ref int exeblock, ref List<Instruction> instructions) { // On the new stack frame, this dependency has already been executed at retb in RestoreFromBounce //XLangUpdateDependencyGraph(exeblock); Validity.Assert(core.DebugProps.DebugStackFrame.Count > 0); { // Restore fepRun DebugFrame debugFrame = core.DebugProps.DebugStackFrame.Pop(); bool isResume = debugFrame.IsResume; if (isResume) { if (core.DebugProps.DebugStackFrame.Count > 1) { DebugFrame frame = core.DebugProps.DebugStackFrame.Peek(); frame.IsResume = true; } terminate = false; // Restore registers except RX on popping of language stackframe ResumeRegistersFromStackExceptRX(); } // Restore return address and lang block pc = (int)rmem.GetAtRelative(StackFrame.kFrameIndexReturnAddress).opdata; exeblock = (int)rmem.GetAtRelative(StackFrame.kFrameIndexFunctionCallerBlock).opdata; istream = exe.instrStreamList[exeblock]; instructions = istream.instrList; executingLanguage = istream.language; Properties.executingGraphNode = debugFrame.ExecutingGraphNode; // Pop language stackframe as this is not allowed in Retb in debug mode rmem.FramePointer = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexFramePointer).opdata; rmem.PopFrame(ProtoCore.DSASM.StackFrame.kStackFrameSize); ResumeRegistersFromStackExceptRX(); bounceType = (ProtoCore.DSASM.CallingConvention.BounceType)TX.opdata; } if (pc < 0) { throw new ProtoCore.Exceptions.EndOfScript(); } }
bool RestoreDebugPropsOnReturnFromFunctionCall(ref int exeblock, ref List<Instruction> instructions, out int ci, out int fi, out bool isReplicating, out DebugFrame debugFrame) { // // TODO: Aparajit, Jun - Determine an alternative to the waspopped flag // bool waspopped = false; Validity.Assert(core.DebugProps.DebugStackFrame.Count > 0); debugFrame = core.DebugProps.DebugStackFrame.Peek(); isReplicating = debugFrame.IsReplicating; #if !__DEBUG_REPLICATE if (!isReplicating) #endif { bool isResume = debugFrame.IsResume; // Comment Jun: Since we dont step into _Dispose() calls, then its debugframe should not be popped off here. bool isDispose = debugFrame.IsDisposeCall; // RestoreCallrForNoBreak and PerformReturnTypeCoerce are NOT called if this is true // or for base class ctor calls and therefore need to be taken care of here if ((isResume || debugFrame.IsBaseCall) && !isDispose) { debugFrame = core.DebugProps.DebugStackFrame.Pop(); waspopped = true; if (isResume) { if (core.DebugProps.DebugStackFrame.Count > 1) { DebugFrame frame = core.DebugProps.DebugStackFrame.Peek(); frame.IsResume = true; } } #if __DEBUG_REPLICATE // Return type coercion and function call GC for replicating case takes place separately // in SerialReplication() when ContinuationStruct.Done == true - pratapa if (!isReplicating) #endif { DebugPerformCoercionAndGC(debugFrame); } // Restore registers except RX on popping of function stackframe ResumeRegistersFromStackExceptRX(); terminate = false; } Properties.executingGraphNode = debugFrame.ExecutingGraphNode; if (core.DebugProps.RunMode.Equals(Runmode.StepOut) && pc == core.DebugProps.StepOutReturnPC) { core.Breakpoints.Clear(); core.Breakpoints.AddRange(core.DebugProps.AllbreakPoints); } } // Restore return address and lang block pc = (int)rmem.GetAtRelative(StackFrame.kFrameIndexReturnAddress).opdata; exeblock = (int)rmem.GetAtRelative(StackFrame.kFrameIndexFunctionCallerBlock).opdata; istream = exe.instrStreamList[exeblock]; instructions = istream.instrList; executingLanguage = istream.language; ci = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexClass).opdata; fi = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexFunction).opdata; int localCount = 0; int paramCount = 0; int blockId = (int)rmem.GetAtRelative(StackFrame.kFrameIndexFunctionBlock).opdata; GetLocalAndParamCount(blockId, ci, fi, out localCount, out paramCount); // Pop function stackframe as this is not allowed in Ret/Retc in debug mode rmem.FramePointer = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexFramePointer).opdata; rmem.PopFrame(ProtoCore.DSASM.StackFrame.kStackFrameSize + localCount + paramCount); ResumeRegistersFromStackExceptRX(); //StackValue svFrameType = rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexCallerStackFrameType); StackValue svFrameType = rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexStackFrameType); StackFrameType frametype = (StackFrameType)svFrameType.opdata; if (frametype == StackFrameType.kTypeLanguage) { bounceType = (ProtoCore.DSASM.CallingConvention.BounceType)TX.opdata; } return waspopped; }
private void RETURN_Handler(Instruction instruction) { isGlobScope = true; runtimeVerify(rmem.ValidateStackFrame()); int ptr = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexThisPtr).opdata; int ci = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexClass).opdata; int fi = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexFunction).opdata; int blockId = (int)SX.opdata; StackValue svBlockDecl = rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexRegisterSX); Validity.Assert(AddressType.BlockIndex == svBlockDecl.optype); blockId = (int)svBlockDecl.opdata; ProcedureNode procNode = GetProcedureNode(blockId, ci, fi); pc = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexReturnAddress).opdata; executingBlock = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexFunctionCallerBlock).opdata; if (core.ExecMode != ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter) { ReturnSiteGC(blockId, ci, fi); } RestoreFromCall(); core.RunningBlock = executingBlock; // If we're returning from a block to a function, the instruction stream needs to be restored. StackValue sv = rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexRegisterTX); Validity.Assert(AddressType.CallingConvention == sv.optype); CallingConvention.CallType callType = (CallingConvention.CallType)sv.opdata; bool explicitCall = CallingConvention.CallType.kExplicit == callType; isExplicitCall = explicitCall; if (!core.Options.IDEDebugMode || core.ExecMode == InterpreterMode.kExpressionInterpreter) { int localCount = 0; int paramCount = 0; GetLocalAndParamCount(blockId, ci, fi, out localCount, out paramCount); rmem.FramePointer = (int)rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexFramePointer).opdata; rmem.PopFrame(ProtoCore.DSASM.StackFrame.kStackFrameSize + localCount + paramCount); if (core.ExecMode != InterpreterMode.kExpressionInterpreter) { // Restoring the registers require the current frame pointer of the stack frame RestoreRegistersFromStackFrame(); bounceType = (ProtoCore.DSASM.CallingConvention.BounceType)TX.opdata; } } terminate = !explicitCall; // Comment Jun: Dispose calls are always implicit and need to terminate // TODO Jun: This instruction should not know about dispose bool isDispose = procNode.name.Equals(ProtoCore.DSDefinitions.Kw.kw_Dispose); if (isDispose) { terminate = true; } // Let the return graphNode always be active if (null != Properties.executingGraphNode) { Properties.executingGraphNode.isDirty = true; } Properties = PopInterpreterProps(); if (explicitCall) { bool wasDebugPropsPopped = false; if (!isDispose) { wasDebugPropsPopped = DebugReturn(procNode, pc); } // This condition should only be reached in the following cases: // 1. Debug StepOver or External Function call in non-replicating mode // 2. Normal execution in Serial (explicit call), non-replicating mode if (!wasDebugPropsPopped) { RX = CallSite.PerformReturnTypeCoerce(procNode, core, RX); // Comment Jun: For explicit calls, we need to manually GC decrement the arguments passed into the function // These arguments were GC incremented on callr for (int i = 0; i < Properties.functionCallArguments.Count; ++i) { GCUtils.GCRelease(Properties.functionCallArguments[i], core); } StackValue svRet = RX; GCDotMethods(procNode.name, ref svRet, Properties.functionCallDotCallDimensions, Properties.functionCallArguments); DecRefCounter(svRet); RX = svRet; } } return; }