Make CodeItem fields private
Make code item fields private and use accessors. Added a hand full of
friend classes to reduce the size of the change.
Changed default to be nullable and removed CreateNullable.
CreateNullable was a bad API since it defaulted to the unsafe, may
add a CreateNonNullable if it's important for performance.
Motivation:
Have a different layout for code items in cdex.
Bug: 63756964
Test: test-art-host-gtest
Test: test/testrunner/testrunner.py --host
Test: art/tools/run-jdwp-tests.sh '--mode=host' '--variant=X32' --debug
Change-Id: I42bc7435e20358682075cb6de52713b595f95bf9
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 869394c..c6c4f4a 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -459,16 +459,8 @@
}
}
-inline IterationRange<DexInstructionIterator> ArtMethod::DexInstructions() {
- CodeItemInstructionAccessor accessor(this);
- return { accessor.begin(),
- accessor.end() };
-}
-
-inline IterationRange<DexInstructionIterator> ArtMethod::NullableDexInstructions() {
- CodeItemInstructionAccessor accessor(CodeItemInstructionAccessor::CreateNullable(this));
- return { accessor.begin(),
- accessor.end() };
+inline CodeItemInstructionAccessor ArtMethod::DexInstructions() {
+ return CodeItemInstructionAccessor(this);
}
} // namespace art
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 9005120..7ddaa7e 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -297,9 +297,8 @@
}
}
if (found_dex_pc != dex::kDexNoIndex) {
- const Instruction* first_catch_instr =
- Instruction::At(&code_item->insns_[found_dex_pc]);
- *has_no_move_exception = (first_catch_instr->Opcode() != Instruction::MOVE_EXCEPTION);
+ const Instruction& first_catch_instr = DexInstructions().InstructionAt(found_dex_pc);
+ *has_no_move_exception = (first_catch_instr.Opcode() != Instruction::MOVE_EXCEPTION);
}
// Put the exception back.
if (exception != nullptr) {
diff --git a/runtime/art_method.h b/runtime/art_method.h
index f433223..ab90a10 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -27,6 +27,7 @@
#include "base/iteration_range.h"
#include "base/macros.h"
#include "base/runtime_debug.h"
+#include "code_item_accessors.h"
#include "dex_file.h"
#include "dex_instruction_iterator.h"
#include "gc_root.h"
@@ -716,13 +717,9 @@
"ptr_sized_fields_.entry_point_from_quick_compiled_code_");
}
- // Returns the dex instructions of the code item for the art method. Must not be called on null
- // code items.
- ALWAYS_INLINE IterationRange<DexInstructionIterator> DexInstructions()
- REQUIRES_SHARED(Locks::mutator_lock_);
-
- // Handles a null code item by returning iterators that have a null address.
- ALWAYS_INLINE IterationRange<DexInstructionIterator> NullableDexInstructions()
+ // Returns the dex instructions of the code item for the art method. Returns an empty array for
+ // the null code item case.
+ ALWAYS_INLINE CodeItemInstructionAccessor DexInstructions()
REQUIRES_SHARED(Locks::mutator_lock_);
protected:
diff --git a/runtime/check_reference_map_visitor.h b/runtime/check_reference_map_visitor.h
index d9e8915..c4a613a 100644
--- a/runtime/check_reference_map_visitor.h
+++ b/runtime/check_reference_map_visitor.h
@@ -18,6 +18,7 @@
#define ART_RUNTIME_CHECK_REFERENCE_MAP_VISITOR_H_
#include "art_method-inl.h"
+#include "code_item_accessors-inl.h"
#include "dex_file_types.h"
#include "oat_quick_method_header.h"
#include "scoped_thread_state_change-inl.h"
@@ -66,14 +67,15 @@
CodeInfo code_info = GetCurrentOatQuickMethodHeader()->GetOptimizedCodeInfo();
CodeInfoEncoding encoding = code_info.ExtractEncoding();
StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding);
- uint16_t number_of_dex_registers = m->GetCodeItem()->registers_size_;
+ CodeItemDataAccessor accessor(m);
+ uint16_t number_of_dex_registers = accessor.RegistersSize();
DexRegisterMap dex_register_map =
code_info.GetDexRegisterMapOf(stack_map, encoding, number_of_dex_registers);
uint32_t register_mask = code_info.GetRegisterMaskOf(encoding, stack_map);
BitMemoryRegion stack_mask = code_info.GetStackMaskOf(encoding, stack_map);
for (int i = 0; i < number_of_references; ++i) {
int reg = registers[i];
- CHECK(reg < m->GetCodeItem()->registers_size_);
+ CHECK_LT(reg, accessor.RegistersSize());
DexRegisterLocation location = dex_register_map.GetDexRegisterLocation(
reg, number_of_dex_registers, code_info, encoding);
switch (location.GetKind()) {
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 55fa632..45b7618 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -4317,15 +4317,14 @@
void ClassLinker::ResolveMethodExceptionHandlerTypes(ArtMethod* method) {
// similar to DexVerifier::ScanTryCatchBlocks and dex2oat's ResolveExceptionsForMethod.
- const DexFile::CodeItem* code_item =
- method->GetDexFile()->GetCodeItem(method->GetCodeItemOffset());
- if (code_item == nullptr) {
+ CodeItemDataAccessor accessor(method);
+ if (!accessor.HasCodeItem()) {
return; // native or abstract method
}
- if (code_item->tries_size_ == 0) {
+ if (accessor.TriesSize() == 0) {
return; // nothing to process
}
- const uint8_t* handlers_ptr = DexFile::GetCatchHandlerData(*code_item, 0);
+ const uint8_t* handlers_ptr = accessor.GetCatchHandlerData(0);
uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
for (uint32_t idx = 0; idx < handlers_size; idx++) {
CatchHandlerIterator iterator(handlers_ptr);
diff --git a/runtime/code_item_accessors-inl.h b/runtime/code_item_accessors-inl.h
index 1ba3c55..f63ea69 100644
--- a/runtime/code_item_accessors-inl.h
+++ b/runtime/code_item_accessors-inl.h
@@ -30,27 +30,9 @@
inline CodeItemInstructionAccessor::CodeItemInstructionAccessor(ArtMethod* method)
: CodeItemInstructionAccessor(method->GetDexFile(), method->GetCodeItem()) {}
-inline CodeItemInstructionAccessor CodeItemInstructionAccessor::CreateNullable(
- ArtMethod* method) {
- DCHECK(method != nullptr);
- CodeItemInstructionAccessor ret;
- const DexFile::CodeItem* code_item = method->GetCodeItem();
- if (code_item != nullptr) {
- ret.Init(method->GetDexFile(), code_item);
- } else {
- DCHECK(!ret.HasCodeItem()) << "Should be null initialized";
- }
- return ret;
-}
-
inline CodeItemDataAccessor::CodeItemDataAccessor(ArtMethod* method)
: CodeItemDataAccessor(method->GetDexFile(), method->GetCodeItem()) {}
-inline CodeItemDataAccessor CodeItemDataAccessor::CreateNullable(ArtMethod* method) {
- DCHECK(method != nullptr);
- return CreateNullable(method->GetDexFile(), method->GetCodeItem());
-}
-
inline CodeItemDebugInfoAccessor::CodeItemDebugInfoAccessor(ArtMethod* method)
: CodeItemDebugInfoAccessor(method->GetDexFile(), method->GetCodeItem()) {}
@@ -59,7 +41,7 @@
if (code_item == nullptr) {
return;
}
- Init(dex_file, code_item, OatFile::GetDebugInfoOffset(*dex_file, code_item));
+ Init(dex_file, code_item, OatFile::GetDebugInfoOffset(*dex_file, code_item->debug_info_off_));
}
} // namespace art
diff --git a/runtime/code_item_accessors-no_art-inl.h b/runtime/code_item_accessors-no_art-inl.h
index 96321b5..ebdd78b 100644
--- a/runtime/code_item_accessors-no_art-inl.h
+++ b/runtime/code_item_accessors-no_art-inl.h
@@ -24,7 +24,6 @@
#include "standard_dex_file.h"
// The no ART version is used by binaries that don't include the whole runtime.
-
namespace art {
inline void CodeItemInstructionAccessor::Init(const CompactDexFile::CodeItem& code_item) {
@@ -39,13 +38,14 @@
inline void CodeItemInstructionAccessor::Init(const DexFile* dex_file,
const DexFile::CodeItem* code_item) {
- DCHECK(dex_file != nullptr);
- DCHECK(code_item != nullptr);
- if (dex_file->IsCompactDexFile()) {
- Init(down_cast<const CompactDexFile::CodeItem&>(*code_item));
- } else {
- DCHECK(dex_file->IsStandardDexFile());
- Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
+ if (code_item != nullptr) {
+ DCHECK(dex_file != nullptr);
+ if (dex_file->IsCompactDexFile()) {
+ Init(down_cast<const CompactDexFile::CodeItem&>(*code_item));
+ } else {
+ DCHECK(dex_file->IsStandardDexFile());
+ Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
+ }
}
}
@@ -63,6 +63,14 @@
return DexInstructionIterator(insns_, insns_size_in_code_units_);
}
+inline IterationRange<DexInstructionIterator> CodeItemInstructionAccessor::InstructionsFrom(
+ uint32_t start_dex_pc) const {
+ DCHECK_LT(start_dex_pc, InsnsSizeInCodeUnits());
+ return {
+ DexInstructionIterator(insns_, start_dex_pc),
+ DexInstructionIterator(insns_, insns_size_in_code_units_) };
+}
+
inline void CodeItemDataAccessor::Init(const CompactDexFile::CodeItem& code_item) {
CodeItemInstructionAccessor::Init(code_item);
registers_size_ = code_item.registers_size_;
@@ -81,13 +89,14 @@
inline void CodeItemDataAccessor::Init(const DexFile* dex_file,
const DexFile::CodeItem* code_item) {
- DCHECK(dex_file != nullptr);
- DCHECK(code_item != nullptr);
- if (dex_file->IsCompactDexFile()) {
- CodeItemDataAccessor::Init(down_cast<const CompactDexFile::CodeItem&>(*code_item));
- } else {
- DCHECK(dex_file->IsStandardDexFile());
- CodeItemDataAccessor::Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
+ if (code_item != nullptr) {
+ DCHECK(dex_file != nullptr);
+ if (dex_file->IsCompactDexFile()) {
+ CodeItemDataAccessor::Init(down_cast<const CompactDexFile::CodeItem&>(*code_item));
+ } else {
+ DCHECK(dex_file->IsStandardDexFile());
+ CodeItemDataAccessor::Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
+ }
}
}
@@ -96,18 +105,6 @@
Init(dex_file, code_item);
}
-inline CodeItemDataAccessor CodeItemDataAccessor::CreateNullable(
- const DexFile* dex_file,
- const DexFile::CodeItem* code_item) {
- CodeItemDataAccessor ret;
- if (code_item != nullptr) {
- ret.Init(dex_file, code_item);
- } else {
- DCHECK(!ret.HasCodeItem()) << "Should be null initialized";
- }
- return ret;
-}
-
inline IterationRange<const DexFile::TryItem*> CodeItemDataAccessor::TryItems() const {
const DexFile::TryItem* try_items = DexFile::GetTryItems(end(), 0u);
return {
@@ -163,7 +160,6 @@
context);
}
-
} // namespace art
#endif // ART_RUNTIME_CODE_ITEM_ACCESSORS_NO_ART_INL_H_
diff --git a/runtime/code_item_accessors.h b/runtime/code_item_accessors.h
index 9f40114..4cbe7a1 100644
--- a/runtime/code_item_accessors.h
+++ b/runtime/code_item_accessors.h
@@ -42,6 +42,8 @@
ALWAYS_INLINE DexInstructionIterator end() const;
+ IterationRange<DexInstructionIterator> InstructionsFrom(uint32_t start_dex_pc) const;
+
uint32_t InsnsSizeInCodeUnits() const {
return insns_size_in_code_units_;
}
@@ -52,6 +54,7 @@
// Return the instruction for a dex pc.
const Instruction& InstructionAt(uint32_t dex_pc) const {
+ DCHECK_LT(dex_pc, InsnsSizeInCodeUnits());
return *Instruction::At(insns_ + dex_pc);
}
@@ -60,10 +63,6 @@
return Insns() != nullptr;
}
- // CreateNullable allows ArtMethods that have a null code item.
- ALWAYS_INLINE static CodeItemInstructionAccessor CreateNullable(ArtMethod* method)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
protected:
CodeItemInstructionAccessor() = default;
@@ -109,14 +108,6 @@
const DexFile::TryItem* FindTryItem(uint32_t try_dex_pc) const;
- // CreateNullable allows ArtMethods that have a null code item.
- ALWAYS_INLINE static CodeItemDataAccessor CreateNullable(ArtMethod* method)
- REQUIRES_SHARED(Locks::mutator_lock_);
-
- ALWAYS_INLINE static CodeItemDataAccessor CreateNullable(
- const DexFile* dex_file,
- const DexFile::CodeItem* code_item);
-
protected:
CodeItemDataAccessor() = default;
diff --git a/runtime/common_dex_operations.h b/runtime/common_dex_operations.h
index 267735f..8988702 100644
--- a/runtime/common_dex_operations.h
+++ b/runtime/common_dex_operations.h
@@ -23,6 +23,7 @@
#include "base/macros.h"
#include "base/mutex.h"
#include "class_linker.h"
+#include "code_item_accessors.h"
#include "handle_scope-inl.h"
#include "instrumentation.h"
#include "interpreter/shadow_frame.h"
@@ -52,7 +53,7 @@
} // namespace interpreter
inline void PerformCall(Thread* self,
- const DexFile::CodeItem* code_item,
+ const CodeItemDataAccessor& accessor,
ArtMethod* caller_method,
const size_t first_dest_reg,
ShadowFrame* callee_frame,
@@ -61,13 +62,13 @@
REQUIRES_SHARED(Locks::mutator_lock_) {
if (LIKELY(Runtime::Current()->IsStarted())) {
if (use_interpreter_entrypoint) {
- interpreter::ArtInterpreterToInterpreterBridge(self, code_item, callee_frame, result);
+ interpreter::ArtInterpreterToInterpreterBridge(self, accessor, callee_frame, result);
} else {
interpreter::ArtInterpreterToCompiledCodeBridge(
self, caller_method, callee_frame, first_dest_reg, result);
}
} else {
- interpreter::UnstartedRuntime::Invoke(self, code_item, callee_frame, result, first_dest_reg);
+ interpreter::UnstartedRuntime::Invoke(self, accessor, callee_frame, result, first_dest_reg);
}
}
diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc
index 575d18e..707885c 100644
--- a/runtime/common_throws.cc
+++ b/runtime/common_throws.cc
@@ -551,43 +551,43 @@
void ThrowNullPointerExceptionFromDexPC(bool check_address, uintptr_t addr) {
uint32_t throw_dex_pc;
ArtMethod* method = Thread::Current()->GetCurrentMethod(&throw_dex_pc);
- const DexFile::CodeItem* code = method->GetCodeItem();
- CHECK_LT(throw_dex_pc, code->insns_size_in_code_units_);
- const Instruction* instr = Instruction::At(&code->insns_[throw_dex_pc]);
- if (check_address && !IsValidImplicitCheck(addr, *instr)) {
+ CodeItemInstructionAccessor accessor(method);
+ CHECK_LT(throw_dex_pc, accessor.InsnsSizeInCodeUnits());
+ const Instruction& instr = accessor.InstructionAt(throw_dex_pc);
+ if (check_address && !IsValidImplicitCheck(addr, instr)) {
const DexFile* dex_file = method->GetDeclaringClass()->GetDexCache()->GetDexFile();
LOG(FATAL) << "Invalid address for an implicit NullPointerException check: "
<< "0x" << std::hex << addr << std::dec
<< ", at "
- << instr->DumpString(dex_file)
+ << instr.DumpString(dex_file)
<< " in "
<< method->PrettyMethod();
}
- switch (instr->Opcode()) {
+ switch (instr.Opcode()) {
case Instruction::INVOKE_DIRECT:
- ThrowNullPointerExceptionForMethodAccess(instr->VRegB_35c(), kDirect);
+ ThrowNullPointerExceptionForMethodAccess(instr.VRegB_35c(), kDirect);
break;
case Instruction::INVOKE_DIRECT_RANGE:
- ThrowNullPointerExceptionForMethodAccess(instr->VRegB_3rc(), kDirect);
+ ThrowNullPointerExceptionForMethodAccess(instr.VRegB_3rc(), kDirect);
break;
case Instruction::INVOKE_VIRTUAL:
- ThrowNullPointerExceptionForMethodAccess(instr->VRegB_35c(), kVirtual);
+ ThrowNullPointerExceptionForMethodAccess(instr.VRegB_35c(), kVirtual);
break;
case Instruction::INVOKE_VIRTUAL_RANGE:
- ThrowNullPointerExceptionForMethodAccess(instr->VRegB_3rc(), kVirtual);
+ ThrowNullPointerExceptionForMethodAccess(instr.VRegB_3rc(), kVirtual);
break;
case Instruction::INVOKE_INTERFACE:
- ThrowNullPointerExceptionForMethodAccess(instr->VRegB_35c(), kInterface);
+ ThrowNullPointerExceptionForMethodAccess(instr.VRegB_35c(), kInterface);
break;
case Instruction::INVOKE_INTERFACE_RANGE:
- ThrowNullPointerExceptionForMethodAccess(instr->VRegB_3rc(), kInterface);
+ ThrowNullPointerExceptionForMethodAccess(instr.VRegB_3rc(), kInterface);
break;
case Instruction::INVOKE_POLYMORPHIC:
- ThrowNullPointerExceptionForMethodAccess(instr->VRegB_45cc(), kVirtual);
+ ThrowNullPointerExceptionForMethodAccess(instr.VRegB_45cc(), kVirtual);
break;
case Instruction::INVOKE_POLYMORPHIC_RANGE:
- ThrowNullPointerExceptionForMethodAccess(instr->VRegB_4rcc(), kVirtual);
+ ThrowNullPointerExceptionForMethodAccess(instr.VRegB_4rcc(), kVirtual);
break;
case Instruction::INVOKE_VIRTUAL_QUICK:
case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: {
@@ -612,7 +612,7 @@
case Instruction::IGET_CHAR:
case Instruction::IGET_SHORT: {
ArtField* field =
- Runtime::Current()->GetClassLinker()->ResolveField(instr->VRegC_22c(), method, false);
+ Runtime::Current()->GetClassLinker()->ResolveField(instr.VRegC_22c(), method, false);
ThrowNullPointerExceptionForFieldAccess(field, true /* read */);
break;
}
@@ -644,7 +644,7 @@
case Instruction::IPUT_CHAR:
case Instruction::IPUT_SHORT: {
ArtField* field =
- Runtime::Current()->GetClassLinker()->ResolveField(instr->VRegC_22c(), method, false);
+ Runtime::Current()->GetClassLinker()->ResolveField(instr.VRegC_22c(), method, false);
ThrowNullPointerExceptionForFieldAccess(field, false /* write */);
break;
}
@@ -707,7 +707,7 @@
const DexFile* dex_file =
method->GetDeclaringClass()->GetDexCache()->GetDexFile();
LOG(FATAL) << "NullPointerException at an unexpected instruction: "
- << instr->DumpString(dex_file)
+ << instr.DumpString(dex_file)
<< " in "
<< method->PrettyMethod();
break;
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index c85c233..2be00f5 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -278,11 +278,8 @@
}
private:
- static bool IsReturn(ArtMethod* method, uint32_t dex_pc)
- REQUIRES_SHARED(Locks::mutator_lock_) {
- const DexFile::CodeItem* code_item = method->GetCodeItem();
- const Instruction* instruction = Instruction::At(&code_item->insns_[dex_pc]);
- return instruction->IsReturn();
+ static bool IsReturn(ArtMethod* method, uint32_t dex_pc) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return method->DexInstructions().InstructionAt(dex_pc).IsReturn();
}
static bool IsListeningToDexPcMoved() REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -1535,15 +1532,15 @@
*/
static uint16_t MangleSlot(uint16_t slot, ArtMethod* m)
REQUIRES_SHARED(Locks::mutator_lock_) {
- const DexFile::CodeItem* code_item = m->GetCodeItem();
- if (code_item == nullptr) {
+ CodeItemDataAccessor accessor(m);
+ if (!accessor.HasCodeItem()) {
// We should not get here for a method without code (native, proxy or abstract). Log it and
// return the slot as is since all registers are arguments.
LOG(WARNING) << "Trying to mangle slot for method without code " << m->PrettyMethod();
return slot;
}
- uint16_t ins_size = code_item->ins_size_;
- uint16_t locals_size = code_item->registers_size_ - ins_size;
+ uint16_t ins_size = accessor.InsSize();
+ uint16_t locals_size = accessor.RegistersSize() - ins_size;
if (slot >= locals_size) {
return slot - locals_size;
} else {
@@ -1566,8 +1563,8 @@
*/
static uint16_t DemangleSlot(uint16_t slot, ArtMethod* m, JDWP::JdwpError* error)
REQUIRES_SHARED(Locks::mutator_lock_) {
- const DexFile::CodeItem* code_item = m->GetCodeItem();
- if (code_item == nullptr) {
+ CodeItemDataAccessor accessor(m);
+ if (!accessor.HasCodeItem()) {
// We should not get here for a method without code (native, proxy or abstract). Log it and
// return the slot as is since all registers are arguments.
LOG(WARNING) << "Trying to demangle slot for method without code "
@@ -1578,9 +1575,9 @@
return slot;
}
} else {
- if (slot < code_item->registers_size_) {
- uint16_t ins_size = code_item->ins_size_;
- uint16_t locals_size = code_item->registers_size_ - ins_size;
+ if (slot < accessor.RegistersSize()) {
+ uint16_t ins_size = accessor.InsSize();
+ uint16_t locals_size = accessor.RegistersSize() - ins_size;
*error = JDWP::ERR_NONE;
return (slot < ins_size) ? slot + locals_size : slot - ins_size;
}
@@ -1793,9 +1790,9 @@
if (m == nullptr) {
return JDWP::ERR_INVALID_METHODID;
}
- const DexFile::CodeItem* code_item = m->GetCodeItem();
- size_t byte_count = code_item->insns_size_in_code_units_ * 2;
- const uint8_t* begin = reinterpret_cast<const uint8_t*>(code_item->insns_);
+ CodeItemDataAccessor accessor(m);
+ size_t byte_count = accessor.InsnsSizeInCodeUnits() * 2;
+ const uint8_t* begin = reinterpret_cast<const uint8_t*>(accessor.Insns());
const uint8_t* end = begin + byte_count;
for (const uint8_t* p = begin; p != end; ++p) {
bytecodes->push_back(*p);
@@ -2978,9 +2975,8 @@
Handle<mirror::Throwable> pending_exception(hs.NewHandle(self->GetException()));
self->ClearException();
if (kIsDebugBuild && pending_exception != nullptr) {
- const DexFile::CodeItem* code_item = location.method->GetCodeItem();
- const Instruction* instr = Instruction::At(&code_item->insns_[location.dex_pc]);
- CHECK_EQ(Instruction::MOVE_EXCEPTION, instr->Opcode());
+ const Instruction& instr = location.method->DexInstructions().InstructionAt(location.dex_pc);
+ CHECK_EQ(Instruction::MOVE_EXCEPTION, instr.Opcode());
}
gJdwpState->PostLocationEvent(&location, this_object, event_flags, return_value);
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 76110f2..f3a88f7 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -320,6 +320,7 @@
debug_info_off_ = new_offset;
}
+ private:
uint16_t registers_size_; // the number of registers used by this code
// (locals + parameters)
uint16_t ins_size_; // the number of words of incoming arguments to the method
@@ -340,6 +341,14 @@
uint16_t insns_[1]; // actual array of bytecode.
private:
+ ART_FRIEND_TEST(CodeItemAccessorsTest, TestDexInstructionsAccessor);
+ friend class CatchHandlerIterator;
+ friend class CodeItemDataAccessor;
+ friend class CodeItemDebugInfoAccessor;
+ friend class CodeItemInstructionAccessor;
+ friend class DexFile; // TODO: Remove this one when it's cleaned up.
+ friend class DexFileVerifier;
+ friend class VdexFile; // TODO: Remove this one when it's cleaned up.
DISALLOW_COPY_AND_ASSIGN(CodeItem);
};
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index 6905504..87eec57 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -22,6 +22,7 @@
#include "base/stl_util.h"
#include "base/unix_file/fd_file.h"
+#include "code_item_accessors-inl.h"
#include "common_runtime_test.h"
#include "dex_file-inl.h"
#include "dex_file_loader.h"
@@ -730,15 +731,8 @@
kRawDexDebugInfoLocalNullType, tmp.GetFilename().c_str(), 0xf25f2b38U, true);
const DexFile::ClassDef& class_def = raw->GetClassDef(0);
const DexFile::CodeItem* code_item = raw->GetCodeItem(raw->FindCodeItemOffset(class_def, 1));
- uint32_t debug_info_offset = raw->GetDebugInfoOffset(code_item);
- ASSERT_TRUE(raw->DecodeDebugLocalInfo(code_item->registers_size_,
- code_item->ins_size_,
- code_item->insns_size_in_code_units_,
- debug_info_offset,
- true,
- 1,
- Callback,
- nullptr));
+ CodeItemDebugInfoAccessor accessor(raw.get(), code_item);
+ ASSERT_TRUE(accessor.DecodeDebugLocalInfo(true, 1, Callback, nullptr));
}
} // namespace art
diff --git a/runtime/dex_file_tracking_registrar.cc b/runtime/dex_file_tracking_registrar.cc
index 4de4376..c157ddc 100644
--- a/runtime/dex_file_tracking_registrar.cc
+++ b/runtime/dex_file_tracking_registrar.cc
@@ -30,6 +30,7 @@
#endif
#include "base/memory_tool.h"
+#include "code_item_accessors-inl.h"
#include "dex_file-inl.h"
namespace art {
@@ -184,9 +185,12 @@
if (code_item != nullptr) {
const void* code_item_begin = reinterpret_cast<const void*>(code_item);
size_t code_item_start = reinterpret_cast<size_t>(code_item);
- size_t code_item_start_end = reinterpret_cast<size_t>(&code_item->insns_[1]);
+ CodeItemInstructionAccessor accessor(dex_file_, code_item);
+ size_t code_item_start_end = reinterpret_cast<size_t>(accessor.Insns());
size_t code_item_start_size = code_item_start_end - code_item_start;
- range_values_.push_back(std::make_tuple(code_item_begin, code_item_start_size, should_poison));
+ range_values_.push_back(std::make_tuple(code_item_begin,
+ code_item_start_size,
+ should_poison));
}
cdit.Next();
}
@@ -204,9 +208,10 @@
while (cdit.HasNextMethod()) {
const DexFile::CodeItem* code_item = cdit.GetMethodCodeItem();
if (code_item != nullptr) {
- const void* insns_begin = reinterpret_cast<const void*>(&code_item->insns_);
+ CodeItemInstructionAccessor accessor(dex_file_, code_item);
+ const void* insns_begin = reinterpret_cast<const void*>(accessor.Insns());
// Member insns_size_in_code_units_ is in 2-byte units
- size_t insns_size = code_item->insns_size_in_code_units_ * 2;
+ size_t insns_size = accessor.InsnsSizeInCodeUnits() * 2;
range_values_.push_back(std::make_tuple(insns_begin, insns_size, should_poison));
}
cdit.Next();
diff --git a/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc b/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc
index d4bc1c7..d22f180 100644
--- a/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_fillarray_entrypoints.cc
@@ -28,7 +28,7 @@
ArtMethod* method, Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) {
ScopedQuickEntrypointChecks sqec(self);
- const uint16_t* const insns = method->GetCodeItem()->insns_;
+ const uint16_t* const insns = method->DexInstructions().Insns();
const Instruction::ArrayDataPayload* payload =
reinterpret_cast<const Instruction::ArrayDataPayload*>(insns + payload_offset);
bool success = FillArrayData(array, payload);
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index ca5b799..a4d14ec 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -784,8 +784,8 @@
DCHECK(!method->IsNative()) << method->PrettyMethod();
uint32_t shorty_len = 0;
ArtMethod* non_proxy_method = method->GetInterfaceMethodIfProxy(kRuntimePointerSize);
- const DexFile::CodeItem* code_item = non_proxy_method->GetCodeItem();
- DCHECK(code_item != nullptr) << method->PrettyMethod();
+ DCHECK(non_proxy_method->GetCodeItem() != nullptr) << method->PrettyMethod();
+ CodeItemDataAccessor accessor(non_proxy_method);
const char* shorty = non_proxy_method->GetShorty(&shorty_len);
JValue result;
@@ -795,12 +795,12 @@
} else {
const char* old_cause = self->StartAssertNoThreadSuspension(
"Building interpreter shadow frame");
- uint16_t num_regs = code_item->registers_size_;
+ uint16_t num_regs = accessor.RegistersSize();
// No last shadow coming from quick.
ShadowFrameAllocaUniquePtr shadow_frame_unique_ptr =
CREATE_SHADOW_FRAME(num_regs, /* link */ nullptr, method, /* dex pc */ 0);
ShadowFrame* shadow_frame = shadow_frame_unique_ptr.get();
- size_t first_arg_reg = code_item->registers_size_ - code_item->ins_size_;
+ size_t first_arg_reg = accessor.RegistersSize() - accessor.InsSize();
BuildQuickShadowFrameVisitor shadow_frame_builder(sp, method->IsStatic(), shorty, shorty_len,
shadow_frame, first_arg_reg);
shadow_frame_builder.VisitArguments();
@@ -823,7 +823,7 @@
}
}
- result = interpreter::EnterInterpreterFromEntryPoint(self, code_item, shadow_frame);
+ result = interpreter::EnterInterpreterFromEntryPoint(self, accessor, shadow_frame);
}
// Pop transition.
@@ -1121,10 +1121,9 @@
// code.
if (!found_stack_map || kIsDebugBuild) {
uint32_t dex_pc = QuickArgumentVisitor::GetCallingDexPc(sp);
- const DexFile::CodeItem* code;
- code = caller->GetCodeItem();
- CHECK_LT(dex_pc, code->insns_size_in_code_units_);
- const Instruction& instr = code->InstructionAt(dex_pc);
+ CodeItemInstructionAccessor accessor(caller);
+ CHECK_LT(dex_pc, accessor.InsnsSizeInCodeUnits());
+ const Instruction& instr = accessor.InstructionAt(dex_pc);
Instruction::Code instr_code = instr.Opcode();
bool is_range;
switch (instr_code) {
@@ -2450,9 +2449,7 @@
// Fetch the dex_method_idx of the target interface method from the caller.
uint32_t dex_method_idx;
uint32_t dex_pc = QuickArgumentVisitor::GetCallingDexPc(sp);
- const DexFile::CodeItem* code_item = caller_method->GetCodeItem();
- DCHECK_LT(dex_pc, code_item->insns_size_in_code_units_);
- const Instruction& instr = code_item->InstructionAt(dex_pc);
+ const Instruction& instr = caller_method->DexInstructions().InstructionAt(dex_pc);
Instruction::Code instr_code = instr.Opcode();
DCHECK(instr_code == Instruction::INVOKE_INTERFACE ||
instr_code == Instruction::INVOKE_INTERFACE_RANGE)
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 49f2021..a4ee21d 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -1246,18 +1246,17 @@
shorty = m->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty()[0];
return false;
}
- const DexFile::CodeItem* code_item = m->GetCodeItem();
- const Instruction* instr = Instruction::At(&code_item->insns_[GetDexPc()]);
- if (instr->IsInvoke()) {
+ const Instruction& instr = m->DexInstructions().InstructionAt(GetDexPc());
+ if (instr.IsInvoke()) {
const DexFile* dex_file = m->GetDexFile();
- if (interpreter::IsStringInit(dex_file, instr->VRegB())) {
+ if (interpreter::IsStringInit(dex_file, instr.VRegB())) {
// Invoking string init constructor is turned into invoking
// StringFactory.newStringFromChars() which returns a string.
shorty = 'L';
return false;
}
// A regular invoke, use callee's shorty.
- uint32_t method_idx = instr->VRegB();
+ uint32_t method_idx = instr.VRegB();
shorty = dex_file->GetMethodShorty(method_idx)[0];
}
// Stop stack walking since we've seen a Java frame.
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 01b7d4e..9b81819 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -240,7 +240,7 @@
static inline JValue Execute(
Thread* self,
- const DexFile::CodeItem* code_item,
+ const CodeItemDataAccessor& accessor,
ShadowFrame& shadow_frame,
JValue result_register,
bool stay_in_interpreter = false) REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -254,11 +254,13 @@
ArtMethod *method = shadow_frame.GetMethod();
if (UNLIKELY(instrumentation->HasMethodEntryListeners())) {
- instrumentation->MethodEnterEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
- method, 0);
+ instrumentation->MethodEnterEvent(self,
+ shadow_frame.GetThisObject(accessor.InsSize()),
+ method,
+ 0);
if (UNLIKELY(self->IsExceptionPending())) {
instrumentation->MethodUnwindEvent(self,
- shadow_frame.GetThisObject(code_item->ins_size_),
+ shadow_frame.GetThisObject(accessor.InsSize()),
method,
0);
return JValue();
@@ -277,7 +279,7 @@
// Calculate the offset of the first input reg. The input registers are in the high regs.
// It's ok to access the code item here since JIT code will have been touched by the
// interpreter and compiler already.
- uint16_t arg_offset = code_item->registers_size_ - code_item->ins_size_;
+ uint16_t arg_offset = accessor.RegistersSize() - accessor.InsSize();
ArtInterpreterToCompiledCodeBridge(self, nullptr, &shadow_frame, arg_offset, &result);
// Push the shadow frame back as the caller will expect it.
self->PushShadowFrame(&shadow_frame);
@@ -302,27 +304,27 @@
if (kInterpreterImplKind == kMterpImplKind) {
if (transaction_active) {
// No Mterp variant - just use the switch interpreter.
- return ExecuteSwitchImpl<false, true>(self, code_item, shadow_frame, result_register,
+ return ExecuteSwitchImpl<false, true>(self, accessor, shadow_frame, result_register,
false);
} else if (UNLIKELY(!Runtime::Current()->IsStarted())) {
- return ExecuteSwitchImpl<false, false>(self, code_item, shadow_frame, result_register,
+ return ExecuteSwitchImpl<false, false>(self, accessor, shadow_frame, result_register,
false);
} else {
while (true) {
// Mterp does not support all instrumentation/debugging.
if (MterpShouldSwitchInterpreters() != 0) {
- return ExecuteSwitchImpl<false, false>(self, code_item, shadow_frame, result_register,
+ return ExecuteSwitchImpl<false, false>(self, accessor, shadow_frame, result_register,
false);
}
bool returned = ExecuteMterpImpl(self,
- code_item->insns_,
+ accessor.Insns(),
&shadow_frame,
&result_register);
if (returned) {
return result_register;
} else {
// Mterp didn't like that instruction. Single-step it with the reference interpreter.
- result_register = ExecuteSwitchImpl<false, false>(self, code_item, shadow_frame,
+ result_register = ExecuteSwitchImpl<false, false>(self, accessor, shadow_frame,
result_register, true);
if (shadow_frame.GetDexPC() == dex::kDexNoIndex) {
// Single-stepped a return or an exception not handled locally. Return to caller.
@@ -334,10 +336,10 @@
} else {
DCHECK_EQ(kInterpreterImplKind, kSwitchImplKind);
if (transaction_active) {
- return ExecuteSwitchImpl<false, true>(self, code_item, shadow_frame, result_register,
+ return ExecuteSwitchImpl<false, true>(self, accessor, shadow_frame, result_register,
false);
} else {
- return ExecuteSwitchImpl<false, false>(self, code_item, shadow_frame, result_register,
+ return ExecuteSwitchImpl<false, false>(self, accessor, shadow_frame, result_register,
false);
}
}
@@ -346,19 +348,19 @@
if (kInterpreterImplKind == kMterpImplKind) {
// No access check variants for Mterp. Just use the switch version.
if (transaction_active) {
- return ExecuteSwitchImpl<true, true>(self, code_item, shadow_frame, result_register,
+ return ExecuteSwitchImpl<true, true>(self, accessor, shadow_frame, result_register,
false);
} else {
- return ExecuteSwitchImpl<true, false>(self, code_item, shadow_frame, result_register,
+ return ExecuteSwitchImpl<true, false>(self, accessor, shadow_frame, result_register,
false);
}
} else {
DCHECK_EQ(kInterpreterImplKind, kSwitchImplKind);
if (transaction_active) {
- return ExecuteSwitchImpl<true, true>(self, code_item, shadow_frame, result_register,
+ return ExecuteSwitchImpl<true, true>(self, accessor, shadow_frame, result_register,
false);
} else {
- return ExecuteSwitchImpl<true, false>(self, code_item, shadow_frame, result_register,
+ return ExecuteSwitchImpl<true, false>(self, accessor, shadow_frame, result_register,
false);
}
}
@@ -387,12 +389,12 @@
}
const char* old_cause = self->StartAssertNoThreadSuspension("EnterInterpreterFromInvoke");
- const DexFile::CodeItem* code_item = method->GetCodeItem();
+ CodeItemDataAccessor accessor(method);
uint16_t num_regs;
uint16_t num_ins;
- if (code_item != nullptr) {
- num_regs = code_item->registers_size_;
- num_ins = code_item->ins_size_;
+ if (accessor.HasCodeItem()) {
+ num_regs = accessor.RegistersSize();
+ num_ins = accessor.InsSize();
} else if (!method->IsInvokable()) {
self->EndAssertNoThreadSuspension(old_cause);
method->ThrowInvocationTimeError();
@@ -454,7 +456,7 @@
}
}
if (LIKELY(!method->IsNative())) {
- JValue r = Execute(self, code_item, *shadow_frame, JValue(), stay_in_interpreter);
+ JValue r = Execute(self, accessor, *shadow_frame, JValue(), stay_in_interpreter);
if (result != nullptr) {
*result = r;
}
@@ -497,7 +499,7 @@
DCHECK(!shadow_frame->GetMethod()->MustCountLocks());
self->SetTopOfShadowStack(shadow_frame);
- const DexFile::CodeItem* code_item = shadow_frame->GetMethod()->GetCodeItem();
+ CodeItemDataAccessor accessor(shadow_frame->GetMethod());
const uint32_t dex_pc = shadow_frame->GetDexPC();
uint32_t new_dex_pc = dex_pc;
if (UNLIKELY(self->IsExceptionPending())) {
@@ -510,7 +512,7 @@
self, *shadow_frame, instrumentation) ? shadow_frame->GetDexPC() : dex::kDexNoIndex;
} else if (!from_code) {
// Deoptimization is not called from code directly.
- const Instruction* instr = Instruction::At(&code_item->insns_[dex_pc]);
+ const Instruction* instr = &accessor.InstructionAt(dex_pc);
if (deopt_method_type == DeoptimizationMethodType::kKeepDexPc) {
DCHECK(first);
// Need to re-execute the dex instruction.
@@ -566,7 +568,7 @@
}
if (new_dex_pc != dex::kDexNoIndex) {
shadow_frame->SetDexPC(new_dex_pc);
- value = Execute(self, code_item, *shadow_frame, value);
+ value = Execute(self, accessor, *shadow_frame, value);
}
ShadowFrame* old_frame = shadow_frame;
shadow_frame = shadow_frame->GetLink();
@@ -580,7 +582,7 @@
ret_val->SetJ(value.GetJ());
}
-JValue EnterInterpreterFromEntryPoint(Thread* self, const DexFile::CodeItem* code_item,
+JValue EnterInterpreterFromEntryPoint(Thread* self, const CodeItemDataAccessor& accessor,
ShadowFrame* shadow_frame) {
DCHECK_EQ(self, Thread::Current());
bool implicit_check = !Runtime::Current()->ExplicitStackOverflowChecks();
@@ -593,11 +595,11 @@
if (jit != nullptr) {
jit->NotifyCompiledCodeToInterpreterTransition(self, shadow_frame->GetMethod());
}
- return Execute(self, code_item, *shadow_frame, JValue());
+ return Execute(self, accessor, *shadow_frame, JValue());
}
void ArtInterpreterToInterpreterBridge(Thread* self,
- const DexFile::CodeItem* code_item,
+ const CodeItemDataAccessor& accessor,
ShadowFrame* shadow_frame,
JValue* result) {
bool implicit_check = !Runtime::Current()->ExplicitStackOverflowChecks();
@@ -626,7 +628,7 @@
}
if (LIKELY(!shadow_frame->GetMethod()->IsNative())) {
- result->SetJ(Execute(self, code_item, *shadow_frame, JValue()).GetJ());
+ result->SetJ(Execute(self, accessor, *shadow_frame, JValue()).GetJ());
} else {
// We don't expect to be asked to interpret native code (which is entered via a JNI compiler
// generated stub) except during testing and image writing.
diff --git a/runtime/interpreter/interpreter.h b/runtime/interpreter/interpreter.h
index df8568e..f9d7774 100644
--- a/runtime/interpreter/interpreter.h
+++ b/runtime/interpreter/interpreter.h
@@ -27,6 +27,7 @@
} // namespace mirror
class ArtMethod;
+class CodeItemDataAccessor;
union JValue;
class ShadowFrame;
class Thread;
@@ -52,12 +53,15 @@
DeoptimizationMethodType method_type)
REQUIRES_SHARED(Locks::mutator_lock_);
-extern JValue EnterInterpreterFromEntryPoint(Thread* self, const DexFile::CodeItem* code_item,
+extern JValue EnterInterpreterFromEntryPoint(Thread* self,
+ const CodeItemDataAccessor& accessor,
ShadowFrame* shadow_frame)
REQUIRES_SHARED(Locks::mutator_lock_);
-void ArtInterpreterToInterpreterBridge(Thread* self, const DexFile::CodeItem* code_item,
- ShadowFrame* shadow_frame, JValue* result)
+void ArtInterpreterToInterpreterBridge(Thread* self,
+ const CodeItemDataAccessor& accessor,
+ ShadowFrame* shadow_frame,
+ JValue* result)
REQUIRES_SHARED(Locks::mutator_lock_);
// One-time sanity check.
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 122d1a8..deed16b 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -1320,7 +1320,7 @@
}
// Compute method information.
- const DexFile::CodeItem* code_item = called_method->GetCodeItem();
+ CodeItemDataAccessor accessor(called_method);
// Number of registers for the callee's call frame.
uint16_t num_regs;
// Test whether to use the interpreter or compiler entrypoint, and save that result to pass to
@@ -1334,7 +1334,7 @@
ClassLinker::ShouldUseInterpreterEntrypoint(
called_method,
called_method->GetEntryPointFromQuickCompiledCode());
- if (LIKELY(code_item != nullptr)) {
+ if (LIKELY(accessor.HasCodeItem())) {
// When transitioning to compiled code, space only needs to be reserved for the input registers.
// The rest of the frame gets discarded. This also prevents accessing the called method's code
// item, saving memory by keeping code items of compiled code untouched.
@@ -1342,8 +1342,8 @@
DCHECK(!Runtime::Current()->IsAotCompiler()) << "Compiler should use interpreter entrypoint";
num_regs = number_of_inputs;
} else {
- num_regs = code_item->registers_size_;
- DCHECK_EQ(string_init ? number_of_inputs - 1 : number_of_inputs, code_item->ins_size_);
+ num_regs = accessor.RegistersSize();
+ DCHECK_EQ(string_init ? number_of_inputs - 1 : number_of_inputs, accessor.InsSize());
}
} else {
DCHECK(called_method->IsNative() || called_method->IsProxyMethod());
@@ -1367,7 +1367,7 @@
DCHECK_GT(num_regs, 0u); // As the method is an instance method, there should be at least 1.
// The new StringFactory call is static and has one fewer argument.
- if (code_item == nullptr) {
+ if (!accessor.HasCodeItem()) {
DCHECK(called_method->IsNative() || called_method->IsProxyMethod());
num_regs--;
} // else ... don't need to change num_regs since it comes up from the string_init's code item
@@ -1499,7 +1499,7 @@
}
PerformCall(self,
- code_item,
+ accessor,
shadow_frame.GetMethod(),
first_dest_reg,
new_shadow_frame,
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index 094f086..81c1e1d 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -67,7 +67,7 @@
{ \
if (UNLIKELY(instrumentation->HasDexPcListeners()) && \
UNLIKELY(!DoDexPcMoveEvent(self, \
- code_item, \
+ accessor, \
shadow_frame, \
dex_pc, \
instrumentation, \
@@ -125,7 +125,7 @@
// jvmti-agents while handling breakpoint or single step events. We had to move this into its own
// function because it was making ExecuteSwitchImpl have too large a stack.
NO_INLINE static bool DoDexPcMoveEvent(Thread* self,
- const DexFile::CodeItem* code_item,
+ const CodeItemDataAccessor& accessor,
const ShadowFrame& shadow_frame,
uint32_t dex_pc,
const instrumentation::Instrumentation* instrumentation,
@@ -139,7 +139,7 @@
hs.NewHandleWrapper(LIKELY(save_ref == nullptr) ? &null_obj : save_ref->GetGCRoot()));
self->ClearException();
instrumentation->DexPcMovedEvent(self,
- shadow_frame.GetThisObject(code_item->ins_size_),
+ shadow_frame.GetThisObject(accessor.InsSize()),
shadow_frame.GetMethod(),
dex_pc);
if (UNLIKELY(self->IsExceptionPending())) {
@@ -188,7 +188,7 @@
}
template<bool do_access_check, bool transaction_active>
-JValue ExecuteSwitchImpl(Thread* self, const DexFile::CodeItem* code_item,
+JValue ExecuteSwitchImpl(Thread* self, const CodeItemDataAccessor& accessor,
ShadowFrame& shadow_frame, JValue result_register,
bool interpret_one_instruction) {
constexpr bool do_assignability_check = do_access_check;
@@ -200,10 +200,10 @@
uint32_t dex_pc = shadow_frame.GetDexPC();
const auto* const instrumentation = Runtime::Current()->GetInstrumentation();
- const uint16_t* const insns = code_item->insns_;
+ ArtMethod* method = shadow_frame.GetMethod();
+ const uint16_t* const insns = accessor.Insns();
const Instruction* inst = Instruction::At(insns + dex_pc);
uint16_t inst_data;
- ArtMethod* method = shadow_frame.GetMethod();
jit::Jit* jit = Runtime::Current()->GetJit();
do {
@@ -303,7 +303,7 @@
!SendMethodExitEvents(self,
instrumentation,
shadow_frame,
- shadow_frame.GetThisObject(code_item->ins_size_),
+ shadow_frame.GetThisObject(accessor.InsSize()),
shadow_frame.GetMethod(),
inst->GetDexPc(insns),
result))) {
@@ -325,7 +325,7 @@
!SendMethodExitEvents(self,
instrumentation,
shadow_frame,
- shadow_frame.GetThisObject(code_item->ins_size_),
+ shadow_frame.GetThisObject(accessor.InsSize()),
shadow_frame.GetMethod(),
inst->GetDexPc(insns),
result))) {
@@ -348,7 +348,7 @@
!SendMethodExitEvents(self,
instrumentation,
shadow_frame,
- shadow_frame.GetThisObject(code_item->ins_size_),
+ shadow_frame.GetThisObject(accessor.InsSize()),
shadow_frame.GetMethod(),
inst->GetDexPc(insns),
result))) {
@@ -370,7 +370,7 @@
!SendMethodExitEvents(self,
instrumentation,
shadow_frame,
- shadow_frame.GetThisObject(code_item->ins_size_),
+ shadow_frame.GetThisObject(accessor.InsSize()),
shadow_frame.GetMethod(),
inst->GetDexPc(insns),
result))) {
@@ -412,7 +412,7 @@
!SendMethodExitEvents(self,
instrumentation,
shadow_frame,
- shadow_frame.GetThisObject(code_item->ins_size_),
+ shadow_frame.GetThisObject(accessor.InsSize()),
shadow_frame.GetMethod(),
inst->GetDexPc(insns),
result))) {
@@ -2484,19 +2484,19 @@
// Explicit definitions of ExecuteSwitchImpl.
template HOT_ATTR
-JValue ExecuteSwitchImpl<true, false>(Thread* self, const DexFile::CodeItem* code_item,
+JValue ExecuteSwitchImpl<true, false>(Thread* self, const CodeItemDataAccessor& accessor,
ShadowFrame& shadow_frame, JValue result_register,
bool interpret_one_instruction);
template HOT_ATTR
-JValue ExecuteSwitchImpl<false, false>(Thread* self, const DexFile::CodeItem* code_item,
+JValue ExecuteSwitchImpl<false, false>(Thread* self, const CodeItemDataAccessor& accessor,
ShadowFrame& shadow_frame, JValue result_register,
bool interpret_one_instruction);
template
-JValue ExecuteSwitchImpl<true, true>(Thread* self, const DexFile::CodeItem* code_item,
+JValue ExecuteSwitchImpl<true, true>(Thread* self, const CodeItemDataAccessor& accessor,
ShadowFrame& shadow_frame, JValue result_register,
bool interpret_one_instruction);
template
-JValue ExecuteSwitchImpl<false, true>(Thread* self, const DexFile::CodeItem* code_item,
+JValue ExecuteSwitchImpl<false, true>(Thread* self, const CodeItemDataAccessor& accessor,
ShadowFrame& shadow_frame, JValue result_register,
bool interpret_one_instruction);
diff --git a/runtime/interpreter/interpreter_switch_impl.h b/runtime/interpreter/interpreter_switch_impl.h
index 267df2e..aa0f854 100644
--- a/runtime/interpreter/interpreter_switch_impl.h
+++ b/runtime/interpreter/interpreter_switch_impl.h
@@ -25,6 +25,7 @@
namespace art {
+class CodeItemDataAccessor;
class ShadowFrame;
class Thread;
@@ -32,7 +33,7 @@
template<bool do_access_check, bool transaction_active>
JValue ExecuteSwitchImpl(Thread* self,
- const DexFile::CodeItem* code_item,
+ const CodeItemDataAccessor& accessor,
ShadowFrame& shadow_frame,
JValue result_register,
bool interpret_one_instruction) REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/interpreter/shadow_frame.cc b/runtime/interpreter/shadow_frame.cc
index ab154cf..fe7e3e0 100644
--- a/runtime/interpreter/shadow_frame.cc
+++ b/runtime/interpreter/shadow_frame.cc
@@ -27,9 +27,9 @@
} else if (m->IsNative()) {
return GetVRegReference(0);
} else {
- const DexFile::CodeItem* code_item = m->GetCodeItem();
- CHECK(code_item != nullptr) << ArtMethod::PrettyMethod(m);
- uint16_t reg = code_item->registers_size_ - code_item->ins_size_;
+ CHECK(m->GetCodeItem() != nullptr) << ArtMethod::PrettyMethod(m);
+ CodeItemDataAccessor accessor(m);
+ uint16_t reg = accessor.RegistersSize() - accessor.InsSize();
return GetVRegReference(reg);
}
}
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index dece830..d1436fa 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -1910,7 +1910,7 @@
tables_initialized_ = true;
}
-void UnstartedRuntime::Invoke(Thread* self, const DexFile::CodeItem* code_item,
+void UnstartedRuntime::Invoke(Thread* self, const CodeItemDataAccessor& accessor,
ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) {
// In a runtime that's not started we intercept certain methods to avoid complicated dependency
// problems in core libraries.
@@ -1930,7 +1930,7 @@
self->PopShadowFrame();
} else {
// Not special, continue with regular interpreter execution.
- ArtInterpreterToInterpreterBridge(self, code_item, shadow_frame, result);
+ ArtInterpreterToInterpreterBridge(self, accessor, shadow_frame, result);
}
}
diff --git a/runtime/interpreter/unstarted_runtime.h b/runtime/interpreter/unstarted_runtime.h
index bc9ead8..2e86dea 100644
--- a/runtime/interpreter/unstarted_runtime.h
+++ b/runtime/interpreter/unstarted_runtime.h
@@ -25,6 +25,7 @@
namespace art {
class ArtMethod;
+class CodeItemDataAccessor;
class Thread;
class ShadowFrame;
@@ -48,7 +49,7 @@
static void Initialize();
static void Invoke(Thread* self,
- const DexFile::CodeItem* code_item,
+ const CodeItemDataAccessor& accessor,
ShadowFrame* shadow_frame,
JValue* result,
size_t arg_offset)
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index 278bc57..12bf79d 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -467,7 +467,8 @@
// Fetch some data before looking up for an OSR method. We don't want thread
// suspension once we hold an OSR method, as the JIT code cache could delete the OSR
// method while we are being suspended.
- const size_t number_of_vregs = method->GetCodeItem()->registers_size_;
+ CodeItemDataAccessor accessor(method);
+ const size_t number_of_vregs = accessor.RegistersSize();
const char* shorty = method->GetShorty();
std::string method_name(VLOG_IS_ON(jit) ? method->PrettyMethod() : "");
void** memory = nullptr;
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc
index 8eb31c1..88f30a8 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -408,7 +408,7 @@
const InstructionOperands* const operands,
JValue* result) REQUIRES_SHARED(Locks::mutator_lock_) {
// Compute method information.
- const DexFile::CodeItem* code_item = called_method->GetCodeItem();
+ CodeItemDataAccessor accessor(called_method);
// Number of registers for the callee's call frame. Note that for non-exact
// invokes, we always derive this information from the callee method. We
@@ -419,10 +419,10 @@
uint16_t num_regs;
size_t num_input_regs;
size_t first_dest_reg;
- if (LIKELY(code_item != nullptr)) {
- num_regs = code_item->registers_size_;
- first_dest_reg = num_regs - code_item->ins_size_;
- num_input_regs = code_item->ins_size_;
+ if (LIKELY(accessor.HasCodeItem())) {
+ num_regs = accessor.RegistersSize();
+ first_dest_reg = num_regs - accessor.InsSize();
+ num_input_regs = accessor.InsSize();
// Parameter registers go at the end of the shadow frame.
DCHECK_NE(first_dest_reg, (size_t)-1);
} else {
@@ -496,7 +496,7 @@
bool use_interpreter_entrypoint = ClassLinker::ShouldUseInterpreterEntrypoint(
called_method, called_method->GetEntryPointFromQuickCompiledCode());
PerformCall(self,
- code_item,
+ accessor,
shadow_frame.GetMethod(),
first_dest_reg,
new_shadow_frame,
@@ -550,10 +550,9 @@
// - One for the only method argument (an EmulatedStackFrame).
static constexpr size_t kNumRegsForTransform = 2;
- const DexFile::CodeItem* code_item = called_method->GetCodeItem();
- DCHECK(code_item != nullptr);
- DCHECK_EQ(kNumRegsForTransform, code_item->registers_size_);
- DCHECK_EQ(kNumRegsForTransform, code_item->ins_size_);
+ CodeItemDataAccessor accessor(called_method);
+ DCHECK_EQ(kNumRegsForTransform, accessor.RegistersSize());
+ DCHECK_EQ(kNumRegsForTransform, accessor.InsSize());
ShadowFrameAllocaUniquePtr shadow_frame_unique_ptr =
CREATE_SHADOW_FRAME(kNumRegsForTransform, &shadow_frame, called_method, /* dex pc */ 0);
@@ -589,7 +588,7 @@
bool use_interpreter_entrypoint = ClassLinker::ShouldUseInterpreterEntrypoint(
called_method, called_method->GetEntryPointFromQuickCompiledCode());
PerformCall(self,
- code_item,
+ accessor,
shadow_frame.GetMethod(),
0 /* first destination register */,
new_shadow_frame,
@@ -1035,14 +1034,14 @@
}
// Compute method information.
- const DexFile::CodeItem* code_item = called_method->GetCodeItem();
+ CodeItemDataAccessor accessor(called_method);
uint16_t num_regs;
size_t num_input_regs;
size_t first_dest_reg;
- if (LIKELY(code_item != nullptr)) {
- num_regs = code_item->registers_size_;
- first_dest_reg = num_regs - code_item->ins_size_;
- num_input_regs = code_item->ins_size_;
+ if (LIKELY(accessor.HasCodeItem())) {
+ num_regs = accessor.RegistersSize();
+ first_dest_reg = num_regs - accessor.InsSize();
+ num_input_regs = accessor.InsSize();
// Parameter registers go at the end of the shadow frame.
DCHECK_NE(first_dest_reg, (size_t)-1);
} else {
@@ -1066,7 +1065,7 @@
bool use_interpreter_entrypoint = ClassLinker::ShouldUseInterpreterEntrypoint(
called_method, called_method->GetEntryPointFromQuickCompiledCode());
PerformCall(self,
- code_item,
+ accessor,
shadow_frame.GetMethod(),
first_dest_reg,
new_shadow_frame,
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index cfef9c7..542692f 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -1377,9 +1377,9 @@
}
// Is there any reason to believe there's any synchronization in this method?
- const DexFile::CodeItem* code_item = m->GetCodeItem();
- CHECK(code_item != nullptr) << m->PrettyMethod();
- if (code_item->tries_size_ == 0) {
+ CHECK(m->GetCodeItem() != nullptr) << m->PrettyMethod();
+ CodeItemDataAccessor accessor(m);
+ if (accessor.TriesSize() == 0) {
return; // No "tries" implies no synchronization, so no held locks to report.
}
@@ -1399,11 +1399,10 @@
for (verifier::MethodVerifier::DexLockInfo& dex_lock_info : monitor_enter_dex_pcs) {
// As a debug check, check that dex PC corresponds to a monitor-enter.
if (kIsDebugBuild) {
- const Instruction* monitor_enter_instruction =
- Instruction::At(&code_item->insns_[dex_lock_info.dex_pc]);
- CHECK_EQ(monitor_enter_instruction->Opcode(), Instruction::MONITOR_ENTER)
+ const Instruction& monitor_enter_instruction = accessor.InstructionAt(dex_lock_info.dex_pc);
+ CHECK_EQ(monitor_enter_instruction.Opcode(), Instruction::MONITOR_ENTER)
<< "expected monitor-enter @" << dex_lock_info.dex_pc << "; was "
- << reinterpret_cast<const void*>(monitor_enter_instruction);
+ << reinterpret_cast<const void*>(&monitor_enter_instruction);
}
// Iterate through the set of dex registers, as the compiler may not have held all of them
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 32f8df7..f437db2 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -1500,14 +1500,10 @@
}
}
-uint32_t OatFile::GetDebugInfoOffset(const DexFile& dex_file,
- const DexFile::CodeItem* code_item) {
- if (code_item == nullptr) {
- return 0;
- }
- const uint32_t debug_info_off = code_item->debug_info_off_;
+uint32_t OatFile::GetDebugInfoOffset(const DexFile& dex_file, uint32_t debug_info_off) {
// Note that although the specification says that 0 should be used if there
// is no debug information, some applications incorrectly use 0xFFFFFFFF.
+ // The following check also handles debug_info_off == 0.
if (debug_info_off < dex_file.Size() || debug_info_off == 0xFFFFFFFF) {
return debug_info_off;
}
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 36a4d7b..1fb17a4 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -114,9 +114,9 @@
const char* abs_dex_location,
std::string* error_msg);
- // Return the debug info offset of the code item `item` located in `dex_file`.
- static uint32_t GetDebugInfoOffset(const DexFile& dex_file,
- const DexFile::CodeItem* item);
+ // Return the actual debug info offset for an offset that might be actually pointing to
+ // dequickening info. The returned debug info offset is the one originally in the the dex file.
+ static uint32_t GetDebugInfoOffset(const DexFile& dex_file, uint32_t debug_info_off);
virtual ~OatFile();
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc
index a7771ab..06b94c3 100644
--- a/runtime/quick_exception_handler.cc
+++ b/runtime/quick_exception_handler.cc
@@ -222,7 +222,8 @@
self_->DumpStack(LOG_STREAM(INFO) << "Setting catch phis: ");
}
- const size_t number_of_vregs = handler_method_->GetCodeItem()->registers_size_;
+ CodeItemDataAccessor accessor(handler_method_);
+ const size_t number_of_vregs = accessor.RegistersSize();
CodeInfo code_info = handler_method_header_->GetOptimizedCodeInfo();
CodeInfoEncoding encoding = code_info.ExtractEncoding();
@@ -359,7 +360,8 @@
const size_t frame_id = GetFrameId();
ShadowFrame* new_frame = GetThread()->FindDebuggerShadowFrame(frame_id);
const bool* updated_vregs;
- const size_t num_regs = method->GetCodeItem()->registers_size_;
+ CodeItemDataAccessor accessor(method);
+ const size_t num_regs = accessor.RegistersSize();
if (new_frame == nullptr) {
new_frame = ShadowFrame::CreateDeoptimizedFrame(num_regs, nullptr, method, GetDexPc());
updated_vregs = nullptr;
@@ -406,7 +408,8 @@
uintptr_t native_pc_offset = method_header->NativeQuickPcOffset(GetCurrentQuickFramePc());
CodeInfoEncoding encoding = code_info.ExtractEncoding();
StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset, encoding);
- const size_t number_of_vregs = m->GetCodeItem()->registers_size_;
+ CodeItemDataAccessor accessor(m);
+ const size_t number_of_vregs = accessor.RegistersSize();
uint32_t register_mask = code_info.GetRegisterMaskOf(encoding, stack_map);
BitMemoryRegion stack_mask = code_info.GetStackMaskOf(encoding, stack_map);
DexRegisterMap vreg_map = IsInInlinedFrame()
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 5ad1f7c..bbea48b 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -154,13 +154,13 @@
return cur_shadow_frame_->GetVRegReference(0);
}
} else {
- const DexFile::CodeItem* code_item = m->GetCodeItem();
- if (code_item == nullptr) {
+ CodeItemDataAccessor accessor(m);
+ if (!accessor.HasCodeItem()) {
UNIMPLEMENTED(ERROR) << "Failed to determine this object of abstract or proxy method: "
<< ArtMethod::PrettyMethod(m);
return nullptr;
} else {
- uint16_t reg = code_item->registers_size_ - code_item->ins_size_;
+ uint16_t reg = accessor.RegistersSize() - accessor.InsSize();
uint32_t value = 0;
bool success = GetVReg(m, reg, kReferenceVReg, &value);
// We currently always guarantee the `this` object is live throughout the method.
@@ -223,11 +223,11 @@
bool StackVisitor::GetVRegFromOptimizedCode(ArtMethod* m, uint16_t vreg, VRegKind kind,
uint32_t* val) const {
DCHECK_EQ(m, GetMethod());
- const DexFile::CodeItem* code_item = m->GetCodeItem();
- DCHECK(code_item != nullptr) << m->PrettyMethod(); // Can't be null or how would we compile
- // its instructions?
- uint16_t number_of_dex_registers = code_item->registers_size_;
- DCHECK_LT(vreg, code_item->registers_size_);
+ // Can't be null or how would we compile its instructions?
+ DCHECK(m->GetCodeItem() != nullptr) << m->PrettyMethod();
+ CodeItemDataAccessor accessor(m);
+ uint16_t number_of_dex_registers = accessor.RegistersSize();
+ DCHECK_LT(vreg, number_of_dex_registers);
const OatQuickMethodHeader* method_header = GetCurrentOatQuickMethodHeader();
CodeInfo code_info = method_header->GetOptimizedCodeInfo();
CodeInfoEncoding encoding = code_info.ExtractEncoding();
@@ -395,8 +395,8 @@
uint16_t vreg,
uint32_t new_value,
VRegKind kind) {
- const DexFile::CodeItem* code_item = m->GetCodeItem();
- if (code_item == nullptr) {
+ CodeItemDataAccessor accessor(m);
+ if (!accessor.HasCodeItem()) {
return false;
}
ShadowFrame* shadow_frame = GetCurrentShadowFrame();
@@ -404,7 +404,7 @@
// This is a compiled frame: we must prepare and update a shadow frame that will
// be executed by the interpreter after deoptimization of the stack.
const size_t frame_id = GetFrameId();
- const uint16_t num_regs = code_item->registers_size_;
+ const uint16_t num_regs = accessor.RegistersSize();
shadow_frame = thread_->FindOrCreateDebuggerShadowFrame(frame_id, num_regs, m, GetDexPc());
CHECK(shadow_frame != nullptr);
// Remember the vreg has been set for debugging and must not be overwritten by the
@@ -432,15 +432,15 @@
LOG(FATAL) << "Expected long or double: kind_lo=" << kind_lo << ", kind_hi=" << kind_hi;
UNREACHABLE();
}
- const DexFile::CodeItem* code_item = m->GetCodeItem();
- if (code_item == nullptr) {
+ CodeItemDataAccessor accessor(m);
+ if (!accessor.HasCodeItem()) {
return false;
}
ShadowFrame* shadow_frame = GetCurrentShadowFrame();
if (shadow_frame == nullptr) {
// This is a compiled frame: we must prepare for deoptimization (see SetVRegFromDebugger).
const size_t frame_id = GetFrameId();
- const uint16_t num_regs = code_item->registers_size_;
+ const uint16_t num_regs = accessor.RegistersSize();
shadow_frame = thread_->FindOrCreateDebuggerShadowFrame(frame_id, num_regs, m, GetDexPc());
CHECK(shadow_frame != nullptr);
// Remember the vreg pair has been set for debugging and must not be overwritten by the
diff --git a/runtime/thread.cc b/runtime/thread.cc
index b86e56b..6babd75 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -3425,7 +3425,7 @@
const CodeInfoEncoding& _encoding,
const StackMap& map,
RootVisitor& _visitor)
- : number_of_dex_registers(method->GetCodeItem()->registers_size_),
+ : number_of_dex_registers(CodeItemDataAccessor(method).RegistersSize()),
code_info(_code_info),
encoding(_encoding),
dex_register_map(code_info.GetDexRegisterMapOf(map,
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 4ff49ed..be6915f 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -350,13 +350,13 @@
}
}
-static bool IsLargeMethod(const DexFile::CodeItem* const code_item) {
- if (code_item == nullptr) {
+static bool IsLargeMethod(const CodeItemDataAccessor& accessor) {
+ if (!accessor.HasCodeItem()) {
return false;
}
- uint16_t registers_size = code_item->registers_size_;
- uint32_t insns_size = code_item->insns_size_in_code_units_;
+ uint16_t registers_size = accessor.RegistersSize();
+ uint32_t insns_size = accessor.InsnsSizeInCodeUnits();
return registers_size * insns_size > 4*1024*1024;
}
@@ -494,7 +494,7 @@
if (duration_ns > MsToNs(100)) {
LOG(WARNING) << "Verification of " << dex_file->PrettyMethod(method_idx)
<< " took " << PrettyDuration(duration_ns)
- << (IsLargeMethod(code_item) ? " (large method)" : "");
+ << (IsLargeMethod(verifier.CodeItem()) ? " (large method)" : "");
}
}
result.types = verifier.encountered_failure_types_;
@@ -567,7 +567,7 @@
dex_cache_(dex_cache),
class_loader_(class_loader),
class_def_(class_def),
- code_item_accessor_(CodeItemDataAccessor::CreateNullable(dex_file, code_item)),
+ code_item_accessor_(dex_file, code_item),
declaring_class_(nullptr),
interesting_dex_pc_(-1),
monitor_enter_dex_pcs_(nullptr),