Skip to content

Commit

Permalink
Reland "[dart2wasm] Use row displacement table for representing RTT c…
Browse files Browse the repository at this point in the history
…lass relationships"

No changes from original CL.

Original CL description:

  The main RTT information we need is whether a subclass is that of
  another and if so how to translate type arguments from the subclass to
  the super class.

  This CL switches the data structure we use to represent this
  relationship to a row-displacement table (simlar to how we do method
  dispatch).

  => With two array lookups we can determine if a class is a superclass of
  another
  => With one more array lookup we obtain the type argument substitution
  array.

  The packing of the row displacement table is 80-90%.

  Issue #55516

  Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/374720
Change-Id: I7ef7f74d999fd211f075a47dffaa7c9c3d5f2a30
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/375281
Commit-Queue: Martin Kustermann <[email protected]>
Reviewed-by: Slava Egorov <[email protected]>
  • Loading branch information
mkustermann authored and Commit Queue committed Jul 11, 2024
1 parent 48599f5 commit 3b62508
Show file tree
Hide file tree
Showing 5 changed files with 285 additions and 188 deletions.
119 changes: 84 additions & 35 deletions pkg/dart2wasm/lib/dispatch_table.dart
Original file line number Diff line number Diff line change
Expand Up @@ -411,7 +411,7 @@ class DispatchTable {
(selector.callCount > 0 && selector.targetCount > 1) ||
(selector.paramInfo.member! == translator.objectNoSuchMethod);

List<SelectorInfo> selectors =
final List<SelectorInfo> selectors =
_selectorInfo.values.where(needsDispatch).toList();

// Sort the selectors based on number of targets and number of use sites.
Expand All @@ -428,40 +428,19 @@ class DispatchTable {

selectors.sort((a, b) => selectorSortWeight(b) - selectorSortWeight(a));

int firstAvailable = 0;
_table = [];
bool first = true;
for (SelectorInfo selector in selectors) {
int offset = first ? 0 : firstAvailable - selector.classIds.first;
first = false;
bool fits;
do {
fits = true;
for (int classId in selector.classIds) {
int entry = offset + classId;
if (entry >= _table.length) {
// Fits
break;
}
if (_table[entry] != null) {
fits = false;
break;
}
}
if (!fits) offset++;
} while (!fits);
selector.offset = offset;
for (int classId in selector.classIds) {
int entry = offset + classId;
while (_table.length <= entry) {
_table.add(null);
}
assert(_table[entry] == null);
_table[entry] = selector.targets[classId];
}
while (firstAvailable < _table.length && _table[firstAvailable] != null) {
firstAvailable++;
}
final rows = <Row<Reference>>[];
for (final selector in selectors) {
final rowValues = <({int index, Reference value})>[];
selector.targets.forEach((int classId, Reference target) {
rowValues.add((index: classId, value: target));
});
rowValues.sort((a, b) => a.index.compareTo(b.index));
rows.add(Row(rowValues));
}

_table = buildRowDisplacementTable<Reference>(rows);
for (int i = 0; i < rows.length; ++i) {
selectors[i].offset = rows[i].offset;
}

wasmTable = m.tables.define(w.RefType.func(nullable: true), _table.length);
Expand All @@ -479,3 +458,73 @@ class DispatchTable {
}
}
}

/// Build a row-displacement table based on fitting the [rows].
///
/// The returned list is the resulting row displacement table with `null`
/// entries representing unused space.
///
/// The offset of all [Row]s will be initialized.
List<V?> buildRowDisplacementTable<V extends Object>(List<Row<V>> rows,
{int firstAvailable = 0}) {
final table = <V?>[];
for (final row in rows) {
final values = row.values;
int offset = firstAvailable - values.first.index;
bool fits;
do {
fits = true;
for (final value in values) {
final int entry = offset + value.index;
if (entry >= table.length) {
// Fits
break;
}
if (table[entry] != null) {
fits = false;
break;
}
}
if (!fits) offset++;
} while (!fits);
row.offset = offset;
for (final (:index, :value) in values) {
final int tableIndex = offset + index;
while (table.length <= tableIndex) {
table.add(null);
}
assert(table[tableIndex] == null);
table[tableIndex] = value;
}
while (firstAvailable < table.length && table[firstAvailable] != null) {
firstAvailable++;
}
}
return table;
}

class Row<V extends Object> {
/// The values of the table row, represented sparsely as (index, value) tuples.
final List<({int index, V value})> values;

/// The given [values] must not be empty and should be sorted by index.
Row(this.values) {
assert(values.isNotEmpty);
assert(() {
int previous = values.first.index;
for (final value in values.skip(1)) {
if (value.index <= previous) return false;
previous = value.index;
}
return true;
}());
}

/// The selected offset of this row.
late final int offset;

int get width => values.last.index - values.first.index + 1;
int get holes => width - values.length;
int get density => (100 * values.length) ~/ width;
int get sparsity => 100 - density;
}
40 changes: 33 additions & 7 deletions pkg/dart2wasm/lib/intrinsics.dart
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,13 @@ class Intrinsifier {
w.StorageType? receiverType = translator.builtinTypes[cls];
switch (receiverType) {
case w.NumType.i32:
switch (name) {
case "unary-":
b.i32_const(0);
codeGen.wrap(receiver, w.NumType.i32);
b.i32_sub();
return w.NumType.i32;
}
codeGen.wrap(receiver, w.NumType.i32);
switch (name) {
case "toIntSigned":
Expand Down Expand Up @@ -262,6 +269,18 @@ class Intrinsifier {
case ">":
b.i32_gt_s();
return boolType;
case "leU":
b.i32_le_u();
return boolType;
case "ltU":
b.i32_lt_u();
return boolType;
case "geU":
b.i32_ge_u();
return boolType;
case "gtU":
b.i32_gt_u();
return boolType;
default:
throw 'Unknown WasmI32 member $name';
}
Expand Down Expand Up @@ -513,19 +532,26 @@ class Intrinsifier {
case "_noSubstitutionIndex":
b.i32_const(RuntimeTypeInformation.noSubstitutionIndex);
return w.NumType.i32;
case "_typeRulesSupers":
case "_typeRowDisplacementOffsets":
final type = translator
.translateStorageType(types.rtt.typeRulesSupersType)
.translateStorageType(types.rtt.typeRowDisplacementOffsetsType)
.unpacked;
translator.constants
.instantiateConstant(null, b, types.rtt.typeRulesSupers, type);
translator.constants.instantiateConstant(
null, b, types.rtt.typeRowDisplacementOffsets, type);
return type;
case "_typeRowDisplacementTable":
final type = translator
.translateStorageType(types.rtt.typeRowDisplacementTableType)
.unpacked;
translator.constants.instantiateConstant(
null, b, types.rtt.typeRowDisplacementTable, type);
return type;
case "_canonicalSubstitutionTable":
case "_typeRowDisplacementSubstTable":
final type = translator
.translateStorageType(types.rtt.substitutionTableConstantType)
.translateStorageType(types.rtt.typeRowDisplacementSubstTableType)
.unpacked;
translator.constants.instantiateConstant(
null, b, types.rtt.substitutionTableConstant, type);
null, b, types.rtt.typeRowDisplacementSubstTable, type);
return type;
case "_typeNames":
final type =
Expand Down
Loading

0 comments on commit 3b62508

Please sign in to comment.