Check if intrinsic abstract values have unique names

Summary:
Fix for #1155
Closes https://github.com/facebook/prepack/pull/1197

Differential Revision: D6546346

Pulled By: hermanventer

fbshipit-source-id: 7c24e1ce4ebf121a6d50176e7dc124d83f7cdad4
This commit is contained in:
Manas 2017-12-12 11:27:07 -08:00 committed by Facebook Github Bot
parent a0ece2f8b4
commit 8ece9d1b3e
7 changed files with 68 additions and 31 deletions

View File

@ -24,6 +24,7 @@ import { ValuesDomain } from "../../domains/index.js";
import { describeLocation } from "../ecma262/Error.js";
import { To } from "../../singletons.js";
import AbstractObjectValue from "../../values/AbstractObjectValue";
import { CompilerDiagnostic, FatalError } from "../../errors.js";
const throwTemplateSrc = "(function(){throw new global.Error('abstract value defined at ' + A);})()";
const throwTemplate = buildExpressionTemplate(throwTemplateSrc);
@ -69,24 +70,33 @@ export function createAbstract(
let { type, template } = parseTypeNameOrTemplate(realm, typeNameOrTemplate);
let result;
let locString,
loc = null;
for (let executionContext of realm.contextStack.slice().reverse()) {
let caller = executionContext.caller;
loc = executionContext.loc;
locString = describeLocation(
realm,
caller ? caller.function : undefined,
caller ? caller.lexicalEnvironment : undefined,
loc
);
if (locString !== undefined) break;
}
let nameString = name ? To.ToStringPartial(realm, name) : "";
if (nameString === "") {
let locString;
for (let executionContext of realm.contextStack.slice().reverse()) {
let caller = executionContext.caller;
locString = describeLocation(
realm,
caller ? caller.function : undefined,
caller ? caller.lexicalEnvironment : undefined,
executionContext.loc
);
if (locString !== undefined) break;
}
let locVal = new StringValue(realm, locString || "(unknown location)");
let kind = "__abstract_" + realm.objectCount++; // need not be an object, but must be unique
result = AbstractValue.createFromTemplate(realm, throwTemplate, type, [locVal], kind);
} else {
let kind = "__abstract_" + nameString; // assume name is unique TODO #1155: check this
let kind = "__abstract_" + nameString;
if (!realm.isNameStringUnique(nameString)) {
let error = new CompilerDiagnostic("An abstract value with the same name exists", loc, "PP0019", "FatalError");
realm.handleError(error);
throw new FatalError();
} else {
realm.saveNameString(nameString);
}
result = AbstractValue.createFromTemplate(realm, buildExpressionTemplate(nameString), type, [], kind);
result.intrinsicName = nameString;
}

View File

@ -181,6 +181,7 @@ export class Realm {
this.errorHandler = opts.errorHandler;
this.globalSymbolRegistry = [];
this._abstractValuesDefined = new Set(); // A set of nameStrings to ensure abstract values have unique names
}
start: number;
@ -264,6 +265,7 @@ export class Realm {
debuggerInstance: DebugServerType | void;
nextGeneratorId: number = 0;
_abstractValuesDefined: Set<string>;
// to force flow to type the annotations
isCompatibleWith(compatibility: Compatibility): boolean {
@ -952,4 +954,12 @@ export class Realm {
}
return errorHandler(diagnostic);
}
saveNameString(nameString: string): void {
this._abstractValuesDefined.add(nameString);
}
isNameStringUnique(nameString: string): boolean {
return !this._abstractValuesDefined.has(nameString);
}
}

View File

@ -0,0 +1,4 @@
// expected errors: [{"location": {"start":{"line":4,"column":0},"end":{"line":4,"column":27},"source":"test/error-handler/abstract-value-check-dup-name-string.js"},"severity":"FatalError","errorCode":"PP0019","message":"An abstract value with the same name exists"}]
__abstract('number', 'foo');
__abstract('number', 'foo');

View File

@ -1,6 +1,6 @@
(function() {
let x = global.__abstract ? __abstract("boolean", "(true)") : true;
let y = global.__abstract ? __abstract("boolean", "(true)") : true;
let x = global.__abstract ? __abstract("boolean", "/* x = */(true)") : true;
let y = global.__abstract ? __abstract("boolean", "/* y = */(true)") : true;
let obj = { p: 42 };
if (y) {
if (x) {

View File

@ -2,16 +2,16 @@ let dims = global.__abstract ? __abstract({
window: undefined,
screen: undefined,
windowPhysicalPixels: __abstract({
width: __abstract("number", "1"),
height: __abstract("number", "1"),
scale: __abstract("number", "2"),
fontScale: __abstract("number", "4"),
width: __abstract("number", "/* windowPhysicalPixels.width = */ 1"),
height: __abstract("number", "/* windowPhysicalPixels.height = */ 1"),
scale: __abstract("number", "/* windowPhysicalPixels.scale = */ 2"),
fontScale: __abstract("number", "/* windowPhysicalPixels.fontScale = */4"),
}),
screenPhysicalPixels: __abstract({
width: __abstract("number", "1"),
height: __abstract("number", "1"),
scale: __abstract("number", "2"),
fontScale: __abstract("number", "4"),
width: __abstract("number", "/* screenPhysicalPixels.width = */ 1"),
height: __abstract("number", "/* screenPhysicalPixels.height = */1"),
scale: __abstract("number", "/* screenPhysicalPixels.scale = */ 2"),
fontScale: __abstract("number", "/*screenPhysicalPixels.fontScale = */4"),
}),
}, `({
window: undefined,

View File

@ -1,6 +1,6 @@
var n = global.__abstract ? __abstract("string", '("x")') : "x";
var m = global.__abstract ? __abstract("string", '("x")') : "x";
var c = global.__abstract ? __abstract("boolean", "true") : true;
var n = global.__abstract ? __abstract("string", '/* n = */ ("x")') : "x";
var m = global.__abstract ? __abstract("string", '/* m = */ ("x")') : "x";
var c = global.__abstract ? __abstract("boolean", "/* c = */ true") : true;
a = {x: 123, y: 444};
if (global.__makeSimple) global.__makeSimple(a);

View File

@ -1,10 +1,13 @@
let c = 0;
let overflow = false;
function check() {
return global.__abstract ? __abstract('boolean', 'true') : true;
function check1() {
return global.__abstract ? __abstract('boolean', '/* check1 */ true') : true;
}
function call() {
if (check()) {
function check2() {
return global.__abstract ? __abstract('boolean', '/* check2 */ true') : true;
}
function call1() {
if (check1()) {
c = c + 1;
if (c > 2) {
overflow = true;
@ -13,8 +16,18 @@ function call() {
}
return 4;
}
a = call();
b = call();
function call2() {
if (check2()) {
c = c + 1;
if (c > 2) {
overflow = true;
return 3;
}
}
return 4;
}
a = call1();
b = call2();
inspect = function() {
return overflow;
};