Skip to content

Commit 6750538

Browse files
natebiggsCommit Queue
authored andcommitted
[dart2wasm] Move uncheckedEntry handling in updateable function wrappers to be branched at runtime.
For selectors that can be overridden in a dynamic module we produce a special dispatch wrapper that each module implements to do dispatch based on the details of its own dispatch table. Then at runtime dispatches of these selectors get sent to the wrapper for the module that owns the class of the receiver object. uncheckedEntry references occupy a different space in the dispatch table and so require their own wrapper logic. Currently we create separate wrappers for the unchecked and checked references. Now we use the same wrapper and have it take an extra argument that indicates if the call is checked or not. We then delegate to the appropriate offsets in the table based on this new flag. Change-Id: I2004575d06c76c0a80570347747e179e8561463a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/422344 Reviewed-by: Martin Kustermann <[email protected]>
1 parent 5976718 commit 6750538

File tree

2 files changed

+56
-63
lines changed

2 files changed

+56
-63
lines changed

pkg/dart2wasm/lib/dynamic_module_kernel_metadata.dart

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -221,12 +221,12 @@ class MainModuleMetadata {
221221
late final DispatchTable dispatchTable;
222222

223223
/// Contains each invoked reference that targets an updateable function.
224-
final Set<(Reference, bool)> invokedReferences;
224+
final Set<Reference> invokedReferences;
225225

226226
/// Maps invocation keys (either selector or builtin) to the implementation's
227227
/// index in the runtime table. Key includes whether the key was invoked
228228
/// with unchecked entry.
229-
final Map<(int, bool), int> keyInvocationToIndex;
229+
final Map<int, int> keyInvocationToIndex;
230230

231231
/// Classes in dfs order.
232232
final List<Class> dfsOrderClassIds;
@@ -299,15 +299,9 @@ class MainModuleMetadata {
299299

300300
dispatchTable.serialize(sink);
301301

302-
sink.writeList(invokedReferences, (r) {
303-
sink.writeReference(r.$1);
304-
sink.writeBool(r.$2);
305-
});
302+
sink.writeList(invokedReferences, sink.writeReference);
306303

307-
sink.writeMap(keyInvocationToIndex, (r) {
308-
sink.writeInt(r.$1);
309-
sink.writeBool(r.$2);
310-
}, sink.writeInt);
304+
sink.writeMap(keyInvocationToIndex, sink.writeInt, sink.writeInt);
311305

312306
sink.writeList(dfsOrderClassIds, sink.writeClass);
313307

@@ -324,17 +318,9 @@ class MainModuleMetadata {
324318

325319
final dispatchTable = DispatchTable.deserialize(source);
326320

327-
final invokedReferences = source.readList(() {
328-
final reference = source.readReference();
329-
final useUncheckedEntry = source.readBool();
330-
return (reference, useUncheckedEntry);
331-
}).toSet();
332-
333-
final keyInvocationToIndex = source.readMap(() {
334-
final key = source.readInt();
335-
final useUncheckedEntry = source.readBool();
336-
return (key, useUncheckedEntry);
337-
}, source.readInt);
321+
final invokedReferences = source.readList(source.readReference).toSet();
322+
323+
final keyInvocationToIndex = source.readMap(source.readInt, source.readInt);
338324

339325
final dfsOrderClasses = source.readList(source.readClass);
340326

pkg/dart2wasm/lib/dynamic_modules.dart

Lines changed: 49 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -521,33 +521,24 @@ class DynamicModuleInfo {
521521

522522
void _initializeOverrideableReferences() {
523523
for (final builtin in BuiltinUpdatableFunctions.values) {
524-
_createUpdateableFunction(
525-
builtin.index, false, builtin._buildType(translator),
524+
_createUpdateableFunction(builtin.index, builtin._buildType(translator),
526525
buildMain: (f) => builtin._buildMain(f, translator),
527526
buildDynamic: (f) => builtin._buildDynamic(f, translator),
528527
name: '#r_${builtin.name}');
529528
}
530529

531-
for (final (reference, useUncheckedEntry) in metadata.invokedReferences) {
530+
for (final reference in metadata.invokedReferences) {
532531
final selector = translator.dispatchTable.selectorForTarget(reference);
533-
translator.functions.recordSelectorUse(selector, useUncheckedEntry);
534-
535-
w.FunctionType signature;
536-
void Function(w.FunctionBuilder) buildMain;
537-
void Function(w.FunctionBuilder) buildDynamic;
532+
translator.functions.recordSelectorUse(selector, false);
538533

539534
final mainSelector = translator.dynamicMainModuleDispatchTable!
540535
.selectorForTarget(reference);
541-
signature = _getGeneralizedSignature(mainSelector);
542-
buildMain =
543-
buildSelectorBranch(reference, useUncheckedEntry, mainSelector);
544-
buildDynamic =
545-
buildSelectorBranch(reference, useUncheckedEntry, mainSelector);
536+
final signature = _getGeneralizedSignature(mainSelector);
537+
final buildMain = buildSelectorBranch(reference, mainSelector);
538+
final buildDynamic = buildSelectorBranch(reference, mainSelector);
546539

547540
_createUpdateableFunction(
548-
mainSelector.id + BuiltinUpdatableFunctions.values.length,
549-
useUncheckedEntry,
550-
signature,
541+
mainSelector.id + BuiltinUpdatableFunctions.values.length, signature,
551542
buildMain: buildMain,
552543
buildDynamic: buildDynamic,
553544
name: '#s${mainSelector.id}_${mainSelector.name}');
@@ -582,16 +573,14 @@ class DynamicModuleInfo {
582573
b.drop();
583574
}
584575

585-
int _createUpdateableFunction(
586-
int key, bool useUncheckedEntry, w.FunctionType type,
576+
int _createUpdateableFunction(int key, w.FunctionType type,
587577
{required void Function(w.FunctionBuilder function) buildMain,
588578
required void Function(w.FunctionBuilder function) buildDynamic,
589579
bool skipDynamic = false,
590580
required String name}) {
591-
final mapKey = (key, useUncheckedEntry);
581+
final mapKey = key;
592582
final index = metadata.keyInvocationToIndex[mapKey] ??=
593583
metadata.keyInvocationToIndex.length;
594-
595584
overrideableFunctions.putIfAbsent(index, () {
596585
if (!isDynamicModule) {
597586
final mainFunction = translator.mainModule.functions.define(type, name);
@@ -611,8 +600,8 @@ class DynamicModuleInfo {
611600
return index;
612601
}
613602

614-
void _callClassIdBranch(int key, bool useUncheckedEntry,
615-
w.InstructionsBuilder b, w.FunctionType signature,
603+
void _callClassIdBranch(
604+
int key, w.InstructionsBuilder b, w.FunctionType signature,
616605
{required void Function(w.FunctionBuilder b) buildMainMatch,
617606
required void Function(w.FunctionBuilder b) buildDynamicMatch,
618607
bool skipDynamic = false,
@@ -622,8 +611,7 @@ class DynamicModuleInfo {
622611
final canSkipDynamicBranch = skipDynamic ||
623612
translator.classIdNumbering.maxDynamicModuleClassId ==
624613
translator.classIdNumbering.maxClassId;
625-
final callIndex = _createUpdateableFunction(
626-
key, useUncheckedEntry, signature,
614+
final callIndex = _createUpdateableFunction(key, signature,
627615
buildMain: buildMainMatch,
628616
buildDynamic: buildDynamicMatch,
629617
skipDynamic: canSkipDynamicBranch,
@@ -644,7 +632,7 @@ class DynamicModuleInfo {
644632
void callClassIdBranchBuiltIn(
645633
BuiltinUpdatableFunctions key, w.InstructionsBuilder b,
646634
{bool skipDynamic = false}) {
647-
_callClassIdBranch(key.index, false, b, key._buildType(translator),
635+
_callClassIdBranch(key.index, b, key._buildType(translator),
648636
buildMainMatch: (f) => key._buildMain(f, translator),
649637
buildDynamicMatch: (f) => key._buildDynamic(f, translator),
650638
name: '#r_${key.name}',
@@ -658,6 +646,7 @@ class DynamicModuleInfo {
658646
// selector's signature may change between compilations.
659647
final generalizedSignature = translator.typesBuilder.defineFunction([
660648
...signature.inputs.map((e) => const w.RefType.any(nullable: true)),
649+
w.NumType.i32,
661650
w.NumType.i32
662651
], [
663652
...signature.outputs.map((e) => const w.RefType.any(nullable: true))
@@ -666,15 +655,16 @@ class DynamicModuleInfo {
666655
}
667656

668657
void Function(w.FunctionBuilder) buildSelectorBranch(
669-
Reference target, bool useUncheckedEntry, SelectorInfo mainSelector) {
658+
Reference target, SelectorInfo mainSelector) {
670659
return (w.FunctionBuilder function) {
671660
final localSelector = translator.dispatchTable.selectorForTarget(target);
672661
final localSignature = localSelector.signature;
673662
final ib = function.body;
674663

675-
final offset = localSelector.targets(unchecked: useUncheckedEntry).offset;
664+
final uncheckedOffset = localSelector.targets(unchecked: true).offset;
665+
final checkedOffset = localSelector.targets(unchecked: false).offset;
676666

677-
if (offset == null) {
667+
if (uncheckedOffset == null && checkedOffset == null) {
678668
ib.unreachable();
679669
ib.end();
680670
return;
@@ -745,12 +735,32 @@ class DynamicModuleInfo {
745735
ib, constant, localSignature.inputs[localsIndex]);
746736
}
747737

748-
ib.local_get(ib.locals.last);
738+
ib.local_get(ib.locals[function.type.inputs.length - 2]);
749739
if (isDynamicModule) {
750740
translator.callReference(translator.scopeClassId.reference, ib);
751741
}
752-
if (offset != 0) {
753-
ib.i32_const(offset);
742+
if (checkedOffset == uncheckedOffset) {
743+
if (checkedOffset != 0) {
744+
ib.i32_const(checkedOffset!);
745+
ib.i32_add();
746+
}
747+
} else if (checkedOffset != 0 || uncheckedOffset != 0) {
748+
// Check if the invocation is checked or unchecked and use the
749+
// appropriate offset.
750+
ib.local_get(ib.locals[function.type.inputs.length - 1]);
751+
ib.if_(const [], const [w.NumType.i32]);
752+
if (uncheckedOffset != null) {
753+
ib.i32_const(uncheckedOffset);
754+
} else {
755+
ib.unreachable();
756+
}
757+
ib.else_();
758+
if (checkedOffset != null) {
759+
ib.i32_const(checkedOffset);
760+
} else {
761+
ib.unreachable();
762+
}
763+
ib.end();
754764
ib.i32_add();
755765
}
756766
final table = translator.dispatchTable.getWasmTable(ib.module);
@@ -764,7 +774,7 @@ class DynamicModuleInfo {
764774
void callOverrideableDispatch(
765775
w.InstructionsBuilder b, SelectorInfo selector, Reference interfaceTarget,
766776
{required bool useUncheckedEntry}) {
767-
metadata.invokedReferences.add((interfaceTarget, useUncheckedEntry));
777+
metadata.invokedReferences.add(interfaceTarget);
768778

769779
final localSignature = selector.signature;
770780
// If any input is not a RefType (i.e. it's an unboxed value) then wrap it
@@ -788,6 +798,7 @@ class DynamicModuleInfo {
788798
final idLocal = b.addLocal(w.NumType.i32);
789799
b.struct_get(translator.topInfo.struct, FieldIndex.classId);
790800
b.local_tee(idLocal);
801+
b.i32_const(useUncheckedEntry ? 1 : 0);
791802
b.local_get(idLocal);
792803

793804
final mainDispatchTable =
@@ -799,17 +810,13 @@ class DynamicModuleInfo {
799810
// For consistency, always use the main module selector ID when generating
800811
// the key.
801812
final key = mainModuleSelector.id + BuiltinUpdatableFunctions.values.length;
802-
_callClassIdBranch(key, useUncheckedEntry, b, generalizedSignature,
813+
_callClassIdBranch(key, b, generalizedSignature,
803814
name: '#s${mainModuleSelector.id}_${mainModuleSelector.name}',
804-
buildMainMatch: buildSelectorBranch(
805-
interfaceTarget, useUncheckedEntry, mainModuleSelector),
806-
buildDynamicMatch: buildSelectorBranch(
807-
interfaceTarget, useUncheckedEntry, mainModuleSelector),
808-
skipDynamic: translator.isDynamicModule &&
809-
selector
810-
.targets(unchecked: useUncheckedEntry)
811-
.targetRanges
812-
.isEmpty);
815+
buildMainMatch:
816+
buildSelectorBranch(interfaceTarget, mainModuleSelector),
817+
buildDynamicMatch:
818+
buildSelectorBranch(interfaceTarget, mainModuleSelector),
819+
skipDynamic: selector.targets(unchecked: false).targetRanges.isEmpty);
813820
translator.convertType(
814821
b, generalizedSignature.outputs.single, localSignature.outputs.single);
815822
}

0 commit comments

Comments
 (0)