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

625 lines
31 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Modules = exports.ModuleTracer = 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 _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
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; }; }();
var _environment = require("../environment.js");
var _errors = require("../errors.js");
var _realm = require("../realm.js");
var _index = require("../methods/index.js");
var _completions = require("../completions.js");
var _singletons = require("../singletons.js");
var _index2 = require("../values/index.js");
var _babelTypes = require("babel-types");
var t = _interopRequireWildcard(_babelTypes);
var _invariant = require("../invariant.js");
var _invariant2 = _interopRequireDefault(_invariant);
var _logger = require("./logger.js");
var _types = require("./types.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 _toArray(arr) { return Array.isArray(arr) ? arr : Array.from(arr); }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
* 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.
*/
function downgradeErrorsToWarnings(realm, f) {
var savedHandler = realm.errorHandler;
function handler(e) {
e.severity = "Warning";
realm.errorHandler = savedHandler;
try {
return realm.handleError(e);
} finally {
realm.errorHandler = handler;
}
}
realm.errorHandler = handler;
try {
return f();
} finally {
realm.errorHandler = savedHandler;
}
}
var ModuleTracer = exports.ModuleTracer = function (_Tracer) {
_inherits(ModuleTracer, _Tracer);
function ModuleTracer(modules, statistics, logModules) {
_classCallCheck(this, ModuleTracer);
var _this = _possibleConstructorReturn(this, (ModuleTracer.__proto__ || Object.getPrototypeOf(ModuleTracer)).call(this));
_this.modules = modules;
_this.evaluateForEffectsNesting = 0;
_this.requireStack = [];
_this.requireSequence = [];
_this.logModules = logModules;
_this.uninitializedModuleIdsRequiredInEvaluateForEffects = new Set();
_this.statistics = statistics;
return _this;
}
// We can't say that a module has been initialized if it was initialized in a
// evaluate for effects context until we know the effects are applied.
_createClass(ModuleTracer, [{
key: "log",
value: function log(message) {
if (this.logModules) console.log("[modules] " + this.requireStack.map(function (_) {
return " ";
}).join("") + message);
}
}, {
key: "beginEvaluateForEffects",
value: function beginEvaluateForEffects(state) {
if (state !== this) {
this.log(">evaluate for effects");
this.evaluateForEffectsNesting++;
this.requireStack.push(undefined);
}
}
}, {
key: "endEvaluateForEffects",
value: function endEvaluateForEffects(state, effects) {
if (state !== this) {
var popped = this.requireStack.pop();
(0, _invariant2.default)(popped === undefined);
this.evaluateForEffectsNesting--;
this.log("<evaluate for effects");
}
}
}, {
key: "detourCall",
value: function detourCall(F, thisArgument, argumentsList, newTarget, performCall) {
var _this2 = this;
var realm = this.modules.realm;
if (F === this.modules.getRequire() && !this.modules.disallowDelayingRequiresOverride && argumentsList.length === 1) {
var moduleId = argumentsList[0];
var moduleIdValue = void 0;
if (moduleId instanceof _index2.NumberValue || moduleId instanceof _index2.StringValue) {
moduleIdValue = moduleId.value;
if (!this.modules.moduleIds.has(moduleIdValue) && this.modules.delayUnsupportedRequires) {
this.modules.logger.logError(moduleId, "Module referenced by require call has not been defined.");
}
} else {
if (this.modules.delayUnsupportedRequires) {
this.modules.logger.logError(moduleId, "First argument to require function is not a number or string value.");
}
return undefined;
}
if (!this.modules.delayUnsupportedRequires) {
if ((this.requireStack.length === 0 || this.requireStack[this.requireStack.length - 1] !== moduleIdValue) && this.modules.moduleIds.has(moduleIdValue)) {
this.requireStack.push(moduleIdValue);
try {
var value = performCall();
this.modules.recordModuleInitialized(moduleIdValue, value);
// Make this into a join point by suppressing the conditional exception.
// TODO: delete this code and let the caller deal with the conditional exception.
var completion = _singletons.Functions.incorporateSavedCompletion(realm, value);
if (completion instanceof _completions.PossiblyNormalCompletion) {
realm.stopEffectCapture(completion);
var warning = new _errors.CompilerDiagnostic("Module import may fail with an exception", completion.location, "PP0018", "Warning");
realm.handleError(warning);
}
return value;
} finally {
(0, _invariant2.default)(this.requireStack.pop() === moduleIdValue);
}
}
return undefined;
}
// If a require fails, recover from it and delay the factory call until runtime
this.log(">require(" + moduleIdValue + ")");
var isTopLevelRequire = this.requireStack.length === 0;
if (this.evaluateForEffectsNesting > 0) {
if (isTopLevelRequire) {
var diagnostic = new _errors.CompilerDiagnostic("Non-deterministically conditional top-level require not currently supported", realm.currentLocation, "PP0017", "FatalError");
realm.handleError(diagnostic);
throw new _errors.FatalError();
} else if (!this.modules.isModuleInitialized(moduleIdValue)) this.uninitializedModuleIdsRequiredInEvaluateForEffects.add(moduleIdValue);
return undefined;
} else {
return downgradeErrorsToWarnings(realm, function () {
var result = void 0;
try {
_this2.requireStack.push(moduleIdValue);
var requireSequenceStart = _this2.requireSequence.length;
_this2.requireSequence.push(moduleIdValue);
var acceleratedModuleIds = void 0,
effects = void 0;
var previousNumDelayedModules = _this2.statistics.delayedModules;
do {
try {
effects = realm.evaluateForEffects(function () {
return performCall();
}, _this2);
} catch (e) {}
acceleratedModuleIds = [];
if (isTopLevelRequire) {
// We gathered all effects, but didn't apply them yet.
// Let's check if there was any call to `require` in a
// evaluate-for-effects context. If so, try to initialize
// that module right now. Acceleration module initialization in this
// way might not actually be desirable, but it works around
// general prepack-limitations around joined abstract values involving
// conditionals. Long term, Prepack needs to implement a notion of refinement
// of conditional abstract values under the known path condition.
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = _this2.uninitializedModuleIdsRequiredInEvaluateForEffects[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var nestedModuleId = _step.value;
var nestedEffects = _this2.modules.tryInitializeModule(nestedModuleId, "accelerated initialization of conditional module " + nestedModuleId + " as it's required in an evaluate-for-effects context by module " + moduleIdValue);
if (_this2.modules.accelerateUnsupportedRequires && nestedEffects !== undefined && nestedEffects[0] instanceof _index2.Value && _this2.modules.isModuleInitialized(nestedModuleId)) {
acceleratedModuleIds.push(nestedModuleId);
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
_this2.uninitializedModuleIdsRequiredInEvaluateForEffects.clear();
// Keep restarting for as long as we find additional modules to accelerate.
if (acceleratedModuleIds.length > 0) {
console.log("restarting require(" + moduleIdValue + ") after accelerating conditional require calls for " + acceleratedModuleIds.join());
_this2.statistics.acceleratedModules += acceleratedModuleIds.length;
}
}
} while (acceleratedModuleIds.length > 0);
if (effects === undefined || effects[0] instanceof _completions.AbruptCompletion) {
console.log("delaying require(" + moduleIdValue + ")");
_this2.statistics.delayedModules = previousNumDelayedModules + 1;
// So we are about to emit a delayed require(...) call.
// However, before we do that, let's try to require all modules that we
// know this delayed require call will require.
// This way, we ensure that those modules will be fully initialized
// before the require call executes.
// TODO #690: More needs to be done to make the delayUnsupportedRequires
// feature completely safe. Open issues are:
// 1) Side-effects on the heap of delayed factory functions are not discovered or rejected.
// 2) While we do process an appropriate list of transitively required modules here,
// it's likely just a subset / prefix of all transivitely required modules, as
// more modules would have been required if the Introspection exception had not been thrown.
// To be correct, those modules would have to be prepacked here as well.
// TODO #798: Watch out for an upcoming change to the __d module declaration where the statically known
// list of dependencies will be announced, so we'll no longer have to guess.
var nestedModulesIds = new Set();
for (var i = requireSequenceStart; i < _this2.requireSequence.length; i++) {
var _nestedModuleId = _this2.requireSequence[i];
if (nestedModulesIds.has(_nestedModuleId)) continue;
nestedModulesIds.add(_nestedModuleId);
_this2.modules.tryInitializeModule(_nestedModuleId, "initialization of module " + _nestedModuleId + " as it's required by module " + moduleIdValue);
}
result = _index2.AbstractValue.createTemporalFromBuildFunction(realm, _index2.Value, [], function (_ref) {
var _ref2 = _toArray(_ref);
return t.callExpression(t.identifier("require"), [t.valueToNode(moduleIdValue)]);
});
} else {
result = effects[0];
if (result instanceof _index2.Value) {
realm.applyEffects(effects, "initialization of module " + moduleIdValue);
_this2.modules.recordModuleInitialized(moduleIdValue, result);
} else if (result instanceof _completions.PossiblyNormalCompletion) {
var _warning = new _errors.CompilerDiagnostic("Module import may fail with an exception", result.location, "PP0018", "Warning");
realm.handleError(_warning);
result = result.value;
realm.applyEffects(effects, "initialization of module " + moduleIdValue);
_this2.modules.recordModuleInitialized(moduleIdValue, result);
} else {
(0, _invariant2.default)(false);
}
}
} finally {
var popped = _this2.requireStack.pop();
(0, _invariant2.default)(popped === moduleIdValue);
_this2.log("<require(" + moduleIdValue + ")");
}
(0, _invariant2.default)(result instanceof _index2.Value);
return result;
});
}
} else if (F === this.modules.getDefine()) {
if (this.evaluateForEffectsNesting !== 0) this.modules.logger.logError(F, "Defining a module in nested partial evaluation is not supported.");
var factoryFunction = argumentsList[0];
if (factoryFunction instanceof _index2.FunctionValue) this.modules.factoryFunctions.add(factoryFunction);else this.modules.logger.logError(factoryFunction, "First argument to define function is not a function value.");
var _moduleId = argumentsList[1];
if (_moduleId instanceof _index2.NumberValue || _moduleId instanceof _index2.StringValue) this.modules.moduleIds.add(_moduleId.value);else this.modules.logger.logError(_moduleId, "Second argument to define function is not a number or string value.");
}
return undefined;
}
}]);
return ModuleTracer;
}(_realm.Tracer);
var Modules = exports.Modules = function () {
function Modules(realm, logger, statistics, logModules, delayUnsupportedRequires, accelerateUnsupportedRequires) {
_classCallCheck(this, Modules);
this.realm = realm;
this.logger = logger;
this._require = realm.intrinsics.undefined;
this._define = realm.intrinsics.undefined;
this.factoryFunctions = new Set();
this.moduleIds = new Set();
this.initializedModules = new Map();
realm.tracers.push(this.moduleTracer = new ModuleTracer(this, statistics, logModules));
this.delayUnsupportedRequires = delayUnsupportedRequires;
this.accelerateUnsupportedRequires = accelerateUnsupportedRequires;
this.disallowDelayingRequiresOverride = false;
}
_createClass(Modules, [{
key: "resolveInitializedModules",
value: function resolveInitializedModules() {
this.initializedModules.clear();
var globalInitializedModulesMap = this._getGlobalProperty("__initializedModules");
(0, _invariant2.default)(globalInitializedModulesMap instanceof _index2.ObjectValue);
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = globalInitializedModulesMap.properties.keys()[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var moduleId = _step2.value;
var property = globalInitializedModulesMap.properties.get(moduleId);
(0, _invariant2.default)(property);
var moduleValue = property.descriptor && property.descriptor.value;
if (moduleValue instanceof _index2.Value) this.initializedModules.set(moduleId, moduleValue);
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
}
}, {
key: "_getGlobalProperty",
value: function _getGlobalProperty(name) {
if (this.active) return this.realm.intrinsics.undefined;
this.active = true;
try {
var realm = this.realm;
return this.logger.tryQuery(function () {
return (0, _index.Get)(realm, realm.$GlobalObject, name);
}, realm.intrinsics.undefined, false);
} finally {
this.active = false;
}
}
}, {
key: "getRequire",
value: function getRequire() {
if (!(this._require instanceof _index2.FunctionValue)) this._require = this._getGlobalProperty("require");
return this._require;
}
}, {
key: "getDefine",
value: function getDefine() {
if (!(this._define instanceof _index2.FunctionValue)) this._define = this._getGlobalProperty("__d");
return this._define;
}
}, {
key: "getIsRequire",
value: function getIsRequire(formalParameters, functions) {
var realm = this.realm;
var logger = this.logger;
var modules = this;
return function (scope, node) {
if (!t.isIdentifier(node.callee) || node.arguments.length !== 1 || !node.arguments[0]) return false;
var argument = node.arguments[0];
if (!t.isNumericLiteral(argument) && !t.isStringLiteral(argument)) return false;
(0, _invariant2.default)(node.callee);
var innerName = node.callee.name;
var _loop = function _loop(f) {
var scopedBinding = scope.getBinding(innerName);
if (scopedBinding) {
if (modules.factoryFunctions.has(f) && formalParameters[1] === scopedBinding.path.node) {
(0, _invariant2.default)(scopedBinding.kind === "param");
return "continue";
}
// The name binds to some local entity, but nothing we'd know what exactly it is
return {
v: false
};
}
var doesNotMatter = true;
var reference = logger.tryQuery(function () {
return _singletons.Environment.ResolveBinding(realm, innerName, doesNotMatter, f.$Environment);
}, undefined, false);
if (reference === undefined) {
// We couldn't resolve as we came across some behavior that we cannot deal with abstractly
return {
v: false
};
}
if (_singletons.Environment.IsUnresolvableReference(realm, reference)) return {
v: false
};
var referencedBase = reference.base;
var referencedName = reference.referencedName;
if (typeof referencedName !== "string") return {
v: false
};
var value = void 0;
if (reference.base instanceof _environment.GlobalEnvironmentRecord) {
value = logger.tryQuery(function () {
return (0, _index.Get)(realm, realm.$GlobalObject, innerName);
}, realm.intrinsics.undefined, false);
} else {
(0, _invariant2.default)(referencedBase instanceof _environment.DeclarativeEnvironmentRecord);
var binding = referencedBase.bindings[referencedName];
if (!binding.initialized) return {
v: false
};
value = binding.value;
}
if (value !== modules.getRequire()) return {
v: false
};
};
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
for (var _iterator3 = functions[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var f = _step3.value;
var _ret = _loop(f);
switch (_ret) {
case "continue":
continue;
default:
if ((typeof _ret === "undefined" ? "undefined" : _typeof(_ret)) === "object") return _ret.v;
}
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3.return) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
return true;
};
}
}, {
key: "recordModuleInitialized",
value: function recordModuleInitialized(moduleId, value) {
this.realm.assignToGlobal(t.memberExpression(t.memberExpression(t.identifier("global"), t.identifier("__initializedModules")), t.identifier("" + moduleId)), value);
}
}, {
key: "tryInitializeModule",
value: function tryInitializeModule(moduleId, message) {
var _this3 = this;
var realm = this.realm;
var previousDisallowDelayingRequiresOverride = this.disallowDelayingRequiresOverride;
this.disallowDelayingRequiresOverride = true;
return downgradeErrorsToWarnings(realm, function () {
try {
var _node = t.callExpression(t.identifier("require"), [t.valueToNode(moduleId)]);
var effects = realm.evaluateNodeForEffectsInGlobalEnv(_node);
realm.applyEffects(effects, message);
return effects;
} catch (err) {
if (err instanceof _errors.FatalError) return undefined;else throw err;
} finally {
_this3.disallowDelayingRequiresOverride = previousDisallowDelayingRequiresOverride;
}
});
}
}, {
key: "initializeMoreModules",
value: function initializeMoreModules() {
// partially evaluate all factory methods by calling require
var count = 0;
var _iteratorNormalCompletion4 = true;
var _didIteratorError4 = false;
var _iteratorError4 = undefined;
try {
for (var _iterator4 = this.moduleIds[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
var moduleId = _step4.value;
if (this.initializedModules.has(moduleId)) continue;
var effects = this.tryInitializeModule(moduleId, "Speculative initialization of module " + moduleId);
if (effects === undefined) continue;
var result = effects[0];
if (!(result instanceof _index2.Value)) continue; // module might throw
count++;
this.initializedModules.set(moduleId, result);
}
} catch (err) {
_didIteratorError4 = true;
_iteratorError4 = err;
} finally {
try {
if (!_iteratorNormalCompletion4 && _iterator4.return) {
_iterator4.return();
}
} finally {
if (_didIteratorError4) {
throw _iteratorError4;
}
}
}
if (count > 0) console.log("=== speculatively initialized " + count + " additional modules");
}
}, {
key: "isModuleInitialized",
value: function isModuleInitialized(moduleId) {
var realm = this.realm;
var oldReadOnly = realm.setReadOnly(true);
var oldDisallowDelayingRequiresOverride = this.disallowDelayingRequiresOverride;
this.disallowDelayingRequiresOverride = true;
try {
var _node2 = t.callExpression(t.identifier("require"), [t.valueToNode(moduleId)]);
var _realm$evaluateNodeFo = realm.evaluateNodeForEffectsInGlobalEnv(_node2),
_realm$evaluateNodeFo2 = _slicedToArray(_realm$evaluateNodeFo, 5),
compl = _realm$evaluateNodeFo2[0],
generator = _realm$evaluateNodeFo2[1],
bindings = _realm$evaluateNodeFo2[2],
properties = _realm$evaluateNodeFo2[3],
createdObjects = _realm$evaluateNodeFo2[4];
// for lint unused
(0, _invariant2.default)(bindings);
if (compl instanceof _completions.AbruptCompletion) return undefined;
(0, _invariant2.default)(compl instanceof _index2.Value);
if (!generator.empty() || compl instanceof _index2.ObjectValue && createdObjects.has(compl)) return undefined;
// Check for escaping property assignments, if none escape, we got an existing object
var escapes = false;
var _iteratorNormalCompletion5 = true;
var _didIteratorError5 = false;
var _iteratorError5 = undefined;
try {
for (var _iterator5 = properties[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
var _ref3 = _step5.value;
var _ref4 = _slicedToArray(_ref3, 1);
var binding = _ref4[0];
var object = binding.object;
(0, _invariant2.default)(object instanceof _index2.ObjectValue);
if (!createdObjects.has(object)) escapes = true;
}
} catch (err) {
_didIteratorError5 = true;
_iteratorError5 = err;
} finally {
try {
if (!_iteratorNormalCompletion5 && _iterator5.return) {
_iterator5.return();
}
} finally {
if (_didIteratorError5) {
throw _iteratorError5;
}
}
}
if (escapes) return undefined;
return compl;
} catch (err) {
if (err instanceof _errors.FatalError) return undefined;
throw err;
} finally {
realm.setReadOnly(oldReadOnly);
this.disallowDelayingRequiresOverride = oldDisallowDelayingRequiresOverride;
}
}
}]);
return Modules;
}();
//# sourceMappingURL=modules.js.map