-
Notifications
You must be signed in to change notification settings - Fork 317
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Short-circuiting || and && #3492
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have to admit I cannot imagine how these changes reflect in the shape of our IGV graphs. It is certainly desirable to verify things like instanceof DataflowError
or makeTypeError
don't appear in graphs that are trained just with Boolean
.
engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/OrNode.java
Outdated
Show resolved
Hide resolved
engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/OrNode.java
Outdated
Show resolved
Hide resolved
7ef43d7
to
4fb0842
Compare
engine/runtime/src/main/java/org/enso/interpreter/node/expression/builtin/bool/AndNode.java
Outdated
Show resolved
Hide resolved
fdb2c0e
to
caaa5bf
Compare
Lazy evaluation of RHS for || and && is typically taken for granted by users of other PLs. This change makes it happen for Enso.
Pushed lhs guard check inside the specialization so as to prevent potentially continuous flipping between optimized and deoptimized version, depending on the LHS value. Simple benchmarks showed 10x improvement compared to the previous solution.
Rather than using multiple specializations in AndNode/OrNode and various instance checks, it seems Truffle is able to better optimize potential DataflowError/Panic by delegating to a separate Node. Benchmarks also appear to be happier that way.
4cf6665
to
73716eb
Compare
@Suspend Object that, | ||
@Cached("build()") ThunkExecutorNode rhsThunkExecutorNode, | ||
@Cached("build()") ToBoolNode ensureBoolNode) { | ||
if (!_this) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To make sure the compiler really understands this method, use a profile for this condition.
return new Stateful(state, false); | ||
} | ||
Stateful result = | ||
rhsThunkExecutorNode.executeThunk(that, state, BaseNode.TailStatus.TAIL_DIRECT); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not a TAIL_DIRECT
, it's a NON_TAIL
. TAIL_DIRECT
is not guaranteed to return in this method (may unwind)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OTOH I wonder if we really want that type check? Given we don't actually depend on the expression evaluating to bool? Why not just return the result of executeThunk
?
return ToBoolNodeGen.create(); | ||
} | ||
|
||
abstract Stateful execute(@MonadicState Object state, Object value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should not return a Stateful
, it's not the node's responsibility – the point of this node is "make sure my arg is a bool", so just return a boolean.
import org.enso.interpreter.runtime.state.Stateful; | ||
|
||
@NodeInfo(description = "Helper node to handle Bool values that can also return DataflowErrors") | ||
public abstract class ToBoolNode extends Node { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A convention we use is to call such throwing conversions ExpectBoolNode
. ToBoolNode
suggests you can convert anything.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was to quick to submit the previous review – so here comes the prose. The more I think about the result casting, the less I like it. I'd just allow any return type and not verify it. It's like if you implemented these in Enso:
Boolean.|| ~that = if this then this else that
You wouldn't check the result type in this impl, and I think we should follow this thinking here.
In that case the type of |
No, we should leave the type as is – it is normal for a type signature to be more restrictive than the implementation :) |
@kustosz as discussed |
02f707e
to
651ea32
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's more simplification to do :)
Pull Request Description
Short-circuiting || and && is typically taken for granted
by users of other PLs. This change makes it happen for Enso.
Related to https://www.pivotaltracker.com/story/show/182261401
Checklist
Please include the following checklist in your PR:
Scala,
Java,
and
Rust
style guides.
./run.sh ide dist
and./run.sh ide watch
.