Skip to content
This repository has been archived by the owner on Feb 12, 2022. It is now read-only.

Enable and constrain optimized array operator support for InstantRender #2547

Closed
wants to merge 5 commits into from

Conversation

sb98052
Copy link

@sb98052 sb98052 commented Sep 13, 2018

This change ensures that the code generated via optimized array loop operators is correct in the InstantRender setting. It enables the optimization of such functions when the --instantRender option is set. Materialization is prevented by ensuring that post-optimization, objects that are reachable from the function are not mutated. Recoverable errors are issued. We also degrade all InstantRender bailouts to recoverable errors, to facilitate debugging. We add a constraint that optimized functions may not be reused.

Resolves #2451 #2448

Copy link

@facebook-github-bot facebook-github-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NTillmann has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

Copy link
Contributor

@NTillmann NTillmann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Please make sure that the internal test produces reasonable results before landing.

src/realm.js Outdated
number of unsupported scenarios. We group all associated compiler diagnostics here. */

instantRenderBailout(message: string, loc: ?BabelNodeSourceLocation) {
let error = new CompilerDiagnostic(message, loc, "PP0039", "RecoverableError");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need an actual Wiki page for this. I am not thrilled by this, however. It may be more specific than PP0001, but it is still vague and not actionable. Each call to this routine should instead have its own error code along with a wiki page that gives concrete advice about it.

// user upgrades the warning to an error.
handleMaterialization = o => {
let diagnosticCode = "PP0044";
if (realm.userChangedDiagnosticToError(diagnosticCode)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is far too subtle to change the semantics of the abstract interpreter based on whether or not a warning was upgraded to an error and then subsequently ignored.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I'll find another way to do this.

diagnosticCode,
"Warning"
);
realm.handleError(error);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never ignore the result of handleError and then carry on. You may only ignore it if you throw a FatalError immediately afterwards.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This I've fixed.

@sb98052 sb98052 dismissed hermanventer’s stale review September 14, 2018 16:37

Dropped the approach that opened a path to adding policies in Prepack.

@NTillmann
Copy link
Contributor

NTillmann commented Sep 14, 2018

Looks fine to me; except that I expect to run into issues when the everything including the module table is getting marked as final. But we can deal with it when we get there.

@sb98052
Copy link
Author

sb98052 commented Sep 17, 2018

Looks fine to me; except that I expect to run into issues when the everything including the module table is getting marked as final. But we can deal with it when we get there.

@NTillmann Note that accessing such objects lead to recoverable errors for Instant Render.

Copy link

@facebook-github-bot facebook-github-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sb98052 has imported this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

Copy link

@facebook-github-bot facebook-github-bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sb98052 is landing this pull request. If you are a Facebook employee, you can view this diff on Phabricator.

);
} else {
let error = new CompilerDiagnostic(
"Mutating a final object, or an object with unknown properties, after some of those " +
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not your doing, but I hate it when terms related to internal implementation details of Prepack leak out via error messages. Moreover, the text of this message is very obscure and may mislead a programmer who has to make sense of it.

Even worse than that, the wiki page for this error gives an outdated example. Prepack already snapshots and does the right thing for the example. I'm none too sure if there are other cases. If there are none, the whole concept of final objects should be deleted. Otherwise, the wiki page should be updated with examples that cover ALL of the other cases.

Is there an issue for this?

number of unsupported scenarios. We group all associated compiler diagnostics here. */
instantRenderBailout(message: string, loc: ?BabelNodeSourceLocation) {
if (loc === undefined) loc = this.currentLocation;
let error = new CompilerDiagnostic(message, loc, "PP0039", "RecoverableError");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I've said before, we should not use the same error code for different error messages. At best we can parameterize a single message. Given that, this abstraction is a trap and should be removed.

// We can't continue because this object is already in its final state
if (realm.instantRender.enabled) {
realm.instantRenderBailout(
"Object mutations that require materialization are currently not supported by InstantRender",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Materialization is an internal concept and should not leak into error messages. The message is also very obscure. If you can't explain why this is not allowed in clear terms along with a wiki page that has a clarifying example, you are not quite done thinking about this problem.

@@ -1348,14 +1348,10 @@ export class ResidualHeapSerializer {
to the __empty built-in */
if (instantRenderMode) {
if (this.emitter.getReasonToWaitForDependencies(elemVal)) {
let error = new CompilerDiagnostic(
this.realm.instantRenderBailout(
"InstantRender does not yet support cyclical arrays or objects",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This error is totally unrelated to the previous call to instantRenderBailout and a perfect example of the trap that I want to remove.

@@ -43,6 +43,11 @@ function evaluatePossibleNestedOptimizedFunctionsAndStoreEffects(
thisValue = func.$BoundThis;
}
invariant(funcToModel instanceof ECMAScriptSourceFunctionValue);

if (realm.instantRender.enabled && realm.collectedNestedOptimizedFunctionEffects.has(funcToModel)) {
realm.instantRenderBailout("Array operators may only be optimized once", funcToModel.expressionLocation);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this mean? Give an example in a wiki page.

@@ -59,6 +64,12 @@ function evaluatePossibleNestedOptimizedFunctionsAndStoreEffects(
// the default behaviour and leaked the nested functions so any bindings
// within the function properly leak and materialize.
if (e instanceof NestedOptimizedFunctionSideEffect) {
if (realm.instantRender.enabled) {
realm.instantRenderBailout(
"InstantRender does not support impure array operators",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is an impure array operator? Give a motivating example in a wiki page.

"PP0039",
"FatalError"
this.realm.instantRenderBailout(
"InstantRender does not yet support cyclical arrays or objects",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this no longer a fatal error? Is it likely that the code generated in this case will do the right thing? If so, I want to see a regression test that does the right thing in this case.

facebook-github-bot pushed a commit that referenced this pull request Sep 17, 2018
Summary:
In support of #2547. Sometimes, it is more desirable (less costly, better for debugging) to flag a warning for a possibly anomalous condition, than to assume that it is anomalous and enforce it as an error. This change exposes warnings that a user upgrades to errors, so that they can then be enforced as such.
Pull Request resolved: #2548

Differential Revision: D9884632

Pulled By: sb98052

fbshipit-source-id: c47b57a21aa047b0f3fa2672508f8fb23c04942a
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants