Add .bss support for inlining across dexfiles within Oat
We can safely reference other dexfiles within the same oat file for cross-dex inlining.
This CL makes the OptStat#NotInlinedBss drop to less than 1% of the not-inlining cases.
Test: ART tests
Change-Id: I676d48d973abf7a6f8412cf3b7bb73afd7747f31
diff --git a/CleanSpec.mk b/CleanSpec.mk
index c9200e1..f7be2d5 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -119,6 +119,7 @@
$(call add-clean-step, find $(OUT_DIR) -name "*.oat" -o -name "*.odex" -o -name "*.art" -o -name '*.vdex' | xargs rm -f)
$(call add-clean-step, find $(OUT_DIR) -name "*.oat" -o -name "*.odex" -o -name "*.art" -o -name '*.vdex' | xargs rm -f)
$(call add-clean-step, find $(OUT_DIR) -name "*.oat" -o -name "*.odex" -o -name "*.art" -o -name '*.vdex' | xargs rm -f)
+$(call add-clean-step, find $(OUT_DIR) -name "*.oat" -o -name "*.odex" -o -name "*.art" -o -name '*.vdex' | xargs rm -f)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index db17bda..a31be3f 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -373,6 +373,11 @@
return initialize_app_image_classes_;
}
+ bool WithinOatFile(const DexFile* dex_file) const {
+ return std::find(GetDexFilesForOatFile().begin(), GetDexFilesForOatFile().end(), dex_file) !=
+ GetDexFilesForOatFile().end();
+ }
+
private:
bool ParseDumpInitFailures(const std::string& option, std::string* error_msg);
bool ParseRegisterAllocationStrategy(const std::string& option, std::string* error_msg);
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index a323405..fe97c7f 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -281,7 +281,8 @@
InvokeRuntimeCallingConvention calling_convention;
if (must_resolve_type) {
- DCHECK(IsSameDexFile(cls_->GetDexFile(), arm64_codegen->GetGraph()->GetDexFile()));
+ DCHECK(IsSameDexFile(cls_->GetDexFile(), arm64_codegen->GetGraph()->GetDexFile()) ||
+ arm64_codegen->GetCompilerOptions().WithinOatFile(&cls_->GetDexFile()));
dex::TypeIndex type_index = cls_->GetTypeIndex();
__ Mov(calling_convention.GetRegisterAt(0).W(), type_index.index_);
if (cls_->NeedsAccessCheck()) {
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index 6d77f54..b58ef12 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -529,7 +529,8 @@
InvokeRuntimeCallingConventionARMVIXL calling_convention;
if (must_resolve_type) {
- DCHECK(IsSameDexFile(cls_->GetDexFile(), arm_codegen->GetGraph()->GetDexFile()));
+ DCHECK(IsSameDexFile(cls_->GetDexFile(), arm_codegen->GetGraph()->GetDexFile()) ||
+ arm_codegen->GetCompilerOptions().WithinOatFile(&cls_->GetDexFile()));
dex::TypeIndex type_index = cls_->GetTypeIndex();
__ Mov(calling_convention.GetRegisterAt(0), type_index.index_);
if (cls_->NeedsAccessCheck()) {
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 4008b7d..7924e56 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -288,7 +288,8 @@
InvokeRuntimeCallingConvention calling_convention;
if (must_resolve_type) {
- DCHECK(IsSameDexFile(cls_->GetDexFile(), x86_codegen->GetGraph()->GetDexFile()));
+ DCHECK(IsSameDexFile(cls_->GetDexFile(), x86_codegen->GetGraph()->GetDexFile()) ||
+ x86_codegen->GetCompilerOptions().WithinOatFile(&cls_->GetDexFile()));
dex::TypeIndex type_index = cls_->GetTypeIndex();
__ movl(calling_convention.GetRegisterAt(0), Immediate(type_index.index_));
if (cls_->NeedsAccessCheck()) {
@@ -5497,7 +5498,8 @@
size_t index = invoke->IsInvokeInterface()
? invoke->AsInvokeInterface()->GetSpecialInputIndex()
: invoke->AsInvokeStaticOrDirect()->GetSpecialInputIndex();
- DCHECK(IsSameDexFile(GetGraph()->GetDexFile(), *invoke->GetMethodReference().dex_file));
+ DCHECK(IsSameDexFile(GetGraph()->GetDexFile(), *invoke->GetMethodReference().dex_file) ||
+ GetCompilerOptions().WithinOatFile(invoke->GetMethodReference().dex_file));
HX86ComputeBaseMethodAddress* method_address =
invoke->InputAt(index)->AsX86ComputeBaseMethodAddress();
// Add the patch entry and bind its label at the end of the instruction.
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index ad81620..f737d06 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -272,7 +272,8 @@
// Custom calling convention: RAX serves as both input and output.
if (must_resolve_type) {
- DCHECK(IsSameDexFile(cls_->GetDexFile(), x86_64_codegen->GetGraph()->GetDexFile()));
+ DCHECK(IsSameDexFile(cls_->GetDexFile(), x86_64_codegen->GetGraph()->GetDexFile()) ||
+ x86_64_codegen->GetCompilerOptions().WithinOatFile(&cls_->GetDexFile()));
dex::TypeIndex type_index = cls_->GetTypeIndex();
__ movl(CpuRegister(RAX), Immediate(type_index.index_));
if (cls_->NeedsAccessCheck()) {
@@ -1228,7 +1229,8 @@
}
void CodeGeneratorX86_64::RecordMethodBssEntryPatch(HInvoke* invoke) {
- DCHECK(IsSameDexFile(GetGraph()->GetDexFile(), *invoke->GetMethodReference().dex_file));
+ DCHECK(IsSameDexFile(GetGraph()->GetDexFile(), *invoke->GetMethodReference().dex_file) ||
+ GetCompilerOptions().WithinOatFile(invoke->GetMethodReference().dex_file));
method_bss_entry_patches_.emplace_back(invoke->GetMethodReference().dex_file,
invoke->GetMethodReference().index);
__ Bind(&method_bss_entry_patches_.back().label);
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index e996512..8d0258d 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -1710,6 +1710,7 @@
// JIT can always encode methods in stack maps.
return true;
}
+
const DexFile* dex_file = callee->GetDexFile();
if (IsSameDexFile(outer_dex_file, *dex_file)) {
return true;
@@ -1718,15 +1719,16 @@
// Inline across dexfiles if the callee's DexFile is:
// 1) in the bootclasspath, or
if (callee->GetDeclaringClass()->GetClassLoader() == nullptr) {
+ // There are cases in which the BCP DexFiles are within the OatFile as far as the compiler
+ // options are concerned, but they have their own OatWriter (and therefore not in the same
+ // OatFile). Then, we request the BSS check for all BCP DexFiles.
+ // TODO(solanes): Add .bss support for BCP.
*out_needs_bss_check = true;
return true;
}
- // 2) is a non-BCP dexfile with an OatDexFile.
- const std::vector<const DexFile*>& dex_files =
- codegen->GetCompilerOptions().GetDexFilesForOatFile();
- if (std::find(dex_files.begin(), dex_files.end(), dex_file) != dex_files.end()) {
- *out_needs_bss_check = true;
+ // 2) is a non-BCP dexfile with the OatFile we are compiling.
+ if (codegen->GetCompilerOptions().WithinOatFile(dex_file)) {
return true;
}
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index 5bd060e..5ac2bbf 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -944,8 +944,9 @@
size_t number_of_indexes,
/*inout*/ SafeMap<const DexFile*, BitVector>* references) {
// We currently support inlining of throwing instructions only when they originate in the
- // same dex file as the outer method. All .bss references are used by throwing instructions.
- DCHECK_EQ(dex_file_, ref.dex_file);
+ // same oat file as the outer method. All .bss references are used by throwing instructions.
+ DCHECK(std::find(writer_->dex_files_->begin(), writer_->dex_files_->end(), ref.dex_file) !=
+ writer_->dex_files_->end());
DCHECK_LT(ref.index, number_of_indexes);
auto refs_it = references->find(ref.dex_file);
diff --git a/runtime/oat.h b/runtime/oat.h
index 5b60073..bc9a2ca 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,8 +32,8 @@
class PACKED(4) OatHeader {
public:
static constexpr std::array<uint8_t, 4> kOatMagic { { 'o', 'a', 't', '\n' } };
- // Last oat version changed reason: Inlining across dex files for non-BCP methods.
- static constexpr std::array<uint8_t, 4> kOatVersion { { '2', '1', '0', '\0' } };
+ // Last oat version changed reason: Inlining across dex files for bss within OAT.
+ static constexpr std::array<uint8_t, 4> kOatVersion { { '2', '1', '1', '\0' } };
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
static constexpr const char* kDebuggableKey = "debuggable";
diff --git a/test/2237-checker-inline-multidex/expected-stdout.txt b/test/2237-checker-inline-multidex/expected-stdout.txt
index e69de29..571349a 100644
--- a/test/2237-checker-inline-multidex/expected-stdout.txt
+++ b/test/2237-checker-inline-multidex/expected-stdout.txt
@@ -0,0 +1,4 @@
+abc
+def
+ghi
+class Multi$Multi2
diff --git a/test/2237-checker-inline-multidex/src-multidex/Multi.java b/test/2237-checker-inline-multidex/src-multidex/Multi.java
index 6c65431..cd234c3 100644
--- a/test/2237-checker-inline-multidex/src-multidex/Multi.java
+++ b/test/2237-checker-inline-multidex/src-multidex/Multi.java
@@ -15,9 +15,27 @@
*/
public class Multi {
- public static String $inline$doThings(String str) {
+ public static String $inline$NeedsEnvironmentMultiDex(String str) {
// StringBuilderAppend needs an environment but it doesn't need a .bss entry.
StringBuilder sb = new StringBuilder();
return sb.append(str).toString();
}
+
+ public static String $inline$NeedsBssEntryStringMultiDex() {
+ return "def";
+ }
+
+ private static String $noinline$InnerInvokeMultiDex() {
+ return "ghi";
+ }
+
+ public static String $inline$NeedsBssEntryInvokeMultiDex() {
+ return $noinline$InnerInvokeMultiDex();
+ }
+
+ public static Class<?> NeedsBssEntryClassMultiDex() {
+ return Multi2.class;
+ }
+
+ private class Multi2 {}
}
diff --git a/test/2237-checker-inline-multidex/src/Main.java b/test/2237-checker-inline-multidex/src/Main.java
index 7e026fb..7ab2e7f 100644
--- a/test/2237-checker-inline-multidex/src/Main.java
+++ b/test/2237-checker-inline-multidex/src/Main.java
@@ -15,15 +15,58 @@
*/
public class Main {
- /// CHECK-START: void Main.main(java.lang.String[]) inliner (before)
- /// CHECK: InvokeStaticOrDirect method_name:Multi.$inline$doThings
-
- /// CHECK-START: void Main.main(java.lang.String[]) inliner (after)
- /// CHECK-NOT: InvokeStaticOrDirect method_name:Multi.$inline$doThings
-
- /// CHECK-START: void Main.main(java.lang.String[]) inliner (after)
- /// CHECK: StringBuilderAppend
public static void main(String[] args) {
- Multi.$inline$doThings("abc");
+ System.out.println(testNeedsEnvironment());
+ System.out.println(testNeedsBssEntryString());
+ System.out.println(testNeedsBssEntryInvoke());
+ System.out.println(testClass());
+ }
+
+ /// CHECK-START: java.lang.String Main.testNeedsEnvironment() inliner (before)
+ /// CHECK: InvokeStaticOrDirect method_name:Multi.$inline$NeedsEnvironmentMultiDex
+
+ /// CHECK-START: java.lang.String Main.testNeedsEnvironment() inliner (after)
+ /// CHECK-NOT: InvokeStaticOrDirect method_name:Multi.$inline$NeedsEnvironmentMultiDex
+
+ /// CHECK-START: java.lang.String Main.testNeedsEnvironment() inliner (after)
+ /// CHECK: StringBuilderAppend
+ public static String testNeedsEnvironment() {
+ return Multi.$inline$NeedsEnvironmentMultiDex("abc");
+ }
+
+ /// CHECK-START: java.lang.String Main.testNeedsBssEntryString() inliner (before)
+ /// CHECK: InvokeStaticOrDirect method_name:Multi.$inline$NeedsBssEntryStringMultiDex
+
+ /// CHECK-START: java.lang.String Main.testNeedsBssEntryString() inliner (after)
+ /// CHECK-NOT: InvokeStaticOrDirect method_name:Multi.$inline$NeedsBssEntryStringMultiDex
+
+ /// CHECK-START: java.lang.String Main.testNeedsBssEntryString() inliner (after)
+ /// CHECK: LoadString load_kind:BssEntry
+ public static String testNeedsBssEntryString() {
+ return Multi.$inline$NeedsBssEntryStringMultiDex();
+ }
+
+ /// CHECK-START: java.lang.String Main.testNeedsBssEntryInvoke() inliner (before)
+ /// CHECK: InvokeStaticOrDirect method_name:Multi.$inline$NeedsBssEntryInvokeMultiDex
+
+ /// CHECK-START: java.lang.String Main.testNeedsBssEntryInvoke() inliner (after)
+ /// CHECK-NOT: InvokeStaticOrDirect method_name:Multi.$inline$NeedsBssEntryInvokeMultiDex
+
+ /// CHECK-START: java.lang.String Main.testNeedsBssEntryInvoke() inliner (after)
+ /// CHECK: InvokeStaticOrDirect method_name:Multi.$noinline$InnerInvokeMultiDex method_load_kind:BssEntry
+ public static String testNeedsBssEntryInvoke() {
+ return Multi.$inline$NeedsBssEntryInvokeMultiDex();
+ }
+
+ /// CHECK-START: java.lang.Class Main.testClass() inliner (before)
+ /// CHECK: InvokeStaticOrDirect method_name:Multi.NeedsBssEntryClassMultiDex
+
+ /// CHECK-START: java.lang.Class Main.testClass() inliner (after)
+ /// CHECK-NOT: InvokeStaticOrDirect method_name:Multi.NeedsBssEntryClassMultiDex
+
+ /// CHECK-START: java.lang.Class Main.testClass() inliner (after)
+ /// CHECK: LoadClass load_kind:BssEntry class_name:Multi$Multi2
+ public static Class<?> testClass() {
+ return Multi.NeedsBssEntryClassMultiDex();
}
}
diff --git a/test/462-checker-inlining-dex-files/src/Main.java b/test/462-checker-inlining-dex-files/src/Main.java
index c2bb479..f426b40 100644
--- a/test/462-checker-inlining-dex-files/src/Main.java
+++ b/test/462-checker-inlining-dex-files/src/Main.java
@@ -47,15 +47,14 @@
return OtherDex.returnIntMethod();
}
- /// CHECK-START: int Main.dontInlineOtherDexStatic() inliner (before)
- /// CHECK-DAG: <<Invoke:i\d+>> InvokeStaticOrDirect
+ /// CHECK-START: int Main.inlineOtherDexStatic() inliner (before)
+ /// CHECK-DAG: <<Invoke:i\d+>> InvokeStaticOrDirect method_name:OtherDex.returnOtherDexStatic
/// CHECK-DAG: Return [<<Invoke>>]
- /// CHECK-START: int Main.dontInlineOtherDexStatic() inliner (after)
- /// CHECK-DAG: <<Invoke:i\d+>> InvokeStaticOrDirect
- /// CHECK-DAG: Return [<<Invoke>>]
+ /// CHECK-START: int Main.inlineOtherDexStatic() inliner (after)
+ /// CHECK-NOT: InvokeStaticOrDirect method_name:OtherDex.returnOtherDexStatic
- public static int dontInlineOtherDexStatic() {
+ public static int inlineOtherDexStatic() {
return OtherDex.returnOtherDexStatic();
}
@@ -75,38 +74,36 @@
}
/// CHECK-START: int Main.dontInlineRecursiveCall() inliner (before)
- /// CHECK-DAG: <<Invoke:i\d+>> InvokeStaticOrDirect
+ /// CHECK-DAG: <<Invoke:i\d+>> InvokeStaticOrDirect method_name:OtherDex.recursiveCall
/// CHECK-DAG: Return [<<Invoke>>]
/// CHECK-START: int Main.dontInlineRecursiveCall() inliner (after)
- /// CHECK-DAG: <<Invoke:i\d+>> InvokeStaticOrDirect
+ /// CHECK-DAG: <<Invoke:i\d+>> InvokeStaticOrDirect method_name:OtherDex.recursiveCall
/// CHECK-DAG: Return [<<Invoke>>]
public static int dontInlineRecursiveCall() {
return OtherDex.recursiveCall();
}
- /// CHECK-START: java.lang.String Main.dontInlineReturnString() inliner (before)
- /// CHECK-DAG: <<Invoke:l\d+>> InvokeStaticOrDirect
+ /// CHECK-START: java.lang.String Main.inlineReturnString() inliner (before)
+ /// CHECK-DAG: <<Invoke:l\d+>> InvokeStaticOrDirect method_name:OtherDex.returnString
/// CHECK-DAG: Return [<<Invoke>>]
- /// CHECK-START: java.lang.String Main.dontInlineReturnString() inliner (after)
- /// CHECK-DAG: <<Invoke:l\d+>> InvokeStaticOrDirect
- /// CHECK-DAG: Return [<<Invoke>>]
+ /// CHECK-START: java.lang.String Main.inlineReturnString() inliner (after)
+ /// CHECK-NOT: InvokeStaticOrDirect method_name:OtherDex.returnString
- public static String dontInlineReturnString() {
+ public static String inlineReturnString() {
return OtherDex.returnString();
}
- /// CHECK-START: java.lang.Class Main.dontInlineOtherDexClass() inliner (before)
- /// CHECK-DAG: <<Invoke:l\d+>> InvokeStaticOrDirect
+ /// CHECK-START: java.lang.Class Main.inlineOtherDexClass() inliner (before)
+ /// CHECK-DAG: <<Invoke:l\d+>> InvokeStaticOrDirect method_name:OtherDex.returnOtherDexClass
/// CHECK-DAG: Return [<<Invoke>>]
- /// CHECK-START: java.lang.Class Main.dontInlineOtherDexClass() inliner (after)
- /// CHECK-DAG: <<Invoke:l\d+>> InvokeStaticOrDirect
- /// CHECK-DAG: Return [<<Invoke>>]
+ /// CHECK-START: java.lang.Class Main.inlineOtherDexClass() inliner (after)
+ /// CHECK-NOT: InvokeStaticOrDirect method_name:OtherDex.returnOtherDexClass
- public static Class<?> dontInlineOtherDexClass() {
+ public static Class<?> inlineOtherDexClass() {
return OtherDex.returnOtherDexClass();
}
@@ -127,15 +124,14 @@
return OtherDex.returnMainClass();
}
- /// CHECK-START: java.lang.Class Main.dontInlineOtherDexClassStaticCall() inliner (before)
- /// CHECK-DAG: <<Invoke:l\d+>> InvokeStaticOrDirect
+ /// CHECK-START: java.lang.Class Main.inlineOtherDexClassStaticCall() inliner (before)
+ /// CHECK-DAG: <<Invoke:l\d+>> InvokeStaticOrDirect method_name:OtherDex.returnOtherDexClassStaticCall
/// CHECK-DAG: Return [<<Invoke>>]
- /// CHECK-START: java.lang.Class Main.dontInlineOtherDexClassStaticCall() inliner (after)
- /// CHECK-DAG: <<Invoke:l\d+>> InvokeStaticOrDirect
- /// CHECK-DAG: Return [<<Invoke>>]
+ /// CHECK-START: java.lang.Class Main.inlineOtherDexClassStaticCall() inliner (after)
+ /// CHECK-NOT: InvokeStaticOrDirect method_name:OtherDex.returnOtherDexClassStaticCall
- public static Class<?> dontInlineOtherDexClassStaticCall() {
+ public static Class<?> inlineOtherDexClassStaticCall() {
return OtherDex.returnOtherDexClassStaticCall();
}
@@ -166,7 +162,7 @@
throw new Error("Expected 38");
}
- if (dontInlineOtherDexStatic() != 1) {
+ if (inlineOtherDexStatic() != 1) {
throw new Error("Expected 1");
}
@@ -174,15 +170,15 @@
throw new Error("Expected 42");
}
- if (dontInlineReturnString() != "OtherDex") {
+ if (inlineReturnString() != "OtherDex") {
throw new Error("Expected OtherDex");
}
- if (dontInlineOtherDexClass() != OtherDex.class) {
+ if (inlineOtherDexClass() != OtherDex.class) {
throw new Error("Expected " + OtherDex.class);
}
- if (dontInlineOtherDexClassStaticCall() != OtherDex.class) {
+ if (inlineOtherDexClassStaticCall() != OtherDex.class) {
throw new Error("Expected " + OtherDex.class);
}