blob: c8ad56847c9f8cc5c42f0d712ce987ff67bed5d9 [file] [log] [blame]
// Copyright (c) 2013, 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.
part of universe;
class FullFunctionSet extends FunctionSet {
FullFunctionSet(Compiler compiler) : super(compiler);
FunctionSetNode newNode(SourceString name)
=> new FullFunctionSetNode(name);
}
class FullFunctionSetNode extends FunctionSetNode {
// To cut down on the time we spend on computing type information
// about the function holders, we limit the number of classes and
// the number of steps it takes to compute them.
static const int MAX_CLASSES = 4;
static const int MAX_CLASSES_STEPS = 32;
FullFunctionSetNode(SourceString name) : super(name);
FunctionSetQuery newQuery(List<Element> functions,
Selector selector,
Compiler compiler) {
List<ClassElement> classes = computeClasses(functions, compiler);
bool isExact = selector.hasExactMask || isExactClass(classes, compiler);
return new FullFunctionSetQuery(functions, classes, isExact);
}
static List<ClassElement> computeClasses(List<Element> functions,
Compiler compiler) {
// TODO(kasperl): Check if any of the found classes may have a
// non-throwing noSuchMethod implementation in a subclass instead
// of always disabling the class list computation.
if (compiler.enabledNoSuchMethod) return null;
List<ClassElement> classes = <ClassElement>[];
int budget = MAX_CLASSES_STEPS;
L: for (Element element in functions) {
ClassElement enclosing = element.getEnclosingClass();
for (int i = 0; i < classes.length; i++) {
if (--budget <= 0) {
return null;
} else if (enclosing.isSubclassOf(classes[i])) {
continue L;
} else if (classes[i].isSubclassOf(enclosing)) {
classes[i] = enclosing;
continue L;
}
}
if (classes.length >= MAX_CLASSES) return null;
classes.add(enclosing);
}
return classes;
}
static bool isExactClass(List<ClassElement> classes, Compiler compiler) {
if (classes == null || classes.length != 1) return false;
ClassElement single = classes[0];
// Return true if the single class in our list does not have a
// single instantiated subclass.
Set<ClassElement> subtypes = compiler.world.subtypes[single];
return subtypes == null
|| subtypes.every((ClassElement each) => !each.isSubclassOf(single));
}
}
class FullFunctionSetQuery extends FunctionSetQuery {
final List<ClassElement> classes;
final bool isExact;
FullFunctionSetQuery(List<Element> functions, this.classes, this.isExact)
: super(functions);
}