[dart2wasm] Update serialization strategy for dynamic modules.
Introduces some more machinery to simplify the serialization pipeline. Now the logic to index kernel nodes is hidden away in the serializer. Now throughout the compiler if entities (i.e. classes, members and references) need to be serialized they can be passed to the serializer directly. Also adds support for tracking brand type assignments from the main module to the dynamic module. This is necessary to decouple the execution order of both compilations which is a WIP. Change-Id: I38dd0ed11811ea12a2230959588b261719976592 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/412461 Reviewed-by: Martin Kustermann <kustermann@google.com> Commit-Queue: Nate Biggs <natebiggs@google.com>
This commit is contained in:
@@ -373,6 +373,14 @@ class ClassInfoCollector {
|
||||
// conservative and mark it as not being final.
|
||||
struct.hasAnySubtypes = true;
|
||||
}
|
||||
|
||||
if (translator.isDynamicModule) {
|
||||
final brandIndex =
|
||||
translator.dynamicModuleInfo!.classMetadata[cls]?.brandIndex;
|
||||
if (brandIndex != null) {
|
||||
translator.typesBuilder.addBrandTypeAssignment(struct, brandIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
translator.classesSupersFirst.add(info);
|
||||
translator.classInfo[cls] = info;
|
||||
@@ -700,9 +708,10 @@ class ClassIdNumbering {
|
||||
final implementors = <Class, List<Class>>{};
|
||||
final classIds = <Class, ClassId>{};
|
||||
|
||||
final savedMapping = translator.dynamicModuleInfo?.classIdMapping;
|
||||
if (savedMapping != null) {
|
||||
savedMapping.forEach((cls, classId) {
|
||||
if (translator.isDynamicModule) {
|
||||
final savedMapping = translator.dynamicModuleInfo!.classMetadata;
|
||||
savedMapping.forEach((cls, info) {
|
||||
final classId = info.classId;
|
||||
classIds[cls] = AbsoluteClassId(classId);
|
||||
savedMaxClassId = max(savedMaxClassId ?? -2, classId);
|
||||
if (!cls.isAbstract && !cls.isAnonymousMixin) {
|
||||
@@ -796,8 +805,7 @@ class ClassIdNumbering {
|
||||
}
|
||||
|
||||
// Make a list of the depth-first pre-order traversal.
|
||||
final dfsOrder =
|
||||
translator.dynamicModuleInfo?.dfsOrderClassIds ?? <Class>[];
|
||||
final dfsOrder = [...?translator.dynamicModuleInfo?.dfsOrderClassIds];
|
||||
final inDfsOrder = {...dfsOrder};
|
||||
|
||||
// Maps any class to a dense range of concrete class ids that are subclasses
|
||||
@@ -907,6 +915,9 @@ final class AbsoluteClassId extends ClassId {
|
||||
int get _localValue => value;
|
||||
|
||||
AbsoluteClassId(this.value);
|
||||
|
||||
@override
|
||||
String toString() => 'Absolute($value)';
|
||||
}
|
||||
|
||||
final class RelativeClassId extends ClassId {
|
||||
@@ -915,6 +926,9 @@ final class RelativeClassId extends ClassId {
|
||||
int get _localValue => relativeValue;
|
||||
|
||||
RelativeClassId(this.relativeValue);
|
||||
|
||||
@override
|
||||
String toString() => 'Relative($relativeValue)';
|
||||
}
|
||||
|
||||
// A range of class ids, both ends inclusive.
|
||||
|
||||
@@ -158,17 +158,7 @@ Future<CompilationResult> compileToModule(
|
||||
compilerOptions.compileSdk = true;
|
||||
}
|
||||
|
||||
DynamicModuleMetadata? dynamicModuleMetadata;
|
||||
final dynamicMainModuleUri = options.dynamicModuleMainUri;
|
||||
if (dynamicMainModuleUri != null && options.dynamicInterfaceUri == null) {
|
||||
final filename = options.dynamicModuleMetadataFile ??
|
||||
Uri.parse(
|
||||
path.setExtension(dynamicMainModuleUri.toFilePath(), '.dyndata'));
|
||||
final dynamicModuleMetadataBytes =
|
||||
await File.fromUri(filename).readAsBytes();
|
||||
final source = BinaryDataSource(dynamicModuleMetadataBytes);
|
||||
dynamicModuleMetadata = DynamicModuleMetadata.deserialize(source);
|
||||
}
|
||||
|
||||
final dynamicModuleMainUri = await resolveUri(options.dynamicModuleMainUri);
|
||||
final dynamicInterfaceUri = await resolveUri(options.dynamicInterfaceUri);
|
||||
@@ -177,10 +167,7 @@ Future<CompilationResult> compileToModule(
|
||||
final isDynamicModule =
|
||||
dynamicModuleMainUri != null && dynamicInterfaceUri == null;
|
||||
if (isDynamicModule) {
|
||||
dynamicModuleMetadata!.verifyDynamicModuleOptions(options);
|
||||
compilerOptions.additionalDills.add(dynamicModuleMainUri);
|
||||
} else if (isDynamicMainModule) {
|
||||
DynamicModuleMetadata.verifyMainModuleOptions(options);
|
||||
}
|
||||
|
||||
CompilerResult? compilerResult;
|
||||
@@ -268,7 +255,20 @@ Future<CompilationResult> compileToModule(
|
||||
|
||||
moduleStrategy.prepareComponent();
|
||||
|
||||
if (isDynamicMainModule) {
|
||||
MainModuleMetadata mainModuleMetadata =
|
||||
MainModuleMetadata.empty(options.translatorOptions, options.environment);
|
||||
|
||||
if (isDynamicModule) {
|
||||
final filename = options.dynamicModuleMetadataFile ??
|
||||
Uri.parse(
|
||||
path.setExtension(dynamicMainModuleUri!.toFilePath(), '.dyndata'));
|
||||
final dynamicModuleMetadataBytes =
|
||||
await File.fromUri(filename).readAsBytes();
|
||||
final source = DataDeserializer(dynamicModuleMetadataBytes, component);
|
||||
mainModuleMetadata = MainModuleMetadata.deserialize(source);
|
||||
mainModuleMetadata.verifyDynamicModuleOptions(options);
|
||||
} else if (isDynamicMainModule) {
|
||||
MainModuleMetadata.verifyMainModuleOptions(options);
|
||||
writeComponentToBinary(component, dynamicModuleMainUri.path,
|
||||
includeSource: false);
|
||||
}
|
||||
@@ -301,9 +301,13 @@ Future<CompilationResult> compileToModule(
|
||||
|
||||
final moduleOutputData = moduleStrategy.buildModuleOutputData();
|
||||
|
||||
if (isDynamicMainModule) {
|
||||
mainModuleMetadata.initialize(component, coreTypes);
|
||||
}
|
||||
|
||||
var translator = Translator(component, coreTypes, libraryIndex, recordClasses,
|
||||
moduleOutputData, options.translatorOptions,
|
||||
dynamicModuleMetadata: dynamicModuleMetadata,
|
||||
mainModuleMetadata: mainModuleMetadata,
|
||||
enableDynamicModules: dynamicModuleMainUri != null);
|
||||
|
||||
String? depFile = options.depFile;
|
||||
@@ -341,9 +345,9 @@ Future<CompilationResult> compileToModule(
|
||||
final filename = options.dynamicModuleMetadataFile ??
|
||||
Uri.parse(
|
||||
path.setExtension(dynamicMainModuleUri!.toFilePath(), '.dyndata'));
|
||||
final sink = BinaryDataSink();
|
||||
translator.dynamicModuleInfo!.toMetadata(options).serialize(sink);
|
||||
await File.fromUri(filename).writeAsBytes(sink.takeBytes());
|
||||
final serializer = DataSerializer(translator.component);
|
||||
translator.dynamicModuleInfo!.metadata.serialize(translator, serializer);
|
||||
await File.fromUri(filename).writeAsBytes(serializer.takeBytes());
|
||||
}
|
||||
|
||||
return CompilationSuccess(wasmModules, jsRuntime, supportJs);
|
||||
|
||||
@@ -397,7 +397,8 @@ class DispatchTable {
|
||||
(_dynamicMethods[member.name.text] ??= {}).add(selector);
|
||||
}
|
||||
}
|
||||
final mainModuleIds = translator.dynamicModuleInfo?.selectorIds?[member];
|
||||
|
||||
final mainModuleIds = translator.dynamicModuleInfo?.selectorIds[member];
|
||||
if (mainModuleIds != null) {
|
||||
selector._mainModuleIds[member] =
|
||||
isGetter ? mainModuleIds.$1 : mainModuleIds.$2;
|
||||
|
||||
@@ -3,8 +3,15 @@
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:kernel/ast.dart';
|
||||
import 'package:kernel/core_types.dart';
|
||||
import 'package:vm/metadata/procedure_attributes.dart'
|
||||
show ProcedureAttributesMetadataRepository;
|
||||
|
||||
import 'class_info.dart';
|
||||
import 'compiler_options.dart';
|
||||
import 'dynamic_modules.dart';
|
||||
import 'intrinsics.dart' show MemberIntrinsic;
|
||||
import 'reference_extensions.dart';
|
||||
import 'serialization.dart';
|
||||
import 'translator.dart';
|
||||
|
||||
@@ -30,24 +37,41 @@ class DynamicModuleGlobalIdRepository extends MetadataRepository<int> {
|
||||
void writeToBinary(int globalId, Node node, BinarySink sink) {}
|
||||
}
|
||||
|
||||
class ClassMetadata {
|
||||
final int classId;
|
||||
final int? brandIndex;
|
||||
|
||||
ClassMetadata(this.classId, this.brandIndex);
|
||||
|
||||
factory ClassMetadata.deserialize(DataDeserializer source) {
|
||||
final classId = source.readInt() - 1;
|
||||
final brandIndex = source.readInt();
|
||||
return ClassMetadata(classId, brandIndex == 0 ? null : brandIndex - 1);
|
||||
}
|
||||
|
||||
void serialize(DataSerializer sink) {
|
||||
sink.writeInt(classId + 1);
|
||||
sink.writeInt(brandIndex == null ? 0 : brandIndex! + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/// Metadata produced by the main module.
|
||||
///
|
||||
/// This data will get serialized as part of the main module compilation process
|
||||
/// and will be provided as an input to be deserialized by subsequent dynamic
|
||||
/// module compilations.
|
||||
class DynamicModuleMetadata {
|
||||
/// Global kernel class ID to dart2wasm class hierarchy class ID.
|
||||
final Map<int, int> classIds;
|
||||
class MainModuleMetadata {
|
||||
/// Class to metadata about the class
|
||||
final Map<Class, ClassMetadata> classMetadata;
|
||||
|
||||
/// Global kernel member ID to getter and setter/method selector ID.
|
||||
final Map<int, (int, int)> selectorIds;
|
||||
/// Member to getter and setter/method selector ID.
|
||||
final Map<Member, (int, int)> selectorIds;
|
||||
|
||||
/// Global kernel class IDs in class hierarchy dfs order.
|
||||
final List<int> dfsOrderClassIds;
|
||||
final List<Class> dfsOrderClassIds;
|
||||
|
||||
/// References for all targets callable from the main module represented as
|
||||
/// member global ID and reference type.
|
||||
final List<(int, int)> callableReferences;
|
||||
/// References for all targets callable from the main module.
|
||||
final Set<Reference> callableReferences;
|
||||
|
||||
/// Key names of updateable functions defined in the main module.
|
||||
final Map<String, int> updateableFunctionsInMain;
|
||||
@@ -57,8 +81,8 @@ class DynamicModuleMetadata {
|
||||
final TranslatorOptions mainModuleTranslatorOptions;
|
||||
final Map<String, String> mainModuleEnvironment;
|
||||
|
||||
DynamicModuleMetadata(
|
||||
this.classIds,
|
||||
MainModuleMetadata._(
|
||||
this.classMetadata,
|
||||
this.selectorIds,
|
||||
this.dfsOrderClassIds,
|
||||
this.callableReferences,
|
||||
@@ -66,26 +90,78 @@ class DynamicModuleMetadata {
|
||||
this.mainModuleTranslatorOptions,
|
||||
this.mainModuleEnvironment);
|
||||
|
||||
void serialize(BinaryDataSink sink) {
|
||||
sink.writeInt(classIds.length);
|
||||
classIds.forEach((globalClassId, classId) {
|
||||
sink.writeInt(globalClassId);
|
||||
sink.writeClassId(classId);
|
||||
MainModuleMetadata.empty(
|
||||
this.mainModuleTranslatorOptions, this.mainModuleEnvironment)
|
||||
: classMetadata = {},
|
||||
selectorIds = {},
|
||||
dfsOrderClassIds = [],
|
||||
callableReferences = {},
|
||||
updateableFunctionsInMain = {};
|
||||
|
||||
void initialize(Component component, CoreTypes coreTypes) {
|
||||
_initializeCallableReferences(component, coreTypes);
|
||||
}
|
||||
|
||||
void finalize(Translator translator) {
|
||||
translator.classInfo.forEach((cls, info) {
|
||||
final id =
|
||||
cls.isAnonymousMixin ? -1 : (info.classId as AbsoluteClassId).value;
|
||||
final structType = info.struct;
|
||||
final brandIndex =
|
||||
translator.typesBuilder.brandTypeAssignments[structType];
|
||||
classMetadata[cls] = ClassMetadata(id, brandIndex);
|
||||
});
|
||||
|
||||
final procedureMetadata =
|
||||
(translator.component.metadata["vm.procedure-attributes.metadata"]
|
||||
as ProcedureAttributesMetadataRepository)
|
||||
.mapping;
|
||||
for (final library in translator.libraries) {
|
||||
for (final cls in library.classes) {
|
||||
for (final member in cls.procedures) {
|
||||
if (!member.isInstanceMember) continue;
|
||||
selectorIds[member] = (
|
||||
procedureMetadata[member]!.getterSelectorId,
|
||||
procedureMetadata[member]!.methodOrSetterSelectorId
|
||||
);
|
||||
}
|
||||
for (final member in cls.fields) {
|
||||
if (!member.isInstanceMember) continue;
|
||||
selectorIds[member] = (
|
||||
procedureMetadata[member]!.getterSelectorId,
|
||||
procedureMetadata[member]!.methodOrSetterSelectorId
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (final cls in translator.classIdNumbering.dfsOrder) {
|
||||
dfsOrderClassIds.add(cls);
|
||||
}
|
||||
}
|
||||
|
||||
void serialize(Translator translator, DataSerializer sink) {
|
||||
finalize(translator);
|
||||
|
||||
sink.writeInt(classMetadata.length);
|
||||
classMetadata.forEach((cls, metadata) {
|
||||
sink.writeClass(cls);
|
||||
metadata.serialize(sink);
|
||||
});
|
||||
sink.writeInt(selectorIds.length);
|
||||
selectorIds.forEach((globalMemberId, selectorIds) {
|
||||
sink.writeInt(globalMemberId);
|
||||
selectorIds.forEach((member, selectorIds) {
|
||||
final wroteMember = sink.writeMember(member);
|
||||
if (!wroteMember) return;
|
||||
sink.writeInt(selectorIds.$1);
|
||||
sink.writeInt(selectorIds.$2);
|
||||
});
|
||||
sink.writeInt(dfsOrderClassIds.length);
|
||||
for (final classId in dfsOrderClassIds) {
|
||||
sink.writeClassId(classId);
|
||||
for (final cls in dfsOrderClassIds) {
|
||||
sink.writeClass(cls);
|
||||
}
|
||||
sink.writeInt(callableReferences.length);
|
||||
for (final callableMemberId in callableReferences) {
|
||||
sink.writeInt(callableMemberId.$1);
|
||||
sink.writeInt(callableMemberId.$2);
|
||||
for (final reference in callableReferences) {
|
||||
sink.writeReference(reference);
|
||||
}
|
||||
sink.writeInt(updateableFunctionsInMain.length);
|
||||
updateableFunctionsInMain.forEach((stringKey, key) {
|
||||
@@ -101,33 +177,33 @@ class DynamicModuleMetadata {
|
||||
});
|
||||
}
|
||||
|
||||
static DynamicModuleMetadata deserialize(BinaryDataSource source) {
|
||||
final classIdMappingLength = source.readInt();
|
||||
final classIds = <int, int>{};
|
||||
for (int i = 0; i < classIdMappingLength; i++) {
|
||||
final globalClassId = source.readInt();
|
||||
final classId = source.readClassId();
|
||||
classIds[globalClassId] = classId;
|
||||
static MainModuleMetadata deserialize(DataDeserializer source) {
|
||||
final classMetadataLength = source.readInt();
|
||||
final classMetadata = <Class, ClassMetadata>{};
|
||||
for (int i = 0; i < classMetadataLength; i++) {
|
||||
final cls = source.readClass();
|
||||
final metadata = ClassMetadata.deserialize(source);
|
||||
classMetadata[cls] = metadata;
|
||||
}
|
||||
|
||||
final selectorIdMappingLength = source.readInt();
|
||||
final selectorIds = <int, (int, int)>{};
|
||||
final selectorIds = <Member, (int, int)>{};
|
||||
for (int i = 0; i < selectorIdMappingLength; i++) {
|
||||
final globalMemberId = source.readInt();
|
||||
final member = source.readMember();
|
||||
final getterSelectorId = source.readInt();
|
||||
final setterOrMethodSelectorId = source.readInt();
|
||||
selectorIds[globalMemberId] =
|
||||
(getterSelectorId, setterOrMethodSelectorId);
|
||||
selectorIds[member] = (getterSelectorId, setterOrMethodSelectorId);
|
||||
}
|
||||
final dfsOrderClassIdsLength = source.readInt();
|
||||
final dfsOrderClassIds = <int>[];
|
||||
for (int i = 0; i < dfsOrderClassIdsLength; i++) {
|
||||
dfsOrderClassIds.add(source.readClassId());
|
||||
final dfsOrderClassesLength = source.readInt();
|
||||
final dfsOrderClasses = <Class>[];
|
||||
for (int i = 0; i < dfsOrderClassesLength; i++) {
|
||||
dfsOrderClasses.add(source.readClass());
|
||||
}
|
||||
final callableMemberIdsLength = source.readInt();
|
||||
final callableMemberIds = <(int, int)>[];
|
||||
for (int i = 0; i < callableMemberIdsLength; i++) {
|
||||
callableMemberIds.add((source.readInt(), source.readInt()));
|
||||
final callableMembersLength = source.readInt();
|
||||
final callableMembers = <Reference>{};
|
||||
for (int i = 0; i < callableMembersLength; i++) {
|
||||
final reference = source.readReference();
|
||||
callableMembers.add(reference);
|
||||
}
|
||||
final updateableFunctionsInMainLength = source.readInt();
|
||||
final updateableFunctionsInMain = <String, int>{};
|
||||
@@ -145,11 +221,11 @@ class DynamicModuleMetadata {
|
||||
mainModuleEnvironment[key] = value;
|
||||
}
|
||||
|
||||
return DynamicModuleMetadata(
|
||||
classIds,
|
||||
return MainModuleMetadata._(
|
||||
classMetadata,
|
||||
selectorIds,
|
||||
dfsOrderClassIds,
|
||||
callableMemberIds,
|
||||
dfsOrderClasses,
|
||||
callableMembers,
|
||||
updateableFunctionsInMain,
|
||||
mainModuleTranslatorOptions,
|
||||
mainModuleEnvironment);
|
||||
@@ -253,4 +329,63 @@ class DynamicModuleMetadata {
|
||||
fail('environment mismatch');
|
||||
}
|
||||
}
|
||||
|
||||
void _initializeCallableReferences(Component component, CoreTypes coreTypes) {
|
||||
void collectCallableReference(Reference reference) {
|
||||
final member = reference.asMember;
|
||||
|
||||
if (member.isExternal) {
|
||||
final isGeneratedIntrinsic = member is Procedure &&
|
||||
MemberIntrinsic.fromProcedure(coreTypes, member) != null;
|
||||
if (!isGeneratedIntrinsic) return;
|
||||
}
|
||||
callableReferences.add(reference);
|
||||
}
|
||||
|
||||
final procedureAttributeMetadata =
|
||||
(component.metadata["vm.procedure-attributes.metadata"]
|
||||
as ProcedureAttributesMetadataRepository)
|
||||
.mapping;
|
||||
void collectCallableReferences(Member member) {
|
||||
if (member is Procedure) {
|
||||
collectCallableReference(member.reference);
|
||||
if (member.isInstanceMember &&
|
||||
member.kind == ProcedureKind.Method &&
|
||||
procedureAttributeMetadata[member]!.hasTearOffUses) {
|
||||
collectCallableReference(member.tearOffReference);
|
||||
}
|
||||
} else if (member is Field) {
|
||||
collectCallableReference(member.getterReference);
|
||||
if (member.hasSetter) {
|
||||
collectCallableReference(member.setterReference!);
|
||||
}
|
||||
} else if (member is Constructor) {
|
||||
if (member.enclosingClass == coreTypes.numClass ||
|
||||
member.enclosingClass == coreTypes.boolClass ||
|
||||
member.enclosingClass ==
|
||||
coreTypes.index.getClass('dart:_boxed_int', 'BoxedInt') ||
|
||||
member.enclosingClass ==
|
||||
coreTypes.index.getClass('dart:_boxed_double', 'BoxedDouble')) {
|
||||
return;
|
||||
}
|
||||
collectCallableReference(member.reference);
|
||||
collectCallableReference(member.initializerReference);
|
||||
collectCallableReference(member.constructorBodyReference);
|
||||
}
|
||||
}
|
||||
|
||||
for (final lib in component.libraries) {
|
||||
for (final member in lib.members) {
|
||||
if (!member.isDynamicModuleCallable(coreTypes)) continue;
|
||||
collectCallableReferences(member);
|
||||
}
|
||||
|
||||
for (final cls in lib.classes) {
|
||||
for (final member in cls.members) {
|
||||
if (!member.isDynamicModuleCallable(coreTypes)) continue;
|
||||
collectCallableReferences(member);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,6 @@ import 'package:kernel/ast.dart';
|
||||
import 'package:kernel/class_hierarchy.dart';
|
||||
import 'package:kernel/core_types.dart';
|
||||
import 'package:kernel/library_index.dart';
|
||||
import 'package:vm/metadata/procedure_attributes.dart'
|
||||
show ProcedureAttributesMetadataRepository;
|
||||
import 'package:vm/transformations/dynamic_interface_annotator.dart'
|
||||
as dynamic_interface_annotator;
|
||||
import 'package:vm/transformations/pragma.dart';
|
||||
@@ -21,7 +19,6 @@ import 'dispatch_table.dart';
|
||||
import 'dynamic_module_kernel_metadata.dart';
|
||||
import 'kernel_nodes.dart';
|
||||
import 'modules.dart';
|
||||
import 'reference_extensions.dart';
|
||||
import 'target.dart';
|
||||
import 'translator.dart';
|
||||
import 'types.dart' show InstanceConstantInterfaceType;
|
||||
@@ -317,22 +314,18 @@ class DynamicModuleInfo {
|
||||
translator.component.dynamicModuleEntryPoint;
|
||||
bool get isDynamicModule => dynamicEntryPoint != null;
|
||||
late final w.FunctionBuilder initFunction;
|
||||
late final MainModuleMetadata metadata;
|
||||
|
||||
Map<Class, int>? _classIdMapping;
|
||||
Map<Class, int>? get classIdMapping => _classIdMapping;
|
||||
Map<Class, ClassMetadata> get classMetadata => metadata.classMetadata;
|
||||
|
||||
Map<Member, (int, int)>? _selectorIds;
|
||||
Map<Member, (int, int)>? get selectorIds => _selectorIds;
|
||||
Map<Member, (int, int)> get selectorIds => metadata.selectorIds;
|
||||
|
||||
List<Reference>? _callableReferences;
|
||||
List<Reference>? get callableReferences => _callableReferences;
|
||||
|
||||
List<Class>? _dfsOrderClassIds;
|
||||
List<Class>? get dfsOrderClassIds => _dfsOrderClassIds;
|
||||
List<Class> get dfsOrderClassIds => metadata.dfsOrderClassIds;
|
||||
|
||||
late final w.Global moduleIdGlobal;
|
||||
|
||||
final Map<String, int> _updateableDispatchKeys;
|
||||
Map<String, int> get _updateableDispatchKeys =>
|
||||
metadata.updateableFunctionsInMain;
|
||||
// null is used to indicate that skipDynamic was passed for this key.
|
||||
final Map<int, w.BaseFunction?> _updateableFunctions = {};
|
||||
|
||||
@@ -346,43 +339,7 @@ class DynamicModuleInfo {
|
||||
late final w.ModuleBuilder dynamicModule =
|
||||
translator.modules.firstWhere((m) => m != translator.mainModule);
|
||||
|
||||
DynamicModuleInfo(this.translator, DynamicModuleMetadata? serializedMetadata)
|
||||
: _updateableDispatchKeys =
|
||||
serializedMetadata?.updateableFunctionsInMain ?? {} {
|
||||
if (serializedMetadata != null) {
|
||||
assert(isDynamicModule);
|
||||
final globalIdRepository = translator
|
||||
.component.metadata[DynamicModuleGlobalIdRepository.repositoryTag]
|
||||
as DynamicModuleGlobalIdRepository;
|
||||
final Map<int, TreeNode> globalIdToNode = {};
|
||||
globalIdRepository.mapping.forEach((node, globalId) {
|
||||
globalIdToNode[globalId] = node;
|
||||
});
|
||||
|
||||
final assignedClassIds = <Class, int>{};
|
||||
serializedMetadata.classIds.forEach((globalId, classId) {
|
||||
assignedClassIds[globalIdToNode[globalId] as Class] = classId;
|
||||
});
|
||||
_classIdMapping = assignedClassIds;
|
||||
|
||||
final assignedSelectorIds = <Member, (int, int)>{};
|
||||
serializedMetadata.selectorIds.forEach((globalId, selectorIds) {
|
||||
assignedSelectorIds[globalIdToNode[globalId] as Member] = selectorIds;
|
||||
});
|
||||
_selectorIds = assignedSelectorIds;
|
||||
|
||||
_dfsOrderClassIds = [
|
||||
for (final globalId in serializedMetadata.dfsOrderClassIds)
|
||||
globalIdToNode[globalId] as Class
|
||||
];
|
||||
|
||||
_callableReferences = [
|
||||
for (final reference in serializedMetadata.callableReferences)
|
||||
_referenceForFlag(
|
||||
globalIdToNode[reference.$1] as Member, reference.$2)
|
||||
];
|
||||
}
|
||||
}
|
||||
DynamicModuleInfo(this.translator, this.metadata);
|
||||
|
||||
void initDynamicModule() {
|
||||
dynamicModule.functions.start = initFunction = dynamicModule.functions
|
||||
@@ -392,6 +349,8 @@ class DynamicModuleInfo {
|
||||
// Make sure the exception tag is exported from the main module.
|
||||
translator.getExceptionTag(dynamicModule);
|
||||
|
||||
_generateDynamicModuleCallableReferences();
|
||||
|
||||
if (isDynamicModule) {
|
||||
_initDynamicModuleId();
|
||||
_initModuleRtt();
|
||||
@@ -426,6 +385,37 @@ class DynamicModuleInfo {
|
||||
b.global_set(moduleIdGlobal);
|
||||
}
|
||||
|
||||
void _generateDynamicModuleCallableReferences() {
|
||||
final references =
|
||||
translator.dynamicModuleInfo!.metadata.callableReferences;
|
||||
|
||||
for (final reference in references) {
|
||||
final member = reference.asMember;
|
||||
|
||||
if (member.isInstanceMember) {
|
||||
final selector = translator.dispatchTable.selectorForTarget(reference);
|
||||
final targetRanges = selector
|
||||
.targets(unchecked: false, dynamicModule: false)
|
||||
.targetRanges
|
||||
.followedBy(selector
|
||||
.targets(unchecked: true, dynamicModule: false)
|
||||
.targetRanges);
|
||||
// Instance members are only callable if their enclosing class is
|
||||
// allocated.
|
||||
for (final (:range, :target) in targetRanges) {
|
||||
if (target != reference) continue;
|
||||
for (int classId = range.start; classId <= range.end; ++classId) {
|
||||
translator.functions.recordClassTargetUse(classId, target);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Generate static members immediately since they are unconditionally
|
||||
// callable.
|
||||
translator.functions.getFunction(reference);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void finishDynamicModule() {
|
||||
_registerModuleRefs(
|
||||
isDynamicModule ? initFunction.body : translator.initFunction.body);
|
||||
@@ -611,99 +601,6 @@ class DynamicModuleInfo {
|
||||
translator.convertType(
|
||||
b, updatedSignature.outputs.single, signature.outputs.single);
|
||||
}
|
||||
|
||||
DynamicModuleMetadata toMetadata(WasmCompilerOptions options) {
|
||||
assert(!isDynamicModule);
|
||||
final globalIdRepository = translator
|
||||
.component.metadata[DynamicModuleGlobalIdRepository.repositoryTag]
|
||||
as DynamicModuleGlobalIdRepository;
|
||||
|
||||
final classIdMapping = <int, int>{};
|
||||
translator.classIdNumbering.classIds.forEach((cls, id) {
|
||||
classIdMapping[globalIdRepository.mapping[cls]!] =
|
||||
(id as AbsoluteClassId).value;
|
||||
});
|
||||
|
||||
final selectorIdMapping = <int, (int, int)>{};
|
||||
final procedureMetadata =
|
||||
(translator.component.metadata["vm.procedure-attributes.metadata"]
|
||||
as ProcedureAttributesMetadataRepository)
|
||||
.mapping;
|
||||
for (final library in translator.libraries) {
|
||||
for (final cls in library.classes) {
|
||||
for (final member in cls.procedures) {
|
||||
if (!member.isInstanceMember) continue;
|
||||
final globalId = globalIdRepository.mapping[member];
|
||||
// TFA might add placeholders for removed members. We can ignore
|
||||
// these.
|
||||
if (globalId == null) continue;
|
||||
selectorIdMapping[globalId] = (
|
||||
procedureMetadata[member]!.getterSelectorId,
|
||||
procedureMetadata[member]!.methodOrSetterSelectorId
|
||||
);
|
||||
}
|
||||
for (final member in cls.fields) {
|
||||
if (!member.isInstanceMember) continue;
|
||||
final globalId = globalIdRepository.mapping[member];
|
||||
// TFA might add placeholders for removed members. We can ignore
|
||||
// these.
|
||||
if (globalId == null) continue;
|
||||
selectorIdMapping[globalId] = (
|
||||
procedureMetadata[member]!.getterSelectorId,
|
||||
procedureMetadata[member]!.methodOrSetterSelectorId
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final dfsOrderClassIds = <int>[];
|
||||
for (final cls in translator.classIdNumbering.dfsOrder) {
|
||||
dfsOrderClassIds.add(globalIdRepository.mapping[cls]!);
|
||||
}
|
||||
|
||||
final callableMemberIds = <(int, int)>[];
|
||||
for (final export in translator.functions.dynamicModuleCallable) {
|
||||
final exportMember = export.asMember;
|
||||
final flag = _flagForReference(export);
|
||||
callableMemberIds.add((globalIdRepository.mapping[exportMember]!, flag));
|
||||
}
|
||||
return DynamicModuleMetadata(
|
||||
classIdMapping,
|
||||
selectorIdMapping,
|
||||
dfsOrderClassIds,
|
||||
callableMemberIds,
|
||||
_updateableDispatchKeys,
|
||||
options.translatorOptions,
|
||||
options.environment);
|
||||
}
|
||||
|
||||
static int _flagForReference(Reference reference) {
|
||||
if (reference.isImplicitGetter) return 0;
|
||||
if (reference.isImplicitSetter) return 1;
|
||||
if (reference.isTearOffReference) return 2;
|
||||
if (reference.isConstructorBodyReference) return 3;
|
||||
if (reference.isInitializerReference) return 4;
|
||||
if (reference.isTypeCheckerReference) return 5;
|
||||
if (reference.isCheckedEntryReference) return 6;
|
||||
if (reference.isUncheckedEntryReference) return 7;
|
||||
if (reference.isBodyReference) return 8;
|
||||
assert(reference == reference.asMember.reference);
|
||||
return 9;
|
||||
}
|
||||
|
||||
static Reference _referenceForFlag(Member member, int flag) {
|
||||
if (flag == 0) return (member as Field).getterReference;
|
||||
if (flag == 1) return (member as Field).setterReference!;
|
||||
if (flag == 2) return (member as Procedure).tearOffReference;
|
||||
if (flag == 3) return (member as Constructor).constructorBodyReference;
|
||||
if (flag == 4) return (member as Constructor).initializerReference;
|
||||
if (flag == 5) return member.typeCheckerReference;
|
||||
if (flag == 6) return member.checkedEntryReference;
|
||||
if (flag == 7) return member.uncheckedEntryReference;
|
||||
if (flag == 8) return member.bodyReference;
|
||||
assert(flag == 9);
|
||||
return member.reference;
|
||||
}
|
||||
}
|
||||
|
||||
/// Emits code to canonicalize the provided constant value at runtime.
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:kernel/ast.dart';
|
||||
import 'package:vm/metadata/procedure_attributes.dart'
|
||||
show ProcedureAttributesMetadataRepository;
|
||||
import 'package:wasm_builder/wasm_builder.dart' as w;
|
||||
|
||||
import 'class_info.dart';
|
||||
@@ -12,7 +10,6 @@ import 'closures.dart';
|
||||
import 'code_generator.dart';
|
||||
import 'dispatch_table.dart';
|
||||
import 'dynamic_modules.dart';
|
||||
import 'intrinsics.dart';
|
||||
import 'reference_extensions.dart';
|
||||
import 'translator.dart';
|
||||
|
||||
@@ -37,9 +34,6 @@ class FunctionCollector {
|
||||
// if an allocation of that class is encountered
|
||||
final Map<int, List<Reference>> _pendingAllocation = {};
|
||||
|
||||
/// Collection of references marked as callable from dynamic modules.
|
||||
Set<Reference> dynamicModuleCallable = {};
|
||||
|
||||
late final WasmFunctionImporter _importedDynamicModuleFunctions =
|
||||
WasmFunctionImporter(translator, '#dmf');
|
||||
|
||||
@@ -141,10 +135,6 @@ class FunctionCollector {
|
||||
}
|
||||
}
|
||||
|
||||
if (translator.dynamicModuleSupportEnabled) {
|
||||
_generateDynamicModuleCallableReferences();
|
||||
}
|
||||
|
||||
// Value classes are always implicitly allocated.
|
||||
recordClassAllocation(
|
||||
translator.classInfo[translator.boxedBoolClass]!.classId);
|
||||
@@ -154,98 +144,6 @@ class FunctionCollector {
|
||||
translator.classInfo[translator.boxedDoubleClass]!.classId);
|
||||
}
|
||||
|
||||
void _generateDynamicModuleCallableReferences() {
|
||||
final references = dynamicModuleCallable = translator.isDynamicModule
|
||||
? translator.dynamicModuleInfo!.callableReferences!.toSet()
|
||||
: _generateCallableReferences();
|
||||
|
||||
for (final reference in references) {
|
||||
final member = reference.asMember;
|
||||
|
||||
if (member.isInstanceMember) {
|
||||
final selector = translator.dispatchTable.selectorForTarget(reference);
|
||||
final targetRanges = selector
|
||||
.targets(unchecked: false, dynamicModule: false)
|
||||
.targetRanges
|
||||
.followedBy(selector
|
||||
.targets(unchecked: true, dynamicModule: false)
|
||||
.targetRanges);
|
||||
// Instance members are only callable if their enclosing class is
|
||||
// allocated.
|
||||
for (final (:range, :target) in targetRanges) {
|
||||
if (target != reference) continue;
|
||||
for (int classId = range.start; classId <= range.end; ++classId) {
|
||||
_recordClassTargetUse(classId, target);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Generate static members immediately since they are unconditionally
|
||||
// callable.
|
||||
getFunction(reference);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Set<Reference> _generateCallableReferences() {
|
||||
assert(
|
||||
translator.dynamicModuleSupportEnabled && !translator.isDynamicModule);
|
||||
|
||||
final exports = <Reference>{};
|
||||
void collectCallableReference(Reference reference) {
|
||||
final member = reference.asMember;
|
||||
|
||||
if (member.isExternal) {
|
||||
final isGeneratedIntrinsic = member is Procedure &&
|
||||
MemberIntrinsic.fromProcedure(translator.coreTypes, member) != null;
|
||||
if (!isGeneratedIntrinsic) return;
|
||||
}
|
||||
exports.add(reference);
|
||||
}
|
||||
|
||||
final procedureAttributeMetadata =
|
||||
(translator.component.metadata["vm.procedure-attributes.metadata"]
|
||||
as ProcedureAttributesMetadataRepository)
|
||||
.mapping;
|
||||
void collectCallableReferences(Member member) {
|
||||
if (member is Procedure) {
|
||||
collectCallableReference(member.reference);
|
||||
if (member.isInstanceMember &&
|
||||
member.kind == ProcedureKind.Method &&
|
||||
procedureAttributeMetadata[member]!.hasTearOffUses) {
|
||||
collectCallableReference(member.tearOffReference);
|
||||
}
|
||||
} else if (member is Field) {
|
||||
collectCallableReference(member.getterReference);
|
||||
if (member.hasSetter) {
|
||||
collectCallableReference(member.setterReference!);
|
||||
}
|
||||
} else if (member is Constructor) {
|
||||
if (translator.classInfo[member.enclosingClass]!.struct
|
||||
.isSubtypeOf(translator.objectInfo.struct)) {
|
||||
collectCallableReference(member.reference);
|
||||
collectCallableReference(member.initializerReference);
|
||||
collectCallableReference(member.constructorBodyReference);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (final lib in translator.libraries) {
|
||||
for (final member in lib.members) {
|
||||
if (!member.isDynamicModuleCallable(translator.coreTypes)) continue;
|
||||
collectCallableReferences(member);
|
||||
}
|
||||
|
||||
for (final cls in lib.classes) {
|
||||
for (final member in cls.members) {
|
||||
if (!member.isDynamicModuleCallable(translator.coreTypes)) continue;
|
||||
collectCallableReferences(member);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return exports;
|
||||
}
|
||||
|
||||
w.BaseFunction? getExistingFunction(Reference target) {
|
||||
return _functions[target];
|
||||
}
|
||||
@@ -261,8 +159,8 @@ class FunctionCollector {
|
||||
// Export the function from the main module if it is callable from dynamic
|
||||
// modules.
|
||||
if (translator.dynamicModuleSupportEnabled &&
|
||||
dynamicModuleCallable.contains(target)) {
|
||||
assert(translator.dynamicModuleSupportEnabled);
|
||||
translator.dynamicModuleInfo!.metadata.callableReferences
|
||||
.contains(target)) {
|
||||
_importedDynamicModuleFunctions.get(function, translator.dynamicModule,
|
||||
exportOnly: true);
|
||||
}
|
||||
@@ -377,7 +275,7 @@ class FunctionCollector {
|
||||
.targets(unchecked: useUncheckedEntry, dynamicModule: false)
|
||||
.targetRanges) {
|
||||
for (int classId = range.start; classId <= range.end; ++classId) {
|
||||
_recordClassTargetUse(classId, target);
|
||||
recordClassTargetUse(classId, target);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -386,14 +284,14 @@ class FunctionCollector {
|
||||
.targets(unchecked: useUncheckedEntry, dynamicModule: true)
|
||||
.targetRanges) {
|
||||
for (int classId = range.start; classId <= range.end; ++classId) {
|
||||
_recordClassTargetUse(classId, target);
|
||||
recordClassTargetUse(classId, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _recordClassTargetUse(int classId, Reference target) {
|
||||
void recordClassTargetUse(int classId, Reference target) {
|
||||
if (_allocatedClasses.contains(classId)) {
|
||||
// Class declaring or inheriting member is allocated somewhere.
|
||||
getFunction(target);
|
||||
|
||||
@@ -5,13 +5,193 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:typed_data';
|
||||
|
||||
class BinaryDataSink {
|
||||
import 'package:kernel/ast.dart';
|
||||
|
||||
import 'dynamic_module_kernel_metadata.dart';
|
||||
import 'reference_extensions.dart';
|
||||
|
||||
class _EntityToIdMapper {
|
||||
final Component component;
|
||||
final Map<TreeNode, int> _ids;
|
||||
|
||||
_EntityToIdMapper(this.component)
|
||||
: _ids =
|
||||
(component.metadata[DynamicModuleGlobalIdRepository.repositoryTag]
|
||||
as DynamicModuleGlobalIdRepository)
|
||||
.mapping;
|
||||
|
||||
int idForClass(Class cls) {
|
||||
return _ids[cls]!;
|
||||
}
|
||||
|
||||
int? idForMember(Member member) {
|
||||
return _ids[member];
|
||||
}
|
||||
|
||||
(int, int)? idForReference(Reference reference) {
|
||||
final memberId = idForMember(reference.asMember);
|
||||
if (memberId == null) return null;
|
||||
return (memberId, _flagForReference(reference));
|
||||
}
|
||||
|
||||
static int _flagForReference(Reference reference) {
|
||||
if (reference.isImplicitGetter) return 0;
|
||||
if (reference.isImplicitSetter) return 1;
|
||||
if (reference.isTearOffReference) return 2;
|
||||
if (reference.isConstructorBodyReference) return 3;
|
||||
if (reference.isInitializerReference) return 4;
|
||||
if (reference.isTypeCheckerReference) return 5;
|
||||
if (reference.isCheckedEntryReference) return 6;
|
||||
if (reference.isUncheckedEntryReference) return 7;
|
||||
if (reference.isBodyReference) return 8;
|
||||
assert(reference == reference.asMember.reference);
|
||||
return 9;
|
||||
}
|
||||
}
|
||||
|
||||
class _IdToEntityMapper {
|
||||
final Component component;
|
||||
final Map<int, TreeNode> _mapping;
|
||||
|
||||
static Map<int, TreeNode> _makeIdsMap(Component component) {
|
||||
final mapping =
|
||||
(component.metadata[DynamicModuleGlobalIdRepository.repositoryTag]
|
||||
as DynamicModuleGlobalIdRepository)
|
||||
.mapping;
|
||||
final inverse = <int, TreeNode>{};
|
||||
mapping.forEach((node, id) {
|
||||
inverse[id] = node;
|
||||
});
|
||||
return inverse;
|
||||
}
|
||||
|
||||
_IdToEntityMapper(this.component) : _mapping = _makeIdsMap(component);
|
||||
|
||||
Class classForId(int id) {
|
||||
return _mapping[id] as Class;
|
||||
}
|
||||
|
||||
Member memberForId(int id) {
|
||||
return _mapping[id] as Member;
|
||||
}
|
||||
|
||||
Reference referenceForId(int classId, int flag) {
|
||||
final member = _mapping[classId] as Member;
|
||||
return _referenceForFlag(member, flag);
|
||||
}
|
||||
|
||||
static Reference _referenceForFlag(Member member, int flag) {
|
||||
if (flag == 0) return (member as Field).getterReference;
|
||||
if (flag == 1) return (member as Field).setterReference!;
|
||||
if (flag == 2) return (member as Procedure).tearOffReference;
|
||||
if (flag == 3) return (member as Constructor).constructorBodyReference;
|
||||
if (flag == 4) return (member as Constructor).initializerReference;
|
||||
if (flag == 5) return member.typeCheckerReference;
|
||||
if (flag == 6) return member.checkedEntryReference;
|
||||
if (flag == 7) return member.uncheckedEntryReference;
|
||||
if (flag == 8) return member.bodyReference;
|
||||
assert(flag == 9);
|
||||
return member.reference;
|
||||
}
|
||||
}
|
||||
|
||||
class DataSerializer {
|
||||
final _BinaryDataSink _sink = _BinaryDataSink();
|
||||
final _EntityToIdMapper _mapper;
|
||||
|
||||
DataSerializer(Component component) : _mapper = _EntityToIdMapper(component);
|
||||
|
||||
void writeString(String value) {
|
||||
_sink.writeString(value);
|
||||
}
|
||||
|
||||
void writeInt(int value) {
|
||||
_sink.writeInt(value);
|
||||
}
|
||||
|
||||
void writeBool(bool value) {
|
||||
_sink.writeInt(value ? 1 : 0);
|
||||
}
|
||||
|
||||
void writeEnum<E extends Enum>(E value) {
|
||||
writeInt(value.index);
|
||||
}
|
||||
|
||||
void writeClass(Class cls) {
|
||||
writeInt(_mapper.idForClass(cls));
|
||||
}
|
||||
|
||||
bool writeMember(Member member) {
|
||||
final memberId = _mapper.idForMember(member);
|
||||
if (memberId == null) return false;
|
||||
writeInt(memberId);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool writeReference(Reference reference) {
|
||||
final referenceId = _mapper.idForReference(reference);
|
||||
if (referenceId == null) return false;
|
||||
writeInt(referenceId.$1);
|
||||
writeInt(referenceId.$2);
|
||||
return true;
|
||||
}
|
||||
|
||||
Uint8List takeBytes() {
|
||||
return _sink.takeBytes();
|
||||
}
|
||||
}
|
||||
|
||||
class DataDeserializer {
|
||||
final _BinaryDataSource _source;
|
||||
final _IdToEntityMapper _mapper;
|
||||
|
||||
DataDeserializer(Uint8List bytes, Component component)
|
||||
: _source = _BinaryDataSource(bytes),
|
||||
_mapper = _IdToEntityMapper(component);
|
||||
|
||||
String readString() {
|
||||
return _source.readString();
|
||||
}
|
||||
|
||||
int readInt() {
|
||||
return _source.readInt();
|
||||
}
|
||||
|
||||
bool readBool() {
|
||||
return _source.readInt() == 1;
|
||||
}
|
||||
|
||||
E readEnum<E extends Enum>(List<E> values) {
|
||||
int index = _source.readInt();
|
||||
assert(
|
||||
0 <= index && index < values.length,
|
||||
"Invalid data kind index. "
|
||||
"Expected one of $values, found index $index.");
|
||||
return values[index];
|
||||
}
|
||||
|
||||
Class readClass() {
|
||||
return _mapper.classForId(_source.readInt());
|
||||
}
|
||||
|
||||
Member readMember() {
|
||||
return _mapper.memberForId(_source.readInt());
|
||||
}
|
||||
|
||||
Reference readReference() {
|
||||
final classId = _source.readInt();
|
||||
final flag = _source.readInt();
|
||||
return _mapper.referenceForId(classId, flag);
|
||||
}
|
||||
}
|
||||
|
||||
class _BinaryDataSink {
|
||||
static const int _initSinkSize = 50 * 1024;
|
||||
|
||||
Uint8List _data = Uint8List(_initSinkSize);
|
||||
int _length = 0;
|
||||
|
||||
BinaryDataSink();
|
||||
_BinaryDataSink();
|
||||
|
||||
int get length => _length;
|
||||
|
||||
@@ -62,15 +242,6 @@ class BinaryDataSink {
|
||||
}
|
||||
}
|
||||
|
||||
void writeClassId(int value) {
|
||||
// Add 1 since some class IDs are -1.
|
||||
writeInt(value + 1);
|
||||
}
|
||||
|
||||
void writeEnum<E extends Enum>(E value) {
|
||||
writeInt(value.index);
|
||||
}
|
||||
|
||||
Uint8List takeBytes() {
|
||||
final result = Uint8List.sublistView(_data, 0, _length);
|
||||
// Free the reference to the large data list so it can potentially be
|
||||
@@ -80,11 +251,11 @@ class BinaryDataSink {
|
||||
}
|
||||
}
|
||||
|
||||
class BinaryDataSource {
|
||||
class _BinaryDataSource {
|
||||
int _byteOffset = 0;
|
||||
final Uint8List _bytes;
|
||||
|
||||
BinaryDataSource(this._bytes);
|
||||
_BinaryDataSource(this._bytes);
|
||||
|
||||
void begin(String tag) {}
|
||||
|
||||
@@ -119,20 +290,6 @@ class BinaryDataSource {
|
||||
}
|
||||
}
|
||||
|
||||
int readClassId() {
|
||||
// Subtract 1 since some class IDs are -1.
|
||||
return readInt() - 1;
|
||||
}
|
||||
|
||||
E readEnum<E extends Enum>(List<E> values) {
|
||||
int index = readInt();
|
||||
assert(
|
||||
0 <= index && index < values.length,
|
||||
"Invalid data kind index. "
|
||||
"Expected one of $values, found index $index.");
|
||||
return values[index];
|
||||
}
|
||||
|
||||
int get length => _bytes.length;
|
||||
int get currentOffset => _byteOffset;
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ class TranslatorOptions {
|
||||
bool requireJsStringBuiltin = false;
|
||||
List<int> watchPoints = [];
|
||||
|
||||
void serialize(BinaryDataSink sink) {
|
||||
void serialize(DataSerializer sink) {
|
||||
sink.writeBool(enableAsserts);
|
||||
sink.writeBool(importSharedMemory);
|
||||
sink.writeBool(inlining);
|
||||
@@ -85,7 +85,7 @@ class TranslatorOptions {
|
||||
sharedMemoryMaxPages == null ? 0 : (sharedMemoryMaxPages! + 1));
|
||||
}
|
||||
|
||||
static TranslatorOptions deserialize(BinaryDataSource source) {
|
||||
static TranslatorOptions deserialize(DataDeserializer source) {
|
||||
final TranslatorOptions options = TranslatorOptions();
|
||||
options.enableAsserts = source.readBool();
|
||||
options.importSharedMemory = source.readBool();
|
||||
@@ -410,7 +410,7 @@ class Translator with KernelNodes {
|
||||
Translator(this.component, this.coreTypes, this.index, this.recordClasses,
|
||||
this._moduleOutputData, this.options,
|
||||
{bool enableDynamicModules = false,
|
||||
DynamicModuleMetadata? dynamicModuleMetadata})
|
||||
required MainModuleMetadata mainModuleMetadata})
|
||||
: libraries = component.libraries,
|
||||
hierarchy =
|
||||
ClassHierarchy(component, coreTypes) as ClosedWorldClassHierarchy {
|
||||
@@ -425,7 +425,7 @@ class Translator with KernelNodes {
|
||||
types = Types(this);
|
||||
exceptionTag = ExceptionTag(this);
|
||||
if (enableDynamicModules) {
|
||||
dynamicModuleInfo = DynamicModuleInfo(this, dynamicModuleMetadata);
|
||||
dynamicModuleInfo = DynamicModuleInfo(this, mainModuleMetadata);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -75,6 +75,7 @@ class _RecGroupBuilder {
|
||||
late final List<List<ir.DefType>> _allRecursiveGroups =
|
||||
_createAllRecursiveGroups();
|
||||
final List<ir.DefType> _allDefinedTypes = [];
|
||||
final Map<ir.DefType, int> _brandTypeAssignments = {};
|
||||
|
||||
_RecGroupBuilder();
|
||||
|
||||
@@ -121,7 +122,7 @@ class _RecGroupBuilder {
|
||||
/// If a rec group is in an equivalence class with multiple groups, it will be
|
||||
/// assigned an index encoded as a brand type. The brand types allows the wasm
|
||||
/// type system to disambiguate members of otherwise equivalent rec groups.
|
||||
static void _assignBrandTypes(List<List<ir.DefType>> groups) {
|
||||
void _assignBrandTypes(List<List<ir.DefType>> groups) {
|
||||
// Collect rec groups joining over:
|
||||
// (1) group length
|
||||
// (2) length of first struct
|
||||
@@ -148,7 +149,12 @@ class _RecGroupBuilder {
|
||||
// All the groups in `equalGroups` are structurally equivalent.
|
||||
// Skip the first group since we can leave one group as-is.
|
||||
for (int i = 1; i < equalGroups.length; i++) {
|
||||
equalGroups[i].insert(0, _getBrandType(i - 1));
|
||||
// Key the assignment on the first element in the group. If a user is
|
||||
// trying to use the brand index to restore the group, then all other
|
||||
// elements are implicitly the same.
|
||||
final typeIndex = _brandTypeAssignments[equalGroups[i].first] ??= i - 1;
|
||||
final brandType = _getBrandType(typeIndex);
|
||||
equalGroups[i].insert(0, brandType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -241,6 +247,12 @@ class TypesBuilder with Builder<ir.Types> {
|
||||
TypesBuilder(this._module, {TypesBuilder? parent})
|
||||
: _recGroupBuilder = parent?._recGroupBuilder ?? _RecGroupBuilder();
|
||||
|
||||
Map<ir.DefType, int> get brandTypeAssignments =>
|
||||
_recGroupBuilder._brandTypeAssignments;
|
||||
|
||||
void addBrandTypeAssignment(ir.DefType type, int brandIndex) =>
|
||||
_recGroupBuilder._brandTypeAssignments[type] = brandIndex;
|
||||
|
||||
/// Add a new function type to the module.
|
||||
///
|
||||
/// All function types are canonicalized, such that identical types become
|
||||
|
||||
Reference in New Issue
Block a user