Skip to content

Commit 255f017

Browse files
joyeecheungBridgeAR
authored andcommitted
buffer: move initialization of buffer prototype into node.js
Instead of exposing it in `lib/internal/buffer.js` after deleting it from the binding and then do the initialization in `lib/buffer.js`, which results in an implicit dependency on the order in which these modules are loaded. PR-URL: #25292 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Ruben Bridgewater <[email protected]>
1 parent 42fc754 commit 255f017

File tree

5 files changed

+69
-47
lines changed

5 files changed

+69
-47
lines changed

lib/buffer.js

+32-8
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,22 @@ const {
3535
swap32: _swap32,
3636
swap64: _swap64,
3737
kMaxLength,
38-
kStringMaxLength
38+
kStringMaxLength,
39+
zeroFill: bindingZeroFill,
40+
41+
// Additional Buffer methods
42+
asciiSlice,
43+
base64Slice,
44+
latin1Slice,
45+
hexSlice,
46+
ucs2Slice,
47+
utf8Slice,
48+
asciiWrite,
49+
base64Write,
50+
latin1Write,
51+
hexWrite,
52+
ucs2Write,
53+
utf8Write
3954
} = internalBinding('buffer');
4055
const {
4156
getOwnNonIndexProperties,
@@ -75,10 +90,6 @@ const { validateString } = require('internal/validators');
7590

7691
const internalBuffer = require('internal/buffer');
7792

78-
const { setupBufferJS } = internalBuffer;
79-
80-
const bindingObj = {};
81-
8293
class FastBuffer extends Uint8Array {}
8394
FastBuffer.prototype.constructor = Buffer;
8495
internalBuffer.FastBuffer = FastBuffer;
@@ -89,6 +100,19 @@ for (const [name, method] of Object.entries(internalBuffer.readWrites)) {
89100
Buffer.prototype[name] = method;
90101
}
91102

103+
Buffer.prototype.asciiSlice = asciiSlice;
104+
Buffer.prototype.base64Slice = base64Slice;
105+
Buffer.prototype.latin1Slice = latin1Slice;
106+
Buffer.prototype.hexSlice = hexSlice;
107+
Buffer.prototype.ucs2Slice = ucs2Slice;
108+
Buffer.prototype.utf8Slice = utf8Slice;
109+
Buffer.prototype.asciiWrite = asciiWrite;
110+
Buffer.prototype.base64Write = base64Write;
111+
Buffer.prototype.latin1Write = latin1Write;
112+
Buffer.prototype.hexWrite = hexWrite;
113+
Buffer.prototype.ucs2Write = ucs2Write;
114+
Buffer.prototype.utf8Write = utf8Write;
115+
92116
const constants = Object.defineProperties({}, {
93117
MAX_LENGTH: {
94118
value: kMaxLength,
@@ -105,11 +129,11 @@ const constants = Object.defineProperties({}, {
105129
Buffer.poolSize = 8 * 1024;
106130
let poolSize, poolOffset, allocPool;
107131

108-
setupBufferJS(Buffer.prototype, bindingObj);
109-
132+
// A toggle used to access the zero fill setting of the array buffer allocator
133+
// in C++.
110134
// |zeroFill| can be undefined when running inside an isolate where we
111135
// do not own the ArrayBuffer allocator. Zero fill is always on in that case.
112-
const zeroFill = bindingObj.zeroFill || [0];
136+
const zeroFill = bindingZeroFill || [0];
113137

114138
function createUnsafeBuffer(size) {
115139
return new FastBuffer(createUnsafeArrayBuffer(size));

lib/internal/bootstrap/node.js

+8-4
Original file line numberDiff line numberDiff line change
@@ -653,11 +653,15 @@ function setupGlobalVariables() {
653653
}
654654
});
655655

656-
// This, as side effect, removes `setupBufferJS` from the buffer binding,
657-
// and exposes it on `internal/buffer`.
658-
NativeModule.require('internal/buffer');
656+
const { Buffer } = NativeModule.require('buffer');
657+
const bufferBinding = internalBinding('buffer');
659658

660-
global.Buffer = NativeModule.require('buffer').Buffer;
659+
// Only after this point can C++ use Buffer::New()
660+
bufferBinding.setBufferPrototype(Buffer.prototype);
661+
delete bufferBinding.setBufferPrototype;
662+
delete bufferBinding.zeroFill;
663+
664+
global.Buffer = Buffer;
661665
process.domain = null;
662666
process._exiting = false;
663667
}

lib/internal/buffer.js

-7
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,11 @@
11
'use strict';
22

3-
const binding = internalBinding('buffer');
43
const {
54
ERR_BUFFER_OUT_OF_BOUNDS,
65
ERR_INVALID_ARG_TYPE,
76
ERR_OUT_OF_RANGE
87
} = require('internal/errors').codes;
98
const { validateNumber } = require('internal/validators');
10-
const { setupBufferJS } = binding;
11-
12-
// Remove from the binding so that function is only available as exported here.
13-
// (That is, for internal use only.)
14-
delete binding.setupBufferJS;
159

1610
// Temporary buffers to convert numbers.
1711
const float32Array = new Float32Array(1);
@@ -779,7 +773,6 @@ function writeFloatBackwards(val, offset = 0) {
779773

780774
// FastBuffer wil be inserted here by lib/buffer.js
781775
module.exports = {
782-
setupBufferJS,
783776
// Container to export all read write functions.
784777
readWrites: {
785778
readUIntLE,

src/node_buffer.cc

+28-28
Original file line numberDiff line numberDiff line change
@@ -1055,38 +1055,12 @@ static void EncodeUtf8String(const FunctionCallbackInfo<Value>& args) {
10551055
}
10561056

10571057

1058-
// pass Buffer object to load prototype methods
1059-
void SetupBufferJS(const FunctionCallbackInfo<Value>& args) {
1058+
void SetBufferPrototype(const FunctionCallbackInfo<Value>& args) {
10601059
Environment* env = Environment::GetCurrent(args);
10611060

10621061
CHECK(args[0]->IsObject());
10631062
Local<Object> proto = args[0].As<Object>();
10641063
env->set_buffer_prototype_object(proto);
1065-
1066-
env->SetMethodNoSideEffect(proto, "asciiSlice", StringSlice<ASCII>);
1067-
env->SetMethodNoSideEffect(proto, "base64Slice", StringSlice<BASE64>);
1068-
env->SetMethodNoSideEffect(proto, "latin1Slice", StringSlice<LATIN1>);
1069-
env->SetMethodNoSideEffect(proto, "hexSlice", StringSlice<HEX>);
1070-
env->SetMethodNoSideEffect(proto, "ucs2Slice", StringSlice<UCS2>);
1071-
env->SetMethodNoSideEffect(proto, "utf8Slice", StringSlice<UTF8>);
1072-
1073-
env->SetMethod(proto, "asciiWrite", StringWrite<ASCII>);
1074-
env->SetMethod(proto, "base64Write", StringWrite<BASE64>);
1075-
env->SetMethod(proto, "latin1Write", StringWrite<LATIN1>);
1076-
env->SetMethod(proto, "hexWrite", StringWrite<HEX>);
1077-
env->SetMethod(proto, "ucs2Write", StringWrite<UCS2>);
1078-
env->SetMethod(proto, "utf8Write", StringWrite<UTF8>);
1079-
1080-
if (auto zero_fill_field = env->isolate_data()->zero_fill_field()) {
1081-
CHECK(args[1]->IsObject());
1082-
auto binding_object = args[1].As<Object>();
1083-
auto array_buffer = ArrayBuffer::New(env->isolate(),
1084-
zero_fill_field,
1085-
sizeof(*zero_fill_field));
1086-
auto name = FIXED_ONE_BYTE_STRING(env->isolate(), "zeroFill");
1087-
auto value = Uint32Array::New(array_buffer, 0, 1);
1088-
CHECK(binding_object->Set(env->context(), name, value).FromJust());
1089-
}
10901064
}
10911065

10921066

@@ -1096,7 +1070,7 @@ void Initialize(Local<Object> target,
10961070
void* priv) {
10971071
Environment* env = Environment::GetCurrent(context);
10981072

1099-
env->SetMethod(target, "setupBufferJS", SetupBufferJS);
1073+
env->SetMethod(target, "setBufferPrototype", SetBufferPrototype);
11001074
env->SetMethodNoSideEffect(target, "createFromString", CreateFromString);
11011075

11021076
env->SetMethodNoSideEffect(target, "byteLengthUtf8", ByteLengthUtf8);
@@ -1121,6 +1095,32 @@ void Initialize(Local<Object> target,
11211095
target->Set(env->context(),
11221096
FIXED_ONE_BYTE_STRING(env->isolate(), "kStringMaxLength"),
11231097
Integer::New(env->isolate(), String::kMaxLength)).FromJust();
1098+
1099+
env->SetMethodNoSideEffect(target, "asciiSlice", StringSlice<ASCII>);
1100+
env->SetMethodNoSideEffect(target, "base64Slice", StringSlice<BASE64>);
1101+
env->SetMethodNoSideEffect(target, "latin1Slice", StringSlice<LATIN1>);
1102+
env->SetMethodNoSideEffect(target, "hexSlice", StringSlice<HEX>);
1103+
env->SetMethodNoSideEffect(target, "ucs2Slice", StringSlice<UCS2>);
1104+
env->SetMethodNoSideEffect(target, "utf8Slice", StringSlice<UTF8>);
1105+
1106+
env->SetMethod(target, "asciiWrite", StringWrite<ASCII>);
1107+
env->SetMethod(target, "base64Write", StringWrite<BASE64>);
1108+
env->SetMethod(target, "latin1Write", StringWrite<LATIN1>);
1109+
env->SetMethod(target, "hexWrite", StringWrite<HEX>);
1110+
env->SetMethod(target, "ucs2Write", StringWrite<UCS2>);
1111+
env->SetMethod(target, "utf8Write", StringWrite<UTF8>);
1112+
1113+
// It can be a nullptr when running inside an isolate where we
1114+
// do not own the ArrayBuffer allocator.
1115+
if (uint32_t* zero_fill_field = env->isolate_data()->zero_fill_field()) {
1116+
Local<ArrayBuffer> array_buffer = ArrayBuffer::New(
1117+
env->isolate(), zero_fill_field, sizeof(*zero_fill_field));
1118+
CHECK(target
1119+
->Set(env->context(),
1120+
FIXED_ONE_BYTE_STRING(env->isolate(), "zeroFill"),
1121+
Uint32Array::New(array_buffer, 0, 1))
1122+
.FromJust());
1123+
}
11241124
}
11251125

11261126
} // anonymous namespace

src/node_internals.h

+1
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ v8::MaybeLocal<v8::Uint8Array> New(Environment* env,
233233
size_t byte_offset,
234234
size_t length) {
235235
v8::Local<v8::Uint8Array> ui = v8::Uint8Array::New(ab, byte_offset, length);
236+
CHECK(!env->buffer_prototype_object().IsEmpty());
236237
v8::Maybe<bool> mb =
237238
ui->SetPrototype(env->context(), env->buffer_prototype_object());
238239
if (mb.IsNothing())

0 commit comments

Comments
 (0)