public StackValue Evaluate(List<StackValue> args, StackFrame stackFrame) { // // Build the stackframe int classScopeCaller = (int)stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kClass).opdata; int returnAddr = (int)stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kReturnAddress).opdata; int blockDecl = (int)mProcNode.runtimeIndex; int blockCaller = (int)stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kFunctionCallerBlock).opdata; int framePointer = mRunTime.runtime.Core.Rmem.FramePointer; StackValue thisPtr = StackUtils.BuildPointer(-1); // Comment Jun: the caller type is the current type in the stackframe StackFrameType callerType = (StackFrameType)stackFrame.GetAt(StackFrame.AbsoluteIndex.kStackFrameType).opdata; StackFrameType type = StackFrameType.kTypeFunction; int depth = 0; List<StackValue> registers = new List<StackValue>(); // Comment Jun: Calling convention data is stored on the TX register StackValue svCallconvention = StackUtils.BuildNode(AddressType.CallingConvention, (long)ProtoCore.DSASM.CallingConvention.BounceType.kImplicit); mRunTime.runtime.TX = svCallconvention; StackValue svBlockDecl = StackUtils.BuildNode(AddressType.BlockIndex, blockDecl); mRunTime.runtime.SX = svBlockDecl; mRunTime.runtime.SaveRegisters(registers); ProtoCore.DSASM.StackFrame newStackFrame = new StackFrame(thisPtr, classScopeCaller, 1, returnAddr, blockDecl, blockCaller, callerType, type, depth, framePointer, registers); List<List<int>> replicationGuides = new List<List<int>>(); if (mRunTime.runtime.Core.Options.IDEDebugMode && mRunTime.runtime.Core.ExecMode != ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter) { mRunTime.runtime.Core.DebugProps.SetUpCallrForDebug(mRunTime.runtime.Core, mRunTime.runtime, mProcNode, returnAddr - 1, false, mCallSite, args, replicationGuides, newStackFrame); } StackValue rx = mCallSite.JILDispatchViaNewInterpreter(new Runtime.Context(), args, replicationGuides, newStackFrame, mRunTime.runtime.Core); if (mRunTime.runtime.Core.Options.IDEDebugMode && mRunTime.runtime.Core.ExecMode != ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter) { mRunTime.runtime.Core.DebugProps.RestoreCallrForNoBreak(mRunTime.runtime.Core, mProcNode); } return rx; }
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); }
/// <summary> /// Get a list of all the function end points that are type compliant, there maybe more than one due to pattern matches /// </summary> /// <returns></returns> public List<FunctionEndPoint> GetExactTypeMatches(ProtoCore.Runtime.Context context, List<StackValue> formalParams, List<ReplicationInstruction> replicationInstructions, StackFrame stackFrame, Core core) { List<FunctionEndPoint> ret = new List<FunctionEndPoint>(); List<List<StackValue>> allReducedParamSVs = Replicator.ComputeAllReducedParams(formalParams, replicationInstructions, core); List<StackValue> reducedParamSVs = allReducedParamSVs[0]; //@TODO(Luke): Need to add type statistics checks to the below if it is an array to stop int[] matching char[] //Now test the reduced Params over all of the available end points foreach (FunctionEndPoint fep in FunctionEndPoints) { if (fep.DoesTypeDeepMatch(reducedParamSVs, core)) { //// The first line checks if the lhs of a dot operation was a class name //if (stackFrame.GetAt(StackFrame.AbsoluteIndex.kThisPtr).optype == AddressType.ClassIndex // && !fep.procedureNode.isConstructor // && !fep.procedureNode.isStatic) if ((stackFrame.GetAt(StackFrame.AbsoluteIndex.kThisPtr).optype == AddressType.Pointer && stackFrame.GetAt(StackFrame.AbsoluteIndex.kThisPtr).opdata == -1 && fep.procedureNode != null && !fep.procedureNode.isConstructor) && !fep.procedureNode.isStatic && (fep.procedureNode.classScope != -1)) { continue; } ret.Add(fep); } } return ret; }
private List<FunctionEndPoint> GetCandidateFunctions(StackFrame stackFrame, Dictionary<FunctionEndPoint, int> candidatesWithDistances) { List<FunctionEndPoint> candidateFunctions = new List<FunctionEndPoint>(); foreach (FunctionEndPoint fep in candidatesWithDistances.Keys) { // The first line checks if the lhs of a dot operation was a class name //if (stackFrame.GetAt(StackFrame.AbsoluteIndex.kThisPtr).IsClassIndex // && !fep.procedureNode.isConstructor // && !fep.procedureNode.isStatic) if ((stackFrame.GetAt(StackFrame.AbsoluteIndex.kThisPtr).IsPointer && stackFrame.GetAt(StackFrame.AbsoluteIndex.kThisPtr).opdata == -1 && fep.procedureNode != null && !fep.procedureNode.isConstructor) && !fep.procedureNode.isStatic && (fep.procedureNode.classScope != -1)) { continue; } candidateFunctions.Add(fep); } return candidateFunctions; }
public StackValue Evaluate(List<StackValue> args, StackFrame stackFrame) { // Build the stackframe var runtimeCore = interpreter.runtime.Core; int classScopeCaller = (int)stackFrame.GetAt(StackFrame.AbsoluteIndex.kClass).opdata; int returnAddr = (int)stackFrame.GetAt(StackFrame.AbsoluteIndex.kReturnAddress).opdata; int blockDecl = procNode.runtimeIndex; int blockCaller = (int)stackFrame.GetAt(StackFrame.AbsoluteIndex.kFunctionCallerBlock).opdata; int framePointer = runtimeCore.Rmem.FramePointer; StackValue thisPtr = StackValue.BuildPointer(-1); // Functoion has variable input parameter. This case only happen // for FFI functions whose last parameter's type is (params T[]). // In this case, we need to convert argument list from // // {a1, a2, ..., am, v1, v2, ..., vn} // // to // // {a1, a2, ..., am, {v1, v2, ..., vn}} if (procNode.isVarArg) { int paramCount = procNode.argInfoList.Count; Validity.Assert(paramCount >= 1); int varParamCount = args.Count - (paramCount - 1); var varParams = args.GetRange(paramCount - 1, varParamCount).ToArray(); args.RemoveRange(paramCount - 1, varParamCount); var packedParams = HeapUtils.StoreArray(varParams, null, interpreter.runtime.Core); args.Add(packedParams); } bool isCallingMemberFunciton = procNode.classScope != Constants.kInvalidIndex && !procNode.isConstructor && !procNode.isStatic; bool isValidThisPointer = true; if (isCallingMemberFunciton) { Validity.Assert(args.Count >= 1); thisPtr = args[0]; if (thisPtr.IsArray) { isValidThisPointer = ArrayUtils.GetFirstNonArrayStackValue(thisPtr, ref thisPtr, runtimeCore); } else { args.RemoveAt(0); } } if (!isValidThisPointer || (!thisPtr.IsPointer && !thisPtr.IsArray)) { runtimeCore.RuntimeStatus.LogWarning(WarningID.kDereferencingNonPointer, WarningMessage.kDeferencingNonPointer); return StackValue.Null; } var callerType = (StackFrameType)stackFrame.GetAt(StackFrame.AbsoluteIndex.kStackFrameType).opdata; interpreter.runtime.TX = StackValue.BuildCallingConversion((int)ProtoCore.DSASM.CallingConvention.BounceType.kImplicit); StackValue svBlockDecl = StackValue.BuildBlockIndex(blockDecl); interpreter.runtime.SX = svBlockDecl; var repGuides = new List<List<ProtoCore.ReplicationGuide>>(); List<StackValue> registers = new List<StackValue>(); interpreter.runtime.SaveRegisters(registers); var newStackFrame = new StackFrame(thisPtr, classScopeCaller, 1, returnAddr, blockDecl, blockCaller, callerType, StackFrameType.kTypeFunction, 0, // depth framePointer, registers, null); bool isInDebugMode = runtimeCore.Options.IDEDebugMode && runtimeCore.ExecMode != InterpreterMode.kExpressionInterpreter; if (isInDebugMode) { runtimeCore.DebugProps.SetUpCallrForDebug(runtimeCore, interpreter.runtime, procNode, returnAddr - 1, false, callsite, args, repGuides, newStackFrame); } StackValue rx = callsite.JILDispatchViaNewInterpreter( new Runtime.Context(), args, repGuides, newStackFrame, runtimeCore); if (isInDebugMode) { runtimeCore.DebugProps.RestoreCallrForNoBreak(runtimeCore, procNode); } interpreter.runtime.DecRefCounter(rx); return rx; }
//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 FunctionEndPoint SelectFEPFromMultiple(StackFrame stackFrame, Core core, List<FunctionEndPoint> feps, List<StackValue> argumentsList) { StackValue svThisPtr = stackFrame.GetAt(StackFrame.AbsoluteIndex.kThisPtr); Validity.Assert(svThisPtr.IsPointer, "this pointer wasn't a pointer. {89635B06-AD53-4170-ADA5-065EB2AE5858}"); int typeID = (int) svThisPtr.metaData.type; //Test for exact match List<FunctionEndPoint> exactFeps = new List<FunctionEndPoint>(); foreach (FunctionEndPoint fep in feps) if (fep.ClassOwnerIndex == typeID) exactFeps.Add(fep); if (exactFeps.Count == 1) { return exactFeps[0]; } //Walk the class tree structure to find the method while (core.ClassTable.ClassNodes[typeID].baseList.Count > 0) { Validity.Assert(core.ClassTable.ClassNodes[typeID].baseList.Count == 1, "Multiple inheritence not yet supported {B93D8D7F-AB4D-4412-8483-33DE739C0ADA}"); typeID = core.ClassTable.ClassNodes[typeID].baseList[0]; foreach (FunctionEndPoint fep in feps) if (fep.ClassOwnerIndex == typeID) return fep; } //We weren't able to distinguish based on class hiearchy, try to sepearete based on array ranking List<int> numberOfArbitraryRanks = new List<int>(); foreach (FunctionEndPoint fep in feps) { int noArbitraries = 0; for (int i = 0; i < argumentsList.Count; i++) { if (fep.FormalParams[i].rank == DSASM.Constants.kArbitraryRank) noArbitraries++; numberOfArbitraryRanks.Add(noArbitraries); } } int smallest = int.MaxValue; List<int> indeciesOfSmallest = new List<int>(); for (int i = 0; i < feps.Count; i++) { if (numberOfArbitraryRanks[i] < smallest) { smallest = numberOfArbitraryRanks[i]; indeciesOfSmallest.Clear(); indeciesOfSmallest.Add(i); } else if (numberOfArbitraryRanks[i] == smallest) indeciesOfSmallest.Add(i); } Validity.Assert(indeciesOfSmallest.Count > 0, "Couldn't find a fep when there should have been multiple: {EB589F55-F36B-404A-91DC-8D0EDC527E72}"); if (indeciesOfSmallest.Count == 1) return feps[indeciesOfSmallest[0]]; if (!CoreUtils.IsInternalMethod(feps[0].procedureNode.name) || CoreUtils.IsGetterSetter(feps[0].procedureNode.name)) { //If this has failed, we have multiple feps, which can't be distiquished by class hiearchy. Emit a warning and select one StringBuilder possibleFuncs = new StringBuilder(); possibleFuncs.Append( "Couldn't decide which function to execute. Please provide more specific type information. Possible functions were: "); foreach (FunctionEndPoint fep in feps) possibleFuncs.AppendLine("\t" + fep.ToString()); possibleFuncs.AppendLine("Error code: {DCE486C0-0975-49F9-BE2C-2E7D8CCD17DD}"); core.RuntimeStatus.LogWarning(RuntimeData.WarningID.kAmbiguousMethodDispatch, possibleFuncs.ToString()); } return feps[0]; //Validity.Assert(false, "We failed to find a single FEP when there should have been multiple. {CA6E1A93-4CF4-4030-AD94-3BF1C3CFC5AF}"); //throw new Exceptions.CompilerInternalException("{CA6E1A93-4CF4-4030-AD94-3BF1C3CFC5AF}"); }
public StackValue Evaluate(List<StackValue> args, StackFrame stackFrame) { // Build the stackframe var runtimeCore = interpreter.runtime.Core; int classScopeCaller = (int)stackFrame.GetAt(StackFrame.AbsoluteIndex.kClass).opdata; int returnAddr = (int)stackFrame.GetAt(StackFrame.AbsoluteIndex.kReturnAddress).opdata; int blockDecl = (int)procNode.runtimeIndex; int blockCaller = (int)stackFrame.GetAt(StackFrame.AbsoluteIndex.kFunctionCallerBlock).opdata; int framePointer = runtimeCore.Rmem.FramePointer; StackValue thisPtr = StackValue.BuildPointer(-1); bool isCallingMemberFunciton = procNode.classScope != Constants.kInvalidIndex && !procNode.isConstructor && !procNode.isStatic; if (isCallingMemberFunciton) { Validity.Assert(args.Count >= 1); thisPtr = args[0]; if (thisPtr.IsArray()) { ArrayUtils.GetFirstNonArrayStackValue(thisPtr, ref thisPtr, runtimeCore); } else { args.RemoveAt(0); } } if (!thisPtr.IsObject() && !thisPtr.IsArray()) { runtimeCore.RuntimeStatus.LogWarning(WarningID.kDereferencingNonPointer, WarningMessage.kDeferencingNonPointer); return StackValue.Null; } var callerType = (StackFrameType)stackFrame.GetAt(StackFrame.AbsoluteIndex.kStackFrameType).opdata; interpreter.runtime.TX = StackValue.BuildCallingConversion((int)ProtoCore.DSASM.CallingConvention.BounceType.kImplicit); StackValue svBlockDecl = StackValue.BuildBlockIndex(blockDecl); interpreter.runtime.SX = svBlockDecl; var repGuides = new List<List<ProtoCore.ReplicationGuide>>(); List<StackValue> registers = new List<StackValue>(); interpreter.runtime.SaveRegisters(registers); var newStackFrame = new StackFrame(thisPtr, classScopeCaller, 1, returnAddr, blockDecl, blockCaller, callerType, StackFrameType.kTypeFunction, 0, // depth framePointer, registers, null); bool isInDebugMode = runtimeCore.Options.IDEDebugMode && runtimeCore.ExecMode != InterpreterMode.kExpressionInterpreter; if (isInDebugMode) { runtimeCore.DebugProps.SetUpCallrForDebug(runtimeCore, interpreter.runtime, procNode, returnAddr - 1, false, callsite, args, repGuides, newStackFrame); } StackValue rx = callsite.JILDispatchViaNewInterpreter( new Runtime.Context(), args, repGuides, newStackFrame, runtimeCore); if (isInDebugMode) { runtimeCore.DebugProps.RestoreCallrForNoBreak(runtimeCore, procNode); } return rx; }
/// <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); }
public override StackValue Execute(ProtoCore.Runtime.Context c, List <StackValue> formalParameters, ProtoCore.DSASM.StackFrame stackFrame, Core core) { // ensure there is no data race, function resolution and execution happens in parallel // but for FFI we want it to be serial cause the code we are calling into may not cope // with parallelism. // // we are always looking and putting our function pointers in handler with each lang // so better lock for FFIHandler (being static) it will be good object to lock // lock (FFIHandlers) { ProtoCore.DSASM.Interpreter interpreter = new ProtoCore.DSASM.Interpreter(core, true); StackValue svThisPtr = stackFrame.GetAt(StackFrame.AbsoluteIndex.kThisPtr); StackValue svBlockDecl = stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kFunctionBlock); // Setup the stack frame data //int thisPtr = (int)stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kThisPtr).opdata; int ci = activation.JILRecord.classIndex; int fi = activation.JILRecord.funcIndex; int returnAddr = (int)stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kReturnAddress).opdata; int blockDecl = (int)svBlockDecl.opdata; int blockCaller = (int)stackFrame.GetAt(DSASM.StackFrame.AbsoluteIndex.kFunctionCallerBlock).opdata; int framePointer = core.Rmem.FramePointer; int locals = activation.JILRecord.locals; FFIHandler handler = FFIHandlers[activation.ModuleType]; FFIActivationRecord r = activation; string className = ""; if (activation.JILRecord.classIndex > 0) { className = core.DSExecutable.classTable.ClassNodes[activation.JILRecord.classIndex].name; } bool gcThisPtr = false; List <ProtoCore.Type> argTypes = new List <Type>(r.ParameterTypes); ProcedureNode fNode = null; if (ProtoCore.DSASM.Constants.kInvalidIndex != ci) { fNode = interpreter.runtime.exe.classTable.ClassNodes[ci].vtable.procList[fi]; } // Check if this is a 'this' pointer function overload that was generated by the compiler if (null != fNode && fNode.isAutoGeneratedThisProc) { int thisPtrIndex = 0; bool isStaticCall = svThisPtr.IsPointer && Constants.kInvalidPointer == (int)svThisPtr.opdata; if (isStaticCall) { thisPtrIndex = formalParameters.Count - 1; } argTypes.RemoveAt(thisPtrIndex); // Comment Jun: Execute() can handle a null this pointer. // But since we dont even need to to reach there if we dont have a valid this pointer, then just return null if (formalParameters[thisPtrIndex].IsNull) { core.RuntimeStatus.LogWarning(ProtoCore.RuntimeData.WarningID.kDereferencingNonPointer, ProtoCore.RuntimeData.WarningMessage.kDeferencingNonPointer); return(StackValue.Null); } // These are the op types allowed. Validity.Assert(formalParameters[thisPtrIndex].IsPointer || formalParameters[thisPtrIndex].IsDefaultArgument); svThisPtr = formalParameters[thisPtrIndex]; gcThisPtr = true; formalParameters.RemoveAt(thisPtrIndex); } FFIFunctionPointer functionPointer = handler.GetFunctionPointer(r.ModuleName, className, r.FunctionName, argTypes, r.ReturnType); mFunctionPointer = Validate(functionPointer) ? functionPointer : null; mFunctionPointer.IsDNI = activation.IsDNI; if (mFunctionPointer == null) { return(ProtoCore.DSASM.StackValue.Null); } List <object> ps = new List <object>(); //obsolete { interpreter.runtime.executingBlock = core.RunningBlock; activation.JILRecord.globs = core.DSExecutable.runtimeSymbols[core.RunningBlock].GetGlobalSize(); // Params formalParameters.Reverse(); for (int i = 0; i < formalParameters.Count; i++) { interpreter.Push(formalParameters[i]); } List <StackValue> registers = new List <DSASM.StackValue>(); interpreter.runtime.SaveRegisters(registers); // Comment Jun: the depth is always 0 for a function call as we are reseting this for each function call // This is only incremented for every language block bounce int depth = 0; StackFrameType callerType = (StackFrameType)stackFrame.GetAt(StackFrame.AbsoluteIndex.kCallerStackFrameType).opdata; // FFI calls do not have execution states core.Rmem.PushStackFrame(svThisPtr, ci, fi, returnAddr, blockDecl, blockCaller, callerType, ProtoCore.DSASM.StackFrameType.kTypeFunction, depth, framePointer, registers, locals, 0); //is there a way the current stack be passed across and back into the managed runtime by FFI calling back into the language? //e.g. DCEnv* carrying all the stack information? look at how vmkit does this. // = jilMain.Run(ActivationRecord.JILRecord.pc, null, true); //double[] tempArray = GetUnderlyingArray<double>(jilMain.runtime.rmem.stack); Object ret = mFunctionPointer.Execute(c, interpreter); StackValue op; if (ret == null) { op = StackValue.Null; } else if (ret is StackValue) { op = (StackValue)ret; } else if (ret is Int64 || ret is int) { op = StackValue.BuildInt((Int64)ret); } else if (ret is double) { op = StackValue.BuildDouble((double)ret); } else { throw new ArgumentException(string.Format("FFI: incorrect return type {0} from external function {1}:{2}", activation.ReturnType.Name, activation.ModuleName, activation.FunctionName)); } // gc the parameters if (gcThisPtr)// && core.Options.EnableThisPointerFunctionOverload) { // thisptr is sent as parameter, so need to gc it. // but when running in expression interpreter mode, do not GC because in DSASM.Executive.DecRefCounter() related GC functions, // the reference count will not be changed in expression interpreter mode. if (core.ExecMode != ProtoCore.DSASM.InterpreterMode.kExpressionInterpreter) { interpreter.runtime.Core.Rmem.Heap.GCRelease(new StackValue[] { svThisPtr }, interpreter.runtime); } } interpreter.runtime.Core.Rmem.Heap.GCRelease(formalParameters.ToArray(), interpreter.runtime); // increment the reference counter of the return value interpreter.runtime.GCRetain(op); // Clear the FFI stack frame // FFI stack frames have no local variables interpreter.runtime.rmem.FramePointer = (int)interpreter.runtime.rmem.GetAtRelative(ProtoCore.DSASM.StackFrame.kFrameIndexFramePointer).opdata; interpreter.runtime.rmem.PopFrame(ProtoCore.DSASM.StackFrame.kStackFrameSize + formalParameters.Count); return(op); //DSASM.Mirror.ExecutionMirror.Unpack(op, core.heap, core); } } }
/// <summary> /// Get a list of all the function end points that are type compliant, there maybe more than one due to pattern matches /// </summary> /// <returns></returns> public List<FunctionEndPoint> GetExactTypeMatches(ProtoCore.Runtime.Context context, List<StackValue> formalParams, List<ReplicationInstruction> replicationInstructions, StackFrame stackFrame, Core core) { List<FunctionEndPoint> ret = new List<FunctionEndPoint>(); List<List<StackValue>> allReducedParamSVs = Replicator.ComputeAllReducedParams(formalParams, replicationInstructions, core); List<StackValue> reducedParamSVs = allReducedParamSVs[0]; //@TODO(Luke): Need to add type statistics checks to the below if it is an array to stop int[] matching char[] //Now test the reduced Params over all of the available end points StackValue thisptr = stackFrame.GetAt(StackFrame.AbsoluteIndex.kThisPtr); bool isInstance = thisptr.IsPointer && thisptr.opdata != Constants.kInvalidIndex; bool isGlobal = thisptr.IsPointer && thisptr.opdata == Constants.kInvalidIndex; foreach (FunctionEndPoint fep in FunctionEndPoints) { var proc = fep.procedureNode; // Member functions are overloaded with thisptr as the first // parameter, so if member function replicates on the left hand // side, the type matching should only be applied to overloaded // member functions, otherwise should only be applied to original // member functions. if (isInstance && context.IsReplicating != proc.isAutoGeneratedThisProc) { continue; } else if (isGlobal && !proc.isConstructor && !proc.isStatic && proc.classScope != Constants.kGlobalScope) { continue; } if (fep.DoesTypeDeepMatch(reducedParamSVs, core)) { ret.Add(fep); } } return ret; }