diff options
author | Vladimir Marko <vmarko@google.com> | 2015-05-19 18:08:00 +0100 |
---|---|---|
committer | Vladimir Marko <vmarko@google.com> | 2015-05-26 19:33:33 +0100 |
commit | 41b175aba41c9365a1c53b8a1afbd17129c87c14 (patch) | |
tree | 5c82606d39543fb932ddc0674694fc0758b1a866 | |
parent | 54d65738eecc1fa79ed528ff2f6b9b4f7a4743be (diff) | |
download | art-41b175aba41c9365a1c53b8a1afbd17129c87c14.zip art-41b175aba41c9365a1c53b8a1afbd17129c87c14.tar.gz art-41b175aba41c9365a1c53b8a1afbd17129c87c14.tar.bz2 |
ART: Clean up arm64 kNumberOfXRegisters usage.
Avoid undefined behavior for arm64 stemming from 1u << 32 in
loops with upper bound kNumberOfXRegisters.
Create iterators for enumerating bits in an integer either
from high to low or from low to high and use them for
<arch>Context::FillCalleeSaves() on all architectures.
Refactor runtime/utils.{h,cc} by moving all bit-fiddling
functions to runtime/base/bit_utils.{h,cc} (together with
the new bit iterators) and all time-related functions to
runtime/base/time_utils.{h,cc}. Improve test coverage and
fix some corner cases for the bit-fiddling functions.
Bug: 13925192
(cherry picked from commit 80afd02024d20e60b197d3adfbb43cc303cf29e0)
Change-Id: I905257a21de90b5860ebe1e39563758f721eab82
161 files changed, 1432 insertions, 893 deletions
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index bfc8956..ccea540 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -124,6 +124,7 @@ RUNTIME_GTEST_COMMON_SRC_FILES := \ runtime/arch/x86_64/instruction_set_features_x86_64_test.cc \ runtime/barrier_test.cc \ runtime/base/bit_field_test.cc \ + runtime/base/bit_utils_test.cc \ runtime/base/bit_vector_test.cc \ runtime/base/hash_set_test.cc \ runtime/base/hex_dump_test.cc \ @@ -131,6 +132,7 @@ RUNTIME_GTEST_COMMON_SRC_FILES := \ runtime/base/mutex_test.cc \ runtime/base/scoped_flock_test.cc \ runtime/base/stringprintf_test.cc \ + runtime/base/time_utils_test.cc \ runtime/base/timing_logger_test.cc \ runtime/base/variant_map_test.cc \ runtime/base/unix_file/fd_file_test.cc \ diff --git a/cmdline/cmdline_parser.h b/cmdline/cmdline_parser.h index e4af4f9..cebba65 100644 --- a/cmdline/cmdline_parser.h +++ b/cmdline/cmdline_parser.h @@ -30,7 +30,6 @@ #include "cmdline_parse_result.h" #include "runtime/base/variant_map.h" -#include "utils.h" #include <vector> #include <memory> diff --git a/cmdline/cmdline_types.h b/cmdline/cmdline_types.h index 03165ed..f38478c 100644 --- a/cmdline/cmdline_types.h +++ b/cmdline/cmdline_types.h @@ -27,6 +27,7 @@ #include "unit.h" #include "jdwp/jdwp.h" #include "runtime/base/logging.h" +#include "runtime/base/time_utils.h" #include "gc/collector_type.h" #include "gc/space/large_object_space.h" #include "profiler_options.h" diff --git a/cmdline/memory_representation.h b/cmdline/memory_representation.h index 93387de..2619c31 100644 --- a/cmdline/memory_representation.h +++ b/cmdline/memory_representation.h @@ -20,24 +20,25 @@ #include <string> #include <assert.h> #include <ostream> -#include "utils.h" + +#include "base/bit_utils.h" namespace art { // An integral representation of bytes of memory. // The underlying runtime size_t value is guaranteed to be a multiple of Divisor. -template <size_t Divisor = 1024> +template <size_t kDivisor = 1024> struct Memory { - static_assert(IsPowerOfTwo(Divisor), "Divisor must be a power of 2"); + static_assert(IsPowerOfTwo(kDivisor), "Divisor must be a power of 2"); - static Memory<Divisor> FromBytes(size_t bytes) { - assert(bytes % Divisor == 0); - return Memory<Divisor>(bytes); + static Memory<kDivisor> FromBytes(size_t bytes) { + assert(bytes % kDivisor == 0); + return Memory<kDivisor>(bytes); } Memory() : Value(0u) {} Memory(size_t value) : Value(value) { // NOLINT [runtime/explicit] [5] - assert(value % Divisor == 0); + assert(value % kDivisor == 0); } operator size_t() const { return Value; } @@ -45,12 +46,10 @@ struct Memory { return Value; } - static constexpr size_t kDivisor = Divisor; - static const char* Name() { static std::string str; if (str.empty()) { - str = "Memory<" + std::to_string(Divisor) + '>'; + str = "Memory<" + std::to_string(kDivisor) + '>'; } return str.c_str(); @@ -59,9 +58,9 @@ struct Memory { size_t Value; }; -template <size_t Divisor> -std::ostream& operator<<(std::ostream& stream, Memory<Divisor> memory) { - return stream << memory.Value << '*' << Divisor; +template <size_t kDivisor> +std::ostream& operator<<(std::ostream& stream, Memory<kDivisor> memory) { + return stream << memory.Value << '*' << kDivisor; } using MemoryKiB = Memory<1024>; diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h index 480d021..45a62bc 100644 --- a/compiler/compiled_method.h +++ b/compiler/compiled_method.h @@ -22,8 +22,8 @@ #include <vector> #include "arch/instruction_set.h" +#include "base/bit_utils.h" #include "method_reference.h" -#include "utils.h" #include "utils/array_ref.h" #include "utils/swap_space.h" diff --git a/compiler/compiler.cc b/compiler/compiler.cc index 5e8ec1e..223affa 100644 --- a/compiler/compiler.cc +++ b/compiler/compiler.cc @@ -20,6 +20,7 @@ #include "dex/quick/quick_compiler_factory.h" #include "driver/compiler_driver.h" #include "optimizing/optimizing_compiler.h" +#include "utils.h" namespace art { diff --git a/compiler/dex/compiler_ir.cc b/compiler/dex/compiler_ir.cc index 7fc1b03..6e1853b 100644 --- a/compiler/dex/compiler_ir.cc +++ b/compiler/dex/compiler_ir.cc @@ -22,6 +22,7 @@ #include "dex/quick/mir_to_lir.h" #include "driver/compiler_driver.h" #include "mir_graph.h" +#include "utils.h" namespace art { diff --git a/compiler/dex/compiler_ir.h b/compiler/dex/compiler_ir.h index dceea24..d28df1d 100644 --- a/compiler/dex/compiler_ir.h +++ b/compiler/dex/compiler_ir.h @@ -21,6 +21,7 @@ #include <string> #include <vector> +#include "arch/instruction_set.h" #include "base/arena_allocator.h" #include "base/scoped_arena_allocator.h" #include "base/timing_logger.h" @@ -31,6 +32,7 @@ namespace art { class ClassLinker; class CompilerDriver; +class DexFile; class Mir2Lir; class MIRGraph; diff --git a/compiler/dex/local_value_numbering.cc b/compiler/dex/local_value_numbering.cc index cc9dbe4..38f7d1e 100644 --- a/compiler/dex/local_value_numbering.cc +++ b/compiler/dex/local_value_numbering.cc @@ -16,9 +16,11 @@ #include "local_value_numbering.h" +#include "base/bit_utils.h" #include "global_value_numbering.h" #include "mir_field_info.h" #include "mir_graph.h" +#include "utils.h" namespace art { diff --git a/compiler/dex/local_value_numbering.h b/compiler/dex/local_value_numbering.h index 67fb647..dff5e27 100644 --- a/compiler/dex/local_value_numbering.h +++ b/compiler/dex/local_value_numbering.h @@ -106,8 +106,7 @@ class LocalValueNumbering : public DeletableArenaObject<kArenaAllocMisc> { } void SetOperandValueImpl(uint16_t s_reg, uint16_t value, SregValueMap* map) { - DCHECK_EQ(map->count(s_reg), 0u) << PrettyMethod(gvn_->cu_->method_idx, *gvn_->cu_->dex_file) - << " LVN id: " << id_ << ", s_reg: " << s_reg; + DCHECK_EQ(map->count(s_reg), 0u); map->Put(s_reg, value); } diff --git a/compiler/dex/mir_analysis.cc b/compiler/dex/mir_analysis.cc index 9099e8a..1cff8dc 100644 --- a/compiler/dex/mir_analysis.cc +++ b/compiler/dex/mir_analysis.cc @@ -30,6 +30,7 @@ #include "driver/compiler_driver.h" #include "driver/compiler_options.h" #include "driver/dex_compilation_unit.h" +#include "utils.h" namespace art { diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc index 1871f07..9fa5148 100644 --- a/compiler/dex/mir_graph.cc +++ b/compiler/dex/mir_graph.cc @@ -35,6 +35,7 @@ #include "leb128.h" #include "pass_driver_me_post_opt.h" #include "stack.h" +#include "utils.h" namespace art { diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h index 7385a8b..f038397 100644 --- a/compiler/dex/mir_graph.h +++ b/compiler/dex/mir_graph.h @@ -20,6 +20,7 @@ #include <stdint.h> #include "base/arena_containers.h" +#include "base/bit_utils.h" #include "base/scoped_arena_containers.h" #include "dex_file.h" #include "dex_instruction.h" diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc index 217dbee..7679db8 100644 --- a/compiler/dex/mir_optimization.cc +++ b/compiler/dex/mir_optimization.cc @@ -31,6 +31,7 @@ #include "quick/dex_file_to_method_inliner_map.h" #include "stack.h" #include "type_inference.h" +#include "utils.h" namespace art { diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc index 2b2d6af..822ea21 100644 --- a/compiler/dex/quick/arm/call_arm.cc +++ b/compiler/dex/quick/arm/call_arm.cc @@ -19,6 +19,7 @@ #include "codegen_arm.h" #include "arm_lir.h" +#include "base/bit_utils.h" #include "base/logging.h" #include "dex/mir_graph.h" #include "dex/quick/dex_file_to_method_inliner_map.h" @@ -29,7 +30,6 @@ #include "mirror/art_method.h" #include "mirror/object_array-inl.h" #include "entrypoints/quick/quick_entrypoints.h" -#include "utils.h" #include "utils/dex_cache_arrays_layout-inl.h" namespace art { diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc index 7598e50..7de8e55 100644 --- a/compiler/dex/quick/arm/int_arm.cc +++ b/compiler/dex/quick/arm/int_arm.cc @@ -20,6 +20,7 @@ #include "arch/instruction_set_features.h" #include "arm_lir.h" +#include "base/bit_utils.h" #include "base/logging.h" #include "dex/compiler_ir.h" #include "dex/mir_graph.h" @@ -28,7 +29,6 @@ #include "driver/compiler_driver.h" #include "entrypoints/quick/quick_entrypoints.h" #include "mirror/array-inl.h" -#include "utils.h" namespace art { diff --git a/compiler/dex/quick/arm64/fp_arm64.cc b/compiler/dex/quick/arm64/fp_arm64.cc index 49b15fe..3b88021 100644 --- a/compiler/dex/quick/arm64/fp_arm64.cc +++ b/compiler/dex/quick/arm64/fp_arm64.cc @@ -20,7 +20,6 @@ #include "base/logging.h" #include "dex/mir_graph.h" #include "dex/quick/mir_to_lir-inl.h" -#include "utils.h" namespace art { diff --git a/compiler/dex/quick/arm64/int_arm64.cc b/compiler/dex/quick/arm64/int_arm64.cc index 9340d01..08aa5d2 100644 --- a/compiler/dex/quick/arm64/int_arm64.cc +++ b/compiler/dex/quick/arm64/int_arm64.cc @@ -20,6 +20,7 @@ #include "arch/instruction_set_features.h" #include "arm64_lir.h" +#include "base/bit_utils.h" #include "base/logging.h" #include "dex/compiler_ir.h" #include "dex/mir_graph.h" @@ -28,7 +29,6 @@ #include "driver/compiler_driver.h" #include "entrypoints/quick/quick_entrypoints.h" #include "mirror/array-inl.h" -#include "utils.h" namespace art { diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc index 0592c74..63f83f9 100644 --- a/compiler/dex/quick/gen_common.cc +++ b/compiler/dex/quick/gen_common.cc @@ -19,6 +19,7 @@ #include <functional> #include "arch/arm/instruction_set_features_arm.h" +#include "base/bit_utils.h" #include "base/macros.h" #include "dex/compiler_ir.h" #include "dex/mir_graph.h" @@ -30,7 +31,6 @@ #include "mirror/object_array-inl.h" #include "mirror/object-inl.h" #include "mirror/object_reference.h" -#include "utils.h" #include "utils/dex_cache_arrays_layout-inl.h" #include "verifier/method_verifier.h" diff --git a/compiler/dex/quick/mir_to_lir-inl.h b/compiler/dex/quick/mir_to_lir-inl.h index 280dbbe..767fe25 100644 --- a/compiler/dex/quick/mir_to_lir-inl.h +++ b/compiler/dex/quick/mir_to_lir-inl.h @@ -21,6 +21,7 @@ #include "base/logging.h" #include "dex/compiler_ir.h" +#include "utils.h" namespace art { diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h index 4fdc728..d54616f 100644 --- a/compiler/dex/quick/mir_to_lir.h +++ b/compiler/dex/quick/mir_to_lir.h @@ -31,6 +31,7 @@ #include "invoke_type.h" #include "lazy_debug_frame_opcode_writer.h" #include "leb128.h" +#include "primitive.h" #include "safe_map.h" #include "utils/array_ref.h" #include "utils/dex_cache_arrays_layout.h" diff --git a/compiler/dex/quick/resource_mask.cc b/compiler/dex/quick/resource_mask.cc index 57e8af3..817a69a 100644 --- a/compiler/dex/quick/resource_mask.cc +++ b/compiler/dex/quick/resource_mask.cc @@ -18,9 +18,9 @@ #include "resource_mask.h" +#include "base/bit_utils.h" #include "base/arena_allocator.h" #include "base/logging.h" -#include "utils.h" namespace art { diff --git a/compiler/dex/quick/x86/assemble_x86.cc b/compiler/dex/quick/x86/assemble_x86.cc index 8467b71..12523ac 100644 --- a/compiler/dex/quick/x86/assemble_x86.cc +++ b/compiler/dex/quick/x86/assemble_x86.cc @@ -16,10 +16,12 @@ #include "codegen_x86.h" +#include "base/bit_utils.h" #include "base/logging.h" #include "dex/compiler_ir.h" #include "dex/quick/mir_to_lir.h" #include "oat.h" +#include "utils.h" #include "x86_lir.h" namespace art { diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc index 943bfc0..9bbb5f8 100755 --- a/compiler/dex/quick/x86/int_x86.cc +++ b/compiler/dex/quick/x86/int_x86.cc @@ -18,12 +18,12 @@ #include "codegen_x86.h" +#include "base/bit_utils.h" #include "base/logging.h" #include "dex/quick/mir_to_lir-inl.h" #include "dex/reg_storage_eq.h" #include "mirror/art_method.h" #include "mirror/array-inl.h" -#include "utils.h" #include "x86_lir.h" namespace art { diff --git a/compiler/dex/type_inference.cc b/compiler/dex/type_inference.cc index 19d591b..cd6467f 100644 --- a/compiler/dex/type_inference.cc +++ b/compiler/dex/type_inference.cc @@ -25,6 +25,7 @@ #include "mir_field_info.h" #include "mir_graph.h" #include "mir_method_info.h" +#include "utils.h" namespace art { diff --git a/compiler/dex/type_inference.h b/compiler/dex/type_inference.h index c9b29bf..85f79af 100644 --- a/compiler/dex/type_inference.h +++ b/compiler/dex/type_inference.h @@ -17,6 +17,7 @@ #ifndef ART_COMPILER_DEX_TYPE_INFERENCE_H_ #define ART_COMPILER_DEX_TYPE_INFERENCE_H_ +#include "base/bit_utils.h" #include "base/logging.h" #include "base/arena_object.h" #include "base/scoped_arena_containers.h" diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index 47288b5..7cc5aae 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -29,6 +29,7 @@ #include "art_field-inl.h" #include "base/stl_util.h" +#include "base/time_utils.h" #include "base/timing_logger.h" #include "class_linker-inl.h" #include "compiled_class.h" diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h index 2b0985a..2cc2409 100644 --- a/compiler/driver/compiler_driver.h +++ b/compiler/driver/compiler_driver.h @@ -24,6 +24,7 @@ #include "arch/instruction_set.h" #include "base/arena_allocator.h" +#include "base/bit_utils.h" #include "base/mutex.h" #include "base/timing_logger.h" #include "class_reference.h" @@ -41,7 +42,6 @@ #include "utils/dedupe_set.h" #include "utils/dex_cache_arrays_layout.h" #include "utils/swap_space.h" -#include "utils.h" namespace art { diff --git a/compiler/dwarf/debug_frame_opcode_writer.h b/compiler/dwarf/debug_frame_opcode_writer.h index 4112c84..d8077d5 100644 --- a/compiler/dwarf/debug_frame_opcode_writer.h +++ b/compiler/dwarf/debug_frame_opcode_writer.h @@ -17,10 +17,10 @@ #ifndef ART_COMPILER_DWARF_DEBUG_FRAME_OPCODE_WRITER_H_ #define ART_COMPILER_DWARF_DEBUG_FRAME_OPCODE_WRITER_H_ +#include "base/bit_utils.h" #include "dwarf/dwarf_constants.h" #include "dwarf/register.h" #include "dwarf/writer.h" -#include "utils.h" namespace art { namespace dwarf { diff --git a/compiler/dwarf/dwarf_test.h b/compiler/dwarf/dwarf_test.h index 230ebe3..370c744 100644 --- a/compiler/dwarf/dwarf_test.h +++ b/compiler/dwarf/dwarf_test.h @@ -25,7 +25,6 @@ #include <string> #include <sys/types.h> -#include "utils.h" #include "base/unix_file/fd_file.h" #include "common_runtime_test.h" #include "elf_builder.h" diff --git a/compiler/dwarf/writer.h b/compiler/dwarf/writer.h index 3b9c558..e703aee 100644 --- a/compiler/dwarf/writer.h +++ b/compiler/dwarf/writer.h @@ -18,9 +18,9 @@ #define ART_COMPILER_DWARF_WRITER_H_ #include <vector> -#include "leb128.h" +#include "base/bit_utils.h" #include "base/logging.h" -#include "utils.h" +#include "leb128.h" namespace art { namespace dwarf { diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h index 63d3a0d..2c68bb8 100644 --- a/compiler/elf_builder.h +++ b/compiler/elf_builder.h @@ -20,6 +20,7 @@ #include <vector> #include "arch/instruction_set.h" +#include "base/bit_utils.h" #include "base/unix_file/fd_file.h" #include "buffered_output_stream.h" #include "elf_utils.h" diff --git a/compiler/elf_writer_debug.cc b/compiler/elf_writer_debug.cc index 5e9cf76..dbbe82e 100644 --- a/compiler/elf_writer_debug.cc +++ b/compiler/elf_writer_debug.cc @@ -25,6 +25,7 @@ #include "dwarf/headers.h" #include "dwarf/register.h" #include "oat_writer.h" +#include "utils.h" namespace art { namespace dwarf { diff --git a/compiler/gc_map_builder.h b/compiler/gc_map_builder.h index 4c36ef7..45e3fc5 100644 --- a/compiler/gc_map_builder.h +++ b/compiler/gc_map_builder.h @@ -19,8 +19,8 @@ #include <vector> +#include "base/bit_utils.h" #include "gc_map.h" -#include "utils.h" namespace art { diff --git a/compiler/image_writer.h b/compiler/image_writer.h index c0cffa5..5921732 100644 --- a/compiler/image_writer.h +++ b/compiler/image_writer.h @@ -26,6 +26,7 @@ #include <string> #include <ostream> +#include "base/bit_utils.h" #include "base/macros.h" #include "driver/compiler_driver.h" #include "gc/space/space.h" @@ -35,7 +36,6 @@ #include "os.h" #include "safe_map.h" #include "gc/space/space.h" -#include "utils.h" namespace art { @@ -136,7 +136,7 @@ class ImageWriter FINAL { friend std::ostream& operator<<(std::ostream& stream, const Bin& bin); - static constexpr size_t kBinBits = MinimumBitsToStore(kBinMirrorCount - 1); + static constexpr size_t kBinBits = MinimumBitsToStore<uint32_t>(kBinMirrorCount - 1); // uint32 = typeof(lockword_) static constexpr size_t kBinShift = BitSizeOf<uint32_t>() - kBinBits; // 111000.....0 diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc index 7c400ee..7ed7097 100644 --- a/compiler/jit/jit_compiler.cc +++ b/compiler/jit/jit_compiler.cc @@ -18,6 +18,7 @@ #include "arch/instruction_set.h" #include "arch/instruction_set_features.h" +#include "base/time_utils.h" #include "base/timing_logger.h" #include "compiler_callbacks.h" #include "dex/pass_manager.h" diff --git a/compiler/jni/quick/arm64/calling_convention_arm64.cc b/compiler/jni/quick/arm64/calling_convention_arm64.cc index a6caff1..4344c90 100644 --- a/compiler/jni/quick/arm64/calling_convention_arm64.cc +++ b/compiler/jni/quick/arm64/calling_convention_arm64.cc @@ -158,7 +158,8 @@ Arm64JniCallingConvention::Arm64JniCallingConvention(bool is_static, bool is_syn const char* shorty) : JniCallingConvention(is_static, is_synchronized, shorty, kFramePointerSize) { uint32_t core_spill_mask = CoreSpillMask(); - for (int x_reg = 0; x_reg < kNumberOfXRegisters; ++x_reg) { + DCHECK_EQ(XZR, kNumberOfXRegisters - 1); // Exclude XZR from the loop (avoid 1 << 32). + for (int x_reg = 0; x_reg < kNumberOfXRegisters - 1; ++x_reg) { if (((1 << x_reg) & core_spill_mask) != 0) { callee_save_regs_.push_back( Arm64ManagedRegister::FromXRegister(static_cast<XRegister>(x_reg))); diff --git a/compiler/jni/quick/calling_convention.cc b/compiler/jni/quick/calling_convention.cc index 436fc0c..2e146c4 100644 --- a/compiler/jni/quick/calling_convention.cc +++ b/compiler/jni/quick/calling_convention.cc @@ -23,7 +23,6 @@ #include "jni/quick/mips64/calling_convention_mips64.h" #include "jni/quick/x86/calling_convention_x86.h" #include "jni/quick/x86_64/calling_convention_x86_64.h" -#include "utils.h" namespace art { diff --git a/compiler/jni/quick/x86/calling_convention_x86.cc b/compiler/jni/quick/x86/calling_convention_x86.cc index 8a45f0c..499dd7c 100644 --- a/compiler/jni/quick/x86/calling_convention_x86.cc +++ b/compiler/jni/quick/x86/calling_convention_x86.cc @@ -19,7 +19,6 @@ #include "base/logging.h" #include "handle_scope-inl.h" #include "utils/x86/managed_register_x86.h" -#include "utils.h" namespace art { namespace x86 { diff --git a/compiler/jni/quick/x86_64/calling_convention_x86_64.cc b/compiler/jni/quick/x86_64/calling_convention_x86_64.cc index bbdf1fe..7e92d12 100644 --- a/compiler/jni/quick/x86_64/calling_convention_x86_64.cc +++ b/compiler/jni/quick/x86_64/calling_convention_x86_64.cc @@ -16,10 +16,10 @@ #include "calling_convention_x86_64.h" +#include "base/bit_utils.h" #include "base/logging.h" #include "handle_scope-inl.h" #include "utils/x86_64/managed_register_x86_64.h" -#include "utils.h" namespace art { namespace x86_64 { diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index f56e446..13775fe 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -493,11 +493,6 @@ InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGene assembler_(codegen->GetAssembler()), codegen_(codegen) {} -static uint32_t LeastSignificantBit(uint32_t mask) { - // ffs starts at 1. - return ffs(mask) - 1; -} - void CodeGeneratorARM::ComputeSpillMask() { core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_; // Save one extra register for baseline. Note that on thumb2, there is no easy diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc index 43fe374..9e18f11 100644 --- a/compiler/optimizing/intrinsics.cc +++ b/compiler/optimizing/intrinsics.cc @@ -22,6 +22,7 @@ #include "invoke_type.h" #include "nodes.h" #include "quick/inline_method_analyser.h" +#include "utils.h" namespace art { diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index 41adc72..2bad682 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -18,6 +18,7 @@ #include "ssa_builder.h" #include "base/bit_vector-inl.h" +#include "base/bit_utils.h" #include "utils/growable_array.h" #include "scoped_thread_state_change.h" diff --git a/compiler/optimizing/parallel_move_resolver.h b/compiler/optimizing/parallel_move_resolver.h index e89417d..9ede910 100644 --- a/compiler/optimizing/parallel_move_resolver.h +++ b/compiler/optimizing/parallel_move_resolver.h @@ -20,6 +20,7 @@ #include "base/value_object.h" #include "utils/growable_array.h" #include "locations.h" +#include "primitive.h" namespace art { diff --git a/compiler/optimizing/register_allocator.h b/compiler/optimizing/register_allocator.h index dc9c708..97bd777 100644 --- a/compiler/optimizing/register_allocator.h +++ b/compiler/optimizing/register_allocator.h @@ -17,6 +17,7 @@ #ifndef ART_COMPILER_OPTIMIZING_REGISTER_ALLOCATOR_H_ #define ART_COMPILER_OPTIMIZING_REGISTER_ALLOCATOR_H_ +#include "arch/instruction_set.h" #include "base/macros.h" #include "primitive.h" #include "utils/growable_array.h" diff --git a/compiler/utils/arm/assembler_arm.cc b/compiler/utils/arm/assembler_arm.cc index c410660..1da0563 100644 --- a/compiler/utils/arm/assembler_arm.cc +++ b/compiler/utils/arm/assembler_arm.cc @@ -16,11 +16,11 @@ #include "assembler_arm.h" +#include "base/bit_utils.h" #include "base/logging.h" #include "entrypoints/quick/quick_entrypoints.h" #include "offsets.h" #include "thread.h" -#include "utils.h" namespace art { namespace arm { diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h index 313f365..ce4c741 100644 --- a/compiler/utils/arm/assembler_arm.h +++ b/compiler/utils/arm/assembler_arm.h @@ -19,13 +19,13 @@ #include <vector> +#include "base/bit_utils.h" #include "base/logging.h" #include "base/value_object.h" #include "constants_arm.h" #include "utils/arm/managed_register_arm.h" #include "utils/assembler.h" #include "offsets.h" -#include "utils.h" namespace art { namespace arm { diff --git a/compiler/utils/arm/assembler_arm32.cc b/compiler/utils/arm/assembler_arm32.cc index 9579691..1c8ea42 100644 --- a/compiler/utils/arm/assembler_arm32.cc +++ b/compiler/utils/arm/assembler_arm32.cc @@ -16,11 +16,11 @@ #include "assembler_arm32.h" +#include "base/bit_utils.h" #include "base/logging.h" #include "entrypoints/quick/quick_entrypoints.h" #include "offsets.h" #include "thread.h" -#include "utils.h" namespace art { namespace arm { diff --git a/compiler/utils/arm/assembler_arm32.h b/compiler/utils/arm/assembler_arm32.h index b922d66..80582e5 100644 --- a/compiler/utils/arm/assembler_arm32.h +++ b/compiler/utils/arm/assembler_arm32.h @@ -24,7 +24,6 @@ #include "utils/arm/managed_register_arm.h" #include "utils/arm/assembler_arm.h" #include "offsets.h" -#include "utils.h" namespace art { namespace arm { diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc index 3b42f63..85f6670 100644 --- a/compiler/utils/arm/assembler_thumb2.cc +++ b/compiler/utils/arm/assembler_thumb2.cc @@ -16,11 +16,11 @@ #include "assembler_thumb2.h" +#include "base/bit_utils.h" #include "base/logging.h" #include "entrypoints/quick/quick_entrypoints.h" #include "offsets.h" #include "thread.h" -#include "utils.h" namespace art { namespace arm { diff --git a/compiler/utils/arm/assembler_thumb2.h b/compiler/utils/arm/assembler_thumb2.h index e33c240..05caeb3 100644 --- a/compiler/utils/arm/assembler_thumb2.h +++ b/compiler/utils/arm/assembler_thumb2.h @@ -24,7 +24,6 @@ #include "utils/arm/managed_register_arm.h" #include "utils/arm/assembler_arm.h" #include "offsets.h" -#include "utils.h" namespace art { namespace arm { diff --git a/compiler/utils/arm64/assembler_arm64.cc b/compiler/utils/arm64/assembler_arm64.cc index 98702a2..3ee79a1 100644 --- a/compiler/utils/arm64/assembler_arm64.cc +++ b/compiler/utils/arm64/assembler_arm64.cc @@ -19,7 +19,6 @@ #include "entrypoints/quick/quick_entrypoints.h" #include "offsets.h" #include "thread.h" -#include "utils.h" using namespace vixl; // NOLINT(build/namespaces) diff --git a/compiler/utils/arm64/assembler_arm64.h b/compiler/utils/arm64/assembler_arm64.h index e47b531..b1b66ed 100644 --- a/compiler/utils/arm64/assembler_arm64.h +++ b/compiler/utils/arm64/assembler_arm64.h @@ -26,7 +26,6 @@ #include "utils/arm64/managed_register_arm64.h" #include "utils/assembler.h" #include "offsets.h" -#include "utils.h" // TODO: make vixl clean wrt -Wshadow. #pragma GCC diagnostic push diff --git a/compiler/utils/arm64/managed_register_arm64.h b/compiler/utils/arm64/managed_register_arm64.h index 62c1d4d..dbcd8c5 100644 --- a/compiler/utils/arm64/managed_register_arm64.h +++ b/compiler/utils/arm64/managed_register_arm64.h @@ -117,8 +117,7 @@ class Arm64ManagedRegister : public ManagedRegister { bool IsSRegister() const { CHECK(IsValidManagedRegister()); - const int test = id_ - (kNumberOfXRegIds + kNumberOfWRegIds + - kNumberOfDRegIds); + const int test = id_ - (kNumberOfXRegIds + kNumberOfWRegIds + kNumberOfDRegIds); return (0 <= test) && (test < kNumberOfSRegIds); } diff --git a/compiler/utils/assembler_test_base.h b/compiler/utils/assembler_test_base.h index 3341151..574051a 100644 --- a/compiler/utils/assembler_test_base.h +++ b/compiler/utils/assembler_test_base.h @@ -17,14 +17,15 @@ #ifndef ART_COMPILER_UTILS_ASSEMBLER_TEST_BASE_H_ #define ART_COMPILER_UTILS_ASSEMBLER_TEST_BASE_H_ -#include "common_runtime_test.h" // For ScratchFile - #include <cstdio> #include <cstdlib> #include <fstream> #include <iterator> #include <sys/stat.h> +#include "common_runtime_test.h" // For ScratchFile +#include "utils.h" + namespace art { // If you want to take a look at the differences between the ART assembler and GCC, set this flag diff --git a/compiler/utils/dedupe_set.h b/compiler/utils/dedupe_set.h index a9a5781..8cdb180 100644 --- a/compiler/utils/dedupe_set.h +++ b/compiler/utils/dedupe_set.h @@ -26,6 +26,7 @@ #include "base/mutex.h" #include "base/stl_util.h" #include "base/stringprintf.h" +#include "base/time_utils.h" #include "utils/swap_space.h" namespace art { diff --git a/compiler/utils/dex_cache_arrays_layout-inl.h b/compiler/utils/dex_cache_arrays_layout-inl.h index 2c50c96..a71eece 100644 --- a/compiler/utils/dex_cache_arrays_layout-inl.h +++ b/compiler/utils/dex_cache_arrays_layout-inl.h @@ -19,11 +19,11 @@ #include "dex_cache_arrays_layout.h" +#include "base/bit_utils.h" #include "base/logging.h" #include "globals.h" #include "mirror/array-inl.h" #include "primitive.h" -#include "utils.h" namespace mirror { class ArtMethod; diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc index 709a911..e769489 100644 --- a/compiler/utils/mips/assembler_mips.cc +++ b/compiler/utils/mips/assembler_mips.cc @@ -16,6 +16,7 @@ #include "assembler_mips.h" +#include "base/bit_utils.h" #include "base/casts.h" #include "entrypoints/quick/quick_entrypoints.h" #include "memory_region.h" diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h index d4acf03..34713e1 100644 --- a/compiler/utils/mips/assembler_mips.h +++ b/compiler/utils/mips/assembler_mips.h @@ -25,7 +25,6 @@ #include "managed_register_mips.h" #include "utils/assembler.h" #include "offsets.h" -#include "utils.h" namespace art { namespace mips { diff --git a/compiler/utils/mips64/assembler_mips64.cc b/compiler/utils/mips64/assembler_mips64.cc index 5e9653d..b95e436 100644 --- a/compiler/utils/mips64/assembler_mips64.cc +++ b/compiler/utils/mips64/assembler_mips64.cc @@ -16,6 +16,7 @@ #include "assembler_mips64.h" +#include "base/bit_utils.h" #include "base/casts.h" #include "entrypoints/quick/quick_entrypoints.h" #include "memory_region.h" @@ -116,7 +117,7 @@ void Mips64Assembler::EmitJump(Label* label, bool link) { int32_t Mips64Assembler::EncodeBranchOffset(int offset, int32_t inst, bool is_jump) { CHECK_ALIGNED(offset, 4); - CHECK(IsInt(POPCOUNT(kBranchOffsetMask), offset)) << offset; + CHECK(IsInt<POPCOUNT(kBranchOffsetMask)>(offset)) << offset; // Properly preserve only the bits supported in the instruction. offset >>= 2; diff --git a/compiler/utils/mips64/assembler_mips64.h b/compiler/utils/mips64/assembler_mips64.h index 2d7c661..95ba967 100644 --- a/compiler/utils/mips64/assembler_mips64.h +++ b/compiler/utils/mips64/assembler_mips64.h @@ -25,7 +25,6 @@ #include "managed_register_mips64.h" #include "utils/assembler.h" #include "offsets.h" -#include "utils.h" namespace art { namespace mips64 { diff --git a/compiler/utils/swap_space.h b/compiler/utils/swap_space.h index 1f8f5da..691df4a 100644 --- a/compiler/utils/swap_space.h +++ b/compiler/utils/swap_space.h @@ -28,7 +28,6 @@ #include "base/macros.h" #include "base/mutex.h" #include "mem_map.h" -#include "utils.h" namespace art { diff --git a/compiler/utils/test_dex_file_builder.h b/compiler/utils/test_dex_file_builder.h index ab039aa..b1d7b4c 100644 --- a/compiler/utils/test_dex_file_builder.h +++ b/compiler/utils/test_dex_file_builder.h @@ -22,8 +22,9 @@ #include <map> #include <vector> +#include "base/bit_utils.h" +#include "base/logging.h" #include "dex_file.h" -#include "utils.h" namespace art { diff --git a/compiler/utils/test_dex_file_builder_test.cc b/compiler/utils/test_dex_file_builder_test.cc index ee6e35d..7a424a2 100644 --- a/compiler/utils/test_dex_file_builder_test.cc +++ b/compiler/utils/test_dex_file_builder_test.cc @@ -18,6 +18,7 @@ #include "dex_file-inl.h" #include "gtest/gtest.h" +#include "utils.h" namespace art { diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h index 136b0cb..5319dac 100644 --- a/compiler/utils/x86/assembler_x86.h +++ b/compiler/utils/x86/assembler_x86.h @@ -18,13 +18,13 @@ #define ART_COMPILER_UTILS_X86_ASSEMBLER_X86_H_ #include <vector> +#include "base/bit_utils.h" #include "base/macros.h" #include "constants_x86.h" #include "globals.h" #include "managed_register_x86.h" #include "offsets.h" #include "utils/assembler.h" -#include "utils.h" namespace art { namespace x86 { diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h index 162714a..7daf994 100644 --- a/compiler/utils/x86_64/assembler_x86_64.h +++ b/compiler/utils/x86_64/assembler_x86_64.h @@ -18,13 +18,14 @@ #define ART_COMPILER_UTILS_X86_64_ASSEMBLER_X86_64_H_ #include <vector> + +#include "base/bit_utils.h" #include "base/macros.h" #include "constants_x86_64.h" #include "globals.h" #include "managed_register_x86_64.h" #include "offsets.h" #include "utils/assembler.h" -#include "utils.h" namespace art { namespace x86_64 { diff --git a/compiler/utils/x86_64/assembler_x86_64_test.cc b/compiler/utils/x86_64/assembler_x86_64_test.cc index 0be4d63..dcffe35 100644 --- a/compiler/utils/x86_64/assembler_x86_64_test.cc +++ b/compiler/utils/x86_64/assembler_x86_64_test.cc @@ -20,9 +20,9 @@ #include <map> #include <random> +#include "base/bit_utils.h" #include "base/stl_util.h" #include "utils/assembler_test.h" -#include "utils.h" namespace art { diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 43bec37..e0f367e 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -41,6 +41,7 @@ #include "base/macros.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 "class_linker.h" diff --git a/patchoat/patchoat.h b/patchoat/patchoat.h index 86f9118..8f16f6b 100644 --- a/patchoat/patchoat.h +++ b/patchoat/patchoat.h @@ -25,7 +25,6 @@ #include "gc/accounting/space_bitmap.h" #include "gc/heap.h" #include "os.h" -#include "utils.h" namespace art { diff --git a/runtime/Android.mk b/runtime/Android.mk index ece9d4b..a4fa24d 100644 --- a/runtime/Android.mk +++ b/runtime/Android.mk @@ -32,6 +32,7 @@ LIBART_COMMON_SRC_FILES := \ base/scoped_flock.cc \ base/stringpiece.cc \ base/stringprintf.cc \ + base/time_utils.cc \ base/timing_logger.cc \ base/unix_file/fd_file.cc \ base/unix_file/random_access_file_utils.cc \ diff --git a/runtime/arch/arm/context_arm.cc b/runtime/arch/arm/context_arm.cc index 5bd23d0..c0e658c 100644 --- a/runtime/arch/arm/context_arm.cc +++ b/runtime/arch/arm/context_arm.cc @@ -16,9 +16,9 @@ #include "context_arm.h" +#include "base/bit_utils.h" #include "mirror/art_method-inl.h" #include "quick/quick_method_frame_info.h" -#include "utils.h" namespace art { namespace arm { @@ -26,12 +26,8 @@ namespace arm { static constexpr uint32_t gZero = 0; void ArmContext::Reset() { - for (size_t i = 0; i < kNumberOfCoreRegisters; i++) { - gprs_[i] = nullptr; - } - for (size_t i = 0; i < kNumberOfSRegisters; i++) { - fprs_[i] = nullptr; - } + std::fill_n(gprs_, arraysize(gprs_), nullptr); + std::fill_n(fprs_, arraysize(fprs_), nullptr); gprs_[SP] = &sp_; gprs_[PC] = &pc_; // Initialize registers with easy to spot debug values. @@ -42,29 +38,23 @@ void ArmContext::Reset() { void ArmContext::FillCalleeSaves(const StackVisitor& fr) { mirror::ArtMethod* method = fr.GetMethod(); const QuickMethodFrameInfo frame_info = method->GetQuickFrameInfo(); - size_t spill_count = POPCOUNT(frame_info.CoreSpillMask()); - size_t fp_spill_count = POPCOUNT(frame_info.FpSpillMask()); - if (spill_count > 0) { - // Lowest number spill is farthest away, walk registers and fill into context - int j = 1; - for (size_t i = 0; i < kNumberOfCoreRegisters; i++) { - if (((frame_info.CoreSpillMask() >> i) & 1) != 0) { - gprs_[i] = fr.CalleeSaveAddress(spill_count - j, frame_info.FrameSizeInBytes()); - j++; - } - } + int spill_pos = 0; + + // Core registers come first, from the highest down to the lowest. + uint32_t core_regs = frame_info.CoreSpillMask(); + DCHECK_EQ(0u, core_regs & (static_cast<uint32_t>(-1) << kNumberOfCoreRegisters)); + for (uint32_t core_reg : HighToLowBits(core_regs)) { + gprs_[core_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes()); + ++spill_pos; } - if (fp_spill_count > 0) { - // Lowest number spill is farthest away, walk registers and fill into context - int j = 1; - for (size_t i = 0; i < kNumberOfSRegisters; i++) { - if (((frame_info.FpSpillMask() >> i) & 1) != 0) { - fprs_[i] = fr.CalleeSaveAddress(spill_count + fp_spill_count - j, - frame_info.FrameSizeInBytes()); - j++; - } - } + DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask())); + + // FP registers come second, from the highest down to the lowest. + for (uint32_t fp_reg : HighToLowBits(frame_info.FpSpillMask())) { + fprs_[fp_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes()); + ++spill_pos; } + DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask()) + POPCOUNT(frame_info.FpSpillMask())); } void ArmContext::SetGPR(uint32_t reg, uintptr_t value) { diff --git a/runtime/arch/arm/quick_method_frame_info_arm.h b/runtime/arch/arm/quick_method_frame_info_arm.h index c1f3fc2..5580ee4 100644 --- a/runtime/arch/arm/quick_method_frame_info_arm.h +++ b/runtime/arch/arm/quick_method_frame_info_arm.h @@ -17,10 +17,10 @@ #ifndef ART_RUNTIME_ARCH_ARM_QUICK_METHOD_FRAME_INFO_ARM_H_ #define ART_RUNTIME_ARCH_ARM_QUICK_METHOD_FRAME_INFO_ARM_H_ +#include "base/bit_utils.h" #include "quick/quick_method_frame_info.h" #include "registers_arm.h" #include "runtime.h" // for Runtime::CalleeSaveType. -#include "utils.h" namespace art { namespace arm { diff --git a/runtime/arch/arm64/context_arm64.cc b/runtime/arch/arm64/context_arm64.cc index ec9c122..9c7bb55 100644 --- a/runtime/arch/arm64/context_arm64.cc +++ b/runtime/arch/arm64/context_arm64.cc @@ -18,9 +18,9 @@ #include "context_arm64.h" +#include "base/bit_utils.h" #include "mirror/art_method-inl.h" #include "quick/quick_method_frame_info.h" -#include "utils.h" namespace art { namespace arm64 { @@ -28,12 +28,8 @@ namespace arm64 { static constexpr uint64_t gZero = 0; void Arm64Context::Reset() { - for (size_t i = 0; i < kNumberOfXRegisters; i++) { - gprs_[i] = nullptr; - } - for (size_t i = 0; i < kNumberOfDRegisters; i++) { - fprs_[i] = nullptr; - } + std::fill_n(gprs_, arraysize(gprs_), nullptr); + std::fill_n(fprs_, arraysize(fprs_), nullptr); gprs_[SP] = &sp_; gprs_[LR] = &pc_; // Initialize registers with easy to spot debug values. @@ -44,30 +40,21 @@ void Arm64Context::Reset() { void Arm64Context::FillCalleeSaves(const StackVisitor& fr) { mirror::ArtMethod* method = fr.GetMethod(); const QuickMethodFrameInfo frame_info = method->GetQuickFrameInfo(); - size_t spill_count = POPCOUNT(frame_info.CoreSpillMask()); - size_t fp_spill_count = POPCOUNT(frame_info.FpSpillMask()); - if (spill_count > 0) { - // Lowest number spill is farthest away, walk registers and fill into context. - int j = 1; - for (size_t i = 0; i < kNumberOfXRegisters; i++) { - if (((frame_info.CoreSpillMask() >> i) & 1) != 0) { - gprs_[i] = fr.CalleeSaveAddress(spill_count - j, frame_info.FrameSizeInBytes()); - j++; - } - } + int spill_pos = 0; + + // Core registers come first, from the highest down to the lowest. + for (uint32_t core_reg : HighToLowBits(frame_info.CoreSpillMask())) { + gprs_[core_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes()); + ++spill_pos; } + DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask())); - if (fp_spill_count > 0) { - // Lowest number spill is farthest away, walk registers and fill into context. - int j = 1; - for (size_t i = 0; i < kNumberOfDRegisters; i++) { - if (((frame_info.FpSpillMask() >> i) & 1) != 0) { - fprs_[i] = fr.CalleeSaveAddress(spill_count + fp_spill_count - j, - frame_info.FrameSizeInBytes()); - j++; - } - } + // FP registers come second, from the highest down to the lowest. + for (uint32_t fp_reg : HighToLowBits(frame_info.FpSpillMask())) { + fprs_[fp_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes()); + ++spill_pos; } + DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask()) + POPCOUNT(frame_info.FpSpillMask())); } void Arm64Context::SetGPR(uint32_t reg, uintptr_t value) { diff --git a/runtime/arch/arm64/quick_method_frame_info_arm64.h b/runtime/arch/arm64/quick_method_frame_info_arm64.h index 61b4dff..dfb3f99 100644 --- a/runtime/arch/arm64/quick_method_frame_info_arm64.h +++ b/runtime/arch/arm64/quick_method_frame_info_arm64.h @@ -17,10 +17,10 @@ #ifndef ART_RUNTIME_ARCH_ARM64_QUICK_METHOD_FRAME_INFO_ARM64_H_ #define ART_RUNTIME_ARCH_ARM64_QUICK_METHOD_FRAME_INFO_ARM64_H_ +#include "base/bit_utils.h" #include "quick/quick_method_frame_info.h" #include "registers_arm64.h" #include "runtime.h" // for Runtime::CalleeSaveType. -#include "utils.h" // for POPCOUNT namespace art { namespace arm64 { diff --git a/runtime/arch/mips/context_mips.cc b/runtime/arch/mips/context_mips.cc index 3b525be..f0c893a 100644 --- a/runtime/arch/mips/context_mips.cc +++ b/runtime/arch/mips/context_mips.cc @@ -16,9 +16,9 @@ #include "context_mips.h" +#include "base/bit_utils.h" #include "mirror/art_method-inl.h" #include "quick/quick_method_frame_info.h" -#include "utils.h" namespace art { namespace mips { @@ -26,12 +26,8 @@ namespace mips { static constexpr uint32_t gZero = 0; void MipsContext::Reset() { - for (size_t i = 0; i < kNumberOfCoreRegisters; i++) { - gprs_[i] = nullptr; - } - for (size_t i = 0; i < kNumberOfFRegisters; i++) { - fprs_[i] = nullptr; - } + std::fill_n(gprs_, arraysize(gprs_), nullptr); + std::fill_n(fprs_, arraysize(fprs_), nullptr); gprs_[SP] = &sp_; gprs_[RA] = &ra_; // Initialize registers with easy to spot debug values. @@ -42,29 +38,21 @@ void MipsContext::Reset() { void MipsContext::FillCalleeSaves(const StackVisitor& fr) { mirror::ArtMethod* method = fr.GetMethod(); const QuickMethodFrameInfo frame_info = method->GetQuickFrameInfo(); - size_t spill_count = POPCOUNT(frame_info.CoreSpillMask()); - size_t fp_spill_count = POPCOUNT(frame_info.FpSpillMask()); - if (spill_count > 0) { - // Lowest number spill is farthest away, walk registers and fill into context. - int j = 1; - for (size_t i = 0; i < kNumberOfCoreRegisters; i++) { - if (((frame_info.CoreSpillMask() >> i) & 1) != 0) { - gprs_[i] = fr.CalleeSaveAddress(spill_count - j, frame_info.FrameSizeInBytes()); - j++; - } - } + int spill_pos = 0; + + // Core registers come first, from the highest down to the lowest. + for (uint32_t core_reg : HighToLowBits(frame_info.CoreSpillMask())) { + gprs_[core_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes()); + ++spill_pos; } - if (fp_spill_count > 0) { - // Lowest number spill is farthest away, walk registers and fill into context. - int j = 1; - for (size_t i = 0; i < kNumberOfFRegisters; i++) { - if (((frame_info.FpSpillMask() >> i) & 1) != 0) { - fprs_[i] = fr.CalleeSaveAddress(spill_count + fp_spill_count - j, - frame_info.FrameSizeInBytes()); - j++; - } - } + DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask())); + + // FP registers come second, from the highest down to the lowest. + for (uint32_t fp_reg : HighToLowBits(frame_info.FpSpillMask())) { + fprs_[fp_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes()); + ++spill_pos; } + DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask()) + POPCOUNT(frame_info.FpSpillMask())); } void MipsContext::SetGPR(uint32_t reg, uintptr_t value) { diff --git a/runtime/arch/mips/quick_method_frame_info_mips.h b/runtime/arch/mips/quick_method_frame_info_mips.h index 5fbffbc..97b295f 100644 --- a/runtime/arch/mips/quick_method_frame_info_mips.h +++ b/runtime/arch/mips/quick_method_frame_info_mips.h @@ -17,6 +17,7 @@ #ifndef ART_RUNTIME_ARCH_MIPS_QUICK_METHOD_FRAME_INFO_MIPS_H_ #define ART_RUNTIME_ARCH_MIPS_QUICK_METHOD_FRAME_INFO_MIPS_H_ +#include "base/bit_utils.h" #include "quick/quick_method_frame_info.h" #include "registers_mips.h" #include "runtime.h" // for Runtime::CalleeSaveType. diff --git a/runtime/arch/mips64/context_mips64.cc b/runtime/arch/mips64/context_mips64.cc index 6b3f4c9..8ce6cf0 100644 --- a/runtime/arch/mips64/context_mips64.cc +++ b/runtime/arch/mips64/context_mips64.cc @@ -16,9 +16,9 @@ #include "context_mips64.h" +#include "base/bit_utils.h" #include "mirror/art_method-inl.h" #include "quick/quick_method_frame_info.h" -#include "utils.h" namespace art { namespace mips64 { @@ -26,12 +26,8 @@ namespace mips64 { static constexpr uintptr_t gZero = 0; void Mips64Context::Reset() { - for (size_t i = 0; i < kNumberOfGpuRegisters; i++) { - gprs_[i] = nullptr; - } - for (size_t i = 0; i < kNumberOfFpuRegisters; i++) { - fprs_[i] = nullptr; - } + std::fill_n(gprs_, arraysize(gprs_), nullptr); + std::fill_n(fprs_, arraysize(fprs_), nullptr); gprs_[SP] = &sp_; gprs_[RA] = &ra_; // Initialize registers with easy to spot debug values. @@ -42,29 +38,21 @@ void Mips64Context::Reset() { void Mips64Context::FillCalleeSaves(const StackVisitor& fr) { mirror::ArtMethod* method = fr.GetMethod(); const QuickMethodFrameInfo frame_info = method->GetQuickFrameInfo(); - size_t spill_count = POPCOUNT(frame_info.CoreSpillMask()); - size_t fp_spill_count = POPCOUNT(frame_info.FpSpillMask()); - if (spill_count > 0) { - // Lowest number spill is farthest away, walk registers and fill into context. - int j = 1; - for (size_t i = 0; i < kNumberOfGpuRegisters; i++) { - if (((frame_info.CoreSpillMask() >> i) & 1) != 0) { - gprs_[i] = fr.CalleeSaveAddress(spill_count - j, frame_info.FrameSizeInBytes()); - j++; - } - } + int spill_pos = 0; + + // Core registers come first, from the highest down to the lowest. + for (uint32_t core_reg : HighToLowBits(frame_info.CoreSpillMask())) { + gprs_[core_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes()); + ++spill_pos; } - if (fp_spill_count > 0) { - // Lowest number spill is farthest away, walk registers and fill into context. - int j = 1; - for (size_t i = 0; i < kNumberOfFpuRegisters; i++) { - if (((frame_info.FpSpillMask() >> i) & 1) != 0) { - fprs_[i] = fr.CalleeSaveAddress(spill_count + fp_spill_count - j, - frame_info.FrameSizeInBytes()); - j++; - } - } + DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask())); + + // FP registers come second, from the highest down to the lowest. + for (uint32_t fp_reg : HighToLowBits(frame_info.FpSpillMask())) { + fprs_[fp_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes()); + ++spill_pos; } + DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask()) + POPCOUNT(frame_info.FpSpillMask())); } void Mips64Context::SetGPR(uint32_t reg, uintptr_t value) { diff --git a/runtime/arch/mips64/quick_method_frame_info_mips64.h b/runtime/arch/mips64/quick_method_frame_info_mips64.h index de55e81..f967be0 100644 --- a/runtime/arch/mips64/quick_method_frame_info_mips64.h +++ b/runtime/arch/mips64/quick_method_frame_info_mips64.h @@ -17,6 +17,7 @@ #ifndef ART_RUNTIME_ARCH_MIPS64_QUICK_METHOD_FRAME_INFO_MIPS64_H_ #define ART_RUNTIME_ARCH_MIPS64_QUICK_METHOD_FRAME_INFO_MIPS64_H_ +#include "base/bit_utils.h" #include "quick/quick_method_frame_info.h" #include "registers_mips64.h" #include "runtime.h" // for Runtime::CalleeSaveType. diff --git a/runtime/arch/x86/context_x86.cc b/runtime/arch/x86/context_x86.cc index 52a35dd..7a5d0c5 100644 --- a/runtime/arch/x86/context_x86.cc +++ b/runtime/arch/x86/context_x86.cc @@ -16,10 +16,9 @@ #include "context_x86.h" +#include "base/bit_utils.h" #include "mirror/art_method-inl.h" #include "quick/quick_method_frame_info.h" -#include "utils.h" - namespace art { namespace x86 { @@ -27,12 +26,8 @@ namespace x86 { static constexpr uintptr_t gZero = 0; void X86Context::Reset() { - for (size_t i = 0; i < kNumberOfCpuRegisters; i++) { - gprs_[i] = nullptr; - } - for (size_t i = 0; i < kNumberOfFloatRegisters; ++i) { - fprs_[i] = nullptr; - } + std::fill_n(gprs_, arraysize(gprs_), nullptr); + std::fill_n(fprs_, arraysize(fprs_), nullptr); gprs_[ESP] = &esp_; // Initialize registers with easy to spot debug values. esp_ = X86Context::kBadGprBase + ESP; @@ -42,36 +37,29 @@ void X86Context::Reset() { void X86Context::FillCalleeSaves(const StackVisitor& fr) { mirror::ArtMethod* method = fr.GetMethod(); const QuickMethodFrameInfo frame_info = method->GetQuickFrameInfo(); - size_t spill_count = POPCOUNT(frame_info.CoreSpillMask()); - size_t fp_spill_count = POPCOUNT(frame_info.FpSpillMask()); - if (spill_count > 0) { - // Lowest number spill is farthest away, walk registers and fill into context. - int j = 2; // Offset j to skip return address spill. - for (int i = 0; i < kNumberOfCpuRegisters; i++) { - if (((frame_info.CoreSpillMask() >> i) & 1) != 0) { - gprs_[i] = fr.CalleeSaveAddress(spill_count - j, frame_info.FrameSizeInBytes()); - j++; - } - } + int spill_pos = 0; + + // Core registers come first, from the highest down to the lowest. + uint32_t core_regs = + frame_info.CoreSpillMask() & ~(static_cast<uint32_t>(-1) << kNumberOfCpuRegisters); + DCHECK_EQ(1, POPCOUNT(frame_info.CoreSpillMask() & ~core_regs)); // Return address spill. + for (uint32_t core_reg : HighToLowBits(core_regs)) { + gprs_[core_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes()); + ++spill_pos; } - if (fp_spill_count > 0) { - // Lowest number spill is farthest away, walk registers and fill into context. - size_t j = 2; // Offset j to skip return address spill. - size_t fp_spill_size_in_words = fp_spill_count * 2; - for (size_t i = 0; i < kNumberOfFloatRegisters; ++i) { - if (((frame_info.FpSpillMask() >> i) & 1) != 0) { - // There are 2 pieces to each XMM register, to match VR size. - fprs_[2*i] = reinterpret_cast<uint32_t*>( - fr.CalleeSaveAddress(spill_count + fp_spill_size_in_words - j, - frame_info.FrameSizeInBytes())); - fprs_[2*i+1] = reinterpret_cast<uint32_t*>( - fr.CalleeSaveAddress(spill_count + fp_spill_size_in_words - j - 1, - frame_info.FrameSizeInBytes())); - // Two void* per XMM register. - j += 2; - } - } + DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask()) - 1); + + // FP registers come second, from the highest down to the lowest. + uint32_t fp_regs = frame_info.FpSpillMask(); + DCHECK_EQ(0u, fp_regs & (static_cast<uint32_t>(-1) << kNumberOfFloatRegisters)); + for (uint32_t fp_reg : HighToLowBits(fp_regs)) { + // Two void* per XMM register. + fprs_[2 * fp_reg] = fr.CalleeSaveAddress(spill_pos + 1, frame_info.FrameSizeInBytes()); + fprs_[2 * fp_reg + 1] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes()); + spill_pos += 2; } + DCHECK_EQ(spill_pos, + POPCOUNT(frame_info.CoreSpillMask()) - 1 + 2 * POPCOUNT(frame_info.FpSpillMask())); } void X86Context::SmashCallerSaves() { diff --git a/runtime/arch/x86/quick_method_frame_info_x86.h b/runtime/arch/x86/quick_method_frame_info_x86.h index 9bba531..ed1d860 100644 --- a/runtime/arch/x86/quick_method_frame_info_x86.h +++ b/runtime/arch/x86/quick_method_frame_info_x86.h @@ -17,6 +17,7 @@ #ifndef ART_RUNTIME_ARCH_X86_QUICK_METHOD_FRAME_INFO_X86_H_ #define ART_RUNTIME_ARCH_X86_QUICK_METHOD_FRAME_INFO_X86_H_ +#include "base/bit_utils.h" #include "quick/quick_method_frame_info.h" #include "registers_x86.h" #include "runtime.h" // for Runtime::CalleeSaveType. diff --git a/runtime/arch/x86_64/context_x86_64.cc b/runtime/arch/x86_64/context_x86_64.cc index 6336541..de54e14 100644 --- a/runtime/arch/x86_64/context_x86_64.cc +++ b/runtime/arch/x86_64/context_x86_64.cc @@ -16,9 +16,9 @@ #include "context_x86_64.h" +#include "base/bit_utils.h" #include "mirror/art_method-inl.h" #include "quick/quick_method_frame_info.h" -#include "utils.h" namespace art { namespace x86_64 { @@ -26,12 +26,8 @@ namespace x86_64 { static constexpr uintptr_t gZero = 0; void X86_64Context::Reset() { - for (size_t i = 0; i < kNumberOfCpuRegisters; ++i) { - gprs_[i] = nullptr; - } - for (size_t i = 0; i < kNumberOfFloatRegisters; ++i) { - fprs_[i] = nullptr; - } + std::fill_n(gprs_, arraysize(gprs_), nullptr); + std::fill_n(fprs_, arraysize(fprs_), nullptr); gprs_[RSP] = &rsp_; // Initialize registers with easy to spot debug values. rsp_ = X86_64Context::kBadGprBase + RSP; @@ -41,29 +37,27 @@ void X86_64Context::Reset() { void X86_64Context::FillCalleeSaves(const StackVisitor& fr) { mirror::ArtMethod* method = fr.GetMethod(); const QuickMethodFrameInfo frame_info = method->GetQuickFrameInfo(); - size_t spill_count = POPCOUNT(frame_info.CoreSpillMask()); - size_t fp_spill_count = POPCOUNT(frame_info.FpSpillMask()); - if (spill_count > 0) { - // Lowest number spill is farthest away, walk registers and fill into context. - size_t j = 2; // Offset j to skip return address spill. - for (size_t i = 0; i < kNumberOfCpuRegisters; ++i) { - if (((frame_info.CoreSpillMask() >> i) & 1) != 0) { - gprs_[i] = fr.CalleeSaveAddress(spill_count - j, frame_info.FrameSizeInBytes()); - j++; - } - } + int spill_pos = 0; + + // Core registers come first, from the highest down to the lowest. + uint32_t core_regs = + frame_info.CoreSpillMask() & ~(static_cast<uint32_t>(-1) << kNumberOfCpuRegisters); + DCHECK_EQ(1, POPCOUNT(frame_info.CoreSpillMask() & ~core_regs)); // Return address spill. + for (uint32_t core_reg : HighToLowBits(core_regs)) { + gprs_[core_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes()); + ++spill_pos; } - if (fp_spill_count > 0) { - // Lowest number spill is farthest away, walk registers and fill into context. - size_t j = 2; // Offset j to skip return address spill. - for (size_t i = 0; i < kNumberOfFloatRegisters; ++i) { - if (((frame_info.FpSpillMask() >> i) & 1) != 0) { - fprs_[i] = reinterpret_cast<uint64_t*>( - fr.CalleeSaveAddress(spill_count + fp_spill_count - j, frame_info.FrameSizeInBytes())); - j++; - } - } + DCHECK_EQ(spill_pos, POPCOUNT(frame_info.CoreSpillMask()) - 1); + + // FP registers come second, from the highest down to the lowest. + uint32_t fp_regs = frame_info.FpSpillMask(); + DCHECK_EQ(0u, fp_regs & (static_cast<uint32_t>(-1) << kNumberOfFloatRegisters)); + for (uint32_t fp_reg : HighToLowBits(fp_regs)) { + fprs_[fp_reg] = fr.CalleeSaveAddress(spill_pos, frame_info.FrameSizeInBytes()); + ++spill_pos; } + DCHECK_EQ(spill_pos, + POPCOUNT(frame_info.CoreSpillMask()) - 1 + POPCOUNT(frame_info.FpSpillMask())); } void X86_64Context::SmashCallerSaves() { diff --git a/runtime/arch/x86_64/quick_method_frame_info_x86_64.h b/runtime/arch/x86_64/quick_method_frame_info_x86_64.h index 53aa212..72d7e99 100644 --- a/runtime/arch/x86_64/quick_method_frame_info_x86_64.h +++ b/runtime/arch/x86_64/quick_method_frame_info_x86_64.h @@ -17,6 +17,7 @@ #ifndef ART_RUNTIME_ARCH_X86_64_QUICK_METHOD_FRAME_INFO_X86_64_H_ #define ART_RUNTIME_ARCH_X86_64_QUICK_METHOD_FRAME_INFO_X86_64_H_ +#include "base/bit_utils.h" #include "quick/quick_method_frame_info.h" #include "registers_x86_64.h" #include "runtime.h" // for Runtime::CalleeSaveType. diff --git a/runtime/barrier.cc b/runtime/barrier.cc index f80a65f..d21f551 100644 --- a/runtime/barrier.cc +++ b/runtime/barrier.cc @@ -17,6 +17,7 @@ #include "barrier.h" #include "base/mutex.h" +#include "base/time_utils.h" #include "thread.h" namespace art { diff --git a/runtime/base/arena_allocator.h b/runtime/base/arena_allocator.h index ab5968c..2e617b5 100644 --- a/runtime/base/arena_allocator.h +++ b/runtime/base/arena_allocator.h @@ -20,10 +20,10 @@ #include <stdint.h> #include <stddef.h> +#include "base/bit_utils.h" #include "debug_stack.h" #include "macros.h" #include "mutex.h" -#include "utils.h" namespace art { diff --git a/runtime/base/bit_utils.h b/runtime/base/bit_utils.h new file mode 100644 index 0000000..7972158 --- /dev/null +++ b/runtime/base/bit_utils.h @@ -0,0 +1,337 @@ +/* + * Copyright (C) 2015 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_BIT_UTILS_H_ +#define ART_RUNTIME_BASE_BIT_UTILS_H_ + +#include <iterator> +#include <limits> +#include <type_traits> + +#include "base/logging.h" +#include "base/iteration_range.h" + +namespace art { + +template<typename T> +static constexpr int CLZ(T x) { + static_assert(std::is_integral<T>::value, "T must be integral"); + // TODO: assert unsigned. There is currently many uses with signed values. + static_assert(sizeof(T) <= sizeof(long long), // NOLINT [runtime/int] [4] + "T too large, must be smaller than long long"); + return (sizeof(T) == sizeof(uint32_t)) + ? __builtin_clz(x) // TODO: __builtin_clz[ll] has undefined behavior for x=0 + : __builtin_clzll(x); +} + +template<typename T> +static constexpr int CTZ(T x) { + static_assert(std::is_integral<T>::value, "T must be integral"); + // TODO: assert unsigned. There is currently many uses with signed values. + return (sizeof(T) == sizeof(uint32_t)) + ? __builtin_ctz(x) + : __builtin_ctzll(x); +} + +template<typename T> +static constexpr int POPCOUNT(T x) { + return (sizeof(T) == sizeof(uint32_t)) + ? __builtin_popcount(x) + : __builtin_popcountll(x); +} + +// Find the bit position of the most significant bit (0-based), or -1 if there were no bits set. +template <typename T> +static constexpr ssize_t MostSignificantBit(T value) { + static_assert(std::is_integral<T>::value, "T must be integral"); + static_assert(std::is_unsigned<T>::value, "T must be unsigned"); + static_assert(std::numeric_limits<T>::radix == 2, "Unexpected radix!"); + return (value == 0) ? -1 : std::numeric_limits<T>::digits - 1 - CLZ(value); +} + +// Find the bit position of the least significant bit (0-based), or -1 if there were no bits set. +template <typename T> +static constexpr ssize_t LeastSignificantBit(T value) { + static_assert(std::is_integral<T>::value, "T must be integral"); + static_assert(std::is_unsigned<T>::value, "T must be unsigned"); + return (value == 0) ? -1 : CTZ(value); +} + +// How many bits (minimally) does it take to store the constant 'value'? i.e. 1 for 1, 3 for 5, etc. +template <typename T> +static constexpr size_t MinimumBitsToStore(T value) { + return static_cast<size_t>(MostSignificantBit(value) + 1); +} + +template <typename T> +static constexpr inline T RoundUpToPowerOfTwo(T x) { + static_assert(std::is_integral<T>::value, "T must be integral"); + static_assert(std::is_unsigned<T>::value, "T must be unsigned"); + // NOTE: Undefined if x > (1 << (std::numeric_limits<T>::digits - 1)). + return (x < 2u) ? x : static_cast<T>(1u) << (std::numeric_limits<T>::digits - CLZ(x - 1u)); +} + +template<typename T> +static constexpr bool IsPowerOfTwo(T x) { + static_assert(std::is_integral<T>::value, "T must be integral"); + // TODO: assert unsigned. There is currently many uses with signed values. + return (x & (x - 1)) == 0; +} + +template<typename T> +static inline int WhichPowerOf2(T x) { + static_assert(std::is_integral<T>::value, "T must be integral"); + // TODO: assert unsigned. There is currently many uses with signed values. + DCHECK((x != 0) && IsPowerOfTwo(x)); + return CTZ(x); +} + +// For rounding integers. +// NOTE: In the absence of std::omit_from_type_deduction<T> or std::identity<T>, use std::decay<T>. +template<typename T> +static constexpr T RoundDown(T x, typename std::decay<T>::type n) WARN_UNUSED; + +template<typename T> +static constexpr T RoundDown(T x, typename std::decay<T>::type n) { + return + DCHECK_CONSTEXPR(IsPowerOfTwo(n), , T(0)) + (x & -n); +} + +template<typename T> +static constexpr T RoundUp(T x, typename std::remove_reference<T>::type n) WARN_UNUSED; + +template<typename T> +static constexpr T RoundUp(T x, typename std::remove_reference<T>::type n) { + return RoundDown(x + n - 1, n); +} + +// For aligning pointers. +template<typename T> +static inline T* AlignDown(T* x, uintptr_t n) WARN_UNUSED; + +template<typename T> +static inline T* AlignDown(T* x, uintptr_t n) { + return reinterpret_cast<T*>(RoundDown(reinterpret_cast<uintptr_t>(x), n)); +} + +template<typename T> +static inline T* AlignUp(T* x, uintptr_t n) WARN_UNUSED; + +template<typename T> +static inline T* AlignUp(T* x, uintptr_t n) { + return reinterpret_cast<T*>(RoundUp(reinterpret_cast<uintptr_t>(x), n)); +} + +template<int n, typename T> +static inline bool IsAligned(T x) { + static_assert((n & (n - 1)) == 0, "n is not a power of two"); + return (x & (n - 1)) == 0; +} + +template<int n, typename T> +static inline bool IsAligned(T* x) { + return IsAligned<n>(reinterpret_cast<const uintptr_t>(x)); +} + +template<typename T> +static inline bool IsAlignedParam(T x, int n) { + return (x & (n - 1)) == 0; +} + +#define CHECK_ALIGNED(value, alignment) \ + CHECK(::art::IsAligned<alignment>(value)) << reinterpret_cast<const void*>(value) + +#define DCHECK_ALIGNED(value, alignment) \ + DCHECK(::art::IsAligned<alignment>(value)) << reinterpret_cast<const void*>(value) + +#define DCHECK_ALIGNED_PARAM(value, alignment) \ + DCHECK(::art::IsAlignedParam(value, alignment)) << reinterpret_cast<const void*>(value) + +// Like sizeof, but count how many bits a type takes. Pass type explicitly. +template <typename T> +static constexpr size_t BitSizeOf() { + static_assert(std::is_integral<T>::value, "T must be integral"); + typedef typename std::make_unsigned<T>::type unsigned_type; + static_assert(sizeof(T) == sizeof(unsigned_type), "Unexpected type size mismatch!"); + static_assert(std::numeric_limits<unsigned_type>::radix == 2, "Unexpected radix!"); + return std::numeric_limits<unsigned_type>::digits; +} + +// Like sizeof, but count how many bits a type takes. Infers type from parameter. +template <typename T> +static constexpr size_t BitSizeOf(T /*x*/) { + return BitSizeOf<T>(); +} + +static inline uint16_t Low16Bits(uint32_t value) { + return static_cast<uint16_t>(value); +} + +static inline uint16_t High16Bits(uint32_t value) { + return static_cast<uint16_t>(value >> 16); +} + +static inline uint32_t Low32Bits(uint64_t value) { + return static_cast<uint32_t>(value); +} + +static inline uint32_t High32Bits(uint64_t value) { + return static_cast<uint32_t>(value >> 32); +} + +// Check whether an N-bit two's-complement representation can hold value. +template <typename T> +static inline bool IsInt(size_t N, T value) { + if (N == BitSizeOf<T>()) { + return true; + } else { + CHECK_LT(0u, N); + CHECK_LT(N, BitSizeOf<T>()); + T limit = static_cast<T>(1) << (N - 1u); + return (-limit <= value) && (value < limit); + } +} + +template <typename T> +static constexpr T GetIntLimit(size_t bits) { + return + DCHECK_CONSTEXPR(bits > 0, "bits cannot be zero", 0) + DCHECK_CONSTEXPR(bits < BitSizeOf<T>(), "kBits must be < max.", 0) + static_cast<T>(1) << (bits - 1); +} + +template <size_t kBits, typename T> +static constexpr bool IsInt(T value) { + static_assert(kBits > 0, "kBits cannot be zero."); + static_assert(kBits <= BitSizeOf<T>(), "kBits must be <= max."); + static_assert(std::is_signed<T>::value, "Needs a signed type."); + // Corner case for "use all bits." Can't use the limits, as they would overflow, but it is + // trivially true. + return (kBits == BitSizeOf<T>()) ? + true : + (-GetIntLimit<T>(kBits) <= value) && (value < GetIntLimit<T>(kBits)); +} + +template <size_t kBits, typename T> +static constexpr bool IsUint(T value) { + static_assert(kBits > 0, "kBits cannot be zero."); + static_assert(kBits <= BitSizeOf<T>(), "kBits must be <= max."); + static_assert(std::is_integral<T>::value, "Needs an integral type."); + // Corner case for "use all bits." Can't use the limits, as they would overflow, but it is + // trivially true. + // NOTE: To avoid triggering assertion in GetIntLimit(kBits+1) if kBits+1==BitSizeOf<T>(), + // use GetIntLimit(kBits)*2u. The unsigned arithmetic works well for us if it overflows. + return (0 <= value) && + (kBits == BitSizeOf<T>() || + (static_cast<typename std::make_unsigned<T>::type>(value) <= + GetIntLimit<typename std::make_unsigned<T>::type>(kBits) * 2u - 1u)); +} + +template <size_t kBits, typename T> +static constexpr bool IsAbsoluteUint(T value) { + static_assert(kBits <= BitSizeOf<T>(), "kBits must be <= max."); + static_assert(std::is_integral<T>::value, "Needs an integral type."); + typedef typename std::make_unsigned<T>::type unsigned_type; + return (kBits == BitSizeOf<T>()) + ? true + : IsUint<kBits>(value < 0 + ? static_cast<unsigned_type>(-1 - value) + 1u // Avoid overflow. + : static_cast<unsigned_type>(value)); +} + +// Using the Curiously Recurring Template Pattern to implement everything shared +// by LowToHighBitIterator and HighToLowBitIterator, i.e. everything but operator*(). +template <typename T, typename Iter> +class BitIteratorBase + : public std::iterator<std::forward_iterator_tag, uint32_t, ptrdiff_t, void, void> { + static_assert(std::is_integral<T>::value, "T must be integral"); + static_assert(std::is_unsigned<T>::value, "T must be unsigned"); + + static_assert(sizeof(T) == sizeof(uint32_t) || sizeof(T) == sizeof(uint64_t), "Unsupported size"); + + public: + BitIteratorBase() : bits_(0u) { } + explicit BitIteratorBase(T bits) : bits_(bits) { } + + Iter& operator++() { + DCHECK_NE(bits_, 0u); + uint32_t bit = *static_cast<Iter&>(*this); + bits_ &= ~(static_cast<T>(1u) << bit); + return static_cast<Iter&>(*this); + } + + Iter& operator++(int) { + Iter tmp(static_cast<Iter&>(*this)); + ++*this; + return tmp; + } + + protected: + T bits_; + + template <typename U, typename I> + friend bool operator==(const BitIteratorBase<U, I>& lhs, const BitIteratorBase<U, I>& rhs); +}; + +template <typename T, typename Iter> +bool operator==(const BitIteratorBase<T, Iter>& lhs, const BitIteratorBase<T, Iter>& rhs) { + return lhs.bits_ == rhs.bits_; +} + +template <typename T, typename Iter> +bool operator!=(const BitIteratorBase<T, Iter>& lhs, const BitIteratorBase<T, Iter>& rhs) { + return !(lhs == rhs); +} + +template <typename T> +class LowToHighBitIterator : public BitIteratorBase<T, LowToHighBitIterator<T>> { + public: + using BitIteratorBase<T, LowToHighBitIterator<T>>::BitIteratorBase; + + uint32_t operator*() const { + DCHECK_NE(this->bits_, 0u); + return CTZ(this->bits_); + } +}; + +template <typename T> +class HighToLowBitIterator : public BitIteratorBase<T, HighToLowBitIterator<T>> { + public: + using BitIteratorBase<T, HighToLowBitIterator<T>>::BitIteratorBase; + + uint32_t operator*() const { + DCHECK_NE(this->bits_, 0u); + static_assert(std::numeric_limits<T>::radix == 2, "Unexpected radix!"); + return std::numeric_limits<T>::digits - 1u - CLZ(this->bits_); + } +}; + +template <typename T> +IterationRange<LowToHighBitIterator<T>> LowToHighBits(T bits) { + return IterationRange<LowToHighBitIterator<T>>( + LowToHighBitIterator<T>(bits), LowToHighBitIterator<T>()); +} + +template <typename T> +IterationRange<HighToLowBitIterator<T>> HighToLowBits(T bits) { + return IterationRange<HighToLowBitIterator<T>>( + HighToLowBitIterator<T>(bits), HighToLowBitIterator<T>()); +} + +} // namespace art + +#endif // ART_RUNTIME_BASE_BIT_UTILS_H_ diff --git a/runtime/base/bit_utils_test.cc b/runtime/base/bit_utils_test.cc new file mode 100644 index 0000000..77bd0b8 --- /dev/null +++ b/runtime/base/bit_utils_test.cc @@ -0,0 +1,400 @@ +/* + * Copyright (C) 2015 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 <vector> + +#include "bit_utils.h" + +#include "gtest/gtest.h" + +namespace art { + +// NOTE: CLZ(0u) is undefined. +static_assert(31 == CLZ<uint32_t>(1u), "TestCLZ32#1"); +static_assert(30 == CLZ<uint32_t>(2u), "TestCLZ32#2"); +static_assert(16 == CLZ<uint32_t>(0x00008765u), "TestCLZ32#3"); +static_assert(15 == CLZ<uint32_t>(0x00012345u), "TestCLZ32#4"); +static_assert(1 == CLZ<uint32_t>(0x43214321u), "TestCLZ32#5"); +static_assert(0 == CLZ<uint32_t>(0x87654321u), "TestCLZ32#6"); + +// NOTE: CLZ(0ull) is undefined. +static_assert(63 == CLZ<uint64_t>(UINT64_C(1)), "TestCLZ64#1"); +static_assert(62 == CLZ<uint64_t>(UINT64_C(3)), "TestCLZ64#2"); +static_assert(48 == CLZ<uint64_t>(UINT64_C(0x00008765)), "TestCLZ64#3"); +static_assert(32 == CLZ<uint64_t>(UINT64_C(0x87654321)), "TestCLZ64#4"); +static_assert(31 == CLZ<uint64_t>(UINT64_C(0x123456789)), "TestCLZ64#5"); +static_assert(16 == CLZ<uint64_t>(UINT64_C(0x876543211234)), "TestCLZ64#6"); +static_assert(1 == CLZ<uint64_t>(UINT64_C(0x4321432187654321)), "TestCLZ64#7"); +static_assert(0 == CLZ<uint64_t>(UINT64_C(0x8765432187654321)), "TestCLZ64#8"); + +// NOTE: CTZ(0u) is undefined. +static_assert(0 == CTZ<uint32_t>(1u), "TestCTZ32#1"); +static_assert(1 == CTZ<uint32_t>(2u), "TestCTZ32#2"); +static_assert(15 == CTZ<uint32_t>(0x45678000u), "TestCTZ32#3"); +static_assert(16 == CTZ<uint32_t>(0x43210000u), "TestCTZ32#4"); +static_assert(30 == CTZ<uint32_t>(0xc0000000u), "TestCTZ32#5"); +static_assert(31 == CTZ<uint32_t>(0x80000000u), "TestCTZ32#6"); + +// NOTE: CTZ(0ull) is undefined. +static_assert(0 == CTZ<uint64_t>(UINT64_C(1)), "TestCTZ64#1"); +static_assert(1 == CTZ<uint64_t>(UINT64_C(2)), "TestCTZ64#2"); +static_assert(16 == CTZ<uint64_t>(UINT64_C(0x43210000)), "TestCTZ64#3"); +static_assert(31 == CTZ<uint64_t>(UINT64_C(0x80000000)), "TestCTZ64#4"); +static_assert(32 == CTZ<uint64_t>(UINT64_C(0x8765432100000000)), "TestCTZ64#5"); +static_assert(48 == CTZ<uint64_t>(UINT64_C(0x4321000000000000)), "TestCTZ64#6"); +static_assert(62 == CTZ<uint64_t>(UINT64_C(0x4000000000000000)), "TestCTZ64#7"); +static_assert(63 == CTZ<uint64_t>(UINT64_C(0x8000000000000000)), "TestCTZ64#8"); + +static_assert(0 == POPCOUNT<uint32_t>(0u), "TestPOPCOUNT32#1"); +static_assert(1 == POPCOUNT<uint32_t>(8u), "TestPOPCOUNT32#2"); +static_assert(15 == POPCOUNT<uint32_t>(0x55555554u), "TestPOPCOUNT32#3"); +static_assert(16 == POPCOUNT<uint32_t>(0xaaaaaaaau), "TestPOPCOUNT32#4"); +static_assert(31 == POPCOUNT<uint32_t>(0xfffffffeu), "TestPOPCOUNT32#5"); +static_assert(32 == POPCOUNT<uint32_t>(0xffffffffu), "TestPOPCOUNT32#6"); + +static_assert(0 == POPCOUNT<uint64_t>(UINT64_C(0)), "TestPOPCOUNT64#1"); +static_assert(1 == POPCOUNT<uint64_t>(UINT64_C(0x40000)), "TestPOPCOUNT64#2"); +static_assert(16 == POPCOUNT<uint64_t>(UINT64_C(0x1414141482828282)), "TestPOPCOUNT64#3"); +static_assert(31 == POPCOUNT<uint64_t>(UINT64_C(0x0000ffff00007fff)), "TestPOPCOUNT64#4"); +static_assert(32 == POPCOUNT<uint64_t>(UINT64_C(0x5555555555555555)), "TestPOPCOUNT64#5"); +static_assert(48 == POPCOUNT<uint64_t>(UINT64_C(0x7777bbbbddddeeee)), "TestPOPCOUNT64#6"); +static_assert(63 == POPCOUNT<uint64_t>(UINT64_C(0x7fffffffffffffff)), "TestPOPCOUNT64#7"); +static_assert(64 == POPCOUNT<uint64_t>(UINT64_C(0xffffffffffffffff)), "TestPOPCOUNT64#8"); + +static_assert(-1 == MostSignificantBit<uint32_t>(0u), "TestMSB32#1"); +static_assert(0 == MostSignificantBit<uint32_t>(1u), "TestMSB32#2"); +static_assert(31 == MostSignificantBit<uint32_t>(~static_cast<uint32_t>(0u)), "TestMSB32#3"); +static_assert(2 == MostSignificantBit<uint32_t>(0b110), "TestMSB32#4"); +static_assert(2 == MostSignificantBit<uint32_t>(0b100), "TestMSB32#5"); + +static_assert(-1 == MostSignificantBit<uint64_t>(UINT64_C(0)), "TestMSB64#1"); +static_assert(0 == MostSignificantBit<uint64_t>(UINT64_C(1)), "TestMSB64#2"); +static_assert(63 == MostSignificantBit<uint64_t>(~UINT64_C(0)), "TestMSB64#3"); +static_assert(34 == MostSignificantBit<uint64_t>(UINT64_C(0x700000000)), "TestMSB64#4"); +static_assert(34 == MostSignificantBit<uint64_t>(UINT64_C(0x777777777)), "TestMSB64#5"); + +static_assert(-1 == LeastSignificantBit<uint32_t>(0u), "TestLSB32#1"); +static_assert(0 == LeastSignificantBit<uint32_t>(1u), "TestLSB32#1"); +static_assert(0 == LeastSignificantBit<uint32_t>(~static_cast<uint32_t>(0u)), "TestLSB32#1"); +static_assert(1 == LeastSignificantBit<uint32_t>(0b110), "TestLSB32#1"); +static_assert(2 == LeastSignificantBit<uint32_t>(0b100), "TestLSB32#1"); + +static_assert(-1 == LeastSignificantBit<uint64_t>(UINT64_C(0)), "TestLSB64#1"); +static_assert(0 == LeastSignificantBit<uint64_t>(UINT64_C(1)), "TestLSB64#2"); +static_assert(0 == LeastSignificantBit<uint64_t>(~UINT64_C(0)), "TestLSB64#3"); +static_assert(12 == LeastSignificantBit<uint64_t>(UINT64_C(0x5000)), "TestLSB64#4"); +static_assert(48 == LeastSignificantBit<uint64_t>(UINT64_C(0x5555000000000000)), "TestLSB64#5"); + +static_assert(0u == MinimumBitsToStore<uint32_t>(0u), "TestMinBits2Store32#1"); +static_assert(1u == MinimumBitsToStore<uint32_t>(1u), "TestMinBits2Store32#2"); +static_assert(2u == MinimumBitsToStore<uint32_t>(0b10u), "TestMinBits2Store32#3"); +static_assert(2u == MinimumBitsToStore<uint32_t>(0b11u), "TestMinBits2Store32#4"); +static_assert(3u == MinimumBitsToStore<uint32_t>(0b100u), "TestMinBits2Store32#5"); +static_assert(3u == MinimumBitsToStore<uint32_t>(0b110u), "TestMinBits2Store32#6"); +static_assert(3u == MinimumBitsToStore<uint32_t>(0b101u), "TestMinBits2Store32#7"); +static_assert(8u == MinimumBitsToStore<uint32_t>(0xFFu), "TestMinBits2Store32#8"); +static_assert(32u == MinimumBitsToStore<uint32_t>(~static_cast<uint32_t>(0u)), + "TestMinBits2Store32#9"); + +static_assert(0u == MinimumBitsToStore<uint64_t>(UINT64_C(0)), "TestMinBits2Store64#1"); +static_assert(1u == MinimumBitsToStore<uint64_t>(UINT64_C(1)), "TestMinBits2Store64#2"); +static_assert(2u == MinimumBitsToStore<uint64_t>(UINT64_C(0b10)), "TestMinBits2Store64#3"); +static_assert(2u == MinimumBitsToStore<uint64_t>(UINT64_C(0b11)), "TestMinBits2Store64#4"); +static_assert(3u == MinimumBitsToStore<uint64_t>(UINT64_C(0b100)), "TestMinBits2Store64#5"); +static_assert(3u == MinimumBitsToStore<uint64_t>(UINT64_C(0b110)), "TestMinBits2Store64#6"); +static_assert(3u == MinimumBitsToStore<uint64_t>(UINT64_C(0b101)), "TestMinBits2Store64#7"); +static_assert(8u == MinimumBitsToStore<uint64_t>(UINT64_C(0xFF)), "TestMinBits2Store64#8"); +static_assert(32u == MinimumBitsToStore<uint64_t>(UINT64_C(0xFFFFFFFF)), "TestMinBits2Store64#9"); +static_assert(33u == MinimumBitsToStore<uint64_t>(UINT64_C(0x1FFFFFFFF)), "TestMinBits2Store64#10"); +static_assert(64u == MinimumBitsToStore<uint64_t>(~UINT64_C(0)), "TestMinBits2Store64#11"); + +static_assert(0 == RoundUpToPowerOfTwo<uint32_t>(0u), "TestRoundUpPowerOfTwo32#1"); +static_assert(1 == RoundUpToPowerOfTwo<uint32_t>(1u), "TestRoundUpPowerOfTwo32#2"); +static_assert(2 == RoundUpToPowerOfTwo<uint32_t>(2u), "TestRoundUpPowerOfTwo32#3"); +static_assert(4 == RoundUpToPowerOfTwo<uint32_t>(3u), "TestRoundUpPowerOfTwo32#4"); +static_assert(8 == RoundUpToPowerOfTwo<uint32_t>(7u), "TestRoundUpPowerOfTwo32#5"); +static_assert(0x40000u == RoundUpToPowerOfTwo<uint32_t>(0x2aaaau), + "TestRoundUpPowerOfTwo32#6"); +static_assert(0x80000000u == RoundUpToPowerOfTwo<uint32_t>(0x40000001u), + "TestRoundUpPowerOfTwo32#7"); +static_assert(0x80000000u == RoundUpToPowerOfTwo<uint32_t>(0x80000000u), + "TestRoundUpPowerOfTwo32#8"); + +static_assert(0 == RoundUpToPowerOfTwo<uint64_t>(UINT64_C(0)), "TestRoundUpPowerOfTwo64#1"); +static_assert(1 == RoundUpToPowerOfTwo<uint64_t>(UINT64_C(1)), "TestRoundUpPowerOfTwo64#2"); +static_assert(2 == RoundUpToPowerOfTwo<uint64_t>(UINT64_C(2)), "TestRoundUpPowerOfTwo64#3"); +static_assert(4 == RoundUpToPowerOfTwo<uint64_t>(UINT64_C(3)), "TestRoundUpPowerOfTwo64#4"); +static_assert(8 == RoundUpToPowerOfTwo<uint64_t>(UINT64_C(7)), "TestRoundUpPowerOfTwo64#5"); +static_assert(UINT64_C(0x40000) == RoundUpToPowerOfTwo<uint64_t>(UINT64_C(0x2aaaa)), + "TestRoundUpPowerOfTwo64#6"); +static_assert( + UINT64_C(0x8000000000000000) == RoundUpToPowerOfTwo<uint64_t>(UINT64_C(0x4000000000000001)), + "TestRoundUpPowerOfTwo64#7"); +static_assert( + UINT64_C(0x8000000000000000) == RoundUpToPowerOfTwo<uint64_t>(UINT64_C(0x8000000000000000)), + "TestRoundUpPowerOfTwo64#8"); + +static constexpr int64_t kInt32MinMinus1 = + static_cast<int64_t>(std::numeric_limits<int32_t>::min()) - 1; +static constexpr int64_t kInt32MaxPlus1 = + static_cast<int64_t>(std::numeric_limits<int32_t>::max()) + 1; +static constexpr int64_t kUint32MaxPlus1 = + static_cast<int64_t>(std::numeric_limits<uint32_t>::max()) + 1; + +TEST(BitUtilsTest, TestIsInt32) { + EXPECT_FALSE(IsInt<int32_t>(1, -2)); + EXPECT_TRUE(IsInt<int32_t>(1, -1)); + EXPECT_TRUE(IsInt<int32_t>(1, 0)); + EXPECT_FALSE(IsInt<int32_t>(1, 1)); + EXPECT_FALSE(IsInt<int32_t>(4, -9)); + EXPECT_TRUE(IsInt<int32_t>(4, -8)); + EXPECT_TRUE(IsInt<int32_t>(4, 7)); + EXPECT_FALSE(IsInt<int32_t>(4, 8)); + EXPECT_FALSE(IsInt<int32_t>(31, std::numeric_limits<int32_t>::min())); + EXPECT_FALSE(IsInt<int32_t>(31, std::numeric_limits<int32_t>::max())); + EXPECT_TRUE(IsInt<int32_t>(32, std::numeric_limits<int32_t>::min())); + EXPECT_TRUE(IsInt<int32_t>(32, std::numeric_limits<int32_t>::max())); +} + +TEST(BitUtilsTest, TestIsInt64) { + EXPECT_FALSE(IsInt<int64_t>(1, -2)); + EXPECT_TRUE(IsInt<int64_t>(1, -1)); + EXPECT_TRUE(IsInt<int64_t>(1, 0)); + EXPECT_FALSE(IsInt<int64_t>(1, 1)); + EXPECT_FALSE(IsInt<int64_t>(4, -9)); + EXPECT_TRUE(IsInt<int64_t>(4, -8)); + EXPECT_TRUE(IsInt<int64_t>(4, 7)); + EXPECT_FALSE(IsInt<int64_t>(4, 8)); + EXPECT_FALSE(IsInt<int64_t>(31, std::numeric_limits<int32_t>::min())); + EXPECT_FALSE(IsInt<int64_t>(31, std::numeric_limits<int32_t>::max())); + EXPECT_TRUE(IsInt<int64_t>(32, std::numeric_limits<int32_t>::min())); + EXPECT_TRUE(IsInt<int64_t>(32, std::numeric_limits<int32_t>::max())); + EXPECT_FALSE(IsInt<int64_t>(32, kInt32MinMinus1)); + EXPECT_FALSE(IsInt<int64_t>(32, kInt32MaxPlus1)); + EXPECT_FALSE(IsInt<int64_t>(63, std::numeric_limits<int64_t>::min())); + EXPECT_FALSE(IsInt<int64_t>(63, std::numeric_limits<int64_t>::max())); + EXPECT_TRUE(IsInt<int64_t>(64, std::numeric_limits<int64_t>::min())); + EXPECT_TRUE(IsInt<int64_t>(64, std::numeric_limits<int64_t>::max())); +} + +static_assert(!IsInt<1, int32_t>(-2), "TestIsInt32#1"); +static_assert(IsInt<1, int32_t>(-1), "TestIsInt32#2"); +static_assert(IsInt<1, int32_t>(0), "TestIsInt32#3"); +static_assert(!IsInt<1, int32_t>(1), "TestIsInt32#4"); +static_assert(!IsInt<4, int32_t>(-9), "TestIsInt32#5"); +static_assert(IsInt<4, int32_t>(-8), "TestIsInt32#6"); +static_assert(IsInt<4, int32_t>(7), "TestIsInt32#7"); +static_assert(!IsInt<4, int32_t>(8), "TestIsInt32#8"); +static_assert(!IsInt<31, int32_t>(std::numeric_limits<int32_t>::min()), "TestIsInt32#9"); +static_assert(!IsInt<31, int32_t>(std::numeric_limits<int32_t>::max()), "TestIsInt32#10"); +static_assert(IsInt<32, int32_t>(std::numeric_limits<int32_t>::min()), "TestIsInt32#11"); +static_assert(IsInt<32, int32_t>(std::numeric_limits<int32_t>::max()), "TestIsInt32#12"); + +static_assert(!IsInt<1, int64_t>(-2), "TestIsInt64#1"); +static_assert(IsInt<1, int64_t>(-1), "TestIsInt64#2"); +static_assert(IsInt<1, int64_t>(0), "TestIsInt64#3"); +static_assert(!IsInt<1, int64_t>(1), "TestIsInt64#4"); +static_assert(!IsInt<4, int64_t>(-9), "TestIsInt64#5"); +static_assert(IsInt<4, int64_t>(-8), "TestIsInt64#6"); +static_assert(IsInt<4, int64_t>(7), "TestIsInt64#7"); +static_assert(!IsInt<4, int64_t>(8), "TestIsInt64#8"); +static_assert(!IsInt<31, int64_t>(std::numeric_limits<int32_t>::min()), "TestIsInt64#9"); +static_assert(!IsInt<31, int64_t>(std::numeric_limits<int32_t>::max()), "TestIsInt64#10"); +static_assert(IsInt<32, int64_t>(std::numeric_limits<int32_t>::min()), "TestIsInt64#11"); +static_assert(IsInt<32, int64_t>(std::numeric_limits<int32_t>::max()), "TestIsInt64#12"); +static_assert(!IsInt<32, int64_t>(kInt32MinMinus1), "TestIsInt64#13"); +static_assert(!IsInt<32, int64_t>(kInt32MaxPlus1), "TestIsInt64#14"); +static_assert(!IsInt<63, int64_t>(std::numeric_limits<int64_t>::min()), "TestIsInt64#15"); +static_assert(!IsInt<63, int64_t>(std::numeric_limits<int64_t>::max()), "TestIsInt64#16"); +static_assert(IsInt<64, int64_t>(std::numeric_limits<int64_t>::min()), "TestIsInt64#17"); +static_assert(IsInt<64, int64_t>(std::numeric_limits<int64_t>::max()), "TestIsInt64#18"); + +static_assert(!IsUint<1, int32_t>(-1), "TestIsUint32#1"); +static_assert(IsUint<1, int32_t>(0), "TestIsUint32#2"); +static_assert(IsUint<1, int32_t>(1), "TestIsUint32#3"); +static_assert(!IsUint<1, int32_t>(2), "TestIsUint32#4"); +static_assert(!IsUint<4, int32_t>(-1), "TestIsUint32#5"); +static_assert(IsUint<4, int32_t>(0), "TestIsUint32#6"); +static_assert(IsUint<4, int32_t>(15), "TestIsUint32#7"); +static_assert(!IsUint<4, int32_t>(16), "TestIsUint32#8"); +static_assert(!IsUint<30, int32_t>(std::numeric_limits<int32_t>::max()), "TestIsUint32#9"); +static_assert(IsUint<31, int32_t>(std::numeric_limits<int32_t>::max()), "TestIsUint32#10"); +static_assert(!IsUint<32, int32_t>(-1), "TestIsUint32#11"); +static_assert(IsUint<32, int32_t>(0), "TestIsUint32#11"); +static_assert(IsUint<32, uint32_t>(static_cast<uint32_t>(-1)), "TestIsUint32#12"); + +static_assert(!IsUint<1, int64_t>(-1), "TestIsUint64#1"); +static_assert(IsUint<1, int64_t>(0), "TestIsUint64#2"); +static_assert(IsUint<1, int64_t>(1), "TestIsUint64#3"); +static_assert(!IsUint<1, int64_t>(2), "TestIsUint64#4"); +static_assert(!IsUint<4, int64_t>(-1), "TestIsUint64#5"); +static_assert(IsUint<4, int64_t>(0), "TestIsUint64#6"); +static_assert(IsUint<4, int64_t>(15), "TestIsUint64#7"); +static_assert(!IsUint<4, int64_t>(16), "TestIsUint64#8"); +static_assert(!IsUint<30, int64_t>(std::numeric_limits<int32_t>::max()), "TestIsUint64#9"); +static_assert(IsUint<31, int64_t>(std::numeric_limits<int32_t>::max()), "TestIsUint64#10"); +static_assert(!IsUint<62, int64_t>(std::numeric_limits<int64_t>::max()), "TestIsUint64#11"); +static_assert(IsUint<63, int64_t>(std::numeric_limits<int64_t>::max()), "TestIsUint64#12"); +static_assert(!IsUint<64, int64_t>(-1), "TestIsUint64#13"); +static_assert(IsUint<64, int64_t>(0), "TestIsUint64#14"); +static_assert(IsUint<64, uint64_t>(static_cast<uint32_t>(-1)), "TestIsUint64#15"); + +static_assert(!IsAbsoluteUint<1, int32_t>(-2), "TestIsAbsoluteUint32#1"); +static_assert(IsAbsoluteUint<1, int32_t>(-1), "TestIsAbsoluteUint32#2"); +static_assert(IsAbsoluteUint<1, int32_t>(0), "TestIsAbsoluteUint32#3"); +static_assert(IsAbsoluteUint<1, int32_t>(1), "TestIsAbsoluteUint32#4"); +static_assert(!IsAbsoluteUint<1, int32_t>(2), "TestIsAbsoluteUint32#5"); +static_assert(!IsAbsoluteUint<4, int32_t>(-16), "TestIsAbsoluteUint32#6"); +static_assert(IsAbsoluteUint<4, int32_t>(-15), "TestIsAbsoluteUint32#7"); +static_assert(IsAbsoluteUint<4, int32_t>(0), "TestIsAbsoluteUint32#8"); +static_assert(IsAbsoluteUint<4, int32_t>(15), "TestIsAbsoluteUint32#9"); +static_assert(!IsAbsoluteUint<4, int32_t>(16), "TestIsAbsoluteUint32#10"); +static_assert(!IsAbsoluteUint<30, int32_t>(std::numeric_limits<int32_t>::max()), + "TestIsAbsoluteUint32#11"); +static_assert(IsAbsoluteUint<31, int32_t>(std::numeric_limits<int32_t>::max()), + "TestIsAbsoluteUint32#12"); +static_assert(!IsAbsoluteUint<31, int32_t>(std::numeric_limits<int32_t>::min()), + "TestIsAbsoluteUint32#13"); +static_assert(IsAbsoluteUint<31, int32_t>(std::numeric_limits<int32_t>::min() + 1), + "TestIsAbsoluteUint32#14"); +static_assert(IsAbsoluteUint<32, int32_t>(std::numeric_limits<int32_t>::max()), + "TestIsAbsoluteUint32#15"); +static_assert(IsAbsoluteUint<32, int32_t>(std::numeric_limits<int32_t>::min()), + "TestIsAbsoluteUint32#16"); +static_assert(IsAbsoluteUint<32, int32_t>(0), "TestIsAbsoluteUint32#17"); + +static_assert(!IsAbsoluteUint<1, int64_t>(-2), "TestIsAbsoluteUint64#1"); +static_assert(IsAbsoluteUint<1, int64_t>(-1), "TestIsAbsoluteUint64#2"); +static_assert(IsAbsoluteUint<1, int64_t>(0), "TestIsAbsoluteUint64#3"); +static_assert(IsAbsoluteUint<1, int64_t>(1), "TestIsAbsoluteUint64#4"); +static_assert(!IsAbsoluteUint<1, int64_t>(2), "TestIsAbsoluteUint64#5"); +static_assert(!IsAbsoluteUint<4, int64_t>(-16), "TestIsAbsoluteUint64#6"); +static_assert(IsAbsoluteUint<4, int64_t>(-15), "TestIsAbsoluteUint64#7"); +static_assert(IsAbsoluteUint<4, int64_t>(0), "TestIsAbsoluteUint64#8"); +static_assert(IsAbsoluteUint<4, int64_t>(15), "TestIsAbsoluteUint64#9"); +static_assert(!IsAbsoluteUint<4, int64_t>(16), "TestIsAbsoluteUint64#10"); +static_assert(!IsAbsoluteUint<30, int64_t>(std::numeric_limits<int32_t>::max()), + "TestIsAbsoluteUint64#11"); +static_assert(IsAbsoluteUint<31, int64_t>(std::numeric_limits<int32_t>::max()), + "TestIsAbsoluteUint64#12"); +static_assert(!IsAbsoluteUint<31, int64_t>(std::numeric_limits<int32_t>::min()), + "TestIsAbsoluteUint64#13"); +static_assert(IsAbsoluteUint<31, int64_t>(std::numeric_limits<int32_t>::min() + 1), + "TestIsAbsoluteUint64#14"); +static_assert(IsAbsoluteUint<32, int64_t>(std::numeric_limits<int32_t>::max()), + "TestIsAbsoluteUint64#15"); +static_assert(IsAbsoluteUint<32, int64_t>(std::numeric_limits<int32_t>::min()), + "TestIsAbsoluteUint64#16"); +static_assert(!IsAbsoluteUint<62, int64_t>(std::numeric_limits<int64_t>::max()), + "TestIsAbsoluteUint64#17"); +static_assert(IsAbsoluteUint<63, int64_t>(std::numeric_limits<int64_t>::max()), + "TestIsAbsoluteUint64#18"); +static_assert(!IsAbsoluteUint<63, int64_t>(std::numeric_limits<int64_t>::min()), + "TestIsAbsoluteUint64#19"); +static_assert(IsAbsoluteUint<63, int64_t>(std::numeric_limits<int64_t>::min() + 1), + "TestIsAbsoluteUint64#20"); +static_assert(IsAbsoluteUint<64, int64_t>(std::numeric_limits<int64_t>::max()), + "TestIsAbsoluteUint64#21"); +static_assert(IsAbsoluteUint<64, int64_t>(std::numeric_limits<int64_t>::min()), + "TestIsAbsoluteUint64#22"); +static_assert(!IsAbsoluteUint<32, int64_t>(-kUint32MaxPlus1), "TestIsAbsoluteUint64#23"); +static_assert(IsAbsoluteUint<32, int64_t>(-kUint32MaxPlus1 + 1), "TestIsAbsoluteUint64#24"); +static_assert(IsAbsoluteUint<32, int64_t>(0), "TestIsAbsoluteUint64#25"); +static_assert(IsAbsoluteUint<64, int64_t>(0), "TestIsAbsoluteUint64#26"); +static_assert(IsAbsoluteUint<32, int64_t>(std::numeric_limits<uint32_t>::max()), + "TestIsAbsoluteUint64#27"); +static_assert(!IsAbsoluteUint<32, int64_t>(kUint32MaxPlus1), "TestIsAbsoluteUint64#28"); + +template <typename Container> +void CheckElements(const std::initializer_list<uint32_t>& expected, const Container& elements) { + auto expected_it = expected.begin(); + auto element_it = elements.begin(); + size_t idx = 0u; + while (expected_it != expected.end() && element_it != elements.end()) { + EXPECT_EQ(*expected_it, *element_it) << idx; + ++idx; + ++expected_it; + ++element_it; + } + ASSERT_TRUE(expected_it == expected.end() && element_it == elements.end()) + << std::boolalpha << (expected_it == expected.end()) << " " << (element_it == elements.end()); +} + +TEST(BitUtilsTest, TestLowToHighBits32) { + CheckElements({}, LowToHighBits<uint32_t>(0u)); + CheckElements({0}, LowToHighBits<uint32_t>(1u)); + CheckElements({15}, LowToHighBits<uint32_t>(0x8000u)); + CheckElements({31}, LowToHighBits<uint32_t>(0x80000000u)); + CheckElements({0, 31}, LowToHighBits<uint32_t>(0x80000001u)); + CheckElements({0, 1, 2, 3, 4, 5, 6, 7, 31}, LowToHighBits<uint32_t>(0x800000ffu)); + CheckElements({0, 8, 16, 24, 31}, LowToHighBits<uint32_t>(0x81010101u)); + CheckElements({16, 17, 30, 31}, LowToHighBits<uint32_t>(0xc0030000u)); + CheckElements({0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}, + LowToHighBits<uint32_t>(0xffffffffu)); +} + +TEST(BitUtilsTest, TestLowToHighBits64) { + CheckElements({}, LowToHighBits<uint64_t>(UINT64_C(0))); + CheckElements({0}, LowToHighBits<uint64_t>(UINT64_C(1))); + CheckElements({32}, LowToHighBits<uint64_t>(UINT64_C(0x100000000))); + CheckElements({63}, LowToHighBits<uint64_t>(UINT64_C(0x8000000000000000))); + CheckElements({0, 63}, LowToHighBits<uint64_t>(UINT64_C(0x8000000000000001))); + CheckElements({0, 1, 2, 3, 4, 5, 6, 7, 63}, + LowToHighBits<uint64_t>(UINT64_C(0x80000000000000ff))); + CheckElements({0, 8, 16, 24, 32, 40, 48, 56, 63}, + LowToHighBits<uint64_t>(UINT64_C(0x8101010101010101))); + CheckElements({16, 17, 62, 63}, LowToHighBits<uint64_t>(UINT64_C(0xc000000000030000))); + CheckElements({0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63}, + LowToHighBits<uint64_t>(UINT64_C(0xffffffffffffffff))); +} + +TEST(BitUtilsTest, TestHighToLowBits32) { + CheckElements({}, HighToLowBits<uint32_t>(0u)); + CheckElements({0}, HighToLowBits<uint32_t>(1u)); + CheckElements({15}, HighToLowBits<uint32_t>(0x8000u)); + CheckElements({31}, HighToLowBits<uint32_t>(0x80000000u)); + CheckElements({31, 0}, HighToLowBits<uint32_t>(0x80000001u)); + CheckElements({31, 7, 6, 5, 4, 3, 2, 1, 0}, HighToLowBits<uint32_t>(0x800000ffu)); + CheckElements({31, 24, 16, 8, 0}, HighToLowBits<uint32_t>(0x81010101u)); + CheckElements({31, 30, 17, 16}, HighToLowBits<uint32_t>(0xc0030000u)); + CheckElements({31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}, + HighToLowBits<uint32_t>(0xffffffffu)); +} + +TEST(BitUtilsTest, TestHighToLowBits64) { + CheckElements({}, HighToLowBits<uint64_t>(UINT64_C(0))); + CheckElements({0}, HighToLowBits<uint64_t>(UINT64_C(1))); + CheckElements({32}, HighToLowBits<uint64_t>(UINT64_C(0x100000000))); + CheckElements({63}, HighToLowBits<uint64_t>(UINT64_C(0x8000000000000000))); + CheckElements({63, 0}, HighToLowBits<uint64_t>(UINT64_C(0x8000000000000001))); + CheckElements({63, 7, 6, 5, 4, 3, 2, 1, 0}, + HighToLowBits<uint64_t>(UINT64_C(0x80000000000000ff))); + CheckElements({63, 56, 48, 40, 32, 24, 16, 8, 0}, + HighToLowBits<uint64_t>(UINT64_C(0x8101010101010101))); + CheckElements({63, 62, 17, 16}, HighToLowBits<uint64_t>(UINT64_C(0xc000000000030000))); + CheckElements({63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, + 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, + 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}, + HighToLowBits<uint64_t>(UINT64_C(0xffffffffffffffff))); +} + +} // namespace art diff --git a/runtime/base/bit_vector-inl.h b/runtime/base/bit_vector-inl.h index 39b19e5..0887798 100644 --- a/runtime/base/bit_vector-inl.h +++ b/runtime/base/bit_vector-inl.h @@ -17,9 +17,9 @@ #ifndef ART_RUNTIME_BASE_BIT_VECTOR_INL_H_ #define ART_RUNTIME_BASE_BIT_VECTOR_INL_H_ +#include "base/bit_utils.h" #include "bit_vector.h" #include "logging.h" -#include "utils.h" namespace art { diff --git a/runtime/base/bit_vector.h b/runtime/base/bit_vector.h index 6e4367a..17835f5 100644 --- a/runtime/base/bit_vector.h +++ b/runtime/base/bit_vector.h @@ -20,7 +20,7 @@ #include <stdint.h> #include <iterator> -#include "utils.h" +#include "base/bit_utils.h" namespace art { diff --git a/runtime/base/bounded_fifo.h b/runtime/base/bounded_fifo.h index d04840a..7bcd382 100644 --- a/runtime/base/bounded_fifo.h +++ b/runtime/base/bounded_fifo.h @@ -17,16 +17,19 @@ #ifndef ART_RUNTIME_BASE_BOUNDED_FIFO_H_ #define ART_RUNTIME_BASE_BOUNDED_FIFO_H_ +#include "base/bit_utils.h" +#include "base/logging.h" + namespace art { // A bounded fifo is a fifo which has a bounded size. The power of two version uses a bit mask to // avoid needing to deal with wrapping integers around or using a modulo operation. -template <typename T, const size_t MaxSize> +template <typename T, const size_t kMaxSize> class BoundedFifoPowerOfTwo { + static_assert(IsPowerOfTwo(kMaxSize), "kMaxSize must be a power of 2."); + public: BoundedFifoPowerOfTwo() { - // TODO: Do this with a compile time check. - CHECK(IsPowerOfTwo(MaxSize)); clear(); } @@ -45,7 +48,7 @@ class BoundedFifoPowerOfTwo { void push_back(const T& value) { ++size_; - DCHECK_LE(size_, MaxSize); + DCHECK_LE(size_, kMaxSize); // Relies on integer overflow behavior. data_[back_index_++ & mask_] = value; } @@ -61,9 +64,9 @@ class BoundedFifoPowerOfTwo { } private: - static const size_t mask_ = MaxSize - 1; + static const size_t mask_ = kMaxSize - 1; size_t back_index_, size_; - T data_[MaxSize]; + T data_[kMaxSize]; }; } // namespace art diff --git a/runtime/base/histogram-inl.h b/runtime/base/histogram-inl.h index 0f969b9..aba3762 100644 --- a/runtime/base/histogram-inl.h +++ b/runtime/base/histogram-inl.h @@ -17,15 +17,16 @@ #ifndef ART_RUNTIME_BASE_HISTOGRAM_INL_H_ #define ART_RUNTIME_BASE_HISTOGRAM_INL_H_ -#include "histogram.h" - -#include "utils.h" - #include <algorithm> #include <cmath> #include <limits> #include <ostream> +#include "histogram.h" + +#include "base/bit_utils.h" +#include "base/time_utils.h" + namespace art { template <class Value> inline void Histogram<Value>::AddValue(Value value) { diff --git a/runtime/base/histogram.h b/runtime/base/histogram.h index c312fb2..ef3a5d7 100644 --- a/runtime/base/histogram.h +++ b/runtime/base/histogram.h @@ -20,7 +20,6 @@ #include <string> #include "base/logging.h" -#include "utils.h" namespace art { diff --git a/runtime/base/iteration_range.h b/runtime/base/iteration_range.h new file mode 100644 index 0000000..5a46376 --- /dev/null +++ b/runtime/base/iteration_range.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2015 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_ITERATION_RANGE_H_ +#define ART_RUNTIME_BASE_ITERATION_RANGE_H_ + +namespace art { + +// Helper class that acts as a container for range-based loops, given an iteration +// range [first, last) defined by two iterators. +template <typename Iter> +class IterationRange { + public: + typedef Iter iterator; + typedef typename std::iterator_traits<Iter>::difference_type difference_type; + typedef typename std::iterator_traits<Iter>::value_type value_type; + typedef typename std::iterator_traits<Iter>::pointer pointer; + typedef typename std::iterator_traits<Iter>::reference reference; + + IterationRange(iterator first, iterator last) : first_(first), last_(last) { } + + iterator begin() const { return first_; } + iterator end() const { return last_; } + iterator cbegin() const { return first_; } + iterator cend() const { return last_; } + + private: + iterator first_; + iterator last_; +}; + +} // namespace art + +#endif // ART_RUNTIME_BASE_ITERATION_RANGE_H_ diff --git a/runtime/base/mutex-inl.h b/runtime/base/mutex-inl.h index a727992..87840e7 100644 --- a/runtime/base/mutex-inl.h +++ b/runtime/base/mutex-inl.h @@ -25,6 +25,7 @@ #include "base/value_object.h" #include "runtime.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 99c7246..5c6065d 100644 --- a/runtime/base/mutex.cc +++ b/runtime/base/mutex.cc @@ -24,12 +24,12 @@ #include "atomic.h" #include "base/logging.h" +#include "base/time_utils.h" #include "base/value_object.h" #include "mutex-inl.h" #include "runtime.h" #include "scoped_thread_state_change.h" #include "thread-inl.h" -#include "utils.h" namespace art { diff --git a/runtime/base/time_utils.cc b/runtime/base/time_utils.cc new file mode 100644 index 0000000..29b849e --- /dev/null +++ b/runtime/base/time_utils.cc @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2015 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 <inttypes.h> +#include <sstream> + +#include "time_utils.h" + +#include "base/logging.h" +#include "base/stringprintf.h" + +namespace art { + +std::string PrettyDuration(uint64_t nano_duration, size_t max_fraction_digits) { + if (nano_duration == 0) { + return "0"; + } else { + return FormatDuration(nano_duration, GetAppropriateTimeUnit(nano_duration), + max_fraction_digits); + } +} + +TimeUnit GetAppropriateTimeUnit(uint64_t nano_duration) { + const uint64_t one_sec = 1000 * 1000 * 1000; + const uint64_t one_ms = 1000 * 1000; + const uint64_t one_us = 1000; + if (nano_duration >= one_sec) { + return kTimeUnitSecond; + } else if (nano_duration >= one_ms) { + return kTimeUnitMillisecond; + } else if (nano_duration >= one_us) { + return kTimeUnitMicrosecond; + } else { + return kTimeUnitNanosecond; + } +} + +uint64_t GetNsToTimeUnitDivisor(TimeUnit time_unit) { + const uint64_t one_sec = 1000 * 1000 * 1000; + const uint64_t one_ms = 1000 * 1000; + const uint64_t one_us = 1000; + + switch (time_unit) { + case kTimeUnitSecond: + return one_sec; + case kTimeUnitMillisecond: + return one_ms; + case kTimeUnitMicrosecond: + return one_us; + case kTimeUnitNanosecond: + return 1; + } + return 0; +} + +std::string FormatDuration(uint64_t nano_duration, TimeUnit time_unit, + size_t max_fraction_digits) { + const char* unit = nullptr; + uint64_t divisor = GetNsToTimeUnitDivisor(time_unit); + switch (time_unit) { + case kTimeUnitSecond: + unit = "s"; + break; + case kTimeUnitMillisecond: + unit = "ms"; + break; + case kTimeUnitMicrosecond: + unit = "us"; + break; + case kTimeUnitNanosecond: + unit = "ns"; + break; + } + const uint64_t whole_part = nano_duration / divisor; + uint64_t fractional_part = nano_duration % divisor; + if (fractional_part == 0) { + return StringPrintf("%" PRIu64 "%s", whole_part, unit); + } else { + static constexpr size_t kMaxDigits = 30; + size_t avail_digits = kMaxDigits; + char fraction_buffer[kMaxDigits]; + char* ptr = fraction_buffer; + uint64_t multiplier = 10; + // This infinite loops if fractional part is 0. + while (avail_digits > 1 && fractional_part * multiplier < divisor) { + multiplier *= 10; + *ptr++ = '0'; + avail_digits--; + } + snprintf(ptr, avail_digits, "%" PRIu64, fractional_part); + fraction_buffer[std::min(kMaxDigits - 1, max_fraction_digits)] = '\0'; + return StringPrintf("%" PRIu64 ".%s%s", whole_part, fraction_buffer, unit); + } +} + +std::string GetIsoDate() { + time_t now = time(nullptr); + tm tmbuf; + tm* ptm = localtime_r(&now, &tmbuf); + return StringPrintf("%04d-%02d-%02d %02d:%02d:%02d", + ptm->tm_year + 1900, ptm->tm_mon+1, ptm->tm_mday, + ptm->tm_hour, ptm->tm_min, ptm->tm_sec); +} + +uint64_t MilliTime() { +#if defined(__linux__) + timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000) + now.tv_nsec / UINT64_C(1000000); +#else // __APPLE__ + timeval now; + gettimeofday(&now, nullptr); + return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000) + now.tv_usec / UINT64_C(1000); +#endif +} + +uint64_t MicroTime() { +#if defined(__linux__) + timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000) + now.tv_nsec / UINT64_C(1000); +#else // __APPLE__ + timeval now; + gettimeofday(&now, nullptr); + return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000) + now.tv_usec; +#endif +} + +uint64_t NanoTime() { +#if defined(__linux__) + timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000000) + now.tv_nsec; +#else // __APPLE__ + timeval now; + gettimeofday(&now, nullptr); + return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000000) + now.tv_usec * UINT64_C(1000); +#endif +} + +uint64_t ThreadCpuNanoTime() { +#if defined(__linux__) + timespec now; + clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now); + return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000000) + now.tv_nsec; +#else // __APPLE__ + UNIMPLEMENTED(WARNING); + return -1; +#endif +} + +void NanoSleep(uint64_t ns) { + timespec tm; + tm.tv_sec = ns / MsToNs(1000); + tm.tv_nsec = ns - static_cast<uint64_t>(tm.tv_sec) * MsToNs(1000); + nanosleep(&tm, nullptr); +} + +void InitTimeSpec(bool absolute, int clock, int64_t ms, int32_t ns, timespec* ts) { + int64_t endSec; + + if (absolute) { +#if !defined(__APPLE__) + clock_gettime(clock, ts); +#else + UNUSED(clock); + timeval tv; + gettimeofday(&tv, nullptr); + ts->tv_sec = tv.tv_sec; + ts->tv_nsec = tv.tv_usec * 1000; +#endif + } else { + ts->tv_sec = 0; + ts->tv_nsec = 0; + } + endSec = ts->tv_sec + ms / 1000; + if (UNLIKELY(endSec >= 0x7fffffff)) { + std::ostringstream ss; + LOG(INFO) << "Note: end time exceeds epoch: " << ss.str(); + endSec = 0x7ffffffe; + } + ts->tv_sec = endSec; + ts->tv_nsec = (ts->tv_nsec + (ms % 1000) * 1000000) + ns; + + // Catch rollover. + if (ts->tv_nsec >= 1000000000L) { + ts->tv_sec++; + ts->tv_nsec -= 1000000000L; + } +} + +} // namespace art diff --git a/runtime/base/time_utils.h b/runtime/base/time_utils.h new file mode 100644 index 0000000..f58c22a --- /dev/null +++ b/runtime/base/time_utils.h @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2015 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_TIME_UTILS_H_ +#define ART_RUNTIME_BASE_TIME_UTILS_H_ + +#include <stdint.h> +#include <string> +#include <time.h> + +#include "base/macros.h" + +namespace art { + +enum TimeUnit { + kTimeUnitNanosecond, + kTimeUnitMicrosecond, + kTimeUnitMillisecond, + kTimeUnitSecond, +}; + +// Returns a human-readable time string which prints every nanosecond while trying to limit the +// number of trailing zeros. Prints using the largest human readable unit up to a second. +// e.g. "1ms", "1.000000001s", "1.001us" +std::string PrettyDuration(uint64_t nano_duration, size_t max_fraction_digits = 3); + +// Format a nanosecond time to specified units. +std::string FormatDuration(uint64_t nano_duration, TimeUnit time_unit, + size_t max_fraction_digits); + +// Get the appropriate unit for a nanosecond duration. +TimeUnit GetAppropriateTimeUnit(uint64_t nano_duration); + +// Get the divisor to convert from a nanoseconds to a time unit. +uint64_t GetNsToTimeUnitDivisor(TimeUnit time_unit); + +// Returns the current date in ISO yyyy-mm-dd hh:mm:ss format. +std::string GetIsoDate(); + +// Returns the monotonic time since some unspecified starting point in milliseconds. +uint64_t MilliTime(); + +// Returns the monotonic time since some unspecified starting point in microseconds. +uint64_t MicroTime(); + +// Returns the monotonic time since some unspecified starting point in nanoseconds. +uint64_t NanoTime(); + +// Returns the thread-specific CPU-time clock in nanoseconds or -1 if unavailable. +uint64_t ThreadCpuNanoTime(); + +// Converts the given number of nanoseconds to milliseconds. +static constexpr inline uint64_t NsToMs(uint64_t ns) { + return ns / 1000 / 1000; +} + +// Converts the given number of milliseconds to nanoseconds +static constexpr inline uint64_t MsToNs(uint64_t ns) { + return ns * 1000 * 1000; +} + +#if defined(__APPLE__) +// No clocks to specify on OS/X, fake value to pass to routines that require a clock. +#define CLOCK_REALTIME 0xebadf00d +#endif + +// Sleep for the given number of nanoseconds, a bad way to handle contention. +void NanoSleep(uint64_t ns); + +// Initialize a timespec to either a relative time (ms,ns), or to the absolute +// time corresponding to the indicated clock value plus the supplied offset. +void InitTimeSpec(bool absolute, int clock, int64_t ms, int32_t ns, timespec* ts); + +} // namespace art + +#endif // ART_RUNTIME_BASE_TIME_UTILS_H_ diff --git a/runtime/base/time_utils_test.cc b/runtime/base/time_utils_test.cc new file mode 100644 index 0000000..c553f4e --- /dev/null +++ b/runtime/base/time_utils_test.cc @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2015 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 "time_utils.h" + +#include "gtest/gtest.h" + +namespace art { + +TEST(TimeUtilsTest, PrettyDuration) { + const uint64_t one_sec = 1000000000; + const uint64_t one_ms = 1000000; + const uint64_t one_us = 1000; + + EXPECT_EQ("1s", PrettyDuration(1 * one_sec)); + EXPECT_EQ("10s", PrettyDuration(10 * one_sec)); + EXPECT_EQ("100s", PrettyDuration(100 * one_sec)); + EXPECT_EQ("1.001s", PrettyDuration(1 * one_sec + one_ms)); + EXPECT_EQ("1.000001s", PrettyDuration(1 * one_sec + one_us, 6)); + EXPECT_EQ("1.000000001s", PrettyDuration(1 * one_sec + 1, 9)); + EXPECT_EQ("1.000s", PrettyDuration(1 * one_sec + one_us, 3)); + + EXPECT_EQ("1ms", PrettyDuration(1 * one_ms)); + EXPECT_EQ("10ms", PrettyDuration(10 * one_ms)); + EXPECT_EQ("100ms", PrettyDuration(100 * one_ms)); + EXPECT_EQ("1.001ms", PrettyDuration(1 * one_ms + one_us)); + EXPECT_EQ("1.000001ms", PrettyDuration(1 * one_ms + 1, 6)); + + EXPECT_EQ("1us", PrettyDuration(1 * one_us)); + EXPECT_EQ("10us", PrettyDuration(10 * one_us)); + EXPECT_EQ("100us", PrettyDuration(100 * one_us)); + EXPECT_EQ("1.001us", PrettyDuration(1 * one_us + 1)); + + EXPECT_EQ("1ns", PrettyDuration(1)); + EXPECT_EQ("10ns", PrettyDuration(10)); + EXPECT_EQ("100ns", PrettyDuration(100)); +} + +TEST(TimeUtilsTest, TestSleep) { + auto start = NanoTime(); + NanoSleep(MsToNs(1500)); + EXPECT_GT(NanoTime() - start, MsToNs(1000)); +} + +} // namespace art diff --git a/runtime/base/timing_logger.cc b/runtime/base/timing_logger.cc index b6a2aaf..f1f6f9b 100644 --- a/runtime/base/timing_logger.cc +++ b/runtime/base/timing_logger.cc @@ -22,9 +22,10 @@ #include "timing_logger.h" #include "base/logging.h" -#include "thread-inl.h" #include "base/stl_util.h" #include "base/histogram-inl.h" +#include "base/time_utils.h" +#include "thread-inl.h" #include <cmath> #include <iomanip> diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index ef94a30..3133a6d 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -30,6 +30,7 @@ #include "base/logging.h" #include "base/scoped_flock.h" #include "base/stl_util.h" +#include "base/time_utils.h" #include "base/unix_file/fd_file.h" #include "base/value_object.h" #include "class_linker-inl.h" diff --git a/runtime/debugger.cc b/runtime/debugger.cc index ef1aa6a..0752c59 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -22,6 +22,7 @@ #include "arch/context.h" #include "art_field-inl.h" +#include "base/time_utils.h" #include "class_linker.h" #include "class_linker-inl.h" #include "dex_file-inl.h" diff --git a/runtime/dex_file-inl.h b/runtime/dex_file-inl.h index 760006a..4e6c3ca 100644 --- a/runtime/dex_file-inl.h +++ b/runtime/dex_file-inl.h @@ -17,11 +17,11 @@ #ifndef ART_RUNTIME_DEX_FILE_INL_H_ #define ART_RUNTIME_DEX_FILE_INL_H_ +#include "base/bit_utils.h" #include "base/logging.h" #include "base/stringpiece.h" #include "dex_file.h" #include "leb128.h" -#include "utils.h" namespace art { diff --git a/runtime/gc/accounting/atomic_stack.h b/runtime/gc/accounting/atomic_stack.h index 399832a..ac716ea 100644 --- a/runtime/gc/accounting/atomic_stack.h +++ b/runtime/gc/accounting/atomic_stack.h @@ -22,11 +22,11 @@ #include <string> #include "atomic.h" +#include "base/bit_utils.h" #include "base/logging.h" #include "base/macros.h" #include "mem_map.h" #include "stack.h" -#include "utils.h" namespace art { namespace gc { diff --git a/runtime/gc/accounting/bitmap-inl.h b/runtime/gc/accounting/bitmap-inl.h index e87a0c0..cd3923a 100644 --- a/runtime/gc/accounting/bitmap-inl.h +++ b/runtime/gc/accounting/bitmap-inl.h @@ -22,8 +22,8 @@ #include <memory> #include "atomic.h" +#include "base/bit_utils.h" #include "base/logging.h" -#include "utils.h" namespace art { namespace gc { diff --git a/runtime/gc/accounting/bitmap.cc b/runtime/gc/accounting/bitmap.cc index 13fcdb3..fdded02 100644 --- a/runtime/gc/accounting/bitmap.cc +++ b/runtime/gc/accounting/bitmap.cc @@ -16,6 +16,7 @@ #include "bitmap-inl.h" +#include "base/bit_utils.h" #include "card_table.h" #include "mem_map.h" diff --git a/runtime/gc/accounting/card_table-inl.h b/runtime/gc/accounting/card_table-inl.h index b936d93..f72f219 100644 --- a/runtime/gc/accounting/card_table-inl.h +++ b/runtime/gc/accounting/card_table-inl.h @@ -18,11 +18,11 @@ #define ART_RUNTIME_GC_ACCOUNTING_CARD_TABLE_INL_H_ #include "atomic.h" +#include "base/bit_utils.h" #include "base/logging.h" #include "card_table.h" #include "mem_map.h" #include "space_bitmap.h" -#include "utils.h" namespace art { namespace gc { diff --git a/runtime/gc/accounting/read_barrier_table.h b/runtime/gc/accounting/read_barrier_table.h index bb9aae7..436df92 100644 --- a/runtime/gc/accounting/read_barrier_table.h +++ b/runtime/gc/accounting/read_barrier_table.h @@ -17,6 +17,7 @@ #ifndef ART_RUNTIME_GC_ACCOUNTING_READ_BARRIER_TABLE_H_ #define ART_RUNTIME_GC_ACCOUNTING_READ_BARRIER_TABLE_H_ +#include "base/bit_utils.h" #include "base/mutex.h" #include "gc/space/space.h" #include "globals.h" diff --git a/runtime/gc/accounting/space_bitmap-inl.h b/runtime/gc/accounting/space_bitmap-inl.h index ae91200..c16f5d3 100644 --- a/runtime/gc/accounting/space_bitmap-inl.h +++ b/runtime/gc/accounting/space_bitmap-inl.h @@ -22,8 +22,8 @@ #include <memory> #include "atomic.h" +#include "base/bit_utils.h" #include "base/logging.h" -#include "utils.h" namespace art { namespace gc { diff --git a/runtime/gc/allocator/dlmalloc.cc b/runtime/gc/allocator/dlmalloc.cc index 8558f96..3d85395 100644 --- a/runtime/gc/allocator/dlmalloc.cc +++ b/runtime/gc/allocator/dlmalloc.cc @@ -16,6 +16,7 @@ #include "dlmalloc.h" +#include "base/bit_utils.h" #include "base/logging.h" // ART specific morecore implementation defined in space.cc. diff --git a/runtime/gc/allocator/rosalloc.h b/runtime/gc/allocator/rosalloc.h index a54edcc..0fcfe72 100644 --- a/runtime/gc/allocator/rosalloc.h +++ b/runtime/gc/allocator/rosalloc.h @@ -27,11 +27,11 @@ #include <vector> #include "base/allocator.h" +#include "base/bit_utils.h" #include "base/mutex.h" #include "base/logging.h" #include "globals.h" #include "thread.h" -#include "utils.h" namespace art { diff --git a/runtime/gc/collector/garbage_collector.cc b/runtime/gc/collector/garbage_collector.cc index 47d6ada..afd0a30 100644 --- a/runtime/gc/collector/garbage_collector.cc +++ b/runtime/gc/collector/garbage_collector.cc @@ -25,11 +25,13 @@ #include "base/histogram-inl.h" #include "base/logging.h" #include "base/mutex-inl.h" +#include "base/time_utils.h" #include "gc/accounting/heap_bitmap.h" #include "gc/space/large_object_space.h" #include "gc/space/space-inl.h" #include "thread-inl.h" #include "thread_list.h" +#include "utils.h" namespace art { namespace gc { diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc index 2db5650..2a9c03d 100644 --- a/runtime/gc/collector/mark_sweep.cc +++ b/runtime/gc/collector/mark_sweep.cc @@ -29,6 +29,7 @@ #include "base/logging.h" #include "base/macros.h" #include "base/mutex-inl.h" +#include "base/time_utils.h" #include "base/timing_logger.h" #include "gc/accounting/card_table-inl.h" #include "gc/accounting/heap_bitmap-inl.h" diff --git a/runtime/gc/heap-inl.h b/runtime/gc/heap-inl.h index fbf36e8..eb0e9be 100644 --- a/runtime/gc/heap-inl.h +++ b/runtime/gc/heap-inl.h @@ -19,6 +19,7 @@ #include "heap.h" +#include "base/time_utils.h" #include "debugger.h" #include "gc/accounting/card_table-inl.h" #include "gc/collector/semi_space.h" @@ -31,6 +32,7 @@ #include "handle_scope-inl.h" #include "thread.h" #include "thread-inl.h" +#include "utils.h" #include "verify_object-inl.h" namespace art { diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index 11a0e3c..fbde494 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -28,6 +28,7 @@ #include "base/dumpable.h" #include "base/histogram-inl.h" #include "base/stl_util.h" +#include "base/time_utils.h" #include "common_throws.h" #include "cutils/sched_policy.h" #include "debugger.h" diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h index 90249f9..c72414a 100644 --- a/runtime/gc/heap.h +++ b/runtime/gc/heap.h @@ -24,6 +24,7 @@ #include "allocator_type.h" #include "arch/instruction_set.h" #include "atomic.h" +#include "base/time_utils.h" #include "base/timing_logger.h" #include "gc/accounting/atomic_stack.h" #include "gc/accounting/card_table.h" diff --git a/runtime/gc/reference_processor.cc b/runtime/gc/reference_processor.cc index 01e8795..5af2a53 100644 --- a/runtime/gc/reference_processor.cc +++ b/runtime/gc/reference_processor.cc @@ -16,6 +16,7 @@ #include "reference_processor.h" +#include "base/time_utils.h" #include "mirror/object-inl.h" #include "mirror/reference.h" #include "mirror/reference-inl.h" @@ -24,6 +25,7 @@ #include "ScopedLocalRef.h" #include "scoped_thread_state_change.h" #include "task_processor.h" +#include "utils.h" #include "well_known_classes.h" namespace art { diff --git a/runtime/gc/space/bump_pointer_space-inl.h b/runtime/gc/space/bump_pointer_space-inl.h index 14a93d1..d9ad9a3 100644 --- a/runtime/gc/space/bump_pointer_space-inl.h +++ b/runtime/gc/space/bump_pointer_space-inl.h @@ -17,6 +17,7 @@ #ifndef ART_RUNTIME_GC_SPACE_BUMP_POINTER_SPACE_INL_H_ #define ART_RUNTIME_GC_SPACE_BUMP_POINTER_SPACE_INL_H_ +#include "base/bit_utils.h" #include "bump_pointer_space.h" namespace art { diff --git a/runtime/gc/space/dlmalloc_space.cc b/runtime/gc/space/dlmalloc_space.cc index 7b1a421..5237c7b 100644 --- a/runtime/gc/space/dlmalloc_space.cc +++ b/runtime/gc/space/dlmalloc_space.cc @@ -16,6 +16,7 @@ #include "dlmalloc_space-inl.h" +#include "base/time_utils.h" #include "gc/accounting/card_table.h" #include "gc/accounting/space_bitmap-inl.h" #include "gc/heap.h" diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index 99f5d45..ade9cec 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -25,8 +25,9 @@ #include "base/macros.h" #include "base/stl_util.h" -#include "base/unix_file/fd_file.h" #include "base/scoped_flock.h" +#include "base/time_utils.h" +#include "base/unix_file/fd_file.h" #include "gc/accounting/space_bitmap-inl.h" #include "mirror/art_method.h" #include "mirror/class-inl.h" diff --git a/runtime/gc/space/large_object_space.cc b/runtime/gc/space/large_object_space.cc index 4dfdaa5..da4a930 100644 --- a/runtime/gc/space/large_object_space.cc +++ b/runtime/gc/space/large_object_space.cc @@ -27,7 +27,6 @@ #include "os.h" #include "space-inl.h" #include "thread-inl.h" -#include "utils.h" namespace art { namespace gc { diff --git a/runtime/gc/space/large_object_space_test.cc b/runtime/gc/space/large_object_space_test.cc index a261663..f04a7ca 100644 --- a/runtime/gc/space/large_object_space_test.cc +++ b/runtime/gc/space/large_object_space_test.cc @@ -14,6 +14,7 @@ * limitations under the License. */ +#include "base/time_utils.h" #include "space_test.h" #include "large_object_space.h" diff --git a/runtime/gc/space/rosalloc_space.cc b/runtime/gc/space/rosalloc_space.cc index 2c7d93e..bc4414d 100644 --- a/runtime/gc/space/rosalloc_space.cc +++ b/runtime/gc/space/rosalloc_space.cc @@ -20,6 +20,7 @@ #define ATRACE_TAG ATRACE_TAG_DALVIK #include "cutils/trace.h" +#include "base/time_utils.h" #include "gc/accounting/card_table.h" #include "gc/accounting/space_bitmap-inl.h" #include "gc/heap.h" diff --git a/runtime/gc/task_processor.cc b/runtime/gc/task_processor.cc index ef34c68..a49121b 100644 --- a/runtime/gc/task_processor.cc +++ b/runtime/gc/task_processor.cc @@ -16,6 +16,7 @@ #include "task_processor.h" +#include "base/time_utils.h" #include "scoped_thread_state_change.h" namespace art { diff --git a/runtime/gc/task_processor_test.cc b/runtime/gc/task_processor_test.cc index 5dd6d8f..f06f68d 100644 --- a/runtime/gc/task_processor_test.cc +++ b/runtime/gc/task_processor_test.cc @@ -14,11 +14,11 @@ * limitations under the License. */ +#include "base/time_utils.h" #include "common_runtime_test.h" #include "task_processor.h" #include "thread_pool.h" #include "thread-inl.h" -#include "utils.h" namespace art { namespace gc { diff --git a/runtime/handle_scope.h b/runtime/handle_scope.h index 271312e..ac28c8a 100644 --- a/runtime/handle_scope.h +++ b/runtime/handle_scope.h @@ -23,7 +23,6 @@ #include "base/macros.h" #include "handle.h" #include "stack.h" -#include "utils.h" #include "verify_object.h" namespace art { diff --git a/runtime/hprof/hprof.cc b/runtime/hprof/hprof.cc index efead51..88a72ec 100644 --- a/runtime/hprof/hprof.cc +++ b/runtime/hprof/hprof.cc @@ -40,6 +40,7 @@ #include "art_field-inl.h" #include "base/logging.h" #include "base/stringprintf.h" +#include "base/time_utils.h" #include "base/unix_file/fd_file.h" #include "class_linker.h" #include "common_throws.h" diff --git a/runtime/image.cc b/runtime/image.cc index 2d8c1c4..d9bd2a8 100644 --- a/runtime/image.cc +++ b/runtime/image.cc @@ -16,10 +16,10 @@ #include "image.h" +#include "base/bit_utils.h" #include "mirror/object_array.h" #include "mirror/object_array-inl.h" #include "mirror/object-inl.h" -#include "utils.h" namespace art { diff --git a/runtime/image.h b/runtime/image.h index 613414a..52995ed 100644 --- a/runtime/image.h +++ b/runtime/image.h @@ -21,7 +21,6 @@ #include "globals.h" #include "mirror/object.h" -#include "utils.h" namespace art { diff --git a/runtime/jdwp/jdwp_handler.cc b/runtime/jdwp/jdwp_handler.cc index 8e9ab32..f7f70f6 100644 --- a/runtime/jdwp/jdwp_handler.cc +++ b/runtime/jdwp/jdwp_handler.cc @@ -32,6 +32,7 @@ #include "jdwp/jdwp_priv.h" #include "runtime.h" #include "thread-inl.h" +#include "utils.h" namespace art { diff --git a/runtime/jdwp/jdwp_main.cc b/runtime/jdwp/jdwp_main.cc index 5b30f0c..e6b97a2 100644 --- a/runtime/jdwp/jdwp_main.cc +++ b/runtime/jdwp/jdwp_main.cc @@ -22,6 +22,7 @@ #include "atomic.h" #include "base/logging.h" +#include "base/time_utils.h" #include "debugger.h" #include "jdwp/jdwp_priv.h" #include "scoped_thread_state_change.h" diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h index c698cfc..8f92453 100644 --- a/runtime/jit/jit.h +++ b/runtime/jit/jit.h @@ -33,6 +33,10 @@ namespace art { class CompilerCallbacks; struct RuntimeArgumentMap; +namespace mirror { +class ArtMethod; +} // namespace mirror + namespace jit { class JitCodeCache; diff --git a/runtime/jit/jit_code_cache_test.cc b/runtime/jit/jit_code_cache_test.cc index 2155552..afa5a3e 100644 --- a/runtime/jit/jit_code_cache_test.cc +++ b/runtime/jit/jit_code_cache_test.cc @@ -21,7 +21,6 @@ #include "mirror/art_method-inl.h" #include "scoped_thread_state_change.h" #include "thread-inl.h" -#include "utils.h" namespace art { namespace jit { diff --git a/runtime/leb128.h b/runtime/leb128.h index 2e27b8e..14683d4 100644 --- a/runtime/leb128.h +++ b/runtime/leb128.h @@ -17,8 +17,11 @@ #ifndef ART_RUNTIME_LEB128_H_ #define ART_RUNTIME_LEB128_H_ +#include <vector> + +#include "base/bit_utils.h" +#include "base/logging.h" #include "globals.h" -#include "utils.h" namespace art { diff --git a/runtime/leb128_test.cc b/runtime/leb128_test.cc index 87e13ff..1bb493d 100644 --- a/runtime/leb128_test.cc +++ b/runtime/leb128_test.cc @@ -18,6 +18,7 @@ #include "gtest/gtest.h" #include "base/histogram-inl.h" +#include "base/time_utils.h" namespace art { diff --git a/runtime/lock_word.h b/runtime/lock_word.h index 655aa3a..aafbfe4 100644 --- a/runtime/lock_word.h +++ b/runtime/lock_word.h @@ -20,9 +20,9 @@ #include <iosfwd> #include <stdint.h> +#include "base/bit_utils.h" #include "base/logging.h" #include "read_barrier.h" -#include "utils.h" namespace art { namespace mirror { diff --git a/runtime/memory_region.h b/runtime/memory_region.h index 6a784eb..13c69ac 100644 --- a/runtime/memory_region.h +++ b/runtime/memory_region.h @@ -18,13 +18,15 @@ #define ART_RUNTIME_MEMORY_REGION_H_ #include <stdint.h> +#include <type_traits> +#include "arch/instruction_set.h" +#include "base/bit_utils.h" #include "base/casts.h" #include "base/logging.h" #include "base/macros.h" #include "base/value_object.h" #include "globals.h" -#include "utils.h" namespace art { @@ -71,7 +73,7 @@ class MemoryRegion FINAL : public ValueObject { template<typename T> ALWAYS_INLINE T LoadUnaligned(uintptr_t offset) const { // Equivalent unsigned integer type corresponding to T. - typedef typename UnsignedIntegerType<sizeof(T)>::type U; + typedef typename std::make_unsigned<T>::type U; U equivalent_unsigned_integer_value = 0; // Read the value byte by byte in a little-endian fashion. for (size_t i = 0; i < sizeof(U); ++i) { @@ -86,7 +88,7 @@ class MemoryRegion FINAL : public ValueObject { template<typename T> ALWAYS_INLINE void StoreUnaligned(uintptr_t offset, T value) const { // Equivalent unsigned integer type corresponding to T. - typedef typename UnsignedIntegerType<sizeof(T)>::type U; + typedef typename std::make_unsigned<T>::type U; U equivalent_unsigned_integer_value = bit_cast<U, T>(value); // Write the value byte by byte in a little-endian fashion. for (size_t i = 0; i < sizeof(U); ++i) { diff --git a/runtime/mirror/array-inl.h b/runtime/mirror/array-inl.h index 8b3418d..e93717e 100644 --- a/runtime/mirror/array-inl.h +++ b/runtime/mirror/array-inl.h @@ -19,11 +19,13 @@ #include "array.h" +#include "base/bit_utils.h" +#include "base/logging.h" #include "base/stringprintf.h" +#include "base/casts.h" #include "class.h" #include "gc/heap-inl.h" #include "thread.h" -#include "utils.h" namespace art { namespace mirror { diff --git a/runtime/mirror/art_method-inl.h b/runtime/mirror/art_method-inl.h index 0f306e8..7c8067a 100644 --- a/runtime/mirror/art_method-inl.h +++ b/runtime/mirror/art_method-inl.h @@ -31,6 +31,7 @@ #include "quick/quick_method_frame_info.h" #include "read_barrier-inl.h" #include "runtime-inl.h" +#include "utils.h" namespace art { namespace mirror { diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h index cc6f5c4..5752a15 100644 --- a/runtime/mirror/class-inl.h +++ b/runtime/mirror/class-inl.h @@ -32,6 +32,7 @@ #include "reference-inl.h" #include "runtime.h" #include "string.h" +#include "utils.h" namespace art { namespace mirror { diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index d3cfd01..b99fc68 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -27,7 +27,6 @@ #include "object_callbacks.h" #include "primitive.h" #include "read_barrier_option.h" -#include "utils.h" #ifndef IMT_SIZE #error IMT_SIZE not defined diff --git a/runtime/mirror/object_array-inl.h b/runtime/mirror/object_array-inl.h index d473816..bef4af6 100644 --- a/runtime/mirror/object_array-inl.h +++ b/runtime/mirror/object_array-inl.h @@ -17,6 +17,8 @@ #ifndef ART_RUNTIME_MIRROR_OBJECT_ARRAY_INL_H_ #define ART_RUNTIME_MIRROR_OBJECT_ARRAY_INL_H_ +#include <string> + #include "object_array.h" #include "array-inl.h" @@ -26,7 +28,7 @@ #include "runtime.h" #include "handle_scope-inl.h" #include "thread.h" -#include <string> +#include "utils.h" namespace art { namespace mirror { diff --git a/runtime/mirror/string-inl.h b/runtime/mirror/string-inl.h index cd5d2f6..35b8aef 100644 --- a/runtime/mirror/string-inl.h +++ b/runtime/mirror/string-inl.h @@ -25,6 +25,7 @@ #include "string.h" #include "thread.h" #include "utf.h" +#include "utils.h" namespace art { namespace mirror { diff --git a/runtime/monitor.cc b/runtime/monitor.cc index 4b41225..dc016a5 100644 --- a/runtime/monitor.cc +++ b/runtime/monitor.cc @@ -23,6 +23,7 @@ #include "base/mutex.h" #include "base/stl_util.h" +#include "base/time_utils.h" #include "class_linker.h" #include "dex_file-inl.h" #include "dex_instruction.h" diff --git a/runtime/monitor_test.cc b/runtime/monitor_test.cc index 30cb2d8..2a29c60 100644 --- a/runtime/monitor_test.cc +++ b/runtime/monitor_test.cc @@ -20,6 +20,7 @@ #include <string> #include "atomic.h" +#include "base/time_utils.h" #include "class_linker-inl.h" #include "common_runtime_test.h" #include "handle_scope-inl.h" @@ -27,7 +28,6 @@ #include "mirror/string-inl.h" // Strings are easiest to allocate #include "scoped_thread_state_change.h" #include "thread_pool.h" -#include "utils.h" namespace art { diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc index 46881b0..1078492 100644 --- a/runtime/native/dalvik_system_VMDebug.cc +++ b/runtime/native/dalvik_system_VMDebug.cc @@ -22,6 +22,7 @@ #include <sstream> #include "base/histogram-inl.h" +#include "base/time_utils.h" #include "class_linker.h" #include "common_throws.h" #include "debugger.h" diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc index 721b7a3..d6aa9b5 100644 --- a/runtime/native/java_lang_reflect_Field.cc +++ b/runtime/native/java_lang_reflect_Field.cc @@ -26,6 +26,7 @@ #include "mirror/field.h" #include "reflection-inl.h" #include "scoped_fast_native_object_access.h" +#include "utils.h" namespace art { diff --git a/runtime/oat.cc b/runtime/oat.cc index 4f6aabc..1dd2aad 100644 --- a/runtime/oat.cc +++ b/runtime/oat.cc @@ -20,8 +20,8 @@ #include <zlib.h> #include "arch/instruction_set_features.h" +#include "base/bit_utils.h" #include "base/stringprintf.h" -#include "utils.h" namespace art { diff --git a/runtime/profiler.cc b/runtime/profiler.cc index 5354fd8..f9218a3 100644 --- a/runtime/profiler.cc +++ b/runtime/profiler.cc @@ -23,6 +23,7 @@ #include <fstream> #include "base/stl_util.h" +#include "base/time_utils.h" #include "base/unix_file/fd_file.h" #include "class_linker.h" #include "common_throws.h" @@ -39,6 +40,7 @@ #include "ScopedLocalRef.h" #include "thread.h" #include "thread_list.h" +#include "utils.h" #include "entrypoints/quick/quick_entrypoints.h" diff --git a/runtime/read_barrier-inl.h b/runtime/read_barrier-inl.h index 5631ff4..d341ee1 100644 --- a/runtime/read_barrier-inl.h +++ b/runtime/read_barrier-inl.h @@ -24,6 +24,7 @@ #include "mirror/object_reference.h" #include "mirror/reference.h" #include "runtime.h" +#include "utils.h" namespace art { diff --git a/runtime/signal_catcher.cc b/runtime/signal_catcher.cc index 863d59b..9f8c55c 100644 --- a/runtime/signal_catcher.cc +++ b/runtime/signal_catcher.cc @@ -28,6 +28,7 @@ #include <sstream> #include "arch/instruction_set.h" +#include "base/time_utils.h" #include "base/unix_file/fd_file.h" #include "class_linker.h" #include "gc/heap.h" diff --git a/runtime/stack.h b/runtime/stack.h index bf61016..4d36573 100644 --- a/runtime/stack.h +++ b/runtime/stack.h @@ -21,11 +21,11 @@ #include <string> #include "arch/instruction_set.h" +#include "base/bit_utils.h" #include "dex_file.h" #include "gc_root.h" #include "mirror/object_reference.h" #include "read_barrier.h" -#include "utils.h" #include "verify_object.h" namespace art { diff --git a/runtime/stack_map.h b/runtime/stack_map.h index f68cafe..6cc1709 100644 --- a/runtime/stack_map.h +++ b/runtime/stack_map.h @@ -18,8 +18,8 @@ #define ART_RUNTIME_STACK_MAP_H_ #include "base/bit_vector.h" +#include "base/bit_utils.h" #include "memory_region.h" -#include "utils.h" namespace art { diff --git a/runtime/thread.cc b/runtime/thread.cc index 2145c9c..b3b55c4 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -33,6 +33,7 @@ #include "arch/context.h" #include "art_field-inl.h" +#include "base/bit_utils.h" #include "base/mutex.h" #include "base/timing_logger.h" #include "base/to_str.h" diff --git a/runtime/thread.h b/runtime/thread.h index 9346813..96e0916 100644 --- a/runtime/thread.h +++ b/runtime/thread.h @@ -61,6 +61,7 @@ namespace mirror { template<class T> class PrimitiveArray; typedef PrimitiveArray<int32_t> IntArray; class StackTraceElement; + class String; class Throwable; } // namespace mirror diff --git a/runtime/thread_linux.cc b/runtime/thread_linux.cc index 0526f49..0731f30 100644 --- a/runtime/thread_linux.cc +++ b/runtime/thread_linux.cc @@ -14,10 +14,11 @@ * limitations under the License. */ -#include "thread.h" - #include <signal.h> +#include "thread.h" +#include "utils.h" + namespace art { void Thread::SetNativePriority(int) { diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc index cc54bbd..7719bb8 100644 --- a/runtime/thread_list.cc +++ b/runtime/thread_list.cc @@ -30,6 +30,7 @@ #include "base/histogram-inl.h" #include "base/mutex.h" #include "base/mutex-inl.h" +#include "base/time_utils.h" #include "base/timing_logger.h" #include "debugger.h" #include "jni_internal.h" @@ -38,7 +39,6 @@ #include "scoped_thread_state_change.h" #include "thread.h" #include "trace.h" -#include "utils.h" #include "well_known_classes.h" namespace art { diff --git a/runtime/thread_pool.cc b/runtime/thread_pool.cc index ce76eae..1e84c9d 100644 --- a/runtime/thread_pool.cc +++ b/runtime/thread_pool.cc @@ -18,6 +18,7 @@ #include "base/casts.h" #include "base/stl_util.h" +#include "base/time_utils.h" #include "runtime.h" #include "thread-inl.h" diff --git a/runtime/trace.cc b/runtime/trace.cc index 7636792..f874716 100644 --- a/runtime/trace.cc +++ b/runtime/trace.cc @@ -24,6 +24,7 @@ #include "base/casts.h" #include "base/stl_util.h" +#include "base/time_utils.h" #include "base/unix_file/fd_file.h" #include "class_linker.h" #include "common_throws.h" @@ -40,6 +41,7 @@ #include "ScopedLocalRef.h" #include "thread.h" #include "thread_list.h" +#include "utils.h" #include "entrypoints/quick/quick_entrypoints.h" namespace art { diff --git a/runtime/utils.cc b/runtime/utils.cc index 7986cdc..fabf9bd 100644 --- a/runtime/utils.cc +++ b/runtime/utils.cc @@ -204,102 +204,6 @@ bool PrintFileToLog(const std::string& file_name, LogSeverity level) { } } -std::string GetIsoDate() { - time_t now = time(nullptr); - tm tmbuf; - tm* ptm = localtime_r(&now, &tmbuf); - return StringPrintf("%04d-%02d-%02d %02d:%02d:%02d", - ptm->tm_year + 1900, ptm->tm_mon+1, ptm->tm_mday, - ptm->tm_hour, ptm->tm_min, ptm->tm_sec); -} - -uint64_t MilliTime() { -#if defined(__linux__) - timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000) + now.tv_nsec / UINT64_C(1000000); -#else // __APPLE__ - timeval now; - gettimeofday(&now, nullptr); - return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000) + now.tv_usec / UINT64_C(1000); -#endif -} - -uint64_t MicroTime() { -#if defined(__linux__) - timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000) + now.tv_nsec / UINT64_C(1000); -#else // __APPLE__ - timeval now; - gettimeofday(&now, nullptr); - return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000) + now.tv_usec; -#endif -} - -uint64_t NanoTime() { -#if defined(__linux__) - timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000000) + now.tv_nsec; -#else // __APPLE__ - timeval now; - gettimeofday(&now, nullptr); - return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000000) + now.tv_usec * UINT64_C(1000); -#endif -} - -uint64_t ThreadCpuNanoTime() { -#if defined(__linux__) - timespec now; - clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now); - return static_cast<uint64_t>(now.tv_sec) * UINT64_C(1000000000) + now.tv_nsec; -#else // __APPLE__ - UNIMPLEMENTED(WARNING); - return -1; -#endif -} - -void NanoSleep(uint64_t ns) { - timespec tm; - tm.tv_sec = ns / MsToNs(1000); - tm.tv_nsec = ns - static_cast<uint64_t>(tm.tv_sec) * MsToNs(1000); - nanosleep(&tm, nullptr); -} - -void InitTimeSpec(bool absolute, int clock, int64_t ms, int32_t ns, timespec* ts) { - int64_t endSec; - - if (absolute) { -#if !defined(__APPLE__) - clock_gettime(clock, ts); -#else - UNUSED(clock); - timeval tv; - gettimeofday(&tv, nullptr); - ts->tv_sec = tv.tv_sec; - ts->tv_nsec = tv.tv_usec * 1000; -#endif - } else { - ts->tv_sec = 0; - ts->tv_nsec = 0; - } - endSec = ts->tv_sec + ms / 1000; - if (UNLIKELY(endSec >= 0x7fffffff)) { - std::ostringstream ss; - LOG(INFO) << "Note: end time exceeds epoch: " << ss.str(); - endSec = 0x7ffffffe; - } - ts->tv_sec = endSec; - ts->tv_nsec = (ts->tv_nsec + (ms % 1000) * 1000000) + ns; - - // Catch rollover. - if (ts->tv_nsec >= 1000000000L) { - ts->tv_sec++; - ts->tv_nsec -= 1000000000L; - } -} - std::string PrettyDescriptor(mirror::String* java_descriptor) { if (java_descriptor == nullptr) { return "null"; @@ -578,88 +482,6 @@ std::string PrettySize(int64_t byte_count) { negative_str, byte_count / kBytesPerUnit[i], kUnitStrings[i]); } -std::string PrettyDuration(uint64_t nano_duration, size_t max_fraction_digits) { - if (nano_duration == 0) { - return "0"; - } else { - return FormatDuration(nano_duration, GetAppropriateTimeUnit(nano_duration), - max_fraction_digits); - } -} - -TimeUnit GetAppropriateTimeUnit(uint64_t nano_duration) { - const uint64_t one_sec = 1000 * 1000 * 1000; - const uint64_t one_ms = 1000 * 1000; - const uint64_t one_us = 1000; - if (nano_duration >= one_sec) { - return kTimeUnitSecond; - } else if (nano_duration >= one_ms) { - return kTimeUnitMillisecond; - } else if (nano_duration >= one_us) { - return kTimeUnitMicrosecond; - } else { - return kTimeUnitNanosecond; - } -} - -uint64_t GetNsToTimeUnitDivisor(TimeUnit time_unit) { - const uint64_t one_sec = 1000 * 1000 * 1000; - const uint64_t one_ms = 1000 * 1000; - const uint64_t one_us = 1000; - - switch (time_unit) { - case kTimeUnitSecond: - return one_sec; - case kTimeUnitMillisecond: - return one_ms; - case kTimeUnitMicrosecond: - return one_us; - case kTimeUnitNanosecond: - return 1; - } - return 0; -} - -std::string FormatDuration(uint64_t nano_duration, TimeUnit time_unit, - size_t max_fraction_digits) { - const char* unit = nullptr; - uint64_t divisor = GetNsToTimeUnitDivisor(time_unit); - switch (time_unit) { - case kTimeUnitSecond: - unit = "s"; - break; - case kTimeUnitMillisecond: - unit = "ms"; - break; - case kTimeUnitMicrosecond: - unit = "us"; - break; - case kTimeUnitNanosecond: - unit = "ns"; - break; - } - const uint64_t whole_part = nano_duration / divisor; - uint64_t fractional_part = nano_duration % divisor; - if (fractional_part == 0) { - return StringPrintf("%" PRIu64 "%s", whole_part, unit); - } else { - static constexpr size_t kMaxDigits = 30; - size_t avail_digits = kMaxDigits; - char fraction_buffer[kMaxDigits]; - char* ptr = fraction_buffer; - uint64_t multiplier = 10; - // This infinite loops if fractional part is 0. - while (avail_digits > 1 && fractional_part * multiplier < divisor) { - multiplier *= 10; - *ptr++ = '0'; - avail_digits--; - } - snprintf(ptr, avail_digits, "%" PRIu64, fractional_part); - fraction_buffer[std::min(kMaxDigits - 1, max_fraction_digits)] = '\0'; - return StringPrintf("%" PRIu64 ".%s%s", whole_part, fraction_buffer, unit); - } -} - std::string PrintableChar(uint16_t ch) { std::string result; result += '\''; diff --git a/runtime/utils.h b/runtime/utils.h index 71ccf85..e7532e1 100644 --- a/runtime/utils.h +++ b/runtime/utils.h @@ -43,13 +43,6 @@ class Object; class String; } // namespace mirror -enum TimeUnit { - kTimeUnitNanosecond, - kTimeUnitMicrosecond, - kTimeUnitMillisecond, - kTimeUnitSecond, -}; - template <typename T> bool ParseUint(const char *in, T* out) { char* end; @@ -78,228 +71,6 @@ bool ParseInt(const char* in, T* out) { return true; } -template<typename T> -static constexpr bool IsPowerOfTwo(T x) { - return (x & (x - 1)) == 0; -} - -template<int n, typename T> -static inline bool IsAligned(T x) { - static_assert((n & (n - 1)) == 0, "n is not a power of two"); - return (x & (n - 1)) == 0; -} - -template<int n, typename T> -static inline bool IsAligned(T* x) { - return IsAligned<n>(reinterpret_cast<const uintptr_t>(x)); -} - -template<typename T> -static inline bool IsAlignedParam(T x, int n) { - return (x & (n - 1)) == 0; -} - -#define CHECK_ALIGNED(value, alignment) \ - CHECK(::art::IsAligned<alignment>(value)) << reinterpret_cast<const void*>(value) - -#define DCHECK_ALIGNED(value, alignment) \ - DCHECK(::art::IsAligned<alignment>(value)) << reinterpret_cast<const void*>(value) - -#define DCHECK_ALIGNED_PARAM(value, alignment) \ - DCHECK(::art::IsAlignedParam(value, alignment)) << reinterpret_cast<const void*>(value) - -// Check whether an N-bit two's-complement representation can hold value. -template <typename T> -static inline bool IsInt(int N, T value) { - int bitsPerT = sizeof(T) * kBitsPerByte; - if (N == bitsPerT) { - return true; - } else { - CHECK_LT(0, N); - CHECK_LT(N, bitsPerT); - T limit = static_cast<T>(1) << (N - 1); - return (-limit <= value) && (value < limit); - } -} - -template <typename T> -static constexpr T GetIntLimit(size_t bits) { - return - DCHECK_CONSTEXPR(bits > 0, "bits cannot be zero", 0) - DCHECK_CONSTEXPR(bits < kBitsPerByte * sizeof(T), "kBits must be < max.", 0) - static_cast<T>(1) << (bits - 1); -} - -template <size_t kBits, typename T> -static constexpr bool IsInt(T value) { - static_assert(kBits > 0, "kBits cannot be zero."); - static_assert(kBits <= kBitsPerByte * sizeof(T), "kBits must be <= max."); - static_assert(std::is_signed<T>::value, "Needs a signed type."); - // Corner case for "use all bits." Can't use the limits, as they would overflow, but it is - // trivially true. - return (kBits == kBitsPerByte * sizeof(T)) ? - true : - (-GetIntLimit<T>(kBits) <= value) && (value < GetIntLimit<T>(kBits)); -} - -template <size_t kBits, typename T> -static constexpr bool IsUint(T value) { - static_assert(kBits > 0, "kBits cannot be zero."); - static_assert(kBits <= kBitsPerByte * sizeof(T), "kBits must be <= max."); - static_assert(std::is_integral<T>::value, "Needs an integral type."); - // Corner case for "use all bits." Can't use the limits, as they would overflow, but it is - // trivially true. - return (0 <= value) && - (kBits == kBitsPerByte * sizeof(T) || - (static_cast<typename std::make_unsigned<T>::type>(value) <= - GetIntLimit<typename std::make_unsigned<T>::type>(kBits + 1) - 1)); -} - -template <size_t kBits, typename T> -static constexpr bool IsAbsoluteUint(T value) { - static_assert(kBits <= kBitsPerByte * sizeof(T), "kBits must be < max."); - return (kBits == kBitsPerByte * sizeof(T)) ? - true : - IsUint<kBits, T>(value < 0 ? -value : value); -} - -static inline uint16_t Low16Bits(uint32_t value) { - return static_cast<uint16_t>(value); -} - -static inline uint16_t High16Bits(uint32_t value) { - return static_cast<uint16_t>(value >> 16); -} - -static inline uint32_t Low32Bits(uint64_t value) { - return static_cast<uint32_t>(value); -} - -static inline uint32_t High32Bits(uint64_t value) { - return static_cast<uint32_t>(value >> 32); -} - -// Traits class providing an unsigned integer type of (byte) size `n`. -template <size_t n> -struct UnsignedIntegerType { - // No defined `type`. -}; - -template <> -struct UnsignedIntegerType<1> { typedef uint8_t type; }; - -template <> -struct UnsignedIntegerType<2> { typedef uint16_t type; }; - -template <> -struct UnsignedIntegerType<4> { typedef uint32_t type; }; - -template <> -struct UnsignedIntegerType<8> { typedef uint64_t type; }; - -// Type identity. -template <typename T> -struct TypeIdentity { - typedef T type; -}; - -// Like sizeof, but count how many bits a type takes. Pass type explicitly. -template <typename T> -static constexpr size_t BitSizeOf() { - return sizeof(T) * CHAR_BIT; -} - -// Like sizeof, but count how many bits a type takes. Infers type from parameter. -template <typename T> -static constexpr size_t BitSizeOf(T /*x*/) { - return sizeof(T) * CHAR_BIT; -} - -// For rounding integers. -template<typename T> -static constexpr T RoundDown(T x, typename TypeIdentity<T>::type n) WARN_UNUSED; - -template<typename T> -static constexpr T RoundDown(T x, typename TypeIdentity<T>::type n) { - return - DCHECK_CONSTEXPR(IsPowerOfTwo(n), , T(0)) - (x & -n); -} - -template<typename T> -static constexpr T RoundUp(T x, typename TypeIdentity<T>::type n) WARN_UNUSED; - -template<typename T> -static constexpr T RoundUp(T x, typename TypeIdentity<T>::type n) { - return RoundDown(x + n - 1, n); -} - -// For aligning pointers. -template<typename T> -static inline T* AlignDown(T* x, uintptr_t n) WARN_UNUSED; - -template<typename T> -static inline T* AlignDown(T* x, uintptr_t n) { - return reinterpret_cast<T*>(RoundDown(reinterpret_cast<uintptr_t>(x), n)); -} - -template<typename T> -static inline T* AlignUp(T* x, uintptr_t n) WARN_UNUSED; - -template<typename T> -static inline T* AlignUp(T* x, uintptr_t n) { - return reinterpret_cast<T*>(RoundUp(reinterpret_cast<uintptr_t>(x), n)); -} - -namespace utils { -namespace detail { // Private, implementation-specific namespace. Do not poke outside of this file. -template <typename T> -static constexpr inline T RoundUpToPowerOfTwoRecursive(T x, size_t bit) { - return bit == (BitSizeOf<T>()) ? x: RoundUpToPowerOfTwoRecursive(x | x >> bit, bit << 1); -} -} // namespace detail -} // namespace utils - -// Recursive implementation is from "Hacker's Delight" by Henry S. Warren, Jr., -// figure 3-3, page 48, where the function is called clp2. -template <typename T> -static constexpr inline T RoundUpToPowerOfTwo(T x) { - return art::utils::detail::RoundUpToPowerOfTwoRecursive(x - 1, 1) + 1; -} - -// Find the bit position of the most significant bit (0-based), or -1 if there were no bits set. -template <typename T> -static constexpr ssize_t MostSignificantBit(T value) { - return (value == 0) ? -1 : (MostSignificantBit(value >> 1) + 1); -} - -// How many bits (minimally) does it take to store the constant 'value'? i.e. 1 for 1, 3 for 5, etc. -template <typename T> -static constexpr size_t MinimumBitsToStore(T value) { - return static_cast<size_t>(MostSignificantBit(value) + 1); -} - -template<typename T> -static constexpr int CLZ(T x) { - static_assert(sizeof(T) <= sizeof(long long), "T too large, must be smaller than long long"); // NOLINT [runtime/int] [4] - return (sizeof(T) == sizeof(uint32_t)) - ? __builtin_clz(x) // TODO: __builtin_clz[ll] has undefined behavior for x=0 - : __builtin_clzll(x); -} - -template<typename T> -static constexpr int CTZ(T x) { - return (sizeof(T) == sizeof(uint32_t)) - ? __builtin_ctz(x) - : __builtin_ctzll(x); -} - -template<typename T> -static inline int WhichPowerOf2(T x) { - DCHECK((x != 0) && IsPowerOfTwo(x)); - return CTZ(x); -} - // Return whether x / divisor == x * (1.0f / divisor), for every float x. static constexpr bool CanDivideByReciprocalMultiplyFloat(int32_t divisor) { // True, if the most significant bits of divisor are 0. @@ -312,13 +83,6 @@ static constexpr bool CanDivideByReciprocalMultiplyDouble(int64_t divisor) { return ((divisor & ((UINT64_C(1) << 52) - 1)) == 0); } -template<typename T> -static constexpr int POPCOUNT(T x) { - return (sizeof(T) == sizeof(uint32_t)) - ? __builtin_popcount(x) - : __builtin_popcountll(x); -} - static inline uint32_t PointerToLowMemUInt32(const void* p) { uintptr_t intp = reinterpret_cast<uintptr_t>(p); DCHECK_LE(intp, 0xFFFFFFFFU); @@ -392,21 +156,6 @@ std::string PrettyJavaAccessFlags(uint32_t access_flags); // Returns a human-readable size string such as "1MB". std::string PrettySize(int64_t size_in_bytes); -// Returns a human-readable time string which prints every nanosecond while trying to limit the -// number of trailing zeros. Prints using the largest human readable unit up to a second. -// e.g. "1ms", "1.000000001s", "1.001us" -std::string PrettyDuration(uint64_t nano_duration, size_t max_fraction_digits = 3); - -// Format a nanosecond time to specified units. -std::string FormatDuration(uint64_t nano_duration, TimeUnit time_unit, - size_t max_fraction_digits); - -// Get the appropriate unit for a nanosecond duration. -TimeUnit GetAppropriateTimeUnit(uint64_t nano_duration); - -// Get the divisor to convert from a nanoseconds to a time unit. -uint64_t GetNsToTimeUnitDivisor(TimeUnit time_unit); - // Performs JNI name mangling as described in section 11.3 "Linking Native Methods" // of the JNI spec. std::string MangleForJni(const std::string& s); @@ -441,43 +190,6 @@ std::string JniLongName(mirror::ArtMethod* m) bool ReadFileToString(const std::string& file_name, std::string* result); bool PrintFileToLog(const std::string& file_name, LogSeverity level); -// Returns the current date in ISO yyyy-mm-dd hh:mm:ss format. -std::string GetIsoDate(); - -// Returns the monotonic time since some unspecified starting point in milliseconds. -uint64_t MilliTime(); - -// Returns the monotonic time since some unspecified starting point in microseconds. -uint64_t MicroTime(); - -// Returns the monotonic time since some unspecified starting point in nanoseconds. -uint64_t NanoTime(); - -// Returns the thread-specific CPU-time clock in nanoseconds or -1 if unavailable. -uint64_t ThreadCpuNanoTime(); - -// Converts the given number of nanoseconds to milliseconds. -static constexpr inline uint64_t NsToMs(uint64_t ns) { - return ns / 1000 / 1000; -} - -// Converts the given number of milliseconds to nanoseconds -static constexpr inline uint64_t MsToNs(uint64_t ns) { - return ns * 1000 * 1000; -} - -#if defined(__APPLE__) -// No clocks to specify on OS/X, fake value to pass to routines that require a clock. -#define CLOCK_REALTIME 0xebadf00d -#endif - -// Sleep for the given number of nanoseconds, a bad way to handle contention. -void NanoSleep(uint64_t ns); - -// Initialize a timespec to either a relative time (ms,ns), or to the absolute -// time corresponding to the indicated clock value plus the supplied offset. -void InitTimeSpec(bool absolute, int clock, int64_t ms, int32_t ns, timespec* ts); - // Splits a string using the given separator character into a vector of // strings. Empty strings will be omitted. void Split(const std::string& s, char separator, std::vector<std::string>* result); diff --git a/runtime/utils_test.cc b/runtime/utils_test.cc index 869d305..8a7f805 100644 --- a/runtime/utils_test.cc +++ b/runtime/utils_test.cc @@ -172,35 +172,6 @@ TEST_F(UtilsTest, PrettySize) { EXPECT_EQ("512B", PrettySize(512)); } -TEST_F(UtilsTest, PrettyDuration) { - const uint64_t one_sec = 1000000000; - const uint64_t one_ms = 1000000; - const uint64_t one_us = 1000; - - EXPECT_EQ("1s", PrettyDuration(1 * one_sec)); - EXPECT_EQ("10s", PrettyDuration(10 * one_sec)); - EXPECT_EQ("100s", PrettyDuration(100 * one_sec)); - EXPECT_EQ("1.001s", PrettyDuration(1 * one_sec + one_ms)); - EXPECT_EQ("1.000001s", PrettyDuration(1 * one_sec + one_us, 6)); - EXPECT_EQ("1.000000001s", PrettyDuration(1 * one_sec + 1, 9)); - EXPECT_EQ("1.000s", PrettyDuration(1 * one_sec + one_us, 3)); - - EXPECT_EQ("1ms", PrettyDuration(1 * one_ms)); - EXPECT_EQ("10ms", PrettyDuration(10 * one_ms)); - EXPECT_EQ("100ms", PrettyDuration(100 * one_ms)); - EXPECT_EQ("1.001ms", PrettyDuration(1 * one_ms + one_us)); - EXPECT_EQ("1.000001ms", PrettyDuration(1 * one_ms + 1, 6)); - - EXPECT_EQ("1us", PrettyDuration(1 * one_us)); - EXPECT_EQ("10us", PrettyDuration(10 * one_us)); - EXPECT_EQ("100us", PrettyDuration(100 * one_us)); - EXPECT_EQ("1.001us", PrettyDuration(1 * one_us + 1)); - - EXPECT_EQ("1ns", PrettyDuration(1)); - EXPECT_EQ("10ns", PrettyDuration(10)); - EXPECT_EQ("100ns", PrettyDuration(100)); -} - TEST_F(UtilsTest, MangleForJni) { ScopedObjectAccess soa(Thread::Current()); EXPECT_EQ("hello_00024world", MangleForJni("hello$world")); @@ -408,119 +379,6 @@ TEST_F(UtilsTest, ExecError) { } } -TEST_F(UtilsTest, RoundUpToPowerOfTwo) { - // Tests the constexpr variant since all the parameters are constexpr - EXPECT_EQ(0, RoundUpToPowerOfTwo(0)); - EXPECT_EQ(1, RoundUpToPowerOfTwo(1)); - EXPECT_EQ(2, RoundUpToPowerOfTwo(2)); - EXPECT_EQ(4, RoundUpToPowerOfTwo(3)); - EXPECT_EQ(8, RoundUpToPowerOfTwo(7)); - - EXPECT_EQ(0b10000L, RoundUpToPowerOfTwo(0b01101L)); - EXPECT_EQ(1ULL << 63, RoundUpToPowerOfTwo(1ULL << 62 | 1ULL)); -} - -TEST_F(UtilsTest, MostSignificantBit) { - EXPECT_EQ(-1, MostSignificantBit(0)); - EXPECT_EQ(0, MostSignificantBit(1)); - EXPECT_EQ(31, MostSignificantBit(~static_cast<uint32_t>(0))); - EXPECT_EQ(2, MostSignificantBit(0b110)); - EXPECT_EQ(2, MostSignificantBit(0b100)); -} - -TEST_F(UtilsTest, MinimumBitsToStore) { - EXPECT_EQ(0u, MinimumBitsToStore(0)); - EXPECT_EQ(1u, MinimumBitsToStore(1)); - EXPECT_EQ(2u, MinimumBitsToStore(0b10)); - EXPECT_EQ(2u, MinimumBitsToStore(0b11)); - EXPECT_EQ(3u, MinimumBitsToStore(0b100)); - EXPECT_EQ(3u, MinimumBitsToStore(0b110)); - EXPECT_EQ(3u, MinimumBitsToStore(0b101)); - EXPECT_EQ(8u, MinimumBitsToStore(0xFF)); - EXPECT_EQ(32u, MinimumBitsToStore(~static_cast<uint32_t>(0))); -} - -static constexpr int64_t INT_MIN_minus1 = static_cast<int64_t>(INT_MIN) - 1; -static constexpr int64_t INT_MAX_plus1 = static_cast<int64_t>(INT_MAX) + 1; -static constexpr int64_t UINT_MAX_plus1 = static_cast<int64_t>(UINT_MAX) + 1; - -TEST_F(UtilsTest, IsInt) { - EXPECT_FALSE(IsInt(1, -2)); - EXPECT_TRUE(IsInt(1, -1)); - EXPECT_TRUE(IsInt(1, 0)); - EXPECT_FALSE(IsInt(1, 1)); - - EXPECT_FALSE(IsInt(4, -9)); - EXPECT_TRUE(IsInt(4, -8)); - EXPECT_TRUE(IsInt(4, 7)); - EXPECT_FALSE(IsInt(4, 8)); - - EXPECT_FALSE(IsInt(32, INT_MIN_minus1)); - EXPECT_TRUE(IsInt(32, INT_MIN)); - EXPECT_TRUE(IsInt(32, INT_MAX)); - EXPECT_FALSE(IsInt(32, INT_MAX_plus1)); -} - -TEST_F(UtilsTest, IsInt_Static) { - EXPECT_FALSE(IsInt<1>(-2)); - EXPECT_TRUE(IsInt<1>(-1)); - EXPECT_TRUE(IsInt<1>(0)); - EXPECT_FALSE(IsInt<1>(1)); - - EXPECT_FALSE(IsInt<4>(-9)); - EXPECT_TRUE(IsInt<4>(-8)); - EXPECT_TRUE(IsInt<4>(7)); - EXPECT_FALSE(IsInt<4>(8)); - - EXPECT_FALSE(IsInt<32>(INT_MIN_minus1)); - EXPECT_TRUE(IsInt<32>(INT_MIN)); - EXPECT_TRUE(IsInt<32>(INT_MAX)); - EXPECT_FALSE(IsInt<32>(INT_MAX_plus1)); -} - -TEST_F(UtilsTest, IsUint) { - EXPECT_FALSE(IsUint<1>(-1)); - EXPECT_TRUE(IsUint<1>(0)); - EXPECT_TRUE(IsUint<1>(1)); - EXPECT_FALSE(IsUint<1>(2)); - - EXPECT_FALSE(IsUint<4>(-1)); - EXPECT_TRUE(IsUint<4>(0)); - EXPECT_TRUE(IsUint<4>(15)); - EXPECT_FALSE(IsUint<4>(16)); - - EXPECT_FALSE(IsUint<32>(-1)); - EXPECT_TRUE(IsUint<32>(0)); - EXPECT_TRUE(IsUint<32>(UINT_MAX)); - EXPECT_FALSE(IsUint<32>(UINT_MAX_plus1)); -} - -TEST_F(UtilsTest, IsAbsoluteUint) { - EXPECT_FALSE(IsAbsoluteUint<1>(-2)); - EXPECT_TRUE(IsAbsoluteUint<1>(-1)); - EXPECT_TRUE(IsAbsoluteUint<32>(0)); - EXPECT_TRUE(IsAbsoluteUint<1>(1)); - EXPECT_FALSE(IsAbsoluteUint<1>(2)); - - EXPECT_FALSE(IsAbsoluteUint<4>(-16)); - EXPECT_TRUE(IsAbsoluteUint<4>(-15)); - EXPECT_TRUE(IsAbsoluteUint<32>(0)); - EXPECT_TRUE(IsAbsoluteUint<4>(15)); - EXPECT_FALSE(IsAbsoluteUint<4>(16)); - - EXPECT_FALSE(IsAbsoluteUint<32>(-UINT_MAX_plus1)); - EXPECT_TRUE(IsAbsoluteUint<32>(-UINT_MAX)); - EXPECT_TRUE(IsAbsoluteUint<32>(0)); - EXPECT_TRUE(IsAbsoluteUint<32>(UINT_MAX)); - EXPECT_FALSE(IsAbsoluteUint<32>(UINT_MAX_plus1)); -} - -TEST_F(UtilsTest, TestSleep) { - auto start = NanoTime(); - NanoSleep(MsToNs(1500)); - EXPECT_GT(NanoTime() - start, MsToNs(1000)); -} - TEST_F(UtilsTest, IsValidDescriptor) { std::vector<uint8_t> descriptor( { 'L', 'a', '/', 'b', '$', 0xed, 0xa0, 0x80, 0xed, 0xb0, 0x80, ';', 0x00 }); diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 6c58d55..b08883e 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -21,6 +21,7 @@ #include "art_field-inl.h" #include "base/logging.h" #include "base/mutex-inl.h" +#include "base/time_utils.h" #include "class_linker.h" #include "compiler_callbacks.h" #include "dex_file-inl.h" @@ -41,6 +42,7 @@ #include "register_line-inl.h" #include "runtime.h" #include "scoped_thread_state_change.h" +#include "utils.h" #include "handle_scope-inl.h" #include "verifier/dex_gc_map.h" |