Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
v8-compile-cache.js352 linesDownload Raw Back to lib
1'use strict';2 3const Module = require('module');4const crypto = require('crypto');5const fs = require('fs');6const path = require('path');7const vm = require('vm');8const os = require('os');9 10const hasOwnProperty = Object.prototype.hasOwnProperty;11 12//------------------------------------------------------------------------------13// FileSystemBlobStore14//------------------------------------------------------------------------------15 16class FileSystemBlobStore {17  constructor(directory, prefix) {18    const name = prefix ? slashEscape(prefix + '.') : '';19    this._blobFilename = path.join(directory, name + 'BLOB');20    this._mapFilename = path.join(directory, name + 'MAP');21    this._lockFilename = path.join(directory, name + 'LOCK');22    this._directory = directory;23    this._load();24  }25 26  has(key, invalidationKey) {27    if (hasOwnProperty.call(this._memoryBlobs, key)) {28      return this._invalidationKeys[key] === invalidationKey;29    } else if (hasOwnProperty.call(this._storedMap, key)) {30      return this._storedMap[key][0] === invalidationKey;31    }32    return false;33  }34 35  get(key, invalidationKey) {36    if (hasOwnProperty.call(this._memoryBlobs, key)) {37      if (this._invalidationKeys[key] === invalidationKey) {38        return this._memoryBlobs[key];39      }40    } else if (hasOwnProperty.call(this._storedMap, key)) {41      const mapping = this._storedMap[key];42      if (mapping[0] === invalidationKey) {43        return this._storedBlob.slice(mapping[1], mapping[2]);44      }45    }46  }47 48  set(key, invalidationKey, buffer) {49    this._invalidationKeys[key] = invalidationKey;50    this._memoryBlobs[key] = buffer;51    this._dirty = true;52  }53 54  delete(key) {55    if (hasOwnProperty.call(this._memoryBlobs, key)) {56      this._dirty = true;57      delete this._memoryBlobs[key];58    }59    if (hasOwnProperty.call(this._invalidationKeys, key)) {60      this._dirty = true;61      delete this._invalidationKeys[key];62    }63    if (hasOwnProperty.call(this._storedMap, key)) {64      this._dirty = true;65      delete this._storedMap[key];66    }67  }68 69  isDirty() {70    return this._dirty;71  }72 73  save() {74    const dump = this._getDump();75    const blobToStore = Buffer.concat(dump[0]);76    const mapToStore = JSON.stringify(dump[1]);77 78    try {79      mkdirpSync(this._directory);80      fs.writeFileSync(this._lockFilename, 'LOCK', {flag: 'wx'});81    } catch (error) {82      // Swallow the exception if we fail to acquire the lock.83      return false;84    }85 86    try {87      fs.writeFileSync(this._blobFilename, blobToStore);88      fs.writeFileSync(this._mapFilename, mapToStore);89    } catch (error) {90      throw error;91    } finally {92      fs.unlinkSync(this._lockFilename);93    }94 95    return true;96  }97 98  _load() {99    try {100      this._storedBlob = fs.readFileSync(this._blobFilename);101      this._storedMap = JSON.parse(fs.readFileSync(this._mapFilename));102    } catch (e) {103      this._storedBlob = Buffer.alloc(0);104      this._storedMap = {};105    }106    this._dirty = false;107    this._memoryBlobs = {};108    this._invalidationKeys = {};109  }110 111  _getDump() {112    const buffers = [];113    const newMap = {};114    let offset = 0;115 116    function push(key, invalidationKey, buffer) {117      buffers.push(buffer);118      newMap[key] = [invalidationKey, offset, offset + buffer.length];119      offset += buffer.length;120    }121 122    for (const key of Object.keys(this._memoryBlobs)) {123      const buffer = this._memoryBlobs[key];124      const invalidationKey = this._invalidationKeys[key];125      push(key, invalidationKey, buffer);126    }127 128    for (const key of Object.keys(this._storedMap)) {129      if (hasOwnProperty.call(newMap, key)) continue;130      const mapping = this._storedMap[key];131      const buffer = this._storedBlob.slice(mapping[1], mapping[2]);132      push(key, mapping[0], buffer);133    }134 135    return [buffers, newMap];136  }137}138 139//------------------------------------------------------------------------------140// NativeCompileCache141//------------------------------------------------------------------------------142 143class NativeCompileCache {144  constructor() {145    this._cacheStore = null;146    this._previousModuleCompile = null;147  }148 149  setCacheStore(cacheStore) {150    this._cacheStore = cacheStore;151  }152 153  install() {154    const self = this;155    this._previousModuleCompile = Module.prototype._compile;156    Module.prototype._compile = function(content, filename) {157      const mod = this;158      function require(id) {159        return mod.require(id);160      }161      require.resolve = function(request) {162        return Module._resolveFilename(request, mod);163      };164      require.main = process.mainModule;165 166      // Enable support to add extra extension types167      require.extensions = Module._extensions;168      require.cache = Module._cache;169 170      const dirname = path.dirname(filename);171 172      const compiledWrapper = self._moduleCompile(filename, content);173 174      // We skip the debugger setup because by the time we run, node has already175      // done that itself.176 177      const args = [mod.exports, require, mod, filename, dirname, process, global];178      return compiledWrapper.apply(mod.exports, args);179    };180  }181 182  uninstall() {183    Module.prototype._compile = this._previousModuleCompile;184  }185 186  _moduleCompile(filename, content) {187    // https://github.com/nodejs/node/blob/v7.5.0/lib/module.js#L511188 189    // Remove shebang190    var contLen = content.length;191    if (contLen >= 2) {192      if (content.charCodeAt(0) === 35/*#*/ &&193          content.charCodeAt(1) === 33/*!*/) {194        if (contLen === 2) {195          // Exact match196          content = '';197        } else {198          // Find end of shebang line and slice it off199          var i = 2;200          for (; i < contLen; ++i) {201            var code = content.charCodeAt(i);202            if (code === 10/*\n*/ || code === 13/*\r*/) break;203          }204          if (i === contLen) {205            content = '';206          } else {207            // Note that this actually includes the newline character(s) in the208            // new output. This duplicates the behavior of the regular209            // expression that was previously used to replace the shebang line210            content = content.slice(i);211          }212        }213      }214    }215 216    // create wrapper function217    var wrapper = Module.wrap(content);218 219    var invalidationKey = crypto220      .createHash('sha1')221      .update(content, 'utf8')222      .digest('hex');223 224    var buffer = this._cacheStore.get(filename, invalidationKey);225 226    var script = new vm.Script(wrapper, {227      filename: filename,228      lineOffset: 0,229      displayErrors: true,230      cachedData: buffer,231      produceCachedData: true,232    });233 234    if (script.cachedDataProduced) {235      this._cacheStore.set(filename, invalidationKey, script.cachedData);236    } else if (script.cachedDataRejected) {237      this._cacheStore.delete(filename);238    }239 240    var compiledWrapper = script.runInThisContext({241      filename: filename,242      lineOffset: 0,243      columnOffset: 0,244      displayErrors: true,245    });246 247    return compiledWrapper;248  }249}250 251//------------------------------------------------------------------------------252// utilities253//254// https://github.com/substack/node-mkdirp/blob/f2003bb/index.js#L55-L98255// https://github.com/zertosh/slash-escape/blob/e7ebb99/slash-escape.js256//------------------------------------------------------------------------------257 258function mkdirpSync(p_) {259  _mkdirpSync(path.resolve(p_), parseInt('0777', 8) & ~process.umask());260}261 262function _mkdirpSync(p, mode) {263  try {264    fs.mkdirSync(p, mode);265  } catch (err0) {266    if (err0.code === 'ENOENT') {267      _mkdirpSync(path.dirname(p));268      _mkdirpSync(p);269    } else {270      try {271        const stat = fs.statSync(p);272        if (!stat.isDirectory()) { throw err0; }273      } catch (err1) {274        throw err0;275      }276    }277  }278}279 280function slashEscape(str) {281  const ESCAPE_LOOKUP = {282    '\\': 'zB',283    ':': 'zC',284    '/': 'zS',285    '\x00': 'z0',286    'z': 'zZ',287  };288  return str.replace(/[\\:\/\x00z]/g, match => (ESCAPE_LOOKUP[match]));289}290 291function supportsCachedData() {292  const script = new vm.Script('""', {produceCachedData: true});293  // chakracore, as of v1.7.1.0, returns `false`.294  return script.cachedDataProduced === true;295}296 297function getCacheDir() {298  // Avoid cache ownership issues on POSIX systems.299  const dirname = typeof process.getuid === 'function'300    ? 'v8-compile-cache-' + process.getuid()301    : 'v8-compile-cache';302  const version = typeof process.versions.v8 === 'string'303    ? process.versions.v8304    : typeof process.versions.chakracore === 'string'305      ? 'chakracore-' + process.versions.chakracore306      : 'node-' + process.version;307  const cacheDir = path.join(os.tmpdir(), dirname, version);308  return cacheDir;309}310 311function getParentName() {312  // `module.parent.filename` is undefined or null when:313  //    * node -e 'require("v8-compile-cache")'314  //    * node -r 'v8-compile-cache'315  //    * Or, requiring from the REPL.316  const parentName = module.parent && typeof module.parent.filename === 'string'317    ? module.parent.filename318    : process.cwd();319  return parentName;320}321 322//------------------------------------------------------------------------------323// main324//------------------------------------------------------------------------------325 326if (!process.env.DISABLE_V8_COMPILE_CACHE && supportsCachedData()) {327  const cacheDir = getCacheDir();328  const prefix = getParentName();329  const blobStore = new FileSystemBlobStore(cacheDir, prefix);330 331  const nativeCompileCache = new NativeCompileCache();332  nativeCompileCache.setCacheStore(blobStore);333  nativeCompileCache.install();334 335  process.once('exit', code => {336    if (blobStore.isDirty()) {337      blobStore.save();338    }339    nativeCompileCache.uninstall();340  });341}342 343module.exports.__TEST__ = {344  FileSystemBlobStore,345  NativeCompileCache,346  mkdirpSync,347  slashEscape,348  supportsCachedData,349  getCacheDir,350  getParentName,351};352 
codekingpro/portable-devtools · Team Ai