prepack
Version:
Execute a JS bundle, serialize global state and side effects to a snapshot that can be quickly restored.
342 lines (298 loc) • 15.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.createAbstractFunction = createAbstractFunction;
exports.default = function (realm) {
let global = realm.$GlobalObject;
global.$DefineOwnProperty("dump", {
value: new _index.NativeFunctionValue(realm, "global.dump", "dump", 0, (context, args) => {
console.log("dump", args.map(arg => arg.serialize()));
return context;
}),
writable: true,
enumerable: false,
configurable: true
});
// Helper function to model values that are obtained from the environment,
// and whose concrete values are not known at Prepack-time.
// __abstract(typeNameOrTemplate, name, options) creates a new abstract value
// where typeNameOrTemplate can be...
// - 'string', 'boolean', 'number', 'object', 'function' or
// - ':string', ':boolean', ':number', ':object', ':function' to indicate that
// the abstract value represents a function that only returns values of the specified type, or
// - an actual object defining known properties.
// If the abstract value gets somehow embedded in the final heap,
// it will be referred to by the supplied name in the generated code.
global.$DefineOwnProperty("__abstract", {
value: createAbstractFunction(realm),
writable: true,
enumerable: false,
configurable: true
});
global.$DefineOwnProperty("__abstractOrNull", {
value: createAbstractFunction(realm, realm.intrinsics.null),
writable: true,
enumerable: false,
configurable: true
});
global.$DefineOwnProperty("__abstractOrNullOrUndefined", {
value: createAbstractFunction(realm, realm.intrinsics.null, realm.intrinsics.undefined),
writable: true,
enumerable: false,
configurable: true
});
global.$DefineOwnProperty("__abstractOrUndefined", {
value: createAbstractFunction(realm, realm.intrinsics.undefined),
writable: true,
enumerable: false,
configurable: true
});
global.$DefineOwnProperty("__optimizedFunctions", {
value: new _index.ObjectValue(realm, realm.intrinsics.ObjectPrototype, "__optimizedFunctions", true),
writable: true,
enumerable: false,
configurable: true
});
let additonalFunctionUid = 0;
// Allows dynamically registering optimized functions.
// WARNING: these functions will get exposed at global scope and called there.
// NB: If we interpret one of these calls in an evaluateForEffects context
// that is not subsequently applied, the function will not be registered
// (because prepack won't have a correct value for the FunctionValue itself)
global.$DefineOwnProperty("__optimize", {
value: new _index.NativeFunctionValue(realm, "global.__optimize", "__optimize", 0, (context, [value, config]) => {
// only optimize functions for now
if (value instanceof _index.ECMAScriptSourceFunctionValue) {
realm.assignToGlobal(t.memberExpression(t.memberExpression(t.identifier("global"), t.identifier("__optimizedFunctions")), t.identifier("" + additonalFunctionUid++)), value);
}
return value;
}),
writable: true,
enumerable: false,
configurable: true
});
if (realm.react.enabled) {
global.$DefineOwnProperty("__reactComponentTrees", {
value: new _index.ObjectValue(realm, realm.intrinsics.ObjectPrototype, "__reactComponentTrees", true),
writable: true,
enumerable: false,
configurable: true
});
let reactComponentRootUid = 0;
global.$DefineOwnProperty("__optimizeReactComponentTree", {
value: new _index.NativeFunctionValue(realm, "global.__optimizeReactComponentTree", "__optimizeReactComponentTree", 0, (context, [component, config]) => {
let hasValidComponent = component instanceof _index.ECMAScriptSourceFunctionValue || (0, _utils2.valueIsKnownReactAbstraction)(realm, component);
let hasValidConfig = config instanceof _index.ObjectValue || config === realm.intrinsics.undefined || config === undefined;
if (!hasValidComponent || !hasValidConfig) {
let diagnostic = new _errors.CompilerDiagnostic("__optimizeReactComponentTree(rootComponent, config) has been called with invalid arguments", realm.currentLocation, "PP0024", "FatalError");
realm.handleError(diagnostic);
if (realm.handleError(diagnostic) === "Fail") throw new _errors.FatalError();
}
let reactComponentTree = new _index.ObjectValue(realm, realm.intrinsics.ObjectPrototype);
reactComponentTree.$Set("rootComponent", component, reactComponentTree);
reactComponentTree.$Set("config", config || realm.intrinsics.undefined, reactComponentTree);
realm.assignToGlobal(t.memberExpression(t.memberExpression(t.identifier("global"), t.identifier("__reactComponentTrees")), t.identifier("" + reactComponentRootUid++)), reactComponentTree);
return component;
}),
writable: true,
enumerable: false,
configurable: true
});
}
global.$DefineOwnProperty("__evaluatePureFunction", {
value: new _index.NativeFunctionValue(realm, "global.__evaluatePureFunction", "__evaluatePureFunction", 0, (context, [functionValue]) => {
(0, _invariant2.default)(functionValue instanceof _index.ECMAScriptSourceFunctionValue);
(0, _invariant2.default)(typeof functionValue.$Call === "function");
let functionCall = functionValue.$Call;
return realm.evaluatePure(() => functionCall(realm.intrinsics.undefined, []));
}),
writable: true,
enumerable: false,
configurable: true
});
// Maps from initialized moduleId to exports object
// NB: Changes to this shouldn't ever be serialized
global.$DefineOwnProperty("__initializedModules", {
value: new _index.ObjectValue(realm, realm.intrinsics.ObjectPrototype, "__initializedModules", true),
writable: true,
enumerable: false,
configurable: true
});
// Helper function used to instatiate a residual function
function deriveNativeFunctionValue(unsafe) {
return new _index.NativeFunctionValue(realm, "global.__residual", "__residual", 2, (context, [typeNameOrTemplate, f, ...args]) => {
if (!realm.useAbstractInterpretation) {
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "realm is not partial");
}
let { type, template } = (0, _utils.parseTypeNameOrTemplate)(realm, typeNameOrTemplate);
if (!_index.Value.isTypeCompatibleWith(f.constructor, _index.FunctionValue)) {
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "cannot determine residual function");
}
(0, _invariant2.default)(f instanceof _index.FunctionValue);
f.isResidual = true;
if (unsafe) f.isUnsafeResidual = true;
let result = _index.AbstractValue.createTemporalFromBuildFunction(realm, type, [f].concat(args), nodes => t.callExpression(nodes[0], nodes.slice(1)));
if (template) {
(0, _invariant2.default)(result instanceof _index.AbstractValue, "the nested properties should only be rebuilt for an abstract value");
template.makePartial();
result.values = new _index2.ValuesDomain(new Set([template]));
(0, _invariant2.default)(realm.generator);
realm.rebuildNestedProperties(result, result.getIdentifier().name);
}
return result;
});
}
// Helper function that identifies a computation that must remain part of the residual program and cannot be partially evaluated,
// e.g. because it contains a loop over abstract values.
// __residual(typeNameOrTemplate, function, arg0, arg1, ...) creates a new abstract value
// that is computed by invoking function(arg0, arg1, ...) in the residual program and
// where typeNameOrTemplate either either 'string', 'boolean', 'number', 'object', or an actual object defining known properties.
// The function must not have side effects, and it must not access any state (besides the supplied arguments).
global.$DefineOwnProperty("__residual", {
value: deriveNativeFunctionValue(false),
writable: true,
enumerable: false,
configurable: true
});
// Helper function that identifies a variant of the residual function that has implicit dependencies. This version of residual will infer the dependencies
// and rewrite the function body to do the same thing as the original residual function.
global.$DefineOwnProperty("__residual_unsafe", {
value: deriveNativeFunctionValue(true),
writable: true,
enumerable: false,
configurable: true
});
// TODO #1023: Remove this property. It's just here as some existing internal test cases assume that the __annotate property is exists and is readable.
global.$DefineOwnProperty("__annotate", {
value: realm.intrinsics.undefined,
writable: true,
enumerable: false,
configurable: true
});
// Internal helper function for tests.
// __isAbstract(value) checks if a given value is abstract.
global.$DefineOwnProperty("__isAbstract", {
value: new _index.NativeFunctionValue(realm, "global.__isAbstract", "__isAbstract", 1, (context, [value]) => {
return new _index.BooleanValue(realm, value instanceof _index.AbstractValue);
}),
writable: true,
enumerable: false,
configurable: true
});
// __makePartial(object) marks an (abstract) object as partial.
global.$DefineOwnProperty("__makePartial", {
value: new _index.NativeFunctionValue(realm, "global.__makePartial", "__makePartial", 1, (context, [object]) => {
if (object instanceof _index.AbstractObjectValue || object instanceof _index.ObjectValue) {
object.makePartial();
return object;
}
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "not an (abstract) object");
}),
writable: true,
enumerable: false,
configurable: true
});
// __makeSimple(object) marks an (abstract) object as one that has no getters or setters.
global.$DefineOwnProperty("__makeSimple", {
value: new _index.NativeFunctionValue(realm, "global.__makeSimple", "__makeSimple", 1, (context, [object, option]) => {
if (object instanceof _index.AbstractObjectValue || object instanceof _index.ObjectValue) {
object.makeSimple(option);
return object;
}
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "not an (abstract) object");
}),
writable: true,
enumerable: false,
configurable: true
});
// Helper function that emits a check whether a given object property has a particular value.
global.$DefineOwnProperty("__assumeDataProperty", {
value: new _index.NativeFunctionValue(realm, "global.__assumeDataProperty", "__assumeDataProperty", 3, (context, [object, propertyName, value, invariantOptions]) => {
if (!realm.useAbstractInterpretation) {
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "realm is not partial");
}
if (object instanceof _index.AbstractObjectValue || object instanceof _index.ObjectValue) {
let generator = realm.generator;
(0, _invariant2.default)(generator);
let key = _singletons.To.ToStringPartial(realm, propertyName);
let propertyIdentifier = generator.getAsPropertyNameExpression(key);
let computed = !t.isIdentifier(propertyIdentifier);
if (realm.emitConcreteModel) {
generator.emitConcreteModel(key, value);
} else {
let accessedPropertyOf = objectNode => t.memberExpression(objectNode, propertyIdentifier, computed);
let inExpressionOf = objectNode => t.unaryExpression("!", t.binaryExpression("in", t.stringLiteral(key), objectNode), true);
let invariantOptionString = invariantOptions ? _singletons.To.ToStringPartial(realm, invariantOptions) : "FULL_INVARIANT";
switch (invariantOptionString) {
// checks (!property in object || object.property === undefined)
case "VALUE_DEFINED_INVARIANT":
let condition = ([objectNode, valueNode]) => t.logicalExpression("||", inExpressionOf(objectNode), t.binaryExpression("===", accessedPropertyOf(objectNode), t.valueToNode(undefined)));
generator.emitInvariant([object, value, object], condition, objnode => accessedPropertyOf(objnode));
break;
case "SKIP_INVARIANT":
break;
case "FULL_INVARIANT":
generator.emitFullInvariant(object, key, value);
break;
default:
(0, _invariant2.default)(false, "Invalid invariantOption " + invariantOptionString);
}
}
realm.generator = undefined; // don't emit code during the following $Set call
// casting to due to Flow workaround above
object.$Set(key, value, object);
realm.generator = generator;
if (object.intrinsicName) realm.rebuildObjectProperty(object, key, value, object.intrinsicName);
return context.$Realm.intrinsics.undefined;
}
throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "not an (abstract) object");
}),
writable: true,
enumerable: false,
configurable: true
});
global.$DefineOwnProperty("__IntrospectionError", {
value: realm.intrinsics.__IntrospectionError,
writable: true,
enumerable: false,
configurable: true
});
global.$DefineOwnProperty("__isIntegral", {
value: new _index.NativeFunctionValue(realm, "global.__isIntegral", "__isIntegral", 1, (context, [value]) => {
return new _index.BooleanValue(realm, value instanceof _index.IntegralValue);
}),
writable: true,
enumerable: false,
configurable: true
});
};
var _index = require("../../values/index.js");
var _singletons = require("../../singletons.js");
var _index2 = require("../../domains/index.js");
var _babelTypes = require("babel-types");
var t = _interopRequireWildcard(_babelTypes);
var _invariant = require("../../invariant.js");
var _invariant2 = _interopRequireDefault(_invariant);
var _utils = require("./utils.js");
var _utils2 = require("../../react/utils.js");
var _errors = require("../../errors.js");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
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)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function createAbstractFunction(realm, ...additionalValues) {
return new _index.NativeFunctionValue(realm, "global.__abstract", "__abstract", 0, (context, [typeNameOrTemplate, name]) => {
if (name instanceof _index.StringValue) name = name.value;
if (name !== undefined && typeof name !== "string") {
throw new TypeError("intrinsic name argument is not a string");
}
return (0, _utils.createAbstract)(realm, typeNameOrTemplate, name, ...additionalValues);
});
} /**
* 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.
*/
//# sourceMappingURL=global.js.map