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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/resolution/members.dart

Issue 26232003: Support type promotion in dart2js. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Updated cf. comments. Created 7 years, 2 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 part of resolution; 5 part of resolution;
6 6
7 abstract class TreeElements { 7 abstract class TreeElements {
8 Element get currentElement; 8 Element get currentElement;
9 Set<Node> get superUses; 9 Set<Node> get superUses;
10 10
(...skipping 21 matching lines...) Expand all
32 * Returns [:true:] if [node] is a type literal. 32 * Returns [:true:] if [node] is a type literal.
33 * 33 *
34 * Resolution marks this by setting the type on the node to be the 34 * Resolution marks this by setting the type on the node to be the
35 * [:Type:] type. 35 * [:Type:] type.
36 */ 36 */
37 bool isTypeLiteral(Send node); 37 bool isTypeLiteral(Send node);
38 38
39 /// Register additional dependencies required by [currentElement]. 39 /// Register additional dependencies required by [currentElement].
40 /// For example, elements that are used by a backend. 40 /// For example, elements that are used by a backend.
41 void registerDependency(Element element); 41 void registerDependency(Element element);
42
43 /// Returns [:true:] if [element] is potentially mutated anywhere in its
44 /// scope.
45 bool isPotentiallyMutated(VariableElement element);
46
47 /// Returns [:true:] if [element] is potentially mutated in [node].
48 bool isPotentiallyMutatedIn(Node node, VariableElement element);
49
50 /// Returns [:true:] if [element] is potentially mutated in a closure.
51 bool isPotentiallyMutatedInClosure(VariableElement element);
52
53 /// Returns [:true:] if [element] is accessed by a closure in [node].
54 bool isAccessedByClosureIn(Node node, VariableElement element);
42 } 55 }
43 56
44 class TreeElementMapping implements TreeElements { 57 class TreeElementMapping implements TreeElements {
45 final Element currentElement; 58 final Element currentElement;
46 final Map<Spannable, Selector> selectors = 59 final Map<Spannable, Selector> selectors =
47 new LinkedHashMap<Spannable, Selector>(); 60 new LinkedHashMap<Spannable, Selector>();
48 final Map<Node, DartType> types = new LinkedHashMap<Node, DartType>(); 61 final Map<Node, DartType> types = new LinkedHashMap<Node, DartType>();
49 final Set<Node> superUses = new LinkedHashSet<Node>(); 62 final Set<Node> superUses = new LinkedHashSet<Node>();
50 final Set<Element> otherDependencies = new LinkedHashSet<Element>(); 63 final Set<Element> otherDependencies = new LinkedHashSet<Element>();
51 final Map<Node, Constant> constants = new Map<Node, Constant>(); 64 final Map<Node, Constant> constants = new Map<Node, Constant>();
65 final Set<VariableElement> potentiallyMutated = new Set<VariableElement>();
66 final Map<Node, Set<VariableElement>> potentiallyMutatedIn =
67 new Map<Node, Set<VariableElement>>();
68 final Set<VariableElement> potentiallyMutatedInClosure =
69 new Set<VariableElement>();
70 final Map<Node, Set<VariableElement>> accessedByClosureIn =
71 new Map<Node, Set<VariableElement>>();
52 final int hashCode = ++hashCodeCounter; 72 final int hashCode = ++hashCodeCounter;
53 static int hashCodeCounter = 0; 73 static int hashCodeCounter = 0;
54 74
55 TreeElementMapping(this.currentElement); 75 TreeElementMapping(this.currentElement);
56 76
57 operator []=(Node node, Element element) { 77 operator []=(Node node, Element element) {
58 assert(invariant(node, () { 78 assert(invariant(node, () {
59 FunctionExpression functionExpression = node.asFunctionExpression(); 79 FunctionExpression functionExpression = node.asFunctionExpression();
60 if (functionExpression != null) { 80 if (functionExpression != null) {
61 return !functionExpression.modifiers.isExternal(); 81 return !functionExpression.modifiers.isExternal();
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
152 } 172 }
153 173
154 bool isTypeLiteral(Send node) { 174 bool isTypeLiteral(Send node) {
155 return getType(node) != null; 175 return getType(node) != null;
156 } 176 }
157 177
158 void registerDependency(Element element) { 178 void registerDependency(Element element) {
159 otherDependencies.add(element.implementation); 179 otherDependencies.add(element.implementation);
160 } 180 }
161 181
182 bool isPotentiallyMutated(VariableElement element) {
183 return potentiallyMutated.contains(element);
184 }
185
186 void setPotentiallyMutated(VariableElement element) {
187 potentiallyMutated.add(element);
188 }
189
190 bool isPotentiallyMutatedIn(Node node, VariableElement element) {
191 Set<Element> mutatedIn = potentiallyMutatedIn[node];
192 return mutatedIn != null && mutatedIn.contains(element);
193 }
194
195 void setPotentiallyMutatedIn(Node node, VariableElement element) {
196 potentiallyMutatedIn.putIfAbsent(
197 node, () => new Set<VariableElement>()).add(element);
198 }
199
200 bool isPotentiallyMutatedInClosure(VariableElement element) {
201 return potentiallyMutatedInClosure.contains(element);
202 }
203
204 void setPotentiallyMutatedInClosure(VariableElement element) {
205 potentiallyMutatedInClosure.add(element);
206 }
207
208 bool isAccessedByClosureIn(Node node, VariableElement element) {
209 Set<Element> accessedIn = accessedByClosureIn[node];
210 return accessedIn != null && accessedIn.contains(element);
211 }
212
213 void setAccessedByClosureIn(Node node, VariableElement element) {
214 accessedByClosureIn.putIfAbsent(
215 node, () => new Set<VariableElement>()).add(element);
216 }
217
162 String toString() => 'TreeElementMapping($currentElement)'; 218 String toString() => 'TreeElementMapping($currentElement)';
163 } 219 }
164 220
165 class ResolverTask extends CompilerTask { 221 class ResolverTask extends CompilerTask {
166 ResolverTask(Compiler compiler) : super(compiler); 222 ResolverTask(Compiler compiler) : super(compiler);
167 223
168 String get name => 'Resolver'; 224 String get name => 'Resolver';
169 225
170 TreeElements resolve(Element element) { 226 TreeElements resolve(Element element) {
171 return measure(() { 227 return measure(() {
(...skipping 1667 matching lines...) Expand 10 before | Expand all | Expand 10 after
1839 bool sendIsMemberAccess = false; 1895 bool sendIsMemberAccess = false;
1840 StatementScope statementScope; 1896 StatementScope statementScope;
1841 int allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION 1897 int allowedCategory = ElementCategory.VARIABLE | ElementCategory.FUNCTION
1842 | ElementCategory.IMPLIES_TYPE; 1898 | ElementCategory.IMPLIES_TYPE;
1843 1899
1844 /// When visiting the type declaration of the variable in a [ForIn] loop, 1900 /// When visiting the type declaration of the variable in a [ForIn] loop,
1845 /// the initializer of the variable is implicit and we should not emit an 1901 /// the initializer of the variable is implicit and we should not emit an
1846 /// error when verifying that all final variables are initialized. 1902 /// error when verifying that all final variables are initialized.
1847 bool allowFinalWithoutInitializer = false; 1903 bool allowFinalWithoutInitializer = false;
1848 1904
1905 /// The nodes for which variable access and mutation must be registed in order
karlklose 2013/10/15 11:56:17 'registed' -> 'registered'.
Johnni Winther 2013/10/15 15:57:00 Done.
1906 /// to determine when variable types are promoted.
karlklose 2013/10/15 11:56:17 'when the static type of variables is promoted.'
Johnni Winther 2013/10/15 15:57:00 Done.
1907 Link<Node> promotionScope = const Link<Node>();
1908
1909 bool isPotentiallyMutableTarget(Element target) {
1910 if (target == null) return false;
1911 return (target.isVariable() || target.isParameter()) &&
1912 !(target.modifiers.isFinal() || target.modifiers.isConst());
1913 }
1914
1849 // TODO(ahe): Find a way to share this with runtime implementation. 1915 // TODO(ahe): Find a way to share this with runtime implementation.
1850 static final RegExp symbolValidationPattern = 1916 static final RegExp symbolValidationPattern =
1851 new RegExp(r'^(?:[a-zA-Z$][a-zA-Z$0-9_]*\.)*(?:[a-zA-Z$][a-zA-Z$0-9_]*=?|' 1917 new RegExp(r'^(?:[a-zA-Z$][a-zA-Z$0-9_]*\.)*(?:[a-zA-Z$][a-zA-Z$0-9_]*=?|'
1852 r'-|' 1918 r'-|'
1853 r'unary-|' 1919 r'unary-|'
1854 r'\[\]=|' 1920 r'\[\]=|'
1855 r'~|' 1921 r'~|'
1856 r'==|' 1922 r'==|'
1857 r'\[\]|' 1923 r'\[\]|'
1858 r'\*|' 1924 r'\*|'
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
1937 } 2003 }
1938 2004
1939 inStaticContext(action()) { 2005 inStaticContext(action()) {
1940 bool wasInstanceContext = inInstanceContext; 2006 bool wasInstanceContext = inInstanceContext;
1941 inInstanceContext = false; 2007 inInstanceContext = false;
1942 var result = action(); 2008 var result = action();
1943 inInstanceContext = wasInstanceContext; 2009 inInstanceContext = wasInstanceContext;
1944 return result; 2010 return result;
1945 } 2011 }
1946 2012
2013 doInPromotionScope(Node node, action()) {
2014 promotionScope = promotionScope.prepend(node);
2015 var result = action();
2016 promotionScope = promotionScope.tail;
2017 return result;
2018 }
2019
1947 visitInStaticContext(Node node) { 2020 visitInStaticContext(Node node) {
1948 inStaticContext(() => visit(node)); 2021 inStaticContext(() => visit(node));
1949 } 2022 }
1950 2023
1951 ErroneousElement warnAndCreateErroneousElement(Node node, 2024 ErroneousElement warnAndCreateErroneousElement(Node node,
1952 SourceString name, 2025 SourceString name,
1953 DualKind kind, 2026 DualKind kind,
1954 [Map arguments = const {}]) { 2027 [Map arguments = const {}]) {
1955 ResolutionWarning warning = new ResolutionWarning( 2028 ResolutionWarning warning = new ResolutionWarning(
1956 kind.warning, arguments, compiler.terseDiagnostics); 2029 kind.warning, arguments, compiler.terseDiagnostics);
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after
2179 statementScope = oldStatementScope; 2252 statementScope = oldStatementScope;
2180 2253
2181 scope = oldScope; 2254 scope = oldScope;
2182 enclosingElement = previousEnclosingElement; 2255 enclosingElement = previousEnclosingElement;
2183 2256
2184 world.registerClosure(function, mapping); 2257 world.registerClosure(function, mapping);
2185 world.registerInstantiatedClass(compiler.functionClass, mapping); 2258 world.registerInstantiatedClass(compiler.functionClass, mapping);
2186 } 2259 }
2187 2260
2188 visitIf(If node) { 2261 visitIf(If node) {
2189 visit(node.condition); 2262 doInPromotionScope(node.condition.expression, () => visit(node.condition));
2190 visitIn(node.thenPart, new BlockScope(scope)); 2263 doInPromotionScope(node.thenPart, () =>
karlklose 2013/10/15 11:56:17 Break line before closure.
Johnni Winther 2013/10/15 15:57:00 Done.
2264 visitIn(node.thenPart, new BlockScope(scope)));
2191 visitIn(node.elsePart, new BlockScope(scope)); 2265 visitIn(node.elsePart, new BlockScope(scope));
2192 } 2266 }
2193 2267
2194 static bool isLogicalOperator(Identifier op) { 2268 static bool isLogicalOperator(Identifier op) {
2195 String str = op.source.stringValue; 2269 String str = op.source.stringValue;
2196 return (identical(str, '&&') || str == '||' || str == '!'); 2270 return (identical(str, '&&') || str == '||' || str == '!');
2197 } 2271 }
2198 2272
2199 Element resolveSend(Send node) { 2273 Element resolveSend(Send node) {
2200 Selector selector = resolveSelector(node, null); 2274 Selector selector = resolveSelector(node, null);
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
2406 } else if (!seenNamedArguments.isEmpty) { 2480 } else if (!seenNamedArguments.isEmpty) {
2407 error(argument, MessageKind.INVALID_ARGUMENT_AFTER_NAMED); 2481 error(argument, MessageKind.INVALID_ARGUMENT_AFTER_NAMED);
2408 } 2482 }
2409 } 2483 }
2410 sendIsMemberAccess = oldSendIsMemberAccess; 2484 sendIsMemberAccess = oldSendIsMemberAccess;
2411 } 2485 }
2412 2486
2413 visitSend(Send node) { 2487 visitSend(Send node) {
2414 bool oldSendIsMemberAccess = sendIsMemberAccess; 2488 bool oldSendIsMemberAccess = sendIsMemberAccess;
2415 sendIsMemberAccess = node.isPropertyAccess || node.isCall; 2489 sendIsMemberAccess = node.isPropertyAccess || node.isCall;
2416 Element target = resolveSend(node); 2490 Element target;
2491 if (node.isLogicalAnd) {
2492 target = doInPromotionScope(node.receiver, () => resolveSend(node));
2493 } else {
2494 target = resolveSend(node);
2495 }
2417 sendIsMemberAccess = oldSendIsMemberAccess; 2496 sendIsMemberAccess = oldSendIsMemberAccess;
2418 2497
2419 if (target != null 2498 if (target != null
2420 && target == compiler.mirrorSystemGetNameFunction 2499 && target == compiler.mirrorSystemGetNameFunction
2421 && !compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(enclosingElement)) { 2500 && !compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(enclosingElement)) {
2422 compiler.reportHint( 2501 compiler.reportHint(
2423 node.selector, MessageKind.STATIC_FUNCTION_BLOAT, 2502 node.selector, MessageKind.STATIC_FUNCTION_BLOAT,
2424 {'class': compiler.mirrorSystemClass.name, 2503 {'class': compiler.mirrorSystemClass.name,
2425 'name': compiler.mirrorSystemGetNameFunction.name}); 2504 'name': compiler.mirrorSystemGetNameFunction.name});
2426 } 2505 }
(...skipping 19 matching lines...) Expand all
2446 world.registerTypeLiteral(target, mapping); 2525 world.registerTypeLiteral(target, mapping);
2447 } else if (target.impliesType() && !sendIsMemberAccess) { 2526 } else if (target.impliesType() && !sendIsMemberAccess) {
2448 // Set the type of the node to [Type] to mark this send as a 2527 // Set the type of the node to [Type] to mark this send as a
2449 // type literal. 2528 // type literal.
2450 mapping.setType(node, compiler.typeClass.computeType(compiler)); 2529 mapping.setType(node, compiler.typeClass.computeType(compiler));
2451 world.registerTypeLiteral(target, mapping); 2530 world.registerTypeLiteral(target, mapping);
2452 2531
2453 // Don't try to make constants of calls to type literals. 2532 // Don't try to make constants of calls to type literals.
2454 analyzeConstant(node, isConst: !node.isCall); 2533 analyzeConstant(node, isConst: !node.isCall);
2455 } 2534 }
2535 if (isPotentiallyMutableTarget(target)) {
2536 if (enclosingElement != target.enclosingElement) {
2537 for (Node scope in promotionScope) {
2538 mapping.setAccessedByClosureIn(scope, target);
2539 }
2540 }
2541 }
2456 } 2542 }
2457 2543
2458 bool resolvedArguments = false; 2544 bool resolvedArguments = false;
2459 if (node.isOperator) { 2545 if (node.isOperator) {
2460 String operatorString = node.selector.asOperator().source.stringValue; 2546 String operatorString = node.selector.asOperator().source.stringValue;
2461 if (identical(operatorString, 'is')) { 2547 if (identical(operatorString, 'is')) {
2462 DartType type = 2548 DartType type =
2463 resolveTypeExpression(node.typeAnnotationFromIsCheckOrCast); 2549 resolveTypeExpression(node.typeAnnotationFromIsCheckOrCast);
2464 if (type != null) { 2550 if (type != null) {
2465 compiler.enqueuer.resolution.registerIsCheck(type, mapping); 2551 compiler.enqueuer.resolution.registerIsCheck(type, mapping);
2466 } 2552 }
2467 resolvedArguments = true; 2553 resolvedArguments = true;
2468 } else if (identical(operatorString, 'as')) { 2554 } else if (identical(operatorString, 'as')) {
2469 DartType type = resolveTypeExpression(node.arguments.head); 2555 DartType type = resolveTypeExpression(node.arguments.head);
2470 if (type != null) { 2556 if (type != null) {
2471 compiler.enqueuer.resolution.registerAsCheck(type, mapping); 2557 compiler.enqueuer.resolution.registerAsCheck(type, mapping);
2472 } 2558 }
2473 resolvedArguments = true; 2559 resolvedArguments = true;
2560 } else if (identical(operatorString, '&&')) {
2561 doInPromotionScope(node.arguments.head,
2562 () => resolveArguments(node.argumentsNode));
2563 resolvedArguments = true;
2474 } 2564 }
2475 } 2565 }
2476 2566
2477 if (!resolvedArguments) { 2567 if (!resolvedArguments) {
2478 resolveArguments(node.argumentsNode); 2568 resolveArguments(node.argumentsNode);
2479 } 2569 }
2480 2570
2481 // If the selector is null, it means that we will not be generating 2571 // If the selector is null, it means that we will not be generating
2482 // code for this as a send. 2572 // code for this as a send.
2483 Selector selector = mapping.getSelector(node); 2573 Selector selector = mapping.getSelector(node);
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
2566 compiler.backend.registerThrowNoSuchMethod(mapping); 2656 compiler.backend.registerThrowNoSuchMethod(mapping);
2567 } else if (target.modifiers.isFinal() || 2657 } else if (target.modifiers.isFinal() ||
2568 target.modifiers.isConst() || 2658 target.modifiers.isConst() ||
2569 (target.isFunction() && 2659 (target.isFunction() &&
2570 Elements.isStaticOrTopLevelFunction(target) && 2660 Elements.isStaticOrTopLevelFunction(target) &&
2571 !target.isSetter())) { 2661 !target.isSetter())) {
2572 setter = warnAndCreateErroneousElement( 2662 setter = warnAndCreateErroneousElement(
2573 node.selector, target.name, MessageKind.CANNOT_RESOLVE_SETTER); 2663 node.selector, target.name, MessageKind.CANNOT_RESOLVE_SETTER);
2574 compiler.backend.registerThrowNoSuchMethod(mapping); 2664 compiler.backend.registerThrowNoSuchMethod(mapping);
2575 } 2665 }
2666 if (isPotentiallyMutableTarget(target)) {
2667 mapping.setPotentiallyMutated(target);
2668 if (enclosingElement != target.enclosingElement) {
2669 mapping.setPotentiallyMutatedInClosure(target);
2670 }
2671 for (Node scope in promotionScope) {
2672 mapping.setPotentiallyMutatedIn(scope, target);
2673 }
2674 }
2576 } 2675 }
2577 2676
2578 visit(node.argumentsNode); 2677 visit(node.argumentsNode);
2579 2678
2580 // TODO(ngeoffray): Check if the target can be assigned. 2679 // TODO(ngeoffray): Check if the target can be assigned.
2581 // TODO(ngeoffray): Warn if target is null and the send is 2680 // TODO(ngeoffray): Warn if target is null and the send is
2582 // unqualified. 2681 // unqualified.
2583 2682
2584 Selector selector = mapping.getSelector(node); 2683 Selector selector = mapping.getSelector(node);
2585 if (isComplex) { 2684 if (isComplex) {
(...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after
2992 mapping.setType(node, listType); 3091 mapping.setType(node, listType);
2993 world.registerInstantiatedType(listType, mapping); 3092 world.registerInstantiatedType(listType, mapping);
2994 compiler.backend.registerRequiredType(listType, enclosingElement); 3093 compiler.backend.registerRequiredType(listType, enclosingElement);
2995 visit(node.elements); 3094 visit(node.elements);
2996 if (node.isConst()) { 3095 if (node.isConst()) {
2997 analyzeConstant(node); 3096 analyzeConstant(node);
2998 } 3097 }
2999 } 3098 }
3000 3099
3001 visitConditional(Conditional node) { 3100 visitConditional(Conditional node) {
3002 node.visitChildren(this); 3101 doInPromotionScope(node.condition, () => visit(node.condition));
3102 doInPromotionScope(node.thenExpression, () => visit(node.thenExpression));
3103 visit(node.elseExpression);
3003 } 3104 }
3004 3105
3005 visitStringInterpolation(StringInterpolation node) { 3106 visitStringInterpolation(StringInterpolation node) {
3006 world.registerInstantiatedClass(compiler.stringClass, mapping); 3107 world.registerInstantiatedClass(compiler.stringClass, mapping);
3007 compiler.backend.registerStringInterpolation(mapping); 3108 compiler.backend.registerStringInterpolation(mapping);
3008 node.visitChildren(this); 3109 node.visitChildren(this);
3009 } 3110 }
3010 3111
3011 visitStringInterpolationPart(StringInterpolationPart node) { 3112 visitStringInterpolationPart(StringInterpolationPart node) {
3012 registerImplicitInvocation(const SourceString('toString'), 0); 3113 registerImplicitInvocation(const SourceString('toString'), 0);
(...skipping 1507 matching lines...) Expand 10 before | Expand all | Expand 10 after
4520 return finishConstructorReference(visit(expression), 4621 return finishConstructorReference(visit(expression),
4521 expression, expression); 4622 expression, expression);
4522 } 4623 }
4523 } 4624 }
4524 4625
4525 /// Looks up [name] in [scope] and unwraps the result. 4626 /// Looks up [name] in [scope] and unwraps the result.
4526 Element lookupInScope(Compiler compiler, Node node, 4627 Element lookupInScope(Compiler compiler, Node node,
4527 Scope scope, SourceString name) { 4628 Scope scope, SourceString name) {
4528 return Elements.unwrap(scope.lookup(name), compiler, node); 4629 return Elements.unwrap(scope.lookup(name), compiler, node);
4529 } 4630 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698