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 inUnderstanding 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 implementand
/or
as follows:
# a and bLOAD aLOAD bAND# foo() and bar()LOAD fooCALL 0LOAD barCALL 0AND
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 expressiona and b
would evaluateb
only ifa
istrue. Ifa
isfalse, no need to evaluate the rest of the expression: it will befalse. Same thing goes foror
, ifa
istrue, no need to evaluate the rest of the expression: it will betrue.
Understanding how short-circuiting works
What we want is evaluate arguments one at a time in an expression, and immediately stop if we have afalse in anand
expression, ortrue in anor
expression. In Python you could write it like this:
ifaandb:print("hello")# vvvifa:ifb:print("hello")# else: ...# -----------------ifaorb:print("hello")# vvvifa:print("hello")# <-+--- this is exactly the same code,else:# | actually not duplicated onceifb:# | compiled.print("hello")# <-/
- (and) We check if
a
istrue, if not do nothing. Otherwise, evaluateb
and act accordingly. - (or) We check if
a
istrue and execute our code. Otherwise evaluateb
and iftrue execute our code.
Implementation in bytecode
Let's see howand
is implemented inArkScript (as of 16/09/2024):
LOAD_SYMBOL aDUPPOP_JUMP_IF_FALSE (after) ---`POP |LOAD_SYMBOL b | <-----------+
- We load our
a
variable as before and duplicate it - We duplicate it for later use
- We pop the duplicate, if it isfalse we jump after the expression, on the next instruction (which could be a store or another compare ; thanks to the duplicate, we still have thefalse value here at the end
- If it istrue, 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 handleif a and b
andval = a and b
separately, as we jump on the next instruction, which might be aPOP_JUMP_IF_FALSE
in the case of a condition (to avoid executing the code of the condition), or aSTORE
in case of a variable assignment.
[!NOTE]
Implementingor
would be practically identical, apart from thePOP_JUMP_IF_FALSE
instruction that would be aPOP_JUMP_IF_TRUE
!
Originally fromlexp.lt
Top comments(0)
For further actions, you may consider blocking this person and/orreporting abuse