Link scr_bytes_dyn.c into libraries (#1693)

This commit is contained in:
Chris Tate
2026-10-21 12:40:07 -05:00
committed by GitHub
8 changed files with 70 additions and 60 deletions
@@ -33,6 +33,7 @@ export async function compilePackedLibrary(
assert: options.assert ?? false,
inspect: options.inspect ?? false,
dynInvoke: options.dynInvoke ?? false,
...(options.dynBuffer === true ? { dynBuffer: true } : {}),
...(options.dynTier === true ? { dynTier: true } : {}),
dc: false,
dynAsync: false,
@@ -321,6 +321,9 @@ export interface LibArchiveOptions {
threadInstances?: boolean;
/** IR-detected link gates (the compileC precedent, refusal-narrowed). */
dynInvoke?: boolean;
/** Buffer.prototype methods on checked-dynamic values: scr_bytes_dyn.c,
* with dynInvoke. */
dynBuffer?: boolean;
/** See CompileOptions.dynTier: the scr_js_* units. */
dynTier?: boolean;
regex?: boolean;
@@ -112,6 +112,7 @@ export async function compileLibArchive(opts: LibArchiveOptions): Promise<void>
...(opts.assert && opts.bigint ? ["scr_bigint_assert.c"] : []),
...(opts.emitter ? ["scr_events_emitter.c", "scr_dyn_handle.c"] : []),
...(opts.dynInvoke ? ["scr_dyn_invoke.c"] : []),
...(opts.dynInvoke && opts.dynBuffer ? ["scr_bytes_dyn.c"] : []),
...(opts.dynTier === true ? ["scr_js_value.c", "scr_js_object.c"] : []),
...(opts.zlib ? ["scr_zlib.c"] : []),
...(opts.copying ? ["scr_copying.c"] : []),
+2
View File
@@ -1706,6 +1706,7 @@ function libraryNativeFeatures(mod: IrModule, backend: "llvm"): EarlyLibraryNati
copying: features.copying,
textDecoderLegacy: features.legacyTextDecoder,
dynInvoke: features.dynInvoke,
...(features.dynBuffer ? { dynBuffer: true } : {}),
...(features.dynTier ? { dynTier: true } : {}),
...(mod.lib?.identity !== undefined ? { buildId: mod.lib.identity.buildId } : {}),
};
@@ -1800,6 +1801,7 @@ async function compileLibraryNative(
copying: features.copying,
textDecoderLegacy: features.textDecoderLegacy,
dynInvoke: features.dynInvoke,
...(features.dynBuffer === true ? { dynBuffer: true } : {}),
...(features.dynTier === true ? { dynTier: true } : {}),
};
if (packTarget !== null) await compilePackedLibrary(archiveOptions, packTarget);
@@ -63,6 +63,8 @@ interface EarlyLibraryCacheStamp {
export interface EarlyLibraryNativeFeatures {
backend: "llvm";
dynInvoke: boolean;
/** Buffer.prototype methods on checked-dynamic values (scr_bytes_dyn.c). */
dynBuffer?: boolean;
dynTier?: boolean;
regex: boolean;
assert: boolean;
@@ -15,6 +15,7 @@ export function withLibraryRuntimeFlavors(matrix) {
"scr_zlib.c",
"scr_copying.c",
"scr_dyn_invoke.c",
"scr_bytes_dyn.c",
"scr_js_value.c",
"scr_js_object.c",
]);
+60
View File
@@ -3957,3 +3957,63 @@ ScrStr *scr_bytes_join(const ScrBytes *b, const ScrStr *separator) {
scr_arr_release(values);
return out;
}
/* ── the checked-dynamic Buffer compare/equals validators ──────────────
* Node's argument ladders for buf.equals / buf.compare / Buffer.compare
* over dyn-boxed arguments (the invalid-input probes: string needles,
* '0' offsets, null/object range args). A well-typed dyn still computes
* the real answer — validation, not a constant fence. */
/* A bytes payload or the API's own ERR_INVALID_ARG_TYPE (borrowed). */
static ScrBytes *scr_bytes_chk_u8(const ScrDyn *d, const char *argname) {
if (!scr_dyn_bytes_is(d, SCR_BYTES_U8)) {
scr_dyn_arg_type_fail(argname, "an instance of Buffer or Uint8Array", d);
return NULL;
}
return d->v.bytes;
}
double scr_buffer_compare_chk(const ScrDyn *a, const ScrDyn *b) {
ScrBytes *b1 = scr_bytes_chk_u8(a, "buf1");
if (!b1) return 0;
ScrBytes *b2 = scr_bytes_chk_u8(b, "buf2");
if (!b2) return 0;
return scr_bytes_compare(b1, b2, 0, 0, 0, 0, 0);
}
bool scr_bytes_equals_chk(const ScrBytes *recv, const ScrDyn *other) {
ScrBytes *o = scr_bytes_chk_u8(other, "otherBuffer");
if (!o) return false;
return scr_bytes_equals(recv, o);
}
/* One offset slot: undefined takes the Node default, non-numbers throw
* ERR_INVALID_ARG_TYPE "of type number", numbers run validateOffset. */
static bool scr_bytes_chk_off(const ScrDyn *d, const char *name, double max,
double dflt, double *out) {
if (d->kind == SCR_DYN_UNDEF) {
*out = dflt;
return true;
}
if (d->kind != SCR_DYN_NUM) {
scr_dyn_arg_type_fail(name, "of type number", d);
return false;
}
*out = d->v.num;
return scr_bytes_validate_off(name, *out, max);
}
double scr_bytes_compare_chk(const ScrBytes *src, const ScrDyn *target,
const ScrDyn *ts, const ScrDyn *te,
const ScrDyn *ss, const ScrDyn *se) {
ScrBytes *t = scr_bytes_chk_u8(target, "target");
if (!t) return 0;
double tsv, tev, ssv, sev;
if (!scr_bytes_chk_off(ts, "targetStart", 9007199254740991.0, 0, &tsv)) return 0;
if (!scr_bytes_chk_off(te, "targetEnd", (double)t->len, (double)t->len, &tev)) return 0;
if (!scr_bytes_chk_off(ss, "sourceStart", 9007199254740991.0, 0, &ssv)) return 0;
if (!scr_bytes_chk_off(se, "sourceEnd", (double)src->len, (double)src->len, &sev)) return 0;
/* Every slot validated or defaulted above; nargs 4 revalidates the
* now-known-good numbers (a no-op) and keeps one comparison core. */
return scr_bytes_compare(src, t, 4, tsv, tev, ssv, sev);
}
-60
View File
@@ -1368,66 +1368,6 @@ ScrBytes *scr_buffer_from_dyn_ref_pooled(const ScrDyn *value, const ScrStr *enco
return scr_buffer_from_dyn_pooled(value, encoding);
}
/* ── the checked-dynamic Buffer compare/equals validators ──────────────
* Node's argument ladders for buf.equals / buf.compare / Buffer.compare
* over dyn-boxed arguments (the invalid-input probes: string needles,
* '0' offsets, null/object range args). A well-typed dyn still computes
* the real answer — validation, not a constant fence. */
/* A bytes payload or the API's own ERR_INVALID_ARG_TYPE (borrowed). */
static ScrBytes *scr_bytes_chk_u8(const ScrDyn *d, const char *argname) {
if (!scr_dyn_bytes_is(d, SCR_BYTES_U8)) {
scr_dyn_arg_type_fail(argname, "an instance of Buffer or Uint8Array", d);
return NULL;
}
return d->v.bytes;
}
double scr_buffer_compare_chk(const ScrDyn *a, const ScrDyn *b) {
ScrBytes *b1 = scr_bytes_chk_u8(a, "buf1");
if (!b1) return 0;
ScrBytes *b2 = scr_bytes_chk_u8(b, "buf2");
if (!b2) return 0;
return scr_bytes_compare(b1, b2, 0, 0, 0, 0, 0);
}
bool scr_bytes_equals_chk(const ScrBytes *recv, const ScrDyn *other) {
ScrBytes *o = scr_bytes_chk_u8(other, "otherBuffer");
if (!o) return false;
return scr_bytes_equals(recv, o);
}
/* One offset slot: undefined takes the Node default, non-numbers throw
* ERR_INVALID_ARG_TYPE "of type number", numbers run validateOffset. */
static bool scr_bytes_chk_off(const ScrDyn *d, const char *name, double max,
double dflt, double *out) {
if (d->kind == SCR_DYN_UNDEF) {
*out = dflt;
return true;
}
if (d->kind != SCR_DYN_NUM) {
scr_dyn_arg_type_fail(name, "of type number", d);
return false;
}
*out = d->v.num;
return scr_bytes_validate_off(name, *out, max);
}
double scr_bytes_compare_chk(const ScrBytes *src, const ScrDyn *target,
const ScrDyn *ts, const ScrDyn *te,
const ScrDyn *ss, const ScrDyn *se) {
ScrBytes *t = scr_bytes_chk_u8(target, "target");
if (!t) return 0;
double tsv, tev, ssv, sev;
if (!scr_bytes_chk_off(ts, "targetStart", 9007199254740991.0, 0, &tsv)) return 0;
if (!scr_bytes_chk_off(te, "targetEnd", (double)t->len, (double)t->len, &tev)) return 0;
if (!scr_bytes_chk_off(ss, "sourceStart", 9007199254740991.0, 0, &ssv)) return 0;
if (!scr_bytes_chk_off(se, "sourceEnd", (double)src->len, (double)src->len, &sev)) return 0;
/* Every slot validated or defaulted above; nargs 4 revalidates the
* now-known-good numbers (a no-op) and keeps one comparison core. */
return scr_bytes_compare(src, t, 4, tsv, tev, ssv, sev);
}
/* new Buffer(number, encoding) — the deprecated ctor's string arm with a
* non-string first argument: Node's exact ERR_INVALID_ARG_TYPE (the
* throwing path never fires DEP0005, so compiled silence matches). */