summaryrefslogtreecommitdiffstats
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/Android.mk5
-rw-r--r--compiler/dex/frontend.cc15
-rw-r--r--compiler/dex/frontend.h16
-rw-r--r--compiler/dex/quick/arm/arm_dex_file_method_inliner.cc103
-rw-r--r--compiler/dex/quick/arm/arm_dex_file_method_inliner.h37
-rw-r--r--compiler/dex/quick/codegen_util.cc3
-rw-r--r--compiler/dex/quick/dex_file_method_inliner.cc346
-rw-r--r--compiler/dex/quick/dex_file_method_inliner.h318
-rw-r--r--compiler/dex/quick/dex_file_to_method_inliner_map.cc79
-rw-r--r--compiler/dex/quick/dex_file_to_method_inliner_map.h53
-rw-r--r--compiler/dex/quick/gen_invoke.cc204
-rw-r--r--compiler/dex/quick/mips/mips_dex_file_method_inliner.cc103
-rw-r--r--compiler/dex/quick/mips/mips_dex_file_method_inliner.h37
-rw-r--r--compiler/dex/quick/mir_to_lir.h4
-rw-r--r--compiler/dex/quick/x86/x86_dex_file_method_inliner.cc109
-rw-r--r--compiler/dex/quick/x86/x86_dex_file_method_inliner.h37
16 files changed, 1271 insertions, 198 deletions
diff --git a/compiler/Android.mk b/compiler/Android.mk
index fc2f02b59e..b7dc9f6c3b 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -23,6 +23,7 @@ LIBART_COMPILER_SRC_FILES := \
dex/local_value_numbering.cc \
dex/arena_allocator.cc \
dex/arena_bit_vector.cc \
+ dex/quick/arm/arm_dex_file_method_inliner.cc \
dex/quick/arm/assemble_arm.cc \
dex/quick/arm/call_arm.cc \
dex/quick/arm/fp_arm.cc \
@@ -30,6 +31,8 @@ LIBART_COMPILER_SRC_FILES := \
dex/quick/arm/target_arm.cc \
dex/quick/arm/utility_arm.cc \
dex/quick/codegen_util.cc \
+ dex/quick/dex_file_method_inliner.cc \
+ dex/quick/dex_file_to_method_inliner_map.cc \
dex/quick/gen_common.cc \
dex/quick/gen_invoke.cc \
dex/quick/gen_loadstore.cc \
@@ -38,6 +41,7 @@ LIBART_COMPILER_SRC_FILES := \
dex/quick/mips/call_mips.cc \
dex/quick/mips/fp_mips.cc \
dex/quick/mips/int_mips.cc \
+ dex/quick/mips/mips_dex_file_method_inliner.cc \
dex/quick/mips/target_mips.cc \
dex/quick/mips/utility_mips.cc \
dex/quick/mir_to_lir.cc \
@@ -48,6 +52,7 @@ LIBART_COMPILER_SRC_FILES := \
dex/quick/x86/int_x86.cc \
dex/quick/x86/target_x86.cc \
dex/quick/x86/utility_x86.cc \
+ dex/quick/x86/x86_dex_file_method_inliner.cc \
dex/portable/mir_to_gbc.cc \
dex/dex_to_dex_compiler.cc \
dex/mir_dataflow.cc \
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc
index 3dc1914c30..b6e062e413 100644
--- a/compiler/dex/frontend.cc
+++ b/compiler/dex/frontend.cc
@@ -31,6 +31,8 @@
#include "llvm/llvm_compilation_unit.h"
#endif
+#include "dex/quick/dex_file_to_method_inliner_map.h"
+
namespace {
#if !defined(ART_USE_PORTABLE_COMPILER)
pthread_once_t llvm_multi_init = PTHREAD_ONCE_INIT;
@@ -61,14 +63,21 @@ LLVMInfo::LLVMInfo() {
LLVMInfo::~LLVMInfo() {
}
+QuickCompilerContext::QuickCompilerContext(CompilerDriver& compiler)
+ : inliner_map_(new DexFileToMethodInlinerMap(&compiler))
+{
+}
+
+QuickCompilerContext::~QuickCompilerContext() {
+}
+
extern "C" void ArtInitQuickCompilerContext(art::CompilerDriver& compiler) {
CHECK(compiler.GetCompilerContext() == NULL);
- LLVMInfo* llvm_info = new LLVMInfo();
- compiler.SetCompilerContext(llvm_info);
+ compiler.SetCompilerContext(new QuickCompilerContext(compiler));
}
extern "C" void ArtUnInitQuickCompilerContext(art::CompilerDriver& compiler) {
- delete reinterpret_cast<LLVMInfo*>(compiler.GetCompilerContext());
+ delete reinterpret_cast<QuickCompilerContext*>(compiler.GetCompilerContext());
compiler.SetCompilerContext(NULL);
}
diff --git a/compiler/dex/frontend.h b/compiler/dex/frontend.h
index b9b4178890..b6e8577fdf 100644
--- a/compiler/dex/frontend.h
+++ b/compiler/dex/frontend.h
@@ -82,6 +82,9 @@ enum debugControlVector {
kDebugTimings
};
+class DexFileToMethodInlinerMap;
+class CompilerDriver;
+
class LLVMInfo {
public:
LLVMInfo();
@@ -110,6 +113,19 @@ class LLVMInfo {
UniquePtr<art::llvm::IRBuilder> ir_builder_;
};
+class QuickCompilerContext {
+ public:
+ QuickCompilerContext(CompilerDriver& compiler);
+ ~QuickCompilerContext();
+
+ DexFileToMethodInlinerMap* GetInlinerMap() {
+ return inliner_map_.get();
+ }
+
+ private:
+ UniquePtr<DexFileToMethodInlinerMap> inliner_map_;
+};
+
struct CompilationUnit;
struct BasicBlock;
diff --git a/compiler/dex/quick/arm/arm_dex_file_method_inliner.cc b/compiler/dex/quick/arm/arm_dex_file_method_inliner.cc
new file mode 100644
index 0000000000..a8ae3cd72c
--- /dev/null
+++ b/compiler/dex/quick/arm/arm_dex_file_method_inliner.cc
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "dex/compiler_enums.h"
+
+#include "arm_dex_file_method_inliner.h"
+
+namespace art {
+
+const DexFileMethodInliner::IntrinsicDef ArmDexFileMethodInliner::kIntrinsicMethods[] = {
+#define INTRINSIC(c, n, p, o, d) \
+ { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, d } }
+
+ INTRINSIC(JavaLangDouble, DoubleToRawLongBits, D_J, kIntrinsicDoubleCvt, 0),
+ INTRINSIC(JavaLangDouble, LongBitsToDouble, J_D, kIntrinsicDoubleCvt, 0),
+ INTRINSIC(JavaLangFloat, FloatToRawIntBits, F_I, kIntrinsicFloatCvt, 0),
+ INTRINSIC(JavaLangFloat, IntBitsToFloat, I_F, kIntrinsicFloatCvt, 0),
+
+ INTRINSIC(JavaLangInteger, ReverseBytes, I_I, kIntrinsicReverseBytes, kWord),
+ INTRINSIC(JavaLangLong, ReverseBytes, J_J, kIntrinsicReverseBytes, kLong),
+ INTRINSIC(JavaLangShort, ReverseBytes, S_S, kIntrinsicReverseBytes, kSignedHalf),
+
+ INTRINSIC(JavaLangMath, Abs, I_I, kIntrinsicAbsInt, 0),
+ INTRINSIC(JavaLangStrictMath, Abs, I_I, kIntrinsicAbsInt, 0),
+ INTRINSIC(JavaLangMath, Abs, J_J, kIntrinsicAbsLong, 0),
+ INTRINSIC(JavaLangStrictMath, Abs, J_J, kIntrinsicAbsLong, 0),
+ INTRINSIC(JavaLangMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
+ INTRINSIC(JavaLangStrictMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
+ INTRINSIC(JavaLangMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
+ INTRINSIC(JavaLangStrictMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
+ INTRINSIC(JavaLangMath, Sqrt, D_D, kIntrinsicSqrt, 0),
+ INTRINSIC(JavaLangStrictMath, Sqrt, D_D, kIntrinsicSqrt, 0),
+
+ INTRINSIC(JavaLangString, CharAt, I_C, kIntrinsicCharAt, 0),
+ INTRINSIC(JavaLangString, CompareTo, String_I, kIntrinsicCompareTo, 0),
+ INTRINSIC(JavaLangString, IsEmpty, _Z, kIntrinsicIsEmptyOrLength, kIntrinsicFlagIsEmpty),
+ INTRINSIC(JavaLangString, IndexOf, II_I, kIntrinsicIndexOf, kIntrinsicFlagNone),
+ INTRINSIC(JavaLangString, IndexOf, I_I, kIntrinsicIndexOf, kIntrinsicFlagBase0),
+ INTRINSIC(JavaLangString, Length, _I, kIntrinsicIsEmptyOrLength, kIntrinsicFlagLength),
+
+ INTRINSIC(JavaLangThread, CurrentThread, _Thread, kIntrinsicCurrentThread, 0),
+
+ INTRINSIC(LibcoreIoMemory, PeekByte, J_B, kIntrinsicPeek, kSignedByte),
+ INTRINSIC(LibcoreIoMemory, PeekIntNative, J_I, kIntrinsicPeek, kWord),
+ INTRINSIC(LibcoreIoMemory, PeekLongNative, J_J, kIntrinsicPeek, kLong),
+ INTRINSIC(LibcoreIoMemory, PeekShortNative, J_S, kIntrinsicPeek, kSignedHalf),
+ INTRINSIC(LibcoreIoMemory, PokeByte, JB_V, kIntrinsicPoke, kSignedByte),
+ INTRINSIC(LibcoreIoMemory, PokeIntNative, JI_V, kIntrinsicPoke, kWord),
+ INTRINSIC(LibcoreIoMemory, PokeLongNative, JJ_V, kIntrinsicPoke, kLong),
+ INTRINSIC(LibcoreIoMemory, PokeShortNative, JS_V, kIntrinsicPoke, kSignedHalf),
+
+ INTRINSIC(SunMiscUnsafe, CompareAndSwapInt, ObjectJII_Z, kIntrinsicCas32,
+ kIntrinsicFlagDontNeedWriteBarrier),
+ INTRINSIC(SunMiscUnsafe, CompareAndSwapObject, ObjectJObjectObject_Z, kIntrinsicCas32,
+ kIntrinsicFlagNeedWriteBarrier),
+
+#define UNSAFE_GET_PUT(type, code, type_flags) \
+ INTRINSIC(SunMiscUnsafe, Get ## type, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
+ type_flags & ~kIntrinsicFlagIsObject), \
+ INTRINSIC(SunMiscUnsafe, Get ## type ## Volatile, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
+ (type_flags | kIntrinsicFlagIsVolatile) & ~kIntrinsicFlagIsObject), \
+ INTRINSIC(SunMiscUnsafe, Put ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
+ type_flags), \
+ INTRINSIC(SunMiscUnsafe, Put ## type ## Volatile, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
+ type_flags | kIntrinsicFlagIsVolatile), \
+ INTRINSIC(SunMiscUnsafe, PutOrdered ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
+ type_flags | kIntrinsicFlagIsOrdered)
+
+ UNSAFE_GET_PUT(Int, I, kIntrinsicFlagNone),
+ UNSAFE_GET_PUT(Long, J, kIntrinsicFlagIsLong),
+ UNSAFE_GET_PUT(Object, Object, kIntrinsicFlagIsObject),
+#undef UNSAFE_GET_PUT
+
+#undef INTRINSIC
+};
+
+ArmDexFileMethodInliner::ArmDexFileMethodInliner() {
+}
+
+ArmDexFileMethodInliner::~ArmDexFileMethodInliner() {
+}
+
+void ArmDexFileMethodInliner::FindIntrinsics(const DexFile* dex_file) {
+ IndexCache cache;
+ DoFindIntrinsics(dex_file, &cache, kIntrinsicMethods, arraysize(kIntrinsicMethods));
+}
+
+} // namespace art
diff --git a/compiler/dex/quick/arm/arm_dex_file_method_inliner.h b/compiler/dex/quick/arm/arm_dex_file_method_inliner.h
new file mode 100644
index 0000000000..3428391624
--- /dev/null
+++ b/compiler/dex/quick/arm/arm_dex_file_method_inliner.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef ART_COMPILER_DEX_QUICK_ARM_ARM_DEX_FILE_METHOD_INLINER_H_
+#define ART_COMPILER_DEX_QUICK_ARM_ARM_DEX_FILE_METHOD_INLINER_H_
+
+#include "dex/quick/dex_file_method_inliner.h"
+
+namespace art {
+
+class ArmDexFileMethodInliner : public DexFileMethodInliner {
+ public:
+ ArmDexFileMethodInliner();
+ ~ArmDexFileMethodInliner();
+
+ void FindIntrinsics(const DexFile* dex_file);
+
+ private:
+ static const IntrinsicDef kIntrinsicMethods[];
+};
+
+} // namespace art
+
+#endif // ART_COMPILER_DEX_QUICK_ARM_ARM_DEX_FILE_METHOD_INLINER_H_
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index dfbc887299..4bc0b357af 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -920,7 +920,8 @@ Mir2Lir::Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena
core_spill_mask_(0),
fp_spill_mask_(0),
first_lir_insn_(NULL),
- last_lir_insn_(NULL) {
+ last_lir_insn_(NULL),
+ inliner_(nullptr) {
promotion_map_ = static_cast<PromotionMap*>
(arena_->Alloc((cu_->num_dalvik_registers + cu_->num_compiler_temps + 1) *
sizeof(promotion_map_[0]), ArenaAllocator::kAllocRegAlloc));
diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc
new file mode 100644
index 0000000000..c962e9df93
--- /dev/null
+++ b/compiler/dex/quick/dex_file_method_inliner.cc
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#include <algorithm>
+#include "base/macros.h"
+#include "dex/mir_graph.h"
+
+#include "dex_file_method_inliner.h"
+
+namespace art {
+
+const char* DexFileMethodInliner::kClassCacheNames[] = {
+ "Z", // kClassCacheBoolean
+ "B", // kClassCacheByte
+ "C", // kClassCacheChar
+ "S", // kClassCacheShort
+ "I", // kClassCacheInt
+ "J", // kClassCacheLong
+ "F", // kClassCacheFloat
+ "D", // kClassCacheDouble
+ "V", // kClassCacheVoid
+ "Ljava/lang/Object;", // kClassCacheJavaLangObject
+ "Ljava/lang/String;", // kClassCacheJavaLangString
+ "Ljava/lang/Double;", // kClassCacheJavaLangDouble
+ "Ljava/lang/Float;", // kClassCacheJavaLangFloat
+ "Ljava/lang/Integer;", // kClassCacheJavaLangInteger
+ "Ljava/lang/Long;", // kClassCacheJavaLangLong
+ "Ljava/lang/Short;", // kClassCacheJavaLangShort
+ "Ljava/lang/Math;", // kClassCacheJavaLangMath
+ "Ljava/lang/StrictMath;", // kClassCacheJavaLangStrictMath
+ "Ljava/lang/Thread;", // kClassCacheJavaLangThread
+ "Llibcore/io/Memory;", // kClassCacheLibcoreIoMemory
+ "Lsun/misc/Unsafe;", // kClassCacheSunMiscUnsafe
+};
+
+const char* DexFileMethodInliner::kNameCacheNames[] = {
+ "reverseBytes", // kNameCacheReverseBytes
+ "doubleToRawLongBits", // kNameCacheDoubleToRawLongBits
+ "longBitsToDouble", // kNameCacheLongBitsToDouble
+ "floatToRawIntBits", // kNameCacheFloatToRawIntBits
+ "intBitsToFloat", // kNameCacheIntBitsToFloat
+ "abs", // kNameCacheAbs
+ "max", // kNameCacheMax
+ "min", // kNameCacheMin
+ "sqrt", // kNameCacheSqrt
+ "charAt", // kNameCacheCharAt
+ "compareTo", // kNameCacheCompareTo
+ "is_empty", // kNameCacheIsEmpty
+ "index_of", // kNameCacheIndexOf
+ "length", // kNameCacheLength
+ "currentThread", // kNameCacheCurrentThread
+ "peekByte", // kNameCachePeekByte
+ "peekIntNative", // kNameCachePeekIntNative
+ "peekLongNative", // kNameCachePeekLongNative
+ "peekShortNative", // kNameCachePeekShortNative
+ "pokeByte", // kNameCachePokeByte
+ "pokeIntNative", // kNameCachePokeIntNative
+ "pokeLongNative", // kNameCachePokeLongNative
+ "pokeShortNative", // kNameCachePokeShortNative
+ "compareAndSwapInt", // kNameCacheCompareAndSwapInt
+ "compareAndSwapObject", // kNameCacheCompareAndSwapObject
+ "getInt", // kNameCacheGetInt
+ "getIntVolatile", // kNameCacheGetIntVolatile
+ "putInt", // kNameCachePutInt
+ "putIntVolatile", // kNameCachePutIntVolatile
+ "putOrderedInt", // kNameCachePutOrderedInt
+ "getLong", // kNameCacheGetLong
+ "getLongVolatile", // kNameCacheGetLongVolatile
+ "putLong", // kNameCachePutLong
+ "putLongVolatile", // kNameCachePutLongVolatile
+ "putOrderedLong", // kNameCachePutOrderedLong
+ "getObject", // kNameCacheGetObject
+ "getObjectVolatile", // kNameCacheGetObjectVolatile
+ "putObject", // kNameCachePutObject
+ "putObjectVolatile", // kNameCachePutObjectVolatile
+ "putOrderedObject", // kNameCachePutOrderedObject
+};
+
+const DexFileMethodInliner::ProtoDef DexFileMethodInliner::kProtoCacheDefs[] = {
+ // kProtoCacheI_I
+ { kClassCacheInt, 1, { kClassCacheInt } },
+ // kProtoCacheJ_J
+ { kClassCacheLong, 1, { kClassCacheLong } },
+ // kProtoCacheS_S
+ { kClassCacheShort, 1, { kClassCacheShort } },
+ // kProtoCacheD_D
+ { kClassCacheDouble, 1, { kClassCacheDouble } },
+ // kProtoCacheD_J
+ { kClassCacheLong, 1, { kClassCacheDouble } },
+ // kProtoCacheJ_D
+ { kClassCacheDouble, 1, { kClassCacheLong } },
+ // kProtoCacheF_I
+ { kClassCacheInt, 1, { kClassCacheFloat } },
+ // kProtoCacheI_F
+ { kClassCacheFloat, 1, { kClassCacheInt } },
+ // kProtoCacheII_I
+ { kClassCacheInt, 2, { kClassCacheInt, kClassCacheInt } },
+ // kProtoCacheI_C
+ { kClassCacheChar, 1, { kClassCacheInt } },
+ // kProtoCacheString_I
+ { kClassCacheInt, 1, { kClassCacheJavaLangString } },
+ // kProtoCache_Z
+ { kClassCacheBoolean, 0, { } },
+ // kProtoCache_I
+ { kClassCacheInt, 0, { } },
+ // kProtoCache_Thread
+ { kClassCacheJavaLangThread, 0, { } },
+ // kProtoCacheJ_B
+ { kClassCacheByte, 1, { kClassCacheLong } },
+ // kProtoCacheJ_I
+ { kClassCacheInt, 1, { kClassCacheLong } },
+ // kProtoCacheJ_S
+ { kClassCacheShort, 1, { kClassCacheLong } },
+ // kProtoCacheJB_V
+ { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheByte } },
+ // kProtoCacheJI_V
+ { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheInt } },
+ // kProtoCacheJJ_V
+ { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheLong } },
+ // kProtoCacheJS_V
+ { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheShort } },
+ // kProtoCacheObjectJII_Z
+ { kClassCacheBoolean, 4, { kClassCacheJavaLangObject, kClassCacheLong,
+ kClassCacheInt, kClassCacheInt } },
+ // kProtoCacheObjectJObjectObject_Z
+ { kClassCacheBoolean, 4, { kClassCacheJavaLangObject, kClassCacheLong,
+ kClassCacheJavaLangObject, kClassCacheJavaLangObject } },
+ // kProtoCacheObjectJ_I
+ { kClassCacheInt, 2, { kClassCacheJavaLangObject, kClassCacheLong } },
+ // kProtoCacheObjectJI_V
+ { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheInt } },
+ // kProtoCacheObjectJ_J
+ { kClassCacheLong, 2, { kClassCacheJavaLangObject, kClassCacheLong } },
+ // kProtoCacheObjectJJ_V
+ { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheLong } },
+ // kProtoCacheObjectJ_Object
+ { kClassCacheJavaLangObject, 2, { kClassCacheJavaLangObject, kClassCacheLong } },
+ // kProtoCacheObjectJObject_V
+ { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong,
+ kClassCacheJavaLangObject } },
+};
+
+DexFileMethodInliner::~DexFileMethodInliner() {
+}
+
+DexFileMethodInliner::DexFileMethodInliner()
+ : dex_file_(NULL)
+{
+ COMPILE_ASSERT(kClassCacheFirst == 0, kClassCacheFirst_not_0);
+ COMPILE_ASSERT(arraysize(kClassCacheNames) == kClassCacheLast, bad_arraysize_kClassCacheNames);
+ COMPILE_ASSERT(kNameCacheFirst == 0, kNameCacheFirst_not_0);
+ COMPILE_ASSERT(arraysize(kNameCacheNames) == kNameCacheLast, bad_arraysize_kNameCacheNames);
+ COMPILE_ASSERT(kProtoCacheFirst == 0, kProtoCacheFirst_not_0);
+ COMPILE_ASSERT(arraysize(kProtoCacheDefs) == kProtoCacheLast, bad_arraysize_kProtoCacheNames);
+}
+
+bool DexFileMethodInliner::IsIntrinsic(uint32_t method_index) const {
+ return intrinsics_.find(method_index) != intrinsics_.end();
+}
+
+bool DexFileMethodInliner::GenIntrinsic(Mir2Lir* backend, CallInfo* info) const {
+ auto it = intrinsics_.find(info->index);
+ if (it == intrinsics_.end()) {
+ return false;
+ }
+ const Intrinsic& intrinsic = it->second;
+ switch (intrinsic.opcode) {
+ case kIntrinsicDoubleCvt:
+ return backend->GenInlinedDoubleCvt(info);
+ case kIntrinsicFloatCvt:
+ return backend->GenInlinedFloatCvt(info);
+ case kIntrinsicReverseBytes:
+ return backend->GenInlinedReverseBytes(info, static_cast<OpSize>(intrinsic.data));
+ case kIntrinsicAbsInt:
+ return backend->GenInlinedAbsInt(info);
+ case kIntrinsicAbsLong:
+ return backend->GenInlinedAbsLong(info);
+ case kIntrinsicMinMaxInt:
+ return backend->GenInlinedMinMaxInt(info, intrinsic.data & kIntrinsicFlagMin);
+ case kIntrinsicSqrt:
+ return backend->GenInlinedSqrt(info);
+ case kIntrinsicCharAt:
+ return backend->GenInlinedCharAt(info);
+ case kIntrinsicCompareTo:
+ return backend->GenInlinedStringCompareTo(info);
+ case kIntrinsicIsEmptyOrLength:
+ return backend->GenInlinedStringIsEmptyOrLength(info, intrinsic.data & kIntrinsicFlagIsEmpty);
+ case kIntrinsicIndexOf:
+ return backend->GenInlinedIndexOf(info, intrinsic.data & kIntrinsicFlagBase0);
+ case kIntrinsicCurrentThread:
+ return backend->GenInlinedCurrentThread(info);
+ case kIntrinsicPeek:
+ return backend->GenInlinedPeek(info, static_cast<OpSize>(intrinsic.data));
+ case kIntrinsicPoke:
+ return backend->GenInlinedPoke(info, static_cast<OpSize>(intrinsic.data));
+ case kIntrinsicCas32:
+ return backend->GenInlinedCas32(info, intrinsic.data & kIntrinsicFlagNeedWriteBarrier);
+ case kIntrinsicUnsafeGet:
+ return backend->GenInlinedUnsafeGet(info, intrinsic.data & kIntrinsicFlagIsLong,
+ intrinsic.data & kIntrinsicFlagIsVolatile);
+ case kIntrinsicUnsafePut:
+ return backend->GenInlinedUnsafePut(info, intrinsic.data & kIntrinsicFlagIsLong,
+ intrinsic.data & kIntrinsicFlagIsObject,
+ intrinsic.data & kIntrinsicFlagIsVolatile,
+ intrinsic.data & kIntrinsicFlagIsOrdered);
+ default:
+ LOG(FATAL) << "Unexpected intrinsic opcode: " << intrinsic.opcode;
+ return false; // avoid warning "control reaches end of non-void function"
+ }
+}
+
+uint32_t DexFileMethodInliner::FindClassIndex(const DexFile* dex_file, IndexCache* cache,
+ ClassCacheIndex index) {
+ uint32_t* class_index = &cache->class_indexes[index];
+ if (*class_index != kIndexUnresolved) {
+ return *class_index;
+ }
+
+ const DexFile::StringId* string_id = dex_file->FindStringId(kClassCacheNames[index]);
+ if (string_id == nullptr) {
+ *class_index = kIndexNotFound;
+ return *class_index;
+ }
+ uint32_t string_index = dex_file->GetIndexForStringId(*string_id);
+
+ const DexFile::TypeId* type_id = dex_file->FindTypeId(string_index);
+ if (type_id == nullptr) {
+ *class_index = kIndexNotFound;
+ return *class_index;
+ }
+ *class_index = dex_file->GetIndexForTypeId(*type_id);
+ return *class_index;
+}
+
+uint32_t DexFileMethodInliner::FindNameIndex(const DexFile* dex_file, IndexCache* cache,
+ NameCacheIndex index) {
+ uint32_t* name_index = &cache->name_indexes[index];
+ if (*name_index != kIndexUnresolved) {
+ return *name_index;
+ }
+
+ const DexFile::StringId* string_id = dex_file->FindStringId(kNameCacheNames[index]);
+ if (string_id == nullptr) {
+ *name_index = kIndexNotFound;
+ return *name_index;
+ }
+ *name_index = dex_file->GetIndexForStringId(*string_id);
+ return *name_index;
+}
+
+uint32_t DexFileMethodInliner::FindProtoIndex(const DexFile* dex_file, IndexCache* cache,
+ ProtoCacheIndex index) {
+ uint32_t* proto_index = &cache->proto_indexes[index];
+ if (*proto_index != kIndexUnresolved) {
+ return *proto_index;
+ }
+
+ const ProtoDef& proto_def = kProtoCacheDefs[index];
+ uint32_t return_index = FindClassIndex(dex_file, cache, proto_def.return_type);
+ if (return_index == kIndexNotFound) {
+ *proto_index = kIndexNotFound;
+ return *proto_index;
+ }
+ uint16_t return_type = static_cast<uint16_t>(return_index);
+ DCHECK_EQ(static_cast<uint32_t>(return_type), return_index);
+
+ uint32_t signature_length = proto_def.param_count;
+ uint16_t signature_type_idxs[kProtoMaxParams];
+ for (uint32_t i = 0; i != signature_length; ++i) {
+ uint32_t param_index = FindClassIndex(dex_file, cache, proto_def.params[i]);
+ if (param_index == kIndexNotFound) {
+ *proto_index = kIndexNotFound;
+ return *proto_index;
+ }
+ signature_type_idxs[i] = static_cast<uint16_t>(param_index);
+ DCHECK_EQ(static_cast<uint32_t>(signature_type_idxs[i]), param_index);
+ }
+
+ const DexFile::ProtoId* proto_id = dex_file->FindProtoId(return_type, signature_type_idxs,
+ signature_length);
+ if (proto_id == nullptr) {
+ *proto_index = kIndexNotFound;
+ return *proto_index;
+ }
+ *proto_index = dex_file->GetIndexForProtoId(*proto_id);
+ return *proto_index;
+}
+
+uint32_t DexFileMethodInliner::FindMethodIndex(const DexFile* dex_file, IndexCache* cache,
+ const MethodDef& method_def) {
+ uint32_t declaring_class_index = FindClassIndex(dex_file, cache, method_def.declaring_class);
+ if (declaring_class_index == kIndexNotFound) {
+ return kIndexNotFound;
+ }
+ uint32_t name_index = FindNameIndex(dex_file, cache, method_def.name);
+ if (name_index == kIndexNotFound) {
+ return kIndexNotFound;
+ }
+ uint32_t proto_index = FindProtoIndex(dex_file, cache, method_def.proto);
+ if (proto_index == kIndexNotFound) {
+ return kIndexNotFound;
+ }
+ const DexFile::MethodId* method_id =
+ dex_file->FindMethodId(dex_file->GetTypeId(declaring_class_index),
+ dex_file->GetStringId(name_index),
+ dex_file->GetProtoId(proto_index));
+ if (method_id == nullptr) {
+ return kIndexNotFound;
+ }
+ return dex_file->GetIndexForMethodId(*method_id);
+}
+
+DexFileMethodInliner::IndexCache::IndexCache() {
+ std::fill_n(class_indexes, arraysize(class_indexes), kIndexUnresolved);
+ std::fill_n(name_indexes, arraysize(name_indexes), kIndexUnresolved);
+ std::fill_n(proto_indexes, arraysize(proto_indexes), kIndexUnresolved);
+}
+
+void DexFileMethodInliner::DoFindIntrinsics(const DexFile* dex_file, IndexCache* cache,
+ const IntrinsicDef* defs, uint32_t def_count) {
+ DCHECK(dex_file != nullptr);
+ DCHECK(dex_file_ == nullptr);
+ for (uint32_t i = 0u; i != def_count; ++i) {
+ uint32_t method_id = FindMethodIndex(dex_file, cache, defs[i].method_def);
+ if (method_id != kIndexNotFound) {
+ DCHECK(intrinsics_.find(method_id) == intrinsics_.end());
+ intrinsics_[method_id] = defs[i].intrinsic;
+ }
+ }
+ dex_file_ = dex_file;
+}
+
+} // namespace art
diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h
new file mode 100644
index 0000000000..95b8dd3adf
--- /dev/null
+++ b/compiler/dex/quick/dex_file_method_inliner.h
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef ART_COMPILER_DEX_QUICK_DEX_FILE_METHOD_INLINER_H_
+#define ART_COMPILER_DEX_QUICK_DEX_FILE_METHOD_INLINER_H_
+
+#include <stdint.h>
+#include <map>
+
+namespace art {
+
+class CallInfo;
+class DexFile;
+class Mir2Lir;
+
+enum IntrinsicOpcode {
+ kIntrinsicDoubleCvt,
+ kIntrinsicFloatCvt,
+ kIntrinsicReverseBytes,
+ kIntrinsicAbsInt,
+ kIntrinsicAbsLong,
+ kIntrinsicMinMaxInt,
+ kIntrinsicSqrt,
+ kIntrinsicCharAt,
+ kIntrinsicCompareTo,
+ kIntrinsicIsEmptyOrLength,
+ kIntrinsicIndexOf,
+ kIntrinsicCurrentThread,
+ kIntrinsicPeek,
+ kIntrinsicPoke,
+ kIntrinsicCas32,
+ kIntrinsicUnsafeGet,
+ kIntrinsicUnsafePut,
+};
+
+enum IntrinsicFlags {
+ kIntrinsicFlagNone = 0,
+
+ // kIntrinsicMinMaxInt
+ kIntrinsicFlagMax = kIntrinsicFlagNone,
+ kIntrinsicFlagMin = 1,
+
+ // kIntrinsicIsEmptyOrLength
+ kIntrinsicFlagLength = kIntrinsicFlagNone,
+ kIntrinsicFlagIsEmpty = 1,
+
+ // kIntrinsicIndexOf
+ kIntrinsicFlagBase0 = 1,
+
+ // kIntrinsicUnsafeCas32
+ kIntrinsicFlagDontNeedWriteBarrier = 0,
+ kIntrinsicFlagNeedWriteBarrier = 1,
+
+ // kIntrinsicUnsafeGet, kIntrinsicUnsafePut
+ kIntrinsicFlagIsLong = 1,
+ kIntrinsicFlagIsVolatile = 2,
+ // kIntrinsicUnsafePut
+ kIntrinsicFlagIsObject = 4,
+ kIntrinsicFlagIsOrdered = 8,
+};
+
+struct Intrinsic {
+ IntrinsicOpcode opcode;
+ uint32_t data;
+};
+
+/**
+ * Handles inlining of methods from a particular DexFile.
+ *
+ * Intrinsics are a special case of inline methods. The DexFile indices for
+ * all the supported intrinsic methods are looked up once by the FindIntrinsics
+ * function and cached by this class for quick lookup by the method index.
+ *
+ * TODO: Detect short methods (at least getters, setters and empty functions)
+ * from the verifier and mark them for inlining. Inline these methods early
+ * during compilation to allow further optimizations. Similarly, provide
+ * additional information about intrinsics to the early phases of compilation.
+ */
+class DexFileMethodInliner {
+ public:
+ virtual ~DexFileMethodInliner();
+
+ /**
+ * Find all known intrinsic methods in the dex_file and cache their indices.
+ */
+ virtual void FindIntrinsics(const DexFile* dex_file) = 0;
+
+ /**
+ * Check whether a particular method index corresponds to an intrinsic function.
+ */
+ bool IsIntrinsic(uint32_t method_index) const;
+
+ /**
+ * Generate code for an intrinsic function invocation.
+ *
+ * TODO: This should be target-specific. For the time being,
+ * it's shared since it dispatches everything to backend.
+ */
+ bool GenIntrinsic(Mir2Lir* backend, CallInfo* info) const;
+
+ protected:
+ DexFileMethodInliner();
+
+ /**
+ * To avoid multiple lookups of a class by its descriptor, we cache its
+ * type index in the IndexCache. These are the indexes into the IndexCache
+ * class_indexes array.
+ */
+ enum ClassCacheIndex : uint8_t { // unit8_t to save space, make larger if needed
+ kClassCacheFirst = 0,
+ kClassCacheBoolean = kClassCacheFirst,
+ kClassCacheByte,
+ kClassCacheChar,
+ kClassCacheShort,
+ kClassCacheInt,
+ kClassCacheLong,
+ kClassCacheFloat,
+ kClassCacheDouble,
+ kClassCacheVoid,
+ kClassCacheJavaLangObject,
+ kClassCacheJavaLangString,
+ kClassCacheJavaLangDouble,
+ kClassCacheJavaLangFloat,
+ kClassCacheJavaLangInteger,
+ kClassCacheJavaLangLong,
+ kClassCacheJavaLangShort,
+ kClassCacheJavaLangMath,
+ kClassCacheJavaLangStrictMath,
+ kClassCacheJavaLangThread,
+ kClassCacheLibcoreIoMemory,
+ kClassCacheSunMiscUnsafe,
+ kClassCacheLast
+ };
+
+ /**
+ * To avoid multiple lookups of a method name string, we cache its string
+ * index in the IndexCache. These are the indexes into the IndexCache
+ * name_indexes array.
+ */
+ enum NameCacheIndex : uint8_t { // unit8_t to save space, make larger if needed
+ kNameCacheFirst = 0,
+ kNameCacheReverseBytes = kNameCacheFirst,
+ kNameCacheDoubleToRawLongBits,
+ kNameCacheLongBitsToDouble,
+ kNameCacheFloatToRawIntBits,
+ kNameCacheIntBitsToFloat,
+ kNameCacheAbs,
+ kNameCacheMax,
+ kNameCacheMin,
+ kNameCacheSqrt,
+ kNameCacheCharAt,
+ kNameCacheCompareTo,
+ kNameCacheIsEmpty,
+ kNameCacheIndexOf,
+ kNameCacheLength,
+ kNameCacheCurrentThread,
+ kNameCachePeekByte,
+ kNameCachePeekIntNative,
+ kNameCachePeekLongNative,
+ kNameCachePeekShortNative,
+ kNameCachePokeByte,
+ kNameCachePokeIntNative,
+ kNameCachePokeLongNative,
+ kNameCachePokeShortNative,
+ kNameCacheCompareAndSwapInt,
+ kNameCacheCompareAndSwapObject,
+ kNameCacheGetInt,
+ kNameCacheGetIntVolatile,
+ kNameCachePutInt,
+ kNameCachePutIntVolatile,
+ kNameCachePutOrderedInt,
+ kNameCacheGetLong,
+ kNameCacheGetLongVolatile,
+ kNameCachePutLong,
+ kNameCachePutLongVolatile,
+ kNameCachePutOrderedLong,
+ kNameCacheGetObject,
+ kNameCacheGetObjectVolatile,
+ kNameCachePutObject,
+ kNameCachePutObjectVolatile,
+ kNameCachePutOrderedObject,
+ kNameCacheLast
+ };
+
+ /**
+ * To avoid multiple lookups of a method signature, we cache its proto
+ * index in the IndexCache. These are the indexes into the IndexCache
+ * proto_indexes array.
+ */
+ enum ProtoCacheIndex : uint8_t { // unit8_t to save space, make larger if needed
+ kProtoCacheFirst = 0,
+ kProtoCacheI_I = kProtoCacheFirst,
+ kProtoCacheJ_J,
+ kProtoCacheS_S,
+ kProtoCacheD_D,
+ kProtoCacheD_J,
+ kProtoCacheJ_D,
+ kProtoCacheF_I,
+ kProtoCacheI_F,
+ kProtoCacheII_I,
+ kProtoCacheI_C,
+ kProtoCacheString_I,
+ kProtoCache_Z,
+ kProtoCache_I,
+ kProtoCache_Thread,
+ kProtoCacheJ_B,
+ kProtoCacheJ_I,
+ kProtoCacheJ_S,
+ kProtoCacheJB_V,
+ kProtoCacheJI_V,
+ kProtoCacheJJ_V,
+ kProtoCacheJS_V,
+ kProtoCacheObjectJII_Z,
+ kProtoCacheObjectJObjectObject_Z,
+ kProtoCacheObjectJ_I,
+ kProtoCacheObjectJI_V,
+ kProtoCacheObjectJ_J,
+ kProtoCacheObjectJJ_V,
+ kProtoCacheObjectJ_Object,
+ kProtoCacheObjectJObject_V,
+ kProtoCacheLast
+ };
+
+ /**
+ * The maximum number of method parameters we support in the ProtoDef.
+ */
+ static constexpr uint32_t kProtoMaxParams = 6;
+
+ /**
+ * The method signature (proto) definition using cached class indexes.
+ * The return_type and params are used with the IndexCache to look up
+ * appropriate class indexes to be passed to DexFile::FindProtoId().
+ */
+ struct ProtoDef {
+ ClassCacheIndex return_type;
+ uint8_t param_count;
+ ClassCacheIndex params[kProtoMaxParams];
+ };
+
+ /**
+ * The method definition using cached class, name and proto indexes.
+ * The class index, method name index and proto index are used with
+ * IndexCache to look up appropriate parameters for DexFile::FindMethodId().
+ */
+ struct MethodDef {
+ ClassCacheIndex declaring_class;
+ NameCacheIndex name;
+ ProtoCacheIndex proto;
+ };
+
+ /**
+ * The definition of an intrinsic function binds the method definition
+ * to an Intrinsic.
+ */
+ struct IntrinsicDef {
+ MethodDef method_def;
+ Intrinsic intrinsic;
+ };
+
+ /**
+ * Cache for class, method name and method signature indexes used during
+ * intrinsic function lookup to avoid multiple lookups of the same items.
+ *
+ * Many classes have multiple intrinsics and/or they are used in multiple
+ * method signatures and we want to avoid repeated lookups since they are
+ * not exactly cheap. The method names and method signatures are sometimes
+ * reused and therefore cached as well.
+ */
+ struct IndexCache {
+ IndexCache();
+
+ uint32_t class_indexes[kClassCacheLast - kClassCacheFirst];
+ uint32_t name_indexes[kNameCacheLast - kNameCacheFirst];
+ uint32_t proto_indexes[kProtoCacheLast - kProtoCacheFirst];
+ };
+
+ static const char* kClassCacheNames[];
+ static const char* kNameCacheNames[];
+ static const ProtoDef kProtoCacheDefs[];
+
+ static const uint32_t kIndexNotFound = static_cast<uint32_t>(-1);
+ static const uint32_t kIndexUnresolved = static_cast<uint32_t>(-2);
+
+ static uint32_t FindClassIndex(const DexFile* dex_file, IndexCache* cache,
+ ClassCacheIndex index);
+ static uint32_t FindNameIndex(const DexFile* dex_file, IndexCache* cache,
+ NameCacheIndex index);
+ static uint32_t FindProtoIndex(const DexFile* dex_file, IndexCache* cache,
+ ProtoCacheIndex index);
+ static uint32_t FindMethodIndex(const DexFile* dex_file, IndexCache* cache,
+ const MethodDef& method_def);
+
+ void DoFindIntrinsics(const DexFile* dex_file, IndexCache* cache,
+ const IntrinsicDef* defs, uint32_t def_count);
+
+ /*
+ * Maps method indexes (for the particular DexFile) to Intrinsic defintions.
+ */
+ std::map<uint32_t, Intrinsic> intrinsics_;
+ const DexFile* dex_file_;
+};
+
+} // namespace art
+
+#endif // ART_COMPILER_DEX_QUICK_DEX_FILE_METHOD_INLINER_H_
diff --git a/compiler/dex/quick/dex_file_to_method_inliner_map.cc b/compiler/dex/quick/dex_file_to_method_inliner_map.cc
new file mode 100644
index 0000000000..38022d2142
--- /dev/null
+++ b/compiler/dex/quick/dex_file_to_method_inliner_map.cc
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#include <algorithm>
+#include <utility>
+#include "thread.h"
+#include "thread-inl.h"
+#include "base/mutex.h"
+#include "base/mutex-inl.h"
+#include "base/logging.h"
+#include "driver/compiler_driver.h"
+#include "dex/quick/arm/arm_dex_file_method_inliner.h"
+#include "dex/quick/mips/mips_dex_file_method_inliner.h"
+#include "dex/quick/x86/x86_dex_file_method_inliner.h"
+
+#include "dex_file_to_method_inliner_map.h"
+
+namespace art {
+
+DexFileToMethodInlinerMap::DexFileToMethodInlinerMap(const CompilerDriver* compiler)
+ : compiler_(compiler),
+ mutex_("inline_helper_mutex")
+{
+}
+
+DexFileToMethodInlinerMap::~DexFileToMethodInlinerMap() {
+ for (auto& entry : inliners_) {
+ delete entry.second;
+ }
+}
+
+const DexFileMethodInliner& DexFileToMethodInlinerMap::GetMethodInliner(const DexFile* dex_file) {
+ Thread* self = Thread::Current();
+ {
+ ReaderMutexLock lock(self, mutex_);
+ auto it = inliners_.find(dex_file);
+ if (it != inliners_.end()) {
+ return *it->second;
+ }
+ }
+
+ WriterMutexLock lock(self, mutex_);
+ DexFileMethodInliner** inliner = &inliners_[dex_file]; // inserts new entry if not found
+ if (*inliner) {
+ return **inliner;
+ }
+ switch (compiler_->GetInstructionSet()) {
+ case kThumb2:
+ *inliner = new ArmDexFileMethodInliner;
+ break;
+ case kX86:
+ *inliner = new X86DexFileMethodInliner;
+ break;
+ case kMips:
+ *inliner = new MipsDexFileMethodInliner;
+ break;
+ default:
+ LOG(FATAL) << "Unexpected instruction set: " << compiler_->GetInstructionSet();
+ }
+ DCHECK(*inliner != nullptr);
+ // TODO: per-dex file locking for the intrinsics container filling.
+ (*inliner)->FindIntrinsics(dex_file);
+ return **inliner;
+}
+
+} // namespace art
diff --git a/compiler/dex/quick/dex_file_to_method_inliner_map.h b/compiler/dex/quick/dex_file_to_method_inliner_map.h
new file mode 100644
index 0000000000..e0b67e5a4b
--- /dev/null
+++ b/compiler/dex/quick/dex_file_to_method_inliner_map.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef ART_COMPILER_DEX_QUICK_DEX_FILE_TO_METHOD_INLINER_MAP_H_
+#define ART_COMPILER_DEX_QUICK_DEX_FILE_TO_METHOD_INLINER_MAP_H_
+
+#include <map>
+#include <vector>
+#include "base/macros.h"
+#include "base/mutex.h"
+
+#include "dex/quick/dex_file_method_inliner.h"
+
+namespace art {
+
+class CompilerDriver;
+class DexFile;
+
+/**
+ * Map each DexFile to its DexFileMethodInliner.
+ *
+ * The method inliner is created and initialized the first time it's requested
+ * for a particular DexFile.
+ */
+class DexFileToMethodInlinerMap {
+ public:
+ DexFileToMethodInlinerMap(const CompilerDriver* compiler);
+ ~DexFileToMethodInlinerMap();
+
+ const DexFileMethodInliner& GetMethodInliner(const DexFile* dex_file) LOCKS_EXCLUDED(mutex_);
+
+ private:
+ const CompilerDriver* const compiler_;
+ ReaderWriterMutex mutex_;
+ std::map<const DexFile*, DexFileMethodInliner*> inliners_ GUARDED_BY(mutex_);
+};
+
+} // namespace art
+
+#endif // ART_COMPILER_DEX_QUICK_DEX_FILE_TO_METHOD_INLINER_MAP_H_
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index d1a9a132bc..469c577071 100644
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -15,6 +15,9 @@
*/
#include "dex/compiler_ir.h"
+#include "dex/frontend.h"
+#include "dex/quick/dex_file_method_inliner.h"
+#include "dex/quick/dex_file_to_method_inliner_map.h"
#include "dex_file-inl.h"
#include "entrypoints/quick/quick_entrypoints.h"
#include "invoke_type.h"
@@ -1227,202 +1230,17 @@ bool Mir2Lir::GenInlinedUnsafePut(CallInfo* info, bool is_long,
return true;
}
-bool Mir2Lir::GenIntrinsic(CallInfo* info) {
- if (info->opt_flags & MIR_INLINED) {
- return false;
- }
- /*
- * TODO: move these to a target-specific structured constant array
- * and use a generic match function. The list of intrinsics may be
- * slightly different depending on target.
- * TODO: Fold this into a matching function that runs during
- * basic block building. This should be part of the action for
- * small method inlining and recognition of the special object init
- * method. By doing this during basic block construction, we can also
- * take advantage of/generate new useful dataflow info.
- */
- const DexFile::MethodId& target_mid = cu_->dex_file->GetMethodId(info->index);
- const DexFile::TypeId& declaring_type = cu_->dex_file->GetTypeId(target_mid.class_idx_);
- StringPiece tgt_methods_declaring_class(
- cu_->dex_file->StringDataByIdx(declaring_type.descriptor_idx_));
- if (tgt_methods_declaring_class.starts_with("Ljava/lang/")) {
- tgt_methods_declaring_class.remove_prefix(sizeof("Ljava/lang/") - 1);
- if (tgt_methods_declaring_class.starts_with("Double;")) {
- std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
- if (tgt_method == "long java.lang.Double.doubleToRawLongBits(double)") {
- return GenInlinedDoubleCvt(info);
- }
- if (tgt_method == "double java.lang.Double.longBitsToDouble(long)") {
- return GenInlinedDoubleCvt(info);
- }
- } else if (tgt_methods_declaring_class.starts_with("Float;")) {
- std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
- if (tgt_method == "int java.lang.Float.floatToRawIntBits(float)") {
- return GenInlinedFloatCvt(info);
- }
- if (tgt_method == "float java.lang.Float.intBitsToFloat(int)") {
- return GenInlinedFloatCvt(info);
- }
- } else if (tgt_methods_declaring_class.starts_with("Integer;")) {
- std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
- if (tgt_method == "int java.lang.Integer.reverseBytes(int)") {
- return GenInlinedReverseBytes(info, kWord);
- }
- } else if (tgt_methods_declaring_class.starts_with("Long;")) {
- std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
- if (tgt_method == "long java.lang.Long.reverseBytes(long)") {
- return GenInlinedReverseBytes(info, kLong);
- }
- } else if (tgt_methods_declaring_class.starts_with("Math;") ||
- tgt_methods_declaring_class.starts_with("StrictMath;")) {
- std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
- if (tgt_method == "int java.lang.Math.abs(int)" ||
- tgt_method == "int java.lang.StrictMath.abs(int)") {
- return GenInlinedAbsInt(info);
- }
- if (tgt_method == "long java.lang.Math.abs(long)" ||
- tgt_method == "long java.lang.StrictMath.abs(long)") {
- return GenInlinedAbsLong(info);
- }
- if (tgt_method == "int java.lang.Math.max(int, int)" ||
- tgt_method == "int java.lang.StrictMath.max(int, int)") {
- return GenInlinedMinMaxInt(info, false /* is_min */);
- }
- if (tgt_method == "int java.lang.Math.min(int, int)" ||
- tgt_method == "int java.lang.StrictMath.min(int, int)") {
- return GenInlinedMinMaxInt(info, true /* is_min */);
- }
- if (tgt_method == "double java.lang.Math.sqrt(double)" ||
- tgt_method == "double java.lang.StrictMath.sqrt(double)") {
- return GenInlinedSqrt(info);
- }
- } else if (tgt_methods_declaring_class.starts_with("Short;")) {
- std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
- if (tgt_method == "short java.lang.Short.reverseBytes(short)") {
- return GenInlinedReverseBytes(info, kSignedHalf);
- }
- } else if (tgt_methods_declaring_class.starts_with("String;")) {
- std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
- if (tgt_method == "char java.lang.String.charAt(int)") {
- return GenInlinedCharAt(info);
- }
- if (tgt_method == "int java.lang.String.compareTo(java.lang.String)") {
- return GenInlinedStringCompareTo(info);
- }
- if (tgt_method == "boolean java.lang.String.is_empty()") {
- return GenInlinedStringIsEmptyOrLength(info, true /* is_empty */);
- }
- if (tgt_method == "int java.lang.String.index_of(int, int)") {
- return GenInlinedIndexOf(info, false /* base 0 */);
- }
- if (tgt_method == "int java.lang.String.index_of(int)") {
- return GenInlinedIndexOf(info, true /* base 0 */);
- }
- if (tgt_method == "int java.lang.String.length()") {
- return GenInlinedStringIsEmptyOrLength(info, false /* is_empty */);
- }
- } else if (tgt_methods_declaring_class.starts_with("Thread;")) {
- std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
- if (tgt_method == "java.lang.Thread java.lang.Thread.currentThread()") {
- return GenInlinedCurrentThread(info);
- }
- }
- } else if (tgt_methods_declaring_class.starts_with("Llibcore/io/Memory;")) {
- std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
- if (tgt_method == "byte libcore.io.Memory.peekByte(long)") {
- return GenInlinedPeek(info, kSignedByte);
- }
- if (tgt_method == "int libcore.io.Memory.peekIntNative(long)") {
- return GenInlinedPeek(info, kWord);
- }
- if (tgt_method == "long libcore.io.Memory.peekLongNative(long)") {
- return GenInlinedPeek(info, kLong);
- }
- if (tgt_method == "short libcore.io.Memory.peekShortNative(long)") {
- return GenInlinedPeek(info, kSignedHalf);
- }
- if (tgt_method == "void libcore.io.Memory.pokeByte(long, byte)") {
- return GenInlinedPoke(info, kSignedByte);
- }
- if (tgt_method == "void libcore.io.Memory.pokeIntNative(long, int)") {
- return GenInlinedPoke(info, kWord);
- }
- if (tgt_method == "void libcore.io.Memory.pokeLongNative(long, long)") {
- return GenInlinedPoke(info, kLong);
- }
- if (tgt_method == "void libcore.io.Memory.pokeShortNative(long, short)") {
- return GenInlinedPoke(info, kSignedHalf);
- }
- } else if (tgt_methods_declaring_class.starts_with("Lsun/misc/Unsafe;")) {
- std::string tgt_method(PrettyMethod(info->index, *cu_->dex_file));
- if (tgt_method == "boolean sun.misc.Unsafe.compareAndSwapInt(java.lang.Object, long, int, int)") {
- return GenInlinedCas32(info, false);
- }
- if (tgt_method == "boolean sun.misc.Unsafe.compareAndSwapObject(java.lang.Object, long, java.lang.Object, java.lang.Object)") {
- return GenInlinedCas32(info, true);
- }
- if (tgt_method == "int sun.misc.Unsafe.getInt(java.lang.Object, long)") {
- return GenInlinedUnsafeGet(info, false /* is_long */, false /* is_volatile */);
- }
- if (tgt_method == "int sun.misc.Unsafe.getIntVolatile(java.lang.Object, long)") {
- return GenInlinedUnsafeGet(info, false /* is_long */, true /* is_volatile */);
- }
- if (tgt_method == "void sun.misc.Unsafe.putInt(java.lang.Object, long, int)") {
- return GenInlinedUnsafePut(info, false /* is_long */, false /* is_object */,
- false /* is_volatile */, false /* is_ordered */);
- }
- if (tgt_method == "void sun.misc.Unsafe.putIntVolatile(java.lang.Object, long, int)") {
- return GenInlinedUnsafePut(info, false /* is_long */, false /* is_object */,
- true /* is_volatile */, false /* is_ordered */);
- }
- if (tgt_method == "void sun.misc.Unsafe.putOrderedInt(java.lang.Object, long, int)") {
- return GenInlinedUnsafePut(info, false /* is_long */, false /* is_object */,
- false /* is_volatile */, true /* is_ordered */);
- }
- if (tgt_method == "long sun.misc.Unsafe.getLong(java.lang.Object, long)") {
- return GenInlinedUnsafeGet(info, true /* is_long */, false /* is_volatile */);
- }
- if (tgt_method == "long sun.misc.Unsafe.getLongVolatile(java.lang.Object, long)") {
- return GenInlinedUnsafeGet(info, true /* is_long */, true /* is_volatile */);
- }
- if (tgt_method == "void sun.misc.Unsafe.putLong(java.lang.Object, long, long)") {
- return GenInlinedUnsafePut(info, true /* is_long */, false /* is_object */,
- false /* is_volatile */, false /* is_ordered */);
- }
- if (tgt_method == "void sun.misc.Unsafe.putLongVolatile(java.lang.Object, long, long)") {
- return GenInlinedUnsafePut(info, true /* is_long */, false /* is_object */,
- true /* is_volatile */, false /* is_ordered */);
- }
- if (tgt_method == "void sun.misc.Unsafe.putOrderedLong(java.lang.Object, long, long)") {
- return GenInlinedUnsafePut(info, true /* is_long */, false /* is_object */,
- false /* is_volatile */, true /* is_ordered */);
- }
- if (tgt_method == "java.lang.Object sun.misc.Unsafe.getObject(java.lang.Object, long)") {
- return GenInlinedUnsafeGet(info, false /* is_long */, false /* is_volatile */);
- }
- if (tgt_method == "java.lang.Object sun.misc.Unsafe.getObjectVolatile(java.lang.Object, long)") {
- return GenInlinedUnsafeGet(info, false /* is_long */, true /* is_volatile */);
- }
- if (tgt_method == "void sun.misc.Unsafe.putObject(java.lang.Object, long, java.lang.Object)") {
- return GenInlinedUnsafePut(info, false /* is_long */, true /* is_object */,
- false /* is_volatile */, false /* is_ordered */);
- }
- if (tgt_method == "void sun.misc.Unsafe.putObjectVolatile(java.lang.Object, long, java.lang.Object)") {
- return GenInlinedUnsafePut(info, false /* is_long */, true /* is_object */,
- true /* is_volatile */, false /* is_ordered */);
+void Mir2Lir::GenInvoke(CallInfo* info) {
+ if (!(info->opt_flags & MIR_INLINED)) {
+ if (inliner_ == nullptr) {
+ QuickCompilerContext* context = reinterpret_cast<QuickCompilerContext*>(
+ cu_->compiler_driver->GetCompilerContext());
+ inliner_ = &context->GetInlinerMap()->GetMethodInliner(cu_->dex_file);
}
- if (tgt_method == "void sun.misc.Unsafe.putOrderedObject(java.lang.Object, long, java.lang.Object)") {
- return GenInlinedUnsafePut(info, false /* is_long */, true /* is_object */,
- false /* is_volatile */, true /* is_ordered */);
+ if (inliner_->GenIntrinsic(this, info)) {
+ return;
}
}
- return false;
-}
-
-void Mir2Lir::GenInvoke(CallInfo* info) {
- if (GenIntrinsic(info)) {
- return;
- }
InvokeType original_type = info->type; // avoiding mutation by ComputeInvokeInfo
int call_state = 0;
LIR* null_ck;
diff --git a/compiler/dex/quick/mips/mips_dex_file_method_inliner.cc b/compiler/dex/quick/mips/mips_dex_file_method_inliner.cc
new file mode 100644
index 0000000000..99eda82d5a
--- /dev/null
+++ b/compiler/dex/quick/mips/mips_dex_file_method_inliner.cc
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "dex/compiler_enums.h"
+
+#include "mips_dex_file_method_inliner.h"
+
+namespace art {
+
+const DexFileMethodInliner::IntrinsicDef MipsDexFileMethodInliner::kIntrinsicMethods[] = {
+#define INTRINSIC(c, n, p, o, d) \
+ { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, d } }
+
+ //INTRINSIC(JavaLangDouble, DoubleToRawLongBits, D_J, kIntrinsicDoubleCvt, 0),
+ //INTRINSIC(JavaLangDouble, LongBitsToDouble, J_D, kIntrinsicDoubleCvt, 0),
+ //INTRINSIC(JavaLangFloat, FloatToRawIntBits, F_I, kIntrinsicFloatCvt, 0),
+ //INTRINSIC(JavaLangFloat, IntBitsToFloat, I_F, kIntrinsicFloatCvt, 0),
+
+ //INTRINSIC(JavaLangInteger, ReverseBytes, I_I, kIntrinsicReverseBytes, kWord),
+ //INTRINSIC(JavaLangLong, ReverseBytes, J_J, kIntrinsicReverseBytes, kLong),
+ //INTRINSIC(JavaLangShort, ReverseBytes, S_S, kIntrinsicReverseBytes, kSignedHalf),
+
+ //INTRINSIC(JavaLangMath, Abs, I_I, kIntrinsicAbsInt, 0),
+ //INTRINSIC(JavaLangStrictMath, Abs, I_I, kIntrinsicAbsInt, 0),
+ //INTRINSIC(JavaLangMath, Abs, J_J, kIntrinsicAbsLong, 0),
+ //INTRINSIC(JavaLangStrictMath, Abs, J_J, kIntrinsicAbsLong, 0),
+ //INTRINSIC(JavaLangMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
+ //INTRINSIC(JavaLangStrictMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
+ //INTRINSIC(JavaLangMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
+ //INTRINSIC(JavaLangStrictMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
+ //INTRINSIC(JavaLangMath, Sqrt, D_D, kIntrinsicSqrt, 0),
+ //INTRINSIC(JavaLangStrictMath, Sqrt, D_D, kIntrinsicSqrt, 0),
+
+ //INTRINSIC(JavaLangString, CharAt, I_C, kIntrinsicCharAt, 0),
+ //INTRINSIC(JavaLangString, CompareTo, String_I, kIntrinsicCompareTo, 0),
+ //INTRINSIC(JavaLangString, IsEmpty, _Z, kIntrinsicIsEmptyOrLength, kIntrinsicFlagIsEmpty),
+ //INTRINSIC(JavaLangString, IndexOf, II_I, kIntrinsicIndexOf, kIntrinsicFlagNone),
+ //INTRINSIC(JavaLangString, IndexOf, I_I, kIntrinsicIndexOf, kIntrinsicFlagBase0),
+ //INTRINSIC(JavaLangString, Length, _I, kIntrinsicIsEmptyOrLength, kIntrinsicFlagLength),
+
+ INTRINSIC(JavaLangThread, CurrentThread, _Thread, kIntrinsicCurrentThread, 0),
+
+ INTRINSIC(LibcoreIoMemory, PeekByte, J_B, kIntrinsicPeek, kSignedByte),
+ //INTRINSIC(LibcoreIoMemory, PeekIntNative, J_I, kIntrinsicPeek, kWord),
+ //INTRINSIC(LibcoreIoMemory, PeekLongNative, J_J, kIntrinsicPeek, kLong),
+ //INTRINSIC(LibcoreIoMemory, PeekShortNative, J_S, kIntrinsicPeek, kSignedHalf),
+ INTRINSIC(LibcoreIoMemory, PokeByte, JB_V, kIntrinsicPoke, kSignedByte),
+ //INTRINSIC(LibcoreIoMemory, PokeIntNative, JI_V, kIntrinsicPoke, kWord),
+ //INTRINSIC(LibcoreIoMemory, PokeLongNative, JJ_V, kIntrinsicPoke, kLong),
+ //INTRINSIC(LibcoreIoMemory, PokeShortNative, JS_V, kIntrinsicPoke, kSignedHalf),
+
+ //INTRINSIC(SunMiscUnsafe, CompareAndSwapInt, ObjectJII_Z, kIntrinsicCas32,
+ // kIntrinsicFlagDontNeedWriteBarrier),
+ //INTRINSIC(SunMiscUnsafe, CompareAndSwapObject, ObjectJObjectObject_Z, kIntrinsicCas32,
+ // kIntrinsicFlagNeedWriteBarrier),
+
+#define UNSAFE_GET_PUT(type, code, type_flags) \
+ INTRINSIC(SunMiscUnsafe, Get ## type, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
+ type_flags & ~kIntrinsicFlagIsObject), \
+ INTRINSIC(SunMiscUnsafe, Get ## type ## Volatile, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
+ (type_flags | kIntrinsicFlagIsVolatile) & ~kIntrinsicFlagIsObject), \
+ INTRINSIC(SunMiscUnsafe, Put ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
+ type_flags), \
+ INTRINSIC(SunMiscUnsafe, Put ## type ## Volatile, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
+ type_flags | kIntrinsicFlagIsVolatile), \
+ INTRINSIC(SunMiscUnsafe, PutOrdered ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
+ type_flags | kIntrinsicFlagIsOrdered)
+
+ //UNSAFE_GET_PUT(Int, I, kIntrinsicFlagNone),
+ //UNSAFE_GET_PUT(Long, J, kIntrinsicFlagIsLong),
+ //UNSAFE_GET_PUT(Object, Object, kIntrinsicFlagIsObject),
+#undef UNSAFE_GET_PUT
+
+#undef INTRINSIC
+};
+
+MipsDexFileMethodInliner::MipsDexFileMethodInliner() {
+}
+
+MipsDexFileMethodInliner::~MipsDexFileMethodInliner() {
+}
+
+void MipsDexFileMethodInliner::FindIntrinsics(const DexFile* dex_file) {
+ IndexCache cache;
+ DoFindIntrinsics(dex_file, &cache, kIntrinsicMethods, arraysize(kIntrinsicMethods));
+}
+
+} // namespace art
diff --git a/compiler/dex/quick/mips/mips_dex_file_method_inliner.h b/compiler/dex/quick/mips/mips_dex_file_method_inliner.h
new file mode 100644
index 0000000000..8fe7ec771b
--- /dev/null
+++ b/compiler/dex/quick/mips/mips_dex_file_method_inliner.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef ART_COMPILER_DEX_QUICK_MIPS_MIPS_DEX_FILE_METHOD_INLINER_H_
+#define ART_COMPILER_DEX_QUICK_MIPS_MIPS_DEX_FILE_METHOD_INLINER_H_
+
+#include "dex/quick/dex_file_method_inliner.h"
+
+namespace art {
+
+class MipsDexFileMethodInliner : public DexFileMethodInliner {
+ public:
+ MipsDexFileMethodInliner();
+ ~MipsDexFileMethodInliner();
+
+ void FindIntrinsics(const DexFile* dex_file);
+
+ private:
+ static const IntrinsicDef kIntrinsicMethods[];
+};
+
+} // namespace art
+
+#endif // ART_COMPILER_DEX_QUICK_MIPS_MIPS_DEX_FILE_METHOD_INLINER_H_
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 4c56b74dc4..58a77c7a0a 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -106,6 +106,7 @@ struct MIR;
struct LIR;
struct RegLocation;
struct RegisterInfo;
+class DexFileMethodInliner;
class MIRGraph;
class Mir2Lir;
@@ -555,7 +556,6 @@ class Mir2Lir : public Backend {
bool GenInlinedUnsafeGet(CallInfo* info, bool is_long, bool is_volatile);
bool GenInlinedUnsafePut(CallInfo* info, bool is_long, bool is_object,
bool is_volatile, bool is_ordered);
- bool GenIntrinsic(CallInfo* info);
int LoadArgRegs(CallInfo* info, int call_state,
NextCallInsn next_call_insn,
const MethodReference& target_method,
@@ -837,6 +837,8 @@ class Mir2Lir : public Backend {
unsigned int fp_spill_mask_;
LIR* first_lir_insn_;
LIR* last_lir_insn_;
+ // Lazily retrieved method inliner for intrinsics.
+ const DexFileMethodInliner* inliner_;
}; // Class Mir2Lir
} // namespace art
diff --git a/compiler/dex/quick/x86/x86_dex_file_method_inliner.cc b/compiler/dex/quick/x86/x86_dex_file_method_inliner.cc
new file mode 100644
index 0000000000..e604106161
--- /dev/null
+++ b/compiler/dex/quick/x86/x86_dex_file_method_inliner.cc
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "dex/compiler_enums.h"
+
+#include "x86_dex_file_method_inliner.h"
+
+namespace art {
+
+const DexFileMethodInliner::IntrinsicDef X86DexFileMethodInliner::kIntrinsicMethods[] = {
+#define INTRINSIC(c, n, p, o, d) \
+ { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, d } }
+
+ INTRINSIC(JavaLangDouble, DoubleToRawLongBits, D_J, kIntrinsicDoubleCvt, 0),
+ INTRINSIC(JavaLangDouble, LongBitsToDouble, J_D, kIntrinsicDoubleCvt, 0),
+ INTRINSIC(JavaLangFloat, FloatToRawIntBits, F_I, kIntrinsicFloatCvt, 0),
+ INTRINSIC(JavaLangFloat, IntBitsToFloat, I_F, kIntrinsicFloatCvt, 0),
+
+ INTRINSIC(JavaLangInteger, ReverseBytes, I_I, kIntrinsicReverseBytes, kWord),
+ INTRINSIC(JavaLangLong, ReverseBytes, J_J, kIntrinsicReverseBytes, kLong),
+ INTRINSIC(JavaLangShort, ReverseBytes, S_S, kIntrinsicReverseBytes, kSignedHalf),
+
+ INTRINSIC(JavaLangMath, Abs, I_I, kIntrinsicAbsInt, 0),
+ INTRINSIC(JavaLangStrictMath, Abs, I_I, kIntrinsicAbsInt, 0),
+ INTRINSIC(JavaLangMath, Abs, J_J, kIntrinsicAbsLong, 0),
+ INTRINSIC(JavaLangStrictMath, Abs, J_J, kIntrinsicAbsLong, 0),
+ INTRINSIC(JavaLangMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
+ INTRINSIC(JavaLangStrictMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
+ INTRINSIC(JavaLangMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
+ INTRINSIC(JavaLangStrictMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
+ //INTRINSIC(JavaLangMath, Sqrt, D_D, kIntrinsicSqrt, 0),
+ //INTRINSIC(JavaLangStrictMath, Sqrt, D_D, kIntrinsicSqrt, 0),
+
+ INTRINSIC(JavaLangString, CharAt, I_C, kIntrinsicCharAt, 0),
+ INTRINSIC(JavaLangString, CompareTo, String_I, kIntrinsicCompareTo, 0),
+ INTRINSIC(JavaLangString, IsEmpty, _Z, kIntrinsicIsEmptyOrLength, kIntrinsicFlagIsEmpty),
+ INTRINSIC(JavaLangString, IndexOf, II_I, kIntrinsicIndexOf, kIntrinsicFlagNone),
+ INTRINSIC(JavaLangString, IndexOf, I_I, kIntrinsicIndexOf, kIntrinsicFlagBase0),
+ INTRINSIC(JavaLangString, Length, _I, kIntrinsicIsEmptyOrLength, kIntrinsicFlagLength),
+
+ INTRINSIC(JavaLangThread, CurrentThread, _Thread, kIntrinsicCurrentThread, 0),
+
+ INTRINSIC(LibcoreIoMemory, PeekByte, J_B, kIntrinsicPeek, kSignedByte),
+ INTRINSIC(LibcoreIoMemory, PeekIntNative, J_I, kIntrinsicPeek, kWord),
+ INTRINSIC(LibcoreIoMemory, PeekLongNative, J_J, kIntrinsicPeek, kLong),
+ INTRINSIC(LibcoreIoMemory, PeekShortNative, J_S, kIntrinsicPeek, kSignedHalf),
+ INTRINSIC(LibcoreIoMemory, PokeByte, JB_V, kIntrinsicPoke, kSignedByte),
+ INTRINSIC(LibcoreIoMemory, PokeIntNative, JI_V, kIntrinsicPoke, kWord),
+ INTRINSIC(LibcoreIoMemory, PokeLongNative, JJ_V, kIntrinsicPoke, kLong),
+ INTRINSIC(LibcoreIoMemory, PokeShortNative, JS_V, kIntrinsicPoke, kSignedHalf),
+
+ //INTRINSIC(SunMiscUnsafe, CompareAndSwapInt, ObjectJII_Z, kIntrinsicCas32,
+ // kIntrinsicFlagDontNeedWriteBarrier),
+ //INTRINSIC(SunMiscUnsafe, CompareAndSwapObject, ObjectJObjectObject_Z, kIntrinsicCas32,
+ // kIntrinsicFlagNeedWriteBarrier),
+
+#define UNSAFE_GET_PUT(type, code, type_flags) \
+ INTRINSIC(SunMiscUnsafe, Get ## type, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
+ type_flags & ~kIntrinsicFlagIsObject), \
+ INTRINSIC(SunMiscUnsafe, Get ## type ## Volatile, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
+ (type_flags | kIntrinsicFlagIsVolatile) & ~kIntrinsicFlagIsObject), \
+ INTRINSIC(SunMiscUnsafe, Put ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
+ type_flags), \
+ INTRINSIC(SunMiscUnsafe, Put ## type ## Volatile, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
+ type_flags | kIntrinsicFlagIsVolatile), \
+ INTRINSIC(SunMiscUnsafe, PutOrdered ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
+ type_flags | kIntrinsicFlagIsOrdered)
+
+ UNSAFE_GET_PUT(Int, I, kIntrinsicFlagNone),
+ UNSAFE_GET_PUT(Long, J, kIntrinsicFlagIsLong),
+
+ //UNSAFE_GET_PUT(Object, Object, kIntrinsicFlagIsObject),
+ // PutObject: "TODO: fix X86, it exhausts registers for card marking."
+ INTRINSIC(SunMiscUnsafe, GetObject, ObjectJ_Object, kIntrinsicUnsafeGet,
+ kIntrinsicFlagNone),
+ INTRINSIC(SunMiscUnsafe, GetObjectVolatile, ObjectJ_Object, kIntrinsicUnsafeGet,
+ kIntrinsicFlagIsVolatile),
+#undef UNSAFE_GET_PUT
+
+#undef INTRINSIC
+};
+
+X86DexFileMethodInliner::X86DexFileMethodInliner() {
+}
+
+X86DexFileMethodInliner::~X86DexFileMethodInliner() {
+}
+
+void X86DexFileMethodInliner::FindIntrinsics(const DexFile* dex_file) {
+ IndexCache cache;
+ DoFindIntrinsics(dex_file, &cache, kIntrinsicMethods, arraysize(kIntrinsicMethods));
+}
+
+} // namespace art
diff --git a/compiler/dex/quick/x86/x86_dex_file_method_inliner.h b/compiler/dex/quick/x86/x86_dex_file_method_inliner.h
new file mode 100644
index 0000000000..7813e444fe
--- /dev/null
+++ b/compiler/dex/quick/x86/x86_dex_file_method_inliner.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef ART_COMPILER_DEX_QUICK_X86_X86_DEX_FILE_METHOD_INLINER_H_
+#define ART_COMPILER_DEX_QUICK_X86_X86_DEX_FILE_METHOD_INLINER_H_
+
+#include "dex/quick/dex_file_method_inliner.h"
+
+namespace art {
+
+class X86DexFileMethodInliner : public DexFileMethodInliner {
+ public:
+ X86DexFileMethodInliner();
+ ~X86DexFileMethodInliner();
+
+ void FindIntrinsics(const DexFile* dex_file);
+
+ private:
+ static const IntrinsicDef kIntrinsicMethods[];
+};
+
+} // namespace art
+
+#endif // ART_COMPILER_DEX_QUICK_X86_X86_DEX_FILE_METHOD_INLINER_H_