diff options
Diffstat (limited to 'compiler/optimizing')
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, ¬_compressed); +        __ movzxb(out, CodeGeneratorX86::ArrayAddress(obj, index, TIMES_1, data_offset)); +        __ jmp(&done); +        __ Bind(¬_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, ¬_compressed); +        __ movzxb(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_1, data_offset)); +        __ jmp(&done); +        __ Bind(¬_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, ¬_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, ¬_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, ©_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(©_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(©_loop); +    __ Bind(©_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, ¬_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, ¬_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, ©_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(©_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(©_loop); + +    __ Bind(©_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; +    }    }  }  |