| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of native; | 5 part of native; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * This could be an abstract class but we use it as a stub for the dart_backend. | 8 * This could be an abstract class but we use it as a stub for the dart_backend. |
| 9 */ | 9 */ |
| 10 class NativeEnqueuer { | 10 class NativeEnqueuer { |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 124 ClassElement _annotationCreatesClass; | 124 ClassElement _annotationCreatesClass; |
| 125 ClassElement _annotationReturnsClass; | 125 ClassElement _annotationReturnsClass; |
| 126 ClassElement _annotationJsNameClass; | 126 ClassElement _annotationJsNameClass; |
| 127 | 127 |
| 128 /// Subclasses of [NativeEnqueuerBase] are constructed by the backend. | 128 /// Subclasses of [NativeEnqueuerBase] are constructed by the backend. |
| 129 NativeEnqueuerBase(this.world, Compiler compiler, this.enableLiveTypeAnalysis) | 129 NativeEnqueuerBase(this.world, Compiler compiler, this.enableLiveTypeAnalysis) |
| 130 : this.compiler = compiler, | 130 : this.compiler = compiler, |
| 131 processedLibraries = compiler.cacheStrategy.newSet(); | 131 processedLibraries = compiler.cacheStrategy.newSet(); |
| 132 | 132 |
| 133 JavaScriptBackend get backend => compiler.backend; | 133 JavaScriptBackend get backend => compiler.backend; |
| 134 Resolution get resolution => compiler.resolution; |
| 134 | 135 |
| 135 void processNativeClasses(Iterable<LibraryElement> libraries) { | 136 void processNativeClasses(Iterable<LibraryElement> libraries) { |
| 136 if (compiler.hasIncrementalSupport) { | 137 if (compiler.hasIncrementalSupport) { |
| 137 // Since [Set.add] returns bool if an element was added, this restricts | 138 // Since [Set.add] returns bool if an element was added, this restricts |
| 138 // [libraries] to ones that haven't already been processed. This saves | 139 // [libraries] to ones that haven't already been processed. This saves |
| 139 // time during incremental compiles. | 140 // time during incremental compiles. |
| 140 libraries = libraries.where(processedLibraries.add); | 141 libraries = libraries.where(processedLibraries.add); |
| 141 } | 142 } |
| 142 libraries.forEach(processNativeClassesInLibrary); | 143 libraries.forEach(processNativeClassesInLibrary); |
| 143 if (backend.isolateHelperLibrary != null) { | 144 if (backend.isolateHelperLibrary != null) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 156 if (element.isClass && element.isNative) { | 157 if (element.isClass && element.isNative) { |
| 157 processNativeClass(element); | 158 processNativeClass(element); |
| 158 } | 159 } |
| 159 }); | 160 }); |
| 160 } | 161 } |
| 161 | 162 |
| 162 void processNativeClass(ClassElement classElement) { | 163 void processNativeClass(ClassElement classElement) { |
| 163 nativeClasses.add(classElement); | 164 nativeClasses.add(classElement); |
| 164 unusedClasses.add(classElement); | 165 unusedClasses.add(classElement); |
| 165 // Resolve class to ensure the class has valid inheritance info. | 166 // Resolve class to ensure the class has valid inheritance info. |
| 166 classElement.ensureResolved(compiler); | 167 classElement.ensureResolved(resolution); |
| 167 } | 168 } |
| 168 | 169 |
| 169 void processSubclassesOfNativeClasses(Iterable<LibraryElement> libraries) { | 170 void processSubclassesOfNativeClasses(Iterable<LibraryElement> libraries) { |
| 170 // Collect potential subclasses, e.g. | 171 // Collect potential subclasses, e.g. |
| 171 // | 172 // |
| 172 // class B extends foo.A {} | 173 // class B extends foo.A {} |
| 173 // | 174 // |
| 174 // String "A" has a potential subclass B. | 175 // String "A" has a potential subclass B. |
| 175 | 176 |
| 176 var potentialExtends = new Map<String, Set<ClassElement>>(); | 177 var potentialExtends = new Map<String, Set<ClassElement>>(); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 195 // fact a subclass of a native class. | 196 // fact a subclass of a native class. |
| 196 | 197 |
| 197 ClassElement nativeSuperclassOf(ClassElement classElement) { | 198 ClassElement nativeSuperclassOf(ClassElement classElement) { |
| 198 if (classElement.isNative) return classElement; | 199 if (classElement.isNative) return classElement; |
| 199 if (classElement.superclass == null) return null; | 200 if (classElement.superclass == null) return null; |
| 200 return nativeSuperclassOf(classElement.superclass); | 201 return nativeSuperclassOf(classElement.superclass); |
| 201 } | 202 } |
| 202 | 203 |
| 203 void walkPotentialSubclasses(ClassElement element) { | 204 void walkPotentialSubclasses(ClassElement element) { |
| 204 if (nativeClassesAndSubclasses.contains(element)) return; | 205 if (nativeClassesAndSubclasses.contains(element)) return; |
| 205 element.ensureResolved(compiler); | 206 element.ensureResolved(resolution); |
| 206 ClassElement nativeSuperclass = nativeSuperclassOf(element); | 207 ClassElement nativeSuperclass = nativeSuperclassOf(element); |
| 207 if (nativeSuperclass != null) { | 208 if (nativeSuperclass != null) { |
| 208 nativeClassesAndSubclasses.add(element); | 209 nativeClassesAndSubclasses.add(element); |
| 209 if (!element.isNative) { | 210 if (!element.isNative) { |
| 210 nonNativeSubclasses.putIfAbsent(nativeSuperclass, | 211 nonNativeSubclasses.putIfAbsent(nativeSuperclass, |
| 211 () => new Set<ClassElement>()) | 212 () => new Set<ClassElement>()) |
| 212 .add(element); | 213 .add(element); |
| 213 } | 214 } |
| 214 Set<ClassElement> potentialSubclasses = potentialExtends[element.name]; | 215 Set<ClassElement> potentialSubclasses = potentialExtends[element.name]; |
| 215 if (potentialSubclasses != null) { | 216 if (potentialSubclasses != null) { |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 312 _annotationReturnsClass = find('Returns'); | 313 _annotationReturnsClass = find('Returns'); |
| 313 _annotationJsNameClass = find('JSName'); | 314 _annotationJsNameClass = find('JSName'); |
| 314 } | 315 } |
| 315 | 316 |
| 316 /// Returns the JSName annotation string or `null` if no JSName annotation is | 317 /// Returns the JSName annotation string or `null` if no JSName annotation is |
| 317 /// present. | 318 /// present. |
| 318 String findJsNameFromAnnotation(Element element) { | 319 String findJsNameFromAnnotation(Element element) { |
| 319 String name = null; | 320 String name = null; |
| 320 ClassElement annotationClass = annotationJsNameClass; | 321 ClassElement annotationClass = annotationJsNameClass; |
| 321 for (MetadataAnnotation annotation in element.implementation.metadata) { | 322 for (MetadataAnnotation annotation in element.implementation.metadata) { |
| 322 annotation.ensureResolved(compiler); | 323 annotation.ensureResolved(resolution); |
| 323 ConstantValue value = | 324 ConstantValue value = |
| 324 compiler.constants.getConstantValue(annotation.constant); | 325 compiler.constants.getConstantValue(annotation.constant); |
| 325 if (!value.isConstructedObject) continue; | 326 if (!value.isConstructedObject) continue; |
| 326 ConstructedConstantValue constructedObject = value; | 327 ConstructedConstantValue constructedObject = value; |
| 327 if (constructedObject.type.element != annotationClass) continue; | 328 if (constructedObject.type.element != annotationClass) continue; |
| 328 | 329 |
| 329 Iterable<ConstantValue> fields = constructedObject.fields.values; | 330 Iterable<ConstantValue> fields = constructedObject.fields.values; |
| 330 // TODO(sra): Better validation of the constant. | 331 // TODO(sra): Better validation of the constant. |
| 331 if (fields.length != 1 || fields.single is! StringConstantValue) { | 332 if (fields.length != 1 || fields.single is! StringConstantValue) { |
| 332 PartialMetadataAnnotation partial = annotation; | |
| 333 compiler.internalError(annotation, | 333 compiler.internalError(annotation, |
| 334 'Annotations needs one string: ${partial.parseNode(compiler)}'); | 334 'Annotations needs one string: ${annotation.node}'); |
| 335 } | 335 } |
| 336 StringConstantValue specStringConstant = fields.single; | 336 StringConstantValue specStringConstant = fields.single; |
| 337 String specString = specStringConstant.toDartString().slowToString(); | 337 String specString = specStringConstant.toDartString().slowToString(); |
| 338 if (name == null) { | 338 if (name == null) { |
| 339 name = specString; | 339 name = specString; |
| 340 } else { | 340 } else { |
| 341 PartialMetadataAnnotation partial = annotation; | |
| 342 compiler.internalError(annotation, | 341 compiler.internalError(annotation, |
| 343 'Too many JSName annotations: ${partial.parseNode(compiler)}'); | 342 'Too many JSName annotations: ${annotation.node}'); |
| 344 } | 343 } |
| 345 } | 344 } |
| 346 return name; | 345 return name; |
| 347 } | 346 } |
| 348 | 347 |
| 349 enqueueClass(ClassElement classElement, cause) { | 348 enqueueClass(ClassElement classElement, cause) { |
| 350 assert(unusedClasses.contains(classElement)); | 349 assert(unusedClasses.contains(classElement)); |
| 351 unusedClasses.remove(classElement); | 350 unusedClasses.remove(classElement); |
| 352 pendingClasses.add(classElement); | 351 pendingClasses.add(classElement); |
| 353 queue.add(() { processClass(classElement, cause); }); | 352 queue.add(() { processClass(classElement, cause); }); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 365 processClass(BaseClassElementX classElement, cause) { | 364 processClass(BaseClassElementX classElement, cause) { |
| 366 // TODO(ahe): Fix this assertion to work in incremental compilation. | 365 // TODO(ahe): Fix this assertion to work in incremental compilation. |
| 367 assert(compiler.hasIncrementalSupport || | 366 assert(compiler.hasIncrementalSupport || |
| 368 !registeredClasses.contains(classElement)); | 367 !registeredClasses.contains(classElement)); |
| 369 | 368 |
| 370 bool firstTime = registeredClasses.isEmpty; | 369 bool firstTime = registeredClasses.isEmpty; |
| 371 pendingClasses.remove(classElement); | 370 pendingClasses.remove(classElement); |
| 372 registeredClasses.add(classElement); | 371 registeredClasses.add(classElement); |
| 373 | 372 |
| 374 // TODO(ahe): Is this really a global dependency? | 373 // TODO(ahe): Is this really a global dependency? |
| 375 classElement.ensureResolved(compiler); | 374 classElement.ensureResolved(resolution); |
| 376 compiler.backend.registerInstantiatedType( | 375 compiler.backend.registerInstantiatedType( |
| 377 classElement.rawType, world, compiler.globalDependencies); | 376 classElement.rawType, world, compiler.globalDependencies); |
| 378 | 377 |
| 379 // Also parse the node to know all its methods because otherwise it will | |
| 380 // only be parsed if there is a call to one of its constructors. | |
| 381 classElement.parseNode(compiler); | |
| 382 | |
| 383 if (firstTime) { | 378 if (firstTime) { |
| 384 queue.add(onFirstNativeClass); | 379 queue.add(onFirstNativeClass); |
| 385 } | 380 } |
| 386 } | 381 } |
| 387 | 382 |
| 388 registerElement(Element element) { | 383 registerElement(Element element) { |
| 389 compiler.withCurrentElement(element, () { | 384 compiler.withCurrentElement(element, () { |
| 390 if (element.isFunction || element.isGetter || element.isSetter) { | 385 if (element.isFunction || element.isGetter || element.isSetter) { |
| 391 handleMethodAnnotations(element); | 386 handleMethodAnnotations(element); |
| 392 if (element.isNative) { | 387 if (element.isNative) { |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 455 element.setNative(name); | 450 element.setNative(name); |
| 456 } | 451 } |
| 457 } | 452 } |
| 458 | 453 |
| 459 bool isIdentifier(String s) => _identifier.hasMatch(s); | 454 bool isIdentifier(String s) => _identifier.hasMatch(s); |
| 460 | 455 |
| 461 bool isNativeMethod(FunctionElementX element) { | 456 bool isNativeMethod(FunctionElementX element) { |
| 462 if (!element.library.canUseNative) return false; | 457 if (!element.library.canUseNative) return false; |
| 463 // Native method? | 458 // Native method? |
| 464 return compiler.withCurrentElement(element, () { | 459 return compiler.withCurrentElement(element, () { |
| 465 Node node = element.parseNode(compiler); | 460 Node node = element.parseNode(resolution.parsing); |
| 466 if (node is! FunctionExpression) return false; | 461 if (node is! FunctionExpression) return false; |
| 467 FunctionExpression functionExpression = node; | 462 FunctionExpression functionExpression = node; |
| 468 node = functionExpression.body; | 463 node = functionExpression.body; |
| 469 Token token = node.getBeginToken(); | 464 Token token = node.getBeginToken(); |
| 470 if (identical(token.stringValue, 'native')) return true; | 465 if (identical(token.stringValue, 'native')) return true; |
| 471 return false; | 466 return false; |
| 472 }); | 467 }); |
| 473 } | 468 } |
| 474 | 469 |
| 475 void registerNativeBehavior(NativeBehavior nativeBehavior, cause) { | 470 void registerNativeBehavior(NativeBehavior nativeBehavior, cause) { |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 683 superclass, | 678 superclass, |
| 684 () => <ClassElement>[]); | 679 () => <ClassElement>[]); |
| 685 directSubtypes.add(cls); | 680 directSubtypes.add(cls); |
| 686 } | 681 } |
| 687 | 682 |
| 688 void logSummary(log(message)) { | 683 void logSummary(log(message)) { |
| 689 log('Compiled ${registeredClasses.length} native classes, ' | 684 log('Compiled ${registeredClasses.length} native classes, ' |
| 690 '${unusedClasses.length} native classes omitted.'); | 685 '${unusedClasses.length} native classes omitted.'); |
| 691 } | 686 } |
| 692 } | 687 } |
| OLD | NEW |