| // Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| package com.android.tools.r8.jasmin; | |
| import static org.junit.Assert.assertEquals; | |
| import com.android.tools.r8.ToolHelper; | |
| import com.android.tools.r8.debuginfo.DebugInfoInspector; | |
| import com.android.tools.r8.graph.DexCode; | |
| import com.android.tools.r8.graph.DexDebugInfo; | |
| import com.android.tools.r8.jasmin.JasminBuilder.ClassFileVersion; | |
| import com.android.tools.r8.naming.MemberNaming.MethodSignature; | |
| import com.android.tools.r8.utils.AndroidApp; | |
| import com.android.tools.r8.utils.codeinspector.ClassSubject; | |
| import com.android.tools.r8.utils.codeinspector.CodeInspector; | |
| import com.android.tools.r8.utils.codeinspector.MethodSubject; | |
| import com.google.common.collect.ImmutableList; | |
| import org.junit.Test; | |
| public class DebugLocalTests extends JasminTestBase { | |
| @Test | |
| public void testSwap() throws Exception { | |
| JasminBuilder builder = new JasminBuilder(); | |
| JasminBuilder.ClassBuilder clazz = builder.addClass("Test"); | |
| MethodSignature foo = clazz.addVirtualMethod("foo", ImmutableList.of("Ljava/lang/String;"), "V", | |
| // The first three vars are out-of-order to verify that the order is not relied on. | |
| ".var 5 is t I from L4 to L6", | |
| ".var 1 is bar Ljava/lang/String; from L0 to L9", | |
| ".var 0 is this LTest; from L0 to L9", | |
| ".var 2 is x I from L1 to L9", | |
| ".var 3 is y I from L2 to L9", | |
| ".var 4 is z I from L3 to L9", | |
| ".var 5 is foobar Ljava/lang/String; from L7 to L9", | |
| ".limit locals 6", | |
| ".limit stack 2", | |
| "L0:", | |
| ".line 23", | |
| " iconst_1", | |
| " istore 2", | |
| "L1:", | |
| ".line 24", | |
| " iconst_2", | |
| " istore 3", | |
| "L2:", | |
| ".line 25", | |
| " iconst_3", | |
| " istore 4", | |
| "L3:", | |
| " .line 27", | |
| " iload 3", | |
| " istore 5", | |
| "L4:", | |
| " .line 28", | |
| " iload 2", | |
| " istore 3", | |
| "L5:", | |
| " .line 29", | |
| " iload 5", | |
| " istore 2", | |
| "L6:", | |
| " .line 32", | |
| " new java/lang/StringBuilder", | |
| " dup", | |
| " invokespecial java/lang/StringBuilder/<init>()V", | |
| " ldc \"And the value of y is: \"", | |
| " invokevirtual java/lang/StringBuilder/append(Ljava/lang/String;)Ljava/lang/StringBuilder;", | |
| " iload 2", | |
| " invokevirtual java/lang/StringBuilder/append(I)Ljava/lang/StringBuilder;", | |
| " iload 3", | |
| " invokevirtual java/lang/StringBuilder/append(I)Ljava/lang/StringBuilder;", | |
| " iload 4", | |
| " invokevirtual java/lang/StringBuilder/append(I)Ljava/lang/StringBuilder;", | |
| " invokevirtual java/lang/StringBuilder/toString()Ljava/lang/String;", | |
| " astore 5", | |
| "L7:", | |
| " .line 34", | |
| " getstatic java/lang/System/out Ljava/io/PrintStream;", | |
| " aload 5", | |
| " invokevirtual java/io/PrintStream/print(Ljava/lang/String;)V", | |
| "L8:", | |
| " .line 35", | |
| " return", | |
| "L9:"); | |
| clazz.addMainMethod( | |
| ".limit stack 3", | |
| ".limit locals 1", | |
| " new Test", | |
| " dup", | |
| " invokespecial Test/<init>()V", | |
| " ldc \"Fsg\"", | |
| " invokevirtual Test/foo(Ljava/lang/String;)V", | |
| " return"); | |
| String expected = "And the value of y is: 213"; | |
| String javaResult = runOnJava(builder, clazz.name); | |
| assertEquals(expected, javaResult); | |
| AndroidApp jasminApp = builder.build(); | |
| AndroidApp d8App = ToolHelper.runD8(jasminApp); | |
| CodeInspector inspector = new CodeInspector(d8App); | |
| ClassSubject classSubject = inspector.clazz("Test"); | |
| MethodSubject methodSubject = classSubject.method(foo); | |
| DexCode code = methodSubject.getMethod().getCode().asDexCode(); | |
| DexDebugInfo info = code.getDebugInfo(); | |
| assertEquals(23, info.startLine); | |
| assertEquals(1, info.parameters.length); | |
| assertEquals("bar", info.parameters[0].toString()); | |
| // TODO(zerny): Verify the debug computed locals information. | |
| String artResult = runOnArt(d8App, clazz.name); | |
| assertEquals(expected, artResult); | |
| } | |
| @Test | |
| public void testNoLocalInfoOnStack() throws Exception { | |
| JasminBuilder builder = new JasminBuilder(); | |
| JasminBuilder.ClassBuilder clazz = builder.addClass("Test"); | |
| MethodSignature foo = clazz.addVirtualMethod("foo", ImmutableList.of(), "I", | |
| ".var 0 is this LTest; from Init to End", | |
| ".var 1 is x I from XStart to XEnd", | |
| ".limit locals 2", | |
| ".limit stack 1", | |
| "Init:", | |
| ".line 1", | |
| " ldc 0", | |
| " istore 1", | |
| "XStart:", | |
| ".line 2", | |
| " ldc 42", | |
| " istore 1", | |
| " iload 1", | |
| "XEnd:", | |
| ".line 3", | |
| " ireturn", | |
| "End:"); | |
| clazz.addMainMethod( | |
| ".limit stack 3", | |
| ".limit locals 1", | |
| " new Test", | |
| " dup", | |
| " invokespecial Test/<init>()V", | |
| " invokevirtual Test/foo()I", | |
| " getstatic java/lang/System/out Ljava/io/PrintStream;", | |
| " swap", | |
| " invokevirtual java/io/PrintStream/print(I)V", | |
| " return"); | |
| String expected = "42"; | |
| String javaResult = runOnJava(builder, clazz.name); | |
| assertEquals(expected, javaResult); | |
| AndroidApp jasminApp = builder.build(); | |
| AndroidApp d8App = ToolHelper.runD8(jasminApp); | |
| DebugInfoInspector info = new DebugInfoInspector(d8App, clazz.name, foo); | |
| info.checkStartLine(1); | |
| info.checkLineHasExactLocals(1, "this", "Test"); | |
| info.checkLineHasExactLocals(2, "this", "Test", "x", "int"); | |
| info.checkLineHasExactLocals(3, "this", "Test"); | |
| String artResult = runOnArt(d8App, clazz.name); | |
| assertEquals(expected, artResult); | |
| } | |
| // Check that we properly handle switching a local slot from one variable to another. | |
| @Test | |
| public void checkLocalChange() throws Exception { | |
| JasminBuilder builder = new JasminBuilder(ClassFileVersion.JDK_1_4); | |
| JasminBuilder.ClassBuilder clazz = builder.addClass("Test"); | |
| MethodSignature foo = clazz.addStaticMethod("foo", ImmutableList.of("I"), "I", | |
| ".limit stack 2", | |
| ".limit locals 2", | |
| ".var 0 is param I from MethodStart to MethodEnd", | |
| ".var 1 is x I from LabelXStart to LabelXEnd", | |
| ".var 1 is y I from LabelYStart to LabelYEnd", | |
| "MethodStart:", | |
| ".line 1", | |
| " ldc 0", | |
| " istore 1", | |
| "LabelXStart:", | |
| ".line 2", | |
| " invokestatic Test/ensureLine()V", | |
| "LabelXEnd:", | |
| " iload 0", | |
| " lookupswitch", | |
| " 1: Case1", | |
| " default: CaseDefault", | |
| "Case1:", | |
| ".line 3", | |
| " ldc 42", | |
| " istore 1", | |
| "LabelYStart:", | |
| ".line 4", | |
| " invokestatic Test/ensureLine()V", | |
| " goto AfterSwitch", | |
| "CaseDefault:", | |
| ".line 5", | |
| " ldc -42", | |
| " istore 1", | |
| ".line 6", | |
| " invokestatic Test/ensureLine()V", | |
| "AfterSwitch:", | |
| ".line 7", | |
| " iload 1", | |
| " ireturn", | |
| "LabelYEnd:", | |
| "MethodEnd:" | |
| ); | |
| clazz.addStaticMethod("ensureLine", ImmutableList.of(), "V", | |
| ".limit stack 0", | |
| ".limit locals 0", | |
| " return"); | |
| clazz.addMainMethod( | |
| ".limit stack 2", | |
| ".limit locals 1", | |
| " ldc 0", | |
| " invokestatic Test/foo(I)I", | |
| " ldc 1", | |
| " invokestatic Test/foo(I)I", | |
| " pop", | |
| " return"); | |
| String expected = ""; | |
| String javaResult = runOnJava(builder, clazz.name); | |
| assertEquals(expected, javaResult); | |
| AndroidApp jasminApp = builder.build(); | |
| AndroidApp d8App = ToolHelper.runD8(jasminApp); | |
| String artResult = runOnArt(d8App, clazz.name); | |
| assertEquals(expected, artResult); | |
| DebugInfoInspector info = new DebugInfoInspector(d8App, clazz.name, foo); | |
| info.checkStartLine(1); | |
| info.checkLineHasExactLocals(1, "param", "int"); | |
| info.checkLineHasExactLocals(2, "param", "int", "x", "int"); | |
| info.checkLineHasExactLocals(4, "param", "int", "y", "int"); | |
| info.checkLineHasExactLocals(6, "param", "int", "y", "int"); | |
| info.checkLineHasExactLocals(7, "param", "int", "y", "int"); | |
| } | |
| @Test | |
| public void testLocalManyRanges() throws Exception { | |
| JasminBuilder builder = new JasminBuilder(); | |
| JasminBuilder.ClassBuilder clazz = builder.addClass("Test"); | |
| MethodSignature foo = clazz.addStaticMethod("foo", ImmutableList.of("I"), "I", | |
| ".limit stack 2", | |
| ".limit locals 2", | |
| ".var 0 is param I from Init to End", | |
| ".var 1 is x I from LabelStart1 to LabelEnd1", | |
| ".var 1 is x I from LabelStart2 to LabelEnd2", | |
| ".var 1 is x I from LabelStart3 to LabelEnd3", | |
| ".var 1 is x I from LabelStart4 to LabelEnd4", | |
| "Init:", | |
| ".line 1", | |
| " iload 0", | |
| " istore 1", | |
| "LabelStart1:", | |
| ".line 2", | |
| " invokestatic Test/ensureLine()V", | |
| "LabelEnd1:", | |
| ".line 3", | |
| " invokestatic Test/ensureLine()V", | |
| "LabelStart2:", | |
| ".line 4", | |
| " invokestatic Test/ensureLine()V", | |
| "LabelEnd2:", | |
| ".line 5", | |
| " invokestatic Test/ensureLine()V", | |
| "LabelStart3:", | |
| ".line 6", | |
| " invokestatic Test/ensureLine()V", | |
| "LabelEnd3:", | |
| ".line 7", | |
| " invokestatic Test/ensureLine()V", | |
| "LabelStart4:", | |
| ".line 8", | |
| " invokestatic Test/ensureLine()V", | |
| "LabelEnd4:", | |
| ".line 9", | |
| " invokestatic Test/ensureLine()V", | |
| " iload 1", | |
| " ireturn", | |
| "End:" | |
| ); | |
| clazz.addStaticMethod("ensureLine", ImmutableList.of(), "V", | |
| ".limit stack 0", | |
| ".limit locals 0", | |
| " return"); | |
| clazz.addMainMethod( | |
| ".limit stack 2", | |
| ".limit locals 1", | |
| " getstatic java/lang/System/out Ljava/io/PrintStream;", | |
| " ldc 42", | |
| " invokestatic Test/foo(I)I", | |
| " invokevirtual java/io/PrintStream/print(I)V", | |
| " return"); | |
| String expected = "42"; | |
| String javaResult = runOnJava(builder, clazz.name); | |
| assertEquals(expected, javaResult); | |
| AndroidApp jasminApp = builder.build(); | |
| AndroidApp d8App = ToolHelper.runD8(jasminApp); | |
| String artResult = runOnArt(d8App, clazz.name); | |
| assertEquals(expected, artResult); | |
| DebugInfoInspector info = new DebugInfoInspector(d8App, clazz.name, foo); | |
| info.checkStartLine(1); | |
| info.checkLineHasExactLocals(1, "param", "int"); | |
| info.checkLineHasExactLocals(2, "param", "int", "x", "int"); | |
| info.checkLineHasExactLocals(3, "param", "int"); | |
| info.checkLineHasExactLocals(4, "param", "int", "x", "int"); | |
| info.checkLineHasExactLocals(5, "param", "int"); | |
| info.checkLineHasExactLocals(6, "param", "int", "x", "int"); | |
| info.checkLineHasExactLocals(7, "param", "int"); | |
| info.checkLineHasExactLocals(8, "param", "int", "x", "int"); | |
| info.checkLineHasExactLocals(9, "param", "int"); | |
| } | |
| @Test | |
| public void argumentLiveAtReturn() throws Exception { | |
| JasminBuilder builder = new JasminBuilder(ClassFileVersion.JDK_1_4); | |
| JasminBuilder.ClassBuilder clazz = builder.addClass("Test"); | |
| /* | |
| This is the original Java source code. | |
| public static int argumentLiveAtReturn(int x) { // Line 1 | |
| switch (x) { | |
| case 0: | |
| return 0; | |
| case 1: | |
| return 0; | |
| case 2: | |
| return 0; | |
| case 100: | |
| return 1; | |
| case 101: | |
| return 1; | |
| case 102: | |
| return 1; | |
| } | |
| return -1; | |
| } | |
| */ | |
| MethodSignature foo = clazz.addStaticMethod("argumentLiveAtReturn", ImmutableList.of("I"), "I", | |
| ".limit stack 2", | |
| ".limit locals 1", | |
| ".var 0 is x I from L0 to L8", | |
| "L0:", | |
| ".line 2", | |
| " iload 0", | |
| "lookupswitch", | |
| " 0: L1", | |
| " 1: L2", | |
| " 2: L3", | |
| " 100: L4", | |
| " 101: L5", | |
| " 102: L6", | |
| " default: L7", | |
| "L1:", | |
| ".line 4", | |
| " iconst_0", | |
| " ireturn", | |
| "L2:", | |
| ".line 6", | |
| " iconst_0", | |
| " ireturn", | |
| "L3:", | |
| ".line 8", | |
| " iconst_0", | |
| " ireturn", | |
| "L4:", | |
| ".line 10", | |
| " iconst_1", | |
| " ireturn", | |
| "L5:", | |
| ".line 12", | |
| " iconst_1", | |
| " ireturn", | |
| "L6:", | |
| ".line 14", | |
| " iconst_1", | |
| " ireturn", | |
| "L7:", | |
| ".line 16", | |
| " iconst_m1", | |
| " ireturn", | |
| "L8:" | |
| ); | |
| clazz.addMainMethod( | |
| ".limit stack 2", | |
| ".limit locals 1", | |
| " getstatic java/lang/System/out Ljava/io/PrintStream;", | |
| " ldc -1", | |
| " invokestatic Test/argumentLiveAtReturn(I)I", | |
| " invokevirtual java/io/PrintStream/print(I)V", | |
| " return"); | |
| String expected = "-1"; | |
| String javaResult = runOnJava(builder, clazz.name); | |
| assertEquals(expected, javaResult); | |
| AndroidApp jasminApp = builder.build(); | |
| AndroidApp d8App = ToolHelper.runD8(jasminApp); | |
| String artResult = runOnArt(d8App, clazz.name); | |
| assertEquals(expected, artResult); | |
| DebugInfoInspector info = new DebugInfoInspector(d8App, clazz.name, foo); | |
| info.checkStartLine(2); | |
| info.checkLineHasExactLocals(2, "x", "int"); | |
| info.checkLineHasExactLocals(4, "x", "int"); | |
| info.checkLineHasExactLocals(6, "x", "int"); | |
| info.checkLineHasExactLocals(8, "x", "int"); | |
| info.checkLineHasExactLocals(10, "x", "int"); | |
| info.checkLineHasExactLocals(12, "x", "int"); | |
| info.checkLineHasExactLocals(14, "x", "int"); | |
| info.checkLineHasExactLocals(16, "x", "int"); | |
| } | |
| @Test | |
| public void testLocalSwitchRewriteToIfs() throws Exception { | |
| JasminBuilder builder = new JasminBuilder(ClassFileVersion.JDK_1_4); | |
| JasminBuilder.ClassBuilder clazz = builder.addClass("Test"); | |
| /* | |
| This is the original Java source code. The code generated by javac have been | |
| slightly modified below to end local t on the lookupswitch instruction. | |
| public static int switchRewrite(int x) { // Line 1 | |
| { | |
| int t = x + 1; | |
| x = t; | |
| x = x + x; | |
| } | |
| switch (x) { | |
| case 1: | |
| return 7; | |
| case 100: | |
| return 8; | |
| } | |
| return -1; | |
| } | |
| */ | |
| MethodSignature foo = clazz.addStaticMethod("switchRewrite", ImmutableList.of("I"), "I", | |
| ".limit stack 2", | |
| ".limit locals 2", | |
| ".var 0 is x I from L0 to L7", | |
| ".var 1 is t I from L1 to L3", | |
| "L0:", | |
| ".line 3", | |
| " iload 0", | |
| " iconst_1", | |
| " iadd", | |
| " istore 1", | |
| "L1:", | |
| ".line 4", | |
| " iload 1", | |
| " istore 0", | |
| "L2:", | |
| ".line 5", | |
| " iload 0", | |
| " iload 0", | |
| " iadd", | |
| " istore 0", | |
| "L3_ORIGINAL:", // This is where javac normally ends t. | |
| ".line 7", | |
| " iload 0", | |
| "lookupswitch", | |
| " 0: L4", | |
| " 100: L5", | |
| " default: L6", | |
| "L3:", // Moved L3 here to end t on the switch instruction. | |
| "L4:", | |
| ".line 9", | |
| " iconst_0", | |
| " ireturn", | |
| "L5:", | |
| ".line 11", | |
| " iconst_1", | |
| " ireturn", | |
| "L6:", | |
| ".line 13", | |
| " iconst_m1", | |
| " ireturn", | |
| "L7:" | |
| ); | |
| clazz.addMainMethod( | |
| ".limit stack 2", | |
| ".limit locals 1", | |
| " getstatic java/lang/System/out Ljava/io/PrintStream;", | |
| " ldc 1", | |
| " invokestatic Test/switchRewrite(I)I", | |
| " invokevirtual java/io/PrintStream/print(I)V", | |
| " return"); | |
| String expected = "-1"; | |
| String javaResult = runOnJava(builder, clazz.name); | |
| assertEquals(expected, javaResult); | |
| AndroidApp jasminApp = builder.build(); | |
| AndroidApp d8App = ToolHelper.runD8(jasminApp); | |
| String artResult = runOnArt(d8App, clazz.name); | |
| assertEquals(expected, artResult); | |
| DebugInfoInspector info = new DebugInfoInspector(d8App, clazz.name, foo); | |
| info.checkStartLine(3); | |
| info.checkLineHasExactLocals(3, "x", "int"); | |
| info.checkLineHasExactLocals(4, "x", "int", "t", "int"); | |
| info.checkLineHasExactLocals(5, "x", "int", "t", "int"); | |
| info.checkLineHasExactLocals(7, "x", "int", "t", "int"); | |
| info.checkLineHasExactLocals(9, "x", "int"); | |
| info.checkLineHasExactLocals(11, "x", "int"); | |
| info.checkLineHasExactLocals(13, "x", "int"); | |
| } | |
| @Test | |
| public void testLocalSwitchRewriteToSwitches() throws Exception { | |
| JasminBuilder builder = new JasminBuilder(ClassFileVersion.JDK_1_4); | |
| JasminBuilder.ClassBuilder clazz = builder.addClass("Test"); | |
| /* | |
| This is the original Java source code. The code generated by javac have been | |
| slightly modified below to end local t on the lookupswitch instruction. | |
| public static int switchRewrite(int x) { // Line 1 | |
| { | |
| int t = x + 1; | |
| x = t; | |
| x = x + x; | |
| } | |
| switch (x) { | |
| case 0: | |
| return 0; | |
| case 1: | |
| return 0; | |
| case 2: | |
| return 0; | |
| case 100: | |
| return 1; | |
| case 101: | |
| return 1; | |
| case 102: | |
| return 1; | |
| } | |
| return -1; | |
| } | |
| */ | |
| MethodSignature foo = clazz.addStaticMethod("switchRewrite", ImmutableList.of("I"), "I", | |
| ".limit stack 2", | |
| ".limit locals 2", | |
| ".var 0 is x I from L0 to L11", | |
| ".var 1 is t I from L1 to L3", | |
| "L0:", | |
| ".line 3", | |
| " iload 0", | |
| " iconst_1", | |
| " iadd", | |
| " istore 1", | |
| "L1:", | |
| ".line 4", | |
| " iload 1", | |
| " istore 0", | |
| "L2:", | |
| ".line 5", | |
| " iload 0", | |
| " iload 0", | |
| " iadd", | |
| " istore 0", | |
| "L3_ORIGINAL:", // This is where javac normally ends t. | |
| ".line 7", | |
| " iload 0", | |
| "lookupswitch", | |
| " 0: L4", | |
| " 1: L5", | |
| " 2: L6", | |
| " 100: L7", | |
| " 101: L8", | |
| " 102: L9", | |
| " default: L10", | |
| "L3:", // Moved L3 here to end t on the switch instruction. | |
| "L4:", | |
| ".line 9", | |
| " iconst_0", | |
| " ireturn", | |
| "L5:", | |
| ".line 11", | |
| " iconst_0", | |
| " ireturn", | |
| "L6:", | |
| ".line 13", | |
| " iconst_0", | |
| " ireturn", | |
| "L7:", | |
| ".line 15", | |
| " iconst_1", | |
| " ireturn", | |
| "L8:", | |
| ".line 17", | |
| " iconst_1", | |
| " ireturn", | |
| "L9:", | |
| ".line 19", | |
| " iconst_1", | |
| " ireturn", | |
| "L10:", | |
| ".line 21", | |
| " iconst_m1", | |
| " ireturn", | |
| "L11:" | |
| ); | |
| clazz.addMainMethod( | |
| ".limit stack 2", | |
| ".limit locals 1", | |
| " getstatic java/lang/System/out Ljava/io/PrintStream;", | |
| " ldc 1", | |
| " invokestatic Test/switchRewrite(I)I", | |
| " invokevirtual java/io/PrintStream/print(I)V", | |
| " return"); | |
| String expected = "-1"; | |
| String javaResult = runOnJava(builder, clazz.name); | |
| assertEquals(expected, javaResult); | |
| AndroidApp jasminApp = builder.build(); | |
| AndroidApp d8App = ToolHelper.runD8(jasminApp); | |
| String artResult = runOnArt(d8App, clazz.name); | |
| assertEquals(expected, artResult); | |
| DebugInfoInspector info = new DebugInfoInspector(d8App, clazz.name, foo); | |
| info.checkStartLine(3); | |
| info.checkLineHasExactLocals(3, "x", "int"); | |
| info.checkLineHasExactLocals(4, "x", "int", "t", "int"); | |
| info.checkLineHasExactLocals(5, "x", "int", "t", "int"); | |
| info.checkLineHasExactLocals(7, "x", "int", "t", "int"); | |
| info.checkLineHasExactLocals(9, "x", "int"); | |
| info.checkLineHasExactLocals(11, "x", "int"); | |
| info.checkLineHasExactLocals(13, "x", "int"); | |
| } | |
| @Test | |
| public void testLocalEndAfterLine() throws Exception { | |
| JasminBuilder builder = new JasminBuilder(); | |
| JasminBuilder.ClassBuilder clazz = builder.addClass("Test"); | |
| MethodSignature foo = clazz.addStaticMethod("foo", ImmutableList.of("I"), "I", | |
| ".limit stack 2", | |
| ".limit locals 2", | |
| ".var 0 is x I from L0 to L4", | |
| ".var 1 is t I from L1 to L3", | |
| "L0:", | |
| ".line 1", | |
| " iload 0", | |
| " iconst_1", | |
| " iadd", | |
| " istore 1", | |
| "L1:", | |
| ".line 2", | |
| " iload 1", | |
| " istore 0", | |
| "L2:", | |
| ".line 3", | |
| " iload 0", | |
| " iload 0", | |
| " iadd", | |
| " istore 0", | |
| ".line 4", | |
| " iload 0", | |
| "L3:", // This should not end t on line 4! | |
| ".line 5", | |
| " ireturn", | |
| "L4:" | |
| ); | |
| clazz.addMainMethod( | |
| ".limit stack 2", | |
| ".limit locals 1", | |
| " getstatic java/lang/System/out Ljava/io/PrintStream;", | |
| " ldc 1", | |
| " invokestatic Test/foo(I)I", | |
| " invokevirtual java/io/PrintStream/print(I)V", | |
| " return"); | |
| String expected = "4"; | |
| String javaResult = runOnJava(builder, clazz.name); | |
| assertEquals(expected, javaResult); | |
| AndroidApp jasminApp = builder.build(); | |
| AndroidApp d8App = ToolHelper.runD8(jasminApp); | |
| String artResult = runOnArt(d8App, clazz.name); | |
| assertEquals(expected, artResult); | |
| DebugInfoInspector info = new DebugInfoInspector(d8App, clazz.name, foo); | |
| info.checkStartLine(1); | |
| info.checkLineHasExactLocals(1, "x", "int"); | |
| info.checkLineHasExactLocals(2, "x", "int", "t", "int"); | |
| info.checkLineHasExactLocals(3, "x", "int", "t", "int"); | |
| info.checkLineHasExactLocals(4, "x", "int", "t", "int"); | |
| info.checkLineHasExactLocals(5, "x", "int"); | |
| } | |
| } |