Chromium Code Reviews| Index: pkg/compiler/lib/src/native/enqueue.dart |
| diff --git a/pkg/compiler/lib/src/native/enqueue.dart b/pkg/compiler/lib/src/native/enqueue.dart |
| index 525ff98f032daa11ee1c5f23e9211afce149a262..444eb6f7dad286f2dfc8828ef9ef492981d873f5 100644 |
| --- a/pkg/compiler/lib/src/native/enqueue.dart |
| +++ b/pkg/compiler/lib/src/native/enqueue.dart |
| @@ -2,25 +2,23 @@ |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| +import 'package:front_end/src/fasta/scanner.dart' show BeginGroupToken, Token; |
| +import 'package:front_end/src/fasta/scanner.dart' as Tokens show EOF_TOKEN; |
| + |
| import '../common.dart'; |
| -import '../common/backend_api.dart' show ForeignResolver; |
| +import '../common/backend_api.dart'; |
| import '../common/resolution.dart' show Resolution; |
| import '../compiler.dart' show Compiler; |
| -import '../constants/values.dart'; |
| import '../common_elements.dart' show CommonElements; |
| import '../elements/elements.dart'; |
| import '../elements/entities.dart'; |
| -import '../elements/modelx.dart' show FunctionElementX; |
| import '../elements/resolution_types.dart'; |
| import '../elements/types.dart'; |
| import '../js_backend/backend_helpers.dart' show BackendHelpers; |
| import '../js_backend/backend_usage.dart' show BackendUsageBuilder; |
| import '../js_backend/js_backend.dart'; |
| -import '../js_backend/native_data.dart' show NativeBasicDataBuilder; |
| +import '../js_backend/native_data.dart' show NativeBasicData, NativeData; |
| import '../js_emitter/js_emitter.dart' show CodeEmitterTask, NativeEmitter; |
| -import 'package:front_end/src/fasta/scanner.dart' show BeginGroupToken, Token; |
| -import 'package:front_end/src/fasta/scanner.dart' as Tokens show EOF_TOKEN; |
| -import '../tree/tree.dart'; |
| import '../universe/use.dart' show StaticUse, TypeUse; |
| import '../universe/world_impact.dart' |
| show WorldImpact, WorldImpactBuilder, WorldImpactBuilderImpl; |
| @@ -50,75 +48,216 @@ class NativeEnqueuer { |
| } |
| abstract class NativeEnqueuerBase implements NativeEnqueuer { |
|
Johnni Winther
2017/03/28 09:30:28
Weird diff. Code is moved from NativeEnqueuerBase
|
| - /// The set of all native classes. Each native class is in [nativeClasses] |
| - /// and exactly one of [unusedClasses] and [registeredClasses]. |
| - final Set<ClassElement> _nativeClasses = new Set<ClassElement>(); |
| - |
| final Set<ClassElement> _registeredClasses = new Set<ClassElement>(); |
| final Set<ClassElement> _unusedClasses = new Set<ClassElement>(); |
| bool get hasInstantiatedNativeClasses => !_registeredClasses.isEmpty; |
| - final Set<ClassElement> nativeClassesAndSubclasses = new Set<ClassElement>(); |
| - |
| - final Compiler compiler; |
| + final Compiler _compiler; |
| final bool enableLiveTypeAnalysis; |
| /// Subclasses of [NativeEnqueuerBase] are constructed by the backend. |
| - NativeEnqueuerBase(Compiler compiler, this.enableLiveTypeAnalysis) |
| - : this.compiler = compiler; |
| + NativeEnqueuerBase(this._compiler, this.enableLiveTypeAnalysis); |
| + |
| + JavaScriptBackend get _backend => _compiler.backend; |
| + BackendHelpers get _helpers => _backend.helpers; |
| + Resolution get _resolution => _compiler.resolution; |
| - JavaScriptBackend get backend => compiler.backend; |
| - BackendHelpers get helpers => backend.helpers; |
| - Resolution get resolution => compiler.resolution; |
| + DiagnosticReporter get _reporter => _compiler.reporter; |
| + CommonElements get _commonElements => _compiler.commonElements; |
| - DiagnosticReporter get reporter => compiler.reporter; |
| - CommonElements get commonElements => compiler.commonElements; |
| + NativeBasicData get _nativeBasicData => _backend.nativeBasicData; |
| - void onInstantiatedType(ResolutionInterfaceType type) { |
| + BackendClasses get _backendClasses => _backend.backendClasses; |
| + |
| + void onInstantiatedType(InterfaceType type) { |
| if (_unusedClasses.remove(type.element)) { |
| _registeredClasses.add(type.element); |
| } |
| } |
| - WorldImpact processNativeClasses(Iterable<LibraryElement> libraries) { |
| - WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl(); |
| - _processNativeClasses(impactBuilder, libraries); |
| - return impactBuilder; |
| + /// Register [classes] as natively instantiated in [impactBuilder]. |
| + void _registerTypeUses( |
| + WorldImpactBuilder impactBuilder, Set<ClassElement> classes, cause) { |
| + for (ClassElement cls in classes) { |
| + if (!_unusedClasses.contains(cls)) { |
| + // No need to add [classElement] to [impactBuilder]: it has already been |
| + // instantiated and we don't track origins of native instantiations |
| + // precisely. |
| + continue; |
| + } |
| + cls.ensureResolved(_resolution); |
| + impactBuilder |
| + .registerTypeUse(new TypeUse.nativeInstantiation(cls.rawType)); |
| + } |
| + } |
| + |
| + void registerNativeBehavior( |
| + WorldImpactBuilder impactBuilder, NativeBehavior nativeBehavior, cause) { |
| + _processNativeBehavior(impactBuilder, nativeBehavior, cause); |
| } |
| - void _processNativeClasses( |
| - WorldImpactBuilder impactBuilder, Iterable<LibraryElement> libraries) { |
| - libraries.forEach(processNativeClassesInLibrary); |
| - if (helpers.isolateHelperLibrary != null) { |
| - processNativeClassesInLibrary(helpers.isolateHelperLibrary); |
| + void _processNativeBehavior( |
| + WorldImpactBuilder impactBuilder, NativeBehavior behavior, cause) { |
| + void registerInstantiation(ResolutionInterfaceType type) { |
| + impactBuilder.registerTypeUse(new TypeUse.nativeInstantiation(type)); |
| } |
| - processSubclassesOfNativeClasses(libraries); |
| + |
| + int unusedBefore = _unusedClasses.length; |
| + Set<ClassElement> matchingClasses = new Set<ClassElement>(); |
| + for (var type in behavior.typesInstantiated) { |
| + if (type is SpecialType) { |
| + if (type == SpecialType.JsObject) { |
| + registerInstantiation(_commonElements.objectType); |
| + } |
| + continue; |
| + } |
| + if (type is ResolutionInterfaceType) { |
| + if (type == _commonElements.numType) { |
| + registerInstantiation(_commonElements.doubleType); |
| + registerInstantiation(_commonElements.intType); |
| + } else if (type == _commonElements.intType || |
| + type == _commonElements.doubleType || |
| + type == _commonElements.stringType || |
| + type == _commonElements.nullType || |
| + type == _commonElements.boolType || |
| + type.asInstanceOf(_backendClasses.listClass) != null) { |
| + registerInstantiation(type); |
| + } |
| + // TODO(johnniwinther): Improve spec string precision to handle type |
| + // arguments and implements relations that preserve generics. Currently |
| + // we cannot distinguish between `List`, `List<dynamic>`, and |
| + // `List<int>` and take all to mean `List<E>`; in effect not including |
| + // any native subclasses of generic classes. |
| + // TODO(johnniwinther,sra): Find and replace uses of `List` with the |
| + // actual implementation classes such as `JSArray` et al. |
| + matchingClasses |
| + .addAll(_findUnusedClassesMatching((ClassElement nativeClass) { |
| + ResolutionInterfaceType nativeType = nativeClass.thisType; |
| + ResolutionInterfaceType specType = type.element.thisType; |
| + return _compiler.types.isSubtype(nativeType, specType); |
| + })); |
| + } else if (type.isDynamic) { |
| + matchingClasses.addAll(_unusedClasses); |
| + } else { |
| + assert(type is ResolutionVoidType); |
| + } |
| + } |
| + if (matchingClasses.isNotEmpty && _registeredClasses.isEmpty) { |
| + matchingClasses.addAll(_onFirstNativeClass(impactBuilder)); |
| + } |
| + _registerTypeUses(impactBuilder, matchingClasses, cause); |
| + |
| + // Give an info so that library developers can compile with -v to find why |
| + // all the native classes are included. |
| + if (unusedBefore > 0 && unusedBefore == matchingClasses.length) { |
| + _reporter.log('All native types marked as used due to $cause.'); |
| + } |
| + } |
| + |
| + Iterable<ClassElement> _findUnusedClassesMatching( |
| + bool predicate(classElement)) { |
| + return _unusedClasses.where(predicate); |
| + } |
| + |
| + void _registerBackendUse(FunctionEntity element) {} |
| + |
| + Iterable<ClassElement> _onFirstNativeClass(WorldImpactBuilder impactBuilder) { |
| + void staticUse(FunctionEntity element) { |
| + impactBuilder.registerStaticUse(new StaticUse.implicitInvoke(element)); |
| + _registerBackendUse(element); |
| + } |
| + |
| + staticUse(_helpers.defineProperty); |
| + staticUse(_helpers.toStringForNativeObject); |
| + staticUse(_helpers.hashCodeForNativeObject); |
| + staticUse(_helpers.closureConverter); |
| + return _findNativeExceptions(); |
| + } |
| + |
| + Iterable<ClassElement> _findNativeExceptions() { |
| + return _findUnusedClassesMatching((classElement) { |
| + // TODO(sra): Annotate exception classes in dart:html. |
| + String name = classElement.name; |
| + if (name.contains('Exception')) return true; |
| + if (name.contains('Error')) return true; |
| + return false; |
| + }); |
| + } |
| +} |
| + |
| +class NativeResolutionEnqueuer extends NativeEnqueuerBase { |
| + /// The set of all native classes. Each native class is in [nativeClasses] |
| + /// and exactly one of [unusedClasses] and [registeredClasses]. |
| + final Set<ClassElement> _nativeClasses = new Set<ClassElement>(); |
| + |
| + Map<String, ClassElement> tagOwner = new Map<String, ClassElement>(); |
| + |
| + NativeResolutionEnqueuer(Compiler compiler) |
| + : super(compiler, compiler.options.enableNativeLiveTypeAnalysis); |
| + |
| + BackendUsageBuilder get _backendUsageBuilder => _backend.backendUsageBuilder; |
| + |
| + void _registerBackendUse(FunctionEntity element) { |
| + _backendUsageBuilder.registerBackendFunctionUse(element); |
| + _backendUsageBuilder.registerGlobalFunctionDependency(element); |
| + } |
| + |
| + WorldImpact processNativeClasses(Iterable<LibraryElement> libraries) { |
| + WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl(); |
| + Set<ClassElement> nativeClasses = new Set<ClassElement>(); |
| + libraries.forEach((l) => _processNativeClassesInLibrary(l, nativeClasses)); |
| + if (_helpers.isolateHelperLibrary != null) { |
| + _processNativeClassesInLibrary( |
| + _helpers.isolateHelperLibrary, nativeClasses); |
| + } |
| + _processSubclassesOfNativeClasses(libraries, nativeClasses); |
| + _nativeClasses.addAll(nativeClasses); |
| + _unusedClasses.addAll(nativeClasses); |
| if (!enableLiveTypeAnalysis) { |
| _registerTypeUses(impactBuilder, _nativeClasses, 'forced'); |
| } |
| + return impactBuilder; |
| } |
| - void processNativeClassesInLibrary(LibraryElement library) { |
| + void _processNativeClassesInLibrary( |
| + LibraryElement library, Set<ClassElement> nativeClasses) { |
| // Use implementation to ensure the inclusion of injected members. |
| library.implementation.forEachLocalMember((Element element) { |
| if (element.isClass) { |
| ClassElement cls = element; |
| - if (backend.nativeBasicData.isNativeClass(cls)) { |
| - processNativeClass(element); |
| + if (_nativeBasicData.isNativeClass(cls)) { |
| + _processNativeClass(element, nativeClasses); |
| } |
| } |
| }); |
| } |
| - void processNativeClass(ClassElement classElement) { |
| - _nativeClasses.add(classElement); |
| - _unusedClasses.add(classElement); |
| + void _processNativeClass( |
| + ClassElement classElement, Set<ClassElement> nativeClasses) { |
| + nativeClasses.add(classElement); |
| // Resolve class to ensure the class has valid inheritance info. |
| - classElement.ensureResolved(resolution); |
| + classElement.ensureResolved(_resolution); |
| + // Js Interop interfaces do not have tags. |
| + if (_nativeBasicData.isJsInteropClass(classElement)) return; |
| + // Since we map from dispatch tags to classes, a dispatch tag must be used |
| + // on only one native class. |
| + for (String tag in _nativeBasicData.getNativeTagsOfClass(classElement)) { |
| + ClassElement owner = tagOwner[tag]; |
| + if (owner != null) { |
| + if (owner != classElement) { |
| + _reporter.internalError( |
| + classElement, "Tag '$tag' already in use by '${owner.name}'"); |
| + } |
| + } else { |
| + tagOwner[tag] = classElement; |
| + } |
| + } |
| } |
| - void processSubclassesOfNativeClasses(Iterable<LibraryElement> libraries) { |
| + void _processSubclassesOfNativeClasses( |
| + Iterable<LibraryElement> libraries, Set<ClassElement> nativeClasses) { |
| + Set<ClassElement> nativeClassesAndSubclasses = new Set<ClassElement>(); |
| // Collect potential subclasses, e.g. |
| // |
| // class B extends foo.A {} |
| @@ -130,7 +269,7 @@ abstract class NativeEnqueuerBase implements NativeEnqueuer { |
| libraries.forEach((library) { |
| library.implementation.forEachLocalMember((element) { |
| if (element.isClass) { |
| - String extendsName = findExtendsNameOfClass(element); |
| + String extendsName = _findExtendsNameOfClass(element); |
| if (extendsName != null) { |
| Set<ClassElement> potentialSubclasses = potentialExtends |
| .putIfAbsent(extendsName, () => new Set<ClassElement>()); |
| @@ -145,15 +284,14 @@ abstract class NativeEnqueuerBase implements NativeEnqueuer { |
| // fact a subclass of a native class. |
| ClassElement nativeSuperclassOf(ClassElement classElement) { |
| - if (backend.nativeBasicData.isNativeClass(classElement)) |
| - return classElement; |
| + if (_nativeBasicData.isNativeClass(classElement)) return classElement; |
| if (classElement.superclass == null) return null; |
| return nativeSuperclassOf(classElement.superclass); |
| } |
| void walkPotentialSubclasses(ClassElement element) { |
| if (nativeClassesAndSubclasses.contains(element)) return; |
| - element.ensureResolved(resolution); |
| + element.ensureResolved(_resolution); |
| ClassElement nativeSuperclass = nativeSuperclassOf(element); |
| if (nativeSuperclass != null) { |
| nativeClassesAndSubclasses.add(element); |
| @@ -164,17 +302,15 @@ abstract class NativeEnqueuerBase implements NativeEnqueuer { |
| } |
| } |
| - _nativeClasses.forEach(walkPotentialSubclasses); |
| - |
| - _nativeClasses.addAll(nativeClassesAndSubclasses); |
| - _unusedClasses.addAll(nativeClassesAndSubclasses); |
| + nativeClasses.forEach(walkPotentialSubclasses); |
| + nativeClasses.addAll(nativeClassesAndSubclasses); |
| } |
| /** |
| * Returns the source string of the class named in the extends clause, or |
| * `null` if there is no extends clause. |
| */ |
| - String findExtendsNameOfClass(ClassElement classElement) { |
| + String _findExtendsNameOfClass(ClassElement classElement) { |
| if (classElement.isResolved) { |
| ClassElement superClass = classElement.superclass; |
| while (superClass != null) { |
| @@ -235,155 +371,11 @@ abstract class NativeEnqueuerBase implements NativeEnqueuer { |
| return id.lexeme; |
| } |
| - return reporter.withCurrentElement(classElement, () { |
| + return _reporter.withCurrentElement(classElement, () { |
| return scanForExtendsName(classElement.position); |
| }); |
| } |
| - /// Register [classes] as natively instantiated in [impactBuilder]. |
| - void _registerTypeUses( |
| - WorldImpactBuilder impactBuilder, Set<ClassElement> classes, cause) { |
| - for (ClassElement cls in classes) { |
| - if (!_unusedClasses.contains(cls)) { |
| - // No need to add [classElement] to [impactBuilder]: it has already been |
| - // instantiated and we don't track origins of native instantiations |
| - // precisely. |
| - continue; |
| - } |
| - cls.ensureResolved(resolution); |
| - impactBuilder |
| - .registerTypeUse(new TypeUse.nativeInstantiation(cls.rawType)); |
| - } |
| - } |
| - |
| - void registerNativeBehavior( |
| - WorldImpactBuilder impactBuilder, NativeBehavior nativeBehavior, cause) { |
| - _processNativeBehavior(impactBuilder, nativeBehavior, cause); |
| - } |
| - |
| - void _processNativeBehavior( |
| - WorldImpactBuilder impactBuilder, NativeBehavior behavior, cause) { |
| - void registerInstantiation(ResolutionInterfaceType type) { |
| - impactBuilder.registerTypeUse(new TypeUse.nativeInstantiation(type)); |
| - } |
| - |
| - int unusedBefore = _unusedClasses.length; |
| - Set<ClassElement> matchingClasses = new Set<ClassElement>(); |
| - for (var type in behavior.typesInstantiated) { |
| - if (type is SpecialType) { |
| - if (type == SpecialType.JsObject) { |
| - registerInstantiation(compiler.commonElements.objectType); |
| - } |
| - continue; |
| - } |
| - if (type is ResolutionInterfaceType) { |
| - if (type == commonElements.numType) { |
| - registerInstantiation(commonElements.doubleType); |
| - registerInstantiation(commonElements.intType); |
| - } else if (type == commonElements.intType || |
| - type == commonElements.doubleType || |
| - type == commonElements.stringType || |
| - type == commonElements.nullType || |
| - type == commonElements.boolType || |
| - type.asInstanceOf(backend.backendClasses.listClass) != null) { |
| - registerInstantiation(type); |
| - } |
| - // TODO(johnniwinther): Improve spec string precision to handle type |
| - // arguments and implements relations that preserve generics. Currently |
| - // we cannot distinguish between `List`, `List<dynamic>`, and |
| - // `List<int>` and take all to mean `List<E>`; in effect not including |
| - // any native subclasses of generic classes. |
| - // TODO(johnniwinther,sra): Find and replace uses of `List` with the |
| - // actual implementation classes such as `JSArray` et al. |
| - matchingClasses |
| - .addAll(_findUnusedClassesMatching((ClassElement nativeClass) { |
| - ResolutionInterfaceType nativeType = nativeClass.thisType; |
| - ResolutionInterfaceType specType = type.element.thisType; |
| - return compiler.types.isSubtype(nativeType, specType); |
| - })); |
| - } else if (type.isDynamic) { |
| - matchingClasses.addAll(_unusedClasses); |
| - } else { |
| - assert(type is ResolutionVoidType); |
| - } |
| - } |
| - if (matchingClasses.isNotEmpty && _registeredClasses.isEmpty) { |
| - matchingClasses.addAll(_onFirstNativeClass(impactBuilder)); |
| - } |
| - _registerTypeUses(impactBuilder, matchingClasses, cause); |
| - |
| - // Give an info so that library developers can compile with -v to find why |
| - // all the native classes are included. |
| - if (unusedBefore > 0 && unusedBefore == matchingClasses.length) { |
| - reporter.log('All native types marked as used due to $cause.'); |
| - } |
| - } |
| - |
| - Iterable<ClassElement> _findUnusedClassesMatching( |
| - bool predicate(classElement)) { |
| - return _unusedClasses.where(predicate); |
| - } |
| - |
| - void registerBackendUse(MethodElement element) {} |
| - |
| - Iterable<ClassElement> _onFirstNativeClass(WorldImpactBuilder impactBuilder) { |
| - void staticUse(MethodElement element) { |
| - impactBuilder.registerStaticUse(new StaticUse.implicitInvoke(element)); |
| - registerBackendUse(element); |
| - } |
| - |
| - staticUse(helpers.defineProperty); |
| - staticUse(helpers.toStringForNativeObject); |
| - staticUse(helpers.hashCodeForNativeObject); |
| - staticUse(helpers.closureConverter); |
| - return _findNativeExceptions(); |
| - } |
| - |
| - Iterable<ClassElement> _findNativeExceptions() { |
| - return _findUnusedClassesMatching((classElement) { |
| - // TODO(sra): Annotate exception classes in dart:html. |
| - String name = classElement.name; |
| - if (name.contains('Exception')) return true; |
| - if (name.contains('Error')) return true; |
| - return false; |
| - }); |
| - } |
| -} |
| - |
| -class NativeResolutionEnqueuer extends NativeEnqueuerBase { |
| - Map<String, ClassElement> tagOwner = new Map<String, ClassElement>(); |
| - |
| - NativeResolutionEnqueuer(Compiler compiler) |
| - : super(compiler, compiler.options.enableNativeLiveTypeAnalysis); |
| - |
| - BackendUsageBuilder get _backendUsageBuilder => backend.backendUsageBuilder; |
| - |
| - void registerBackendUse(MethodElement element) { |
| - _backendUsageBuilder.registerBackendFunctionUse(element); |
| - _backendUsageBuilder.registerGlobalFunctionDependency(element); |
| - } |
| - |
| - void processNativeClass(ClassElement classElement) { |
| - super.processNativeClass(classElement); |
| - |
| - // Js Interop interfaces do not have tags. |
| - if (backend.nativeBasicData.isJsInteropClass(classElement)) return; |
| - // Since we map from dispatch tags to classes, a dispatch tag must be used |
| - // on only one native class. |
| - for (String tag |
| - in backend.nativeBasicData.getNativeTagsOfClass(classElement)) { |
| - ClassElement owner = tagOwner[tag]; |
| - if (owner != null) { |
| - if (owner != classElement) { |
| - reporter.internalError( |
| - classElement, "Tag '$tag' already in use by '${owner.name}'"); |
| - } |
| - } else { |
| - tagOwner[tag] = classElement; |
| - } |
| - } |
| - } |
| - |
| void logSummary(log(message)) { |
| log('Resolved ${_registeredClasses.length} native elements used, ' |
| '${_unusedClasses.length} native elements dead.'); |
| @@ -399,11 +391,18 @@ class NativeCodegenEnqueuer extends NativeEnqueuerBase { |
| NativeCodegenEnqueuer( |
| Compiler compiler, this.emitter, this._resolutionEnqueuer) |
| - : super(compiler, compiler.options.enableNativeLiveTypeAnalysis); |
| + : super(compiler, compiler.options.enableNativeLiveTypeAnalysis) {} |
| + |
| + NativeData get _nativeData => _backend.nativeData; |
| + |
| + WorldImpact processNativeClasses(Iterable<LibraryElement> libraries) { |
| + WorldImpactBuilderImpl impactBuilder = new WorldImpactBuilderImpl(); |
| + _unusedClasses.addAll(_resolutionEnqueuer._nativeClasses); |
| - void _processNativeClasses( |
| - WorldImpactBuilder impactBuilder, Iterable<LibraryElement> libraries) { |
| - super._processNativeClasses(impactBuilder, libraries); |
| + if (!enableLiveTypeAnalysis) { |
| + _registerTypeUses( |
| + impactBuilder, _resolutionEnqueuer._nativeClasses, 'forced'); |
| + } |
| // HACK HACK - add all the resolved classes. |
| Set<ClassElement> matchingClasses = new Set<ClassElement>(); |
| @@ -416,6 +415,7 @@ class NativeCodegenEnqueuer extends NativeEnqueuerBase { |
| matchingClasses.addAll(_onFirstNativeClass(impactBuilder)); |
| } |
| _registerTypeUses(impactBuilder, matchingClasses, 'was resolved'); |
| + return impactBuilder; |
| } |
| void _registerTypeUses( |
| @@ -430,7 +430,7 @@ class NativeCodegenEnqueuer extends NativeEnqueuerBase { |
| } |
| void _addSubtypes(ClassElement cls, NativeEmitter emitter) { |
| - if (!backend.nativeData.isNativeClass(cls)) return; |
| + if (!_nativeData.isNativeClass(cls)) return; |
| if (doneAddSubtypes.contains(cls)) return; |
| doneAddSubtypes.add(cls); |
| @@ -449,7 +449,7 @@ class NativeCodegenEnqueuer extends NativeEnqueuerBase { |
| // natives classes. |
| ClassElement superclass = cls.superclass; |
| while (superclass != null && superclass.isMixinApplication) { |
| - assert(!backend.nativeData.isNativeClass(superclass)); |
| + assert(!_nativeData.isNativeClass(superclass)); |
| superclass = superclass.superclass; |
| } |