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

Side by Side Diff: lib/compiler/implementation/js_backend/backend.dart

Issue 10908068: Better tracking of provided types at call sites (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Rebase again Created 8 years, 3 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
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 typedef void Recompile(Element element); 5 typedef void Recompile(Element element);
6 6
7 class ReturnInfo { 7 class ReturnInfo {
8 HType returnType; 8 HType returnType;
9 List<Element> compiledFunctions; 9 List<Element> compiledFunctions;
10 10
(...skipping 18 matching lines...) Expand all
29 } 29 }
30 compiledFunctions.clear(); 30 compiledFunctions.clear();
31 } 31 }
32 } 32 }
33 33
34 // Note that lazy initializers are treated like functions (but are not 34 // Note that lazy initializers are treated like functions (but are not
35 // of type [FunctionElement]. 35 // of type [FunctionElement].
36 addCompiledFunction(Element function) => compiledFunctions.add(function); 36 addCompiledFunction(Element function) => compiledFunctions.add(function);
37 } 37 }
38 38
39 class OptionalParameterTypes {
40 final List<SourceString> names;
41 final List<HType> types;
42
43 OptionalParameterTypes(int optionalArgumentsCount)
44 : names = new List<SourceString>(optionalArgumentsCount),
45 types = new List<HType>(optionalArgumentsCount);
46
47 int get length => names.length;
48 SourceString name(int index) => names[index];
49 HType type(int index) => types[index];
50 int indexOf(SourceString name) => names.indexOf(name);
51
52 HType typeFor(SourceString name) {
53 int index = indexOf(name);
54 if (index == -1) return null;
55 return type(index);
56 }
57
58 void update(int index, SourceString name, HType type) {
59 names[index] = name;
60 types[index] = type;
61 }
62
63 String toString() => "OptionalParameterTypes($names, $types)";
64 }
65
39 class HTypeList { 66 class HTypeList {
40 final List<HType> types; 67 final List<HType> types;
68 final List<SourceString> namedArguments;
41 69
42 HTypeList(int length) : types = new List<HType>(length); 70 HTypeList(int length)
43 const HTypeList.withAllUnknown() : types = null; 71 : types = new List<HType>(length),
72 namedArguments = null;
73 HTypeList.withNamedArguments(int length, this.namedArguments)
74 : types = new List<HType>(length);
75 const HTypeList.allUnknown()
76 : types = null,
77 namedArguments = null;
44 78
45 factory HTypeList.fromInvocation(HInvoke node, HTypeMap types) { 79 factory HTypeList.fromStaticInvocation(HInvokeStatic node, HTypeMap types) {
46 bool allUnknown = true; 80 bool allUnknown = true;
47 for (int i = 1; i < node.inputs.length; i++) { 81 for (int i = 1; i < node.inputs.length; i++) {
48 if (types[node.inputs[i]] != HType.UNKNOWN) { 82 if (types[node.inputs[i]] != HType.UNKNOWN) {
49 allUnknown = false; 83 allUnknown = false;
50 break; 84 break;
51 } 85 }
52 } 86 }
53 if (allUnknown) return HTypeList.ALL_UNKNOWN; 87 if (allUnknown) return HTypeList.ALL_UNKNOWN;
54 88
55 HTypeList result = new HTypeList(node.inputs.length - 1); 89 HTypeList result = new HTypeList(node.inputs.length - 1);
56 for (int i = 0; i < result.types.length; i++) { 90 for (int i = 0; i < result.types.length; i++) {
57 result.types[i] = types[node.inputs[i + 1]]; 91 result.types[i] = types[node.inputs[i + 1]];
58 } 92 }
59 return result; 93 return result;
60 } 94 }
61 95
62 static const HTypeList ALL_UNKNOWN = const HTypeList.withAllUnknown(); 96 factory HTypeList.fromDynamicInvocation(HInvokeDynamic node,
97 Selector selector,
98 HTypeMap types) {
99 HTypeList result;
100 int argumentsCount = node.inputs.length - 1;
101 if (selector.namedArgumentCount > 0) {
102 result =
103 new HTypeList.withNamedArguments(
104 argumentsCount, selector.namedArguments);
105 } else {
106 result = new HTypeList(argumentsCount);
107 }
108 for (int i = 0; i < result.types.length; i++) {
109 result.types[i] = types[node.inputs[i + 1]];
110 }
111 return result;
112 }
113
114 static const HTypeList ALL_UNKNOWN = const HTypeList.allUnknown();
63 115
64 bool get allUnknown => types === null; 116 bool get allUnknown => types === null;
117 bool get hasNamedArguments => namedArguments != null;
65 int get length => types.length; 118 int get length => types.length;
66 HType operator[](int index) => types[index]; 119 HType operator[](int index) => types[index];
67 120
68 HTypeList union(HTypeList other) { 121 HTypeList union(HTypeList other) {
69 if (allUnknown) return this; 122 if (allUnknown) return this;
70 if (other.allUnknown) return other; 123 if (other.allUnknown) return other;
71 if (length != other.length) return HTypeList.ALL_UNKNOWN; 124 if (length != other.length) return HTypeList.ALL_UNKNOWN;
72 bool onlyUnknown = true; 125 bool onlyUnknown = true;
73 HTypeList result = this; 126 HTypeList result = this;
74 for (int i = 0; i < length; i++) { 127 for (int i = 0; i < length; i++) {
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
111 result.types.setRange(0, i, this.types); 164 result.types.setRange(0, i, this.types);
112 } 165 }
113 if (result != this) { 166 if (result != this) {
114 result.types[i] = newType; 167 result.types[i] = newType;
115 } 168 }
116 if (result[i] != HType.UNKNOWN) onlyUnknown = false; 169 if (result[i] != HType.UNKNOWN) onlyUnknown = false;
117 } 170 }
118 return onlyUnknown ? HTypeList.ALL_UNKNOWN : result; 171 return onlyUnknown ? HTypeList.ALL_UNKNOWN : result;
119 } 172 }
120 173
174 HTypeList unionWithOptionalParameters(
175 Selector selector,
176 FunctionSignature signature,
177 OptionalParameterTypes defaultValueTypes) {
178 assert(allUnknown || selector.argumentCount == this.length);
179 // Create a new HTypeList for holding types for all parameters.
180 HTypeList result = new HTypeList(signature.parameterCount);
181
182 // First fill in the type of the positional arguments.
183 int nextTypeIndex = -1;
184 if (allUnknown) {
185 for (int i = 0; i < selector.positionalArgumentCount; i++) {
186 result.types[i] = HType.UNKNOWN;
187 }
188 } else {
189 result.types.setRange(0, selector.positionalArgumentCount, this.types);
190 nextTypeIndex = selector.positionalArgumentCount;
191 }
192
193 // Next fill the type of the optional arguments.
194 // As the selector can pass optional arguments positionally some of the
195 // optional arguments might already have a type set. We only need to look
196 // at the optional arguments not passed positionally.
197 // The variable 'index' is counting the signatures optional arguments, the
198 // variable 'next' is set to the next optional arguments to look at and
199 // is used to skip some optional arguments.
200 int next = selector.positionalArgumentCount;
201 int index = signature.requiredParameterCount;
202 signature.forEachOptionalParameter((Element element) {
203 // If some optional parameters were passed positionally these have
204 // already been filled.
205 if (index == next) {
206 assert(result.types[index] === null);
207 HType type = null;
208 if (hasNamedArguments &&
209 selector.namedArguments.indexOf(element.name) >= 0) {
210 type = types[nextTypeIndex++];
211 } else {
212 type = defaultValueTypes.typeFor(element.name);
213 }
214 result.types[index] = type;
215 next++;
216 }
217 index++;
218 });
219 return result;
220 }
221
121 String toString() => 222 String toString() =>
122 allUnknown ? "HTypeList.ALL_UNKNOWN" : "HTypeList $types"; 223 allUnknown ? "HTypeList.ALL_UNKNOWN" : "HTypeList $types";
123 } 224 }
124 225
125 class ArgumentTypesRegistry { 226 class ArgumentTypesRegistry {
126 final JavaScriptBackend backend; 227 final JavaScriptBackend backend;
127 final Map<Element, HTypeList> staticTypeMap; 228 final Map<Element, HTypeList> staticTypeMap;
128 final Set<Element> optimizedStaticFunctions; 229 final Set<Element> optimizedStaticFunctions;
129 final SelectorMap<HTypeList> selectorTypeMap; 230 final SelectorMap<HTypeList> selectorTypeMap;
130 final FunctionSet optimizedFunctions; 231 final FunctionSet optimizedFunctions;
131 final Map<Element, HTypeList> optimizedTypes; 232 final Map<Element, HTypeList> optimizedTypes;
233 final Map<Element, OptionalParameterTypes> optimizedDefaultValueTypes;
132 234
133 ArgumentTypesRegistry(JavaScriptBackend backend) 235 ArgumentTypesRegistry(JavaScriptBackend backend)
134 : staticTypeMap = new Map<Element, HTypeList>(), 236 : staticTypeMap = new Map<Element, HTypeList>(),
135 optimizedStaticFunctions = new Set<Element>(), 237 optimizedStaticFunctions = new Set<Element>(),
136 selectorTypeMap = new SelectorMap<HTypeList>(backend.compiler), 238 selectorTypeMap = new SelectorMap<HTypeList>(backend.compiler),
137 optimizedFunctions = new FunctionSet(backend.compiler), 239 optimizedFunctions = new FunctionSet(backend.compiler),
138 optimizedTypes = new Map<Element, HTypeList>(), 240 optimizedTypes = new Map<Element, HTypeList>(),
241 optimizedDefaultValueTypes =
242 new Map<Element, OptionalParameterTypes>(),
139 this.backend = backend; 243 this.backend = backend;
140 244
141 Compiler get compiler => backend.compiler; 245 Compiler get compiler => backend.compiler;
142 246
143 // Gather the type information provided. If the types contains no
144 // useful information there is no need to actually store them.
145 HTypeList computeProvidedTypes(HInvoke node, HTypeMap types) {
146 return new HTypeList.fromInvocation(node, types);
147 }
148
149 void registerStaticInvocation(HInvokeStatic node, HTypeMap types) { 247 void registerStaticInvocation(HInvokeStatic node, HTypeMap types) {
150 Element element = node.element; 248 Element element = node.element;
151 HTypeList oldTypes = staticTypeMap[element]; 249 HTypeList oldTypes = staticTypeMap[element];
152 if (oldTypes == null) { 250 if (oldTypes == null) {
153 staticTypeMap[element] = computeProvidedTypes(node, types); 251 staticTypeMap[element] = new HTypeList.fromStaticInvocation(node, types);
154 } else { 252 } else {
155 if (oldTypes.allUnknown) return; 253 if (oldTypes.allUnknown) return;
156 HTypeList newTypes = oldTypes.unionWithInvoke(node, types); 254 HTypeList newTypes = oldTypes.unionWithInvoke(node, types);
157 if (newTypes === oldTypes) return; 255 if (newTypes === oldTypes) return;
158 staticTypeMap[element] = newTypes; 256 staticTypeMap[element] = newTypes;
159 if (optimizedStaticFunctions.contains(element)) { 257 if (optimizedStaticFunctions.contains(element)) {
160 backend.scheduleForRecompilation(element); 258 backend.scheduleForRecompilation(element);
161 } 259 }
162 } 260 }
163 } 261 }
(...skipping 17 matching lines...) Expand all
181 // TODO(sgjesse): These checks should use the codegenWorld and keep track 279 // TODO(sgjesse): These checks should use the codegenWorld and keep track
182 // of changes to this information. 280 // of changes to this information.
183 Element element = node.element; 281 Element element = node.element;
184 Universe resolverWorld = compiler.resolverWorld; 282 Universe resolverWorld = compiler.resolverWorld;
185 if (element != null && 283 if (element != null &&
186 (resolverWorld.hasFieldGetter(element, compiler) || 284 (resolverWorld.hasFieldGetter(element, compiler) ||
187 resolverWorld.hasInvokedGetter(element, compiler))) { 285 resolverWorld.hasInvokedGetter(element, compiler))) {
188 return; 286 return;
189 } 287 }
190 288
191 // TODO(kasperl): For now, we're only dealing with non-named arguments. 289 HTypeList providedTypes =
192 // We should generalize this. 290 new HTypeList.fromDynamicInvocation(node, selector, types);
193 HTypeList providedTypes = selector.namedArguments.isEmpty()
194 ? computeProvidedTypes(node, types)
195 : HTypeList.ALL_UNKNOWN;
196 if (!selectorTypeMap.containsKey(selector)) { 291 if (!selectorTypeMap.containsKey(selector)) {
197 selectorTypeMap[selector] = providedTypes; 292 selectorTypeMap[selector] = providedTypes;
198 } else { 293 } else {
199 HTypeList oldTypes = selectorTypeMap[selector]; 294 HTypeList oldTypes = selectorTypeMap[selector];
200 HTypeList newTypes = oldTypes.unionWithInvoke(node, types); 295 HTypeList newTypes = oldTypes.unionWithInvoke(node, types);
201 if (newTypes === oldTypes) return; 296 if (newTypes === oldTypes) return;
202 selectorTypeMap[selector] = newTypes; 297 selectorTypeMap[selector] = newTypes;
203 } 298 }
204 299
205 // If we're not compiling, we don't have to do anything. 300 // If we're not compiling, we don't have to do anything.
206 if (compiler.phase != Compiler.PHASE_COMPILING) return; 301 if (compiler.phase != Compiler.PHASE_COMPILING) return;
207 302
208 // Run through all optimized functions and figure out if they need 303 // Run through all optimized functions and figure out if they need
209 // to be recompiled because of this new invocation. 304 // to be recompiled because of this new invocation.
210 optimizedFunctions.filterBySelector(selector).forEach((Element element) { 305 optimizedFunctions.filterBySelector(selector).forEach((Element element) {
211 // TODO(kasperl): Maybe check if the element is already marked for 306 // TODO(kasperl): Maybe check if the element is already marked for
212 // recompilation? Could be pretty cheap compared to computing 307 // recompilation? Could be pretty cheap compared to computing
213 // union types. 308 // union types.
214 HTypeList newTypes = parameterTypes(element); 309 HTypeList newTypes =
310 parameterTypes(element, optimizedDefaultValueTypes[element]);
215 bool recompile = false; 311 bool recompile = false;
216 if (newTypes.allUnknown) { 312 if (newTypes.allUnknown) {
217 recompile = true; 313 recompile = true;
218 } else { 314 } else {
219 HTypeList oldTypes = optimizedTypes[element]; 315 HTypeList oldTypes = optimizedTypes[element];
220 if (newTypes.length != oldTypes.length) { 316 assert(newTypes.length == oldTypes.length);
221 // TODO(kasperl): This can be improved. If the newTypes aren't in 317 for (int i = 0; i < oldTypes.length; i++) {
222 // conflict we can avoid the recompilation.
223 recompile = true;
224 } else for (int i = 0; i < oldTypes.length; i++) {
225 if (newTypes[i] != oldTypes[i]) { 318 if (newTypes[i] != oldTypes[i]) {
226 recompile = true; 319 recompile = true;
227 break; 320 break;
228 } 321 }
229 } 322 }
230 } 323 }
231 if (recompile) backend.scheduleForRecompilation(element); 324 if (recompile) backend.scheduleForRecompilation(element);
232 }); 325 });
233 } 326 }
234 327
235 HTypeList parameterTypes(element) { 328 HTypeList parameterTypes(FunctionElement element,
329 OptionalParameterTypes defaultValueTypes) {
236 // Handle static functions separately. 330 // Handle static functions separately.
237 if (Elements.isStaticOrTopLevelFunction(element)) { 331 if (Elements.isStaticOrTopLevelFunction(element)) {
238 HTypeList types = staticTypeMap[element]; 332 HTypeList types = staticTypeMap[element];
239 if (types !== null) { 333 if (types !== null) {
240 if (!optimizedStaticFunctions.contains(element)) { 334 if (!optimizedStaticFunctions.contains(element)) {
241 optimizedStaticFunctions.add(element); 335 optimizedStaticFunctions.add(element);
242 } 336 }
243 return types; 337 return types;
244 } else { 338 } else {
245 return HTypeList.ALL_UNKNOWN; 339 return HTypeList.ALL_UNKNOWN;
246 } 340 }
247 } 341 }
248 342
343 // Getters have no parameters.
344 if (element.isGetter()) return HTypeList.ALL_UNKNOWN;
345
249 // TODO(kasperl): What kind of non-members do we get here? 346 // TODO(kasperl): What kind of non-members do we get here?
250 if (!element.isMember()) return HTypeList.ALL_UNKNOWN; 347 if (!element.isMember()) return HTypeList.ALL_UNKNOWN;
251 348
252 FunctionSignature signature = element.computeSignature(compiler); 349 FunctionSignature signature = element.computeSignature(compiler);
253 HTypeList found = null; 350 HTypeList found = null;
254 selectorTypeMap.visitMatching(element, 351 selectorTypeMap.visitMatching(element,
255 (Selector selector, HTypeList types) { 352 (Selector selector, HTypeList types) {
256 if (selector.argumentCount != signature.parameterCount) { 353 if (selector.argumentCount != signature.parameterCount ||
257 found = HTypeList.ALL_UNKNOWN; 354 selector.namedArgumentCount > 0) {
258 return false; 355 types = types.unionWithOptionalParameters(selector,
259 } else if (found === null) { 356 signature,
260 found = types; 357 defaultValueTypes);
261 return true;
262 } else {
263 found = found.union(types);
264 return !found.allUnknown;
265 } 358 }
359 assert(types.allUnknown || types.length == signature.parameterCount);
360 found = (found === null) ? types : found.union(types);
361 return !found.allUnknown;
266 }); 362 });
267 return found !== null ? found : HTypeList.ALL_UNKNOWN; 363 return found !== null ? found : HTypeList.ALL_UNKNOWN;
268 } 364 }
269 365
270 void registerOptimization(Element element, HTypeList parameterTypes) { 366 void registerOptimization(Element element,
367 HTypeList parameterTypes,
368 OptionalParameterTypes defaultValueTypes) {
271 if (Elements.isStaticOrTopLevelFunction(element)) { 369 if (Elements.isStaticOrTopLevelFunction(element)) {
272 if (parameterTypes.allUnknown) { 370 if (parameterTypes.allUnknown) {
273 optimizedStaticFunctions.remove(element); 371 optimizedStaticFunctions.remove(element);
274 } else { 372 } else {
275 optimizedStaticFunctions.add(element); 373 optimizedStaticFunctions.add(element);
276 } 374 }
277 } 375 }
278 376
279 // TODO(kasperl): What kind of non-members do we get here? 377 // TODO(kasperl): What kind of non-members do we get here?
280 if (!element.isMember()) return; 378 if (!element.isMember()) return;
281 379
282 if (parameterTypes.allUnknown) { 380 if (parameterTypes.allUnknown) {
283 optimizedFunctions.remove(element); 381 optimizedFunctions.remove(element);
284 optimizedTypes.remove(element); 382 optimizedTypes.remove(element);
383 optimizedDefaultValueTypes.remove(element);
285 } else { 384 } else {
286 optimizedFunctions.add(element); 385 optimizedFunctions.add(element);
287 optimizedTypes[element] = parameterTypes; 386 optimizedTypes[element] = parameterTypes;
387 optimizedDefaultValueTypes[element] = defaultValueTypes;
288 } 388 }
289 } 389 }
290 } 390 }
291 391
292 class JavaScriptItemCompilationContext extends ItemCompilationContext { 392 class JavaScriptItemCompilationContext extends ItemCompilationContext {
293 final HTypeMap types; 393 final HTypeMap types;
294 394
295 JavaScriptItemCompilationContext() : types = new HTypeMap(); 395 JavaScriptItemCompilationContext() : types = new HTypeMap();
296 } 396 }
297 397
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after
515 */ 615 */
516 void registerNonCallStaticUse(HStatic node) { 616 void registerNonCallStaticUse(HStatic node) {
517 argumentTypes.registerNonCallStaticUse(node); 617 argumentTypes.registerNonCallStaticUse(node);
518 } 618 }
519 619
520 /** 620 /**
521 * Retrieve the types of the parameters used for calling the [element] 621 * Retrieve the types of the parameters used for calling the [element]
522 * function. The types are optimistic in the sense as they are based on the 622 * function. The types are optimistic in the sense as they are based on the
523 * possible invocations of the function seen so far. 623 * possible invocations of the function seen so far.
524 */ 624 */
525 HTypeList optimisticParameterTypes(FunctionElement element) { 625 HTypeList optimisticParameterTypes(
526 return argumentTypes.parameterTypes(element); 626 FunctionElement element,
627 OptionalParameterTypes defaultValueTypes) {
628 return argumentTypes.parameterTypes(element, defaultValueTypes);
527 } 629 }
528 630
529 /** 631 /**
530 * Register that the function [element] has been optimized under the 632 * Register that the function [element] has been optimized under the
531 * assumptions that the types [parameterType] will be used for calling it. 633 * assumptions that the types [parameterType] will be used for calling it.
532 * If this assumption fail the function will be scheduled for recompilation. 634 * The passed [defaultValueTypes] holds the types of default values for
635 * the optional parameters. If this assumption fail the function will be
636 * scheduled for recompilation.
533 */ 637 */
534 registerParameterTypesOptimization( 638 registerParameterTypesOptimization(
535 FunctionElement element, HTypeList parameterTypes) { 639 FunctionElement element,
536 argumentTypes.registerOptimization(element, parameterTypes); 640 HTypeList parameterTypes,
641 OptionalParameterTypes defaultValueTypes) {
642 argumentTypes.registerOptimization(
643 element, parameterTypes, defaultValueTypes);
537 } 644 }
538 645
539 void registerReturnType(FunctionElement element, HType returnType) { 646 void registerReturnType(FunctionElement element, HType returnType) {
540 ReturnInfo info = returnInfo[element]; 647 ReturnInfo info = returnInfo[element];
541 if (info != null) { 648 if (info != null) {
542 info.update(returnType, scheduleForRecompilation); 649 info.update(returnType, scheduleForRecompilation);
543 } else { 650 } else {
544 returnInfo[element] = new ReturnInfo(returnType); 651 returnInfo[element] = new ReturnInfo(returnType);
545 } 652 }
546 } 653 }
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
594 return const SourceString('listSuperTypeCheck'); 701 return const SourceString('listSuperTypeCheck');
595 } 702 }
596 } else if (nativeCheck) { 703 } else if (nativeCheck) {
597 return const SourceString('callTypeCheck'); 704 return const SourceString('callTypeCheck');
598 } else { 705 } else {
599 return const SourceString('propertyTypeCheck'); 706 return const SourceString('propertyTypeCheck');
600 } 707 }
601 } 708 }
602 } 709 }
603 } 710 }
OLDNEW
« no previous file with comments | « lib/compiler/implementation/elements/elements.dart ('k') | lib/compiler/implementation/ssa/builder.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698