prepack
Version:
Execute a JS bundle, serialize global state and side effects to a snapshot that can be quickly restored.
228 lines (176 loc) • 10.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = _default;
var _completions = require("../completions.js");
var _environment = require("../environment.js");
var _errors = require("../errors.js");
var _ForOfStatement = require("./ForOfStatement.js");
var _index = require("../methods/index.js");
var _singletons = require("../singletons.js");
var _index2 = require("../values/index.js");
var _invariant = _interopRequireDefault(require("../invariant.js"));
var t = _interopRequireWildcard(require("@babel/types"));
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
// helper func to report error
function reportError(realm, loc) {
let error = new _errors.CompilerDiagnostic("for in loops over unknown objects are not yet supported", loc, "PP0013", "FatalError");
realm.handleError(error);
throw new _errors.FatalError();
} // ECMA262 13.7.5.11
function _default(ast, strictCode, env, realm, labelSet) {
let {
left,
right,
body
} = ast;
function reportErrorAndThrowIfNotConcrete(val, loc) {
if (val instanceof _index2.AbstractValue) reportError(realm, loc);
}
try {
if (left.type === "VariableDeclaration") {
if (left.kind === "var") {
// for (var ForBinding in Expression) Statement
// 1. Let keyResult be ? ForIn/OfHeadEvaluation(« », Expression, enumerate).
let keyResult = (0, _ForOfStatement.ForInOfHeadEvaluation)(realm, env, [], right, "enumerate", strictCode);
if (keyResult.isPartialObject() && keyResult.isSimpleObject()) {
return emitResidualLoopIfSafe(ast, strictCode, env, realm, left, right, keyResult, body);
}
reportErrorAndThrowIfNotConcrete(keyResult, right.loc);
(0, _invariant.default)(keyResult instanceof _index2.ObjectValue); // 2. Return ? ForIn/OfBodyEvaluation(ForBinding, Statement, keyResult, varBinding, labelSet).
return (0, _ForOfStatement.ForInOfBodyEvaluation)(realm, env, left.declarations[0].id, body, keyResult, "varBinding", labelSet, strictCode);
} else {
// for (ForDeclaration in Expression) Statement
// 1. Let keyResult be the result of performing ? ForIn/OfHeadEvaluation(BoundNames of ForDeclaration, Expression, enumerate).
let keyResult = (0, _ForOfStatement.ForInOfHeadEvaluation)(realm, env, _singletons.Environment.BoundNames(realm, left), right, "enumerate", strictCode);
reportErrorAndThrowIfNotConcrete(keyResult, right.loc);
(0, _invariant.default)(keyResult instanceof _index2.ObjectValue); // 2. Return ? ForIn/OfBodyEvaluation(ForDeclaration, Statement, keyResult, lexicalBinding, labelSet).
return (0, _ForOfStatement.ForInOfBodyEvaluation)(realm, env, left, body, keyResult, "lexicalBinding", labelSet, strictCode);
}
} else {
// for (LeftHandSideExpression in Expression) Statement
// 1. Let keyResult be ? ForIn/OfHeadEvaluation(« », Expression, enumerate).
let keyResult = (0, _ForOfStatement.ForInOfHeadEvaluation)(realm, env, [], right, "enumerate", strictCode);
reportErrorAndThrowIfNotConcrete(keyResult, right.loc);
(0, _invariant.default)(keyResult instanceof _index2.ObjectValue); // 2. Return ? ForIn/OfBodyEvaluation(LeftHandSideExpression, Statement, keyResult, assignment, labelSet).
return (0, _ForOfStatement.ForInOfBodyEvaluation)(realm, env, left, body, keyResult, "assignment", labelSet, strictCode);
}
} catch (e) {
if (e instanceof _completions.BreakCompletion) {
if (!e.target) return (0, _index.UpdateEmpty)(realm, e, realm.intrinsics.undefined).value;
}
throw e;
}
}
function emitResidualLoopIfSafe(ast, strictCode, env, realm, lh, obexpr, ob, body) {
(0, _invariant.default)(ob.isSimpleObject());
let oldEnv = realm.getRunningContext().lexicalEnvironment;
let blockEnv = _singletons.Environment.NewDeclarativeEnvironment(realm, oldEnv);
realm.getRunningContext().lexicalEnvironment = blockEnv;
try {
let envRec = blockEnv.environmentRecord;
(0, _invariant.default)(envRec instanceof _environment.DeclarativeEnvironmentRecord, "expected declarative environment record");
let absStr = _index2.AbstractValue.createFromType(realm, _index2.StringValue);
let boundName;
for (let n of _singletons.Environment.BoundNames(realm, lh)) {
(0, _invariant.default)(boundName === undefined);
boundName = t.identifier(n);
envRec.CreateMutableBinding(n, false);
envRec.InitializeBinding(n, absStr);
}
let {
result,
generator: gen,
modifiedBindings,
modifiedProperties,
createdObjects
} = realm.evaluateNodeForEffects(body, strictCode, blockEnv);
if (result instanceof _completions.SimpleNormalCompletion && gen.empty() && modifiedBindings.size === 0 && modifiedProperties.size === 1) {
(0, _invariant.default)(createdObjects.size === 0); // or there will be more than one property
let targetObject;
let sourceObject;
modifiedProperties.forEach((desc, key, map) => {
if (key.object.unknownProperty === key) {
targetObject = key.object;
(0, _invariant.default)(desc !== undefined);
let sourceValue = desc.throwIfNotConcrete(realm).value;
if (sourceValue instanceof _index2.AbstractValue) {
// because sourceValue was written to key.object.unknownProperty it must be that
let cond = sourceValue.args[0]; // and because the write always creates a value of this shape
(0, _invariant.default)(cond instanceof _index2.AbstractValue && cond.kind === "template for property name condition");
let falseVal = sourceValue.args[2];
if (falseVal instanceof _index2.AbstractValue && falseVal.kind === "template for prototype member expression") {
// check that the value that was assigned itself came from
// an expression of the form sourceObject[absStr].
let mem = sourceValue.args[1];
while (mem instanceof _index2.AbstractValue) {
if (mem.kind === "sentinel member expression" && mem.args[0] instanceof _index2.ObjectValue && mem.args[1] === absStr) {
sourceObject = mem.args[0];
break;
} // check if mem is a test for absStr being equal to a known property
// if so skip over it until we get to the expression of the form sourceObject[absStr].
let condition = mem.args[0];
if (condition instanceof _index2.AbstractValue && condition.kind === "check for known property") {
if (condition.args[0] === absStr) {
mem = mem.args[2];
continue;
}
}
break;
}
}
}
}
});
if (targetObject instanceof _index2.ObjectValue && sourceObject !== undefined) {
let o = ob;
if (ob instanceof _index2.AbstractObjectValue && !ob.values.isTop() && ob.values.getElements().size === 1) {
// Note that it is not safe, in general, to extract a concrete object from the values domain of
// an abstract object. We can get away with it here only because the concrete object does not
// escape the code below and is thus never referenced directly in generated code because of this logic.
for (let oe of ob.values.getElements()) {
(0, _invariant.default)(oe instanceof _index2.ObjectValue);
o = oe;
}
}
let generator = realm.generator;
(0, _invariant.default)(generator !== undefined); // make target object simple and partial, so that it returns a fully
// abstract value for every property it is queried for.
targetObject.makeSimple();
targetObject.makePartial();
if (sourceObject === o) {
// Known enumerable properties of sourceObject can become known properties of targetObject.
(0, _invariant.default)(sourceObject.isPartialObject()); // EnumerableOwnProperties is sufficient because sourceObject is simple
let keyValPairs = (0, _index.EnumerableOwnProperties)(realm, sourceObject, "key+value", true);
for (let keyVal of keyValPairs) {
(0, _invariant.default)(keyVal instanceof _index2.ArrayValue);
let key = keyVal.$Get("0", keyVal);
let val = keyVal.$Get("1", keyVal);
(0, _invariant.default)(key instanceof _index2.StringValue); // sourceObject is simple
targetObject.$Set(key, val, targetObject);
}
} // add loop to generator
(0, _invariant.default)(boundName != null);
generator.emitForInStatement(o, lh, sourceObject, targetObject, boundName);
return realm.intrinsics.undefined;
}
}
} finally {
// 6. Set the running execution context's LexicalEnvironment to oldEnv.
realm.getRunningContext().lexicalEnvironment = oldEnv;
realm.onDestroyScope(blockEnv);
}
reportError(realm, obexpr.loc);
(0, _invariant.default)(false);
}
//# sourceMappingURL=ForInStatement.js.map