Summary
performance.measure(name, ...) requires name to be a string in Node. Perry currently coerces name with the same String(value) behavior used by performance.mark(), so undefined, null, numbers, booleans, objects, arrays, and symbols can create measure entries instead of throwing.
Node behavior
Probe run with npx --yes node@25.9.0:
const { performance } = require("node:perf_hooks");
for (const value of [undefined, null, 0, true, {}, [], Symbol("s")]) {
try {
performance.measure(value);
console.log(String(value), "no throw");
} catch (err) {
console.log(String(value), err.name, err.code || "no-code", err.message);
}
}
Observed result: every non-string value throws TypeError [ERR_INVALID_ARG_TYPE] for the "name" argument. This differs from performance.mark(), which intentionally string-coerces non-symbol names.
Perry implementation evidence
crates/perry-runtime/src/perf_hooks.rs::js_perf_mark() explicitly checks symbols and otherwise calls coerce_to_string(name_val), matching Node mark-name coercion.
crates/perry-runtime/src/perf_hooks.rs::js_perf_measure() also starts with let name = coerce_to_string(name_val); and has no string-type validation or symbol-specific error path.
crates/perry-runtime/src/object/native_module_dispatch.rs routes ("perf_hooks", "measure") directly to js_perf_measure(arg(0), arg(1), arg(2)).
- Existing perf_hooks fixtures cover valid measure names and option endpoint validation, but not invalid
name types.
Expected fix
- Validate that
performance.measure() receives a string name before creating an entry.
- Throw
TypeError [ERR_INVALID_ARG_TYPE] for missing, null, primitive non-string, object, array, and symbol names.
- Preserve the existing
performance.mark() name coercion behavior.
- Add parity coverage for invalid
measure() name values and one control case showing mark(1).name === "1" still works.
Summary
performance.measure(name, ...)requiresnameto be a string in Node. Perry currently coercesnamewith the sameString(value)behavior used byperformance.mark(), soundefined,null, numbers, booleans, objects, arrays, and symbols can create measure entries instead of throwing.Node behavior
Probe run with
npx --yes node@25.9.0:Observed result: every non-string value throws
TypeError [ERR_INVALID_ARG_TYPE]for the"name"argument. This differs fromperformance.mark(), which intentionally string-coerces non-symbol names.Perry implementation evidence
crates/perry-runtime/src/perf_hooks.rs::js_perf_mark()explicitly checks symbols and otherwise callscoerce_to_string(name_val), matching Node mark-name coercion.crates/perry-runtime/src/perf_hooks.rs::js_perf_measure()also starts withlet name = coerce_to_string(name_val);and has no string-type validation or symbol-specific error path.crates/perry-runtime/src/object/native_module_dispatch.rsroutes("perf_hooks", "measure")directly tojs_perf_measure(arg(0), arg(1), arg(2)).nametypes.Expected fix
performance.measure()receives a stringnamebefore creating an entry.TypeError [ERR_INVALID_ARG_TYPE]for missing, null, primitive non-string, object, array, and symbol names.performance.mark()name coercion behavior.measure()name values and one control case showingmark(1).name === "1"still works.