Files
2023-08-01 13:49:46 +02:00

279 lines
17 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Referentializer = undefined;
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 _environment = require("../environment.js");
var _errors = require("../errors.js");
var _index = require("../values/index.js");
var _babelTypes = require("babel-types");
var t = _interopRequireWildcard(_babelTypes);
var _generator = require("../utils/generator.js");
var _invariant = require("../invariant.js");
var _invariant2 = _interopRequireDefault(_invariant);
var _types = require("./types.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 _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
/*
* This class helps fixup names in residual functions for variables that these
* functions capture from parent scopes.
* For each ReferentializationScope it creates a _get_scope_binding function
* that contains the initialization for all of that scope's FunctionInstances
* which will contain a switch statement with all the initializations.
*/
// Each of these will correspond to a different preludeGenerator and thus will
// have different values available for initialization. FunctionValues should
// only be additional functions.
var Referentializer = exports.Referentializer = function () {
function Referentializer(options, scopeNameGenerator, referentializedNameGenerator, statistics) {
_classCallCheck(this, Referentializer);
this._options = options;
this.scopeNameGenerator = scopeNameGenerator;
this.statistics = statistics;
this.referentializationState = new Map();
this._referentializedNameGenerator = referentializedNameGenerator;
}
_createClass(Referentializer, [{
key: "_createReferentializationState",
value: function _createReferentializationState() {
return {
capturedScopeInstanceIdx: 0,
capturedScopesArray: t.identifier(this.scopeNameGenerator.generate("main")),
capturedScopeAccessFunctionId: t.identifier(this.scopeNameGenerator.generate("get_scope_binding")),
serializedScopes: new Map()
};
}
}, {
key: "_getReferentializationState",
value: function _getReferentializationState(referentializationScope) {
return (0, _utils.getOrDefault)(this.referentializationState, referentializationScope, this._createReferentializationState.bind(this));
}
// Generate a shared function for accessing captured scope bindings.
// TODO: skip generating this function if the captured scope is not shared by multiple residual functions.
}, {
key: "createCaptureScopeAccessFunction",
value: function createCaptureScopeAccessFunction(referentializationScope) {
var body = [];
var selectorParam = t.identifier("selector");
var captured = t.identifier("__captured");
var capturedScopesArray = this._getReferentializationState(referentializationScope).capturedScopesArray;
var selectorExpression = t.memberExpression(capturedScopesArray, selectorParam, /*Indexer syntax*/true);
// One switch case for one scope.
var cases = [];
var serializedScopes = this._getReferentializationState(referentializationScope).serializedScopes;
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = serializedScopes.values()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var scopeBinding = _step.value;
var scopeObjectExpression = t.arrayExpression(scopeBinding.initializationValues);
cases.push(t.switchCase(t.numericLiteral(scopeBinding.id), [t.expressionStatement(t.assignmentExpression("=", selectorExpression, scopeObjectExpression)), t.breakStatement()]));
}
// Default case.
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
cases.push(t.switchCase(null, [t.throwStatement(t.newExpression(t.identifier("Error"), [t.stringLiteral("Unknown scope selector")]))]));
body.push(t.variableDeclaration("var", [t.variableDeclarator(captured, selectorExpression)]));
body.push(t.ifStatement(t.unaryExpression("!", captured), t.blockStatement([t.switchStatement(selectorParam, cases), t.expressionStatement(t.assignmentExpression("=", captured, selectorExpression))])));
body.push(t.returnStatement(captured));
var factoryFunction = t.functionExpression(null, [selectorParam], t.blockStatement(body));
var accessFunctionId = this._getReferentializationState(referentializationScope).capturedScopeAccessFunctionId;
return t.variableDeclaration("var", [t.variableDeclarator(accessFunctionId, factoryFunction)]);
}
}, {
key: "_getSerializedBindingScopeInstance",
value: function _getSerializedBindingScopeInstance(residualBinding) {
var declarativeEnvironmentRecord = residualBinding.declarativeEnvironmentRecord;
var referentializationScope = residualBinding.referencedOnlyFromAdditionalFunctions || "GLOBAL";
(0, _invariant2.default)(declarativeEnvironmentRecord);
// figure out if this is accessed only from additional functions
var serializedScopes = this._getReferentializationState(referentializationScope).serializedScopes;
var scope = serializedScopes.get(declarativeEnvironmentRecord);
if (!scope) {
var refState = this._getReferentializationState(referentializationScope);
scope = {
name: this.scopeNameGenerator.generate(),
id: refState.capturedScopeInstanceIdx++,
initializationValues: [],
containingAdditionalFunction: residualBinding.referencedOnlyFromAdditionalFunctions
};
serializedScopes.set(declarativeEnvironmentRecord, scope);
}
residualBinding.scope = scope;
return scope;
}
}, {
key: "getReferentializedScopeInitialization",
value: function getReferentializedScopeInitialization(scope) {
var capturedScope = scope.capturedScope;
(0, _invariant2.default)(capturedScope);
var funcName = this._getReferentializationState(scope.containingAdditionalFunction || "GLOBAL").capturedScopeAccessFunctionId;
return [t.variableDeclaration("var", [t.variableDeclarator(t.identifier(capturedScope), t.callExpression(funcName, [t.identifier(scope.name)]))])];
}
}, {
key: "referentializeBinding",
value: function referentializeBinding(residualBinding, name, instance) {
if (this._options.simpleClosures) {
// When simpleClosures is enabled, then space for captured mutable bindings is allocated upfront.
var serializedBindingId = t.identifier(this._referentializedNameGenerator.generate(name));
var serializedValue = residualBinding.serializedValue;
(0, _invariant2.default)(serializedValue);
var declar = t.variableDeclaration("var", [t.variableDeclarator(serializedBindingId, serializedValue)]);
instance.initializationStatements.push(declar);
residualBinding.serializedValue = serializedBindingId;
} else {
// When simpleClosures is not enabled, then space for captured mutable bindings is allocated lazily.
var scope = this._getSerializedBindingScopeInstance(residualBinding);
var capturedScope = "__captured" + scope.name;
// Save the serialized value for initialization at the top of
// the factory.
// This can serialize more variables than are necessary to execute
// the function because every function serializes every
// modified variable of its parent scope. In some cases it could be
// an improvement to split these variables into multiple
// scopes.
var variableIndexInScope = scope.initializationValues.length;
(0, _invariant2.default)(residualBinding.serializedValue);
scope.initializationValues.push(residualBinding.serializedValue);
scope.capturedScope = capturedScope;
// Replace binding usage with scope references
residualBinding.serializedValue = t.memberExpression(t.identifier(capturedScope), t.numericLiteral(variableIndexInScope), true // Array style access.
);
}
residualBinding.referentialized = true;
this.statistics.referentialized++;
}
}, {
key: "referentialize",
value: function referentialize(unbound, instances, shouldReferentializeInstanceFn) {
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = instances[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var instance = _step2.value;
var residualBindings = instance.residualFunctionBindings;
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
for (var _iterator3 = unbound[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var name = _step3.value;
var residualBinding = residualBindings.get(name);
(0, _invariant2.default)(residualBinding !== undefined);
if (residualBinding.modified) {
// Initialize captured scope at function call instead of globally
if (!residualBinding.referentialized) {
if (!shouldReferentializeInstanceFn(instance)) {
// TODO #989: Fix additional functions and referentialization
throw new _errors.FatalError("TODO: implement referentialization for prepacked functions");
}
this.referentializeBinding(residualBinding, name, instance);
}
(0, _invariant2.default)(residualBinding.referentialized);
if (residualBinding.declarativeEnvironmentRecord && residualBinding.scope) {
instance.scopeInstances.set(residualBinding.scope.name, residualBinding.scope);
}
}
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3.return) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
}
}, {
key: "createCapturedScopesArrayInitialization",
value: function createCapturedScopesArrayInitialization(referentializationScope) {
return t.variableDeclaration("var", [t.variableDeclarator(this._getReferentializationState(referentializationScope).capturedScopesArray, t.callExpression(t.identifier("Array"), [t.numericLiteral(this._getReferentializationState(referentializationScope).capturedScopeInstanceIdx)]))]);
}
}]);
return Referentializer;
}();
//# sourceMappingURL=Referentializer.js.map