Files
scriptc/packages/runtime-pack-common/scripts/share-artifacts.mjs
T
Chris Tate c4105d23a7 Stop building and shipping runtime import bitcode
Program builds have not imported runtime bitcode since fc38e6279, but
every runtime pack still built and listed it: release units through the
helper's prune-import, speed units as runtime-unit's second output. That
is 24 MB of the linux-x64-gnu pack.

Building that bitcode also cost scr_glibc_math its runtime profile: the
pruned import module keeps the floor, ceil and trunc ifuncs without their
resolvers and fails verification, and runtime-unit built it before the
object, so the whole speed unit fell back to a direct compile. The build
printed only the first line of the helper's stderr, a CPU feature
warning.

- runtime-unit's --bitcode is optional (feature
  "runtime-unit-optional-bitcode"), and pack builds no longer pass it or
  run prune-import. Speed objects come out as before, scr_glibc_math's now
  with the runtime profile.
- Pack manifests list no bitcode, and the compiler no longer validates the
  field. verify and share-artifacts check objects only.
- A unit the helper can't emit reports the helper's JSON diagnostic.
- The zero-cost gate names changed runtime functions from the objects'
  disassembly instead of the bitcode.
2026-10-29 17:58:37 -05:00

45 lines
1.7 KiB
JavaScript

import { readdir, rm, rmdir } from "node:fs/promises";
import { join } from "node:path";
/** Points the artifacts of one runtime unit that hold the same bytes at one
* file and deletes the copies. Variants whose defines a unit does not read,
* and flavors that compile a unit the same way, produce identical objects.
* Each link selects one flavor and one variant of each unit, so
* no link names a shared file twice. `root` is the directory artifact paths
* are relative to; flavors keep the order they were built in, so the first
* flavor's path holds the shared file. */
export async function shareIdenticalArtifacts(flavors, root) {
const firstPaths = new Map();
for (const flavor of Object.values(flavors)) {
for (const unit of flavor.runtime_units) {
let paths = firstPaths.get(unit.source);
if (paths === undefined) {
paths = new Map();
firstPaths.set(unit.source, paths);
}
for (const variant of unit.variants) {
const first = paths.get(variant.sha256);
if (first === undefined) {
paths.set(variant.sha256, variant.path);
} else if (first !== variant.path) {
await rm(join(root, variant.path));
variant.path = first;
}
}
}
}
await removeEmptyDirectories(join(root, "artifacts"));
}
async function removeEmptyDirectories(directory) {
const entries = await readdir(directory, { withFileTypes: true });
let remaining = entries.length;
for (const entry of entries) {
if (entry.isDirectory() && (await removeEmptyDirectories(join(directory, entry.name))))
remaining--;
}
if (remaining > 0) return false;
await rmdir(directory);
return true;
}