Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 import 'package:kernel/ast.dart' as ir; | 5 import 'package:kernel/ast.dart' as ir; |
| 6 import 'package:kernel/text/ast_to_text.dart' show debugNodeToString; | 6 import 'package:kernel/text/ast_to_text.dart' show debugNodeToString; |
| 7 | 7 |
| 8 import '../closure.dart'; | 8 import '../closure.dart'; |
| 9 import '../common.dart'; | 9 import '../common.dart'; |
| 10 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; | 10 import '../common/codegen.dart' show CodegenRegistry, CodegenWorkItem; |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 95 ir.FunctionNode _targetFunction; | 95 ir.FunctionNode _targetFunction; |
| 96 | 96 |
| 97 /// A stack of [DartType]s that have been seen during inlining of factory | 97 /// A stack of [DartType]s that have been seen during inlining of factory |
| 98 /// constructors. These types are preserved in [HInvokeStatic]s and | 98 /// constructors. These types are preserved in [HInvokeStatic]s and |
| 99 /// [HCreate]s inside the inline code and registered during code generation | 99 /// [HCreate]s inside the inline code and registered during code generation |
| 100 /// for these nodes. | 100 /// for these nodes. |
| 101 // TODO(karlklose): consider removing this and keeping the (substituted) types | 101 // TODO(karlklose): consider removing this and keeping the (substituted) types |
| 102 // of the type variables in an environment (like the [LocalsHandler]). | 102 // of the type variables in an environment (like the [LocalsHandler]). |
| 103 final List<DartType> currentImplicitInstantiations = <DartType>[]; | 103 final List<DartType> currentImplicitInstantiations = <DartType>[]; |
| 104 | 104 |
| 105 HInstruction rethrowableException; | |
| 106 | |
| 105 @override | 107 @override |
| 106 JavaScriptBackend get backend => compiler.backend; | 108 JavaScriptBackend get backend => compiler.backend; |
| 107 | 109 |
| 108 @override | 110 @override |
| 109 TreeElements get elements => resolvedAst.elements; | 111 TreeElements get elements => resolvedAst.elements; |
| 110 | 112 |
| 111 SourceInformationBuilder sourceInformationBuilder; | 113 SourceInformationBuilder sourceInformationBuilder; |
| 112 KernelAstAdapter astAdapter; | 114 KernelAstAdapter astAdapter; |
| 113 LoopHandler<ir.Node> loopHandler; | 115 LoopHandler<ir.Node> loopHandler; |
| 114 TypeBuilder typeBuilder; | 116 TypeBuilder typeBuilder; |
| (...skipping 1509 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1624 stack.add(graph.addConstantNull(compiler)); | 1626 stack.add(graph.addConstantNull(compiler)); |
| 1625 } | 1627 } |
| 1626 | 1628 |
| 1627 void handleForeignJs(ir.StaticInvocation invocation) { | 1629 void handleForeignJs(ir.StaticInvocation invocation) { |
| 1628 if (_unexpectedForeignArguments(invocation, 2)) { | 1630 if (_unexpectedForeignArguments(invocation, 2)) { |
| 1629 stack.add(graph.addConstantNull(compiler)); // Result expected on stack. | 1631 stack.add(graph.addConstantNull(compiler)); // Result expected on stack. |
| 1630 return; | 1632 return; |
| 1631 } | 1633 } |
| 1632 | 1634 |
| 1633 native.NativeBehavior nativeBehavior = | 1635 native.NativeBehavior nativeBehavior = |
| 1634 astAdapter.getNativeBehavior(invocation); | 1636 astAdapter.getNativeBehaviorForJsCall(invocation); |
| 1635 assert(invariant(astAdapter.getNode(invocation), nativeBehavior != null, | 1637 assert(invariant(astAdapter.getNode(invocation), nativeBehavior != null, |
| 1636 message: "No NativeBehavior for $invocation")); | 1638 message: "No NativeBehavior for $invocation")); |
| 1637 | 1639 |
| 1638 List<HInstruction> inputs = <HInstruction>[]; | 1640 List<HInstruction> inputs = <HInstruction>[]; |
| 1639 for (ir.Expression argument in invocation.arguments.positional.skip(2)) { | 1641 for (ir.Expression argument in invocation.arguments.positional.skip(2)) { |
| 1640 argument.accept(this); | 1642 argument.accept(this); |
| 1641 inputs.add(pop()); | 1643 inputs.add(pop()); |
| 1642 } | 1644 } |
| 1643 | 1645 |
| 1644 if (nativeBehavior.codeTemplate.positionalArgumentCount != inputs.length) { | 1646 if (nativeBehavior.codeTemplate.positionalArgumentCount != inputs.length) { |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1847 _visitArgumentsForStaticTarget(target.function, invocation.arguments); | 1849 _visitArgumentsForStaticTarget(target.function, invocation.arguments); |
| 1848 TypeMask typeMask = new TypeMask.nonNullExact( | 1850 TypeMask typeMask = new TypeMask.nonNullExact( |
| 1849 astAdapter.getElement(target.enclosingClass), closedWorld); | 1851 astAdapter.getElement(target.enclosingClass), closedWorld); |
| 1850 _pushStaticInvocation(target, arguments, typeMask); | 1852 _pushStaticInvocation(target, arguments, typeMask); |
| 1851 } | 1853 } |
| 1852 | 1854 |
| 1853 @override | 1855 @override |
| 1854 void visitIsExpression(ir.IsExpression isExpression) { | 1856 void visitIsExpression(ir.IsExpression isExpression) { |
| 1855 isExpression.operand.accept(this); | 1857 isExpression.operand.accept(this); |
| 1856 HInstruction expression = pop(); | 1858 HInstruction expression = pop(); |
| 1859 push(buildIsNode(isExpression, isExpression.type, expression)); | |
| 1860 } | |
| 1857 | 1861 |
| 1862 @override | |
| 1863 void visitThrow(ir.Throw throwNode) { | |
| 1864 _visitThrowExpression(throwNode.expression); | |
| 1865 if (isReachable) { | |
| 1866 push(new HThrowExpression(pop(), null)); | |
| 1867 isReachable = false; | |
| 1868 } | |
| 1869 } | |
| 1870 | |
| 1871 void _visitThrowExpression(ir.Expression expression) { | |
| 1872 bool old = _inExpressionOfThrow; | |
| 1873 try { | |
| 1874 _inExpressionOfThrow = true; | |
| 1875 expression.accept(this); | |
| 1876 } finally { | |
| 1877 _inExpressionOfThrow = old; | |
| 1878 } | |
| 1879 } | |
| 1880 | |
| 1881 @override | |
| 1882 void visitThisExpression(ir.ThisExpression thisExpression) { | |
| 1883 stack.add(localsHandler.readThis()); | |
| 1884 } | |
| 1885 | |
| 1886 @override | |
| 1887 void visitNot(ir.Not not) { | |
| 1888 not.operand.accept(this); | |
| 1889 push(new HNot(popBoolified(), commonMasks.boolType)); | |
| 1890 } | |
| 1891 | |
| 1892 @override | |
| 1893 void visitStringConcatenation(ir.StringConcatenation stringConcat) { | |
| 1894 KernelStringBuilder stringBuilder = new KernelStringBuilder(this); | |
| 1895 stringConcat.accept(stringBuilder); | |
| 1896 stack.add(stringBuilder.result); | |
| 1897 } | |
| 1898 | |
| 1899 bool _isInterfaceWithNoRawTypes(ir.DartType type) { | |
| 1900 return type is ir.InterfaceType && | |
| 1901 (type as ir.InterfaceType) | |
| 1902 .typeArguments | |
| 1903 .any((ir.DartType typeArgType) => typeArgType is! ir.DynamicType); | |
| 1904 } | |
| 1905 | |
| 1906 HInstruction buildIsNode( | |
|
Siggi Cherem (dart-lang)
2016/12/15 00:59:45
nit: consider moving this up next to visitIsExpres
Emily Fortuna
2016/12/15 01:25:43
Done.
| |
| 1907 ir.Node node, ir.DartType dart_type, HInstruction expression) { | |
| 1858 // TODO(sra): Convert the type testing logic here to use ir.DartType. | 1908 // TODO(sra): Convert the type testing logic here to use ir.DartType. |
| 1859 DartType type = astAdapter.getDartType(isExpression.type); | 1909 DartType type = astAdapter.getDartType(dart_type); |
| 1860 | 1910 |
| 1861 type = localsHandler.substInContext(type).unaliased; | 1911 type = localsHandler.substInContext(type).unaliased; |
| 1862 | 1912 |
| 1863 if (type is MethodTypeVariableType) { | 1913 if (type is MethodTypeVariableType) { |
| 1864 push(graph.addConstantBool(true, compiler)); | 1914 return graph.addConstantBool(true, compiler); |
| 1865 return; | |
| 1866 } | 1915 } |
| 1867 | 1916 |
| 1868 if (type is MalformedType) { | 1917 if (type is MalformedType) { |
| 1869 ErroneousElement element = type.element; | 1918 ErroneousElement element = type.element; |
| 1870 generateTypeError(isExpression, element.message); | 1919 generateTypeError(node, element.message); |
| 1871 push(new HIs.compound(type, expression, pop(), commonMasks.boolType)); | 1920 return new HIs.compound(type, expression, pop(), commonMasks.boolType); |
| 1872 return; | |
| 1873 } | 1921 } |
| 1874 | 1922 |
| 1875 if (type.isFunctionType) { | 1923 if (type.isFunctionType) { |
| 1876 List arguments = <HInstruction>[buildFunctionType(type), expression]; | 1924 List arguments = <HInstruction>[buildFunctionType(type), expression]; |
| 1877 _pushDynamicInvocation(isExpression, commonMasks.boolType, arguments, | 1925 _pushDynamicInvocation(node, commonMasks.boolType, arguments, |
| 1878 selector: new Selector.call( | 1926 selector: new Selector.call( |
| 1879 new PrivateName('_isTest', astAdapter.jsHelperLibrary), | 1927 new PrivateName('_isTest', astAdapter.jsHelperLibrary), |
| 1880 CallStructure.ONE_ARG)); | 1928 CallStructure.ONE_ARG)); |
| 1881 push(new HIs.compound(type, expression, pop(), commonMasks.boolType)); | 1929 return new HIs.compound(type, expression, pop(), commonMasks.boolType); |
| 1882 return; | |
| 1883 } | 1930 } |
| 1884 | 1931 |
| 1885 if (type.isTypeVariable) { | 1932 if (type.isTypeVariable) { |
| 1886 HInstruction runtimeType = | 1933 HInstruction runtimeType = |
| 1887 typeBuilder.addTypeVariableReference(type, sourceElement); | 1934 typeBuilder.addTypeVariableReference(type, sourceElement); |
| 1888 _pushStaticInvocation(astAdapter.checkSubtypeOfRuntimeType, | 1935 _pushStaticInvocation(astAdapter.checkSubtypeOfRuntimeType, |
| 1889 <HInstruction>[expression, runtimeType], commonMasks.boolType); | 1936 <HInstruction>[expression, runtimeType], commonMasks.boolType); |
| 1890 push(new HIs.variable(type, expression, pop(), commonMasks.boolType)); | 1937 return new HIs.variable(type, expression, pop(), commonMasks.boolType); |
| 1891 return; | |
| 1892 } | 1938 } |
| 1893 | 1939 |
| 1894 // TODO(sra): Type with type parameters. | 1940 // TODO(sra): Type with type parameters. |
| 1895 | 1941 |
| 1896 if (backend.hasDirectCheckFor(type)) { | 1942 if (backend.hasDirectCheckFor(type)) { |
| 1897 push(new HIs.direct(type, expression, commonMasks.boolType)); | 1943 return new HIs.direct(type, expression, commonMasks.boolType); |
| 1898 return; | |
| 1899 } | 1944 } |
| 1900 | 1945 |
| 1901 // The interceptor is not always needed. It is removed by optimization | 1946 // The interceptor is not always needed. It is removed by optimization |
| 1902 // when the receiver type or tested type permit. | 1947 // when the receiver type or tested type permit. |
| 1903 HInterceptor interceptor = _interceptorFor(expression); | 1948 HInterceptor interceptor = _interceptorFor(expression); |
| 1904 push(new HIs.raw(type, expression, interceptor, commonMasks.boolType)); | 1949 return new HIs.raw(type, expression, interceptor, commonMasks.boolType); |
| 1905 } | 1950 } |
| 1906 | 1951 |
| 1907 @override | 1952 @override |
| 1908 void visitThrow(ir.Throw throwNode) { | 1953 void visitTryCatch(ir.TryCatch tryCatch) { |
| 1909 _visitThrowExpression(throwNode.expression); | 1954 TryCatchFinallyBuilder tryBuilder = new TryCatchFinallyBuilder(this); |
| 1910 if (isReachable) { | 1955 tryCatch.body.accept(this); |
| 1911 push(new HThrowExpression(pop(), null)); | 1956 tryBuilder |
| 1912 isReachable = false; | 1957 ..closeTryBody() |
| 1913 } | 1958 ..buildCatch(tryCatch) |
| 1914 } | 1959 ..cleanUp(); |
| 1915 | 1960 } |
| 1916 void _visitThrowExpression(ir.Expression expression) { | 1961 |
| 1917 bool old = _inExpressionOfThrow; | 1962 /// `try { ... } catch { ... } finally { ... }` statements are a little funny |
| 1918 try { | 1963 /// because a try can have one or both of {catch|finally}. The way this is |
| 1919 _inExpressionOfThrow = true; | 1964 /// encoded in kernel AST are two separate classes with no common superclass |
| 1920 expression.accept(this); | 1965 /// aside from Statement. If a statement has both `catch` and `finally` |
| 1921 } finally { | 1966 /// clauses then it is encoded in kernel as so that the TryCatch is the body |
| 1922 _inExpressionOfThrow = old; | 1967 /// statement of the TryFinally. To produce more efficient code rather than |
| 1923 } | 1968 /// nested try statements, the visitors avoid one potential level of |
| 1924 } | 1969 /// recursion. |
| 1925 | |
| 1926 @override | 1970 @override |
| 1927 void visitThisExpression(ir.ThisExpression thisExpression) { | 1971 void visitTryFinally(ir.TryFinally tryFinally) { |
| 1928 stack.add(localsHandler.readThis()); | 1972 TryCatchFinallyBuilder tryBuilder = new TryCatchFinallyBuilder(this); |
| 1929 } | 1973 |
| 1930 | 1974 // We do these shenanigans to produce better looking code that doesn't |
| 1931 @override | 1975 // have nested try statements. |
| 1932 void visitNot(ir.Not not) { | 1976 if (tryFinally.body is ir.TryCatch) { |
| 1933 not.operand.accept(this); | 1977 ir.TryCatch tryCatch = tryFinally.body; |
| 1934 push(new HNot(popBoolified(), commonMasks.boolType)); | 1978 tryCatch.body.accept(this); |
| 1935 } | 1979 tryBuilder |
| 1936 | 1980 ..closeTryBody() |
| 1937 @override | 1981 ..buildCatch(tryCatch); |
| 1938 void visitStringConcatenation(ir.StringConcatenation stringConcat) { | 1982 } else { |
| 1939 KernelStringBuilder stringBuilder = new KernelStringBuilder(this); | 1983 tryFinally.body.accept(this); |
| 1940 stringConcat.accept(stringBuilder); | 1984 tryBuilder.closeTryBody(); |
| 1941 stack.add(stringBuilder.result); | 1985 } |
| 1986 | |
| 1987 tryBuilder | |
| 1988 ..buildFinallyBlock(tryFinally) | |
| 1989 ..cleanUp(); | |
| 1942 } | 1990 } |
| 1943 } | 1991 } |
| 1992 | |
| 1993 /// Class in charge of building try, catch and/or finally blocks. This handles | |
| 1994 /// the instructions that need to be output and the dominator calculation of | |
| 1995 /// this sequence of code. | |
| 1996 class TryCatchFinallyBuilder { | |
| 1997 HBasicBlock enterBlock; | |
| 1998 HBasicBlock startTryBlock; | |
| 1999 HBasicBlock endTryBlock; | |
| 2000 HBasicBlock startCatchBlock; | |
| 2001 HBasicBlock endCatchBlock; | |
| 2002 HBasicBlock startFinallyBlock; | |
| 2003 HBasicBlock endFinallyBlock; | |
| 2004 HBasicBlock exitBlock; | |
| 2005 HTry tryInstruction; | |
| 2006 HLocalValue exception; | |
| 2007 KernelSsaBuilder kernelBuilder; | |
| 2008 | |
| 2009 SubGraph bodyGraph; | |
| 2010 SubGraph catchGraph; | |
| 2011 SubGraph finallyGraph; | |
| 2012 | |
| 2013 // The original set of locals that were defined before this try block. | |
| 2014 // The catch block and the finally block must not reuse the existing locals | |
| 2015 // handler. None of the variables that have been defined in the body-block | |
| 2016 // will be used, but for loops we will add (unnecessary) phis that will | |
| 2017 // reference the body variables. This makes it look as if the variables were | |
| 2018 // used in a non-dominated block. | |
| 2019 LocalsHandler originalSavedLocals; | |
| 2020 | |
| 2021 TryCatchFinallyBuilder(this.kernelBuilder) { | |
| 2022 tryInstruction = new HTry(); | |
| 2023 originalSavedLocals = new LocalsHandler.from(kernelBuilder.localsHandler); | |
| 2024 enterBlock = kernelBuilder.openNewBlock(); | |
| 2025 kernelBuilder.close(tryInstruction); | |
| 2026 | |
| 2027 startTryBlock = kernelBuilder.graph.addNewBlock(); | |
| 2028 kernelBuilder.open(startTryBlock); | |
| 2029 } | |
| 2030 | |
| 2031 void _addExitTrySuccessor(successor) { | |
| 2032 if (successor == null) return; | |
| 2033 // Iterate over all blocks created inside this try/catch, and | |
| 2034 // attach successor information to blocks that end with | |
| 2035 // [HExitTry]. | |
| 2036 for (int i = startTryBlock.id; i < successor.id; i++) { | |
| 2037 HBasicBlock block = kernelBuilder.graph.blocks[i]; | |
| 2038 var last = block.last; | |
| 2039 if (last is HExitTry) { | |
| 2040 block.addSuccessor(successor); | |
| 2041 } | |
| 2042 } | |
| 2043 } | |
| 2044 | |
| 2045 void _addOptionalSuccessor(block1, block2) { | |
| 2046 if (block2 != null) block1.addSuccessor(block2); | |
| 2047 } | |
| 2048 | |
| 2049 /// Helper function to set up basic block successors for try-catch-finally | |
| 2050 /// sequences. | |
| 2051 void _setBlockSuccessors() { | |
| 2052 // Setup all successors. The entry block that contains the [HTry] | |
| 2053 // has 1) the body, 2) the catch, 3) the finally, and 4) the exit | |
| 2054 // blocks as successors. | |
| 2055 enterBlock.addSuccessor(startTryBlock); | |
| 2056 _addOptionalSuccessor(enterBlock, startCatchBlock); | |
| 2057 _addOptionalSuccessor(enterBlock, startFinallyBlock); | |
| 2058 enterBlock.addSuccessor(exitBlock); | |
| 2059 | |
| 2060 // The body has either the catch or the finally block as successor. | |
| 2061 if (endTryBlock != null) { | |
| 2062 assert(startCatchBlock != null || startFinallyBlock != null); | |
| 2063 endTryBlock.addSuccessor( | |
| 2064 startCatchBlock != null ? startCatchBlock : startFinallyBlock); | |
| 2065 endTryBlock.addSuccessor(exitBlock); | |
| 2066 } | |
| 2067 | |
| 2068 // The catch block has either the finally or the exit block as | |
| 2069 // successor. | |
| 2070 endCatchBlock?.addSuccessor( | |
| 2071 startFinallyBlock != null ? startFinallyBlock : exitBlock); | |
| 2072 | |
| 2073 // The finally block has the exit block as successor. | |
| 2074 endFinallyBlock?.addSuccessor(exitBlock); | |
| 2075 | |
| 2076 // If a block inside try/catch aborts (eg with a return statement), | |
| 2077 // we explicitely mark this block a predecessor of the catch | |
| 2078 // block and the finally block. | |
| 2079 _addExitTrySuccessor(startCatchBlock); | |
| 2080 _addExitTrySuccessor(startFinallyBlock); | |
| 2081 } | |
| 2082 | |
| 2083 /// Build the finally{} clause of a try/{catch}/finally statement. Note this | |
| 2084 /// does not examine the body of the try clause, only the finally portion. | |
| 2085 void buildFinallyBlock(ir.TryFinally tryFinally) { | |
| 2086 kernelBuilder.localsHandler = new LocalsHandler.from(originalSavedLocals); | |
| 2087 startFinallyBlock = kernelBuilder.graph.addNewBlock(); | |
| 2088 kernelBuilder.open(startFinallyBlock); | |
| 2089 tryFinally.finalizer.accept(kernelBuilder); | |
| 2090 if (!kernelBuilder.isAborted()) { | |
| 2091 endFinallyBlock = kernelBuilder.close(new HGoto()); | |
| 2092 } | |
| 2093 tryInstruction.finallyBlock = startFinallyBlock; | |
| 2094 finallyGraph = | |
| 2095 new SubGraph(startFinallyBlock, kernelBuilder.lastOpenedBlock); | |
| 2096 } | |
| 2097 | |
| 2098 void closeTryBody() { | |
| 2099 // We use a [HExitTry] instead of a [HGoto] for the try block | |
| 2100 // because it will have multiple successors: the join block, and | |
| 2101 // the catch or finally block. | |
| 2102 if (!kernelBuilder.isAborted()) { | |
| 2103 endTryBlock = kernelBuilder.close(new HExitTry()); | |
| 2104 } | |
| 2105 bodyGraph = new SubGraph(startTryBlock, kernelBuilder.lastOpenedBlock); | |
| 2106 } | |
| 2107 | |
| 2108 void buildCatch(ir.TryCatch tryCatch) { | |
| 2109 kernelBuilder.localsHandler = new LocalsHandler.from(originalSavedLocals); | |
| 2110 startCatchBlock = kernelBuilder.graph.addNewBlock(); | |
| 2111 kernelBuilder.open(startCatchBlock); | |
| 2112 // Note that the name of this local is irrelevant. | |
| 2113 SyntheticLocal local = new SyntheticLocal( | |
| 2114 'exception', kernelBuilder.localsHandler.executableContext); | |
| 2115 exception = new HLocalValue(local, kernelBuilder.commonMasks.nonNullType); | |
| 2116 kernelBuilder.add(exception); | |
| 2117 HInstruction oldRethrowableException = kernelBuilder.rethrowableException; | |
| 2118 kernelBuilder.rethrowableException = exception; | |
| 2119 | |
| 2120 kernelBuilder._pushStaticInvocation( | |
| 2121 kernelBuilder.astAdapter.exceptionUnwrapper, | |
| 2122 [exception], | |
| 2123 kernelBuilder.astAdapter.exceptionUnwrapperType); | |
| 2124 HInvokeStatic unwrappedException = kernelBuilder.pop(); | |
| 2125 tryInstruction.exception = exception; | |
| 2126 int catchesIndex = 0; | |
| 2127 | |
| 2128 void pushCondition(ir.Catch catchBlock) { | |
| 2129 if (catchBlock.guard is! ir.DynamicType) { | |
| 2130 HInstruction condition = kernelBuilder.buildIsNode( | |
| 2131 catchBlock.exception, catchBlock.guard, unwrappedException); | |
| 2132 // TODO(efortuna): Just to be clear, the stackTrace type is never | |
| 2133 // checked? | |
|
Siggi Cherem (dart-lang)
2016/12/15 00:59:45
correct - I don't believe there is a way to specif
Emily Fortuna
2016/12/15 01:25:43
Acknowledged.
| |
| 2134 kernelBuilder.push(condition); | |
| 2135 } else { | |
| 2136 kernelBuilder.stack.add( | |
| 2137 kernelBuilder.graph.addConstantBool(true, kernelBuilder.compiler)); | |
| 2138 } | |
| 2139 } | |
| 2140 | |
| 2141 void visitThen() { | |
| 2142 ir.Catch catchBlock = tryCatch.catches[catchesIndex]; | |
| 2143 catchesIndex++; | |
| 2144 if (catchBlock.exception != null) { | |
| 2145 LocalVariableElement exceptionVariable = | |
| 2146 kernelBuilder.astAdapter.getElement(catchBlock.exception); | |
| 2147 kernelBuilder.localsHandler | |
| 2148 .updateLocal(exceptionVariable, unwrappedException); | |
| 2149 } | |
| 2150 if (catchBlock.stackTrace != null) { | |
| 2151 kernelBuilder._pushStaticInvocation( | |
| 2152 kernelBuilder.astAdapter.traceFromException, | |
| 2153 [exception], | |
| 2154 kernelBuilder.astAdapter.traceFromExceptionType); | |
| 2155 HInstruction traceInstruction = kernelBuilder.pop(); | |
| 2156 LocalVariableElement traceVariable = | |
| 2157 kernelBuilder.astAdapter.getElement(catchBlock.stackTrace); | |
| 2158 kernelBuilder.localsHandler | |
| 2159 .updateLocal(traceVariable, traceInstruction); | |
| 2160 } | |
| 2161 catchBlock.body.accept(kernelBuilder); | |
| 2162 } | |
| 2163 | |
| 2164 void visitElse() { | |
| 2165 if (catchesIndex >= tryCatch.catches.length) { | |
| 2166 kernelBuilder.closeAndGotoExit(new HThrow( | |
| 2167 exception, exception.sourceInformation, | |
| 2168 isRethrow: true)); | |
| 2169 } else { | |
| 2170 // TODO(efortuna): Make SsaBranchBuilder handle kernel elements, and | |
| 2171 // pass tryCatch in here as the "diagnosticNode". | |
| 2172 kernelBuilder.handleIf( | |
| 2173 visitCondition: () { | |
| 2174 pushCondition(tryCatch.catches[catchesIndex]); | |
| 2175 }, | |
| 2176 visitThen: visitThen, | |
| 2177 visitElse: visitElse); | |
| 2178 } | |
| 2179 } | |
| 2180 | |
| 2181 ir.Catch firstBlock = tryCatch.catches[catchesIndex]; | |
| 2182 // TODO(efortuna): Make SsaBranchBuilder handle kernel elements, and then | |
| 2183 // pass tryCatch in here as the "diagnosticNode". | |
| 2184 kernelBuilder.handleIf( | |
| 2185 visitCondition: () { | |
| 2186 pushCondition(firstBlock); | |
| 2187 }, | |
| 2188 visitThen: visitThen, | |
| 2189 visitElse: visitElse); | |
| 2190 if (!kernelBuilder.isAborted()) { | |
| 2191 endCatchBlock = kernelBuilder.close(new HGoto()); | |
| 2192 } | |
| 2193 | |
| 2194 kernelBuilder.rethrowableException = oldRethrowableException; | |
| 2195 tryInstruction.catchBlock = startCatchBlock; | |
| 2196 catchGraph = new SubGraph(startCatchBlock, kernelBuilder.lastOpenedBlock); | |
| 2197 } | |
| 2198 | |
| 2199 void cleanUp() { | |
| 2200 exitBlock = kernelBuilder.graph.addNewBlock(); | |
| 2201 _setBlockSuccessors(); | |
| 2202 | |
| 2203 // Use the locals handler not altered by the catch and finally | |
| 2204 // blocks. | |
| 2205 kernelBuilder.localsHandler = originalSavedLocals; | |
| 2206 kernelBuilder.open(exitBlock); | |
| 2207 enterBlock.setBlockFlow( | |
| 2208 new HTryBlockInformation( | |
| 2209 kernelBuilder.wrapStatementGraph(bodyGraph), | |
| 2210 exception, | |
| 2211 kernelBuilder.wrapStatementGraph(catchGraph), | |
| 2212 kernelBuilder.wrapStatementGraph(finallyGraph)), | |
| 2213 exitBlock); | |
| 2214 } | |
| 2215 } | |
| OLD | NEW |