[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:
Simon Binder
2026-04-30 03:46:55 -07:00
committed by dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent 73a2c6c9a7
commit fe8f4cd369
22 changed files with 1292 additions and 141 deletions
+3 -3
View File
@@ -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))
)
+142
View File
@@ -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.
-56
View File
@@ -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);
+7 -24
View File
@@ -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
View File
@@ -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
View File
@@ -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