Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(27)

Unified Diff: pkg/compiler/lib/src/js_backend/backend.dart

Issue 2685573002: Replace Backend with JavaScriptBackend. (Closed)
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/compiler/lib/src/js_backend/backend.dart
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index e2bc6c8bab58189f34bd06f817cd3c590ffb5ace..9ae269b6475e4fcfd727655be2d200c96741524e 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -11,15 +11,11 @@ import 'package:js_runtime/shared/embedded_names.dart' as embeddedNames;
import '../closure.dart';
import '../common.dart';
import '../common/backend_api.dart'
- show
- Backend,
- BackendClasses,
- ImpactTransformer,
- ForeignResolver,
- NativeRegistry;
+ show BackendClasses, ImpactTransformer, ForeignResolver, NativeRegistry;
import '../common/codegen.dart' show CodegenImpact, CodegenWorkItem;
import '../common/names.dart' show Identifiers, Uris;
-import '../common/resolution.dart' show Frontend, Resolution, ResolutionImpact;
+import '../common/resolution.dart'
+ show Frontend, Resolution, ResolutionImpact, Target;
import '../common/tasks.dart' show CompilerTask;
import '../compiler.dart' show Compiler;
import '../constants/constant_system.dart';
@@ -33,7 +29,7 @@ import '../elements/entities.dart';
import '../elements/resolution_types.dart';
import '../elements/types.dart';
import '../enqueue.dart'
- show Enqueuer, ResolutionEnqueuer, TreeShakingEnqueuerStrategy;
+ show Enqueuer, EnqueueTask, ResolutionEnqueuer, TreeShakingEnqueuerStrategy;
import '../io/position_information.dart' show PositionSourceInformationStrategy;
import '../io/source_information.dart' show SourceInformationStrategy;
import '../io/start_end_information.dart'
@@ -45,6 +41,8 @@ import '../js/rewrite_async.dart';
import '../js_emitter/js_emitter.dart' show CodeEmitterTask;
import '../library_loader.dart' show LibraryLoader, LoadedLibraries;
import '../native/native.dart' as native;
+import '../patch_parser.dart'
+ show checkNativeAnnotation, checkJsInteropAnnotation;
import '../ssa/ssa.dart' show SsaFunctionCompiler;
import '../tracer.dart';
import '../tree/tree.dart';
@@ -304,9 +302,12 @@ enum SyntheticConstantKind {
NAME
}
-class JavaScriptBackend extends Backend {
+class JavaScriptBackend extends Target {
+ final Compiler compiler;
+
String get patchVersion => emitter.patchVersion;
+ /// Returns true if the backend supports reflection.
bool get supportsReflection => emitter.supportsReflection;
final Annotations annotations;
@@ -530,17 +531,23 @@ class JavaScriptBackend extends Backend {
/// Builds kernel representation for the program.
KernelTask kernelTask;
+ /// The compiler task responsible for the compilation of constants for both
+ /// the frontend and the backend.
JavaScriptConstantTask constantCompilerTask;
+ /// Backend transformation methods for the world impacts.
JavaScriptImpactTransformer impactTransformer;
PatchResolverTask patchResolverTask;
+ /// Whether or not `noSuchMethod` support has been enabled.
bool enabledNoSuchMethod = false;
bool _noSuchMethodEnabledForCodegen = false;
+ /// The strategy used for collecting and emitting source information.
SourceInformationStrategy sourceInformationStrategy;
+ /// Interface for serialization of backend specific data.
JavaScriptBackendSerialization serialization;
StagedWorldImpactBuilder constantImpactsForResolution =
@@ -553,8 +560,11 @@ class JavaScriptBackend extends Backend {
BackendHelpers helpers;
final BackendImpacts impacts;
+
+ /// Common classes used by the backend.
BackendClasses backendClasses;
+ /// Backend access to the front-end.
final JSFrontendAccess frontend;
Tracer tracer;
@@ -577,7 +587,7 @@ class JavaScriptBackend extends Backend {
: const JavaScriptSourceInformationStrategy(),
impacts = new BackendImpacts(compiler),
frontend = new JSFrontendAccess(compiler),
- super(compiler) {
+ this.compiler = compiler {
helpers =
new BackendHelpers(compiler.elementEnvironment, this, commonElements);
emitter =
@@ -599,6 +609,8 @@ class JavaScriptBackend extends Backend {
backendClasses = new JavaScriptBackendClasses(helpers);
}
+ /// The [ConstantSystem] used to interpret compile-time constants for this
+ /// backend.
ConstantSystem get constantSystem => constants.constantSystem;
DiagnosticReporter get reporter => compiler.reporter;
@@ -675,11 +687,11 @@ class JavaScriptBackend extends Backend {
assert(invariant(element, element.isDeclaration, message: ""));
if (element is ConstructorElement &&
(element == helpers.streamIteratorConstructor ||
- compiler.commonElements.isSymbolConstructor(element) ||
- helpers.isSymbolValidatedConstructor(element) ||
- element == helpers.syncCompleterConstructor)) {
- // TODO(johnniwinther): These are valid but we could be more precise.
- return true;
+ compiler.commonElements.isSymbolConstructor(element) ||
+ helpers.isSymbolValidatedConstructor(element) ||
+ element == helpers.syncCompleterConstructor)) {
+ // TODO(johnniwinther): These are valid but we could be more precise.
+ return true;
} else if (element == commonElements.symbolClass ||
element == helpers.objectNoSuchMethod) {
// TODO(johnniwinther): These are valid but we could be more precise.
@@ -734,6 +746,10 @@ class JavaScriptBackend extends Backend {
return isAccessibleByReflection(element.declaration);
}
+ /// Returns true if global optimizations such as type inferencing
+ /// can apply to this element. One category of elements that do not
+ /// apply is runtime helpers that the backend calls, but the
+ /// optimizations don't see those calls.
bool canBeUsedForGlobalOptimizations(Element element) {
return !usedByBackend(element) && !invokedReflectively(element);
}
@@ -781,7 +797,7 @@ class JavaScriptBackend extends Backend {
return aliasedSuperMembers.contains(member);
}
- /// Returns `true` if [element] is part of JsInterop.
+ /// Returns `true` if [element] is implemented via typed JavaScript interop.
@override
bool isJsInterop(Element element) => nativeData.isJsInterop(element);
@@ -1056,6 +1072,7 @@ class JavaScriptBackend extends Backend {
}
}
+ /// Called during codegen when [constant] has been used.
void computeImpactForCompileTimeConstant(ConstantValue constant,
WorldImpactBuilder impactBuilder, bool isForResolution) {
computeImpactForCompileTimeConstantInternal(
@@ -1128,11 +1145,16 @@ class JavaScriptBackend extends Backend {
}
}
+ /// Called to notify to the backend that a class is being instantiated. Any
+ /// backend specific [WorldImpact] of this is returned.
WorldImpact registerInstantiatedClass(ClassElement cls,
{bool forResolution}) {
return _processClass(cls, forResolution: forResolution);
}
+ /// Called to notify to the backend that a class is implemented by an
+ /// instantiated class. Any backend specific [WorldImpact] of this is
+ /// returned.
WorldImpact registerImplementedClass(ClassElement cls, {bool forResolution}) {
return _processClass(cls, forResolution: forResolution);
}
@@ -1265,11 +1287,13 @@ class JavaScriptBackend extends Backend {
return impactBuilder;
}
+ /// Called to instruct to the backend register [type] as instantiated on
+ /// [enqueuer].
void registerInstantiatedType(ResolutionInterfaceType type) {
lookupMapAnalysis.registerInstantiatedType(type);
}
- @override
+ /// Compute the [WorldImpact] for backend helper methods.
WorldImpact computeHelpersImpact() {
assert(helpers.interceptorsLibrary != null);
WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl();
@@ -1293,7 +1317,7 @@ class JavaScriptBackend extends Backend {
return impactBuilder;
}
- onResolutionComplete(
+ void onResolutionComplete(
ClosedWorld closedWorld, ClosedWorldRefiner closedWorldRefiner) {
for (Entity entity in compiler.enqueuer.resolution.processedEntities) {
processAnnotations(entity, closedWorldRefiner);
@@ -1304,8 +1328,7 @@ class JavaScriptBackend extends Backend {
_registeredMetadata.clear();
}
- onTypeInferenceComplete() {
- super.onTypeInferenceComplete();
+ void onTypeInferenceComplete() {
noSuchMethodRegistry.onTypeInferenceComplete();
}
@@ -1322,6 +1345,9 @@ class JavaScriptBackend extends Backend {
return const WorldImpact();
}
+ /// Called to instruct the backend to register that a closure exists for a
+ /// function on an instantiated generic class. Any backend specific
+ /// [WorldImpact] of this is returned.
WorldImpact registerClosureWithFreeTypeVariables(Element closure,
{bool forResolution}) {
if (forResolution || methodNeedsRti(closure)) {
@@ -1330,10 +1356,14 @@ class JavaScriptBackend extends Backend {
return const WorldImpact();
}
+ /// Called to register that a member has been closurized. Any backend specific
+ /// [WorldImpact] of this is returned.
WorldImpact registerBoundClosure() {
return impactTransformer.createImpactFor(impacts.memberClosure);
}
+ /// Called to register that a static function has been closurized. Any backend
+ /// specific [WorldImpact] of this is returned.
WorldImpact registerGetOfStaticFunction() {
return impactTransformer.createImpactFor(impacts.staticClosure);
}
@@ -1348,11 +1378,14 @@ class JavaScriptBackend extends Backend {
return impactTransformer.createImpactFor(impacts.runtimeTypeSupport);
}
+ /// Register a runtime type variable bound tests between [typeArgument] and
+ /// [bound].
void registerTypeVariableBoundsSubtypeCheck(
ResolutionDartType typeArgument, ResolutionDartType bound) {
rti.registerTypeVariableBoundsSubtypeCheck(typeArgument, bound);
}
+ /// Returns the [WorldImpact] of enabling deferred loading.
WorldImpact computeDeferredLoadingImpact() {
return impactTransformer.createImpactFor(impacts.deferredLoading);
}
@@ -1400,6 +1433,8 @@ class JavaScriptBackend extends Backend {
return impactTransformer.createImpactFor(impacts.noSuchMethodSupport);
}
+ /// Called to enable support for isolates. Any backend specific [WorldImpact]
+ /// of this is returned.
WorldImpact enableIsolateSupport({bool forResolution}) {
WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl();
// TODO(floitsch): We should also ensure that the class IsolateMessage is
@@ -1444,6 +1479,7 @@ class JavaScriptBackend extends Backend {
CodegenEnqueuer get codegenEnqueuer => compiler.enqueuer.codegen;
+ /// Creates an [Enqueuer] for code generation specific to this backend.
CodegenEnqueuer createCodegenEnqueuer(CompilerTask task, Compiler compiler) {
return new CodegenEnqueuer(
task, this, compiler.options, const TreeShakingEnqueuerStrategy());
@@ -1548,6 +1584,7 @@ class JavaScriptBackend extends Backend {
return jsAst.prettyPrint(generatedCode[element], compiler);
}
+ /// Generates the output and returns the total size of the generated code.
int assembleProgram(ClosedWorld closedWorld) {
int programSize = emitter.assembleProgram(namer, closedWorld);
noSuchMethodRegistry.emitDiagnostic();
@@ -1769,6 +1806,8 @@ class JavaScriptBackend extends Backend {
return _closedWorld.hasOnlySubclasses(classElement);
}
+ /// Called to register that [element] is statically known to be used. Any
+ /// backend specific [WorldImpact] of this is returned.
WorldImpact registerUsedElement(MemberElement element, {bool forResolution}) {
WorldImpactBuilderImpl worldImpact = new WorldImpactBuilderImpl();
if (element == helpers.disableTreeShakingMarker) {
@@ -1892,31 +1931,54 @@ class JavaScriptBackend extends Backend {
return false;
}
+ /// This method is called immediately after the [library] and its parts have
+ /// been scanned.
Future onLibraryScanned(LibraryElement library, LibraryLoader loader) {
- return super.onLibraryScanned(library, loader).then((_) {
- if (library.isPlatformLibrary &&
- // Don't patch library currently disallowed.
- !library.isSynthesized &&
- !library.isPatched &&
- // Don't patch deserialized libraries.
- !compiler.serialization.isDeserialized(library)) {
- // Apply patch, if any.
- Uri patchUri = compiler.resolvePatchUri(library.canonicalUri.path);
- if (patchUri != null) {
- return compiler.patchParser.patchLibrary(loader, patchUri, library);
- }
+ // TODO(johnniwinther): Move this to [JavaScriptBackend].
Siggi Cherem (dart-lang) 2017/02/08 00:10:03 remove TODO?
Johnni Winther 2017/02/08 09:46:35 Done.
+ if (!compiler.serialization.isDeserialized(library)) {
+ if (canLibraryUseNative(library)) {
+ library.forEachLocalMember((Element element) {
+ if (element.isClass) {
+ checkNativeAnnotation(compiler, element);
+ }
+ });
}
- }).then((_) {
- Uri uri = library.canonicalUri;
- if (uri == Uris.dart_html) {
- htmlLibraryIsLoaded = true;
- } else if (uri == LookupMapAnalysis.PACKAGE_LOOKUP_MAP) {
- lookupMapAnalysis.init(library);
+ checkJsInteropAnnotation(compiler, library);
+ library.forEachLocalMember((Element element) {
+ checkJsInteropAnnotation(compiler, element);
+ if (element.isClass && isJsInterop(element)) {
+ ClassElement classElement = element;
+ classElement.forEachMember((_, memberElement) {
+ checkJsInteropAnnotation(compiler, memberElement);
+ });
+ }
+ });
+ }
+ if (library.isPlatformLibrary &&
+ // Don't patch library currently disallowed.
+ !library.isSynthesized &&
+ !library.isPatched &&
+ // Don't patch deserialized libraries.
+ !compiler.serialization.isDeserialized(library)) {
+ // Apply patch, if any.
+ Uri patchUri = compiler.resolvePatchUri(library.canonicalUri.path);
+ if (patchUri != null) {
+ return compiler.patchParser.patchLibrary(loader, patchUri, library);
}
- annotations.onLibraryScanned(library);
- });
+ }
+ Uri uri = library.canonicalUri;
+ if (uri == Uris.dart_html) {
+ htmlLibraryIsLoaded = true;
+ } else if (uri == LookupMapAnalysis.PACKAGE_LOOKUP_MAP) {
+ lookupMapAnalysis.init(library);
+ }
+ annotations.onLibraryScanned(library);
+ return new Future.value();
}
+ /// This method is called when all new libraries loaded through
+ /// [LibraryLoader.loadLibrary] has been loaded and their imports/exports
+ /// have been computed.
Future onLibrariesLoaded(LoadedLibraries loadedLibraries) {
if (!loadedLibraries.containsLibrary(Uris.dart_core)) {
return new Future.value();
@@ -1949,6 +2011,9 @@ class JavaScriptBackend extends Backend {
return new Future.value();
}
+ /// Called by [MirrorUsageAnalyzerTask] after it has merged all @MirrorsUsed
+ /// annotations. The arguments corresponds to the unions of the corresponding
+ /// fields of the annotations.
void registerMirrorUsage(
Set<String> symbols, Set<Element> targets, Set<Element> metaTargets) {
if (symbols == null && targets == null && metaTargets == null) {
@@ -1988,26 +2053,27 @@ class JavaScriptBackend extends Backend {
return membersNeededForReflection.contains(element);
}
+ /// Returns `true` if this member element needs reflection information at
+ /// runtime.
bool isMemberAccessibleByReflection(MemberElement element) {
return membersNeededForReflection.contains(element);
}
- /**
- * Returns true if the element has to be resolved due to a mirrorsUsed
- * annotation. If we have insufficient mirrors used annotations, we only
- * keep additional elements if treeshaking has been disabled.
- */
+ /// Returns true if this element has to be enqueued due to
+ /// mirror usage. Might be a subset of [referencedFromMirrorSystem] if
+ /// normal tree shaking is still active ([isTreeShakingDisabled] is false).
bool requiredByMirrorSystem(Element element) {
return hasInsufficientMirrorsUsed && isTreeShakingDisabled ||
matchesMirrorsMetaTarget(element) ||
targetsUsed.contains(element);
}
- /**
- * Returns true if the element matches a mirrorsUsed annotation. If
- * we have insufficient mirrorsUsed information, this returns true for
- * all elements, as they might all be potentially referenced.
- */
+ /// Returns true if this element is covered by a mirrorsUsed annotation.
+ ///
+ /// Note that it might still be ok to tree shake the element away if no
+ /// reflection is used in the program (and thus [isTreeShakingDisabled] is
+ /// still false). Therefore _do not_ use this predicate to decide inclusion
+ /// in the tree, use [requiredByMirrorSystem] instead.
bool referencedFromMirrorSystem(Element element, [recursive = true]) {
Element enclosing = recursive ? element.enclosingElement : null;
@@ -2244,7 +2310,22 @@ class JavaScriptBackend extends Backend {
return staticFields;
}
- /// Called when [enqueuer] is empty, but before it is closed.
+ /// Called when [enqueuer]'s queue is empty, but before it is closed.
+ ///
+ /// This is used, for example, by the JS backend to enqueue additional
+ /// elements needed for reflection. [recentClasses] is a collection of
+ /// all classes seen for the first time by the [enqueuer] since the last call
+ /// to [onQueueEmpty].
+ ///
+ /// A return value of [:true:] indicates that [recentClasses] has been
+ /// processed and its elements do not need to be seen in the next round. When
+ /// [:false:] is returned, [onQueueEmpty] will be called again once the
+ /// resolution queue has drained and [recentClasses] will be a superset of the
+ /// current value.
+ ///
+ /// There is no guarantee that a class is only present once in
+ /// [recentClasses], but every class seen by the [enqueuer] will be present in
+ /// [recentClasses] at least once.
bool onQueueEmpty(Enqueuer enqueuer, Iterable<ClassEntity> recentClasses) {
// Add elements used synthetically, that is, through features rather than
// syntax, for instance custom elements.
@@ -2385,6 +2466,8 @@ class JavaScriptBackend extends Backend {
entities.forEach(processElementMetadata);
}
+ /// Called after the queue is closed. [onQueueEmpty] may be called multiple
+ /// times, but [onQueueClosed] is only called once.
void onQueueClosed() {
lookupMapAnalysis.onQueueClosed();
jsInteropAnalysis.onQueueClosed();
@@ -2403,6 +2486,8 @@ class JavaScriptBackend extends Backend {
_closedWorldCache = value;
}
+ /// Called when the compiler starts running the codegen enqueuer. The
+ /// [WorldImpact] of enabled backend features is returned.
WorldImpact onCodegenStart(ClosedWorld closedWorld) {
_closedWorld = closedWorld;
_namer = determineNamer(_closedWorld, compiler.codegenWorldBuilder);
@@ -2415,11 +2500,30 @@ class JavaScriptBackend extends Backend {
return const WorldImpact();
}
+ /// Called when code generation has been completed.
void onCodegenEnd() {
sourceInformationStrategy.onComplete();
tracer.close();
}
+ // Does this element belong in the output
+ bool shouldOutput(Element element) => true;
+
+ /// Returns `true` if the `native` pseudo keyword is supported for [library].
+ bool canLibraryUseNative(LibraryElement library) {
+ return native.maybeEnableNative(compiler, library);
+ }
+
+ @override
+ bool isTargetSpecificLibrary(LibraryElement library) {
+ Uri canonicalUri = library.canonicalUri;
+ if (canonicalUri == BackendHelpers.DART_JS_HELPER ||
+ canonicalUri == BackendHelpers.DART_INTERCEPTORS) {
+ return true;
+ }
+ return false;
+ }
+
/// Process backend specific annotations.
void processAnnotations(
Element element, ClosedWorldRefiner closedWorldRefiner) {
@@ -2506,7 +2610,7 @@ class JavaScriptBackend extends Backend {
MethodElement helperForMainArity() => helpers.mainHasTooManyParameters;
- @override
+ /// Computes the [WorldImpact] of calling [mainMethod] as the entry point.
WorldImpact computeMainImpact(MethodElement mainMethod,
{bool forResolution}) {
WorldImpactBuilderImpl mainImpact = new WorldImpactBuilderImpl();
@@ -2540,10 +2644,12 @@ class JavaScriptBackend extends Backend {
return "${outName}_$name$extension";
}
- @override
+ /// Enable deferred loading. Returns `true` if the backend supports deferred
+ /// loading.
bool enableDeferredLoadingIfSupported(Spannable node) => true;
- @override
+ /// Enable compilation of code with compile time errors. Returns `true` if
+ /// supported by the backend.
bool enableCodegenWithErrorsIfSupported(Spannable node) => true;
jsAst.Expression rewriteAsync(
@@ -2610,14 +2716,17 @@ class JavaScriptBackend extends Backend {
"_internal": "_internal/js_runtime/lib/internal_patch.dart"
};
- @override
+ /// Returns the location of the patch-file associated with [libraryName]
+ /// resolved from [plaformConfigUri].
+ ///
+ /// Returns null if there is none.
Uri resolvePatchUri(String libraryName, Uri platformConfigUri) {
String patchLocation = _patchLocations[libraryName];
if (patchLocation == null) return null;
return platformConfigUri.resolve(patchLocation);
}
- @override
+ /// Creates an impact strategy to use for compilation.
ImpactStrategy createImpactStrategy(
{bool supportDeferredLoad: true,
bool supportDumpInfo: true,
@@ -2627,6 +2736,8 @@ class JavaScriptBackend extends Backend {
supportDumpInfo: supportDumpInfo,
supportSerialization: supportSerialization);
}
+
+ EnqueueTask makeEnqueuer() => new EnqueueTask(compiler);
}
class JSFrontendAccess implements Frontend {

Powered by Google App Engine
This is Rietveld 408576698