blob: 6f979fd9d88eda79fb61b650ab4293330b41ccbe [file] [log] [blame]
// 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);
}
}