| OLD | NEW |
| 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 library dart2js.kernel.backend_strategy; | 5 library dart2js.kernel.backend_strategy; |
| 6 | 6 |
| 7 import 'package:kernel/ast.dart' as ir; | 7 import 'package:kernel/ast.dart' as ir; |
| 8 | 8 |
| 9 import '../backend_strategy.dart'; | 9 import '../backend_strategy.dart'; |
| 10 import '../closure.dart'; | 10 import '../closure.dart'; |
| (...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 273 | 273 |
| 274 KernelToLocalsMap getLocalsMap(MemberEntity member) { | 274 KernelToLocalsMap getLocalsMap(MemberEntity member) { |
| 275 return _localsMaps.putIfAbsent( | 275 return _localsMaps.putIfAbsent( |
| 276 member, () => new KernelToLocalsMapImpl(member)); | 276 member, () => new KernelToLocalsMapImpl(member)); |
| 277 } | 277 } |
| 278 } | 278 } |
| 279 | 279 |
| 280 class KernelToLocalsMapImpl implements KernelToLocalsMap { | 280 class KernelToLocalsMapImpl implements KernelToLocalsMap { |
| 281 final List<MemberEntity> _members = <MemberEntity>[]; | 281 final List<MemberEntity> _members = <MemberEntity>[]; |
| 282 Map<ir.VariableDeclaration, KLocal> _map = <ir.VariableDeclaration, KLocal>{}; | 282 Map<ir.VariableDeclaration, KLocal> _map = <ir.VariableDeclaration, KLocal>{}; |
| 283 Map<ir.LabeledStatement, KJumpTarget> _jumpTargetMap; | 283 Map<ir.TreeNode, KJumpTarget> _jumpTargetMap; |
| 284 Set<ir.BreakStatement> _breaksAsContinue; |
| 284 | 285 |
| 285 MemberEntity get currentMember => _members.last; | 286 MemberEntity get currentMember => _members.last; |
| 286 | 287 |
| 287 // TODO(johnniwinther): Compute this eagerly from the root of the member. | 288 // TODO(johnniwinther): Compute this eagerly from the root of the member. |
| 288 void _ensureJumpMap(ir.TreeNode node) { | 289 void _ensureJumpMap(ir.TreeNode node) { |
| 289 if (_jumpTargetMap == null) { | 290 if (_jumpTargetMap == null) { |
| 290 JumpVisitor visitor = new JumpVisitor(currentMember); | 291 JumpVisitor visitor = new JumpVisitor(currentMember); |
| 291 | 292 |
| 292 // Find the root node for the current member. | 293 // Find the root node for the current member. |
| 293 while (node is! ir.Member) { | 294 while (node is! ir.Member) { |
| 294 node = node.parent; | 295 node = node.parent; |
| 295 } | 296 } |
| 296 | 297 |
| 297 node.accept(visitor); | 298 node.accept(visitor); |
| 298 _jumpTargetMap = visitor.jumpTargetMap; | 299 _jumpTargetMap = visitor.jumpTargetMap; |
| 300 _breaksAsContinue = visitor.breaksAsContinue; |
| 299 } | 301 } |
| 300 } | 302 } |
| 301 | 303 |
| 302 KernelToLocalsMapImpl(MemberEntity member) { | 304 KernelToLocalsMapImpl(MemberEntity member) { |
| 303 _members.add(member); | 305 _members.add(member); |
| 304 } | 306 } |
| 305 | 307 |
| 306 @override | 308 @override |
| 307 void enterInlinedMember(MemberEntity member) { | 309 void enterInlinedMember(MemberEntity member) { |
| 308 _members.add(member); | 310 _members.add(member); |
| 309 } | 311 } |
| 310 | 312 |
| 311 @override | 313 @override |
| 312 void leaveInlinedMember(MemberEntity member) { | 314 void leaveInlinedMember(MemberEntity member) { |
| 313 assert(member == currentMember); | 315 assert(member == currentMember); |
| 314 _members.removeLast(); | 316 _members.removeLast(); |
| 315 } | 317 } |
| 316 | 318 |
| 317 @override | 319 @override |
| 318 JumpTarget getJumpTargetForBreak(ir.BreakStatement node) { | 320 JumpTarget getJumpTargetForBreak(ir.BreakStatement node) { |
| 319 _ensureJumpMap(node.target); | 321 _ensureJumpMap(node.target); |
| 320 JumpTarget target = _jumpTargetMap[node.target]; | 322 JumpTarget target = _jumpTargetMap[node]; |
| 321 assert(target != null, failedAt(currentMember, 'No target for $node.')); | 323 assert(target != null, failedAt(currentMember, 'No target for $node.')); |
| 322 return target; | 324 return target; |
| 323 } | 325 } |
| 324 | 326 |
| 325 @override | 327 @override |
| 328 bool generateContinueForBreak(ir.BreakStatement node) { |
| 329 return _breaksAsContinue.contains(node); |
| 330 } |
| 331 |
| 332 @override |
| 326 JumpTarget getJumpTargetForContinueSwitch(ir.ContinueSwitchStatement node) { | 333 JumpTarget getJumpTargetForContinueSwitch(ir.ContinueSwitchStatement node) { |
| 327 _ensureJumpMap(node.target); | 334 _ensureJumpMap(node.target); |
| 328 throw new UnimplementedError( | 335 throw new UnimplementedError( |
| 329 'KernelToLocalsMapImpl.getJumpTargetForContinueSwitch'); | 336 'KernelToLocalsMapImpl.getJumpTargetForContinueSwitch'); |
| 330 } | 337 } |
| 331 | 338 |
| 332 @override | 339 @override |
| 333 JumpTarget getJumpTargetForSwitchCase(ir.SwitchCase node) { | 340 JumpTarget getJumpTargetForSwitchCase(ir.SwitchCase node) { |
| 334 _ensureJumpMap(node); | 341 _ensureJumpMap(node); |
| 335 throw new UnimplementedError( | 342 throw new UnimplementedError( |
| 336 'KernelToLocalsMapImpl.getJumpTargetForSwitchCase'); | 343 'KernelToLocalsMapImpl.getJumpTargetForSwitchCase'); |
| 337 } | 344 } |
| 338 | 345 |
| 339 @override | 346 @override |
| 340 JumpTarget getJumpTargetForDo(ir.DoStatement node) { | 347 JumpTarget getJumpTargetForDo(ir.DoStatement node) { |
| 341 _ensureJumpMap(node); | 348 _ensureJumpMap(node); |
| 342 return _jumpTargetMap[node.parent]; | 349 return _jumpTargetMap[node.parent]; |
| 343 } | 350 } |
| 344 | 351 |
| 345 @override | 352 @override |
| 346 JumpTarget getJumpTargetForLabel(ir.LabeledStatement node) { | 353 JumpTarget getJumpTargetForLabel(ir.LabeledStatement node) { |
| 347 _ensureJumpMap(node); | 354 _ensureJumpMap(node); |
| 348 JumpTarget target = _jumpTargetMap[node]; | 355 return _jumpTargetMap[node]; |
| 349 assert(target != null, failedAt(currentMember, 'No target for $node.')); | |
| 350 return target; | |
| 351 } | 356 } |
| 352 | 357 |
| 353 @override | 358 @override |
| 354 JumpTarget getJumpTargetForSwitch(ir.SwitchStatement node) { | 359 JumpTarget getJumpTargetForSwitch(ir.SwitchStatement node) { |
| 355 _ensureJumpMap(node); | 360 _ensureJumpMap(node); |
| 356 throw new UnimplementedError( | 361 throw new UnimplementedError( |
| 357 'KernelToLocalsMapImpl.getJumpTargetForSwitch'); | 362 'KernelToLocalsMapImpl.getJumpTargetForSwitch'); |
| 358 } | 363 } |
| 359 | 364 |
| 360 @override | 365 @override |
| 361 JumpTarget getJumpTargetForFor(ir.ForStatement node) { | 366 JumpTarget getJumpTargetForFor(ir.ForStatement node) { |
| 362 _ensureJumpMap(node); | 367 _ensureJumpMap(node); |
| 363 return _jumpTargetMap[node.parent]; | 368 return _jumpTargetMap[node]; |
| 364 } | 369 } |
| 365 | 370 |
| 366 @override | 371 @override |
| 367 JumpTarget getJumpTargetForForIn(ir.ForInStatement node) { | 372 JumpTarget getJumpTargetForForIn(ir.ForInStatement node) { |
| 368 _ensureJumpMap(node); | 373 _ensureJumpMap(node); |
| 369 return _jumpTargetMap[node.parent]; | 374 return _jumpTargetMap[node.parent]; |
| 370 } | 375 } |
| 371 | 376 |
| 372 @override | 377 @override |
| 373 JumpTarget getJumpTargetForWhile(ir.WhileStatement node) { | 378 JumpTarget getJumpTargetForWhile(ir.WhileStatement node) { |
| 374 _ensureJumpMap(node); | 379 _ensureJumpMap(node); |
| 375 return _jumpTargetMap[node.parent]; | 380 return _jumpTargetMap[node.parent]; |
| 376 } | 381 } |
| 377 | 382 |
| 378 @override | 383 @override |
| 379 Local getLocal(ir.VariableDeclaration node) { | 384 Local getLocal(ir.VariableDeclaration node) { |
| 380 return _map.putIfAbsent(node, () { | 385 return _map.putIfAbsent(node, () { |
| 381 return new KLocal(node.name, currentMember); | 386 return new KLocal(node.name, currentMember); |
| 382 }); | 387 }); |
| 383 } | 388 } |
| 384 | 389 |
| 385 @override | 390 @override |
| 386 LoopClosureRepresentationInfo getClosureRepresentationInfoForLoop( | 391 LoopClosureRepresentationInfo getClosureRepresentationInfoForLoop( |
| 387 ClosureDataLookup closureLookup, ir.TreeNode node) { | 392 ClosureDataLookup closureLookup, ir.TreeNode node) { |
| 388 return closureLookup.getClosureRepresentationInfoForLoop(node); | 393 return closureLookup.getClosureRepresentationInfoForLoop(node); |
| 389 } | 394 } |
| 390 } | 395 } |
| 391 | 396 |
| 392 class JumpVisitor extends ir.Visitor { | 397 class JumpVisitor extends ir.Visitor { |
| 398 int index = 0; |
| 393 final MemberEntity member; | 399 final MemberEntity member; |
| 394 final Map<ir.LabeledStatement, KJumpTarget> jumpTargetMap = | 400 final Map<ir.TreeNode, KJumpTarget> jumpTargetMap = |
| 395 <ir.LabeledStatement, KJumpTarget>{}; | 401 <ir.TreeNode, KJumpTarget>{}; |
| 402 final Set<ir.BreakStatement> breaksAsContinue = new Set<ir.BreakStatement>(); |
| 396 | 403 |
| 397 JumpVisitor(this.member); | 404 JumpVisitor(this.member); |
| 398 | 405 |
| 399 KJumpTarget _getJumpTarget(ir.LabeledStatement node) { | 406 KJumpTarget _getJumpTarget(ir.TreeNode node) { |
| 400 return jumpTargetMap.putIfAbsent(node, () { | 407 return jumpTargetMap.putIfAbsent(node, () { |
| 401 return new KJumpTarget(member, jumpTargetMap.length); | 408 return new KJumpTarget(member, index++); |
| 402 }); | 409 }); |
| 403 } | 410 } |
| 404 | 411 |
| 405 @override | 412 @override |
| 406 defaultNode(ir.Node node) => node.visitChildren(this); | 413 defaultNode(ir.Node node) => node.visitChildren(this); |
| 407 | 414 |
| 415 bool _canBeBreakTarget(ir.TreeNode node) { |
| 416 // TODO(johnniwinther): Add more. |
| 417 return node is ir.ForStatement; |
| 418 } |
| 419 |
| 420 bool _canBeContinueTarget(ir.TreeNode node) { |
| 421 // TODO(johnniwinther): Add more. |
| 422 return node is ir.ForStatement; |
| 423 } |
| 424 |
| 408 @override | 425 @override |
| 409 visitBreakStatement(ir.BreakStatement node) { | 426 visitBreakStatement(ir.BreakStatement node) { |
| 410 KJumpTarget target = _getJumpTarget(node.target); | 427 // TODO(johnniwinther): Add labels if the enclosing loop is not the implicit |
| 411 target.isBreakTarget = true; | 428 // break target. |
| 429 KJumpTarget target; |
| 430 ir.TreeNode body = node.target.body; |
| 431 ir.TreeNode parent = node.target.parent; |
| 432 if (_canBeBreakTarget(body)) { |
| 433 // We have code like |
| 434 // |
| 435 // l1: for (int i = 0; i < 10; i++) { |
| 436 // break l1: |
| 437 // } |
| 438 // |
| 439 // and can therefore use the for loop as the break target. |
| 440 target = _getJumpTarget(body); |
| 441 target.isBreakTarget = true; |
| 442 } else if (_canBeContinueTarget(parent)) { |
| 443 // We have code like |
| 444 // |
| 445 // for (int i = 0; i < 10; i++) l1: { |
| 446 // break l1: |
| 447 // } |
| 448 // |
| 449 // and can therefore use the for loop as a continue target. |
| 450 target = _getJumpTarget(parent); |
| 451 target.isContinueTarget = true; |
| 452 breaksAsContinue.add(node); |
| 453 } else { |
| 454 target = _getJumpTarget(node.target); |
| 455 target.isBreakTarget = true; |
| 456 } |
| 457 jumpTargetMap[node] = target; |
| 412 super.visitBreakStatement(node); | 458 super.visitBreakStatement(node); |
| 413 } | 459 } |
| 414 } | 460 } |
| 415 | 461 |
| 416 class KJumpTarget extends JumpTarget<ir.Node> { | 462 class KJumpTarget extends JumpTarget<ir.Node> { |
| 417 final MemberEntity memberContext; | 463 final MemberEntity memberContext; |
| 418 final int nestingLevel; | 464 final int nestingLevel; |
| 419 | 465 |
| 420 KJumpTarget(this.memberContext, this.nestingLevel); | 466 KJumpTarget(this.memberContext, this.nestingLevel); |
| 421 | 467 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 434 | 480 |
| 435 @override | 481 @override |
| 436 List<LabelDefinition<ir.Node>> get labels { | 482 List<LabelDefinition<ir.Node>> get labels { |
| 437 return const <LabelDefinition<ir.Node>>[]; | 483 return const <LabelDefinition<ir.Node>>[]; |
| 438 } | 484 } |
| 439 | 485 |
| 440 @override | 486 @override |
| 441 ir.Node get statement { | 487 ir.Node get statement { |
| 442 throw new UnimplementedError('KJumpTarget.statement'); | 488 throw new UnimplementedError('KJumpTarget.statement'); |
| 443 } | 489 } |
| 490 |
| 491 String toString() { |
| 492 StringBuffer sb = new StringBuffer(); |
| 493 sb.write('KJumpTarget['); |
| 494 sb.write('memberContext='); |
| 495 sb.write(memberContext); |
| 496 sb.write(',nestingLevel='); |
| 497 sb.write(nestingLevel); |
| 498 sb.write(',isBreakTarget='); |
| 499 sb.write(isBreakTarget); |
| 500 sb.write(',isContinueTarget='); |
| 501 sb.write(isContinueTarget); |
| 502 sb.write(']'); |
| 503 return sb.toString(); |
| 504 } |
| 444 } | 505 } |
| 445 | 506 |
| 446 class KLocal implements Local { | 507 class KLocal implements Local { |
| 447 final String name; | 508 final String name; |
| 448 final MemberEntity memberContext; | 509 final MemberEntity memberContext; |
| 449 | 510 |
| 450 KLocal(this.name, this.memberContext); | 511 KLocal(this.name, this.memberContext); |
| 451 | 512 |
| 452 @override | 513 @override |
| 453 Entity get executableContext => memberContext; | 514 Entity get executableContext => memberContext; |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 507 Iterable<ClassEntity> sortClasses(Iterable<ClassEntity> classes) { | 568 Iterable<ClassEntity> sortClasses(Iterable<ClassEntity> classes) { |
| 508 return classes.toList() | 569 return classes.toList() |
| 509 ..sort((ClassEntity a, ClassEntity b) { | 570 ..sort((ClassEntity a, ClassEntity b) { |
| 510 int r = _compareLibraries(a.library, b.library); | 571 int r = _compareLibraries(a.library, b.library); |
| 511 if (r != 0) return r; | 572 if (r != 0) return r; |
| 512 return _compareNodes( | 573 return _compareNodes( |
| 513 a, elementMap.getClassNode(a), b, elementMap.getClassNode(b)); | 574 a, elementMap.getClassNode(a), b, elementMap.getClassNode(b)); |
| 514 }); | 575 }); |
| 515 } | 576 } |
| 516 } | 577 } |
| OLD | NEW |