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

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: 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 * mustInline(function) implies canInline.
27 */ 28 */
28 class FunctionInlineCache { 29 class FunctionInlineCache {
29 final Map<FunctionElement, bool> canBeInlined = 30 static const int _mustNotInline = 0;
30 new Map<FunctionElement, bool>(); 31 // May-inline in loop means that we don't know yet.
32 static const int _mayInlineInLoop = 1;
33 static const int _canInlineInLoop = 2;
34 static const int _canInline = 3;
35 static const int _mustInline = 4;
31 36
32 final Map<FunctionElement, bool> canBeInlinedInsideLoop = 37 final Map<FunctionElement, int> _cachedDecisions =
33 new Map<FunctionElement, bool>(); 38 new Map<FunctionElement, int>();
34 39
35 // Returns [:true:]/[:false:] if we have a cached decision. 40 // Returns `true`/`false` if we have a cached decision.
36 // Returns [:null:] otherwise. 41 // Returns `null` otherwise.
37 bool canInline(FunctionElement element, {bool insideLoop}) { 42 bool canInline(FunctionElement element, {bool insideLoop}) {
38 return insideLoop ? canBeInlinedInsideLoop[element] : canBeInlined[element]; 43 int decision = _cachedDecisions[element];
44 if (decision == null) return null;
45 if (insideLoop) {
46 // We might be able to inline inside a loop, but don't know it yet.
47 if (decision == _mayInlineInLoop) return null;
48 return (decision >= _canInlineInLoop);
49 }
50 return decision >= _canInline;
51 }
52
53 bool mustInline(FunctionElement element) {
54 return _cachedDecisions[element] == _mustInline;
39 } 55 }
40 56
41 void markAsInlinable(FunctionElement element, {bool insideLoop}) { 57 void markAsInlinable(FunctionElement element, {bool insideLoop}) {
42 if (insideLoop) { 58 int oldDecision = _cachedDecisions[element];
43 canBeInlinedInsideLoop[element] = true; 59 assert(oldDecision != 0);
44 } else { 60 if (oldDecision == null) oldDecision = _mustNotInline;
45 // If we can inline a function outside a loop then we should do it inside 61
46 // a loop as well. 62 int newDecision = insideLoop ? _canInlineInLoop : _canInline;
47 canBeInlined[element] = true; 63
48 canBeInlinedInsideLoop[element] = true; 64 if (newDecision > oldDecision) {
65 _cachedDecisions[element] = newDecision;
49 } 66 }
50 } 67 }
51 68
52 void markAsNonInlinable(FunctionElement element, {bool insideLoop}) { 69 void markAsNonInlinable(FunctionElement element, {bool insideLoop}) {
70 assert(_cachedDecisions[element] != _mustInline);
71
53 if (insideLoop == null || insideLoop) { 72 if (insideLoop == null || insideLoop) {
Johnni Winther 2015/03/02 10:02:28 Why allow [insideLoop] to be null. Shouldn't the d
floitsch 2015/03/02 15:18:29 Done.
54 // If we can't inline a function inside a loop, then we should not inline 73 _cachedDecisions[element] = _mustNotInline;
55 // it outside a loop either.
56 canBeInlined[element] = false;
57 canBeInlinedInsideLoop[element] = false;
58 } else { 74 } else {
59 canBeInlined[element] = false; 75 // We can't inline outside a loop, but we might still be allowed to do it
76 // outside.
77 // If the cached decision already has a value we must not change it.
78 // Otherwise mark this function as potentially inlinable inside a loop.
79 int oldDecision = _cachedDecisions[element];
80 if (oldDecision == null) {
81 _cachedDecisions[element] = _mayInlineInLoop;
82 }
60 } 83 }
61 } 84 }
85
86 void markAsMustInline(FunctionElement element) {
87 _cachedDecisions[element] = _mustInline;
88 }
62 } 89 }
63 90
64 class JavaScriptBackend extends Backend { 91 class JavaScriptBackend extends Backend {
65 static final Uri DART_JS_HELPER = new Uri(scheme: 'dart', path: '_js_helper'); 92 static final Uri DART_JS_HELPER = new Uri(scheme: 'dart', path: '_js_helper');
66 static final Uri DART_INTERCEPTORS = 93 static final Uri DART_INTERCEPTORS =
67 new Uri(scheme: 'dart', path: '_interceptors'); 94 new Uri(scheme: 'dart', path: '_interceptors');
68 static final Uri DART_INTERNAL = 95 static final Uri DART_INTERNAL =
69 new Uri(scheme: 'dart', path: '_internal'); 96 new Uri(scheme: 'dart', path: '_internal');
70 static final Uri DART_FOREIGN_HELPER = 97 static final Uri DART_FOREIGN_HELPER =
71 new Uri(scheme: 'dart', path: '_foreign_helper'); 98 new Uri(scheme: 'dart', path: '_foreign_helper');
72 static final Uri DART_JS_MIRRORS = 99 static final Uri DART_JS_MIRRORS =
73 new Uri(scheme: 'dart', path: '_js_mirrors'); 100 new Uri(scheme: 'dart', path: '_js_mirrors');
74 static final Uri DART_JS_NAMES = 101 static final Uri DART_JS_NAMES =
75 new Uri(scheme: 'dart', path: '_js_names'); 102 new Uri(scheme: 'dart', path: '_js_names');
76 static final Uri DART_EMBEDDED_NAMES = 103 static final Uri DART_EMBEDDED_NAMES =
77 new Uri(scheme: 'dart', path: '_js_embedded_names'); 104 new Uri(scheme: 'dart', path: '_js_embedded_names');
78 static final Uri DART_ISOLATE_HELPER = 105 static final Uri DART_ISOLATE_HELPER =
79 new Uri(scheme: 'dart', path: '_isolate_helper'); 106 new Uri(scheme: 'dart', path: '_isolate_helper');
80 static final Uri DART_HTML = 107 static final Uri DART_HTML =
81 new Uri(scheme: 'dart', path: 'html'); 108 new Uri(scheme: 'dart', path: 'html');
82 109
83 static const String INVOKE_ON = '_getCachedInvocation'; 110 static const String INVOKE_ON = '_getCachedInvocation';
84 static const String START_ROOT_ISOLATE = 'startRootIsolate'; 111 static const String START_ROOT_ISOLATE = 'startRootIsolate';
85 112
86 113
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'; 114 String get patchVersion => USE_NEW_EMITTER ? 'new' : 'old';
96 115
97 final Annotations annotations = new Annotations(); 116 final Annotations annotations = new Annotations();
98 117
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. 118 /// Reference to the internal library to lookup functions to always inline.
104 LibraryElement internalLibrary; 119 LibraryElement internalLibrary;
105 120
106 121
107 /// Set of classes that need to be considered for reflection although not 122 /// Set of classes that need to be considered for reflection although not
108 /// otherwise visible during resolution. 123 /// otherwise visible during resolution.
109 Iterable<ClassElement> get classesRequiredForReflection { 124 Iterable<ClassElement> get classesRequiredForReflection {
110 // TODO(herhut): Clean this up when classes needed for rti are tracked. 125 // TODO(herhut): Clean this up when classes needed for rti are tracked.
111 return [closureClass, jsIndexableClass]; 126 return [closureClass, jsIndexableClass];
112 } 127 }
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
167 ClassElement typeLiteralClass; 182 ClassElement typeLiteralClass;
168 ClassElement mapLiteralClass; 183 ClassElement mapLiteralClass;
169 ClassElement constMapLiteralClass; 184 ClassElement constMapLiteralClass;
170 ClassElement typeVariableClass; 185 ClassElement typeVariableClass;
171 ConstructorElement mapLiteralConstructor; 186 ConstructorElement mapLiteralConstructor;
172 ConstructorElement mapLiteralConstructorEmpty; 187 ConstructorElement mapLiteralConstructorEmpty;
173 188
174 ClassElement noSideEffectsClass; 189 ClassElement noSideEffectsClass;
175 ClassElement noThrowsClass; 190 ClassElement noThrowsClass;
176 ClassElement noInlineClass; 191 ClassElement noInlineClass;
192 ClassElement forceInlineClass;
177 ClassElement irRepresentationClass; 193 ClassElement irRepresentationClass;
178 194
179 Element getInterceptorMethod; 195 Element getInterceptorMethod;
180 196
181 ClassElement jsInvocationMirrorClass; 197 ClassElement jsInvocationMirrorClass;
182 198
183 /// If [true], the compiler will emit code that writes the name of the current 199 /// 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 200 /// method together with its class and library to the console the first time
185 /// the method is called. 201 /// the method is called.
186 static const bool TRACE_CALLS = false; 202 static const bool TRACE_CALLS = false;
(...skipping 766 matching lines...) Expand 10 before | Expand all | Expand 10 after
953 assert(traceHelper != null); 969 assert(traceHelper != null);
954 enqueueInResolution(traceHelper, registry); 970 enqueueInResolution(traceHelper, registry);
955 } 971 }
956 registerCheckedModeHelpers(registry); 972 registerCheckedModeHelpers(registry);
957 } 973 }
958 974
959 onResolutionComplete() { 975 onResolutionComplete() {
960 super.onResolutionComplete(); 976 super.onResolutionComplete();
961 computeMembersNeededForReflection(); 977 computeMembersNeededForReflection();
962 rti.computeClassesNeedingRti(); 978 rti.computeClassesNeedingRti();
963 computeFunctionsToAlwaysInline();
964 }
965
966 void computeFunctionsToAlwaysInline() {
967 functionsToAlwaysInline = <FunctionElement>[];
968 if (internalLibrary == null) return;
969
970 // Try to find all functions intended to always inline. If their enclosing
971 // class is not resolved we skip the methods, but it is an error to mention
972 // a function or class that cannot be found.
973 for (String className in ALWAYS_INLINE.keys) {
974 ClassElement cls = find(internalLibrary, className);
975 if (cls.resolutionState != STATE_DONE) continue;
976 for (String functionName in ALWAYS_INLINE[className]) {
977 Element function = cls.lookupMember(functionName);
978 assert(invariant(cls, function is FunctionElement,
979 message: 'unable to find function $functionName in $className'));
980 functionsToAlwaysInline.add(function);
981 }
982 }
983 } 979 }
984 980
985 void registerGetRuntimeTypeArgument(Registry registry) { 981 void registerGetRuntimeTypeArgument(Registry registry) {
986 enqueueInResolution(getGetRuntimeTypeArgument(), registry); 982 enqueueInResolution(getGetRuntimeTypeArgument(), registry);
987 enqueueInResolution(getGetTypeArgumentByIndex(), registry); 983 enqueueInResolution(getGetTypeArgumentByIndex(), registry);
988 enqueueInResolution(getCopyTypeArguments(), registry); 984 enqueueInResolution(getCopyTypeArguments(), registry);
989 } 985 }
990 986
991 void registerCallMethodWithFreeTypeVariables( 987 void registerCallMethodWithFreeTypeVariables(
992 Element callMethod, 988 Element callMethod,
(...skipping 868 matching lines...) Expand 10 before | Expand all | Expand 10 after
1861 1857
1862 typeLiteralClass = findClass('TypeImpl'); 1858 typeLiteralClass = findClass('TypeImpl');
1863 constMapLiteralClass = findClass('ConstantMap'); 1859 constMapLiteralClass = findClass('ConstantMap');
1864 typeVariableClass = findClass('TypeVariable'); 1860 typeVariableClass = findClass('TypeVariable');
1865 1861
1866 jsIndexingBehaviorInterface = findClass('JavaScriptIndexingBehavior'); 1862 jsIndexingBehaviorInterface = findClass('JavaScriptIndexingBehavior');
1867 1863
1868 noSideEffectsClass = findClass('NoSideEffects'); 1864 noSideEffectsClass = findClass('NoSideEffects');
1869 noThrowsClass = findClass('NoThrows'); 1865 noThrowsClass = findClass('NoThrows');
1870 noInlineClass = findClass('NoInline'); 1866 noInlineClass = findClass('NoInline');
1867 forceInlineClass = findClass('ForceInline');
1871 irRepresentationClass = findClass('IrRepresentation'); 1868 irRepresentationClass = findClass('IrRepresentation');
1872 1869
1873 getIsolateAffinityTagMarker = findMethod('getIsolateAffinityTag'); 1870 getIsolateAffinityTagMarker = findMethod('getIsolateAffinityTag');
1874 1871
1875 requiresPreambleMarker = findMethod('requiresPreamble'); 1872 requiresPreambleMarker = findMethod('requiresPreamble');
1876 } else if (uri == DART_JS_MIRRORS) { 1873 } else if (uri == DART_JS_MIRRORS) {
1877 disableTreeShakingMarker = find(library, 'disableTreeShaking'); 1874 disableTreeShakingMarker = find(library, 'disableTreeShaking');
1878 preserveMetadataMarker = find(library, 'preserveMetadata'); 1875 preserveMetadataMarker = find(library, 'preserveMetadata');
1879 preserveUrisMarker = find(library, 'preserveUris'); 1876 preserveUrisMarker = find(library, 'preserveUris');
1880 preserveLibraryNamesMarker = find(library, 'preserveLibraryNames'); 1877 preserveLibraryNamesMarker = find(library, 'preserveLibraryNames');
(...skipping 436 matching lines...) Expand 10 before | Expand all | Expand 10 after
2317 } 2314 }
2318 2315
2319 void onElementResolved(Element element, TreeElements elements) { 2316 void onElementResolved(Element element, TreeElements elements) {
2320 if (element.isFunction && annotations.noInline(element)) { 2317 if (element.isFunction && annotations.noInline(element)) {
2321 inlineCache.markAsNonInlinable(element); 2318 inlineCache.markAsNonInlinable(element);
2322 } 2319 }
2323 2320
2324 LibraryElement library = element.library; 2321 LibraryElement library = element.library;
2325 if (!library.isPlatformLibrary && !library.canUseNative) return; 2322 if (!library.isPlatformLibrary && !library.canUseNative) return;
2326 bool hasNoInline = false; 2323 bool hasNoInline = false;
2324 bool hasForceInline = false;
2327 bool hasNoThrows = false; 2325 bool hasNoThrows = false;
2328 bool hasNoSideEffects = false; 2326 bool hasNoSideEffects = false;
2329 for (MetadataAnnotation metadata in element.metadata) { 2327 for (MetadataAnnotation metadata in element.metadata) {
2330 metadata.ensureResolved(compiler); 2328 metadata.ensureResolved(compiler);
2331 if (!metadata.constant.value.isConstructedObject) continue; 2329 if (!metadata.constant.value.isConstructedObject) continue;
2332 ObjectConstantValue value = metadata.constant.value; 2330 ObjectConstantValue value = metadata.constant.value;
2333 ClassElement cls = value.type.element; 2331 ClassElement cls = value.type.element;
2334 if (cls == noInlineClass) { 2332 if (cls == forceInlineClass) {
2333 hasForceInline = true;
2334 if (VERBOSE_OPTIMIZER_HINTS) {
2335 compiler.reportHint(element,
2336 MessageKind.GENERIC,
2337 {'text': "Must inline"});
2338 }
2339 inlineCache.markAsMustInline(element);
2340 } else if (cls == noInlineClass) {
2335 hasNoInline = true; 2341 hasNoInline = true;
2336 if (VERBOSE_OPTIMIZER_HINTS) { 2342 if (VERBOSE_OPTIMIZER_HINTS) {
2337 compiler.reportHint(element, 2343 compiler.reportHint(element,
2338 MessageKind.GENERIC, 2344 MessageKind.GENERIC,
2339 {'text': "Cannot inline"}); 2345 {'text': "Cannot inline"});
2340 } 2346 }
2341 inlineCache.markAsNonInlinable(element); 2347 inlineCache.markAsNonInlinable(element);
2342 } else if (cls == noThrowsClass) { 2348 } else if (cls == noThrowsClass) {
2343 hasNoThrows = true; 2349 hasNoThrows = true;
2344 if (!Elements.isStaticOrTopLevelFunction(element)) { 2350 if (!Elements.isStaticOrTopLevelFunction(element)) {
(...skipping 10 matching lines...) Expand all
2355 } else if (cls == noSideEffectsClass) { 2361 } else if (cls == noSideEffectsClass) {
2356 hasNoSideEffects = true; 2362 hasNoSideEffects = true;
2357 if (VERBOSE_OPTIMIZER_HINTS) { 2363 if (VERBOSE_OPTIMIZER_HINTS) {
2358 compiler.reportHint(element, 2364 compiler.reportHint(element,
2359 MessageKind.GENERIC, 2365 MessageKind.GENERIC,
2360 {'text': "Has no side effects"}); 2366 {'text': "Has no side effects"});
2361 } 2367 }
2362 compiler.world.registerSideEffectsFree(element); 2368 compiler.world.registerSideEffectsFree(element);
2363 } 2369 }
2364 } 2370 }
2371 if (hasForceInline && hasNoInline) {
2372 compiler.internalError(element,
2373 "@ForceInline() must not be used with @NoInline.");
2374 }
2365 if (hasNoThrows && !hasNoInline) { 2375 if (hasNoThrows && !hasNoInline) {
2366 compiler.internalError(element, 2376 compiler.internalError(element,
2367 "@NoThrows() should always be combined with @NoInline."); 2377 "@NoThrows() should always be combined with @NoInline.");
2368 } 2378 }
2369 if (hasNoSideEffects && !hasNoInline) { 2379 if (hasNoSideEffects && !hasNoInline) {
2370 compiler.internalError(element, 2380 compiler.internalError(element,
2371 "@NoSideEffects() should always be combined with @NoInline."); 2381 "@NoSideEffects() should always be combined with @NoInline.");
2372 } 2382 }
2373 if (element == invokeOnMethod) { 2383 if (element == invokeOnMethod) {
2374 compiler.enabledInvokeOn = true; 2384 compiler.enabledInvokeOn = true;
(...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after
2705 } 2715 }
2706 } 2716 }
2707 2717
2708 /// Records that [constant] is used by the element behind [registry]. 2718 /// Records that [constant] is used by the element behind [registry].
2709 class Dependency { 2719 class Dependency {
2710 final ConstantValue constant; 2720 final ConstantValue constant;
2711 final Element annotatedElement; 2721 final Element annotatedElement;
2712 2722
2713 const Dependency(this.constant, this.annotatedElement); 2723 const Dependency(this.constant, this.annotatedElement);
2714 } 2724 }
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