Version 2.18.0-35.0.dev
Merge commit 'fec466e3fe726060d411bc0dc2ed5ae5977a2ab1' into 'dev'
diff --git a/DEPS b/DEPS
index 0416bb7..a2c215f 100644
--- a/DEPS
+++ b/DEPS
@@ -39,7 +39,7 @@
# Checked-in SDK version. The checked-in SDK is a Dart SDK distribution in a
# cipd package used to run Dart scripts in the build and test infrastructure.
- "sdk_tag": "version:2.16.2",
+ "sdk_tag": "version:2.17.0-266.1.beta",
# co19 is a cipd package. Use update.sh in tests/co19[_2] to update these
# hashes. It requires access to the dart-build-access group, which EngProd
diff --git a/pkg/_fe_analyzer_shared/lib/src/scanner/abstract_scanner.dart b/pkg/_fe_analyzer_shared/lib/src/scanner/abstract_scanner.dart
index 8c6a343..1f81c6b 100644
--- a/pkg/_fe_analyzer_shared/lib/src/scanner/abstract_scanner.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/scanner/abstract_scanner.dart
@@ -9,7 +9,15 @@
import 'dart:typed_data' show Uint16List, Uint32List;
import 'token.dart'
- show BeginToken, Keyword, KeywordToken, SyntheticToken, Token, TokenType;
+ show
+ BeginToken,
+ CommentToken,
+ Keyword,
+ KeywordToken,
+ LanguageVersionToken,
+ SyntheticToken,
+ Token,
+ TokenType;
import 'token.dart' as analyzer show StringToken;
@@ -34,8 +42,7 @@
import 'keyword_state.dart' show KeywordState;
-import 'token_impl.dart'
- show CommentToken, DartDocToken, LanguageVersionToken, StringToken;
+import 'token_impl.dart' show DartDocToken, StringTokenImpl;
import 'token_constants.dart';
@@ -570,11 +577,9 @@
{
AbstractScanner option1 = createRecoveryOptionScanner();
option1.insertSyntheticClosers(originalStack, groupingStack);
- option1Recoveries =
- option1.recoveryOptionTokenizer(option1.appendEndGroupInternal(
- /* foundMatchingBrace = */ true,
- type,
- openKind));
+ option1Recoveries = option1.recoveryOptionTokenizer(
+ option1.appendEndGroupInternal(
+ /* foundMatchingBrace = */ true, type, openKind));
option1Recoveries += option1.groupingStack.slowLength();
}
@@ -583,11 +588,9 @@
{
AbstractScanner option2 = createRecoveryOptionScanner();
option2.groupingStack = originalStack;
- option2Recoveries =
- option2.recoveryOptionTokenizer(option2.appendEndGroupInternal(
- /* foundMatchingBrace = */ false,
- type,
- openKind));
+ option2Recoveries = option2.recoveryOptionTokenizer(
+ option2.appendEndGroupInternal(
+ /* foundMatchingBrace = */ false, type, openKind));
// We add 1 to make this option pay for ignoring this token.
option2Recoveries += option2.groupingStack.slowLength() + 1;
}
@@ -1914,7 +1917,7 @@
codeUnits.add(next);
next = advance();
}
- appendToken(new StringToken.fromString(
+ appendToken(new StringTokenImpl.fromString(
TokenType.IDENTIFIER, new String.fromCharCodes(codeUnits), charOffset,
precedingComments: comments));
return next;
diff --git a/pkg/_fe_analyzer_shared/lib/src/scanner/recover.dart b/pkg/_fe_analyzer_shared/lib/src/scanner/recover.dart
index c18e6b1..616fa2b 100644
--- a/pkg/_fe_analyzer_shared/lib/src/scanner/recover.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/scanner/recover.dart
@@ -6,7 +6,7 @@
import 'token.dart' show Token, TokenType;
-import 'token_impl.dart' show StringToken;
+import 'token_impl.dart' show StringTokenImpl;
import 'error_token.dart' show ErrorToken;
@@ -49,7 +49,7 @@
}
Token synthesizeToken(int charOffset, String value, TokenType type) {
- return new StringToken.fromString(type, value, charOffset);
+ return new StringTokenImpl.fromString(type, value, charOffset);
}
Token skipToEof(Token token) {
diff --git a/pkg/_fe_analyzer_shared/lib/src/scanner/scanner.dart b/pkg/_fe_analyzer_shared/lib/src/scanner/scanner.dart
index 35a6386..b9b7cbc 100644
--- a/pkg/_fe_analyzer_shared/lib/src/scanner/scanner.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/scanner/scanner.dart
@@ -22,8 +22,7 @@
export 'token_impl.dart'
show
- LanguageVersionToken,
- StringToken,
+ StringTokenImpl,
isBinaryOperator,
isMinusOperator,
isTernaryOperator,
@@ -32,7 +31,7 @@
export 'error_token.dart' show ErrorToken, buildUnexpectedCharacterToken;
-export 'token_impl.dart' show LanguageVersionToken;
+export 'token.dart' show LanguageVersionToken;
export 'token_constants.dart' show EOF_TOKEN;
diff --git a/pkg/_fe_analyzer_shared/lib/src/scanner/string_scanner.dart b/pkg/_fe_analyzer_shared/lib/src/scanner/string_scanner.dart
index 7594362..f31fbb1 100644
--- a/pkg/_fe_analyzer_shared/lib/src/scanner/string_scanner.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/scanner/string_scanner.dart
@@ -4,7 +4,13 @@
library dart2js.scanner.string_scanner;
-import 'token.dart' show Token, SyntheticStringToken, TokenType;
+import 'token.dart'
+ show
+ CommentToken,
+ LanguageVersionToken,
+ SyntheticStringToken,
+ Token,
+ TokenType;
import 'token.dart' as analyzer show StringToken;
@@ -12,7 +18,11 @@
show AbstractScanner, LanguageVersionChanged, ScannerConfiguration;
import 'token_impl.dart'
- show CommentToken, DartDocToken, LanguageVersionToken, StringToken;
+ show
+ CommentTokenImpl,
+ DartDocToken,
+ LanguageVersionTokenImpl,
+ StringTokenImpl;
import 'error_token.dart' show ErrorToken;
@@ -69,7 +79,7 @@
analyzer.StringToken createSubstringToken(
TokenType type, int start, bool asciiOnly,
[int extraOffset = 0]) {
- return new StringToken.fromSubstring(
+ return new StringTokenImpl.fromSubstring(
type, string, start, scanOffset + extraOffset, tokenStart,
canonicalize: true, precedingComments: comments);
}
@@ -85,7 +95,7 @@
@override
CommentToken createCommentToken(TokenType type, int start, bool asciiOnly,
[int extraOffset = 0]) {
- return new CommentToken.fromSubstring(
+ return new CommentTokenImpl.fromSubstring(
type, string, start, scanOffset + extraOffset, tokenStart,
canonicalize: true);
}
@@ -101,7 +111,7 @@
@override
LanguageVersionToken createLanguageVersionToken(
int start, int major, int minor) {
- return new LanguageVersionToken.fromSubstring(
+ return new LanguageVersionTokenImpl.fromSubstring(
string, start, scanOffset, tokenStart, major, minor,
canonicalize: true);
}
diff --git a/pkg/_fe_analyzer_shared/lib/src/scanner/token_impl.dart b/pkg/_fe_analyzer_shared/lib/src/scanner/token_impl.dart
index da39df5..986340a 100644
--- a/pkg/_fe_analyzer_shared/lib/src/scanner/token_impl.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/scanner/token_impl.dart
@@ -4,8 +4,14 @@
library _fe_analyzer_shared.scanner.token;
-import 'token.dart' as analyzer;
-import 'token.dart' show TokenType;
+import 'token.dart'
+ show
+ DocumentationCommentToken,
+ SimpleToken,
+ TokenType,
+ CommentToken,
+ StringToken,
+ LanguageVersionToken;
import 'token_constants.dart' show IDENTIFIER_TOKEN;
@@ -16,7 +22,7 @@
* number literals, comments, and error tokens, using the corresponding
* precedence info.
*/
-class StringToken extends analyzer.SimpleToken implements analyzer.StringToken {
+class StringTokenImpl extends SimpleToken implements StringToken {
/**
* The length threshold above which substring tokens are computed lazily.
*
@@ -33,8 +39,8 @@
* Creates a non-lazy string token. If [canonicalize] is true, the string
* is canonicalized before the token is created.
*/
- StringToken.fromString(TokenType type, String value, int charOffset,
- {bool canonicalize: false, analyzer.CommentToken? precedingComments})
+ StringTokenImpl.fromString(TokenType type, String value, int charOffset,
+ {bool canonicalize: false, CommentToken? precedingComments})
: valueOrLazySubstring = canonicalizedString(
value, /* start = */ 0, value.length, canonicalize),
super(type, charOffset, precedingComments);
@@ -43,9 +49,9 @@
* Creates a lazy string token. If [canonicalize] is true, the string
* is canonicalized before the token is created.
*/
- StringToken.fromSubstring(
+ StringTokenImpl.fromSubstring(
TokenType type, String data, int start, int end, int charOffset,
- {bool canonicalize: false, analyzer.CommentToken? precedingComments})
+ {bool canonicalize: false, CommentToken? precedingComments})
: super(type, charOffset, precedingComments) {
int length = end - start;
if (length <= LAZY_THRESHOLD) {
@@ -61,9 +67,9 @@
* Creates a lazy string token. If [asciiOnly] is false, the byte array
* is passed through a UTF-8 decoder.
*/
- StringToken.fromUtf8Bytes(TokenType type, List<int> data, int start, int end,
- bool asciiOnly, int charOffset,
- {analyzer.CommentToken? precedingComments})
+ StringTokenImpl.fromUtf8Bytes(TokenType type, List<int> data, int start,
+ int end, bool asciiOnly, int charOffset,
+ {CommentToken? precedingComments})
: super(type, charOffset, precedingComments) {
int length = end - start;
if (length <= LAZY_THRESHOLD) {
@@ -73,10 +79,6 @@
}
}
- StringToken._(TokenType type, this.valueOrLazySubstring, int charOffset,
- [analyzer.CommentToken? precedingComments])
- : super(type, charOffset, precedingComments);
-
@override
String get lexeme {
if (valueOrLazySubstring is String) {
@@ -119,28 +121,15 @@
String value() => lexeme;
}
-/**
- * A String-valued token that does not exist in the original source.
- */
-class SyntheticStringToken extends StringToken
- implements analyzer.SyntheticStringToken {
- SyntheticStringToken(TokenType type, String value, int offset,
- [analyzer.CommentToken? precedingComments])
- : super._(type, value, offset, precedingComments);
-
+class CommentTokenImpl extends StringTokenImpl implements CommentToken {
@override
- int get length => 0;
-}
-
-class CommentToken extends StringToken implements analyzer.CommentToken {
- @override
- analyzer.SimpleToken? parent;
+ SimpleToken? parent;
/**
* Creates a lazy comment token. If [canonicalize] is true, the string
* is canonicalized before the token is created.
*/
- CommentToken.fromSubstring(
+ CommentTokenImpl.fromSubstring(
TokenType type, String data, int start, int end, int charOffset,
{bool canonicalize: false})
: super.fromSubstring(type, data, start, end, charOffset,
@@ -149,44 +138,44 @@
/**
* Creates a non-lazy comment token.
*/
- CommentToken.fromString(TokenType type, String lexeme, int charOffset)
+ CommentTokenImpl.fromString(TokenType type, String lexeme, int charOffset)
: super.fromString(type, lexeme, charOffset);
/**
* Creates a lazy string token. If [asciiOnly] is false, the byte array
* is passed through a UTF-8 decoder.
*/
- CommentToken.fromUtf8Bytes(TokenType type, List<int> data, int start, int end,
- bool asciiOnly, int charOffset)
+ CommentTokenImpl.fromUtf8Bytes(TokenType type, List<int> data, int start,
+ int end, bool asciiOnly, int charOffset)
: super.fromUtf8Bytes(type, data, start, end, asciiOnly, charOffset);
}
-class LanguageVersionToken extends CommentToken
- implements analyzer.LanguageVersionToken {
+class LanguageVersionTokenImpl extends CommentTokenImpl
+ implements LanguageVersionToken {
@override
int major;
@override
int minor;
- LanguageVersionToken.from(String text, int offset, this.major, this.minor)
+ LanguageVersionTokenImpl.from(String text, int offset, this.major, this.minor)
: super.fromString(TokenType.SINGLE_LINE_COMMENT, text, offset);
- LanguageVersionToken.fromSubstring(
+ LanguageVersionTokenImpl.fromSubstring(
String string, int start, int end, int tokenStart, this.major, this.minor,
{bool canonicalize: false})
: super.fromSubstring(
TokenType.SINGLE_LINE_COMMENT, string, start, end, tokenStart,
canonicalize: canonicalize);
- LanguageVersionToken.fromUtf8Bytes(List<int> bytes, int start, int end,
+ LanguageVersionTokenImpl.fromUtf8Bytes(List<int> bytes, int start, int end,
int tokenStart, this.major, this.minor)
: super.fromUtf8Bytes(
TokenType.SINGLE_LINE_COMMENT, bytes, start, end, true, tokenStart);
}
-class DartDocToken extends CommentToken
- implements analyzer.DocumentationCommentToken {
+class DartDocToken extends CommentTokenImpl
+ implements DocumentationCommentToken {
/**
* Creates a lazy comment token. If [canonicalize] is true, the string
* is canonicalized before the token is created.
diff --git a/pkg/_fe_analyzer_shared/lib/src/scanner/utf8_bytes_scanner.dart b/pkg/_fe_analyzer_shared/lib/src/scanner/utf8_bytes_scanner.dart
index da22f90..a0fd026 100644
--- a/pkg/_fe_analyzer_shared/lib/src/scanner/utf8_bytes_scanner.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/scanner/utf8_bytes_scanner.dart
@@ -6,9 +6,9 @@
import 'dart:convert' show unicodeBomCharacterRune, utf8;
-import 'token.dart' show SyntheticStringToken, TokenType;
+import 'token.dart' show LanguageVersionToken, SyntheticStringToken, TokenType;
-import 'token.dart' as analyzer show StringToken;
+import 'token.dart' as analyzer;
import 'scanner.dart' show unicodeReplacementCharacter;
@@ -16,7 +16,11 @@
show AbstractScanner, LanguageVersionChanged, ScannerConfiguration;
import 'token_impl.dart'
- show CommentToken, DartDocToken, LanguageVersionToken, StringToken;
+ show
+ CommentTokenImpl,
+ DartDocToken,
+ LanguageVersionTokenImpl,
+ StringTokenImpl;
/**
* Scanner that reads from a UTF-8 encoded list of bytes and creates tokens
@@ -227,7 +231,7 @@
analyzer.StringToken createSubstringToken(
TokenType type, int start, bool asciiOnly,
[int extraOffset = 0]) {
- return new StringToken.fromUtf8Bytes(
+ return new StringTokenImpl.fromUtf8Bytes(
type, bytes, start, byteOffset + extraOffset, asciiOnly, tokenStart,
precedingComments: comments);
}
@@ -235,15 +239,17 @@
@override
analyzer.StringToken createSyntheticSubstringToken(
TokenType type, int start, bool asciiOnly, String syntheticChars) {
- String source = StringToken.decodeUtf8(bytes, start, byteOffset, asciiOnly);
+ String source =
+ StringTokenImpl.decodeUtf8(bytes, start, byteOffset, asciiOnly);
return new SyntheticStringToken(
type, source + syntheticChars, tokenStart, source.length);
}
@override
- CommentToken createCommentToken(TokenType type, int start, bool asciiOnly,
+ analyzer.CommentToken createCommentToken(
+ TokenType type, int start, bool asciiOnly,
[int extraOffset = 0]) {
- return new CommentToken.fromUtf8Bytes(
+ return new CommentTokenImpl.fromUtf8Bytes(
type, bytes, start, byteOffset + extraOffset, asciiOnly, tokenStart);
}
@@ -257,7 +263,7 @@
@override
LanguageVersionToken createLanguageVersionToken(
int start, int major, int minor) {
- return new LanguageVersionToken.fromUtf8Bytes(
+ return new LanguageVersionTokenImpl.fromUtf8Bytes(
bytes, start, byteOffset, tokenStart, major, minor);
}
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_state.dart b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
index 8d0f309..e2a6383 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_state.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
@@ -5,7 +5,7 @@
import 'dart:typed_data';
import 'package:_fe_analyzer_shared/src/scanner/token_impl.dart'
- show StringToken;
+ show StringTokenImpl;
import 'package:analyzer/dart/analysis/declared_variables.dart';
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
@@ -563,7 +563,7 @@
// StringToken uses a static instance of StringCanonicalizer, so we need
// to clear it explicitly once we are done using it for this file.
- StringToken.canonicalizer.clear();
+ StringTokenImpl.canonicalizer.clear();
return unit;
}
diff --git a/pkg/analyzer/lib/src/dart/micro/library_graph.dart b/pkg/analyzer/lib/src/dart/micro/library_graph.dart
index d58d6bb..b36a098 100644
--- a/pkg/analyzer/lib/src/dart/micro/library_graph.dart
+++ b/pkg/analyzer/lib/src/dart/micro/library_graph.dart
@@ -877,7 +877,7 @@
// StringToken uses a static instance of StringCanonicalizer, so we need
// to clear it explicitly once we are done using it for this file.
- StringToken.canonicalizer.clear();
+ StringTokenImpl.canonicalizer.clear();
// TODO(scheglov) Use actual versions.
unit.languageVersion = LibraryLanguageVersion(
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index e14406b..3438fa9 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -50,7 +50,7 @@
show NullValue, StackListener;
import 'package:_fe_analyzer_shared/src/scanner/errors.dart'
show translateErrorToken;
-import 'package:_fe_analyzer_shared/src/scanner/scanner.dart' hide StringToken;
+import 'package:_fe_analyzer_shared/src/scanner/scanner.dart';
import 'package:_fe_analyzer_shared/src/scanner/token.dart'
show KeywordToken, StringToken, SyntheticStringToken, SyntheticToken;
import 'package:_fe_analyzer_shared/src/scanner/token_constants.dart';
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index db1a627..ebe16a8 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -118,7 +118,7 @@
/// will be performed the next time an analysis context is created.
void clearCaches() {
// See https://github.com/dart-lang/sdk/issues/30314.
- StringToken.canonicalizer.clear();
+ StringTokenImpl.canonicalizer.clear();
}
}
diff --git a/pkg/analyzer/test/generated/parser_test_base.dart b/pkg/analyzer/test/generated/parser_test_base.dart
index e0c50bb..ef2d196 100644
--- a/pkg/analyzer/test/generated/parser_test_base.dart
+++ b/pkg/analyzer/test/generated/parser_test_base.dart
@@ -807,8 +807,8 @@
null,
null,
Token(Keyword.CLASS, 0),
- astFactory.simpleIdentifier(
- fasta.StringToken.fromString(TokenType.IDENTIFIER, className, 6)),
+ astFactory.simpleIdentifier(fasta.StringTokenImpl.fromString(
+ TokenType.IDENTIFIER, className, 6)),
null,
null,
null,
diff --git a/pkg/dart2wasm/lib/code_generator.dart b/pkg/dart2wasm/lib/code_generator.dart
index f086339..d12efbd 100644
--- a/pkg/dart2wasm/lib/code_generator.dart
+++ b/pkg/dart2wasm/lib/code_generator.dart
@@ -388,6 +388,17 @@
});
}
+ /// Helper function to throw a Wasm ref downcast error.
+ void throwWasmRefError(String expected) {
+ wrap(
+ StringLiteral(expected),
+ translator
+ .translateType(translator.coreTypes.stringNonNullableRawType));
+ _call(translator.stackTraceCurrent.reference);
+ _call(translator.throwWasmRefError.reference);
+ b.unreachable();
+ }
+
/// Generates code for an expression plus conversion code to convert the
/// result to the expected type if needed. All expression code generation goes
/// through this method.
@@ -1660,9 +1671,28 @@
@override
w.ValueType visitFunctionInvocation(
FunctionInvocation node, w.ValueType expectedType) {
+ Expression receiver = node.receiver;
+ if (receiver is InstanceGet &&
+ receiver.interfaceTarget == translator.wasmFunctionCall) {
+ // Receiver is a WasmFunction
+ assert(receiver.name.text == "call");
+ w.RefType receiverType =
+ translator.translateType(dartTypeOf(receiver.receiver)) as w.RefType;
+ w.Local temp = addLocal(receiverType);
+ wrap(receiver.receiver, receiverType);
+ b.local_set(temp);
+ w.FunctionType functionType = receiverType.heapType as w.FunctionType;
+ assert(node.arguments.positional.length == functionType.inputs.length);
+ for (int i = 0; i < node.arguments.positional.length; i++) {
+ wrap(node.arguments.positional[i], functionType.inputs[i]);
+ }
+ b.local_get(temp);
+ b.call_ref();
+ return translator.outputOrVoid(functionType.outputs);
+ }
int parameterCount = node.functionType?.requiredParameterCount ??
node.arguments.positional.length;
- return _functionCall(parameterCount, node.receiver, node.arguments);
+ return _functionCall(parameterCount, receiver, node.arguments);
}
w.ValueType _functionCall(
diff --git a/pkg/dart2wasm/lib/intrinsics.dart b/pkg/dart2wasm/lib/intrinsics.dart
index 0fa9329..7fb0cf5 100644
--- a/pkg/dart2wasm/lib/intrinsics.dart
+++ b/pkg/dart2wasm/lib/intrinsics.dart
@@ -118,28 +118,45 @@
Intrinsifier(this.codeGen);
w.ValueType? generateInstanceGetterIntrinsic(InstanceGet node) {
- DartType receiverType = dartTypeOf(node.receiver);
+ Expression receiver = node.receiver;
+ DartType receiverType = dartTypeOf(receiver);
String name = node.name.text;
+ Member target = node.interfaceTarget;
+ Class cls = target.enclosingClass!;
+
+ // WasmAnyRef.isObject
+ if (cls == translator.wasmAnyRefClass) {
+ assert(name == "isObject");
+ w.Label succeed = b.block(const [], const [w.NumType.i32]);
+ w.Label fail = b.block(const [], const [w.RefType.any(nullable: false)]);
+ codeGen.wrap(receiver, w.RefType.any(nullable: false));
+ b.br_on_non_data(fail);
+ translator.ref_test(b, translator.topInfo);
+ b.br(succeed);
+ b.end(); // fail
+ b.drop();
+ b.i32_const(0);
+ b.end(); // succeed
+ return w.NumType.i32;
+ }
// _WasmArray.length
- if (node.interfaceTarget.enclosingClass == translator.wasmArrayBaseClass) {
+ if (cls == translator.wasmArrayBaseClass) {
assert(name == 'length');
DartType elementType =
(receiverType as InterfaceType).typeArguments.single;
w.ArrayType arrayType = translator.arrayTypeForDartType(elementType);
- Expression array = node.receiver;
- codeGen.wrap(array, w.RefType.def(arrayType, nullable: true));
+ codeGen.wrap(receiver, w.RefType.def(arrayType, nullable: true));
b.array_len(arrayType);
b.i64_extend_i32_u();
return w.NumType.i64;
}
// int.bitlength
- if (node.interfaceTarget.enclosingClass == translator.coreTypes.intClass &&
- name == 'bitLength') {
+ if (cls == translator.coreTypes.intClass && name == 'bitLength') {
w.Local temp = codeGen.function.addLocal(w.NumType.i64);
b.i64_const(64);
- codeGen.wrap(node.receiver, w.NumType.i64);
+ codeGen.wrap(receiver, w.NumType.i64);
b.local_tee(temp);
b.local_get(temp);
b.i64_const(63);
@@ -151,28 +168,26 @@
}
// _HashAbstractImmutableBase._indexNullable
- if (node.interfaceTarget == translator.immutableMapIndexNullable) {
+ if (target == translator.immutableMapIndexNullable) {
ClassInfo info = translator.classInfo[translator.hashFieldBaseClass]!;
- codeGen.wrap(node.receiver, info.nullableType);
+ codeGen.wrap(receiver, info.nullableType);
b.struct_get(info.struct, FieldIndex.hashBaseIndex);
return info.struct.fields[FieldIndex.hashBaseIndex].type.unpacked;
}
// _Compound._typedDataBase
- if (node.interfaceTarget.enclosingClass == translator.ffiCompoundClass &&
- name == '_typedDataBase') {
+ if (cls == translator.ffiCompoundClass && name == '_typedDataBase') {
// A compound (subclass of Struct or Union) is represented by its i32
// address. The _typedDataBase field contains a Pointer pointing to the
// compound, whose representation is the same.
- codeGen.wrap(node.receiver, w.NumType.i32);
+ codeGen.wrap(receiver, w.NumType.i32);
return w.NumType.i32;
}
// Pointer.address
- if (node.interfaceTarget.enclosingClass == translator.ffiPointerClass &&
- name == 'address') {
+ if (cls == translator.ffiPointerClass && name == 'address') {
// A Pointer is represented by its i32 address.
- codeGen.wrap(node.receiver, w.NumType.i32);
+ codeGen.wrap(receiver, w.NumType.i32);
b.i64_extend_i32_u();
return w.NumType.i64;
}
@@ -185,17 +200,17 @@
DartType receiverType = dartTypeOf(receiver);
String name = node.name.text;
Procedure target = node.interfaceTarget;
+ Class cls = target.enclosingClass!;
// _TypedListBase._setRange
- if (target.enclosingClass == translator.typedListBaseClass &&
- name == "_setRange") {
+ if (cls == translator.typedListBaseClass && name == "_setRange") {
// Always fall back to alternative implementation.
b.i32_const(0);
return w.NumType.i32;
}
// _TypedList._(get|set)(Int|Uint|Float)(8|16|32|64)
- if (node.interfaceTarget.enclosingClass == translator.typedListClass) {
+ if (cls == translator.typedListClass) {
Match? match = RegExp("^_(get|set)(Int|Uint|Float)(8|16|32|64)\$")
.matchAsPrefix(name);
if (match != null) {
@@ -319,11 +334,24 @@
}
}
+ // WasmAnyRef.toObject
+ if (cls == translator.wasmAnyRefClass) {
+ assert(name == "toObject");
+ w.Label succeed = b.block(const [], [translator.topInfo.nonNullableType]);
+ w.Label fail = b.block(const [], const [w.RefType.any(nullable: false)]);
+ codeGen.wrap(receiver, w.RefType.any(nullable: false));
+ b.br_on_non_data(fail);
+ translator.br_on_cast(b, succeed, translator.topInfo);
+ b.end(); // fail
+ codeGen.throwWasmRefError("a Dart object");
+ b.end(); // succeed
+ return translator.topInfo.nonNullableType;
+ }
+
// WasmIntArray.(readSigned|readUnsigned|write)
// WasmFloatArray.(read|write)
// WasmObjectArray.(read|write)
- if (node.interfaceTarget.enclosingClass?.superclass ==
- translator.wasmArrayBaseClass) {
+ if (cls.superclass == translator.wasmArrayBaseClass) {
DartType elementType =
(receiverType as InterfaceType).typeArguments.single;
w.ArrayType arrayType = translator.arrayTypeForDartType(elementType);
@@ -388,10 +416,8 @@
}
// Wasm(I32|I64|F32|F64) conversions
- if (node.interfaceTarget.enclosingClass?.superclass?.superclass ==
- translator.wasmTypesBaseClass) {
- w.StorageType receiverType =
- translator.builtinTypes[node.interfaceTarget.enclosingClass]!;
+ if (cls.superclass?.superclass == translator.wasmTypesBaseClass) {
+ w.StorageType receiverType = translator.builtinTypes[cls]!;
switch (receiverType) {
case w.NumType.i32:
assert(name == "toIntSigned" || name == "toIntUnsigned");
@@ -557,6 +583,7 @@
w.ValueType? generateStaticIntrinsic(StaticInvocation node) {
String name = node.name.text;
+ Class? cls = node.target.enclosingClass;
// dart:core static functions
if (node.target.enclosingLibrary == translator.coreTypes.coreLibrary) {
@@ -710,7 +737,7 @@
b.f64_reinterpret_i64();
return w.NumType.f64;
case "getID":
- assert(node.target.enclosingClass?.name == "ClassID");
+ assert(cls?.name == "ClassID");
ClassInfo info = translator.topInfo;
codeGen.wrap(node.arguments.positional.single, info.nullableType);
b.struct_get(info.struct, FieldIndex.classId);
@@ -836,24 +863,58 @@
}
}
- // Wasm(Int|Float|Object)Array constructors
- if (node.target.enclosingClass?.superclass ==
- translator.wasmArrayBaseClass) {
- Expression length = node.arguments.positional[0];
- w.ArrayType arrayType =
- translator.arrayTypeForDartType(node.arguments.types.single);
- codeGen.wrap(length, w.NumType.i64);
- b.i32_wrap_i64();
- translator.array_new_default(b, arrayType);
- return w.RefType.def(arrayType, nullable: false);
- }
+ if (cls != null && translator.isWasmType(cls)) {
+ // Wasm(Int|Float|Object)Array constructors
+ if (cls.superclass == translator.wasmArrayBaseClass) {
+ Expression length = node.arguments.positional[0];
+ w.ArrayType arrayType =
+ translator.arrayTypeForDartType(node.arguments.types.single);
+ codeGen.wrap(length, w.NumType.i64);
+ b.i32_wrap_i64();
+ translator.array_new_default(b, arrayType);
+ return w.RefType.def(arrayType, nullable: false);
+ }
- // Wasm(I32|I64|F32|F64) constructors
- if (node.target.enclosingClass?.superclass?.superclass ==
- translator.wasmTypesBaseClass) {
+ // (WasmFuncRef|WasmFunction).fromRef constructors
+ if ((cls == translator.wasmFuncRefClass ||
+ cls == translator.wasmFunctionClass) &&
+ name == "fromRef") {
+ Expression ref = node.arguments.positional[0];
+ w.RefType resultType = typeOfExp(node) as w.RefType;
+ w.Label succeed = b.block(const [], [resultType]);
+ w.Label fail =
+ b.block(const [], const [w.RefType.any(nullable: false)]);
+ codeGen.wrap(ref, w.RefType.any(nullable: false));
+ b.br_on_non_func(fail);
+ if (cls == translator.wasmFunctionClass) {
+ assert(resultType.heapType is w.FunctionType);
+ translator.br_on_cast_fail(b, fail, resultType.heapType);
+ }
+ b.br(succeed);
+ b.end(); // fail
+ codeGen.throwWasmRefError("a function with the expected signature");
+ b.end(); // succeed
+ return resultType;
+ }
+
+ // WasmFunction.fromFunction constructor
+ if (cls == translator.wasmFunctionClass) {
+ assert(name == "fromFunction");
+ Expression f = node.arguments.positional[0];
+ if (f is! ConstantExpression || f.constant is! StaticTearOffConstant) {
+ throw "Argument to WasmFunction.fromFunction isn't a static function";
+ }
+ StaticTearOffConstant func = f.constant as StaticTearOffConstant;
+ w.BaseFunction wasmFunction =
+ translator.functions.getFunction(func.targetReference);
+ w.Global functionRef = translator.makeFunctionRef(wasmFunction);
+ b.global_get(functionRef);
+ return functionRef.type.type;
+ }
+
+ // Wasm(AnyRef|FuncRef|EqRef|DataRef|I32|I64|F32|F64) constructors
Expression value = node.arguments.positional[0];
- w.StorageType targetType =
- translator.builtinTypes[node.target.enclosingClass]!;
+ w.StorageType targetType = translator.builtinTypes[cls]!;
switch (targetType) {
case w.NumType.i32:
codeGen.wrap(value, w.NumType.i64);
@@ -869,6 +930,10 @@
case w.NumType.f64:
codeGen.wrap(value, w.NumType.f64);
return w.NumType.f64;
+ default:
+ w.RefType valueType = targetType as w.RefType;
+ codeGen.wrap(value, valueType);
+ return valueType;
}
}
diff --git a/pkg/dart2wasm/lib/translator.dart b/pkg/dart2wasm/lib/translator.dart
index 1eacf81..2a61d3c 100644
--- a/pkg/dart2wasm/lib/translator.dart
+++ b/pkg/dart2wasm/lib/translator.dart
@@ -67,8 +67,10 @@
late final Class wasmTypesBaseClass;
late final Class wasmArrayBaseClass;
late final Class wasmAnyRefClass;
+ late final Class wasmFuncRefClass;
late final Class wasmEqRefClass;
late final Class wasmDataRefClass;
+ late final Class wasmFunctionClass;
late final Class boxedBoolClass;
late final Class boxedIntClass;
late final Class boxedDoubleClass;
@@ -91,11 +93,13 @@
late final Class typedListViewClass;
late final Class byteDataViewClass;
late final Class typeErrorClass;
+ late final Procedure wasmFunctionCall;
late final Procedure stackTraceCurrent;
late final Procedure stringEquals;
late final Procedure stringInterpolate;
late final Procedure throwNullCheckError;
late final Procedure throwAsCheckError;
+ late final Procedure throwWasmRefError;
late final Procedure mapFactory;
late final Procedure mapPut;
late final Procedure immutableMapIndexNullable;
@@ -130,7 +134,7 @@
final Map<int, w.StructType> functionTypeCache = {};
final Map<w.StructType, int> functionTypeParameterCount = {};
final Map<int, w.DefinedGlobal> functionTypeRtt = {};
- final Map<w.DefinedFunction, w.DefinedGlobal> functionRefCache = {};
+ final Map<w.BaseFunction, w.DefinedGlobal> functionRefCache = {};
final Map<Procedure, w.DefinedFunction> tearOffFunctionCache = {};
ClassInfo get topInfo => classes[0];
@@ -161,8 +165,10 @@
wasmTypesBaseClass = lookupWasm("_WasmBase");
wasmArrayBaseClass = lookupWasm("_WasmArray");
wasmAnyRefClass = lookupWasm("WasmAnyRef");
+ wasmFuncRefClass = lookupWasm("WasmFuncRef");
wasmEqRefClass = lookupWasm("WasmEqRef");
wasmDataRefClass = lookupWasm("WasmDataRef");
+ wasmFunctionClass = lookupWasm("WasmFunction");
boxedBoolClass = lookupCore("_BoxedBool");
boxedIntClass = lookupCore("_BoxedInt");
boxedDoubleClass = lookupCore("_BoxedDouble");
@@ -185,6 +191,8 @@
typedListClass = lookupTypedData("_TypedList");
typedListViewClass = lookupTypedData("_TypedListView");
byteDataViewClass = lookupTypedData("_ByteDataView");
+ wasmFunctionCall =
+ wasmFunctionClass.procedures.firstWhere((p) => p.name.text == "call");
stackTraceCurrent =
stackTraceClass.procedures.firstWhere((p) => p.name.text == "current");
stringEquals =
@@ -195,6 +203,8 @@
.firstWhere((p) => p.name.text == "_throwNullCheckError");
throwAsCheckError = typeErrorClass.procedures
.firstWhere((p) => p.name.text == "_throwAsCheckError");
+ throwWasmRefError = typeErrorClass.procedures
+ .firstWhere((p) => p.name.text == "_throwWasmRefError");
mapFactory = lookupCollection("LinkedHashMap").procedures.firstWhere(
(p) => p.kind == ProcedureKind.Factory && p.name.text == "_default");
mapPut = lookupCollection("_CompactLinkedCustomHashMap")
@@ -208,9 +218,10 @@
coreTypes.boolClass: w.NumType.i32,
coreTypes.intClass: w.NumType.i64,
coreTypes.doubleClass: w.NumType.f64,
- wasmAnyRefClass: w.RefType.any(nullable: false),
- wasmEqRefClass: w.RefType.eq(nullable: false),
- wasmDataRefClass: w.RefType.data(nullable: false),
+ wasmAnyRefClass: const w.RefType.any(nullable: false),
+ wasmFuncRefClass: const w.RefType.func(nullable: false),
+ wasmEqRefClass: const w.RefType.eq(nullable: false),
+ wasmDataRefClass: const w.RefType.data(nullable: false),
boxedBoolClass: w.NumType.i32,
boxedIntClass: w.NumType.i64,
boxedDoubleClass: w.NumType.f64,
@@ -421,6 +432,28 @@
return w.RefType.def(arrayTypeForDartType(elementType),
nullable: false);
}
+ if (type.classNode == wasmFunctionClass) {
+ DartType functionType = type.typeArguments.single;
+ if (functionType is! FunctionType) {
+ throw "The type argument of a WasmFunction must be a function type";
+ }
+ if (functionType.typeParameters.isNotEmpty ||
+ functionType.namedParameters.isNotEmpty ||
+ functionType.requiredParameterCount !=
+ functionType.positionalParameters.length) {
+ throw "A WasmFunction can't have optional/type parameters";
+ }
+ List<w.ValueType> inputs = [
+ for (DartType type in functionType.positionalParameters)
+ translateType(type)
+ ];
+ List<w.ValueType> outputs = [
+ if (functionType.returnType != const VoidType())
+ translateType(functionType.returnType)
+ ];
+ w.FunctionType wasmType = this.functionType(inputs, outputs);
+ return w.RefType.def(wasmType, nullable: type.isPotentiallyNullable);
+ }
return typeForInfo(
classInfo[type.classNode]!, type.isPotentiallyNullable);
}
@@ -498,7 +531,7 @@
return functionTypeParameterCount[heapType]!;
}
- w.DefinedGlobal makeFunctionRef(w.DefinedFunction f) {
+ w.DefinedGlobal makeFunctionRef(w.BaseFunction f) {
return functionRefCache.putIfAbsent(f, () {
w.DefinedGlobal global = m.addGlobal(
w.GlobalType(w.RefType.def(f.type, nullable: false), mutable: false));
@@ -605,11 +638,16 @@
b.ref_as_non_null();
} else {
// Downcast
- var heapType = (to as w.RefType).heapType;
- ClassInfo? info = classForHeapType[heapType];
if (from.nullable && !to.nullable) {
b.ref_as_non_null();
}
+ var heapType = (to as w.RefType).heapType;
+ if (heapType is w.FunctionType) {
+ b.ref_as_func();
+ ref_cast(b, heapType);
+ return;
+ }
+ ClassInfo? info = classForHeapType[heapType];
if (!(from as w.RefType).heapType.isSubtypeOf(w.HeapType.data)) {
b.ref_as_data();
}
@@ -711,7 +749,7 @@
// The [type] parameter taken by the methods is either a [ClassInfo] (to use
// the RTT for the class), an [int] (to use the RTT for the closure struct
// corresponding to functions with that number of parameters) or a
- // [w.DataType] (to use the canonical RTT for the type).
+ // [w.DefType] (to use the canonical RTT for the type).
void struct_new(w.Instructions b, Object type) {
if (options.runtimeTypes) {
@@ -823,7 +861,7 @@
}
return struct;
} else {
- b.rtt_canon(type as w.DataType);
+ b.rtt_canon(type as w.DefType);
return type;
}
}
diff --git a/pkg/front_end/lib/src/fasta/compiler_context.dart b/pkg/front_end/lib/src/fasta/compiler_context.dart
index 9d86de3..0ace047 100644
--- a/pkg/front_end/lib/src/fasta/compiler_context.dart
+++ b/pkg/front_end/lib/src/fasta/compiler_context.dart
@@ -12,7 +12,7 @@
import 'package:_fe_analyzer_shared/src/util/colors.dart' as colors;
import 'package:_fe_analyzer_shared/src/scanner/token_impl.dart'
- show StringToken;
+ show StringTokenImpl;
import 'package:kernel/ast.dart' show Source;
@@ -137,7 +137,7 @@
}
void clear() {
- StringToken.canonicalizer.clear();
+ StringTokenImpl.canonicalizer.clear();
errors.clear();
dependencies.clear();
}
diff --git a/pkg/front_end/test/fasta/parser/token_stream_rewriter_test.dart b/pkg/front_end/test/fasta/parser/token_stream_rewriter_test.dart
index 6828c746..6d01c32 100644
--- a/pkg/front_end/test/fasta/parser/token_stream_rewriter_test.dart
+++ b/pkg/front_end/test/fasta/parser/token_stream_rewriter_test.dart
@@ -6,7 +6,7 @@
import 'package:_fe_analyzer_shared/src/scanner/scanner.dart'
show ScannerResult, scanString;
import 'package:_fe_analyzer_shared/src/scanner/token.dart'
- show ReplacementToken, Token, TokenType;
+ show ReplacementToken, StringToken, Token, TokenType;
import 'package:_fe_analyzer_shared/src/scanner/token_impl.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -162,7 +162,7 @@
void test_replaceNextTokenWithSyntheticToken_1() {
Token a = _makeToken(0, 'a');
StringToken b = _makeToken(5, 'b');
- b.precedingComments = new CommentToken.fromSubstring(
+ b.precedingComments = new CommentTokenImpl.fromSubstring(
TokenType.SINGLE_LINE_COMMENT, "Test comment", 1, 9, 1,
canonicalize: true);
Token c = _makeToken(10, 'c');
@@ -186,7 +186,7 @@
void test_replaceNextTokenWithSyntheticToken_2() {
Token a = _makeToken(0, 'a');
StringToken b = _makeToken(5, 'b');
- b.precedingComments = new CommentToken.fromSubstring(
+ b.precedingComments = new CommentTokenImpl.fromSubstring(
TokenType.SINGLE_LINE_COMMENT, "Test comment", 1, 9, 1,
canonicalize: true);
_link([a, b]);
@@ -208,7 +208,7 @@
void test_replaceNextTokensWithSyntheticToken_1() {
Token a = _makeToken(0, 'a');
StringToken b = _makeToken(5, 'b');
- b.precedingComments = new CommentToken.fromSubstring(
+ b.precedingComments = new CommentTokenImpl.fromSubstring(
TokenType.SINGLE_LINE_COMMENT, "Test comment", 1, 9, 1,
canonicalize: true);
Token c = _makeToken(10, 'c');
@@ -236,7 +236,7 @@
void test_replaceNextTokensWithSyntheticToken_2() {
Token a = _makeToken(0, 'a');
StringToken b = _makeToken(5, 'b');
- b.precedingComments = new CommentToken.fromSubstring(
+ b.precedingComments = new CommentTokenImpl.fromSubstring(
TokenType.SINGLE_LINE_COMMENT, "Test comment", 1, 9, 1,
canonicalize: true);
Token c = _makeToken(10, 'c');
@@ -338,7 +338,8 @@
}
StringToken _makeToken(int charOffset, String text) {
- return new StringToken.fromString(TokenType.IDENTIFIER, text, charOffset);
+ return new StringTokenImpl.fromString(
+ TokenType.IDENTIFIER, text, charOffset);
}
}
diff --git a/pkg/front_end/test/parser_suite.dart b/pkg/front_end/test/parser_suite.dart
index 9ed7b26..c73cb53 100644
--- a/pkg/front_end/test/parser_suite.dart
+++ b/pkg/front_end/test/parser_suite.dart
@@ -406,7 +406,10 @@
}
}
if (addTypes) {
- sb.write("[${token.runtimeType}]");
+ // Avoid 6000+ changes caused by "Impl" being added to some token
+ // classes.
+ String type = token.runtimeType.toString().replaceFirst("Impl", "");
+ sb.write("[$type]");
}
printed = true;
endOfLast = token.end;
diff --git a/pkg/wasm_builder/lib/src/instructions.dart b/pkg/wasm_builder/lib/src/instructions.dart
index 10df25a..6c04e05 100644
--- a/pkg/wasm_builder/lib/src/instructions.dart
+++ b/pkg/wasm_builder/lib/src/instructions.dart
@@ -1234,7 +1234,8 @@
/// Emit a `br_on_cast_static_fail` instruction.
void br_on_cast_static_fail(Label label, DefType targetType) {
assert(_verifyBranchTypes(label, 1, [_topOfStack]));
- assert(_verifyCast((inputs) => [RefType.def(targetType, nullable: false)],
+ assert(_verifyCastStatic(
+ (inputs) => [RefType.def(targetType, nullable: false)],
trace: ['br_on_cast_static_fail', label, targetType]));
writeBytes(const [0xFB, 0x47]);
_writeLabel(label);
diff --git a/sdk/lib/_internal/wasm/lib/errors_patch.dart b/sdk/lib/_internal/wasm/lib/errors_patch.dart
index d560ac0..666f279 100644
--- a/sdk/lib/_internal/wasm/lib/errors_patch.dart
+++ b/sdk/lib/_internal/wasm/lib/errors_patch.dart
@@ -65,4 +65,11 @@
stackTrace);
return _throwObjectWithStackTrace(typeError, stackTrace);
}
+
+ @pragma("wasm:entry-point")
+ static Never _throwWasmRefError(String expected, StackTrace stackTrace) {
+ final typeError = _TypeError.fromMessageAndStackTrace(
+ "The Wasm reference is not $expected", stackTrace);
+ return _throwObjectWithStackTrace(typeError, stackTrace);
+ }
}
diff --git a/sdk/lib/wasm/wasm_types.dart b/sdk/lib/wasm/wasm_types.dart
index 288deaa..ea09211 100644
--- a/sdk/lib/wasm/wasm_types.dart
+++ b/sdk/lib/wasm/wasm_types.dart
@@ -23,17 +23,49 @@
/// The Wasm `anyref` type.
@pragma("wasm:entry-point")
-class WasmAnyRef extends _WasmBase {}
+class WasmAnyRef extends _WasmBase {
+ /// Upcast Dart object to `anyref`.
+ external factory WasmAnyRef.fromObject(Object o);
+
+ /// Whether this reference is a Dart object.
+ external bool get isObject;
+
+ /// Downcast `anyref` to a Dart object.
+ ///
+ /// Will throw if the reference is not a Dart object.
+ external Object toObject();
+}
+
+/// The Wasm `funcref` type.
+@pragma("wasm:entry-point")
+class WasmFuncRef extends WasmAnyRef {
+ /// Upcast typed function reference to `funcref`
+ external factory WasmFuncRef.fromWasmFunction(WasmFunction<Function> fun);
+
+ /// Downcast `anyref` to `funcref`.
+ ///
+ /// Will throw if the reference is not a `funcref`.
+ external factory WasmFuncRef.fromRef(WasmAnyRef ref);
+}
/// The Wasm `eqref` type.
@pragma("wasm:entry-point")
-class WasmEqRef extends WasmAnyRef {}
+class WasmEqRef extends WasmAnyRef {
+ /// Upcast Dart object to `eqref`.
+ external factory WasmEqRef.fromObject(Object o);
+}
/// The Wasm `dataref` type.
@pragma("wasm:entry-point")
-class WasmDataRef extends WasmEqRef {}
+class WasmDataRef extends WasmEqRef {
+ /// Upcast Dart object to `dataref`.
+ external factory WasmDataRef.fromObject(Object o);
+}
abstract class _WasmArray extends WasmDataRef {
+ /// Dummy factory to silence error about missing superclass constructor.
+ external factory _WasmArray._dummy();
+
external int get length;
}
@@ -102,6 +134,25 @@
external void write(int index, T value);
}
+/// Wasm typed function reference.
+@pragma("wasm:entry-point")
+class WasmFunction<F extends Function> extends WasmFuncRef {
+ /// Create a typed function reference referring to the given function.
+ ///
+ /// The argument must directly name a static function with no optional
+ /// parameters and no type parameters.
+ external factory WasmFunction.fromFunction(F f);
+
+ /// Downcast `anyref` to a typed function reference.
+ ///
+ /// Will throw if the reference is not a function with the expected signature.
+ external factory WasmFunction.fromRef(WasmAnyRef ref);
+
+ /// Call the function referred to by this typed function reference.
+ @pragma("wasm:entry-point")
+ external F get call;
+}
+
extension IntToWasmInt on int {
WasmI32 toWasmI32() => WasmI32.fromInt(this);
WasmI64 toWasmI64() => WasmI64.fromInt(this);
diff --git a/tests/web/wasm/wasm_types_test.dart b/tests/web/wasm/wasm_types_test.dart
new file mode 100644
index 0000000..5538605
--- /dev/null
+++ b/tests/web/wasm/wasm_types_test.dart
@@ -0,0 +1,110 @@
+// Copyright (c) 2022, 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:wasm';
+
+import 'package:expect/expect.dart';
+
+@pragma("wasm:import", "Object.create")
+external WasmAnyRef createObject(WasmAnyRef? prototype);
+
+@pragma("wasm:import", "Array.of")
+external WasmAnyRef singularArray(WasmAnyRef element);
+
+@pragma("wasm:import", "Reflect.apply")
+external WasmAnyRef apply(
+ WasmAnyRef target, WasmAnyRef thisArgument, WasmAnyRef argumentsList);
+
+WasmAnyRef? anyRef;
+WasmEqRef? eqRef;
+WasmDataRef? dataRef;
+
+int funCount = 0;
+
+void fun(WasmEqRef arg) {
+ funCount++;
+ Expect.equals("Dart object", arg.toObject());
+}
+
+test() {
+ // Some test objects
+ Object dartObject1 = "1";
+ Object dartObject2 = true;
+ Object dartObject3 = Object();
+ WasmAnyRef jsObject1 = createObject(null);
+
+ // A JS object is not a Dart object.
+ Expect.isFalse(jsObject1.isObject);
+
+ // A Wasm ref can be null and can be checked for null.
+ WasmAnyRef? jsObject2 = null;
+ Expect.isTrue(jsObject2 == null);
+
+ // Upcast Dart objects to Wasm refs and put them in fields.
+ anyRef = WasmAnyRef.fromObject(dartObject1);
+ eqRef = WasmEqRef.fromObject(dartObject2);
+ dataRef = WasmDataRef.fromObject(dartObject3);
+
+ // Dart objects are Dart objects.
+ Expect.isTrue(anyRef!.isObject);
+ Expect.isTrue(eqRef!.isObject);
+ Expect.isTrue(dataRef!.isObject);
+
+ // Casting back yields the original objects.
+ Expect.identical(dartObject1, anyRef!.toObject());
+ Expect.identical(dartObject2, eqRef!.toObject());
+ Expect.identical(dartObject3, dataRef!.toObject());
+
+ // Casting a JS object to a Dart object throws.
+ Object o;
+ Expect.throws(() {
+ o = jsObject1.toObject();
+ }, (_) => true);
+
+ // Integer and float conversions
+ Expect.equals(1, 1.toWasmI32().toIntSigned());
+ Expect.equals(-2, (-2).toWasmI32().toIntSigned());
+ Expect.equals(3, 3.toWasmI32().toIntUnsigned());
+ Expect.notEquals(-4, (-4).toWasmI32().toIntUnsigned());
+ Expect.equals(5, 5.toWasmI64().toInt());
+ Expect.equals(6.0, 6.0.toWasmF32().toDouble());
+ Expect.notEquals(7.1, 7.1.toWasmF32().toDouble());
+ Expect.equals(8.0, 8.0.toWasmF64().toDouble());
+
+ // Create a typed function reference for a Dart function and call it, both
+ // directly and from JS.
+ var dartObjectRef = WasmEqRef.fromObject("Dart object");
+ var ff = WasmFunction.fromFunction(fun);
+ ff.call(dartObjectRef);
+ apply(ff, createObject(null), singularArray(dartObjectRef));
+ Expect.isFalse(ff.isObject);
+
+ // Cast a typed function reference to a `funcref` and back.
+ WasmFuncRef funcref = WasmFuncRef.fromWasmFunction(ff);
+ var ff2 = WasmFunction<void Function(WasmEqRef)>.fromRef(funcref);
+ ff2.call(dartObjectRef);
+ Expect.isFalse(ff2.isObject);
+
+ // Casting a non-function JS object to a typed function reference throws.
+ Expect.throws(() {
+ WasmFunction<double Function(double)>.fromRef(jsObject1);
+ }, (_) => true);
+
+ // Create a typed function reference from an import and call it.
+ var createObjectFun = WasmFunction.fromFunction(createObject);
+ WasmAnyRef jsObject3 = createObjectFun.call(null);
+ Expect.isFalse(jsObject3.isObject);
+
+ Expect.equals(3, funCount);
+}
+
+main() {
+ try {
+ test();
+ } catch (e, s) {
+ print(e);
+ print(s);
+ rethrow;
+ }
+}
diff --git a/tools/VERSION b/tools/VERSION
index 6c9080c..5aa9356 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 18
PATCH 0
-PRERELEASE 34
+PRERELEASE 35
PRERELEASE_PATCH 0
\ No newline at end of file