OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |