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

Side by Side Diff: pkg/compiler/lib/src/ssa/builder_kernel.dart

Issue 2377813002: kernel->ssa: implement for-in loops (Closed)
Patch Set: fix another import Created 4 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
« no previous file with comments | « pkg/compiler/lib/src/ssa/builder.dart ('k') | pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2016, 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 'package:kernel/ast.dart' as ir; 5 import 'package:kernel/ast.dart' as ir;
6 6
7 import '../common.dart'; 7 import '../common.dart';
8 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; 8 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem;
9 import '../common/names.dart';
9 import '../common/tasks.dart' show CompilerTask; 10 import '../common/tasks.dart' show CompilerTask;
10 import '../compiler.dart'; 11 import '../compiler.dart';
11 import '../dart_types.dart'; 12 import '../dart_types.dart';
12 import '../elements/elements.dart'; 13 import '../elements/elements.dart';
13 import '../io/source_information.dart'; 14 import '../io/source_information.dart';
14 import '../js_backend/backend.dart' show JavaScriptBackend; 15 import '../js_backend/backend.dart' show JavaScriptBackend;
15 import '../kernel/kernel.dart'; 16 import '../kernel/kernel.dart';
16 import '../resolution/tree_elements.dart'; 17 import '../resolution/tree_elements.dart';
17 import '../tree/dartstring.dart'; 18 import '../tree/dartstring.dart';
18 import '../types/masks.dart'; 19 import '../types/masks.dart';
19 import '../universe/selector.dart'; 20 import '../universe/selector.dart';
20
21 import 'graph_builder.dart'; 21 import 'graph_builder.dart';
22 import 'kernel_ast_adapter.dart'; 22 import 'kernel_ast_adapter.dart';
23 import 'kernel_string_builder.dart'; 23 import 'kernel_string_builder.dart';
24 import 'locals_handler.dart'; 24 import 'locals_handler.dart';
25 import 'loop_handler.dart'; 25 import 'loop_handler.dart';
26 import 'nodes.dart'; 26 import 'nodes.dart';
27 import 'ssa_branch_builder.dart'; 27 import 'ssa_branch_builder.dart';
28 28
29 class SsaKernelBuilderTask extends CompilerTask { 29 class SsaKernelBuilderTask extends CompilerTask {
30 final JavaScriptBackend backend; 30 final JavaScriptBackend backend;
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after
235 235
236 void buildBody() { 236 void buildBody() {
237 forStatement.body.accept(this); 237 forStatement.body.accept(this);
238 } 238 }
239 239
240 loopHandler.handleLoop( 240 loopHandler.handleLoop(
241 forStatement, buildInitializer, buildCondition, buildUpdate, buildBody); 241 forStatement, buildInitializer, buildCondition, buildUpdate, buildBody);
242 } 242 }
243 243
244 @override 244 @override
245 void visitForInStatement(ir.ForInStatement forInStatement) {
246 if (forInStatement.isAsync) {
247 compiler.reporter.internalError(astAdapter.getNode(forInStatement),
248 "Cannot compile async for-in using kernel.");
249 }
250 // If the expression being iterated over is a JS indexable type, we can
251 // generate an optimized version of for-in that uses indexing.
252 if (astAdapter.isJsIndexableIterator(forInStatement)) {
253 _buildForInIndexable(forInStatement);
254 } else {
255 _buildForInIterator(forInStatement);
256 }
257 }
258
259 /// Builds the graph for a for-in node with an indexable expression.
260 ///
261 /// In this case we build:
262 ///
263 /// int end = a.length;
264 /// for (int i = 0;
265 /// i < a.length;
266 /// checkConcurrentModificationError(a.length == end, a), ++i) {
267 /// <declaredIdentifier> = a[i];
268 /// <body>
269 /// }
270 _buildForInIndexable(ir.ForInStatement forInStatement) {
271 SyntheticLocal indexVariable = new SyntheticLocal('_i', targetElement);
272
273 // These variables are shared by initializer, condition, body and update.
274 HInstruction array; // Set in buildInitializer.
275 bool isFixed; // Set in buildInitializer.
276 HInstruction originalLength = null; // Set for growable lists.
277
278 HInstruction buildGetLength() {
279 HFieldGet result = new HFieldGet(
280 astAdapter.jsIndexableLength, array, backend.positiveIntType,
281 isAssignable: !isFixed);
282 add(result);
283 return result;
284 }
285
286 void buildConcurrentModificationErrorCheck() {
287 if (originalLength == null) return;
288 // The static call checkConcurrentModificationError() is expanded in
289 // codegen to:
290 //
291 // array.length == _end || throwConcurrentModificationError(array)
292 //
293 HInstruction length = buildGetLength();
294 push(new HIdentity(length, originalLength, null, backend.boolType));
295 _pushStaticInvocation(
296 astAdapter.checkConcurrentModificationError,
297 [pop(), array],
298 astAdapter.checkConcurrentModificationErrorReturnType);
299 pop();
300 }
301
302 void buildInitializer() {
303 forInStatement.iterable.accept(this);
304 array = pop();
305 isFixed = astAdapter.isFixedLength(array.instructionType);
306 localsHandler.updateLocal(
307 indexVariable, graph.addConstantInt(0, compiler));
308 originalLength = buildGetLength();
309 }
310
311 HInstruction buildCondition() {
312 HInstruction index = localsHandler.readLocal(indexVariable);
313 HInstruction length = buildGetLength();
314 HInstruction compare = new HLess(index, length, null, backend.boolType);
315 add(compare);
316 return compare;
317 }
318
319 void buildBody() {
320 // If we had mechanically inlined ArrayIterator.moveNext(), it would have
321 // inserted the ConcurrentModificationError check as part of the
322 // condition. It is not necessary on the first iteration since there is
323 // no code between calls to `get iterator` and `moveNext`, so the test is
324 // moved to the loop update.
325
326 // Find a type for the element. Use the element type of the indexer of the
327 // array, as this is stronger than the iterator's `get current` type, for
328 // example, `get current` includes null.
329 // TODO(sra): The element type of a container type mask might be better.
330 TypeMask type = astAdapter.inferredIndexType(forInStatement);
331
332 HInstruction index = localsHandler.readLocal(indexVariable);
333 HInstruction value = new HIndex(array, index, null, type);
334 add(value);
335
336 localsHandler.updateLocal(
337 astAdapter.getLocal(forInStatement.variable), value);
338
339 forInStatement.body.accept(this);
340 }
341
342 void buildUpdate() {
343 // See buildBody as to why we check here.
344 buildConcurrentModificationErrorCheck();
345
346 // TODO(sra): It would be slightly shorter to generate `a[i++]` in the
347 // body (and that more closely follows what an inlined iterator would do)
348 // but the code is horrible as `i+1` is carried around the loop in an
349 // additional variable.
350 HInstruction index = localsHandler.readLocal(indexVariable);
351 HInstruction one = graph.addConstantInt(1, compiler);
352 HInstruction addInstruction =
353 new HAdd(index, one, null, backend.positiveIntType);
354 add(addInstruction);
355 localsHandler.updateLocal(indexVariable, addInstruction);
356 }
357
358 loopHandler.handleLoop(forInStatement, buildInitializer, buildCondition,
359 buildUpdate, buildBody);
360 }
361
362 _buildForInIterator(ir.ForInStatement forInStatement) {
363 // Generate a structure equivalent to:
364 // Iterator<E> $iter = <iterable>.iterator;
365 // while ($iter.moveNext()) {
366 // <declaredIdentifier> = $iter.current;
367 // <body>
368 // }
369
370 // The iterator is shared between initializer, condition and body.
371 HInstruction iterator;
372
373 void buildInitializer() {
374 TypeMask mask = astAdapter.typeOfIterator(forInStatement);
375 forInStatement.iterable.accept(this);
376 HInstruction receiver = pop();
377 _pushDynamicInvocation(forInStatement, mask, <HInstruction>[receiver],
378 selector: Selectors.iterator);
379 iterator = pop();
380 }
381
382 HInstruction buildCondition() {
383 TypeMask mask = astAdapter.typeOfIteratorMoveNext(forInStatement);
384 _pushDynamicInvocation(forInStatement, mask, <HInstruction>[iterator],
385 selector: Selectors.moveNext);
386 return popBoolified();
387 }
388
389 void buildBody() {
390 TypeMask mask = astAdapter.typeOfIteratorCurrent(forInStatement);
391 _pushDynamicInvocation(forInStatement, mask, [iterator],
392 selector: Selectors.current);
393 localsHandler.updateLocal(
394 astAdapter.getLocal(forInStatement.variable), pop());
395 forInStatement.body.accept(this);
396 }
397
398 loopHandler.handleLoop(
399 forInStatement, buildInitializer, buildCondition, () {}, buildBody);
400 }
401
402 @override
245 void visitWhileStatement(ir.WhileStatement whileStatement) { 403 void visitWhileStatement(ir.WhileStatement whileStatement) {
246 assert(isReachable); 404 assert(isReachable);
247 HInstruction buildCondition() { 405 HInstruction buildCondition() {
248 whileStatement.condition.accept(this); 406 whileStatement.condition.accept(this);
249 return popBoolified(); 407 return popBoolified();
250 } 408 }
251 409
252 loopHandler.handleLoop(whileStatement, () {}, buildCondition, () {}, () { 410 loopHandler.handleLoop(whileStatement, () {}, buildCondition, () {}, () {
253 whileStatement.body.accept(this); 411 whileStatement.body.accept(this);
254 }); 412 });
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
323 List<HInstruction> elements = <HInstruction>[]; 481 List<HInstruction> elements = <HInstruction>[];
324 for (ir.Expression element in listLiteral.expressions) { 482 for (ir.Expression element in listLiteral.expressions) {
325 element.accept(this); 483 element.accept(this);
326 elements.add(pop()); 484 elements.add(pop());
327 } 485 }
328 listInstruction = new HLiteralList(elements, backend.extendableArrayType); 486 listInstruction = new HLiteralList(elements, backend.extendableArrayType);
329 add(listInstruction); 487 add(listInstruction);
330 // TODO(het): set runtime type info 488 // TODO(het): set runtime type info
331 } 489 }
332 490
333 // TODO(het): Set the instruction type to the list type given by inference 491 TypeMask type = astAdapter.typeOfNewList(targetElement, listLiteral);
492 if (!type.containsAll(compiler.closedWorld)) {
493 listInstruction.instructionType = type;
494 }
334 stack.add(listInstruction); 495 stack.add(listInstruction);
335 } 496 }
336 497
337 @override 498 @override
338 void visitMapLiteral(ir.MapLiteral mapLiteral) { 499 void visitMapLiteral(ir.MapLiteral mapLiteral) {
339 if (mapLiteral.isConst) { 500 if (mapLiteral.isConst) {
340 stack.add( 501 stack.add(
341 graph.addConstant(astAdapter.getConstantFor(mapLiteral), compiler)); 502 graph.addConstant(astAdapter.getConstantFor(mapLiteral), compiler));
342 return; 503 return;
343 } 504 }
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
405 add(new HStaticStore(astAdapter.getElement(staticTarget), value)); 566 add(new HStaticStore(astAdapter.getElement(staticTarget), value));
406 } 567 }
407 stack.add(value); 568 stack.add(value);
408 } 569 }
409 570
410 @override 571 @override
411 void visitPropertyGet(ir.PropertyGet propertyGet) { 572 void visitPropertyGet(ir.PropertyGet propertyGet) {
412 propertyGet.receiver.accept(this); 573 propertyGet.receiver.accept(this);
413 HInstruction receiver = pop(); 574 HInstruction receiver = pop();
414 575
415 List<HInstruction> inputs = <HInstruction>[]; 576 _pushDynamicInvocation(propertyGet, astAdapter.typeOfGet(propertyGet),
416 bool isIntercepted = astAdapter.isIntercepted(propertyGet); 577 <HInstruction>[receiver]);
417 if (isIntercepted) {
418 HInterceptor interceptor = _interceptorFor(receiver);
419 inputs.add(interceptor);
420 }
421 inputs.add(receiver);
422
423 TypeMask type = astAdapter.selectorGetterTypeOf(propertyGet);
424
425 push(new HInvokeDynamicGetter(astAdapter.getGetterSelector(propertyGet),
426 astAdapter.typeOfGet(propertyGet), null, inputs, type));
427 } 578 }
428 579
429 @override 580 @override
430 void visitVariableGet(ir.VariableGet variableGet) { 581 void visitVariableGet(ir.VariableGet variableGet) {
431 LocalElement local = astAdapter.getElement(variableGet.variable); 582 Local local = astAdapter.getLocal(variableGet.variable);
432 stack.add(localsHandler.readLocal(local)); 583 stack.add(localsHandler.readLocal(local));
433 } 584 }
434 585
435 @override 586 @override
436 void visitVariableSet(ir.VariableSet variableSet) { 587 void visitVariableSet(ir.VariableSet variableSet) {
437 variableSet.value.accept(this); 588 variableSet.value.accept(this);
438 HInstruction value = pop(); 589 HInstruction value = pop();
439 _visitLocalSetter(variableSet.variable, value); 590 _visitLocalSetter(variableSet.variable, value);
440 } 591 }
441 592
442 @override 593 @override
443 void visitVariableDeclaration(ir.VariableDeclaration declaration) { 594 void visitVariableDeclaration(ir.VariableDeclaration declaration) {
444 LocalElement local = astAdapter.getElement(declaration); 595 Local local = astAdapter.getLocal(declaration);
445 if (declaration.initializer == null) { 596 if (declaration.initializer == null) {
446 HInstruction initialValue = graph.addConstantNull(compiler); 597 HInstruction initialValue = graph.addConstantNull(compiler);
447 localsHandler.updateLocal(local, initialValue); 598 localsHandler.updateLocal(local, initialValue);
448 } else { 599 } else {
449 // TODO(het): handle case where the variable is top-level or static 600 // TODO(het): handle case where the variable is top-level or static
450 declaration.initializer.accept(this); 601 declaration.initializer.accept(this);
451 HInstruction initialValue = pop(); 602 HInstruction initialValue = pop();
452 603
453 _visitLocalSetter(declaration, initialValue); 604 _visitLocalSetter(declaration, initialValue);
454 605
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
501 void _pushStaticInvocation( 652 void _pushStaticInvocation(
502 ir.Node target, List<HInstruction> arguments, TypeMask typeMask) { 653 ir.Node target, List<HInstruction> arguments, TypeMask typeMask) {
503 HInstruction instruction = new HInvokeStatic( 654 HInstruction instruction = new HInvokeStatic(
504 astAdapter.getElement(target).declaration, arguments, typeMask, 655 astAdapter.getElement(target).declaration, arguments, typeMask,
505 targetCanThrow: astAdapter.getCanThrow(target)); 656 targetCanThrow: astAdapter.getCanThrow(target));
506 instruction.sideEffects = astAdapter.getSideEffects(target); 657 instruction.sideEffects = astAdapter.getSideEffects(target);
507 658
508 push(instruction); 659 push(instruction);
509 } 660 }
510 661
662 void _pushDynamicInvocation(
663 ir.Node node, TypeMask mask, List<HInstruction> arguments,
664 {Selector selector}) {
665 HInstruction receiver = arguments.first;
666 List<HInstruction> inputs = <HInstruction>[];
667
668 selector ??= astAdapter.getSelector(node);
669 bool isIntercepted = astAdapter.isInterceptedSelector(selector);
670
671 if (isIntercepted) {
672 HInterceptor interceptor = _interceptorFor(receiver);
673 inputs.add(interceptor);
674 }
675 inputs.addAll(arguments);
676
677 TypeMask type = astAdapter.selectorTypeOf(selector, mask);
678 if (selector.isGetter) {
679 push(new HInvokeDynamicGetter(selector, mask, null, inputs, type));
680 } else if (selector.isSetter) {
681 push(new HInvokeDynamicSetter(selector, mask, null, inputs, type));
682 } else {
683 push(new HInvokeDynamicMethod(
684 selector, mask, inputs, type, isIntercepted));
685 }
686 }
687
511 // TODO(het): Decide when to inline 688 // TODO(het): Decide when to inline
512 @override 689 @override
513 void visitMethodInvocation(ir.MethodInvocation invocation) { 690 void visitMethodInvocation(ir.MethodInvocation invocation) {
514 invocation.receiver.accept(this); 691 invocation.receiver.accept(this);
515 HInstruction receiver = pop(); 692 HInstruction receiver = pop();
516 693
517 List<HInstruction> arguments = <HInstruction>[receiver] 694 _pushDynamicInvocation(
518 ..addAll(_visitArguments(invocation.arguments)); 695 invocation,
519 696 astAdapter.typeOfInvocation(invocation),
520 List<HInstruction> inputs = <HInstruction>[]; 697 <HInstruction>[receiver]
521 698 ..addAll(_visitArguments(invocation.arguments)));
522 bool isIntercepted = astAdapter.isIntercepted(invocation);
523 if (isIntercepted) {
524 HInterceptor interceptor = _interceptorFor(receiver);
525 inputs.add(interceptor);
526 }
527 inputs.addAll(arguments);
528
529 TypeMask type = astAdapter.selectorTypeOf(invocation);
530
531 push(new HInvokeDynamicMethod(astAdapter.getSelector(invocation),
532 astAdapter.typeOfInvocation(invocation), inputs, type, isIntercepted));
533 } 699 }
534 700
535 HInterceptor _interceptorFor(HInstruction intercepted) { 701 HInterceptor _interceptorFor(HInstruction intercepted) {
536 HInterceptor interceptor = 702 HInterceptor interceptor =
537 new HInterceptor(intercepted, backend.nonNullType); 703 new HInterceptor(intercepted, backend.nonNullType);
538 add(interceptor); 704 add(interceptor);
539 return interceptor; 705 return interceptor;
540 } 706 }
541 707
542 static ir.Class _containingClass(ir.TreeNode node) { 708 static ir.Class _containingClass(ir.TreeNode node) {
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
622 push(new HNot(popBoolified(), backend.boolType)); 788 push(new HNot(popBoolified(), backend.boolType));
623 } 789 }
624 790
625 @override 791 @override
626 void visitStringConcatenation(ir.StringConcatenation stringConcat) { 792 void visitStringConcatenation(ir.StringConcatenation stringConcat) {
627 KernelStringBuilder stringBuilder = new KernelStringBuilder(this); 793 KernelStringBuilder stringBuilder = new KernelStringBuilder(this);
628 stringConcat.accept(stringBuilder); 794 stringConcat.accept(stringBuilder);
629 stack.add(stringBuilder.result); 795 stack.add(stringBuilder.result);
630 } 796 }
631 } 797 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/ssa/builder.dart ('k') | pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698