[dart2wasm, standalone] Port dart:core patches except String
This replaces js-interop and `JS(...)` usages in patches for `dart:core` in the dart2wasm standalone target with explicit host imports. This still uses JS strings as a string implementation, so js-interop from `dart:core` hasn't been removed completely. Migrating strings will require additional changes - mainly to `dart:js_interop` itself, which we want to remove from the standalone target anyway. So, I believe it makes sense to migrate strings last. In most cases, these imports match the manual JavaScript we've used before. `StringBuffer`s are an exception here, the default platform implements them via string concatenation but some embedders might benefit from explicit string buffers. TEST=tests/corelib/** Change-Id: I1ea18ac30bac24b30e528b2c28d925fda886c988 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/491480 Reviewed-by: Martin Kustermann <kustermann@google.com> Commit-Queue: Martin Kustermann <kustermann@google.com> Reviewed-by: Slava Egorov <vegorov@google.com>
This commit is contained in:
committed by
dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent
73a2c6c9a7
commit
fe8f4cd369
@@ -1,9 +1,9 @@
|
||||
(module $module0
|
||||
(type $#Top (struct
|
||||
(field $field0 i32)))
|
||||
(type $JSExternWrapper (sub $#Top (struct
|
||||
(type $JSExternWrapper (sub $Object (struct
|
||||
(field $field0 i32)
|
||||
(field $_externRef externref))))
|
||||
(type $Object (struct
|
||||
(field $field0 i32)))
|
||||
(global $"\"Hello world\"" (mut (ref null $JSExternWrapper))
|
||||
(ref.null none))
|
||||
)
|
||||
@@ -424,6 +424,148 @@ String dart2wasmHtml(String title, String wasmPath, String mjsPath,
|
||||
const str = helperInstance.exports.stringFromCharCodeArray(chars, start, length);
|
||||
return str;
|
||||
},
|
||||
monotonicClockFrequency: () => 1_000_000,
|
||||
monotonicClockTicks: () => BigInt(Math.round(performance.now() * 1000)),
|
||||
weakRefCreate: (dartValue) => new WeakRef(dartValue),
|
||||
weakRefGet: (weakRef) => weakRef.deref() ?? null,
|
||||
expandoCreate: () => new WeakMap(),
|
||||
expandoGet: (expando, target, _hash) => expando.get(target) ?? null,
|
||||
expandoSet: (expando, target, _hash, value) => expando.set(target, value),
|
||||
finalizerCreate: (callback, firstParameter) => {
|
||||
return new FinalizationRegistry((heldValue) => {
|
||||
callback(heldValue, firstParameter);
|
||||
});
|
||||
},
|
||||
finalizerAttach: (finalizer, object, token, detachToken) => {
|
||||
if (detachToken) {
|
||||
finalizer.register(object, token, detachToken);
|
||||
} else {
|
||||
finalizer.register(object, token);
|
||||
}
|
||||
},
|
||||
finalizerDetach: (finalizer, detachToken) => finalizer.unregister(detachToken),
|
||||
baseUri: () => globalThis.location.href,
|
||||
isWindows: () => false,
|
||||
stackTraceGetCurrent: () => new Error().stack,
|
||||
stackTraceToString: (trace) => {
|
||||
const stackString = trace.toString();
|
||||
const frames = stackString.split('\\n');
|
||||
// Format of stack traces is:
|
||||
// 1. stackTraceGetCurrent (from this embedder object)
|
||||
// 2. module0.StackTrace.current <noInline>
|
||||
// 3. The callsite we care about.
|
||||
const drop = 1 + frames.findIndex((l) => l.indexOf('stackTraceGetCurrent') > 0);
|
||||
return frames.slice(drop).join('\\n');
|
||||
},
|
||||
doubleTryParse: (source) => {
|
||||
if (!/${r'^\s*[+-]?(?:Infinity|NaN|(?:\.\d+|\d+(?:\.\d*)?)(?:[eE][+-]?\d+)?)\s*$'}/.test(source)) {
|
||||
const trimmed = source.trim();
|
||||
// parseFloat is more lenient than double.tryParse, see wasm/lib/double_patch.dart for details.
|
||||
if (!(trimmed == 'NaN' || trimmed == '+NaN' || trimmed == '-NaN')) {
|
||||
return null;
|
||||
}
|
||||
return { result: NaN };
|
||||
} else {
|
||||
return { result: parseFloat(source) };
|
||||
}
|
||||
},
|
||||
tryParseResultGetDouble: ({result}) => result,
|
||||
i64ToString: (source, radix) => source.toString(radix),
|
||||
f64ToExponential: (source) => source.toExponential(),
|
||||
f64ToExponentialWithFractionDigits: (source, digits) => {
|
||||
return source.toExponential(digits);
|
||||
},
|
||||
f64ToPrecision: (source, digits) => source.toPrecision(digits),
|
||||
f64ToFixed: (source, digits) => source.toFixed(digits),
|
||||
f64ToString: (source) => {
|
||||
if (Object.is(source, -0)) return '-0.0';
|
||||
if (Number.isNaN(source)) return 'NaN';
|
||||
if (source == Number.NEGATIVE_INFINITY) return '-Infinity';
|
||||
if (source == Number.POSITIVE_INFINITY) return 'Infinity';
|
||||
|
||||
let formatted = source.toString();
|
||||
if (source % 1.0 == 0 && formatted.indexOf('e') == -1) {
|
||||
formatted += '.0';
|
||||
}
|
||||
return formatted;
|
||||
},
|
||||
stringBufferCreate: () => ({ contents: '' }),
|
||||
stringBufferWriteString: (buffer, append) => {
|
||||
buffer.contents += append;
|
||||
},
|
||||
stringBufferWriteCharCode: (buffer, code) => {
|
||||
buffer.contents += String.fromCodePoint(code);
|
||||
},
|
||||
stringBufferClear: (buffer) => {
|
||||
buffer.contents = ''
|
||||
},
|
||||
stringBufferLength: (buffer) => buffer.contents.length,
|
||||
stringBufferToString: ({contents}) => contents,
|
||||
regexpCreateOrFailWithString: (pattern, multiLine, caseSensitive, unicode, dotAll) => {
|
||||
let flags = '';
|
||||
if (multiLine) flags += 'm';
|
||||
if (!caseSensitive) flags += 'i';
|
||||
if (unicode) flags += 'u';
|
||||
if (dotAll) flags += 's';
|
||||
|
||||
try {
|
||||
// Prepare two regular expressions, one for regular matches and one
|
||||
// for matchAsPrefix.
|
||||
return {
|
||||
regular: new RegExp(pattern, flags + 'g'),
|
||||
asPrefix: new RegExp(pattern, flags + 'y'),
|
||||
};
|
||||
} catch (e) {
|
||||
return String(e);
|
||||
}
|
||||
},
|
||||
regexpIsRegexp: (source) => typeof(source) !== 'string',
|
||||
regexpEscape: (source) => {
|
||||
// Note: We can't use RegExp.escape here, it escapes too much and we
|
||||
// have tests expecting that e.g. \t isn't escaped.
|
||||
if (/${r'[[\]{}()*+?.\\^$|]'}/.test(source)) {
|
||||
return source.replace(/${r'[[\]{}()*+?.\\^$|]'}/g, "${r'\\$&'}");
|
||||
} else {
|
||||
return source;
|
||||
}
|
||||
},
|
||||
regexpMatch: (regexp, string, start, asPrefix) => {
|
||||
const regex = asPrefix ? regexp.asPrefix : regexp.regular;
|
||||
regex.lastIndex = start;
|
||||
const match = regex.exec(string);
|
||||
if (match) {
|
||||
return {
|
||||
start: match.index,
|
||||
end: match.index + match[0].length,
|
||||
groupNames: match.groups ? Object.keys(match.groups) : [],
|
||||
groups: match,
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
regexpMatchGetStart: (match) => match.start,
|
||||
regexpMatchGetEnd: (match) => match.end,
|
||||
regexpMatchGetGroupCount: (match) => match.groups.length - 1,
|
||||
regexpMatchGetGroup: (match, index) => match.groups[index] ?? null,
|
||||
regexpMatchGetNamedGroups: (match) => match.groupNames.length,
|
||||
regexpMatchGetGroupName: (match, index) => match.groupNames[index],
|
||||
regexpMatchGetGroupByName: (match, index) => match.groups.groups[match.groupNames[index]] ?? null,
|
||||
timeZoneNameForClampedSeconds: (secondsSinceEpoch) => {
|
||||
const date = new Date(Number(secondsSinceEpoch * 1000n));
|
||||
const match = /\\((.*)\\)/.exec(date.toString());
|
||||
if (match == null) {
|
||||
// This should never happen on any recent browser.
|
||||
return '';
|
||||
}
|
||||
return match[1];
|
||||
},
|
||||
timeZoneOffsetInSecondsForClampedSeconds: (secondsSinceEpoch) => {
|
||||
const date = new Date(Number(secondsSinceEpoch * 1000n));
|
||||
// This needs to be negated because Dart wants the difference between
|
||||
// local time and UTC.
|
||||
return -date.getTimezoneOffset() * 60;
|
||||
},
|
||||
};
|
||||
""";
|
||||
final additionalImports = standalone ? '{ dart: dartEmbedder }' : '{}';
|
||||
|
||||
@@ -225,23 +225,6 @@ class LateError {
|
||||
}
|
||||
}
|
||||
|
||||
void checkValidWeakTarget(object, name) {
|
||||
if ((object == null) ||
|
||||
(object is bool) ||
|
||||
(object is num) ||
|
||||
(object is String) ||
|
||||
(object is Record) ||
|
||||
(object is Pointer) ||
|
||||
(object is Struct) ||
|
||||
(object is Union)) {
|
||||
throw ArgumentError.value(
|
||||
object,
|
||||
name,
|
||||
"Cannot be a string, number, boolean, record, null, Pointer, Struct or Union",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@pragma("vm:entry-point")
|
||||
class FinalizerBase {
|
||||
/// The list of finalizers of this isolate.
|
||||
|
||||
@@ -31,60 +31,4 @@ class _Uri {
|
||||
|
||||
@patch
|
||||
static bool get _isWindows => _isWindowsCached;
|
||||
|
||||
@patch
|
||||
static String _uriEncode(
|
||||
int canonicalMask,
|
||||
String text,
|
||||
Encoding encoding,
|
||||
bool spaceToPlus,
|
||||
) {
|
||||
// First check if the text will be changed by encoding.
|
||||
int i = 0;
|
||||
if (identical(encoding, utf8) ||
|
||||
identical(encoding, latin1) ||
|
||||
identical(encoding, ascii)) {
|
||||
// Encoding is compatible with the original string.
|
||||
// Find first character that needs encoding.
|
||||
for (; i < text.length; i++) {
|
||||
var char = text.codeUnitAt(i);
|
||||
if (char >= 128 || _charTables.codeUnitAt(char) & canonicalMask == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i == text.length) return text;
|
||||
|
||||
// Encode the string into bytes then generate an ASCII only string
|
||||
// by percent encoding selected bytes.
|
||||
StringBuffer result = StringBuffer();
|
||||
for (int j = 0; j < i; j++) {
|
||||
result.writeCharCode(text.codeUnitAt(j));
|
||||
}
|
||||
|
||||
// TODO(lrn): Is there a way to only encode from index i and forwards.
|
||||
var bytes = encoding.encode(text);
|
||||
for (; i < bytes.length; i++) {
|
||||
int byte = bytes[i];
|
||||
if (byte < 128 && ((_charTables.codeUnitAt(byte) & canonicalMask) != 0)) {
|
||||
result.writeCharCode(byte);
|
||||
} else if (spaceToPlus && byte == _SPACE) {
|
||||
result.writeCharCode(_PLUS);
|
||||
} else {
|
||||
const String hexDigits = '0123456789ABCDEF';
|
||||
result
|
||||
..writeCharCode(_PERCENT)
|
||||
..writeCharCode(hexDigits.codeUnitAt(byte >> 4))
|
||||
..writeCharCode(hexDigits.codeUnitAt(byte & 0x0f));
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
@patch
|
||||
static String _makeQueryFromParameters(
|
||||
Map<String, dynamic /*String?|Iterable<String>*/> queryParameters,
|
||||
) {
|
||||
return _makeQueryFromParametersDefault(queryParameters);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
|
||||
// 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:ffi' show Pointer, Struct, Union;
|
||||
|
||||
void checkValidWeakTarget(object, name) {
|
||||
if ((object == null) ||
|
||||
(object is bool) ||
|
||||
(object is num) ||
|
||||
(object is String) ||
|
||||
(object is Record) ||
|
||||
(object is Pointer) ||
|
||||
(object is Struct) ||
|
||||
(object is Union)) {
|
||||
throw ArgumentError.value(
|
||||
object,
|
||||
name,
|
||||
"Cannot be a string, number, boolean, record, null, Pointer, Struct or Union",
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
|
||||
// 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:convert' show Encoding, utf8, latin1, ascii;
|
||||
|
||||
@patch
|
||||
class _Uri {
|
||||
@patch
|
||||
static String _uriEncode(
|
||||
int canonicalMask,
|
||||
String text,
|
||||
Encoding encoding,
|
||||
bool spaceToPlus,
|
||||
) {
|
||||
// First check if the text will be changed by encoding.
|
||||
int i = 0;
|
||||
if (identical(encoding, utf8) ||
|
||||
identical(encoding, latin1) ||
|
||||
identical(encoding, ascii)) {
|
||||
// Encoding is compatible with the original string.
|
||||
// Find first character that needs encoding.
|
||||
for (; i < text.length; i++) {
|
||||
var char = text.codeUnitAt(i);
|
||||
if (char >= 128 || _charTables.codeUnitAt(char) & canonicalMask == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i == text.length) return text;
|
||||
|
||||
// Encode the string into bytes then generate an ASCII only string
|
||||
// by percent encoding selected bytes.
|
||||
StringBuffer result = StringBuffer();
|
||||
for (int j = 0; j < i; j++) {
|
||||
result.writeCharCode(text.codeUnitAt(j));
|
||||
}
|
||||
|
||||
// TODO(lrn): Is there a way to only encode from index i and forwards.
|
||||
var bytes = encoding.encode(text);
|
||||
for (; i < bytes.length; i++) {
|
||||
int byte = bytes[i];
|
||||
if (byte < 128 && ((_charTables.codeUnitAt(byte) & canonicalMask) != 0)) {
|
||||
result.writeCharCode(byte);
|
||||
} else if (spaceToPlus && byte == _SPACE) {
|
||||
result.writeCharCode(_PLUS);
|
||||
} else {
|
||||
const String hexDigits = '0123456789ABCDEF';
|
||||
result
|
||||
..writeCharCode(_PERCENT)
|
||||
..writeCharCode(hexDigits.codeUnitAt(byte >> 4))
|
||||
..writeCharCode(hexDigits.codeUnitAt(byte & 0x0f));
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
@patch
|
||||
static String _makeQueryFromParameters(
|
||||
Map<String, dynamic /*String?|Iterable<String>*/> queryParameters,
|
||||
) {
|
||||
return _makeQueryFromParametersDefault(queryParameters);
|
||||
}
|
||||
}
|
||||
@@ -313,23 +313,6 @@ final class BoxedDouble implements double {
|
||||
return this;
|
||||
}
|
||||
|
||||
static const int CACHE_SIZE_LOG2 = 3;
|
||||
static const int CACHE_LENGTH = 1 << (CACHE_SIZE_LOG2 + 1);
|
||||
static const int CACHE_MASK = CACHE_LENGTH - 1;
|
||||
// Each cached double value, represented as it's 64-bits.
|
||||
@pragma("wasm:initialize-at-startup")
|
||||
static final WasmArray<int> _cacheKeys = WasmArray<int>.filled(
|
||||
CACHE_LENGTH,
|
||||
doubleToIntBits(1.0),
|
||||
);
|
||||
// The toString() of the double value with same index in [_cacheKeys].
|
||||
@pragma("wasm:initialize-at-startup")
|
||||
static final WasmArray<String> _cacheValues = WasmArray<String>.filled(
|
||||
CACHE_LENGTH,
|
||||
'1.0',
|
||||
);
|
||||
static int _cacheEvictIndex = 0;
|
||||
|
||||
external String toString();
|
||||
|
||||
external toStringAsFixed(int fractionDigits);
|
||||
|
||||
@@ -8,6 +8,23 @@ import 'dart:_string';
|
||||
|
||||
@patch
|
||||
class BoxedDouble {
|
||||
static const int CACHE_SIZE_LOG2 = 3;
|
||||
static const int CACHE_LENGTH = 1 << (CACHE_SIZE_LOG2 + 1);
|
||||
static const int CACHE_MASK = CACHE_LENGTH - 1;
|
||||
// Each cached double value, represented as it's 64-bits.
|
||||
@pragma("wasm:initialize-at-startup")
|
||||
static final WasmArray<int> _cacheKeys = WasmArray<int>.filled(
|
||||
CACHE_LENGTH,
|
||||
doubleToIntBits(1.0),
|
||||
);
|
||||
// The toString() of the double value with same index in [_cacheKeys].
|
||||
@pragma("wasm:initialize-at-startup")
|
||||
static final WasmArray<String> _cacheValues = WasmArray<String>.filled(
|
||||
CACHE_LENGTH,
|
||||
'1.0',
|
||||
);
|
||||
static int _cacheEvictIndex = 0;
|
||||
|
||||
@patch
|
||||
String toString() {
|
||||
final int bits = doubleToIntBits(value);
|
||||
|
||||
@@ -2,28 +2,11 @@
|
||||
// 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, unsafeCast;
|
||||
import 'dart:_internal' show patch, unsafeCast, checkValidWeakTarget;
|
||||
import 'dart:_js_helper' show isJSUndefined, JS;
|
||||
import 'dart:_wasm';
|
||||
import 'dart:js_interop' hide JS;
|
||||
import 'dart:js_interop' as js_interop;
|
||||
import 'dart:ffi' show Pointer, Struct, Union;
|
||||
|
||||
void _checkValidWeakTarget(Object object) {
|
||||
if ((object is bool) ||
|
||||
(object is num) ||
|
||||
(object is String) ||
|
||||
(object is Record) ||
|
||||
(object is Pointer) ||
|
||||
(object is Struct) ||
|
||||
(object is Union)) {
|
||||
throw ArgumentError.value(
|
||||
object,
|
||||
"A string, number, boolean, record, Pointer, Struct or Union "
|
||||
"can't be a weak target",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@patch
|
||||
class Expando<T extends Object> {
|
||||
@@ -36,7 +19,7 @@ class Expando<T extends Object> {
|
||||
|
||||
@patch
|
||||
T? operator [](Object object) {
|
||||
_checkValidWeakTarget(object);
|
||||
checkValidWeakTarget(object, 'object');
|
||||
final result = JS<WasmExternRef?>(
|
||||
"(map, o) => map.get(o)",
|
||||
_jsWeakMap,
|
||||
@@ -49,7 +32,7 @@ class Expando<T extends Object> {
|
||||
|
||||
@patch
|
||||
void operator []=(Object object, T? value) {
|
||||
_checkValidWeakTarget(object);
|
||||
checkValidWeakTarget(object, 'object');
|
||||
JS<void>(
|
||||
"(map, o, v) => map.set(o, v)",
|
||||
_jsWeakMap,
|
||||
@@ -74,7 +57,7 @@ class WeakReference<T extends Object> {
|
||||
@patch
|
||||
factory WeakReference(T target) {
|
||||
if (_supportsWeakRef) {
|
||||
_checkValidWeakTarget(target);
|
||||
checkValidWeakTarget(target, 'target');
|
||||
return _WeakReferenceWrapper<T>(target);
|
||||
}
|
||||
// The polyfill does not validate [target]. This lets the tests distinguish
|
||||
@@ -153,9 +136,9 @@ class _FinalizationRegistryWrapper<T> implements Finalizer<T> {
|
||||
);
|
||||
|
||||
void attach(Object value, T peer, {Object? detach}) {
|
||||
_checkValidWeakTarget(value);
|
||||
checkValidWeakTarget(value, 'value');
|
||||
if (detach != null) {
|
||||
_checkValidWeakTarget(detach);
|
||||
checkValidWeakTarget(detach, 'detach');
|
||||
_jsFinalizationRegistry.registerWithDetach(
|
||||
value.toExternalReference,
|
||||
peer.toExternalReference,
|
||||
@@ -170,7 +153,7 @@ class _FinalizationRegistryWrapper<T> implements Finalizer<T> {
|
||||
}
|
||||
|
||||
void detach(Object detach) {
|
||||
_checkValidWeakTarget(detach);
|
||||
checkValidWeakTarget(detach, 'detach');
|
||||
_jsFinalizationRegistry.unregister(detach.toExternalReference);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
|
||||
// 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:_embedder' as embedder;
|
||||
import "dart:_internal" show doubleToIntBits, intBitsToDouble, patch;
|
||||
import 'dart:_string';
|
||||
import 'dart:_wasm';
|
||||
|
||||
@patch
|
||||
class BoxedDouble {
|
||||
@patch
|
||||
String toString() {
|
||||
return JSStringImpl.fromRefUnchecked(
|
||||
embedder.f64ToString(WasmF64.fromDouble(value)),
|
||||
);
|
||||
}
|
||||
|
||||
@patch
|
||||
String toStringAsFixed(int fractionDigits) {
|
||||
// See ECMAScript-262, 15.7.4.5 for details.
|
||||
|
||||
// Step 2.
|
||||
// 0 <= fractionDigits <= 20
|
||||
RangeErrorUtils.checkValueBetweenZeroAndPositiveMax(
|
||||
fractionDigits,
|
||||
20,
|
||||
"fractionDigits",
|
||||
);
|
||||
|
||||
// Step 3.
|
||||
double x = this;
|
||||
|
||||
// Step 4.
|
||||
if (isNaN) return "NaN";
|
||||
if (this == double.infinity) return "Infinity";
|
||||
if (this == -double.infinity) return "-Infinity";
|
||||
|
||||
// Step 5 and 6 skipped. Will be dealt with by native function.
|
||||
|
||||
// Step 7.
|
||||
if (x >= 1e21 || x <= -1e21) {
|
||||
return x.toString();
|
||||
}
|
||||
|
||||
String result = _toStringAsFixed(fractionDigits);
|
||||
if (this == 0 && isNegative) return '-$result';
|
||||
return result;
|
||||
}
|
||||
|
||||
String _toStringAsFixed(int fractionDigits) => JSStringImpl.fromRefUnchecked(
|
||||
embedder.f64ToFixed(
|
||||
WasmF64.fromDouble(this),
|
||||
WasmI32.fromInt(fractionDigits),
|
||||
),
|
||||
);
|
||||
|
||||
@patch
|
||||
String toStringAsExponential([int? fractionDigits]) {
|
||||
// See ECMAScript-262, 15.7.4.6 for details.
|
||||
|
||||
// The EcmaScript specification checks for NaN and Infinity before looking
|
||||
// at the fractionDigits. In Dart we are consistent with toStringAsFixed and
|
||||
// look at the fractionDigits first.
|
||||
|
||||
// Step 7.
|
||||
if (fractionDigits != null) {
|
||||
// 0 <= fractionDigits <= 20
|
||||
RangeErrorUtils.checkValueBetweenZeroAndPositiveMax(
|
||||
fractionDigits,
|
||||
20,
|
||||
"fractionDigits",
|
||||
);
|
||||
}
|
||||
|
||||
if (isNaN) return "NaN";
|
||||
if (this == double.infinity) return "Infinity";
|
||||
if (this == -double.infinity) return "-Infinity";
|
||||
|
||||
String result = _toStringAsExponential(fractionDigits);
|
||||
if (this == 0 && isNegative) return '-$result';
|
||||
return result;
|
||||
}
|
||||
|
||||
String _toStringAsExponential(int? fractionDigits) =>
|
||||
JSStringImpl.fromRefUnchecked(
|
||||
fractionDigits == null
|
||||
? embedder.f64ToExponential(WasmF64.fromDouble(this))
|
||||
: embedder.f64ToExponentialWithFractionDigits(
|
||||
WasmF64.fromDouble(this),
|
||||
WasmI32.fromInt(fractionDigits),
|
||||
),
|
||||
);
|
||||
|
||||
@patch
|
||||
String toStringAsPrecision(int precision) {
|
||||
// See ECMAScript-262, 15.7.4.7 for details.
|
||||
|
||||
// The EcmaScript specification checks for NaN and Infinity before looking
|
||||
// at the fractionDigits. In Dart we are consistent with toStringAsFixed and
|
||||
// look at the fractionDigits first.
|
||||
|
||||
// Step 8.
|
||||
RangeErrorUtils.checkValueInInterval(precision, 1, 21, "precision");
|
||||
|
||||
if (isNaN) return "NaN";
|
||||
if (this == double.infinity) return "Infinity";
|
||||
if (this == -double.infinity) return "-Infinity";
|
||||
|
||||
String result = _toStringAsPrecision(precision);
|
||||
if (this == 0 && isNegative) return '-$result';
|
||||
return result;
|
||||
}
|
||||
|
||||
String _toStringAsPrecision(int fractionDigits) =>
|
||||
JSStringImpl.fromRefUnchecked(
|
||||
embedder.f64ToPrecision(
|
||||
WasmF64.fromDouble(this),
|
||||
WasmI32.fromInt(fractionDigits),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
|
||||
// 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:_embedder' show i64ToString;
|
||||
import 'dart:_error_utils';
|
||||
import 'dart:_internal';
|
||||
import 'dart:_string';
|
||||
import 'dart:_wasm';
|
||||
|
||||
@patch
|
||||
class BoxedInt {
|
||||
@patch
|
||||
String toRadixString(int radix) {
|
||||
RangeErrorUtils.checkValueInInterval(radix, 2, 36, "radix");
|
||||
return _intToString(this, radix);
|
||||
}
|
||||
|
||||
@patch
|
||||
String toString() => _intToString(this, 10);
|
||||
}
|
||||
|
||||
String _intToString(int value, int radix) {
|
||||
return JSStringImpl.fromRefUnchecked(
|
||||
i64ToString(WasmI64.fromInt(value), WasmI32.fromInt(radix)),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
|
||||
// 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:_embedder';
|
||||
import "dart:_internal" show patch;
|
||||
import 'dart:_string';
|
||||
import 'dart:_wasm';
|
||||
|
||||
@patch
|
||||
class DateTime {
|
||||
@patch
|
||||
static int _getCurrentMicros() => currentTimeMicros().toInt();
|
||||
|
||||
@patch
|
||||
static String _timeZoneNameForClampedSeconds(int secondsSinceEpoch) =>
|
||||
JSStringImpl.fromRefUnchecked(
|
||||
timeZoneNameForClampedSeconds(WasmI64.fromInt(secondsSinceEpoch)),
|
||||
);
|
||||
|
||||
// In Dart, the offset is the difference between local time and UTC,
|
||||
// while in JS, the offset is the difference between UTC and local time.
|
||||
// As a result, the signs are opposite, so we negate the value returned by JS.
|
||||
@patch
|
||||
static int _timeZoneOffsetInSecondsForClampedSeconds(int secondsSinceEpoch) =>
|
||||
timeZoneOffsetInSecondsForClampedSeconds(
|
||||
WasmI64.fromInt(secondsSinceEpoch),
|
||||
).toIntSigned();
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
|
||||
// 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:_embedder';
|
||||
import 'dart:_internal' show patch;
|
||||
import 'dart:_js_helper';
|
||||
import 'dart:_wasm';
|
||||
|
||||
@patch
|
||||
class double {
|
||||
@patch
|
||||
static double parse(String source) {
|
||||
double? result = tryParse(source);
|
||||
if (result == null) {
|
||||
throw FormatException('Invalid double $source');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@patch
|
||||
static double? tryParse(String source) {
|
||||
final parseResult = doubleTryParse(
|
||||
jsStringFromDartString(source).wrappedExternRef,
|
||||
);
|
||||
if (parseResult.isNull) {
|
||||
return null;
|
||||
} else {
|
||||
return tryParseResultGetDouble(parseResult).toDouble();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,3 +73,263 @@ external WasmExternRef stringFromAsciiBytes(
|
||||
WasmI32 start,
|
||||
WasmI32 length,
|
||||
);
|
||||
|
||||
/// Get the frequency of ticks reported by [monotonicClockTicks] in Hz.
|
||||
///
|
||||
/// Currently, the only supported values are 1kHz and 1MHz. Attempting to use
|
||||
/// a stopwatch in Dart will fail if the function returns an unsupported value.
|
||||
///
|
||||
/// This function must return the same value every time it is called.
|
||||
@pragma("wasm:import", "dart.monotonicClockFrequency")
|
||||
external WasmI32 monotonicClockFrequency();
|
||||
|
||||
/// An integer incrementing with [monotonicClockFrequency].
|
||||
@pragma("wasm:import", "dart.monotonicClockTicks")
|
||||
external WasmI64 monotonicClockTicks();
|
||||
|
||||
/// Creates a weak reference wrapping [originalValue].
|
||||
///
|
||||
/// The SDK verifies that [originalValue] is a valid target (not a number,
|
||||
/// boolean, string, record or FFI type) before calling this.
|
||||
@pragma("wasm:import", "dart.weakRefCreate")
|
||||
external WasmExternRef weakRefCreate(WasmAnyRef originalValue);
|
||||
|
||||
/// Returns the value wrapped in [weakRefCreate], or null.
|
||||
@pragma("wasm:import", "dart.weakRefGet")
|
||||
external WasmAnyRef? weakRefGet(WasmExternRef? weakReference);
|
||||
|
||||
/// Creates a new [Expando].
|
||||
@pragma("wasm:import", "dart.expandoCreate")
|
||||
external WasmExternRef expandoCreate();
|
||||
|
||||
/// Lookup a value stored on [target] with [expandoSet].
|
||||
///
|
||||
/// The SDK verifies that [target] is a valid target before calling this.
|
||||
@pragma("wasm:import", "dart.expandoGet")
|
||||
external WasmAnyRef? expandoGet(
|
||||
WasmExternRef? expando,
|
||||
WasmAnyRef target,
|
||||
WasmI64 targetIdentityHashCode,
|
||||
);
|
||||
|
||||
/// Associates the [value] with the [target] object in the expando.
|
||||
///
|
||||
/// The SDK verifies that [target] is a valid target before calling this.
|
||||
@pragma("wasm:import", "dart.expandoSet")
|
||||
external WasmVoid expandoSet(
|
||||
WasmExternRef? expando,
|
||||
WasmAnyRef target,
|
||||
WasmI64 targetIdentityHashCode,
|
||||
WasmAnyRef? value,
|
||||
);
|
||||
|
||||
/// Creates a native finalizer that may invoke the [callback] with the
|
||||
/// [firstParameter] and a second token when a registered object becomes
|
||||
/// unreachable.
|
||||
@pragma("wasm:import", "dart.finalizerCreate")
|
||||
external WasmExternRef finalizerCreate(
|
||||
WasmFunction<WasmVoid Function(WasmAnyRef, WasmAnyRef?)> callback,
|
||||
WasmAnyRef firstParameter,
|
||||
);
|
||||
|
||||
/// Attaches an object to a finalizer.
|
||||
///
|
||||
/// After [object] becomes unreachable, the `callback` passed to
|
||||
/// [finalizerCreate] may be invoked with [token] as a second parameter.
|
||||
///
|
||||
/// If [detachToken] is non-null, it can later be passed to [finalizerDetach] to
|
||||
/// remove the [object] from the finalizer.
|
||||
@pragma("wasm:import", "dart.finalizerAttach")
|
||||
external WasmVoid finalizerAttach(
|
||||
WasmExternRef? finalizer,
|
||||
WasmAnyRef object,
|
||||
WasmAnyRef? token,
|
||||
WasmAnyRef? detachToken,
|
||||
);
|
||||
|
||||
@pragma("wasm:import", "dart.finalizerDetach")
|
||||
external WasmVoid finalizerDetach(
|
||||
WasmExternRef? finalizer,
|
||||
WasmAnyRef detachToken,
|
||||
);
|
||||
|
||||
/// Returns the string value for [Uri.base], or null if no base URI exists.
|
||||
@pragma("wasm:import", "dart.baseUri")
|
||||
external WasmExternRef? baseUri();
|
||||
|
||||
/// Returns `1` if running on Windows, `0` otherwise.
|
||||
@pragma("wasm:import", "dart.isWindows")
|
||||
external WasmI32 isWindows();
|
||||
|
||||
/// Creates a stack trace object from the current call stack.
|
||||
///
|
||||
/// This backs [StackTrace.current], so implementations should hide calls to
|
||||
/// this extern from the created stack trace.
|
||||
@pragma("wasm:import", "dart.stackTraceGetCurrent")
|
||||
external WasmExternRef stackTraceGetCurrent();
|
||||
|
||||
/// Renders a stack trace returned by [stackTraceGetCurrent] as a string.
|
||||
@pragma("wasm:import", "dart.stackTraceToString")
|
||||
external WasmExternRef stackTraceToString(WasmExternRef? trace);
|
||||
|
||||
/// Attempts to parse a string as a double, following semantics described in
|
||||
/// [double.parse].
|
||||
///
|
||||
/// If the string can't be parsed as a double, return null. Otherwise, returns a
|
||||
/// structure that can be used by [tryParseResultGetDouble] to extract the
|
||||
/// parsed double.
|
||||
@pragma("wasm:import", "dart.doubleTryParse")
|
||||
external WasmExternRef? doubleTryParse(WasmExternRef? string);
|
||||
|
||||
/// Extracts the double parsed from [doubleTryParse] returning a non-nullable
|
||||
/// value.
|
||||
@pragma("wasm:import", "dart.tryParseResultGetDouble")
|
||||
external WasmF64 tryParseResultGetDouble(WasmExternRef? parseResult);
|
||||
|
||||
/// The implementation of [int.toRadixString].
|
||||
///
|
||||
/// The SDK will only call this with radix values between 2 and 36 (inclusive).
|
||||
@pragma("wasm:import", "dart.i64ToString")
|
||||
external WasmExternRef i64ToString(WasmI64 value, WasmI32 radix);
|
||||
|
||||
/// This and [f64ToExponentialWithFractionDigits] must behave exactly as
|
||||
/// `Number.prototype.toExponential` in JavaScript.
|
||||
@pragma("wasm:import", "dart.f64ToExponential")
|
||||
external WasmExternRef f64ToExponential(WasmF64 value);
|
||||
|
||||
@pragma("wasm:import", "dart.f64ToExponentialWithFractionDigits")
|
||||
external WasmExternRef f64ToExponentialWithFractionDigits(
|
||||
WasmF64 value,
|
||||
WasmI32 fractionDigits,
|
||||
);
|
||||
|
||||
/// Must behave exactly as `Number.prototype.toPrecision` in JavaScript.
|
||||
@pragma("wasm:import", "dart.f64ToPrecision")
|
||||
external WasmExternRef f64ToPrecision(WasmF64 value, WasmI32 fractionDigits);
|
||||
|
||||
/// Must behave exactly as `Number.prototype.toFixed` in JavaScript.
|
||||
@pragma("wasm:import", "dart.f64ToFixed")
|
||||
external WasmExternRef f64ToFixed(WasmF64 value, WasmI32 fractionDigits);
|
||||
|
||||
/// Implements [double.toString].
|
||||
@pragma("wasm:import", "dart.f64ToString")
|
||||
external WasmExternRef f64ToString(WasmF64 value);
|
||||
|
||||
/// Creates a string buffer object.
|
||||
@pragma("wasm:import", "dart.stringBufferCreate")
|
||||
external WasmExternRef stringBufferCreate();
|
||||
|
||||
/// Appends a string to a string buffer.
|
||||
@pragma("wasm:import", "dart.stringBufferWriteString")
|
||||
external WasmVoid stringBufferWriteString(
|
||||
WasmExternRef? buffer,
|
||||
WasmExternRef? string,
|
||||
);
|
||||
|
||||
/// Appends a string containing the character with the [code] point to a string
|
||||
/// buffer.
|
||||
@pragma("wasm:import", "dart.stringBufferWriteCharCode")
|
||||
external WasmVoid stringBufferWriteCharCode(
|
||||
WasmExternRef? buffer,
|
||||
WasmI32 code,
|
||||
);
|
||||
|
||||
/// Clears the contents of a string buffer.
|
||||
@pragma("wasm:import", "dart.stringBufferClear")
|
||||
external WasmVoid stringBufferClear(WasmExternRef? buffer);
|
||||
|
||||
/// The current length of a string in a string buffer.
|
||||
@pragma("wasm:import", "dart.stringBufferLength")
|
||||
external WasmI32 stringBufferLength(WasmExternRef? buffer);
|
||||
|
||||
/// Turn a string buffer into a string.
|
||||
@pragma("wasm:import", "dart.stringBufferToString")
|
||||
external WasmExternRef stringBufferToString(WasmExternRef? buffer);
|
||||
|
||||
/// Attempts to parse the `string` as a regular expression with the given
|
||||
/// options.
|
||||
///
|
||||
/// Returns a regular expression object if that succeeds, or an error message as
|
||||
/// a string otherwise.
|
||||
@pragma("wasm:import", "dart.regexpCreateOrFailWithString")
|
||||
external WasmExternRef regexpCreateOrFailWithString(
|
||||
WasmExternRef? string,
|
||||
WasmI32 multiLine,
|
||||
WasmI32 caseSensitive,
|
||||
WasmI32 unicode,
|
||||
WasmI32 dotAll,
|
||||
);
|
||||
|
||||
/// Called with the return value of [regexpCreateOrFailWithString], returns
|
||||
/// whether [ref] is a regular expression object.
|
||||
///
|
||||
/// If this returns `0`, the return value is interpreted as an error message
|
||||
/// string instead.
|
||||
@pragma("wasm:import", "dart.regexpIsRegexp")
|
||||
external WasmI32 regexpIsRegexp(WasmExternRef? ref);
|
||||
|
||||
/// Implementation of [RegExp.escape].
|
||||
@pragma("wasm:import", "dart.regexpEscape")
|
||||
external WasmExternRef regexpEscape(WasmExternRef? string);
|
||||
|
||||
/// If [asPrefix] is `0`, return the first match of [string] for [regexp] at or
|
||||
/// after [start] code units.
|
||||
///
|
||||
/// If [asPrefix] is `1`, only return the match if it starts exactly at [start].
|
||||
@pragma("wasm:import", "dart.regexpMatch")
|
||||
external WasmExternRef? regexpMatch(
|
||||
WasmExternRef? regexp,
|
||||
WasmExternRef? string,
|
||||
WasmI32 start,
|
||||
WasmI32 asPrefix,
|
||||
);
|
||||
|
||||
/// Implementation of [Match.start] for a [regexpMatch].
|
||||
@pragma("wasm:import", "dart.regexpMatchGetStart")
|
||||
external WasmI32 regexpMatchGetStart(WasmExternRef? match);
|
||||
|
||||
/// Implementation of [Match.end] for a [regexpMatch].
|
||||
@pragma("wasm:import", "dart.regexpMatchGetEnd")
|
||||
external WasmI32 regexpMatchGetEnd(WasmExternRef? match);
|
||||
|
||||
/// Implementation of [Match.groupCount] for a [regexpMatch].
|
||||
@pragma("wasm:import", "dart.regexpMatchGetGroupCount")
|
||||
external WasmI32 regexpMatchGetGroupCount(WasmExternRef? match);
|
||||
|
||||
/// Implementation of [Match.group] for a [regexpMatch].
|
||||
///
|
||||
/// This is only called with an index between 0 and [regexpMatchGetGroupCount]
|
||||
/// (inclusive).
|
||||
@pragma("wasm:import", "dart.regexpMatchGetGroup")
|
||||
external WasmExternRef? regexpMatchGetGroup(
|
||||
WasmExternRef? match,
|
||||
WasmI32 index,
|
||||
);
|
||||
|
||||
/// The amount of named groups in a regexp match.
|
||||
@pragma("wasm:import", "dart.regexpMatchGetNamedGroups")
|
||||
external WasmI32 regexpMatchGetNamedGroups(WasmExternRef? match);
|
||||
|
||||
/// For an index between 0 and [regexpMatchGetNamedGroups] (exclusive), returns
|
||||
/// the name of the regexp group.
|
||||
@pragma("wasm:import", "dart.regexpMatchGetGroupName")
|
||||
external WasmExternRef regexpMatchGetGroupName(
|
||||
WasmExternRef? match,
|
||||
WasmI32 index,
|
||||
);
|
||||
|
||||
/// For an index of [regexpMatchGetNamedGroups], returns the match of the group
|
||||
/// named `regexpMatchGetGroupName(match, nameIndex)`.
|
||||
@pragma("wasm:import", "dart.regexpMatchGetGroupByName")
|
||||
external WasmExternRef? regexpMatchGetGroupByName(
|
||||
WasmExternRef? match,
|
||||
WasmI32 nameIndex,
|
||||
);
|
||||
|
||||
@pragma("wasm:import", "dart.timeZoneNameForClampedSeconds")
|
||||
external WasmExternRef timeZoneNameForClampedSeconds(WasmI64 secondsSinceEpoch);
|
||||
|
||||
@pragma("wasm:import", "dart.timeZoneOffsetInSecondsForClampedSeconds")
|
||||
external WasmI32 timeZoneOffsetInSecondsForClampedSeconds(
|
||||
WasmI64 secondsSinceEpoch,
|
||||
);
|
||||
|
||||
@@ -0,0 +1,238 @@
|
||||
// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
|
||||
// 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:_embedder';
|
||||
import 'dart:_error_utils';
|
||||
import 'dart:_internal' show patch;
|
||||
import 'dart:_js_helper';
|
||||
import 'dart:_string';
|
||||
import 'dart:_wasm';
|
||||
|
||||
@patch
|
||||
class RegExp {
|
||||
@patch
|
||||
factory RegExp(
|
||||
String source, {
|
||||
bool multiLine = false,
|
||||
bool caseSensitive = true,
|
||||
bool unicode = false,
|
||||
bool dotAll = false,
|
||||
}) {
|
||||
return _EmbedderRegExp(source, multiLine, caseSensitive, unicode, dotAll);
|
||||
}
|
||||
|
||||
@patch
|
||||
static String escape(String text) {
|
||||
return JSStringImpl.fromRefUnchecked(
|
||||
regexpEscape(jsStringFromDartString(text).wrappedExternRef),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
final class _EmbedderRegExp implements RegExp {
|
||||
WasmExternRef? _regexp = WasmExternRef.nullRef;
|
||||
|
||||
@override
|
||||
final String pattern;
|
||||
@override
|
||||
final bool isMultiLine;
|
||||
@override
|
||||
final bool isCaseSensitive;
|
||||
@override
|
||||
final bool isUnicode;
|
||||
@override
|
||||
final bool isDotAll;
|
||||
|
||||
_EmbedderRegExp(
|
||||
this.pattern,
|
||||
this.isMultiLine,
|
||||
this.isCaseSensitive,
|
||||
this.isUnicode,
|
||||
this.isDotAll,
|
||||
) {
|
||||
final compiled = regexpCreateOrFailWithString(
|
||||
jsStringFromDartString(pattern).wrappedExternRef,
|
||||
WasmI32.fromBool(isMultiLine),
|
||||
WasmI32.fromBool(isCaseSensitive),
|
||||
WasmI32.fromBool(isUnicode),
|
||||
WasmI32.fromBool(isDotAll),
|
||||
);
|
||||
if (!regexpIsRegexp(compiled).toBool()) {
|
||||
// The returned value is the stringified JavaScript exception. Turn it
|
||||
// into a Dart exception.
|
||||
final errorMessage = JSStringImpl.fromRefUnchecked(compiled);
|
||||
throw FormatException('Illegal RegExp pattern ($errorMessage)', pattern);
|
||||
}
|
||||
|
||||
this._regexp = compiled;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
final buffer = StringBuffer('RegExp/');
|
||||
buffer.write(pattern);
|
||||
buffer.write('/');
|
||||
|
||||
if (isMultiLine) buffer.write('m');
|
||||
if (!isCaseSensitive) buffer.write('i');
|
||||
if (isUnicode) buffer.write('u');
|
||||
if (isDotAll) buffer.write('s');
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<RegExpMatch> allMatches(String input, [int start = 0]) {
|
||||
RangeErrorUtils.checkValueBetweenZeroAndPositiveMax(start, input.length);
|
||||
return Iterable.withIterator(
|
||||
() => _EmbedderMatchesIterator(this, input, start),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
RegExpMatch? firstMatch(String input) {
|
||||
return _search(input, 0, false);
|
||||
}
|
||||
|
||||
@override
|
||||
bool hasMatch(String input) {
|
||||
return firstMatch(input) != null;
|
||||
}
|
||||
|
||||
@override
|
||||
Match? matchAsPrefix(String string, [int start = 0]) {
|
||||
return _search(string, start, true);
|
||||
}
|
||||
|
||||
_EmbedderMatch? _search(String string, int start, bool exactStartIndex) {
|
||||
RangeErrorUtils.checkValueBetweenZeroAndPositiveMax(start, string.length);
|
||||
final match = regexpMatch(
|
||||
_regexp,
|
||||
jsStringFromDartString(string).wrappedExternRef,
|
||||
WasmI32.fromInt(start),
|
||||
WasmI32.fromBool(exactStartIndex),
|
||||
);
|
||||
if (match.isNull) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return _EmbedderMatch(this, string).._match = match;
|
||||
}
|
||||
|
||||
@override
|
||||
String? stringMatch(String input) {
|
||||
var match = firstMatch(input);
|
||||
if (match != null) return match[0];
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
final class _EmbedderMatch implements RegExpMatch {
|
||||
@override
|
||||
final _EmbedderRegExp pattern;
|
||||
@override
|
||||
final String input;
|
||||
|
||||
WasmExternRef? _match = WasmExternRef.nullRef;
|
||||
|
||||
_EmbedderMatch(this.pattern, this.input);
|
||||
|
||||
@override
|
||||
String? operator [](int group) {
|
||||
return this.group(group);
|
||||
}
|
||||
|
||||
@override
|
||||
int get start => regexpMatchGetStart(_match).toIntUnsigned();
|
||||
|
||||
@override
|
||||
int get end => regexpMatchGetEnd(_match).toIntUnsigned();
|
||||
|
||||
@override
|
||||
int get groupCount => regexpMatchGetGroupCount(_match).toIntUnsigned();
|
||||
|
||||
@override
|
||||
String? group(int group) {
|
||||
IndexErrorUtils.checkIndex(group, groupCount + 1);
|
||||
final contents = regexpMatchGetGroup(_match, WasmI32.fromInt(group));
|
||||
return contents.isNull ? null : JSStringImpl.fromRefUnchecked(contents);
|
||||
}
|
||||
|
||||
@override
|
||||
List<String?> groups(List<int> groupIndices) {
|
||||
return [for (final index in groupIndices) group(index)];
|
||||
}
|
||||
|
||||
@override
|
||||
late final List<String> groupNames = List.generate(
|
||||
regexpMatchGetNamedGroups(_match).toIntUnsigned(),
|
||||
(i) {
|
||||
return JSStringImpl.fromRefUnchecked(
|
||||
regexpMatchGetGroupName(_match, WasmI32.fromInt(i)),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@override
|
||||
String? namedGroup(String name) {
|
||||
final groupIndex = groupNames.indexOf(name);
|
||||
if (groupIndex < 0) {
|
||||
throw ArgumentError.value(name, "name", "Not a capture group name");
|
||||
}
|
||||
|
||||
final contents = regexpMatchGetGroupByName(
|
||||
_match,
|
||||
WasmI32.fromInt(groupIndex),
|
||||
);
|
||||
return contents.isNull ? null : JSStringImpl.fromRefUnchecked(contents);
|
||||
}
|
||||
}
|
||||
|
||||
class _EmbedderMatchesIterator implements Iterator<RegExpMatch> {
|
||||
final _EmbedderRegExp _regExp;
|
||||
String? _string;
|
||||
int _nextIndex;
|
||||
RegExpMatch? _current;
|
||||
|
||||
_EmbedderMatchesIterator(this._regExp, this._string, this._nextIndex);
|
||||
|
||||
RegExpMatch get current => _current as RegExpMatch;
|
||||
|
||||
static bool _isLeadSurrogate(int c) {
|
||||
return c >= 0xd800 && c <= 0xdbff;
|
||||
}
|
||||
|
||||
static bool _isTrailSurrogate(int c) {
|
||||
return c >= 0xdc00 && c <= 0xdfff;
|
||||
}
|
||||
|
||||
bool moveNext() {
|
||||
var string = _string;
|
||||
if (string == null) return false;
|
||||
|
||||
if (_nextIndex <= string.length) {
|
||||
final match = _regExp._search(_string!, _nextIndex, false);
|
||||
if (match != null) {
|
||||
_current = match;
|
||||
int nextIndex = match.end;
|
||||
if (match.start == nextIndex) {
|
||||
// Zero-width match. Advance by one more, unless the regexp
|
||||
// is in unicode mode and it would put us within a surrogate
|
||||
// pair. In that case, advance past the code point as a whole.
|
||||
if (_regExp.isUnicode &&
|
||||
_nextIndex + 1 < string.length &&
|
||||
_isLeadSurrogate(string.codeUnitAt(_nextIndex)) &&
|
||||
_isTrailSurrogate(string.codeUnitAt(_nextIndex + 1))) {
|
||||
nextIndex++;
|
||||
}
|
||||
nextIndex++;
|
||||
}
|
||||
_nextIndex = nextIndex;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
_current = null;
|
||||
_string = null; // Marks iteration as ended.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
|
||||
// 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:_embedder';
|
||||
import 'dart:_internal' show patch;
|
||||
import 'dart:_string';
|
||||
import 'dart:_wasm';
|
||||
|
||||
@patch
|
||||
class StackTrace {
|
||||
@patch
|
||||
@pragma("wasm:entry-point")
|
||||
@pragma('wasm:never-inline')
|
||||
static StackTrace get current {
|
||||
final hostStackTrace = stackTraceGetCurrent();
|
||||
return _EmbedderStackTrace(hostStackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
final class _EmbedderStackTrace implements StackTrace {
|
||||
WasmExternRef? _embedderStackTrace = WasmExternRef.nullRef;
|
||||
|
||||
_EmbedderStackTrace(WasmExternRef? obj) {
|
||||
_embedderStackTrace = obj;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return JSStringImpl.fromRefUnchecked(
|
||||
stackTraceToString(_embedderStackTrace),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
|
||||
// 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:_embedder';
|
||||
|
||||
@patch
|
||||
class Stopwatch {
|
||||
@patch
|
||||
static int _initTicker() {
|
||||
final frequency = monotonicClockFrequency().toIntUnsigned();
|
||||
if (frequency != 1000 && frequency != 1000000) {
|
||||
throw AssertionError(
|
||||
'dart:monotonicClockFrequency import must return either 1kHz or 1MHz.',
|
||||
);
|
||||
}
|
||||
return frequency;
|
||||
}
|
||||
|
||||
@patch
|
||||
static int _now() => monotonicClockTicks().toInt();
|
||||
|
||||
@patch
|
||||
int get elapsedMicroseconds {
|
||||
int ticks = elapsedTicks;
|
||||
if (_frequency == 1000000) return ticks;
|
||||
assert(_frequency == 1000);
|
||||
return ticks * 1000;
|
||||
}
|
||||
|
||||
@patch
|
||||
int get elapsedMilliseconds {
|
||||
int ticks = elapsedTicks;
|
||||
if (_frequency == 1000) return ticks;
|
||||
assert(_frequency == 1000000);
|
||||
return ticks ~/ 1000;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
|
||||
// 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:_embedder';
|
||||
import 'dart:_internal' show patch;
|
||||
import 'dart:_js_helper';
|
||||
import 'dart:_string';
|
||||
import 'dart:_wasm';
|
||||
|
||||
@patch
|
||||
class StringBuffer {
|
||||
WasmExternRef? _hostBuffer = WasmExternRef.nullRef;
|
||||
|
||||
@patch
|
||||
@pragma("wasm:prefer-inline")
|
||||
StringBuffer([Object content = '']) {
|
||||
_hostBuffer = stringBufferCreate();
|
||||
if (content is! String || content.isNotEmpty) {
|
||||
write(content);
|
||||
}
|
||||
}
|
||||
|
||||
@patch
|
||||
int get length => stringBufferLength(_hostBuffer).toIntUnsigned();
|
||||
|
||||
@patch
|
||||
void write(Object? obj) {
|
||||
if (obj is String) {
|
||||
_writeString(obj);
|
||||
} else {
|
||||
_writeString(obj.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@patch
|
||||
void writeCharCode(int charCode) {
|
||||
stringBufferWriteCharCode(_hostBuffer, WasmI32.fromInt(charCode));
|
||||
}
|
||||
|
||||
@patch
|
||||
void writeAll(Iterable<dynamic> objects, [String separator = ""]) {
|
||||
final iterator = objects.iterator;
|
||||
if (!iterator.moveNext()) return;
|
||||
|
||||
if (separator.isEmpty) {
|
||||
do {
|
||||
write(iterator.current);
|
||||
} while (iterator.moveNext());
|
||||
} else {
|
||||
write(iterator.current);
|
||||
while (iterator.moveNext()) {
|
||||
_writeString(separator);
|
||||
write(iterator.current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@patch
|
||||
void writeln([Object? obj = '']) {
|
||||
write(obj);
|
||||
writeCharCode(10 /*\n*/);
|
||||
}
|
||||
|
||||
@patch
|
||||
void clear() {
|
||||
stringBufferClear(_hostBuffer);
|
||||
}
|
||||
|
||||
@patch
|
||||
String toString() {
|
||||
return JSStringImpl.fromRefUnchecked(stringBufferToString(_hostBuffer));
|
||||
}
|
||||
|
||||
void _writeString(String str) {
|
||||
stringBufferWriteString(
|
||||
_hostBuffer,
|
||||
jsStringFromDartString(str).wrappedExternRef,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
|
||||
// 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:_embedder';
|
||||
import 'dart:_internal' show patch;
|
||||
import 'dart:_string';
|
||||
import 'dart:_wasm';
|
||||
|
||||
@patch
|
||||
class Uri {
|
||||
@patch
|
||||
static Uri get base {
|
||||
final currentUri = JSStringImpl.fromRefUnchecked(baseUri());
|
||||
if (currentUri != null) {
|
||||
return Uri.parse(currentUri);
|
||||
}
|
||||
throw UnsupportedError("'Uri.base' is not supported");
|
||||
}
|
||||
}
|
||||
|
||||
@patch
|
||||
class _Uri {
|
||||
@patch
|
||||
static bool get _isWindows => _isWindowsCached;
|
||||
|
||||
static final bool _isWindowsCached = isWindows().toBool();
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
|
||||
// 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:_embedder';
|
||||
import 'dart:_internal' show patch, unsafeCast, checkValidWeakTarget;
|
||||
import 'dart:_wasm';
|
||||
import 'dart:async';
|
||||
|
||||
@patch
|
||||
class Expando<T extends Object> {
|
||||
WasmExternRef? _expando = WasmExternRef.nullRef;
|
||||
|
||||
@patch
|
||||
Expando([String? name]) : name = name {
|
||||
_expando = expandoCreate();
|
||||
}
|
||||
|
||||
@patch
|
||||
T? operator [](Object object) {
|
||||
checkValidWeakTarget(object, 'object');
|
||||
return unsafeCast(
|
||||
expandoGet(
|
||||
_expando,
|
||||
WasmAnyRef.fromObject(object),
|
||||
WasmI64.fromInt(identityHashCode(object)),
|
||||
)?.toObject(),
|
||||
);
|
||||
}
|
||||
|
||||
@patch
|
||||
void operator []=(Object object, T? value) {
|
||||
checkValidWeakTarget(object, 'object');
|
||||
expandoSet(
|
||||
_expando,
|
||||
WasmAnyRef.fromObject(object),
|
||||
WasmI64.fromInt(identityHashCode(object)),
|
||||
value == null ? null : WasmAnyRef.fromObject(value),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@patch
|
||||
class WeakReference<T extends Object> {
|
||||
@patch
|
||||
factory WeakReference(T target) {
|
||||
checkValidWeakTarget(target, 'target');
|
||||
return _EmbedderWeakReference<T>(target);
|
||||
}
|
||||
}
|
||||
|
||||
final class _EmbedderWeakReference<T extends Object>
|
||||
implements WeakReference<T> {
|
||||
WasmExternRef? _ref = WasmExternRef.nullRef;
|
||||
|
||||
_EmbedderWeakReference(T target) {
|
||||
_ref = weakRefCreate(WasmAnyRef.fromObject(target));
|
||||
}
|
||||
|
||||
@override
|
||||
T? get target {
|
||||
return unsafeCast(weakRefGet(_ref)?.toObject());
|
||||
}
|
||||
}
|
||||
|
||||
@patch
|
||||
class Finalizer<T> {
|
||||
@patch
|
||||
factory Finalizer(void Function(T) callback) {
|
||||
return _EmbedderFinalizer<T>(callback);
|
||||
}
|
||||
}
|
||||
|
||||
final class _EmbedderFinalizer<T> implements Finalizer<T> {
|
||||
final void Function(T) _callback;
|
||||
WasmExternRef? _finalizer = WasmExternRef.nullRef;
|
||||
|
||||
_EmbedderFinalizer(void Function(T) callback)
|
||||
: _callback = Zone.current.bindUnaryCallback(callback) {
|
||||
_finalizer = finalizerCreate(
|
||||
WasmFunction.fromFunction(_entrypoint),
|
||||
WasmAnyRef.fromObject(this),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void attach(Object value, T finalizationToken, {Object? detach}) {
|
||||
checkValidWeakTarget(value, 'value');
|
||||
if (detach != null) checkValidWeakTarget(detach, 'detach');
|
||||
|
||||
finalizerAttach(
|
||||
_finalizer,
|
||||
WasmAnyRef.fromObject(value),
|
||||
finalizationToken == null
|
||||
? null
|
||||
: WasmAnyRef.fromObject(finalizationToken),
|
||||
detach == null ? null : WasmAnyRef.fromObject(detach),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void detach(Object detach) {
|
||||
checkValidWeakTarget(detach, 'detach');
|
||||
finalizerDetach(_finalizer, WasmAnyRef.fromObject(detach));
|
||||
}
|
||||
|
||||
static WasmVoid _entrypoint(WasmAnyRef finalizer, WasmAnyRef? token) {
|
||||
final dartFinalizer = unsafeCast<_EmbedderFinalizer>(finalizer.toObject());
|
||||
dartFinalizer._callback(token?.toObject());
|
||||
return WasmVoid();
|
||||
}
|
||||
}
|
||||
+19
-14
@@ -15,7 +15,8 @@
|
||||
"_internal": {
|
||||
"uri": "internal/internal.dart",
|
||||
"patches": [
|
||||
"_internal/vm/lib/internal_patch.dart"
|
||||
"_internal/vm/lib/internal_patch.dart",
|
||||
"_internal/vm_shared/lib/check_valid_weak_target_patch.dart"
|
||||
]
|
||||
},
|
||||
"async": {
|
||||
@@ -53,7 +54,8 @@
|
||||
"_internal/vm_shared/lib/integers_patch.dart",
|
||||
"_internal/vm_shared/lib/map_patch.dart",
|
||||
"_internal/vm_shared/lib/null_patch.dart",
|
||||
"_internal/vm_shared/lib/string_buffer_patch.dart"
|
||||
"_internal/vm_shared/lib/string_buffer_patch.dart",
|
||||
"_internal/vm_shared/lib/uri_encode_patch.dart"
|
||||
]
|
||||
},
|
||||
"developer": {
|
||||
@@ -285,18 +287,19 @@
|
||||
"_internal/wasm/lib/array_patch.dart",
|
||||
"_internal/wasm/lib/bigint_patch_patch.dart",
|
||||
"_internal/wasm/lib/core_patch.dart",
|
||||
"_internal/wasm/lib/double_patch.dart",
|
||||
"_internal/wasm/lib/date_patch_patch.dart",
|
||||
"_internal/wasm_standalone/lib/double_patch.dart",
|
||||
"_internal/wasm_standalone/lib/date_patch_patch.dart",
|
||||
"_internal/wasm/lib/int_common_patch.dart",
|
||||
"_internal/wasm/lib/int_patch.dart",
|
||||
"_internal/wasm/lib/regexp_patch.dart",
|
||||
"_internal/wasm/lib/stack_trace_patch.dart",
|
||||
"_internal/wasm/lib/string_buffer_patch.dart",
|
||||
"_internal/wasm_standalone/lib/regexp_patch.dart",
|
||||
"_internal/wasm_standalone/lib/stack_trace_patch.dart",
|
||||
"_internal/wasm_standalone/lib/string_buffer_patch.dart",
|
||||
"_internal/wasm/lib/string_patch.dart",
|
||||
"_internal/wasm/lib/stopwatch_patch.dart",
|
||||
"_internal/wasm_standalone/lib/stopwatch_patch.dart",
|
||||
"_internal/wasm/lib/sync_star_patch.dart",
|
||||
"_internal/wasm/lib/uri_patch.dart",
|
||||
"_internal/wasm/lib/weak_patch.dart"
|
||||
"_internal/wasm_standalone/lib/uri_patch.dart",
|
||||
"_internal/vm_shared/lib/uri_encode_patch.dart",
|
||||
"_internal/wasm_standalone/lib/weak_patch.dart"
|
||||
]
|
||||
},
|
||||
"convert": {
|
||||
@@ -320,12 +323,12 @@
|
||||
},
|
||||
"_boxed_int": {
|
||||
"uri": "_internal/wasm/lib/boxed_int.dart",
|
||||
"patches": "_internal/wasm/lib/boxed_int_patch.dart"
|
||||
"patches": "_internal/wasm_standalone/lib/boxed_int_patch.dart"
|
||||
},
|
||||
"_boxed_double": {
|
||||
"uri": "_internal/wasm/lib/boxed_double.dart",
|
||||
"patches": [
|
||||
"_internal/wasm/lib/boxed_double_patch.dart"
|
||||
"_internal/wasm_standalone/lib/boxed_double_patch.dart"
|
||||
]
|
||||
},
|
||||
"_string": {
|
||||
@@ -350,7 +353,8 @@
|
||||
"_internal/wasm/lib/deferred_patch.dart",
|
||||
"_internal/wasm/lib/internal_json_encode_patch.dart",
|
||||
"_internal/wasm/lib/invoke_main_patch.dart",
|
||||
"_internal/wasm/lib/print_patch.dart"
|
||||
"_internal/wasm/lib/print_patch.dart",
|
||||
"_internal/vm_shared/lib/check_valid_weak_target_patch.dart"
|
||||
]
|
||||
},
|
||||
"_wasm": {
|
||||
@@ -386,7 +390,8 @@
|
||||
"_internal/wasm/lib/deferred_patch.dart",
|
||||
"_internal/wasm/lib/internal_json_encode_patch.dart",
|
||||
"_internal/wasm/lib/invoke_main_patch.dart",
|
||||
"_internal/wasm/lib/print_patch.dart"
|
||||
"_internal/wasm/lib/print_patch.dart",
|
||||
"_internal/vm_shared/lib/check_valid_weak_target_patch.dart"
|
||||
]
|
||||
},
|
||||
"_wasm": {
|
||||
|
||||
+15
-10
@@ -26,6 +26,7 @@ vm_common:
|
||||
uri: "internal/internal.dart"
|
||||
patches:
|
||||
- "_internal/vm/lib/internal_patch.dart"
|
||||
- _internal/vm_shared/lib/check_valid_weak_target_patch.dart
|
||||
|
||||
async:
|
||||
uri: "async/async.dart"
|
||||
@@ -60,6 +61,7 @@ vm_common:
|
||||
- "_internal/vm_shared/lib/map_patch.dart"
|
||||
- "_internal/vm_shared/lib/null_patch.dart"
|
||||
- "_internal/vm_shared/lib/string_buffer_patch.dart"
|
||||
- "_internal/vm_shared/lib/uri_encode_patch.dart"
|
||||
|
||||
developer:
|
||||
uri: "developer/developer.dart"
|
||||
@@ -243,18 +245,19 @@ wasm_standalone:
|
||||
- _internal/wasm/lib/array_patch.dart
|
||||
- _internal/wasm/lib/bigint_patch_patch.dart
|
||||
- _internal/wasm/lib/core_patch.dart
|
||||
- _internal/wasm/lib/double_patch.dart # TODO(53884): Rewrite without JS interop in _internal/wasm_standalone
|
||||
- _internal/wasm/lib/date_patch_patch.dart # TODO(53884): Rewrite without JS interop in _internal/wasm_standalone
|
||||
- _internal/wasm_standalone/lib/double_patch.dart
|
||||
- _internal/wasm_standalone/lib/date_patch_patch.dart
|
||||
- _internal/wasm/lib/int_common_patch.dart
|
||||
- _internal/wasm/lib/int_patch.dart
|
||||
- _internal/wasm/lib/regexp_patch.dart # TODO(53884): Rewrite without JS interop in _internal/wasm_standalone
|
||||
- _internal/wasm/lib/stack_trace_patch.dart # TODO(53884): Rewrite without JS interop in _internal/wasm_standalone
|
||||
- _internal/wasm/lib/string_buffer_patch.dart # TODO(53884): Rewrite without JS interop in _internal/wasm_standalone
|
||||
- _internal/wasm_standalone/lib/regexp_patch.dart
|
||||
- _internal/wasm_standalone/lib/stack_trace_patch.dart
|
||||
- _internal/wasm_standalone/lib/string_buffer_patch.dart
|
||||
- _internal/wasm/lib/string_patch.dart # TODO(53884): Rewrite without JS interop in _internal/wasm_standalone
|
||||
- _internal/wasm/lib/stopwatch_patch.dart # TODO(53884): Rewrite without JS interop in _internal/wasm_standalone
|
||||
- _internal/wasm_standalone/lib/stopwatch_patch.dart
|
||||
- _internal/wasm/lib/sync_star_patch.dart
|
||||
- _internal/wasm/lib/uri_patch.dart # TODO(53884): Rewrite without JS interop in _internal/wasm_standalone
|
||||
- _internal/wasm/lib/weak_patch.dart # TODO(53884): Rewrite without JS interop in _internal/wasm_standalone
|
||||
- _internal/wasm_standalone/lib/uri_patch.dart
|
||||
- _internal/vm_shared/lib/uri_encode_patch.dart
|
||||
- _internal/wasm_standalone/lib/weak_patch.dart
|
||||
convert:
|
||||
uri: convert/convert.dart
|
||||
patches:
|
||||
@@ -271,11 +274,11 @@ wasm_standalone:
|
||||
_boxed_int:
|
||||
uri: _internal/wasm/lib/boxed_int.dart
|
||||
patches:
|
||||
_internal/wasm/lib/boxed_int_patch.dart # TODO(53884): Rewrite without JS interop in _internal/wasm_standalone
|
||||
_internal/wasm_standalone/lib/boxed_int_patch.dart
|
||||
_boxed_double:
|
||||
uri: _internal/wasm/lib/boxed_double.dart
|
||||
patches:
|
||||
- _internal/wasm/lib/boxed_double_patch.dart # TODO(53884): Rewrite without JS interop in _internal/wasm_standalone
|
||||
- _internal/wasm_standalone/lib/boxed_double_patch.dart
|
||||
_string:
|
||||
uri: _internal/wasm/lib/js_string.dart # TODO(53884): Rewrite without JS interop in _internal/wasm_standalone
|
||||
_typed_data:
|
||||
@@ -294,6 +297,7 @@ wasm_standalone:
|
||||
- _internal/wasm/lib/internal_json_encode_patch.dart # Needs to be migrated
|
||||
- _internal/wasm/lib/invoke_main_patch.dart # TODO(53884): Rewrite without JS interop in _internal/wasm_standalone
|
||||
- _internal/wasm/lib/print_patch.dart # TODO(53884): Rewrite without JS interop in _internal/wasm_standalone
|
||||
- _internal/vm_shared/lib/check_valid_weak_target_patch.dart
|
||||
_wasm:
|
||||
uri: _wasm/wasm_types.dart
|
||||
patches: _internal/wasm/lib/wasm_types_patch.dart # TODO(53884): Remove once other wasm_standalone patches no longer reference this
|
||||
@@ -319,6 +323,7 @@ wasm_js_common:
|
||||
- _internal/wasm/lib/internal_json_encode_patch.dart
|
||||
- _internal/wasm/lib/invoke_main_patch.dart
|
||||
- _internal/wasm/lib/print_patch.dart
|
||||
- _internal/vm_shared/lib/check_valid_weak_target_patch.dart
|
||||
_wasm:
|
||||
uri: _wasm/wasm_types.dart
|
||||
patches: _internal/wasm/lib/wasm_types_patch.dart
|
||||
|
||||
Reference in New Issue
Block a user