blob: 40928ee7a4be7286f7f604e5d98c566ed5cb5254 [file] [log] [blame]
// 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.dex.Constants;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map.Entry;
import org.junit.Test;
public class JumboStringTests extends JasminTestBase {
// String constants are split into several class files to ensure both the constant-pool and
// instruction count are below the class-file limits.
private static int CLASSES_COUNT = 10;
private static int MIN_STRING_COUNT = Constants.MAX_NON_JUMBO_INDEX + 2;
private static int EXTRA_STRINGS_PER_CLASSES_COUNT = MIN_STRING_COUNT % CLASSES_COUNT;
private static int STRINGS_PER_CLASSES_COUNT =
EXTRA_STRINGS_PER_CLASSES_COUNT + MIN_STRING_COUNT / CLASSES_COUNT;
@Test
public void test() throws Exception {
JasminBuilder builder = new JasminBuilder();
LinkedHashMap<String, MethodSignature> classes = new LinkedHashMap<>(CLASSES_COUNT);
for (int i = 0; i < CLASSES_COUNT; i++) {
JasminBuilder.ClassBuilder clazz = builder.addClass("Test" + i);
List<String> lines = new ArrayList<>(STRINGS_PER_CLASSES_COUNT + 100);
lines.addAll(
ImmutableList.of(
".limit locals 3",
".limit stack 4",
".var 0 is this LTest; from L0 to L2",
".var 1 is i I from L0 to L2",
".var 2 is strings [Ljava/lang/String; from L1 to L2",
"L0:",
".line 1",
" ldc " + STRINGS_PER_CLASSES_COUNT,
" anewarray java/lang/String",
" astore 2",
"L1:",
".line 2"));
for (int j = 0; j < STRINGS_PER_CLASSES_COUNT; j++) {
lines.add(" aload 2");
lines.add(" ldc " + j);
lines.add(" ldc \"string" + i + "_" + j + "\"");
lines.add(" aastore");
}
lines.addAll(
ImmutableList.of(
"L2:",
" .line 3",
" aload 2",
" iload 1",
" aaload",
" checkcast java/lang/String",
" areturn"));
MethodSignature foo =
clazz.addVirtualMethod(
"foo", ImmutableList.of("I"), "Ljava/lang/String;", lines.toArray(new String[0]));
classes.put(clazz.name, foo);
}
JasminBuilder.ClassBuilder clazz = builder.addClass("Test");
clazz.addMainMethod(
".limit stack 3",
".limit locals 1",
" new Test0",
" dup",
" invokespecial Test0/<init>()V",
" ldc 42",
" invokevirtual Test0/foo(I)Ljava/lang/String;",
" getstatic java/lang/System/out Ljava/io/PrintStream;",
" swap",
" invokevirtual java/io/PrintStream/print(Ljava/lang/String;)V",
" return");
String expected = "string0_42";
assertEquals(expected, runOnJava(builder, clazz.name));
AndroidApp jasminApp = builder.build();
AndroidApp d8App = ToolHelper.runD8(jasminApp);
assertEquals(expected, runOnArt(d8App, clazz.name));
CodeInspector inspector = new CodeInspector(d8App);
for (Entry<String, MethodSignature> entry : classes.entrySet()) {
DebugInfoInspector info = new DebugInfoInspector(inspector, entry.getKey(), entry.getValue());
info.checkStartLine(1);
// If jumbo-string processing fails to keep debug info, some methods will have lost 'i' here.
info.checkLineHasExactLocals(1, "this", entry.getKey(), "i", "int");
info.checkLineHasExactLocals(
2, "this", entry.getKey(), "i", "int", "strings", "java.lang.String[]");
}
}
}