diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2024-01-20 02:22:07 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2024-01-20 02:22:07 +0000 |
commit | 3b42b7471a9043306321139c9b7ae31e916280c8 (patch) | |
tree | 6f801c8690ed6e4e8736781568c8ba029825f95a | |
parent | 0bd302a69360d088c60b62e199712d9d178a3d76 (diff) | |
parent | 16f474294d94a8a3d032d2ad706d7299fb6f490e (diff) | |
download | art-android-u-qpr3-beta-1-gpl.tar.gz |
Snap for 11335836 from 16f474294d94a8a3d032d2ad706d7299fb6f490e to 24Q2-beta-releaseandroid-u-qpr3-beta-1-gplandroid-u-qpr3-beta-1-gpl
Change-Id: I3bab9b05878119523e57bac0eb063bbcf9165674
377 files changed, 2880 insertions, 2079 deletions
diff --git a/OWNERS_boot_profile b/OWNERS_boot_profile new file mode 100644 index 0000000000..b4b2f80e79 --- /dev/null +++ b/OWNERS_boot_profile @@ -0,0 +1,4 @@ +# Owners of boot image and system server profiles. +islamelbanna@google.com +ngeoffray@google.com +vmarko@google.com diff --git a/build/boot/Android.bp b/build/boot/Android.bp index 292bb6fbe4..e0bf395872 100644 --- a/build/boot/Android.bp +++ b/build/boot/Android.bp @@ -21,9 +21,52 @@ package { default_applicable_licenses: ["art_license"], } +// TODO: b/319697968 - Remove the conditional logic and let art-bootclasspath-fragment always +// depend on the exportable stubs once metalava fully supports flagged api handling. +soong_config_module_type { + name: "art_bootclasspath_fragment_soong_config_defaults", + module_type: "java_defaults", + config_namespace: "ANDROID", + bool_variables: [ + "release_hidden_api_exportable_stubs", + ], + properties: [ + "core_platform_api.stub_libs", + ], +} + +art_bootclasspath_fragment_soong_config_defaults { + name: "art-bootclasspath-fragment-soong-config-defaults", + soong_config_variables: { + release_hidden_api_exportable_stubs: { + // When "RELEASE_HIDDEN_API_EXPORTABLE_STUBS" build flag is set, + // depend on the exportable stubs + core_platform_api: { + stub_libs: [ + // Core platform (aka. module_lib) stubs for all the non-coverage contents. + "art.module.public.api.stubs.exportable.module_lib", + ], + }, + conditions_default: { + // When "RELEASE_HIDDEN_API_EXPORTABLE_STUBS" build flag is not set, + // depend on the everything stubs + core_platform_api: { + stub_libs: [ + // Core platform (aka. module_lib) stubs for all the non-coverage contents. + "art.module.public.api.stubs.module_lib", + ], + }, + }, + }, + }, +} + // Encapsulate the contributions made by the com.android.art to the bootclasspath. bootclasspath_fragment { name: "art-bootclasspath-fragment", + defaults: [ + "art-bootclasspath-fragment-soong-config-defaults", + ], image_name: "art", // Must match the ART_APEX_JARS set in build/make/core/envsetup.mk contents: [ @@ -41,12 +84,6 @@ bootclasspath_fragment { "art.module.public.api", ], }, - core_platform_api: { - stub_libs: [ - // Core platform (aka. module_lib) stubs for all the non-coverage contents. - "art.module.public.api.stubs.module_lib", - ], - }, // Additional properties to append when coverage is enabled, i.e. when // EMMA_INSTRUMENT_FRAMEWORK=true diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc index c14d5d37e8..523a666f8a 100644 --- a/compiler/jit/jit_compiler.cc +++ b/compiler/jit/jit_compiler.cc @@ -226,9 +226,5 @@ bool JitCompiler::IsBaselineCompiler() const { return compiler_options_->IsBaseline(); } -uint32_t JitCompiler::GetInlineMaxCodeUnits() const { - return compiler_options_->GetInlineMaxCodeUnits(); -} - } // namespace jit } // namespace art diff --git a/compiler/jit/jit_compiler.h b/compiler/jit/jit_compiler.h index 66aa545dd7..5a919fb612 100644 --- a/compiler/jit/jit_compiler.h +++ b/compiler/jit/jit_compiler.h @@ -64,8 +64,6 @@ class JitCompiler : public JitCompilerInterface { bool compress, /*out*/ size_t* num_symbols) override; - uint32_t GetInlineMaxCodeUnits() const override; - private: std::unique_ptr<CompilerOptions> compiler_options_; std::unique_ptr<Compiler> compiler_; diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index f12df196e5..9027976165 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -847,8 +847,8 @@ class MethodEntryExitHooksSlowPathARM64 : public SlowPathCodeARM64 { class CompileOptimizedSlowPathARM64 : public SlowPathCodeARM64 { public: - CompileOptimizedSlowPathARM64(HSuspendCheck* check, Register profiling_info) - : SlowPathCodeARM64(check), + explicit CompileOptimizedSlowPathARM64(Register profiling_info) + : SlowPathCodeARM64(/* instruction= */ nullptr), profiling_info_(profiling_info) {} void EmitNativeCode(CodeGenerator* codegen) override { @@ -861,18 +861,10 @@ class CompileOptimizedSlowPathARM64 : public SlowPathCodeARM64 { __ Mov(counter, ProfilingInfo::GetOptimizeThreshold()); __ Strh(counter, MemOperand(profiling_info_, ProfilingInfo::BaselineHotnessCountOffset().Int32Value())); - if (instruction_ != nullptr) { - // Only saves live vector regs for SIMD. - SaveLiveRegisters(codegen, instruction_->GetLocations()); - } __ Ldr(lr, MemOperand(tr, entrypoint_offset)); // Note: we don't record the call here (and therefore don't generate a stack // map), as the entrypoint should never be suspended. __ Blr(lr); - if (instruction_ != nullptr) { - // Only restores live vector regs for SIMD. - RestoreLiveRegisters(codegen, instruction_->GetLocations()); - } __ B(GetExitLabel()); } @@ -1288,7 +1280,7 @@ void InstructionCodeGeneratorARM64::VisitMethodEntryHook(HMethodEntryHook* instr GenerateMethodEntryExitHook(instruction); } -void CodeGeneratorARM64::MaybeIncrementHotness(HSuspendCheck* suspend_check, bool is_frame_entry) { +void CodeGeneratorARM64::MaybeIncrementHotness(bool is_frame_entry) { MacroAssembler* masm = GetVIXLAssembler(); if (GetCompilerOptions().CountHotnessInCompiledCode()) { UseScratchRegisterScope temps(masm); @@ -1311,10 +1303,11 @@ void CodeGeneratorARM64::MaybeIncrementHotness(HSuspendCheck* suspend_check, boo DCHECK(info != nullptr); DCHECK(!HasEmptyFrame()); uint64_t address = reinterpret_cast64<uint64_t>(info); + vixl::aarch64::Label done; UseScratchRegisterScope temps(masm); Register counter = temps.AcquireW(); - SlowPathCodeARM64* slow_path = new (GetScopedAllocator()) CompileOptimizedSlowPathARM64( - suspend_check, /* profiling_info= */ lr); + SlowPathCodeARM64* slow_path = + new (GetScopedAllocator()) CompileOptimizedSlowPathARM64(/* profiling_info= */ lr); AddSlowPath(slow_path); __ Ldr(lr, jit_patches_.DeduplicateUint64Literal(address)); __ Ldrh(counter, MemOperand(lr, ProfilingInfo::BaselineHotnessCountOffset().Int32Value())); @@ -1438,7 +1431,7 @@ void CodeGeneratorARM64::GenerateFrameEntry() { __ Str(wzr, MemOperand(sp, GetStackOffsetOfShouldDeoptimizeFlag())); } } - MaybeIncrementHotness(/* suspend_check= */ nullptr, /* is_frame_entry= */ true); + MaybeIncrementHotness(/* is_frame_entry= */ true); MaybeGenerateMarkingRegisterCheck(/* code= */ __LINE__); } @@ -3699,7 +3692,7 @@ void InstructionCodeGeneratorARM64::HandleGoto(HInstruction* got, HBasicBlock* s HLoopInformation* info = block->GetLoopInformation(); if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) { - codegen_->MaybeIncrementHotness(info->GetSuspendCheck(), /* is_frame_entry= */ false); + codegen_->MaybeIncrementHotness(/* is_frame_entry= */ false); GenerateSuspendCheck(info->GetSuspendCheck(), successor); return; // `GenerateSuspendCheck()` emitted the jump. } @@ -4604,8 +4597,7 @@ void CodeGeneratorARM64::MaybeGenerateInlineCacheCheck(HInstruction* instruction if (ProfilingInfoBuilder::IsInlineCacheUseful(instruction->AsInvoke(), this)) { ProfilingInfo* info = GetGraph()->GetProfilingInfo(); DCHECK(info != nullptr); - InlineCache* cache = ProfilingInfoBuilder::GetInlineCache( - info, GetCompilerOptions(), instruction->AsInvoke()); + InlineCache* cache = ProfilingInfoBuilder::GetInlineCache(info, instruction->AsInvoke()); if (cache != nullptr) { uint64_t address = reinterpret_cast64<uint64_t>(cache); vixl::aarch64::Label done; diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h index 9c7c42f4c7..7ff08f55cb 100644 --- a/compiler/optimizing/code_generator_arm64.h +++ b/compiler/optimizing/code_generator_arm64.h @@ -1017,7 +1017,7 @@ class CodeGeneratorARM64 : public CodeGenerator { } void MaybeGenerateInlineCacheCheck(HInstruction* instruction, vixl::aarch64::Register klass); - void MaybeIncrementHotness(HSuspendCheck* suspend_check, bool is_frame_entry); + void MaybeIncrementHotness(bool is_frame_entry); bool CanUseImplicitSuspendCheck() const; diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc index 0f9dcb4a5a..00c14b0b46 100644 --- a/compiler/optimizing/code_generator_arm_vixl.cc +++ b/compiler/optimizing/code_generator_arm_vixl.cc @@ -971,9 +971,8 @@ class MethodEntryExitHooksSlowPathARMVIXL : public SlowPathCodeARMVIXL { class CompileOptimizedSlowPathARMVIXL : public SlowPathCodeARMVIXL { public: - CompileOptimizedSlowPathARMVIXL(HSuspendCheck* suspend_check, - vixl32::Register profiling_info) - : SlowPathCodeARMVIXL(suspend_check), + explicit CompileOptimizedSlowPathARMVIXL(vixl32::Register profiling_info) + : SlowPathCodeARMVIXL(/* instruction= */ nullptr), profiling_info_(profiling_info) {} void EmitNativeCode(CodeGenerator* codegen) override { @@ -2276,8 +2275,7 @@ void InstructionCodeGeneratorARMVIXL::VisitMethodEntryHook(HMethodEntryHook* ins GenerateMethodEntryExitHook(instruction); } -void CodeGeneratorARMVIXL::MaybeIncrementHotness(HSuspendCheck* suspend_check, - bool is_frame_entry) { +void CodeGeneratorARMVIXL::MaybeIncrementHotness(bool is_frame_entry) { if (GetCompilerOptions().CountHotnessInCompiledCode()) { UseScratchRegisterScope temps(GetVIXLAssembler()); vixl32::Register temp = temps.Acquire(); @@ -2308,8 +2306,8 @@ void CodeGeneratorARMVIXL::MaybeIncrementHotness(HSuspendCheck* suspend_check, uint32_t address = reinterpret_cast32<uint32_t>(info); UseScratchRegisterScope temps(GetVIXLAssembler()); vixl32::Register tmp = temps.Acquire(); - SlowPathCodeARMVIXL* slow_path = new (GetScopedAllocator()) CompileOptimizedSlowPathARMVIXL( - suspend_check, /* profiling_info= */ lr); + SlowPathCodeARMVIXL* slow_path = + new (GetScopedAllocator()) CompileOptimizedSlowPathARMVIXL(/* profiling_info= */ lr); AddSlowPath(slow_path); __ Mov(lr, address); __ Ldrh(tmp, MemOperand(lr, ProfilingInfo::BaselineHotnessCountOffset().Int32Value())); @@ -2384,7 +2382,7 @@ void CodeGeneratorARMVIXL::GenerateFrameEntry() { if (HasEmptyFrame()) { // Ensure that the CFI opcode list is not empty. GetAssembler()->cfi().Nop(); - MaybeIncrementHotness(/* suspend_check= */ nullptr, /* is_frame_entry= */ true); + MaybeIncrementHotness(/* is_frame_entry= */ true); return; } @@ -2484,7 +2482,7 @@ void CodeGeneratorARMVIXL::GenerateFrameEntry() { GetAssembler()->StoreToOffset(kStoreWord, temp, sp, GetStackOffsetOfShouldDeoptimizeFlag()); } - MaybeIncrementHotness(/* suspend_check= */ nullptr, /* is_frame_entry= */ true); + MaybeIncrementHotness(/* is_frame_entry= */ true); MaybeGenerateMarkingRegisterCheck(/* code= */ 1); } @@ -2829,7 +2827,7 @@ void InstructionCodeGeneratorARMVIXL::HandleGoto(HInstruction* got, HBasicBlock* HLoopInformation* info = block->GetLoopInformation(); if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) { - codegen_->MaybeIncrementHotness(info->GetSuspendCheck(), /* is_frame_entry= */ false); + codegen_->MaybeIncrementHotness(/* is_frame_entry= */ false); GenerateSuspendCheck(info->GetSuspendCheck(), successor); return; } @@ -3689,8 +3687,7 @@ void CodeGeneratorARMVIXL::MaybeGenerateInlineCacheCheck(HInstruction* instructi DCHECK_EQ(r0.GetCode(), klass.GetCode()); if (ProfilingInfoBuilder::IsInlineCacheUseful(instruction->AsInvoke(), this)) { ProfilingInfo* info = GetGraph()->GetProfilingInfo(); - InlineCache* cache = ProfilingInfoBuilder::GetInlineCache( - info, GetCompilerOptions(), instruction->AsInvoke()); + InlineCache* cache = ProfilingInfoBuilder::GetInlineCache(info, instruction->AsInvoke()); if (cache != nullptr) { uint32_t address = reinterpret_cast32<uint32_t>(cache); vixl32::Label done; diff --git a/compiler/optimizing/code_generator_arm_vixl.h b/compiler/optimizing/code_generator_arm_vixl.h index 11b60b3fd2..00e0bfa399 100644 --- a/compiler/optimizing/code_generator_arm_vixl.h +++ b/compiler/optimizing/code_generator_arm_vixl.h @@ -885,7 +885,7 @@ class CodeGeneratorARMVIXL : public CodeGenerator { } void MaybeGenerateInlineCacheCheck(HInstruction* instruction, vixl32::Register klass); - void MaybeIncrementHotness(HSuspendCheck* suspend_check, bool is_frame_entry); + void MaybeIncrementHotness(bool is_frame_entry); private: // Encoding of thunk type and data for link-time generated thunks for Baker read barriers. diff --git a/compiler/optimizing/code_generator_riscv64.cc b/compiler/optimizing/code_generator_riscv64.cc index 108c948345..0c0b8a9f14 100644 --- a/compiler/optimizing/code_generator_riscv64.cc +++ b/compiler/optimizing/code_generator_riscv64.cc @@ -266,8 +266,8 @@ void LocationsBuilderRISCV64::HandleInvoke(HInvoke* instruction) { class CompileOptimizedSlowPathRISCV64 : public SlowPathCodeRISCV64 { public: - CompileOptimizedSlowPathRISCV64(HSuspendCheck* suspend_check, XRegister base, int32_t imm12) - : SlowPathCodeRISCV64(suspend_check), + CompileOptimizedSlowPathRISCV64(XRegister base, int32_t imm12) + : SlowPathCodeRISCV64(/*instruction=*/ nullptr), base_(base), imm12_(imm12) {} @@ -280,18 +280,10 @@ class CompileOptimizedSlowPathRISCV64 : public SlowPathCodeRISCV64 { XRegister counter = srs.AllocateXRegister(); __ LoadConst32(counter, ProfilingInfo::GetOptimizeThreshold()); __ Sh(counter, base_, imm12_); - if (instruction_ != nullptr) { - // Only saves live vector regs for SIMD. - SaveLiveRegisters(codegen, instruction_->GetLocations()); - } __ Loadd(RA, TR, entrypoint_offset); // Note: we don't record the call here (and therefore don't generate a stack // map), as the entrypoint should never be suspended. __ Jalr(RA); - if (instruction_ != nullptr) { - // Only restores live vector regs for SIMD. - RestoreLiveRegisters(codegen, instruction_->GetLocations()); - } __ J(GetExitLabel()); } @@ -2017,7 +2009,7 @@ void InstructionCodeGeneratorRISCV64::HandleGoto(HInstruction* instruction, HLoopInformation* info = block->GetLoopInformation(); if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) { - codegen_->MaybeIncrementHotness(info->GetSuspendCheck(), /*is_frame_entry=*/ false); + codegen_->MaybeIncrementHotness(/*is_frame_entry=*/ false); GenerateSuspendCheck(info->GetSuspendCheck(), successor); return; // `GenerateSuspendCheck()` emitted the jump. } @@ -5702,8 +5694,7 @@ CodeGeneratorRISCV64::CodeGeneratorRISCV64(HGraph* graph, AddAllocatedRegister(Location::RegisterLocation(RA)); } -void CodeGeneratorRISCV64::MaybeIncrementHotness(HSuspendCheck* suspend_check, - bool is_frame_entry) { +void CodeGeneratorRISCV64::MaybeIncrementHotness(bool is_frame_entry) { if (GetCompilerOptions().CountHotnessInCompiledCode()) { ScratchRegisterScope srs(GetAssembler()); XRegister method = is_frame_entry ? kArtMethodRegister : srs.AllocateXRegister(); @@ -5735,7 +5726,7 @@ void CodeGeneratorRISCV64::MaybeIncrementHotness(HSuspendCheck* suspend_check, XRegister tmp = RA; __ LoadConst64(tmp, base_address); SlowPathCodeRISCV64* slow_path = - new (GetScopedAllocator()) CompileOptimizedSlowPathRISCV64(suspend_check, tmp, imm12); + new (GetScopedAllocator()) CompileOptimizedSlowPathRISCV64(tmp, imm12); AddSlowPath(slow_path); __ Lhu(counter, tmp, imm12); __ Beqz(counter, slow_path->GetEntryLabel()); // Can clobber `TMP` if taken. @@ -5880,7 +5871,7 @@ void CodeGeneratorRISCV64::GenerateFrameEntry() { __ Storew(Zero, SP, GetStackOffsetOfShouldDeoptimizeFlag()); } } - MaybeIncrementHotness(/* suspend_check= */ nullptr, /*is_frame_entry=*/ true); + MaybeIncrementHotness(/*is_frame_entry=*/ true); } void CodeGeneratorRISCV64::GenerateFrameExit() { @@ -6743,8 +6734,7 @@ void CodeGeneratorRISCV64::MaybeGenerateInlineCacheCheck(HInstruction* instructi if (ProfilingInfoBuilder::IsInlineCacheUseful(instruction->AsInvoke(), this)) { ProfilingInfo* info = GetGraph()->GetProfilingInfo(); DCHECK(info != nullptr); - InlineCache* cache = ProfilingInfoBuilder::GetInlineCache( - info, GetCompilerOptions(), instruction->AsInvoke()); + InlineCache* cache = ProfilingInfoBuilder::GetInlineCache(info, instruction->AsInvoke()); if (cache != nullptr) { uint64_t address = reinterpret_cast64<uint64_t>(cache); Riscv64Label done; diff --git a/compiler/optimizing/code_generator_riscv64.h b/compiler/optimizing/code_generator_riscv64.h index 29ccf9dc0b..321403f7f2 100644 --- a/compiler/optimizing/code_generator_riscv64.h +++ b/compiler/optimizing/code_generator_riscv64.h @@ -76,9 +76,6 @@ static constexpr int32_t kFClassNaNMinValue = 0x100; V(StringGetCharsNoCheck) \ V(StringStringIndexOf) \ V(StringStringIndexOfAfter) \ - V(StringNewStringFromBytes) \ - V(StringNewStringFromChars) \ - V(StringNewStringFromString) \ V(StringBufferAppend) \ V(StringBufferLength) \ V(StringBufferToString) \ @@ -94,7 +91,6 @@ static constexpr int32_t kFClassNaNMinValue = 0x100; V(StringBuilderAppendDouble) \ V(StringBuilderLength) \ V(StringBuilderToString) \ - V(ThreadInterrupted) \ V(CRC32Update) \ V(CRC32UpdateBytes) \ V(CRC32UpdateByteBuffer) \ @@ -642,7 +638,7 @@ class CodeGeneratorRISCV64 : public CodeGenerator { void GenerateMemoryBarrier(MemBarrierKind kind); - void MaybeIncrementHotness(HSuspendCheck* suspend_check, bool is_frame_entry); + void MaybeIncrementHotness(bool is_frame_entry); bool CanUseImplicitSuspendCheck() const; diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index ed40673ad1..71db5c99af 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -990,24 +990,16 @@ class MethodEntryExitHooksSlowPathX86 : public SlowPathCode { class CompileOptimizedSlowPathX86 : public SlowPathCode { public: - CompileOptimizedSlowPathX86(HSuspendCheck* suspend_check, uint32_t counter_address) - : SlowPathCode(suspend_check), + explicit CompileOptimizedSlowPathX86(uint32_t counter_address) + : SlowPathCode(/* instruction= */ nullptr), counter_address_(counter_address) {} void EmitNativeCode(CodeGenerator* codegen) override { CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen); __ Bind(GetEntryLabel()); __ movw(Address::Absolute(counter_address_), Immediate(ProfilingInfo::GetOptimizeThreshold())); - if (instruction_ != nullptr) { - // Only saves full width XMM for SIMD. - SaveLiveRegisters(codegen, instruction_->GetLocations()); - } x86_codegen->GenerateInvokeRuntime( GetThreadOffset<kX86PointerSize>(kQuickCompileOptimized).Int32Value()); - if (instruction_ != nullptr) { - // Only restores full width XMM for SIMD. - RestoreLiveRegisters(codegen, instruction_->GetLocations()); - } __ jmp(GetExitLabel()); } @@ -1334,7 +1326,7 @@ void InstructionCodeGeneratorX86::VisitMethodEntryHook(HMethodEntryHook* instruc GenerateMethodEntryExitHook(instruction); } -void CodeGeneratorX86::MaybeIncrementHotness(HSuspendCheck* suspend_check, bool is_frame_entry) { +void CodeGeneratorX86::MaybeIncrementHotness(bool is_frame_entry) { if (GetCompilerOptions().CountHotnessInCompiledCode()) { Register reg = EAX; if (is_frame_entry) { @@ -1357,15 +1349,12 @@ void CodeGeneratorX86::MaybeIncrementHotness(HSuspendCheck* suspend_check, bool } if (GetGraph()->IsCompilingBaseline() && !Runtime::Current()->IsAotCompiler()) { - // Note the slow path doesn't save SIMD registers, so if we were to - // call it on loop back edge, we would need to fix this. ProfilingInfo* info = GetGraph()->GetProfilingInfo(); DCHECK(info != nullptr); uint32_t address = reinterpret_cast32<uint32_t>(info) + ProfilingInfo::BaselineHotnessCountOffset().Int32Value(); DCHECK(!HasEmptyFrame()); - SlowPathCode* slow_path = - new (GetScopedAllocator()) CompileOptimizedSlowPathX86(suspend_check, address); + SlowPathCode* slow_path = new (GetScopedAllocator()) CompileOptimizedSlowPathX86(address); AddSlowPath(slow_path); // With multiple threads, this can overflow. This is OK, we will eventually get to see // it reaching 0. Also, at this point we have no register available to look @@ -1452,7 +1441,7 @@ void CodeGeneratorX86::GenerateFrameEntry() { } } - MaybeIncrementHotness(/* suspend_check= */ nullptr, /* is_frame_entry= */ true); + MaybeIncrementHotness(/* is_frame_entry= */ true); } void CodeGeneratorX86::GenerateFrameExit() { @@ -1903,7 +1892,7 @@ void InstructionCodeGeneratorX86::HandleGoto(HInstruction* got, HBasicBlock* suc HLoopInformation* info = block->GetLoopInformation(); if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) { - codegen_->MaybeIncrementHotness(info->GetSuspendCheck(), /* is_frame_entry= */ false); + codegen_->MaybeIncrementHotness(/* is_frame_entry= */ false); GenerateSuspendCheck(info->GetSuspendCheck(), successor); return; } @@ -2859,8 +2848,7 @@ void CodeGeneratorX86::MaybeGenerateInlineCacheCheck(HInstruction* instruction, if (ProfilingInfoBuilder::IsInlineCacheUseful(instruction->AsInvoke(), this)) { ProfilingInfo* info = GetGraph()->GetProfilingInfo(); DCHECK(info != nullptr); - InlineCache* cache = ProfilingInfoBuilder::GetInlineCache( - info, GetCompilerOptions(), instruction->AsInvoke()); + InlineCache* cache = ProfilingInfoBuilder::GetInlineCache(info, instruction->AsInvoke()); if (cache != nullptr) { uint32_t address = reinterpret_cast32<uint32_t>(cache); if (kIsDebugBuild) { diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h index f455812bc7..5b59bfc7e3 100644 --- a/compiler/optimizing/code_generator_x86.h +++ b/compiler/optimizing/code_generator_x86.h @@ -728,7 +728,7 @@ class CodeGeneratorX86 : public CodeGenerator { void GenerateExplicitNullCheck(HNullCheck* instruction) override; void MaybeGenerateInlineCacheCheck(HInstruction* instruction, Register klass); - void MaybeIncrementHotness(HSuspendCheck* suspend_check, bool is_frame_entry); + void MaybeIncrementHotness(bool is_frame_entry); // When we don't know the proper offset for the value, we use kPlaceholder32BitOffset. // The correct value will be inserted when processing Assembler fixups. diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 05b1de9f0a..9d010190f7 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -1043,8 +1043,8 @@ class MethodEntryExitHooksSlowPathX86_64 : public SlowPathCode { class CompileOptimizedSlowPathX86_64 : public SlowPathCode { public: - CompileOptimizedSlowPathX86_64(HSuspendCheck* suspend_check, uint64_t counter_address) - : SlowPathCode(suspend_check), + explicit CompileOptimizedSlowPathX86_64(uint64_t counter_address) + : SlowPathCode(/* instruction= */ nullptr), counter_address_(counter_address) {} void EmitNativeCode(CodeGenerator* codegen) override { @@ -1052,16 +1052,8 @@ class CompileOptimizedSlowPathX86_64 : public SlowPathCode { __ Bind(GetEntryLabel()); __ movq(CpuRegister(TMP), Immediate(counter_address_)); __ movw(Address(CpuRegister(TMP), 0), Immediate(ProfilingInfo::GetOptimizeThreshold())); - if (instruction_ != nullptr) { - // Only saves full width XMM for SIMD. - SaveLiveRegisters(codegen, instruction_->GetLocations()); - } x86_64_codegen->GenerateInvokeRuntime( GetThreadOffset<kX86_64PointerSize>(kQuickCompileOptimized).Int32Value()); - if (instruction_ != nullptr) { - // Only restores full width XMM for SIMD. - RestoreLiveRegisters(codegen, instruction_->GetLocations()); - } __ jmp(GetExitLabel()); } @@ -1771,7 +1763,7 @@ void InstructionCodeGeneratorX86_64::VisitMethodExitHook(HMethodExitHook* instru GenerateMethodEntryExitHook(instruction); } -void CodeGeneratorX86_64::MaybeIncrementHotness(HSuspendCheck* suspend_check, bool is_frame_entry) { +void CodeGeneratorX86_64::MaybeIncrementHotness(bool is_frame_entry) { if (GetCompilerOptions().CountHotnessInCompiledCode()) { NearLabel overflow; Register method = kMethodRegisterArgument; @@ -1794,8 +1786,7 @@ void CodeGeneratorX86_64::MaybeIncrementHotness(HSuspendCheck* suspend_check, bo CHECK(!HasEmptyFrame()); uint64_t address = reinterpret_cast64<uint64_t>(info) + ProfilingInfo::BaselineHotnessCountOffset().Int32Value(); - SlowPathCode* slow_path = - new (GetScopedAllocator()) CompileOptimizedSlowPathX86_64(suspend_check, address); + SlowPathCode* slow_path = new (GetScopedAllocator()) CompileOptimizedSlowPathX86_64(address); AddSlowPath(slow_path); // Note: if the address was in the 32bit range, we could use // Address::Absolute and avoid this movq. @@ -1900,7 +1891,7 @@ void CodeGeneratorX86_64::GenerateFrameEntry() { } } - MaybeIncrementHotness(/* suspend_check= */ nullptr, /* is_frame_entry= */ true); + MaybeIncrementHotness(/* is_frame_entry= */ true); } void CodeGeneratorX86_64::GenerateFrameExit() { @@ -2087,7 +2078,7 @@ void InstructionCodeGeneratorX86_64::HandleGoto(HInstruction* got, HBasicBlock* HLoopInformation* info = block->GetLoopInformation(); if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) { - codegen_->MaybeIncrementHotness(info->GetSuspendCheck(), /* is_frame_entry= */ false); + codegen_->MaybeIncrementHotness(/* is_frame_entry= */ false); GenerateSuspendCheck(info->GetSuspendCheck(), successor); return; } @@ -3150,8 +3141,7 @@ void CodeGeneratorX86_64::MaybeGenerateInlineCacheCheck(HInstruction* instructio if (ProfilingInfoBuilder::IsInlineCacheUseful(instruction->AsInvoke(), this)) { ProfilingInfo* info = GetGraph()->GetProfilingInfo(); DCHECK(info != nullptr); - InlineCache* cache = ProfilingInfoBuilder::GetInlineCache( - info, GetCompilerOptions(), instruction->AsInvoke()); + InlineCache* cache = ProfilingInfoBuilder::GetInlineCache(info, instruction->AsInvoke()); if (cache != nullptr) { uint64_t address = reinterpret_cast64<uint64_t>(cache); NearLabel done; diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h index 1698c2634a..e4d3eac6bc 100644 --- a/compiler/optimizing/code_generator_x86_64.h +++ b/compiler/optimizing/code_generator_x86_64.h @@ -695,7 +695,7 @@ class CodeGeneratorX86_64 : public CodeGenerator { void GenerateExplicitNullCheck(HNullCheck* instruction) override; void MaybeGenerateInlineCacheCheck(HInstruction* instruction, CpuRegister cls); - void MaybeIncrementHotness(HSuspendCheck* suspend_check, bool is_frame_entry); + void MaybeIncrementHotness(bool is_frame_entry); static void BlockNonVolatileXmmRegisters(LocationSummary* locations); diff --git a/compiler/optimizing/constant_folding.cc b/compiler/optimizing/constant_folding.cc index 66bbf548bb..64ef17898a 100644 --- a/compiler/optimizing/constant_folding.cc +++ b/compiler/optimizing/constant_folding.cc @@ -32,8 +32,8 @@ namespace art HIDDEN { // as constants. class HConstantFoldingVisitor final : public HGraphDelegateVisitor { public: - HConstantFoldingVisitor(HGraph* graph, OptimizingCompilerStats* stats, bool use_all_optimizations) - : HGraphDelegateVisitor(graph, stats), use_all_optimizations_(use_all_optimizations) {} + explicit HConstantFoldingVisitor(HGraph* graph, OptimizingCompilerStats* stats) + : HGraphDelegateVisitor(graph, stats) {} private: void VisitBasicBlock(HBasicBlock* block) override; @@ -66,9 +66,6 @@ class HConstantFoldingVisitor final : public HGraphDelegateVisitor { void FoldNumberOfLeadingZerosIntrinsic(HInvoke* invoke); void FoldNumberOfTrailingZerosIntrinsic(HInvoke* invoke); - // Use all optimizations without restrictions. - bool use_all_optimizations_; - DISALLOW_COPY_AND_ASSIGN(HConstantFoldingVisitor); }; @@ -109,7 +106,7 @@ class InstructionWithAbsorbingInputSimplifier : public HGraphVisitor { bool HConstantFolding::Run() { - HConstantFoldingVisitor visitor(graph_, stats_, use_all_optimizations_); + HConstantFoldingVisitor visitor(graph_, stats_); // Process basic blocks in reverse post-order in the dominator tree, // so that an instruction turned into a constant, used as input of // another instruction, may possibly be used to turn that second @@ -232,11 +229,6 @@ void HConstantFoldingVisitor::PropagateValue(HBasicBlock* starting_block, uses_before = variable->GetUses().SizeSlow(); } - if (variable->GetUses().HasExactlyOneElement()) { - // Nothing to do, since we only have the `if (variable)` use or the `condition` use. - return; - } - variable->ReplaceUsesDominatedBy( starting_block->GetFirstInstruction(), constant, /* strictly_dominated= */ false); @@ -249,12 +241,6 @@ void HConstantFoldingVisitor::PropagateValue(HBasicBlock* starting_block, } void HConstantFoldingVisitor::VisitIf(HIf* inst) { - // This optimization can take a lot of compile time since we have a lot of If instructions in - // graphs. - if (!use_all_optimizations_) { - return; - } - // Consistency check: the true and false successors do not dominate each other. DCHECK(!inst->IfTrueSuccessor()->Dominates(inst->IfFalseSuccessor()) && !inst->IfFalseSuccessor()->Dominates(inst->IfTrueSuccessor())); diff --git a/compiler/optimizing/constant_folding.h b/compiler/optimizing/constant_folding.h index 29648e907c..73ac3ceb81 100644 --- a/compiler/optimizing/constant_folding.h +++ b/compiler/optimizing/constant_folding.h @@ -43,18 +43,14 @@ class HConstantFolding : public HOptimization { public: HConstantFolding(HGraph* graph, OptimizingCompilerStats* stats = nullptr, - const char* name = kConstantFoldingPassName, - bool use_all_optimizations = false) - : HOptimization(graph, name, stats), use_all_optimizations_(use_all_optimizations) {} + const char* name = kConstantFoldingPassName) + : HOptimization(graph, name, stats) {} bool Run() override; static constexpr const char* kConstantFoldingPassName = "constant_folding"; private: - // Use all optimizations without restrictions. - bool use_all_optimizations_; - DISALLOW_COPY_AND_ASSIGN(HConstantFolding); }; diff --git a/compiler/optimizing/constant_folding_test.cc b/compiler/optimizing/constant_folding_test.cc index acdc8e6d3c..689d77111c 100644 --- a/compiler/optimizing/constant_folding_test.cc +++ b/compiler/optimizing/constant_folding_test.cc @@ -60,9 +60,7 @@ class ConstantFoldingTest : public CommonCompilerTest, public OptimizingUnitTest std::string actual_before = printer_before.str(); EXPECT_EQ(expected_before, actual_before); - HConstantFolding constant_folding( - graph_, /* stats= */ nullptr, "constant_folding", /* use_all_optimizations= */ true); - constant_folding.Run(); + HConstantFolding(graph_, /* stats= */ nullptr, "constant_folding").Run(); GraphChecker graph_checker_cf(graph_); graph_checker_cf.Run(); ASSERT_TRUE(graph_checker_cf.IsValid()); diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc index afbf941355..b7f7a0f550 100644 --- a/compiler/optimizing/graph_visualizer.cc +++ b/compiler/optimizing/graph_visualizer.cc @@ -867,8 +867,7 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { std::ostringstream oss; oss << pass_name_; if (!IsDebugDump()) { - oss << " (" << (GetGraph()->IsCompilingBaseline() ? "baseline " : "") - << (is_after_pass_ ? "after" : "before") + oss << " (" << (is_after_pass_ ? "after" : "before") << (graph_in_bad_state_ ? ", bad_state" : "") << ")"; } PrintProperty("name", oss.str().c_str()); diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index fcd899ed1c..e0bf028138 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -37,7 +37,6 @@ #include "mirror/object_array-alloc-inl.h" #include "mirror/object_array-inl.h" #include "nodes.h" -#include "profiling_info_builder.h" #include "reference_type_propagation.h" #include "register_allocator_linear_scan.h" #include "scoped_thread_state_change-inl.h" @@ -533,15 +532,6 @@ bool HInliner::TryInline(HInvoke* invoke_instruction) { return result; } - if (graph_->IsCompilingBaseline()) { - LOG_FAIL_NO_STAT() << "Call to " << invoke_instruction->GetMethodReference().PrettyMethod() - << " not inlined because we are compiling baseline and we could not" - << " statically resolve the target"; - // For baseline compilation, we will collect inline caches, so we should not - // try to inline using them. - return false; - } - DCHECK(!invoke_instruction->IsInvokeStaticOrDirect()); // No try catch inlining allowed here, or recursively. For try catch inlining we are banking on @@ -692,36 +682,17 @@ HInliner::InlineCacheType HInliner::GetInlineCacheJIT( ArtMethod* caller = graph_->GetArtMethod(); // Under JIT, we should always know the caller. DCHECK(caller != nullptr); - - InlineCache* cache = nullptr; - // Start with the outer graph profiling info. - ProfilingInfo* profiling_info = outermost_graph_->GetProfilingInfo(); - if (profiling_info != nullptr) { - if (depth_ == 0) { - cache = profiling_info->GetInlineCache(invoke_instruction->GetDexPc()); - } else { - uint32_t dex_pc = ProfilingInfoBuilder::EncodeInlinedDexPc( - this, codegen_->GetCompilerOptions(), invoke_instruction); - if (dex_pc != kNoDexPc) { - cache = profiling_info->GetInlineCache(dex_pc); - } - } - } - - if (cache == nullptr) { - // Check the current graph profiling info. - profiling_info = graph_->GetProfilingInfo(); - if (profiling_info == nullptr) { - return kInlineCacheNoData; - } - - cache = profiling_info->GetInlineCache(invoke_instruction->GetDexPc()); + ProfilingInfo* profiling_info = graph_->GetProfilingInfo(); + if (profiling_info == nullptr) { + return kInlineCacheNoData; } + InlineCache* cache = profiling_info->GetInlineCache(invoke_instruction->GetDexPc()); if (cache == nullptr) { - // Either we never hit this invoke and we never compiled the callee, - // or the method wasn't resolved when we performed baseline compilation. - // Bail for now. + // This shouldn't happen, but we don't guarantee that method resolution + // between baseline compilation and optimizing compilation is identical. Be robust, + // warn about it, and return that we don't have any inline cache data. + LOG(WARNING) << "No inline cache found for " << caller->PrettyMethod(); return kInlineCacheNoData; } Runtime::Current()->GetJit()->GetCodeCache()->CopyInlineCacheInto(*cache, classes); @@ -747,12 +718,6 @@ HInliner::InlineCacheType HInliner::GetInlineCacheAOT( const ProfileCompilationInfo::InlineCacheMap* inline_caches = hotness.GetInlineCacheMap(); DCHECK(inline_caches != nullptr); - - // Inlined inline caches are not supported in AOT, so we use the dex pc directly, and don't - // call `InlineCache::EncodeDexPc`. - // To support it, we would need to ensure `inline_max_code_units` remain the - // same between dex2oat and runtime, for example by adding it to the boot - // image oat header. const auto it = inline_caches->find(invoke_instruction->GetDexPc()); if (it == inline_caches->end()) { return kInlineCacheUninitialized; @@ -2112,20 +2077,6 @@ bool HInliner::CanInlineBody(const HGraph* callee_graph, << " could not be inlined because it needs a BSS check"; return false; } - - if (outermost_graph_->IsCompilingBaseline() && - (current->IsInvokeVirtual() || current->IsInvokeInterface()) && - ProfilingInfoBuilder::IsInlineCacheUseful(current->AsInvoke(), codegen_)) { - uint32_t maximum_inlining_depth_for_baseline = - InlineCache::MaxDexPcEncodingDepth( - outermost_graph_->GetArtMethod(), - codegen_->GetCompilerOptions().GetInlineMaxCodeUnits()); - if (depth_ + 1 > maximum_inlining_depth_for_baseline) { - LOG_FAIL_NO_STAT() << "Reached maximum depth for inlining in baseline compilation: " - << depth_ << " for " << callee_graph->GetArtMethod()->PrettyMethod(); - return false; - } - } } } @@ -2237,7 +2188,6 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, // The current invoke is not a try block. !invoke_instruction->GetBlock()->IsTryBlock(); RunOptimizations(callee_graph, - invoke_instruction->GetEnvironment(), code_item, dex_compilation_unit, try_catch_inlining_allowed_for_recursive_inline); @@ -2277,7 +2227,6 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, } void HInliner::RunOptimizations(HGraph* callee_graph, - HEnvironment* caller_environment, const dex::CodeItem* code_item, const DexCompilationUnit& dex_compilation_unit, bool try_catch_inlining_allowed_for_recursive_inline) { @@ -2326,7 +2275,6 @@ void HInliner::RunOptimizations(HGraph* callee_graph, total_number_of_dex_registers_ + accessor.RegistersSize(), total_number_of_instructions_ + number_of_instructions, this, - caller_environment, depth_ + 1, try_catch_inlining_allowed_for_recursive_inline); inliner.Run(); diff --git a/compiler/optimizing/inliner.h b/compiler/optimizing/inliner.h index 48600543c6..5e68dd866e 100644 --- a/compiler/optimizing/inliner.h +++ b/compiler/optimizing/inliner.h @@ -43,7 +43,6 @@ class HInliner : public HOptimization { size_t total_number_of_dex_registers, size_t total_number_of_instructions, HInliner* parent, - HEnvironment* caller_environment, size_t depth, bool try_catch_inlining_allowed, const char* name = kInlinerPassName) @@ -55,7 +54,6 @@ class HInliner : public HOptimization { total_number_of_dex_registers_(total_number_of_dex_registers), total_number_of_instructions_(total_number_of_instructions), parent_(parent), - caller_environment_(caller_environment), depth_(depth), inlining_budget_(0), try_catch_inlining_allowed_(try_catch_inlining_allowed), @@ -66,12 +64,6 @@ class HInliner : public HOptimization { static constexpr const char* kInlinerPassName = "inliner"; - const HInliner* GetParent() const { return parent_; } - const HEnvironment* GetCallerEnvironment() const { return caller_environment_; } - - const HGraph* GetOutermostGraph() const { return outermost_graph_; } - const HGraph* GetGraph() const { return graph_; } - private: enum InlineCacheType { kInlineCacheNoData = 0, @@ -117,7 +109,6 @@ class HInliner : public HOptimization { // Run simple optimizations on `callee_graph`. void RunOptimizations(HGraph* callee_graph, - HEnvironment* caller_environment, const dex::CodeItem* code_item, const DexCompilationUnit& dex_compilation_unit, bool try_catch_inlining_allowed_for_recursive_inline) @@ -330,10 +321,9 @@ class HInliner : public HOptimization { const size_t total_number_of_dex_registers_; size_t total_number_of_instructions_; - // The 'parent' inliner, that means the inlining optimization that requested + // The 'parent' inliner, that means the inlinigng optimization that requested // `graph_` to be inlined. const HInliner* const parent_; - const HEnvironment* const caller_environment_; const size_t depth_; // The budget left for inlining, in number of instructions. diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc index 3183dac348..27a41762e2 100644 --- a/compiler/optimizing/intrinsics_arm64.cc +++ b/compiler/optimizing/intrinsics_arm64.cc @@ -114,6 +114,7 @@ class ReadBarrierSystemArrayCopySlowPathARM64 : public SlowPathCodeARM64 { Register tmp_reg = WRegisterFrom(tmp_); __ Bind(GetEntryLabel()); + // The source range and destination pointer were initialized before entering the slow-path. vixl::aarch64::Label slow_copy_loop; __ Bind(&slow_copy_loop); __ Ldr(tmp_reg, MemOperand(src_curr_addr, element_size, PostIndex)); @@ -2731,14 +2732,12 @@ void IntrinsicCodeGeneratorARM64::VisitStringGetCharsNoCheck(HInvoke* invoke) { // so if we choose to jump to the slow path we will end up in the native implementation. static constexpr int32_t kSystemArrayCopyCharThreshold = 192; -static void SetSystemArrayCopyLocationRequires(LocationSummary* locations, - uint32_t at, - HInstruction* input) { +static Location LocationForSystemArrayCopyInput(HInstruction* input) { HIntConstant* const_input = input->AsIntConstantOrNull(); - if (const_input != nullptr && !vixl::aarch64::Assembler::IsImmAddSub(const_input->GetValue())) { - locations->SetInAt(at, Location::RequiresRegister()); + if (const_input != nullptr && vixl::aarch64::Assembler::IsImmAddSub(const_input->GetValue())) { + return Location::ConstantLocation(const_input); } else { - locations->SetInAt(at, Location::RegisterOrConstant(input)); + return Location::RequiresRegister(); } } @@ -2771,10 +2770,10 @@ void IntrinsicLocationsBuilderARM64::VisitSystemArrayCopyChar(HInvoke* invoke) { new (allocator) LocationSummary(invoke, LocationSummary::kCallOnSlowPath, kIntrinsified); // arraycopy(char[] src, int src_pos, char[] dst, int dst_pos, int length). locations->SetInAt(0, Location::RequiresRegister()); - SetSystemArrayCopyLocationRequires(locations, 1, invoke->InputAt(1)); + locations->SetInAt(1, LocationForSystemArrayCopyInput(invoke->InputAt(1))); locations->SetInAt(2, Location::RequiresRegister()); - SetSystemArrayCopyLocationRequires(locations, 3, invoke->InputAt(3)); - SetSystemArrayCopyLocationRequires(locations, 4, invoke->InputAt(4)); + locations->SetInAt(3, LocationForSystemArrayCopyInput(invoke->InputAt(3))); + locations->SetInAt(4, LocationForSystemArrayCopyInput(invoke->InputAt(4))); locations->AddTemp(Location::RequiresRegister()); locations->AddTemp(Location::RequiresRegister()); @@ -2782,92 +2781,97 @@ void IntrinsicLocationsBuilderARM64::VisitSystemArrayCopyChar(HInvoke* invoke) { } static void CheckSystemArrayCopyPosition(MacroAssembler* masm, - const Location& pos, - const Register& input, - const Location& length, + Register array, + Location pos, + Location length, SlowPathCodeARM64* slow_path, - const Register& temp, - bool length_is_input_length = false) { + Register temp, + bool length_is_array_length, + bool position_sign_checked) { const int32_t length_offset = mirror::Array::LengthOffset().Int32Value(); if (pos.IsConstant()) { int32_t pos_const = pos.GetConstant()->AsIntConstant()->GetValue(); if (pos_const == 0) { - if (!length_is_input_length) { - // Check that length(input) >= length. - __ Ldr(temp, MemOperand(input, length_offset)); + if (!length_is_array_length) { + // Check that length(array) >= length. + __ Ldr(temp, MemOperand(array, length_offset)); __ Cmp(temp, OperandFrom(length, DataType::Type::kInt32)); __ B(slow_path->GetEntryLabel(), lt); } } else { - // Check that length(input) >= pos. - __ Ldr(temp, MemOperand(input, length_offset)); - __ Subs(temp, temp, pos_const); - __ B(slow_path->GetEntryLabel(), lt); + // Calculate length(array) - pos. + // Both operands are known to be non-negative `int32_t`, so the difference cannot underflow + // as `int32_t`. If the result is negative, the B.LT below shall go to the slow path. + __ Ldr(temp, MemOperand(array, length_offset)); + __ Sub(temp, temp, pos_const); - // Check that (length(input) - pos) >= length. + // Check that (length(array) - pos) >= length. __ Cmp(temp, OperandFrom(length, DataType::Type::kInt32)); __ B(slow_path->GetEntryLabel(), lt); } - } else if (length_is_input_length) { + } else if (length_is_array_length) { // The only way the copy can succeed is if pos is zero. __ Cbnz(WRegisterFrom(pos), slow_path->GetEntryLabel()); } else { // Check that pos >= 0. Register pos_reg = WRegisterFrom(pos); - __ Tbnz(pos_reg, pos_reg.GetSizeInBits() - 1, slow_path->GetEntryLabel()); + if (!position_sign_checked) { + __ Tbnz(pos_reg, pos_reg.GetSizeInBits() - 1, slow_path->GetEntryLabel()); + } - // Check that pos <= length(input) && (length(input) - pos) >= length. - __ Ldr(temp, MemOperand(input, length_offset)); - __ Subs(temp, temp, pos_reg); - // Ccmp if length(input) >= pos, else definitely bail to slow path (N!=V == lt). - __ Ccmp(temp, OperandFrom(length, DataType::Type::kInt32), NFlag, ge); + // Calculate length(array) - pos. + // Both operands are known to be non-negative `int32_t`, so the difference cannot underflow + // as `int32_t`. If the result is negative, the B.LT below shall go to the slow path. + __ Ldr(temp, MemOperand(array, length_offset)); + __ Sub(temp, temp, pos_reg); + + // Check that (length(array) - pos) >= length. + __ Cmp(temp, OperandFrom(length, DataType::Type::kInt32)); __ B(slow_path->GetEntryLabel(), lt); } } +static void GenArrayAddress(MacroAssembler* masm, + Register dest, + Register base, + Location pos, + DataType::Type type, + int32_t data_offset) { + if (pos.IsConstant()) { + int32_t constant = pos.GetConstant()->AsIntConstant()->GetValue(); + __ Add(dest, base, DataType::Size(type) * constant + data_offset); + } else { + if (data_offset != 0) { + __ Add(dest, base, data_offset); + base = dest; + } + __ Add(dest, base, Operand(XRegisterFrom(pos), LSL, DataType::SizeShift(type))); + } +} + // Compute base source address, base destination address, and end // source address for System.arraycopy* intrinsics in `src_base`, // `dst_base` and `src_end` respectively. static void GenSystemArrayCopyAddresses(MacroAssembler* masm, DataType::Type type, - const Register& src, - const Location& src_pos, - const Register& dst, - const Location& dst_pos, - const Location& copy_length, - const Register& src_base, - const Register& dst_base, - const Register& src_end) { + Register src, + Location src_pos, + Register dst, + Location dst_pos, + Location copy_length, + Register src_base, + Register dst_base, + Register src_end) { // This routine is used by the SystemArrayCopy and the SystemArrayCopyChar intrinsics. DCHECK(type == DataType::Type::kReference || type == DataType::Type::kUint16) << "Unexpected element type: " << type; const int32_t element_size = DataType::Size(type); - const int32_t element_size_shift = DataType::SizeShift(type); const uint32_t data_offset = mirror::Array::DataOffset(element_size).Uint32Value(); - if (src_pos.IsConstant()) { - int32_t constant = src_pos.GetConstant()->AsIntConstant()->GetValue(); - __ Add(src_base, src, element_size * constant + data_offset); - } else { - __ Add(src_base, src, data_offset); - __ Add(src_base, src_base, Operand(XRegisterFrom(src_pos), LSL, element_size_shift)); - } - - if (dst_pos.IsConstant()) { - int32_t constant = dst_pos.GetConstant()->AsIntConstant()->GetValue(); - __ Add(dst_base, dst, element_size * constant + data_offset); - } else { - __ Add(dst_base, dst, data_offset); - __ Add(dst_base, dst_base, Operand(XRegisterFrom(dst_pos), LSL, element_size_shift)); - } - + GenArrayAddress(masm, src_base, src, src_pos, type, data_offset); + GenArrayAddress(masm, dst_base, dst, dst_pos, type, data_offset); if (src_end.IsValid()) { - if (copy_length.IsConstant()) { - int32_t constant = copy_length.GetConstant()->AsIntConstant()->GetValue(); - __ Add(src_end, src_base, element_size * constant); - } else { - __ Add(src_end, src_base, Operand(XRegisterFrom(copy_length), LSL, element_size_shift)); - } + GenArrayAddress(masm, src_end, src_base, copy_length, type, /*data_offset=*/ 0); } } @@ -2913,20 +2917,22 @@ void IntrinsicCodeGeneratorARM64::VisitSystemArrayCopyChar(HInvoke* invoke) { Register src_stop_addr = WRegisterFrom(locations->GetTemp(2)); CheckSystemArrayCopyPosition(masm, - src_pos, src, + src_pos, length, slow_path, src_curr_addr, - false); + /*length_is_array_length=*/ false, + /*position_sign_checked=*/ false); CheckSystemArrayCopyPosition(masm, - dst_pos, dst, + dst_pos, length, slow_path, src_curr_addr, - false); + /*length_is_array_length=*/ false, + /*position_sign_checked=*/ false); src_curr_addr = src_curr_addr.X(); dst_curr_addr = dst_curr_addr.X(); @@ -3043,9 +3049,6 @@ void IntrinsicCodeGeneratorARM64::VisitSystemArrayCopyChar(HInvoke* invoke) { // We can choose to use the native implementation there for longer copy lengths. static constexpr int32_t kSystemArrayCopyThreshold = 128; -// CodeGenerator::CreateSystemArrayCopyLocationSummary use three temporary registers. -// We want to use two temporary registers in order to reduce the register pressure in arm64. -// So we don't use the CodeGenerator::CreateSystemArrayCopyLocationSummary. void IntrinsicLocationsBuilderARM64::VisitSystemArrayCopy(HInvoke* invoke) { // The only read barrier implementation supporting the // SystemArrayCopy intrinsic is the Baker-style read barriers. @@ -3053,67 +3056,27 @@ void IntrinsicLocationsBuilderARM64::VisitSystemArrayCopy(HInvoke* invoke) { return; } - // Check to see if we have known failures that will cause us to have to bail out - // to the runtime, and just generate the runtime call directly. - HIntConstant* src_pos = invoke->InputAt(1)->AsIntConstantOrNull(); - HIntConstant* dest_pos = invoke->InputAt(3)->AsIntConstantOrNull(); - - // The positions must be non-negative. - if ((src_pos != nullptr && src_pos->GetValue() < 0) || - (dest_pos != nullptr && dest_pos->GetValue() < 0)) { - // We will have to fail anyways. - return; - } - - // The length must be >= 0. - HIntConstant* length = invoke->InputAt(4)->AsIntConstantOrNull(); - if (length != nullptr) { - int32_t len = length->GetValue(); - if (len < 0 || len >= kSystemArrayCopyThreshold) { - // Just call as normal. - return; - } - } - - SystemArrayCopyOptimizations optimizations(invoke); - - if (optimizations.GetDestinationIsSource()) { - if (src_pos != nullptr && dest_pos != nullptr && src_pos->GetValue() < dest_pos->GetValue()) { - // We only support backward copying if source and destination are the same. - return; + constexpr size_t kInitialNumTemps = 2u; // We need at least two temps. + LocationSummary* locations = CodeGenerator::CreateSystemArrayCopyLocationSummary( + invoke, kSystemArrayCopyThreshold, kInitialNumTemps); + if (locations != nullptr) { + locations->SetInAt(1, LocationForSystemArrayCopyInput(invoke->InputAt(1))); + locations->SetInAt(3, LocationForSystemArrayCopyInput(invoke->InputAt(3))); + locations->SetInAt(4, LocationForSystemArrayCopyInput(invoke->InputAt(4))); + if (codegen_->EmitBakerReadBarrier()) { + // Temporary register IP0, obtained from the VIXL scratch register + // pool, cannot be used in ReadBarrierSystemArrayCopySlowPathARM64 + // (because that register is clobbered by ReadBarrierMarkRegX + // entry points). It cannot be used in calls to + // CodeGeneratorARM64::GenerateFieldLoadWithBakerReadBarrier + // either. For these reasons, get a third extra temporary register + // from the register allocator. + locations->AddTemp(Location::RequiresRegister()); + } else { + // Cases other than Baker read barriers: the third temporary will + // be acquired from the VIXL scratch register pool. } } - - if (optimizations.GetDestinationIsPrimitiveArray() || optimizations.GetSourceIsPrimitiveArray()) { - // We currently don't intrinsify primitive copying. - return; - } - - ArenaAllocator* allocator = invoke->GetBlock()->GetGraph()->GetAllocator(); - LocationSummary* locations = - new (allocator) LocationSummary(invoke, LocationSummary::kCallOnSlowPath, kIntrinsified); - // arraycopy(Object src, int src_pos, Object dest, int dest_pos, int length). - locations->SetInAt(0, Location::RequiresRegister()); - SetSystemArrayCopyLocationRequires(locations, 1, invoke->InputAt(1)); - locations->SetInAt(2, Location::RequiresRegister()); - SetSystemArrayCopyLocationRequires(locations, 3, invoke->InputAt(3)); - SetSystemArrayCopyLocationRequires(locations, 4, invoke->InputAt(4)); - - locations->AddTemp(Location::RequiresRegister()); - locations->AddTemp(Location::RequiresRegister()); - if (codegen_->EmitBakerReadBarrier()) { - // Temporary register IP0, obtained from the VIXL scratch register - // pool, cannot be used in ReadBarrierSystemArrayCopySlowPathARM64 - // (because that register is clobbered by ReadBarrierMarkRegX - // entry points). It cannot be used in calls to - // CodeGeneratorARM64::GenerateFieldLoadWithBakerReadBarrier - // either. For these reasons, get a third extra temporary register - // from the register allocator. - locations->AddTemp(Location::RequiresRegister()); - } else { - // Cases other than Baker read barriers: the third temporary will - // be acquired from the VIXL scratch register pool. - } } void IntrinsicCodeGeneratorARM64::VisitSystemArrayCopy(HInvoke* invoke) { @@ -3147,38 +3110,37 @@ void IntrinsicCodeGeneratorARM64::VisitSystemArrayCopy(HInvoke* invoke) { vixl::aarch64::Label conditions_on_positions_validated; SystemArrayCopyOptimizations optimizations(invoke); - // If source and destination are the same, we go to slow path if we need to do - // forward copying. - if (src_pos.IsConstant()) { - int32_t src_pos_constant = src_pos.GetConstant()->AsIntConstant()->GetValue(); - if (dest_pos.IsConstant()) { - int32_t dest_pos_constant = dest_pos.GetConstant()->AsIntConstant()->GetValue(); - if (optimizations.GetDestinationIsSource()) { - // Checked when building locations. - DCHECK_GE(src_pos_constant, dest_pos_constant); - } else if (src_pos_constant < dest_pos_constant) { - __ Cmp(src, dest); - __ B(intrinsic_slow_path->GetEntryLabel(), eq); + // If source and destination are the same, we go to slow path if we need to do forward copying. + // We do not need to do this check if the source and destination positions are the same. + if (!optimizations.GetSourcePositionIsDestinationPosition()) { + if (src_pos.IsConstant()) { + int32_t src_pos_constant = src_pos.GetConstant()->AsIntConstant()->GetValue(); + if (dest_pos.IsConstant()) { + int32_t dest_pos_constant = dest_pos.GetConstant()->AsIntConstant()->GetValue(); + if (optimizations.GetDestinationIsSource()) { + // Checked when building locations. + DCHECK_GE(src_pos_constant, dest_pos_constant); + } else if (src_pos_constant < dest_pos_constant) { + __ Cmp(src, dest); + __ B(intrinsic_slow_path->GetEntryLabel(), eq); + } + } else { + if (!optimizations.GetDestinationIsSource()) { + __ Cmp(src, dest); + __ B(&conditions_on_positions_validated, ne); + } + __ Cmp(WRegisterFrom(dest_pos), src_pos_constant); + __ B(intrinsic_slow_path->GetEntryLabel(), gt); } - // Checked when building locations. - DCHECK(!optimizations.GetDestinationIsSource() || - (src_pos_constant >= dest_pos.GetConstant()->AsIntConstant()->GetValue())); } else { if (!optimizations.GetDestinationIsSource()) { __ Cmp(src, dest); __ B(&conditions_on_positions_validated, ne); } - __ Cmp(WRegisterFrom(dest_pos), src_pos_constant); - __ B(intrinsic_slow_path->GetEntryLabel(), gt); + __ Cmp(RegisterFrom(src_pos, invoke->InputAt(1)->GetType()), + OperandFrom(dest_pos, invoke->InputAt(3)->GetType())); + __ B(intrinsic_slow_path->GetEntryLabel(), lt); } - } else { - if (!optimizations.GetDestinationIsSource()) { - __ Cmp(src, dest); - __ B(&conditions_on_positions_validated, ne); - } - __ Cmp(RegisterFrom(src_pos, invoke->InputAt(1)->GetType()), - OperandFrom(dest_pos, invoke->InputAt(3)->GetType())); - __ B(intrinsic_slow_path->GetEntryLabel(), lt); } __ Bind(&conditions_on_positions_validated); @@ -3194,9 +3156,7 @@ void IntrinsicCodeGeneratorARM64::VisitSystemArrayCopy(HInvoke* invoke) { } // We have already checked in the LocationsBuilder for the constant case. - if (!length.IsConstant() && - !optimizations.GetCountIsSourceLength() && - !optimizations.GetCountIsDestinationLength()) { + if (!length.IsConstant()) { // Merge the following two comparisons into one: // If the length is negative, bail out (delegate to libcore's native implementation). // If the length >= 128 then (currently) prefer native implementation. @@ -3205,252 +3165,155 @@ void IntrinsicCodeGeneratorARM64::VisitSystemArrayCopy(HInvoke* invoke) { } // Validity checks: source. CheckSystemArrayCopyPosition(masm, - src_pos, src, + src_pos, length, intrinsic_slow_path, temp1, - optimizations.GetCountIsSourceLength()); + optimizations.GetCountIsSourceLength(), + /*position_sign_checked=*/ false); // Validity checks: dest. + bool dest_position_sign_checked = optimizations.GetSourcePositionIsDestinationPosition(); CheckSystemArrayCopyPosition(masm, - dest_pos, dest, + dest_pos, length, intrinsic_slow_path, temp1, - optimizations.GetCountIsDestinationLength()); - { - // We use a block to end the scratch scope before the write barrier, thus - // freeing the temporary registers so they can be used in `MarkGCCard`. - UseScratchRegisterScope temps(masm); - Location temp3_loc; // Used only for Baker read barrier. - Register temp3; + optimizations.GetCountIsDestinationLength(), + dest_position_sign_checked); + + auto check_non_primitive_array_class = [&](Register klass, Register temp) { + // No read barrier is needed for reading a chain of constant references for comparing + // with null, or for reading a constant primitive value, see `ReadBarrierOption`. + // /* HeapReference<Class> */ temp = klass->component_type_ + __ Ldr(temp, HeapOperand(klass, component_offset)); + codegen_->GetAssembler()->MaybeUnpoisonHeapReference(temp); + // Check that the component type is not null. + __ Cbz(temp, intrinsic_slow_path->GetEntryLabel()); + // Check that the component type is not a primitive. + // /* uint16_t */ temp = static_cast<uint16>(klass->primitive_type_); + __ Ldr(temp, HeapOperand(temp, primitive_offset)); + static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot"); + __ Cbnz(temp, intrinsic_slow_path->GetEntryLabel()); + }; + + if (!optimizations.GetDoesNotNeedTypeCheck()) { + // Check whether all elements of the source array are assignable to the component + // type of the destination array. We do two checks: the classes are the same, + // or the destination is Object[]. If none of these checks succeed, we go to the + // slow path. + if (codegen_->EmitBakerReadBarrier()) { - temp3_loc = locations->GetTemp(2); - temp3 = WRegisterFrom(temp3_loc); + Location temp3_loc = locations->GetTemp(2); + // /* HeapReference<Class> */ temp1 = dest->klass_ + codegen_->GenerateFieldLoadWithBakerReadBarrier(invoke, + temp1_loc, + dest.W(), + class_offset, + temp3_loc, + /* needs_null_check= */ false, + /* use_load_acquire= */ false); + // Register `temp1` is not trashed by the read barrier emitted + // by GenerateFieldLoadWithBakerReadBarrier below, as that + // method produces a call to a ReadBarrierMarkRegX entry point, + // which saves all potentially live registers, including + // temporaries such a `temp1`. + // /* HeapReference<Class> */ temp2 = src->klass_ + codegen_->GenerateFieldLoadWithBakerReadBarrier(invoke, + temp2_loc, + src.W(), + class_offset, + temp3_loc, + /* needs_null_check= */ false, + /* use_load_acquire= */ false); } else { - temp3 = temps.AcquireW(); + // /* HeapReference<Class> */ temp1 = dest->klass_ + __ Ldr(temp1, MemOperand(dest, class_offset)); + codegen_->GetAssembler()->MaybeUnpoisonHeapReference(temp1); + // /* HeapReference<Class> */ temp2 = src->klass_ + __ Ldr(temp2, MemOperand(src, class_offset)); + codegen_->GetAssembler()->MaybeUnpoisonHeapReference(temp2); } - if (!optimizations.GetDoesNotNeedTypeCheck()) { - // Check whether all elements of the source array are assignable to the component - // type of the destination array. We do two checks: the classes are the same, - // or the destination is Object[]. If none of these checks succeed, we go to the - // slow path. - - if (codegen_->EmitBakerReadBarrier()) { - if (!optimizations.GetSourceIsNonPrimitiveArray()) { - // /* HeapReference<Class> */ temp1 = src->klass_ - codegen_->GenerateFieldLoadWithBakerReadBarrier(invoke, - temp1_loc, - src.W(), - class_offset, - temp3_loc, - /* needs_null_check= */ false, - /* use_load_acquire= */ false); - // Bail out if the source is not a non primitive array. - // /* HeapReference<Class> */ temp1 = temp1->component_type_ - codegen_->GenerateFieldLoadWithBakerReadBarrier(invoke, - temp1_loc, - temp1, - component_offset, - temp3_loc, - /* needs_null_check= */ false, - /* use_load_acquire= */ false); - __ Cbz(temp1, intrinsic_slow_path->GetEntryLabel()); - // If heap poisoning is enabled, `temp1` has been unpoisoned - // by the previous call to GenerateFieldLoadWithBakerReadBarrier. - // /* uint16_t */ temp1 = static_cast<uint16>(temp1->primitive_type_); - __ Ldrh(temp1, HeapOperand(temp1, primitive_offset)); - static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot"); - __ Cbnz(temp1, intrinsic_slow_path->GetEntryLabel()); - } - - // /* HeapReference<Class> */ temp1 = dest->klass_ - codegen_->GenerateFieldLoadWithBakerReadBarrier(invoke, - temp1_loc, - dest.W(), - class_offset, - temp3_loc, - /* needs_null_check= */ false, - /* use_load_acquire= */ false); - - if (!optimizations.GetDestinationIsNonPrimitiveArray()) { - // Bail out if the destination is not a non primitive array. - // - // Register `temp1` is not trashed by the read barrier emitted - // by GenerateFieldLoadWithBakerReadBarrier below, as that - // method produces a call to a ReadBarrierMarkRegX entry point, - // which saves all potentially live registers, including - // temporaries such a `temp1`. - // /* HeapReference<Class> */ temp2 = temp1->component_type_ - codegen_->GenerateFieldLoadWithBakerReadBarrier(invoke, - temp2_loc, - temp1, - component_offset, - temp3_loc, - /* needs_null_check= */ false, - /* use_load_acquire= */ false); - __ Cbz(temp2, intrinsic_slow_path->GetEntryLabel()); - // If heap poisoning is enabled, `temp2` has been unpoisoned - // by the previous call to GenerateFieldLoadWithBakerReadBarrier. - // /* uint16_t */ temp2 = static_cast<uint16>(temp2->primitive_type_); - __ Ldrh(temp2, HeapOperand(temp2, primitive_offset)); - static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot"); - __ Cbnz(temp2, intrinsic_slow_path->GetEntryLabel()); - } - - // For the same reason given earlier, `temp1` is not trashed by the - // read barrier emitted by GenerateFieldLoadWithBakerReadBarrier below. - // /* HeapReference<Class> */ temp2 = src->klass_ - codegen_->GenerateFieldLoadWithBakerReadBarrier(invoke, - temp2_loc, - src.W(), - class_offset, - temp3_loc, - /* needs_null_check= */ false, - /* use_load_acquire= */ false); - // Note: if heap poisoning is on, we are comparing two unpoisoned references here. - __ Cmp(temp1, temp2); - - if (optimizations.GetDestinationIsTypedObjectArray()) { - vixl::aarch64::Label do_copy; - __ B(&do_copy, eq); - // /* HeapReference<Class> */ temp1 = temp1->component_type_ - codegen_->GenerateFieldLoadWithBakerReadBarrier(invoke, - temp1_loc, - temp1, - component_offset, - temp3_loc, - /* needs_null_check= */ false, - /* use_load_acquire= */ false); - // /* HeapReference<Class> */ temp1 = temp1->super_class_ - // We do not need to emit a read barrier for the following - // heap reference load, as `temp1` is only used in a - // comparison with null below, and this reference is not - // kept afterwards. - __ Ldr(temp1, HeapOperand(temp1, super_offset)); - __ Cbnz(temp1, intrinsic_slow_path->GetEntryLabel()); - __ Bind(&do_copy); - } else { - __ B(intrinsic_slow_path->GetEntryLabel(), ne); - } - } else { - // Non read barrier code. - - // /* HeapReference<Class> */ temp1 = dest->klass_ - __ Ldr(temp1, MemOperand(dest, class_offset)); - // /* HeapReference<Class> */ temp2 = src->klass_ - __ Ldr(temp2, MemOperand(src, class_offset)); - bool did_unpoison = false; - if (!optimizations.GetDestinationIsNonPrimitiveArray() || - !optimizations.GetSourceIsNonPrimitiveArray()) { - // One or two of the references need to be unpoisoned. Unpoison them - // both to make the identity check valid. - codegen_->GetAssembler()->MaybeUnpoisonHeapReference(temp1); - codegen_->GetAssembler()->MaybeUnpoisonHeapReference(temp2); - did_unpoison = true; - } - - if (!optimizations.GetDestinationIsNonPrimitiveArray()) { - // Bail out if the destination is not a non primitive array. - // /* HeapReference<Class> */ temp3 = temp1->component_type_ - __ Ldr(temp3, HeapOperand(temp1, component_offset)); - __ Cbz(temp3, intrinsic_slow_path->GetEntryLabel()); - codegen_->GetAssembler()->MaybeUnpoisonHeapReference(temp3); - // /* uint16_t */ temp3 = static_cast<uint16>(temp3->primitive_type_); - __ Ldrh(temp3, HeapOperand(temp3, primitive_offset)); - static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot"); - __ Cbnz(temp3, intrinsic_slow_path->GetEntryLabel()); - } - - if (!optimizations.GetSourceIsNonPrimitiveArray()) { - // Bail out if the source is not a non primitive array. - // /* HeapReference<Class> */ temp3 = temp2->component_type_ - __ Ldr(temp3, HeapOperand(temp2, component_offset)); - __ Cbz(temp3, intrinsic_slow_path->GetEntryLabel()); - codegen_->GetAssembler()->MaybeUnpoisonHeapReference(temp3); - // /* uint16_t */ temp3 = static_cast<uint16>(temp3->primitive_type_); - __ Ldrh(temp3, HeapOperand(temp3, primitive_offset)); - static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot"); - __ Cbnz(temp3, intrinsic_slow_path->GetEntryLabel()); - } - - __ Cmp(temp1, temp2); - - if (optimizations.GetDestinationIsTypedObjectArray()) { - vixl::aarch64::Label do_copy; - __ B(&do_copy, eq); - if (!did_unpoison) { - codegen_->GetAssembler()->MaybeUnpoisonHeapReference(temp1); - } - // /* HeapReference<Class> */ temp1 = temp1->component_type_ - __ Ldr(temp1, HeapOperand(temp1, component_offset)); - codegen_->GetAssembler()->MaybeUnpoisonHeapReference(temp1); - // /* HeapReference<Class> */ temp1 = temp1->super_class_ - __ Ldr(temp1, HeapOperand(temp1, super_offset)); - // No need to unpoison the result, we're comparing against null. - __ Cbnz(temp1, intrinsic_slow_path->GetEntryLabel()); - __ Bind(&do_copy); - } else { - __ B(intrinsic_slow_path->GetEntryLabel(), ne); - } - } - } else if (!optimizations.GetSourceIsNonPrimitiveArray()) { + __ Cmp(temp1, temp2); + if (optimizations.GetDestinationIsTypedObjectArray()) { DCHECK(optimizations.GetDestinationIsNonPrimitiveArray()); + vixl::aarch64::Label do_copy; + // For class match, we can skip the source type check regardless of the optimization flag. + __ B(&do_copy, eq); + // No read barrier is needed for reading a chain of constant references + // for comparing with null, see `ReadBarrierOption`. + // /* HeapReference<Class> */ temp1 = temp1->component_type_ + __ Ldr(temp1, HeapOperand(temp1, component_offset)); + codegen_->GetAssembler()->MaybeUnpoisonHeapReference(temp1); + // /* HeapReference<Class> */ temp1 = temp1->super_class_ + __ Ldr(temp1, HeapOperand(temp1, super_offset)); + // No need to unpoison the result, we're comparing against null. + __ Cbnz(temp1, intrinsic_slow_path->GetEntryLabel()); // Bail out if the source is not a non primitive array. - if (codegen_->EmitBakerReadBarrier()) { - // /* HeapReference<Class> */ temp1 = src->klass_ - codegen_->GenerateFieldLoadWithBakerReadBarrier(invoke, - temp1_loc, - src.W(), - class_offset, - temp3_loc, - /* needs_null_check= */ false, - /* use_load_acquire= */ false); - // /* HeapReference<Class> */ temp2 = temp1->component_type_ - codegen_->GenerateFieldLoadWithBakerReadBarrier(invoke, - temp2_loc, - temp1, - component_offset, - temp3_loc, - /* needs_null_check= */ false, - /* use_load_acquire= */ false); - __ Cbz(temp2, intrinsic_slow_path->GetEntryLabel()); - // If heap poisoning is enabled, `temp2` has been unpoisoned - // by the previous call to GenerateFieldLoadWithBakerReadBarrier. - } else { - // /* HeapReference<Class> */ temp1 = src->klass_ - __ Ldr(temp1, HeapOperand(src.W(), class_offset)); - codegen_->GetAssembler()->MaybeUnpoisonHeapReference(temp1); - // /* HeapReference<Class> */ temp2 = temp1->component_type_ - __ Ldr(temp2, HeapOperand(temp1, component_offset)); - __ Cbz(temp2, intrinsic_slow_path->GetEntryLabel()); - codegen_->GetAssembler()->MaybeUnpoisonHeapReference(temp2); + if (!optimizations.GetSourceIsNonPrimitiveArray()) { + check_non_primitive_array_class(temp2, temp2); + } + __ Bind(&do_copy); + } else { + DCHECK(!optimizations.GetDestinationIsTypedObjectArray()); + // For class match, we can skip the array type check completely if at least one of source + // and destination is known to be a non primitive array, otherwise one check is enough. + __ B(intrinsic_slow_path->GetEntryLabel(), ne); + if (!optimizations.GetDestinationIsNonPrimitiveArray() && + !optimizations.GetSourceIsNonPrimitiveArray()) { + check_non_primitive_array_class(temp2, temp2); } - // /* uint16_t */ temp2 = static_cast<uint16>(temp2->primitive_type_); - __ Ldrh(temp2, HeapOperand(temp2, primitive_offset)); - static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot"); - __ Cbnz(temp2, intrinsic_slow_path->GetEntryLabel()); + } + } else if (!optimizations.GetSourceIsNonPrimitiveArray()) { + DCHECK(optimizations.GetDestinationIsNonPrimitiveArray()); + // Bail out if the source is not a non primitive array. + // No read barrier is needed for reading a chain of constant references for comparing + // with null, or for reading a constant primitive value, see `ReadBarrierOption`. + // /* HeapReference<Class> */ temp2 = src->klass_ + __ Ldr(temp2, MemOperand(src, class_offset)); + codegen_->GetAssembler()->MaybeUnpoisonHeapReference(temp2); + check_non_primitive_array_class(temp2, temp2); + } + + if (length.IsConstant() && length.GetConstant()->AsIntConstant()->GetValue() == 0) { + // Null constant length: not need to emit the loop code at all. + } else { + vixl::aarch64::Label skip_copy_and_write_barrier; + if (length.IsRegister()) { + // Don't enter the copy loop if the length is null. + __ Cbz(WRegisterFrom(length), &skip_copy_and_write_barrier); } - if (length.IsConstant() && length.GetConstant()->AsIntConstant()->GetValue() == 0) { - // Null constant length: not need to emit the loop code at all. - } else { + { + // We use a block to end the scratch scope before the write barrier, thus + // freeing the temporary registers so they can be used in `MarkGCCard`. + UseScratchRegisterScope temps(masm); + bool emit_rb = codegen_->EmitBakerReadBarrier(); + Register temp3; + Register tmp; + if (emit_rb) { + temp3 = WRegisterFrom(locations->GetTemp(2)); + // Make sure `tmp` is not IP0, as it is clobbered by ReadBarrierMarkRegX entry points + // in ReadBarrierSystemArrayCopySlowPathARM64. Explicitly allocate the register IP1. + DCHECK(temps.IsAvailable(ip1)); + temps.Exclude(ip1); + tmp = ip1.W(); + } else { + temp3 = temps.AcquireW(); + tmp = temps.AcquireW(); + } + Register src_curr_addr = temp1.X(); Register dst_curr_addr = temp2.X(); Register src_stop_addr = temp3.X(); - vixl::aarch64::Label done; const DataType::Type type = DataType::Type::kReference; const int32_t element_size = DataType::Size(type); - if (length.IsRegister()) { - // Don't enter the copy loop if the length is null. - __ Cbz(WRegisterFrom(length), &done); - } - - if (codegen_->EmitBakerReadBarrier()) { + SlowPathCodeARM64* read_barrier_slow_path = nullptr; + if (emit_rb) { // TODO: Also convert this intrinsic to the IsGcMarking strategy? // SystemArrayCopy implementation for Baker read barriers (see @@ -3471,21 +3334,6 @@ void IntrinsicCodeGeneratorARM64::VisitSystemArrayCopy(HInvoke* invoke) { // } while (src_ptr != end_ptr) // } - // Make sure `tmp` is not IP0, as it is clobbered by - // ReadBarrierMarkRegX entry points in - // ReadBarrierSystemArrayCopySlowPathARM64. - DCHECK(temps.IsAvailable(ip0)); - temps.Exclude(ip0); - Register tmp = temps.AcquireW(); - DCHECK_NE(LocationFrom(tmp).reg(), IP0); - // Put IP0 back in the pool so that VIXL has at least one - // scratch register available to emit macro-instructions (note - // that IP1 is already used for `tmp`). Indeed some - // macro-instructions used in GenSystemArrayCopyAddresses - // (invoked hereunder) may require a scratch register (for - // instance to emit a load with a large constant offset). - temps.Include(ip0); - // /* int32_t */ monitor = src->monitor_ __ Ldr(tmp, HeapOperand(src.W(), monitor_offset)); // /* LockWord */ lock_word = LockWord(monitor) @@ -3499,78 +3347,57 @@ void IntrinsicCodeGeneratorARM64::VisitSystemArrayCopy(HInvoke* invoke) { // on `tmp`. __ Add(src.X(), src.X(), Operand(tmp.X(), LSR, 32)); - // Compute base source address, base destination address, and end - // source address for System.arraycopy* intrinsics in `src_base`, - // `dst_base` and `src_end` respectively. - // Note that `src_curr_addr` is computed from from `src` (and - // `src_pos`) here, and thus honors the artificial dependency - // of `src` on `tmp`. - GenSystemArrayCopyAddresses(masm, - type, - src, - src_pos, - dest, - dest_pos, - length, - src_curr_addr, - dst_curr_addr, - src_stop_addr); - // Slow path used to copy array when `src` is gray. - SlowPathCodeARM64* read_barrier_slow_path = + read_barrier_slow_path = new (codegen_->GetScopedAllocator()) ReadBarrierSystemArrayCopySlowPathARM64( invoke, LocationFrom(tmp)); codegen_->AddSlowPath(read_barrier_slow_path); + } + // Compute base source address, base destination address, and end + // source address for System.arraycopy* intrinsics in `src_base`, + // `dst_base` and `src_end` respectively. + // Note that `src_curr_addr` is computed from from `src` (and + // `src_pos`) here, and thus honors the artificial dependency + // of `src` on `tmp`. + GenSystemArrayCopyAddresses(masm, + type, + src, + src_pos, + dest, + dest_pos, + length, + src_curr_addr, + dst_curr_addr, + src_stop_addr); + + if (emit_rb) { // Given the numeric representation, it's enough to check the low bit of the rb_state. static_assert(ReadBarrier::NonGrayState() == 0, "Expecting non-gray to have value 0"); static_assert(ReadBarrier::GrayState() == 1, "Expecting gray to have value 1"); __ Tbnz(tmp, LockWord::kReadBarrierStateShift, read_barrier_slow_path->GetEntryLabel()); + } - // Fast-path copy. - // Iterate over the arrays and do a raw copy of the objects. We don't need to - // poison/unpoison. - vixl::aarch64::Label loop; - __ Bind(&loop); - __ Ldr(tmp, MemOperand(src_curr_addr, element_size, PostIndex)); - __ Str(tmp, MemOperand(dst_curr_addr, element_size, PostIndex)); - __ Cmp(src_curr_addr, src_stop_addr); - __ B(&loop, ne); - + // Iterate over the arrays and do a raw copy of the objects. We don't need to + // poison/unpoison. + vixl::aarch64::Label loop; + __ Bind(&loop); + __ Ldr(tmp, MemOperand(src_curr_addr, element_size, PostIndex)); + __ Str(tmp, MemOperand(dst_curr_addr, element_size, PostIndex)); + __ Cmp(src_curr_addr, src_stop_addr); + __ B(&loop, ne); + + if (emit_rb) { + DCHECK(read_barrier_slow_path != nullptr); __ Bind(read_barrier_slow_path->GetExitLabel()); - } else { - // Non read barrier code. - // Compute base source address, base destination address, and end - // source address for System.arraycopy* intrinsics in `src_base`, - // `dst_base` and `src_end` respectively. - GenSystemArrayCopyAddresses(masm, - type, - src, - src_pos, - dest, - dest_pos, - length, - src_curr_addr, - dst_curr_addr, - src_stop_addr); - // Iterate over the arrays and do a raw copy of the objects. We don't need to - // poison/unpoison. - vixl::aarch64::Label loop; - __ Bind(&loop); - { - Register tmp = temps.AcquireW(); - __ Ldr(tmp, MemOperand(src_curr_addr, element_size, PostIndex)); - __ Str(tmp, MemOperand(dst_curr_addr, element_size, PostIndex)); - } - __ Cmp(src_curr_addr, src_stop_addr); - __ B(&loop, ne); } - __ Bind(&done); } - } - // We only need one card marking on the destination array. - codegen_->MarkGCCard(dest.W(), Register(), /* emit_null_check= */ false); + // We only need one card marking on the destination array. + codegen_->MarkGCCard(dest.W(), Register(), /* emit_null_check= */ false); + + __ Bind(&skip_copy_and_write_barrier); + } __ Bind(intrinsic_slow_path->GetExitLabel()); } diff --git a/compiler/optimizing/intrinsics_riscv64.cc b/compiler/optimizing/intrinsics_riscv64.cc index 8b85ea4538..a43ab2f206 100644 --- a/compiler/optimizing/intrinsics_riscv64.cc +++ b/compiler/optimizing/intrinsics_riscv64.cc @@ -56,6 +56,7 @@ class ReadBarrierSystemArrayCopySlowPathRISCV64 : public SlowPathCodeRISCV64 { XRegister tmp_reg = tmp_.AsRegister<XRegister>(); __ Bind(GetEntryLabel()); + // The source range and destination pointer were initialized before entering the slow-path. Riscv64Label slow_copy_loop; __ Bind(&slow_copy_loop); __ Loadwu(tmp_reg, src_curr_addr, 0); @@ -928,6 +929,76 @@ void IntrinsicCodeGeneratorRISCV64::VisitStringIndexOfAfter(HInvoke* invoke) { GenerateVisitStringIndexOf(invoke, GetAssembler(), codegen_, /* start_at_zero= */ false); } +void IntrinsicLocationsBuilderRISCV64::VisitStringNewStringFromBytes(HInvoke* invoke) { + LocationSummary* locations = new (allocator_) LocationSummary( + invoke, LocationSummary::kCallOnMainAndSlowPath, kIntrinsified); + InvokeRuntimeCallingConvention calling_convention; + locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); + locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); + locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); + locations->SetInAt(3, Location::RegisterLocation(calling_convention.GetRegisterAt(3))); + locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kReference)); +} + +void IntrinsicCodeGeneratorRISCV64::VisitStringNewStringFromBytes(HInvoke* invoke) { + Riscv64Assembler* assembler = GetAssembler(); + LocationSummary* locations = invoke->GetLocations(); + XRegister byte_array = locations->InAt(0).AsRegister<XRegister>(); + + SlowPathCodeRISCV64* slow_path = + new (codegen_->GetScopedAllocator()) IntrinsicSlowPathRISCV64(invoke); + codegen_->AddSlowPath(slow_path); + __ Beqz(byte_array, slow_path->GetEntryLabel()); + + codegen_->InvokeRuntime(kQuickAllocStringFromBytes, invoke, invoke->GetDexPc(), slow_path); + CheckEntrypointTypes<kQuickAllocStringFromBytes, void*, void*, int32_t, int32_t, int32_t>(); + __ Bind(slow_path->GetExitLabel()); +} + +void IntrinsicLocationsBuilderRISCV64::VisitStringNewStringFromChars(HInvoke* invoke) { + LocationSummary* locations = + new (allocator_) LocationSummary(invoke, LocationSummary::kCallOnMainOnly, kIntrinsified); + InvokeRuntimeCallingConvention calling_convention; + locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); + locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); + locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); + locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kReference)); +} + +void IntrinsicCodeGeneratorRISCV64::VisitStringNewStringFromChars(HInvoke* invoke) { + // No need to emit code checking whether `locations->InAt(2)` is a null + // pointer, as callers of the native method + // + // java.lang.StringFactory.newStringFromChars(int offset, int charCount, char[] data) + // + // all include a null check on `data` before calling that method. + codegen_->InvokeRuntime(kQuickAllocStringFromChars, invoke, invoke->GetDexPc()); + CheckEntrypointTypes<kQuickAllocStringFromChars, void*, int32_t, int32_t, void*>(); +} + +void IntrinsicLocationsBuilderRISCV64::VisitStringNewStringFromString(HInvoke* invoke) { + LocationSummary* locations = new (allocator_) LocationSummary( + invoke, LocationSummary::kCallOnMainAndSlowPath, kIntrinsified); + InvokeRuntimeCallingConvention calling_convention; + locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); + locations->SetOut(calling_convention.GetReturnLocation(DataType::Type::kReference)); +} + +void IntrinsicCodeGeneratorRISCV64::VisitStringNewStringFromString(HInvoke* invoke) { + Riscv64Assembler* assembler = GetAssembler(); + LocationSummary* locations = invoke->GetLocations(); + XRegister string_to_copy = locations->InAt(0).AsRegister<XRegister>(); + + SlowPathCodeRISCV64* slow_path = + new (codegen_->GetScopedAllocator()) IntrinsicSlowPathRISCV64(invoke); + codegen_->AddSlowPath(slow_path); + __ Beqz(string_to_copy, slow_path->GetEntryLabel()); + + codegen_->InvokeRuntime(kQuickAllocStringFromString, invoke, invoke->GetDexPc(), slow_path); + CheckEntrypointTypes<kQuickAllocStringFromString, void*, void*>(); + __ Bind(slow_path->GetExitLabel()); +} + static void GenerateSet(CodeGeneratorRISCV64* codegen, std::memory_order order, Location value, @@ -1497,112 +1568,116 @@ void IntrinsicCodeGeneratorRISCV64::VisitSystemArrayCopy(HInvoke* invoke) { temp2, optimizations.GetCountIsDestinationLength(), dest_position_sign_checked); - { - // We use a block to end the scratch scope before the write barrier, thus - // freeing the temporary registers so they can be used in `MarkGCCard`. - ScratchRegisterScope srs(assembler); - bool emit_rb = codegen_->EmitBakerReadBarrier(); - XRegister temp3 = - emit_rb ? locations->GetTemp(2).AsRegister<XRegister>() : srs.AllocateXRegister(); - - auto check_non_primitive_array_class = [&](XRegister klass, XRegister temp) { - // No read barrier is needed for reading a chain of constant references for comparing - // with null, or for reading a constant primitive value, see `ReadBarrierOption`. - // /* HeapReference<Class> */ temp = klass->component_type_ - __ Loadwu(temp, klass, component_offset); - codegen_->MaybeUnpoisonHeapReference(temp); - __ Beqz(temp, intrinsic_slow_path->GetEntryLabel()); - // /* uint16_t */ temp = static_cast<uint16>(klass->primitive_type_); - __ Loadhu(temp, temp, primitive_offset); - static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot"); - __ Bnez(temp, intrinsic_slow_path->GetEntryLabel()); - }; - - if (!optimizations.GetDoesNotNeedTypeCheck()) { - // Check whether all elements of the source array are assignable to the component - // type of the destination array. We do two checks: the classes are the same, - // or the destination is Object[]. If none of these checks succeed, we go to the - // slow path. - if (emit_rb) { - // /* HeapReference<Class> */ temp1 = dest->klass_ - codegen_->GenerateFieldLoadWithBakerReadBarrier(invoke, - Location::RegisterLocation(temp1), - dest, - class_offset, - Location::RegisterLocation(temp3), - /* needs_null_check= */ false); - // /* HeapReference<Class> */ temp2 = src->klass_ - codegen_->GenerateFieldLoadWithBakerReadBarrier(invoke, - Location::RegisterLocation(temp2), - src, - class_offset, - Location::RegisterLocation(temp3), - /* needs_null_check= */ false); - } else { - // /* HeapReference<Class> */ temp1 = dest->klass_ - __ Loadwu(temp1, dest, class_offset); - codegen_->MaybeUnpoisonHeapReference(temp1); - // /* HeapReference<Class> */ temp2 = src->klass_ - __ Loadwu(temp2, src, class_offset); - codegen_->MaybeUnpoisonHeapReference(temp2); - } + auto check_non_primitive_array_class = [&](XRegister klass, XRegister temp) { + // No read barrier is needed for reading a chain of constant references for comparing + // with null, or for reading a constant primitive value, see `ReadBarrierOption`. + // /* HeapReference<Class> */ temp = klass->component_type_ + __ Loadwu(temp, klass, component_offset); + codegen_->MaybeUnpoisonHeapReference(temp); + // Check that the component type is not null. + __ Beqz(temp, intrinsic_slow_path->GetEntryLabel()); + // Check that the component type is not a primitive. + // /* uint16_t */ temp = static_cast<uint16>(klass->primitive_type_); + __ Loadhu(temp, temp, primitive_offset); + static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot"); + __ Bnez(temp, intrinsic_slow_path->GetEntryLabel()); + }; - if (optimizations.GetDestinationIsTypedObjectArray()) { - DCHECK(optimizations.GetDestinationIsNonPrimitiveArray()); - Riscv64Label do_copy; - // For class match, we can skip the source type check regardless of the optimization flag. - __ Beq(temp1, temp2, &do_copy); - // /* HeapReference<Class> */ temp1 = temp1->component_type_ - // No read barrier is needed for reading a chain of constant references - // for comparing with null, see `ReadBarrierOption`. - __ Loadwu(temp1, temp1, component_offset); - codegen_->MaybeUnpoisonHeapReference(temp1); - // /* HeapReference<Class> */ temp1 = temp1->super_class_ - __ Loadwu(temp1, temp1, super_offset); - // No need to unpoison the result, we're comparing against null. - __ Bnez(temp1, intrinsic_slow_path->GetEntryLabel()); - // Bail out if the source is not a non primitive array. - if (!optimizations.GetSourceIsNonPrimitiveArray()) { - check_non_primitive_array_class(temp2, temp3); - } - __ Bind(&do_copy); - } else { - DCHECK(!optimizations.GetDestinationIsTypedObjectArray()); - // For class match, we can skip the array type check completely if at least one of source - // and destination is known to be a non primitive array, otherwise one check is enough. - __ Bne(temp1, temp2, intrinsic_slow_path->GetEntryLabel()); - if (!optimizations.GetDestinationIsNonPrimitiveArray() && - !optimizations.GetSourceIsNonPrimitiveArray()) { - check_non_primitive_array_class(temp2, temp3); - } - } - } else if (!optimizations.GetSourceIsNonPrimitiveArray()) { - DCHECK(optimizations.GetDestinationIsNonPrimitiveArray()); - // Bail out if the source is not a non primitive array. - // No read barrier is needed for reading a chain of constant references for comparing - // with null, or for reading a constant primitive value, see `ReadBarrierOption`. - // /* HeapReference<Class> */ temp1 = src->klass_ + if (!optimizations.GetDoesNotNeedTypeCheck()) { + // Check whether all elements of the source array are assignable to the component + // type of the destination array. We do two checks: the classes are the same, + // or the destination is Object[]. If none of these checks succeed, we go to the + // slow path. + + if (codegen_->EmitBakerReadBarrier()) { + XRegister temp3 = locations->GetTemp(2).AsRegister<XRegister>(); + // /* HeapReference<Class> */ temp1 = dest->klass_ + codegen_->GenerateFieldLoadWithBakerReadBarrier(invoke, + Location::RegisterLocation(temp1), + dest, + class_offset, + Location::RegisterLocation(temp3), + /* needs_null_check= */ false); + // /* HeapReference<Class> */ temp2 = src->klass_ + codegen_->GenerateFieldLoadWithBakerReadBarrier(invoke, + Location::RegisterLocation(temp2), + src, + class_offset, + Location::RegisterLocation(temp3), + /* needs_null_check= */ false); + } else { + // /* HeapReference<Class> */ temp1 = dest->klass_ + __ Loadwu(temp1, dest, class_offset); + codegen_->MaybeUnpoisonHeapReference(temp1); + // /* HeapReference<Class> */ temp2 = src->klass_ __ Loadwu(temp2, src, class_offset); codegen_->MaybeUnpoisonHeapReference(temp2); - check_non_primitive_array_class(temp2, temp3); } - if (length.IsConstant() && length.GetConstant()->AsIntConstant()->GetValue() == 0) { - // Null constant length: not need to emit the loop code at all. + if (optimizations.GetDestinationIsTypedObjectArray()) { + DCHECK(optimizations.GetDestinationIsNonPrimitiveArray()); + Riscv64Label do_copy; + // For class match, we can skip the source type check regardless of the optimization flag. + __ Beq(temp1, temp2, &do_copy); + // No read barrier is needed for reading a chain of constant references + // for comparing with null, see `ReadBarrierOption`. + // /* HeapReference<Class> */ temp1 = temp1->component_type_ + __ Loadwu(temp1, temp1, component_offset); + codegen_->MaybeUnpoisonHeapReference(temp1); + // /* HeapReference<Class> */ temp1 = temp1->super_class_ + __ Loadwu(temp1, temp1, super_offset); + // No need to unpoison the result, we're comparing against null. + __ Bnez(temp1, intrinsic_slow_path->GetEntryLabel()); + // Bail out if the source is not a non primitive array. + if (!optimizations.GetSourceIsNonPrimitiveArray()) { + check_non_primitive_array_class(temp2, temp2); + } + __ Bind(&do_copy); } else { + DCHECK(!optimizations.GetDestinationIsTypedObjectArray()); + // For class match, we can skip the array type check completely if at least one of source + // and destination is known to be a non primitive array, otherwise one check is enough. + __ Bne(temp1, temp2, intrinsic_slow_path->GetEntryLabel()); + if (!optimizations.GetDestinationIsNonPrimitiveArray() && + !optimizations.GetSourceIsNonPrimitiveArray()) { + check_non_primitive_array_class(temp2, temp2); + } + } + } else if (!optimizations.GetSourceIsNonPrimitiveArray()) { + DCHECK(optimizations.GetDestinationIsNonPrimitiveArray()); + // Bail out if the source is not a non primitive array. + // No read barrier is needed for reading a chain of constant references for comparing + // with null, or for reading a constant primitive value, see `ReadBarrierOption`. + // /* HeapReference<Class> */ temp2 = src->klass_ + __ Loadwu(temp2, src, class_offset); + codegen_->MaybeUnpoisonHeapReference(temp2); + check_non_primitive_array_class(temp2, temp2); + } + + if (length.IsConstant() && length.GetConstant()->AsIntConstant()->GetValue() == 0) { + // Null constant length: not need to emit the loop code at all. + } else { + Riscv64Label skip_copy_and_write_barrier; + if (length.IsRegister()) { + // Don't enter the copy loop if the length is null. + __ Beqz(length.AsRegister<XRegister>(), &skip_copy_and_write_barrier); + } + + { + // We use a block to end the scratch scope before the write barrier, thus + // freeing the scratch registers so they can be used in `MarkGCCard`. + ScratchRegisterScope srs(assembler); + bool emit_rb = codegen_->EmitBakerReadBarrier(); + XRegister temp3 = + emit_rb ? locations->GetTemp(2).AsRegister<XRegister>() : srs.AllocateXRegister(); + XRegister src_curr_addr = temp1; XRegister dst_curr_addr = temp2; XRegister src_stop_addr = temp3; - Riscv64Label done; const DataType::Type type = DataType::Type::kReference; const int32_t element_size = DataType::Size(type); - if (length.IsRegister()) { - // Don't enter the copy loop if the length is null. - __ Beqz(length.AsRegister<XRegister>(), &done); - } - XRegister tmp = kNoXRegister; SlowPathCodeRISCV64* read_barrier_slow_path = nullptr; if (emit_rb) { @@ -1688,17 +1763,18 @@ void IntrinsicCodeGeneratorRISCV64::VisitSystemArrayCopy(HInvoke* invoke) { __ Addi(dst_curr_addr, dst_curr_addr, element_size); // Bare: `TMP` shall not be clobbered. __ Bne(src_curr_addr, src_stop_addr, &loop, /*is_bare=*/ true); - __ Bind(&done); if (emit_rb) { DCHECK(read_barrier_slow_path != nullptr); __ Bind(read_barrier_slow_path->GetExitLabel()); } } - } - // We only need one card marking on the destination array. - codegen_->MarkGCCard(dest, XRegister(kNoXRegister), /* emit_null_check= */ false); + // We only need one card marking on the destination array. + codegen_->MarkGCCard(dest, XRegister(kNoXRegister), /* emit_null_check= */ false); + + __ Bind(&skip_copy_and_write_barrier); + } __ Bind(intrinsic_slow_path->GetExitLabel()); } @@ -4289,6 +4365,26 @@ void IntrinsicCodeGeneratorRISCV64::VisitThreadCurrentThread(HInvoke* invoke) { __ Loadwu(out, TR, Thread::PeerOffset<kRiscv64PointerSize>().Int32Value()); } +void IntrinsicLocationsBuilderRISCV64::VisitThreadInterrupted(HInvoke* invoke) { + LocationSummary* locations = + new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified); + locations->SetOut(Location::RequiresRegister()); +} + +void IntrinsicCodeGeneratorRISCV64::VisitThreadInterrupted(HInvoke* invoke) { + LocationSummary* locations = invoke->GetLocations(); + Riscv64Assembler* assembler = GetAssembler(); + XRegister out = locations->Out().AsRegister<XRegister>(); + Riscv64Label done; + + codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny); + __ Loadw(out, TR, Thread::InterruptedOffset<kRiscv64PointerSize>().Int32Value()); + __ Beqz(out, &done); + __ Storew(Zero, TR, Thread::InterruptedOffset<kRiscv64PointerSize>().Int32Value()); + codegen_->GenerateMemoryBarrier(MemBarrierKind::kAnyAny); + __ Bind(&done); +} + void IntrinsicLocationsBuilderRISCV64::VisitReachabilityFence(HInvoke* invoke) { LocationSummary* locations = new (allocator_) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified); diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc index 97c19a1665..5986a2f3a0 100644 --- a/compiler/optimizing/intrinsics_x86.cc +++ b/compiler/optimizing/intrinsics_x86.cc @@ -115,6 +115,7 @@ class ReadBarrierSystemArrayCopySlowPathX86 : public SlowPathCode { Register value = locations->GetTemp(3).AsRegister<Register>(); __ Bind(GetEntryLabel()); + // The `src_curr_addr` and `dst_curr_addr` were initialized before entering the slow-path. GenArrayAddress(assembler, src_stop_addr, src_curr_addr, length, type, /*data_offset=*/ 0u); NearLabel loop; diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc index b65f57d71e..5177ac4d44 100644 --- a/compiler/optimizing/intrinsics_x86_64.cc +++ b/compiler/optimizing/intrinsics_x86_64.cc @@ -111,6 +111,7 @@ class ReadBarrierSystemArrayCopySlowPathX86_64 : public SlowPathCode { CpuRegister src_stop_addr = locations->GetTemp(2).AsRegister<CpuRegister>(); __ Bind(GetEntryLabel()); + // The `src_curr_addr` and `dst_curr_addr` were initialized before entering the slow-path. GenArrayAddress(assembler, src_stop_addr, src_curr_addr, length, type, /*data_offset=*/ 0u); NearLabel loop; diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc index 2e5ee84d76..e7b95c8d00 100644 --- a/compiler/optimizing/load_store_elimination.cc +++ b/compiler/optimizing/load_store_elimination.cc @@ -861,23 +861,33 @@ class LSEVisitor final : private HGraphDelegateVisitor { } void VisitInstanceFieldGet(HInstanceFieldGet* instruction) override { + HInstruction* object = instruction->InputAt(0); if (instruction->IsVolatile()) { - HandleAcquireLoad(instruction); - return; + ReferenceInfo* ref_info = heap_location_collector_.FindReferenceInfoOf( + heap_location_collector_.HuntForOriginalReference(object)); + if (!ref_info->IsSingletonAndRemovable()) { + HandleAcquireLoad(instruction); + return; + } + // Treat it as a normal load if it is a removable singleton. } - HInstruction* object = instruction->InputAt(0); const FieldInfo& field = instruction->GetFieldInfo(); VisitGetLocation(instruction, heap_location_collector_.GetFieldHeapLocation(object, &field)); } void VisitInstanceFieldSet(HInstanceFieldSet* instruction) override { + HInstruction* object = instruction->InputAt(0); if (instruction->IsVolatile()) { - HandleReleaseStore(instruction); - return; + ReferenceInfo* ref_info = heap_location_collector_.FindReferenceInfoOf( + heap_location_collector_.HuntForOriginalReference(object)); + if (!ref_info->IsSingletonAndRemovable()) { + HandleReleaseStore(instruction); + return; + } + // Treat it as a normal store if it is a removable singleton. } - HInstruction* object = instruction->InputAt(0); const FieldInfo& field = instruction->GetFieldInfo(); HInstruction* value = instruction->InputAt(1); size_t idx = heap_location_collector_.GetFieldHeapLocation(object, &field); @@ -890,8 +900,8 @@ class LSEVisitor final : private HGraphDelegateVisitor { return; } - HInstruction* cls = instruction->InputAt(0); const FieldInfo& field = instruction->GetFieldInfo(); + HInstruction* cls = instruction->InputAt(0); VisitGetLocation(instruction, heap_location_collector_.GetFieldHeapLocation(cls, &field)); } @@ -901,14 +911,30 @@ class LSEVisitor final : private HGraphDelegateVisitor { return; } - HInstruction* cls = instruction->InputAt(0); const FieldInfo& field = instruction->GetFieldInfo(); + HInstruction* cls = instruction->InputAt(0); HInstruction* value = instruction->InputAt(1); size_t idx = heap_location_collector_.GetFieldHeapLocation(cls, &field); VisitSetLocation(instruction, idx, value); } void VisitMonitorOperation(HMonitorOperation* monitor_op) override { + HInstruction* object = monitor_op->InputAt(0); + ReferenceInfo* ref_info = heap_location_collector_.FindReferenceInfoOf( + heap_location_collector_.HuntForOriginalReference(object)); + if (ref_info->IsSingletonAndRemovable()) { + // If the object is a removable singleton, we know that no other threads will have + // access to it, and we can remove the MonitorOperation instruction. + // MONITOR_ENTER throws when encountering a null object. If `object` is a removable + // singleton, it is guaranteed to be non-null so we don't have to worry about the NullCheck. + DCHECK(!object->CanBeNull()); + monitor_op->GetBlock()->RemoveInstruction(monitor_op); + MaybeRecordStat(stats_, MethodCompilationStat::kRemovedMonitorOp); + return; + } + + // We detected a monitor operation that we couldn't remove. See also LSEVisitor::Run(). + monitor_op->GetBlock()->GetGraph()->SetHasMonitorOperations(true); if (monitor_op->IsEnter()) { HandleAcquireLoad(monitor_op); } else { @@ -2439,8 +2465,7 @@ void LSEVisitor::ProcessLoopPhiWithUnknownInput(PhiPlaceholder loop_phi_with_unk if (load_or_store->GetBlock() != block) { break; // End of instructions from the current block. } - bool is_store = load_or_store->GetSideEffects().DoesAnyWrite(); - DCHECK_EQ(is_store, IsStore(load_or_store)); + const bool is_store = IsStore(load_or_store); HInstruction* stored_value = nullptr; if (is_store) { auto it = store_records_.find(load_or_store); @@ -2772,6 +2797,10 @@ void LSEVisitor::FindStoresWritingOldValues() { } void LSEVisitor::Run() { + // 0. Set HasMonitorOperations to false. If we encounter some MonitorOperations that we can't + // remove, we will set it to true in VisitMonitorOperation. + GetGraph()->SetHasMonitorOperations(false); + // 1. Process blocks and instructions in reverse post order. for (HBasicBlock* block : GetGraph()->GetReversePostOrder()) { VisitBasicBlock(block); @@ -2813,14 +2842,22 @@ void LSEVisitor::FinishFullLSE() { load->ReplaceWith(substitute); load->GetBlock()->RemoveInstruction(load); + if ((load->IsInstanceFieldGet() && load->AsInstanceFieldGet()->IsVolatile()) || + (load->IsStaticFieldGet() && load->AsStaticFieldGet()->IsVolatile())) { + MaybeRecordStat(stats_, MethodCompilationStat::kRemovedVolatileLoad); + } } // Remove all the stores we can. for (const LoadStoreRecord& record : loads_and_stores_) { - bool is_store = record.load_or_store->GetSideEffects().DoesAnyWrite(); - DCHECK_EQ(is_store, IsStore(record.load_or_store)); - if (is_store && !kept_stores_.IsBitSet(record.load_or_store->GetId())) { + if (IsStore(record.load_or_store) && !kept_stores_.IsBitSet(record.load_or_store->GetId())) { record.load_or_store->GetBlock()->RemoveInstruction(record.load_or_store); + if ((record.load_or_store->IsInstanceFieldSet() && + record.load_or_store->AsInstanceFieldSet()->IsVolatile()) || + (record.load_or_store->IsStaticFieldSet() && + record.load_or_store->AsStaticFieldSet()->IsVolatile())) { + MaybeRecordStat(stats_, MethodCompilationStat::kRemovedVolatileStore); + } } } diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index 2cfe5b3ae2..e6cb3a2379 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -1575,14 +1575,46 @@ void HInstruction::ReplaceWith(HInstruction* other) { void HInstruction::ReplaceUsesDominatedBy(HInstruction* dominator, HInstruction* replacement, bool strictly_dominated) { + // Get the dominated blocks first to faster calculation of domination afterwards. + HGraph* graph = GetBlock()->GetGraph(); + ArenaBitVector visited_blocks(graph->GetAllocator(), + graph->GetBlocks().size(), + /* expandable= */ false, + kArenaAllocMisc); + visited_blocks.ClearAllBits(); + ScopedArenaAllocator allocator(graph->GetArenaStack()); + ScopedArenaQueue<const HBasicBlock*> worklist(allocator.Adapter(kArenaAllocMisc)); + HBasicBlock* dominator_block = dominator->GetBlock(); + worklist.push(dominator_block); + + while (!worklist.empty()) { + const HBasicBlock* current = worklist.front(); + worklist.pop(); + visited_blocks.SetBit(current->GetBlockId()); + for (HBasicBlock* dominated : current->GetDominatedBlocks()) { + if (visited_blocks.IsBitSet(dominated->GetBlockId())) { + continue; + } + worklist.push(dominated); + } + } + const HUseList<HInstruction*>& uses = GetUses(); for (auto it = uses.begin(), end = uses.end(); it != end; /* ++it below */) { HInstruction* user = it->GetUser(); + HBasicBlock* block = user->GetBlock(); size_t index = it->GetIndex(); // Increment `it` now because `*it` may disappear thanks to user->ReplaceInput(). ++it; - const bool dominated = - strictly_dominated ? dominator->StrictlyDominates(user) : dominator->Dominates(user); + bool dominated = false; + if (dominator_block == block) { + // Trickier case, call the other methods. + dominated = + strictly_dominated ? dominator->StrictlyDominates(user) : dominator->Dominates(user); + } else { + // Block domination. + dominated = visited_blocks.IsBitSet(block->GetBlockId()); + } if (dominated) { user->ReplaceInput(replacement, index); @@ -1590,9 +1622,8 @@ void HInstruction::ReplaceUsesDominatedBy(HInstruction* dominator, // If the input flows from a block dominated by `dominator`, we can replace it. // We do not perform this for catch phis as we don't have control flow support // for their inputs. - const ArenaVector<HBasicBlock*>& predecessors = user->GetBlock()->GetPredecessors(); - HBasicBlock* predecessor = predecessors[index]; - if (dominator->GetBlock()->Dominates(predecessor)) { + HBasicBlock* predecessor = block->GetPredecessors()[index]; + if (visited_blocks.IsBitSet(predecessor->GetBlockId())) { user->ReplaceInput(replacement, index); } } diff --git a/compiler/optimizing/optimization.cc b/compiler/optimizing/optimization.cc index a4df48c0ee..9c1506afa5 100644 --- a/compiler/optimizing/optimization.cc +++ b/compiler/optimizing/optimization.cc @@ -80,7 +80,6 @@ const char* OptimizationPassName(OptimizationPass pass) { return BoundsCheckElimination::kBoundsCheckEliminationPassName; case OptimizationPass::kLoadStoreElimination: return LoadStoreElimination::kLoadStoreEliminationPassName; - case OptimizationPass::kAggressiveConstantFolding: case OptimizationPass::kConstantFolding: return HConstantFolding::kConstantFoldingPassName; case OptimizationPass::kDeadCodeElimination: @@ -238,10 +237,6 @@ ArenaVector<HOptimization*> ConstructOptimizations( case OptimizationPass::kConstantFolding: opt = new (allocator) HConstantFolding(graph, stats, pass_name); break; - case OptimizationPass::kAggressiveConstantFolding: - opt = new (allocator) - HConstantFolding(graph, stats, pass_name, /* use_all_optimizations_ = */ true); - break; case OptimizationPass::kDeadCodeElimination: opt = new (allocator) HDeadCodeElimination(graph, stats, pass_name); break; @@ -257,7 +252,6 @@ ArenaVector<HOptimization*> ConstructOptimizations( accessor.RegistersSize(), /* total_number_of_instructions= */ 0, /* parent= */ nullptr, - /* caller_environment= */ nullptr, /* depth= */ 0, /* try_catch_inlining_allowed= */ true, pass_name); diff --git a/compiler/optimizing/optimization.h b/compiler/optimizing/optimization.h index 57c5f4639c..55aa8f914b 100644 --- a/compiler/optimizing/optimization.h +++ b/compiler/optimizing/optimization.h @@ -67,7 +67,6 @@ class HOptimization : public ArenaObject<kArenaAllocOptimization> { // field is preferred over a string lookup at places where performance matters. // TODO: generate this table and lookup methods below automatically? enum class OptimizationPass { - kAggressiveConstantFolding, kAggressiveInstructionSimplifier, kBoundsCheckElimination, kCHAGuardOptimization, diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 5868f22ab8..8909a59ddf 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -368,10 +368,10 @@ class OptimizingCompiler final : public Compiler { const DexCompilationUnit& dex_compilation_unit, PassObserver* pass_observer) const; - bool RunRequiredPasses(HGraph* graph, - CodeGenerator* codegen, - const DexCompilationUnit& dex_compilation_unit, - PassObserver* pass_observer) const; + bool RunBaselineOptimizations(HGraph* graph, + CodeGenerator* codegen, + const DexCompilationUnit& dex_compilation_unit, + PassObserver* pass_observer) const; std::vector<uint8_t> GenerateJitDebugInfo(const debug::MethodDebugInfo& method_debug_info); @@ -444,10 +444,10 @@ static bool IsInstructionSetSupported(InstructionSet instruction_set) { instruction_set == InstructionSet::kX86_64; } -bool OptimizingCompiler::RunRequiredPasses(HGraph* graph, - CodeGenerator* codegen, - const DexCompilationUnit& dex_compilation_unit, - PassObserver* pass_observer) const { +bool OptimizingCompiler::RunBaselineOptimizations(HGraph* graph, + CodeGenerator* codegen, + const DexCompilationUnit& dex_compilation_unit, + PassObserver* pass_observer) const { switch (codegen->GetCompilerOptions().GetInstructionSet()) { #if defined(ART_ENABLE_CODEGEN_arm) case InstructionSet::kThumb2: @@ -666,7 +666,7 @@ void OptimizingCompiler::RunOptimizations(HGraph* graph, OptDef(OptimizationPass::kGlobalValueNumbering), // Simplification (TODO: only if GVN occurred). OptDef(OptimizationPass::kSelectGenerator), - OptDef(OptimizationPass::kAggressiveConstantFolding, + OptDef(OptimizationPass::kConstantFolding, "constant_folding$after_gvn"), OptDef(OptimizationPass::kInstructionSimplifier, "instruction_simplifier$after_gvn"), @@ -904,15 +904,21 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator, } } - if (compilation_kind == CompilationKind::kBaseline && compiler_options.ProfileBranches()) { - // Branch profiling currently doesn't support running optimizations. - RunRequiredPasses(graph, codegen.get(), dex_compilation_unit, &pass_observer); + if (compilation_kind == CompilationKind::kBaseline) { + RunBaselineOptimizations(graph, codegen.get(), dex_compilation_unit, &pass_observer); } else { RunOptimizations(graph, codegen.get(), dex_compilation_unit, &pass_observer); PassScope scope(WriteBarrierElimination::kWBEPassName, &pass_observer); WriteBarrierElimination(graph, compilation_stats_.get()).Run(); } + RegisterAllocator::Strategy regalloc_strategy = + compiler_options.GetRegisterAllocationStrategy(); + AllocateRegisters(graph, + codegen.get(), + &pass_observer, + regalloc_strategy, + compilation_stats_.get()); // If we are compiling baseline and we haven't created a profiling info for // this method already, do it now. if (jit != nullptr && @@ -929,14 +935,6 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* allocator, } } - RegisterAllocator::Strategy regalloc_strategy = - compiler_options.GetRegisterAllocationStrategy(); - AllocateRegisters(graph, - codegen.get(), - &pass_observer, - regalloc_strategy, - compilation_stats_.get()); - codegen->Compile(); pass_observer.DumpDisassembly(); diff --git a/compiler/optimizing/optimizing_compiler_stats.h b/compiler/optimizing/optimizing_compiler_stats.h index 4549af3cbf..60d18d2f24 100644 --- a/compiler/optimizing/optimizing_compiler_stats.h +++ b/compiler/optimizing/optimizing_compiler_stats.h @@ -50,6 +50,9 @@ enum class MethodCompilationStat { kRemovedDeadPhi, kRemovedTry, kRemovedNullCheck, + kRemovedVolatileLoad, + kRemovedVolatileStore, + kRemovedMonitorOp, kNotCompiledSkipped, kNotCompiledInvalidBytecode, kNotCompiledThrowCatchLoop, diff --git a/compiler/optimizing/profiling_info_builder.cc b/compiler/optimizing/profiling_info_builder.cc index 19795f5466..7888753830 100644 --- a/compiler/optimizing/profiling_info_builder.cc +++ b/compiler/optimizing/profiling_info_builder.cc @@ -20,7 +20,6 @@ #include "code_generator.h" #include "driver/compiler_options.h" #include "dex/code_item_accessors-inl.h" -#include "inliner.h" #include "jit/profiling_info.h" #include "optimizing_compiler_stats.h" #include "scoped_thread_state_change-inl.h" @@ -43,53 +42,10 @@ void ProfilingInfoBuilder::Run() { ProfilingInfo::Create(soa.Self(), GetGraph()->GetArtMethod(), inline_caches_)); } - -uint32_t ProfilingInfoBuilder::EncodeInlinedDexPc(const HInliner* inliner, - const CompilerOptions& compiler_options, - HInvoke* invoke) { - DCHECK(inliner->GetCallerEnvironment() != nullptr); - DCHECK(inliner->GetParent() != nullptr); - std::vector<uint32_t> temp_vector; - temp_vector.push_back(invoke->GetDexPc()); - while (inliner->GetCallerEnvironment() != nullptr) { - temp_vector.push_back(inliner->GetCallerEnvironment()->GetDexPc()); - inliner = inliner->GetParent(); - } - - DCHECK_EQ(inliner->GetOutermostGraph(), inliner->GetGraph()); - return InlineCache::EncodeDexPc( - inliner->GetOutermostGraph()->GetArtMethod(), - temp_vector, - compiler_options.GetInlineMaxCodeUnits()); -} - -static uint32_t EncodeDexPc(HInvoke* invoke, const CompilerOptions& compiler_options) { - std::vector<uint32_t> dex_pcs; - ArtMethod* outer_method = nullptr; - for (HEnvironment* environment = invoke->GetEnvironment(); - environment != nullptr; - environment = environment->GetParent()) { - outer_method = environment->GetMethod(); - dex_pcs.push_back(environment->GetDexPc()); - } - - ScopedObjectAccess soa(Thread::Current()); - return InlineCache::EncodeDexPc( - outer_method, - dex_pcs, - compiler_options.GetInlineMaxCodeUnits()); -} - void ProfilingInfoBuilder::HandleInvoke(HInvoke* invoke) { + DCHECK(!invoke->GetEnvironment()->IsFromInlinedInvoke()); if (IsInlineCacheUseful(invoke, codegen_)) { - uint32_t dex_pc = EncodeDexPc(invoke, compiler_options_); - if (dex_pc != kNoDexPc) { - inline_caches_.push_back(dex_pc); - } else { - ScopedObjectAccess soa(Thread::Current()); - LOG(WARNING) << "Could not encode dex pc for " - << invoke->GetResolvedMethod()->PrettyMethod(); - } + inline_caches_.push_back(invoke->GetDexPc()); } } @@ -125,15 +81,10 @@ bool ProfilingInfoBuilder::IsInlineCacheUseful(HInvoke* invoke, CodeGenerator* c return true; } -InlineCache* ProfilingInfoBuilder::GetInlineCache(ProfilingInfo* info, - const CompilerOptions& compiler_options, - HInvoke* instruction) { +InlineCache* ProfilingInfoBuilder::GetInlineCache(ProfilingInfo* info, HInvoke* instruction) { + DCHECK(!instruction->GetEnvironment()->IsFromInlinedInvoke()); ScopedObjectAccess soa(Thread::Current()); - uint32_t dex_pc = EncodeDexPc(instruction, compiler_options); - if (dex_pc == kNoDexPc) { - return nullptr; - } - return info->GetInlineCache(dex_pc); + return info->GetInlineCache(instruction->GetDexPc()); } } // namespace art diff --git a/compiler/optimizing/profiling_info_builder.h b/compiler/optimizing/profiling_info_builder.h index c8dc59a03c..2185b0eed3 100644 --- a/compiler/optimizing/profiling_info_builder.h +++ b/compiler/optimizing/profiling_info_builder.h @@ -24,7 +24,6 @@ namespace art HIDDEN { class CodeGenerator; class CompilerOptions; -class HInliner; class InlineCache; class ProfilingInfo; @@ -43,13 +42,8 @@ class ProfilingInfoBuilder : public HGraphDelegateVisitor { static constexpr const char* kProfilingInfoBuilderPassName = "profiling_info_builder"; - static InlineCache* GetInlineCache(ProfilingInfo* info, - const CompilerOptions& compiler_options, - HInvoke* invoke); + static InlineCache* GetInlineCache(ProfilingInfo* info, HInvoke* invoke); static bool IsInlineCacheUseful(HInvoke* invoke, CodeGenerator* codegen); - static uint32_t EncodeInlinedDexPc( - const HInliner* inliner, const CompilerOptions& compiler_options, HInvoke* invoke) - REQUIRES_SHARED(Locks::mutator_lock_); private: void VisitInvokeVirtual(HInvokeVirtual* invoke) override; @@ -58,7 +52,7 @@ class ProfilingInfoBuilder : public HGraphDelegateVisitor { void HandleInvoke(HInvoke* invoke); CodeGenerator* codegen_; - const CompilerOptions& compiler_options_; + [[maybe_unused]] const CompilerOptions& compiler_options_; std::vector<uint32_t> inline_caches_; DISALLOW_COPY_AND_ASSIGN(ProfilingInfoBuilder); diff --git a/libartbase/base/atomic.h b/libartbase/base/atomic.h index 226a088a40..91f1982720 100644 --- a/libartbase/base/atomic.h +++ b/libartbase/base/atomic.h @@ -125,6 +125,14 @@ class PACKED(sizeof(T)) Atomic : public std::atomic<T> { } }; +// Increment a debug- or statistics-only counter when there is a single writer, especially if +// concurrent reads are uncommon. Usually appreciably faster in this case. +// NOT suitable as an approximate counter with multiple writers. +template <typename T> +void IncrementStatsCounter(std::atomic<T>* a) { + a->store(a->load(std::memory_order_relaxed) + 1, std::memory_order_relaxed); +} + using AtomicInteger = Atomic<int32_t>; static_assert(sizeof(AtomicInteger) == sizeof(int32_t), "Weird AtomicInteger size"); diff --git a/libartservice/service/api/system-server-current.txt b/libartservice/service/api/system-server-current.txt index 9c1220edbc..de687d1add 100644 --- a/libartservice/service/api/system-server-current.txt +++ b/libartservice/service/api/system-server-current.txt @@ -6,6 +6,7 @@ package com.android.server.art { ctor public ArtManagerLocal(@NonNull android.content.Context); method public void addDexoptDoneCallback(boolean, @NonNull java.util.concurrent.Executor, @NonNull com.android.server.art.ArtManagerLocal.DexoptDoneCallback); method public void cancelBackgroundDexoptJob(); + method public void clearAdjustCompilerFilterCallback(); method @NonNull public void clearAppProfiles(@NonNull com.android.server.pm.PackageManagerLocal.FilteredSnapshot, @NonNull String); method public void clearBatchDexoptStartCallback(); method public void clearScheduleBackgroundDexoptJobCallback(); @@ -22,6 +23,7 @@ package com.android.server.art { method public void printShellCommandHelp(@NonNull java.io.PrintWriter); method public void removeDexoptDoneCallback(@NonNull com.android.server.art.ArtManagerLocal.DexoptDoneCallback); method public int scheduleBackgroundDexoptJob(); + method public void setAdjustCompilerFilterCallback(@NonNull java.util.concurrent.Executor, @NonNull com.android.server.art.ArtManagerLocal.AdjustCompilerFilterCallback); method public void setBatchDexoptStartCallback(@NonNull java.util.concurrent.Executor, @NonNull com.android.server.art.ArtManagerLocal.BatchDexoptStartCallback); method public void setScheduleBackgroundDexoptJobCallback(@NonNull java.util.concurrent.Executor, @NonNull com.android.server.art.ArtManagerLocal.ScheduleBackgroundDexoptJobCallback); method @NonNull public android.os.ParcelFileDescriptor snapshotAppProfile(@NonNull com.android.server.pm.PackageManagerLocal.FilteredSnapshot, @NonNull String, @Nullable String) throws com.android.server.art.ArtManagerLocal.SnapshotProfileException; @@ -30,6 +32,10 @@ package com.android.server.art { method public void unscheduleBackgroundDexoptJob(); } + public static interface ArtManagerLocal.AdjustCompilerFilterCallback { + method @NonNull public String onAdjustCompilerFilter(@NonNull String, @NonNull String, @NonNull String); + } + public static interface ArtManagerLocal.BatchDexoptStartCallback { method public void onBatchDexoptStart(@NonNull com.android.server.pm.PackageManagerLocal.FilteredSnapshot, @NonNull String, @NonNull java.util.List<java.lang.String>, @NonNull com.android.server.art.model.BatchDexoptParams.Builder, @NonNull android.os.CancellationSignal); } diff --git a/libartservice/service/java/com/android/server/art/ArtFileManager.java b/libartservice/service/java/com/android/server/art/ArtFileManager.java index 3db91642b6..51e8462b0c 100644 --- a/libartservice/service/java/com/android/server/art/ArtFileManager.java +++ b/libartservice/service/java/com/android/server/art/ArtFileManager.java @@ -69,13 +69,14 @@ public class ArtFileManager { } /** - * @param excludeNotFound If true, excludes secondary dex files that are not found on the - * filesystem. + * @param excludeObsoleteDexesAndLoaders If true, excludes secondary dex files and loaders based + * on file visibility. See details in {@link + * DexUseManagerLocal#getCheckedSecondaryDexInfo}. */ @NonNull public List<Pair<DetailedDexInfo, Abi>> getDexAndAbis(@NonNull PackageState pkgState, @NonNull AndroidPackage pkg, boolean forPrimaryDex, boolean forSecondaryDex, - boolean excludeNotFound) { + boolean excludeObsoleteDexesAndLoaders) { List<Pair<DetailedDexInfo, Abi>> dexAndAbis = new ArrayList<>(); if (forPrimaryDex) { for (DetailedPrimaryDexInfo dexInfo : @@ -86,9 +87,9 @@ public class ArtFileManager { } } if (forSecondaryDex) { - List<? extends SecondaryDexInfo> dexInfos = excludeNotFound - ? mInjector.getDexUseManager().getFilteredDetailedSecondaryDexInfo( - pkgState.getPackageName()) + List<? extends SecondaryDexInfo> dexInfos = excludeObsoleteDexesAndLoaders + ? mInjector.getDexUseManager().getCheckedSecondaryDexInfo( + pkgState.getPackageName(), true /* excludeObsoleteDexesAndLoaders */) : mInjector.getDexUseManager().getSecondaryDexInfo(pkgState.getPackageName()); for (SecondaryDexInfo dexInfo : dexInfos) { for (Abi abi : Utils.getAllAbisForNames(dexInfo.abiNames(), pkgState)) { @@ -141,7 +142,7 @@ public class ArtFileManager { for (Pair<DetailedDexInfo, Abi> pair : getDexAndAbis(pkgState, pkg, true /* forPrimaryDex */, true /* forSecondaryDex */, - true /* excludeNotFound */)) { + true /* excludeObsoleteDexesAndLoaders */)) { DetailedDexInfo dexInfo = pair.first; Abi abi = pair.second; try { @@ -178,9 +179,14 @@ public class ArtFileManager { return UsableArtifactLists.create(artifacts, vdexFiles, runtimeArtifacts); } + /** + * @param excludeForObsoleteDexesAndLoaders If true, excludes profiles for secondary dex files + * and loaders based on file visibility. See details in {@link + * DexUseManagerLocal#getCheckedSecondaryDexInfo}. + */ @NonNull public ProfileLists getProfiles(@NonNull PackageState pkgState, @NonNull AndroidPackage pkg, - boolean alsoForSecondaryDex, boolean excludeDexNotFound) { + boolean alsoForSecondaryDex, boolean excludeForObsoleteDexesAndLoaders) { List<ProfilePath> refProfiles = new ArrayList<>(); List<ProfilePath> curProfiles = new ArrayList<>(); @@ -190,9 +196,9 @@ public class ArtFileManager { PrimaryDexUtils.getCurProfiles(mInjector.getUserManager(), pkgState, dexInfo)); } if (alsoForSecondaryDex) { - List<? extends SecondaryDexInfo> dexInfos = excludeDexNotFound - ? mInjector.getDexUseManager().getFilteredDetailedSecondaryDexInfo( - pkgState.getPackageName()) + List<? extends SecondaryDexInfo> dexInfos = excludeForObsoleteDexesAndLoaders + ? mInjector.getDexUseManager().getCheckedSecondaryDexInfo( + pkgState.getPackageName(), true /* excludeForObsoleteDexesAndLoaders */) : mInjector.getDexUseManager().getSecondaryDexInfo(pkgState.getPackageName()); for (SecondaryDexInfo dexInfo : dexInfos) { refProfiles.add(AidlUtils.buildProfilePathForSecondaryRef(dexInfo.dexPath())); diff --git a/libartservice/service/java/com/android/server/art/ArtManagerLocal.java b/libartservice/service/java/com/android/server/art/ArtManagerLocal.java index b8e05494f6..ee253f9ff0 100644 --- a/libartservice/service/java/com/android/server/art/ArtManagerLocal.java +++ b/libartservice/service/java/com/android/server/art/ArtManagerLocal.java @@ -248,7 +248,8 @@ public final class ArtManagerLocal { AndroidPackage pkg = Utils.getPackageOrThrow(pkgState); List<Pair<DetailedDexInfo, Abi>> dexAndAbis = mInjector.getArtFileManager().getDexAndAbis( pkgState, pkg, (flags & ArtFlags.FLAG_FOR_PRIMARY_DEX) != 0, - (flags & ArtFlags.FLAG_FOR_SECONDARY_DEX) != 0, false /* excludeNotFound */); + (flags & ArtFlags.FLAG_FOR_SECONDARY_DEX) != 0, + false /* excludeObsoleteDexesAndLoaders */); try { List<DexContainerFileDexoptStatus> statuses = new ArrayList<>(); @@ -305,8 +306,8 @@ public final class ArtManagerLocal { // We want to delete as many profiles as possible, so this deletes profiles of all known // secondary dex files. If there are unknown secondary dex files, their profiles will be // deleted by `cleanup`. - ProfileLists list = mInjector.getArtFileManager().getProfiles( - pkgState, pkg, true /* alsoForSecondaryDex */, false /* excludeDexNotFound */); + ProfileLists list = mInjector.getArtFileManager().getProfiles(pkgState, pkg, + true /* alsoForSecondaryDex */, false /* excludeForObsoleteDexesAndLoaders */); for (ProfilePath profile : list.allProfiles()) { mInjector.getArtd().deleteProfile(profile); } @@ -804,7 +805,8 @@ public final class ArtManagerLocal { if (Utils.canDexoptPackage(appPkgState, null /* appHibernationManager */)) { AndroidPackage appPkg = Utils.getPackageOrThrow(appPkgState); ProfileLists list = mInjector.getArtFileManager().getProfiles(appPkgState, appPkg, - false /* alsoForSecondaryDex */, true /* excludeDexNotFound */); + false /* alsoForSecondaryDex */, + true /* excludeForObsoleteDexesAndLoaders */); profiles.addAll(list.allProfiles()); } }); @@ -908,8 +910,8 @@ public final class ArtManagerLocal { artifactsSize += artd.getRuntimeArtifactsSize(runtimeArtifacts); } - ProfileLists profileLists = mInjector.getArtFileManager().getProfiles( - pkgState, pkg, true /* alsoForSecondaryDex */, true /* excludeDexNotFound */); + ProfileLists profileLists = mInjector.getArtFileManager().getProfiles(pkgState, pkg, + true /* alsoForSecondaryDex */, true /* excludeForObsoleteDexesAndLoaders */); for (ProfilePath profile : profileLists.refProfiles()) { refProfilesSize += artd.getProfileSize(profile); } @@ -926,6 +928,28 @@ public final class ArtManagerLocal { } /** + * Overrides the compiler filter of a package. The callback is called whenever a package is + * going to be dexopted. This method is thread-safe. + */ + @SuppressLint("UnflaggedApi") // Flag support for mainline is not available. + @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + public void setAdjustCompilerFilterCallback(@NonNull @CallbackExecutor Executor executor, + @NonNull AdjustCompilerFilterCallback callback) { + mInjector.getConfig().setAdjustCompilerFilterCallback(executor, callback); + } + + /** + * Clears the callback set by {@link + * #setAdjustCompilerFilterCallback(Executor, AdjustCompilerFilterCallback)}. This + * method is thread-safe. + */ + @SuppressLint("UnflaggedApi") // Flag support for mainline is not available. + @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + public void clearAdjustCompilerFilterCallback() { + mInjector.getConfig().clearAdjustCompilerFilterCallback(); + } + + /** * Cleans up obsolete profiles and artifacts. * * This is done in a mark-and-sweep approach. @@ -960,7 +984,8 @@ public final class ArtManagerLocal { } AndroidPackage pkg = Utils.getPackageOrThrow(pkgState); ProfileLists profileLists = mInjector.getArtFileManager().getProfiles(pkgState, pkg, - true /* alsoForSecondaryDex */, true /* excludeDexNotFound */); + true /* alsoForSecondaryDex */, + true /* excludeForObsoleteDexesAndLoaders */); profilesToKeep.addAll(profileLists.allProfiles()); if (!Utils.shouldSkipDexoptDueToHibernation( pkgState, mInjector.getAppHibernationManager())) { @@ -1240,6 +1265,55 @@ public final class ArtManagerLocal { void onDexoptDone(@NonNull DexoptResult result); } + /** @hide */ + @SuppressLint("UnflaggedApi") // Flag support for mainline is not available. + @SystemApi(client = SystemApi.Client.SYSTEM_SERVER) + @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + public interface AdjustCompilerFilterCallback { + /** + * Returns the adjusted compiler filter for the given package. If a package doesn't need + * adjustment, this callback must return {@code originalCompilerFilter}. The callback must + * be able to handle unknown {@code originalCompilerFilter} and unknown {@code reason} + * because more compiler filters and reasons may be added in the future. + * + * The returned compiler filter overrides any compiler filter set by {@link + * DexoptParams.Builder#setCompilerFilter}, no matter the dexopt is initiated by a + * {@link #dexoptPackage} API call or any automatic batch dexopt (e.g., dexopt on boot and + * background dexopt). + * + * This callback is useful for: + * - Consistently overriding the compiler filter regardless of the dexopt initiator, for + * some performance-sensitive packages. + * - Providing a compiler filter for specific packages during batch dexopt. + * + * The actual compiler filter to be used for dexopt will be determined in the following + * order: + * + * 1. The default compiler filter for the given reason. + * 2. The compiler filter set explicitly by {@link DexoptParams.Builder#setCompilerFilter}. + * 3. ART Service's internal adjustments to upgrade the compiler filter, based on whether + * the package is System UI, etc. + * 4. The adjustments made by this callback. + * 5. ART Service's internal adjustments to downgrade the compiler filter, based on whether + * the profile is available, etc. + * + * @param packageName the name of the package to be dexopted + * @param originalCompilerFilter the compiler filter before adjustment. This is the result + * of step 3 described above. It would be the input to step 5 described above if + * it wasn't for this callback. + * @param reason the compilation reason of this dexopt operation. It is a string defined in + * {@link ReasonMapping} or a custom string passed to {@link + * DexoptParams.Builder#Builder(String)} + * + * @return the compiler filter after adjustment. This will be the input to step 5 described + * above + */ + @SuppressLint("UnflaggedApi") // Flag support for mainline is not available. + @NonNull + String onAdjustCompilerFilter(@NonNull String packageName, + @NonNull String originalCompilerFilter, @NonNull String reason); + } + /** * Represents an error that happens when snapshotting profiles. * diff --git a/libartservice/service/java/com/android/server/art/DexUseManagerLocal.java b/libartservice/service/java/com/android/server/art/DexUseManagerLocal.java index b9d0afe0d9..e9ef1a3e37 100644 --- a/libartservice/service/java/com/android/server/art/DexUseManagerLocal.java +++ b/libartservice/service/java/com/android/server/art/DexUseManagerLocal.java @@ -230,23 +230,30 @@ public class DexUseManagerLocal { * method doesn't take dex file visibility into account, so it can only be used for debugging * purpose, such as dumpsys. * - * @see #getFilteredDetailedSecondaryDexInfo(String) + * @see #getCheckedSecondaryDexInfo(String) * @hide */ public @NonNull List<? extends SecondaryDexInfo> getSecondaryDexInfo( @NonNull String packageName) { - return getSecondaryDexInfoImpl(packageName, false /* checkDexFile */); + return getSecondaryDexInfoImpl( + packageName, false /* checkDexFile */, false /* excludeObsoleteDexesAndLoaders */); } /** * Same as above, but requires disk IO, and returns the detailed information, including dex file - * visibility, filtered by dex file existence and visibility. + * visibility. + * + * @param excludeObsoleteDexesAndLoaders If true, excludes secondary dex files and loaders based + * on file visibility. More specifically, excludes loaders that can no longer load a + * secondary dex file due to a file visibility change, and excludes secondary dex files + * that are not found or only have obsolete loaders * * @hide */ - public @NonNull List<DetailedSecondaryDexInfo> getFilteredDetailedSecondaryDexInfo( - @NonNull String packageName) { - return getSecondaryDexInfoImpl(packageName, true /* checkDexFile */); + public @NonNull List<CheckedSecondaryDexInfo> getCheckedSecondaryDexInfo( + @NonNull String packageName, boolean excludeObsoleteDexesAndLoaders) { + return getSecondaryDexInfoImpl( + packageName, true /* checkDexFile */, excludeObsoleteDexesAndLoaders); } /** @@ -282,20 +289,22 @@ public class DexUseManagerLocal { } /** - * @param checkDexFile if true, check the existence and visibility of the dex files, and filter - * the results accordingly. Note that the value of the {@link - * DetailedSecondaryDexInfo#isDexFilePublic()} field is undefined if this argument is - * false. + * @param checkDexFile if true, check the existence and visibility of the dex files. Note that + * the value of the {@link CheckedSecondaryDexInfo#fileVisibility()} field is undefined + * if this argument is false + * @param excludeObsoleteDexesAndLoaders see {@link #getCheckedSecondaryDexInfo}. Only takes + * effect if {@code checkDexFile} is true */ - private @NonNull List<DetailedSecondaryDexInfo> getSecondaryDexInfoImpl( - @NonNull String packageName, boolean checkDexFile) { + private @NonNull List<CheckedSecondaryDexInfo> getSecondaryDexInfoImpl( + @NonNull String packageName, boolean checkDexFile, + boolean excludeObsoleteDexesAndLoaders) { synchronized (mLock) { PackageDexUse packageDexUse = mDexUse.mPackageDexUseByOwningPackageName.get(packageName); if (packageDexUse == null) { return List.of(); } - var results = new ArrayList<DetailedSecondaryDexInfo>(); + var results = new ArrayList<CheckedSecondaryDexInfo>(); for (var entry : packageDexUse.mSecondaryDexUseByDexFile.entrySet()) { String dexPath = entry.getKey(); SecondaryDexUse secondaryDexUse = entry.getValue(); @@ -303,12 +312,13 @@ public class DexUseManagerLocal { @FileVisibility int visibility = checkDexFile ? getDexFileVisibility(dexPath) : FileVisibility.OTHER_READABLE; - if (visibility == FileVisibility.NOT_FOUND) { + if (visibility == FileVisibility.NOT_FOUND && excludeObsoleteDexesAndLoaders) { continue; } Map<DexLoader, SecondaryDexUseRecord> filteredRecordByLoader; - if (visibility == FileVisibility.OTHER_READABLE) { + if (visibility == FileVisibility.OTHER_READABLE + || !excludeObsoleteDexesAndLoaders) { filteredRecordByLoader = secondaryDexUse.mRecordByLoader; } else { // Only keep the entry that belongs to the same app. @@ -347,10 +357,9 @@ public class DexUseManagerLocal { .map(record -> Utils.assertNonEmpty(record.mAbiName)) .collect(Collectors.toSet()); Set<DexLoader> loaders = Set.copyOf(filteredRecordByLoader.keySet()); - results.add(DetailedSecondaryDexInfo.create(dexPath, + results.add(CheckedSecondaryDexInfo.create(dexPath, Objects.requireNonNull(secondaryDexUse.mUserHandle), clc, distinctAbiNames, - loaders, isUsedByOtherApps(loaders, packageName), - visibility == FileVisibility.OTHER_READABLE)); + loaders, isUsedByOtherApps(loaders, packageName), visibility)); } return Collections.unmodifiableList(results); } @@ -857,22 +866,19 @@ public class DexUseManagerLocal { */ @Immutable @AutoValue - public abstract static class DetailedSecondaryDexInfo + public abstract static class CheckedSecondaryDexInfo extends SecondaryDexInfo implements DetailedDexInfo { - static DetailedSecondaryDexInfo create(@NonNull String dexPath, + static CheckedSecondaryDexInfo create(@NonNull String dexPath, @NonNull UserHandle userHandle, @NonNull String displayClassLoaderContext, @NonNull Set<String> abiNames, @NonNull Set<DexLoader> loaders, - boolean isUsedByOtherApps, boolean isDexFilePublic) { - return new AutoValue_DexUseManagerLocal_DetailedSecondaryDexInfo(dexPath, userHandle, + boolean isUsedByOtherApps, @FileVisibility int fileVisibility) { + return new AutoValue_DexUseManagerLocal_CheckedSecondaryDexInfo(dexPath, userHandle, displayClassLoaderContext, Collections.unmodifiableSet(abiNames), - Collections.unmodifiableSet(loaders), isUsedByOtherApps, isDexFilePublic); + Collections.unmodifiableSet(loaders), isUsedByOtherApps, fileVisibility); } - /** - * Returns true if the filesystem permission of the dex file has the "read" bit for "others" - * (S_IROTH). - */ - public abstract boolean isDexFilePublic(); + /** Indicates the visibility of the dex file. */ + public abstract @FileVisibility int fileVisibility(); } private static class DexUse { diff --git a/libartservice/service/java/com/android/server/art/DexoptHelper.java b/libartservice/service/java/com/android/server/art/DexoptHelper.java index c04a9811c8..fda43ca919 100644 --- a/libartservice/service/java/com/android/server/art/DexoptHelper.java +++ b/libartservice/service/java/com/android/server/art/DexoptHelper.java @@ -347,14 +347,16 @@ public class DexoptHelper { PrimaryDexopter getPrimaryDexopter(@NonNull PackageState pkgState, @NonNull AndroidPackage pkg, @NonNull DexoptParams params, @NonNull CancellationSignal cancellationSignal) { - return new PrimaryDexopter(mContext, pkgState, pkg, params, cancellationSignal); + return new PrimaryDexopter( + mContext, mConfig, pkgState, pkg, params, cancellationSignal); } @NonNull SecondaryDexopter getSecondaryDexopter(@NonNull PackageState pkgState, @NonNull AndroidPackage pkg, @NonNull DexoptParams params, @NonNull CancellationSignal cancellationSignal) { - return new SecondaryDexopter(mContext, pkgState, pkg, params, cancellationSignal); + return new SecondaryDexopter( + mContext, mConfig, pkgState, pkg, params, cancellationSignal); } @NonNull diff --git a/libartservice/service/java/com/android/server/art/Dexopter.java b/libartservice/service/java/com/android/server/art/Dexopter.java index fff39351c0..8713ff19bb 100644 --- a/libartservice/service/java/com/android/server/art/Dexopter.java +++ b/libartservice/service/java/com/android/server/art/Dexopter.java @@ -16,11 +16,13 @@ package com.android.server.art; +import static com.android.server.art.ArtManagerLocal.AdjustCompilerFilterCallback; import static com.android.server.art.OutputArtifacts.PermissionSettings; import static com.android.server.art.ProfilePath.TmpProfilePath; import static com.android.server.art.Utils.Abi; import static com.android.server.art.Utils.InitProfileResult; import static com.android.server.art.model.ArtFlags.DexoptFlags; +import static com.android.server.art.model.Config.Callback; import static com.android.server.art.model.DexoptResult.DexContainerFileDexoptResult; import android.R; @@ -45,6 +47,7 @@ import androidx.annotation.RequiresApi; import com.android.internal.annotations.VisibleForTesting; import com.android.server.LocalManagerRegistry; import com.android.server.art.model.ArtFlags; +import com.android.server.art.model.Config; import com.android.server.art.model.DetailedDexInfo; import com.android.server.art.model.DexoptParams; import com.android.server.art.model.DexoptResult; @@ -300,6 +303,8 @@ public abstract class Dexopter<DexInfoType extends DetailedDexInfo> { return results; } + // The javadoc on `AdjustCompilerFilterCallback.onAdjustCompilerFilter` may need updating when + // this method is changed. @NonNull private String adjustCompilerFilter( @NonNull String targetCompilerFilter, @NonNull DexInfoType dexInfo) { @@ -312,6 +317,17 @@ public abstract class Dexopter<DexInfoType extends DetailedDexInfo> { targetCompilerFilter = "speed-profile"; } + Callback<AdjustCompilerFilterCallback, Void> callback = + mInjector.getConfig().getAdjustCompilerFilterCallback(); + if (callback != null) { + // Local variables passed to the lambda must be final or effectively final. + final String originalCompilerFilter = targetCompilerFilter; + targetCompilerFilter = Utils.executeAndWait(callback.executor(), () -> { + return callback.get().onAdjustCompilerFilter( + mPkgState.getPackageName(), originalCompilerFilter, mParams.getReason()); + }); + } + // Code below should only downgrade the compiler filter. Don't upgrade the compiler filter // beyond this point! @@ -688,9 +704,11 @@ public abstract class Dexopter<DexInfoType extends DetailedDexInfo> { @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED) public static class Injector { @NonNull private final Context mContext; + @NonNull private final Config mConfig; - public Injector(@NonNull Context context) { + public Injector(@NonNull Context context, @NonNull Config config) { mContext = context; + mConfig = config; // Call the getters for various dependencies, to ensure correct initialization order. getUserManager(); @@ -747,5 +765,10 @@ public abstract class Dexopter<DexInfoType extends DetailedDexInfo> { } return -1; } + + @NonNull + public Config getConfig() { + return mConfig; + } } } diff --git a/libartservice/service/java/com/android/server/art/DumpHelper.java b/libartservice/service/java/com/android/server/art/DumpHelper.java index 2a640ec48d..d9523b9fae 100644 --- a/libartservice/service/java/com/android/server/art/DumpHelper.java +++ b/libartservice/service/java/com/android/server/art/DumpHelper.java @@ -16,8 +16,8 @@ package com.android.server.art; +import static com.android.server.art.DexUseManagerLocal.CheckedSecondaryDexInfo; import static com.android.server.art.DexUseManagerLocal.DexLoader; -import static com.android.server.art.DexUseManagerLocal.SecondaryDexInfo; import static com.android.server.art.model.DexoptStatus.DexContainerFileDexoptStatus; import android.annotation.NonNull; @@ -99,11 +99,13 @@ public class DumpHelper { mInjector.getArtManagerLocal() .getDexoptStatus(snapshot, packageName) .getDexContainerFileDexoptStatuses(); - Map<String, SecondaryDexInfo> secondaryDexInfoByDexPath = + Map<String, CheckedSecondaryDexInfo> secondaryDexInfoByDexPath = mInjector.getDexUseManager() - .getSecondaryDexInfo(packageName) + .getCheckedSecondaryDexInfo( + packageName, false /* excludeObsoleteDexesAndLoaders */) .stream() - .collect(Collectors.toMap(SecondaryDexInfo::dexPath, Function.identity())); + .collect(Collectors.toMap( + CheckedSecondaryDexInfo::dexPath, Function.identity())); // Use LinkedHashMap to keep the order. They are ordered by their split indexes. var primaryStatusesByDexPath = @@ -157,9 +159,9 @@ public class DumpHelper { private void dumpSecondaryDex(@NonNull IndentingPrintWriter ipw, @NonNull PackageManagerLocal.FilteredSnapshot snapshot, List<DexContainerFileDexoptStatus> fileStatuses, @NonNull String packageName, - @NonNull SecondaryDexInfo info) { + @NonNull CheckedSecondaryDexInfo info) { String dexPath = fileStatuses.get(0).getDexContainerFile(); - @FileVisibility int visibility = getDexFileVisibility(dexPath); + @FileVisibility int visibility = info.fileVisibility(); ipw.println(dexPath + (visibility == FileVisibility.NOT_FOUND ? " (removed)" @@ -236,15 +238,6 @@ public class DumpHelper { return result.toString(); } - private @FileVisibility int getDexFileVisibility(@NonNull String dexPath) { - try { - return mInjector.getArtd().getDexFileVisibility(dexPath); - } catch (ServiceSpecificException | RemoteException e) { - Log.e(TAG, "Failed to get visibility of " + dexPath, e); - return FileVisibility.NOT_FOUND; - } - } - /** Injector pattern for testing purpose. */ @VisibleForTesting public static class Injector { @@ -264,10 +257,5 @@ public class DumpHelper { return Objects.requireNonNull( LocalManagerRegistry.getManager(DexUseManagerLocal.class)); } - - @NonNull - public IArtd getArtd() { - return Utils.getArtd(); - } } } diff --git a/libartservice/service/java/com/android/server/art/PrimaryDexopter.java b/libartservice/service/java/com/android/server/art/PrimaryDexopter.java index c6e64b69e1..38fca5f5f0 100644 --- a/libartservice/service/java/com/android/server/art/PrimaryDexopter.java +++ b/libartservice/service/java/com/android/server/art/PrimaryDexopter.java @@ -38,6 +38,7 @@ import androidx.annotation.RequiresApi; import com.android.internal.annotations.VisibleForTesting; import com.android.modules.utils.pm.PackageStateModulesUtils; import com.android.server.art.model.ArtFlags; +import com.android.server.art.model.Config; import com.android.server.art.model.DexoptParams; import com.android.server.art.model.DexoptResult; import com.android.server.pm.PackageManagerLocal; @@ -59,10 +60,10 @@ public class PrimaryDexopter extends Dexopter<DetailedPrimaryDexInfo> { private final int mSharedGid; - public PrimaryDexopter(@NonNull Context context, @NonNull PackageState pkgState, - @NonNull AndroidPackage pkg, @NonNull DexoptParams params, - @NonNull CancellationSignal cancellationSignal) { - this(new Injector(context), pkgState, pkg, params, cancellationSignal); + public PrimaryDexopter(@NonNull Context context, @NonNull Config config, + @NonNull PackageState pkgState, @NonNull AndroidPackage pkg, + @NonNull DexoptParams params, @NonNull CancellationSignal cancellationSignal) { + this(new Injector(context, config), pkgState, pkg, params, cancellationSignal); } @VisibleForTesting diff --git a/libartservice/service/java/com/android/server/art/SecondaryDexopter.java b/libartservice/service/java/com/android/server/art/SecondaryDexopter.java index 892147de68..2841ee278b 100644 --- a/libartservice/service/java/com/android/server/art/SecondaryDexopter.java +++ b/libartservice/service/java/com/android/server/art/SecondaryDexopter.java @@ -16,7 +16,7 @@ package com.android.server.art; -import static com.android.server.art.DexUseManagerLocal.DetailedSecondaryDexInfo; +import static com.android.server.art.DexUseManagerLocal.CheckedSecondaryDexInfo; import static com.android.server.art.OutputArtifacts.PermissionSettings; import static com.android.server.art.OutputArtifacts.PermissionSettings.SeContext; import static com.android.server.art.Utils.Abi; @@ -30,6 +30,7 @@ import android.os.CancellationSignal; import androidx.annotation.RequiresApi; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.art.model.Config; import com.android.server.art.model.DexoptParams; import com.android.server.pm.pkg.AndroidPackage; import com.android.server.pm.pkg.PackageState; @@ -38,13 +39,13 @@ import java.util.List; /** @hide */ @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) -public class SecondaryDexopter extends Dexopter<DetailedSecondaryDexInfo> { +public class SecondaryDexopter extends Dexopter<CheckedSecondaryDexInfo> { private static final String TAG = ArtManagerLocal.TAG; - public SecondaryDexopter(@NonNull Context context, @NonNull PackageState pkgState, - @NonNull AndroidPackage pkg, @NonNull DexoptParams params, - @NonNull CancellationSignal cancellationSignal) { - this(new Injector(context), pkgState, pkg, params, cancellationSignal); + public SecondaryDexopter(@NonNull Context context, @NonNull Config config, + @NonNull PackageState pkgState, @NonNull AndroidPackage pkg, + @NonNull DexoptParams params, @NonNull CancellationSignal cancellationSignal) { + this(new Injector(context, config), pkgState, pkg, params, cancellationSignal); } @VisibleForTesting @@ -63,29 +64,29 @@ public class SecondaryDexopter extends Dexopter<DetailedSecondaryDexInfo> { @Override @NonNull - protected List<DetailedSecondaryDexInfo> getDexInfoList() { - return mInjector.getDexUseManager().getFilteredDetailedSecondaryDexInfo( - mPkgState.getPackageName()); + protected List<CheckedSecondaryDexInfo> getDexInfoList() { + return mInjector.getDexUseManager().getCheckedSecondaryDexInfo( + mPkgState.getPackageName(), true /* excludeObsoleteDexesAndLoaders */); } @Override - protected boolean isDexoptable(@NonNull DetailedSecondaryDexInfo dexInfo) { + protected boolean isDexoptable(@NonNull CheckedSecondaryDexInfo dexInfo) { return true; } @Override - protected boolean needsToBeShared(@NonNull DetailedSecondaryDexInfo dexInfo) { + protected boolean needsToBeShared(@NonNull CheckedSecondaryDexInfo dexInfo) { return dexInfo.isUsedByOtherApps(); } @Override - protected boolean isDexFilePublic(@NonNull DetailedSecondaryDexInfo dexInfo) { - return dexInfo.isDexFilePublic(); + protected boolean isDexFilePublic(@NonNull CheckedSecondaryDexInfo dexInfo) { + return dexInfo.fileVisibility() == FileVisibility.OTHER_READABLE; } @Override @NonNull - protected List<ProfilePath> getExternalProfiles(@NonNull DetailedSecondaryDexInfo dexInfo) { + protected List<ProfilePath> getExternalProfiles(@NonNull CheckedSecondaryDexInfo dexInfo) { // A secondary dex file doesn't have any external profile to use. return List.of(); } @@ -93,7 +94,7 @@ public class SecondaryDexopter extends Dexopter<DetailedSecondaryDexInfo> { @Override @NonNull protected PermissionSettings getPermissionSettings( - @NonNull DetailedSecondaryDexInfo dexInfo, boolean canBePublic) { + @NonNull CheckedSecondaryDexInfo dexInfo, boolean canBePublic) { int uid = getUid(dexInfo); // We need the "execute" bit for "others" even though `canBePublic` is false because the // directory can contain other artifacts that needs to be public. @@ -109,38 +110,38 @@ public class SecondaryDexopter extends Dexopter<DetailedSecondaryDexInfo> { @Override @NonNull - protected List<Abi> getAllAbis(@NonNull DetailedSecondaryDexInfo dexInfo) { + protected List<Abi> getAllAbis(@NonNull CheckedSecondaryDexInfo dexInfo) { return Utils.getAllAbisForNames(dexInfo.abiNames(), mPkgState); } @Override @NonNull - protected ProfilePath buildRefProfilePath(@NonNull DetailedSecondaryDexInfo dexInfo) { + protected ProfilePath buildRefProfilePath(@NonNull CheckedSecondaryDexInfo dexInfo) { return AidlUtils.buildProfilePathForSecondaryRef(dexInfo.dexPath()); } @Override @NonNull protected OutputProfile buildOutputProfile( - @NonNull DetailedSecondaryDexInfo dexInfo, boolean isPublic) { + @NonNull CheckedSecondaryDexInfo dexInfo, boolean isPublic) { int uid = getUid(dexInfo); return AidlUtils.buildOutputProfileForSecondary(dexInfo.dexPath(), uid, uid, isPublic); } @Override @NonNull - protected List<ProfilePath> getCurProfiles(@NonNull DetailedSecondaryDexInfo dexInfo) { + protected List<ProfilePath> getCurProfiles(@NonNull CheckedSecondaryDexInfo dexInfo) { // A secondary dex file can only be loaded by one user, so there is only one profile. return List.of(AidlUtils.buildProfilePathForSecondaryCur(dexInfo.dexPath())); } @Override @Nullable - protected DexMetadataPath buildDmPath(@NonNull DetailedSecondaryDexInfo dexInfo) { + protected DexMetadataPath buildDmPath(@NonNull CheckedSecondaryDexInfo dexInfo) { return null; } - private int getUid(@NonNull DetailedSecondaryDexInfo dexInfo) { + private int getUid(@NonNull CheckedSecondaryDexInfo dexInfo) { return dexInfo.userHandle().getUid(mPkgState.getAppId()); } } diff --git a/libartservice/service/java/com/android/server/art/Utils.java b/libartservice/service/java/com/android/server/art/Utils.java index 57d57b59b0..82418beb02 100644 --- a/libartservice/service/java/com/android/server/art/Utils.java +++ b/libartservice/service/java/com/android/server/art/Utils.java @@ -65,6 +65,7 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.Future; +import java.util.function.Supplier; import java.util.stream.Collectors; /** @hide */ @@ -274,6 +275,10 @@ public final class Utils { getFuture(CompletableFuture.runAsync(runnable, executor)); } + public static <T> T executeAndWait(@NonNull Executor executor, @NonNull Supplier<T> supplier) { + return getFuture(CompletableFuture.supplyAsync(supplier, executor)); + } + public static <T> T getFuture(Future<T> future) { try { return future.get(); diff --git a/libartservice/service/java/com/android/server/art/model/Config.java b/libartservice/service/java/com/android/server/art/model/Config.java index 49bc9308da..2ea82303aa 100644 --- a/libartservice/service/java/com/android/server/art/model/Config.java +++ b/libartservice/service/java/com/android/server/art/model/Config.java @@ -16,6 +16,7 @@ package com.android.server.art.model; +import static com.android.server.art.ArtManagerLocal.AdjustCompilerFilterCallback; import static com.android.server.art.ArtManagerLocal.BatchDexoptStartCallback; import static com.android.server.art.ArtManagerLocal.DexoptDoneCallback; import static com.android.server.art.ArtManagerLocal.ScheduleBackgroundDexoptJobCallback; @@ -62,6 +63,14 @@ public class Config { private LinkedHashMap<DexoptDoneCallback, Callback<DexoptDoneCallback, Boolean>> mDexoptDoneCallbacks = new LinkedHashMap<>(); + /** + * @see ArtManagerLocal#setAdjustCompilerFilterCallback(Executor, + * AdjustCompilerFilterCallback) + */ + @GuardedBy("this") + @Nullable + private Callback<AdjustCompilerFilterCallback, Void> mAdjustCompilerFilterCallback = null; + public synchronized void setBatchDexoptStartCallback( @NonNull Executor executor, @NonNull BatchDexoptStartCallback callback) { mBatchDexoptStartCallback = Callback.create(callback, executor); @@ -109,6 +118,21 @@ public class Config { return new ArrayList<>(mDexoptDoneCallbacks.values()); } + public synchronized void setAdjustCompilerFilterCallback( + @NonNull Executor executor, @NonNull AdjustCompilerFilterCallback callback) { + mAdjustCompilerFilterCallback = Callback.create(callback, executor); + } + + public synchronized void clearAdjustCompilerFilterCallback() { + mAdjustCompilerFilterCallback = null; + } + + @Nullable + public synchronized Callback<AdjustCompilerFilterCallback, Void> + getAdjustCompilerFilterCallback() { + return mAdjustCompilerFilterCallback; + } + @AutoValue public static abstract class Callback<CallbackType, ExtraType> { public abstract @NonNull CallbackType get(); diff --git a/libartservice/service/javatests/com/android/server/art/ArtManagerLocalTest.java b/libartservice/service/javatests/com/android/server/art/ArtManagerLocalTest.java index 94fbdaccd9..6e78de9127 100644 --- a/libartservice/service/javatests/com/android/server/art/ArtManagerLocalTest.java +++ b/libartservice/service/javatests/com/android/server/art/ArtManagerLocalTest.java @@ -18,7 +18,7 @@ package com.android.server.art; import static android.os.ParcelFileDescriptor.AutoCloseInputStream; -import static com.android.server.art.DexUseManagerLocal.DetailedSecondaryDexInfo; +import static com.android.server.art.DexUseManagerLocal.CheckedSecondaryDexInfo; import static com.android.server.art.model.DexoptResult.DexContainerFileDexoptResult; import static com.android.server.art.model.DexoptResult.PackageDexoptResult; import static com.android.server.art.model.DexoptStatus.DexContainerFileDexoptStatus; @@ -129,8 +129,8 @@ public class ArtManagerLocalTest { @Mock private StorageManager mStorageManager; private PackageState mPkgState1; private AndroidPackage mPkg1; - private DetailedSecondaryDexInfo mPkg1SecondaryDexInfo1; - private DetailedSecondaryDexInfo mPkg1SecondaryDexInfoNotFound; + private CheckedSecondaryDexInfo mPkg1SecondaryDexInfo1; + private CheckedSecondaryDexInfo mPkg1SecondaryDexInfoNotFound; private Config mConfig; // True if the artifacts should be in dalvik-cache. @@ -218,9 +218,15 @@ public class ArtManagerLocalTest { .when(mDexUseManager) .getSecondaryDexInfo(eq(PKG_NAME_1)); lenient() + .doReturn(List.of(mPkg1SecondaryDexInfo1, mPkg1SecondaryDexInfoNotFound)) + .when(mDexUseManager) + .getCheckedSecondaryDexInfo( + eq(PKG_NAME_1), eq(false) /* excludeObsoleteDexesAndLoaders */); + lenient() .doReturn(List.of(mPkg1SecondaryDexInfo1)) .when(mDexUseManager) - .getFilteredDetailedSecondaryDexInfo(eq(PKG_NAME_1)); + .getCheckedSecondaryDexInfo( + eq(PKG_NAME_1), eq(true) /* excludeObsoleteDexesAndLoaders */); simulateStorageNotLow(); @@ -1283,8 +1289,8 @@ public class ArtManagerLocalTest { return getDexoptStatusResult; } - private DetailedSecondaryDexInfo createSecondaryDexInfo(String dexPath) throws Exception { - var dexInfo = mock(DetailedSecondaryDexInfo.class); + private CheckedSecondaryDexInfo createSecondaryDexInfo(String dexPath) throws Exception { + var dexInfo = mock(CheckedSecondaryDexInfo.class); lenient().when(dexInfo.dexPath()).thenReturn(dexPath); lenient().when(dexInfo.abiNames()).thenReturn(Set.of("arm64-v8a")); lenient().when(dexInfo.classLoaderContext()).thenReturn("CLC"); diff --git a/libartservice/service/javatests/com/android/server/art/DexUseManagerTest.java b/libartservice/service/javatests/com/android/server/art/DexUseManagerTest.java index c8ece398b9..5662090aeb 100644 --- a/libartservice/service/javatests/com/android/server/art/DexUseManagerTest.java +++ b/libartservice/service/javatests/com/android/server/art/DexUseManagerTest.java @@ -16,7 +16,7 @@ package com.android.server.art; -import static com.android.server.art.DexUseManagerLocal.DetailedSecondaryDexInfo; +import static com.android.server.art.DexUseManagerLocal.CheckedSecondaryDexInfo; import static com.android.server.art.DexUseManagerLocal.DexLoader; import static com.android.server.art.DexUseManagerLocal.SecondaryDexInfo; @@ -87,11 +87,11 @@ public class DexUseManagerTest { private final UserHandle mUserHandle = Binder.getCallingUserHandle(); /** - * The default value of `isDexFilePublic` returned by `getSecondaryDexInfo`. The value doesn't + * The default value of `fileVisibility` returned by `getSecondaryDexInfo`. The value doesn't * matter because it's undefined, but it's needed for deep equality check, to make the test * simpler. */ - private final boolean mDefaultIsDexFilePublic = true; + private final @FileVisibility int mDefaultFileVisibility = FileVisibility.OTHER_READABLE; @Mock private PackageManagerLocal.FilteredSnapshot mSnapshot; @Mock private DexUseManagerLocal.Injector mInjector; @@ -325,10 +325,10 @@ public class DexUseManagerTest { List<? extends SecondaryDexInfo> dexInfoList = mDexUseManager.getSecondaryDexInfo(OWNING_PKG_NAME); assertThat(dexInfoList) - .containsExactly(DetailedSecondaryDexInfo.create(mCeDir + "/foo.apk", mUserHandle, + .containsExactly(CheckedSecondaryDexInfo.create(mCeDir + "/foo.apk", mUserHandle, "CLC", Set.of("arm64-v8a"), Set.of(DexLoader.create(OWNING_PKG_NAME, false /* isolatedProcess */)), - false /* isUsedByOtherApps */, mDefaultIsDexFilePublic)); + false /* isUsedByOtherApps */, FileVisibility.OTHER_READABLE)); assertThat(dexInfoList.get(0).classLoaderContext()).isEqualTo("CLC"); } @@ -341,10 +341,10 @@ public class DexUseManagerTest { List<? extends SecondaryDexInfo> dexInfoList = mDexUseManager.getSecondaryDexInfo(OWNING_PKG_NAME); assertThat(dexInfoList) - .containsExactly(DetailedSecondaryDexInfo.create(mDeDir + "/foo.apk", mUserHandle, + .containsExactly(CheckedSecondaryDexInfo.create(mDeDir + "/foo.apk", mUserHandle, "CLC", Set.of("arm64-v8a"), Set.of(DexLoader.create(OWNING_PKG_NAME, true /* isolatedProcess */)), - true /* isUsedByOtherApps */, mDefaultIsDexFilePublic)); + true /* isUsedByOtherApps */, FileVisibility.OTHER_READABLE)); assertThat(dexInfoList.get(0).classLoaderContext()).isEqualTo("CLC"); } @@ -356,10 +356,10 @@ public class DexUseManagerTest { List<? extends SecondaryDexInfo> dexInfoList = mDexUseManager.getSecondaryDexInfo(OWNING_PKG_NAME); assertThat(dexInfoList) - .containsExactly(DetailedSecondaryDexInfo.create(mCeDir + "/foo.apk", mUserHandle, + .containsExactly(CheckedSecondaryDexInfo.create(mCeDir + "/foo.apk", mUserHandle, "CLC", Set.of("armeabi-v7a"), Set.of(DexLoader.create(LOADING_PKG_NAME, false /* isolatedProcess */)), - true /* isUsedByOtherApps */, mDefaultIsDexFilePublic)); + true /* isUsedByOtherApps */, FileVisibility.OTHER_READABLE)); assertThat(dexInfoList.get(0).classLoaderContext()).isEqualTo("CLC"); } @@ -371,10 +371,10 @@ public class DexUseManagerTest { List<? extends SecondaryDexInfo> dexInfoList = mDexUseManager.getSecondaryDexInfo(OWNING_PKG_NAME); assertThat(dexInfoList) - .containsExactly(DetailedSecondaryDexInfo.create(mCeDir + "/foo.apk", mUserHandle, + .containsExactly(CheckedSecondaryDexInfo.create(mCeDir + "/foo.apk", mUserHandle, SecondaryDexInfo.UNSUPPORTED_CLASS_LOADER_CONTEXT, Set.of("armeabi-v7a"), Set.of(DexLoader.create(LOADING_PKG_NAME, false /* isolatedProcess */)), - true /* isUsedByOtherApps */, mDefaultIsDexFilePublic)); + true /* isUsedByOtherApps */, FileVisibility.OTHER_READABLE)); assertThat(dexInfoList.get(0).classLoaderContext()).isNull(); } @@ -388,12 +388,12 @@ public class DexUseManagerTest { List<? extends SecondaryDexInfo> dexInfoList = mDexUseManager.getSecondaryDexInfo(OWNING_PKG_NAME); assertThat(dexInfoList) - .containsExactly(DetailedSecondaryDexInfo.create(mCeDir + "/foo.apk", mUserHandle, + .containsExactly(CheckedSecondaryDexInfo.create(mCeDir + "/foo.apk", mUserHandle, SecondaryDexInfo.VARYING_CLASS_LOADER_CONTEXTS, Set.of("arm64-v8a", "armeabi-v7a"), Set.of(DexLoader.create(OWNING_PKG_NAME, false /* isolatedProcess */), DexLoader.create(LOADING_PKG_NAME, false /* isolatedProcess */)), - true /* isUsedByOtherApps */, mDefaultIsDexFilePublic)); + true /* isUsedByOtherApps */, FileVisibility.OTHER_READABLE)); assertThat(dexInfoList.get(0).classLoaderContext()).isNull(); } @@ -489,7 +489,7 @@ public class DexUseManagerTest { List<? extends SecondaryDexInfo> dexInfoList = mDexUseManager.getSecondaryDexInfo(OWNING_PKG_NAME); assertThat(dexInfoList) - .containsExactly(DetailedSecondaryDexInfo.create(mCeDir + "/foo.apk", mUserHandle, + .containsExactly(CheckedSecondaryDexInfo.create(mCeDir + "/foo.apk", mUserHandle, "UpdatedCLC", Set.of("arm64-v8a", "armeabi-v7a"), Set.of(DexLoader.create(OWNING_PKG_NAME, false /* isolatedProcess */), @@ -497,21 +497,21 @@ public class DexUseManagerTest { true /* isolatedProcess */), DexLoader.create(LOADING_PKG_NAME, false /* isolatedProcess */)), - true /* isUsedByOtherApps */, mDefaultIsDexFilePublic), - DetailedSecondaryDexInfo.create(mCeDir + "/bar.apk", mUserHandle, + true /* isUsedByOtherApps */, mDefaultFileVisibility), + CheckedSecondaryDexInfo.create(mCeDir + "/bar.apk", mUserHandle, SecondaryDexInfo.VARYING_CLASS_LOADER_CONTEXTS, Set.of("arm64-v8a", "armeabi-v7a"), Set.of(DexLoader.create( OWNING_PKG_NAME, false /* isolatedProcess */), DexLoader.create( LOADING_PKG_NAME, false /* isolatedProcess */)), - true /* isUsedByOtherApps */, mDefaultIsDexFilePublic), - DetailedSecondaryDexInfo.create(mCeDir + "/baz.apk", mUserHandle, + true /* isUsedByOtherApps */, mDefaultFileVisibility), + CheckedSecondaryDexInfo.create(mCeDir + "/baz.apk", mUserHandle, SecondaryDexInfo.UNSUPPORTED_CLASS_LOADER_CONTEXT, Set.of("arm64-v8a"), Set.of(DexLoader.create( OWNING_PKG_NAME, false /* isolatedProcess */)), - false /* isUsedByOtherApps */, mDefaultIsDexFilePublic)); + false /* isUsedByOtherApps */, mDefaultFileVisibility)); assertThat(mDexUseManager.getSecondaryDexContainerFileUseInfo(OWNING_PKG_NAME)) .containsExactly(DexContainerFileUseInfo.create(mCeDir + "/foo.apk", mUserHandle, @@ -525,7 +525,7 @@ public class DexUseManagerTest { } @Test - public void testFilteredDetailedSecondaryDexPublic() throws Exception { + public void testCheckedSecondaryDexPublic() throws Exception { when(mArtd.getDexFileVisibility(mCeDir + "/foo.apk")) .thenReturn(FileVisibility.OTHER_READABLE); @@ -534,16 +534,17 @@ public class DexUseManagerTest { mDexUseManager.notifyDexContainersLoaded( mSnapshot, LOADING_PKG_NAME, Map.of(mCeDir + "/foo.apk", "CLC")); - assertThat(mDexUseManager.getFilteredDetailedSecondaryDexInfo(OWNING_PKG_NAME)) - .containsExactly(DetailedSecondaryDexInfo.create(mCeDir + "/foo.apk", mUserHandle, + assertThat(mDexUseManager.getCheckedSecondaryDexInfo( + OWNING_PKG_NAME, true /* excludeObsoleteDexesAndLoaders */)) + .containsExactly(CheckedSecondaryDexInfo.create(mCeDir + "/foo.apk", mUserHandle, "CLC", Set.of("arm64-v8a", "armeabi-v7a"), Set.of(DexLoader.create(OWNING_PKG_NAME, false /* isolatedProcess */), DexLoader.create(LOADING_PKG_NAME, false /* isolatedProcess */)), - true /* isUsedByOtherApps */, true /* isDexFilePublic */)); + true /* isUsedByOtherApps */, FileVisibility.OTHER_READABLE)); } @Test - public void testFilteredDetailedSecondaryDexPrivate() throws Exception { + public void testCheckedSecondaryDexPrivate() throws Exception { when(mArtd.getDexFileVisibility(mCeDir + "/foo.apk")) .thenReturn(FileVisibility.NOT_OTHER_READABLE); @@ -556,36 +557,57 @@ public class DexUseManagerTest { mDexUseManager.notifyDexContainersLoaded( mSnapshot, OWNING_PKG_NAME, Map.of(mCeDir + "/foo.apk", "CLC")); - assertThat(mDexUseManager.getFilteredDetailedSecondaryDexInfo(OWNING_PKG_NAME)) - .containsExactly(DetailedSecondaryDexInfo.create(mCeDir + "/foo.apk", mUserHandle, + assertThat(mDexUseManager.getCheckedSecondaryDexInfo( + OWNING_PKG_NAME, true /* excludeObsoleteDexesAndLoaders */)) + .containsExactly(CheckedSecondaryDexInfo.create(mCeDir + "/foo.apk", mUserHandle, "CLC", Set.of("arm64-v8a"), Set.of(DexLoader.create(OWNING_PKG_NAME, false /* isolatedProcess */)), - false /* isUsedByOtherApps */, false /* isDexFilePublic */)); + false /* isUsedByOtherApps */, FileVisibility.NOT_OTHER_READABLE)); + + assertThat(mDexUseManager.getCheckedSecondaryDexInfo( + OWNING_PKG_NAME, false /* excludeObsoleteDexesAndLoaders */)) + .containsExactly(CheckedSecondaryDexInfo.create(mCeDir + "/foo.apk", mUserHandle, + "CLC", Set.of("arm64-v8a", "armeabi-v7a"), + Set.of(DexLoader.create(OWNING_PKG_NAME, false /* isolatedProcess */), + DexLoader.create(LOADING_PKG_NAME, false /* isolatedProcess */), + DexLoader.create(OWNING_PKG_NAME, true /* isolatedProcess */)), + true /* isUsedByOtherApps */, FileVisibility.NOT_OTHER_READABLE)); } @Test - public void testFilteredDetailedSecondaryDexFilteredDueToVisibility() throws Exception { - when(mArtd.getDexFileVisibility(mCeDir + "/foo.apk")) - .thenReturn(FileVisibility.NOT_OTHER_READABLE); - - mDexUseManager.notifyDexContainersLoaded( - mSnapshot, LOADING_PKG_NAME, Map.of(mCeDir + "/foo.apk", "CLC")); + public void testCheckedSecondaryDexNotFound() throws Exception { + when(mArtd.getDexFileVisibility(mCeDir + "/foo.apk")).thenReturn(FileVisibility.NOT_FOUND); - when(Process.isIsolatedUid(anyInt())).thenReturn(true); mDexUseManager.notifyDexContainersLoaded( mSnapshot, OWNING_PKG_NAME, Map.of(mCeDir + "/foo.apk", "CLC")); - assertThat(mDexUseManager.getFilteredDetailedSecondaryDexInfo(OWNING_PKG_NAME)).isEmpty(); + assertThat(mDexUseManager.getCheckedSecondaryDexInfo( + OWNING_PKG_NAME, true /* excludeObsoleteDexesAndLoaders */)) + .isEmpty(); + + assertThat(mDexUseManager.getCheckedSecondaryDexInfo( + OWNING_PKG_NAME, false /* excludeObsoleteDexesAndLoaders */)) + .containsExactly(CheckedSecondaryDexInfo.create(mCeDir + "/foo.apk", mUserHandle, + "CLC", Set.of("arm64-v8a"), + Set.of(DexLoader.create(OWNING_PKG_NAME, false /* isolatedProcess */)), + false /* isUsedByOtherApps */, FileVisibility.NOT_FOUND)); } @Test - public void testFilteredDetailedSecondaryDexFilteredDueToNotFound() throws Exception { - when(mArtd.getDexFileVisibility(mCeDir + "/foo.apk")).thenReturn(FileVisibility.NOT_FOUND); + public void testCheckedSecondaryDexFilteredDueToVisibility() throws Exception { + when(mArtd.getDexFileVisibility(mCeDir + "/foo.apk")) + .thenReturn(FileVisibility.NOT_OTHER_READABLE); mDexUseManager.notifyDexContainersLoaded( + mSnapshot, LOADING_PKG_NAME, Map.of(mCeDir + "/foo.apk", "CLC")); + + when(Process.isIsolatedUid(anyInt())).thenReturn(true); + mDexUseManager.notifyDexContainersLoaded( mSnapshot, OWNING_PKG_NAME, Map.of(mCeDir + "/foo.apk", "CLC")); - assertThat(mDexUseManager.getFilteredDetailedSecondaryDexInfo(OWNING_PKG_NAME)).isEmpty(); + assertThat(mDexUseManager.getCheckedSecondaryDexInfo( + OWNING_PKG_NAME, true /* excludeObsoleteDexesAndLoaders */)) + .isEmpty(); } @Test @@ -746,10 +768,10 @@ public class DexUseManagerTest { mSnapshot, LOADING_PKG_NAME, Map.of(mCeDir + "/foo.apk", "CLC")); assertThat(mDexUseManager.getSecondaryDexInfo(OWNING_PKG_NAME)) - .containsExactly(DetailedSecondaryDexInfo.create(mCeDir + "/foo.apk", mUserHandle, + .containsExactly(CheckedSecondaryDexInfo.create(mCeDir + "/foo.apk", mUserHandle, "CLC", Set.of("armeabi-v7a"), Set.of(DexLoader.create(LOADING_PKG_NAME, false /* isolatedProcess */)), - true /* isUsedByOtherApps */, mDefaultIsDexFilePublic)); + true /* isUsedByOtherApps */, mDefaultFileVisibility)); } private AndroidPackage createPackage(String packageName) { diff --git a/libartservice/service/javatests/com/android/server/art/DumpHelperTest.java b/libartservice/service/javatests/com/android/server/art/DumpHelperTest.java index 694bba7136..be2887d20f 100644 --- a/libartservice/service/javatests/com/android/server/art/DumpHelperTest.java +++ b/libartservice/service/javatests/com/android/server/art/DumpHelperTest.java @@ -16,6 +16,7 @@ package com.android.server.art; +import static com.android.server.art.DexUseManagerLocal.CheckedSecondaryDexInfo; import static com.android.server.art.DexUseManagerLocal.DexLoader; import static com.android.server.art.DexUseManagerLocal.SecondaryDexInfo; import static com.android.server.art.model.DexoptStatus.DexContainerFileDexoptStatus; @@ -68,7 +69,6 @@ public class DumpHelperTest { @Mock private ArtManagerLocal mArtManagerLocal; @Mock private DexUseManagerLocal mDexUseManagerLocal; @Mock private PackageManagerLocal.FilteredSnapshot mSnapshot; - @Mock private IArtd mArtd; private DumpHelper mDumpHelper; @@ -85,7 +85,6 @@ public class DumpHelperTest { lenient().when(mInjector.getArtManagerLocal()).thenReturn(mArtManagerLocal); lenient().when(mInjector.getDexUseManager()).thenReturn(mDexUseManagerLocal); - lenient().when(mInjector.getArtd()).thenReturn(mArtd); Map<String, PackageState> pkgStates = createPackageStates(); lenient().when(mSnapshot.getPackageStates()).thenReturn(pkgStates); @@ -214,7 +213,7 @@ public class DumpHelperTest { .thenReturn(Set.of(DexLoader.create(PKG_NAME_FOO, false /* isolatedProcess */), DexLoader.create(PKG_NAME_BAR, false /* isolatedProcess */))); - var info1 = mock(SecondaryDexInfo.class); + var info1 = mock(CheckedSecondaryDexInfo.class); lenient().when(info1.dexPath()).thenReturn("/data/user_de/0/foo/1.apk"); lenient() .when(info1.displayClassLoaderContext()) @@ -239,11 +238,9 @@ public class DumpHelperTest { lenient().when(info1.loaders()).thenReturn(loaders); // The output should show the dex path with "(removed)". - lenient() - .when(mArtd.getDexFileVisibility("/data/user_de/0/foo/1.apk")) - .thenReturn(FileVisibility.NOT_FOUND); + lenient().when(info1.fileVisibility()).thenReturn(FileVisibility.NOT_FOUND); - var info2 = mock(SecondaryDexInfo.class); + var info2 = mock(CheckedSecondaryDexInfo.class); lenient().when(info2.dexPath()).thenReturn("/data/user_de/0/foo/2.apk"); lenient().when(info2.displayClassLoaderContext()).thenReturn("PCL[]"); lenient() @@ -255,14 +252,13 @@ public class DumpHelperTest { lenient() .when(info2.loaders()) .thenReturn(Set.of(DexLoader.create(PKG_NAME_FOO, false /* isolatedProcess */))); - lenient() - .when(mArtd.getDexFileVisibility("/data/user_de/0/foo/2.apk")) - .thenReturn(FileVisibility.OTHER_READABLE); + lenient().when(info2.fileVisibility()).thenReturn(FileVisibility.OTHER_READABLE); lenient() .doReturn(List.of(info1, info2)) .when(mDexUseManagerLocal) - .getSecondaryDexInfo(PKG_NAME_FOO); + .getCheckedSecondaryDexInfo( + PKG_NAME_FOO, false /* excludeObsoleteDexesAndLoaders */); } private void setUpForBar() { diff --git a/libartservice/service/javatests/com/android/server/art/PrimaryDexopterParameterizedTest.java b/libartservice/service/javatests/com/android/server/art/PrimaryDexopterParameterizedTest.java index efe567fe0e..b9b8bd31e4 100644 --- a/libartservice/service/javatests/com/android/server/art/PrimaryDexopterParameterizedTest.java +++ b/libartservice/service/javatests/com/android/server/art/PrimaryDexopterParameterizedTest.java @@ -168,6 +168,32 @@ public class PrimaryDexopterParameterizedTest extends PrimaryDexopterTestBase { params.mExpectedCompilerFilter = "speed"; list.add(params); + // It respects the adjustment made by the callback. + params = new Params(); + params.mRequestedCompilerFilter = "speed-profile"; + params.mExpectedCallbackInputCompilerFilter = "speed-profile"; + params.mCallbackReturnedCompilerFilter = "speed"; + params.mExpectedCompilerFilter = "speed"; + list.add(params); + + // It upgrades the compiler filter before calling the callback. + params = new Params(); + params.mRequestedCompilerFilter = "speed-profile"; + params.mIsSystemUi = true; + params.mExpectedCallbackInputCompilerFilter = "speed"; + params.mCallbackReturnedCompilerFilter = "speed"; + params.mExpectedCompilerFilter = "speed"; + list.add(params); + + // It downgrades the compiler filter after calling the callback. + params = new Params(); + params.mRequestedCompilerFilter = "speed-profile"; + params.mExpectedCallbackInputCompilerFilter = "speed-profile"; + params.mCallbackReturnedCompilerFilter = "speed-profile"; + params.mIsUseEmbeddedDex = true; + params.mExpectedCompilerFilter = "verify"; + list.add(params); + return list; } @@ -198,6 +224,17 @@ public class PrimaryDexopterParameterizedTest extends PrimaryDexopterTestBase { lenient().when(mArtd.isInDalvikCache(any())).thenReturn(mParams.mIsInDalvikCache); + if (mParams.mCallbackReturnedCompilerFilter != null) { + mConfig.setAdjustCompilerFilterCallback( + Runnable::run, (packageName, originalCompilerFilter, reason) -> { + assertThat(packageName).isEqualTo(PKG_NAME); + assertThat(originalCompilerFilter) + .isEqualTo(mParams.mExpectedCallbackInputCompilerFilter); + assertThat(reason).isEqualTo("install"); + return mParams.mCallbackReturnedCompilerFilter; + }); + } + mDexoptParams = new DexoptParams.Builder("install") .setCompilerFilter(mParams.mRequestedCompilerFilter) @@ -334,6 +371,7 @@ public class PrimaryDexopterParameterizedTest extends PrimaryDexopterTestBase { // Options. public String mRequestedCompilerFilter = "verify"; + public String mCallbackReturnedCompilerFilter = null; public boolean mForce = false; public boolean mShouldDowngrade = false; public boolean mSkipIfStorageLow = false; @@ -343,6 +381,7 @@ public class PrimaryDexopterParameterizedTest extends PrimaryDexopterTestBase { public boolean mAlwaysDebuggable = false; // Expectations. + public String mExpectedCallbackInputCompilerFilter = "verify"; public String mExpectedCompilerFilter = "verify"; public int mExpectedDexoptTrigger = DexoptTrigger.COMPILER_FILTER_IS_BETTER | DexoptTrigger.PRIMARY_BOOT_IMAGE_BECOMES_USABLE | DexoptTrigger.NEED_EXTRACTION; @@ -358,19 +397,22 @@ public class PrimaryDexopterParameterizedTest extends PrimaryDexopterTestBase { + "isLauncher=%b," + "isUseEmbeddedDex=%b," + "requestedCompilerFilter=%s," + + "callbackReturnedCompilerFilter=%s," + "force=%b," + "shouldDowngrade=%b," + "skipIfStorageLow=%b," + "ignoreProfile=%b," + "alwaysDebuggable=%b" + " => " - + "targetCompilerFilter=%s," + + "expectedCallbackInputCompilerFilter=%s," + + "expectedCompilerFilter=%s," + "expectedDexoptTrigger=%d," + "expectedIsDebuggable=%b," + "expectedIsHiddenApiPolicyEnabled=%b", mIsInDalvikCache, mHiddenApiEnforcementPolicy, mIsVmSafeMode, mIsDebuggable, - mIsSystemUi, mIsLauncher, mIsUseEmbeddedDex, mRequestedCompilerFilter, mForce, - mShouldDowngrade, mSkipIfStorageLow, mIgnoreProfile, mAlwaysDebuggable, + mIsSystemUi, mIsLauncher, mIsUseEmbeddedDex, mRequestedCompilerFilter, + mCallbackReturnedCompilerFilter, mForce, mShouldDowngrade, mSkipIfStorageLow, + mIgnoreProfile, mAlwaysDebuggable, mExpectedCallbackInputCompilerFilter, mExpectedCompilerFilter, mExpectedDexoptTrigger, mExpectedIsDebuggable, mExpectedIsHiddenApiPolicyEnabled); } diff --git a/libartservice/service/javatests/com/android/server/art/PrimaryDexopterTestBase.java b/libartservice/service/javatests/com/android/server/art/PrimaryDexopterTestBase.java index 60b64262e5..7a8287fe4c 100644 --- a/libartservice/service/javatests/com/android/server/art/PrimaryDexopterTestBase.java +++ b/libartservice/service/javatests/com/android/server/art/PrimaryDexopterTestBase.java @@ -31,6 +31,7 @@ import android.os.UserManager; import android.os.storage.StorageManager; import com.android.modules.utils.pm.PackageStateModulesUtils; +import com.android.server.art.model.Config; import com.android.server.art.testing.StaticMockitoRule; import com.android.server.pm.pkg.AndroidPackage; import com.android.server.pm.pkg.AndroidPackageSplit; @@ -68,9 +69,17 @@ public class PrimaryDexopterTestBase { protected PackageUserState mPkgUserStateNotInstalled; protected PackageUserState mPkgUserStateInstalled; protected CancellationSignal mCancellationSignal; + protected Config mConfig; @Before public void setUp() throws Exception { + mPkgUserStateNotInstalled = createPackageUserState(false /* installed */); + mPkgUserStateInstalled = createPackageUserState(true /* installed */); + mPkgState = createPackageState(); + mPkg = mPkgState.getAndroidPackage(); + mCancellationSignal = new CancellationSignal(); + mConfig = new Config(); + lenient().when(mInjector.getArtd()).thenReturn(mArtd); lenient().when(mInjector.isSystemUiPackage(any())).thenReturn(false); lenient().when(mInjector.isLauncherPackage(any())).thenReturn(false); @@ -78,6 +87,7 @@ public class PrimaryDexopterTestBase { lenient().when(mInjector.getDexUseManager()).thenReturn(mDexUseManager); lenient().when(mInjector.getStorageManager()).thenReturn(mStorageManager); lenient().when(mInjector.getArtVersion()).thenReturn(ART_VERSION); + lenient().when(mInjector.getConfig()).thenReturn(mConfig); lenient() .when(SystemProperties.get("dalvik.vm.systemuicompilerfilter")) @@ -104,12 +114,6 @@ public class PrimaryDexopterTestBase { lenient().when(mDexUseManager.isPrimaryDexUsedByOtherApps(any(), any())).thenReturn(false); lenient().when(mStorageManager.getAllocatableBytes(any())).thenReturn(1l); - - mPkgUserStateNotInstalled = createPackageUserState(false /* installed */); - mPkgUserStateInstalled = createPackageUserState(true /* installed */); - mPkgState = createPackageState(); - mPkg = mPkgState.getAndroidPackage(); - mCancellationSignal = new CancellationSignal(); } private AndroidPackage createPackage() { diff --git a/libartservice/service/javatests/com/android/server/art/SecondaryDexopterTest.java b/libartservice/service/javatests/com/android/server/art/SecondaryDexopterTest.java index 3ef256c08d..f80503d09b 100644 --- a/libartservice/service/javatests/com/android/server/art/SecondaryDexopterTest.java +++ b/libartservice/service/javatests/com/android/server/art/SecondaryDexopterTest.java @@ -16,7 +16,7 @@ package com.android.server.art; -import static com.android.server.art.DexUseManagerLocal.DetailedSecondaryDexInfo; +import static com.android.server.art.DexUseManagerLocal.CheckedSecondaryDexInfo; import static com.android.server.art.OutputArtifacts.PermissionSettings; import static com.android.server.art.model.DexoptResult.DexContainerFileDexoptResult; import static com.android.server.art.testing.TestingUtils.deepEq; @@ -43,6 +43,7 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.server.art.model.ArtFlags; +import com.android.server.art.model.Config; import com.android.server.art.model.DexoptParams; import com.android.server.art.model.DexoptResult; import com.android.server.art.testing.StaticMockitoRule; @@ -105,11 +106,17 @@ public class SecondaryDexopterTest { private PackageState mPkgState; private AndroidPackage mPkg; private CancellationSignal mCancellationSignal; + protected Config mConfig; private SecondaryDexopter mSecondaryDexopter; @Before public void setUp() throws Exception { + mPkgState = createPackageState(); + mPkg = mPkgState.getAndroidPackage(); + mCancellationSignal = new CancellationSignal(); + mConfig = new Config(); + lenient() .when(SystemProperties.getBoolean(eq("dalvik.vm.always_debuggable"), anyBoolean())) .thenReturn(false); @@ -129,16 +136,14 @@ public class SecondaryDexopterTest { lenient().when(mInjector.isSystemUiPackage(any())).thenReturn(false); lenient().when(mInjector.isLauncherPackage(any())).thenReturn(false); lenient().when(mInjector.getDexUseManager()).thenReturn(mDexUseManager); + lenient().when(mInjector.getConfig()).thenReturn(mConfig); - List<DetailedSecondaryDexInfo> secondaryDexInfo = createSecondaryDexInfo(); + List<CheckedSecondaryDexInfo> secondaryDexInfo = createSecondaryDexInfo(); lenient() - .when(mDexUseManager.getFilteredDetailedSecondaryDexInfo(eq(PKG_NAME))) + .when(mDexUseManager.getCheckedSecondaryDexInfo( + eq(PKG_NAME), eq(true) /* excludeObsoleteDexesAndLoaders */)) .thenReturn(secondaryDexInfo); - mPkgState = createPackageState(); - mPkg = mPkgState.getAndroidPackage(); - mCancellationSignal = new CancellationSignal(); - prepareProfiles(); // Dexopt is always needed and successful. @@ -235,33 +240,33 @@ public class SecondaryDexopterTest { return pkgState; } - private List<DetailedSecondaryDexInfo> createSecondaryDexInfo() throws Exception { + private List<CheckedSecondaryDexInfo> createSecondaryDexInfo() throws Exception { // This should be compiled with profile. - var dex1Info = mock(DetailedSecondaryDexInfo.class); + var dex1Info = mock(CheckedSecondaryDexInfo.class); lenient().when(dex1Info.dexPath()).thenReturn(DEX_1); lenient().when(dex1Info.userHandle()).thenReturn(USER_HANDLE); lenient().when(dex1Info.classLoaderContext()).thenReturn("CLC_FOR_DEX_1"); lenient().when(dex1Info.abiNames()).thenReturn(Set.of("arm64-v8a")); lenient().when(dex1Info.isUsedByOtherApps()).thenReturn(false); - lenient().when(dex1Info.isDexFilePublic()).thenReturn(true); + lenient().when(dex1Info.fileVisibility()).thenReturn(FileVisibility.OTHER_READABLE); // This should be compiled without profile because it's used by other apps. - var dex2Info = mock(DetailedSecondaryDexInfo.class); + var dex2Info = mock(CheckedSecondaryDexInfo.class); lenient().when(dex2Info.dexPath()).thenReturn(DEX_2); lenient().when(dex2Info.userHandle()).thenReturn(USER_HANDLE); lenient().when(dex2Info.classLoaderContext()).thenReturn("CLC_FOR_DEX_2"); lenient().when(dex2Info.abiNames()).thenReturn(Set.of("arm64-v8a", "armeabi-v7a")); lenient().when(dex2Info.isUsedByOtherApps()).thenReturn(true); - lenient().when(dex2Info.isDexFilePublic()).thenReturn(true); + lenient().when(dex2Info.fileVisibility()).thenReturn(FileVisibility.OTHER_READABLE); // This should be compiled with verify because the class loader context is invalid. - var dex3Info = mock(DetailedSecondaryDexInfo.class); + var dex3Info = mock(CheckedSecondaryDexInfo.class); lenient().when(dex3Info.dexPath()).thenReturn(DEX_3); lenient().when(dex3Info.userHandle()).thenReturn(USER_HANDLE); lenient().when(dex3Info.classLoaderContext()).thenReturn(null); lenient().when(dex3Info.abiNames()).thenReturn(Set.of("arm64-v8a")); lenient().when(dex3Info.isUsedByOtherApps()).thenReturn(false); - lenient().when(dex3Info.isDexFilePublic()).thenReturn(false); + lenient().when(dex3Info.fileVisibility()).thenReturn(FileVisibility.NOT_OTHER_READABLE); return List.of(dex1Info, dex2Info, dex3Info); } diff --git a/runtime/aot_class_linker.cc b/runtime/aot_class_linker.cc index 9b2e8767ef..dfdc3d73c5 100644 --- a/runtime/aot_class_linker.cc +++ b/runtime/aot_class_linker.cc @@ -25,7 +25,7 @@ #include "runtime.h" #include "verifier/verifier_enums.h" -namespace art { +namespace art HIDDEN { AotClassLinker::AotClassLinker(InternTable* intern_table) : ClassLinker(intern_table, /*fast_class_not_found_exceptions=*/ false) {} diff --git a/runtime/aot_class_linker.h b/runtime/aot_class_linker.h index be4ab2b938..1cf91636bb 100644 --- a/runtime/aot_class_linker.h +++ b/runtime/aot_class_linker.h @@ -17,10 +17,11 @@ #ifndef ART_RUNTIME_AOT_CLASS_LINKER_H_ #define ART_RUNTIME_AOT_CLASS_LINKER_H_ +#include "base/macros.h" #include "sdk_checker.h" #include "class_linker.h" -namespace art { +namespace art HIDDEN { namespace gc { class Heap; @@ -33,10 +34,10 @@ class AotClassLinker : public ClassLinker { explicit AotClassLinker(InternTable *intern_table); ~AotClassLinker(); -static bool CanReferenceInBootImageExtension(ObjPtr<mirror::Class> klass, gc::Heap* heap) + EXPORT static bool CanReferenceInBootImageExtension(ObjPtr<mirror::Class> klass, gc::Heap* heap) REQUIRES_SHARED(Locks::mutator_lock_); - void SetSdkChecker(std::unique_ptr<SdkChecker>&& sdk_checker_); + EXPORT void SetSdkChecker(std::unique_ptr<SdkChecker>&& sdk_checker_); const SdkChecker* GetSdkChecker() const; bool DenyAccessBasedOnPublicSdk([[maybe_unused]] ArtMethod* art_method) const override diff --git a/runtime/app_info.cc b/runtime/app_info.cc index 3fef5651b0..5ec57c7660 100644 --- a/runtime/app_info.cc +++ b/runtime/app_info.cc @@ -21,7 +21,7 @@ #include "base/safe_map.h" #include "thread-inl.h" -namespace art { +namespace art HIDDEN { static constexpr const char* kUnknownValue = "unknown"; diff --git a/runtime/app_info.h b/runtime/app_info.h index 0b8132aa6f..20cec94a78 100644 --- a/runtime/app_info.h +++ b/runtime/app_info.h @@ -19,10 +19,11 @@ #include <vector> +#include "base/macros.h" #include "base/mutex.h" #include <base/safe_map.h> -namespace art { +namespace art HIDDEN { // Constants used by VMRuntime.java to interface with the runtime. // We could get them from the well known class but it's simpler to diff --git a/runtime/app_info_test.cc b/runtime/app_info_test.cc index 51dd42f6fb..39d07aa516 100644 --- a/runtime/app_info_test.cc +++ b/runtime/app_info_test.cc @@ -20,7 +20,7 @@ #include "gtest/gtest.h" -namespace art { +namespace art HIDDEN { TEST(AppInfoTest, RegisterAppInfo) { AppInfo app_info; diff --git a/runtime/art_field-inl.h b/runtime/art_field-inl.h index 43f2831f99..7137658387 100644 --- a/runtime/art_field-inl.h +++ b/runtime/art_field-inl.h @@ -32,7 +32,7 @@ #include "obj_ptr-inl.h" #include "thread-current-inl.h" -namespace art { +namespace art HIDDEN { inline bool ArtField::IsProxyField() { // No read barrier needed, we're reading the constant declaring class only to read diff --git a/runtime/art_field.cc b/runtime/art_field.cc index c248bf73a1..dcfd7582fe 100644 --- a/runtime/art_field.cc +++ b/runtime/art_field.cc @@ -29,7 +29,7 @@ #include "scoped_thread_state_change-inl.h" #include "well_known_classes.h" -namespace art { +namespace art HIDDEN { void ArtField::SetOffset(MemberOffset num_bytes) { DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous()); diff --git a/runtime/art_field.h b/runtime/art_field.h index 906eda408f..49899dafd6 100644 --- a/runtime/art_field.h +++ b/runtime/art_field.h @@ -17,6 +17,7 @@ #ifndef ART_RUNTIME_ART_FIELD_H_ #define ART_RUNTIME_ART_FIELD_H_ +#include "base/macros.h" #include "dex/modifiers.h" #include "dex/primitive.h" #include "gc_root.h" @@ -25,7 +26,7 @@ #include "read_barrier_option.h" #include "verify_object.h" -namespace art { +namespace art HIDDEN { class DexFile; template<typename T> class LengthPrefixedArray; @@ -39,7 +40,7 @@ class Object; class String; } // namespace mirror -class ArtField final { +class EXPORT ArtField final { public: // Visit declaring classes of all the art-fields in 'array' that reside // in [start_boundary, end_boundary). diff --git a/runtime/art_method-alloc-inl.h b/runtime/art_method-alloc-inl.h index 13051b156e..f91063c2d3 100644 --- a/runtime/art_method-alloc-inl.h +++ b/runtime/art_method-alloc-inl.h @@ -23,7 +23,7 @@ #include "handle_scope.h" #include "mirror/class-alloc-inl.h" -namespace art { +namespace art HIDDEN { namespace detail { diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h index 46c78d2b21..cca20879c2 100644 --- a/runtime/art_method-inl.h +++ b/runtime/art_method-inl.h @@ -46,7 +46,7 @@ #include "runtime-inl.h" #include "thread-current-inl.h" -namespace art { +namespace art HIDDEN { namespace detail { diff --git a/runtime/art_method.cc b/runtime/art_method.cc index 6bb33a13bb..dee62659e3 100644 --- a/runtime/art_method.cc +++ b/runtime/art_method.cc @@ -53,7 +53,7 @@ #include "scoped_thread_state_change-inl.h" #include "vdex_file.h" -namespace art { +namespace art HIDDEN { using android::base::StringPrintf; diff --git a/runtime/art_method.h b/runtime/art_method.h index e5384235fb..dff49e247b 100644 --- a/runtime/art_method.h +++ b/runtime/art_method.h @@ -39,7 +39,7 @@ #include "offsets.h" #include "read_barrier_option.h" -namespace art { +namespace art HIDDEN { class CodeItemDataAccessor; class CodeItemDebugInfoAccessor; @@ -84,7 +84,7 @@ template <char Shorty> struct HandleShortyTraits; template <> struct HandleShortyTraits<'L'>; } // namespace detail -class ArtMethod final { +class EXPORT ArtMethod final { public: // Should the class state be checked on sensitive operations? DECLARE_RUNTIME_DEBUG_FLAG(kCheckDeclaringClassState); diff --git a/runtime/art_method_test.cc b/runtime/art_method_test.cc index b1e9ed3879..8176cca062 100644 --- a/runtime/art_method_test.cc +++ b/runtime/art_method_test.cc @@ -23,7 +23,7 @@ #include "mirror/class-alloc-inl.h" #include "well_known_classes.h" -namespace art { +namespace art HIDDEN { namespace { // Helper function to avoid `ASSERT_EQ` with floating point types. diff --git a/runtime/backtrace_helper.cc b/runtime/backtrace_helper.cc index 260843d7dc..16beb8ee9e 100644 --- a/runtime/backtrace_helper.cc +++ b/runtime/backtrace_helper.cc @@ -38,7 +38,7 @@ #endif -namespace art { +namespace art HIDDEN { // We only really support libunwindstack on linux which is unfortunate but since this is only for // gcstress this isn't a huge deal. diff --git a/runtime/backtrace_helper.h b/runtime/backtrace_helper.h index 9be2550b92..9be08ca195 100644 --- a/runtime/backtrace_helper.h +++ b/runtime/backtrace_helper.h @@ -20,11 +20,13 @@ #include <stddef.h> #include <stdint.h> +#include "base/macros.h" + namespace unwindstack { class Unwinder; } -namespace art { +namespace art HIDDEN { // Using libunwindstack class BacktraceCollector { diff --git a/runtime/barrier.cc b/runtime/barrier.cc index a6cc9ba053..6a9bdfcd8f 100644 --- a/runtime/barrier.cc +++ b/runtime/barrier.cc @@ -23,7 +23,7 @@ #include "base/time_utils.h" #include "thread.h" -namespace art { +namespace art HIDDEN { Barrier::Barrier(int count, bool verify_count_on_shutdown) : count_(count), diff --git a/runtime/barrier.h b/runtime/barrier.h index 4c94a144bd..d2ff5b239d 100644 --- a/runtime/barrier.h +++ b/runtime/barrier.h @@ -30,8 +30,9 @@ #include <memory> #include "base/locks.h" +#include "base/macros.h" -namespace art { +namespace art HIDDEN { class ConditionVariable; class LOCKABLE Mutex; @@ -39,18 +40,18 @@ class LOCKABLE Mutex; // TODO: Maybe give this a better name. class Barrier { public: - enum LockHandling { + enum EXPORT LockHandling { kAllowHoldingLocks, kDisallowHoldingLocks, }; // If verify_count_on_shutdown is true, the destructor verifies that the count is zero in the // destructor. This means that all expected threads went through the barrier. - explicit Barrier(int count, bool verify_count_on_shutdown = true); - virtual ~Barrier(); + EXPORT explicit Barrier(int count, bool verify_count_on_shutdown = true); + EXPORT virtual ~Barrier(); // Pass through the barrier, decrement the count but do not block. - void Pass(Thread* self) REQUIRES(!GetLock()); + EXPORT void Pass(Thread* self) REQUIRES(!GetLock()); // Increment the barrier but do not block. The caller should ensure that it // decrements/passes it eventually. void IncrementNoWait(Thread* self) REQUIRES(!GetLock()); @@ -67,7 +68,7 @@ class Barrier { // Increment the count by delta, wait on condition while count is non zero. If LockHandling is // kAllowHoldingLocks we will not check that all locks are released when waiting. template <Barrier::LockHandling locks = kDisallowHoldingLocks> - void Increment(Thread* self, int delta) REQUIRES(!GetLock()); + EXPORT void Increment(Thread* self, int delta) REQUIRES(!GetLock()); // Increment the count by delta, wait on condition while count is non zero, with a timeout. // Returns true if time out occurred. diff --git a/runtime/barrier_test.cc b/runtime/barrier_test.cc index e53241cb76..fbb263990c 100644 --- a/runtime/barrier_test.cc +++ b/runtime/barrier_test.cc @@ -24,7 +24,7 @@ #include "thread-current-inl.h" #include "thread_pool.h" -namespace art { +namespace art HIDDEN { class CheckWaitTask : public Task { public: CheckWaitTask(Barrier* barrier, AtomicInteger* count1, AtomicInteger* count2) diff --git a/runtime/debug_print.cc b/runtime/debug_print.cc index fd9e050a7d..ef4143a177 100644 --- a/runtime/debug_print.cc +++ b/runtime/debug_print.cc @@ -31,7 +31,7 @@ #include "thread-current-inl.h" #include "well_known_classes-inl.h" -namespace art { +namespace art HIDDEN { std::string DescribeSpace(ObjPtr<mirror::Class> klass) { std::ostringstream oss; diff --git a/runtime/debug_print.h b/runtime/debug_print.h index 7c6840284d..b4c3bba431 100644 --- a/runtime/debug_print.h +++ b/runtime/debug_print.h @@ -18,13 +18,14 @@ #define ART_RUNTIME_DEBUG_PRINT_H_ #include "base/locks.h" +#include "base/macros.h" #include "mirror/object.h" // Helper functions for printing extra information for certain hard to diagnose bugs. -namespace art { +namespace art HIDDEN { -std::string DescribeSpace(ObjPtr<mirror::Class> klass) +EXPORT std::string DescribeSpace(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR; std::string DescribeLoaders(ObjPtr<mirror::ClassLoader> loader, const char* class_descriptor) REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR; diff --git a/runtime/debugger.cc b/runtime/debugger.cc index e5535156c1..3a30cb87e4 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -83,7 +83,7 @@ #include "thread_pool.h" #include "well_known_classes.h" -namespace art { +namespace art HIDDEN { using android::base::StringPrintf; diff --git a/runtime/debugger.h b/runtime/debugger.h index a79add9b8e..fd261ab51a 100644 --- a/runtime/debugger.h +++ b/runtime/debugger.h @@ -27,18 +27,19 @@ #include "base/array_ref.h" #include "base/locks.h" #include "base/logging.h" +#include "base/macros.h" #include "jni.h" #include "runtime.h" #include "runtime_callbacks.h" #include "thread.h" #include "thread_state.h" -namespace art { +namespace art HIDDEN { class Dbg { public: - static void SetJdwpAllowed(bool allowed); - static bool IsJdwpAllowed(); + EXPORT static void SetJdwpAllowed(bool allowed); + EXPORT static bool IsJdwpAllowed(); // Invoked by the GC in case we need to keep DDMS informed. static void GcDidFinish() REQUIRES(!Locks::mutator_lock_); @@ -82,15 +83,14 @@ class Dbg { REQUIRES_SHARED(Locks::mutator_lock_); static void DdmSetThreadNotification(bool enable) REQUIRES(!Locks::thread_list_lock_); - static bool DdmHandleChunk( - JNIEnv* env, - uint32_t type, - const ArrayRef<const jbyte>& data, - /*out*/uint32_t* out_type, - /*out*/std::vector<uint8_t>* out_data); - - static void DdmConnected() REQUIRES_SHARED(Locks::mutator_lock_); - static void DdmDisconnected() REQUIRES_SHARED(Locks::mutator_lock_); + EXPORT static bool DdmHandleChunk(JNIEnv* env, + uint32_t type, + const ArrayRef<const jbyte>& data, + /*out*/ uint32_t* out_type, + /*out*/ std::vector<uint8_t>* out_data); + + EXPORT static void DdmConnected() REQUIRES_SHARED(Locks::mutator_lock_); + EXPORT static void DdmDisconnected() REQUIRES_SHARED(Locks::mutator_lock_); /* * Allocation tracking support. diff --git a/runtime/deoptimization_kind.h b/runtime/deoptimization_kind.h index 65a1cf1f2f..76a11b349c 100644 --- a/runtime/deoptimization_kind.h +++ b/runtime/deoptimization_kind.h @@ -18,8 +18,9 @@ #define ART_RUNTIME_DEOPTIMIZATION_KIND_H_ #include "base/logging.h" +#include "base/macros.h" -namespace art { +namespace art HIDDEN { enum class DeoptimizationKind { kAotInlineCache = 0, diff --git a/runtime/dex/dex_file_annotations.cc b/runtime/dex/dex_file_annotations.cc index 827ced9545..76cea993b2 100644 --- a/runtime/dex/dex_file_annotations.cc +++ b/runtime/dex/dex_file_annotations.cc @@ -41,7 +41,7 @@ #include "thread.h" #include "well_known_classes.h" -namespace art { +namespace art HIDDEN { using android::base::StringPrintf; diff --git a/runtime/dex/dex_file_annotations.h b/runtime/dex/dex_file_annotations.h index cffeb25e57..3a79e11256 100644 --- a/runtime/dex/dex_file_annotations.h +++ b/runtime/dex/dex_file_annotations.h @@ -23,7 +23,7 @@ #include "mirror/object_array.h" #include "obj_ptr.h" -namespace art { +namespace art HIDDEN { namespace mirror { class ClassLoader; @@ -40,7 +40,7 @@ ObjPtr<mirror::Object> GetAnnotationForField(ArtField* field, REQUIRES_SHARED(Locks::mutator_lock_); ObjPtr<mirror::ObjectArray<mirror::Object>> GetAnnotationsForField(ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_); -ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureAnnotationForField(ArtField* field) +EXPORT ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureAnnotationForField(ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_); bool IsFieldAnnotationPresent(ArtField* field, Handle<mirror::Class> annotation_class) REQUIRES_SHARED(Locks::mutator_lock_); @@ -67,8 +67,8 @@ bool GetParametersMetadataForMethod( ArtMethod* method, /*out*/ MutableHandle<mirror::ObjectArray<mirror::String>>* names, /*out*/ MutableHandle<mirror::IntArray>* access_flags) REQUIRES_SHARED(Locks::mutator_lock_); -ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureAnnotationForMethod(ArtMethod* method) - REQUIRES_SHARED(Locks::mutator_lock_); +EXPORT ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureAnnotationForMethod( + ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_); // Check whether `method` is annotated with `annotation_class`. // If `lookup_in_resolved_boot_classes` is true, look up any of the // method's annotations' classes in the bootstrap class loader's @@ -83,14 +83,14 @@ bool IsMethodAnnotationPresent(ArtMethod* method, // is annotated with @dalvik.annotation.optimization.FastNative or // @dalvik.annotation.optimization.CriticalNative with build visibility. // If yes, return the associated access flags, i.e. kAccFastNative or kAccCriticalNative. -uint32_t GetNativeMethodAnnotationAccessFlags(const DexFile& dex_file, - const dex::ClassDef& class_def, - uint32_t method_index); +EXPORT uint32_t GetNativeMethodAnnotationAccessFlags(const DexFile& dex_file, + const dex::ClassDef& class_def, + uint32_t method_index); // Is the method from the `dex_file` with the given `field_index` // annotated with @dalvik.annotation.optimization.NeverCompile? -bool MethodIsNeverCompile(const DexFile& dex_file, - const dex::ClassDef& class_def, - uint32_t method_index); +EXPORT bool MethodIsNeverCompile(const DexFile& dex_file, + const dex::ClassDef& class_def, + uint32_t method_index); // Is the method from the `dex_file` with the given `field_index` // annotated with @dalvik.annotation.optimization.NeverInline? bool MethodIsNeverInline(const DexFile& dex_file, @@ -137,9 +137,9 @@ bool GetInnerClass(Handle<mirror::Class> klass, /*out*/ ObjPtr<mirror::String>* REQUIRES_SHARED(Locks::mutator_lock_); bool GetInnerClassFlags(Handle<mirror::Class> klass, uint32_t* flags) REQUIRES_SHARED(Locks::mutator_lock_); -ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureAnnotationForClass( +EXPORT ObjPtr<mirror::ObjectArray<mirror::String>> GetSignatureAnnotationForClass( Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); -const char* GetSourceDebugExtension(Handle<mirror::Class> klass) +EXPORT const char* GetSourceDebugExtension(Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); ObjPtr<mirror::Class> GetNestHost(Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/dex2oat_environment_test.h b/runtime/dex2oat_environment_test.h index 54a007f891..202f8cf92a 100644 --- a/runtime/dex2oat_environment_test.h +++ b/runtime/dex2oat_environment_test.h @@ -23,6 +23,7 @@ #include <vector> #include "base/file_utils.h" +#include "base/macros.h" #include "base/os.h" #include "base/stl_util.h" #include "base/utils.h" @@ -38,7 +39,7 @@ #include "runtime.h" #include "ziparchive/zip_writer.h" -namespace art { +namespace art HIDDEN { static constexpr bool kDebugArgs = false; diff --git a/runtime/dex_reference_collection.h b/runtime/dex_reference_collection.h index 047771f4a5..d571cf0ce4 100644 --- a/runtime/dex_reference_collection.h +++ b/runtime/dex_reference_collection.h @@ -22,7 +22,7 @@ #include "base/macros.h" -namespace art { +namespace art HIDDEN { class DexFile; diff --git a/runtime/dex_register_location.cc b/runtime/dex_register_location.cc index f3b09733b9..a425b683d4 100644 --- a/runtime/dex_register_location.cc +++ b/runtime/dex_register_location.cc @@ -16,7 +16,7 @@ #include "dex_register_location.h" -namespace art { +namespace art HIDDEN { std::ostream& operator<<(std::ostream& stream, DexRegisterLocation::Kind kind) { return stream << "Kind<" << static_cast<int32_t>(kind) << ">"; diff --git a/runtime/dex_register_location.h b/runtime/dex_register_location.h index 98b4d41e2d..f33fd44608 100644 --- a/runtime/dex_register_location.h +++ b/runtime/dex_register_location.h @@ -21,9 +21,10 @@ #include <cstdint> #include "base/dchecked_vector.h" +#include "base/macros.h" #include "base/memory_region.h" -namespace art { +namespace art HIDDEN { // Dex register location container used by DexRegisterMap and StackMapStream. class DexRegisterLocation { @@ -85,7 +86,7 @@ class DexRegisterLocation { friend class DexRegisterMap; // Allow creation of uninitialized array of locations. }; -std::ostream& operator<<(std::ostream& stream, DexRegisterLocation::Kind kind); +EXPORT std::ostream& operator<<(std::ostream& stream, DexRegisterLocation::Kind kind); std::ostream& operator<<(std::ostream& stream, const DexRegisterLocation& reg); } // namespace art diff --git a/runtime/dexopt_test.cc b/runtime/dexopt_test.cc index 3eee9e03e0..970590fda8 100644 --- a/runtime/dexopt_test.cc +++ b/runtime/dexopt_test.cc @@ -38,7 +38,7 @@ #include "oat_file_assistant.h" #include "profile/profile_compilation_info.h" -namespace art { +namespace art HIDDEN { void DexoptTest::SetUp() { ReserveImageSpace(); Dex2oatEnvironmentTest::SetUp(); diff --git a/runtime/dexopt_test.h b/runtime/dexopt_test.h index a2363939ea..cf32785c0b 100644 --- a/runtime/dexopt_test.h +++ b/runtime/dexopt_test.h @@ -20,9 +20,10 @@ #include <string> #include <vector> +#include "base/macros.h" #include "dex2oat_environment_test.h" -namespace art { +namespace art HIDDEN { class DexoptTest : public Dex2oatEnvironmentTest { public: diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h index 4a1dfba786..a854e0c5ac 100644 --- a/runtime/entrypoints/entrypoint_utils-inl.h +++ b/runtime/entrypoints/entrypoint_utils-inl.h @@ -47,7 +47,7 @@ #include "thread.h" #include "well_known_classes.h" -namespace art { +namespace art HIDDEN { inline std::string GetResolvedMethodErrorString(ClassLinker* class_linker, ArtMethod* inlined_method, diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc index aa27df4dc5..96a2231930 100644 --- a/runtime/entrypoints/entrypoint_utils.cc +++ b/runtime/entrypoints/entrypoint_utils.cc @@ -43,7 +43,7 @@ #include "scoped_thread_state_change-inl.h" #include "well_known_classes-inl.h" -namespace art { +namespace art HIDDEN { void CheckReferenceResult(Handle<mirror::Object> o, Thread* self) { if (o == nullptr) { diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h index cfa744d278..3dfeaae024 100644 --- a/runtime/entrypoints/entrypoint_utils.h +++ b/runtime/entrypoints/entrypoint_utils.h @@ -29,7 +29,7 @@ #include "handle.h" #include "jvalue.h" -namespace art { +namespace art HIDDEN { namespace mirror { class Array; diff --git a/runtime/entrypoints/jni/jni_entrypoints.cc b/runtime/entrypoints/jni/jni_entrypoints.cc index 359614bf92..885764f180 100644 --- a/runtime/entrypoints/jni/jni_entrypoints.cc +++ b/runtime/entrypoints/jni/jni_entrypoints.cc @@ -33,7 +33,7 @@ #include "stack_map.h" #include "thread.h" -namespace art { +namespace art HIDDEN { static inline uint32_t GetInvokeStaticMethodIndex(ArtMethod* caller, uint32_t dex_pc) REQUIRES_SHARED(Locks::mutator_lock_) { diff --git a/runtime/entrypoints/jni/jni_entrypoints.h b/runtime/entrypoints/jni/jni_entrypoints.h index def9ddba73..4b515db50d 100644 --- a/runtime/entrypoints/jni/jni_entrypoints.h +++ b/runtime/entrypoints/jni/jni_entrypoints.h @@ -25,7 +25,7 @@ #define JNI_ENTRYPOINT_OFFSET(ptr_size, x) \ Thread::JniEntryPointOffset<ptr_size>(OFFSETOF_MEMBER(JniEntryPoints, x)) -namespace art { +namespace art HIDDEN { // Pointers to functions that are called by JNI trampolines via thread-local storage. struct JniEntryPoints { diff --git a/runtime/entrypoints/math_entrypoints.cc b/runtime/entrypoints/math_entrypoints.cc index b0eaf1ed03..5db8dbfe9d 100644 --- a/runtime/entrypoints/math_entrypoints.cc +++ b/runtime/entrypoints/math_entrypoints.cc @@ -18,7 +18,7 @@ #include "entrypoint_utils-inl.h" -namespace art { +namespace art HIDDEN { extern "C" double art_l2d(int64_t l) { return static_cast<double>(l); diff --git a/runtime/entrypoints/math_entrypoints_test.cc b/runtime/entrypoints/math_entrypoints_test.cc index fe61f5dd11..337f9f0925 100644 --- a/runtime/entrypoints/math_entrypoints_test.cc +++ b/runtime/entrypoints/math_entrypoints_test.cc @@ -20,7 +20,7 @@ #include "base/common_art_test.h" -namespace art { +namespace art HIDDEN { class MathEntrypointsTest : public CommonArtTest {}; diff --git a/runtime/entrypoints/quick/callee_save_frame.h b/runtime/entrypoints/quick/callee_save_frame.h index 7d9b844b0c..81219234b8 100644 --- a/runtime/entrypoints/quick/callee_save_frame.h +++ b/runtime/entrypoints/quick/callee_save_frame.h @@ -32,7 +32,7 @@ #include "arch/x86/callee_save_frame_x86.h" #include "arch/x86_64/callee_save_frame_x86_64.h" -namespace art { +namespace art HIDDEN { class ArtMethod; class ScopedQuickEntrypointChecks { diff --git a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc index 7b3d84915a..82595ed636 100644 --- a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc @@ -27,7 +27,7 @@ #include "mirror/object_array-inl.h" #include "mirror/string-alloc-inl.h" -namespace art { +namespace art HIDDEN { static constexpr bool kUseTlabFastPath = true; diff --git a/runtime/entrypoints/quick/quick_alloc_entrypoints.h b/runtime/entrypoints/quick/quick_alloc_entrypoints.h index c4d8a808b2..94f4a27691 100644 --- a/runtime/entrypoints/quick/quick_alloc_entrypoints.h +++ b/runtime/entrypoints/quick/quick_alloc_entrypoints.h @@ -21,7 +21,7 @@ #include "gc/allocator_type.h" #include "quick_entrypoints.h" -namespace art { +namespace art HIDDEN { void ResetQuickAllocEntryPoints(QuickEntryPoints* qpoints); diff --git a/runtime/entrypoints/quick/quick_cast_entrypoints.cc b/runtime/entrypoints/quick/quick_cast_entrypoints.cc index 083d5786ce..a32c483431 100644 --- a/runtime/entrypoints/quick/quick_cast_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_cast_entrypoints.cc @@ -17,7 +17,7 @@ #include "mirror/class-inl.h" #include "mirror/object-inl.h" -namespace art { +namespace art HIDDEN { // Assignable test for code, won't throw. Null and equality tests already performed extern "C" size_t artIsAssignableFromCode(mirror::Class* klass, mirror::Class* ref_class) diff --git a/runtime/entrypoints/quick/quick_default_externs.h b/runtime/entrypoints/quick/quick_default_externs.h index cb3caac9ab..5119b27076 100644 --- a/runtime/entrypoints/quick/quick_default_externs.h +++ b/runtime/entrypoints/quick/quick_default_externs.h @@ -19,7 +19,7 @@ #include <cstdint> -namespace art { +namespace art HIDDEN { namespace mirror { class Array; class Class; diff --git a/runtime/entrypoints/quick/quick_default_init_entrypoints.h b/runtime/entrypoints/quick/quick_default_init_entrypoints.h index ea077889ee..46840e60ed 100644 --- a/runtime/entrypoints/quick/quick_default_init_entrypoints.h +++ b/runtime/entrypoints/quick/quick_default_init_entrypoints.h @@ -24,7 +24,7 @@ #include "quick_default_externs.h" #include "quick_entrypoints.h" -namespace art { +namespace art HIDDEN { static void DefaultInitEntryPoints(JniEntryPoints* jpoints, QuickEntryPoints* qpoints, diff --git a/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc b/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc index 277bc7bf06..29060457fd 100644 --- a/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc @@ -23,7 +23,7 @@ #include "runtime.h" #include "thread.h" -namespace art { +namespace art HIDDEN { NO_RETURN static void artDeoptimizeImpl(Thread* self, DeoptimizationKind kind, diff --git a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc index 9973d1aa47..f29143f79a 100644 --- a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc @@ -32,7 +32,7 @@ #include "oat_file-inl.h" #include "runtime.h" -namespace art { +namespace art HIDDEN { static void StoreObjectInBss(ArtMethod* outer_method, const OatFile* oat_file, diff --git a/runtime/entrypoints/quick/quick_entrypoints.h b/runtime/entrypoints/quick/quick_entrypoints.h index 0e73c63828..fe01424c7c 100644 --- a/runtime/entrypoints/quick/quick_entrypoints.h +++ b/runtime/entrypoints/quick/quick_entrypoints.h @@ -27,7 +27,7 @@ #define QUICK_ENTRYPOINT_OFFSET(ptr_size, x) \ Thread::QuickEntryPointOffset<ptr_size>(OFFSETOF_MEMBER(QuickEntryPoints, x)) -namespace art { +namespace art HIDDEN { namespace mirror { class Array; diff --git a/runtime/entrypoints/quick/quick_entrypoints_enum.cc b/runtime/entrypoints/quick/quick_entrypoints_enum.cc index 5387e44d9b..80d9313dcf 100644 --- a/runtime/entrypoints/quick/quick_entrypoints_enum.cc +++ b/runtime/entrypoints/quick/quick_entrypoints_enum.cc @@ -16,7 +16,7 @@ #include "quick_entrypoints_enum.h" -namespace art { +namespace art HIDDEN { bool EntrypointRequiresStackMap(QuickEntrypointEnum trampoline) { // Entrypoints that do not require a stackmap. In general leaf methods diff --git a/runtime/entrypoints/quick/quick_entrypoints_enum.h b/runtime/entrypoints/quick/quick_entrypoints_enum.h index 017cba68ea..c84ca20d56 100644 --- a/runtime/entrypoints/quick/quick_entrypoints_enum.h +++ b/runtime/entrypoints/quick/quick_entrypoints_enum.h @@ -20,7 +20,7 @@ #include "quick_entrypoints.h" #include "thread.h" -namespace art { +namespace art HIDDEN { // Define an enum for the entrypoints. Names are prepended a 'kQuick'. enum QuickEntrypointEnum { // NOLINT(whitespace/braces) diff --git a/runtime/entrypoints/quick/quick_field_entrypoints.cc b/runtime/entrypoints/quick/quick_field_entrypoints.cc index edf58faf6a..39b21ead02 100644 --- a/runtime/entrypoints/quick/quick_field_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_field_entrypoints.cc @@ -26,7 +26,7 @@ #include "mirror/class-inl.h" #include "mirror/object_reference.h" -namespace art { +namespace art HIDDEN { // Fast path field resolution that can't initialize classes or throw exceptions. inline ArtField* FindFieldFast(uint32_t field_idx, diff --git a/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc b/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc index 5b7fe0ccf4..b87d81501b 100644 --- a/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc @@ -19,7 +19,7 @@ #include "entrypoints/entrypoint_utils.h" #include "mirror/array.h" -namespace art { +namespace art HIDDEN { /* * Handle fill array data by copying appropriate part of dex file into array. diff --git a/runtime/entrypoints/quick/quick_jni_entrypoints.cc b/runtime/entrypoints/quick/quick_jni_entrypoints.cc index 06c27b37c8..c9ec7a7dec 100644 --- a/runtime/entrypoints/quick/quick_jni_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_jni_entrypoints.cc @@ -36,7 +36,7 @@ } \ } -namespace art { +namespace art HIDDEN { extern "C" int artMethodExitHook(Thread* self, ArtMethod* method, diff --git a/runtime/entrypoints/quick/quick_lock_entrypoints.cc b/runtime/entrypoints/quick/quick_lock_entrypoints.cc index 87286cf651..402f8f613c 100644 --- a/runtime/entrypoints/quick/quick_lock_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_lock_entrypoints.cc @@ -18,7 +18,7 @@ #include "common_throws.h" #include "mirror/object-inl.h" -namespace art { +namespace art HIDDEN { extern "C" int artLockObjectFromCode(mirror::Object* obj, Thread* self) NO_THREAD_SAFETY_ANALYSIS diff --git a/runtime/entrypoints/quick/quick_string_builder_append_entrypoints.cc b/runtime/entrypoints/quick/quick_string_builder_append_entrypoints.cc index 9afaf439dc..9e5fe1c826 100644 --- a/runtime/entrypoints/quick/quick_string_builder_append_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_string_builder_append_entrypoints.cc @@ -19,7 +19,7 @@ #include "string_builder_append.h" #include "obj_ptr-inl.h" -namespace art { +namespace art HIDDEN { extern "C" mirror::String* artStringBuilderAppend(uint32_t format, const uint32_t* args, diff --git a/runtime/entrypoints/quick/quick_thread_entrypoints.cc b/runtime/entrypoints/quick/quick_thread_entrypoints.cc index 5dca58ab04..53e14d0d7a 100644 --- a/runtime/entrypoints/quick/quick_thread_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_thread_entrypoints.cc @@ -19,7 +19,7 @@ #include "runtime.h" #include "thread-inl.h" -namespace art { +namespace art HIDDEN { extern "C" void artDeoptimizeIfNeeded(Thread* self, uintptr_t result, bool is_ref) REQUIRES_SHARED(Locks::mutator_lock_) { diff --git a/runtime/entrypoints/quick/quick_throw_entrypoints.cc b/runtime/entrypoints/quick/quick_throw_entrypoints.cc index 202b031bca..781f3e549d 100644 --- a/runtime/entrypoints/quick/quick_throw_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_throw_entrypoints.cc @@ -24,7 +24,7 @@ #include "thread.h" #include "well_known_classes.h" -namespace art { +namespace art HIDDEN { // Deliver an exception that's pending on thread helping set up a callee save frame on the way. extern "C" NO_RETURN void artDeliverPendingExceptionFromCode(Thread* self) diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index 664cf622a8..d87388e86b 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -58,7 +58,7 @@ #include "var_handles.h" #include "well_known_classes.h" -namespace art { +namespace art HIDDEN { extern "C" NO_RETURN void artDeoptimizeFromCompiledCode(DeoptimizationKind kind, Thread* self); extern "C" NO_RETURN void artDeoptimize(Thread* self, bool skip_method_exit_callbacks); @@ -943,9 +943,8 @@ class GetQuickReferenceArgumentAtVisitor final : public QuickArgumentVisitor { // Returning reference argument at position `arg_pos` in Quick stack frame at address `sp`. // NOTE: Only used for testing purposes. -extern "C" StackReference<mirror::Object>* artQuickGetProxyReferenceArgumentAt(size_t arg_pos, - ArtMethod** sp) - REQUIRES_SHARED(Locks::mutator_lock_) { +EXPORT extern "C" StackReference<mirror::Object>* artQuickGetProxyReferenceArgumentAt( + size_t arg_pos, ArtMethod** sp) REQUIRES_SHARED(Locks::mutator_lock_) { ArtMethod* proxy_method = *sp; ArtMethod* non_proxy_method = proxy_method->GetInterfaceMethodIfProxy(kRuntimePointerSize); CHECK(!non_proxy_method->IsStatic()) diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc index 0f0fb69f4b..14e5a7cdfd 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc @@ -22,7 +22,7 @@ #include "common_runtime_test.h" #include "quick/quick_method_frame_info.h" -namespace art { +namespace art HIDDEN { class QuickTrampolineEntrypointsTest : public CommonRuntimeTest { protected: diff --git a/runtime/gc/allocation_listener.h b/runtime/gc/allocation_listener.h index f286c6cf6e..15daab2136 100644 --- a/runtime/gc/allocation_listener.h +++ b/runtime/gc/allocation_listener.h @@ -26,7 +26,7 @@ #include "handle.h" #include "obj_ptr.h" -namespace art { +namespace art HIDDEN { namespace mirror { class Class; diff --git a/runtime/gc/allocation_record.cc b/runtime/gc/allocation_record.cc index f0d379fde6..f98edf4aa8 100644 --- a/runtime/gc/allocation_record.cc +++ b/runtime/gc/allocation_record.cc @@ -27,7 +27,7 @@ #include <android-base/properties.h> -namespace art { +namespace art HIDDEN { namespace gc { int32_t AllocRecordStackTraceElement::ComputeLineNumber() const { diff --git a/runtime/gc/allocation_record.h b/runtime/gc/allocation_record.h index 8b4cc67b91..8273ea4df8 100644 --- a/runtime/gc/allocation_record.h +++ b/runtime/gc/allocation_record.h @@ -20,11 +20,12 @@ #include <list> #include <memory> +#include "base/macros.h" #include "base/mutex.h" #include "gc_root.h" #include "obj_ptr.h" -namespace art { +namespace art HIDDEN { class ArtMethod; class IsMarkedVisitor; @@ -215,11 +216,8 @@ class AllocRecordObjectMap { // Caller needs to check that it is enabled before calling since we read the stack trace before // checking the enabled boolean. - void RecordAllocation(Thread* self, - ObjPtr<mirror::Object>* obj, - size_t byte_count) - REQUIRES(!Locks::alloc_tracker_lock_) - REQUIRES_SHARED(Locks::mutator_lock_); + EXPORT void RecordAllocation(Thread* self, ObjPtr<mirror::Object>* obj, size_t byte_count) + REQUIRES(!Locks::alloc_tracker_lock_) REQUIRES_SHARED(Locks::mutator_lock_); static void SetAllocTrackingEnabled(bool enabled) REQUIRES(!Locks::alloc_tracker_lock_); diff --git a/runtime/gc/allocator/art-dlmalloc.cc b/runtime/gc/allocator/art-dlmalloc.cc index 62a768db39..86732324d9 100644 --- a/runtime/gc/allocator/art-dlmalloc.cc +++ b/runtime/gc/allocator/art-dlmalloc.cc @@ -19,6 +19,7 @@ #include <android-base/logging.h> #include "base/bit_utils.h" +#include "gc/space/dlmalloc_space.h" // ART specific morecore implementation defined in space.cc. static void* art_heap_morecore(void* m, intptr_t increment); @@ -57,50 +58,3 @@ static void art_heap_usage_error(const char* function, void* p) { LOG(FATAL) << "Incorrect use of function '" << function << "' argument " << p << " not expected"; } - -#include <sys/mman.h> - -#include "base/utils.h" -#include "runtime_globals.h" - -extern "C" void DlmallocMadviseCallback(void* start, void* end, size_t used_bytes, void* arg) { - // Is this chunk in use? - if (used_bytes != 0) { - return; - } - // Do we have any whole pages to give back? - start = reinterpret_cast<void*>(art::RoundUp(reinterpret_cast<uintptr_t>(start), art::gPageSize)); - end = reinterpret_cast<void*>(art::RoundDown(reinterpret_cast<uintptr_t>(end), art::gPageSize)); - if (end > start) { - size_t length = reinterpret_cast<uint8_t*>(end) - reinterpret_cast<uint8_t*>(start); - int rc = madvise(start, length, MADV_DONTNEED); - if (UNLIKELY(rc != 0)) { - errno = rc; - PLOG(FATAL) << "madvise failed during heap trimming"; - } - size_t* reclaimed = reinterpret_cast<size_t*>(arg); - *reclaimed += length; - } -} - -extern "C" void DlmallocBytesAllocatedCallback([[maybe_unused]] void* start, - [[maybe_unused]] void* end, - size_t used_bytes, - void* arg) { - if (used_bytes == 0) { - return; - } - size_t* bytes_allocated = reinterpret_cast<size_t*>(arg); - *bytes_allocated += used_bytes + sizeof(size_t); -} - -extern "C" void DlmallocObjectsAllocatedCallback([[maybe_unused]] void* start, - [[maybe_unused]] void* end, - size_t used_bytes, - void* arg) { - if (used_bytes == 0) { - return; - } - size_t* objects_allocated = reinterpret_cast<size_t*>(arg); - ++(*objects_allocated); -} diff --git a/runtime/gc/allocator/art-dlmalloc.h b/runtime/gc/allocator/art-dlmalloc.h index 296de72c70..cffde4d8a5 100644 --- a/runtime/gc/allocator/art-dlmalloc.h +++ b/runtime/gc/allocator/art-dlmalloc.h @@ -36,26 +36,4 @@ #include "dlmalloc.h" #pragma GCC diagnostic pop -// Callback for dlmalloc_inspect_all or mspace_inspect_all that will madvise(2) unused -// pages back to the kernel. -extern "C" void DlmallocMadviseCallback(void* start, void* end, size_t used_bytes, void* /*arg*/); - -// Callbacks for dlmalloc_inspect_all or mspace_inspect_all that will -// count the number of bytes allocated and objects allocated, -// respectively. -extern "C" void DlmallocBytesAllocatedCallback(void* start, void* end, size_t used_bytes, void* arg); -extern "C" void DlmallocObjectsAllocatedCallback(void* start, void* end, size_t used_bytes, void* arg); - -namespace art { -namespace gc { -namespace allocator { - -// Callback from dlmalloc when it needs to increase the footprint. Must be implemented somewhere -// else (currently dlmalloc_space.cc). -void* ArtDlMallocMoreCore(void* mspace, intptr_t increment); - -} // namespace allocator -} // namespace gc -} // namespace art - #endif // ART_RUNTIME_GC_ALLOCATOR_ART_DLMALLOC_H_ diff --git a/runtime/gc/allocator_type.h b/runtime/gc/allocator_type.h index fb298379c9..71188868b2 100644 --- a/runtime/gc/allocator_type.h +++ b/runtime/gc/allocator_type.h @@ -19,7 +19,9 @@ #include <iosfwd> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { namespace gc { // Different types of allocators. diff --git a/runtime/gc/collector/concurrent_copying-inl.h b/runtime/gc/collector/concurrent_copying-inl.h index 5a25166f9a..a905e812f3 100644 --- a/runtime/gc/collector/concurrent_copying-inl.h +++ b/runtime/gc/collector/concurrent_copying-inl.h @@ -28,7 +28,7 @@ #include "mirror/class.h" #include "mirror/object-readbarrier-inl.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace collector { diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc index af4848a17b..4987ed07d5 100644 --- a/runtime/gc/collector/concurrent_copying.cc +++ b/runtime/gc/collector/concurrent_copying.cc @@ -47,7 +47,7 @@ #include "thread_list.h" #include "well_known_classes.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace collector { diff --git a/runtime/gc/collector/concurrent_copying.h b/runtime/gc/collector/concurrent_copying.h index 47d297bdbb..469d54abdf 100644 --- a/runtime/gc/collector/concurrent_copying.h +++ b/runtime/gc/collector/concurrent_copying.h @@ -17,6 +17,7 @@ #ifndef ART_RUNTIME_GC_COLLECTOR_CONCURRENT_COPYING_H_ #define ART_RUNTIME_GC_COLLECTOR_CONCURRENT_COPYING_H_ +#include "base/macros.h" #include "garbage_collector.h" #include "gc/accounting/space_bitmap.h" #include "immune_spaces.h" @@ -27,7 +28,7 @@ #include <unordered_map> #include <vector> -namespace art { +namespace art HIDDEN { class Barrier; class Closure; class RootInfo; @@ -167,17 +168,15 @@ class ConcurrentCopying : public GarbageCollector { REQUIRES_SHARED(Locks::mutator_lock_); private: - void PushOntoMarkStack(Thread* const self, mirror::Object* obj) - REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!mark_stack_lock_); + EXPORT void PushOntoMarkStack(Thread* const self, mirror::Object* obj) + REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!mark_stack_lock_); // Returns a to-space copy of the from-space object from_ref, and atomically installs a // forwarding pointer. Ensures that the forwarding reference is visible to other threads before // the returned to-space pointer becomes visible to them. - mirror::Object* Copy(Thread* const self, - mirror::Object* from_ref, - mirror::Object* holder, - MemberOffset offset) - REQUIRES_SHARED(Locks::mutator_lock_) + EXPORT mirror::Object* Copy(Thread* const self, + mirror::Object* from_ref, + mirror::Object* holder, + MemberOffset offset) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!mark_stack_lock_, !skipped_blocks_lock_, !immune_gray_stack_lock_); // Scan the reference fields of object `to_ref`. template <bool kNoUnEvac> @@ -288,8 +287,9 @@ class ConcurrentCopying : public GarbageCollector { REQUIRES_SHARED(Locks::mutator_lock_); // Dump information about heap reference `ref`, referenced from object `obj` at offset `offset`, // and return it as a string. - std::string DumpHeapReference(mirror::Object* obj, MemberOffset offset, mirror::Object* ref) - REQUIRES_SHARED(Locks::mutator_lock_); + EXPORT std::string DumpHeapReference(mirror::Object* obj, + MemberOffset offset, + mirror::Object* ref) REQUIRES_SHARED(Locks::mutator_lock_); // Dump information about GC root `ref` and return it as a string. std::string DumpGcRoot(mirror::Object* ref) REQUIRES_SHARED(Locks::mutator_lock_); void AssertToSpaceInvariantInNonMovingSpace(mirror::Object* obj, mirror::Object* ref) @@ -298,12 +298,11 @@ class ConcurrentCopying : public GarbageCollector { void DisableMarking() REQUIRES_SHARED(Locks::mutator_lock_); void IssueDisableMarkingCheckpoint() REQUIRES_SHARED(Locks::mutator_lock_); void ExpandGcMarkStack() REQUIRES_SHARED(Locks::mutator_lock_); - mirror::Object* MarkNonMoving(Thread* const self, - mirror::Object* from_ref, - mirror::Object* holder = nullptr, - MemberOffset offset = MemberOffset(0)) - REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!mark_stack_lock_, !skipped_blocks_lock_); + EXPORT mirror::Object* MarkNonMoving(Thread* const self, + mirror::Object* from_ref, + mirror::Object* holder = nullptr, + MemberOffset offset = MemberOffset(0)) + REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!mark_stack_lock_, !skipped_blocks_lock_); ALWAYS_INLINE mirror::Object* MarkUnevacFromSpaceRegion(Thread* const self, mirror::Object* from_ref, accounting::SpaceBitmap<kObjectAlignment>* bitmap) @@ -315,8 +314,8 @@ class ConcurrentCopying : public GarbageCollector { REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!immune_gray_stack_lock_); void ScanImmuneObject(mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!mark_stack_lock_); - mirror::Object* MarkFromReadBarrierWithMeasurements(Thread* const self, - mirror::Object* from_ref) + EXPORT mirror::Object* MarkFromReadBarrierWithMeasurements(Thread* const self, + mirror::Object* from_ref) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!mark_stack_lock_, !skipped_blocks_lock_, !immune_gray_stack_lock_); void DumpPerformanceInfo(std::ostream& os) override REQUIRES(!rb_slow_path_histogram_lock_); diff --git a/runtime/gc/collector/garbage_collector.cc b/runtime/gc/collector/garbage_collector.cc index 6c9c005238..0274d987c8 100644 --- a/runtime/gc/collector/garbage_collector.cc +++ b/runtime/gc/collector/garbage_collector.cc @@ -38,7 +38,7 @@ #include "thread-current-inl.h" #include "thread_list.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace collector { diff --git a/runtime/gc/collector/garbage_collector.h b/runtime/gc/collector/garbage_collector.h index 40348d614d..ea5acdf202 100644 --- a/runtime/gc/collector/garbage_collector.h +++ b/runtime/gc/collector/garbage_collector.h @@ -21,6 +21,7 @@ #include <list> #include "base/histogram.h" +#include "base/macros.h" #include "base/metrics/metrics.h" #include "base/mutex.h" #include "base/timing_logger.h" @@ -32,7 +33,7 @@ #include "object_byte_pair.h" #include "object_callbacks.h" -namespace art { +namespace art HIDDEN { namespace mirror { class Class; diff --git a/runtime/gc/collector/gc_type.h b/runtime/gc/collector/gc_type.h index f03ba1f0c6..e666c04826 100644 --- a/runtime/gc/collector/gc_type.h +++ b/runtime/gc/collector/gc_type.h @@ -19,7 +19,9 @@ #include <iosfwd> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { namespace gc { namespace collector { diff --git a/runtime/gc/collector/immune_region.cc b/runtime/gc/collector/immune_region.cc index 8a04c178b5..a6b90b87be 100644 --- a/runtime/gc/collector/immune_region.cc +++ b/runtime/gc/collector/immune_region.cc @@ -19,7 +19,7 @@ #include "gc/space/space-inl.h" #include "mirror/object.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace collector { diff --git a/runtime/gc/collector/immune_region.h b/runtime/gc/collector/immune_region.h index 80ee44cf68..ee0ce847c9 100644 --- a/runtime/gc/collector/immune_region.h +++ b/runtime/gc/collector/immune_region.h @@ -19,7 +19,7 @@ #include "base/macros.h" -namespace art { +namespace art HIDDEN { namespace mirror { class Object; } // namespace mirror diff --git a/runtime/gc/collector/immune_spaces.cc b/runtime/gc/collector/immune_spaces.cc index 683ca8de0b..28704af919 100644 --- a/runtime/gc/collector/immune_spaces.cc +++ b/runtime/gc/collector/immune_spaces.cc @@ -24,7 +24,7 @@ #include "mirror/object.h" #include "oat_file.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace collector { diff --git a/runtime/gc/collector/immune_spaces.h b/runtime/gc/collector/immune_spaces.h index 950c35b27a..5ee4ffc32d 100644 --- a/runtime/gc/collector/immune_spaces.h +++ b/runtime/gc/collector/immune_spaces.h @@ -24,7 +24,7 @@ #include <set> -namespace art { +namespace art HIDDEN { namespace gc { namespace space { class ContinuousSpace; diff --git a/runtime/gc/collector/immune_spaces_test.cc b/runtime/gc/collector/immune_spaces_test.cc index 2337eadf7a..cee3d242e6 100644 --- a/runtime/gc/collector/immune_spaces_test.cc +++ b/runtime/gc/collector/immune_spaces_test.cc @@ -24,7 +24,7 @@ #include "oat_file.h" #include "thread-current-inl.h" -namespace art { +namespace art HIDDEN { namespace mirror { class Object; } // namespace mirror diff --git a/runtime/gc/collector/iteration.h b/runtime/gc/collector/iteration.h index 348f49df00..d70a30b829 100644 --- a/runtime/gc/collector/iteration.h +++ b/runtime/gc/collector/iteration.h @@ -21,11 +21,12 @@ #include <vector> #include "android-base/macros.h" +#include "base/macros.h" #include "base/timing_logger.h" #include "gc/gc_cause.h" #include "object_byte_pair.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace collector { diff --git a/runtime/gc/collector/mark_compact-inl.h b/runtime/gc/collector/mark_compact-inl.h index fe67906d4b..454d79ae88 100644 --- a/runtime/gc/collector/mark_compact-inl.h +++ b/runtime/gc/collector/mark_compact-inl.h @@ -21,7 +21,7 @@ #include "mark_compact.h" #include "mirror/object-inl.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace collector { diff --git a/runtime/gc/collector/mark_compact.cc b/runtime/gc/collector/mark_compact.cc index ce7c739c8d..e5bac5a9ba 100644 --- a/runtime/gc/collector/mark_compact.cc +++ b/runtime/gc/collector/mark_compact.cc @@ -93,7 +93,7 @@ using ::android::base::ParseBoolResult; } // namespace #endif -namespace art { +namespace art HIDDEN { static bool HaveMremapDontunmap() { const size_t page_size = GetPageSizeSlow(); diff --git a/runtime/gc/collector/mark_compact.h b/runtime/gc/collector/mark_compact.h index 4f0e6e04fa..076249bf11 100644 --- a/runtime/gc/collector/mark_compact.h +++ b/runtime/gc/collector/mark_compact.h @@ -37,9 +37,9 @@ #include "immune_spaces.h" #include "offsets.h" -namespace art { +namespace art HIDDEN { -bool KernelSupportsUffd(); +EXPORT bool KernelSupportsUffd(); namespace mirror { class DexCache; diff --git a/runtime/gc/collector/mark_sweep-inl.h b/runtime/gc/collector/mark_sweep-inl.h index 2257b0db8f..2eac037940 100644 --- a/runtime/gc/collector/mark_sweep-inl.h +++ b/runtime/gc/collector/mark_sweep-inl.h @@ -25,7 +25,7 @@ #include "mirror/object_array-inl.h" #include "mirror/reference.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace collector { diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc index fdaf5a2f57..984d71ca25 100644 --- a/runtime/gc/collector/mark_sweep.cc +++ b/runtime/gc/collector/mark_sweep.cc @@ -46,7 +46,7 @@ #include "thread-current-inl.h" #include "thread_list.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace collector { diff --git a/runtime/gc/collector/mark_sweep.h b/runtime/gc/collector/mark_sweep.h index 12fd7f9995..2a628a40fe 100644 --- a/runtime/gc/collector/mark_sweep.h +++ b/runtime/gc/collector/mark_sweep.h @@ -29,7 +29,7 @@ #include "immune_spaces.h" #include "offsets.h" -namespace art { +namespace art HIDDEN { namespace mirror { class Class; diff --git a/runtime/gc/collector/object_byte_pair.h b/runtime/gc/collector/object_byte_pair.h index 16ef06b6dd..06268b94ee 100644 --- a/runtime/gc/collector/object_byte_pair.h +++ b/runtime/gc/collector/object_byte_pair.h @@ -19,7 +19,9 @@ #include <inttypes.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { namespace gc { namespace collector { diff --git a/runtime/gc/collector/partial_mark_sweep.cc b/runtime/gc/collector/partial_mark_sweep.cc index e283a9583a..dc6d99e1dc 100644 --- a/runtime/gc/collector/partial_mark_sweep.cc +++ b/runtime/gc/collector/partial_mark_sweep.cc @@ -20,7 +20,7 @@ #include "gc/space/space.h" #include "thread-current-inl.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace collector { diff --git a/runtime/gc/collector/partial_mark_sweep.h b/runtime/gc/collector/partial_mark_sweep.h index 76c44a35bb..8b2c3a8d4c 100644 --- a/runtime/gc/collector/partial_mark_sweep.h +++ b/runtime/gc/collector/partial_mark_sweep.h @@ -19,7 +19,9 @@ #include "mark_sweep.h" -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { namespace gc { namespace collector { diff --git a/runtime/gc/collector/semi_space-inl.h b/runtime/gc/collector/semi_space-inl.h index ef6df08b45..8ef6512b58 100644 --- a/runtime/gc/collector/semi_space-inl.h +++ b/runtime/gc/collector/semi_space-inl.h @@ -22,7 +22,7 @@ #include "gc/accounting/heap_bitmap.h" #include "mirror/object-inl.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace collector { diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc index 397271b03d..77800c32e0 100644 --- a/runtime/gc/collector/semi_space.cc +++ b/runtime/gc/collector/semi_space.cc @@ -52,7 +52,7 @@ using ::art::mirror::Object; -namespace art { +namespace art HIDDEN { namespace gc { namespace collector { diff --git a/runtime/gc/collector/semi_space.h b/runtime/gc/collector/semi_space.h index 6d3ac0846e..b6d98ce84d 100644 --- a/runtime/gc/collector/semi_space.h +++ b/runtime/gc/collector/semi_space.h @@ -29,7 +29,7 @@ #include "mirror/object_reference.h" #include "offsets.h" -namespace art { +namespace art HIDDEN { class Thread; diff --git a/runtime/gc/collector/sticky_mark_sweep.cc b/runtime/gc/collector/sticky_mark_sweep.cc index e1bd16c1fb..96c13229c0 100644 --- a/runtime/gc/collector/sticky_mark_sweep.cc +++ b/runtime/gc/collector/sticky_mark_sweep.cc @@ -24,7 +24,7 @@ #include "runtime.h" #include "thread-current-inl.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace collector { diff --git a/runtime/gc/collector/sticky_mark_sweep.h b/runtime/gc/collector/sticky_mark_sweep.h index f65413d153..0c1cd2d114 100644 --- a/runtime/gc/collector/sticky_mark_sweep.h +++ b/runtime/gc/collector/sticky_mark_sweep.h @@ -20,7 +20,7 @@ #include "base/macros.h" #include "partial_mark_sweep.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace collector { diff --git a/runtime/gc/collector_type.h b/runtime/gc/collector_type.h index 290860136b..3c19079c08 100644 --- a/runtime/gc/collector_type.h +++ b/runtime/gc/collector_type.h @@ -19,7 +19,9 @@ #include <iosfwd> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { namespace gc { // Which types of collections are able to be performed. diff --git a/runtime/gc/gc_cause.cc b/runtime/gc/gc_cause.cc index 02fe2f975c..ec213e50e8 100644 --- a/runtime/gc/gc_cause.cc +++ b/runtime/gc/gc_cause.cc @@ -23,7 +23,7 @@ #include <ostream> -namespace art { +namespace art HIDDEN { namespace gc { const char* PrettyCause(GcCause cause) { diff --git a/runtime/gc/gc_cause.h b/runtime/gc/gc_cause.h index 5c039b31ee..e035510969 100644 --- a/runtime/gc/gc_cause.h +++ b/runtime/gc/gc_cause.h @@ -19,7 +19,9 @@ #include <iosfwd> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { namespace gc { // What caused the GC? diff --git a/runtime/gc/gc_pause_listener.h b/runtime/gc/gc_pause_listener.h index da35d2a0de..a626a3ca29 100644 --- a/runtime/gc/gc_pause_listener.h +++ b/runtime/gc/gc_pause_listener.h @@ -17,7 +17,9 @@ #ifndef ART_RUNTIME_GC_GC_PAUSE_LISTENER_H_ #define ART_RUNTIME_GC_GC_PAUSE_LISTENER_H_ -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { namespace gc { class GcPauseListener { diff --git a/runtime/gc/heap-inl.h b/runtime/gc/heap-inl.h index 9d4b4a0986..5d6e149b98 100644 --- a/runtime/gc/heap-inl.h +++ b/runtime/gc/heap-inl.h @@ -38,7 +38,7 @@ #include "verify_object.h" #include "write_barrier-inl.h" -namespace art { +namespace art HIDDEN { namespace gc { template <bool kInstrumented, bool kCheckLargeObject, typename PreFenceVisitor> diff --git a/runtime/gc/heap-visit-objects-inl.h b/runtime/gc/heap-visit-objects-inl.h index a235c44033..2b719ee241 100644 --- a/runtime/gc/heap-visit-objects-inl.h +++ b/runtime/gc/heap-visit-objects-inl.h @@ -29,7 +29,7 @@ #include "thread-current-inl.h" #include "thread_list.h" -namespace art { +namespace art HIDDEN { namespace gc { // Visit objects when threads aren't suspended. If concurrent moving diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index c10f41719a..b7821a3e98 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -108,7 +108,7 @@ #include "verify_object-inl.h" #include "well_known_classes.h" -namespace art { +namespace art HIDDEN { #ifdef ART_TARGET_ANDROID namespace { diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h index ab7a95f55a..d0944e0f55 100644 --- a/runtime/gc/heap.h +++ b/runtime/gc/heap.h @@ -49,7 +49,7 @@ #include "scoped_thread_state_change.h" #include "verify_object.h" -namespace art { +namespace art HIDDEN { class ConditionVariable; enum class InstructionSet; @@ -387,8 +387,8 @@ class Heap { bool IsMovableObject(ObjPtr<mirror::Object> obj) const REQUIRES_SHARED(Locks::mutator_lock_); // Enables us to compacting GC until objects are released. - void IncrementDisableMovingGC(Thread* self) REQUIRES(!*gc_complete_lock_); - void DecrementDisableMovingGC(Thread* self) REQUIRES(!*gc_complete_lock_); + EXPORT void IncrementDisableMovingGC(Thread* self) REQUIRES(!*gc_complete_lock_); + EXPORT void DecrementDisableMovingGC(Thread* self) REQUIRES(!*gc_complete_lock_); // Temporarily disable thread flip for JNI critical calls. void IncrementDisableThreadFlip(Thread* self) REQUIRES(!*thread_flip_lock_); @@ -407,7 +407,7 @@ class Heap { // Initiates an explicit garbage collection. Guarantees that a GC started after this call has // completed. - void CollectGarbage(bool clear_soft_references, GcCause cause = kGcCauseExplicit) + EXPORT void CollectGarbage(bool clear_soft_references, GcCause cause = kGcCauseExplicit) REQUIRES(!*gc_complete_lock_, !*pending_task_lock_, !process_state_update_lock_); // Does a concurrent GC, provided the GC numbered requested_gc_num has not already been @@ -485,7 +485,8 @@ class Heap { // Blocks the caller until the garbage collector becomes idle and returns the type of GC we // waited for. Only waits for running collections, ignoring a requested but unstarted GC. Only // heuristic, since a new GC may have started by the time we return. - collector::GcType WaitForGcToComplete(GcCause cause, Thread* self) REQUIRES(!*gc_complete_lock_); + EXPORT collector::GcType WaitForGcToComplete(GcCause cause, Thread* self) + REQUIRES(!*gc_complete_lock_); // Update the heap's process state to a new value, may cause compaction to occur. void UpdateProcessState(ProcessState old_process_state, ProcessState new_process_state) @@ -554,7 +555,7 @@ class Heap { return rb_table_.get(); } - void AddFinalizerReference(Thread* self, ObjPtr<mirror::Object>* object); + EXPORT void AddFinalizerReference(Thread* self, ObjPtr<mirror::Object>* object); // Returns the number of bytes currently allocated. // The result should be treated as an approximation, if it is being concurrently updated. @@ -605,7 +606,7 @@ class Heap { // Implements java.lang.Runtime.totalMemory, returning approximate amount of memory currently // consumed by an application. - size_t GetTotalMemory() const; + EXPORT size_t GetTotalMemory() const; // Returns approximately how much free memory we have until the next GC happens. size_t GetFreeMemoryUntilGC() const { @@ -628,7 +629,8 @@ class Heap { // Get the space that corresponds to an object's address. Current implementation searches all // spaces in turn. If fail_ok is false then failing to find a space will cause an abort. // TODO: consider using faster data structure like binary tree. - space::ContinuousSpace* FindContinuousSpaceFromObject(ObjPtr<mirror::Object>, bool fail_ok) const + EXPORT space::ContinuousSpace* FindContinuousSpaceFromObject(ObjPtr<mirror::Object>, + bool fail_ok) const REQUIRES_SHARED(Locks::mutator_lock_); space::ContinuousSpace* FindContinuousSpaceFromAddress(const mirror::Object* addr) const @@ -638,7 +640,7 @@ class Heap { bool fail_ok) const REQUIRES_SHARED(Locks::mutator_lock_); - space::Space* FindSpaceFromObject(ObjPtr<mirror::Object> obj, bool fail_ok) const + EXPORT space::Space* FindSpaceFromObject(ObjPtr<mirror::Object> obj, bool fail_ok) const REQUIRES_SHARED(Locks::mutator_lock_); space::Space* FindSpaceFromAddress(const void* ptr) const @@ -654,7 +656,7 @@ class Heap { REQUIRES(!*gc_complete_lock_, !*pending_task_lock_, !process_state_update_lock_); // Deflate monitors, ... and trim the spaces. - void Trim(Thread* self) REQUIRES(!*gc_complete_lock_); + EXPORT void Trim(Thread* self) REQUIRES(!*gc_complete_lock_); void RevokeThreadLocalBuffers(Thread* thread); void RevokeRosAllocThreadLocalBuffers(Thread* thread); @@ -683,12 +685,11 @@ class Heap { void PreZygoteFork() NO_THREAD_SAFETY_ANALYSIS; // Mark and empty stack. - void FlushAllocStack() - REQUIRES_SHARED(Locks::mutator_lock_) + EXPORT void FlushAllocStack() REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::heap_bitmap_lock_); // Revoke all the thread-local allocation stacks. - void RevokeAllThreadLocalAllocationStacks(Thread* self) + EXPORT void RevokeAllThreadLocalAllocationStacks(Thread* self) REQUIRES(Locks::mutator_lock_, !Locks::runtime_shutdown_lock_, !Locks::thread_list_lock_); // Mark all the objects in the allocation stack in the specified bitmap. @@ -715,7 +716,9 @@ class Heap { return boot_image_spaces_; } - bool ObjectIsInBootImageSpace(ObjPtr<mirror::Object> obj) const + // TODO(b/260881207): refactor to only use this function in debug builds and + // remove EXPORT. + EXPORT bool ObjectIsInBootImageSpace(ObjPtr<mirror::Object> obj) const REQUIRES_SHARED(Locks::mutator_lock_); bool IsInBootImageOatFile(const void* p) const @@ -772,7 +775,7 @@ class Heap { } void DumpSpaces(std::ostream& stream) const REQUIRES_SHARED(Locks::mutator_lock_); - std::string DumpSpaces() const REQUIRES_SHARED(Locks::mutator_lock_); + EXPORT std::string DumpSpaces() const REQUIRES_SHARED(Locks::mutator_lock_); // GC performance measuring void DumpGcPerformanceInfo(std::ostream& os) @@ -921,9 +924,7 @@ class Heap { // Also update state (bytes_until_sample). // By calling JHPCheckNonTlabSampleAllocation from different functions for Large allocations and // non-moving allocations we are able to use the stack to identify these allocations separately. - void JHPCheckNonTlabSampleAllocation(Thread* self, - mirror::Object* ret, - size_t alloc_size); + EXPORT void JHPCheckNonTlabSampleAllocation(Thread* self, mirror::Object* ret, size_t alloc_size); // In Tlab case: Calculate the next tlab size (location of next sample point) and whether // a sample should be taken. size_t JHPCalculateNextTlabSize(Thread* self, @@ -984,31 +985,31 @@ class Heap { bool IsGCDisabledForShutdown() const REQUIRES(!*gc_complete_lock_); // Create a new alloc space and compact default alloc space to it. - HomogeneousSpaceCompactResult PerformHomogeneousSpaceCompact() + EXPORT HomogeneousSpaceCompactResult PerformHomogeneousSpaceCompact() REQUIRES(!*gc_complete_lock_, !process_state_update_lock_); - bool SupportHomogeneousSpaceCompactAndCollectorTransitions() const; + EXPORT bool SupportHomogeneousSpaceCompactAndCollectorTransitions() const; // Install an allocation listener. - void SetAllocationListener(AllocationListener* l); + EXPORT void SetAllocationListener(AllocationListener* l); // Remove an allocation listener. Note: the listener must not be deleted, as for performance // reasons, we assume it stays valid when we read it (so that we don't require a lock). - void RemoveAllocationListener(); + EXPORT void RemoveAllocationListener(); // Install a gc pause listener. - void SetGcPauseListener(GcPauseListener* l); + EXPORT void SetGcPauseListener(GcPauseListener* l); // Get the currently installed gc pause listener, or null. GcPauseListener* GetGcPauseListener() { return gc_pause_listener_.load(std::memory_order_acquire); } // Remove a gc pause listener. Note: the listener must not be deleted, as for performance // reasons, we assume it stays valid when we read it (so that we don't require a lock). - void RemoveGcPauseListener(); + EXPORT void RemoveGcPauseListener(); - const Verification* GetVerification() const; + EXPORT const Verification* GetVerification() const; void PostForkChildAction(Thread* self) REQUIRES(!*gc_complete_lock_); - void TraceHeapSize(size_t heap_size); + EXPORT void TraceHeapSize(size_t heap_size); bool AddHeapTask(gc::HeapTask* task); @@ -1114,17 +1115,16 @@ class Heap { // attempt failed. // Called with thread suspension disallowed, but re-enables it, and may suspend, internally. // Returns null if instrumentation or the allocator changed. - mirror::Object* AllocateInternalWithGc(Thread* self, - AllocatorType allocator, - bool instrumented, - size_t num_bytes, - size_t* bytes_allocated, - size_t* usable_size, - size_t* bytes_tl_bulk_allocated, - ObjPtr<mirror::Class>* klass) + EXPORT mirror::Object* AllocateInternalWithGc(Thread* self, + AllocatorType allocator, + bool instrumented, + size_t num_bytes, + size_t* bytes_allocated, + size_t* usable_size, + size_t* bytes_tl_bulk_allocated, + ObjPtr<mirror::Class>* klass) REQUIRES(!Locks::thread_suspend_count_lock_, !*gc_complete_lock_, !*pending_task_lock_) - REQUIRES(Roles::uninterruptible_) - REQUIRES_SHARED(Locks::mutator_lock_); + REQUIRES(Roles::uninterruptible_) REQUIRES_SHARED(Locks::mutator_lock_); // Allocate into a specific space. mirror::Object* AllocateInto(Thread* self, @@ -1148,13 +1148,13 @@ class Heap { size_t* bytes_tl_bulk_allocated) REQUIRES_SHARED(Locks::mutator_lock_); - mirror::Object* AllocWithNewTLAB(Thread* self, - AllocatorType allocator_type, - size_t alloc_size, - bool grow, - size_t* bytes_allocated, - size_t* usable_size, - size_t* bytes_tl_bulk_allocated) + EXPORT mirror::Object* AllocWithNewTLAB(Thread* self, + AllocatorType allocator_type, + size_t alloc_size, + bool grow, + size_t* bytes_allocated, + size_t* usable_size, + size_t* bytes_tl_bulk_allocated) REQUIRES_SHARED(Locks::mutator_lock_); void ThrowOutOfMemoryError(Thread* self, size_t byte_count, AllocatorType allocator_type) @@ -1177,12 +1177,11 @@ class Heap { void RequestCollectorTransition(CollectorType desired_collector_type, uint64_t delta_time) REQUIRES(!*pending_task_lock_); - void RequestConcurrentGCAndSaveObject(Thread* self, - bool force_full, - uint32_t observed_gc_num, - ObjPtr<mirror::Object>* obj) - REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!*pending_task_lock_); + EXPORT void RequestConcurrentGCAndSaveObject(Thread* self, + bool force_full, + uint32_t observed_gc_num, + ObjPtr<mirror::Object>* obj) + REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!*pending_task_lock_); static constexpr uint32_t GC_NUM_ANY = std::numeric_limits<uint32_t>::max(); @@ -1261,9 +1260,10 @@ class Heap { void PushOnAllocationStackWithInternalGC(Thread* self, ObjPtr<mirror::Object>* obj) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!*gc_complete_lock_, !*pending_task_lock_, !process_state_update_lock_); - void PushOnThreadLocalAllocationStackWithInternalGC(Thread* thread, ObjPtr<mirror::Object>* obj) + EXPORT void PushOnThreadLocalAllocationStackWithInternalGC(Thread* thread, + ObjPtr<mirror::Object>* obj) REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!*gc_complete_lock_, !*pending_task_lock_, !process_state_update_lock_); + REQUIRES(!*gc_complete_lock_, !*pending_task_lock_, !process_state_update_lock_); void ClearPendingTrim(Thread* self) REQUIRES(!*pending_task_lock_); void ClearPendingCollectorTransition(Thread* self) REQUIRES(!*pending_task_lock_); @@ -1294,10 +1294,11 @@ class Heap { void UpdateGcCountRateHistograms() REQUIRES(gc_complete_lock_); // GC stress mode attempts to do one GC per unique backtrace. - void CheckGcStressMode(Thread* self, ObjPtr<mirror::Object>* obj) - REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!*gc_complete_lock_, !*pending_task_lock_, - !*backtrace_lock_, !process_state_update_lock_); + EXPORT void CheckGcStressMode(Thread* self, ObjPtr<mirror::Object>* obj) + REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!*gc_complete_lock_, + !*pending_task_lock_, + !*backtrace_lock_, + !process_state_update_lock_); collector::GcType NonStickyGcType() const { return HasZygoteSpace() ? collector::kGcTypePartial : collector::kGcTypeFull; @@ -1322,7 +1323,9 @@ class Heap { void IncrementFreedEver(); // Remove a vlog code from heap-inl.h which is transitively included in half the world. - static void VlogHeapGrowth(size_t max_allowed_footprint, size_t new_footprint, size_t alloc_size); + EXPORT static void VlogHeapGrowth(size_t max_allowed_footprint, + size_t new_footprint, + size_t alloc_size); // Return our best approximation of the number of bytes of native memory that // are currently in use, and could possibly be reclaimed as an indirect result diff --git a/runtime/gc/heap_test.cc b/runtime/gc/heap_test.cc index 42ba911062..bd8fdc6b46 100644 --- a/runtime/gc/heap_test.cc +++ b/runtime/gc/heap_test.cc @@ -28,7 +28,7 @@ #include "mirror/object_array-inl.h" #include "scoped_thread_state_change-inl.h" -namespace art { +namespace art HIDDEN { namespace gc { class HeapTest : public CommonRuntimeTest { diff --git a/runtime/gc/heap_verification_test.cc b/runtime/gc/heap_verification_test.cc index a7583fe7f1..168feefea0 100644 --- a/runtime/gc/heap_verification_test.cc +++ b/runtime/gc/heap_verification_test.cc @@ -28,7 +28,7 @@ #include "scoped_thread_state_change-inl.h" #include "verification-inl.h" -namespace art { +namespace art HIDDEN { namespace gc { class VerificationTest : public CommonRuntimeTest { diff --git a/runtime/gc/reference_processor.cc b/runtime/gc/reference_processor.cc index f24c94279c..cb777c895c 100644 --- a/runtime/gc/reference_processor.cc +++ b/runtime/gc/reference_processor.cc @@ -36,7 +36,7 @@ #include "thread_pool.h" #include "well_known_classes.h" -namespace art { +namespace art HIDDEN { namespace gc { static constexpr bool kAsyncReferenceQueueAdd = false; diff --git a/runtime/gc/reference_processor.h b/runtime/gc/reference_processor.h index 0f84211a87..48aff6c2a2 100644 --- a/runtime/gc/reference_processor.h +++ b/runtime/gc/reference_processor.h @@ -17,12 +17,13 @@ #ifndef ART_RUNTIME_GC_REFERENCE_PROCESSOR_H_ #define ART_RUNTIME_GC_REFERENCE_PROCESSOR_H_ +#include "base/macros.h" #include "base/locks.h" #include "jni.h" #include "reference_queue.h" #include "runtime_globals.h" -namespace art { +namespace art HIDDEN { class IsMarkedVisitor; class TimingLogger; diff --git a/runtime/gc/reference_queue.cc b/runtime/gc/reference_queue.cc index 53eef9c027..82fd89ecb1 100644 --- a/runtime/gc/reference_queue.cc +++ b/runtime/gc/reference_queue.cc @@ -25,7 +25,7 @@ #include "mirror/reference-inl.h" #include "object_callbacks.h" -namespace art { +namespace art HIDDEN { namespace gc { ReferenceQueue::ReferenceQueue(Mutex* lock) : lock_(lock), list_(nullptr) { diff --git a/runtime/gc/reference_queue.h b/runtime/gc/reference_queue.h index 69f04d783a..d43eb347a9 100644 --- a/runtime/gc/reference_queue.h +++ b/runtime/gc/reference_queue.h @@ -23,6 +23,7 @@ #include "base/atomic.h" #include "base/locks.h" +#include "base/macros.h" #include "base/timing_logger.h" #include "jni.h" #include "obj_ptr.h" @@ -30,7 +31,7 @@ #include "runtime_globals.h" #include "thread_pool.h" -namespace art { +namespace art HIDDEN { class Mutex; diff --git a/runtime/gc/reference_queue_test.cc b/runtime/gc/reference_queue_test.cc index c8e71b02ac..2b5c3fdea7 100644 --- a/runtime/gc/reference_queue_test.cc +++ b/runtime/gc/reference_queue_test.cc @@ -23,7 +23,7 @@ #include "reference_queue.h" #include "scoped_thread_state_change-inl.h" -namespace art { +namespace art HIDDEN { namespace gc { class ReferenceQueueTest : public CommonRuntimeTest { diff --git a/runtime/gc/scoped_gc_critical_section.cc b/runtime/gc/scoped_gc_critical_section.cc index 7a0a6e8736..368649a563 100644 --- a/runtime/gc/scoped_gc_critical_section.cc +++ b/runtime/gc/scoped_gc_critical_section.cc @@ -21,7 +21,7 @@ #include "runtime.h" #include "thread-current-inl.h" -namespace art { +namespace art HIDDEN { namespace gc { const char* GCCriticalSection::Enter(GcCause cause, CollectorType type) { diff --git a/runtime/gc/scoped_gc_critical_section.h b/runtime/gc/scoped_gc_critical_section.h index 8ad01580c2..8481767667 100644 --- a/runtime/gc/scoped_gc_critical_section.h +++ b/runtime/gc/scoped_gc_critical_section.h @@ -18,10 +18,11 @@ #define ART_RUNTIME_GC_SCOPED_GC_CRITICAL_SECTION_H_ #include "base/locks.h" +#include "base/macros.h" #include "collector_type.h" #include "gc_cause.h" -namespace art { +namespace art HIDDEN { class Thread; @@ -35,10 +36,10 @@ class GCCriticalSection { ~GCCriticalSection() {} // Starts a GCCriticalSection. Returns the previous no-suspension reason. - const char* Enter(GcCause cause, CollectorType type) ACQUIRE(Roles::uninterruptible_); + EXPORT const char* Enter(GcCause cause, CollectorType type) ACQUIRE(Roles::uninterruptible_); // Ends a GCCriticalSection. Takes the old no-suspension reason. - void Exit(const char* old_reason) RELEASE(Roles::uninterruptible_); + EXPORT void Exit(const char* old_reason) RELEASE(Roles::uninterruptible_); private: Thread* const self_; @@ -50,9 +51,9 @@ class GCCriticalSection { // suspended. class ScopedGCCriticalSection { public: - ScopedGCCriticalSection(Thread* self, GcCause cause, CollectorType collector_type) + EXPORT ScopedGCCriticalSection(Thread* self, GcCause cause, CollectorType collector_type) ACQUIRE(Roles::uninterruptible_); - ~ScopedGCCriticalSection() RELEASE(Roles::uninterruptible_); + EXPORT ~ScopedGCCriticalSection() RELEASE(Roles::uninterruptible_); private: GCCriticalSection critical_section_; diff --git a/runtime/gc/space/bump_pointer_space-inl.h b/runtime/gc/space/bump_pointer_space-inl.h index 2774b9e71c..6751344bc4 100644 --- a/runtime/gc/space/bump_pointer_space-inl.h +++ b/runtime/gc/space/bump_pointer_space-inl.h @@ -22,7 +22,7 @@ #include "base/bit_utils.h" #include "mirror/object-inl.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace space { diff --git a/runtime/gc/space/bump_pointer_space-walk-inl.h b/runtime/gc/space/bump_pointer_space-walk-inl.h index 89e42bcf27..86af0451de 100644 --- a/runtime/gc/space/bump_pointer_space-walk-inl.h +++ b/runtime/gc/space/bump_pointer_space-walk-inl.h @@ -25,7 +25,7 @@ #include <memory> -namespace art { +namespace art HIDDEN { namespace gc { namespace space { diff --git a/runtime/gc/space/bump_pointer_space.cc b/runtime/gc/space/bump_pointer_space.cc index aa85ba1247..17e08357e8 100644 --- a/runtime/gc/space/bump_pointer_space.cc +++ b/runtime/gc/space/bump_pointer_space.cc @@ -20,7 +20,7 @@ #include "mirror/object-inl.h" #include "thread_list.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace space { diff --git a/runtime/gc/space/bump_pointer_space.h b/runtime/gc/space/bump_pointer_space.h index d5ab5069ec..77beb476e6 100644 --- a/runtime/gc/space/bump_pointer_space.h +++ b/runtime/gc/space/bump_pointer_space.h @@ -22,7 +22,7 @@ #include <deque> -namespace art { +namespace art HIDDEN { namespace mirror { class Object; @@ -39,7 +39,7 @@ namespace space { // A bump pointer space allocates by incrementing a pointer, it doesn't provide a free // implementation as its intended to be evacuated. -class BumpPointerSpace final : public ContinuousMemMapAllocSpace { +class EXPORT BumpPointerSpace final : public ContinuousMemMapAllocSpace { public: using WalkCallback = void (*)(void *, void *, int, void *); diff --git a/runtime/gc/space/dlmalloc_space-inl.h b/runtime/gc/space/dlmalloc_space-inl.h index 6041fd02af..0d9467314b 100644 --- a/runtime/gc/space/dlmalloc_space-inl.h +++ b/runtime/gc/space/dlmalloc_space-inl.h @@ -21,7 +21,7 @@ #include "gc/allocator/art-dlmalloc.h" #include "thread.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace space { diff --git a/runtime/gc/space/dlmalloc_space.cc b/runtime/gc/space/dlmalloc_space.cc index e5253cd697..b45e4824ed 100644 --- a/runtime/gc/space/dlmalloc_space.cc +++ b/runtime/gc/space/dlmalloc_space.cc @@ -16,6 +16,8 @@ #include "dlmalloc_space-inl.h" +#include <sys/mman.h> + #include "base/logging.h" // For VLOG. #include "base/time_utils.h" #include "base/utils.h" @@ -32,12 +34,60 @@ #include "thread.h" #include "thread_list.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace space { static constexpr bool kPrefetchDuringDlMallocFreeList = true; +// Callback for mspace_inspect_all that will madvise(2) unused pages back to +// the kernel. +void DlmallocMadviseCallback(void* start, void* end, size_t used_bytes, void* arg) { + // Is this chunk in use? + if (used_bytes != 0) { + return; + } + // Do we have any whole pages to give back? + start = reinterpret_cast<void*>(art::RoundUp(reinterpret_cast<uintptr_t>(start), art::gPageSize)); + end = reinterpret_cast<void*>(art::RoundDown(reinterpret_cast<uintptr_t>(end), art::gPageSize)); + if (end > start) { + size_t length = reinterpret_cast<uint8_t*>(end) - reinterpret_cast<uint8_t*>(start); + int rc = madvise(start, length, MADV_DONTNEED); + if (UNLIKELY(rc != 0)) { + errno = rc; + PLOG(FATAL) << "madvise failed during heap trimming"; + } + size_t* reclaimed = reinterpret_cast<size_t*>(arg); + *reclaimed += length; + } +} + +// Callback for mspace_inspect_all that will count the number of bytes +// allocated. +void DlmallocBytesAllocatedCallback([[maybe_unused]] void* start, + [[maybe_unused]] void* end, + size_t used_bytes, + void* arg) { + if (used_bytes == 0) { + return; + } + size_t* bytes_allocated = reinterpret_cast<size_t*>(arg); + *bytes_allocated += used_bytes + sizeof(size_t); +} + +// Callback for mspace_inspect_all that will count the number of objects +// allocated. +void DlmallocObjectsAllocatedCallback([[maybe_unused]] void* start, + [[maybe_unused]] void* end, + size_t used_bytes, + void* arg) { + if (used_bytes == 0) { + return; + } + size_t* objects_allocated = reinterpret_cast<size_t*>(arg); + ++(*objects_allocated); +} + DlMallocSpace::DlMallocSpace(MemMap&& mem_map, size_t initial_size, const std::string& name, diff --git a/runtime/gc/space/dlmalloc_space.h b/runtime/gc/space/dlmalloc_space.h index 429b4d035a..774d2e3c80 100644 --- a/runtime/gc/space/dlmalloc_space.h +++ b/runtime/gc/space/dlmalloc_space.h @@ -20,7 +20,7 @@ #include "malloc_space.h" #include "space.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace collector { @@ -188,6 +188,14 @@ class DlMallocSpace : public MallocSpace { }; } // namespace space + +namespace allocator { + +// Callback from dlmalloc when it needs to increase the footprint. +// Must be implemented outside of art-dlmalloc.cc. +void* ArtDlMallocMoreCore(void* mspace, intptr_t increment); + +} // namespace allocator } // namespace gc } // namespace art diff --git a/runtime/gc/space/dlmalloc_space_random_test.cc b/runtime/gc/space/dlmalloc_space_random_test.cc index b653bcf03a..bcca442fb8 100644 --- a/runtime/gc/space/dlmalloc_space_random_test.cc +++ b/runtime/gc/space/dlmalloc_space_random_test.cc @@ -18,7 +18,7 @@ #include "dlmalloc_space.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace space { namespace { diff --git a/runtime/gc/space/dlmalloc_space_static_test.cc b/runtime/gc/space/dlmalloc_space_static_test.cc index 74dd765dfd..c07a8eaa8b 100644 --- a/runtime/gc/space/dlmalloc_space_static_test.cc +++ b/runtime/gc/space/dlmalloc_space_static_test.cc @@ -18,7 +18,7 @@ #include "dlmalloc_space.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace space { namespace { diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index 7d0bb1b674..3314c14fca 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -69,7 +69,7 @@ #include "runtime.h" #include "space-inl.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace space { diff --git a/runtime/gc/space/image_space.h b/runtime/gc/space/image_space.h index 5271489fc6..63a47c86c1 100644 --- a/runtime/gc/space/image_space.h +++ b/runtime/gc/space/image_space.h @@ -24,7 +24,7 @@ #include "runtime.h" #include "space.h" -namespace art { +namespace art HIDDEN { class DexFile; enum class InstructionSet; @@ -152,9 +152,9 @@ class ImageSpace : public MemMapSpace { // Try to open an existing app image space for an oat file, // using the boot image spaces from the current Runtime. - static std::unique_ptr<ImageSpace> CreateFromAppImage(const char* image, - const OatFile* oat_file, - std::string* error_msg) + EXPORT static std::unique_ptr<ImageSpace> CreateFromAppImage(const char* image, + const OatFile* oat_file, + std::string* error_msg) REQUIRES_SHARED(Locks::mutator_lock_); // Try to open an existing app image space for an the oat file and given boot image spaces. static std::unique_ptr<ImageSpace> CreateFromAppImage( @@ -167,7 +167,7 @@ class ImageSpace : public MemMapSpace { static bool IsBootClassPathOnDisk(InstructionSet image_isa); // Give access to the OatFile. - const OatFile* GetOatFile() const; + EXPORT const OatFile* GetOatFile() const; // Releases the OatFile from the ImageSpace so it can be transfer to // the caller, presumably the OatFileManager. @@ -238,8 +238,8 @@ class ImageSpace : public MemMapSpace { // Returns the checksums for the boot image, extensions and extra boot class path dex files, // based on the image spaces and boot class path dex files loaded in memory. // The `image_spaces` must correspond to the head of the `boot_class_path`. - static std::string GetBootClassPathChecksums(ArrayRef<ImageSpace* const> image_spaces, - ArrayRef<const DexFile* const> boot_class_path); + EXPORT static std::string GetBootClassPathChecksums( + ArrayRef<ImageSpace* const> image_spaces, ArrayRef<const DexFile* const> boot_class_path); // Returns the total number of components (jar files) associated with the image spaces. static size_t GetNumberOfComponents(ArrayRef<gc::space::ImageSpace* const> image_spaces); @@ -255,7 +255,7 @@ class ImageSpace : public MemMapSpace { /*out*/std::string* error_msg); // Expand a single image location to multi-image locations based on the dex locations. - static std::vector<std::string> ExpandMultiImageLocations( + EXPORT static std::vector<std::string> ExpandMultiImageLocations( ArrayRef<const std::string> dex_locations, const std::string& image_location, bool boot_image_extension = false); diff --git a/runtime/gc/space/image_space_test.cc b/runtime/gc/space/image_space_test.cc index 8fb39e849b..e6b758fe55 100644 --- a/runtime/gc/space/image_space_test.cc +++ b/runtime/gc/space/image_space_test.cc @@ -28,7 +28,7 @@ #include "noop_compiler_callbacks.h" #include "oat_file.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace space { diff --git a/runtime/gc/space/large_object_space.cc b/runtime/gc/space/large_object_space.cc index b0db30b176..3d9fd5a620 100644 --- a/runtime/gc/space/large_object_space.cc +++ b/runtime/gc/space/large_object_space.cc @@ -36,7 +36,7 @@ #include "space-inl.h" #include "thread-current-inl.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace space { diff --git a/runtime/gc/space/large_object_space.h b/runtime/gc/space/large_object_space.h index 5588f5f7c6..ae1526d818 100644 --- a/runtime/gc/space/large_object_space.h +++ b/runtime/gc/space/large_object_space.h @@ -27,7 +27,7 @@ #include <set> #include <vector> -namespace art { +namespace art HIDDEN { namespace gc { namespace space { diff --git a/runtime/gc/space/large_object_space_test.cc b/runtime/gc/space/large_object_space_test.cc index 99a67c5812..1d1bc6e683 100644 --- a/runtime/gc/space/large_object_space_test.cc +++ b/runtime/gc/space/large_object_space_test.cc @@ -19,7 +19,7 @@ #include "base/time_utils.h" #include "space_test.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace space { diff --git a/runtime/gc/space/malloc_space.cc b/runtime/gc/space/malloc_space.cc index b25c4fab38..ca2991a8b8 100644 --- a/runtime/gc/space/malloc_space.cc +++ b/runtime/gc/space/malloc_space.cc @@ -35,7 +35,7 @@ #include "thread.h" #include "thread_list.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace space { diff --git a/runtime/gc/space/malloc_space.h b/runtime/gc/space/malloc_space.h index 59ab3f3214..73ce4e7436 100644 --- a/runtime/gc/space/malloc_space.h +++ b/runtime/gc/space/malloc_space.h @@ -24,7 +24,7 @@ #include "base/memory_tool.h" #include "base/mutex.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace collector { diff --git a/runtime/gc/space/memory_tool_malloc_space-inl.h b/runtime/gc/space/memory_tool_malloc_space-inl.h index ba088893f7..3fc2b7ab40 100644 --- a/runtime/gc/space/memory_tool_malloc_space-inl.h +++ b/runtime/gc/space/memory_tool_malloc_space-inl.h @@ -23,7 +23,7 @@ #include "memory_tool_settings.h" #include "mirror/object-inl.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace space { diff --git a/runtime/gc/space/memory_tool_malloc_space.h b/runtime/gc/space/memory_tool_malloc_space.h index ce72b5b435..c76bb9c4ad 100644 --- a/runtime/gc/space/memory_tool_malloc_space.h +++ b/runtime/gc/space/memory_tool_malloc_space.h @@ -19,7 +19,7 @@ #include "malloc_space.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace space { diff --git a/runtime/gc/space/memory_tool_settings.h b/runtime/gc/space/memory_tool_settings.h index e9333c8c97..6fe4f59c34 100644 --- a/runtime/gc/space/memory_tool_settings.h +++ b/runtime/gc/space/memory_tool_settings.h @@ -17,7 +17,7 @@ #ifndef ART_RUNTIME_GC_SPACE_MEMORY_TOOL_SETTINGS_H_ #define ART_RUNTIME_GC_SPACE_MEMORY_TOOL_SETTINGS_H_ -namespace art { +namespace art HIDDEN { namespace gc { namespace space { diff --git a/runtime/gc/space/region_space-inl.h b/runtime/gc/space/region_space-inl.h index 4376137cb4..d67fc0ef47 100644 --- a/runtime/gc/space/region_space-inl.h +++ b/runtime/gc/space/region_space-inl.h @@ -22,7 +22,7 @@ #include "region_space.h" #include "thread-current-inl.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace space { diff --git a/runtime/gc/space/region_space.cc b/runtime/gc/space/region_space.cc index 49ea2d64e6..e891739ec7 100644 --- a/runtime/gc/space/region_space.cc +++ b/runtime/gc/space/region_space.cc @@ -24,7 +24,7 @@ #include "mirror/object-inl.h" #include "thread_list.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace space { diff --git a/runtime/gc/space/region_space.h b/runtime/gc/space/region_space.h index 98f2060df1..c6b68250fc 100644 --- a/runtime/gc/space/region_space.h +++ b/runtime/gc/space/region_space.h @@ -25,7 +25,7 @@ #include <functional> #include <map> -namespace art { +namespace art HIDDEN { namespace gc { namespace accounting { @@ -99,7 +99,7 @@ class RegionSpace final : public ContinuousMemMapAllocSpace { REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!region_lock_) { return AllocationSizeNonvirtual(obj, usable_size); } - size_t AllocationSizeNonvirtual(mirror::Object* obj, size_t* usable_size) + EXPORT size_t AllocationSizeNonvirtual(mirror::Object* obj, size_t* usable_size) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!region_lock_); size_t Free(Thread*, mirror::Object*) override { @@ -117,7 +117,7 @@ class RegionSpace final : public ContinuousMemMapAllocSpace { return &mark_bitmap_; } - void Clear() override REQUIRES(!region_lock_); + EXPORT void Clear() override REQUIRES(!region_lock_); // Remove read and write memory protection from the whole region space, // i.e. make memory pages backing the region area not readable and not @@ -128,7 +128,7 @@ class RegionSpace final : public ContinuousMemMapAllocSpace { // pages backing the region area readable and writable. This method is useful // to avoid page protection faults when dumping information about an invalid // reference. - void Unprotect(); + EXPORT void Unprotect(); // Change the non growth limit capacity to new capacity by shrinking or expanding the map. // Currently, only shrinking is supported. @@ -137,15 +137,15 @@ class RegionSpace final : public ContinuousMemMapAllocSpace { // growth limit. void ClampGrowthLimit(size_t new_capacity) REQUIRES(!region_lock_); - void Dump(std::ostream& os) const override; + EXPORT void Dump(std::ostream& os) const override; void DumpRegions(std::ostream& os) REQUIRES(!region_lock_); // Dump region containing object `obj`. Precondition: `obj` is in the region space. void DumpRegionForObject(std::ostream& os, mirror::Object* obj) REQUIRES(!region_lock_); - void DumpNonFreeRegions(std::ostream& os) REQUIRES(!region_lock_); + EXPORT void DumpNonFreeRegions(std::ostream& os) REQUIRES(!region_lock_); - size_t RevokeThreadLocalBuffers(Thread* thread) override REQUIRES(!region_lock_); + EXPORT size_t RevokeThreadLocalBuffers(Thread* thread) override REQUIRES(!region_lock_); size_t RevokeThreadLocalBuffers(Thread* thread, const bool reuse) REQUIRES(!region_lock_); - size_t RevokeAllThreadLocalBuffers() override + EXPORT size_t RevokeAllThreadLocalBuffers() override REQUIRES(!Locks::runtime_shutdown_lock_, !Locks::thread_list_lock_, !region_lock_); void AssertThreadLocalBuffersAreRevoked(Thread* thread) REQUIRES(!region_lock_); void AssertAllThreadLocalBuffersAreRevoked() @@ -227,7 +227,7 @@ class RegionSpace final : public ContinuousMemMapAllocSpace { accounting::ContinuousSpaceBitmap::SweepCallback* GetSweepCallback() override { return nullptr; } - bool LogFragmentationAllocFailure(std::ostream& os, size_t failed_alloc_bytes) override + EXPORT bool LogFragmentationAllocFailure(std::ostream& os, size_t failed_alloc_bytes) override REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!region_lock_); // Object alignment within the space. @@ -453,11 +453,11 @@ class RegionSpace final : public ContinuousMemMapAllocSpace { REQUIRES(region_space->region_lock_); // Given a free region, declare it non-free (allocated) and large. - void UnfreeLarge(RegionSpace* region_space, uint32_t alloc_time) + EXPORT void UnfreeLarge(RegionSpace* region_space, uint32_t alloc_time) REQUIRES(region_space->region_lock_); // Given a free region, declare it non-free (allocated) and large tail. - void UnfreeLargeTail(RegionSpace* region_space, uint32_t alloc_time) + EXPORT void UnfreeLargeTail(RegionSpace* region_space, uint32_t alloc_time) REQUIRES(region_space->region_lock_); void MarkAsAllocated(RegionSpace* region_space, uint32_t alloc_time) @@ -715,7 +715,7 @@ class RegionSpace final : public ContinuousMemMapAllocSpace { } } - Region* AllocateRegion(bool for_evac) REQUIRES(region_lock_); + EXPORT Region* AllocateRegion(bool for_evac) REQUIRES(region_lock_); void RevokeThreadLocalBuffersLocked(Thread* thread, bool reuse) REQUIRES(region_lock_); // Scan region range [`begin`, `end`) in increasing order to try to diff --git a/runtime/gc/space/rosalloc_space-inl.h b/runtime/gc/space/rosalloc_space-inl.h index 09aa7cf8a3..f37376377e 100644 --- a/runtime/gc/space/rosalloc_space-inl.h +++ b/runtime/gc/space/rosalloc_space-inl.h @@ -24,7 +24,7 @@ #include "gc/space/memory_tool_settings.h" #include "thread.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace space { diff --git a/runtime/gc/space/rosalloc_space.cc b/runtime/gc/space/rosalloc_space.cc index 86a5d3a794..2639755015 100644 --- a/runtime/gc/space/rosalloc_space.cc +++ b/runtime/gc/space/rosalloc_space.cc @@ -31,7 +31,7 @@ #include "thread.h" #include "thread_list.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace space { diff --git a/runtime/gc/space/rosalloc_space.h b/runtime/gc/space/rosalloc_space.h index 7becea0828..712b344a4f 100644 --- a/runtime/gc/space/rosalloc_space.h +++ b/runtime/gc/space/rosalloc_space.h @@ -21,7 +21,7 @@ #include "malloc_space.h" #include "space.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace collector { diff --git a/runtime/gc/space/rosalloc_space_random_test.cc b/runtime/gc/space/rosalloc_space_random_test.cc index 3010b775f3..211c6be515 100644 --- a/runtime/gc/space/rosalloc_space_random_test.cc +++ b/runtime/gc/space/rosalloc_space_random_test.cc @@ -18,7 +18,7 @@ #include "rosalloc_space.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace space { namespace { diff --git a/runtime/gc/space/rosalloc_space_static_test.cc b/runtime/gc/space/rosalloc_space_static_test.cc index 860a4615e4..fcb03cec65 100644 --- a/runtime/gc/space/rosalloc_space_static_test.cc +++ b/runtime/gc/space/rosalloc_space_static_test.cc @@ -18,7 +18,7 @@ #include "rosalloc_space.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace space { namespace { diff --git a/runtime/gc/space/space-inl.h b/runtime/gc/space/space-inl.h index 3ea68cf9ca..d5fb081a78 100644 --- a/runtime/gc/space/space-inl.h +++ b/runtime/gc/space/space-inl.h @@ -24,7 +24,7 @@ #include "image_space.h" #include "large_object_space.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace space { diff --git a/runtime/gc/space/space.cc b/runtime/gc/space/space.cc index cae9ce8f06..5fc09b83df 100644 --- a/runtime/gc/space/space.cc +++ b/runtime/gc/space/space.cc @@ -25,7 +25,7 @@ #include "runtime.h" #include "thread-current-inl.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace space { diff --git a/runtime/gc/space/space.h b/runtime/gc/space/space.h index 160c73097c..abe26b4e26 100644 --- a/runtime/gc/space/space.h +++ b/runtime/gc/space/space.h @@ -28,7 +28,7 @@ #include "gc/collector/object_byte_pair.h" #include "runtime_globals.h" -namespace art { +namespace art HIDDEN { namespace mirror { class Object; } // namespace mirror @@ -77,7 +77,7 @@ enum SpaceType { std::ostream& operator<<(std::ostream& os, SpaceType space_type); // A space contains memory allocated for managed objects. -class Space { +class EXPORT Space { public: // Dump space. Also key method for C++ vtables. virtual void Dump(std::ostream& os) const; diff --git a/runtime/gc/space/space_create_test.cc b/runtime/gc/space/space_create_test.cc index 25bc12e85b..83568351b3 100644 --- a/runtime/gc/space/space_create_test.cc +++ b/runtime/gc/space/space_create_test.cc @@ -20,7 +20,7 @@ #include "rosalloc_space.h" #include "scoped_thread_state_change-inl.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace space { diff --git a/runtime/gc/space/space_test.h b/runtime/gc/space/space_test.h index 4b01e83b38..2be1b9445a 100644 --- a/runtime/gc/space/space_test.h +++ b/runtime/gc/space/space_test.h @@ -31,7 +31,7 @@ #include "thread_list.h" #include "zygote_space.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace space { diff --git a/runtime/gc/space/zygote_space.cc b/runtime/gc/space/zygote_space.cc index f40061ff88..cab183ef94 100644 --- a/runtime/gc/space/zygote_space.cc +++ b/runtime/gc/space/zygote_space.cc @@ -25,7 +25,7 @@ #include "runtime.h" #include "thread-current-inl.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace space { diff --git a/runtime/gc/space/zygote_space.h b/runtime/gc/space/zygote_space.h index 3ebc943d96..12cc5c7e8b 100644 --- a/runtime/gc/space/zygote_space.h +++ b/runtime/gc/space/zygote_space.h @@ -21,7 +21,7 @@ #include "gc/accounting/space_bitmap.h" #include "malloc_space.h" -namespace art { +namespace art HIDDEN { namespace gc { namespace space { diff --git a/runtime/gc/system_weak.h b/runtime/gc/system_weak.h index 57d593c756..721977d596 100644 --- a/runtime/gc/system_weak.h +++ b/runtime/gc/system_weak.h @@ -17,11 +17,12 @@ #ifndef ART_RUNTIME_GC_SYSTEM_WEAK_H_ #define ART_RUNTIME_GC_SYSTEM_WEAK_H_ +#include "base/macros.h" #include "base/mutex.h" #include "object_callbacks.h" #include "thread-inl.h" -namespace art { +namespace art HIDDEN { namespace gc { class AbstractSystemWeakHolder { diff --git a/runtime/gc/system_weak_test.cc b/runtime/gc/system_weak_test.cc index dd936538e5..b2a8c4d179 100644 --- a/runtime/gc/system_weak_test.cc +++ b/runtime/gc/system_weak_test.cc @@ -31,7 +31,7 @@ #include "scoped_thread_state_change-inl.h" #include "thread_list.h" -namespace art { +namespace art HIDDEN { namespace gc { class SystemWeakTest : public CommonRuntimeTest { diff --git a/runtime/gc/task_processor.cc b/runtime/gc/task_processor.cc index e56dbd17c3..50be93e844 100644 --- a/runtime/gc/task_processor.cc +++ b/runtime/gc/task_processor.cc @@ -19,7 +19,7 @@ #include "base/time_utils.h" #include "scoped_thread_state_change-inl.h" -namespace art { +namespace art HIDDEN { namespace gc { TaskProcessor::TaskProcessor() diff --git a/runtime/gc/task_processor.h b/runtime/gc/task_processor.h index b9e6938b09..65d703d082 100644 --- a/runtime/gc/task_processor.h +++ b/runtime/gc/task_processor.h @@ -20,11 +20,12 @@ #include <memory> #include <set> +#include "base/macros.h" #include "base/mutex.h" #include "runtime_globals.h" #include "thread_pool.h" -namespace art { +namespace art HIDDEN { namespace gc { class HeapTask : public SelfDeletingTask { diff --git a/runtime/gc/task_processor_test.cc b/runtime/gc/task_processor_test.cc index 3614a51d90..5ee49415a5 100644 --- a/runtime/gc/task_processor_test.cc +++ b/runtime/gc/task_processor_test.cc @@ -20,7 +20,7 @@ #include "thread-current-inl.h" #include "thread_pool.h" -namespace art { +namespace art HIDDEN { namespace gc { class TaskProcessorTest : public CommonRuntimeTest { diff --git a/runtime/gc/verification-inl.h b/runtime/gc/verification-inl.h index 1ef96e2954..6becd26f4e 100644 --- a/runtime/gc/verification-inl.h +++ b/runtime/gc/verification-inl.h @@ -21,7 +21,7 @@ #include "mirror/class-inl.h" -namespace art { +namespace art HIDDEN { namespace gc { template <ReadBarrierOption kReadBarrierOption> diff --git a/runtime/gc/verification.cc b/runtime/gc/verification.cc index 8ef61cbea0..926156fd8f 100644 --- a/runtime/gc/verification.cc +++ b/runtime/gc/verification.cc @@ -25,7 +25,7 @@ #include "mirror/class-inl.h" #include "mirror/object-refvisitor-inl.h" -namespace art { +namespace art HIDDEN { namespace gc { std::string Verification::DumpRAMAroundAddress(uintptr_t addr, uintptr_t bytes) const { diff --git a/runtime/gc/verification.h b/runtime/gc/verification.h index 7a5d01a40a..0a9f78a26f 100644 --- a/runtime/gc/verification.h +++ b/runtime/gc/verification.h @@ -17,11 +17,12 @@ #ifndef ART_RUNTIME_GC_VERIFICATION_H_ #define ART_RUNTIME_GC_VERIFICATION_H_ +#include "base/macros.h" #include "obj_ptr.h" #include "offsets.h" #include "read_barrier_option.h" -namespace art { +namespace art HIDDEN { namespace mirror { class Class; @@ -45,10 +46,10 @@ class Verification { REQUIRES_SHARED(Locks::mutator_lock_); // Don't use ObjPtr for things that might not be aligned like the invalid reference. - void LogHeapCorruption(ObjPtr<mirror::Object> holder, - MemberOffset offset, - mirror::Object* ref, - bool fatal) const REQUIRES_SHARED(Locks::mutator_lock_); + EXPORT void LogHeapCorruption(ObjPtr<mirror::Object> holder, + MemberOffset offset, + mirror::Object* ref, + bool fatal) const REQUIRES_SHARED(Locks::mutator_lock_); // Return true if the klass is likely to be a valid mirror::Class. // Returns true if the class is a valid mirror::Class or possibly spuriously. @@ -68,7 +69,7 @@ class Verification { // Find the first path to the target from the root set. Should be called while paused since // visiting roots is not safe otherwise. - std::string FirstPathFromRootSet(ObjPtr<mirror::Object> target) const + EXPORT std::string FirstPathFromRootSet(ObjPtr<mirror::Object> target) const REQUIRES_SHARED(Locks::mutator_lock_); // Does not check alignment, used by DumpRAMAroundAddress. diff --git a/runtime/gc/weak_root_state.h b/runtime/gc/weak_root_state.h index 0784d3c738..316527fce5 100644 --- a/runtime/gc/weak_root_state.h +++ b/runtime/gc/weak_root_state.h @@ -19,7 +19,9 @@ #include <iosfwd> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { namespace gc { enum WeakRootState { diff --git a/runtime/gc_root-inl.h b/runtime/gc_root-inl.h index e561d29f99..736fdd3890 100644 --- a/runtime/gc_root-inl.h +++ b/runtime/gc_root-inl.h @@ -24,7 +24,7 @@ #include "obj_ptr-inl.h" #include "read_barrier-inl.h" -namespace art { +namespace art HIDDEN { template<class MirrorType> template<ReadBarrierOption kReadBarrierOption> diff --git a/runtime/gc_root.h b/runtime/gc_root.h index 19e2786ae2..da9d3af6cb 100644 --- a/runtime/gc_root.h +++ b/runtime/gc_root.h @@ -22,7 +22,7 @@ #include "mirror/object_reference.h" #include "read_barrier_option.h" -namespace art { +namespace art HIDDEN { class ArtField; class ArtMethod; template<class MirrorType> class ObjPtr; @@ -54,7 +54,7 @@ enum RootType { kRootVMInternal, kRootJNIMonitor, }; -std::ostream& operator<<(std::ostream& os, RootType root_type); +EXPORT std::ostream& operator<<(std::ostream& os, RootType root_type); // Only used by hprof. thread_id_ and type_ are only used by hprof. class RootInfo { diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc index dcbf9ebf52..fa0a02f997 100644 --- a/runtime/interpreter/interpreter.cc +++ b/runtime/interpreter/interpreter.cc @@ -35,7 +35,7 @@ #include "thread-inl.h" #include "unstarted_runtime.h" -namespace art { +namespace art HIDDEN { namespace interpreter { ALWAYS_INLINE static ObjPtr<mirror::Object> ObjArg(uint32_t arg) diff --git a/runtime/interpreter/interpreter.h b/runtime/interpreter/interpreter.h index f7bc1a3d55..c7508f66f9 100644 --- a/runtime/interpreter/interpreter.h +++ b/runtime/interpreter/interpreter.h @@ -18,10 +18,11 @@ #define ART_RUNTIME_INTERPRETER_INTERPRETER_H_ #include "base/locks.h" +#include "base/macros.h" #include "dex/dex_file.h" #include "obj_ptr.h" -namespace art { +namespace art HIDDEN { namespace mirror { class Object; } // namespace mirror diff --git a/runtime/interpreter/interpreter_cache-inl.h b/runtime/interpreter/interpreter_cache-inl.h index 804d382877..a325ea464a 100644 --- a/runtime/interpreter/interpreter_cache-inl.h +++ b/runtime/interpreter/interpreter_cache-inl.h @@ -21,7 +21,7 @@ #include "thread.h" -namespace art { +namespace art HIDDEN { inline bool InterpreterCache::Get(Thread* self, const void* key, /* out */ size_t* value) { DCHECK(self->GetInterpreterCache() == this) << "Must be called from owning thread"; diff --git a/runtime/interpreter/interpreter_cache.cc b/runtime/interpreter/interpreter_cache.cc index 7e7b294c17..a272d14bba 100644 --- a/runtime/interpreter/interpreter_cache.cc +++ b/runtime/interpreter/interpreter_cache.cc @@ -17,7 +17,7 @@ #include "interpreter_cache.h" #include "thread-inl.h" -namespace art { +namespace art HIDDEN { void InterpreterCache::Clear(Thread* owning_thread) { DCHECK(owning_thread->GetInterpreterCache() == this); diff --git a/runtime/interpreter/interpreter_cache.h b/runtime/interpreter/interpreter_cache.h index 8714bc613c..410fdf58ab 100644 --- a/runtime/interpreter/interpreter_cache.h +++ b/runtime/interpreter/interpreter_cache.h @@ -23,7 +23,7 @@ #include "base/bit_utils.h" #include "base/macros.h" -namespace art { +namespace art HIDDEN { class Thread; @@ -60,7 +60,7 @@ class ALIGNED(16) InterpreterCache { } // Clear the whole cache. It requires the owning thread for DCHECKs. - void Clear(Thread* owning_thread); + EXPORT void Clear(Thread* owning_thread); ALWAYS_INLINE bool Get(Thread* self, const void* key, /* out */ size_t* value); diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc index 814f28da75..85ed318390 100644 --- a/runtime/interpreter/interpreter_common.cc +++ b/runtime/interpreter/interpreter_common.cc @@ -50,7 +50,7 @@ #include "var_handles.h" #include "well_known_classes.h" -namespace art { +namespace art HIDDEN { namespace interpreter { void ThrowNullPointerExceptionFromInterpreter() { diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h index 94cf8f8795..0745a000e7 100644 --- a/runtime/interpreter/interpreter_common.h +++ b/runtime/interpreter/interpreter_common.h @@ -64,7 +64,7 @@ #include "unstarted_runtime.h" #include "verifier/method_verifier.h" -namespace art { +namespace art HIDDEN { namespace interpreter { void ThrowNullPointerExceptionFromInterpreter() diff --git a/runtime/interpreter/interpreter_switch_impl-inl.h b/runtime/interpreter/interpreter_switch_impl-inl.h index ddde26d0cf..db20f3951b 100644 --- a/runtime/interpreter/interpreter_switch_impl-inl.h +++ b/runtime/interpreter/interpreter_switch_impl-inl.h @@ -40,7 +40,7 @@ #include "thread.h" #include "verifier/method_verifier.h" -namespace art { +namespace art HIDDEN { namespace interpreter { // Short-lived helper class which executes single DEX bytecode. It is inlined by compiler. diff --git a/runtime/interpreter/interpreter_switch_impl.h b/runtime/interpreter/interpreter_switch_impl.h index 3a42c217a9..c390692f10 100644 --- a/runtime/interpreter/interpreter_switch_impl.h +++ b/runtime/interpreter/interpreter_switch_impl.h @@ -24,7 +24,7 @@ #include "jvalue.h" #include "obj_ptr.h" -namespace art { +namespace art HIDDEN { class ShadowFrame; class Thread; diff --git a/runtime/interpreter/interpreter_switch_impl0.cc b/runtime/interpreter/interpreter_switch_impl0.cc index b4e5f5061d..65ae2fe333 100644 --- a/runtime/interpreter/interpreter_switch_impl0.cc +++ b/runtime/interpreter/interpreter_switch_impl0.cc @@ -19,7 +19,7 @@ #include "interpreter_switch_impl-inl.h" -namespace art { +namespace art HIDDEN { namespace interpreter { // Explicit definition of ExecuteSwitchImplCpp. diff --git a/runtime/interpreter/interpreter_switch_impl1.cc b/runtime/interpreter/interpreter_switch_impl1.cc index f8f9fcc81a..b9033d926e 100644 --- a/runtime/interpreter/interpreter_switch_impl1.cc +++ b/runtime/interpreter/interpreter_switch_impl1.cc @@ -19,7 +19,7 @@ #include "interpreter_switch_impl-inl.h" -namespace art { +namespace art HIDDEN { namespace interpreter { // Explicit definition of ExecuteSwitchImplCpp. diff --git a/runtime/interpreter/lock_count_data.cc b/runtime/interpreter/lock_count_data.cc index 64b59cd390..ad53d703b3 100644 --- a/runtime/interpreter/lock_count_data.cc +++ b/runtime/interpreter/lock_count_data.cc @@ -23,7 +23,7 @@ #include "mirror/object-inl.h" #include "thread.h" -namespace art { +namespace art HIDDEN { void LockCountData::AddMonitor(Thread* self, mirror::Object* obj) { if (obj == nullptr) { diff --git a/runtime/interpreter/lock_count_data.h b/runtime/interpreter/lock_count_data.h index efa14c5bbc..ec108fc5c1 100644 --- a/runtime/interpreter/lock_count_data.h +++ b/runtime/interpreter/lock_count_data.h @@ -21,8 +21,9 @@ #include <vector> #include "base/locks.h" +#include "base/macros.h" -namespace art { +namespace art HIDDEN { namespace mirror { class Object; diff --git a/runtime/interpreter/mterp/nterp.cc b/runtime/interpreter/mterp/nterp.cc index 668289a37d..bcc59a4032 100644 --- a/runtime/interpreter/mterp/nterp.cc +++ b/runtime/interpreter/mterp/nterp.cc @@ -31,7 +31,7 @@ #include "mirror/string-alloc-inl.h" #include "nterp_helpers.h" -namespace art { +namespace art HIDDEN { namespace interpreter { bool IsNterpSupported() { diff --git a/runtime/interpreter/mterp/nterp.h b/runtime/interpreter/mterp/nterp.h index a7745db716..446fb858ce 100644 --- a/runtime/interpreter/mterp/nterp.h +++ b/runtime/interpreter/mterp/nterp.h @@ -19,11 +19,12 @@ #include "base/array_ref.h" #include "base/globals.h" +#include "base/macros.h" extern "C" void* artNterpAsmInstructionStart[]; extern "C" void* artNterpAsmInstructionEnd[]; -namespace art { +namespace art HIDDEN { class ArtMethod; diff --git a/runtime/interpreter/safe_math.h b/runtime/interpreter/safe_math.h index 25a9353bc0..9b6265f420 100644 --- a/runtime/interpreter/safe_math.h +++ b/runtime/interpreter/safe_math.h @@ -20,7 +20,9 @@ #include <functional> #include <type_traits> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { namespace interpreter { // Declares a type which is the larger in bit size of the two template parameters. diff --git a/runtime/interpreter/safe_math_test.cc b/runtime/interpreter/safe_math_test.cc index 28087a395b..c88ac4e061 100644 --- a/runtime/interpreter/safe_math_test.cc +++ b/runtime/interpreter/safe_math_test.cc @@ -20,7 +20,7 @@ #include "gtest/gtest.h" -namespace art { +namespace art HIDDEN { namespace interpreter { TEST(SafeMath, Add) { diff --git a/runtime/interpreter/shadow_frame-inl.h b/runtime/interpreter/shadow_frame-inl.h index 799b2d205d..a05d60f59b 100644 --- a/runtime/interpreter/shadow_frame-inl.h +++ b/runtime/interpreter/shadow_frame-inl.h @@ -21,7 +21,7 @@ #include "obj_ptr-inl.h" -namespace art { +namespace art HIDDEN { template<VerifyObjectFlags kVerifyFlags /*= kDefaultVerifyFlags*/> inline void ShadowFrame::SetVRegReference(size_t i, ObjPtr<mirror::Object> val) diff --git a/runtime/interpreter/shadow_frame.cc b/runtime/interpreter/shadow_frame.cc index 264ec6a997..5ed4224900 100644 --- a/runtime/interpreter/shadow_frame.cc +++ b/runtime/interpreter/shadow_frame.cc @@ -18,7 +18,7 @@ #include "art_method-inl.h" -namespace art { +namespace art HIDDEN { mirror::Object* ShadowFrame::GetThisObject() const { ArtMethod* m = GetMethod(); diff --git a/runtime/interpreter/shadow_frame.h b/runtime/interpreter/shadow_frame.h index 7ca2423856..54c40b2e3c 100644 --- a/runtime/interpreter/shadow_frame.h +++ b/runtime/interpreter/shadow_frame.h @@ -28,7 +28,7 @@ #include "stack_reference.h" #include "verify_object.h" -namespace art { +namespace art HIDDEN { namespace mirror { class Object; diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc index 6cf6746f01..3b5bee80d7 100644 --- a/runtime/interpreter/unstarted_runtime.cc +++ b/runtime/interpreter/unstarted_runtime.cc @@ -66,7 +66,7 @@ #include "unstarted_runtime_list.h" #include "well_known_classes-inl.h" -namespace art { +namespace art HIDDEN { namespace interpreter { using android::base::StringAppendV; diff --git a/runtime/interpreter/unstarted_runtime.h b/runtime/interpreter/unstarted_runtime.h index 8b31f8f441..60092ad958 100644 --- a/runtime/interpreter/unstarted_runtime.h +++ b/runtime/interpreter/unstarted_runtime.h @@ -19,11 +19,12 @@ #include "interpreter.h" +#include "base/macros.h" #include "dex/dex_file.h" #include "jvalue.h" #include "unstarted_runtime_list.h" -namespace art { +namespace art HIDDEN { class ArtMethod; class CodeItemDataAccessor; @@ -47,7 +48,7 @@ namespace interpreter { class UnstartedRuntime { public: - static void Initialize(); + EXPORT static void Initialize(); // For testing. When we destroy the Runtime and create a new one, // we need to reinitialize maps with new `ArtMethod*` keys. diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc index daa1a825de..d21c5ea145 100644 --- a/runtime/interpreter/unstarted_runtime_test.cc +++ b/runtime/interpreter/unstarted_runtime_test.cc @@ -45,7 +45,7 @@ #include "transaction.h" #include "unstarted_runtime_list.h" -namespace art { +namespace art HIDDEN { namespace interpreter { // Deleter to be used with ShadowFrame::CreateDeoptimizedFrame objects. diff --git a/runtime/jit/debugger_interface.cc b/runtime/jit/debugger_interface.cc index 112746e2fe..8c9fb4c999 100644 --- a/runtime/jit/debugger_interface.cc +++ b/runtime/jit/debugger_interface.cc @@ -93,7 +93,7 @@ // attempting to run TSAN on this code. // -namespace art { +namespace art HIDDEN { static Mutex g_jit_debug_lock("JIT native debug entries", kNativeDebugInterfaceLock); static Mutex g_dex_debug_lock("DEX native debug entries", kNativeDebugInterfaceLock); @@ -108,8 +108,11 @@ constexpr uint32_t kJitRepackGroupSize = 64 * KB; // Automatically call the repack method every 'n' new entries. constexpr uint32_t kJitRepackFrequency = 64; +} // namespace art + // Public binary interface between ART and native tools (gdb, libunwind, etc). // The fields below need to be exported and have special names as per the gdb api. +namespace art EXPORT { extern "C" { enum JITAction { JIT_NOACTION = 0, @@ -198,6 +201,9 @@ extern "C" { void (*__dex_debug_register_code_ptr)() = __dex_debug_register_code; JITDescriptor __dex_debug_descriptor GUARDED_BY(g_dex_debug_lock) {}; } +} // namespace art + +namespace art HIDDEN { // The fields below are internal, but we keep them here anyway for consistency. // Their state is related to the static state above and it must be kept in sync. diff --git a/runtime/jit/debugger_interface.h b/runtime/jit/debugger_interface.h index 62288de8cf..da7e90749e 100644 --- a/runtime/jit/debugger_interface.h +++ b/runtime/jit/debugger_interface.h @@ -25,7 +25,7 @@ #include "base/array_ref.h" #include "base/locks.h" -namespace art { +namespace art HIDDEN { class DexFile; class Mutex; @@ -70,7 +70,7 @@ size_t GetJitMiniDebugInfoMemUsage() REQUIRES_SHARED(Locks::jit_lock_); // Get the lock which protects the native debug info. // Used only in tests to unwind while the JIT thread is running. // TODO: Unwinding should be race-free. Remove this. -Mutex* GetNativeDebugInfoLock(); +EXPORT Mutex* GetNativeDebugInfoLock(); // Call given callback for every non-zygote symbol. // The callback parameters are (address, size, name). diff --git a/runtime/jit/jit-inl.h b/runtime/jit/jit-inl.h index 237f63ce97..52099c2e1d 100644 --- a/runtime/jit/jit-inl.h +++ b/runtime/jit/jit-inl.h @@ -24,7 +24,7 @@ #include "thread.h" #include "runtime-inl.h" -namespace art { +namespace art HIDDEN { namespace jit { inline void Jit::AddSamples(Thread* self, ArtMethod* method) { diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc index 0ee138fa06..4d4a1ed79c 100644 --- a/runtime/jit/jit.cc +++ b/runtime/jit/jit.cc @@ -58,7 +58,7 @@ using android::base::unique_fd; -namespace art { +namespace art HIDDEN { namespace jit { static constexpr bool kEnableOnStackReplacement = true; diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h index 1c579167ad..ddf408fb33 100644 --- a/runtime/jit/jit.h +++ b/runtime/jit/jit.h @@ -35,7 +35,7 @@ #include "obj_ptr.h" #include "thread_pool.h" -namespace art { +namespace art HIDDEN { class ArtMethod; class ClassLinker; @@ -200,7 +200,6 @@ class JitCompilerInterface { virtual void ParseCompilerOptions() = 0; virtual bool IsBaselineCompiler() const = 0; virtual void SetDebuggableCompilerOption(bool value) = 0; - virtual uint32_t GetInlineMaxCodeUnits() const = 0; virtual std::vector<uint8_t> PackElfFileForJIT(ArrayRef<const JITCodeEntry*> elf_files, ArrayRef<const void*> removed_symbols, @@ -309,8 +308,10 @@ class Jit { // Create JIT itself. static std::unique_ptr<Jit> Create(JitCodeCache* code_cache, JitOptions* options); - bool CompileMethod(ArtMethod* method, Thread* self, CompilationKind compilation_kind, bool prejit) - REQUIRES_SHARED(Locks::mutator_lock_); + EXPORT bool CompileMethod(ArtMethod* method, + Thread* self, + CompilationKind compilation_kind, + bool prejit) REQUIRES_SHARED(Locks::mutator_lock_); void VisitRoots(RootVisitor* visitor); @@ -371,7 +372,7 @@ class Jit { } // Wait until there is no more pending compilation tasks. - void WaitForCompilationToFinish(Thread* self); + EXPORT void WaitForCompilationToFinish(Thread* self); // Profiling methods. void MethodEntered(Thread* thread, ArtMethod* method) @@ -412,7 +413,7 @@ class Jit { void DumpTypeInfoForLoadedTypes(ClassLinker* linker); // Return whether we should try to JIT compiled code as soon as an ArtMethod is invoked. - bool JitAtFirstUse(); + EXPORT bool JitAtFirstUse(); // Return whether we can invoke JIT code for `method`. bool CanInvokeCompiledCode(ArtMethod* method); @@ -438,16 +439,16 @@ class Jit { } // Stop the JIT by waiting for all current compilations and enqueued compilations to finish. - void Stop(); + EXPORT void Stop(); // Start JIT threads. - void Start(); + EXPORT void Start(); // Transition to a child state. - void PostForkChildAction(bool is_system_server, bool is_zygote); + EXPORT void PostForkChildAction(bool is_system_server, bool is_zygote); // Prepare for forking. - void PreZygoteFork(); + EXPORT void PreZygoteFork(); // Adjust state after forking. void PostZygoteFork(); @@ -540,7 +541,7 @@ class Jit { REQUIRES_SHARED(Locks::mutator_lock_); // JIT compiler - static JitCompilerInterface* jit_compiler_; + EXPORT static JitCompilerInterface* jit_compiler_; // JIT resources owned by runtime. jit::JitCodeCache* const code_cache_; @@ -588,7 +589,7 @@ class Jit { }; // Helper class to stop the JIT for a given scope. This will wait for the JIT to quiesce. -class ScopedJitSuspend { +class EXPORT ScopedJitSuspend { public: ScopedJitSuspend(); ~ScopedJitSuspend(); diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc index e8d8b3b663..f44b822bb1 100644 --- a/runtime/jit/jit_code_cache.cc +++ b/runtime/jit/jit_code_cache.cc @@ -60,7 +60,7 @@ #include "thread-inl.h" #include "thread_list.h" -namespace art { +namespace art HIDDEN { namespace jit { static constexpr size_t kCodeSizeLogThreshold = 50 * KB; diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h index e61ae7963d..96fc7e2706 100644 --- a/runtime/jit/jit_code_cache.h +++ b/runtime/jit/jit_code_cache.h @@ -37,7 +37,7 @@ #include "jit_memory_region.h" #include "profiling_info.h" -namespace art { +namespace art HIDDEN { class ArtMethod; template<class T> class Handle; @@ -211,7 +211,7 @@ class JitCodeCache { REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::jit_lock_); - void NotifyMethodRedefined(ArtMethod* method) + EXPORT void NotifyMethodRedefined(ArtMethod* method) REQUIRES(Locks::mutator_lock_) REQUIRES(!Locks::jit_lock_); @@ -232,13 +232,13 @@ class JitCodeCache { REQUIRES(!Locks::jit_lock_); // Return true if the code cache contains this pc. - bool ContainsPc(const void* pc) const; + EXPORT bool ContainsPc(const void* pc) const; // Return true if the code cache contains this pc in the private region (i.e. not from zygote). bool PrivateRegionContainsPc(const void* pc) const; // Return true if the code cache contains this method. - bool ContainsMethod(ArtMethod* method) + EXPORT bool ContainsMethod(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::jit_lock_); // Return the code pointer for a JNI-compiled stub if the method is in the cache, null otherwise. @@ -289,7 +289,7 @@ class JitCodeCache { REQUIRES(Locks::jit_lock_); // Perform a collection on the code cache. - void GarbageCollectCache(Thread* self) + EXPORT void GarbageCollectCache(Thread* self) REQUIRES(!Locks::jit_lock_) REQUIRES_SHARED(Locks::mutator_lock_); @@ -300,14 +300,14 @@ class JitCodeCache { REQUIRES(!Locks::jit_lock_) REQUIRES_SHARED(Locks::mutator_lock_); - OatQuickMethodHeader* LookupOsrMethodHeader(ArtMethod* method) + EXPORT OatQuickMethodHeader* LookupOsrMethodHeader(ArtMethod* method) REQUIRES(!Locks::jit_lock_) REQUIRES_SHARED(Locks::mutator_lock_); // Removes method from the cache for testing purposes. The caller // must ensure that all threads are suspended and the method should // not be in any thread's stack. - bool RemoveMethod(ArtMethod* method, bool release_memory) + EXPORT bool RemoveMethod(ArtMethod* method, bool release_memory) REQUIRES(!Locks::jit_lock_) REQUIRES(Locks::mutator_lock_); @@ -338,12 +338,12 @@ class JitCodeCache { // Adds to `methods` all profiled methods which are part of any of the given dex locations. // Saves inline caches for a method if its hotness meets `inline_cache_threshold` after being // baseline compiled. - void GetProfiledMethods(const std::set<std::string>& dex_base_locations, - std::vector<ProfileMethodInfo>& methods, - uint16_t inline_cache_threshold) REQUIRES(!Locks::jit_lock_) + EXPORT void GetProfiledMethods(const std::set<std::string>& dex_base_locations, + std::vector<ProfileMethodInfo>& methods, + uint16_t inline_cache_threshold) REQUIRES(!Locks::jit_lock_) REQUIRES_SHARED(Locks::mutator_lock_); - void InvalidateAllCompiledCode() + EXPORT void InvalidateAllCompiledCode() REQUIRES(!Locks::jit_lock_) REQUIRES_SHARED(Locks::mutator_lock_); @@ -370,11 +370,11 @@ class JitCodeCache { // Notify the code cache that the method at the pointer 'old_method' is being moved to the pointer // 'new_method' since it is being made obsolete. - void MoveObsoleteMethod(ArtMethod* old_method, ArtMethod* new_method) + EXPORT void MoveObsoleteMethod(ArtMethod* old_method, ArtMethod* new_method) REQUIRES(!Locks::jit_lock_) REQUIRES(Locks::mutator_lock_); // Dynamically change whether we want to garbage collect code. - void SetGarbageCollectCode(bool value) REQUIRES(!Locks::jit_lock_); + EXPORT void SetGarbageCollectCode(bool value) REQUIRES(!Locks::jit_lock_); bool GetGarbageCollectCode() REQUIRES(!Locks::jit_lock_); @@ -392,13 +392,13 @@ class JitCodeCache { REQUIRES(!Locks::jit_lock_) REQUIRES_SHARED(Locks::mutator_lock_); - void PostForkChildAction(bool is_system_server, bool is_zygote); + EXPORT void PostForkChildAction(bool is_system_server, bool is_zygote); // Clear the entrypoints of JIT compiled methods that belong in the zygote space. // This is used for removing non-debuggable JIT code at the point we realize the runtime // is debuggable. Also clear the Precompiled flag from all methods so the non-debuggable code // doesn't come back. - void TransitionToDebuggable() REQUIRES(!Locks::jit_lock_) REQUIRES(Locks::mutator_lock_); + EXPORT void TransitionToDebuggable() REQUIRES(!Locks::jit_lock_) REQUIRES(Locks::mutator_lock_); JitMemoryRegion* GetCurrentRegion(); bool IsSharedRegion(const JitMemoryRegion& region) const { return ®ion == &shared_region_; } diff --git a/runtime/jit/jit_memory_region.cc b/runtime/jit/jit_memory_region.cc index 911b7d7aca..3a4ef973eb 100644 --- a/runtime/jit/jit_memory_region.cc +++ b/runtime/jit/jit_memory_region.cc @@ -34,7 +34,7 @@ using android::base::unique_fd; -namespace art { +namespace art HIDDEN { namespace jit { // Data cache will be half of the capacity diff --git a/runtime/jit/jit_memory_region.h b/runtime/jit/jit_memory_region.h index 8a3d6c3e55..7391541f07 100644 --- a/runtime/jit/jit_memory_region.h +++ b/runtime/jit/jit_memory_region.h @@ -26,7 +26,7 @@ #include "gc_root-inl.h" #include "handle.h" -namespace art { +namespace art HIDDEN { namespace mirror { class Object; diff --git a/runtime/jit/jit_memory_region_test.cc b/runtime/jit/jit_memory_region_test.cc index bf943f9981..449255a7f7 100644 --- a/runtime/jit/jit_memory_region_test.cc +++ b/runtime/jit/jit_memory_region_test.cc @@ -29,7 +29,7 @@ #include "base/utils.h" #include "common_runtime_test.h" -namespace art { +namespace art HIDDEN { namespace jit { // These tests only run on bionic. diff --git a/runtime/jit/jit_scoped_code_cache_write.h b/runtime/jit/jit_scoped_code_cache_write.h index e2adebfb1b..ed21cf9fbd 100644 --- a/runtime/jit/jit_scoped_code_cache_write.h +++ b/runtime/jit/jit_scoped_code_cache_write.h @@ -22,7 +22,7 @@ #include "base/systrace.h" #include "base/utils.h" // For CheckedCall -namespace art { +namespace art HIDDEN { namespace jit { class JitMemoryRegion; diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc index af5f561d8c..91b011bce8 100644 --- a/runtime/jit/profile_saver.cc +++ b/runtime/jit/profile_saver.cc @@ -43,7 +43,7 @@ #include "profile/profile_compilation_info.h" #include "scoped_thread_state_change-inl.h" -namespace art { +namespace art HIDDEN { using Hotness = ProfileCompilationInfo::MethodHotness; diff --git a/runtime/jit/profile_saver.h b/runtime/jit/profile_saver.h index b5fb1e6c26..1042db9a89 100644 --- a/runtime/jit/profile_saver.h +++ b/runtime/jit/profile_saver.h @@ -24,7 +24,7 @@ #include "profile/profile_compilation_info.h" #include "profile_saver_options.h" -namespace art { +namespace art HIDDEN { class ProfileSaver { public: @@ -53,7 +53,7 @@ class ProfileSaver { static void NotifyJitActivity() REQUIRES(!Locks::profiler_lock_, !instance_->wait_lock_); // For testing or manual purposes (SIGUSR1). - static void ForceProcessProfiles() REQUIRES(!Locks::profiler_lock_, !Locks::mutator_lock_); + EXPORT static void ForceProcessProfiles() REQUIRES(!Locks::profiler_lock_, !Locks::mutator_lock_); // Notify that startup has completed. static void NotifyStartupCompleted() REQUIRES(!Locks::profiler_lock_, !instance_->wait_lock_); diff --git a/runtime/jit/profile_saver_options.h b/runtime/jit/profile_saver_options.h index f53b5fcfcc..f6d928ff6b 100644 --- a/runtime/jit/profile_saver_options.h +++ b/runtime/jit/profile_saver_options.h @@ -17,7 +17,7 @@ #include <ostream> #include <string> -namespace art { +namespace art HIDDEN { struct ProfileSaverOptions { public: diff --git a/runtime/jit/profile_saver_test.cc b/runtime/jit/profile_saver_test.cc index e737b7c8ee..e522677eca 100644 --- a/runtime/jit/profile_saver_test.cc +++ b/runtime/jit/profile_saver_test.cc @@ -22,7 +22,7 @@ #include "profile_saver.h" #include "profile/profile_compilation_info.h" -namespace art { +namespace art HIDDEN { using Hotness = ProfileCompilationInfo::MethodHotness; diff --git a/runtime/jit/profiling_info.cc b/runtime/jit/profiling_info.cc index 1aaf53e0a1..395e175d7c 100644 --- a/runtime/jit/profiling_info.cc +++ b/runtime/jit/profiling_info.cc @@ -23,7 +23,7 @@ #include "scoped_thread_state_change-inl.h" #include "thread.h" -namespace art { +namespace art HIDDEN { ProfilingInfo::ProfilingInfo(ArtMethod* method, const std::vector<uint32_t>& inline_cache_entries, @@ -114,9 +114,6 @@ BranchCache* ProfilingInfo::GetBranchCache(uint32_t dex_pc) { void ProfilingInfo::AddInvokeInfo(uint32_t dex_pc, mirror::Class* cls) { InlineCache* cache = GetInlineCache(dex_pc); - if (cache == nullptr) { - return; - } for (size_t i = 0; i < InlineCache::kIndividualCacheSize; ++i) { mirror::Class* existing = cache->classes_[i].Read<kWithoutReadBarrier>(); mirror::Class* marked = ReadBarrier::IsMarked(existing); @@ -162,39 +159,4 @@ ScopedProfilingInfoUse::~ScopedProfilingInfoUse() { } } -uint32_t InlineCache::EncodeDexPc(ArtMethod* method, - const std::vector<uint32_t>& dex_pcs, - uint32_t inline_max_code_units) { - if (kIsDebugBuild) { - // Make sure `inline_max_code_units` is always the same. - static uint32_t global_max_code_units = inline_max_code_units; - CHECK_EQ(global_max_code_units, inline_max_code_units); - } - if (dex_pcs.size() - 1 > MaxDexPcEncodingDepth(method, inline_max_code_units)) { - return -1; - } - uint32_t size = dex_pcs.size(); - uint32_t insns_size = method->DexInstructions().InsnsSizeInCodeUnits(); - - uint32_t dex_pc = dex_pcs[size - 1]; - uint32_t shift = MinimumBitsToStore(insns_size - 1); - for (uint32_t i = size - 1; i > 0; --i) { - DCHECK_LT(shift, BitSizeOf<uint32_t>()); - dex_pc += ((dex_pcs[i - 1] + 1) << shift); - shift += MinimumBitsToStore(inline_max_code_units); - } - return dex_pc; -} - -uint32_t InlineCache::MaxDexPcEncodingDepth(ArtMethod* method, uint32_t inline_max_code_units) { - uint32_t insns_size = method->DexInstructions().InsnsSizeInCodeUnits(); - uint32_t num_bits = MinimumBitsToStore(insns_size - 1); - uint32_t depth = 0; - do { - depth++; - num_bits += MinimumBitsToStore(inline_max_code_units); - } while (num_bits <= BitSizeOf<uint32_t>()); - return depth - 1; -} - } // namespace art diff --git a/runtime/jit/profiling_info.h b/runtime/jit/profiling_info.h index 4ce20ff66a..05420fd904 100644 --- a/runtime/jit/profiling_info.h +++ b/runtime/jit/profiling_info.h @@ -25,10 +25,9 @@ #include "interpreter/mterp/nterp.h" #include "offsets.h" -namespace art { +namespace art HIDDEN { class ArtMethod; -class CompilerOptions; class ProfilingInfo; namespace jit { @@ -51,18 +50,6 @@ class InlineCache { return MemberOffset(OFFSETOF_MEMBER(InlineCache, classes_)); } - // Encode the list of `dex_pcs` to fit into an uint32_t. - static uint32_t EncodeDexPc(ArtMethod* method, - const std::vector<uint32_t>& dex_pcs, - uint32_t inline_max_code_units) - REQUIRES_SHARED(Locks::mutator_lock_); - - // Return the maximum inlining depth that we support to encode a list of dex - // pcs. - static uint32_t MaxDexPcEncodingDepth(ArtMethod* method, - uint32_t inline_max_code_units) - REQUIRES_SHARED(Locks::mutator_lock_); - private: uint32_t dex_pc_; GcRoot<mirror::Class> classes_[kIndividualCacheSize]; @@ -112,9 +99,9 @@ class BranchCache { class ProfilingInfo { public: // Create a ProfilingInfo for 'method'. - static ProfilingInfo* Create(Thread* self, - ArtMethod* method, - const std::vector<uint32_t>& inline_cache_entries) + EXPORT static ProfilingInfo* Create(Thread* self, + ArtMethod* method, + const std::vector<uint32_t>& inline_cache_entries) REQUIRES_SHARED(Locks::mutator_lock_); // Add information from an executed INVOKE instruction to the profile. diff --git a/runtime/jit/profiling_info_test.cc b/runtime/jit/profiling_info_test.cc index 021bebfe4e..a8a95774d8 100644 --- a/runtime/jit/profiling_info_test.cc +++ b/runtime/jit/profiling_info_test.cc @@ -33,7 +33,7 @@ #include "profile/profile_test_helper.h" #include "scoped_thread_state_change-inl.h" -namespace art { +namespace art HIDDEN { using Hotness = ProfileCompilationInfo::MethodHotness; diff --git a/runtime/jni/check_jni.cc b/runtime/jni/check_jni.cc index 3dc9b9f475..db4205cdf8 100644 --- a/runtime/jni/check_jni.cc +++ b/runtime/jni/check_jni.cc @@ -51,7 +51,7 @@ #include "thread.h" #include "well_known_classes.h" -namespace art { +namespace art HIDDEN { // This helper cannot be in the anonymous namespace because it needs to be // declared as a friend by JniVmExt and JniEnvExt. diff --git a/runtime/jni/check_jni.h b/runtime/jni/check_jni.h index 10fdfe859d..854aa20617 100644 --- a/runtime/jni/check_jni.h +++ b/runtime/jni/check_jni.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { const JNINativeInterface* GetCheckJniNativeInterface(); const JNIInvokeInterface* GetCheckJniInvokeInterface(); diff --git a/runtime/jni/java_vm_ext-inl.h b/runtime/jni/java_vm_ext-inl.h index c98a5532f6..75cfabb588 100644 --- a/runtime/jni/java_vm_ext-inl.h +++ b/runtime/jni/java_vm_ext-inl.h @@ -22,7 +22,7 @@ #include "read_barrier_config.h" #include "thread-inl.h" -namespace art { +namespace art HIDDEN { inline bool JavaVMExt::MayAccessWeakGlobals(Thread* self) const { DCHECK(self != nullptr); diff --git a/runtime/jni/java_vm_ext.cc b/runtime/jni/java_vm_ext.cc index 18abd8b3ee..2a364f37b1 100644 --- a/runtime/jni/java_vm_ext.cc +++ b/runtime/jni/java_vm_ext.cc @@ -54,7 +54,7 @@ #include "ti/agent.h" #include "well_known_classes-inl.h" -namespace art { +namespace art HIDDEN { using android::base::StringAppendF; using android::base::StringAppendV; @@ -1210,7 +1210,7 @@ jstring JavaVMExt::GetLibrarySearchPath(JNIEnv* env, jobject class_loader) { // JNI Invocation interface. -extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) { +extern "C" EXPORT jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) { ScopedTrace trace(__FUNCTION__); const JavaVMInitArgs* args = static_cast<JavaVMInitArgs*>(vm_args); if (JavaVMExt::IsBadJniVersion(args->version)) { @@ -1252,7 +1252,7 @@ extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) { return JNI_OK; } -extern "C" jint JNI_GetCreatedJavaVMs(JavaVM** vms_buf, jsize buf_len, jsize* vm_count) { +extern "C" EXPORT jint JNI_GetCreatedJavaVMs(JavaVM** vms_buf, jsize buf_len, jsize* vm_count) { Runtime* runtime = Runtime::Current(); if (runtime == nullptr || buf_len == 0) { *vm_count = 0; @@ -1264,7 +1264,7 @@ extern "C" jint JNI_GetCreatedJavaVMs(JavaVM** vms_buf, jsize buf_len, jsize* vm } // Historically unsupported. -extern "C" jint JNI_GetDefaultJavaVMInitArgs(void* /*vm_args*/) { +extern "C" EXPORT jint JNI_GetDefaultJavaVMInitArgs(void* /*vm_args*/) { return JNI_ERR; } diff --git a/runtime/jni/java_vm_ext.h b/runtime/jni/java_vm_ext.h index 7f4f5485b6..c04bee7db1 100644 --- a/runtime/jni/java_vm_ext.h +++ b/runtime/jni/java_vm_ext.h @@ -25,7 +25,7 @@ #include "obj_ptr.h" #include "reference_table.h" -namespace art { +namespace art HIDDEN { namespace linker { class ImageWriter; @@ -103,11 +103,11 @@ class JavaVMExt : public JavaVM { * Returns 'true' on success. On failure, sets 'error_msg' to a * human-readable description of the error. */ - bool LoadNativeLibrary(JNIEnv* env, - const std::string& path, - jobject class_loader, - jclass caller_class, - std::string* error_msg); + EXPORT bool LoadNativeLibrary(JNIEnv* env, + const std::string& path, + jobject class_loader, + jclass caller_class, + std::string* error_msg); // Unload native libraries with cleared class loaders. void UnloadNativeLibraries() @@ -139,7 +139,7 @@ class JavaVMExt : public JavaVM { bool SetCheckJniEnabled(bool enabled); - void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_) + EXPORT void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::jni_globals_lock_); void DisallowNewWeakGlobals() @@ -151,17 +151,15 @@ class JavaVMExt : public JavaVM { void BroadcastForNewWeakGlobals() REQUIRES(!Locks::jni_weak_globals_lock_); - jobject AddGlobalRef(Thread* self, ObjPtr<mirror::Object> obj) - REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!Locks::jni_globals_lock_); + EXPORT jobject AddGlobalRef(Thread* self, ObjPtr<mirror::Object> obj) + REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::jni_globals_lock_); - jweak AddWeakGlobalRef(Thread* self, ObjPtr<mirror::Object> obj) - REQUIRES_SHARED(Locks::mutator_lock_) - REQUIRES(!Locks::jni_weak_globals_lock_); + EXPORT jweak AddWeakGlobalRef(Thread* self, ObjPtr<mirror::Object> obj) + REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::jni_weak_globals_lock_); - void DeleteGlobalRef(Thread* self, jobject obj) REQUIRES(!Locks::jni_globals_lock_); + EXPORT void DeleteGlobalRef(Thread* self, jobject obj) REQUIRES(!Locks::jni_globals_lock_); - void DeleteWeakGlobalRef(Thread* self, jweak obj) REQUIRES(!Locks::jni_weak_globals_lock_); + EXPORT void DeleteWeakGlobalRef(Thread* self, jweak obj) REQUIRES(!Locks::jni_weak_globals_lock_); void SweepJniWeakGlobals(IsMarkedVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_) @@ -214,8 +212,7 @@ class JavaVMExt : public JavaVM { jint HandleGetEnv(/*out*/void** env, jint version) REQUIRES(!env_hooks_lock_); - void AddEnvironmentHook(GetEnvHook hook) - REQUIRES(!env_hooks_lock_); + EXPORT void AddEnvironmentHook(GetEnvHook hook) REQUIRES(!env_hooks_lock_); static bool IsBadJniVersion(int version); diff --git a/runtime/jni/java_vm_ext_test.cc b/runtime/jni/java_vm_ext_test.cc index e7295aaa62..f9176fc5c4 100644 --- a/runtime/jni/java_vm_ext_test.cc +++ b/runtime/jni/java_vm_ext_test.cc @@ -23,7 +23,7 @@ #include "java_vm_ext.h" #include "runtime.h" -namespace art { +namespace art HIDDEN { class JavaVmExtTest : public CommonRuntimeTest { protected: diff --git a/runtime/jni/jni_env_ext-inl.h b/runtime/jni/jni_env_ext-inl.h index 0c04192958..9adb173e60 100644 --- a/runtime/jni/jni_env_ext-inl.h +++ b/runtime/jni/jni_env_ext-inl.h @@ -22,17 +22,12 @@ #include "local_reference_table-inl.h" #include "mirror/object.h" -namespace art { +namespace art HIDDEN { template<typename T> inline T JNIEnvExt::AddLocalReference(ObjPtr<mirror::Object> obj) { - std::string error_msg; - IndirectRef ref = locals_.Add(local_ref_cookie_, obj, &error_msg); - if (UNLIKELY(ref == nullptr)) { - // This is really unexpected if we allow resizing local IRTs... - LOG(FATAL) << error_msg; - UNREACHABLE(); - } + DCHECK(obj != nullptr); + jobject ref = NewLocalRef(obj.Ptr()); // TODO: fix this to understand PushLocalFrame, so we can turn it on. if (false) { diff --git a/runtime/jni/jni_env_ext.cc b/runtime/jni/jni_env_ext.cc index fcf38bafb0..a68df6f658 100644 --- a/runtime/jni/jni_env_ext.cc +++ b/runtime/jni/jni_env_ext.cc @@ -36,7 +36,7 @@ #include "thread-inl.h" #include "thread_list.h" -namespace art { +namespace art HIDDEN { using android::base::StringPrintf; diff --git a/runtime/jni/jni_env_ext.h b/runtime/jni/jni_env_ext.h index 1f57658c87..177c70d171 100644 --- a/runtime/jni/jni_env_ext.h +++ b/runtime/jni/jni_env_ext.h @@ -25,7 +25,7 @@ #include "obj_ptr.h" #include "reference_table.h" -namespace art { +namespace art HIDDEN { class ArtMethod; class ArtField; @@ -66,8 +66,8 @@ class JNIEnvExt : public JNIEnv { void UpdateLocal(IndirectRef iref, ObjPtr<mirror::Object> obj) REQUIRES_SHARED(Locks::mutator_lock_); - jobject NewLocalRef(mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_); - void DeleteLocalRef(jobject obj) REQUIRES_SHARED(Locks::mutator_lock_); + EXPORT jobject NewLocalRef(mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_); + EXPORT void DeleteLocalRef(jobject obj) REQUIRES_SHARED(Locks::mutator_lock_); void TrimLocals() REQUIRES_SHARED(Locks::mutator_lock_) { locals_.Trim(); @@ -138,12 +138,12 @@ class JNIEnvExt : public JNIEnv { // to all threads. // Note: JNI function table overrides are sensitive to the order of operations wrt/ CheckJNI. // After overriding the JNI function table, CheckJNI toggling is ignored. - static void SetTableOverride(const JNINativeInterface* table_override) + EXPORT static void SetTableOverride(const JNINativeInterface* table_override) REQUIRES(!Locks::thread_list_lock_, !Locks::jni_function_table_lock_); // Return either the regular, or the CheckJNI function table. Will return table_override_ instead // if it is not null. - static const JNINativeInterface* GetFunctionTable(bool check_jni) + EXPORT static const JNINativeInterface* GetFunctionTable(bool check_jni) REQUIRES(Locks::jni_function_table_lock_); static void ResetFunctionTable() diff --git a/runtime/jni/jni_id_manager.cc b/runtime/jni/jni_id_manager.cc index 5af1a78013..c7c2733951 100644 --- a/runtime/jni/jni_id_manager.cc +++ b/runtime/jni/jni_id_manager.cc @@ -46,7 +46,7 @@ #include "thread-inl.h" #include "thread.h" -namespace art { +namespace art HIDDEN { namespace jni { constexpr bool kTraceIds = false; diff --git a/runtime/jni/jni_id_manager.h b/runtime/jni/jni_id_manager.h index c8ebfc331a..c7ebeb8abb 100644 --- a/runtime/jni/jni_id_manager.h +++ b/runtime/jni/jni_id_manager.h @@ -29,7 +29,7 @@ #include "jni_id_type.h" #include "reflective_value_visitor.h" -namespace art { +namespace art HIDDEN { namespace mirror { class Object; class ClassExt; @@ -50,15 +50,15 @@ class JniIdManager { void Init(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_); - ArtMethod* DecodeMethodId(jmethodID method) REQUIRES(!Locks::jni_id_lock_); - ArtField* DecodeFieldId(jfieldID field) REQUIRES(!Locks::jni_id_lock_); - jmethodID EncodeMethodId(ReflectiveHandle<ArtMethod> method) REQUIRES(!Locks::jni_id_lock_) + EXPORT ArtMethod* DecodeMethodId(jmethodID method) REQUIRES(!Locks::jni_id_lock_); + EXPORT ArtField* DecodeFieldId(jfieldID field) REQUIRES(!Locks::jni_id_lock_); + EXPORT jmethodID EncodeMethodId(ReflectiveHandle<ArtMethod> method) REQUIRES(!Locks::jni_id_lock_) REQUIRES_SHARED(Locks::mutator_lock_); - jmethodID EncodeMethodId(ArtMethod* method) REQUIRES(!Locks::jni_id_lock_) + EXPORT jmethodID EncodeMethodId(ArtMethod* method) REQUIRES(!Locks::jni_id_lock_) REQUIRES_SHARED(Locks::mutator_lock_); - jfieldID EncodeFieldId(ReflectiveHandle<ArtField> field) REQUIRES(!Locks::jni_id_lock_) + EXPORT jfieldID EncodeFieldId(ReflectiveHandle<ArtField> field) REQUIRES(!Locks::jni_id_lock_) REQUIRES_SHARED(Locks::mutator_lock_); - jfieldID EncodeFieldId(ArtField* field) REQUIRES(!Locks::jni_id_lock_) + EXPORT jfieldID EncodeFieldId(ArtField* field) REQUIRES(!Locks::jni_id_lock_) REQUIRES_SHARED(Locks::mutator_lock_); void VisitReflectiveTargets(ReflectiveValueVisitor* rvv) @@ -66,7 +66,7 @@ class JniIdManager { void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_); - ObjPtr<mirror::Object> GetPointerMarker() REQUIRES_SHARED(Locks::mutator_lock_); + EXPORT ObjPtr<mirror::Object> GetPointerMarker() REQUIRES_SHARED(Locks::mutator_lock_); private: template <typename ArtType> @@ -113,7 +113,7 @@ class JniIdManager { // This is required since normally we need to be able to allocate to encode new ids. This should // only be used when absolutely required, for example to invoke user-callbacks during heap walking // or similar. -class ScopedEnableSuspendAllJniIdQueries { +class EXPORT ScopedEnableSuspendAllJniIdQueries { public: ScopedEnableSuspendAllJniIdQueries() REQUIRES_SHARED(Locks::mutator_lock_); ~ScopedEnableSuspendAllJniIdQueries() REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/jni/jni_internal.cc b/runtime/jni/jni_internal.cc index 71bed2e0be..50037ecbfd 100644 --- a/runtime/jni/jni_internal.cc +++ b/runtime/jni/jni_internal.cc @@ -66,7 +66,7 @@ #include "thread.h" #include "well_known_classes-inl.h" -namespace art { +namespace art HIDDEN { namespace { diff --git a/runtime/jni/jni_internal.h b/runtime/jni/jni_internal.h index cfe8208a11..10168b511d 100644 --- a/runtime/jni/jni_internal.h +++ b/runtime/jni/jni_internal.h @@ -27,14 +27,14 @@ #include "runtime.h" #include "thread.h" -namespace art { +namespace art HIDDEN { class ArtField; class ArtMethod; class ScopedObjectAccess; const JNINativeInterface* GetJniNativeInterface(); -const JNINativeInterface* GetRuntimeShutdownNativeInterface(); +EXPORT const JNINativeInterface* GetRuntimeShutdownNativeInterface(); int ThrowNewException(JNIEnv* env, jclass exception_class, const char* msg, jobject cause); diff --git a/runtime/jni/jni_internal_test.cc b/runtime/jni/jni_internal_test.cc index 7f65925910..676bd59a55 100644 --- a/runtime/jni/jni_internal_test.cc +++ b/runtime/jni/jni_internal_test.cc @@ -28,7 +28,7 @@ #include "nativehelper/scoped_local_ref.h" #include "scoped_thread_state_change-inl.h" -namespace art { +namespace art HIDDEN { using android::base::StringPrintf; diff --git a/runtime/jni/local_reference_table-inl.h b/runtime/jni/local_reference_table-inl.h index 8b4604976f..cc94e9c538 100644 --- a/runtime/jni/local_reference_table-inl.h +++ b/runtime/jni/local_reference_table-inl.h @@ -27,7 +27,7 @@ #include "mirror/object_reference.h" #include "verify_object.h" -namespace art { +namespace art HIDDEN { namespace jni { inline void LrtEntry::SetReference(ObjPtr<mirror::Object> ref) { diff --git a/runtime/jni/local_reference_table.cc b/runtime/jni/local_reference_table.cc index bf55f0ec3e..b8c2efcd45 100644 --- a/runtime/jni/local_reference_table.cc +++ b/runtime/jni/local_reference_table.cc @@ -34,7 +34,7 @@ #include <cstdlib> -namespace art { +namespace art HIDDEN { namespace jni { static constexpr bool kDumpStackOnNonLocalReference = false; diff --git a/runtime/jni/local_reference_table.h b/runtime/jni/local_reference_table.h index df2b5075a5..85c7964103 100644 --- a/runtime/jni/local_reference_table.h +++ b/runtime/jni/local_reference_table.h @@ -39,7 +39,7 @@ #include "obj_ptr.h" #include "offsets.h" -namespace art { +namespace art HIDDEN { class RootInfo; @@ -274,8 +274,7 @@ class LocalReferenceTable { // will return null if an error happened (with an appropriate error message set). IndirectRef Add(LRTSegmentState previous_state, ObjPtr<mirror::Object> obj, - std::string* error_msg) - REQUIRES_SHARED(Locks::mutator_lock_); + std::string* error_msg) REQUIRES_SHARED(Locks::mutator_lock_); // Given an `IndirectRef` in the table, return the `Object` it refers to. // @@ -330,7 +329,7 @@ class LocalReferenceTable { // without recovering holes. Thus this is a conservative estimate. size_t FreeCapacity() const; - void VisitRoots(RootVisitor* visitor, const RootInfo& root_info) + EXPORT void VisitRoots(RootVisitor* visitor, const RootInfo& root_info) REQUIRES_SHARED(Locks::mutator_lock_); LRTSegmentState GetSegmentState() const { diff --git a/runtime/jni/local_reference_table_test.cc b/runtime/jni/local_reference_table_test.cc index 5839c60d0a..5063d728b2 100644 --- a/runtime/jni/local_reference_table_test.cc +++ b/runtime/jni/local_reference_table_test.cc @@ -24,7 +24,7 @@ #include "mirror/object-inl.h" #include "scoped_thread_state_change-inl.h" -namespace art { +namespace art HIDDEN { namespace jni { using android::base::StringPrintf; diff --git a/runtime/metrics/statsd.cc b/runtime/metrics/statsd.cc index 716989131e..764550e648 100644 --- a/runtime/metrics/statsd.cc +++ b/runtime/metrics/statsd.cc @@ -386,12 +386,11 @@ class StatsdBackend : public MetricsBackend { EncodeCompileFilter(session_data_.compiler_filter), EncodeCompilationReason(session_data_.compilation_reason), current_timestamp_, - 0, // TODO: collect and report thread type (0 means UNKNOWN, but that - // constant is not present in all branches) + 0, // deprecated - was ArtThreadType datum_id.value(), static_cast<int64_t>(value), - statsd::ART_DATUM_REPORTED__DEX_METADATA_TYPE__ART_DEX_METADATA_TYPE_UNKNOWN, - statsd::ART_DATUM_REPORTED__APK_TYPE__ART_APK_TYPE_UNKNOWN, + 0, // deprecated - was ArtDexMetadataType + 0, // deprecated - was ArtApkType EncodeInstructionSet(kRuntimeISA), EncodeGcCollectorType(Runtime::Current()->GetHeap()->GetForegroundCollectorType()), EncodeUffdMinorFaultSupport()); diff --git a/runtime/native/dalvik_system_BaseDexClassLoader.cc b/runtime/native/dalvik_system_BaseDexClassLoader.cc index a4f702c28d..f9a1aba022 100644 --- a/runtime/native/dalvik_system_BaseDexClassLoader.cc +++ b/runtime/native/dalvik_system_BaseDexClassLoader.cc @@ -25,7 +25,7 @@ #include "nativehelper/jni_macros.h" #include "thread-inl.h" -namespace art { +namespace art HIDDEN { static bool append_string(Thread* self, Handle<mirror::ObjectArray<mirror::String>> array, diff --git a/runtime/native/dalvik_system_BaseDexClassLoader.h b/runtime/native/dalvik_system_BaseDexClassLoader.h index 4ec03ef7a6..5a18b18b50 100644 --- a/runtime/native/dalvik_system_BaseDexClassLoader.h +++ b/runtime/native/dalvik_system_BaseDexClassLoader.h @@ -20,7 +20,9 @@ #include <jni.h> #include <unistd.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_dalvik_system_BaseDexClassLoader(JNIEnv* env); diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc index f602f73630..f1c5d541a9 100644 --- a/runtime/native/dalvik_system_DexFile.cc +++ b/runtime/native/dalvik_system_DexFile.cc @@ -62,7 +62,7 @@ #include <sys/system_properties.h> #endif // ART_TARGET_ANDROID -namespace art { +namespace art HIDDEN { // Should be the same as dalvik.system.DexFile.ENFORCE_READ_ONLY_JAVA_DCL static constexpr uint64_t kEnforceReadOnlyJavaDcl = 218865702; diff --git a/runtime/native/dalvik_system_DexFile.h b/runtime/native/dalvik_system_DexFile.h index 77d219dfad..c22b83d6e8 100644 --- a/runtime/native/dalvik_system_DexFile.h +++ b/runtime/native/dalvik_system_DexFile.h @@ -20,7 +20,9 @@ #include <jni.h> #include <unistd.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { constexpr size_t kOatFileIndex = 0; constexpr size_t kDexFileIndexStart = 1; diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc index cf2b25d6a2..137b04fede 100644 --- a/runtime/native/dalvik_system_VMDebug.cc +++ b/runtime/native/dalvik_system_VMDebug.cc @@ -51,7 +51,7 @@ #include "thread-inl.h" #include "trace.h" -namespace art { +namespace art HIDDEN { static jobjectArray VMDebug_getVmFeatureList(JNIEnv* env, jclass) { ScopedObjectAccess soa(Thread::ForEnv(env)); diff --git a/runtime/native/dalvik_system_VMDebug.h b/runtime/native/dalvik_system_VMDebug.h index b7eb8a8379..6d53fbea9d 100644 --- a/runtime/native/dalvik_system_VMDebug.h +++ b/runtime/native/dalvik_system_VMDebug.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_dalvik_system_VMDebug(JNIEnv* env); diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc index f1561a2530..e774f07dc9 100644 --- a/runtime/native/dalvik_system_VMRuntime.cc +++ b/runtime/native/dalvik_system_VMRuntime.cc @@ -66,6 +66,8 @@ extern "C" void android_set_application_target_sdk_version(uint32_t version); #include "thread-inl.h" #include "thread_list.h" +// TODO(260881207): should be HIDDEN, but some apps fail to launch +// (e.g. b/319255249) namespace art { using android::base::StringPrintf; diff --git a/runtime/native/dalvik_system_VMRuntime.h b/runtime/native/dalvik_system_VMRuntime.h index 795caa5ec6..d66c107a30 100644 --- a/runtime/native/dalvik_system_VMRuntime.h +++ b/runtime/native/dalvik_system_VMRuntime.h @@ -19,6 +19,10 @@ #include <jni.h> +#include "base/macros.h" + +// TODO(260881207): should be HIDDEN, but some apps fail to launch +// (e.g. b/319255249) namespace art { void register_dalvik_system_VMRuntime(JNIEnv* env); diff --git a/runtime/native/dalvik_system_VMStack.cc b/runtime/native/dalvik_system_VMStack.cc index 596b2eb435..599bdb9e4b 100644 --- a/runtime/native/dalvik_system_VMStack.cc +++ b/runtime/native/dalvik_system_VMStack.cc @@ -32,7 +32,7 @@ #include "scoped_thread_state_change-inl.h" #include "thread_list.h" -namespace art { +namespace art HIDDEN { template <typename T, typename ResultT = diff --git a/runtime/native/dalvik_system_VMStack.h b/runtime/native/dalvik_system_VMStack.h index 5638f99ec1..c7a62ad46a 100644 --- a/runtime/native/dalvik_system_VMStack.h +++ b/runtime/native/dalvik_system_VMStack.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_dalvik_system_VMStack(JNIEnv* env); diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc index dd44e2ec4b..cc47032bd4 100644 --- a/runtime/native/dalvik_system_ZygoteHooks.cc +++ b/runtime/native/dalvik_system_ZygoteHooks.cc @@ -47,7 +47,7 @@ #include <sys/resource.h> -namespace art { +namespace art HIDDEN { // Set to true to always determine the non-debuggable classes even if we would not allow a debugger // to actually attach. diff --git a/runtime/native/dalvik_system_ZygoteHooks.h b/runtime/native/dalvik_system_ZygoteHooks.h index ca0658d318..fbd14c0fcc 100644 --- a/runtime/native/dalvik_system_ZygoteHooks.h +++ b/runtime/native/dalvik_system_ZygoteHooks.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_dalvik_system_ZygoteHooks(JNIEnv* env); diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc index 2abc4935e0..1dc74e0db2 100644 --- a/runtime/native/java_lang_Class.cc +++ b/runtime/native/java_lang_Class.cc @@ -56,7 +56,7 @@ #include "scoped_thread_state_change-inl.h" #include "well_known_classes-inl.h" -namespace art { +namespace art HIDDEN { static std::function<hiddenapi::AccessContext()> GetHiddenapiAccessContextFunction(Thread* self) { return [=]() REQUIRES_SHARED(Locks::mutator_lock_) { diff --git a/runtime/native/java_lang_Class.h b/runtime/native/java_lang_Class.h index 8f769c39e9..aaa9b669d0 100644 --- a/runtime/native/java_lang_Class.h +++ b/runtime/native/java_lang_Class.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_java_lang_Class(JNIEnv* env); diff --git a/runtime/native/java_lang_Object.cc b/runtime/native/java_lang_Object.cc index 8fc10d1114..5649b2cc5b 100644 --- a/runtime/native/java_lang_Object.cc +++ b/runtime/native/java_lang_Object.cc @@ -24,7 +24,7 @@ #include "native_util.h" #include "scoped_fast_native_object_access-inl.h" -namespace art { +namespace art HIDDEN { static jobject Object_internalClone(JNIEnv* env, jobject java_this) { ScopedFastNativeObjectAccess soa(env); diff --git a/runtime/native/java_lang_Object.h b/runtime/native/java_lang_Object.h index c860571904..1ea2c05d19 100644 --- a/runtime/native/java_lang_Object.h +++ b/runtime/native/java_lang_Object.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_java_lang_Object(JNIEnv* env); diff --git a/runtime/native/java_lang_StackStreamFactory.cc b/runtime/native/java_lang_StackStreamFactory.cc index f876c1014b..24d903047d 100644 --- a/runtime/native/java_lang_StackStreamFactory.cc +++ b/runtime/native/java_lang_StackStreamFactory.cc @@ -23,7 +23,7 @@ #include "scoped_fast_native_object_access-inl.h" #include "thread.h" -namespace art { +namespace art HIDDEN { static jobject StackStreamFactory_nativeGetStackAnchor(JNIEnv* env, jclass) { ScopedFastNativeObjectAccess soa(env); diff --git a/runtime/native/java_lang_StackStreamFactory.h b/runtime/native/java_lang_StackStreamFactory.h index 2216871ebf..31b3c9528d 100644 --- a/runtime/native/java_lang_StackStreamFactory.h +++ b/runtime/native/java_lang_StackStreamFactory.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_java_lang_StackStreamFactory(JNIEnv* env); diff --git a/runtime/native/java_lang_String.cc b/runtime/native/java_lang_String.cc index f70a188e79..1ba0028fd3 100644 --- a/runtime/native/java_lang_String.cc +++ b/runtime/native/java_lang_String.cc @@ -31,7 +31,7 @@ #include "scoped_thread_state_change-inl.h" #include "verify_object.h" -namespace art { +namespace art HIDDEN { static jchar String_charAt(JNIEnv* env, jobject java_this, jint index) { ScopedFastNativeObjectAccess soa(env); diff --git a/runtime/native/java_lang_String.h b/runtime/native/java_lang_String.h index 357eb3daf9..a78fdcec72 100644 --- a/runtime/native/java_lang_String.h +++ b/runtime/native/java_lang_String.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_java_lang_String(JNIEnv* env); diff --git a/runtime/native/java_lang_StringFactory.cc b/runtime/native/java_lang_StringFactory.cc index 2fbebc0941..e6c03dbcf2 100644 --- a/runtime/native/java_lang_StringFactory.cc +++ b/runtime/native/java_lang_StringFactory.cc @@ -28,7 +28,7 @@ #include "scoped_fast_native_object_access-inl.h" #include "scoped_thread_state_change-inl.h" -namespace art { +namespace art HIDDEN { static jstring StringFactory_newStringFromBytes(JNIEnv* env, jclass, jbyteArray java_data, jint high, jint offset, jint byte_count) { diff --git a/runtime/native/java_lang_StringFactory.h b/runtime/native/java_lang_StringFactory.h index c476ad3db9..cdc19df87d 100644 --- a/runtime/native/java_lang_StringFactory.h +++ b/runtime/native/java_lang_StringFactory.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_java_lang_StringFactory(JNIEnv* env); diff --git a/runtime/native/java_lang_System.cc b/runtime/native/java_lang_System.cc index 63cbd2c815..203d98dc4c 100644 --- a/runtime/native/java_lang_System.cc +++ b/runtime/native/java_lang_System.cc @@ -29,7 +29,7 @@ #include "native_util.h" #include "scoped_fast_native_object_access-inl.h" -namespace art { +namespace art HIDDEN { /* * We make guarantees about the atomicity of accesses to primitive variables. These guarantees diff --git a/runtime/native/java_lang_System.h b/runtime/native/java_lang_System.h index e371fa5db4..a52972711d 100644 --- a/runtime/native/java_lang_System.h +++ b/runtime/native/java_lang_System.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_java_lang_System(JNIEnv* env); diff --git a/runtime/native/java_lang_Thread.cc b/runtime/native/java_lang_Thread.cc index fd67a0a7fa..65e3009c0f 100644 --- a/runtime/native/java_lang_Thread.cc +++ b/runtime/native/java_lang_Thread.cc @@ -29,7 +29,7 @@ #include "thread_list.h" #include "verify_object.h" -namespace art { +namespace art HIDDEN { static jobject Thread_currentThread(JNIEnv* env, jclass) { ScopedFastNativeObjectAccess soa(env); diff --git a/runtime/native/java_lang_Thread.h b/runtime/native/java_lang_Thread.h index 7700ce29a8..ef880a9904 100644 --- a/runtime/native/java_lang_Thread.h +++ b/runtime/native/java_lang_Thread.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_java_lang_Thread(JNIEnv* env); diff --git a/runtime/native/java_lang_Throwable.cc b/runtime/native/java_lang_Throwable.cc index b89e287481..091ad03bb2 100644 --- a/runtime/native/java_lang_Throwable.cc +++ b/runtime/native/java_lang_Throwable.cc @@ -23,7 +23,7 @@ #include "scoped_fast_native_object_access-inl.h" #include "thread.h" -namespace art { +namespace art HIDDEN { static jobject Throwable_nativeFillInStackTrace(JNIEnv* env, jclass) { ScopedFastNativeObjectAccess soa(env); diff --git a/runtime/native/java_lang_Throwable.h b/runtime/native/java_lang_Throwable.h index f9aea84abe..6758e48951 100644 --- a/runtime/native/java_lang_Throwable.h +++ b/runtime/native/java_lang_Throwable.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_java_lang_Throwable(JNIEnv* env); diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc index 4dad46fb8c..ba1fde00d3 100644 --- a/runtime/native/java_lang_VMClassLoader.cc +++ b/runtime/native/java_lang_VMClassLoader.cc @@ -38,7 +38,7 @@ #include "thread-inl.h" #include "well_known_classes-inl.h" -namespace art { +namespace art HIDDEN { // A class so we can be friends with ClassLinker and access internal methods. class VMClassLoader { diff --git a/runtime/native/java_lang_VMClassLoader.h b/runtime/native/java_lang_VMClassLoader.h index bf8d94f5a9..adf0c0aeac 100644 --- a/runtime/native/java_lang_VMClassLoader.h +++ b/runtime/native/java_lang_VMClassLoader.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_java_lang_VMClassLoader(JNIEnv* env); diff --git a/runtime/native/java_lang_invoke_MethodHandle.cc b/runtime/native/java_lang_invoke_MethodHandle.cc index 5309a28a09..819656fd05 100644 --- a/runtime/native/java_lang_invoke_MethodHandle.cc +++ b/runtime/native/java_lang_invoke_MethodHandle.cc @@ -27,7 +27,7 @@ #include "native_util.h" #include "scoped_thread_state_change-inl.h" -namespace art { +namespace art HIDDEN { static void MethodHandle_invokeExactWithFrame(JNIEnv* env, jobject thiz, jobject arguments) { ScopedObjectAccess soa(env); diff --git a/runtime/native/java_lang_invoke_MethodHandle.h b/runtime/native/java_lang_invoke_MethodHandle.h index 1f38ac7b27..f46f32426b 100644 --- a/runtime/native/java_lang_invoke_MethodHandle.h +++ b/runtime/native/java_lang_invoke_MethodHandle.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_java_lang_invoke_MethodHandle(JNIEnv* env); diff --git a/runtime/native/java_lang_invoke_MethodHandleImpl.cc b/runtime/native/java_lang_invoke_MethodHandleImpl.cc index 00ce01f11a..ccd3370ff7 100644 --- a/runtime/native/java_lang_invoke_MethodHandleImpl.cc +++ b/runtime/native/java_lang_invoke_MethodHandleImpl.cc @@ -28,7 +28,7 @@ #include "runtime.h" #include "scoped_thread_state_change-inl.h" -namespace art { +namespace art HIDDEN { static jobject MethodHandleImpl_getMemberInternal(JNIEnv* env, jobject thiz) { ScopedObjectAccess soa(env); diff --git a/runtime/native/java_lang_invoke_MethodHandleImpl.h b/runtime/native/java_lang_invoke_MethodHandleImpl.h index 0e50371697..49d4c2c9ec 100644 --- a/runtime/native/java_lang_invoke_MethodHandleImpl.h +++ b/runtime/native/java_lang_invoke_MethodHandleImpl.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_java_lang_invoke_MethodHandleImpl(JNIEnv* env); diff --git a/runtime/native/java_lang_ref_FinalizerReference.cc b/runtime/native/java_lang_ref_FinalizerReference.cc index 535b243411..52f6f734d9 100644 --- a/runtime/native/java_lang_ref_FinalizerReference.cc +++ b/runtime/native/java_lang_ref_FinalizerReference.cc @@ -26,7 +26,7 @@ #include "native_util.h" #include "scoped_fast_native_object_access-inl.h" -namespace art { +namespace art HIDDEN { static jboolean FinalizerReference_makeCircularListIfUnenqueued(JNIEnv* env, jobject javaThis) { ScopedFastNativeObjectAccess soa(env); diff --git a/runtime/native/java_lang_ref_FinalizerReference.h b/runtime/native/java_lang_ref_FinalizerReference.h index 848a7aded6..13d1a12c34 100644 --- a/runtime/native/java_lang_ref_FinalizerReference.h +++ b/runtime/native/java_lang_ref_FinalizerReference.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_java_lang_ref_FinalizerReference(JNIEnv* env); diff --git a/runtime/native/java_lang_ref_Reference.cc b/runtime/native/java_lang_ref_Reference.cc index bd7235e14f..4c411c8db4 100644 --- a/runtime/native/java_lang_ref_Reference.cc +++ b/runtime/native/java_lang_ref_Reference.cc @@ -26,7 +26,7 @@ #include "native_util.h" #include "scoped_fast_native_object_access-inl.h" -namespace art { +namespace art HIDDEN { static jobject Reference_getReferent(JNIEnv* env, jobject javaThis) { ScopedFastNativeObjectAccess soa(env); diff --git a/runtime/native/java_lang_ref_Reference.h b/runtime/native/java_lang_ref_Reference.h index 0cbf11646d..cc75069657 100644 --- a/runtime/native/java_lang_ref_Reference.h +++ b/runtime/native/java_lang_ref_Reference.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_java_lang_ref_Reference(JNIEnv* env); diff --git a/runtime/native/java_lang_reflect_Array.cc b/runtime/native/java_lang_reflect_Array.cc index ff94593cdf..9ac6e614b6 100644 --- a/runtime/native/java_lang_reflect_Array.cc +++ b/runtime/native/java_lang_reflect_Array.cc @@ -29,7 +29,7 @@ #include "native_util.h" #include "scoped_fast_native_object_access-inl.h" -namespace art { +namespace art HIDDEN { static jobject Array_createMultiArray( JNIEnv* env, jclass, jclass javaElementClass, jintArray javaDimArray) { diff --git a/runtime/native/java_lang_reflect_Array.h b/runtime/native/java_lang_reflect_Array.h index 805bf7992a..35b87b7af4 100644 --- a/runtime/native/java_lang_reflect_Array.h +++ b/runtime/native/java_lang_reflect_Array.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_java_lang_reflect_Array(JNIEnv* env); diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc index 98afddc260..f9278ab0d6 100644 --- a/runtime/native/java_lang_reflect_Constructor.cc +++ b/runtime/native/java_lang_reflect_Constructor.cc @@ -34,7 +34,7 @@ #include "reflection.h" #include "scoped_fast_native_object_access-inl.h" -namespace art { +namespace art HIDDEN { static jobjectArray Constructor_getExceptionTypes(JNIEnv* env, jobject javaMethod) { ScopedFastNativeObjectAccess soa(env); diff --git a/runtime/native/java_lang_reflect_Constructor.h b/runtime/native/java_lang_reflect_Constructor.h index 7baae978e6..9c36ef4fed 100644 --- a/runtime/native/java_lang_reflect_Constructor.h +++ b/runtime/native/java_lang_reflect_Constructor.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_java_lang_reflect_Constructor(JNIEnv* env); diff --git a/runtime/native/java_lang_reflect_Executable.cc b/runtime/native/java_lang_reflect_Executable.cc index 87c9f6c341..3f3b648ecf 100644 --- a/runtime/native/java_lang_reflect_Executable.cc +++ b/runtime/native/java_lang_reflect_Executable.cc @@ -35,7 +35,7 @@ #include "scoped_fast_native_object_access-inl.h" #include "well_known_classes.h" -namespace art { +namespace art HIDDEN { using android::base::StringPrintf; diff --git a/runtime/native/java_lang_reflect_Executable.h b/runtime/native/java_lang_reflect_Executable.h index 0cfed62e49..05b0a234e0 100644 --- a/runtime/native/java_lang_reflect_Executable.h +++ b/runtime/native/java_lang_reflect_Executable.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_java_lang_reflect_Executable(JNIEnv* env); diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc index f2603d4c48..622b514ea3 100644 --- a/runtime/native/java_lang_reflect_Field.cc +++ b/runtime/native/java_lang_reflect_Field.cc @@ -37,7 +37,7 @@ #include "scoped_fast_native_object_access-inl.h" #include "well_known_classes.h" -namespace art { +namespace art HIDDEN { using android::base::StringPrintf; diff --git a/runtime/native/java_lang_reflect_Field.h b/runtime/native/java_lang_reflect_Field.h index 1739711de8..b5368b97f0 100644 --- a/runtime/native/java_lang_reflect_Field.h +++ b/runtime/native/java_lang_reflect_Field.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_java_lang_reflect_Field(JNIEnv* env); diff --git a/runtime/native/java_lang_reflect_Method.cc b/runtime/native/java_lang_reflect_Method.cc index 5f02ad0fd9..8cbc070eee 100644 --- a/runtime/native/java_lang_reflect_Method.cc +++ b/runtime/native/java_lang_reflect_Method.cc @@ -32,7 +32,7 @@ #include "reflection.h" #include "scoped_fast_native_object_access-inl.h" -namespace art { +namespace art HIDDEN { static jobject Method_getDefaultValue(JNIEnv* env, jobject javaMethod) { ScopedFastNativeObjectAccess soa(env); diff --git a/runtime/native/java_lang_reflect_Method.h b/runtime/native/java_lang_reflect_Method.h index 3a93cd05d9..4b48ced9f4 100644 --- a/runtime/native/java_lang_reflect_Method.h +++ b/runtime/native/java_lang_reflect_Method.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_java_lang_reflect_Method(JNIEnv* env); diff --git a/runtime/native/java_lang_reflect_Parameter.cc b/runtime/native/java_lang_reflect_Parameter.cc index 263a56796f..fe9e4e3cbf 100644 --- a/runtime/native/java_lang_reflect_Parameter.cc +++ b/runtime/native/java_lang_reflect_Parameter.cc @@ -28,7 +28,7 @@ #include "native_util.h" #include "scoped_fast_native_object_access-inl.h" -namespace art { +namespace art HIDDEN { using android::base::StringPrintf; diff --git a/runtime/native/java_lang_reflect_Parameter.h b/runtime/native/java_lang_reflect_Parameter.h index f6322b146f..97873fbfaf 100644 --- a/runtime/native/java_lang_reflect_Parameter.h +++ b/runtime/native/java_lang_reflect_Parameter.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_java_lang_reflect_Parameter(JNIEnv* env); diff --git a/runtime/native/java_lang_reflect_Proxy.cc b/runtime/native/java_lang_reflect_Proxy.cc index f723ed223d..a89f8274f8 100644 --- a/runtime/native/java_lang_reflect_Proxy.cc +++ b/runtime/native/java_lang_reflect_Proxy.cc @@ -27,7 +27,7 @@ #include "scoped_fast_native_object_access-inl.h" #include "verify_object.h" -namespace art { +namespace art HIDDEN { static jclass Proxy_generateProxy(JNIEnv* env, jclass, jstring name, jobjectArray interfaces, jobject loader, jobjectArray methods, jobjectArray throws) { diff --git a/runtime/native/java_lang_reflect_Proxy.h b/runtime/native/java_lang_reflect_Proxy.h index e25f0f76b6..e6b3f241c7 100644 --- a/runtime/native/java_lang_reflect_Proxy.h +++ b/runtime/native/java_lang_reflect_Proxy.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_java_lang_reflect_Proxy(JNIEnv* env); diff --git a/runtime/native/java_util_concurrent_atomic_AtomicLong.cc b/runtime/native/java_util_concurrent_atomic_AtomicLong.cc index fa288edcb8..3f4c609432 100644 --- a/runtime/native/java_util_concurrent_atomic_AtomicLong.cc +++ b/runtime/native/java_util_concurrent_atomic_AtomicLong.cc @@ -24,7 +24,7 @@ #include "jni/jni_internal.h" #include "native_util.h" -namespace art { +namespace art HIDDEN { static jboolean AtomicLong_VMSupportsCS8(JNIEnv*, jclass) { return QuasiAtomic::LongAtomicsUseMutexes(kRuntimeISA) ? JNI_FALSE : JNI_TRUE; diff --git a/runtime/native/java_util_concurrent_atomic_AtomicLong.h b/runtime/native/java_util_concurrent_atomic_AtomicLong.h index 990dc861ff..de442ed39b 100644 --- a/runtime/native/java_util_concurrent_atomic_AtomicLong.h +++ b/runtime/native/java_util_concurrent_atomic_AtomicLong.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_java_util_concurrent_atomic_AtomicLong(JNIEnv* env); diff --git a/runtime/native/jdk_internal_misc_Unsafe.cc b/runtime/native/jdk_internal_misc_Unsafe.cc index 9b2021d176..10c6b2da4f 100644 --- a/runtime/native/jdk_internal_misc_Unsafe.cc +++ b/runtime/native/jdk_internal_misc_Unsafe.cc @@ -36,7 +36,7 @@ #include "scoped_fast_native_object_access-inl.h" #include "well_known_classes-inl.h" -namespace art { +namespace art HIDDEN { namespace { // Checks a JNI argument `size` fits inside a size_t and throws a RuntimeException if not (see diff --git a/runtime/native/jdk_internal_misc_Unsafe.h b/runtime/native/jdk_internal_misc_Unsafe.h index 779cd5fb3e..61b377bbfa 100644 --- a/runtime/native/jdk_internal_misc_Unsafe.h +++ b/runtime/native/jdk_internal_misc_Unsafe.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_jdk_internal_misc_Unsafe(JNIEnv* env); diff --git a/runtime/native/libcore_io_Memory.cc b/runtime/native/libcore_io_Memory.cc index 5e38280259..66a16ed0ad 100644 --- a/runtime/native/libcore_io_Memory.cc +++ b/runtime/native/libcore_io_Memory.cc @@ -25,7 +25,7 @@ #include "nativehelper/scoped_primitive_array.h" #include "scoped_fast_native_object_access-inl.h" -namespace art { +namespace art HIDDEN { // Use packed structures for access to unaligned data on targets with alignment restrictions. // The compiler will generate appropriate code to access these structures without diff --git a/runtime/native/libcore_io_Memory.h b/runtime/native/libcore_io_Memory.h index 8c8a2ec17c..bf60986be4 100644 --- a/runtime/native/libcore_io_Memory.h +++ b/runtime/native/libcore_io_Memory.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_libcore_io_Memory(JNIEnv* env); diff --git a/runtime/native/libcore_util_CharsetUtils.cc b/runtime/native/libcore_util_CharsetUtils.cc index 46f8993a10..b497f1092d 100644 --- a/runtime/native/libcore_util_CharsetUtils.cc +++ b/runtime/native/libcore_util_CharsetUtils.cc @@ -28,7 +28,7 @@ #include "nativehelper/jni_macros.h" #include "scoped_fast_native_object_access-inl.h" -namespace art { +namespace art HIDDEN { static void CharsetUtils_asciiBytesToChars(JNIEnv* env, jclass, jbyteArray javaBytes, jint offset, jint length, jcharArray javaChars) { diff --git a/runtime/native/libcore_util_CharsetUtils.h b/runtime/native/libcore_util_CharsetUtils.h index 3518bdb6f7..eaafcab30e 100644 --- a/runtime/native/libcore_util_CharsetUtils.h +++ b/runtime/native/libcore_util_CharsetUtils.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_libcore_util_CharsetUtils(JNIEnv* env); diff --git a/runtime/native/native_util.h b/runtime/native/native_util.h index 784dba319e..f399359b11 100644 --- a/runtime/native/native_util.h +++ b/runtime/native/native_util.h @@ -23,7 +23,7 @@ #include "base/macros.h" #include "nativehelper/scoped_local_ref.h" -namespace art { +namespace art HIDDEN { ALWAYS_INLINE inline void RegisterNativeMethodsInternal(JNIEnv* env, const char* jni_class_name, diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc index 419aed8578..b2e94f90cc 100644 --- a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc +++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc @@ -26,7 +26,7 @@ #include "nativehelper/scoped_primitive_array.h" #include "scoped_fast_native_object_access-inl.h" -namespace art { +namespace art HIDDEN { static void DdmServer_nativeSendChunk(JNIEnv* env, jclass, jint type, jbyteArray javaData, jint offset, jint length) { diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.h b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.h index 9a4645c1aa..fc5cfc9b59 100644 --- a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.h +++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_org_apache_harmony_dalvik_ddmc_DdmServer(JNIEnv* env); diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc index f20cd281e8..6da4529289 100644 --- a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc +++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc @@ -31,7 +31,7 @@ #include "scoped_fast_native_object_access-inl.h" #include "thread_list.h" -namespace art { +namespace art HIDDEN { static void DdmVmInternal_setRecentAllocationsTrackingEnabled(JNIEnv*, jclass, jboolean enable) { Dbg::SetAllocTrackingEnabled(enable); diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.h b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.h index 736e4c8793..5484f3682c 100644 --- a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.h +++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_org_apache_harmony_dalvik_ddmc_DdmVmInternal(JNIEnv* env); diff --git a/runtime/native/scoped_fast_native_object_access-inl.h b/runtime/native/scoped_fast_native_object_access-inl.h index 0b8ad117d2..cd1a0b26d7 100644 --- a/runtime/native/scoped_fast_native_object_access-inl.h +++ b/runtime/native/scoped_fast_native_object_access-inl.h @@ -22,7 +22,7 @@ #include "art_method.h" #include "scoped_thread_state_change-inl.h" -namespace art { +namespace art HIDDEN { inline ScopedFastNativeObjectAccess::ScopedFastNativeObjectAccess(JNIEnv* env) : ScopedObjectAccessAlreadyRunnable(env) { diff --git a/runtime/native/scoped_fast_native_object_access.h b/runtime/native/scoped_fast_native_object_access.h index 6a9365d517..a3b01d7701 100644 --- a/runtime/native/scoped_fast_native_object_access.h +++ b/runtime/native/scoped_fast_native_object_access.h @@ -19,9 +19,10 @@ #include <jni.h> +#include "base/macros.h" #include "scoped_thread_state_change.h" -namespace art { +namespace art HIDDEN { // Variant of ScopedObjectAccess that does no runnable transitions. Should only be used by "fast" // JNI methods. diff --git a/runtime/native/string_array_utils.h b/runtime/native/string_array_utils.h index 41d50933f9..f1fbe540f5 100644 --- a/runtime/native/string_array_utils.h +++ b/runtime/native/string_array_utils.h @@ -17,13 +17,14 @@ #ifndef ART_RUNTIME_NATIVE_STRING_ARRAY_UTILS_H_ #define ART_RUNTIME_NATIVE_STRING_ARRAY_UTILS_H_ +#include "base/macros.h" #include "base/locks.h" #include "class_root-inl.h" #include "handle_scope-inl.h" #include "mirror/object_array-alloc-inl.h" #include "mirror/string.h" -namespace art { +namespace art HIDDEN { namespace detail { diff --git a/runtime/native/sun_misc_Unsafe.cc b/runtime/native/sun_misc_Unsafe.cc index f1e47ee100..573b5a9db2 100644 --- a/runtime/native/sun_misc_Unsafe.cc +++ b/runtime/native/sun_misc_Unsafe.cc @@ -36,7 +36,7 @@ #include "scoped_fast_native_object_access-inl.h" #include "well_known_classes-inl.h" -namespace art { +namespace art HIDDEN { static jboolean Unsafe_compareAndSwapInt(JNIEnv* env, jobject, jobject javaObj, jlong offset, jint expectedValue, jint newValue) { diff --git a/runtime/native/sun_misc_Unsafe.h b/runtime/native/sun_misc_Unsafe.h index 93194f4fad..fe120b5a9b 100644 --- a/runtime/native/sun_misc_Unsafe.h +++ b/runtime/native/sun_misc_Unsafe.h @@ -19,7 +19,9 @@ #include <jni.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { void register_sun_misc_Unsafe(JNIEnv* env); diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc index 86a2ddabfd..590a596c1f 100644 --- a/runtime/quick_exception_handler.cc +++ b/runtime/quick_exception_handler.cc @@ -407,10 +407,6 @@ class DeoptimizeStackVisitor final : public StackVisitor { return bottom_shadow_frame_; } - const std::vector<uint32_t>& GetDexPcs() const { - return dex_pcs_; - } - void FinishStackWalk() REQUIRES_SHARED(Locks::mutator_lock_) { // This is the upcall, or the next full frame in single-frame deopt, or the // code isn't deoptimizeable. We remember the frame and last pc so that we @@ -519,14 +515,11 @@ class DeoptimizeStackVisitor final : public StackVisitor { } prev_shadow_frame_ = new_frame; - if (single_frame_deopt_) { - dex_pcs_.push_back(GetDexPc()); - if (!IsInInlinedFrame()) { - // Single-frame deopt ends at the first non-inlined frame and needs to store that method. - single_frame_done_ = true; - single_frame_deopt_method_ = method; - single_frame_deopt_quick_method_header_ = GetCurrentOatQuickMethodHeader(); - } + if (single_frame_deopt_ && !IsInInlinedFrame()) { + // Single-frame deopt ends at the first non-inlined frame and needs to store that method. + single_frame_done_ = true; + single_frame_deopt_method_ = method; + single_frame_deopt_quick_method_header_ = GetCurrentOatQuickMethodHeader(); } callee_method_ = method; return true; @@ -666,7 +659,6 @@ class DeoptimizeStackVisitor final : public StackVisitor { // a deopt after running method exit callbacks if the callback throws or requests events that // need a deopt. bool skip_method_exit_callbacks_; - std::vector<uint32_t> dex_pcs_; DISALLOW_COPY_AND_ASSIGN(DeoptimizeStackVisitor); }; @@ -747,26 +739,11 @@ void QuickExceptionHandler::DeoptimizeSingleFrame(DeoptimizationKind kind) { case Instruction::INVOKE_VIRTUAL: case Instruction::INVOKE_INTERFACE_RANGE: case Instruction::INVOKE_VIRTUAL_RANGE: { - uint32_t encoded_dex_pc = InlineCache::EncodeDexPc( - visitor.GetSingleFrameDeoptMethod(), - visitor.GetDexPcs(), - runtime->GetJit()->GetJitCompiler()->GetInlineMaxCodeUnits()); - if (encoded_dex_pc != static_cast<uint32_t>(-1)) { - // The inline cache comes from the top-level method. - runtime->GetJit()->GetCodeCache()->MaybeUpdateInlineCache( - visitor.GetSingleFrameDeoptMethod(), - encoded_dex_pc, - shadow_frame->GetVRegReference(inst->VRegC())->GetClass(), - self_); - } else { - // If the top-level inline cache did not exist, update the one for the - // bottom method, we know it's the one that was used for compilation. - runtime->GetJit()->GetCodeCache()->MaybeUpdateInlineCache( - shadow_frame->GetMethod(), - dex_pc, - shadow_frame->GetVRegReference(inst->VRegC())->GetClass(), - self_); - } + runtime->GetJit()->GetCodeCache()->MaybeUpdateInlineCache( + shadow_frame->GetMethod(), + dex_pc, + shadow_frame->GetVRegReference(inst->VRegC())->GetClass(), + self_); break; } default: { diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h index d8f68c4080..83ab469c68 100644 --- a/runtime/thread-inl.h +++ b/runtime/thread-inl.h @@ -237,6 +237,7 @@ inline void Thread::TransitionToSuspendedAndRunCheckpoints(ThreadState new_state StateAndFlags old_state_and_flags = GetStateAndFlags(std::memory_order_relaxed); DCHECK_EQ(old_state_and_flags.GetState(), ThreadState::kRunnable); if (UNLIKELY(old_state_and_flags.IsFlagSet(ThreadFlag::kCheckpointRequest))) { + IncrementStatsCounter(&checkpoint_count_); RunCheckpointFunction(); continue; } @@ -255,6 +256,7 @@ inline void Thread::TransitionToSuspendedAndRunCheckpoints(ThreadState new_state tls32_.state_and_flags.CompareAndSetWeakRelease(old_state_and_flags.GetValue(), new_state_and_flags.GetValue()); if (LIKELY(done)) { + IncrementStatsCounter(&suspended_count_); break; } } diff --git a/runtime/thread.cc b/runtime/thread.cc index 719ecfbf9c..46856e3e99 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -1724,8 +1724,10 @@ bool Thread::RequestSynchronousCheckpoint(Closure* function, ThreadState wait_st } } if (!is_suspended) { - bool success = - Runtime::Current()->GetThreadList()->WaitForSuspendBarrier(&wrapped_barrier.barrier_); + bool success = !Runtime::Current() + ->GetThreadList() + ->WaitForSuspendBarrier(&wrapped_barrier.barrier_) + .has_value(); CHECK(success); } diff --git a/runtime/thread.h b/runtime/thread.h index 49e9952e70..6de1e26615 100644 --- a/runtime/thread.h +++ b/runtime/thread.h @@ -2324,6 +2324,15 @@ class EXPORT Thread { // Debug disable read barrier count, only is checked for debug builds and only in the runtime. uint8_t debug_disallow_read_barrier_ = 0; + // Counters used only for debugging and error reporting. Likely to wrap. Small to avoid + // increasing Thread size. + // We currently maintain these unconditionally, since it doesn't cost much, and we seem to have + // persistent issues with suspension timeouts, which these should help to diagnose. + // TODO: Reconsider this. + std::atomic<uint8_t> suspended_count_ = 0; // Number of times we entered a suspended state after + // running checkpoints. + std::atomic<uint8_t> checkpoint_count_ = 0; // Number of checkpoints we started running. + // Note that it is not in the packed struct, may not be accessed for cross compilation. uintptr_t poison_object_cookie_ = 0; diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc index c07f53fbdb..d69ad35a9e 100644 --- a/runtime/thread_list.cc +++ b/runtime/thread_list.cc @@ -655,36 +655,107 @@ void ThreadList::FlipThreadRoots(Closure* thread_flip_visitor, Locks::mutator_lock_->SharedUnlock(self); } -bool ThreadList::WaitForSuspendBarrier(AtomicInteger* barrier) { #if ART_USE_FUTEXES - // Only fail after multiple timeouts, to make us robust against app freezing. - static constexpr int kIters = 5; +static constexpr int kSuspendBarrierIters = 5; + +// Returns true if it timed out. +static bool WaitOnceForSuspendBarrier(AtomicInteger* barrier, + int32_t cur_val, + uint64_t timeout_ns) { timespec wait_timeout; - InitTimeSpec( - false, CLOCK_MONOTONIC, NsToMs(thread_suspend_timeout_ns_ / kIters), 0, &wait_timeout); -#else - static constexpr int kIters = 10'000'000; -#endif - for (int i = 0; i < kIters;) { - int32_t cur_val = barrier->load(std::memory_order_acquire); - if (cur_val <= 0) { - DCHECK_EQ(cur_val, 0); + DCHECK_GE(NsToMs(timeout_ns / kSuspendBarrierIters), 100ul); + InitTimeSpec(false, CLOCK_MONOTONIC, NsToMs(timeout_ns / kSuspendBarrierIters), 0, &wait_timeout); + if (futex(barrier->Address(), FUTEX_WAIT_PRIVATE, cur_val, &wait_timeout, nullptr, 0) != 0) { + if (errno == ETIMEDOUT) { return true; + } else if (errno != EAGAIN && errno != EINTR) { + PLOG(FATAL) << "futex wait for suspend barrier failed"; } -#if ART_USE_FUTEXES - if (futex(barrier->Address(), FUTEX_WAIT_PRIVATE, cur_val, &wait_timeout, nullptr, 0) != 0) { - if (errno == ETIMEDOUT) { - ++i; - } else if (errno != EAGAIN && errno != EINTR) { - PLOG(FATAL) << "futex wait for suspend barrier failed"; - } + } + return false; +} + +#else +static constexpr int kSuspendBarrierIters = 10; + +static bool WaitOnceForSuspendBarrier(AtomicInteger* barrier, + int32_t cur_val, + uint64_t timeout_ns) { + DCHECK_GE(NsToMs(timeout_ns / kSuspendBarrierIters), 100ul); + for (int i = 0; i < 1'000'000; ++i) { + sched_yield(); + if (barrier->load(std::memory_order_acquire) == 0) { + return false; } + } + return true; +} +#endif + +// Return a short string describing the scheduling state of the thread with the given tid. +static std::string GetThreadState(pid_t t) { +#if defined(__linux__) + static constexpr int BUF_SIZE = 90; + char file_name_buf[BUF_SIZE]; + char buf[BUF_SIZE]; + snprintf(file_name_buf, BUF_SIZE, "/proc/%d/stat", t); + int stat_fd = open(file_name_buf, O_RDONLY | O_CLOEXEC); + if (stat_fd < 0) { + return std::string("failed to get thread state: ") + std::string(strerror(errno)); + } + CHECK(stat_fd >= 0) << strerror(errno); + ssize_t bytes_read = TEMP_FAILURE_RETRY(read(stat_fd, buf, BUF_SIZE)); + CHECK(bytes_read >= 0) << strerror(errno); + int ret = close(stat_fd); + DCHECK(ret == 0) << strerror(errno); + buf[BUF_SIZE - 1] = '\0'; + return buf; #else - sched_yield(); // Not ideal, but ART_USE_FUTEXES is set on Linux, including all targets. - ++i; + return "unknown state"; +#endif +} + +std::optional<std::string> ThreadList::WaitForSuspendBarrier(AtomicInteger* barrier, pid_t t) { + // Only fail after kIter timeouts, to make us robust against app freezing. +#if ART_USE_FUTEXES + const uint64_t start_time = NanoTime(); #endif + int32_t cur_val = barrier->load(std::memory_order_acquire); + if (cur_val <= 0) { + DCHECK_EQ(cur_val, 0); + return std::nullopt; + } + int i = 0; + if (WaitOnceForSuspendBarrier(barrier, cur_val, thread_suspend_timeout_ns_)) { + i = 1; + } + cur_val = barrier->load(std::memory_order_acquire); + if (cur_val <= 0) { + DCHECK_EQ(cur_val, 0); + return std::nullopt; + } + + // Long wait; gather information in case of timeout. + std::string sampled_state = t == 0 ? "" : GetThreadState(t); + while (i < kSuspendBarrierIters) { + if (WaitOnceForSuspendBarrier(barrier, cur_val, thread_suspend_timeout_ns_)) { + ++i; +#if ART_USE_FUTEXES + CHECK_GE(NanoTime() - start_time, + i * thread_suspend_timeout_ns_ / kSuspendBarrierIters - 1'000'000); +#endif + } + cur_val = barrier->load(std::memory_order_acquire); + if (cur_val <= 0) { + DCHECK_EQ(cur_val, 0); + return std::nullopt; + } } - return barrier->load(std::memory_order_acquire) == 0; + std::string result = t == 0 ? "" : + "Target states: [" + sampled_state + ", " + GetThreadState(t) + + "]" + std::to_string(cur_val) + "@" + + std::to_string((uintptr_t)barrier) + "->"; + return result + std::to_string(barrier->load(std::memory_order_acquire)); } void ThreadList::SuspendAll(const char* cause, bool long_suspend) { @@ -830,7 +901,7 @@ void ThreadList::SuspendAllInternal(Thread* self, SuspendReason reason) { // We're already not runnable, so an attempt to suspend us should succeed. } - if (!WaitForSuspendBarrier(&pending_threads)) { + if (WaitForSuspendBarrier(&pending_threads).has_value()) { const uint64_t wait_time = NanoTime() - start_time; MutexLock mu(self, *Locks::thread_list_lock_); MutexLock mu2(self, *Locks::thread_suspend_count_lock_); @@ -1005,7 +1076,7 @@ Thread* ThreadList::SuspendThreadByPeer(jobject peer, SuspendReason reason) { usleep(kThreadSuspendSleepUs); } // Now wait for target to decrement suspend barrier. - if (is_suspended || WaitForSuspendBarrier(&wrapped_barrier.barrier_)) { + if (is_suspended || !WaitForSuspendBarrier(&wrapped_barrier.barrier_).has_value()) { // wrapped_barrier.barrier_ has been decremented and will no longer be accessed. VLOG(threads) << "SuspendThreadByPeer thread suspended: " << *thread; if (ATraceEnabled()) { @@ -1035,7 +1106,11 @@ Thread* ThreadList::SuspendThreadByThreadId(uint32_t thread_id, SuspendReason re CHECK_NE(thread_id, kInvalidThreadId); VLOG(threads) << "SuspendThreadByThreadId starting"; Thread* thread; + pid_t tid; + uint8_t suspended_count; + uint8_t checkpoint_count; WrappedSuspend1Barrier wrapped_barrier{}; + static_assert(sizeof wrapped_barrier.barrier_ == sizeof(uint32_t)); for (int iter_count = 1;; ++iter_count) { { // Note: this will transition to runnable and potentially suspend. @@ -1053,6 +1128,9 @@ Thread* ThreadList::SuspendThreadByThreadId(uint32_t thread_id, SuspendReason re { MutexLock suspend_count_mu(self, *Locks::thread_suspend_count_lock_); if (LIKELY(self->GetSuspendCount() == 0)) { + tid = thread->GetTid(); + suspended_count = thread->suspended_count_; + checkpoint_count = thread->checkpoint_count_; thread->IncrementSuspendCount(self, nullptr, &wrapped_barrier, reason); if (thread->IsSuspended()) { // See the discussion in mutator_gc_coord.md and SuspendAllInternal for the race here. @@ -1077,7 +1155,17 @@ Thread* ThreadList::SuspendThreadByThreadId(uint32_t thread_id, SuspendReason re usleep(kThreadSuspendSleepUs); } // Now wait for target to decrement suspend barrier. - if (is_suspended || WaitForSuspendBarrier(&wrapped_barrier.barrier_)) { + std::optional<std::string> failure_info; + if (!is_suspended) { + // As an experiment, redundantly trigger suspension. TODO: Remove this. + std::atomic_thread_fence(std::memory_order_seq_cst); + thread->TriggerSuspend(); + failure_info = WaitForSuspendBarrier(&wrapped_barrier.barrier_, tid); + if (!failure_info.has_value()) { + is_suspended = true; + } + } + if (is_suspended) { // wrapped_barrier.barrier_ has been decremented and will no longer be accessed. VLOG(threads) << "SuspendThreadByThreadId thread suspended: " << *thread; if (ATraceEnabled()) { @@ -1099,15 +1187,20 @@ Thread* ThreadList::SuspendThreadByThreadId(uint32_t thread_id, SuspendReason re MutexLock suspend_count_mu(self, *Locks::thread_suspend_count_lock_); first_barrier = thread->tlsPtr_.active_suspend1_barriers; } + // 'thread' should still be suspended, and hence stick around. LOG(FATAL) << StringPrintf( "SuspendThreadByThreadId timed out: %d (%s), state&flags: 0x%x, priority: %d," - " barriers: %p, ours: %p", + " barriers: %p, ours: %p, barrier value: %d, nsusps: %d, ncheckpts: %d, thread_info: %s", thread_id, name.c_str(), thread->GetStateAndFlags(std::memory_order_relaxed).GetValue(), thread->GetNativePriority(), first_barrier, - &wrapped_barrier); + &wrapped_barrier, + wrapped_barrier.barrier_.load(), + thread->suspended_count_ - suspended_count, + thread->checkpoint_count_ - checkpoint_count, + failure_info.value().c_str()); UNREACHABLE(); } } diff --git a/runtime/thread_list.h b/runtime/thread_list.h index 55baed8a31..f5eb5fdb2a 100644 --- a/runtime/thread_list.h +++ b/runtime/thread_list.h @@ -211,8 +211,10 @@ class ThreadList { REQUIRES(!Locks::thread_list_lock_, !Locks::thread_suspend_count_lock_, !Locks::mutator_lock_); - // Wait for suspend barrier to reach zero. Return false on timeout. - bool WaitForSuspendBarrier(AtomicInteger* barrier); + // Wait for suspend barrier to reach zero. Return a string possibly containing diagnostic + // information on timeout, nothing on success. The argument t specifies a thread to monitor for + // the diagnostic information. If 0 is passed, we return an empty string on timeout. + std::optional<std::string> WaitForSuspendBarrier(AtomicInteger* barrier, pid_t t = 0); private: uint32_t AllocThreadId(Thread* self); diff --git a/runtime/verifier/class_verifier.cc b/runtime/verifier/class_verifier.cc index 084e714b42..d1b882f9f4 100644 --- a/runtime/verifier/class_verifier.cc +++ b/runtime/verifier/class_verifier.cc @@ -42,7 +42,7 @@ #include "verifier/method_verifier.h" #include "verifier/reg_type_cache.h" -namespace art { +namespace art HIDDEN { namespace verifier { using android::base::StringPrintf; diff --git a/runtime/verifier/class_verifier.h b/runtime/verifier/class_verifier.h index 65bc28c299..75a5a35b7e 100644 --- a/runtime/verifier/class_verifier.h +++ b/runtime/verifier/class_verifier.h @@ -23,13 +23,14 @@ #include <android-base/thread_annotations.h> #include "base/locks.h" +#include "base/macros.h" #include "handle.h" #include "obj_ptr.h" #include "verifier/method_verifier.h" #include "verifier/reg_type_cache.h" #include "verifier_enums.h" -namespace art { +namespace art HIDDEN { class ClassLinker; class CompilerCallbacks; @@ -55,18 +56,17 @@ class ClassVerifier { public: // The main entrypoint for class verification. During AOT, `klass` can be // null. - static FailureKind VerifyClass(Thread* self, - VerifierDeps* verifier_deps, - const DexFile* dex_file, - Handle<mirror::Class> klass, - Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, - const dex::ClassDef& class_def, - CompilerCallbacks* callbacks, - HardFailLogMode log_level, - uint32_t api_level, - std::string* error) - REQUIRES_SHARED(Locks::mutator_lock_); + EXPORT static FailureKind VerifyClass(Thread* self, + VerifierDeps* verifier_deps, + const DexFile* dex_file, + Handle<mirror::Class> klass, + Handle<mirror::DexCache> dex_cache, + Handle<mirror::ClassLoader> class_loader, + const dex::ClassDef& class_def, + CompilerCallbacks* callbacks, + HardFailLogMode log_level, + uint32_t api_level, + std::string* error) REQUIRES_SHARED(Locks::mutator_lock_); private: DISALLOW_COPY_AND_ASSIGN(ClassVerifier); diff --git a/runtime/verifier/instruction_flags.cc b/runtime/verifier/instruction_flags.cc index ca3c68796d..73fb375731 100644 --- a/runtime/verifier/instruction_flags.cc +++ b/runtime/verifier/instruction_flags.cc @@ -18,7 +18,7 @@ #include <string.h> -namespace art { +namespace art HIDDEN { namespace verifier { std::string InstructionFlags::ToString() const { diff --git a/runtime/verifier/instruction_flags.h b/runtime/verifier/instruction_flags.h index 6cd2865f25..da5e2cd178 100644 --- a/runtime/verifier/instruction_flags.h +++ b/runtime/verifier/instruction_flags.h @@ -22,7 +22,7 @@ #include "base/macros.h" -namespace art { +namespace art HIDDEN { namespace verifier { class InstructionFlags final { diff --git a/runtime/verifier/method_verifier-inl.h b/runtime/verifier/method_verifier-inl.h index a9fb1a0773..a13a58eede 100644 --- a/runtime/verifier/method_verifier-inl.h +++ b/runtime/verifier/method_verifier-inl.h @@ -19,7 +19,7 @@ #include "method_verifier.h" -namespace art { +namespace art HIDDEN { namespace verifier { inline RegisterLine* MethodVerifier::GetRegLine(uint32_t dex_pc) { diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 9830bfc8d7..fc5a57ed26 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -65,7 +65,7 @@ #include "verifier/method_verifier.h" #include "verifier_deps.h" -namespace art { +namespace art HIDDEN { namespace verifier { using android::base::StringPrintf; diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h index 649a24526c..288043610e 100644 --- a/runtime/verifier/method_verifier.h +++ b/runtime/verifier/method_verifier.h @@ -36,7 +36,7 @@ #include "register_line.h" #include "verifier_enums.h" -namespace art { +namespace art HIDDEN { class ClassLinker; class DexFile; @@ -97,25 +97,25 @@ class PcToRegisterLineTable { // The verifier class MethodVerifier { public: - static MethodVerifier* VerifyMethodAndDump(Thread* self, - VariableIndentationOutputStream* vios, - uint32_t method_idx, - const DexFile* dex_file, - Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, - const dex::ClassDef& class_def, - const dex::CodeItem* code_item, - uint32_t method_access_flags, - uint32_t api_level) + EXPORT static MethodVerifier* VerifyMethodAndDump(Thread* self, + VariableIndentationOutputStream* vios, + uint32_t method_idx, + const DexFile* dex_file, + Handle<mirror::DexCache> dex_cache, + Handle<mirror::ClassLoader> class_loader, + const dex::ClassDef& class_def, + const dex::CodeItem* code_item, + uint32_t method_access_flags, + uint32_t api_level) REQUIRES_SHARED(Locks::mutator_lock_); // Calculates the type information at the given `dex_pc`. // No classes will be loaded. - static MethodVerifier* CalculateVerificationInfo(Thread* self, - ArtMethod* method, - Handle<mirror::DexCache> dex_cache, - Handle<mirror::ClassLoader> class_loader, - uint32_t dex_pc) + EXPORT static MethodVerifier* CalculateVerificationInfo(Thread* self, + ArtMethod* method, + Handle<mirror::DexCache> dex_cache, + Handle<mirror::ClassLoader> class_loader, + uint32_t dex_pc) REQUIRES_SHARED(Locks::mutator_lock_); const DexFile& GetDexFile() const { diff --git a/runtime/verifier/method_verifier_test.cc b/runtime/verifier/method_verifier_test.cc index 0f0fd17905..1c6ed7c9b0 100644 --- a/runtime/verifier/method_verifier_test.cc +++ b/runtime/verifier/method_verifier_test.cc @@ -30,7 +30,7 @@ #include "scoped_thread_state_change-inl.h" #include "verifier_enums.h" -namespace art { +namespace art HIDDEN { namespace verifier { using metrics::test::CounterValue; diff --git a/runtime/verifier/reg_type-inl.h b/runtime/verifier/reg_type-inl.h index 7fb24b2602..8db2fe669a 100644 --- a/runtime/verifier/reg_type-inl.h +++ b/runtime/verifier/reg_type-inl.h @@ -25,7 +25,7 @@ #include "mirror/class.h" #include "verifier_deps.h" -namespace art { +namespace art HIDDEN { namespace verifier { inline bool RegType::CanAccess(const RegType& other) const { diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc index 0433c6dcc5..845bcdc087 100644 --- a/runtime/verifier/reg_type.cc +++ b/runtime/verifier/reg_type.cc @@ -35,7 +35,7 @@ #include <limits> #include <sstream> -namespace art { +namespace art HIDDEN { namespace verifier { using android::base::StringPrintf; diff --git a/runtime/verifier/reg_type.h b/runtime/verifier/reg_type.h index 6cc9880f8c..66f075e73f 100644 --- a/runtime/verifier/reg_type.h +++ b/runtime/verifier/reg_type.h @@ -33,7 +33,7 @@ #include "handle_scope.h" #include "obj_ptr.h" -namespace art { +namespace art HIDDEN { namespace mirror { class Class; class ClassLoader; diff --git a/runtime/verifier/reg_type_cache-inl.h b/runtime/verifier/reg_type_cache-inl.h index b987c2c59c..b619694714 100644 --- a/runtime/verifier/reg_type_cache-inl.h +++ b/runtime/verifier/reg_type_cache-inl.h @@ -28,7 +28,7 @@ #include "reg_type.h" #include "reg_type_cache.h" -namespace art { +namespace art HIDDEN { namespace verifier { inline const art::verifier::RegType& RegTypeCache::GetFromId(uint16_t id) const { diff --git a/runtime/verifier/reg_type_cache.cc b/runtime/verifier/reg_type_cache.cc index 55b37338cf..e57290c418 100644 --- a/runtime/verifier/reg_type_cache.cc +++ b/runtime/verifier/reg_type_cache.cc @@ -32,7 +32,7 @@ #include "mirror/object-inl.h" #include "reg_type-inl.h" -namespace art { +namespace art HIDDEN { namespace verifier { ALWAYS_INLINE static inline bool MatchingPrecisionForClass(const RegType* entry, bool precise) diff --git a/runtime/verifier/reg_type_cache.h b/runtime/verifier/reg_type_cache.h index d88d4db177..ae8b904ecd 100644 --- a/runtime/verifier/reg_type_cache.h +++ b/runtime/verifier/reg_type_cache.h @@ -28,7 +28,7 @@ #include "gc_root.h" #include "handle_scope.h" -namespace art { +namespace art HIDDEN { namespace mirror { class Class; diff --git a/runtime/verifier/reg_type_test.cc b/runtime/verifier/reg_type_test.cc index 8ab7fc8cae..ec4c23ee59 100644 --- a/runtime/verifier/reg_type_test.cc +++ b/runtime/verifier/reg_type_test.cc @@ -28,7 +28,7 @@ #include "scoped_thread_state_change-inl.h" #include "thread-current-inl.h" -namespace art { +namespace art HIDDEN { namespace verifier { class RegTypeTest : public CommonRuntimeTest { diff --git a/runtime/verifier/register_line-inl.h b/runtime/verifier/register_line-inl.h index 6fa87c6fec..3967aaa88e 100644 --- a/runtime/verifier/register_line-inl.h +++ b/runtime/verifier/register_line-inl.h @@ -23,7 +23,7 @@ #include "method_verifier.h" #include "reg_type_cache-inl.h" -namespace art { +namespace art HIDDEN { namespace verifier { // Should we dump a warning on failures to verify balanced locking? That would be an indication to diff --git a/runtime/verifier/register_line.cc b/runtime/verifier/register_line.cc index 0e9e0d4a52..62f2eb3ec0 100644 --- a/runtime/verifier/register_line.cc +++ b/runtime/verifier/register_line.cc @@ -23,7 +23,7 @@ #include "reg_type-inl.h" #include "register_line-inl.h" -namespace art { +namespace art HIDDEN { namespace verifier { using android::base::StringPrintf; diff --git a/runtime/verifier/register_line.h b/runtime/verifier/register_line.h index 3db1efb38e..fc8c4cbc6c 100644 --- a/runtime/verifier/register_line.h +++ b/runtime/verifier/register_line.h @@ -24,10 +24,11 @@ #include <android-base/logging.h> #include "base/locks.h" +#include "base/macros.h" #include "base/safe_map.h" #include "base/scoped_arena_containers.h" -namespace art { +namespace art HIDDEN { class Instruction; diff --git a/runtime/verifier/scoped_newline.h b/runtime/verifier/scoped_newline.h index fb29e3ece8..ef2fc92154 100644 --- a/runtime/verifier/scoped_newline.h +++ b/runtime/verifier/scoped_newline.h @@ -21,7 +21,9 @@ #include <android-base/logging.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { namespace verifier { // RAII to inject a newline after a message. diff --git a/runtime/verifier/verifier_compiler_binding.h b/runtime/verifier/verifier_compiler_binding.h index 2266d50171..f94ea02109 100644 --- a/runtime/verifier/verifier_compiler_binding.h +++ b/runtime/verifier/verifier_compiler_binding.h @@ -22,7 +22,7 @@ #include "base/macros.h" #include "verifier_enums.h" -namespace art { +namespace art HIDDEN { namespace verifier { ALWAYS_INLINE diff --git a/runtime/verifier/verifier_deps.cc b/runtime/verifier/verifier_deps.cc index 3286a605e8..6740446c3d 100644 --- a/runtime/verifier/verifier_deps.cc +++ b/runtime/verifier/verifier_deps.cc @@ -35,7 +35,7 @@ #include "reg_type_cache-inl.h" #include "runtime.h" -namespace art { +namespace art HIDDEN { namespace verifier { VerifierDeps::VerifierDeps(const std::vector<const DexFile*>& dex_files, bool output_only) diff --git a/runtime/verifier/verifier_deps.h b/runtime/verifier/verifier_deps.h index 46b35545cf..dfa13ea112 100644 --- a/runtime/verifier/verifier_deps.h +++ b/runtime/verifier/verifier_deps.h @@ -23,6 +23,7 @@ #include "base/array_ref.h" #include "base/locks.h" +#include "base/macros.h" #include "dex/dex_file_structs.h" #include "dex/dex_file_types.h" #include "handle.h" @@ -30,7 +31,7 @@ #include "thread.h" #include "verifier_enums.h" // For MethodVerifier::FailureKind. -namespace art { +namespace art HIDDEN { class ArtField; class ArtMethod; @@ -60,18 +61,21 @@ class RegType; // changes in the classpath. class VerifierDeps { public: - explicit VerifierDeps(const std::vector<const DexFile*>& dex_files, bool output_only = true); + EXPORT explicit VerifierDeps(const std::vector<const DexFile*>& dex_files, + bool output_only = true); // Marker to know whether a class is verified. A non-verified class will have // this marker as its offset entry in the encoded data. static uint32_t constexpr kNotVerifiedMarker = std::numeric_limits<uint32_t>::max(); // Fill dependencies from stored data. Returns true on success, false on failure. - bool ParseStoredData(const std::vector<const DexFile*>& dex_files, ArrayRef<const uint8_t> data); + EXPORT bool ParseStoredData(const std::vector<const DexFile*>& dex_files, + ArrayRef<const uint8_t> data); // Merge `other` into this `VerifierDeps`'. `other` and `this` must be for the // same set of dex files. - void MergeWith(std::unique_ptr<VerifierDeps> other, const std::vector<const DexFile*>& dex_files); + EXPORT void MergeWith(std::unique_ptr<VerifierDeps> other, + const std::vector<const DexFile*>& dex_files); // Record information that a class was verified. // Note that this function is different from MaybeRecordVerificationStatus() which @@ -80,10 +84,10 @@ class VerifierDeps { REQUIRES(!Locks::verifier_deps_lock_); // Record the verification status of the class defined in `class_def`. - static void MaybeRecordVerificationStatus(VerifierDeps* verifier_deps, - const DexFile& dex_file, - const dex::ClassDef& class_def, - FailureKind failure_kind) + EXPORT static void MaybeRecordVerificationStatus(VerifierDeps* verifier_deps, + const DexFile& dex_file, + const dex::ClassDef& class_def, + FailureKind failure_kind) REQUIRES(!Locks::verifier_deps_lock_); // Record the outcome `is_assignable` of type assignability test from `source` @@ -110,15 +114,16 @@ class VerifierDeps { // Serialize the recorded dependencies and store the data into `buffer`. // `dex_files` provides the order of the dex files in which the dependencies // should be emitted. - void Encode(const std::vector<const DexFile*>& dex_files, std::vector<uint8_t>* buffer) const; + EXPORT void Encode(const std::vector<const DexFile*>& dex_files, + std::vector<uint8_t>* buffer) const; - void Dump(VariableIndentationOutputStream* vios) const; + EXPORT void Dump(VariableIndentationOutputStream* vios) const; // Verify the encoded dependencies of this `VerifierDeps` are still valid. - bool ValidateDependencies(Thread* self, - Handle<mirror::ClassLoader> class_loader, - const std::vector<const DexFile*>& dex_files, - /* out */ std::string* error_msg) const + EXPORT bool ValidateDependencies(Thread* self, + Handle<mirror::ClassLoader> class_loader, + const std::vector<const DexFile*>& dex_files, + /* out */ std::string* error_msg) const REQUIRES_SHARED(Locks::mutator_lock_); const std::vector<bool>& GetVerifiedClasses(const DexFile& dex_file) const { @@ -138,7 +143,7 @@ class VerifierDeps { } // Resets the data related to the given dex files. - void ClearData(const std::vector<const DexFile*>& dex_files); + EXPORT void ClearData(const std::vector<const DexFile*>& dex_files); // Parses raw VerifierDeps data to extract bitvectors of which class def indices // were verified or not. The given `dex_files` must match the order and count of @@ -195,7 +200,7 @@ class VerifierDeps { // `dex_file` is not reported as being compiled. DexFileDeps* GetDexFileDeps(const DexFile& dex_file); - const DexFileDeps* GetDexFileDeps(const DexFile& dex_file) const; + EXPORT const DexFileDeps* GetDexFileDeps(const DexFile& dex_file) const; // Returns the index of `str`. If it is defined in `dex_file_`, this is the dex // string ID. If not, an ID is assigned to the string and cached in `strings_` diff --git a/runtime/verifier/verifier_enums.h b/runtime/verifier/verifier_enums.h index 9c55e99206..57994581db 100644 --- a/runtime/verifier/verifier_enums.h +++ b/runtime/verifier/verifier_enums.h @@ -19,7 +19,9 @@ #include <stdint.h> -namespace art { +#include "base/macros.h" + +namespace art HIDDEN { namespace verifier { // The mode that the verifier should run as. diff --git a/test/2242-checker-lse-acquire-release-operations/src/Main.java b/test/2242-checker-lse-acquire-release-operations/src/Main.java index 433a4cd343..4db0f359ef 100644 --- a/test/2242-checker-lse-acquire-release-operations/src/Main.java +++ b/test/2242-checker-lse-acquire-release-operations/src/Main.java @@ -24,63 +24,126 @@ class TestClass { public class Main { public static void main(String[] args) { // Volatile accesses. - assertEquals($noinline$testVolatileAccessesMustBeKept(new TestClass()), 3); + assertEquals(3, $noinline$testVolatileAccessesMustBeKept(new TestClass())); + assertEquals(3, $noinline$testSingletonVolatileAccessesCanBeRemoved()); // Volatile loads - Different fields shouldn't alias. - assertEquals($noinline$testVolatileLoadDifferentFields(new TestClass(), new TestClass()), 3); + assertEquals(3, $noinline$testVolatileLoadDifferentFields(new TestClass(), new TestClass())); assertEquals( - $noinline$testVolatileLoadDifferentFieldsBlocking(new TestClass(), new TestClass()), - 3); + 3, $noinline$testVolatileLoadDifferentFieldsBlocking(new TestClass(), new TestClass())); // Volatile loads - Redundant store. - assertEquals($noinline$testVolatileLoadRedundantStore(new TestClass()), 2); - assertEquals($noinline$testVolatileLoadRedundantStoreBlocking(new TestClass()), 2); - assertEquals($noinline$testVolatileLoadRedundantStoreBlockingOnlyLoad(new TestClass()), 2); + assertEquals(2, $noinline$testVolatileLoadRedundantStore(new TestClass())); + assertEquals(2, $noinline$testVolatileLoadRedundantStoreBlocking(new TestClass())); + assertEquals(2, $noinline$testVolatileLoadRedundantStoreBlockingOnlyLoad(new TestClass())); // Volatile loads - Set and merge values. - assertEquals($noinline$testVolatileLoadSetAndMergeValues(new TestClass(), true), 1); - assertEquals($noinline$testVolatileLoadSetAndMergeValues(new TestClass(), false), 2); - assertEquals($noinline$testVolatileLoadSetAndMergeValuesBlocking(new TestClass(), true), 1); - assertEquals($noinline$testVolatileLoadSetAndMergeValuesBlocking(new TestClass(), false), 2); + assertEquals(1, $noinline$testVolatileLoadSetAndMergeValues(new TestClass(), true)); + assertEquals(2, $noinline$testVolatileLoadSetAndMergeValues(new TestClass(), false)); + assertEquals(1, $noinline$testVolatileLoadSetAndMergeValuesBlocking(new TestClass(), true)); + assertEquals(2, $noinline$testVolatileLoadSetAndMergeValuesBlocking(new TestClass(), false)); - // Volatile stores - Different fields shouldn't alias. - assertEquals($noinline$testVolatileStoreDifferentFields(new TestClass(), new TestClass()), 3); + // Volatile loads - Removal - Different fields shouldn't alias. + assertEquals(3, + $noinline$testVolatileLoadDifferentFieldsRemovedSynchronization( + new TestClass(), new TestClass())); + + // Volatile loads - Removal - Redundant store. assertEquals( - $noinline$testVolatileStoreDifferentFieldsBlocking(new TestClass(), new TestClass()), - 3); + 2, $noinline$testVolatileLoadRedundantStoreRemovedSynchronization(new TestClass())); + + // Volatile loads - Removal - Set and merge values. + assertEquals(1, + $noinline$testVolatileLoadSetAndMergeValuesRemovedSynchronization( + new TestClass(), true)); + assertEquals(2, + $noinline$testVolatileLoadSetAndMergeValuesRemovedSynchronization( + new TestClass(), false)); + + // Volatile loads - Removal - with inlining + assertEquals(2, $noinline$testVolatileLoadInlineMethodWithSynchronizedScope(new TestClass())); + + // Volatile stores - Different fields shouldn't alias. + assertEquals(3, $noinline$testVolatileStoreDifferentFields(new TestClass(), new TestClass())); + assertEquals(3, + $noinline$testVolatileStoreDifferentFieldsBlocking(new TestClass(), new TestClass())); // Volatile stores - Redundant store. - assertEquals($noinline$testVolatileStoreRedundantStore(new TestClass()), 2); - assertEquals($noinline$testVolatileStoreRedundantStoreBlocking(new TestClass()), 2); - assertEquals($noinline$testVolatileStoreRedundantStoreBlockingOnlyLoad(new TestClass()), 2); + assertEquals(2, $noinline$testVolatileStoreRedundantStore(new TestClass())); + assertEquals(2, $noinline$testVolatileStoreRedundantStoreBlocking(new TestClass())); + assertEquals(2, $noinline$testVolatileStoreRedundantStoreBlockingOnlyLoad(new TestClass())); // Volatile stores - Set and merge values. - assertEquals($noinline$testVolatileStoreSetAndMergeValues(new TestClass(), true), 1); - assertEquals($noinline$testVolatileStoreSetAndMergeValues(new TestClass(), false), 2); - assertEquals($noinline$testVolatileStoreSetAndMergeValuesNotBlocking(new TestClass(), true), 1); - assertEquals($noinline$testVolatileStoreSetAndMergeValuesNotBlocking(new TestClass(), false), 2); + assertEquals(1, $noinline$testVolatileStoreSetAndMergeValues(new TestClass(), true)); + assertEquals(2, $noinline$testVolatileStoreSetAndMergeValues(new TestClass(), false)); + assertEquals(1, $noinline$testVolatileStoreSetAndMergeValuesNotBlocking(new TestClass(), true)); + assertEquals( + 2, $noinline$testVolatileStoreSetAndMergeValuesNotBlocking(new TestClass(), false)); + + // Volatile stores - Removal - Different fields shouldn't alias. + assertEquals(3, + $noinline$testVolatileStoreDifferentFieldsRemovedSynchronization( + new TestClass(), new TestClass())); + + // Volatile stores - Removal - Redundant store. + assertEquals( + 2, $noinline$testVolatileStoreRedundantStoreRemovedSynchronization(new TestClass())); + + // Volatile stores - Removal - Set and merge values. + assertEquals(1, + $noinline$testVolatileStoreSetAndMergeValuesRemovedSynchronization( + new TestClass(), true)); + assertEquals(2, + $noinline$testVolatileStoreSetAndMergeValuesRemovedSynchronization( + new TestClass(), false)); + + // Volatile stores - Removal - with inlining + assertEquals(2, $noinline$testVolatileStoreInlineMethodWithSynchronizedScope(new TestClass())); // Monitor Operations - Different fields shouldn't alias. + // Make sure the static variable used for synchronization is non-null. + classForSync = new TestClass(); + assertEquals( - $noinline$testMonitorOperationDifferentFields(new TestClass(), new TestClass()), 3); - assertEquals($noinline$testMonitorOperationDifferentFieldsBlocking( - new TestClass(), new TestClass()), - 3); + 3, $noinline$testMonitorOperationDifferentFields(new TestClass(), new TestClass())); + assertEquals(3, + $noinline$testMonitorOperationDifferentFieldsBlocking( + new TestClass(), new TestClass())); // Monitor Operations - Redundant store. - assertEquals($noinline$testMonitorOperationRedundantStore(new TestClass()), 2); - assertEquals($noinline$testMonitorOperationRedundantStoreBlocking(new TestClass()), 2); - assertEquals( - $noinline$testMonitorOperationRedundantStoreBlockingOnlyLoad(new TestClass()), 2); - assertEquals($noinline$testMonitorOperationRedundantStoreBlockingExit(new TestClass()), 2); + assertEquals(2, $noinline$testMonitorOperationRedundantStore(new TestClass())); + assertEquals(2, $noinline$testMonitorOperationRedundantStoreBlocking(new TestClass())); + assertEquals(2, $noinline$testMonitorOperationRedundantStoreBlockingOnlyLoad(new TestClass())); + assertEquals(2, $noinline$testMonitorOperationRedundantStoreBlockingExit(new TestClass())); // Monitor Operations - Set and merge values. - assertEquals($noinline$testMonitorOperationSetAndMergeValues(new TestClass(), true), 1); - assertEquals($noinline$testMonitorOperationSetAndMergeValues(new TestClass(), false), 2); + assertEquals(1, $noinline$testMonitorOperationSetAndMergeValues(new TestClass(), true)); + assertEquals(2, $noinline$testMonitorOperationSetAndMergeValues(new TestClass(), false)); + assertEquals(1, $noinline$testMonitorOperationSetAndMergeValuesBlocking(new TestClass(), true)); + assertEquals( + 2, $noinline$testMonitorOperationSetAndMergeValuesBlocking(new TestClass(), false)); + + // Monitor Operations - Removal - Different fields shouldn't alias. + assertEquals(3, + $noinline$testMonitorOperationDifferentFieldsRemovedSynchronization( + new TestClass(), new TestClass())); + + // Monitor Operations - Removal - Redundant store. assertEquals( - $noinline$testMonitorOperationSetAndMergeValuesBlocking(new TestClass(), true), 1); + 2, $noinline$testMonitorOperationRedundantStoreRemovedSynchronization(new TestClass())); + + // Monitor Operations - Removal - Set and merge values. + assertEquals(1, + $noinline$testMonitorOperationSetAndMergeValuesRemovedSynchronization( + new TestClass(), true)); + assertEquals(2, + $noinline$testMonitorOperationSetAndMergeValuesRemovedSynchronization( + new TestClass(), false)); + + // Monitor Operations - Removal - with inlining + assertEquals(2, $noinline$testMonitorOperationInlineSynchronizedMethod(new TestClass())); assertEquals( - $noinline$testMonitorOperationSetAndMergeValuesBlocking(new TestClass(), false), 2); + 2, $noinline$testMonitorOperationInlineMethodWithSynchronizedScope(new TestClass())); } public static void assertEquals(int expected, int result) { @@ -114,6 +177,31 @@ public class Main { return result; } + /// CHECK-START: int Main.$noinline$testSingletonVolatileAccessesCanBeRemoved() load_store_elimination (before) + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldGet + /// CHECK: InstanceFieldGet + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldGet + + /// CHECK-START: int Main.$noinline$testSingletonVolatileAccessesCanBeRemoved() load_store_elimination (after) + /// CHECK-NOT: InstanceFieldSet + + /// CHECK-START: int Main.$noinline$testSingletonVolatileAccessesCanBeRemoved() load_store_elimination (after) + /// CHECK-NOT: InstanceFieldGet + static int $noinline$testSingletonVolatileAccessesCanBeRemoved() { + Main m = new Main(); + int result; + m.vi = 3; + // Redundant load can be removed. + result = m.vi; + result = m.vi; + // Redundant store can be removed. + m.vi = 3; + result = m.vi; + return result; + } + /// CHECK-START: int Main.$noinline$testVolatileLoadDifferentFields(TestClass, TestClass) load_store_elimination (before) /// CHECK: InstanceFieldGet field_name:TestClass.vi /// CHECK: InstanceFieldSet @@ -288,6 +376,136 @@ public class Main { return obj.i; } + /// CHECK-START: int Main.$noinline$testVolatileLoadDifferentFieldsRemovedSynchronization(TestClass, TestClass) load_store_elimination (before) + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldGet field_name:Main.vi + /// CHECK: InstanceFieldGet + /// CHECK: InstanceFieldGet + + /// CHECK-START: int Main.$noinline$testVolatileLoadDifferentFieldsRemovedSynchronization(TestClass, TestClass) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldGet field_name:Main.vi + + /// CHECK-START: int Main.$noinline$testVolatileLoadDifferentFieldsRemovedSynchronization(TestClass, TestClass) load_store_elimination (after) + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldSet + + /// CHECK-START: int Main.$noinline$testVolatileLoadDifferentFieldsRemovedSynchronization(TestClass, TestClass) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldGet + + static int $noinline$testVolatileLoadDifferentFieldsRemovedSynchronization( + TestClass obj1, TestClass obj2) { + Main m = new Main(); + + obj1.i = 1; + obj2.j = 2; + int unused = m.vi; + + return obj1.i + obj2.j; + } + + /// CHECK-START: int Main.$noinline$testVolatileLoadRedundantStoreRemovedSynchronization(TestClass) load_store_elimination (before) + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldGet field_name:Main.vi + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldGet field_name:Main.vi + /// CHECK: InstanceFieldGet + + /// CHECK-START: int Main.$noinline$testVolatileLoadRedundantStoreRemovedSynchronization(TestClass) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldGet field_name:Main.vi + + /// CHECK-START: int Main.$noinline$testVolatileLoadRedundantStoreRemovedSynchronization(TestClass) load_store_elimination (after) + /// CHECK: InstanceFieldSet + /// CHECK-NOT: InstanceFieldSet + + /// CHECK-START: int Main.$noinline$testVolatileLoadRedundantStoreRemovedSynchronization(TestClass) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldGet + + static int $noinline$testVolatileLoadRedundantStoreRemovedSynchronization(TestClass obj) { + Main m = new Main(); + + obj.j = 1; + int unused = m.vi; + obj.j = 2; + unused = m.vi; + + return obj.j; + } + + /// CHECK-START: int Main.$noinline$testVolatileLoadSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (before) + /// CHECK-DAG: InstanceFieldSet + /// CHECK-DAG: InstanceFieldSet + /// CHECK-DAG: InstanceFieldGet field_name:Main.vi + /// CHECK-DAG: InstanceFieldGet + /// CHECK-DAG: Return + + /// CHECK-START: int Main.$noinline$testVolatileLoadSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (after) + /// CHECK-DAG: InstanceFieldSet + /// CHECK-DAG: InstanceFieldSet + /// CHECK-DAG: Return + + /// CHECK-START: int Main.$noinline$testVolatileLoadSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldGet field_name:Main.vi + + /// CHECK-START: int Main.$noinline$testVolatileLoadSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (after) + /// CHECK: Phi + + /// CHECK-START: int Main.$noinline$testVolatileLoadSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldGet + + static int $noinline$testVolatileLoadSetAndMergeValuesRemovedSynchronization( + TestClass obj, boolean b) { + Main m = new Main(); + + if (b) { + obj.i = 1; + } else { + obj.i = 2; + } + int unused = m.vi; + return obj.i; + } + + // Can't eliminate the setters, or volatile getters in this method. + + /// CHECK-START: int Main.$inline$SetterWithVolatileLoads(TestClass) load_store_elimination (before) + /// CHECK: InstanceFieldSet field_name:TestClass.j + /// CHECK: InstanceFieldGet field_name:Main.vi + /// CHECK: InstanceFieldSet field_name:TestClass.j + /// CHECK: InstanceFieldGet field_name:Main.vi + + /// CHECK-START: int Main.$inline$SetterWithVolatileLoads(TestClass) load_store_elimination (after) + /// CHECK: InstanceFieldSet field_name:TestClass.j + /// CHECK: InstanceFieldGet field_name:Main.vi + /// CHECK: InstanceFieldSet field_name:TestClass.j + /// CHECK: InstanceFieldGet field_name:Main.vi + int $inline$SetterWithVolatileLoads(TestClass obj) { + obj.j = 1; + int unused = this.vi; + obj.j = 2; + unused = this.vi; + return obj.j; + } + + // But we can eliminate once inlined. + + /// CHECK-START: int Main.$noinline$testVolatileLoadInlineMethodWithSynchronizedScope(TestClass) load_store_elimination (before) + /// CHECK: InstanceFieldSet field_name:TestClass.j + /// CHECK: InstanceFieldGet field_name:Main.vi + /// CHECK: InstanceFieldSet field_name:TestClass.j + /// CHECK: InstanceFieldGet field_name:Main.vi + + /// CHECK-START: int Main.$noinline$testVolatileLoadInlineMethodWithSynchronizedScope(TestClass) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldGet field_name:Main.vi + + /// CHECK-START: int Main.$noinline$testVolatileLoadInlineMethodWithSynchronizedScope(TestClass) load_store_elimination (after) + /// CHECK: InstanceFieldSet field_name:TestClass.j + /// CHECK-NOT: InstanceFieldSet field_name:TestClass.j + static int $noinline$testVolatileLoadInlineMethodWithSynchronizedScope(TestClass obj) { + Main m = new Main(); + return m.$inline$SetterWithVolatileLoads(obj); + } + /// CHECK-START: int Main.$noinline$testVolatileStoreDifferentFields(TestClass, TestClass) load_store_elimination (before) /// CHECK: InstanceFieldSet field_name:TestClass.vi /// CHECK: InstanceFieldSet @@ -462,6 +680,136 @@ public class Main { return obj.i; } + /// CHECK-START: int Main.$noinline$testVolatileStoreDifferentFieldsRemovedSynchronization(TestClass, TestClass) load_store_elimination (before) + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldSet field_name:Main.vi + /// CHECK: InstanceFieldGet + /// CHECK: InstanceFieldGet + + /// CHECK-START: int Main.$noinline$testVolatileStoreDifferentFieldsRemovedSynchronization(TestClass, TestClass) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldSet field_name:Main.vi + + /// CHECK-START: int Main.$noinline$testVolatileStoreDifferentFieldsRemovedSynchronization(TestClass, TestClass) load_store_elimination (after) + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldSet + + /// CHECK-START: int Main.$noinline$testVolatileStoreDifferentFieldsRemovedSynchronization(TestClass, TestClass) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldGet + + static int $noinline$testVolatileStoreDifferentFieldsRemovedSynchronization( + TestClass obj1, TestClass obj2) { + Main m = new Main(); + + obj1.i = 1; + obj2.j = 2; + m.vi = 123; + + return obj1.i + obj2.j; + } + + /// CHECK-START: int Main.$noinline$testVolatileStoreRedundantStoreRemovedSynchronization(TestClass) load_store_elimination (before) + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldGet + + /// CHECK-START: int Main.$noinline$testVolatileStoreRedundantStoreRemovedSynchronization(TestClass) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldSet field_name:Main.vi + + /// CHECK-START: int Main.$noinline$testVolatileStoreRedundantStoreRemovedSynchronization(TestClass) load_store_elimination (after) + /// CHECK: InstanceFieldSet + /// CHECK-NOT: InstanceFieldSet + + /// CHECK-START: int Main.$noinline$testVolatileStoreRedundantStoreRemovedSynchronization(TestClass) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldGet + + static int $noinline$testVolatileStoreRedundantStoreRemovedSynchronization(TestClass obj) { + Main m = new Main(); + + obj.j = 1; + m.vi = 123; + obj.j = 2; + m.vi = 123; + + return obj.j; + } + + /// CHECK-START: int Main.$noinline$testVolatileStoreSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (before) + /// CHECK-DAG: InstanceFieldSet + /// CHECK-DAG: InstanceFieldSet + /// CHECK-DAG: InstanceFieldSet + /// CHECK-DAG: InstanceFieldGet + /// CHECK-DAG: Return + + /// CHECK-START: int Main.$noinline$testVolatileStoreSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (after) + /// CHECK-DAG: InstanceFieldSet + /// CHECK-DAG: InstanceFieldSet + /// CHECK-DAG: Return + + /// CHECK-START: int Main.$noinline$testVolatileStoreSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldSet field_name:Main.vi + + /// CHECK-START: int Main.$noinline$testVolatileStoreSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (after) + /// CHECK: Phi + + /// CHECK-START: int Main.$noinline$testVolatileStoreSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldGet + + static int $noinline$testVolatileStoreSetAndMergeValuesRemovedSynchronization( + TestClass obj, boolean b) { + Main m = new Main(); + + if (b) { + obj.i = 1; + } else { + obj.i = 2; + } + m.vi = 123; + return obj.i; + } + + // Can't eliminate the setters in this method. + + /// CHECK-START: int Main.$inline$SetterWithVolatileStores(TestClass) load_store_elimination (before) + /// CHECK: InstanceFieldSet field_name:TestClass.j + /// CHECK: InstanceFieldSet field_name:Main.vi + /// CHECK: InstanceFieldSet field_name:TestClass.j + /// CHECK: InstanceFieldSet field_name:Main.vi + + /// CHECK-START: int Main.$inline$SetterWithVolatileStores(TestClass) load_store_elimination (after) + /// CHECK: InstanceFieldSet field_name:TestClass.j + /// CHECK: InstanceFieldSet field_name:Main.vi + /// CHECK: InstanceFieldSet field_name:TestClass.j + /// CHECK: InstanceFieldSet field_name:Main.vi + int $inline$SetterWithVolatileStores(TestClass obj) { + obj.j = 1; + this.vi = 123; + obj.j = 2; + this.vi = 123; + return obj.j; + } + + // But we can eliminate once inlined. + + /// CHECK-START: int Main.$noinline$testVolatileStoreInlineMethodWithSynchronizedScope(TestClass) load_store_elimination (before) + /// CHECK: InstanceFieldSet field_name:TestClass.j + /// CHECK: InstanceFieldSet field_name:Main.vi + /// CHECK: InstanceFieldSet field_name:TestClass.j + /// CHECK: InstanceFieldSet field_name:Main.vi + + /// CHECK-START: int Main.$noinline$testVolatileStoreInlineMethodWithSynchronizedScope(TestClass) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldSet field_name:Main.vi + + /// CHECK-START: int Main.$noinline$testVolatileStoreInlineMethodWithSynchronizedScope(TestClass) load_store_elimination (after) + /// CHECK: InstanceFieldSet field_name:TestClass.j + /// CHECK-NOT: InstanceFieldSet field_name:TestClass.j + static int $noinline$testVolatileStoreInlineMethodWithSynchronizedScope(TestClass obj) { + Main m = new Main(); + return m.$inline$SetterWithVolatileStores(obj); + } + /// CHECK-START: int Main.$noinline$testMonitorOperationDifferentFields(TestClass, TestClass) load_store_elimination (before) /// CHECK: InstanceFieldSet /// CHECK: InstanceFieldSet @@ -483,15 +831,11 @@ public class Main { // Unrelated monitor operations shouldn't block LSE. static int $noinline$testMonitorOperationDifferentFields(TestClass obj1, TestClass obj2) { - Main m = new Main(); - synchronized (m) {} - + synchronized (classForSync) {} obj1.i = 1; obj2.j = 2; int result = obj1.i + obj2.j; - - synchronized (m) {} - + synchronized (classForSync) {} return result; } @@ -513,11 +857,9 @@ public class Main { // A synchronized operation blocks loads. static int $noinline$testMonitorOperationDifferentFieldsBlocking(TestClass obj1, TestClass obj2) { - Main m = new Main(); - obj1.i = 1; obj2.j = 2; - synchronized (m) { + synchronized (classForSync) { return obj1.i + obj2.j; } } @@ -539,12 +881,10 @@ public class Main { /// CHECK-NOT: InstanceFieldGet static int $noinline$testMonitorOperationRedundantStore(TestClass obj) { - Main m = new Main(); - synchronized (m) { + synchronized (classForSync) { obj.j = 1; obj.j = 2; } - return obj.j; } @@ -565,13 +905,10 @@ public class Main { /// CHECK-NOT: InstanceFieldGet static int $noinline$testMonitorOperationRedundantStoreBlocking(TestClass obj) { - Main m = new Main(); - // This store must be kept due to the monitor operation. obj.j = 1; - synchronized (m) {} + synchronized (classForSync) {} obj.j = 2; - return obj.j; } @@ -592,13 +929,10 @@ public class Main { /// CHECK: InstanceFieldGet static int $noinline$testMonitorOperationRedundantStoreBlockingOnlyLoad(TestClass obj) { - Main m = new Main(); - // This store can be safely removed. obj.j = 1; obj.j = 2; - synchronized (m) {} - + synchronized (classForSync) {} // This load remains due to the monitor operation. return obj.j; } @@ -622,16 +956,13 @@ public class Main { /// CHECK-NOT: InstanceFieldGet static int $noinline$testMonitorOperationRedundantStoreBlockingExit(TestClass obj) { - Main m = new Main(); - - synchronized (m) { + synchronized (classForSync) { // This store can be removed. obj.j = 0; // This store must be kept due to the monitor exit operation. obj.j = 1; } obj.j = 2; - return obj.j; } @@ -658,13 +989,11 @@ public class Main { /// CHECK-NOT: InstanceFieldGet static int $noinline$testMonitorOperationSetAndMergeValues(TestClass obj, boolean b) { - Main m = new Main(); - if (b) { - synchronized (m) {} + synchronized (classForSync) {} obj.i = 1; } else { - synchronized (m) {} + synchronized (classForSync) {} obj.i = 2; } return obj.i; @@ -690,6 +1019,102 @@ public class Main { /// CHECK: InstanceFieldGet static int $noinline$testMonitorOperationSetAndMergeValuesBlocking(TestClass obj, boolean b) { + if (b) { + obj.i = 1; + } else { + obj.i = 2; + } + synchronized (classForSync) {} + return obj.i; + } + + /// CHECK-START: int Main.$noinline$testMonitorOperationDifferentFieldsRemovedSynchronization(TestClass, TestClass) load_store_elimination (before) + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldGet + /// CHECK: InstanceFieldGet + + /// CHECK-START: int Main.$noinline$testMonitorOperationDifferentFieldsRemovedSynchronization(TestClass, TestClass) load_store_elimination (before) + /// CHECK: MonitorOperation kind:enter + /// CHECK: MonitorOperation kind:exit + + /// CHECK-START: int Main.$noinline$testMonitorOperationDifferentFieldsRemovedSynchronization(TestClass, TestClass) load_store_elimination (after) + /// CHECK-NOT: MonitorOperation + + /// CHECK-START: int Main.$noinline$testMonitorOperationDifferentFieldsRemovedSynchronization(TestClass, TestClass) load_store_elimination (after) + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldSet + + /// CHECK-START: int Main.$noinline$testMonitorOperationDifferentFieldsRemovedSynchronization(TestClass, TestClass) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldGet + + static int $noinline$testMonitorOperationDifferentFieldsRemovedSynchronization( + TestClass obj1, TestClass obj2) { + Main m = new Main(); + + obj1.i = 1; + obj2.j = 2; + synchronized (m) {} + + return obj1.i + obj2.j; + } + + /// CHECK-START: int Main.$noinline$testMonitorOperationRedundantStoreRemovedSynchronization(TestClass) load_store_elimination (before) + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldGet + + /// CHECK-START: int Main.$noinline$testMonitorOperationRedundantStoreRemovedSynchronization(TestClass) load_store_elimination (before) + /// CHECK: MonitorOperation kind:enter + /// CHECK: MonitorOperation kind:exit + /// CHECK: MonitorOperation kind:enter + /// CHECK: MonitorOperation kind:exit + + /// CHECK-START: int Main.$noinline$testMonitorOperationRedundantStoreRemovedSynchronization(TestClass) load_store_elimination (after) + /// CHECK-NOT: MonitorOperation + + /// CHECK-START: int Main.$noinline$testMonitorOperationRedundantStoreRemovedSynchronization(TestClass) load_store_elimination (after) + /// CHECK: InstanceFieldSet + /// CHECK-NOT: InstanceFieldSet + + /// CHECK-START: int Main.$noinline$testMonitorOperationRedundantStoreRemovedSynchronization(TestClass) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldGet + static int $noinline$testMonitorOperationRedundantStoreRemovedSynchronization(TestClass obj) { + Main m = new Main(); + + obj.j = 1; + synchronized (m) {} + obj.j = 2; + synchronized (m) {} + + return obj.j; + } + + /// CHECK-START: int Main.$noinline$testMonitorOperationSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (before) + /// CHECK-DAG: InstanceFieldSet + /// CHECK-DAG: InstanceFieldSet + /// CHECK-DAG: InstanceFieldGet + /// CHECK-DAG: Return + + /// CHECK-START: int Main.$noinline$testMonitorOperationSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (after) + /// CHECK-DAG: InstanceFieldSet + /// CHECK-DAG: InstanceFieldSet + /// CHECK-DAG: Return + + /// CHECK-START: int Main.$noinline$testMonitorOperationSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (before) + /// CHECK-DAG: MonitorOperation kind:enter + /// CHECK-DAG: MonitorOperation kind:exit + + /// CHECK-START: int Main.$noinline$testMonitorOperationSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (after) + /// CHECK-NOT: MonitorOperation + + /// CHECK-START: int Main.$noinline$testMonitorOperationSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (after) + /// CHECK: Phi + + /// CHECK-START: int Main.$noinline$testMonitorOperationSetAndMergeValuesRemovedSynchronization(TestClass, boolean) load_store_elimination (after) + /// CHECK-NOT: InstanceFieldGet + static int $noinline$testMonitorOperationSetAndMergeValuesRemovedSynchronization( + TestClass obj, boolean b) { Main m = new Main(); if (b) { @@ -700,4 +1125,75 @@ public class Main { synchronized (m) {} return obj.i; } + + synchronized int $inline$synchronizedSetter(TestClass obj) { + obj.j = 1; + obj.j = 2; + return obj.j; + } + + /// CHECK-START: int Main.$noinline$testMonitorOperationInlineSynchronizedMethod(TestClass) inliner (before) + /// CHECK-NOT: MonitorOperation + + /// CHECK-START: int Main.$noinline$testMonitorOperationInlineSynchronizedMethod(TestClass) inliner (after) + /// CHECK: MonitorOperation kind:enter + /// CHECK: MonitorOperation kind:exit + + /// CHECK-START: int Main.$noinline$testMonitorOperationInlineSynchronizedMethod(TestClass) load_store_elimination (before) + /// CHECK: MonitorOperation kind:enter + /// CHECK: MonitorOperation kind:exit + + /// CHECK-START: int Main.$noinline$testMonitorOperationInlineSynchronizedMethod(TestClass) load_store_elimination (before) + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldSet + /// CHECK-NOT: InstanceFieldSet + + /// CHECK-START: int Main.$noinline$testMonitorOperationInlineSynchronizedMethod(TestClass) load_store_elimination (after) + /// CHECK-NOT: MonitorOperation + + /// CHECK-START: int Main.$noinline$testMonitorOperationInlineSynchronizedMethod(TestClass) load_store_elimination (after) + /// CHECK: InstanceFieldSet + /// CHECK-NOT: InstanceFieldSet + static int $noinline$testMonitorOperationInlineSynchronizedMethod(TestClass obj) { + Main m = new Main(); + return m.$inline$synchronizedSetter(obj); + } + + int $inline$SetterWithSynchronizedScope(TestClass obj) { + synchronized (this) { + obj.j = 1; + obj.j = 2; + return obj.j; + } + } + + /// CHECK-START: int Main.$noinline$testMonitorOperationInlineMethodWithSynchronizedScope(TestClass) inliner (before) + /// CHECK-NOT: MonitorOperation + + /// CHECK-START: int Main.$noinline$testMonitorOperationInlineMethodWithSynchronizedScope(TestClass) inliner (after) + /// CHECK: MonitorOperation kind:enter + /// CHECK: MonitorOperation kind:exit + + /// CHECK-START: int Main.$noinline$testMonitorOperationInlineMethodWithSynchronizedScope(TestClass) load_store_elimination (before) + /// CHECK: MonitorOperation kind:enter + /// CHECK: MonitorOperation kind:exit + + /// CHECK-START: int Main.$noinline$testMonitorOperationInlineMethodWithSynchronizedScope(TestClass) load_store_elimination (before) + /// CHECK: InstanceFieldSet + /// CHECK: InstanceFieldSet + /// CHECK-NOT: InstanceFieldSet + + /// CHECK-START: int Main.$noinline$testMonitorOperationInlineMethodWithSynchronizedScope(TestClass) load_store_elimination (after) + /// CHECK-NOT: MonitorOperation + + /// CHECK-START: int Main.$noinline$testMonitorOperationInlineMethodWithSynchronizedScope(TestClass) load_store_elimination (after) + /// CHECK: InstanceFieldSet + /// CHECK-NOT: InstanceFieldSet + static int $noinline$testMonitorOperationInlineMethodWithSynchronizedScope(TestClass obj) { + Main m = new Main(); + return m.$inline$SetterWithSynchronizedScope(obj); + } + + static TestClass classForSync; + volatile int vi; } diff --git a/test/2244-checker-remove-try-boundary/src/Main.java b/test/2244-checker-remove-try-boundary/src/Main.java index 65c40c5daa..1b616a5ecc 100644 --- a/test/2244-checker-remove-try-boundary/src/Main.java +++ b/test/2244-checker-remove-try-boundary/src/Main.java @@ -158,30 +158,29 @@ public class Main { } // The throw gets eliminated by `SimplifyIfs` in DCE, so we can detect that nothing can throw in - // the graph and eliminate the `TryBoundary` instructions. It does so in `after_gvn` since it - // requires the VisitIf optimization which happens later in the graph. + // the graph and eliminate the `TryBoundary` instructions. - /// CHECK-START: int Main.$noinline$testOptimizeAfterOneBranchDisappears(int, boolean) dead_code_elimination$after_gvn (before) + /// CHECK-START: int Main.$noinline$testOptimizeAfterOneBranchDisappears(int, boolean) dead_code_elimination$initial (before) /// CHECK: Throw - /// CHECK-START: int Main.$noinline$testOptimizeAfterOneBranchDisappears(int, boolean) dead_code_elimination$after_gvn (before) + /// CHECK-START: int Main.$noinline$testOptimizeAfterOneBranchDisappears(int, boolean) dead_code_elimination$initial (before) /// CHECK: TryBoundary /// CHECK: TryBoundary /// CHECK: TryBoundary /// CHECK: TryBoundary /// CHECK-NOT: TryBoundary - /// CHECK-START: int Main.$noinline$testOptimizeAfterOneBranchDisappears(int, boolean) dead_code_elimination$after_gvn (before) + /// CHECK-START: int Main.$noinline$testOptimizeAfterOneBranchDisappears(int, boolean) dead_code_elimination$initial (before) /// CHECK: flags "catch_block" /// CHECK-NOT: flags "catch_block" - /// CHECK-START: int Main.$noinline$testOptimizeAfterOneBranchDisappears(int, boolean) dead_code_elimination$after_gvn (after) + /// CHECK-START: int Main.$noinline$testOptimizeAfterOneBranchDisappears(int, boolean) dead_code_elimination$initial (after) /// CHECK-NOT: Throw - /// CHECK-START: int Main.$noinline$testOptimizeAfterOneBranchDisappears(int, boolean) dead_code_elimination$after_gvn (after) + /// CHECK-START: int Main.$noinline$testOptimizeAfterOneBranchDisappears(int, boolean) dead_code_elimination$initial (after) /// CHECK-NOT: TryBoundary - /// CHECK-START: int Main.$noinline$testOptimizeAfterOneBranchDisappears(int, boolean) dead_code_elimination$after_gvn (after) + /// CHECK-START: int Main.$noinline$testOptimizeAfterOneBranchDisappears(int, boolean) dead_code_elimination$initial (after) /// CHECK-NOT: flags "catch_block" public static int $noinline$testOptimizeAfterOneBranchDisappears(int a, boolean val) { try { diff --git a/test/2247-checker-write-barrier-elimination/src/Main.java b/test/2247-checker-write-barrier-elimination/src/Main.java index 76fb05a2c0..c03ada30b5 100644 --- a/test/2247-checker-write-barrier-elimination/src/Main.java +++ b/test/2247-checker-write-barrier-elimination/src/Main.java @@ -50,8 +50,8 @@ public class Main { // instructions that can throw. $noinline$testInstanceFieldSetsBlocked( new Main(), new Object(), new Object(), new Object()); - $noinline$testStaticFieldSetsBlocked(new Object(), new Object(), new Object()); - $noinline$testArraySetsSameRTIBlocked(); + $noinline$testStaticFieldSetsBlocked(new Main(), new Object(), new Object(), new Object()); + $noinline$testArraySetsSameRTIBlocked(new Main()); } /// CHECK-START: Main Main.$noinline$testInstanceFieldSets(Main, java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after) @@ -273,46 +273,45 @@ public class Main { return m; } - /// CHECK-START: void Main.$noinline$testStaticFieldSetsBlocked(java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after) + /// CHECK-START: void Main.$noinline$testStaticFieldSetsBlocked(Main, java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after) /// CHECK: StaticFieldSet field_name:Main.inner_static field_type:Reference write_barrier_kind:EmitWithNullCheck /// CHECK: InvokeStaticOrDirect method_name:Main.$noinline$emptyMethod /// CHECK: StaticFieldSet field_name:Main.inner_static2 field_type:Reference write_barrier_kind:EmitWithNullCheck /// CHECK: MonitorOperation kind:enter /// CHECK: StaticFieldSet field_name:Main.inner_static3 field_type:Reference write_barrier_kind:EmitWithNullCheck - /// CHECK-START: void Main.$noinline$testStaticFieldSetsBlocked(java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after) + /// CHECK-START: void Main.$noinline$testStaticFieldSetsBlocked(Main, java.lang.Object, java.lang.Object, java.lang.Object) disassembly (after) /// CHECK: ; card_table /// CHECK: ; card_table /// CHECK: ; card_table /// CHECK-NOT: ; card_table - private static void $noinline$testStaticFieldSetsBlocked(Object o, Object o2, Object o3) { + private static void $noinline$testStaticFieldSetsBlocked( + Main m, Object o, Object o2, Object o3) { inner_static = o; $noinline$emptyMethod(); inner_static2 = o2; - Main m = new Main(); synchronized (m) { inner_static3 = o3; } } - /// CHECK-START: java.lang.Object[] Main.$noinline$testArraySetsSameRTIBlocked() disassembly (after) + /// CHECK-START: java.lang.Object[] Main.$noinline$testArraySetsSameRTIBlocked(Main) disassembly (after) /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:EmitNoNullCheck /// CHECK: InvokeStaticOrDirect method_name:Main.$noinline$emptyMethod /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:EmitNoNullCheck /// CHECK: MonitorOperation kind:enter /// CHECK: ArraySet needs_type_check:false can_trigger_gc:false write_barrier_kind:EmitNoNullCheck - /// CHECK-START: java.lang.Object[] Main.$noinline$testArraySetsSameRTIBlocked() disassembly (after) + /// CHECK-START: java.lang.Object[] Main.$noinline$testArraySetsSameRTIBlocked(Main) disassembly (after) /// CHECK: ; card_table /// CHECK: ; card_table /// CHECK: ; card_table /// CHECK-NOT: ; card_table - private static java.lang.Object[] $noinline$testArraySetsSameRTIBlocked() { + private static java.lang.Object[] $noinline$testArraySetsSameRTIBlocked(Main m) { Object[] arr = new Object[3]; arr[0] = inner_static; $noinline$emptyMethod(); arr[1] = inner_static2; - Main m = new Main(); synchronized (m) { arr[2] = inner_static3; } diff --git a/test/2271-profile-inline-cache/src/Main.java b/test/2271-profile-inline-cache/src/Main.java index 81ba535154..a95d4acd91 100644 --- a/test/2271-profile-inline-cache/src/Main.java +++ b/test/2271-profile-inline-cache/src/Main.java @@ -21,6 +21,12 @@ import java.util.Arrays; import java.util.stream.Collectors; public class Main { + private static File sFile = null; + private static Method sMethod1 = null; + private static Method sMethod2 = null; + private static Method sMethod3 = null; + private static Method sMethod4 = null; + public static void main(String[] args) throws Exception { System.loadLibrary(args[0]); @@ -29,69 +35,84 @@ public class Main { return; } - File file = null; - try { - file = createTempFile(); - String codePath = System.getenv("DEX_LOCATION") + "/2271-profile-inline-cache.jar"; - VMRuntime.registerAppInfo("test.app", file.getPath(), file.getPath(), - new String[] {codePath}, VMRuntime.CODE_PATH_TYPE_PRIMARY_APK); - - Derived1 derived1 = new Derived1(); - Derived2 derived2 = new Derived2(); - - // This method is below the inline cache threshold. - Method method1 = Main.class.getDeclaredMethod("$noinline$method1", Base.class); - ensureJitBaselineCompiled(method1); - // The baseline code doesn't update the inline cache if we are marking. Force a GC now - // so that GC will unlikely take place during the method calls below. - Runtime.getRuntime().gc(); + sMethod1 = Main.class.getDeclaredMethod("$noinline$method1", Base.class); + sMethod2 = Main.class.getDeclaredMethod("$noinline$method2", Base.class); + sMethod3 = Main.class.getDeclaredMethod("$noinline$method3", Base.class); + sMethod4 = Main.class.getDeclaredMethod("$noinline$method4", Base.class); + + sFile = createTempFile(); + sFile.deleteOnExit(); + String codePath = System.getenv("DEX_LOCATION") + "/2271-profile-inline-cache.jar"; + VMRuntime.registerAppInfo("test.app", sFile.getPath(), sFile.getPath(), + new String[] {codePath}, VMRuntime.CODE_PATH_TYPE_PRIMARY_APK); + + for (int i = 0; i < 10; i++) { + try { + test(); + return; + } catch (ScopedAssertNoGc.NoGcAssertionFailure e) { + // This should rarely happen. When it happens, reset the state, delete the profile, + // and try again. + reset(); + sFile.delete(); + } + } + + // The possibility of hitting this line only exists in theory, unless the test is wrong. + throw new RuntimeException("NoGcAssertionFailure occurred 10 times"); + } + + private static void test() throws Exception { + Derived1 derived1 = new Derived1(); + Derived2 derived2 = new Derived2(); + + // This method is below the inline cache threshold. + ensureJitBaselineCompiled(sMethod1); + try (ScopedAssertNoGc noGc = new ScopedAssertNoGc()) { $noinline$method1(derived1); for (int i = 0; i < 2998; i++) { $noinline$method1(derived2); } - checkMethodHasNoInlineCache(file, method1); - - // This method is right on the inline cache threshold. - Method method2 = Main.class.getDeclaredMethod("$noinline$method2", Base.class); - ensureJitBaselineCompiled(method2); - // The baseline code doesn't update the inline cache if we are marking. Force a GC now - // so that GC will unlikely take place during the method calls below. - Runtime.getRuntime().gc(); + } + checkMethodHasNoInlineCache(sFile, sMethod1); + + // This method is right on the inline cache threshold. + ensureJitBaselineCompiled(sMethod2); + try (ScopedAssertNoGc noGc = new ScopedAssertNoGc()) { $noinline$method2(derived1); for (int i = 0; i < 2999; i++) { $noinline$method2(derived2); } - checkMethodHasInlineCache(file, method2, Derived1.class, Derived2.class); - - // This method is above the inline cache threshold. - Method method3 = Main.class.getDeclaredMethod("$noinline$method3", Base.class); - ensureJitBaselineCompiled(method3); - // The baseline code doesn't update the inline cache if we are marking. Force a GC now - // so that GC will unlikely take place during the method calls below. - Runtime.getRuntime().gc(); + } + checkMethodHasInlineCache(sFile, sMethod2, Derived1.class, Derived2.class); + + // This method is above the inline cache threshold. + ensureJitBaselineCompiled(sMethod3); + try (ScopedAssertNoGc noGc = new ScopedAssertNoGc()) { for (int i = 0; i < 10000; i++) { $noinline$method3(derived1); } for (int i = 0; i < 10000; i++) { $noinline$method3(derived2); } - checkMethodHasInlineCache(file, method3, Derived1.class, Derived2.class); - - // This method is above the JIT threshold. - Method method4 = Main.class.getDeclaredMethod("$noinline$method4", Base.class); - ensureJitBaselineCompiled(method4); - // The baseline code doesn't update the inline cache if we are marking. Force a GC now - // so that GC will unlikely take place during the method calls below. - Runtime.getRuntime().gc(); + } + checkMethodHasInlineCache(sFile, sMethod3, Derived1.class, Derived2.class); + + // This method is above the JIT threshold. + ensureJitBaselineCompiled(sMethod4); + try (ScopedAssertNoGc noGc = new ScopedAssertNoGc()) { $noinline$method4(derived1); $noinline$method4(derived2); - ensureMethodJitCompiled(method4); - checkMethodHasInlineCache(file, method4, Derived1.class, Derived2.class); - } finally { - if (file != null) { - file.delete(); - } } + ensureMethodJitCompiled(sMethod4); + checkMethodHasInlineCache(sFile, sMethod4, Derived1.class, Derived2.class); + } + + private static void reset() { + removeJitCompiledMethod(sMethod1, false /* releaseMemory */); + removeJitCompiledMethod(sMethod2, false /* releaseMemory */); + removeJitCompiledMethod(sMethod3, false /* releaseMemory */); + removeJitCompiledMethod(sMethod4, false /* releaseMemory */); } public static void $noinline$method1(Base obj) { @@ -152,6 +173,8 @@ public class Main { public static native boolean hasInlineCacheInProfile( String profile, Method method, Class<?>... targetTypes); public static native boolean hasJit(); + public static native int getCurrentGcNum(); + public static native boolean removeJitCompiledMethod(Method method, boolean releaseMemory); private static final String TEMP_FILE_NAME_PREFIX = "temp"; private static final String TEMP_FILE_NAME_SUFFIX = "-file"; @@ -170,13 +193,6 @@ public class Main { } } - private static void sleep(long millis) { - try { - Thread.sleep(millis); - } catch (InterruptedException ignored) { - } - } - private static class VMRuntime { public static final int CODE_PATH_TYPE_PRIMARY_APK = 1 << 0; private static final Method registerAppInfoMethod; @@ -197,4 +213,37 @@ public class Main { null, packageName, curProfile, refProfile, codePaths, codePathsType); } } + + // This scope is intended to guard code that doesn't expect GC to take place. Because we can't + // really prevent GC in Java code (calling a native method that enters a GCCriticalSection will + // cause the runtime to hang forever when transitioning from native back to Java), this is a + // workaround that forces a GC at the beginning so that GC will unlikely take place within the + // scope. If a GC still takes place within the scope, this will throw NoGcAssertionFailure. + // + // The baseline code doesn't update the inline cache if we are marking, so we use this scope to + // guard calls to virtual methods for which we want inline cache to be updated. + private static class ScopedAssertNoGc implements AutoCloseable { + private final int mLastGcNum; + + public ScopedAssertNoGc() { + System.gc(); + mLastGcNum = getCurrentGcNum(); + } + + @Override + public void close() throws NoGcAssertionFailure { + int currentGcNum = getCurrentGcNum(); + if (currentGcNum != mLastGcNum) { + throw new NoGcAssertionFailure( + String.format("GC happened within the scope (before: %d, after: %d)", + mLastGcNum, currentGcNum)); + } + } + + public static class NoGcAssertionFailure extends Exception { + public NoGcAssertionFailure(String message) { + super(message); + } + } + } } diff --git a/test/442-checker-constant-folding/src/Main.java b/test/442-checker-constant-folding/src/Main.java index 4539fae097..7c6d6091ee 100644 --- a/test/442-checker-constant-folding/src/Main.java +++ b/test/442-checker-constant-folding/src/Main.java @@ -1551,21 +1551,20 @@ public class Main { return (double) imm; } - /// CHECK-START: int Main.$inline$SpecialCaseForZeroInt(int) constant_folding$after_gvn (before) - /// CHECK-DAG: Add - /// CHECK-DAG: Shl + /// CHECK-START: int Main.$inline$SpecialCaseForZeroInt(int) constant_folding (before) /// CHECK-DAG: Add + /// CHECK-DAG: Mul - /// CHECK-START: int Main.$inline$SpecialCaseForZeroInt(int) constant_folding$after_gvn (before) + /// CHECK-START: int Main.$inline$SpecialCaseForZeroInt(int) constant_folding (before) /// CHECK-NOT: IntConstant 6 - /// CHECK-START: int Main.$inline$SpecialCaseForZeroInt(int) constant_folding$after_gvn (after) + /// CHECK-START: int Main.$inline$SpecialCaseForZeroInt(int) constant_folding (after) /// CHECK-NOT: Add - /// CHECK-START: int Main.$inline$SpecialCaseForZeroInt(int) constant_folding$after_gvn (after) - /// CHECK-NOT: Shl + /// CHECK-START: int Main.$inline$SpecialCaseForZeroInt(int) constant_folding (after) + /// CHECK-NOT: Mul - /// CHECK-START: int Main.$inline$SpecialCaseForZeroInt(int) constant_folding$after_gvn (after) + /// CHECK-START: int Main.$inline$SpecialCaseForZeroInt(int) constant_folding (after) /// CHECK-DAG: <<Const:i\d+>> IntConstant 6 /// CHECK-DAG: Return [<<Const>>] private static int $inline$SpecialCaseForZeroInt(int value) { @@ -1575,21 +1574,20 @@ public class Main { return value; } - /// CHECK-START: long Main.$inline$SpecialCaseForZeroLong(long) constant_folding$after_gvn (before) - /// CHECK-DAG: Add - /// CHECK-DAG: Shl + /// CHECK-START: long Main.$inline$SpecialCaseForZeroLong(long) constant_folding (before) /// CHECK-DAG: Add + /// CHECK-DAG: Mul - /// CHECK-START: long Main.$inline$SpecialCaseForZeroLong(long) constant_folding$after_gvn (before) + /// CHECK-START: long Main.$inline$SpecialCaseForZeroLong(long) constant_folding (before) /// CHECK-NOT: LongConstant 6 - /// CHECK-START: long Main.$inline$SpecialCaseForZeroLong(long) constant_folding$after_gvn (after) + /// CHECK-START: long Main.$inline$SpecialCaseForZeroLong(long) constant_folding (after) /// CHECK-NOT: Add - /// CHECK-START: long Main.$inline$SpecialCaseForZeroLong(long) constant_folding$after_gvn (after) - /// CHECK-NOT: Shl + /// CHECK-START: long Main.$inline$SpecialCaseForZeroLong(long) constant_folding (after) + /// CHECK-NOT: Mul - /// CHECK-START: long Main.$inline$SpecialCaseForZeroLong(long) constant_folding$after_gvn (after) + /// CHECK-START: long Main.$inline$SpecialCaseForZeroLong(long) constant_folding (after) /// CHECK-DAG: <<Const:j\d+>> LongConstant 6 /// CHECK-DAG: Return [<<Const>>] private static long $inline$SpecialCaseForZeroLong(long value) { @@ -1599,14 +1597,14 @@ public class Main { return value; } - /// CHECK-START: float Main.$noinline$SpecialCaseForZeroFloat(float) constant_folding$after_gvn (before) + /// CHECK-START: float Main.$noinline$SpecialCaseForZeroFloat(float) constant_folding (before) /// CHECK-DAG: Add /// CHECK-DAG: Mul - /// CHECK-START: float Main.$noinline$SpecialCaseForZeroFloat(float) constant_folding$after_gvn (after) + /// CHECK-START: float Main.$noinline$SpecialCaseForZeroFloat(float) constant_folding (after) /// CHECK-NOT: FloatConstant 6 - /// CHECK-START: float Main.$noinline$SpecialCaseForZeroFloat(float) constant_folding$after_gvn (after) + /// CHECK-START: float Main.$noinline$SpecialCaseForZeroFloat(float) constant_folding (after) /// CHECK-DAG: Add /// CHECK-DAG: Mul private static float $noinline$SpecialCaseForZeroFloat(float value) { @@ -1616,14 +1614,14 @@ public class Main { return value; } - /// CHECK-START: double Main.$noinline$SpecialCaseForZeroDouble(double) constant_folding$after_gvn (before) + /// CHECK-START: double Main.$noinline$SpecialCaseForZeroDouble(double) constant_folding (before) /// CHECK-DAG: Add /// CHECK-DAG: Mul - /// CHECK-START: double Main.$noinline$SpecialCaseForZeroDouble(double) constant_folding$after_gvn (after) + /// CHECK-START: double Main.$noinline$SpecialCaseForZeroDouble(double) constant_folding (after) /// CHECK-NOT: DoubleConstant 6 - /// CHECK-START: double Main.$noinline$SpecialCaseForZeroDouble(double) constant_folding$after_gvn (after) + /// CHECK-START: double Main.$noinline$SpecialCaseForZeroDouble(double) constant_folding (after) /// CHECK-DAG: Add /// CHECK-DAG: Mul private static double $noinline$SpecialCaseForZeroDouble(double value) { @@ -1634,17 +1632,17 @@ public class Main { } // Note that we have Add instead of sub since internally we do `Add(value, -1)`. - /// CHECK-START: int Main.$noinline$NotEqualsPropagationInt(int) constant_folding$after_gvn (before) + /// CHECK-START: int Main.$noinline$NotEqualsPropagationInt(int) constant_folding (before) /// CHECK-DAG: Add /// CHECK-DAG: Div - /// CHECK-START: int Main.$noinline$NotEqualsPropagationInt(int) constant_folding$after_gvn (after) + /// CHECK-START: int Main.$noinline$NotEqualsPropagationInt(int) constant_folding (after) /// CHECK-NOT: Add - /// CHECK-START: int Main.$noinline$NotEqualsPropagationInt(int) constant_folding$after_gvn (after) + /// CHECK-START: int Main.$noinline$NotEqualsPropagationInt(int) constant_folding (after) /// CHECK-NOT: Div - /// CHECK-START: int Main.$noinline$NotEqualsPropagationInt(int) constant_folding$after_gvn (after) + /// CHECK-START: int Main.$noinline$NotEqualsPropagationInt(int) constant_folding (after) /// CHECK-DAG: <<Const:i\d+>> IntConstant 1 /// CHECK-DAG: Return [<<Const>>] private static int $noinline$NotEqualsPropagationInt(int value) { @@ -1655,17 +1653,17 @@ public class Main { } } - /// CHECK-START: long Main.$noinline$NotEqualsPropagationLong(long) constant_folding$after_gvn (before) + /// CHECK-START: long Main.$noinline$NotEqualsPropagationLong(long) constant_folding (before) /// CHECK-DAG: Sub /// CHECK-DAG: Div - /// CHECK-START: long Main.$noinline$NotEqualsPropagationLong(long) constant_folding$after_gvn (after) + /// CHECK-START: long Main.$noinline$NotEqualsPropagationLong(long) constant_folding (after) /// CHECK-NOT: Sub - /// CHECK-START: long Main.$noinline$NotEqualsPropagationLong(long) constant_folding$after_gvn (after) + /// CHECK-START: long Main.$noinline$NotEqualsPropagationLong(long) constant_folding (after) /// CHECK-NOT: Div - /// CHECK-START: long Main.$noinline$NotEqualsPropagationLong(long) constant_folding$after_gvn (after) + /// CHECK-START: long Main.$noinline$NotEqualsPropagationLong(long) constant_folding (after) /// CHECK-DAG: <<Const:j\d+>> LongConstant 1 /// CHECK-DAG: Return [<<Const>>] private static long $noinline$NotEqualsPropagationLong(long value) { @@ -1676,13 +1674,13 @@ public class Main { } } - /// CHECK-START: float Main.$noinline$NotEqualsPropagationFloat(float) constant_folding$after_gvn (before) + /// CHECK-START: float Main.$noinline$NotEqualsPropagationFloat(float) constant_folding (before) /// CHECK-DAG: Sub - /// CHECK-DAG: Mul + /// CHECK-DAG: Div - /// CHECK-START: float Main.$noinline$NotEqualsPropagationFloat(float) constant_folding$after_gvn (after) + /// CHECK-START: float Main.$noinline$NotEqualsPropagationFloat(float) constant_folding (after) /// CHECK-DAG: Sub - /// CHECK-DAG: Mul + /// CHECK-DAG: Div private static float $noinline$NotEqualsPropagationFloat(float value) { if (value != 3F) { return value; @@ -1691,13 +1689,13 @@ public class Main { } } - /// CHECK-START: double Main.$noinline$NotEqualsPropagationDouble(double) constant_folding$after_gvn (before) + /// CHECK-START: double Main.$noinline$NotEqualsPropagationDouble(double) constant_folding (before) /// CHECK-DAG: Sub - /// CHECK-DAG: Mul + /// CHECK-DAG: Div - /// CHECK-START: double Main.$noinline$NotEqualsPropagationDouble(double) constant_folding$after_gvn (after) + /// CHECK-START: double Main.$noinline$NotEqualsPropagationDouble(double) constant_folding (after) /// CHECK-DAG: Sub - /// CHECK-DAG: Mul + /// CHECK-DAG: Div private static double $noinline$NotEqualsPropagationDouble(double value) { if (value != 3D) { return value; @@ -1706,46 +1704,32 @@ public class Main { } } - /// CHECK-START: int Main.$noinline$InlineCalleeWithSpecialCaseForZeroInt(int) constant_folding$after_gvn (before) - /// CHECK-DAG: Add - /// CHECK-DAG: Shl - /// CHECK-DAG: Add - - /// CHECK-START: int Main.$noinline$InlineCalleeWithSpecialCaseForZeroInt(int) constant_folding$after_gvn (after) + /// CHECK-START: int Main.$noinline$InlineCaleeWithSpecialCaseForZeroInt(int) inliner (after) /// CHECK-NOT: Add - /// CHECK-START: int Main.$noinline$InlineCalleeWithSpecialCaseForZeroInt(int) constant_folding$after_gvn (after) - /// CHECK-NOT: Shl + /// CHECK-START: int Main.$noinline$InlineCaleeWithSpecialCaseForZeroInt(int) inliner (after) + /// CHECK-NOT: Mul - /// CHECK-START: int Main.$noinline$InlineCalleeWithSpecialCaseForZeroInt(int) dead_code_elimination$after_gvn (after) - /// CHECK-DAG: <<Param:i\d+>> ParameterValue - /// CHECK-DAG: <<Const6:i\d+>> IntConstant 6 - /// CHECK-DAG: Return [<<Param>>] - /// CHECK-DAG: Return [<<Const6>>] - private static int $noinline$InlineCalleeWithSpecialCaseForZeroInt(int value) { + /// CHECK-START: int Main.$noinline$InlineCaleeWithSpecialCaseForZeroInt(int) inliner (after) + /// CHECK-DAG: <<Const:i\d+>> IntConstant 6 + /// CHECK-DAG: Return [<<Const>>] + private static int $noinline$InlineCaleeWithSpecialCaseForZeroInt(int value) { if (value == 0) { return $inline$SpecialCaseForZeroInt(value); } return value; } - /// CHECK-START: long Main.$noinline$InlineCalleeWithSpecialCaseForZeroLong(long) constant_folding$after_gvn (before) - /// CHECK-DAG: Add - /// CHECK-DAG: Shl - /// CHECK-DAG: Add - - /// CHECK-START: long Main.$noinline$InlineCalleeWithSpecialCaseForZeroLong(long) constant_folding$after_gvn (after) + /// CHECK-START: long Main.$noinline$InlineCaleeWithSpecialCaseForZeroLong(long) inliner (after) /// CHECK-NOT: Add - /// CHECK-START: long Main.$noinline$InlineCalleeWithSpecialCaseForZeroLong(long) constant_folding$after_gvn (after) - /// CHECK-NOT: Shl + /// CHECK-START: long Main.$noinline$InlineCaleeWithSpecialCaseForZeroLong(long) inliner (after) + /// CHECK-NOT: Mul - /// CHECK-START: long Main.$noinline$InlineCalleeWithSpecialCaseForZeroLong(long) dead_code_elimination$after_gvn (after) - /// CHECK-DAG: <<Param:j\d+>> ParameterValue - /// CHECK-DAG: <<Const6:j\d+>> LongConstant 6 - /// CHECK-DAG: Return [<<Param>>] - /// CHECK-DAG: Return [<<Const6>>] - private static long $noinline$InlineCalleeWithSpecialCaseForZeroLong(long value) { + /// CHECK-START: long Main.$noinline$InlineCaleeWithSpecialCaseForZeroLong(long) inliner (after) + /// CHECK-DAG: <<Const:j\d+>> LongConstant 6 + /// CHECK-DAG: Return [<<Const>>] + private static long $noinline$InlineCaleeWithSpecialCaseForZeroLong(long value) { if (value == 0L) { return $inline$SpecialCaseForZeroLong(value); } @@ -1754,11 +1738,11 @@ public class Main { // Check that don't propagate the value == 3 on `if not true` branch, as the `if true` branch also // flows into the same block. - /// CHECK-START: int Main.$noinline$NotEqualsImplicitElseInt(int) constant_folding$after_gvn (before) + /// CHECK-START: int Main.$noinline$NotEqualsImplicitElseInt(int) constant_folding (before) /// CHECK-DAG: Add /// CHECK-DAG: Div - /// CHECK-START: int Main.$noinline$NotEqualsImplicitElseInt(int) constant_folding$after_gvn (after) + /// CHECK-START: int Main.$noinline$NotEqualsImplicitElseInt(int) constant_folding (after) /// CHECK-DAG: Add /// CHECK-DAG: Div private static int $noinline$NotEqualsImplicitElseInt(int value) { @@ -1768,11 +1752,11 @@ public class Main { return (value - 1) / 2; } - /// CHECK-START: long Main.$noinline$NotEqualsImplicitElseLong(long) constant_folding$after_gvn (before) + /// CHECK-START: long Main.$noinline$NotEqualsImplicitElseLong(long) constant_folding (before) /// CHECK-DAG: Sub /// CHECK-DAG: Div - /// CHECK-START: long Main.$noinline$NotEqualsImplicitElseLong(long) constant_folding$after_gvn (after) + /// CHECK-START: long Main.$noinline$NotEqualsImplicitElseLong(long) constant_folding (after) /// CHECK-DAG: Sub /// CHECK-DAG: Div private static long $noinline$NotEqualsImplicitElseLong(long value) { @@ -1782,13 +1766,13 @@ public class Main { return (value - 1L) / 2L; } - /// CHECK-START: float Main.$noinline$NotEqualsImplicitElseFloat(float) constant_folding$after_gvn (before) + /// CHECK-START: float Main.$noinline$NotEqualsImplicitElseFloat(float) constant_folding (before) /// CHECK-DAG: Sub - /// CHECK-DAG: Mul + /// CHECK-DAG: Div - /// CHECK-START: float Main.$noinline$NotEqualsImplicitElseFloat(float) constant_folding$after_gvn (after) + /// CHECK-START: float Main.$noinline$NotEqualsImplicitElseFloat(float) constant_folding (after) /// CHECK-DAG: Sub - /// CHECK-DAG: Mul + /// CHECK-DAG: Div private static float $noinline$NotEqualsImplicitElseFloat(float value) { if (value != 3F) { value += 1F; @@ -1796,13 +1780,13 @@ public class Main { return (value - 1F) / 2F; } - /// CHECK-START: double Main.$noinline$NotEqualsImplicitElseDouble(double) constant_folding$after_gvn (before) + /// CHECK-START: double Main.$noinline$NotEqualsImplicitElseDouble(double) constant_folding (before) /// CHECK-DAG: Sub - /// CHECK-DAG: Mul + /// CHECK-DAG: Div - /// CHECK-START: double Main.$noinline$NotEqualsImplicitElseDouble(double) constant_folding$after_gvn (after) + /// CHECK-START: double Main.$noinline$NotEqualsImplicitElseDouble(double) constant_folding (after) /// CHECK-DAG: Sub - /// CHECK-DAG: Mul + /// CHECK-DAG: Div private static double $noinline$NotEqualsImplicitElseDouble(double value) { if (value != 3D) { value += 1D; @@ -1810,39 +1794,37 @@ public class Main { return (value - 1D) / 2D; } - // By propagating the boolean we can eliminate some equality comparisons as we already know their + // By propagating the boolean we can elimniate some equality comparisons as we already know their // result. In turn, we also enable DeadCodeElimination to eliminate more code. - /// CHECK-START: int Main.$noinline$PropagatingParameterValue(boolean, int) constant_folding$after_gvn (before) - /// CHECK-DAG: <<Param:z\d+>> ParameterValue - /// CHECK-DAG: Select [{{i\d+}},{{i\d+}},<<Param>>] - /// CHECK-DAG: Select [{{i\d+}},{{i\d+}},<<Param>>] + /// CHECK-START: int Main.$noinline$PropagatingParameterValue(boolean) constant_folding (before) + /// CHECK-DAG: Equal + /// CHECK-DAG: Equal + /// CHECK-DAG: Equal - /// CHECK-START: int Main.$noinline$PropagatingParameterValue(boolean, int) constant_folding$after_gvn (after) - /// CHECK-DAG: <<Const0:i\d+>> IntConstant 0 - /// CHECK-DAG: <<Const1:i\d+>> IntConstant 1 - /// CHECK-DAG: Select [{{i\d+}},{{i\d+}},<<Const0>>] - /// CHECK-DAG: Select [{{i\d+}},{{i\d+}},<<Const1>>] + /// CHECK-START: int Main.$noinline$PropagatingParameterValue(boolean) constant_folding (after) + /// CHECK: Equal + /// CHECK-NOT: Equal - /// CHECK-START: int Main.$noinline$PropagatingParameterValue(boolean, int) dead_code_elimination$after_gvn (before) + /// CHECK-START: int Main.$noinline$PropagatingParameterValue(boolean) dead_code_elimination$initial (before) /// CHECK-DAG: IntConstant 1 /// CHECK-DAG: IntConstant 2 /// CHECK-DAG: IntConstant 3 /// CHECK-DAG: IntConstant 4 - /// CHECK-START: int Main.$noinline$PropagatingParameterValue(boolean, int) dead_code_elimination$after_gvn (after) + /// CHECK-START: int Main.$noinline$PropagatingParameterValue(boolean) dead_code_elimination$initial (after) /// CHECK-DAG: IntConstant 1 /// CHECK-DAG: IntConstant 4 - /// CHECK-START: int Main.$noinline$PropagatingParameterValue(boolean, int) dead_code_elimination$after_gvn (after) + /// CHECK-START: int Main.$noinline$PropagatingParameterValue(boolean) dead_code_elimination$initial (after) /// CHECK-NOT: IntConstant 2 - /// CHECK-START: int Main.$noinline$PropagatingParameterValue(boolean, int) dead_code_elimination$after_gvn (after) + /// CHECK-START: int Main.$noinline$PropagatingParameterValue(boolean) dead_code_elimination$initial (after) /// CHECK-NOT: IntConstant 3 - private static int $noinline$PropagatingParameterValue(boolean value, int initial_value) { + private static int $noinline$PropagatingParameterValue(boolean value) { if (value) { - return value ? initial_value + 1 : initial_value + 2; + return value ? 1 : 2; } else { - return value ? initial_value + 3 : initial_value + 4; + return value ? 3 : 4; } } @@ -1980,7 +1962,7 @@ public class Main { // Tests for propagating known values due to if clauses. // Propagating within the same method. These are marked $inline$ since we used them in - // `InlineCalleeWithSpecialCaseForZeroInt`. + // `InlineCaleeWithSpecialCaseForZeroInt`. assertIntEquals(6, $inline$SpecialCaseForZeroInt(0)); assertIntEquals(3, $inline$SpecialCaseForZeroInt(3)); assertLongEquals(6L, $inline$SpecialCaseForZeroLong(0L)); @@ -2003,10 +1985,10 @@ public class Main { assertDoubleEquals(1D, $noinline$NotEqualsPropagationDouble(3D)); // Propagating so that the inliner can use it. - assertIntEquals(6, $noinline$InlineCalleeWithSpecialCaseForZeroInt(0)); - assertIntEquals(3, $noinline$InlineCalleeWithSpecialCaseForZeroInt(3)); - assertLongEquals(6L, $noinline$InlineCalleeWithSpecialCaseForZeroLong(0L)); - assertLongEquals(3L, $noinline$InlineCalleeWithSpecialCaseForZeroLong(3L)); + assertIntEquals(6, $noinline$InlineCaleeWithSpecialCaseForZeroInt(0)); + assertIntEquals(3, $noinline$InlineCaleeWithSpecialCaseForZeroInt(3)); + assertLongEquals(6L, $noinline$InlineCaleeWithSpecialCaseForZeroLong(0L)); + assertLongEquals(3L, $noinline$InlineCaleeWithSpecialCaseForZeroLong(3L)); // Propagating within the same method, with not equals assertIntEquals(0, $noinline$NotEqualsImplicitElseInt(0)); @@ -2019,8 +2001,8 @@ public class Main { assertDoubleEquals(1D, $noinline$NotEqualsImplicitElseDouble(3D)); // Propagating parameters. - assertIntEquals(1, $noinline$PropagatingParameterValue(true, 0)); - assertIntEquals(4, $noinline$PropagatingParameterValue(false, 0)); + assertIntEquals(1, $noinline$PropagatingParameterValue(true)); + assertIntEquals(4, $noinline$PropagatingParameterValue(false)); } Main() throws ClassNotFoundException { diff --git a/test/485-checker-dce-loop-update/smali/TestCase.smali b/test/485-checker-dce-loop-update/smali/TestCase.smali index 5290bad3ed..3e7bca93c9 100644 --- a/test/485-checker-dce-loop-update/smali/TestCase.smali +++ b/test/485-checker-dce-loop-update/smali/TestCase.smali @@ -224,7 +224,7 @@ ## CHECK-DAG: If [<<ArgY>>] loop:<<HeaderY>> # # ### Inner loop ### -## CHECK-DAG: <<PhiZ2:i\d+>> Phi [<<PhiZ1>>,<<XorZ>>] loop:<<HeaderZ:B\d+>> +## CHECK-DAG: <<PhiZ2:i\d+>> Phi [<<PhiZ1>>,<<Cst0>>] loop:<<HeaderZ:B\d+>> ## CHECK-DAG: <<XorZ>> Xor [<<PhiZ2>>,<<Cst1>>] loop:<<HeaderZ>> ## CHECK-DAG: <<CondZ:z\d+>> Equal [<<XorZ>>,<<Cst0>>] loop:<<HeaderZ>> ## CHECK-DAG: If [<<CondZ>>] loop:<<HeaderZ>> @@ -246,8 +246,8 @@ ## CHECK-DAG: <<Add7>> Add [<<PhiX>>,<<Cst7>>] loop:<<HeaderY>> # # ### Inner loop ### -## CHECK-DAG: <<PhiZ:i\d+>> Phi [<<ArgZ>>,<<XorZ:i\d+>>] loop:<<HeaderZ:B\d+>> -## CHECK-DAG: <<XorZ>> Xor [<<PhiZ>>,<<Cst1>>] loop:<<HeaderZ>> +## CHECK-DAG: <<PhiZ:i\d+>> Phi [<<ArgZ>>,<<Cst0>>] loop:<<HeaderZ:B\d+>> +## CHECK-DAG: <<XorZ:i\d+>> Xor [<<PhiZ>>,<<Cst1>>] loop:<<HeaderZ>> ## CHECK-DAG: <<CondZ:z\d+>> Equal [<<XorZ>>,<<Cst0>>] loop:<<HeaderZ>> ## CHECK-DAG: If [<<CondZ>>] loop:<<HeaderZ>> # diff --git a/test/543-checker-dce-trycatch/smali/TestCase.smali b/test/543-checker-dce-trycatch/smali/TestCase.smali index 7ad9ba8e64..15eaabbc04 100644 --- a/test/543-checker-dce-trycatch/smali/TestCase.smali +++ b/test/543-checker-dce-trycatch/smali/TestCase.smali @@ -206,6 +206,7 @@ ## CHECK-START: int TestCase.testCatchPhiInputs_DefinedInTryBlock(int, int, int, int) dead_code_elimination$after_inlining (before) ## CHECK-DAG: <<Arg0:i\d+>> ParameterValue ## CHECK-DAG: <<Arg1:i\d+>> ParameterValue +## CHECK-DAG: <<Const0x0:i\d+>> IntConstant 0 ## CHECK-DAG: <<Const0xa:i\d+>> IntConstant 10 ## CHECK-DAG: <<Const0xb:i\d+>> IntConstant 11 ## CHECK-DAG: <<Const0xc:i\d+>> IntConstant 12 @@ -215,7 +216,7 @@ ## CHECK-DAG: <<Const0x10:i\d+>> IntConstant 16 ## CHECK-DAG: <<Const0x11:i\d+>> IntConstant 17 ## CHECK-DAG: <<Add:i\d+>> Add [<<Arg0>>,<<Arg1>>] -## CHECK-DAG: <<Phi:i\d+>> Phi [<<Add>>,<<Const0xf>>] reg:3 is_catch_phi:false +## CHECK-DAG: <<Phi:i\d+>> Phi [<<Const0x0>>,<<Const0xf>>] reg:3 is_catch_phi:false ## CHECK-DAG: Phi [<<Const0xa>>,<<Const0xb>>,<<Const0xd>>] reg:1 is_catch_phi:true ## CHECK-DAG: Phi [<<Add>>,<<Const0xc>>,<<Const0xe>>] reg:2 is_catch_phi:true ## CHECK-DAG: Phi [<<Phi>>,<<Const0x10>>,<<Const0x11>>] reg:3 is_catch_phi:true @@ -248,7 +249,8 @@ if-eqz v3, :define_phi const v3, 0xf :define_phi - # v3 = Phi [Add, 0xf] # dead catch phi input, defined in the dead block (HPhi) + # v3 = Phi [Add, 0xf] # dead catch phi input, defined in the dead block (HPhi). + # Note that the Add has to be equal to 0 since we do `if-eqz v3` div-int/2addr p0, v2 :else diff --git a/test/708-jit-cache-churn/jit.cc b/test/708-jit-cache-churn/jit.cc deleted file mode 100644 index 1b80eb3c0c..0000000000 --- a/test/708-jit-cache-churn/jit.cc +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "jni.h" - -#include "art_method.h" -#include "jit/jit.h" -#include "jit/jit_code_cache.h" -#include "jni/jni_internal.h" -#include "mirror/class.h" -#include "runtime.h" -#include "scoped_thread_state_change-inl.h" -#include "thread_list.h" - -namespace art { - -extern "C" JNIEXPORT -jboolean -Java_JitCacheChurnTest_removeJitCompiledMethod(JNIEnv* env, - jclass, - jobject javaMethod, - jboolean releaseMemory) { - if (!Runtime::Current()->UseJitCompilation()) { - return JNI_FALSE; - } - - jit::Jit* jit = Runtime::Current()->GetJit(); - jit->WaitForCompilationToFinish(Thread::Current()); - - ScopedObjectAccess soa(env); - ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod); - - jit::JitCodeCache* code_cache = jit->GetCodeCache(); - - // Drop the shared mutator lock - ScopedThreadSuspension selfSuspension(Thread::Current(), art::ThreadState::kNative); - // Get exclusive mutator lock with suspend all. - ScopedSuspendAll suspend("Removing JIT compiled method", /*long_suspend*/true); - bool removed = code_cache->RemoveMethod(method, static_cast<bool>(releaseMemory)); - return removed ? JNI_TRUE : JNI_FALSE; -} - -} // namespace art diff --git a/test/708-jit-cache-churn/src/JitCacheChurnTest.java b/test/708-jit-cache-churn/src/JitCacheChurnTest.java index abc5f35f70..8902d8db0f 100644 --- a/test/708-jit-cache-churn/src/JitCacheChurnTest.java +++ b/test/708-jit-cache-churn/src/JitCacheChurnTest.java @@ -244,7 +244,7 @@ public class JitCacheChurnTest { System.err.println(e); System.exit(-1); } - removeJitCompiledMethod(method, false); + Main.removeJitCompiledMethod(method, false); } private void removeJittedMethods(int mask) { @@ -274,6 +274,4 @@ public class JitCacheChurnTest { concurrentExecution.shutdown(); } } - - private static native void removeJitCompiledMethod(Method method, boolean releaseMemory); } diff --git a/test/708-jit-cache-churn/src/Main.java b/test/708-jit-cache-churn/src/Main.java index 0595aae506..4d11dae899 100644 --- a/test/708-jit-cache-churn/src/Main.java +++ b/test/708-jit-cache-churn/src/Main.java @@ -14,6 +14,8 @@ * limitations under the License. */ +import java.lang.reflect.Method; + public class Main { public static void main(String[] args) throws Exception { @@ -28,4 +30,5 @@ public class Main { static native boolean hasJit(); static native void ensureJitCompiled(Class<?> klass, String methodName); + static native void removeJitCompiledMethod(Method method, boolean releaseMemory); } diff --git a/test/912-classes/src-art/art/Test912.java b/test/912-classes/src-art/art/Test912.java index 8e6b75f9a0..56c9364d45 100644 --- a/test/912-classes/src-art/art/Test912.java +++ b/test/912-classes/src-art/art/Test912.java @@ -262,6 +262,7 @@ public class Test912 { "java.util.NoSuchElementException", "java.io.FileNotFoundException", // b/63581208 "java.util.zip.ZipException", // b/63581208 + "sun.invoke.util.Wrapper", // For "ClassEvents" thread in JIT/no-image config. }; for (String s : PRELOAD_FOR_JIT) { Class.forName(s); diff --git a/test/Android.bp b/test/Android.bp index fef4d99c2b..00c5f6be89 100644 --- a/test/Android.bp +++ b/test/Android.bp @@ -905,7 +905,6 @@ cc_defaults { "667-jit-jni-stub/jit_jni_stub_test.cc", "674-hiddenapi/hiddenapi.cc", "692-vdex-inmem-loader/vdex_inmem_loader.cc", - "708-jit-cache-churn/jit.cc", "720-thread-priority/thread_priority.cc", "800-smali/jni.cc", "817-hiddenapi/test_native.cc", diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc index 27f1ebad12..8e0507327e 100644 --- a/test/common/runtime_state.cc +++ b/test/common/runtime_state.cc @@ -566,4 +566,36 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasInlineCacheInProfile( return JNI_FALSE; } +extern "C" JNIEXPORT jint JNICALL Java_Main_getCurrentGcNum(JNIEnv* env, jclass) { + // Prevent any new GC before getting the current GC num. + ScopedObjectAccess soa(env); + gc::Heap* heap = Runtime::Current()->GetHeap(); + heap->WaitForGcToComplete(gc::kGcCauseJitCodeCache, Thread::Current()); + return heap->GetCurrentGcNum(); +} + +extern "C" JNIEXPORT jboolean Java_Main_removeJitCompiledMethod(JNIEnv* env, + jclass, + jobject java_method, + jboolean release_memory) { + if (!Runtime::Current()->UseJitCompilation()) { + return JNI_FALSE; + } + + jit::Jit* jit = Runtime::Current()->GetJit(); + jit->WaitForCompilationToFinish(Thread::Current()); + + ScopedObjectAccess soa(env); + ArtMethod* method = ArtMethod::FromReflectedMethod(soa, java_method); + + jit::JitCodeCache* code_cache = jit->GetCodeCache(); + + // Drop the shared mutator lock. + ScopedThreadSuspension self_suspension(Thread::Current(), art::ThreadState::kNative); + // Get exclusive mutator lock with suspend all. + ScopedSuspendAll suspend("Removing JIT compiled method", /*long_suspend=*/true); + bool removed = code_cache->RemoveMethod(method, static_cast<bool>(release_memory)); + return removed ? JNI_TRUE : JNI_FALSE; +} + } // namespace art diff --git a/tools/veridex/Android.bp b/tools/veridex/Android.bp index 7b120cfcc4..ada2f6bdca 100644 --- a/tools/veridex/Android.bp +++ b/tools/veridex/Android.bp @@ -63,3 +63,99 @@ sh_binary_host { src: "appcompat.sh", filename_from_src: true, } + +genrule { + name: "system_stub_dex_d8_input_jar", + srcs: [":system_android_jar"], + tools: ["zip2zip"], + out: ["system_stub_dex_d8_input.jar"], + cmd: "$(location zip2zip) " + + "-j -i $(in) " + + "-o $(out) \"**/*.class\" ", +} + +genrule { + name: "system_stub_dex", + srcs: [ + ":system_stub_dex_d8_input_jar", + ], + tools: [ + "d8", + ], + out: [ + "dex_dir/classes.dex", + "dex_dir/classes2.dex", + ], + cmd: "mkdir -p $(genDir)/dex_dir &&" + + "$(location d8) " + + "-JXmx4096M -JXX:+TieredCompilation -JXX:TieredStopAtLevel=1 " + + "-JDcom.android.tools.r8.emitRecordAnnotationsInDex " + + "-JDcom.android.tools.r8.emitPermittedSubclassesAnnotationsInDex " + + "-JXX:OnError=\"cat hs_err_pid%p.log\" " + + "-JXX:CICompilerCount=6 -JXX:+UseDynamicNumberOfGCThreads " + + "--output $(genDir)/dex_dir " + + "--min-api 1000 " + + "$(in)", +} + +genrule { + name: "public_oahl_stub_dex_d8_input_jar", + srcs: [":public.org.apache.http.legacy.jar"], + tools: ["zip2zip"], + out: ["oahl_stub_dex_d8_input.jar"], + cmd: "$(location zip2zip) " + + "-j -i $(in) " + + "-o $(out) \"**/*.class\" ", +} + +genrule { + name: "public_oahl_stub_dex", + srcs: [ + ":public_oahl_stub_dex_d8_input_jar", + ], + tools: [ + "d8", + ], + out: [ + "dex_dir/classes.dex", + ], + cmd: "mkdir -p $(genDir)/dex_dir &&" + + "$(location d8) " + + "-JXmx4096M -JXX:+TieredCompilation -JXX:TieredStopAtLevel=1 " + + "-JDcom.android.tools.r8.emitRecordAnnotationsInDex " + + "-JDcom.android.tools.r8.emitPermittedSubclassesAnnotationsInDex " + + "-JXX:OnError=\"cat hs_err_pid%p.log\" " + + "-JXX:CICompilerCount=6 -JXX:+UseDynamicNumberOfGCThreads " + + "--output $(genDir)/dex_dir " + + "--min-api 1000 " + + "$(in)", +} + +genrule { + name: "veridex_zip", + srcs: [ + "appcompat.sh", + ":platform-bootclasspath{hiddenapi-flags.csv}", + ":system_stub_dex", + ":public_oahl_stub_dex", + ], + tools: [ + "soong_zip", + "veridex", + ], + out: ["veridex.zip"], + cmd: "mkdir -p $(genDir)/tmp &&" + + "ls -1 $(locations :system_stub_dex) | sort > $(genDir)/tmp/system-stubs.zip.list && " + + "$(locations soong_zip) -o $(genDir)/tmp/system-stubs.zip" + + " -j -l $(genDir)/tmp/system-stubs.zip.list && " + + "ls -1 $(locations :public_oahl_stub_dex) | sort > $(genDir)/tmp/org.apache.http.legacy-stubs.zip.list && " + + "$(locations soong_zip) -o $(genDir)/tmp/org.apache.http.legacy-stubs.zip " + + " -j -l $(genDir)/tmp/org.apache.http.legacy-stubs.zip.list && " + + "$(locations soong_zip) -o $(out)" + + " -C `dirname $(location appcompat.sh)` -f $(location appcompat.sh)" + + " -C `dirname $(location :platform-bootclasspath{hiddenapi-flags.csv})` -f $(location :platform-bootclasspath{hiddenapi-flags.csv})" + + " -C `dirname $(location veridex)` -f $(location veridex)" + + " -j -f $(genDir)/tmp/system-stubs.zip" + + " -j -f $(genDir)/tmp/org.apache.http.legacy-stubs.zip", + visibility: ["//visibility:public"], +} diff --git a/tools/veridex/Android.mk b/tools/veridex/Android.mk index 9ea9b3a5be..3c7a16ded1 100644 --- a/tools/veridex/Android.mk +++ b/tools/veridex/Android.mk @@ -15,7 +15,7 @@ # # TODO(b/172480617): Clean up the platform dependencies on this. - +# TODO(b/319389869 : Remove the Android.mk after the meta license be resolved. LOCAL_PATH := $(call my-dir) # The veridex tool takes stub dex files as input, so we generate both the system and oahl |