Skip to content

Commit 5457443

Browse files
legendecasjazelly
andauthored
lib,src: support DOMException ser-des
Added serialization and deserialization support for `DOMException`. Co-Authored-By: jazelly <[email protected]> PR-URL: #58649 Fixes: #49181 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Ethan Arrowood <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Jason Zhang <[email protected]>
1 parent 3a7f8ef commit 5457443

File tree

6 files changed

+137
-2
lines changed

6 files changed

+137
-2
lines changed

lib/eslint.config_partial.mjs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,4 +525,16 @@ export default [
525525
],
526526
},
527527
},
528+
{
529+
files: [
530+
'lib/internal/per_context/domexception.js',
531+
],
532+
languageOptions: {
533+
globals: {
534+
// Parameters passed to internal modules.
535+
privateSymbols: 'readonly',
536+
perIsolateSymbols: 'readonly',
537+
},
538+
},
539+
},
528540
];

lib/internal/per_context/domexception.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,18 @@ const {
1212
SymbolToStringTag,
1313
TypeError,
1414
} = primordials;
15+
const {
16+
transfer_mode_private_symbol,
17+
} = privateSymbols;
18+
const {
19+
messaging_clone_symbol,
20+
messaging_deserialize_symbol,
21+
} = perIsolateSymbols;
22+
23+
/**
24+
* Maps to BaseObject::TransferMode::kCloneable
25+
*/
26+
const kCloneable = 2;
1527

