-
Notifications
You must be signed in to change notification settings - Fork 424
Conversation
Looking into the tests more, I thought that the ordering here mattered but it doesn't seem to matter as this is the order of how the React Reconciler takes conditions – which seems to have flipper from before so I think this is actually fine. Unfortunately, the same It appears that https://support.circleci.com/hc/en-us/articles/360007188574-Build-has-hit-timeout-limit |
src/evaluators/BinaryExpression.js
Outdated
@@ -284,7 +285,8 @@ export function computeBinary( | |||
|
|||
if (isPure && effects) { | |||
realm.applyEffects(effects); | |||
return realm.returnOrThrowCompletion(effects.result); | |||
if (effects.result instanceof SimpleNormalCompletion) return effects.result.value; | |||
effects.result; |
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.
return effects.result;
?
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.
Actually no, that is debugging code that got left in. I'll remove.
@hermanventer Sorry, this only seems to occur with |
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 feel like the simplifier rules are becoming quite problematic to write and rewrite. We need a more principled approach. Maybe not Z3 based, but there should be some kind of term rewriting system that we should be able to leverage, to write and verify rules and to generate code from it.
And instead of poking around narrow patterns, there should be normal forms, and efficient ways to encode the boolean structures...
src/methods/join.js
Outdated
joinValuesOfSelectedCompletions( | ||
selector: Completion => boolean, | ||
completion: Completion, | ||
keepInfeasiblePaths: boolean = false |
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.
Why would it ever be desirable to keep infeasible paths?
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.
It is not desirable, but a hack to work around the fact that generator.emitConditionalThrow wants a value for its parameter. Fixing that to take the completion instead would be preferable. For this PR, however, that seems out of scope.
src/utils/generator.js
Outdated
@@ -597,7 +597,7 @@ export class Generator { | |||
} else if (result instanceof JoinedNormalAndAbruptCompletions) { | |||
let selector = c => | |||
c instanceof ThrowCompletion && c.value !== realm.intrinsics.__bottomValue && !(c.value instanceof EmptyValue); | |||
output.emitConditionalThrow(Join.joinValuesOfSelectedCompletions(selector, result)); | |||
output.emitConditionalThrow(Join.joinValuesOfSelectedCompletions(selector, result, true)); |
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.
It's hard to tell from the callsite what the , true
argument means. Maybe make it named?
Why don't you want to keepInfeasiblePaths
here?
src/utils/simplifier.js
Outdated
if (y instanceof AbstractValue && y.kind === "||") { | ||
// x || x || y <=> x || y | ||
if (x.equals(y.args[0])) return y; | ||
// y || x || y <=> x || y |
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 comment seems to be missing code.
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'll delete the comment.
src/utils/simplifier.js
Outdated
if (x.equals(y.args[0])) return y; | ||
// y || x || y <=> x || y | ||
if (x instanceof AbstractValue && x.kind === "!") { | ||
// !x || x || y <=> y |
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 (and the next) rule seems wrong, unless I am missing some special JavaScript craziness.
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.
The comment is correct if you don't equate the meta variable x with the comment variable x. I'll update the comment to make it more difficult to equate them.
src/utils/simplifier.js
Outdated
// y && (x && y) <=> x && y | ||
if (x.equals(y.args[0]) || x.equals(y.args[1])) return y; | ||
} | ||
// x && (x && y || x && z) <=> x && (y && z) |
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.
The comment seems wrong, while the implementation may be correct.
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.
The comment tries to communicate the pattern in the most abstract way. The code does not follow the names in the comment when things get complicated.
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 think the comment should be // x && (x && y || x && z) <=> x && (y || z)
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.
At this stage, rewriting the simplifier does not seem like a top priority. It certainly is out of scope for this PR.
src/utils/simplifier.js
Outdated
if (y instanceof AbstractValue && y.kind === "||") { | ||
// x || x || y <=> x || y | ||
if (x.equals(y.args[0])) return y; | ||
// y || x || y <=> x || y |
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'll delete the comment.
src/utils/simplifier.js
Outdated
if (x.equals(y.args[0])) return y; | ||
// y || x || y <=> x || y | ||
if (x instanceof AbstractValue && x.kind === "!") { | ||
// !x || x || y <=> y |
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.
The comment is correct if you don't equate the meta variable x with the comment variable x. I'll update the comment to make it more difficult to equate them.
src/utils/simplifier.js
Outdated
// y && (x && y) <=> x && y | ||
if (x.equals(y.args[0]) || x.equals(y.args[1])) return y; | ||
} | ||
// x && (x && y || x && z) <=> x && (y && z) |
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.
The comment tries to communicate the pattern in the most abstract way. The code does not follow the names in the comment when things get complicated.
src/utils/simplifier.js
Outdated
// y && (x && y) <=> x && y | ||
if (x.equals(y.args[0]) || x.equals(y.args[1])) return y; | ||
} | ||
// x && (x && y || x && z) <=> x && (y && z) |
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 think the comment should be // x && (x && y || x && z) <=> x && (y || z)
src/utils/simplifier.js
Outdated
if (x.equals(y.args[0])) return y; | ||
if (x instanceof AbstractValue && x.kind === "!") { | ||
// !x0 || x0 || y1 <=> y1 | ||
if (x.args[0].equals(y.args[0])) return y.args[1]; |
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 still seems wrong to me. !x || x || y
should be equivalent to true
, not y
.
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.
Duh! I'll remove this.
9bdea56
to
40228ef
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.
hermanventer has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
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.
hermanventer has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
src/utils/simplifier.js
Outdated
// x || x || y <=> x || y | ||
if (x.equals(y.args[0])) return y; | ||
if (x instanceof AbstractValue && x.kind === "!") { | ||
// !x0 || y0 || x0 <=> y0 |
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 seems wrong to me. !x0 || ... || x0
is true
, not equivalent to some random 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.
Correct. Moreover, only if isCondition is true.
src/utils/simplifier.js
Outdated
if (x.args[0].equals(y) || x.args[1].equals(y)) return x; | ||
} else if (x.kind === "!") { | ||
// !x && x <=> false | ||
if (x.args[0].equals(y)) return realm.intrinsics.false; |
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.
Only if isCondition
, right?
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.
Correct.
c69d7d8
to
f22c424
Compare
@trueadm Sadly, the internal React test is failing, presumably because of exceeding implies limits (a lot of those appear in the log output). Could you have a look and give a prognosis of how fixable this may be? It might be necessary to make some changes so that simplification has a better worst case complexity. (And that may not be easy at all.) |
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.
hermanventer has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
src/utils/simplifier.js
Outdated
if (x.kind === "&&") { | ||
// (x && y) && x <=> x && y | ||
// (x && y) && y <=> x && y | ||
if (x.args[0].equals(y) || x.args[1].equals(y)) return x; |
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.
Thinking about it, the first one is actually only valid if isCondition
without reordering: (1 && 2) && 1
vs 1 && 2
.
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.
Good catch.
This PR is currently failing the internal React bundle test with an invariant in _getTarget in the serializer. I'll dig into it today and see if I can see if there's anything obvious. |
Summary: Release note: Speed up simplifier by using an implication cache per path branch The realm's path conditions is now a class instances and an explicit tree, along with caches for expressions that have already been checked for true/false using Path.implies on the current set of path conditions. The AbstractValueImplicationCounter is still there as flag, to be renamed later. It is no longer used as a global k-limit, but enables k-limits on the cost of constructing a new set of path conditions. When React is the target, path conditions are not re-specialized. This leads to a very nice performance win for the large React internal test. A number of tweaks to the simplifier were needed to get tests to pass. Some of these were borrowed from PR #2460. Pull Request resolved: #2494 Reviewed By: trueadm Differential Revision: D9554820 Pulled By: hermanventer fbshipit-source-id: 5fdc550499975fe11c0c954b9502cd4eeab2bafe
Summary: Release note: none This fixes two problems uncovered while debugging the failure of PR #2460 when run on a large internal test case: 1) CSE did not fix up recently introduced aliases of expressions. 2) The serializer logic visited array elements that were not visited because of recently introduced leak logic. Pull Request resolved: #2516 Differential Revision: D9599235 Pulled By: hermanventer fbshipit-source-id: a2047227b4aa2e0e2def7d8e7ebe0724a9525160
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.
hermanventer has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.
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.
LGTM, merging as this is blocker for others.
Release note: none
Closes #2435
Closes #1829
Join.composeWithEffects composes a forked completion with subsequent effects. When two or more forks could end normally, this could result in shallow copies of the subsequent effects. These were then joined together and applied, so it was mostly OK. The generator of the subsequent effects, however, ended up being joined with itself and thus transformed the generator tree to a DAG, which is not desirable for the serializer.
The new approach is to extract a join condition from the forked completion and using it to join the subsequent effects with a newly constructed empty effects. The condition ensures that the subsequent effects are applied only in situations where the forked completion is not abrupt.
Extracting this condition makes for complicated abstract expressions and this uncovered some existing bugs and limitations that are also addressed in this pull request. As a side effect, path conditions are now longer and the time to compile unrolled loops with conditional abrupt completions inside their bodies has gone up so much that the unroll limit had to be lowered.
Please note that the expected output React tests has changed because of re-ordering. I'm none too sure that this re-ordering is necessarily benign, so please review carefully.