Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions Plugins/BridgeJS/Sources/BridgeJSLink/BridgeJSLink.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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) = [];",
Expand Down Expand Up @@ -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(
Expand Down
21 changes: 14 additions & 7 deletions Plugins/BridgeJS/Sources/BridgeJSLink/JSGlueGen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -53,6 +57,10 @@ final class JSGlueVariableScope {
reservedStorageToReturnOptionalHeapObject,
reservedTextEncoder,
reservedTextDecoder,
reservedCachedEncode,
reservedStrEncCache,
reservedStrEncCacheMax,
reservedMaxUTF8Len,
reservedStringStack,
reservedI32Stack,
reservedI64Stack,
Expand Down Expand Up @@ -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"]
}
Expand Down Expand Up @@ -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"]
}
Expand Down Expand Up @@ -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 []
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [];
Expand Down Expand Up @@ -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));
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [];
Expand Down Expand Up @@ -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));
}
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [];
Expand Down Expand Up @@ -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));
}
Expand Down Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [];
Expand Down Expand Up @@ -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));
}
Expand Down
Loading
Loading