public static string Run(string source, ref StringBuilder emitter) { var context = new Runtime.Context(); var emitter2 = emitter; var astBuilder = new Compiler.AstGenerator(); var etGenerator = new Compiler.EtGenerator(); var scope = Scope.CreateGlobal(context); Func<object, object> emit = (obj) => { emitter2.Append(JsTypeConverter.ToString(obj)); return null; }; scope.Global( "emit", emit ); context.SetupGlobals(scope); var astNodes = astBuilder.Build(source); var compiled = etGenerator.Build(astNodes, context); compiled(scope); return emitter.ToString(); }
public static string Run(string source) { var emitter = new StringBuilder(); var context = new Runtime.Context(); var astBuilder = new Compiler.AstGenerator(); var etGenerator = new Compiler.EtGenerator(); var scope = Scope.CreateGlobal(context); Func<object, object> emit = (obj) => { return emitter.Append(JsTypeConverter.ToString(obj)); }; scope.Global("emit", emit); Action<object> assert = (obj) => { Assert.AreEqual((object)true, obj); }; scope.Global("assert", assert); Action<object, object, object> assertEqual = (a, b, msg) => { Assert.AreEqual(a, b, (string)msg); }; scope.Global("assertEqual", assertEqual); Action<object, object> assertFalse = (obj, msg) => { Assert.IsFalse((bool)obj, (string)msg); }; scope.Global("assertFalse", assertFalse); Action<object, object> assertTrue = (obj, msg) => { Assert.IsTrue((bool)obj, (string)msg); }; scope.Global("assertTrue", assertTrue); context.SetupGlobals(scope); var astNodes = astBuilder.Build(source); var compiled = etGenerator.Build(astNodes, context); compiled(scope); return emitter.ToString(); }
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 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.opdata; if (!isDynamicCall) { StackValue svType = rmem.Pop(); runtimeVerify(svType.IsStaticType); } ProcedureNode fNode = null; // Pop off number of dimensions indexed into this function call // f()[0][1] -> 2 dimensions StackValue svDim = rmem.Pop(); runtimeVerify(svDim.IsArrayDimension); 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.kCallingConstructorOnInstance, message); return StackValue.Null; } } else { // Global function fNode = exe.procedureTable[blockDeclId].Procedures[functionIndex]; } // Build the arg values list var arguments = new List<StackValue>(); var replicationGuides = new List<List<ReplicationGuide>>(); // 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.opdata > 0) { var dimArray = rmem.Heap.ToHeapObject<DSArray>(svArrayPtrDimesions); Validity.Assert(dimArray.Count == svDimensionCount.opdata); dotCallDimensions.AddRange(dimArray.Values); } } else { PopArgumentsFromStack(fNode.ArgumentTypes.Count, ref arguments, ref replicationGuides); } replicationGuides.Reverse(); arguments.Reverse(); 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); } // 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.IsPointer) { string message = String.Format(Resources.kInvokeMethodOnInvalidObject, fNode.Name); runtimeCore.RuntimeStatus.LogWarning(WarningID.kDereferencingNonPointer, 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.opdata != 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 = new List<StackValue>(); SaveRegisters(registers); // 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.kTypeFunction : StackFrameType.kTypeLanguage, StackFrameType.kTypeFunction, 0, rmem.FramePointer, registers, null); FunctionCounter counter = FindCounter(functionIndex, classIndex, fNode.Name); StackValue sv = StackValue.Null; if (runtimeCore.Options.IDEDebugMode && runtimeCore.Options.RunMode != InterpreterMode.kExpressionInterpreter) { 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); } } SX = StackValue.BuildBlockIndex(blockDeclId); stackFrame.SX = SX; //Dispatch without recursion tracking explicitCall = false; IsExplicitCall = explicitCall; sv = callsite.JILDispatch(arguments, replicationGuides, 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 = arguments; Properties.functionCallDotCallDimensions = dotCallDimensions; explicitCall = true; IsExplicitCall = explicitCall; int entryPC = (int)sv.opdata; CallExplicit(entryPC); } // 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.kExpressionInterpreter) { runtimeCore.DebugProps.RestoreCallrForNoBreak(runtimeCore, fNode); } GCDotMethods(fNode.Name, ref sv, dotCallDimensions, arguments); if (fNode.Name.ToCharArray()[0] != '%' && fNode.Name.ToCharArray()[0] != '_') { exe.calledInFunction = false; } } return sv; }
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.opdata; if (!isDynamicCall) { StackValue svType = rmem.Pop(); runtimeVerify(svType.IsStaticType); } ProcedureNode fNode = null; // Pop off number of dimensions indexed into this function call // f()[0][1] -> 2 dimensions StackValue svDim = rmem.Pop(); runtimeVerify(svDim.IsArrayDimension); bool isCallingMemberFunction = Constants.kInvalidIndex != classIndex; if (isCallingMemberFunction) { fNode = exe.classTable.ClassNodes[classIndex].ProcTable.procList[functionIndex]; if (depth > 0 && fNode.IsConstructor) { string message = String.Format(Resources.KCallingConstructorOnInstance, fNode.Name); runtimeCore.RuntimeStatus.LogWarning(WarningID.kCallingConstructorOnInstance, message); return StackValue.Null; } } else { // Global function fNode = exe.procedureTable[blockDeclId].procList[functionIndex]; } // Build the arg values list var arguments = new List<StackValue>(); var replicationGuides = new List<List<ReplicationGuide>>(); // 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.opdata > 0) { var dimArray = rmem.Heap.ToHeapObject<DSArray>(svArrayPtrDimesions); Validity.Assert(dimArray.Count == svDimensionCount.opdata); dotCallDimensions.AddRange(dimArray.Values); } } else { PopArgumentsFromStack(fNode.ArgumentTypes.Count, ref arguments, ref replicationGuides); } replicationGuides.Reverse(); arguments.Reverse(); 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); } // 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.IsPointer) { string message = String.Format(Resources.kInvokeMethodOnInvalidObject, fNode.Name); runtimeCore.RuntimeStatus.LogWarning(WarningID.kDereferencingNonPointer, 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.opdata != 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 = new List<StackValue>(); SaveRegisters(registers); // 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.kTypeFunction : StackFrameType.kTypeLanguage, StackFrameType.kTypeFunction, 0, rmem.FramePointer, registers, null); FunctionCounter counter = FindCounter(functionIndex, classIndex, fNode.Name); StackValue sv = StackValue.Null; if (runtimeCore.Options.RecursionChecking) { //Do the recursion check before call if (counter.times < Constants.kRecursionTheshold) //&& counter.sharedCounter < Constants.kRepetationTheshold) { // Build a context object in JILDispatch and call the Dispatch if (counter.times == 0) { counter.times++; exe.calledInFunction = true; } else if (counter.times >= 1) { if (fNode.Name.ToCharArray()[0] != '%' && fNode.Name.ToCharArray()[0] != '_' && !fNode.Name.Equals(Constants.kDotMethodName) && exe.calledInFunction) { counter.times++; } } if (runtimeCore.Options.IDEDebugMode && runtimeCore.Options.RunMode != InterpreterMode.kExpressionInterpreter) { runtimeCore.DebugProps.SetUpCallrForDebug(runtimeCore, this, fNode, pc, false, callsite, arguments, replicationGuides, stackFrame, dotCallDimensions, hasDebugInfo); } sv = callsite.JILDispatch(arguments, replicationGuides, stackFrame, runtimeCore, runtimeContext); } else { FindRecursivePoints(); string message = String.Format(Resources.kMethodStackOverflow, exe.recursivePoint[0].name); runtimeCore.RuntimeStatus.LogWarning(WarningID.kInvalidRecursion, message); exe.recursivePoint = new List<FunctionCounter>(); exe.funcCounterTable = new List<FunctionCounter>(); sv = StackValue.Null; } } else { if (runtimeCore.Options.IDEDebugMode && runtimeCore.Options.RunMode != InterpreterMode.kExpressionInterpreter) { 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); } } SX = StackValue.BuildBlockIndex(blockDeclId); stackFrame.SX = SX; //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 (runtimeCore.RuntimeOptions.IDEDebugMode) { DebugFrame debugFrame = runtimeCore.DebugProps.DebugStackFrame.Peek(); //if (debugFrame.IsReplicating || runtimeCore.ContinuationStruct.IsContinuation) if (debugFrame.IsReplicating) { FunctionEndPoint fep = null; ContinuationStructure cs = runtimeCore.ContinuationStruct; if (runtimeCore.RuntimeOptions.ExecutionMode == ProtoCore.ExecutionMode.Serial || runtimeCore.RuntimeOptions.IDEDebugMode) { // This needs to be done only for the initial argument arrays (ie before the first replicating call) - pratapa if(runtimeCore.ContinuationStruct.IsFirstCall) { runtimeCore.ContinuationStruct.InitialDepth = depth; runtimeCore.ContinuationStruct.InitialPC = pc; runtimeCore.ContinuationStruct.InitialArguments = arguments; runtimeCore.ContinuationStruct.InitialDotCallDimensions = dotCallDimensions; for (int i = 0; i < arguments.Count; ++i) { GCUtils.GCRetain(arguments[i], core); } // Hardcoded runtimeCore.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); runtimeCore.ContinuationStruct = cs; runtimeCore.ContinuationStruct.IsFirstCall = true; } } else sv = callsite.JILDispatch(arguments, replicationGuides, stackFrame, core); } else #endif sv = callsite.JILDispatch(arguments, replicationGuides, 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 = arguments; Properties.functionCallDotCallDimensions = dotCallDimensions; explicitCall = true; IsExplicitCall = explicitCall; int entryPC = (int)sv.opdata; CallExplicit(entryPC); } } // 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.kExpressionInterpreter) { runtimeCore.DebugProps.RestoreCallrForNoBreak(runtimeCore, fNode); } GCDotMethods(fNode.Name, ref sv, dotCallDimensions, arguments); if (fNode.Name.ToCharArray()[0] != '%' && fNode.Name.ToCharArray()[0] != '_') { exe.calledInFunction = false; } } return sv; }
public override StackValue Execute(Runtime.Context c, List <StackValue> formalParameters, StackFrame stackFrame, RuntimeCore runtimeCore) { if (mInterpreter == null) { Init(runtimeCore); } if (mFunctionPointer == null) { return(StackValue.Null); } if (stackFrame != null) { StackValue svThisPtr = stackFrame.ThisPtr; // Check if this is a 'this' pointer function overload that was generated by the compiler if (null != mFNode && mFNode.IsAutoGeneratedThisProc) { int thisPtrIndex = 0; bool isStaticCall = svThisPtr.IsPointer && Constants.kInvalidPointer == svThisPtr.Pointer; if (isStaticCall) { stackFrame.ThisPtr = formalParameters[thisPtrIndex]; } // Comment Jun: Execute() can handle a null this pointer. // But since we don't even need to to reach there if we don't have a valid this pointer, then just return null if (formalParameters[thisPtrIndex].IsNull) { runtimeCore.RuntimeStatus.LogWarning( Runtime.WarningID.DereferencingNonPointer, Resources.kDereferencingNonPointer); return(StackValue.Null); } // These are the op types allowed. Validity.Assert(formalParameters[thisPtrIndex].IsPointer || formalParameters[thisPtrIndex].IsDefaultArgument); // Make sure we to pass a pointer to unmarshal. if (formalParameters[thisPtrIndex].IsPointer) { svThisPtr = formalParameters[thisPtrIndex]; } formalParameters.RemoveAt(thisPtrIndex); } formalParameters.Add(svThisPtr); } Object ret = mFunctionPointer.Execute(c, mInterpreter, formalParameters); 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)); } return(op); }