diff options
author | Nicolas Geoffray <ngeoffray@google.com> | 2015-03-23 17:52:58 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2015-03-23 17:52:59 +0000 |
commit | d24ba2c44c76a2b2dd13aafe8f7981c15be31a98 (patch) | |
tree | 0e1d0813c1d8d1c7239a900c1653296975713df0 | |
parent | 90d480c26f7524f35323a11d6ba2880ff3db789a (diff) | |
parent | 7e4c3508e4f5512650b63c41f7872a749e99aee9 (diff) | |
download | android_art-d24ba2c44c76a2b2dd13aafe8f7981c15be31a98.tar.gz android_art-d24ba2c44c76a2b2dd13aafe8f7981c15be31a98.tar.bz2 android_art-d24ba2c44c76a2b2dd13aafe8f7981c15be31a98.zip |
Merge "Inline across dex files."
-rw-r--r-- | compiler/optimizing/builder.cc | 12 | ||||
-rw-r--r-- | compiler/optimizing/inliner.cc | 26 | ||||
-rw-r--r-- | compiler/optimizing/inliner.h | 3 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 6 | ||||
-rw-r--r-- | test/462-checker-inlining-across-dex-files/expected.txt | 0 | ||||
-rw-r--r-- | test/462-checker-inlining-across-dex-files/info.txt | 1 | ||||
-rw-r--r-- | test/462-checker-inlining-across-dex-files/src-multidex/OtherDex.java | 50 | ||||
-rw-r--r-- | test/462-checker-inlining-across-dex-files/src/Main.java | 139 | ||||
-rwxr-xr-x | test/etc/default-build | 13 |
9 files changed, 233 insertions, 17 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index ec7fd62975..cbb41b1837 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -616,8 +616,8 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction, DCHECK((optimized_invoke_type == invoke_type) || (optimized_invoke_type != kDirect) || compiler_driver_->GetCompilerOptions().GetCompilePic()); bool is_recursive = - (target_method.dex_method_index == outer_compilation_unit_->GetDexMethodIndex()); - DCHECK(!is_recursive || (target_method.dex_file == outer_compilation_unit_->GetDexFile())); + (target_method.dex_method_index == dex_compilation_unit_->GetDexMethodIndex()); + DCHECK(!is_recursive || (target_method.dex_file == dex_compilation_unit_->GetDexFile())); invoke = new (arena_) HInvokeStaticOrDirect( arena_, number_of_arguments, return_type, dex_pc, target_method.dex_method_index, is_recursive, optimized_invoke_type); @@ -711,7 +711,7 @@ bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction, uint16_t field_index = instruction.VRegB_21c(); ScopedObjectAccess soa(Thread::Current()); - StackHandleScope<4> hs(soa.Self()); + StackHandleScope<5> hs(soa.Self()); Handle<mirror::DexCache> dex_cache(hs.NewHandle( dex_compilation_unit_->GetClassLinker()->FindDexCache(*dex_compilation_unit_->GetDexFile()))); Handle<mirror::ClassLoader> class_loader(hs.NewHandle( @@ -724,8 +724,10 @@ bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction, return false; } + Handle<mirror::DexCache> outer_dex_cache(hs.NewHandle( + outer_compilation_unit_->GetClassLinker()->FindDexCache(*outer_compilation_unit_->GetDexFile()))); Handle<mirror::Class> referrer_class(hs.NewHandle(compiler_driver_->ResolveCompilingMethodsClass( - soa, dex_cache, class_loader, outer_compilation_unit_))); + soa, outer_dex_cache, class_loader, outer_compilation_unit_))); // The index at which the field's class is stored in the DexCache's type array. uint32_t storage_index; @@ -738,7 +740,7 @@ bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction, // TODO: find out why this check is needed. bool is_in_dex_cache = compiler_driver_->CanAssumeTypeIsPresentInDexCache( - *outer_compilation_unit_->GetDexFile(), storage_index); + *dex_compilation_unit_->GetDexFile(), storage_index); bool is_initialized = resolved_field->GetDeclaringClass()->IsInitialized() && is_in_dex_cache; bool is_referrer_class = (referrer_class.Get() == resolved_field->GetDeclaringClass()); diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 968fe3e73c..82d63573bc 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -85,11 +85,9 @@ bool HInliner::TryInline(HInvoke* invoke_instruction, return false; } + bool can_use_dex_cache = true; if (resolved_method->GetDexFile()->GetLocation().compare(outer_dex_file.GetLocation()) != 0) { - VLOG(compiler) << "Did not inline " - << PrettyMethod(method_index, outer_dex_file) - << " because it is in a different dex file"; - return false; + can_use_dex_cache = false; } const DexFile::CodeItem* code_item = resolved_method->GetCodeItem(); @@ -124,7 +122,7 @@ bool HInliner::TryInline(HInvoke* invoke_instruction, return false; } - if (!TryBuildAndInline(resolved_method, invoke_instruction, method_index)) { + if (!TryBuildAndInline(resolved_method, invoke_instruction, method_index, can_use_dex_cache)) { resolved_method->SetShouldNotInline(); return false; } @@ -136,7 +134,8 @@ bool HInliner::TryInline(HInvoke* invoke_instruction, bool HInliner::TryBuildAndInline(Handle<mirror::ArtMethod> resolved_method, HInvoke* invoke_instruction, - uint32_t method_index) const { + uint32_t method_index, + bool can_use_dex_cache) const { ScopedObjectAccess soa(Thread::Current()); const DexFile::CodeItem* code_item = resolved_method->GetCodeItem(); const DexFile& outer_dex_file = *outer_compilation_unit_.GetDexFile(); @@ -145,10 +144,10 @@ bool HInliner::TryBuildAndInline(Handle<mirror::ArtMethod> resolved_method, nullptr, outer_compilation_unit_.GetClassLoader(), outer_compilation_unit_.GetClassLinker(), - outer_dex_file, + *resolved_method->GetDexFile(), code_item, resolved_method->GetDeclaringClass()->GetDexClassDefIndex(), - method_index, + resolved_method->GetDexMethodIndex(), resolved_method->GetAccessFlags(), nullptr); @@ -159,7 +158,7 @@ bool HInliner::TryBuildAndInline(Handle<mirror::ArtMethod> resolved_method, HGraphBuilder builder(callee_graph, &dex_compilation_unit, &outer_compilation_unit_, - &outer_dex_file, + resolved_method->GetDexFile(), compiler_driver_, &inline_stats); @@ -200,7 +199,7 @@ bool HInliner::TryBuildAndInline(Handle<mirror::ArtMethod> resolved_method, if (depth_ + 1 < kDepthLimit) { HInliner inliner( - callee_graph, outer_compilation_unit_, compiler_driver_, stats_, depth_ + 1); + callee_graph, dex_compilation_unit, compiler_driver_, stats_, depth_ + 1); inliner.Run(); } @@ -235,6 +234,13 @@ bool HInliner::TryBuildAndInline(Handle<mirror::ArtMethod> resolved_method, << " needs an environment"; return false; } + + if (!can_use_dex_cache && current->NeedsDexCache()) { + VLOG(compiler) << "Method " << PrettyMethod(method_index, outer_dex_file) + << " could not be inlined because " << current->DebugName() + << " it is in a different dex file and requires access to the dex cache"; + return false; + } } } diff --git a/compiler/optimizing/inliner.h b/compiler/optimizing/inliner.h index 1251977138..4b7e2ff213 100644 --- a/compiler/optimizing/inliner.h +++ b/compiler/optimizing/inliner.h @@ -48,7 +48,8 @@ class HInliner : public HOptimization { bool TryInline(HInvoke* invoke_instruction, uint32_t method_index, InvokeType invoke_type) const; bool TryBuildAndInline(Handle<mirror::ArtMethod> resolved_method, HInvoke* invoke_instruction, - uint32_t method_index) const; + uint32_t method_index, + bool can_use_dex_cache) const; const DexCompilationUnit& outer_compilation_unit_; CompilerDriver* const compiler_driver_; diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index a35fa1d8c3..07ff8ba010 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -1200,6 +1200,8 @@ class HInstruction : public ArenaObject<kArenaAllocMisc> { return NeedsEnvironment() || IsLoadClass() || IsLoadString(); } + virtual bool NeedsDexCache() const { return false; } + protected: virtual const HUserRecord<HInstruction*> InputRecordAt(size_t i) const = 0; virtual void SetRawInputRecordAt(size_t index, const HUserRecord<HInstruction*>& input) = 0; @@ -2090,6 +2092,7 @@ class HInvokeStaticOrDirect : public HInvoke { InvokeType GetInvokeType() const { return invoke_type_; } bool IsRecursive() const { return is_recursive_; } + bool NeedsDexCache() const OVERRIDE { return !IsRecursive(); } DECLARE_INSTRUCTION(InvokeStaticOrDirect); @@ -2972,6 +2975,8 @@ class HLoadClass : public HExpression<0> { return loaded_class_rti_.IsExact(); } + bool NeedsDexCache() const OVERRIDE { return !is_referrers_class_; } + DECLARE_INSTRUCTION(LoadClass); private: @@ -3007,6 +3012,7 @@ class HLoadString : public HExpression<0> { // TODO: Can we deopt or debug when we resolve a string? bool NeedsEnvironment() const OVERRIDE { return false; } + bool NeedsDexCache() const OVERRIDE { return true; } DECLARE_INSTRUCTION(LoadString); diff --git a/test/462-checker-inlining-across-dex-files/expected.txt b/test/462-checker-inlining-across-dex-files/expected.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/462-checker-inlining-across-dex-files/expected.txt diff --git a/test/462-checker-inlining-across-dex-files/info.txt b/test/462-checker-inlining-across-dex-files/info.txt new file mode 100644 index 0000000000..57008c39e1 --- /dev/null +++ b/test/462-checker-inlining-across-dex-files/info.txt @@ -0,0 +1 @@ +Check our inlining heuristics across dex files in optimizing. diff --git a/test/462-checker-inlining-across-dex-files/src-multidex/OtherDex.java b/test/462-checker-inlining-across-dex-files/src-multidex/OtherDex.java new file mode 100644 index 0000000000..61f4e43706 --- /dev/null +++ b/test/462-checker-inlining-across-dex-files/src-multidex/OtherDex.java @@ -0,0 +1,50 @@ +/* +* Copyright (C) 2015 The Android Open Source Project +* +* 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. +*/ + +public class OtherDex { + public static void emptyMethod() { + } + + public static int returnIntMethod() { + return 38; + } + + public static int returnOtherDexStatic() { + return myStatic; + } + + public static int returnMainStatic() { + return Main.myStatic; + } + + public static int recursiveCall() { + return recursiveCall(); + } + + public static String returnString() { + return "OtherDex"; + } + + public static Class returnOtherDexClass() { + return OtherDex.class; + } + + public static Class returnMainClass() { + return Main.class; + } + + static int myStatic = 1; +} diff --git a/test/462-checker-inlining-across-dex-files/src/Main.java b/test/462-checker-inlining-across-dex-files/src/Main.java new file mode 100644 index 0000000000..23956c04b1 --- /dev/null +++ b/test/462-checker-inlining-across-dex-files/src/Main.java @@ -0,0 +1,139 @@ +/* +* Copyright (C) 2015 The Android Open Source Project +* +* 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. +*/ + +public class Main { + + // CHECK-START: void Main.inlineEmptyMethod() inliner (before) + // CHECK-DAG: [[Invoke:v\d+]] InvokeStaticOrDirect + // CHECK-DAG: ReturnVoid + + // CHECK-START: void Main.inlineEmptyMethod() inliner (after) + // CHECK-NOT: InvokeStaticOrDirect + + public static void inlineEmptyMethod() { + OtherDex.emptyMethod(); + } + + // CHECK-START: int Main.inlineReturnIntMethod() inliner (before) + // CHECK-DAG: [[Invoke:i\d+]] InvokeStaticOrDirect + // CHECK-DAG: Return [ [[Invoke]] ] + + // CHECK-START: int Main.inlineReturnIntMethod() inliner (after) + // CHECK-NOT: InvokeStaticOrDirect + + // CHECK-START: int Main.inlineReturnIntMethod() inliner (after) + // CHECK-DAG: [[Const38:i\d+]] IntConstant 38 + // CHECK-DAG: Return [ [[Const38]] ] + + public static int inlineReturnIntMethod() { + return OtherDex.returnIntMethod(); + } + + // CHECK-START: int Main.dontInlineOtherDexStatic() inliner (before) + // CHECK-DAG: [[Invoke:i\d+]] InvokeStaticOrDirect + // CHECK-DAG: Return [ [[Invoke]] ] + + // CHECK-START: int Main.dontInlineOtherDexStatic() inliner (after) + // CHECK-DAG: [[Invoke:i\d+]] InvokeStaticOrDirect + // CHECK-DAG: Return [ [[Invoke]] ] + public static int dontInlineOtherDexStatic() { + return OtherDex.returnOtherDexStatic(); + } + + // CHECK-START: int Main.inlineMainStatic() inliner (before) + // CHECK-DAG: [[Invoke:i\d+]] InvokeStaticOrDirect + // CHECK-DAG: Return [ [[Invoke]] ] + + // CHECK-START: int Main.inlineMainStatic() inliner (after) + // CHECK-DAG: [[Static:i\d+]] StaticFieldGet + // CHECK-DAG: Return [ [[Static]] ] + public static int inlineMainStatic() { + return OtherDex.returnMainStatic(); + } + + // CHECK-START: int Main.dontInlineRecursiveCall() inliner (before) + // CHECK-DAG: [[Invoke:i\d+]] InvokeStaticOrDirect + // CHECK-DAG: Return [ [[Invoke]] ] + + // CHECK-START: int Main.dontInlineRecursiveCall() inliner (after) + // CHECK-DAG: [[Invoke:i\d+]] InvokeStaticOrDirect + // 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-DAG: Return [ [[Invoke]] ] + + // CHECK-START: java.lang.String Main.dontInlineReturnString() inliner (after) + // CHECK-DAG: [[Invoke:l\d+]] InvokeStaticOrDirect + // CHECK-DAG: Return [ [[Invoke]] ] + public static String dontInlineReturnString() { + return OtherDex.returnString(); + } + + // CHECK-START: java.lang.Class Main.dontInlineOtherDexClass() inliner (before) + // CHECK-DAG: [[Invoke:l\d+]] InvokeStaticOrDirect + // CHECK-DAG: Return [ [[Invoke]] ] + + // CHECK-START: java.lang.Class Main.dontInlineOtherDexClass() inliner (after) + // CHECK-DAG: [[Invoke:l\d+]] InvokeStaticOrDirect + // CHECK-DAG: Return [ [[Invoke]] ] + public static Class dontInlineOtherDexClass() { + return OtherDex.returnOtherDexClass(); + } + + // CHECK-START: java.lang.Class Main.inlineMainClass() inliner (before) + // CHECK-DAG: [[Invoke:l\d+]] InvokeStaticOrDirect + // CHECK-DAG: Return [ [[Invoke]] ] + + // CHECK-START: java.lang.Class Main.inlineMainClass() inliner (after) + // CHECK-DAG: [[Class:l\d+]] LoadClass + // CHECK-DAG: Return [ [[Class]] ] + public static Class inlineMainClass() { + return OtherDex.returnMainClass(); + } + + public static void main(String[] args) { + inlineEmptyMethod(); + if (inlineReturnIntMethod() != 38) { + throw new Error("Expected 38"); + } + + if (dontInlineOtherDexStatic() != 1) { + throw new Error("Expected 1"); + } + + if (inlineMainStatic() != 42) { + throw new Error("Expected 42"); + } + + if (dontInlineReturnString() != "OtherDex") { + throw new Error("Expected OtherDex"); + } + + if (dontInlineOtherDexClass() != OtherDex.class) { + throw new Error("Expected " + OtherDex.class); + } + + if (inlineMainClass() != Main.class) { + throw new Error("Expected " + Main.class); + } + } + + public static int myStatic = 42; +} diff --git a/test/etc/default-build b/test/etc/default-build index 58c9564bab..928de575a3 100755 --- a/test/etc/default-build +++ b/test/etc/default-build @@ -39,7 +39,7 @@ if [ -e classes.dex ]; then fi mkdir classes -${JAVAC} -d classes `find src -name '*.java'` +${JAVAC} -implicit:none -classpath src-multidex -d classes `find src -name '*.java'` if [ -d src2 ]; then ${JAVAC} -d classes `find src2 -name '*.java'` @@ -75,3 +75,14 @@ fi if [ ${NEED_DEX} = "true" ]; then zip $TEST_NAME.jar classes.dex fi + +# Create a single jar with two dex files for multidex. +if [ -d src-multidex ]; then + mkdir classes2 + ${JAVAC} -implicit:none -classpath src -d classes2 `find src-multidex -name '*.java'` + if [ ${NEED_DEX} = "true" ]; then + ${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex \ + --dump-width=1000 ${DX_FLAGS} classes2 + zip $TEST_NAME.jar classes.dex classes2.dex + fi +fi |