Just-in-time (JIT) binding

Carl Sassenrath, CTO
REBOL Technologies
11-Apr-2006 16:39 GMT

Article #0010
Main page || Index || Prior Article [0009] || Next Article [0011] || 21 Comments || Send feedback

REBOL 3.0 will introduce a new type of binding: just-in-time (JIT) binding. This is a long article, but I thought you would be interested in the details, and I know you will not be shy in providing your comments.

Currently, REBOL supports two types of binding:

 Definitional Context Binding (DCB)Binding that occurs when you define a block of data as the body of a specific datatype or context. This is the normal REBOL binding as implemented by the bind function. For example, the variables of a function are bound to the function body when the make function! operation is performed (or mezz function like func, function, etc.)

 Late Path Binding (LPB)Binding that occurs when you use a path that contains symbolic fields. This very late binding occurs during the evaluation of the path itself. This happens mainly when you access the fields of an object, and it is done so late to allow the fields to be variables themselves.

These binding methods work fine for normal REBOL code; however, when processing dialects of REBOL, they provide no benefit because the words of the dialect never undergo definitional processing. Dialects are just blocks, not specialized datatypes such as functions or objects.

During the implementation of the Rebcode project (which created a unique model for a high performance REBOL virtual machine), it became obvious that a very fast lookup method was needed for the opcodes of the VM. When you specify an add or sub you don't want the interpreter wasting any time trying to figure out what those opcode actually mean.

Two solutions became obvious: use DCB or come up with a new type of late binding, which for lack of a better term I will call just-in-time binding (JIT). Both methods were considered; however, because Rebcode was embodied in a function wrapper, it had the opportunity for definitional processing. In addition, modification of Rebcode blocks is not allowed after definition. So DCB was perfect and improved the speed of Rebcode by three or four times.

So, what about other REBOL dialects? Can the performance of dialects like draw and parse be improved? Yes, they can. Take the draw dialect as an example. The keywords (commands) of the dialect are evaluated quickly, but for large blocks (such as a large SVG image), performance could be better. A significant amount of time is required resolving the keywords each time the draw block is evaluated.

Rebcode was implemented using the technique where a dialect context defined the words of the dialect, and DCB was used to bind the dialect block to that context. There is nothing fancy here. However, this DCB method does not work well for dialect blocks like draw, which are allowed to change dynamically. For instance, during an animation the programmer may insert or remove commands in/from the draw block. Such changes would invalidate the work done by a DCB process, but the alternative would be to burden the programmer with maintaining the bindings manually during each insertion, and we would prefer to avoid that.

Here enters JIT binding. In JIT, words are bound to the context as they are encountered during the evaluation stream. Unlike LPB, the words of the block are modified to hold their new bindings. They are sticky. The next time the block is evaluated only a quick check of the word's context is required, and no other action is needed. If a new word has been inserted, the check fails, and the JIT bind occurs.

The result is that dialects like draw and parse can evaluate much faster, but without the need to prebind the words of the dialect block. And, if the block remains substantially un-modified, the evaluation speed of the dialect is very close to that of pure REBOL code (requiring only the extra context check for each word).

Is there a downside to this method? Yes. Good design is all about managing tradeoffs. It takes a small amount of time to setup the JIT bind method prior to dialect evaluation. For very short blocks that contain less than three or four keywords, the overhead of the JIT setup could slow those blocks down. This is the kind of thing we will need to test and evaluate. There may also be a slight penalty for exceptions (errors, breaks, returns, throws) that occur during evaluation of JIT dialects; however, such events should be rare for most dialected code.

In conclusion: JIT binding is really just a evaluation-time style of definitional context binding. It is believed that this type of binding could provide substantial additional performance for the dialects used in draw, parse, and others. It is also possible that we could use JIT in place of LPB to improve performance for object field access. That must be studied.

Note: this concept is still in the early design stage, and we should know more soon. If you have any comments on this idea, I know that you will happily post them here. Thanks.


Updated 24-Mar-2017 - Edit - Copyright REBOL Technologies -