Back out "[prepack][PR] Support call expressions where the base might be an abstract conditional"

Summary: It caused some regressions but we're not sure why. Need to increase test coverage first. Reverting for now.

Reviewed By: trueadm

Differential Revision: D8205062

fbshipit-source-id: fe03f8ea9e8c3d85b3ce96912c5135019f407a56
This commit is contained in:
Dan Abramov 2018-05-30 09:40:40 -07:00 committed by Facebook Github Bot
parent 24181252fe
commit f55285012e
4 changed files with 20 additions and 171 deletions

View File

@ -13,17 +13,11 @@ import { CompilerDiagnostic, FatalError } from "../errors.js";
import { AbruptCompletion, PossiblyNormalCompletion } from "../completions.js";
import type { Realm } from "../realm.js";
import { Effects } from "../realm.js";
import { type LexicalEnvironment, type BaseValue, mightBecomeAnObject } from "../environment.js";
import type { LexicalEnvironment } from "../environment.js";
import { EnvironmentRecord } from "../environment.js";
import { TypesDomain, ValuesDomain } from "../domains/index.js";
import {
AbstractValue,
AbstractObjectValue,
ConcreteValue,
FunctionValue,
ObjectValue,
Value,
} from "../values/index.js";
import { Value } from "../values/index.js";
import { AbstractValue, AbstractObjectValue, BooleanValue, ConcreteValue, FunctionValue } from "../values/index.js";
import { Reference } from "../environment.js";
import { Environment, Functions, Havoc, Join } from "../singletons.js";
import {
@ -53,103 +47,28 @@ export default function(
// 1. Let ref be the result of evaluating MemberExpression.
let ref = env.evaluate(ast.callee, strictCode);
return evaluateReference(ref, ast, strictCode, env, realm);
}
function evaluateReference(
ref: Reference | Value,
ast: BabelNodeCallExpression,
strictCode: boolean,
env: LexicalEnvironment,
realm: Realm
): Value {
if (
ref instanceof Reference &&
ref.base instanceof AbstractValue &&
ref.base.mightNotBeObject() &&
realm.isInPureScope()
) {
let base = ref.base;
if (base.kind === "conditional") {
return evaluateConditionalReferenceBase(ref, ast, strictCode, env, realm);
}
let dummy = ref.base;
// avoid explicitly converting ref.base to an object because that will create a generator entry
// leading to two object allocations rather than one.
return realm.evaluateWithPossibleThrowCompletion(
() => generateRuntimeCall(ref, base, ast, strictCode, env, realm),
() => generateRuntimeCall(ref, dummy, ast, strictCode, env, realm),
TypesDomain.topVal,
ValuesDomain.topVal
);
}
// 2. Let func be ? GetValue(ref).
let func = Environment.GetValue(realm, ref);
return EvaluateCall(ref, func, ast, strictCode, env, realm);
}
function evaluateConditionalReferenceBase(
ref: Reference,
ast: BabelNodeCallExpression,
strictCode: boolean,
env: LexicalEnvironment,
realm: Realm
): Value {
let base = ref.base;
invariant(base instanceof AbstractValue);
invariant(base.kind === "conditional", "evaluateConditionalReferenceBase expects an abstract conditional");
let [condValue, consequentVal, alternateVal] = base.args;
invariant(condValue instanceof AbstractValue);
return realm.evaluateWithAbstractConditional(
condValue,
() => {
return realm.evaluateForEffects(
() => {
if (
consequentVal instanceof AbstractObjectValue ||
consequentVal instanceof ObjectValue ||
mightBecomeAnObject(consequentVal)
) {
let consequentRef = new Reference(
((consequentVal: any): BaseValue),
ref.referencedName,
ref.strict,
ref.thisValue
);
return evaluateReference(consequentRef, ast, strictCode, env, realm);
}
return consequentVal;
},
null,
"evaluateConditionalReferenceBase consequent"
);
},
() => {
return realm.evaluateForEffects(
() => {
if (
alternateVal instanceof AbstractObjectValue ||
alternateVal instanceof ObjectValue ||
mightBecomeAnObject(alternateVal)
) {
let alternateRef = new Reference(
((alternateVal: any): BaseValue),
ref.referencedName,
ref.strict,
ref.thisValue
);
return evaluateReference(alternateRef, ast, strictCode, env, realm);
}
return alternateVal;
},
null,
"evaluateConditionalReferenceBase alternate"
);
}
);
}
function callBothFunctionsAndJoinTheirEffects(
args: Array<Value>,
ast: BabelNodeCallExpression,
@ -158,7 +77,7 @@ function callBothFunctionsAndJoinTheirEffects(
realm: Realm
): Value {
let [cond, func1, func2] = args;
invariant(cond instanceof AbstractValue);
invariant(cond instanceof AbstractValue && cond.getType() === BooleanValue);
invariant(Value.isTypeCompatibleWith(func1.getType(), FunctionValue));
invariant(Value.isTypeCompatibleWith(func2.getType(), FunctionValue));

View File

@ -11,13 +11,7 @@
import type { PropertyKeyValue } from "../types.js";
import type { ECMAScriptFunctionValue } from "../values/index.js";
import {
EnvironmentRecord,
GlobalEnvironmentRecord,
LexicalEnvironment,
mightBecomeAnObject,
Reference,
} from "../environment.js";
import { LexicalEnvironment, Reference, EnvironmentRecord, GlobalEnvironmentRecord } from "../environment.js";
import { FatalError } from "../errors.js";
import { Realm, ExecutionContext } from "../realm.js";
import Value from "../values/Value.js";
@ -287,29 +281,22 @@ export function OrdinaryCallBindThis(
return envRec.BindThisValue(thisValue);
}
function callNativeFunctionValue(
// ECMA262 9.2.1.3
export function OrdinaryCallEvaluateBody(
realm: Realm,
f: NativeFunctionValue,
f: ECMAScriptFunctionValue,
argumentsList: Array<Value>
): Value | AbruptCompletion {
let env = realm.getRunningContext().lexicalEnvironment;
let context = env.environmentRecord.GetThisBinding();
): Reference | Value | AbruptCompletion {
if (f instanceof NativeFunctionValue) {
let env = realm.getRunningContext().lexicalEnvironment;
let context = env.environmentRecord.GetThisBinding();
const functionCall = contextVal => {
if (context instanceof AbstractObjectValue && context.kind === "conditional") {
// TODO: we should handle this case and split the calls up
// on the conditional, as it may yield better results
}
try {
invariant(
contextVal instanceof AbstractObjectValue ||
contextVal instanceof ObjectValue ||
contextVal instanceof NullValue ||
contextVal instanceof UndefinedValue ||
mightBecomeAnObject(contextVal)
);
return f.callCallback(
// this is to get around Flow not understand the above invariant
((contextVal: any): AbstractObjectValue | ObjectValue | NullValue | UndefinedValue),
argumentsList,
env.environmentRecord.$NewTarget
);
return f.callCallback(context, argumentsList, env.environmentRecord.$NewTarget);
} catch (err) {
if (err instanceof AbruptCompletion) {
return err;
@ -319,33 +306,6 @@ function callNativeFunctionValue(
throw new FatalError(err);
}
}
};
if (context instanceof AbstractObjectValue && context.kind === "conditional") {
let [condValue, consequentVal, alternateVal] = context.args;
invariant(condValue instanceof AbstractValue);
return realm.evaluateWithAbstractConditional(
condValue,
() => {
return realm.evaluateForEffects(() => functionCall(consequentVal), null, "callNativeFunctionValue consequent");
},
() => {
return realm.evaluateForEffects(() => functionCall(alternateVal), null, "callNativeFunctionValue alternate");
}
);
}
return functionCall(context);
}
// ECMA262 9.2.1.3
export function OrdinaryCallEvaluateBody(
realm: Realm,
f: ECMAScriptFunctionValue,
argumentsList: Array<Value>
): Reference | Value | AbruptCompletion {
if (f instanceof NativeFunctionValue) {
return callNativeFunctionValue(realm, f, argumentsList);
} else {
invariant(f instanceof ECMAScriptSourceFunctionValue);
let F = f;

View File

@ -1,16 +0,0 @@
// does contain:1-2-3
function fn(a) {
var array = (a === null ? [1,2,3] : [4,5,6]);
return array.join("-");
}
global.__optimize && __optimize(fn);
inspect = function() {
return JSON.stringify({
a: fn(null),
b: fn(true),
});
}

View File

@ -1,14 +0,0 @@
function fn(a, b) {
var array = (a === null ? b : [4,5,6]);
return array.join("-");
}
global.__optimize && __optimize(fn);
inspect = function() {
return JSON.stringify({
a: fn(null, [1,2,3]),
b: fn(true, [1,2,3]),
});
}