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

Unified Diff: sdk/lib/_internal/compiler/implementation/native_handler.dart

Issue 11304021: Add NativeEnqueuer to work with the Enqueuer. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 1 month 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: sdk/lib/_internal/compiler/implementation/native_handler.dart
diff --git a/sdk/lib/_internal/compiler/implementation/native_handler.dart b/sdk/lib/_internal/compiler/implementation/native_handler.dart
index 0ba42aea08f475ea08ac938302867d44a04d2ed6..a3e82a5b5db809e38dc1eb4df7873cb6dd062863 100644
--- a/sdk/lib/_internal/compiler/implementation/native_handler.dart
+++ b/sdk/lib/_internal/compiler/implementation/native_handler.dart
@@ -13,66 +13,294 @@ import 'ssa/ssa.dart';
import 'tree/tree.dart';
import 'util/util.dart';
-void processNativeClasses(Enqueuer world,
- CodeEmitterTask emitter,
- Collection<LibraryElement> libraries) {
- for (LibraryElement library in libraries) {
- processNativeClassesInLibrary(world, emitter, library);
- }
+
+// This could be an abstract class but we use it as a stub for the dart_backend.
+class NativeEnqueuer {
+ void processNativeClasses(Collection<LibraryElement> libraries) {}
+
+
+ void registerElement(Element element) {}
+
+ // Method is a member of a native class.
+ void registerMethod(Element method) {}
+
+ // Field is a member of a native class.
+ void registerFieldLoad(Element field) {}
+ void registerFieldStore(Element field) {}
+
+ // JS-form code can be an instantiation point for types.
+ //
+ // JS('_DOMWindowImpl', 'window');
+ //
+ // TODO(sra): Who calls this?
+ // TODO(sra): How do we parse the type?
+ // void registerJS(type) {}
+
+ void registerJSDartType(DartType type, Node locationNode) {}
}
-void addSubtypes(ClassElement cls,
- NativeEmitter emitter) {
- for (DartType type in cls.allSupertypes) {
- List<Element> subtypes = emitter.subtypes.putIfAbsent(
- type.element,
- () => <ClassElement>[]);
- subtypes.add(cls);
+
+class NativeEnqueuerBase implements NativeEnqueuer {
ngeoffray 2012/11/08 08:18:01 A couple of high-level comments and alternatives a
sra1 2012/11/15 00:09:10 Enqueuer already needs to be split into a resoluti
+
+ final Set<ClassElement> nativeClasses = new Set<ClassElement>();
+
+ // Each class is exactly one of these sets.
+ final Set<ClassElement> registeredClasses = new Set<ClassElement>();
+ final Set<ClassElement> unusedClasses = new Set<ClassElement>();
+ final Set<ClassElement> pendingClasses = new Set<ClassElement>();
+
+ final queue = new Queue(); // Classes in pendingClasse have thunks in queue.
+ bool flushing = false;
+
+ final Set<DartType> escapedTypes = new Set<DartType>();
+ final Set<DartType> capturedTypes = new Set<DartType>();
+
+
+ final Enqueuer world;
+ final Compiler compiler;
+
+ // constructed by backend.
+ NativeEnqueuerBase(this.world, this.compiler);
+
+ void processNativeClasses(Collection<LibraryElement> libraries) {
+ libraries.forEach(processNativeClassesInLibrary);
+
+ // nativeClasses.forEach(enqueueClass); flushQueue();
+ }
+
+ void processNativeClassesInLibrary(LibraryElement library) {
+ // Use implementation to ensure the inclusion of injected members.
+ library.implementation.forEachLocalMember((Element element) {
+ if (element.kind == ElementKind.CLASS) {
+ ClassElement classElement = element;
+ if (classElement.isNative()) {
+ nativeClasses.add(classElement);
+ unusedClasses.add(classElement);
+
+ // Resolve class to ensure the class has valid inheritance info.
+ classElement.ensureResolved(compiler);
+ }
+ }
+ });
+ }
+
+ enqueueClass(ClassElement classElement, cause) {
+ assert(unusedClasses.contains(classElement));
+ compiler.log(
+ 'Adding native class ${classElement.name.slowToString()},'
+ ' why: $cause');
+ unusedClasses.remove(classElement);
+ pendingClasses.add(classElement);
+ queue.add(() { processClass(classElement, cause); });
+ }
+
+ void flushQueue() {
+ if (flushing) return;
+ flushing = true;
+ while (!queue.isEmpty) {
+ (queue.removeFirst())();
+ }
+ flushing = false;
+ }
+
+ processClass(ClassElement classElement, cause) {
+ assert(!registeredClasses.contains(classElement));
+
+ bool firstTime = registeredClasses.isEmpty;
+ pendingClasses.remove(classElement);
+ registeredClasses.add(classElement);
+
+ // print('processClass $classElement $cause');
+ world.registerInstantiatedClass(classElement);
+
+ // Also parse the node to know all its methods because
+ // otherwise it will only be parsed if there is a call to
+ // one of its constructors.
+ classElement.parseNode(compiler);
+
+ if (firstTime) {
+ queue.add(onFirstNativeClass);
+ }
+ }
+
+ registerElement(Element element) {
+ if (element.isFunction()) return registerMethod(element);
+ }
+
+ registerMethod(Element method) {
+ if (isNativeMethod(method)) {
+ // print('Native method call $method');
+ captureType(method.computeType(compiler), method);
+ flushQueue();
+ }
+ }
+
+ bool isNativeMethod(Element element) {
+ // Native method?
+ Node node = element.parseNode(compiler);
+ if (node is! FunctionExpression) return false;
+ node = node.body;
+ Token token = node.getBeginToken();
+ if (token.stringValue == 'native') return true;
+ return false;
+ }
+
+ registerFieldLoad(Element field) {
+ // print('Native load field $field');
+ captureType(field.computeType(compiler), field);
+ flushQueue();
}
- List<Element> directSubtypes = emitter.directSubtypes.putIfAbsent(
- cls.superclass,
- () => <ClassElement>[]);
- directSubtypes.add(cls);
+ registerFieldStore(Element field) {
+ // print('Native store field $field');
+ escapeType(field.computeType(compiler), field);
+ flushQueue();
+ }
+
+ void registerJSDartType(DartType type, Node locationNode) {
+ captureType(type, locationNode);
+ flushQueue();
+ }
+
+ escapeType(DartType type, cause) {
+ type = type.unalias(compiler);
+ if (escapedTypes.contains(type)) return;
+ escapedTypes.add(type);
+ // print(' escapeType $type');
+
+ if (type is FunctionType) {
+ escapeType(type.returnType, cause);
+ // TODO: use FunctionSignature.
+ for (Link<DartType> parameters = type.parameterTypes;
+ !parameters.isEmpty;
+ parameters = parameters.tail) {
+ captureType(parameters.head, cause);
+ }
+ }
+ }
+
+ captureType(DartType type, cause) {
+ type = type.unalias(compiler);
+ if (capturedTypes.contains(type)) return;
+ capturedTypes.add(type);
+ // print(' capturedType $type');
+
+ if (type is FunctionType) {
+ captureType(type.returnType, cause);
+ for (Link<DartType> parameters = type.parameterTypes;
+ !parameters.isEmpty;
+ parameters = parameters.tail) {
+ escapeType(parameters.head, cause);
+ }
+ } else {
+ bool allUsedBefore = unusedClasses.isEmpty;
+ enqueueUnusedClassesMatching(
+ (nativeClass) => compiler.types.isSubtype(nativeClass.type, type),
+ cause,
+ 'subtypeof($type)');
+ if (unusedClasses.isEmpty && !allUsedBefore) {
+ if (cause is Node) {
+ throw 'Eugh $cause';
+ compiler.log('All native types marked as used due to $cause.');
+ } else if (cause.position() != null) {
+ //compiler.cancel('Eugh!', token: cause.position());
+ compiler.log('All native types marked used due to $cause.');
+ } else {
+ compiler.log('All native types marked used due to $type.');
+ }
+ }
+ }
+
+ // TODO(sra): Do we need to do something for capturing List<Node>? For now,
+ // hope that NodeListImpl matches List, causing NodeListImpl.operator[] to
+ // match some invocation, leading to instantiating Node.
+
+ // Required for:
+ // typedef void MutationCallback(List<MutationRecord> mutations, MutationObserver observer);
+ // No other code instantiates MutationRecord.
+ // We can work-around by annotating the MutationObserver constructor with a list of 'also created' type.
+
+ }
+
+ enqueueUnusedClassesMatching(predicate, cause, [reason]) {
+ var matches = unusedClasses.filter(predicate);
+ // print('${matches.length} matches: $matches\n.. $reason $world');
+ matches.forEach((c) => enqueueClass(c, cause));
+ }
+
+ onFirstNativeClass() {
+ staticUse(name) => world.registerStaticUse(compiler.findHelper(name));
+
+ staticUse(const SourceString('dynamicFunction'));
+ staticUse(const SourceString('dynamicSetMetadata'));
+ staticUse(const SourceString('defineProperty'));
+ staticUse(const SourceString('toStringForNativeObject'));
+ staticUse(const SourceString('hashCodeForNativeObject'));
+
+ addNativeExceptions();
+ }
+
+ addNativeExceptions() {
+ enqueueUnusedClassesMatching((classElement) {
+ // TODO(sra): Annotate exception classes in dart:html.
+ var name = classElement.name.slowToString();
+ if (name.contains('Exception')) return true;
+ if (name.contains('Error')) return true;
+ return false;
+ },
+ 'native exception');
+ }
}
-void processNativeClassesInLibrary(Enqueuer world,
- CodeEmitterTask emitter,
- LibraryElement library) {
- bool hasNativeClass = false;
- final compiler = emitter.compiler;
- // Use implementation to ensure the inclusion of injected members.
- library.implementation.forEachLocalMember((Element element) {
- if (element.kind == ElementKind.CLASS) {
- ClassElement classElement = element;
- if (classElement.isNative()) {
- hasNativeClass = true;
- world.registerInstantiatedClass(classElement);
- // Also parse the node to know all its methods because
- // otherwise it will only be parsed if there is a call to
- // one of its constructor.
- classElement.parseNode(compiler);
- // Resolve to setup the inheritance.
- classElement.ensureResolved(compiler);
- // Add the information that this class is a subtype of
- // its supertypes. The code emitter and the ssa builder use that
- // information.
- addSubtypes(classElement, emitter.nativeEmitter);
+
+class NativeResolutionEnqueuer extends NativeEnqueuerBase {
+
+ NativeResolutionEnqueuer(Enqueuer world, Compiler compiler)
+ : super(world, compiler);
+}
+
+
+class NativeCodegenEnqueuer extends NativeEnqueuerBase {
+
+ final CodeEmitterTask emitter;
+
+ NativeCodegenEnqueuer(Enqueuer world, Compiler compiler, this.emitter)
+ : super(world, compiler);
+
+ void processNativeClasses(Collection<LibraryElement> libraries) {
+ super.processNativeClasses(libraries);
+
+ // HACK HACK - add all the resolved classes.
+ for (final classElement
+ in compiler.enqueuer.resolution.nativeEnqueuer.registeredClasses) {
+ if (unusedClasses.contains(classElement)) {
+ enqueueClass(classElement, 'was resolved');
}
}
- });
- if (hasNativeClass) {
- world.registerStaticUse(compiler.findHelper(
- const SourceString('dynamicFunction')));
- world.registerStaticUse(compiler.findHelper(
- const SourceString('dynamicSetMetadata')));
- world.registerStaticUse(compiler.findHelper(
- const SourceString('defineProperty')));
- world.registerStaticUse(compiler.findHelper(
- const SourceString('toStringForNativeObject')));
- world.registerStaticUse(compiler.findHelper(
- const SourceString('hashCodeForNativeObject')));
+ flushQueue();
+ }
+
+ processClass(ClassElement classElement, cause) {
+ super.processClass(classElement, cause);
+ // Add the information that this class is a subtype of its supertypes. The
+ // code emitter and the ssa builder use that information.
+ addSubtypes(classElement, emitter.nativeEmitter);
+ }
+
+ void addSubtypes(ClassElement cls, NativeEmitter emitter) {
+ for (DartType type in cls.allSupertypes) {
+ List<Element> subtypes = emitter.subtypes.putIfAbsent(
+ type.element,
+ () => <ClassElement>[]);
+ subtypes.add(cls);
+ }
+
+ List<Element> directSubtypes = emitter.directSubtypes.putIfAbsent(
+ cls.superclass,
+ () => <ClassElement>[]);
+ directSubtypes.add(cls);
}
+
}
void maybeEnableNative(Compiler compiler,

Powered by Google App Engine
This is Rietveld 408576698