diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift index ceaaae8f1..344e643f8 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift @@ -339,6 +339,26 @@ public struct BridgeJSLink { "let \(JSGlueVariableScope.reservedStorageToReturnOptionalFloat);", "let \(JSGlueVariableScope.reservedStorageToReturnOptionalDouble);", "let \(JSGlueVariableScope.reservedStorageToReturnOptionalHeapObject);", + "const \(JSGlueVariableScope.reservedStrEncCache) = new Map();", + "const \(JSGlueVariableScope.reservedStrEncCacheMax) = 4096;", + "function \(JSGlueVariableScope.reservedCachedEncode)(str) {", + " let encoded = \(JSGlueVariableScope.reservedStrEncCache).get(str);", + " if (encoded) {", + " \(JSGlueVariableScope.reservedStrEncCache).delete(str);", + " \(JSGlueVariableScope.reservedStrEncCache).set(str, encoded);", + " return encoded;", + " }", + " encoded = \(JSGlueVariableScope.reservedTextEncoder).encode(str);", + " if (\(JSGlueVariableScope.reservedStrEncCache).size >= \(JSGlueVariableScope.reservedStrEncCacheMax)) {", + " \(JSGlueVariableScope.reservedStrEncCache).delete(\(JSGlueVariableScope.reservedStrEncCache).keys().next().value);", + " }", + " \(JSGlueVariableScope.reservedStrEncCache).set(str, encoded);", + " return encoded;", + "}", + // Worst-case UTF-8 byte count: each UTF-16 code unit can expand + // to at most 3 bytes. Surrogate pairs (2 units) produce 4 bytes, + // so the per-unit ratio stays <= 3. + "function \(JSGlueVariableScope.reservedMaxUTF8Len)(str) { return str.length * 3; }", "let \(JSGlueVariableScope.reservedStringStack) = [];", "let \(JSGlueVariableScope.reservedI32Stack) = [];", "let \(JSGlueVariableScope.reservedI64Stack) = [];", @@ -396,6 +416,23 @@ public struct BridgeJSLink { printer.write("bytes.set(source);") } printer.write("}") + printer.write("bjs[\"swift_js_init_memory_from_string\"] = function(sourceId, bytesPtr) {") + printer.indent { + printer.write( + "const str = \(JSGlueVariableScope.reservedSwift).\(JSGlueVariableScope.reservedMemory).getObject(sourceId);" + ) + printer.write( + "\(JSGlueVariableScope.reservedSwift).\(JSGlueVariableScope.reservedMemory).release(sourceId);" + ) + printer.write( + "const target = new Uint8Array(\(JSGlueVariableScope.reservedMemory).buffer, bytesPtr);" + ) + printer.write( + "const result = \(JSGlueVariableScope.reservedTextEncoder).encodeInto(str, target);" + ) + printer.write("return result.written;") + } + printer.write("}") printer.write("bjs[\"swift_js_make_js_string\"] = function(ptr, len) {") printer.indent { printer.write( diff --git a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift index 1ad397f71..dbae9f23d 100644 --- a/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift +++ b/Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift @@ -24,6 +24,10 @@ final class JSGlueVariableScope { static let reservedStorageToReturnOptionalHeapObject = "tmpRetOptionalHeapObject" static let reservedTextEncoder = "textEncoder" static let reservedTextDecoder = "textDecoder" + static let reservedCachedEncode = "_cachedEncode" + static let reservedStrEncCache = "_strEncCache" + static let reservedStrEncCacheMax = "_strEncCacheMax" + static let reservedMaxUTF8Len = "_maxUTF8Len" static let reservedStringStack = "strStack" static let reservedI32Stack = "i32Stack" static let reservedI64Stack = "i64Stack" @@ -53,6 +57,10 @@ final class JSGlueVariableScope { reservedStorageToReturnOptionalHeapObject, reservedTextEncoder, reservedTextDecoder, + reservedCachedEncode, + reservedStrEncCache, + reservedStrEncCacheMax, + reservedMaxUTF8Len, reservedStringStack, reservedI32Stack, reservedI64Stack, @@ -263,7 +271,7 @@ struct IntrinsicJSFragment: Sendable { let argument = arguments[0] let bytesLabel = scope.variable("\(argument)Bytes") let bytesIdLabel = scope.variable("\(argument)Id") - printer.write("const \(bytesLabel) = \(JSGlueVariableScope.reservedTextEncoder).encode(\(argument));") + printer.write("const \(bytesLabel) = \(JSGlueVariableScope.reservedCachedEncode)(\(argument));") printer.write("const \(bytesIdLabel) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(bytesLabel));") return [bytesIdLabel, "\(bytesLabel).length"] } @@ -296,7 +304,7 @@ struct IntrinsicJSFragment: Sendable { printCode: { arguments, context in let printer = context.printer printer.write( - "\(JSGlueVariableScope.reservedStorageToReturnBytes) = \(JSGlueVariableScope.reservedTextEncoder).encode(\(arguments[0]));" + "\(JSGlueVariableScope.reservedStorageToReturnBytes) = \(JSGlueVariableScope.reservedCachedEncode)(\(arguments[0]));" ) return ["\(JSGlueVariableScope.reservedStorageToReturnBytes).length"] } @@ -2116,15 +2124,14 @@ struct IntrinsicJSFragment: Sendable { printCode: { arguments, context in let (scope, printer) = (context.scope, context.printer) let value = arguments[0] - let bytesVar = scope.variable("bytes") let idVar = scope.variable("id") printer.write( - "const \(bytesVar) = \(JSGlueVariableScope.reservedTextEncoder).encode(\(value));" + "const \(idVar) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(value));" ) - printer.write( - "const \(idVar) = \(JSGlueVariableScope.reservedSwift).memory.retain(\(bytesVar));" + scope.emitPushI32Parameter( + "\(JSGlueVariableScope.reservedMaxUTF8Len)(\(value))", + printer: printer ) - scope.emitPushI32Parameter("\(bytesVar).length", printer: printer) scope.emitPushI32Parameter(idVar, printer: printer) return [] } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js index 8359220c9..6e2e7ab7c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ArrayTypes.js @@ -32,6 +32,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -72,6 +89,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } @@ -301,9 +325,8 @@ export async function createInstantiator(options, swift) { arrayResult.reverse(); let ret = imports.importProcessStrings(arrayResult); for (const elem of ret) { - const bytes = textEncoder.encode(elem); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(elem); + i32Stack.push(_maxUTF8Len(elem)); i32Stack.push(id); } i32Stack.push(ret.length); @@ -411,9 +434,8 @@ export async function createInstantiator(options, swift) { } i32Stack.push(nums.length); for (const elem1 of strs) { - const bytes = textEncoder.encode(elem1); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(elem1); + i32Stack.push(_maxUTF8Len(elem1)); i32Stack.push(id); } i32Stack.push(strs.length); @@ -466,9 +488,8 @@ export async function createInstantiator(options, swift) { }, processStringArray: function bjs_processStringArray(values) { for (const elem of values) { - const bytes = textEncoder.encode(elem); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(elem); + i32Stack.push(_maxUTF8Len(elem)); i32Stack.push(id); } i32Stack.push(values.length); @@ -570,7 +591,7 @@ export async function createInstantiator(options, swift) { structHelpers.Point.lower(elem); } i32Stack.push(points.length); - const matchingBytes = textEncoder.encode(matching); + const matchingBytes = _cachedEncode(matching); const matchingId = swift.memory.retain(matchingBytes); instance.exports.bjs_findFirstPoint(matchingId, matchingBytes.length); const structValue = structHelpers.Point.lift(); @@ -651,9 +672,8 @@ export async function createInstantiator(options, swift) { for (const elem of values) { const isSome = elem != null ? 1 : 0; if (isSome) { - const bytes = textEncoder.encode(elem); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(elem); + i32Stack.push(_maxUTF8Len(elem)); i32Stack.push(id); } i32Stack.push(isSome); @@ -807,9 +827,8 @@ export async function createInstantiator(options, swift) { processNestedStringArray: function bjs_processNestedStringArray(values) { for (const elem of values) { for (const elem1 of elem) { - const bytes = textEncoder.encode(elem1); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(elem1); + i32Stack.push(_maxUTF8Len(elem1)); i32Stack.push(id); } i32Stack.push(elem.length); @@ -976,9 +995,8 @@ export async function createInstantiator(options, swift) { } i32Stack.push(nums.length); for (const elem1 of strs) { - const bytes = textEncoder.encode(elem1); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(elem1); + i32Stack.push(_maxUTF8Len(elem1)); i32Stack.push(id); } i32Stack.push(strs.length); @@ -997,9 +1015,8 @@ export async function createInstantiator(options, swift) { const isSome1 = b != null; if (isSome1) { for (const elem1 of b) { - const bytes = textEncoder.encode(elem1); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(elem1); + i32Stack.push(_maxUTF8Len(elem1)); i32Stack.push(id); } i32Stack.push(b.length); diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js index bf368738e..2de08f91d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Async.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -47,6 +64,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } @@ -216,7 +240,7 @@ export async function createInstantiator(options, swift) { return ret1; }, asyncRoundTripString: function bjs_asyncRoundTripString(v) { - const vBytes = textEncoder.encode(v); + const vBytes = _cachedEncode(v); const vId = swift.memory.retain(vBytes); const ret = instance.exports.bjs_asyncRoundTripString(vId, vBytes.length); const ret1 = swift.memory.getObject(ret); diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.js index 89ab29827..d2371eeff 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncImport.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -162,6 +179,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } @@ -360,7 +384,7 @@ export async function createInstantiator(options, swift) { } bjs["make_swift_closure_TestModule_10TestModulesSS_y"] = function(boxPtr, file, line) { const lower_closure_TestModule_10TestModulesSS_y = function(param0) { - const param0Bytes = textEncoder.encode(param0); + const param0Bytes = _cachedEncode(param0); const param0Id = swift.memory.retain(param0Bytes); instance.exports.invoke_swift_closure_TestModule_10TestModulesSS_y(boxPtr, param0Id, param0Bytes.length); if (tmpRetException) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.js index 7fd6a0d6b..3d9f08669 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/AsyncStaticImport.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -161,6 +178,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js index cafd250b0..96aa43d7a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DefaultParameters.js @@ -25,6 +25,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -38,9 +55,8 @@ export async function createInstantiator(options, swift) { let bjs = null; const __bjs_createConfigHelpers = () => ({ lower: (value) => { - const bytes = textEncoder.encode(value.name); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(value.name); + i32Stack.push(_maxUTF8Len(value.name)); i32Stack.push(id); i32Stack.push((value.value | 0)); i32Stack.push(value.enabled ? 1 : 0); @@ -89,6 +105,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } @@ -331,7 +354,7 @@ export async function createInstantiator(options, swift) { } constructor(name) { - const nameBytes = textEncoder.encode(name); + const nameBytes = _cachedEncode(name); const nameId = swift.memory.retain(nameBytes); const ret = instance.exports.bjs_DefaultGreeter_init(nameId, nameBytes.length); return DefaultGreeter.__construct(ret); @@ -343,7 +366,7 @@ export async function createInstantiator(options, swift) { return ret; } set name(value) { - const valueBytes = textEncoder.encode(value); + const valueBytes = _cachedEncode(value); const valueId = swift.memory.retain(valueBytes); instance.exports.bjs_DefaultGreeter_name_set(this.pointer, valueId, valueBytes.length); } @@ -364,12 +387,12 @@ export async function createInstantiator(options, swift) { } constructor(name = "Default", count = 42, enabled = true, status = StatusValues.Active, tag = null) { - const nameBytes = textEncoder.encode(name); + const nameBytes = _cachedEncode(name); const nameId = swift.memory.retain(nameBytes); const isSome = tag != null; let result, result1; if (isSome) { - const tagBytes = textEncoder.encode(tag); + const tagBytes = _cachedEncode(tag); const tagId = swift.memory.retain(tagBytes); result = tagId; result1 = tagBytes.length; @@ -387,7 +410,7 @@ export async function createInstantiator(options, swift) { return ret; } set name(value) { - const valueBytes = textEncoder.encode(value); + const valueBytes = _cachedEncode(value); const valueId = swift.memory.retain(valueBytes); instance.exports.bjs_ConstructorDefaults_name_set(this.pointer, valueId, valueBytes.length); } @@ -422,7 +445,7 @@ export async function createInstantiator(options, swift) { const isSome = value != null; let result, result1; if (isSome) { - const valueBytes = textEncoder.encode(value); + const valueBytes = _cachedEncode(value); const valueId = swift.memory.retain(valueBytes); result = valueId; result1 = valueBytes.length; @@ -444,7 +467,7 @@ export async function createInstantiator(options, swift) { EmptyGreeter, ConstructorDefaults, testStringDefault: function bjs_testStringDefault(message = "Hello World") { - const messageBytes = textEncoder.encode(message); + const messageBytes = _cachedEncode(message); const messageId = swift.memory.retain(messageBytes); instance.exports.bjs_testStringDefault(messageId, messageBytes.length); const ret = tmpRetString; @@ -471,7 +494,7 @@ export async function createInstantiator(options, swift) { const isSome = name != null; let result, result1; if (isSome) { - const nameBytes = textEncoder.encode(name); + const nameBytes = _cachedEncode(name); const nameId = swift.memory.retain(nameBytes); result = nameId; result1 = nameBytes.length; @@ -488,7 +511,7 @@ export async function createInstantiator(options, swift) { const isSome = greeting != null; let result, result1; if (isSome) { - const greetingBytes = textEncoder.encode(greeting); + const greetingBytes = _cachedEncode(greeting); const greetingId = swift.memory.retain(greetingBytes); result = greetingId; result1 = greetingBytes.length; @@ -502,7 +525,7 @@ export async function createInstantiator(options, swift) { return optResult; }, testMultipleDefaults: function bjs_testMultipleDefaults(title = "Default Title", count = 10, enabled = false) { - const titleBytes = textEncoder.encode(title); + const titleBytes = _cachedEncode(title); const titleId = swift.memory.retain(titleBytes); instance.exports.bjs_testMultipleDefaults(titleId, titleBytes.length, count, enabled); const ret = tmpRetString; @@ -560,9 +583,8 @@ export async function createInstantiator(options, swift) { }, testStringArrayDefault: function bjs_testStringArrayDefault(names = ["a", "b", "c"]) { for (const elem of names) { - const bytes = textEncoder.encode(elem); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(elem); + i32Stack.push(_maxUTF8Len(elem)); i32Stack.push(id); } i32Stack.push(names.length); @@ -622,7 +644,7 @@ export async function createInstantiator(options, swift) { return arrayResult; }, testMixedWithArrayDefault: function bjs_testMixedWithArrayDefault(name = "test", values = [10, 20, 30], enabled = true) { - const nameBytes = textEncoder.encode(name); + const nameBytes = _cachedEncode(name); const nameId = swift.memory.retain(nameBytes); for (const elem of values) { i32Stack.push((elem | 0)); diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js index 920017972..e48ee121a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/DictionaryTypes.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -32,16 +49,14 @@ export async function createInstantiator(options, swift) { let bjs = null; const __bjs_createCountersHelpers = () => ({ lower: (value) => { - const bytes = textEncoder.encode(value.name); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(value.name); + i32Stack.push(_maxUTF8Len(value.name)); i32Stack.push(id); const entries = Object.entries(value.counts); for (const entry of entries) { const [key, value] = entry; - const bytes1 = textEncoder.encode(key); - const id1 = swift.memory.retain(bytes1); - i32Stack.push(bytes1.length); + const id1 = swift.memory.retain(key); + i32Stack.push(_maxUTF8Len(key)); i32Stack.push(id1); const isSome = value != null ? 1 : 0; if (isSome) { @@ -88,6 +103,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } @@ -258,9 +280,8 @@ export async function createInstantiator(options, swift) { const entries = Object.entries(ret); for (const entry of entries) { const [key, value] = entry; - const bytes = textEncoder.encode(key); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(key); + i32Stack.push(_maxUTF8Len(key)); i32Stack.push(id); f64Stack.push(value); } @@ -349,9 +370,8 @@ export async function createInstantiator(options, swift) { const entries = Object.entries(values); for (const entry of entries) { const [key, value] = entry; - const bytes = textEncoder.encode(key); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(key); + i32Stack.push(_maxUTF8Len(key)); i32Stack.push(id); i32Stack.push((value | 0)); } @@ -372,13 +392,11 @@ export async function createInstantiator(options, swift) { const entries = Object.entries(values); for (const entry of entries) { const [key, value] = entry; - const bytes = textEncoder.encode(key); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(key); + i32Stack.push(_maxUTF8Len(key)); i32Stack.push(id); - const bytes1 = textEncoder.encode(value); - const id1 = swift.memory.retain(bytes1); - i32Stack.push(bytes1.length); + const id1 = swift.memory.retain(value); + i32Stack.push(_maxUTF8Len(value)); i32Stack.push(id1); } i32Stack.push(entries.length); @@ -405,9 +423,8 @@ export async function createInstantiator(options, swift) { const entries = Object.entries(values); for (const entry of entries) { const [key, value] = entry; - const bytes = textEncoder.encode(key); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(key); + i32Stack.push(_maxUTF8Len(key)); i32Stack.push(id); for (const elem of value) { i32Stack.push((elem | 0)); @@ -435,9 +452,8 @@ export async function createInstantiator(options, swift) { const entries = Object.entries(boxes); for (const entry of entries) { const [key, value] = entry; - const bytes = textEncoder.encode(key); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(key); + i32Stack.push(_maxUTF8Len(key)); i32Stack.push(id); ptrStack.push(value.pointer); } @@ -457,9 +473,8 @@ export async function createInstantiator(options, swift) { const entries = Object.entries(boxes); for (const entry of entries) { const [key, value] = entry; - const bytes = textEncoder.encode(key); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(key); + i32Stack.push(_maxUTF8Len(key)); i32Stack.push(id); const isSome = value != null ? 1 : 0; if (isSome) { diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js index 3d2230c6c..13e2e8a47 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumAssociatedValue.js @@ -100,6 +100,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -127,9 +144,8 @@ export async function createInstantiator(options, swift) { const enumTag = value.tag; switch (enumTag) { case APIResultValues.Tag.Success: { - const bytes = textEncoder.encode(value.param0); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(value.param0); + i32Stack.push(_maxUTF8Len(value.param0)); i32Stack.push(id); return APIResultValues.Tag.Success; } @@ -188,24 +204,21 @@ export async function createInstantiator(options, swift) { const enumTag = value.tag; switch (enumTag) { case ComplexResultValues.Tag.Success: { - const bytes = textEncoder.encode(value.param0); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(value.param0); + i32Stack.push(_maxUTF8Len(value.param0)); i32Stack.push(id); return ComplexResultValues.Tag.Success; } case ComplexResultValues.Tag.Error: { i32Stack.push((value.param1 | 0)); - const bytes = textEncoder.encode(value.param0); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(value.param0); + i32Stack.push(_maxUTF8Len(value.param0)); i32Stack.push(id); return ComplexResultValues.Tag.Error; } case ComplexResultValues.Tag.Status: { - const bytes = textEncoder.encode(value.param2); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(value.param2); + i32Stack.push(_maxUTF8Len(value.param2)); i32Stack.push(id); i32Stack.push((value.param1 | 0)); i32Stack.push(value.param0 ? 1 : 0); @@ -218,17 +231,14 @@ export async function createInstantiator(options, swift) { return ComplexResultValues.Tag.Coordinates; } case ComplexResultValues.Tag.Comprehensive: { - const bytes = textEncoder.encode(value.param8); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(value.param8); + i32Stack.push(_maxUTF8Len(value.param8)); i32Stack.push(id); - const bytes1 = textEncoder.encode(value.param7); - const id1 = swift.memory.retain(bytes1); - i32Stack.push(bytes1.length); + const id1 = swift.memory.retain(value.param7); + i32Stack.push(_maxUTF8Len(value.param7)); i32Stack.push(id1); - const bytes2 = textEncoder.encode(value.param6); - const id2 = swift.memory.retain(bytes2); - i32Stack.push(bytes2.length); + const id2 = swift.memory.retain(value.param6); + i32Stack.push(_maxUTF8Len(value.param6)); i32Stack.push(id2); f64Stack.push(value.param5); f64Stack.push(value.param4); @@ -290,24 +300,21 @@ export async function createInstantiator(options, swift) { const enumTag = value.tag; switch (enumTag) { case ResultValues.Tag.Success: { - const bytes = textEncoder.encode(value.param0); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(value.param0); + i32Stack.push(_maxUTF8Len(value.param0)); i32Stack.push(id); return ResultValues.Tag.Success; } case ResultValues.Tag.Failure: { i32Stack.push((value.param1 | 0)); - const bytes = textEncoder.encode(value.param0); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(value.param0); + i32Stack.push(_maxUTF8Len(value.param0)); i32Stack.push(id); return ResultValues.Tag.Failure; } case ResultValues.Tag.Status: { - const bytes = textEncoder.encode(value.param2); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(value.param2); + i32Stack.push(_maxUTF8Len(value.param2)); i32Stack.push(id); i32Stack.push((value.param1 | 0)); i32Stack.push(value.param0 ? 1 : 0); @@ -343,17 +350,15 @@ export async function createInstantiator(options, swift) { const enumTag = value.tag; switch (enumTag) { case NetworkingResultValues.Tag.Success: { - const bytes = textEncoder.encode(value.param0); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(value.param0); + i32Stack.push(_maxUTF8Len(value.param0)); i32Stack.push(id); return NetworkingResultValues.Tag.Success; } case NetworkingResultValues.Tag.Failure: { i32Stack.push((value.param1 | 0)); - const bytes = textEncoder.encode(value.param0); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(value.param0); + i32Stack.push(_maxUTF8Len(value.param0)); i32Stack.push(id); return NetworkingResultValues.Tag.Failure; } @@ -383,9 +388,8 @@ export async function createInstantiator(options, swift) { case APIOptionalResultValues.Tag.Success: { const isSome = value.param0 != null ? 1 : 0; if (isSome) { - const bytes = textEncoder.encode(value.param0); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(value.param0); + i32Stack.push(_maxUTF8Len(value.param0)); i32Stack.push(id); } i32Stack.push(isSome); @@ -407,9 +411,8 @@ export async function createInstantiator(options, swift) { case APIOptionalResultValues.Tag.Status: { const isSome = value.param2 != null ? 1 : 0; if (isSome) { - const bytes = textEncoder.encode(value.param2); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(value.param2); + i32Stack.push(_maxUTF8Len(value.param2)); i32Stack.push(id); } i32Stack.push(isSome); @@ -780,6 +783,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js index fe94c046f..272f62897 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumCase.js @@ -43,6 +43,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -71,6 +88,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js index 10fe31f64..9a21c57ca 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.Global.js @@ -63,6 +63,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -91,6 +108,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js index a6aeee4b0..7ed15f796 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumNamespace.js @@ -44,6 +44,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -72,6 +89,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js index 7e5334811..0693abe58 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/EnumRawType.js @@ -94,6 +94,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -123,6 +140,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } @@ -276,7 +300,7 @@ export async function createInstantiator(options, swift) { TestModule["bjs_returnsFeatureFlag"] = function bjs_returnsFeatureFlag() { try { let ret = imports.returnsFeatureFlag(); - tmpRetBytes = textEncoder.encode(ret); + tmpRetBytes = _cachedEncode(ret); return tmpRetBytes.length; } catch (error) { setException(error); @@ -298,7 +322,7 @@ export async function createInstantiator(options, swift) { const js = swift.memory.heap; const exports = { setTheme: function bjs_setTheme(theme) { - const themeBytes = textEncoder.encode(theme); + const themeBytes = _cachedEncode(theme); const themeId = swift.memory.retain(themeBytes); instance.exports.bjs_setTheme(themeId, themeBytes.length); }, @@ -312,7 +336,7 @@ export async function createInstantiator(options, swift) { const isSome = input != null; let result, result1; if (isSome) { - const inputBytes = textEncoder.encode(input); + const inputBytes = _cachedEncode(input); const inputId = swift.memory.retain(inputBytes); result = inputId; result1 = inputBytes.length; @@ -326,7 +350,7 @@ export async function createInstantiator(options, swift) { return optResult; }, setTSTheme: function bjs_setTSTheme(theme) { - const themeBytes = textEncoder.encode(theme); + const themeBytes = _cachedEncode(theme); const themeId = swift.memory.retain(themeBytes); instance.exports.bjs_setTSTheme(themeId, themeBytes.length); }, @@ -340,7 +364,7 @@ export async function createInstantiator(options, swift) { const isSome = input != null; let result, result1; if (isSome) { - const inputBytes = textEncoder.encode(input); + const inputBytes = _cachedEncode(input); const inputId = swift.memory.retain(inputBytes); result = inputId; result1 = inputBytes.length; @@ -354,7 +378,7 @@ export async function createInstantiator(options, swift) { return optResult; }, setFeatureFlag: function bjs_setFeatureFlag(flag) { - const flagBytes = textEncoder.encode(flag); + const flagBytes = _cachedEncode(flag); const flagId = swift.memory.retain(flagBytes); instance.exports.bjs_setFeatureFlag(flagId, flagBytes.length); }, @@ -368,7 +392,7 @@ export async function createInstantiator(options, swift) { const isSome = input != null; let result, result1; if (isSome) { - const inputBytes = textEncoder.encode(input); + const inputBytes = _cachedEncode(input); const inputId = swift.memory.retain(inputBytes); result = inputId; result1 = inputBytes.length; @@ -520,7 +544,7 @@ export async function createInstantiator(options, swift) { return optResult; }, processTheme: function bjs_processTheme(theme) { - const themeBytes = textEncoder.encode(theme); + const themeBytes = _cachedEncode(theme); const themeId = swift.memory.retain(themeBytes); const ret = instance.exports.bjs_processTheme(themeId, themeBytes.length); return ret; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.js index 53ddd7301..3bf8e8958 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/FixedWidthIntegers.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -48,6 +65,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.js index 346b74eac..3b119d468 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalGetter.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -48,6 +65,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.js index f74095374..2c3fa5c0e 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/GlobalThisImports.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -47,6 +64,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.js index c2490c0ea..017e54b0f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.ConfigPointer.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -47,6 +64,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } @@ -277,7 +301,7 @@ export async function createInstantiator(options, swift) { } constructor(name) { - const nameBytes = textEncoder.encode(name); + const nameBytes = _cachedEncode(name); const nameId = swift.memory.retain(nameBytes); const ret = instance.exports.bjs_CachedModel_init(nameId, nameBytes.length); return CachedModel.__construct(ret); @@ -289,7 +313,7 @@ export async function createInstantiator(options, swift) { return ret; } set name(value) { - const valueBytes = textEncoder.encode(value); + const valueBytes = _cachedEncode(value); const valueId = swift.memory.retain(valueBytes); instance.exports.bjs_CachedModel_name_set(this.pointer, valueId, valueBytes.length); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.PerClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.PerClass.js index d970c5d77..375662b79 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.PerClass.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.PerClass.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -47,6 +64,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } @@ -277,7 +301,7 @@ export async function createInstantiator(options, swift) { } constructor(name) { - const nameBytes = textEncoder.encode(name); + const nameBytes = _cachedEncode(name); const nameId = swift.memory.retain(nameBytes); const ret = instance.exports.bjs_CachedModel_init(nameId, nameBytes.length); return CachedModel.__construct(ret); @@ -289,7 +313,7 @@ export async function createInstantiator(options, swift) { return ret; } set name(value) { - const valueBytes = textEncoder.encode(value); + const valueBytes = _cachedEncode(value); const valueId = swift.memory.retain(valueBytes); instance.exports.bjs_CachedModel_name_set(this.pointer, valueId, valueBytes.length); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.js index d970c5d77..375662b79 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/IdentityModeClass.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -47,6 +64,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } @@ -277,7 +301,7 @@ export async function createInstantiator(options, swift) { } constructor(name) { - const nameBytes = textEncoder.encode(name); + const nameBytes = _cachedEncode(name); const nameId = swift.memory.retain(nameBytes); const ret = instance.exports.bjs_CachedModel_init(nameId, nameBytes.length); return CachedModel.__construct(ret); @@ -289,7 +313,7 @@ export async function createInstantiator(options, swift) { return ret; } set name(value) { - const valueBytes = textEncoder.encode(value); + const valueBytes = _cachedEncode(value); const valueId = swift.memory.retain(valueBytes); instance.exports.bjs_CachedModel_name_set(this.pointer, valueId, valueBytes.length); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js index 06cf6550e..866e49c5f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportArray.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -48,6 +65,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js index c469fcb58..79649e4e5 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ImportedTypeInExportedInterface.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -86,6 +103,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.js index 952197c2a..c3b4660c6 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/InvalidPropertyNames.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -48,6 +65,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } @@ -211,7 +235,7 @@ export async function createInstantiator(options, swift) { TestModule["bjs_WeirdNaming_normalProperty_get"] = function bjs_WeirdNaming_normalProperty_get(self) { try { let ret = swift.memory.getObject(self).normalProperty; - tmpRetBytes = textEncoder.encode(ret); + tmpRetBytes = _cachedEncode(ret); return tmpRetBytes.length; } catch (error) { setException(error); @@ -238,7 +262,7 @@ export async function createInstantiator(options, swift) { TestModule["bjs_WeirdNaming_property_with_spaces_get"] = function bjs_WeirdNaming_property_with_spaces_get(self) { try { let ret = swift.memory.getObject(self)["property with spaces"]; - tmpRetBytes = textEncoder.encode(ret); + tmpRetBytes = _cachedEncode(ret); return tmpRetBytes.length; } catch (error) { setException(error); @@ -256,7 +280,7 @@ export async function createInstantiator(options, swift) { TestModule["bjs_WeirdNaming_constructor_get"] = function bjs_WeirdNaming_constructor_get(self) { try { let ret = swift.memory.getObject(self).constructor; - tmpRetBytes = textEncoder.encode(ret); + tmpRetBytes = _cachedEncode(ret); return tmpRetBytes.length; } catch (error) { setException(error); @@ -265,7 +289,7 @@ export async function createInstantiator(options, swift) { TestModule["bjs_WeirdNaming_for_get"] = function bjs_WeirdNaming_for_get(self) { try { let ret = swift.memory.getObject(self).for; - tmpRetBytes = textEncoder.encode(ret); + tmpRetBytes = _cachedEncode(ret); return tmpRetBytes.length; } catch (error) { setException(error); @@ -274,7 +298,7 @@ export async function createInstantiator(options, swift) { TestModule["bjs_WeirdNaming_Any_get"] = function bjs_WeirdNaming_Any_get(self) { try { let ret = swift.memory.getObject(self).Any; - tmpRetBytes = textEncoder.encode(ret); + tmpRetBytes = _cachedEncode(ret); return tmpRetBytes.length; } catch (error) { setException(error); diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.js index 88a5adb38..fd9779d3a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClass.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -48,6 +65,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } @@ -211,7 +235,7 @@ export async function createInstantiator(options, swift) { TestModule["bjs_Greeter_name_get"] = function bjs_Greeter_name_get(self) { try { let ret = swift.memory.getObject(self).name; - tmpRetBytes = textEncoder.encode(ret); + tmpRetBytes = _cachedEncode(ret); return tmpRetBytes.length; } catch (error) { setException(error); @@ -237,7 +261,7 @@ export async function createInstantiator(options, swift) { TestModule["bjs_Greeter_greet"] = function bjs_Greeter_greet(self) { try { let ret = swift.memory.getObject(self).greet(); - tmpRetBytes = textEncoder.encode(ret); + tmpRetBytes = _cachedEncode(ret); return tmpRetBytes.length; } catch (error) { setException(error); diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.js index 10fafb7a0..e9b1935f9 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSClassStaticFunctions.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -48,6 +65,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js index 0258b63b6..6f9677b18 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/JSValue.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -137,6 +154,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js index 195eef468..0991dd31c 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedGlobal.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -47,6 +64,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js index ca54493f6..1c30675c2 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedModules.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -47,6 +64,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js index 3551caab2..ba01360eb 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/MixedPrivate.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -47,6 +64,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js index a63df44be..835fc1966 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.Global.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -47,6 +64,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } @@ -279,7 +303,7 @@ export async function createInstantiator(options, swift) { } constructor(name) { - const nameBytes = textEncoder.encode(name); + const nameBytes = _cachedEncode(name); const nameId = swift.memory.retain(nameBytes); const ret = instance.exports.bjs___Swift_Foundation_Greeter_init(nameId, nameBytes.length); return Greeter.__construct(ret); diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js index 32a325bda..e6b021bce 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Namespaces.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -47,6 +64,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } @@ -279,7 +303,7 @@ export async function createInstantiator(options, swift) { } constructor(name) { - const nameBytes = textEncoder.encode(name); + const nameBytes = _cachedEncode(name); const nameId = swift.memory.retain(nameBytes); const ret = instance.exports.bjs___Swift_Foundation_Greeter_init(nameId, nameBytes.length); return Greeter.__construct(ret); diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js index cf24e7e2d..962cae896 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/NestedType.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -58,6 +75,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js index 1d585ce0b..2e15660e8 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Optionals.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -48,6 +65,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } @@ -577,7 +601,7 @@ export async function createInstantiator(options, swift) { const isSome = name != null; let result, result1; if (isSome) { - const nameBytes = textEncoder.encode(name); + const nameBytes = _cachedEncode(name); const nameId = swift.memory.retain(nameBytes); result = nameId; result1 = nameBytes.length; @@ -598,7 +622,7 @@ export async function createInstantiator(options, swift) { const isSome = name != null; let result, result1; if (isSome) { - const nameBytes = textEncoder.encode(name); + const nameBytes = _cachedEncode(name); const nameId = swift.memory.retain(nameBytes); result = nameId; result1 = nameBytes.length; @@ -618,7 +642,7 @@ export async function createInstantiator(options, swift) { const isSome = value != null; let result, result1; if (isSome) { - const valueBytes = textEncoder.encode(value); + const valueBytes = _cachedEncode(value); const valueId = swift.memory.retain(valueBytes); result = valueId; result1 = valueBytes.length; @@ -648,7 +672,7 @@ export async function createInstantiator(options, swift) { const isSome = value != null; let result, result1; if (isSome) { - const valueBytes = textEncoder.encode(value); + const valueBytes = _cachedEncode(value); const valueId = swift.memory.retain(valueBytes); result = valueId; result1 = valueBytes.length; @@ -721,7 +745,7 @@ export async function createInstantiator(options, swift) { const isSome = name != null; let result, result1; if (isSome) { - const nameBytes = textEncoder.encode(name); + const nameBytes = _cachedEncode(name); const nameId = swift.memory.retain(nameBytes); result = nameId; result1 = nameBytes.length; @@ -808,7 +832,7 @@ export async function createInstantiator(options, swift) { const isSome = name != null; let result, result1; if (isSome) { - const nameBytes = textEncoder.encode(name); + const nameBytes = _cachedEncode(name); const nameId = swift.memory.retain(nameBytes); result = nameId; result1 = nameBytes.length; @@ -825,7 +849,7 @@ export async function createInstantiator(options, swift) { const isSome = name != null; let result, result1; if (isSome) { - const nameBytes = textEncoder.encode(name); + const nameBytes = _cachedEncode(name); const nameId = swift.memory.retain(nameBytes); result = nameId; result1 = nameBytes.length; @@ -842,7 +866,7 @@ export async function createInstantiator(options, swift) { const isSome = name != null; let result, result1; if (isSome) { - const nameBytes = textEncoder.encode(name); + const nameBytes = _cachedEncode(name); const nameId = swift.memory.retain(nameBytes); result = nameId; result1 = nameBytes.length; @@ -859,7 +883,7 @@ export async function createInstantiator(options, swift) { const isSome = name != null; let result, result1; if (isSome) { - const nameBytes = textEncoder.encode(name); + const nameBytes = _cachedEncode(name); const nameId = swift.memory.retain(nameBytes); result = nameId; result1 = nameBytes.length; @@ -890,7 +914,7 @@ export async function createInstantiator(options, swift) { const isSome = name != null; let result, result1; if (isSome) { - const nameBytes = textEncoder.encode(name); + const nameBytes = _cachedEncode(name); const nameId = swift.memory.retain(nameBytes); result = nameId; result1 = nameBytes.length; @@ -907,7 +931,7 @@ export async function createInstantiator(options, swift) { const isSome = firstName != null; let result, result1; if (isSome) { - const firstNameBytes = textEncoder.encode(firstName); + const firstNameBytes = _cachedEncode(firstName); const firstNameId = swift.memory.retain(firstNameBytes); result = firstNameId; result1 = firstNameBytes.length; @@ -918,7 +942,7 @@ export async function createInstantiator(options, swift) { const isSome1 = lastName != null; let result2, result3; if (isSome1) { - const lastNameBytes = textEncoder.encode(lastName); + const lastNameBytes = _cachedEncode(lastName); const lastNameId = swift.memory.retain(lastNameBytes); result2 = lastNameId; result3 = lastNameBytes.length; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.js index 490f2b4e2..48ebb85a3 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveParameters.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -48,6 +65,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.js index bec07b959..37f2f2860 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PrimitiveReturn.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -48,6 +65,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js index 7f840708e..545148d3a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/PropertyTypes.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -47,6 +64,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } @@ -267,7 +291,7 @@ export async function createInstantiator(options, swift) { } constructor(intValue, floatValue, doubleValue, boolValue, stringValue, jsObject) { - const stringValueBytes = textEncoder.encode(stringValue); + const stringValueBytes = _cachedEncode(stringValue); const stringValueId = swift.memory.retain(stringValueBytes); const ret = instance.exports.bjs_PropertyHolder_init(intValue, floatValue, doubleValue, boolValue, stringValueId, stringValueBytes.length, swift.memory.retain(jsObject)); return PropertyHolder.__construct(ret); @@ -313,7 +337,7 @@ export async function createInstantiator(options, swift) { return ret; } set stringValue(value) { - const valueBytes = textEncoder.encode(value); + const valueBytes = _cachedEncode(value); const valueId = swift.memory.retain(valueBytes); instance.exports.bjs_PropertyHolder_stringValue_set(this.pointer, valueId, valueBytes.length); } @@ -362,7 +386,7 @@ export async function createInstantiator(options, swift) { return ret; } set lazyValue(value) { - const valueBytes = textEncoder.encode(value); + const valueBytes = _cachedEncode(value); const valueId = swift.memory.retain(valueBytes); instance.exports.bjs_PropertyHolder_lazyValue_set(this.pointer, valueId, valueBytes.length); } @@ -377,7 +401,7 @@ export async function createInstantiator(options, swift) { return ret; } set computedReadWrite(value) { - const valueBytes = textEncoder.encode(value); + const valueBytes = _cachedEncode(value); const valueId = swift.memory.retain(valueBytes); instance.exports.bjs_PropertyHolder_computedReadWrite_set(this.pointer, valueId, valueBytes.length); } @@ -392,7 +416,7 @@ export async function createInstantiator(options, swift) { const exports = { PropertyHolder, createPropertyHolder: function bjs_createPropertyHolder(intValue, floatValue, doubleValue, boolValue, stringValue, jsObject) { - const stringValueBytes = textEncoder.encode(stringValue); + const stringValueBytes = _cachedEncode(stringValue); const stringValueId = swift.memory.retain(stringValueBytes); const ret = instance.exports.bjs_createPropertyHolder(intValue, floatValue, doubleValue, boolValue, stringValueId, stringValueBytes.length, swift.memory.retain(jsObject)); return PropertyHolder.__construct(ret); diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js index 9fb9b172b..81aab2d31 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Protocol.js @@ -43,6 +43,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -59,9 +76,8 @@ export async function createInstantiator(options, swift) { const enumTag = value.tag; switch (enumTag) { case ResultValues.Tag.Success: { - const bytes = textEncoder.encode(value.param0); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(value.param0); + i32Stack.push(_maxUTF8Len(value.param0)); i32Stack.push(id); return ResultValues.Tag.Success; } @@ -104,6 +120,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } @@ -281,7 +304,7 @@ export async function createInstantiator(options, swift) { TestModule["bjs_MyViewControllerDelegate_delegateName_get"] = function bjs_MyViewControllerDelegate_delegateName_get(self) { try { let ret = swift.memory.getObject(self).delegateName; - tmpRetBytes = textEncoder.encode(ret); + tmpRetBytes = _cachedEncode(ret); return tmpRetBytes.length; } catch (error) { setException(error); @@ -334,7 +357,7 @@ export async function createInstantiator(options, swift) { TestModule["bjs_MyViewControllerDelegate_rawStringEnum_get"] = function bjs_MyViewControllerDelegate_rawStringEnum_get(self) { try { let ret = swift.memory.getObject(self).rawStringEnum; - tmpRetBytes = textEncoder.encode(ret); + tmpRetBytes = _cachedEncode(ret); return tmpRetBytes.length; } catch (error) { setException(error); @@ -533,7 +556,7 @@ export async function createInstantiator(options, swift) { TestModule["bjs_MyViewControllerDelegate_createEnum"] = function bjs_MyViewControllerDelegate_createEnum(self) { try { let ret = swift.memory.getObject(self).createEnum(); - tmpRetBytes = textEncoder.encode(ret); + tmpRetBytes = _cachedEncode(ret); return tmpRetBytes.length; } catch (error) { setException(error); @@ -654,7 +677,7 @@ export async function createInstantiator(options, swift) { instance.exports.bjs_MyViewController_triggerEvent(this.pointer); } updateValue(value) { - const valueBytes = textEncoder.encode(value); + const valueBytes = _cachedEncode(value); const valueId = swift.memory.retain(valueBytes); instance.exports.bjs_MyViewController_updateValue(this.pointer, valueId, valueBytes.length); } @@ -663,9 +686,9 @@ export async function createInstantiator(options, swift) { return ret !== 0; } updateLabel(prefix, suffix) { - const prefixBytes = textEncoder.encode(prefix); + const prefixBytes = _cachedEncode(prefix); const prefixId = swift.memory.retain(prefixBytes); - const suffixBytes = textEncoder.encode(suffix); + const suffixBytes = _cachedEncode(suffix); const suffixId = swift.memory.retain(suffixBytes); instance.exports.bjs_MyViewController_updateLabel(this.pointer, prefixId, prefixBytes.length, suffixId, suffixBytes.length); } @@ -757,9 +780,8 @@ export async function createInstantiator(options, swift) { const entries = Object.entries(value); for (const entry of entries) { const [key, value1] = entry; - const bytes = textEncoder.encode(key); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(key); + i32Stack.push(_maxUTF8Len(key)); i32Stack.push(id); const objId = swift.memory.retain(value1); i32Stack.push(objId); @@ -797,9 +819,8 @@ export async function createInstantiator(options, swift) { const entries = Object.entries(delegates); for (const entry of entries) { const [key, value] = entry; - const bytes = textEncoder.encode(key); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(key); + i32Stack.push(_maxUTF8Len(key)); i32Stack.push(id); const objId = swift.memory.retain(value); i32Stack.push(objId); diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js index aefdb5679..d7461e8b1 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/ProtocolInClosure.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -72,6 +89,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } @@ -246,7 +270,7 @@ export async function createInstantiator(options, swift) { try { const callback = swift.memory.getObject(callbackId); let ret = callback(swift.memory.getObject(param0)); - tmpRetBytes = textEncoder.encode(ret); + tmpRetBytes = _cachedEncode(ret); return tmpRetBytes.length; } catch (error) { setException(error); @@ -271,7 +295,7 @@ export async function createInstantiator(options, swift) { try { const callback = swift.memory.getObject(callbackId); let ret = callback(param0IsSome ? swift.memory.getObject(param0ObjectId) : null); - tmpRetBytes = textEncoder.encode(ret); + tmpRetBytes = _cachedEncode(ret); return tmpRetBytes.length; } catch (error) { setException(error); @@ -336,7 +360,7 @@ export async function createInstantiator(options, swift) { TestModule["bjs_Renderable_render"] = function bjs_Renderable_render(self) { try { let ret = swift.memory.getObject(self).render(); - tmpRetBytes = textEncoder.encode(ret); + tmpRetBytes = _cachedEncode(ret); return tmpRetBytes.length; } catch (error) { setException(error); @@ -413,7 +437,7 @@ export async function createInstantiator(options, swift) { } constructor(name) { - const nameBytes = textEncoder.encode(name); + const nameBytes = _cachedEncode(name); const nameId = swift.memory.retain(nameBytes); const ret = instance.exports.bjs_Widget_init(nameId, nameBytes.length); return Widget.__construct(ret); @@ -425,7 +449,7 @@ export async function createInstantiator(options, swift) { return ret; } set name(value) { - const valueBytes = textEncoder.encode(value); + const valueBytes = _cachedEncode(value); const valueId = swift.memory.retain(valueBytes); instance.exports.bjs_Widget_name_set(this.pointer, valueId, valueBytes.length); } @@ -440,7 +464,7 @@ export async function createInstantiator(options, swift) { return ret; }, makeRenderableFactory: function bjs_makeRenderableFactory(defaultName) { - const defaultNameBytes = textEncoder.encode(defaultName); + const defaultNameBytes = _cachedEncode(defaultName); const defaultNameId = swift.memory.retain(defaultNameBytes); const ret = instance.exports.bjs_makeRenderableFactory(defaultNameId, defaultNameBytes.length); return swift.memory.getObject(ret); diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js index ef685b8a4..3b536b76a 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.Global.js @@ -30,6 +30,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -46,9 +63,8 @@ export async function createInstantiator(options, swift) { const enumTag = value.tag; switch (enumTag) { case APIResultValues.Tag.Success: { - const bytes = textEncoder.encode(value.param0); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(value.param0); + i32Stack.push(_maxUTF8Len(value.param0)); i32Stack.push(id); return APIResultValues.Tag.Success; } @@ -91,6 +107,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } @@ -375,7 +398,7 @@ export async function createInstantiator(options, swift) { Utils: { String: { uppercase: function bjs_Utils_String_static_uppercase(text) { - const textBytes = textEncoder.encode(text); + const textBytes = _cachedEncode(text); const textId = swift.memory.retain(textBytes); instance.exports.bjs_Utils_String_static_uppercase(textId, textBytes.length); const ret = tmpRetString; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js index 1fd066076..7a31bcda6 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticFunctions.js @@ -30,6 +30,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -46,9 +63,8 @@ export async function createInstantiator(options, swift) { const enumTag = value.tag; switch (enumTag) { case APIResultValues.Tag.Success: { - const bytes = textEncoder.encode(value.param0); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(value.param0); + i32Stack.push(_maxUTF8Len(value.param0)); i32Stack.push(id); return APIResultValues.Tag.Success; } @@ -91,6 +107,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } @@ -369,7 +392,7 @@ export async function createInstantiator(options, swift) { Utils: { String: { uppercase: function bjs_Utils_String_static_uppercase(text) { - const textBytes = textEncoder.encode(text); + const textBytes = _cachedEncode(text); const textId = swift.memory.retain(textBytes); instance.exports.bjs_Utils_String_static_uppercase(textId, textBytes.length); const ret = tmpRetString; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js index 5800fcb56..c2021ef91 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.Global.js @@ -24,6 +24,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -52,6 +69,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } @@ -304,7 +328,7 @@ export async function createInstantiator(options, swift) { return ret; } static set classVariable(value) { - const valueBytes = textEncoder.encode(value); + const valueBytes = _cachedEncode(value); const valueId = swift.memory.retain(valueBytes); instance.exports.bjs_PropertyClass_static_classVariable_set(valueId, valueBytes.length); } @@ -315,7 +339,7 @@ export async function createInstantiator(options, swift) { return ret; } static set computedProperty(value) { - const valueBytes = textEncoder.encode(value); + const valueBytes = _cachedEncode(value); const valueId = swift.memory.retain(valueBytes); instance.exports.bjs_PropertyClass_static_computedProperty_set(valueId, valueBytes.length); } @@ -333,7 +357,7 @@ export async function createInstantiator(options, swift) { const isSome = value != null; let result, result1; if (isSome) { - const valueBytes = textEncoder.encode(value); + const valueBytes = _cachedEncode(value); const valueId = swift.memory.retain(valueBytes); result = valueId; result1 = valueBytes.length; @@ -361,7 +385,7 @@ export async function createInstantiator(options, swift) { return ret; }, set enumProperty(value) { - const valueBytes = textEncoder.encode(value); + const valueBytes = _cachedEncode(value); const valueId = swift.memory.retain(valueBytes); instance.exports.bjs_PropertyEnum_static_enumProperty_set(valueId, valueBytes.length); }, @@ -376,7 +400,7 @@ export async function createInstantiator(options, swift) { return ret; }, set computedEnum(value) { - const valueBytes = textEncoder.encode(value); + const valueBytes = _cachedEncode(value); const valueId = swift.memory.retain(valueBytes); instance.exports.bjs_PropertyEnum_static_computedEnum_set(valueId, valueBytes.length); } @@ -389,7 +413,7 @@ export async function createInstantiator(options, swift) { return ret; }, set namespaceProperty(value) { - const valueBytes = textEncoder.encode(value); + const valueBytes = _cachedEncode(value); const valueId = swift.memory.retain(valueBytes); instance.exports.bjs_PropertyNamespace_static_namespaceProperty_set(valueId, valueBytes.length); }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js index b81255810..240e9e919 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StaticProperties.js @@ -24,6 +24,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -52,6 +69,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } @@ -304,7 +328,7 @@ export async function createInstantiator(options, swift) { return ret; } static set classVariable(value) { - const valueBytes = textEncoder.encode(value); + const valueBytes = _cachedEncode(value); const valueId = swift.memory.retain(valueBytes); instance.exports.bjs_PropertyClass_static_classVariable_set(valueId, valueBytes.length); } @@ -315,7 +339,7 @@ export async function createInstantiator(options, swift) { return ret; } static set computedProperty(value) { - const valueBytes = textEncoder.encode(value); + const valueBytes = _cachedEncode(value); const valueId = swift.memory.retain(valueBytes); instance.exports.bjs_PropertyClass_static_computedProperty_set(valueId, valueBytes.length); } @@ -333,7 +357,7 @@ export async function createInstantiator(options, swift) { const isSome = value != null; let result, result1; if (isSome) { - const valueBytes = textEncoder.encode(value); + const valueBytes = _cachedEncode(value); const valueId = swift.memory.retain(valueBytes); result = valueId; result1 = valueBytes.length; @@ -355,7 +379,7 @@ export async function createInstantiator(options, swift) { return ret; }, set enumProperty(value) { - const valueBytes = textEncoder.encode(value); + const valueBytes = _cachedEncode(value); const valueId = swift.memory.retain(valueBytes); instance.exports.bjs_PropertyEnum_static_enumProperty_set(valueId, valueBytes.length); }, @@ -370,7 +394,7 @@ export async function createInstantiator(options, swift) { return ret; }, set computedEnum(value) { - const valueBytes = textEncoder.encode(value); + const valueBytes = _cachedEncode(value); const valueId = swift.memory.retain(valueBytes); instance.exports.bjs_PropertyEnum_static_computedEnum_set(valueId, valueBytes.length); } @@ -383,7 +407,7 @@ export async function createInstantiator(options, swift) { return ret; }, set namespaceProperty(value) { - const valueBytes = textEncoder.encode(value); + const valueBytes = _cachedEncode(value); const valueId = swift.memory.retain(valueBytes); instance.exports.bjs_PropertyNamespace_static_namespaceProperty_set(valueId, valueBytes.length); }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.js index 033f08cd2..4b530827b 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringParameter.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -48,6 +65,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } @@ -222,12 +246,12 @@ export async function createInstantiator(options, swift) { const js = swift.memory.heap; const exports = { checkString: function bjs_checkString(a) { - const aBytes = textEncoder.encode(a); + const aBytes = _cachedEncode(a); const aId = swift.memory.retain(aBytes); instance.exports.bjs_checkString(aId, aBytes.length); }, roundtripString: function bjs_roundtripString(a) { - const aBytes = textEncoder.encode(a); + const aBytes = _cachedEncode(a); const aId = swift.memory.retain(aBytes); instance.exports.bjs_roundtripString(aId, aBytes.length); const ret = tmpRetString; diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.js index 8187b9e92..112266378 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/StringReturn.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -48,6 +65,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } @@ -193,7 +217,7 @@ export async function createInstantiator(options, swift) { TestModule["bjs_checkString"] = function bjs_checkString() { try { let ret = imports.checkString(); - tmpRetBytes = textEncoder.encode(ret); + tmpRetBytes = _cachedEncode(ret); return tmpRetBytes.length; } catch (error) { setException(error); diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js index 9ee57d692..0a3b7029f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClass.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -48,6 +65,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } @@ -295,7 +319,7 @@ export async function createInstantiator(options, swift) { } constructor(name) { - const nameBytes = textEncoder.encode(name); + const nameBytes = _cachedEncode(name); const nameId = swift.memory.retain(nameBytes); const ret = instance.exports.bjs_Greeter_init(nameId, nameBytes.length); return Greeter.__construct(ret); @@ -307,7 +331,7 @@ export async function createInstantiator(options, swift) { return ret; } changeName(name) { - const nameBytes = textEncoder.encode(name); + const nameBytes = _cachedEncode(name); const nameId = swift.memory.retain(nameBytes); instance.exports.bjs_Greeter_changeName(this.pointer, nameId, nameBytes.length); } @@ -330,7 +354,7 @@ export async function createInstantiator(options, swift) { return ret; } set name(value) { - const valueBytes = textEncoder.encode(value); + const valueBytes = _cachedEncode(value); const valueId = swift.memory.retain(valueBytes); instance.exports.bjs_Greeter_name_set(this.pointer, valueId, valueBytes.length); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js index 0b4ca3dcc..2984bddac 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosure.js @@ -49,6 +49,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -87,9 +104,8 @@ export async function createInstantiator(options, swift) { const __bjs_createAnimalHelpers = () => ({ lower: (value) => { - const bytes = textEncoder.encode(value.type); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(value.type); + i32Stack.push(_maxUTF8Len(value.type)); i32Stack.push(id); }, lift: () => { @@ -102,9 +118,8 @@ export async function createInstantiator(options, swift) { const enumTag = value.tag; switch (enumTag) { case APIResultValues.Tag.Success: { - const bytes = textEncoder.encode(value.param0); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(value.param0); + i32Stack.push(_maxUTF8Len(value.param0)); i32Stack.push(id); return APIResultValues.Tag.Success; } @@ -175,6 +190,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } @@ -355,7 +377,7 @@ export async function createInstantiator(options, swift) { const callback = swift.memory.getObject(callbackId); const string = decodeString(param0Bytes, param0Count); let ret = callback(string); - tmpRetBytes = textEncoder.encode(ret); + tmpRetBytes = _cachedEncode(ret); return tmpRetBytes.length; } catch (error) { setException(error); @@ -363,7 +385,7 @@ export async function createInstantiator(options, swift) { } bjs["make_swift_closure_TestModule_10TestModule5ThemeO_5ThemeO"] = function(boxPtr, file, line) { const lower_closure_TestModule_10TestModule5ThemeO_5ThemeO = function(param0) { - const param0Bytes = textEncoder.encode(param0); + const param0Bytes = _cachedEncode(param0); const param0Id = swift.memory.retain(param0Bytes); instance.exports.invoke_swift_closure_TestModule_10TestModule5ThemeO_5ThemeO(boxPtr, param0Id, param0Bytes.length); const ret = tmpRetString; @@ -480,7 +502,7 @@ export async function createInstantiator(options, swift) { const callback = swift.memory.getObject(callbackId); const string = decodeString(param0Bytes, param0Count); let ret = callback(string); - tmpRetBytes = textEncoder.encode(ret); + tmpRetBytes = _cachedEncode(ret); return tmpRetBytes.length; } catch (error) { setException(error); @@ -488,7 +510,7 @@ export async function createInstantiator(options, swift) { } bjs["make_swift_closure_TestModule_10TestModuleSS_SS"] = function(boxPtr, file, line) { const lower_closure_TestModule_10TestModuleSS_SS = function(param0) { - const param0Bytes = textEncoder.encode(param0); + const param0Bytes = _cachedEncode(param0); const param0Id = swift.memory.retain(param0Bytes); instance.exports.invoke_swift_closure_TestModule_10TestModuleSS_SS(boxPtr, param0Id, param0Bytes.length); const ret = tmpRetString; @@ -643,7 +665,7 @@ export async function createInstantiator(options, swift) { const isSome = param0 != null; let result, result1; if (isSome) { - const param0Bytes = textEncoder.encode(param0); + const param0Bytes = _cachedEncode(param0); const param0Id = swift.memory.retain(param0Bytes); result = param0Id; result1 = param0Bytes.length; @@ -830,7 +852,7 @@ export async function createInstantiator(options, swift) { const isSome = param0 != null; let result, result1; if (isSome) { - const param0Bytes = textEncoder.encode(param0); + const param0Bytes = _cachedEncode(param0); const param0Id = swift.memory.retain(param0Bytes); result = param0Id; result1 = param0Bytes.length; @@ -1038,7 +1060,7 @@ export async function createInstantiator(options, swift) { } constructor(name) { - const nameBytes = textEncoder.encode(name); + const nameBytes = _cachedEncode(name); const nameId = swift.memory.retain(nameBytes); const ret = instance.exports.bjs_Person_init(nameId, nameBytes.length); return Person.__construct(ret); @@ -1185,7 +1207,7 @@ export async function createInstantiator(options, swift) { APIResult: APIResultValues, Animal: { init: function(type) { - const typeBytes = textEncoder.encode(type); + const typeBytes = _cachedEncode(type); const typeId = swift.memory.retain(typeBytes); instance.exports.bjs_Animal_init(typeId, typeBytes.length); const structValue = structHelpers.Animal.lift(); diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js index d9df868ec..40705f53d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftClosureImports.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -73,6 +90,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js index abfb24d48..556f3f5d2 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStruct.js @@ -24,6 +24,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -39,9 +56,8 @@ export async function createInstantiator(options, swift) { lower: (value) => { f64Stack.push(value.x); f64Stack.push(value.y); - const bytes = textEncoder.encode(value.label); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(value.label); + i32Stack.push(_maxUTF8Len(value.label)); i32Stack.push(id); const isSome = value.optCount != null ? 1 : 0; if (isSome) { @@ -79,13 +95,11 @@ export async function createInstantiator(options, swift) { }); const __bjs_createAddressHelpers = () => ({ lower: (value) => { - const bytes = textEncoder.encode(value.street); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(value.street); + i32Stack.push(_maxUTF8Len(value.street)); i32Stack.push(id); - const bytes1 = textEncoder.encode(value.city); - const id1 = swift.memory.retain(bytes1); - i32Stack.push(bytes1.length); + const id1 = swift.memory.retain(value.city); + i32Stack.push(_maxUTF8Len(value.city)); i32Stack.push(id1); const isSome = value.zipCode != null ? 1 : 0; if (isSome) { @@ -109,17 +123,15 @@ export async function createInstantiator(options, swift) { }); const __bjs_createPersonHelpers = () => ({ lower: (value) => { - const bytes = textEncoder.encode(value.name); - const id = swift.memory.retain(bytes); - i32Stack.push(bytes.length); + const id = swift.memory.retain(value.name); + i32Stack.push(_maxUTF8Len(value.name)); i32Stack.push(id); i32Stack.push((value.age | 0)); structHelpers.Address.lower(value.address); const isSome = value.email != null ? 1 : 0; if (isSome) { - const bytes1 = textEncoder.encode(value.email); - const id1 = swift.memory.retain(bytes1); - i32Stack.push(bytes1.length); + const id1 = swift.memory.retain(value.email); + i32Stack.push(_maxUTF8Len(value.email)); i32Stack.push(id1); } i32Stack.push(isSome); @@ -260,6 +272,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } @@ -536,7 +555,7 @@ export async function createInstantiator(options, swift) { } constructor(name) { - const nameBytes = textEncoder.encode(name); + const nameBytes = _cachedEncode(name); const nameId = swift.memory.retain(nameBytes); const ret = instance.exports.bjs_Greeter_init(nameId, nameBytes.length); return Greeter.__construct(ret); @@ -554,7 +573,7 @@ export async function createInstantiator(options, swift) { return ret; } set name(value) { - const valueBytes = textEncoder.encode(value); + const valueBytes = _cachedEncode(value); const valueId = swift.memory.retain(valueBytes); instance.exports.bjs_Greeter_name_set(this.pointer, valueId, valueBytes.length); } @@ -600,7 +619,7 @@ export async function createInstantiator(options, swift) { Precision: PrecisionValues, DataPoint: { init: function(x, y, label, optCount, optFlag) { - const labelBytes = textEncoder.encode(label); + const labelBytes = _cachedEncode(label); const labelId = swift.memory.retain(labelBytes); const isSome = optCount != null; const isSome1 = optFlag != null; @@ -630,7 +649,7 @@ export async function createInstantiator(options, swift) { return ret; }, set defaultConfig(value) { - const valueBytes = textEncoder.encode(value); + const valueBytes = _cachedEncode(value); const valueId = swift.memory.retain(valueBytes); instance.exports.bjs_ConfigStruct_static_defaultConfig_set(valueId, valueBytes.length); }, diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js index d4f1160f3..bd4403e30 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftStructImports.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -59,6 +76,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.js index 4e0fd8341..ad26a6d9d 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/SwiftTypedClosureAccess.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -72,6 +89,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.js index b2c381a03..b1f8b1ead 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/Throws.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -47,6 +64,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js index ef81ef69e..85501dc5f 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/UnsafePointer.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -64,6 +81,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } diff --git a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.js b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.js index 97948b286..8f9313a43 100644 --- a/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.js +++ b/Plugins/BridgeJS/Tests/BridgeJSToolTests/__Snapshots__/BridgeJSLinkTests/VoidParameterVoidReturn.js @@ -19,6 +19,23 @@ export async function createInstantiator(options, swift) { let tmpRetOptionalFloat; let tmpRetOptionalDouble; let tmpRetOptionalHeapObject; + const _strEncCache = new Map(); + const _strEncCacheMax = 4096; + function _cachedEncode(str) { + let encoded = _strEncCache.get(str); + if (encoded) { + _strEncCache.delete(str); + _strEncCache.set(str, encoded); + return encoded; + } + encoded = textEncoder.encode(str); + if (_strEncCache.size >= _strEncCacheMax) { + _strEncCache.delete(_strEncCache.keys().next().value); + } + _strEncCache.set(str, encoded); + return encoded; + } + function _maxUTF8Len(str) { return str.length * 3; } let strStack = []; let i32Stack = []; let i64Stack = []; @@ -48,6 +65,13 @@ export async function createInstantiator(options, swift) { const bytes = new Uint8Array(memory.buffer, bytesPtr); bytes.set(source); } + bjs["swift_js_init_memory_from_string"] = function(sourceId, bytesPtr) { + const str = swift.memory.getObject(sourceId); + swift.memory.release(sourceId); + const target = new Uint8Array(memory.buffer, bytesPtr); + const result = textEncoder.encodeInto(str, target); + return result.written; + } bjs["swift_js_make_js_string"] = function(ptr, len) { return swift.memory.retain(decodeString(ptr, len)); } diff --git a/Plugins/PackageToJS/Templates/instantiate.js b/Plugins/PackageToJS/Templates/instantiate.js index 3dda6b28e..3cfe0b0f5 100644 --- a/Plugins/PackageToJS/Templates/instantiate.js +++ b/Plugins/PackageToJS/Templates/instantiate.js @@ -36,6 +36,7 @@ async function createInstantiator(options, swift) { importObject["bjs"] = { swift_js_return_string: unexpectedBjsCall, swift_js_init_memory: unexpectedBjsCall, + swift_js_init_memory_from_string: unexpectedBjsCall, swift_js_make_js_string: unexpectedBjsCall, swift_js_init_memory_with_result: unexpectedBjsCall, swift_js_throw: unexpectedBjsCall, diff --git a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift index 86a1aaf3f..578be4b6e 100644 --- a/Sources/JavaScriptKit/BridgeJSIntrinsics.swift +++ b/Sources/JavaScriptKit/BridgeJSIntrinsics.swift @@ -478,9 +478,14 @@ extension String: _BridgedSwiftStackType { } @_spi(BridgeJS) public static func bridgeJSStackPop() -> String { - let bytes = _swift_js_pop_i32() - let count = _swift_js_pop_i32() - return bridgeJSLiftParameter(bytes, count) + let sourceId = _swift_js_pop_i32() + let maxCount = _swift_js_pop_i32() + #if !arch(wasm32) + guard #available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *) else { _onlyAvailableOnWasm() } + #endif + return String(unsafeUninitializedCapacity: Int(maxCount)) { b in + Int(_swift_js_init_memory_from_string(sourceId, b.baseAddress.unsafelyUnwrapped)) + } } @_spi(BridgeJS) public consuming func bridgeJSLowerReturn() -> Void { @@ -917,6 +922,30 @@ private func _swift_js_init_memory_extern(_ sourceId: Int32, _ ptr: UnsafeMutabl _swift_js_init_memory_extern(sourceId, ptr) } +#if arch(wasm32) +@_extern(wasm, module: "bjs", name: "swift_js_init_memory_from_string") +private func _swift_js_init_memory_from_string_extern(_ sourceId: Int32, _ ptr: UnsafeMutablePointer) -> Int32 +#else +private func _swift_js_init_memory_from_string_extern( + _ sourceId: Int32, + _ ptr: UnsafeMutablePointer +) -> Int32 { + _onlyAvailableOnWasm() +} +#endif + +/// Encodes a JS string directly into WASM memory via `encodeInto()` and returns the actual byte count written. +/// +/// - Parameter sourceId: The object ID of the source JS string. +/// - Parameter ptr: The pointer to the WebAssembly memory to write into. +/// - Returns: The number of bytes actually written. +@_spi(BridgeJS) @inline(never) public func _swift_js_init_memory_from_string( + _ sourceId: Int32, + _ ptr: UnsafeMutablePointer +) -> Int32 { + _swift_js_init_memory_from_string_extern(sourceId, ptr) +} + #if arch(wasm32) @_extern(wasm, module: "bjs", name: "swift_js_push_string") private func _swift_js_push_string_extern(_ ptr: UnsafePointer?, _ len: Int32)