In the previous article, we saw how to compile functions and handle their scopes. We also saw how to optimize a certain kind of function calls, the tail call ones in Understanding tail call optimization, now we are going to see yet another optimization, this time on conditions and expression evaluation.
# Basic way to deal with conditionals
Following the previous article(s), we could implement and
/ or
as follows:
|
|
As you can see, each argument have to be evaluated before calling the operator, which is not something we might want! In mainstream languages like C, C++, Java, Python… the expression a and b
would evaluate b
only if a
is true. If a
is false, no need to evaluate the rest of the expression: it will be false. Same thing goes for or
, if a
is true, no need to evaluate the rest of the expression: it will be true.
# Understanding how short-circuiting works
What we want is evaluate arguments one at a time in an expression, and immediately stop if we have a false in an and
expression, or true in an or
expression. In Python you could write it like this:
|
|
- (and) We check if
a
is true, if not do nothing. Otherwise, evaluateb
and act accordingly. - (or) We check if
a
is true and execute our code. Otherwise evaluateb
and if true execute our code.
# Implementation in bytecode
Let’s see how and
is implemented in ArkScript (as of 16/09/2024):
|
|
- We load our
a
variable as before and duplicate it - We duplicate it for later use
- We pop the duplicate, if it is false we jump after the expression, on the next instruction (which could be a store or another compare ; thanks to the duplicate, we still have the false value here at the end
- If it is true, we pop the original value, we don’t need it anymore and just load
b
. As in3.
we continue with no special treatment with the next instruction, now having our boolean loaded to compare it, store it…
And that’s it, we don’t have to have a specific implementation to handle if a and b
and val = a and b
separately, as we jump on the next instruction, which might be a POP_JUMP_IF_FALSE
in the case of a condition (to avoid executing the code of the condition), or a STORE
in case of a variable assignment.
[!NOTE] Implementing
or
would be practically identical, apart from thePOP_JUMP_IF_FALSE
instruction that would be aPOP_JUMP_IF_TRUE
!