1098 lines
48 KiB
JavaScript
1098 lines
48 KiB
JavaScript
"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
|