diff options
author | Brian Carlstrom <bdc@google.com> | 2013-08-27 17:31:03 -0700 |
---|---|---|
committer | Brian Carlstrom <bdc@google.com> | 2013-10-28 00:06:03 -0700 |
commit | ba150c37d582eeeb8c11ba5245edc281cf31793c (patch) | |
tree | ca12cf82602e4b78b2a6ca463e9d0e35fc5e3ff6 /runtime | |
parent | 3c2a6e2468e3e519ade6c3cfcaad7cd34243cdf1 (diff) | |
download | art-ba150c37d582eeeb8c11ba5245edc281cf31793c.zip art-ba150c37d582eeeb8c11ba5245edc281cf31793c.tar.gz art-ba150c37d582eeeb8c11ba5245edc281cf31793c.tar.bz2 |
Omit OatMethodOffsets for classes without compiled code
Change-Id: If0d290f4aebc778ff12d8fed017c270ad2ac3220
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/Android.mk | 3 | ||||
-rw-r--r-- | runtime/base/allocator.cc | 74 | ||||
-rw-r--r-- | runtime/base/allocator.h | 41 | ||||
-rw-r--r-- | runtime/base/bit_vector.cc | 177 | ||||
-rw-r--r-- | runtime/base/bit_vector.h | 134 | ||||
-rw-r--r-- | runtime/base/bit_vector_test.cc | 122 | ||||
-rw-r--r-- | runtime/exception_test.cc | 2 | ||||
-rw-r--r-- | runtime/globals.h | 20 | ||||
-rw-r--r-- | runtime/mirror/class.h | 1 | ||||
-rw-r--r-- | runtime/oat.cc | 2 | ||||
-rw-r--r-- | runtime/oat.h | 13 | ||||
-rw-r--r-- | runtime/oat_file.cc | 80 | ||||
-rw-r--r-- | runtime/oat_file.h | 20 |
13 files changed, 668 insertions, 21 deletions
diff --git a/runtime/Android.mk b/runtime/Android.mk index 8579222..e4b7e47 100644 --- a/runtime/Android.mk +++ b/runtime/Android.mk @@ -21,6 +21,8 @@ include art/build/Android.common.mk LIBART_COMMON_SRC_FILES := \ atomic.cc.arm \ barrier.cc \ + base/allocator.cc \ + base/bit_vector.cc \ base/logging.cc \ base/mutex.cc \ base/stringpiece.cc \ @@ -247,6 +249,7 @@ LIBART_ENUM_OPERATOR_OUT_HEADER_FILES := \ locks.h \ lock_word.h \ mirror/class.h \ + oat.h \ thread.h \ thread_state.h \ verifier/method_verifier.h diff --git a/runtime/base/allocator.cc b/runtime/base/allocator.cc new file mode 100644 index 0000000..4f7753d --- /dev/null +++ b/runtime/base/allocator.cc @@ -0,0 +1,74 @@ +/* + * 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. + */ + +#include "allocator.h" + +#include <inttypes.h> +#include <stdlib.h> + +#include "base/logging.h" + +namespace art { + +class MallocAllocator : public Allocator { + public: + explicit MallocAllocator() {} + ~MallocAllocator() {} + + virtual void* Alloc(size_t size) { + return calloc(sizeof(uint8_t), size); + } + + virtual void Free(void* p) { + free(p); + } + + private: + DISALLOW_COPY_AND_ASSIGN(MallocAllocator); +}; + +MallocAllocator g_malloc_allocator; + +class NoopAllocator : public Allocator { + public: + explicit NoopAllocator() {} + ~NoopAllocator() {} + + virtual void* Alloc(size_t size) { + LOG(FATAL) << "NoopAllocator::Alloc should not be called"; + return NULL; + } + + virtual void Free(void* p) { + // Noop. + } + + private: + DISALLOW_COPY_AND_ASSIGN(NoopAllocator); +}; + +NoopAllocator g_noop_allocator; + +Allocator* Allocator::GetMallocAllocator() { + return &g_malloc_allocator; +} + +Allocator* Allocator::GetNoopAllocator() { + return &g_noop_allocator; +} + + +} // namespace art diff --git a/runtime/base/allocator.h b/runtime/base/allocator.h new file mode 100644 index 0000000..917bf0b --- /dev/null +++ b/runtime/base/allocator.h @@ -0,0 +1,41 @@ +/* + * 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_BASE_ALLOCATOR_H_ +#define ART_RUNTIME_BASE_ALLOCATOR_H_ + +#include "base/macros.h" + +namespace art { + +class Allocator { + public: + static Allocator* GetMallocAllocator(); + static Allocator* GetNoopAllocator(); + + Allocator() {} + virtual ~Allocator() {} + + virtual void* Alloc(size_t) = 0; + virtual void Free(void*) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(Allocator); +}; + +} // namespace art + +#endif // ART_RUNTIME_BASE_ALLOCATOR_H_ diff --git a/runtime/base/bit_vector.cc b/runtime/base/bit_vector.cc new file mode 100644 index 0000000..3b82651 --- /dev/null +++ b/runtime/base/bit_vector.cc @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "bit_vector.h" + +namespace art { + +// TODO: profile to make sure this is still a win relative to just using shifted masks. +static uint32_t check_masks[32] = { + 0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010, + 0x00000020, 0x00000040, 0x00000080, 0x00000100, 0x00000200, + 0x00000400, 0x00000800, 0x00001000, 0x00002000, 0x00004000, + 0x00008000, 0x00010000, 0x00020000, 0x00040000, 0x00080000, + 0x00100000, 0x00200000, 0x00400000, 0x00800000, 0x01000000, + 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, + 0x40000000, 0x80000000 }; + +static inline uint32_t BitsToWords(uint32_t bits) { + return (bits + 31) >> 5; +} + +// TODO: replace excessive argument defaulting when we are at gcc 4.7 +// or later on host with delegating constructor support. Specifically, +// starts_bits and storage_size/storage are mutually exclusive. +BitVector::BitVector(uint32_t start_bits, + bool expandable, + Allocator* allocator, + uint32_t storage_size, + uint32_t* storage) + : allocator_(allocator), + expandable_(expandable), + storage_size_(storage_size), + storage_(storage) { + DCHECK_EQ(sizeof(storage_[0]), 4U); // Assuming 32-bit units. + if (storage_ == NULL) { + storage_size_ = BitsToWords(start_bits); + storage_ = static_cast<uint32_t*>(allocator_->Alloc(storage_size_ * sizeof(uint32_t))); + } +} + +BitVector::~BitVector() { + allocator_->Free(storage_); +} + +/* + * Determine whether or not the specified bit is set. + */ +bool BitVector::IsBitSet(uint32_t num) const { + DCHECK_LT(num, storage_size_ * sizeof(uint32_t) * 8); + + uint32_t val = storage_[num >> 5] & check_masks[num & 0x1f]; + return (val != 0); +} + +// Mark all bits bit as "clear". +void BitVector::ClearAllBits() { + memset(storage_, 0, storage_size_ * sizeof(uint32_t)); +} + +// Mark the specified bit as "set". +/* + * TUNING: this could have pathologically bad growth/expand behavior. Make sure we're + * not using it badly or change resize mechanism. + */ +void BitVector::SetBit(uint32_t num) { + if (num >= storage_size_ * sizeof(uint32_t) * 8) { + DCHECK(expandable_) << "Attempted to expand a non-expandable bitmap to position " << num; + + /* Round up to word boundaries for "num+1" bits */ + uint32_t new_size = BitsToWords(num + 1); + DCHECK_GT(new_size, storage_size_); + uint32_t *new_storage = + static_cast<uint32_t*>(allocator_->Alloc(new_size * sizeof(uint32_t))); + memcpy(new_storage, storage_, storage_size_ * sizeof(uint32_t)); + // Zero out the new storage words. + memset(&new_storage[storage_size_], 0, (new_size - storage_size_) * sizeof(uint32_t)); + // TOTO: collect stats on space wasted because of resize. + storage_ = new_storage; + storage_size_ = new_size; + } + + storage_[num >> 5] |= check_masks[num & 0x1f]; +} + +// Mark the specified bit as "unset". +void BitVector::ClearBit(uint32_t num) { + DCHECK_LT(num, storage_size_ * sizeof(uint32_t) * 8); + storage_[num >> 5] &= ~check_masks[num & 0x1f]; +} + +// Intersect with another bit vector. Sizes and expandability must be the same. +void BitVector::Intersect(const BitVector* src) { + DCHECK_EQ(storage_size_, src->GetStorageSize()); + DCHECK_EQ(expandable_, src->IsExpandable()); + for (uint32_t idx = 0; idx < storage_size_; idx++) { + storage_[idx] &= src->GetRawStorageWord(idx); + } +} + +/* + * Union with another bit vector. Sizes and expandability must be the same. + */ +void BitVector::Union(const BitVector* src) { + DCHECK_EQ(storage_size_, src->GetStorageSize()); + DCHECK_EQ(expandable_, src->IsExpandable()); + for (uint32_t idx = 0; idx < storage_size_; idx++) { + storage_[idx] |= src->GetRawStorageWord(idx); + } +} + +// Count the number of bits that are set. +uint32_t BitVector::NumSetBits() const { + uint32_t count = 0; + for (uint32_t word = 0; word < storage_size_; word++) { + count += __builtin_popcount(storage_[word]); + } + return count; +} + +// Count the number of bits that are set up through and including num. +uint32_t BitVector::NumSetBits(uint32_t num) const { + DCHECK_LT(num, storage_size_ * sizeof(uint32_t) * 8); + uint32_t last_word = num >> 5; + uint32_t partial_word_bits = num & 0x1f; + + // partial_word_bits | # | | | partial_word_mask + // 00000 | 0 | 0xffffffff >> (31 - 0) | (1 << (0 + 1)) - 1 | 0x00000001 + // 00001 | 1 | 0xffffffff >> (31 - 1) | (1 << (1 + 1)) - 1 | 0x00000003 + // 00010 | 2 | 0xffffffff >> (31 - 2) | (1 << (2 + 1)) - 1 | 0x00000007 + // ..... | + // 11110 | 30 | 0xffffffff >> (31 - 30) | (1 << (30 + 1)) - 1 | 0x7fffffff + // 11111 | 31 | 0xffffffff >> (31 - 31) | last_full_word++ | 0xffffffff + uint32_t partial_word_mask = 0xffffffff >> (0x1f - partial_word_bits); + + uint32_t count = 0; + for (uint32_t word = 0; word < last_word; word++) { + count += __builtin_popcount(storage_[word]); + } + count += __builtin_popcount(storage_[last_word] & partial_word_mask); + return count; +} + +BitVector::Iterator* BitVector::GetIterator() const { + return new (allocator_) Iterator(this); +} + +/* + * Mark specified number of bits as "set". Cannot set all bits like ClearAll + * since there might be unused bits - setting those to one will confuse the + * iterator. + */ +void BitVector::SetInitialBits(uint32_t num_bits) { + DCHECK_LE(BitsToWords(num_bits), storage_size_); + uint32_t idx; + for (idx = 0; idx < (num_bits >> 5); idx++) { + storage_[idx] = -1; + } + uint32_t rem_num_bits = num_bits & 0x1f; + if (rem_num_bits) { + storage_[idx] = (1 << rem_num_bits) - 1; + } +} + +} // namespace art diff --git a/runtime/base/bit_vector.h b/runtime/base/bit_vector.h new file mode 100644 index 0000000..74bec08 --- /dev/null +++ b/runtime/base/bit_vector.h @@ -0,0 +1,134 @@ +/* + * 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_BASE_BIT_VECTOR_H_ +#define ART_RUNTIME_BASE_BIT_VECTOR_H_ + +#include <stdint.h> +#include <stddef.h> + +#include "allocator.h" +#include "base/logging.h" +#include "utils.h" + +namespace art { + +/* + * Expanding bitmap, used for tracking resources. Bits are numbered starting + * from zero. All operations on a BitVector are unsynchronized. + */ +class BitVector { + public: + class Iterator { + public: + explicit Iterator(const BitVector* bit_vector) + : p_bits_(bit_vector), + bit_storage_(bit_vector->GetRawStorage()), + bit_index_(0), + bit_size_(p_bits_->storage_size_ * sizeof(uint32_t) * 8) {} + + // Return the position of the next set bit. -1 means end-of-element reached. + int32_t Next() { + // Did anything obviously change since we started? + DCHECK_EQ(bit_size_, p_bits_->GetStorageSize() * sizeof(uint32_t) * 8); + DCHECK_EQ(bit_storage_, p_bits_->GetRawStorage()); + + if (UNLIKELY(bit_index_ >= bit_size_)) return -1; + + uint32_t word_index = bit_index_ / 32; + uint32_t word = bit_storage_[word_index]; + // Mask out any bits in the first word we've already considered. + word >>= bit_index_ & 0x1f; + if (word == 0) { + bit_index_ &= ~0x1f; + do { + word_index++; + if (UNLIKELY((word_index * 32) >= bit_size_)) { + bit_index_ = bit_size_; + return -1; + } + word = bit_storage_[word_index]; + bit_index_ += 32; + } while (word == 0); + } + bit_index_ += CTZ(word) + 1; + return bit_index_ - 1; + } + + static void* operator new(size_t size, Allocator* allocator) { + return allocator->Alloc(sizeof(BitVector::Iterator)); + }; + static void operator delete(void* p) { + Iterator* it = reinterpret_cast<Iterator*>(p); + it->p_bits_->allocator_->Free(p); + } + + private: + const BitVector* const p_bits_; + const uint32_t* const bit_storage_; + uint32_t bit_index_; // Current index (size in bits). + const uint32_t bit_size_; // Size of vector in bits. + + friend class BitVector; + }; + + BitVector(uint32_t start_bits, + bool expandable, + Allocator* allocator, + uint32_t storage_size = 0, + uint32_t* storage = NULL); + + virtual ~BitVector(); + + void SetBit(uint32_t num); + void ClearBit(uint32_t num); + bool IsBitSet(uint32_t num) const; + void ClearAllBits(); + void SetInitialBits(uint32_t num_bits); + void Copy(BitVector* src) { + memcpy(storage_, src->GetRawStorage(), sizeof(uint32_t) * storage_size_); + } + void Intersect(const BitVector* src2); + void Union(const BitVector* src); + // Are we equal to another bit vector? Note: expandability attributes must also match. + bool Equal(const BitVector* src) { + return (storage_size_ == src->GetStorageSize()) && + (expandable_ == src->IsExpandable()) && + (memcmp(storage_, src->GetRawStorage(), storage_size_ * sizeof(uint32_t)) == 0); + } + uint32_t NumSetBits() const; + uint32_t NumSetBits(uint32_t num) const; + + Iterator* GetIterator() const; + + uint32_t GetStorageSize() const { return storage_size_; } + bool IsExpandable() const { return expandable_; } + uint32_t GetRawStorageWord(size_t idx) const { return storage_[idx]; } + uint32_t* GetRawStorage() { return storage_; } + const uint32_t* GetRawStorage() const { return storage_; } + size_t GetSizeOf() const { return storage_size_ * sizeof(uint32_t); } + + private: + Allocator* const allocator_; + const bool expandable_; // expand bitmap if we run out? + uint32_t storage_size_; // current size, in 32-bit words. + uint32_t* storage_; +}; + + +} // namespace art + +#endif // ART_RUNTIME_BASE_BIT_VECTOR_H_ diff --git a/runtime/base/bit_vector_test.cc b/runtime/base/bit_vector_test.cc new file mode 100644 index 0000000..d99d059 --- /dev/null +++ b/runtime/base/bit_vector_test.cc @@ -0,0 +1,122 @@ +/* + * 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. + */ + +#include "UniquePtr.h" +#include "bit_vector.h" +#include "gtest/gtest.h" + +namespace art { + +TEST(BitVector, Test) { + const size_t kBits = 32; + + BitVector bv(kBits, false, Allocator::GetMallocAllocator()); + EXPECT_EQ(1U, bv.GetStorageSize()); + EXPECT_EQ(kWordSize, bv.GetSizeOf()); + EXPECT_FALSE(bv.IsExpandable()); + + EXPECT_EQ(0U, bv.NumSetBits()); + EXPECT_EQ(0U, bv.NumSetBits(0)); + EXPECT_EQ(0U, bv.NumSetBits(kBits - 1)); + for (size_t i = 0; i < kBits; i++) { + EXPECT_FALSE(bv.IsBitSet(i)); + } + EXPECT_EQ(0U, bv.GetRawStorageWord(0)); + EXPECT_EQ(0U, *bv.GetRawStorage()); + + BitVector::Iterator empty_iterator(&bv); + EXPECT_EQ(-1, empty_iterator.Next()); + + UniquePtr<BitVector::Iterator> empty_iterator_on_heap(bv.GetIterator()); + EXPECT_EQ(-1, empty_iterator_on_heap->Next()); + + bv.SetBit(0); + bv.SetBit(kBits - 1); + EXPECT_EQ(2U, bv.NumSetBits()); + EXPECT_EQ(1U, bv.NumSetBits(0)); + EXPECT_EQ(2U, bv.NumSetBits(kBits - 1)); + EXPECT_TRUE(bv.IsBitSet(0)); + for (size_t i = 1; i < kBits - 1; i++) { + EXPECT_FALSE(bv.IsBitSet(i)); + } + EXPECT_TRUE(bv.IsBitSet(kBits - 1)); + EXPECT_EQ(0x80000001U, bv.GetRawStorageWord(0)); + EXPECT_EQ(0x80000001U, *bv.GetRawStorage()); + + BitVector::Iterator iterator(&bv); + EXPECT_EQ(0, iterator.Next()); + EXPECT_EQ(static_cast<int>(kBits - 1), iterator.Next()); + EXPECT_EQ(-1, iterator.Next()); +} + +TEST(BitVector, NoopAllocator) { + const uint32_t kWords = 2; + + uint32_t bits[kWords]; + memset(bits, 0, sizeof(bits)); + + BitVector bv(0U, false, Allocator::GetNoopAllocator(), kWords, bits); + EXPECT_EQ(kWords, bv.GetStorageSize()); + EXPECT_EQ(kWords * kWordSize, bv.GetSizeOf()); + EXPECT_EQ(bits, bv.GetRawStorage()); + EXPECT_EQ(0U, bv.NumSetBits()); + + bv.SetBit(8); + EXPECT_EQ(1U, bv.NumSetBits()); + EXPECT_EQ(0x00000100U, bv.GetRawStorageWord(0)); + EXPECT_EQ(0x00000000U, bv.GetRawStorageWord(1)); + EXPECT_EQ(1U, bv.NumSetBits()); + + bv.SetBit(16); + EXPECT_EQ(2U, bv.NumSetBits()); + EXPECT_EQ(0x00010100U, bv.GetRawStorageWord(0)); + EXPECT_EQ(0x00000000U, bv.GetRawStorageWord(1)); + EXPECT_EQ(2U, bv.NumSetBits()); + + bv.SetBit(32); + EXPECT_EQ(3U, bv.NumSetBits()); + EXPECT_EQ(0x00010100U, bv.GetRawStorageWord(0)); + EXPECT_EQ(0x00000001U, bv.GetRawStorageWord(1)); + EXPECT_EQ(3U, bv.NumSetBits()); + + bv.SetBit(48); + EXPECT_EQ(4U, bv.NumSetBits()); + EXPECT_EQ(0x00010100U, bv.GetRawStorageWord(0)); + EXPECT_EQ(0x00010001U, bv.GetRawStorageWord(1)); + EXPECT_EQ(4U, bv.NumSetBits()); + + EXPECT_EQ(0U, bv.NumSetBits(0)); + + EXPECT_EQ(0U, bv.NumSetBits(7)); + EXPECT_EQ(1U, bv.NumSetBits(8)); + EXPECT_EQ(1U, bv.NumSetBits(9)); + + EXPECT_EQ(1U, bv.NumSetBits(15)); + EXPECT_EQ(2U, bv.NumSetBits(16)); + EXPECT_EQ(2U, bv.NumSetBits(17)); + + EXPECT_EQ(2U, bv.NumSetBits(31)); + EXPECT_EQ(3U, bv.NumSetBits(32)); + EXPECT_EQ(3U, bv.NumSetBits(33)); + + EXPECT_EQ(3U, bv.NumSetBits(47)); + EXPECT_EQ(4U, bv.NumSetBits(48)); + EXPECT_EQ(4U, bv.NumSetBits(49)); + + EXPECT_EQ(4U, bv.NumSetBits(63)); +} + +} // namespace art diff --git a/runtime/exception_test.cc b/runtime/exception_test.cc index 2e6b0a8..a5f9997 100644 --- a/runtime/exception_test.cc +++ b/runtime/exception_test.cc @@ -146,7 +146,7 @@ TEST_F(ExceptionTest, StackTraceElement) { ScopedObjectAccess soa(env); std::vector<uintptr_t> fake_stack; - ASSERT_EQ(kStackAlignment, 16); + ASSERT_EQ(kStackAlignment, 16U); ASSERT_EQ(sizeof(uintptr_t), sizeof(uint32_t)); #if !defined(ART_USE_PORTABLE_COMPILER) diff --git a/runtime/globals.h b/runtime/globals.h index c397494..31574ff 100644 --- a/runtime/globals.h +++ b/runtime/globals.h @@ -30,30 +30,30 @@ const size_t KB = 1024; const size_t MB = KB * KB; const size_t GB = KB * KB * KB; -const int kWordSize = sizeof(word); -const int kPointerSize = sizeof(void*); +const size_t kWordSize = sizeof(word); +const size_t kPointerSize = sizeof(void*); -const int kBitsPerByte = 8; -const int kBitsPerByteLog2 = 3; +const size_t kBitsPerByte = 8; +const size_t kBitsPerByteLog2 = 3; const int kBitsPerWord = kWordSize * kBitsPerByte; -const int kWordHighBitMask = 1 << (kBitsPerWord - 1); +const size_t kWordHighBitMask = 1 << (kBitsPerWord - 1); // Required stack alignment -const int kStackAlignment = 16; +const size_t kStackAlignment = 16; // Required object alignment -const int kObjectAlignment = 8; +const size_t kObjectAlignment = 8; // ARM instruction alignment. ARM processors require code to be 4-byte aligned, // but ARM ELF requires 8.. -const int kArmAlignment = 8; +const size_t kArmAlignment = 8; // MIPS instruction alignment. MIPS processors require code to be 4-byte aligned. // TODO: Can this be 4? -const int kMipsAlignment = 8; +const size_t kMipsAlignment = 8; // X86 instruction alignment. This is the recommended alignment for maximum performance. -const int kX86Alignment = 16; +const size_t kX86Alignment = 16; // System page size. We check this against sysconf(_SC_PAGE_SIZE) at runtime, but use a simple // compile-time constant so the compiler can generate better code. diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index dbc6f57..d15f337 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -122,6 +122,7 @@ class MANAGED Class : public StaticStorageBase { kStatusVerified = 7, // Logically part of linking; done pre-init. kStatusInitializing = 8, // Class init in progress. kStatusInitialized = 9, // Ready to go. + kStatusMax = 10, }; Status GetStatus() const { diff --git a/runtime/oat.cc b/runtime/oat.cc index c01f77c..6fe5d10 100644 --- a/runtime/oat.cc +++ b/runtime/oat.cc @@ -22,7 +22,7 @@ namespace art { const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' }; -const uint8_t OatHeader::kOatVersion[] = { '0', '0', '7', '\0' }; +const uint8_t OatHeader::kOatVersion[] = { '0', '0', '8', '\0' }; OatHeader::OatHeader() { memset(this, 0, sizeof(*this)); diff --git a/runtime/oat.h b/runtime/oat.h index a653cf8..a9dc540 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -104,6 +104,19 @@ class PACKED(4) OatHeader { DISALLOW_COPY_AND_ASSIGN(OatHeader); }; +// OatMethodOffsets are currently 7x32-bits=224-bits long, so if we can +// save even one OatMethodOffsets struct, the more complicated encoding +// using a bitmap pays for itself since few classes will have 224 +// methods. +enum OatClassType { + kOatClassAllCompiled = 0, // OatClass is followed by an OatMethodOffsets for each method. + kOatClassSomeCompiled = 1, // A bitmap of which OatMethodOffsets are present follows the OatClass. + kOatClassNoneCompiled = 2, // All methods are interpretted so no OatMethodOffsets are necessary. + kOatClassMax = 3, +}; + +std::ostream& operator<<(std::ostream& os, const OatClassType& rhs); + class PACKED(4) OatMethodOffsets { public: OatMethodOffsets(); diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index 7553dcc..fa2b485 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -18,6 +18,7 @@ #include <dlfcn.h> +#include "base/bit_vector.h" #include "base/stl_util.h" #include "base/unix_file/fd_file.h" #include "elf_file.h" @@ -384,29 +385,92 @@ const OatFile::OatClass* OatFile::OatDexFile::GetOatClass(uint16_t class_def_ind const byte* oat_class_pointer = oat_file_->Begin() + oat_class_offset; CHECK_LT(oat_class_pointer, oat_file_->End()) << oat_file_->GetLocation(); - mirror::Class::Status status = *reinterpret_cast<const mirror::Class::Status*>(oat_class_pointer); - const byte* methods_pointer = oat_class_pointer + sizeof(status); + const byte* status_pointer = oat_class_pointer; + CHECK_LT(status_pointer, oat_file_->End()) << oat_file_->GetLocation(); + mirror::Class::Status status = + static_cast<mirror::Class::Status>(*reinterpret_cast<const int16_t*>(status_pointer)); + CHECK_LT(status, mirror::Class::kStatusMax); + + const byte* type_pointer = status_pointer + sizeof(uint16_t); + CHECK_LT(type_pointer, oat_file_->End()) << oat_file_->GetLocation(); + OatClassType type = static_cast<OatClassType>(*reinterpret_cast<const uint16_t*>(type_pointer)); + CHECK_LT(type, kOatClassMax); + + const byte* bitmap_pointer = type_pointer + sizeof(int16_t); + CHECK_LT(bitmap_pointer, oat_file_->End()) << oat_file_->GetLocation(); + uint32_t bitmap_size = 0; + if (type == kOatClassSomeCompiled) { + bitmap_size = static_cast<uint32_t>(*reinterpret_cast<const uint32_t*>(bitmap_pointer)); + bitmap_pointer += sizeof(bitmap_size); + CHECK_LT(bitmap_pointer, oat_file_->End()) << oat_file_->GetLocation(); + } + + const byte* methods_pointer = bitmap_pointer + bitmap_size; CHECK_LT(methods_pointer, oat_file_->End()) << oat_file_->GetLocation(); return new OatClass(oat_file_, status, + type, + bitmap_size, + reinterpret_cast<const uint32_t*>(bitmap_pointer), reinterpret_cast<const OatMethodOffsets*>(methods_pointer)); } OatFile::OatClass::OatClass(const OatFile* oat_file, mirror::Class::Status status, + OatClassType type, + uint32_t bitmap_size, + const uint32_t* bitmap_pointer, const OatMethodOffsets* methods_pointer) - : oat_file_(oat_file), status_(status), methods_pointer_(methods_pointer) {} - -OatFile::OatClass::~OatClass() {} + : oat_file_(oat_file), status_(status), type_(type), + bitmap_(NULL), methods_pointer_(methods_pointer) { + switch (type_) { + case kOatClassAllCompiled: { + CHECK_EQ(0U, bitmap_size); + break; + } + case kOatClassSomeCompiled: { + CHECK_NE(0U, bitmap_size); + bitmap_ = new BitVector(0, false, Allocator::GetNoopAllocator(), bitmap_size, + const_cast<uint32_t*>(bitmap_pointer)); + break; + } + case kOatClassNoneCompiled: { + CHECK_EQ(0U, bitmap_size); + methods_pointer_ = NULL; + break; + } + case kOatClassMax: { + LOG(FATAL) << "Invalid OatClassType " << type_; + break; + } + } +} -mirror::Class::Status OatFile::OatClass::GetStatus() const { - return status_; +OatFile::OatClass::~OatClass() { + delete bitmap_; } const OatFile::OatMethod OatFile::OatClass::GetOatMethod(uint32_t method_index) const { - const OatMethodOffsets& oat_method_offsets = methods_pointer_[method_index]; + if (methods_pointer_ == NULL) { + CHECK_EQ(kOatClassNoneCompiled, type_); + return OatMethod(NULL, 0, 0, 0, 0, 0, 0, 0); + } + size_t methods_pointer_index; + if (bitmap_ == NULL) { + CHECK_EQ(kOatClassAllCompiled, type_); + methods_pointer_index = method_index; + } else { + CHECK_EQ(kOatClassSomeCompiled, type_); + if (!bitmap_->IsBitSet(method_index)) { + return OatMethod(NULL, 0, 0, 0, 0, 0, 0, 0); + } + size_t num_set_bits = bitmap_->NumSetBits(method_index); + CHECK_NE(0U, num_set_bits); + methods_pointer_index = num_set_bits - 1; + } + const OatMethodOffsets& oat_method_offsets = methods_pointer_[methods_pointer_index]; return OatMethod( oat_file_->Begin(), oat_method_offsets.code_offset_, diff --git a/runtime/oat_file.h b/runtime/oat_file.h index af14760..887a9d1 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -29,6 +29,7 @@ namespace art { +class BitVector; class ElfFile; class MemMap; class OatMethodOffsets; @@ -145,7 +146,13 @@ class OatFile { class OatClass { public: - mirror::Class::Status GetStatus() const; + mirror::Class::Status GetStatus() const { + return status_; + } + + OatClassType GetType() const { + return type_; + } // get the OatMethod entry based on its index into the class // defintion. direct methods come first, followed by virtual @@ -157,10 +164,21 @@ class OatFile { private: OatClass(const OatFile* oat_file, mirror::Class::Status status, + OatClassType type, + uint32_t bitmap_size, + const uint32_t* bitmap_pointer, const OatMethodOffsets* methods_pointer); const OatFile* oat_file_; + const mirror::Class::Status status_; + COMPILE_ASSERT(mirror::Class::Status::kStatusMax < (2 ^ 16), class_status_wont_fit_in_16bits); + + OatClassType type_; + COMPILE_ASSERT(OatClassType::kOatClassMax < (2 ^ 16), oat_class_type_wont_fit_in_16bits); + + const BitVector* bitmap_; + const OatMethodOffsets* methods_pointer_; friend class OatDexFile; |