Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(294)

Unified Diff: pkg/compiler/lib/src/js_backend/backend.dart

Issue 962703004: Add "force inline" to internal annotations. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address comments. Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | pkg/compiler/lib/src/ssa/builder.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/js_backend/backend.dart
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index 0723cd1beec8f57bc926737cfc713882f56527ef..1ed077da32f754dbdefa76b2a66c7b3bbd76fb52 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -26,39 +26,184 @@ abstract class FunctionCompiler {
* !canInline(function, insideLoop: true) implies !canInline(function)
*/
class FunctionInlineCache {
- final Map<FunctionElement, bool> canBeInlined =
- new Map<FunctionElement, bool>();
+ static const int _unknown = -1;
+ static const int _mustNotInline = 0;
+ // May-inline-in-loop means that the function may not be inlined outside loops
+ // but may be inlined in a loop.
+ static const int _mayInlineInLoopMustNotOutside = 1;
+ // The function can be inlined in a loop, but not outside.
+ static const int _canInlineInLoopMustNotOutside = 2;
+ // May-inline means that we know that it can be inlined inside a loop, but
+ // don't know about the general case yet.
+ static const int _canInlineInLoopMayInlineOutside = 3;
+ static const int _canInline = 4;
+ static const int _mustInline = 5;
+
+ final Map<FunctionElement, int> _cachedDecisions =
+ new Map<FunctionElement, int>();
+
+ // Returns `true`/`false` if we have a cached decision.
+ // Returns `null` otherwise.
+ bool canInline(FunctionElement element, {bool insideLoop}) {
+ int decision = _cachedDecisions[element];
- final Map<FunctionElement, bool> canBeInlinedInsideLoop =
- new Map<FunctionElement, bool>();
+ if (decision == null) {
+ decision = _unknown;
+ }
- // Returns [:true:]/[:false:] if we have a cached decision.
- // Returns [:null:] otherwise.
- bool canInline(FunctionElement element, {bool insideLoop}) {
- return insideLoop ? canBeInlinedInsideLoop[element] : canBeInlined[element];
+ if (insideLoop) {
+ switch (decision) {
+ case _mustNotInline:
+ return false;
+
+ case _unknown:
+ case _mayInlineInLoopMustNotOutside:
+ // We know we can't inline outside a loop, but don't know for the
+ // loop case. Return `null` to indicate that we don't know yet.
+ return null;
+
+ case _canInlineInLoopMustNotOutside:
+ case _canInlineInLoopMayInlineOutside:
+ case _canInline:
+ case _mustInline:
+ return true;
+ }
+ } else {
+ switch (decision) {
+ case _mustNotInline:
+ case _mayInlineInLoopMustNotOutside:
+ case _canInlineInLoopMustNotOutside:
+ return false;
+
+ case _unknown:
+ case _canInlineInLoopMayInlineOutside:
+ // We know we can inline inside a loop, but don't know for the
+ // non-loop case. Return `null` to indicate that we don't know yet.
+ return null;
+
+ case _canInline:
+ case _mustInline:
+ return true;
+ }
+ }
+
+ // Quiet static checker.
+ return null;
}
void markAsInlinable(FunctionElement element, {bool insideLoop}) {
+ int oldDecision = _cachedDecisions[element];
+
+ if (oldDecision == null) {
+ oldDecision = _unknown;
+ }
+
if (insideLoop) {
- canBeInlinedInsideLoop[element] = true;
+ switch (oldDecision) {
+ case _mustNotInline:
+ throw new SpannableAssertionFailure(element,
+ "Can't mark a function as non-inlinable and inlinable at the "
+ "same time.");
+
+ case _unknown:
+ // We know that it can be inlined in a loop, but don't know about the
+ // non-loop case yet.
+ _cachedDecisions[element] = _canInlineInLoopMayInlineOutside;
+ break;
+
+ case _mayInlineInLoopMustNotOutside:
+ _cachedDecisions[element] = _canInlineInLoopMustNotOutside;
+ break;
+
+ case _canInlineInLoopMustNotOutside:
+ case _canInlineInLoopMayInlineOutside:
+ case _canInline:
+ case _mustInline:
+ // Do nothing.
+ break;
+ }
} else {
- // If we can inline a function outside a loop then we should do it inside
- // a loop as well.
- canBeInlined[element] = true;
- canBeInlinedInsideLoop[element] = true;
+ switch (oldDecision) {
+ case _mustNotInline:
+ case _mayInlineInLoopMustNotOutside:
+ case _canInlineInLoopMustNotOutside:
+ throw new SpannableAssertionFailure(element,
+ "Can't mark a function as non-inlinable and inlinable at the "
+ "same time.");
+
+ case _unknown:
+ case _canInlineInLoopMayInlineOutside:
+ _cachedDecisions[element] = _canInline;
+ break;
+
+ case _canInline:
+ case _mustInline:
+ // Do nothing.
+ break;
+
+ }
}
}
- void markAsNonInlinable(FunctionElement element, {bool insideLoop}) {
- if (insideLoop == null || insideLoop) {
- // If we can't inline a function inside a loop, then we should not inline
- // it outside a loop either.
- canBeInlined[element] = false;
- canBeInlinedInsideLoop[element] = false;
+ void markAsNonInlinable(FunctionElement element, {bool insideLoop: true}) {
+ int oldDecision = _cachedDecisions[element];
+
+ if (oldDecision == null) {
+ oldDecision = _unknown;
+ }
+
+ if (insideLoop) {
+ switch (oldDecision) {
+ case _canInlineInLoopMustNotOutside:
+ case _canInlineInLoopMayInlineOutside:
+ case _canInline:
+ case _mustInline:
+ throw new SpannableAssertionFailure(element,
+ "Can't mark a function as non-inlinable and inlinable at the "
+ "same time.");
+
+ case _mayInlineInLoopMustNotOutside:
+ case _unknown:
+ _cachedDecisions[element] = _mustNotInline;
+ break;
+
+ case _mustNotInline:
+ // Do nothing.
+ break;
+ }
} else {
- canBeInlined[element] = false;
+ switch (oldDecision) {
+ case _canInline:
+ case _mustInline:
+ throw new SpannableAssertionFailure(element,
+ "Can't mark a function as non-inlinable and inlinable at the "
+ "same time.");
+
+ case _unknown:
+ // We can't inline outside a loop, but we might still be allowed to do
+ // so outside.
+ _cachedDecisions[element] = _mayInlineInLoopMustNotOutside;
+ break;
+
+ case _canInlineInLoopMayInlineOutside:
+ // We already knew that the function could be inlined inside a loop,
+ // but didn't have information about the non-loop case. Now we know
+ // that it can't be inlined outside a loop.
+ _cachedDecisions[element] = _canInlineInLoopMustNotOutside;
+ break;
+
+ case _mayInlineInLoopMustNotOutside:
+ case _canInlineInLoopMustNotOutside:
+ case _mustNotInline:
+ // Do nothing.
+ break;
+ }
}
}
+
+ void markAsMustInline(FunctionElement element) {
+ _cachedDecisions[element] = _mustInline;
+ }
}
class JavaScriptBackend extends Backend {
@@ -84,22 +229,10 @@ class JavaScriptBackend extends Backend {
static const String START_ROOT_ISOLATE = 'startRootIsolate';
- /// The list of functions for classes in the [internalLibrary] that we want
- /// to inline always. Any function in this list must be inlinable with
- /// respect to the conditions used in [InlineWeeder.canInline], except for
- /// size/complexity heuristics.
- static const Map<String, List<String>> ALWAYS_INLINE =
- const <String, List<String>> {
- };
-
String get patchVersion => USE_NEW_EMITTER ? 'new' : 'old';
final Annotations annotations = new Annotations();
- /// List of [FunctionElement]s that we want to inline always. This list is
- /// filled when resolution is complete by looking up in [internalLibrary].
- List<FunctionElement> functionsToAlwaysInline;
-
/// Reference to the internal library to lookup functions to always inline.
LibraryElement internalLibrary;
@@ -174,6 +307,7 @@ class JavaScriptBackend extends Backend {
ClassElement noSideEffectsClass;
ClassElement noThrowsClass;
ClassElement noInlineClass;
+ ClassElement forceInlineClass;
ClassElement irRepresentationClass;
Element getInterceptorMethod;
@@ -961,26 +1095,6 @@ class JavaScriptBackend extends Backend {
super.onResolutionComplete();
computeMembersNeededForReflection();
rti.computeClassesNeedingRti();
- computeFunctionsToAlwaysInline();
- }
-
- void computeFunctionsToAlwaysInline() {
- functionsToAlwaysInline = <FunctionElement>[];
- if (internalLibrary == null) return;
-
- // Try to find all functions intended to always inline. If their enclosing
- // class is not resolved we skip the methods, but it is an error to mention
- // a function or class that cannot be found.
- for (String className in ALWAYS_INLINE.keys) {
- ClassElement cls = find(internalLibrary, className);
- if (cls.resolutionState != STATE_DONE) continue;
- for (String functionName in ALWAYS_INLINE[className]) {
- Element function = cls.lookupMember(functionName);
- assert(invariant(cls, function is FunctionElement,
- message: 'unable to find function $functionName in $className'));
- functionsToAlwaysInline.add(function);
- }
- }
}
void registerGetRuntimeTypeArgument(Registry registry) {
@@ -1869,6 +1983,7 @@ class JavaScriptBackend extends Backend {
noSideEffectsClass = findClass('NoSideEffects');
noThrowsClass = findClass('NoThrows');
noInlineClass = findClass('NoInline');
+ forceInlineClass = findClass('ForceInline');
irRepresentationClass = findClass('IrRepresentation');
getIsolateAffinityTagMarker = findMethod('getIsolateAffinityTag');
@@ -2325,6 +2440,7 @@ class JavaScriptBackend extends Backend {
LibraryElement library = element.library;
if (!library.isPlatformLibrary && !library.canUseNative) return;
bool hasNoInline = false;
+ bool hasForceInline = false;
bool hasNoThrows = false;
bool hasNoSideEffects = false;
for (MetadataAnnotation metadata in element.metadata) {
@@ -2332,7 +2448,15 @@ class JavaScriptBackend extends Backend {
if (!metadata.constant.value.isConstructedObject) continue;
ObjectConstantValue value = metadata.constant.value;
ClassElement cls = value.type.element;
- if (cls == noInlineClass) {
+ if (cls == forceInlineClass) {
+ hasForceInline = true;
+ if (VERBOSE_OPTIMIZER_HINTS) {
+ compiler.reportHint(element,
+ MessageKind.GENERIC,
+ {'text': "Must inline"});
+ }
+ inlineCache.markAsMustInline(element);
+ } else if (cls == noInlineClass) {
hasNoInline = true;
if (VERBOSE_OPTIMIZER_HINTS) {
compiler.reportHint(element,
@@ -2363,6 +2487,10 @@ class JavaScriptBackend extends Backend {
compiler.world.registerSideEffectsFree(element);
}
}
+ if (hasForceInline && hasNoInline) {
+ compiler.internalError(element,
+ "@ForceInline() must not be used with @NoInline.");
+ }
if (hasNoThrows && !hasNoInline) {
compiler.internalError(element,
"@NoThrows() should always be combined with @NoInline.");
« no previous file with comments | « no previous file | pkg/compiler/lib/src/ssa/builder.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698