[dart2wasm] Optimize Dart->JS string conversion by specializing for OneByteString vs TwoByteString

Change-Id: Ia143312dc694a10fdaa778a57631bc98d14d9c7d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/372484
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Ömer Ağacan <omersa@google.com>
This commit is contained in:
Martin Kustermann 2024-06-21 17:46:30 +00:00 committed by Commit Queue
parent ef59500e6f
commit 5e12a4a79b
2 changed files with 65 additions and 48 deletions

View file

@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:_internal' show patch;
import 'dart:_internal' show patch, unsafeCast;
import 'dart:_js_helper' show JS;
import 'dart:_string';
import 'dart:_wasm';
@ -10,23 +10,42 @@ import 'dart:_wasm';
@patch
@pragma('wasm:prefer-inline')
JSStringImpl jsStringFromDartString(String s) {
if (s is JSStringImpl) return s;
return JSStringImpl(JS<WasmExternRef>(r'''
if (s is OneByteString) {
return JSStringImpl(JS<WasmExternRef>(r'''
(s, length) => {
let result = '';
let index = 0;
while (index < length) {
let chunkLength = Math.min(length - index, 0xFFFF);
const array = new Array(chunkLength);
for (let i = 0; i < chunkLength; i++) {
array[i] = dartInstance.exports.$stringRead(s, index++);
}
result += String.fromCharCode(...array);
let result = '';
let index = 0;
while (index < length) {
let chunkLength = Math.min(length - index, 0xFFFF);
const array = new Array(chunkLength);
for (let i = 0; i < chunkLength; i++) {
array[i] = dartInstance.exports.$stringRead1(s, index++);
}
return result;
result += String.fromCharCode(...array);
}
return result;
}
''', jsObjectFromDartObject(s), s.length.toWasmI32()));
}
if (s is TwoByteString) {
return JSStringImpl(JS<WasmExternRef>(r'''
(s, length) => {
let result = '';
let index = 0;
while (index < length) {
let chunkLength = Math.min(length - index, 0xFFFF);
const array = new Array(chunkLength);
for (let i = 0; i < chunkLength; i++) {
array[i] = dartInstance.exports.$stringRead2(s, index++);
}
result += String.fromCharCode(...array);
}
return result;
}
''', jsObjectFromDartObject(s), s.length.toWasmI32()));
}
return unsafeCast<JSStringImpl>(s);
}
@patch
@ -40,15 +59,45 @@ String jsStringToDartString(JSStringImpl s) => JS<String>(r'''
if (range < 256) {
const dartString = dartInstance.exports.$stringAllocate1(length);
for (let i = 0; i < length; i++) {
dartInstance.exports.$stringWrite1(dartString, i, s.codePointAt(i));
dartInstance.exports.$stringWrite1(dartString, i, s.codePointAt(i));
}
return dartString;
} else {
const dartString = dartInstance.exports.$stringAllocate2(length);
for (let i = 0; i < length; i++) {
dartInstance.exports.$stringWrite2(dartString, i, s.charCodeAt(i));
dartInstance.exports.$stringWrite2(dartString, i, s.charCodeAt(i));
}
return dartString;
}
}
''', s.toExternRef, s.length.toWasmI32());
@pragma("wasm:export", "\$stringAllocate1")
OneByteString _stringAllocate1(WasmI32 length) {
return OneByteString.withLength(length.toIntSigned());
}
@pragma("wasm:export", "\$stringRead1")
WasmI32 _stringRead1(OneByteString string, WasmI32 index) {
return string.codeUnitAtUnchecked(index.toIntSigned()).toWasmI32();
}
@pragma("wasm:export", "\$stringWrite1")
void _stringWrite1(OneByteString string, WasmI32 index, WasmI32 codePoint) {
string.setUnchecked(index.toIntSigned(), codePoint.toIntSigned());
}
@pragma("wasm:export", "\$stringAllocate2")
TwoByteString _stringAllocate2(WasmI32 length) {
return TwoByteString.withLength(length.toIntSigned());
}
@pragma("wasm:export", "\$stringRead2")
WasmI32 _stringRead2(TwoByteString string, WasmI32 index) {
return string.codeUnitAtUnchecked(index.toIntSigned()).toWasmI32();
}
@pragma("wasm:export", "\$stringWrite2")
void _stringWrite2(TwoByteString string, WasmI32 index, WasmI32 codePoint) {
string.setUnchecked(index.toIntSigned(), codePoint.toIntSigned());
}

View file

@ -1638,35 +1638,3 @@ final class TwoByteString extends StringBase {
return offset + length;
}
}
// String accessors used to perform Dart<->JS string conversion
@pragma("wasm:export", "\$stringLength")
WasmI32 _stringLength(String string) {
return string.length.toWasmI32();
}
@pragma("wasm:export", "\$stringRead")
WasmI32 _stringRead(String string, WasmI32 index) {
return string.codeUnitAt(index.toIntSigned()).toWasmI32();
}
@pragma("wasm:export", "\$stringAllocate1")
OneByteString _stringAllocate1(WasmI32 length) {
return OneByteString.withLength(length.toIntSigned());
}
@pragma("wasm:export", "\$stringWrite1")
void _stringWrite1(OneByteString string, WasmI32 index, WasmI32 codePoint) {
string.setUnchecked(index.toIntSigned(), codePoint.toIntSigned());
}
@pragma("wasm:export", "\$stringAllocate2")
TwoByteString _stringAllocate2(WasmI32 length) {
return TwoByteString.withLength(length.toIntSigned());
}
@pragma("wasm:export", "\$stringWrite2")
void _stringWrite2(TwoByteString string, WasmI32 index, WasmI32 codePoint) {
string.setUnchecked(index.toIntSigned(), codePoint.toIntSigned());
}