public StackValue GetData(int blockId, int symbolindex, int scope) { MemoryRegion region = DSASM.MemoryRegion.kInvalidRegion; if (Constants.kGlobalScope == scope) { region = Executable.runtimeSymbols[blockId].symbolList[symbolindex].memregion; } else { region = ClassTable.ClassNodes[scope].symbols.symbolList[symbolindex].memregion; } if (MemoryRegion.kMemStack == region) { return(GetStackData(blockId, symbolindex, scope)); } else if (MemoryRegion.kMemHeap == region) { //return GetHeapData(symbolindex); throw new NotImplementedException("{69604961-DE03-440A-97EB-0390B1B0E510}"); } else if (MemoryRegion.kMemStatic == region) { Validity.Assert(false, "static region not yet supported, {63EA5434-D2E2-40B6-A816-0046F573236F}"); } Validity.Assert(false, "unsupported memory region, {DCA48F13-EEE1-4374-B301-C96870D44C6B}"); return(StackValue.BuildInt(0)); }
/// <summary> /// Get all keys from an array /// </summary> /// <param name="array"></param> /// <param name="core"></param> /// <returns></returns> public static StackValue[] GetKeys(StackValue array, Core core) { Validity.Assert(StackUtils.IsArray(array)); if (!StackUtils.IsArray(array)) { return(null); } HeapElement he = GetHeapElement(array, core); List <StackValue> keys = new List <StackValue>(); for (int i = 0; i < he.VisibleSize; ++i) { keys.Add(StackValue.BuildInt(i)); } if (he.Dict != null) { foreach (var key in he.Dict.Keys) { keys.Add(key); } } return(keys.ToArray()); }
public void TestGCStringCleanup() { // Simulating the following graph /* * def generateString() { * return 1+"@" +2; * }; * * vv = [Imperative]{ * generateString(); * // "1@2" will be on the heap * // current stack has no reference type elements * // --------------------------------GC kicks in due to mem threshold---------------------------- * // "1@2" on the heap will be marked as white - since no stack elements have a reference to it * // * // Async VM execution computes a new generateString() fn Call * cc = generateString(); * // * // cc is pushed on the stack and holds a reference to the "1@2" heap element * // * // GC starts the sweep process in which it deletes "1@2" heap element * // ----------------------------------GC is finished--------------------------------------------- * return cc; * }; * // * // vv is still on the stack with a reference to a now null heap element */ var heap = new Heap(); string sseValue = "hello world"; // Allocate a string on the heap. // Similar to what would happen if a string stack element was pushed on the stack and then popped (due to out of scope). heap.AllocateString(sseValue); StackValue someStackValue = StackValue.BuildNull(); var notifications = new Dictionary <Heap.GCState, (Action, Action)>() { { Heap.GCState.Sweep, (() => { // Simulate a new string (with the same value as existing one on heap) stack element being created while GC is propagating or sweeping someStackValue = heap.AllocateString(sseValue); }, () => { }) } }; // Start GC with a random stack value as gcRoot (not the string stack element, because it was pushed out of the stack) heap.FullGCTest(new List <StackValue>() { StackValue.BuildInt(1) }, testExecutive, notifications); // The stack element that was pushed after GC start should be valid. Assert.IsNotNull(heap.ToHeapObject <DSString>(someStackValue)); }
// // 1. Get the graphnode given the varname // 2. Get the sv of the symbol // 3. set the sv to the new value // 4. Get all graphnpodes dependent on the symbol and mark them dirty // 5. Re-execute the script // proc AssociativeEngine.SetValue(string varname, int block, StackValue, sv) // symbol = dsEXE.GetSymbol(varname, block) // globalStackIndex = symbol.stackindex // runtime.stack[globalStackIndex] = sv // AssociativeEngine.Propagate(symbol) // runtime.Execute() // end // private bool SetValue(string varName, int?value, out int nodesMarkedDirty) { int blockId = 0; // 1. Get the graphnode given the varname AssociativeGraph.GraphNode graphNode = MirrorTarget.GetFirstGraphNode(varName, out blockId); if (graphNode == null) { nodesMarkedDirty = 0; return(false); } SymbolNode symbol = graphNode.updateNodeRefList[0].nodeList[0].symbol; // 2. Get the sv of the symbol int globalStackIndex = symbol.index; // 3. set the sv to the new value StackValue sv; if (null == value) { sv = StackValue.Null; } else { sv = StackValue.BuildInt((long)value); } MirrorTarget.rmem.Stack[globalStackIndex] = sv; // 4. Get all graphnpodes dependent on the symbol and mark them dirty const int outerBlock = 0; ProtoCore.DSASM.Executable exe = MirrorTarget.exe; List <AssociativeGraph.GraphNode> reachableGraphNodes = AssociativeEngine.Utils.UpdateDependencyGraph( graphNode, MirrorTarget, graphNode.exprUID, false, runtimeCore.Options.ExecuteSSA, outerBlock, false); // Mark reachable nodes as dirty Validity.Assert(reachableGraphNodes != null); nodesMarkedDirty = reachableGraphNodes.Count; foreach (AssociativeGraph.GraphNode gnode in reachableGraphNodes) { gnode.isDirty = true; } // 5. Re-execute the script - re-execution occurs after this call return(true); }
public void TestMultiDimensionaldArray() { var heap = new Heap(); var array1 = heap.AllocateArray(new StackValue[] { StackValue.BuildInt(0) }); var array2 = heap.AllocateArray(new StackValue[] { array1 }); var array3 = heap.AllocateArray(new StackValue[] { array2 }); heap.GCMarkAndSweep(new List <StackValue>() { }, testExecutive); Assert.IsNull(heap.ToHeapObject <DSArray>(array1)); Assert.IsNull(heap.ToHeapObject <DSArray>(array2)); Assert.IsNull(heap.ToHeapObject <DSArray>(array3)); }
public void TestBasic() { var heap = new Heap(); var values = new StackValue[] { StackValue.BuildInt(0), StackValue.BuildInt(1), StackValue.BuildInt(2) }; var array = heap.AllocateArray(values); var str = heap.AllocateString("hello world"); heap.GCMarkAndSweep(new List <StackValue>(), testExecutive); Assert.IsNull(heap.ToHeapObject <DSArray>(array)); Assert.IsNull(heap.ToHeapObject <DSArray>(str)); }
/// <summary> /// Get all keys from an array /// </summary> /// <param name="array"></param> /// <param name="core"></param> /// <returns></returns> public static StackValue[] GetKeys(StackValue array, Core core) { Validity.Assert(array.IsArray); if (!array.IsArray) { return(null); } HeapElement he = GetHeapElement(array, core); var keys = Enumerable.Range(0, he.VisibleSize).Select(i => StackValue.BuildInt(i)).ToList(); if (he.Dict != null) { keys.AddRange(he.Dict.Keys); } return(keys.ToArray()); }
public static StackValue BuildStackValueForPrimitive(AssociativeNode node) { Validity.Assert(IsPrimitiveASTNode(node) == true); if (node is IntNode) { return(StackValue.BuildInt((node as IntNode).Value)); } else if (node is DoubleNode) { return(StackValue.BuildDouble((node as DoubleNode).Value)); } else if (node is BooleanNode) { return(StackValue.BuildBoolean((node as BooleanNode).Value)); } return(StackValue.BuildNull()); }
public void TestDictionary() { var heap = new Heap(); var key = heap.AllocateArray(new StackValue[] { StackValue.BuildInt(42) }); var val = heap.AllocateString("Hello world"); var dict = new Dictionary <StackValue, StackValue>(); dict[key] = val; var array = heap.AllocateArray(new StackValue[] { }); heap.GCMarkAndSweep(new List <StackValue>() { }, testExecutive); Assert.IsNull(heap.ToHeapObject <DSArray>(val)); Assert.IsNull(heap.ToHeapObject <DSArray>(array)); }
public void PushStackFrame(StackValue svThisPtr, int classIndex, int funcIndex, int pc, int functionBlockDecl, int functionBlockCaller, StackFrameType callerType, StackFrameType type, int depth, int fp, List <StackValue> registers, int locsize, int executionStates) { // TODO Jun: Performance // Push frame should only require adjusting the frame index instead of pushing dummy elements PushFrame(locsize); Push(StackValue.BuildInt(fp)); PushRegisters(registers); Push(StackValue.BuildInt(executionStates)); Push(StackValue.BuildInt(0)); Push(StackValue.BuildInt(depth)); Push(StackValue.BuildFrameType((int)type)); Push(StackValue.BuildFrameType((int)callerType)); Push(StackValue.BuildBlockIndex(functionBlockCaller)); Push(StackValue.BuildBlockIndex(functionBlockDecl)); Push(StackValue.BuildInt(pc)); Push(StackValue.BuildInt(funcIndex)); Push(StackValue.BuildInt(classIndex)); Push(svThisPtr); FramePointer = Stack.Count; }
public void TestNonPointers01() { var heap = new Heap(); var values = new StackValue[] { StackValue.BuildInt(0), StackValue.BuildInt(1), StackValue.BuildInt(2) }; var array1 = heap.AllocateArray(values); var allTypes = new List <StackValue>(); var rawPointer = (int)array1.RawIntValue; for (int i = 0; i < (int)AddressType.ArrayKey; ++i) { var val = new StackValue() { optype = (AddressType)i, opdata = rawPointer }; if (!val.IsReferenceType) { allTypes.Add(val); } } var array2 = heap.AllocateArray(allTypes.ToArray()); heap.GCMarkAndSweep(new List <StackValue>() { array1 }, testExecutive); HeapElement arrayHeapElement; Assert.IsTrue(heap.TryGetHeapElement(array1, out arrayHeapElement)); heap.Free(); }
public void TestNonPointers02() { var heap = new Heap(); var values = new StackValue[] { StackValue.BuildInt(0), StackValue.BuildInt(1), StackValue.BuildInt(2) }; var array = heap.AllocateArray(values); var allTypes = new List <StackValue>(); var rawPointer = (int)array.RawIntValue; for (int i = 0; i < (int)AddressType.ArrayKey; ++i) { var val = new StackValue() { optype = (AddressType)i, opdata = rawPointer }; if (!val.IsReferenceType) { allTypes.Add(val); } } // non pointer gc root won't retain memory heap.GCMarkAndSweep(allTypes, testExecutive); HeapElement arrayHeapElement; Assert.IsFalse(heap.TryGetHeapElement(array, out arrayHeapElement)); heap.Free(); }
public void TestBasic() { var heap = new Heap(); var values = new StackValue[] { StackValue.BuildInt(0), StackValue.BuildInt(1), StackValue.BuildInt(2) }; var array = heap.AllocateArray(values); var str = heap.AllocateString("hello world"); heap.GCMarkAndSweep(new List <StackValue>(), testExecutive); HeapElement arrayHeapElement; Assert.IsFalse(heap.TryGetHeapElement(array, out arrayHeapElement)); HeapElement strHeapElement; Assert.IsFalse(heap.TryGetHeapElement(str, out strHeapElement)); }
public void TestMultiDimensionaldArray() { var heap = new Heap(); var array1 = heap.AllocateArray(new StackValue[] { StackValue.BuildInt(0) }); var array2 = heap.AllocateArray(new StackValue[] { array1 }); var array3 = heap.AllocateArray(new StackValue[] { array2 }); heap.GCMarkAndSweep(new List <StackValue>() { }, testExecutive); HeapElement array1HeapElement; Assert.IsFalse(heap.TryGetHeapElement(array1, out array1HeapElement)); HeapElement array2HeapElement; Assert.IsFalse(heap.TryGetHeapElement(array2, out array2HeapElement)); HeapElement array3HeapElement; Assert.IsFalse(heap.TryGetHeapElement(array3, out array3HeapElement)); }
public void TestDictionary() { var heap = new Heap(); var key = heap.AllocateArray(new StackValue[] { StackValue.BuildInt(42) }); var val = heap.AllocateString("Hello world"); var dict = new Dictionary <StackValue, StackValue>(); dict[key] = val; var array = heap.AllocateArray(new StackValue[] { }, dict); heap.GCMarkAndSweep(new List <StackValue>() { }, testExecutive); HeapElement valHeapElement; Assert.IsFalse(heap.TryGetHeapElement(val, out valHeapElement)); HeapElement arrayHeapElement; Assert.IsFalse(heap.TryGetHeapElement(array, out arrayHeapElement)); }
public override StackValue Execute(ProtoCore.Runtime.Context c, List <StackValue> formalParameters, ProtoCore.DSASM.StackFrame stackFrame, Core core) { ProtoCore.DSASM.Interpreter interpreter = new ProtoCore.DSASM.Interpreter(core, true); ProtoCore.DSASM.Executive oldDSASMExec = null; if (core.CurrentExecutive != null) { oldDSASMExec = core.CurrentExecutive.CurrentDSASMExec; core.CurrentExecutive.CurrentDSASMExec = interpreter.runtime; } // Assert for the block type activation.globs = core.DSExecutable.runtimeSymbols[core.RunningBlock].GetGlobalSize(); // // Comment Jun: // Storing execution states is relevant only if the current scope is a function, // as this mechanism is used to keep track of maintining execution states of recursive calls // This mechanism should also be ignored if the function call is non-recursive as it does not need to maintains state in that case int execStateSize = procedureNode.GraphNodeList.Count; stackFrame.SetAt(StackFrame.AbsoluteIndex.kExecutionStates, StackValue.BuildInt(execStateSize)); for (int n = execStateSize - 1; n >= 0; --n) { AssociativeGraph.GraphNode gnode = procedureNode.GraphNodeList[n]; interpreter.Push(StackValue.BuildBoolean(gnode.isDirty)); } // Push Params formalParameters.Reverse(); for (int i = 0; i < formalParameters.Count; i++) { interpreter.Push(formalParameters[i]); } StackValue svThisPtr = stackFrame.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); }
private ExecutionMirror Execute(int programCounterToExecuteFrom, List <Instruction> breakpoints, bool fepRun = false) { ProtoCore.Runtime.Context context = new ProtoCore.Runtime.Context(); core.Breakpoints = breakpoints; resumeBlockID = core.RunningBlock; int locals = 0; if (core.DebugProps.FirstStackFrame != null) { core.DebugProps.FirstStackFrame.SetAt(ProtoCore.DSASM.StackFrame.AbsoluteIndex.kFramePointer, StackValue.BuildInt(core.GlobOffset)); // Comment Jun: Tell the new bounce stackframe that this is an implicit bounce // Register TX is used for this. StackValue svCallConvention = StackValue.BuildCallingConversion((int)ProtoCore.DSASM.CallingConvention.BounceType.kImplicit); core.DebugProps.FirstStackFrame.SetAt(ProtoCore.DSASM.StackFrame.AbsoluteIndex.kRegisterTX, svCallConvention); } core.Bounce(resumeBlockID, programCounterToExecuteFrom, context, breakpoints, core.DebugProps.FirstStackFrame, locals, null, EventSink, fepRun); return(new ExecutionMirror(core.CurrentExecutive.CurrentDSASMExec, core)); }
/// <summary> /// If an input is a dominant list, restructure the result based on the /// structure of dominant list. /// /// Note the dominant structure will be restored only if the dominant /// list is zipped with other arguments, or the replication is applied /// to the dominant list firstly. /// </summary> /// <param name="ret"></param> /// <param name="domStructure"></param> /// <param name="instructions"></param> /// <param name="runtimeCore"></param> /// <returns></returns> public static StackValue RestoreDominantStructure( StackValue ret, DominantListStructure domStructure, List <ReplicationInstruction> instructions, RuntimeCore runtimeCore) { if (domStructure == null) { return(ret); } var domListIndex = domStructure.ArgumentIndex; var indicesList = domStructure.Indices; // If there is replication on the dominant list, it should be the // topest replicaiton. if (instructions != null && instructions.Any()) { var firstInstruciton = instructions.First(); if (firstInstruciton.Zipped) { if (!firstInstruciton.ZipIndecies.Contains(domListIndex)) { return(ret); } } else { if (firstInstruciton.CartesianIndex != domListIndex) { return(ret); } } } // Allocate an empty array to hold the value StackValue newRet; try { newRet = runtimeCore.RuntimeMemory.Heap.AllocateArray(new StackValue[] { }); } catch (RunOutOfMemoryException) { runtimeCore.RuntimeStatus.LogWarning(Runtime.WarningID.RunOutOfMemory, Resources.RunOutOfMemory); return(StackValue.Null); } var array = runtimeCore.Heap.ToHeapObject <DSArray>(newRet); // Write the result back var values = ret.IsArray ? runtimeCore.Heap.ToHeapObject <DSArray>(ret).Values : Enumerable.Repeat(ret, 1); var valueIndicePairs = values.Zip(indicesList, (val, idx) => new { Value = val, Indices = idx }); foreach (var item in valueIndicePairs) { var value = item.Value; var indices = item.Indices.Select(x => StackValue.BuildInt(x)).ToArray(); array.SetValueForIndices(indices, value, runtimeCore); } return(newRet); }
public override StackValue Execute(ProtoCore.Runtime.Context c, List <StackValue> formalParameters, ProtoCore.DSASM.StackFrame stackFrame, RuntimeCore runtimeCore) { // ensure there is no data race, function resolution and execution happens in parallel // but for FFI we want it to be serial cause the code we are calling into may not cope // with parallelism. // // we are always looking and putting our function pointers in handler with each lang // so better lock for FFIHandler (being static) it will be good object to lock // lock (FFIHandlers) { Interpreter interpreter = new Interpreter(runtimeCore, true); // Setup the stack frame data StackValue svThisPtr = stackFrame.ThisPtr; int ci = activation.JILRecord.classIndex; int fi = activation.JILRecord.funcIndex; int returnAddr = stackFrame.ReturnPC; int blockDecl = stackFrame.FunctionBlock; int blockCaller = stackFrame.FunctionCallerBlock; int framePointer = runtimeCore.RuntimeMemory.FramePointer; int locals = activation.JILRecord.locals; FFIHandler handler = FFIHandlers[activation.ModuleType]; FFIActivationRecord r = activation; string className = ""; if (activation.JILRecord.classIndex > 0) { className = runtimeCore.DSExecutable.classTable.ClassNodes[activation.JILRecord.classIndex].Name; } List <ProtoCore.Type> argTypes = new List <Type>(r.ParameterTypes); ProcedureNode fNode = null; if (ProtoCore.DSASM.Constants.kInvalidIndex != ci) { fNode = interpreter.runtime.exe.classTable.ClassNodes[ci].ProcTable.Procedures[fi]; } // Check if this is a 'this' pointer function overload that was generated by the compiler if (null != fNode && fNode.IsAutoGeneratedThisProc) { int thisPtrIndex = 0; bool isStaticCall = svThisPtr.IsPointer && Constants.kInvalidPointer == svThisPtr.Pointer; if (isStaticCall) { stackFrame.ThisPtr = formalParameters[thisPtrIndex]; } argTypes.RemoveAt(thisPtrIndex); // Comment Jun: Execute() can handle a null this pointer. // But since we dont even need to to reach there if we dont have a valid this pointer, then just return null if (formalParameters[thisPtrIndex].IsNull) { runtimeCore.RuntimeStatus.LogWarning(ProtoCore.Runtime.WarningID.DereferencingNonPointer, Resources.kDeferencingNonPointer); return(StackValue.Null); } // These are the op types allowed. Validity.Assert(formalParameters[thisPtrIndex].IsPointer || formalParameters[thisPtrIndex].IsDefaultArgument); svThisPtr = formalParameters[thisPtrIndex]; formalParameters.RemoveAt(thisPtrIndex); } FFIFunctionPointer functionPointer = handler.GetFunctionPointer(r.ModuleName, className, r.FunctionName, argTypes, r.ReturnType); mFunctionPointer = Validate(functionPointer) ? functionPointer : null; mFunctionPointer.IsDNI = activation.IsDNI; if (mFunctionPointer == null) { return(ProtoCore.DSASM.StackValue.Null); } { interpreter.runtime.executingBlock = runtimeCore.RunningBlock; activation.JILRecord.globs = runtimeCore.DSExecutable.runtimeSymbols[runtimeCore.RunningBlock].GetGlobalSize(); // Params formalParameters.Reverse(); for (int i = 0; i < formalParameters.Count; i++) { interpreter.Push(formalParameters[i]); } List <StackValue> registers = interpreter.runtime.GetRegisters(); // Comment Jun: the depth is always 0 for a function call as we are reseting this for each function call // This is only incremented for every language block bounce int depth = 0; StackFrameType callerType = stackFrame.CallerStackFrameType; // FFI calls do not have execution states runtimeCore.RuntimeMemory.PushFrameForLocals(locals); StackFrame newStackFrame = new StackFrame(svThisPtr, ci, fi, returnAddr, blockDecl, blockCaller, callerType, StackFrameType.Function, depth, framePointer, 0, registers, 0); runtimeCore.RuntimeMemory.PushStackFrame(newStackFrame); //is there a way the current stack be passed across and back into the managed runtime by FFI calling back into the language? //e.g. DCEnv* carrying all the stack information? look at how vmkit does this. // = jilMain.Run(ActivationRecord.JILRecord.pc, null, true); //double[] tempArray = GetUnderlyingArray<double>(jilMain.runtime.rmem.stack); Object ret = mFunctionPointer.Execute(c, interpreter); StackValue op; if (ret == null) { op = StackValue.Null; } else if (ret is StackValue) { op = (StackValue)ret; } else if (ret is Int64 || ret is int) { op = StackValue.BuildInt((Int64)ret); } else if (ret is double) { op = StackValue.BuildDouble((double)ret); } else { throw new ArgumentException(string.Format("FFI: incorrect return type {0} from external function {1}:{2}", activation.ReturnType.Name, activation.ModuleName, activation.FunctionName)); } // Clear the FFI stack frame // FFI stack frames have no local variables interpreter.runtime.rmem.FramePointer = (int)interpreter.runtime.rmem.GetAtRelative(StackFrame.FrameIndexFramePointer).IntegerValue; interpreter.runtime.rmem.PopFrame(StackFrame.StackFrameSize + formalParameters.Count); return(op); } } }
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); }
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); } } }