MSIL Indirect Goto?

  • Thread starter Thread starter paul.at.gmail
  • Start date Start date
P

paul.at.gmail

I am starting experimenting with IL code generation for a Forth-like
stack-based language that uses the CLR evaluation stack as the
Parameter stack (i.e. not a call stack) and a separate array for the
call stack. Therefore I expect I must avoid the IL ret instruction,
which enforces an empty evaluation stack on method return. To achieve
this I need to perform an indirect branch or jump as suggested below.
Does anyone know how to achieve this indirect jump efficiently in IL?

..method private hidebysig static void MyMethod() cil managed
{
.entrypoint
.maxstack 2
stind stackPtr // push the return address on the seperate call stack
ldsfld stackPtr // increment the stack pointer
ldc.i4.1
add
stsfld stackPtr
:
..execute the method..
:
// I don't want to use ret therefore...
ldsfld stackPtr
ldc.i4.1
sub
stsfld stackPtr
ldind stackPtr
?? // bra indirect or similar required here
}
 
paul.at.gmail said:
I am starting experimenting with IL code generation for a Forth-like
stack-based language that uses the CLR evaluation stack as the
Parameter stack (i.e. not a call stack) and a separate array for the
call stack. Therefore I expect I must avoid the IL ret instruction,
which enforces an empty evaluation stack on method return. To achieve
this I need to perform an indirect branch or jump as suggested below.
Does anyone know how to achieve this indirect jump efficiently in IL?

I don't believe there is. AFAIK the runtime does not let you branch outside
of the current method.

I am curious, is this the right way to go about things? Is there a good
reason for using the evaluation stack as a parameter stack instead of using
it as the call stack it wants to be? What precisely is the reason you want
to try to force the runtime into working differently than it is really
designed to?
 
I want to compare how a stack-based language (like Forth) would use the
CLR stack model with how a conventional language (e.g. C#) uses it.
Forth has two stacks - a Parameter stack and a Return stack. The CLR
implements a single stack and uses it for both purposes. In Forth, the
Parameter stack is a global resource and not restricted to the scope of
a single method (word in Forth), hence the workaround required. I agree
I am trying to workaround the designed CLR behaviour, which will
introduce inefficiencies and defeat my objective of making best use of
a (virtual) stack machine with a stack-oriented high-level language.

BTW, I think the following may be a solution:

..method private hidebysig static void MyMethod() cil managed
{
stind stackPtr // push the return address on the seperate call stack
ldsfld stackPtr // increment the stack pointer
ldc.i4.1
add
stsfld stackPtr
:
..execute the method..
:
call void _MyRet()
}

..method private hidebysig static void _MyRet() cil managed
{
pop // Discard the MyMethod() return address
ldsfld stackPtr
ldc.i4.1
sub
stsfld stackPtr
ldind stackPtr
ret // Returns to the caller of MyMethod()
}

What do you think?
 
paul.at.gmail said:
I want to compare how a stack-based language (like Forth) would use the
CLR stack model with how a conventional language (e.g. C#) uses it.
Forth has two stacks - a Parameter stack and a Return stack. The CLR
implements a single stack and uses it for both purposes. In Forth, the
Parameter stack is a global resource and not restricted to the scope of
a single method (word in Forth), hence the workaround required. I agree
I am trying to workaround the designed CLR behaviour, which will
introduce inefficiencies and defeat my objective of making best use of
a (virtual) stack machine with a stack-oriented high-level language.

Ahh, I see. Its messy, and I know hte CLR has some problems with alot of
less conventional languages. Good luck.
BTW, I think the following may be a solution:

.method private hidebysig static void MyMethod() cil managed
{
stind stackPtr // push the return address on the seperate call stack
ldsfld stackPtr // increment the stack pointer
ldc.i4.1
add
stsfld stackPtr
:
..execute the method..
:
call void _MyRet()
}

.method private hidebysig static void _MyRet() cil managed
{
pop // Discard the MyMethod() return address
ldsfld stackPtr
ldc.i4.1
sub
stsfld stackPtr
ldind stackPtr
ret // Returns to the caller of MyMethod()
}

What do you think?

It looks like it will work, assuming the CLR doesn't balk at it(didn't try
it.) It is still messy, and either swaping the stacks around or using a
three stack approach where both the parameter and the return stacks are
arrays and the CLR stack is just an implementation detail that you use to
make the system work would be cleaner, but perhaps contrary to your efforts.
Again, good luck.
 
Back
Top