| 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 |