本文整理汇总了C#中ICpu.GetStackSize方法的典型用法代码示例。如果您正苦于以下问题:C# ICpu.GetStackSize方法的具体用法?C# ICpu.GetStackSize怎么用?C# ICpu.GetStackSize使用的例子?那么恭喜您, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类ICpu
的用法示例。
在下文中一共展示了ICpu.GetStackSize方法的6个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C#代码示例。
示例1: ReverseStackArgs
/// <summary>
/// Take the topmost arguments down to the ARG_MARKER_STRING, pop them off, and then
/// put them back again in reversed order so a function can read them in normal order.
/// Note that if this is an indirect call, it will also consume the thing just under
/// the ARG_MARKER, since that's expected to be the delegate or KOSDelegate that we already
/// read and pulled the needed information from.
/// <param name="cpu">the cpu we are running on, fur stack manipulation purposes</param>
/// <param name="direct">need to know if this was a direct or indirect call. If indirect,
/// then that means it also needs to consume the indirect reference off the stack just under
/// the args</param>
/// </summary>
public static void ReverseStackArgs(ICpu cpu, bool direct)
{
List<object> args = new List<object>();
object arg = cpu.PopValue();
while (cpu.GetStackSize() > 0 && arg.GetType() != ArgMarkerType)
{
args.Add(arg);
// It's important to dereference with PopValue, not using PopStack, because the function
// being called might not even be able to see the variable in scope anyway.
// In other words, if calling a function like so:
// declare foo to 3.
// myfunc(foo).
// The code inside myfunc needs to see that as being identical to just saying:
// myfunc(3).
// It has to be unaware of the fact that the name of the argument was 'foo'. It just needs to
// see the contents that were inside foo.
arg = cpu.PopValue();
}
if (! direct)
cpu.PopStack(); // throw away the delegate or KOSDelegate info - we already snarfed it by now.
// Push the arg marker back on again.
cpu.PushStack(new KOSArgMarkerType());
// Push the arguments back on again, which will invert their order:
foreach (object item in args)
cpu.PushStack(item);
}
示例2: StaticExecute
/// <summary>
/// Performs the actual execution of a subroutine call, either from this opcode or externally from elsewhere.
/// All "call a routine" logic should shunt through this code here, which handles all the complex cases,
/// or at least it should.
/// Note that in the case of a user function, this does not *ACTUALLY* execute the function yet. It just
/// arranges the stack correctly for the call and returns the new location that the IP should be jumped to
/// on the next instruction to begin the subroutine. For all built-in cases, it actually executes the
/// call right now and doesn't return until it's done. But for User functions it can't do that - it can only
/// advise on where to jump on the next instruction to begin the function.
/// </summary>
/// <param name="cpu">the cpu its running on</param>
/// <param name="direct">same meaning as OpcodeCall.Direct</param>
/// <param name="destination">if direct, then this is the function name</param>
/// <param name="calledFromKOSDelegateCall">true if KOSDelegate.Call() brought us here. If true that
/// means any pre-bound args are already on the stack. If false it means they aren't and this will have to
/// put them there.</param>
/// <returns>new IP to jump to, if this should be followed up by a jump. If -1 then it means don't jump.</returns>
public static int StaticExecute(ICpu cpu, bool direct, object destination, bool calledFromKOSDelegateCall)
{
object functionPointer;
object delegateReturn = null;
int newIP = -1; // new instruction pointer to jump to, next, if any.
if (direct)
{
functionPointer = cpu.GetValue(destination);
if (functionPointer == null)
throw new KOSException("Attempt to call function failed - Value of function pointer for " + destination + " is null.");
}
else // for indirect calls, dig down to find what's underneath the argument list in the stack and use that:
{
bool foundBottom = false;
int digDepth;
int argsCount = 0;
for (digDepth = 0; (! foundBottom) && digDepth < cpu.GetStackSize() ; ++digDepth)
{
object arg = cpu.PeekValue(digDepth);
if (arg != null && arg.GetType() == ArgMarkerType)
foundBottom = true;
else
++argsCount;
}
functionPointer = cpu.PeekValue(digDepth);
if (! ( functionPointer is Delegate || functionPointer is KOSDelegate || functionPointer is ISuffixResult))
{
// Indirect calls are meant to be delegates. If they are not, then that means the
// function parentheses were put on by the user when they weren't required. Just dig
// through the stack to the result of the getMember and skip the rest of the execute logic
// If args were passed to a non-method, then clean them off the stack, and complain:
if (argsCount>0)
{
for (int i=1 ; i<=argsCount; ++i)
cpu.PopValue();
throw new KOSArgumentMismatchException(
0, argsCount, "\n(In fact in this case the parentheses are entirely optional)");
}
cpu.PopValue(); // pop the ArgMarkerString too.
return -1;
}
}
// If it's a string it might not really be a built-in, it might still be a user func.
// Detect whether it's built-in, and if it's not, then convert it into the equivalent
// user func call by making it be an integer instruction pointer instead:
if (functionPointer is string || functionPointer is StringValue)
{
string functionName = functionPointer.ToString();
if (functionName.EndsWith("()"))
functionName = functionName.Substring(0, functionName.Length - 2);
if (!(cpu.BuiltInExists(functionName)))
{
// It is not a built-in, so instead get its value as a user function pointer variable, despite
// the fact that it's being called AS IF it was direct.
if (!functionName.EndsWith("*")) functionName = functionName + "*";
if (!functionName.StartsWith("$")) functionName = "$" + functionName;
functionPointer = cpu.GetValue(functionName);
}
}
KOSDelegate kosDelegate = functionPointer as KOSDelegate;
if (kosDelegate != null)
{
if (! calledFromKOSDelegateCall)
kosDelegate.InsertPreBoundArgs();
}
IUserDelegate userDelegate = functionPointer as IUserDelegate;
if (userDelegate != null)
functionPointer = userDelegate.EntryPoint;
BuiltinDelegate builtinDel = functionPointer as BuiltinDelegate;
if (builtinDel != null && (! calledFromKOSDelegateCall) )
functionPointer = builtinDel.Name;
// If the IP for a jump location got encapsulated as a user int when it got stored
// into the internal variable, then get the primitive int back out of it again:
ScalarIntValue userInt = functionPointer as ScalarIntValue;
if (userInt != null)
functionPointer = userInt.GetIntValue();
//.........这里部分代码省略.........
示例3: Execute
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;
}
示例4: Invoke
public void Invoke(ICpu cpu)
{
MethodInfo methInfo = del.Method;
ParameterInfo[] paramArray = methInfo.GetParameters();
var args = new List<object>();
var paramArrayArgs = new List<Structure>();
// Will be true iff the lastmost parameter of the delegate is using the C# 'param' keyword and thus
// expects the remainder of the arguments marshalled together into one array object.
bool isParamArrayArg = false;
CpuUtility.ReverseStackArgs(cpu, false);
for (int i = 0; i < paramArray.Length; ++i)
{
object arg = cpu.PopValue();
Type argType = arg.GetType();
ParameterInfo paramInfo = paramArray[i];
// If this is the lastmost parameter then it might be a 'param' array which expects all the rest of
// the arguments to be collected together into one single array parameter when invoking the method:
isParamArrayArg = (i == paramArray.Length - 1 && Attribute.IsDefined(paramInfo, typeof(ParamArrayAttribute)));
if (arg != null && arg.GetType() == CpuUtility.ArgMarkerType)
{
if (isParamArrayArg)
break; // with param arguments, you want to consume everything to the arg bottom - it's normal.
else
throw new KOSArgumentMismatchException(paramArray.Length, paramArray.Length - (i + 1));
}
// Either the expected type of this one parameter, or if it's a 'param' array as the last arg, then
// the expected type of that array's elements:
Type paramType = (isParamArrayArg ? paramInfo.ParameterType.GetElementType() : paramInfo.ParameterType);
// Parameter type-safe checking:
bool inheritable = paramType.IsAssignableFrom(argType);
if (!inheritable)
{
bool castError = false;
// If it's not directly assignable to the expected type, maybe it's "castable" to it:
try
{
arg = Convert.ChangeType(arg, Type.GetTypeCode(paramType));
}
catch (InvalidCastException)
{
throw new KOSCastException(argType, paramType);
}
catch (FormatException)
{
castError = true;
}
if (castError)
{
throw new Exception(string.Format("Argument {0}({1}) to method {2} should be {3} instead of {4}.", (paramArray.Length - i), arg, methInfo.Name, paramType.Name, argType));
}
}
if (isParamArrayArg)
{
paramArrayArgs.Add(Structure.FromPrimitiveWithAssert(arg));
--i; // keep hitting the last item in the param list again and again until a forced break because of arg bottom marker.
}
else
{
args.Add(Structure.FromPrimitiveWithAssert(arg));
}
}
if (isParamArrayArg)
{
// collect the param array args that were at the end into the one single
// array item that will be sent to the method when invoked:
args.Add(paramArrayArgs.ToArray());
}
// Consume the bottom marker under the args, which had better be
// immediately under the args we just popped, or the count was off.
if (!isParamArrayArg) // A param array arg will have already consumed the arg bottom mark.
{
bool foundArgMarker = false;
int numExtraArgs = 0;
while (cpu.GetStackSize() > 0 && !foundArgMarker)
{
object marker = cpu.PopValue();
if (marker != null && marker.GetType() == CpuUtility.ArgMarkerType)
foundArgMarker = true;
else
++numExtraArgs;
}
if (numExtraArgs > 0)
throw new KOSArgumentMismatchException(paramArray.Length, paramArray.Length + numExtraArgs);
}
// Delegate.DynamicInvoke expects a null, rather than an array of zero length, when
// there are no arguments to pass:
object[] argArray = (args.Count > 0) ? args.ToArray() : null;
try
{
// I could find no documentation on what DynamicInvoke returns when the delegate
// is a function returning void. Does it return a null? I don't know. So to avoid the
//.........这里部分代码省略.........
示例5: ExecuteDelegate
/// <summary>
/// Call this when executing a delegate function whose delegate object was stored on
/// the stack underneath the arguments. The code here is using reflection and complex
/// enough that it needed to be separated from the main Execute method.
/// </summary>
/// <param name="cpu">the cpu this opcode is being called on</param>
/// <param name="dlg">the delegate object this opcode is being called for.</param>
/// <returns>whatever object the delegate method returned</returns>
public static object ExecuteDelegate(ICpu cpu, Delegate dlg)
{
MethodInfo methInfo = dlg.Method;
ParameterInfo[] paramArray = methInfo.GetParameters();
var args = new List<object>();
// Iterating over parameter signature backward because stack:
for (int i = paramArray.Length - 1 ; i >= 0 ; --i)
{
object arg = cpu.PopValue();
if (arg != null && arg.GetType() == ArgMarkerType)
throw new KOSArgumentMismatchException(paramArray.Length, paramArray.Length - (i+1));
Type argType = arg.GetType();
ParameterInfo paramInfo = paramArray[i];
Type paramType = paramInfo.ParameterType;
// Parameter type-safe checking:
bool inheritable = paramType.IsAssignableFrom(argType);
if (! inheritable)
{
bool castError = false;
// If it's not directly assignable to the expected type, maybe it's "castable" to it:
try
{
arg = Convert.ChangeType(arg, Type.GetTypeCode(paramType));
}
catch (InvalidCastException)
{
throw new KOSCastException(argType, paramType);
}
catch (FormatException) {
castError = true;
}
if (castError) {
throw new Exception(string.Format("Argument {0}({1}) to method {2} should be {3} instead of {4}.", (paramArray.Length - i), arg, methInfo.Name, paramType.Name, argType));
}
}
args.Add(arg);
}
// Consume the bottom marker under the args, which had better be
// immediately under the args we just popped, or the count was off:
bool foundArgMarker = false;
int numExtraArgs = 0;
while (cpu.GetStackSize() > 0 && !foundArgMarker)
{
object marker = cpu.PopValue();
if (marker != null && marker.GetType() == ArgMarkerType)
foundArgMarker = true;
else
++numExtraArgs;
}
if (numExtraArgs > 0)
throw new KOSArgumentMismatchException(paramArray.Length, paramArray.Length + numExtraArgs);
args.Reverse(); // Put back in normal order instead of stack order.
// Dialog.DynamicInvoke expects a null, rather than an array of zero length, when
// there are no arguments to pass:
object[] argArray = (args.Count>0) ? args.ToArray() : null;
try
{
// I could find no documentation on what DynamicInvoke returns when the delegate
// is a function returning void. Does it return a null? I don't know. So to avoid the
// problem, I split this into these two cases:
if (methInfo.ReturnType == typeof(void))
{
dlg.DynamicInvoke(argArray);
return null; // So that the compiler building the opcodes for a function call statement doesn't
// have to know the function prototype to decide whether or
// not it needs to pop a value from the stack for the return value. By adding this,
// it can unconditionally assume there will be exactly 1 value left behind on the stack
// regardless of what function it was that was being called.
}
return dlg.DynamicInvoke(argArray);
}
catch (TargetInvocationException e)
{
// Annoyingly, calling DynamicInvoke on a delegate wraps any exceptions the delegate throws inside
// this TargetInvocationException, which hides them from the kOS user unless we do this:
if (e.InnerException != null)
throw e.InnerException;
throw;
}
}
示例6: Execute
public override void Execute(ICpu cpu)
{
object functionPointer;
object delegateReturn = null;
if (Direct)
{
functionPointer = cpu.GetValue(Destination);
if (functionPointer == null)
throw new KOSException("Attempt to call function failed - Value of function pointer for " + Destination + " is null.");
}
else // for indirect calls, dig down to find what's underneath the argument list in the stack and use that:
{
bool foundBottom = false;
int digDepth;
int argsCount = 0;
for (digDepth = 0; (! foundBottom) && digDepth < cpu.GetStackSize() ; ++digDepth)
{
object arg = cpu.PeekValue(digDepth);
if (arg != null && arg.GetType() == ArgMarkerType)
foundBottom = true;
else
++argsCount;
}
functionPointer = cpu.PeekValue(digDepth);
if (! ( functionPointer is Delegate))
{
// Indirect calls are meant to be delegates. If they are not, then that means the
// function parentheses were put on by the user when they weren't required. Just dig
// through the stack to the result of the getMember and skip the rest of the execute logic
// If args were passed to a non-method, then clean them off the stack, and complain:
if (argsCount>0)
{
for (int i=1 ; i<=argsCount; ++i)
cpu.PopValue();
throw new KOSArgumentMismatchException(
0, argsCount, "\n(In fact in this case the parentheses are entirely optional)");
}
cpu.PopValue(); // pop the ArgMarkerString too.
return;
}
}
// If it's a string it might not really be a built-in, it might still be a user func.
// Detect whether it's built-in, and if it's not, then convert it into the equivalent
// user func call by making it be an integer instruction pointer instead:
if (functionPointer is string)
{
string functionName = functionPointer as string;
if (functionName.EndsWith("()"))
functionName = functionName.Substring(0, functionName.Length - 2);
if (!(cpu.BuiltInExists(functionName)))
{
// It is not a built-in, so instead get its value as a user function pointer variable, despite
// the fact that it's being called AS IF it was direct.
if (!functionName.EndsWith("*")) functionName = functionName + "*";
if (!functionName.StartsWith("$")) functionName = "$" + functionName;
functionPointer = cpu.GetValue(functionName);
}
}
IUserDelegate userDelegate = functionPointer as IUserDelegate;
if (userDelegate != null)
functionPointer = userDelegate.EntryPoint;
if (functionPointer is int)
{
ReverseStackArgs(cpu);
int currentPointer = cpu.InstructionPointer;
DeltaInstructionPointer = (int)functionPointer - currentPointer;
var contextRecord = new SubroutineContext(currentPointer+1);
cpu.PushAboveStack(contextRecord);
if (userDelegate != null)
{
cpu.AssertValidDelegateCall(userDelegate);
// Reverse-push the closure's scope record, just after the function return context got put on the stack.
for (int i = userDelegate.Closure.Count - 1 ; i >= 0 ; --i)
cpu.PushAboveStack(userDelegate.Closure[i]);
}
}
else if (functionPointer is string)
{
// Built-ins don't need to dereference the stack values because they
// don't leave the scope - they're not implemented that way. But later we
// might want to change that.
var name = functionPointer as string;
string functionName = name;
if (functionName.EndsWith("()"))
functionName = functionName.Substring(0, functionName.Length - 2);
cpu.CallBuiltinFunction(functionName);
}
else if (functionPointer is Delegate)
{
delegateReturn = ExecuteDelegate(cpu, (Delegate)functionPointer);
}
else
{
// This is one of those "the user had better NEVER see this error" sorts of messages that's here to keep us in check:
throw new Exception(
string.Format("kOS internal error: OpcodeCall calling a function described using {0} which is of type {1} and kOS doesn't know how to call that.", functionPointer, functionPointer.GetType().Name)
//.........这里部分代码省略.........