Files
2020-03-02 14:53:23 +07:00

155 lines
4.5 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.fabricate = fabricate;
exports.fabricateTwice = fabricateTwice;
exports.shutdown = shutdown;
var _log = require("./log.js");
var _child_process = require("child_process");
const script = `
var vm = require('vm');
var module = require('module');
var stdin = Buffer.alloc(0);
process.stdin.on('data', function (data) {
stdin = Buffer.concat([ stdin, data ]);
if (stdin.length >= 4) {
var sizeOfSnap = stdin.readInt32LE(0);
if (stdin.length >= 4 + sizeOfSnap + 4) {
var sizeOfBody = stdin.readInt32LE(4 + sizeOfSnap);
if (stdin.length >= 4 + sizeOfSnap + 4 + sizeOfBody) {
var snap = stdin.toString('utf8', 4, 4 + sizeOfSnap);
var body = Buffer.alloc(sizeOfBody);
var startOfBody = 4 + sizeOfSnap + 4;
stdin.copy(body, 0, startOfBody, startOfBody + sizeOfBody);
stdin = Buffer.alloc(0);
var code = module.wrap(body);
var s = new vm.Script(code, {
filename: snap,
produceCachedData: true,
sourceless: true
});
if (!s.cachedDataProduced) {
console.error('Pkg: Cached data not produced.');
process.exit(2);
}
var h = Buffer.alloc(4);
var b = s.cachedData;
h.writeInt32LE(b.length, 0);
process.stdout.write(h);
process.stdout.write(b);
}
}
}
});
process.stdin.resume();
`;
const children = {};
function fabricate(bakes, fabricator, snap, body, cb) {
bakes = bakes.filter(function (bake) {
// list of bakes that don't influence the bytecode
const bake2 = bake.replace(/_/g, '-');
return !['--prof', '--v8-options', '--trace-opt', '--trace-deopt'].includes(bake2);
});
const cmd = fabricator.binaryPath;
const key = JSON.stringify([cmd, bakes]);
let child = children[key];
if (!child) {
const stderr = _log.log.debugMode ? process.stdout : 'ignore';
child = children[key] = (0, _child_process.spawn)(cmd, bakes.concat('-e', script), {
stdio: ['pipe', 'pipe', stderr],
env: {
PKG_EXECPATH: 'PKG_INVOKE_NODEJS'
}
});
}
function kill() {
delete children[key];
child.kill();
}
let stdout = Buffer.alloc(0);
function onError(error) {
removeListeners();
kill();
cb(new Error(`Failed to make bytecode ${fabricator.nodeRange}-${fabricator.arch} for file ${snap} error (${error.message})`));
}
function onClose(code) {
removeListeners();
kill();
if (code !== 0) {
return cb(new Error(`Failed to make bytecode ${fabricator.nodeRange}-${fabricator.arch} for file ${snap}`));
} else {
console.log(stdout.toString());
return cb(new Error(`${cmd} closed unexpectedly`));
}
}
function onData(data) {
stdout = Buffer.concat([stdout, data]);
if (stdout.length >= 4) {
const sizeOfBlob = stdout.readInt32LE(0);
if (stdout.length >= 4 + sizeOfBlob) {
const blob = Buffer.alloc(sizeOfBlob);
stdout.copy(blob, 0, 4, 4 + sizeOfBlob);
removeListeners();
return cb(undefined, blob);
}
}
}
child.on('error', onError);
child.on('close', onClose);
child.stdin.on('error', onError);
child.stdout.on('error', onError);
child.stdout.on('data', onData);
function removeListeners() {
child.removeListener('error', onError);
child.removeListener('close', onClose);
child.stdin.removeListener('error', onError);
child.stdout.removeListener('error', onError);
child.stdout.removeListener('data', onData);
}
const h = Buffer.alloc(4);
let b = Buffer.from(snap);
h.writeInt32LE(b.length, 0);
child.stdin.write(h);
child.stdin.write(b);
b = body;
h.writeInt32LE(b.length, 0);
child.stdin.write(h);
child.stdin.write(b);
}
function fabricateTwice(bakes, fabricator, snap, body, cb) {
fabricate(bakes, fabricator, snap, body, (error, buffer) => {
// node0 can not produce second time, even if first time produced fine,
// probably because of 'filename' cache. also, there are wierd cases
// when node4 can not compile as well, for example file 'lib/js-yaml/dumper.js'
// of package js-yaml@3.9.0 does not get bytecode second time on node4-win-x64
if (error) return fabricate(bakes, fabricator, snap, body, cb);
cb(undefined, buffer);
});
}
function shutdown() {
for (const key in children) {
const child = children[key];
delete children[key];
child.kill();
}
}