| // Copyright (c) 2017, 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. |
| |
| // @dart=2.12 |
| |
| // TODO(johnniwinther): Add a test that ensure that this library doesn't depend |
| // on the dart2js internals. |
| library compiler.src.kernel.dart2js_target; |
| |
| import 'package:_fe_analyzer_shared/src/messages/codes.dart' |
| show Message, LocatedMessage; |
| import 'package:_js_interop_checks/js_interop_checks.dart'; |
| import 'package:_js_interop_checks/src/transformations/js_util_optimizer.dart'; |
| import 'package:_js_interop_checks/src/transformations/static_interop_class_eraser.dart'; |
| import 'package:kernel/ast.dart' as ir; |
| import 'package:kernel/class_hierarchy.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 '../options.dart'; |
| import 'invocation_mirror_constants.dart'; |
| import 'transformations/clone_mixin_methods_with_super.dart' as transformMixins |
| show transformLibraries; |
| import 'transformations/lowering.dart' as lowering show transformLibraries; |
| |
| const Iterable<String> _allowedDartSchemePaths = [ |
| 'async', |
| 'html', |
| 'html_common', |
| 'indexed_db', |
| 'js', |
| 'js_util', |
| 'svg', |
| '_native_typed_data', |
| 'web_audio', |
| 'web_gl', |
| ]; |
| |
| List<Pattern> _allowedNativeTestPatterns = [ |
| RegExp(r'(?<!generated_)tests/web/native'), |
| RegExp(r'(?<!generated_)tests/web/internal'), |
| 'generated_tests/web/native/native_test', |
| RegExp(r'(?<!generated_)tests/web_2/native'), |
| RegExp(r'(?<!generated_)tests/web_2/internal'), |
| 'generated_tests/web_2/native/native_test', |
| ]; |
| |
| bool allowedNativeTest(Uri uri) { |
| String path = uri.path; |
| return _allowedNativeTestPatterns.any((pattern) => path.contains(pattern)); |
| } |
| |
| bool maybeEnableNative(Uri uri) { |
| bool allowedDartLibrary() { |
| if (!uri.isScheme('dart')) return false; |
| return _allowedDartSchemePaths.contains(uri.path); |
| } |
| |
| return allowedNativeTest(uri) || allowedDartLibrary(); |
| } |
| |
| /// A kernel [Target] to configure the Dart Front End for dart2js. |
| class Dart2jsTarget extends Target { |
| @override |
| final TargetFlags flags; |
| @override |
| final String name; |
| |
| final CompilerOptions? options; |
| final bool canPerformGlobalTransforms; |
| final bool supportsUnevaluatedConstants; |
| |
| Dart2jsTarget(this.name, this.flags, |
| {this.options, |
| this.canPerformGlobalTransforms = true, |
| this.supportsUnevaluatedConstants = true}); |
| |
| @override |
| bool get enableNoSuchMethodForwarders => true; |
| |
| @override |
| int get enabledLateLowerings => LateLowering.none; |
| |
| @override |
| bool get supportsLateLoweringSentinel => true; |
| |
| @override |
| bool get useStaticFieldLowering => false; |
| |
| // TODO(johnniwinther,sigmund): Remove this when js-interop handles getter |
| // calls encoded with an explicit property get or disallows getter calls. |
| @override |
| bool get supportsExplicitGetterCalls => false; |
| |
| @override |
| int get enabledConstructorTearOffLowerings => ConstructorTearOffLowering.all; |
| |
| @override |
| List<String> get extraRequiredLibraries => requiredLibraries[name]!; |
| |
| @override |
| List<String> get extraIndexedLibraries => const [ |
| 'dart:_foreign_helper', |
| 'dart:_interceptors', |
| 'dart:_js_helper', |
| 'dart:_late_helper', |
| 'dart:js', |
| 'dart:js_util' |
| ]; |
| |
| @override |
| bool mayDefineRestrictedType(Uri uri) => |
| uri.isScheme('dart') && |
| (uri.path == 'core' || |
| uri.path == 'typed_data' || |
| uri.path == '_interceptors' || |
| uri.path == '_native_typed_data'); |
| |
| @override |
| bool allowPlatformPrivateLibraryAccess(Uri importer, Uri imported) => |
| super.allowPlatformPrivateLibraryAccess(importer, imported) || |
| maybeEnableNative(importer) || |
| (importer.isScheme('package') && |
| importer.path.startsWith('dart2js_runtime_metrics/')); |
| |
| @override |
| bool enableNative(Uri uri) => maybeEnableNative(uri); |
| |
| @override |
| bool get nativeExtensionExpectsString => false; |
| |
| @override |
| bool get errorOnUnexactWebIntLiterals => true; |
| |
| @override |
| void performModularTransformationsOnLibraries( |
| ir.Component component, |
| CoreTypes coreTypes, |
| ClassHierarchy hierarchy, |
| List<ir.Library> libraries, |
| Map<String, String>? environmentDefines, |
| DiagnosticReporter diagnosticReporter, |
| ReferenceFromIndex? referenceFromIndex, |
| {void Function(String msg)? logger, |
| ChangedStructureNotifier? changedStructureNotifier}) { |
| var nativeClasses = JsInteropChecks.getNativeClasses(component); |
| var jsUtilOptimizer = JsUtilOptimizer(coreTypes, hierarchy); |
| var staticInteropClassEraser = StaticInteropClassEraser(coreTypes); |
| for (var library in libraries) { |
| JsInteropChecks( |
| coreTypes, |
| diagnosticReporter as DiagnosticReporter<Message, LocatedMessage>, |
| nativeClasses) |
| .visitLibrary(library); |
| // TODO (rileyporter): Merge js_util optimizations with other lowerings |
| // in the single pass in `transformations/lowering.dart`. |
| jsUtilOptimizer.visitLibrary(library); |
| staticInteropClassEraser.visitLibrary(library); |
| } |
| lowering.transformLibraries(libraries, coreTypes, hierarchy, options); |
| logger?.call("Lowering transformations performed"); |
| if (canPerformGlobalTransforms) { |
| transformMixins.transformLibraries(libraries); |
| logger?.call("Mixin transformations performed"); |
| } |
| } |
| |
| @override |
| ir.Expression instantiateInvocation( |
| CoreTypes coreTypes, |
| ir.Expression receiver, |
| String name, |
| ir.Arguments arguments, |
| int offset, |
| bool isSuper) { |
| int kind; |
| if (name.startsWith('get:')) { |
| kind = invocationMirrorGetterKind; |
| name = name.substring(4); |
| } else if (name.startsWith('set:')) { |
| kind = invocationMirrorSetterKind; |
| name = name.substring(4); |
| } else { |
| kind = invocationMirrorMethodKind; |
| } |
| return ir.StaticInvocation( |
| coreTypes.index |
| .getTopLevelProcedure('dart:core', '_createInvocationMirror'), |
| ir.Arguments(<ir.Expression>[ |
| ir.StringLiteral(name)..fileOffset = offset, |
| ir.ListLiteral(arguments.types |
| .map<ir.Expression>((t) => ir.TypeLiteral(t)) |
| .toList()), |
| ir.ListLiteral(arguments.positional)..fileOffset = offset, |
| ir.MapLiteral(List<ir.MapLiteralEntry>.from( |
| arguments.named.map((ir.NamedExpression arg) { |
| return ir.MapLiteralEntry( |
| ir.StringLiteral(arg.name)..fileOffset = arg.fileOffset, |
| arg.value) |
| ..fileOffset = arg.fileOffset; |
| })), keyType: coreTypes.stringNonNullableRawType) |
| ..isConst = (arguments.named.length == 0) |
| ..fileOffset = arguments.fileOffset, |
| ir.IntLiteral(kind)..fileOffset = offset, |
| ])) |
| ..fileOffset = offset; |
| } |
| |
| @override |
| ir.Expression instantiateNoSuchMethodError(CoreTypes coreTypes, |
| ir.Expression receiver, String name, ir.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}) { |
| // TODO(sigmund): implement; |
| return ir.InvalidExpression(null); |
| } |
| |
| @override |
| ConstantsBackend get constantsBackend => Dart2jsConstantsBackend( |
| supportsUnevaluatedConstants: supportsUnevaluatedConstants); |
| |
| @override |
| DartLibrarySupport get dartLibrarySupport => |
| const Dart2jsDartLibrarySupport(); |
| } |
| |
| const implicitlyUsedLibraries = <String>[ |
| 'dart:_foreign_helper', |
| 'dart:_interceptors', |
| 'dart:_js_helper', |
| 'dart:_late_helper', |
| 'dart:js_util' |
| ]; |
| |
| // TODO(sigmund): this "extraRequiredLibraries" needs to be removed... |
| // compile-platform should just specify which libraries to compile instead. |
| const requiredLibraries = <String, List<String>>{ |
| 'dart2js': [ |
| 'dart:_async_await_error_codes', |
| 'dart:_dart2js_runtime_metrics', |
| 'dart:_foreign_helper', |
| 'dart:_http', |
| 'dart:_interceptors', |
| 'dart:_internal', |
| 'dart:_js', |
| 'dart:_js_annotations', |
| 'dart:_js_embedded_names', |
| 'dart:_js_helper', |
| 'dart:_js_names', |
| 'dart:_js_primitives', |
| 'dart:_late_helper', |
| 'dart:_metadata', |
| 'dart:_native_typed_data', |
| 'dart:_recipe_syntax', |
| 'dart:_rti', |
| 'dart:async', |
| 'dart:collection', |
| 'dart:convert', |
| 'dart:developer', |
| 'dart:html', |
| 'dart:html_common', |
| 'dart:indexed_db', |
| 'dart:io', |
| 'dart:isolate', |
| 'dart:js', |
| 'dart:js_util', |
| 'dart:math', |
| 'dart:svg', |
| 'dart:typed_data', |
| 'dart:web_audio', |
| 'dart:web_gl', |
| ], |
| 'dart2js_server': [ |
| 'dart:_async_await_error_codes', |
| 'dart:_dart2js_runtime_metrics', |
| 'dart:_foreign_helper', |
| 'dart:_http', |
| 'dart:_interceptors', |
| 'dart:_internal', |
| 'dart:_js', |
| 'dart:_js_annotations', |
| 'dart:_js_embedded_names', |
| 'dart:_js_helper', |
| 'dart:_js_names', |
| 'dart:_js_primitives', |
| 'dart:_late_helper', |
| 'dart:_native_typed_data', |
| 'dart:_recipe_syntax', |
| 'dart:_rti', |
| 'dart:async', |
| 'dart:collection', |
| 'dart:convert', |
| 'dart:developer', |
| 'dart:io', |
| 'dart:isolate', |
| 'dart:js', |
| 'dart:js_util', |
| 'dart:math', |
| 'dart:typed_data', |
| ] |
| }; |
| |
| /// Extends the Dart2jsTarget to transform outlines to meet the requirements |
| /// of summaries in bazel and package-build. |
| class Dart2jsSummaryTarget extends Dart2jsTarget with SummaryMixin { |
| @override |
| final List<Uri> sources; |
| |
| @override |
| final bool excludeNonSources; |
| |
| Dart2jsSummaryTarget(String name, this.sources, this.excludeNonSources, |
| TargetFlags targetFlags) |
| : super(name, targetFlags); |
| } |
| |
| class Dart2jsConstantsBackend extends ConstantsBackend { |
| @override |
| final bool supportsUnevaluatedConstants; |
| |
| const Dart2jsConstantsBackend({required this.supportsUnevaluatedConstants}); |
| |
| @override |
| NumberSemantics get numberSemantics => NumberSemantics.js; |
| } |
| |
| class Dart2jsDartLibrarySupport extends CustomizedDartLibrarySupport { |
| const Dart2jsDartLibrarySupport() |
| : super(supported: const {'_dart2js_runtime_metrics'}); |
| } |