Index: pkg/compiler/lib/src/js_backend/backend_helpers.dart |
diff --git a/pkg/compiler/lib/src/js_backend/backend_helpers.dart b/pkg/compiler/lib/src/js_backend/backend_helpers.dart |
index 3c5989186d668fa3dee996cb0e33ab00154b968c..899d65eb8d261a86746b7d023c0e95f26d74f629 100644 |
--- a/pkg/compiler/lib/src/js_backend/backend_helpers.dart |
+++ b/pkg/compiler/lib/src/js_backend/backend_helpers.dart |
@@ -4,20 +4,50 @@ |
library dart2js.js_backend.helpers; |
+import '../common.dart'; |
+import '../common/names.dart' show |
+ Uris; |
import '../common/resolution.dart' show |
Resolution; |
import '../compiler.dart' show |
Compiler; |
+import '../core_types.dart' show |
+ CoreClasses; |
import '../elements/elements.dart' show |
+ AbstractFieldElement, |
ClassElement, |
+ ConstructorElement, |
Element, |
+ EnumClassElement, |
+ FunctionElement, |
LibraryElement, |
MethodElement; |
+import '../library_loader.dart' show |
+ LoadedLibraries; |
import 'js_backend.dart'; |
/// Helper classes and functions for the JavaScript backend. |
class BackendHelpers { |
+ static final Uri DART_JS_HELPER = new Uri(scheme: 'dart', path: '_js_helper'); |
+ static final Uri DART_INTERCEPTORS = |
+ new Uri(scheme: 'dart', path: '_interceptors'); |
+ static final Uri DART_FOREIGN_HELPER = |
+ new Uri(scheme: 'dart', path: '_foreign_helper'); |
+ static final Uri DART_JS_MIRRORS = |
+ new Uri(scheme: 'dart', path: '_js_mirrors'); |
+ static final Uri DART_JS_NAMES = |
+ new Uri(scheme: 'dart', path: '_js_names'); |
+ static final Uri DART_EMBEDDED_NAMES = |
+ new Uri(scheme: 'dart', path: '_js_embedded_names'); |
+ static final Uri DART_ISOLATE_HELPER = |
+ new Uri(scheme: 'dart', path: '_isolate_helper'); |
+ static final Uri PACKAGE_JS = |
+ new Uri(scheme: 'package', path: 'js/js.dart'); |
+ |
+ static const String INVOKE_ON = '_getCachedInvocation'; |
+ static const String START_ROOT_ISOLATE = 'startRootIsolate'; |
+ |
final Compiler compiler; |
Element cachedCheckConcurrentModificationError; |
@@ -28,16 +58,348 @@ class BackendHelpers { |
Resolution get resolution => backend.resolution; |
+ CoreClasses get coreClasses => compiler.coreClasses; |
+ |
+ DiagnosticReporter get reporter => compiler.reporter; |
+ |
MethodElement assertTest; |
MethodElement assertThrow; |
MethodElement assertHelper; |
- Element findHelper(String name) => backend.findHelper(name); |
- Element findAsyncHelper(String name) => backend.findAsyncHelper(name); |
- Element findInterceptor(String name) => backend.findInterceptor(name); |
+ LibraryElement jsHelperLibrary; |
+ LibraryElement asyncLibrary; |
+ LibraryElement interceptorsLibrary; |
+ LibraryElement foreignLibrary; |
+ LibraryElement isolateHelperLibrary; |
+ |
+ /// Reference to the internal library to lookup functions to always inline. |
+ LibraryElement internalLibrary; |
+ |
+ ClassElement closureClass; |
+ ClassElement boundClosureClass; |
+ Element assertUnreachableMethod; |
+ Element invokeOnMethod; |
+ |
+ ClassElement jsInterceptorClass; |
+ ClassElement jsStringClass; |
+ ClassElement jsArrayClass; |
+ ClassElement jsNumberClass; |
+ ClassElement jsIntClass; |
+ ClassElement jsDoubleClass; |
+ ClassElement jsNullClass; |
+ ClassElement jsBoolClass; |
+ ClassElement jsPlainJavaScriptObjectClass; |
+ ClassElement jsUnknownJavaScriptObjectClass; |
+ ClassElement jsJavaScriptFunctionClass; |
+ ClassElement jsJavaScriptObjectClass; |
+ |
+ ClassElement jsIndexableClass; |
+ ClassElement jsMutableIndexableClass; |
+ |
+ ClassElement jsMutableArrayClass; |
+ ClassElement jsFixedArrayClass; |
+ ClassElement jsExtendableArrayClass; |
+ ClassElement jsUnmodifiableArrayClass; |
+ ClassElement jsPositiveIntClass; |
+ ClassElement jsUInt32Class; |
+ ClassElement jsUInt31Class; |
+ |
+ Element jsIndexableLength; |
+ Element jsArrayTypedConstructor; |
+ Element jsArrayRemoveLast; |
+ Element jsArrayAdd; |
+ Element jsStringSplit; |
+ Element jsStringToString; |
+ Element jsStringOperatorAdd; |
+ Element objectEquals; |
+ |
+ ClassElement typeLiteralClass; |
+ ClassElement mapLiteralClass; |
+ ClassElement constMapLiteralClass; |
+ ClassElement typeVariableClass; |
+ ConstructorElement mapLiteralConstructor; |
+ ConstructorElement mapLiteralConstructorEmpty; |
+ Element mapLiteralUntypedMaker; |
+ Element mapLiteralUntypedEmptyMaker; |
+ |
+ ClassElement noSideEffectsClass; |
+ ClassElement noThrowsClass; |
+ ClassElement noInlineClass; |
+ ClassElement forceInlineClass; |
+ ClassElement irRepresentationClass; |
+ |
+ ClassElement jsAnnotationClass; |
+ |
+ Element getInterceptorMethod; |
+ |
+ ClassElement jsInvocationMirrorClass; |
+ |
+ ClassElement typedArrayClass; |
+ ClassElement typedArrayOfIntClass; |
+ |
+ /** |
+ * Interface used to determine if an object has the JavaScript |
+ * indexing behavior. The interface is only visible to specific |
+ * libraries. |
+ */ |
+ ClassElement jsIndexingBehaviorInterface; |
+ |
+ Element getNativeInterceptorMethod; |
+ |
+ /// Holds the method "getIsolateAffinityTag" when dart:_js_helper has been |
+ /// loaded. |
+ FunctionElement getIsolateAffinityTagMarker; |
+ |
+ /// Holds the method "disableTreeShaking" in js_mirrors when |
+ /// dart:mirrors has been loaded. |
+ FunctionElement disableTreeShakingMarker; |
+ |
+ /// Holds the method "preserveNames" in js_mirrors when |
+ /// dart:mirrors has been loaded. |
+ FunctionElement preserveNamesMarker; |
+ |
+ /// Holds the method "preserveMetadata" in js_mirrors when |
+ /// dart:mirrors has been loaded. |
+ FunctionElement preserveMetadataMarker; |
+ |
+ /// Holds the method "preserveUris" in js_mirrors when |
+ /// dart:mirrors has been loaded. |
+ FunctionElement preserveUrisMarker; |
+ |
+ /// Holds the method "preserveLibraryNames" in js_mirrors when |
+ /// dart:mirrors has been loaded. |
+ FunctionElement preserveLibraryNamesMarker; |
+ |
+ /// Holds the method "requiresPreamble" in _js_helper. |
+ FunctionElement requiresPreambleMarker; |
+ |
+ /// Holds the class for the [JsGetName] enum. |
+ EnumClassElement jsGetNameEnum; |
+ |
+ /// Holds the class for the [JsBuiltins] enum. |
+ EnumClassElement jsBuiltinEnum; |
+ |
+ // TODO(johnniwinther): Make these private. |
+ // TODO(johnniwinther): Split into findHelperFunction and findHelperClass and |
+ // add a check that the element has the expected kind. |
+ Element findHelper(String name) => find(jsHelperLibrary, name); |
+ Element findAsyncHelper(String name) => find(asyncLibrary, name); |
+ Element findInterceptor(String name) => find(interceptorsLibrary, name); |
Element find(LibraryElement library, String name) { |
- return backend.find(library, name); |
+ Element element = library.implementation.findLocal(name); |
+ assert(invariant(library, element != null, |
+ message: "Element '$name' not found in '${library.canonicalUri}'.")); |
+ return element; |
+ } |
+ |
+ void onLibraryCreated(LibraryElement library) { |
+ Uri uri = library.canonicalUri; |
+ if (uri == DART_JS_HELPER) { |
+ jsHelperLibrary = library; |
+ } else if (uri == Uris.dart_async) { |
+ asyncLibrary = library; |
+ } else if (uri == Uris.dart__internal) { |
+ internalLibrary = library; |
+ } else if (uri == DART_INTERCEPTORS) { |
+ interceptorsLibrary = library; |
+ } else if (uri == DART_FOREIGN_HELPER) { |
+ foreignLibrary = library; |
+ } else if (uri == DART_ISOLATE_HELPER) { |
+ isolateHelperLibrary = library; |
+ } |
+ } |
+ |
+ void initializeHelperClasses(DiagnosticReporter reporter) { |
+ final List missingHelperClasses = []; |
+ ClassElement lookupHelperClass(String name) { |
+ ClassElement result = findHelper(name); |
+ if (result == null) { |
+ missingHelperClasses.add(name); |
+ } |
+ return result; |
+ } |
+ jsInvocationMirrorClass = lookupHelperClass('JSInvocationMirror'); |
+ boundClosureClass = lookupHelperClass('BoundClosure'); |
+ closureClass = lookupHelperClass('Closure'); |
+ if (!missingHelperClasses.isEmpty) { |
+ reporter.internalError(jsHelperLibrary, |
+ 'dart:_js_helper library does not contain required classes: ' |
+ '$missingHelperClasses'); |
+ } |
+ } |
+ |
+ void onLibraryScanned(LibraryElement library) { |
+ Uri uri = library.canonicalUri; |
+ |
+ FunctionElement findMethod(String name) { |
+ return find(library, name); |
+ } |
+ |
+ ClassElement findClass(String name) { |
+ return find(library, name); |
+ } |
+ |
+ if (uri == DART_INTERCEPTORS) { |
+ getInterceptorMethod = findMethod('getInterceptor'); |
+ getNativeInterceptorMethod = findMethod('getNativeInterceptor'); |
+ jsInterceptorClass = findClass('Interceptor'); |
+ jsStringClass = findClass('JSString'); |
+ jsArrayClass = findClass('JSArray'); |
+ // The int class must be before the double class, because the |
+ // emitter relies on this list for the order of type checks. |
+ jsIntClass = findClass('JSInt'); |
+ jsPositiveIntClass = findClass('JSPositiveInt'); |
+ jsUInt32Class = findClass('JSUInt32'); |
+ jsUInt31Class = findClass('JSUInt31'); |
+ jsDoubleClass = findClass('JSDouble'); |
+ jsNumberClass = findClass('JSNumber'); |
+ jsNullClass = findClass('JSNull'); |
+ jsBoolClass = findClass('JSBool'); |
+ jsMutableArrayClass = findClass('JSMutableArray'); |
+ jsFixedArrayClass = findClass('JSFixedArray'); |
+ jsExtendableArrayClass = findClass('JSExtendableArray'); |
+ jsUnmodifiableArrayClass = findClass('JSUnmodifiableArray'); |
+ jsPlainJavaScriptObjectClass = findClass('PlainJavaScriptObject'); |
+ jsJavaScriptObjectClass = findClass('JavaScriptObject'); |
+ jsJavaScriptFunctionClass = findClass('JavaScriptFunction'); |
+ jsUnknownJavaScriptObjectClass = findClass('UnknownJavaScriptObject'); |
+ jsIndexableClass = findClass('JSIndexable'); |
+ jsMutableIndexableClass = findClass('JSMutableIndexable'); |
+ } else if (uri == DART_JS_HELPER) { |
+ initializeHelperClasses(reporter); |
+ assertTest = findHelper('assertTest'); |
+ assertThrow = findHelper('assertThrow'); |
+ assertHelper = findHelper('assertHelper'); |
+ assertUnreachableMethod = findHelper('assertUnreachable'); |
+ |
+ typeLiteralClass = findClass('TypeImpl'); |
+ constMapLiteralClass = findClass('ConstantMap'); |
+ typeVariableClass = findClass('TypeVariable'); |
+ |
+ jsIndexingBehaviorInterface = findClass('JavaScriptIndexingBehavior'); |
+ |
+ noSideEffectsClass = findClass('NoSideEffects'); |
+ noThrowsClass = findClass('NoThrows'); |
+ noInlineClass = findClass('NoInline'); |
+ forceInlineClass = findClass('ForceInline'); |
+ irRepresentationClass = findClass('IrRepresentation'); |
+ |
+ getIsolateAffinityTagMarker = findMethod('getIsolateAffinityTag'); |
+ |
+ requiresPreambleMarker = findMethod('requiresPreamble'); |
+ } else if (uri == DART_JS_MIRRORS) { |
+ disableTreeShakingMarker = find(library, 'disableTreeShaking'); |
+ preserveMetadataMarker = find(library, 'preserveMetadata'); |
+ preserveUrisMarker = find(library, 'preserveUris'); |
+ preserveLibraryNamesMarker = find(library, 'preserveLibraryNames'); |
+ } else if (uri == DART_JS_NAMES) { |
+ preserveNamesMarker = find(library, 'preserveNames'); |
+ } else if (uri == DART_EMBEDDED_NAMES) { |
+ jsGetNameEnum = find(library, 'JsGetName'); |
+ jsBuiltinEnum = find(library, 'JsBuiltin'); |
+ } else if (uri == Uris.dart__native_typed_data) { |
+ typedArrayClass = findClass('NativeTypedArray'); |
+ typedArrayOfIntClass = findClass('NativeTypedArrayOfInt'); |
+ } else if (uri == PACKAGE_JS) { |
+ jsAnnotationClass = find(library, 'JS'); |
+ } |
+ } |
+ |
+ |
+ void onLibrariesLoaded(LoadedLibraries loadedLibraries) { |
+ assert(loadedLibraries.containsLibrary(Uris.dart_core)); |
+ assert(loadedLibraries.containsLibrary(DART_INTERCEPTORS)); |
+ assert(loadedLibraries.containsLibrary(DART_JS_HELPER)); |
+ |
+ if (jsInvocationMirrorClass != null) { |
+ jsInvocationMirrorClass.ensureResolved(resolution); |
+ invokeOnMethod = jsInvocationMirrorClass.lookupLocalMember(INVOKE_ON); |
+ } |
+ |
+ // [LinkedHashMap] is reexported from dart:collection and can therefore not |
+ // be loaded from dart:core in [onLibraryScanned]. |
+ mapLiteralClass = compiler.coreLibrary.find('LinkedHashMap'); |
+ assert(invariant(compiler.coreLibrary, mapLiteralClass != null, |
+ message: "Element 'LinkedHashMap' not found in 'dart:core'.")); |
+ |
+ // TODO(kasperl): Some tests do not define the special JSArray |
+ // subclasses, so we check to see if they are defined before |
+ // trying to resolve them. |
+ if (jsFixedArrayClass != null) { |
+ jsFixedArrayClass.ensureResolved(resolution); |
+ } |
+ if (jsExtendableArrayClass != null) { |
+ jsExtendableArrayClass.ensureResolved(resolution); |
+ } |
+ if (jsUnmodifiableArrayClass != null) { |
+ jsUnmodifiableArrayClass.ensureResolved(resolution); |
+ } |
+ |
+ jsIndexableClass.ensureResolved(resolution); |
+ jsIndexableLength = compiler.lookupElementIn( |
+ jsIndexableClass, 'length'); |
+ if (jsIndexableLength != null && jsIndexableLength.isAbstractField) { |
+ AbstractFieldElement element = jsIndexableLength; |
+ jsIndexableLength = element.getter; |
+ } |
+ |
+ jsArrayClass.ensureResolved(resolution); |
+ jsArrayTypedConstructor = compiler.lookupElementIn(jsArrayClass, 'typed'); |
+ jsArrayRemoveLast = compiler.lookupElementIn(jsArrayClass, 'removeLast'); |
+ jsArrayAdd = compiler.lookupElementIn(jsArrayClass, 'add'); |
+ |
+ jsStringClass.ensureResolved(resolution); |
+ jsStringSplit = compiler.lookupElementIn(jsStringClass, 'split'); |
+ jsStringOperatorAdd = compiler.lookupElementIn(jsStringClass, '+'); |
+ jsStringToString = compiler.lookupElementIn(jsStringClass, 'toString'); |
+ |
+ objectEquals = compiler.lookupElementIn(coreClasses.objectClass, '=='); |
+ } |
+ |
+ Element get badMain { |
+ return findHelper('badMain'); |
+ } |
+ |
+ Element get missingMain { |
+ return findHelper('missingMain'); |
+ } |
+ |
+ Element get mainHasTooManyParameters { |
+ return findHelper('mainHasTooManyParameters'); |
+ } |
+ |
+ Element get loadLibraryWrapper { |
+ return findHelper("_loadLibraryWrapper"); |
+ } |
+ |
+ Element get boolConversionCheck { |
+ return findHelper('boolConversionCheck'); |
+ } |
+ |
+ Element get consoleTraceHelper { |
+ return findHelper('consoleTraceHelper'); |
+ } |
+ |
+ Element get postTraceHelper { |
+ return findHelper('postTraceHelper'); |
+ } |
+ |
+ Element get closureFromTearOff { |
+ return findHelper('closureFromTearOff'); |
+ } |
+ |
+ Element get isJsIndexable { |
+ return findHelper('isJsIndexable'); |
+ } |
+ |
+ |
+ Element get throwIllegalArgumentException { |
+ return findHelper('iae'); |
+ } |
+ |
+ Element get throwIndexOutOfRangeException { |
+ return findHelper('ioore'); |
} |
Element get exceptionUnwrapper { |
@@ -252,6 +614,30 @@ class BackendHelpers { |
return classElement.lookupConstructor(""); |
} |
+ ClassElement get VoidRuntimeType { |
+ return findHelper('VoidRuntimeType'); |
+ } |
+ |
+ ClassElement get RuntimeType { |
+ return findHelper('RuntimeType'); |
+ } |
+ |
+ ClassElement get RuntimeFunctionType { |
+ return findHelper('RuntimeFunctionType'); |
+ } |
+ |
+ ClassElement get RuntimeTypePlain { |
+ return findHelper('RuntimeTypePlain'); |
+ } |
+ |
+ ClassElement get RuntimeTypeGeneric { |
+ return findHelper('RuntimeTypeGeneric'); |
+ } |
+ |
+ ClassElement get DynamicRuntimeType { |
+ return findHelper('DynamicRuntimeType'); |
+ } |
+ |
MethodElement get functionTypeTestMetaHelper { |
return findHelper('functionTypeTestMetaHelper'); |
} |
@@ -259,4 +645,24 @@ class BackendHelpers { |
MethodElement get defineProperty { |
return findHelper('defineProperty'); |
} |
+ |
+ Element get startRootIsolate { |
+ return find(isolateHelperLibrary, START_ROOT_ISOLATE); |
+ } |
+ |
+ Element get currentIsolate { |
+ return find(isolateHelperLibrary, '_currentIsolate'); |
+ } |
+ |
+ Element get callInIsolate { |
+ return find(isolateHelperLibrary, '_callInIsolate'); |
+ } |
+ |
+ Element get findIndexForNativeSubclassType { |
+ return findInterceptor('findIndexForNativeSubclassType'); |
+ } |
+ |
+ Element get convertRtiToRuntimeType { |
+ return findHelper('convertRtiToRuntimeType'); |
+ } |
} |