| 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.js_model.locals; | 5 library dart2js.js_model.locals; |
| 6 | 6 |
| 7 import 'package:kernel/ast.dart' as ir; | 7 import 'package:kernel/ast.dart' as ir; |
| 8 | 8 |
| 9 import 'closure.dart' show JClosureClass; | 9 import 'closure.dart' show JClosureClass; |
| 10 import '../closure.dart'; | 10 import '../closure.dart'; |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 164 } | 164 } |
| 165 | 165 |
| 166 @override | 166 @override |
| 167 CapturedLoopScope getCapturedLoopScope( | 167 CapturedLoopScope getCapturedLoopScope( |
| 168 ClosureDataLookup closureLookup, ir.TreeNode node) { | 168 ClosureDataLookup closureLookup, ir.TreeNode node) { |
| 169 return closureLookup.getCapturedLoopScope(node); | 169 return closureLookup.getCapturedLoopScope(node); |
| 170 } | 170 } |
| 171 } | 171 } |
| 172 | 172 |
| 173 class JumpVisitor extends ir.Visitor { | 173 class JumpVisitor extends ir.Visitor { |
| 174 int index = 0; | 174 int jumpIndex = 0; |
| 175 int labelIndex = 0; |
| 175 final MemberEntity member; | 176 final MemberEntity member; |
| 176 final Map<ir.TreeNode, JJumpTarget> jumpTargetMap = | 177 final Map<ir.TreeNode, JJumpTarget> jumpTargetMap = |
| 177 <ir.TreeNode, JJumpTarget>{}; | 178 <ir.TreeNode, JJumpTarget>{}; |
| 178 final Set<ir.BreakStatement> breaksAsContinue = new Set<ir.BreakStatement>(); | 179 final Set<ir.BreakStatement> breaksAsContinue = new Set<ir.BreakStatement>(); |
| 179 | 180 |
| 180 JumpVisitor(this.member); | 181 JumpVisitor(this.member); |
| 181 | 182 |
| 182 JJumpTarget _getJumpTarget(ir.TreeNode node) { | 183 JJumpTarget _getJumpTarget(ir.TreeNode node) { |
| 183 return jumpTargetMap.putIfAbsent(node, () { | 184 return jumpTargetMap.putIfAbsent(node, () { |
| 184 return new JJumpTarget(member, index++); | 185 return new JJumpTarget(member, jumpIndex++); |
| 185 }); | 186 }); |
| 186 } | 187 } |
| 187 | 188 |
| 188 @override | 189 @override |
| 189 defaultNode(ir.Node node) => node.visitChildren(this); | 190 defaultNode(ir.Node node) => node.visitChildren(this); |
| 190 | 191 |
| 191 bool _canBeBreakTarget(ir.TreeNode node) { | 192 bool _canBeBreakTarget(ir.TreeNode node) { |
| 192 return node is ir.ForStatement || | 193 return node is ir.ForStatement || |
| 193 node is ir.ForInStatement || | 194 node is ir.ForInStatement || |
| 194 node is ir.WhileStatement || | 195 node is ir.WhileStatement || |
| (...skipping 19 matching lines...) Expand all Loading... |
| 214 if (_canBeBreakTarget(body)) { | 215 if (_canBeBreakTarget(body)) { |
| 215 // We have code like | 216 // We have code like |
| 216 // | 217 // |
| 217 // l1: for (int i = 0; i < 10; i++) { | 218 // l1: for (int i = 0; i < 10; i++) { |
| 218 // break l1: | 219 // break l1: |
| 219 // } | 220 // } |
| 220 // | 221 // |
| 221 // and can therefore use the for loop as the break target. | 222 // and can therefore use the for loop as the break target. |
| 222 target = _getJumpTarget(body); | 223 target = _getJumpTarget(body); |
| 223 target.isBreakTarget = true; | 224 target.isBreakTarget = true; |
| 225 ir.TreeNode search = node; |
| 226 bool needsLabel = false; |
| 227 while (search != node.target) { |
| 228 if (_canBeBreakTarget(search)) { |
| 229 needsLabel = search != body; |
| 230 break; |
| 231 } |
| 232 search = search.parent; |
| 233 } |
| 234 if (needsLabel) { |
| 235 target.addLabel(node.target, 'label${labelIndex++}', |
| 236 isBreakTarget: true); |
| 237 } |
| 224 } else if (_canBeContinueTarget(parent)) { | 238 } else if (_canBeContinueTarget(parent)) { |
| 225 // We have code like | 239 // We have code like |
| 226 // | 240 // |
| 227 // for (int i = 0; i < 10; i++) l1: { | 241 // for (int i = 0; i < 10; i++) l1: { |
| 228 // break l1: | 242 // break l1: |
| 229 // } | 243 // } |
| 230 // | 244 // |
| 231 // and can therefore use the for loop as a continue target. | 245 // and can therefore use the for loop as a continue target. |
| 232 target = _getJumpTarget(parent); | 246 target = _getJumpTarget(parent); |
| 233 target.isContinueTarget = true; | 247 target.isContinueTarget = true; |
| 234 breaksAsContinue.add(node); | 248 breaksAsContinue.add(node); |
| 235 } else { | 249 } else { |
| 236 target = _getJumpTarget(node.target); | 250 target = _getJumpTarget(node.target); |
| 237 target.isBreakTarget = true; | 251 target.isBreakTarget = true; |
| 238 } | 252 } |
| 239 jumpTargetMap[node] = target; | 253 jumpTargetMap[node] = target; |
| 240 super.visitBreakStatement(node); | 254 super.visitBreakStatement(node); |
| 241 } | 255 } |
| 242 } | 256 } |
| 243 | 257 |
| 244 class JJumpTarget extends JumpTarget<ir.Node> { | 258 class JJumpTarget extends JumpTarget<ir.Node> { |
| 245 final MemberEntity memberContext; | 259 final MemberEntity memberContext; |
| 246 final int nestingLevel; | 260 final int nestingLevel; |
| 261 List<LabelDefinition<ir.Node>> _labels; |
| 247 | 262 |
| 248 JJumpTarget(this.memberContext, this.nestingLevel); | 263 JJumpTarget(this.memberContext, this.nestingLevel); |
| 249 | 264 |
| 250 bool isBreakTarget = false; | 265 bool isBreakTarget = false; |
| 251 bool isContinueTarget = false; | 266 bool isContinueTarget = false; |
| 252 bool isSwitch = false; | 267 bool isSwitch = false; |
| 253 | 268 |
| 254 @override | 269 @override |
| 255 Entity get executableContext => memberContext; | 270 Entity get executableContext => memberContext; |
| 256 | 271 |
| 257 @override | 272 @override |
| 258 LabelDefinition<ir.Node> addLabel(ir.Node label, String labelName, | 273 LabelDefinition<ir.Node> addLabel(ir.Node label, String labelName, |
| 259 {bool isBreakTarget: false}) { | 274 {bool isBreakTarget: false}) { |
| 260 throw new UnimplementedError('KJumpTarget.addLabel'); | 275 _labels ??= <LabelDefinition<ir.Node>>[]; |
| 276 LabelDefinition<ir.Node> labelDefinition = new JLabelDefinition( |
| 277 this, label, labelName, |
| 278 isBreakTarget: isBreakTarget); |
| 279 _labels.add(labelDefinition); |
| 280 return labelDefinition; |
| 261 } | 281 } |
| 262 | 282 |
| 263 @override | 283 @override |
| 264 List<LabelDefinition<ir.Node>> get labels { | 284 List<LabelDefinition<ir.Node>> get labels { |
| 265 return const <LabelDefinition<ir.Node>>[]; | 285 return _labels ?? const <LabelDefinition<ir.Node>>[]; |
| 266 } | 286 } |
| 267 | 287 |
| 268 @override | 288 @override |
| 269 ir.Node get statement { | 289 ir.Node get statement { |
| 270 throw new UnimplementedError('KJumpTarget.statement'); | 290 throw new UnimplementedError('JJumpTarget.statement'); |
| 271 } | 291 } |
| 272 | 292 |
| 273 String toString() { | 293 String toString() { |
| 274 StringBuffer sb = new StringBuffer(); | 294 StringBuffer sb = new StringBuffer(); |
| 275 sb.write('KJumpTarget['); | 295 sb.write('JJumpTarget('); |
| 276 sb.write('memberContext='); | 296 sb.write('memberContext='); |
| 277 sb.write(memberContext); | 297 sb.write(memberContext); |
| 278 sb.write(',nestingLevel='); | 298 sb.write(',nestingLevel='); |
| 279 sb.write(nestingLevel); | 299 sb.write(nestingLevel); |
| 280 sb.write(',isBreakTarget='); | 300 sb.write(',isBreakTarget='); |
| 281 sb.write(isBreakTarget); | 301 sb.write(isBreakTarget); |
| 282 sb.write(',isContinueTarget='); | 302 sb.write(',isContinueTarget='); |
| 283 sb.write(isContinueTarget); | 303 sb.write(isContinueTarget); |
| 284 sb.write(']'); | 304 if (_labels != null) { |
| 305 sb.write(',labels='); |
| 306 sb.write(_labels); |
| 307 } |
| 308 sb.write(')'); |
| 285 return sb.toString(); | 309 return sb.toString(); |
| 286 } | 310 } |
| 287 } | 311 } |
| 312 |
| 313 class JLabelDefinition extends LabelDefinition<ir.Node> { |
| 314 final JumpTarget<ir.Node> target; |
| 315 final ir.Node label; |
| 316 final String labelName; |
| 317 final bool isBreakTarget; |
| 318 final bool isContinueTarget; |
| 319 |
| 320 JLabelDefinition(this.target, this.label, this.labelName, |
| 321 {this.isBreakTarget: false, this.isContinueTarget: false}); |
| 322 |
| 323 @override |
| 324 String get name => labelName; |
| 325 String toString() { |
| 326 StringBuffer sb = new StringBuffer(); |
| 327 sb.write('JLabelDefinition('); |
| 328 sb.write('label='); |
| 329 sb.write(label); |
| 330 sb.write(',labelName='); |
| 331 sb.write(labelName); |
| 332 sb.write(',isBreakTarget='); |
| 333 sb.write(isBreakTarget); |
| 334 sb.write(',isContinueTarget='); |
| 335 sb.write(isContinueTarget); |
| 336 sb.write(')'); |
| 337 return sb.toString(); |
| 338 } |
| 339 } |
| 288 | 340 |
| 289 class JLocal implements Local { | 341 class JLocal implements Local { |
| 290 final String name; | 342 final String name; |
| 291 final MemberEntity memberContext; | 343 final MemberEntity memberContext; |
| 292 | 344 |
| 293 /// True if this local represents a local parameter. | 345 /// True if this local represents a local parameter. |
| 294 final bool isRegularParameter; | 346 final bool isRegularParameter; |
| 295 | 347 |
| 296 JLocal(this.name, this.memberContext, [isParameter = false]) | 348 JLocal(this.name, this.memberContext, [isParameter = false]) |
| 297 : isRegularParameter = isParameter; | 349 : isRegularParameter = isParameter; |
| 298 | 350 |
| 299 @override | 351 @override |
| 300 Entity get executableContext => memberContext; | 352 Entity get executableContext => memberContext; |
| 301 | 353 |
| 302 String toString() { | 354 String toString() { |
| 303 StringBuffer sb = new StringBuffer(); | 355 StringBuffer sb = new StringBuffer(); |
| 304 sb.write('local('); | 356 sb.write('local('); |
| 305 if (memberContext.enclosingClass != null) { | 357 if (memberContext.enclosingClass != null) { |
| 306 sb.write(memberContext.enclosingClass.name); | 358 sb.write(memberContext.enclosingClass.name); |
| 307 sb.write('.'); | 359 sb.write('.'); |
| 308 } | 360 } |
| 309 sb.write(memberContext.name); | 361 sb.write(memberContext.name); |
| 310 sb.write('#'); | 362 sb.write('#'); |
| 311 sb.write(name); | 363 sb.write(name); |
| 312 sb.write(')'); | 364 sb.write(')'); |
| 313 return sb.toString(); | 365 return sb.toString(); |
| 314 } | 366 } |
| 315 } | 367 } |
| OLD | NEW |