Index: pkg/compiler/lib/src/world.dart |
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart |
index 87090deb797ef77020dc2caf090676d0e593a610..6ce4b16ccc34c0a5acaba7ce20bacf790ea1591e 100644 |
--- a/pkg/compiler/lib/src/world.dart |
+++ b/pkg/compiler/lib/src/world.dart |
@@ -19,7 +19,7 @@ import 'elements/elements.dart' |
TypedefElement, |
VariableElement; |
import 'ordered_typeset.dart'; |
-import 'types/masks.dart' show TypeMask, FlatTypeMask; |
+import 'types/masks.dart' show CommonMasks, FlatTypeMask, TypeMask; |
import 'universe/class_set.dart'; |
import 'universe/function_set.dart' show FunctionSet; |
import 'universe/selector.dart' show Selector; |
@@ -38,30 +38,7 @@ abstract class ClassWorld { |
// TODO(johnniwinther): Refine this into a `BackendClasses` interface. |
Backend get backend; |
- // TODO(johnniwinther): Remove the need for this getter. |
- @deprecated |
- Compiler get compiler; |
- |
- /// The [ClassElement] for the [Object] class defined in 'dart:core'. |
- ClassElement get objectClass; |
- |
- /// The [ClassElement] for the [Function] class defined in 'dart:core'. |
- ClassElement get functionClass; |
- |
- /// The [ClassElement] for the [bool] class defined in 'dart:core'. |
- ClassElement get boolClass; |
- |
- /// The [ClassElement] for the [num] class defined in 'dart:core'. |
- ClassElement get numClass; |
- |
- /// The [ClassElement] for the [int] class defined in 'dart:core'. |
- ClassElement get intClass; |
- |
- /// The [ClassElement] for the [double] class defined in 'dart:core'. |
- ClassElement get doubleClass; |
- |
- /// The [ClassElement] for the [String] class defined in 'dart:core'. |
- ClassElement get stringClass; |
+ CoreClasses get coreClasses; |
/// Returns `true` if [cls] is either directly or indirectly instantiated. |
bool isInstantiated(ClassElement cls); |
@@ -185,18 +162,98 @@ abstract class ClassWorld { |
/// |
/// If [cls] is provided, the dump will contain only classes related to [cls]. |
String dump([ClassElement cls]); |
+ |
+ /// Returns [ClassHierarchyNode] for [cls] used to model the class hierarchies |
+ /// of known classes. |
+ /// |
+ /// This method is only provided for testing. For queries on classes, use the |
+ /// methods defined in [ClassWorld]. |
+ ClassHierarchyNode getClassHierarchyNode(ClassElement cls); |
+} |
+ |
+/// The [ClosedWorld] represents the information known about a program when |
+/// compiling with closed-world semantics. |
+/// |
+/// This expands [ClassWorld] with information about live functions, |
+/// side effects, and selectors with known single targets. |
+abstract class ClosedWorld extends ClassWorld { |
+ /// Returns the [FunctionSet] containing all live functions in the closed |
+ /// world. |
+ FunctionSet get allFunctions; |
+ |
+ /// Returns `true` if the field [element] is known to be effectively final. |
+ bool fieldNeverChanges(Element element); |
+ |
+ /// Extends the receiver type [mask] for calling [selector] to take live |
+ /// `noSuchMethod` handlers into account. |
+ TypeMask extendMaskIfReachesAll(Selector selector, TypeMask mask); |
+ |
+ /// Returns all resolved typedefs. |
+ Iterable<TypedefElement> get allTypedefs; |
+ |
+ /// Returns the single [Element] that matches a call to [selector] on a |
+ /// receiver of type [mask]. If multiple targets exist, `null` is returned. |
+ Element locateSingleElement(Selector selector, TypeMask mask); |
+ |
+ /// Returns the single field that matches a call to [selector] on a |
+ /// receiver of type [mask]. If multiple targets exist or the single target |
+ /// is not a field, `null` is returned. |
+ VariableElement locateSingleField(Selector selector, TypeMask mask); |
+ |
+ /// Returns the side effects of executing [element]. |
+ SideEffects getSideEffectsOfElement(Element element); |
+ |
+ /// Returns the side effects of calling [selector] on a receiver of type |
+ /// [mask]. |
+ SideEffects getSideEffectsOfSelector(Selector selector, TypeMask mask); |
+ |
+ /// Returns `true` if [element] is guaranteed not to throw an exception. |
+ bool getCannotThrow(Element element); |
+ |
+ /// Returns `true` if [element] is called in a loop. |
+ // TODO(johnniwinther): Is this 'potentially called' or 'known to be called'? |
+ bool isCalledInLoop(Element element); |
+ |
+ /// Returns `true` if [element] might be passed to `Function.apply`. |
+ // TODO(johnniwinther): Is this 'passed invocation target` or |
+ // `passed as argument`? |
+ bool getMightBePassedToApply(Element element); |
} |
-class World implements ClassWorld { |
- ClassElement get objectClass => coreClasses.objectClass; |
- ClassElement get functionClass => coreClasses.functionClass; |
- ClassElement get boolClass => coreClasses.boolClass; |
- ClassElement get numClass => coreClasses.numClass; |
- ClassElement get intClass => coreClasses.intClass; |
- ClassElement get doubleClass => coreClasses.doubleClass; |
- ClassElement get stringClass => coreClasses.stringClass; |
- ClassElement get nullClass => coreClasses.nullClass; |
+/// Interface for computing side effects and uses of elements. This is used |
+/// during type inference to compute the [ClosedWorld] for code generation. |
+abstract class ClosedWorldRefiner { |
+ /// Registers the side [effects] of executing [element]. |
+ void registerSideEffects(Element element, SideEffects effects); |
+ /// Registers the executing of [element] as without side effects. |
+ void registerSideEffectsFree(Element element); |
+ |
+ /// Returns the currently known side effects of executing [element]. |
+ SideEffects getCurrentlyKnownSideEffects(Element element); |
+ |
+ /// Registers that [element] might be passed to `Function.apply`. |
+ // TODO(johnniwinther): Is this 'passed invocation target` or |
+ // `passed as argument`? |
+ void registerMightBePassedToApply(Element element); |
+ |
+ /// Returns `true` if [element] might be passed to `Function.apply` given the |
+ /// currently inferred information. |
+ bool getCurrentlyKnownMightBePassedToApply(Element element); |
+ |
+ /// Registers that [element] is called in a loop. |
+ // TODO(johnniwinther): Is this 'potentially called' or 'known to be called'? |
+ void addFunctionCalledInLoop(Element element); |
+ |
+ /// Registers that [element] is guaranteed not to throw an exception. |
+ void registerCannotThrow(Element element); |
+ |
+ /// Adds the closure class [cls] to the inference world. The class is |
+ /// considered directly instantiated. |
+ void registerClosureClass(ClassElement cls); |
+} |
+ |
+class World implements ClosedWorld, ClosedWorldRefiner { |
/// Cache of [FlatTypeMask]s grouped by the 8 possible values of the |
/// `FlatTypeMask.flags` property. |
List<Map<ClassElement, TypeMask>> canonicalizedTypeMasks = |
@@ -221,10 +278,10 @@ class World implements ClassWorld { |
assert(checkInvariants(x)); |
assert(checkInvariants(y, mustBeInstantiated: false)); |
- if (y == objectClass) return true; |
- if (x == objectClass) return false; |
+ if (y == coreClasses.objectClass) return true; |
+ if (x == coreClasses.objectClass) return false; |
if (x.asInstanceOf(y) != null) return true; |
- if (y != functionClass) return false; |
+ if (y != coreClasses.functionClass) return false; |
return x.callType != null; |
} |
@@ -233,8 +290,8 @@ class World implements ClassWorld { |
assert(checkInvariants(x)); |
assert(checkInvariants(y)); |
- if (y == objectClass) return true; |
- if (x == objectClass) return false; |
+ if (y == coreClasses.objectClass) return true; |
+ if (x == coreClasses.objectClass) return false; |
while (x != null && x.hierarchyDepth >= y.hierarchyDepth) { |
if (x == y) return true; |
x = x.superclass; |
@@ -262,7 +319,7 @@ class World implements ClassWorld { |
/// Returns `true` if [cls] is implemented by an instantiated class. |
bool isImplemented(ClassElement cls) { |
- return compiler.resolverWorld.isImplemented(cls); |
+ return _compiler.resolverWorld.isImplemented(cls); |
} |
/// Returns an iterable over the directly instantiated classes that extend |
@@ -394,7 +451,7 @@ class World implements ClassWorld { |
/// extend it. |
bool hasOnlySubclasses(ClassElement cls) { |
// TODO(johnniwinther): move this to ClassSet? |
- if (cls == objectClass) return true; |
+ if (cls == coreClasses.objectClass) return true; |
ClassSet classSet = _classSets[cls.declaration]; |
if (classSet == null) { |
// Vacuously true. |
@@ -442,7 +499,7 @@ class World implements ClassWorld { |
List<ClassElement> commonSupertypes = <ClassElement>[]; |
OUTER: |
for (Link<DartType> link = typeSet[depth]; |
- link.head.element != objectClass; |
+ link.head.element != coreClasses.objectClass; |
link = link.tail) { |
ClassElement cls = link.head.element; |
for (Link<OrderedTypeSet> link = otherTypeSets; |
@@ -454,7 +511,7 @@ class World implements ClassWorld { |
} |
commonSupertypes.add(cls); |
} |
- commonSupertypes.add(objectClass); |
+ commonSupertypes.add(coreClasses.objectClass); |
return commonSupertypes; |
} |
@@ -547,8 +604,9 @@ class World implements ClassWorld { |
return subclasses.contains(type); |
} |
- final Compiler compiler; |
- Backend get backend => compiler.backend; |
+ final Compiler _compiler; |
+ Backend get backend => _compiler.backend; |
+ CommonMasks get commonMasks => _compiler.commonMasks; |
final FunctionSet allFunctions; |
final Set<Element> functionsCalledInLoop = new Set<Element>(); |
final Map<Element, SideEffects> sideEffects = new Map<Element, SideEffects>(); |
@@ -580,11 +638,11 @@ class World implements ClassWorld { |
final Set<Element> alreadyPopulated; |
- bool get isClosed => compiler.phase > Compiler.PHASE_RESOLVING; |
+ bool get isClosed => _compiler.phase > Compiler.PHASE_RESOLVING; |
// Used by selectors. |
bool isForeign(Element element) { |
- return compiler.backend.isForeign(element); |
+ return backend.isForeign(element); |
} |
Set<ClassElement> typesImplementedBySubclassesOf(ClassElement cls) { |
@@ -593,18 +651,24 @@ class World implements ClassWorld { |
World(Compiler compiler) |
: allFunctions = new FunctionSet(compiler), |
- this.compiler = compiler, |
+ this._compiler = compiler, |
alreadyPopulated = compiler.cacheStrategy.newSet(); |
- CoreClasses get coreClasses => compiler.coreClasses; |
+ CoreClasses get coreClasses => _compiler.coreClasses; |
- DiagnosticReporter get reporter => compiler.reporter; |
+ DiagnosticReporter get reporter => _compiler.reporter; |
/// Called to add [cls] to the set of known classes. |
/// |
/// This ensures that class hierarchy queries can be performed on [cls] and |
/// classes that extend or implement it. |
- void registerClass(ClassElement cls, {bool isDirectlyInstantiated: false}) { |
+ void registerClass(ClassElement cls) => _registerClass(cls); |
+ |
+ void registerClosureClass(ClassElement cls) { |
+ _registerClass(cls, isDirectlyInstantiated: true); |
+ } |
+ |
+ void _registerClass(ClassElement cls, {bool isDirectlyInstantiated: false}) { |
_ensureClassSet(cls); |
if (isDirectlyInstantiated) { |
_updateClassHierarchyNodeForClass(cls, directlyInstantiated: true); |
@@ -693,7 +757,7 @@ class World implements ClassWorld { |
/// properties of the [ClassHierarchyNode] for [cls]. |
void addSubtypes(ClassElement cls) { |
- if (compiler.options.hasIncrementalSupport && |
+ if (_compiler.options.hasIncrementalSupport && |
!alreadyPopulated.add(cls)) { |
return; |
} |
@@ -722,7 +786,7 @@ class World implements ClassWorld { |
// classes: if the superclass of these classes require RTI, then |
// they also need RTI, so that a constructor passes the type |
// variables to the super constructor. |
- compiler.resolverWorld.directlyInstantiatedClasses.forEach(addSubtypes); |
+ _compiler.resolverWorld.directlyInstantiatedClasses.forEach(addSubtypes); |
} |
@override |
@@ -764,17 +828,17 @@ class World implements ClassWorld { |
} |
Element locateSingleElement(Selector selector, TypeMask mask) { |
- mask ??= compiler.commonMasks.dynamicType; |
- return mask.locateSingleElement(selector, compiler); |
+ mask ??= commonMasks.dynamicType; |
+ return mask.locateSingleElement(selector, _compiler); |
} |
TypeMask extendMaskIfReachesAll(Selector selector, TypeMask mask) { |
bool canReachAll = true; |
if (mask != null) { |
- canReachAll = compiler.enabledInvokeOn && |
+ canReachAll = _compiler.enabledInvokeOn && |
mask.needsNoSuchMethodHandling(selector, this); |
} |
- return canReachAll ? compiler.commonMasks.dynamicType : mask; |
+ return canReachAll ? commonMasks.dynamicType : mask; |
} |
void addFunctionCalledInLoop(Element element) { |
@@ -799,8 +863,8 @@ class World implements ClassWorld { |
return true; |
} |
if (element.isInstanceMember) { |
- return !compiler.resolverWorld.hasInvokedSetter(element, this) && |
- !compiler.resolverWorld.fieldSetters.contains(element); |
+ return !_compiler.resolverWorld.hasInvokedSetter(element, this) && |
+ !_compiler.resolverWorld.fieldSetters.contains(element); |
} |
return false; |
} |
@@ -819,6 +883,11 @@ class World implements ClassWorld { |
}); |
} |
+ @override |
+ SideEffects getCurrentlyKnownSideEffects(Element element) { |
+ return getSideEffectsOfElement(element); |
+ } |
+ |
void registerSideEffects(Element element, SideEffects effects) { |
if (sideEffectsFreeElements.contains(element)) return; |
sideEffects[element.declaration] = effects; |
@@ -878,5 +947,10 @@ class World implements ClassWorld { |
return functionsThatMightBePassedToApply.contains(element); |
} |
- bool get hasClosedWorldAssumption => !compiler.options.hasIncrementalSupport; |
+ @override |
+ bool getCurrentlyKnownMightBePassedToApply(Element element) { |
+ return getMightBePassedToApply(element); |
+ } |
+ |
+ bool get hasClosedWorldAssumption => !_compiler.options.hasIncrementalSupport; |
} |