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 |