mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 16:59:47 +00:00
[dart2wasm] Use [WasmArray]s for positional/named arguments in dynamic calls
This avoids allocating lists in dynamic calls for positional/named arguments. => Doing so allows removing more usages of [List] in the RTT. => Also results in up to 50% faster dynamic calls. => Probably also results in smaller code. The list allocation is now pushed to the slow path where we create [Invocation] object that is then used for NoSuchMethod handling. Change-Id: If578fb044a6cf7f31bd409c177b361181ba68a01 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/344821 Reviewed-by: Ömer Ağacan <omersa@google.com> Commit-Queue: Martin Kustermann <kustermann@google.com>
This commit is contained in:
parent
5a4b438ddb
commit
3343b7a841
|
@ -1908,12 +1908,11 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
|||
b.local_set(typeArgsLocal);
|
||||
|
||||
// Evaluate positional arguments
|
||||
makeList(DynamicType(), positionalArguments.length,
|
||||
final positionalArgsLocal = function.addLocal(makeArray(
|
||||
translator.nullableObjectArrayType, positionalArguments.length,
|
||||
(elementType, elementIdx) {
|
||||
wrap(positionalArguments[elementIdx], elementType);
|
||||
}, isGrowable: false);
|
||||
final positionalArgsLocal = function.addLocal(
|
||||
translator.classInfo[translator.fixedLengthListClass]!.nonNullableType);
|
||||
}));
|
||||
b.local_set(positionalArgsLocal);
|
||||
|
||||
// Evaluate named arguments. The arguments need to be evaluated in the
|
||||
|
@ -1929,9 +1928,10 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
|||
}
|
||||
namedArgumentLocals.sort((e1, e2) => e1.key.compareTo(e2.key));
|
||||
|
||||
// Create named argument list
|
||||
makeList(DynamicType(), namedArguments.length * 2,
|
||||
(elementType, elementIdx) {
|
||||
// Create named argument array
|
||||
final namedArgsLocal = function.addLocal(
|
||||
makeArray(translator.nullableObjectArrayType, namedArguments.length * 2,
|
||||
(elementType, elementIdx) {
|
||||
if (elementIdx % 2 == 0) {
|
||||
final name = namedArgumentLocals[elementIdx ~/ 2].key;
|
||||
final w.ValueType symbolValueType =
|
||||
|
@ -1942,9 +1942,7 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
|||
final local = namedArgumentLocals[elementIdx ~/ 2].value;
|
||||
b.local_get(local);
|
||||
}
|
||||
}, isGrowable: false);
|
||||
final namedArgsLocal = function.addLocal(
|
||||
translator.classInfo[translator.fixedLengthListClass]!.nonNullableType);
|
||||
}));
|
||||
b.local_set(namedArgsLocal);
|
||||
|
||||
final nullBlock = b.block([], [translator.topInfo.nonNullableType]);
|
||||
|
@ -2973,14 +2971,18 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
|||
|
||||
w.ValueType makeArrayFromExpressions(
|
||||
List<Expression> expressions, InterfaceType elementType) {
|
||||
return translator.makeArray(
|
||||
function,
|
||||
translator.arrayTypeForDartType(elementType),
|
||||
expressions.length, (w.ValueType elementType, int i) {
|
||||
wrap(expressions[i], elementType);
|
||||
return makeArray(
|
||||
translator.arrayTypeForDartType(elementType), expressions.length,
|
||||
(w.ValueType type, int i) {
|
||||
wrap(expressions[i], type);
|
||||
});
|
||||
}
|
||||
|
||||
w.ValueType makeArray(w.ArrayType arrayType, int length,
|
||||
void Function(w.ValueType, int) generateItem) {
|
||||
return translator.makeArray(function, arrayType, length, generateItem);
|
||||
}
|
||||
|
||||
@override
|
||||
w.ValueType visitMapLiteral(MapLiteral node, w.ValueType expectedType) {
|
||||
types.makeType(this, node.keyType);
|
||||
|
@ -3456,7 +3458,8 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
|||
param.name!,
|
||||
() {
|
||||
b.local_get(positionalArgsLocal);
|
||||
translator.indexList(b, (b) => b.i32_const(positionalParamIdx));
|
||||
b.i32_const(positionalParamIdx);
|
||||
b.array_get(translator.nullableObjectArrayType);
|
||||
},
|
||||
() {
|
||||
types.makeType(this, param.type);
|
||||
|
@ -3490,8 +3493,8 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
|||
param.name!,
|
||||
() {
|
||||
b.local_get(namedArgsLocal);
|
||||
translator.indexList(b,
|
||||
(b) => b.i32_const(mapNamedParameterToArrayIndex(param.name!)));
|
||||
b.i32_const(mapNamedParameterToArrayIndex(param.name!));
|
||||
b.array_get(translator.nullableObjectArrayType);
|
||||
},
|
||||
() {
|
||||
types.makeType(this, param.type);
|
||||
|
@ -3519,7 +3522,8 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
|||
|
||||
void pushArgument(w.Local listLocal, int listIdx, int wasmInputIdx) {
|
||||
b.local_get(listLocal);
|
||||
translator.indexList(b, (b) => b.i32_const(listIdx));
|
||||
b.i32_const(listIdx);
|
||||
b.array_get(translator.nullableObjectArrayType);
|
||||
translator.convertType(function, translator.topInfo.nullableType,
|
||||
memberWasmInputs[wasmInputIdx]);
|
||||
}
|
||||
|
|
|
@ -201,8 +201,8 @@ class Forwarder {
|
|||
|
||||
final receiverLocal = function.locals[0]; // ref #Top
|
||||
final typeArgsLocal = function.locals[1]; // ref _ListBase
|
||||
final positionalArgsLocal = function.locals[2]; // ref _ListBase
|
||||
final namedArgsLocal = function.locals[3]; // ref _ListBase
|
||||
final positionalArgsLocal = function.locals[2]; // ref WasmArray
|
||||
final namedArgsLocal = function.locals[3]; // ref WasmArray
|
||||
|
||||
final classIdLocal = function.addLocal(w.NumType.i32);
|
||||
|
||||
|
@ -302,7 +302,7 @@ class Forwarder {
|
|||
// positionalArgs.length >= nRequired &&
|
||||
// positionalArgs.length <= nTotal
|
||||
b.local_get(positionalArgsLocal);
|
||||
translator.getListLength(b);
|
||||
b.array_len();
|
||||
b.local_tee(numArgsLocal);
|
||||
b.i32_const(nRequired);
|
||||
b.i32_ge_u();
|
||||
|
@ -316,9 +316,10 @@ class Forwarder {
|
|||
// Add default values of optional positional parameters if needed
|
||||
w.Local? adjustedPositionalArgsLocal;
|
||||
if (nRequired != nTotal) {
|
||||
adjustedPositionalArgsLocal = function.addLocal(translator
|
||||
.classInfo[translator.growableListClass]!.nonNullableType);
|
||||
_makeEmptyGrowableList(translator, function, nTotal);
|
||||
adjustedPositionalArgsLocal =
|
||||
function.addLocal(translator.nullableObjectArrayTypeRef);
|
||||
b.i32_const(nTotal);
|
||||
b.array_new_default(translator.nullableObjectArrayType);
|
||||
b.local_set(adjustedPositionalArgsLocal);
|
||||
|
||||
// Copy passed arguments
|
||||
|
@ -332,11 +333,11 @@ class Forwarder {
|
|||
b.i32_lt_u();
|
||||
b.if_();
|
||||
b.local_get(adjustedPositionalArgsLocal);
|
||||
b.local_get(argIdxLocal);
|
||||
b.local_get(positionalArgsLocal);
|
||||
translator.indexList(b, (b) => b.local_get(argIdxLocal));
|
||||
b.call(translator.functions
|
||||
.getFunction(translator.growableListAdd.reference));
|
||||
b.drop();
|
||||
b.local_get(argIdxLocal);
|
||||
b.array_get(translator.nullableObjectArrayType);
|
||||
b.array_set(translator.nullableObjectArrayType);
|
||||
b.local_get(argIdxLocal);
|
||||
b.i32_const(1);
|
||||
b.i32_add();
|
||||
|
@ -353,17 +354,14 @@ class Forwarder {
|
|||
b.i32_const(optionalParamIdx);
|
||||
b.i32_le_u();
|
||||
b.if_();
|
||||
b.local_get(adjustedPositionalArgsLocal);
|
||||
|
||||
final param = targetMemberParamInfo.positional[optionalParamIdx]!;
|
||||
|
||||
b.local_get(adjustedPositionalArgsLocal);
|
||||
b.i32_const(optionalParamIdx);
|
||||
translator.constants.instantiateConstant(
|
||||
function, b, param, translator.topInfo.nullableType);
|
||||
|
||||
b.call(translator.functions
|
||||
.getFunction(translator.growableListAdd.reference));
|
||||
b.drop();
|
||||
|
||||
b.array_set(translator.nullableObjectArrayType);
|
||||
b.end();
|
||||
}
|
||||
}
|
||||
|
@ -375,15 +373,15 @@ class Forwarder {
|
|||
if (targetMemberParamInfo.named.isEmpty) {
|
||||
// namedArgs.length == 0
|
||||
b.local_get(namedArgsLocal);
|
||||
translator.getListLength(b);
|
||||
b.array_len();
|
||||
b.i32_eqz();
|
||||
b.i32_eqz();
|
||||
b.br_if(noSuchMethodBlock);
|
||||
} else {
|
||||
adjustedNamedArgsLocal = function.addLocal(translator
|
||||
.classInfo[translator.growableListClass]!.nonNullableType);
|
||||
_makeEmptyGrowableList(
|
||||
translator, function, targetMemberParamInfo.named.length);
|
||||
adjustedNamedArgsLocal =
|
||||
function.addLocal(translator.nullableObjectArrayTypeRef);
|
||||
b.i32_const(targetMemberParamInfo.named.length);
|
||||
b.array_new_default(translator.nullableObjectArrayType);
|
||||
b.local_set(adjustedNamedArgsLocal);
|
||||
|
||||
final namedParameterIdxLocal = function.addLocal(
|
||||
|
@ -391,7 +389,7 @@ class Forwarder {
|
|||
|
||||
final remainingNamedArgsLocal = numArgsLocal;
|
||||
b.local_get(namedArgsLocal);
|
||||
translator.getListLength(b);
|
||||
b.array_len();
|
||||
b.i32_const(1);
|
||||
b.i32_shr_u();
|
||||
b.local_set(remainingNamedArgsLocal);
|
||||
|
@ -409,7 +407,10 @@ class Forwarder {
|
|||
return null;
|
||||
}
|
||||
|
||||
for (final name in targetMemberParamInfo.names) {
|
||||
for (int nameIdx = 0;
|
||||
nameIdx < targetMemberParamInfo.names.length;
|
||||
++nameIdx) {
|
||||
final String name = targetMemberParamInfo.names[nameIdx];
|
||||
final Constant? paramInfoDefaultValue =
|
||||
targetMemberParamInfo.named[name]!;
|
||||
final Expression? functionNodeDefaultValue =
|
||||
|
@ -441,23 +442,27 @@ class Forwarder {
|
|||
paramInfoDefaultValue == null) {
|
||||
// Required parameter missing
|
||||
b.br_if(noSuchMethodBlock);
|
||||
|
||||
// Copy provided named parameter.
|
||||
|
||||
b.local_get(adjustedNamedArgsLocal);
|
||||
b.i32_const(nameIdx);
|
||||
|
||||
b.local_get(namedArgsLocal);
|
||||
translator.indexList(b, (b) {
|
||||
b.local_get(namedParameterIdxLocal);
|
||||
translator.convertType(
|
||||
function, namedParameterIdxLocal.type, w.NumType.i64);
|
||||
b.i32_wrap_i64();
|
||||
});
|
||||
b.call(translator.functions
|
||||
.getFunction(translator.growableListAdd.reference));
|
||||
b.drop();
|
||||
b.local_get(namedParameterIdxLocal);
|
||||
translator.convertType(
|
||||
function, namedParameterIdxLocal.type, w.NumType.i64);
|
||||
b.i32_wrap_i64();
|
||||
b.array_get(translator.nullableObjectArrayType);
|
||||
|
||||
b.array_set(translator.nullableObjectArrayType);
|
||||
} else {
|
||||
// Optional, either has a default in the member or not used by
|
||||
// the member
|
||||
b.if_();
|
||||
|
||||
b.local_get(adjustedNamedArgsLocal);
|
||||
b.i32_const(nameIdx);
|
||||
|
||||
if (functionNodeDefaultValue != null) {
|
||||
// Used by the member, has a default value
|
||||
|
@ -475,24 +480,19 @@ class Forwarder {
|
|||
translator.topInfo.nullableType,
|
||||
);
|
||||
}
|
||||
|
||||
b.call(translator.functions
|
||||
.getFunction(translator.growableListAdd.reference));
|
||||
b.drop();
|
||||
b.array_set(translator.nullableObjectArrayType);
|
||||
|
||||
b.else_();
|
||||
|
||||
b.local_get(adjustedNamedArgsLocal);
|
||||
b.i32_const(nameIdx);
|
||||
b.local_get(namedArgsLocal);
|
||||
translator.indexList(b, (b) {
|
||||
b.local_get(namedParameterIdxLocal);
|
||||
translator.convertType(
|
||||
function, namedParameterIdxLocal.type, w.NumType.i64);
|
||||
b.i32_wrap_i64();
|
||||
});
|
||||
b.call(translator.functions
|
||||
.getFunction(translator.growableListAdd.reference));
|
||||
b.drop();
|
||||
b.local_get(namedParameterIdxLocal);
|
||||
translator.convertType(
|
||||
function, namedParameterIdxLocal.type, w.NumType.i64);
|
||||
b.i32_wrap_i64();
|
||||
b.array_get(translator.nullableObjectArrayType);
|
||||
b.array_set(translator.nullableObjectArrayType);
|
||||
|
||||
b.end();
|
||||
}
|
||||
|
@ -676,8 +676,8 @@ void generateDynamicFunctionCall(
|
|||
final listArgumentType =
|
||||
translator.classInfo[translator.listBaseClass]!.nonNullableType;
|
||||
assert(typeArgsLocal.type == listArgumentType);
|
||||
assert(posArgsLocal.type == listArgumentType);
|
||||
assert(namedArgsLocal.type == listArgumentType);
|
||||
assert(posArgsLocal.type == translator.nullableObjectArrayTypeRef);
|
||||
assert(namedArgsLocal.type == translator.nullableObjectArrayTypeRef);
|
||||
|
||||
final b = function.body;
|
||||
|
||||
|
@ -744,9 +744,11 @@ void createInvocationObject(
|
|||
|
||||
b.local_get(typeArgsLocal);
|
||||
b.local_get(positionalArgsLocal);
|
||||
b.call(translator.functions
|
||||
.getFunction(translator.positionalParametersToList.reference));
|
||||
b.local_get(namedArgsLocal);
|
||||
b.call(translator.functions
|
||||
.getFunction(translator.namedParameterListToMap.reference));
|
||||
.getFunction(translator.namedParametersToMap.reference));
|
||||
b.call(translator.functions
|
||||
.getFunction(translator.invocationGenericMethodFactory.reference));
|
||||
}
|
||||
|
@ -853,27 +855,6 @@ void generateNoSuchMethodCall(
|
|||
b.call_indirect(noSuchMethodWasmFunctionType);
|
||||
}
|
||||
|
||||
void _makeEmptyGrowableList(
|
||||
Translator translator, w.FunctionBuilder function, int capacity) {
|
||||
final b = function.body;
|
||||
Class cls = translator.growableListClass;
|
||||
ClassInfo info = translator.classInfo[cls]!;
|
||||
translator.functions.allocateClass(info.classId);
|
||||
w.ArrayType arrayType = translator.listArrayType;
|
||||
|
||||
b.i32_const(info.classId);
|
||||
b.i32_const(initialIdentityHash);
|
||||
translator.constants.instantiateConstant(
|
||||
function,
|
||||
b,
|
||||
TypeLiteralConstant(DynamicType()),
|
||||
translator.classInfo[translator.typeClass]!.nonNullableType);
|
||||
b.i64_const(0); // _length
|
||||
b.i32_const(capacity);
|
||||
b.array_new_default(arrayType); // _data
|
||||
b.struct_new(info.struct);
|
||||
}
|
||||
|
||||
class ClassIdRange {
|
||||
final int start;
|
||||
final int end; // inclusive
|
||||
|
|
|
@ -1728,17 +1728,15 @@ class Intrinsifier {
|
|||
b.local_set(typeArgsLocal);
|
||||
|
||||
// Create empty list for positional args if the argument is null
|
||||
final posArgsLocal = function.addLocal(listArgumentType);
|
||||
final posArgsLocal =
|
||||
function.addLocal(translator.nullableObjectArrayTypeRef);
|
||||
b.local_get(posArgsNullableLocal);
|
||||
b.ref_is_null();
|
||||
b.if_([], [listArgumentType]);
|
||||
translator.constants.instantiateConstant(
|
||||
function,
|
||||
b,
|
||||
ListConstant(
|
||||
InterfaceType(translator.objectInfo.cls!, Nullability.nullable),
|
||||
[]),
|
||||
translator.objectInfo.nonNullableType);
|
||||
|
||||
b.if_([], [translator.nullableObjectArrayTypeRef]);
|
||||
translator.makeArray(
|
||||
function, translator.nullableObjectArrayType, 0, (_, __) {});
|
||||
|
||||
b.else_();
|
||||
// List argument may be a custom list type, convert it to `_ListBase`
|
||||
// with `_List.of`.
|
||||
|
@ -1751,15 +1749,16 @@ class Intrinsifier {
|
|||
b.local_get(posArgsNullableLocal);
|
||||
b.ref_as_non_null();
|
||||
codeGen.call(translator.listOf.reference);
|
||||
translator.getListBaseArray(b);
|
||||
b.end();
|
||||
b.local_set(posArgsLocal);
|
||||
|
||||
// Convert named argument map to list, to be passed to shape and type
|
||||
// checkers and the dynamic call entry.
|
||||
final namedArgsListLocal = function.addLocal(listArgumentType);
|
||||
final namedArgsListLocal =
|
||||
function.addLocal(translator.nullableObjectArrayTypeRef);
|
||||
b.local_get(namedArgsLocal);
|
||||
codeGen.call(translator.namedParameterMapToList.reference);
|
||||
b.ref_cast(listArgumentType); // ref Object -> ref _ListBase
|
||||
codeGen.call(translator.namedParameterMapToArray.reference);
|
||||
b.local_set(namedArgsListLocal);
|
||||
|
||||
final noSuchMethodBlock = b.block();
|
||||
|
|
|
@ -275,10 +275,12 @@ mixin KernelNodes {
|
|||
// dart:core dynamic invocation helper procedures
|
||||
late final Procedure getNamedParameterIndex =
|
||||
index.getTopLevelProcedure("dart:core", "_getNamedParameterIndex");
|
||||
late final Procedure namedParameterListToMap =
|
||||
index.getTopLevelProcedure("dart:core", "_namedParameterListToMap");
|
||||
late final Procedure namedParameterMapToList =
|
||||
index.getTopLevelProcedure("dart:core", "_namedParameterMapToList");
|
||||
late final Procedure positionalParametersToList =
|
||||
index.getTopLevelProcedure("dart:core", "_positionalParametersToList");
|
||||
late final Procedure namedParametersToMap =
|
||||
index.getTopLevelProcedure("dart:core", "_namedParametersToMap");
|
||||
late final Procedure namedParameterMapToArray =
|
||||
index.getTopLevelProcedure("dart:core", "_namedParameterMapToArray");
|
||||
late final Procedure listOf = index.getProcedure("dart:core", "_List", "of");
|
||||
|
||||
// dart:_wasm procedures
|
||||
|
|
|
@ -128,6 +128,10 @@ class Translator with KernelNodes {
|
|||
.fields[FieldIndex.listArray]
|
||||
.type as w.RefType)
|
||||
.heapType as w.ArrayType;
|
||||
late final w.ArrayType nullableObjectArrayType =
|
||||
arrayTypeForDartType(coreTypes.objectRawType(Nullability.nullable));
|
||||
late final w.RefType nullableObjectArrayTypeRef =
|
||||
w.RefType.def(nullableObjectArrayType, nullable: false);
|
||||
|
||||
/// Dart types that have specialized Wasm representations.
|
||||
late final Map<Class, w.StorageType> builtinTypes = {
|
||||
|
@ -184,10 +188,10 @@ class Translator with KernelNodes {
|
|||
classInfo[listBaseClass]!.nonNullableType,
|
||||
|
||||
// Positional arguments
|
||||
classInfo[listBaseClass]!.nonNullableType,
|
||||
nullableObjectArrayTypeRef,
|
||||
|
||||
// Named arguments, represented as array of symbol and object pairs
|
||||
classInfo[listBaseClass]!.nonNullableType,
|
||||
nullableObjectArrayTypeRef,
|
||||
], [
|
||||
topInfo.nullableType
|
||||
]);
|
||||
|
@ -202,10 +206,10 @@ class Translator with KernelNodes {
|
|||
classInfo[listBaseClass]!.nonNullableType,
|
||||
|
||||
// Positional arguments
|
||||
classInfo[listBaseClass]!.nonNullableType,
|
||||
nullableObjectArrayTypeRef,
|
||||
|
||||
// Named arguments, represented as array of symbol and object pairs
|
||||
classInfo[listBaseClass]!.nonNullableType,
|
||||
nullableObjectArrayTypeRef,
|
||||
], [
|
||||
topInfo.nullableType
|
||||
]);
|
||||
|
@ -1029,16 +1033,12 @@ class Translator with KernelNodes {
|
|||
return arrayTypeRef;
|
||||
}
|
||||
|
||||
/// Indexes a Dart `List` on the stack.
|
||||
/// Indexes a Dart `_ListBase` on the stack.
|
||||
void indexList(
|
||||
w.InstructionsBuilder b, void pushIndex(w.InstructionsBuilder b)) {
|
||||
ClassInfo info = classInfo[listBaseClass]!;
|
||||
w.ArrayType arrayType =
|
||||
(info.struct.fields[FieldIndex.listArray].type as w.RefType).heapType
|
||||
as w.ArrayType;
|
||||
b.struct_get(info.struct, FieldIndex.listArray);
|
||||
getListBaseArray(b);
|
||||
pushIndex(b);
|
||||
b.array_get(arrayType);
|
||||
b.array_get(nullableObjectArrayType);
|
||||
}
|
||||
|
||||
/// Pushes a Dart `List`'s length onto the stack as `i32`.
|
||||
|
@ -1048,6 +1048,12 @@ class Translator with KernelNodes {
|
|||
b.i32_wrap_i64();
|
||||
}
|
||||
|
||||
/// Get the _ListBase._array field of type WasmArray<Object?>.
|
||||
void getListBaseArray(w.InstructionsBuilder b) {
|
||||
ClassInfo info = classInfo[listBaseClass]!;
|
||||
b.struct_get(info.struct, FieldIndex.listArray);
|
||||
}
|
||||
|
||||
ClassInfo getRecordClassInfo(RecordType recordType) =>
|
||||
classInfo[recordClasses[RecordShape.fromType(recordType)]!]!;
|
||||
|
||||
|
@ -1207,16 +1213,18 @@ class _ClosureDynamicEntryGenerator implements _FunctionGenerator {
|
|||
if (posIdx < positionalRequired) {
|
||||
// Shape check passed, argument must be passed
|
||||
b.local_get(posArgsListLocal);
|
||||
translator.indexList(b, (b) => b.i32_const(posIdx));
|
||||
b.i32_const(posIdx);
|
||||
b.array_get(translator.nullableObjectArrayType);
|
||||
} else {
|
||||
// Argument may be missing
|
||||
b.i32_const(posIdx);
|
||||
b.local_get(posArgsListLocal);
|
||||
translator.getListLength(b);
|
||||
b.array_len();
|
||||
b.i32_lt_u();
|
||||
b.if_([], [translator.topInfo.nullableType]);
|
||||
b.local_get(posArgsListLocal);
|
||||
translator.indexList(b, (b) => b.i32_const(posIdx));
|
||||
b.i32_const(posIdx);
|
||||
b.array_get(translator.nullableObjectArrayType);
|
||||
b.else_();
|
||||
translator.constants.instantiateConstant(function, b,
|
||||
paramInfo.positional[posIdx]!, translator.topInfo.nullableType);
|
||||
|
@ -1260,12 +1268,11 @@ class _ClosureDynamicEntryGenerator implements _FunctionGenerator {
|
|||
if (functionNodeDefaultValue == null && paramInfoDefaultValue == null) {
|
||||
// Shape check passed, parameter must be passed
|
||||
b.local_get(namedArgsListLocal);
|
||||
translator.indexList(b, (b) {
|
||||
b.local_get(namedArgValueIndexLocal);
|
||||
translator.convertType(
|
||||
function, namedArgValueIndexLocal.type, w.NumType.i64);
|
||||
b.i32_wrap_i64();
|
||||
});
|
||||
b.local_get(namedArgValueIndexLocal);
|
||||
translator.convertType(
|
||||
function, namedArgValueIndexLocal.type, w.NumType.i64);
|
||||
b.i32_wrap_i64();
|
||||
b.array_get(translator.nullableObjectArrayType);
|
||||
} else {
|
||||
// Parameter may not be passed.
|
||||
b.local_get(namedArgValueIndexLocal);
|
||||
|
@ -1289,12 +1296,11 @@ class _ClosureDynamicEntryGenerator implements _FunctionGenerator {
|
|||
}
|
||||
b.else_(); // value index not null
|
||||
b.local_get(namedArgsListLocal);
|
||||
translator.indexList(b, (b) {
|
||||
b.local_get(namedArgValueIndexLocal);
|
||||
translator.convertType(
|
||||
function, namedArgValueIndexLocal.type, w.NumType.i64);
|
||||
b.i32_wrap_i64();
|
||||
});
|
||||
b.local_get(namedArgValueIndexLocal);
|
||||
translator.convertType(
|
||||
function, namedArgValueIndexLocal.type, w.NumType.i64);
|
||||
b.i32_wrap_i64();
|
||||
b.array_get(translator.nullableObjectArrayType);
|
||||
b.end();
|
||||
translator.convertType(
|
||||
function, translator.topInfo.nullableType, targetInputs[inputIdx]);
|
||||
|
|
|
@ -8,7 +8,8 @@ part of "core_patch.dart";
|
|||
/// forwarder and returns the index of the value of that named parameter.
|
||||
/// Returns `null` if the name is not in the list.
|
||||
@pragma("wasm:entry-point")
|
||||
int? _getNamedParameterIndex(List<Object?> namedArguments, Symbol paramName) {
|
||||
int? _getNamedParameterIndex(
|
||||
WasmArray<Object?> namedArguments, Symbol paramName) {
|
||||
for (int i = 0; i < namedArguments.length; i += 2) {
|
||||
if (identical(namedArguments[i], paramName)) {
|
||||
return i + 1;
|
||||
|
@ -17,10 +18,21 @@ int? _getNamedParameterIndex(List<Object?> namedArguments, Symbol paramName) {
|
|||
return null;
|
||||
}
|
||||
|
||||
/// Converts a positional parameter list passed to a dynamic forwarder to a
|
||||
/// list that can be passed to `Invocation` constructors.
|
||||
@pragma("wasm:entry-point")
|
||||
List<Object?> _positionalParametersToList(WasmArray<Object?> positional) {
|
||||
final result = <Object?>[];
|
||||
for (int i = 0; i < positional.length; ++i) {
|
||||
result.add(positional[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Converts a named parameter list passed to a dynamic forwarder to a map that
|
||||
/// can be passed to `Invocation` constructors.
|
||||
@pragma("wasm:entry-point")
|
||||
Map<Symbol, Object?> _namedParameterListToMap(List<Object?> namedArguments) {
|
||||
Map<Symbol, Object?> _namedParametersToMap(WasmArray<Object?> namedArguments) {
|
||||
final Map<Symbol, Object?> map = {};
|
||||
for (int i = 0; i < namedArguments.length; i += 2) {
|
||||
map[namedArguments[i] as Symbol] = namedArguments[i + 1];
|
||||
|
@ -33,9 +45,10 @@ Map<Symbol, Object?> _namedParameterListToMap(List<Object?> namedArguments) {
|
|||
///
|
||||
/// This is the opposite of [_namedParameterListToMap].
|
||||
@pragma("wasm:entry-point")
|
||||
List<Object?> _namedParameterMapToList(Map<Symbol, Object?>? namedArguments) {
|
||||
WasmArray<Object?> _namedParameterMapToArray(
|
||||
Map<Symbol, Object?>? namedArguments) {
|
||||
if (namedArguments == null || namedArguments.isEmpty) {
|
||||
return const [];
|
||||
return const WasmArray.literal([]);
|
||||
}
|
||||
|
||||
final List<MapEntry<Symbol, Object?>> entries = namedArguments.entries
|
||||
|
@ -43,12 +56,12 @@ List<Object?> _namedParameterMapToList(Map<Symbol, Object?>? namedArguments) {
|
|||
..sort((entry1, entry2) =>
|
||||
_symbolToString(entry1.key).compareTo(_symbolToString(entry2.key)));
|
||||
|
||||
final List<Object?> list = [];
|
||||
final WasmArray<Object?> result = WasmArray<Object?>(2 * entries.length);
|
||||
|
||||
for (final entry in entries) {
|
||||
list.add(entry.key);
|
||||
list.add(entry.value);
|
||||
for (int i = 0; i < entries.length; ++i) {
|
||||
result[2 * i] = entries[i].key;
|
||||
result[2 * i + 1] = entries[i].value;
|
||||
}
|
||||
|
||||
return list;
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -70,15 +70,6 @@ extension on List<_Type> {
|
|||
}
|
||||
}
|
||||
|
||||
// Direct getter to bypass the covariance check and the bounds check when
|
||||
// indexing into a Dart list. This makes the indexing more efficient and avoids
|
||||
// performing type checks while performing type checks.
|
||||
extension _BypassListIndexingChecks<T> on List<T> {
|
||||
@pragma("wasm:prefer-inline")
|
||||
T _getUnchecked(int index) =>
|
||||
unsafeCast(unsafeCast<_ListBase<T>>(this)._data[index]);
|
||||
}
|
||||
|
||||
// TODO(joshualitt): We can cache the result of [_FutureOrType.asFuture].
|
||||
abstract class _Type implements Type {
|
||||
final bool isDeclaredNullable;
|
||||
|
@ -1175,7 +1166,7 @@ class _TypeCheckVerificationError extends Error {
|
|||
/// [namedArguments] is a list of `Symbol` and `Object?` pairs.
|
||||
@pragma("wasm:entry-point")
|
||||
bool _checkClosureShape(_FunctionType functionType, List<_Type> typeArguments,
|
||||
List<Object?> positionalArguments, List<dynamic> namedArguments) {
|
||||
WasmArray<Object?> positionalArguments, WasmArray<dynamic> namedArguments) {
|
||||
// Check type args, add default types to the type list if its empty
|
||||
if (typeArguments.isEmpty) {
|
||||
final defaults = functionType.typeParameterDefaults;
|
||||
|
@ -1208,8 +1199,7 @@ bool _checkClosureShape(_FunctionType functionType, List<_Type> typeArguments,
|
|||
continue;
|
||||
}
|
||||
|
||||
String argName = _symbolToString(
|
||||
namedArguments._getUnchecked(namedArgIdx * 2) as Symbol);
|
||||
String argName = _symbolToString(namedArguments[namedArgIdx * 2] as Symbol);
|
||||
|
||||
final cmp = argName.compareTo(param.name);
|
||||
|
||||
|
@ -1247,7 +1237,7 @@ bool _checkClosureShape(_FunctionType functionType, List<_Type> typeArguments,
|
|||
/// [namedArguments] is a list of `Symbol` and `Object?` pairs.
|
||||
@pragma("wasm:entry-point")
|
||||
void _checkClosureType(_FunctionType functionType, List<_Type> typeArguments,
|
||||
List<Object?> positionalArguments, List<dynamic> namedArguments) {
|
||||
WasmArray<Object?> positionalArguments, WasmArray<dynamic> namedArguments) {
|
||||
assert(functionType.typeParameterBounds.length == typeArguments.length);
|
||||
|
||||
if (!typeArguments.isEmpty) {
|
||||
|
@ -1272,7 +1262,7 @@ void _checkClosureType(_FunctionType functionType, List<_Type> typeArguments,
|
|||
|
||||
// Check positional arguments
|
||||
for (int i = 0; i < positionalArguments.length; i += 1) {
|
||||
final Object? arg = positionalArguments._getUnchecked(i);
|
||||
final Object? arg = positionalArguments[i];
|
||||
final _Type paramTy = functionType.positionalParameters[i];
|
||||
if (!_isSubtype(arg, paramTy)) {
|
||||
// TODO(50991): Positional parameter names not available in runtime
|
||||
|
@ -1286,10 +1276,10 @@ void _checkClosureType(_FunctionType functionType, List<_Type> typeArguments,
|
|||
int namedParamIdx = 0;
|
||||
int namedArgIdx = 0;
|
||||
while (namedArgIdx * 2 < namedArguments.length) {
|
||||
final String argName = _symbolToString(
|
||||
namedArguments._getUnchecked(namedArgIdx * 2) as Symbol);
|
||||
final String argName =
|
||||
_symbolToString(namedArguments[namedArgIdx * 2] as Symbol);
|
||||
if (argName == functionType.namedParameters[namedParamIdx].name) {
|
||||
final arg = namedArguments._getUnchecked(namedArgIdx * 2 + 1);
|
||||
final arg = namedArguments[namedArgIdx * 2 + 1];
|
||||
final paramTy = functionType.namedParameters[namedParamIdx].type;
|
||||
if (!_isSubtype(arg, paramTy)) {
|
||||
_TypeError._throwArgumentTypeCheckError(
|
||||
|
|
Loading…
Reference in a new issue