| // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| // 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. |
| |
| library dart2js.js_emitter.type_test_registry; |
| |
| import '../common.dart'; |
| import '../common_elements.dart'; |
| import '../elements/entities.dart'; |
| import '../elements/types.dart'; |
| import '../js_backend/runtime_types.dart' |
| show |
| RuntimeTypesChecks, |
| RuntimeTypesChecksBuilder, |
| RuntimeTypesSubstitutions; |
| import '../js_backend/mirrors_data.dart'; |
| import '../options.dart'; |
| import '../universe/world_builder.dart'; |
| import '../world.dart' show ClosedWorld; |
| |
| class TypeTestRegistry { |
| final ElementEnvironment _elementEnvironment; |
| |
| /// After [computeNeededClasses] this set only contains classes that are only |
| /// used for RTI. |
| Set<ClassEntity> _rtiNeededClasses; |
| |
| final CompilerOptions _options; |
| final CodegenWorldBuilder _codegenWorldBuilder; |
| final ClosedWorld _closedWorld; |
| |
| RuntimeTypesChecks _rtiChecks; |
| |
| TypeTestRegistry(this._options, this._codegenWorldBuilder, this._closedWorld, |
| this._elementEnvironment); |
| |
| RuntimeTypesChecks get rtiChecks { |
| assert( |
| _rtiChecks != null, |
| failedAt(NO_LOCATION_SPANNABLE, |
| "RuntimeTypesChecks has not been computed yet.")); |
| return _rtiChecks; |
| } |
| |
| Iterable<ClassEntity> get rtiNeededClasses { |
| assert( |
| _rtiNeededClasses != null, |
| failedAt(NO_LOCATION_SPANNABLE, |
| "rtiNeededClasses has not been computed yet.")); |
| return _rtiNeededClasses; |
| } |
| |
| void computeRtiNeededClasses(RuntimeTypesSubstitutions rtiSubstitutions, |
| MirrorsData mirrorsData, Iterable<MemberEntity> liveMembers) { |
| _rtiNeededClasses = new Set<ClassEntity>(); |
| |
| void addClassWithSuperclasses(ClassEntity cls) { |
| _rtiNeededClasses.add(cls); |
| for (ClassEntity superclass = _elementEnvironment.getSuperClass(cls); |
| superclass != null; |
| superclass = _elementEnvironment.getSuperClass(superclass)) { |
| _rtiNeededClasses.add(superclass); |
| } |
| } |
| |
| void addClassesWithSuperclasses(Iterable<ClassEntity> classes) { |
| for (ClassEntity cls in classes) { |
| addClassWithSuperclasses(cls); |
| } |
| } |
| |
| // 1. Add classes that are referenced by type arguments or substitutions in |
| // argument checks. |
| addClassesWithSuperclasses(rtiChecks.requiredClasses); |
| |
| bool canTearOff(MemberEntity function) { |
| if (!function.isFunction || |
| function.isConstructor || |
| function.isGetter || |
| function.isSetter) { |
| return false; |
| } else if (function.isInstanceMember) { |
| if (!function.enclosingClass.isClosure) { |
| return _codegenWorldBuilder.hasInvokedGetter(function, _closedWorld); |
| } |
| } |
| return false; |
| } |
| |
| bool canBeReflectedAsFunction(MemberEntity element) { |
| return !element.isField; |
| } |
| |
| bool canBeReified(MemberEntity element) { |
| return (canTearOff(element) || |
| mirrorsData.isMemberAccessibleByReflection(element)); |
| } |
| |
| // 2. Find all types referenced from the types of elements that can be |
| // reflected on 'as functions'. |
| liveMembers.where((MemberEntity element) { |
| return canBeReflectedAsFunction(element) && canBeReified(element); |
| }).forEach((_function) { |
| FunctionEntity function = _function; |
| FunctionType type = _elementEnvironment.getFunctionType(function); |
| for (ClassEntity cls in _rtiChecks.getReferencedClasses(type)) { |
| while (cls != null) { |
| _rtiNeededClasses.add(cls); |
| cls = _elementEnvironment.getSuperClass(cls); |
| } |
| } |
| }); |
| } |
| |
| void computeRequiredTypeChecks(RuntimeTypesChecksBuilder rtiChecksBuilder) { |
| _rtiChecks = rtiChecksBuilder.computeRequiredChecks(_codegenWorldBuilder, |
| strongMode: _options.strongMode); |
| } |
| } |