| // Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| import 'package:kernel/ast.dart'; |
| import 'package:kernel/class_hierarchy.dart'; |
| import 'package:kernel/clone.dart'; |
| import 'package:kernel/core_types.dart'; |
| import 'package:kernel/reference_from_index.dart'; |
| import 'package:kernel/target/changed_structure_notifier.dart'; |
| import 'package:kernel/target/targets.dart'; |
| import 'package:vm/transformations/mixin_full_resolution.dart' |
| as transformMixins show transformLibraries; |
| import 'package:vm/transformations/ffi/common.dart' as ffiHelper |
| show calculateTransitiveImportsOfDartFfiIfUsed; |
| import 'package:vm/transformations/ffi/definitions.dart' |
| as transformFfiDefinitions show transformLibraries; |
| import 'package:vm/transformations/ffi/use_sites.dart' as transformFfiUseSites |
| show transformLibraries; |
| |
| import 'package:dart2wasm/constants_backend.dart'; |
| import 'package:dart2wasm/transformers.dart' as wasmTrans; |
| |
| class WasmTarget extends Target { |
| Class? _growableList; |
| Class? _immutableList; |
| Class? _wasmImmutableLinkedHashMap; |
| Class? _unmodifiableSet; |
| Class? _compactLinkedCustomHashMap; |
| Class? _compactLinkedHashSet; |
| Class? _oneByteString; |
| Class? _twoByteString; |
| |
| @override |
| late final ConstantsBackend constantsBackend; |
| |
| @override |
| String get name => 'wasm'; |
| |
| @override |
| TargetFlags get flags => TargetFlags(enableNullSafety: true); |
| |
| @override |
| List<String> get extraRequiredLibraries => const <String>[ |
| 'dart:ffi', |
| 'dart:_internal', |
| 'dart:typed_data', |
| 'dart:nativewrappers', |
| 'dart:js_util_wasm', |
| ]; |
| |
| @override |
| List<String> get extraIndexedLibraries => const <String>[ |
| "dart:collection", |
| "dart:typed_data", |
| ]; |
| |
| void _patchHostEndian(CoreTypes coreTypes) { |
| // Fix Endian.host to be a const field equal to Endian.little instead of |
| // a final field. Wasm is a little-endian platform. |
| // Can't use normal patching process for this because CFE does not |
| // support patching fields. |
| // See http://dartbug.com/32836 for the background. |
| final Field host = |
| coreTypes.index.getField('dart:typed_data', 'Endian', 'host'); |
| final Field little = |
| coreTypes.index.getField('dart:typed_data', 'Endian', 'little'); |
| host.isConst = true; |
| host.initializer = new CloneVisitorNotMembers().clone(little.initializer!) |
| ..parent = host; |
| } |
| |
| @override |
| void performPreConstantEvaluationTransformations( |
| Component component, |
| CoreTypes coreTypes, |
| List<Library> libraries, |
| DiagnosticReporter diagnosticReporter, |
| {void Function(String msg)? logger, |
| ChangedStructureNotifier? changedStructureNotifier}) { |
| constantsBackend = WasmConstantsBackend(coreTypes); |
| _patchHostEndian(coreTypes); |
| } |
| |
| @override |
| void performModularTransformationsOnLibraries( |
| Component component, |
| CoreTypes coreTypes, |
| ClassHierarchy hierarchy, |
| List<Library> libraries, |
| Map<String, String>? environmentDefines, |
| DiagnosticReporter diagnosticReporter, |
| ReferenceFromIndex? referenceFromIndex, |
| {void logger(String msg)?, |
| ChangedStructureNotifier? changedStructureNotifier}) { |
| transformMixins.transformLibraries( |
| this, coreTypes, hierarchy, libraries, referenceFromIndex); |
| logger?.call("Transformed mixin applications"); |
| |
| List<Library>? transitiveImportingDartFfi = ffiHelper |
| .calculateTransitiveImportsOfDartFfiIfUsed(component, libraries); |
| if (transitiveImportingDartFfi == null) { |
| logger?.call("Skipped ffi transformation"); |
| } else { |
| transformFfiDefinitions.transformLibraries( |
| component, |
| coreTypes, |
| hierarchy, |
| transitiveImportingDartFfi, |
| diagnosticReporter, |
| referenceFromIndex, |
| changedStructureNotifier); |
| transformFfiUseSites.transformLibraries(component, coreTypes, hierarchy, |
| transitiveImportingDartFfi, diagnosticReporter, referenceFromIndex); |
| logger?.call("Transformed ffi annotations"); |
| } |
| |
| wasmTrans.transformLibraries(libraries, coreTypes, hierarchy); |
| } |
| |
| @override |
| void performTransformationsOnProcedure( |
| CoreTypes coreTypes, |
| ClassHierarchy hierarchy, |
| Procedure procedure, |
| Map<String, String>? environmentDefines, |
| {void logger(String msg)?}) { |
| wasmTrans.transformProcedure(procedure, coreTypes, hierarchy); |
| } |
| |
| @override |
| Expression instantiateInvocation(CoreTypes coreTypes, Expression receiver, |
| String name, Arguments arguments, int offset, bool isSuper) { |
| throw "Unsupported: instantiateInvocation"; |
| } |
| |
| Expression instantiateNoSuchMethodError(CoreTypes coreTypes, |
| Expression receiver, String name, Arguments arguments, int offset, |
| {bool isMethod: false, |
| bool isGetter: false, |
| bool isSetter: false, |
| bool isField: false, |
| bool isLocalVariable: false, |
| bool isDynamic: false, |
| bool isSuper: false, |
| bool isStatic: false, |
| bool isConstructor: false, |
| bool isTopLevel: false}) { |
| throw "Unsupported: instantiateNoSuchMethodError"; |
| } |
| |
| @override |
| bool get supportsSetLiterals => false; |
| |
| @override |
| int get enabledLateLowerings => LateLowering.all; |
| |
| @override |
| int get enabledConstructorTearOffLowerings => ConstructorTearOffLowering.all; |
| |
| @override |
| bool get supportsExplicitGetterCalls => true; |
| |
| @override |
| bool get supportsLateLoweringSentinel => false; |
| |
| @override |
| bool get useStaticFieldLowering => false; |
| |
| @override |
| bool enableNative(Uri uri) => true; |
| |
| @override |
| Class concreteListLiteralClass(CoreTypes coreTypes) { |
| return _growableList ??= |
| coreTypes.index.getClass('dart:core', '_GrowableList'); |
| } |
| |
| @override |
| Class concreteConstListLiteralClass(CoreTypes coreTypes) { |
| return _immutableList ??= |
| coreTypes.index.getClass('dart:core', '_ImmutableList'); |
| } |
| |
| @override |
| Class concreteMapLiteralClass(CoreTypes coreTypes) { |
| return _compactLinkedCustomHashMap ??= coreTypes.index |
| .getClass('dart:collection', '_CompactLinkedCustomHashMap'); |
| } |
| |
| @override |
| Class concreteConstMapLiteralClass(CoreTypes coreTypes) { |
| return _wasmImmutableLinkedHashMap ??= coreTypes.index |
| .getClass('dart:collection', '_WasmImmutableLinkedHashMap'); |
| } |
| |
| @override |
| Class concreteSetLiteralClass(CoreTypes coreTypes) { |
| return _compactLinkedHashSet ??= |
| coreTypes.index.getClass('dart:collection', '_CompactLinkedHashSet'); |
| } |
| |
| @override |
| Class concreteConstSetLiteralClass(CoreTypes coreTypes) { |
| return _unmodifiableSet ??= |
| coreTypes.index.getClass('dart:collection', '_UnmodifiableSet'); |
| } |
| |
| @override |
| Class concreteStringLiteralClass(CoreTypes coreTypes, String value) { |
| const int maxLatin1 = 0xff; |
| for (int i = 0; i < value.length; ++i) { |
| if (value.codeUnitAt(i) > maxLatin1) { |
| return _twoByteString ??= |
| coreTypes.index.getClass('dart:core', '_TwoByteString'); |
| } |
| } |
| return _oneByteString ??= |
| coreTypes.index.getClass('dart:core', '_OneByteString'); |
| } |
| |
| @override |
| bool isSupportedPragma(String pragmaName) => pragmaName.startsWith("wasm:"); |
| } |