UNPKG

prepack

Version:

Execute a JS bundle, serialize global state and side effects to a snapshot that can be quickly restored.

316 lines (234 loc) 12.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _index = require("./index.js"); var _is = require("../methods/is.js"); var _singletons = require("../singletons.js"); var _invariant = _interopRequireDefault(require("../invariant.js")); var _errors = require("../errors.js"); var _descriptors = require("../descriptors.js"); var _completions = require("../completions.js"); 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. */ /* strict-local */ function evaluatePossibleNestedOptimizedFunctionsAndStoreEffects(realm, abstractArrayValue, possibleNestedOptimizedFunctions) { for (let _ref of possibleNestedOptimizedFunctions) { let { func, thisValue } = _ref; let funcToModel = func; if (func instanceof _index.BoundFunctionValue) { funcToModel = func.$BoundTargetFunction; thisValue = func.$BoundThis; } (0, _invariant.default)(funcToModel instanceof _index.ECMAScriptSourceFunctionValue); if (funcToModel.isCalledInMultipleContexts) return; let previouslyComputedEffects = realm.collectedNestedOptimizedFunctionEffects.get(funcToModel); if (previouslyComputedEffects !== undefined) { if (realm.instantRender.enabled) { realm.instantRenderBailout("Array operators may only be optimized once", funcToModel.expressionLocation); } else { // We currently do not support context-sensitive specialization, // where the calls we specialize depend on the specialization context. // TODO: #2454 // TODO: Implement context-sensitive specialization instead of giving up funcToModel.isCalledInMultipleContexts = true; _singletons.Leak.value(realm, func); return; } } let funcCall = _singletons.Utils.createModelledFunctionCall(realm, funcToModel, undefined, thisValue); // We take the modelled function and wrap it in a pure evaluation so we can check for // side-effects that occur when evaluating the function. If there are side-effects, then // we don't try and optimize the nested function. let pureFuncCall = () => realm.evaluatePure(funcCall, /*bubbles*/ false, () => { throw new _errors.NestedOptimizedFunctionSideEffect(); }); let effects; try { effects = realm.evaluateForEffects(pureFuncCall, null, "temporalArray nestedOptimizedFunction"); } catch (e) { // If the nested optimized function had side-effects, we need to fallback to // the default behaviour and leaked the nested functions so any bindings // within the function properly leak and materialize. if (e instanceof _errors.NestedOptimizedFunctionSideEffect) { if (realm.instantRender.enabled) { realm.instantRenderBailout("InstantRender does not support impure array operators", funcCall.expressionLocation); } _singletons.Leak.value(realm, func); return; } throw e; } // Check if effects were pure then add them if (abstractArrayValue.nestedOptimizedFunctionEffects === undefined) { abstractArrayValue.nestedOptimizedFunctionEffects = new Map(); } abstractArrayValue.nestedOptimizedFunctionEffects.set(funcToModel, effects); realm.collectedNestedOptimizedFunctionEffects.set(funcToModel, effects); } } /* We track aliases explicitly, because we currently do not have the primitives to model objects created inside of the loop. TODO: Revisit when #2543 and subsequent modeling work lands. At that point, instead of of a mayAliasSet, we can return a widened abstract value. */ function modelUnknownPropertyOfSpecializedArray(realm, args, array, possibleNestedOptimizedFunctions) { let sentinelProperty = { key: undefined, descriptor: new _descriptors.PropertyDescriptor({ writable: true, enumerable: true, configurable: true }), object: array }; let mayAliasedObjects = new Set(); if (realm.arrayNestedOptimizedFunctionsEnabled && possibleNestedOptimizedFunctions) { (0, _invariant.default)(possibleNestedOptimizedFunctions.length > 0); if (possibleNestedOptimizedFunctions[0].kind === "map") { for (let _ref2 of possibleNestedOptimizedFunctions) { let { func } = _ref2; let funcToModel; if (func instanceof _index.BoundFunctionValue) { funcToModel = func.$BoundTargetFunction; } else { funcToModel = func; } (0, _invariant.default)(funcToModel instanceof _index.ECMAScriptSourceFunctionValue); if (array.nestedOptimizedFunctionEffects !== undefined) { let effects = array.nestedOptimizedFunctionEffects.get(funcToModel); if (effects !== undefined) { (0, _invariant.default)(effects.result instanceof _completions.SimpleNormalCompletion); let reachableObjects = _singletons.Materialize.computeReachableObjects(realm, effects.result.value); for (let reachableObject of reachableObjects) { if (!effects.createdObjects.has(reachableObject)) mayAliasedObjects.add(reachableObject); } } } } } // For filter, we just collect the may alias set of the mapped array if (args.length > 0) { let mappedArray = args[0]; if (ArrayValue.isIntrinsicAndHasWidenedNumericProperty(mappedArray)) { (0, _invariant.default)(mappedArray instanceof ArrayValue); (0, _invariant.default)(mappedArray.unknownProperty !== undefined); (0, _invariant.default)(mappedArray.unknownProperty.descriptor instanceof _descriptors.PropertyDescriptor); let unknownPropertyValue = mappedArray.unknownProperty.descriptor.value; (0, _invariant.default)(unknownPropertyValue instanceof _index.AbstractValue); let aliasSet = unknownPropertyValue.args[0]; (0, _invariant.default)(aliasSet instanceof _index.AbstractValue && aliasSet.kind === "mayAliasSet"); for (let aliasedObject of aliasSet.args) { (0, _invariant.default)(aliasedObject instanceof _index.ObjectValue); mayAliasedObjects.add(aliasedObject); } } } } let aliasSet = _index.AbstractValue.createFromType(realm, _index.Value, "mayAliasSet", [...mayAliasedObjects]); sentinelProperty.descriptor.value = _index.AbstractValue.createFromType(realm, _index.Value, "widened numeric property", [aliasSet]); return sentinelProperty; } function createArrayWithWidenedNumericProperty(realm, args, intrinsicName, possibleNestedOptimizedFunctions) { let abstractArrayValue = new ArrayValue(realm, intrinsicName); if (possibleNestedOptimizedFunctions !== undefined && possibleNestedOptimizedFunctions.length > 0) { if (realm.arrayNestedOptimizedFunctionsEnabled && (!realm.react.enabled || realm.react.optimizeNestedFunctions)) { evaluatePossibleNestedOptimizedFunctionsAndStoreEffects(realm, abstractArrayValue, possibleNestedOptimizedFunctions); } else { // If nested optimized functions are disabled, we need to fallback to // the default behaviour and leaked the nested functions so any bindings // within the function properly leak and materialize. for (let _ref3 of possibleNestedOptimizedFunctions) { let { func } = _ref3; _singletons.Leak.value(realm, func); } } } // Add unknownProperty so we manually handle this object property access abstractArrayValue.unknownProperty = modelUnknownPropertyOfSpecializedArray(realm, args, abstractArrayValue, possibleNestedOptimizedFunctions); return abstractArrayValue; } class ArrayValue extends _index.ObjectValue { constructor(realm, intrinsicName) { super(realm, realm.intrinsics.ArrayPrototype, intrinsicName); } getKind() { return "Array"; } isSimpleObject() { return this.$TypedArrayName === undefined; } // ECMA262 9.4.2.1 $DefineOwnProperty(P, Desc) { let A = this; // 1. Assert: IsPropertyKey(P) is true. (0, _invariant.default)((0, _is.IsPropertyKey)(this.$Realm, P), "expected a property key"); // 2. If P is "length", then if (P === "length" || P instanceof _index.StringValue && P.value === "length") { // a. Return ? ArraySetLength(A, Desc). return _singletons.Properties.ArraySetLength(this.$Realm, A, Desc); } else if ((0, _is.IsArrayIndex)(this.$Realm, P)) { if (ArrayValue.isIntrinsicAndHasWidenedNumericProperty(this)) { // The length of an array with widenend numeric properties is always abstract let succeeded = _singletons.Properties.OrdinaryDefineOwnProperty(this.$Realm, A, P, Desc); if (succeeded === false) return false; return true; } // 3. Else if P is an array index, then // a. Let oldLenDesc be OrdinaryGetOwnProperty(A, "length"). let oldLenDesc = _singletons.Properties.OrdinaryGetOwnProperty(this.$Realm, A, "length"); // b. Assert: oldLenDesc will never be undefined or an accessor descriptor because Array objects are // created with a length data property that cannot be deleted or reconfigured. (0, _invariant.default)(oldLenDesc !== undefined && !(0, _is.IsAccessorDescriptor)(this.$Realm, oldLenDesc), "cannot be undefined or an accessor descriptor"); _singletons.Properties.ThrowIfMightHaveBeenDeleted(oldLenDesc); oldLenDesc = oldLenDesc.throwIfNotConcrete(this.$Realm); // c. Let oldLen be oldLenDesc.[[Value]]. let oldLen = oldLenDesc.value; (0, _invariant.default)(oldLen instanceof _index.Value); oldLen = oldLen.throwIfNotConcrete(); (0, _invariant.default)(oldLen instanceof _index.NumberValue, "expected number value"); oldLen = oldLen.value; // d. Let index be ! ToUint32(P). let index = _singletons.To.ToUint32(this.$Realm, typeof P === "string" ? new _index.StringValue(this.$Realm, P) : P); // e. If index ≥ oldLen and oldLenDesc.[[Writable]] is false, return false. if (index >= oldLen && oldLenDesc.writable === false) return false; // f. Let succeeded be ! OrdinaryDefineOwnProperty(A, P, Desc). let succeeded = _singletons.Properties.OrdinaryDefineOwnProperty(this.$Realm, A, P, Desc); // g. If succeeded is false, return false. if (succeeded === false) return false; // h. If index ≥ oldLen, then if (index >= oldLen) { // i. Set oldLenDesc.[[Value]] to index + 1. oldLenDesc.value = new _index.NumberValue(this.$Realm, index + 1); // ii. Let succeeded be OrdinaryDefineOwnProperty(A, "length", oldLenDesc). succeeded = _singletons.Properties.OrdinaryDefineOwnProperty(this.$Realm, A, "length", oldLenDesc); // iii. Assert: succeeded is true. (0, _invariant.default)(succeeded, "expected length definition to succeed"); } // i. Return true. return true; } // 1. Return OrdinaryDefineOwnProperty(A, P, Desc). return _singletons.Properties.OrdinaryDefineOwnProperty(this.$Realm, A, P, Desc); } static createTemporalWithWidenedNumericProperty(realm, args, operationDescriptor, possibleNestedOptimizedFunctions) { (0, _invariant.default)(realm.generator !== undefined); let value = realm.generator.deriveConcreteObject(intrinsicName => createArrayWithWidenedNumericProperty(realm, args, intrinsicName, possibleNestedOptimizedFunctions), args, operationDescriptor, { isPure: true }); (0, _invariant.default)(value instanceof ArrayValue); return value; } static isIntrinsicAndHasWidenedNumericProperty(obj) { if (obj instanceof ArrayValue && obj.intrinsicName !== undefined && obj.isScopedTemplate !== undefined) { (0, _invariant.default)(_index.ObjectValue.isIntrinsicDerivedObject(obj)); const prop = obj.unknownProperty; if (prop !== undefined && prop.descriptor !== undefined) { const desc = prop.descriptor.throwIfNotConcrete(obj.$Realm); return desc.value instanceof _index.AbstractValue && desc.value.kind === "widened numeric property"; } } return false; } } exports.default = ArrayValue; //# sourceMappingURL=ArrayValue.js.map