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

Side by Side 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: Remove mustInline. It's not used. Created 5 years, 9 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | pkg/compiler/lib/src/ssa/builder.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 _mustNotInline = 0;
Johnni Winther 2015/03/03 08:57:47 The logic for these tags is both complex and scatt
floitsch 2015/03/03 18:54:13 Made the logic much more explicit (and verbose).
30 new Map<FunctionElement, bool>(); 30 // May-inline-in-loop means that the function may not be inlined outside loops
31 // but may be inlined in a loop.
32 static const int _mayInlineInLoop = 1;
33 // The function can be inlined in a loop, but not outside.
34 static const int _canInlineInLoop = 2;
35 // May-inline means that we know that it can be inlined inside a loop, but
36 // don't know about the general case yet.
37 static const int _mayInline = 3;
38 static const int _canInline = 4;
39 static const int _mustInline = 5;
31 40
32 final Map<FunctionElement, bool> canBeInlinedInsideLoop = 41 final Map<FunctionElement, int> _cachedDecisions =
33 new Map<FunctionElement, bool>(); 42 new Map<FunctionElement, int>();
34 43
35 // Returns [:true:]/[:false:] if we have a cached decision. 44 // Returns `true`/`false` if we have a cached decision.
36 // Returns [:null:] otherwise. 45 // Returns `null` otherwise.
37 bool canInline(FunctionElement element, {bool insideLoop}) { 46 bool canInline(FunctionElement element, {bool insideLoop}) {
38 return insideLoop ? canBeInlinedInsideLoop[element] : canBeInlined[element]; 47 int decision = _cachedDecisions[element];
48 if (decision == null) return null;
49 if (insideLoop) {
50 // We might be able to inline inside a loop, but don't know it yet.
51 if (decision == _mayInlineInLoop) return null;
52 return (decision >= _canInlineInLoop);
53 }
54 if (decision == _mayInline) return null;
55 return decision >= _canInline;
39 } 56 }
40 57
41 void markAsInlinable(FunctionElement element, {bool insideLoop}) { 58 void markAsInlinable(FunctionElement element, {bool insideLoop}) {
59 int oldDecision = _cachedDecisions[element];
60 assert(oldDecision != _mustNotInline);
61
42 if (insideLoop) { 62 if (insideLoop) {
43 canBeInlinedInsideLoop[element] = true; 63 if (oldDecision == null) {
64 // We know that it can be inlined in a loop, but don't know about the
65 // non-loop case yet.
66 _cachedDecisions[element] = _mayInline;
67 } else if (oldDecision == _mayInlineInLoop) {
68 _cachedDecisions[element] = _canInlineInLoop;
69 }
44 } else { 70 } else {
45 // If we can inline a function outside a loop then we should do it inside 71 if (oldDecision == null || oldDecision <= _mayInline) {
46 // a loop as well. 72 _cachedDecisions[element] = _canInline;
47 canBeInlined[element] = true; 73 }
48 canBeInlinedInsideLoop[element] = true;
49 } 74 }
50 } 75 }
51 76
52 void markAsNonInlinable(FunctionElement element, {bool insideLoop}) { 77 void markAsNonInlinable(FunctionElement element, {bool insideLoop: true}) {
53 if (insideLoop == null || insideLoop) { 78 assert(_cachedDecisions[element] != _mustInline);
54 // If we can't inline a function inside a loop, then we should not inline 79
55 // it outside a loop either. 80 if (insideLoop) {
56 canBeInlined[element] = false; 81 _cachedDecisions[element] = _mustNotInline;
57 canBeInlinedInsideLoop[element] = false;
58 } else { 82 } else {
59 canBeInlined[element] = false; 83 // We can't inline outside a loop, but we might still be allowed to do it
84 // outside.
85 int oldDecision = _cachedDecisions[element];
86 if (oldDecision == null) {
87 _cachedDecisions[element] = _mayInlineInLoop;
88 } else if (oldDecision == _mayInline) {
89 // We already knew that the function could be inlined inside a loop, but
90 // didn't have information about the non-loop case. Now we know that it
91 // can't be inlined outside a loop.
92 _cachedDecisions[element] = _canInlineInLoop;
93 }
60 } 94 }
61 } 95 }
96
97 void markAsMustInline(FunctionElement element) {
98 _cachedDecisions[element] = _mustInline;
99 }
62 } 100 }
63 101
64 class JavaScriptBackend extends Backend { 102 class JavaScriptBackend extends Backend {
65 static final Uri DART_JS_HELPER = new Uri(scheme: 'dart', path: '_js_helper'); 103 static final Uri DART_JS_HELPER = new Uri(scheme: 'dart', path: '_js_helper');
66 static final Uri DART_INTERCEPTORS = 104 static final Uri DART_INTERCEPTORS =
67 new Uri(scheme: 'dart', path: '_interceptors'); 105 new Uri(scheme: 'dart', path: '_interceptors');
68 static final Uri DART_INTERNAL = 106 static final Uri DART_INTERNAL =
69 new Uri(scheme: 'dart', path: '_internal'); 107 new Uri(scheme: 'dart', path: '_internal');
70 static final Uri DART_FOREIGN_HELPER = 108 static final Uri DART_FOREIGN_HELPER =
71 new Uri(scheme: 'dart', path: '_foreign_helper'); 109 new Uri(scheme: 'dart', path: '_foreign_helper');
72 static final Uri DART_JS_MIRRORS = 110 static final Uri DART_JS_MIRRORS =
73 new Uri(scheme: 'dart', path: '_js_mirrors'); 111 new Uri(scheme: 'dart', path: '_js_mirrors');
74 static final Uri DART_JS_NAMES = 112 static final Uri DART_JS_NAMES =
75 new Uri(scheme: 'dart', path: '_js_names'); 113 new Uri(scheme: 'dart', path: '_js_names');
76 static final Uri DART_EMBEDDED_NAMES = 114 static final Uri DART_EMBEDDED_NAMES =
77 new Uri(scheme: 'dart', path: '_js_embedded_names'); 115 new Uri(scheme: 'dart', path: '_js_embedded_names');
78 static final Uri DART_ISOLATE_HELPER = 116 static final Uri DART_ISOLATE_HELPER =
79 new Uri(scheme: 'dart', path: '_isolate_helper'); 117 new Uri(scheme: 'dart', path: '_isolate_helper');
80 static final Uri DART_HTML = 118 static final Uri DART_HTML =
81 new Uri(scheme: 'dart', path: 'html'); 119 new Uri(scheme: 'dart', path: 'html');
82 120
83 static const String INVOKE_ON = '_getCachedInvocation'; 121 static const String INVOKE_ON = '_getCachedInvocation';
84 static const String START_ROOT_ISOLATE = 'startRootIsolate'; 122 static const String START_ROOT_ISOLATE = 'startRootIsolate';
85 123
86 124
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'; 125 String get patchVersion => USE_NEW_EMITTER ? 'new' : 'old';
96 126
97 final Annotations annotations = new Annotations(); 127 final Annotations annotations = new Annotations();
98 128
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. 129 /// Reference to the internal library to lookup functions to always inline.
104 LibraryElement internalLibrary; 130 LibraryElement internalLibrary;
105 131
106 132
107 /// Set of classes that need to be considered for reflection although not 133 /// Set of classes that need to be considered for reflection although not
108 /// otherwise visible during resolution. 134 /// otherwise visible during resolution.
109 Iterable<ClassElement> get classesRequiredForReflection { 135 Iterable<ClassElement> get classesRequiredForReflection {
110 // TODO(herhut): Clean this up when classes needed for rti are tracked. 136 // TODO(herhut): Clean this up when classes needed for rti are tracked.
111 return [closureClass, jsIndexableClass]; 137 return [closureClass, jsIndexableClass];
112 } 138 }
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
167 ClassElement typeLiteralClass; 193 ClassElement typeLiteralClass;
168 ClassElement mapLiteralClass; 194 ClassElement mapLiteralClass;
169 ClassElement constMapLiteralClass; 195 ClassElement constMapLiteralClass;
170 ClassElement typeVariableClass; 196 ClassElement typeVariableClass;
171 ConstructorElement mapLiteralConstructor; 197 ConstructorElement mapLiteralConstructor;
172 ConstructorElement mapLiteralConstructorEmpty; 198 ConstructorElement mapLiteralConstructorEmpty;
173 199
174 ClassElement noSideEffectsClass; 200 ClassElement noSideEffectsClass;
175 ClassElement noThrowsClass; 201 ClassElement noThrowsClass;
176 ClassElement noInlineClass; 202 ClassElement noInlineClass;
203 ClassElement forceInlineClass;
177 ClassElement irRepresentationClass; 204 ClassElement irRepresentationClass;
178 205
179 Element getInterceptorMethod; 206 Element getInterceptorMethod;
180 207
181 ClassElement jsInvocationMirrorClass; 208 ClassElement jsInvocationMirrorClass;
182 209
183 /// If [true], the compiler will emit code that writes the name of the current 210 /// 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 211 /// method together with its class and library to the console the first time
185 /// the method is called. 212 /// the method is called.
186 static const bool TRACE_CALLS = false; 213 static const bool TRACE_CALLS = false;
(...skipping 767 matching lines...) Expand 10 before | Expand all | Expand 10 after
954 assert(traceHelper != null); 981 assert(traceHelper != null);
955 enqueueInResolution(traceHelper, registry); 982 enqueueInResolution(traceHelper, registry);
956 } 983 }
957 registerCheckedModeHelpers(registry); 984 registerCheckedModeHelpers(registry);
958 } 985 }
959 986
960 onResolutionComplete() { 987 onResolutionComplete() {
961 super.onResolutionComplete(); 988 super.onResolutionComplete();
962 computeMembersNeededForReflection(); 989 computeMembersNeededForReflection();
963 rti.computeClassesNeedingRti(); 990 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 } 991 }
985 992
986 void registerGetRuntimeTypeArgument(Registry registry) { 993 void registerGetRuntimeTypeArgument(Registry registry) {
987 enqueueInResolution(getGetRuntimeTypeArgument(), registry); 994 enqueueInResolution(getGetRuntimeTypeArgument(), registry);
988 enqueueInResolution(getGetTypeArgumentByIndex(), registry); 995 enqueueInResolution(getGetTypeArgumentByIndex(), registry);
989 enqueueInResolution(getCopyTypeArguments(), registry); 996 enqueueInResolution(getCopyTypeArguments(), registry);
990 } 997 }
991 998
992 void registerCallMethodWithFreeTypeVariables( 999 void registerCallMethodWithFreeTypeVariables(
993 Element callMethod, 1000 Element callMethod,
(...skipping 868 matching lines...) Expand 10 before | Expand all | Expand 10 after
1862 1869
1863 typeLiteralClass = findClass('TypeImpl'); 1870 typeLiteralClass = findClass('TypeImpl');
1864 constMapLiteralClass = findClass('ConstantMap'); 1871 constMapLiteralClass = findClass('ConstantMap');
1865 typeVariableClass = findClass('TypeVariable'); 1872 typeVariableClass = findClass('TypeVariable');
1866 1873
1867 jsIndexingBehaviorInterface = findClass('JavaScriptIndexingBehavior'); 1874 jsIndexingBehaviorInterface = findClass('JavaScriptIndexingBehavior');
1868 1875
1869 noSideEffectsClass = findClass('NoSideEffects'); 1876 noSideEffectsClass = findClass('NoSideEffects');
1870 noThrowsClass = findClass('NoThrows'); 1877 noThrowsClass = findClass('NoThrows');
1871 noInlineClass = findClass('NoInline'); 1878 noInlineClass = findClass('NoInline');
1879 forceInlineClass = findClass('ForceInline');
1872 irRepresentationClass = findClass('IrRepresentation'); 1880 irRepresentationClass = findClass('IrRepresentation');
1873 1881
1874 getIsolateAffinityTagMarker = findMethod('getIsolateAffinityTag'); 1882 getIsolateAffinityTagMarker = findMethod('getIsolateAffinityTag');
1875 1883
1876 requiresPreambleMarker = findMethod('requiresPreamble'); 1884 requiresPreambleMarker = findMethod('requiresPreamble');
1877 } else if (uri == DART_JS_MIRRORS) { 1885 } else if (uri == DART_JS_MIRRORS) {
1878 disableTreeShakingMarker = find(library, 'disableTreeShaking'); 1886 disableTreeShakingMarker = find(library, 'disableTreeShaking');
1879 preserveMetadataMarker = find(library, 'preserveMetadata'); 1887 preserveMetadataMarker = find(library, 'preserveMetadata');
1880 preserveUrisMarker = find(library, 'preserveUris'); 1888 preserveUrisMarker = find(library, 'preserveUris');
1881 preserveLibraryNamesMarker = find(library, 'preserveLibraryNames'); 1889 preserveLibraryNamesMarker = find(library, 'preserveLibraryNames');
(...skipping 436 matching lines...) Expand 10 before | Expand all | Expand 10 after
2318 } 2326 }
2319 2327
2320 void onElementResolved(Element element, TreeElements elements) { 2328 void onElementResolved(Element element, TreeElements elements) {
2321 if (element.isFunction && annotations.noInline(element)) { 2329 if (element.isFunction && annotations.noInline(element)) {
2322 inlineCache.markAsNonInlinable(element); 2330 inlineCache.markAsNonInlinable(element);
2323 } 2331 }
2324 2332
2325 LibraryElement library = element.library; 2333 LibraryElement library = element.library;
2326 if (!library.isPlatformLibrary && !library.canUseNative) return; 2334 if (!library.isPlatformLibrary && !library.canUseNative) return;
2327 bool hasNoInline = false; 2335 bool hasNoInline = false;
2336 bool hasForceInline = false;
2328 bool hasNoThrows = false; 2337 bool hasNoThrows = false;
2329 bool hasNoSideEffects = false; 2338 bool hasNoSideEffects = false;
2330 for (MetadataAnnotation metadata in element.metadata) { 2339 for (MetadataAnnotation metadata in element.metadata) {
2331 metadata.ensureResolved(compiler); 2340 metadata.ensureResolved(compiler);
2332 if (!metadata.constant.value.isConstructedObject) continue; 2341 if (!metadata.constant.value.isConstructedObject) continue;
2333 ObjectConstantValue value = metadata.constant.value; 2342 ObjectConstantValue value = metadata.constant.value;
2334 ClassElement cls = value.type.element; 2343 ClassElement cls = value.type.element;
2335 if (cls == noInlineClass) { 2344 if (cls == forceInlineClass) {
2345 hasForceInline = true;
2346 if (VERBOSE_OPTIMIZER_HINTS) {
2347 compiler.reportHint(element,
2348 MessageKind.GENERIC,
2349 {'text': "Must inline"});
2350 }
2351 inlineCache.markAsMustInline(element);
2352 } else if (cls == noInlineClass) {
2336 hasNoInline = true; 2353 hasNoInline = true;
2337 if (VERBOSE_OPTIMIZER_HINTS) { 2354 if (VERBOSE_OPTIMIZER_HINTS) {
2338 compiler.reportHint(element, 2355 compiler.reportHint(element,
2339 MessageKind.GENERIC, 2356 MessageKind.GENERIC,
2340 {'text': "Cannot inline"}); 2357 {'text': "Cannot inline"});
2341 } 2358 }
2342 inlineCache.markAsNonInlinable(element); 2359 inlineCache.markAsNonInlinable(element);
2343 } else if (cls == noThrowsClass) { 2360 } else if (cls == noThrowsClass) {
2344 hasNoThrows = true; 2361 hasNoThrows = true;
2345 if (!Elements.isStaticOrTopLevelFunction(element)) { 2362 if (!Elements.isStaticOrTopLevelFunction(element)) {
(...skipping 10 matching lines...) Expand all
2356 } else if (cls == noSideEffectsClass) { 2373 } else if (cls == noSideEffectsClass) {
2357 hasNoSideEffects = true; 2374 hasNoSideEffects = true;
2358 if (VERBOSE_OPTIMIZER_HINTS) { 2375 if (VERBOSE_OPTIMIZER_HINTS) {
2359 compiler.reportHint(element, 2376 compiler.reportHint(element,
2360 MessageKind.GENERIC, 2377 MessageKind.GENERIC,
2361 {'text': "Has no side effects"}); 2378 {'text': "Has no side effects"});
2362 } 2379 }
2363 compiler.world.registerSideEffectsFree(element); 2380 compiler.world.registerSideEffectsFree(element);
2364 } 2381 }
2365 } 2382 }
2383 if (hasForceInline && hasNoInline) {
2384 compiler.internalError(element,
2385 "@ForceInline() must not be used with @NoInline.");
2386 }
2366 if (hasNoThrows && !hasNoInline) { 2387 if (hasNoThrows && !hasNoInline) {
2367 compiler.internalError(element, 2388 compiler.internalError(element,
2368 "@NoThrows() should always be combined with @NoInline."); 2389 "@NoThrows() should always be combined with @NoInline.");
2369 } 2390 }
2370 if (hasNoSideEffects && !hasNoInline) { 2391 if (hasNoSideEffects && !hasNoInline) {
2371 compiler.internalError(element, 2392 compiler.internalError(element,
2372 "@NoSideEffects() should always be combined with @NoInline."); 2393 "@NoSideEffects() should always be combined with @NoInline.");
2373 } 2394 }
2374 if (element == invokeOnMethod) { 2395 if (element == invokeOnMethod) {
2375 compiler.enabledInvokeOn = true; 2396 compiler.enabledInvokeOn = true;
(...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after
2706 } 2727 }
2707 } 2728 }
2708 2729
2709 /// Records that [constant] is used by the element behind [registry]. 2730 /// Records that [constant] is used by the element behind [registry].
2710 class Dependency { 2731 class Dependency {
2711 final ConstantValue constant; 2732 final ConstantValue constant;
2712 final Element annotatedElement; 2733 final Element annotatedElement;
2713 2734
2714 const Dependency(this.constant, this.annotatedElement); 2735 const Dependency(this.constant, this.annotatedElement);
2715 } 2736 }
OLDNEW
« 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