Skip to content

Commit b61b4c9

Browse files
committed
src,lib: make JSTransferables based on private symbols
Serializes and transfers platform objects implemented as a JS class based on private symbols instead of V8 object internal slots. This avoids the need to alter the prototype chains and mixins to make the JS class to be transferable.
1 parent a8a6173 commit b61b4c9

23 files changed

+342
-232
lines changed

lib/internal/abort_controller.js

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,15 @@ const {
5858
const assert = require('internal/assert');
5959

6060
const {
61-
messaging_deserialize_symbol: kDeserialize,
62-
messaging_transfer_symbol: kTransfer,
63-
messaging_transfer_list_symbol: kTransferList,
64-
} = internalBinding('symbols');
61+
kDeserialize,
62+
kTransfer,
63+
kTransferList,
64+
} = require('internal/worker/js_transferable');
6565

6666
let _MessageChannel;
67-
let makeTransferable;
67+
let markTransferMode;
6868

69-
// Loading the MessageChannel and makeTransferable have to be done lazily
69+
// Loading the MessageChannel and markTransferable have to be done lazily
7070
// because otherwise we'll end up with a require cycle that ends up with
7171
// an incomplete initialization of abort_controller.
7272

@@ -75,10 +75,10 @@ function lazyMessageChannel() {
7575
return new _MessageChannel();
7676
}
7777

