mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 17:40:04 +00:00
Use WasmObjectArray instead of List in RTT metadata
This reduces flute's complex.dart slightly complex.wasm 1596131 -> 1563506 (-2%) complex.wasm.unopt 3562573 -> 3535797 (-0.7%) And makes the code probably slightly faster Change-Id: Id35f2b156d39b6e77b62240a83f78914999bb744 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/340565 Commit-Queue: Martin Kustermann <kustermann@google.com> Reviewed-by: Ömer Ağacan <omersa@google.com>
This commit is contained in:
parent
17f4344336
commit
72f6db9261
|
@ -93,6 +93,16 @@ class Constants {
|
|||
ListConstant(elementType, entries),
|
||||
});
|
||||
|
||||
/// Creates a `WasmIntArray<T>` with the given [Constant]s
|
||||
InstanceConstant makeIntArrayOf(
|
||||
InterfaceType elementType, List<IntConstant> entries) =>
|
||||
InstanceConstant(translator.wasmIntArrayClass.reference, [
|
||||
elementType,
|
||||
], {
|
||||
translator.wasmIntArrayValueField.fieldReference:
|
||||
ListConstant(elementType, entries),
|
||||
});
|
||||
|
||||
/// Ensure that the constant has a Wasm global assigned.
|
||||
///
|
||||
/// Sub-constants must have Wasm globals assigned before the global for the
|
||||
|
@ -186,6 +196,10 @@ class ConstantInstantiator extends ConstantVisitor<w.ValueType>
|
|||
@override
|
||||
w.ValueType visitIntConstant(IntConstant constant) {
|
||||
if (expectedType is w.RefType) return defaultConstant(constant);
|
||||
if (expectedType == w.NumType.i32) {
|
||||
b.i32_const(constant.value);
|
||||
return w.NumType.i32;
|
||||
}
|
||||
b.i64_const(constant.value);
|
||||
return w.NumType.i64;
|
||||
}
|
||||
|
@ -382,6 +396,9 @@ class ConstantCreator extends ConstantVisitor<ConstantInfo?>
|
|||
if (cls == translator.wasmObjectArrayClass) {
|
||||
return _makeWasmArrayLiteral(constant);
|
||||
}
|
||||
if (cls == translator.wasmIntArrayClass) {
|
||||
return _makeWasmArrayLiteral(constant);
|
||||
}
|
||||
|
||||
ClassInfo info = translator.classInfo[cls]!;
|
||||
translator.functions.allocateClass(info.classId);
|
||||
|
|
|
@ -973,6 +973,7 @@ class Intrinsifier {
|
|||
b.local_set(receiverLocal);
|
||||
|
||||
ClassInfo newInfo = translator.classInfo[newClass]!;
|
||||
translator.functions.allocateClass(newInfo.classId);
|
||||
b.i32_const(newInfo.classId);
|
||||
b.i32_const(initialIdentityHash);
|
||||
b.local_get(receiverLocal);
|
||||
|
@ -993,8 +994,10 @@ class Intrinsifier {
|
|||
w.ValueType? generateConstructorIntrinsic(ConstructorInvocation node) {
|
||||
String name = node.name.text;
|
||||
|
||||
// WasmObjectArray.literal
|
||||
if (node.target.enclosingClass == translator.wasmObjectArrayClass &&
|
||||
// WasmObjectArray.literal & WasmIntArray.literal
|
||||
final klass = node.target.enclosingClass;
|
||||
if ((klass == translator.wasmObjectArrayClass ||
|
||||
klass == translator.wasmIntArrayClass) &&
|
||||
name == "literal") {
|
||||
w.ArrayType arrayType =
|
||||
translator.arrayTypeForDartType(node.arguments.types.single);
|
||||
|
|
|
@ -153,6 +153,10 @@ mixin KernelNodes {
|
|||
index.getClass("dart:_wasm", "WasmObjectArray");
|
||||
late final Field wasmObjectArrayValueField =
|
||||
index.getField("dart:_wasm", "WasmObjectArray", "_value");
|
||||
late final Class wasmIntArrayClass =
|
||||
index.getClass("dart:_wasm", "WasmIntArray");
|
||||
late final Field wasmIntArrayValueField =
|
||||
index.getField("dart:_wasm", "WasmIntArray", "_value");
|
||||
|
||||
// dart:_internal procedures
|
||||
late final Procedure loadLibrary =
|
||||
|
|
|
@ -224,69 +224,84 @@ class Types {
|
|||
/// TODO(joshualitt): This implementation is just temporary. Eventually we
|
||||
/// should move to a data structure more closely resembling [typeRules].
|
||||
w.ValueType makeTypeRulesSupers(w.InstructionsBuilder b) {
|
||||
w.ValueType expectedType =
|
||||
translator.classInfo[translator.immutableListClass]!.nonNullableType;
|
||||
DartType listIntType = InterfaceType(translator.immutableListClass,
|
||||
Nullability.nonNullable, [translator.coreTypes.intNonNullableRawType]);
|
||||
List<ListConstant> listIntConstant = [];
|
||||
final wasmI32Type =
|
||||
InterfaceType(translator.wasmI32Class, Nullability.nonNullable);
|
||||
|
||||
final supersOfClasses = <Constant>[];
|
||||
for (List<int> supers in typeRulesSupers) {
|
||||
listIntConstant.add(ListConstant(
|
||||
listIntType, supers.map((i) => IntConstant(i)).toList()));
|
||||
supersOfClasses.add(translator.constants.makeIntArrayOf(
|
||||
wasmI32Type, [for (final cid in supers) IntConstant(cid)]));
|
||||
}
|
||||
DartType listListIntType = InterfaceType(
|
||||
translator.immutableListClass, Nullability.nonNullable, [listIntType]);
|
||||
translator.constants.instantiateConstant(
|
||||
null, b, ListConstant(listListIntType, listIntConstant), expectedType);
|
||||
return expectedType;
|
||||
|
||||
final arrayOfWasmI32Type = InterfaceType(
|
||||
translator.wasmIntArrayClass, Nullability.nonNullable, [wasmI32Type]);
|
||||
final typeRuleSupers =
|
||||
translator.constants.makeArrayOf(arrayOfWasmI32Type, supersOfClasses);
|
||||
|
||||
final arrayOfArrayOfWasmI32Type = InterfaceType(
|
||||
translator.wasmObjectArrayClass,
|
||||
Nullability.nonNullable,
|
||||
[arrayOfWasmI32Type]);
|
||||
|
||||
final typeRulesSupersType =
|
||||
translator.translateStorageType(arrayOfArrayOfWasmI32Type).unpacked;
|
||||
translator.constants
|
||||
.instantiateConstant(null, b, typeRuleSupers, typeRulesSupersType);
|
||||
return typeRulesSupersType;
|
||||
}
|
||||
|
||||
/// Similar to the above, but provides the substitutions required for each
|
||||
/// supertype.
|
||||
/// TODO(joshualitt): Like [makeTypeRulesSupers], this is just temporary.
|
||||
w.ValueType makeTypeRulesSubstitutions(w.InstructionsBuilder b) {
|
||||
w.ValueType expectedType =
|
||||
translator.classInfo[translator.immutableListClass]!.nonNullableType;
|
||||
DartType listTypeType = InterfaceType(
|
||||
translator.immutableListClass,
|
||||
final typeType =
|
||||
InterfaceType(translator.typeClass, Nullability.nonNullable);
|
||||
final arrayOfType = InterfaceType(
|
||||
translator.wasmObjectArrayClass, Nullability.nonNullable, [typeType]);
|
||||
final arrayOfArrayOfType = InterfaceType(translator.wasmObjectArrayClass,
|
||||
Nullability.nonNullable, [arrayOfType]);
|
||||
final arrayOfArrayOfArrayOfType = InterfaceType(
|
||||
translator.wasmObjectArrayClass,
|
||||
Nullability.nonNullable,
|
||||
[translator.typeClass.getThisType(coreTypes, Nullability.nonNullable)]);
|
||||
DartType listListTypeType = InterfaceType(
|
||||
translator.immutableListClass, Nullability.nonNullable, [listTypeType]);
|
||||
DartType listListListTypeType = InterfaceType(translator.immutableListClass,
|
||||
Nullability.nonNullable, [listListTypeType]);
|
||||
List<ListConstant> substitutionsConstantL0 = [];
|
||||
[arrayOfArrayOfType]);
|
||||
|
||||
final substitutionsConstantL0 = <Constant>[];
|
||||
for (List<List<DartType>> substitutionsL1 in typeRulesSubstitutions) {
|
||||
List<ListConstant> substitutionsConstantL1 = [];
|
||||
final substitutionsConstantL1 = <Constant>[];
|
||||
for (List<DartType> substitutionsL2 in substitutionsL1) {
|
||||
substitutionsConstantL1.add(ListConstant(listTypeType,
|
||||
substitutionsL2.map((t) => TypeLiteralConstant(t)).toList()));
|
||||
substitutionsConstantL1.add(translator.constants.makeArrayOf(typeType,
|
||||
[for (final t in substitutionsL2) TypeLiteralConstant(t)]));
|
||||
}
|
||||
substitutionsConstantL0
|
||||
.add(ListConstant(listListTypeType, substitutionsConstantL1));
|
||||
substitutionsConstantL0.add(translator.constants
|
||||
.makeArrayOf(arrayOfType, substitutionsConstantL1));
|
||||
}
|
||||
|
||||
final typeRulesSubstitutionsType =
|
||||
translator.translateStorageType(arrayOfArrayOfArrayOfType).unpacked;
|
||||
translator.constants.instantiateConstant(
|
||||
null,
|
||||
b,
|
||||
ListConstant(listListListTypeType, substitutionsConstantL0),
|
||||
expectedType);
|
||||
return expectedType;
|
||||
translator.constants
|
||||
.makeArrayOf(arrayOfArrayOfType, substitutionsConstantL0),
|
||||
typeRulesSubstitutionsType);
|
||||
return typeRulesSubstitutionsType;
|
||||
}
|
||||
|
||||
/// Returns a list of string type names for pretty printing types.
|
||||
w.ValueType makeTypeNames(w.InstructionsBuilder b) {
|
||||
w.ValueType expectedType =
|
||||
translator.classInfo[translator.immutableListClass]!.nonNullableType;
|
||||
List<StringConstant> listStringConstant = [];
|
||||
for (String name in typeNames) {
|
||||
listStringConstant.add(StringConstant(name));
|
||||
}
|
||||
DartType listStringType = InterfaceType(
|
||||
translator.immutableListClass,
|
||||
Nullability.nonNullable,
|
||||
[translator.coreTypes.stringNonNullableRawType]);
|
||||
translator.constants.instantiateConstant(null, b,
|
||||
ListConstant(listStringType, listStringConstant), expectedType);
|
||||
return expectedType;
|
||||
final stringType =
|
||||
translator.coreTypes.stringRawType(Nullability.nonNullable);
|
||||
final arrayOfStringType = InterfaceType(
|
||||
translator.wasmObjectArrayClass, Nullability.nonNullable, [stringType]);
|
||||
|
||||
final arrayOfStrings = translator.constants.makeArrayOf(
|
||||
stringType, [for (final name in typeNames) StringConstant(name)]);
|
||||
|
||||
final typeNamesType =
|
||||
translator.translateStorageType(arrayOfStringType).unpacked;
|
||||
translator.constants
|
||||
.instantiateConstant(null, b, arrayOfStrings, typeNamesType);
|
||||
return typeNamesType;
|
||||
}
|
||||
|
||||
/// Build a global array of byte values used to categorize runtime types.
|
||||
|
|
|
@ -65,6 +65,26 @@ extension on WasmObjectArray<_NamedParameter> {
|
|||
}
|
||||
}
|
||||
|
||||
extension on WasmObjectArray<String> {
|
||||
@pragma("wasm:prefer-inline")
|
||||
String operator [](int index) => read(index);
|
||||
}
|
||||
|
||||
extension on WasmObjectArray<WasmIntArray<WasmI32>> {
|
||||
@pragma("wasm:prefer-inline")
|
||||
WasmIntArray<WasmI32> operator [](int index) => read(index);
|
||||
}
|
||||
|
||||
extension on WasmObjectArray<WasmObjectArray<_Type>> {
|
||||
@pragma("wasm:prefer-inline")
|
||||
WasmObjectArray<_Type> operator [](int index) => read(index);
|
||||
}
|
||||
|
||||
extension on WasmObjectArray<WasmObjectArray<WasmObjectArray<_Type>>> {
|
||||
@pragma("wasm:prefer-inline")
|
||||
WasmObjectArray<WasmObjectArray<_Type>> operator [](int index) => read(index);
|
||||
}
|
||||
|
||||
// TODO: Remove any occurence of `List`s in this file.
|
||||
extension on List<_Type> {
|
||||
@pragma("wasm:prefer-inline")
|
||||
|
@ -630,9 +650,10 @@ class _RecordType extends _Type {
|
|||
identical(names, other.names);
|
||||
}
|
||||
|
||||
external List<List<int>> _getTypeRulesSupers();
|
||||
external List<List<List<_Type>>> _getTypeRulesSubstitutions();
|
||||
external List<String> _getTypeNames();
|
||||
external WasmObjectArray<WasmIntArray<WasmI32>> _getTypeRulesSupers();
|
||||
external WasmObjectArray<WasmObjectArray<WasmObjectArray<_Type>>>
|
||||
_getTypeRulesSubstitutions();
|
||||
external WasmObjectArray<String> _getTypeNames();
|
||||
|
||||
/// Type parameter environment used while comparing function types.
|
||||
///
|
||||
|
@ -681,11 +702,12 @@ class _Environment {
|
|||
|
||||
class _TypeUniverse {
|
||||
/// 'Map' of classId to the transitive set of super classes it implements.
|
||||
final List<List<int>> typeRulesSupers;
|
||||
final WasmObjectArray<WasmIntArray<WasmI32>> typeRulesSupers;
|
||||
|
||||
/// 'Map' of classId, and super offset(from [typeRulesSupers]) to a list of
|
||||
/// type substitutions.
|
||||
final List<List<List<_Type>>> typeRulesSubstitutions;
|
||||
final WasmObjectArray<WasmObjectArray<WasmObjectArray<_Type>>>
|
||||
typeRulesSubstitutions;
|
||||
|
||||
const _TypeUniverse._(this.typeRulesSupers, this.typeRulesSubstitutions);
|
||||
|
||||
|
@ -870,21 +892,21 @@ class _TypeUniverse {
|
|||
|
||||
// Otherwise, check if [s] is a subtype of [t], and if it is then compare
|
||||
// [s]'s type substitutions with [t]'s type arguments.
|
||||
List<int> sSupers = typeRulesSupers._getUnchecked(sId);
|
||||
if (sSupers.isEmpty) return false;
|
||||
final WasmIntArray<WasmI32> sSupers = typeRulesSupers[sId];
|
||||
if (sSupers.length == 0) return false;
|
||||
int sSuperIndexOfT = -1;
|
||||
for (int i = 0; i < sSupers.length; i++) {
|
||||
if (sSupers._getUnchecked(i) == tId) {
|
||||
if (sSupers.readUnsigned(i) == tId) {
|
||||
sSuperIndexOfT = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sSuperIndexOfT == -1) return false;
|
||||
assert(sSuperIndexOfT < typeRulesSubstitutions._getUnchecked(sId).length);
|
||||
assert(sSuperIndexOfT < typeRulesSubstitutions[sId].length);
|
||||
|
||||
// Return early if we don't have to check type arguments.
|
||||
List<_Type> substitutions =
|
||||
typeRulesSubstitutions._getUnchecked(sId)._getUnchecked(sSuperIndexOfT);
|
||||
WasmObjectArray<_Type> substitutions =
|
||||
typeRulesSubstitutions[sId][sSuperIndexOfT];
|
||||
if (substitutions.isEmpty && sTypeArguments.isEmpty) {
|
||||
return true;
|
||||
}
|
||||
|
@ -904,7 +926,7 @@ class _TypeUniverse {
|
|||
WasmObjectArray<_Type>(substitutions.length, _literal<dynamic>());
|
||||
for (int i = 0; i < substitutions.length; i++) {
|
||||
substituted[i] = substituteTypeArgument(
|
||||
substitutions._getUnchecked(i), typeArgumentsForSubstitution, null);
|
||||
substitutions[i], typeArgumentsForSubstitution, null);
|
||||
}
|
||||
return areTypeArgumentsSubtypes(substituted, sEnv, t.typeArguments, tEnv);
|
||||
}
|
||||
|
|
|
@ -194,8 +194,14 @@ class WasmF64 extends _WasmFloat {
|
|||
/// A Wasm array with integer element type.
|
||||
@pragma("wasm:entry-point")
|
||||
class WasmIntArray<T extends _WasmInt> extends WasmArrayRef {
|
||||
/// Dummy value field to contain the value for constant instances.
|
||||
@pragma("wasm:entry-point")
|
||||
final List<int> _value;
|
||||
|
||||
external factory WasmIntArray(int length);
|
||||
|
||||
const WasmIntArray.literal(this._value) : super._();
|
||||
|
||||
external int readSigned(int index);
|
||||
external int readUnsigned(int index);
|
||||
external void write(int index, int value);
|
||||
|
|
|
@ -144,6 +144,15 @@ test() {
|
|||
Expect.notIdentical(arrayAlit3.read(0), arrayAlit3.read(1));
|
||||
Expect.identical(arrayAlit3.read(0), arrayAlit3.read(2));
|
||||
|
||||
final int32Array = WasmIntArray<WasmI32>.literal([0, 1, 2, 3]);
|
||||
final int32ArrayC = const WasmIntArray<WasmI32>.literal([0, 10, 20, 30]);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
Expect.equals(int32Array.readSigned(i), i);
|
||||
}
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
Expect.equals(int32ArrayC.readSigned(i), i * 10);
|
||||
}
|
||||
|
||||
Expect.isFalse(arrayA == arrayAlit1);
|
||||
Expect.isFalse(arrayAlit2 == arrayAlit3);
|
||||
Expect.isTrue(arrayAlit3 == arrayAlit4);
|
||||
|
|
Loading…
Reference in a new issue