Skip to content

Commit 9c66a0a

Browse files
committed
buffer: address PR feedback
- Guard ensureUint8ArrayToHex against --no-js-base-64 flag by falling back to C++ hexSlice when toHex is unavailable - Remove THROW_AND_RETURN_UNLESS_BUFFER and return value from slow Swap16/32/64 to match fast path conventions (JS validates) - Add TRACK_V8_FAST_API_CALL to FastSwap16/32/64 - Add test/parallel/test-buffer-swap-fast.js for fast API verification
1 parent 1ec8a92 commit 9c66a0a

3 files changed

Lines changed: 54 additions & 13 deletions

File tree

lib/buffer.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,13 @@ const {
5656
uncurryThis,
5757
} = primordials;
5858

59-
// V8 shipping feature (toHex) is installed by
60-
// InitializeExperimentalGlobal(), which is skipped during snapshot creation
61-
// TODO: Remove this once V8 shipping feature (toHex) is available.
59+
// Lazily initialized: toHex is installed by InitializeExperimentalGlobal()
60+
// (skipped during snapshot creation) and may be disabled with --no-js-base-64.
6261
let Uint8ArrayPrototypeToHex;
6362
function ensureUint8ArrayToHex() {
6463
if (Uint8ArrayPrototypeToHex === undefined) {
65-
Uint8ArrayPrototypeToHex = uncurryThis(Uint8ArrayPrototype.toHex);
64+
Uint8ArrayPrototypeToHex = Uint8ArrayPrototype.toHex ?
65+
uncurryThis(Uint8ArrayPrototype.toHex) : null;
6666
}
6767
}
6868

@@ -715,6 +715,10 @@ function base64ByteLength(str, bytes) {
715715

716716
function hexSliceToHex(buf, start, end) {
717717
ensureUint8ArrayToHex();
718+
// Fall back to C++ when toHex is unavailable or the result would exceed
719+
// kStringMaxLength (so the correct ERR_STRING_TOO_LONG error is thrown).
720+
if (Uint8ArrayPrototypeToHex === null || (end - start) * 2 > kStringMaxLength)
721+
return hexSlice(buf, start, end);
718722
return Uint8ArrayPrototypeToHex(
719723
new Uint8Array(TypedArrayPrototypeGetBuffer(buf),
720724
TypedArrayPrototypeGetByteOffset(buf) + start,

src/node_buffer.cc

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,17 +1196,15 @@ int32_t FastIndexOfNumber(Local<Value>,
11961196
static CFunction fast_index_of_number(CFunction::Make(FastIndexOfNumber));
11971197

11981198
void Swap16(const FunctionCallbackInfo<Value>& args) {
1199-
Environment* env = Environment::GetCurrent(args);
1200-
THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
12011199
SPREAD_BUFFER_ARG(args[0], ts_obj);
12021200
CHECK(nbytes::SwapBytes16(ts_obj_data, ts_obj_length));
1203-
args.GetReturnValue().Set(args[0]);
12041201
}
12051202

12061203
void FastSwap16(Local<Value> receiver,
12071204
Local<Value> buffer_obj,
12081205
// NOLINTNEXTLINE(runtime/references)
12091206
FastApiCallbackOptions& options) {
1207+
TRACK_V8_FAST_API_CALL("buffer.swap16");
12101208
HandleScope scope(options.isolate);
12111209
ArrayBufferViewContents<char> buffer(buffer_obj);
12121210
CHECK(nbytes::SwapBytes16(const_cast<char*>(buffer.data()), buffer.length()));
@@ -1215,17 +1213,15 @@ void FastSwap16(Local<Value> receiver,
12151213
static CFunction fast_swap16(CFunction::Make(FastSwap16));
12161214

12171215
void Swap32(const FunctionCallbackInfo<Value>& args) {
1218-
Environment* env = Environment::GetCurrent(args);
1219-
THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
12201216
SPREAD_BUFFER_ARG(args[0], ts_obj);
12211217
CHECK(nbytes::SwapBytes32(ts_obj_data, ts_obj_length));
1222-
args.GetReturnValue().Set(args[0]);
12231218
}
12241219

12251220
void FastSwap32(Local<Value> receiver,
12261221
Local<Value> buffer_obj,
12271222
// NOLINTNEXTLINE(runtime/references)
12281223
FastApiCallbackOptions& options) {
1224+
TRACK_V8_FAST_API_CALL("buffer.swap32");
12291225
HandleScope scope(options.isolate);
12301226
ArrayBufferViewContents<char> buffer(buffer_obj);
12311227
CHECK(nbytes::SwapBytes32(const_cast<char*>(buffer.data()), buffer.length()));
@@ -1234,17 +1230,15 @@ void FastSwap32(Local<Value> receiver,
12341230
static CFunction fast_swap32(CFunction::Make(FastSwap32));
12351231

12361232
void Swap64(const FunctionCallbackInfo<Value>& args) {
1237-
Environment* env = Environment::GetCurrent(args);
1238-
THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
12391233
SPREAD_BUFFER_ARG(args[0], ts_obj);
12401234
CHECK(nbytes::SwapBytes64(ts_obj_data, ts_obj_length));
1241-
args.GetReturnValue().Set(args[0]);
12421235
}
12431236

12441237
void FastSwap64(Local<Value> receiver,
12451238
Local<Value> buffer_obj,
12461239
// NOLINTNEXTLINE(runtime/references)
12471240
FastApiCallbackOptions& options) {
1241+
TRACK_V8_FAST_API_CALL("buffer.swap64");
12481242
HandleScope scope(options.isolate);
12491243
ArrayBufferViewContents<char> buffer(buffer_obj);
12501244
CHECK(nbytes::SwapBytes64(const_cast<char*>(buffer.data()), buffer.length()));
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Flags: --expose-internals --no-warnings --allow-natives-syntax
2+
'use strict';
3+
4+
const common = require('../common');
5+
const assert = require('assert');
6+
7+
function testFastSwap16() {
8+
const buf = Buffer.alloc(256);
9+
buf.swap16();
10+
}
11+
12+
function testFastSwap32() {
13+
const buf = Buffer.alloc(256);
14+
buf.swap32();
15+
}
16+
17+
function testFastSwap64() {
18+
const buf = Buffer.alloc(256);
19+
buf.swap64();
20+
}
21+
22+
eval('%PrepareFunctionForOptimization(Buffer.prototype.swap16)');
23+
testFastSwap16();
24+
eval('%OptimizeFunctionOnNextCall(Buffer.prototype.swap16)');
25+
testFastSwap16();
26+
27+
eval('%PrepareFunctionForOptimization(Buffer.prototype.swap32)');
28+
testFastSwap32();
29+
eval('%OptimizeFunctionOnNextCall(Buffer.prototype.swap32)');
30+
testFastSwap32();
31+
32+
eval('%PrepareFunctionForOptimization(Buffer.prototype.swap64)');
33+
testFastSwap64();
34+
eval('%OptimizeFunctionOnNextCall(Buffer.prototype.swap64)');
35+
testFastSwap64();
36+
37+
if (common.isDebug) {
38+
const { internalBinding } = require('internal/test/binding');
39+
const { getV8FastApiCallCount } = internalBinding('debug');
40+
assert.strictEqual(getV8FastApiCallCount('buffer.swap16'), 1);
41+
assert.strictEqual(getV8FastApiCallCount('buffer.swap32'), 1);
42+
assert.strictEqual(getV8FastApiCallCount('buffer.swap64'), 1);
43+
}

0 commit comments

Comments
 (0)