"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ResidualFunctions = undefined; var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /** * 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. */ var _errors = require("../errors.js"); var _realm = require("../realm.js"); var _index = require("../values/index.js"); var _babelTypes = require("babel-types"); var t = _interopRequireWildcard(_babelTypes); var _babelTraverse = require("babel-traverse"); var _babelTraverse2 = _interopRequireDefault(_babelTraverse); var _invariant = require("../invariant.js"); var _invariant2 = _interopRequireDefault(_invariant); var _types = require("./types.js"); var _visitors = require("./visitors.js"); var _modules = require("./modules.js"); var _ResidualFunctionInitializers = require("./ResidualFunctionInitializers.js"); var _internalizer = require("../utils/internalizer.js"); var _Referentializer = require("./Referentializer.js"); var _utils = require("./utils.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 _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var ResidualFunctions = exports.ResidualFunctions = function () { function ResidualFunctions(realm, statistics, options, modules, requireReturns, locationService, prelude, initializerNameGenerator, factoryNameGenerator, scopeNameGenerator, referentializedNameGenerator, residualFunctionInfos, residualFunctionInstances, additionalFunctionValueInfos, additionalFunctionValueNestedFunctions) { _classCallCheck(this, ResidualFunctions); this.realm = realm; this.statistics = statistics; this.modules = modules; this.requireReturns = requireReturns; this.locationService = locationService; this.prelude = prelude; this.factoryNameGenerator = factoryNameGenerator; this.functionPrototypes = new Map(); this.firstFunctionUsages = new Map(); this.functions = new Map(); this.functionInstances = []; this.residualFunctionInitializers = new _ResidualFunctionInitializers.ResidualFunctionInitializers(locationService, prelude, initializerNameGenerator); this.residualFunctionInfos = residualFunctionInfos; this.residualFunctionInstances = residualFunctionInstances; this.additionalFunctionValueInfos = additionalFunctionValueInfos; this.referentializer = new _Referentializer.Referentializer(options, scopeNameGenerator, referentializedNameGenerator, statistics); var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = residualFunctionInstances.values()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var instance = _step.value; (0, _invariant2.default)(instance !== undefined); if (!additionalFunctionValueInfos.has(instance.functionValue)) this.addFunctionInstance(instance); } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } this.additionalFunctionValueNestedFunctions = additionalFunctionValueNestedFunctions; this.simpleClosures = !!options.simpleClosures; } _createClass(ResidualFunctions, [{ key: "addFunctionInstance", value: function addFunctionInstance(instance) { this.functionInstances.push(instance); var code = instance.functionValue.$ECMAScriptCode; (0, _invariant2.default)(code != null); (0, _utils.getOrDefault)(this.functions, code, function () { return []; }).push(instance); } }, { key: "setFunctionPrototype", value: function setFunctionPrototype(constructor, prototypeId) { this.functionPrototypes.set(constructor, prototypeId); } }, { key: "addFunctionUsage", value: function addFunctionUsage(val, bodyReference) { if (!this.firstFunctionUsages.has(val)) this.firstFunctionUsages.set(val, bodyReference); } }, { key: "_shouldUseFactoryFunction", value: function _shouldUseFactoryFunction(funcBody, instances) { function shouldInlineFunction() { var shouldInline = true; if (funcBody.start && funcBody.end) { var bodySize = funcBody.end - funcBody.start; shouldInline = bodySize <= 30; } return shouldInline; } var functionInfo = this.residualFunctionInfos.get(funcBody); (0, _invariant2.default)(functionInfo); var usesArguments = functionInfo.usesArguments; return !shouldInlineFunction() && instances.length > 1 && !usesArguments && !this.simpleClosures; } // Note: this function takes linear time. Please do not call it inside loop. }, { key: "_hasRewrittenFunctionInstance", value: function _hasRewrittenFunctionInstance(rewrittenAdditionalFunctions, instances) { return instances.find(function (instance) { return rewrittenAdditionalFunctions.has(instance.functionValue); }) !== undefined; } }, { key: "_generateFactoryFunctionInfos", value: function _generateFactoryFunctionInfos(rewrittenAdditionalFunctions) { var factoryFunctionInfos = new Map(); var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = this.functions[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var _ref = _step2.value; var _ref2 = _slicedToArray(_ref, 2); var functionBody = _ref2[0]; var instances = _ref2[1]; (0, _invariant2.default)(instances.length > 0); var factoryId = void 0; var suffix = instances[0].functionValue.__originalName || this.realm.debugNames ? "factoryFunction" : ""; if (this._shouldUseFactoryFunction(functionBody, instances)) { // Rewritten function should never use factory function. (0, _invariant2.default)(!this._hasRewrittenFunctionInstance(rewrittenAdditionalFunctions, instances)); factoryId = t.identifier(this.factoryNameGenerator.generate(suffix)); } else { // For inline function body case, use the first function as the factory function. factoryId = this.locationService.getLocation(instances[0].functionValue); } var functionUniqueTag = functionBody.uniqueOrderedTag; (0, _invariant2.default)(functionUniqueTag); var functionInfo = this.residualFunctionInfos.get(functionBody); (0, _invariant2.default)(functionInfo); factoryFunctionInfos.set(functionUniqueTag, { factoryId: factoryId, functionInfo: functionInfo }); } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } return factoryFunctionInfos; } // Preserve residual functions' ordering based on its ast dfs traversal order. // This is necessary to prevent unexpected code locality issues. }, { key: "_sortFunctionByOriginalOrdering", value: function _sortFunctionByOriginalOrdering(functionEntries) { functionEntries.sort(function (funcA, funcB) { var funcAUniqueTag = funcA[0].uniqueOrderedTag; (0, _invariant2.default)(funcAUniqueTag); var funcBUniqueTag = funcB[0].uniqueOrderedTag; (0, _invariant2.default)(funcBUniqueTag); return funcAUniqueTag - funcBUniqueTag; }); } }, { key: "spliceFunctions", value: function spliceFunctions(rewrittenAdditionalFunctions) { var _this = this; this.residualFunctionInitializers.scrubFunctionInitializers(); var functionBodies = new Map(); // these need to get spliced in at the end var additionalFunctionPreludes = new Map(); var additionalFunctionModifiedBindingsSegment = new Map(); var getModifiedBindingsSegment = function getModifiedBindingsSegment(additionalFunction) { return (0, _utils.getOrDefault)(additionalFunctionModifiedBindingsSegment, additionalFunction, function () { return []; }); }; var getFunctionBody = function getFunctionBody(instance) { return (0, _utils.getOrDefault)(functionBodies, instance, function () { return []; }); }; var globalPrelude = this.prelude; function getPrelude(instance) { var additionalFunction = instance.containingAdditionalFunction; var b = void 0; if (additionalFunction) { b = (0, _utils.getOrDefault)(additionalFunctionPreludes, additionalFunction, function () { return []; }); } else { b = globalPrelude; } return b; } var requireStatistics = { replaced: 0, count: 0 }; var functionEntries = Array.from(this.functions.entries()); this._sortFunctionByOriginalOrdering(functionEntries); this.statistics.functions = functionEntries.length; var unstrictFunctionBodies = []; var strictFunctionBodies = []; var funcNodes = new Map(); var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for (var _iterator3 = functionEntries[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var _ref3 = _step3.value; var _ref4 = _slicedToArray(_ref3, 2); var funcBody = _ref4[0]; var instances = _ref4[1]; var functionInfo = this.residualFunctionInfos.get(funcBody); (0, _invariant2.default)(functionInfo); this.referentializer.referentialize(functionInfo.unbound, instances, function (instance) { return !rewrittenAdditionalFunctions.has(instance.functionValue); }); } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3.return) { _iterator3.return(); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } var defineFunction = function defineFunction(instance, funcId, funcNode) { var functionValue = instance.functionValue; if (instance.initializationStatements.length > 0) { // always add initialization statements to insertion point var initializationBody = getFunctionBody(instance); Array.prototype.push.apply(initializationBody, instance.initializationStatements); } var body = void 0; if (t.isFunctionExpression(funcNode)) { funcNodes.set(functionValue, funcNode); body = getPrelude(instance); } else { (0, _invariant2.default)(t.isCallExpression(funcNode)); // .bind call body = getFunctionBody(instance); } body.push(t.variableDeclaration("var", [t.variableDeclarator(funcId, funcNode)])); var prototypeId = _this.functionPrototypes.get(functionValue); if (prototypeId !== undefined) { var id = _this.locationService.getLocation(functionValue); (0, _invariant2.default)(id !== undefined); body.push(t.variableDeclaration("var", [t.variableDeclarator(prototypeId, t.memberExpression(id, t.identifier("prototype")))])); } }; // Emit code for ModifiedBindings for additional functions var _iteratorNormalCompletion4 = true; var _didIteratorError4 = false; var _iteratorError4 = undefined; try { for (var _iterator4 = this.additionalFunctionValueInfos[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { var _ref5 = _step4.value; var _ref6 = _slicedToArray(_ref5, 2); var funcValue = _ref6[0]; var funcInfo = _ref6[1]; var _iteratorNormalCompletion11 = true; var _didIteratorError11 = false; var _iteratorError11 = undefined; try { for (var _iterator11 = funcInfo.modifiedBindings[Symbol.iterator](), _step11; !(_iteratorNormalCompletion11 = (_step11 = _iterator11.next()).done); _iteratorNormalCompletion11 = true) { var _ref15 = _step11.value; var _ref16 = _slicedToArray(_ref15, 2); var residualBinding = _ref16[1]; var scope = residualBinding.scope; // TODO #989: This should probably be an invariant once captures work properly // Currently we don't referentialize bindings in additional functions (but we // do for bindings nested in additional functions) if (!residualBinding.referentialized) continue; // Find the proper prelude to emit to (global vs additional function's prelude) var bodySegment = getModifiedBindingsSegment(funcValue); // binding has been referentialized, so setup the scope to be able to // access bindings from other __captured_scopes initializers if (scope && scope.containingAdditionalFunction !== funcValue) { var decl = t.variableDeclaration("var", [t.variableDeclarator(t.identifier(scope.name), t.numericLiteral(scope.id))]); var init = this.referentializer.getReferentializedScopeInitialization(scope); bodySegment.push(decl); // flow forces me to do this Array.prototype.push.apply(bodySegment, init); } var newValue = residualBinding.additionalValueSerialized; (0, _invariant2.default)(newValue); var binding_reference = residualBinding.serializedValue; (0, _invariant2.default)(binding_reference); (0, _invariant2.default)(t.isLVal(binding_reference), "Referentialized values are always LVals"); // This mutation is safe because it should always be either a global identifier (for global bindings) // or an accessor to a referentialized value. bodySegment.push(t.expressionStatement(t.assignmentExpression("=", binding_reference, newValue))); } } catch (err) { _didIteratorError11 = true; _iteratorError11 = err; } finally { try { if (!_iteratorNormalCompletion11 && _iterator11.return) { _iterator11.return(); } } finally { if (_didIteratorError11) { throw _iteratorError11; } } } } // Process Additional Functions } catch (err) { _didIteratorError4 = true; _iteratorError4 = err; } finally { try { if (!_iteratorNormalCompletion4 && _iterator4.return) { _iterator4.return(); } } finally { if (_didIteratorError4) { throw _iteratorError4; } } } var _iteratorNormalCompletion5 = true; var _didIteratorError5 = false; var _iteratorError5 = undefined; try { for (var _iterator5 = this.additionalFunctionValueInfos.entries()[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) { var _ref7 = _step5.value; var _ref8 = _slicedToArray(_ref7, 2); var _funcValue = _ref8[0]; var additionalFunctionInfo = _ref8[1]; var instance = additionalFunctionInfo.instance; var functionValue = _funcValue; var params = functionValue.$FormalParameters; (0, _invariant2.default)(params !== undefined); var rewrittenBody = rewrittenAdditionalFunctions.get(_funcValue); (0, _invariant2.default)(rewrittenBody); // rewritten functions shouldn't have references fixed up because the body, // consists of serialized code. For simplicity we emit their instances in a naive way var functionBody = t.blockStatement(rewrittenBody); var id = this.locationService.getLocation(_funcValue); (0, _invariant2.default)(id !== undefined); var funcParams = params.slice(); var funcNode = t.functionExpression(null, funcParams, functionBody); if (_funcValue.$Strict) { strictFunctionBodies.push(funcNode); } else { unstrictFunctionBodies.push(funcNode); } defineFunction(instance, id, funcNode); } // Process normal functions } catch (err) { _didIteratorError5 = true; _iteratorError5 = err; } finally { try { if (!_iteratorNormalCompletion5 && _iterator5.return) { _iterator5.return(); } } finally { if (_didIteratorError5) { throw _iteratorError5; } } } var factoryFunctionInfos = this._generateFactoryFunctionInfos(rewrittenAdditionalFunctions); var _loop = function _loop(_funcBody, _instances) { var functionInfo = _this.residualFunctionInfos.get(_funcBody); (0, _invariant2.default)(functionInfo); var unbound = functionInfo.unbound, modified = functionInfo.modified, usesThis = functionInfo.usesThis; var params = _instances[0].functionValue.$FormalParameters; (0, _invariant2.default)(params !== undefined); // Split instances into normal or nested in an additional function var normalInstances = []; var additionalFunctionNestedInstances = []; var _iteratorNormalCompletion12 = true; var _didIteratorError12 = false; var _iteratorError12 = undefined; try { for (var _iterator12 = _instances[Symbol.iterator](), _step12; !(_iteratorNormalCompletion12 = (_step12 = _iterator12.next()).done); _iteratorNormalCompletion12 = true) { var _instance = _step12.value; if (_this.additionalFunctionValueNestedFunctions.has(_instance.functionValue)) additionalFunctionNestedInstances.push(_instance);else normalInstances.push(_instance); } } catch (err) { _didIteratorError12 = true; _iteratorError12 = err; } finally { try { if (!_iteratorNormalCompletion12 && _iterator12.return) { _iterator12.return(); } } finally { if (_didIteratorError12) { throw _iteratorError12; } } } var naiveProcessInstances = function naiveProcessInstances(instancesToSplice) { _this.statistics.functionClones += instancesToSplice.length - 1; var _iteratorNormalCompletion13 = true; var _didIteratorError13 = false; var _iteratorError13 = undefined; try { for (var _iterator13 = instancesToSplice[Symbol.iterator](), _step13; !(_iteratorNormalCompletion13 = (_step13 = _iterator13.next()).done); _iteratorNormalCompletion13 = true) { var _instance2 = _step13.value; var _functionValue = _instance2.functionValue, residualFunctionBindings = _instance2.residualFunctionBindings, scopeInstances = _instance2.scopeInstances; var _id = _this.locationService.getLocation(_functionValue); var _funcParams = params.slice(); var _funcNode = t.functionExpression(null, _funcParams, t.cloneDeep(_funcBody)); var scopeInitialization = []; var _iteratorNormalCompletion14 = true; var _didIteratorError14 = false; var _iteratorError14 = undefined; try { for (var _iterator14 = scopeInstances[Symbol.iterator](), _step14; !(_iteratorNormalCompletion14 = (_step14 = _iterator14.next()).done); _iteratorNormalCompletion14 = true) { var _ref17 = _step14.value; var _ref18 = _slicedToArray(_ref17, 2); var scopeName = _ref18[0]; var _scope = _ref18[1]; scopeInitialization.push(t.variableDeclaration("var", [t.variableDeclarator(t.identifier(scopeName), t.numericLiteral(_scope.id))])); scopeInitialization = scopeInitialization.concat(_this.referentializer.getReferentializedScopeInitialization(_scope)); } } catch (err) { _didIteratorError14 = true; _iteratorError14 = err; } finally { try { if (!_iteratorNormalCompletion14 && _iterator14.return) { _iterator14.return(); } } finally { if (_didIteratorError14) { throw _iteratorError14; } } } _funcNode.body.body = scopeInitialization.concat(_funcNode.body.body); (0, _babelTraverse2.default)(t.file(t.program([t.expressionStatement(_funcNode)])), _visitors.ClosureRefReplacer, null, { residualFunctionBindings: residualFunctionBindings, modified: modified, requireReturns: _this.requireReturns, requireStatistics: requireStatistics, isRequire: _this.modules.getIsRequire(_funcParams, [_functionValue]), factoryFunctionInfos: factoryFunctionInfos }); if (_functionValue.$Strict) { strictFunctionBodies.push(_funcNode); } else { unstrictFunctionBodies.push(_funcNode); } defineFunction(_instance2, _id, _funcNode); } } catch (err) { _didIteratorError13 = true; _iteratorError13 = err; } finally { try { if (!_iteratorNormalCompletion13 && _iterator13.return) { _iterator13.return(); } } finally { if (_didIteratorError13) { throw _iteratorError13; } } } }; if (additionalFunctionNestedInstances.length > 0) naiveProcessInstances(additionalFunctionNestedInstances); if (!_this._shouldUseFactoryFunction(_funcBody, normalInstances)) { naiveProcessInstances(normalInstances); } else if (normalInstances.length > 0) { var functionUniqueTag = _funcBody.uniqueOrderedTag; (0, _invariant2.default)(functionUniqueTag); var factoryInfo = factoryFunctionInfos.get(functionUniqueTag); (0, _invariant2.default)(factoryInfo); var factoryId = factoryInfo.factoryId; // filter included variables to only include those that are different var factoryNames = []; var sameResidualBindings = new Map(); var _iteratorNormalCompletion15 = true; var _didIteratorError15 = false; var _iteratorError15 = undefined; try { for (var _iterator15 = unbound[Symbol.iterator](), _step15; !(_iteratorNormalCompletion15 = (_step15 = _iterator15.next()).done); _iteratorNormalCompletion15 = true) { var name = _step15.value; var isDifferent = false; var lastBinding = void 0; var firstBinding = normalInstances[0].residualFunctionBindings.get(name); (0, _invariant2.default)(firstBinding); if (firstBinding.modified) { // Must modify for traversal sameResidualBindings.set(name, firstBinding); continue; } var _iteratorNormalCompletion19 = true; var _didIteratorError19 = false; var _iteratorError19 = undefined; try { for (var _iterator19 = normalInstances[Symbol.iterator](), _step19; !(_iteratorNormalCompletion19 = (_step19 = _iterator19.next()).done); _iteratorNormalCompletion19 = true) { var _ref21 = _step19.value; var _residualFunctionBindings = _ref21.residualFunctionBindings; var _residualBinding = _residualFunctionBindings.get(name); (0, _invariant2.default)(_residualBinding); (0, _invariant2.default)(!_residualBinding.modified); if (!lastBinding) { lastBinding = _residualBinding; } else if (!(0, _types.AreSameResidualBinding)(_this.realm, _residualBinding, lastBinding)) { isDifferent = true; break; } } } catch (err) { _didIteratorError19 = true; _iteratorError19 = err; } finally { try { if (!_iteratorNormalCompletion19 && _iterator19.return) { _iterator19.return(); } } finally { if (_didIteratorError19) { throw _iteratorError19; } } } if (isDifferent) { factoryNames.push(name); } else { (0, _invariant2.default)(lastBinding); sameResidualBindings.set(name, lastBinding); } } } catch (err) { _didIteratorError15 = true; _iteratorError15 = err; } finally { try { if (!_iteratorNormalCompletion15 && _iterator15.return) { _iterator15.return(); } } finally { if (_didIteratorError15) { throw _iteratorError15; } } } var factoryParams = []; var _iteratorNormalCompletion16 = true; var _didIteratorError16 = false; var _iteratorError16 = undefined; try { for (var _iterator16 = factoryNames[Symbol.iterator](), _step16; !(_iteratorNormalCompletion16 = (_step16 = _iterator16.next()).done); _iteratorNormalCompletion16 = true) { var key = _step16.value; factoryParams.push(t.identifier(key)); } } catch (err) { _didIteratorError16 = true; _iteratorError16 = err; } finally { try { if (!_iteratorNormalCompletion16 && _iterator16.return) { _iterator16.return(); } } finally { if (_didIteratorError16) { throw _iteratorError16; } } } var scopeInitialization = []; var _iteratorNormalCompletion17 = true; var _didIteratorError17 = false; var _iteratorError17 = undefined; try { for (var _iterator17 = normalInstances[0].scopeInstances[Symbol.iterator](), _step17; !(_iteratorNormalCompletion17 = (_step17 = _iterator17.next()).done); _iteratorNormalCompletion17 = true) { var _ref19 = _step17.value; var _ref20 = _slicedToArray(_ref19, 2); var scopeName = _ref20[0]; var _scope2 = _ref20[1]; factoryParams.push(t.identifier(scopeName)); scopeInitialization = scopeInitialization.concat(_this.referentializer.getReferentializedScopeInitialization(_scope2)); } } catch (err) { _didIteratorError17 = true; _iteratorError17 = err; } finally { try { if (!_iteratorNormalCompletion17 && _iterator17.return) { _iterator17.return(); } } finally { if (_didIteratorError17) { throw _iteratorError17; } } } factoryParams = factoryParams.concat(params).slice(); // The Replacer below mutates the AST while the original AST may still be referenced // by another outer residual function so let's clone the original AST to avoid modifying it. var factoryNode = t.functionExpression(null, factoryParams, t.cloneDeep(_funcBody)); if (normalInstances[0].functionValue.$Strict) { strictFunctionBodies.push(factoryNode); } else { unstrictFunctionBodies.push(factoryNode); } factoryNode.body.body = scopeInitialization.concat(factoryNode.body.body); // factory functions do not depend on any nested generator scope, so they go to the prelude var factoryDeclaration = t.variableDeclaration("var", [t.variableDeclarator(factoryId, factoryNode)]); _this.prelude.push(factoryDeclaration); (0, _babelTraverse2.default)(t.file(t.program([t.expressionStatement(factoryNode)])), _visitors.ClosureRefReplacer, null, { residualFunctionBindings: sameResidualBindings, modified: modified, requireReturns: _this.requireReturns, requireStatistics: requireStatistics, isRequire: _this.modules.getIsRequire(factoryParams, normalInstances.map(function (instance) { return instance.functionValue; })), factoryFunctionInfos: factoryFunctionInfos }); var _loop2 = function _loop2(_instance3) { var functionValue = _instance3.functionValue, residualFunctionBindings = _instance3.residualFunctionBindings, insertionPoint = _instance3.insertionPoint; var functionId = _this.locationService.getLocation(functionValue); (0, _invariant2.default)(functionId !== undefined); var hasFunctionArg = false; var flatArgs = factoryNames.map(function (name) { var residualBinding = residualFunctionBindings.get(name); (0, _invariant2.default)(residualBinding); var serializedValue = residualBinding.serializedValue; hasFunctionArg = hasFunctionArg || residualBinding.value && residualBinding.value instanceof _index.FunctionValue; (0, _invariant2.default)(serializedValue); return serializedValue; }); var _iteratorNormalCompletion20 = true; var _didIteratorError20 = false; var _iteratorError20 = undefined; try { for (var _iterator20 = _instance3.scopeInstances[Symbol.iterator](), _step20; !(_iteratorNormalCompletion20 = (_step20 = _iterator20.next()).done); _iteratorNormalCompletion20 = true) { var entry = _step20.value; flatArgs.push(t.numericLiteral(entry[1].id)); } } catch (err) { _didIteratorError20 = true; _iteratorError20 = err; } finally { try { if (!_iteratorNormalCompletion20 && _iterator20.return) { _iterator20.return(); } } finally { if (_didIteratorError20) { throw _iteratorError20; } } } var funcNode = void 0; var firstUsage = _this.firstFunctionUsages.get(functionValue); (0, _invariant2.default)(insertionPoint !== undefined); if ( // The same free variables in shared instances may refer to objects with different initialization values // so a stub forward function is needed during delay initializations. _this.residualFunctionInitializers.hasInitializerStatement(functionValue) || usesThis || hasFunctionArg || firstUsage !== undefined && !firstUsage.isNotEarlierThan(insertionPoint) || _this.functionPrototypes.get(functionValue) !== undefined || _this.simpleClosures) { var callArgs = [t.thisExpression()]; var _iteratorNormalCompletion21 = true; var _didIteratorError21 = false; var _iteratorError21 = undefined; try { for (var _iterator21 = flatArgs[Symbol.iterator](), _step21; !(_iteratorNormalCompletion21 = (_step21 = _iterator21.next()).done); _iteratorNormalCompletion21 = true) { var flatArg = _step21.value; callArgs.push(flatArg); } } catch (err) { _didIteratorError21 = true; _iteratorError21 = err; } finally { try { if (!_iteratorNormalCompletion21 && _iterator21.return) { _iterator21.return(); } } finally { if (_didIteratorError21) { throw _iteratorError21; } } } var _iteratorNormalCompletion22 = true; var _didIteratorError22 = false; var _iteratorError22 = undefined; try { for (var _iterator22 = params[Symbol.iterator](), _step22; !(_iteratorNormalCompletion22 = (_step22 = _iterator22.next()).done); _iteratorNormalCompletion22 = true) { var param = _step22.value; if (param.type !== "Identifier") { throw new _errors.FatalError("TODO: do not know how to deal with non-Identifier parameters"); } callArgs.push(param); } } catch (err) { _didIteratorError22 = true; _iteratorError22 = err; } finally { try { if (!_iteratorNormalCompletion22 && _iterator22.return) { _iterator22.return(); } } finally { if (_didIteratorError22) { throw _iteratorError22; } } } var callee = t.memberExpression(factoryId, t.identifier("call")); var childBody = t.blockStatement([t.returnStatement(t.callExpression(callee, callArgs))]); funcNode = t.functionExpression(null, params, childBody); if (functionValue.$Strict) { strictFunctionBodies.push(funcNode); } else { unstrictFunctionBodies.push(funcNode); } } else { funcNode = t.callExpression(t.memberExpression(factoryId, t.identifier("bind")), [_internalizer.nullExpression].concat(flatArgs)); } defineFunction(_instance3, functionId, funcNode); }; var _iteratorNormalCompletion18 = true; var _didIteratorError18 = false; var _iteratorError18 = undefined; try { for (var _iterator18 = normalInstances[Symbol.iterator](), _step18; !(_iteratorNormalCompletion18 = (_step18 = _iterator18.next()).done); _iteratorNormalCompletion18 = true) { var _instance3 = _step18.value; _loop2(_instance3); } } catch (err) { _didIteratorError18 = true; _iteratorError18 = err; } finally { try { if (!_iteratorNormalCompletion18 && _iterator18.return) { _iterator18.return(); } } finally { if (_didIteratorError18) { throw _iteratorError18; } } } } }; var _iteratorNormalCompletion6 = true; var _didIteratorError6 = false; var _iteratorError6 = undefined; try { for (var _iterator6 = functionEntries[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) { var _ref9 = _step6.value; var _ref10 = _slicedToArray(_ref9, 2); var _funcBody = _ref10[0]; var _instances = _ref10[1]; _loop(_funcBody, _instances); } } catch (err) { _didIteratorError6 = true; _iteratorError6 = err; } finally { try { if (!_iteratorNormalCompletion6 && _iterator6.return) { _iterator6.return(); } } finally { if (_didIteratorError6) { throw _iteratorError6; } } } var _iteratorNormalCompletion7 = true; var _didIteratorError7 = false; var _iteratorError7 = undefined; try { for (var _iterator7 = this.referentializer.referentializationState.keys()[Symbol.iterator](), _step7; !(_iteratorNormalCompletion7 = (_step7 = _iterator7.next()).done); _iteratorNormalCompletion7 = true) { var referentializationScope = _step7.value; var prelude = this.prelude; // Get the prelude for this additional function value if (referentializationScope !== "GLOBAL") { var _additionalFunction = referentializationScope; prelude = (0, _utils.getOrDefault)(additionalFunctionPreludes, _additionalFunction, function () { return []; }); } prelude.unshift(this.referentializer.createCaptureScopeAccessFunction(referentializationScope)); prelude.unshift(this.referentializer.createCapturedScopesArrayInitialization(referentializationScope)); } } catch (err) { _didIteratorError7 = true; _iteratorError7 = err; } finally { try { if (!_iteratorNormalCompletion7 && _iterator7.return) { _iterator7.return(); } } finally { if (_didIteratorError7) { throw _iteratorError7; } } } var _iteratorNormalCompletion8 = true; var _didIteratorError8 = false; var _iteratorError8 = undefined; try { for (var _iterator8 = this.functionInstances.reverse()[Symbol.iterator](), _step8; !(_iteratorNormalCompletion8 = (_step8 = _iterator8.next()).done); _iteratorNormalCompletion8 = true) { var instance = _step8.value; var functionBody = functionBodies.get(instance); if (functionBody !== undefined) { var insertionPoint = instance.insertionPoint; (0, _invariant2.default)(insertionPoint instanceof _types.BodyReference); // v8 seems to do something clever with array splicing, so this potentially // expensive operations seems to be actually cheap. Array.prototype.splice.apply(insertionPoint.body.entries, [insertionPoint.index, 0].concat(functionBody)); } } } catch (err) { _didIteratorError8 = true; _iteratorError8 = err; } finally { try { if (!_iteratorNormalCompletion8 && _iterator8.return) { _iterator8.return(); } } finally { if (_didIteratorError8) { throw _iteratorError8; } } } var _iteratorNormalCompletion9 = true; var _didIteratorError9 = false; var _iteratorError9 = undefined; try { for (var _iterator9 = rewrittenAdditionalFunctions.entries()[Symbol.iterator](), _step9; !(_iteratorNormalCompletion9 = (_step9 = _iterator9.next()).done); _iteratorNormalCompletion9 = true) { var _ref11 = _step9.value; var _ref12 = _slicedToArray(_ref11, 2); var additionalFunction = _ref12[0]; var body = _ref12[1]; var bodySegment = additionalFunctionModifiedBindingsSegment.get(additionalFunction); var prelude = additionalFunctionPreludes.get(additionalFunction); if (prelude) body.unshift.apply(body, _toConsumableArray(prelude)); if (bodySegment) { if (body.length > 0 && t.isReturnStatement(body[body.length - 1])) { var returnStatement = body.pop(); body.push.apply(body, _toConsumableArray(bodySegment).concat([returnStatement])); } else { body.push.apply(body, _toConsumableArray(bodySegment)); } } } // Inject initializer code for indexed vars into functions (for delay initializations) } catch (err) { _didIteratorError9 = true; _iteratorError9 = err; } finally { try { if (!_iteratorNormalCompletion9 && _iterator9.return) { _iterator9.return(); } } finally { if (_didIteratorError9) { throw _iteratorError9; } } } var _iteratorNormalCompletion10 = true; var _didIteratorError10 = false; var _iteratorError10 = undefined; try { for (var _iterator10 = funcNodes[Symbol.iterator](), _step10; !(_iteratorNormalCompletion10 = (_step10 = _iterator10.next()).done); _iteratorNormalCompletion10 = true) { var _ref13 = _step10.value; var _ref14 = _slicedToArray(_ref13, 2); var functionValue = _ref14[0]; var funcNode = _ref14[1]; var initializerStatement = this.residualFunctionInitializers.getInitializerStatement(functionValue); if (initializerStatement !== undefined) { (0, _invariant2.default)(t.isFunctionExpression(funcNode)); var blockStatement = funcNode.body; blockStatement.body.unshift(initializerStatement); } } } catch (err) { _didIteratorError10 = true; _iteratorError10 = err; } finally { try { if (!_iteratorNormalCompletion10 && _iterator10.return) { _iterator10.return(); } } finally { if (_didIteratorError10) { throw _iteratorError10; } } } return { unstrictFunctionBodies: unstrictFunctionBodies, strictFunctionBodies: strictFunctionBodies, requireStatistics: requireStatistics }; } }]); return ResidualFunctions; }(); //# sourceMappingURL=ResidualFunctions.js.map