diff --git a/pkg/dart2wasm/lib/class_info.dart b/pkg/dart2wasm/lib/class_info.dart index 44650e67d70..b683be712ab 100644 --- a/pkg/dart2wasm/lib/class_info.dart +++ b/pkg/dart2wasm/lib/class_info.dart @@ -7,7 +7,6 @@ import 'dart:math'; import 'package:dart2wasm/translator.dart'; import 'package:kernel/ast.dart'; -import 'package:kernel/library_index.dart'; import 'package:wasm_builder/wasm_builder.dart' as w; @@ -217,25 +216,25 @@ class ClassInfoCollector { /// shape class with that many fields. final Map _recordStructs = {}; - /// Masquerades for implementation classes. For each entry of the map, all - /// subtypes of the key masquerade as the value. - late final Map _masquerades = _computeMasquerades(); + /// Any subtype of these needs to masqueraded (modulo special js-compatibility + /// mode semantics) or specially treated due to being from a different type + /// (e.g. record, closure) + late final Set masqueraded = _computeMasquerades(); - /// Masqueraded types are mapped to these classes. - late final Set masqueradeValues = _masquerades.values.toSet(); - - Map _computeMasquerades() { - final map = { - translator.coreTypes.boolClass: translator.coreTypes.boolClass, - translator.coreTypes.intClass: translator.coreTypes.intClass, - translator.coreTypes.doubleClass: translator.coreTypes.doubleClass, - translator.coreTypes.stringClass: translator.coreTypes.stringClass, - translator.index.getClass("dart:core", "_Type"): - translator.coreTypes.typeClass, - translator.index.getClass("dart:core", "_ListBase"): - translator.coreTypes.listClass + Set _computeMasquerades() { + final values = { + translator.coreTypes.boolClass, + translator.coreTypes.intClass, + translator.coreTypes.doubleClass, + translator.coreTypes.stringClass, + translator.coreTypes.functionClass, + translator.coreTypes.recordClass, + translator.index.getClass("dart:core", "_Type"), + translator.index.getClass("dart:core", "_ListBase"), }; for (final name in const [ + "ByteBuffer", + "ByteData", "Int8List", "Uint8List", "Uint8ClampedList", @@ -252,49 +251,9 @@ class ClassInfoCollector { "Float64x2List", ]) { final Class? cls = translator.index.tryGetClass("dart:typed_data", name); - if (cls != null) { - map[cls] = cls; - } + if (cls != null) values.add(cls); } - return map; - } - - late final Set _neverMasquerades = _computeNeverMasquerades(); - - /// These types switch from properly reified non-masquerading types in regular - /// Dart2Wasm mode to masquerading types in js compatibility mode. - final Set jsCompatibilityTypes = { - "JSStringImpl", - "JSArrayBufferImpl", - "JSDataViewImpl", - "JSInt8ArrayImpl", - "JSUint8ArrayImpl", - "JSUint8ClampedArrayImpl", - "JSInt16ArrayImpl", - "JSUint16ArrayImpl", - "JSInt32ArrayImpl", - "JSInt32x4ArrayImpl", - "JSUint32ArrayImpl", - "JSBigUint64ArrayImpl", - "JSBigInt64ArrayImpl", - "JSFloat32ArrayImpl", - "JSFloat32x4ArrayImpl", - "JSFloat64ArrayImpl", - "JSFloat64x2ArrayImpl", - }; - - Set _computeNeverMasquerades() { - // The JS types do not masquerade in regular Dart2Wasm, but they aren't - // always used so we have to construct this set programmatically. - final jsTypesLibraryIndex = - LibraryIndex(translator.component, ["dart:_js_types"]); - final neverMasquerades = [ - if (!translator.options.jsCompatibility) ...jsCompatibilityTypes, - ] - .map((name) => jsTypesLibraryIndex.tryGetClass("dart:_js_types", name)) - .toSet(); - neverMasquerades.removeWhere((c) => c == null); - return neverMasquerades.cast(); + return values; } /// Wasm field type for fields with type [_Type]. Fields of this type are @@ -341,14 +300,14 @@ class ClassInfoCollector { } // In the Wasm type hierarchy, Object, bool and num sit directly below - // the Top type. The implementation classes _StringBase and _Type sit + // the Top type. The implementation classes WasmStringBase and _Type sit // directly below the public classes they implement. // All other classes sit below their superclass. ClassInfo superInfo = cls == translator.coreTypes.boolClass || cls == translator.coreTypes.numClass ? topInfo : (!translator.options.jsCompatibility && - cls == translator.stringBaseClass) || + cls == translator.wasmStringBaseClass) || cls == translator.typeClass ? translator.classInfo[cls.implementedTypes.single.classNode]! : translator.classInfo[superclass]!; @@ -390,29 +349,6 @@ class ClassInfoCollector { translator.classes[classId] = info; translator.classInfo[cls] = info; translator.classForHeapType.putIfAbsent(info.struct, () => info!); - - ClassInfo? computeMasquerade() { - if (_neverMasquerades.contains(cls)) { - return null; - } - if (info!.superInfo?.masquerade != null) { - return info.superInfo!.masquerade; - } - for (Supertype implemented in cls.implementedTypes) { - ClassInfo? implementedMasquerade = - translator.classInfo[implemented.classNode]!.masquerade; - if (implementedMasquerade != null) { - return implementedMasquerade; - } - } - Class? selfMasquerade = _masquerades[cls]; - if (selfMasquerade != null) { - return translator.classInfo[selfMasquerade]!; - } - return null; - } - - info.masquerade = computeMasquerade(); } void _createStructForRecordClass(Map classIds, Class cls) { @@ -505,7 +441,7 @@ class ClassInfoCollector { const int firstClassId = 1; translator.classIdNumbering = - ClassIdNumbering._number(translator, masqueradeValues, firstClassId); + ClassIdNumbering._number(translator, masqueraded, firstClassId); final classIds = translator.classIdNumbering.classIds; final dfsOrder = translator.classIdNumbering.dfsOrder; @@ -560,12 +496,18 @@ class ClassIdNumbering { final Map> _subclasses; final Map> _implementors; final List _concreteSubclassIdRanges; + final Set _masqueraded; final List dfsOrder; final Map classIds; - ClassIdNumbering._(this._subclasses, this._implementors, - this._concreteSubclassIdRanges, this.dfsOrder, this.classIds); + ClassIdNumbering._( + this._subclasses, + this._implementors, + this._concreteSubclassIdRanges, + this._masqueraded, + this.dfsOrder, + this.classIds); final Map> _transitiveImplementors = {}; Set _getTransitiveImplementors(Class klass) { @@ -611,8 +553,19 @@ class ClassIdNumbering { return _concreteClassIdRanges[klass] = ranges; } + late final int firstNonMasqueradedInterfaceClassCid = (() { + int lastMasqueradedClassId = 0; + for (final cls in _masqueraded) { + final ranges = getConcreteClassIdRanges(cls); + if (ranges.isNotEmpty) { + lastMasqueradedClassId = max(lastMasqueradedClassId, ranges.last.end); + } + } + return lastMasqueradedClassId + 1; + })(); + static ClassIdNumbering _number( - Translator translator, Set masqueradeValues, int firstClassId) { + Translator translator, Set masqueraded, int firstClassId) { // Make graph from class to its subclasses. late final Class root; final subclasses = >{}; @@ -645,7 +598,8 @@ class ClassIdNumbering { final fixedOrder = { translator.coreTypes.boolClass: -10, translator.coreTypes.numClass: -9, - if (!translator.options.jsCompatibility) translator.stringBaseClass: -8, + if (!translator.options.jsCompatibility) + translator.wasmStringBaseClass: -8, translator.jsStringClass: -7, translator.typeClass: -6, translator.listBaseClass: -5, @@ -657,7 +611,7 @@ class ClassIdNumbering { final importUri = klass.enclosingLibrary.importUri.toString(); if (importUri.startsWith('dart:')) { - if (masqueradeValues.contains(klass)) return -1; + if (masqueraded.contains(klass)) return -1; // Bundle the typed data and collection together, they may not have // common base class except for `Object` but most of them have similar // selectors. @@ -700,26 +654,8 @@ class ClassIdNumbering { firstClassId + classCount, Range.empty(), growable: false); - // TODO: We may consider removing the type category table. But until we do - // we have to make sure that all masqueraded types that concrete classes may - // be mapped to have class ids that are <=255. - // - // We still want to maintain that all classes's concrete subclasses form a - // single continious class-id range. - // - // => So we move the abstract masqeraded classes before all the concrete - // ones. - int nextAbstractClassId = firstClassId; - for (Class cls in masqueradeValues) { - if (cls.isAbstract) { - assert(classIds[cls] == null); - classIds[cls] = nextAbstractClassId++; - } - } - int nextConcreteClassId = nextAbstractClassId; - nextAbstractClassId = firstClassId + - (nextAbstractClassId - firstClassId) + - concreteClassCount; + int nextConcreteClassId = firstClassId; + int nextAbstractClassId = firstClassId + concreteClassCount; dfs(root, (Class cls) { dfsOrder.add(cls); if (cls.isAbstract) { @@ -740,11 +676,9 @@ class ClassIdNumbering { concreteSubclassRanges[classIds[cls]!] = range; } }); - for (Class cls in masqueradeValues) { - assert(classIds[cls]! <= 255); - } - return ClassIdNumbering._( - subclasses, implementors, concreteSubclassRanges, dfsOrder, classIds); + + return ClassIdNumbering._(subclasses, implementors, concreteSubclassRanges, + masqueraded, dfsOrder, classIds); } } diff --git a/pkg/dart2wasm/lib/code_generator.dart b/pkg/dart2wasm/lib/code_generator.dart index 509ff61137e..6d2e8a42931 100644 --- a/pkg/dart2wasm/lib/code_generator.dart +++ b/pkg/dart2wasm/lib/code_generator.dart @@ -3803,3 +3803,46 @@ enum _VirtualCallKind { bool get isSetter => this == _VirtualCallKind.Set; } + +extension MacroAssembler on w.InstructionsBuilder { + // Expects there to be a i32 on the stack, will consume it and leave + // true/false on the stack. + void emitClassIdRangeCheck(CodeGenerator codeGen, List ranges) { + if (ranges.isEmpty) { + drop(); + i32_const(0); + } else if (ranges.length == 1) { + final range = ranges[0]; + + i32_const(range.start); + if (range.length == 1) { + i32_eq(); + } else { + i32_sub(); + i32_const(range.length); + i32_lt_u(); + } + } else { + w.Local idLocal = codeGen.addLocal(w.NumType.i32); + local_set(idLocal); + w.Label done = block(const [], const [w.NumType.i32]); + i32_const(1); + + for (Range range in ranges) { + local_get(idLocal); + i32_const(range.start); + if (range.length == 1) { + i32_eq(); + } else { + i32_sub(); + i32_const(range.length); + i32_lt_u(); + } + br_if(done); + } + drop(); + i32_const(0); + end(); // done + } + } +} diff --git a/pkg/dart2wasm/lib/compiler_options.dart b/pkg/dart2wasm/lib/compiler_options.dart index f7377f7f25c..992d55ef2c7 100644 --- a/pkg/dart2wasm/lib/compiler_options.dart +++ b/pkg/dart2wasm/lib/compiler_options.dart @@ -18,7 +18,7 @@ class WasmCompilerOptions { String outputFile; String? depFile; String? outputJSRuntimeFile; - Map environment = const {}; + Map environment = {}; Map feExperimentalFlags = const {}; String? multiRootScheme; List multiRoots = const []; diff --git a/pkg/dart2wasm/lib/dart2wasm.dart b/pkg/dart2wasm/lib/dart2wasm.dart index 7fb8339d41a..2c9d8c1173c 100644 --- a/pkg/dart2wasm/lib/dart2wasm.dart +++ b/pkg/dart2wasm/lib/dart2wasm.dart @@ -36,9 +36,10 @@ final List