Special case "x === undefined || x === null" kind of expressions (#2188)

Summary:
Release note: special case expression simplification for Instant Render

When instant render is enabled turn x === undefined || x === null into __cannotBecomeObject(x) so that Instant Render can easily compile it down to a single byte code.
Closes https://github.com/facebook/prepack/pull/2188

Differential Revision: D8716594

Pulled By: hermanventer

fbshipit-source-id: bbcb25462f79852d8deac29bfed62e86745e5589
This commit is contained in:
Herman Venter 2018-07-02 13:36:27 -07:00 committed by Facebook Github Bot
parent 67a47fd48f
commit 466d19ddfd
4 changed files with 48 additions and 1 deletions

View File

@ -318,6 +318,7 @@ function runTest(name, code, options: PrepackOptions, args) {
options.invariantLevel = code.includes("// omit invariants") || args.verbose ? 0 : 99;
if (code.includes("// emit concrete model")) options.emitConcreteModel = true;
if (code.includes("// exceeds stack limit")) options.maxStackDepth = 10;
if (code.includes("// instant render")) options.instantRender = true;
if (code.includes("// react")) {
options.reactEnabled = true;
options.reactOutput = "jsx";

View File

@ -17,6 +17,7 @@ import { Realm } from "../realm.js";
import { AbstractValue, BooleanValue, ConcreteValue, Value } from "../values/index.js";
import { Path, To } from "../singletons.js";
import EmptyValue from "../values/EmptyValue";
import * as t from "babel-types";
export default function simplifyAndRefineAbstractValue(
realm: Realm,
@ -110,6 +111,33 @@ function simplify(realm, value: Value, isCondition: boolean = false): Value {
!y.args[1].mightNotBeTrue()
)
return y;
if (realm.instantRender.enabled) {
if (op === "||" && x0 instanceof AbstractValue && y0 instanceof AbstractValue) {
if (x0.kind === "===" && y0.kind === "===") {
let [xa, xb] = x0.args;
let [ya, yb] = y0.args;
if (xa.equals(ya) && !xb.equals(yb) && nullOrUndefined(xb) && nullOrUndefined(yb)) return rewrite(xa);
else if (xb.equals(yb) && !xa.equals(ya) && nullOrUndefined(xa) && nullOrUndefined(ya)) return rewrite(xb);
else if (xa.equals(yb) && !xb.equals(ya) && nullOrUndefined(xb) && nullOrUndefined(ya)) return rewrite(xa);
else if (xb.equals(ya) && !xa.equals(yb) && nullOrUndefined(xa) && nullOrUndefined(yb)) return rewrite(xb);
function nullOrUndefined(z: Value) {
return !z.mightNotBeNull() || !z.mightNotBeUndefined();
}
function rewrite(z: Value) {
return AbstractValue.createFromBuildFunction(
realm,
BooleanValue,
[xa],
([n]) => {
let callFunc = t.identifier("global.__cannotBecomeObject");
return t.callExpression(callFunc, [n]);
},
{ kind: "global.__cannotBecomeObject(A)" }
);
}
}
}
}
if (x.equals(x0) && y.equals(y0)) return value;
return AbstractValue.createFromLogicalOp(realm, (value.kind: any), x, y, loc, isCondition, true);
}

View File

@ -79,7 +79,8 @@ export type AbstractValueKind =
| "global.JSON.parse(A)"
| "JSON.stringify(...)"
| "JSON.parse(...)"
| "global.Math.imul(A, B)";
| "global.Math.imul(A, B)"
| "global.__cannotBecomeObject(A)";
// Use AbstractValue.makeKind to make a kind from one of these prefices.
type AbstractValueKindPrefix =

View File

@ -0,0 +1,17 @@
// instant render
// add at runtime:global.__cannotBecomeObject = a => a === undefined || a === null;
// does not contain:void 0
let a = global.__abstract ? __abstract(undefined, "(true)") : true;
let x1 = a === undefined || a === null;
let x2 = a === undefined || null === a;
let x3 = undefined === a || a === null;
let x4 = undefined === a || null === a;
let x5 = a === null || a === undefined;
let x6 = a === null || undefined === a;
let x7 = null === a || a === undefined;
let x8 = null === a || undefined === a;
global.inspect = function() { return [x1, x2, x3, x4, x5, x6, x7, x8].join(" "); }