diff options
106 files changed, 1231 insertions, 472 deletions
diff --git a/build/Android.bp b/build/Android.bp index 62f71ff275..3eb4aaff79 100644 --- a/build/Android.bp +++ b/build/Android.bp @@ -18,16 +18,30 @@ bootstrap_go_package { } art_clang_tidy_errors = [ - // Protect scoped things like MutexLock. - "bugprone-unused-raii", + "bugprone-lambda-function-name", + "bugprone-unused-raii", // Protect scoped things like MutexLock. + "bugprone-virtual-near-miss", + "modernize-use-bool-literals", + "modernize-use-nullptr", + "modernize-use-using", + "performance-faster-string-find", "performance-for-range-copy", + "performance-implicit-conversion-in-loop", "performance-unnecessary-copy-initialization", "performance-unnecessary-value-param", "misc-unused-using-decls", ] // Should be: strings.Join(art_clang_tidy_errors, ","). -art_clang_tidy_errors_str = "bugprone-unused-raii" +art_clang_tidy_errors_str = "bugprone-lambda-function-name" + + ",bugprone-unused-raii" + + ",bugprone-virtual-near-miss" + + ",modernize-redundant-void-arg" + + ",modernize-use-bool-literals" + + ",modernize-use-nullptr" + + ",modernize-use-using" + + ",performance-faster-string-find" + ",performance-for-range-copy" + + ",performance-implicit-conversion-in-loop" + ",performance-unnecessary-copy-initialization" + ",performance-unnecessary-value-param" + ",misc-unused-using-decls" @@ -44,6 +58,11 @@ art_clang_tidy_disabled = [ // No exceptions. "-misc-noexcept-move-constructor", "-performance-noexcept-move-constructor", + // "Modernization" we don't agree with. + "-modernize-use-auto", + "-modernize-return-braced-init-list", + "-modernize-use-default-member-init", + "-modernize-pass-by-value", ] art_global_defaults { diff --git a/compiler/dex/inline_method_analyser.cc b/compiler/dex/inline_method_analyser.cc index fe8b766d0f..183173b298 100644 --- a/compiler/dex/inline_method_analyser.cc +++ b/compiler/dex/inline_method_analyser.cc @@ -41,7 +41,7 @@ namespace { // anonymous namespace class Matcher { public: // Match function type. - typedef bool MatchFn(Matcher* matcher); + using MatchFn = bool(Matcher*); template <size_t size> static bool Match(const CodeItemDataAccessor* code_item, MatchFn* const (&pattern)[size]); diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h index e77d621b58..2ca15f7fed 100644 --- a/compiler/optimizing/code_generator.h +++ b/compiler/optimizing/code_generator.h @@ -622,7 +622,7 @@ class CodeGenerator : public DeletableArenaObject<kArenaAllocCodeGenerator> { // otherwise return a fall-back info that should be used instead. virtual HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, - HInvokeStaticOrDirect* invoke) = 0; + ArtMethod* method) = 0; // Generate a call to a static or direct method. virtual void GenerateStaticOrDirectCall( diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index d56f7aaca1..25eadcdc72 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -4053,7 +4053,7 @@ static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM64* codege HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARM64::GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, - HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) { + ArtMethod* method ATTRIBUTE_UNUSED) { // On ARM64 we support all dispatch types. return desired_dispatch_info; } diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h index 2e7a20b553..1ba58b1a9f 100644 --- a/compiler/optimizing/code_generator_arm64.h +++ b/compiler/optimizing/code_generator_arm64.h @@ -557,7 +557,7 @@ class CodeGeneratorARM64 : public CodeGenerator { // otherwise return a fall-back info that should be used instead. HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, - HInvokeStaticOrDirect* invoke) override; + ArtMethod* method) override; void GenerateStaticOrDirectCall( HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path = nullptr) override; diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc index 3580975c62..d5149b3ec8 100644 --- a/compiler/optimizing/code_generator_arm_vixl.cc +++ b/compiler/optimizing/code_generator_arm_vixl.cc @@ -8650,7 +8650,7 @@ void CodeGeneratorARMVIXL::GenerateReadBarrierForRootSlow(HInstruction* instruct // otherwise return a fall-back info that should be used instead. HInvokeStaticOrDirect::DispatchInfo CodeGeneratorARMVIXL::GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, - HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) { + ArtMethod* method ATTRIBUTE_UNUSED) { return desired_dispatch_info; } diff --git a/compiler/optimizing/code_generator_arm_vixl.h b/compiler/optimizing/code_generator_arm_vixl.h index 33502d4f68..5edca87147 100644 --- a/compiler/optimizing/code_generator_arm_vixl.h +++ b/compiler/optimizing/code_generator_arm_vixl.h @@ -547,7 +547,7 @@ class CodeGeneratorARMVIXL : public CodeGenerator { // otherwise return a fall-back info that should be used instead. HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, - HInvokeStaticOrDirect* invoke) override; + ArtMethod* method) override; void GenerateStaticOrDirectCall( HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path = nullptr) override; diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc index d74a7a760f..1cf55152bb 100644 --- a/compiler/optimizing/code_generator_mips.cc +++ b/compiler/optimizing/code_generator_mips.cc @@ -7964,7 +7964,7 @@ Register CodeGeneratorMIPS::GetInvokeStaticOrDirectExtraParameter(HInvokeStaticO HInvokeStaticOrDirect::DispatchInfo CodeGeneratorMIPS::GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, - HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) { + ArtMethod* method ATTRIBUTE_UNUSED) { return desired_dispatch_info; } diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h index bf9589331b..50807310b6 100644 --- a/compiler/optimizing/code_generator_mips.h +++ b/compiler/optimizing/code_generator_mips.h @@ -563,7 +563,7 @@ class CodeGeneratorMIPS : public CodeGenerator { // otherwise return a fall-back info that should be used instead. HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, - HInvokeStaticOrDirect* invoke) override; + ArtMethod* method) override; void GenerateStaticOrDirectCall( HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path = nullptr) override; diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc index 7c89808d54..27534b004a 100644 --- a/compiler/optimizing/code_generator_mips64.cc +++ b/compiler/optimizing/code_generator_mips64.cc @@ -6059,7 +6059,7 @@ HLoadClass::LoadKind CodeGeneratorMIPS64::GetSupportedLoadClassKind( HInvokeStaticOrDirect::DispatchInfo CodeGeneratorMIPS64::GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, - HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) { + ArtMethod* method ATTRIBUTE_UNUSED) { // On MIPS64 we support all dispatch types. return desired_dispatch_info; } diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h index ddc154d40f..52f3a62f33 100644 --- a/compiler/optimizing/code_generator_mips64.h +++ b/compiler/optimizing/code_generator_mips64.h @@ -541,7 +541,7 @@ class CodeGeneratorMIPS64 : public CodeGenerator { // otherwise return a fall-back info that should be used instead. HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, - HInvokeStaticOrDirect* invoke) override; + ArtMethod* method) override; void GenerateStaticOrDirectCall( HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path = nullptr) override; diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 6a27081dab..11ffa99bd9 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -4785,7 +4785,7 @@ void CodeGeneratorX86::GenerateMemoryBarrier(MemBarrierKind kind) { HInvokeStaticOrDirect::DispatchInfo CodeGeneratorX86::GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, - HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) { + ArtMethod* method ATTRIBUTE_UNUSED) { return desired_dispatch_info; } @@ -8301,7 +8301,7 @@ void CodeGeneratorX86::PatchJitRootUse(uint8_t* code, uint32_t code_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment; uintptr_t address = reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>); - typedef __attribute__((__aligned__(1))) uint32_t unaligned_uint32_t; + using unaligned_uint32_t = __attribute__((__aligned__(1))) uint32_t; reinterpret_cast<unaligned_uint32_t*>(code + code_offset)[0] = dchecked_integral_cast<uint32_t>(address); } diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h index 615477171b..93b0461975 100644 --- a/compiler/optimizing/code_generator_x86.h +++ b/compiler/optimizing/code_generator_x86.h @@ -410,7 +410,7 @@ class CodeGeneratorX86 : public CodeGenerator { // otherwise return a fall-back info that should be used instead. HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, - HInvokeStaticOrDirect* invoke) override; + ArtMethod* method) override; // Generate a call to a static or direct method. void GenerateStaticOrDirectCall( diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 489652b85b..8a1d5850c0 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -978,7 +978,7 @@ inline Condition X86_64FPCondition(IfCondition cond) { HInvokeStaticOrDirect::DispatchInfo CodeGeneratorX86_64::GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, - HInvokeStaticOrDirect* invoke ATTRIBUTE_UNUSED) { + ArtMethod* method ATTRIBUTE_UNUSED) { return desired_dispatch_info; } @@ -7542,7 +7542,7 @@ void CodeGeneratorX86_64::PatchJitRootUse(uint8_t* code, uint32_t code_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment; uintptr_t address = reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>); - typedef __attribute__((__aligned__(1))) uint32_t unaligned_uint32_t; + using unaligned_uint32_t = __attribute__((__aligned__(1))) uint32_t; reinterpret_cast<unaligned_uint32_t*>(code + code_offset)[0] = dchecked_integral_cast<uint32_t>(address); } diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h index f77a5c84b4..1e7139718b 100644 --- a/compiler/optimizing/code_generator_x86_64.h +++ b/compiler/optimizing/code_generator_x86_64.h @@ -409,7 +409,7 @@ class CodeGeneratorX86_64 : public CodeGenerator { // otherwise return a fall-back info that should be used instead. HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, - HInvokeStaticOrDirect* invoke) override; + ArtMethod* method) override; void GenerateStaticOrDirectCall( HInvokeStaticOrDirect* invoke, Location temp, SlowPathCode* slow_path = nullptr) override; diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc index 31db8c205f..d45653c6e4 100644 --- a/compiler/optimizing/graph_visualizer.cc +++ b/compiler/optimizing/graph_visualizer.cc @@ -106,8 +106,7 @@ std::ostream& operator<<(std::ostream& os, const StringList& list) { } } -typedef Disassembler* create_disasm_prototype(InstructionSet instruction_set, - DisassemblerOptions* options); +using create_disasm_prototype = Disassembler*(InstructionSet, DisassemblerOptions*); class HGraphVisualizerDisassembler { public: HGraphVisualizerDisassembler(InstructionSet instruction_set, diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 3ba741472e..1be96fbd50 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -2022,13 +2022,11 @@ void HInliner::RunOptimizations(HGraph* callee_graph, // optimization that could lead to a HDeoptimize. The following optimizations do not. HDeadCodeElimination dce(callee_graph, inline_stats_, "dead_code_elimination$inliner"); HConstantFolding fold(callee_graph, "constant_folding$inliner"); - HSharpening sharpening(callee_graph, codegen_); InstructionSimplifier simplify(callee_graph, codegen_, inline_stats_); IntrinsicsRecognizer intrinsics(callee_graph, inline_stats_); HOptimization* optimizations[] = { &intrinsics, - &sharpening, &simplify, &fold, &dce, diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc index 034761db57..72b6748c50 100644 --- a/compiler/optimizing/instruction_builder.cc +++ b/compiler/optimizing/instruction_builder.cc @@ -978,11 +978,8 @@ bool HInstructionBuilder::BuildInvoke(const Instruction& instruction, } } - HInvokeStaticOrDirect::DispatchInfo dispatch_info = { - HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall, - HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod, - 0u - }; + HInvokeStaticOrDirect::DispatchInfo dispatch_info = + HSharpening::SharpenInvokeStaticOrDirect(resolved_method, code_generator_); MethodReference target_method(resolved_method->GetDexFile(), resolved_method->GetDexMethodIndex()); invoke = new (allocator_) HInvokeStaticOrDirect(allocator_, diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc index bb96c211cb..7ee5ad081e 100644 --- a/compiler/optimizing/instruction_simplifier.cc +++ b/compiler/optimizing/instruction_simplifier.cc @@ -2290,7 +2290,7 @@ void InstructionSimplifierVisitor::SimplifySystemArrayCopy(HInvoke* instruction) // the invoke, as we would need to look it up in the current dex file, and it // is unlikely that it exists. The most usual situation for such typed // arraycopy methods is a direct pointer to the boot image. - HSharpening::SharpenInvokeStaticOrDirect(invoke, codegen_); + invoke->SetDispatchInfo(HSharpening::SharpenInvokeStaticOrDirect(method, codegen_)); } } } diff --git a/compiler/optimizing/optimization.cc b/compiler/optimizing/optimization.cc index 142ddb5fbb..75466a3cba 100644 --- a/compiler/optimizing/optimization.cc +++ b/compiler/optimizing/optimization.cc @@ -84,8 +84,6 @@ const char* OptimizationPassName(OptimizationPass pass) { return HDeadCodeElimination::kDeadCodeEliminationPassName; case OptimizationPass::kInliner: return HInliner::kInlinerPassName; - case OptimizationPass::kSharpening: - return HSharpening::kSharpeningPassName; case OptimizationPass::kSelectGenerator: return HSelectGenerator::kSelectGeneratorPassName; case OptimizationPass::kInstructionSimplifier: @@ -148,7 +146,6 @@ OptimizationPass OptimizationPassByName(const std::string& pass_name) { X(OptimizationPass::kLoopOptimization); X(OptimizationPass::kScheduling); X(OptimizationPass::kSelectGenerator); - X(OptimizationPass::kSharpening); X(OptimizationPass::kSideEffectsAnalysis); #ifdef ART_ENABLE_CODEGEN_arm X(OptimizationPass::kInstructionSimplifierArm); @@ -264,9 +261,6 @@ ArenaVector<HOptimization*> ConstructOptimizations( pass_name); break; } - case OptimizationPass::kSharpening: - opt = new (allocator) HSharpening(graph, codegen, pass_name); - break; case OptimizationPass::kSelectGenerator: opt = new (allocator) HSelectGenerator(graph, handles, stats, pass_name); break; diff --git a/compiler/optimizing/optimization.h b/compiler/optimizing/optimization.h index 88b283cebf..c258d516de 100644 --- a/compiler/optimizing/optimization.h +++ b/compiler/optimizing/optimization.h @@ -84,7 +84,6 @@ enum class OptimizationPass { kLoopOptimization, kScheduling, kSelectGenerator, - kSharpening, kSideEffectsAnalysis, #ifdef ART_ENABLE_CODEGEN_arm kInstructionSimplifierArm, diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index ff1207abab..5f6f71ddc9 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -624,7 +624,6 @@ void OptimizingCompiler::RunOptimizations(HGraph* graph, OptimizationDef optimizations[] = { // Initial optimizations. OptDef(OptimizationPass::kIntrinsicsRecognizer), - OptDef(OptimizationPass::kSharpening), OptDef(OptimizationPass::kConstantFolding), OptDef(OptimizationPass::kInstructionSimplifier), OptDef(OptimizationPass::kDeadCodeElimination, diff --git a/compiler/optimizing/parallel_move_test.cc b/compiler/optimizing/parallel_move_test.cc index 399a6d8cbd..a8ab6cdd0c 100644 --- a/compiler/optimizing/parallel_move_test.cc +++ b/compiler/optimizing/parallel_move_test.cc @@ -174,8 +174,8 @@ class ParallelMoveTest : public ::testing::Test { template<> const bool ParallelMoveTest<TestParallelMoveResolverWithSwap>::has_swap = true; template<> const bool ParallelMoveTest<TestParallelMoveResolverNoSwap>::has_swap = false; -typedef ::testing::Types<TestParallelMoveResolverWithSwap, TestParallelMoveResolverNoSwap> - ParallelMoveResolverTestTypes; +using ParallelMoveResolverTestTypes = + ::testing::Types<TestParallelMoveResolverWithSwap, TestParallelMoveResolverNoSwap>; TYPED_TEST_CASE(ParallelMoveTest, ParallelMoveResolverTestTypes); diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc index 5c2f57e314..c864951a47 100644 --- a/compiler/optimizing/sharpening.cc +++ b/compiler/optimizing/sharpening.cc @@ -35,22 +35,6 @@ namespace art { -bool HSharpening::Run() { - // We don't care about the order of the blocks here. - for (HBasicBlock* block : graph_->GetReversePostOrder()) { - for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { - HInstruction* instruction = it.Current(); - if (instruction->IsInvokeStaticOrDirect()) { - SharpenInvokeStaticOrDirect(instruction->AsInvokeStaticOrDirect(), codegen_); - } - // TODO: Move the sharpening of invoke-virtual/-interface/-super from HGraphBuilder - // here. Rewrite it to avoid the CompilerDriver's reliance on verifier data - // because we know the type better when inlining. - } - } - return true; -} - static bool IsInBootImage(ArtMethod* method) { const std::vector<gc::space::ImageSpace*>& image_spaces = Runtime::Current()->GetHeap()->GetBootImageSpaces(); @@ -72,17 +56,14 @@ static bool BootImageAOTCanEmbedMethod(ArtMethod* method, const CompilerOptions& return compiler_options.IsImageClass(dex_file.StringByTypeIdx(klass->GetDexTypeIndex())); } -void HSharpening::SharpenInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke, - CodeGenerator* codegen) { - if (invoke->IsStringInit()) { - // Not using the dex cache arrays. But we could still try to use a better dispatch... - // TODO: Use direct_method and direct_code for the appropriate StringFactory method. - return; +HInvokeStaticOrDirect::DispatchInfo HSharpening::SharpenInvokeStaticOrDirect( + ArtMethod* callee, CodeGenerator* codegen) { + if (kIsDebugBuild) { + ScopedObjectAccess soa(Thread::Current()); // Required for GetDeclaringClass below. + DCHECK(callee != nullptr); + DCHECK(!(callee->IsConstructor() && callee->GetDeclaringClass()->IsStringClass())); } - ArtMethod* callee = invoke->GetResolvedMethod(); - DCHECK(callee != nullptr); - HInvokeStaticOrDirect::MethodLoadKind method_load_kind; HInvokeStaticOrDirect::CodePtrLocation code_ptr_location; uint64_t method_load_data = 0u; @@ -141,9 +122,7 @@ void HSharpening::SharpenInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke, HInvokeStaticOrDirect::DispatchInfo desired_dispatch_info = { method_load_kind, code_ptr_location, method_load_data }; - HInvokeStaticOrDirect::DispatchInfo dispatch_info = - codegen->GetSupportedInvokeStaticOrDirectDispatch(desired_dispatch_info, invoke); - invoke->SetDispatchInfo(dispatch_info); + return codegen->GetSupportedInvokeStaticOrDirectDispatch(desired_dispatch_info, callee); } HLoadClass::LoadKind HSharpening::ComputeLoadClassKind( diff --git a/compiler/optimizing/sharpening.h b/compiler/optimizing/sharpening.h index dc55eea683..b81867201f 100644 --- a/compiler/optimizing/sharpening.h +++ b/compiler/optimizing/sharpening.h @@ -25,24 +25,13 @@ namespace art { class CodeGenerator; class DexCompilationUnit; -// Optimization that tries to improve the way we dispatch methods and access types, -// fields, etc. Besides actual method sharpening based on receiver type (for example -// virtual->direct), this includes selecting the best available dispatch for -// invoke-static/-direct based on code generator support. -class HSharpening : public HOptimization { +// Utility methods that try to improve the way we dispatch methods, and access +// types and strings. +class HSharpening { public: - HSharpening(HGraph* graph, - CodeGenerator* codegen, - const char* name = kSharpeningPassName) - : HOptimization(graph, name), - codegen_(codegen) { } - - bool Run() override; - - static constexpr const char* kSharpeningPassName = "sharpening"; - - // Used by Sharpening and InstructionSimplifier. - static void SharpenInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke, CodeGenerator* codegen); + // Used by the builder and InstructionSimplifier. + static HInvokeStaticOrDirect::DispatchInfo SharpenInvokeStaticOrDirect( + ArtMethod* callee, CodeGenerator* codegen); // Used by the builder and the inliner. static HLoadClass::LoadKind ComputeLoadClassKind(HLoadClass* load_class, @@ -61,9 +50,6 @@ class HSharpening : public HOptimization { CodeGenerator* codegen, const DexCompilationUnit& dex_compilation_unit, VariableSizedHandleScope* handles); - - private: - CodeGenerator* codegen_; }; } // namespace art diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc index c0b6f988d4..65d3031b67 100644 --- a/compiler/utils/mips/assembler_mips.cc +++ b/compiler/utils/mips/assembler_mips.cc @@ -179,7 +179,7 @@ void MipsAssembler::PatchCFI(size_t number_of_delayed_adjust_pcs) { return; } - typedef DebugFrameOpCodeWriterForAssembler::DelayedAdvancePC DelayedAdvancePC; + using DelayedAdvancePC = DebugFrameOpCodeWriterForAssembler::DelayedAdvancePC; const auto data = cfi().ReleaseStreamAndPrepareForDelayedAdvancePC(); const std::vector<uint8_t>& old_stream = data.first; const std::vector<DelayedAdvancePC>& advances = data.second; diff --git a/compiler/utils/mips/assembler_mips32r5_test.cc b/compiler/utils/mips/assembler_mips32r5_test.cc index bd73c12dc5..98fc44ba5d 100644 --- a/compiler/utils/mips/assembler_mips32r5_test.cc +++ b/compiler/utils/mips/assembler_mips32r5_test.cc @@ -38,12 +38,12 @@ class AssemblerMIPS32r5Test : public AssemblerTest<mips::MipsAssembler, uint32_t, mips::VectorRegister> { public: - typedef AssemblerTest<mips::MipsAssembler, - mips::MipsLabel, - mips::Register, - mips::FRegister, - uint32_t, - mips::VectorRegister> Base; + using Base = AssemblerTest<mips::MipsAssembler, + mips::MipsLabel, + mips::Register, + mips::FRegister, + uint32_t, + mips::VectorRegister>; // These tests were taking too long, so we hide the DriverStr() from AssemblerTest<> // and reimplement it without the verification against `assembly_string`. b/73903608 diff --git a/compiler/utils/mips/assembler_mips32r6_test.cc b/compiler/utils/mips/assembler_mips32r6_test.cc index 9637c25e7e..723c489f21 100644 --- a/compiler/utils/mips/assembler_mips32r6_test.cc +++ b/compiler/utils/mips/assembler_mips32r6_test.cc @@ -38,12 +38,12 @@ class AssemblerMIPS32r6Test : public AssemblerTest<mips::MipsAssembler, uint32_t, mips::VectorRegister> { public: - typedef AssemblerTest<mips::MipsAssembler, - mips::MipsLabel, - mips::Register, - mips::FRegister, - uint32_t, - mips::VectorRegister> Base; + using Base = AssemblerTest<mips::MipsAssembler, + mips::MipsLabel, + mips::Register, + mips::FRegister, + uint32_t, + mips::VectorRegister>; // These tests were taking too long, so we hide the DriverStr() from AssemblerTest<> // and reimplement it without the verification against `assembly_string`. b/73903608 diff --git a/compiler/utils/mips/assembler_mips_test.cc b/compiler/utils/mips/assembler_mips_test.cc index f137c60eb8..4f8ccee2c2 100644 --- a/compiler/utils/mips/assembler_mips_test.cc +++ b/compiler/utils/mips/assembler_mips_test.cc @@ -37,11 +37,11 @@ class AssemblerMIPSTest : public AssemblerTest<mips::MipsAssembler, mips::FRegister, uint32_t> { public: - typedef AssemblerTest<mips::MipsAssembler, - mips::MipsLabel, - mips::Register, - mips::FRegister, - uint32_t> Base; + using Base = AssemblerTest<mips::MipsAssembler, + mips::MipsLabel, + mips::Register, + mips::FRegister, + uint32_t>; // These tests were taking too long, so we hide the DriverStr() from AssemblerTest<> // and reimplement it without the verification against `assembly_string`. b/73903608 diff --git a/compiler/utils/mips64/assembler_mips64.cc b/compiler/utils/mips64/assembler_mips64.cc index 5b1c5d9e01..a6f807d1e5 100644 --- a/compiler/utils/mips64/assembler_mips64.cc +++ b/compiler/utils/mips64/assembler_mips64.cc @@ -52,7 +52,7 @@ void Mips64Assembler::PatchCFI() { return; } - typedef DebugFrameOpCodeWriterForAssembler::DelayedAdvancePC DelayedAdvancePC; + using DelayedAdvancePC = DebugFrameOpCodeWriterForAssembler::DelayedAdvancePC; const auto data = cfi().ReleaseStreamAndPrepareForDelayedAdvancePC(); const std::vector<uint8_t>& old_stream = data.first; const std::vector<DelayedAdvancePC>& advances = data.second; diff --git a/compiler/utils/mips64/assembler_mips64_test.cc b/compiler/utils/mips64/assembler_mips64_test.cc index 3218ae3a90..66711c3210 100644 --- a/compiler/utils/mips64/assembler_mips64_test.cc +++ b/compiler/utils/mips64/assembler_mips64_test.cc @@ -41,12 +41,12 @@ class AssemblerMIPS64Test : public AssemblerTest<mips64::Mips64Assembler, uint32_t, mips64::VectorRegister> { public: - typedef AssemblerTest<mips64::Mips64Assembler, - mips64::Mips64Label, - mips64::GpuRegister, - mips64::FpuRegister, - uint32_t, - mips64::VectorRegister> Base; + using Base = AssemblerTest<mips64::Mips64Assembler, + mips64::Mips64Label, + mips64::GpuRegister, + mips64::FpuRegister, + uint32_t, + mips64::VectorRegister>; // These tests were taking too long, so we hide the DriverStr() from AssemblerTest<> // and reimplement it without the verification against `assembly_string`. b/73903608 diff --git a/compiler/utils/x86/assembler_x86_test.cc b/compiler/utils/x86/assembler_x86_test.cc index b03c40aa3e..ad75174d23 100644 --- a/compiler/utils/x86/assembler_x86_test.cc +++ b/compiler/utils/x86/assembler_x86_test.cc @@ -44,11 +44,11 @@ class AssemblerX86Test : public AssemblerTest<x86::X86Assembler, x86::XmmRegister, x86::Immediate> { public: - typedef AssemblerTest<x86::X86Assembler, - x86::Address, - x86::Register, - x86::XmmRegister, - x86::Immediate> Base; + using Base = AssemblerTest<x86::X86Assembler, + x86::Address, + x86::Register, + x86::XmmRegister, + x86::Immediate>; protected: std::string GetArchitectureString() override { diff --git a/compiler/utils/x86_64/assembler_x86_64_test.cc b/compiler/utils/x86_64/assembler_x86_64_test.cc index 65711e0855..fe42f9b19b 100644 --- a/compiler/utils/x86_64/assembler_x86_64_test.cc +++ b/compiler/utils/x86_64/assembler_x86_64_test.cc @@ -137,11 +137,11 @@ class AssemblerX86_64Test : public AssemblerTest<x86_64::X86_64Assembler, x86_64::XmmRegister, x86_64::Immediate> { public: - typedef AssemblerTest<x86_64::X86_64Assembler, - x86_64::Address, - x86_64::CpuRegister, - x86_64::XmmRegister, - x86_64::Immediate> Base; + using Base = AssemblerTest<x86_64::X86_64Assembler, + x86_64::Address, + x86_64::CpuRegister, + x86_64::XmmRegister, + x86_64::Immediate>; protected: // Get the typically used name for this architecture, e.g., aarch64, x86-64, ... diff --git a/dex2oat/linker/elf_writer_test.cc b/dex2oat/linker/elf_writer_test.cc index ef85fd16ff..e7db70c49e 100644 --- a/dex2oat/linker/elf_writer_test.cc +++ b/dex2oat/linker/elf_writer_test.cc @@ -164,7 +164,7 @@ TEST_F(ElfWriterTest, EncodeDecodeOatPatches) { // Patch manually. std::vector<uint8_t> expected = initial_data; for (uintptr_t location : patch_locations) { - typedef __attribute__((__aligned__(1))) uint32_t UnalignedAddress; + using UnalignedAddress = __attribute__((__aligned__(1))) uint32_t; *reinterpret_cast<UnalignedAddress*>(expected.data() + location) += delta; } diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc index e2db11f2aa..7e8346b760 100644 --- a/dex2oat/linker/oat_writer.cc +++ b/dex2oat/linker/oat_writer.cc @@ -92,10 +92,10 @@ static constexpr bool kOatWriterForceOatCodeLayout = false; static constexpr bool kOatWriterDebugOatCodeLayout = false; -typedef DexFile::Header __attribute__((aligned(1))) UnalignedDexFileHeader; +using UnalignedDexFileHeader = __attribute__((aligned(1))) DexFile::Header; const UnalignedDexFileHeader* AsUnalignedDexFileHeader(const uint8_t* raw_data) { - return reinterpret_cast<const UnalignedDexFileHeader*>(raw_data); + return reinterpret_cast<const UnalignedDexFileHeader*>(raw_data); } class ChecksumUpdatingOutputStream : public OutputStream { @@ -2405,7 +2405,7 @@ bool OatWriter::WriteRodata(OutputStream* out) { if (static_cast<uint32_t>(new_offset) != expected_file_offset) { PLOG(ERROR) << "Failed to seek to oat code section. Actual: " << new_offset << " Expected: " << expected_file_offset << " File: " << out->GetLocation(); - return 0; + return false; } DCHECK_OFFSET(); diff --git a/dex2oat/linker/x86/relative_patcher_x86_base.cc b/dex2oat/linker/x86/relative_patcher_x86_base.cc index 6a9690d768..0b24e83073 100644 --- a/dex2oat/linker/x86/relative_patcher_x86_base.cc +++ b/dex2oat/linker/x86/relative_patcher_x86_base.cc @@ -50,7 +50,7 @@ void X86BaseRelativePatcher::PatchCall(std::vector<uint8_t>* code, uint32_t displacement = target_offset - patch_offset; displacement -= kPcDisplacement; // The base PC is at the end of the 4-byte patch. - typedef __attribute__((__aligned__(1))) int32_t unaligned_int32_t; + using unaligned_int32_t = __attribute__((__aligned__(1))) int32_t; reinterpret_cast<unaligned_int32_t*>(&(*code)[literal_offset])[0] = displacement; } diff --git a/dex2oat/linker/x86_64/relative_patcher_x86_64.cc b/dex2oat/linker/x86_64/relative_patcher_x86_64.cc index 9633564999..d391ba3687 100644 --- a/dex2oat/linker/x86_64/relative_patcher_x86_64.cc +++ b/dex2oat/linker/x86_64/relative_patcher_x86_64.cc @@ -31,7 +31,7 @@ void X86_64RelativePatcher::PatchPcRelativeReference(std::vector<uint8_t>* code, uint32_t displacement = target_offset - patch_offset; displacement -= kPcDisplacement; // The base PC is at the end of the 4-byte patch. - typedef __attribute__((__aligned__(1))) int32_t unaligned_int32_t; + using unaligned_int32_t = __attribute__((__aligned__(1))) int32_t; reinterpret_cast<unaligned_int32_t*>(&(*code)[patch.LiteralOffset()])[0] = displacement; } diff --git a/dexdump/Android.bp b/dexdump/Android.bp index 3e576c82da..d15bbda4f4 100644 --- a/dexdump/Android.bp +++ b/dexdump/Android.bp @@ -17,12 +17,12 @@ cc_defaults { name: "dexdump_defaults", + defaults: ["art_defaults"], srcs: [ "dexdump_cfg.cc", "dexdump_main.cc", "dexdump.cc", ], - cflags: ["-Wall", "-Werror"], } art_cc_binary { diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc index 95d88be27d..1d6112f2e8 100644 --- a/dexdump/dexdump.cc +++ b/dexdump/dexdump.cc @@ -69,14 +69,14 @@ FILE* gOutFile = stdout; /* * Data types that match the definitions in the VM specification. */ -typedef uint8_t u1; -typedef uint16_t u2; -typedef uint32_t u4; -typedef uint64_t u8; -typedef int8_t s1; -typedef int16_t s2; -typedef int32_t s4; -typedef int64_t s8; +using u1 = uint8_t; +using u2 = uint16_t; +using u4 = uint32_t; +using u8 = uint64_t; +using s1 = int8_t; +using s2 = int16_t; +using s4 = int32_t; +using s8 = int64_t; /* * Basic information about a field or a method. @@ -1800,18 +1800,18 @@ static void processDexFile(const char* fileName, // Iterate over all classes. char* package = nullptr; const u4 classDefsSize = pDexFile->GetHeader().class_defs_size_; - for (u4 i = 0; i < classDefsSize; i++) { - dumpClass(pDexFile, i, &package); + for (u4 j = 0; j < classDefsSize; j++) { + dumpClass(pDexFile, j, &package); } // for // Iterate over all method handles. - for (u4 i = 0; i < pDexFile->NumMethodHandles(); ++i) { - dumpMethodHandle(pDexFile, i); + for (u4 j = 0; j < pDexFile->NumMethodHandles(); ++j) { + dumpMethodHandle(pDexFile, j); } // for // Iterate over all call site ids. - for (u4 i = 0; i < pDexFile->NumCallSiteIds(); ++i) { - dumpCallSite(pDexFile, i); + for (u4 j = 0; j < pDexFile->NumCallSiteIds(); ++j) { + dumpCallSite(pDexFile, j); } // for // Free the last package allocated. diff --git a/dexdump/dexdump_main.cc b/dexdump/dexdump_main.cc index f4a3866088..cf0d1130dd 100644 --- a/dexdump/dexdump_main.cc +++ b/dexdump/dexdump_main.cc @@ -37,7 +37,7 @@ static const char* gProgName = "dexdump"; /* * Shows usage. */ -static void usage(void) { +static void usage() { LOG(ERROR) << "Copyright (C) 2007 The Android Open Source Project\n"; LOG(ERROR) << gProgName << ": [-a] [-c] [-d] [-e] [-f] [-h] [-i] [-j] [-l layout] [-o outfile]" " dexfile...\n"; @@ -64,7 +64,7 @@ int dexdumpDriver(int argc, char** argv) { gOptions.verbose = true; // Parse all arguments. - while (1) { + while (true) { const int ic = getopt(argc, argv, "acdefghijl:o:"); if (ic < 0) { break; // done diff --git a/dexlayout/dexlayout_main.cc b/dexlayout/dexlayout_main.cc index 9f73347354..a851cfae01 100644 --- a/dexlayout/dexlayout_main.cc +++ b/dexlayout/dexlayout_main.cc @@ -42,7 +42,7 @@ static const char* kProgramName = "dexlayout"; /* * Shows usage. */ -static void Usage(void) { +static void Usage() { LOG(ERROR) << "Copyright (C) 2016 The Android Open Source Project\n"; LOG(ERROR) << kProgramName << ": [-a] [-c] [-d] [-e] [-f] [-h] [-i] [-l layout] [-o outfile] [-p profile]" @@ -85,7 +85,7 @@ int DexlayoutDriver(int argc, char** argv) { bool want_usage = false; // Parse all arguments. - while (1) { + while (true) { const int ic = getopt(argc, argv, "abcdefghil:o:p:stuvw:x:"); if (ic < 0) { break; // done diff --git a/dexlist/Android.bp b/dexlist/Android.bp index bd521acbc0..217a024357 100644 --- a/dexlist/Android.bp +++ b/dexlist/Android.bp @@ -14,18 +14,14 @@ art_cc_binary { name: "dexlist", + defaults: ["art_defaults"], host_supported: true, srcs: ["dexlist.cc"], - cflags: ["-Wall", "-Werror"], shared_libs: [ "libdexfile", "libartbase", "libbase" ], - // TODO: fix b/72216369 and remove the need for this. - include_dirs: [ - "art/runtime" // dex utils. - ], } art_cc_test { diff --git a/dexlist/dexlist.cc b/dexlist/dexlist.cc index c2514a1c52..067daa7842 100644 --- a/dexlist/dexlist.cc +++ b/dexlist/dexlist.cc @@ -55,9 +55,9 @@ static FILE* gOutFile = stdout; /* * Data types that match the definitions in the VM specification. */ -typedef uint8_t u1; -typedef uint32_t u4; -typedef uint64_t u8; +using u1 = uint8_t; +using u4 = uint32_t; +using u8 = uint64_t; /* * Returns a newly-allocated string for the "dot version" of the class @@ -197,7 +197,7 @@ static int processFile(const char* fileName) { /* * Shows usage. */ -static void usage(void) { +static void usage() { LOG(ERROR) << "Copyright (C) 2007 The Android Open Source Project\n"; LOG(ERROR) << gProgName << ": [-m p.c.m] [-o outfile] dexfile..."; LOG(ERROR) << ""; @@ -212,7 +212,7 @@ int dexlistDriver(int argc, char** argv) { memset(&gOptions, 0, sizeof(gOptions)); // Parse all arguments. - while (1) { + while (true) { const int ic = getopt(argc, argv, "o:m:"); if (ic < 0) { break; // done diff --git a/disassembler/disassembler_arm.cc b/disassembler/disassembler_arm.cc index c1a6f59341..4a0c027f61 100644 --- a/disassembler/disassembler_arm.cc +++ b/disassembler/disassembler_arm.cc @@ -137,12 +137,12 @@ class DisassemblerArm::CustomDisassembler final : public PrintDisassembler { void DisassemblerArm::CustomDisassembler::CustomDisassemblerStream::PrintLiteral(LocationType type, int32_t offset) { // Literal offsets are not required to be aligned, so we may need unaligned access. - typedef const int16_t unaligned_int16_t __attribute__ ((aligned (1))); - typedef const uint16_t unaligned_uint16_t __attribute__ ((aligned (1))); - typedef const int32_t unaligned_int32_t __attribute__ ((aligned (1))); - typedef const int64_t unaligned_int64_t __attribute__ ((aligned (1))); - typedef const float unaligned_float __attribute__ ((aligned (1))); - typedef const double unaligned_double __attribute__ ((aligned (1))); + using unaligned_int16_t = const int16_t __attribute__ ((aligned (1))); + using unaligned_uint16_t = const uint16_t __attribute__ ((aligned (1))); + using unaligned_int32_t = const int32_t __attribute__ ((aligned (1))); + using unaligned_int64_t = const int64_t __attribute__ ((aligned (1))); + using unaligned_float = const float __attribute__ ((aligned (1))); + using unaligned_double = const double __attribute__ ((aligned (1))); // Zeros are used for the LocationType values this function does not care about. const size_t literal_size[kVst4Location + 1] = { diff --git a/imgdiag/imgdiag.cc b/imgdiag/imgdiag.cc index 51b3d753d7..1b2e8d7526 100644 --- a/imgdiag/imgdiag.cc +++ b/imgdiag/imgdiag.cc @@ -762,7 +762,8 @@ class RegionSpecializedBase<ArtMethod> : public RegionCommon<ArtMethod> { std::unordered_set<size_t> dirty_members; // Examine the members comprising the ArtMethod, computing which members are dirty. - for (const std::pair<size_t, MemberInfo::NameAndSize>& p : member_info_.offset_to_name_size_) { + for (const std::pair<const size_t, + MemberInfo::NameAndSize>& p : member_info_.offset_to_name_size_) { const size_t offset = p.first; if (memcmp(base_ptr + offset, remote_bytes + offset, p.second.size_) != 0) { dirty_members.insert(p.first); @@ -788,7 +789,8 @@ class RegionSpecializedBase<ArtMethod> : public RegionCommon<ArtMethod> { void DumpDirtyEntries() REQUIRES_SHARED(Locks::mutator_lock_) { DumpSamplesAndOffsetCount(); os_ << " offset to field map:\n"; - for (const std::pair<size_t, MemberInfo::NameAndSize>& p : member_info_.offset_to_name_size_) { + for (const std::pair<const size_t, + MemberInfo::NameAndSize>& p : member_info_.offset_to_name_size_) { const size_t offset = p.first; const size_t size = p.second.size_; os_ << StringPrintf(" %zu-%zu: ", offset, offset + size - 1) diff --git a/libartbase/Android.bp b/libartbase/Android.bp index 1b603b51e1..19f15322ef 100644 --- a/libartbase/Android.bp +++ b/libartbase/Android.bp @@ -29,6 +29,8 @@ cc_defaults { "base/hex_dump.cc", "base/logging.cc", "base/malloc_arena_pool.cc", + "base/membarrier.cc", + "base/memfd.cc", "base/memory_region.cc", "base/mem_map.cc", // "base/mem_map_fuchsia.cc", put in target when fuchsia supported by soong @@ -186,6 +188,8 @@ art_cc_test { "base/indenter_test.cc", "base/leb128_test.cc", "base/logging_test.cc", + "base/memfd_test.cc", + "base/membarrier_test.cc", "base/memory_region_test.cc", "base/mem_map_test.cc", "base/safe_copy_test.cc", diff --git a/libartbase/base/membarrier.cc b/libartbase/base/membarrier.cc new file mode 100644 index 0000000000..490dbf3fa0 --- /dev/null +++ b/libartbase/base/membarrier.cc @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2018 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 "membarrier.h" + +#include <errno.h> + +#include <sys/syscall.h> +#include <unistd.h> +#include "macros.h" + +#if defined(__BIONIC__) + +#include <atomic> +#include <android/get_device_api_level.h> +#include <linux/membarrier.h> + +#define CHECK_MEMBARRIER_CMD(art_value, membarrier_value) \ + static_assert(static_cast<int>(art_value) == membarrier_value, "Bad value for " # art_value) +CHECK_MEMBARRIER_CMD(art::MembarrierCommand::kQuery, MEMBARRIER_CMD_QUERY); +CHECK_MEMBARRIER_CMD(art::MembarrierCommand::kGlobal, MEMBARRIER_CMD_SHARED); +CHECK_MEMBARRIER_CMD(art::MembarrierCommand::kPrivateExpedited, MEMBARRIER_CMD_PRIVATE_EXPEDITED); +CHECK_MEMBARRIER_CMD(art::MembarrierCommand::kRegisterPrivateExpedited, + MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED); +CHECK_MEMBARRIER_CMD(art::MembarrierCommand::kPrivateExpedited, MEMBARRIER_CMD_PRIVATE_EXPEDITED); +#undef CHECK_MEMBARRIER_CMD + +#endif // __BIONIC + +namespace art { + +#if defined(__NR_membarrier) + +int membarrier(MembarrierCommand command) { +#if defined(__BIONIC__) + // Avoid calling membarrier on older Android versions where membarrier may be barred by secomp + // causing the current process to be killed. The probing here could be considered expensive so + // endeavour not to repeat too often. + static int api_level = android_get_device_api_level(); + if (api_level < __ANDROID_API_Q__) { + errno = ENOSYS; + return -1; + } +#endif // __BIONIC__ + return syscall(__NR_membarrier, static_cast<int>(command), 0); +} + +#else // __NR_membarrier + +int membarrier(MembarrierCommand command ATTRIBUTE_UNUSED) { + // In principle this could be supported on linux, but Android's prebuilt glibc does not include + // the system call number defintions (b/111199492). + errno = ENOSYS; + return -1; +} + +#endif // __NR_membarrier + +} // namespace art diff --git a/libartbase/base/membarrier.h b/libartbase/base/membarrier.h new file mode 100644 index 0000000000..f829fc1f80 --- /dev/null +++ b/libartbase/base/membarrier.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef ART_LIBARTBASE_BASE_MEMBARRIER_H_ +#define ART_LIBARTBASE_BASE_MEMBARRIER_H_ + +namespace art { + // Command types for the linux membarrier system call. Different Linux installation may include + // different subsets of these commands (at the same codepoints). + // + // Hardcoding these values is temporary until bionic and prebuilts glibc have an up to date + // linux/membarrier.h. The order and values follow the current linux definitions. + enum class MembarrierCommand : int { + // MEMBARRIER_CMD_QUERY + kQuery = 0, + // MEMBARRIER_CMD_GLOBAL + kGlobal = (1 << 0), + // MEMBARRIER_CMD_GLOBAL_EXPEDITED + kGlobalExpedited = (1 << 1), + // MEMBARRIER_CMD_REGISTER_GLOBAL_EXPEDITED + kRegisterGlobalExpedited = (1 << 2), + // MEMBARRIER_CMD_PRIVATE_EXPEDITED + kPrivateExpedited = (1 << 3), + // MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED + kRegisterPrivateExpedited = (1 << 4), + // MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE + kPrivateExpeditedSyncCore = (1 << 5), + // MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE + kRegisterPrivateExpeditedSyncCore = (1 << 6) + }; + + // Call membarrier(2) if available on platform and return result. This method can fail if the + // command is not supported by the kernel. The underlying system call is linux specific. + int membarrier(MembarrierCommand command); + +} // namespace art + +#endif // ART_LIBARTBASE_BASE_MEMBARRIER_H_ diff --git a/libartbase/base/membarrier_test.cc b/libartbase/base/membarrier_test.cc new file mode 100644 index 0000000000..3eedf14dcd --- /dev/null +++ b/libartbase/base/membarrier_test.cc @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2018 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 <gtest/gtest.h> + +#include "membarrier.h" + +class ScopedErrnoCleaner { + public: + ScopedErrnoCleaner() { errno = 0; } + ~ScopedErrnoCleaner() { errno = 0; } +}; + +bool HasMembarrier(art::MembarrierCommand cmd) { + ScopedErrnoCleaner errno_cleaner; + int supported_cmds = art::membarrier(art::MembarrierCommand::kQuery); + return (supported_cmds > 0) && ((supported_cmds & static_cast<int>(cmd)) != 0); +} + +TEST(membarrier, query) { + ScopedErrnoCleaner errno_cleaner; + int supported = art::membarrier(art::MembarrierCommand::kQuery); + if (errno == 0) { + ASSERT_LE(0, supported); + } else { + ASSERT_TRUE(errno == ENOSYS && supported == -1); + } +} + +TEST(membarrier, global_barrier) { + if (!HasMembarrier(art::MembarrierCommand::kGlobal)) { + GTEST_LOG_(INFO) << "MembarrierCommand::kGlobal not supported, skipping test."; + return; + } + ASSERT_EQ(0, art::membarrier(art::MembarrierCommand::kGlobal)); +} + +static const char* MembarrierCommandToName(art::MembarrierCommand cmd) { +#define CASE_VALUE(x) case (x): return #x; + switch (cmd) { + CASE_VALUE(art::MembarrierCommand::kQuery); + CASE_VALUE(art::MembarrierCommand::kGlobal); + CASE_VALUE(art::MembarrierCommand::kGlobalExpedited); + CASE_VALUE(art::MembarrierCommand::kRegisterGlobalExpedited); + CASE_VALUE(art::MembarrierCommand::kPrivateExpedited); + CASE_VALUE(art::MembarrierCommand::kRegisterPrivateExpedited); + CASE_VALUE(art::MembarrierCommand::kPrivateExpeditedSyncCore); + CASE_VALUE(art::MembarrierCommand::kRegisterPrivateExpeditedSyncCore); + } +} + +static void TestRegisterAndBarrierCommands(art::MembarrierCommand membarrier_cmd_register, + art::MembarrierCommand membarrier_cmd_barrier) { + if (!HasMembarrier(membarrier_cmd_register)) { + GTEST_LOG_(INFO) << MembarrierCommandToName(membarrier_cmd_register) + << " not supported, skipping test."; + return; + } + if (!HasMembarrier(membarrier_cmd_barrier)) { + GTEST_LOG_(INFO) << MembarrierCommandToName(membarrier_cmd_barrier) + << " not supported, skipping test."; + return; + } + + ScopedErrnoCleaner errno_cleaner; + + // Check barrier use without prior registration. + if (membarrier_cmd_register == art::MembarrierCommand::kRegisterGlobalExpedited) { + // Global barrier use is always okay. + ASSERT_EQ(0, art::membarrier(membarrier_cmd_barrier)); + } else { + // Private barrier should fail. + ASSERT_EQ(-1, art::membarrier(membarrier_cmd_barrier)); + ASSERT_EQ(EPERM, errno); + errno = 0; + } + + // Check registration for barrier succeeds. + ASSERT_EQ(0, art::membarrier(membarrier_cmd_register)); + + // Check barrier use after registration succeeds. + ASSERT_EQ(0, art::membarrier(membarrier_cmd_barrier)); +} + +TEST(membarrier, global_expedited) { + TestRegisterAndBarrierCommands(art::MembarrierCommand::kRegisterGlobalExpedited, + art::MembarrierCommand::kGlobalExpedited); +} + +TEST(membarrier, private_expedited) { + TestRegisterAndBarrierCommands(art::MembarrierCommand::kRegisterPrivateExpedited, + art::MembarrierCommand::kPrivateExpedited); +} + +TEST(membarrier, private_expedited_sync_core) { + TestRegisterAndBarrierCommands(art::MembarrierCommand::kRegisterPrivateExpeditedSyncCore, + art::MembarrierCommand::kPrivateExpeditedSyncCore); +} diff --git a/libartbase/base/memfd.cc b/libartbase/base/memfd.cc new file mode 100644 index 0000000000..1afcd7b311 --- /dev/null +++ b/libartbase/base/memfd.cc @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2018 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 "memfd.h" + +#include <errno.h> +#include <sys/syscall.h> +#include <unistd.h> + +#include "macros.h" + +// When building for linux host, glibc in prebuilts does not include memfd_create system call +// number. As a temporary testing measure, we add the definition here. +#if defined(__linux__) && !defined(__NR_memfd_create) +#if defined(__x86_64__) +#define __NR_memfd_create 319 +#elif defined(__i386__) +#define __NR_memfd_create 356 +#endif // defined(__i386__) +#endif // defined(__linux__) && !defined(__NR_memfd_create) + +namespace art { + +#if defined(__NR_memfd_create) + +int memfd_create(const char* name, unsigned int flags) { + return syscall(__NR_memfd_create, name, flags); +} + +#else // __NR_memfd_create + +int memfd_create(const char* name ATTRIBUTE_UNUSED, unsigned int flags ATTRIBUTE_UNUSED) { + errno = ENOSYS; + return -1; +} + +#endif // __NR_memfd_create + +} // namespace art diff --git a/libartbase/base/memfd.h b/libartbase/base/memfd.h new file mode 100644 index 0000000000..4367198185 --- /dev/null +++ b/libartbase/base/memfd.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef ART_LIBARTBASE_BASE_MEMFD_H_ +#define ART_LIBARTBASE_BASE_MEMFD_H_ + +namespace art { + + // Call memfd(2) if available on platform and return result. +int memfd_create(const char* name, unsigned int flags); + +} // namespace art + +#endif // ART_LIBARTBASE_BASE_MEMFD_H_ diff --git a/libartbase/base/memfd_test.cc b/libartbase/base/memfd_test.cc new file mode 100644 index 0000000000..1edf3a11ce --- /dev/null +++ b/libartbase/base/memfd_test.cc @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2018 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 <gtest/gtest.h> + +#include "memfd.h" + +TEST(memfd, basic) { + errno = 0; + int fd = art::memfd_create("memfd_create_test", 0); + if (fd < 0) { + ASSERT_EQ(ENOSYS, errno); + GTEST_LOG_(INFO) << "memfd_create not supported, skipping test."; + return; + } + ASSERT_TRUE(close(fd) == 0 || errno != EBADF); +} diff --git a/libartbase/base/utils.cc b/libartbase/base/utils.cc index 74cc5b97b2..2242fe877e 100644 --- a/libartbase/base/utils.cc +++ b/libartbase/base/utils.cc @@ -213,42 +213,4 @@ void SleepForever() { } } -bool FlushInstructionPipeline() { - // membarrier(2) is only supported for target builds (b/111199492). -#if defined(__BIONIC__) - static constexpr int kSyncCoreMask = - MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE | - MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE; - static bool have_probed = false; - static bool have_sync_core = false; - - if (UNLIKELY(!have_probed)) { - // Probe membarrier(2) commands supported by kernel. - int commands = syscall(__NR_membarrier, MEMBARRIER_CMD_QUERY, 0); - if (commands >= 0) { - have_sync_core = (commands & kSyncCoreMask) == kSyncCoreMask; - if (have_sync_core) { - // Register with kernel that we'll be using the private expedited sync core command. - CheckedCall(syscall, - "membarrier register sync core", - __NR_membarrier, - MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE, - 0); - } - } - have_probed = true; - } - - if (have_sync_core) { - CheckedCall(syscall, - "membarrier sync core", - __NR_membarrier, - MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE, - 0); - return true; - } -#endif // defined(__BIONIC__) - return false; -} - } // namespace art diff --git a/libartbase/base/utils.h b/libartbase/base/utils.h index d85960d811..e6a0459e27 100644 --- a/libartbase/base/utils.h +++ b/libartbase/base/utils.h @@ -162,9 +162,6 @@ inline void FlushInstructionCache(void* begin, void* end) { __builtin___clear_cache(reinterpret_cast<char*>(begin), reinterpret_cast<char*>(end)); } -// Flush instruction pipeline. Returns true on success, false if feature is unsupported. -bool FlushInstructionPipeline(); - template <typename T> constexpr PointerSize ConvertToPointerSize(T any) { if (any == 4 || any == 8) { diff --git a/libdexfile/dex/dex_file_loader.cc b/libdexfile/dex/dex_file_loader.cc index 400c32b519..4aafc665ee 100644 --- a/libdexfile/dex/dex_file_loader.cc +++ b/libdexfile/dex/dex_file_loader.cc @@ -25,10 +25,6 @@ #include "standard_dex_file.h" #include "ziparchive/zip_archive.h" -// system/core/zip_archive definitions. -struct ZipEntry; -typedef void* ZipArchiveHandle; - namespace art { namespace { diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 707fc1c9ed..d30ec3157d 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -419,7 +419,7 @@ class OatDumper { return instruction_set_; } - typedef std::vector<std::unique_ptr<const DexFile>> DexFileUniqV; + using DexFileUniqV = std::vector<std::unique_ptr<const DexFile>>; bool Dump(std::ostream& os) { bool success = true; @@ -2480,7 +2480,7 @@ class ImageDumper { size_t bytes; size_t count; }; - typedef SafeMap<std::string, SizeAndCount> SizeAndCountTable; + using SizeAndCountTable = SafeMap<std::string, SizeAndCount>; SizeAndCountTable sizes_and_counts; void Update(const char* descriptor, size_t object_bytes_in) { diff --git a/patchoat/patchoat_test.cc b/patchoat/patchoat_test.cc index 6492b96b34..79ae9872ba 100644 --- a/patchoat/patchoat_test.cc +++ b/patchoat/patchoat_test.cc @@ -405,7 +405,7 @@ TEST_F(PatchoatTest, PatchoatRelocationSameAsDex2oatRelocation) { std::vector<std::string> patchoat_image_shortened_basenames(patchoat_image_basenames.size()); for (size_t i = 0; i < patchoat_image_basenames.size(); i++) { patchoat_image_shortened_basenames[i] = - patchoat_image_basenames[i].substr(patchoat_image_basenames[i].find_last_of("@") + 1); + patchoat_image_basenames[i].substr(patchoat_image_basenames[i].find_last_of('@') + 1); } ASSERT_EQ(dex2oat_image_basenames, patchoat_image_shortened_basenames); @@ -515,16 +515,16 @@ class PatchoatVerificationTest : public PatchoatTest { std::vector<std::string> rel_shortened_basenames(rel_basenames.size()); std::vector<std::string> relocated_image_shortened_basenames(relocated_image_basenames.size()); for (size_t i = 0; i < rel_basenames.size(); i++) { - rel_shortened_basenames[i] = rel_basenames[i].substr(rel_basenames[i].find_last_of("@") + 1); + rel_shortened_basenames[i] = rel_basenames[i].substr(rel_basenames[i].find_last_of('@') + 1); rel_shortened_basenames[i] = - rel_shortened_basenames[i].substr(0, rel_shortened_basenames[i].find(".")); + rel_shortened_basenames[i].substr(0, rel_shortened_basenames[i].find('.')); } for (size_t i = 0; i < relocated_image_basenames.size(); i++) { relocated_image_shortened_basenames[i] = - relocated_image_basenames[i].substr(relocated_image_basenames[i].find_last_of("@") + 1); + relocated_image_basenames[i].substr(relocated_image_basenames[i].find_last_of('@') + 1); relocated_image_shortened_basenames[i] = relocated_image_shortened_basenames[i].substr( - 0, relocated_image_shortened_basenames[i].find(".")); + 0, relocated_image_shortened_basenames[i].find('.')); } ASSERT_EQ(rel_shortened_basenames, relocated_image_shortened_basenames); } diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc index 28b29125cd..b2ddff3f6a 100644 --- a/runtime/base/mutex.cc +++ b/runtime/base/mutex.cc @@ -227,18 +227,15 @@ void BaseMutex::DumpAll(std::ostream& os) { // No mutexes have been created yet during at startup. return; } - typedef std::set<BaseMutex*>::const_iterator It; os << "(Contended)\n"; - for (It it = all_mutexes->begin(); it != all_mutexes->end(); ++it) { - BaseMutex* mutex = *it; + for (const BaseMutex* mutex : *all_mutexes) { if (mutex->HasEverContended()) { mutex->Dump(os); os << "\n"; } } os << "(Never contented)\n"; - for (It it = all_mutexes->begin(); it != all_mutexes->end(); ++it) { - BaseMutex* mutex = *it; + for (const BaseMutex* mutex : *all_mutexes) { if (!mutex->HasEverContended()) { mutex->Dump(os); os << "\n"; diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index befeea463a..d9daae7b21 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -307,7 +307,7 @@ struct FieldGapsComparator { return lhs.size < rhs.size || (lhs.size == rhs.size && lhs.start_offset > rhs.start_offset); } }; -typedef std::priority_queue<FieldGap, std::vector<FieldGap>, FieldGapsComparator> FieldGaps; +using FieldGaps = std::priority_queue<FieldGap, std::vector<FieldGap>, FieldGapsComparator>; // Adds largest aligned gaps to queue of gaps. static void AddFieldGap(uint32_t gap_start, uint32_t gap_end, FieldGaps* gaps) { @@ -2301,7 +2301,7 @@ ObjPtr<mirror::Class> ClassLinker::EnsureResolved(Thread* self, return klass; } -typedef std::pair<const DexFile*, const DexFile::ClassDef*> ClassPathEntry; +using ClassPathEntry = std::pair<const DexFile*, const DexFile::ClassDef*>; // Search a collection of DexFiles for a descriptor ClassPathEntry FindInClassPath(const char* descriptor, diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc index e7715c4934..4277f0093f 100644 --- a/runtime/elf_file.cc +++ b/runtime/elf_file.cc @@ -1417,7 +1417,7 @@ template <typename ElfTypes> void ElfFileImpl<ElfTypes>::ApplyOatPatches( const uint8_t* patches, const uint8_t* patches_end, Elf_Addr delta, uint8_t* to_patch, const uint8_t* to_patch_end) { - typedef __attribute__((__aligned__(1))) Elf_Addr UnalignedAddress; + using UnalignedAddress = __attribute__((__aligned__(1))) Elf_Addr; while (patches < patches_end) { to_patch += DecodeUnsignedLeb128(&patches); DCHECK_LE(patches, patches_end) << "Unexpected end of patch list."; diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index 8f064a3dc2..ee4a0f4f56 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -1029,9 +1029,7 @@ class ImageSpace::Loader { if (obj->IsClass<kVerifyNone>()) { mirror::Class* as_klass = obj->AsClass<kVerifyNone>(); FixupObjectAdapter visitor(boot_image_, boot_oat_, app_image_, app_oat_); - as_klass->FixupNativePointers<kVerifyNone, kWithoutReadBarrier>(as_klass, - pointer_size_, - visitor); + as_klass->FixupNativePointers<kVerifyNone>(as_klass, pointer_size_, visitor); // Deal with the pointer arrays. Use the helper function since multiple classes can reference // the same arrays. mirror::PointerArray* const vtable = as_klass->GetVTable<kVerifyNone, kWithoutReadBarrier>(); diff --git a/runtime/hprof/hprof.cc b/runtime/hprof/hprof.cc index e8a47d1087..9467c4c952 100644 --- a/runtime/hprof/hprof.cc +++ b/runtime/hprof/hprof.cc @@ -148,11 +148,11 @@ enum HprofBasicType { hprof_basic_long = 11, }; -typedef uint32_t HprofStringId; -typedef uint32_t HprofClassObjectId; -typedef uint32_t HprofClassSerialNumber; -typedef uint32_t HprofStackTraceSerialNumber; -typedef uint32_t HprofStackFrameId; +using HprofStringId = uint32_t; +using HprofClassObjectId = uint32_t; +using HprofClassSerialNumber = uint32_t; +using HprofStackTraceSerialNumber = uint32_t; +using HprofStackFrameId = uint32_t; static constexpr HprofStackTraceSerialNumber kHprofNullStackTrace = 0; class EndianOutput { diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc index 048c6e4d66..df66061d01 100644 --- a/runtime/interpreter/interpreter.cc +++ b/runtime/interpreter/interpreter.cc @@ -56,7 +56,7 @@ static void InterpreterJni(Thread* self, ScopedObjectAccessUnchecked soa(self); if (method->IsStatic()) { if (shorty == "L") { - typedef jobject (fntype)(JNIEnv*, jclass); + using fntype = jobject(JNIEnv*, jclass); fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); ScopedLocalRef<jclass> klass(soa.Env(), soa.AddLocalReference<jclass>(method->GetDeclaringClass())); @@ -67,35 +67,35 @@ static void InterpreterJni(Thread* self, } result->SetL(soa.Decode<mirror::Object>(jresult)); } else if (shorty == "V") { - typedef void (fntype)(JNIEnv*, jclass); + using fntype = void(JNIEnv*, jclass); fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); ScopedLocalRef<jclass> klass(soa.Env(), soa.AddLocalReference<jclass>(method->GetDeclaringClass())); ScopedThreadStateChange tsc(self, kNative); fn(soa.Env(), klass.get()); } else if (shorty == "Z") { - typedef jboolean (fntype)(JNIEnv*, jclass); + using fntype = jboolean(JNIEnv*, jclass); fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); ScopedLocalRef<jclass> klass(soa.Env(), soa.AddLocalReference<jclass>(method->GetDeclaringClass())); ScopedThreadStateChange tsc(self, kNative); result->SetZ(fn(soa.Env(), klass.get())); } else if (shorty == "BI") { - typedef jbyte (fntype)(JNIEnv*, jclass, jint); + using fntype = jbyte(JNIEnv*, jclass, jint); fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); ScopedLocalRef<jclass> klass(soa.Env(), soa.AddLocalReference<jclass>(method->GetDeclaringClass())); ScopedThreadStateChange tsc(self, kNative); result->SetB(fn(soa.Env(), klass.get(), args[0])); } else if (shorty == "II") { - typedef jint (fntype)(JNIEnv*, jclass, jint); + using fntype = jint(JNIEnv*, jclass, jint); fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); ScopedLocalRef<jclass> klass(soa.Env(), soa.AddLocalReference<jclass>(method->GetDeclaringClass())); ScopedThreadStateChange tsc(self, kNative); result->SetI(fn(soa.Env(), klass.get(), args[0])); } else if (shorty == "LL") { - typedef jobject (fntype)(JNIEnv*, jclass, jobject); + using fntype = jobject(JNIEnv*, jclass, jobject); fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); ScopedLocalRef<jclass> klass(soa.Env(), soa.AddLocalReference<jclass>(method->GetDeclaringClass())); @@ -108,14 +108,14 @@ static void InterpreterJni(Thread* self, } result->SetL(soa.Decode<mirror::Object>(jresult)); } else if (shorty == "IIZ") { - typedef jint (fntype)(JNIEnv*, jclass, jint, jboolean); + using fntype = jint(JNIEnv*, jclass, jint, jboolean); fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); ScopedLocalRef<jclass> klass(soa.Env(), soa.AddLocalReference<jclass>(method->GetDeclaringClass())); ScopedThreadStateChange tsc(self, kNative); result->SetI(fn(soa.Env(), klass.get(), args[0], args[1])); } else if (shorty == "ILI") { - typedef jint (fntype)(JNIEnv*, jclass, jobject, jint); + using fntype = jint(JNIEnv*, jclass, jobject, jint); fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>( method->GetEntryPointFromJni())); ScopedLocalRef<jclass> klass(soa.Env(), @@ -125,7 +125,7 @@ static void InterpreterJni(Thread* self, ScopedThreadStateChange tsc(self, kNative); result->SetI(fn(soa.Env(), klass.get(), arg0.get(), args[1])); } else if (shorty == "SIZ") { - typedef jshort (fntype)(JNIEnv*, jclass, jint, jboolean); + using fntype = jshort(JNIEnv*, jclass, jint, jboolean); fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetEntryPointFromJni())); ScopedLocalRef<jclass> klass(soa.Env(), @@ -133,14 +133,14 @@ static void InterpreterJni(Thread* self, ScopedThreadStateChange tsc(self, kNative); result->SetS(fn(soa.Env(), klass.get(), args[0], args[1])); } else if (shorty == "VIZ") { - typedef void (fntype)(JNIEnv*, jclass, jint, jboolean); + using fntype = void(JNIEnv*, jclass, jint, jboolean); fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); ScopedLocalRef<jclass> klass(soa.Env(), soa.AddLocalReference<jclass>(method->GetDeclaringClass())); ScopedThreadStateChange tsc(self, kNative); fn(soa.Env(), klass.get(), args[0], args[1]); } else if (shorty == "ZLL") { - typedef jboolean (fntype)(JNIEnv*, jclass, jobject, jobject); + using fntype = jboolean(JNIEnv*, jclass, jobject, jobject); fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); ScopedLocalRef<jclass> klass(soa.Env(), soa.AddLocalReference<jclass>(method->GetDeclaringClass())); @@ -151,7 +151,7 @@ static void InterpreterJni(Thread* self, ScopedThreadStateChange tsc(self, kNative); result->SetZ(fn(soa.Env(), klass.get(), arg0.get(), arg1.get())); } else if (shorty == "ZILL") { - typedef jboolean (fntype)(JNIEnv*, jclass, jint, jobject, jobject); + using fntype = jboolean(JNIEnv*, jclass, jint, jobject, jobject); fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); ScopedLocalRef<jclass> klass(soa.Env(), soa.AddLocalReference<jclass>(method->GetDeclaringClass())); @@ -162,7 +162,7 @@ static void InterpreterJni(Thread* self, ScopedThreadStateChange tsc(self, kNative); result->SetZ(fn(soa.Env(), klass.get(), args[0], arg1.get(), arg2.get())); } else if (shorty == "VILII") { - typedef void (fntype)(JNIEnv*, jclass, jint, jobject, jint, jint); + using fntype = void(JNIEnv*, jclass, jint, jobject, jint, jint); fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); ScopedLocalRef<jclass> klass(soa.Env(), soa.AddLocalReference<jclass>(method->GetDeclaringClass())); @@ -171,7 +171,7 @@ static void InterpreterJni(Thread* self, ScopedThreadStateChange tsc(self, kNative); fn(soa.Env(), klass.get(), args[0], arg1.get(), args[2], args[3]); } else if (shorty == "VLILII") { - typedef void (fntype)(JNIEnv*, jclass, jobject, jint, jobject, jint, jint); + using fntype = void(JNIEnv*, jclass, jobject, jint, jobject, jint, jint); fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); ScopedLocalRef<jclass> klass(soa.Env(), soa.AddLocalReference<jclass>(method->GetDeclaringClass())); @@ -187,7 +187,7 @@ static void InterpreterJni(Thread* self, } } else { if (shorty == "L") { - typedef jobject (fntype)(JNIEnv*, jobject); + using fntype = jobject(JNIEnv*, jobject); fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); ScopedLocalRef<jobject> rcvr(soa.Env(), soa.AddLocalReference<jobject>(receiver)); @@ -198,14 +198,14 @@ static void InterpreterJni(Thread* self, } result->SetL(soa.Decode<mirror::Object>(jresult)); } else if (shorty == "V") { - typedef void (fntype)(JNIEnv*, jobject); + using fntype = void(JNIEnv*, jobject); fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); ScopedLocalRef<jobject> rcvr(soa.Env(), soa.AddLocalReference<jobject>(receiver)); ScopedThreadStateChange tsc(self, kNative); fn(soa.Env(), rcvr.get()); } else if (shorty == "LL") { - typedef jobject (fntype)(JNIEnv*, jobject, jobject); + using fntype = jobject(JNIEnv*, jobject, jobject); fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); ScopedLocalRef<jobject> rcvr(soa.Env(), soa.AddLocalReference<jobject>(receiver)); @@ -219,7 +219,7 @@ static void InterpreterJni(Thread* self, result->SetL(soa.Decode<mirror::Object>(jresult)); ScopedThreadStateChange tsc(self, kNative); } else if (shorty == "III") { - typedef jint (fntype)(JNIEnv*, jobject, jint, jint); + using fntype = jint(JNIEnv*, jobject, jint, jint); fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni()); ScopedLocalRef<jobject> rcvr(soa.Env(), soa.AddLocalReference<jobject>(receiver)); diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc index d4b51af903..78cb649f5c 100644 --- a/runtime/interpreter/unstarted_runtime.cc +++ b/runtime/interpreter/unstarted_runtime.cc @@ -1180,19 +1180,19 @@ static void UnstartedMemoryPeek( } case Primitive::kPrimShort: { - typedef int16_t unaligned_short __attribute__ ((aligned (1))); + using unaligned_short = int16_t __attribute__ ((aligned (1))); result->SetS(*reinterpret_cast<unaligned_short*>(static_cast<intptr_t>(address))); return; } case Primitive::kPrimInt: { - typedef int32_t unaligned_int __attribute__ ((aligned (1))); + using unaligned_int = int32_t __attribute__ ((aligned (1))); result->SetI(*reinterpret_cast<unaligned_int*>(static_cast<intptr_t>(address))); return; } case Primitive::kPrimLong: { - typedef int64_t unaligned_long __attribute__ ((aligned (1))); + using unaligned_long = int64_t __attribute__ ((aligned (1))); result->SetJ(*reinterpret_cast<unaligned_long*>(static_cast<intptr_t>(address))); return; } @@ -1919,11 +1919,16 @@ void UnstartedRuntime::UnstartedJNIUnsafeGetArrayIndexScaleForComponentType( result->SetI(Primitive::ComponentSize(primitive_type)); } -typedef void (*InvokeHandler)(Thread* self, ShadowFrame* shadow_frame, JValue* result, - size_t arg_size); +using InvokeHandler = void(*)(Thread* self, + ShadowFrame* shadow_frame, + JValue* result, + size_t arg_size); -typedef void (*JNIHandler)(Thread* self, ArtMethod* method, mirror::Object* receiver, - uint32_t* args, JValue* result); +using JNIHandler = void(*)(Thread* self, + ArtMethod* method, + mirror::Object* receiver, + uint32_t* args, + JValue* result); static bool tables_initialized_ = false; static std::unordered_map<std::string, InvokeHandler> invoke_handlers_; diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc index 200fc5b334..38195b4911 100644 --- a/runtime/interpreter/unstarted_runtime_test.cc +++ b/runtime/interpreter/unstarted_runtime_test.cc @@ -261,7 +261,7 @@ TEST_F(UnstartedRuntimeTest, MemoryPeekShort) { UnstartedMemoryPeekShort(self, tmp.get(), &result, 0); - typedef int16_t unaligned_short __attribute__ ((aligned (1))); + using unaligned_short = int16_t __attribute__ ((aligned (1))); const unaligned_short* short_ptr = reinterpret_cast<const unaligned_short*>(base_ptr + i); EXPECT_EQ(result.GetS(), *short_ptr); } @@ -284,7 +284,7 @@ TEST_F(UnstartedRuntimeTest, MemoryPeekInt) { UnstartedMemoryPeekInt(self, tmp.get(), &result, 0); - typedef int32_t unaligned_int __attribute__ ((aligned (1))); + using unaligned_int = int32_t __attribute__ ((aligned (1))); const unaligned_int* int_ptr = reinterpret_cast<const unaligned_int*>(base_ptr + i); EXPECT_EQ(result.GetI(), *int_ptr); } @@ -307,7 +307,7 @@ TEST_F(UnstartedRuntimeTest, MemoryPeekLong) { UnstartedMemoryPeekLong(self, tmp.get(), &result, 0); - typedef int64_t unaligned_long __attribute__ ((aligned (1))); + using unaligned_long = int64_t __attribute__ ((aligned (1))); const unaligned_long* long_ptr = reinterpret_cast<const unaligned_long*>(base_ptr + i); EXPECT_EQ(result.GetJ(), *long_ptr); } diff --git a/runtime/jdwp/jdwp_adb.cc b/runtime/jdwp/jdwp_adb.cc index e6043c65de..9245f1e47f 100644 --- a/runtime/jdwp/jdwp_adb.cc +++ b/runtime/jdwp/jdwp_adb.cc @@ -346,7 +346,7 @@ bool JdwpAdbState::ProcessIncoming() { if (!HaveFullPacket()) { /* read some more, looping until we have data */ errno = 0; - while (1) { + while (true) { int selCount; fd_set readfds; int maxfd = -1; diff --git a/runtime/jdwp/jdwp_handler.cc b/runtime/jdwp/jdwp_handler.cc index 1e61ba0f2d..0a54e38698 100644 --- a/runtime/jdwp/jdwp_handler.cc +++ b/runtime/jdwp/jdwp_handler.cc @@ -1432,7 +1432,7 @@ static JdwpError DDM_Chunk(JdwpState* state, Request* request, ExpandBuf* pReply /* * Handler map decl. */ -typedef JdwpError (*JdwpRequestHandler)(JdwpState* state, Request* request, ExpandBuf* reply); +using JdwpRequestHandler = JdwpError(*)(JdwpState* state, Request* request, ExpandBuf* reply); struct JdwpHandlerMap { uint8_t cmdSet; diff --git a/runtime/jdwp/jdwp_socket.cc b/runtime/jdwp/jdwp_socket.cc index 29fa1603dd..b8b0e16fae 100644 --- a/runtime/jdwp/jdwp_socket.cc +++ b/runtime/jdwp/jdwp_socket.cc @@ -383,7 +383,7 @@ bool JdwpSocketState::ProcessIncoming() { if (!HaveFullPacket()) { /* read some more, looping until we have data */ errno = 0; - while (1) { + while (true) { int selCount; fd_set readfds; int maxfd = -1; diff --git a/runtime/jit/debugger_interface.cc b/runtime/jit/debugger_interface.cc index 63fb22cfce..6cd719a55c 100644 --- a/runtime/jit/debugger_interface.cc +++ b/runtime/jit/debugger_interface.cc @@ -77,11 +77,11 @@ namespace art { extern "C" { - typedef enum { + enum JITAction { JIT_NOACTION = 0, JIT_REGISTER_FN, JIT_UNREGISTER_FN - } JITAction; + }; struct JITCodeEntry { // Atomic to ensure the reader can always iterate over the linked list diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc index bcbdc3bece..191795be91 100644 --- a/runtime/jit/jit_code_cache.cc +++ b/runtime/jit/jit_code_cache.cc @@ -23,6 +23,7 @@ #include "base/enums.h" #include "base/histogram-inl.h" #include "base/logging.h" // For VLOG. +#include "base/membarrier.h" #include "base/mem_map.h" #include "base/quasi_atomic.h" #include "base/stl_util.h" @@ -187,6 +188,11 @@ JitCodeCache* JitCodeCache::Create(size_t initial_capacity, return nullptr; } + // Register for membarrier expedited sync core if JIT will be generating code. + if (!used_only_for_profile_data) { + art::membarrier(art::MembarrierCommand::kRegisterPrivateExpeditedSyncCore); + } + // Decide how we should map the code and data sections. // If we use the code cache just for profiling we do not need to map the code section as // executable. @@ -809,9 +815,8 @@ uint8_t* JitCodeCache::CommitCodeInternal(Thread* self, // shootdown (incidentally invalidating the CPU pipelines by sending an IPI to all cores to // notify them of the TLB invalidation). Some architectures, notably ARM and ARM64, have // hardware support that broadcasts TLB invalidations and so their kernels have no software - // based TLB shootdown. FlushInstructionPipeline() is a wrapper around the Linux - // membarrier(MEMBARRIER_CMD_PRIVATE_EXPEDITED) syscall which does the appropriate flushing. - FlushInstructionPipeline(); + // based TLB shootdown. + art::membarrier(art::MembarrierCommand::kPrivateExpeditedSyncCore); DCHECK(!Runtime::Current()->IsAotCompiler()); if (has_should_deoptimize_flag) { diff --git a/runtime/jni/java_vm_ext.cc b/runtime/jni/java_vm_ext.cc index 42406cf73c..6769368ee4 100644 --- a/runtime/jni/java_vm_ext.cc +++ b/runtime/jni/java_vm_ext.cc @@ -333,7 +333,7 @@ class Libraries { } ScopedThreadSuspension sts(self, kNative); // Do this without holding the jni libraries lock to prevent possible deadlocks. - typedef void (*JNI_OnUnloadFn)(JavaVM*, void*); + using JNI_OnUnloadFn = void(*)(JavaVM*, void*); for (auto library : unload_libraries) { void* const sym = library->FindSymbol("JNI_OnUnload", nullptr); if (sym == nullptr) { @@ -1026,7 +1026,7 @@ bool JavaVMExt::LoadNativeLibrary(JNIEnv* env, self->SetClassLoaderOverride(class_loader); VLOG(jni) << "[Calling JNI_OnLoad in \"" << path << "\"]"; - typedef int (*JNI_OnLoadFn)(JavaVM*, void*); + using JNI_OnLoadFn = int(*)(JavaVM*, void*); JNI_OnLoadFn jni_on_load = reinterpret_cast<JNI_OnLoadFn>(sym); int version = (*jni_on_load)(this, nullptr); diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h index 8bdd561ec4..a31a91443c 100644 --- a/runtime/mirror/array.h +++ b/runtime/mirror/array.h @@ -189,8 +189,9 @@ class PointerArray : public Array { T GetElementPtrSize(uint32_t idx, PointerSize ptr_size) REQUIRES_SHARED(Locks::mutator_lock_); + template<VerifyObjectFlags kVerifyFlags = kVerifyNone> void** ElementAddress(size_t index, PointerSize ptr_size) REQUIRES_SHARED(Locks::mutator_lock_) { - DCHECK_LT(index, static_cast<size_t>(GetLength())); + DCHECK_LT(index, static_cast<size_t>(GetLength<kVerifyFlags>())); return reinterpret_cast<void**>(reinterpret_cast<uint8_t*>(this) + Array::DataOffset(static_cast<size_t>(ptr_size)).Uint32Value() + static_cast<size_t>(ptr_size) * index); diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h index 33822d1b27..df70fab21f 100644 --- a/runtime/mirror/class-inl.h +++ b/runtime/mirror/class-inl.h @@ -251,18 +251,14 @@ inline void Class::SetMethodsPtrUnchecked(LengthPrefixedArray<ArtMethod>* new_me uint32_t num_direct, uint32_t num_virtual) { DCHECK_LE(num_direct + num_virtual, (new_methods == nullptr) ? 0 : new_methods->size()); - SetMethodsPtrInternal(new_methods); + SetField64<false>(OFFSET_OF_OBJECT_MEMBER(Class, methods_), + static_cast<uint64_t>(reinterpret_cast<uintptr_t>(new_methods))); SetFieldShort<false>(OFFSET_OF_OBJECT_MEMBER(Class, copied_methods_offset_), dchecked_integral_cast<uint16_t>(num_direct + num_virtual)); SetFieldShort<false>(OFFSET_OF_OBJECT_MEMBER(Class, virtual_methods_offset_), dchecked_integral_cast<uint16_t>(num_direct)); } -inline void Class::SetMethodsPtrInternal(LengthPrefixedArray<ArtMethod>* new_methods) { - SetField64<false>(OFFSET_OF_OBJECT_MEMBER(Class, methods_), - static_cast<uint64_t>(reinterpret_cast<uintptr_t>(new_methods))); -} - template<VerifyObjectFlags kVerifyFlags> inline ArtMethod* Class::GetVirtualMethod(size_t i, PointerSize pointer_size) { CheckPointerSize(pointer_size); @@ -1069,49 +1065,42 @@ inline uint32_t Class::NumStaticFields() { return arr != nullptr ? arr->size() : 0u; } -template <VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption, typename Visitor> +template <typename T, VerifyObjectFlags kVerifyFlags, typename Visitor> +inline void Class::FixupNativePointer( + Class* dest, PointerSize pointer_size, const Visitor& visitor, MemberOffset member_offset) { + void** address = + reinterpret_cast<void**>(reinterpret_cast<uintptr_t>(dest) + member_offset.Uint32Value()); + T old_value = GetFieldPtrWithSize<T, kVerifyFlags>(member_offset, pointer_size); + T new_value = visitor(old_value, address); + if (old_value != new_value) { + dest->SetFieldPtrWithSize</* kTransactionActive */ false, + /* kCheckTransaction */ true, + kVerifyNone>(member_offset, new_value, pointer_size); + } +} + +template <VerifyObjectFlags kVerifyFlags, typename Visitor> inline void Class::FixupNativePointers(Class* dest, PointerSize pointer_size, const Visitor& visitor) { - auto dest_address_fn = [dest](MemberOffset offset) { - return reinterpret_cast<void**>(reinterpret_cast<uintptr_t>(dest) + offset.Uint32Value()); - }; // Update the field arrays. - LengthPrefixedArray<ArtField>* const sfields = GetSFieldsPtr(); - void** sfields_dest_address = dest_address_fn(OFFSET_OF_OBJECT_MEMBER(Class, sfields_)); - LengthPrefixedArray<ArtField>* const new_sfields = visitor(sfields, sfields_dest_address); - if (sfields != new_sfields) { - dest->SetSFieldsPtrUnchecked(new_sfields); - } - LengthPrefixedArray<ArtField>* const ifields = GetIFieldsPtr(); - void** ifields_dest_address = dest_address_fn(OFFSET_OF_OBJECT_MEMBER(Class, ifields_)); - LengthPrefixedArray<ArtField>* const new_ifields = visitor(ifields, ifields_dest_address); - if (ifields != new_ifields) { - dest->SetIFieldsPtrUnchecked(new_ifields); - } + FixupNativePointer<LengthPrefixedArray<ArtField>*, kVerifyFlags>( + dest, pointer_size, visitor, OFFSET_OF_OBJECT_MEMBER(Class, sfields_)); + FixupNativePointer<LengthPrefixedArray<ArtField>*, kVerifyFlags>( + dest, pointer_size, visitor, OFFSET_OF_OBJECT_MEMBER(Class, ifields_)); // Update method array. - LengthPrefixedArray<ArtMethod>* methods = GetMethodsPtr(); - void** methods_dest_address = dest_address_fn(OFFSET_OF_OBJECT_MEMBER(Class, methods_)); - LengthPrefixedArray<ArtMethod>* new_methods = visitor(methods, methods_dest_address); - if (methods != new_methods) { - dest->SetMethodsPtrInternal(new_methods); - } + FixupNativePointer<LengthPrefixedArray<ArtMethod>*, kVerifyFlags>( + dest, pointer_size, visitor, OFFSET_OF_OBJECT_MEMBER(Class, methods_)); // Fix up embedded tables. if (!IsTemp<kVerifyNone>() && ShouldHaveEmbeddedVTable<kVerifyNone>()) { - for (int32_t i = 0, count = GetEmbeddedVTableLength(); i < count; ++i) { - ArtMethod* method = GetEmbeddedVTableEntry(i, pointer_size); - void** method_dest_addr = dest_address_fn(EmbeddedVTableEntryOffset(i, pointer_size)); - ArtMethod* new_method = visitor(method, method_dest_addr); - if (method != new_method) { - dest->SetEmbeddedVTableEntryUnchecked(i, new_method, pointer_size); - } + for (int32_t i = 0, count = GetEmbeddedVTableLength<kVerifyFlags>(); i < count; ++i) { + FixupNativePointer<ArtMethod*, kVerifyFlags>( + dest, pointer_size, visitor, EmbeddedVTableEntryOffset(i, pointer_size)); } } if (!IsTemp<kVerifyNone>() && ShouldHaveImt<kVerifyNone>()) { - ImTable* imt = GetImt(pointer_size); - void** imt_dest_addr = dest_address_fn(ImtPtrOffset(pointer_size)); - ImTable* new_imt = visitor(imt, imt_dest_addr); - dest->SetImt(new_imt, pointer_size); + FixupNativePointer<ImTable*, kVerifyFlags>( + dest, pointer_size, visitor, ImtPtrOffset(pointer_size)); } } diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index 3d434f1f7d..f640d3b27a 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -1263,14 +1263,14 @@ class MANAGED Class final : public Object { // the corresponding entry in dest if visitor(obj) != obj to prevent dirty memory. Dest should be // initialized to a copy of *this to prevent issues. Does not visit the ArtMethod and ArtField // roots. - template <VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, - ReadBarrierOption kReadBarrierOption = kWithReadBarrier, - typename Visitor> + template <VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, typename Visitor> void FixupNativePointers(Class* dest, PointerSize pointer_size, const Visitor& visitor) REQUIRES_SHARED(Locks::mutator_lock_); private: - ALWAYS_INLINE void SetMethodsPtrInternal(LengthPrefixedArray<ArtMethod>* new_methods) + template <typename T, VerifyObjectFlags kVerifyFlags, typename Visitor> + void FixupNativePointer( + Class* dest, PointerSize pointer_size, const Visitor& visitor, MemberOffset member_offset) REQUIRES_SHARED(Locks::mutator_lock_); ALWAYS_INLINE static ArraySlice<ArtMethod> GetMethodsSliceRangeUnchecked( diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h index ed0beafa08..22ccd20b4a 100644 --- a/runtime/mirror/dex_cache.h +++ b/runtime/mirror/dex_cache.h @@ -401,12 +401,14 @@ class MANAGED DexCache final : public Object { return GetField32<kVerifyFlags>(NumResolvedTypesOffset()); } + template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> size_t NumResolvedMethods() REQUIRES_SHARED(Locks::mutator_lock_) { - return GetField32(NumResolvedMethodsOffset()); + return GetField32<kVerifyFlags>(NumResolvedMethodsOffset()); } + template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> size_t NumResolvedFields() REQUIRES_SHARED(Locks::mutator_lock_) { - return GetField32(NumResolvedFieldsOffset()); + return GetField32<kVerifyFlags>(NumResolvedFieldsOffset()); } template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> diff --git a/runtime/mirror/iftable.h b/runtime/mirror/iftable.h index 9e3c9af86d..3d4c5a70ce 100644 --- a/runtime/mirror/iftable.h +++ b/runtime/mirror/iftable.h @@ -39,9 +39,15 @@ class MANAGED IfTable final : public ObjectArray<Object> { template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, ReadBarrierOption kReadBarrierOption = kWithReadBarrier> + PointerArray* GetMethodArrayOrNull(int32_t i) REQUIRES_SHARED(Locks::mutator_lock_) { + return down_cast<PointerArray*>( + Get<kVerifyFlags, kReadBarrierOption>((i * kMax) + kMethodArray)); + } + + template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, + ReadBarrierOption kReadBarrierOption = kWithReadBarrier> PointerArray* GetMethodArray(int32_t i) REQUIRES_SHARED(Locks::mutator_lock_) { - auto* method_array = down_cast<PointerArray*>(Get<kVerifyFlags, kReadBarrierOption>( - (i * kMax) + kMethodArray)); + PointerArray* method_array = GetMethodArrayOrNull<kVerifyFlags, kReadBarrierOption>(i); DCHECK(method_array != nullptr); return method_array; } @@ -49,9 +55,8 @@ class MANAGED IfTable final : public ObjectArray<Object> { template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, ReadBarrierOption kReadBarrierOption = kWithReadBarrier> size_t GetMethodArrayCount(int32_t i) REQUIRES_SHARED(Locks::mutator_lock_) { - auto* method_array = down_cast<PointerArray*>( - Get<kVerifyFlags, kReadBarrierOption>((i * kMax) + kMethodArray)); - return method_array == nullptr ? 0u : method_array->GetLength(); + PointerArray* method_array = GetMethodArrayOrNull<kVerifyFlags, kReadBarrierOption>(i); + return method_array == nullptr ? 0u : method_array->GetLength<kVerifyFlags>(); } void SetMethodArray(int32_t i, ObjPtr<PointerArray> arr) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/mirror/object_array-inl.h b/runtime/mirror/object_array-inl.h index 1d2f47f86a..7d101bf095 100644 --- a/runtime/mirror/object_array-inl.h +++ b/runtime/mirror/object_array-inl.h @@ -67,7 +67,7 @@ inline ObjPtr<ObjectArray<T>> ObjectArray<T>::Alloc(Thread* self, template<class T> template<VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption> inline T* ObjectArray<T>::Get(int32_t i) { - if (!CheckIsValidIndex(i)) { + if (!CheckIsValidIndex<kVerifyFlags>(i)) { DCHECK(Thread::Current()->IsExceptionPending()); return nullptr; } diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc index 0b615a6b9a..cf6543fa26 100644 --- a/runtime/mirror/object_test.cc +++ b/runtime/mirror/object_test.cc @@ -204,7 +204,7 @@ TEST_F(ObjectTest, AllocArray_FillUsable) { template<typename ArrayT> void TestPrimitiveArray(ClassLinker* cl) { ScopedObjectAccess soa(Thread::Current()); - typedef typename ArrayT::ElementType T; + using T = typename ArrayT::ElementType; StackHandleScope<2> hs(soa.Self()); Handle<ArrayT> a = hs.NewHandle(ArrayT::Alloc(soa.Self(), 2)); @@ -252,9 +252,9 @@ TEST_F(ObjectTest, PrimitiveArray_Short_Alloc) { } TEST_F(ObjectTest, PrimitiveArray_Double_Alloc) { - typedef DoubleArray ArrayT; + using ArrayT = DoubleArray; ScopedObjectAccess soa(Thread::Current()); - typedef typename ArrayT::ElementType T; + using T = typename ArrayT::ElementType; StackHandleScope<2> hs(soa.Self()); Handle<ArrayT> a = hs.NewHandle(ArrayT::Alloc(soa.Self(), 2)); @@ -283,9 +283,9 @@ TEST_F(ObjectTest, PrimitiveArray_Double_Alloc) { } TEST_F(ObjectTest, PrimitiveArray_Float_Alloc) { - typedef FloatArray ArrayT; + using ArrayT = FloatArray; ScopedObjectAccess soa(Thread::Current()); - typedef typename ArrayT::ElementType T; + using T = typename ArrayT::ElementType; StackHandleScope<2> hs(soa.Self()); Handle<ArrayT> a = hs.NewHandle(ArrayT::Alloc(soa.Self(), 2)); diff --git a/runtime/mirror/var_handle.cc b/runtime/mirror/var_handle.cc index 864e1eab73..ce794084d1 100644 --- a/runtime/mirror/var_handle.cc +++ b/runtime/mirror/var_handle.cc @@ -691,7 +691,7 @@ class TypeAdaptorAccessor : public Object::Accessor<T> { template <typename T> class FieldAccessViaAccessor { public: - typedef Object::Accessor<T> Accessor; + using Accessor = Object::Accessor<T>; // Apply an Accessor to get a field in an object. static void Get(ObjPtr<Object> obj, diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc index 0e619407e5..b18a048c60 100644 --- a/runtime/native/dalvik_system_VMRuntime.cc +++ b/runtime/native/dalvik_system_VMRuntime.cc @@ -325,7 +325,7 @@ static void VMRuntime_runHeapTasks(JNIEnv* env, jobject) { Runtime::Current()->GetHeap()->GetTaskProcessor()->RunAllTasks(ThreadForEnv(env)); } -typedef std::map<std::string, ObjPtr<mirror::String>> StringTable; +using StringTable = std::map<std::string, ObjPtr<mirror::String>>; class PreloadDexCachesStringsVisitor : public SingleRootVisitor { public: diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index 0579b6e39d..731e4a503a 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -410,7 +410,7 @@ inline static bool ReadOatDexFileData(const OatFile& oat_file, return false; } static_assert(std::is_trivial<T>::value, "T must be a trivial type"); - typedef __attribute__((__aligned__(1))) T unaligned_type; + using unaligned_type = __attribute__((__aligned__(1))) T; *value = *reinterpret_cast<const unaligned_type*>(*oat); *oat += sizeof(T); return true; diff --git a/runtime/transaction.cc b/runtime/transaction.cc index c9766bc9ca..1e5b2bbd4c 100644 --- a/runtime/transaction.cc +++ b/runtime/transaction.cc @@ -320,7 +320,7 @@ void Transaction::VisitRoots(RootVisitor* visitor) { void Transaction::VisitObjectLogs(RootVisitor* visitor) { // List of moving roots. - typedef std::pair<mirror::Object*, mirror::Object*> ObjectPair; + using ObjectPair = std::pair<mirror::Object*, mirror::Object*>; std::list<ObjectPair> moving_roots; // Visit roots. @@ -348,7 +348,7 @@ void Transaction::VisitObjectLogs(RootVisitor* visitor) { void Transaction::VisitArrayLogs(RootVisitor* visitor) { // List of moving roots. - typedef std::pair<mirror::Array*, mirror::Array*> ArrayPair; + using ArrayPair = std::pair<mirror::Array*, mirror::Array*>; std::list<ArrayPair> moving_roots; for (auto& it : array_logs_) { diff --git a/sigchainlib/sigchain_test.cc b/sigchainlib/sigchain_test.cc index 53e1e40454..bb997877a1 100644 --- a/sigchainlib/sigchain_test.cc +++ b/sigchainlib/sigchain_test.cc @@ -38,7 +38,7 @@ #include "sigchain.h" #if !defined(__BIONIC__) -typedef sigset_t sigset64_t; +using sigset64_t = sigset_t; static int sigemptyset64(sigset64_t* set) { return sigemptyset(set); diff --git a/simulator/code_simulator_container.cc b/simulator/code_simulator_container.cc index 3206bc7844..dc553dfe5d 100644 --- a/simulator/code_simulator_container.cc +++ b/simulator/code_simulator_container.cc @@ -34,13 +34,13 @@ CodeSimulatorContainer::CodeSimulatorContainer(InstructionSet target_isa) if (libart_simulator_handle_ == nullptr) { VLOG(simulator) << "Could not load " << libart_simulator_so_name << ": " << dlerror(); } else { - typedef CodeSimulator* (*create_code_simulator_ptr_)(InstructionSet target_isa); - create_code_simulator_ptr_ create_code_simulator_ = - reinterpret_cast<create_code_simulator_ptr_>( + using CreateCodeSimulatorPtr = CodeSimulator*(*)(InstructionSet); + CreateCodeSimulatorPtr create_code_simulator = + reinterpret_cast<CreateCodeSimulatorPtr>( dlsym(libart_simulator_handle_, "CreateCodeSimulator")); - DCHECK(create_code_simulator_ != nullptr) << "Fail to find symbol of CreateCodeSimulator: " + DCHECK(create_code_simulator != nullptr) << "Fail to find symbol of CreateCodeSimulator: " << dlerror(); - simulator_ = create_code_simulator_(target_isa); + simulator_ = create_code_simulator(target_isa); } } diff --git a/test/004-JniTest/jni_test.cc b/test/004-JniTest/jni_test.cc index 33a8f5bba2..d82c526ee3 100644 --- a/test/004-JniTest/jni_test.cc +++ b/test/004-JniTest/jni_test.cc @@ -62,7 +62,7 @@ static void* AttachHelper(void* arg) { int attach_result = jvm->AttachCurrentThread(&env, &args); CHECK_EQ(attach_result, 0); - typedef void (*Fn)(JNIEnv*); + using Fn = void(*)(JNIEnv*); Fn fn = reinterpret_cast<Fn>(arg); fn(env); diff --git a/test/089-many-methods/check b/test/089-many-methods/check index 1f71e8e0a0..e09a291fea 100755 --- a/test/089-many-methods/check +++ b/test/089-many-methods/check @@ -14,5 +14,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -grep Error "$2" > "$2.tmp" -diff --strip-trailing-cr -q "$1" "$2.tmp" >/dev/null +EXPECTED_ERROR="Cannot fit requested classes in a single dex" +if ! grep -q "$EXPECTED_ERROR" "$2"; then + exit 1 +else + exit 0 +fi diff --git a/test/089-many-methods/expected.txt b/test/089-many-methods/expected.txt index bb6ba3c7bc..b75bde462c 100644 --- a/test/089-many-methods/expected.txt +++ b/test/089-many-methods/expected.txt @@ -1 +1 @@ -Error: Cannot fit requested classes in a single dex file (# fields: 131000 > 65536) +See the 'check' script for the expectation! diff --git a/test/115-native-bridge/nativebridge.cc b/test/115-native-bridge/nativebridge.cc index a74f7638bd..cc7e806ba5 100644 --- a/test/115-native-bridge/nativebridge.cc +++ b/test/115-native-bridge/nativebridge.cc @@ -45,7 +45,7 @@ static const android::NativeBridgeRuntimeCallbacks* gNativeBridgeArtCallbacks; static jint trampoline_JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env = nullptr; - typedef jint (*FnPtr_t)(JavaVM*, void*); + using FnPtr_t = jint(*)(JavaVM*, void*); FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>(find_native_bridge_method("JNI_OnLoad")->fnPtr); vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6); @@ -91,9 +91,8 @@ static jint trampoline_JNI_OnLoad(JavaVM* vm, void* reserved) { return fnPtr(vm, reserved); } -static void trampoline_Java_Main_testFindClassOnAttachedNativeThread(JNIEnv* env, - jclass klass) { - typedef void (*FnPtr_t)(JNIEnv*, jclass); +static void trampoline_Java_Main_testFindClassOnAttachedNativeThread(JNIEnv* env, jclass klass) { + using FnPtr_t = void(*)(JNIEnv*, jclass); FnPtr_t fnPtr = reinterpret_cast<FnPtr_t> (find_native_bridge_method("testFindClassOnAttachedNativeThread")->fnPtr); printf("%s called!\n", __FUNCTION__); @@ -102,7 +101,7 @@ static void trampoline_Java_Main_testFindClassOnAttachedNativeThread(JNIEnv* env static void trampoline_Java_Main_testFindFieldOnAttachedNativeThreadNative(JNIEnv* env, jclass klass) { - typedef void (*FnPtr_t)(JNIEnv*, jclass); + using FnPtr_t = void(*)(JNIEnv*, jclass); FnPtr_t fnPtr = reinterpret_cast<FnPtr_t> (find_native_bridge_method("testFindFieldOnAttachedNativeThreadNative")->fnPtr); printf("%s called!\n", __FUNCTION__); @@ -111,7 +110,7 @@ static void trampoline_Java_Main_testFindFieldOnAttachedNativeThreadNative(JNIEn static void trampoline_Java_Main_testCallStaticVoidMethodOnSubClassNative(JNIEnv* env, jclass klass) { - typedef void (*FnPtr_t)(JNIEnv*, jclass); + using FnPtr_t = void(*)(JNIEnv*, jclass); FnPtr_t fnPtr = reinterpret_cast<FnPtr_t> (find_native_bridge_method("testCallStaticVoidMethodOnSubClassNative")->fnPtr); printf("%s called!\n", __FUNCTION__); @@ -119,7 +118,7 @@ static void trampoline_Java_Main_testCallStaticVoidMethodOnSubClassNative(JNIEnv } static jobject trampoline_Java_Main_testGetMirandaMethodNative(JNIEnv* env, jclass klass) { - typedef jobject (*FnPtr_t)(JNIEnv*, jclass); + using FnPtr_t = jobject(*)(JNIEnv*, jclass); FnPtr_t fnPtr = reinterpret_cast<FnPtr_t> (find_native_bridge_method("testGetMirandaMethodNative")->fnPtr); printf("%s called!\n", __FUNCTION__); @@ -127,7 +126,7 @@ static jobject trampoline_Java_Main_testGetMirandaMethodNative(JNIEnv* env, jcla } static void trampoline_Java_Main_testNewStringObject(JNIEnv* env, jclass klass) { - typedef void (*FnPtr_t)(JNIEnv*, jclass); + using FnPtr_t = void(*)(JNIEnv*, jclass); FnPtr_t fnPtr = reinterpret_cast<FnPtr_t> (find_native_bridge_method("testNewStringObject")->fnPtr); printf("%s called!\n", __FUNCTION__); @@ -135,7 +134,7 @@ static void trampoline_Java_Main_testNewStringObject(JNIEnv* env, jclass klass) } static void trampoline_Java_Main_testZeroLengthByteBuffers(JNIEnv* env, jclass klass) { - typedef void (*FnPtr_t)(JNIEnv*, jclass); + using FnPtr_t = void(*)(JNIEnv*, jclass); FnPtr_t fnPtr = reinterpret_cast<FnPtr_t> (find_native_bridge_method("testZeroLengthByteBuffers")->fnPtr); printf("%s called!\n", __FUNCTION__); @@ -145,8 +144,8 @@ static void trampoline_Java_Main_testZeroLengthByteBuffers(JNIEnv* env, jclass k static jbyte trampoline_Java_Main_byteMethod(JNIEnv* env, jclass klass, jbyte b1, jbyte b2, jbyte b3, jbyte b4, jbyte b5, jbyte b6, jbyte b7, jbyte b8, jbyte b9, jbyte b10) { - typedef jbyte (*FnPtr_t)(JNIEnv*, jclass, jbyte, jbyte, jbyte, jbyte, jbyte, - jbyte, jbyte, jbyte, jbyte, jbyte); + using FnPtr_t = jbyte(*)(JNIEnv*, jclass, jbyte, jbyte, jbyte, jbyte, jbyte, jbyte, jbyte, jbyte, + jbyte, jbyte); FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>(find_native_bridge_method("byteMethod")->fnPtr); printf("%s called!\n", __FUNCTION__); return fnPtr(env, klass, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10); @@ -155,8 +154,8 @@ static jbyte trampoline_Java_Main_byteMethod(JNIEnv* env, jclass klass, jbyte b1 static jshort trampoline_Java_Main_shortMethod(JNIEnv* env, jclass klass, jshort s1, jshort s2, jshort s3, jshort s4, jshort s5, jshort s6, jshort s7, jshort s8, jshort s9, jshort s10) { - typedef jshort (*FnPtr_t)(JNIEnv*, jclass, jshort, jshort, jshort, jshort, jshort, - jshort, jshort, jshort, jshort, jshort); + using FnPtr_t = jshort(*)(JNIEnv*, jclass, jshort, jshort, jshort, jshort, jshort, jshort, jshort, + jshort, jshort, jshort); FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>(find_native_bridge_method("shortMethod")->fnPtr); printf("%s called!\n", __FUNCTION__); return fnPtr(env, klass, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10); @@ -166,7 +165,7 @@ static jboolean trampoline_Java_Main_booleanMethod(JNIEnv* env, jclass klass, jb jboolean b2, jboolean b3, jboolean b4, jboolean b5, jboolean b6, jboolean b7, jboolean b8, jboolean b9, jboolean b10) { - typedef jboolean (*FnPtr_t)(JNIEnv*, jclass, jboolean, jboolean, jboolean, jboolean, jboolean, + using FnPtr_t = jboolean(*)(JNIEnv*, jclass, jboolean, jboolean, jboolean, jboolean, jboolean, jboolean, jboolean, jboolean, jboolean, jboolean); FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>(find_native_bridge_method("booleanMethod")->fnPtr); printf("%s called!\n", __FUNCTION__); @@ -176,8 +175,8 @@ static jboolean trampoline_Java_Main_booleanMethod(JNIEnv* env, jclass klass, jb static jchar trampoline_Java_Main_charMethod(JNIEnv* env, jclass klass, jchar c1, jchar c2, jchar c3, jchar c4, jchar c5, jchar c6, jchar c7, jchar c8, jchar c9, jchar c10) { - typedef jchar (*FnPtr_t)(JNIEnv*, jclass, jchar, jchar, jchar, jchar, jchar, - jchar, jchar, jchar, jchar, jchar); + using FnPtr_t = jchar(*)(JNIEnv*, jclass, jchar, jchar, jchar, jchar, jchar, jchar, jchar, jchar, + jchar, jchar); FnPtr_t fnPtr = reinterpret_cast<FnPtr_t>(find_native_bridge_method("charMethod")->fnPtr); printf("%s called!\n", __FUNCTION__); return fnPtr(env, klass, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10); diff --git a/test/1900-track-alloc/alloc.cc b/test/1900-track-alloc/alloc.cc index db5617c54c..f2096111da 100644 --- a/test/1900-track-alloc/alloc.cc +++ b/test/1900-track-alloc/alloc.cc @@ -24,7 +24,7 @@ namespace art { namespace Test1900TrackAlloc { -typedef jvmtiError (*GetGlobalState)(jvmtiEnv* env, jlong* allocated); +using GetGlobalState = jvmtiError(*)(jvmtiEnv* env, jlong* allocated); struct AllocTrackingData { GetGlobalState get_global_state; diff --git a/test/1940-ddms-ext/ddm_ext.cc b/test/1940-ddms-ext/ddm_ext.cc index cc29df9a49..452187bdcb 100644 --- a/test/1940-ddms-ext/ddm_ext.cc +++ b/test/1940-ddms-ext/ddm_ext.cc @@ -25,7 +25,7 @@ namespace art { namespace Test1940DdmExt { -typedef jvmtiError (*DdmHandleChunk)(jvmtiEnv* env, +using DdmHandleChunk = jvmtiError(*)(jvmtiEnv* env, jint type_in, jint len_in, const jbyte* data_in, diff --git a/test/1946-list-descriptors/descriptors.cc b/test/1946-list-descriptors/descriptors.cc index 01b306dea5..07fee6141b 100644 --- a/test/1946-list-descriptors/descriptors.cc +++ b/test/1946-list-descriptors/descriptors.cc @@ -24,7 +24,7 @@ namespace art { namespace Test1946Descriptors { -typedef jvmtiError (*GetDescriptorList)(jvmtiEnv* env, jobject loader, jint* cnt, char*** descs); +using GetDescriptorList = jvmtiError(*)(jvmtiEnv* env, jobject loader, jint* cnt, char*** descs); struct DescriptorData { GetDescriptorList get_descriptor_list; diff --git a/test/1951-monitor-enter-no-suspend/raw_monitor.cc b/test/1951-monitor-enter-no-suspend/raw_monitor.cc index 0425e350fd..efd02b6ae4 100644 --- a/test/1951-monitor-enter-no-suspend/raw_monitor.cc +++ b/test/1951-monitor-enter-no-suspend/raw_monitor.cc @@ -26,7 +26,7 @@ namespace art { namespace Test1951MonitorEnterNoSuspend { -typedef jvmtiError (*RawMonitorEnterNoSuspend)(jvmtiEnv* env, jrawMonitorID mon); +using RawMonitorEnterNoSuspend = jvmtiError(*)(jvmtiEnv* env, jrawMonitorID mon); template <typename T> static void Dealloc(T* t) { diff --git a/test/478-checker-clinit-check-pruning/src/Main.java b/test/478-checker-clinit-check-pruning/src/Main.java index e16fa69c1c..b1bc51e89d 100644 --- a/test/478-checker-clinit-check-pruning/src/Main.java +++ b/test/478-checker-clinit-check-pruning/src/Main.java @@ -26,7 +26,7 @@ public class Main { /// CHECK-START: void Main.invokeStaticInlined() builder (after) /// CHECK-DAG: <<LoadClass:l\d+>> LoadClass gen_clinit_check:false /// CHECK-DAG: <<ClinitCheck:l\d+>> ClinitCheck [<<LoadClass>>] - /// CHECK-DAG: InvokeStaticOrDirect [{{[ij]\d+}},<<ClinitCheck>>] + /// CHECK-DAG: InvokeStaticOrDirect [{{([ij]\d+,)?}}<<ClinitCheck>>] /// CHECK-START: void Main.invokeStaticInlined() inliner (after) /// CHECK-DAG: <<LoadClass:l\d+>> LoadClass gen_clinit_check:false @@ -69,7 +69,7 @@ public class Main { /// CHECK-START: void Main.invokeStaticNotInlined() builder (after) /// CHECK: <<LoadClass:l\d+>> LoadClass gen_clinit_check:false /// CHECK: <<ClinitCheck:l\d+>> ClinitCheck [<<LoadClass>>] - /// CHECK: InvokeStaticOrDirect [{{[ij]\d+}},<<ClinitCheck>>] + /// CHECK: InvokeStaticOrDirect [{{([ij]\d+,)?}}<<ClinitCheck>>] /// CHECK-START: void Main.invokeStaticNotInlined() inliner (after) /// CHECK: <<LoadClass:l\d+>> LoadClass gen_clinit_check:false diff --git a/test/552-checker-sharpening/src/Main.java b/test/552-checker-sharpening/src/Main.java index 746887ff1a..0bceffd685 100644 --- a/test/552-checker-sharpening/src/Main.java +++ b/test/552-checker-sharpening/src/Main.java @@ -41,10 +41,7 @@ public class Main { return x; } - /// CHECK-START: int Main.testSimple(int) sharpening (before) - /// CHECK: InvokeStaticOrDirect method_load_kind:RuntimeCall - - /// CHECK-START-{ARM,ARM64,MIPS,MIPS64,X86,X86_64}: int Main.testSimple(int) sharpening (after) + /// CHECK-START-{ARM,ARM64,MIPS,MIPS64,X86,X86_64}: int Main.testSimple(int) builder (after) /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry /// CHECK-START-X86: int Main.testSimple(int) pc_relative_fixups_x86 (before) @@ -59,11 +56,7 @@ public class Main { return $noinline$foo(x); } - /// CHECK-START: int Main.testDiamond(boolean, int) sharpening (before) - /// CHECK: InvokeStaticOrDirect method_load_kind:RuntimeCall - /// CHECK: InvokeStaticOrDirect method_load_kind:RuntimeCall - - /// CHECK-START-{ARM,ARM64,MIPS,MIPS64,X86,X86_64}: int Main.testDiamond(boolean, int) sharpening (after) + /// CHECK-START-{ARM,ARM64,MIPS,MIPS64,X86,X86_64}: int Main.testDiamond(boolean, int) builder (after) /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry @@ -194,18 +187,12 @@ public class Main { } /// CHECK-START-{ARM,ARM64,MIPS,MIPS64,X86,X86_64}: java.lang.String Main.$noinline$toHexString(int) builder (after) - /// CHECK: InvokeStaticOrDirect method_load_kind:RuntimeCall - - /// CHECK-START-{ARM,ARM64,MIPS,MIPS64,X86,X86_64}: java.lang.String Main.$noinline$toHexString(int) sharpening (after) /// CHECK: InvokeStaticOrDirect method_load_kind:BootImageRelRo public static String $noinline$toHexString(int value) { return Integer.toString(value, 16); } /// CHECK-START-{ARM,ARM64,MIPS,MIPS64,X86,X86_64}: java.lang.String Main.$noinline$toHexStringIndirect(int) builder (after) - /// CHECK: InvokeStaticOrDirect method_load_kind:RuntimeCall - - /// CHECK-START-{ARM,ARM64,MIPS,MIPS64,X86,X86_64}: java.lang.String Main.$noinline$toHexStringIndirect(int) sharpening (after) /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry /// CHECK-START-X86: java.lang.String Main.$noinline$toHexStringIndirect(int) pc_relative_fixups_x86 (before) diff --git a/test/565-checker-rotate/smali/Main2.smali b/test/565-checker-rotate/smali/Main2.smali index ca5027e971..98eaf11b1d 100644 --- a/test/565-checker-rotate/smali/Main2.smali +++ b/test/565-checker-rotate/smali/Main2.smali @@ -16,13 +16,12 @@ .super Ljava/lang/Object; ## CHECK-START: int Main2.rotateLeftBoolean(boolean, int) intrinsics_recognition (after) -## CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod ## CHECK: <<ArgVal:z\d+>> ParameterValue ## CHECK: <<ArgDist:i\d+>> ParameterValue ## CHECK-DAG: <<Zero:i\d+>> IntConstant 0 ## CHECK-DAG: <<One:i\d+>> IntConstant 1 ## CHECK-DAG: <<Val:i\d+>> Phi [<<One>>,<<Zero>>] -## CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<Val>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft +## CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<Val>>,<<ArgDist>>{{(,[ij]\d+)?}}] intrinsic:IntegerRotateLeft ## CHECK-DAG: Return [<<Result>>] ## CHECK-START: int Main2.rotateLeftBoolean(boolean, int) instruction_simplifier (after) @@ -92,14 +91,13 @@ .end method ## CHECK-START: int Main2.rotateRightBoolean(boolean, int) intrinsics_recognition (after) -## CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod ## CHECK: <<ArgVal:z\d+>> ParameterValue ## CHECK: <<ArgDist:i\d+>> ParameterValue ## CHECK-DAG: <<Zero:i\d+>> IntConstant 0 ## CHECK-DAG: <<One:i\d+>> IntConstant 1 ## CHECK-DAG: <<Val:i\d+>> Phi [<<One>>,<<Zero>>] -## CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<Val>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight -## CHECK-DAG: Return [<<Result>>] +## CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<Val>>,<<ArgDist>>{{(,[ij]\d+)?}}] intrinsic:IntegerRotateRight +## CHECK-DAG: Return [<<Result>>] ## CHECK-START: int Main2.rotateRightBoolean(boolean, int) instruction_simplifier (after) ## CHECK: <<ArgVal:z\d+>> ParameterValue diff --git a/test/565-checker-rotate/src-art/Main.java b/test/565-checker-rotate/src-art/Main.java index b9e1315bd4..f6f281bdfd 100644 --- a/test/565-checker-rotate/src-art/Main.java +++ b/test/565-checker-rotate/src-art/Main.java @@ -21,10 +21,9 @@ public class Main { private static Class main2; /// CHECK-START: int Main.rotateLeftByte(byte, int) intrinsics_recognition (after) - /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod /// CHECK: <<ArgVal:b\d+>> ParameterValue /// CHECK: <<ArgDist:i\d+>> ParameterValue - /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft + /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>{{(,[ij]\d+)?}}] intrinsic:IntegerRotateLeft /// CHECK-DAG: Return [<<Result>>] /// CHECK-START: int Main.rotateLeftByte(byte, int) instruction_simplifier (after) @@ -42,10 +41,9 @@ public class Main { } /// CHECK-START: int Main.rotateLeftShort(short, int) intrinsics_recognition (after) - /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod /// CHECK: <<ArgVal:s\d+>> ParameterValue /// CHECK: <<ArgDist:i\d+>> ParameterValue - /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft + /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>{{(,[ij]\d+)?}}] intrinsic:IntegerRotateLeft /// CHECK-DAG: Return [<<Result>>] /// CHECK-START: int Main.rotateLeftShort(short, int) instruction_simplifier (after) @@ -63,10 +61,9 @@ public class Main { } /// CHECK-START: int Main.rotateLeftChar(char, int) intrinsics_recognition (after) - /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod /// CHECK: <<ArgVal:c\d+>> ParameterValue /// CHECK: <<ArgDist:i\d+>> ParameterValue - /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft + /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>{{(,[ij]\d+)?}}] intrinsic:IntegerRotateLeft /// CHECK-DAG: Return [<<Result>>] /// CHECK-START: int Main.rotateLeftChar(char, int) instruction_simplifier (after) @@ -84,10 +81,9 @@ public class Main { } /// CHECK-START: int Main.rotateLeftInt(int, int) intrinsics_recognition (after) - /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod /// CHECK: <<ArgVal:i\d+>> ParameterValue /// CHECK: <<ArgDist:i\d+>> ParameterValue - /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft + /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>{{(,[ij]\d+)?}}] intrinsic:IntegerRotateLeft /// CHECK-DAG: Return [<<Result>>] /// CHECK-START: int Main.rotateLeftInt(int, int) instruction_simplifier (after) @@ -105,10 +101,9 @@ public class Main { } /// CHECK-START: long Main.rotateLeftLong(long, int) intrinsics_recognition (after) - /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod /// CHECK: <<ArgVal:j\d+>> ParameterValue /// CHECK: <<ArgDist:i\d+>> ParameterValue - /// CHECK-DAG: <<Result:j\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:LongRotateLeft + /// CHECK-DAG: <<Result:j\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>{{(,[ij]\d+)?}}] intrinsic:LongRotateLeft /// CHECK-DAG: Return [<<Result>>] /// CHECK-START: long Main.rotateLeftLong(long, int) instruction_simplifier (after) @@ -126,10 +121,9 @@ public class Main { } /// CHECK-START: int Main.rotateRightByte(byte, int) intrinsics_recognition (after) - /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod /// CHECK: <<ArgVal:b\d+>> ParameterValue /// CHECK: <<ArgDist:i\d+>> ParameterValue - /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight + /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>{{(,[ij]\d+)?}}] intrinsic:IntegerRotateRight /// CHECK-DAG: Return [<<Result>>] /// CHECK-START: int Main.rotateRightByte(byte, int) instruction_simplifier (after) @@ -146,10 +140,9 @@ public class Main { } /// CHECK-START: int Main.rotateRightShort(short, int) intrinsics_recognition (after) - /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod /// CHECK: <<ArgVal:s\d+>> ParameterValue /// CHECK: <<ArgDist:i\d+>> ParameterValue - /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight + /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>{{(,[ij]\d+)?}}] intrinsic:IntegerRotateRight /// CHECK-DAG: Return [<<Result>>] /// CHECK-START: int Main.rotateRightShort(short, int) instruction_simplifier (after) @@ -166,10 +159,9 @@ public class Main { } /// CHECK-START: int Main.rotateRightChar(char, int) intrinsics_recognition (after) - /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod /// CHECK: <<ArgVal:c\d+>> ParameterValue /// CHECK: <<ArgDist:i\d+>> ParameterValue - /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight + /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>{{(,[ij]\d+)?}}] intrinsic:IntegerRotateRight /// CHECK-DAG: Return [<<Result>>] /// CHECK-START: int Main.rotateRightChar(char, int) instruction_simplifier (after) @@ -186,10 +178,9 @@ public class Main { } /// CHECK-START: int Main.rotateRightInt(int, int) intrinsics_recognition (after) - /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod /// CHECK: <<ArgVal:i\d+>> ParameterValue /// CHECK: <<ArgDist:i\d+>> ParameterValue - /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight + /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>{{(,[ij]\d+)?}}] intrinsic:IntegerRotateRight /// CHECK-DAG: Return [<<Result>>] /// CHECK-START: int Main.rotateRightInt(int, int) instruction_simplifier (after) @@ -206,10 +197,9 @@ public class Main { } /// CHECK-START: long Main.rotateRightLong(long, int) intrinsics_recognition (after) - /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod /// CHECK: <<ArgVal:j\d+>> ParameterValue /// CHECK: <<ArgDist:i\d+>> ParameterValue - /// CHECK-DAG: <<Result:j\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:LongRotateRight + /// CHECK-DAG: <<Result:j\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>{{(,[ij]\d+)?}}] intrinsic:LongRotateRight /// CHECK-DAG: Return [<<Result>>] /// CHECK-START: long Main.rotateRightLong(long, int) instruction_simplifier (after) @@ -227,10 +217,9 @@ public class Main { /// CHECK-START: int Main.rotateLeftIntWithByteDistance(int, byte) intrinsics_recognition (after) - /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod /// CHECK: <<ArgVal:i\d+>> ParameterValue /// CHECK: <<ArgDist:b\d+>> ParameterValue - /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateLeft + /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>{{(,[ij]\d+)?}}] intrinsic:IntegerRotateLeft /// CHECK-DAG: Return [<<Result>>] /// CHECK-START: int Main.rotateLeftIntWithByteDistance(int, byte) instruction_simplifier (after) @@ -248,10 +237,9 @@ public class Main { } /// CHECK-START: int Main.rotateRightIntWithByteDistance(int, byte) intrinsics_recognition (after) - /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod /// CHECK: <<ArgVal:i\d+>> ParameterValue /// CHECK: <<ArgDist:b\d+>> ParameterValue - /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>,<<Method>>] intrinsic:IntegerRotateRight + /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<ArgVal>>,<<ArgDist>>{{(,[ij]\d+)?}}] intrinsic:IntegerRotateRight /// CHECK-DAG: Return [<<Result>>] /// CHECK-START: int Main.rotateRightIntWithByteDistance(int, byte) instruction_simplifier (after) diff --git a/test/566-checker-signum/smali/Main2.smali b/test/566-checker-signum/smali/Main2.smali index d99ad8662b..ec63cf850e 100644 --- a/test/566-checker-signum/smali/Main2.smali +++ b/test/566-checker-signum/smali/Main2.smali @@ -16,11 +16,10 @@ .super Ljava/lang/Object; ## CHECK-START: int Main2.signBoolean(boolean) intrinsics_recognition (after) -## CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod ## CHECK-DAG: <<Zero:i\d+>> IntConstant 0 ## CHECK-DAG: <<One:i\d+>> IntConstant 1 ## CHECK-DAG: <<Phi:i\d+>> Phi [<<One>>,<<Zero>>] -## CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<Phi>>,<<Method>>] intrinsic:IntegerSignum +## CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<Phi>>{{(,[ij]\d+)?}}] intrinsic:IntegerSignum ## CHECK-DAG: Return [<<Result>>] ## CHECK-START: int Main2.signBoolean(boolean) instruction_simplifier (after) diff --git a/test/567-checker-compare/smali/Smali.smali b/test/567-checker-compare/smali/Smali.smali index 8fc39f1acd..94b1f13482 100644 --- a/test/567-checker-compare/smali/Smali.smali +++ b/test/567-checker-compare/smali/Smali.smali @@ -16,12 +16,11 @@ .super Ljava/lang/Object; ## CHECK-START: int Smali.compareBooleans(boolean, boolean) intrinsics_recognition (after) -## CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod ## CHECK-DAG: <<Zero:i\d+>> IntConstant 0 ## CHECK-DAG: <<One:i\d+>> IntConstant 1 ## CHECK-DAG: <<PhiX:i\d+>> Phi [<<One>>,<<Zero>>] ## CHECK-DAG: <<PhiY:i\d+>> Phi [<<One>>,<<Zero>>] -## CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<PhiX>>,<<PhiY>>,<<Method>>] intrinsic:IntegerCompare +## CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect [<<PhiX>>,<<PhiY>>{{(,[ij]\d+)?}}] intrinsic:IntegerCompare ## CHECK-DAG: Return [<<Result>>] ## CHECK-START: int Smali.compareBooleans(boolean, boolean) instruction_simplifier (after) diff --git a/test/567-checker-compare/src/Main.java b/test/567-checker-compare/src/Main.java index abfaf9f146..f43ac300f7 100644 --- a/test/567-checker-compare/src/Main.java +++ b/test/567-checker-compare/src/Main.java @@ -22,9 +22,8 @@ public class Main { /// CHECK-START: void Main.$opt$noinline$testReplaceInputWithItself(int) intrinsics_recognition (after) /// CHECK-DAG: <<ArgX:i\d+>> ParameterValue - /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod /// CHECK-DAG: <<Zero:i\d+>> IntConstant 0 - /// CHECK-DAG: <<Cmp:i\d+>> InvokeStaticOrDirect [<<ArgX>>,<<Zero>>,<<Method>>] intrinsic:IntegerCompare + /// CHECK-DAG: <<Cmp:i\d+>> InvokeStaticOrDirect [<<ArgX>>,<<Zero>>{{(,[ij]\d+)?}}] intrinsic:IntegerCompare /// CHECK-DAG: GreaterThanOrEqual [<<Cmp>>,<<Zero>>] /// CHECK-START: void Main.$opt$noinline$testReplaceInputWithItself(int) instruction_simplifier (after) diff --git a/test/593-checker-boolean-2-integral-conv/smali/SmaliTests.smali b/test/593-checker-boolean-2-integral-conv/smali/SmaliTests.smali index f74e88f580..bd90fe7db5 100644 --- a/test/593-checker-boolean-2-integral-conv/smali/SmaliTests.smali +++ b/test/593-checker-boolean-2-integral-conv/smali/SmaliTests.smali @@ -210,14 +210,12 @@ .end method ## CHECK-START: int SmaliTests.longToIntOfBoolean() builder (after) -## CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod ## CHECK-DAG: <<Sget:z\d+>> StaticFieldGet -## CHECK-DAG: <<ZToJ:j\d+>> InvokeStaticOrDirect [<<Sget>>,<<Method>>] +## CHECK-DAG: <<ZToJ:j\d+>> InvokeStaticOrDirect [<<Sget>>{{(,[ij]\d+)?}}] ## CHECK-DAG: <<JToI:i\d+>> TypeConversion [<<ZToJ>>] ## CHECK-DAG: Return [<<JToI>>] ## CHECK-START: int SmaliTests.longToIntOfBoolean() inliner (after) -## CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod ## CHECK-DAG: <<Zero:i\d+>> IntConstant 0 ## CHECK-DAG: <<One:i\d+>> IntConstant 1 ## CHECK-DAG: <<Sget:z\d+>> StaticFieldGet @@ -228,7 +226,6 @@ ## CHECK-DAG: Return [<<JToI>>] ## CHECK-START: int SmaliTests.longToIntOfBoolean() select_generator (after) -## CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod ## CHECK-DAG: <<Zero:i\d+>> IntConstant 0 ## CHECK-DAG: <<One:i\d+>> IntConstant 1 ## CHECK-DAG: <<Sget:z\d+>> StaticFieldGet @@ -236,7 +233,6 @@ ## CHECK-DAG: Return [<<Sel>>] ## CHECK-START: int SmaliTests.longToIntOfBoolean() instruction_simplifier$after_bce (after) -## CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod ## CHECK-DAG: <<Sget:z\d+>> StaticFieldGet ## CHECK-DAG: Return [<<Sget>>] .method public static longToIntOfBoolean()I diff --git a/test/593-checker-boolean-2-integral-conv/src/Main.java b/test/593-checker-boolean-2-integral-conv/src/Main.java index fdc0919f2b..b085c42cab 100644 --- a/test/593-checker-boolean-2-integral-conv/src/Main.java +++ b/test/593-checker-boolean-2-integral-conv/src/Main.java @@ -100,14 +100,12 @@ public class Main { } /// CHECK-START: int Main.longToIntOfBoolean() builder (after) - /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod /// CHECK-DAG: <<Sget:z\d+>> StaticFieldGet - /// CHECK-DAG: <<ZToJ:j\d+>> InvokeStaticOrDirect [<<Sget>>,<<Method>>] + /// CHECK-DAG: <<ZToJ:j\d+>> InvokeStaticOrDirect [<<Sget>>{{(,[ij]\d+)?}}] /// CHECK-DAG: <<JToI:i\d+>> TypeConversion [<<ZToJ>>] /// CHECK-DAG: Return [<<JToI>>] /// CHECK-START: int Main.longToIntOfBoolean() inliner (after) - /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod /// CHECK-DAG: <<Zero:j\d+>> LongConstant 0 /// CHECK-DAG: <<One:j\d+>> LongConstant 1 /// CHECK-DAG: <<Sget:z\d+>> StaticFieldGet @@ -123,7 +121,6 @@ public class Main { /// CHECK-NOT: Phi /// CHECK-START: int Main.longToIntOfBoolean() select_generator (after) - /// CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod /// CHECK-DAG: <<Zero:j\d+>> LongConstant 0 /// CHECK-DAG: <<One:j\d+>> LongConstant 1 /// CHECK-DAG: <<Sget:z\d+>> StaticFieldGet @@ -135,7 +132,6 @@ public class Main { // TODO: Re-enable checks below after simplifier is updated to handle this pattern: b/63064517 // CHECK-START: int Main.longToIntOfBoolean() instruction_simplifier$after_bce (after) - // CHECK-DAG: <<Method:[ij]\d+>> CurrentMethod // CHECK-DAG: <<Sget:z\d+>> StaticFieldGet // CHECK-DAG: Return [<<Sget>>] diff --git a/test/602-deoptimizeable/src/Main.java b/test/602-deoptimizeable/src/Main.java index d995923f88..3d45b861c9 100644 --- a/test/602-deoptimizeable/src/Main.java +++ b/test/602-deoptimizeable/src/Main.java @@ -126,6 +126,9 @@ public class Main { assertIsManaged(); map.put(new DummyObject(10), Long.valueOf(100)); assertIsInterpreted(); // Every deoptimizeable method is deoptimized. + if (map.get(new DummyObject(10)) == null) { + System.out.println("Expected map to contain DummyObject(10)"); + } } catch (Exception e) { e.printStackTrace(System.out); } diff --git a/tools/ti-fast/README.md b/tools/ti-fast/README.md index bc468826ec..a0a7dd7c35 100644 --- a/tools/ti-fast/README.md +++ b/tools/ti-fast/README.md @@ -21,6 +21,10 @@ following format: called. This behavior is static. The no-log methods have no branches and just immediately return. +* If 'all' is one of the arguments all events the current runtime is capable of + providing will be listened for and all other arguments (excepting 'log') will + be ignored. + * The event-names are the same names as are used in the jvmtiEventCallbacks struct. diff --git a/tools/ti-fast/tifast.cc b/tools/ti-fast/tifast.cc index b147addfd5..85c433b10f 100644 --- a/tools/ti-fast/tifast.cc +++ b/tools/ti-fast/tifast.cc @@ -36,6 +36,13 @@ namespace { // env. static constexpr jint kArtTiVersion = JVMTI_VERSION_1_2 | 0x40000000; +template <typename ...Args> static void Unused(Args... args ATTRIBUTE_UNUSED) {} + +// jthread is a typedef of jobject so we use this to allow the templates to distinguish them. +struct jthreadContainer { jthread thread; }; +// jlocation is a typedef of jlong so use this to distinguish the less common jlong. +struct jlongContainer { jlong val; }; + static void AddCapsForEvent(jvmtiEvent event, jvmtiCapabilities* caps) { switch (event) { #define DO_CASE(name, cap_name) \ @@ -63,59 +70,520 @@ static void AddCapsForEvent(jvmtiEvent event, jvmtiCapabilities* caps) { } // Setup for all supported events. Give a macro with fun(name, event_num, args) +#define FOR_ALL_SUPPORTED_JNI_EVENTS(fun) \ + fun(SingleStep, EVENT(SINGLE_STEP), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jmethodID meth, jlocation loc), (jvmti, jni, jthreadContainer{.thread = thread}, meth, loc)) \ + fun(MethodEntry, EVENT(METHOD_ENTRY), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jmethodID meth), (jvmti, jni, jthreadContainer{.thread = thread}, meth)) \ + fun(MethodExit, EVENT(METHOD_EXIT), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jmethodID meth, jboolean jb, jvalue jv), (jvmti, jni, jthreadContainer{.thread = thread}, meth, jb, jv)) \ + fun(NativeMethodBind, EVENT(NATIVE_METHOD_BIND), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jmethodID meth, void* v1, void** v2), (jvmti, jni, jthreadContainer{.thread = thread}, meth, v1, v2)) \ + fun(Exception, EVENT(EXCEPTION), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jmethodID meth1, jlocation loc1, jobject obj, jmethodID meth2, jlocation loc2), (jvmti, jni, jthreadContainer{.thread = thread}, meth1, loc1, obj, meth2, loc2)) \ + fun(ExceptionCatch, EVENT(EXCEPTION_CATCH), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jmethodID meth, jlocation loc, jobject obj), (jvmti, jni, jthreadContainer{.thread = thread}, meth, loc, obj)) \ + fun(ThreadStart, EVENT(THREAD_START), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread), (jvmti, jni, jthreadContainer{.thread = thread})) \ + fun(ThreadEnd, EVENT(THREAD_END), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread), (jvmti, jni, jthreadContainer{.thread = thread})) \ + fun(ClassLoad, EVENT(CLASS_LOAD), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jclass klass), (jvmti, jni, jthreadContainer{.thread = thread}, klass) ) \ + fun(ClassPrepare, EVENT(CLASS_PREPARE), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jclass klass), (jvmti, jni, jthreadContainer{.thread = thread}, klass)) \ + fun(ClassFileLoadHook, EVENT(CLASS_FILE_LOAD_HOOK), (jvmtiEnv* jvmti, JNIEnv* jni, jclass klass, jobject obj1, const char* c1, jobject obj2, jint i1, const unsigned char* c2, jint* ip1, unsigned char** cp1), (jvmti, jni, klass, obj1, c1, obj2, i1, c2, ip1, cp1)) \ + fun(MonitorContendedEnter, EVENT(MONITOR_CONTENDED_ENTER), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jobject obj), (jvmti, jni, jthreadContainer{.thread = thread}, obj)) \ + fun(MonitorContendedEntered, EVENT(MONITOR_CONTENDED_ENTERED), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jobject obj), (jvmti, jni, jthreadContainer{.thread = thread}, obj)) \ + fun(MonitorWait, EVENT(MONITOR_WAIT), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jobject obj, jlong l1), (jvmti, jni, jthreadContainer{.thread = thread}, obj, jlongContainer{.val = l1})) \ + fun(MonitorWaited, EVENT(MONITOR_WAITED), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jobject obj, jboolean b1), (jvmti, jni, jthreadContainer{.thread = thread}, obj, b1)) \ + fun(ResourceExhausted, EVENT(RESOURCE_EXHAUSTED), (jvmtiEnv* jvmti, JNIEnv* jni, jint i1, const void* cv, const char* cc), (jvmti, jni, i1, cv, cc)) \ + fun(VMObjectAlloc, EVENT(VM_OBJECT_ALLOC), (jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jobject obj, jclass klass, jlong l1), (jvmti, jni, jthreadContainer{.thread = thread}, obj, klass, jlongContainer{.val = l1})) \ + +#define FOR_ALL_SUPPORTED_NO_JNI_EVENTS(fun) \ + fun(CompiledMethodLoad, EVENT(COMPILED_METHOD_LOAD), (jvmtiEnv* jvmti, jmethodID meth, jint i1, const void* cv1, jint i2, const jvmtiAddrLocationMap* alm, const void* cv2), (jvmti, meth, i1, cv1, i2, alm, cv2)) \ + fun(CompiledMethodUnload, EVENT(COMPILED_METHOD_UNLOAD), (jvmtiEnv* jvmti, jmethodID meth, const void* cv1), (jvmti, meth, cv1)) \ + fun(DynamicCodeGenerated, EVENT(DYNAMIC_CODE_GENERATED), (jvmtiEnv* jvmti, const char* cc, const void* cv, jint i1), (jvmti, cc, cv, i1)) \ + fun(DataDumpRequest, EVENT(DATA_DUMP_REQUEST), (jvmtiEnv* jvmti), (jvmti)) \ + fun(GarbageCollectionStart, EVENT(GARBAGE_COLLECTION_START), (jvmtiEnv* jvmti), (jvmti)) \ + fun(GarbageCollectionFinish, EVENT(GARBAGE_COLLECTION_FINISH), (jvmtiEnv* jvmti), (jvmti)) + #define FOR_ALL_SUPPORTED_EVENTS(fun) \ - fun(SingleStep, EVENT(SINGLE_STEP), (jvmtiEnv*, JNIEnv*, jthread, jmethodID, jlocation)) \ - fun(MethodEntry, EVENT(METHOD_ENTRY), (jvmtiEnv*, JNIEnv*, jthread, jmethodID)) \ - fun(MethodExit, EVENT(METHOD_EXIT), (jvmtiEnv*, JNIEnv*, jthread, jmethodID, jboolean, jvalue)) \ - fun(NativeMethodBind, EVENT(NATIVE_METHOD_BIND), (jvmtiEnv*, JNIEnv*, jthread, jmethodID, void*, void**)) \ - fun(Exception, EVENT(EXCEPTION), (jvmtiEnv*, JNIEnv*, jthread, jmethodID, jlocation, jobject, jmethodID, jlocation)) \ - fun(ExceptionCatch, EVENT(EXCEPTION_CATCH), (jvmtiEnv*, JNIEnv*, jthread, jmethodID, jlocation, jobject)) \ - fun(ThreadStart, EVENT(THREAD_START), (jvmtiEnv*, JNIEnv*, jthread)) \ - fun(ThreadEnd, EVENT(THREAD_END), (jvmtiEnv*, JNIEnv*, jthread)) \ - fun(ClassLoad, EVENT(CLASS_LOAD), (jvmtiEnv*, JNIEnv*, jthread, jclass)) \ - fun(ClassPrepare, EVENT(CLASS_PREPARE), (jvmtiEnv*, JNIEnv*, jthread, jclass)) \ - fun(ClassFileLoadHook, EVENT(CLASS_FILE_LOAD_HOOK), (jvmtiEnv*, JNIEnv*, jclass, jobject, const char*, jobject, jint, const unsigned char*, jint*, unsigned char**)) \ - fun(CompiledMethodLoad, EVENT(COMPILED_METHOD_LOAD), (jvmtiEnv*, jmethodID, jint, const void*, jint, const jvmtiAddrLocationMap*, const void*)) \ - fun(CompiledMethodUnload, EVENT(COMPILED_METHOD_UNLOAD), (jvmtiEnv*, jmethodID, const void*)) \ - fun(DynamicCodeGenerated, EVENT(DYNAMIC_CODE_GENERATED), (jvmtiEnv*, const char*, const void*, jint)) \ - fun(DataDumpRequest, EVENT(DATA_DUMP_REQUEST), (jvmtiEnv*)) \ - fun(MonitorContendedEnter, EVENT(MONITOR_CONTENDED_ENTER), (jvmtiEnv*, JNIEnv*, jthread, jobject)) \ - fun(MonitorContendedEntered, EVENT(MONITOR_CONTENDED_ENTERED), (jvmtiEnv*, JNIEnv*, jthread, jobject)) \ - fun(MonitorWait, EVENT(MONITOR_WAIT), (jvmtiEnv*, JNIEnv*, jthread, jobject, jlong)) \ - fun(MonitorWaited, EVENT(MONITOR_WAITED), (jvmtiEnv*, JNIEnv*, jthread, jobject, jboolean)) \ - fun(ResourceExhausted, EVENT(RESOURCE_EXHAUSTED), (jvmtiEnv*, JNIEnv*, jint, const void*, const char*)) \ - fun(VMObjectAlloc, EVENT(VM_OBJECT_ALLOC), (jvmtiEnv*, JNIEnv*, jthread, jobject, jclass, jlong)) \ - fun(GarbageCollectionStart, EVENT(GARBAGE_COLLECTION_START), (jvmtiEnv*)) \ - fun(GarbageCollectionFinish, EVENT(GARBAGE_COLLECTION_FINISH), (jvmtiEnv*)) - -#define GENERATE_EMPTY_FUNCTION(name, number, args) \ - static void JNICALL empty ## name args { } + FOR_ALL_SUPPORTED_JNI_EVENTS(fun) \ + FOR_ALL_SUPPORTED_NO_JNI_EVENTS(fun) + +static const jvmtiEvent kAllEvents[] = { +#define GET_EVENT(a, event, b, c) event, +FOR_ALL_SUPPORTED_EVENTS(GET_EVENT) +#undef GET_EVENT +}; + +#define GENERATE_EMPTY_FUNCTION(name, number, args, argnames) \ + static void JNICALL empty ## name args { Unused argnames ; } FOR_ALL_SUPPORTED_EVENTS(GENERATE_EMPTY_FUNCTION) #undef GENERATE_EMPTY_FUNCTION static jvmtiEventCallbacks kEmptyCallbacks { -#define CREATE_EMPTY_EVENT_CALLBACKS(name, num, args) \ +#define CREATE_EMPTY_EVENT_CALLBACKS(name, num, args, argnames) \ .name = empty ## name, FOR_ALL_SUPPORTED_EVENTS(CREATE_EMPTY_EVENT_CALLBACKS) #undef CREATE_EMPTY_EVENT_CALLBACKS }; -#define GENERATE_LOG_FUNCTION(name, number, args) \ - static void JNICALL log ## name args { \ - LOG(INFO) << "Got event " << #name ; \ +static void DeleteLocalRef(JNIEnv* env, jobject obj) { + if (obj != nullptr && env != nullptr) { + env->DeleteLocalRef(obj); + } +} + +class ScopedThreadInfo { + public: + ScopedThreadInfo(jvmtiEnv* jvmtienv, JNIEnv* env, jthread thread) + : jvmtienv_(jvmtienv), env_(env), free_name_(false) { + if (thread == nullptr) { + info_.name = const_cast<char*>("<NULLPTR>"); + } else if (jvmtienv->GetThreadInfo(thread, &info_) != JVMTI_ERROR_NONE) { + info_.name = const_cast<char*>("<UNKNOWN THREAD>"); + } else { + free_name_ = true; + } + } + + ~ScopedThreadInfo() { + if (free_name_) { + jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(info_.name)); + } + DeleteLocalRef(env_, info_.thread_group); + DeleteLocalRef(env_, info_.context_class_loader); + } + + const char* GetName() const { + return info_.name; + } + + private: + jvmtiEnv* jvmtienv_; + JNIEnv* env_; + bool free_name_; + jvmtiThreadInfo info_{}; +}; + +class ScopedClassInfo { + public: + ScopedClassInfo(jvmtiEnv* jvmtienv, jclass c) : jvmtienv_(jvmtienv), class_(c) {} + + ~ScopedClassInfo() { + if (class_ != nullptr) { + jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_)); + jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(generic_)); + jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(file_)); + jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(debug_ext_)); + } + } + + bool Init(bool get_generic = true) { + if (class_ == nullptr) { + name_ = const_cast<char*>("<NONE>"); + generic_ = const_cast<char*>("<NONE>"); + return true; + } else { + jvmtiError ret1 = jvmtienv_->GetSourceFileName(class_, &file_); + jvmtiError ret2 = jvmtienv_->GetSourceDebugExtension(class_, &debug_ext_); + char** gen_ptr = &generic_; + if (!get_generic) { + generic_ = nullptr; + gen_ptr = nullptr; + } + return jvmtienv_->GetClassSignature(class_, &name_, gen_ptr) == JVMTI_ERROR_NONE && + ret1 != JVMTI_ERROR_MUST_POSSESS_CAPABILITY && + ret1 != JVMTI_ERROR_INVALID_CLASS && + ret2 != JVMTI_ERROR_MUST_POSSESS_CAPABILITY && + ret2 != JVMTI_ERROR_INVALID_CLASS; + } + } + + jclass GetClass() const { + return class_; + } + + const char* GetName() const { + return name_; + } + + const char* GetGeneric() const { + return generic_; + } + + const char* GetSourceDebugExtension() const { + if (debug_ext_ == nullptr) { + return "<UNKNOWN_SOURCE_DEBUG_EXTENSION>"; + } else { + return debug_ext_; + } + } + const char* GetSourceFileName() const { + if (file_ == nullptr) { + return "<UNKNOWN_FILE>"; + } else { + return file_; } -FOR_ALL_SUPPORTED_EVENTS(GENERATE_LOG_FUNCTION) + } + + private: + jvmtiEnv* jvmtienv_; + jclass class_; + char* name_ = nullptr; + char* generic_ = nullptr; + char* file_ = nullptr; + char* debug_ext_ = nullptr; + + friend std::ostream& operator<<(std::ostream &os, ScopedClassInfo const& m); +}; + +class ScopedMethodInfo { + public: + ScopedMethodInfo(jvmtiEnv* jvmtienv, JNIEnv* env, jmethodID m) + : jvmtienv_(jvmtienv), env_(env), method_(m) {} + + ~ScopedMethodInfo() { + DeleteLocalRef(env_, declaring_class_); + jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_)); + jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(signature_)); + jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(generic_)); + } + + bool Init(bool get_generic = true) { + if (jvmtienv_->GetMethodDeclaringClass(method_, &declaring_class_) != JVMTI_ERROR_NONE) { + return false; + } + class_info_.reset(new ScopedClassInfo(jvmtienv_, declaring_class_)); + jint nlines; + jvmtiLineNumberEntry* lines; + jvmtiError err = jvmtienv_->GetLineNumberTable(method_, &nlines, &lines); + if (err == JVMTI_ERROR_NONE) { + if (nlines > 0) { + first_line_ = lines[0].line_number; + } + jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(lines)); + } else if (err != JVMTI_ERROR_ABSENT_INFORMATION && + err != JVMTI_ERROR_NATIVE_METHOD) { + return false; + } + return class_info_->Init(get_generic) && + (jvmtienv_->GetMethodName(method_, &name_, &signature_, &generic_) == JVMTI_ERROR_NONE); + } + + const ScopedClassInfo& GetDeclaringClassInfo() const { + return *class_info_; + } + + jclass GetDeclaringClass() const { + return declaring_class_; + } + + const char* GetName() const { + return name_; + } + + const char* GetSignature() const { + return signature_; + } + + const char* GetGeneric() const { + return generic_; + } + + jint GetFirstLine() const { + return first_line_; + } + + private: + jvmtiEnv* jvmtienv_; + JNIEnv* env_; + jmethodID method_; + jclass declaring_class_ = nullptr; + std::unique_ptr<ScopedClassInfo> class_info_; + char* name_ = nullptr; + char* signature_ = nullptr; + char* generic_ = nullptr; + jint first_line_ = -1; + + friend std::ostream& operator<<(std::ostream &os, ScopedMethodInfo const& m); +}; + +std::ostream& operator<<(std::ostream &os, ScopedClassInfo const& c) { + const char* generic = c.GetGeneric(); + if (generic != nullptr) { + return os << c.GetName() << "<" << generic << ">" << " file: " << c.GetSourceFileName(); + } else { + return os << c.GetName() << " file: " << c.GetSourceFileName(); + } +} + +std::ostream& operator<<(std::ostream &os, ScopedMethodInfo const& m) { + return os << m.GetDeclaringClassInfo().GetName() << "->" << m.GetName() << m.GetSignature() + << " (source: " << m.GetDeclaringClassInfo().GetSourceFileName() << ":" + << m.GetFirstLine() << ")"; +} + + +class LogPrinter { + public: + explicit LogPrinter(jvmtiEvent event) : event_(event) {} + + template <typename ...Args> void PrintRestNoJNI(jvmtiEnv* jvmti, Args... args) { + PrintRest(jvmti, static_cast<JNIEnv*>(nullptr), args...); + } + + template <typename ...Args> void PrintRest(jvmtiEnv* jvmti, JNIEnv* env, Args... args); + template <typename ...Args> void PrintRest(jvmtiEnv* jvmti, + JNIEnv* env, + jlongContainer l, + Args... args); + template <typename ...Args> void PrintRest(jvmtiEnv* jvmti, + JNIEnv* env, + jthreadContainer thr, + Args... args); + template <typename ...Args> void PrintRest(jvmtiEnv* jvmti, + JNIEnv* env, + jboolean i, + Args... args); + template <typename ...Args> void PrintRest(jvmtiEnv* jvmti, + JNIEnv* env, + jint i, + Args... args); + template <typename ...Args> void PrintRest(jvmtiEnv* jvmti, + JNIEnv* env, + jclass klass, + Args... args); + template <typename ...Args> void PrintRest(jvmtiEnv* jvmti, + JNIEnv* env, + jmethodID meth, + Args... args); + template <typename ...Args> void PrintRest(jvmtiEnv* jvmti, + JNIEnv* env, + jlocation loc, + Args... args); + template <typename ...Args> void PrintRest(jvmtiEnv* jvmti, + JNIEnv* env, + jint* ip, + Args... args); + template <typename ...Args> void PrintRest(jvmtiEnv* jvmti, + JNIEnv* env, + const void* loc, + Args... args); + template <typename ...Args> void PrintRest(jvmtiEnv* jvmti, + JNIEnv* env, + void* loc, + Args... args); + template <typename ...Args> void PrintRest(jvmtiEnv* jvmti, + JNIEnv* env, + void** loc, + Args... args); + template <typename ...Args> void PrintRest(jvmtiEnv* jvmti, + JNIEnv* env, + unsigned char** v, + Args... args); + template <typename ...Args> void PrintRest(jvmtiEnv* jvmti, + JNIEnv* env, + const unsigned char* v, + Args... args); + template <typename ...Args> void PrintRest(jvmtiEnv* jvmti, + JNIEnv* env, + const char* v, + Args... args); + template <typename ...Args> void PrintRest(jvmtiEnv* jvmti, + JNIEnv* env, + const jvmtiAddrLocationMap* v, + Args... args); + template <typename ...Args> void PrintRest(jvmtiEnv* jvmti, + JNIEnv* env, + jvalue v, + Args... args); + template <typename ...Args> void PrintRest(jvmtiEnv* jvmti, + JNIEnv* env, + jobject v, + Args... args); + + std::string GetResult() { + std::string out_str = stream.str(); + return start_args + out_str; + } + + private: + jvmtiEvent event_; + std::string start_args; + std::ostringstream stream; +}; + +// Base case +template<> void LogPrinter::PrintRest(jvmtiEnv* jvmti ATTRIBUTE_UNUSED, JNIEnv* jni) { + if (jni == nullptr) { + start_args = "jvmtiEnv*"; + } else { + start_args = "jvmtiEnv*, JNIEnv*"; + } +} + +template<typename ...Args> +void LogPrinter::PrintRest(jvmtiEnv* jvmti, + JNIEnv* jni, + const jvmtiAddrLocationMap* v, + Args... args) { + if (v != nullptr) { + stream << ", const jvmtiAddrLocationMap*[start_address: " + << v->start_address << ", location: " << v->location << "]"; + } else { + stream << ", const jvmtiAddrLocationMap*[nullptr]"; + } + PrintRest(jvmti, jni, args...); +} + +template<typename ...Args> +void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jint* v, Args... args) { + stream << ", jint*[" << static_cast<const void*>(v) << "]"; + PrintRest(jvmti, jni, args...); +} + +template<typename ...Args> +void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, const void* v, Args... args) { + stream << ", const void*[" << v << "]"; + PrintRest(jvmti, jni, args...); +} + +template<typename ...Args> +void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, unsigned char** v, Args... args) { + stream << ", unsigned char**[" << static_cast<const void*>(v) << "]"; + PrintRest(jvmti, jni, args...); +} + +template<typename ...Args> +void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, const unsigned char* v, Args... args) { + stream << ", const unsigned char*[" << static_cast<const void*>(v) << "]"; + PrintRest(jvmti, jni, args...); +} + +template<typename ...Args> +void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, const char* v, Args... args) { + stream << ", const char*[" << v << "]"; + PrintRest(jvmti, jni, args...); +} + +template<typename ...Args> +void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jvalue v ATTRIBUTE_UNUSED, Args... args) { + stream << ", jvalue[<UNION>]"; + PrintRest(jvmti, jni, args...); +} + +template<typename ...Args> +void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, void** v, Args... args) { + stream << ", void**[" << v << "]"; + PrintRest(jvmti, jni, args...); +} + +template<typename ...Args> +void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, void* v, Args... args) { + stream << ", void*[" << v << "]"; + PrintRest(jvmti, jni, args...); +} + +template<typename ...Args> +void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jlongContainer l, Args... args) { + stream << ", jlong[" << l.val << ", hex: 0x" << std::hex << l.val << "]"; + PrintRest(jvmti, jni, args...); +} + +template<typename ...Args> +void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jlocation l, Args... args) { + stream << ", jlocation[" << l << ", hex: 0x" << std::hex << l << "]"; + PrintRest(jvmti, jni, args...); +} + +template<typename ...Args> +void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jboolean b, Args... args) { + stream << ", jboolean[" << (b ? "true" : "false") << "]"; + PrintRest(jvmti, jni, args...); +} + +template<typename ...Args> +void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jint i, Args... args) { + stream << ", jint[" << i << ", hex: 0x" << std::hex << i << "]"; + PrintRest(jvmti, jni, args...); +} + +template<typename ...Args> +void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jobject obj, Args... args) { + if (obj == nullptr) { + stream << ", jobject[nullptr]"; + } else { + jni->PushLocalFrame(1); + jclass klass = jni->GetObjectClass(obj); + ScopedClassInfo sci(jvmti, klass); + if (sci.Init(event_ != JVMTI_EVENT_VM_OBJECT_ALLOC)) { + stream << ", jobject[type: " << sci << "]"; + } else { + stream << ", jobject[type: TYPE UNKNOWN]"; + } + jni->PopLocalFrame(nullptr); + } + PrintRest(jvmti, jni, args...); +} + +template<typename ...Args> +void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jthreadContainer thr, Args... args) { + ScopedThreadInfo sti(jvmti, jni, thr.thread); + stream << ", jthread[" << sti.GetName() << "]"; + PrintRest(jvmti, jni, args...); +} + +template<typename ...Args> +void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass, Args... args) { + ScopedClassInfo sci(jvmti, klass); + if (sci.Init(/*get_generic*/event_ != JVMTI_EVENT_VM_OBJECT_ALLOC)) { + stream << ", jclass[" << sci << "]"; + } else { + stream << ", jclass[TYPE UNKNOWN]"; + } + PrintRest(jvmti, jni, args...); +} + +template<typename ...Args> +void LogPrinter::PrintRest(jvmtiEnv* jvmti, JNIEnv* jni, jmethodID meth, Args... args) { + ScopedMethodInfo smi(jvmti, jni, meth); + if (smi.Init()) { + stream << ", jmethodID[" << smi << "]"; + } else { + stream << ", jmethodID[METHOD UNKNOWN]"; + } + PrintRest(jvmti, jni, args...); +} + +#define GENERATE_LOG_FUNCTION_JNI(name, event, args, argnames) \ + static void JNICALL log ## name args { \ + LogPrinter printer(event); \ + printer.PrintRest argnames; \ + LOG(INFO) << "Got event " << #name << "(" << printer.GetResult() << ")"; \ + } \ + +#define GENERATE_LOG_FUNCTION_NO_JNI(name, event, args, argnames) \ + static void JNICALL log ## name args { \ + LogPrinter printer(event); \ + printer.PrintRestNoJNI argnames; \ + LOG(INFO) << "Got event " << #name << "(" << printer.GetResult() << ")"; \ + } \ + +FOR_ALL_SUPPORTED_JNI_EVENTS(GENERATE_LOG_FUNCTION_JNI) +FOR_ALL_SUPPORTED_NO_JNI_EVENTS(GENERATE_LOG_FUNCTION_NO_JNI) #undef GENERATE_LOG_FUNCTION static jvmtiEventCallbacks kLogCallbacks { -#define CREATE_LOG_EVENT_CALLBACK(name, num, args) \ +#define CREATE_LOG_EVENT_CALLBACK(name, num, args, argnames) \ .name = log ## name, FOR_ALL_SUPPORTED_EVENTS(CREATE_LOG_EVENT_CALLBACK) #undef CREATE_LOG_EVENT_CALLBACK }; +static std::string EventToName(jvmtiEvent desired_event) { +#define CHECK_NAME(name, event, args, argnames) \ + if (desired_event == event) { \ + return #name; \ + } + FOR_ALL_SUPPORTED_EVENTS(CHECK_NAME); + LOG(FATAL) << "Unknown event " << desired_event; + __builtin_unreachable(); +#undef CHECK_NAME +} static jvmtiEvent NameToEvent(const std::string& desired_name) { -#define CHECK_NAME(name, event, args) \ +#define CHECK_NAME(name, event, args, argnames) \ if (desired_name == #name) { \ return event; \ } @@ -125,14 +593,46 @@ static jvmtiEvent NameToEvent(const std::string& desired_name) { #undef CHECK_NAME } +#undef FOR_ALL_SUPPORTED_JNI_EVENTS +#undef FOR_ALL_SUPPORTED_NO_JNI_EVENTS #undef FOR_ALL_SUPPORTED_EVENTS -static std::vector<jvmtiEvent> GetRequestedEventList(const std::string& args) { + +static std::vector<jvmtiEvent> GetAllAvailableEvents(jvmtiEnv* jvmti) { + std::vector<jvmtiEvent> out; + jvmtiCapabilities caps{}; + jvmti->GetPotentialCapabilities(&caps); + uint8_t caps_bytes[sizeof(caps)]; + memcpy(caps_bytes, &caps, sizeof(caps)); + for (jvmtiEvent e : kAllEvents) { + jvmtiCapabilities req{}; + AddCapsForEvent(e, &req); + uint8_t req_bytes[sizeof(req)]; + memcpy(req_bytes, &req, sizeof(req)); + bool good = true; + for (size_t i = 0; i < sizeof(caps); i++) { + if ((req_bytes[i] & caps_bytes[i]) != req_bytes[i]) { + good = false; + break; + } + } + if (good) { + out.push_back(e); + } else { + LOG(WARNING) << "Unable to get capabilities for event " << EventToName(e); + } + } + return out; +} + +static std::vector<jvmtiEvent> GetRequestedEventList(jvmtiEnv* jvmti, const std::string& args) { std::vector<jvmtiEvent> res; std::stringstream args_stream(args); std::string item; while (std::getline(args_stream, item, ',')) { if (item == "") { continue; + } else if (item == "all") { + return GetAllAvailableEvents(jvmti); } res.push_back(NameToEvent(item)); } @@ -168,12 +668,17 @@ static jint AgentStart(JavaVM* vm, args = args.substr(3); } - std::vector<jvmtiEvent> events = GetRequestedEventList(args); + std::vector<jvmtiEvent> events = GetRequestedEventList(jvmti, args); jvmtiCapabilities caps{}; for (jvmtiEvent e : events) { AddCapsForEvent(e, &caps); } + if (is_log) { + caps.can_get_line_numbers = 1; + caps.can_get_source_file_name = 1; + caps.can_get_source_debug_extension = 1; + } error = jvmti->AddCapabilities(&caps); if (error != JVMTI_ERROR_NONE) { LOG(ERROR) << "Unable to set caps"; diff --git a/tools/veridex/appcompat.sh b/tools/veridex/appcompat.sh index 9a24d82c9b..a24e84f616 100755 --- a/tools/veridex/appcompat.sh +++ b/tools/veridex/appcompat.sh @@ -55,7 +55,9 @@ else OUT=${OUT_DIR} fi -PACKAGING=${OUT}/target/common/obj/PACKAGING +if [[ -z "${PACKAGING}" ]]; then + PACKAGING=${OUT}/target/common/obj/PACKAGING +fi if [ -z "$ANDROID_HOST_OUT" ] ; then ANDROID_HOST_OUT=${OUT}/host/linux-x86 diff --git a/tools/veridex/veridex.cc b/tools/veridex/veridex.cc index cf1167fe9c..7206c7d1e3 100644 --- a/tools/veridex/veridex.cc +++ b/tools/veridex/veridex.cc @@ -65,6 +65,16 @@ VeriMethod VeriClass::getClass_ = nullptr; VeriMethod VeriClass::loadClass_ = nullptr; VeriField VeriClass::sdkInt_ = nullptr; +static const char* kDexFileOption = "--dex-file="; +static const char* kStubsOption = "--core-stubs="; +static const char* kWhitelistOption = "--whitelist="; +static const char* kBlacklistOption = "--blacklist="; +static const char* kDarkGreylistOption = "--dark-greylist="; +static const char* kLightGreylistOption = "--light-greylist="; +static const char* kImprecise = "--imprecise"; +static const char* kTargetSdkVersion = "--target-sdk-version="; +static const char* kOnlyReportSdkUses = "--only-report-sdk-uses"; + struct VeridexOptions { const char* dex_file = nullptr; const char* core_stubs = nullptr; @@ -90,16 +100,6 @@ static void ParseArgs(VeridexOptions* options, int argc, char** argv) { argv++; argc--; - static const char* kDexFileOption = "--dex-file="; - static const char* kStubsOption = "--core-stubs="; - static const char* kWhitelistOption = "--whitelist="; - static const char* kBlacklistOption = "--blacklist="; - static const char* kDarkGreylistOption = "--dark-greylist="; - static const char* kLightGreylistOption = "--light-greylist="; - static const char* kImprecise = "--imprecise"; - static const char* kTargetSdkVersion = "--target-sdk-version="; - static const char* kOnlyReportSdkUses = "--only-report-sdk-uses"; - for (int i = 0; i < argc; ++i) { if (StartsWith(argv[i], kDexFileOption)) { options->dex_file = Substr(argv[i], strlen(kDexFileOption)); @@ -138,6 +138,12 @@ class Veridex { static int Run(int argc, char** argv) { VeridexOptions options; ParseArgs(&options, argc, argv); + + if (!options.dex_file) { + LOG(ERROR) << "Required argument '" << kDexFileOption << "' not provided."; + return 1; + } + gTargetSdkVersion = options.target_sdk_version; std::vector<std::string> boot_content; @@ -229,6 +235,9 @@ class Veridex { options.blacklist = nullptr; options.dark_greylist = nullptr; options.light_greylist = nullptr; + } else { + // Otherwise, omit SDK uses. + options.whitelist = nullptr; } // Find and log uses of hidden APIs. @@ -335,4 +344,3 @@ class Veridex { int main(int argc, char** argv) { return art::Veridex::Run(argc, argv); } - |