3

Background: I am programming a .NET compiler (very similar to C#) for a school project. One of the features I am currently trying to add is tailcall recursion within methods.

More info: In CIL, the "this" is passed into instance methods as if it were just another argument. So, accessing the first argument of a static method, you would emit ldarg.0, but accessing the first argument of an instance method, you would emit ldarg.1, and accessing "this" in an instance method you would emit ldarg.0. (Instance methods are even more similar to extension methods than I ever imagined.)

Question: Can you set "this" using starg.0 without any side effects?

Why this is in question: Whether or not a method is an instance method is set with the MethodBuilder, which is a bit of a black box. Although "this" seems just like any other argument, for all I know some JIT compilers keep track of "this" separately and change their behavior depending on this value. If there are side effects when you set "this" in an instance method, then how can I avoid them?

McKay
  • 12,334
  • 7
  • 53
  • 76
leviathanbadger
  • 1,682
  • 15
  • 23
  • While it's an interesting question, I'd like to add you're asking about what I think will be a corner case: your question only matters if tailcalling the current method on a different class instance. Tailcalling a different method is not possible the way you describe anyway, and tailcalling the current method with the same `this` doesn't need a modification of argument 0. –  Feb 09 '12 at 00:03

2 Answers2

2

You may want to have a look at how F# implements tail-call.

Chris Shain
  • 50,833
  • 6
  • 93
  • 125
  • I said this in a comment below as well, but I'll repeat it here. Looking back, I didn't ask what I actually meant, just how to fix a symptom of it. It was an honest mistake, but I'm sorry I was misleading anyway. – leviathanbadger Feb 09 '12 at 00:35
1

You can extract this as a local variable. This way you will know that you can set it safely. (I hope I understand your question correctly)

Stilgar
  • 22,354
  • 14
  • 64
  • 101
  • This doesn't solve the problem - the same side effects that will happen if you just emit starg.0 and act on the assumption that the JIT compiler is updated as well. Thanks for the answer, though. – leviathanbadger Feb 08 '12 at 23:55
  • @aboveyou00 This is a correct answer, even if `starg.0` is unsafe (I don't see why it would be, but I don't know for sure), using an extra variable in place of argument 0 definitely must be safe. –  Feb 09 '12 at 00:06
  • So you are worried that the JIT compiler will keep track of "this" even if you pass the reference to a local variable? – Stilgar Feb 09 '12 at 00:06
  • I don't mean that the JIT would modify arg.0 behind your back, I mean that they might not check for your own modification and that that might affect code execution in a subtle way. In any case, Chris Shain answered my question. See his post above, and the eventual resultant MSDN page: [OpCodes.TailCall Field](http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.tailcall.aspx) – leviathanbadger Feb 09 '12 at 00:11
  • @aboveyou00 For the first part, yes, but if you have arg.0 in a local variable, and use that local variable throughout your method, you don't need to change arg.0, so the question of whether changes to arg.0 cause problems becomes moot. –  Feb 09 '12 at 00:18
  • 1
    @aboveyou00 For the second part, OpCodes.TailCall doesn't have too much to do with the question as you asked it. OpCodes.TailCall is about letting the .NET runtime perform tail call optimisation (and changing any arguments is unnecessary for that), while the question you asked (perhaps not the one you meant to ask) is about a compiler performing the tail call optimisation. But it would be interesting to attempt to implement both, and I'm glad you found what you were looking for. –  Feb 09 '12 at 00:19
  • It was interesting to learn of the existance of the tail op code – Stilgar Feb 09 '12 at 00:22
  • @hvd For the most part, good point. I suppose that I picked the solution to my problem as a whole, rather than the literal "answer." Looking back at my original post, I don't think I asked what I meant in the first place. For that, I'm sorry. But I'll leave the answer as it currently stands, because it was more useful to me. – leviathanbadger Feb 09 '12 at 00:32