Skip to content

Commit 8fb8c16

Browse files
committed
BridgeJS: Reuse container codecs by element type
1 parent 1cabe6c commit 8fb8c16

19 files changed

Lines changed: 502 additions & 57 deletions

Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -216,12 +216,23 @@ enum ContainerCodecJS {
216216
private static let primitiveCodecIntrinsicName = "containerPrimitiveCodecs"
217217

218218
/// The single description of each container shape's stack ABI.
219+
///
220+
/// The combinators memoize per element codec object. Statically known
221+
/// compositions are hoisted into module-scope `const`s and so instantiate a
222+
/// combinator only once, but a generic call site resolves its element codec
223+
/// from a runtime type ID and cannot be hoisted; memoizing keeps those call
224+
/// sites from allocating a fresh codec on every call.
219225
static func combinatorDeclarations() -> [String] {
220226
let i32 = JSGlueVariableScope.reservedI32Stack
221227
let stringCodec = JSGlueVariableScope.reservedStringCodec
222228
return [
229+
"const \(arrayCodec)Cache = new WeakMap();",
223230
"function \(arrayCodec)(elementCodec) {",
224-
" return {",
231+
" let codec = \(arrayCodec)Cache.get(elementCodec);",
232+
" if (codec !== undefined) {",
233+
" return codec;",
234+
" }",
235+
" codec = {",
225236
" lower(value) {",
226237
" for (let i = 0; i < value.length; i++) {",
227238
" elementCodec.lower(value[i]);",
@@ -240,11 +251,22 @@ enum ContainerCodecJS {
240251
" return result;",
241252
" },",
242253
" };",
254+
" \(arrayCodec)Cache.set(elementCodec, codec);",
255+
" return codec;",
243256
"}",
244257
// `isUndefinedOr` selects the `JSUndefinedOr` flavor: `null` is then a
245258
// present value and absence surfaces as `undefined` instead of `null`.
259+
// The two flavors are cached separately because they differ in
260+
// behavior, not just in the element codec.
261+
"const \(optionalCodec)Cache = new WeakMap();",
262+
"const \(optionalCodec)UndefinedOrCache = new WeakMap();",
246263
"function \(optionalCodec)(elementCodec, isUndefinedOr = false) {",
247-
" return {",
264+
" const cache = isUndefinedOr ? \(optionalCodec)UndefinedOrCache : \(optionalCodec)Cache;",
265+
" let codec = cache.get(elementCodec);",
266+
" if (codec !== undefined) {",
267+
" return codec;",
268+
" }",
269+
" codec = {",
248270
" lower(value) {",
249271
" const isSome = isUndefinedOr ? value !== undefined : value != null;",
250272
" if (isSome) {",
@@ -261,9 +283,16 @@ enum ContainerCodecJS {
261283
" return elementCodec.lift();",
262284
" },",
263285
" };",
286+
" cache.set(elementCodec, codec);",
287+
" return codec;",
264288
"}",
289+
"const \(dictCodec)Cache = new WeakMap();",
265290
"function \(dictCodec)(valueCodec) {",
266-
" return {",
291+
" let codec = \(dictCodec)Cache.get(valueCodec);",
292+
" if (codec !== undefined) {",
293+
" return codec;",
294+
" }",
295+
" codec = {",
267296
" lower(value) {",
268297
" const keys = Object.keys(value);",
269298
" for (let i = 0; i < keys.length; i++) {",
@@ -283,6 +312,8 @@ enum ContainerCodecJS {
283312
" return result;",
284313
" },",
285314
" };",
315+
" \(dictCodec)Cache.set(valueCodec, codec);",
316+
" return codec;",
286317
"}",
287318
]
288319
}

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Alias.js

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,13 @@ export async function createInstantiator(options, swift) {
3737

3838
let _exports = null;
3939
let bjs = null;
40+
const __bjs_arrayCodecCache = new WeakMap();
4041
function __bjs_arrayCodec(elementCodec) {
41-
return {
42+
let codec = __bjs_arrayCodecCache.get(elementCodec);
43+
if (codec !== undefined) {
44+
return codec;
45+
}
46+
codec = {
4247
lower(value) {
4348
for (let i = 0; i < value.length; i++) {
4449
elementCodec.lower(value[i]);
@@ -57,9 +62,18 @@ export async function createInstantiator(options, swift) {
5762
return result;
5863
},
5964
};
65+
__bjs_arrayCodecCache.set(elementCodec, codec);
66+
return codec;
6067
}
68+
const __bjs_optionalCodecCache = new WeakMap();
69+
const __bjs_optionalCodecUndefinedOrCache = new WeakMap();
6170
function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) {
62-
return {
71+
const cache = isUndefinedOr ? __bjs_optionalCodecUndefinedOrCache : __bjs_optionalCodecCache;
72+
let codec = cache.get(elementCodec);
73+
if (codec !== undefined) {
74+
return codec;
75+
}
76+
codec = {
6377
lower(value) {
6478
const isSome = isUndefinedOr ? value !== undefined : value != null;
6579
if (isSome) {
@@ -76,9 +90,16 @@ export async function createInstantiator(options, swift) {
7690
return elementCodec.lift();
7791
},
7892
};
93+
cache.set(elementCodec, codec);
94+
return codec;
7995
}
96+
const __bjs_dictCodecCache = new WeakMap();
8097
function __bjs_dictCodec(valueCodec) {
81-
return {
98+
let codec = __bjs_dictCodecCache.get(valueCodec);
99+
if (codec !== undefined) {
100+
return codec;
101+
}
102+
codec = {
82103
lower(value) {
83104
const keys = Object.keys(value);
84105
for (let i = 0; i < keys.length; i++) {
@@ -98,6 +119,8 @@ export async function createInstantiator(options, swift) {
98119
return result;
99120
},
100121
};
122+
__bjs_dictCodecCache.set(valueCodec, codec);
123+
return codec;
101124
}
102125

103126
const __bjs_stringCodec = {

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,13 @@ export async function createInstantiator(options, swift) {
4444

4545
let _exports = null;
4646
let bjs = null;
47+
const __bjs_arrayCodecCache = new WeakMap();
4748
function __bjs_arrayCodec(elementCodec) {
48-
return {
49+
let codec = __bjs_arrayCodecCache.get(elementCodec);
50+
if (codec !== undefined) {
51+
return codec;
52+
}
53+
codec = {
4954
lower(value) {
5055
for (let i = 0; i < value.length; i++) {
5156
elementCodec.lower(value[i]);
@@ -64,9 +69,18 @@ export async function createInstantiator(options, swift) {
6469
return result;
6570
},
6671
};
72+
__bjs_arrayCodecCache.set(elementCodec, codec);
73+
return codec;
6774
}
75+
const __bjs_optionalCodecCache = new WeakMap();
76+
const __bjs_optionalCodecUndefinedOrCache = new WeakMap();
6877
function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) {
69-
return {
78+
const cache = isUndefinedOr ? __bjs_optionalCodecUndefinedOrCache : __bjs_optionalCodecCache;
79+
let codec = cache.get(elementCodec);
80+
if (codec !== undefined) {
81+
return codec;
82+
}
83+
codec = {
7084
lower(value) {
7185
const isSome = isUndefinedOr ? value !== undefined : value != null;
7286
if (isSome) {
@@ -83,9 +97,16 @@ export async function createInstantiator(options, swift) {
8397
return elementCodec.lift();
8498
},
8599
};
100+
cache.set(elementCodec, codec);
101+
return codec;
86102
}
103+
const __bjs_dictCodecCache = new WeakMap();
87104
function __bjs_dictCodec(valueCodec) {
88-
return {
105+
let codec = __bjs_dictCodecCache.get(valueCodec);
106+
if (codec !== undefined) {
107+
return codec;
108+
}
109+
codec = {
89110
lower(value) {
90111
const keys = Object.keys(value);
91112
for (let i = 0; i < keys.length; i++) {
@@ -105,6 +126,8 @@ export async function createInstantiator(options, swift) {
105126
return result;
106127
},
107128
};
129+
__bjs_dictCodecCache.set(valueCodec, codec);
130+
return codec;
108131
}
109132

110133
const __bjs_stringCodec = {

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,13 @@ export async function createInstantiator(options, swift) {
4141

4242
let _exports = null;
4343
let bjs = null;
44+
const __bjs_arrayCodecCache = new WeakMap();
4445
function __bjs_arrayCodec(elementCodec) {
45-
return {
46+
let codec = __bjs_arrayCodecCache.get(elementCodec);
47+
if (codec !== undefined) {
48+
return codec;
49+
}
50+
codec = {
4651
lower(value) {
4752
for (let i = 0; i < value.length; i++) {
4853
elementCodec.lower(value[i]);
@@ -61,9 +66,18 @@ export async function createInstantiator(options, swift) {
6166
return result;
6267
},
6368
};
69+
__bjs_arrayCodecCache.set(elementCodec, codec);
70+
return codec;
6471
}
72+
const __bjs_optionalCodecCache = new WeakMap();
73+
const __bjs_optionalCodecUndefinedOrCache = new WeakMap();
6574
function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) {
66-
return {
75+
const cache = isUndefinedOr ? __bjs_optionalCodecUndefinedOrCache : __bjs_optionalCodecCache;
76+
let codec = cache.get(elementCodec);
77+
if (codec !== undefined) {
78+
return codec;
79+
}
80+
codec = {
6781
lower(value) {
6882
const isSome = isUndefinedOr ? value !== undefined : value != null;
6983
if (isSome) {
@@ -80,9 +94,16 @@ export async function createInstantiator(options, swift) {
8094
return elementCodec.lift();
8195
},
8296
};
97+
cache.set(elementCodec, codec);
98+
return codec;
8399
}
100+
const __bjs_dictCodecCache = new WeakMap();
84101
function __bjs_dictCodec(valueCodec) {
85-
return {
102+
let codec = __bjs_dictCodecCache.get(valueCodec);
103+
if (codec !== undefined) {
104+
return codec;
105+
}
106+
codec = {
86107
lower(value) {
87108
const keys = Object.keys(value);
88109
for (let i = 0; i < keys.length; i++) {
@@ -102,6 +123,8 @@ export async function createInstantiator(options, swift) {
102123
return result;
103124
},
104125
};
126+
__bjs_dictCodecCache.set(valueCodec, codec);
127+
return codec;
105128
}
106129

107130
const __bjs_stringCodec = {

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,13 @@ export async function createInstantiator(options, swift) {
3737

3838
let _exports = null;
3939
let bjs = null;
40+
const __bjs_arrayCodecCache = new WeakMap();
4041
function __bjs_arrayCodec(elementCodec) {
41-
return {
42+
let codec = __bjs_arrayCodecCache.get(elementCodec);
43+
if (codec !== undefined) {
44+
return codec;
45+
}
46+
codec = {
4247
lower(value) {
4348
for (let i = 0; i < value.length; i++) {
4449
elementCodec.lower(value[i]);
@@ -57,9 +62,18 @@ export async function createInstantiator(options, swift) {
5762
return result;
5863
},
5964
};
65+
__bjs_arrayCodecCache.set(elementCodec, codec);
66+
return codec;
6067
}
68+
const __bjs_optionalCodecCache = new WeakMap();
69+
const __bjs_optionalCodecUndefinedOrCache = new WeakMap();
6170
function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) {
62-
return {
71+
const cache = isUndefinedOr ? __bjs_optionalCodecUndefinedOrCache : __bjs_optionalCodecCache;
72+
let codec = cache.get(elementCodec);
73+
if (codec !== undefined) {
74+
return codec;
75+
}
76+
codec = {
6377
lower(value) {
6478
const isSome = isUndefinedOr ? value !== undefined : value != null;
6579
if (isSome) {
@@ -76,9 +90,16 @@ export async function createInstantiator(options, swift) {
7690
return elementCodec.lift();
7791
},
7892
};
93+
cache.set(elementCodec, codec);
94+
return codec;
7995
}
96+
const __bjs_dictCodecCache = new WeakMap();
8097
function __bjs_dictCodec(valueCodec) {
81-
return {
98+
let codec = __bjs_dictCodecCache.get(valueCodec);
99+
if (codec !== undefined) {
100+
return codec;
101+
}
102+
codec = {
82103
lower(value) {
83104
const keys = Object.keys(value);
84105
for (let i = 0; i < keys.length; i++) {
@@ -98,6 +119,8 @@ export async function createInstantiator(options, swift) {
98119
return result;
99120
},
100121
};
122+
__bjs_dictCodecCache.set(valueCodec, codec);
123+
return codec;
101124
}
102125

103126
const __bjs_stringCodec = {

Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,13 @@ export async function createInstantiator(options, swift) {
3131

3232
let _exports = null;
3333
let bjs = null;
34+
const __bjs_arrayCodecCache = new WeakMap();
3435
function __bjs_arrayCodec(elementCodec) {
35-
return {
36+
let codec = __bjs_arrayCodecCache.get(elementCodec);
37+
if (codec !== undefined) {
38+
return codec;
39+
}
40+
codec = {
3641
lower(value) {
3742
for (let i = 0; i < value.length; i++) {
3843
elementCodec.lower(value[i]);
@@ -51,9 +56,18 @@ export async function createInstantiator(options, swift) {
5156
return result;
5257
},
5358
};
59+
__bjs_arrayCodecCache.set(elementCodec, codec);
60+
return codec;
5461
}
62+
const __bjs_optionalCodecCache = new WeakMap();
63+
const __bjs_optionalCodecUndefinedOrCache = new WeakMap();
5564
function __bjs_optionalCodec(elementCodec, isUndefinedOr = false) {
56-
return {
65+
const cache = isUndefinedOr ? __bjs_optionalCodecUndefinedOrCache : __bjs_optionalCodecCache;
66+
let codec = cache.get(elementCodec);
67+
if (codec !== undefined) {
68+
return codec;
69+
}
70+
codec = {
5771
lower(value) {
5872
const isSome = isUndefinedOr ? value !== undefined : value != null;
5973
if (isSome) {
@@ -70,9 +84,16 @@ export async function createInstantiator(options, swift) {
7084
return elementCodec.lift();
7185
},
7286
};
87+
cache.set(elementCodec, codec);
88+
return codec;
7389
}
90+
const __bjs_dictCodecCache = new WeakMap();
7491
function __bjs_dictCodec(valueCodec) {
75-
return {
92+
let codec = __bjs_dictCodecCache.get(valueCodec);
93+
if (codec !== undefined) {
94+
return codec;
95+
}
96+
codec = {
7697
lower(value) {
7798
const keys = Object.keys(value);
7899
for (let i = 0; i < keys.length; i++) {
@@ -92,6 +113,8 @@ export async function createInstantiator(options, swift) {
92113
return result;
93114
},
94115
};
116+
__bjs_dictCodecCache.set(valueCodec, codec);
117+
return codec;
95118
}
96119

97120
const __bjs_stringCodec = {

0 commit comments

Comments
 (0)