1628
function throwInvalidThisError(Base, type) {
1729
const err = new Base();
@@ -50,6 +62,7 @@ const disusedNamesSet = new SafeSet()
5062

5163
class DOMException {
5264
constructor(message = '', options = 'Error') {
65+
this[transfer_mode_private_symbol] = kCloneable;
5366
ErrorCaptureStackTrace(this);
5467

5568
if (options && typeof options === 'object') {
@@ -76,6 +89,28 @@ class DOMException {
7689
}
7790
}
7891

92+
[messaging_clone_symbol]() {
93+
// See serialization steps in https://webidl.spec.whatwg.org/#dom-domexception-domexception
94+
const internals = internalsMap.get(this);
95+
return {
96+
data: {
97+
message: internals.message,
98+
name: internals.name,
99+
stack: this.stack,
100+
},
101+
deserializeInfo: 'internal/worker/clone_dom_exception:DOMException',
102+
};
103+
}
104+
105+
[messaging_deserialize_symbol](data) {
106+
// See deserialization steps in https://webidl.spec.whatwg.org/#dom-domexception-domexception
107+
internalsMap.set(this, {
108+
message: data.message,
109+
name: data.name,
110+
});
111+
this.stack = data.stack;
112+
}
113+
79114
get name() {
80115
const internals = internalsMap.get(this);
81116
if (internals === undefined) {
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
'use strict';
2+
3+
// Delegate to the actual DOMException implementation.
4+
module.exports = {
5+
DOMException: internalBinding('messaging').DOMException,
6+
};

src/api/environment.cc

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -767,13 +767,13 @@ MaybeLocal<Object> InitializePrivateSymbols(Local<Context> context,
767767
Context::Scope context_scope(context);
768768

769769
Local<ObjectTemplate> private_symbols = ObjectTemplate::New(isolate);
770-
Local<Object> private_symbols_object;
771770
#define V(PropertyName, _) \
772771
private_symbols->Set(isolate, #PropertyName, isolate_data->PropertyName());
773772

774773
PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V)
775774
#undef V
776775

776+
Local<Object> private_symbols_object;
777777
if (!private_symbols->NewInstance(context).ToLocal(&private_symbols_object) ||
778778
private_symbols_object->SetPrototypeV2(context, Null(isolate))
779779
.IsNothing()) {
@@ -783,6 +783,32 @@ MaybeLocal<Object> InitializePrivateSymbols(Local<Context> context,
783783
return scope.Escape(private_symbols_object);
784784
}
785785

786+
MaybeLocal<Object> InitializePerIsolateSymbols(Local<Context> context,
787+
IsolateData* isolate_data) {
788+
CHECK(isolate_data);
789+
Isolate* isolate = context->GetIsolate();
790+
EscapableHandleScope scope(isolate);
791+
Context::Scope context_scope(context);
792+
793+
Local<ObjectTemplate> per_isolate_symbols = ObjectTemplate::New(isolate);
794+
#define V(PropertyName, _) \
795+
per_isolate_symbols->Set( \
796+
isolate, #PropertyName, isolate_data->PropertyName());
797+
798+
PER_ISOLATE_SYMBOL_PROPERTIES(V)
799+
#undef V
800+
801+
Local<Object> per_isolate_symbols_object;
802+
if (!per_isolate_symbols->NewInstance(context).ToLocal(
803+
&per_isolate_symbols_object) ||
804+
per_isolate_symbols_object->SetPrototypeV2(context, Null(isolate))
805+
.IsNothing()) {
806+
return MaybeLocal<Object>();
807+
}
808+
809+
return scope.Escape(per_isolate_symbols_object);
810+
}
811+
786812
Maybe<void> InitializePrimordials(Local<Context> context,
787813
IsolateData* isolate_data) {
788814
// Run per-context JS files.
@@ -812,6 +838,12 @@ Maybe<void> InitializePrimordials(Local<Context> context,
812838
return Nothing<void>();
813839
}
814840

841+
Local<Object> per_isolate_symbols;
842+
if (!InitializePerIsolateSymbols(context, isolate_data)
843+
.ToLocal(&per_isolate_symbols)) {
844+
return Nothing<void>();
845+
}
846+
815847
static const char* context_files[] = {"internal/per_context/primordials",
816848
"internal/per_context/domexception",
817849
"internal/per_context/messageport",
@@ -827,7 +859,8 @@ Maybe<void> InitializePrimordials(Local<Context> context,
827859
builtin_loader.SetEagerCompile();
828860

829861
for (const char** module = context_files; *module != nullptr; module++) {
830-
Local<Value> arguments[] = {exports, primordials, private_symbols};
862+
Local<Value> arguments[] = {
863+
exports, primordials, private_symbols, per_isolate_symbols};
831864

832865
if (builtin_loader
833866
.CompileAndCall(

src/node_builtins.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,7 @@ MaybeLocal<Function> BuiltinLoader::LookupAndCompile(Local<Context> context,
416416
FIXED_ONE_BYTE_STRING(isolate, "exports"),
417417
FIXED_ONE_BYTE_STRING(isolate, "primordials"),
418418
FIXED_ONE_BYTE_STRING(isolate, "privateSymbols"),
419+
FIXED_ONE_BYTE_STRING(isolate, "perIsolateSymbols"),
419420
};
420421
} else if (strncmp(id, "internal/main/", strlen("internal/main/")) == 0 ||
421422
strncmp(id,
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
'use strict';
2+
3+
require('../common');
4+
const assert = require('assert');
5+
6+
function assertDOMException(actual, expected) {
7+
assert.strictEqual(actual instanceof DOMException, true);
8+
assert.strictEqual(actual.message, expected.message);
9+
assert.strictEqual(actual.name, expected.name);
10+
assert.strictEqual(actual.code, expected.code);
11+
assert.strictEqual(actual.stack, expected.stack);
12+
}
13+
14+
{
15+
// Clone basic DOMException
16+
const e = new DOMException('test');
17+
const clone = structuredClone(e);
18+
const clone2 = structuredClone(clone);
19+
assertDOMException(clone, e);
20+
assertDOMException(clone2, e);
21+
}
22+
23+
{
24+
// Clone a DOMException with a name
25+
const e = new DOMException('test', 'DataCloneError');
26+
const clone = structuredClone(e);
27+
const clone2 = structuredClone(clone);
28+
assertDOMException(clone, e);
29+
assertDOMException(clone2, e);
30+
}
31+
32+
{
33+
// Clone an arbitrary object with a DOMException prototype
34+
const obj = {};
35+
Object.setPrototypeOf(obj, DOMException.prototype);
36+
const clone = structuredClone(obj);
37+
assert.strictEqual(clone instanceof DOMException, false);
38+
}
39+
40+
{
41+
// Transfer a DOMException. DOMExceptions are not transferable.
42+
const e = new DOMException('test');
43+
assert.throws(() => {
44+
structuredClone(e, { transfer: [e] });
45+
}, {
46+
name: 'DataCloneError',
47+
});
48+
}

0 commit comments

Comments
 (0)