Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of js_backend; | 5 part of js_backend; |
| 6 | 6 |
| 7 const VERBOSE_OPTIMIZER_HINTS = false; | 7 const VERBOSE_OPTIMIZER_HINTS = false; |
| 8 | 8 |
| 9 const bool USE_CPS_IR = const bool.fromEnvironment("USE_CPS_IR"); | 9 const bool USE_CPS_IR = const bool.fromEnvironment("USE_CPS_IR"); |
| 10 | 10 |
| 11 class JavaScriptItemCompilationContext extends ItemCompilationContext { | 11 class JavaScriptItemCompilationContext extends ItemCompilationContext { |
| 12 final Set<HInstruction> boundsChecked = new Set<HInstruction>(); | 12 final Set<HInstruction> boundsChecked = new Set<HInstruction>(); |
| 13 final Set<HInstruction> allocatedFixedLists = new Set<HInstruction>(); | 13 final Set<HInstruction> allocatedFixedLists = new Set<HInstruction>(); |
| 14 } | 14 } |
| 15 | 15 |
| 16 abstract class FunctionCompiler { | 16 abstract class FunctionCompiler { |
| 17 /// Generates JavaScript code for `work.element`. | 17 /// Generates JavaScript code for `work.element`. |
| 18 jsAst.Fun compile(CodegenWorkItem work); | 18 jsAst.Fun compile(CodegenWorkItem work); |
| 19 | 19 |
| 20 Iterable get tasks; | 20 Iterable get tasks; |
| 21 } | 21 } |
| 22 | 22 |
| 23 /* | 23 /* |
| 24 * Invariants: | 24 * Invariants: |
| 25 * canInline(function) implies canInline(function, insideLoop:true) | 25 * canInline(function) implies canInline(function, insideLoop:true) |
| 26 * !canInline(function, insideLoop: true) implies !canInline(function) | 26 * !canInline(function, insideLoop: true) implies !canInline(function) |
| 27 */ | 27 */ |
| 28 class FunctionInlineCache { | 28 class FunctionInlineCache { |
| 29 final Map<FunctionElement, bool> canBeInlined = | 29 static const int _unknown = -1; |
| 30 new Map<FunctionElement, bool>(); | 30 static const int _mustNotInline = 0; |
| 31 // May-inline-in-loop means that the function may not be inlined outside loops | |
| 32 // but may be inlined in a loop. | |
| 33 static const int _mayInlineInLoopMustNotOutside = 1; | |
| 34 // The function can be inlined in a loop, but not outside. | |
| 35 static const int _canInlineInLoopMustNotOutside = 2; | |
| 36 // May-inline means that we know that it can be inlined inside a loop, but | |
| 37 // don't know about the general case yet. | |
| 38 static const int _canInlineInLoopMayInlineOutside = 3; | |
| 39 static const int _canInline = 4; | |
| 40 static const int _mustInline = 5; | |
| 31 | 41 |
| 32 final Map<FunctionElement, bool> canBeInlinedInsideLoop = | 42 final Map<FunctionElement, int> _cachedDecisions = |
| 33 new Map<FunctionElement, bool>(); | 43 new Map<FunctionElement, int>(); |
| 34 | 44 |
| 35 // Returns [:true:]/[:false:] if we have a cached decision. | 45 // Returns `true`/`false` if we have a cached decision. |
| 36 // Returns [:null:] otherwise. | 46 // Returns `null` otherwise. |
| 37 bool canInline(FunctionElement element, {bool insideLoop}) { | 47 bool canInline(FunctionElement element, {bool insideLoop}) { |
| 38 return insideLoop ? canBeInlinedInsideLoop[element] : canBeInlined[element]; | 48 int decision = _cachedDecisions[element]; |
| 49 | |
| 50 if (decision == null) { | |
| 51 decision = _unknown; | |
| 52 } | |
| 53 | |
| 54 if (insideLoop) { | |
| 55 switch (decision) { | |
| 56 case _mustNotInline: | |
| 57 return false; | |
| 58 | |
| 59 case _unknown: | |
| 60 case _mayInlineInLoopMustNotOutside: | |
| 61 // We know we can't inline outside a loop, but don't know for the | |
| 62 // loop case. Return `null` to indicate that we don't know yet. | |
| 63 return null; | |
| 64 | |
| 65 case _canInlineInLoopMustNotOutside: | |
| 66 case _canInlineInLoopMayInlineOutside: | |
| 67 case _canInline: | |
| 68 case _mustInline: | |
| 69 return true; | |
| 70 } | |
| 71 } else { | |
| 72 switch (decision) { | |
| 73 case _mustNotInline: | |
| 74 case _mayInlineInLoopMustNotOutside: | |
| 75 case _canInlineInLoopMustNotOutside: | |
| 76 return false; | |
| 77 | |
| 78 case _unknown: | |
| 79 case _canInlineInLoopMayInlineOutside: | |
| 80 // We know we can inline inside a loop, but don't know for the | |
| 81 // non-loop case. Return `null` to indicate that we don't know yet. | |
| 82 return null; | |
| 83 | |
| 84 case _canInline: | |
| 85 case _mustInline: | |
| 86 return true; | |
| 87 } | |
| 88 } | |
| 89 | |
| 90 // Quiet static checker. | |
| 91 return null; | |
| 39 } | 92 } |
| 40 | 93 |
| 41 void markAsInlinable(FunctionElement element, {bool insideLoop}) { | 94 void markAsInlinable(FunctionElement element, {bool insideLoop}) { |
| 95 int oldDecision = _cachedDecisions[element]; | |
| 96 | |
| 97 if (oldDecision == null) { | |
| 98 oldDecision = _unknown; | |
| 99 } | |
| 100 | |
| 42 if (insideLoop) { | 101 if (insideLoop) { |
| 43 canBeInlinedInsideLoop[element] = true; | 102 switch (oldDecision) { |
| 103 case _mustNotInline: | |
| 104 throw new SpannableAssertionFailure(element, | |
| 105 "Can't mark a function as non-inlinable and inlinable at the " | |
| 106 "same time."); | |
| 107 break; | |
|
Johnni Winther
2015/03/04 09:19:16
`break;` shouldn't be necessary for warning-freene
floitsch
2015/03/04 13:24:58
Done.
| |
| 108 | |
| 109 case _unknown: | |
| 110 // We know that it can be inlined in a loop, but don't know about the | |
| 111 // non-loop case yet. | |
| 112 _cachedDecisions[element] = _canInlineInLoopMayInlineOutside; | |
| 113 break; | |
| 114 | |
| 115 case _mayInlineInLoopMustNotOutside: | |
|
Johnni Winther
2015/03/04 09:19:16
Shouldn't _mayInlineInLoopMustNotOutside but repla
floitsch
2015/03/04 13:24:58
good catch. thanks.
done.
| |
| 116 case _canInlineInLoopMustNotOutside: | |
| 117 case _canInlineInLoopMayInlineOutside: | |
| 118 case _canInline: | |
| 119 case _mustInline: | |
| 120 // Do nothing. | |
| 121 break; | |
| 122 } | |
| 44 } else { | 123 } else { |
| 45 // If we can inline a function outside a loop then we should do it inside | 124 switch (oldDecision) { |
| 46 // a loop as well. | 125 case _mustNotInline: |
| 47 canBeInlined[element] = true; | 126 case _mayInlineInLoopMustNotOutside: |
| 48 canBeInlinedInsideLoop[element] = true; | 127 case _canInlineInLoopMustNotOutside: |
| 128 throw new SpannableAssertionFailure(element, | |
| 129 "Can't mark a function as non-inlinable and inlinable at the " | |
| 130 "same time."); | |
| 131 break; | |
|
Johnni Winther
2015/03/04 09:19:16
`break;` shouldn't be necessary for warning-freene
floitsch
2015/03/04 13:24:59
Done.
| |
| 132 | |
| 133 | |
| 134 case _unknown: | |
| 135 case _canInlineInLoopMayInlineOutside: | |
| 136 _cachedDecisions[element] = _canInline; | |
| 137 break; | |
| 138 | |
| 139 case _canInline: | |
| 140 case _mustInline: | |
| 141 // Do nothing. | |
| 142 break; | |
| 143 | |
| 144 } | |
| 49 } | 145 } |
| 50 } | 146 } |
| 51 | 147 |
| 52 void markAsNonInlinable(FunctionElement element, {bool insideLoop}) { | 148 void markAsNonInlinable(FunctionElement element, {bool insideLoop: true}) { |
| 53 if (insideLoop == null || insideLoop) { | 149 int oldDecision = _cachedDecisions[element]; |
| 54 // If we can't inline a function inside a loop, then we should not inline | 150 |
| 55 // it outside a loop either. | 151 if (oldDecision == null) { |
| 56 canBeInlined[element] = false; | 152 oldDecision = _unknown; |
| 57 canBeInlinedInsideLoop[element] = false; | 153 } |
| 154 | |
| 155 if (insideLoop) { | |
| 156 switch (oldDecision) { | |
| 157 case _canInlineInLoopMustNotOutside: | |
| 158 case _canInlineInLoopMayInlineOutside: | |
| 159 case _canInline: | |
| 160 case _mustInline: | |
| 161 throw new SpannableAssertionFailure(element, | |
| 162 "Can't mark a function as non-inlinable and inlinable at the " | |
| 163 "same time."); | |
| 164 break; | |
| 165 | |
| 166 case _mayInlineInLoopMustNotOutside: | |
| 167 case _unknown: | |
| 168 _cachedDecisions[element] = _mustNotInline; | |
| 169 break; | |
| 170 | |
| 171 case _mustNotInline: | |
| 172 // Do nothing. | |
| 173 break; | |
| 174 } | |
| 58 } else { | 175 } else { |
| 59 canBeInlined[element] = false; | 176 switch (oldDecision) { |
| 177 case _canInline: | |
| 178 case _mustInline: | |
| 179 throw new SpannableAssertionFailure(element, | |
| 180 "Can't mark a function as non-inlinable and inlinable at the " | |
| 181 "same time."); | |
| 182 break; | |
|
Johnni Winther
2015/03/04 09:19:16
`break;` shouldn't be necessary for warning-freene
floitsch
2015/03/04 13:24:58
Done.
| |
| 183 | |
| 184 case _unknown: | |
| 185 // We can't inline outside a loop, but we might still be allowed to do | |
| 186 // it outside. | |
| 187 _cachedDecisions[element] = _mayInlineInLoopMustNotOutside; | |
| 188 break; | |
| 189 | |
| 190 case _canInlineInLoopMayInlineOutside: | |
| 191 // We already knew that the function could be inlined inside a loop, | |
| 192 // but didn't have information about the non-loop case. Now we know | |
| 193 // that it can't be inlined outside a loop. | |
| 194 _cachedDecisions[element] = _canInlineInLoopMustNotOutside; | |
| 195 break; | |
| 196 | |
| 197 case _mayInlineInLoopMustNotOutside: | |
| 198 case _canInlineInLoopMustNotOutside: | |
| 199 case _mustNotInline: | |
| 200 // Do nothing. | |
| 201 break; | |
| 202 } | |
| 60 } | 203 } |
| 61 } | 204 } |
| 205 | |
| 206 void markAsMustInline(FunctionElement element) { | |
| 207 _cachedDecisions[element] = _mustInline; | |
| 208 } | |
| 62 } | 209 } |
| 63 | 210 |
| 64 class JavaScriptBackend extends Backend { | 211 class JavaScriptBackend extends Backend { |
| 65 static final Uri DART_JS_HELPER = new Uri(scheme: 'dart', path: '_js_helper'); | 212 static final Uri DART_JS_HELPER = new Uri(scheme: 'dart', path: '_js_helper'); |
| 66 static final Uri DART_INTERCEPTORS = | 213 static final Uri DART_INTERCEPTORS = |
| 67 new Uri(scheme: 'dart', path: '_interceptors'); | 214 new Uri(scheme: 'dart', path: '_interceptors'); |
| 68 static final Uri DART_INTERNAL = | 215 static final Uri DART_INTERNAL = |
| 69 new Uri(scheme: 'dart', path: '_internal'); | 216 new Uri(scheme: 'dart', path: '_internal'); |
| 70 static final Uri DART_FOREIGN_HELPER = | 217 static final Uri DART_FOREIGN_HELPER = |
| 71 new Uri(scheme: 'dart', path: '_foreign_helper'); | 218 new Uri(scheme: 'dart', path: '_foreign_helper'); |
| 72 static final Uri DART_JS_MIRRORS = | 219 static final Uri DART_JS_MIRRORS = |
| 73 new Uri(scheme: 'dart', path: '_js_mirrors'); | 220 new Uri(scheme: 'dart', path: '_js_mirrors'); |
| 74 static final Uri DART_JS_NAMES = | 221 static final Uri DART_JS_NAMES = |
| 75 new Uri(scheme: 'dart', path: '_js_names'); | 222 new Uri(scheme: 'dart', path: '_js_names'); |
| 76 static final Uri DART_EMBEDDED_NAMES = | 223 static final Uri DART_EMBEDDED_NAMES = |
| 77 new Uri(scheme: 'dart', path: '_js_embedded_names'); | 224 new Uri(scheme: 'dart', path: '_js_embedded_names'); |
| 78 static final Uri DART_ISOLATE_HELPER = | 225 static final Uri DART_ISOLATE_HELPER = |
| 79 new Uri(scheme: 'dart', path: '_isolate_helper'); | 226 new Uri(scheme: 'dart', path: '_isolate_helper'); |
| 80 static final Uri DART_HTML = | 227 static final Uri DART_HTML = |
| 81 new Uri(scheme: 'dart', path: 'html'); | 228 new Uri(scheme: 'dart', path: 'html'); |
| 82 | 229 |
| 83 static const String INVOKE_ON = '_getCachedInvocation'; | 230 static const String INVOKE_ON = '_getCachedInvocation'; |
| 84 static const String START_ROOT_ISOLATE = 'startRootIsolate'; | 231 static const String START_ROOT_ISOLATE = 'startRootIsolate'; |
| 85 | 232 |
| 86 | 233 |
| 87 /// The list of functions for classes in the [internalLibrary] that we want | |
| 88 /// to inline always. Any function in this list must be inlinable with | |
| 89 /// respect to the conditions used in [InlineWeeder.canInline], except for | |
| 90 /// size/complexity heuristics. | |
| 91 static const Map<String, List<String>> ALWAYS_INLINE = | |
| 92 const <String, List<String>> { | |
| 93 }; | |
| 94 | |
| 95 String get patchVersion => USE_NEW_EMITTER ? 'new' : 'old'; | 234 String get patchVersion => USE_NEW_EMITTER ? 'new' : 'old'; |
| 96 | 235 |
| 97 final Annotations annotations = new Annotations(); | 236 final Annotations annotations = new Annotations(); |
| 98 | 237 |
| 99 /// List of [FunctionElement]s that we want to inline always. This list is | |
| 100 /// filled when resolution is complete by looking up in [internalLibrary]. | |
| 101 List<FunctionElement> functionsToAlwaysInline; | |
| 102 | |
| 103 /// Reference to the internal library to lookup functions to always inline. | 238 /// Reference to the internal library to lookup functions to always inline. |
| 104 LibraryElement internalLibrary; | 239 LibraryElement internalLibrary; |
| 105 | 240 |
| 106 | 241 |
| 107 /// Set of classes that need to be considered for reflection although not | 242 /// Set of classes that need to be considered for reflection although not |
| 108 /// otherwise visible during resolution. | 243 /// otherwise visible during resolution. |
| 109 Iterable<ClassElement> get classesRequiredForReflection { | 244 Iterable<ClassElement> get classesRequiredForReflection { |
| 110 // TODO(herhut): Clean this up when classes needed for rti are tracked. | 245 // TODO(herhut): Clean this up when classes needed for rti are tracked. |
| 111 return [closureClass, jsIndexableClass]; | 246 return [closureClass, jsIndexableClass]; |
| 112 } | 247 } |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 167 ClassElement typeLiteralClass; | 302 ClassElement typeLiteralClass; |
| 168 ClassElement mapLiteralClass; | 303 ClassElement mapLiteralClass; |
| 169 ClassElement constMapLiteralClass; | 304 ClassElement constMapLiteralClass; |
| 170 ClassElement typeVariableClass; | 305 ClassElement typeVariableClass; |
| 171 ConstructorElement mapLiteralConstructor; | 306 ConstructorElement mapLiteralConstructor; |
| 172 ConstructorElement mapLiteralConstructorEmpty; | 307 ConstructorElement mapLiteralConstructorEmpty; |
| 173 | 308 |
| 174 ClassElement noSideEffectsClass; | 309 ClassElement noSideEffectsClass; |
| 175 ClassElement noThrowsClass; | 310 ClassElement noThrowsClass; |
| 176 ClassElement noInlineClass; | 311 ClassElement noInlineClass; |
| 312 ClassElement forceInlineClass; | |
| 177 ClassElement irRepresentationClass; | 313 ClassElement irRepresentationClass; |
| 178 | 314 |
| 179 Element getInterceptorMethod; | 315 Element getInterceptorMethod; |
| 180 | 316 |
| 181 ClassElement jsInvocationMirrorClass; | 317 ClassElement jsInvocationMirrorClass; |
| 182 | 318 |
| 183 /// If [true], the compiler will emit code that writes the name of the current | 319 /// If [true], the compiler will emit code that writes the name of the current |
| 184 /// method together with its class and library to the console the first time | 320 /// method together with its class and library to the console the first time |
| 185 /// the method is called. | 321 /// the method is called. |
| 186 static const bool TRACE_CALLS = false; | 322 static const bool TRACE_CALLS = false; |
| (...skipping 767 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 954 assert(traceHelper != null); | 1090 assert(traceHelper != null); |
| 955 enqueueInResolution(traceHelper, registry); | 1091 enqueueInResolution(traceHelper, registry); |
| 956 } | 1092 } |
| 957 registerCheckedModeHelpers(registry); | 1093 registerCheckedModeHelpers(registry); |
| 958 } | 1094 } |
| 959 | 1095 |
| 960 onResolutionComplete() { | 1096 onResolutionComplete() { |
| 961 super.onResolutionComplete(); | 1097 super.onResolutionComplete(); |
| 962 computeMembersNeededForReflection(); | 1098 computeMembersNeededForReflection(); |
| 963 rti.computeClassesNeedingRti(); | 1099 rti.computeClassesNeedingRti(); |
| 964 computeFunctionsToAlwaysInline(); | |
| 965 } | |
| 966 | |
| 967 void computeFunctionsToAlwaysInline() { | |
| 968 functionsToAlwaysInline = <FunctionElement>[]; | |
| 969 if (internalLibrary == null) return; | |
| 970 | |
| 971 // Try to find all functions intended to always inline. If their enclosing | |
| 972 // class is not resolved we skip the methods, but it is an error to mention | |
| 973 // a function or class that cannot be found. | |
| 974 for (String className in ALWAYS_INLINE.keys) { | |
| 975 ClassElement cls = find(internalLibrary, className); | |
| 976 if (cls.resolutionState != STATE_DONE) continue; | |
| 977 for (String functionName in ALWAYS_INLINE[className]) { | |
| 978 Element function = cls.lookupMember(functionName); | |
| 979 assert(invariant(cls, function is FunctionElement, | |
| 980 message: 'unable to find function $functionName in $className')); | |
| 981 functionsToAlwaysInline.add(function); | |
| 982 } | |
| 983 } | |
| 984 } | 1100 } |
| 985 | 1101 |
| 986 void registerGetRuntimeTypeArgument(Registry registry) { | 1102 void registerGetRuntimeTypeArgument(Registry registry) { |
| 987 enqueueInResolution(getGetRuntimeTypeArgument(), registry); | 1103 enqueueInResolution(getGetRuntimeTypeArgument(), registry); |
| 988 enqueueInResolution(getGetTypeArgumentByIndex(), registry); | 1104 enqueueInResolution(getGetTypeArgumentByIndex(), registry); |
| 989 enqueueInResolution(getCopyTypeArguments(), registry); | 1105 enqueueInResolution(getCopyTypeArguments(), registry); |
| 990 } | 1106 } |
| 991 | 1107 |
| 992 void registerCallMethodWithFreeTypeVariables( | 1108 void registerCallMethodWithFreeTypeVariables( |
| 993 Element callMethod, | 1109 Element callMethod, |
| (...skipping 868 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1862 | 1978 |
| 1863 typeLiteralClass = findClass('TypeImpl'); | 1979 typeLiteralClass = findClass('TypeImpl'); |
| 1864 constMapLiteralClass = findClass('ConstantMap'); | 1980 constMapLiteralClass = findClass('ConstantMap'); |
| 1865 typeVariableClass = findClass('TypeVariable'); | 1981 typeVariableClass = findClass('TypeVariable'); |
| 1866 | 1982 |
| 1867 jsIndexingBehaviorInterface = findClass('JavaScriptIndexingBehavior'); | 1983 jsIndexingBehaviorInterface = findClass('JavaScriptIndexingBehavior'); |
| 1868 | 1984 |
| 1869 noSideEffectsClass = findClass('NoSideEffects'); | 1985 noSideEffectsClass = findClass('NoSideEffects'); |
| 1870 noThrowsClass = findClass('NoThrows'); | 1986 noThrowsClass = findClass('NoThrows'); |
| 1871 noInlineClass = findClass('NoInline'); | 1987 noInlineClass = findClass('NoInline'); |
| 1988 forceInlineClass = findClass('ForceInline'); | |
| 1872 irRepresentationClass = findClass('IrRepresentation'); | 1989 irRepresentationClass = findClass('IrRepresentation'); |
| 1873 | 1990 |
| 1874 getIsolateAffinityTagMarker = findMethod('getIsolateAffinityTag'); | 1991 getIsolateAffinityTagMarker = findMethod('getIsolateAffinityTag'); |
| 1875 | 1992 |
| 1876 requiresPreambleMarker = findMethod('requiresPreamble'); | 1993 requiresPreambleMarker = findMethod('requiresPreamble'); |
| 1877 } else if (uri == DART_JS_MIRRORS) { | 1994 } else if (uri == DART_JS_MIRRORS) { |
| 1878 disableTreeShakingMarker = find(library, 'disableTreeShaking'); | 1995 disableTreeShakingMarker = find(library, 'disableTreeShaking'); |
| 1879 preserveMetadataMarker = find(library, 'preserveMetadata'); | 1996 preserveMetadataMarker = find(library, 'preserveMetadata'); |
| 1880 preserveUrisMarker = find(library, 'preserveUris'); | 1997 preserveUrisMarker = find(library, 'preserveUris'); |
| 1881 preserveLibraryNamesMarker = find(library, 'preserveLibraryNames'); | 1998 preserveLibraryNamesMarker = find(library, 'preserveLibraryNames'); |
| (...skipping 436 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2318 } | 2435 } |
| 2319 | 2436 |
| 2320 void onElementResolved(Element element, TreeElements elements) { | 2437 void onElementResolved(Element element, TreeElements elements) { |
| 2321 if (element.isFunction && annotations.noInline(element)) { | 2438 if (element.isFunction && annotations.noInline(element)) { |
| 2322 inlineCache.markAsNonInlinable(element); | 2439 inlineCache.markAsNonInlinable(element); |
| 2323 } | 2440 } |
| 2324 | 2441 |
| 2325 LibraryElement library = element.library; | 2442 LibraryElement library = element.library; |
| 2326 if (!library.isPlatformLibrary && !library.canUseNative) return; | 2443 if (!library.isPlatformLibrary && !library.canUseNative) return; |
| 2327 bool hasNoInline = false; | 2444 bool hasNoInline = false; |
| 2445 bool hasForceInline = false; | |
| 2328 bool hasNoThrows = false; | 2446 bool hasNoThrows = false; |
| 2329 bool hasNoSideEffects = false; | 2447 bool hasNoSideEffects = false; |
| 2330 for (MetadataAnnotation metadata in element.metadata) { | 2448 for (MetadataAnnotation metadata in element.metadata) { |
| 2331 metadata.ensureResolved(compiler); | 2449 metadata.ensureResolved(compiler); |
| 2332 if (!metadata.constant.value.isConstructedObject) continue; | 2450 if (!metadata.constant.value.isConstructedObject) continue; |
| 2333 ObjectConstantValue value = metadata.constant.value; | 2451 ObjectConstantValue value = metadata.constant.value; |
| 2334 ClassElement cls = value.type.element; | 2452 ClassElement cls = value.type.element; |
| 2335 if (cls == noInlineClass) { | 2453 if (cls == forceInlineClass) { |
| 2454 hasForceInline = true; | |
| 2455 if (VERBOSE_OPTIMIZER_HINTS) { | |
| 2456 compiler.reportHint(element, | |
| 2457 MessageKind.GENERIC, | |
| 2458 {'text': "Must inline"}); | |
| 2459 } | |
| 2460 inlineCache.markAsMustInline(element); | |
| 2461 } else if (cls == noInlineClass) { | |
| 2336 hasNoInline = true; | 2462 hasNoInline = true; |
| 2337 if (VERBOSE_OPTIMIZER_HINTS) { | 2463 if (VERBOSE_OPTIMIZER_HINTS) { |
| 2338 compiler.reportHint(element, | 2464 compiler.reportHint(element, |
| 2339 MessageKind.GENERIC, | 2465 MessageKind.GENERIC, |
| 2340 {'text': "Cannot inline"}); | 2466 {'text': "Cannot inline"}); |
| 2341 } | 2467 } |
| 2342 inlineCache.markAsNonInlinable(element); | 2468 inlineCache.markAsNonInlinable(element); |
| 2343 } else if (cls == noThrowsClass) { | 2469 } else if (cls == noThrowsClass) { |
| 2344 hasNoThrows = true; | 2470 hasNoThrows = true; |
| 2345 if (!Elements.isStaticOrTopLevelFunction(element)) { | 2471 if (!Elements.isStaticOrTopLevelFunction(element)) { |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 2356 } else if (cls == noSideEffectsClass) { | 2482 } else if (cls == noSideEffectsClass) { |
| 2357 hasNoSideEffects = true; | 2483 hasNoSideEffects = true; |
| 2358 if (VERBOSE_OPTIMIZER_HINTS) { | 2484 if (VERBOSE_OPTIMIZER_HINTS) { |
| 2359 compiler.reportHint(element, | 2485 compiler.reportHint(element, |
| 2360 MessageKind.GENERIC, | 2486 MessageKind.GENERIC, |
| 2361 {'text': "Has no side effects"}); | 2487 {'text': "Has no side effects"}); |
| 2362 } | 2488 } |
| 2363 compiler.world.registerSideEffectsFree(element); | 2489 compiler.world.registerSideEffectsFree(element); |
| 2364 } | 2490 } |
| 2365 } | 2491 } |
| 2492 if (hasForceInline && hasNoInline) { | |
| 2493 compiler.internalError(element, | |
| 2494 "@ForceInline() must not be used with @NoInline."); | |
| 2495 } | |
| 2366 if (hasNoThrows && !hasNoInline) { | 2496 if (hasNoThrows && !hasNoInline) { |
| 2367 compiler.internalError(element, | 2497 compiler.internalError(element, |
| 2368 "@NoThrows() should always be combined with @NoInline."); | 2498 "@NoThrows() should always be combined with @NoInline."); |
| 2369 } | 2499 } |
| 2370 if (hasNoSideEffects && !hasNoInline) { | 2500 if (hasNoSideEffects && !hasNoInline) { |
| 2371 compiler.internalError(element, | 2501 compiler.internalError(element, |
| 2372 "@NoSideEffects() should always be combined with @NoInline."); | 2502 "@NoSideEffects() should always be combined with @NoInline."); |
| 2373 } | 2503 } |
| 2374 if (element == invokeOnMethod) { | 2504 if (element == invokeOnMethod) { |
| 2375 compiler.enabledInvokeOn = true; | 2505 compiler.enabledInvokeOn = true; |
| (...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2706 } | 2836 } |
| 2707 } | 2837 } |
| 2708 | 2838 |
| 2709 /// Records that [constant] is used by the element behind [registry]. | 2839 /// Records that [constant] is used by the element behind [registry]. |
| 2710 class Dependency { | 2840 class Dependency { |
| 2711 final ConstantValue constant; | 2841 final ConstantValue constant; |
| 2712 final Element annotatedElement; | 2842 final Element annotatedElement; |
| 2713 | 2843 |
| 2714 const Dependency(this.constant, this.annotatedElement); | 2844 const Dependency(this.constant, this.annotatedElement); |
| 2715 } | 2845 } |
| OLD | NEW |