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 class InvocationInfo { | 5 class InvocationInfo { |
| 6 int parameterCount; | 6 int parameterCount = -1; |
| 7 List<HType> providedTypes; | 7 List<HType> providedTypes; |
| 8 List<Element> compiledFunctions; | 8 List<Element> compiledFunctions; |
| 9 | 9 |
| 10 InvocationInfo(List<HType> types) | 10 InvocationInfo(HInvoke node) : compiledFunctions = new List<Element>() { |
|
floitsch
2012/08/15 09:11:59
nit: move the init into a separate line.
Søren Gjesse
2012/08/15 12:17:10
Done.
| |
| 11 : parameterCount = types != null ? types.length : -1, | 11 // If no node is provided this is an invocation info to indicate no type |
| 12 providedTypes = types, | 12 // information. |
| 13 compiledFunctions = new List<Element>(); | 13 if (node == null) return; |
|
floitsch
2012/08/15 09:11:59
named constructor: InvocationInfo.withoutType() ?
Søren Gjesse
2012/08/15 12:17:10
Good point, done.
| |
| 14 // Gather the type information provided. If the types contains no useful | |
| 15 // information there is no need to actually store them. | |
| 16 bool allUnknown = true; | |
| 17 for (int i = 1; i < node.inputs.length; i++) { | |
| 18 if (node.inputs[i].propagatedType != HType.UNKNOWN) { | |
| 19 allUnknown = false; | |
| 20 break; | |
| 21 } | |
| 22 } | |
| 23 if (!allUnknown) { | |
| 24 providedTypes = new List<HType>(node.inputs.length - 1); | |
| 25 for (int i = 0; i < providedTypes.length; i++) { | |
| 26 providedTypes[i] = node.inputs[i + 1].propagatedType; | |
| 27 } | |
| 28 parameterCount = providedTypes.length; | |
| 29 } | |
| 30 } | |
| 31 | |
| 32 void update(HInvoke node, var recompile) { | |
| 33 // If we don't know anything useful about the types adding more | |
| 34 // information will not help. | |
| 35 if (!hasTypeInformation) return; | |
| 36 | |
| 37 // Update the type information with the provided types. | |
| 38 bool typesChanged = false; | |
| 39 bool allUnknown = true; | |
| 40 for (int i = 0; i < providedTypes.length; i++) { | |
| 41 HType newType = providedTypes[i].union(node.inputs[i + 1].propagatedType); | |
| 42 if (newType != providedTypes[i]) { | |
| 43 typesChanged = true; | |
| 44 providedTypes[i] = newType; | |
| 45 } | |
| 46 if (providedTypes[i] != HType.UNKNOWN) allUnknown = false; | |
| 47 } | |
| 48 // If the provided types change we need to recompile all functions which | |
| 49 // have been compiled under the now invalidated assumptions. | |
| 50 if (typesChanged && compiledFunctions.length != 0) { | |
| 51 if (recompile != null) { | |
| 52 compiledFunctions.forEach(recompile); | |
| 53 } | |
| 54 compiledFunctions.clear(); | |
| 55 } | |
| 56 // If all information is lost no need to keep it around. | |
| 57 if (allUnknown) clearTypeInformation(); | |
| 58 } | |
| 14 | 59 |
| 15 addCompiledFunction(FunctionElement function) => | 60 addCompiledFunction(FunctionElement function) => |
| 16 compiledFunctions.add(function); | 61 compiledFunctions.add(function); |
| 17 | 62 |
| 18 void clearTypeInformation() => providedTypes = null; | 63 void clearTypeInformation() => providedTypes = null; |
| 19 bool get hasTypeInformation() => providedTypes != null; | 64 bool get hasTypeInformation() => providedTypes != null; |
| 20 | 65 |
| 21 } | 66 } |
| 22 | 67 |
| 23 class JavaScriptBackend extends Backend { | 68 class JavaScriptBackend extends Backend { |
| 24 SsaBuilderTask builder; | 69 SsaBuilderTask builder; |
| 25 SsaOptimizerTask optimizer; | 70 SsaOptimizerTask optimizer; |
| 26 SsaCodeGeneratorTask generator; | 71 SsaCodeGeneratorTask generator; |
| 27 CodeEmitterTask emitter; | 72 CodeEmitterTask emitter; |
| 28 final Map<Element, Map<Element, HType>> fieldInitializers; | 73 final Map<Element, Map<Element, HType>> fieldInitializers; |
| 29 final Map<Element, Map<Element, HType>> fieldConstructorSetters; | 74 final Map<Element, Map<Element, HType>> fieldConstructorSetters; |
| 30 final Map<Element, Map<Element, HType>> fieldSettersType; | 75 final Map<Element, Map<Element, HType>> fieldSettersType; |
| 31 | 76 |
| 77 final Map<Element, InvocationInfo> staticInvocationInfo; | |
| 32 final Map<SourceString, Map<Selector, InvocationInfo>> invocationInfo; | 78 final Map<SourceString, Map<Selector, InvocationInfo>> invocationInfo; |
| 33 | 79 |
| 34 final List<Element> invalidateAfterCodegen; | 80 final List<Element> invalidateAfterCodegen; |
| 35 | 81 |
| 36 List<CompilerTask> get tasks() { | 82 List<CompilerTask> get tasks() { |
| 37 return <CompilerTask>[builder, optimizer, generator, emitter]; | 83 return <CompilerTask>[builder, optimizer, generator, emitter]; |
| 38 } | 84 } |
| 39 | 85 |
| 40 JavaScriptBackend(Compiler compiler, bool generateSourceMap) | 86 JavaScriptBackend(Compiler compiler, bool generateSourceMap) |
| 41 : emitter = new CodeEmitterTask(compiler, generateSourceMap), | 87 : emitter = new CodeEmitterTask(compiler, generateSourceMap), |
| 42 fieldInitializers = new Map<Element, Map<Element, HType>>(), | 88 fieldInitializers = new Map<Element, Map<Element, HType>>(), |
| 43 fieldConstructorSetters = new Map<Element, Map<Element, HType>>(), | 89 fieldConstructorSetters = new Map<Element, Map<Element, HType>>(), |
| 44 fieldSettersType = new Map<Element, Map<Element, HType>>(), | 90 fieldSettersType = new Map<Element, Map<Element, HType>>(), |
| 45 invocationInfo = new Map<SourceString, Map<Selector, InvocationInfo>>(), | 91 invocationInfo = new Map<SourceString, Map<Selector, InvocationInfo>>(), |
| 92 staticInvocationInfo = new Map<Element, InvocationInfo>(), | |
| 46 invalidateAfterCodegen = new List<Element>(), | 93 invalidateAfterCodegen = new List<Element>(), |
| 47 super(compiler) { | 94 super(compiler) { |
| 48 builder = new SsaBuilderTask(this); | 95 builder = new SsaBuilderTask(this); |
| 49 optimizer = new SsaOptimizerTask(this); | 96 optimizer = new SsaOptimizerTask(this); |
| 50 generator = new SsaCodeGeneratorTask(this); | 97 generator = new SsaCodeGeneratorTask(this); |
| 51 } | 98 } |
| 52 | 99 |
| 53 void enqueueHelpers(Enqueuer world) { | 100 void enqueueHelpers(Enqueuer world) { |
| 54 enqueueAllTopLevelFunctions(compiler.jsHelperLibrary, world); | 101 enqueueAllTopLevelFunctions(compiler.jsHelperLibrary, world); |
| 55 enqueueAllTopLevelFunctions(compiler.interceptorsLibrary, world); | 102 enqueueAllTopLevelFunctions(compiler.interceptorsLibrary, world); |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 190 /** | 237 /** |
| 191 * Register a dynamic invocation and collect the provided types for the | 238 * Register a dynamic invocation and collect the provided types for the |
| 192 * named selector. | 239 * named selector. |
| 193 */ | 240 */ |
| 194 void registerDynamicInvocation(HInvokeDynamicMethod node, Selector selector) { | 241 void registerDynamicInvocation(HInvokeDynamicMethod node, Selector selector) { |
| 195 Map<Selector, InvocationInfo> invocationInfos = | 242 Map<Selector, InvocationInfo> invocationInfos = |
| 196 invocationInfo.putIfAbsent(node.name, | 243 invocationInfo.putIfAbsent(node.name, |
| 197 () => new Map<Selector, InvocationInfo>()); | 244 () => new Map<Selector, InvocationInfo>()); |
| 198 InvocationInfo info = invocationInfos[selector]; | 245 InvocationInfo info = invocationInfos[selector]; |
| 199 if (info != null) { | 246 if (info != null) { |
| 200 // If we don't know anything useful about the types adding more | 247 recompile(Element element) { |
|
floitsch
2012/08/15 09:11:59
void recompile(Element element) {
Søren Gjesse
2012/08/15 12:17:10
Done.
| |
| 201 // information will not help. | 248 if (compiler.phase == Compiler.PHASE_COMPILING) { |
| 202 if (!info.hasTypeInformation) return; | 249 invalidateAfterCodegen.add(element); |
| 250 } | |
| 251 } | |
|
floitsch
2012/08/15 09:11:59
new line after function declarations.
Søren Gjesse
2012/08/15 12:17:10
Done.
| |
| 252 info.update(node, recompile); | |
| 253 } else { | |
| 254 invocationInfos[selector] = new InvocationInfo(node); | |
| 255 } | |
| 256 } | |
| 203 | 257 |
| 204 // Update the type information with the provided types. | 258 /** |
| 205 bool typesChanged = false; | 259 * Register a static invocation and collect the provided types for the |
| 206 List<HType> types = info.providedTypes; | 260 * named selector. |
| 207 bool allUnknown = true; | 261 */ |
| 208 for (int i = 0; i < types.length; i++) { | 262 void registerStaticInvocation(HInvokeStatic node) { |
| 209 HType newType = types[i].union(node.inputs[i + 1].propagatedType); | 263 InvocationInfo info = staticInvocationInfo[node.element]; |
| 210 if (newType != types[i]) { | 264 if (info != null) { |
| 211 typesChanged = true; | 265 recompile(Element element) { |
| 212 types[i] = newType; | 266 if (compiler.phase == Compiler.PHASE_COMPILING) { |
| 267 invalidateAfterCodegen.add(element); | |
| 213 } | 268 } |
| 214 if (types[i] != HType.UNKNOWN) allUnknown = false; | |
| 215 } | 269 } |
| 216 // If the provided types change we need to recompile all functions which | 270 info.update(node, recompile); |
| 217 // have been compiled under the now invalidated assumptions. | 271 } else { |
| 218 if (typesChanged && info.compiledFunctions.length != 0) { | 272 staticInvocationInfo[node.element] = new InvocationInfo(node); |
| 273 } | |
| 274 } | |
| 275 | |
| 276 /** | |
| 277 * Register that a static is used for something else than a call target. | |
| 278 */ | |
| 279 void registerNonCallStaticUse(HStatic node) { | |
|
floitsch
2012/08/15 09:11:59
where is the same functionality for dynamic calls?
Søren Gjesse
2012/08/15 12:17:10
We don't have it, and its a bug. I have filed http
| |
| 280 // When a static is used for anything else than a call target we cannot | |
| 281 // infer anything about its parameter types. | |
| 282 InvocationInfo info = staticInvocationInfo[node.element]; | |
| 283 if (info == null) { | |
| 284 staticInvocationInfo[node.element] = new InvocationInfo(null); | |
| 285 } else { | |
| 286 info.clearTypeInformation(); | |
| 287 if (info.compiledFunctions.length != 0) { | |
| 219 if (compiler.phase == Compiler.PHASE_COMPILING) { | 288 if (compiler.phase == Compiler.PHASE_COMPILING) { |
| 220 info.compiledFunctions.forEach(invalidateAfterCodegen.add); | 289 info.compiledFunctions.forEach(invalidateAfterCodegen.add); |
| 221 info.compiledFunctions.clear(); | 290 info.compiledFunctions.clear(); |
| 222 } | 291 } |
| 223 } | 292 } |
| 224 // If all information is lost no need to keep it around. | |
| 225 if (allUnknown) info.clearTypeInformation(); | |
| 226 } else { | |
| 227 // Gather the type information provided. If the types contains no useful | |
| 228 // information there is no need to actually store them. | |
| 229 bool allUnknown = true; | |
| 230 for (int i = 1; i < node.inputs.length; i++) { | |
| 231 if (node.inputs[i].propagatedType != HType.UNKNOWN) { | |
| 232 allUnknown = false; | |
| 233 break; | |
| 234 } | |
| 235 } | |
| 236 List<HType> types = null; | |
| 237 if (!allUnknown) { | |
| 238 types = new List<HType>(node.inputs.length - 1); | |
| 239 for (int i = 0; i < types.length; i++) { | |
| 240 types[i] = node.inputs[i + 1].propagatedType; | |
| 241 } | |
| 242 } | |
| 243 InvocationInfo info = new InvocationInfo(types); | |
| 244 invocationInfos[selector] = info; | |
| 245 } | 293 } |
| 246 } | 294 } |
| 247 | 295 |
| 248 /** | 296 /** |
| 249 * Retreive the types of the parameters used for calling the [element] | 297 * Retreive the types of the parameters used for calling the [element] |
| 250 * function. The types are optimistic in the sense as they are based on the | 298 * function. The types are optimistic in the sense as they are based on the |
| 251 * possible invocations of the function seen so far. As compiling more | 299 * possible invocations of the function seen so far. As compiling more |
| 252 * code can invalidate this asumption the function is registered for being | 300 * code can invalidate this asumption the function is registered for being |
| 253 * re-compiled if new possible invocations of this function invalidate these | 301 * re-compiled if new possible invocations of this function invalidate these |
| 254 * asumptions. | 302 * asumptions. |
| 255 */ | 303 */ |
| 256 List<HType> optimisticParameterTypesWithRecompilationOnTypeChange( | 304 List<HType> optimisticParameterTypesWithRecompilationOnTypeChange( |
| 257 FunctionElement element) { | 305 FunctionElement element) { |
| 258 Map<Selector, InvocationInfo> invocationInfos = | 306 if (Elements.isStaticOrTopLevelFunction(element)) { |
| 259 invocationInfo[element.name]; | 307 InvocationInfo found = staticInvocationInfo[element]; |
| 260 if (invocationInfos == null) return null; | 308 if (found != null && found.hasTypeInformation) { |
| 309 FunctionSignature signature = element.computeSignature(compiler); | |
| 310 if (signature.parameterCount == found.parameterCount) { | |
| 311 found.addCompiledFunction(element); | |
| 312 return found.providedTypes; | |
| 313 } | |
| 314 } | |
| 315 return null; | |
| 316 } else { | |
| 317 Map<Selector, InvocationInfo> invocationInfos = | |
| 318 invocationInfo[element.name]; | |
| 319 if (invocationInfos == null) return null; | |
| 261 | 320 |
| 262 int foundCount = 0; | 321 int foundCount = 0; |
| 263 InvocationInfo found = null; | 322 InvocationInfo found = null; |
| 264 invocationInfos.forEach((Selector selector, InvocationInfo info) { | 323 invocationInfos.forEach((Selector selector, InvocationInfo info) { |
| 265 if (selector.applies(element, compiler)) { | 324 if (selector.applies(element, compiler)) { |
| 266 found = info; | 325 found = info; |
| 267 foundCount++; | 326 foundCount++; |
| 327 } | |
| 328 }); | |
| 329 | |
| 330 if (foundCount == 1 && found.hasTypeInformation) { | |
| 331 FunctionSignature signature = element.computeSignature(compiler); | |
| 332 if (signature.parameterCount == found.parameterCount) { | |
| 333 found.addCompiledFunction(element); | |
| 334 return found.providedTypes; | |
| 335 } | |
| 268 } | 336 } |
| 269 }); | 337 return null; |
| 270 | |
| 271 if (foundCount == 1 && found.hasTypeInformation) { | |
| 272 FunctionSignature signature = element.computeSignature(compiler); | |
| 273 if (signature.parameterCount == found.parameterCount) { | |
| 274 found.addCompiledFunction(element); | |
| 275 return found.providedTypes; | |
| 276 } | |
| 277 } | 338 } |
| 278 return null; | |
| 279 } | 339 } |
| 280 } | 340 } |
| OLD | NEW |