diff options
327 files changed, 3220 insertions, 2765 deletions
diff --git a/cmdline/cmdline.h b/cmdline/cmdline.h index 60dfdce03b..95ab12324c 100644 --- a/cmdline/cmdline.h +++ b/cmdline/cmdline.h @@ -28,6 +28,7 @@ #include "base/file_utils.h" #include "base/logging.h" +#include "base/mutex.h" #include "base/stringpiece.h" #include "noop_compiler_callbacks.h" #include "runtime.h" @@ -303,6 +304,7 @@ struct CmdlineArgs { template <typename Args = CmdlineArgs> struct CmdlineMain { int Main(int argc, char** argv) { + Locks::Init(); InitLogging(argv, Runtime::Abort); std::unique_ptr<Args> args = std::unique_ptr<Args>(CreateArguments()); args_ = args.get(); diff --git a/cmdline/cmdline_parser_test.cc b/cmdline/cmdline_parser_test.cc index 3cb9731a17..235a2aa90e 100644 --- a/cmdline/cmdline_parser_test.cc +++ b/cmdline/cmdline_parser_test.cc @@ -20,12 +20,13 @@ #include "gtest/gtest.h" +#include "base/mutex.h" +#include "base/utils.h" #include "jdwp_provider.h" #include "experimental_flags.h" #include "parsed_options.h" #include "runtime.h" #include "runtime_options.h" -#include "utils.h" #define EXPECT_NULL(expected) EXPECT_EQ(reinterpret_cast<const void*>(expected), \ reinterpret_cast<void*>(nullptr)); @@ -126,6 +127,7 @@ class CmdlineParserTest : public ::testing::Test { using RuntimeParser = ParsedOptions::RuntimeParser; static void SetUpTestCase() { + art::Locks::Init(); art::InitLogging(nullptr, art::Runtime::Abort); // argv = null } diff --git a/cmdline/cmdline_result.h b/cmdline/cmdline_result.h index e41043abf0..0ae1145a52 100644 --- a/cmdline/cmdline_result.h +++ b/cmdline/cmdline_result.h @@ -18,7 +18,7 @@ #define ART_CMDLINE_CMDLINE_RESULT_H_ #include <assert.h> -#include <utils.h> +#include "base/utils.h" namespace art { // Result of an attempt to process the command line arguments. If fails, specifies diff --git a/compiler/Android.bp b/compiler/Android.bp index 40c676c406..c4d538fc88 100644 --- a/compiler/Android.bp +++ b/compiler/Android.bp @@ -256,7 +256,14 @@ art_cc_library { instrumentation: true, profile_file: "art/dex2oat.profdata", benchmarks: ["dex2oat"], - } + }, + target: { + android: { + lto: { + thin: true, + }, + }, + }, } art_cc_library { diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc index a20313374c..d3e3a51f7a 100644 --- a/compiler/common_compiler_test.cc +++ b/compiler/common_compiler_test.cc @@ -21,6 +21,7 @@ #include "art_method-inl.h" #include "base/callee_save_type.h" #include "base/enums.h" +#include "base/utils.h" #include "class_linker.h" #include "compiled_method-inl.h" #include "dex/descriptors_names.h" @@ -36,7 +37,6 @@ #include "oat_quick_method_header.h" #include "scoped_thread_state_change-inl.h" #include "thread-current-inl.h" -#include "utils.h" namespace art { diff --git a/compiler/compiler.cc b/compiler/compiler.cc index 7c7ae71d77..646040fd9d 100644 --- a/compiler/compiler.cc +++ b/compiler/compiler.cc @@ -19,10 +19,10 @@ #include <android-base/logging.h> #include "base/macros.h" +#include "base/utils.h" #include "dex/code_item_accessors-inl.h" #include "driver/compiler_driver.h" #include "optimizing/optimizing_compiler.h" -#include "utils.h" namespace art { diff --git a/compiler/compiler.h b/compiler/compiler.h index a17e2b5875..f2ec3a9fa3 100644 --- a/compiler/compiler.h +++ b/compiler/compiler.h @@ -18,8 +18,8 @@ #define ART_COMPILER_COMPILER_H_ #include "base/mutex.h" +#include "base/os.h" #include "dex/dex_file.h" -#include "os.h" namespace art { diff --git a/compiler/debug/dwarf/dwarf_test.h b/compiler/debug/dwarf/dwarf_test.h index 5405759c1f..9a7c604ca1 100644 --- a/compiler/debug/dwarf/dwarf_test.h +++ b/compiler/debug/dwarf/dwarf_test.h @@ -26,12 +26,12 @@ #include <set> #include <string> +#include "base/os.h" #include "base/unix_file/fd_file.h" #include "common_runtime_test.h" #include "gtest/gtest.h" #include "linker/elf_builder.h" #include "linker/file_output_stream.h" -#include "os.h" namespace art { namespace dwarf { diff --git a/compiler/debug/elf_symtab_writer.h b/compiler/debug/elf_symtab_writer.h index 1310e8dabd..7a8e29191a 100644 --- a/compiler/debug/elf_symtab_writer.h +++ b/compiler/debug/elf_symtab_writer.h @@ -20,12 +20,12 @@ #include <map> #include <unordered_set> +#include "base/utils.h" #include "debug/debug_info.h" #include "debug/method_debug_info.h" #include "dex/dex_file-inl.h" #include "dex/code_item_accessors.h" #include "linker/elf_builder.h" -#include "utils.h" namespace art { namespace debug { diff --git a/compiler/driver/compiled_method_storage.cc b/compiler/driver/compiled_method_storage.cc index 48477abe5b..a26a985ff9 100644 --- a/compiler/driver/compiled_method_storage.cc +++ b/compiler/driver/compiled_method_storage.cc @@ -21,10 +21,10 @@ #include <android-base/logging.h> +#include "base/utils.h" #include "compiled_method.h" #include "linker/linker_patch.h" #include "thread-current-inl.h" -#include "utils.h" #include "utils/dedupe_set-inl.h" #include "utils/swap_space.h" diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index a3bb4ec34d..8db892bf18 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -29,6 +29,8 @@ #include "base/array_ref.h" #include "base/bit_utils.h" #include "base/mutex.h" +#include "base/os.h" +#include "base/quasi_atomic.h" #include "base/safe_map.h" #include "base/timing_logger.h" #include "class_reference.h" @@ -39,7 +41,6 @@ #include "dex/dex_to_dex_compiler.h" #include "driver/compiled_method_storage.h" #include "method_reference.h" -#include "os.h" #include "thread_pool.h" #include "utils/atomic_dex_ref_map.h" #include "utils/dex_cache_arrays_layout.h" diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h index 18b0913430..05d8805e81 100644 --- a/compiler/driver/compiler_options.h +++ b/compiler/driver/compiler_options.h @@ -22,10 +22,10 @@ #include <vector> #include "base/macros.h" +#include "base/utils.h" #include "compiler_filter.h" #include "globals.h" #include "optimizing/register_allocator.h" -#include "utils.h" namespace art { diff --git a/compiler/driver/dex_compilation_unit.cc b/compiler/driver/dex_compilation_unit.cc index 2e315b5d12..c90c37d54a 100644 --- a/compiler/driver/dex_compilation_unit.cc +++ b/compiler/driver/dex_compilation_unit.cc @@ -16,10 +16,10 @@ #include "dex_compilation_unit.h" +#include "base/utils.h" #include "dex/code_item_accessors-inl.h" #include "dex/descriptors_names.h" #include "mirror/dex_cache.h" -#include "utils.h" namespace art { diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc index fc44927231..d001cfe4fc 100644 --- a/compiler/jni/quick/jni_compiler.cc +++ b/compiler/jni/quick/jni_compiler.cc @@ -27,6 +27,7 @@ #include "base/enums.h" #include "base/logging.h" // For VLOG. #include "base/macros.h" +#include "base/utils.h" #include "calling_convention.h" #include "class_linker.h" #include "debug/dwarf/debug_frame_opcode_writer.h" @@ -37,7 +38,6 @@ #include "jni_env_ext.h" #include "memory_region.h" #include "thread.h" -#include "utils.h" #include "utils/arm/managed_register_arm.h" #include "utils/arm64/managed_register_arm64.h" #include "utils/assembler.h" diff --git a/compiler/linker/file_output_stream.h b/compiler/linker/file_output_stream.h index 28296a47fd..deb051fca4 100644 --- a/compiler/linker/file_output_stream.h +++ b/compiler/linker/file_output_stream.h @@ -17,9 +17,9 @@ #ifndef ART_COMPILER_LINKER_FILE_OUTPUT_STREAM_H_ #define ART_COMPILER_LINKER_FILE_OUTPUT_STREAM_H_ -#include "output_stream.h" +#include "base/os.h" -#include "os.h" +#include "output_stream.h" namespace art { namespace linker { diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 1f9c5546e2..b0ddd8e8c6 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -78,6 +78,7 @@ using helpers::OutputFPRegister; using helpers::OutputRegister; using helpers::QRegisterFrom; using helpers::RegisterFrom; +using helpers::SRegisterFrom; using helpers::StackOperandFrom; using helpers::VIXLRegCodeFromART; using helpers::WRegisterFrom; @@ -5462,6 +5463,119 @@ void InstructionCodeGeneratorARM64::VisitRem(HRem* rem) { } } +// TODO: integrate with HandleBinaryOp? +static void CreateMinMaxLocations(ArenaAllocator* allocator, HBinaryOperation* minmax) { + LocationSummary* locations = new (allocator) LocationSummary(minmax); + switch (minmax->GetResultType()) { + case DataType::Type::kInt32: + case DataType::Type::kInt64: + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + break; + case DataType::Type::kFloat32: + case DataType::Type::kFloat64: + locations->SetInAt(0, Location::RequiresFpuRegister()); + locations->SetInAt(1, Location::RequiresFpuRegister()); + locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); + break; + default: + LOG(FATAL) << "Unexpected type for HMinMax " << minmax->GetResultType(); + } +} + +void InstructionCodeGeneratorARM64::GenerateMinMax(LocationSummary* locations, + bool is_min, + DataType::Type type) { + Location op1 = locations->InAt(0); + Location op2 = locations->InAt(1); + Location out = locations->Out(); + + Register op1_reg; + Register op2_reg; + Register out_reg; + if (type == DataType::Type::kInt64) { + op1_reg = XRegisterFrom(op1); + op2_reg = XRegisterFrom(op2); + out_reg = XRegisterFrom(out); + } else { + DCHECK_EQ(type, DataType::Type::kInt32); + op1_reg = WRegisterFrom(op1); + op2_reg = WRegisterFrom(op2); + out_reg = WRegisterFrom(out); + } + + __ Cmp(op1_reg, op2_reg); + __ Csel(out_reg, op1_reg, op2_reg, is_min ? lt : gt); +} + +void InstructionCodeGeneratorARM64::GenerateMinMaxFP(LocationSummary* locations, + bool is_min, + DataType::Type type) { + Location op1 = locations->InAt(0); + Location op2 = locations->InAt(1); + Location out = locations->Out(); + + FPRegister op1_reg; + FPRegister op2_reg; + FPRegister out_reg; + if (type == DataType::Type::kFloat64) { + op1_reg = DRegisterFrom(op1); + op2_reg = DRegisterFrom(op2); + out_reg = DRegisterFrom(out); + } else { + DCHECK_EQ(type, DataType::Type::kFloat32); + op1_reg = SRegisterFrom(op1); + op2_reg = SRegisterFrom(op2); + out_reg = SRegisterFrom(out); + } + + if (is_min) { + __ Fmin(out_reg, op1_reg, op2_reg); + } else { + __ Fmax(out_reg, op1_reg, op2_reg); + } +} + +void LocationsBuilderARM64::VisitMin(HMin* min) { + CreateMinMaxLocations(GetGraph()->GetAllocator(), min); +} + +// TODO: integrate with HandleBinaryOp? +void InstructionCodeGeneratorARM64::VisitMin(HMin* min) { + switch (min->GetResultType()) { + case DataType::Type::kInt32: + case DataType::Type::kInt64: + GenerateMinMax(min->GetLocations(), /*is_min*/ true, min->GetResultType()); + break; + case DataType::Type::kFloat32: + case DataType::Type::kFloat64: + GenerateMinMaxFP(min->GetLocations(), /*is_min*/ true, min->GetResultType()); + break; + default: + LOG(FATAL) << "Unexpected type for HMin " << min->GetResultType(); + } +} + +void LocationsBuilderARM64::VisitMax(HMax* max) { + CreateMinMaxLocations(GetGraph()->GetAllocator(), max); +} + +void InstructionCodeGeneratorARM64::VisitMax(HMax* max) { + switch (max->GetResultType()) { + case DataType::Type::kInt32: + case DataType::Type::kInt64: + GenerateMinMax(max->GetLocations(), /*is_min*/ false, max->GetResultType()); + break; + case DataType::Type::kFloat32: + case DataType::Type::kFloat64: + GenerateMinMaxFP(max->GetLocations(), /*is_min*/ false, max->GetResultType()); + break; + default: + LOG(FATAL) << "Unexpected type for HMax " << max->GetResultType(); + } +} + void LocationsBuilderARM64::VisitAbs(HAbs* abs) { LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(abs); switch (abs->GetResultType()) { diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h index e34f799d15..70f5500016 100644 --- a/compiler/optimizing/code_generator_arm64.h +++ b/compiler/optimizing/code_generator_arm64.h @@ -273,6 +273,9 @@ class InstructionCodeGeneratorARM64 : public InstructionCodeGenerator { void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info); void HandleCondition(HCondition* instruction); + void GenerateMinMax(LocationSummary* locations, bool is_min, DataType::Type type); + void GenerateMinMaxFP(LocationSummary* locations, bool is_min, DataType::Type type); + // Generate a heap reference load using one register `out`: // // out <- *(out + offset) diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc index 13518adf7d..4fef027e6d 100644 --- a/compiler/optimizing/code_generator_arm_vixl.cc +++ b/compiler/optimizing/code_generator_arm_vixl.cc @@ -4690,6 +4690,254 @@ void InstructionCodeGeneratorARMVIXL::VisitRem(HRem* rem) { } } +static void CreateMinMaxLocations(ArenaAllocator* allocator, HBinaryOperation* minmax) { + LocationSummary* locations = new (allocator) LocationSummary(minmax); + switch (minmax->GetResultType()) { + case DataType::Type::kInt32: + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + break; + case DataType::Type::kInt64: + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + locations->SetOut(Location::SameAsFirstInput()); + break; + case DataType::Type::kFloat32: + locations->SetInAt(0, Location::RequiresFpuRegister()); + locations->SetInAt(1, Location::RequiresFpuRegister()); + locations->SetOut(Location::SameAsFirstInput()); + locations->AddTemp(Location::RequiresRegister()); + break; + case DataType::Type::kFloat64: + locations->SetInAt(0, Location::RequiresFpuRegister()); + locations->SetInAt(1, Location::RequiresFpuRegister()); + locations->SetOut(Location::SameAsFirstInput()); + break; + default: + LOG(FATAL) << "Unexpected type for HMinMax " << minmax->GetResultType(); + } +} + +void InstructionCodeGeneratorARMVIXL::GenerateMinMax(LocationSummary* locations, bool is_min) { + Location op1_loc = locations->InAt(0); + Location op2_loc = locations->InAt(1); + Location out_loc = locations->Out(); + + vixl32::Register op1 = RegisterFrom(op1_loc); + vixl32::Register op2 = RegisterFrom(op2_loc); + vixl32::Register out = RegisterFrom(out_loc); + + __ Cmp(op1, op2); + + { + ExactAssemblyScope aas(GetVIXLAssembler(), + 3 * kMaxInstructionSizeInBytes, + CodeBufferCheckScope::kMaximumSize); + + __ ite(is_min ? lt : gt); + __ mov(is_min ? lt : gt, out, op1); + __ mov(is_min ? ge : le, out, op2); + } +} + +void InstructionCodeGeneratorARMVIXL::GenerateMinMaxLong(LocationSummary* locations, bool is_min) { + Location op1_loc = locations->InAt(0); + Location op2_loc = locations->InAt(1); + Location out_loc = locations->Out(); + + // Optimization: don't generate any code if inputs are the same. + if (op1_loc.Equals(op2_loc)) { + DCHECK(out_loc.Equals(op1_loc)); // out_loc is set as SameAsFirstInput() in location builder. + return; + } + + vixl32::Register op1_lo = LowRegisterFrom(op1_loc); + vixl32::Register op1_hi = HighRegisterFrom(op1_loc); + vixl32::Register op2_lo = LowRegisterFrom(op2_loc); + vixl32::Register op2_hi = HighRegisterFrom(op2_loc); + vixl32::Register out_lo = LowRegisterFrom(out_loc); + vixl32::Register out_hi = HighRegisterFrom(out_loc); + UseScratchRegisterScope temps(GetVIXLAssembler()); + const vixl32::Register temp = temps.Acquire(); + + DCHECK(op1_lo.Is(out_lo)); + DCHECK(op1_hi.Is(out_hi)); + + // Compare op1 >= op2, or op1 < op2. + __ Cmp(out_lo, op2_lo); + __ Sbcs(temp, out_hi, op2_hi); + + // Now GE/LT condition code is correct for the long comparison. + { + vixl32::ConditionType cond = is_min ? ge : lt; + ExactAssemblyScope it_scope(GetVIXLAssembler(), + 3 * kMaxInstructionSizeInBytes, + CodeBufferCheckScope::kMaximumSize); + __ itt(cond); + __ mov(cond, out_lo, op2_lo); + __ mov(cond, out_hi, op2_hi); + } +} + +void InstructionCodeGeneratorARMVIXL::GenerateMinMaxFloat(HInstruction* min_max, bool is_min) { + LocationSummary* locations = min_max->GetLocations(); + Location op1_loc = locations->InAt(0); + Location op2_loc = locations->InAt(1); + Location out_loc = locations->Out(); + + // Optimization: don't generate any code if inputs are the same. + if (op1_loc.Equals(op2_loc)) { + DCHECK(out_loc.Equals(op1_loc)); // out_loc is set as SameAsFirstInput() in location builder. + return; + } + + vixl32::SRegister op1 = SRegisterFrom(op1_loc); + vixl32::SRegister op2 = SRegisterFrom(op2_loc); + vixl32::SRegister out = SRegisterFrom(out_loc); + + UseScratchRegisterScope temps(GetVIXLAssembler()); + const vixl32::Register temp1 = temps.Acquire(); + vixl32::Register temp2 = RegisterFrom(locations->GetTemp(0)); + vixl32::Label nan, done; + vixl32::Label* final_label = codegen_->GetFinalLabel(min_max, &done); + + DCHECK(op1.Is(out)); + + __ Vcmp(op1, op2); + __ Vmrs(RegisterOrAPSR_nzcv(kPcCode), FPSCR); + __ B(vs, &nan, /* far_target */ false); // if un-ordered, go to NaN handling. + + // op1 <> op2 + vixl32::ConditionType cond = is_min ? gt : lt; + { + ExactAssemblyScope it_scope(GetVIXLAssembler(), + 2 * kMaxInstructionSizeInBytes, + CodeBufferCheckScope::kMaximumSize); + __ it(cond); + __ vmov(cond, F32, out, op2); + } + // for <>(not equal), we've done min/max calculation. + __ B(ne, final_label, /* far_target */ false); + + // handle op1 == op2, max(+0.0,-0.0), min(+0.0,-0.0). + __ Vmov(temp1, op1); + __ Vmov(temp2, op2); + if (is_min) { + __ Orr(temp1, temp1, temp2); + } else { + __ And(temp1, temp1, temp2); + } + __ Vmov(out, temp1); + __ B(final_label); + + // handle NaN input. + __ Bind(&nan); + __ Movt(temp1, High16Bits(kNanFloat)); // 0x7FC0xxxx is a NaN. + __ Vmov(out, temp1); + + if (done.IsReferenced()) { + __ Bind(&done); + } +} + +void InstructionCodeGeneratorARMVIXL::GenerateMinMaxDouble(HInstruction* min_max, bool is_min) { + LocationSummary* locations = min_max->GetLocations(); + Location op1_loc = locations->InAt(0); + Location op2_loc = locations->InAt(1); + Location out_loc = locations->Out(); + + // Optimization: don't generate any code if inputs are the same. + if (op1_loc.Equals(op2_loc)) { + DCHECK(out_loc.Equals(op1_loc)); // out_loc is set as SameAsFirstInput() in. + return; + } + + vixl32::DRegister op1 = DRegisterFrom(op1_loc); + vixl32::DRegister op2 = DRegisterFrom(op2_loc); + vixl32::DRegister out = DRegisterFrom(out_loc); + vixl32::Label handle_nan_eq, done; + vixl32::Label* final_label = codegen_->GetFinalLabel(min_max, &done); + + DCHECK(op1.Is(out)); + + __ Vcmp(op1, op2); + __ Vmrs(RegisterOrAPSR_nzcv(kPcCode), FPSCR); + __ B(vs, &handle_nan_eq, /* far_target */ false); // if un-ordered, go to NaN handling. + + // op1 <> op2 + vixl32::ConditionType cond = is_min ? gt : lt; + { + ExactAssemblyScope it_scope(GetVIXLAssembler(), + 2 * kMaxInstructionSizeInBytes, + CodeBufferCheckScope::kMaximumSize); + __ it(cond); + __ vmov(cond, F64, out, op2); + } + // for <>(not equal), we've done min/max calculation. + __ B(ne, final_label, /* far_target */ false); + + // handle op1 == op2, max(+0.0,-0.0). + if (!is_min) { + __ Vand(F64, out, op1, op2); + __ B(final_label); + } + + // handle op1 == op2, min(+0.0,-0.0), NaN input. + __ Bind(&handle_nan_eq); + __ Vorr(F64, out, op1, op2); // assemble op1/-0.0/NaN. + + if (done.IsReferenced()) { + __ Bind(&done); + } +} + +void LocationsBuilderARMVIXL::VisitMin(HMin* min) { + CreateMinMaxLocations(GetGraph()->GetAllocator(), min); +} + +void InstructionCodeGeneratorARMVIXL::VisitMin(HMin* min) { + switch (min->GetResultType()) { + case DataType::Type::kInt32: + GenerateMinMax(min->GetLocations(), /*is_min*/ true); + break; + case DataType::Type::kInt64: + GenerateMinMaxLong(min->GetLocations(), /*is_min*/ true); + break; + case DataType::Type::kFloat32: + GenerateMinMaxFloat(min, /*is_min*/ true); + break; + case DataType::Type::kFloat64: + GenerateMinMaxDouble(min, /*is_min*/ true); + break; + default: + LOG(FATAL) << "Unexpected type for HMin " << min->GetResultType(); + } +} + +void LocationsBuilderARMVIXL::VisitMax(HMax* max) { + CreateMinMaxLocations(GetGraph()->GetAllocator(), max); +} + +void InstructionCodeGeneratorARMVIXL::VisitMax(HMax* max) { + switch (max->GetResultType()) { + case DataType::Type::kInt32: + GenerateMinMax(max->GetLocations(), /*is_min*/ false); + break; + case DataType::Type::kInt64: + GenerateMinMaxLong(max->GetLocations(), /*is_min*/ false); + break; + case DataType::Type::kFloat32: + GenerateMinMaxFloat(max, /*is_min*/ false); + break; + case DataType::Type::kFloat64: + GenerateMinMaxDouble(max, /*is_min*/ false); + break; + default: + LOG(FATAL) << "Unexpected type for HMax " << max->GetResultType(); + } +} + void LocationsBuilderARMVIXL::VisitAbs(HAbs* abs) { LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(abs); switch (abs->GetResultType()) { diff --git a/compiler/optimizing/code_generator_arm_vixl.h b/compiler/optimizing/code_generator_arm_vixl.h index bbc715c59d..726a2f9030 100644 --- a/compiler/optimizing/code_generator_arm_vixl.h +++ b/compiler/optimizing/code_generator_arm_vixl.h @@ -349,6 +349,11 @@ class InstructionCodeGeneratorARMVIXL : public InstructionCodeGenerator { bool value_can_be_null); void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info); + void GenerateMinMax(LocationSummary* locations, bool is_min); + void GenerateMinMaxLong(LocationSummary* locations, bool is_min); + void GenerateMinMaxFloat(HInstruction* min_max, bool is_min); + void GenerateMinMaxDouble(HInstruction* min_max, bool is_min); + // Generate a heap reference load using one register `out`: // // out <- *(out + offset) diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc index eb5f72e953..ae42bbcc70 100644 --- a/compiler/optimizing/code_generator_mips.cc +++ b/compiler/optimizing/code_generator_mips.cc @@ -8779,6 +8779,397 @@ void InstructionCodeGeneratorMIPS::VisitRem(HRem* instruction) { } } +static void CreateMinMaxLocations(ArenaAllocator* allocator, HBinaryOperation* minmax) { + LocationSummary* locations = new (allocator) LocationSummary(minmax); + switch (minmax->GetResultType()) { + case DataType::Type::kInt32: + case DataType::Type::kInt64: + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + break; + case DataType::Type::kFloat32: + case DataType::Type::kFloat64: + locations->SetInAt(0, Location::RequiresFpuRegister()); + locations->SetInAt(1, Location::RequiresFpuRegister()); + locations->SetOut(Location::RequiresFpuRegister(), Location::kOutputOverlap); + break; + default: + LOG(FATAL) << "Unexpected type for HMinMax " << minmax->GetResultType(); + } +} + +void InstructionCodeGeneratorMIPS::GenerateMinMax(LocationSummary* locations, + bool is_min, + bool isR6, + DataType::Type type) { + if (isR6) { + // Some architectures, such as ARM and MIPS (prior to r6), have a + // conditional move instruction which only changes the target + // (output) register if the condition is true (MIPS prior to r6 had + // MOVF, MOVT, MOVN, and MOVZ). The SELEQZ and SELNEZ instructions + // always change the target (output) register. If the condition is + // true the output register gets the contents of the "rs" register; + // otherwise, the output register is set to zero. One consequence + // of this is that to implement something like "rd = c==0 ? rs : rt" + // MIPS64r6 needs to use a pair of SELEQZ/SELNEZ instructions. + // After executing this pair of instructions one of the output + // registers from the pair will necessarily contain zero. Then the + // code ORs the output registers from the SELEQZ/SELNEZ instructions + // to get the final result. + // + // The initial test to see if the output register is same as the + // first input register is needed to make sure that value in the + // first input register isn't clobbered before we've finished + // computing the output value. The logic in the corresponding else + // clause performs the same task but makes sure the second input + // register isn't clobbered in the event that it's the same register + // as the output register; the else clause also handles the case + // where the output register is distinct from both the first, and the + // second input registers. + if (type == DataType::Type::kInt64) { + Register a_lo = locations->InAt(0).AsRegisterPairLow<Register>(); + Register a_hi = locations->InAt(0).AsRegisterPairHigh<Register>(); + Register b_lo = locations->InAt(1).AsRegisterPairLow<Register>(); + Register b_hi = locations->InAt(1).AsRegisterPairHigh<Register>(); + Register out_lo = locations->Out().AsRegisterPairLow<Register>(); + Register out_hi = locations->Out().AsRegisterPairHigh<Register>(); + + MipsLabel compare_done; + + if (a_lo == b_lo) { + if (out_lo != a_lo) { + __ Move(out_lo, a_lo); + __ Move(out_hi, a_hi); + } + } else { + __ Slt(TMP, b_hi, a_hi); + __ Bne(b_hi, a_hi, &compare_done); + + __ Sltu(TMP, b_lo, a_lo); + + __ Bind(&compare_done); + + if (is_min) { + __ Seleqz(AT, a_lo, TMP); + __ Selnez(out_lo, b_lo, TMP); // Safe even if out_lo == a_lo/b_lo + // because at this point we're + // done using a_lo/b_lo. + } else { + __ Selnez(AT, a_lo, TMP); + __ Seleqz(out_lo, b_lo, TMP); // ditto + } + __ Or(out_lo, out_lo, AT); + if (is_min) { + __ Seleqz(AT, a_hi, TMP); + __ Selnez(out_hi, b_hi, TMP); // ditto but for out_hi & a_hi/b_hi + } else { + __ Selnez(AT, a_hi, TMP); + __ Seleqz(out_hi, b_hi, TMP); // ditto but for out_hi & a_hi/b_hi + } + __ Or(out_hi, out_hi, AT); + } + } else { + DCHECK_EQ(type, DataType::Type::kInt32); + Register a = locations->InAt(0).AsRegister<Register>(); + Register b = locations->InAt(1).AsRegister<Register>(); + Register out = locations->Out().AsRegister<Register>(); + + if (a == b) { + if (out != a) { + __ Move(out, a); + } + } else { + __ Slt(AT, b, a); + if (is_min) { + __ Seleqz(TMP, a, AT); + __ Selnez(AT, b, AT); + } else { + __ Selnez(TMP, a, AT); + __ Seleqz(AT, b, AT); + } + __ Or(out, TMP, AT); + } + } + } else { // !isR6 + if (type == DataType::Type::kInt64) { + Register a_lo = locations->InAt(0).AsRegisterPairLow<Register>(); + Register a_hi = locations->InAt(0).AsRegisterPairHigh<Register>(); + Register b_lo = locations->InAt(1).AsRegisterPairLow<Register>(); + Register b_hi = locations->InAt(1).AsRegisterPairHigh<Register>(); + Register out_lo = locations->Out().AsRegisterPairLow<Register>(); + Register out_hi = locations->Out().AsRegisterPairHigh<Register>(); + + MipsLabel compare_done; + + if (a_lo == b_lo) { + if (out_lo != a_lo) { + __ Move(out_lo, a_lo); + __ Move(out_hi, a_hi); + } + } else { + __ Slt(TMP, a_hi, b_hi); + __ Bne(a_hi, b_hi, &compare_done); + + __ Sltu(TMP, a_lo, b_lo); + + __ Bind(&compare_done); + + if (is_min) { + if (out_lo != a_lo) { + __ Movn(out_hi, a_hi, TMP); + __ Movn(out_lo, a_lo, TMP); + } + if (out_lo != b_lo) { + __ Movz(out_hi, b_hi, TMP); + __ Movz(out_lo, b_lo, TMP); + } + } else { + if (out_lo != a_lo) { + __ Movz(out_hi, a_hi, TMP); + __ Movz(out_lo, a_lo, TMP); + } + if (out_lo != b_lo) { + __ Movn(out_hi, b_hi, TMP); + __ Movn(out_lo, b_lo, TMP); + } + } + } + } else { + DCHECK_EQ(type, DataType::Type::kInt32); + Register a = locations->InAt(0).AsRegister<Register>(); + Register b = locations->InAt(1).AsRegister<Register>(); + Register out = locations->Out().AsRegister<Register>(); + + if (a == b) { + if (out != a) { + __ Move(out, a); + } + } else { + __ Slt(AT, a, b); + if (is_min) { + if (out != a) { + __ Movn(out, a, AT); + } + if (out != b) { + __ Movz(out, b, AT); + } + } else { + if (out != a) { + __ Movz(out, a, AT); + } + if (out != b) { + __ Movn(out, b, AT); + } + } + } + } + } +} + +void InstructionCodeGeneratorMIPS::GenerateMinMaxFP(LocationSummary* locations, + bool is_min, + bool isR6, + DataType::Type type) { + FRegister out = locations->Out().AsFpuRegister<FRegister>(); + FRegister a = locations->InAt(0).AsFpuRegister<FRegister>(); + FRegister b = locations->InAt(1).AsFpuRegister<FRegister>(); + + if (isR6) { + MipsLabel noNaNs; + MipsLabel done; + FRegister ftmp = ((out != a) && (out != b)) ? out : FTMP; + + // When Java computes min/max it prefers a NaN to a number; the + // behavior of MIPSR6 is to prefer numbers to NaNs, i.e., if one of + // the inputs is a NaN and the other is a valid number, the MIPS + // instruction will return the number; Java wants the NaN value + // returned. This is why there is extra logic preceding the use of + // the MIPS min.fmt/max.fmt instructions. If either a, or b holds a + // NaN, return the NaN, otherwise return the min/max. + if (type == DataType::Type::kFloat64) { + __ CmpUnD(FTMP, a, b); + __ Bc1eqz(FTMP, &noNaNs); + + // One of the inputs is a NaN + __ CmpEqD(ftmp, a, a); + // If a == a then b is the NaN, otherwise a is the NaN. + __ SelD(ftmp, a, b); + + if (ftmp != out) { + __ MovD(out, ftmp); + } + + __ B(&done); + + __ Bind(&noNaNs); + + if (is_min) { + __ MinD(out, a, b); + } else { + __ MaxD(out, a, b); + } + } else { + DCHECK_EQ(type, DataType::Type::kFloat32); + __ CmpUnS(FTMP, a, b); + __ Bc1eqz(FTMP, &noNaNs); + + // One of the inputs is a NaN + __ CmpEqS(ftmp, a, a); + // If a == a then b is the NaN, otherwise a is the NaN. + __ SelS(ftmp, a, b); + + if (ftmp != out) { + __ MovS(out, ftmp); + } + + __ B(&done); + + __ Bind(&noNaNs); + + if (is_min) { + __ MinS(out, a, b); + } else { + __ MaxS(out, a, b); + } + } + + __ Bind(&done); + + } else { // !isR6 + MipsLabel ordered; + MipsLabel compare; + MipsLabel select; + MipsLabel done; + + if (type == DataType::Type::kFloat64) { + __ CunD(a, b); + } else { + DCHECK_EQ(type, DataType::Type::kFloat32); + __ CunS(a, b); + } + __ Bc1f(&ordered); + + // a or b (or both) is a NaN. Return one, which is a NaN. + if (type == DataType::Type::kFloat64) { + __ CeqD(b, b); + } else { + __ CeqS(b, b); + } + __ B(&select); + + __ Bind(&ordered); + + // Neither is a NaN. + // a == b? (-0.0 compares equal with +0.0) + // If equal, handle zeroes, else compare further. + if (type == DataType::Type::kFloat64) { + __ CeqD(a, b); + } else { + __ CeqS(a, b); + } + __ Bc1f(&compare); + + // a == b either bit for bit or one is -0.0 and the other is +0.0. + if (type == DataType::Type::kFloat64) { + __ MoveFromFpuHigh(TMP, a); + __ MoveFromFpuHigh(AT, b); + } else { + __ Mfc1(TMP, a); + __ Mfc1(AT, b); + } + + if (is_min) { + // -0.0 prevails over +0.0. + __ Or(TMP, TMP, AT); + } else { + // +0.0 prevails over -0.0. + __ And(TMP, TMP, AT); + } + + if (type == DataType::Type::kFloat64) { + __ Mfc1(AT, a); + __ Mtc1(AT, out); + __ MoveToFpuHigh(TMP, out); + } else { + __ Mtc1(TMP, out); + } + __ B(&done); + + __ Bind(&compare); + + if (type == DataType::Type::kFloat64) { + if (is_min) { + // return (a <= b) ? a : b; + __ ColeD(a, b); + } else { + // return (a >= b) ? a : b; + __ ColeD(b, a); // b <= a + } + } else { + if (is_min) { + // return (a <= b) ? a : b; + __ ColeS(a, b); + } else { + // return (a >= b) ? a : b; + __ ColeS(b, a); // b <= a + } + } + + __ Bind(&select); + + if (type == DataType::Type::kFloat64) { + __ MovtD(out, a); + __ MovfD(out, b); + } else { + __ MovtS(out, a); + __ MovfS(out, b); + } + + __ Bind(&done); + } +} + +void LocationsBuilderMIPS::VisitMin(HMin* min) { + CreateMinMaxLocations(GetGraph()->GetAllocator(), min); +} + +void InstructionCodeGeneratorMIPS::VisitMin(HMin* min) { + bool isR6 = codegen_->GetInstructionSetFeatures().IsR6(); + switch (min->GetResultType()) { + case DataType::Type::kInt32: + case DataType::Type::kInt64: + GenerateMinMax(min->GetLocations(), /*is_min*/ true, isR6, min->GetResultType()); + break; + case DataType::Type::kFloat32: + case DataType::Type::kFloat64: + GenerateMinMaxFP(min->GetLocations(), /*is_min*/ true, isR6, min->GetResultType()); + break; + default: + LOG(FATAL) << "Unexpected type for HMin " << min->GetResultType(); + } +} + +void LocationsBuilderMIPS::VisitMax(HMax* max) { + CreateMinMaxLocations(GetGraph()->GetAllocator(), max); +} + +void InstructionCodeGeneratorMIPS::VisitMax(HMax* max) { + bool isR6 = codegen_->GetInstructionSetFeatures().IsR6(); + switch (max->GetResultType()) { + case DataType::Type::kInt32: + case DataType::Type::kInt64: + GenerateMinMax(max->GetLocations(), /*is_min*/ false, isR6, max->GetResultType()); + break; + case DataType::Type::kFloat32: + case DataType::Type::kFloat64: + GenerateMinMaxFP(max->GetLocations(), /*is_min*/ false, isR6, max->GetResultType()); + break; + default: + LOG(FATAL) << "Unexpected type for HMax " << max->GetResultType(); + } +} + void LocationsBuilderMIPS::VisitAbs(HAbs* abs) { LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(abs); switch (abs->GetResultType()) { diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h index d09ab7cce0..ae5fe5be19 100644 --- a/compiler/optimizing/code_generator_mips.h +++ b/compiler/optimizing/code_generator_mips.h @@ -246,6 +246,8 @@ class InstructionCodeGeneratorMIPS : public InstructionCodeGenerator { bool value_can_be_null); void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info, uint32_t dex_pc); + void GenerateMinMax(LocationSummary* locations, bool is_min, bool isR6, DataType::Type type); + void GenerateMinMaxFP(LocationSummary* locations, bool is_min, bool isR6, DataType::Type type); void GenerateAbsFP(LocationSummary* locations, DataType::Type type, bool isR2OrNewer, bool isR6); // Generate a heap reference load using one register `out`: diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc index 9593eec455..8031cca7cb 100644 --- a/compiler/optimizing/code_generator_mips64.cc +++ b/compiler/optimizing/code_generator_mips64.cc @@ -6665,6 +6665,188 @@ void InstructionCodeGeneratorMIPS64::VisitRem(HRem* instruction) { } } +static void CreateMinMaxLocations(ArenaAllocator* allocator, HBinaryOperation* minmax) { + LocationSummary* locations = new (allocator) LocationSummary(minmax); + switch (minmax->GetResultType()) { + case DataType::Type::kInt32: + case DataType::Type::kInt64: + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); + break; + case DataType::Type::kFloat32: + case DataType::Type::kFloat64: + locations->SetInAt(0, Location::RequiresFpuRegister()); + locations->SetInAt(1, Location::RequiresFpuRegister()); + locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); + break; + default: + LOG(FATAL) << "Unexpected type for HMinMax " << minmax->GetResultType(); + } +} + +void InstructionCodeGeneratorMIPS64::GenerateMinMax(LocationSummary* locations, bool is_min) { + GpuRegister lhs = locations->InAt(0).AsRegister<GpuRegister>(); + GpuRegister rhs = locations->InAt(1).AsRegister<GpuRegister>(); + GpuRegister out = locations->Out().AsRegister<GpuRegister>(); + + if (lhs == rhs) { + if (out != lhs) { + __ Move(out, lhs); + } + } else { + // Some architectures, such as ARM and MIPS (prior to r6), have a + // conditional move instruction which only changes the target + // (output) register if the condition is true (MIPS prior to r6 had + // MOVF, MOVT, and MOVZ). The SELEQZ and SELNEZ instructions always + // change the target (output) register. If the condition is true the + // output register gets the contents of the "rs" register; otherwise, + // the output register is set to zero. One consequence of this is + // that to implement something like "rd = c==0 ? rs : rt" MIPS64r6 + // needs to use a pair of SELEQZ/SELNEZ instructions. After + // executing this pair of instructions one of the output registers + // from the pair will necessarily contain zero. Then the code ORs the + // output registers from the SELEQZ/SELNEZ instructions to get the + // final result. + // + // The initial test to see if the output register is same as the + // first input register is needed to make sure that value in the + // first input register isn't clobbered before we've finished + // computing the output value. The logic in the corresponding else + // clause performs the same task but makes sure the second input + // register isn't clobbered in the event that it's the same register + // as the output register; the else clause also handles the case + // where the output register is distinct from both the first, and the + // second input registers. + if (out == lhs) { + __ Slt(AT, rhs, lhs); + if (is_min) { + __ Seleqz(out, lhs, AT); + __ Selnez(AT, rhs, AT); + } else { + __ Selnez(out, lhs, AT); + __ Seleqz(AT, rhs, AT); + } + } else { + __ Slt(AT, lhs, rhs); + if (is_min) { + __ Seleqz(out, rhs, AT); + __ Selnez(AT, lhs, AT); + } else { + __ Selnez(out, rhs, AT); + __ Seleqz(AT, lhs, AT); + } + } + __ Or(out, out, AT); + } +} + +void InstructionCodeGeneratorMIPS64::GenerateMinMaxFP(LocationSummary* locations, + bool is_min, + DataType::Type type) { + FpuRegister a = locations->InAt(0).AsFpuRegister<FpuRegister>(); + FpuRegister b = locations->InAt(1).AsFpuRegister<FpuRegister>(); + FpuRegister out = locations->Out().AsFpuRegister<FpuRegister>(); + + Mips64Label noNaNs; + Mips64Label done; + FpuRegister ftmp = ((out != a) && (out != b)) ? out : FTMP; + + // When Java computes min/max it prefers a NaN to a number; the + // behavior of MIPSR6 is to prefer numbers to NaNs, i.e., if one of + // the inputs is a NaN and the other is a valid number, the MIPS + // instruction will return the number; Java wants the NaN value + // returned. This is why there is extra logic preceding the use of + // the MIPS min.fmt/max.fmt instructions. If either a, or b holds a + // NaN, return the NaN, otherwise return the min/max. + if (type == DataType::Type::kFloat64) { + __ CmpUnD(FTMP, a, b); + __ Bc1eqz(FTMP, &noNaNs); + + // One of the inputs is a NaN + __ CmpEqD(ftmp, a, a); + // If a == a then b is the NaN, otherwise a is the NaN. + __ SelD(ftmp, a, b); + + if (ftmp != out) { + __ MovD(out, ftmp); + } + + __ Bc(&done); + + __ Bind(&noNaNs); + + if (is_min) { + __ MinD(out, a, b); + } else { + __ MaxD(out, a, b); + } + } else { + DCHECK_EQ(type, DataType::Type::kFloat32); + __ CmpUnS(FTMP, a, b); + __ Bc1eqz(FTMP, &noNaNs); + + // One of the inputs is a NaN + __ CmpEqS(ftmp, a, a); + // If a == a then b is the NaN, otherwise a is the NaN. + __ SelS(ftmp, a, b); + + if (ftmp != out) { + __ MovS(out, ftmp); + } + + __ Bc(&done); + + __ Bind(&noNaNs); + + if (is_min) { + __ MinS(out, a, b); + } else { + __ MaxS(out, a, b); + } + } + + __ Bind(&done); +} + +void LocationsBuilderMIPS64::VisitMin(HMin* min) { + CreateMinMaxLocations(GetGraph()->GetAllocator(), min); +} + +void InstructionCodeGeneratorMIPS64::VisitMin(HMin* min) { + switch (min->GetResultType()) { + case DataType::Type::kInt32: + case DataType::Type::kInt64: + GenerateMinMax(min->GetLocations(), /*is_min*/ true); + break; + case DataType::Type::kFloat32: + case DataType::Type::kFloat64: + GenerateMinMaxFP(min->GetLocations(), /*is_min*/ true, min->GetResultType()); + break; + default: + LOG(FATAL) << "Unexpected type for HMin " << min->GetResultType(); + } +} + +void LocationsBuilderMIPS64::VisitMax(HMax* max) { + CreateMinMaxLocations(GetGraph()->GetAllocator(), max); +} + +void InstructionCodeGeneratorMIPS64::VisitMax(HMax* max) { + switch (max->GetResultType()) { + case DataType::Type::kInt32: + case DataType::Type::kInt64: + GenerateMinMax(max->GetLocations(), /*is_min*/ false); + break; + case DataType::Type::kFloat32: + case DataType::Type::kFloat64: + GenerateMinMaxFP(max->GetLocations(), /*is_min*/ false, max->GetResultType()); + break; + default: + LOG(FATAL) << "Unexpected type for HMax " << max->GetResultType(); + } +} + void LocationsBuilderMIPS64::VisitAbs(HAbs* abs) { LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(abs); switch (abs->GetResultType()) { diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h index ddeb3eb90c..5d925d5d5a 100644 --- a/compiler/optimizing/code_generator_mips64.h +++ b/compiler/optimizing/code_generator_mips64.h @@ -242,6 +242,9 @@ class InstructionCodeGeneratorMIPS64 : public InstructionCodeGenerator { bool value_can_be_null); void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info); + void GenerateMinMax(LocationSummary* locations, bool is_min); + void GenerateMinMaxFP(LocationSummary* locations, bool is_min, DataType::Type type); + // Generate a heap reference load using one register `out`: // // out <- *(out + offset) diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 51b96be0f8..536909aa1f 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -51,6 +51,9 @@ static constexpr int kC2ConditionMask = 0x400; static constexpr int kFakeReturnRegister = Register(8); +static constexpr int64_t kDoubleNaN = INT64_C(0x7FF8000000000000); +static constexpr int32_t kFloatNaN = INT32_C(0x7FC00000); + // NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy. #define __ down_cast<X86Assembler*>(codegen->GetAssembler())-> // NOLINT #define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kX86PointerSize, x).Int32Value() @@ -3802,6 +3805,217 @@ void InstructionCodeGeneratorX86::VisitRem(HRem* rem) { } } +static void CreateMinMaxLocations(ArenaAllocator* allocator, HBinaryOperation* minmax) { + LocationSummary* locations = new (allocator) LocationSummary(minmax); + switch (minmax->GetResultType()) { + case DataType::Type::kInt32: + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + locations->SetOut(Location::SameAsFirstInput()); + break; + case DataType::Type::kInt64: + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + locations->SetOut(Location::SameAsFirstInput()); + // Register to use to perform a long subtract to set cc. + locations->AddTemp(Location::RequiresRegister()); + break; + case DataType::Type::kFloat32: + locations->SetInAt(0, Location::RequiresFpuRegister()); + locations->SetInAt(1, Location::RequiresFpuRegister()); + locations->SetOut(Location::SameAsFirstInput()); + locations->AddTemp(Location::RequiresRegister()); + break; + case DataType::Type::kFloat64: + locations->SetInAt(0, Location::RequiresFpuRegister()); + locations->SetInAt(1, Location::RequiresFpuRegister()); + locations->SetOut(Location::SameAsFirstInput()); + break; + default: + LOG(FATAL) << "Unexpected type for HMinMax " << minmax->GetResultType(); + } +} + +void InstructionCodeGeneratorX86::GenerateMinMax(LocationSummary* locations, + bool is_min, + DataType::Type type) { + Location op1_loc = locations->InAt(0); + Location op2_loc = locations->InAt(1); + + // Shortcut for same input locations. + if (op1_loc.Equals(op2_loc)) { + // Can return immediately, as op1_loc == out_loc. + // Note: if we ever support separate registers, e.g., output into memory, we need to check for + // a copy here. + DCHECK(locations->Out().Equals(op1_loc)); + return; + } + + if (type == DataType::Type::kInt64) { + // Need to perform a subtract to get the sign right. + // op1 is already in the same location as the output. + Location output = locations->Out(); + Register output_lo = output.AsRegisterPairLow<Register>(); + Register output_hi = output.AsRegisterPairHigh<Register>(); + + Register op2_lo = op2_loc.AsRegisterPairLow<Register>(); + Register op2_hi = op2_loc.AsRegisterPairHigh<Register>(); + + // The comparison is performed by subtracting the second operand from + // the first operand and then setting the status flags in the same + // manner as the SUB instruction." + __ cmpl(output_lo, op2_lo); + + // Now use a temp and the borrow to finish the subtraction of op2_hi. + Register temp = locations->GetTemp(0).AsRegister<Register>(); + __ movl(temp, output_hi); + __ sbbl(temp, op2_hi); + + // Now the condition code is correct. + Condition cond = is_min ? Condition::kGreaterEqual : Condition::kLess; + __ cmovl(cond, output_lo, op2_lo); + __ cmovl(cond, output_hi, op2_hi); + } else { + DCHECK_EQ(type, DataType::Type::kInt32); + Register out = locations->Out().AsRegister<Register>(); + Register op2 = op2_loc.AsRegister<Register>(); + + // (out := op1) + // out <=? op2 + // if out is min jmp done + // out := op2 + // done: + + __ cmpl(out, op2); + Condition cond = is_min ? Condition::kGreater : Condition::kLess; + __ cmovl(cond, out, op2); + } +} + +void InstructionCodeGeneratorX86::GenerateMinMaxFP(LocationSummary* locations, + bool is_min, + DataType::Type type) { + Location op1_loc = locations->InAt(0); + Location op2_loc = locations->InAt(1); + Location out_loc = locations->Out(); + XmmRegister out = out_loc.AsFpuRegister<XmmRegister>(); + + // Shortcut for same input locations. + if (op1_loc.Equals(op2_loc)) { + DCHECK(out_loc.Equals(op1_loc)); + return; + } + + // (out := op1) + // out <=? op2 + // if Nan jmp Nan_label + // if out is min jmp done + // if op2 is min jmp op2_label + // handle -0/+0 + // jmp done + // Nan_label: + // out := NaN + // op2_label: + // out := op2 + // done: + // + // This removes one jmp, but needs to copy one input (op1) to out. + // + // TODO: This is straight from Quick (except literal pool). Make NaN an out-of-line slowpath? + + XmmRegister op2 = op2_loc.AsFpuRegister<XmmRegister>(); + + NearLabel nan, done, op2_label; + if (type == DataType::Type::kFloat64) { + __ ucomisd(out, op2); + } else { + DCHECK_EQ(type, DataType::Type::kFloat32); + __ ucomiss(out, op2); + } + + __ j(Condition::kParityEven, &nan); + + __ j(is_min ? Condition::kAbove : Condition::kBelow, &op2_label); + __ j(is_min ? Condition::kBelow : Condition::kAbove, &done); + + // Handle 0.0/-0.0. + if (is_min) { + if (type == DataType::Type::kFloat64) { + __ orpd(out, op2); + } else { + __ orps(out, op2); + } + } else { + if (type == DataType::Type::kFloat64) { + __ andpd(out, op2); + } else { + __ andps(out, op2); + } + } + __ jmp(&done); + + // NaN handling. + __ Bind(&nan); + if (type == DataType::Type::kFloat64) { + // TODO: Use a constant from the constant table (requires extra input). + __ LoadLongConstant(out, kDoubleNaN); + } else { + Register constant = locations->GetTemp(0).AsRegister<Register>(); + __ movl(constant, Immediate(kFloatNaN)); + __ movd(out, constant); + } + __ jmp(&done); + + // out := op2; + __ Bind(&op2_label); + if (type == DataType::Type::kFloat64) { + __ movsd(out, op2); + } else { + __ movss(out, op2); + } + + // Done. + __ Bind(&done); +} + +void LocationsBuilderX86::VisitMin(HMin* min) { + CreateMinMaxLocations(GetGraph()->GetAllocator(), min); +} + +void InstructionCodeGeneratorX86::VisitMin(HMin* min) { + switch (min->GetResultType()) { + case DataType::Type::kInt32: + case DataType::Type::kInt64: + GenerateMinMax(min->GetLocations(), /*is_min*/ true, min->GetResultType()); + break; + case DataType::Type::kFloat32: + case DataType::Type::kFloat64: + GenerateMinMaxFP(min->GetLocations(), /*is_min*/ true, min->GetResultType()); + break; + default: + LOG(FATAL) << "Unexpected type for HMin " << min->GetResultType(); + } +} + +void LocationsBuilderX86::VisitMax(HMax* max) { + CreateMinMaxLocations(GetGraph()->GetAllocator(), max); +} + +void InstructionCodeGeneratorX86::VisitMax(HMax* max) { + switch (max->GetResultType()) { + case DataType::Type::kInt32: + case DataType::Type::kInt64: + GenerateMinMax(max->GetLocations(), /*is_min*/ false, max->GetResultType()); + break; + case DataType::Type::kFloat32: + case DataType::Type::kFloat64: + GenerateMinMaxFP(max->GetLocations(), /*is_min*/ false, max->GetResultType()); + break; + default: + LOG(FATAL) << "Unexpected type for HMax " << max->GetResultType(); + } +} + void LocationsBuilderX86::VisitAbs(HAbs* abs) { LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(abs); switch (abs->GetResultType()) { diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h index 51e5bca00b..82496d12e5 100644 --- a/compiler/optimizing/code_generator_x86.h +++ b/compiler/optimizing/code_generator_x86.h @@ -225,6 +225,8 @@ class InstructionCodeGeneratorX86 : public InstructionCodeGenerator { void GenerateShlLong(const Location& loc, int shift); void GenerateShrLong(const Location& loc, int shift); void GenerateUShrLong(const Location& loc, int shift); + void GenerateMinMax(LocationSummary* locations, bool is_min, DataType::Type type); + void GenerateMinMaxFP(LocationSummary* locations, bool is_min, DataType::Type type); void HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info, diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 0bb56a2b4a..bb1fbc5290 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -3821,6 +3821,183 @@ void InstructionCodeGeneratorX86_64::VisitRem(HRem* rem) { } } +static void CreateMinMaxLocations(ArenaAllocator* allocator, HBinaryOperation* minmax) { + LocationSummary* locations = new (allocator) LocationSummary(minmax); + switch (minmax->GetResultType()) { + case DataType::Type::kInt32: + case DataType::Type::kInt64: + locations->SetInAt(0, Location::RequiresRegister()); + locations->SetInAt(1, Location::RequiresRegister()); + locations->SetOut(Location::SameAsFirstInput()); + break; + case DataType::Type::kFloat32: + case DataType::Type::kFloat64: + locations->SetInAt(0, Location::RequiresFpuRegister()); + locations->SetInAt(1, Location::RequiresFpuRegister()); + // The following is sub-optimal, but all we can do for now. It would be fine to also accept + // the second input to be the output (we can simply swap inputs). + locations->SetOut(Location::SameAsFirstInput()); + break; + default: + LOG(FATAL) << "Unexpected type for HMinMax " << minmax->GetResultType(); + } +} + +void InstructionCodeGeneratorX86_64::GenerateMinMax(LocationSummary* locations, + bool is_min, + DataType::Type type) { + Location op1_loc = locations->InAt(0); + Location op2_loc = locations->InAt(1); + + // Shortcut for same input locations. + if (op1_loc.Equals(op2_loc)) { + // Can return immediately, as op1_loc == out_loc. + // Note: if we ever support separate registers, e.g., output into memory, we need to check for + // a copy here. + DCHECK(locations->Out().Equals(op1_loc)); + return; + } + + CpuRegister out = locations->Out().AsRegister<CpuRegister>(); + CpuRegister op2 = op2_loc.AsRegister<CpuRegister>(); + + // (out := op1) + // out <=? op2 + // if out is min jmp done + // out := op2 + // done: + + if (type == DataType::Type::kInt64) { + __ cmpq(out, op2); + __ cmov(is_min ? Condition::kGreater : Condition::kLess, out, op2, /*is64bit*/ true); + } else { + DCHECK_EQ(type, DataType::Type::kInt32); + __ cmpl(out, op2); + __ cmov(is_min ? Condition::kGreater : Condition::kLess, out, op2, /*is64bit*/ false); + } +} + +void InstructionCodeGeneratorX86_64::GenerateMinMaxFP(LocationSummary* locations, + bool is_min, + DataType::Type type) { + Location op1_loc = locations->InAt(0); + Location op2_loc = locations->InAt(1); + Location out_loc = locations->Out(); + XmmRegister out = out_loc.AsFpuRegister<XmmRegister>(); + + // Shortcut for same input locations. + if (op1_loc.Equals(op2_loc)) { + DCHECK(out_loc.Equals(op1_loc)); + return; + } + + // (out := op1) + // out <=? op2 + // if Nan jmp Nan_label + // if out is min jmp done + // if op2 is min jmp op2_label + // handle -0/+0 + // jmp done + // Nan_label: + // out := NaN + // op2_label: + // out := op2 + // done: + // + // This removes one jmp, but needs to copy one input (op1) to out. + // + // TODO: This is straight from Quick. Make NaN an out-of-line slowpath? + + XmmRegister op2 = op2_loc.AsFpuRegister<XmmRegister>(); + + NearLabel nan, done, op2_label; + if (type == DataType::Type::kFloat64) { + __ ucomisd(out, op2); + } else { + DCHECK_EQ(type, DataType::Type::kFloat32); + __ ucomiss(out, op2); + } + + __ j(Condition::kParityEven, &nan); + + __ j(is_min ? Condition::kAbove : Condition::kBelow, &op2_label); + __ j(is_min ? Condition::kBelow : Condition::kAbove, &done); + + // Handle 0.0/-0.0. + if (is_min) { + if (type == DataType::Type::kFloat64) { + __ orpd(out, op2); + } else { + __ orps(out, op2); + } + } else { + if (type == DataType::Type::kFloat64) { + __ andpd(out, op2); + } else { + __ andps(out, op2); + } + } + __ jmp(&done); + + // NaN handling. + __ Bind(&nan); + if (type == DataType::Type::kFloat64) { + __ movsd(out, codegen_->LiteralInt64Address(INT64_C(0x7FF8000000000000))); + } else { + __ movss(out, codegen_->LiteralInt32Address(INT32_C(0x7FC00000))); + } + __ jmp(&done); + + // out := op2; + __ Bind(&op2_label); + if (type == DataType::Type::kFloat64) { + __ movsd(out, op2); + } else { + __ movss(out, op2); + } + + // Done. + __ Bind(&done); +} + +void LocationsBuilderX86_64::VisitMin(HMin* min) { + CreateMinMaxLocations(GetGraph()->GetAllocator(), min); +} + +void InstructionCodeGeneratorX86_64::VisitMin(HMin* min) { + switch (min->GetResultType()) { + case DataType::Type::kInt32: + case DataType::Type::kInt64: + GenerateMinMax(min->GetLocations(), /*is_min*/ true, min->GetResultType()); + break; + case DataType::Type::kFloat32: + case DataType::Type::kFloat64: + GenerateMinMaxFP(min->GetLocations(), /*is_min*/ true, min->GetResultType()); + break; + default: + LOG(FATAL) << "Unexpected type for HMin " << min->GetResultType(); + } +} + +void LocationsBuilderX86_64::VisitMax(HMax* max) { + CreateMinMaxLocations(GetGraph()->GetAllocator(), max); +} + +void InstructionCodeGeneratorX86_64::VisitMax(HMax* max) { + switch (max->GetResultType()) { + case DataType::Type::kInt32: + case DataType::Type::kInt64: + GenerateMinMax(max->GetLocations(), /*is_min*/ false, max->GetResultType()); + break; + case DataType::Type::kFloat32: + case DataType::Type::kFloat64: + GenerateMinMaxFP(max->GetLocations(), /*is_min*/ false, max->GetResultType()); + break; + default: + LOG(FATAL) << "Unexpected type for HMax " << max->GetResultType(); + } +} + void LocationsBuilderX86_64::VisitAbs(HAbs* abs) { LocationSummary* locations = new (GetGraph()->GetAllocator()) LocationSummary(abs); switch (abs->GetResultType()) { diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h index 1079e94dfc..933afdab26 100644 --- a/compiler/optimizing/code_generator_x86_64.h +++ b/compiler/optimizing/code_generator_x86_64.h @@ -222,6 +222,9 @@ class InstructionCodeGeneratorX86_64 : public InstructionCodeGenerator { bool value_can_be_null); void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info); + void GenerateMinMax(LocationSummary* locations, bool is_min, DataType::Type type); + void GenerateMinMaxFP(LocationSummary* locations, bool is_min, DataType::Type type); + // Generate a heap reference load using one register `out`: // // out <- *(out + offset) diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc index ba4040acad..a0fd5ffcb1 100644 --- a/compiler/optimizing/codegen_test.cc +++ b/compiler/optimizing/codegen_test.cc @@ -18,6 +18,7 @@ #include <memory> #include "base/macros.h" +#include "base/utils.h" #include "builder.h" #include "codegen_test_utils.h" #include "dex/dex_file.h" @@ -26,7 +27,6 @@ #include "nodes.h" #include "optimizing_unit_test.h" #include "register_allocator_linear_scan.h" -#include "utils.h" #include "utils/arm/assembler_arm_vixl.h" #include "utils/arm/managed_register_arm.h" #include "utils/mips/managed_register_mips.h" diff --git a/compiler/optimizing/gvn.cc b/compiler/optimizing/gvn.cc index 71c394ec1f..f05159b735 100644 --- a/compiler/optimizing/gvn.cc +++ b/compiler/optimizing/gvn.cc @@ -17,11 +17,11 @@ #include "gvn.h" #include "base/arena_bit_vector.h" +#include "base/bit_vector-inl.h" #include "base/scoped_arena_allocator.h" #include "base/scoped_arena_containers.h" -#include "base/bit_vector-inl.h" +#include "base/utils.h" #include "side_effects_analysis.h" -#include "utils.h" namespace art { diff --git a/compiler/optimizing/induction_var_range.cc b/compiler/optimizing/induction_var_range.cc index d699d01ecb..0a310ca940 100644 --- a/compiler/optimizing/induction_var_range.cc +++ b/compiler/optimizing/induction_var_range.cc @@ -78,16 +78,10 @@ static bool IsGEZero(HInstruction* instruction) { DCHECK(instruction != nullptr); if (instruction->IsArrayLength()) { return true; - } else if (instruction->IsInvokeStaticOrDirect()) { - switch (instruction->AsInvoke()->GetIntrinsic()) { - case Intrinsics::kMathMinIntInt: - case Intrinsics::kMathMinLongLong: - // Instruction MIN(>=0, >=0) is >= 0. - return IsGEZero(instruction->InputAt(0)) && - IsGEZero(instruction->InputAt(1)); - default: - break; - } + } else if (instruction->IsMin()) { + // Instruction MIN(>=0, >=0) is >= 0. + return IsGEZero(instruction->InputAt(0)) && + IsGEZero(instruction->InputAt(1)); } else if (instruction->IsAbs()) { // Instruction ABS(>=0) is >= 0. // NOTE: ABS(minint) = minint prevents assuming @@ -101,21 +95,14 @@ static bool IsGEZero(HInstruction* instruction) { /** Hunts "under the hood" for a suitable instruction at the hint. */ static bool IsMaxAtHint( HInstruction* instruction, HInstruction* hint, /*out*/HInstruction** suitable) { - if (instruction->IsInvokeStaticOrDirect()) { - switch (instruction->AsInvoke()->GetIntrinsic()) { - case Intrinsics::kMathMinIntInt: - case Intrinsics::kMathMinLongLong: - // For MIN(x, y), return most suitable x or y as maximum. - return IsMaxAtHint(instruction->InputAt(0), hint, suitable) || - IsMaxAtHint(instruction->InputAt(1), hint, suitable); - default: - break; - } + if (instruction->IsMin()) { + // For MIN(x, y), return most suitable x or y as maximum. + return IsMaxAtHint(instruction->InputAt(0), hint, suitable) || + IsMaxAtHint(instruction->InputAt(1), hint, suitable); } else { *suitable = instruction; return HuntForDeclaration(instruction) == hint; } - return false; } /** Post-analysis simplification of a minimum value that makes the bound more useful to clients. */ @@ -364,11 +351,11 @@ void InductionVarRange::Replace(HInstruction* instruction, } } -bool InductionVarRange::IsFinite(HLoopInformation* loop, /*out*/ int64_t* tc) const { +bool InductionVarRange::IsFinite(HLoopInformation* loop, /*out*/ int64_t* trip_count) const { HInductionVarAnalysis::InductionInfo *trip = induction_analysis_->LookupInfo(loop, GetLoopControl(loop)); if (trip != nullptr && !IsUnsafeTripCount(trip)) { - IsConstant(trip->op_a, kExact, tc); + IsConstant(trip->op_a, kExact, trip_count); return true; } return false; diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc index eac8d2f593..34837700a2 100644 --- a/compiler/optimizing/instruction_simplifier.cc +++ b/compiler/optimizing/instruction_simplifier.cc @@ -120,6 +120,8 @@ class InstructionSimplifierVisitor : public HGraphDelegateVisitor { void SimplifyReturnThis(HInvoke* invoke); void SimplifyAllocationIntrinsic(HInvoke* invoke); void SimplifyMemBarrier(HInvoke* invoke, MemBarrierKind barrier_kind); + void SimplifyMin(HInvoke* invoke, DataType::Type type); + void SimplifyMax(HInvoke* invoke, DataType::Type type); void SimplifyAbs(HInvoke* invoke, DataType::Type type); CodeGenerator* codegen_; @@ -2407,6 +2409,20 @@ void InstructionSimplifierVisitor::SimplifyMemBarrier(HInvoke* invoke, invoke->GetBlock()->ReplaceAndRemoveInstructionWith(invoke, mem_barrier); } +void InstructionSimplifierVisitor::SimplifyMin(HInvoke* invoke, DataType::Type type) { + DCHECK(invoke->IsInvokeStaticOrDirect()); + HMin* min = new (GetGraph()->GetAllocator()) + HMin(type, invoke->InputAt(0), invoke->InputAt(1), invoke->GetDexPc()); + invoke->GetBlock()->ReplaceAndRemoveInstructionWith(invoke, min); +} + +void InstructionSimplifierVisitor::SimplifyMax(HInvoke* invoke, DataType::Type type) { + DCHECK(invoke->IsInvokeStaticOrDirect()); + HMax* max = new (GetGraph()->GetAllocator()) + HMax(type, invoke->InputAt(0), invoke->InputAt(1), invoke->GetDexPc()); + invoke->GetBlock()->ReplaceAndRemoveInstructionWith(invoke, max); +} + void InstructionSimplifierVisitor::SimplifyAbs(HInvoke* invoke, DataType::Type type) { DCHECK(invoke->IsInvokeStaticOrDirect()); HAbs* abs = new (GetGraph()->GetAllocator()) @@ -2497,6 +2513,30 @@ void InstructionSimplifierVisitor::VisitInvoke(HInvoke* instruction) { case Intrinsics::kVarHandleStoreStoreFence: SimplifyMemBarrier(instruction, MemBarrierKind::kStoreStore); break; + case Intrinsics::kMathMinIntInt: + SimplifyMin(instruction, DataType::Type::kInt32); + break; + case Intrinsics::kMathMinLongLong: + SimplifyMin(instruction, DataType::Type::kInt64); + break; + case Intrinsics::kMathMinFloatFloat: + SimplifyMin(instruction, DataType::Type::kFloat32); + break; + case Intrinsics::kMathMinDoubleDouble: + SimplifyMin(instruction, DataType::Type::kFloat64); + break; + case Intrinsics::kMathMaxIntInt: + SimplifyMax(instruction, DataType::Type::kInt32); + break; + case Intrinsics::kMathMaxLongLong: + SimplifyMax(instruction, DataType::Type::kInt64); + break; + case Intrinsics::kMathMaxFloatFloat: + SimplifyMax(instruction, DataType::Type::kFloat32); + break; + case Intrinsics::kMathMaxDoubleDouble: + SimplifyMax(instruction, DataType::Type::kFloat64); + break; case Intrinsics::kMathAbsInt: SimplifyAbs(instruction, DataType::Type::kInt32); break; diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc index acb830e524..f8dc316e45 100644 --- a/compiler/optimizing/intrinsics.cc +++ b/compiler/optimizing/intrinsics.cc @@ -18,6 +18,7 @@ #include "art_field-inl.h" #include "art_method-inl.h" +#include "base/utils.h" #include "class_linker.h" #include "dex/invoke_type.h" #include "driver/compiler_driver.h" @@ -26,7 +27,6 @@ #include "nodes.h" #include "scoped_thread_state_change-inl.h" #include "thread-current-inl.h" -#include "utils.h" namespace art { diff --git a/compiler/optimizing/intrinsics.h b/compiler/optimizing/intrinsics.h index 24aff226ca..1035cbc2c4 100644 --- a/compiler/optimizing/intrinsics.h +++ b/compiler/optimizing/intrinsics.h @@ -266,6 +266,14 @@ void IntrinsicCodeGenerator ## Arch::Visit ## Name(HInvoke* invoke) { \ << " should have been converted to HIR"; \ } #define UNREACHABLE_INTRINSICS(Arch) \ +UNREACHABLE_INTRINSIC(Arch, MathMinIntInt) \ +UNREACHABLE_INTRINSIC(Arch, MathMinLongLong) \ +UNREACHABLE_INTRINSIC(Arch, MathMinFloatFloat) \ +UNREACHABLE_INTRINSIC(Arch, MathMinDoubleDouble) \ +UNREACHABLE_INTRINSIC(Arch, MathMaxIntInt) \ +UNREACHABLE_INTRINSIC(Arch, MathMaxLongLong) \ +UNREACHABLE_INTRINSIC(Arch, MathMaxFloatFloat) \ +UNREACHABLE_INTRINSIC(Arch, MathMaxDoubleDouble) \ UNREACHABLE_INTRINSIC(Arch, MathAbsInt) \ UNREACHABLE_INTRINSIC(Arch, MathAbsLong) \ UNREACHABLE_INTRINSIC(Arch, MathAbsFloat) \ diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc index 0b04fff927..81c0b50932 100644 --- a/compiler/optimizing/intrinsics_arm64.cc +++ b/compiler/optimizing/intrinsics_arm64.cc @@ -344,14 +344,6 @@ void IntrinsicCodeGeneratorARM64::VisitShortReverseBytes(HInvoke* invoke) { GenReverseBytes(invoke->GetLocations(), DataType::Type::kInt16, GetVIXLAssembler()); } -static void CreateIntIntToIntLocations(ArenaAllocator* allocator, HInvoke* invoke) { - LocationSummary* locations = - new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified); - locations->SetInAt(0, Location::RequiresRegister()); - locations->SetInAt(1, Location::RequiresRegister()); - locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); -} - static void GenNumberOfLeadingZeros(LocationSummary* locations, DataType::Type type, MacroAssembler* masm) { @@ -529,113 +521,6 @@ void IntrinsicCodeGeneratorARM64::VisitLongLowestOneBit(HInvoke* invoke) { GenLowestOneBit(invoke, DataType::Type::kInt64, GetVIXLAssembler()); } -static void GenMinMaxFP(LocationSummary* locations, - bool is_min, - bool is_double, - MacroAssembler* masm) { - Location op1 = locations->InAt(0); - Location op2 = locations->InAt(1); - Location out = locations->Out(); - - FPRegister op1_reg = is_double ? DRegisterFrom(op1) : SRegisterFrom(op1); - FPRegister op2_reg = is_double ? DRegisterFrom(op2) : SRegisterFrom(op2); - FPRegister out_reg = is_double ? DRegisterFrom(out) : SRegisterFrom(out); - if (is_min) { - __ Fmin(out_reg, op1_reg, op2_reg); - } else { - __ Fmax(out_reg, op1_reg, op2_reg); - } -} - -static void CreateFPFPToFPLocations(ArenaAllocator* allocator, HInvoke* invoke) { - LocationSummary* locations = - new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified); - locations->SetInAt(0, Location::RequiresFpuRegister()); - locations->SetInAt(1, Location::RequiresFpuRegister()); - locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); -} - -void IntrinsicLocationsBuilderARM64::VisitMathMinDoubleDouble(HInvoke* invoke) { - CreateFPFPToFPLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorARM64::VisitMathMinDoubleDouble(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), /* is_min */ true, /* is_double */ true, GetVIXLAssembler()); -} - -void IntrinsicLocationsBuilderARM64::VisitMathMinFloatFloat(HInvoke* invoke) { - CreateFPFPToFPLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorARM64::VisitMathMinFloatFloat(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), /* is_min */ true, /* is_double */ false, GetVIXLAssembler()); -} - -void IntrinsicLocationsBuilderARM64::VisitMathMaxDoubleDouble(HInvoke* invoke) { - CreateFPFPToFPLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorARM64::VisitMathMaxDoubleDouble(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), /* is_min */ false, /* is_double */ true, GetVIXLAssembler()); -} - -void IntrinsicLocationsBuilderARM64::VisitMathMaxFloatFloat(HInvoke* invoke) { - CreateFPFPToFPLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorARM64::VisitMathMaxFloatFloat(HInvoke* invoke) { - GenMinMaxFP( - invoke->GetLocations(), /* is_min */ false, /* is_double */ false, GetVIXLAssembler()); -} - -static void GenMinMax(LocationSummary* locations, - bool is_min, - bool is_long, - MacroAssembler* masm) { - Location op1 = locations->InAt(0); - Location op2 = locations->InAt(1); - Location out = locations->Out(); - - Register op1_reg = is_long ? XRegisterFrom(op1) : WRegisterFrom(op1); - Register op2_reg = is_long ? XRegisterFrom(op2) : WRegisterFrom(op2); - Register out_reg = is_long ? XRegisterFrom(out) : WRegisterFrom(out); - - __ Cmp(op1_reg, op2_reg); - __ Csel(out_reg, op1_reg, op2_reg, is_min ? lt : gt); -} - -void IntrinsicLocationsBuilderARM64::VisitMathMinIntInt(HInvoke* invoke) { - CreateIntIntToIntLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorARM64::VisitMathMinIntInt(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), /* is_min */ true, /* is_long */ false, GetVIXLAssembler()); -} - -void IntrinsicLocationsBuilderARM64::VisitMathMinLongLong(HInvoke* invoke) { - CreateIntIntToIntLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorARM64::VisitMathMinLongLong(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), /* is_min */ true, /* is_long */ true, GetVIXLAssembler()); -} - -void IntrinsicLocationsBuilderARM64::VisitMathMaxIntInt(HInvoke* invoke) { - CreateIntIntToIntLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorARM64::VisitMathMaxIntInt(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), /* is_min */ false, /* is_long */ false, GetVIXLAssembler()); -} - -void IntrinsicLocationsBuilderARM64::VisitMathMaxLongLong(HInvoke* invoke) { - CreateIntIntToIntLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorARM64::VisitMathMaxLongLong(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), /* is_min */ false, /* is_long */ true, GetVIXLAssembler()); -} - static void CreateFPToFPLocations(ArenaAllocator* allocator, HInvoke* invoke) { LocationSummary* locations = new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified); diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc index e351fcc706..e61a0b0809 100644 --- a/compiler/optimizing/intrinsics_arm_vixl.cc +++ b/compiler/optimizing/intrinsics_arm_vixl.cc @@ -432,264 +432,6 @@ void IntrinsicCodeGeneratorARMVIXL::VisitLongNumberOfTrailingZeros(HInvoke* invo GenNumberOfTrailingZeros(invoke, DataType::Type::kInt64, codegen_); } -static void GenMinMaxFloat(HInvoke* invoke, bool is_min, CodeGeneratorARMVIXL* codegen) { - ArmVIXLAssembler* assembler = codegen->GetAssembler(); - Location op1_loc = invoke->GetLocations()->InAt(0); - Location op2_loc = invoke->GetLocations()->InAt(1); - Location out_loc = invoke->GetLocations()->Out(); - - // Optimization: don't generate any code if inputs are the same. - if (op1_loc.Equals(op2_loc)) { - DCHECK(out_loc.Equals(op1_loc)); // out_loc is set as SameAsFirstInput() in location builder. - return; - } - - vixl32::SRegister op1 = SRegisterFrom(op1_loc); - vixl32::SRegister op2 = SRegisterFrom(op2_loc); - vixl32::SRegister out = OutputSRegister(invoke); - UseScratchRegisterScope temps(assembler->GetVIXLAssembler()); - const vixl32::Register temp1 = temps.Acquire(); - vixl32::Register temp2 = RegisterFrom(invoke->GetLocations()->GetTemp(0)); - vixl32::Label nan, done; - vixl32::Label* final_label = codegen->GetFinalLabel(invoke, &done); - - DCHECK(op1.Is(out)); - - __ Vcmp(op1, op2); - __ Vmrs(RegisterOrAPSR_nzcv(kPcCode), FPSCR); - __ B(vs, &nan, /* far_target */ false); // if un-ordered, go to NaN handling. - - // op1 <> op2 - vixl32::ConditionType cond = is_min ? gt : lt; - { - ExactAssemblyScope it_scope(assembler->GetVIXLAssembler(), - 2 * kMaxInstructionSizeInBytes, - CodeBufferCheckScope::kMaximumSize); - __ it(cond); - __ vmov(cond, F32, out, op2); - } - // for <>(not equal), we've done min/max calculation. - __ B(ne, final_label, /* far_target */ false); - - // handle op1 == op2, max(+0.0,-0.0), min(+0.0,-0.0). - __ Vmov(temp1, op1); - __ Vmov(temp2, op2); - if (is_min) { - __ Orr(temp1, temp1, temp2); - } else { - __ And(temp1, temp1, temp2); - } - __ Vmov(out, temp1); - __ B(final_label); - - // handle NaN input. - __ Bind(&nan); - __ Movt(temp1, High16Bits(kNanFloat)); // 0x7FC0xxxx is a NaN. - __ Vmov(out, temp1); - - if (done.IsReferenced()) { - __ Bind(&done); - } -} - -static void CreateFPFPToFPLocations(ArenaAllocator* allocator, HInvoke* invoke) { - LocationSummary* locations = - new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified); - locations->SetInAt(0, Location::RequiresFpuRegister()); - locations->SetInAt(1, Location::RequiresFpuRegister()); - locations->SetOut(Location::SameAsFirstInput()); -} - -void IntrinsicLocationsBuilderARMVIXL::VisitMathMinFloatFloat(HInvoke* invoke) { - CreateFPFPToFPLocations(allocator_, invoke); - invoke->GetLocations()->AddTemp(Location::RequiresRegister()); -} - -void IntrinsicCodeGeneratorARMVIXL::VisitMathMinFloatFloat(HInvoke* invoke) { - GenMinMaxFloat(invoke, /* is_min */ true, codegen_); -} - -void IntrinsicLocationsBuilderARMVIXL::VisitMathMaxFloatFloat(HInvoke* invoke) { - CreateFPFPToFPLocations(allocator_, invoke); - invoke->GetLocations()->AddTemp(Location::RequiresRegister()); -} - -void IntrinsicCodeGeneratorARMVIXL::VisitMathMaxFloatFloat(HInvoke* invoke) { - GenMinMaxFloat(invoke, /* is_min */ false, codegen_); -} - -static void GenMinMaxDouble(HInvoke* invoke, bool is_min, CodeGeneratorARMVIXL* codegen) { - ArmVIXLAssembler* assembler = codegen->GetAssembler(); - Location op1_loc = invoke->GetLocations()->InAt(0); - Location op2_loc = invoke->GetLocations()->InAt(1); - Location out_loc = invoke->GetLocations()->Out(); - - // Optimization: don't generate any code if inputs are the same. - if (op1_loc.Equals(op2_loc)) { - DCHECK(out_loc.Equals(op1_loc)); // out_loc is set as SameAsFirstInput() in. - return; - } - - vixl32::DRegister op1 = DRegisterFrom(op1_loc); - vixl32::DRegister op2 = DRegisterFrom(op2_loc); - vixl32::DRegister out = OutputDRegister(invoke); - vixl32::Label handle_nan_eq, done; - vixl32::Label* final_label = codegen->GetFinalLabel(invoke, &done); - - DCHECK(op1.Is(out)); - - __ Vcmp(op1, op2); - __ Vmrs(RegisterOrAPSR_nzcv(kPcCode), FPSCR); - __ B(vs, &handle_nan_eq, /* far_target */ false); // if un-ordered, go to NaN handling. - - // op1 <> op2 - vixl32::ConditionType cond = is_min ? gt : lt; - { - ExactAssemblyScope it_scope(assembler->GetVIXLAssembler(), - 2 * kMaxInstructionSizeInBytes, - CodeBufferCheckScope::kMaximumSize); - __ it(cond); - __ vmov(cond, F64, out, op2); - } - // for <>(not equal), we've done min/max calculation. - __ B(ne, final_label, /* far_target */ false); - - // handle op1 == op2, max(+0.0,-0.0). - if (!is_min) { - __ Vand(F64, out, op1, op2); - __ B(final_label); - } - - // handle op1 == op2, min(+0.0,-0.0), NaN input. - __ Bind(&handle_nan_eq); - __ Vorr(F64, out, op1, op2); // assemble op1/-0.0/NaN. - - if (done.IsReferenced()) { - __ Bind(&done); - } -} - -void IntrinsicLocationsBuilderARMVIXL::VisitMathMinDoubleDouble(HInvoke* invoke) { - CreateFPFPToFPLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorARMVIXL::VisitMathMinDoubleDouble(HInvoke* invoke) { - GenMinMaxDouble(invoke, /* is_min */ true , codegen_); -} - -void IntrinsicLocationsBuilderARMVIXL::VisitMathMaxDoubleDouble(HInvoke* invoke) { - CreateFPFPToFPLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorARMVIXL::VisitMathMaxDoubleDouble(HInvoke* invoke) { - GenMinMaxDouble(invoke, /* is_min */ false, codegen_); -} - -static void GenMinMaxLong(HInvoke* invoke, bool is_min, ArmVIXLAssembler* assembler) { - Location op1_loc = invoke->GetLocations()->InAt(0); - Location op2_loc = invoke->GetLocations()->InAt(1); - Location out_loc = invoke->GetLocations()->Out(); - - // Optimization: don't generate any code if inputs are the same. - if (op1_loc.Equals(op2_loc)) { - DCHECK(out_loc.Equals(op1_loc)); // out_loc is set as SameAsFirstInput() in location builder. - return; - } - - vixl32::Register op1_lo = LowRegisterFrom(op1_loc); - vixl32::Register op1_hi = HighRegisterFrom(op1_loc); - vixl32::Register op2_lo = LowRegisterFrom(op2_loc); - vixl32::Register op2_hi = HighRegisterFrom(op2_loc); - vixl32::Register out_lo = LowRegisterFrom(out_loc); - vixl32::Register out_hi = HighRegisterFrom(out_loc); - UseScratchRegisterScope temps(assembler->GetVIXLAssembler()); - const vixl32::Register temp = temps.Acquire(); - - DCHECK(op1_lo.Is(out_lo)); - DCHECK(op1_hi.Is(out_hi)); - - // Compare op1 >= op2, or op1 < op2. - __ Cmp(out_lo, op2_lo); - __ Sbcs(temp, out_hi, op2_hi); - - // Now GE/LT condition code is correct for the long comparison. - { - vixl32::ConditionType cond = is_min ? ge : lt; - ExactAssemblyScope it_scope(assembler->GetVIXLAssembler(), - 3 * kMaxInstructionSizeInBytes, - CodeBufferCheckScope::kMaximumSize); - __ itt(cond); - __ mov(cond, out_lo, op2_lo); - __ mov(cond, out_hi, op2_hi); - } -} - -static void CreateLongLongToLongLocations(ArenaAllocator* allocator, HInvoke* invoke) { - LocationSummary* locations = - new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified); - locations->SetInAt(0, Location::RequiresRegister()); - locations->SetInAt(1, Location::RequiresRegister()); - locations->SetOut(Location::SameAsFirstInput()); -} - -void IntrinsicLocationsBuilderARMVIXL::VisitMathMinLongLong(HInvoke* invoke) { - CreateLongLongToLongLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorARMVIXL::VisitMathMinLongLong(HInvoke* invoke) { - GenMinMaxLong(invoke, /* is_min */ true, GetAssembler()); -} - -void IntrinsicLocationsBuilderARMVIXL::VisitMathMaxLongLong(HInvoke* invoke) { - CreateLongLongToLongLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorARMVIXL::VisitMathMaxLongLong(HInvoke* invoke) { - GenMinMaxLong(invoke, /* is_min */ false, GetAssembler()); -} - -static void GenMinMax(HInvoke* invoke, bool is_min, ArmVIXLAssembler* assembler) { - vixl32::Register op1 = InputRegisterAt(invoke, 0); - vixl32::Register op2 = InputRegisterAt(invoke, 1); - vixl32::Register out = OutputRegister(invoke); - - __ Cmp(op1, op2); - - { - ExactAssemblyScope aas(assembler->GetVIXLAssembler(), - 3 * kMaxInstructionSizeInBytes, - CodeBufferCheckScope::kMaximumSize); - - __ ite(is_min ? lt : gt); - __ mov(is_min ? lt : gt, out, op1); - __ mov(is_min ? ge : le, out, op2); - } -} - -static void CreateIntIntToIntLocations(ArenaAllocator* allocator, HInvoke* invoke) { - LocationSummary* locations = - new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified); - locations->SetInAt(0, Location::RequiresRegister()); - locations->SetInAt(1, Location::RequiresRegister()); - locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); -} - -void IntrinsicLocationsBuilderARMVIXL::VisitMathMinIntInt(HInvoke* invoke) { - CreateIntIntToIntLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorARMVIXL::VisitMathMinIntInt(HInvoke* invoke) { - GenMinMax(invoke, /* is_min */ true, GetAssembler()); -} - -void IntrinsicLocationsBuilderARMVIXL::VisitMathMaxIntInt(HInvoke* invoke) { - CreateIntIntToIntLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorARMVIXL::VisitMathMaxIntInt(HInvoke* invoke) { - GenMinMax(invoke, /* is_min */ false, GetAssembler()); -} - void IntrinsicLocationsBuilderARMVIXL::VisitMathSqrt(HInvoke* invoke) { CreateFPToFPLocations(allocator_, invoke); } diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc index 6d6ff7576b..bc1292b2b7 100644 --- a/compiler/optimizing/intrinsics_mips.cc +++ b/compiler/optimizing/intrinsics_mips.cc @@ -58,6 +58,10 @@ inline bool IntrinsicCodeGeneratorMIPS::Is32BitFPU() const { return codegen_->GetInstructionSetFeatures().Is32BitFloatingPoint(); } +inline bool IntrinsicCodeGeneratorMIPS::HasMsa() const { + return codegen_->GetInstructionSetFeatures().HasMsa(); +} + #define __ codegen->GetAssembler()-> static void MoveFromReturnRegister(Location trg, @@ -612,6 +616,7 @@ static void CreateFPToFPLocations(ArenaAllocator* allocator, HInvoke* invoke) { static void GenBitCount(LocationSummary* locations, DataType::Type type, bool isR6, + bool hasMsa, MipsAssembler* assembler) { Register out = locations->Out().AsRegister<Register>(); @@ -637,85 +642,102 @@ static void GenBitCount(LocationSummary* locations, // instructions compared to a loop-based algorithm which required 47 // instructions. - if (type == DataType::Type::kInt32) { - Register in = locations->InAt(0).AsRegister<Register>(); - - __ Srl(TMP, in, 1); - __ LoadConst32(AT, 0x55555555); - __ And(TMP, TMP, AT); - __ Subu(TMP, in, TMP); - __ LoadConst32(AT, 0x33333333); - __ And(out, TMP, AT); - __ Srl(TMP, TMP, 2); - __ And(TMP, TMP, AT); - __ Addu(TMP, out, TMP); - __ Srl(out, TMP, 4); - __ Addu(out, out, TMP); - __ LoadConst32(AT, 0x0F0F0F0F); - __ And(out, out, AT); - __ LoadConst32(TMP, 0x01010101); - if (isR6) { - __ MulR6(out, out, TMP); + if (hasMsa) { + if (type == DataType::Type::kInt32) { + Register in = locations->InAt(0).AsRegister<Register>(); + __ Mtc1(in, FTMP); + __ PcntW(static_cast<VectorRegister>(FTMP), static_cast<VectorRegister>(FTMP)); + __ Mfc1(out, FTMP); } else { - __ MulR2(out, out, TMP); + DCHECK_EQ(type, DataType::Type::kInt64); + Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>(); + Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>(); + __ Mtc1(in_lo, FTMP); + __ Mthc1(in_hi, FTMP); + __ PcntD(static_cast<VectorRegister>(FTMP), static_cast<VectorRegister>(FTMP)); + __ Mfc1(out, FTMP); } - __ Srl(out, out, 24); } else { - DCHECK_EQ(type, DataType::Type::kInt64); - Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>(); - Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>(); - Register tmp_hi = locations->GetTemp(0).AsRegister<Register>(); - Register out_hi = locations->GetTemp(1).AsRegister<Register>(); - Register tmp_lo = TMP; - Register out_lo = out; + if (type == DataType::Type::kInt32) { + Register in = locations->InAt(0).AsRegister<Register>(); - __ Srl(tmp_lo, in_lo, 1); - __ Srl(tmp_hi, in_hi, 1); + __ Srl(TMP, in, 1); + __ LoadConst32(AT, 0x55555555); + __ And(TMP, TMP, AT); + __ Subu(TMP, in, TMP); + __ LoadConst32(AT, 0x33333333); + __ And(out, TMP, AT); + __ Srl(TMP, TMP, 2); + __ And(TMP, TMP, AT); + __ Addu(TMP, out, TMP); + __ Srl(out, TMP, 4); + __ Addu(out, out, TMP); + __ LoadConst32(AT, 0x0F0F0F0F); + __ And(out, out, AT); + __ LoadConst32(TMP, 0x01010101); + if (isR6) { + __ MulR6(out, out, TMP); + } else { + __ MulR2(out, out, TMP); + } + __ Srl(out, out, 24); + } else { + DCHECK_EQ(type, DataType::Type::kInt64); + Register in_lo = locations->InAt(0).AsRegisterPairLow<Register>(); + Register in_hi = locations->InAt(0).AsRegisterPairHigh<Register>(); + Register tmp_hi = locations->GetTemp(0).AsRegister<Register>(); + Register out_hi = locations->GetTemp(1).AsRegister<Register>(); + Register tmp_lo = TMP; + Register out_lo = out; - __ LoadConst32(AT, 0x55555555); + __ Srl(tmp_lo, in_lo, 1); + __ Srl(tmp_hi, in_hi, 1); - __ And(tmp_lo, tmp_lo, AT); - __ Subu(tmp_lo, in_lo, tmp_lo); + __ LoadConst32(AT, 0x55555555); - __ And(tmp_hi, tmp_hi, AT); - __ Subu(tmp_hi, in_hi, tmp_hi); + __ And(tmp_lo, tmp_lo, AT); + __ Subu(tmp_lo, in_lo, tmp_lo); - __ LoadConst32(AT, 0x33333333); + __ And(tmp_hi, tmp_hi, AT); + __ Subu(tmp_hi, in_hi, tmp_hi); - __ And(out_lo, tmp_lo, AT); - __ Srl(tmp_lo, tmp_lo, 2); - __ And(tmp_lo, tmp_lo, AT); - __ Addu(tmp_lo, out_lo, tmp_lo); + __ LoadConst32(AT, 0x33333333); - __ And(out_hi, tmp_hi, AT); - __ Srl(tmp_hi, tmp_hi, 2); - __ And(tmp_hi, tmp_hi, AT); - __ Addu(tmp_hi, out_hi, tmp_hi); + __ And(out_lo, tmp_lo, AT); + __ Srl(tmp_lo, tmp_lo, 2); + __ And(tmp_lo, tmp_lo, AT); + __ Addu(tmp_lo, out_lo, tmp_lo); - // Here we deviate from the original algorithm a bit. We've reached - // the stage where the bitfields holding the subtotals are large - // enough to hold the combined subtotals for both the low word, and - // the high word. This means that we can add the subtotals for the - // the high, and low words into a single word, and compute the final - // result for both the high, and low words using fewer instructions. - __ LoadConst32(AT, 0x0F0F0F0F); + __ And(out_hi, tmp_hi, AT); + __ Srl(tmp_hi, tmp_hi, 2); + __ And(tmp_hi, tmp_hi, AT); + __ Addu(tmp_hi, out_hi, tmp_hi); - __ Addu(TMP, tmp_hi, tmp_lo); + // Here we deviate from the original algorithm a bit. We've reached + // the stage where the bitfields holding the subtotals are large + // enough to hold the combined subtotals for both the low word, and + // the high word. This means that we can add the subtotals for the + // the high, and low words into a single word, and compute the final + // result for both the high, and low words using fewer instructions. + __ LoadConst32(AT, 0x0F0F0F0F); - __ Srl(out, TMP, 4); - __ And(out, out, AT); - __ And(TMP, TMP, AT); - __ Addu(out, out, TMP); + __ Addu(TMP, tmp_hi, tmp_lo); - __ LoadConst32(AT, 0x01010101); + __ Srl(out, TMP, 4); + __ And(out, out, AT); + __ And(TMP, TMP, AT); + __ Addu(out, out, TMP); - if (isR6) { - __ MulR6(out, out, AT); - } else { - __ MulR2(out, out, AT); - } + __ LoadConst32(AT, 0x01010101); - __ Srl(out, out, 24); + if (isR6) { + __ MulR6(out, out, AT); + } else { + __ MulR2(out, out, AT); + } + + __ Srl(out, out, 24); + } } } @@ -725,7 +747,7 @@ void IntrinsicLocationsBuilderMIPS::VisitIntegerBitCount(HInvoke* invoke) { } void IntrinsicCodeGeneratorMIPS::VisitIntegerBitCount(HInvoke* invoke) { - GenBitCount(invoke->GetLocations(), DataType::Type::kInt32, IsR6(), GetAssembler()); + GenBitCount(invoke->GetLocations(), DataType::Type::kInt32, IsR6(), HasMsa(), GetAssembler()); } // int java.lang.Long.bitCount(int) @@ -739,459 +761,7 @@ void IntrinsicLocationsBuilderMIPS::VisitLongBitCount(HInvoke* invoke) { } void IntrinsicCodeGeneratorMIPS::VisitLongBitCount(HInvoke* invoke) { - GenBitCount(invoke->GetLocations(), DataType::Type::kInt64, IsR6(), GetAssembler()); -} - -static void GenMinMaxFP(LocationSummary* locations, - bool is_min, - DataType::Type type, - bool is_R6, - MipsAssembler* assembler) { - FRegister out = locations->Out().AsFpuRegister<FRegister>(); - FRegister a = locations->InAt(0).AsFpuRegister<FRegister>(); - FRegister b = locations->InAt(1).AsFpuRegister<FRegister>(); - - if (is_R6) { - MipsLabel noNaNs; - MipsLabel done; - FRegister ftmp = ((out != a) && (out != b)) ? out : FTMP; - - // When Java computes min/max it prefers a NaN to a number; the - // behavior of MIPSR6 is to prefer numbers to NaNs, i.e., if one of - // the inputs is a NaN and the other is a valid number, the MIPS - // instruction will return the number; Java wants the NaN value - // returned. This is why there is extra logic preceding the use of - // the MIPS min.fmt/max.fmt instructions. If either a, or b holds a - // NaN, return the NaN, otherwise return the min/max. - if (type == DataType::Type::kFloat64) { - __ CmpUnD(FTMP, a, b); - __ Bc1eqz(FTMP, &noNaNs); - - // One of the inputs is a NaN - __ CmpEqD(ftmp, a, a); - // If a == a then b is the NaN, otherwise a is the NaN. - __ SelD(ftmp, a, b); - - if (ftmp != out) { - __ MovD(out, ftmp); - } - - __ B(&done); - - __ Bind(&noNaNs); - - if (is_min) { - __ MinD(out, a, b); - } else { - __ MaxD(out, a, b); - } - } else { - DCHECK_EQ(type, DataType::Type::kFloat32); - __ CmpUnS(FTMP, a, b); - __ Bc1eqz(FTMP, &noNaNs); - - // One of the inputs is a NaN - __ CmpEqS(ftmp, a, a); - // If a == a then b is the NaN, otherwise a is the NaN. - __ SelS(ftmp, a, b); - - if (ftmp != out) { - __ MovS(out, ftmp); - } - - __ B(&done); - - __ Bind(&noNaNs); - - if (is_min) { - __ MinS(out, a, b); - } else { - __ MaxS(out, a, b); - } - } - - __ Bind(&done); - } else { - MipsLabel ordered; - MipsLabel compare; - MipsLabel select; - MipsLabel done; - - if (type == DataType::Type::kFloat64) { - __ CunD(a, b); - } else { - DCHECK_EQ(type, DataType::Type::kFloat32); - __ CunS(a, b); - } - __ Bc1f(&ordered); - - // a or b (or both) is a NaN. Return one, which is a NaN. - if (type == DataType::Type::kFloat64) { - __ CeqD(b, b); - } else { - __ CeqS(b, b); - } - __ B(&select); - - __ Bind(&ordered); - - // Neither is a NaN. - // a == b? (-0.0 compares equal with +0.0) - // If equal, handle zeroes, else compare further. - if (type == DataType::Type::kFloat64) { - __ CeqD(a, b); - } else { - __ CeqS(a, b); - } - __ Bc1f(&compare); - - // a == b either bit for bit or one is -0.0 and the other is +0.0. - if (type == DataType::Type::kFloat64) { - __ MoveFromFpuHigh(TMP, a); - __ MoveFromFpuHigh(AT, b); - } else { - __ Mfc1(TMP, a); - __ Mfc1(AT, b); - } - - if (is_min) { - // -0.0 prevails over +0.0. - __ Or(TMP, TMP, AT); - } else { - // +0.0 prevails over -0.0. - __ And(TMP, TMP, AT); - } - - if (type == DataType::Type::kFloat64) { - __ Mfc1(AT, a); - __ Mtc1(AT, out); - __ MoveToFpuHigh(TMP, out); - } else { - __ Mtc1(TMP, out); - } - __ B(&done); - - __ Bind(&compare); - - if (type == DataType::Type::kFloat64) { - if (is_min) { - // return (a <= b) ? a : b; - __ ColeD(a, b); - } else { - // return (a >= b) ? a : b; - __ ColeD(b, a); // b <= a - } - } else { - if (is_min) { - // return (a <= b) ? a : b; - __ ColeS(a, b); - } else { - // return (a >= b) ? a : b; - __ ColeS(b, a); // b <= a - } - } - - __ Bind(&select); - - if (type == DataType::Type::kFloat64) { - __ MovtD(out, a); - __ MovfD(out, b); - } else { - __ MovtS(out, a); - __ MovfS(out, b); - } - - __ Bind(&done); - } -} - -static void CreateFPFPToFPLocations(ArenaAllocator* allocator, HInvoke* invoke) { - LocationSummary* locations = - new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified); - locations->SetInAt(0, Location::RequiresFpuRegister()); - locations->SetInAt(1, Location::RequiresFpuRegister()); - locations->SetOut(Location::RequiresFpuRegister(), Location::kOutputOverlap); -} - -// double java.lang.Math.min(double, double) -void IntrinsicLocationsBuilderMIPS::VisitMathMinDoubleDouble(HInvoke* invoke) { - CreateFPFPToFPLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorMIPS::VisitMathMinDoubleDouble(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), - /* is_min */ true, - DataType::Type::kFloat64, - IsR6(), - GetAssembler()); -} - -// float java.lang.Math.min(float, float) -void IntrinsicLocationsBuilderMIPS::VisitMathMinFloatFloat(HInvoke* invoke) { - CreateFPFPToFPLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorMIPS::VisitMathMinFloatFloat(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), - /* is_min */ true, - DataType::Type::kFloat32, - IsR6(), - GetAssembler()); -} - -// double java.lang.Math.max(double, double) -void IntrinsicLocationsBuilderMIPS::VisitMathMaxDoubleDouble(HInvoke* invoke) { - CreateFPFPToFPLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorMIPS::VisitMathMaxDoubleDouble(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), - /* is_min */ false, - DataType::Type::kFloat64, - IsR6(), - GetAssembler()); -} - -// float java.lang.Math.max(float, float) -void IntrinsicLocationsBuilderMIPS::VisitMathMaxFloatFloat(HInvoke* invoke) { - CreateFPFPToFPLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorMIPS::VisitMathMaxFloatFloat(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), - /* is_min */ false, - DataType::Type::kFloat32, - IsR6(), - GetAssembler()); -} - -static void CreateIntIntToIntLocations(ArenaAllocator* allocator, HInvoke* invoke) { - LocationSummary* locations = - new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified); - locations->SetInAt(0, Location::RequiresRegister()); - locations->SetInAt(1, Location::RequiresRegister()); - locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); -} - -static void GenMinMax(LocationSummary* locations, - bool is_min, - DataType::Type type, - bool is_R6, - MipsAssembler* assembler) { - if (is_R6) { - // Some architectures, such as ARM and MIPS (prior to r6), have a - // conditional move instruction which only changes the target - // (output) register if the condition is true (MIPS prior to r6 had - // MOVF, MOVT, MOVN, and MOVZ). The SELEQZ and SELNEZ instructions - // always change the target (output) register. If the condition is - // true the output register gets the contents of the "rs" register; - // otherwise, the output register is set to zero. One consequence - // of this is that to implement something like "rd = c==0 ? rs : rt" - // MIPS64r6 needs to use a pair of SELEQZ/SELNEZ instructions. - // After executing this pair of instructions one of the output - // registers from the pair will necessarily contain zero. Then the - // code ORs the output registers from the SELEQZ/SELNEZ instructions - // to get the final result. - // - // The initial test to see if the output register is same as the - // first input register is needed to make sure that value in the - // first input register isn't clobbered before we've finished - // computing the output value. The logic in the corresponding else - // clause performs the same task but makes sure the second input - // register isn't clobbered in the event that it's the same register - // as the output register; the else clause also handles the case - // where the output register is distinct from both the first, and the - // second input registers. - if (type == DataType::Type::kInt64) { - Register a_lo = locations->InAt(0).AsRegisterPairLow<Register>(); - Register a_hi = locations->InAt(0).AsRegisterPairHigh<Register>(); - Register b_lo = locations->InAt(1).AsRegisterPairLow<Register>(); - Register b_hi = locations->InAt(1).AsRegisterPairHigh<Register>(); - Register out_lo = locations->Out().AsRegisterPairLow<Register>(); - Register out_hi = locations->Out().AsRegisterPairHigh<Register>(); - - MipsLabel compare_done; - - if (a_lo == b_lo) { - if (out_lo != a_lo) { - __ Move(out_lo, a_lo); - __ Move(out_hi, a_hi); - } - } else { - __ Slt(TMP, b_hi, a_hi); - __ Bne(b_hi, a_hi, &compare_done); - - __ Sltu(TMP, b_lo, a_lo); - - __ Bind(&compare_done); - - if (is_min) { - __ Seleqz(AT, a_lo, TMP); - __ Selnez(out_lo, b_lo, TMP); // Safe even if out_lo == a_lo/b_lo - // because at this point we're - // done using a_lo/b_lo. - } else { - __ Selnez(AT, a_lo, TMP); - __ Seleqz(out_lo, b_lo, TMP); // ditto - } - __ Or(out_lo, out_lo, AT); - if (is_min) { - __ Seleqz(AT, a_hi, TMP); - __ Selnez(out_hi, b_hi, TMP); // ditto but for out_hi & a_hi/b_hi - } else { - __ Selnez(AT, a_hi, TMP); - __ Seleqz(out_hi, b_hi, TMP); // ditto but for out_hi & a_hi/b_hi - } - __ Or(out_hi, out_hi, AT); - } - } else { - DCHECK_EQ(type, DataType::Type::kInt32); - Register a = locations->InAt(0).AsRegister<Register>(); - Register b = locations->InAt(1).AsRegister<Register>(); - Register out = locations->Out().AsRegister<Register>(); - - if (a == b) { - if (out != a) { - __ Move(out, a); - } - } else { - __ Slt(AT, b, a); - if (is_min) { - __ Seleqz(TMP, a, AT); - __ Selnez(AT, b, AT); - } else { - __ Selnez(TMP, a, AT); - __ Seleqz(AT, b, AT); - } - __ Or(out, TMP, AT); - } - } - } else { - if (type == DataType::Type::kInt64) { - Register a_lo = locations->InAt(0).AsRegisterPairLow<Register>(); - Register a_hi = locations->InAt(0).AsRegisterPairHigh<Register>(); - Register b_lo = locations->InAt(1).AsRegisterPairLow<Register>(); - Register b_hi = locations->InAt(1).AsRegisterPairHigh<Register>(); - Register out_lo = locations->Out().AsRegisterPairLow<Register>(); - Register out_hi = locations->Out().AsRegisterPairHigh<Register>(); - - MipsLabel compare_done; - - if (a_lo == b_lo) { - if (out_lo != a_lo) { - __ Move(out_lo, a_lo); - __ Move(out_hi, a_hi); - } - } else { - __ Slt(TMP, a_hi, b_hi); - __ Bne(a_hi, b_hi, &compare_done); - - __ Sltu(TMP, a_lo, b_lo); - - __ Bind(&compare_done); - - if (is_min) { - if (out_lo != a_lo) { - __ Movn(out_hi, a_hi, TMP); - __ Movn(out_lo, a_lo, TMP); - } - if (out_lo != b_lo) { - __ Movz(out_hi, b_hi, TMP); - __ Movz(out_lo, b_lo, TMP); - } - } else { - if (out_lo != a_lo) { - __ Movz(out_hi, a_hi, TMP); - __ Movz(out_lo, a_lo, TMP); - } - if (out_lo != b_lo) { - __ Movn(out_hi, b_hi, TMP); - __ Movn(out_lo, b_lo, TMP); - } - } - } - } else { - DCHECK_EQ(type, DataType::Type::kInt32); - Register a = locations->InAt(0).AsRegister<Register>(); - Register b = locations->InAt(1).AsRegister<Register>(); - Register out = locations->Out().AsRegister<Register>(); - - if (a == b) { - if (out != a) { - __ Move(out, a); - } - } else { - __ Slt(AT, a, b); - if (is_min) { - if (out != a) { - __ Movn(out, a, AT); - } - if (out != b) { - __ Movz(out, b, AT); - } - } else { - if (out != a) { - __ Movz(out, a, AT); - } - if (out != b) { - __ Movn(out, b, AT); - } - } - } - } - } -} - -// int java.lang.Math.min(int, int) -void IntrinsicLocationsBuilderMIPS::VisitMathMinIntInt(HInvoke* invoke) { - CreateIntIntToIntLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorMIPS::VisitMathMinIntInt(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), - /* is_min */ true, - DataType::Type::kInt32, - IsR6(), - GetAssembler()); -} - -// long java.lang.Math.min(long, long) -void IntrinsicLocationsBuilderMIPS::VisitMathMinLongLong(HInvoke* invoke) { - CreateIntIntToIntLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorMIPS::VisitMathMinLongLong(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), - /* is_min */ true, - DataType::Type::kInt64, - IsR6(), - GetAssembler()); -} - -// int java.lang.Math.max(int, int) -void IntrinsicLocationsBuilderMIPS::VisitMathMaxIntInt(HInvoke* invoke) { - CreateIntIntToIntLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorMIPS::VisitMathMaxIntInt(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), - /* is_min */ false, - DataType::Type::kInt32, - IsR6(), - GetAssembler()); -} - -// long java.lang.Math.max(long, long) -void IntrinsicLocationsBuilderMIPS::VisitMathMaxLongLong(HInvoke* invoke) { - CreateIntIntToIntLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorMIPS::VisitMathMaxLongLong(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), - /* is_min */ false, - DataType::Type::kInt64, - IsR6(), - GetAssembler()); + GenBitCount(invoke->GetLocations(), DataType::Type::kInt64, IsR6(), HasMsa(), GetAssembler()); } // double java.lang.Math.sqrt(double) diff --git a/compiler/optimizing/intrinsics_mips.h b/compiler/optimizing/intrinsics_mips.h index 13397f11d4..1c1ba40132 100644 --- a/compiler/optimizing/intrinsics_mips.h +++ b/compiler/optimizing/intrinsics_mips.h @@ -71,6 +71,7 @@ class IntrinsicCodeGeneratorMIPS FINAL : public IntrinsicVisitor { bool IsR2OrNewer() const; bool IsR6() const; bool Is32BitFPU() const; + bool HasMsa() const; private: MipsAssembler* GetAssembler(); diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc index 5debd26c5a..f429afde2c 100644 --- a/compiler/optimizing/intrinsics_mips64.cc +++ b/compiler/optimizing/intrinsics_mips64.cc @@ -46,6 +46,10 @@ ArenaAllocator* IntrinsicCodeGeneratorMIPS64::GetAllocator() { return codegen_->GetGraph()->GetAllocator(); } +inline bool IntrinsicCodeGeneratorMIPS64::HasMsa() const { + return codegen_->GetInstructionSetFeatures().HasMsa(); +} + #define __ codegen->GetAssembler()-> static void MoveFromReturnRegister(Location trg, @@ -386,6 +390,7 @@ static void CreateFPToFPLocations(ArenaAllocator* allocator, HInvoke* invoke) { static void GenBitCount(LocationSummary* locations, const DataType::Type type, + const bool hasMsa, Mips64Assembler* assembler) { GpuRegister out = locations->Out().AsRegister<GpuRegister>(); GpuRegister in = locations->InAt(0).AsRegister<GpuRegister>(); @@ -414,41 +419,52 @@ static void GenBitCount(LocationSummary* locations, // bits are set but the algorithm here attempts to minimize the total // number of instructions executed even when a large number of bits // are set. - - if (type == DataType::Type::kInt32) { - __ Srl(TMP, in, 1); - __ LoadConst32(AT, 0x55555555); - __ And(TMP, TMP, AT); - __ Subu(TMP, in, TMP); - __ LoadConst32(AT, 0x33333333); - __ And(out, TMP, AT); - __ Srl(TMP, TMP, 2); - __ And(TMP, TMP, AT); - __ Addu(TMP, out, TMP); - __ Srl(out, TMP, 4); - __ Addu(out, out, TMP); - __ LoadConst32(AT, 0x0F0F0F0F); - __ And(out, out, AT); - __ LoadConst32(TMP, 0x01010101); - __ MulR6(out, out, TMP); - __ Srl(out, out, 24); - } else if (type == DataType::Type::kInt64) { - __ Dsrl(TMP, in, 1); - __ LoadConst64(AT, 0x5555555555555555L); - __ And(TMP, TMP, AT); - __ Dsubu(TMP, in, TMP); - __ LoadConst64(AT, 0x3333333333333333L); - __ And(out, TMP, AT); - __ Dsrl(TMP, TMP, 2); - __ And(TMP, TMP, AT); - __ Daddu(TMP, out, TMP); - __ Dsrl(out, TMP, 4); - __ Daddu(out, out, TMP); - __ LoadConst64(AT, 0x0F0F0F0F0F0F0F0FL); - __ And(out, out, AT); - __ LoadConst64(TMP, 0x0101010101010101L); - __ Dmul(out, out, TMP); - __ Dsrl32(out, out, 24); + if (hasMsa) { + if (type == DataType::Type::kInt32) { + __ Mtc1(in, FTMP); + __ PcntW(static_cast<VectorRegister>(FTMP), static_cast<VectorRegister>(FTMP)); + __ Mfc1(out, FTMP); + } else { + __ Dmtc1(in, FTMP); + __ PcntD(static_cast<VectorRegister>(FTMP), static_cast<VectorRegister>(FTMP)); + __ Dmfc1(out, FTMP); + } + } else { + if (type == DataType::Type::kInt32) { + __ Srl(TMP, in, 1); + __ LoadConst32(AT, 0x55555555); + __ And(TMP, TMP, AT); + __ Subu(TMP, in, TMP); + __ LoadConst32(AT, 0x33333333); + __ And(out, TMP, AT); + __ Srl(TMP, TMP, 2); + __ And(TMP, TMP, AT); + __ Addu(TMP, out, TMP); + __ Srl(out, TMP, 4); + __ Addu(out, out, TMP); + __ LoadConst32(AT, 0x0F0F0F0F); + __ And(out, out, AT); + __ LoadConst32(TMP, 0x01010101); + __ MulR6(out, out, TMP); + __ Srl(out, out, 24); + } else { + __ Dsrl(TMP, in, 1); + __ LoadConst64(AT, 0x5555555555555555L); + __ And(TMP, TMP, AT); + __ Dsubu(TMP, in, TMP); + __ LoadConst64(AT, 0x3333333333333333L); + __ And(out, TMP, AT); + __ Dsrl(TMP, TMP, 2); + __ And(TMP, TMP, AT); + __ Daddu(TMP, out, TMP); + __ Dsrl(out, TMP, 4); + __ Daddu(out, out, TMP); + __ LoadConst64(AT, 0x0F0F0F0F0F0F0F0FL); + __ And(out, out, AT); + __ LoadConst64(TMP, 0x0101010101010101L); + __ Dmul(out, out, TMP); + __ Dsrl32(out, out, 24); + } } } @@ -458,7 +474,7 @@ void IntrinsicLocationsBuilderMIPS64::VisitIntegerBitCount(HInvoke* invoke) { } void IntrinsicCodeGeneratorMIPS64::VisitIntegerBitCount(HInvoke* invoke) { - GenBitCount(invoke->GetLocations(), DataType::Type::kInt32, GetAssembler()); + GenBitCount(invoke->GetLocations(), DataType::Type::kInt32, HasMsa(), GetAssembler()); } // int java.lang.Long.bitCount(long) @@ -467,222 +483,7 @@ void IntrinsicLocationsBuilderMIPS64::VisitLongBitCount(HInvoke* invoke) { } void IntrinsicCodeGeneratorMIPS64::VisitLongBitCount(HInvoke* invoke) { - GenBitCount(invoke->GetLocations(), DataType::Type::kInt64, GetAssembler()); -} - -static void GenMinMaxFP(LocationSummary* locations, - bool is_min, - DataType::Type type, - Mips64Assembler* assembler) { - FpuRegister a = locations->InAt(0).AsFpuRegister<FpuRegister>(); - FpuRegister b = locations->InAt(1).AsFpuRegister<FpuRegister>(); - FpuRegister out = locations->Out().AsFpuRegister<FpuRegister>(); - - Mips64Label noNaNs; - Mips64Label done; - FpuRegister ftmp = ((out != a) && (out != b)) ? out : FTMP; - - // When Java computes min/max it prefers a NaN to a number; the - // behavior of MIPSR6 is to prefer numbers to NaNs, i.e., if one of - // the inputs is a NaN and the other is a valid number, the MIPS - // instruction will return the number; Java wants the NaN value - // returned. This is why there is extra logic preceding the use of - // the MIPS min.fmt/max.fmt instructions. If either a, or b holds a - // NaN, return the NaN, otherwise return the min/max. - if (type == DataType::Type::kFloat64) { - __ CmpUnD(FTMP, a, b); - __ Bc1eqz(FTMP, &noNaNs); - - // One of the inputs is a NaN - __ CmpEqD(ftmp, a, a); - // If a == a then b is the NaN, otherwise a is the NaN. - __ SelD(ftmp, a, b); - - if (ftmp != out) { - __ MovD(out, ftmp); - } - - __ Bc(&done); - - __ Bind(&noNaNs); - - if (is_min) { - __ MinD(out, a, b); - } else { - __ MaxD(out, a, b); - } - } else { - DCHECK_EQ(type, DataType::Type::kFloat32); - __ CmpUnS(FTMP, a, b); - __ Bc1eqz(FTMP, &noNaNs); - - // One of the inputs is a NaN - __ CmpEqS(ftmp, a, a); - // If a == a then b is the NaN, otherwise a is the NaN. - __ SelS(ftmp, a, b); - - if (ftmp != out) { - __ MovS(out, ftmp); - } - - __ Bc(&done); - - __ Bind(&noNaNs); - - if (is_min) { - __ MinS(out, a, b); - } else { - __ MaxS(out, a, b); - } - } - - __ Bind(&done); -} - -static void CreateFPFPToFPLocations(ArenaAllocator* allocator, HInvoke* invoke) { - LocationSummary* locations = - new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified); - locations->SetInAt(0, Location::RequiresFpuRegister()); - locations->SetInAt(1, Location::RequiresFpuRegister()); - locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); -} - -// double java.lang.Math.min(double, double) -void IntrinsicLocationsBuilderMIPS64::VisitMathMinDoubleDouble(HInvoke* invoke) { - CreateFPFPToFPLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorMIPS64::VisitMathMinDoubleDouble(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), /* is_min */ true, DataType::Type::kFloat64, GetAssembler()); -} - -// float java.lang.Math.min(float, float) -void IntrinsicLocationsBuilderMIPS64::VisitMathMinFloatFloat(HInvoke* invoke) { - CreateFPFPToFPLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorMIPS64::VisitMathMinFloatFloat(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), /* is_min */ true, DataType::Type::kFloat32, GetAssembler()); -} - -// double java.lang.Math.max(double, double) -void IntrinsicLocationsBuilderMIPS64::VisitMathMaxDoubleDouble(HInvoke* invoke) { - CreateFPFPToFPLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorMIPS64::VisitMathMaxDoubleDouble(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), /* is_min */ false, DataType::Type::kFloat64, GetAssembler()); -} - -// float java.lang.Math.max(float, float) -void IntrinsicLocationsBuilderMIPS64::VisitMathMaxFloatFloat(HInvoke* invoke) { - CreateFPFPToFPLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorMIPS64::VisitMathMaxFloatFloat(HInvoke* invoke) { - GenMinMaxFP(invoke->GetLocations(), /* is_min */ false, DataType::Type::kFloat32, GetAssembler()); -} - -static void GenMinMax(LocationSummary* locations, - bool is_min, - Mips64Assembler* assembler) { - GpuRegister lhs = locations->InAt(0).AsRegister<GpuRegister>(); - GpuRegister rhs = locations->InAt(1).AsRegister<GpuRegister>(); - GpuRegister out = locations->Out().AsRegister<GpuRegister>(); - - if (lhs == rhs) { - if (out != lhs) { - __ Move(out, lhs); - } - } else { - // Some architectures, such as ARM and MIPS (prior to r6), have a - // conditional move instruction which only changes the target - // (output) register if the condition is true (MIPS prior to r6 had - // MOVF, MOVT, and MOVZ). The SELEQZ and SELNEZ instructions always - // change the target (output) register. If the condition is true the - // output register gets the contents of the "rs" register; otherwise, - // the output register is set to zero. One consequence of this is - // that to implement something like "rd = c==0 ? rs : rt" MIPS64r6 - // needs to use a pair of SELEQZ/SELNEZ instructions. After - // executing this pair of instructions one of the output registers - // from the pair will necessarily contain zero. Then the code ORs the - // output registers from the SELEQZ/SELNEZ instructions to get the - // final result. - // - // The initial test to see if the output register is same as the - // first input register is needed to make sure that value in the - // first input register isn't clobbered before we've finished - // computing the output value. The logic in the corresponding else - // clause performs the same task but makes sure the second input - // register isn't clobbered in the event that it's the same register - // as the output register; the else clause also handles the case - // where the output register is distinct from both the first, and the - // second input registers. - if (out == lhs) { - __ Slt(AT, rhs, lhs); - if (is_min) { - __ Seleqz(out, lhs, AT); - __ Selnez(AT, rhs, AT); - } else { - __ Selnez(out, lhs, AT); - __ Seleqz(AT, rhs, AT); - } - } else { - __ Slt(AT, lhs, rhs); - if (is_min) { - __ Seleqz(out, rhs, AT); - __ Selnez(AT, lhs, AT); - } else { - __ Selnez(out, rhs, AT); - __ Seleqz(AT, lhs, AT); - } - } - __ Or(out, out, AT); - } -} - -static void CreateIntIntToIntLocations(ArenaAllocator* allocator, HInvoke* invoke) { - LocationSummary* locations = - new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified); - locations->SetInAt(0, Location::RequiresRegister()); - locations->SetInAt(1, Location::RequiresRegister()); - locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); -} - -// int java.lang.Math.min(int, int) -void IntrinsicLocationsBuilderMIPS64::VisitMathMinIntInt(HInvoke* invoke) { - CreateIntIntToIntLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorMIPS64::VisitMathMinIntInt(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), /* is_min */ true, GetAssembler()); -} - -// long java.lang.Math.min(long, long) -void IntrinsicLocationsBuilderMIPS64::VisitMathMinLongLong(HInvoke* invoke) { - CreateIntIntToIntLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorMIPS64::VisitMathMinLongLong(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), /* is_min */ true, GetAssembler()); -} - -// int java.lang.Math.max(int, int) -void IntrinsicLocationsBuilderMIPS64::VisitMathMaxIntInt(HInvoke* invoke) { - CreateIntIntToIntLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorMIPS64::VisitMathMaxIntInt(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), /* is_min */ false, GetAssembler()); -} - -// long java.lang.Math.max(long, long) -void IntrinsicLocationsBuilderMIPS64::VisitMathMaxLongLong(HInvoke* invoke) { - CreateIntIntToIntLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorMIPS64::VisitMathMaxLongLong(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), /* is_min */ false, GetAssembler()); + GenBitCount(invoke->GetLocations(), DataType::Type::kInt64, HasMsa(), GetAssembler()); } // double java.lang.Math.sqrt(double) diff --git a/compiler/optimizing/intrinsics_mips64.h b/compiler/optimizing/intrinsics_mips64.h index 6f40d90ddb..748b0b02b2 100644 --- a/compiler/optimizing/intrinsics_mips64.h +++ b/compiler/optimizing/intrinsics_mips64.h @@ -68,6 +68,8 @@ class IntrinsicCodeGeneratorMIPS64 FINAL : public IntrinsicVisitor { #undef INTRINSICS_LIST #undef OPTIMIZING_INTRINSICS + bool HasMsa() const; + private: Mips64Assembler* GetAssembler(); diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc index 0edc061e97..c4f322bf0c 100644 --- a/compiler/optimizing/intrinsics_x86.cc +++ b/compiler/optimizing/intrinsics_x86.cc @@ -40,11 +40,6 @@ namespace art { namespace x86 { -static constexpr int kDoubleNaNHigh = 0x7FF80000; -static constexpr int kDoubleNaNLow = 0x00000000; -static constexpr int64_t kDoubleNaN = INT64_C(0x7FF8000000000000); -static constexpr int32_t kFloatNaN = INT32_C(0x7FC00000); - IntrinsicLocationsBuilderX86::IntrinsicLocationsBuilderX86(CodeGeneratorX86* codegen) : allocator_(codegen->GetGraph()->GetAllocator()), codegen_(codegen) { @@ -333,278 +328,6 @@ void IntrinsicCodeGeneratorX86::VisitShortReverseBytes(HInvoke* invoke) { GenReverseBytes(invoke->GetLocations(), DataType::Type::kInt16, GetAssembler()); } -static void GenMinMaxFP(HInvoke* invoke, - bool is_min, - bool is_double, - X86Assembler* assembler, - CodeGeneratorX86* codegen) { - LocationSummary* locations = invoke->GetLocations(); - Location op1_loc = locations->InAt(0); - Location op2_loc = locations->InAt(1); - Location out_loc = locations->Out(); - XmmRegister out = out_loc.AsFpuRegister<XmmRegister>(); - - // Shortcut for same input locations. - if (op1_loc.Equals(op2_loc)) { - DCHECK(out_loc.Equals(op1_loc)); - return; - } - - // (out := op1) - // out <=? op2 - // if Nan jmp Nan_label - // if out is min jmp done - // if op2 is min jmp op2_label - // handle -0/+0 - // jmp done - // Nan_label: - // out := NaN - // op2_label: - // out := op2 - // done: - // - // This removes one jmp, but needs to copy one input (op1) to out. - // - // TODO: This is straight from Quick (except literal pool). Make NaN an out-of-line slowpath? - - XmmRegister op2 = op2_loc.AsFpuRegister<XmmRegister>(); - - NearLabel nan, done, op2_label; - if (is_double) { - __ ucomisd(out, op2); - } else { - __ ucomiss(out, op2); - } - - __ j(Condition::kParityEven, &nan); - - __ j(is_min ? Condition::kAbove : Condition::kBelow, &op2_label); - __ j(is_min ? Condition::kBelow : Condition::kAbove, &done); - - // Handle 0.0/-0.0. - if (is_min) { - if (is_double) { - __ orpd(out, op2); - } else { - __ orps(out, op2); - } - } else { - if (is_double) { - __ andpd(out, op2); - } else { - __ andps(out, op2); - } - } - __ jmp(&done); - - // NaN handling. - __ Bind(&nan); - // Do we have a constant area pointer? - if (locations->GetInputCount() == 3 && locations->InAt(2).IsValid()) { - HX86ComputeBaseMethodAddress* method_address = - invoke->InputAt(2)->AsX86ComputeBaseMethodAddress(); - DCHECK(locations->InAt(2).IsRegister()); - Register constant_area = locations->InAt(2).AsRegister<Register>(); - if (is_double) { - __ movsd(out, codegen->LiteralInt64Address(kDoubleNaN, method_address, constant_area)); - } else { - __ movss(out, codegen->LiteralInt32Address(kFloatNaN, method_address, constant_area)); - } - } else { - if (is_double) { - __ pushl(Immediate(kDoubleNaNHigh)); - __ pushl(Immediate(kDoubleNaNLow)); - __ movsd(out, Address(ESP, 0)); - __ addl(ESP, Immediate(8)); - } else { - __ pushl(Immediate(kFloatNaN)); - __ movss(out, Address(ESP, 0)); - __ addl(ESP, Immediate(4)); - } - } - __ jmp(&done); - - // out := op2; - __ Bind(&op2_label); - if (is_double) { - __ movsd(out, op2); - } else { - __ movss(out, op2); - } - - // Done. - __ Bind(&done); -} - -static void CreateFPFPToFPLocations(ArenaAllocator* allocator, HInvoke* invoke) { - LocationSummary* locations = - new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified); - locations->SetInAt(0, Location::RequiresFpuRegister()); - locations->SetInAt(1, Location::RequiresFpuRegister()); - // The following is sub-optimal, but all we can do for now. It would be fine to also accept - // the second input to be the output (we can simply swap inputs). - locations->SetOut(Location::SameAsFirstInput()); - HInvokeStaticOrDirect* static_or_direct = invoke->AsInvokeStaticOrDirect(); - DCHECK(static_or_direct != nullptr); - if (static_or_direct->HasSpecialInput() && - invoke->InputAt(static_or_direct->GetSpecialInputIndex())->IsX86ComputeBaseMethodAddress()) { - locations->SetInAt(2, Location::RequiresRegister()); - } -} - -void IntrinsicLocationsBuilderX86::VisitMathMinDoubleDouble(HInvoke* invoke) { - CreateFPFPToFPLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorX86::VisitMathMinDoubleDouble(HInvoke* invoke) { - GenMinMaxFP(invoke, - /* is_min */ true, - /* is_double */ true, - GetAssembler(), - codegen_); -} - -void IntrinsicLocationsBuilderX86::VisitMathMinFloatFloat(HInvoke* invoke) { - CreateFPFPToFPLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorX86::VisitMathMinFloatFloat(HInvoke* invoke) { - GenMinMaxFP(invoke, - /* is_min */ true, - /* is_double */ false, - GetAssembler(), - codegen_); -} - -void IntrinsicLocationsBuilderX86::VisitMathMaxDoubleDouble(HInvoke* invoke) { - CreateFPFPToFPLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorX86::VisitMathMaxDoubleDouble(HInvoke* invoke) { - GenMinMaxFP(invoke, - /* is_min */ false, - /* is_double */ true, - GetAssembler(), - codegen_); -} - -void IntrinsicLocationsBuilderX86::VisitMathMaxFloatFloat(HInvoke* invoke) { - CreateFPFPToFPLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorX86::VisitMathMaxFloatFloat(HInvoke* invoke) { - GenMinMaxFP(invoke, - /* is_min */ false, - /* is_double */ false, - GetAssembler(), - codegen_); -} - -static void GenMinMax(LocationSummary* locations, bool is_min, bool is_long, - X86Assembler* assembler) { - Location op1_loc = locations->InAt(0); - Location op2_loc = locations->InAt(1); - - // Shortcut for same input locations. - if (op1_loc.Equals(op2_loc)) { - // Can return immediately, as op1_loc == out_loc. - // Note: if we ever support separate registers, e.g., output into memory, we need to check for - // a copy here. - DCHECK(locations->Out().Equals(op1_loc)); - return; - } - - if (is_long) { - // Need to perform a subtract to get the sign right. - // op1 is already in the same location as the output. - Location output = locations->Out(); - Register output_lo = output.AsRegisterPairLow<Register>(); - Register output_hi = output.AsRegisterPairHigh<Register>(); - - Register op2_lo = op2_loc.AsRegisterPairLow<Register>(); - Register op2_hi = op2_loc.AsRegisterPairHigh<Register>(); - - // Spare register to compute the subtraction to set condition code. - Register temp = locations->GetTemp(0).AsRegister<Register>(); - - // Subtract off op2_low. - __ movl(temp, output_lo); - __ subl(temp, op2_lo); - - // Now use the same tempo and the borrow to finish the subtraction of op2_hi. - __ movl(temp, output_hi); - __ sbbl(temp, op2_hi); - - // Now the condition code is correct. - Condition cond = is_min ? Condition::kGreaterEqual : Condition::kLess; - __ cmovl(cond, output_lo, op2_lo); - __ cmovl(cond, output_hi, op2_hi); - } else { - Register out = locations->Out().AsRegister<Register>(); - Register op2 = op2_loc.AsRegister<Register>(); - - // (out := op1) - // out <=? op2 - // if out is min jmp done - // out := op2 - // done: - - __ cmpl(out, op2); - Condition cond = is_min ? Condition::kGreater : Condition::kLess; - __ cmovl(cond, out, op2); - } -} - -static void CreateIntIntToIntLocations(ArenaAllocator* allocator, HInvoke* invoke) { - LocationSummary* locations = - new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified); - locations->SetInAt(0, Location::RequiresRegister()); - locations->SetInAt(1, Location::RequiresRegister()); - locations->SetOut(Location::SameAsFirstInput()); -} - -static void CreateLongLongToLongLocations(ArenaAllocator* allocator, HInvoke* invoke) { - LocationSummary* locations = - new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified); - locations->SetInAt(0, Location::RequiresRegister()); - locations->SetInAt(1, Location::RequiresRegister()); - locations->SetOut(Location::SameAsFirstInput()); - // Register to use to perform a long subtract to set cc. - locations->AddTemp(Location::RequiresRegister()); -} - -void IntrinsicLocationsBuilderX86::VisitMathMinIntInt(HInvoke* invoke) { - CreateIntIntToIntLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorX86::VisitMathMinIntInt(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), /* is_min */ true, /* is_long */ false, GetAssembler()); -} - -void IntrinsicLocationsBuilderX86::VisitMathMinLongLong(HInvoke* invoke) { - CreateLongLongToLongLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorX86::VisitMathMinLongLong(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), /* is_min */ true, /* is_long */ true, GetAssembler()); -} - -void IntrinsicLocationsBuilderX86::VisitMathMaxIntInt(HInvoke* invoke) { - CreateIntIntToIntLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorX86::VisitMathMaxIntInt(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), /* is_min */ false, /* is_long */ false, GetAssembler()); -} - -void IntrinsicLocationsBuilderX86::VisitMathMaxLongLong(HInvoke* invoke) { - CreateLongLongToLongLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorX86::VisitMathMaxLongLong(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), /* is_min */ false, /* is_long */ true, GetAssembler()); -} - static void CreateFPToFPLocations(ArenaAllocator* allocator, HInvoke* invoke) { LocationSummary* locations = new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified); diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc index 9d378d6b59..437bc3dd3c 100644 --- a/compiler/optimizing/intrinsics_x86_64.cc +++ b/compiler/optimizing/intrinsics_x86_64.cc @@ -236,208 +236,6 @@ void IntrinsicCodeGeneratorX86_64::VisitShortReverseBytes(HInvoke* invoke) { GenReverseBytes(invoke->GetLocations(), DataType::Type::kInt16, GetAssembler()); } -static void GenMinMaxFP(LocationSummary* locations, - bool is_min, - bool is_double, - X86_64Assembler* assembler, - CodeGeneratorX86_64* codegen) { - Location op1_loc = locations->InAt(0); - Location op2_loc = locations->InAt(1); - Location out_loc = locations->Out(); - XmmRegister out = out_loc.AsFpuRegister<XmmRegister>(); - - // Shortcut for same input locations. - if (op1_loc.Equals(op2_loc)) { - DCHECK(out_loc.Equals(op1_loc)); - return; - } - - // (out := op1) - // out <=? op2 - // if Nan jmp Nan_label - // if out is min jmp done - // if op2 is min jmp op2_label - // handle -0/+0 - // jmp done - // Nan_label: - // out := NaN - // op2_label: - // out := op2 - // done: - // - // This removes one jmp, but needs to copy one input (op1) to out. - // - // TODO: This is straight from Quick. Make NaN an out-of-line slowpath? - - XmmRegister op2 = op2_loc.AsFpuRegister<XmmRegister>(); - - NearLabel nan, done, op2_label; - if (is_double) { - __ ucomisd(out, op2); - } else { - __ ucomiss(out, op2); - } - - __ j(Condition::kParityEven, &nan); - - __ j(is_min ? Condition::kAbove : Condition::kBelow, &op2_label); - __ j(is_min ? Condition::kBelow : Condition::kAbove, &done); - - // Handle 0.0/-0.0. - if (is_min) { - if (is_double) { - __ orpd(out, op2); - } else { - __ orps(out, op2); - } - } else { - if (is_double) { - __ andpd(out, op2); - } else { - __ andps(out, op2); - } - } - __ jmp(&done); - - // NaN handling. - __ Bind(&nan); - if (is_double) { - __ movsd(out, codegen->LiteralInt64Address(INT64_C(0x7FF8000000000000))); - } else { - __ movss(out, codegen->LiteralInt32Address(INT32_C(0x7FC00000))); - } - __ jmp(&done); - - // out := op2; - __ Bind(&op2_label); - if (is_double) { - __ movsd(out, op2); - } else { - __ movss(out, op2); - } - - // Done. - __ Bind(&done); -} - -static void CreateFPFPToFP(ArenaAllocator* allocator, HInvoke* invoke) { - LocationSummary* locations = - new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified); - locations->SetInAt(0, Location::RequiresFpuRegister()); - locations->SetInAt(1, Location::RequiresFpuRegister()); - // The following is sub-optimal, but all we can do for now. It would be fine to also accept - // the second input to be the output (we can simply swap inputs). - locations->SetOut(Location::SameAsFirstInput()); -} - -void IntrinsicLocationsBuilderX86_64::VisitMathMinDoubleDouble(HInvoke* invoke) { - CreateFPFPToFP(allocator_, invoke); -} - -void IntrinsicCodeGeneratorX86_64::VisitMathMinDoubleDouble(HInvoke* invoke) { - GenMinMaxFP( - invoke->GetLocations(), /* is_min */ true, /* is_double */ true, GetAssembler(), codegen_); -} - -void IntrinsicLocationsBuilderX86_64::VisitMathMinFloatFloat(HInvoke* invoke) { - CreateFPFPToFP(allocator_, invoke); -} - -void IntrinsicCodeGeneratorX86_64::VisitMathMinFloatFloat(HInvoke* invoke) { - GenMinMaxFP( - invoke->GetLocations(), /* is_min */ true, /* is_double */ false, GetAssembler(), codegen_); -} - -void IntrinsicLocationsBuilderX86_64::VisitMathMaxDoubleDouble(HInvoke* invoke) { - CreateFPFPToFP(allocator_, invoke); -} - -void IntrinsicCodeGeneratorX86_64::VisitMathMaxDoubleDouble(HInvoke* invoke) { - GenMinMaxFP( - invoke->GetLocations(), /* is_min */ false, /* is_double */ true, GetAssembler(), codegen_); -} - -void IntrinsicLocationsBuilderX86_64::VisitMathMaxFloatFloat(HInvoke* invoke) { - CreateFPFPToFP(allocator_, invoke); -} - -void IntrinsicCodeGeneratorX86_64::VisitMathMaxFloatFloat(HInvoke* invoke) { - GenMinMaxFP( - invoke->GetLocations(), /* is_min */ false, /* is_double */ false, GetAssembler(), codegen_); -} - -static void GenMinMax(LocationSummary* locations, bool is_min, bool is_long, - X86_64Assembler* assembler) { - Location op1_loc = locations->InAt(0); - Location op2_loc = locations->InAt(1); - - // Shortcut for same input locations. - if (op1_loc.Equals(op2_loc)) { - // Can return immediately, as op1_loc == out_loc. - // Note: if we ever support separate registers, e.g., output into memory, we need to check for - // a copy here. - DCHECK(locations->Out().Equals(op1_loc)); - return; - } - - CpuRegister out = locations->Out().AsRegister<CpuRegister>(); - CpuRegister op2 = op2_loc.AsRegister<CpuRegister>(); - - // (out := op1) - // out <=? op2 - // if out is min jmp done - // out := op2 - // done: - - if (is_long) { - __ cmpq(out, op2); - } else { - __ cmpl(out, op2); - } - - __ cmov(is_min ? Condition::kGreater : Condition::kLess, out, op2, is_long); -} - -static void CreateIntIntToIntLocations(ArenaAllocator* allocator, HInvoke* invoke) { - LocationSummary* locations = - new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified); - locations->SetInAt(0, Location::RequiresRegister()); - locations->SetInAt(1, Location::RequiresRegister()); - locations->SetOut(Location::SameAsFirstInput()); -} - -void IntrinsicLocationsBuilderX86_64::VisitMathMinIntInt(HInvoke* invoke) { - CreateIntIntToIntLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorX86_64::VisitMathMinIntInt(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), /* is_min */ true, /* is_long */ false, GetAssembler()); -} - -void IntrinsicLocationsBuilderX86_64::VisitMathMinLongLong(HInvoke* invoke) { - CreateIntIntToIntLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorX86_64::VisitMathMinLongLong(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), /* is_min */ true, /* is_long */ true, GetAssembler()); -} - -void IntrinsicLocationsBuilderX86_64::VisitMathMaxIntInt(HInvoke* invoke) { - CreateIntIntToIntLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorX86_64::VisitMathMaxIntInt(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), /* is_min */ false, /* is_long */ false, GetAssembler()); -} - -void IntrinsicLocationsBuilderX86_64::VisitMathMaxLongLong(HInvoke* invoke) { - CreateIntIntToIntLocations(allocator_, invoke); -} - -void IntrinsicCodeGeneratorX86_64::VisitMathMaxLongLong(HInvoke* invoke) { - GenMinMax(invoke->GetLocations(), /* is_min */ false, /* is_long */ true, GetAssembler()); -} - static void CreateFPToFPLocations(ArenaAllocator* allocator, HInvoke* invoke) { LocationSummary* locations = new (allocator) LocationSummary(invoke, LocationSummary::kNoCall, kIntrinsified); diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc index 5a483e234b..d3b081e005 100644 --- a/compiler/optimizing/loop_optimization.cc +++ b/compiler/optimizing/loop_optimization.cc @@ -334,29 +334,14 @@ static bool IsAddConst(HInstruction* instruction, // Detect reductions of the following forms, // x = x_phi + .. // x = x_phi - .. -// x = max(x_phi, ..) // x = min(x_phi, ..) +// x = max(x_phi, ..) static bool HasReductionFormat(HInstruction* reduction, HInstruction* phi) { - if (reduction->IsAdd()) { + if (reduction->IsAdd() || reduction->IsMin() || reduction->IsMax()) { return (reduction->InputAt(0) == phi && reduction->InputAt(1) != phi) || (reduction->InputAt(0) != phi && reduction->InputAt(1) == phi); } else if (reduction->IsSub()) { return (reduction->InputAt(0) == phi && reduction->InputAt(1) != phi); - } else if (reduction->IsInvokeStaticOrDirect()) { - switch (reduction->AsInvokeStaticOrDirect()->GetIntrinsic()) { - case Intrinsics::kMathMinIntInt: - case Intrinsics::kMathMinLongLong: - case Intrinsics::kMathMinFloatFloat: - case Intrinsics::kMathMinDoubleDouble: - case Intrinsics::kMathMaxIntInt: - case Intrinsics::kMathMaxLongLong: - case Intrinsics::kMathMaxFloatFloat: - case Intrinsics::kMathMaxDoubleDouble: - return (reduction->InputAt(0) == phi && reduction->InputAt(1) != phi) || - (reduction->InputAt(0) != phi && reduction->InputAt(1) == phi); - default: - return false; - } } return false; } @@ -1322,50 +1307,34 @@ bool HLoopOptimization::VectorizeUse(LoopNode* node, } return true; } - } else if (instruction->IsInvokeStaticOrDirect()) { - // Accept particular intrinsics. - HInvokeStaticOrDirect* invoke = instruction->AsInvokeStaticOrDirect(); - switch (invoke->GetIntrinsic()) { - case Intrinsics::kMathMinIntInt: - case Intrinsics::kMathMinLongLong: - case Intrinsics::kMathMinFloatFloat: - case Intrinsics::kMathMinDoubleDouble: - case Intrinsics::kMathMaxIntInt: - case Intrinsics::kMathMaxLongLong: - case Intrinsics::kMathMaxFloatFloat: - case Intrinsics::kMathMaxDoubleDouble: { - // Deal with vector restrictions. - HInstruction* opa = instruction->InputAt(0); - HInstruction* opb = instruction->InputAt(1); - HInstruction* r = opa; - HInstruction* s = opb; - bool is_unsigned = false; - if (HasVectorRestrictions(restrictions, kNoMinMax)) { - return false; - } else if (HasVectorRestrictions(restrictions, kNoHiBits) && - !IsNarrowerOperands(opa, opb, type, &r, &s, &is_unsigned)) { - return false; // reject, unless all operands are same-extension narrower - } - // Accept MIN/MAX(x, y) for vectorizable operands. - DCHECK(r != nullptr); - DCHECK(s != nullptr); - if (generate_code && vector_mode_ != kVector) { // de-idiom - r = opa; - s = opb; - } - if (VectorizeUse(node, r, generate_code, type, restrictions) && - VectorizeUse(node, s, generate_code, type, restrictions)) { - if (generate_code) { - GenerateVecOp( - instruction, vector_map_->Get(r), vector_map_->Get(s), type, is_unsigned); - } - return true; - } - return false; + } else if (instruction->IsMin() || instruction->IsMax()) { + // Deal with vector restrictions. + HInstruction* opa = instruction->InputAt(0); + HInstruction* opb = instruction->InputAt(1); + HInstruction* r = opa; + HInstruction* s = opb; + bool is_unsigned = false; + if (HasVectorRestrictions(restrictions, kNoMinMax)) { + return false; + } else if (HasVectorRestrictions(restrictions, kNoHiBits) && + !IsNarrowerOperands(opa, opb, type, &r, &s, &is_unsigned)) { + return false; // reject, unless all operands are same-extension narrower + } + // Accept MIN/MAX(x, y) for vectorizable operands. + DCHECK(r != nullptr); + DCHECK(s != nullptr); + if (generate_code && vector_mode_ != kVector) { // de-idiom + r = opa; + s = opb; + } + if (VectorizeUse(node, r, generate_code, type, restrictions) && + VectorizeUse(node, s, generate_code, type, restrictions)) { + if (generate_code) { + GenerateVecOp( + instruction, vector_map_->Get(r), vector_map_->Get(s), type, is_unsigned); } - default: - return false; - } // switch + return true; + } } return false; } @@ -1806,80 +1775,29 @@ void HLoopOptimization::GenerateVecOp(HInstruction* org, GENERATE_VEC( new (global_allocator_) HVecUShr(global_allocator_, opa, opb, type, vector_length_, dex_pc), new (global_allocator_) HUShr(org_type, opa, opb, dex_pc)); + case HInstruction::kMin: + GENERATE_VEC( + new (global_allocator_) HVecMin(global_allocator_, + opa, + opb, + HVecOperation::ToProperType(type, is_unsigned), + vector_length_, + dex_pc), + new (global_allocator_) HMin(org_type, opa, opb, dex_pc)); + case HInstruction::kMax: + GENERATE_VEC( + new (global_allocator_) HVecMax(global_allocator_, + opa, + opb, + HVecOperation::ToProperType(type, is_unsigned), + vector_length_, + dex_pc), + new (global_allocator_) HMax(org_type, opa, opb, dex_pc)); case HInstruction::kAbs: DCHECK(opb == nullptr); GENERATE_VEC( new (global_allocator_) HVecAbs(global_allocator_, opa, type, vector_length_, dex_pc), new (global_allocator_) HAbs(org_type, opa, dex_pc)); - case HInstruction::kInvokeStaticOrDirect: { - HInvokeStaticOrDirect* invoke = org->AsInvokeStaticOrDirect(); - if (vector_mode_ == kVector) { - switch (invoke->GetIntrinsic()) { - case Intrinsics::kMathMinIntInt: - case Intrinsics::kMathMinLongLong: - case Intrinsics::kMathMinFloatFloat: - case Intrinsics::kMathMinDoubleDouble: { - vector = new (global_allocator_) - HVecMin(global_allocator_, - opa, - opb, - HVecOperation::ToProperType(type, is_unsigned), - vector_length_, - dex_pc); - break; - } - case Intrinsics::kMathMaxIntInt: - case Intrinsics::kMathMaxLongLong: - case Intrinsics::kMathMaxFloatFloat: - case Intrinsics::kMathMaxDoubleDouble: { - vector = new (global_allocator_) - HVecMax(global_allocator_, - opa, - opb, - HVecOperation::ToProperType(type, is_unsigned), - vector_length_, - dex_pc); - break; - } - default: - LOG(FATAL) << "Unsupported SIMD intrinsic " << org->GetId(); - UNREACHABLE(); - } // switch invoke - } else { - // In scalar code, simply clone the method invoke, and replace its operands with the - // corresponding new scalar instructions in the loop. The instruction will get an - // environment while being inserted from the instruction map in original program order. - DCHECK(vector_mode_ == kSequential); - size_t num_args = invoke->GetNumberOfArguments(); - HInvokeStaticOrDirect* new_invoke = new (global_allocator_) HInvokeStaticOrDirect( - global_allocator_, - num_args, - invoke->GetType(), - invoke->GetDexPc(), - invoke->GetDexMethodIndex(), - invoke->GetResolvedMethod(), - invoke->GetDispatchInfo(), - invoke->GetInvokeType(), - invoke->GetTargetMethod(), - invoke->GetClinitCheckRequirement()); - HInputsRef inputs = invoke->GetInputs(); - size_t num_inputs = inputs.size(); - DCHECK_LE(num_args, num_inputs); - DCHECK_EQ(num_inputs, new_invoke->GetInputs().size()); // both invokes agree - for (size_t index = 0; index < num_inputs; ++index) { - HInstruction* new_input = index < num_args - ? vector_map_->Get(inputs[index]) - : inputs[index]; // beyond arguments: just pass through - new_invoke->SetArgumentAt(index, new_input); - } - new_invoke->SetIntrinsic(invoke->GetIntrinsic(), - kNeedsEnvironmentOrCache, - kNoSideEffects, - kNoThrow); - vector = new_invoke; - } - break; - } default: break; } // switch diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 99d80d77c5..9da46206da 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -26,6 +26,7 @@ #include "base/arena_object.h" #include "base/array_ref.h" #include "base/iteration_range.h" +#include "base/quasi_atomic.h" #include "base/stl_util.h" #include "base/transform_array_ref.h" #include "data_type.h" @@ -1383,7 +1384,9 @@ class HLoopInformationOutwardIterator : public ValueObject { M(LoadException, Instruction) \ M(LoadString, Instruction) \ M(LongConstant, Constant) \ + M(Max, Instruction) \ M(MemoryBarrier, Instruction) \ + M(Min, BinaryOperation) \ M(MonitorOperation, Instruction) \ M(Mul, BinaryOperation) \ M(NativeDebugInfo, Instruction) \ @@ -5016,6 +5019,76 @@ class HRem FINAL : public HBinaryOperation { DEFAULT_COPY_CONSTRUCTOR(Rem); }; +class HMin FINAL : public HBinaryOperation { + public: + HMin(DataType::Type result_type, + HInstruction* left, + HInstruction* right, + uint32_t dex_pc) + : HBinaryOperation(kMin, result_type, left, right, SideEffects::None(), dex_pc) {} + + bool IsCommutative() const OVERRIDE { return true; } + + // Evaluation for integral values. + template <typename T> static T ComputeIntegral(T x, T y) { + return (x <= y) ? x : y; + } + + HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { + return GetBlock()->GetGraph()->GetIntConstant( + ComputeIntegral(x->GetValue(), y->GetValue()), GetDexPc()); + } + HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE { + return GetBlock()->GetGraph()->GetLongConstant( + ComputeIntegral(x->GetValue(), y->GetValue()), GetDexPc()); + } + // TODO: Evaluation for floating-point values. + HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED, + HFloatConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { return nullptr; } + HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED, + HDoubleConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { return nullptr; } + + DECLARE_INSTRUCTION(Min); + + protected: + DEFAULT_COPY_CONSTRUCTOR(Min); +}; + +class HMax FINAL : public HBinaryOperation { + public: + HMax(DataType::Type result_type, + HInstruction* left, + HInstruction* right, + uint32_t dex_pc) + : HBinaryOperation(kMax, result_type, left, right, SideEffects::None(), dex_pc) {} + + bool IsCommutative() const OVERRIDE { return true; } + + // Evaluation for integral values. + template <typename T> static T ComputeIntegral(T x, T y) { + return (x >= y) ? x : y; + } + + HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE { + return GetBlock()->GetGraph()->GetIntConstant( + ComputeIntegral(x->GetValue(), y->GetValue()), GetDexPc()); + } + HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE { + return GetBlock()->GetGraph()->GetLongConstant( + ComputeIntegral(x->GetValue(), y->GetValue()), GetDexPc()); + } + // TODO: Evaluation for floating-point values. + HConstant* Evaluate(HFloatConstant* x ATTRIBUTE_UNUSED, + HFloatConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { return nullptr; } + HConstant* Evaluate(HDoubleConstant* x ATTRIBUTE_UNUSED, + HDoubleConstant* y ATTRIBUTE_UNUSED) const OVERRIDE { return nullptr; } + + DECLARE_INSTRUCTION(Max); + + protected: + DEFAULT_COPY_CONSTRUCTOR(Max); +}; + class HAbs FINAL : public HUnaryOperation { public: HAbs(DataType::Type result_type, HInstruction* input, uint32_t dex_pc = kNoDexPc) diff --git a/compiler/optimizing/optimizing_compiler_stats.h b/compiler/optimizing/optimizing_compiler_stats.h index 0023265e50..00194ff1fe 100644 --- a/compiler/optimizing/optimizing_compiler_stats.h +++ b/compiler/optimizing/optimizing_compiler_stats.h @@ -22,9 +22,9 @@ #include <string> #include <type_traits> -#include "atomic.h" +#include "base/atomic.h" +#include "base/globals.h" #include "base/logging.h" // For VLOG_IS_ON. -#include "globals.h" namespace art { diff --git a/compiler/optimizing/pc_relative_fixups_x86.cc b/compiler/optimizing/pc_relative_fixups_x86.cc index a3ca6311c2..2591783cb6 100644 --- a/compiler/optimizing/pc_relative_fixups_x86.cc +++ b/compiler/optimizing/pc_relative_fixups_x86.cc @@ -234,12 +234,13 @@ class PCRelativeHandlerVisitor : public HGraphVisitor { switch (invoke->GetIntrinsic()) { case Intrinsics::kMathAbsDouble: case Intrinsics::kMathAbsFloat: - LOG(FATAL) << "Unreachable abs"; - UNREACHABLE(); case Intrinsics::kMathMaxDoubleDouble: case Intrinsics::kMathMaxFloatFloat: case Intrinsics::kMathMinDoubleDouble: case Intrinsics::kMathMinFloatFloat: + LOG(FATAL) << "Unreachable min/max/abs: intrinsics should have been lowered " + "to IR nodes by instruction simplifier"; + UNREACHABLE(); case Intrinsics::kMathRoundFloat: if (!base_added) { DCHECK(invoke_static_or_direct != nullptr); diff --git a/compiler/optimizing/scheduler.cc b/compiler/optimizing/scheduler.cc index cdbe48342d..bca538fb17 100644 --- a/compiler/optimizing/scheduler.cc +++ b/compiler/optimizing/scheduler.cc @@ -679,6 +679,8 @@ bool HScheduler::IsSchedulable(const HInstruction* instruction) const { instruction->IsCompare() || instruction->IsCondition() || instruction->IsDiv() || + instruction->IsMin() || + instruction->IsMax() || instruction->IsMul() || instruction->IsOr() || instruction->IsRem() || diff --git a/compiler/utils/assembler_test_base.h b/compiler/utils/assembler_test_base.h index 1482210ac4..778a01566c 100644 --- a/compiler/utils/assembler_test_base.h +++ b/compiler/utils/assembler_test_base.h @@ -25,9 +25,9 @@ #include "android-base/strings.h" +#include "base/utils.h" #include "common_runtime_test.h" // For ScratchFile #include "exec_utils.h" -#include "utils.h" namespace art { diff --git a/compiler/utils/atomic_dex_ref_map.h b/compiler/utils/atomic_dex_ref_map.h index cabd79e9f1..fc2437999e 100644 --- a/compiler/utils/atomic_dex_ref_map.h +++ b/compiler/utils/atomic_dex_ref_map.h @@ -17,7 +17,7 @@ #ifndef ART_COMPILER_UTILS_ATOMIC_DEX_REF_MAP_H_ #define ART_COMPILER_UTILS_ATOMIC_DEX_REF_MAP_H_ -#include "atomic.h" +#include "base/atomic.h" #include "base/dchecked_vector.h" #include "base/safe_map.h" #include "dex/dex_file_reference.h" diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc index 2218ef9af2..b2ad490a57 100644 --- a/compiler/utils/mips/assembler_mips.cc +++ b/compiler/utils/mips/assembler_mips.cc @@ -2793,6 +2793,26 @@ void MipsAssembler::Hadd_uD(VectorRegister wd, VectorRegister ws, VectorRegister DsFsmInstr(EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x15)).FprOuts(wd).FprIns(ws, wt); } +void MipsAssembler::PcntB(VectorRegister wd, VectorRegister ws) { + CHECK(HasMsa()); + DsFsmInstr(EmitMsa2R(0xc1, 0x0, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws); +} + +void MipsAssembler::PcntH(VectorRegister wd, VectorRegister ws) { + CHECK(HasMsa()); + DsFsmInstr(EmitMsa2R(0xc1, 0x1, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws); +} + +void MipsAssembler::PcntW(VectorRegister wd, VectorRegister ws) { + CHECK(HasMsa()); + DsFsmInstr(EmitMsa2R(0xc1, 0x2, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws); +} + +void MipsAssembler::PcntD(VectorRegister wd, VectorRegister ws) { + CHECK(HasMsa()); + DsFsmInstr(EmitMsa2R(0xc1, 0x3, ws, wd, 0x1e)).FprOuts(wd).FprIns(ws); +} + void MipsAssembler::ReplicateFPToVectorRegister(VectorRegister dst, FRegister src, bool is_double) { diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h index 7de8e2e366..c6ce62b4f4 100644 --- a/compiler/utils/mips/assembler_mips.h +++ b/compiler/utils/mips/assembler_mips.h @@ -756,6 +756,11 @@ class MipsAssembler FINAL : public Assembler, public JNIMacroAssembler<PointerSi void Hadd_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt); void Hadd_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt); + void PcntB(VectorRegister wd, VectorRegister ws); + void PcntH(VectorRegister wd, VectorRegister ws); + void PcntW(VectorRegister wd, VectorRegister ws); + void PcntD(VectorRegister wd, VectorRegister ws); + // Helper for replicating floating point value in all destination elements. void ReplicateFPToVectorRegister(VectorRegister dst, FRegister src, bool is_double); diff --git a/compiler/utils/mips/assembler_mips32r6_test.cc b/compiler/utils/mips/assembler_mips32r6_test.cc index 937ee25bcb..691c33f3e7 100644 --- a/compiler/utils/mips/assembler_mips32r6_test.cc +++ b/compiler/utils/mips/assembler_mips32r6_test.cc @@ -2277,6 +2277,22 @@ TEST_F(AssemblerMIPS32r6Test, FillW) { DriverStr(RepeatVR(&mips::MipsAssembler::FillW, "fill.w ${reg1}, ${reg2}"), "fill.w"); } +TEST_F(AssemblerMIPS32r6Test, PcntB) { + DriverStr(RepeatVV(&mips::MipsAssembler::PcntB, "pcnt.b ${reg1}, ${reg2}"), "pcnt.b"); +} + +TEST_F(AssemblerMIPS32r6Test, PcntH) { + DriverStr(RepeatVV(&mips::MipsAssembler::PcntH, "pcnt.h ${reg1}, ${reg2}"), "pcnt.h"); +} + +TEST_F(AssemblerMIPS32r6Test, PcntW) { + DriverStr(RepeatVV(&mips::MipsAssembler::PcntW, "pcnt.w ${reg1}, ${reg2}"), "pcnt.w"); +} + +TEST_F(AssemblerMIPS32r6Test, PcntD) { + DriverStr(RepeatVV(&mips::MipsAssembler::PcntD, "pcnt.d ${reg1}, ${reg2}"), "pcnt.d"); +} + TEST_F(AssemblerMIPS32r6Test, LdiB) { DriverStr(RepeatVIb(&mips::MipsAssembler::LdiB, -8, "ldi.b ${reg}, {imm}"), "ldi.b"); } diff --git a/compiler/utils/mips64/assembler_mips64.cc b/compiler/utils/mips64/assembler_mips64.cc index e1b0e75108..5a817fa960 100644 --- a/compiler/utils/mips64/assembler_mips64.cc +++ b/compiler/utils/mips64/assembler_mips64.cc @@ -2279,6 +2279,26 @@ void Mips64Assembler::Hadd_uD(VectorRegister wd, VectorRegister ws, VectorRegist EmitMsa3R(0x5, 0x3, wt, ws, wd, 0x15); } +void Mips64Assembler::PcntB(VectorRegister wd, VectorRegister ws) { + CHECK(HasMsa()); + EmitMsa2R(0xc1, 0x0, ws, wd, 0x1e); +} + +void Mips64Assembler::PcntH(VectorRegister wd, VectorRegister ws) { + CHECK(HasMsa()); + EmitMsa2R(0xc1, 0x1, ws, wd, 0x1e); +} + +void Mips64Assembler::PcntW(VectorRegister wd, VectorRegister ws) { + CHECK(HasMsa()); + EmitMsa2R(0xc1, 0x2, ws, wd, 0x1e); +} + +void Mips64Assembler::PcntD(VectorRegister wd, VectorRegister ws) { + CHECK(HasMsa()); + EmitMsa2R(0xc1, 0x3, ws, wd, 0x1e); +} + void Mips64Assembler::ReplicateFPToVectorRegister(VectorRegister dst, FpuRegister src, bool is_double) { diff --git a/compiler/utils/mips64/assembler_mips64.h b/compiler/utils/mips64/assembler_mips64.h index 7a61f39e64..542dbafc87 100644 --- a/compiler/utils/mips64/assembler_mips64.h +++ b/compiler/utils/mips64/assembler_mips64.h @@ -863,6 +863,11 @@ class Mips64Assembler FINAL : public Assembler, public JNIMacroAssembler<Pointer void Hadd_uW(VectorRegister wd, VectorRegister ws, VectorRegister wt); void Hadd_uD(VectorRegister wd, VectorRegister ws, VectorRegister wt); + void PcntB(VectorRegister wd, VectorRegister ws); + void PcntH(VectorRegister wd, VectorRegister ws); + void PcntW(VectorRegister wd, VectorRegister ws); + void PcntD(VectorRegister wd, VectorRegister ws); + // Helper for replicating floating point value in all destination elements. void ReplicateFPToVectorRegister(VectorRegister dst, FpuRegister src, bool is_double); diff --git a/compiler/utils/mips64/assembler_mips64_test.cc b/compiler/utils/mips64/assembler_mips64_test.cc index b0e1d91c3f..fb5f12be93 100644 --- a/compiler/utils/mips64/assembler_mips64_test.cc +++ b/compiler/utils/mips64/assembler_mips64_test.cc @@ -3529,6 +3529,22 @@ TEST_F(AssemblerMIPS64Test, FillD) { DriverStr(RepeatVR(&mips64::Mips64Assembler::FillD, "fill.d ${reg1}, ${reg2}"), "fill.d"); } +TEST_F(AssemblerMIPS64Test, PcntB) { + DriverStr(RepeatVV(&mips64::Mips64Assembler::PcntB, "pcnt.b ${reg1}, ${reg2}"), "pcnt.b"); +} + +TEST_F(AssemblerMIPS64Test, PcntH) { + DriverStr(RepeatVV(&mips64::Mips64Assembler::PcntH, "pcnt.h ${reg1}, ${reg2}"), "pcnt.h"); +} + +TEST_F(AssemblerMIPS64Test, PcntW) { + DriverStr(RepeatVV(&mips64::Mips64Assembler::PcntW, "pcnt.w ${reg1}, ${reg2}"), "pcnt.w"); +} + +TEST_F(AssemblerMIPS64Test, PcntD) { + DriverStr(RepeatVV(&mips64::Mips64Assembler::PcntD, "pcnt.d ${reg1}, ${reg2}"), "pcnt.d"); +} + TEST_F(AssemblerMIPS64Test, LdiB) { DriverStr(RepeatVIb(&mips64::Mips64Assembler::LdiB, -8, "ldi.b ${reg}, {imm}"), "ldi.b"); } diff --git a/compiler/utils/swap_space_test.cc b/compiler/utils/swap_space_test.cc index f4bca59cb3..1650080e66 100644 --- a/compiler/utils/swap_space_test.cc +++ b/compiler/utils/swap_space_test.cc @@ -24,9 +24,9 @@ #include "gtest/gtest.h" +#include "base/os.h" #include "base/unix_file/fd_file.h" #include "common_runtime_test.h" -#include "os.h" namespace art { diff --git a/compiler/utils/test_dex_file_builder_test.cc b/compiler/utils/test_dex_file_builder_test.cc index 736a17edac..788afd8e1a 100644 --- a/compiler/utils/test_dex_file_builder_test.cc +++ b/compiler/utils/test_dex_file_builder_test.cc @@ -16,9 +16,9 @@ #include "test_dex_file_builder.h" +#include "base/utils.h" #include "dex/dex_file-inl.h" #include "gtest/gtest.h" -#include "utils.h" namespace art { diff --git a/dex2oat/Android.bp b/dex2oat/Android.bp index b67898d2a6..b158231bc3 100644 --- a/dex2oat/Android.bp +++ b/dex2oat/Android.bp @@ -139,7 +139,14 @@ art_cc_binary { "-Wno-frame-larger-than=", "-DART_PGO_INSTRUMENTATION", ], - } + }, + target: { + android: { + lto: { + thin: true, + }, + }, + }, } art_cc_binary { diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 926575e10c..73afbad184 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -46,12 +46,15 @@ #include "base/file_utils.h" #include "base/leb128.h" #include "base/macros.h" +#include "base/mutex.h" +#include "base/os.h" #include "base/scoped_flock.h" #include "base/stl_util.h" #include "base/stringpiece.h" #include "base/time_utils.h" #include "base/timing_logger.h" #include "base/unix_file/fd_file.h" +#include "base/utils.h" #include "class_linker.h" #include "class_loader_context.h" #include "cmdline_parser.h" @@ -89,11 +92,9 @@ #include "mirror/object_array-inl.h" #include "oat_file.h" #include "oat_file_assistant.h" -#include "os.h" #include "runtime.h" #include "runtime_options.h" #include "scoped_thread_state_change-inl.h" -#include "utils.h" #include "vdex_file.h" #include "verifier/verifier_deps.h" #include "well_known_classes.h" @@ -1164,6 +1165,7 @@ class Dex2Oat FINAL { original_argc = argc; original_argv = argv; + Locks::Init(); InitLogging(argv, Runtime::Abort); compiler_options_.reset(new CompilerOptions()); diff --git a/dex2oat/dex2oat_image_test.cc b/dex2oat/dex2oat_image_test.cc index 05592f1806..f542c60d81 100644 --- a/dex2oat/dex2oat_image_test.cc +++ b/dex2oat/dex2oat_image_test.cc @@ -29,13 +29,13 @@ #include "base/file_utils.h" #include "base/macros.h" #include "base/unix_file/fd_file.h" +#include "base/utils.h" #include "dex/art_dex_file_loader.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_loader.h" #include "jit/profile_compilation_info.h" #include "method_reference.h" #include "runtime.h" -#include "utils.h" namespace art { @@ -129,9 +129,9 @@ class Dex2oatImageTest : public CommonRuntimeTest { std::string art_file = scratch.GetFilename() + ".art"; std::string oat_file = scratch.GetFilename() + ".oat"; std::string vdex_file = scratch.GetFilename() + ".vdex"; - ret.art_size = GetFileSizeBytes(art_file); - ret.oat_size = GetFileSizeBytes(oat_file); - ret.vdex_size = GetFileSizeBytes(vdex_file); + ret.art_size = OS::GetFileSizeBytes(art_file.c_str()); + ret.oat_size = OS::GetFileSizeBytes(oat_file.c_str()); + ret.vdex_size = OS::GetFileSizeBytes(vdex_file.c_str()); CHECK_GT(ret.art_size, 0u) << art_file; CHECK_GT(ret.oat_size, 0u) << oat_file; CHECK_GT(ret.vdex_size, 0u) << vdex_file; @@ -228,7 +228,7 @@ class Dex2oatImageTest : public CommonRuntimeTest { } }; -TEST_F(Dex2oatImageTest, TestModesAndFilters) { +TEST_F(Dex2oatImageTest, DISABLED_TestModesAndFilters) { if (kIsTargetBuild) { // This test is too slow for target builds. return; diff --git a/dex2oat/dex2oat_options.h b/dex2oat/dex2oat_options.h index ccc85c8951..cc124c1afa 100644 --- a/dex2oat/dex2oat_options.h +++ b/dex2oat/dex2oat_options.h @@ -21,6 +21,7 @@ #include <string> #include <vector> +#include "arch/instruction_set.h" #include "base/variant_map.h" #include "cmdline_types.h" // TODO: don't need to include this file here #include "compiler.h" diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc index 6b75595005..96dd319946 100644 --- a/dex2oat/dex2oat_test.cc +++ b/dex2oat/dex2oat_test.cc @@ -29,6 +29,7 @@ #include "base/macros.h" #include "base/mutex-inl.h" +#include "base/utils.h" #include "bytecode_utils.h" #include "dex/art_dex_file_loader.h" #include "dex/base64_test_util.h" @@ -40,7 +41,6 @@ #include "jit/profile_compilation_info.h" #include "oat.h" #include "oat_file.h" -#include "utils.h" #include "vdex_file.h" #include "ziparchive/zip_writer.h" diff --git a/dex2oat/linker/elf_writer.h b/dex2oat/linker/elf_writer.h index 7c4774038e..bcf2cd7d4b 100644 --- a/dex2oat/linker/elf_writer.h +++ b/dex2oat/linker/elf_writer.h @@ -25,8 +25,8 @@ #include "base/array_ref.h" #include "base/macros.h" #include "base/mutex.h" +#include "base/os.h" #include "debug/debug_info.h" -#include "os.h" namespace art { diff --git a/dex2oat/linker/elf_writer_quick.cc b/dex2oat/linker/elf_writer_quick.cc index d2e863c2a8..07b02f1033 100644 --- a/dex2oat/linker/elf_writer_quick.cc +++ b/dex2oat/linker/elf_writer_quick.cc @@ -24,6 +24,7 @@ #include "base/casts.h" #include "base/leb128.h" +#include "base/utils.h" #include "compiled_method.h" #include "debug/elf_debug_writer.h" #include "debug/method_debug_info.h" @@ -36,7 +37,6 @@ #include "linker/file_output_stream.h" #include "thread-current-inl.h" #include "thread_pool.h" -#include "utils.h" namespace art { namespace linker { diff --git a/dex2oat/linker/elf_writer_quick.h b/dex2oat/linker/elf_writer_quick.h index e20957c5ce..274d18b858 100644 --- a/dex2oat/linker/elf_writer_quick.h +++ b/dex2oat/linker/elf_writer_quick.h @@ -20,8 +20,8 @@ #include <memory> #include "arch/instruction_set.h" +#include "base/os.h" #include "elf_writer.h" -#include "os.h" namespace art { diff --git a/dex2oat/linker/elf_writer_test.cc b/dex2oat/linker/elf_writer_test.cc index 8427e7b8ce..b2be003b5d 100644 --- a/dex2oat/linker/elf_writer_test.cc +++ b/dex2oat/linker/elf_writer_test.cc @@ -18,13 +18,13 @@ #include "base/file_utils.h" #include "base/unix_file/fd_file.h" +#include "base/utils.h" #include "common_compiler_test.h" #include "elf_file.h" #include "elf_file_impl.h" #include "elf_writer_quick.h" #include "linker/elf_builder.h" #include "oat.h" -#include "utils.h" namespace art { namespace linker { diff --git a/dex2oat/linker/image_test.h b/dex2oat/linker/image_test.h index c6ce951506..319c5fb675 100644 --- a/dex2oat/linker/image_test.h +++ b/dex2oat/linker/image_test.h @@ -28,6 +28,7 @@ #include "art_method-inl.h" #include "base/file_utils.h" #include "base/unix_file/fd_file.h" +#include "base/utils.h" #include "class_linker-inl.h" #include "common_compiler_test.h" #include "compiler_callbacks.h" @@ -46,7 +47,6 @@ #include "oat_writer.h" #include "scoped_thread_state_change-inl.h" #include "signal_catcher.h" -#include "utils.h" namespace art { namespace linker { diff --git a/dex2oat/linker/image_writer.h b/dex2oat/linker/image_writer.h index 856edfb3bc..36bbb47786 100644 --- a/dex2oat/linker/image_writer.h +++ b/dex2oat/linker/image_writer.h @@ -33,7 +33,9 @@ #include "base/enums.h" #include "base/length_prefixed_array.h" #include "base/macros.h" +#include "base/os.h" #include "base/safe_map.h" +#include "base/utils.h" #include "class_table.h" #include "driver/compiler_driver.h" #include "image.h" @@ -43,8 +45,6 @@ #include "mirror/dex_cache.h" #include "oat_file.h" #include "obj_ptr.h" -#include "os.h" -#include "utils.h" namespace art { namespace gc { diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc index 2feb14a357..c72beea6ce 100644 --- a/dex2oat/linker/oat_writer.cc +++ b/dex2oat/linker/oat_writer.cc @@ -27,6 +27,7 @@ #include "base/enums.h" #include "base/file_magic.h" #include "base/logging.h" // For VLOG +#include "base/os.h" #include "base/safe_map.h" #include "base/stl_util.h" #include "base/unix_file/fd_file.h" @@ -60,7 +61,6 @@ #include "mirror/dex_cache-inl.h" #include "mirror/object-inl.h" #include "oat_quick_method_header.h" -#include "os.h" #include "quicken_info.h" #include "scoped_thread_state_change-inl.h" #include "type_lookup_table.h" diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h index d67e4dedfc..0cb0ef20df 100644 --- a/dex2oat/linker/oat_writer.h +++ b/dex2oat/linker/oat_writer.h @@ -24,6 +24,7 @@ #include "base/array_ref.h" #include "base/dchecked_vector.h" +#include "base/os.h" #include "base/safe_map.h" #include "compiler.h" #include "dex/compact_dex_level.h" @@ -33,7 +34,6 @@ #include "method_reference.h" #include "mirror/class.h" #include "oat.h" -#include "os.h" #include "string_reference.h" #include "type_reference.h" diff --git a/dexdump/dexdump_test.cc b/dexdump/dexdump_test.cc index 559dc8e781..63e0e3f20d 100644 --- a/dexdump/dexdump_test.cc +++ b/dexdump/dexdump_test.cc @@ -22,10 +22,10 @@ #include <unistd.h> #include "arch/instruction_set.h" +#include "base/os.h" +#include "base/utils.h" #include "common_runtime_test.h" #include "exec_utils.h" -#include "os.h" -#include "utils.h" namespace art { diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp index bea61d0c71..24be25bd26 100644 --- a/dexlayout/Android.bp +++ b/dexlayout/Android.bp @@ -44,7 +44,14 @@ art_cc_library { instrumentation: true, profile_file: "art/dex2oat.profdata", benchmarks: ["dex2oat"], - } + }, + target: { + android: { + lto: { + thin: true, + }, + }, + }, } art_cc_library { diff --git a/dexlayout/compact_dex_writer.h b/dexlayout/compact_dex_writer.h index 0e7d65f9e4..eaf85185f1 100644 --- a/dexlayout/compact_dex_writer.h +++ b/dexlayout/compact_dex_writer.h @@ -22,8 +22,8 @@ #include <memory> // For unique_ptr #include <unordered_map> +#include "base/utils.h" #include "dex_writer.h" -#include "utils.h" namespace art { diff --git a/dexlayout/dex_writer.h b/dexlayout/dex_writer.h index df098c0f6f..db1898bf26 100644 --- a/dexlayout/dex_writer.h +++ b/dexlayout/dex_writer.h @@ -22,13 +22,12 @@ #include <functional> #include <memory> // For unique_ptr +#include "base/os.h" #include "base/unix_file/fd_file.h" #include "dex/compact_dex_level.h" #include "dex_container.h" #include "dex/dex_file.h" #include "dex_ir.h" -#include "mem_map.h" -#include "os.h" #include <queue> diff --git a/dexlayout/dexdiag.cc b/dexlayout/dexdiag.cc index c0d6f02c00..6cb141f688 100644 --- a/dexlayout/dexdiag.cc +++ b/dexlayout/dexdiag.cc @@ -27,6 +27,7 @@ #include "android-base/stringprintf.h" #include "base/logging.h" // For InitLogging. +#include "base/mutex.h" #include "base/stringpiece.h" #include "dexlayout.h" @@ -470,6 +471,7 @@ static int DexDiagMain(int argc, char* argv[]) { } // Art specific set up. + Locks::Init(); InitLogging(argv, Runtime::Abort); MemMap::Init(); diff --git a/dexlayout/dexdiag_test.cc b/dexlayout/dexdiag_test.cc index 9927576400..068949ceba 100644 --- a/dexlayout/dexdiag_test.cc +++ b/dexlayout/dexdiag_test.cc @@ -20,9 +20,9 @@ #include "common_runtime_test.h" #include "base/file_utils.h" +#include "base/os.h" #include "exec_utils.h" #include "oat_file.h" -#include "os.h" namespace art { diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc index 159a4a5ec2..ec0cbe6a60 100644 --- a/dexlayout/dexlayout.cc +++ b/dexlayout/dexlayout.cc @@ -34,6 +34,8 @@ #include "android-base/stringprintf.h" #include "base/logging.h" // For VLOG_IS_ON. +#include "base/os.h" +#include "base/utils.h" #include "dex/art_dex_file_loader.h" #include "dex/descriptors_names.h" #include "dex/dex_file-inl.h" @@ -48,8 +50,6 @@ #include "dex_writer.h" #include "jit/profile_compilation_info.h" #include "mem_map.h" -#include "os.h" -#include "utils.h" namespace art { diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h index b79a59209d..2bca10ddfb 100644 --- a/dexlayout/dexlayout.h +++ b/dexlayout/dexlayout.h @@ -31,7 +31,6 @@ #include "dex_container.h" #include "dex/dex_file_layout.h" #include "dex_ir.h" -#include "mem_map.h" namespace art { diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc index 981f9010ee..6719d0848c 100644 --- a/dexlayout/dexlayout_test.cc +++ b/dexlayout/dexlayout_test.cc @@ -22,6 +22,7 @@ #include <unistd.h> #include "base/unix_file/fd_file.h" +#include "base/utils.h" #include "common_runtime_test.h" #include "dex/art_dex_file_loader.h" #include "dex/base64_test_util.h" @@ -31,7 +32,6 @@ #include "dexlayout.h" #include "exec_utils.h" #include "jit/profile_compilation_info.h" -#include "utils.h" namespace art { diff --git a/dexlist/dexlist_test.cc b/dexlist/dexlist_test.cc index ae44848461..0b9adbddb8 100644 --- a/dexlist/dexlist_test.cc +++ b/dexlist/dexlist_test.cc @@ -22,12 +22,12 @@ #include <unistd.h> #include "arch/instruction_set.h" +#include "base/os.h" +#include "base/utils.h" #include "common_runtime_test.h" #include "exec_utils.h" #include "gc/heap.h" #include "gc/space/image_space.h" -#include "os.h" -#include "utils.h" namespace art { diff --git a/dexoptanalyzer/dexoptanalyzer.cc b/dexoptanalyzer/dexoptanalyzer.cc index 6d4b3e3e52..febccf1950 100644 --- a/dexoptanalyzer/dexoptanalyzer.cc +++ b/dexoptanalyzer/dexoptanalyzer.cc @@ -17,19 +17,19 @@ #include <string> #include "base/logging.h" // For InitLogging. +#include "base/mutex.h" +#include "base/os.h" +#include "base/utils.h" #include "android-base/stringprintf.h" #include "android-base/strings.h" #include "base/file_utils.h" -#include "base/logging.h" // For InitLogging. #include "compiler_filter.h" #include "class_loader_context.h" #include "dex/dex_file.h" #include "noop_compiler_callbacks.h" #include "oat_file_assistant.h" -#include "os.h" #include "runtime.h" #include "thread-inl.h" -#include "utils.h" namespace art { @@ -142,6 +142,7 @@ class DexoptAnalyzer FINAL { original_argc = argc; original_argv = argv; + Locks::Init(); InitLogging(argv, Runtime::Abort); // Skip over the command name. argv++; diff --git a/disassembler/disassembler_mips.cc b/disassembler/disassembler_mips.cc index b5f5d6ff10..eaf11be7f2 100644 --- a/disassembler/disassembler_mips.cc +++ b/disassembler/disassembler_mips.cc @@ -487,6 +487,7 @@ static const MipsInstruction gMipsInstructions[] = { { kMsaMask | (0xf << 22), kMsa | (0x3 << 22) | 0x19, "copy_u", "yX" }, { kMsaMask | (0xf << 22), kMsa | (0x4 << 22) | 0x19, "insert", "YD" }, { kMsaMask | (0xff << 18), kMsa | (0xc0 << 18) | 0x1e, "fill", "vkD" }, + { kMsaMask | (0xff << 18), kMsa | (0xc1 << 18) | 0x1e, "pcnt", "vkm" }, { kMsaMask | (0x7 << 23), kMsa | (0x6 << 23) | 0x7, "ldi", "kx" }, { kMsaSpecialMask | (0xf << 2), kMsa | (0x8 << 2), "ld", "kw" }, { kMsaSpecialMask | (0xf << 2), kMsa | (0x9 << 2), "st", "kw" }, diff --git a/imgdiag/imgdiag.cc b/imgdiag/imgdiag.cc index 8aa638a0e0..ddb8fe1302 100644 --- a/imgdiag/imgdiag.cc +++ b/imgdiag/imgdiag.cc @@ -30,6 +30,7 @@ #include "art_field-inl.h" #include "art_method-inl.h" +#include "base/os.h" #include "base/unix_file/fd_file.h" #include "class_linker.h" #include "gc/heap.h" @@ -40,7 +41,6 @@ #include "oat.h" #include "oat_file.h" #include "oat_file_manager.h" -#include "os.h" #include "scoped_thread_state_change-inl.h" #include "backtrace/BacktraceMap.h" diff --git a/imgdiag/imgdiag_test.cc b/imgdiag/imgdiag_test.cc index 80b0c26b7f..52096f0d7b 100644 --- a/imgdiag/imgdiag_test.cc +++ b/imgdiag/imgdiag_test.cc @@ -24,13 +24,13 @@ #include "android-base/stringprintf.h" #include "arch/instruction_set.h" +#include "base/os.h" +#include "base/utils.h" #include "common_runtime_test.h" #include "exec_utils.h" #include "gc/heap.h" #include "gc/space/image_space.h" -#include "os.h" #include "runtime.h" -#include "utils.h" namespace art { diff --git a/libartbase/Android.bp b/libartbase/Android.bp index 290d39844c..3c61944477 100644 --- a/libartbase/Android.bp +++ b/libartbase/Android.bp @@ -14,15 +14,100 @@ // limitations under the License. // +cc_defaults { + name: "libartbase_defaults", + defaults: ["art_defaults"], + host_supported: true, + srcs: [ + "base/allocator.cc", + "base/bit_vector.cc", + "base/file_magic.cc", + "base/hex_dump.cc", + "base/logging.cc", + "base/os_linux.cc", + "base/runtime_debug.cc", + "base/safe_copy.cc", + "base/scoped_flock.cc", + "base/time_utils.cc", + "base/unix_file/fd_file.cc", + "base/unix_file/random_access_file_utils.cc", + "base/utils.cc", + ], + generated_sources: ["art_libartbase_operator_srcs"], + cflags: ["-DBUILDING_LIBART=1"], + shared_libs: [ + // For common macros. + "libbase", + "liblog", + ], + export_include_dirs: ["."], + // ART's macros.h depends on libbase's macros.h. + // Note: runtime_options.h depends on cmdline. But we don't really want to export this + // generically. dex2oat takes care of it itself. + export_shared_lib_headers: ["libbase"], +} + +gensrcs { + name: "art_libartbase_operator_srcs", + cmd: "$(location generate_operator_out) art/libartbase $(in) > $(out)", + tools: ["generate_operator_out"], + srcs: [ + "base/allocator.h", + "base/callee_save_type.h", + "base/unix_file/fd_file.h", + ], + output_extension: "operator_out.cc", +} + +art_cc_library { + name: "libartbase", + defaults: ["libartbase_defaults"], + // Leave the symbols in the shared library so that stack unwinders can + // produce meaningful name resolution. + strip: { + keep_symbols: true, + }, + shared_libs: ["libbase"], + export_shared_lib_headers: ["libbase"], +} + +art_cc_library { + name: "libartbased", + defaults: [ + "art_debug_defaults", + "libartbase_defaults", + ], + shared_libs: ["libbase"], + export_shared_lib_headers: ["libbase"], +} + +// For now many of these tests still use CommonRuntimeTest, almost universally because of +// ScratchFile and related. +// TODO: Remove CommonRuntimeTest dependency from these tests. art_cc_test { name: "art_libartbase_tests", defaults: [ "art_gtest_defaults", ], srcs: [ + "base/bit_field_test.cc", + "base/bit_string_test.cc", + "base/bit_struct_test.cc", "base/bit_utils_test.cc", + "base/bit_vector_test.cc", "base/hash_set_test.cc", + "base/hex_dump_test.cc", + "base/histogram_test.cc", "base/leb128_test.cc", + "base/logging_test.cc", + "base/safe_copy_test.cc", + "base/scoped_flock_test.cc", + "base/time_utils_test.cc", + "base/transform_array_ref_test.cc", + "base/transform_iterator_test.cc", + "base/unix_file/fd_file_test.cc", + "base/utils_test.cc", + "base/variant_map_test.cc", ], shared_libs: [ "libbase", @@ -36,4 +121,3 @@ cc_library_headers { shared_libs: ["libbase"], export_shared_lib_headers: ["libbase"], } - diff --git a/runtime/base/aborting.h b/libartbase/base/aborting.h index 8906c96ea7..c7089af695 100644 --- a/runtime/base/aborting.h +++ b/libartbase/base/aborting.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_ABORTING_H_ -#define ART_RUNTIME_BASE_ABORTING_H_ +#ifndef ART_LIBARTBASE_BASE_ABORTING_H_ +#define ART_LIBARTBASE_BASE_ABORTING_H_ #include <atomic> @@ -28,4 +28,4 @@ extern std::atomic<unsigned int> gAborting; } // namespace art -#endif // ART_RUNTIME_BASE_ABORTING_H_ +#endif // ART_LIBARTBASE_BASE_ABORTING_H_ diff --git a/runtime/base/allocator.cc b/libartbase/base/allocator.cc index 2da88c3830..a42414507b 100644 --- a/runtime/base/allocator.cc +++ b/libartbase/base/allocator.cc @@ -21,7 +21,7 @@ #include <android-base/logging.h> -#include "atomic.h" +#include "base/atomic.h" namespace art { diff --git a/runtime/base/allocator.h b/libartbase/base/allocator.h index 3cedb66abe..d92fe193e6 100644 --- a/runtime/base/allocator.h +++ b/libartbase/base/allocator.h @@ -14,14 +14,13 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_ALLOCATOR_H_ -#define ART_RUNTIME_BASE_ALLOCATOR_H_ +#ifndef ART_LIBARTBASE_BASE_ALLOCATOR_H_ +#define ART_LIBARTBASE_BASE_ALLOCATOR_H_ #include <type_traits> -#include "atomic.h" +#include "base/atomic.h" #include "base/macros.h" -#include "base/mutex.h" namespace art { @@ -154,4 +153,4 @@ using TrackingAllocator = typename std::conditional<kEnableTrackingAllocator, } // namespace art -#endif // ART_RUNTIME_BASE_ALLOCATOR_H_ +#endif // ART_LIBARTBASE_BASE_ALLOCATOR_H_ diff --git a/runtime/base/array_ref.h b/libartbase/base/array_ref.h index 2753c81bd5..1d7bde6044 100644 --- a/runtime/base/array_ref.h +++ b/libartbase/base/array_ref.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_ARRAY_REF_H_ -#define ART_RUNTIME_BASE_ARRAY_REF_H_ +#ifndef ART_LIBARTBASE_BASE_ARRAY_REF_H_ +#define ART_LIBARTBASE_BASE_ARRAY_REF_H_ #include <type_traits> #include <vector> @@ -206,4 +206,4 @@ bool operator!=(const ArrayRef<T>& lhs, const ArrayRef<T>& rhs) { } // namespace art -#endif // ART_RUNTIME_BASE_ARRAY_REF_H_ +#endif // ART_LIBARTBASE_BASE_ARRAY_REF_H_ diff --git a/runtime/base/array_slice.h b/libartbase/base/array_slice.h index a7bce7dc56..1ef2fbad8b 100644 --- a/runtime/base/array_slice.h +++ b/libartbase/base/array_slice.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_ARRAY_SLICE_H_ -#define ART_RUNTIME_BASE_ARRAY_SLICE_H_ +#ifndef ART_LIBARTBASE_BASE_ARRAY_SLICE_H_ +#define ART_LIBARTBASE_BASE_ARRAY_SLICE_H_ #include "base/bit_utils.h" #include "base/casts.h" @@ -149,4 +149,4 @@ class ArraySlice { } // namespace art -#endif // ART_RUNTIME_BASE_ARRAY_SLICE_H_ +#endif // ART_LIBARTBASE_BASE_ARRAY_SLICE_H_ diff --git a/runtime/atomic.h b/libartbase/base/atomic.h index 0e2f056d3a..fd34cc6143 100644 --- a/runtime/atomic.h +++ b/libartbase/base/atomic.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_ATOMIC_H_ -#define ART_RUNTIME_ATOMIC_H_ +#ifndef ART_LIBARTBASE_BASE_ATOMIC_H_ +#define ART_LIBARTBASE_BASE_ATOMIC_H_ #include <stdint.h> #include <atomic> @@ -24,167 +24,10 @@ #include <android-base/logging.h> -#include "arch/instruction_set.h" #include "base/macros.h" namespace art { -class Mutex; - -// QuasiAtomic encapsulates two separate facilities that we are -// trying to move away from: "quasiatomic" 64 bit operations -// and custom memory fences. For the time being, they remain -// exposed. Clients should be converted to use either class Atomic -// below whenever possible, and should eventually use C++11 atomics. -// The two facilities that do not have a good C++11 analog are -// ThreadFenceForConstructor and Atomic::*JavaData. -// -// NOTE: Two "quasiatomic" operations on the exact same memory address -// are guaranteed to operate atomically with respect to each other, -// but no guarantees are made about quasiatomic operations mixed with -// non-quasiatomic operations on the same address, nor about -// quasiatomic operations that are performed on partially-overlapping -// memory. -class QuasiAtomic { - static constexpr bool NeedSwapMutexes(InstructionSet isa) { - // TODO - mips64 still need this for Cas64 ??? - return (isa == InstructionSet::kMips) || (isa == InstructionSet::kMips64); - } - - public: - static void Startup(); - - static void Shutdown(); - - // Reads the 64-bit value at "addr" without tearing. - static int64_t Read64(volatile const int64_t* addr) { - if (!NeedSwapMutexes(kRuntimeISA)) { - int64_t value; -#if defined(__LP64__) - value = *addr; -#else -#if defined(__arm__) -#if defined(__ARM_FEATURE_LPAE) - // With LPAE support (such as Cortex-A15) then ldrd is defined not to tear. - __asm__ __volatile__("@ QuasiAtomic::Read64\n" - "ldrd %0, %H0, %1" - : "=r" (value) - : "m" (*addr)); -#else - // Exclusive loads are defined not to tear, clearing the exclusive state isn't necessary. - __asm__ __volatile__("@ QuasiAtomic::Read64\n" - "ldrexd %0, %H0, %1" - : "=r" (value) - : "Q" (*addr)); -#endif -#elif defined(__i386__) - __asm__ __volatile__( - "movq %1, %0\n" - : "=x" (value) - : "m" (*addr)); -#else - LOG(FATAL) << "Unsupported architecture"; -#endif -#endif // defined(__LP64__) - return value; - } else { - return SwapMutexRead64(addr); - } - } - - // Writes to the 64-bit value at "addr" without tearing. - static void Write64(volatile int64_t* addr, int64_t value) { - if (!NeedSwapMutexes(kRuntimeISA)) { -#if defined(__LP64__) - *addr = value; -#else -#if defined(__arm__) -#if defined(__ARM_FEATURE_LPAE) - // If we know that ARM architecture has LPAE (such as Cortex-A15) strd is defined not to tear. - __asm__ __volatile__("@ QuasiAtomic::Write64\n" - "strd %1, %H1, %0" - : "=m"(*addr) - : "r" (value)); -#else - // The write is done as a swap so that the cache-line is in the exclusive state for the store. - int64_t prev; - int status; - do { - __asm__ __volatile__("@ QuasiAtomic::Write64\n" - "ldrexd %0, %H0, %2\n" - "strexd %1, %3, %H3, %2" - : "=&r" (prev), "=&r" (status), "+Q"(*addr) - : "r" (value) - : "cc"); - } while (UNLIKELY(status != 0)); -#endif -#elif defined(__i386__) - __asm__ __volatile__( - "movq %1, %0" - : "=m" (*addr) - : "x" (value)); -#else - LOG(FATAL) << "Unsupported architecture"; -#endif -#endif // defined(__LP64__) - } else { - SwapMutexWrite64(addr, value); - } - } - - // Atomically compare the value at "addr" to "old_value", if equal replace it with "new_value" - // and return true. Otherwise, don't swap, and return false. - // This is fully ordered, i.e. it has C++11 memory_order_seq_cst - // semantics (assuming all other accesses use a mutex if this one does). - // This has "strong" semantics; if it fails then it is guaranteed that - // at some point during the execution of Cas64, *addr was not equal to - // old_value. - static bool Cas64(int64_t old_value, int64_t new_value, volatile int64_t* addr) { - if (!NeedSwapMutexes(kRuntimeISA)) { - return __sync_bool_compare_and_swap(addr, old_value, new_value); - } else { - return SwapMutexCas64(old_value, new_value, addr); - } - } - - // Does the architecture provide reasonable atomic long operations or do we fall back on mutexes? - static bool LongAtomicsUseMutexes(InstructionSet isa) { - return NeedSwapMutexes(isa); - } - - static void ThreadFenceAcquire() { - std::atomic_thread_fence(std::memory_order_acquire); - } - - static void ThreadFenceRelease() { - std::atomic_thread_fence(std::memory_order_release); - } - - static void ThreadFenceForConstructor() { - #if defined(__aarch64__) - __asm__ __volatile__("dmb ishst" : : : "memory"); - #else - std::atomic_thread_fence(std::memory_order_release); - #endif - } - - static void ThreadFenceSequentiallyConsistent() { - std::atomic_thread_fence(std::memory_order_seq_cst); - } - - private: - static Mutex* GetSwapMutex(const volatile int64_t* addr); - static int64_t SwapMutexRead64(volatile const int64_t* addr); - static void SwapMutexWrite64(volatile int64_t* addr, int64_t val); - static bool SwapMutexCas64(int64_t old_value, int64_t new_value, volatile int64_t* addr); - - // We stripe across a bunch of different mutexes to reduce contention. - static constexpr size_t kSwapMutexCount = 32; - static std::vector<Mutex*>* gSwapMutexes; - - DISALLOW_COPY_AND_ASSIGN(QuasiAtomic); -}; - template<typename T> class PACKED(sizeof(T)) Atomic : public std::atomic<T> { public: @@ -409,4 +252,4 @@ static_assert(sizeof(Atomic<int64_t>) == sizeof(int64_t), "Weird Atomic<int64> s } // namespace art -#endif // ART_RUNTIME_ATOMIC_H_ +#endif // ART_LIBARTBASE_BASE_ATOMIC_H_ diff --git a/runtime/base/bit_field.h b/libartbase/base/bit_field.h index 86007d6a35..9971735138 100644 --- a/runtime/base/bit_field.h +++ b/libartbase/base/bit_field.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_BIT_FIELD_H_ -#define ART_RUNTIME_BASE_BIT_FIELD_H_ +#ifndef ART_LIBARTBASE_BASE_BIT_FIELD_H_ +#define ART_LIBARTBASE_BASE_BIT_FIELD_H_ #include <android-base/logging.h> @@ -89,4 +89,4 @@ class BitField { } // namespace art -#endif // ART_RUNTIME_BASE_BIT_FIELD_H_ +#endif // ART_LIBARTBASE_BASE_BIT_FIELD_H_ diff --git a/runtime/base/bit_field_test.cc b/libartbase/base/bit_field_test.cc index afeb2c4422..afeb2c4422 100644 --- a/runtime/base/bit_field_test.cc +++ b/libartbase/base/bit_field_test.cc diff --git a/runtime/base/bit_string.h b/libartbase/base/bit_string.h index 7d9fb70de7..0e051f358b 100644 --- a/runtime/base/bit_string.h +++ b/libartbase/base/bit_string.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_BIT_STRING_H_ -#define ART_RUNTIME_BASE_BIT_STRING_H_ +#ifndef ART_LIBARTBASE_BASE_BIT_STRING_H_ +#define ART_LIBARTBASE_BASE_BIT_STRING_H_ #include "base/bit_struct.h" #include "base/bit_utils.h" @@ -296,4 +296,4 @@ inline std::ostream& operator<<(std::ostream& os, const BitString& bit_string) { } // namespace art -#endif // ART_RUNTIME_BASE_BIT_STRING_H_ +#endif // ART_LIBARTBASE_BASE_BIT_STRING_H_ diff --git a/runtime/base/bit_string_test.cc b/libartbase/base/bit_string_test.cc index 23274e3f2f..23274e3f2f 100644 --- a/runtime/base/bit_string_test.cc +++ b/libartbase/base/bit_string_test.cc diff --git a/runtime/base/bit_struct.h b/libartbase/base/bit_struct.h index 7eb63c6b5c..386b896073 100644 --- a/runtime/base/bit_struct.h +++ b/libartbase/base/bit_struct.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_BIT_STRUCT_H_ -#define ART_RUNTIME_BASE_BIT_STRUCT_H_ +#ifndef ART_LIBARTBASE_BASE_BIT_STRUCT_H_ +#define ART_LIBARTBASE_BASE_BIT_STRUCT_H_ #include "base/bit_utils.h" #include "bit_struct_detail.h" @@ -303,4 +303,4 @@ static constexpr size_t BitStructSizeOf() { } // namespace art -#endif // ART_RUNTIME_BASE_BIT_STRUCT_H_ +#endif // ART_LIBARTBASE_BASE_BIT_STRUCT_H_ diff --git a/runtime/base/bit_struct_detail.h b/libartbase/base/bit_struct_detail.h index 24f6c4c85e..facfa61efb 100644 --- a/runtime/base/bit_struct_detail.h +++ b/libartbase/base/bit_struct_detail.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_BIT_STRUCT_DETAIL_H_ -#define ART_RUNTIME_BASE_BIT_STRUCT_DETAIL_H_ +#ifndef ART_LIBARTBASE_BASE_BIT_STRUCT_DETAIL_H_ +#define ART_LIBARTBASE_BASE_BIT_STRUCT_DETAIL_H_ #include "base/bit_utils.h" #include "globals.h" @@ -116,4 +116,4 @@ static constexpr bool ValidateBitStructSize() { } // namespace detail } // namespace art -#endif // ART_RUNTIME_BASE_BIT_STRUCT_DETAIL_H_ +#endif // ART_LIBARTBASE_BASE_BIT_STRUCT_DETAIL_H_ diff --git a/runtime/base/bit_struct_test.cc b/libartbase/base/bit_struct_test.cc index 577682ccce..577682ccce 100644 --- a/runtime/base/bit_struct_test.cc +++ b/libartbase/base/bit_struct_test.cc diff --git a/runtime/base/bit_vector-inl.h b/libartbase/base/bit_vector-inl.h index e67d4e25eb..7a9f4650da 100644 --- a/runtime/base/bit_vector-inl.h +++ b/libartbase/base/bit_vector-inl.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_BIT_VECTOR_INL_H_ -#define ART_RUNTIME_BASE_BIT_VECTOR_INL_H_ +#ifndef ART_LIBARTBASE_BASE_BIT_VECTOR_INL_H_ +#define ART_LIBARTBASE_BASE_BIT_VECTOR_INL_H_ #include "bit_vector.h" @@ -97,4 +97,4 @@ inline bool BitVector::Equal(const BitVector* src) const { } // namespace art -#endif // ART_RUNTIME_BASE_BIT_VECTOR_INL_H_ +#endif // ART_LIBARTBASE_BASE_BIT_VECTOR_INL_H_ diff --git a/runtime/base/bit_vector.cc b/libartbase/base/bit_vector.cc index c706c7ebf2..c706c7ebf2 100644 --- a/runtime/base/bit_vector.cc +++ b/libartbase/base/bit_vector.cc diff --git a/runtime/base/bit_vector.h b/libartbase/base/bit_vector.h index 564092a1a2..2ffa2aa9c9 100644 --- a/runtime/base/bit_vector.h +++ b/libartbase/base/bit_vector.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_BIT_VECTOR_H_ -#define ART_RUNTIME_BASE_BIT_VECTOR_H_ +#ifndef ART_LIBARTBASE_BASE_BIT_VECTOR_H_ +#define ART_LIBARTBASE_BASE_BIT_VECTOR_H_ #include <stdint.h> #include <iterator> @@ -293,4 +293,4 @@ class BitVector { } // namespace art -#endif // ART_RUNTIME_BASE_BIT_VECTOR_H_ +#endif // ART_LIBARTBASE_BASE_BIT_VECTOR_H_ diff --git a/runtime/base/bit_vector_test.cc b/libartbase/base/bit_vector_test.cc index 0e3df76fe2..0e3df76fe2 100644 --- a/runtime/base/bit_vector_test.cc +++ b/libartbase/base/bit_vector_test.cc diff --git a/runtime/base/bounded_fifo.h b/libartbase/base/bounded_fifo.h index 1520770fe6..444f31a55b 100644 --- a/runtime/base/bounded_fifo.h +++ b/libartbase/base/bounded_fifo.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_BOUNDED_FIFO_H_ -#define ART_RUNTIME_BASE_BOUNDED_FIFO_H_ +#ifndef ART_LIBARTBASE_BASE_BOUNDED_FIFO_H_ +#define ART_LIBARTBASE_BASE_BOUNDED_FIFO_H_ #include <android-base/logging.h> @@ -72,4 +72,4 @@ class BoundedFifoPowerOfTwo { } // namespace art -#endif // ART_RUNTIME_BASE_BOUNDED_FIFO_H_ +#endif // ART_LIBARTBASE_BASE_BOUNDED_FIFO_H_ diff --git a/runtime/base/callee_save_type.h b/libartbase/base/callee_save_type.h index e9cd63c3a0..3e44a3a73f 100644 --- a/runtime/base/callee_save_type.h +++ b/libartbase/base/callee_save_type.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_CALLEE_SAVE_TYPE_H_ -#define ART_RUNTIME_BASE_CALLEE_SAVE_TYPE_H_ +#ifndef ART_LIBARTBASE_BASE_CALLEE_SAVE_TYPE_H_ +#define ART_LIBARTBASE_BASE_CALLEE_SAVE_TYPE_H_ #include <cstddef> #include <ostream> @@ -44,4 +44,4 @@ static inline constexpr CalleeSaveType GetCanonicalCalleeSaveType(CalleeSaveType } // namespace art -#endif // ART_RUNTIME_BASE_CALLEE_SAVE_TYPE_H_ +#endif // ART_LIBARTBASE_BASE_CALLEE_SAVE_TYPE_H_ diff --git a/runtime/base/dchecked_vector.h b/libartbase/base/dchecked_vector.h index 7236ac301a..e9ce6d0aaf 100644 --- a/runtime/base/dchecked_vector.h +++ b/libartbase/base/dchecked_vector.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_DCHECKED_VECTOR_H_ -#define ART_RUNTIME_BASE_DCHECKED_VECTOR_H_ +#ifndef ART_LIBARTBASE_BASE_DCHECKED_VECTOR_H_ +#define ART_LIBARTBASE_BASE_DCHECKED_VECTOR_H_ #include <algorithm> #include <type_traits> @@ -225,4 +225,4 @@ bool operator>=(const dchecked_vector<T, Alloc>& lhs, const dchecked_vector<T, A } // namespace art -#endif // ART_RUNTIME_BASE_DCHECKED_VECTOR_H_ +#endif // ART_LIBARTBASE_BASE_DCHECKED_VECTOR_H_ diff --git a/runtime/base/debug_stack.h b/libartbase/base/debug_stack.h index 1331e10a02..f2d93d462a 100644 --- a/runtime/base/debug_stack.h +++ b/libartbase/base/debug_stack.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_DEBUG_STACK_H_ -#define ART_RUNTIME_BASE_DEBUG_STACK_H_ +#ifndef ART_LIBARTBASE_BASE_DEBUG_STACK_H_ +#define ART_LIBARTBASE_BASE_DEBUG_STACK_H_ #include <android-base/logging.h> #include <android-base/macros.h> @@ -144,4 +144,4 @@ class DebugStackIndirectTopRefImpl { } // namespace art -#endif // ART_RUNTIME_BASE_DEBUG_STACK_H_ +#endif // ART_LIBARTBASE_BASE_DEBUG_STACK_H_ diff --git a/runtime/base/file_magic.cc b/libartbase/base/file_magic.cc index 2b9bed0397..2b9bed0397 100644 --- a/runtime/base/file_magic.cc +++ b/libartbase/base/file_magic.cc diff --git a/runtime/base/file_magic.h b/libartbase/base/file_magic.h index e7bd706a5c..53f551cb3a 100644 --- a/runtime/base/file_magic.h +++ b/libartbase/base/file_magic.h @@ -14,13 +14,13 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_FILE_MAGIC_H_ -#define ART_RUNTIME_BASE_FILE_MAGIC_H_ +#ifndef ART_LIBARTBASE_BASE_FILE_MAGIC_H_ +#define ART_LIBARTBASE_BASE_FILE_MAGIC_H_ #include <stdint.h> #include <string> -#include "os.h" +#include "base/os.h" namespace art { @@ -35,4 +35,4 @@ bool IsZipMagic(uint32_t magic); } // namespace art -#endif // ART_RUNTIME_BASE_FILE_MAGIC_H_ +#endif // ART_LIBARTBASE_BASE_FILE_MAGIC_H_ diff --git a/runtime/base/hex_dump.cc b/libartbase/base/hex_dump.cc index bce6b53f4d..bce6b53f4d 100644 --- a/runtime/base/hex_dump.cc +++ b/libartbase/base/hex_dump.cc diff --git a/runtime/base/hex_dump.h b/libartbase/base/hex_dump.h index 2ce0aefe67..55f4d53c2e 100644 --- a/runtime/base/hex_dump.h +++ b/libartbase/base/hex_dump.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_HEX_DUMP_H_ -#define ART_RUNTIME_BASE_HEX_DUMP_H_ +#ifndef ART_LIBARTBASE_BASE_HEX_DUMP_H_ +#define ART_LIBARTBASE_BASE_HEX_DUMP_H_ #include "base/macros.h" @@ -52,4 +52,4 @@ inline std::ostream& operator<<(std::ostream& os, const HexDump& rhs) { } // namespace art -#endif // ART_RUNTIME_BASE_HEX_DUMP_H_ +#endif // ART_LIBARTBASE_BASE_HEX_DUMP_H_ diff --git a/runtime/base/hex_dump_test.cc b/libartbase/base/hex_dump_test.cc index bfd5c75284..bfd5c75284 100644 --- a/runtime/base/hex_dump_test.cc +++ b/libartbase/base/hex_dump_test.cc diff --git a/runtime/base/histogram-inl.h b/libartbase/base/histogram-inl.h index 3ce0140c84..26d01b2883 100644 --- a/runtime/base/histogram-inl.h +++ b/libartbase/base/histogram-inl.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_HISTOGRAM_INL_H_ -#define ART_RUNTIME_BASE_HISTOGRAM_INL_H_ +#ifndef ART_LIBARTBASE_BASE_HISTOGRAM_INL_H_ +#define ART_LIBARTBASE_BASE_HISTOGRAM_INL_H_ #include <algorithm> #include <cmath> @@ -28,7 +28,7 @@ #include "base/bit_utils.h" #include "base/time_utils.h" -#include "utils.h" +#include "base/utils.h" namespace art { @@ -277,4 +277,4 @@ inline double Histogram<Value>::Percentile(double per, const CumulativeData& dat #pragma clang diagnostic pop } // namespace art -#endif // ART_RUNTIME_BASE_HISTOGRAM_INL_H_ +#endif // ART_LIBARTBASE_BASE_HISTOGRAM_INL_H_ diff --git a/runtime/base/histogram.h b/libartbase/base/histogram.h index 7544a9c918..39a1866b4d 100644 --- a/runtime/base/histogram.h +++ b/libartbase/base/histogram.h @@ -13,8 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_HISTOGRAM_H_ -#define ART_RUNTIME_BASE_HISTOGRAM_H_ +#ifndef ART_LIBARTBASE_BASE_HISTOGRAM_H_ +#define ART_LIBARTBASE_BASE_HISTOGRAM_H_ #include <string> #include <vector> @@ -128,4 +128,4 @@ template <class Value> class Histogram { }; } // namespace art -#endif // ART_RUNTIME_BASE_HISTOGRAM_H_ +#endif // ART_LIBARTBASE_BASE_HISTOGRAM_H_ diff --git a/runtime/base/histogram_test.cc b/libartbase/base/histogram_test.cc index 7aa5f9037f..7aa5f9037f 100644 --- a/runtime/base/histogram_test.cc +++ b/libartbase/base/histogram_test.cc diff --git a/runtime/base/length_prefixed_array.h b/libartbase/base/length_prefixed_array.h index 2df5a99352..7c09bddd55 100644 --- a/runtime/base/length_prefixed_array.h +++ b/libartbase/base/length_prefixed_array.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_LENGTH_PREFIXED_ARRAY_H_ -#define ART_RUNTIME_BASE_LENGTH_PREFIXED_ARRAY_H_ +#ifndef ART_LIBARTBASE_BASE_LENGTH_PREFIXED_ARRAY_H_ +#define ART_LIBARTBASE_BASE_LENGTH_PREFIXED_ARRAY_H_ #include <stddef.h> // for offsetof() #include <string.h> // for memset() @@ -23,7 +23,7 @@ #include "base/bit_utils.h" #include "base/casts.h" #include "base/iteration_range.h" -#include "stride_iterator.h" +#include "base/stride_iterator.h" namespace art { @@ -118,4 +118,4 @@ IterationRange<StrideIterator<T>> MakeIterationRangeFromLengthPrefixedArray( } // namespace art -#endif // ART_RUNTIME_BASE_LENGTH_PREFIXED_ARRAY_H_ +#endif // ART_LIBARTBASE_BASE_LENGTH_PREFIXED_ARRAY_H_ diff --git a/runtime/base/logging.cc b/libartbase/base/logging.cc index 78d54292d1..37b1f8264a 100644 --- a/runtime/base/logging.cc +++ b/libartbase/base/logging.cc @@ -21,8 +21,6 @@ #include <sstream> #include "aborting.h" -#include "mutex.h" -#include "utils.h" // Headers for LogMessage::LogLine. #ifdef ART_TARGET_ANDROID @@ -59,8 +57,6 @@ void InitLogging(char* argv[], AbortFunction& abort_function) { if (gCmdLine.get() != nullptr) { return; } - // TODO: Move this to a more obvious InitART... - Locks::Init(); // Stash the command line for later use. We can use /proc/self/cmdline on Linux to recover this, // but we don't have that luxury on the Mac, and there are a couple of argv[0] variants that are diff --git a/runtime/base/logging.h b/libartbase/base/logging.h index c562bdf59f..fd5fc74383 100644 --- a/runtime/base/logging.h +++ b/libartbase/base/logging.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_LOGGING_H_ -#define ART_RUNTIME_BASE_LOGGING_H_ +#ifndef ART_LIBARTBASE_BASE_LOGGING_H_ +#define ART_LIBARTBASE_BASE_LOGGING_H_ #include <ostream> #include <sstream> @@ -110,4 +110,4 @@ class LogHelper { } // namespace art -#endif // ART_RUNTIME_BASE_LOGGING_H_ +#endif // ART_LIBARTBASE_BASE_LOGGING_H_ diff --git a/runtime/base/logging_test.cc b/libartbase/base/logging_test.cc index 404e080b03..404e080b03 100644 --- a/runtime/base/logging_test.cc +++ b/libartbase/base/logging_test.cc diff --git a/runtime/os.h b/libartbase/base/os.h index 7130fc3732..4062d90f88 100644 --- a/runtime/os.h +++ b/libartbase/base/os.h @@ -14,8 +14,10 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_OS_H_ -#define ART_RUNTIME_OS_H_ +#ifndef ART_LIBARTBASE_BASE_OS_H_ +#define ART_LIBARTBASE_BASE_OS_H_ + +#include <stdint.h> namespace unix_file { class FdFile; @@ -47,12 +49,15 @@ class OS { static File* OpenFileWithFlags(const char* name, int flags, bool auto_flush = true); // Check if a file exists. - static bool FileExists(const char* name); + static bool FileExists(const char* name, bool check_file_type = true); // Check if a directory exists. static bool DirectoryExists(const char* name); + + // Get the size of a file (or -1 if it does not exist). + static int64_t GetFileSizeBytes(const char* name); }; } // namespace art -#endif // ART_RUNTIME_OS_H_ +#endif // ART_LIBARTBASE_BASE_OS_H_ diff --git a/runtime/os_linux.cc b/libartbase/base/os_linux.cc index 1b3e0000da..6b5a604423 100644 --- a/runtime/os_linux.cc +++ b/libartbase/base/os_linux.cc @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "os.h" +#include "base/os.h" #include <fcntl.h> #include <sys/stat.h> @@ -64,10 +64,14 @@ File* OS::OpenFileWithFlags(const char* name, int flags, bool auto_flush) { return file.release(); } -bool OS::FileExists(const char* name) { +bool OS::FileExists(const char* name, bool check_file_type) { struct stat st; if (stat(name, &st) == 0) { - return S_ISREG(st.st_mode); // TODO: Deal with symlinks? + if (check_file_type) { + return S_ISREG(st.st_mode); // TODO: Deal with symlinks? + } else { + return true; + } } else { return false; } @@ -82,4 +86,13 @@ bool OS::DirectoryExists(const char* name) { } } +int64_t OS::GetFileSizeBytes(const char* name) { + struct stat st; + if (stat(name, &st) == 0) { + return -1; // TODO: Deal with symlinks? + } else { + return st.st_size; + } +} + } // namespace art diff --git a/runtime/base/runtime_debug.cc b/libartbase/base/runtime_debug.cc index 4f8a8ec9c6..4f8a8ec9c6 100644 --- a/runtime/base/runtime_debug.cc +++ b/libartbase/base/runtime_debug.cc diff --git a/runtime/base/runtime_debug.h b/libartbase/base/runtime_debug.h index 89a0361fa7..7d91166aa7 100644 --- a/runtime/base/runtime_debug.h +++ b/libartbase/base/runtime_debug.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_RUNTIME_DEBUG_H_ -#define ART_RUNTIME_BASE_RUNTIME_DEBUG_H_ +#ifndef ART_LIBARTBASE_BASE_RUNTIME_DEBUG_H_ +#define ART_LIBARTBASE_BASE_RUNTIME_DEBUG_H_ namespace art { @@ -58,4 +58,4 @@ void SetRuntimeDebugFlagsEnabled(bool enabled); } // namespace art -#endif // ART_RUNTIME_BASE_RUNTIME_DEBUG_H_ +#endif // ART_LIBARTBASE_BASE_RUNTIME_DEBUG_H_ diff --git a/runtime/base/safe_copy.cc b/libartbase/base/safe_copy.cc index 7ba5cbd3e6..7ba5cbd3e6 100644 --- a/runtime/base/safe_copy.cc +++ b/libartbase/base/safe_copy.cc diff --git a/runtime/base/safe_copy.h b/libartbase/base/safe_copy.h index d0f497c0bd..56cdfecc2d 100644 --- a/runtime/base/safe_copy.h +++ b/libartbase/base/safe_copy.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_SAFE_COPY_H_ -#define ART_RUNTIME_BASE_SAFE_COPY_H_ +#ifndef ART_LIBARTBASE_BASE_SAFE_COPY_H_ +#define ART_LIBARTBASE_BASE_SAFE_COPY_H_ #include <sys/types.h> @@ -28,4 +28,4 @@ ssize_t SafeCopy(void *dst, const void *src, size_t len); } // namespace art -#endif // ART_RUNTIME_BASE_SAFE_COPY_H_ +#endif // ART_LIBARTBASE_BASE_SAFE_COPY_H_ diff --git a/runtime/base/safe_copy_test.cc b/libartbase/base/safe_copy_test.cc index a9ec9528a1..a9ec9528a1 100644 --- a/runtime/base/safe_copy_test.cc +++ b/libartbase/base/safe_copy_test.cc diff --git a/runtime/base/scoped_flock.cc b/libartbase/base/scoped_flock.cc index 514b97bfb1..514b97bfb1 100644 --- a/runtime/base/scoped_flock.cc +++ b/libartbase/base/scoped_flock.cc diff --git a/runtime/base/scoped_flock.h b/libartbase/base/scoped_flock.h index db6c819c6c..476b25748b 100644 --- a/runtime/base/scoped_flock.h +++ b/libartbase/base/scoped_flock.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_SCOPED_FLOCK_H_ -#define ART_RUNTIME_BASE_SCOPED_FLOCK_H_ +#ifndef ART_LIBARTBASE_BASE_SCOPED_FLOCK_H_ +#define ART_LIBARTBASE_BASE_SCOPED_FLOCK_H_ #include <memory> #include <string> @@ -23,8 +23,8 @@ #include <android-base/unique_fd.h> #include "base/macros.h" +#include "base/os.h" #include "base/unix_file/fd_file.h" -#include "os.h" namespace art { @@ -85,4 +85,4 @@ class LockedFileCloseNoFlush { } // namespace art -#endif // ART_RUNTIME_BASE_SCOPED_FLOCK_H_ +#endif // ART_LIBARTBASE_BASE_SCOPED_FLOCK_H_ diff --git a/runtime/base/scoped_flock_test.cc b/libartbase/base/scoped_flock_test.cc index 1b6caaf747..1b6caaf747 100644 --- a/runtime/base/scoped_flock_test.cc +++ b/libartbase/base/scoped_flock_test.cc diff --git a/runtime/stride_iterator.h b/libartbase/base/stride_iterator.h index 511c2c66f2..67c0d3803e 100644 --- a/runtime/stride_iterator.h +++ b/libartbase/base/stride_iterator.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_STRIDE_ITERATOR_H_ -#define ART_RUNTIME_STRIDE_ITERATOR_H_ +#ifndef ART_LIBARTBASE_BASE_STRIDE_ITERATOR_H_ +#define ART_LIBARTBASE_BASE_STRIDE_ITERATOR_H_ #include <iterator> @@ -147,4 +147,4 @@ bool operator>=(const StrideIterator<T>& lhs, const StrideIterator<T>& rhs) { } // namespace art -#endif // ART_RUNTIME_STRIDE_ITERATOR_H_ +#endif // ART_LIBARTBASE_BASE_STRIDE_ITERATOR_H_ diff --git a/runtime/base/strlcpy.h b/libartbase/base/strlcpy.h index de135ea990..98ea34b0a5 100644 --- a/runtime/base/strlcpy.h +++ b/libartbase/base/strlcpy.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_STRLCPY_H_ -#define ART_RUNTIME_BASE_STRLCPY_H_ +#ifndef ART_LIBARTBASE_BASE_STRLCPY_H_ +#define ART_LIBARTBASE_BASE_STRLCPY_H_ #include <cstdio> #include <cstring> @@ -35,4 +35,4 @@ static inline size_t strlcpy(char* dst, const char* src, size_t size) { #endif -#endif // ART_RUNTIME_BASE_STRLCPY_H_ +#endif // ART_LIBARTBASE_BASE_STRLCPY_H_ diff --git a/runtime/base/systrace.h b/libartbase/base/systrace.h index dc2206e420..2ff33e8c84 100644 --- a/runtime/base/systrace.h +++ b/libartbase/base/systrace.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_SYSTRACE_H_ -#define ART_RUNTIME_BASE_SYSTRACE_H_ +#ifndef ART_LIBARTBASE_BASE_SYSTRACE_H_ +#define ART_LIBARTBASE_BASE_SYSTRACE_H_ #define ATRACE_TAG ATRACE_TAG_DALVIK #include <cutils/trace.h> @@ -80,4 +80,4 @@ class ScopedTraceNoStart { } // namespace art -#endif // ART_RUNTIME_BASE_SYSTRACE_H_ +#endif // ART_LIBARTBASE_BASE_SYSTRACE_H_ diff --git a/runtime/base/time_utils.cc b/libartbase/base/time_utils.cc index 3c09d5a36f..3c09d5a36f 100644 --- a/runtime/base/time_utils.cc +++ b/libartbase/base/time_utils.cc diff --git a/runtime/base/time_utils.h b/libartbase/base/time_utils.h index 7648a109fa..811af5d682 100644 --- a/runtime/base/time_utils.h +++ b/libartbase/base/time_utils.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_TIME_UTILS_H_ -#define ART_RUNTIME_BASE_TIME_UTILS_H_ +#ifndef ART_LIBARTBASE_BASE_TIME_UTILS_H_ +#define ART_LIBARTBASE_BASE_TIME_UTILS_H_ #include <stdint.h> #include <time.h> @@ -101,4 +101,4 @@ void InitTimeSpec(bool absolute, int clock, int64_t ms, int32_t ns, timespec* ts } // namespace art -#endif // ART_RUNTIME_BASE_TIME_UTILS_H_ +#endif // ART_LIBARTBASE_BASE_TIME_UTILS_H_ diff --git a/runtime/base/time_utils_test.cc b/libartbase/base/time_utils_test.cc index c553f4ed03..c553f4ed03 100644 --- a/runtime/base/time_utils_test.cc +++ b/libartbase/base/time_utils_test.cc diff --git a/runtime/base/to_str.h b/libartbase/base/to_str.h index 6b1c84c411..74d9584f78 100644 --- a/runtime/base/to_str.h +++ b/libartbase/base/to_str.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_TO_STR_H_ -#define ART_RUNTIME_BASE_TO_STR_H_ +#ifndef ART_LIBARTBASE_BASE_TO_STR_H_ +#define ART_LIBARTBASE_BASE_TO_STR_H_ #include <sstream> @@ -47,4 +47,4 @@ class ToStr { } // namespace art -#endif // ART_RUNTIME_BASE_TO_STR_H_ +#endif // ART_LIBARTBASE_BASE_TO_STR_H_ diff --git a/runtime/base/tracking_safe_map.h b/libartbase/base/tracking_safe_map.h index 2f3984d106..2750de1b94 100644 --- a/runtime/base/tracking_safe_map.h +++ b/libartbase/base/tracking_safe_map.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_TRACKING_SAFE_MAP_H_ -#define ART_RUNTIME_BASE_TRACKING_SAFE_MAP_H_ +#ifndef ART_LIBARTBASE_BASE_TRACKING_SAFE_MAP_H_ +#define ART_LIBARTBASE_BASE_TRACKING_SAFE_MAP_H_ #include "base/allocator.h" #include "base/safe_map.h" @@ -29,4 +29,4 @@ class AllocationTrackingSafeMap : public SafeMap< } // namespace art -#endif // ART_RUNTIME_BASE_TRACKING_SAFE_MAP_H_ +#endif // ART_LIBARTBASE_BASE_TRACKING_SAFE_MAP_H_ diff --git a/runtime/base/transform_array_ref.h b/libartbase/base/transform_array_ref.h index a4e0bc27ed..de2739e2fc 100644 --- a/runtime/base/transform_array_ref.h +++ b/libartbase/base/transform_array_ref.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_TRANSFORM_ARRAY_REF_H_ -#define ART_RUNTIME_BASE_TRANSFORM_ARRAY_REF_H_ +#ifndef ART_LIBARTBASE_BASE_TRANSFORM_ARRAY_REF_H_ +#define ART_LIBARTBASE_BASE_TRANSFORM_ARRAY_REF_H_ #include <type_traits> @@ -193,4 +193,4 @@ TransformArrayRef<const typename Container::value_type, Function> MakeTransformA } // namespace art -#endif // ART_RUNTIME_BASE_TRANSFORM_ARRAY_REF_H_ +#endif // ART_LIBARTBASE_BASE_TRANSFORM_ARRAY_REF_H_ diff --git a/runtime/base/transform_array_ref_test.cc b/libartbase/base/transform_array_ref_test.cc index da0340d36b..da0340d36b 100644 --- a/runtime/base/transform_array_ref_test.cc +++ b/libartbase/base/transform_array_ref_test.cc diff --git a/runtime/base/transform_iterator.h b/libartbase/base/transform_iterator.h index 9c8f822b71..82d9f9e325 100644 --- a/runtime/base/transform_iterator.h +++ b/libartbase/base/transform_iterator.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_TRANSFORM_ITERATOR_H_ -#define ART_RUNTIME_BASE_TRANSFORM_ITERATOR_H_ +#ifndef ART_LIBARTBASE_BASE_TRANSFORM_ITERATOR_H_ +#define ART_LIBARTBASE_BASE_TRANSFORM_ITERATOR_H_ #include <iterator> #include <type_traits> @@ -175,4 +175,4 @@ auto MakeTransformRange(BaseRange& range, Function f) { } // namespace art -#endif // ART_RUNTIME_BASE_TRANSFORM_ITERATOR_H_ +#endif // ART_LIBARTBASE_BASE_TRANSFORM_ITERATOR_H_ diff --git a/runtime/base/transform_iterator_test.cc b/libartbase/base/transform_iterator_test.cc index 63b6e4f531..63b6e4f531 100644 --- a/runtime/base/transform_iterator_test.cc +++ b/libartbase/base/transform_iterator_test.cc diff --git a/runtime/base/unix_file/README b/libartbase/base/unix_file/README index e9aec22954..e9aec22954 100644 --- a/runtime/base/unix_file/README +++ b/libartbase/base/unix_file/README diff --git a/runtime/base/unix_file/fd_file.cc b/libartbase/base/unix_file/fd_file.cc index f9da178de8..b2881b8ed0 100644 --- a/runtime/base/unix_file/fd_file.cc +++ b/libartbase/base/unix_file/fd_file.cc @@ -31,7 +31,7 @@ #else #include <algorithm> #include "base/stl_util.h" -#include "globals.h" +#include "base/globals.h" #endif namespace unix_file { diff --git a/runtime/base/unix_file/fd_file.h b/libartbase/base/unix_file/fd_file.h index 3fb70f644d..fe3317f64e 100644 --- a/runtime/base/unix_file/fd_file.h +++ b/libartbase/base/unix_file/fd_file.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_UNIX_FILE_FD_FILE_H_ -#define ART_RUNTIME_BASE_UNIX_FILE_FD_FILE_H_ +#ifndef ART_LIBARTBASE_BASE_UNIX_FILE_FD_FILE_H_ +#define ART_LIBARTBASE_BASE_UNIX_FILE_FD_FILE_H_ #include <fcntl.h> @@ -192,4 +192,4 @@ std::ostream& operator<<(std::ostream& os, const FdFile::GuardState& kind); } // namespace unix_file -#endif // ART_RUNTIME_BASE_UNIX_FILE_FD_FILE_H_ +#endif // ART_LIBARTBASE_BASE_UNIX_FILE_FD_FILE_H_ diff --git a/runtime/base/unix_file/fd_file_test.cc b/libartbase/base/unix_file/fd_file_test.cc index 042fbc9284..042fbc9284 100644 --- a/runtime/base/unix_file/fd_file_test.cc +++ b/libartbase/base/unix_file/fd_file_test.cc diff --git a/runtime/base/unix_file/random_access_file.h b/libartbase/base/unix_file/random_access_file.h index 31a6dbe1fc..d2124cc843 100644 --- a/runtime/base/unix_file/random_access_file.h +++ b/libartbase/base/unix_file/random_access_file.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_UNIX_FILE_RANDOM_ACCESS_FILE_H_ -#define ART_RUNTIME_BASE_UNIX_FILE_RANDOM_ACCESS_FILE_H_ +#ifndef ART_LIBARTBASE_BASE_UNIX_FILE_RANDOM_ACCESS_FILE_H_ +#define ART_LIBARTBASE_BASE_UNIX_FILE_RANDOM_ACCESS_FILE_H_ #include <stdint.h> @@ -65,4 +65,4 @@ class RandomAccessFile { } // namespace unix_file -#endif // ART_RUNTIME_BASE_UNIX_FILE_RANDOM_ACCESS_FILE_H_ +#endif // ART_LIBARTBASE_BASE_UNIX_FILE_RANDOM_ACCESS_FILE_H_ diff --git a/runtime/base/unix_file/random_access_file_test.h b/libartbase/base/unix_file/random_access_file_test.h index 91858c21de..1de5f7b72c 100644 --- a/runtime/base/unix_file/random_access_file_test.h +++ b/libartbase/base/unix_file/random_access_file_test.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_UNIX_FILE_RANDOM_ACCESS_FILE_TEST_H_ -#define ART_RUNTIME_BASE_UNIX_FILE_RANDOM_ACCESS_FILE_TEST_H_ +#ifndef ART_LIBARTBASE_BASE_UNIX_FILE_RANDOM_ACCESS_FILE_TEST_H_ +#define ART_LIBARTBASE_BASE_UNIX_FILE_RANDOM_ACCESS_FILE_TEST_H_ #include <errno.h> #include <memory> @@ -180,4 +180,4 @@ class RandomAccessFileTest : public testing::Test { } // namespace unix_file -#endif // ART_RUNTIME_BASE_UNIX_FILE_RANDOM_ACCESS_FILE_TEST_H_ +#endif // ART_LIBARTBASE_BASE_UNIX_FILE_RANDOM_ACCESS_FILE_TEST_H_ diff --git a/runtime/base/unix_file/random_access_file_utils.cc b/libartbase/base/unix_file/random_access_file_utils.cc index aae65c1cde..aae65c1cde 100644 --- a/runtime/base/unix_file/random_access_file_utils.cc +++ b/libartbase/base/unix_file/random_access_file_utils.cc diff --git a/runtime/base/unix_file/random_access_file_utils.h b/libartbase/base/unix_file/random_access_file_utils.h index 30c81c09aa..47c4c2a57b 100644 --- a/runtime/base/unix_file/random_access_file_utils.h +++ b/libartbase/base/unix_file/random_access_file_utils.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_UNIX_FILE_RANDOM_ACCESS_FILE_UTILS_H_ -#define ART_RUNTIME_BASE_UNIX_FILE_RANDOM_ACCESS_FILE_UTILS_H_ +#ifndef ART_LIBARTBASE_BASE_UNIX_FILE_RANDOM_ACCESS_FILE_UTILS_H_ +#define ART_LIBARTBASE_BASE_UNIX_FILE_RANDOM_ACCESS_FILE_UTILS_H_ namespace unix_file { @@ -27,4 +27,4 @@ bool CopyFile(const RandomAccessFile& src, RandomAccessFile* dst); } // namespace unix_file -#endif // ART_RUNTIME_BASE_UNIX_FILE_RANDOM_ACCESS_FILE_UTILS_H_ +#endif // ART_LIBARTBASE_BASE_UNIX_FILE_RANDOM_ACCESS_FILE_UTILS_H_ diff --git a/runtime/utils.cc b/libartbase/base/utils.cc index 7246c3d279..029cffd3ab 100644 --- a/runtime/utils.cc +++ b/libartbase/base/utils.cc @@ -30,8 +30,7 @@ #include "android-base/stringprintf.h" #include "android-base/strings.h" -#include "dex/utf-inl.h" -#include "os.h" +#include "base/os.h" #if defined(__APPLE__) #include <crt_externs.h> diff --git a/runtime/utils.h b/libartbase/base/utils.h index 0c3a0a231a..c8c5b72bf7 100644 --- a/runtime/utils.h +++ b/libartbase/base/utils.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_UTILS_H_ -#define ART_RUNTIME_UTILS_H_ +#ifndef ART_LIBARTBASE_BASE_UTILS_H_ +#define ART_LIBARTBASE_BASE_UTILS_H_ #include <pthread.h> #include <stdlib.h> @@ -25,11 +25,11 @@ #include <android-base/logging.h> -#include "arch/instruction_set.h" #include "base/casts.h" +#include "base/enums.h" +#include "base/globals.h" +#include "base/macros.h" #include "base/stringpiece.h" -#include "dex/primitive.h" -#include "globals.h" namespace art { @@ -260,4 +260,4 @@ static inline size_t HashBytes(const uint8_t* data, size_t len) { } // namespace art -#endif // ART_RUNTIME_UTILS_H_ +#endif // ART_LIBARTBASE_BASE_UTILS_H_ diff --git a/libartbase/base/utils_test.cc b/libartbase/base/utils_test.cc new file mode 100644 index 0000000000..892d1fd5bf --- /dev/null +++ b/libartbase/base/utils_test.cc @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2011 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 "utils.h" + +#include "gtest/gtest.h" + +namespace art { + +class UtilsTest : public testing::Test {}; + +TEST_F(UtilsTest, PrettySize) { + EXPECT_EQ("1GB", PrettySize(1 * GB)); + EXPECT_EQ("2GB", PrettySize(2 * GB)); + if (sizeof(size_t) > sizeof(uint32_t)) { + EXPECT_EQ("100GB", PrettySize(100 * GB)); + } + EXPECT_EQ("1024KB", PrettySize(1 * MB)); + EXPECT_EQ("10MB", PrettySize(10 * MB)); + EXPECT_EQ("100MB", PrettySize(100 * MB)); + EXPECT_EQ("1024B", PrettySize(1 * KB)); + EXPECT_EQ("10KB", PrettySize(10 * KB)); + EXPECT_EQ("100KB", PrettySize(100 * KB)); + EXPECT_EQ("0B", PrettySize(0)); + EXPECT_EQ("1B", PrettySize(1)); + EXPECT_EQ("10B", PrettySize(10)); + EXPECT_EQ("100B", PrettySize(100)); + EXPECT_EQ("512B", PrettySize(512)); +} + +TEST_F(UtilsTest, Split) { + std::vector<std::string> actual; + std::vector<std::string> expected; + + expected.clear(); + + actual.clear(); + Split("", ':', &actual); + EXPECT_EQ(expected, actual); + + actual.clear(); + Split(":", ':', &actual); + EXPECT_EQ(expected, actual); + + expected.clear(); + expected.push_back("foo"); + + actual.clear(); + Split(":foo", ':', &actual); + EXPECT_EQ(expected, actual); + + actual.clear(); + Split("foo:", ':', &actual); + EXPECT_EQ(expected, actual); + + actual.clear(); + Split(":foo:", ':', &actual); + EXPECT_EQ(expected, actual); + + expected.push_back("bar"); + + actual.clear(); + Split("foo:bar", ':', &actual); + EXPECT_EQ(expected, actual); + + actual.clear(); + Split(":foo:bar", ':', &actual); + EXPECT_EQ(expected, actual); + + actual.clear(); + Split("foo:bar:", ':', &actual); + EXPECT_EQ(expected, actual); + + actual.clear(); + Split(":foo:bar:", ':', &actual); + EXPECT_EQ(expected, actual); + + expected.push_back("baz"); + + actual.clear(); + Split("foo:bar:baz", ':', &actual); + EXPECT_EQ(expected, actual); + + actual.clear(); + Split(":foo:bar:baz", ':', &actual); + EXPECT_EQ(expected, actual); + + actual.clear(); + Split("foo:bar:baz:", ':', &actual); + EXPECT_EQ(expected, actual); + + actual.clear(); + Split(":foo:bar:baz:", ':', &actual); + EXPECT_EQ(expected, actual); +} + +TEST_F(UtilsTest, ArrayCount) { + int i[64]; + EXPECT_EQ(ArrayCount(i), 64u); + char c[7]; + EXPECT_EQ(ArrayCount(c), 7u); +} + +TEST_F(UtilsTest, BoundsCheckedCast) { + char buffer[64]; + const char* buffer_end = buffer + ArrayCount(buffer); + EXPECT_EQ(BoundsCheckedCast<const uint64_t*>(nullptr, buffer, buffer_end), nullptr); + EXPECT_EQ(BoundsCheckedCast<const uint64_t*>(buffer, buffer, buffer_end), + reinterpret_cast<const uint64_t*>(buffer)); + EXPECT_EQ(BoundsCheckedCast<const uint64_t*>(buffer + 56, buffer, buffer_end), + reinterpret_cast<const uint64_t*>(buffer + 56)); + EXPECT_EQ(BoundsCheckedCast<const uint64_t*>(buffer - 1, buffer, buffer_end), nullptr); + EXPECT_EQ(BoundsCheckedCast<const uint64_t*>(buffer + 57, buffer, buffer_end), nullptr); +} + +} // namespace art diff --git a/runtime/base/variant_map.h b/libartbase/base/variant_map.h index c480b5162d..4e02c54499 100644 --- a/runtime/base/variant_map.h +++ b/libartbase/base/variant_map.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_BASE_VARIANT_MAP_H_ -#define ART_RUNTIME_BASE_VARIANT_MAP_H_ +#ifndef ART_LIBARTBASE_BASE_VARIANT_MAP_H_ +#define ART_LIBARTBASE_BASE_VARIANT_MAP_H_ #include <memory.h> #include <map> @@ -467,4 +467,4 @@ struct VariantMap { } // namespace art -#endif // ART_RUNTIME_BASE_VARIANT_MAP_H_ +#endif // ART_LIBARTBASE_BASE_VARIANT_MAP_H_ diff --git a/runtime/base/variant_map_test.cc b/libartbase/base/variant_map_test.cc index 4677b6d3b3..4677b6d3b3 100644 --- a/runtime/base/variant_map_test.cc +++ b/libartbase/base/variant_map_test.cc diff --git a/libdexfile/Android.bp b/libdexfile/Android.bp index 797b4590c4..ae4ded58e2 100644 --- a/libdexfile/Android.bp +++ b/libdexfile/Android.bp @@ -24,6 +24,7 @@ cc_defaults { "dex/descriptors_names.cc", "dex/dex_file.cc", "dex/dex_file_exception_helpers.cc", + "dex/dex_file_layout.cc", "dex/dex_file_loader.cc", "dex/dex_file_tracking_registrar.cc", "dex/dex_file_verifier.cc", @@ -54,6 +55,9 @@ cc_defaults { }, generated_sources: ["dexfile_operator_srcs"], shared_libs: [ + // Important note: relying on libartbase's header_lib is perfectly acceptable. + // However, relying on the libartbase shared library introduces further, possibly cyclic, + // dependencies for clients outside of ART. "liblog", // For common macros. "libbase", @@ -77,6 +81,7 @@ gensrcs { tools: ["generate_operator_out"], srcs: [ "dex/dex_file.h", + "dex/dex_file_layout.h", "dex/dex_instruction.h", "dex/dex_instruction_utils.h", "dex/invoke_type.h", diff --git a/runtime/dex/dex_file_layout.cc b/libdexfile/dex/dex_file_layout.cc index d85d61d56b..1e36e05f50 100644 --- a/runtime/dex/dex_file_layout.cc +++ b/libdexfile/dex/dex_file_layout.cc @@ -18,11 +18,27 @@ #include <sys/mman.h> -#include "base/file_utils.h" -#include "dex/dex_file.h" +#include "dex_file.h" namespace art { +int DexLayoutSection::MadviseLargestPageAlignedRegion(const uint8_t* begin, + const uint8_t* end, + int advice) { + DCHECK_LE(begin, end); + begin = AlignUp(begin, kPageSize); + end = AlignDown(end, kPageSize); + if (begin < end) { + // TODO: remove the direct dependency on madvise here. + int result = madvise(const_cast<uint8_t*>(begin), end - begin, advice); + if (result != 0) { + PLOG(WARNING) << "madvise failed " << result; + } + return result; + } + return 0; +} + void DexLayoutSection::Subsection::Madvise(const DexFile* dex_file, int advice) const { DCHECK(dex_file != nullptr); DCHECK_LT(start_offset_, dex_file->Size()); diff --git a/runtime/dex/dex_file_layout.h b/libdexfile/dex/dex_file_layout.h index 793e3b5de7..183aefa5a4 100644 --- a/runtime/dex/dex_file_layout.h +++ b/libdexfile/dex/dex_file_layout.h @@ -14,8 +14,8 @@ * limitations under the License. */ -#ifndef ART_RUNTIME_DEX_DEX_FILE_LAYOUT_H_ -#define ART_RUNTIME_DEX_DEX_FILE_LAYOUT_H_ +#ifndef ART_LIBDEXFILE_DEX_DEX_FILE_LAYOUT_H_ +#define ART_LIBDEXFILE_DEX_DEX_FILE_LAYOUT_H_ #include <algorithm> #include <cstdint> @@ -96,6 +96,9 @@ class DexLayoutSection { void Madvise(const DexFile* dex_file, int advice) const; }; + // Madvise the largest page-aligned region contained in [begin, end). + static int MadviseLargestPageAlignedRegion(const uint8_t* begin, const uint8_t* end, int advice); + Subsection parts_[static_cast<size_t>(LayoutType::kLayoutTypeCount)]; }; @@ -121,4 +124,4 @@ std::ostream& operator<<(std::ostream& os, const DexLayoutSections& sections); } // namespace art -#endif // ART_RUNTIME_DEX_DEX_FILE_LAYOUT_H_ +#endif // ART_LIBDEXFILE_DEX_DEX_FILE_LAYOUT_H_ diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 85c7281102..8069408b5a 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -34,6 +34,7 @@ #include "art_field-inl.h" #include "art_method-inl.h" #include "base/bit_utils_iterator.h" +#include "base/os.h" #include "base/safe_map.h" #include "base/stl_util.h" #include "base/unix_file/fd_file.h" @@ -69,7 +70,6 @@ #include "oat.h" #include "oat_file-inl.h" #include "oat_file_manager.h" -#include "os.h" #include "scoped_thread_state_change-inl.h" #include "stack.h" #include "stack_map.h" diff --git a/oatdump/oatdump_test.h b/oatdump/oatdump_test.h index d4bed6b3da..fac0bb234e 100644 --- a/oatdump/oatdump_test.h +++ b/oatdump/oatdump_test.h @@ -25,13 +25,13 @@ #include "arch/instruction_set.h" #include "base/file_utils.h" +#include "base/os.h" #include "base/unix_file/fd_file.h" +#include "base/utils.h" #include "common_runtime_test.h" #include "exec_utils.h" #include "gc/heap.h" #include "gc/space/image_space.h" -#include "os.h" -#include "utils.h" #include <sys/types.h> #include <unistd.h> diff --git a/openjdkjvmti/events.cc b/openjdkjvmti/events.cc index 8b40a7e072..07b1529adb 100644 --- a/openjdkjvmti/events.cc +++ b/openjdkjvmti/events.cc @@ -1004,6 +1004,27 @@ bool EventHandler::OtherMonitorEventsEnabledAnywhere(ArtJvmtiEvent event) { return false; } +void EventHandler::SetupFramePopTraceListener(bool enable) { + if (enable) { + frame_pop_enabled = true; + SetupTraceListener(method_trace_listener_.get(), ArtJvmtiEvent::kFramePop, enable); + } else { + // remove the listener if we have no outstanding frames. + { + art::ReaderMutexLock mu(art::Thread::Current(), envs_lock_); + for (ArtJvmTiEnv* env : envs) { + art::ReaderMutexLock event_mu(art::Thread::Current(), env->event_info_mutex_); + if (!env->notify_frames.empty()) { + // Leaving FramePop listener since there are unsent FramePop events. + return; + } + } + frame_pop_enabled = false; + } + SetupTraceListener(method_trace_listener_.get(), ArtJvmtiEvent::kFramePop, enable); + } +} + // Handle special work for the given event type, if necessary. void EventHandler::HandleEventType(ArtJvmtiEvent event, bool enable) { switch (event) { @@ -1018,14 +1039,14 @@ void EventHandler::HandleEventType(ArtJvmtiEvent event, bool enable) { case ArtJvmtiEvent::kGarbageCollectionFinish: SetupGcPauseTracking(gc_pause_listener_.get(), event, enable); return; - // FramePop can never be disabled once it's been turned on since we would either need to deal - // with dangling pointers or have missed events. - // TODO We really need to make this not the case anymore. + // FramePop can never be disabled once it's been turned on if it was turned off with outstanding + // pop-events since we would either need to deal with dangling pointers or have missed events. case ArtJvmtiEvent::kFramePop: - if (!enable || (enable && frame_pop_enabled)) { + if (enable && frame_pop_enabled) { + // The frame-pop event was held on by pending events so we don't need to do anything. break; } else { - SetupTraceListener(method_trace_listener_.get(), event, enable); + SetupFramePopTraceListener(enable); break; } case ArtJvmtiEvent::kMethodEntry: diff --git a/openjdkjvmti/events.h b/openjdkjvmti/events.h index 8141eff88c..bf12cb191e 100644 --- a/openjdkjvmti/events.h +++ b/openjdkjvmti/events.h @@ -247,6 +247,9 @@ class EventHandler { private: void SetupTraceListener(JvmtiMethodTraceListener* listener, ArtJvmtiEvent event, bool enable); + // Specifically handle the FramePop event which it might not always be possible to turn off. + void SetupFramePopTraceListener(bool enable); + template <ArtJvmtiEvent kEvent, typename ...Args> ALWAYS_INLINE inline std::vector<impl::EventHandlerFunc<kEvent>> CollectEvents(art::Thread* thread, diff --git a/openjdkjvmti/ti_class.cc b/openjdkjvmti/ti_class.cc index e289eb090e..261fe3e810 100644 --- a/openjdkjvmti/ti_class.cc +++ b/openjdkjvmti/ti_class.cc @@ -39,6 +39,7 @@ #include "art_jvmti.h" #include "base/array_ref.h" #include "base/macros.h" +#include "base/utils.h" #include "class_linker.h" #include "class_loader_utils.h" #include "class_table-inl.h" @@ -73,7 +74,6 @@ #include "ti_class_loader-inl.h" #include "ti_phase.h" #include "ti_redefine.h" -#include "utils.h" #include "well_known_classes.h" namespace openjdkjvmti { diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc index 46734548a8..5d430d2073 100644 --- a/openjdkjvmti/ti_redefine.cc +++ b/openjdkjvmti/ti_redefine.cc @@ -1402,13 +1402,6 @@ void Redefiner::ClassRedefinition::UpdateMethods(art::ObjPtr<art::mirror::Class> method.SetCodeItemOffset(dex_file_->FindCodeItemOffset(class_def, dex_method_idx)); // Clear all the intrinsics related flags. method.SetNotIntrinsic(); - // Notify the jit that this method is redefined. - art::jit::Jit* jit = driver_->runtime_->GetJit(); - // Non-invokable methods don't have any JIT data associated with them so we don't need to tell - // the jit about them. - if (jit != nullptr && method.IsInvokable()) { - jit->GetCodeCache()->NotifyMethodRedefined(&method); - } } } @@ -1450,6 +1443,23 @@ void Redefiner::ClassRedefinition::UpdateClass( art::ObjPtr<art::mirror::ClassExt> ext(mclass->GetExtData()); CHECK(!ext.IsNull()); ext->SetOriginalDexFile(original_dex_file); + + // Notify the jit that all the methods in this class were redefined. Need to do this last since + // the jit relies on the dex_file_ being correct (for native methods at least) to find the method + // meta-data. + art::jit::Jit* jit = driver_->runtime_->GetJit(); + if (jit != nullptr) { + art::PointerSize image_pointer_size = + driver_->runtime_->GetClassLinker()->GetImagePointerSize(); + auto code_cache = jit->GetCodeCache(); + // Non-invokable methods don't have any JIT data associated with them so we don't need to tell + // the jit about them. + for (art::ArtMethod& method : mclass->GetDeclaredMethods(image_pointer_size)) { + if (method.IsInvokable()) { + code_cache->NotifyMethodRedefined(&method); + } + } + } } // Restores the old obsolete methods maps if it turns out they weren't needed (ie there were no new diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc index 0115772456..3df640902a 100644 --- a/patchoat/patchoat.cc +++ b/patchoat/patchoat.cc @@ -35,11 +35,14 @@ #include "base/file_utils.h" #include "base/leb128.h" #include "base/logging.h" // For InitLogging. +#include "base/mutex.h" #include "base/memory_tool.h" +#include "base/os.h" #include "base/scoped_flock.h" #include "base/stringpiece.h" #include "base/unix_file/fd_file.h" #include "base/unix_file/random_access_file_utils.h" +#include "base/utils.h" #include "elf_file.h" #include "elf_file_impl.h" #include "elf_utils.h" @@ -54,11 +57,9 @@ #include "mirror/reference.h" #include "noop_compiler_callbacks.h" #include "offsets.h" -#include "os.h" #include "runtime.h" #include "scoped_thread_state_change-inl.h" #include "thread.h" -#include "utils.h" namespace art { @@ -1177,6 +1178,7 @@ static int patchoat_verify_image(TimingLogger& timings, } static int patchoat(int argc, char **argv) { + Locks::Init(); InitLogging(argv, Runtime::Abort); MemMap::Init(); const bool debug = kIsDebugBuild; diff --git a/patchoat/patchoat.h b/patchoat/patchoat.h index feba523f56..2b1210b5b1 100644 --- a/patchoat/patchoat.h +++ b/patchoat/patchoat.h @@ -21,12 +21,12 @@ #include "base/enums.h" #include "base/macros.h" #include "base/mutex.h" +#include "base/os.h" #include "elf_file.h" #include "elf_utils.h" #include "gc/accounting/space_bitmap.h" #include "gc/heap.h" #include "gc/space/image_space.h" -#include "os.h" #include "runtime.h" namespace art { diff --git a/profman/profile_assistant.cc b/profman/profile_assistant.cc index a00b1fa5bd..b509fb4027 100644 --- a/profman/profile_assistant.cc +++ b/profman/profile_assistant.cc @@ -16,8 +16,8 @@ #include "profile_assistant.h" +#include "base/os.h" #include "base/unix_file/fd_file.h" -#include "os.h" namespace art { diff --git a/profman/profile_assistant_test.cc b/profman/profile_assistant_test.cc index 6359814615..9494f04a5a 100644 --- a/profman/profile_assistant_test.cc +++ b/profman/profile_assistant_test.cc @@ -19,6 +19,7 @@ #include "android-base/strings.h" #include "art_method-inl.h" #include "base/unix_file/fd_file.h" +#include "base/utils.h" #include "common_runtime_test.h" #include "dex/descriptors_names.h" #include "exec_utils.h" @@ -28,7 +29,6 @@ #include "obj_ptr-inl.h" #include "profile_assistant.h" #include "scoped_thread_state_change-inl.h" -#include "utils.h" namespace art { diff --git a/profman/profman.cc b/profman/profman.cc index 5551c34b60..d1cc56389a 100644 --- a/profman/profman.cc +++ b/profman/profman.cc @@ -34,10 +34,12 @@ #include "base/dumpable.h" #include "base/logging.h" // For InitLogging. +#include "base/mutex.h" #include "base/scoped_flock.h" #include "base/stringpiece.h" #include "base/time_utils.h" #include "base/unix_file/fd_file.h" +#include "base/utils.h" #include "boot_image_profile.h" #include "bytecode_utils.h" #include "dex/art_dex_file_loader.h" @@ -49,7 +51,6 @@ #include "profile_assistant.h" #include "runtime.h" #include "type_reference.h" -#include "utils.h" #include "zip_archive.h" namespace art { @@ -204,6 +205,7 @@ class ProfMan FINAL { original_argc = argc; original_argv = argv; + Locks::Init(); InitLogging(argv, Runtime::Abort); // Skip over the command name. diff --git a/runtime/Android.bp b/runtime/Android.bp index c017c5fed8..daab2326c0 100644 --- a/runtime/Android.bp +++ b/runtime/Android.bp @@ -31,25 +31,14 @@ cc_defaults { "aot_class_linker.cc", "art_field.cc", "art_method.cc", - "atomic.cc", "barrier.cc", - "base/allocator.cc", "base/arena_allocator.cc", "base/arena_bit_vector.cc", - "base/bit_vector.cc", - "base/file_magic.cc", "base/file_utils.cc", - "base/hex_dump.cc", - "base/logging.cc", "base/mutex.cc", - "base/runtime_debug.cc", - "base/safe_copy.cc", + "base/quasi_atomic.cc", "base/scoped_arena_allocator.cc", - "base/scoped_flock.cc", - "base/time_utils.cc", "base/timing_logger.cc", - "base/unix_file/fd_file.cc", - "base/unix_file/random_access_file_utils.cc", "cha.cc", "check_jni.cc", "class_linker.cc", @@ -60,7 +49,6 @@ cc_defaults { "debugger.cc", "dex/art_dex_file_loader.cc", "dex/dex_file_annotations.cc", - "dex/dex_file_layout.cc", "dex_to_dex_decompiler.cc", "elf_file.cc", "exec_utils.cc", @@ -192,7 +180,6 @@ cc_defaults { "oat_quick_method_header.cc", "object_lock.cc", "offsets.cc", - "os_linux.cc", "parsed_options.cc", "plugin.cc", "quick_exception_handler.cc", @@ -215,7 +202,6 @@ cc_defaults { "trace.cc", "transaction.cc", "type_lookup_table.cc", - "utils.cc", "vdex_file.cc", "verifier/instruction_flags.cc", "verifier/method_verifier.cc", @@ -406,7 +392,6 @@ cc_defaults { ], header_libs: [ "art_cmdlineparser_headers", - "art_libartbase_headers", "libnativehelper_header_only", "jni_platform_headers", ], @@ -440,13 +425,9 @@ gensrcs { tools: ["generate_operator_out"], srcs: [ "arch/instruction_set.h", - "base/allocator.h", - "base/callee_save_type.h", "base/mutex.h", - "base/unix_file/fd_file.h", "class_status.h", "debugger.h", - "dex/dex_file_layout.h", "gc_root.h", "gc/allocator_type.h", "gc/allocator/rosalloc.h", @@ -487,8 +468,15 @@ art_cc_library { strip: { keep_symbols: true, }, - shared_libs: ["libdexfile"], - export_shared_lib_headers: ["libdexfile"], + whole_static_libs: [ + "libartbase", + ], + shared_libs: [ + "libdexfile", + ], + export_shared_lib_headers: [ + "libdexfile", + ], } art_cc_library { @@ -497,8 +485,15 @@ art_cc_library { "art_debug_defaults", "libart_defaults", ], - shared_libs: ["libdexfiled"], - export_shared_lib_headers: ["libdexfiled"], + whole_static_libs: [ + "libartbased", + ], + shared_libs: [ + "libdexfiled", + ], + export_shared_lib_headers: [ + "libdexfiled", + ], } art_cc_library { @@ -540,23 +535,9 @@ art_cc_test { "arch/x86_64/instruction_set_features_x86_64_test.cc", "barrier_test.cc", "base/arena_allocator_test.cc", - "base/bit_field_test.cc", - "base/bit_string_test.cc", - "base/bit_struct_test.cc", - "base/bit_vector_test.cc", "base/file_utils_test.cc", - "base/hex_dump_test.cc", - "base/histogram_test.cc", - "base/logging_test.cc", "base/mutex_test.cc", - "base/safe_copy_test.cc", - "base/scoped_flock_test.cc", - "base/time_utils_test.cc", "base/timing_logger_test.cc", - "base/transform_array_ref_test.cc", - "base/transform_iterator_test.cc", - "base/variant_map_test.cc", - "base/unix_file/fd_file_test.cc", "cha_test.cc", "class_linker_test.cc", "class_loader_context_test.cc", @@ -615,7 +596,6 @@ art_cc_test { "thread_pool_test.cc", "transaction_test.cc", "type_lookup_table_test.cc", - "utils_test.cc", "vdex_file_test.cc", "verifier/method_verifier_test.cc", "verifier/reg_type_test.cc", diff --git a/runtime/arch/arm/quick_entrypoints_cc_arm.cc b/runtime/arch/arm/quick_entrypoints_cc_arm.cc index 232ec3140e..987b4590b7 100644 --- a/runtime/arch/arm/quick_entrypoints_cc_arm.cc +++ b/runtime/arch/arm/quick_entrypoints_cc_arm.cc @@ -15,7 +15,7 @@ */ #include "art_method.h" -#include "utils.h" // For RoundUp(). +#include "base/utils.h" // For RoundUp(). namespace art { diff --git a/runtime/arch/instruction_set_features.cc b/runtime/arch/instruction_set_features.cc index b6b24c24fb..0c45bc9197 100644 --- a/runtime/arch/instruction_set_features.cc +++ b/runtime/arch/instruction_set_features.cc @@ -19,7 +19,7 @@ #include "android-base/strings.h" #include "base/casts.h" -#include "utils.h" +#include "base/utils.h" #include "arm/instruction_set_features_arm.h" #include "arm64/instruction_set_features_arm64.h" diff --git a/runtime/arch/mips/entrypoints_init_mips.cc b/runtime/arch/mips/entrypoints_init_mips.cc index badee59568..9418caf98c 100644 --- a/runtime/arch/mips/entrypoints_init_mips.cc +++ b/runtime/arch/mips/entrypoints_init_mips.cc @@ -17,8 +17,9 @@ #include <string.h> #include "arch/mips/asm_support_mips.h" -#include "atomic.h" +#include "base/atomic.h" #include "base/logging.h" +#include "base/quasi_atomic.h" #include "entrypoints/entrypoint_utils.h" #include "entrypoints/jni/jni_entrypoints.h" #include "entrypoints/math_entrypoints.h" diff --git a/runtime/arch/mips64/entrypoints_init_mips64.cc b/runtime/arch/mips64/entrypoints_init_mips64.cc index bdfb9421df..2acfe147f8 100644 --- a/runtime/arch/mips64/entrypoints_init_mips64.cc +++ b/runtime/arch/mips64/entrypoints_init_mips64.cc @@ -18,7 +18,8 @@ #include <string.h> #include "arch/mips64/asm_support_mips64.h" -#include "atomic.h" +#include "base/atomic.h" +#include "base/quasi_atomic.h" #include "entrypoints/entrypoint_utils.h" #include "entrypoints/jni/jni_entrypoints.h" #include "entrypoints/math_entrypoints.h" diff --git a/runtime/art_field.cc b/runtime/art_field.cc index 3f70958cff..b867621f02 100644 --- a/runtime/art_field.cc +++ b/runtime/art_field.cc @@ -17,6 +17,7 @@ #include "art_field.h" #include "art_field-inl.h" +#include "base/utils.h" #include "class_linker-inl.h" #include "dex/descriptors_names.h" #include "gc/accounting/card_table-inl.h" @@ -26,7 +27,6 @@ #include "mirror/object_array-inl.h" #include "runtime.h" #include "scoped_thread_state_change-inl.h" -#include "utils.h" #include "well_known_classes.h" namespace art { diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h index 92769942c0..8bf91d9da1 100644 --- a/runtime/art_method-inl.h +++ b/runtime/art_method-inl.h @@ -21,6 +21,7 @@ #include "art_field.h" #include "base/callee_save_type.h" +#include "base/utils.h" #include "class_linker-inl.h" #include "common_throws.h" #include "dex/code_item_accessors-inl.h" @@ -44,7 +45,6 @@ #include "runtime-inl.h" #include "scoped_thread_state_change-inl.h" #include "thread-current-inl.h" -#include "utils.h" namespace art { diff --git a/runtime/barrier_test.cc b/runtime/barrier_test.cc index ecdabba8a5..04bb6bab1e 100644 --- a/runtime/barrier_test.cc +++ b/runtime/barrier_test.cc @@ -18,7 +18,7 @@ #include <string> -#include "atomic.h" +#include "base/atomic.h" #include "common_runtime_test.h" #include "mirror/object_array-inl.h" #include "thread-current-inl.h" diff --git a/runtime/base/arena_allocator.cc b/runtime/base/arena_allocator.cc index e87f631c2e..292bde0272 100644 --- a/runtime/base/arena_allocator.cc +++ b/runtime/base/arena_allocator.cc @@ -25,9 +25,9 @@ #include <android-base/logging.h> +#include "base/systrace.h" #include "mem_map.h" #include "mutex.h" -#include "systrace.h" #include "thread-current-inl.h" namespace art { diff --git a/runtime/base/arena_allocator.h b/runtime/base/arena_allocator.h index 060b6fac2e..c3011091e8 100644 --- a/runtime/base/arena_allocator.h +++ b/runtime/base/arena_allocator.h @@ -21,10 +21,10 @@ #include <stdint.h> #include "base/bit_utils.h" +#include "base/debug_stack.h" +#include "base/dchecked_vector.h" #include "base/macros.h" #include "base/memory_tool.h" -#include "dchecked_vector.h" -#include "debug_stack.h" #include "mutex.h" namespace art { diff --git a/runtime/base/file_utils.cc b/runtime/base/file_utils.cc index dd3f8d5b3c..f9d0d12d88 100644 --- a/runtime/base/file_utils.cc +++ b/runtime/base/file_utils.cc @@ -17,10 +17,7 @@ #include "file_utils.h" #include <inttypes.h> -#include <pthread.h> -#include <sys/mman.h> // For madvise #include <sys/stat.h> -#include <sys/syscall.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> @@ -47,10 +44,10 @@ #include "base/bit_utils.h" #include "base/stl_util.h" +#include "base/os.h" #include "base/unix_file/fd_file.h" #include "dex/dex_file_loader.h" #include "globals.h" -#include "os.h" #if defined(__APPLE__) #include <crt_externs.h> @@ -308,19 +305,6 @@ std::string GetSystemImageFilename(const char* location, const InstructionSet is return filename; } -bool FileExists(const std::string& filename) { - struct stat buffer; - return stat(filename.c_str(), &buffer) == 0; -} - -bool FileExistsAndNotEmpty(const std::string& filename) { - struct stat buffer; - if (stat(filename.c_str(), &buffer) != 0) { - return false; - } - return buffer.st_size > 0; -} - std::string ReplaceFileExtension(const std::string& filename, const std::string& new_extension) { const size_t last_ext = filename.find_last_of('.'); if (last_ext == std::string::npos) { @@ -330,26 +314,6 @@ std::string ReplaceFileExtension(const std::string& filename, const std::string& } } -int64_t GetFileSizeBytes(const std::string& filename) { - struct stat stat_buf; - int rc = stat(filename.c_str(), &stat_buf); - return rc == 0 ? stat_buf.st_size : -1; -} - -int MadviseLargestPageAlignedRegion(const uint8_t* begin, const uint8_t* end, int advice) { - DCHECK_LE(begin, end); - begin = AlignUp(begin, kPageSize); - end = AlignDown(end, kPageSize); - if (begin < end) { - int result = madvise(const_cast<uint8_t*>(begin), end - begin, advice); - if (result != 0) { - PLOG(WARNING) << "madvise failed " << result; - } - return result; - } - return 0; -} - bool LocationIsOnSystem(const char* location) { UniqueCPtr<const char[]> path(realpath(location, nullptr)); return path != nullptr && android::base::StartsWith(path.get(), GetAndroidRoot().c_str()); diff --git a/runtime/base/file_utils.h b/runtime/base/file_utils.h index cac0950d9c..7f691d546b 100644 --- a/runtime/base/file_utils.h +++ b/runtime/base/file_utils.h @@ -65,10 +65,6 @@ std::string GetSystemImageFilename(const char* location, InstructionSet isa); // Returns the vdex filename for the given oat filename. std::string GetVdexFilename(const std::string& oat_filename); -// Returns true if the file exists. -bool FileExists(const std::string& filename); -bool FileExistsAndNotEmpty(const std::string& filename); - // Returns `filename` with the text after the last occurrence of '.' replaced with // `extension`. If `filename` does not contain a period, returns a string containing `filename`, // a period, and `new_extension`. @@ -76,12 +72,6 @@ bool FileExistsAndNotEmpty(const std::string& filename); // ReplaceFileExtension("foo", "abc") == "foo.abc" std::string ReplaceFileExtension(const std::string& filename, const std::string& new_extension); -// Return the file size in bytes or -1 if the file does not exists. -int64_t GetFileSizeBytes(const std::string& filename); - -// Madvise the largest page aligned region within begin and end. -int MadviseLargestPageAlignedRegion(const uint8_t* begin, const uint8_t* end, int advice); - // Return whether the location is on system (i.e. android root). bool LocationIsOnSystem(const char* location); diff --git a/runtime/base/mutex-inl.h b/runtime/base/mutex-inl.h index 01adbf17e2..d6dbab4606 100644 --- a/runtime/base/mutex-inl.h +++ b/runtime/base/mutex-inl.h @@ -21,9 +21,9 @@ #include "mutex.h" +#include "base/utils.h" #include "base/value_object.h" #include "thread.h" -#include "utils.h" #if ART_USE_FUTEXES #include "linux/futex.h" diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc index 3d2226c1dc..a1f30b6794 100644 --- a/runtime/base/mutex.cc +++ b/runtime/base/mutex.cc @@ -21,7 +21,7 @@ #include "android-base/stringprintf.h" -#include "atomic.h" +#include "base/atomic.h" #include "base/logging.h" #include "base/systrace.h" #include "base/time_utils.h" diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h index 4f7001a101..437661798f 100644 --- a/runtime/base/mutex.h +++ b/runtime/base/mutex.h @@ -26,10 +26,10 @@ #include <android-base/logging.h> -#include "atomic.h" #include "base/aborting.h" +#include "base/atomic.h" +#include "base/globals.h" #include "base/macros.h" -#include "globals.h" #if defined(__APPLE__) #define ART_USE_FUTEXES 0 @@ -50,6 +50,7 @@ class SHARED_LOCKABLE ReaderWriterMutex; class SHARED_LOCKABLE MutatorMutex; class ScopedContentionRecorder; class Thread; +class Mutex; // LockLevel is used to impose a lock hierarchy [1] where acquisition of a Mutex at a higher or // equal level to a lock a thread holds is invalid. The lock hierarchy achieves a cycle free diff --git a/runtime/atomic.cc b/runtime/base/quasi_atomic.cc index 07aceb7cfc..1a82812981 100644 --- a/runtime/atomic.cc +++ b/runtime/base/quasi_atomic.cc @@ -14,7 +14,8 @@ * limitations under the License. */ -#include "atomic.h" +#include "base/quasi_atomic.h" + #include "base/mutex.h" #include "base/stl_util.h" #include "thread-current-inl.h" diff --git a/runtime/base/quasi_atomic.h b/runtime/base/quasi_atomic.h new file mode 100644 index 0000000000..067d01db01 --- /dev/null +++ b/runtime/base/quasi_atomic.h @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2008 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_RUNTIME_BASE_QUASI_ATOMIC_H_ +#define ART_RUNTIME_BASE_QUASI_ATOMIC_H_ + +#include <stdint.h> +#include <atomic> +#include <limits> +#include <vector> + +#include <android-base/logging.h> + +#include "arch/instruction_set.h" +#include "base/macros.h" + +namespace art { + +class Mutex; + +// QuasiAtomic encapsulates two separate facilities that we are +// trying to move away from: "quasiatomic" 64 bit operations +// and custom memory fences. For the time being, they remain +// exposed. Clients should be converted to use either class Atomic +// below whenever possible, and should eventually use C++11 atomics. +// The two facilities that do not have a good C++11 analog are +// ThreadFenceForConstructor and Atomic::*JavaData. +// +// NOTE: Two "quasiatomic" operations on the exact same memory address +// are guaranteed to operate atomically with respect to each other, +// but no guarantees are made about quasiatomic operations mixed with +// non-quasiatomic operations on the same address, nor about +// quasiatomic operations that are performed on partially-overlapping +// memory. +class QuasiAtomic { + static constexpr bool NeedSwapMutexes(InstructionSet isa) { + // TODO - mips64 still need this for Cas64 ??? + return (isa == InstructionSet::kMips) || (isa == InstructionSet::kMips64); + } + + public: + static void Startup(); + + static void Shutdown(); + + // Reads the 64-bit value at "addr" without tearing. + static int64_t Read64(volatile const int64_t* addr) { + if (!NeedSwapMutexes(kRuntimeISA)) { + int64_t value; +#if defined(__LP64__) + value = *addr; +#else +#if defined(__arm__) +#if defined(__ARM_FEATURE_LPAE) + // With LPAE support (such as Cortex-A15) then ldrd is defined not to tear. + __asm__ __volatile__("@ QuasiAtomic::Read64\n" + "ldrd %0, %H0, %1" + : "=r" (value) + : "m" (*addr)); +#else + // Exclusive loads are defined not to tear, clearing the exclusive state isn't necessary. + __asm__ __volatile__("@ QuasiAtomic::Read64\n" + "ldrexd %0, %H0, %1" + : "=r" (value) + : "Q" (*addr)); +#endif +#elif defined(__i386__) + __asm__ __volatile__( + "movq %1, %0\n" + : "=x" (value) + : "m" (*addr)); +#else + LOG(FATAL) << "Unsupported architecture"; +#endif +#endif // defined(__LP64__) + return value; + } else { + return SwapMutexRead64(addr); + } + } + + // Writes to the 64-bit value at "addr" without tearing. + static void Write64(volatile int64_t* addr, int64_t value) { + if (!NeedSwapMutexes(kRuntimeISA)) { +#if defined(__LP64__) + *addr = value; +#else +#if defined(__arm__) +#if defined(__ARM_FEATURE_LPAE) + // If we know that ARM architecture has LPAE (such as Cortex-A15) strd is defined not to tear. + __asm__ __volatile__("@ QuasiAtomic::Write64\n" + "strd %1, %H1, %0" + : "=m"(*addr) + : "r" (value)); +#else + // The write is done as a swap so that the cache-line is in the exclusive state for the store. + int64_t prev; + int status; + do { + __asm__ __volatile__("@ QuasiAtomic::Write64\n" + "ldrexd %0, %H0, %2\n" + "strexd %1, %3, %H3, %2" + : "=&r" (prev), "=&r" (status), "+Q"(*addr) + : "r" (value) + : "cc"); + } while (UNLIKELY(status != 0)); +#endif +#elif defined(__i386__) + __asm__ __volatile__( + "movq %1, %0" + : "=m" (*addr) + : "x" (value)); +#else + LOG(FATAL) << "Unsupported architecture"; +#endif +#endif // defined(__LP64__) + } else { + SwapMutexWrite64(addr, value); + } + } + + // Atomically compare the value at "addr" to "old_value", if equal replace it with "new_value" + // and return true. Otherwise, don't swap, and return false. + // This is fully ordered, i.e. it has C++11 memory_order_seq_cst + // semantics (assuming all other accesses use a mutex if this one does). + // This has "strong" semantics; if it fails then it is guaranteed that + // at some point during the execution of Cas64, *addr was not equal to + // old_value. + static bool Cas64(int64_t old_value, int64_t new_value, volatile int64_t* addr) { + if (!NeedSwapMutexes(kRuntimeISA)) { + return __sync_bool_compare_and_swap(addr, old_value, new_value); + } else { + return SwapMutexCas64(old_value, new_value, addr); + } + } + + // Does the architecture provide reasonable atomic long operations or do we fall back on mutexes? + static bool LongAtomicsUseMutexes(InstructionSet isa) { + return NeedSwapMutexes(isa); + } + + static void ThreadFenceAcquire() { + std::atomic_thread_fence(std::memory_order_acquire); + } + + static void ThreadFenceRelease() { + std::atomic_thread_fence(std::memory_order_release); + } + + static void ThreadFenceForConstructor() { + #if defined(__aarch64__) + __asm__ __volatile__("dmb ishst" : : : "memory"); + #else + std::atomic_thread_fence(std::memory_order_release); + #endif + } + + static void ThreadFenceSequentiallyConsistent() { + std::atomic_thread_fence(std::memory_order_seq_cst); + } + + private: + static Mutex* GetSwapMutex(const volatile int64_t* addr); + static int64_t SwapMutexRead64(volatile const int64_t* addr); + static void SwapMutexWrite64(volatile int64_t* addr, int64_t val); + static bool SwapMutexCas64(int64_t old_value, int64_t new_value, volatile int64_t* addr); + + // We stripe across a bunch of different mutexes to reduce contention. + static constexpr size_t kSwapMutexCount = 32; + static std::vector<Mutex*>* gSwapMutexes; + + DISALLOW_COPY_AND_ASSIGN(QuasiAtomic); +}; + +} // namespace art + +#endif // ART_RUNTIME_BASE_QUASI_ATOMIC_H_ diff --git a/runtime/base/scoped_arena_allocator.h b/runtime/base/scoped_arena_allocator.h index 202902e5aa..a253e2f535 100644 --- a/runtime/base/scoped_arena_allocator.h +++ b/runtime/base/scoped_arena_allocator.h @@ -20,9 +20,9 @@ #include <android-base/logging.h> #include "arena_allocator.h" +#include "base/debug_stack.h" +#include "base/globals.h" #include "base/macros.h" -#include "debug_stack.h" -#include "globals.h" namespace art { diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 0c205568fa..1d72875269 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -38,12 +38,15 @@ #include "base/casts.h" #include "base/leb128.h" #include "base/logging.h" +#include "base/os.h" +#include "base/quasi_atomic.h" #include "base/scoped_arena_containers.h" #include "base/scoped_flock.h" #include "base/stl_util.h" #include "base/systrace.h" #include "base/time_utils.h" #include "base/unix_file/fd_file.h" +#include "base/utils.h" #include "base/value_object.h" #include "cha.h" #include "class_linker-inl.h" @@ -111,14 +114,12 @@ #include "oat_file_assistant.h" #include "oat_file_manager.h" #include "object_lock.h" -#include "os.h" #include "runtime.h" #include "runtime_callbacks.h" #include "scoped_thread_state_change-inl.h" #include "thread-inl.h" #include "thread_list.h" #include "trace.h" -#include "utils.h" #include "utils/dex_cache_arrays_layout-inl.h" #include "verifier/method_verifier.h" #include "well_known_classes.h" diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index 80ef6544e8..8cd0604ac3 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -1596,6 +1596,63 @@ TEST_F(ClassLinkerTest, CreateWellKnownClassLoader) { LoadDexInDelegateLastClassLoader("Interfaces", class_loader_c); } +TEST_F(ClassLinkerTest, PrettyClass) { + ScopedObjectAccess soa(Thread::Current()); + EXPECT_EQ("null", mirror::Class::PrettyClass(nullptr)); + mirror::Class* c = class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/String;"); + ASSERT_TRUE(c != nullptr); + mirror::Object* o = mirror::ObjectArray<mirror::String>::Alloc(soa.Self(), c, 0); + EXPECT_EQ("java.lang.Class<java.lang.String[]>", mirror::Class::PrettyClass(o->GetClass())); +} + +TEST_F(ClassLinkerTest, PrettyClassAndClassLoader) { + ScopedObjectAccess soa(Thread::Current()); + EXPECT_EQ("null", mirror::Class::PrettyClassAndClassLoader(nullptr)); + mirror::Class* c = class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/String;"); + ASSERT_TRUE(c != nullptr); + mirror::Object* o = mirror::ObjectArray<mirror::String>::Alloc(soa.Self(), c, 0); + EXPECT_EQ("java.lang.Class<java.lang.String[],null>", + mirror::Class::PrettyClassAndClassLoader(o->GetClass())); +} + +TEST_F(ClassLinkerTest, PrettyField) { + ScopedObjectAccess soa(Thread::Current()); + EXPECT_EQ("null", ArtField::PrettyField(nullptr)); + + mirror::Class* java_lang_String = class_linker_->FindSystemClass(soa.Self(), + "Ljava/lang/String;"); + + ArtField* f; + f = java_lang_String->FindDeclaredInstanceField("count", "I"); + EXPECT_EQ("int java.lang.String.count", f->PrettyField()); + EXPECT_EQ("java.lang.String.count", f->PrettyField(false)); +} + +TEST_F(ClassLinkerTest, JniShortName_JniLongName) { + ScopedObjectAccess soa(Thread::Current()); + mirror::Class* c = class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/String;"); + ASSERT_TRUE(c != nullptr); + ArtMethod* m; + + m = c->FindClassMethod("charAt", "(I)C", kRuntimePointerSize); + ASSERT_TRUE(m != nullptr); + ASSERT_FALSE(m->IsDirect()); + EXPECT_EQ("Java_java_lang_String_charAt", m->JniShortName()); + EXPECT_EQ("Java_java_lang_String_charAt__I", m->JniLongName()); + + m = c->FindClassMethod("indexOf", "(Ljava/lang/String;I)I", kRuntimePointerSize); + ASSERT_TRUE(m != nullptr); + ASSERT_FALSE(m->IsDirect()); + EXPECT_EQ("Java_java_lang_String_indexOf", m->JniShortName()); + EXPECT_EQ("Java_java_lang_String_indexOf__Ljava_lang_String_2I", m->JniLongName()); + + m = c->FindClassMethod("copyValueOf", "([CII)Ljava/lang/String;", kRuntimePointerSize); + ASSERT_TRUE(m != nullptr); + ASSERT_TRUE(m->IsStatic()); + EXPECT_EQ("Java_java_lang_String_copyValueOf", m->JniShortName()); + EXPECT_EQ("Java_java_lang_String_copyValueOf___3CII", m->JniLongName()); +} + class ClassLinkerClassLoaderTest : public ClassLinkerTest { protected: // Verifies that the class identified by the given descriptor is loaded with diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc index e7a1374d5f..05159e253d 100644 --- a/runtime/common_runtime_test.cc +++ b/runtime/common_runtime_test.cc @@ -30,6 +30,8 @@ #include "base/file_utils.h" #include "base/logging.h" #include "base/macros.h" +#include "base/mutex.h" +#include "base/os.h" #include "base/runtime_debug.h" #include "base/stl_util.h" #include "base/unix_file/fd_file.h" @@ -52,7 +54,6 @@ #include "mirror/class_loader.h" #include "native/dalvik_system_DexFile.h" #include "noop_compiler_callbacks.h" -#include "os.h" #include "runtime-inl.h" #include "scoped_thread_state_change-inl.h" #include "thread.h" @@ -64,6 +65,7 @@ int main(int argc, char **argv) { // everything else. In case you want to see all messages, comment out the line. setenv("ANDROID_LOG_TAGS", "*:e", 1); + art::Locks::Init(); art::InitLogging(argv, art::Runtime::Abort); LOG(INFO) << "Running main() from common_runtime_test.cc..."; testing::InitGoogleTest(&argc, argv); diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h index 85b0dbb43c..7fc70e294f 100644 --- a/runtime/common_runtime_test.h +++ b/runtime/common_runtime_test.h @@ -26,13 +26,13 @@ #include "arch/instruction_set.h" #include "base/mutex.h" +#include "base/os.h" #include "base/unix_file/fd_file.h" #include "dex/art_dex_file_loader.h" #include "dex/compact_dex_level.h" #include "globals.h" // TODO: Add inl file and avoid including inl. #include "obj_ptr-inl.h" -#include "os.h" #include "scoped_thread_state_change-inl.h" namespace art { diff --git a/runtime/compiler_filter.cc b/runtime/compiler_filter.cc index 7b2dd05156..bda64ebf25 100644 --- a/runtime/compiler_filter.cc +++ b/runtime/compiler_filter.cc @@ -16,7 +16,7 @@ #include "compiler_filter.h" -#include "utils.h" +#include "base/utils.h" namespace art { diff --git a/runtime/dex/art_dex_file_loader_test.cc b/runtime/dex/art_dex_file_loader_test.cc index 25d4dd0875..6e2cfec381 100644 --- a/runtime/dex/art_dex_file_loader_test.cc +++ b/runtime/dex/art_dex_file_loader_test.cc @@ -19,6 +19,7 @@ #include <memory> #include "art_dex_file_loader.h" +#include "base/os.h" #include "base/stl_util.h" #include "base/unix_file/fd_file.h" #include "common_runtime_test.h" @@ -29,7 +30,6 @@ #include "dex/dex_file-inl.h" #include "dex/dex_file_loader.h" #include "mem_map.h" -#include "os.h" #include "scoped_thread_state_change-inl.h" #include "thread-current-inl.h" diff --git a/runtime/dex2oat_environment_test.h b/runtime/dex2oat_environment_test.h index 75642fc889..00a95cc7bd 100644 --- a/runtime/dex2oat_environment_test.h +++ b/runtime/dex2oat_environment_test.h @@ -24,7 +24,9 @@ #include <gtest/gtest.h> #include "base/file_utils.h" +#include "base/os.h" #include "base/stl_util.h" +#include "base/utils.h" #include "common_runtime_test.h" #include "compiler_callbacks.h" #include "dex/art_dex_file_loader.h" @@ -33,9 +35,7 @@ #include "gc/heap.h" #include "gc/space/image_space.h" #include "oat_file_assistant.h" -#include "os.h" #include "runtime.h" -#include "utils.h" namespace art { diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc index b4661819ef..719b4af293 100644 --- a/runtime/elf_file.cc +++ b/runtime/elf_file.cc @@ -28,9 +28,9 @@ #include "base/leb128.h" #include "base/stl_util.h" #include "base/unix_file/fd_file.h" +#include "base/utils.h" #include "elf_file_impl.h" #include "elf_utils.h" -#include "utils.h" namespace art { diff --git a/runtime/elf_file.h b/runtime/elf_file.h index b1c9395fb5..ab9e6fa2ec 100644 --- a/runtime/elf_file.h +++ b/runtime/elf_file.h @@ -21,9 +21,9 @@ #include <string> #include "base/macros.h" +#include "base/os.h" // Explicitly include our own elf.h to avoid Linux and other dependencies. #include "./elf.h" -#include "os.h" namespace art { template <typename ElfTypes> diff --git a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc index 1ab67ec2b9..ed5885f224 100644 --- a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc @@ -18,6 +18,7 @@ #include "art_method-inl.h" #include "base/enums.h" +#include "base/quasi_atomic.h" #include "callee_save_frame.h" #include "dex/dex_file_types.h" #include "entrypoints/entrypoint_utils-inl.h" diff --git a/runtime/gc/accounting/atomic_stack.h b/runtime/gc/accounting/atomic_stack.h index f8d8271335..6b103bfe1b 100644 --- a/runtime/gc/accounting/atomic_stack.h +++ b/runtime/gc/accounting/atomic_stack.h @@ -25,7 +25,7 @@ #include <android-base/logging.h> -#include "atomic.h" +#include "base/atomic.h" #include "base/macros.h" #include "mem_map.h" #include "stack_reference.h" diff --git a/runtime/gc/accounting/bitmap-inl.h b/runtime/gc/accounting/bitmap-inl.h index bf153f56d8..a71b212af3 100644 --- a/runtime/gc/accounting/bitmap-inl.h +++ b/runtime/gc/accounting/bitmap-inl.h @@ -23,7 +23,7 @@ #include <android-base/logging.h> -#include "atomic.h" +#include "base/atomic.h" #include "base/bit_utils.h" namespace art { diff --git a/runtime/gc/accounting/card_table-inl.h b/runtime/gc/accounting/card_table-inl.h index adca5c835e..14f5d0e1c6 100644 --- a/runtime/gc/accounting/card_table-inl.h +++ b/runtime/gc/accounting/card_table-inl.h @@ -21,7 +21,7 @@ #include <android-base/logging.h> -#include "atomic.h" +#include "base/atomic.h" #include "base/bit_utils.h" #include "mem_map.h" #include "space_bitmap.h" diff --git a/runtime/gc/accounting/card_table.cc b/runtime/gc/accounting/card_table.cc index 934e57a61b..4eea607c39 100644 --- a/runtime/gc/accounting/card_table.cc +++ b/runtime/gc/accounting/card_table.cc @@ -19,13 +19,13 @@ #include <sys/mman.h> #include "base/systrace.h" +#include "base/utils.h" #include "card_table-inl.h" #include "gc/heap.h" #include "gc/space/space.h" #include "heap_bitmap.h" #include "mem_map.h" #include "runtime.h" -#include "utils.h" namespace art { namespace gc { diff --git a/runtime/gc/accounting/card_table_test.cc b/runtime/gc/accounting/card_table_test.cc index cb2479ffad..87965eddb8 100644 --- a/runtime/gc/accounting/card_table_test.cc +++ b/runtime/gc/accounting/card_table_test.cc @@ -18,14 +18,14 @@ #include <string> -#include "atomic.h" +#include "base/atomic.h" +#include "base/utils.h" #include "common_runtime_test.h" #include "handle_scope-inl.h" #include "mirror/class-inl.h" #include "mirror/string-inl.h" // Strings are easiest to allocate #include "scoped_thread_state_change-inl.h" #include "thread_pool.h" -#include "utils.h" namespace art { diff --git a/runtime/gc/accounting/remembered_set.h b/runtime/gc/accounting/remembered_set.h index e9376a90ef..b96f0d318c 100644 --- a/runtime/gc/accounting/remembered_set.h +++ b/runtime/gc/accounting/remembered_set.h @@ -18,8 +18,9 @@ #define ART_RUNTIME_GC_ACCOUNTING_REMEMBERED_SET_H_ #include "base/allocator.h" +#include "base/globals.h" +#include "base/mutex.h" #include "base/safe_map.h" -#include "globals.h" #include <set> #include <vector> diff --git a/runtime/gc/accounting/space_bitmap-inl.h b/runtime/gc/accounting/space_bitmap-inl.h index 354b9e1dbd..384e3c2f4c 100644 --- a/runtime/gc/accounting/space_bitmap-inl.h +++ b/runtime/gc/accounting/space_bitmap-inl.h @@ -23,7 +23,7 @@ #include <android-base/logging.h> -#include "atomic.h" +#include "base/atomic.h" #include "base/bit_utils.h" namespace art { diff --git a/runtime/gc/allocator/dlmalloc.cc b/runtime/gc/allocator/dlmalloc.cc index 4570e9c1b8..e508d5fddf 100644 --- a/runtime/gc/allocator/dlmalloc.cc +++ b/runtime/gc/allocator/dlmalloc.cc @@ -59,8 +59,8 @@ static void art_heap_usage_error(const char* function, void* p) { #include <sys/mman.h> -#include "globals.h" -#include "utils.h" +#include "base/globals.h" +#include "base/utils.h" extern "C" void DlmallocMadviseCallback(void* start, void* end, size_t used_bytes, void* arg) { // Is this chunk in use? diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc index a78813bf7c..b10c504dd5 100644 --- a/runtime/gc/collector/concurrent_copying.cc +++ b/runtime/gc/collector/concurrent_copying.cc @@ -20,6 +20,7 @@ #include "base/enums.h" #include "base/file_utils.h" #include "base/histogram-inl.h" +#include "base/quasi_atomic.h" #include "base/stl_util.h" #include "base/systrace.h" #include "debugger.h" diff --git a/runtime/gc/collector/garbage_collector.cc b/runtime/gc/collector/garbage_collector.cc index fa34270d95..5e3692ea9a 100644 --- a/runtime/gc/collector/garbage_collector.cc +++ b/runtime/gc/collector/garbage_collector.cc @@ -26,6 +26,7 @@ #include "base/mutex-inl.h" #include "base/systrace.h" #include "base/time_utils.h" +#include "base/utils.h" #include "gc/accounting/heap_bitmap.h" #include "gc/gc_pause_listener.h" #include "gc/heap.h" @@ -34,7 +35,6 @@ #include "runtime.h" #include "thread-current-inl.h" #include "thread_list.h" -#include "utils.h" namespace art { namespace gc { diff --git a/runtime/gc/collector/mark_compact.h b/runtime/gc/collector/mark_compact.h index 41228099d3..e7749597cd 100644 --- a/runtime/gc/collector/mark_compact.h +++ b/runtime/gc/collector/mark_compact.h @@ -20,7 +20,7 @@ #include <deque> #include <memory> // For unique_ptr. -#include "atomic.h" +#include "base/atomic.h" #include "base/macros.h" #include "base/mutex.h" #include "garbage_collector.h" diff --git a/runtime/gc/collector/mark_sweep.h b/runtime/gc/collector/mark_sweep.h index 53b899e09e..5e0fe0607f 100644 --- a/runtime/gc/collector/mark_sweep.h +++ b/runtime/gc/collector/mark_sweep.h @@ -19,7 +19,7 @@ #include <memory> -#include "atomic.h" +#include "base/atomic.h" #include "barrier.h" #include "base/macros.h" #include "base/mutex.h" diff --git a/runtime/gc/collector/semi_space.h b/runtime/gc/collector/semi_space.h index fc77c17497..d1d45c8df6 100644 --- a/runtime/gc/collector/semi_space.h +++ b/runtime/gc/collector/semi_space.h @@ -19,7 +19,7 @@ #include <memory> -#include "atomic.h" +#include "base/atomic.h" #include "base/macros.h" #include "base/mutex.h" #include "garbage_collector.h" diff --git a/runtime/gc/heap-inl.h b/runtime/gc/heap-inl.h index 6735961591..41ee18350d 100644 --- a/runtime/gc/heap-inl.h +++ b/runtime/gc/heap-inl.h @@ -20,7 +20,9 @@ #include "heap.h" #include "allocation_listener.h" +#include "base/quasi_atomic.h" #include "base/time_utils.h" +#include "base/utils.h" #include "gc/accounting/atomic_stack.h" #include "gc/accounting/card_table-inl.h" #include "gc/allocation_record.h" @@ -34,7 +36,6 @@ #include "obj_ptr-inl.h" #include "runtime.h" #include "thread-inl.h" -#include "utils.h" #include "verify_object.h" namespace art { diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index 19b4acd836..e8f720bf3a 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -32,6 +32,7 @@ #include "base/histogram-inl.h" #include "base/logging.h" // For VLOG. #include "base/memory_tool.h" +#include "base/os.h" #include "base/stl_util.h" #include "base/systrace.h" #include "base/time_utils.h" @@ -81,7 +82,6 @@ #include "mirror/reference-inl.h" #include "nativehelper/scoped_local_ref.h" #include "obj_ptr-inl.h" -#include "os.h" #include "reflection.h" #include "runtime.h" #include "scoped_thread_state_change-inl.h" @@ -143,6 +143,10 @@ static constexpr bool kLogAllGCs = false; static constexpr size_t kPartialTlabSize = 16 * KB; static constexpr bool kUsePartialTlabs = true; +// Use Max heap for 2 seconds, this is smaller than the usual 5s window since we don't want to leave +// allocate with relaxed ergonomics for that long. +static constexpr size_t kPostForkMaxHeapDurationMS = 2000; + #if defined(__LP64__) || !defined(ADDRESS_SANITIZER) // 300 MB (0x12c00000) - (default non-moving space capacity). static uint8_t* const kPreferredAllocSpaceBegin = @@ -3539,6 +3543,12 @@ void Heap::ClampGrowthLimit() { } void Heap::ClearGrowthLimit() { + if (max_allowed_footprint_ == growth_limit_ && growth_limit_ < capacity_) { + max_allowed_footprint_ = capacity_; + concurrent_start_bytes_ = + std::max(max_allowed_footprint_, kMinConcurrentRemainingBytes) - + kMinConcurrentRemainingBytes; + } growth_limit_ = capacity_; ScopedObjectAccess soa(Thread::Current()); for (const auto& space : continuous_spaces_) { @@ -4110,5 +4120,32 @@ void Heap::VlogHeapGrowth(size_t max_allowed_footprint, size_t new_footprint, si << PrettySize(new_footprint) << " for a " << PrettySize(alloc_size) << " allocation"; } +class Heap::TriggerPostForkCCGcTask : public HeapTask { + public: + explicit TriggerPostForkCCGcTask(uint64_t target_time) : HeapTask(target_time) {} + void Run(Thread* self) OVERRIDE { + gc::Heap* heap = Runtime::Current()->GetHeap(); + // Trigger a GC, if not already done. The first GC after fork, whenever + // takes place, will adjust the thresholds to normal levels. + if (heap->max_allowed_footprint_ == heap->growth_limit_) { + heap->RequestConcurrentGC(self, kGcCauseBackground, false); + } + } +}; + +void Heap::PostForkChildAction(Thread* self) { + // Temporarily increase max_allowed_footprint_ and concurrent_start_bytes_ to + // max values to avoid GC during app launch. + if (collector_type_ == kCollectorTypeCC && !IsLowMemoryMode()) { + // Set max_allowed_footprint_ to the largest allowed value. + SetIdealFootprint(growth_limit_); + // Set concurrent_start_bytes_ to half of the heap size. + concurrent_start_bytes_ = std::max(max_allowed_footprint_ / 2, GetBytesAllocated()); + + GetTaskProcessor()->AddTask( + self, new TriggerPostForkCCGcTask(NanoTime() + MsToNs(kPostForkMaxHeapDurationMS))); + } +} + } // namespace gc } // namespace art diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h index 592172f9fe..d9eff7bfef 100644 --- a/runtime/gc/heap.h +++ b/runtime/gc/heap.h @@ -26,7 +26,7 @@ #include "allocator_type.h" #include "arch/instruction_set.h" -#include "atomic.h" +#include "base/atomic.h" #include "base/macros.h" #include "base/mutex.h" #include "base/runtime_debug.h" @@ -832,10 +832,13 @@ class Heap { const Verification* GetVerification() const; + void PostForkChildAction(Thread* self); + private: class ConcurrentGCTask; class CollectorTransitionTask; class HeapTrimTask; + class TriggerPostForkCCGcTask; // Compact source space to target space. Returns the collector used. collector::GarbageCollector* Compact(space::ContinuousMemMapAllocSpace* target_space, diff --git a/runtime/gc/reference_processor.cc b/runtime/gc/reference_processor.cc index c59642fe4e..356f3ecaa8 100644 --- a/runtime/gc/reference_processor.cc +++ b/runtime/gc/reference_processor.cc @@ -17,6 +17,7 @@ #include "reference_processor.h" #include "base/time_utils.h" +#include "base/utils.h" #include "collector/garbage_collector.h" #include "java_vm_ext.h" #include "mirror/class-inl.h" @@ -28,7 +29,6 @@ #include "reflection.h" #include "scoped_thread_state_change-inl.h" #include "task_processor.h" -#include "utils.h" #include "well_known_classes.h" namespace art { diff --git a/runtime/gc/reference_queue.h b/runtime/gc/reference_queue.h index c48d48c530..af7788130b 100644 --- a/runtime/gc/reference_queue.h +++ b/runtime/gc/reference_queue.h @@ -21,7 +21,7 @@ #include <string> #include <vector> -#include "atomic.h" +#include "base/atomic.h" #include "base/mutex.h" #include "base/timing_logger.h" #include "globals.h" diff --git a/runtime/gc/space/dlmalloc_space.cc b/runtime/gc/space/dlmalloc_space.cc index a3eef90e3a..025c3f0ead 100644 --- a/runtime/gc/space/dlmalloc_space.cc +++ b/runtime/gc/space/dlmalloc_space.cc @@ -18,6 +18,7 @@ #include "base/logging.h" // For VLOG. #include "base/time_utils.h" +#include "base/utils.h" #include "gc/accounting/card_table.h" #include "gc/accounting/space_bitmap-inl.h" #include "gc/heap.h" @@ -30,7 +31,6 @@ #include "scoped_thread_state_change-inl.h" #include "thread.h" #include "thread_list.h" -#include "utils.h" namespace art { namespace gc { diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index 366eb535f4..c100bc0c75 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -32,10 +32,12 @@ #include "base/enums.h" #include "base/file_utils.h" #include "base/macros.h" +#include "base/os.h" #include "base/scoped_flock.h" #include "base/stl_util.h" #include "base/systrace.h" #include "base/time_utils.h" +#include "base/utils.h" #include "dex/art_dex_file_loader.h" #include "dex/dex_file_loader.h" #include "exec_utils.h" @@ -46,10 +48,8 @@ #include "mirror/object-inl.h" #include "mirror/object-refvisitor-inl.h" #include "oat_file.h" -#include "os.h" #include "runtime.h" #include "space-inl.h" -#include "utils.h" namespace art { namespace gc { diff --git a/runtime/gc/space/image_space_fs.h b/runtime/gc/space/image_space_fs.h index 6ce81e9209..14deb6f001 100644 --- a/runtime/gc/space/image_space_fs.h +++ b/runtime/gc/space/image_space_fs.h @@ -23,13 +23,13 @@ #include "android-base/stringprintf.h" #include "base/file_utils.h" +#include "base/globals.h" #include "base/logging.h" // For VLOG. #include "base/macros.h" +#include "base/os.h" #include "base/unix_file/fd_file.h" -#include "globals.h" -#include "os.h" +#include "base/utils.h" #include "runtime.h" -#include "utils.h" namespace art { namespace gc { diff --git a/runtime/gc/space/large_object_space.cc b/runtime/gc/space/large_object_space.cc index d2efb102e9..512cde484d 100644 --- a/runtime/gc/space/large_object_space.cc +++ b/runtime/gc/space/large_object_space.cc @@ -25,12 +25,12 @@ #include "base/macros.h" #include "base/memory_tool.h" #include "base/mutex-inl.h" +#include "base/os.h" #include "base/stl_util.h" #include "gc/accounting/heap_bitmap-inl.h" #include "gc/accounting/space_bitmap-inl.h" #include "gc/heap.h" #include "image.h" -#include "os.h" #include "scoped_thread_state_change-inl.h" #include "space-inl.h" #include "thread-current-inl.h" diff --git a/runtime/gc/space/malloc_space.cc b/runtime/gc/space/malloc_space.cc index 17274b508d..0965560e2c 100644 --- a/runtime/gc/space/malloc_space.cc +++ b/runtime/gc/space/malloc_space.cc @@ -19,6 +19,7 @@ #include "android-base/stringprintf.h" #include "base/logging.h" // For VLOG +#include "base/utils.h" #include "gc/accounting/card_table-inl.h" #include "gc/accounting/space_bitmap-inl.h" #include "gc/heap.h" @@ -30,7 +31,6 @@ #include "runtime.h" #include "thread.h" #include "thread_list.h" -#include "utils.h" namespace art { namespace gc { diff --git a/runtime/gc/space/rosalloc_space.cc b/runtime/gc/space/rosalloc_space.cc index 3a685cb82d..e7865363a1 100644 --- a/runtime/gc/space/rosalloc_space.cc +++ b/runtime/gc/space/rosalloc_space.cc @@ -19,6 +19,7 @@ #include "base/logging.h" // For VLOG. #include "base/time_utils.h" +#include "base/utils.h" #include "gc/accounting/card_table.h" #include "gc/accounting/space_bitmap-inl.h" #include "gc/heap.h" @@ -29,7 +30,6 @@ #include "scoped_thread_state_change-inl.h" #include "thread.h" #include "thread_list.h" -#include "utils.h" namespace art { namespace gc { diff --git a/runtime/gc/space/space.h b/runtime/gc/space/space.h index 12bccb35e7..7af19fae61 100644 --- a/runtime/gc/space/space.h +++ b/runtime/gc/space/space.h @@ -20,7 +20,7 @@ #include <memory> #include <string> -#include "atomic.h" +#include "base/atomic.h" #include "base/macros.h" #include "base/mutex.h" #include "gc/accounting/space_bitmap.h" diff --git a/runtime/gc/space/zygote_space.cc b/runtime/gc/space/zygote_space.cc index fddb3f2dd2..cde155fb22 100644 --- a/runtime/gc/space/zygote_space.cc +++ b/runtime/gc/space/zygote_space.cc @@ -17,12 +17,12 @@ #include "zygote_space.h" #include "base/mutex-inl.h" +#include "base/utils.h" #include "gc/accounting/card_table-inl.h" #include "gc/accounting/space_bitmap-inl.h" #include "gc/heap.h" #include "runtime.h" #include "thread-current-inl.h" -#include "utils.h" namespace art { namespace gc { diff --git a/runtime/hprof/hprof.cc b/runtime/hprof/hprof.cc index 52ee5169fb..aa716f12ac 100644 --- a/runtime/hprof/hprof.cc +++ b/runtime/hprof/hprof.cc @@ -44,6 +44,7 @@ #include "base/array_ref.h" #include "base/macros.h" #include "base/mutex.h" +#include "base/os.h" #include "base/safe_map.h" #include "base/time_utils.h" #include "base/unix_file/fd_file.h" @@ -64,7 +65,6 @@ #include "mirror/class-inl.h" #include "mirror/class.h" #include "mirror/object-refvisitor-inl.h" -#include "os.h" #include "scoped_thread_state_change-inl.h" #include "thread_list.h" diff --git a/runtime/image.cc b/runtime/image.cc index 99406229a5..0955c3a3ca 100644 --- a/runtime/image.cc +++ b/runtime/image.cc @@ -18,10 +18,10 @@ #include "base/bit_utils.h" #include "base/length_prefixed_array.h" +#include "base/utils.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" #include "mirror/object_array.h" -#include "utils.h" namespace art { diff --git a/runtime/indirect_reference_table.cc b/runtime/indirect_reference_table.cc index 51878312d9..3b9cc0f946 100644 --- a/runtime/indirect_reference_table.cc +++ b/runtime/indirect_reference_table.cc @@ -18,6 +18,7 @@ #include "base/dumpable-inl.h" #include "base/systrace.h" +#include "base/utils.h" #include "java_vm_ext.h" #include "jni_internal.h" #include "nth_caller_visitor.h" @@ -25,7 +26,6 @@ #include "runtime.h" #include "scoped_thread_state_change-inl.h" #include "thread.h" -#include "utils.h" #include <cstdlib> diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc index b6055cb6c8..7ddd17329c 100644 --- a/runtime/instrumentation.cc +++ b/runtime/instrumentation.cc @@ -21,7 +21,7 @@ #include "arch/context.h" #include "art_field-inl.h" #include "art_method-inl.h" -#include "atomic.h" +#include "base/atomic.h" #include "base/callee_save_type.h" #include "class_linker.h" #include "debugger.h" diff --git a/runtime/intern_table.h b/runtime/intern_table.h index 05f2794b38..cb976917e6 100644 --- a/runtime/intern_table.h +++ b/runtime/intern_table.h @@ -19,7 +19,7 @@ #include <unordered_set> -#include "atomic.h" +#include "base/atomic.h" #include "base/allocator.h" #include "base/hash_set.h" #include "base/mutex.h" diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc index d8f858e95b..e35d80f724 100644 --- a/runtime/interpreter/interpreter_switch_impl.cc +++ b/runtime/interpreter/interpreter_switch_impl.cc @@ -17,6 +17,7 @@ #include "interpreter_switch_impl.h" #include "base/enums.h" +#include "base/quasi_atomic.h" #include "dex/dex_file_types.h" #include "experimental_flags.h" #include "interpreter_common.h" diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc index 9c7645af9e..2a9ef2ce98 100644 --- a/runtime/interpreter/mterp/mterp.cc +++ b/runtime/interpreter/mterp/mterp.cc @@ -18,6 +18,8 @@ * Mterp entry point and support functions. */ #include "mterp.h" + +#include "base/quasi_atomic.h" #include "debugger.h" #include "entrypoints/entrypoint_utils-inl.h" #include "interpreter/interpreter_common.h" diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc index a0b58ef29e..600561b85c 100644 --- a/runtime/interpreter/unstarted_runtime.cc +++ b/runtime/interpreter/unstarted_runtime.cc @@ -33,6 +33,7 @@ #include "base/casts.h" #include "base/enums.h" #include "base/macros.h" +#include "base/quasi_atomic.h" #include "class_linker.h" #include "common_throws.h" #include "dex/descriptors_names.h" diff --git a/runtime/jdwp/jdwp.h b/runtime/jdwp/jdwp.h index b491c3ee5c..bf1d665e9d 100644 --- a/runtime/jdwp/jdwp.h +++ b/runtime/jdwp/jdwp.h @@ -17,7 +17,7 @@ #ifndef ART_RUNTIME_JDWP_JDWP_H_ #define ART_RUNTIME_JDWP_JDWP_H_ -#include "atomic.h" +#include "base/atomic.h" #include "base/logging.h" // For VLOG. #include "base/mutex.h" #include "jdwp/jdwp_bits.h" diff --git a/runtime/jdwp/jdwp_handler.cc b/runtime/jdwp/jdwp_handler.cc index 90cac853ff..291a983e75 100644 --- a/runtime/jdwp/jdwp_handler.cc +++ b/runtime/jdwp/jdwp_handler.cc @@ -22,7 +22,7 @@ #include "android-base/stringprintf.h" -#include "atomic.h" +#include "base/atomic.h" #include "base/hex_dump.h" #include "base/logging.h" // For VLOG. #include "base/macros.h" diff --git a/runtime/jdwp/jdwp_main.cc b/runtime/jdwp/jdwp_main.cc index 63f5dc8b69..557b032154 100644 --- a/runtime/jdwp/jdwp_main.cc +++ b/runtime/jdwp/jdwp_main.cc @@ -22,7 +22,7 @@ #include "android-base/stringprintf.h" -#include "atomic.h" +#include "base/atomic.h" #include "base/logging.h" // For VLOG. #include "base/time_utils.h" #include "debugger.h" diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc index 6d99ad0046..a757960e3e 100644 --- a/runtime/jit/jit.cc +++ b/runtime/jit/jit.cc @@ -23,6 +23,7 @@ #include "base/logging.h" // For VLOG. #include "base/memory_tool.h" #include "base/runtime_debug.h" +#include "base/utils.h" #include "debugger.h" #include "entrypoints/runtime_asm_entrypoints.h" #include "interpreter/interpreter.h" @@ -38,7 +39,6 @@ #include "stack_map.h" #include "thread-inl.h" #include "thread_list.h" -#include "utils.h" namespace art { namespace jit { diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc index 68a3647974..0941b0beb3 100644 --- a/runtime/jit/jit_code_cache.cc +++ b/runtime/jit/jit_code_cache.cc @@ -22,6 +22,7 @@ #include "art_method-inl.h" #include "base/enums.h" #include "base/logging.h" // For VLOG. +#include "base/quasi_atomic.h" #include "base/stl_util.h" #include "base/systrace.h" #include "base/time_utils.h" @@ -327,33 +328,20 @@ const void* JitCodeCache::GetJniStubCode(ArtMethod* method) { class ScopedCodeCacheWrite : ScopedTrace { public: - explicit ScopedCodeCacheWrite(MemMap* code_map, bool only_for_tlb_shootdown = false) + explicit ScopedCodeCacheWrite(MemMap* code_map) : ScopedTrace("ScopedCodeCacheWrite"), - code_map_(code_map), - only_for_tlb_shootdown_(only_for_tlb_shootdown) { + code_map_(code_map) { ScopedTrace trace("mprotect all"); - CheckedCall(mprotect, - "make code writable", - code_map_->Begin(), - only_for_tlb_shootdown_ ? kPageSize : code_map_->Size(), - kProtAll); + CheckedCall(mprotect, "make code writable", code_map_->Begin(), code_map_->Size(), kProtAll); } ~ScopedCodeCacheWrite() { ScopedTrace trace("mprotect code"); - CheckedCall(mprotect, - "make code protected", - code_map_->Begin(), - only_for_tlb_shootdown_ ? kPageSize : code_map_->Size(), - kProtCode); + CheckedCall(mprotect, "make code protected", code_map_->Begin(), code_map_->Size(), kProtCode); } private: MemMap* const code_map_; - // If we're using ScopedCacheWrite only for TLB shootdown, we limit the scope of mprotect to - // one page. - const bool only_for_tlb_shootdown_; - DISALLOW_COPY_AND_ASSIGN(ScopedCodeCacheWrite); }; @@ -811,8 +799,6 @@ uint8_t* JitCodeCache::CommitCodeInternal(Thread* self, FillRootTable(roots_data, roots); { // Flush data cache, as compiled code references literals in it. - // We also need a TLB shootdown to act as memory barrier across cores. - ScopedCodeCacheWrite ccw(code_map_.get(), /* only_for_tlb_shootdown */ true); FlushDataCache(reinterpret_cast<char*>(roots_data), reinterpret_cast<char*>(roots_data + data_size)); } diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h index 0d1311fe34..16335c6911 100644 --- a/runtime/jit/jit_code_cache.h +++ b/runtime/jit/jit_code_cache.h @@ -19,8 +19,8 @@ #include "instrumentation.h" -#include "atomic.h" #include "base/arena_containers.h" +#include "base/atomic.h" #include "base/histogram-inl.h" #include "base/macros.h" #include "base/mutex.h" diff --git a/runtime/jit/profile_compilation_info.cc b/runtime/jit/profile_compilation_info.cc index 7be29c9414..1bbce4f414 100644 --- a/runtime/jit/profile_compilation_info.cc +++ b/runtime/jit/profile_compilation_info.cc @@ -37,16 +37,16 @@ #include "base/file_utils.h" #include "base/logging.h" // For VLOG. #include "base/mutex.h" +#include "base/os.h" #include "base/safe_map.h" #include "base/scoped_flock.h" #include "base/stl_util.h" #include "base/systrace.h" #include "base/time_utils.h" #include "base/unix_file/fd_file.h" +#include "base/utils.h" #include "dex/dex_file_loader.h" #include "jit/profiling_info.h" -#include "os.h" -#include "utils.h" #include "zip_archive.h" namespace art { @@ -278,7 +278,7 @@ bool ProfileCompilationInfo::Save(const std::string& filename, uint64_t* bytes_w // access and fail immediately if we can't. bool result = Save(fd); if (result) { - int64_t size = GetFileSizeBytes(filename); + int64_t size = OS::GetFileSizeBytes(filename.c_str()); if (size != -1) { VLOG(profiler) << "Successfully saved profile info to " << filename << " Size: " diff --git a/runtime/jit/profile_compilation_info.h b/runtime/jit/profile_compilation_info.h index 7e09b6b833..a0f6bf8dd6 100644 --- a/runtime/jit/profile_compilation_info.h +++ b/runtime/jit/profile_compilation_info.h @@ -20,9 +20,9 @@ #include <set> #include <vector> -#include "atomic.h" #include "base/arena_containers.h" #include "base/arena_object.h" +#include "base/atomic.h" #include "base/safe_map.h" #include "bit_memory_region.h" #include "dex/dex_cache_resolved_classes.h" diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc index 4c73d872f2..b78fcacc08 100644 --- a/runtime/jni_internal.cc +++ b/runtime/jni_internal.cc @@ -25,8 +25,8 @@ #include "art_field-inl.h" #include "art_method-inl.h" -#include "atomic.h" #include "base/allocator.h" +#include "base/atomic.h" #include "base/enums.h" #include "base/logging.h" // For VLOG. #include "base/mutex.h" diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc index 26acef06d6..b9d51c1125 100644 --- a/runtime/mem_map.cc +++ b/runtime/mem_map.cc @@ -35,10 +35,10 @@ #include "base/allocator.h" #include "base/bit_utils.h" #include "base/file_utils.h" +#include "base/globals.h" #include "base/logging.h" // For VLOG_IS_ON. #include "base/memory_tool.h" -#include "globals.h" -#include "utils.h" +#include "base/utils.h" #ifndef MAP_ANONYMOUS #define MAP_ANONYMOUS MAP_ANON diff --git a/runtime/mirror/array.cc b/runtime/mirror/array.cc index 25283bc310..ea202e766f 100644 --- a/runtime/mirror/array.cc +++ b/runtime/mirror/array.cc @@ -16,6 +16,7 @@ #include "array-inl.h" +#include "base/utils.h" #include "class-inl.h" #include "class.h" #include "class_linker-inl.h" @@ -26,7 +27,6 @@ #include "object-inl.h" #include "object_array-inl.h" #include "thread.h" -#include "utils.h" namespace art { namespace mirror { diff --git a/runtime/mirror/call_site.h b/runtime/mirror/call_site.h index db244a5442..93f274808c 100644 --- a/runtime/mirror/call_site.h +++ b/runtime/mirror/call_site.h @@ -17,8 +17,8 @@ #ifndef ART_RUNTIME_MIRROR_CALL_SITE_H_ #define ART_RUNTIME_MIRROR_CALL_SITE_H_ +#include "base/utils.h" #include "mirror/method_handle_impl.h" -#include "utils.h" namespace art { diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h index 86d538ec80..ee7d217e8d 100644 --- a/runtime/mirror/class-inl.h +++ b/runtime/mirror/class-inl.h @@ -23,6 +23,7 @@ #include "art_method.h" #include "base/array_slice.h" #include "base/length_prefixed_array.h" +#include "base/utils.h" #include "class_linker.h" #include "class_loader.h" #include "common_throws.h" @@ -39,7 +40,6 @@ #include "reference-inl.h" #include "runtime.h" #include "string.h" -#include "utils.h" namespace art { namespace mirror { diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index 7a09391056..3f4e841f86 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -21,6 +21,7 @@ #include "art_field-inl.h" #include "art_method-inl.h" #include "base/logging.h" // For VLOG. +#include "base/utils.h" #include "class-inl.h" #include "class_ext.h" #include "class_linker-inl.h" @@ -40,7 +41,6 @@ #include "runtime.h" #include "thread.h" #include "throwable.h" -#include "utils.h" #include "well_known_classes.h" namespace art { diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index 6000317c85..ea065676a0 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -21,6 +21,8 @@ #include "base/casts.h" #include "base/enums.h" #include "base/iteration_range.h" +#include "base/stride_iterator.h" +#include "base/utils.h" #include "class_flags.h" #include "class_status.h" #include "dex/dex_file.h" @@ -33,9 +35,7 @@ #include "object.h" #include "object_array.h" #include "read_barrier_option.h" -#include "stride_iterator.h" #include "thread.h" -#include "utils.h" namespace art { diff --git a/runtime/mirror/class_ext.cc b/runtime/mirror/class_ext.cc index c18b219f19..081957964c 100644 --- a/runtime/mirror/class_ext.cc +++ b/runtime/mirror/class_ext.cc @@ -19,13 +19,13 @@ #include "art_method-inl.h" #include "base/casts.h" #include "base/enums.h" +#include "base/utils.h" #include "class-inl.h" #include "dex/dex_file-inl.h" #include "gc/accounting/card_table-inl.h" #include "object-inl.h" #include "object_array.h" #include "stack_trace_element.h" -#include "utils.h" #include "well_known_classes.h" namespace art { diff --git a/runtime/mirror/emulated_stack_frame.h b/runtime/mirror/emulated_stack_frame.h index 9bfa4d6098..23626f46e0 100644 --- a/runtime/mirror/emulated_stack_frame.h +++ b/runtime/mirror/emulated_stack_frame.h @@ -17,12 +17,12 @@ #ifndef ART_RUNTIME_MIRROR_EMULATED_STACK_FRAME_H_ #define ART_RUNTIME_MIRROR_EMULATED_STACK_FRAME_H_ +#include "base/utils.h" #include "dex/dex_instruction.h" #include "method_type.h" #include "object.h" #include "stack.h" #include "string.h" -#include "utils.h" namespace art { diff --git a/runtime/mirror/method_handles_lookup.h b/runtime/mirror/method_handles_lookup.h index dd8d45e66f..fefcb2ed29 100644 --- a/runtime/mirror/method_handles_lookup.h +++ b/runtime/mirror/method_handles_lookup.h @@ -17,11 +17,11 @@ #ifndef ART_RUNTIME_MIRROR_METHOD_HANDLES_LOOKUP_H_ #define ART_RUNTIME_MIRROR_METHOD_HANDLES_LOOKUP_H_ +#include "base/utils.h" #include "gc_root.h" #include "handle.h" #include "obj_ptr.h" #include "object.h" -#include "utils.h" namespace art { diff --git a/runtime/mirror/method_type.h b/runtime/mirror/method_type.h index edd991092a..3627214d90 100644 --- a/runtime/mirror/method_type.h +++ b/runtime/mirror/method_type.h @@ -17,10 +17,10 @@ #ifndef ART_RUNTIME_MIRROR_METHOD_TYPE_H_ #define ART_RUNTIME_MIRROR_METHOD_TYPE_H_ +#include "base/utils.h" #include "object_array.h" #include "object.h" #include "string.h" -#include "utils.h" namespace art { diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h index 7fdaa32751..55dd51427c 100644 --- a/runtime/mirror/object-inl.h +++ b/runtime/mirror/object-inl.h @@ -22,7 +22,7 @@ #include "array-inl.h" #include "art_field.h" #include "art_method.h" -#include "atomic.h" +#include "base/atomic.h" #include "class-inl.h" #include "class_flags.h" #include "class_linker.h" diff --git a/runtime/mirror/object-readbarrier-inl.h b/runtime/mirror/object-readbarrier-inl.h index 126cb04cf1..aeaa850abe 100644 --- a/runtime/mirror/object-readbarrier-inl.h +++ b/runtime/mirror/object-readbarrier-inl.h @@ -19,7 +19,7 @@ #include "object.h" -#include "atomic.h" +#include "base/atomic.h" #include "heap_poisoning.h" #include "lock_word-inl.h" #include "object_reference-inl.h" diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h index 816ac69b29..95f82cb147 100644 --- a/runtime/mirror/object.h +++ b/runtime/mirror/object.h @@ -17,7 +17,7 @@ #ifndef ART_RUNTIME_MIRROR_OBJECT_H_ #define ART_RUNTIME_MIRROR_OBJECT_H_ -#include "atomic.h" +#include "base/atomic.h" #include "base/casts.h" #include "base/enums.h" #include "globals.h" diff --git a/runtime/mirror/object_array-inl.h b/runtime/mirror/object_array-inl.h index 5cfc987e44..086d2f4672 100644 --- a/runtime/mirror/object_array-inl.h +++ b/runtime/mirror/object_array-inl.h @@ -24,6 +24,7 @@ #include "android-base/stringprintf.h" #include "array-inl.h" +#include "base/utils.h" #include "class.h" #include "gc/heap.h" #include "handle_scope-inl.h" @@ -31,7 +32,6 @@ #include "object-inl.h" #include "runtime.h" #include "thread.h" -#include "utils.h" namespace art { namespace mirror { diff --git a/runtime/mirror/object_reference.h b/runtime/mirror/object_reference.h index 7fd9c71b24..cf1f85d236 100644 --- a/runtime/mirror/object_reference.h +++ b/runtime/mirror/object_reference.h @@ -17,7 +17,7 @@ #ifndef ART_RUNTIME_MIRROR_OBJECT_REFERENCE_H_ #define ART_RUNTIME_MIRROR_OBJECT_REFERENCE_H_ -#include "atomic.h" +#include "base/atomic.h" #include "base/mutex.h" // For Locks::mutator_lock_. #include "globals.h" #include "heap_poisoning.h" diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc index 32a99eb753..5306eac7f6 100644 --- a/runtime/mirror/object_test.cc +++ b/runtime/mirror/object_test.cc @@ -787,5 +787,23 @@ TEST_F(ObjectTest, ObjectPointer) { } } +TEST_F(ObjectTest, PrettyTypeOf) { + ScopedObjectAccess soa(Thread::Current()); + EXPECT_EQ("null", mirror::Object::PrettyTypeOf(nullptr)); + + StackHandleScope<2> hs(soa.Self()); + Handle<mirror::String> s(hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), ""))); + EXPECT_EQ("java.lang.String", mirror::Object::PrettyTypeOf(s.Get())); + + Handle<mirror::ShortArray> a(hs.NewHandle(mirror::ShortArray::Alloc(soa.Self(), 2))); + EXPECT_EQ("short[]", mirror::Object::PrettyTypeOf(a.Get())); + + mirror::Class* c = class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/String;"); + ASSERT_TRUE(c != nullptr); + mirror::Object* o = mirror::ObjectArray<mirror::String>::Alloc(soa.Self(), c, 0); + EXPECT_EQ("java.lang.String[]", mirror::Object::PrettyTypeOf(o)); + EXPECT_EQ("java.lang.Class<java.lang.String[]>", mirror::Object::PrettyTypeOf(o->GetClass())); +} + } // namespace mirror } // namespace art diff --git a/runtime/mirror/string-inl.h b/runtime/mirror/string-inl.h index 8c2a49c5f6..a60861cc28 100644 --- a/runtime/mirror/string-inl.h +++ b/runtime/mirror/string-inl.h @@ -22,14 +22,14 @@ #include "array.h" #include "base/bit_utils.h" +#include "base/globals.h" +#include "base/utils.h" #include "class.h" #include "common_throws.h" #include "dex/utf.h" #include "gc/heap-inl.h" -#include "globals.h" #include "runtime.h" #include "thread.h" -#include "utils.h" namespace art { namespace mirror { diff --git a/runtime/mirror/throwable.cc b/runtime/mirror/throwable.cc index a7a6d087e1..b6173d422b 100644 --- a/runtime/mirror/throwable.cc +++ b/runtime/mirror/throwable.cc @@ -20,6 +20,7 @@ #include "art_method-inl.h" #include "base/enums.h" +#include "base/utils.h" #include "class-inl.h" #include "dex/dex_file-inl.h" #include "gc/accounting/card_table-inl.h" @@ -28,7 +29,6 @@ #include "object_array.h" #include "stack_trace_element.h" #include "string.h" -#include "utils.h" #include "well_known_classes.h" namespace art { diff --git a/runtime/monitor.cc b/runtime/monitor.cc index 0c9c65a401..2a938da15b 100644 --- a/runtime/monitor.cc +++ b/runtime/monitor.cc @@ -23,6 +23,7 @@ #include "art_method-inl.h" #include "base/logging.h" // For VLOG. #include "base/mutex.h" +#include "base/quasi_atomic.h" #include "base/stl_util.h" #include "base/systrace.h" #include "base/time_utils.h" diff --git a/runtime/monitor.h b/runtime/monitor.h index f150a8c091..384ebbedaa 100644 --- a/runtime/monitor.h +++ b/runtime/monitor.h @@ -25,8 +25,8 @@ #include <list> #include <vector> -#include "atomic.h" #include "base/allocator.h" +#include "base/atomic.h" #include "base/mutex.h" #include "gc_root.h" #include "lock_word.h" diff --git a/runtime/monitor_pool.h b/runtime/monitor_pool.h index 80bae7ff69..c6b0b0b86e 100644 --- a/runtime/monitor_pool.h +++ b/runtime/monitor_pool.h @@ -22,7 +22,7 @@ #include "base/allocator.h" #ifdef __LP64__ #include <stdint.h> -#include "atomic.h" +#include "base/atomic.h" #include "runtime.h" #else #include "base/stl_util.h" // STLDeleteElements diff --git a/runtime/monitor_test.cc b/runtime/monitor_test.cc index 7d89652ddf..bff8d7678c 100644 --- a/runtime/monitor_test.cc +++ b/runtime/monitor_test.cc @@ -18,7 +18,7 @@ #include <string> -#include "atomic.h" +#include "base/atomic.h" #include "barrier.h" #include "base/time_utils.h" #include "class_linker-inl.h" diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc index 5d18b6e757..13319c4c57 100644 --- a/runtime/native/dalvik_system_DexFile.cc +++ b/runtime/native/dalvik_system_DexFile.cc @@ -22,7 +22,9 @@ #include "base/file_utils.h" #include "base/logging.h" +#include "base/os.h" #include "base/stl_util.h" +#include "base/utils.h" #include "class_linker.h" #include <class_loader_context.h> #include "common_throws.h" @@ -43,10 +45,8 @@ #include "oat_file.h" #include "oat_file_assistant.h" #include "oat_file_manager.h" -#include "os.h" #include "runtime.h" #include "scoped_thread_state_change-inl.h" -#include "utils.h" #include "well_known_classes.h" #include "zip_archive.h" diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc index 08e471b9ec..89135698e3 100644 --- a/runtime/native/dalvik_system_ZygoteHooks.cc +++ b/runtime/native/dalvik_system_ZygoteHooks.cc @@ -306,6 +306,8 @@ static void ZygoteHooks_nativePostForkChild(JNIEnv* env, LOG(ERROR) << StringPrintf("Unknown bits set in runtime_flags: %#x", runtime_flags); } + Runtime::Current()->GetHeap()->PostForkChildAction(thread); + // Update tracing. if (Trace::GetMethodTracingMode() != TracingMode::kTracingInactive) { Trace::TraceOutputMode output_mode = Trace::GetOutputMode(); diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc index 688ae1977e..13275d92e4 100644 --- a/runtime/native/java_lang_reflect_Field.cc +++ b/runtime/native/java_lang_reflect_Field.cc @@ -20,6 +20,7 @@ #include "nativehelper/jni_macros.h" #include "art_field-inl.h" +#include "base/utils.h" #include "class_linker-inl.h" #include "class_linker.h" #include "common_throws.h" @@ -31,7 +32,6 @@ #include "native_util.h" #include "reflection-inl.h" #include "scoped_fast_native_object_access-inl.h" -#include "utils.h" #include "well_known_classes.h" namespace art { diff --git a/runtime/native/java_lang_reflect_Parameter.cc b/runtime/native/java_lang_reflect_Parameter.cc index 1ab91098d7..b80b20cd8d 100644 --- a/runtime/native/java_lang_reflect_Parameter.cc +++ b/runtime/native/java_lang_reflect_Parameter.cc @@ -20,13 +20,13 @@ #include "nativehelper/jni_macros.h" #include "art_method-inl.h" +#include "base/utils.h" #include "common_throws.h" #include "dex/dex_file-inl.h" #include "dex/dex_file_annotations.h" #include "jni_internal.h" #include "native_util.h" #include "scoped_fast_native_object_access-inl.h" -#include "utils.h" namespace art { diff --git a/runtime/native/java_util_concurrent_atomic_AtomicLong.cc b/runtime/native/java_util_concurrent_atomic_AtomicLong.cc index bd4b0fec70..c0032975ce 100644 --- a/runtime/native/java_util_concurrent_atomic_AtomicLong.cc +++ b/runtime/native/java_util_concurrent_atomic_AtomicLong.cc @@ -19,7 +19,8 @@ #include "nativehelper/jni_macros.h" #include "arch/instruction_set.h" -#include "atomic.h" +#include "base/atomic.h" +#include "base/quasi_atomic.h" #include "jni_internal.h" #include "native_util.h" diff --git a/runtime/native/sun_misc_Unsafe.cc b/runtime/native/sun_misc_Unsafe.cc index 1af65a371b..25f984f6be 100644 --- a/runtime/native/sun_misc_Unsafe.cc +++ b/runtime/native/sun_misc_Unsafe.cc @@ -24,6 +24,7 @@ #include "nativehelper/jni_macros.h" +#include "base/quasi_atomic.h" #include "common_throws.h" #include "gc/accounting/card_table-inl.h" #include "jni_internal.h" diff --git a/runtime/native_stack_dump.cc b/runtime/native_stack_dump.cc index 4d4bab764c..530c266975 100644 --- a/runtime/native_stack_dump.cc +++ b/runtime/native_stack_dump.cc @@ -32,6 +32,7 @@ #include <vector> #include <linux/unistd.h> +#include <poll.h> #include <signal.h> #include <stdlib.h> #include <sys/time.h> @@ -44,11 +45,11 @@ #include "base/file_utils.h" #include "base/memory_tool.h" #include "base/mutex.h" +#include "base/os.h" #include "base/unix_file/fd_file.h" +#include "base/utils.h" #include "oat_quick_method_header.h" -#include "os.h" #include "thread-current-inl.h" -#include "utils.h" #endif @@ -145,21 +146,14 @@ static void Drain(size_t expected, bool prefix_written = false; for (;;) { - constexpr uint32_t kWaitTimeExpectedMicros = 500 * 1000; - constexpr uint32_t kWaitTimeUnexpectedMicros = 50 * 1000; - - struct timeval tv; - tv.tv_sec = 0; - tv.tv_usec = expected > 0 ? kWaitTimeExpectedMicros : kWaitTimeUnexpectedMicros; - - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(in, &rfds); - - int retval = TEMP_FAILURE_RETRY(select(in + 1, &rfds, nullptr, nullptr, &tv)); - - if (retval < 0) { - // Other side may have crashed or other errors. + constexpr uint32_t kWaitTimeExpectedMilli = 500; + constexpr uint32_t kWaitTimeUnexpectedMilli = 50; + + int timeout = expected > 0 ? kWaitTimeExpectedMilli : kWaitTimeUnexpectedMilli; + struct pollfd read_fd{in, POLLIN, 0}; + int retval = TEMP_FAILURE_RETRY(poll(&read_fd, 1, timeout)); + if (retval == -1) { + // An error occurred. pipe->reset(); return; } @@ -169,19 +163,23 @@ static void Drain(size_t expected, return; } - DCHECK_EQ(retval, 1); + if (!(read_fd.revents & POLLIN)) { + // addr2line call exited. + pipe->reset(); + return; + } constexpr size_t kMaxBuffer = 128; // Relatively small buffer. Should be OK as we're on an // alt stack, but just to be sure... char buffer[kMaxBuffer]; memset(buffer, 0, kMaxBuffer); int bytes_read = TEMP_FAILURE_RETRY(read(in, buffer, kMaxBuffer - 1)); - - if (bytes_read < 0) { + if (bytes_read <= 0) { // This should not really happen... pipe->reset(); return; } + buffer[bytes_read] = '\0'; char* tmp = buffer; while (*tmp != 0) { diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index 3576683fee..b0e1de2b81 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -40,9 +40,11 @@ #include "base/enums.h" #include "base/file_utils.h" #include "base/logging.h" // For VLOG_IS_ON. +#include "base/os.h" #include "base/stl_util.h" #include "base/systrace.h" #include "base/unix_file/fd_file.h" +#include "base/utils.h" #include "dex/art_dex_file_loader.h" #include "dex/dex_file_loader.h" #include "dex/dex_file_types.h" @@ -58,10 +60,8 @@ #include "oat.h" #include "oat_file-inl.h" #include "oat_file_manager.h" -#include "os.h" #include "runtime.h" #include "type_lookup_table.h" -#include "utils.h" #include "vdex_file.h" namespace art { @@ -1812,9 +1812,9 @@ void OatDexFile::MadviseDexFile(const DexFile& dex_file, MadviseState state) { // Default every dex file to MADV_RANDOM when its loaded by default for low ram devices. // Other devices have enough page cache to get performance benefits from loading more pages // into the page cache. - MadviseLargestPageAlignedRegion(dex_file.Begin(), - dex_file.Begin() + dex_file.Size(), - MADV_RANDOM); + DexLayoutSection::MadviseLargestPageAlignedRegion(dex_file.Begin(), + dex_file.Begin() + dex_file.Size(), + MADV_RANDOM); } const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile(); if (oat_dex_file != nullptr) { diff --git a/runtime/oat_file.h b/runtime/oat_file.h index 255a31bba9..3c2cd00c8d 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -23,9 +23,11 @@ #include "base/array_ref.h" #include "base/mutex.h" +#include "base/os.h" #include "base/safe_map.h" #include "base/stringpiece.h" #include "base/tracking_safe_map.h" +#include "base/utils.h" #include "class_status.h" #include "compiler_filter.h" #include "dex/dex_file.h" @@ -34,9 +36,7 @@ #include "index_bss_mapping.h" #include "mirror/object.h" #include "oat.h" -#include "os.h" #include "type_lookup_table.h" -#include "utils.h" namespace art { diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc index c5569ff909..5888c37582 100644 --- a/runtime/oat_file_assistant.cc +++ b/runtime/oat_file_assistant.cc @@ -25,7 +25,9 @@ #include "base/file_utils.h" #include "base/logging.h" // For VLOG. +#include "base/os.h" #include "base/stl_util.h" +#include "base/utils.h" #include "class_linker.h" #include "compiler_filter.h" #include "dex/art_dex_file_loader.h" @@ -35,10 +37,8 @@ #include "gc/space/image_space.h" #include "image.h" #include "oat.h" -#include "os.h" #include "runtime.h" #include "scoped_thread_state_change-inl.h" -#include "utils.h" #include "vdex_file.h" #include "class_loader_context.h" @@ -1263,10 +1263,14 @@ std::unique_ptr<OatFile> OatFileAssistant::OatFileInfo::ReleaseFileForUse() { switch (Status()) { case kOatBootImageOutOfDate: + // OutOfDate may be either a mismatched image, or a missing image. if (oat_file_assistant_->HasOriginalDexFiles()) { - // If there are original dex files, it is better to use them. + // If there are original dex files, it is better to use them (to avoid a potential + // quickening mismatch because the boot image changed). break; } + // If we do not accept the oat file, we may not have access to dex bytecode at all. Grudgingly + // go forward. FALLTHROUGH_INTENDED; case kOatRelocationOutOfDate: diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h index 6da49a9c29..8d6ec0014a 100644 --- a/runtime/oat_file_assistant.h +++ b/runtime/oat_file_assistant.h @@ -23,12 +23,12 @@ #include <string> #include "arch/instruction_set.h" +#include "base/os.h" #include "base/scoped_flock.h" #include "base/unix_file/fd_file.h" #include "compiler_filter.h" #include "class_loader_context.h" #include "oat_file.h" -#include "os.h" namespace art { diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc index 72f7d02892..676071b247 100644 --- a/runtime/oat_file_assistant_test.cc +++ b/runtime/oat_file_assistant_test.cc @@ -27,16 +27,16 @@ #include "android-base/strings.h" #include "art_field-inl.h" +#include "base/os.h" +#include "base/utils.h" #include "class_linker-inl.h" #include "class_loader_context.h" #include "common_runtime_test.h" #include "dexopt_test.h" #include "oat_file.h" #include "oat_file_manager.h" -#include "os.h" #include "scoped_thread_state_change-inl.h" #include "thread-current-inl.h" -#include "utils.h" namespace art { diff --git a/runtime/oat_quick_method_header.h b/runtime/oat_quick_method_header.h index 4443255f64..f0966b7bfa 100644 --- a/runtime/oat_quick_method_header.h +++ b/runtime/oat_quick_method_header.h @@ -19,10 +19,10 @@ #include "arch/instruction_set.h" #include "base/macros.h" +#include "base/utils.h" #include "method_info.h" #include "quick/quick_method_frame_info.h" #include "stack_map.h" -#include "utils.h" namespace art { diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc index c61ecc880b..470287b449 100644 --- a/runtime/parsed_options.cc +++ b/runtime/parsed_options.cc @@ -23,13 +23,13 @@ #include "base/file_utils.h" #include "base/macros.h" #include "base/stringpiece.h" +#include "base/utils.h" #include "debugger.h" #include "gc/heap.h" #include "monitor.h" #include "runtime.h" #include "ti/agent.h" #include "trace.h" -#include "utils.h" #include "cmdline_parser.h" #include "runtime_options.h" @@ -161,10 +161,6 @@ std::unique_ptr<RuntimeParser> ParsedOptions::MakeParser(bool ignore_unrecognize .Define({"-XX:EnableHSpaceCompactForOOM", "-XX:DisableHSpaceCompactForOOM"}) .WithValues({true, false}) .IntoKey(M::EnableHSpaceCompactForOOM) - .Define("-XX:DumpNativeStackOnSigQuit:_") - .WithType<bool>() - .WithValueMap({{"false", false}, {"true", true}}) - .IntoKey(M::DumpNativeStackOnSigQuit) .Define("-XX:MadviseRandomAccess:_") .WithType<bool>() .WithValueMap({{"false", false}, {"true", true}}) @@ -735,7 +731,6 @@ void ParsedOptions::Usage(const char* fmt, ...) { UsageMessage(stream, " -XX:BackgroundGC=none\n"); UsageMessage(stream, " -XX:LargeObjectSpace={disabled,map,freelist}\n"); UsageMessage(stream, " -XX:LargeObjectThreshold=N\n"); - UsageMessage(stream, " -XX:DumpNativeStackOnSigQuit=booleanvalue\n"); UsageMessage(stream, " -XX:MadviseRandomAccess:booleanvalue\n"); UsageMessage(stream, " -XX:SlowDebug={false,true}\n"); UsageMessage(stream, " -Xmethod-trace\n"); diff --git a/runtime/read_barrier-inl.h b/runtime/read_barrier-inl.h index a77d100b92..58f6c04c3e 100644 --- a/runtime/read_barrier-inl.h +++ b/runtime/read_barrier-inl.h @@ -19,6 +19,7 @@ #include "read_barrier.h" +#include "base/utils.h" #include "gc/accounting/read_barrier_table.h" #include "gc/collector/concurrent_copying-inl.h" #include "gc/heap.h" @@ -26,7 +27,6 @@ #include "mirror/object_reference.h" #include "mirror/reference.h" #include "runtime.h" -#include "utils.h" namespace art { diff --git a/runtime/reference_table.cc b/runtime/reference_table.cc index a6df27b236..d62cbdb11a 100644 --- a/runtime/reference_table.cc +++ b/runtime/reference_table.cc @@ -19,6 +19,7 @@ #include "android-base/stringprintf.h" #include "base/mutex.h" +#include "base/utils.h" #include "gc/allocation_record.h" #include "gc/heap.h" #include "indirect_reference_table.h" @@ -30,7 +31,6 @@ #include "mirror/string-inl.h" #include "runtime-inl.h" #include "thread.h" -#include "utils.h" namespace art { diff --git a/runtime/reflection-inl.h b/runtime/reflection-inl.h index 87432ab77b..26fb021903 100644 --- a/runtime/reflection-inl.h +++ b/runtime/reflection-inl.h @@ -21,13 +21,13 @@ #include "android-base/stringprintf.h" +#include "base/utils.h" #include "common_throws.h" #include "dex/descriptors_names.h" #include "dex/primitive.h" #include "jvalue-inl.h" #include "mirror/object-inl.h" #include "obj_ptr-inl.h" -#include "utils.h" namespace art { diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 4442fc6a54..0ca646cdb6 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -56,16 +56,20 @@ #include "art_method-inl.h" #include "asm_support.h" #include "asm_support_check.h" -#include "atomic.h" #include "base/aborting.h" #include "base/arena_allocator.h" +#include "base/atomic.h" #include "base/dumpable.h" #include "base/enums.h" #include "base/file_utils.h" #include "base/memory_tool.h" +#include "base/mutex.h" +#include "base/os.h" +#include "base/quasi_atomic.h" #include "base/stl_util.h" #include "base/systrace.h" #include "base/unix_file/fd_file.h" +#include "base/utils.h" #include "class_linker-inl.h" #include "compiler_callbacks.h" #include "debugger.h" @@ -141,7 +145,6 @@ #include "oat_file.h" #include "oat_file_manager.h" #include "object_callbacks.h" -#include "os.h" #include "parsed_options.h" #include "quick/quick_method_frame_info.h" #include "reflection.h" @@ -157,7 +160,6 @@ #include "ti/agent.h" #include "trace.h" #include "transaction.h" -#include "utils.h" #include "vdex_file.h" #include "verifier/method_verifier.h" #include "well_known_classes.h" @@ -269,7 +271,6 @@ Runtime::Runtime() pending_hidden_api_warning_(false), dedupe_hidden_api_warnings_(true), always_set_hidden_api_warning_flag_(false), - dump_native_stack_on_sig_quit_(true), pruned_dalvik_cache_(false), // Initially assume we perceive jank in case the process state is never updated. process_state_(kProcessStateJankPerceptible), @@ -621,6 +622,7 @@ void Runtime::SweepSystemWeaks(IsMarkedVisitor* visitor) { bool Runtime::ParseOptions(const RuntimeOptions& raw_options, bool ignore_unrecognized, RuntimeArgumentMap* runtime_options) { + Locks::Init(); InitLogging(/* argv */ nullptr, Abort); // Calls Locks::Init() as a side effect. bool parsed = ParsedOptions::Parse(raw_options, ignore_unrecognized, runtime_options); if (!parsed) { @@ -1151,7 +1153,6 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) { is_explicit_gc_disabled_ = runtime_options.Exists(Opt::DisableExplicitGC); dex2oat_enabled_ = runtime_options.GetOrDefault(Opt::Dex2Oat); image_dex2oat_enabled_ = runtime_options.GetOrDefault(Opt::ImageDex2Oat); - dump_native_stack_on_sig_quit_ = runtime_options.GetOrDefault(Opt::DumpNativeStackOnSigQuit); vfprintf_ = runtime_options.GetOrDefault(Opt::HookVfprintf); exit_ = runtime_options.GetOrDefault(Opt::HookExit); @@ -2215,7 +2216,7 @@ void Runtime::RegisterAppInfo(const std::vector<std::string>& code_paths, LOG(WARNING) << "JIT profile information will not be recorded: profile filename is empty."; return; } - if (!FileExists(profile_output_filename)) { + if (!OS::FileExists(profile_output_filename.c_str(), false /*check_file_type*/)) { LOG(WARNING) << "JIT profile information will not be recorded: profile file does not exits."; return; } diff --git a/runtime/runtime.h b/runtime/runtime.h index c7f650ea3f..b961e7f39a 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -651,10 +651,6 @@ class Runtime { safe_mode_ = mode; } - bool GetDumpNativeStackOnSigQuit() const { - return dump_native_stack_on_sig_quit_; - } - bool GetPrunedDalvikCache() const { return pruned_dalvik_cache_; } @@ -1005,9 +1001,6 @@ class Runtime { // when there is a warning. This is only used for testing. bool always_set_hidden_api_warning_flag_; - // Whether threads should dump their native stack on SIGQUIT. - bool dump_native_stack_on_sig_quit_; - // Whether the dalvik cache was pruned when initializing the runtime. bool pruned_dalvik_cache_; diff --git a/runtime/runtime_common.cc b/runtime/runtime_common.cc index 59af9187f9..41bfb58d93 100644 --- a/runtime/runtime_common.cc +++ b/runtime/runtime_common.cc @@ -41,7 +41,6 @@ namespace art { using android::base::StringPrintf; static constexpr bool kUseSigRTTimeout = true; -static constexpr bool kDumpNativeStackOnTimeout = true; const char* GetSignalName(int signal_number) { switch (signal_number) { @@ -441,7 +440,7 @@ void HandleUnexpectedSignalCommon(int signal_number, // Special timeout signal. Try to dump all threads. // Note: Do not use DumpForSigQuit, as that might disable native unwind, but the native parts // are of value here. - runtime->GetThreadList()->Dump(std::cerr, kDumpNativeStackOnTimeout); + runtime->GetThreadList()->Dump(std::cerr); std::cerr << std::endl; } diff --git a/runtime/runtime_common.h b/runtime/runtime_common.h index 06d66270af..3fba441b55 100644 --- a/runtime/runtime_common.h +++ b/runtime/runtime_common.h @@ -31,8 +31,8 @@ #include <iomanip> #include "base/dumpable.h" +#include "base/utils.h" #include "native_stack_dump.h" -#include "utils.h" namespace art { diff --git a/runtime/runtime_options.cc b/runtime/runtime_options.cc index bce0d81cfb..f8c680db44 100644 --- a/runtime/runtime_options.cc +++ b/runtime/runtime_options.cc @@ -18,13 +18,13 @@ #include <memory> +#include "base/utils.h" #include "debugger.h" #include "gc/heap.h" #include "monitor.h" #include "runtime.h" #include "thread_list.h" #include "trace.h" -#include "utils.h" namespace art { diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def index 4121ad69ed..dcb1335023 100644 --- a/runtime/runtime_options.def +++ b/runtime/runtime_options.def @@ -70,7 +70,6 @@ RUNTIME_OPTIONS_KEY (Unit, LowMemoryMode) RUNTIME_OPTIONS_KEY (bool, UseTLAB, (kUseTlab || kUseReadBarrier)) RUNTIME_OPTIONS_KEY (bool, EnableHSpaceCompactForOOM, true) RUNTIME_OPTIONS_KEY (bool, UseJitCompilation, false) -RUNTIME_OPTIONS_KEY (bool, DumpNativeStackOnSigQuit, true) RUNTIME_OPTIONS_KEY (bool, MadviseRandomAccess, false) RUNTIME_OPTIONS_KEY (unsigned int, JITCompileThreshold) RUNTIME_OPTIONS_KEY (unsigned int, JITWarmupThreshold) diff --git a/runtime/signal_catcher.cc b/runtime/signal_catcher.cc index 9c3afbb133..d590ad5cc6 100644 --- a/runtime/signal_catcher.cc +++ b/runtime/signal_catcher.cc @@ -36,18 +36,18 @@ #include "arch/instruction_set.h" #include "base/file_utils.h" #include "base/logging.h" // For GetCmdLine. +#include "base/os.h" #include "base/time_utils.h" #include "base/unix_file/fd_file.h" +#include "base/utils.h" #include "class_linker.h" #include "gc/heap.h" #include "jit/profile_saver.h" -#include "os.h" #include "runtime.h" #include "scoped_thread_state_change-inl.h" #include "signal_set.h" #include "thread.h" #include "thread_list.h" -#include "utils.h" namespace art { diff --git a/runtime/thread.cc b/runtime/thread.cc index 4cdf015478..f0bd9aa65e 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -45,6 +45,7 @@ #include "base/systrace.h" #include "base/timing_logger.h" #include "base/to_str.h" +#include "base/utils.h" #include "class_linker-inl.h" #include "debugger.h" #include "dex/descriptors_names.h" @@ -90,7 +91,6 @@ #include "stack_map.h" #include "thread-inl.h" #include "thread_list.h" -#include "utils.h" #include "verifier/method_verifier.h" #include "verify_object.h" #include "well_known_classes.h" @@ -1161,10 +1161,9 @@ void Thread::ShortDump(std::ostream& os) const { << "]"; } -void Thread::Dump(std::ostream& os, bool dump_native_stack, BacktraceMap* backtrace_map, - bool force_dump_stack) const { +void Thread::Dump(std::ostream& os, BacktraceMap* backtrace_map, bool force_dump_stack) const { DumpState(os); - DumpStack(os, dump_native_stack, backtrace_map, force_dump_stack); + DumpStack(os, backtrace_map, force_dump_stack); } mirror::String* Thread::GetThreadName() const { @@ -1964,10 +1963,7 @@ void Thread::DumpJavaStack(std::ostream& os, bool check_suspended, bool dump_loc } } -void Thread::DumpStack(std::ostream& os, - bool dump_native_stack, - BacktraceMap* backtrace_map, - bool force_dump_stack) const { +void Thread::DumpStack(std::ostream& os, BacktraceMap* backtrace_map, bool force_dump_stack) const { // TODO: we call this code when dying but may not have suspended the thread ourself. The // IsSuspended check is therefore racy with the use for dumping (normally we inhibit // the race with the thread_suspend_count_lock_). @@ -1980,7 +1976,7 @@ void Thread::DumpStack(std::ostream& os, } if (safe_to_dump || force_dump_stack) { // If we're currently in native code, dump that stack before dumping the managed stack. - if (dump_native_stack && (dump_for_abort || force_dump_stack || ShouldShowNativeStack(this))) { + if (dump_for_abort || force_dump_stack || ShouldShowNativeStack(this)) { DumpKernelStack(os, GetTid(), " kernel: ", false); ArtMethod* method = GetCurrentMethod(nullptr, diff --git a/runtime/thread.h b/runtime/thread.h index 295685e799..108fbc7f86 100644 --- a/runtime/thread.h +++ b/runtime/thread.h @@ -28,7 +28,7 @@ #include "arch/context.h" #include "arch/instruction_set.h" -#include "atomic.h" +#include "base/atomic.h" #include "base/enums.h" #include "base/macros.h" #include "base/mutex.h" @@ -207,7 +207,6 @@ class Thread { // Dumps the detailed thread state and the thread stack (used for SIGQUIT). void Dump(std::ostream& os, - bool dump_native_stack = true, BacktraceMap* backtrace_map = nullptr, bool force_dump_stack = false) const REQUIRES(!Locks::thread_suspend_count_lock_) @@ -1303,7 +1302,6 @@ class Thread { void DumpState(std::ostream& os) const REQUIRES_SHARED(Locks::mutator_lock_); void DumpStack(std::ostream& os, - bool dump_native_stack = true, BacktraceMap* backtrace_map = nullptr, bool force_dump_stack = false) const REQUIRES(!Locks::thread_suspend_count_lock_) diff --git a/runtime/thread_linux.cc b/runtime/thread_linux.cc index 9673eee795..d05fecf0a9 100644 --- a/runtime/thread_linux.cc +++ b/runtime/thread_linux.cc @@ -19,7 +19,7 @@ #include <signal.h> #include "base/logging.h" // For VLOG. -#include "utils.h" +#include "base/utils.h" namespace art { diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc index 8095ef57c7..2e41b9f455 100644 --- a/runtime/thread_list.cc +++ b/runtime/thread_list.cc @@ -152,9 +152,8 @@ void ThreadList::DumpForSigQuit(std::ostream& os) { suspend_all_historam_.PrintConfidenceIntervals(os, 0.99, data); // Dump time to suspend. } } - bool dump_native_stack = Runtime::Current()->GetDumpNativeStackOnSigQuit(); - Dump(os, dump_native_stack); - DumpUnattachedThreads(os, dump_native_stack && kDumpUnattachedThreadNativeStackForSigQuit); + Dump(os); + DumpUnattachedThreads(os, kDumpUnattachedThreadNativeStackForSigQuit); } static void DumpUnattachedThread(std::ostream& os, pid_t tid, bool dump_native_stack) @@ -201,11 +200,10 @@ static constexpr uint32_t kDumpWaitTimeout = kIsTargetBuild ? 100000 : 20000; // A closure used by Thread::Dump. class DumpCheckpoint FINAL : public Closure { public: - DumpCheckpoint(std::ostream* os, bool dump_native_stack) + explicit DumpCheckpoint(std::ostream* os) : os_(os), barrier_(0), - backtrace_map_(dump_native_stack ? BacktraceMap::Create(getpid()) : nullptr), - dump_native_stack_(dump_native_stack) { + backtrace_map_(BacktraceMap::Create(getpid())) { if (backtrace_map_ != nullptr) { backtrace_map_->SetSuffixesToIgnore(std::vector<std::string> { "oat", "odex" }); } @@ -219,7 +217,7 @@ class DumpCheckpoint FINAL : public Closure { std::ostringstream local_os; { ScopedObjectAccess soa(self); - thread->Dump(local_os, dump_native_stack_, backtrace_map_.get()); + thread->Dump(local_os, backtrace_map_.get()); } { // Use the logging lock to ensure serialization when writing to the common ostream. @@ -247,18 +245,16 @@ class DumpCheckpoint FINAL : public Closure { Barrier barrier_; // A backtrace map, so that all threads use a shared info and don't reacquire/parse separately. std::unique_ptr<BacktraceMap> backtrace_map_; - // Whether we should dump the native stack. - const bool dump_native_stack_; }; -void ThreadList::Dump(std::ostream& os, bool dump_native_stack) { +void ThreadList::Dump(std::ostream& os) { Thread* self = Thread::Current(); { MutexLock mu(self, *Locks::thread_list_lock_); os << "DALVIK THREADS (" << list_.size() << "):\n"; } if (self != nullptr) { - DumpCheckpoint checkpoint(&os, dump_native_stack); + DumpCheckpoint checkpoint(&os); size_t threads_running_checkpoint; { // Use SOA to prevent deadlocks if multiple threads are calling Dump() at the same time. @@ -269,7 +265,7 @@ void ThreadList::Dump(std::ostream& os, bool dump_native_stack) { checkpoint.WaitForThreadsToRunThroughCheckpoint(threads_running_checkpoint); } } else { - DumpUnattachedThreads(os, dump_native_stack); + DumpUnattachedThreads(os, /* dump_native_stack */ true); } } @@ -491,7 +487,6 @@ void ThreadList::RunEmptyCheckpoint() { // Found a runnable thread that hasn't responded to the empty checkpoint request. // Assume it's stuck and safe to dump its stack. thread->Dump(LOG_STREAM(FATAL_WITHOUT_ABORT), - /*dump_native_stack*/ true, /*backtrace_map*/ nullptr, /*force_dump_stack*/ true); } diff --git a/runtime/thread_list.h b/runtime/thread_list.h index 895c1a41ce..09b10d2ad3 100644 --- a/runtime/thread_list.h +++ b/runtime/thread_list.h @@ -57,7 +57,7 @@ class ThreadList { void DumpForSigQuit(std::ostream& os) REQUIRES(!Locks::thread_list_lock_, !Locks::mutator_lock_); // For thread suspend timeout dumps. - void Dump(std::ostream& os, bool dump_native_stack = true) + void Dump(std::ostream& os) REQUIRES(!Locks::thread_list_lock_, !Locks::thread_suspend_count_lock_); pid_t GetLockOwner(); // For SignalCatcher. diff --git a/runtime/thread_pool.cc b/runtime/thread_pool.cc index 386cdf006a..bec1150807 100644 --- a/runtime/thread_pool.cc +++ b/runtime/thread_pool.cc @@ -29,9 +29,9 @@ #include "base/casts.h" #include "base/stl_util.h" #include "base/time_utils.h" +#include "base/utils.h" #include "runtime.h" #include "thread-current-inl.h" -#include "utils.h" namespace art { diff --git a/runtime/thread_pool_test.cc b/runtime/thread_pool_test.cc index 28aa21f7a2..895a108af0 100644 --- a/runtime/thread_pool_test.cc +++ b/runtime/thread_pool_test.cc @@ -18,7 +18,7 @@ #include <string> -#include "atomic.h" +#include "base/atomic.h" #include "common_runtime_test.h" #include "scoped_thread_state_change-inl.h" #include "thread-inl.h" diff --git a/runtime/trace.cc b/runtime/trace.cc index d97dcb5a3d..0f321b6591 100644 --- a/runtime/trace.cc +++ b/runtime/trace.cc @@ -24,10 +24,12 @@ #include "art_method-inl.h" #include "base/casts.h" #include "base/enums.h" +#include "base/os.h" #include "base/stl_util.h" #include "base/systrace.h" #include "base/time_utils.h" #include "base/unix_file/fd_file.h" +#include "base/utils.h" #include "class_linker.h" #include "common_throws.h" #include "debugger.h" @@ -41,12 +43,10 @@ #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" #include "nativehelper/scoped_local_ref.h" -#include "os.h" #include "scoped_thread_state_change-inl.h" #include "stack.h" #include "thread.h" #include "thread_list.h" -#include "utils.h" namespace art { diff --git a/runtime/trace.h b/runtime/trace.h index 7ce12dace0..86b8d00d51 100644 --- a/runtime/trace.h +++ b/runtime/trace.h @@ -26,12 +26,12 @@ #include <unordered_map> #include <vector> -#include "atomic.h" +#include "base/atomic.h" #include "base/macros.h" +#include "base/os.h" #include "base/safe_map.h" #include "globals.h" #include "instrumentation.h" -#include "os.h" namespace art { diff --git a/runtime/type_lookup_table.cc b/runtime/type_lookup_table.cc index 925a9089cb..7e204fc03a 100644 --- a/runtime/type_lookup_table.cc +++ b/runtime/type_lookup_table.cc @@ -20,9 +20,9 @@ #include <memory> #include "base/bit_utils.h" +#include "base/utils.h" #include "dex/dex_file-inl.h" #include "dex/utf-inl.h" -#include "utils.h" namespace art { diff --git a/runtime/utils_test.cc b/runtime/utils_test.cc deleted file mode 100644 index e67e93f9c5..0000000000 --- a/runtime/utils_test.cc +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright (C) 2011 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 "utils.h" - -#include <libgen.h> -#include <stdlib.h> - -#include "base/enums.h" -#include "base/file_utils.h" -#include "base/stl_util.h" -#include "class_linker-inl.h" -#include "common_runtime_test.h" -#include "exec_utils.h" -#include "handle_scope-inl.h" -#include "mirror/array-inl.h" -#include "mirror/array.h" -#include "mirror/object-inl.h" -#include "mirror/object_array-inl.h" -#include "mirror/string.h" -#include "scoped_thread_state_change-inl.h" - -#include "base/memory_tool.h" - -namespace art { - -class UtilsTest : public CommonRuntimeTest {}; - -TEST_F(UtilsTest, PrettyTypeOf) { - ScopedObjectAccess soa(Thread::Current()); - EXPECT_EQ("null", mirror::Object::PrettyTypeOf(nullptr)); - - StackHandleScope<2> hs(soa.Self()); - Handle<mirror::String> s(hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), ""))); - EXPECT_EQ("java.lang.String", mirror::Object::PrettyTypeOf(s.Get())); - - Handle<mirror::ShortArray> a(hs.NewHandle(mirror::ShortArray::Alloc(soa.Self(), 2))); - EXPECT_EQ("short[]", mirror::Object::PrettyTypeOf(a.Get())); - - mirror::Class* c = class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/String;"); - ASSERT_TRUE(c != nullptr); - mirror::Object* o = mirror::ObjectArray<mirror::String>::Alloc(soa.Self(), c, 0); - EXPECT_EQ("java.lang.String[]", mirror::Object::PrettyTypeOf(o)); - EXPECT_EQ("java.lang.Class<java.lang.String[]>", mirror::Object::PrettyTypeOf(o->GetClass())); -} - -TEST_F(UtilsTest, PrettyClass) { - ScopedObjectAccess soa(Thread::Current()); - EXPECT_EQ("null", mirror::Class::PrettyClass(nullptr)); - mirror::Class* c = class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/String;"); - ASSERT_TRUE(c != nullptr); - mirror::Object* o = mirror::ObjectArray<mirror::String>::Alloc(soa.Self(), c, 0); - EXPECT_EQ("java.lang.Class<java.lang.String[]>", mirror::Class::PrettyClass(o->GetClass())); -} - -TEST_F(UtilsTest, PrettyClassAndClassLoader) { - ScopedObjectAccess soa(Thread::Current()); - EXPECT_EQ("null", mirror::Class::PrettyClassAndClassLoader(nullptr)); - mirror::Class* c = class_linker_->FindSystemClass(soa.Self(), "[Ljava/lang/String;"); - ASSERT_TRUE(c != nullptr); - mirror::Object* o = mirror::ObjectArray<mirror::String>::Alloc(soa.Self(), c, 0); - EXPECT_EQ("java.lang.Class<java.lang.String[],null>", - mirror::Class::PrettyClassAndClassLoader(o->GetClass())); -} - -TEST_F(UtilsTest, PrettyField) { - ScopedObjectAccess soa(Thread::Current()); - EXPECT_EQ("null", ArtField::PrettyField(nullptr)); - - mirror::Class* java_lang_String = class_linker_->FindSystemClass(soa.Self(), - "Ljava/lang/String;"); - - ArtField* f; - f = java_lang_String->FindDeclaredInstanceField("count", "I"); - EXPECT_EQ("int java.lang.String.count", f->PrettyField()); - EXPECT_EQ("java.lang.String.count", f->PrettyField(false)); -} - -TEST_F(UtilsTest, PrettySize) { - EXPECT_EQ("1GB", PrettySize(1 * GB)); - EXPECT_EQ("2GB", PrettySize(2 * GB)); - if (sizeof(size_t) > sizeof(uint32_t)) { - EXPECT_EQ("100GB", PrettySize(100 * GB)); - } - EXPECT_EQ("1024KB", PrettySize(1 * MB)); - EXPECT_EQ("10MB", PrettySize(10 * MB)); - EXPECT_EQ("100MB", PrettySize(100 * MB)); - EXPECT_EQ("1024B", PrettySize(1 * KB)); - EXPECT_EQ("10KB", PrettySize(10 * KB)); - EXPECT_EQ("100KB", PrettySize(100 * KB)); - EXPECT_EQ("0B", PrettySize(0)); - EXPECT_EQ("1B", PrettySize(1)); - EXPECT_EQ("10B", PrettySize(10)); - EXPECT_EQ("100B", PrettySize(100)); - EXPECT_EQ("512B", PrettySize(512)); -} - -TEST_F(UtilsTest, JniShortName_JniLongName) { - ScopedObjectAccess soa(Thread::Current()); - mirror::Class* c = class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/String;"); - ASSERT_TRUE(c != nullptr); - ArtMethod* m; - - m = c->FindClassMethod("charAt", "(I)C", kRuntimePointerSize); - ASSERT_TRUE(m != nullptr); - ASSERT_FALSE(m->IsDirect()); - EXPECT_EQ("Java_java_lang_String_charAt", m->JniShortName()); - EXPECT_EQ("Java_java_lang_String_charAt__I", m->JniLongName()); - - m = c->FindClassMethod("indexOf", "(Ljava/lang/String;I)I", kRuntimePointerSize); - ASSERT_TRUE(m != nullptr); - ASSERT_FALSE(m->IsDirect()); - EXPECT_EQ("Java_java_lang_String_indexOf", m->JniShortName()); - EXPECT_EQ("Java_java_lang_String_indexOf__Ljava_lang_String_2I", m->JniLongName()); - - m = c->FindClassMethod("copyValueOf", "([CII)Ljava/lang/String;", kRuntimePointerSize); - ASSERT_TRUE(m != nullptr); - ASSERT_TRUE(m->IsStatic()); - EXPECT_EQ("Java_java_lang_String_copyValueOf", m->JniShortName()); - EXPECT_EQ("Java_java_lang_String_copyValueOf___3CII", m->JniLongName()); -} - -TEST_F(UtilsTest, Split) { - std::vector<std::string> actual; - std::vector<std::string> expected; - - expected.clear(); - - actual.clear(); - Split("", ':', &actual); - EXPECT_EQ(expected, actual); - - actual.clear(); - Split(":", ':', &actual); - EXPECT_EQ(expected, actual); - - expected.clear(); - expected.push_back("foo"); - - actual.clear(); - Split(":foo", ':', &actual); - EXPECT_EQ(expected, actual); - - actual.clear(); - Split("foo:", ':', &actual); - EXPECT_EQ(expected, actual); - - actual.clear(); - Split(":foo:", ':', &actual); - EXPECT_EQ(expected, actual); - - expected.push_back("bar"); - - actual.clear(); - Split("foo:bar", ':', &actual); - EXPECT_EQ(expected, actual); - - actual.clear(); - Split(":foo:bar", ':', &actual); - EXPECT_EQ(expected, actual); - - actual.clear(); - Split("foo:bar:", ':', &actual); - EXPECT_EQ(expected, actual); - - actual.clear(); - Split(":foo:bar:", ':', &actual); - EXPECT_EQ(expected, actual); - - expected.push_back("baz"); - - actual.clear(); - Split("foo:bar:baz", ':', &actual); - EXPECT_EQ(expected, actual); - - actual.clear(); - Split(":foo:bar:baz", ':', &actual); - EXPECT_EQ(expected, actual); - - actual.clear(); - Split("foo:bar:baz:", ':', &actual); - EXPECT_EQ(expected, actual); - - actual.clear(); - Split(":foo:bar:baz:", ':', &actual); - EXPECT_EQ(expected, actual); -} - -TEST_F(UtilsTest, ArrayCount) { - int i[64]; - EXPECT_EQ(ArrayCount(i), 64u); - char c[7]; - EXPECT_EQ(ArrayCount(c), 7u); -} - -TEST_F(UtilsTest, BoundsCheckedCast) { - char buffer[64]; - const char* buffer_end = buffer + ArrayCount(buffer); - EXPECT_EQ(BoundsCheckedCast<const uint64_t*>(nullptr, buffer, buffer_end), nullptr); - EXPECT_EQ(BoundsCheckedCast<const uint64_t*>(buffer, buffer, buffer_end), - reinterpret_cast<const uint64_t*>(buffer)); - EXPECT_EQ(BoundsCheckedCast<const uint64_t*>(buffer + 56, buffer, buffer_end), - reinterpret_cast<const uint64_t*>(buffer + 56)); - EXPECT_EQ(BoundsCheckedCast<const uint64_t*>(buffer - 1, buffer, buffer_end), nullptr); - EXPECT_EQ(BoundsCheckedCast<const uint64_t*>(buffer + 57, buffer, buffer_end), nullptr); -} - -} // namespace art diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h index d27f431cdc..72f03f266a 100644 --- a/runtime/vdex_file.h +++ b/runtime/vdex_file.h @@ -22,9 +22,9 @@ #include "base/array_ref.h" #include "base/macros.h" +#include "base/os.h" #include "dex/compact_offset_table.h" #include "mem_map.h" -#include "os.h" #include "quicken_info.h" namespace art { diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 52bd7362ef..74c2244cfe 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -30,6 +30,7 @@ #include "base/stl_util.h" #include "base/systrace.h" #include "base/time_utils.h" +#include "base/utils.h" #include "class_linker.h" #include "compiler_callbacks.h" #include "dex/descriptors_names.h" @@ -55,7 +56,6 @@ #include "runtime.h" #include "scoped_thread_state_change-inl.h" #include "stack.h" -#include "utils.h" #include "verifier_compiler_binding.h" #include "verifier_deps.h" diff --git a/runtime/verifier/method_verifier_test.cc b/runtime/verifier/method_verifier_test.cc index 97c1b62abe..db3f093905 100644 --- a/runtime/verifier/method_verifier_test.cc +++ b/runtime/verifier/method_verifier_test.cc @@ -21,11 +21,11 @@ #include "android-base/strings.h" +#include "base/utils.h" #include "class_linker-inl.h" #include "common_runtime_test.h" #include "dex/dex_file-inl.h" #include "scoped_thread_state_change-inl.h" -#include "utils.h" #include "verifier_enums.h" namespace art { diff --git a/runtime/zip_archive.h b/runtime/zip_archive.h index 7b45690462..aa54018574 100644 --- a/runtime/zip_archive.h +++ b/runtime/zip_archive.h @@ -23,11 +23,11 @@ #include <android-base/logging.h> +#include "base/os.h" #include "base/safe_map.h" #include "base/unix_file/random_access_file.h" #include "globals.h" #include "mem_map.h" -#include "os.h" // system/core/zip_archive definitions. struct ZipEntry; diff --git a/runtime/zip_archive_test.cc b/runtime/zip_archive_test.cc index 4fc7ee2e20..48ee94ce8c 100644 --- a/runtime/zip_archive_test.cc +++ b/runtime/zip_archive_test.cc @@ -22,9 +22,9 @@ #include <zlib.h> #include <memory> +#include "base/os.h" #include "base/unix_file/fd_file.h" #include "common_runtime_test.h" -#include "os.h" namespace art { diff --git a/sigchainlib/sigchain_test.cc b/sigchainlib/sigchain_test.cc index 9f338ad3a2..1d1e54f127 100644 --- a/sigchainlib/sigchain_test.cc +++ b/sigchainlib/sigchain_test.cc @@ -50,7 +50,7 @@ static int sigismember64(sigset64_t* set, int member) { static int RealSigprocmask(int how, const sigset64_t* new_sigset, sigset64_t* old_sigset) { // glibc's sigset_t is overly large, so sizeof(*new_sigset) doesn't work. - return syscall(__NR_rt_sigprocmask, how, new_sigset, old_sigset, 8); + return syscall(__NR_rt_sigprocmask, how, new_sigset, old_sigset, NSIG/8); } class SigchainTest : public ::testing::Test { diff --git a/test/137-cfi/cfi.cc b/test/137-cfi/cfi.cc index 83234f0382..b91d983e75 100644 --- a/test/137-cfi/cfi.cc +++ b/test/137-cfi/cfi.cc @@ -31,11 +31,11 @@ #include "base/file_utils.h" #include "base/macros.h" +#include "base/utils.h" #include "gc/heap.h" #include "gc/space/image_space.h" #include "oat_file.h" #include "runtime.h" -#include "utils.h" namespace art { diff --git a/test/1949-short-dex-file/expected.txt b/test/1949-short-dex-file/expected.txt new file mode 100644 index 0000000000..863339fb8c --- /dev/null +++ b/test/1949-short-dex-file/expected.txt @@ -0,0 +1 @@ +Passed diff --git a/test/1949-short-dex-file/info.txt b/test/1949-short-dex-file/info.txt new file mode 100644 index 0000000000..e924086e23 --- /dev/null +++ b/test/1949-short-dex-file/info.txt @@ -0,0 +1,30 @@ +Tests the fix for b/74116990 + +The JIT was reading into incorrect dex files during class redefinition if a +native method was present. + +The transformed dex file is specifically crafted to have exactly 4 methodIDs in +it. They are (in order): + (0) Ljava/lang/Object;-><init>()V + (1) Lxyz/Transform;-><init>()V + (2) Lxyz/Transform;->bar()V + (3) Lxyz/Transform;->foo()V + +In the transformed version of the dex file there is a new method. The new list of methodIDs is: + (0) Lart/Test1949;->doNothing()V + (1) Ljava/lang/Object;-><init>()V + (2) Lxyz/Transform;-><init>()V + (3) Lxyz/Transform;->bar()V + (4) Lxyz/Transform;->foo()V + +This test tries to get the JIT to read out-of-bounds on the initial dex file by getting it to +read the 5th method id of the new file (Lxyz/Transform;->foo()V) from the old dex file (which +only has 4 method ids). + +To do this we need to make sure that the class being transformed is near the end of the +alphabet (package xyz, method foo). If it is further forward than the other method-ids then the +JIT will read an incorrect (but valid) method-id from the old-dex file. This is why the error +wasn't caught in our other tests (package art is always at the front). + +The final method that causes the OOB read needs to be a native method because that is the only +method-type the jit uses dex-file information to keep track of. diff --git a/test/988-method-trace/check b/test/1949-short-dex-file/run index de64a3e17b..c6e62ae6cd 100644..100755 --- a/test/988-method-trace/check +++ b/test/1949-short-dex-file/run @@ -1,12 +1,12 @@ #!/bin/bash # -# Copyright (C) 2017 The Android Open Source Project +# Copyright 2016 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 +# 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, @@ -14,10 +14,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Building for libcore, this uses @hide API which gives it wrong method trace in the expected.txt -# TODO: would be nice if we could build against core_current jars in the future to avoid this. -if [[ "$NEED_DEX" == true ]]; then - patch -p0 expected.txt < expected_jack.diff >/dev/null -fi - -./default-check "$@" +./default-run "$@" --jvmti diff --git a/test/1949-short-dex-file/src/Main.java b/test/1949-short-dex-file/src/Main.java new file mode 100644 index 0000000000..dbbaa861c9 --- /dev/null +++ b/test/1949-short-dex-file/src/Main.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +public class Main { + public static void main(String[] args) throws Exception { + art.Test1949.run(); + } +} diff --git a/test/1949-short-dex-file/src/art/Redefinition.java b/test/1949-short-dex-file/src/art/Redefinition.java new file mode 100644 index 0000000000..56d2938a01 --- /dev/null +++ b/test/1949-short-dex-file/src/art/Redefinition.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package art; + +import java.util.ArrayList; +// Common Redefinition functions. Placed here for use by CTS +public class Redefinition { + public static final class CommonClassDefinition { + public final Class<?> target; + public final byte[] class_file_bytes; + public final byte[] dex_file_bytes; + + public CommonClassDefinition(Class<?> target, byte[] class_file_bytes, byte[] dex_file_bytes) { + this.target = target; + this.class_file_bytes = class_file_bytes; + this.dex_file_bytes = dex_file_bytes; + } + } + + // A set of possible test configurations. Test should set this if they need to. + // This must be kept in sync with the defines in ti-agent/common_helper.cc + public static enum Config { + COMMON_REDEFINE(0), + COMMON_RETRANSFORM(1), + COMMON_TRANSFORM(2); + + private final int val; + private Config(int val) { + this.val = val; + } + } + + public static void setTestConfiguration(Config type) { + nativeSetTestConfiguration(type.val); + } + + private static native void nativeSetTestConfiguration(int type); + + // Transforms the class + public static native void doCommonClassRedefinition(Class<?> target, + byte[] classfile, + byte[] dexfile); + + public static void doMultiClassRedefinition(CommonClassDefinition... defs) { + ArrayList<Class<?>> classes = new ArrayList<>(); + ArrayList<byte[]> class_files = new ArrayList<>(); + ArrayList<byte[]> dex_files = new ArrayList<>(); + + for (CommonClassDefinition d : defs) { + classes.add(d.target); + class_files.add(d.class_file_bytes); + dex_files.add(d.dex_file_bytes); + } + doCommonMultiClassRedefinition(classes.toArray(new Class<?>[0]), + class_files.toArray(new byte[0][]), + dex_files.toArray(new byte[0][])); + } + + public static void addMultiTransformationResults(CommonClassDefinition... defs) { + for (CommonClassDefinition d : defs) { + addCommonTransformationResult(d.target.getCanonicalName(), + d.class_file_bytes, + d.dex_file_bytes); + } + } + + public static native void doCommonMultiClassRedefinition(Class<?>[] targets, + byte[][] classfiles, + byte[][] dexfiles); + public static native void doCommonClassRetransformation(Class<?>... target); + public static native void setPopRetransformations(boolean pop); + public static native void popTransformationFor(String name); + public static native void enableCommonRetransformation(boolean enable); + public static native void addCommonTransformationResult(String target_name, + byte[] class_bytes, + byte[] dex_bytes); +} diff --git a/test/1949-short-dex-file/src/art/Test1949.java b/test/1949-short-dex-file/src/art/Test1949.java new file mode 100644 index 0000000000..98fa7fc2c1 --- /dev/null +++ b/test/1949-short-dex-file/src/art/Test1949.java @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2016 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. + */ + +package art; + +import java.lang.reflect.*; +import java.util.Base64; +import java.nio.ByteBuffer; + +public class Test1949 { + private final static boolean isDalvik = System.getProperty("java.vm.name").equals("Dalvik"); + + // This dex file is specifically crafted to have exactly 4 methodIDs in it. They are (in order): + // (0) Ljava/lang/Object;-><init>()V + // (1) Lxyz/Transform;-><init>()V + // (2) Lxyz/Transform;->bar()V + // (3) Lxyz/Transform;->foo()V + // + // In the transformed version of the dex file there is a new method. The new list of methodIDs is: + // (0) Lart/Test1949;->doNothing()V + // (1) Ljava/lang/Object;-><init>()V + // (2) Lxyz/Transform;-><init>()V + // (3) Lxyz/Transform;->bar()V + // (4) Lxyz/Transform;->foo()V + // + // This test tries to get the JIT to read out-of-bounds on the initial dex file by getting it to + // read the 5th method id of the new file (Lxyz/Transform;->foo()V) from the old dex file (which + // only has 4 method ids). + // + // To do this we need to make sure that the class being transformed is near the end of the + // alphabet (package xyz, method foo). If it is further forward than the other method-ids then the + // JIT will read an incorrect (but valid) method-id from the old-dex file. This is why the error + // wasn't caught in our other tests (package art is always at the front). + // + // The final method that causes the OOB read needs to be a native method because that is the only + // method-type the jit uses dex-file information to keep track of. + + /** + * base64 encoded class/dex file for + * package xyz; + * public class Transform { + * public native void foo(); + * public void bar() {} + * } + */ + private static final byte[] CLASS_BYTES_INIT = Base64.getDecoder().decode( + "yv66vgAAADUADwoAAwAMBwANBwAOAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJU" + + "YWJsZQEAA2ZvbwEAA2JhcgEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwABAAFAQANeHl6" + + "L1RyYW5zZm9ybQEAEGphdmEvbGFuZy9PYmplY3QAIQACAAMAAAAAAAMAAQAEAAUAAQAGAAAAHQAB" + + "AAEAAAAFKrcAAbEAAAABAAcAAAAGAAEAAAACAQEACAAFAAAAAQAJAAUAAQAGAAAAGQAAAAEAAAAB" + + "sQAAAAEABwAAAAYAAQAAAAQAAQAKAAAAAgAL"); + private static final byte[] DEX_BYTES_INIT = Base64.getDecoder().decode( + "ZGV4CjAzNQBDUutFJpeT+okk+aXah8NQ61q2XRtkmChwAgAAcAAAAHhWNBIAAAAAAAAAANwBAAAI" + + "AAAAcAAAAAMAAACQAAAAAQAAAJwAAAAAAAAAAAAAAAQAAACoAAAAAQAAAMgAAACIAQAA6AAAABwB" + + "AAAkAQAAOAEAAEkBAABZAQAAXAEAAGEBAABmAQAAAQAAAAIAAAAEAAAABAAAAAIAAAAAAAAAAAAA" + + "AAAAAAABAAAAAAAAAAEAAAAFAAAAAQAAAAYAAAABAAAAAQAAAAAAAAAAAAAAAwAAAAAAAADDAQAA" + + "AAAAAAEAAQABAAAAEgEAAAQAAABwEAAAAAAOAAEAAQAAAAAAFgEAAAEAAAAOAAIADgAEAA4AAAAG" + + "PGluaXQ+ABJMamF2YS9sYW5nL09iamVjdDsAD0x4eXovVHJhbnNmb3JtOwAOVHJhbnNmb3JtLmph" + + "dmEAAVYAA2JhcgADZm9vAFt+fkQ4eyJtaW4tYXBpIjoxLCJzaGEtMSI6IjkwZWYyMjkwNWMzZmVj" + + "Y2FiMjMwMzBhNmJkYzU2NTcwYTMzNWVmMDUiLCJ2ZXJzaW9uIjoidjEuMS44LWRldiJ9AAAAAQIB" + + "gYAE6AECAYACAYECAAAAAAAAAAAMAAAAAAAAAAEAAAAAAAAAAQAAAAgAAABwAAAAAgAAAAMAAACQ" + + "AAAAAwAAAAEAAACcAAAABQAAAAQAAACoAAAABgAAAAEAAADIAAAAASAAAAIAAADoAAAAAyAAAAIA" + + "AAASAQAAAiAAAAgAAAAcAQAAACAAAAEAAADDAQAAAxAAAAEAAADYAQAAABAAAAEAAADcAQAA"); + + /** + * base64 encoded class/dex file for + * package xyz; + * public class Transform { + * public native void foo(); + * public void bar() { + * // Make sure the methodID is before any of the ones in Transform + * art.Test1949.doNothing(); + * } + * } + */ + private static final byte[] CLASS_BYTES_FINAL = Base64.getDecoder().decode( + "yv66vgAAADUAFAoABAANCgAOAA8HABAHABEBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAPTGluZU51" + + "bWJlclRhYmxlAQADZm9vAQADYmFyAQAKU291cmNlRmlsZQEADlRyYW5zZm9ybS5qYXZhDAAFAAYH" + + "ABIMABMABgEADXh5ei9UcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2JqZWN0AQAMYXJ0L1Rlc3QxOTQ5" + + "AQAJZG9Ob3RoaW5nACEAAwAEAAAAAAADAAEABQAGAAEABwAAAB0AAQABAAAABSq3AAGxAAAAAQAI" + + "AAAABgABAAAAAgEBAAkABgAAAAEACgAGAAEABwAAABwAAAABAAAABLgAArEAAAABAAgAAAAGAAEA" + + "AAAEAAEACwAAAAIADA=="); + private static final byte[] DEX_BYTES_FINAL = Base64.getDecoder().decode( + "ZGV4CjAzNQBHXBiw7Hso1vnmaXE1VCV41f4+0aECixOgAgAAcAAAAHhWNBIAAAAAAAAAAAwCAAAK" + + "AAAAcAAAAAQAAACYAAAAAQAAAKgAAAAAAAAAAAAAAAUAAAC0AAAAAQAAANwAAACkAQAA/AAAADQB" + + "AAA8AQAATAEAAGABAABxAQAAgQEAAIQBAACJAQAAlAEAAJkBAAABAAAAAgAAAAMAAAAFAAAABQAA" + + "AAMAAAAAAAAAAAAAAAcAAAABAAAAAAAAAAIAAAAAAAAAAgAAAAYAAAACAAAACAAAAAIAAAABAAAA" + + "AQAAAAAAAAAEAAAAAAAAAPYBAAAAAAAAAQABAAEAAAAsAQAABAAAAHAQAQAAAA4AAQABAAAAAAAw" + + "AQAABAAAAHEAAAAAAA4AAgAOAAQADgAGPGluaXQ+AA5MYXJ0L1Rlc3QxOTQ5OwASTGphdmEvbGFu" + + "Zy9PYmplY3Q7AA9MeHl6L1RyYW5zZm9ybTsADlRyYW5zZm9ybS5qYXZhAAFWAANiYXIACWRvTm90" + + "aGluZwADZm9vAFt+fkQ4eyJtaW4tYXBpIjoxLCJzaGEtMSI6IjkwZWYyMjkwNWMzZmVjY2FiMjMw" + + "MzBhNmJkYzU2NTcwYTMzNWVmMDUiLCJ2ZXJzaW9uIjoidjEuMS44LWRldiJ9AAAAAQICgYAE/AED" + + "AZQCAYECAAAAAAAMAAAAAAAAAAEAAAAAAAAAAQAAAAoAAABwAAAAAgAAAAQAAACYAAAAAwAAAAEA" + + "AACoAAAABQAAAAUAAAC0AAAABgAAAAEAAADcAAAAASAAAAIAAAD8AAAAAyAAAAIAAAAsAQAAAiAA" + + "AAoAAAA0AQAAACAAAAEAAAD2AQAAAxAAAAEAAAAIAgAAABAAAAEAAAAMAgAA"); + + public static void run() throws Exception { + Redefinition.setTestConfiguration(Redefinition.Config.COMMON_REDEFINE); + doTest(); + } + + // A method with a methodID before anything in Transform. + public static void doNothing() {} + + private static ClassLoader CreateClassLoader(byte[] clz, byte[] dex) throws Exception { + if (isDalvik) { + Class<?> class_loader_class = Class.forName("dalvik.system.InMemoryDexClassLoader"); + Constructor<?> ctor = class_loader_class.getConstructor(ByteBuffer.class, ClassLoader.class); + /* on Dalvik, this is a DexFile; otherwise, it's null */ + return (ClassLoader)ctor.newInstance(ByteBuffer.wrap(dex), Test1949.class.getClassLoader()); + } else { + return new ClassLoader() { + public Class<?> findClass(String name) throws ClassNotFoundException { + if (name.equals("xyz.Transform")) { + return defineClass(name, clz, 0, clz.length); + } else { + throw new ClassNotFoundException("Couldn't find class: " + name); + } + } + }; + } + } + + public static void doTest() throws Exception { + Class c = CreateClassLoader(CLASS_BYTES_INIT, DEX_BYTES_INIT).loadClass("xyz.Transform"); + Redefinition.doCommonClassRedefinition(c, CLASS_BYTES_FINAL, DEX_BYTES_FINAL); + System.out.println("Passed"); + } +} diff --git a/test/445-checker-licm/src/Main.java b/test/445-checker-licm/src/Main.java index bd5d9e20c7..517aacd9f2 100644 --- a/test/445-checker-licm/src/Main.java +++ b/test/445-checker-licm/src/Main.java @@ -153,7 +153,6 @@ public class Main { return result; } - /// CHECK-START: int Main.invariantBoundIntrinsic(int) instruction_simplifier (before) /// CHECK-DAG: InvokeStaticOrDirect loop:{{B\d+}} // @@ -176,14 +175,17 @@ public class Main { return result; } - /// CHECK-START: int Main.invariantBodyIntrinsic(int, int) licm (before) + /// CHECK-START: int Main.invariantBodyIntrinsic(int, int) instruction_simplifier (before) /// CHECK-DAG: InvokeStaticOrDirect loop:{{B\d+}} + /// CHECK-START: int Main.invariantBodyIntrinsic(int, int) licm (before) + /// CHECK-DAG: Max loop:{{B\d+}} + /// CHECK-START: int Main.invariantBodyIntrinsic(int, int) licm (after) - /// CHECK-NOT: InvokeStaticOrDirect loop:{{B\d+}} + /// CHECK-NOT: Max loop:{{B\d+}} /// CHECK-START: int Main.invariantBodyIntrinsic(int, int) licm (after) - /// CHECK-DAG: InvokeStaticOrDirect loop:none + /// CHECK-DAG: Max loop:none public static int invariantBodyIntrinsic(int x, int y) { int result = 0; diff --git a/test/562-checker-no-intermediate/src/Main.java b/test/562-checker-no-intermediate/src/Main.java index 104ba8bc06..2b19918142 100644 --- a/test/562-checker-no-intermediate/src/Main.java +++ b/test/562-checker-no-intermediate/src/Main.java @@ -18,7 +18,7 @@ public class Main { /** * Check that the intermediate address computation is not reordered or merged - * across the call to Math.abs(). + * across a method call. */ /// CHECK-START-ARM: void Main.main(java.lang.String[]) instruction_simplifier_arm (before) @@ -26,7 +26,7 @@ public class Main { /// CHECK-DAG: <<Array:l\d+>> NullCheck /// CHECK-DAG: <<Index:i\d+>> BoundsCheck /// CHECK-DAG: <<ArrayGet:i\d+>> ArrayGet [<<Array>>,<<Index>>] - /// CHECK-DAG: <<AbsM42:i\d+>> InvokeStaticOrDirect [<<ConstM42>>] intrinsic:MathAbsInt + /// CHECK-DAG: <<AbsM42:i\d+>> InvokeStaticOrDirect [<<ConstM42>>{{(,[ij]\d+)?}}] method_name:Main.$noinline$abs /// CHECK-DAG: <<Add:i\d+>> Add [<<ArrayGet>>,<<AbsM42>>] /// CHECK-DAG: ArraySet [<<Array>>,<<Index>>,<<Add>>] @@ -37,7 +37,7 @@ public class Main { /// CHECK-DAG: <<Index:i\d+>> BoundsCheck /// CHECK-DAG: <<Address1:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] /// CHECK-DAG: <<ArrayGet:i\d+>> ArrayGet [<<Address1>>,<<Index>>] - /// CHECK-DAG: <<AbsM42:i\d+>> InvokeStaticOrDirect [<<ConstM42>>] intrinsic:MathAbsInt + /// CHECK-DAG: <<AbsM42:i\d+>> InvokeStaticOrDirect [<<ConstM42>>{{(,[ij]\d+)?}}] method_name:Main.$noinline$abs /// CHECK-DAG: <<Add:i\d+>> Add [<<ArrayGet>>,<<AbsM42>>] /// CHECK-DAG: <<Address2:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] /// CHECK-DAG: ArraySet [<<Address2>>,<<Index>>,<<Add>>] @@ -49,7 +49,7 @@ public class Main { /// CHECK-DAG: <<Index:i\d+>> BoundsCheck /// CHECK-DAG: <<Address1:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] /// CHECK-DAG: <<ArrayGet:i\d+>> ArrayGet [<<Address1>>,<<Index>>] - /// CHECK-DAG: <<AbsM42:i\d+>> InvokeStaticOrDirect [<<ConstM42>>] intrinsic:MathAbsInt + /// CHECK-DAG: <<AbsM42:i\d+>> InvokeStaticOrDirect [<<ConstM42>>{{(,[ij]\d+)?}}] method_name:Main.$noinline$abs /// CHECK-DAG: <<Add:i\d+>> Add [<<ArrayGet>>,<<AbsM42>>] /// CHECK-DAG: <<Address2:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] /// CHECK-DAG: ArraySet [<<Address2>>,<<Index>>,<<Add>>] @@ -60,7 +60,7 @@ public class Main { /// CHECK-DAG: <<Array:l\d+>> NullCheck /// CHECK-DAG: <<Index:i\d+>> BoundsCheck /// CHECK-DAG: <<ArrayGet:i\d+>> ArrayGet [<<Array>>,<<Index>>] - /// CHECK-DAG: <<AbsM42:i\d+>> InvokeStaticOrDirect [<<ConstM42>>] intrinsic:MathAbsInt + /// CHECK-DAG: <<AbsM42:i\d+>> InvokeStaticOrDirect [<<ConstM42>>{{(,[ij]\d+)?}}] method_name:Main.$noinline$abs /// CHECK-DAG: <<Add:i\d+>> Add [<<ArrayGet>>,<<AbsM42>>] /// CHECK-DAG: ArraySet [<<Array>>,<<Index>>,<<Add>>] @@ -71,7 +71,7 @@ public class Main { /// CHECK-DAG: <<Index:i\d+>> BoundsCheck /// CHECK-DAG: <<Address1:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] /// CHECK-DAG: <<ArrayGet:i\d+>> ArrayGet [<<Address1>>,<<Index>>] - /// CHECK-DAG: <<AbsM42:i\d+>> InvokeStaticOrDirect [<<ConstM42>>] intrinsic:MathAbsInt + /// CHECK-DAG: <<AbsM42:i\d+>> InvokeStaticOrDirect [<<ConstM42>>{{(,[ij]\d+)?}}] method_name:Main.$noinline$abs /// CHECK-DAG: <<Add:i\d+>> Add [<<ArrayGet>>,<<AbsM42>>] /// CHECK-DAG: <<Address2:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] /// CHECK-DAG: ArraySet [<<Address2>>,<<Index>>,<<Add>>] @@ -83,13 +83,17 @@ public class Main { /// CHECK-DAG: <<Index:i\d+>> BoundsCheck /// CHECK-DAG: <<Address1:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] /// CHECK-DAG: <<ArrayGet:i\d+>> ArrayGet [<<Address1>>,<<Index>>] - /// CHECK-DAG: <<AbsM42:i\d+>> InvokeStaticOrDirect [<<ConstM42>>] intrinsic:MathAbsInt + /// CHECK-DAG: <<AbsM42:i\d+>> InvokeStaticOrDirect [<<ConstM42>>{{(,[ij]\d+)?}}] method_name:Main.$noinline$abs /// CHECK-DAG: <<Add:i\d+>> Add [<<ArrayGet>>,<<AbsM42>>] /// CHECK-DAG: <<Address2:i\d+>> IntermediateAddress [<<Array>>,<<DataOffset>>] /// CHECK-DAG: ArraySet [<<Address2>>,<<Index>>,<<Add>>] public static void main(String[] args) { - array[index] += Math.abs(-42); + array[index] += $noinline$abs(-42); + } + + public static int $noinline$abs(int value) { + return Math.abs(value); } static int index = 0; diff --git a/test/631-checker-fp-abs/src/Main.java b/test/631-checker-fp-abs/src/Main.java index 0f85dc6865..2db93b8248 100644 --- a/test/631-checker-fp-abs/src/Main.java +++ b/test/631-checker-fp-abs/src/Main.java @@ -23,6 +23,9 @@ */ public class Main { + private final static boolean isDalvik = + System.getProperty("java.vm.name").equals("Dalvik"); + private static final int SPQUIET = 1 << 22; private static final long DPQUIET = 1L << 51; @@ -73,13 +76,16 @@ public class Main { // A few NaN numbers. int[] spnans = { - 0x7f800001, + 0x7f800001, // signaling 0x7fa00000, - 0x7fc00000, + 0x7fbfffff, + 0x7fc00000, // quiet + 0x7fc00001, 0x7fffffff, - 0xff800001, + 0xff800001, // signaling 0xffa00000, - 0xffc00000, + 0xffbfffff, + 0xffc00000, // quiet 0xffffffff }; for (int i = 0; i < spnans.length; i++) { @@ -142,6 +148,13 @@ public class Main { // We allow that an expected NaN result has become quiet. private static void expectEqualsNaN32(int expected, int result) { if (expected != result && (expected | SPQUIET) != result) { + if (!isDalvik) { + // If not on ART, relax the expected value more towards just + // "spec compliance" and allow sign bit to remain set for NaN. + if (expected == (result & Integer.MAX_VALUE)) { + return; + } + } throw new Error("Expected: 0x" + Integer.toHexString(expected) + ", found: 0x" + Integer.toHexString(result)); } @@ -157,6 +170,13 @@ public class Main { // We allow that an expected NaN result has become quiet. private static void expectEqualsNaN64(long expected, long result) { if (expected != result && (expected | DPQUIET) != result) { + if (!isDalvik) { + // If not on ART, relax the expected value more towards just + // "spec compliance" and allow sign bit to remain set for NaN. + if (expected == (result & Long.MAX_VALUE)) { + return; + } + } throw new Error("Expected: 0x" + Long.toHexString(expected) + ", found: 0x" + Long.toHexString(result)); } diff --git a/test/645-checker-abs-simd/src/Main.java b/test/645-checker-abs-simd/src/Main.java index 4c69e58004..870a403ff5 100644 --- a/test/645-checker-abs-simd/src/Main.java +++ b/test/645-checker-abs-simd/src/Main.java @@ -19,6 +19,9 @@ */ public class Main { + private final static boolean isDalvik = + System.getProperty("java.vm.name").equals("Dalvik"); + private static final int SPQUIET = 1 << 22; private static final long DPQUIET = 1L << 51; @@ -378,6 +381,13 @@ public class Main { // We allow that an expected NaN result has become quiet. private static void expectEqualsNaN32(int expected, int result) { if (expected != result && (expected | SPQUIET) != result) { + if (!isDalvik) { + // If not on ART, relax the expected value more towards just + // "spec compliance" and allow sign bit to remain set for NaN. + if (expected == (result & Integer.MAX_VALUE)) { + return; + } + } throw new Error("Expected: 0x" + Integer.toHexString(expected) + ", found: 0x" + Integer.toHexString(result)); } @@ -386,6 +396,13 @@ public class Main { // We allow that an expected NaN result has become quiet. private static void expectEqualsNaN64(long expected, long result) { if (expected != result && (expected | DPQUIET) != result) { + if (!isDalvik) { + // If not on ART, relax the expected value more towards just + // "spec compliance" and allow sign bit to remain set for NaN. + if (expected == (result & Long.MAX_VALUE)) { + return; + } + } throw new Error("Expected: 0x" + Long.toHexString(expected) + ", found: 0x" + Long.toHexString(result)); } diff --git a/test/651-checker-byte-simd-minmax/src/Main.java b/test/651-checker-byte-simd-minmax/src/Main.java index 45949ae90a..4e667bbc6f 100644 --- a/test/651-checker-byte-simd-minmax/src/Main.java +++ b/test/651-checker-byte-simd-minmax/src/Main.java @@ -23,7 +23,7 @@ public class Main { /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none /// CHECK-DAG: <<Get1:b\d+>> ArrayGet loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Get2:b\d+>> ArrayGet loop:<<Loop>> outer_loop:none - /// CHECK-DAG: <<Min:i\d+>> InvokeStaticOrDirect [<<Get1>>,<<Get2>>] intrinsic:MathMinIntInt loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Min:i\d+>> Min [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<Min>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none // @@ -54,7 +54,7 @@ public class Main { /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none /// CHECK-DAG: <<Get1:a\d+>> ArrayGet loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Get2:a\d+>> ArrayGet loop:<<Loop>> outer_loop:none - /// CHECK-DAG: <<Min:i\d+>> InvokeStaticOrDirect [<<Get1>>,<<Get2>>] intrinsic:MathMinIntInt loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Min:i\d+>> Min [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<Min>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none // @@ -74,7 +74,7 @@ public class Main { /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none /// CHECK-DAG: <<Get1:b\d+>> ArrayGet loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Get2:b\d+>> ArrayGet loop:<<Loop>> outer_loop:none - /// CHECK-DAG: <<Max:i\d+>> InvokeStaticOrDirect [<<Get1>>,<<Get2>>] intrinsic:MathMaxIntInt loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Max:i\d+>> Max [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<Max>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none // @@ -105,7 +105,7 @@ public class Main { /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none /// CHECK-DAG: <<Get1:a\d+>> ArrayGet loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Get2:a\d+>> ArrayGet loop:<<Loop>> outer_loop:none - /// CHECK-DAG: <<Max:i\d+>> InvokeStaticOrDirect [<<Get1>>,<<Get2>>] intrinsic:MathMaxIntInt loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Max:i\d+>> Max [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<Max>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none // @@ -125,7 +125,7 @@ public class Main { /// CHECK-DAG: <<I100:i\d+>> IntConstant 100 loop:none /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none /// CHECK-DAG: <<Get:b\d+>> ArrayGet loop:<<Loop>> outer_loop:none - /// CHECK-DAG: <<Min:i\d+>> InvokeStaticOrDirect [<<Get>>,<<I100>>] intrinsic:MathMinIntInt loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Min:i\d+>> Min [<<Get>>,<<I100>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Cnv:b\d+>> TypeConversion [<<Min>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none // diff --git a/test/651-checker-char-simd-minmax/src/Main.java b/test/651-checker-char-simd-minmax/src/Main.java index 9b056094a3..520e10b6c1 100644 --- a/test/651-checker-char-simd-minmax/src/Main.java +++ b/test/651-checker-char-simd-minmax/src/Main.java @@ -23,7 +23,7 @@ public class Main { /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none /// CHECK-DAG: <<Get1:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Get2:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none - /// CHECK-DAG: <<Min:i\d+>> InvokeStaticOrDirect [<<Get1>>,<<Get2>>] intrinsic:MathMinIntInt loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Min:i\d+>> Min [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Cnv:c\d+>> TypeConversion [<<Min>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none // @@ -43,7 +43,7 @@ public class Main { /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none /// CHECK-DAG: <<Get1:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Get2:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none - /// CHECK-DAG: <<Max:i\d+>> InvokeStaticOrDirect [<<Get1>>,<<Get2>>] intrinsic:MathMaxIntInt loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Max:i\d+>> Max [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Cnv:c\d+>> TypeConversion [<<Max>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none // @@ -63,7 +63,7 @@ public class Main { /// CHECK-DAG: <<I100:i\d+>> IntConstant 100 loop:none /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none /// CHECK-DAG: <<Get:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none - /// CHECK-DAG: <<Min:i\d+>> InvokeStaticOrDirect [<<Get>>,<<I100>>] intrinsic:MathMinIntInt loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Min:i\d+>> Min [<<Get>>,<<I100>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Cnv:c\d+>> TypeConversion [<<Min>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none // diff --git a/test/651-checker-double-simd-minmax/src/Main.java b/test/651-checker-double-simd-minmax/src/Main.java index 6b12e7e63c..2eaf907167 100644 --- a/test/651-checker-double-simd-minmax/src/Main.java +++ b/test/651-checker-double-simd-minmax/src/Main.java @@ -23,7 +23,7 @@ public class Main { /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none /// CHECK-DAG: <<Get1:d\d+>> ArrayGet loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Get2:d\d+>> ArrayGet loop:<<Loop>> outer_loop:none - /// CHECK-DAG: <<Min:d\d+>> InvokeStaticOrDirect [<<Get1>>,<<Get2>>] intrinsic:MathMinDoubleDouble loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Min:d\d+>> Min [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Min>>] loop:<<Loop>> outer_loop:none // // TODO x86: 0.0 vs -0.0? @@ -45,7 +45,7 @@ public class Main { /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none /// CHECK-DAG: <<Get1:d\d+>> ArrayGet loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Get2:d\d+>> ArrayGet loop:<<Loop>> outer_loop:none - /// CHECK-DAG: <<Max:d\d+>> InvokeStaticOrDirect [<<Get1>>,<<Get2>>] intrinsic:MathMaxDoubleDouble loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Max:d\d+>> Max [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Max>>] loop:<<Loop>> outer_loop:none // // TODO x86: 0.0 vs -0.0? diff --git a/test/651-checker-float-simd-minmax/src/Main.java b/test/651-checker-float-simd-minmax/src/Main.java index 278a9c9367..dc09dfc7cc 100644 --- a/test/651-checker-float-simd-minmax/src/Main.java +++ b/test/651-checker-float-simd-minmax/src/Main.java @@ -23,7 +23,7 @@ public class Main { /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none /// CHECK-DAG: <<Get1:f\d+>> ArrayGet loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Get2:f\d+>> ArrayGet loop:<<Loop>> outer_loop:none - /// CHECK-DAG: <<Min:f\d+>> InvokeStaticOrDirect [<<Get1>>,<<Get2>>] intrinsic:MathMinFloatFloat loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Min:f\d+>> Min [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Min>>] loop:<<Loop>> outer_loop:none // // TODO x86: 0.0 vs -0.0? @@ -45,7 +45,7 @@ public class Main { /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none /// CHECK-DAG: <<Get1:f\d+>> ArrayGet loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Get2:f\d+>> ArrayGet loop:<<Loop>> outer_loop:none - /// CHECK-DAG: <<Max:f\d+>> InvokeStaticOrDirect [<<Get1>>,<<Get2>>] intrinsic:MathMaxFloatFloat loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Max:f\d+>> Max [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Max>>] loop:<<Loop>> outer_loop:none // // TODO x86: 0.0 vs -0.0? diff --git a/test/651-checker-int-simd-minmax/src/Main.java b/test/651-checker-int-simd-minmax/src/Main.java index cfa0ae7dca..82fad84d08 100644 --- a/test/651-checker-int-simd-minmax/src/Main.java +++ b/test/651-checker-int-simd-minmax/src/Main.java @@ -23,7 +23,7 @@ public class Main { /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none /// CHECK-DAG: <<Get1:i\d+>> ArrayGet loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Get2:i\d+>> ArrayGet loop:<<Loop>> outer_loop:none - /// CHECK-DAG: <<Min:i\d+>> InvokeStaticOrDirect [<<Get1>>,<<Get2>>] intrinsic:MathMinIntInt loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Min:i\d+>> Min [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Min>>] loop:<<Loop>> outer_loop:none // /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.doitMin(int[], int[], int[]) loop_optimization (after) @@ -42,7 +42,7 @@ public class Main { /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none /// CHECK-DAG: <<Get1:i\d+>> ArrayGet loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Get2:i\d+>> ArrayGet loop:<<Loop>> outer_loop:none - /// CHECK-DAG: <<Max:i\d+>> InvokeStaticOrDirect [<<Get1>>,<<Get2>>] intrinsic:MathMaxIntInt loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Max:i\d+>> Max [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Max>>] loop:<<Loop>> outer_loop:none // /// CHECK-START-{ARM,ARM64,MIPS64}: void Main.doitMax(int[], int[], int[]) loop_optimization (after) diff --git a/test/651-checker-long-simd-minmax/src/Main.java b/test/651-checker-long-simd-minmax/src/Main.java index 458cb8bf1b..f52686e54c 100644 --- a/test/651-checker-long-simd-minmax/src/Main.java +++ b/test/651-checker-long-simd-minmax/src/Main.java @@ -23,7 +23,7 @@ public class Main { /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none /// CHECK-DAG: <<Get1:j\d+>> ArrayGet loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Get2:j\d+>> ArrayGet loop:<<Loop>> outer_loop:none - /// CHECK-DAG: <<Min:j\d+>> InvokeStaticOrDirect [<<Get1>>,<<Get2>>] intrinsic:MathMinLongLong loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Min:j\d+>> Min [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Min>>] loop:<<Loop>> outer_loop:none // // Not directly supported for longs. @@ -48,7 +48,7 @@ public class Main { /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none /// CHECK-DAG: <<Get1:j\d+>> ArrayGet loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Get2:j\d+>> ArrayGet loop:<<Loop>> outer_loop:none - /// CHECK-DAG: <<Max:j\d+>> InvokeStaticOrDirect [<<Get1>>,<<Get2>>] intrinsic:MathMaxLongLong loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Max:j\d+>> Max [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Max>>] loop:<<Loop>> outer_loop:none // // Not directly supported for longs. diff --git a/test/651-checker-short-simd-minmax/src/Main.java b/test/651-checker-short-simd-minmax/src/Main.java index 5f10adab79..4300ca2951 100644 --- a/test/651-checker-short-simd-minmax/src/Main.java +++ b/test/651-checker-short-simd-minmax/src/Main.java @@ -23,7 +23,7 @@ public class Main { /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none /// CHECK-DAG: <<Get1:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Get2:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none - /// CHECK-DAG: <<Min:i\d+>> InvokeStaticOrDirect [<<Get1>>,<<Get2>>] intrinsic:MathMinIntInt loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Min:i\d+>> Min [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<Min>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none // @@ -54,7 +54,7 @@ public class Main { /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none /// CHECK-DAG: <<Get1:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Get2:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none - /// CHECK-DAG: <<Min:i\d+>> InvokeStaticOrDirect [<<Get1>>,<<Get2>>] intrinsic:MathMinIntInt loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Min:i\d+>> Min [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<Min>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none // @@ -74,7 +74,7 @@ public class Main { /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none /// CHECK-DAG: <<Get1:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Get2:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none - /// CHECK-DAG: <<Max:i\d+>> InvokeStaticOrDirect [<<Get1>>,<<Get2>>] intrinsic:MathMaxIntInt loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Max:i\d+>> Max [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<Max>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none // @@ -105,7 +105,7 @@ public class Main { /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none /// CHECK-DAG: <<Get1:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Get2:c\d+>> ArrayGet loop:<<Loop>> outer_loop:none - /// CHECK-DAG: <<Max:i\d+>> InvokeStaticOrDirect [<<Get1>>,<<Get2>>] intrinsic:MathMaxIntInt loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Max:i\d+>> Max [<<Get1>>,<<Get2>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<Max>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none // @@ -125,7 +125,7 @@ public class Main { /// CHECK-DAG: <<I100:i\d+>> IntConstant 100 loop:none /// CHECK-DAG: <<Phi:i\d+>> Phi loop:<<Loop:B\d+>> outer_loop:none /// CHECK-DAG: <<Get:s\d+>> ArrayGet loop:<<Loop>> outer_loop:none - /// CHECK-DAG: <<Min:i\d+>> InvokeStaticOrDirect [<<Get>>,<<I100>>] intrinsic:MathMinIntInt loop:<<Loop>> outer_loop:none + /// CHECK-DAG: <<Min:i\d+>> Min [<<Get>>,<<I100>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Cnv:s\d+>> TypeConversion [<<Min>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>> outer_loop:none // diff --git a/test/661-checker-simd-reduc/src/Main.java b/test/661-checker-simd-reduc/src/Main.java index 3a0a0495c4..fcd50a6d15 100644 --- a/test/661-checker-simd-reduc/src/Main.java +++ b/test/661-checker-simd-reduc/src/Main.java @@ -378,7 +378,7 @@ public class Main { /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<ConsM>>,{{i\d+}}] loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Get:i\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none - /// CHECK-DAG: InvokeStaticOrDirect [<<Phi2>>,<<Get>>] intrinsic:MathMinIntInt loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Min [<<Phi2>>,<<Get>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: Return [<<Phi2>>] loop:none // @@ -438,7 +438,7 @@ public class Main { /// CHECK-DAG: <<Phi1:i\d+>> Phi [<<Cons0>>,{{i\d+}}] loop:<<Loop:B\d+>> outer_loop:none /// CHECK-DAG: <<Phi2:i\d+>> Phi [<<ConsM>>,{{i\d+}}] loop:<<Loop>> outer_loop:none /// CHECK-DAG: <<Get:i\d+>> ArrayGet [{{l\d+}},<<Phi1>>] loop:<<Loop>> outer_loop:none - /// CHECK-DAG: InvokeStaticOrDirect [<<Phi2>>,<<Get>>] intrinsic:MathMaxIntInt loop:<<Loop>> outer_loop:none + /// CHECK-DAG: Max [<<Phi2>>,<<Get>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: Add [<<Phi1>>,<<Cons1>>] loop:<<Loop>> outer_loop:none /// CHECK-DAG: Return [<<Phi2>>] loop:none // diff --git a/test/988-method-trace/expected.txt b/test/988-method-trace/expected.txt index 574d5b0772..7f64e23a77 100644 --- a/test/988-method-trace/expected.txt +++ b/test/988-method-trace/expected.txt @@ -107,8 +107,8 @@ fibonacci(5)=5 ......=> public static char[] java.util.Arrays.copyOf(char[],int) .......=> public static int java.lang.Math.min(int,int) .......<= public static int java.lang.Math.min(int,int) -> <class java.lang.Integer: 16> -.......=> public static void java.lang.System.arraycopy(char[],int,char[],int,int) -.......<= public static void java.lang.System.arraycopy(char[],int,char[],int,int) -> <null: null> +.......=> public static void java.lang.System.arraycopy(java.lang.Object,int,java.lang.Object,int,int) +.......<= public static void java.lang.System.arraycopy(java.lang.Object,int,java.lang.Object,int,int) -> <null: null> ......<= public static char[] java.util.Arrays.copyOf(char[],int) -> <class [C: [B, a, d, , a, r, g, u, m, e, n, t, :, , -, 1, 9, , <, , 0, <control-0000>, <control-0000>, <control-0000>, <control-0000>, <control-0000>, <control-0000>, <control-0000>, <control-0000>, <control-0000>, <control-0000>, <control-0000>, <control-0000>, <control-0000>]> .....<= private void java.lang.AbstractStringBuilder.ensureCapacityInternal(int) -> <null: null> .....=> static void java.lang.Integer.getChars(int,int,char[]) @@ -208,8 +208,8 @@ fibonacci(-19) -> java.lang.Error: Bad argument: -19 < 0 ......=> public static char[] java.util.Arrays.copyOf(char[],int) .......=> public static int java.lang.Math.min(int,int) .......<= public static int java.lang.Math.min(int,int) -> <class java.lang.Integer: 16> -.......=> public static void java.lang.System.arraycopy(char[],int,char[],int,int) -.......<= public static void java.lang.System.arraycopy(char[],int,char[],int,int) -> <null: null> +.......=> public static void java.lang.System.arraycopy(java.lang.Object,int,java.lang.Object,int,int) +.......<= public static void java.lang.System.arraycopy(java.lang.Object,int,java.lang.Object,int,int) -> <null: null> ......<= public static char[] java.util.Arrays.copyOf(char[],int) -> <class [C: [B, a, d, , a, r, g, u, m, e, n, t, :, , -, 1, 9, , <, , 0, <control-0000>, <control-0000>, <control-0000>, <control-0000>, <control-0000>, <control-0000>, <control-0000>, <control-0000>, <control-0000>, <control-0000>, <control-0000>, <control-0000>, <control-0000>]> .....<= private void java.lang.AbstractStringBuilder.ensureCapacityInternal(int) -> <null: null> .....=> static void java.lang.Integer.getChars(int,int,char[]) diff --git a/test/988-method-trace/expected_jack.diff b/test/988-method-trace/expected_jack.diff deleted file mode 100644 index 11364a0539..0000000000 --- a/test/988-method-trace/expected_jack.diff +++ /dev/null @@ -1,10 +0,0 @@ -450,453c450,453 -< .=> public static void java.lang.System.arraycopy(java.lang.Object,int,java.lang.Object,int,int) -< .<= public static void java.lang.System.arraycopy(java.lang.Object,int,java.lang.Object,int,int) -> <null: null> -< .=> public static void java.lang.System.arraycopy(java.lang.Object,int,java.lang.Object,int,int) -< .<= public static void java.lang.System.arraycopy(java.lang.Object,int,java.lang.Object,int,int) -> <null: null> ---- -> .=> public static void java.lang.System.arraycopy(int[],int,int[],int,int) -> .<= public static void java.lang.System.arraycopy(int[],int,int[],int,int) -> <null: null> -> .=> public static void java.lang.System.arraycopy(char[],int,char[],int,int) -> .<= public static void java.lang.System.arraycopy(char[],int,char[],int,int) -> <null: null> diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar index 6444eb9a89..86adb733a9 100755 --- a/test/etc/run-test-jar +++ b/test/etc/run-test-jar @@ -775,9 +775,6 @@ if [ "$HOST" = "n" ]; then TMP_DIR_OPTION="-Djava.io.tmpdir=/data/local/tmp" fi -# We set DumpNativeStackOnSigQuit to false to avoid stressing libunwind. -# b/27185632 -# b/24664297 dalvikvm_cmdline="$INVOKE_WITH $GDB $ANDROID_ROOT/bin/$DALVIKVM \ $GDB_ARGS \ $FLAGS \ @@ -868,7 +865,12 @@ if [ "$HOST" = "n" ]; then fi # System libraries needed by libarttestd.so - PUBLIC_LIBS=libart.so:libartd.so:libc++.so:libbacktrace.so:libdexfile.so:libdexfiled.so:libbase.so:libnativehelper.so + PUBLIC_LIBS=libc++.so:libbacktrace.so:libbase.so:libnativehelper.so + if [ "$TEST_IS_NDEBUG" = "y" ]; then + PUBLIC_LIBS=$PUBLIC_LIBS:libart.so:libdexfile.so + else + PUBLIC_LIBS=$PUBLIC_LIBS:libartd.so:libdexfiled.so + fi # Create a script with the command. The command can get longer than the longest # allowed adb command and there is no way to get the exit status from a adb shell diff --git a/test/knownfailures.json b/test/knownfailures.json index 2bf09c3f82..5fb78191ef 100644 --- a/test/knownfailures.json +++ b/test/knownfailures.json @@ -504,6 +504,7 @@ { "tests": [ "031-class-attributes", + "715-clinit-implicit-parameter-annotations", "911-get-stack-trace" ], "description": [ diff --git a/test/testrunner/target_config.py b/test/testrunner/target_config.py index 9d0377510a..2c433af512 100644 --- a/test/testrunner/target_config.py +++ b/test/testrunner/target_config.py @@ -69,7 +69,13 @@ target_config = { } }, 'art-gcstress-gcverify': { - 'run-test': ['--gcstress', + # Don't include --interpreter, because it takes too long to run all + # the tests on the build bot (b/74225325) + 'run-test': ['--interp-ac', + '--jit', + '--optimizing', + '--speed-profile', + '--gcstress', '--gcverify'], 'env' : { 'ART_USE_READ_BARRIER' : 'false', diff --git a/test/ti-stress/stress.cc b/test/ti-stress/stress.cc index d2da244397..bbe74656dd 100644 --- a/test/ti-stress/stress.cc +++ b/test/ti-stress/stress.cc @@ -24,9 +24,9 @@ #include <jni.h> +#include "base/utils.h" #include "exec_utils.h" #include "jvmti.h" -#include "utils.h" #pragma clang diagnostic push diff --git a/tools/external_oj_libjdwp_art_failures.txt b/tools/external_oj_libjdwp_art_failures.txt index 6c2206fe46..9b6ff984f8 100644 --- a/tools/external_oj_libjdwp_art_failures.txt +++ b/tools/external_oj_libjdwp_art_failures.txt @@ -13,12 +13,6 @@ name: "org.apache.harmony.jpda.tests.jdwp.ThreadReference.ThreadGroup002Test#testThreadGroup002" }, { - description: "Test fails due to modifiers not including ACC_SUPER", - result: EXEC_FAILED, - bug: 66906055, - name: "org.apache.harmony.jpda.tests.jdwp.ReferenceType.ModifiersTest#testModifiers001" -}, -{ description: "Test fails due to static values not being set correctly.", result: EXEC_FAILED, bug: 66905894, diff --git a/tools/hiddenapi/hiddenapi.cc b/tools/hiddenapi/hiddenapi.cc index d986cf82d6..d22998ae1b 100644 --- a/tools/hiddenapi/hiddenapi.cc +++ b/tools/hiddenapi/hiddenapi.cc @@ -21,12 +21,12 @@ #include "android-base/stringprintf.h" #include "android-base/strings.h" +#include "base/os.h" #include "base/unix_file/fd_file.h" #include "dex/art_dex_file_loader.h" #include "dex/dex_file-inl.h" #include "dex/hidden_api_access_flags.h" #include "mem_map.h" -#include "os.h" namespace art { |