Skip to content

Commit 01ba74f

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 495feb5 commit 01ba74f

File tree

3 files changed

+54
-13
lines changed

3 files changed

+54
-13
lines changed

lib/buffer.js

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

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

@@ -684,6 +684,10 @@ function base64ByteLength(str, bytes) {
684684

685685
function hexSliceToHex(buf, start, end) {
686686
ensureUint8ArrayToHex();
687+
// Fall back to C++ when toHex is unavailable or the result would exceed
688+
// kStringMaxLength (so the correct ERR_STRING_TOO_LONG error is thrown).
689+
if (Uint8ArrayPrototypeToHex === null || (end - start) * 2 > kStringMaxLength)
690+
return hexSlice(buf, start, end);
687691
return Uint8ArrayPrototypeToHex(
688692
new Uint8Array(TypedArrayPrototypeGetBuffer(buf),
689693
TypedArrayPrototypeGetByteOffset(buf) + start,

src/node_buffer.cc

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

12021202
void Swap16(const FunctionCallbackInfo<Value>& args) {
1203-
Environment* env = Environment::GetCurrent(args);
1204-
THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
12051203
SPREAD_BUFFER_ARG(args[0], ts_obj);
12061204
CHECK(nbytes::SwapBytes16(ts_obj_data, ts_obj_length));
1207-
args.GetReturnValue().Set(args[0]);
12081205
}
12091206

12101207
void FastSwap16(Local<Value> receiver,
12111208
Local<Value> buffer_obj,
12121209
// NOLINTNEXTLINE(runtime/references)
12131210
FastApiCallbackOptions& options) {
1211+
TRACK_V8_FAST_API_CALL("buffer.swap16");
12141212
HandleScope scope(options.isolate);
12151213
ArrayBufferViewContents<char> buffer(buffer_obj);
12161214
CHECK(nbytes::SwapBytes16(const_cast<char*>(buffer.data()), buffer.length()));
@@ -1219,17 +1217,15 @@ void FastSwap16(Local<Value> receiver,
12191217
static CFunction fast_swap16(CFunction::Make(FastSwap16));
12201218

12211219
void Swap32(const FunctionCallbackInfo<Value>& args) {
1222-
Environment* env = Environment::GetCurrent(args);
1223-
THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
12241220
SPREAD_BUFFER_ARG(args[0], ts_obj);
12251221
CHECK(nbytes::SwapBytes32(ts_obj_data, ts_obj_length));
1226-
args.GetReturnValue().Set(args[0]);
12271222
}
12281223

12291224
void FastSwap32(Local<Value> receiver,
12301225
Local<Value> buffer_obj,
12311226
// NOLINTNEXTLINE(runtime/references)
12321227
FastApiCallbackOptions& options) {
1228+
TRACK_V8_FAST_API_CALL("buffer.swap32");
12331229
HandleScope scope(options.isolate);
12341230
ArrayBufferViewContents<char> buffer(buffer_obj);
12351231
CHECK(nbytes::SwapBytes32(const_cast<char*>(buffer.data()), buffer.length()));
@@ -1238,17 +1234,15 @@ void FastSwap32(Local<Value> receiver,
12381234
static CFunction fast_swap32(CFunction::Make(FastSwap32));
12391235

12401236
void Swap64(const FunctionCallbackInfo<Value>& args) {
1241-
Environment* env = Environment::GetCurrent(args);
1242-
THROW_AND_RETURN_UNLESS_BUFFER(env, args[0]);
12431237
SPREAD_BUFFER_ARG(args[0], ts_obj);
12441238
CHECK(nbytes::SwapBytes64(ts_obj_data, ts_obj_length));
1245-
args.GetReturnValue().Set(args[0]);
12461239
}
12471240

12481241
void FastSwap64(Local<Value> receiver,
12491242
Local<Value> buffer_obj,
12501243
// NOLINTNEXTLINE(runtime/references)
12511244
FastApiCallbackOptions& options) {
1245+
TRACK_V8_FAST_API_CALL("buffer.swap64");
12521246
HandleScope scope(options.isolate);
12531247
ArrayBufferViewContents<char> buffer(buffer_obj);
12541248
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)