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

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
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 @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 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/ssa/kernel_ast_adapter.dart » ('j') | tests/compiler/dart2js/kernel/try_catch_test.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698