Skip to content

Commit 8b495a0

Browse files
mkustermannCommit Queue
authored andcommitted
[dart2wasm] Fix remaining issues around [Symbol] and privacy
Symbol comparison & hashing has to take library privacy into account. We refactor the compiler to move symbol related logic to a new `pkg/dart2wasm/lib/symbols.dart:Symbols`. It will be responsible for making symbol constants, mangling and minification. In there we encapsulate the name mangling required to make library privacy work (similar to how the VM does it). We also clean up the runtime implementation (which was a copy of the VM) and make the unmangling be based purely on removing trailing `...@<number>`. Fixes the following tests * co19/LibTest/core/Symbol/Symbol_A03_t01 * co19/LibTest/core/Symbol/Symbol_A03_t02 * language/private/private_test Closes #50791 Change-Id: If1bb19f3d8868662531162a0458754007017df33 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/435140 Commit-Queue: Martin Kustermann <[email protected]> Reviewed-by: Ömer Ağacan <[email protected]>
1 parent ca662a8 commit 8b495a0

File tree

9 files changed

+140
-124
lines changed

9 files changed

+140
-124
lines changed

pkg/dart2wasm/lib/code_generator.dart

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1741,7 +1741,7 @@ abstract class AstCodeGenerator
17411741
final typeArguments = node.arguments.types;
17421742
final positionalArguments = node.arguments.positional;
17431743
final namedArguments = node.arguments.named;
1744-
final memberName = node.name.text;
1744+
final memberName = node.name;
17451745
final forwarder = translator
17461746
.getDynamicForwardersForModule(b.module)
17471747
.getDynamicInvocationForwarder(memberName);
@@ -1788,8 +1788,8 @@ abstract class AstCodeGenerator
17881788
final name = namedArgumentLocals[elementIdx ~/ 2].key;
17891789
final w.ValueType symbolValueType =
17901790
translator.classInfo[translator.symbolClass]!.nonNullableType;
1791-
translator.constants.instantiateConstant(
1792-
b, SymbolConstant(name, null), symbolValueType);
1791+
translator.constants.instantiateConstant(b,
1792+
translator.symbols.symbolForNamedParameter(name), symbolValueType);
17931793
} else {
17941794
final local = namedArgumentLocals[elementIdx ~/ 2].value;
17951795
b.local_get(local);
@@ -2165,7 +2165,7 @@ abstract class AstCodeGenerator
21652165
@override
21662166
w.ValueType visitDynamicGet(DynamicGet node, w.ValueType expectedType) {
21672167
final receiver = node.receiver;
2168-
final memberName = node.name.text;
2168+
final memberName = node.name;
21692169
final forwarder = translator
21702170
.getDynamicForwardersForModule(b.module)
21712171
.getDynamicGetForwarder(memberName);
@@ -2198,7 +2198,7 @@ abstract class AstCodeGenerator
21982198
w.ValueType visitDynamicSet(DynamicSet node, w.ValueType expectedType) {
21992199
final receiver = node.receiver;
22002200
final value = node.value;
2201-
final memberName = node.name.text;
2201+
final memberName = node.name;
22022202
final forwarder = translator
22032203
.getDynamicForwardersForModule(b.module)
22042204
.getDynamicSetForwarder(memberName);
@@ -3179,7 +3179,7 @@ abstract class AstCodeGenerator
31793179
}
31803180
translator.constants.instantiateConstant(
31813181
b,
3182-
SymbolConstant(member.name.text, null),
3182+
translator.symbols.methodSymbolFromName(member.name),
31833183
translator.classInfo[translator.symbolClass]!.nonNullableType);
31843184
call(translator
31853185
.noSuchMethodErrorThrowUnimplementedExternalMemberError.reference);

pkg/dart2wasm/lib/constants.dart

Lines changed: 13 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5-
import 'dart:convert';
65
import 'dart:typed_data';
76

87
import 'package:kernel/ast.dart';
@@ -80,18 +79,6 @@ class Constants {
8079
w.DataSegmentBuilder? int32Segment;
8180
late final ClassInfo typeInfo = translator.classInfo[translator.typeClass]!;
8281

83-
final Map<String, int> symbolOrdinals = {};
84-
85-
String minifySymbol(String originalValue) {
86-
if (translator.options.minify) {
87-
int symbolOrdinal = symbolOrdinals.putIfAbsent(
88-
originalValue, () => symbolOrdinals.length);
89-
return _intToBase64(symbolOrdinal);
90-
} else {
91-
return originalValue;
92-
}
93-
}
94-
9582
final Map<DartType, InstanceConstant> _loweredTypeConstants = {};
9683
late final BoolConstant _cachedTrueConstant = BoolConstant(true);
9784
late final BoolConstant _cachedFalseConstant = BoolConstant(false);
@@ -145,15 +132,17 @@ class Constants {
145132
}
146133

147134
/// Makes a `_NamedParameter` [InstanceConstant].
148-
InstanceConstant makeNamedParameterConstant(NamedType n) =>
149-
InstanceConstant(translator.namedParameterClass.reference, const [], {
150-
translator.namedParameterNameField.fieldReference:
151-
SymbolConstant(n.name, null),
152-
translator.namedParameterTypeField.fieldReference:
153-
_lowerTypeConstant(n.type),
154-
translator.namedParameterIsRequiredField.fieldReference:
155-
BoolConstant(n.isRequired),
156-
});
135+
InstanceConstant makeNamedParameterConstant(NamedType n) {
136+
return InstanceConstant(
137+
translator.namedParameterClass.reference, const [], {
138+
translator.namedParameterNameField.fieldReference:
139+
translator.symbols.symbolForNamedParameter(n.name),
140+
translator.namedParameterTypeField.fieldReference:
141+
_lowerTypeConstant(n.type),
142+
translator.namedParameterIsRequiredField.fieldReference:
143+
BoolConstant(n.isRequired),
144+
});
145+
}
157146

158147
/// Creates a `WasmArray<_NamedParameter>` to be used as field of
159148
/// `_FunctionType`.
@@ -1176,8 +1165,8 @@ class ConstantCreator extends ConstantVisitor<ConstantInfo?>
11761165
ClassInfo info = translator.classInfo[translator.symbolClass]!;
11771166
translator.functions.recordClassAllocation(info.classId);
11781167
w.RefType stringType = translator.stringType;
1179-
final String symbolStringValue = constants.minifySymbol(constant.name);
1180-
StringConstant nameConstant = StringConstant(symbolStringValue);
1168+
final nameConstant =
1169+
StringConstant(translator.symbols.getMangledSymbolName(constant));
11811170
bool lazy = ensureConstant(nameConstant)?.isLazy ?? false;
11821171
return createConstant(constant, info.nonNullableType, lazy: lazy, (b) {
11831172
b.pushObjectHeaderFields(translator, info);
@@ -1211,19 +1200,6 @@ class ConstantCreator extends ConstantVisitor<ConstantInfo?>
12111200
}
12121201
}
12131202

1214-
List<int> _intToLittleEndianBytes(int i) {
1215-
List<int> bytes = [];
1216-
bytes.add(i & 0xFF);
1217-
i >>>= 8;
1218-
while (i != 0) {
1219-
bytes.add(i & 0xFF);
1220-
i >>>= 8;
1221-
}
1222-
return bytes;
1223-
}
1224-
1225-
String _intToBase64(int i) => base64.encode(_intToLittleEndianBytes(i));
1226-
12271203
/// Resolves to true if the visited Constant is accessible from dynamic
12281204
/// submodules.
12291205
///

pkg/dart2wasm/lib/dispatch_table.dart

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -400,13 +400,13 @@ class DispatchTable {
400400
final Map<int, SelectorInfo> _selectorInfo = {};
401401

402402
/// Maps member names to getter selectors with the same member name.
403-
final Map<String, Set<SelectorInfo>> _dynamicGetters = {};
403+
final Map<Name, Set<SelectorInfo>> _dynamicGetters = {};
404404

405405
/// Maps member names to setter selectors with the same member name.
406-
final Map<String, Set<SelectorInfo>> _dynamicSetters = {};
406+
final Map<Name, Set<SelectorInfo>> _dynamicSetters = {};
407407

408408
/// Maps member names to method selectors with the same member name.
409-
final Map<String, Set<SelectorInfo>> _dynamicMethods = {};
409+
final Map<Name, Set<SelectorInfo>> _dynamicMethods = {};
410410

411411
/// Contents of [_definedWasmTable]. For a selector with ID S and a target
412412
/// class of the selector with ID C, `table[S + C]` gives the reference to the
@@ -427,7 +427,7 @@ class DispatchTable {
427427
sink.writeList(_selectorInfo.values, (s) => s.serialize(sink));
428428
sink.writeList(_table, (r) => sink.writeNullable(r, sink.writeReference));
429429
// Preserve call selectors for closure calls which are handled dynamically.
430-
final callSelectors = _dynamicGetters['call']!;
430+
final callSelectors = _dynamicGetters[Name('call')]!;
431431
sink.writeList(callSelectors, (s) => sink.writeInt(s.id));
432432
}
433433

@@ -450,7 +450,7 @@ class DispatchTable {
450450
for (final selectorId in callSelectorIds) {
451451
callSelectors.add(dispatchTable._selectorInfo[selectorId]!);
452452
}
453-
dispatchTable._dynamicGetters['call'] = callSelectors;
453+
dispatchTable._dynamicGetters[Name('call')] = callSelectors;
454454

455455
return dispatchTable;
456456
}
@@ -497,27 +497,27 @@ class DispatchTable {
497497

498498
if (calledDynamically) {
499499
if (isGetter) {
500-
(_dynamicGetters[member.name.text] ??= {}).add(selector);
500+
(_dynamicGetters[member.name] ??= {}).add(selector);
501501
} else if (isSetter) {
502-
(_dynamicSetters[member.name.text] ??= {}).add(selector);
502+
(_dynamicSetters[member.name] ??= {}).add(selector);
503503
} else {
504-
(_dynamicMethods[member.name.text] ??= {}).add(selector);
504+
(_dynamicMethods[member.name] ??= {}).add(selector);
505505
}
506506
}
507507

508508
return selector;
509509
}
510510

511511
/// Get selectors for getters and tear-offs with the given name.
512-
Iterable<SelectorInfo> dynamicGetterSelectors(String memberName) =>
512+
Iterable<SelectorInfo> dynamicGetterSelectors(Name memberName) =>
513513
_dynamicGetters[memberName] ?? Iterable.empty();
514514

515515
/// Get selectors for setters with the given name.
516-
Iterable<SelectorInfo> dynamicSetterSelectors(String memberName) =>
516+
Iterable<SelectorInfo> dynamicSetterSelectors(Name memberName) =>
517517
_dynamicSetters[memberName] ?? Iterable.empty();
518518

519519
/// Get selectors for methods with the given name.
520-
Iterable<SelectorInfo> dynamicMethodSelectors(String memberName) =>
520+
Iterable<SelectorInfo> dynamicMethodSelectors(Name memberName) =>
521521
_dynamicMethods[memberName] ?? Iterable.empty();
522522

523523
void _initializeWasmTable() {

pkg/dart2wasm/lib/dynamic_forwarders.dart

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,21 @@ class DynamicForwarders {
1818
final Translator translator;
1919
final w.ModuleBuilder callingModule;
2020

21-
final Map<String, CallTarget> _getterForwarderOfName = {};
22-
final Map<String, CallTarget> _setterForwarderOfName = {};
23-
final Map<String, CallTarget> _methodForwarderOfName = {};
21+
final Map<Name, CallTarget> _getterForwarderOfName = {};
22+
final Map<Name, CallTarget> _setterForwarderOfName = {};
23+
final Map<Name, CallTarget> _methodForwarderOfName = {};
2424

2525
DynamicForwarders(this.translator, this.callingModule);
2626

27-
CallTarget getDynamicGetForwarder(String memberName) =>
27+
CallTarget getDynamicGetForwarder(Name memberName) =>
2828
_getterForwarderOfName[memberName] ??= _DynamicForwarderCallTarget(
2929
translator, _ForwarderKind.Getter, memberName, callingModule);
3030

31-
CallTarget getDynamicSetForwarder(String memberName) =>
31+
CallTarget getDynamicSetForwarder(Name memberName) =>
3232
_setterForwarderOfName[memberName] ??= _DynamicForwarderCallTarget(
3333
translator, _ForwarderKind.Setter, memberName, callingModule);
3434

35-
CallTarget getDynamicInvocationForwarder(String memberName) {
35+
CallTarget getDynamicInvocationForwarder(Name memberName) {
3636
// Add Wasm function to the map before generating the forwarder code, to
3737
// allow recursive calls in the "call" forwarder.
3838
var forwarder = _methodForwarderOfName[memberName];
@@ -48,13 +48,13 @@ class DynamicForwarders {
4848
class _DynamicForwarderCallTarget extends CallTarget {
4949
final Translator translator;
5050
final _ForwarderKind _kind;
51-
final String memberName;
51+
final Name memberName;
5252
final w.ModuleBuilder callingModule;
5353

5454
_DynamicForwarderCallTarget(
5555
this.translator, this._kind, this.memberName, this.callingModule)
5656
: assert(!translator.isDynamicSubmodule ||
57-
(memberName == 'call' && _kind == _ForwarderKind.Method)),
57+
(memberName.text == 'call' && _kind == _ForwarderKind.Method)),
5858
super(_kind.functionType(translator));
5959

6060
@override
@@ -95,7 +95,7 @@ class _DynamicForwarderCallTarget extends CallTarget {
9595
class _DynamicForwarderCodeGenerator extends CodeGenerator {
9696
final Translator translator;
9797
final _ForwarderKind _kind;
98-
final String memberName;
98+
final Name memberName;
9999
final w.FunctionBuilder function;
100100

101101
_DynamicForwarderCodeGenerator(
@@ -409,7 +409,7 @@ class _DynamicForwarderCodeGenerator extends CodeGenerator {
409409
b.local_get(namedArgsLocal);
410410
translator.constants.instantiateConstant(
411411
b,
412-
SymbolConstant(name, null),
412+
translator.symbols.symbolForNamedParameter(name),
413413
translator.classInfo[translator.symbolClass]!.nonNullableType);
414414

415415
translator.callReference(
@@ -558,7 +558,7 @@ class _DynamicForwarderCodeGenerator extends CodeGenerator {
558558
// Value is not a closure
559559
final callForwarder = translator
560560
.getDynamicForwardersForModule(b.module)
561-
.getDynamicInvocationForwarder("call")
561+
.getDynamicInvocationForwarder(Name('call'))
562562
.function;
563563
b.local_get(receiverLocal);
564564
b.local_get(typeArgsLocal);
@@ -728,11 +728,13 @@ void generateDynamicFunctionCall(
728728
void createInvocationObject(
729729
Translator translator,
730730
w.InstructionsBuilder b,
731-
String memberName,
731+
Name memberName,
732732
w.Local typeArgsLocal,
733733
w.Local positionalArgsLocal,
734734
w.Local namedArgsLocal) {
735-
translator.constants.instantiateConstant(b, SymbolConstant(memberName, null),
735+
translator.constants.instantiateConstant(
736+
b,
737+
translator.symbols.methodSymbolFromName(memberName),
736738
translator.classInfo[translator.symbolClass]!.nonNullableType);
737739

738740
b.local_get(typeArgsLocal);
@@ -748,9 +750,11 @@ void createInvocationObject(
748750
void createGetterInvocationObject(
749751
Translator translator,
750752
w.InstructionsBuilder b,
751-
String memberName,
753+
Name memberName,
752754
) {
753-
translator.constants.instantiateConstant(b, SymbolConstant(memberName, null),
755+
translator.constants.instantiateConstant(
756+
b,
757+
translator.symbols.getterSymbolFromName(memberName),
754758
translator.classInfo[translator.symbolClass]!.nonNullableType);
755759

756760
translator.callReference(translator.invocationGetterFactory.reference, b);
@@ -759,12 +763,12 @@ void createGetterInvocationObject(
759763
void createSetterInvocationObject(
760764
Translator translator,
761765
w.InstructionsBuilder b,
762-
String memberName,
766+
Name memberName,
763767
w.Local positionalArgLocal,
764768
) {
765-
memberName = '$memberName=';
766-
767-
translator.constants.instantiateConstant(b, SymbolConstant(memberName, null),
769+
translator.constants.instantiateConstant(
770+
b,
771+
translator.symbols.setterSymbolFromName(memberName),
768772
translator.classInfo[translator.symbolClass]!.nonNullableType);
769773

770774
b.local_get(positionalArgLocal);

pkg/dart2wasm/lib/intrinsics.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2039,8 +2039,8 @@ class Intrinsifier {
20392039
translator,
20402040
b,
20412041
() => b.local_get(closureLocal),
2042-
() => createInvocationObject(translator, b, "call", typeArgsLocal,
2043-
posArgsLocal, namedArgsListLocal));
2042+
() => createInvocationObject(translator, b, Name('call'),
2043+
typeArgsLocal, posArgsLocal, namedArgsListLocal));
20442044

20452045
// Error._throw
20462046
case MemberIntrinsic.errorThrow:

pkg/dart2wasm/lib/symbols.dart

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'dart:convert';
6+
7+
import 'package:kernel/ast.dart';
8+
9+
class Symbols {
10+
final bool minify;
11+
Symbols(this.minify);
12+
13+
SymbolConstant methodSymbolFromName(Name name) {
14+
return SymbolConstant(name.text, name.libraryReference);
15+
}
16+
17+
SymbolConstant getterSymbolFromName(Name name) {
18+
return SymbolConstant(name.text, name.libraryReference);
19+
}
20+
21+
SymbolConstant setterSymbolFromName(Name name) {
22+
return SymbolConstant('${name.text}=', name.libraryReference);
23+
}
24+
25+
SymbolConstant symbolForNamedParameter(String name) {
26+
// Named parameters cannot be private.
27+
assert(!name.startsWith('_'));
28+
return SymbolConstant(name, null);
29+
}
30+
31+
final Map<SymbolConstant, int> symbolOrdinals = {};
32+
String getMangledSymbolName(SymbolConstant symbol) {
33+
if (minify) {
34+
return _intToBase64(
35+
symbolOrdinals.putIfAbsent(symbol, () => symbolOrdinals.length));
36+
}
37+
38+
if (symbol.libraryReference == null) {
39+
return symbol.name;
40+
}
41+
42+
// We have a private symbol. The symbol must have been constructed using
43+
// the `#...` syntax (as all `new Symbol()` or `const Symbol()` are not
44+
// considered private - even if they start with "_").
45+
//
46+
// The symbol must be a private identifier (library symbols like `#a.b.c` do
47+
// not have private parts in them).
48+
assert(!symbol.name.contains('.') && symbol.name.startsWith('_'));
49+
return '${symbol.name}@${symbol.libraryReference!.canonicalName.hashCode}';
50+
}
51+
}
52+
53+
List<int> _intToLittleEndianBytes(int i) {
54+
List<int> bytes = [];
55+
bytes.add(i & 0xFF);
56+
i >>>= 8;
57+
while (i != 0) {
58+
bytes.add(i & 0xFF);
59+
i >>>= 8;
60+
}
61+
return bytes;
62+
}
63+
64+
String _intToBase64(int i) => base64.encode(_intToLittleEndianBytes(i));

0 commit comments

Comments
 (0)