| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 library native; | 5 library native; |
| 6 | 6 |
| 7 import 'dart:collection' show Queue; | 7 import 'dart:collection' show Queue; |
| 8 import 'dart2jslib.dart'; | 8 import 'dart2jslib.dart'; |
| 9 import 'dart_types.dart'; | 9 import 'dart_types.dart'; |
| 10 import 'elements/elements.dart'; | 10 import 'elements/elements.dart'; |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 130 processSubclassesOfNativeClasses(libraries); | 130 processSubclassesOfNativeClasses(libraries); |
| 131 if (!enableLiveTypeAnalysis) { | 131 if (!enableLiveTypeAnalysis) { |
| 132 nativeClasses.forEach((c) => enqueueClass(c, 'forced')); | 132 nativeClasses.forEach((c) => enqueueClass(c, 'forced')); |
| 133 flushQueue(); | 133 flushQueue(); |
| 134 } | 134 } |
| 135 } | 135 } |
| 136 | 136 |
| 137 void processNativeClassesInLibrary(LibraryElement library) { | 137 void processNativeClassesInLibrary(LibraryElement library) { |
| 138 // Use implementation to ensure the inclusion of injected members. | 138 // Use implementation to ensure the inclusion of injected members. |
| 139 library.implementation.forEachLocalMember((Element element) { | 139 library.implementation.forEachLocalMember((Element element) { |
| 140 if (element.isClass() && element.isNative()) { | 140 if (element.isClass && element.isNative) { |
| 141 processNativeClass(element); | 141 processNativeClass(element); |
| 142 } | 142 } |
| 143 }); | 143 }); |
| 144 } | 144 } |
| 145 | 145 |
| 146 void processNativeClass(ClassElement classElement) { | 146 void processNativeClass(ClassElement classElement) { |
| 147 nativeClasses.add(classElement); | 147 nativeClasses.add(classElement); |
| 148 unusedClasses.add(classElement); | 148 unusedClasses.add(classElement); |
| 149 // Resolve class to ensure the class has valid inheritance info. | 149 // Resolve class to ensure the class has valid inheritance info. |
| 150 classElement.ensureResolved(compiler); | 150 classElement.ensureResolved(compiler); |
| 151 } | 151 } |
| 152 | 152 |
| 153 void processSubclassesOfNativeClasses(Iterable<LibraryElement> libraries) { | 153 void processSubclassesOfNativeClasses(Iterable<LibraryElement> libraries) { |
| 154 // Collect potential subclasses, e.g. | 154 // Collect potential subclasses, e.g. |
| 155 // | 155 // |
| 156 // class B extends foo.A {} | 156 // class B extends foo.A {} |
| 157 // | 157 // |
| 158 // String "A" has a potential subclass B. | 158 // String "A" has a potential subclass B. |
| 159 | 159 |
| 160 var potentialExtends = new Map<String, Set<ClassElement>>(); | 160 var potentialExtends = new Map<String, Set<ClassElement>>(); |
| 161 | 161 |
| 162 libraries.forEach((library) { | 162 libraries.forEach((library) { |
| 163 library.implementation.forEachLocalMember((element) { | 163 library.implementation.forEachLocalMember((element) { |
| 164 if (element.isClass()) { | 164 if (element.isClass) { |
| 165 String name = element.name; | 165 String name = element.name; |
| 166 String extendsName = findExtendsNameOfClass(element); | 166 String extendsName = findExtendsNameOfClass(element); |
| 167 if (extendsName != null) { | 167 if (extendsName != null) { |
| 168 Set<ClassElement> potentialSubclasses = | 168 Set<ClassElement> potentialSubclasses = |
| 169 potentialExtends.putIfAbsent( | 169 potentialExtends.putIfAbsent( |
| 170 extendsName, | 170 extendsName, |
| 171 () => new Set<ClassElement>()); | 171 () => new Set<ClassElement>()); |
| 172 potentialSubclasses.add(element); | 172 potentialSubclasses.add(element); |
| 173 } | 173 } |
| 174 } | 174 } |
| 175 }); | 175 }); |
| 176 }); | 176 }); |
| 177 | 177 |
| 178 // Resolve all the native classes and any classes that might extend them in | 178 // Resolve all the native classes and any classes that might extend them in |
| 179 // [potentialExtends], and then check that the properly resolved class is in | 179 // [potentialExtends], and then check that the properly resolved class is in |
| 180 // fact a subclass of a native class. | 180 // fact a subclass of a native class. |
| 181 | 181 |
| 182 ClassElement nativeSuperclassOf(ClassElement classElement) { | 182 ClassElement nativeSuperclassOf(ClassElement classElement) { |
| 183 if (classElement.isNative()) return classElement; | 183 if (classElement.isNative) return classElement; |
| 184 if (classElement.superclass == null) return null; | 184 if (classElement.superclass == null) return null; |
| 185 return nativeSuperclassOf(classElement.superclass); | 185 return nativeSuperclassOf(classElement.superclass); |
| 186 } | 186 } |
| 187 | 187 |
| 188 void walkPotentialSubclasses(ClassElement element) { | 188 void walkPotentialSubclasses(ClassElement element) { |
| 189 if (nativeClassesAndSubclasses.contains(element)) return; | 189 if (nativeClassesAndSubclasses.contains(element)) return; |
| 190 element.ensureResolved(compiler); | 190 element.ensureResolved(compiler); |
| 191 ClassElement nativeSuperclass = nativeSuperclassOf(element); | 191 ClassElement nativeSuperclass = nativeSuperclassOf(element); |
| 192 if (nativeSuperclass != null) { | 192 if (nativeSuperclass != null) { |
| 193 nativeClassesAndSubclasses.add(element); | 193 nativeClassesAndSubclasses.add(element); |
| 194 if (!element.isNative()) { | 194 if (!element.isNative) { |
| 195 nonNativeSubclasses.putIfAbsent(nativeSuperclass, | 195 nonNativeSubclasses.putIfAbsent(nativeSuperclass, |
| 196 () => new Set<ClassElement>()) | 196 () => new Set<ClassElement>()) |
| 197 .add(element); | 197 .add(element); |
| 198 } | 198 } |
| 199 Set<ClassElement> potentialSubclasses = potentialExtends[element.name]; | 199 Set<ClassElement> potentialSubclasses = potentialExtends[element.name]; |
| 200 if (potentialSubclasses != null) { | 200 if (potentialSubclasses != null) { |
| 201 potentialSubclasses.forEach(walkPotentialSubclasses); | 201 potentialSubclasses.forEach(walkPotentialSubclasses); |
| 202 } | 202 } |
| 203 } | 203 } |
| 204 } | 204 } |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 257 if (token.stringValue != '.') break; | 257 if (token.stringValue != '.') break; |
| 258 token = token.next; | 258 token = token.next; |
| 259 if (!token.isIdentifier()) return null; | 259 if (!token.isIdentifier()) return null; |
| 260 id = token; | 260 id = token; |
| 261 } | 261 } |
| 262 // Should be at '{', 'with', 'implements', '<' or 'native'. | 262 // Should be at '{', 'with', 'implements', '<' or 'native'. |
| 263 return id.value; | 263 return id.value; |
| 264 } | 264 } |
| 265 | 265 |
| 266 return compiler.withCurrentElement(classElement, () { | 266 return compiler.withCurrentElement(classElement, () { |
| 267 return scanForExtendsName(classElement.position()); | 267 return scanForExtendsName(classElement.position); |
| 268 }); | 268 }); |
| 269 } | 269 } |
| 270 | 270 |
| 271 ClassElement get annotationCreatesClass { | 271 ClassElement get annotationCreatesClass { |
| 272 findAnnotationClasses(); | 272 findAnnotationClasses(); |
| 273 return _annotationCreatesClass; | 273 return _annotationCreatesClass; |
| 274 } | 274 } |
| 275 | 275 |
| 276 ClassElement get annotationReturnsClass { | 276 ClassElement get annotationReturnsClass { |
| 277 findAnnotationClasses(); | 277 findAnnotationClasses(); |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 361 // only be parsed if there is a call to one of its constructors. | 361 // only be parsed if there is a call to one of its constructors. |
| 362 classElement.parseNode(compiler); | 362 classElement.parseNode(compiler); |
| 363 | 363 |
| 364 if (firstTime) { | 364 if (firstTime) { |
| 365 queue.add(onFirstNativeClass); | 365 queue.add(onFirstNativeClass); |
| 366 } | 366 } |
| 367 } | 367 } |
| 368 | 368 |
| 369 registerElement(Element element) { | 369 registerElement(Element element) { |
| 370 compiler.withCurrentElement(element, () { | 370 compiler.withCurrentElement(element, () { |
| 371 if (element.isFunction() || element.isGetter() || element.isSetter()) { | 371 if (element.isFunction || element.isGetter || element.isSetter) { |
| 372 handleMethodAnnotations(element); | 372 handleMethodAnnotations(element); |
| 373 if (element.isNative()) { | 373 if (element.isNative) { |
| 374 registerMethodUsed(element); | 374 registerMethodUsed(element); |
| 375 } | 375 } |
| 376 } else if (element.isField()) { | 376 } else if (element.isField) { |
| 377 handleFieldAnnotations(element); | 377 handleFieldAnnotations(element); |
| 378 if (element.isNative()) { | 378 if (element.isNative) { |
| 379 registerFieldLoad(element); | 379 registerFieldLoad(element); |
| 380 registerFieldStore(element); | 380 registerFieldStore(element); |
| 381 } | 381 } |
| 382 } | 382 } |
| 383 }); | 383 }); |
| 384 } | 384 } |
| 385 | 385 |
| 386 handleFieldAnnotations(Element element) { | 386 handleFieldAnnotations(Element element) { |
| 387 if (element.enclosingElement.isNative()) { | 387 if (element.enclosingElement.isNative) { |
| 388 // Exclude non-instance (static) fields - they not really native and are | 388 // Exclude non-instance (static) fields - they not really native and are |
| 389 // compiled as isolate globals. Access of a property of a constructor | 389 // compiled as isolate globals. Access of a property of a constructor |
| 390 // function or a non-method property in the prototype chain, must be coded | 390 // function or a non-method property in the prototype chain, must be coded |
| 391 // using a JS-call. | 391 // using a JS-call. |
| 392 if (element.isInstanceMember()) { | 392 if (element.isInstanceMember) { |
| 393 setNativeName(element); | 393 setNativeName(element); |
| 394 } | 394 } |
| 395 } | 395 } |
| 396 } | 396 } |
| 397 | 397 |
| 398 handleMethodAnnotations(Element method) { | 398 handleMethodAnnotations(Element method) { |
| 399 if (isNativeMethod(method)) { | 399 if (isNativeMethod(method)) { |
| 400 setNativeName(method); | 400 setNativeName(method); |
| 401 } | 401 } |
| 402 } | 402 } |
| 403 | 403 |
| 404 /// Sets the native name of [element], either from an annotation, or | 404 /// Sets the native name of [element], either from an annotation, or |
| 405 /// defaulting to the Dart name. | 405 /// defaulting to the Dart name. |
| 406 void setNativeName(Element element) { | 406 void setNativeName(Element element) { |
| 407 String name = findJsNameFromAnnotation(element); | 407 String name = findJsNameFromAnnotation(element); |
| 408 if (name == null) name = element.name; | 408 if (name == null) name = element.name; |
| 409 element.setNative(name); | 409 element.setNative(name); |
| 410 } | 410 } |
| 411 | 411 |
| 412 bool isNativeMethod(Element element) { | 412 bool isNativeMethod(Element element) { |
| 413 if (!element.getLibrary().canUseNative) return false; | 413 if (!element.library.canUseNative) return false; |
| 414 // Native method? | 414 // Native method? |
| 415 return compiler.withCurrentElement(element, () { | 415 return compiler.withCurrentElement(element, () { |
| 416 Node node = element.parseNode(compiler); | 416 Node node = element.parseNode(compiler); |
| 417 if (node is! FunctionExpression) return false; | 417 if (node is! FunctionExpression) return false; |
| 418 FunctionExpression functionExpression = node; | 418 FunctionExpression functionExpression = node; |
| 419 node = functionExpression.body; | 419 node = functionExpression.body; |
| 420 Token token = node.getBeginToken(); | 420 Token token = node.getBeginToken(); |
| 421 if (identical(token.stringValue, 'native')) return true; | 421 if (identical(token.stringValue, 'native')) return true; |
| 422 return false; | 422 return false; |
| 423 }); | 423 }); |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 589 } | 589 } |
| 590 | 590 |
| 591 processClass(ClassElement classElement, cause) { | 591 processClass(ClassElement classElement, cause) { |
| 592 super.processClass(classElement, cause); | 592 super.processClass(classElement, cause); |
| 593 // Add the information that this class is a subtype of its supertypes. The | 593 // Add the information that this class is a subtype of its supertypes. The |
| 594 // code emitter and the ssa builder use that information. | 594 // code emitter and the ssa builder use that information. |
| 595 addSubtypes(classElement, emitter.nativeEmitter); | 595 addSubtypes(classElement, emitter.nativeEmitter); |
| 596 } | 596 } |
| 597 | 597 |
| 598 void addSubtypes(ClassElement cls, NativeEmitter emitter) { | 598 void addSubtypes(ClassElement cls, NativeEmitter emitter) { |
| 599 if (!cls.isNative()) return; | 599 if (!cls.isNative) return; |
| 600 if (doneAddSubtypes.contains(cls)) return; | 600 if (doneAddSubtypes.contains(cls)) return; |
| 601 doneAddSubtypes.add(cls); | 601 doneAddSubtypes.add(cls); |
| 602 | 602 |
| 603 // Walk the superclass chain since classes on the superclass chain might not | 603 // Walk the superclass chain since classes on the superclass chain might not |
| 604 // be instantiated (abstract or simply unused). | 604 // be instantiated (abstract or simply unused). |
| 605 addSubtypes(cls.superclass, emitter); | 605 addSubtypes(cls.superclass, emitter); |
| 606 | 606 |
| 607 for (DartType type in cls.allSupertypes) { | 607 for (DartType type in cls.allSupertypes) { |
| 608 List<Element> subtypes = emitter.subtypes.putIfAbsent( | 608 List<Element> subtypes = emitter.subtypes.putIfAbsent( |
| 609 type.element, | 609 type.element, |
| 610 () => <ClassElement>[]); | 610 () => <ClassElement>[]); |
| 611 subtypes.add(cls); | 611 subtypes.add(cls); |
| 612 } | 612 } |
| 613 | 613 |
| 614 // Skip through all the mixin applications in the super class | 614 // Skip through all the mixin applications in the super class |
| 615 // chain. That way, the direct subtypes set only contain the | 615 // chain. That way, the direct subtypes set only contain the |
| 616 // natives classes. | 616 // natives classes. |
| 617 ClassElement superclass = cls.superclass; | 617 ClassElement superclass = cls.superclass; |
| 618 while (superclass != null && superclass.isMixinApplication) { | 618 while (superclass != null && superclass.isMixinApplication) { |
| 619 assert(!superclass.isNative()); | 619 assert(!superclass.isNative); |
| 620 superclass = superclass.superclass; | 620 superclass = superclass.superclass; |
| 621 } | 621 } |
| 622 | 622 |
| 623 List<Element> directSubtypes = emitter.directSubtypes.putIfAbsent( | 623 List<Element> directSubtypes = emitter.directSubtypes.putIfAbsent( |
| 624 superclass, | 624 superclass, |
| 625 () => <ClassElement>[]); | 625 () => <ClassElement>[]); |
| 626 directSubtypes.add(cls); | 626 directSubtypes.add(cls); |
| 627 } | 627 } |
| 628 | 628 |
| 629 void logSummary(log(message)) { | 629 void logSummary(log(message)) { |
| (...skipping 354 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 984 "Type '$typeString' not found."); | 984 "Type '$typeString' not found."); |
| 985 } | 985 } |
| 986 | 986 |
| 987 static _errorNode(locationNodeOrElement, compiler) { | 987 static _errorNode(locationNodeOrElement, compiler) { |
| 988 if (locationNodeOrElement is Node) return locationNodeOrElement; | 988 if (locationNodeOrElement is Node) return locationNodeOrElement; |
| 989 return locationNodeOrElement.parseNode(compiler); | 989 return locationNodeOrElement.parseNode(compiler); |
| 990 } | 990 } |
| 991 } | 991 } |
| 992 | 992 |
| 993 void checkAllowedLibrary(ElementListener listener, Token token) { | 993 void checkAllowedLibrary(ElementListener listener, Token token) { |
| 994 LibraryElement currentLibrary = listener.compilationUnitElement.getLibrary(); | 994 LibraryElement currentLibrary = listener.compilationUnitElement.library; |
| 995 if (!currentLibrary.canUseNative) { | 995 if (!currentLibrary.canUseNative) { |
| 996 listener.recoverableError(token, "Unexpected token"); | 996 listener.recoverableError(token, "Unexpected token"); |
| 997 } | 997 } |
| 998 } | 998 } |
| 999 | 999 |
| 1000 Token handleNativeBlockToSkip(Listener listener, Token token) { | 1000 Token handleNativeBlockToSkip(Listener listener, Token token) { |
| 1001 checkAllowedLibrary(listener, token); | 1001 checkAllowedLibrary(listener, token); |
| 1002 token = token.next; | 1002 token = token.next; |
| 1003 if (identical(token.kind, STRING_TOKEN)) { | 1003 if (identical(token.kind, STRING_TOKEN)) { |
| 1004 token = token.next; | 1004 token = token.next; |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1105 } | 1105 } |
| 1106 | 1106 |
| 1107 // Check which pattern this native method follows: | 1107 // Check which pattern this native method follows: |
| 1108 // 1) foo() native; | 1108 // 1) foo() native; |
| 1109 // hasBody = false | 1109 // hasBody = false |
| 1110 // 2) foo() native "bar"; | 1110 // 2) foo() native "bar"; |
| 1111 // No longer supported, this is now done with @JSName('foo') and case 1. | 1111 // No longer supported, this is now done with @JSName('foo') and case 1. |
| 1112 // 3) foo() native "return 42"; | 1112 // 3) foo() native "return 42"; |
| 1113 // hasBody = true | 1113 // hasBody = true |
| 1114 bool hasBody = false; | 1114 bool hasBody = false; |
| 1115 assert(element.isNative()); | 1115 assert(element.isNative); |
| 1116 String nativeMethodName = element.fixedBackendName(); | 1116 String nativeMethodName = element.fixedBackendName; |
| 1117 if (nativeBody != null) { | 1117 if (nativeBody != null) { |
| 1118 LiteralString jsCode = nativeBody.asLiteralString(); | 1118 LiteralString jsCode = nativeBody.asLiteralString(); |
| 1119 String str = jsCode.dartString.slowToString(); | 1119 String str = jsCode.dartString.slowToString(); |
| 1120 if (nativeRedirectionRegExp.hasMatch(str)) { | 1120 if (nativeRedirectionRegExp.hasMatch(str)) { |
| 1121 compiler.internalError( | 1121 compiler.internalError( |
| 1122 nativeBody, "Deprecated syntax, use @JSName('name') instead."); | 1122 nativeBody, "Deprecated syntax, use @JSName('name') instead."); |
| 1123 } | 1123 } |
| 1124 hasBody = true; | 1124 hasBody = true; |
| 1125 } | 1125 } |
| 1126 | 1126 |
| 1127 if (!hasBody) { | 1127 if (!hasBody) { |
| 1128 nativeEmitter.nativeMethods.add(element); | 1128 nativeEmitter.nativeMethods.add(element); |
| 1129 } | 1129 } |
| 1130 | 1130 |
| 1131 FunctionSignature parameters = element.functionSignature; | 1131 FunctionSignature parameters = element.functionSignature; |
| 1132 if (!hasBody) { | 1132 if (!hasBody) { |
| 1133 List<String> arguments = <String>[]; | 1133 List<String> arguments = <String>[]; |
| 1134 List<HInstruction> inputs = <HInstruction>[]; | 1134 List<HInstruction> inputs = <HInstruction>[]; |
| 1135 String receiver = ''; | 1135 String receiver = ''; |
| 1136 if (element.isInstanceMember()) { | 1136 if (element.isInstanceMember) { |
| 1137 receiver = '#.'; | 1137 receiver = '#.'; |
| 1138 inputs.add(builder.localsHandler.readThis()); | 1138 inputs.add(builder.localsHandler.readThis()); |
| 1139 } | 1139 } |
| 1140 parameters.forEachParameter((ParameterElement parameter) { | 1140 parameters.forEachParameter((ParameterElement parameter) { |
| 1141 DartType type = parameter.type.unalias(compiler); | 1141 DartType type = parameter.type.unalias(compiler); |
| 1142 HInstruction input = builder.localsHandler.readLocal(parameter); | 1142 HInstruction input = builder.localsHandler.readLocal(parameter); |
| 1143 if (type is FunctionType) { | 1143 if (type is FunctionType) { |
| 1144 // The parameter type is a function type either directly or through | 1144 // The parameter type is a function type either directly or through |
| 1145 // typedef(s). | 1145 // typedef(s). |
| 1146 input = convertDartClosure(parameter, type); | 1146 input = convertDartClosure(parameter, type); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1180 LiteralString jsCode = nativeBody.asLiteralString(); | 1180 LiteralString jsCode = nativeBody.asLiteralString(); |
| 1181 builder.push(new HForeign.statement( | 1181 builder.push(new HForeign.statement( |
| 1182 js.js.statementTemplateYielding( | 1182 js.js.statementTemplateYielding( |
| 1183 new js.LiteralStatement(jsCode.dartString.slowToString())), | 1183 new js.LiteralStatement(jsCode.dartString.slowToString())), |
| 1184 <HInstruction>[], | 1184 <HInstruction>[], |
| 1185 new SideEffects(), | 1185 new SideEffects(), |
| 1186 null, | 1186 null, |
| 1187 backend.dynamicType)); | 1187 backend.dynamicType)); |
| 1188 } | 1188 } |
| 1189 } | 1189 } |
| OLD | NEW |