78-
function lazyMakeTransferable(obj) {
79-
makeTransferable ??=
80-
require('internal/worker/js_transferable').makeTransferable;
81-
return makeTransferable(obj);
78+
function lazyMarkTransferMode(obj, cloneable, transferable) {
79+
markTransferMode ??=
80+
require('internal/worker/js_transferable').markTransferMode;
81+
markTransferMode(obj, cloneable, transferable);
8282
}
8383

8484
const clearTimeoutRegistry = new SafeFinalizationRegistry(clearTimeout);
@@ -355,7 +355,10 @@ function createAbortSignal(init = kEmptyObject) {
355355
signal[kAborted] = aborted;
356356
signal[kReason] = reason;
357357
signal[kComposite] = composite;
358-
return transferable ? lazyMakeTransferable(signal) : signal;
358+
if (transferable) {
359+
lazyMarkTransferMode(signal, false, true);
360+
}
361+
return signal;
359362
}
360363

361364
function abortSignal(signal, reason) {
@@ -411,7 +414,8 @@ class AbortController {
411414
function transferableAbortSignal(signal) {
412415
if (signal?.[kAborted] === undefined)
413416
throw new ERR_INVALID_ARG_TYPE('signal', 'AbortSignal', signal);
414-
return lazyMakeTransferable(signal);
417+
lazyMarkTransferMode(signal, false, true);
418+
return signal;
415419
}
416420

417421
/**

lib/internal/blob.js

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ const {
3232
const { URL } = require('internal/url');
3333

3434
const {
35-
makeTransferable,
35+
markTransferMode,
3636
kClone,
3737
kDeserialize,
3838
} = require('internal/worker/js_transferable');
@@ -136,6 +136,8 @@ class Blob {
136136
* @constructs {Blob}
137137
*/
138138
constructor(sources = [], options) {
139+
markTransferMode(this, true, false);
140+
139141
if (sources === null ||
140142
typeof sources[SymbolIterator] !== 'function' ||
141143
typeof sources === 'string') {
@@ -167,9 +169,6 @@ class Blob {
167169
type = `${type}`;
168170
this[kType] = RegExpPrototypeExec(disallowedTypeCharacters, type) !== null ?
169171
'' : StringPrototypeToLowerCase(type);
170-
171-
// eslint-disable-next-line no-constructor-return
172-
return makeTransferable(this);
173172
}
174173

175174
[kInspect](depth, options) {
@@ -385,16 +384,19 @@ class Blob {
385384
}
386385

387386
function ClonedBlob() {
388-
return makeTransferable(ReflectConstruct(function() {}, [], Blob));
387+
return ReflectConstruct(function() {
388+
markTransferMode(this, true, false);
389+
}, [], Blob);
389390
}
390391
ClonedBlob.prototype[kDeserialize] = () => {};
391392

392393
function createBlob(handle, length, type = '') {
393-
return makeTransferable(ReflectConstruct(function() {
394+
return ReflectConstruct(function() {
395+
markTransferMode(this, true, false);
394396
this[kHandle] = handle;
395397
this[kType] = type;
396398
this[kLength] = length;
397-
}, [], Blob));
399+
}, [], Blob);
398400
}
399401

400402
ObjectDefineProperty(Blob.prototype, SymbolToStringTag, {

lib/internal/blocklist.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const {
2020
} = require('internal/socketaddress');
2121

2222
const {
23-
JSTransferable,
23+
markTransferMode,
2424
kClone,
2525
kDeserialize,
2626
} = require('internal/worker/js_transferable');
@@ -36,9 +36,9 @@ const {
3636

3737
const { validateInt32, validateString } = require('internal/validators');
3838

39-
class BlockList extends JSTransferable {
39+
class BlockList {
4040
constructor() {
41-
super();
41+
markTransferMode(this, true, false);
4242
this[kHandle] = new BlockListHandle();
4343
this[kHandle][owner_symbol] = this;
4444
}
@@ -148,9 +148,9 @@ class BlockList extends JSTransferable {
148148
}
149149
}
150150

151-
class InternalBlockList extends JSTransferable {
151+
class InternalBlockList {
152152
constructor(handle) {
153-
super();
153+
markTransferMode(this, true, false);
154154
this[kHandle] = handle;
155155
if (handle !== undefined)
156156
handle[owner_symbol] = this;

lib/internal/crypto/keys.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ const {
5757
} = require('internal/util/types');
5858

5959
const {
60-
makeTransferable,
60+
markTransferMode,
6161
kClone,
6262
kDeserialize,
6363
} = require('internal/worker/js_transferable');
@@ -706,24 +706,22 @@ ObjectDefineProperties(CryptoKey.prototype, {
706706
// All internal code must use new InternalCryptoKey to create
707707
// CryptoKey instances. The CryptoKey class is exposed to end
708708
// user code but is not permitted to be constructed directly.
709-
// Using makeTransferable also allows the CryptoKey to be
709+
// Using markTransferMode also allows the CryptoKey to be
710710
// cloned to Workers.
711711
class InternalCryptoKey {
712712
constructor(
713713
keyObject,
714714
algorithm,
715715
keyUsages,
716716
extractable) {
717+
markTransferMode(this, true, false);
717718
// Using symbol properties here currently instead of private
718719
// properties because (for now) the performance penalty of
719720
// private fields is still too high.
720721
this[kKeyObject] = keyObject;
721722
this[kAlgorithm] = algorithm;
722723
this[kExtractable] = extractable;
723724
this[kKeyUsages] = keyUsages;
724-
725-
// eslint-disable-next-line no-constructor-return
726-
return makeTransferable(this);
727725
}
728726

729727
[kClone]() {

lib/internal/crypto/x509.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ const {
4848
} = require('internal/errors');
4949

5050
const {
51-
JSTransferable,
51+
markTransferMode,
5252
kClone,
5353
kDeserialize,
5454
} = require('internal/worker/js_transferable');
@@ -94,16 +94,16 @@ function getFlags(options = kEmptyObject) {
9494
return flags;
9595
}
9696

97-
class InternalX509Certificate extends JSTransferable {
97+
class InternalX509Certificate {
9898
[kInternalState] = new SafeMap();
9999

100100
constructor(handle) {
101-
super();
101+
markTransferMode(this, true, false);
102102
this[kHandle] = handle;
103103
}
104104
}
105105

106-
class X509Certificate extends JSTransferable {
106+
class X509Certificate {
107107
[kInternalState] = new SafeMap();
108108

109109
constructor(buffer) {
@@ -115,7 +115,7 @@ class X509Certificate extends JSTransferable {
115115
['string', 'Buffer', 'TypedArray', 'DataView'],
116116
buffer);
117117
}
118-
super();
118+
markTransferMode(this, true, false);
119119
this[kHandle] = parseX509(buffer);
120120
}
121121

lib/internal/event_target.js

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,7 @@ const {
1010
ObjectDefineProperties,
1111
ObjectDefineProperty,
1212
ObjectGetOwnPropertyDescriptor,
13-
ObjectGetOwnPropertyDescriptors,
14-
ObjectSetPrototypeOf,
15-
ObjectValues,
1613
ReflectApply,
17-
SafeArrayIterator,
1814
SafeFinalizationRegistry,
1915
SafeMap,
2016
SafeWeakMap,
@@ -1114,30 +1110,9 @@ function defineEventHandler(emitter, name, event = name) {
11141110
});
11151111
}
11161112

1117-
const EventEmitterMixin = (Superclass) => {
1118-
class MixedEventEmitter extends Superclass {
1119-
constructor(...args) {
1120-
args = new SafeArrayIterator(args);
1121-
super(...args);
1122-
FunctionPrototypeCall(EventEmitter, this);
1123-
}
1124-
}
1125-
const protoProps = ObjectGetOwnPropertyDescriptors(EventEmitter.prototype);
1126-
delete protoProps.constructor;
1127-
const propertiesValues = ObjectValues(protoProps);
1128-
for (let i = 0; i < propertiesValues.length; i++) {
1129-
// We want to use null-prototype objects to not rely on globally mutable
1130-
// %Object.prototype%.
1131-
ObjectSetPrototypeOf(propertiesValues[i], null);
1132-
}
1133-
ObjectDefineProperties(MixedEventEmitter.prototype, protoProps);
1134-
return MixedEventEmitter;
1135-
};
1136-
11371113
module.exports = {
11381114
Event,
11391115
CustomEvent,
1140-
EventEmitterMixin,
11411116
EventTarget,
11421117
NodeEventTarget,
11431118
defineEventHandler,

lib/internal/fs/promises.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ const {
9090
lazyDOMException,
9191
promisify,
9292
} = require('internal/util');
93-
const { EventEmitterMixin } = require('internal/event_target');
93+
const EventEmitter = require('events');
9494
const { StringDecoder } = require('string_decoder');
9595
const { kFSWatchStart, watch } = require('internal/fs/watchers');
9696
const nonNativeWatcher = require('internal/fs/recursive_watch');
@@ -110,7 +110,7 @@ const kLocked = Symbol('kLocked');
110110
const { kUsePromises } = binding;
111111
const { Interface } = require('internal/readline/interface');
112112
const {
113-
JSTransferable, kDeserialize, kTransfer, kTransferList,
113+
kDeserialize, kTransfer, kTransferList, markTransferMode,
114114
} = require('internal/worker/js_transferable');
115115

116116
const getDirectoryEntriesPromise = promisify(getDirents);
@@ -130,12 +130,13 @@ function lazyFsStreams() {
130130
return fsStreams ??= require('internal/fs/streams');
131131
}
132132

133-
class FileHandle extends EventEmitterMixin(JSTransferable) {
133+
class FileHandle extends EventEmitter {
134134
/**
135135
* @param {InternalFSBinding.FileHandle | undefined} filehandle
136136
*/
137137
constructor(filehandle) {
138138
super();
139+
markTransferMode(this, false, true);
139140
this[kHandle] = filehandle;
140141
this[kFd] = filehandle ? filehandle.fd : -1;
141142

lib/internal/histogram.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ const kRecordable = Symbol('kRecordable');
4545
const {
4646
kClone,
4747
kDeserialize,
48-
makeTransferable,
48+
markTransferMode,
4949
} = require('internal/worker/js_transferable');
5050

5151
function isHistogram(object) {
@@ -319,21 +319,23 @@ class RecordableHistogram extends Histogram {
319319
}
320320

321321
function internalHistogram(handle) {
322-
return makeTransferable(ReflectConstruct(
322+
return ReflectConstruct(
323323
function() {
324+
markTransferMode(this, true, false);
324325
this[kHandle] = handle;
325326
this[kMap] = new SafeMap();
326-
}, [], Histogram));
327+
}, [], Histogram);
327328
}
328329
internalHistogram.prototype[kDeserialize] = () => {};
329330

330331
function internalRecordableHistogram(handle) {
331-
return makeTransferable(ReflectConstruct(
332+
return ReflectConstruct(
332333
function() {
334+
markTransferMode(this, true, false);
333335
this[kHandle] = handle;
334336
this[kMap] = new SafeMap();
335337
this[kRecordable] = true;
336-
}, [], RecordableHistogram));
338+
}, [], RecordableHistogram);
337339
}
338340
internalRecordableHistogram.prototype[kDeserialize] = () => {};
339341

lib/internal/perf/event_loop_delay.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ const {
3232
} = require('internal/util');
3333

3434
const {
35-
makeTransferable,
35+
markTransferMode,
3636
} = require('internal/worker/js_transferable');
3737

3838
const kEnabled = Symbol('kEnabled');
@@ -79,12 +79,13 @@ function monitorEventLoopDelay(options = kEmptyObject) {
7979
const { resolution = 10 } = options;
8080
validateInteger(resolution, 'options.resolution', 1);
8181

82-
return makeTransferable(ReflectConstruct(
82+
return ReflectConstruct(
8383
function() {
84+
markTransferMode(this, true, false);
8485
this[kEnabled] = false;
8586
this[kHandle] = createELDHistogram(resolution);
8687
this[kMap] = new SafeMap();
87-
}, [], ELDHistogram));
88+
}, [], ELDHistogram);
8889
}
8990

9091
module.exports = monitorEventLoopDelay;

lib/internal/socketaddress.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,21 +32,22 @@ const {
3232
const { inspect } = require('internal/util/inspect');
3333

3434
const {
35-
JSTransferable,
35+
markTransferMode,
3636
kClone,
3737
kDeserialize,
3838
} = require('internal/worker/js_transferable');
3939

4040
const kHandle = Symbol('kHandle');
4141
const kDetail = Symbol('kDetail');
4242

43-
class SocketAddress extends JSTransferable {
43+
class SocketAddress {
4444
static isSocketAddress(value) {
4545
return value?.[kHandle] !== undefined;
4646
}
4747

4848
constructor(options = kEmptyObject) {
49-
super();
49+
markTransferMode(this, true, false);
50+
5051
validateObject(options, 'options');
5152
let { family = 'ipv4' } = options;
5253
const {
@@ -139,9 +140,10 @@ class SocketAddress extends JSTransferable {
139140
}
140141
}
141142

142-
class InternalSocketAddress extends JSTransferable {
143+
class InternalSocketAddress {
143144
constructor(handle) {
144-
super();
145+
markTransferMode(this, true, false);
146+
145147
this[kHandle] = handle;
146148
this[kDetail] = this[kHandle]?.detail({
147149
address: undefined,

0 commit comments

Comments
 (0)