Add option to not emit invariants for model functions

Summary:
FunctionValues should not be compared with `===` from the model. Add an option to disable this invariant.
Closes https://github.com/facebook/prepack/pull/881

Differential Revision: D5626447

Pulled By: cblappert

fbshipit-source-id: 3f0bb71cd6dd0b556e46df85658c715798fa0204
This commit is contained in:
Christopher Blappert 2017-08-15 15:23:09 -07:00 committed by Facebook Github Bot
parent 69761bf597
commit be70144220
3 changed files with 52 additions and 10 deletions

View File

@ -189,14 +189,20 @@ function runTest(name, code, options, args) {
markersToFind.push({ positive, value, start: i + marker.length });
}
}
let addedCode = "";
let injectAtRuntime = "// add at runtime:";
if (code.includes(injectAtRuntime)) {
let i = code.indexOf(injectAtRuntime);
addedCode = code.substring(i + injectAtRuntime.length, code.indexOf("\n", i));
}
let unique = 27277;
let oldUniqueSuffix = "";
try {
expected = exec(`(function () {${code} // keep newline here as code may end with comment
expected = exec(`${addedCode}\n(function () {${code} // keep newline here as code may end with comment
}).call(this);`);
let i = 0;
let max = 4;
let max = addedCode ? 1 : 4;
let oldCode = code;
let anyDelayedValues = false;
for (; i < max; i++) {
@ -220,7 +226,7 @@ function runTest(name, code, options, args) {
}
}
if (markersIssue) break;
actual = exec(newCode);
actual = exec(addedCode + newCode);
if (expected !== actual) {
console.log(chalk.red("Output mismatch!"));
break;
@ -249,6 +255,7 @@ function runTest(name, code, options, args) {
oldCode = newCode;
oldUniqueSuffix = newUniqueSuffix;
}
if (i === 1) return true;
if (i === max) {
if (anyDelayedValues) {
// TODO #835: Make delayed initializations logic more sophisticated in order to still reach a fixed point.

View File

@ -256,7 +256,7 @@ export default function(realm: Realm): void {
"global.__assumeDataProperty",
"__assumeDataProperty",
3,
(context, [object, propertyName, value]) => {
(context, [object, propertyName, value, invariantOptions]) => {
if (!realm.useAbstractInterpretation) {
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "realm is not partial");
}
@ -267,12 +267,32 @@ export default function(realm: Realm): void {
if ((object: any) instanceof AbstractObjectValue || (object: any) instanceof ObjectValue) {
let generator = realm.generator;
invariant(generator);
generator.emitInvariant(
[object, value, object],
([objectNode, valueNode]) =>
t.binaryExpression("!==", t.memberExpression(objectNode, t.identifier(key)), valueNode),
objnode => t.memberExpression(objnode, t.identifier(key))
);
let condition = ([objectNode, valueNode]) =>
t.binaryExpression("!==", t.memberExpression(objectNode, t.identifier(key)), valueNode);
if (invariantOptions) {
let invariantOptionString = ToStringPartial(realm, invariantOptions);
switch (invariantOptionString) {
case "VALUE_DEFINED_INVARIANT":
condition = ([objectNode, valueNode]) =>
t.binaryExpression(
"===",
t.memberExpression(objectNode, t.identifier(key)),
t.valueToNode(undefined)
);
break;
case "SKIP_INVARIANT":
condition = null;
break;
case "FULL_INVARIANT":
break;
default:
invariant(false, "Invalid invariantOption " + invariantOptionString);
}
}
if (condition)
generator.emitInvariant([object, value, object], condition, objnode =>
t.memberExpression(objnode, t.identifier(key))
);
realm.generator = undefined; // don't emit code during the following $Set call
// casting to due to Flow workaround above
(object: any).$Set(key, value, object);

View File

@ -0,0 +1,15 @@
// add at runtime: global.fun = console.log;
var result = [];
global.log = function (arg) { result.push(arg); };
if (global.__assumeDataProperty) {
__assumeDataProperty(global, "fun",
function (arg1) {
__residual("void", function(arg1, console) {
console.log(arg1);
}, arg1, console);
}, "VALUE_DEFINED_INVARIANT");
}
global.fun("literal");
inspect = function() { return undefined; };