UNPKG

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
"use strict"; 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