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

Side by Side Diff: tests/compiler/dart2js/closure/closure_test.dart

Issue 2999003002: Add more tested features to closure_test (Closed)
Patch Set: Updated cf. comments. Created 3 years, 4 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
OLDNEW
1 // Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2017, 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 import 'dart:io'; 5 import 'dart:io' hide Link;
6 import 'package:async_helper/async_helper.dart'; 6 import 'package:async_helper/async_helper.dart';
7 import 'package:compiler/src/closure.dart'; 7 import 'package:compiler/src/closure.dart';
8 import 'package:compiler/src/common.dart'; 8 import 'package:compiler/src/common.dart';
9 import 'package:compiler/src/compiler.dart'; 9 import 'package:compiler/src/compiler.dart';
10 import 'package:compiler/src/diagnostics/diagnostic_listener.dart'; 10 import 'package:compiler/src/diagnostics/diagnostic_listener.dart';
11 import 'package:compiler/src/elements/elements.dart'; 11 import 'package:compiler/src/elements/elements.dart';
12 import 'package:compiler/src/elements/entities.dart'; 12 import 'package:compiler/src/elements/entities.dart';
13 import 'package:compiler/src/kernel/element_map.dart'; 13 import 'package:compiler/src/kernel/element_map.dart';
14 import 'package:compiler/src/kernel/kernel_backend_strategy.dart'; 14 import 'package:compiler/src/kernel/kernel_backend_strategy.dart';
15 import 'package:compiler/src/js_model/locals.dart'; 15 import 'package:compiler/src/js_model/locals.dart';
16 import 'package:compiler/src/tree/nodes.dart' as ast; 16 import 'package:compiler/src/tree/nodes.dart' as ast;
17 import 'package:compiler/src/util/util.dart';
18 import 'package:expect/expect.dart';
17 import '../equivalence/id_equivalence.dart'; 19 import '../equivalence/id_equivalence.dart';
18 import '../equivalence/id_equivalence_helper.dart'; 20 import '../equivalence/id_equivalence_helper.dart';
19 import 'package:kernel/ast.dart' as ir; 21 import 'package:kernel/ast.dart' as ir;
20 22
21 main() { 23 main(List<String> args) {
24 bool verbose = args.contains('-v');
22 asyncTest(() async { 25 asyncTest(() async {
23 Directory dataDir = new Directory.fromUri(Platform.script.resolve('data')); 26 Directory dataDir = new Directory.fromUri(Platform.script.resolve('data'));
24 await for (FileSystemEntity entity in dataDir.list()) { 27 await for (FileSystemEntity entity in dataDir.list()) {
28 print('----------------------------------------------------------------');
25 print('Checking ${entity.uri}'); 29 print('Checking ${entity.uri}');
30 print('----------------------------------------------------------------');
26 String annotatedCode = await new File.fromUri(entity.uri).readAsString(); 31 String annotatedCode = await new File.fromUri(entity.uri).readAsString();
27 await checkCode(annotatedCode, computeClosureData, compileFromSource); 32 print('--from source---------------------------------------------------');
28 await checkCode(annotatedCode, computeKernelClosureData, compileFromDill); 33 await checkCode(annotatedCode, computeClosureData, compileFromSource,
34 verbose: verbose);
35 // TODO(johnnniwinther,efortuna): Enable the these tests for .dill.
36 if (['captured_variable.dart'].contains(entity.uri.pathSegments.last)) {
37 print('--skipped for dill--------------------------------------------');
38 continue;
39 }
40 print('--from dill-----------------------------------------------------');
41 await checkCode(annotatedCode, computeKernelClosureData, compileFromDill,
42 verbose: verbose);
29 } 43 }
30 }); 44 });
31 } 45 }
32 46
33 /// Compute closure data mapping for [_member] as a [MemberElement]. 47 /// Compute closure data mapping for [_member] as a [MemberElement].
34 /// 48 ///
35 /// Fills [actualMap] with the data and [sourceSpanMap] with the source spans 49 /// Fills [actualMap] with the data and [sourceSpanMap] with the source spans
36 /// for the data origin. 50 /// for the data origin.
37 void computeClosureData(Compiler compiler, MemberEntity _member, 51 void computeClosureData(Compiler compiler, MemberEntity _member,
38 Map<Id, String> actualMap, Map<Id, SourceSpan> sourceSpanMap) { 52 Map<Id, String> actualMap, Map<Id, SourceSpan> sourceSpanMap,
53 {bool verbose: false}) {
39 MemberElement member = _member; 54 MemberElement member = _member;
40 ClosureDataLookup<ast.Node> closureDataLookup = 55 ClosureDataLookup<ast.Node> closureDataLookup =
41 compiler.backendStrategy.closureDataLookup as ClosureDataLookup<ast.Node>; 56 compiler.backendStrategy.closureDataLookup as ClosureDataLookup<ast.Node>;
42 new ClosureAstComputer(compiler.reporter, actualMap, sourceSpanMap, 57 new ClosureAstComputer(compiler.reporter, actualMap, sourceSpanMap,
43 member.resolvedAst, closureDataLookup) 58 member.resolvedAst, closureDataLookup,
59 verbose: verbose)
44 .run(); 60 .run();
45 } 61 }
46 62
47 /// Compute closure data mapping for [member] as a kernel based element. 63 /// Compute closure data mapping for [member] as a kernel based element.
48 /// 64 ///
49 /// Fills [actualMap] with the data and [sourceSpanMap] with the source spans 65 /// Fills [actualMap] with the data and [sourceSpanMap] with the source spans
50 /// for the data origin. 66 /// for the data origin.
51 void computeKernelClosureData(Compiler compiler, MemberEntity member, 67 void computeKernelClosureData(Compiler compiler, MemberEntity member,
52 Map<Id, String> actualMap, Map<Id, SourceSpan> sourceSpanMap) { 68 Map<Id, String> actualMap, Map<Id, SourceSpan> sourceSpanMap,
69 {bool verbose: false}) {
53 KernelBackendStrategy backendStrategy = compiler.backendStrategy; 70 KernelBackendStrategy backendStrategy = compiler.backendStrategy;
54 KernelToElementMapForBuilding elementMap = backendStrategy.elementMap; 71 KernelToElementMapForBuilding elementMap = backendStrategy.elementMap;
55 GlobalLocalsMap localsMap = backendStrategy.globalLocalsMapForTesting; 72 GlobalLocalsMap localsMap = backendStrategy.globalLocalsMapForTesting;
56 ClosureDataLookup closureDataLookup = backendStrategy.closureDataLookup; 73 ClosureDataLookup closureDataLookup = backendStrategy.closureDataLookup;
57 MemberDefinition definition = elementMap.getMemberDefinition(member); 74 MemberDefinition definition = elementMap.getMemberDefinition(member);
58 assert(definition.kind == MemberKind.regular, 75 assert(definition.kind == MemberKind.regular,
59 failedAt(member, "Unexpected member definition $definition")); 76 failedAt(member, "Unexpected member definition $definition"));
60 new ClosureIrChecker(actualMap, sourceSpanMap, elementMap, member, 77 new ClosureIrChecker(actualMap, sourceSpanMap, elementMap, member,
61 localsMap.getLocalsMap(member), closureDataLookup) 78 localsMap.getLocalsMap(member), closureDataLookup,
79 verbose: verbose)
62 .run(definition.node); 80 .run(definition.node);
63 } 81 }
64 82
65 /// Ast visitor for computing closure data. 83 /// Ast visitor for computing closure data.
66 class ClosureAstComputer extends AbstractResolvedAstComputer { 84 class ClosureAstComputer extends AbstractResolvedAstComputer
85 with ComputeValueMixin {
67 final ClosureDataLookup<ast.Node> closureDataLookup; 86 final ClosureDataLookup<ast.Node> closureDataLookup;
68 final ClosureRepresentationInfo info; 87 final bool verbose;
69 88
70 ClosureAstComputer( 89 ClosureAstComputer(
71 DiagnosticReporter reporter, 90 DiagnosticReporter reporter,
72 Map<Id, String> actualMap, 91 Map<Id, String> actualMap,
73 Map<Id, Spannable> spannableMap, 92 Map<Id, Spannable> spannableMap,
74 ResolvedAst resolvedAst, 93 ResolvedAst resolvedAst,
75 this.closureDataLookup) 94 this.closureDataLookup,
76 : this.info = 95 {this.verbose: false})
77 closureDataLookup.getClosureRepresentationInfo(resolvedAst.element), 96 : super(reporter, actualMap, spannableMap, resolvedAst) {
78 super(reporter, actualMap, spannableMap, resolvedAst); 97 push(resolvedAst.element);
98 }
99
100 visitFunctionExpression(ast.FunctionExpression node) {
101 Entity localFunction = resolvedAst.elements.getFunctionDefinition(node);
102 if (localFunction is LocalFunctionElement) {
103 push(localFunction);
104 super.visitFunctionExpression(node);
105 pop();
106 } else {
107 super.visitFunctionExpression(node);
108 }
109 }
79 110
80 @override 111 @override
81 String computeNodeValue(ast.Node node, [AstElement element]) { 112 String computeNodeValue(ast.Node node, [AstElement element]) {
82 if (element != null && element.isLocal) { 113 if (element != null && element.isLocal) {
83 LocalElement local = element; 114 if (element.isFunction) {
84 return computeLocalValue(info, local); 115 return computeEntityValue(element);
116 } else {
117 LocalElement local = element;
118 return computeLocalValue(local);
119 }
85 } 120 }
86 // TODO(johnniwinther,efortuna): Collect data for other nodes? 121 // TODO(johnniwinther,efortuna): Collect data for other nodes?
87 return null; 122 return null;
88 } 123 }
89 124
90 @override 125 @override
91 String computeElementValue(AstElement element) { 126 String computeElementValue(AstElement element) {
92 // TODO(johnniwinther,efortuna): Collect data for the member 127 // TODO(johnniwinther,efortuna): Collect data for the member
93 // (has thisLocal, has box, etc.). 128 // (has thisLocal, has box, etc.).
94 return null; 129 return computeEntityValue(element);
95 } 130 }
96 } 131 }
97 132
98 /// Kernel IR visitor for computing closure data. 133 /// Kernel IR visitor for computing closure data.
99 class ClosureIrChecker extends AbstractIrComputer { 134 class ClosureIrChecker extends AbstractIrComputer
135 with ComputeValueMixin<ir.Node> {
100 final ClosureDataLookup<ir.Node> closureDataLookup; 136 final ClosureDataLookup<ir.Node> closureDataLookup;
101 final ScopeInfo info;
102 final KernelToLocalsMap _localsMap; 137 final KernelToLocalsMap _localsMap;
138 final bool verbose;
103 139
104 ClosureIrChecker( 140 ClosureIrChecker(
105 Map<Id, String> actualMap, 141 Map<Id, String> actualMap,
106 Map<Id, SourceSpan> sourceSpanMap, 142 Map<Id, SourceSpan> sourceSpanMap,
107 KernelToElementMapForBuilding elementMap, 143 KernelToElementMapForBuilding elementMap,
108 MemberEntity member, 144 MemberEntity member,
109 this._localsMap, 145 this._localsMap,
110 this.closureDataLookup) 146 this.closureDataLookup,
111 : this.info = closureDataLookup.getScopeInfo(member), 147 {this.verbose: false})
112 super(actualMap, sourceSpanMap); 148 : super(actualMap, sourceSpanMap) {
149 push(member);
150 }
151
152 visitFunctionExpression(ir.FunctionExpression node) {
153 Local localFunction = _localsMap.getLocalFunction(node);
154 push(localFunction);
155 super.visitFunctionExpression(node);
156 pop();
157 }
158
159 visitFunctionDeclaration(ir.FunctionDeclaration node) {
160 Local localFunction = _localsMap.getLocalFunction(node);
161 push(localFunction);
162 super.visitFunctionDeclaration(node);
163 pop();
164 }
113 165
114 @override 166 @override
115 String computeNodeValue(ir.Node node) { 167 String computeNodeValue(ir.Node node) {
116 if (node is ir.VariableDeclaration) { 168 if (node is ir.VariableDeclaration) {
117 Local local = _localsMap.getLocalVariable(node); 169 Local local = _localsMap.getLocalVariable(node);
118 return computeLocalValue(info, local); 170 return computeLocalValue(local);
119 } 171 }
120 // TODO(johnniwinther,efortuna): Collect data for other nodes? 172 // TODO(johnniwinther,efortuna): Collect data for other nodes?
121 return null; 173 return null;
122 } 174 }
123 175
124 @override 176 @override
125 String computeMemberValue(ir.Member member) { 177 String computeMemberValue(ir.Member member) {
126 // TODO(johnniwinther,efortuna): Collect data for the member 178 // TODO(johnniwinther,efortuna): Collect data for the member
127 // (has thisLocal, has box, etc.). 179 // (has thisLocal, has box, etc.).
128 return null; 180 return computeEntityValue(entity);
129 } 181 }
130 } 182 }
131 183
132 /// Compute a string representation of the data stored for [local] in [info]. 184 abstract class ComputeValueMixin<T> {
133 String computeLocalValue(ScopeInfo info, Local local) { 185 bool get verbose;
134 StringBuffer sb = new StringBuffer(); 186 ClosureDataLookup<T> get closureDataLookup;
135 if (info.localIsUsedInTryOrSync(local)) { 187 Entity get entity => entityStack.head;
136 sb.write('inTry'); 188 Link<Entity> entityStack = const Link<Entity>();
189 Link<ScopeInfo> scopeInfoStack = const Link<ScopeInfo>();
190 ScopeInfo get scopeInfo => scopeInfoStack.head;
191 CapturedScope capturedScope;
192 Link<ClosureRepresentationInfo> closureRepresentationInfoStack =
193 const Link<ClosureRepresentationInfo>();
194 ClosureRepresentationInfo get closureRepresentationInfo =>
195 closureRepresentationInfoStack.head;
196
197 void push(Entity entity) {
198 entityStack = entityStack.prepend(entity);
199 scopeInfoStack =
200 scopeInfoStack.prepend(closureDataLookup.getScopeInfo(entity));
201 if (entity is MemberEntity) {
202 capturedScope = closureDataLookup.getCapturedScope(entity);
203 }
204 closureRepresentationInfoStack = closureRepresentationInfoStack.prepend(
205 closureDataLookup.getClosureRepresentationInfoForTesting(entity));
206 dump(entity);
137 } 207 }
138 // TODO(johnniwinther,efortuna): Add more info (captured, boxed etc.). 208
139 return sb.toString(); 209 void pop() {
210 entityStack = entityStack.tail;
211 scopeInfoStack = scopeInfoStack.tail;
212 closureRepresentationInfoStack = closureRepresentationInfoStack.tail;
213 }
214
215 void dump(Entity entity) {
216 if (!verbose) return;
217
218 print('entity: $entity');
219 print(' scopeInfo (${scopeInfo.runtimeType})');
220 scopeInfo.forEachBoxedVariable((a, b) => print(' boxed1: $a->$b'));
221 print(' capturedScope (${capturedScope.runtimeType})');
222 capturedScope.forEachBoxedVariable((a, b) => print(' boxed2: $a->$b'));
223 print(
224 ' closureRepresentationInfo (${closureRepresentationInfo.runtimeType})') ;
225 closureRepresentationInfo
226 ?.forEachCapturedVariable((a, b) => print(' captured: $a->$b'));
227 closureRepresentationInfo
228 ?.forEachFreeVariable((a, b) => print(' free3: $a->$b'));
229 closureRepresentationInfo
230 ?.forEachBoxedVariable((a, b) => print(' boxed3: $a->$b'));
231 }
232
233 /// Compute a string representation of the data stored for [local] in [info].
234 String computeLocalValue(Local local) {
235 List<String> features = <String>[];
236 if (scopeInfo.localIsUsedInTryOrSync(local)) {
237 features.add('inTry');
238 // TODO(johnniwinther,efortuna): Should this be enabled and checked?
239 //Expect.isTrue(capturedScope.localIsUsedInTryOrSync(local));
240 } else {
241 //Expect.isFalse(capturedScope.localIsUsedInTryOrSync(local));
242 }
243 if (scopeInfo.isBoxed(local)) {
244 features.add('boxed');
245 Expect.isTrue(capturedScope.isBoxed(local));
246 } else {
247 Expect.isFalse(capturedScope.isBoxed(local));
248 }
249 if (capturedScope.context == local) {
250 features.add('local');
251 }
252 if (capturedScope is CapturedLoopScope) {
253 CapturedLoopScope loopScope = capturedScope;
254 if (loopScope.boxedLoopVariables.contains(local)) {
255 features.add('loop');
256 }
257 }
258 if (closureRepresentationInfo != null) {
259 if (closureRepresentationInfo.createdFieldEntities.contains(local)) {
260 features.add('field');
261 }
262 if (closureRepresentationInfo.isVariableBoxed(local)) {
263 features.add('variable-boxed');
264 }
265 }
266 // TODO(johnniwinther,efortuna): Add more info?
267 return (features.toList()..sort()).join(',');
268 }
269
270 String computeEntityValue(Entity entity) {
271 Map<String, String> features = <String, String>{};
272
273 void addLocals(String name, forEach(f(Local local, _))) {
274 List<String> names = <String>[];
275 forEach((Local local, _) {
276 if (local is BoxLocal) {
277 names.add('box');
278 } else {
279 names.add(local.name);
280 }
281 });
282 String value = names.isEmpty ? null : '[${(names..sort()).join(',')}]';
283 if (features.containsKey(name)) {
284 Expect.equals(
285 features[name], value, "Inconsistent values for $name on $entity.");
286 }
287 features[name] = value;
288 }
289
290 if (scopeInfo.thisLocal != null) {
291 features['hasThis'] = '';
292 }
293 addLocals('boxed', scopeInfo.forEachBoxedVariable);
294
295 if (entity is MemberEntity) {
296 if (capturedScope.requiresContextBox) {
297 features['requiresBox'] = '';
298 }
299 addLocals('boxed', capturedScope.forEachBoxedVariable);
300 }
301
302 if (closureRepresentationInfo != null) {
303 addLocals('boxed', closureRepresentationInfo.forEachBoxedVariable);
304 addLocals('captured', closureRepresentationInfo.forEachCapturedVariable);
305 addLocals('free', closureRepresentationInfo.forEachFreeVariable);
306 }
307
308 StringBuffer sb = new StringBuffer();
309 bool needsComma = false;
310 for (String name in features.keys.toList()..sort()) {
311 String value = features[name];
312 if (value != null) {
313 if (needsComma) {
314 sb.write(',');
315 }
316 sb.write(name);
317 if (value != '') {
318 sb.write('=');
319 sb.write(value);
320 }
321 needsComma = true;
322 }
323 }
324 return sb.toString();
325 }
140 } 326 }
OLDNEW
« no previous file with comments | « tests/compiler/dart2js/annotated_code_helper.dart ('k') | tests/compiler/dart2js/closure/data/captured_variable.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698