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

Unified 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: 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 side-by-side diff with in-line comments
Download patch
Index: lib/compiler/implementation/js_backend/backend.dart
diff --git a/lib/compiler/implementation/js_backend/backend.dart b/lib/compiler/implementation/js_backend/backend.dart
index c96cd0eba00473d7d7754bf000249b85ac1b3e01..1979b0048a62d47c20275eb38dd87c125afbfdfd 100644
--- a/lib/compiler/implementation/js_backend/backend.dart
+++ b/lib/compiler/implementation/js_backend/backend.dart
@@ -35,13 +35,40 @@ class ReturnInfo {
compiledFunctions.add(function);
}
-class HTypeList {
+class OptionalParameterTypes {
+ final List<SourceString> names;
final List<HType> types;
- HTypeList(int length) : types = new List<HType>(length);
- const HTypeList.allUnknown() : types = null;
+ OptionalParameterTypes(int optionalArgumentsCount)
+ : names = new List<SourceString>(optionalArgumentsCount),
+ types = new List<HType>(optionalArgumentsCount);
+
+ int get length => names.length;
+ SourceString name(int index) => names[index];
+ HType type(int index) => types[index];
- factory HTypeList.fromInvocation(HInvoke node, HTypeMap types) {
+ void insert(int index, SourceString name, HType type) {
kasperl 2012/09/04 09:18:45 Insert makes it sound like you're growing the list
Søren Gjesse 2012/09/04 14:55:07 Done.
+ names[index] = name;
+ types[index] = type;
+ }
+
+ String toString() => "OptionalParameterTypes($names, $types)";
+}
+
+class HTypeList {
+ final List<HType> types;
+ final List<SourceString> namedArguments;
+
+ HTypeList(int length)
+ : types = new List<HType>(length),
+ namedArguments = null;
+ HTypeList.withNamedArguments(int length, this.namedArguments)
+ : types = new List<HType>(length);
+ const HTypeList.allUnknown()
+ : types = null,
+ namedArguments = null;
+
+ factory HTypeList.fromStaticInvocation(HInvokeStatic node, HTypeMap types) {
bool allUnknown = true;
for (int i = 1; i < node.inputs.length; i++) {
if (types[node.inputs[i]] != HType.UNKNOWN) {
@@ -58,9 +85,27 @@ class HTypeList {
return result;
}
+ factory HTypeList.fromDynamicInvocation(HInvokeDynamic node,
+ Selector selector,
+ HTypeMap types) {
+ HTypeList result;
+ if (selector.namedArgumentCount > 0) {
+ result =
+ new HTypeList.withNamedArguments(
+ node.inputs.length - 1, selector.namedArguments);
kasperl 2012/09/04 09:18:45 Maybe cache node.inputs.length - 1 in a local to m
Søren Gjesse 2012/09/04 14:55:07 Done.
+ } else {
+ result = new HTypeList(node.inputs.length - 1);
+ }
+ for (int i = 0; i < result.types.length; i++) {
+ result.types[i] = types[node.inputs[i + 1]];
+ }
+ return result;
+ }
+
static const HTypeList ALL_UNKNOWN = const HTypeList.allUnknown();
bool get allUnknown => types === null;
+ bool get hasNamedArguments => namedArguments != null;
int get length => types.length;
HType operator[](int index) => types[index];
@@ -117,6 +162,56 @@ class HTypeList {
return onlyUnknown ? HTypeList.ALL_UNKNOWN : result;
}
+ HTypeList unionWithOptionalParameters(
kasperl 2012/09/04 09:18:45 This is fairly complicated. Can you add unit tests
Søren Gjesse 2012/09/04 14:55:07 I tried to do it in tests/compiler/dart2js/backend
+ Selector selector,
+ FunctionSignature signature,
+ OptionalParameterTypes defaultValueTypes) {
+ assert(allUnknown || selector.argumentCount == this.length);
+ // Create a new HTypeList for holding types for all parameters.
+ HTypeList result = new HTypeList(signature.parameterCount);
+
+ // First fill in the type of the positional arguments.
+ int nextTypeIndex = -1;
+ if (allUnknown) {
+ for (int i = 0; i < selector.positionalArgumentCount; i++) {
+ result.types[i] = HType.UNKNOWN;
+ }
+ } else {
+ result.types.setRange(0, selector.positionalArgumentCount, this.types);
+ nextTypeIndex = selector.positionalArgumentCount;
+ }
+ int next = selector.positionalArgumentCount; // Next parameter of interest.
+ int index = signature.requiredParameterCount; // Current parameter.
+ signature.forEachOptionalParameter((Element element) {
+ // If some optional parameters where passed positional these have
kasperl 2012/09/04 09:18:45 positional -> positionally
kasperl 2012/09/04 09:18:45 where -> were
Søren Gjesse 2012/09/04 14:55:07 Done.
Søren Gjesse 2012/09/04 14:55:07 Done.
+ // already been filled.
+ int positionalArgumentCount = selector.positionalArgumentCount;
kasperl 2012/09/04 09:18:45 This local isn't used.
Søren Gjesse 2012/09/04 14:55:07 Removed.
+ if (index == next) {
+ assert(result.types[index] === null);
+ HType type = null;
+ if (selector.namedArgumentCount > 0 && hasNamedArguments) {
+ for (int i = 0; i < namedArguments.length; i++) {
kasperl 2012/09/04 09:18:45 Could you use namedArguments.indexOf here? Maybe y
Søren Gjesse 2012/09/04 14:55:07 Nice simplification. Done.
+ if (namedArguments[i] == element.name) {
+ type = types[nextTypeIndex++];
+ break;
+ }
+ }
+ }
+ if (type === null) {
+ for (int i = 0; i < defaultValueTypes.length; i++) {
kasperl 2012/09/04 09:18:45 Maybe add indexOf to OptionalParameterTypes?
Søren Gjesse 2012/09/04 14:55:07 Added typeFor(SourceString name) instead.
+ if (defaultValueTypes.name(i) == element.name) {
+ type = defaultValueTypes.type(i);
kasperl 2012/09/04 09:18:45 If you end up not going for indexOf, you should pr
Søren Gjesse 2012/09/04 14:55:07 See above.
+ }
+ }
+ }
+ result.types[index] = type;
+ next++;
+ }
+ index++;
+ });
+ return result;
+ }
+
String toString() =>
allUnknown ? "HTypeList.ALL_UNKNOWN" : "HTypeList $types";
}
@@ -128,6 +223,7 @@ class ArgumentTypesRegistry {
final SelectorMap<HTypeList> selectorTypeMap;
final FunctionSet optimizedFunctions;
final Map<Element, HTypeList> optimizedTypes;
+ final Map<Element, OptionalParameterTypes> optimizedDefaultValueTypes;
ArgumentTypesRegistry(JavaScriptBackend backend)
: staticTypeMap = new Map<Element, HTypeList>(),
@@ -135,21 +231,17 @@ class ArgumentTypesRegistry {
selectorTypeMap = new SelectorMap<HTypeList>(backend.compiler),
optimizedFunctions = new FunctionSet(backend.compiler),
optimizedTypes = new Map<Element, HTypeList>(),
+ optimizedDefaultValueTypes =
+ new Map<Element, OptionalParameterTypes>(),
this.backend = backend;
Compiler get compiler => backend.compiler;
- // Gather the type information provided. If the types contains no
- // useful information there is no need to actually store them.
- HTypeList computeProvidedTypes(HInvoke node, HTypeMap types) {
- return new HTypeList.fromInvocation(node, types);
- }
-
void registerStaticInvocation(HInvokeStatic node, HTypeMap types) {
Element element = node.element;
HTypeList oldTypes = staticTypeMap[element];
if (oldTypes == null) {
- staticTypeMap[element] = computeProvidedTypes(node, types);
+ staticTypeMap[element] = new HTypeList.fromStaticInvocation(node, types);
} else {
if (oldTypes.allUnknown) return;
HTypeList newTypes = oldTypes.unionWithInvoke(node, types);
@@ -187,11 +279,8 @@ class ArgumentTypesRegistry {
return;
}
- // TODO(kasperl): For now, we're only dealing with non-named arguments.
- // We should generalize this.
- HTypeList providedTypes = selector.namedArguments.isEmpty()
- ? computeProvidedTypes(node, types)
- : HTypeList.ALL_UNKNOWN;
+ HTypeList providedTypes =
+ new HTypeList.fromDynamicInvocation(node, selector, types);
if (!selectorTypeMap.containsKey(selector)) {
selectorTypeMap[selector] = providedTypes;
} else {
@@ -210,17 +299,15 @@ class ArgumentTypesRegistry {
// TODO(kasperl): Maybe check if the element is already marked for
// recompilation? Could be pretty cheap compared to computing
// union types.
- HTypeList newTypes = parameterTypes(element);
+ HTypeList newTypes =
+ parameterTypes(element, optimizedDefaultValueTypes[element]);
bool recompile = false;
if (newTypes.allUnknown) {
recompile = true;
} else {
HTypeList oldTypes = optimizedTypes[element];
- if (newTypes.length != oldTypes.length) {
- // TODO(kasperl): This can be improved. If the newTypes aren't in
- // conflict we can avoid the recompilation.
- recompile = true;
- } else for (int i = 0; i < oldTypes.length; i++) {
+ assert(newTypes.length == oldTypes.length);
kasperl 2012/09/04 09:18:45 This is great!
Søren Gjesse 2012/09/04 14:55:07 Thanks.
+ for (int i = 0; i < oldTypes.length; i++) {
if (newTypes[i] != oldTypes[i]) {
recompile = true;
break;
@@ -231,7 +318,8 @@ class ArgumentTypesRegistry {
});
}
- HTypeList parameterTypes(element) {
+ HTypeList parameterTypes(FunctionElement element,
+ OptionalParameterTypes defaultValueTypes) {
// Handle static functions separately.
if (Elements.isStaticOrTopLevelFunction(element)) {
HTypeList types = staticTypeMap[element];
@@ -245,19 +333,25 @@ class ArgumentTypesRegistry {
}
}
+
// TODO(kasperl): What kind of non-members do we get here?
if (!element.isMember()) return HTypeList.ALL_UNKNOWN;
+ if (element.isGetter()) return HTypeList.ALL_UNKNOWN;
kasperl 2012/09/04 09:18:45 Add a comment that explains why getters should lea
Søren Gjesse 2012/09/04 14:55:07 Done.
FunctionSignature signature = element.computeSignature(compiler);
HTypeList found = null;
selectorTypeMap.visitMatching(element,
(Selector selector, HTypeList types) {
- if (selector.argumentCount != signature.parameterCount) {
- found = HTypeList.ALL_UNKNOWN;
- return false;
- } else if (found === null) {
+ if (selector.argumentCount != signature.parameterCount ||
+ selector.namedArgumentCount > 0) {
+ types = types.unionWithOptionalParameters(selector,
+ signature,
kasperl 2012/09/04 09:18:45 Indentation is slightly off.
Søren Gjesse 2012/09/04 14:55:07 Done.
Søren Gjesse 2012/09/04 14:55:07 Done.
+ defaultValueTypes);
+ }
+ assert(types.allUnknown || types.length == signature.parameterCount);
+ if (found === null) {
found = types;
- return true;
+ return !found.allUnknown;
kasperl 2012/09/04 09:18:45 This should be shareable now. Something like:
Søren Gjesse 2012/09/04 14:55:07 Done.
} else {
found = found.union(types);
return !found.allUnknown;
@@ -266,7 +360,9 @@ class ArgumentTypesRegistry {
return found !== null ? found : HTypeList.ALL_UNKNOWN;
}
- void registerOptimization(Element element, HTypeList parameterTypes) {
+ void registerOptimization(Element element,
+ HTypeList parameterTypes,
+ OptionalParameterTypes defaultValueTypes) {
if (Elements.isStaticOrTopLevelFunction(element)) {
if (parameterTypes.allUnknown) {
optimizedStaticFunctions.remove(element);
@@ -281,9 +377,11 @@ class ArgumentTypesRegistry {
if (parameterTypes.allUnknown) {
optimizedFunctions.remove(element);
optimizedTypes.remove(element);
+ optimizedDefaultValueTypes.remove(element);
} else {
optimizedFunctions.add(element);
optimizedTypes[element] = parameterTypes;
+ optimizedDefaultValueTypes[element] = defaultValueTypes;
}
}
}
@@ -505,18 +603,25 @@ class JavaScriptBackend extends Backend {
* function. The types are optimistic in the sense as they are based on the
* possible invocations of the function seen so far.
*/
- HTypeList optimisticParameterTypes(FunctionElement element) {
- return argumentTypes.parameterTypes(element);
+ HTypeList optimisticParameterTypes(
+ FunctionElement element,
+ OptionalParameterTypes defaultValueTypes) {
+ return argumentTypes.parameterTypes(element, defaultValueTypes);
}
/**
* Register that the function [element] has been optimized under the
* assumptions that the types [parameterType] will be used for calling it.
- * If this assumption fail the function will be scheduled for recompilation.
+ * The passed [defaultValueTypes] holds the types of default values for
+ * the optional parameters. If this assumption fail the function will be
+ * scheduled for recompilation.
*/
registerParameterTypesOptimization(
- FunctionElement element, HTypeList parameterTypes) {
- argumentTypes.registerOptimization(element, parameterTypes);
+ FunctionElement element,
+ HTypeList parameterTypes,
kasperl 2012/09/04 09:18:45 I wonder if we should have an abstraction over all
Søren Gjesse 2012/09/04 14:55:07 That might be - I will look at that as a separate
+ OptionalParameterTypes defaultValueTypes) {
+ argumentTypes.registerOptimization(
+ element, parameterTypes, defaultValueTypes);
}
void registerReturnType(FunctionElement element, HType returnType) {

Powered by Google App Engine
This is Rietveld 408576698