diff options
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/base/macros.h | 2 | ||||
-rw-r--r-- | runtime/common_test.h | 4 | ||||
-rw-r--r-- | runtime/compiled_method.cc | 28 | ||||
-rw-r--r-- | runtime/compiled_method.h | 17 | ||||
-rw-r--r-- | runtime/exception_test.cc | 29 | ||||
-rw-r--r-- | runtime/leb128.h | 26 | ||||
-rw-r--r-- | runtime/mapping_table.h | 196 | ||||
-rw-r--r-- | runtime/mirror/abstract_method-inl.h | 8 | ||||
-rw-r--r-- | runtime/mirror/abstract_method.cc | 70 | ||||
-rw-r--r-- | runtime/mirror/abstract_method.h | 65 | ||||
-rw-r--r-- | runtime/oat_file.cc | 8 | ||||
-rw-r--r-- | runtime/oat_file.h | 8 | ||||
-rw-r--r-- | runtime/stack.cc | 9 | ||||
-rw-r--r-- | runtime/stack.h | 72 | ||||
-rw-r--r-- | runtime/thread.cc | 5 | ||||
-rw-r--r-- | runtime/vmap_table.h | 115 |
16 files changed, 409 insertions, 253 deletions
diff --git a/runtime/base/macros.h b/runtime/base/macros.h index 879c10c..6531858 100644 --- a/runtime/base/macros.h +++ b/runtime/base/macros.h @@ -142,6 +142,8 @@ char (&ArraySizeHelper(T (&array)[N]))[N]; #define HOT_ATTR __attribute__ ((hot)) #endif +#define PURE __attribute__ ((__pure__)) + // bionic and glibc both have TEMP_FAILURE_RETRY, but Mac OS' libc doesn't. #ifndef TEMP_FAILURE_RETRY #define TEMP_FAILURE_RETRY(exp) ({ \ diff --git a/runtime/common_test.h b/runtime/common_test.h index a543617..7110e11 100644 --- a/runtime/common_test.h +++ b/runtime/common_test.h @@ -168,8 +168,8 @@ class CommonTest : public testing::Test { const size_t frame_size_in_bytes, const uint32_t core_spill_mask, const uint32_t fp_spill_mask, - const uint32_t* mapping_table, - const uint16_t* vmap_table, + const uint8_t* mapping_table, + const uint8_t* vmap_table, const uint8_t* gc_map) { return OatFile::OatMethod(NULL, reinterpret_cast<uint32_t>(code), diff --git a/runtime/compiled_method.cc b/runtime/compiled_method.cc index c64c71e..4631cb5 100644 --- a/runtime/compiled_method.cc +++ b/runtime/compiled_method.cc @@ -112,35 +112,13 @@ CompiledMethod::CompiledMethod(InstructionSet instruction_set, const size_t frame_size_in_bytes, const uint32_t core_spill_mask, const uint32_t fp_spill_mask, - const std::vector<uint32_t>& mapping_table, - const std::vector<uint16_t>& vmap_table, + const std::vector<uint8_t>& mapping_table, + const std::vector<uint8_t>& vmap_table, const std::vector<uint8_t>& native_gc_map) : CompiledCode(instruction_set, code), frame_size_in_bytes_(frame_size_in_bytes), core_spill_mask_(core_spill_mask), fp_spill_mask_(fp_spill_mask), + mapping_table_(mapping_table), vmap_table_(vmap_table), gc_map_(native_gc_map) { - DCHECK_EQ(vmap_table.size(), - static_cast<uint32_t>(__builtin_popcount(core_spill_mask) - + __builtin_popcount(fp_spill_mask))); - CHECK_LE(vmap_table.size(), (1U << 16) - 1); // length must fit in 2^16-1 - - std::vector<uint32_t> length_prefixed_mapping_table; - length_prefixed_mapping_table.push_back(mapping_table.size()); - length_prefixed_mapping_table.insert(length_prefixed_mapping_table.end(), - mapping_table.begin(), - mapping_table.end()); - DCHECK_EQ(mapping_table.size() + 1, length_prefixed_mapping_table.size()); - - std::vector<uint16_t> length_prefixed_vmap_table; - length_prefixed_vmap_table.push_back(vmap_table.size()); - length_prefixed_vmap_table.insert(length_prefixed_vmap_table.end(), - vmap_table.begin(), - vmap_table.end()); - DCHECK_EQ(vmap_table.size() + 1, length_prefixed_vmap_table.size()); - DCHECK_EQ(vmap_table.size(), length_prefixed_vmap_table[0]); - - mapping_table_ = length_prefixed_mapping_table; - vmap_table_ = length_prefixed_vmap_table; - DCHECK_EQ(vmap_table_[0], static_cast<uint32_t>(__builtin_popcount(core_spill_mask) + __builtin_popcount(fp_spill_mask))); } CompiledMethod::CompiledMethod(InstructionSet instruction_set, diff --git a/runtime/compiled_method.h b/runtime/compiled_method.h index 800dde2..b3bb20f 100644 --- a/runtime/compiled_method.h +++ b/runtime/compiled_method.h @@ -103,8 +103,8 @@ class CompiledMethod : public CompiledCode { const size_t frame_size_in_bytes, const uint32_t core_spill_mask, const uint32_t fp_spill_mask, - const std::vector<uint32_t>& mapping_table, - const std::vector<uint16_t>& vmap_table, + const std::vector<uint8_t>& mapping_table, + const std::vector<uint8_t>& vmap_table, const std::vector<uint8_t>& native_gc_map); // Constructs a CompiledMethod for the JniCompiler. @@ -147,11 +147,11 @@ class CompiledMethod : public CompiledCode { return fp_spill_mask_; } - const std::vector<uint32_t>& GetMappingTable() const { + const std::vector<uint8_t>& GetMappingTable() const { return mapping_table_; } - const std::vector<uint16_t>& GetVmapTable() const { + const std::vector<uint8_t>& GetVmapTable() const { return vmap_table_; } @@ -166,10 +166,11 @@ class CompiledMethod : public CompiledCode { const uint32_t core_spill_mask_; // For quick code, a bit mask describing spilled FPR callee-save registers. const uint32_t fp_spill_mask_; - // For quick code, a map from native PC offset to dex PC. - std::vector<uint32_t> mapping_table_; - // For quick code, a map from GPR/FPR register to dex register. - std::vector<uint16_t> vmap_table_; + // For quick code, a uleb128 encoded map from native PC offset to dex PC aswell as dex PC to + // native PC offset. Size prefixed. + std::vector<uint8_t> mapping_table_; + // For quick code, a uleb128 encoded map from GPR/FPR register to dex register. Size prefixed. + std::vector<uint8_t> vmap_table_; // For quick code, a map keyed by native PC indices to bitmaps describing what dalvik registers // are live. For portable code, the key is a dalvik PC. std::vector<uint8_t> gc_map_; diff --git a/runtime/exception_test.cc b/runtime/exception_test.cc index a7a6d46..933b74a 100644 --- a/runtime/exception_test.cc +++ b/runtime/exception_test.cc @@ -18,6 +18,7 @@ #include "common_test.h" #include "dex_file.h" #include "gtest/gtest.h" +#include "leb128_encoder.h" #include "mirror/class-inl.h" #include "mirror/object_array-inl.h" #include "mirror/object-inl.h" @@ -53,17 +54,17 @@ class ExceptionTest : public CommonTest { fake_code_.push_back(0x70 | i); } - fake_mapping_data_.push_back(4); // first element is count - fake_mapping_data_.push_back(4); // total (non-length) elements - fake_mapping_data_.push_back(2); // count of pc to dex elements + fake_mapping_data_.PushBack(4); // first element is count + fake_mapping_data_.PushBack(4); // total (non-length) elements + fake_mapping_data_.PushBack(2); // count of pc to dex elements // --- pc to dex table - fake_mapping_data_.push_back(3); // offset 3 - fake_mapping_data_.push_back(3); // maps to dex offset 3 + fake_mapping_data_.PushBack(3); // offset 3 + fake_mapping_data_.PushBack(3); // maps to dex offset 3 // --- dex to pc table - fake_mapping_data_.push_back(3); // offset 3 - fake_mapping_data_.push_back(3); // maps to dex offset 3 + fake_mapping_data_.PushBack(3); // offset 3 + fake_mapping_data_.PushBack(3); // maps to dex offset 3 - fake_vmap_table_data_.push_back(0); + fake_vmap_table_data_.PushBack(0); fake_gc_map_.push_back(0); // 0 bytes to encode references and native pc offsets. fake_gc_map_.push_back(0); @@ -74,24 +75,24 @@ class ExceptionTest : public CommonTest { ASSERT_TRUE(method_f_ != NULL); method_f_->SetFrameSizeInBytes(kStackAlignment); method_f_->SetEntryPointFromCompiledCode(CompiledMethod::CodePointer(&fake_code_[sizeof(code_size)], kThumb2)); - method_f_->SetMappingTable(&fake_mapping_data_[0]); - method_f_->SetVmapTable(&fake_vmap_table_data_[0]); + method_f_->SetMappingTable(&fake_mapping_data_.GetData()[0]); + method_f_->SetVmapTable(&fake_vmap_table_data_.GetData()[0]); method_f_->SetNativeGcMap(&fake_gc_map_[0]); method_g_ = my_klass_->FindVirtualMethod("g", "(I)V"); ASSERT_TRUE(method_g_ != NULL); method_g_->SetFrameSizeInBytes(kStackAlignment); method_g_->SetEntryPointFromCompiledCode(CompiledMethod::CodePointer(&fake_code_[sizeof(code_size)], kThumb2)); - method_g_->SetMappingTable(&fake_mapping_data_[0]); - method_g_->SetVmapTable(&fake_vmap_table_data_[0]); + method_g_->SetMappingTable(&fake_mapping_data_.GetData()[0]); + method_g_->SetVmapTable(&fake_vmap_table_data_.GetData()[0]); method_g_->SetNativeGcMap(&fake_gc_map_[0]); } const DexFile* dex_; std::vector<uint8_t> fake_code_; - std::vector<uint32_t> fake_mapping_data_; - std::vector<uint16_t> fake_vmap_table_data_; + UnsignedLeb128EncodingVector fake_mapping_data_; + UnsignedLeb128EncodingVector fake_vmap_table_data_; std::vector<uint8_t> fake_gc_map_; mirror::AbstractMethod* method_f_; diff --git a/runtime/leb128.h b/runtime/leb128.h index ca955b0..6041f8c 100644 --- a/runtime/leb128.h +++ b/runtime/leb128.h @@ -24,8 +24,8 @@ namespace art { // Reads an unsigned LEB128 value, updating the given pointer to point // just past the end of the read value. This function tolerates // non-zero high-order bits in the fifth encoded byte. -static inline uint32_t DecodeUnsignedLeb128(const byte** data) { - const byte* ptr = *data; +static inline uint32_t DecodeUnsignedLeb128(const uint8_t** data) { + const uint8_t* ptr = *data; int result = *(ptr++); if (result > 0x7f) { int cur = *(ptr++); @@ -53,15 +53,15 @@ static inline uint32_t DecodeUnsignedLeb128(const byte** data) { // just past the end of the read value. This function tolerates // non-zero high-order bits in the fifth encoded byte. // It is possible for this function to return -1. -static inline int32_t DecodeUnsignedLeb128P1(const byte** data) { +static inline int32_t DecodeUnsignedLeb128P1(const uint8_t** data) { return DecodeUnsignedLeb128(data) - 1; } // Reads a signed LEB128 value, updating the given pointer to point // just past the end of the read value. This function tolerates // non-zero high-order bits in the fifth encoded byte. -static inline int32_t DecodeSignedLeb128(const byte** data) { - const byte* ptr = *data; +static inline int32_t DecodeSignedLeb128(const uint8_t** data) { + const uint8_t* ptr = *data; int32_t result = *(ptr++); if (result <= 0x7f) { result = (result << 25) >> 25; @@ -103,22 +103,6 @@ static inline uint32_t UnsignedLeb128Size(uint32_t data) { return count; } -// Writes a 32-bit value in unsigned ULEB128 format. -// Returns the updated pointer. -static inline uint8_t* WriteUnsignedLeb128(uint8_t* ptr, uint32_t data) { - while (true) { - uint8_t out = data & 0x7f; - if (out != data) { - *ptr++ = out | 0x80; - data >>= 7; - } else { - *ptr++ = out; - break; - } - } - return ptr; -} - } // namespace art #endif // ART_RUNTIME_LEB128_H_ diff --git a/runtime/mapping_table.h b/runtime/mapping_table.h new file mode 100644 index 0000000..2162008 --- /dev/null +++ b/runtime/mapping_table.h @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2013 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_MAPPING_TABLE_H_ +#define ART_RUNTIME_MAPPING_TABLE_H_ + +#include "base/logging.h" +#include "leb128.h" + +namespace art { + +// A utility for processing the raw uleb128 encoded mapping table created by the quick compiler. +class MappingTable { + public: + explicit MappingTable(const uint8_t* encoded_map) : encoded_table_(encoded_map) { + } + + uint32_t TotalSize() const PURE { + const uint8_t* table = encoded_table_; + if (table == NULL) { + return 0; + } else { + return DecodeUnsignedLeb128(&table); + } + } + + uint32_t DexToPcSize() const PURE { + const uint8_t* table = encoded_table_; + if (table == NULL) { + return 0; + } else { + uint32_t total_size = DecodeUnsignedLeb128(&table); + uint32_t pc_to_dex_size = DecodeUnsignedLeb128(&table); + return total_size - pc_to_dex_size; + } + } + + const uint8_t* FirstDexToPcPtr() const { + const uint8_t* table = encoded_table_; + if (table != NULL) { + DecodeUnsignedLeb128(&table); // Total_size, unused. + uint32_t pc_to_dex_size = DecodeUnsignedLeb128(&table); + for (uint32_t i = 0; i < pc_to_dex_size; ++i) { + DecodeUnsignedLeb128(&table); // Move ptr past native PC. + DecodeUnsignedLeb128(&table); // Move ptr past dex PC. + } + } + return table; + } + + class DexToPcIterator { + public: + DexToPcIterator(const MappingTable* table, uint32_t element) : + table_(table), element_(element), end_(table_->DexToPcSize()), encoded_table_ptr_(NULL), + native_pc_offset_(0), dex_pc_(0) { + if (element == 0) { + encoded_table_ptr_ = table_->FirstDexToPcPtr(); + native_pc_offset_ = DecodeUnsignedLeb128(&encoded_table_ptr_); + dex_pc_ = DecodeUnsignedLeb128(&encoded_table_ptr_); + } else { + DCHECK_EQ(table_->DexToPcSize(), element); + } + } + uint32_t NativePcOffset() const { + return native_pc_offset_; + } + uint32_t DexPc() const { + return dex_pc_; + } + void operator++() { + ++element_; + if (element_ != end_) { // Avoid reading beyond the end of the table. + native_pc_offset_ = DecodeUnsignedLeb128(&encoded_table_ptr_); + dex_pc_ = DecodeUnsignedLeb128(&encoded_table_ptr_); + } + } + bool operator==(const DexToPcIterator& rhs) const { + CHECK(table_ == rhs.table_); + return element_ == rhs.element_; + } + bool operator!=(const DexToPcIterator& rhs) const { + CHECK(table_ == rhs.table_); + return element_ != rhs.element_; + } + + private: + const MappingTable* const table_; // The original table. + uint32_t element_; // A value in the range 0 to end_. + const uint32_t end_; // Equal to table_->DexToPcSize(). + const uint8_t* encoded_table_ptr_; // Either NULL or points to encoded data after this entry. + uint32_t native_pc_offset_; // The current value of native pc offset. + uint32_t dex_pc_; // The current value of dex pc. + }; + + DexToPcIterator DexToPcBegin() const { + return DexToPcIterator(this, 0); + } + + DexToPcIterator DexToPcEnd() const { + uint32_t size = DexToPcSize(); + return DexToPcIterator(this, size); + } + + uint32_t PcToDexSize() const PURE { + const uint8_t* table = encoded_table_; + if (table == NULL) { + return 0; + } else { + DecodeUnsignedLeb128(&table); // Total_size, unused. + uint32_t pc_to_dex_size = DecodeUnsignedLeb128(&table); + return pc_to_dex_size; + } + } + + const uint8_t* FirstPcToDexPtr() const { + const uint8_t* table = encoded_table_; + if (table != NULL) { + DecodeUnsignedLeb128(&table); // Total_size, unused. + DecodeUnsignedLeb128(&table); // PC to Dex size, unused. + } + return table; + } + + class PcToDexIterator { + public: + PcToDexIterator(const MappingTable* table, uint32_t element) : + table_(table), element_(element), end_(table_->PcToDexSize()), encoded_table_ptr_(NULL), + native_pc_offset_(0), dex_pc_(0) { + if (element == 0) { + encoded_table_ptr_ = table_->FirstPcToDexPtr(); + native_pc_offset_ = DecodeUnsignedLeb128(&encoded_table_ptr_); + dex_pc_ = DecodeUnsignedLeb128(&encoded_table_ptr_); + } else { + DCHECK_EQ(table_->PcToDexSize(), element); + } + } + uint32_t NativePcOffset() const { + return native_pc_offset_; + } + uint32_t DexPc() const { + return dex_pc_; + } + void operator++() { + ++element_; + if (element_ != end_) { // Avoid reading beyond the end of the table. + native_pc_offset_ = DecodeUnsignedLeb128(&encoded_table_ptr_); + dex_pc_ = DecodeUnsignedLeb128(&encoded_table_ptr_); + } + } + bool operator==(const PcToDexIterator& rhs) const { + CHECK(table_ == rhs.table_); + return element_ == rhs.element_; + } + bool operator!=(const PcToDexIterator& rhs) const { + CHECK(table_ == rhs.table_); + return element_ != rhs.element_; + } + + private: + const MappingTable* const table_; // The original table. + uint32_t element_; // A value in the range 0 to PcToDexSize. + const uint32_t end_; // Equal to table_->PcToDexSize(). + const uint8_t* encoded_table_ptr_; // Either NULL or points to encoded data after this entry. + uint32_t native_pc_offset_; // The current value of native pc offset. + uint32_t dex_pc_; // The current value of dex pc. + }; + + PcToDexIterator PcToDexBegin() const { + return PcToDexIterator(this, 0); + } + + PcToDexIterator PcToDexEnd() const { + uint32_t size = PcToDexSize(); + return PcToDexIterator(this, size); + } + + private: + const uint8_t* const encoded_table_; +}; + +} // namespace art + +#endif // ART_RUNTIME_MAPPING_TABLE_H_ diff --git a/runtime/mirror/abstract_method-inl.h b/runtime/mirror/abstract_method-inl.h index 8fde99b..d47b3eb 100644 --- a/runtime/mirror/abstract_method-inl.h +++ b/runtime/mirror/abstract_method-inl.h @@ -144,22 +144,22 @@ inline void AbstractMethod::SetOatCodeOffset(uint32_t code_offset) { inline uint32_t AbstractMethod::GetOatMappingTableOffset() const { DCHECK(!Runtime::Current()->IsStarted()); - return reinterpret_cast<uint32_t>(GetMappingTableRaw()); + return reinterpret_cast<uint32_t>(GetMappingTable()); } inline void AbstractMethod::SetOatMappingTableOffset(uint32_t mapping_table_offset) { DCHECK(!Runtime::Current()->IsStarted()); - SetMappingTable(reinterpret_cast<const uint32_t*>(mapping_table_offset)); + SetMappingTable(reinterpret_cast<const uint8_t*>(mapping_table_offset)); } inline uint32_t AbstractMethod::GetOatVmapTableOffset() const { DCHECK(!Runtime::Current()->IsStarted()); - return reinterpret_cast<uint32_t>(GetVmapTableRaw()); + return reinterpret_cast<uint32_t>(GetVmapTable()); } inline void AbstractMethod::SetOatVmapTableOffset(uint32_t vmap_table_offset) { DCHECK(!Runtime::Current()->IsStarted()); - SetVmapTable(reinterpret_cast<uint16_t*>(vmap_table_offset)); + SetVmapTable(reinterpret_cast<uint8_t*>(vmap_table_offset)); } inline void AbstractMethod::SetOatNativeGcMapOffset(uint32_t gc_map_offset) { diff --git a/runtime/mirror/abstract_method.cc b/runtime/mirror/abstract_method.cc index 93065e7..b3db5c2 100644 --- a/runtime/mirror/abstract_method.cc +++ b/runtime/mirror/abstract_method.cc @@ -24,6 +24,7 @@ #include "gc/accounting/card_table-inl.h" #include "interpreter/interpreter.h" #include "jni_internal.h" +#include "mapping_table.h" #include "object-inl.h" #include "object_array.h" #include "object_array-inl.h" @@ -157,43 +158,27 @@ uintptr_t AbstractMethod::NativePcOffset(const uintptr_t pc) const { return pc - reinterpret_cast<uintptr_t>(code); } -// Find the lowest-address native safepoint pc for a given dex pc -uintptr_t AbstractMethod::ToFirstNativeSafepointPc(const uint32_t dex_pc) const { -#if !defined(ART_USE_PORTABLE_COMPILER) - const uint32_t* mapping_table = GetPcToDexMappingTable(); - if (mapping_table == NULL) { - DCHECK(IsNative() || IsCalleeSaveMethod() || IsProxyMethod()) << PrettyMethod(this); - return DexFile::kDexNoIndex; // Special no mapping case - } - size_t mapping_table_length = GetPcToDexMappingTableLength(); - for (size_t i = 0; i < mapping_table_length; i += 2) { - if (mapping_table[i + 1] == dex_pc) { - const void* code = Runtime::Current()->GetInstrumentation()->GetQuickCodeFor(this); - return mapping_table[i] + reinterpret_cast<uintptr_t>(code); - } - } - LOG(FATAL) << "Failed to find native offset for dex pc 0x" << std::hex << dex_pc - << " in " << PrettyMethod(this); - return 0; -#else - // Compiler LLVM doesn't use the machine pc, we just use dex pc instead. - return static_cast<uint32_t>(dex_pc); -#endif -} - uint32_t AbstractMethod::ToDexPc(const uintptr_t pc) const { #if !defined(ART_USE_PORTABLE_COMPILER) - const uint32_t* mapping_table = GetPcToDexMappingTable(); - if (mapping_table == NULL) { + MappingTable table(GetMappingTable()); + if (table.TotalSize() == 0) { DCHECK(IsNative() || IsCalleeSaveMethod() || IsProxyMethod()) << PrettyMethod(this); return DexFile::kDexNoIndex; // Special no mapping case } - size_t mapping_table_length = GetPcToDexMappingTableLength(); const void* code = Runtime::Current()->GetInstrumentation()->GetQuickCodeFor(this); uint32_t sought_offset = pc - reinterpret_cast<uintptr_t>(code); - for (size_t i = 0; i < mapping_table_length; i += 2) { - if (mapping_table[i] == sought_offset) { - return mapping_table[i + 1]; + // Assume the caller wants a pc-to-dex mapping so check here first. + typedef MappingTable::PcToDexIterator It; + for (It cur = table.PcToDexBegin(), end = table.PcToDexEnd(); cur != end; ++cur) { + if (cur.NativePcOffset() == sought_offset) { + return cur.DexPc(); + } + } + // Now check dex-to-pc mappings. + typedef MappingTable::DexToPcIterator It2; + for (It2 cur = table.DexToPcBegin(), end = table.DexToPcEnd(); cur != end; ++cur) { + if (cur.NativePcOffset() == sought_offset) { + return cur.DexPc(); } } LOG(FATAL) << "Failed to find Dex offset for PC offset " << reinterpret_cast<void*>(sought_offset) @@ -207,21 +192,28 @@ uint32_t AbstractMethod::ToDexPc(const uintptr_t pc) const { } uintptr_t AbstractMethod::ToNativePc(const uint32_t dex_pc) const { - const uint32_t* mapping_table = GetDexToPcMappingTable(); - if (mapping_table == NULL) { + MappingTable table(GetMappingTable()); + if (table.TotalSize() == 0) { DCHECK_EQ(dex_pc, 0U); return 0; // Special no mapping/pc == 0 case } - size_t mapping_table_length = GetDexToPcMappingTableLength(); - for (size_t i = 0; i < mapping_table_length; i += 2) { - uint32_t map_offset = mapping_table[i]; - uint32_t map_dex_offset = mapping_table[i + 1]; - if (map_dex_offset == dex_pc) { + // Assume the caller wants a dex-to-pc mapping so check here first. + typedef MappingTable::DexToPcIterator It; + for (It cur = table.DexToPcBegin(), end = table.DexToPcEnd(); cur != end; ++cur) { + if (cur.DexPc() == dex_pc) { const void* code = Runtime::Current()->GetInstrumentation()->GetQuickCodeFor(this); - return reinterpret_cast<uintptr_t>(code) + map_offset; + return reinterpret_cast<uintptr_t>(code) + cur.NativePcOffset(); } } - LOG(FATAL) << "Looking up Dex PC not contained in method, 0x" << std::hex << dex_pc + // Now check pc-to-dex mappings. + typedef MappingTable::PcToDexIterator It2; + for (It2 cur = table.PcToDexBegin(), end = table.PcToDexEnd(); cur != end; ++cur) { + if (cur.DexPc() == dex_pc) { + const void* code = Runtime::Current()->GetInstrumentation()->GetQuickCodeFor(this); + return reinterpret_cast<uintptr_t>(code) + cur.NativePcOffset(); + } + } + LOG(FATAL) << "Failed to find native offset for dex pc 0x" << std::hex << dex_pc << " in " << PrettyMethod(this); return 0; } diff --git a/runtime/mirror/abstract_method.h b/runtime/mirror/abstract_method.h index 2e6e262..5b8c61c 100644 --- a/runtime/mirror/abstract_method.h +++ b/runtime/mirror/abstract_method.h @@ -246,54 +246,13 @@ class MANAGED AbstractMethod : public Object { return OFFSET_OF_OBJECT_MEMBER(AbstractMethod, entry_point_from_compiled_code_); } - const uint32_t* GetMappingTable() const { - const uint32_t* map = GetMappingTableRaw(); - if (map == NULL) { - return map; - } - return map + 1; - } - - uint32_t GetPcToDexMappingTableLength() const { - const uint32_t* map = GetMappingTableRaw(); - if (map == NULL) { - return 0; - } - return map[2]; - } - - const uint32_t* GetPcToDexMappingTable() const { - const uint32_t* map = GetMappingTableRaw(); - if (map == NULL) { - return map; - } - return map + 3; - } - - - uint32_t GetDexToPcMappingTableLength() const { - const uint32_t* map = GetMappingTableRaw(); - if (map == NULL) { - return 0; - } - return map[1] - map[2]; - } - - const uint32_t* GetDexToPcMappingTable() const { - const uint32_t* map = GetMappingTableRaw(); - if (map == NULL) { - return map; - } - return map + 3 + map[2]; + // Callers should wrap the uint8_t* in a MappingTable instance for convenient access. + const uint8_t* GetMappingTable() const { + return GetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, mapping_table_), false); } - - const uint32_t* GetMappingTableRaw() const { - return GetFieldPtr<const uint32_t*>(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, mapping_table_), false); - } - - void SetMappingTable(const uint32_t* mapping_table) { - SetFieldPtr<const uint32_t*>(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, mapping_table_), + void SetMappingTable(const uint8_t* mapping_table) { + SetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, mapping_table_), mapping_table, false); } @@ -301,13 +260,13 @@ class MANAGED AbstractMethod : public Object { void SetOatMappingTableOffset(uint32_t mapping_table_offset); - // Callers should wrap the uint16_t* in a VmapTable instance for convenient access. - const uint16_t* GetVmapTableRaw() const { - return GetFieldPtr<const uint16_t*>(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, vmap_table_), false); + // Callers should wrap the uint8_t* in a VmapTable instance for convenient access. + const uint8_t* GetVmapTable() const { + return GetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, vmap_table_), false); } - void SetVmapTable(const uint16_t* vmap_table) { - SetFieldPtr<const uint16_t*>(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, vmap_table_), vmap_table, false); + void SetVmapTable(const uint8_t* vmap_table) { + SetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(AbstractMethod, vmap_table_), vmap_table, false); } uint32_t GetOatVmapTableOffset() const; @@ -403,10 +362,6 @@ class MANAGED AbstractMethod : public Object { // Converts a dex PC to a native PC. uintptr_t ToNativePc(const uint32_t dex_pc) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - // Converts a dex PC to the first corresponding safepoint PC. - uintptr_t ToFirstNativeSafepointPc(const uint32_t dex_pc) - const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - // Find the catch block for the given exception type and dex_pc. When a catch block is found, // indicates whether the found catch block is responsible for clearing the exception or whether // a move-exception instruction is present. diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index 7bffc8c..93e98ad 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -28,6 +28,7 @@ #include "mirror/object-inl.h" #include "os.h" #include "utils.h" +#include "vmap_table.h" namespace art { @@ -416,9 +417,10 @@ OatFile::OatMethod::OatMethod(const byte* base, DCHECK_EQ(0U, static_cast<uint32_t>(__builtin_popcount(core_spill_mask_) + __builtin_popcount(fp_spill_mask_))); } else { - const uint16_t* vmap_table_ = reinterpret_cast<const uint16_t*>(begin_ + vmap_table_offset_); - DCHECK_EQ(vmap_table_[0], static_cast<uint32_t>(__builtin_popcount(core_spill_mask_) + - __builtin_popcount(fp_spill_mask_))); + VmapTable vmap_table(reinterpret_cast<const uint8_t*>(begin_ + vmap_table_offset_)); + + DCHECK_EQ(vmap_table.Size(), static_cast<uint32_t>(__builtin_popcount(core_spill_mask_) + + __builtin_popcount(fp_spill_mask_))); } } else { DCHECK_EQ(vmap_table_offset_, 0U); diff --git a/runtime/oat_file.h b/runtime/oat_file.h index fff6c8a..6503014 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -97,11 +97,11 @@ class OatFile { const void* GetCode() const; uint32_t GetCodeSize() const; - const uint32_t* GetMappingTable() const { - return GetOatPointer<const uint32_t*>(mapping_table_offset_); + const uint8_t* GetMappingTable() const { + return GetOatPointer<const uint8_t*>(mapping_table_offset_); } - const uint16_t* GetVmapTable() const { - return GetOatPointer<const uint16_t*>(vmap_table_offset_); + const uint8_t* GetVmapTable() const { + return GetOatPointer<const uint8_t*>(vmap_table_offset_); } const uint8_t* GetNativeGcMap() const { return GetOatPointer<const uint8_t*>(native_gc_map_offset_); diff --git a/runtime/stack.cc b/runtime/stack.cc index 7f3f40c..e1a752a 100644 --- a/runtime/stack.cc +++ b/runtime/stack.cc @@ -24,6 +24,7 @@ #include "object_utils.h" #include "thread_list.h" #include "throw_location.h" +#include "vmap_table.h" namespace art { @@ -135,10 +136,10 @@ uint32_t StackVisitor::GetVReg(mirror::AbstractMethod* m, uint16_t vreg, VRegKin if (cur_quick_frame_ != NULL) { DCHECK(context_ != NULL); // You can't reliably read registers without a context. DCHECK(m == GetMethod()); - const VmapTable vmap_table(m->GetVmapTableRaw()); + const VmapTable vmap_table(m->GetVmapTable()); uint32_t vmap_offset; // TODO: IsInContext stops before spotting floating point registers. - if (vmap_table.IsInContext(vreg, vmap_offset, kind)) { + if (vmap_table.IsInContext(vreg, kind, &vmap_offset)) { bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg); uint32_t spill_mask = is_float ? m->GetFpSpillMask() : m->GetCoreSpillMask(); @@ -160,10 +161,10 @@ void StackVisitor::SetVReg(mirror::AbstractMethod* m, uint16_t vreg, uint32_t ne if (cur_quick_frame_ != NULL) { DCHECK(context_ != NULL); // You can't reliably write registers without a context. DCHECK(m == GetMethod()); - const VmapTable vmap_table(m->GetVmapTableRaw()); + const VmapTable vmap_table(m->GetVmapTable()); uint32_t vmap_offset; // TODO: IsInContext stops before spotting floating point registers. - if (vmap_table.IsInContext(vreg, vmap_offset, kind)) { + if (vmap_table.IsInContext(vreg, kind, &vmap_offset)) { bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg); uint32_t spill_mask = is_float ? m->GetFpSpillMask() : m->GetCoreSpillMask(); const uint32_t reg = vmap_table.ComputeRegister(spill_mask, vmap_offset, kReferenceVReg); diff --git a/runtime/stack.h b/runtime/stack.h index de93846..388e401 100644 --- a/runtime/stack.h +++ b/runtime/stack.h @@ -571,78 +571,6 @@ class StackVisitor { Context* const context_; }; -class VmapTable { - public: - explicit VmapTable(const uint16_t* table) : table_(table) { - } - - uint16_t operator[](size_t i) const { - return table_[i + 1]; - } - - size_t size() const { - return table_[0]; - } - - // Is the dex register 'vreg' in the context or on the stack? Should not be called when the - // 'kind' is unknown or constant. - bool IsInContext(size_t vreg, uint32_t& vmap_offset, VRegKind kind) const { - DCHECK(kind == kReferenceVReg || kind == kIntVReg || kind == kFloatVReg || - kind == kLongLoVReg || kind == kLongHiVReg || kind == kDoubleLoVReg || - kind == kDoubleHiVReg || kind == kImpreciseConstant); - vmap_offset = 0xEBAD0FF5; - // TODO: take advantage of the registers being ordered - // TODO: we treat kImpreciseConstant as an integer below, need to ensure that such values - // are never promoted to floating point registers. - bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg); - bool in_floats = false; - for (size_t i = 0; i < size(); ++i) { - // Stop if we find what we are are looking for. - if ((table_[i + 1] == vreg) && (in_floats == is_float)) { - vmap_offset = i; - return true; - } - // 0xffff is the marker for LR (return PC on x86), following it are spilled float registers. - if (table_[i + 1] == 0xffff) { - in_floats = true; - } - } - return false; - } - - // Compute the register number that corresponds to the entry in the vmap (vmap_offset, computed - // by IsInContext above). If the kind is floating point then the result will be a floating point - // register number, otherwise it will be an integer register number. - uint32_t ComputeRegister(uint32_t spill_mask, uint32_t vmap_offset, VRegKind kind) const { - // Compute the register we need to load from the context. - DCHECK(kind == kReferenceVReg || kind == kIntVReg || kind == kFloatVReg || - kind == kLongLoVReg || kind == kLongHiVReg || kind == kDoubleLoVReg || - kind == kDoubleHiVReg || kind == kImpreciseConstant); - // TODO: we treat kImpreciseConstant as an integer below, need to ensure that such values - // are never promoted to floating point registers. - bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg); - uint32_t matches = 0; - if (is_float) { - while (table_[matches] != 0xffff) { - matches++; - } - } - CHECK_LT(vmap_offset - matches, static_cast<uint32_t>(__builtin_popcount(spill_mask))); - uint32_t spill_shifts = 0; - while (matches != (vmap_offset + 1)) { - DCHECK_NE(spill_mask, 0u); - matches += spill_mask & 1; // Add 1 if the low bit is set - spill_mask >>= 1; - spill_shifts++; - } - spill_shifts--; // wind back one as we want the last match - return spill_shifts; - } - - private: - const uint16_t* table_; -}; - } // namespace art #endif // ART_RUNTIME_STACK_H_ diff --git a/runtime/thread.cc b/runtime/thread.cc index c79caa2..07a003d 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -66,6 +66,7 @@ #include "utils.h" #include "verifier/dex_gc_map.h" #include "verifier/method_verifier.h" +#include "vmap_table.h" #include "well_known_classes.h" namespace art { @@ -2043,7 +2044,7 @@ class ReferenceMapVisitor : public StackVisitor { if (num_regs > 0) { const uint8_t* reg_bitmap = map.FindBitMap(GetNativePcOffset()); DCHECK(reg_bitmap != NULL); - const VmapTable vmap_table(m->GetVmapTableRaw()); + const VmapTable vmap_table(m->GetVmapTable()); uint32_t core_spills = m->GetCoreSpillMask(); uint32_t fp_spills = m->GetFpSpillMask(); size_t frame_size = m->GetFrameSizeInBytes(); @@ -2055,7 +2056,7 @@ class ReferenceMapVisitor : public StackVisitor { if (TestBitmap(reg, reg_bitmap)) { uint32_t vmap_offset; mirror::Object* ref; - if (vmap_table.IsInContext(reg, vmap_offset, kReferenceVReg)) { + if (vmap_table.IsInContext(reg, kReferenceVReg, &vmap_offset)) { uintptr_t val = GetGPR(vmap_table.ComputeRegister(core_spills, vmap_offset, kReferenceVReg)); ref = reinterpret_cast<mirror::Object*>(val); diff --git a/runtime/vmap_table.h b/runtime/vmap_table.h new file mode 100644 index 0000000..abc50b9 --- /dev/null +++ b/runtime/vmap_table.h @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_VMAP_TABLE_H_ +#define ART_RUNTIME_VMAP_TABLE_H_ + +#include "base/logging.h" +#include "leb128.h" +#include "stack.h" + +namespace art { + +class VmapTable { + public: + explicit VmapTable(const uint8_t* table) : table_(table) { + } + + // Look up nth entry, not called from performance critical code. + uint16_t operator[](size_t n) const { + const uint8_t* table = table_; + size_t size = DecodeUnsignedLeb128(&table); + CHECK_LT(n, size); + uint16_t entry = DecodeUnsignedLeb128(&table); + for (size_t i = 0; i < n; ++i) { + entry = DecodeUnsignedLeb128(&table); + } + return entry; + } + + size_t Size() const { + const uint8_t* table = table_; + return DecodeUnsignedLeb128(&table); + } + + // Is the dex register 'vreg' in the context or on the stack? Should not be called when the + // 'kind' is unknown or constant. + bool IsInContext(size_t vreg, VRegKind kind, uint32_t* vmap_offset) const { + DCHECK(kind == kReferenceVReg || kind == kIntVReg || kind == kFloatVReg || + kind == kLongLoVReg || kind == kLongHiVReg || kind == kDoubleLoVReg || + kind == kDoubleHiVReg || kind == kImpreciseConstant); + *vmap_offset = 0xEBAD0FF5; + // TODO: take advantage of the registers being ordered + // TODO: we treat kImpreciseConstant as an integer below, need to ensure that such values + // are never promoted to floating point registers. + bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg); + bool in_floats = false; + const uint8_t* table = table_; + size_t end = DecodeUnsignedLeb128(&table); + for (size_t i = 0; i < end; ++i) { + // Stop if we find what we are are looking for. + uint16_t entry = DecodeUnsignedLeb128(&table); + if ((entry == vreg) && (in_floats == is_float)) { + *vmap_offset = i; + return true; + } + // 0xffff is the marker for LR (return PC on x86), following it are spilled float registers. + if (entry == 0xffff) { + in_floats = true; + } + } + return false; + } + + // Compute the register number that corresponds to the entry in the vmap (vmap_offset, computed + // by IsInContext above). If the kind is floating point then the result will be a floating point + // register number, otherwise it will be an integer register number. + uint32_t ComputeRegister(uint32_t spill_mask, uint32_t vmap_offset, VRegKind kind) const { + // Compute the register we need to load from the context. + DCHECK(kind == kReferenceVReg || kind == kIntVReg || kind == kFloatVReg || + kind == kLongLoVReg || kind == kLongHiVReg || kind == kDoubleLoVReg || + kind == kDoubleHiVReg || kind == kImpreciseConstant); + // TODO: we treat kImpreciseConstant as an integer below, need to ensure that such values + // are never promoted to floating point registers. + bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg); + uint32_t matches = 0; + if (UNLIKELY(is_float)) { + const uint8_t* table = table_; + DecodeUnsignedLeb128(&table); // Skip size. + while (DecodeUnsignedLeb128(&table) != 0xffff) { + matches++; + } + matches++; + } + CHECK_LT(vmap_offset - matches, static_cast<uint32_t>(__builtin_popcount(spill_mask))); + uint32_t spill_shifts = 0; + while (matches != (vmap_offset + 1)) { + DCHECK_NE(spill_mask, 0u); + matches += spill_mask & 1; // Add 1 if the low bit is set + spill_mask >>= 1; + spill_shifts++; + } + spill_shifts--; // wind back one as we want the last match + return spill_shifts; + } + + private: + const uint8_t* const table_; +}; + +} // namespace art + +#endif // ART_RUNTIME_VMAP_TABLE_H_ |