예제 #1
0
        private void PushCall(VMModule module, int functionIndex, byte[] argumentData)
        {
            // TODO: Need either better documentation about how bound functions must not re-retrieve arguments from
            // the original argumentSource after a Call Continuation, or we need to use unique argument buffers for each
            // bound function call (with pooling of course). I'd opt for the former, it's super easy to just grab your
            // arguments as soon as you enter the bound function, and is the cleanest as well.

            GetFunctionStackSizes(module, functionIndex,
                                  out int _,
                                  out int argumentMemorySize,
                                  out int stackSize);

            if (argumentData.Length != argumentMemorySize)
            {
                throw new ArgumentOutOfRangeException(nameof(argumentData), "Function argument size differs.");
            }

            // Function input + space for function index
            _argumentBuffer.Recreate(stackSize + sizeof(int));

            for (int i = 0, ilen = argumentData.Length; i < ilen; ++i)
            {
                _argumentBuffer.PushVal(argumentData[i]);
            }
            _argumentBuffer.PushValInt(functionIndex);
            PushCall(module, _argumentBuffer);
        }
예제 #2
0
        private void GetFunctionStackSizes(
            VMModule module,
            int functionIndex,
            out int returnValueSize,
            out int argumentMemorySize,
            out int stackSize)
        {
            int definedFunctionCount = module.ILModule.DefinedFunctions.Length;

            if (functionIndex >= definedFunctionCount)
            {
                VMFunction function = module.VMFunctions[functionIndex];
                returnValueSize    = function.ReturnValueSize;
                argumentMemorySize = function.ArgumentMemorySize;
                stackSize          = returnValueSize + argumentMemorySize;
                //frame = AcquireFrame(function.ArgumentMemorySize);
                //frame.BindingEnumerator = function.Delegate(this, new ArgumentSource(frame.Memory, 0));
            }
            else
            {
                ILFunction function = module.ILModule.DefinedFunctions[functionIndex];
                returnValueSize    = function.ReturnValueSize;
                argumentMemorySize = function.ArgumentMemorySize;
                stackSize          = function.MaxStackSize;
                //frame = AcquireFrame(function.MaxStackSize);
            }
        }
예제 #3
0
        public bool Call(
            VMModule module,
            string functionName,
            byte[] argumentData,
            Action <bool>?finished = null)
        {
            if (IsRunning)
            {
                throw new InvalidOperationException("Cannot call function while running");
            }

            int functionIndex = LookupFunction(module.ILModule, functionName);

            if (functionIndex == -1)
            {
                return(false);
            }

            int argumentsSize;

            if (functionIndex < module.ILModule.DefinedFunctions.Length)
            {
                argumentsSize = module.ILModule.DefinedFunctions[functionIndex].ArgumentMemorySize;
            }
            else
            {
                argumentsSize = module.VMFunctions[functionIndex].ArgumentMemorySize;
            }

            if (argumentData.Length != argumentsSize)
            {
                // TODO: Should this be an exception? At the very least we need a result code to determine why it failed.
                return(false);
            }

            if (finished == null)
            {
                finished = success => { };
            }

            IsRunning = true;

            _finishedCallback = finished;
            _cycleCount       = 0;

            PushCall(module, functionIndex, argumentData);

            if (_isStepping)
            {
                Break();
            }
            else
            {
                Continue();
            }

            return(true);
        }
예제 #4
0
 public static Continuation Call(VMModule module, int functionIndex, IReadOnlyList <int> arguments)
 {
     return(new Continuation {
         Action = ContinuationAction.CALL,
         Module = module,
         FunctionIndex = functionIndex,
         Arguments = arguments
     });
 }
예제 #5
0
        public static Continuation Call(VMModule module, string functionName, IReadOnlyList <int> arguments)
        {
            int index = VirtualMachine.LookupFunction(module.ILModule, functionName);

            if (index == -1)
            {
                throw new ArgumentException($"Function {functionName} not found in given module", nameof(functionName));
            }
            return(Call(module, index, arguments));
        }
예제 #6
0
        private void PushCall(VMModule module, StackFrameMemory sourceStack)
        {
            int functionIndex = sourceStack.PopValInt();

            GetFunctionStackSizes(module, functionIndex,
                                  out int returnValueSize,
                                  out int argumentMemorySize,
                                  out int stackSize);

            StackFrame frame = AcquireFrame(stackSize);

            frame.Module   = module;
            frame.Function = functionIndex;
            frame.Memory.CopyFrom(sourceStack, sourceStack.StackPointer - argumentMemorySize, returnValueSize, argumentMemorySize);
            sourceStack.Discard(argumentMemorySize);
            PushCallStack(frame);

            // TODO: PERF: Try to optimize out calls to HandleModuleAdded when we can deduce that the module has already
            // been seen.
            // For calls pushed by the CALL instruction, we know that the module will be the same and that we don't need
            // to call this function.
            _debugger?.HandleModuleAdded(module);
        }