"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("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(" 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