예제 #1
0
            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));
            }
예제 #2
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());
        }
예제 #3
0
        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));
        }
예제 #4
0
        //
        //  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);
        }
예제 #5
0
        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));
        }
예제 #6
0
        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));
        }
예제 #7
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(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());
        }
예제 #8
0
        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());
        }
예제 #9
0
        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));
        }
예제 #10
0
 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;
 }
예제 #11
0
        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();
        }
예제 #12
0
        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();
        }
예제 #13
0
        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));
        }
예제 #14
0
        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));
        }
예제 #15
0
        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));
        }
예제 #16
0
        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);
        }
예제 #17
0
        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));
        }
예제 #18
0
        /// <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);
                }
            }
        }
예제 #20
0
        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);
        }
예제 #21
0
        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);
                }
            }
        }