Beispiel #1
0
 /// <summary>
 /// Do the actual work of the Execute() method.  This was pulled out
 /// to a separate static method so that others can call it without needing
 /// an actual popscope object.  Everything OpcodePopScope.Execute() does
 /// should actually be done here, so as to ensure that external callers of
 /// this get exactly the same behaviour as a full popstack opcode.
 /// </summary>
 /// <param name="cpuObj">the shared.cpu to operate on.</param>
 /// <param name="levels">number of levels to popscope.</param>
 public static void DoPopScope(ICpu cpuObj, Int16 levels)
 {
     cpuObj.PopAboveStack(levels);
 }
Beispiel #2
0
        public override void Execute(ICpu cpu)
        {
            // Return value should be atop the stack.
            // Pop it, eval it, and push it back,
            // i.e. if the statement was RETURN X, and X is 2, then you want
            // it to return the number 2, not the variable name $x, which could
            // be a variable local to this function which is about to go out of scope
            // so the caller can't access it:
            object returnVal = cpu.PopValue();

            // Now dig down through the stack until the argbottom is found.
            // anything still leftover above that should be unread parameters we
            // should throw away:
            object shouldBeArgMarker = 0; // just a temp to force the loop to execute at least once.
            while (shouldBeArgMarker == null || (shouldBeArgMarker.GetType() != OpcodeCall.ArgMarkerType))
            {
                if (cpu.GetStackSize() <= 0)
                {
                    throw new KOSArgumentMismatchException(
                        string.Format("Something is wrong with the stack - no arg bottom mark when doing a return.  This is an internal problem with kOS")
                       );
                }
                shouldBeArgMarker = cpu.PopStack();
            }

            cpu.PushStack(Structure.FromPrimitive(returnVal));

            // Now, after the eval was done, NOW finally pop the scope, after we don't need local vars anymore:
            if( Depth > 0 )
                OpcodePopScope.DoPopScope(cpu, Depth);

            // The only thing on the "above stack" now that is allowed to get in the way of
            // finding the context record that tells us where to jump back to, are the potential
            // closure scope frames that might have been pushed if this subroutine was
            // called via a delegate reference.  Consume any of those that are in
            // the way, then expect the context record.  Any other pattern encountered
            // is proof the stack alignment got screwed up:
            bool okay;
            VariableScope peeked = cpu.PeekRaw(-1, out okay) as VariableScope;
            while (okay && peeked != null && peeked.IsClosure)
            {
                cpu.PopAboveStack(1);
                peeked = cpu.PeekRaw(-1, out okay) as VariableScope;
            }
            object shouldBeContextRecord = cpu.PopAboveStack(1);
            if ( !(shouldBeContextRecord is SubroutineContext) )
            {
                // This should never happen with any user code:
                throw new Exception( "kOS internal error: Stack misalignment detected when returning from routine.");
            }

            var contextRecord = shouldBeContextRecord as SubroutineContext;

            // Special case for when the subroutine was really being called as an interrupt
            // trigger from the kOS CPU itself.  In that case we don't want to leave the
            // return value atop the stack, and instead want to pop it and use it to decide
            // whether or not the re-insert the trigger for next time:
            if (contextRecord.IsTrigger)
            {
                cpu.PopStack(); // already got the return value up above, just ignore it.
                if (returnVal is bool || returnVal is BooleanValue )
                    if (Convert.ToBoolean(returnVal))
                        cpu.AddTrigger(contextRecord.TriggerPointer);
            }

            int destinationPointer = contextRecord.CameFromInstPtr;
            int currentPointer = cpu.InstructionPointer;
            DeltaInstructionPointer = destinationPointer - currentPointer;
        }
Beispiel #3
0
        public override void Execute(ICpu cpu)
        {
            // Return value should be atop the stack - we have to pop it so that
            // we can reach the arg start marker under it:
            object returnVal = cpu.PopValue();

            // The next thing on the stack under the return value should be the marker that indicated where
            // the parameters started.  It should be thrown away now.  If the next thing is NOT the marker
            // of where the parameters started, that is proof the stack is misaligned, probably because the
            // number of args passed didn't match the number of DECLARE PARAMETER statements in the function:
            string shouldBeArgMarker = cpu.PopStack() as string;

            if ( (shouldBeArgMarker == null) || (!(shouldBeArgMarker.Equals(OpcodeCall.ARG_MARKER_STRING))) )
            {
                throw new KOSArgumentMismatchException(
                    string.Format("(detected when returning from function and the stack still had {0} on it)",
                    (shouldBeArgMarker ?? "a non-string value"))
                );
            }
            // If the proper argument marker was found, then it's all okay, so put the return value
            // back, where it belongs, now that the arg start marker was popped off:
            cpu.PushStack(returnVal);

            // Now, after the eval was done, NOW finally pop the scope, after we don't need local vars anymore:
            if( Depth > 0 )
                OpcodePopScope.DoPopScope(cpu, Depth);

            // The only thing on the "above stack" now that is allowed to get in the way of
            // finding the context record that tells us where to jump back to, are the potential
            // closure scope frames that might have been pushed if this subroutine was
            // called via a delegate reference.  Consume any of those that are in
            // the way, then expect the context record.  Any other pattern encountered
            // is proof the stack alignment got screwed up:
            bool okay;
            VariableScope peeked = cpu.PeekRaw(-1, out okay) as VariableScope;
            while (okay && peeked != null && peeked.IsClosure)
            {
                cpu.PopAboveStack(1);
                peeked = cpu.PeekRaw(-1, out okay) as VariableScope;
            }
            object shouldBeContextRecord = cpu.PopAboveStack(1);
            if ( !(shouldBeContextRecord is SubroutineContext) )
            {
                // This should never happen with any user code:
                throw new Exception( "kOS internal error: Stack misalignment detected when returning from routine.");
            }

            var contextRecord = shouldBeContextRecord as SubroutineContext;

            int destinationPointer = contextRecord.CameFromInstPtr;
            int currentPointer = cpu.InstructionPointer;
            DeltaInstructionPointer = destinationPointer - currentPointer;
        }