From d776ff08e07494327716f0d2ea1a774b2ebfbca9 Mon Sep 17 00:00:00 2001 From: Mathieu Chartier Date: Tue, 17 Jan 2017 09:32:18 -0800 Subject: Add invoke infos to stack maps Invoke info records the invoke type and dex method index for invokes that may reach artQuickResolutionTrampoline. Having this information recorded allows the runtime to avoid reading the dex code and pulling in extra pages. Code size increase for a large app: 93886360 -> 95811480 (2.05% increase) 1/2 of the code size increase is from making less stack maps deduped. I suspect there is less deduping because of the invoke info method index. Merged disabled until we measure the RAM savings. Test: test-art-host, N6P boots Bug: 34109702 Change-Id: I6c5e4a60675a1d7c76dee0561a12909e4ab6d5d9 --- runtime/stack_map.h | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) (limited to 'runtime/stack_map.h') diff --git a/runtime/stack_map.h b/runtime/stack_map.h index f7a64026b7..67f0b5715d 100644 --- a/runtime/stack_map.h +++ b/runtime/stack_map.h @@ -1145,6 +1145,94 @@ struct ByteSizedTable { } }; +// Format is [native pc, invoke type, method index]. +class InvokeInfoEncoding { + public: + void SetFromSizes(size_t native_pc_max, + size_t invoke_type_max, + size_t method_index_max) { + total_bit_size_ = 0; + DCHECK_EQ(kNativePcBitOffset, total_bit_size_); + total_bit_size_ += MinimumBitsToStore(native_pc_max); + invoke_type_bit_offset_ = total_bit_size_; + total_bit_size_ += MinimumBitsToStore(invoke_type_max); + method_index_bit_offset_ = total_bit_size_; + total_bit_size_ += MinimumBitsToStore(method_index_max); + } + + ALWAYS_INLINE FieldEncoding GetNativePcEncoding() const { + return FieldEncoding(kNativePcBitOffset, invoke_type_bit_offset_); + } + + ALWAYS_INLINE FieldEncoding GetInvokeTypeEncoding() const { + return FieldEncoding(invoke_type_bit_offset_, method_index_bit_offset_); + } + + ALWAYS_INLINE FieldEncoding GetMethodIndexEncoding() const { + return FieldEncoding(method_index_bit_offset_, total_bit_size_); + } + + ALWAYS_INLINE size_t BitSize() const { + return total_bit_size_; + } + + template + void Encode(Vector* dest) const { + static_assert(alignof(InvokeInfoEncoding) == 1, "Should not require alignment"); + const uint8_t* ptr = reinterpret_cast(this); + dest->insert(dest->end(), ptr, ptr + sizeof(*this)); + } + + void Decode(const uint8_t** ptr) { + *this = *reinterpret_cast(*ptr); + *ptr += sizeof(*this); + } + + private: + static constexpr uint8_t kNativePcBitOffset = 0; + uint8_t invoke_type_bit_offset_; + uint8_t method_index_bit_offset_; + uint8_t total_bit_size_; +}; + +class InvokeInfo { + public: + explicit InvokeInfo(BitMemoryRegion region) : region_(region) {} + + ALWAYS_INLINE uint32_t GetNativePcOffset(const InvokeInfoEncoding& encoding, + InstructionSet instruction_set) const { + CodeOffset offset( + CodeOffset::FromCompressedOffset(encoding.GetNativePcEncoding().Load(region_))); + return offset.Uint32Value(instruction_set); + } + + ALWAYS_INLINE void SetNativePcCodeOffset(const InvokeInfoEncoding& encoding, + CodeOffset native_pc_offset) { + encoding.GetNativePcEncoding().Store(region_, native_pc_offset.CompressedValue()); + } + + ALWAYS_INLINE uint32_t GetInvokeType(const InvokeInfoEncoding& encoding) const { + return encoding.GetInvokeTypeEncoding().Load(region_); + } + + ALWAYS_INLINE void SetInvokeType(const InvokeInfoEncoding& encoding, uint32_t invoke_type) { + encoding.GetInvokeTypeEncoding().Store(region_, invoke_type); + } + + ALWAYS_INLINE uint32_t GetMethodIndex(const InvokeInfoEncoding& encoding) const { + return encoding.GetMethodIndexEncoding().Load(region_); + } + + ALWAYS_INLINE void SetMethodIndex(const InvokeInfoEncoding& encoding, uint32_t method_index) { + encoding.GetMethodIndexEncoding().Store(region_, method_index); + } + + bool IsValid() const { return region_.pointer() != nullptr; } + + private: + BitMemoryRegion region_; +}; + // Most of the fields are encoded as ULEB128 to save space. struct CodeInfoEncoding { static constexpr uint32_t kInvalidSize = static_cast(-1); @@ -1154,6 +1242,7 @@ struct CodeInfoEncoding { BitEncodingTable stack_map; BitEncodingTable register_mask; BitEncodingTable stack_mask; + BitEncodingTable invoke_info; BitEncodingTable inline_info; CodeInfoEncoding() {} @@ -1165,6 +1254,7 @@ struct CodeInfoEncoding { stack_map.Decode(&ptr); register_mask.Decode(&ptr); stack_mask.Decode(&ptr); + invoke_info.Decode(&ptr); if (stack_map.encoding.GetInlineInfoEncoding().BitSize() > 0) { inline_info.Decode(&ptr); } else { @@ -1183,6 +1273,7 @@ struct CodeInfoEncoding { stack_map.Encode(dest); register_mask.Encode(dest); stack_mask.Encode(dest); + invoke_info.Encode(dest); if (stack_map.encoding.GetInlineInfoEncoding().BitSize() > 0) { inline_info.Encode(dest); } @@ -1199,6 +1290,7 @@ struct CodeInfoEncoding { stack_map.UpdateBitOffset(&bit_offset); register_mask.UpdateBitOffset(&bit_offset); stack_mask.UpdateBitOffset(&bit_offset); + invoke_info.UpdateBitOffset(&bit_offset); inline_info.UpdateBitOffset(&bit_offset); cache_non_header_size = RoundUp(bit_offset, kBitsPerByte) / kBitsPerByte - HeaderSize(); } @@ -1303,6 +1395,10 @@ class CodeInfo { return encoding.stack_map.encoding.BitSize() * GetNumberOfStackMaps(encoding); } + InvokeInfo GetInvokeInfo(const CodeInfoEncoding& encoding, size_t index) const { + return InvokeInfo(encoding.invoke_info.BitRegion(region_, index)); + } + DexRegisterMap GetDexRegisterMapOf(StackMap stack_map, const CodeInfoEncoding& encoding, size_t number_of_dex_registers) const { @@ -1426,6 +1522,17 @@ class CodeInfo { return StackMap(); } + InvokeInfo GetInvokeInfoForNativePcOffset(uint32_t native_pc_offset, + const CodeInfoEncoding& encoding) { + for (size_t index = 0; index < encoding.invoke_info.num_entries; index++) { + InvokeInfo item = GetInvokeInfo(encoding, index); + if (item.GetNativePcOffset(encoding.invoke_info.encoding, kRuntimeISA) == native_pc_offset) { + return item; + } + } + return InvokeInfo(BitMemoryRegion()); + } + // Dump this CodeInfo object on `os`. `code_offset` is the (absolute) // native PC of the compiled method and `number_of_dex_registers` the // number of Dex virtual registers used in this method. If -- cgit v1.2.3-59-g8ed1b