OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 dart2js.js_backend.helpers; | 5 library dart2js.js_backend.helpers; |
6 | 6 |
| 7 import '../common.dart'; |
| 8 import '../common/names.dart' show |
| 9 Uris; |
7 import '../common/resolution.dart' show | 10 import '../common/resolution.dart' show |
8 Resolution; | 11 Resolution; |
9 import '../compiler.dart' show | 12 import '../compiler.dart' show |
10 Compiler; | 13 Compiler; |
| 14 import '../core_types.dart' show |
| 15 CoreClasses; |
11 import '../elements/elements.dart' show | 16 import '../elements/elements.dart' show |
| 17 AbstractFieldElement, |
12 ClassElement, | 18 ClassElement, |
| 19 ConstructorElement, |
13 Element, | 20 Element, |
| 21 EnumClassElement, |
| 22 FunctionElement, |
14 LibraryElement, | 23 LibraryElement, |
15 MethodElement; | 24 MethodElement; |
| 25 import '../library_loader.dart' show |
| 26 LoadedLibraries; |
16 | 27 |
17 import 'js_backend.dart'; | 28 import 'js_backend.dart'; |
18 | 29 |
19 /// Helper classes and functions for the JavaScript backend. | 30 /// Helper classes and functions for the JavaScript backend. |
20 class BackendHelpers { | 31 class BackendHelpers { |
| 32 static final Uri DART_JS_HELPER = new Uri(scheme: 'dart', path: '_js_helper'); |
| 33 static final Uri DART_INTERCEPTORS = |
| 34 new Uri(scheme: 'dart', path: '_interceptors'); |
| 35 static final Uri DART_FOREIGN_HELPER = |
| 36 new Uri(scheme: 'dart', path: '_foreign_helper'); |
| 37 static final Uri DART_JS_MIRRORS = |
| 38 new Uri(scheme: 'dart', path: '_js_mirrors'); |
| 39 static final Uri DART_JS_NAMES = |
| 40 new Uri(scheme: 'dart', path: '_js_names'); |
| 41 static final Uri DART_EMBEDDED_NAMES = |
| 42 new Uri(scheme: 'dart', path: '_js_embedded_names'); |
| 43 static final Uri DART_ISOLATE_HELPER = |
| 44 new Uri(scheme: 'dart', path: '_isolate_helper'); |
| 45 static final Uri PACKAGE_JS = |
| 46 new Uri(scheme: 'package', path: 'js/js.dart'); |
| 47 |
| 48 static const String INVOKE_ON = '_getCachedInvocation'; |
| 49 static const String START_ROOT_ISOLATE = 'startRootIsolate'; |
| 50 |
21 final Compiler compiler; | 51 final Compiler compiler; |
22 | 52 |
23 Element cachedCheckConcurrentModificationError; | 53 Element cachedCheckConcurrentModificationError; |
24 | 54 |
25 BackendHelpers(this.compiler); | 55 BackendHelpers(this.compiler); |
26 | 56 |
27 JavaScriptBackend get backend => compiler.backend; | 57 JavaScriptBackend get backend => compiler.backend; |
28 | 58 |
29 Resolution get resolution => backend.resolution; | 59 Resolution get resolution => backend.resolution; |
30 | 60 |
| 61 CoreClasses get coreClasses => compiler.coreClasses; |
| 62 |
| 63 DiagnosticReporter get reporter => compiler.reporter; |
| 64 |
31 MethodElement assertTest; | 65 MethodElement assertTest; |
32 MethodElement assertThrow; | 66 MethodElement assertThrow; |
33 MethodElement assertHelper; | 67 MethodElement assertHelper; |
34 | 68 |
35 Element findHelper(String name) => backend.findHelper(name); | 69 |
36 Element findAsyncHelper(String name) => backend.findAsyncHelper(name); | 70 LibraryElement jsHelperLibrary; |
37 Element findInterceptor(String name) => backend.findInterceptor(name); | 71 LibraryElement asyncLibrary; |
38 | 72 LibraryElement interceptorsLibrary; |
| 73 LibraryElement foreignLibrary; |
| 74 LibraryElement isolateHelperLibrary; |
| 75 |
| 76 /// Reference to the internal library to lookup functions to always inline. |
| 77 LibraryElement internalLibrary; |
| 78 |
| 79 ClassElement closureClass; |
| 80 ClassElement boundClosureClass; |
| 81 Element assertUnreachableMethod; |
| 82 Element invokeOnMethod; |
| 83 |
| 84 ClassElement jsInterceptorClass; |
| 85 ClassElement jsStringClass; |
| 86 ClassElement jsArrayClass; |
| 87 ClassElement jsNumberClass; |
| 88 ClassElement jsIntClass; |
| 89 ClassElement jsDoubleClass; |
| 90 ClassElement jsNullClass; |
| 91 ClassElement jsBoolClass; |
| 92 ClassElement jsPlainJavaScriptObjectClass; |
| 93 ClassElement jsUnknownJavaScriptObjectClass; |
| 94 ClassElement jsJavaScriptFunctionClass; |
| 95 ClassElement jsJavaScriptObjectClass; |
| 96 |
| 97 ClassElement jsIndexableClass; |
| 98 ClassElement jsMutableIndexableClass; |
| 99 |
| 100 ClassElement jsMutableArrayClass; |
| 101 ClassElement jsFixedArrayClass; |
| 102 ClassElement jsExtendableArrayClass; |
| 103 ClassElement jsUnmodifiableArrayClass; |
| 104 ClassElement jsPositiveIntClass; |
| 105 ClassElement jsUInt32Class; |
| 106 ClassElement jsUInt31Class; |
| 107 |
| 108 Element jsIndexableLength; |
| 109 Element jsArrayTypedConstructor; |
| 110 Element jsArrayRemoveLast; |
| 111 Element jsArrayAdd; |
| 112 Element jsStringSplit; |
| 113 Element jsStringToString; |
| 114 Element jsStringOperatorAdd; |
| 115 Element objectEquals; |
| 116 |
| 117 ClassElement typeLiteralClass; |
| 118 ClassElement mapLiteralClass; |
| 119 ClassElement constMapLiteralClass; |
| 120 ClassElement typeVariableClass; |
| 121 ConstructorElement mapLiteralConstructor; |
| 122 ConstructorElement mapLiteralConstructorEmpty; |
| 123 Element mapLiteralUntypedMaker; |
| 124 Element mapLiteralUntypedEmptyMaker; |
| 125 |
| 126 ClassElement noSideEffectsClass; |
| 127 ClassElement noThrowsClass; |
| 128 ClassElement noInlineClass; |
| 129 ClassElement forceInlineClass; |
| 130 ClassElement irRepresentationClass; |
| 131 |
| 132 ClassElement jsAnnotationClass; |
| 133 |
| 134 Element getInterceptorMethod; |
| 135 |
| 136 ClassElement jsInvocationMirrorClass; |
| 137 |
| 138 ClassElement typedArrayClass; |
| 139 ClassElement typedArrayOfIntClass; |
| 140 |
| 141 /** |
| 142 * Interface used to determine if an object has the JavaScript |
| 143 * indexing behavior. The interface is only visible to specific |
| 144 * libraries. |
| 145 */ |
| 146 ClassElement jsIndexingBehaviorInterface; |
| 147 |
| 148 Element getNativeInterceptorMethod; |
| 149 |
| 150 /// Holds the method "getIsolateAffinityTag" when dart:_js_helper has been |
| 151 /// loaded. |
| 152 FunctionElement getIsolateAffinityTagMarker; |
| 153 |
| 154 /// Holds the method "disableTreeShaking" in js_mirrors when |
| 155 /// dart:mirrors has been loaded. |
| 156 FunctionElement disableTreeShakingMarker; |
| 157 |
| 158 /// Holds the method "preserveNames" in js_mirrors when |
| 159 /// dart:mirrors has been loaded. |
| 160 FunctionElement preserveNamesMarker; |
| 161 |
| 162 /// Holds the method "preserveMetadata" in js_mirrors when |
| 163 /// dart:mirrors has been loaded. |
| 164 FunctionElement preserveMetadataMarker; |
| 165 |
| 166 /// Holds the method "preserveUris" in js_mirrors when |
| 167 /// dart:mirrors has been loaded. |
| 168 FunctionElement preserveUrisMarker; |
| 169 |
| 170 /// Holds the method "preserveLibraryNames" in js_mirrors when |
| 171 /// dart:mirrors has been loaded. |
| 172 FunctionElement preserveLibraryNamesMarker; |
| 173 |
| 174 /// Holds the method "requiresPreamble" in _js_helper. |
| 175 FunctionElement requiresPreambleMarker; |
| 176 |
| 177 /// Holds the class for the [JsGetName] enum. |
| 178 EnumClassElement jsGetNameEnum; |
| 179 |
| 180 /// Holds the class for the [JsBuiltins] enum. |
| 181 EnumClassElement jsBuiltinEnum; |
| 182 |
| 183 // TODO(johnniwinther): Make these private. |
| 184 // TODO(johnniwinther): Split into findHelperFunction and findHelperClass and |
| 185 // add a check that the element has the expected kind. |
| 186 Element findHelper(String name) => find(jsHelperLibrary, name); |
| 187 Element findAsyncHelper(String name) => find(asyncLibrary, name); |
| 188 Element findInterceptor(String name) => find(interceptorsLibrary, name); |
39 Element find(LibraryElement library, String name) { | 189 Element find(LibraryElement library, String name) { |
40 return backend.find(library, name); | 190 Element element = library.implementation.findLocal(name); |
| 191 assert(invariant(library, element != null, |
| 192 message: "Element '$name' not found in '${library.canonicalUri}'.")); |
| 193 return element; |
| 194 } |
| 195 |
| 196 void onLibraryCreated(LibraryElement library) { |
| 197 Uri uri = library.canonicalUri; |
| 198 if (uri == DART_JS_HELPER) { |
| 199 jsHelperLibrary = library; |
| 200 } else if (uri == Uris.dart_async) { |
| 201 asyncLibrary = library; |
| 202 } else if (uri == Uris.dart__internal) { |
| 203 internalLibrary = library; |
| 204 } else if (uri == DART_INTERCEPTORS) { |
| 205 interceptorsLibrary = library; |
| 206 } else if (uri == DART_FOREIGN_HELPER) { |
| 207 foreignLibrary = library; |
| 208 } else if (uri == DART_ISOLATE_HELPER) { |
| 209 isolateHelperLibrary = library; |
| 210 } |
| 211 } |
| 212 |
| 213 void initializeHelperClasses(DiagnosticReporter reporter) { |
| 214 final List missingHelperClasses = []; |
| 215 ClassElement lookupHelperClass(String name) { |
| 216 ClassElement result = findHelper(name); |
| 217 if (result == null) { |
| 218 missingHelperClasses.add(name); |
| 219 } |
| 220 return result; |
| 221 } |
| 222 jsInvocationMirrorClass = lookupHelperClass('JSInvocationMirror'); |
| 223 boundClosureClass = lookupHelperClass('BoundClosure'); |
| 224 closureClass = lookupHelperClass('Closure'); |
| 225 if (!missingHelperClasses.isEmpty) { |
| 226 reporter.internalError(jsHelperLibrary, |
| 227 'dart:_js_helper library does not contain required classes: ' |
| 228 '$missingHelperClasses'); |
| 229 } |
| 230 } |
| 231 |
| 232 void onLibraryScanned(LibraryElement library) { |
| 233 Uri uri = library.canonicalUri; |
| 234 |
| 235 FunctionElement findMethod(String name) { |
| 236 return find(library, name); |
| 237 } |
| 238 |
| 239 ClassElement findClass(String name) { |
| 240 return find(library, name); |
| 241 } |
| 242 |
| 243 if (uri == DART_INTERCEPTORS) { |
| 244 getInterceptorMethod = findMethod('getInterceptor'); |
| 245 getNativeInterceptorMethod = findMethod('getNativeInterceptor'); |
| 246 jsInterceptorClass = findClass('Interceptor'); |
| 247 jsStringClass = findClass('JSString'); |
| 248 jsArrayClass = findClass('JSArray'); |
| 249 // The int class must be before the double class, because the |
| 250 // emitter relies on this list for the order of type checks. |
| 251 jsIntClass = findClass('JSInt'); |
| 252 jsPositiveIntClass = findClass('JSPositiveInt'); |
| 253 jsUInt32Class = findClass('JSUInt32'); |
| 254 jsUInt31Class = findClass('JSUInt31'); |
| 255 jsDoubleClass = findClass('JSDouble'); |
| 256 jsNumberClass = findClass('JSNumber'); |
| 257 jsNullClass = findClass('JSNull'); |
| 258 jsBoolClass = findClass('JSBool'); |
| 259 jsMutableArrayClass = findClass('JSMutableArray'); |
| 260 jsFixedArrayClass = findClass('JSFixedArray'); |
| 261 jsExtendableArrayClass = findClass('JSExtendableArray'); |
| 262 jsUnmodifiableArrayClass = findClass('JSUnmodifiableArray'); |
| 263 jsPlainJavaScriptObjectClass = findClass('PlainJavaScriptObject'); |
| 264 jsJavaScriptObjectClass = findClass('JavaScriptObject'); |
| 265 jsJavaScriptFunctionClass = findClass('JavaScriptFunction'); |
| 266 jsUnknownJavaScriptObjectClass = findClass('UnknownJavaScriptObject'); |
| 267 jsIndexableClass = findClass('JSIndexable'); |
| 268 jsMutableIndexableClass = findClass('JSMutableIndexable'); |
| 269 } else if (uri == DART_JS_HELPER) { |
| 270 initializeHelperClasses(reporter); |
| 271 assertTest = findHelper('assertTest'); |
| 272 assertThrow = findHelper('assertThrow'); |
| 273 assertHelper = findHelper('assertHelper'); |
| 274 assertUnreachableMethod = findHelper('assertUnreachable'); |
| 275 |
| 276 typeLiteralClass = findClass('TypeImpl'); |
| 277 constMapLiteralClass = findClass('ConstantMap'); |
| 278 typeVariableClass = findClass('TypeVariable'); |
| 279 |
| 280 jsIndexingBehaviorInterface = findClass('JavaScriptIndexingBehavior'); |
| 281 |
| 282 noSideEffectsClass = findClass('NoSideEffects'); |
| 283 noThrowsClass = findClass('NoThrows'); |
| 284 noInlineClass = findClass('NoInline'); |
| 285 forceInlineClass = findClass('ForceInline'); |
| 286 irRepresentationClass = findClass('IrRepresentation'); |
| 287 |
| 288 getIsolateAffinityTagMarker = findMethod('getIsolateAffinityTag'); |
| 289 |
| 290 requiresPreambleMarker = findMethod('requiresPreamble'); |
| 291 } else if (uri == DART_JS_MIRRORS) { |
| 292 disableTreeShakingMarker = find(library, 'disableTreeShaking'); |
| 293 preserveMetadataMarker = find(library, 'preserveMetadata'); |
| 294 preserveUrisMarker = find(library, 'preserveUris'); |
| 295 preserveLibraryNamesMarker = find(library, 'preserveLibraryNames'); |
| 296 } else if (uri == DART_JS_NAMES) { |
| 297 preserveNamesMarker = find(library, 'preserveNames'); |
| 298 } else if (uri == DART_EMBEDDED_NAMES) { |
| 299 jsGetNameEnum = find(library, 'JsGetName'); |
| 300 jsBuiltinEnum = find(library, 'JsBuiltin'); |
| 301 } else if (uri == Uris.dart__native_typed_data) { |
| 302 typedArrayClass = findClass('NativeTypedArray'); |
| 303 typedArrayOfIntClass = findClass('NativeTypedArrayOfInt'); |
| 304 } else if (uri == PACKAGE_JS) { |
| 305 jsAnnotationClass = find(library, 'JS'); |
| 306 } |
| 307 } |
| 308 |
| 309 |
| 310 void onLibrariesLoaded(LoadedLibraries loadedLibraries) { |
| 311 assert(loadedLibraries.containsLibrary(Uris.dart_core)); |
| 312 assert(loadedLibraries.containsLibrary(DART_INTERCEPTORS)); |
| 313 assert(loadedLibraries.containsLibrary(DART_JS_HELPER)); |
| 314 |
| 315 if (jsInvocationMirrorClass != null) { |
| 316 jsInvocationMirrorClass.ensureResolved(resolution); |
| 317 invokeOnMethod = jsInvocationMirrorClass.lookupLocalMember(INVOKE_ON); |
| 318 } |
| 319 |
| 320 // [LinkedHashMap] is reexported from dart:collection and can therefore not |
| 321 // be loaded from dart:core in [onLibraryScanned]. |
| 322 mapLiteralClass = compiler.coreLibrary.find('LinkedHashMap'); |
| 323 assert(invariant(compiler.coreLibrary, mapLiteralClass != null, |
| 324 message: "Element 'LinkedHashMap' not found in 'dart:core'.")); |
| 325 |
| 326 // TODO(kasperl): Some tests do not define the special JSArray |
| 327 // subclasses, so we check to see if they are defined before |
| 328 // trying to resolve them. |
| 329 if (jsFixedArrayClass != null) { |
| 330 jsFixedArrayClass.ensureResolved(resolution); |
| 331 } |
| 332 if (jsExtendableArrayClass != null) { |
| 333 jsExtendableArrayClass.ensureResolved(resolution); |
| 334 } |
| 335 if (jsUnmodifiableArrayClass != null) { |
| 336 jsUnmodifiableArrayClass.ensureResolved(resolution); |
| 337 } |
| 338 |
| 339 jsIndexableClass.ensureResolved(resolution); |
| 340 jsIndexableLength = compiler.lookupElementIn( |
| 341 jsIndexableClass, 'length'); |
| 342 if (jsIndexableLength != null && jsIndexableLength.isAbstractField) { |
| 343 AbstractFieldElement element = jsIndexableLength; |
| 344 jsIndexableLength = element.getter; |
| 345 } |
| 346 |
| 347 jsArrayClass.ensureResolved(resolution); |
| 348 jsArrayTypedConstructor = compiler.lookupElementIn(jsArrayClass, 'typed'); |
| 349 jsArrayRemoveLast = compiler.lookupElementIn(jsArrayClass, 'removeLast'); |
| 350 jsArrayAdd = compiler.lookupElementIn(jsArrayClass, 'add'); |
| 351 |
| 352 jsStringClass.ensureResolved(resolution); |
| 353 jsStringSplit = compiler.lookupElementIn(jsStringClass, 'split'); |
| 354 jsStringOperatorAdd = compiler.lookupElementIn(jsStringClass, '+'); |
| 355 jsStringToString = compiler.lookupElementIn(jsStringClass, 'toString'); |
| 356 |
| 357 objectEquals = compiler.lookupElementIn(coreClasses.objectClass, '=='); |
| 358 } |
| 359 |
| 360 Element get badMain { |
| 361 return findHelper('badMain'); |
| 362 } |
| 363 |
| 364 Element get missingMain { |
| 365 return findHelper('missingMain'); |
| 366 } |
| 367 |
| 368 Element get mainHasTooManyParameters { |
| 369 return findHelper('mainHasTooManyParameters'); |
| 370 } |
| 371 |
| 372 Element get loadLibraryWrapper { |
| 373 return findHelper("_loadLibraryWrapper"); |
| 374 } |
| 375 |
| 376 Element get boolConversionCheck { |
| 377 return findHelper('boolConversionCheck'); |
| 378 } |
| 379 |
| 380 Element get consoleTraceHelper { |
| 381 return findHelper('consoleTraceHelper'); |
| 382 } |
| 383 |
| 384 Element get postTraceHelper { |
| 385 return findHelper('postTraceHelper'); |
| 386 } |
| 387 |
| 388 Element get closureFromTearOff { |
| 389 return findHelper('closureFromTearOff'); |
| 390 } |
| 391 |
| 392 Element get isJsIndexable { |
| 393 return findHelper('isJsIndexable'); |
| 394 } |
| 395 |
| 396 |
| 397 Element get throwIllegalArgumentException { |
| 398 return findHelper('iae'); |
| 399 } |
| 400 |
| 401 Element get throwIndexOutOfRangeException { |
| 402 return findHelper('ioore'); |
41 } | 403 } |
42 | 404 |
43 Element get exceptionUnwrapper { | 405 Element get exceptionUnwrapper { |
44 return findHelper('unwrapException'); | 406 return findHelper('unwrapException'); |
45 } | 407 } |
46 | 408 |
47 Element get throwRuntimeError { | 409 Element get throwRuntimeError { |
48 return findHelper('throwRuntimeError'); | 410 return findHelper('throwRuntimeError'); |
49 } | 411 } |
50 | 412 |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
245 ClassElement classElement = asyncStarController; | 607 ClassElement classElement = asyncStarController; |
246 return classElement.lookupConstructor(""); | 608 return classElement.lookupConstructor(""); |
247 } | 609 } |
248 | 610 |
249 Element get streamIteratorConstructor { | 611 Element get streamIteratorConstructor { |
250 ClassElement classElement = find(compiler.asyncLibrary, "StreamIterator"); | 612 ClassElement classElement = find(compiler.asyncLibrary, "StreamIterator"); |
251 classElement.ensureResolved(resolution); | 613 classElement.ensureResolved(resolution); |
252 return classElement.lookupConstructor(""); | 614 return classElement.lookupConstructor(""); |
253 } | 615 } |
254 | 616 |
| 617 ClassElement get VoidRuntimeType { |
| 618 return findHelper('VoidRuntimeType'); |
| 619 } |
| 620 |
| 621 ClassElement get RuntimeType { |
| 622 return findHelper('RuntimeType'); |
| 623 } |
| 624 |
| 625 ClassElement get RuntimeFunctionType { |
| 626 return findHelper('RuntimeFunctionType'); |
| 627 } |
| 628 |
| 629 ClassElement get RuntimeTypePlain { |
| 630 return findHelper('RuntimeTypePlain'); |
| 631 } |
| 632 |
| 633 ClassElement get RuntimeTypeGeneric { |
| 634 return findHelper('RuntimeTypeGeneric'); |
| 635 } |
| 636 |
| 637 ClassElement get DynamicRuntimeType { |
| 638 return findHelper('DynamicRuntimeType'); |
| 639 } |
| 640 |
255 MethodElement get functionTypeTestMetaHelper { | 641 MethodElement get functionTypeTestMetaHelper { |
256 return findHelper('functionTypeTestMetaHelper'); | 642 return findHelper('functionTypeTestMetaHelper'); |
257 } | 643 } |
258 | 644 |
259 MethodElement get defineProperty { | 645 MethodElement get defineProperty { |
260 return findHelper('defineProperty'); | 646 return findHelper('defineProperty'); |
261 } | 647 } |
| 648 |
| 649 Element get startRootIsolate { |
| 650 return find(isolateHelperLibrary, START_ROOT_ISOLATE); |
| 651 } |
| 652 |
| 653 Element get currentIsolate { |
| 654 return find(isolateHelperLibrary, '_currentIsolate'); |
| 655 } |
| 656 |
| 657 Element get callInIsolate { |
| 658 return find(isolateHelperLibrary, '_callInIsolate'); |
| 659 } |
| 660 |
| 661 Element get findIndexForNativeSubclassType { |
| 662 return findInterceptor('findIndexForNativeSubclassType'); |
| 663 } |
| 664 |
| 665 Element get convertRtiToRuntimeType { |
| 666 return findHelper('convertRtiToRuntimeType'); |
| 667 } |
262 } | 668 } |
OLD | NEW |