Revert "Revert "Add kJitTableAddress for HLoadClass.""
This reverts commit d2d5262c8370309e1f2a009f00aafc24f1cf00a0.
Change-Id: I6149d5c7d5df0b0fc5cb646a802a2eea8d01ac08
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index fa6a522..402eeee 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -1402,6 +1402,14 @@
entry.second = index;
++index;
}
+ for (auto& entry : jit_class_roots_) {
+ // Update the `roots` with the class, and replace the address temporarily
+ // stored to the index in the table.
+ uint64_t address = entry.second;
+ roots->Set(index, reinterpret_cast<StackReference<mirror::Class>*>(address)->AsMirrorPtr());
+ entry.second = index;
+ ++index;
+ }
EmitJitRootPatches(code, roots_data);
}
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 4b11e7c..2e2c3c0 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -34,6 +34,7 @@
#include "stack_map_stream.h"
#include "string_reference.h"
#include "utils/label.h"
+#include "utils/type_reference.h"
namespace art {
@@ -343,7 +344,7 @@
void BuildStackMaps(MemoryRegion region, const DexFile::CodeItem& code_item);
size_t ComputeStackMapsSize();
size_t GetNumberOfJitRoots() const {
- return jit_string_roots_.size();
+ return jit_string_roots_.size() + jit_class_roots_.size();
}
// Fills the `literals` array with literals collected during code generation.
@@ -611,6 +612,8 @@
block_order_(nullptr),
jit_string_roots_(StringReferenceValueComparator(),
graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
+ jit_class_roots_(TypeReferenceValueComparator(),
+ graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
disasm_info_(nullptr),
stats_(stats),
graph_(graph),
@@ -681,6 +684,7 @@
virtual void EmitJitRootPatches(uint8_t* code ATTRIBUTE_UNUSED,
const uint8_t* roots_data ATTRIBUTE_UNUSED) {
DCHECK_EQ(jit_string_roots_.size(), 0u);
+ DCHECK_EQ(jit_class_roots_.size(), 0u);
}
// Frame size required for this method.
@@ -711,7 +715,12 @@
// Maps a StringReference (dex_file, string_index) to the index in the literal table.
// Entries are intially added with a 0 index, and `EmitJitRoots` will compute all the
// indices.
- ArenaSafeMap<StringReference, size_t, StringReferenceValueComparator> jit_string_roots_;
+ ArenaSafeMap<StringReference, uint32_t, StringReferenceValueComparator> jit_string_roots_;
+
+ // Maps a ClassReference (dex_file, type_index) to the index in the literal table.
+ // Entries are intially added with a pointer in the handle zone, and `EmitJitRoots`
+ // will compute all the indices.
+ ArenaSafeMap<TypeReference, uint64_t, TypeReferenceValueComparator> jit_class_roots_;
DisassemblyInformation* disasm_info_;
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index ed6eef1..866f2c5 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -1216,7 +1216,9 @@
boot_image_address_patches_(std::less<uint32_t>(),
graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
jit_string_patches_(StringReferenceValueComparator(),
- graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
+ graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
+ jit_class_patches_(TypeReferenceValueComparator(),
+ graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
// Always save the LR register to mimic Quick.
AddAllocatedRegister(Location::RegisterLocation(LR));
}
@@ -5712,8 +5714,7 @@
break;
case HLoadClass::LoadKind::kBootImageAddress:
break;
- case HLoadClass::LoadKind::kDexCacheAddress:
- DCHECK(Runtime::Current()->UseJitCompilation());
+ case HLoadClass::LoadKind::kJitTableAddress:
break;
case HLoadClass::LoadKind::kDexCachePcRelative:
DCHECK(!Runtime::Current()->UseJitCompilation());
@@ -5814,22 +5815,12 @@
__ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
break;
}
- case HLoadClass::LoadKind::kDexCacheAddress: {
- DCHECK_NE(cls->GetAddress(), 0u);
- uint32_t address = dchecked_integral_cast<uint32_t>(cls->GetAddress());
- // 16-bit LDR immediate has a 5-bit offset multiplied by the size and that gives
- // a 128B range. To try and reduce the number of literals if we load multiple types,
- // simply split the dex cache address to a 128B aligned base loaded from a literal
- // and the remaining offset embedded in the load.
- static_assert(sizeof(GcRoot<mirror::Class>) == 4u, "Expected GC root to be 4 bytes.");
- DCHECK_ALIGNED(cls->GetAddress(), 4u);
- constexpr size_t offset_bits = /* encoded bits */ 5 + /* scale */ 2;
- uint32_t base_address = address & ~MaxInt<uint32_t>(offset_bits);
- uint32_t offset = address & MaxInt<uint32_t>(offset_bits);
- __ LoadLiteral(out, codegen_->DeduplicateDexCacheAddressLiteral(base_address));
- // /* GcRoot<mirror::Class> */ out = *(base_address + offset)
- GenerateGcRootFieldLoad(cls, out_loc, out, offset, read_barrier_option);
- generate_null_check = !cls->IsInDexCache();
+ case HLoadClass::LoadKind::kJitTableAddress: {
+ __ LoadLiteral(out, codegen_->DeduplicateJitClassLiteral(cls->GetDexFile(),
+ cls->GetTypeIndex(),
+ cls->GetAddress()));
+ // /* GcRoot<mirror::Class> */ out = *out
+ GenerateGcRootFieldLoad(cls, out_loc, out, /* offset */ 0, kCompilerReadBarrierOption);
break;
}
case HLoadClass::LoadKind::kDexCachePcRelative: {
@@ -7391,6 +7382,15 @@
[this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
}
+Literal* CodeGeneratorARM::DeduplicateJitClassLiteral(const DexFile& dex_file,
+ dex::TypeIndex type_index,
+ uint64_t address) {
+ jit_class_roots_.Overwrite(TypeReference(&dex_file, type_index), address);
+ return jit_class_patches_.GetOrCreate(
+ TypeReference(&dex_file, type_index),
+ [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
+}
+
template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
inline void CodeGeneratorARM::EmitPcRelativeLinkerPatches(
const ArenaDeque<PcRelativePatchInfo>& infos,
@@ -7707,18 +7707,28 @@
}
}
+static void PatchJitRootUse(uint8_t* code,
+ const uint8_t* roots_data,
+ Literal* literal,
+ uint64_t index_in_table) {
+ DCHECK(literal->GetLabel()->IsBound());
+ uint32_t literal_offset = literal->GetLabel()->Position();
+ uintptr_t address =
+ reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>);
+ uint8_t* data = code + literal_offset;
+ reinterpret_cast<uint32_t*>(data)[0] = dchecked_integral_cast<uint32_t>(address);
+}
+
void CodeGeneratorARM::EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) {
for (const auto& entry : jit_string_patches_) {
const auto& it = jit_string_roots_.find(entry.first);
DCHECK(it != jit_string_roots_.end());
- size_t index_in_table = it->second;
- Literal* literal = entry.second;
- DCHECK(literal->GetLabel()->IsBound());
- uint32_t literal_offset = literal->GetLabel()->Position();
- uintptr_t address =
- reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>);
- uint8_t* data = code + literal_offset;
- reinterpret_cast<uint32_t*>(data)[0] = dchecked_integral_cast<uint32_t>(address);
+ PatchJitRootUse(code, roots_data, entry.second, it->second);
+ }
+ for (const auto& entry : jit_class_patches_) {
+ const auto& it = jit_class_roots_.find(entry.first);
+ DCHECK(it != jit_class_roots_.end());
+ PatchJitRootUse(code, roots_data, entry.second, it->second);
}
}
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index 8230512..b929172 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -491,6 +491,9 @@
Literal* DeduplicateBootImageAddressLiteral(uint32_t address);
Literal* DeduplicateDexCacheAddressLiteral(uint32_t address);
Literal* DeduplicateJitStringLiteral(const DexFile& dex_file, dex::StringIndex string_index);
+ Literal* DeduplicateJitClassLiteral(const DexFile& dex_file,
+ dex::TypeIndex type_index,
+ uint64_t address);
void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE;
@@ -599,9 +602,9 @@
using StringToLiteralMap = ArenaSafeMap<StringReference,
Literal*,
StringReferenceValueComparator>;
- using BootTypeToLiteralMap = ArenaSafeMap<TypeReference,
- Literal*,
- TypeReferenceValueComparator>;
+ using TypeToLiteralMap = ArenaSafeMap<TypeReference,
+ Literal*,
+ TypeReferenceValueComparator>;
Literal* DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map);
Literal* DeduplicateMethodLiteral(MethodReference target_method, MethodToLiteralMap* map);
@@ -638,7 +641,7 @@
// PC-relative String patch info; type depends on configuration (app .bss or boot image PIC).
ArenaDeque<PcRelativePatchInfo> pc_relative_string_patches_;
// Deduplication map for boot type literals for kBootImageLinkTimeAddress.
- BootTypeToLiteralMap boot_image_type_patches_;
+ TypeToLiteralMap boot_image_type_patches_;
// PC-relative type patch info.
ArenaDeque<PcRelativePatchInfo> pc_relative_type_patches_;
// Deduplication map for patchable boot image addresses.
@@ -646,6 +649,8 @@
// Patches for string literals in JIT compiled code.
StringToLiteralMap jit_string_patches_;
+ // Patches for class literals in JIT compiled code.
+ TypeToLiteralMap jit_class_patches_;
DISALLOW_COPY_AND_ASSIGN(CodeGeneratorARM);
};
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 6eebd69..89e5d9e 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -1162,7 +1162,9 @@
boot_image_address_patches_(std::less<uint32_t>(),
graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
jit_string_patches_(StringReferenceValueComparator(),
- graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
+ graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
+ jit_class_patches_(TypeReferenceValueComparator(),
+ graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
// Save the link register (containing the return address) to mimic Quick.
AddAllocatedRegister(LocationFrom(lr));
}
@@ -4182,6 +4184,14 @@
[this]() { return __ CreateLiteralDestroyedWithPool<uint32_t>(/* placeholder */ 0u); });
}
+vixl::aarch64::Literal<uint32_t>* CodeGeneratorARM64::DeduplicateJitClassLiteral(
+ const DexFile& dex_file, dex::TypeIndex type_index, uint64_t address) {
+ jit_class_roots_.Overwrite(TypeReference(&dex_file, type_index), address);
+ return jit_class_patches_.GetOrCreate(
+ TypeReference(&dex_file, type_index),
+ [this]() { return __ CreateLiteralDestroyedWithPool<uint32_t>(/* placeholder */ 0u); });
+}
+
void CodeGeneratorARM64::EmitAdrpPlaceholder(vixl::aarch64::Label* fixup_label,
vixl::aarch64::Register reg) {
DCHECK(reg.IsX());
@@ -4359,7 +4369,7 @@
break;
case HLoadClass::LoadKind::kBootImageAddress:
break;
- case HLoadClass::LoadKind::kDexCacheAddress:
+ case HLoadClass::LoadKind::kJitTableAddress:
DCHECK(Runtime::Current()->UseJitCompilation());
break;
case HLoadClass::LoadKind::kDexCachePcRelative:
@@ -4452,26 +4462,16 @@
__ Ldr(out.W(), codegen_->DeduplicateBootImageAddressLiteral(cls->GetAddress()));
break;
}
- case HLoadClass::LoadKind::kDexCacheAddress: {
- DCHECK_NE(cls->GetAddress(), 0u);
- // LDR immediate has a 12-bit offset multiplied by the size and for 32-bit loads
- // that gives a 16KiB range. To try and reduce the number of literals if we load
- // multiple types, simply split the dex cache address to a 16KiB aligned base
- // loaded from a literal and the remaining offset embedded in the load.
- static_assert(sizeof(GcRoot<mirror::Class>) == 4u, "Expected GC root to be 4 bytes.");
- DCHECK_ALIGNED(cls->GetAddress(), 4u);
- constexpr size_t offset_bits = /* encoded bits */ 12 + /* scale */ 2;
- uint64_t base_address = cls->GetAddress() & ~MaxInt<uint64_t>(offset_bits);
- uint32_t offset = cls->GetAddress() & MaxInt<uint64_t>(offset_bits);
- __ Ldr(out.X(), codegen_->DeduplicateDexCacheAddressLiteral(base_address));
- // /* GcRoot<mirror::Class> */ out = *(base_address + offset)
+ case HLoadClass::LoadKind::kJitTableAddress: {
+ __ Ldr(out, codegen_->DeduplicateJitClassLiteral(cls->GetDexFile(),
+ cls->GetTypeIndex(),
+ cls->GetAddress()));
GenerateGcRootFieldLoad(cls,
out_loc,
out.X(),
- offset,
+ /* offset */ 0,
/* fixup_label */ nullptr,
- read_barrier_option);
- generate_null_check = !cls->IsInDexCache();
+ kCompilerReadBarrierOption);
break;
}
case HLoadClass::LoadKind::kDexCachePcRelative: {
@@ -5782,17 +5782,27 @@
}
}
+static void PatchJitRootUse(uint8_t* code,
+ const uint8_t* roots_data,
+ vixl::aarch64::Literal<uint32_t>* literal,
+ uint64_t index_in_table) {
+ uint32_t literal_offset = literal->GetOffset();
+ uintptr_t address =
+ reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>);
+ uint8_t* data = code + literal_offset;
+ reinterpret_cast<uint32_t*>(data)[0] = dchecked_integral_cast<uint32_t>(address);
+}
+
void CodeGeneratorARM64::EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) {
for (const auto& entry : jit_string_patches_) {
const auto& it = jit_string_roots_.find(entry.first);
DCHECK(it != jit_string_roots_.end());
- size_t index_in_table = it->second;
- vixl::aarch64::Literal<uint32_t>* literal = entry.second;
- uint32_t literal_offset = literal->GetOffset();
- uintptr_t address =
- reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>);
- uint8_t* data = code + literal_offset;
- reinterpret_cast<uint32_t*>(data)[0] = dchecked_integral_cast<uint32_t>(address);
+ PatchJitRootUse(code, roots_data, entry.second, it->second);
+ }
+ for (const auto& entry : jit_class_patches_) {
+ const auto& it = jit_class_roots_.find(entry.first);
+ DCHECK(it != jit_class_roots_.end());
+ PatchJitRootUse(code, roots_data, entry.second, it->second);
}
}
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index 868c8b0..50bbc99 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -569,6 +569,9 @@
vixl::aarch64::Literal<uint64_t>* DeduplicateDexCacheAddressLiteral(uint64_t address);
vixl::aarch64::Literal<uint32_t>* DeduplicateJitStringLiteral(const DexFile& dex_file,
dex::StringIndex string_index);
+ vixl::aarch64::Literal<uint32_t>* DeduplicateJitClassLiteral(const DexFile& dex_file,
+ dex::TypeIndex string_index,
+ uint64_t address);
void EmitAdrpPlaceholder(vixl::aarch64::Label* fixup_label, vixl::aarch64::Register reg);
void EmitAddPlaceholder(vixl::aarch64::Label* fixup_label,
@@ -682,9 +685,9 @@
using StringToLiteralMap = ArenaSafeMap<StringReference,
vixl::aarch64::Literal<uint32_t>*,
StringReferenceValueComparator>;
- using BootTypeToLiteralMap = ArenaSafeMap<TypeReference,
- vixl::aarch64::Literal<uint32_t>*,
- TypeReferenceValueComparator>;
+ using TypeToLiteralMap = ArenaSafeMap<TypeReference,
+ vixl::aarch64::Literal<uint32_t>*,
+ TypeReferenceValueComparator>;
vixl::aarch64::Literal<uint32_t>* DeduplicateUint32Literal(uint32_t value,
Uint32ToLiteralMap* map);
@@ -749,7 +752,7 @@
// PC-relative String patch info; type depends on configuration (app .bss or boot image PIC).
ArenaDeque<PcRelativePatchInfo> pc_relative_string_patches_;
// Deduplication map for boot type literals for kBootImageLinkTimeAddress.
- BootTypeToLiteralMap boot_image_type_patches_;
+ TypeToLiteralMap boot_image_type_patches_;
// PC-relative type patch info.
ArenaDeque<PcRelativePatchInfo> pc_relative_type_patches_;
// Deduplication map for patchable boot image addresses.
@@ -757,6 +760,8 @@
// Patches for string literals in JIT compiled code.
StringToLiteralMap jit_string_patches_;
+ // Patches for class literals in JIT compiled code.
+ TypeToLiteralMap jit_class_patches_;
DISALLOW_COPY_AND_ASSIGN(CodeGeneratorARM64);
};
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index 3a3d2a9..2c6df38 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -5776,7 +5776,7 @@
case HLoadClass::LoadKind::kBootImageAddress:
// TODO(VIXL): Enable it back when literal pools are fixed in VIXL.
return HLoadClass::LoadKind::kDexCacheViaMethod;
- case HLoadClass::LoadKind::kDexCacheAddress:
+ case HLoadClass::LoadKind::kJitTableAddress:
// TODO(VIXL): Enable it back when literal pools are fixed in VIXL.
return HLoadClass::LoadKind::kDexCacheViaMethod;
case HLoadClass::LoadKind::kDexCachePcRelative:
@@ -5868,7 +5868,7 @@
TODO_VIXL32(FATAL);
break;
}
- case HLoadClass::LoadKind::kDexCacheAddress: {
+ case HLoadClass::LoadKind::kJitTableAddress: {
TODO_VIXL32(FATAL);
break;
}
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index ff48f66..cae4161 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -5251,9 +5251,9 @@
break;
case HLoadClass::LoadKind::kBootImageAddress:
break;
- case HLoadClass::LoadKind::kDexCacheAddress:
+ case HLoadClass::LoadKind::kJitTableAddress:
DCHECK(Runtime::Current()->UseJitCompilation());
- fallback_load = false;
+ fallback_load = true;
break;
case HLoadClass::LoadKind::kDexCachePcRelative:
DCHECK(!Runtime::Current()->UseJitCompilation());
@@ -5614,17 +5614,8 @@
codegen_->DeduplicateBootImageAddressLiteral(address));
break;
}
- case HLoadClass::LoadKind::kDexCacheAddress: {
- DCHECK_NE(cls->GetAddress(), 0u);
- uint32_t address = dchecked_integral_cast<uint32_t>(cls->GetAddress());
- static_assert(sizeof(GcRoot<mirror::Class>) == 4u, "Expected GC root to be 4 bytes.");
- DCHECK_ALIGNED(cls->GetAddress(), 4u);
- int16_t offset = Low16Bits(address);
- uint32_t base_address = address - offset; // This accounts for offset sign extension.
- __ Lui(out, High16Bits(base_address));
- // /* GcRoot<mirror::Class> */ out = *(base_address + offset)
- GenerateGcRootFieldLoad(cls, out_loc, out, offset);
- generate_null_check = !cls->IsInDexCache();
+ case HLoadClass::LoadKind::kJitTableAddress: {
+ LOG(FATAL) << "Unimplemented";
break;
}
case HLoadClass::LoadKind::kDexCachePcRelative: {
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index d6e92cc..8612a67 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -1013,6 +1013,7 @@
string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
jit_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
+ jit_class_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
constant_area_start_(-1),
fixups_to_jump_tables_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
method_address_offset_(-1) {
@@ -6034,7 +6035,7 @@
break;
case HLoadClass::LoadKind::kBootImageAddress:
break;
- case HLoadClass::LoadKind::kDexCacheAddress:
+ case HLoadClass::LoadKind::kJitTableAddress:
DCHECK(Runtime::Current()->UseJitCompilation());
break;
case HLoadClass::LoadKind::kDexCacheViaMethod:
@@ -6073,6 +6074,16 @@
locations->SetOut(Location::RequiresRegister());
}
+Label* CodeGeneratorX86::NewJitRootClassPatch(const DexFile& dex_file,
+ dex::TypeIndex dex_index,
+ uint64_t address) {
+ jit_class_roots_.Overwrite(TypeReference(&dex_file, dex_index), address);
+ // Add a patch entry and return the label.
+ jit_class_patches_.emplace_back(dex_file, dex_index.index_);
+ PatchInfo<Label>* info = &jit_class_patches_.back();
+ return &info->label;
+}
+
void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) {
LocationSummary* locations = cls->GetLocations();
if (cls->NeedsAccessCheck()) {
@@ -6124,16 +6135,12 @@
codegen_->RecordSimplePatch();
break;
}
- case HLoadClass::LoadKind::kDexCacheAddress: {
- DCHECK_NE(cls->GetAddress(), 0u);
- uint32_t address = dchecked_integral_cast<uint32_t>(cls->GetAddress());
+ case HLoadClass::LoadKind::kJitTableAddress: {
+ Address address = Address::Absolute(CodeGeneratorX86::kDummy32BitOffset);
+ Label* fixup_label = codegen_->NewJitRootClassPatch(
+ cls->GetDexFile(), cls->GetTypeIndex(), cls->GetAddress());
// /* GcRoot<mirror::Class> */ out = *address
- GenerateGcRootFieldLoad(cls,
- out_loc,
- Address::Absolute(address),
- /* fixup_label */ nullptr,
- read_barrier_option);
- generate_null_check = !cls->IsInDexCache();
+ GenerateGcRootFieldLoad(cls, out_loc, address, fixup_label, kCompilerReadBarrierOption);
break;
}
case HLoadClass::LoadKind::kDexCachePcRelative: {
@@ -7770,18 +7777,31 @@
}
}
+void CodeGeneratorX86::PatchJitRootUse(uint8_t* code,
+ const uint8_t* roots_data,
+ const PatchInfo<Label>& info,
+ uint64_t index_in_table) const {
+ uint32_t code_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
+ uintptr_t address =
+ reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>);
+ typedef __attribute__((__aligned__(1))) uint32_t unaligned_uint32_t;
+ reinterpret_cast<unaligned_uint32_t*>(code + code_offset)[0] =
+ dchecked_integral_cast<uint32_t>(address);
+}
+
void CodeGeneratorX86::EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) {
for (const PatchInfo<Label>& info : jit_string_patches_) {
- const auto& it = jit_string_roots_.find(StringReference(&info.dex_file,
- dex::StringIndex(info.index)));
+ const auto& it = jit_string_roots_.find(
+ StringReference(&info.dex_file, dex::StringIndex(info.index)));
DCHECK(it != jit_string_roots_.end());
- size_t index_in_table = it->second;
- uint32_t code_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
- uintptr_t address =
- reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>);
- typedef __attribute__((__aligned__(1))) uint32_t unaligned_uint32_t;
- reinterpret_cast<unaligned_uint32_t*>(code + code_offset)[0] =
- dchecked_integral_cast<uint32_t>(address);
+ PatchJitRootUse(code, roots_data, info, it->second);
+ }
+
+ for (const PatchInfo<Label>& info : jit_class_patches_) {
+ const auto& it = jit_class_roots_.find(
+ TypeReference(&info.dex_file, dex::TypeIndex(info.index)));
+ DCHECK(it != jit_class_roots_.end());
+ PatchJitRootUse(code, roots_data, info, it->second);
}
}
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 2ae3670..c44da97 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -416,12 +416,17 @@
Label* NewStringBssEntryPatch(HLoadString* load_string);
Label* NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file, uint32_t element_offset);
Label* NewJitRootStringPatch(const DexFile& dex_file, dex::StringIndex dex_index);
+ Label* NewJitRootClassPatch(const DexFile& dex_file, dex::TypeIndex dex_index, uint64_t address);
void MoveFromReturnRegister(Location trg, Primitive::Type type) OVERRIDE;
// Emit linker patches.
void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE;
+ void PatchJitRootUse(uint8_t* code,
+ const uint8_t* roots_data,
+ const PatchInfo<Label>& info,
+ uint64_t index_in_table) const;
void EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) OVERRIDE;
// Emit a write barrier.
@@ -623,6 +628,9 @@
// Patches for string root accesses in JIT compiled code.
ArenaDeque<PatchInfo<Label>> jit_string_patches_;
+ // Patches for class root accesses in JIT compiled code.
+ ArenaDeque<PatchInfo<Label>> jit_class_patches_;
+
// Offset to the start of the constant area in the assembled code.
// Used for fixups to the constant area.
int32_t constant_area_start_;
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 4474dec..7dfc736 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -1260,7 +1260,8 @@
string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
fixups_to_jump_tables_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
- jit_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
+ jit_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
+ jit_class_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
}
@@ -5460,8 +5461,7 @@
break;
case HLoadClass::LoadKind::kBootImageAddress:
break;
- case HLoadClass::LoadKind::kDexCacheAddress:
- DCHECK(Runtime::Current()->UseJitCompilation());
+ case HLoadClass::LoadKind::kJitTableAddress:
break;
case HLoadClass::LoadKind::kDexCachePcRelative:
DCHECK(!Runtime::Current()->UseJitCompilation());
@@ -5500,6 +5500,16 @@
locations->SetOut(Location::RequiresRegister());
}
+Label* CodeGeneratorX86_64::NewJitRootClassPatch(const DexFile& dex_file,
+ dex::TypeIndex dex_index,
+ uint64_t address) {
+ jit_class_roots_.Overwrite(TypeReference(&dex_file, dex_index), address);
+ // Add a patch entry and return the label.
+ jit_class_patches_.emplace_back(dex_file, dex_index.index_);
+ PatchInfo<Label>* info = &jit_class_patches_.back();
+ return &info->label;
+}
+
void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
LocationSummary* locations = cls->GetLocations();
if (cls->NeedsAccessCheck()) {
@@ -5543,26 +5553,13 @@
codegen_->RecordSimplePatch();
break;
}
- case HLoadClass::LoadKind::kDexCacheAddress: {
- DCHECK_NE(cls->GetAddress(), 0u);
+ case HLoadClass::LoadKind::kJitTableAddress: {
+ Address address = Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset,
+ /* no_rip */ true);
+ Label* fixup_label =
+ codegen_->NewJitRootClassPatch(cls->GetDexFile(), cls->GetTypeIndex(), cls->GetAddress());
// /* GcRoot<mirror::Class> */ out = *address
- if (IsUint<32>(cls->GetAddress())) {
- Address address = Address::Absolute(cls->GetAddress(), /* no_rip */ true);
- GenerateGcRootFieldLoad(cls,
- out_loc,
- address,
- /* fixup_label */ nullptr,
- read_barrier_option);
- } else {
- // TODO: Consider using opcode A1, i.e. movl eax, moff32 (with 64-bit address).
- __ movq(out, Immediate(cls->GetAddress()));
- GenerateGcRootFieldLoad(cls,
- out_loc,
- Address(out, 0),
- /* fixup_label */ nullptr,
- read_barrier_option);
- }
- generate_null_check = !cls->IsInDexCache();
+ GenerateGcRootFieldLoad(cls, out_loc, address, fixup_label, kCompilerReadBarrierOption);
break;
}
case HLoadClass::LoadKind::kDexCachePcRelative: {
@@ -7127,18 +7124,31 @@
}
}
+void CodeGeneratorX86_64::PatchJitRootUse(uint8_t* code,
+ const uint8_t* roots_data,
+ const PatchInfo<Label>& info,
+ uint64_t index_in_table) const {
+ uint32_t code_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
+ uintptr_t address =
+ reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>);
+ typedef __attribute__((__aligned__(1))) uint32_t unaligned_uint32_t;
+ reinterpret_cast<unaligned_uint32_t*>(code + code_offset)[0] =
+ dchecked_integral_cast<uint32_t>(address);
+}
+
void CodeGeneratorX86_64::EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) {
for (const PatchInfo<Label>& info : jit_string_patches_) {
- const auto& it = jit_string_roots_.find(StringReference(&info.dex_file,
- dex::StringIndex(info.index)));
+ const auto& it = jit_string_roots_.find(
+ StringReference(&info.dex_file, dex::StringIndex(info.index)));
DCHECK(it != jit_string_roots_.end());
- size_t index_in_table = it->second;
- uint32_t code_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
- uintptr_t address =
- reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>);
- typedef __attribute__((__aligned__(1))) uint32_t unaligned_uint32_t;
- reinterpret_cast<unaligned_uint32_t*>(code + code_offset)[0] =
- dchecked_integral_cast<uint32_t>(address);
+ PatchJitRootUse(code, roots_data, info, it->second);
+ }
+
+ for (const PatchInfo<Label>& info : jit_class_patches_) {
+ const auto& it = jit_class_roots_.find(
+ TypeReference(&info.dex_file, dex::TypeIndex(info.index)));
+ DCHECK(it != jit_class_roots_.end());
+ PatchJitRootUse(code, roots_data, info, it->second);
}
}
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index 2f41f73..391a23b 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -413,11 +413,17 @@
Label* NewStringBssEntryPatch(HLoadString* load_string);
Label* NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file, uint32_t element_offset);
Label* NewJitRootStringPatch(const DexFile& dex_file, dex::StringIndex dex_index);
+ Label* NewJitRootClassPatch(const DexFile& dex_file, dex::TypeIndex dex_index, uint64_t address);
void MoveFromReturnRegister(Location trg, Primitive::Type type) OVERRIDE;
void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE;
+ void PatchJitRootUse(uint8_t* code,
+ const uint8_t* roots_data,
+ const PatchInfo<Label>& info,
+ uint64_t index_in_table) const;
+
void EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) OVERRIDE;
const X86_64InstructionSetFeatures& GetInstructionSetFeatures() const {
@@ -608,6 +614,9 @@
// Patches for string literals in JIT compiled code.
ArenaDeque<PatchInfo<Label>> jit_string_patches_;
+ // Patches for class literals in JIT compiled code.
+ ArenaDeque<PatchInfo<Label>> jit_class_patches_;
+
DISALLOW_COPY_AND_ASSIGN(CodeGeneratorX86_64);
};
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 8d93867..fe4662a 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -1444,7 +1444,7 @@
// optimization that could lead to a HDeoptimize. The following optimizations do not.
HDeadCodeElimination dce(callee_graph, stats_, "dead_code_elimination$inliner");
HConstantFolding fold(callee_graph, "constant_folding$inliner");
- HSharpening sharpening(callee_graph, codegen_, dex_compilation_unit, compiler_driver_);
+ HSharpening sharpening(callee_graph, codegen_, dex_compilation_unit, compiler_driver_, handles_);
InstructionSimplifier simplify(callee_graph, stats_);
IntrinsicsRecognizer intrinsics(callee_graph, stats_);
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 594255c..925d4f1 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -2487,8 +2487,8 @@
return os << "BootImageLinkTimePcRelative";
case HLoadClass::LoadKind::kBootImageAddress:
return os << "BootImageAddress";
- case HLoadClass::LoadKind::kDexCacheAddress:
- return os << "DexCacheAddress";
+ case HLoadClass::LoadKind::kJitTableAddress:
+ return os << "JitTableAddress";
case HLoadClass::LoadKind::kDexCachePcRelative:
return os << "DexCachePcRelative";
case HLoadClass::LoadKind::kDexCacheViaMethod:
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index e3f4d8f..659cdda 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -5493,9 +5493,8 @@
// GetIncludePatchInformation().
kBootImageAddress,
- // Load from the resolved types array at an absolute address.
- // Used for classes outside the boot image referenced by JIT-compiled code.
- kDexCacheAddress,
+ // Load from the root table associated with the JIT compiled method.
+ kJitTableAddress,
// Load from resolved types array in the dex cache using a PC-relative load.
// Used for classes outside boot image when we know that we can access
@@ -5588,7 +5587,6 @@
NeedsAccessCheck();
}
-
bool CanThrow() const OVERRIDE {
return CanCallRuntime();
}
@@ -5613,7 +5611,9 @@
return load_data_.address;
}
- bool NeedsDexCacheOfDeclaringClass() const OVERRIDE { return !IsReferrersClass(); }
+ bool NeedsDexCacheOfDeclaringClass() const OVERRIDE {
+ return !IsReferrersClass();
+ }
static SideEffects SideEffectsForArchRuntimeCalls() {
return SideEffects::CanTriggerGC();
@@ -5672,7 +5672,8 @@
}
static bool HasAddress(LoadKind load_kind) {
- return load_kind == LoadKind::kBootImageAddress || load_kind == LoadKind::kDexCacheAddress;
+ return load_kind == LoadKind::kBootImageAddress ||
+ load_kind == LoadKind::kJitTableAddress;
}
static bool HasDexCacheReference(LoadKind load_kind) {
@@ -5691,7 +5692,7 @@
union {
uint32_t dex_cache_element_index; // Only for dex cache reference.
- uint64_t address; // Up to 64-bit, needed for kDexCacheAddress on 64-bit targets.
+ uint64_t address; // Up to 64-bit, needed for kJitTableAddress on 64-bit targets.
} load_data_;
ReferenceTypeInfo loaded_class_rti_;
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 8ea2b06..64c87dc 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -375,7 +375,8 @@
const DexFile& dex_file,
Handle<mirror::DexCache> dex_cache,
ArtMethod* method,
- bool osr) const;
+ bool osr,
+ VariableSizedHandleScope* handles) const;
void MaybeRunInliner(HGraph* graph,
CodeGenerator* codegen,
@@ -495,7 +496,7 @@
number_of_dex_registers,
/* depth */ 0);
} else if (opt_name == HSharpening::kSharpeningPassName) {
- return new (arena) HSharpening(graph, codegen, dex_compilation_unit, driver);
+ return new (arena) HSharpening(graph, codegen, dex_compilation_unit, driver, handles);
} else if (opt_name == HSelectGenerator::kSelectGeneratorPassName) {
return new (arena) HSelectGenerator(graph, stats);
} else if (opt_name == HInductionVarAnalysis::kInductionPassName) {
@@ -767,7 +768,8 @@
HInductionVarAnalysis* induction = new (arena) HInductionVarAnalysis(graph);
BoundsCheckElimination* bce = new (arena) BoundsCheckElimination(graph, *side_effects, induction);
HLoopOptimization* loop = new (arena) HLoopOptimization(graph, induction);
- HSharpening* sharpening = new (arena) HSharpening(graph, codegen, dex_compilation_unit, driver);
+ HSharpening* sharpening = new (arena) HSharpening(
+ graph, codegen, dex_compilation_unit, driver, handles);
InstructionSimplifier* simplify2 = new (arena) InstructionSimplifier(
graph, stats, "instruction_simplifier$after_inlining");
InstructionSimplifier* simplify3 = new (arena) InstructionSimplifier(
@@ -866,7 +868,8 @@
const DexFile& dex_file,
Handle<mirror::DexCache> dex_cache,
ArtMethod* method,
- bool osr) const {
+ bool osr,
+ VariableSizedHandleScope* handles) const {
MaybeRecordStat(MethodCompilationStat::kAttemptCompilation);
CompilerDriver* compiler_driver = GetCompilerDriver();
InstructionSet instruction_set = compiler_driver->GetInstructionSet();
@@ -976,64 +979,56 @@
compiler_driver,
dump_mutex_);
- VLOG(compiler) << "Building " << pass_observer.GetMethodName();
-
{
- ScopedObjectAccess soa(Thread::Current());
- VariableSizedHandleScope handles(soa.Self());
- // Do not hold `mutator_lock_` between optimizations.
- ScopedThreadSuspension sts(soa.Self(), kNative);
-
- {
- PassScope scope(HGraphBuilder::kBuilderPassName, &pass_observer);
- HGraphBuilder builder(graph,
- &dex_compilation_unit,
- &dex_compilation_unit,
- &dex_file,
- *code_item,
- compiler_driver,
- compilation_stats_.get(),
- interpreter_metadata,
- dex_cache,
- &handles);
- GraphAnalysisResult result = builder.BuildGraph();
- if (result != kAnalysisSuccess) {
- switch (result) {
- case kAnalysisSkipped:
- MaybeRecordStat(MethodCompilationStat::kNotCompiledSkipped);
- break;
- case kAnalysisInvalidBytecode:
- MaybeRecordStat(MethodCompilationStat::kNotCompiledInvalidBytecode);
- break;
- case kAnalysisFailThrowCatchLoop:
- MaybeRecordStat(MethodCompilationStat::kNotCompiledThrowCatchLoop);
- break;
- case kAnalysisFailAmbiguousArrayOp:
- MaybeRecordStat(MethodCompilationStat::kNotCompiledAmbiguousArrayOp);
- break;
- case kAnalysisSuccess:
- UNREACHABLE();
- }
- pass_observer.SetGraphInBadState();
- return nullptr;
+ VLOG(compiler) << "Building " << pass_observer.GetMethodName();
+ PassScope scope(HGraphBuilder::kBuilderPassName, &pass_observer);
+ HGraphBuilder builder(graph,
+ &dex_compilation_unit,
+ &dex_compilation_unit,
+ &dex_file,
+ *code_item,
+ compiler_driver,
+ compilation_stats_.get(),
+ interpreter_metadata,
+ dex_cache,
+ handles);
+ GraphAnalysisResult result = builder.BuildGraph();
+ if (result != kAnalysisSuccess) {
+ switch (result) {
+ case kAnalysisSkipped:
+ MaybeRecordStat(MethodCompilationStat::kNotCompiledSkipped);
+ break;
+ case kAnalysisInvalidBytecode:
+ MaybeRecordStat(MethodCompilationStat::kNotCompiledInvalidBytecode);
+ break;
+ case kAnalysisFailThrowCatchLoop:
+ MaybeRecordStat(MethodCompilationStat::kNotCompiledThrowCatchLoop);
+ break;
+ case kAnalysisFailAmbiguousArrayOp:
+ MaybeRecordStat(MethodCompilationStat::kNotCompiledAmbiguousArrayOp);
+ break;
+ case kAnalysisSuccess:
+ UNREACHABLE();
}
+ pass_observer.SetGraphInBadState();
+ return nullptr;
}
-
- RunOptimizations(graph,
- codegen.get(),
- compiler_driver,
- dex_compilation_unit,
- &pass_observer,
- &handles);
-
- RegisterAllocator::Strategy regalloc_strategy =
- compiler_options.GetRegisterAllocationStrategy();
- AllocateRegisters(graph, codegen.get(), &pass_observer, regalloc_strategy);
-
- codegen->Compile(code_allocator);
- pass_observer.DumpDisassembly();
}
+ RunOptimizations(graph,
+ codegen.get(),
+ compiler_driver,
+ dex_compilation_unit,
+ &pass_observer,
+ handles);
+
+ RegisterAllocator::Strategy regalloc_strategy =
+ compiler_options.GetRegisterAllocationStrategy();
+ AllocateRegisters(graph, codegen.get(), &pass_observer, regalloc_strategy);
+
+ codegen->Compile(code_allocator);
+ pass_observer.DumpDisassembly();
+
return codegen.release();
}
@@ -1055,19 +1050,27 @@
verified_method->GetEncounteredVerificationFailures())) {
ArenaAllocator arena(Runtime::Current()->GetArenaPool());
CodeVectorAllocator code_allocator(&arena);
- std::unique_ptr<CodeGenerator> codegen(
- TryCompile(&arena,
- &code_allocator,
- code_item,
- access_flags,
- invoke_type,
- class_def_idx,
- method_idx,
- jclass_loader,
- dex_file,
- dex_cache,
- nullptr,
- /* osr */ false));
+ std::unique_ptr<CodeGenerator> codegen;
+ {
+ ScopedObjectAccess soa(Thread::Current());
+ VariableSizedHandleScope handles(soa.Self());
+ // Go to native so that we don't block GC during compilation.
+ ScopedThreadSuspension sts(soa.Self(), kNative);
+ codegen.reset(
+ TryCompile(&arena,
+ &code_allocator,
+ code_item,
+ access_flags,
+ invoke_type,
+ class_def_idx,
+ method_idx,
+ jclass_loader,
+ dex_file,
+ dex_cache,
+ nullptr,
+ /* osr */ false,
+ &handles));
+ }
if (codegen.get() != nullptr) {
MaybeRecordStat(MethodCompilationStat::kCompiled);
method = Emit(&arena, &code_allocator, codegen.get(), compiler_driver, code_item);
@@ -1138,6 +1141,8 @@
ArenaAllocator arena(Runtime::Current()->GetJitArenaPool());
CodeVectorAllocator code_allocator(&arena);
+ VariableSizedHandleScope handles(self);
+
std::unique_ptr<CodeGenerator> codegen;
{
// Go to native so that we don't block GC during compilation.
@@ -1154,7 +1159,8 @@
*dex_file,
dex_cache,
method,
- osr));
+ osr,
+ &handles));
if (codegen.get() == nullptr) {
return false;
}
diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc
index daf160a..bbbb1a1 100644
--- a/compiler/optimizing/sharpening.cc
+++ b/compiler/optimizing/sharpening.cc
@@ -151,7 +151,7 @@
bool is_in_dex_cache = false;
bool is_in_boot_image = false;
- HLoadClass::LoadKind desired_load_kind;
+ HLoadClass::LoadKind desired_load_kind = static_cast<HLoadClass::LoadKind>(-1);
uint64_t address = 0u; // Class or dex cache element address.
{
ScopedObjectAccess soa(Thread::Current());
@@ -190,18 +190,19 @@
// TODO: Use direct pointers for all non-moving spaces, not just boot image. Bug: 29530787
desired_load_kind = HLoadClass::LoadKind::kBootImageAddress;
address = reinterpret_cast64<uint64_t>(klass);
+ } else if (is_in_dex_cache) {
+ desired_load_kind = HLoadClass::LoadKind::kJitTableAddress;
+ // We store in the address field the location of the stack reference maintained
+ // by the handle. We do this now so that the code generation does not need to figure
+ // out which class loader to use.
+ address = reinterpret_cast<uint64_t>(handles_->NewHandle(klass).GetReference());
} else {
- // Note: If the class is not in the dex cache or isn't initialized, the
- // instruction needs environment and will not be inlined across dex files.
- // Within a dex file, the slow-path helper loads the correct class and
- // inlined frames are used correctly for OOM stack trace.
- // TODO: Write a test for this. Bug: 29416588
- desired_load_kind = HLoadClass::LoadKind::kDexCacheAddress;
- void* dex_cache_element_address = &dex_cache->GetResolvedTypes()[type_index.index_];
- address = reinterpret_cast64<uint64_t>(dex_cache_element_address);
+ // Class not loaded yet. Fallback to the dex cache.
+ // TODO(ngeoffray): Generate HDeoptimize instead.
+ desired_load_kind = HLoadClass::LoadKind::kDexCacheViaMethod;
}
- // AOT app compilation. Check if the class is in the boot image.
} else if (is_in_boot_image && !codegen_->GetCompilerOptions().GetCompilePic()) {
+ // AOT app compilation. Check if the class is in the boot image.
desired_load_kind = HLoadClass::LoadKind::kBootImageAddress;
address = reinterpret_cast64<uint64_t>(klass);
} else {
@@ -215,6 +216,7 @@
}
}
}
+ DCHECK_NE(desired_load_kind, static_cast<HLoadClass::LoadKind>(-1));
if (is_in_boot_image) {
load_class->MarkInBootImage();
@@ -245,7 +247,7 @@
load_class->SetLoadKindWithTypeReference(load_kind, dex_file, type_index);
break;
case HLoadClass::LoadKind::kBootImageAddress:
- case HLoadClass::LoadKind::kDexCacheAddress:
+ case HLoadClass::LoadKind::kJitTableAddress:
DCHECK_NE(address, 0u);
load_class->SetLoadKindWithAddress(load_kind, address);
break;
diff --git a/compiler/optimizing/sharpening.h b/compiler/optimizing/sharpening.h
index d35ae66..7418954 100644
--- a/compiler/optimizing/sharpening.h
+++ b/compiler/optimizing/sharpening.h
@@ -35,11 +35,13 @@
HSharpening(HGraph* graph,
CodeGenerator* codegen,
const DexCompilationUnit& compilation_unit,
- CompilerDriver* compiler_driver)
+ CompilerDriver* compiler_driver,
+ VariableSizedHandleScope* handles)
: HOptimization(graph, kSharpeningPassName),
codegen_(codegen),
compilation_unit_(compilation_unit),
- compiler_driver_(compiler_driver) { }
+ compiler_driver_(compiler_driver),
+ handles_(handles) { }
void Run() OVERRIDE;
@@ -53,6 +55,7 @@
CodeGenerator* codegen_;
const DexCompilationUnit& compilation_unit_;
CompilerDriver* compiler_driver_;
+ VariableSizedHandleScope* handles_;
};
} // namespace art
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 93f50ad..1b0ad83 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -297,10 +297,11 @@
ObjPtr<mirror::Object> object = roots->Get(i);
if (kIsDebugBuild) {
// Ensure the string is strongly interned. b/32995596
- CHECK(object->IsString());
- ObjPtr<mirror::String> str = reinterpret_cast<mirror::String*>(object.Ptr());
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- CHECK(class_linker->GetInternTable()->LookupStrong(Thread::Current(), str) != nullptr);
+ if (object->IsString()) {
+ ObjPtr<mirror::String> str = reinterpret_cast<mirror::String*>(object.Ptr());
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ CHECK(class_linker->GetInternTable()->LookupStrong(Thread::Current(), str) != nullptr);
+ }
}
gc_roots[i] = GcRoot<mirror::Object>(object);
}
@@ -316,6 +317,31 @@
return data - ComputeRootTableSize(roots);
}
+// Helper for the GC to process a weak class in a JIT root table.
+static inline void ProcessWeakClass(GcRoot<mirror::Class>* root_ptr, IsMarkedVisitor* visitor)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ // This does not need a read barrier because this is called by GC.
+ mirror::Class* cls = root_ptr->Read<kWithoutReadBarrier>();
+ if (cls != nullptr) {
+ DCHECK((cls->IsClass<kDefaultVerifyFlags, kWithoutReadBarrier>()));
+ // Look at the classloader of the class to know if it has been unloaded.
+ // This does not need a read barrier because this is called by GC.
+ mirror::Object* class_loader =
+ cls->GetClassLoader<kDefaultVerifyFlags, kWithoutReadBarrier>();
+ if (class_loader == nullptr || visitor->IsMarked(class_loader) != nullptr) {
+ // The class loader is live, update the entry if the class has moved.
+ mirror::Class* new_cls = down_cast<mirror::Class*>(visitor->IsMarked(cls));
+ // Note that new_object can be null for CMS and newly allocated objects.
+ if (new_cls != nullptr && new_cls != cls) {
+ *root_ptr = GcRoot<mirror::Class>(new_cls);
+ }
+ } else {
+ // The class loader is not live, clear the entry.
+ *root_ptr = GcRoot<mirror::Class>(nullptr);
+ }
+ }
+}
+
void JitCodeCache::SweepRootTables(IsMarkedVisitor* visitor) {
MutexLock mu(Thread::Current(), lock_);
for (const auto& entry : method_code_map_) {
@@ -325,17 +351,22 @@
for (uint32_t i = 0; i < number_of_roots; ++i) {
// This does not need a read barrier because this is called by GC.
mirror::Object* object = roots[i].Read<kWithoutReadBarrier>();
- DCHECK(object != nullptr);
- mirror::Object* new_object = visitor->IsMarked(object);
- // We know the string is marked because it's a strongly-interned string that
- // is always alive. The IsMarked implementation of the CMS collector returns
- // null for newly allocated objects, but we know those haven't moved. Therefore,
- // only update the entry if we get a different non-null string.
- // TODO: Do not use IsMarked for j.l.Class, and adjust once we move this method
- // out of the weak access/creation pause. b/32167580
- if (new_object != nullptr && new_object != object) {
- DCHECK(new_object->IsString());
- roots[i] = GcRoot<mirror::Object>(new_object);
+ if (object == nullptr) {
+ // entry got deleted in a previous sweep.
+ } else if (object->IsString<kDefaultVerifyFlags, kWithoutReadBarrier>()) {
+ mirror::Object* new_object = visitor->IsMarked(object);
+ // We know the string is marked because it's a strongly-interned string that
+ // is always alive. The IsMarked implementation of the CMS collector returns
+ // null for newly allocated objects, but we know those haven't moved. Therefore,
+ // only update the entry if we get a different non-null string.
+ // TODO: Do not use IsMarked for j.l.Class, and adjust once we move this method
+ // out of the weak access/creation pause. b/32167580
+ if (new_object != nullptr && new_object != object) {
+ DCHECK(new_object->IsString());
+ roots[i] = GcRoot<mirror::Object>(new_object);
+ }
+ } else {
+ ProcessWeakClass(reinterpret_cast<GcRoot<mirror::Class>*>(&roots[i]), visitor);
}
}
}
@@ -344,26 +375,7 @@
for (size_t i = 0; i < info->number_of_inline_caches_; ++i) {
InlineCache* cache = &info->cache_[i];
for (size_t j = 0; j < InlineCache::kIndividualCacheSize; ++j) {
- // This does not need a read barrier because this is called by GC.
- mirror::Class* cls = cache->classes_[j].Read<kWithoutReadBarrier>();
- if (cls != nullptr) {
- // Look at the classloader of the class to know if it has been
- // unloaded.
- // This does not need a read barrier because this is called by GC.
- mirror::Object* class_loader =
- cls->GetClassLoader<kDefaultVerifyFlags, kWithoutReadBarrier>();
- if (class_loader == nullptr || visitor->IsMarked(class_loader) != nullptr) {
- // The class loader is live, update the entry if the class has moved.
- mirror::Class* new_cls = down_cast<mirror::Class*>(visitor->IsMarked(cls));
- // Note that new_object can be null for CMS and newly allocated objects.
- if (new_cls != nullptr && new_cls != cls) {
- cache->classes_[j] = GcRoot<mirror::Class>(new_cls);
- }
- } else {
- // The class loader is not live, clear the entry.
- cache->classes_[j] = GcRoot<mirror::Class>(nullptr);
- }
- }
+ ProcessWeakClass(&cache->classes_[j], visitor);
}
}
}