diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/Android.mk | 5 | ||||
-rw-r--r-- | compiler/dex/frontend.cc | 15 | ||||
-rw-r--r-- | compiler/dex/frontend.h | 16 | ||||
-rw-r--r-- | compiler/dex/quick/arm/arm_dex_file_method_inliner.cc | 103 | ||||
-rw-r--r-- | compiler/dex/quick/arm/arm_dex_file_method_inliner.h | 37 | ||||
-rw-r--r-- | compiler/dex/quick/codegen_util.cc | 3 | ||||
-rw-r--r-- | compiler/dex/quick/dex_file_method_inliner.cc | 346 | ||||
-rw-r--r-- | compiler/dex/quick/dex_file_method_inliner.h | 318 | ||||
-rw-r--r-- | compiler/dex/quick/dex_file_to_method_inliner_map.cc | 79 | ||||
-rw-r--r-- | compiler/dex/quick/dex_file_to_method_inliner_map.h | 53 | ||||
-rw-r--r-- | compiler/dex/quick/gen_invoke.cc | 204 | ||||
-rw-r--r-- | compiler/dex/quick/mips/mips_dex_file_method_inliner.cc | 103 | ||||
-rw-r--r-- | compiler/dex/quick/mips/mips_dex_file_method_inliner.h | 37 | ||||
-rw-r--r-- | compiler/dex/quick/mir_to_lir.h | 4 | ||||
-rw-r--r-- | compiler/dex/quick/x86/x86_dex_file_method_inliner.cc | 109 | ||||
-rw-r--r-- | compiler/dex/quick/x86/x86_dex_file_method_inliner.h | 37 |
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_ |