return nullptr;
}
+/* Search the existing constants in the literal pool for an exact class match */
+LIR* Mir2Lir::ScanLiteralPoolClass(LIR* data_target, const DexFile& dex_file, uint32_t type_idx) {
+ while (data_target) {
+ if (static_cast<uint32_t>(data_target->operands[0]) == type_idx &&
+ UnwrapPointer(data_target->operands[1]) == &dex_file) {
+ return data_target;
+ }
+ data_target = data_target->next;
+ }
+ return nullptr;
+}
+
/*
* The following are building blocks to insert constants into the pool or
* instruction streams.
data_lir = class_literal_list_;
while (data_lir != NULL) {
uint32_t target_method_idx = data_lir->operands[0];
+ const DexFile* class_dex_file =
+ reinterpret_cast<const DexFile*>(UnwrapPointer(data_lir->operands[1]));
cu_->compiler_driver->AddClassPatch(cu_->dex_file,
cu_->class_def_idx,
cu_->method_idx,
target_method_idx,
+ class_dex_file,
code_buffer_.size());
const DexFile::TypeId& target_method_id = cu_->dex_file->GetTypeId(target_method_idx);
// unique value based on target to ensure code deduplication works
DCHECK_NE(cu_->instruction_set, kMips) << reinterpret_cast<void*>(data_target);
}
-void Mir2Lir::LoadClassType(uint32_t type_idx, SpecialTargetRegister symbolic_reg) {
+void Mir2Lir::LoadClassType(const DexFile& dex_file, uint32_t type_idx,
+ SpecialTargetRegister symbolic_reg) {
// Use the literal pool and a PC-relative load from a data word.
- LIR* data_target = ScanLiteralPool(class_literal_list_, type_idx, 0);
+ LIR* data_target = ScanLiteralPoolClass(class_literal_list_, dex_file, type_idx);
if (data_target == nullptr) {
data_target = AddWordData(&class_literal_list_, type_idx);
}
+ data_target->operands[1] = WrapPointer(const_cast<DexFile*>(&dex_file));
// Loads a Class pointer, which is a reference as it lives in the heap.
LIR* load_pc_rel = OpPcRelLoad(TargetReg(symbolic_reg, kRef), data_target);
AppendLIR(load_pc_rel);
true, // kIntrinsicRint
true, // kIntrinsicRoundFloat
true, // kIntrinsicRoundDouble
- false, // kIntrinsicGet
+ false, // kIntrinsicReferenceGet
false, // kIntrinsicCharAt
false, // kIntrinsicCompareTo
false, // kIntrinsicIsEmptyOrLength
COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicRint], Rint_must_be_static);
COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicRoundFloat], RoundFloat_must_be_static);
COMPILE_ASSERT(kIntrinsicIsStatic[kIntrinsicRoundDouble], RoundDouble_must_be_static);
-COMPILE_ASSERT(!kIntrinsicIsStatic[kIntrinsicGet], Get_must_not_be_static);
+COMPILE_ASSERT(!kIntrinsicIsStatic[kIntrinsicReferenceGet], Get_must_not_be_static);
COMPILE_ASSERT(!kIntrinsicIsStatic[kIntrinsicCharAt], CharAt_must_not_be_static);
COMPILE_ASSERT(!kIntrinsicIsStatic[kIntrinsicCompareTo], CompareTo_must_not_be_static);
COMPILE_ASSERT(!kIntrinsicIsStatic[kIntrinsicIsEmptyOrLength], IsEmptyOrLength_must_not_be_static);
"floor", // kNameCacheFloor
"rint", // kNameCacheRint
"round", // kNameCacheRound
- "get", // kNameCacheGet
+ "get", // kNameCacheReferenceGet
"charAt", // kNameCacheCharAt
"compareTo", // kNameCacheCompareTo
"isEmpty", // kNameCacheIsEmpty
INTRINSIC(JavaLangMath, Round, D_J, kIntrinsicRoundDouble, 0),
INTRINSIC(JavaLangStrictMath, Round, D_J, kIntrinsicRoundDouble, 0),
- INTRINSIC(JavaLangRefReference, Get, _Object, kIntrinsicGet, 0),
+ INTRINSIC(JavaLangRefReference, ReferenceGet, _Object, kIntrinsicReferenceGet, 0),
INTRINSIC(JavaLangString, CharAt, I_C, kIntrinsicCharAt, 0),
INTRINSIC(JavaLangString, CompareTo, String_I, kIntrinsicCompareTo, 0),
return backend->GenInlinedRound(info, false /* is_double */);
case kIntrinsicRoundDouble:
return backend->GenInlinedRound(info, true /* is_double */);
- case kIntrinsicGet:
- return backend->GenInlinedGet(info);
+ case kIntrinsicReferenceGet:
+ return backend->GenInlinedReferenceGet(info);
case kIntrinsicCharAt:
return backend->GenInlinedCharAt(info);
case kIntrinsicCompareTo:
kNameCacheFloor,
kNameCacheRint,
kNameCacheRound,
- kNameCacheGet,
+ kNameCacheReferenceGet,
kNameCacheCharAt,
kNameCacheCompareTo,
kNameCacheIsEmpty,
&direct_type_ptr, &is_finalizable)) {
// The fast path.
if (!use_direct_type_ptr) {
- LoadClassType(type_idx, kArg0);
+ LoadClassType(*dex_file, type_idx, kArg0);
CallRuntimeHelperRegMethodRegLocation(kQuickAllocArrayResolved, TargetReg(kArg0, kNotWide),
rl_src, true);
} else {
!is_finalizable) {
// The fast path.
if (!use_direct_type_ptr) {
- LoadClassType(type_idx, kArg0);
+ LoadClassType(*dex_file, type_idx, kArg0);
if (!is_type_initialized) {
CallRuntimeHelperRegMethod(kQuickAllocObjectResolved, TargetReg(kArg0, kRef), true);
} else {
#include "mirror/class-inl.h"
#include "mirror/dex_cache.h"
#include "mirror/object_array-inl.h"
-#include "mirror/reference-inl.h"
#include "mirror/string.h"
#include "mir_to_lir-inl.h"
-#include "scoped_thread_state_change.h"
#include "x86/codegen_x86.h"
namespace art {
return res;
}
-bool Mir2Lir::GenInlinedGet(CallInfo* info) {
+bool Mir2Lir::GenInlinedReferenceGet(CallInfo* info) {
if (cu_->instruction_set == kMips) {
// TODO - add Mips implementation
return false;
}
- // the refrence class is stored in the image dex file which might not be the same as the cu's
- // dex file. Query the reference class for the image dex file then reset to starting dex file
- // in after loading class type.
- uint16_t type_idx = 0;
- const DexFile* ref_dex_file = nullptr;
- {
- ScopedObjectAccess soa(Thread::Current());
- type_idx = mirror::Reference::GetJavaLangRefReference()->GetDexTypeIndex();
- ref_dex_file = mirror::Reference::GetJavaLangRefReference()->GetDexCache()->GetDexFile();
- }
- CHECK(LIKELY(ref_dex_file != nullptr));
-
- // address is either static within the image file, or needs to be patched up after compilation.
- bool unused_type_initialized;
bool use_direct_type_ptr;
uintptr_t direct_type_ptr;
- bool is_finalizable;
- const DexFile* old_dex = cu_->dex_file;
- cu_->dex_file = ref_dex_file;
+ ClassReference ref;
+ if (!cu_->compiler_driver->CanEmbedReferenceTypeInCode(&ref,
+ &use_direct_type_ptr, &direct_type_ptr)) {
+ return false;
+ }
+
RegStorage reg_class = TargetReg(kArg1, kRef);
Clobber(reg_class);
LockTemp(reg_class);
- if (!cu_->compiler_driver->CanEmbedTypeInCode(*ref_dex_file, type_idx, &unused_type_initialized,
- &use_direct_type_ptr, &direct_type_ptr,
- &is_finalizable) || is_finalizable) {
- cu_->dex_file = old_dex;
- // address is not known and post-compile patch is not possible, cannot insert intrinsic.
- return false;
- }
if (use_direct_type_ptr) {
LoadConstant(reg_class, direct_type_ptr);
} else {
- LoadClassType(type_idx, kArg1);
+ uint16_t type_idx = ref.first->GetClassDef(ref.second).class_idx_;
+ LoadClassType(*ref.first, type_idx, kArg1);
}
- cu_->dex_file = old_dex;
- // get the offset for flags in reference class.
- uint32_t slow_path_flag_offset = 0;
- uint32_t disable_flag_offset = 0;
- {
- ScopedObjectAccess soa(Thread::Current());
- mirror::Class* reference_class = mirror::Reference::GetJavaLangRefReference();
- slow_path_flag_offset = reference_class->GetSlowPathFlagOffset().Uint32Value();
- disable_flag_offset = reference_class->GetDisableIntrinsicFlagOffset().Uint32Value();
- }
+ uint32_t slow_path_flag_offset = cu_->compiler_driver->GetReferenceSlowFlagOffset();
+ uint32_t disable_flag_offset = cu_->compiler_driver->GetReferenceDisableFlagOffset();
CHECK(slow_path_flag_offset && disable_flag_offset &&
(slow_path_flag_offset != disable_flag_offset));
LIR* ScanLiteralPool(LIR* data_target, int value, unsigned int delta);
LIR* ScanLiteralPoolWide(LIR* data_target, int val_lo, int val_hi);
LIR* ScanLiteralPoolMethod(LIR* data_target, const MethodReference& method);
+ LIR* ScanLiteralPoolClass(LIR* data_target, const DexFile& dex_file, uint32_t type_idx);
LIR* AddWordData(LIR* *constant_list_p, int value);
LIR* AddWideData(LIR* *constant_list_p, int val_lo, int val_hi);
void ProcessSwitchTables();
*/
RegLocation InlineTargetWide(CallInfo* info);
- bool GenInlinedGet(CallInfo* info);
+ bool GenInlinedReferenceGet(CallInfo* info);
virtual bool GenInlinedCharAt(CallInfo* info);
bool GenInlinedStringIsEmptyOrLength(CallInfo* info, bool is_empty);
virtual bool GenInlinedReverseBits(CallInfo* info, OpSize size);
/*
* @brief Load the Class* of a Dex Class type into the register.
+ * @param dex DexFile that contains the class type.
* @param type How the method will be invoked.
* @param register that will contain the code address.
* @note register will be passed to TargetReg to get physical register.
*/
- virtual void LoadClassType(uint32_t type_idx, SpecialTargetRegister symbolic_reg);
+ virtual void LoadClassType(const DexFile& dex_file, uint32_t type_idx,
+ SpecialTargetRegister symbolic_reg);
// Routines that work for the generic case, but may be overriden by target.
/*
/*
* @brief Load the Class* of a Dex Class type into the register.
+ * @param dex DexFile that contains the class type.
* @param type How the method will be invoked.
* @param register that will contain the code address.
* @note register will be passed to TargetReg to get physical register.
*/
- void LoadClassType(uint32_t type_idx, SpecialTargetRegister symbolic_reg) OVERRIDE;
+ void LoadClassType(const DexFile& dex_file, uint32_t type_idx,
+ SpecialTargetRegister symbolic_reg) OVERRIDE;
void FlushIns(RegLocation* ArgLocs, RegLocation rl_method) OVERRIDE;
method_address_insns_.Insert(move);
}
-void X86Mir2Lir::LoadClassType(uint32_t type_idx, SpecialTargetRegister symbolic_reg) {
+void X86Mir2Lir::LoadClassType(const DexFile& dex_file, uint32_t type_idx,
+ SpecialTargetRegister symbolic_reg) {
/*
* For x86, just generate a 32 bit move immediate instruction, that will be filled
* in at 'link time'. For now, put a unique value based on target to ensure that
* code deduplication works.
*/
- const DexFile::TypeId& id = cu_->dex_file->GetTypeId(type_idx);
+ const DexFile::TypeId& id = dex_file.GetTypeId(type_idx);
uintptr_t ptr = reinterpret_cast<uintptr_t>(&id);
// Generate the move instruction with the unique pointer and save index and type.
LIR *move = RawLIR(current_dalvik_offset_, kX86Mov32RI,
TargetReg(symbolic_reg, kNotWide).GetReg(),
- static_cast<int>(ptr), type_idx);
+ static_cast<int>(ptr), type_idx,
+ WrapPointer(const_cast<DexFile*>(&dex_file)));
AppendLIR(move);
class_type_address_insns_.Insert(move);
}
for (uint32_t i = 0; i < class_type_address_insns_.Size(); i++) {
LIR* p = class_type_address_insns_.Get(i);
DCHECK_EQ(p->opcode, kX86Mov32RI);
+
+ const DexFile* class_dex_file =
+ reinterpret_cast<const DexFile*>(UnwrapPointer(p->operands[3]));
uint32_t target_method_idx = p->operands[2];
// The offset to patch is the last 4 bytes of the instruction.
int patch_offset = p->offset + p->flags.size - 4;
cu_->compiler_driver->AddClassPatch(cu_->dex_file, cu_->class_def_idx,
- cu_->method_idx, target_method_idx, patch_offset);
+ cu_->method_idx, target_method_idx, class_dex_file,
+ patch_offset);
}
// And now the PC-relative calls to methods.
}
}
+bool CompilerDriver::CanEmbedReferenceTypeInCode(ClassReference* ref,
+ bool* use_direct_ptr,
+ uintptr_t* direct_type_ptr) {
+ CHECK(ref != nullptr);
+ CHECK(use_direct_ptr != nullptr);
+ CHECK(direct_type_ptr != nullptr);
+
+ ScopedObjectAccess soa(Thread::Current());
+ mirror::Class* reference_class = mirror::Reference::GetJavaLangRefReference();
+ bool is_initialized;
+ bool unused_finalizable;
+ // Make sure we have a finished Reference class object before attempting to use it.
+ if (!CanEmbedTypeInCode(*reference_class->GetDexCache()->GetDexFile(),
+ reference_class->GetDexTypeIndex(), &is_initialized,
+ use_direct_ptr, direct_type_ptr, &unused_finalizable) ||
+ !is_initialized) {
+ return false;
+ }
+ ref->first = &reference_class->GetDexFile();
+ ref->second = reference_class->GetDexClassDefIndex();
+ return true;
+}
+
+uint32_t CompilerDriver::GetReferenceSlowFlagOffset() const {
+ ScopedObjectAccess soa(Thread::Current());
+ mirror::Class* klass = mirror::Reference::GetJavaLangRefReference();
+ DCHECK(klass->IsInitialized());
+ return klass->GetSlowPathFlagOffset().Uint32Value();
+}
+
+uint32_t CompilerDriver::GetReferenceDisableFlagOffset() const {
+ ScopedObjectAccess soa(Thread::Current());
+ mirror::Class* klass = mirror::Reference::GetJavaLangRefReference();
+ DCHECK(klass->IsInitialized());
+ return klass->GetDisableIntrinsicFlagOffset().Uint32Value();
+}
+
void CompilerDriver::ProcessedInstanceField(bool resolved) {
if (!resolved) {
stats_->UnresolvedInstanceField();
uint16_t referrer_class_def_idx,
uint32_t referrer_method_idx,
uint32_t target_type_idx,
+ const DexFile* target_type_dex_file,
size_t literal_offset) {
MutexLock mu(Thread::Current(), compiled_methods_lock_);
classes_to_patch_.push_back(new TypePatchInformation(dex_file,
referrer_class_def_idx,
referrer_method_idx,
target_type_idx,
+ target_type_dex_file,
literal_offset));
}
bool* is_type_initialized, bool* use_direct_type_ptr,
uintptr_t* direct_type_ptr, bool* out_is_finalizable);
+ // Query methods for the java.lang.ref.Reference class.
+ bool CanEmbedReferenceTypeInCode(ClassReference* ref,
+ bool* use_direct_type_ptr, uintptr_t* direct_type_ptr);
+ uint32_t GetReferenceSlowFlagOffset() const;
+ uint32_t GetReferenceDisableFlagOffset() const;
+
// Get the DexCache for the
mirror::DexCache* GetDexCache(const DexCompilationUnit* mUnit)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
uint16_t referrer_class_def_idx,
uint32_t referrer_method_idx,
uint32_t target_method_idx,
+ const DexFile* target_dex_file,
size_t literal_offset)
LOCKS_EXCLUDED(compiled_methods_lock_);
class TypePatchInformation : public PatchInformation {
public:
+ const DexFile& GetTargetTypeDexFile() const {
+ return *target_type_dex_file_;
+ }
+
uint32_t GetTargetTypeIdx() const {
return target_type_idx_;
}
uint16_t referrer_class_def_idx,
uint32_t referrer_method_idx,
uint32_t target_type_idx,
+ const DexFile* target_type_dex_file,
size_t literal_offset)
: PatchInformation(dex_file, referrer_class_def_idx,
referrer_method_idx, literal_offset),
- target_type_idx_(target_type_idx) {
+ target_type_idx_(target_type_idx), target_type_dex_file_(target_type_dex_file) {
}
const uint32_t target_type_idx_;
+ const DexFile* target_type_dex_file_;
friend class CompilerDriver;
DISALLOW_COPY_AND_ASSIGN(TypePatchInformation);
mirror::Class* ElfPatcher::GetTargetType(const CompilerDriver::TypePatchInformation* patch) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
StackHandleScope<2> hs(Thread::Current());
- Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->FindDexCache(patch->GetDexFile())));
- mirror::Class* klass = class_linker->ResolveType(patch->GetDexFile(), patch->GetTargetTypeIdx(),
+ Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->FindDexCache(
+ patch->GetTargetTypeDexFile())));
+ mirror::Class* klass = class_linker->ResolveType(patch->GetTargetTypeDexFile(),
+ patch->GetTargetTypeIdx(),
dex_cache, NullHandle<mirror::ClassLoader>());
CHECK(klass != NULL)
- << patch->GetDexFile().GetLocation() << " " << patch->GetTargetTypeIdx();
+ << patch->GetTargetTypeDexFile().GetLocation() << " " << patch->GetTargetTypeIdx();
CHECK(dex_cache->GetResolvedTypes()->Get(patch->GetTargetTypeIdx()) == klass)
<< patch->GetDexFile().GetLocation() << " " << patch->GetReferrerMethodIdx() << " "
<< PrettyClass(dex_cache->GetResolvedTypes()->Get(patch->GetTargetTypeIdx())) << " "
}
if (patch->IsType()) {
const CompilerDriver::TypePatchInformation* tpatch = patch->AsType();
- const DexFile::TypeId& id = tpatch->GetDexFile().GetTypeId(tpatch->GetTargetTypeIdx());
+ const DexFile::TypeId& id = tpatch->GetTargetTypeDexFile().GetTypeId(tpatch->GetTargetTypeIdx());
uint32_t expected = reinterpret_cast<uintptr_t>(&id) & 0xFFFFFFFF;
uint32_t actual = *patch_location;
CHECK(actual == expected || actual == value) << "Patching type failed: " << std::hex
kIntrinsicRint,
kIntrinsicRoundFloat,
kIntrinsicRoundDouble,
- kIntrinsicGet,
+ kIntrinsicReferenceGet,
kIntrinsicCharAt,
kIntrinsicCompareTo,
kIntrinsicIsEmptyOrLength,