OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 class Interceptors { | 5 class Interceptors { |
6 Compiler compiler; | 6 Compiler compiler; |
7 Interceptors(Compiler this.compiler); | 7 Interceptors(Compiler this.compiler); |
8 | 8 |
9 SourceString mapOperatorToMethodName(Operator op) { | 9 SourceString mapOperatorToMethodName(Operator op) { |
10 String name = op.source.stringValue; | 10 String name = op.source.stringValue; |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
87 | 87 |
88 class SsaBuilderTask extends CompilerTask { | 88 class SsaBuilderTask extends CompilerTask { |
89 SsaBuilderTask(Compiler compiler) | 89 SsaBuilderTask(Compiler compiler) |
90 : super(compiler), interceptors = new Interceptors(compiler); | 90 : super(compiler), interceptors = new Interceptors(compiler); |
91 String get name() => 'SSA builder'; | 91 String get name() => 'SSA builder'; |
92 Interceptors interceptors; | 92 Interceptors interceptors; |
93 | 93 |
94 HGraph build(WorkItem work) { | 94 HGraph build(WorkItem work) { |
95 return measure(() { | 95 return measure(() { |
96 FunctionElement element = work.element; | 96 FunctionElement element = work.element; |
97 TreeElements elements = work.resolutionTree; | |
98 HInstruction.idCounter = 0; | 97 HInstruction.idCounter = 0; |
99 SsaBuilder builder = new SsaBuilder(compiler, elements); | 98 SsaBuilder builder = new SsaBuilder(compiler, work); |
100 HGraph graph; | 99 HGraph graph; |
101 switch (element.kind) { | 100 switch (element.kind) { |
102 case ElementKind.GENERATIVE_CONSTRUCTOR: | 101 case ElementKind.GENERATIVE_CONSTRUCTOR: |
103 graph = compileConstructor(builder, work); | 102 graph = compileConstructor(builder, work); |
104 break; | 103 break; |
105 case ElementKind.GENERATIVE_CONSTRUCTOR_BODY: | 104 case ElementKind.GENERATIVE_CONSTRUCTOR_BODY: |
106 case ElementKind.FUNCTION: | 105 case ElementKind.FUNCTION: |
107 case ElementKind.GETTER: | 106 case ElementKind.GETTER: |
108 case ElementKind.SETTER: | 107 case ElementKind.SETTER: |
109 graph = builder.buildMethod(work.element); | 108 graph = builder.buildMethod(work.element); |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
260 assert(isAccessedDirectly(element)); | 259 assert(isAccessedDirectly(element)); |
261 return directLocals[element] !== null; | 260 return directLocals[element] !== null; |
262 } | 261 } |
263 | 262 |
264 /** | 263 /** |
265 * Returns true if the local can be accessed directly. Boxed variables or | 264 * Returns true if the local can be accessed directly. Boxed variables or |
266 * captured variables that are stored in the closure-field return [false]. | 265 * captured variables that are stored in the closure-field return [false]. |
267 */ | 266 */ |
268 bool isAccessedDirectly(Element element) { | 267 bool isAccessedDirectly(Element element) { |
269 assert(element !== null); | 268 assert(element !== null); |
270 return redirectionMapping[element] === null; | 269 return redirectionMapping[element] === null |
| 270 && !closureData.usedVariablesInTry.contains(element); |
271 } | 271 } |
272 | 272 |
273 bool isStoredInClosureField(Element element) { | 273 bool isStoredInClosureField(Element element) { |
274 assert(element !== null); | 274 assert(element !== null); |
275 if (isAccessedDirectly(element)) return false; | 275 if (isAccessedDirectly(element)) return false; |
276 Element redirectElement = redirectionMapping[element]; | 276 Element redirectElement = redirectionMapping[element]; |
| 277 if (redirectElement == null) return false; |
277 if (redirectElement.enclosingElement.kind == ElementKind.CLASS) { | 278 if (redirectElement.enclosingElement.kind == ElementKind.CLASS) { |
278 assert(redirectElement is ClosureFieldElement); | 279 assert(redirectElement is ClosureFieldElement); |
279 return true; | 280 return true; |
280 } | 281 } |
281 return false; | 282 return false; |
282 } | 283 } |
283 | 284 |
284 bool isBoxed(Element element) { | 285 bool isBoxed(Element element) { |
285 if (isAccessedDirectly(element)) return false; | 286 if (isAccessedDirectly(element)) return false; |
286 if (isStoredInClosureField(element)) return false; | 287 if (isStoredInClosureField(element)) return false; |
287 // TODO(floitsch): add some asserts that we really have a boxed element. | 288 return redirectionMapping[element] !== null; |
288 return true; | 289 } |
| 290 |
| 291 bool isUsedInTry(Element element) { |
| 292 return closureData.usedVariablesInTry.contains(element); |
289 } | 293 } |
290 | 294 |
291 /** | 295 /** |
292 * Returns an [HInstruction] for the given element. If the element is | 296 * Returns an [HInstruction] for the given element. If the element is |
293 * boxed or stored in a closure then the method generates code to retrieve | 297 * boxed or stored in a closure then the method generates code to retrieve |
294 * the value. | 298 * the value. |
295 */ | 299 */ |
296 HInstruction readLocal(Element element) { | 300 HInstruction readLocal(Element element) { |
297 if (isAccessedDirectly(element)) { | 301 if (isAccessedDirectly(element)) { |
298 if (directLocals[element] == null) { | 302 if (directLocals[element] == null) { |
299 builder.compiler.internalError( | 303 builder.compiler.internalError( |
300 "Could not find value", node: element.parseNode(builder.compiler)); | 304 "Could not find value", node: element.parseNode(builder.compiler)); |
301 } | 305 } |
302 return directLocals[element]; | 306 return directLocals[element]; |
303 } else if (isStoredInClosureField(element)) { | 307 } else if (isStoredInClosureField(element)) { |
304 Element redirect = redirectionMapping[element]; | 308 Element redirect = redirectionMapping[element]; |
305 // We must not use the [LocalsHandler.thisDefinition] since that could | 309 // We must not use the [LocalsHandler.thisDefinition] since that could |
306 // point to a captured this which would be stored in a closure-field | 310 // point to a captured this which would be stored in a closure-field |
307 // itself. | 311 // itself. |
308 HInstruction receiver = new HThis(); | 312 HInstruction receiver = new HThis(); |
309 builder.add(receiver); | 313 builder.add(receiver); |
310 HInstruction fieldGet = new HFieldGet(redirect, receiver); | 314 HInstruction fieldGet = new HFieldGet(redirect, receiver); |
311 builder.add(fieldGet); | 315 builder.add(fieldGet); |
312 return fieldGet; | 316 return fieldGet; |
313 } else { | 317 } else if (isBoxed(element)) { |
314 assert(isBoxed(element)); | |
315 Element redirect = redirectionMapping[element]; | 318 Element redirect = redirectionMapping[element]; |
316 // In the function that declares the captured variable the box is | 319 // In the function that declares the captured variable the box is |
317 // accessed as direct local. Inside the nested closure the box is | 320 // accessed as direct local. Inside the nested closure the box is |
318 // accessed through a closure-field. | 321 // accessed through a closure-field. |
319 // Calling [readLocal] makes sure we generate the correct code to get | 322 // Calling [readLocal] makes sure we generate the correct code to get |
320 // the box. | 323 // the box. |
321 assert(redirect.enclosingElement.kind == ElementKind.VARIABLE); | 324 assert(redirect.enclosingElement.kind == ElementKind.VARIABLE); |
322 HInstruction box = readLocal(redirect.enclosingElement); | 325 HInstruction box = readLocal(redirect.enclosingElement); |
323 HInstruction lookup = new HFieldGet(redirect, box); | 326 HInstruction lookup = new HFieldGet(redirect, box); |
324 builder.add(lookup); | 327 builder.add(lookup); |
325 return lookup; | 328 return lookup; |
| 329 } else { |
| 330 assert(isUsedInTry(element)); |
| 331 HInstruction variable = new HFieldGet.fromActivation(element); |
| 332 builder.add(variable); |
| 333 return variable; |
326 } | 334 } |
327 } | 335 } |
328 | 336 |
329 /** | 337 /** |
330 * Sets the [element] to [value]. If the element is boxed or stored in a | 338 * Sets the [element] to [value]. If the element is boxed or stored in a |
331 * closure then the method generates code to set the value. | 339 * closure then the method generates code to set the value. |
332 */ | 340 */ |
333 void updateLocal(Element element, HInstruction value) { | 341 void updateLocal(Element element, HInstruction value) { |
334 // TODO(floitsch): replace the following if with an assert. | 342 // TODO(floitsch): replace the following if with an assert. |
335 if (element is !VariableElement) { | 343 if (element is !VariableElement) { |
336 builder.compiler.internalError("expected a variable", | 344 builder.compiler.internalError("expected a variable", |
337 node: element.parseNode(builder.compiler)); | 345 node: element.parseNode(builder.compiler)); |
338 } | 346 } |
339 | 347 |
340 if (isAccessedDirectly(element)) { | 348 if (isAccessedDirectly(element)) { |
341 directLocals[element] = value; | 349 directLocals[element] = value; |
342 } else if (isStoredInClosureField(element)) { | 350 } else if (isStoredInClosureField(element)) { |
343 Element redirect = redirectionMapping[element]; | 351 Element redirect = redirectionMapping[element]; |
344 // We must not use the [LocalsHandler.thisDefinition] since that could | 352 // We must not use the [LocalsHandler.thisDefinition] since that could |
345 // point to a captured this which would be stored in a closure-field | 353 // point to a captured this which would be stored in a closure-field |
346 // itself. | 354 // itself. |
347 HInstruction receiver = new HThis(); | 355 HInstruction receiver = new HThis(); |
348 builder.add(receiver); | 356 builder.add(receiver); |
349 builder.add(new HFieldSet(redirect, receiver, value)); | 357 builder.add(new HFieldSet(redirect, receiver, value)); |
350 } else { | 358 } else if (isBoxed(element)) { |
351 assert(isBoxed(element)); | |
352 Element redirect = redirectionMapping[element]; | 359 Element redirect = redirectionMapping[element]; |
353 // The box itself could be captured, or be local. A local variable that | 360 // The box itself could be captured, or be local. A local variable that |
354 // is captured will be boxed, but the box itself will be a local. | 361 // is captured will be boxed, but the box itself will be a local. |
355 // Inside the closure the box is stored in a closure-field and cannot | 362 // Inside the closure the box is stored in a closure-field and cannot |
356 // be accessed directly. | 363 // be accessed directly. |
357 assert(redirect.enclosingElement.kind == ElementKind.VARIABLE); | 364 assert(redirect.enclosingElement.kind == ElementKind.VARIABLE); |
358 HInstruction box = readLocal(redirect.enclosingElement); | 365 HInstruction box = readLocal(redirect.enclosingElement); |
359 builder.add(new HFieldSet(redirect, box, value)); | 366 builder.add(new HFieldSet(redirect, box, value)); |
| 367 } else { |
| 368 assert(isUsedInTry(element)); |
| 369 builder.add(new HFieldSet.fromActivation(element,value)); |
360 } | 370 } |
361 } | 371 } |
362 | 372 |
363 void startLoop(Node node, HBasicBlock loopEntry) { | 373 void startLoop(Node node, HBasicBlock loopEntry) { |
364 ClosureScope scopeData = closureData.capturingScopes[node]; | 374 ClosureScope scopeData = closureData.capturingScopes[node]; |
365 if (scopeData !== null) { | 375 if (scopeData !== null) { |
366 builder.compiler.unimplemented("Captured variable in a loop", node: node); | 376 builder.compiler.unimplemented("Captured variable in a loop", node: node); |
367 } | 377 } |
368 | 378 |
369 // Create a copy because we modify the map while iterating over | 379 // Create a copy because we modify the map while iterating over |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
406 } | 416 } |
407 }); | 417 }); |
408 directLocals = joinedLocals; | 418 directLocals = joinedLocals; |
409 } | 419 } |
410 } | 420 } |
411 | 421 |
412 class SsaBuilder implements Visitor { | 422 class SsaBuilder implements Visitor { |
413 final Compiler compiler; | 423 final Compiler compiler; |
414 final TreeElements elements; | 424 final TreeElements elements; |
415 final Interceptors interceptors; | 425 final Interceptors interceptors; |
| 426 final WorkItem work; |
416 bool methodInterceptionEnabled; | 427 bool methodInterceptionEnabled; |
417 HGraph graph; | 428 HGraph graph; |
418 LocalsHandler localsHandler; | 429 LocalsHandler localsHandler; |
419 | 430 |
420 // We build the Ssa graph by simulating a stack machine. | 431 // We build the Ssa graph by simulating a stack machine. |
421 List<HInstruction> stack; | 432 List<HInstruction> stack; |
422 | 433 |
423 // The current block to add instructions to. Might be null, if we are | 434 // The current block to add instructions to. Might be null, if we are |
424 // visiting dead code. | 435 // visiting dead code. |
425 HBasicBlock current; | 436 HBasicBlock current; |
426 | 437 |
427 SsaBuilder(Compiler compiler, this.elements) | 438 SsaBuilder(Compiler compiler, WorkItem work) |
428 : this.compiler = compiler, | 439 : this.compiler = compiler, |
| 440 this.work = work, |
429 interceptors = compiler.builder.interceptors, | 441 interceptors = compiler.builder.interceptors, |
430 methodInterceptionEnabled = true, | 442 methodInterceptionEnabled = true, |
| 443 elements = work.resolutionTree, |
431 graph = new HGraph(), | 444 graph = new HGraph(), |
432 stack = new List<HInstruction>() { | 445 stack = new List<HInstruction>() { |
433 localsHandler = new LocalsHandler(this); | 446 localsHandler = new LocalsHandler(this); |
434 } | 447 } |
435 | 448 |
436 void disableMethodInterception() { | 449 void disableMethodInterception() { |
437 assert(methodInterceptionEnabled); | 450 assert(methodInterceptionEnabled); |
438 methodInterceptionEnabled = false; | 451 methodInterceptionEnabled = false; |
439 } | 452 } |
440 | 453 |
(...skipping 1255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1696 | 1709 |
1697 visitNamedArgument(NamedArgument node) { | 1710 visitNamedArgument(NamedArgument node) { |
1698 visit(node.expression); | 1711 visit(node.expression); |
1699 } | 1712 } |
1700 | 1713 |
1701 visitSwitchStatement(SwitchStatement node) { | 1714 visitSwitchStatement(SwitchStatement node) { |
1702 compiler.unimplemented('SsaBuilder.visitSwitchStatement', node: node); | 1715 compiler.unimplemented('SsaBuilder.visitSwitchStatement', node: node); |
1703 } | 1716 } |
1704 | 1717 |
1705 visitTryStatement(TryStatement node) { | 1718 visitTryStatement(TryStatement node) { |
1706 compiler.unimplemented('SsaBuilder.visitTryStatement', node: node); | 1719 work.allowSpeculativeOptimization = false; |
| 1720 assert(!work.isBailoutVersion()); |
| 1721 HBasicBlock enterBlock = graph.addNewBlock(); |
| 1722 close(new HGoto()).addSuccessor(enterBlock); |
| 1723 open(enterBlock); |
| 1724 close(new HTry()); |
| 1725 |
| 1726 HBasicBlock tryBody = graph.addNewBlock(); |
| 1727 enterBlock.addSuccessor(tryBody); |
| 1728 open(tryBody); |
| 1729 visit(node.tryBlock); |
| 1730 HBasicBlock endTryBody; |
| 1731 if (!isAborted()) endTryBody = close(new HGoto()); |
| 1732 |
| 1733 List<HBasicBlock> catchBlocks = <HBasicBlock>[]; |
| 1734 int catchBlocksCount = 0; |
| 1735 for (CatchBlock catchBlock in node.catchBlocks.nodes) { |
| 1736 if (++catchBlocksCount != 1) { |
| 1737 compiler.unimplemented('SsaBuilder multiple catch blocks', node: node); |
| 1738 } |
| 1739 HBasicBlock block = graph.addNewBlock(); |
| 1740 enterBlock.addSuccessor(block); |
| 1741 open(block); |
| 1742 visit(catchBlock); |
| 1743 if (!isAborted()) { |
| 1744 close(new HGoto()); |
| 1745 catchBlocks.add(block); |
| 1746 } |
| 1747 } |
| 1748 |
| 1749 HBasicBlock exitBlock = graph.addNewBlock(); |
| 1750 |
| 1751 if (endTryBody != null) { |
| 1752 endTryBody.addSuccessor(exitBlock); |
| 1753 } |
| 1754 |
| 1755 for (HBasicBlock block in catchBlocks) { |
| 1756 block.addSuccessor(exitBlock); |
| 1757 } |
| 1758 |
| 1759 if (node.finallyBlock != null) { |
| 1760 compiler.unimplemented('SsaBuilder finally block', node: node); |
| 1761 } |
| 1762 |
| 1763 open(exitBlock); |
1707 } | 1764 } |
1708 | 1765 |
1709 visitScriptTag(ScriptTag node) { | 1766 visitScriptTag(ScriptTag node) { |
1710 compiler.unimplemented('SsaBuilder.visitScriptTag', node: node); | 1767 compiler.unimplemented('SsaBuilder.visitScriptTag', node: node); |
1711 } | 1768 } |
1712 | 1769 |
1713 visitCatchBlock(CatchBlock node) { | 1770 visitCatchBlock(CatchBlock node) { |
1714 compiler.unimplemented('SsaBuilder.visitCatchBlock', node: node); | 1771 NodeList formals = node.formals; |
| 1772 VariableDefinitions exception = formals.nodes.head; |
| 1773 if (exception.type != null) { |
| 1774 compiler.unimplemented('SsaBuilder catch with type', node: node); |
| 1775 } |
| 1776 visit(node.block); |
1715 } | 1777 } |
1716 | 1778 |
1717 visitTypedef(Typedef node) { | 1779 visitTypedef(Typedef node) { |
1718 compiler.unimplemented('SsaBuilder.visitTypedef', node: node); | 1780 compiler.unimplemented('SsaBuilder.visitTypedef', node: node); |
1719 } | 1781 } |
1720 } | 1782 } |
OLD | NEW |