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 249 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
260 assert(isAccessedDirectly(element)); | 260 assert(isAccessedDirectly(element)); |
261 return directLocals[element] !== null; | 261 return directLocals[element] !== null; |
262 } | 262 } |
263 | 263 |
264 /** | 264 /** |
265 * Returns true if the local can be accessed directly. Boxed variables or | 265 * Returns true if the local can be accessed directly. Boxed variables or |
266 * captured variables that are stored in the closure-field return [false]. | 266 * captured variables that are stored in the closure-field return [false]. |
267 */ | 267 */ |
268 bool isAccessedDirectly(Element element) { | 268 bool isAccessedDirectly(Element element) { |
269 assert(element !== null); | 269 assert(element !== null); |
270 return redirectionMapping[element] === null; | 270 return redirectionMapping[element] === null |
271 && !closureData.usedVariablesInTry.contains(element); | |
271 } | 272 } |
272 | 273 |
273 bool isStoredInClosureField(Element element) { | 274 bool isStoredInClosureField(Element element) { |
274 assert(element !== null); | 275 assert(element !== null); |
275 if (isAccessedDirectly(element)) return false; | 276 if (isAccessedDirectly(element)) return false; |
276 Element redirectElement = redirectionMapping[element]; | 277 Element redirectElement = redirectionMapping[element]; |
278 if (redirectElement == null) return false; | |
277 if (redirectElement.enclosingElement.kind == ElementKind.CLASS) { | 279 if (redirectElement.enclosingElement.kind == ElementKind.CLASS) { |
278 assert(redirectElement is ClosureFieldElement); | 280 assert(redirectElement is ClosureFieldElement); |
279 return true; | 281 return true; |
280 } | 282 } |
281 return false; | 283 return false; |
282 } | 284 } |
283 | 285 |
284 bool isBoxed(Element element) { | 286 bool isBoxed(Element element) { |
285 if (isAccessedDirectly(element)) return false; | 287 if (isAccessedDirectly(element)) return false; |
286 if (isStoredInClosureField(element)) return false; | 288 if (isStoredInClosureField(element)) return false; |
287 // TODO(floitsch): add some asserts that we really have a boxed element. | 289 return redirectionMapping[element] !== null; |
288 return true; | 290 } |
291 | |
292 bool isUsedInTry(Element element) { | |
293 return closureData.usedVariablesInTry.contains(element); | |
289 } | 294 } |
290 | 295 |
291 /** | 296 /** |
292 * Returns an [HInstruction] for the given element. If the element is | 297 * 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 | 298 * boxed or stored in a closure then the method generates code to retrieve |
294 * the value. | 299 * the value. |
295 */ | 300 */ |
296 HInstruction readLocal(Element element) { | 301 HInstruction readLocal(Element element) { |
297 if (isAccessedDirectly(element)) { | 302 if (isAccessedDirectly(element)) { |
298 if (directLocals[element] == null) { | 303 if (directLocals[element] == null) { |
299 builder.compiler.internalError( | 304 builder.compiler.internalError( |
300 "Could not find value", node: element.parseNode(builder.compiler)); | 305 "Could not find value", node: element.parseNode(builder.compiler)); |
301 } | 306 } |
302 return directLocals[element]; | 307 return directLocals[element]; |
303 } else if (isStoredInClosureField(element)) { | 308 } else if (isStoredInClosureField(element)) { |
304 Element redirect = redirectionMapping[element]; | 309 Element redirect = redirectionMapping[element]; |
305 // We must not use the [LocalsHandler.thisDefinition] since that could | 310 // We must not use the [LocalsHandler.thisDefinition] since that could |
306 // point to a captured this which would be stored in a closure-field | 311 // point to a captured this which would be stored in a closure-field |
307 // itself. | 312 // itself. |
308 HInstruction receiver = new HThis(); | 313 HInstruction receiver = new HThis(); |
309 builder.add(receiver); | 314 builder.add(receiver); |
310 HInstruction fieldGet = new HFieldGet(redirect, receiver); | 315 HInstruction fieldGet = new HFieldGet(redirect, receiver); |
311 builder.add(fieldGet); | 316 builder.add(fieldGet); |
312 return fieldGet; | 317 return fieldGet; |
313 } else { | 318 } else if (isBoxed(element)) { |
314 assert(isBoxed(element)); | |
315 Element redirect = redirectionMapping[element]; | 319 Element redirect = redirectionMapping[element]; |
316 // In the function that declares the captured variable the box is | 320 // In the function that declares the captured variable the box is |
317 // accessed as direct local. Inside the nested closure the box is | 321 // accessed as direct local. Inside the nested closure the box is |
318 // accessed through a closure-field. | 322 // accessed through a closure-field. |
319 // Calling [readLocal] makes sure we generate the correct code to get | 323 // Calling [readLocal] makes sure we generate the correct code to get |
320 // the box. | 324 // the box. |
321 assert(redirect.enclosingElement.kind == ElementKind.VARIABLE); | 325 assert(redirect.enclosingElement.kind == ElementKind.VARIABLE); |
322 HInstruction box = readLocal(redirect.enclosingElement); | 326 HInstruction box = readLocal(redirect.enclosingElement); |
323 HInstruction lookup = new HFieldGet(redirect, box); | 327 HInstruction lookup = new HFieldGet(redirect, box); |
324 builder.add(lookup); | 328 builder.add(lookup); |
325 return lookup; | 329 return lookup; |
330 } else { | |
331 assert(isUsedInTry(element)); | |
332 HInstruction variable = new HFieldGet.fromActivation(element); | |
333 builder.add(variable); | |
334 return variable; | |
326 } | 335 } |
327 } | 336 } |
328 | 337 |
329 /** | 338 /** |
330 * Sets the [element] to [value]. If the element is boxed or stored in a | 339 * 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. | 340 * closure then the method generates code to set the value. |
332 */ | 341 */ |
333 void updateLocal(Element element, HInstruction value) { | 342 void updateLocal(Element element, HInstruction value) { |
334 // TODO(floitsch): replace the following if with an assert. | 343 // TODO(floitsch): replace the following if with an assert. |
335 if (element is !VariableElement) { | 344 if (element is !VariableElement) { |
336 builder.compiler.internalError("expected a variable", | 345 builder.compiler.internalError("expected a variable", |
337 node: element.parseNode(builder.compiler)); | 346 node: element.parseNode(builder.compiler)); |
338 } | 347 } |
339 | 348 |
340 if (isAccessedDirectly(element)) { | 349 if (isAccessedDirectly(element)) { |
341 directLocals[element] = value; | 350 directLocals[element] = value; |
342 } else if (isStoredInClosureField(element)) { | 351 } else if (isStoredInClosureField(element)) { |
343 Element redirect = redirectionMapping[element]; | 352 Element redirect = redirectionMapping[element]; |
344 // We must not use the [LocalsHandler.thisDefinition] since that could | 353 // We must not use the [LocalsHandler.thisDefinition] since that could |
345 // point to a captured this which would be stored in a closure-field | 354 // point to a captured this which would be stored in a closure-field |
346 // itself. | 355 // itself. |
347 HInstruction receiver = new HThis(); | 356 HInstruction receiver = new HThis(); |
348 builder.add(receiver); | 357 builder.add(receiver); |
349 builder.add(new HFieldSet(redirect, receiver, value)); | 358 builder.add(new HFieldSet(redirect, receiver, value)); |
350 } else { | 359 } else if (isBoxed(element)) { |
351 assert(isBoxed(element)); | |
352 Element redirect = redirectionMapping[element]; | 360 Element redirect = redirectionMapping[element]; |
353 // The box itself could be captured, or be local. A local variable that | 361 // 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. | 362 // 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 | 363 // Inside the closure the box is stored in a closure-field and cannot |
356 // be accessed directly. | 364 // be accessed directly. |
357 assert(redirect.enclosingElement.kind == ElementKind.VARIABLE); | 365 assert(redirect.enclosingElement.kind == ElementKind.VARIABLE); |
358 HInstruction box = readLocal(redirect.enclosingElement); | 366 HInstruction box = readLocal(redirect.enclosingElement); |
359 builder.add(new HFieldSet(redirect, box, value)); | 367 builder.add(new HFieldSet(redirect, box, value)); |
368 } else { | |
369 assert(isUsedInTry(element)); | |
370 builder.add(new HFieldSet.fromActivation(element,value)); | |
360 } | 371 } |
361 } | 372 } |
362 | 373 |
363 void startLoop(Node node, HBasicBlock loopEntry) { | 374 void startLoop(Node node, HBasicBlock loopEntry) { |
364 ClosureScope scopeData = closureData.capturingScopes[node]; | 375 ClosureScope scopeData = closureData.capturingScopes[node]; |
365 if (scopeData !== null) { | 376 if (scopeData !== null) { |
366 builder.compiler.unimplemented("Captured variable in a loop", node: node); | 377 builder.compiler.unimplemented("Captured variable in a loop", node: node); |
367 } | 378 } |
368 | 379 |
369 // Create a copy because we modify the map while iterating over | 380 // Create a copy because we modify the map while iterating over |
(...skipping 1326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1696 | 1707 |
1697 visitNamedArgument(NamedArgument node) { | 1708 visitNamedArgument(NamedArgument node) { |
1698 visit(node.expression); | 1709 visit(node.expression); |
1699 } | 1710 } |
1700 | 1711 |
1701 visitSwitchStatement(SwitchStatement node) { | 1712 visitSwitchStatement(SwitchStatement node) { |
1702 compiler.unimplemented('SsaBuilder.visitSwitchStatement', node: node); | 1713 compiler.unimplemented('SsaBuilder.visitSwitchStatement', node: node); |
1703 } | 1714 } |
1704 | 1715 |
1705 visitTryStatement(TryStatement node) { | 1716 visitTryStatement(TryStatement node) { |
1706 compiler.unimplemented('SsaBuilder.visitTryStatement', node: node); | 1717 HBasicBlock enterBlock = graph.addNewBlock(); |
1718 close(new HGoto()).addSuccessor(enterBlock); | |
1719 open(enterBlock); | |
1720 close(new HTry()); | |
1721 | |
1722 HBasicBlock tryBody = graph.addNewBlock(); | |
1723 enterBlock.addSuccessor(tryBody); | |
1724 open(tryBody); | |
1725 visit(node.tryBlock); | |
1726 HBasicBlock endTryBlock; | |
1727 if (!isAborted()) endTryBlock = close(new HGoto()); | |
floitsch
2012/02/07 17:40:00
We usually just update the variable:
tryBlock = cl
ngeoffray
2012/02/08 09:52:23
As discussed, renamed the variable to endTryBody.
| |
1728 | |
1729 List<HBasicBlock> catchBlocks = <HBasicBlock>[]; | |
1730 int catchBlocksCount = 0; | |
1731 for (CatchBlock catchBlock in node.catchBlocks.nodes) { | |
1732 if (++catchBlocksCount != 1) { | |
1733 compiler.unimplemented('SsaBuilder multiple catch blocks', node: node); | |
1734 } | |
1735 HBasicBlock block = graph.addNewBlock(); | |
1736 enterBlock.addSuccessor(block); | |
1737 open(block); | |
1738 visit(catchBlock); | |
1739 if (!isAborted()) { | |
1740 close(new HGoto()); | |
1741 catchBlocks.add(block); | |
1742 } | |
1743 } | |
1744 | |
1745 HBasicBlock exitBlock = graph.addNewBlock(); | |
1746 | |
1747 if (endTryBlock != null) { | |
1748 endTryBlock.addSuccessor(exitBlock); | |
1749 } | |
1750 | |
1751 for (HBasicBlock block in catchBlocks) { | |
1752 block.addSuccessor(exitBlock); | |
1753 } | |
1754 | |
1755 if (node.finallyBlock != null) { | |
1756 compiler.unimplemented('SsaBuilder finally block', node: node); | |
1757 } | |
1758 | |
1759 HBasicBlock joinBlock = graph.addNewBlock(); | |
floitsch
2012/02/07 17:40:00
now that I think about it, I'm not sure we need th
ngeoffray
2012/02/08 09:52:23
Done.
| |
1760 open(exitBlock); | |
1761 close(new HGoto()).addSuccessor(joinBlock); | |
1762 | |
1763 open(joinBlock); | |
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 |