perf(buffer): optimize Buffer.from(array) by using setFromArrayLike directly (#26135)

## Summary

Optimizes `Buffer.from(array)` by bypassing `JSC::construct()` overhead
(~30ns) and leveraging JSC's internal array optimizations.

## Changes

- For JSArray inputs, directly use `setFromArrayLike()` which internally
detects array indexing types (Int32Shape/DoubleShape) and uses bulk copy
operations (`copyFromInt32ShapeArray`/`copyFromDoubleShapeArray`)
- Array-like objects and iterables continue to use the existing slow
path
- Added mitata benchmark for measuring performance

## Benchmark Results

| Test | Before | After | Improvement |
|------|--------|-------|-------------|
| Buffer.from(int32[8]) | ~85ns | ~43ns | ~50% faster |
| Buffer.from(int32[64]) | ~207ns | ~120ns | ~42% faster |
| Buffer.from(int32[1024]) | ~1.85μs | ~1.32μs | ~29% faster |
| Buffer.from(double[8]) | ~86ns | ~50ns | ~42% faster |
| Buffer.from(double[64]) | ~212ns | ~151ns | ~29% faster |

Bun is now faster than Node.js for these operations.

## Test

All 449 buffer tests pass.
This commit is contained in:
SUZUKI Sosuke
2026-01-16 05:10:47 +09:00
committed by GitHub
parent b268004715
commit f01467d3dc
2 changed files with 68 additions and 1 deletions

View File

@@ -0,0 +1,38 @@
// @runtime bun,node
import { Buffer } from "node:buffer";
import { bench, group, run } from "../runner.mjs";
// Small arrays (common case)
const int32Array8 = [1, 2, 3, 4, 5, 6, 7, 8];
const doubleArray8 = [1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5];
// Medium arrays
const int32Array64 = Array.from({ length: 64 }, (_, i) => i % 256);
const doubleArray64 = Array.from({ length: 64 }, (_, i) => i + 0.5);
// Large arrays
const int32Array1024 = Array.from({ length: 1024 }, (_, i) => i % 256);
// Array-like objects (fallback path)
const arrayLike8 = { 0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, length: 8 };
// Empty array
const emptyArray = [];
group("Buffer.from(array) - Int32 arrays", () => {
bench("Buffer.from(int32[8])", () => Buffer.from(int32Array8));
bench("Buffer.from(int32[64])", () => Buffer.from(int32Array64));
bench("Buffer.from(int32[1024])", () => Buffer.from(int32Array1024));
});
group("Buffer.from(array) - Double arrays", () => {
bench("Buffer.from(double[8])", () => Buffer.from(doubleArray8));
bench("Buffer.from(double[64])", () => Buffer.from(doubleArray64));
});
group("Buffer.from(array) - Edge cases", () => {
bench("Buffer.from([])", () => Buffer.from(emptyArray));
bench("Buffer.from(arrayLike[8])", () => Buffer.from(arrayLike8));
});
await run();