Hi,
A while back I announced that I was working on a .NET to PIR translator for
my final year project at uni. In case you've ever pondered how well it's
doing, and you don't read Planet Parrot or my blog, the answer is "pretty
well". So far I'm successfully translating:
* Parameters
* Local variables
* Arithemtic and logical ops
* Int/float type conversion
* Checked arithmetic and conversion ops
* Conditional ops and branches
* Non-static method calling, virtual method calling and field access for
classes in the same assembly
* Instructions relating to arrays
* Object instantiation, kinda, but missing the all important constructor
call
Which brings me to about 140 of the 215 instructions there are to translate.
Anyway, onto the real point of the email.
.NET has these managed reference thingies. They're basically like pointers,
but safe. What makes them safe is that only certain instructions can create
them and the pointer value can't be set directly (we can do that fine - just
have a PMC with an underlying struct that hold the pointer, but provide no
PMC methods that set that pointer).
Making them work on Parrot is no problem. Making them work without
comprimising the safety of the VM is harder. Amongst the things you can get
a pointer to are parameters and local variables. Under .NET that means
stack locations; with Parrot that means registers. So, imagine this.
1) Get reference to local in the current method
2) Stash that reference somewhere so it lasts longer than the current
method's context does, or just return it
3) Assigns to that reference later => BANG! Segfault, or perhaps controlled
scribbling to evade security policies etc
Under .NET we have info to track statically where managed references go so
we can do escape analysis before ever running the code to check it is safe
to run. A .NET VM can implement this just fine. However, on Parrot we
can't do this - statically we only know that a P register could hold any old
PMC.
Some discussion on IRC later, leo had come up with two suggestions for
handling this.
1) A two part solution.
a) Make set an MMD operation. This way, a .NET managed reference PMC knows
when it may be about to escape and can say "hey, this ain't allowed" in an
exceptionesque kinda way.
b) Add a v-table flag saying "returning me is forbidden" and checking that
on any PMCs that get returned. (However, there are subtle issues. For
example, we want to be able to pass the PMC to methods that are called from
this one - after all, it's how byref passing is implemented. But with tail
calls we should probably not do it. Also haven't yet pondered if closures
or co-routines may lead to some kinda leakage.)
2) Add a new Reference register type. We have INSP, so we'd also have R too
(perhaps). R registers would only have a very limited set of possible
operations that could be performed on them; not being able to return them
would be one of these. They shouldn't cause an opcode explosion as you
won't be able to do that much with them, so few ops that exist now would be
useful to act upon them. Obviously, you wouldn't be able to assign just any
address to them either. They should be useful beyond running .NET code too.
Of course, adding these would require some effort.
Maybe someone has an idea for a better way. Anyhow, that's the problem and
the ideas so far. Comments and suggestions very welcome.
Thanks,
Jonathan