Chromium Code Reviews| Index: lib/compiler/implementation/compiler.dart |
| diff --git a/lib/compiler/implementation/compiler.dart b/lib/compiler/implementation/compiler.dart |
| index ca6ca2ba8cb60374a28e6029a5089e9d50e33292..f289d17cabbded9118a63f8a8a414d31005f1c82 100644 |
| --- a/lib/compiler/implementation/compiler.dart |
| +++ b/lib/compiler/implementation/compiler.dart |
| @@ -51,6 +51,23 @@ class Backend { |
| abstract List<CompilerTask> get tasks(); |
| } |
| +class InvocationInfo { |
| + InvocationInfo(List<HType> types) |
| + : parameterCount = types != null ? types.length : -1, |
| + providedTypes = types, |
| + compiledFunctions = new List<Element>(); |
| + |
| + addCompiledFunction(FunctionElement function) => |
| + compiledFunctions.add(function); |
| + |
| + void clearTypeInformation() => providedTypes = null; |
| + bool get hasTypeInformation() => providedTypes != null; |
| + |
| + int parameterCount; |
| + List<HType> providedTypes; |
| + List<Element> compiledFunctions; |
| +} |
| + |
| class JavaScriptBackend extends Backend { |
| SsaBuilderTask builder; |
| SsaOptimizerTask optimizer; |
| @@ -60,6 +77,8 @@ class JavaScriptBackend extends Backend { |
| final Map<Element, Map<Element, HType>> fieldConstructorSetters; |
| final Map<Element, Map<Element, HType>> fieldSettersType; |
| + final Map<SourceString, Map<Selector, InvocationInfo>> invocationInfo; |
| + |
| List<CompilerTask> get tasks() { |
| return <CompilerTask>[builder, optimizer, generator, emitter]; |
| } |
| @@ -69,6 +88,7 @@ class JavaScriptBackend extends Backend { |
| fieldInitializers = new Map<Element, Map<Element, HType>>(), |
| fieldConstructorSetters = new Map<Element, Map<Element, HType>>(), |
| fieldSettersType = new Map<Element, Map<Element, HType>>(), |
| + invocationInfo = new Map<SourceString, Map<Selector, InvocationInfo>>(), |
| super(compiler) { |
| builder = new SsaBuilderTask(this); |
| optimizer = new SsaOptimizerTask(this); |
| @@ -204,6 +224,91 @@ class JavaScriptBackend extends Backend { |
| if (!fields.containsKey(field)) return HType.CONFLICTING; |
| return fields[field]; |
| } |
| + |
| + // Register a dynamic invocation and collects the provided types for the |
| + // named selector. |
| + void registerDynamicInvocation(HInvokeDynamicMethod node, Selector selector) { |
| + Map<Selector, InvocationInfo> invocationInfos = |
| + invocationInfo.putIfAbsent(node.name, |
| + () => new Map<Selector, InvocationInfo>()); |
| + InvocationInfo info = invocationInfos[selector]; |
| + if (info != null) { |
| + // If we don't know anything useful about the types adding more |
| + // information will not help. |
| + if (!info.hasTypeInformation) return; |
| + |
| + // Update the type information with the provided types. |
| + bool typesChanged = false; |
| + List<HType> types = info.providedTypes; |
| + bool allUnknown = true; |
| + for (int i = 0; i < types.length; i++) { |
| + HType newType = types[i].union(node.inputs[i + 1].propagatedType); |
| + if (newType != types[i]) { |
| + typesChanged = true; |
| + types[i] = newType; |
| + } |
| + if (types[i] != HType.UNKNOWN) allUnknown = false; |
| + } |
| + // If the provided types change we need to recompile all functions which |
| + // have been compiled under the now invalidated assumptions. |
| + if (typesChanged && info.compiledFunctions.length != 0) { |
| + if (compiler.phase == Compiler.PHASE_COMPILING) { |
| + info.compiledFunctions.forEach( |
| + (e) => compiler.enqueuer.codegen.eagerRecompile(e) |
| + ); |
| + info.compiledFunctions.clear(); |
| + } |
| + } |
| + // If all information is lost no need to keep it around. |
| + if (allUnknown) info.clearTypeInformation(); |
| + } else { |
| + // Gather the type information provided. If the types contains no useful |
| + // information there is no need to actually store them. |
| + bool allUnknown = true; |
| + for (int i = 1; i < node.inputs.length; i++) { |
| + if (node.inputs[i].propagatedType != HType.UNKNOWN) { |
| + allUnknown = false; |
| + break; |
| + } |
| + } |
| + List<HType> types; |
| + if (allUnknown) { |
| + types == null; |
| + } else { |
| + types = new List<HType>(node.inputs.length - 1); |
| + for (int i = 0; i < types.length; i++) { |
| + types[i] = node.inputs[i + 1].propagatedType; |
| + } |
| + } |
| + InvocationInfo info = new InvocationInfo(types); |
| + invocationInfos[selector] = info; |
| + } |
| + } |
| + |
| + List<HType> optimisticParameterTypes(FunctionElement element) { |
|
floitsch
2012/08/06 15:01:06
Rename. The name doesn't convey that the element i
Søren Gjesse
2012/08/07 09:06:03
Renamed to optimisticParameterTypesWithRecompilati
|
| + Map<Selector, InvocationInfo> invocationInfos = |
| + invocationInfo[element.name]; |
| + if (invocationInfos == null) return null; |
| + |
| + int foundCount = 0; |
| + InvocationInfo found = null; |
| + invocationInfos.forEach((Selector selector, InvocationInfo info) { |
| + if (selector.applies(element, compiler)) { |
| + found = info; |
| + foundCount++; |
| + } |
| + }); |
| + |
| + if (foundCount == 1) { |
|
floitsch
2012/08/06 15:01:06
&& found.hasTypeInformation.
Move this test up. No
Søren Gjesse
2012/08/07 09:06:03
Done.
|
| + FunctionSignature signature = element.computeSignature(compiler); |
| + if (found.hasTypeInformation && |
| + signature.parameterCount == found.parameterCount) { |
| + found.addCompiledFunction(element); |
| + return found.providedTypes; |
| + } |
| + } |
| + return null; |
| + } |
| } |
| class Compiler implements DiagnosticListener { |
| @@ -360,7 +465,7 @@ class Compiler implements DiagnosticListener { |
| api.Diagnostic.CRASH); |
| // TODO(ahe): Obtain the build ID. |
| var buildId = 'build number could not be determined'; |
| - print(MessageKind.PLEASE_REPORT_THE_CRASH.message([buildId])); |
|
floitsch
2012/08/06 15:01:06
why?
Søren Gjesse
2012/08/07 09:06:03
Bad edit.
|
| + (MessageKind.PLEASE_REPORT_THE_CRASH.message([buildId])); |
|
ahe
2012/08/06 15:01:35
Bad edit?
Søren Gjesse
2012/08/07 09:06:03
Reverted.
|
| } |
| void cancel([String reason, Node node, Token token, |