summaryrefslogtreecommitdiff
path: root/compiler/optimizing
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing')
-rw-r--r--compiler/optimizing/code_generator.h37
-rw-r--r--compiler/optimizing/code_generator_arm.cc181
-rw-r--r--compiler/optimizing/code_generator_arm.h8
-rw-r--r--compiler/optimizing/code_generator_arm64.cc201
-rw-r--r--compiler/optimizing/code_generator_arm64.h16
-rw-r--r--compiler/optimizing/code_generator_mips.cc198
-rw-r--r--compiler/optimizing/code_generator_mips.h8
-rw-r--r--compiler/optimizing/code_generator_x86.cc213
-rw-r--r--compiler/optimizing/code_generator_x86.h28
-rw-r--r--compiler/optimizing/code_generator_x86_64.cc187
-rw-r--r--compiler/optimizing/code_generator_x86_64.h29
-rw-r--r--compiler/optimizing/dex_cache_array_fixups_arm.cc15
-rw-r--r--compiler/optimizing/dex_cache_array_fixups_mips.cc15
-rw-r--r--compiler/optimizing/intrinsics_x86.cc154
-rw-r--r--compiler/optimizing/intrinsics_x86_64.cc127
-rw-r--r--compiler/optimizing/nodes.cc10
-rw-r--r--compiler/optimizing/nodes.h45
-rw-r--r--compiler/optimizing/pc_relative_fixups_mips.cc1
-rw-r--r--compiler/optimizing/pc_relative_fixups_x86.cc2
-rw-r--r--compiler/optimizing/sharpening.cc14
20 files changed, 790 insertions, 699 deletions
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 49f4f18390..85002045a3 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -531,15 +531,40 @@ class CodeGenerator : public DeletableArenaObject<kArenaAllocCodeGenerator> {
uint32_t GetReferenceDisableFlagOffset() const;
protected:
- // Patch info used for recording locations of required linker patches and their targets,
- // i.e. target method, string, type or code identified by their dex file and index.
+ // Method patch info used for recording locations of required linker patches and
+ // target methods. The target method can be used for various purposes, whether for
+ // patching the address of the method or the code pointer or a PC-relative call.
template <typename LabelType>
- struct PatchInfo {
- PatchInfo(const DexFile& target_dex_file, uint32_t target_index)
- : dex_file(target_dex_file), index(target_index) { }
+ struct MethodPatchInfo {
+ explicit MethodPatchInfo(MethodReference m) : target_method(m), label() { }
+
+ MethodReference target_method;
+ LabelType label;
+ };
+
+ // String patch info used for recording locations of required linker patches and
+ // target strings. The actual string address can be absolute or PC-relative.
+ template <typename LabelType>
+ struct StringPatchInfo {
+ StringPatchInfo(const DexFile& df, uint32_t index)
+ : dex_file(df), string_index(index), label() { }
+
+ const DexFile& dex_file;
+ uint32_t string_index;
+ LabelType label;
+ };
+
+ // Type patch info used for recording locations of required linker patches and
+ // target types. The actual type address can be absolute or PC-relative.
+ // TODO: Consider merging with MethodPatchInfo and StringPatchInfo - all these
+ // classes contain the dex file, some index and the label.
+ template <typename LabelType>
+ struct TypePatchInfo {
+ TypePatchInfo(const DexFile& df, uint32_t index)
+ : dex_file(df), type_index(index), label() { }
const DexFile& dex_file;
- uint32_t index;
+ uint32_t type_index;
LabelType label;
};
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 9870876879..681988d2ac 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -422,50 +422,6 @@ class LoadClassSlowPathARM : public SlowPathCodeARM {
DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM);
};
-class LoadStringSlowPathARM : public SlowPathCodeARM {
- public:
- explicit LoadStringSlowPathARM(HLoadString* instruction) : SlowPathCodeARM(instruction) {}
-
- void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
- LocationSummary* locations = instruction_->GetLocations();
- DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
-
- CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
- __ Bind(GetEntryLabel());
- SaveLiveRegisters(codegen, locations);
-
- InvokeRuntimeCallingConvention calling_convention;
- HLoadString* load = instruction_->AsLoadString();
- const uint32_t string_index = load->GetStringIndex();
- __ LoadImmediate(calling_convention.GetRegisterAt(0), string_index);
- arm_codegen->InvokeRuntime(kQuickResolveString, instruction_, instruction_->GetDexPc(), this);
- CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
- arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
-
- RestoreLiveRegisters(codegen, locations);
-
- // Store the resolved String to the BSS entry.
- // TODO: Change art_quick_resolve_string to kSaveEverything and use a temporary for the
- // .bss entry address in the fast path, so that we can avoid another calculation here.
- CodeGeneratorARM::PcRelativePatchInfo* labels =
- arm_codegen->NewPcRelativeStringPatch(load->GetDexFile(), string_index);
- __ BindTrackedLabel(&labels->movw_label);
- __ movw(IP, /* placeholder */ 0u);
- __ BindTrackedLabel(&labels->movt_label);
- __ movt(IP, /* placeholder */ 0u);
- __ BindTrackedLabel(&labels->add_pc_label);
- __ add(IP, IP, ShifterOperand(PC));
- __ str(locations->Out().AsRegister<Register>(), Address(IP));
-
- __ b(GetExitLabel());
- }
-
- const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathARM"; }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM);
-};
-
class TypeCheckSlowPathARM : public SlowPathCodeARM {
public:
TypeCheckSlowPathARM(HInstruction* instruction, bool is_fatal)
@@ -5685,8 +5641,15 @@ HLoadString::LoadKind CodeGeneratorARM::GetSupportedLoadStringKind(
case HLoadString::LoadKind::kDexCacheAddress:
DCHECK(Runtime::Current()->UseJitCompilation());
break;
- case HLoadString::LoadKind::kBssEntry:
+ case HLoadString::LoadKind::kDexCachePcRelative:
DCHECK(!Runtime::Current()->UseJitCompilation());
+ // We disable pc-relative load when there is an irreducible loop, as the optimization
+ // is incompatible with it.
+ // TODO: Create as many ArmDexCacheArraysBase instructions as needed for methods
+ // with irreducible loops.
+ if (GetGraph()->HasIrreducibleLoops()) {
+ return HLoadString::LoadKind::kDexCacheViaMethod;
+ }
break;
case HLoadString::LoadKind::kDexCacheViaMethod:
break;
@@ -5696,13 +5659,12 @@ HLoadString::LoadKind CodeGeneratorARM::GetSupportedLoadStringKind(
void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
LocationSummary::CallKind call_kind = load->NeedsEnvironment()
- ? ((load->GetLoadKind() == HLoadString::LoadKind::kDexCacheViaMethod)
- ? LocationSummary::kCallOnMainOnly
- : LocationSummary::kCallOnSlowPath)
+ ? LocationSummary::kCallOnMainOnly
: LocationSummary::kNoCall;
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
HLoadString::LoadKind load_kind = load->GetLoadKind();
+ DCHECK(load_kind != HLoadString::LoadKind::kDexCachePcRelative) << "Not supported";
if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod) {
locations->SetInAt(0, Location::RequiresRegister());
locations->SetOut(Location::RegisterLocation(R0));
@@ -5724,7 +5686,6 @@ void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
return; // No dex cache slow path.
}
case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
- DCHECK(codegen_->GetCompilerOptions().IsBootImage());
CodeGeneratorARM::PcRelativePatchInfo* labels =
codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
__ BindTrackedLabel(&labels->movw_label);
@@ -5741,23 +5702,6 @@ void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
__ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
return; // No dex cache slow path.
}
- case HLoadString::LoadKind::kBssEntry: {
- DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
- CodeGeneratorARM::PcRelativePatchInfo* labels =
- codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
- __ BindTrackedLabel(&labels->movw_label);
- __ movw(out, /* placeholder */ 0u);
- __ BindTrackedLabel(&labels->movt_label);
- __ movt(out, /* placeholder */ 0u);
- __ BindTrackedLabel(&labels->add_pc_label);
- __ add(out, out, ShifterOperand(PC));
- GenerateGcRootFieldLoad(load, out_loc, out, 0);
- SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
- codegen_->AddSlowPath(slow_path);
- __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
- __ Bind(slow_path->GetExitLabel());
- return;
- }
default:
break;
}
@@ -6906,8 +6850,7 @@ void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
__ bl(GetFrameEntryLabel());
break;
case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative:
- relative_call_patches_.emplace_back(*invoke->GetTargetMethod().dex_file,
- invoke->GetTargetMethod().dex_method_index);
+ relative_call_patches_.emplace_back(invoke->GetTargetMethod());
__ BindTrackedLabel(&relative_call_patches_.back().label);
// Arbitrarily branch to the BL itself, override at link time.
__ bl(&relative_call_patches_.back().label);
@@ -7009,37 +6952,17 @@ Literal* CodeGeneratorARM::DeduplicateDexCacheAddressLiteral(uint32_t address) {
return DeduplicateUint32Literal(address, &uint32_literals_);
}
-template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
-inline void CodeGeneratorARM::EmitPcRelativeLinkerPatches(
- const ArenaDeque<PcRelativePatchInfo>& infos,
- ArenaVector<LinkerPatch>* linker_patches) {
- for (const PcRelativePatchInfo& info : infos) {
- const DexFile& dex_file = info.target_dex_file;
- size_t offset_or_index = info.offset_or_index;
- DCHECK(info.add_pc_label.IsBound());
- uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
- // Add MOVW patch.
- DCHECK(info.movw_label.IsBound());
- uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
- linker_patches->push_back(Factory(movw_offset, &dex_file, add_pc_offset, offset_or_index));
- // Add MOVT patch.
- DCHECK(info.movt_label.IsBound());
- uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
- linker_patches->push_back(Factory(movt_offset, &dex_file, add_pc_offset, offset_or_index));
- }
-}
-
void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
DCHECK(linker_patches->empty());
size_t size =
method_patches_.size() +
call_patches_.size() +
relative_call_patches_.size() +
- /* MOVW+MOVT for each entry */ 2u * pc_relative_dex_cache_patches_.size() +
+ /* MOVW+MOVT for each base */ 2u * pc_relative_dex_cache_patches_.size() +
boot_image_string_patches_.size() +
- /* MOVW+MOVT for each entry */ 2u * pc_relative_string_patches_.size() +
+ /* MOVW+MOVT for each base */ 2u * pc_relative_string_patches_.size() +
boot_image_type_patches_.size() +
- /* MOVW+MOVT for each entry */ 2u * pc_relative_type_patches_.size() +
+ /* MOVW+MOVT for each base */ 2u * pc_relative_type_patches_.size() +
boot_image_address_patches_.size();
linker_patches->reserve(size);
for (const auto& entry : method_patches_) {
@@ -7060,13 +6983,32 @@ void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patche
target_method.dex_file,
target_method.dex_method_index));
}
- for (const PatchInfo<Label>& info : relative_call_patches_) {
+ for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
uint32_t literal_offset = info.label.Position();
- linker_patches->push_back(
- LinkerPatch::RelativeCodePatch(literal_offset, &info.dex_file, info.index));
+ linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
+ info.target_method.dex_file,
+ info.target_method.dex_method_index));
+ }
+ for (const PcRelativePatchInfo& info : pc_relative_dex_cache_patches_) {
+ const DexFile& dex_file = info.target_dex_file;
+ size_t base_element_offset = info.offset_or_index;
+ DCHECK(info.add_pc_label.IsBound());
+ uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
+ // Add MOVW patch.
+ DCHECK(info.movw_label.IsBound());
+ uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
+ linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(movw_offset,
+ &dex_file,
+ add_pc_offset,
+ base_element_offset));
+ // Add MOVT patch.
+ DCHECK(info.movt_label.IsBound());
+ uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
+ linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(movt_offset,
+ &dex_file,
+ add_pc_offset,
+ base_element_offset));
}
- EmitPcRelativeLinkerPatches<LinkerPatch::DexCacheArrayPatch>(pc_relative_dex_cache_patches_,
- linker_patches);
for (const auto& entry : boot_image_string_patches_) {
const StringReference& target_string = entry.first;
Literal* literal = entry.second;
@@ -7076,12 +7018,25 @@ void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patche
target_string.dex_file,
target_string.string_index));
}
- if (!GetCompilerOptions().IsBootImage()) {
- EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(pc_relative_string_patches_,
- linker_patches);
- } else {
- EmitPcRelativeLinkerPatches<LinkerPatch::RelativeStringPatch>(pc_relative_string_patches_,
- linker_patches);
+ for (const PcRelativePatchInfo& info : pc_relative_string_patches_) {
+ const DexFile& dex_file = info.target_dex_file;
+ uint32_t string_index = info.offset_or_index;
+ DCHECK(info.add_pc_label.IsBound());
+ uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
+ // Add MOVW patch.
+ DCHECK(info.movw_label.IsBound());
+ uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
+ linker_patches->push_back(LinkerPatch::RelativeStringPatch(movw_offset,
+ &dex_file,
+ add_pc_offset,
+ string_index));
+ // Add MOVT patch.
+ DCHECK(info.movt_label.IsBound());
+ uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
+ linker_patches->push_back(LinkerPatch::RelativeStringPatch(movt_offset,
+ &dex_file,
+ add_pc_offset,
+ string_index));
}
for (const auto& entry : boot_image_type_patches_) {
const TypeReference& target_type = entry.first;
@@ -7092,8 +7047,26 @@ void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patche
target_type.dex_file,
target_type.type_index));
}
- EmitPcRelativeLinkerPatches<LinkerPatch::RelativeTypePatch>(pc_relative_type_patches_,
- linker_patches);
+ for (const PcRelativePatchInfo& info : pc_relative_type_patches_) {
+ const DexFile& dex_file = info.target_dex_file;
+ uint32_t type_index = info.offset_or_index;
+ DCHECK(info.add_pc_label.IsBound());
+ uint32_t add_pc_offset = dchecked_integral_cast<uint32_t>(info.add_pc_label.Position());
+ // Add MOVW patch.
+ DCHECK(info.movw_label.IsBound());
+ uint32_t movw_offset = dchecked_integral_cast<uint32_t>(info.movw_label.Position());
+ linker_patches->push_back(LinkerPatch::RelativeTypePatch(movw_offset,
+ &dex_file,
+ add_pc_offset,
+ type_index));
+ // Add MOVT patch.
+ DCHECK(info.movt_label.IsBound());
+ uint32_t movt_offset = dchecked_integral_cast<uint32_t>(info.movt_label.Position());
+ linker_patches->push_back(LinkerPatch::RelativeTypePatch(movt_offset,
+ &dex_file,
+ add_pc_offset,
+ type_index));
+ }
for (const auto& entry : boot_image_address_patches_) {
DCHECK(GetCompilerOptions().GetIncludePatchInformation());
Literal* literal = entry.second;
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index ef2e23f258..6416d40f7f 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -593,10 +593,6 @@ class CodeGeneratorARM : public CodeGenerator {
uint32_t offset_or_index,
ArenaDeque<PcRelativePatchInfo>* patches);
- template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
- static void EmitPcRelativeLinkerPatches(const ArenaDeque<PcRelativePatchInfo>& infos,
- ArenaVector<LinkerPatch>* linker_patches);
-
// Labels for each block that will be compiled.
Label* block_labels_; // Indexed by block id.
Label frame_entry_label_;
@@ -613,12 +609,12 @@ class CodeGeneratorARM : public CodeGenerator {
MethodToLiteralMap call_patches_;
// Relative call patch info.
// Using ArenaDeque<> which retains element addresses on push/emplace_back().
- ArenaDeque<PatchInfo<Label>> relative_call_patches_;
+ ArenaDeque<MethodPatchInfo<Label>> relative_call_patches_;
// PC-relative patch info for each HArmDexCacheArraysBase.
ArenaDeque<PcRelativePatchInfo> pc_relative_dex_cache_patches_;
// Deduplication map for boot string literals for kBootImageLinkTimeAddress.
BootStringToLiteralMap boot_image_string_patches_;
- // PC-relative String patch info; type depends on configuration (app .bss or boot image PIC).
+ // PC-relative String patch info.
ArenaDeque<PcRelativePatchInfo> pc_relative_string_patches_;
// Deduplication map for boot type literals for kBootImageLinkTimeAddress.
BootTypeToLiteralMap boot_image_type_patches_;
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 969d653f97..4f7f36bb5a 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -329,55 +329,6 @@ class LoadClassSlowPathARM64 : public SlowPathCodeARM64 {
DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM64);
};
-class LoadStringSlowPathARM64 : public SlowPathCodeARM64 {
- public:
- explicit LoadStringSlowPathARM64(HLoadString* instruction) : SlowPathCodeARM64(instruction) {}
-
- void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
- LocationSummary* locations = instruction_->GetLocations();
- DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
- CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
-
- __ Bind(GetEntryLabel());
- SaveLiveRegisters(codegen, locations);
-
- InvokeRuntimeCallingConvention calling_convention;
- const uint32_t string_index = instruction_->AsLoadString()->GetStringIndex();
- __ Mov(calling_convention.GetRegisterAt(0).W(), string_index);
- arm64_codegen->InvokeRuntime(kQuickResolveString, instruction_, instruction_->GetDexPc(), this);
- CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
- Primitive::Type type = instruction_->GetType();
- arm64_codegen->MoveLocation(locations->Out(), calling_convention.GetReturnLocation(type), type);
-
- RestoreLiveRegisters(codegen, locations);
-
- // Store the resolved String to the BSS entry.
- UseScratchRegisterScope temps(arm64_codegen->GetVIXLAssembler());
- Register temp = temps.AcquireX();
- const DexFile& dex_file = instruction_->AsLoadString()->GetDexFile();
- // TODO: Change art_quick_resolve_string to kSaveEverything and use a temporary
- // for the ADRP in the fast path, so that we can avoid the ADRP here.
- vixl::aarch64::Label* adrp_label =
- arm64_codegen->NewPcRelativeStringPatch(dex_file, string_index);
- arm64_codegen->EmitAdrpPlaceholder(adrp_label, temp);
- vixl::aarch64::Label* strp_label =
- arm64_codegen->NewPcRelativeStringPatch(dex_file, string_index, adrp_label);
- {
- SingleEmissionCheckScope guard(arm64_codegen->GetVIXLAssembler());
- __ Bind(strp_label);
- __ str(RegisterFrom(locations->Out(), Primitive::kPrimNot),
- MemOperand(temp, /* offset placeholder */ 0));
- }
-
- __ B(GetExitLabel());
- }
-
- const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathARM64"; }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM64);
-};
-
class NullCheckSlowPathARM64 : public SlowPathCodeARM64 {
public:
explicit NullCheckSlowPathARM64(HNullCheck* instr) : SlowPathCodeARM64(instr) {}
@@ -3680,11 +3631,19 @@ void CodeGeneratorARM64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invok
const DexFile& dex_file = invoke->GetDexFile();
uint32_t element_offset = invoke->GetDexCacheArrayOffset();
vixl::aarch64::Label* adrp_label = NewPcRelativeDexCacheArrayPatch(dex_file, element_offset);
- EmitAdrpPlaceholder(adrp_label, XRegisterFrom(temp));
+ {
+ SingleEmissionCheckScope guard(GetVIXLAssembler());
+ __ Bind(adrp_label);
+ __ adrp(XRegisterFrom(temp), /* offset placeholder */ 0);
+ }
// Add LDR with its PC-relative DexCache access patch.
vixl::aarch64::Label* ldr_label =
NewPcRelativeDexCacheArrayPatch(dex_file, element_offset, adrp_label);
- EmitLdrOffsetPlaceholder(ldr_label, XRegisterFrom(temp), XRegisterFrom(temp));
+ {
+ SingleEmissionCheckScope guard(GetVIXLAssembler());
+ __ Bind(ldr_label);
+ __ ldr(XRegisterFrom(temp), MemOperand(XRegisterFrom(temp), /* offset placeholder */ 0));
+ }
break;
}
case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
@@ -3717,8 +3676,7 @@ void CodeGeneratorARM64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invok
__ Bl(&frame_entry_label_);
break;
case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative: {
- relative_call_patches_.emplace_back(*invoke->GetTargetMethod().dex_file,
- invoke->GetTargetMethod().dex_method_index);
+ relative_call_patches_.emplace_back(invoke->GetTargetMethod());
vixl::aarch64::Label* label = &relative_call_patches_.back().label;
SingleEmissionCheckScope guard(GetVIXLAssembler());
__ Bind(label);
@@ -3840,45 +3798,6 @@ vixl::aarch64::Literal<uint64_t>* CodeGeneratorARM64::DeduplicateDexCacheAddress
return DeduplicateUint64Literal(address);
}
-void CodeGeneratorARM64::EmitAdrpPlaceholder(vixl::aarch64::Label* fixup_label,
- vixl::aarch64::Register reg) {
- DCHECK(reg.IsX());
- SingleEmissionCheckScope guard(GetVIXLAssembler());
- __ Bind(fixup_label);
- __ adrp(reg, /* offset placeholder */ 0);
-}
-
-void CodeGeneratorARM64::EmitAddPlaceholder(vixl::aarch64::Label* fixup_label,
- vixl::aarch64::Register out,
- vixl::aarch64::Register base) {
- DCHECK(out.IsX());
- DCHECK(base.IsX());
- SingleEmissionCheckScope guard(GetVIXLAssembler());
- __ Bind(fixup_label);
- __ add(out, base, Operand(/* offset placeholder */ 0));
-}
-
-void CodeGeneratorARM64::EmitLdrOffsetPlaceholder(vixl::aarch64::Label* fixup_label,
- vixl::aarch64::Register out,
- vixl::aarch64::Register base) {
- DCHECK(base.IsX());
- SingleEmissionCheckScope guard(GetVIXLAssembler());
- __ Bind(fixup_label);
- __ ldr(out, MemOperand(base, /* offset placeholder */ 0));
-}
-
-template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
-inline void CodeGeneratorARM64::EmitPcRelativeLinkerPatches(
- const ArenaDeque<PcRelativePatchInfo>& infos,
- ArenaVector<LinkerPatch>* linker_patches) {
- for (const PcRelativePatchInfo& info : infos) {
- linker_patches->push_back(Factory(info.label.GetLocation(),
- &info.target_dex_file,
- info.pc_insn_label->GetLocation(),
- info.offset_or_index));
- }
-}
-
void CodeGeneratorARM64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
DCHECK(linker_patches->empty());
size_t size =
@@ -3906,9 +3825,10 @@ void CodeGeneratorARM64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patc
target_method.dex_file,
target_method.dex_method_index));
}
- for (const PatchInfo<vixl::aarch64::Label>& info : relative_call_patches_) {
- linker_patches->push_back(
- LinkerPatch::RelativeCodePatch(info.label.GetLocation(), &info.dex_file, info.index));
+ for (const MethodPatchInfo<vixl::aarch64::Label>& info : relative_call_patches_) {
+ linker_patches->push_back(LinkerPatch::RelativeCodePatch(info.label.GetLocation(),
+ info.target_method.dex_file,
+ info.target_method.dex_method_index));
}
for (const PcRelativePatchInfo& info : pc_relative_dex_cache_patches_) {
linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(info.label.GetLocation(),
@@ -3923,12 +3843,11 @@ void CodeGeneratorARM64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patc
target_string.dex_file,
target_string.string_index));
}
- if (!GetCompilerOptions().IsBootImage()) {
- EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(pc_relative_string_patches_,
- linker_patches);
- } else {
- EmitPcRelativeLinkerPatches<LinkerPatch::RelativeStringPatch>(pc_relative_string_patches_,
- linker_patches);
+ for (const PcRelativePatchInfo& info : pc_relative_string_patches_) {
+ linker_patches->push_back(LinkerPatch::RelativeStringPatch(info.label.GetLocation(),
+ &info.target_dex_file,
+ info.pc_insn_label->GetLocation(),
+ info.offset_or_index));
}
for (const auto& entry : boot_image_type_patches_) {
const TypeReference& target_type = entry.first;
@@ -3937,8 +3856,12 @@ void CodeGeneratorARM64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patc
target_type.dex_file,
target_type.type_index));
}
- EmitPcRelativeLinkerPatches<LinkerPatch::RelativeTypePatch>(pc_relative_type_patches_,
- linker_patches);
+ for (const PcRelativePatchInfo& info : pc_relative_type_patches_) {
+ linker_patches->push_back(LinkerPatch::RelativeTypePatch(info.label.GetLocation(),
+ &info.target_dex_file,
+ info.pc_insn_label->GetLocation(),
+ info.offset_or_index));
+ }
for (const auto& entry : boot_image_address_patches_) {
DCHECK(GetCompilerOptions().GetIncludePatchInformation());
vixl::aarch64::Literal<uint32_t>* literal = entry.second;
@@ -4095,11 +4018,19 @@ void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) {
const DexFile& dex_file = cls->GetDexFile();
uint32_t type_index = cls->GetTypeIndex();
vixl::aarch64::Label* adrp_label = codegen_->NewPcRelativeTypePatch(dex_file, type_index);
- codegen_->EmitAdrpPlaceholder(adrp_label, out.X());
+ {
+ SingleEmissionCheckScope guard(GetVIXLAssembler());
+ __ Bind(adrp_label);
+ __ adrp(out.X(), /* offset placeholder */ 0);
+ }
// Add ADD with its PC-relative type patch.
vixl::aarch64::Label* add_label =
codegen_->NewPcRelativeTypePatch(dex_file, type_index, adrp_label);
- codegen_->EmitAddPlaceholder(add_label, out.X(), out.X());
+ {
+ SingleEmissionCheckScope guard(GetVIXLAssembler());
+ __ Bind(add_label);
+ __ add(out.X(), out.X(), Operand(/* offset placeholder */ 0));
+ }
break;
}
case HLoadClass::LoadKind::kBootImageAddress: {
@@ -4136,7 +4067,11 @@ void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) {
uint32_t element_offset = cls->GetDexCacheElementOffset();
vixl::aarch64::Label* adrp_label =
codegen_->NewPcRelativeDexCacheArrayPatch(dex_file, element_offset);
- codegen_->EmitAdrpPlaceholder(adrp_label, out.X());
+ {
+ SingleEmissionCheckScope guard(GetVIXLAssembler());
+ __ Bind(adrp_label);
+ __ adrp(out.X(), /* offset placeholder */ 0);
+ }
// Add LDR with its PC-relative DexCache access patch.
vixl::aarch64::Label* ldr_label =
codegen_->NewPcRelativeDexCacheArrayPatch(dex_file, element_offset, adrp_label);
@@ -4221,7 +4156,7 @@ HLoadString::LoadKind CodeGeneratorARM64::GetSupportedLoadStringKind(
case HLoadString::LoadKind::kDexCacheAddress:
DCHECK(Runtime::Current()->UseJitCompilation());
break;
- case HLoadString::LoadKind::kBssEntry:
+ case HLoadString::LoadKind::kDexCachePcRelative:
DCHECK(!Runtime::Current()->UseJitCompilation());
break;
case HLoadString::LoadKind::kDexCacheViaMethod:
@@ -4232,9 +4167,7 @@ HLoadString::LoadKind CodeGeneratorARM64::GetSupportedLoadStringKind(
void LocationsBuilderARM64::VisitLoadString(HLoadString* load) {
LocationSummary::CallKind call_kind = load->NeedsEnvironment()
- ? ((load->GetLoadKind() == HLoadString::LoadKind::kDexCacheViaMethod)
- ? LocationSummary::kCallOnMainOnly
- : LocationSummary::kCallOnSlowPath)
+ ? LocationSummary::kCallOnMainOnly
: LocationSummary::kNoCall;
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
if (load->GetLoadKind() == HLoadString::LoadKind::kDexCacheViaMethod) {
@@ -4258,13 +4191,20 @@ void InstructionCodeGeneratorARM64::VisitLoadString(HLoadString* load) {
// Add ADRP with its PC-relative String patch.
const DexFile& dex_file = load->GetDexFile();
uint32_t string_index = load->GetStringIndex();
- DCHECK(codegen_->GetCompilerOptions().IsBootImage());
vixl::aarch64::Label* adrp_label = codegen_->NewPcRelativeStringPatch(dex_file, string_index);
- codegen_->EmitAdrpPlaceholder(adrp_label, out.X());
+ {
+ SingleEmissionCheckScope guard(GetVIXLAssembler());
+ __ Bind(adrp_label);
+ __ adrp(out.X(), /* offset placeholder */ 0);
+ }
// Add ADD with its PC-relative String patch.
vixl::aarch64::Label* add_label =
codegen_->NewPcRelativeStringPatch(dex_file, string_index, adrp_label);
- codegen_->EmitAddPlaceholder(add_label, out.X(), out.X());
+ {
+ SingleEmissionCheckScope guard(GetVIXLAssembler());
+ __ Bind(add_label);
+ __ add(out.X(), out.X(), Operand(/* offset placeholder */ 0));
+ }
return; // No dex cache slow path.
}
case HLoadString::LoadKind::kBootImageAddress: {
@@ -4272,28 +4212,6 @@ void InstructionCodeGeneratorARM64::VisitLoadString(HLoadString* load) {
__ Ldr(out.W(), codegen_->DeduplicateBootImageAddressLiteral(load->GetAddress()));
return; // No dex cache slow path.
}
- case HLoadString::LoadKind::kBssEntry: {
- // Add ADRP with its PC-relative String .bss entry patch.
- const DexFile& dex_file = load->GetDexFile();
- uint32_t string_index = load->GetStringIndex();
- DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
- vixl::aarch64::Label* adrp_label = codegen_->NewPcRelativeStringPatch(dex_file, string_index);
- codegen_->EmitAdrpPlaceholder(adrp_label, out.X());
- // Add LDR with its PC-relative String patch.
- vixl::aarch64::Label* ldr_label =
- codegen_->NewPcRelativeStringPatch(dex_file, string_index, adrp_label);
- // /* GcRoot<mirror::Class> */ out = *(base_address + offset) /* PC-relative */
- GenerateGcRootFieldLoad(load,
- load->GetLocations()->Out(),
- out.X(),
- /* placeholder */ 0u,
- ldr_label);
- SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM64(load);
- codegen_->AddSlowPath(slow_path);
- __ Cbz(out.X(), slow_path->GetEntryLabel());
- __ Bind(slow_path->GetExitLabel());
- return;
- }
default:
break;
}
@@ -5063,7 +4981,6 @@ void InstructionCodeGeneratorARM64::GenerateGcRootFieldLoad(HInstruction* instru
uint32_t offset,
vixl::aarch64::Label* fixup_label,
bool requires_read_barrier) {
- DCHECK(fixup_label == nullptr || offset == 0u);
Register root_reg = RegisterFrom(root, Primitive::kPrimNot);
if (requires_read_barrier) {
DCHECK(kEmitCompilerReadBarrier);
@@ -5080,7 +4997,9 @@ void InstructionCodeGeneratorARM64::GenerateGcRootFieldLoad(HInstruction* instru
if (fixup_label == nullptr) {
__ Ldr(root_reg, MemOperand(obj, offset));
} else {
- codegen_->EmitLdrOffsetPlaceholder(fixup_label, root_reg, obj);
+ SingleEmissionCheckScope guard(GetVIXLAssembler());
+ __ Bind(fixup_label);
+ __ ldr(root_reg, MemOperand(obj, offset));
}
static_assert(
sizeof(mirror::CompressedReference<mirror::Object>) == sizeof(GcRoot<mirror::Object>),
@@ -5109,7 +5028,9 @@ void InstructionCodeGeneratorARM64::GenerateGcRootFieldLoad(HInstruction* instru
if (fixup_label == nullptr) {
__ Add(root_reg.X(), obj.X(), offset);
} else {
- codegen_->EmitAddPlaceholder(fixup_label, root_reg.X(), obj.X());
+ SingleEmissionCheckScope guard(GetVIXLAssembler());
+ __ Bind(fixup_label);
+ __ add(root_reg.X(), obj.X(), offset);
}
// /* mirror::Object* */ root = root->Read()
codegen_->GenerateReadBarrierForRootSlow(instruction, root, root);
@@ -5120,7 +5041,9 @@ void InstructionCodeGeneratorARM64::GenerateGcRootFieldLoad(HInstruction* instru
if (fixup_label == nullptr) {
__ Ldr(root_reg, MemOperand(obj, offset));
} else {
- codegen_->EmitLdrOffsetPlaceholder(fixup_label, root_reg, obj.X());
+ SingleEmissionCheckScope guard(GetVIXLAssembler());
+ __ Bind(fixup_label);
+ __ ldr(root_reg, MemOperand(obj, offset));
}
// Note that GC roots are not affected by heap poisoning, thus we
// do not have to unpoison `root_reg` here.
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index eb28ecb427..a15224578d 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -564,14 +564,6 @@ class CodeGeneratorARM64 : public CodeGenerator {
vixl::aarch64::Literal<uint32_t>* DeduplicateBootImageAddressLiteral(uint64_t address);
vixl::aarch64::Literal<uint64_t>* DeduplicateDexCacheAddressLiteral(uint64_t address);
- void EmitAdrpPlaceholder(vixl::aarch64::Label* fixup_label, vixl::aarch64::Register reg);
- void EmitAddPlaceholder(vixl::aarch64::Label* fixup_label,
- vixl::aarch64::Register out,
- vixl::aarch64::Register base);
- void EmitLdrOffsetPlaceholder(vixl::aarch64::Label* fixup_label,
- vixl::aarch64::Register out,
- vixl::aarch64::Register base);
-
void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE;
// Fast path implementation of ReadBarrier::Barrier for a heap
@@ -699,10 +691,6 @@ class CodeGeneratorARM64 : public CodeGenerator {
void EmitJumpTables();
- template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
- static void EmitPcRelativeLinkerPatches(const ArenaDeque<PcRelativePatchInfo>& infos,
- ArenaVector<LinkerPatch>* linker_patches);
-
// Labels for each block that will be compiled.
// We use a deque so that the `vixl::aarch64::Label` objects do not move in memory.
ArenaDeque<vixl::aarch64::Label> block_labels_; // Indexed by block id.
@@ -725,12 +713,12 @@ class CodeGeneratorARM64 : public CodeGenerator {
MethodToLiteralMap call_patches_;
// Relative call patch info.
// Using ArenaDeque<> which retains element addresses on push/emplace_back().
- ArenaDeque<PatchInfo<vixl::aarch64::Label>> relative_call_patches_;
+ ArenaDeque<MethodPatchInfo<vixl::aarch64::Label>> relative_call_patches_;
// PC-relative DexCache access info.
ArenaDeque<PcRelativePatchInfo> pc_relative_dex_cache_patches_;
// Deduplication map for boot string literals for kBootImageLinkTimeAddress.
BootStringToLiteralMap boot_image_string_patches_;
- // PC-relative String patch info; type depends on configuration (app .bss or boot image PIC).
+ // PC-relative String patch info.
ArenaDeque<PcRelativePatchInfo> pc_relative_string_patches_;
// Deduplication map for boot type literals for kBootImageLinkTimeAddress.
BootTypeToLiteralMap boot_image_type_patches_;
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index f0118a465b..5c0ca85c78 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -279,8 +279,7 @@ class LoadStringSlowPathMIPS : public SlowPathCodeMIPS {
SaveLiveRegisters(codegen, locations);
InvokeRuntimeCallingConvention calling_convention;
- HLoadString* load = instruction_->AsLoadString();
- const uint32_t string_index = load->GetStringIndex();
+ const uint32_t string_index = instruction_->AsLoadString()->GetStringIndex();
__ LoadConst32(calling_convention.GetRegisterAt(0), string_index);
mips_codegen->InvokeRuntime(kQuickResolveString, instruction_, instruction_->GetDexPc(), this);
CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
@@ -290,19 +289,6 @@ class LoadStringSlowPathMIPS : public SlowPathCodeMIPS {
type);
RestoreLiveRegisters(codegen, locations);
-
- // Store the resolved String to the BSS entry.
- // TODO: Change art_quick_resolve_string to kSaveEverything and use a temporary for the
- // .bss entry address in the fast path, so that we can avoid another calculation here.
- bool isR6 = mips_codegen->GetInstructionSetFeatures().IsR6();
- Register base = isR6 ? ZERO : locations->InAt(0).AsRegister<Register>();
- Register out = locations->Out().AsRegister<Register>();
- DCHECK_NE(out, AT);
- CodeGeneratorMIPS::PcRelativePatchInfo* info =
- mips_codegen->NewPcRelativeStringPatch(load->GetDexFile(), string_index);
- mips_codegen->EmitPcRelativeAddressPlaceholder(info, AT, base);
- __ StoreToOffset(kStoreWord, out, AT, 0);
-
__ B(GetExitLabel());
}
@@ -971,24 +957,6 @@ void CodeGeneratorMIPS::AddLocationAsTemp(Location location, LocationSummary* lo
}
}
-template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
-inline void CodeGeneratorMIPS::EmitPcRelativeLinkerPatches(
- const ArenaDeque<PcRelativePatchInfo>& infos,
- ArenaVector<LinkerPatch>* linker_patches) {
- for (const PcRelativePatchInfo& info : infos) {
- const DexFile& dex_file = info.target_dex_file;
- size_t offset_or_index = info.offset_or_index;
- DCHECK(info.high_label.IsBound());
- uint32_t high_offset = __ GetLabelLocation(&info.high_label);
- // On R2 we use HMipsComputeBaseMethodAddress and patch relative to
- // the assembler's base label used for PC-relative addressing.
- uint32_t pc_rel_offset = info.pc_rel_label.IsBound()
- ? __ GetLabelLocation(&info.pc_rel_label)
- : __ GetPcRelBaseLabelLocation();
- linker_patches->push_back(Factory(high_offset, &dex_file, pc_rel_offset, offset_or_index));
- }
-}
-
void CodeGeneratorMIPS::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
DCHECK(linker_patches->empty());
size_t size =
@@ -1019,17 +987,48 @@ void CodeGeneratorMIPS::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patch
target_method.dex_file,
target_method.dex_method_index));
}
- EmitPcRelativeLinkerPatches<LinkerPatch::DexCacheArrayPatch>(pc_relative_dex_cache_patches_,
- linker_patches);
- if (!GetCompilerOptions().IsBootImage()) {
- EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(pc_relative_string_patches_,
- linker_patches);
- } else {
- EmitPcRelativeLinkerPatches<LinkerPatch::RelativeStringPatch>(pc_relative_string_patches_,
- linker_patches);
+ for (const PcRelativePatchInfo& info : pc_relative_dex_cache_patches_) {
+ const DexFile& dex_file = info.target_dex_file;
+ size_t base_element_offset = info.offset_or_index;
+ DCHECK(info.high_label.IsBound());
+ uint32_t high_offset = __ GetLabelLocation(&info.high_label);
+ DCHECK(info.pc_rel_label.IsBound());
+ uint32_t pc_rel_offset = __ GetLabelLocation(&info.pc_rel_label);
+ linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(high_offset,
+ &dex_file,
+ pc_rel_offset,
+ base_element_offset));
+ }
+ for (const PcRelativePatchInfo& info : pc_relative_string_patches_) {
+ const DexFile& dex_file = info.target_dex_file;
+ size_t string_index = info.offset_or_index;
+ DCHECK(info.high_label.IsBound());
+ uint32_t high_offset = __ GetLabelLocation(&info.high_label);
+ // On R2 we use HMipsComputeBaseMethodAddress and patch relative to
+ // the assembler's base label used for PC-relative literals.
+ uint32_t pc_rel_offset = info.pc_rel_label.IsBound()
+ ? __ GetLabelLocation(&info.pc_rel_label)
+ : __ GetPcRelBaseLabelLocation();
+ linker_patches->push_back(LinkerPatch::RelativeStringPatch(high_offset,
+ &dex_file,
+ pc_rel_offset,
+ string_index));
+ }
+ for (const PcRelativePatchInfo& info : pc_relative_type_patches_) {
+ const DexFile& dex_file = info.target_dex_file;
+ size_t type_index = info.offset_or_index;
+ DCHECK(info.high_label.IsBound());
+ uint32_t high_offset = __ GetLabelLocation(&info.high_label);
+ // On R2 we use HMipsComputeBaseMethodAddress and patch relative to
+ // the assembler's base label used for PC-relative literals.
+ uint32_t pc_rel_offset = info.pc_rel_label.IsBound()
+ ? __ GetLabelLocation(&info.pc_rel_label)
+ : __ GetPcRelBaseLabelLocation();
+ linker_patches->push_back(LinkerPatch::RelativeTypePatch(high_offset,
+ &dex_file,
+ pc_rel_offset,
+ type_index));
}
- EmitPcRelativeLinkerPatches<LinkerPatch::RelativeTypePatch>(pc_relative_type_patches_,
- linker_patches);
for (const auto& entry : boot_image_string_patches_) {
const StringReference& target_string = entry.first;
Literal* literal = entry.second;
@@ -1119,36 +1118,6 @@ Literal* CodeGeneratorMIPS::DeduplicateBootImageAddressLiteral(uint32_t address)
return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address), map);
}
-void CodeGeneratorMIPS::EmitPcRelativeAddressPlaceholder(
- PcRelativePatchInfo* info, Register out, Register base) {
- bool reordering = __ SetReorder(false);
- if (GetInstructionSetFeatures().IsR6()) {
- DCHECK_EQ(base, ZERO);
- __ Bind(&info->high_label);
- __ Bind(&info->pc_rel_label);
- // Add a 32-bit offset to PC.
- __ Auipc(out, /* placeholder */ 0x1234);
- __ Addiu(out, out, /* placeholder */ 0x5678);
- } else {
- // If base is ZERO, emit NAL to obtain the actual base.
- if (base == ZERO) {
- // Generate a dummy PC-relative call to obtain PC.
- __ Nal();
- }
- __ Bind(&info->high_label);
- __ Lui(out, /* placeholder */ 0x1234);
- // If we emitted the NAL, bind the pc_rel_label, otherwise base is a register holding
- // the HMipsComputeBaseMethodAddress which has its own label stored in MipsAssembler.
- if (base == ZERO) {
- __ Bind(&info->pc_rel_label);
- }
- __ Ori(out, out, /* placeholder */ 0x5678);
- // Add a 32-bit offset to PC.
- __ Addu(out, out, (base == ZERO) ? RA : base);
- }
- __ SetReorder(reordering);
-}
-
void CodeGeneratorMIPS::MarkGCCard(Register object, Register value) {
MipsLabel done;
Register card = AT;
@@ -4260,8 +4229,6 @@ HLoadString::LoadKind CodeGeneratorMIPS::GetSupportedLoadStringKind(
}
// We disable PC-relative load when there is an irreducible loop, as the optimization
// is incompatible with it.
- // TODO: Create as many MipsDexCacheArraysBase instructions as needed for methods
- // with irreducible loops.
bool has_irreducible_loops = GetGraph()->HasIrreducibleLoops();
bool fallback_load = has_irreducible_loops;
switch (desired_string_load_kind) {
@@ -4277,8 +4244,10 @@ HLoadString::LoadKind CodeGeneratorMIPS::GetSupportedLoadStringKind(
DCHECK(Runtime::Current()->UseJitCompilation());
fallback_load = false;
break;
- case HLoadString::LoadKind::kBssEntry:
+ case HLoadString::LoadKind::kDexCachePcRelative:
DCHECK(!Runtime::Current()->UseJitCompilation());
+ // TODO: Create as many MipsDexCacheArraysBase instructions as needed for methods
+ // with irreducible loops.
break;
case HLoadString::LoadKind::kDexCacheViaMethod:
fallback_load = false;
@@ -4658,7 +4627,23 @@ void InstructionCodeGeneratorMIPS::VisitLoadClass(HLoadClass* cls) {
DCHECK(!kEmitCompilerReadBarrier);
CodeGeneratorMIPS::PcRelativePatchInfo* info =
codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
- codegen_->EmitPcRelativeAddressPlaceholder(info, out, base_or_current_method_reg);
+ bool reordering = __ SetReorder(false);
+ if (isR6) {
+ __ Bind(&info->high_label);
+ __ Bind(&info->pc_rel_label);
+ // Add a 32-bit offset to PC.
+ __ Auipc(out, /* placeholder */ 0x1234);
+ __ Addiu(out, out, /* placeholder */ 0x5678);
+ } else {
+ __ Bind(&info->high_label);
+ __ Lui(out, /* placeholder */ 0x1234);
+ // We do not bind info->pc_rel_label here, we'll use the assembler's label
+ // for PC-relative literals and the base from HMipsComputeBaseMethodAddress.
+ __ Ori(out, out, /* placeholder */ 0x5678);
+ // Add a 32-bit offset to PC.
+ __ Addu(out, out, base_or_current_method_reg);
+ }
+ __ SetReorder(reordering);
break;
}
case HLoadClass::LoadKind::kBootImageAddress: {
@@ -4747,9 +4732,7 @@ void InstructionCodeGeneratorMIPS::VisitClearException(HClearException* clear AT
void LocationsBuilderMIPS::VisitLoadString(HLoadString* load) {
LocationSummary::CallKind call_kind = (load->NeedsEnvironment() || kEmitCompilerReadBarrier)
- ? ((load->GetLoadKind() == HLoadString::LoadKind::kDexCacheViaMethod)
- ? LocationSummary::kCallOnMainOnly
- : LocationSummary::kCallOnSlowPath)
+ ? LocationSummary::kCallOnSlowPath
: LocationSummary::kNoCall;
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
HLoadString::LoadKind load_kind = load->GetLoadKind();
@@ -4763,7 +4746,7 @@ void LocationsBuilderMIPS::VisitLoadString(HLoadString* load) {
}
FALLTHROUGH_INTENDED;
// We need an extra register for PC-relative dex cache accesses.
- case HLoadString::LoadKind::kBssEntry:
+ case HLoadString::LoadKind::kDexCachePcRelative:
case HLoadString::LoadKind::kDexCacheViaMethod:
locations->SetInAt(0, Location::RequiresRegister());
break;
@@ -4785,7 +4768,6 @@ void InstructionCodeGeneratorMIPS::VisitLoadString(HLoadString* load) {
case HLoadString::LoadKind::kBootImageLinkTimeAddress:
case HLoadString::LoadKind::kBootImageAddress:
case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
- case HLoadString::LoadKind::kBssEntry:
base_or_current_method_reg = isR6 ? ZERO : locations->InAt(0).AsRegister<Register>();
break;
default:
@@ -4803,10 +4785,25 @@ void InstructionCodeGeneratorMIPS::VisitLoadString(HLoadString* load) {
return; // No dex cache slow path.
case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
DCHECK(!kEmitCompilerReadBarrier);
- DCHECK(codegen_->GetCompilerOptions().IsBootImage());
CodeGeneratorMIPS::PcRelativePatchInfo* info =
codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
- codegen_->EmitPcRelativeAddressPlaceholder(info, out, base_or_current_method_reg);
+ bool reordering = __ SetReorder(false);
+ if (isR6) {
+ __ Bind(&info->high_label);
+ __ Bind(&info->pc_rel_label);
+ // Add a 32-bit offset to PC.
+ __ Auipc(out, /* placeholder */ 0x1234);
+ __ Addiu(out, out, /* placeholder */ 0x5678);
+ } else {
+ __ Bind(&info->high_label);
+ __ Lui(out, /* placeholder */ 0x1234);
+ // We do not bind info->pc_rel_label here, we'll use the assembler's label
+ // for PC-relative literals and the base from HMipsComputeBaseMethodAddress.
+ __ Ori(out, out, /* placeholder */ 0x5678);
+ // Add a 32-bit offset to PC.
+ __ Addu(out, out, base_or_current_method_reg);
+ }
+ __ SetReorder(reordering);
return; // No dex cache slow path.
}
case HLoadString::LoadKind::kBootImageAddress: {
@@ -4818,18 +4815,6 @@ void InstructionCodeGeneratorMIPS::VisitLoadString(HLoadString* load) {
codegen_->DeduplicateBootImageAddressLiteral(address));
return; // No dex cache slow path.
}
- case HLoadString::LoadKind::kBssEntry: {
- DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
- CodeGeneratorMIPS::PcRelativePatchInfo* info =
- codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
- codegen_->EmitPcRelativeAddressPlaceholder(info, out, base_or_current_method_reg);
- __ LoadFromOffset(kLoadWord, out, out, 0);
- SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathMIPS(load);
- codegen_->AddSlowPath(slow_path);
- __ Beqz(out, slow_path->GetEntryLabel());
- __ Bind(slow_path->GetExitLabel());
- return;
- }
default:
break;
}
@@ -6026,8 +6011,25 @@ void InstructionCodeGeneratorMIPS::VisitMipsDexCacheArraysBase(HMipsDexCacheArra
Register reg = base->GetLocations()->Out().AsRegister<Register>();
CodeGeneratorMIPS::PcRelativePatchInfo* info =
codegen_->NewPcRelativeDexCacheArrayPatch(base->GetDexFile(), base->GetElementOffset());
- // TODO: Reuse MipsComputeBaseMethodAddress on R2 instead of passing ZERO to force emitting NAL.
- codegen_->EmitPcRelativeAddressPlaceholder(info, reg, ZERO);
+ bool reordering = __ SetReorder(false);
+ if (codegen_->GetInstructionSetFeatures().IsR6()) {
+ __ Bind(&info->high_label);
+ __ Bind(&info->pc_rel_label);
+ // Add a 32-bit offset to PC.
+ __ Auipc(reg, /* placeholder */ 0x1234);
+ __ Addiu(reg, reg, /* placeholder */ 0x5678);
+ } else {
+ // Generate a dummy PC-relative call to obtain PC.
+ __ Nal();
+ __ Bind(&info->high_label);
+ __ Lui(reg, /* placeholder */ 0x1234);
+ __ Bind(&info->pc_rel_label);
+ __ Ori(reg, reg, /* placeholder */ 0x5678);
+ // Add a 32-bit offset to PC.
+ __ Addu(reg, reg, RA);
+ // TODO: Can we share this code with that of VisitMipsComputeBaseMethodAddress()?
+ }
+ __ SetReorder(reordering);
}
void LocationsBuilderMIPS::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h
index 0e8d8d40cf..f943978b3b 100644
--- a/compiler/optimizing/code_generator_mips.h
+++ b/compiler/optimizing/code_generator_mips.h
@@ -435,8 +435,6 @@ class CodeGeneratorMIPS : public CodeGenerator {
Literal* DeduplicateBootImageTypeLiteral(const DexFile& dex_file, uint32_t type_index);
Literal* DeduplicateBootImageAddressLiteral(uint32_t address);
- void EmitPcRelativeAddressPlaceholder(PcRelativePatchInfo* info, Register out, Register base);
-
private:
Register GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke, Register temp);
@@ -457,10 +455,6 @@ class CodeGeneratorMIPS : public CodeGenerator {
uint32_t offset_or_index,
ArenaDeque<PcRelativePatchInfo>* patches);
- template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
- void EmitPcRelativeLinkerPatches(const ArenaDeque<PcRelativePatchInfo>& infos,
- ArenaVector<LinkerPatch>* linker_patches);
-
// Labels for each block that will be compiled.
MipsLabel* block_labels_;
MipsLabel frame_entry_label_;
@@ -479,7 +473,7 @@ class CodeGeneratorMIPS : public CodeGenerator {
ArenaDeque<PcRelativePatchInfo> pc_relative_dex_cache_patches_;
// Deduplication map for boot string literals for kBootImageLinkTimeAddress.
BootStringToLiteralMap boot_image_string_patches_;
- // PC-relative String patch info; type depends on configuration (app .bss or boot image PIC).
+ // PC-relative String patch info.
ArenaDeque<PcRelativePatchInfo> pc_relative_string_patches_;
// Deduplication map for boot type literals for kBootImageLinkTimeAddress.
BootTypeToLiteralMap boot_image_type_patches_;
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 49426440f6..a7051aeeb1 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -150,6 +150,9 @@ class BoundsCheckSlowPathX86 : public SlowPathCode {
length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(2));
}
__ movl(length_loc.AsRegister<Register>(), array_len);
+ if (mirror::kUseStringCompression) {
+ __ andl(length_loc.AsRegister<Register>(), Immediate(INT32_MAX));
+ }
}
x86_codegen->EmitParallelMoves(
locations->InAt(0),
@@ -209,42 +212,6 @@ class SuspendCheckSlowPathX86 : public SlowPathCode {
DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86);
};
-class LoadStringSlowPathX86 : public SlowPathCode {
- public:
- explicit LoadStringSlowPathX86(HLoadString* instruction): SlowPathCode(instruction) {}
-
- void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
- LocationSummary* locations = instruction_->GetLocations();
- DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
-
- CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
- __ Bind(GetEntryLabel());
- SaveLiveRegisters(codegen, locations);
-
- InvokeRuntimeCallingConvention calling_convention;
- const uint32_t string_index = instruction_->AsLoadString()->GetStringIndex();
- __ movl(calling_convention.GetRegisterAt(0), Immediate(string_index));
- x86_codegen->InvokeRuntime(kQuickResolveString, instruction_, instruction_->GetDexPc(), this);
- CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
- x86_codegen->Move32(locations->Out(), Location::RegisterLocation(EAX));
- RestoreLiveRegisters(codegen, locations);
-
- // Store the resolved String to the BSS entry.
- Register method_address = locations->InAt(0).AsRegister<Register>();
- __ movl(Address(method_address, CodeGeneratorX86::kDummy32BitOffset),
- locations->Out().AsRegister<Register>());
- Label* fixup_label = x86_codegen->NewStringBssEntryPatch(instruction_->AsLoadString());
- __ Bind(fixup_label);
-
- __ jmp(GetExitLabel());
- }
-
- const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathX86"; }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86);
-};
-
class LoadClassSlowPathX86 : public SlowPathCode {
public:
LoadClassSlowPathX86(HLoadClass* cls,
@@ -4327,8 +4294,7 @@ Location CodeGeneratorX86::GenerateCalleeMethodStaticOrDirectCall(HInvokeStaticO
break;
case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
__ movl(temp.AsRegister<Register>(), Immediate(/* placeholder */ 0));
- method_patches_.emplace_back(*invoke->GetTargetMethod().dex_file,
- invoke->GetTargetMethod().dex_method_index);
+ method_patches_.emplace_back(invoke->GetTargetMethod());
__ Bind(&method_patches_.back().label); // Bind the label at the end of the "movl" insn.
break;
case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
@@ -4373,8 +4339,7 @@ void CodeGeneratorX86::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
__ call(GetFrameEntryLabel());
break;
case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative: {
- relative_call_patches_.emplace_back(*invoke->GetTargetMethod().dex_file,
- invoke->GetTargetMethod().dex_method_index);
+ relative_call_patches_.emplace_back(invoke->GetTargetMethod());
Label* label = &relative_call_patches_.back().label;
__ call(label); // Bind to the patch label, override at link time.
__ Bind(label); // Bind the label at the end of the "call" insn.
@@ -4433,8 +4398,7 @@ void CodeGeneratorX86::RecordSimplePatch() {
}
}
-void CodeGeneratorX86::RecordBootStringPatch(HLoadString* load_string) {
- DCHECK(GetCompilerOptions().IsBootImage());
+void CodeGeneratorX86::RecordStringPatch(HLoadString* load_string) {
string_patches_.emplace_back(load_string->GetDexFile(), load_string->GetStringIndex());
__ Bind(&string_patches_.back().label);
}
@@ -4444,12 +4408,6 @@ void CodeGeneratorX86::RecordTypePatch(HLoadClass* load_class) {
__ Bind(&type_patches_.back().label);
}
-Label* CodeGeneratorX86::NewStringBssEntryPatch(HLoadString* load_string) {
- DCHECK(!GetCompilerOptions().IsBootImage());
- string_patches_.emplace_back(load_string->GetDexFile(), load_string->GetStringIndex());
- return &string_patches_.back().label;
-}
-
Label* CodeGeneratorX86::NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file,
uint32_t element_offset) {
// Add the patch entry and bind its label at the end of the instruction.
@@ -4457,21 +4415,6 @@ Label* CodeGeneratorX86::NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file
return &pc_relative_dex_cache_patches_.back().label;
}
-// The label points to the end of the "movl" or another instruction but the literal offset
-// for method patch needs to point to the embedded constant which occupies the last 4 bytes.
-constexpr uint32_t kLabelPositionToLiteralOffsetAdjustment = 4u;
-
-template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
-inline void CodeGeneratorX86::EmitPcRelativeLinkerPatches(
- const ArenaDeque<PatchInfo<Label>>& infos,
- ArenaVector<LinkerPatch>* linker_patches) {
- for (const PatchInfo<Label>& info : infos) {
- uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
- linker_patches->push_back(
- Factory(literal_offset, &info.dex_file, GetMethodAddressOffset(), info.index));
- }
-}
-
void CodeGeneratorX86::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
DCHECK(linker_patches->empty());
size_t size =
@@ -4482,38 +4425,59 @@ void CodeGeneratorX86::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patche
string_patches_.size() +
type_patches_.size();
linker_patches->reserve(size);
- for (const PatchInfo<Label>& info : method_patches_) {
+ // The label points to the end of the "movl" insn but the literal offset for method
+ // patch needs to point to the embedded constant which occupies the last 4 bytes.
+ constexpr uint32_t kLabelPositionToLiteralOffsetAdjustment = 4u;
+ for (const MethodPatchInfo<Label>& info : method_patches_) {
uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
- linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset, &info.dex_file, info.index));
+ linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
+ info.target_method.dex_file,
+ info.target_method.dex_method_index));
}
- for (const PatchInfo<Label>& info : relative_call_patches_) {
+ for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
- linker_patches->push_back(
- LinkerPatch::RelativeCodePatch(literal_offset, &info.dex_file, info.index));
+ linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
+ info.target_method.dex_file,
+ info.target_method.dex_method_index));
+ }
+ for (const PcRelativeDexCacheAccessInfo& info : pc_relative_dex_cache_patches_) {
+ uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
+ linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(literal_offset,
+ &info.target_dex_file,
+ GetMethodAddressOffset(),
+ info.element_offset));
}
- EmitPcRelativeLinkerPatches<LinkerPatch::DexCacheArrayPatch>(pc_relative_dex_cache_patches_,
- linker_patches);
for (const Label& label : simple_patches_) {
uint32_t literal_offset = label.Position() - kLabelPositionToLiteralOffsetAdjustment;
linker_patches->push_back(LinkerPatch::RecordPosition(literal_offset));
}
- if (!GetCompilerOptions().IsBootImage()) {
- EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(string_patches_, linker_patches);
- } else if (GetCompilerOptions().GetCompilePic()) {
- EmitPcRelativeLinkerPatches<LinkerPatch::RelativeStringPatch>(string_patches_, linker_patches);
- } else {
- for (const PatchInfo<Label>& info : string_patches_) {
+ if (GetCompilerOptions().GetCompilePic()) {
+ for (const StringPatchInfo<Label>& info : string_patches_) {
uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
- linker_patches->push_back(
- LinkerPatch::StringPatch(literal_offset, &info.dex_file, info.index));
+ linker_patches->push_back(LinkerPatch::RelativeStringPatch(literal_offset,
+ &info.dex_file,
+ GetMethodAddressOffset(),
+ info.string_index));
+ }
+ for (const TypePatchInfo<Label>& info : type_patches_) {
+ uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
+ linker_patches->push_back(LinkerPatch::RelativeTypePatch(literal_offset,
+ &info.dex_file,
+ GetMethodAddressOffset(),
+ info.type_index));
}
- }
- if (GetCompilerOptions().GetCompilePic()) {
- EmitPcRelativeLinkerPatches<LinkerPatch::RelativeTypePatch>(type_patches_, linker_patches);
} else {
- for (const PatchInfo<Label>& info : type_patches_) {
+ for (const StringPatchInfo<Label>& info : string_patches_) {
uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
- linker_patches->push_back(LinkerPatch::TypePatch(literal_offset, &info.dex_file, info.index));
+ linker_patches->push_back(LinkerPatch::StringPatch(literal_offset,
+ &info.dex_file,
+ info.string_index));
+ }
+ for (const TypePatchInfo<Label>& info : type_patches_) {
+ uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
+ linker_patches->push_back(LinkerPatch::TypePatch(literal_offset,
+ &info.dex_file,
+ info.type_index));
}
}
}
@@ -5060,7 +5024,23 @@ void InstructionCodeGeneratorX86::VisitArrayGet(HArrayGet* instruction) {
case Primitive::kPrimChar: {
Register out = out_loc.AsRegister<Register>();
- __ movzxw(out, CodeGeneratorX86::ArrayAddress(obj, index, TIMES_2, data_offset));
+ if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
+ // Branch cases into compressed and uncompressed for each index's type.
+ uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
+ NearLabel done, not_compressed;
+ __ cmpl(Address(obj, count_offset), Immediate(0));
+ codegen_->MaybeRecordImplicitNullCheck(instruction);
+ __ j(kGreaterEqual, &not_compressed);
+ __ movzxb(out, CodeGeneratorX86::ArrayAddress(obj, index, TIMES_1, data_offset));
+ __ jmp(&done);
+ __ Bind(&not_compressed);
+ __ movzxw(out, CodeGeneratorX86::ArrayAddress(obj, index, TIMES_2, data_offset));
+ __ Bind(&done);
+ } else {
+ // Common case for charAt of array of char or when string compression's
+ // feature is turned off.
+ __ movzxw(out, CodeGeneratorX86::ArrayAddress(obj, index, TIMES_2, data_offset));
+ }
break;
}
@@ -5398,6 +5378,10 @@ void InstructionCodeGeneratorX86::VisitArrayLength(HArrayLength* instruction) {
Register out = locations->Out().AsRegister<Register>();
__ movl(out, Address(obj, offset));
codegen_->MaybeRecordImplicitNullCheck(instruction);
+ // Mask out most significant bit in case the array is String's array of char.
+ if (mirror::kUseStringCompression && instruction->IsStringLength()) {
+ __ andl(out, Immediate(INT32_MAX));
+ }
}
void LocationsBuilderX86::VisitBoundsCheck(HBoundsCheck* instruction) {
@@ -5411,9 +5395,15 @@ void LocationsBuilderX86::VisitBoundsCheck(HBoundsCheck* instruction) {
if (!length->IsEmittedAtUseSite()) {
locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
}
+ // Need register to see array's length.
+ if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
+ locations->AddTemp(Location::RequiresRegister());
+ }
}
void InstructionCodeGeneratorX86::VisitBoundsCheck(HBoundsCheck* instruction) {
+ const bool is_string_compressed_char_at =
+ mirror::kUseStringCompression && instruction->IsStringCharAt();
LocationSummary* locations = instruction->GetLocations();
Location index_loc = locations->InAt(0);
Location length_loc = locations->InAt(1);
@@ -5448,13 +5438,23 @@ void InstructionCodeGeneratorX86::VisitBoundsCheck(HBoundsCheck* instruction) {
uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(array_length->AsArrayLength());
Location array_loc = array_length->GetLocations()->InAt(0);
Address array_len(array_loc.AsRegister<Register>(), len_offset);
- if (index_loc.IsConstant()) {
- int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
- __ cmpl(array_len, Immediate(value));
+ if (is_string_compressed_char_at) {
+ Register length_reg = locations->GetTemp(0).AsRegister<Register>();
+ __ movl(length_reg, array_len);
+ codegen_->MaybeRecordImplicitNullCheck(array_length);
+ __ andl(length_reg, Immediate(INT32_MAX));
+ codegen_->GenerateIntCompare(length_reg, index_loc);
} else {
- __ cmpl(array_len, index_loc.AsRegister<Register>());
+ // Checking bounds for general case:
+ // Array of char or string's array with feature compression off.
+ if (index_loc.IsConstant()) {
+ int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
+ __ cmpl(array_len, Immediate(value));
+ } else {
+ __ cmpl(array_len, index_loc.AsRegister<Register>());
+ }
+ codegen_->MaybeRecordImplicitNullCheck(array_length);
}
- codegen_->MaybeRecordImplicitNullCheck(array_length);
} else {
codegen_->GenerateIntCompare(length_loc, index_loc);
}
@@ -5991,7 +5991,7 @@ HLoadString::LoadKind CodeGeneratorX86::GetSupportedLoadStringKind(
case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
DCHECK(GetCompilerOptions().GetCompilePic());
FALLTHROUGH_INTENDED;
- case HLoadString::LoadKind::kBssEntry:
+ case HLoadString::LoadKind::kDexCachePcRelative:
DCHECK(!Runtime::Current()->UseJitCompilation()); // Note: boot image is also non-JIT.
// We disable pc-relative load when there is an irreducible loop, as the optimization
// is incompatible with it.
@@ -6014,15 +6014,13 @@ HLoadString::LoadKind CodeGeneratorX86::GetSupportedLoadStringKind(
void LocationsBuilderX86::VisitLoadString(HLoadString* load) {
LocationSummary::CallKind call_kind = (load->NeedsEnvironment() || kEmitCompilerReadBarrier)
- ? ((load->GetLoadKind() == HLoadString::LoadKind::kDexCacheViaMethod)
- ? LocationSummary::kCallOnMainOnly
- : LocationSummary::kCallOnSlowPath)
+ ? LocationSummary::kCallOnMainOnly
: LocationSummary::kNoCall;
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
HLoadString::LoadKind load_kind = load->GetLoadKind();
if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod ||
load_kind == HLoadString::LoadKind::kBootImageLinkTimePcRelative ||
- load_kind == HLoadString::LoadKind::kBssEntry) {
+ load_kind == HLoadString::LoadKind::kDexCachePcRelative) {
locations->SetInAt(0, Location::RequiresRegister());
}
if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod) {
@@ -6040,13 +6038,13 @@ void InstructionCodeGeneratorX86::VisitLoadString(HLoadString* load) {
switch (load->GetLoadKind()) {
case HLoadString::LoadKind::kBootImageLinkTimeAddress: {
__ movl(out, Immediate(/* placeholder */ 0));
- codegen_->RecordBootStringPatch(load);
+ codegen_->RecordStringPatch(load);
return; // No dex cache slow path.
}
case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
Register method_address = locations->InAt(0).AsRegister<Register>();
__ leal(out, Address(method_address, CodeGeneratorX86::kDummy32BitOffset));
- codegen_->RecordBootStringPatch(load);
+ codegen_->RecordStringPatch(load);
return; // No dex cache slow path.
}
case HLoadString::LoadKind::kBootImageAddress: {
@@ -6056,19 +6054,6 @@ void InstructionCodeGeneratorX86::VisitLoadString(HLoadString* load) {
codegen_->RecordSimplePatch();
return; // No dex cache slow path.
}
- case HLoadString::LoadKind::kBssEntry: {
- Register method_address = locations->InAt(0).AsRegister<Register>();
- Address address = Address(method_address, CodeGeneratorX86::kDummy32BitOffset);
- Label* fixup_label = codegen_->NewStringBssEntryPatch(load);
- // /* GcRoot<mirror::Class> */ out = *address /* PC-relative */
- GenerateGcRootFieldLoad(load, out_loc, address, fixup_label);
- SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86(load);
- codegen_->AddSlowPath(slow_path);
- __ testl(out, out);
- __ j(kEqual, slow_path->GetEntryLabel());
- __ Bind(slow_path->GetExitLabel());
- return;
- }
default:
break;
}
@@ -7332,13 +7317,17 @@ void CodeGeneratorX86::Compare32BitValue(Register dest, int32_t value) {
void CodeGeneratorX86::GenerateIntCompare(Location lhs, Location rhs) {
Register lhs_reg = lhs.AsRegister<Register>();
+ GenerateIntCompare(lhs_reg, rhs);
+}
+
+void CodeGeneratorX86::GenerateIntCompare(Register lhs, Location rhs) {
if (rhs.IsConstant()) {
int32_t value = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
- Compare32BitValue(lhs_reg, value);
+ Compare32BitValue(lhs, value);
} else if (rhs.IsStackSlot()) {
- __ cmpl(lhs_reg, Address(ESP, rhs.GetStackIndex()));
+ __ cmpl(lhs, Address(ESP, rhs.GetStackIndex()));
} else {
- __ cmpl(lhs_reg, rhs.AsRegister<Register>());
+ __ cmpl(lhs, rhs.AsRegister<Register>());
}
}
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 27ea3bfc0a..1bd28da178 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -411,9 +411,8 @@ class CodeGeneratorX86 : public CodeGenerator {
void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE;
void RecordSimplePatch();
- void RecordBootStringPatch(HLoadString* load_string);
+ void RecordStringPatch(HLoadString* load_string);
void RecordTypePatch(HLoadClass* load_class);
- Label* NewStringBssEntryPatch(HLoadString* load_string);
Label* NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file, uint32_t element_offset);
void MoveFromReturnRegister(Location trg, Primitive::Type type) OVERRIDE;
@@ -475,6 +474,7 @@ class CodeGeneratorX86 : public CodeGenerator {
// Compare int values. Supports only register locations for `lhs`.
void GenerateIntCompare(Location lhs, Location rhs);
+ void GenerateIntCompare(Register lhs, Location rhs);
// Construct address for array access.
static Address ArrayAddress(Register obj,
@@ -580,9 +580,15 @@ class CodeGeneratorX86 : public CodeGenerator {
private:
Register GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke, Register temp);
- template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
- void EmitPcRelativeLinkerPatches(const ArenaDeque<PatchInfo<Label>>& infos,
- ArenaVector<LinkerPatch>* linker_patches);
+ struct PcRelativeDexCacheAccessInfo {
+ PcRelativeDexCacheAccessInfo(const DexFile& dex_file, uint32_t element_off)
+ : target_dex_file(dex_file), element_offset(element_off), label() { }
+
+ const DexFile& target_dex_file;
+ uint32_t element_offset;
+ // NOTE: Label is bound to the end of the instruction that has an embedded 32-bit offset.
+ Label label;
+ };
// Labels for each block that will be compiled.
Label* block_labels_; // Indexed by block id.
@@ -594,16 +600,16 @@ class CodeGeneratorX86 : public CodeGenerator {
const X86InstructionSetFeatures& isa_features_;
// Method patch info. Using ArenaDeque<> which retains element addresses on push/emplace_back().
- ArenaDeque<PatchInfo<Label>> method_patches_;
- ArenaDeque<PatchInfo<Label>> relative_call_patches_;
+ ArenaDeque<MethodPatchInfo<Label>> method_patches_;
+ ArenaDeque<MethodPatchInfo<Label>> relative_call_patches_;
// PC-relative DexCache access info.
- ArenaDeque<PatchInfo<Label>> pc_relative_dex_cache_patches_;
+ ArenaDeque<PcRelativeDexCacheAccessInfo> pc_relative_dex_cache_patches_;
// Patch locations for patchoat where the linker doesn't do any other work.
ArenaDeque<Label> simple_patches_;
- // String patch locations; type depends on configuration (app .bss or boot image PIC/non-PIC).
- ArenaDeque<PatchInfo<Label>> string_patches_;
+ // String patch locations.
+ ArenaDeque<StringPatchInfo<Label>> string_patches_;
// Type patch locations.
- ArenaDeque<PatchInfo<Label>> type_patches_;
+ ArenaDeque<TypePatchInfo<Label>> type_patches_;
// Offset to the start of the constant area in the assembled code.
// Used for fixups to the constant area.
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 95569a7903..b243ee0c59 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -198,6 +198,9 @@ class BoundsCheckSlowPathX86_64 : public SlowPathCode {
length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(2));
}
__ movl(length_loc.AsRegister<CpuRegister>(), array_len);
+ if (mirror::kUseStringCompression) {
+ __ andl(length_loc.AsRegister<CpuRegister>(), Immediate(INT32_MAX));
+ }
}
// We're moving two locations to locations that could overlap, so we need a parallel
@@ -284,44 +287,6 @@ class LoadClassSlowPathX86_64 : public SlowPathCode {
DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86_64);
};
-class LoadStringSlowPathX86_64 : public SlowPathCode {
- public:
- explicit LoadStringSlowPathX86_64(HLoadString* instruction) : SlowPathCode(instruction) {}
-
- void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
- LocationSummary* locations = instruction_->GetLocations();
- DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
-
- CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
- __ Bind(GetEntryLabel());
- SaveLiveRegisters(codegen, locations);
-
- InvokeRuntimeCallingConvention calling_convention;
- const uint32_t string_index = instruction_->AsLoadString()->GetStringIndex();
- __ movl(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(string_index));
- x86_64_codegen->InvokeRuntime(kQuickResolveString,
- instruction_,
- instruction_->GetDexPc(),
- this);
- CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
- x86_64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
- RestoreLiveRegisters(codegen, locations);
-
- // Store the resolved String to the BSS entry.
- __ movl(Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip */ false),
- locations->Out().AsRegister<CpuRegister>());
- Label* fixup_label = x86_64_codegen->NewStringBssEntryPatch(instruction_->AsLoadString());
- __ Bind(fixup_label);
-
- __ jmp(GetExitLabel());
- }
-
- const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathX86_64"; }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86_64);
-};
-
class TypeCheckSlowPathX86_64 : public SlowPathCode {
public:
TypeCheckSlowPathX86_64(HInstruction* instruction, bool is_fatal)
@@ -807,8 +772,7 @@ Location CodeGeneratorX86_64::GenerateCalleeMethodStaticOrDirectCall(HInvokeStat
break;
case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
__ movl(temp.AsRegister<CpuRegister>(), Immediate(0)); // Placeholder.
- method_patches_.emplace_back(*invoke->GetTargetMethod().dex_file,
- invoke->GetTargetMethod().dex_method_index);
+ method_patches_.emplace_back(invoke->GetTargetMethod());
__ Bind(&method_patches_.back().label); // Bind the label at the end of the "movl" insn.
break;
case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: {
@@ -855,8 +819,7 @@ void CodeGeneratorX86_64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invo
__ call(&frame_entry_label_);
break;
case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative: {
- relative_call_patches_.emplace_back(*invoke->GetTargetMethod().dex_file,
- invoke->GetTargetMethod().dex_method_index);
+ relative_call_patches_.emplace_back(invoke->GetTargetMethod());
Label* label = &relative_call_patches_.back().label;
__ call(label); // Bind to the patch label, override at link time.
__ Bind(label); // Bind the label at the end of the "call" insn.
@@ -916,8 +879,7 @@ void CodeGeneratorX86_64::RecordSimplePatch() {
}
}
-void CodeGeneratorX86_64::RecordBootStringPatch(HLoadString* load_string) {
- DCHECK(GetCompilerOptions().IsBootImage());
+void CodeGeneratorX86_64::RecordStringPatch(HLoadString* load_string) {
string_patches_.emplace_back(load_string->GetDexFile(), load_string->GetStringIndex());
__ Bind(&string_patches_.back().label);
}
@@ -927,12 +889,6 @@ void CodeGeneratorX86_64::RecordTypePatch(HLoadClass* load_class) {
__ Bind(&type_patches_.back().label);
}
-Label* CodeGeneratorX86_64::NewStringBssEntryPatch(HLoadString* load_string) {
- DCHECK(!GetCompilerOptions().IsBootImage());
- string_patches_.emplace_back(load_string->GetDexFile(), load_string->GetStringIndex());
- return &string_patches_.back().label;
-}
-
Label* CodeGeneratorX86_64::NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file,
uint32_t element_offset) {
// Add a patch entry and return the label.
@@ -940,21 +896,6 @@ Label* CodeGeneratorX86_64::NewPcRelativeDexCacheArrayPatch(const DexFile& dex_f
return &pc_relative_dex_cache_patches_.back().label;
}
-// The label points to the end of the "movl" or another instruction but the literal offset
-// for method patch needs to point to the embedded constant which occupies the last 4 bytes.
-constexpr uint32_t kLabelPositionToLiteralOffsetAdjustment = 4u;
-
-template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
-inline void CodeGeneratorX86_64::EmitPcRelativeLinkerPatches(
- const ArenaDeque<PatchInfo<Label>>& infos,
- ArenaVector<LinkerPatch>* linker_patches) {
- for (const PatchInfo<Label>& info : infos) {
- uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
- linker_patches->push_back(
- Factory(literal_offset, &info.dex_file, info.label.Position(), info.index));
- }
-}
-
void CodeGeneratorX86_64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
DCHECK(linker_patches->empty());
size_t size =
@@ -965,29 +906,48 @@ void CodeGeneratorX86_64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_pat
string_patches_.size() +
type_patches_.size();
linker_patches->reserve(size);
- for (const PatchInfo<Label>& info : method_patches_) {
+ // The label points to the end of the "movl" insn but the literal offset for method
+ // patch needs to point to the embedded constant which occupies the last 4 bytes.
+ constexpr uint32_t kLabelPositionToLiteralOffsetAdjustment = 4u;
+ for (const MethodPatchInfo<Label>& info : method_patches_) {
uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
- linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset, &info.dex_file, info.index));
+ linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
+ info.target_method.dex_file,
+ info.target_method.dex_method_index));
}
- for (const PatchInfo<Label>& info : relative_call_patches_) {
+ for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
- linker_patches->push_back(
- LinkerPatch::RelativeCodePatch(literal_offset, &info.dex_file, info.index));
+ linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
+ info.target_method.dex_file,
+ info.target_method.dex_method_index));
+ }
+ for (const PcRelativeDexCacheAccessInfo& info : pc_relative_dex_cache_patches_) {
+ uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
+ linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(literal_offset,
+ &info.target_dex_file,
+ info.label.Position(),
+ info.element_offset));
}
- EmitPcRelativeLinkerPatches<LinkerPatch::DexCacheArrayPatch>(pc_relative_dex_cache_patches_,
- linker_patches);
for (const Label& label : simple_patches_) {
uint32_t literal_offset = label.Position() - kLabelPositionToLiteralOffsetAdjustment;
linker_patches->push_back(LinkerPatch::RecordPosition(literal_offset));
}
- if (!GetCompilerOptions().IsBootImage()) {
- EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(string_patches_, linker_patches);
- } else {
+ for (const StringPatchInfo<Label>& info : string_patches_) {
// These are always PC-relative, see GetSupportedLoadStringKind().
- EmitPcRelativeLinkerPatches<LinkerPatch::RelativeStringPatch>(string_patches_, linker_patches);
+ uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
+ linker_patches->push_back(LinkerPatch::RelativeStringPatch(literal_offset,
+ &info.dex_file,
+ info.label.Position(),
+ info.string_index));
+ }
+ for (const TypePatchInfo<Label>& info : type_patches_) {
+ // These are always PC-relative, see GetSupportedLoadClassKind().
+ uint32_t literal_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
+ linker_patches->push_back(LinkerPatch::RelativeTypePatch(literal_offset,
+ &info.dex_file,
+ info.label.Position(),
+ info.type_index));
}
- // These are always PC-relative, see GetSupportedLoadClassKind().
- EmitPcRelativeLinkerPatches<LinkerPatch::RelativeTypePatch>(type_patches_, linker_patches);
}
void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
@@ -4528,7 +4488,21 @@ void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
case Primitive::kPrimChar: {
CpuRegister out = out_loc.AsRegister<CpuRegister>();
- __ movzxw(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_2, data_offset));
+ if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
+ // Branch cases into compressed and uncompressed for each index's type.
+ uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
+ NearLabel done, not_compressed;
+ __ cmpl(Address(obj, count_offset), Immediate(0));
+ codegen_->MaybeRecordImplicitNullCheck(instruction);
+ __ j(kGreaterEqual, &not_compressed);
+ __ movzxb(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_1, data_offset));
+ __ jmp(&done);
+ __ Bind(&not_compressed);
+ __ movzxw(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_2, data_offset));
+ __ Bind(&done);
+ } else {
+ __ movzxw(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_2, data_offset));
+ }
break;
}
@@ -4850,6 +4824,10 @@ void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction)
CpuRegister out = locations->Out().AsRegister<CpuRegister>();
__ movl(out, Address(obj, offset));
codegen_->MaybeRecordImplicitNullCheck(instruction);
+ // Mask out most significant bit in case the array is String's array of char.
+ if (mirror::kUseStringCompression && instruction->IsStringLength()) {
+ __ andl(out, Immediate(INT32_MAX));
+ }
}
void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
@@ -4899,13 +4877,23 @@ void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction)
uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(array_length->AsArrayLength());
Location array_loc = array_length->GetLocations()->InAt(0);
Address array_len(array_loc.AsRegister<CpuRegister>(), len_offset);
- if (index_loc.IsConstant()) {
- int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
- __ cmpl(array_len, Immediate(value));
+ if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
+ CpuRegister length_reg = CpuRegister(TMP);
+ __ movl(length_reg, array_len);
+ codegen_->MaybeRecordImplicitNullCheck(array_length);
+ __ andl(length_reg, Immediate(INT32_MAX));
+ codegen_->GenerateIntCompare(length_reg, index_loc);
} else {
- __ cmpl(array_len, index_loc.AsRegister<CpuRegister>());
+ // Checking the bound for general case:
+ // Array of char or String's array when the compression feature off.
+ if (index_loc.IsConstant()) {
+ int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
+ __ cmpl(array_len, Immediate(value));
+ } else {
+ __ cmpl(array_len, index_loc.AsRegister<CpuRegister>());
+ }
+ codegen_->MaybeRecordImplicitNullCheck(array_length);
}
- codegen_->MaybeRecordImplicitNullCheck(array_length);
} else {
codegen_->GenerateIntCompare(length_loc, index_loc);
}
@@ -5402,7 +5390,7 @@ HLoadString::LoadKind CodeGeneratorX86_64::GetSupportedLoadStringKind(
case HLoadString::LoadKind::kDexCacheAddress:
DCHECK(Runtime::Current()->UseJitCompilation());
break;
- case HLoadString::LoadKind::kBssEntry:
+ case HLoadString::LoadKind::kDexCachePcRelative:
DCHECK(!Runtime::Current()->UseJitCompilation());
break;
case HLoadString::LoadKind::kDexCacheViaMethod:
@@ -5413,9 +5401,7 @@ HLoadString::LoadKind CodeGeneratorX86_64::GetSupportedLoadStringKind(
void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
LocationSummary::CallKind call_kind = load->NeedsEnvironment()
- ? ((load->GetLoadKind() == HLoadString::LoadKind::kDexCacheViaMethod)
- ? LocationSummary::kCallOnMainOnly
- : LocationSummary::kCallOnSlowPath)
+ ? LocationSummary::kCallOnMainOnly
: LocationSummary::kNoCall;
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
if (load->GetLoadKind() == HLoadString::LoadKind::kDexCacheViaMethod) {
@@ -5434,7 +5420,7 @@ void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
switch (load->GetLoadKind()) {
case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
__ leal(out, Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip */ false));
- codegen_->RecordBootStringPatch(load);
+ codegen_->RecordStringPatch(load);
return; // No dex cache slow path.
}
case HLoadString::LoadKind::kBootImageAddress: {
@@ -5444,19 +5430,6 @@ void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
codegen_->RecordSimplePatch();
return; // No dex cache slow path.
}
- case HLoadString::LoadKind::kBssEntry: {
- Address address = Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset,
- /* no_rip */ false);
- Label* fixup_label = codegen_->NewStringBssEntryPatch(load);
- // /* GcRoot<mirror::Class> */ out = *address /* PC-relative */
- GenerateGcRootFieldLoad(load, out_loc, address, fixup_label);
- SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
- codegen_->AddSlowPath(slow_path);
- __ testl(out, out);
- __ j(kEqual, slow_path->GetEntryLabel());
- __ Bind(slow_path->GetExitLabel());
- return;
- }
default:
break;
}
@@ -6583,13 +6556,17 @@ void CodeGeneratorX86_64::Compare64BitValue(CpuRegister dest, int64_t value) {
void CodeGeneratorX86_64::GenerateIntCompare(Location lhs, Location rhs) {
CpuRegister lhs_reg = lhs.AsRegister<CpuRegister>();
+ GenerateIntCompare(lhs_reg, rhs);
+}
+
+void CodeGeneratorX86_64::GenerateIntCompare(CpuRegister lhs, Location rhs) {
if (rhs.IsConstant()) {
int32_t value = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
- Compare32BitValue(lhs_reg, value);
+ Compare32BitValue(lhs, value);
} else if (rhs.IsStackSlot()) {
- __ cmpl(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
+ __ cmpl(lhs, Address(CpuRegister(RSP), rhs.GetStackIndex()));
} else {
- __ cmpl(lhs_reg, rhs.AsRegister<CpuRegister>());
+ __ cmpl(lhs, rhs.AsRegister<CpuRegister>());
}
}
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index 74b065d317..8dec44eb03 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -406,9 +406,8 @@ class CodeGeneratorX86_64 : public CodeGenerator {
void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE;
void RecordSimplePatch();
- void RecordBootStringPatch(HLoadString* load_string);
+ void RecordStringPatch(HLoadString* load_string);
void RecordTypePatch(HLoadClass* load_class);
- Label* NewStringBssEntryPatch(HLoadString* load_string);
Label* NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file, uint32_t element_offset);
void MoveFromReturnRegister(Location trg, Primitive::Type type) OVERRIDE;
@@ -511,8 +510,9 @@ class CodeGeneratorX86_64 : public CodeGenerator {
void Compare32BitValue(CpuRegister dest, int32_t value);
void Compare64BitValue(CpuRegister dest, int64_t value);
- // Compare int values. Supports only register locations for `lhs`.
+ // Compare int values. Supports register locations for `lhs`.
void GenerateIntCompare(Location lhs, Location rhs);
+ void GenerateIntCompare(CpuRegister lhs, Location rhs);
// Compare long values. Supports only register locations for `lhs`.
void GenerateLongCompare(Location lhs, Location rhs);
@@ -555,9 +555,14 @@ class CodeGeneratorX86_64 : public CodeGenerator {
static constexpr int32_t kDummy32BitOffset = 256;
private:
- template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
- static void EmitPcRelativeLinkerPatches(const ArenaDeque<PatchInfo<Label>>& infos,
- ArenaVector<LinkerPatch>* linker_patches);
+ struct PcRelativeDexCacheAccessInfo {
+ PcRelativeDexCacheAccessInfo(const DexFile& dex_file, uint32_t element_off)
+ : target_dex_file(dex_file), element_offset(element_off), label() { }
+
+ const DexFile& target_dex_file;
+ uint32_t element_offset;
+ Label label;
+ };
// Labels for each block that will be compiled.
Label* block_labels_; // Indexed by block id.
@@ -573,16 +578,16 @@ class CodeGeneratorX86_64 : public CodeGenerator {
int constant_area_start_;
// Method patch info. Using ArenaDeque<> which retains element addresses on push/emplace_back().
- ArenaDeque<PatchInfo<Label>> method_patches_;
- ArenaDeque<PatchInfo<Label>> relative_call_patches_;
+ ArenaDeque<MethodPatchInfo<Label>> method_patches_;
+ ArenaDeque<MethodPatchInfo<Label>> relative_call_patches_;
// PC-relative DexCache access info.
- ArenaDeque<PatchInfo<Label>> pc_relative_dex_cache_patches_;
+ ArenaDeque<PcRelativeDexCacheAccessInfo> pc_relative_dex_cache_patches_;
// Patch locations for patchoat where the linker doesn't do any other work.
ArenaDeque<Label> simple_patches_;
- // String patch locations; type depends on configuration (app .bss or boot image PIC).
- ArenaDeque<PatchInfo<Label>> string_patches_;
+ // String patch locations.
+ ArenaDeque<StringPatchInfo<Label>> string_patches_;
// Type patch locations.
- ArenaDeque<PatchInfo<Label>> type_patches_;
+ ArenaDeque<TypePatchInfo<Label>> type_patches_;
// Fixups for jump tables need to be handled specially.
ArenaVector<JumpTableRIPFixup*> fixups_to_jump_tables_;
diff --git a/compiler/optimizing/dex_cache_array_fixups_arm.cc b/compiler/optimizing/dex_cache_array_fixups_arm.cc
index 82b81238ab..7010171c80 100644
--- a/compiler/optimizing/dex_cache_array_fixups_arm.cc
+++ b/compiler/optimizing/dex_cache_array_fixups_arm.cc
@@ -62,6 +62,21 @@ class DexCacheArrayFixupsVisitor : public HGraphVisitor {
}
}
+ void VisitLoadString(HLoadString* load_string) OVERRIDE {
+ // If this is a load with PC-relative access to the dex cache strings array,
+ // we need to add the dex cache arrays base as the special input.
+ if (load_string->GetLoadKind() == HLoadString::LoadKind::kDexCachePcRelative) {
+ // Initialize base for target dex file if needed.
+ const DexFile& dex_file = load_string->GetDexFile();
+ HArmDexCacheArraysBase* base = GetOrCreateDexCacheArrayBase(dex_file);
+ // Update the element offset in base.
+ DexCacheArraysLayout layout(kArmPointerSize, &dex_file);
+ base->UpdateElementOffset(layout.StringOffset(load_string->GetStringIndex()));
+ // Add the special argument base to the load.
+ load_string->AddSpecialInput(base);
+ }
+ }
+
void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE {
// If this is an invoke with PC-relative access to the dex cache methods array,
// we need to add the dex cache arrays base as the special input.
diff --git a/compiler/optimizing/dex_cache_array_fixups_mips.cc b/compiler/optimizing/dex_cache_array_fixups_mips.cc
index 31fff26dd5..4456b49e87 100644
--- a/compiler/optimizing/dex_cache_array_fixups_mips.cc
+++ b/compiler/optimizing/dex_cache_array_fixups_mips.cc
@@ -68,6 +68,21 @@ class DexCacheArrayFixupsVisitor : public HGraphVisitor {
}
}
+ void VisitLoadString(HLoadString* load_string) OVERRIDE {
+ // If this is a load with PC-relative access to the dex cache strings array,
+ // we need to add the dex cache arrays base as the special input.
+ if (load_string->GetLoadKind() == HLoadString::LoadKind::kDexCachePcRelative) {
+ // Initialize base for target dex file if needed.
+ const DexFile& dex_file = load_string->GetDexFile();
+ HMipsDexCacheArraysBase* base = GetOrCreateDexCacheArrayBase(dex_file);
+ // Update the element offset in base.
+ DexCacheArraysLayout layout(kMipsPointerSize, &dex_file);
+ base->UpdateElementOffset(layout.StringOffset(load_string->GetStringIndex()));
+ // Add the special argument base to the load.
+ load_string->AddSpecialInput(base);
+ }
+ }
+
void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE {
// If this is an invoke with PC-relative access to the dex cache methods array,
// we need to add the dex cache arrays base as the special input.
diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc
index e61aba05b4..f41e4d95b5 100644
--- a/compiler/optimizing/intrinsics_x86.cc
+++ b/compiler/optimizing/intrinsics_x86.cc
@@ -1401,23 +1401,39 @@ void IntrinsicCodeGeneratorX86::VisitStringEquals(HInvoke* invoke) {
__ cmpl(str, arg);
__ j(kEqual, &return_true);
- // Load length of receiver string.
+ // Load length and compression flag of receiver string.
__ movl(ecx, Address(str, count_offset));
- // Check if lengths are equal, return false if they're not.
+ // Check if lengths and compression flags are equal, return false if they're not.
+ // Two identical strings will always have same compression style since
+ // compression style is decided on alloc.
__ cmpl(ecx, Address(arg, count_offset));
__ j(kNotEqual, &return_false);
- // Return true if both strings are empty.
- __ jecxz(&return_true);
+ if (mirror::kUseStringCompression) {
+ NearLabel string_uncompressed;
+ // Differ cases into both compressed or both uncompressed. Different compression style
+ // is cut above.
+ __ cmpl(ecx, Immediate(0));
+ __ j(kGreaterEqual, &string_uncompressed);
+ // Divide string length by 2, rounding up, and continue as if uncompressed.
+ // Merge clearing the compression flag (+0x80000000) with +1 for rounding.
+ __ addl(ecx, Immediate(0x80000001));
+ __ shrl(ecx, Immediate(1));
+ __ Bind(&string_uncompressed);
+ }
+ // Return true if strings are empty.
+ __ jecxz(&return_true);
// Load starting addresses of string values into ESI/EDI as required for repe_cmpsl instruction.
__ leal(esi, Address(str, value_offset));
__ leal(edi, Address(arg, value_offset));
- // Divide string length by 2 to compare characters 2 at a time and adjust for odd lengths.
+ // Divide string length by 2 to compare characters 2 at a time and adjust for lengths not
+ // divisible by 2.
__ addl(ecx, Immediate(1));
__ shrl(ecx, Immediate(1));
- // Assertions that must hold in order to compare strings 2 characters at a time.
+ // Assertions that must hold in order to compare strings 2 characters (uncompressed)
+ // or 4 characters (compressed) at a time.
DCHECK_ALIGNED(value_offset, 4);
static_assert(IsAligned<4>(kObjectAlignment), "String of odd length is not zero padded");
@@ -1461,6 +1477,10 @@ static void CreateStringIndexOfLocations(HInvoke* invoke,
locations->AddTemp(Location::RegisterLocation(ECX));
// Need another temporary to be able to compute the result.
locations->AddTemp(Location::RequiresRegister());
+ if (mirror::kUseStringCompression) {
+ // Need another temporary to be able to save unflagged string length.
+ locations->AddTemp(Location::RequiresRegister());
+ }
}
static void GenerateStringIndexOf(HInvoke* invoke,
@@ -1478,6 +1498,8 @@ static void GenerateStringIndexOf(HInvoke* invoke,
Register counter = locations->GetTemp(0).AsRegister<Register>();
Register string_length = locations->GetTemp(1).AsRegister<Register>();
Register out = locations->Out().AsRegister<Register>();
+ // Only used when string compression feature is on.
+ Register string_length_flagged;
// Check our assumptions for registers.
DCHECK_EQ(string_obj, EDI);
@@ -1515,6 +1537,12 @@ static void GenerateStringIndexOf(HInvoke* invoke,
// Load string length, i.e., the count field of the string.
__ movl(string_length, Address(string_obj, count_offset));
+ if (mirror::kUseStringCompression) {
+ string_length_flagged = locations->GetTemp(2).AsRegister<Register>();
+ __ movl(string_length_flagged, string_length);
+ // Mask out first bit used as compression flag.
+ __ andl(string_length, Immediate(INT32_MAX));
+ }
// Do a zero-length check.
// TODO: Support jecxz.
@@ -1540,20 +1568,50 @@ static void GenerateStringIndexOf(HInvoke* invoke,
__ cmpl(start_index, Immediate(0));
__ cmovl(kGreater, counter, start_index);
- // Move to the start of the string: string_obj + value_offset + 2 * start_index.
- __ leal(string_obj, Address(string_obj, counter, ScaleFactor::TIMES_2, value_offset));
-
- // Now update ecx (the repne scasw work counter). We have string.length - start_index left to
- // compare.
+ if (mirror::kUseStringCompression) {
+ NearLabel modify_counter, offset_uncompressed_label;
+ __ cmpl(string_length_flagged, Immediate(0));
+ __ j(kGreaterEqual, &offset_uncompressed_label);
+ // Move to the start of the string: string_obj + value_offset + start_index.
+ __ leal(string_obj, Address(string_obj, counter, ScaleFactor::TIMES_1, value_offset));
+ __ jmp(&modify_counter);
+
+ // Move to the start of the string: string_obj + value_offset + 2 * start_index.
+ __ Bind(&offset_uncompressed_label);
+ __ leal(string_obj, Address(string_obj, counter, ScaleFactor::TIMES_2, value_offset));
+
+ // Now update ecx (the repne scasw work counter). We have string.length - start_index left to
+ // compare.
+ __ Bind(&modify_counter);
+ } else {
+ __ leal(string_obj, Address(string_obj, counter, ScaleFactor::TIMES_2, value_offset));
+ }
__ negl(counter);
__ leal(counter, Address(string_length, counter, ScaleFactor::TIMES_1, 0));
}
- // Everything is set up for repne scasw:
- // * Comparison address in EDI.
- // * Counter in ECX.
- __ repne_scasw();
-
+ if (mirror::kUseStringCompression) {
+ NearLabel uncompressed_string_comparison;
+ NearLabel comparison_done;
+ __ cmpl(string_length_flagged, Immediate(0));
+ __ j(kGreater, &uncompressed_string_comparison);
+
+ // Check if EAX (search_value) is ASCII.
+ __ cmpl(search_value, Immediate(127));
+ __ j(kGreater, &not_found_label);
+ // Comparing byte-per-byte.
+ __ repne_scasb();
+ __ jmp(&comparison_done);
+
+ // Everything is set up for repne scasw:
+ // * Comparison address in EDI.
+ // * Counter in ECX.
+ __ Bind(&uncompressed_string_comparison);
+ __ repne_scasw();
+ __ Bind(&comparison_done);
+ } else {
+ __ repne_scasw();
+ }
// Did we find a match?
__ j(kNotEqual, &not_found_label);
@@ -1706,38 +1764,64 @@ void IntrinsicCodeGeneratorX86::VisitStringGetCharsNoCheck(HInvoke* invoke) {
const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
DCHECK_EQ(char_size, 2u);
- // Compute the address of the destination buffer.
- __ leal(EDI, Address(dst, dstBegin, ScaleFactor::TIMES_2, data_offset));
-
- // Compute the address of the source string.
- if (srcBegin.IsConstant()) {
- // Compute the address of the source string by adding the number of chars from
- // the source beginning to the value offset of a string.
- __ leal(ESI, Address(obj, srcBegin_value * char_size + value_offset));
- } else {
- __ leal(ESI, Address(obj, srcBegin.AsRegister<Register>(),
- ScaleFactor::TIMES_2, value_offset));
- }
-
// Compute the number of chars (words) to move.
- // Now is the time to save ECX, since we don't know if it will be used later.
+ // Save ECX, since we don't know if it will be used later.
__ pushl(ECX);
int stack_adjust = kX86WordSize;
__ cfi().AdjustCFAOffset(stack_adjust);
DCHECK_EQ(srcEnd, ECX);
if (srcBegin.IsConstant()) {
- if (srcBegin_value != 0) {
- __ subl(ECX, Immediate(srcBegin_value));
- }
+ __ subl(ECX, Immediate(srcBegin_value));
} else {
DCHECK(srcBegin.IsRegister());
__ subl(ECX, srcBegin.AsRegister<Register>());
}
- // Do the move.
+ NearLabel done;
+ if (mirror::kUseStringCompression) {
+ // Location of count in string
+ const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
+ const size_t c_char_size = Primitive::ComponentSize(Primitive::kPrimByte);
+ DCHECK_EQ(c_char_size, 1u);
+ __ pushl(EAX);
+ __ cfi().AdjustCFAOffset(stack_adjust);
+
+ NearLabel copy_loop, copy_uncompressed;
+ __ cmpl(Address(obj, count_offset), Immediate(0));
+ __ j(kGreaterEqual, &copy_uncompressed);
+ // Compute the address of the source string by adding the number of chars from
+ // the source beginning to the value offset of a string.
+ __ leal(ESI, CodeGeneratorX86::ArrayAddress(obj, srcBegin, TIMES_1, value_offset));
+
+ // Start the loop to copy String's value to Array of Char.
+ __ leal(EDI, Address(dst, dstBegin, ScaleFactor::TIMES_2, data_offset));
+ __ Bind(&copy_loop);
+ __ jecxz(&done);
+ // Use EAX temporary (convert byte from ESI to word).
+ // TODO: Use LODSB/STOSW (not supported by X86Assembler) with AH initialized to 0.
+ __ movzxb(EAX, Address(ESI, 0));
+ __ movw(Address(EDI, 0), EAX);
+ __ leal(EDI, Address(EDI, char_size));
+ __ leal(ESI, Address(ESI, c_char_size));
+ // TODO: Add support for LOOP to X86Assembler.
+ __ subl(ECX, Immediate(1));
+ __ jmp(&copy_loop);
+ __ Bind(&copy_uncompressed);
+ }
+
+ // Do the copy for uncompressed string.
+ // Compute the address of the destination buffer.
+ __ leal(EDI, Address(dst, dstBegin, ScaleFactor::TIMES_2, data_offset));
+ __ leal(ESI, CodeGeneratorX86::ArrayAddress(obj, srcBegin, TIMES_2, value_offset));
__ rep_movsw();
- // And restore ECX.
+ __ Bind(&done);
+ if (mirror::kUseStringCompression) {
+ // Restore EAX.
+ __ popl(EAX);
+ __ cfi().AdjustCFAOffset(-stack_adjust);
+ }
+ // Restore ECX.
__ popl(ECX);
__ cfi().AdjustCFAOffset(-stack_adjust);
}
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index 0f31fabbfb..4b0afca122 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -1568,14 +1568,27 @@ void IntrinsicCodeGeneratorX86_64::VisitStringEquals(HInvoke* invoke) {
__ cmpl(str, arg);
__ j(kEqual, &return_true);
- // Load length of receiver string.
+ // Load length and compression flag of receiver string.
__ movl(rcx, Address(str, count_offset));
- // Check if lengths are equal, return false if they're not.
+ // Check if lengths and compressiond flags are equal, return false if they're not.
+ // Two identical strings will always have same compression style since
+ // compression style is decided on alloc.
__ cmpl(rcx, Address(arg, count_offset));
__ j(kNotEqual, &return_false);
+
+ if (mirror::kUseStringCompression) {
+ NearLabel string_uncompressed;
+ // Both string are compressed.
+ __ cmpl(rcx, Immediate(0));
+ __ j(kGreaterEqual, &string_uncompressed);
+ // Divide string length by 2, rounding up, and continue as if uncompressed.
+ // Merge clearing the compression flag with +1 for rounding.
+ __ addl(rcx, Immediate(static_cast<int32_t>(0x80000001)));
+ __ shrl(rcx, Immediate(1));
+ __ Bind(&string_uncompressed);
+ }
// Return true if both strings are empty.
__ jrcxz(&return_true);
-
// Load starting addresses of string values into RSI/RDI as required for repe_cmpsq instruction.
__ leal(rsi, Address(str, value_offset));
__ leal(rdi, Address(arg, value_offset));
@@ -1584,7 +1597,8 @@ void IntrinsicCodeGeneratorX86_64::VisitStringEquals(HInvoke* invoke) {
__ addl(rcx, Immediate(3));
__ shrl(rcx, Immediate(2));
- // Assertions that must hold in order to compare strings 4 characters at a time.
+ // Assertions that must hold in order to compare strings 4 characters (uncompressed)
+ // or 8 characters (compressed) at a time.
DCHECK_ALIGNED(value_offset, 8);
static_assert(IsAligned<8>(kObjectAlignment), "String is not zero padded");
@@ -1674,7 +1688,8 @@ static void GenerateStringIndexOf(HInvoke* invoke,
__ j(kAbove, slow_path->GetEntryLabel());
}
- // From here down, we know that we are looking for a char that fits in 16 bits.
+ // From here down, we know that we are looking for a char that fits in
+ // 16 bits (uncompressed) or 8 bits (compressed).
// Location of reference to data array within the String object.
int32_t value_offset = mirror::String::ValueOffset().Int32Value();
// Location of count within the String object.
@@ -1682,6 +1697,12 @@ static void GenerateStringIndexOf(HInvoke* invoke,
// Load string length, i.e., the count field of the string.
__ movl(string_length, Address(string_obj, count_offset));
+ if (mirror::kUseStringCompression) {
+ // Use TMP to keep string_length_flagged.
+ __ movl(CpuRegister(TMP), string_length);
+ // Mask out first bit used as compression flag.
+ __ andl(string_length, Immediate(INT32_MAX));
+ }
// Do a length check.
// TODO: Support jecxz.
@@ -1692,7 +1713,6 @@ static void GenerateStringIndexOf(HInvoke* invoke,
if (start_at_zero) {
// Number of chars to scan is the same as the string length.
__ movl(counter, string_length);
-
// Move to the start of the string.
__ addq(string_obj, Immediate(value_offset));
} else {
@@ -1707,19 +1727,44 @@ static void GenerateStringIndexOf(HInvoke* invoke,
__ cmpl(start_index, Immediate(0));
__ cmov(kGreater, counter, start_index, /* is64bit */ false); // 32-bit copy is enough.
- // Move to the start of the string: string_obj + value_offset + 2 * start_index.
- __ leaq(string_obj, Address(string_obj, counter, ScaleFactor::TIMES_2, value_offset));
-
+ if (mirror::kUseStringCompression) {
+ NearLabel modify_counter, offset_uncompressed_label;
+ __ cmpl(CpuRegister(TMP), Immediate(0));
+ __ j(kGreaterEqual, &offset_uncompressed_label);
+ __ leaq(string_obj, Address(string_obj, counter, ScaleFactor::TIMES_1, value_offset));
+ __ jmp(&modify_counter);
+ // Move to the start of the string: string_obj + value_offset + 2 * start_index.
+ __ Bind(&offset_uncompressed_label);
+ __ leaq(string_obj, Address(string_obj, counter, ScaleFactor::TIMES_2, value_offset));
+ __ Bind(&modify_counter);
+ } else {
+ __ leaq(string_obj, Address(string_obj, counter, ScaleFactor::TIMES_2, value_offset));
+ }
// Now update ecx, the work counter: it's gonna be string.length - start_index.
__ negq(counter); // Needs to be 64-bit negation, as the address computation is 64-bit.
__ leaq(counter, Address(string_length, counter, ScaleFactor::TIMES_1, 0));
}
- // Everything is set up for repne scasw:
- // * Comparison address in RDI.
- // * Counter in ECX.
- __ repne_scasw();
-
+ if (mirror::kUseStringCompression) {
+ NearLabel uncompressed_string_comparison;
+ NearLabel comparison_done;
+ __ cmpl(CpuRegister(TMP), Immediate(0));
+ __ j(kGreater, &uncompressed_string_comparison);
+ // Check if RAX (search_value) is ASCII.
+ __ cmpl(search_value, Immediate(127));
+ __ j(kGreater, &not_found_label);
+ // Comparing byte-per-byte.
+ __ repne_scasb();
+ __ jmp(&comparison_done);
+ // Everything is set up for repne scasw:
+ // * Comparison address in RDI.
+ // * Counter in ECX.
+ __ Bind(&uncompressed_string_comparison);
+ __ repne_scasw();
+ __ Bind(&comparison_done);
+ } else {
+ __ repne_scasw();
+ }
// Did we find a match?
__ j(kNotEqual, &not_found_label);
@@ -1871,32 +1916,54 @@ void IntrinsicCodeGeneratorX86_64::VisitStringGetCharsNoCheck(HInvoke* invoke) {
const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
DCHECK_EQ(char_size, 2u);
- // Compute the address of the destination buffer.
- __ leaq(CpuRegister(RDI), Address(dst, dstBegin, ScaleFactor::TIMES_2, data_offset));
-
- // Compute the address of the source string.
- if (srcBegin.IsConstant()) {
- // Compute the address of the source string by adding the number of chars from
- // the source beginning to the value offset of a string.
- __ leaq(CpuRegister(RSI), Address(obj, srcBegin_value * char_size + value_offset));
- } else {
- __ leaq(CpuRegister(RSI), Address(obj, srcBegin.AsRegister<CpuRegister>(),
- ScaleFactor::TIMES_2, value_offset));
- }
-
+ NearLabel done;
// Compute the number of chars (words) to move.
__ movl(CpuRegister(RCX), srcEnd);
if (srcBegin.IsConstant()) {
- if (srcBegin_value != 0) {
- __ subl(CpuRegister(RCX), Immediate(srcBegin_value));
- }
+ __ subl(CpuRegister(RCX), Immediate(srcBegin_value));
} else {
DCHECK(srcBegin.IsRegister());
__ subl(CpuRegister(RCX), srcBegin.AsRegister<CpuRegister>());
}
+ if (mirror::kUseStringCompression) {
+ NearLabel copy_uncompressed, copy_loop;
+ const size_t c_char_size = Primitive::ComponentSize(Primitive::kPrimByte);
+ DCHECK_EQ(c_char_size, 1u);
+ // Location of count in string.
+ const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
+ __ cmpl(Address(obj, count_offset), Immediate(0));
+ __ j(kGreaterEqual, &copy_uncompressed);
+ // Compute the address of the source string by adding the number of chars from
+ // the source beginning to the value offset of a string.
+ __ leaq(CpuRegister(RSI),
+ CodeGeneratorX86_64::ArrayAddress(obj, srcBegin, TIMES_1, value_offset));
+ // Start the loop to copy String's value to Array of Char.
+ __ leaq(CpuRegister(RDI), Address(dst, dstBegin, ScaleFactor::TIMES_2, data_offset));
+
+ __ Bind(&copy_loop);
+ __ jrcxz(&done);
+ // Use TMP as temporary (convert byte from RSI to word).
+ // TODO: Selecting RAX as the temporary and using LODSB/STOSW.
+ __ movzxb(CpuRegister(TMP), Address(CpuRegister(RSI), 0));
+ __ movw(Address(CpuRegister(RDI), 0), CpuRegister(TMP));
+ __ leaq(CpuRegister(RDI), Address(CpuRegister(RDI), char_size));
+ __ leaq(CpuRegister(RSI), Address(CpuRegister(RSI), c_char_size));
+ // TODO: Add support for LOOP to X86_64Assembler.
+ __ subl(CpuRegister(RCX), Immediate(1));
+ __ jmp(&copy_loop);
+
+ __ Bind(&copy_uncompressed);
+ }
+
+ __ leaq(CpuRegister(RSI),
+ CodeGeneratorX86_64::ArrayAddress(obj, srcBegin, TIMES_2, value_offset));
+ // Compute the address of the destination buffer.
+ __ leaq(CpuRegister(RDI), Address(dst, dstBegin, ScaleFactor::TIMES_2, data_offset));
// Do the move.
__ rep_movsw();
+
+ __ Bind(&done);
}
static void GenPeek(LocationSummary* locations, Primitive::Type size, X86_64Assembler* assembler) {
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index cea29bca2b..ef9bf23a17 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -2607,8 +2607,12 @@ bool HLoadString::InstructionDataEquals(const HInstruction* other) const {
LoadKind load_kind = GetLoadKind();
if (HasAddress(load_kind)) {
return GetAddress() == other_load_string->GetAddress();
+ } else if (HasStringReference(load_kind)) {
+ return IsSameDexFile(GetDexFile(), other_load_string->GetDexFile());
} else {
- DCHECK(HasStringReference(load_kind)) << load_kind;
+ DCHECK(HasDexCacheReference(load_kind)) << load_kind;
+ // If the string indexes and dex files are the same, dex cache element offsets
+ // must also be the same, so we don't need to compare them.
return IsSameDexFile(GetDexFile(), other_load_string->GetDexFile());
}
}
@@ -2638,8 +2642,8 @@ std::ostream& operator<<(std::ostream& os, HLoadString::LoadKind rhs) {
return os << "BootImageAddress";
case HLoadString::LoadKind::kDexCacheAddress:
return os << "DexCacheAddress";
- case HLoadString::LoadKind::kBssEntry:
- return os << "BssEntry";
+ case HLoadString::LoadKind::kDexCachePcRelative:
+ return os << "DexCachePcRelative";
case HLoadString::LoadKind::kDexCacheViaMethod:
return os << "DexCacheViaMethod";
default:
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 077e867d64..397abded27 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -5650,9 +5650,10 @@ class HLoadString FINAL : public HInstruction {
// Used for strings outside the boot image referenced by JIT-compiled code.
kDexCacheAddress,
- // Load from an entry in the .bss section using a PC-relative load.
- // Used for strings outside boot image when .bss is accessible with a PC-relative load.
- kBssEntry,
+ // Load from resolved strings array in the dex cache using a PC-relative load.
+ // Used for strings outside boot image when we know that we can access
+ // the dex cache arrays using a PC-relative load.
+ kDexCachePcRelative,
// Load from resolved strings array accessed through the class loaded from
// the compiled method's own ArtMethod*. This is the default access type when
@@ -5671,7 +5672,7 @@ class HLoadString FINAL : public HInstruction {
string_index_(string_index) {
SetPackedFlag<kFlagIsInDexCache>(false);
SetPackedField<LoadKindField>(LoadKind::kDexCacheViaMethod);
- load_data_.dex_file_ = &dex_file;
+ load_data_.ref.dex_file = &dex_file;
}
void SetLoadKindWithAddress(LoadKind load_kind, uint64_t address) {
@@ -5684,11 +5685,20 @@ class HLoadString FINAL : public HInstruction {
const DexFile& dex_file,
uint32_t string_index) {
DCHECK(HasStringReference(load_kind));
- load_data_.dex_file_ = &dex_file;
+ load_data_.ref.dex_file = &dex_file;
string_index_ = string_index;
SetLoadKindInternal(load_kind);
}
+ void SetLoadKindWithDexCacheReference(LoadKind load_kind,
+ const DexFile& dex_file,
+ uint32_t element_index) {
+ DCHECK(HasDexCacheReference(load_kind));
+ load_data_.ref.dex_file = &dex_file;
+ load_data_.ref.dex_cache_element_index = element_index;
+ SetLoadKindInternal(load_kind);
+ }
+
LoadKind GetLoadKind() const {
return GetPackedField<LoadKindField>();
}
@@ -5700,6 +5710,8 @@ class HLoadString FINAL : public HInstruction {
return string_index_;
}
+ uint32_t GetDexCacheElementOffset() const;
+
uint64_t GetAddress() const {
DCHECK(HasAddress(GetLoadKind()));
return load_data_.address;
@@ -5769,7 +5781,6 @@ class HLoadString FINAL : public HInstruction {
static bool HasStringReference(LoadKind load_kind) {
return load_kind == LoadKind::kBootImageLinkTimeAddress ||
load_kind == LoadKind::kBootImageLinkTimePcRelative ||
- load_kind == LoadKind::kBssEntry ||
load_kind == LoadKind::kDexCacheViaMethod;
}
@@ -5777,6 +5788,10 @@ class HLoadString FINAL : public HInstruction {
return load_kind == LoadKind::kBootImageAddress || load_kind == LoadKind::kDexCacheAddress;
}
+ static bool HasDexCacheReference(LoadKind load_kind) {
+ return load_kind == LoadKind::kDexCachePcRelative;
+ }
+
void SetLoadKindInternal(LoadKind load_kind);
// The special input is the HCurrentMethod for kDexCacheViaMethod.
@@ -5789,7 +5804,10 @@ class HLoadString FINAL : public HInstruction {
uint32_t string_index_;
union {
- const DexFile* dex_file_; // For string reference.
+ struct {
+ const DexFile* dex_file; // For string reference and dex cache reference.
+ uint32_t dex_cache_element_index; // Only for dex cache reference.
+ } ref;
uint64_t address; // Up to 64-bit, needed for kDexCacheAddress on 64-bit targets.
} load_data_;
@@ -5799,8 +5817,15 @@ std::ostream& operator<<(std::ostream& os, HLoadString::LoadKind rhs);
// Note: defined outside class to see operator<<(., HLoadString::LoadKind).
inline const DexFile& HLoadString::GetDexFile() const {
- DCHECK(HasStringReference(GetLoadKind())) << GetLoadKind();
- return *load_data_.dex_file_;
+ DCHECK(HasStringReference(GetLoadKind()) || HasDexCacheReference(GetLoadKind()))
+ << GetLoadKind();
+ return *load_data_.ref.dex_file;
+}
+
+// Note: defined outside class to see operator<<(., HLoadString::LoadKind).
+inline uint32_t HLoadString::GetDexCacheElementOffset() const {
+ DCHECK(HasDexCacheReference(GetLoadKind())) << GetLoadKind();
+ return load_data_.ref.dex_cache_element_index;
}
// Note: defined outside class to see operator<<(., HLoadString::LoadKind).
@@ -5808,7 +5833,7 @@ inline void HLoadString::AddSpecialInput(HInstruction* special_input) {
// The special input is used for PC-relative loads on some architectures,
// including literal pool loads, which are PC-relative too.
DCHECK(GetLoadKind() == LoadKind::kBootImageLinkTimePcRelative ||
- GetLoadKind() == LoadKind::kBssEntry ||
+ GetLoadKind() == LoadKind::kDexCachePcRelative ||
GetLoadKind() == LoadKind::kBootImageLinkTimeAddress ||
GetLoadKind() == LoadKind::kBootImageAddress) << GetLoadKind();
// HLoadString::GetInputRecords() returns an empty array at this point,
diff --git a/compiler/optimizing/pc_relative_fixups_mips.cc b/compiler/optimizing/pc_relative_fixups_mips.cc
index 82feb95a2f..6006e6cf5d 100644
--- a/compiler/optimizing/pc_relative_fixups_mips.cc
+++ b/compiler/optimizing/pc_relative_fixups_mips.cc
@@ -83,7 +83,6 @@ class PCRelativeHandlerVisitor : public HGraphVisitor {
case HLoadString::LoadKind::kBootImageLinkTimeAddress:
case HLoadString::LoadKind::kBootImageAddress:
case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
- case HLoadString::LoadKind::kBssEntry:
// Add a base register for PC-relative literals on R2.
InitializePCRelativeBasePointer();
load_string->AddSpecialInput(base_);
diff --git a/compiler/optimizing/pc_relative_fixups_x86.cc b/compiler/optimizing/pc_relative_fixups_x86.cc
index b1fdb1792d..75587af7a1 100644
--- a/compiler/optimizing/pc_relative_fixups_x86.cc
+++ b/compiler/optimizing/pc_relative_fixups_x86.cc
@@ -92,7 +92,7 @@ class PCRelativeHandlerVisitor : public HGraphVisitor {
void VisitLoadString(HLoadString* load_string) OVERRIDE {
HLoadString::LoadKind load_kind = load_string->GetLoadKind();
if (load_kind == HLoadString::LoadKind::kBootImageLinkTimePcRelative ||
- load_kind == HLoadString::LoadKind::kBssEntry) {
+ load_kind == HLoadString::LoadKind::kDexCachePcRelative) {
InitializePCRelativeBasePointer();
load_string->AddSpecialInput(base_);
}
diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc
index c1cfe8d00f..a4a3e0695d 100644
--- a/compiler/optimizing/sharpening.cc
+++ b/compiler/optimizing/sharpening.cc
@@ -163,7 +163,7 @@ void HSharpening::ProcessLoadClass(HLoadClass* load_class) {
: hs.NewHandle(class_linker->FindDexCache(soa.Self(), dex_file));
mirror::Class* klass = dex_cache->GetResolvedType(type_index);
- if (codegen_->GetCompilerOptions().IsBootImage()) {
+ if (compiler_driver_->IsBootImage()) {
// Compiling boot image. Check if the class is a boot image class.
DCHECK(!runtime->UseJitCompilation());
if (!compiler_driver_->GetSupportBootImageFixup()) {
@@ -281,7 +281,7 @@ void HSharpening::ProcessLoadString(HLoadString* load_string) {
? compilation_unit_.GetDexCache()
: hs.NewHandle(class_linker->FindDexCache(soa.Self(), dex_file));
- if (codegen_->GetCompilerOptions().IsBootImage()) {
+ if (compiler_driver_->IsBootImage()) {
// Compiling boot image. Resolve the string and allocate it if needed.
DCHECK(!runtime->UseJitCompilation());
mirror::String* string = class_linker->ResolveString(dex_file, string_index, dex_cache);
@@ -311,8 +311,6 @@ void HSharpening::ProcessLoadString(HLoadString* load_string) {
!codegen_->GetCompilerOptions().GetCompilePic()) {
desired_load_kind = HLoadString::LoadKind::kBootImageAddress;
address = reinterpret_cast64<uint64_t>(string);
- } else {
- desired_load_kind = HLoadString::LoadKind::kBssEntry;
}
}
}
@@ -321,7 +319,6 @@ void HSharpening::ProcessLoadString(HLoadString* load_string) {
switch (load_kind) {
case HLoadString::LoadKind::kBootImageLinkTimeAddress:
case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
- case HLoadString::LoadKind::kBssEntry:
case HLoadString::LoadKind::kDexCacheViaMethod:
load_string->SetLoadKindWithStringReference(load_kind, dex_file, string_index);
break;
@@ -330,6 +327,13 @@ void HSharpening::ProcessLoadString(HLoadString* load_string) {
DCHECK_NE(address, 0u);
load_string->SetLoadKindWithAddress(load_kind, address);
break;
+ case HLoadString::LoadKind::kDexCachePcRelative: {
+ PointerSize pointer_size = InstructionSetPointerSize(codegen_->GetInstructionSet());
+ DexCacheArraysLayout layout(pointer_size, &dex_file);
+ size_t element_index = layout.StringOffset(string_index);
+ load_string->SetLoadKindWithDexCacheReference(load_kind, dex_file, element_index);
+ break;
+ }
}
}