🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Oh noes, we aer teh borked!

Published March 10, 2009
Advertisement
My happy little scheme to eliminate shared state and cross-task side effects has hit a major speed bump.

The problem, in particular, is that we can't do a naive traversal of the code tree to detect all side effects. As long as we don't use any higher-order functions, it's fine and actually fairly simple to ensure that all side effects are contained correctly.

However, as soon as a higher-order function is involved, we run into problems. Consider this simple case:

entrypoint : () -> (){	task(async1)	{		foobar()	}}foobar : () -> (){	shellfunction(borken)	}shellfunction : (function op : () -> ()) -> (){	op()}borken : () -> (){	debugwritestring("Oh noes! We borked the task checker!")}



The debugwritestring operation is flagged as unsafe for using from tasks, since it may cause contention for the console. Normally, the usage of an unsafe function would be caught, and a compile-time error would be thrown.

However, since we only invoke the borken function indirectly via a higher-order function, the error is missed. At compile time, the op parameter of shellfunction is not bound to anything, so there is no way to tell what function might be passed. Without any bindings, the function call is ignored, and the program traversal walks right past the obvious error without even blinking.


The solution, of course, is to build a tree of higher-order function calls and test every potential code path that might invoke such a function. This may prove complicated and even slow, but it only needs to be done once - at compile time - and at runtime things will be just as simple and fast.

(Technically, because of the way the VM is architected, you can actually do illegal things by writing EpochASM code directly, or even bytecode. Since a lot of safety checks are only done at compile time, you can do some pretty cool hacks if you're willing to get dirty and play with the VM's guts.)


So my big challenge of the day is to come up with a way to handle the higher-order function case during the validation traversal.

Aside from that one hangup, tasks are working great. My goal is to get message passing implemented within the next week, so I have a few days spare to polish everything up and write the pitch documents for GDC.
0 likes 2 comments

Comments

choffstein
Well, if you are already generating an AST, isn't it simple to flag your way up the tree if a node is found to be unsafe?

E.g. debugstring is unsafe, so borken is unsafe. borken is referenced in foobar, so foobar is unsafe. Therefore, the code should regurgitate an 'unsafe'. So really, you just need 1 unsafe flag per function. Start at the bottom of your AST and work your way up...

Then again, this also would assume that anytime you have 'f(a)' in your code, and you generate your AST, you aren't creating a new node for f. Instead, all nodes that contain f point to the same f node. So in your example, all references in the AST to 'borken' would point to the same function node. It requires a bit more 'linking' of the tree, but makes propagating 'unsafe' markers up pretty easy.
March 10, 2009 02:25 PM
ApochPiQ
The problem isn't really traversing the code tree; the problem is that bindings for higher order functions don't exist at compile time. The fact that the borken function is called at all is not known statically, aside from some sneakiness to ensure that the function parameters match the required signature. In other words, there's no branch of the AST to actually traverse at compile time - it's built on the fly when the code invokes a higher order function.

The fix is pretty simple, though - all I have to do is look for instructions that push function references onto the stack. We can then do a temporary, speculative binding of the function reference, and therefore traverse that branch of the tree.
March 10, 2009 04:27 PM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement
Advertisement