JVM prune exception edges in DFA in some cases
This commit is contained in:
+6
-4
@@ -82,13 +82,15 @@ class UninitializedStoresProcessor(private val methodNode: MethodNode) {
|
||||
private val isInSpecialMethod = methodNode.name == "<init>" || methodNode.name == "<clinit>"
|
||||
|
||||
fun run() {
|
||||
val interpreter = UninitializedNewValueMarkerInterpreter(methodNode.instructions)
|
||||
|
||||
if (methodNode.instructions.toArray().none { it.opcode == Opcodes.NEW })
|
||||
return
|
||||
|
||||
val frames = CustomFramesMethodAnalyzer("fake", methodNode, interpreter, this::UninitializedNewValueFrame).analyze()
|
||||
|
||||
val interpreter = UninitializedNewValueMarkerInterpreter(methodNode.instructions)
|
||||
val analyzer = object : FastMethodAnalyzer<BasicValue>("fake", methodNode, interpreter, pruneExceptionEdges = true) {
|
||||
override fun newFrame(nLocals: Int, nStack: Int): Frame<BasicValue> =
|
||||
UninitializedNewValueFrame(nLocals, nStack)
|
||||
}
|
||||
val frames = analyzer.analyze()
|
||||
interpreter.analyzePopInstructions(frames)
|
||||
|
||||
for ((index, insn) in methodNode.instructions.toArray().withIndex()) {
|
||||
|
||||
+6
-6
@@ -17,6 +17,7 @@
|
||||
package org.jetbrains.kotlin.codegen.optimization
|
||||
|
||||
import org.jetbrains.kotlin.codegen.inline.ReifiedTypeInliner
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.FastMethodAnalyzer
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.InstructionLivenessAnalyzer
|
||||
import org.jetbrains.kotlin.codegen.optimization.common.OptimizationBasicInterpreter
|
||||
import org.jetbrains.kotlin.codegen.optimization.fixStack.top
|
||||
@@ -49,22 +50,21 @@ class RedundantCheckCastEliminationMethodTransformer : MethodTransformer() {
|
||||
|
||||
val redundantCheckCasts = ArrayList<TypeInsnNode>()
|
||||
|
||||
val frames = analyze(internalClassName, methodNode, interpreter)
|
||||
val frames = FastMethodAnalyzer(internalClassName, methodNode, interpreter, pruneExceptionEdges = true).analyze()
|
||||
for (i in insns.indices) {
|
||||
val valueType = frames[i]?.top()?.type ?: continue
|
||||
val insn = insns[i]
|
||||
|
||||
if (insn is TypeInsnNode) {
|
||||
val insnType = Type.getObjectType(insn.desc)
|
||||
if (insn.opcode == Opcodes.CHECKCAST) {
|
||||
val typeInsn = insn as TypeInsnNode
|
||||
val insnType = Type.getObjectType(typeInsn.desc)
|
||||
if (!isTrivialSubtype(insnType, valueType)) continue
|
||||
|
||||
//Keep casts to multiarray types cause dex doesn't recognize ANEWARRAY [Ljava/lang/Object; as Object [][], but Object [] type
|
||||
//It's not clear is it bug in dex or not and maybe best to distinguish such types from MULTINEWARRRAY ones in method analyzer
|
||||
if (isMultiArrayType(insnType)) continue
|
||||
|
||||
if (insn.opcode == Opcodes.CHECKCAST) {
|
||||
redundantCheckCasts.add(insn)
|
||||
}
|
||||
redundantCheckCasts.add(typeInsn)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-29
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.optimization.common
|
||||
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Frame
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Interpreter
|
||||
import org.jetbrains.org.objectweb.asm.tree.analysis.Value
|
||||
|
||||
class CustomFramesMethodAnalyzer<V : Value>(
|
||||
owner: String, method: MethodNode, interpreter: Interpreter<V>,
|
||||
private val frameFactory: (Int, Int) -> Frame<V>
|
||||
) : FastMethodAnalyzer<V>(owner, method, interpreter) {
|
||||
override fun newFrame(nLocals: Int, nStack: Int) = frameFactory(nLocals, nStack)
|
||||
}
|
||||
+23
-10
@@ -47,10 +47,12 @@ import org.jetbrains.org.objectweb.asm.tree.analysis.Value
|
||||
* @see org.jetbrains.kotlin.codegen.optimization.fixStack.FastStackAnalyzer
|
||||
*/
|
||||
@Suppress("DuplicatedCode")
|
||||
open class FastMethodAnalyzer<V : Value>(
|
||||
open class FastMethodAnalyzer<V : Value>
|
||||
@JvmOverloads constructor(
|
||||
private val owner: String,
|
||||
val method: MethodNode,
|
||||
private val interpreter: Interpreter<V>
|
||||
private val method: MethodNode,
|
||||
private val interpreter: Interpreter<V>,
|
||||
private val pruneExceptionEdges: Boolean = false
|
||||
) {
|
||||
private val insnsArray = method.instructions.toArray()
|
||||
private val nInsns = method.instructions.size()
|
||||
@@ -74,6 +76,11 @@ open class FastMethodAnalyzer<V : Value>(
|
||||
computeExceptionHandlersForEachInsn(method)
|
||||
initMergeNodes()
|
||||
|
||||
val isTcbStart = BooleanArray(nInsns)
|
||||
for (tcb in method.tryCatchBlocks) {
|
||||
isTcbStart[tcb.start.indexOf()] = true
|
||||
}
|
||||
|
||||
val current = newFrame(method.maxLocals, method.maxStack)
|
||||
val handler = newFrame(method.maxLocals, method.maxStack)
|
||||
initLocals(current)
|
||||
@@ -107,14 +114,20 @@ open class FastMethodAnalyzer<V : Value>(
|
||||
}
|
||||
}
|
||||
|
||||
handlers[insn]?.forEach { tcb ->
|
||||
val exnType = Type.getObjectType(tcb.type ?: "java/lang/Throwable")
|
||||
val jump = tcb.handler.indexOf()
|
||||
// Jump by an exception edge clears the stack, putting exception on top.
|
||||
// So, unless we have a store operation, anything we change on stack would be lost,
|
||||
// and there's no need to analyze exception handler again.
|
||||
// Add an exception edge from TCB start to make sure handler itself is still visited.
|
||||
if (!pruneExceptionEdges || insnOpcode in Opcodes.ISTORE..Opcodes.ASTORE || insnOpcode == Opcodes.IINC || isTcbStart[insn]) {
|
||||
handlers[insn]?.forEach { tcb ->
|
||||
val exnType = Type.getObjectType(tcb.type ?: "java/lang/Throwable")
|
||||
val jump = tcb.handler.indexOf()
|
||||
|
||||
handler.init(f)
|
||||
handler.clearStack()
|
||||
handler.push(interpreter.newValue(exnType))
|
||||
mergeControlFlowEdge(jump, handler)
|
||||
handler.init(f)
|
||||
handler.clearStack()
|
||||
handler.push(interpreter.newValue(exnType))
|
||||
mergeControlFlowEdge(jump, handler)
|
||||
}
|
||||
}
|
||||
|
||||
} catch (e: AnalyzerException) {
|
||||
|
||||
+22
-6
@@ -8787,12 +8787,6 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
runTest("compiler/testData/codegen/box/controlStructures/quicksort.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("slowHtmlLikeDsl.kt")
|
||||
public void testSlowHtmlLikeDsl() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/controlStructures/slowHtmlLikeDsl.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tcbInEliminatedCondition.kt")
|
||||
public void testTcbInEliminatedCondition() throws Exception {
|
||||
@@ -9451,6 +9445,28 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/controlStructures/slowDsl")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class SlowDsl {
|
||||
@Test
|
||||
public void testAllFilesPresentInSlowDsl() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/controlStructures/slowDsl"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("slowHtmlLikeDsl.kt")
|
||||
public void testSlowHtmlLikeDsl() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/controlStructures/slowDsl/slowHtmlLikeDsl.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("slowHtmlLikeDslNoInline.kt")
|
||||
public void testSlowHtmlLikeDslNoInline() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/controlStructures/slowDsl/slowHtmlLikeDslNoInline.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
+5
-1
@@ -35,9 +35,13 @@ inline fun Builder.t2(body: Builder.() -> Unit) {
|
||||
|
||||
val expectedLength = 1906
|
||||
|
||||
fun doStuff(b: Builder) {
|
||||
b.t2 { t2 { t2 { t2 { t2 { t2 { t2 { text("1") } } } } } } }
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val b = Builder("")
|
||||
b.t2 { t2 { t2 { t2 { t2 { t2 { t2 { text("1") } } } } } } }
|
||||
doStuff(b)
|
||||
if (b.content.length != expectedLength)
|
||||
return "${b.content.length}"
|
||||
else
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// ^ this test might be rather slow
|
||||
|
||||
class Builder(var content: String)
|
||||
|
||||
fun Builder.begin(t: String) {
|
||||
content += "<$t>"
|
||||
}
|
||||
|
||||
fun Builder.text(t: String) {
|
||||
content += t
|
||||
}
|
||||
|
||||
fun Builder.end(t: String) {
|
||||
content += "</$t>"
|
||||
}
|
||||
|
||||
fun err(e: Throwable) {}
|
||||
|
||||
fun Builder.tag(t: String, body: Builder.() -> Unit) {
|
||||
begin(t)
|
||||
try {
|
||||
body()
|
||||
} catch (e: Throwable) {
|
||||
err(e)
|
||||
} finally {
|
||||
end(t)
|
||||
}
|
||||
}
|
||||
|
||||
fun Builder.t2(body: Builder.() -> Unit) {
|
||||
tag("t", body)
|
||||
tag("t", body)
|
||||
}
|
||||
|
||||
val expectedLength = 1906
|
||||
|
||||
fun box(): String {
|
||||
val b = Builder("")
|
||||
b.t2 { t2 { t2 { t2 { t2 { t2 { t2 { text("1") } } } } } } }
|
||||
if (b.content.length != expectedLength)
|
||||
return "${b.content.length}"
|
||||
else
|
||||
return "OK"
|
||||
}
|
||||
+22
-6
@@ -8667,12 +8667,6 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
runTest("compiler/testData/codegen/box/controlStructures/quicksort.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("slowHtmlLikeDsl.kt")
|
||||
public void testSlowHtmlLikeDsl() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/controlStructures/slowHtmlLikeDsl.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tcbInEliminatedCondition.kt")
|
||||
public void testTcbInEliminatedCondition() throws Exception {
|
||||
@@ -9331,6 +9325,28 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/controlStructures/slowDsl")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class SlowDsl {
|
||||
@Test
|
||||
public void testAllFilesPresentInSlowDsl() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/controlStructures/slowDsl"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("slowHtmlLikeDsl.kt")
|
||||
public void testSlowHtmlLikeDsl() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/controlStructures/slowDsl/slowHtmlLikeDsl.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("slowHtmlLikeDslNoInline.kt")
|
||||
public void testSlowHtmlLikeDslNoInline() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/controlStructures/slowDsl/slowHtmlLikeDslNoInline.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
+22
-6
@@ -8787,12 +8787,6 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
runTest("compiler/testData/codegen/box/controlStructures/quicksort.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("slowHtmlLikeDsl.kt")
|
||||
public void testSlowHtmlLikeDsl() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/controlStructures/slowHtmlLikeDsl.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("tcbInEliminatedCondition.kt")
|
||||
public void testTcbInEliminatedCondition() throws Exception {
|
||||
@@ -9451,6 +9445,28 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/controlStructures/slowDsl")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class SlowDsl {
|
||||
@Test
|
||||
public void testAllFilesPresentInSlowDsl() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/controlStructures/slowDsl"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM_IR, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("slowHtmlLikeDsl.kt")
|
||||
public void testSlowHtmlLikeDsl() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/controlStructures/slowDsl/slowHtmlLikeDsl.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("slowHtmlLikeDslNoInline.kt")
|
||||
public void testSlowHtmlLikeDslNoInline() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/controlStructures/slowDsl/slowHtmlLikeDslNoInline.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
+23
-5
@@ -6698,11 +6698,6 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
runTest("compiler/testData/codegen/box/controlStructures/quicksort.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("slowHtmlLikeDsl.kt")
|
||||
public void testSlowHtmlLikeDsl() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/controlStructures/slowHtmlLikeDsl.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("tcbInEliminatedCondition.kt")
|
||||
public void testTcbInEliminatedCondition() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/controlStructures/tcbInEliminatedCondition.kt");
|
||||
@@ -7284,6 +7279,29 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/controlStructures/slowDsl")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class SlowDsl extends AbstractLightAnalysisModeTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInSlowDsl() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/controlStructures/slowDsl"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("slowHtmlLikeDsl.kt")
|
||||
public void testSlowHtmlLikeDsl() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/controlStructures/slowDsl/slowHtmlLikeDsl.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("slowHtmlLikeDslNoInline.kt")
|
||||
public void testSlowHtmlLikeDslNoInline() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/controlStructures/slowDsl/slowHtmlLikeDslNoInline.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
+10
@@ -6525,6 +6525,16 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/controlStructures/slowDsl")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class SlowDsl {
|
||||
@Test
|
||||
public void testAllFilesPresentInSlowDsl() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/controlStructures/slowDsl"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
+10
@@ -6567,6 +6567,16 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/controlStructures/slowDsl")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class SlowDsl {
|
||||
@Test
|
||||
public void testAllFilesPresentInSlowDsl() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/controlStructures/slowDsl"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.JS_IR, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
+13
@@ -5691,6 +5691,19 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/controlStructures/slowDsl")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class SlowDsl extends AbstractIrCodegenBoxWasmTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest0(this::doTest, TargetBackend.WASM, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInSlowDsl() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/controlStructures/slowDsl"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.WASM, true);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
|
||||
+12
@@ -7369,6 +7369,18 @@ public class NativeCodegenBoxTestGenerated extends AbstractNativeCodegenBoxTest
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/controlStructures/slowDsl")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@Tag("codegen")
|
||||
@UseExtTestCaseGroupProvider()
|
||||
public class SlowDsl {
|
||||
@Test
|
||||
public void testAllFilesPresentInSlowDsl() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/box/controlStructures/slowDsl"), Pattern.compile("^(.+)\\.kt$"), null, TargetBackend.NATIVE, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("compiler/testData/codegen/box/controlStructures/tryCatchInExpressions")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
Reference in New Issue
Block a user