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

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: Addressed review comments 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 17 matching lines...) Expand all
28 compiledFunctions.forEach(recompile); 28 compiledFunctions.forEach(recompile);
29 } 29 }
30 compiledFunctions.clear(); 30 compiledFunctions.clear();
31 } 31 }
32 } 32 }
33 33
34 addCompiledFunction(FunctionElement function) => 34 addCompiledFunction(FunctionElement function) =>
35 compiledFunctions.add(function); 35 compiledFunctions.add(function);
36 } 36 }
37 37
38 class OptionalParameterTypes {
39 final List<SourceString> names;
40 final List<HType> types;
41
42 OptionalParameterTypes(int optionalArgumentsCount)
43 : names = new List<SourceString>(optionalArgumentsCount),
44 types = new List<HType>(optionalArgumentsCount);
45
46 int get length => names.length;
47 SourceString name(int index) => names[index];
48 HType type(int index) => types[index];
49 int indexOf(SourceString name) => names.indexOf(name);
50
51 HType typeFor(SourceString name) {
52 int index = indexOf(name);
53 if (index == -1) return null;
54 return type(index);
55 }
56
57 void update(int index, SourceString name, HType type) {
58 names[index] = name;
59 types[index] = type;
60 }
61
62 String toString() => "OptionalParameterTypes($names, $types)";
63 }
64
38 class HTypeList { 65 class HTypeList {
39 final List<HType> types; 66 final List<HType> types;
67 final List<SourceString> namedArguments;
40 68
41 HTypeList(int length) : types = new List<HType>(length); 69 HTypeList(int length)
42 const HTypeList.allUnknown() : types = null; 70 : types = new List<HType>(length),
71 namedArguments = null;
72 HTypeList.withNamedArguments(int length, this.namedArguments)
73 : types = new List<HType>(length);
74 const HTypeList.allUnknown()
75 : types = null,
76 namedArguments = null;
43 77
44 factory HTypeList.fromInvocation(HInvoke node, HTypeMap types) { 78 factory HTypeList.fromStaticInvocation(HInvokeStatic node, HTypeMap types) {
45 bool allUnknown = true; 79 bool allUnknown = true;
46 for (int i = 1; i < node.inputs.length; i++) { 80 for (int i = 1; i < node.inputs.length; i++) {
47 if (types[node.inputs[i]] != HType.UNKNOWN) { 81 if (types[node.inputs[i]] != HType.UNKNOWN) {
48 allUnknown = false; 82 allUnknown = false;
49 break; 83 break;
50 } 84 }
51 } 85 }
52 if (allUnknown) return HTypeList.ALL_UNKNOWN; 86 if (allUnknown) return HTypeList.ALL_UNKNOWN;
53 87
54 HTypeList result = new HTypeList(node.inputs.length - 1); 88 HTypeList result = new HTypeList(node.inputs.length - 1);
55 for (int i = 0; i < result.types.length; i++) { 89 for (int i = 0; i < result.types.length; i++) {
56 result.types[i] = types[node.inputs[i + 1]]; 90 result.types[i] = types[node.inputs[i + 1]];
57 } 91 }
58 return result; 92 return result;
59 } 93 }
60 94
95 factory HTypeList.fromDynamicInvocation(HInvokeDynamic node,
96 Selector selector,
97 HTypeMap types) {
98 HTypeList result;
99 int argumentsCount = node.inputs.length - 1;
100 if (selector.namedArgumentCount > 0) {
101 result =
102 new HTypeList.withNamedArguments(
103 argumentsCount, selector.namedArguments);
104 } else {
105 result = new HTypeList(argumentsCount);
106 }
107 for (int i = 0; i < result.types.length; i++) {
108 result.types[i] = types[node.inputs[i + 1]];
109 }
110 return result;
111 }
112
61 static const HTypeList ALL_UNKNOWN = const HTypeList.allUnknown(); 113 static const HTypeList ALL_UNKNOWN = const HTypeList.allUnknown();
62 114
63 bool get allUnknown => types === null; 115 bool get allUnknown => types === null;
116 bool get hasNamedArguments => namedArguments != null;
64 int get length => types.length; 117 int get length => types.length;
65 HType operator[](int index) => types[index]; 118 HType operator[](int index) => types[index];
66 119
67 HTypeList union(HTypeList other) { 120 HTypeList union(HTypeList other) {
68 if (allUnknown) return this; 121 if (allUnknown) return this;
69 if (other.allUnknown) return other; 122 if (other.allUnknown) return other;
70 if (length != other.length) return HTypeList.ALL_UNKNOWN; 123 if (length != other.length) return HTypeList.ALL_UNKNOWN;
71 bool onlyUnknown = true; 124 bool onlyUnknown = true;
72 HTypeList result = this; 125 HTypeList result = this;
73 for (int i = 0; i < length; i++) { 126 for (int i = 0; i < length; i++) {
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
110 result.types.setRange(0, i, this.types); 163 result.types.setRange(0, i, this.types);
111 } 164 }
112 if (result != this) { 165 if (result != this) {
113 result.types[i] = newType; 166 result.types[i] = newType;
114 } 167 }
115 if (result[i] != HType.UNKNOWN) onlyUnknown = false; 168 if (result[i] != HType.UNKNOWN) onlyUnknown = false;
116 } 169 }
117 return onlyUnknown ? HTypeList.ALL_UNKNOWN : result; 170 return onlyUnknown ? HTypeList.ALL_UNKNOWN : result;
118 } 171 }
119 172
173 HTypeList unionWithOptionalParameters(
174 Selector selector,
175 FunctionSignature signature,
176 OptionalParameterTypes defaultValueTypes) {
177 assert(allUnknown || selector.argumentCount == this.length);
178 // Create a new HTypeList for holding types for all parameters.
179 HTypeList result = new HTypeList(signature.parameterCount);
180
181 // First fill in the type of the positional arguments.
182 int nextTypeIndex = -1;
183 if (allUnknown) {
184 for (int i = 0; i < selector.positionalArgumentCount; i++) {
185 result.types[i] = HType.UNKNOWN;
186 }
187 } else {
188 result.types.setRange(0, selector.positionalArgumentCount, this.types);
189 nextTypeIndex = selector.positionalArgumentCount;
190 }
191 int next = selector.positionalArgumentCount; // Next parameter of interest.
kasperl 2012/09/05 07:06:29 Maybe add a newline and a new comment that explain
Søren Gjesse 2012/09/05 08:02:59 Done.
192 int index = signature.requiredParameterCount; // Current parameter.
193 signature.forEachOptionalParameter((Element element) {
194 // If some optional parameters were passed positionally these have
195 // already been filled.
196 if (index == next) {
197 assert(result.types[index] === null);
198 HType type = null;
199 if (hasNamedArguments &&
200 selector.namedArguments.indexOf(element.name) >= 0) {
201 type = types[nextTypeIndex++];
202 } else {
203 type = defaultValueTypes.typeFor(element.name);
204 }
205 result.types[index] = type;
206 next++;
207 }
208 index++;
209 });
210 return result;
211 }
212
120 String toString() => 213 String toString() =>
121 allUnknown ? "HTypeList.ALL_UNKNOWN" : "HTypeList $types"; 214 allUnknown ? "HTypeList.ALL_UNKNOWN" : "HTypeList $types";
122 } 215 }
123 216
124 class ArgumentTypesRegistry { 217 class ArgumentTypesRegistry {
125 final JavaScriptBackend backend; 218 final JavaScriptBackend backend;
126 final Map<Element, HTypeList> staticTypeMap; 219 final Map<Element, HTypeList> staticTypeMap;
127 final Set<Element> optimizedStaticFunctions; 220 final Set<Element> optimizedStaticFunctions;
128 final SelectorMap<HTypeList> selectorTypeMap; 221 final SelectorMap<HTypeList> selectorTypeMap;
129 final FunctionSet optimizedFunctions; 222 final FunctionSet optimizedFunctions;
130 final Map<Element, HTypeList> optimizedTypes; 223 final Map<Element, HTypeList> optimizedTypes;
224 final Map<Element, OptionalParameterTypes> optimizedDefaultValueTypes;
131 225
132 ArgumentTypesRegistry(JavaScriptBackend backend) 226 ArgumentTypesRegistry(JavaScriptBackend backend)
133 : staticTypeMap = new Map<Element, HTypeList>(), 227 : staticTypeMap = new Map<Element, HTypeList>(),
134 optimizedStaticFunctions = new Set<Element>(), 228 optimizedStaticFunctions = new Set<Element>(),
135 selectorTypeMap = new SelectorMap<HTypeList>(backend.compiler), 229 selectorTypeMap = new SelectorMap<HTypeList>(backend.compiler),
136 optimizedFunctions = new FunctionSet(backend.compiler), 230 optimizedFunctions = new FunctionSet(backend.compiler),
137 optimizedTypes = new Map<Element, HTypeList>(), 231 optimizedTypes = new Map<Element, HTypeList>(),
232 optimizedDefaultValueTypes =
233 new Map<Element, OptionalParameterTypes>(),
138 this.backend = backend; 234 this.backend = backend;
139 235
140 Compiler get compiler => backend.compiler; 236 Compiler get compiler => backend.compiler;
141 237
142 // Gather the type information provided. If the types contains no
143 // useful information there is no need to actually store them.
144 HTypeList computeProvidedTypes(HInvoke node, HTypeMap types) {
145 return new HTypeList.fromInvocation(node, types);
146 }
147
148 void registerStaticInvocation(HInvokeStatic node, HTypeMap types) { 238 void registerStaticInvocation(HInvokeStatic node, HTypeMap types) {
149 Element element = node.element; 239 Element element = node.element;
150 HTypeList oldTypes = staticTypeMap[element]; 240 HTypeList oldTypes = staticTypeMap[element];
151 if (oldTypes == null) { 241 if (oldTypes == null) {
152 staticTypeMap[element] = computeProvidedTypes(node, types); 242 staticTypeMap[element] = new HTypeList.fromStaticInvocation(node, types);
153 } else { 243 } else {
154 if (oldTypes.allUnknown) return; 244 if (oldTypes.allUnknown) return;
155 HTypeList newTypes = oldTypes.unionWithInvoke(node, types); 245 HTypeList newTypes = oldTypes.unionWithInvoke(node, types);
156 if (newTypes === oldTypes) return; 246 if (newTypes === oldTypes) return;
157 staticTypeMap[element] = newTypes; 247 staticTypeMap[element] = newTypes;
158 if (optimizedStaticFunctions.contains(element)) { 248 if (optimizedStaticFunctions.contains(element)) {
159 backend.scheduleForRecompilation(element); 249 backend.scheduleForRecompilation(element);
160 } 250 }
161 } 251 }
162 } 252 }
(...skipping 17 matching lines...) Expand all
180 // TODO(sgjesse): These checks should use the codegenWorld and keep track 270 // TODO(sgjesse): These checks should use the codegenWorld and keep track
181 // of changes to this information. 271 // of changes to this information.
182 Element element = node.element; 272 Element element = node.element;
183 Universe resolverWorld = compiler.resolverWorld; 273 Universe resolverWorld = compiler.resolverWorld;
184 if (element != null && 274 if (element != null &&
185 (resolverWorld.hasFieldGetter(element, compiler) || 275 (resolverWorld.hasFieldGetter(element, compiler) ||
186 resolverWorld.hasInvokedGetter(element, compiler))) { 276 resolverWorld.hasInvokedGetter(element, compiler))) {
187 return; 277 return;
188 } 278 }
189 279
190 // TODO(kasperl): For now, we're only dealing with non-named arguments. 280 HTypeList providedTypes =
191 // We should generalize this. 281 new HTypeList.fromDynamicInvocation(node, selector, types);
192 HTypeList providedTypes = selector.namedArguments.isEmpty()
193 ? computeProvidedTypes(node, types)
194 : HTypeList.ALL_UNKNOWN;
195 if (!selectorTypeMap.containsKey(selector)) { 282 if (!selectorTypeMap.containsKey(selector)) {
196 selectorTypeMap[selector] = providedTypes; 283 selectorTypeMap[selector] = providedTypes;
197 } else { 284 } else {
198 HTypeList oldTypes = selectorTypeMap[selector]; 285 HTypeList oldTypes = selectorTypeMap[selector];
199 HTypeList newTypes = oldTypes.unionWithInvoke(node, types); 286 HTypeList newTypes = oldTypes.unionWithInvoke(node, types);
200 if (newTypes === oldTypes) return; 287 if (newTypes === oldTypes) return;
201 selectorTypeMap[selector] = newTypes; 288 selectorTypeMap[selector] = newTypes;
202 } 289 }
203 290
204 // If we're not compiling, we don't have to do anything. 291 // If we're not compiling, we don't have to do anything.
205 if (compiler.phase != Compiler.PHASE_COMPILING) return; 292 if (compiler.phase != Compiler.PHASE_COMPILING) return;
206 293
207 // Run through all optimized functions and figure out if they need 294 // Run through all optimized functions and figure out if they need
208 // to be recompiled because of this new invocation. 295 // to be recompiled because of this new invocation.
209 optimizedFunctions.filterBySelector(selector).forEach((Element element) { 296 optimizedFunctions.filterBySelector(selector).forEach((Element element) {
210 // TODO(kasperl): Maybe check if the element is already marked for 297 // TODO(kasperl): Maybe check if the element is already marked for
211 // recompilation? Could be pretty cheap compared to computing 298 // recompilation? Could be pretty cheap compared to computing
212 // union types. 299 // union types.
213 HTypeList newTypes = parameterTypes(element); 300 HTypeList newTypes =
301 parameterTypes(element, optimizedDefaultValueTypes[element]);
214 bool recompile = false; 302 bool recompile = false;
215 if (newTypes.allUnknown) { 303 if (newTypes.allUnknown) {
216 recompile = true; 304 recompile = true;
217 } else { 305 } else {
218 HTypeList oldTypes = optimizedTypes[element]; 306 HTypeList oldTypes = optimizedTypes[element];
219 if (newTypes.length != oldTypes.length) { 307 assert(newTypes.length == oldTypes.length);
220 // TODO(kasperl): This can be improved. If the newTypes aren't in 308 for (int i = 0; i < oldTypes.length; i++) {
221 // conflict we can avoid the recompilation.
222 recompile = true;
223 } else for (int i = 0; i < oldTypes.length; i++) {
224 if (newTypes[i] != oldTypes[i]) { 309 if (newTypes[i] != oldTypes[i]) {
225 recompile = true; 310 recompile = true;
226 break; 311 break;
227 } 312 }
228 } 313 }
229 } 314 }
230 if (recompile) backend.scheduleForRecompilation(element); 315 if (recompile) backend.scheduleForRecompilation(element);
231 }); 316 });
232 } 317 }
233 318
234 HTypeList parameterTypes(element) { 319 HTypeList parameterTypes(FunctionElement element,
320 OptionalParameterTypes defaultValueTypes) {
235 // Handle static functions separately. 321 // Handle static functions separately.
236 if (Elements.isStaticOrTopLevelFunction(element)) { 322 if (Elements.isStaticOrTopLevelFunction(element)) {
237 HTypeList types = staticTypeMap[element]; 323 HTypeList types = staticTypeMap[element];
238 if (types !== null) { 324 if (types !== null) {
239 if (!optimizedStaticFunctions.contains(element)) { 325 if (!optimizedStaticFunctions.contains(element)) {
240 optimizedStaticFunctions.add(element); 326 optimizedStaticFunctions.add(element);
241 } 327 }
242 return types; 328 return types;
243 } else { 329 } else {
244 return HTypeList.ALL_UNKNOWN; 330 return HTypeList.ALL_UNKNOWN;
245 } 331 }
246 } 332 }
247 333
334
248 // TODO(kasperl): What kind of non-members do we get here? 335 // TODO(kasperl): What kind of non-members do we get here?
249 if (!element.isMember()) return HTypeList.ALL_UNKNOWN; 336 if (!element.isMember()) return HTypeList.ALL_UNKNOWN;
337 // Getters have no parameters.
kasperl 2012/09/05 07:06:29 Maybe move this up before the slightly weird !isMe
Søren Gjesse 2012/09/05 08:02:59 Done.
338 if (element.isGetter()) return HTypeList.ALL_UNKNOWN;
250 339
251 FunctionSignature signature = element.computeSignature(compiler); 340 FunctionSignature signature = element.computeSignature(compiler);
252 HTypeList found = null; 341 HTypeList found = null;
253 selectorTypeMap.visitMatching(element, 342 selectorTypeMap.visitMatching(element,
254 (Selector selector, HTypeList types) { 343 (Selector selector, HTypeList types) {
255 if (selector.argumentCount != signature.parameterCount) { 344 if (selector.argumentCount != signature.parameterCount ||
256 found = HTypeList.ALL_UNKNOWN; 345 selector.namedArgumentCount > 0) {
257 return false; 346 types = types.unionWithOptionalParameters(selector,
258 } else if (found === null) { 347 signature,
259 found = types; 348 defaultValueTypes);
260 return true;
261 } else {
262 found = found.union(types);
263 return !found.allUnknown;
264 } 349 }
350 assert(types.allUnknown || types.length == signature.parameterCount);
351 found = (found === null) ? types : found.union(types);
352 return !found.allUnknown;
265 }); 353 });
266 return found !== null ? found : HTypeList.ALL_UNKNOWN; 354 return found !== null ? found : HTypeList.ALL_UNKNOWN;
267 } 355 }
268 356
269 void registerOptimization(Element element, HTypeList parameterTypes) { 357 void registerOptimization(Element element,
358 HTypeList parameterTypes,
359 OptionalParameterTypes defaultValueTypes) {
270 if (Elements.isStaticOrTopLevelFunction(element)) { 360 if (Elements.isStaticOrTopLevelFunction(element)) {
271 if (parameterTypes.allUnknown) { 361 if (parameterTypes.allUnknown) {
272 optimizedStaticFunctions.remove(element); 362 optimizedStaticFunctions.remove(element);
273 } else { 363 } else {
274 optimizedStaticFunctions.add(element); 364 optimizedStaticFunctions.add(element);
275 } 365 }
276 } 366 }
277 367
278 // TODO(kasperl): What kind of non-members do we get here? 368 // TODO(kasperl): What kind of non-members do we get here?
279 if (!element.isMember()) return; 369 if (!element.isMember()) return;
280 370
281 if (parameterTypes.allUnknown) { 371 if (parameterTypes.allUnknown) {
282 optimizedFunctions.remove(element); 372 optimizedFunctions.remove(element);
283 optimizedTypes.remove(element); 373 optimizedTypes.remove(element);
374 optimizedDefaultValueTypes.remove(element);
284 } else { 375 } else {
285 optimizedFunctions.add(element); 376 optimizedFunctions.add(element);
286 optimizedTypes[element] = parameterTypes; 377 optimizedTypes[element] = parameterTypes;
378 optimizedDefaultValueTypes[element] = defaultValueTypes;
287 } 379 }
288 } 380 }
289 } 381 }
290 382
291 class JavaScriptItemCompilationContext extends ItemCompilationContext { 383 class JavaScriptItemCompilationContext extends ItemCompilationContext {
292 final HTypeMap types; 384 final HTypeMap types;
293 385
294 JavaScriptItemCompilationContext() : types = new HTypeMap(); 386 JavaScriptItemCompilationContext() : types = new HTypeMap();
295 } 387 }
296 388
(...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after
498 */ 590 */
499 void registerNonCallStaticUse(HStatic node) { 591 void registerNonCallStaticUse(HStatic node) {
500 argumentTypes.registerNonCallStaticUse(node); 592 argumentTypes.registerNonCallStaticUse(node);
501 } 593 }
502 594
503 /** 595 /**
504 * Retrieve the types of the parameters used for calling the [element] 596 * Retrieve the types of the parameters used for calling the [element]
505 * function. The types are optimistic in the sense as they are based on the 597 * function. The types are optimistic in the sense as they are based on the
506 * possible invocations of the function seen so far. 598 * possible invocations of the function seen so far.
507 */ 599 */
508 HTypeList optimisticParameterTypes(FunctionElement element) { 600 HTypeList optimisticParameterTypes(
509 return argumentTypes.parameterTypes(element); 601 FunctionElement element,
602 OptionalParameterTypes defaultValueTypes) {
603 return argumentTypes.parameterTypes(element, defaultValueTypes);
510 } 604 }
511 605
512 /** 606 /**
513 * Register that the function [element] has been optimized under the 607 * Register that the function [element] has been optimized under the
514 * assumptions that the types [parameterType] will be used for calling it. 608 * assumptions that the types [parameterType] will be used for calling it.
515 * If this assumption fail the function will be scheduled for recompilation. 609 * The passed [defaultValueTypes] holds the types of default values for
610 * the optional parameters. If this assumption fail the function will be
611 * scheduled for recompilation.
516 */ 612 */
517 registerParameterTypesOptimization( 613 registerParameterTypesOptimization(
518 FunctionElement element, HTypeList parameterTypes) { 614 FunctionElement element,
519 argumentTypes.registerOptimization(element, parameterTypes); 615 HTypeList parameterTypes,
616 OptionalParameterTypes defaultValueTypes) {
617 argumentTypes.registerOptimization(
618 element, parameterTypes, defaultValueTypes);
520 } 619 }
521 620
522 void registerReturnType(FunctionElement element, HType returnType) { 621 void registerReturnType(FunctionElement element, HType returnType) {
523 ReturnInfo info = returnInfo[element]; 622 ReturnInfo info = returnInfo[element];
524 if (info != null) { 623 if (info != null) {
525 info.update(returnType, scheduleForRecompilation); 624 info.update(returnType, scheduleForRecompilation);
526 } else { 625 } else {
527 returnInfo[element] = new ReturnInfo(returnType); 626 returnInfo[element] = new ReturnInfo(returnType);
528 } 627 }
529 } 628 }
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
577 return const SourceString('listSuperTypeCheck'); 676 return const SourceString('listSuperTypeCheck');
578 } 677 }
579 } else if (nativeCheck) { 678 } else if (nativeCheck) {
580 return const SourceString('callTypeCheck'); 679 return const SourceString('callTypeCheck');
581 } else { 680 } else {
582 return const SourceString('propertyTypeCheck'); 681 return const SourceString('propertyTypeCheck');
583 } 682 }
584 } 683 }
585 } 684 }
586 } 685 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698