UNPKG

prepack

Version:

Execute a JS bundle, serialize global state and side effects to a snapshot that can be quickly restored.

224 lines (176 loc) 10.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Serializer = undefined; var _environment = require("../environment.js"); var _realm = require("../realm.js"); var _errors = require("../errors.js"); var _completions = require("../completions.js"); var _generator = require("../utils/generator.js"); var _babelGenerator = require("babel-generator"); var _babelGenerator2 = _interopRequireDefault(_babelGenerator); var _traverseFast = require("../utils/traverse-fast.js"); var _traverseFast2 = _interopRequireDefault(_traverseFast); var _invariant = require("../invariant.js"); var _invariant2 = _interopRequireDefault(_invariant); var _types = require("./types.js"); var _functions = require("./functions.js"); var _logger = require("../utils/logger.js"); var _modules = require("../utils/modules.js"); var _flow = require("../utils/flow.js"); var _LoggingTracer = require("./LoggingTracer.js"); var _ResidualHeapVisitor = require("./ResidualHeapVisitor.js"); var _ResidualHeapSerializer = require("./ResidualHeapSerializer.js"); var _ResidualHeapValueIdentifiers = require("./ResidualHeapValueIdentifiers.js"); var _LazyObjectsSerializer = require("./LazyObjectsSerializer.js"); var _babelTypes = require("babel-types"); var t = _interopRequireWildcard(_babelTypes); var _ResidualHeapRefCounter = require("./ResidualHeapRefCounter"); var _ResidualHeapGraphGenerator = require("./ResidualHeapGraphGenerator"); var _Referentializer = require("./Referentializer.js"); 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 _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * 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. */ class Serializer { constructor(realm, serializerOptions = {}) { (0, _invariant2.default)(realm.useAbstractInterpretation); // Start tracking mutations realm.generator = new _generator.Generator(realm, "main"); this.realm = realm; this.logger = new _logger.Logger(this.realm, !!serializerOptions.internalDebug); this.statistics = new _types.SerializerStatistics(); this.modules = new _modules.Modules(this.realm, this.logger, this.statistics, !!serializerOptions.logModules, !!serializerOptions.delayUnsupportedRequires, !!serializerOptions.accelerateUnsupportedRequires); this.functions = new _functions.Functions(this.realm, this.modules.moduleTracer); if (serializerOptions.trace) this.realm.tracers.push(new _LoggingTracer.LoggingTracer(this.realm)); this.options = serializerOptions; this.react = { usedReactElementKeys: new Set() }; } _execute(sources, sourceMaps = false) { let realm = this.realm; let [res, code] = realm.$GlobalEnv.executeSources(sources, "script", ast => { let realmPreludeGenerator = realm.preludeGenerator; (0, _invariant2.default)(realmPreludeGenerator); let forbiddenNames = realmPreludeGenerator.nameGenerator.forbiddenNames; (0, _traverseFast2.default)(ast, node => { if (!t.isIdentifier(node)) return false; forbiddenNames.add(node.name); return true; }); }); if (res instanceof _completions.AbruptCompletion) { let context = new _realm.ExecutionContext(); realm.pushContext(context); try { this.logger.logCompletion(res); } finally { realm.popContext(context); } let diagnostic = new _errors.CompilerDiagnostic("Global code may end abruptly", res.location, "PP0016", "FatalError"); realm.handleError(diagnostic); throw new _errors.FatalError(); } return code; } init(sources, sourceMaps = false) { // Phase 1: Let's interpret. let timingStats = this.options.profile ? new _types.TimingStatistics() : undefined; if (timingStats !== undefined) { timingStats.totalTime = Date.now(); timingStats.globalCodeTime = Date.now(); } if (this.realm.react.verbose) { this.logger.logInformation(`Evaluating initialization path...`); } let code = this._execute(sources); let environmentRecordIdAfterGlobalCode = _environment.EnvironmentRecord.nextId; if (timingStats !== undefined) timingStats.globalCodeTime = Date.now() - timingStats.globalCodeTime; if (this.logger.hasErrors()) return undefined; this.modules.resolveInitializedModules(); this.functions.checkThatFunctionsAreIndependent(); let reactStatistics = null; if (this.realm.react.enabled) { reactStatistics = new _types.ReactStatistics(); this.functions.checkRootReactComponentTrees(reactStatistics, this.react); } if (this.options.initializeMoreModules) { if (timingStats !== undefined) timingStats.initializeMoreModulesTime = Date.now(); this.modules.initializeMoreModules(); if (this.logger.hasErrors()) return undefined; if (timingStats !== undefined) timingStats.initializeMoreModulesTime = Date.now() - timingStats.initializeMoreModulesTime; } let additionalFunctionValuesAndEffects = this.functions.getAdditionalFunctionValuesToEffects(); // Deep traversal of the heap to identify the necessary scope of residual functions if (timingStats !== undefined) timingStats.deepTraversalTime = Date.now(); let preludeGenerator = this.realm.preludeGenerator; (0, _invariant2.default)(preludeGenerator !== undefined); let referentializer = new _Referentializer.Referentializer(this.realm, this.options, preludeGenerator.createNameGenerator("__scope_"), preludeGenerator.createNameGenerator("$"), this.statistics); if (this.realm.react.verbose) { this.logger.logInformation(`Visiting evaluated nodes...`); } let residualHeapVisitor = new _ResidualHeapVisitor.ResidualHeapVisitor(this.realm, this.logger, this.modules, additionalFunctionValuesAndEffects, referentializer, environmentRecordIdAfterGlobalCode); residualHeapVisitor.visitRoots(); if (this.logger.hasErrors()) return undefined; if (timingStats !== undefined) timingStats.deepTraversalTime = Date.now() - timingStats.deepTraversalTime; if (this.realm.react.verbose) { this.logger.logInformation(`Serializing evaluated nodes...`); } const realmPreludeGenerator = this.realm.preludeGenerator; (0, _invariant2.default)(realmPreludeGenerator); const residualHeapValueIdentifiers = new _ResidualHeapValueIdentifiers.ResidualHeapValueIdentifiers(residualHeapVisitor.values.keys(), realmPreludeGenerator); let heapGraph; if (this.options.heapGraphFormat) { const heapRefCounter = new _ResidualHeapRefCounter.ResidualHeapRefCounter(this.realm, this.logger, this.modules, additionalFunctionValuesAndEffects, referentializer); heapRefCounter.visitRoots(); const heapGraphGenerator = new _ResidualHeapGraphGenerator.ResidualHeapGraphGenerator(this.realm, this.logger, this.modules, additionalFunctionValuesAndEffects, residualHeapValueIdentifiers, heapRefCounter.getResult(), referentializer); heapGraphGenerator.visitRoots(); (0, _invariant2.default)(this.options.heapGraphFormat); heapGraph = heapGraphGenerator.generateResult(this.options.heapGraphFormat); } // Phase 2: Let's serialize the heap and generate code. // Serialize for the first time in order to gather reference counts if (this.options.inlineExpressions) { if (timingStats !== undefined) timingStats.referenceCountsTime = Date.now(); residualHeapValueIdentifiers.initPass1(); new _ResidualHeapSerializer.ResidualHeapSerializer(this.realm, this.logger, this.modules, residualHeapValueIdentifiers, residualHeapVisitor.inspector, residualHeapVisitor.values, residualHeapVisitor.functionInstances, residualHeapVisitor.classMethodInstances, residualHeapVisitor.functionInfos, this.options, residualHeapVisitor.referencedDeclaredValues, additionalFunctionValuesAndEffects, residualHeapVisitor.additionalFunctionValueInfos, residualHeapVisitor.declarativeEnvironmentRecordsBindings, this.statistics, this.react, referentializer, residualHeapVisitor.generatorParents).serialize(); if (this.logger.hasErrors()) return undefined; if (timingStats !== undefined) timingStats.referenceCountsTime = Date.now() - timingStats.referenceCountsTime; residualHeapValueIdentifiers.initPass2(); } // Serialize for a second time, using reference counts to minimize number of generated identifiers if (timingStats !== undefined) timingStats.serializePassTime = Date.now(); const TargetSerializer = this.options.lazyObjectsRuntime != null ? _LazyObjectsSerializer.LazyObjectsSerializer : _ResidualHeapSerializer.ResidualHeapSerializer; let residualHeapSerializer = new TargetSerializer(this.realm, this.logger, this.modules, residualHeapValueIdentifiers, residualHeapVisitor.inspector, residualHeapVisitor.values, residualHeapVisitor.functionInstances, residualHeapVisitor.classMethodInstances, residualHeapVisitor.functionInfos, this.options, residualHeapVisitor.referencedDeclaredValues, additionalFunctionValuesAndEffects, residualHeapVisitor.additionalFunctionValueInfos, residualHeapVisitor.declarativeEnvironmentRecordsBindings, this.statistics, this.react, referentializer, residualHeapVisitor.generatorParents); let ast = residualHeapSerializer.serialize(); if (this.realm.stripFlow) { (0, _flow.stripFlowTypeAnnotations)(ast); } // the signature for generate is not complete, hence the any let generated = (0, _babelGenerator2.default)(ast, { sourceMaps: sourceMaps }, code); if (timingStats !== undefined) { timingStats.serializePassTime = Date.now() - timingStats.serializePassTime; timingStats.totalTime = Date.now() - timingStats.totalTime; } (0, _invariant2.default)(!this.logger.hasErrors()); if (this.options.logStatistics) residualHeapSerializer.statistics.log(); return { code: generated.code, map: generated.map, reactStatistics, statistics: residualHeapSerializer.statistics, timingStats: timingStats, heapGraph }; } } exports.Serializer = Serializer; //# sourceMappingURL=serializer.js.map