Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(169)

Side by Side Diff: pkg/compiler/lib/src/ssa/builder_kernel.dart

Issue 2570273004: Make try/catch/finally work with Kernel code and some refactoring. (Closed)
Patch Set: . Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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 HInstruction buildIsNode(
1863 ir.Node node, ir.DartType dart_type, HInstruction expression) {
1858 // TODO(sra): Convert the type testing logic here to use ir.DartType. 1864 // TODO(sra): Convert the type testing logic here to use ir.DartType.
1859 DartType type = astAdapter.getDartType(isExpression.type); 1865 DartType type = astAdapter.getDartType(dart_type);
1860 1866
1861 type = localsHandler.substInContext(type).unaliased; 1867 type = localsHandler.substInContext(type).unaliased;
1862 1868
1863 if (type is MethodTypeVariableType) { 1869 if (type is MethodTypeVariableType) {
1864 push(graph.addConstantBool(true, compiler)); 1870 return graph.addConstantBool(true, compiler);
1865 return;
1866 } 1871 }
1867 1872
1868 if (type is MalformedType) { 1873 if (type is MalformedType) {
1869 ErroneousElement element = type.element; 1874 ErroneousElement element = type.element;
1870 generateTypeError(isExpression, element.message); 1875 generateTypeError(node, element.message);
1871 push(new HIs.compound(type, expression, pop(), commonMasks.boolType)); 1876 return new HIs.compound(type, expression, pop(), commonMasks.boolType);
1872 return;
1873 } 1877 }
1874 1878
1875 if (type.isFunctionType) { 1879 if (type.isFunctionType) {
1876 List arguments = <HInstruction>[buildFunctionType(type), expression]; 1880 List arguments = <HInstruction>[buildFunctionType(type), expression];
1877 _pushDynamicInvocation(isExpression, commonMasks.boolType, arguments, 1881 _pushDynamicInvocation(node, commonMasks.boolType, arguments,
1878 selector: new Selector.call( 1882 selector: new Selector.call(
1879 new PrivateName('_isTest', astAdapter.jsHelperLibrary), 1883 new PrivateName('_isTest', astAdapter.jsHelperLibrary),
1880 CallStructure.ONE_ARG)); 1884 CallStructure.ONE_ARG));
1881 push(new HIs.compound(type, expression, pop(), commonMasks.boolType)); 1885 return new HIs.compound(type, expression, pop(), commonMasks.boolType);
1882 return;
1883 } 1886 }
1884 1887
1885 if (type.isTypeVariable) { 1888 if (type.isTypeVariable) {
1886 HInstruction runtimeType = 1889 HInstruction runtimeType =
1887 typeBuilder.addTypeVariableReference(type, sourceElement); 1890 typeBuilder.addTypeVariableReference(type, sourceElement);
1888 _pushStaticInvocation(astAdapter.checkSubtypeOfRuntimeType, 1891 _pushStaticInvocation(astAdapter.checkSubtypeOfRuntimeType,
1889 <HInstruction>[expression, runtimeType], commonMasks.boolType); 1892 <HInstruction>[expression, runtimeType], commonMasks.boolType);
1890 push(new HIs.variable(type, expression, pop(), commonMasks.boolType)); 1893 return new HIs.variable(type, expression, pop(), commonMasks.boolType);
1891 return;
1892 } 1894 }
1893 1895
1894 // TODO(sra): Type with type parameters. 1896 // TODO(sra): Type with type parameters.
1895 1897
1896 if (backend.hasDirectCheckFor(type)) { 1898 if (backend.hasDirectCheckFor(type)) {
1897 push(new HIs.direct(type, expression, commonMasks.boolType)); 1899 return new HIs.direct(type, expression, commonMasks.boolType);
1898 return;
1899 } 1900 }
1900 1901
1901 // The interceptor is not always needed. It is removed by optimization 1902 // The interceptor is not always needed. It is removed by optimization
1902 // when the receiver type or tested type permit. 1903 // when the receiver type or tested type permit.
1903 HInterceptor interceptor = _interceptorFor(expression); 1904 HInterceptor interceptor = _interceptorFor(expression);
1904 push(new HIs.raw(type, expression, interceptor, commonMasks.boolType)); 1905 return new HIs.raw(type, expression, interceptor, commonMasks.boolType);
1905 } 1906 }
1906 1907
1907 @override 1908 @override
1908 void visitThrow(ir.Throw throwNode) { 1909 void visitThrow(ir.Throw throwNode) {
1909 _visitThrowExpression(throwNode.expression); 1910 _visitThrowExpression(throwNode.expression);
1910 if (isReachable) { 1911 if (isReachable) {
1911 push(new HThrowExpression(pop(), null)); 1912 push(new HThrowExpression(pop(), null));
1912 isReachable = false; 1913 isReachable = false;
1913 } 1914 }
1914 } 1915 }
(...skipping 18 matching lines...) Expand all
1933 not.operand.accept(this); 1934 not.operand.accept(this);
1934 push(new HNot(popBoolified(), commonMasks.boolType)); 1935 push(new HNot(popBoolified(), commonMasks.boolType));
1935 } 1936 }
1936 1937
1937 @override 1938 @override
1938 void visitStringConcatenation(ir.StringConcatenation stringConcat) { 1939 void visitStringConcatenation(ir.StringConcatenation stringConcat) {
1939 KernelStringBuilder stringBuilder = new KernelStringBuilder(this); 1940 KernelStringBuilder stringBuilder = new KernelStringBuilder(this);
1940 stringConcat.accept(stringBuilder); 1941 stringConcat.accept(stringBuilder);
1941 stack.add(stringBuilder.result); 1942 stack.add(stringBuilder.result);
1942 } 1943 }
1944
1945 @override
1946 void visitTryCatch(ir.TryCatch tryCatch) {
1947 TryCatchFinallyBuilder tryBuilder = new TryCatchFinallyBuilder(this);
1948 tryCatch.body.accept(this);
1949 tryBuilder
1950 ..closeTryBody()
1951 ..buildCatch(tryCatch)
1952 ..cleanUp();
1953 }
1954
1955 /// `try { ... } catch { ... } finally { ... }` statements are a little funny
1956 /// because a try can have one or both of {catch|finally}. The way this is
1957 /// encoded in kernel AST are two separate classes with no common superclass
1958 /// aside from Statement. If a statement has both `catch` and `finally`
1959 /// clauses then it is encoded in kernel as so that the TryCatch is the body
1960 /// statement of the TryFinally. To produce more efficient code rather than
1961 /// nested try statements, the visitors avoid one potential level of
1962 /// recursion.
1963 @override
1964 void visitTryFinally(ir.TryFinally tryFinally) {
1965 TryCatchFinallyBuilder tryBuilder = new TryCatchFinallyBuilder(this);
1966
1967 // We do these shenanigans to produce better looking code that doesn't
1968 // have nested try statements.
1969 if (tryFinally.body is ir.TryCatch) {
1970 ir.TryCatch tryCatch = tryFinally.body;
1971 tryCatch.body.accept(this);
1972 tryBuilder
1973 ..closeTryBody()
1974 ..buildCatch(tryCatch);
1975 } else {
1976 tryFinally.body.accept(this);
1977 tryBuilder.closeTryBody();
1978 }
1979
1980 tryBuilder
1981 ..buildFinallyBlock(tryFinally)
1982 ..cleanUp();
1983 }
1943 } 1984 }
1985
1986 /// Class in charge of building try, catch and/or finally blocks. This handles
1987 /// the instructions that need to be output and the dominator calculation of
1988 /// this sequence of code.
1989 class TryCatchFinallyBuilder {
1990 HBasicBlock enterBlock;
1991 HBasicBlock startTryBlock;
1992 HBasicBlock endTryBlock;
1993 HBasicBlock startCatchBlock;
1994 HBasicBlock endCatchBlock;
1995 HBasicBlock startFinallyBlock;
1996 HBasicBlock endFinallyBlock;
1997 HBasicBlock exitBlock;
1998 HTry tryInstruction;
1999 HLocalValue exception;
2000 KernelSsaBuilder kernelBuilder;
2001
2002 SubGraph bodyGraph;
2003 SubGraph catchGraph;
2004 SubGraph finallyGraph;
2005
2006 // The original set of locals that were defined before this try block.
2007 // The catch block and the finally block must not reuse the existing locals
2008 // handler. None of the variables that have been defined in the body-block
2009 // will be used, but for loops we will add (unnecessary) phis that will
2010 // reference the body variables. This makes it look as if the variables were
2011 // used in a non-dominated block.
2012 LocalsHandler originalSavedLocals;
2013
2014 TryCatchFinallyBuilder(this.kernelBuilder) {
2015 tryInstruction = new HTry();
2016 originalSavedLocals = new LocalsHandler.from(kernelBuilder.localsHandler);
2017 enterBlock = kernelBuilder.openNewBlock();
2018 kernelBuilder.close(tryInstruction);
2019
2020 startTryBlock = kernelBuilder.graph.addNewBlock();
2021 kernelBuilder.open(startTryBlock);
2022 }
2023
2024 void _addExitTrySuccessor(successor) {
2025 if (successor == null) return;
2026 // Iterate over all blocks created inside this try/catch, and
2027 // attach successor information to blocks that end with
2028 // [HExitTry].
2029 for (int i = startTryBlock.id; i < successor.id; i++) {
2030 HBasicBlock block = kernelBuilder.graph.blocks[i];
2031 var last = block.last;
2032 if (last is HExitTry) {
2033 block.addSuccessor(successor);
2034 }
2035 }
2036 }
2037
2038 void _addOptionalSuccessor(block1, block2) {
2039 if (block2 != null) block1.addSuccessor(block2);
2040 }
2041
2042 /// Helper function to set up basic block successors for try-catch-finally
2043 /// sequences.
2044 void _setBlockSuccessors() {
2045 // Setup all successors. The entry block that contains the [HTry]
2046 // has 1) the body, 2) the catch, 3) the finally, and 4) the exit
2047 // blocks as successors.
2048 enterBlock.addSuccessor(startTryBlock);
2049 _addOptionalSuccessor(enterBlock, startCatchBlock);
2050 _addOptionalSuccessor(enterBlock, startFinallyBlock);
2051 enterBlock.addSuccessor(exitBlock);
2052
2053 // The body has either the catch or the finally block as successor.
2054 if (endTryBlock != null) {
2055 assert(startCatchBlock != null || startFinallyBlock != null);
2056 endTryBlock.addSuccessor(
2057 startCatchBlock != null ? startCatchBlock : startFinallyBlock);
2058 endTryBlock.addSuccessor(exitBlock);
2059 }
2060
2061 // The catch block has either the finally or the exit block as
2062 // successor.
2063 endCatchBlock?.addSuccessor(
2064 startFinallyBlock != null ? startFinallyBlock : exitBlock);
2065
2066 // The finally block has the exit block as successor.
2067 endFinallyBlock?.addSuccessor(exitBlock);
2068
2069 // If a block inside try/catch aborts (eg with a return statement),
2070 // we explicitely mark this block a predecessor of the catch
2071 // block and the finally block.
2072 _addExitTrySuccessor(startCatchBlock);
2073 _addExitTrySuccessor(startFinallyBlock);
2074 }
2075
2076 /// Build the finally{} clause of a try/{catch}/finally statement. Note this
2077 /// does not examine the body of the try clause, only the finally portion.
2078 void buildFinallyBlock(ir.TryFinally tryFinally) {
2079 kernelBuilder.localsHandler = new LocalsHandler.from(originalSavedLocals);
2080 startFinallyBlock = kernelBuilder.graph.addNewBlock();
2081 kernelBuilder.open(startFinallyBlock);
2082 tryFinally.finalizer.accept(kernelBuilder);
2083 if (!kernelBuilder.isAborted()) {
2084 endFinallyBlock = kernelBuilder.close(new HGoto());
2085 }
2086 tryInstruction.finallyBlock = startFinallyBlock;
2087 finallyGraph =
2088 new SubGraph(startFinallyBlock, kernelBuilder.lastOpenedBlock);
2089 }
2090
2091 void closeTryBody() {
2092 // We use a [HExitTry] instead of a [HGoto] for the try block
2093 // because it will have multiple successors: the join block, and
2094 // the catch or finally block.
2095 if (!kernelBuilder.isAborted()) {
2096 endTryBlock = kernelBuilder.close(new HExitTry());
2097 }
2098 bodyGraph = new SubGraph(startTryBlock, kernelBuilder.lastOpenedBlock);
2099 }
2100
2101 void buildCatch(ir.TryCatch tryCatch) {
2102 kernelBuilder.localsHandler = new LocalsHandler.from(originalSavedLocals);
2103 startCatchBlock = kernelBuilder.graph.addNewBlock();
2104 kernelBuilder.open(startCatchBlock);
2105 // Note that the name of this local is irrelevant.
2106 SyntheticLocal local = new SyntheticLocal(
2107 'exception', kernelBuilder.localsHandler.executableContext);
2108 exception = new HLocalValue(local, kernelBuilder.commonMasks.nonNullType);
2109 kernelBuilder.add(exception);
2110 HInstruction oldRethrowableException = kernelBuilder.rethrowableException;
2111 kernelBuilder.rethrowableException = exception;
2112
2113 kernelBuilder._pushStaticInvocation(
2114 kernelBuilder.astAdapter.exceptionUnwrapper,
2115 [exception],
2116 kernelBuilder.astAdapter.exceptionUnwrapperType);
2117 HInvokeStatic unwrappedException = kernelBuilder.pop();
2118 tryInstruction.exception = exception;
2119 int catchesIndex = 0;
2120
2121 void pushCondition(ir.Catch catchBlock) {
2122 if (catchBlock.guard is! ir.DynamicType) {
2123 HInstruction condition = kernelBuilder.buildIsNode(
2124 catchBlock.exception, catchBlock.guard, unwrappedException);
2125 kernelBuilder.push(condition);
2126 } else {
2127 kernelBuilder.stack.add(
2128 kernelBuilder.graph.addConstantBool(true, kernelBuilder.compiler));
2129 }
2130 }
2131
2132 void visitThen() {
2133 ir.Catch catchBlock = tryCatch.catches[catchesIndex];
2134 catchesIndex++;
2135 if (catchBlock.exception != null) {
2136 LocalVariableElement exceptionVariable =
2137 kernelBuilder.astAdapter.getElement(catchBlock.exception);
2138 kernelBuilder.localsHandler
2139 .updateLocal(exceptionVariable, unwrappedException);
2140 }
2141 if (catchBlock.stackTrace != null) {
2142 kernelBuilder._pushStaticInvocation(
2143 kernelBuilder.astAdapter.traceFromException,
2144 [exception],
2145 kernelBuilder.astAdapter.traceFromExceptionType);
2146 HInstruction traceInstruction = kernelBuilder.pop();
2147 LocalVariableElement traceVariable =
2148 kernelBuilder.astAdapter.getElement(catchBlock.stackTrace);
2149 kernelBuilder.localsHandler
2150 .updateLocal(traceVariable, traceInstruction);
2151 }
2152 catchBlock.body.accept(kernelBuilder);
2153 }
2154
2155 void visitElse() {
2156 if (catchesIndex >= tryCatch.catches.length) {
2157 kernelBuilder.closeAndGotoExit(new HThrow(
2158 exception, exception.sourceInformation,
2159 isRethrow: true));
2160 } else {
2161 // TODO(efortuna): Make SsaBranchBuilder handle kernel elements, and
2162 // pass tryCatch in here as the "diagnosticNode".
2163 kernelBuilder.handleIf(
2164 visitCondition: () {
2165 pushCondition(tryCatch.catches[catchesIndex]);
2166 },
2167 visitThen: visitThen,
2168 visitElse: visitElse);
2169 }
2170 }
2171
2172 ir.Catch firstBlock = tryCatch.catches[catchesIndex];
2173 // TODO(efortuna): Make SsaBranchBuilder handle kernel elements, and then
2174 // pass tryCatch in here as the "diagnosticNode".
2175 kernelBuilder.handleIf(
2176 visitCondition: () {
2177 pushCondition(firstBlock);
2178 },
2179 visitThen: visitThen,
2180 visitElse: visitElse);
2181 if (!kernelBuilder.isAborted()) {
2182 endCatchBlock = kernelBuilder.close(new HGoto());
2183 }
2184
2185 kernelBuilder.rethrowableException = oldRethrowableException;
2186 tryInstruction.catchBlock = startCatchBlock;
2187 catchGraph = new SubGraph(startCatchBlock, kernelBuilder.lastOpenedBlock);
2188 }
2189
2190 void cleanUp() {
2191 exitBlock = kernelBuilder.graph.addNewBlock();
2192 _setBlockSuccessors();
2193
2194 // Use the locals handler not altered by the catch and finally
2195 // blocks.
2196 kernelBuilder.localsHandler = originalSavedLocals;
2197 kernelBuilder.open(exitBlock);
2198 enterBlock.setBlockFlow(
2199 new HTryBlockInformation(
2200 kernelBuilder.wrapStatementGraph(bodyGraph),
2201 exception,
2202 kernelBuilder.wrapStatementGraph(catchGraph),
2203 kernelBuilder.wrapStatementGraph(finallyGraph)),
2204 exitBlock);
2205 }
2206 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698