perf: use jsonStringifyFast for faster JSON serialization (#25733)

## Summary

Apply the same optimization technique from PR #25717 (Response.json) to
other APIs that use JSON.stringify internally:

- **IPC message serialization** (`ipc.zig`) - used for inter-process
communication
- **console.log with %j format** (`ConsoleObject.zig`) - commonly used
for debugging
- **PostgreSQL JSON/JSONB types** (`PostgresRequest.zig`) - database
operations
- **MySQL JSON type** (`MySQLTypes.zig`) - database operations
- **Jest %j/%o format specifiers** (`jest.zig`) - test output formatting
- **Transpiler tsconfig/macros** (`JSTranspiler.zig`) - build
configuration

### Root Cause

When calling `JSONStringify(globalObject, value, 0)`, the space
parameter `0` becomes `jsNumber(0)`, which is NOT `undefined`. This
causes JSC's FastStringifier (SIMD-optimized) to bail out:

```cpp
// In WebKit's JSONObject.cpp FastStringifier::stringify()
if (!space.isUndefined()) {
    logOutcome("space"_s);
    return { };  // Bail out to slow path
}
```

Using `jsonStringifyFast` which passes `jsUndefined()` triggers the fast
path.

### Expected Performance Improvement

Based on PR #25717 results, these changes should provide ~3x speedup for
JSON serialization in the affected APIs.

## Test plan

- [x] Debug build compiles successfully
- [x] Basic functionality verified (IPC, console.log %j, Response.json)
- [x] Existing tests pass

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
robobun
2025-12-28 18:01:07 -08:00
committed by GitHub
parent 37fc8e99f7
commit d04b86d34f
6 changed files with 15 additions and 8 deletions

View File

@@ -1629,11 +1629,11 @@ pub const Formatter = struct {
},
.j => {
// JSON.stringify the value
// JSON.stringify the value using FastStringifier for SIMD optimization
var str = bun.String.empty;
defer str.deref();
try next_value.jsonStringify(global, 0, &str);
try next_value.jsonStringifyFast(global, &str);
this.addForNewLine(str.length());
writer.print("{f}", .{str});
},

View File

@@ -165,7 +165,8 @@ pub const Config = struct {
}
if (!kind.isStringLike()) {
try tsconfig.jsonStringify(globalThis, 0, &out);
// Use jsonStringifyFast for SIMD-optimized serialization
try tsconfig.jsonStringifyFast(globalThis, &out);
} else {
out = try tsconfig.toBunString(globalThis);
}
@@ -204,7 +205,8 @@ pub const Config = struct {
defer out.deref();
// TODO: write a converter between JSC types and Bun AST types
if (is_object) {
try macros.jsonStringify(globalThis, 0, &out);
// Use jsonStringifyFast for SIMD-optimized serialization
try macros.jsonStringifyFast(globalThis, &out);
} else {
out = try macros.toBunString(globalThis);
}

View File

@@ -229,7 +229,9 @@ const json = struct {
pub fn serialize(writer: *bun.io.StreamBuffer, global: *jsc.JSGlobalObject, value: JSValue, is_internal: IsInternal) !usize {
var out: bun.String = undefined;
try value.jsonStringify(global, 0, &out);
// Use jsonStringifyFast which passes undefined for the space parameter,
// triggering JSC's SIMD-optimized FastStringifier code path.
try value.jsonStringifyFast(global, &out);
defer out.deref();
if (out.tag == .Dead) return IPCSerializationError.SerializationFailed;

View File

@@ -430,7 +430,8 @@ pub fn formatLabel(globalThis: *JSGlobalObject, label: string, function_args: []
'j', 'o' => {
var str = bun.String.empty;
defer str.deref();
try current_arg.jsonStringify(globalThis, 0, &str);
// Use jsonStringifyFast for SIMD-optimized serialization
try current_arg.jsonStringifyFast(globalThis, &str);
const owned_slice = bun.handleOom(str.toOwnedSlice(allocator));
defer allocator.free(owned_slice);
bun.handleOom(list.appendSlice(owned_slice));

View File

@@ -486,7 +486,8 @@ pub const Value = union(enum) {
.MYSQL_TYPE_JSON => {
var str: bun.String = bun.String.empty;
try value.jsonStringify(globalObject, 0, &str);
// Use jsonStringifyFast for SIMD-optimized serialization
try value.jsonStringifyFast(globalObject, &str);
defer str.deref();
return Value{ .string = str.toUTF8(bun.default_allocator) };
},

View File

@@ -101,7 +101,8 @@ pub fn writeBind(
.jsonb, .json => {
var str = bun.String.empty;
defer str.deref();
try value.jsonStringify(globalObject, 0, &str);
// Use jsonStringifyFast for SIMD-optimized serialization
try value.jsonStringifyFast(globalObject, &str);
const slice = str.toUTF8WithoutRef(bun.default_allocator);
defer slice.deinit();
const l = try writer.length();