diff options
-rw-r--r-- | compiler/dex/inline_method_analyser.cc | 104 | ||||
-rw-r--r-- | compiler/dex/inline_method_analyser.h | 12 | ||||
-rw-r--r-- | dex2oat/dex2oat_test.cc | 2 | ||||
-rw-r--r-- | runtime/Android.bp | 1 | ||||
-rw-r--r-- | runtime/art_method-inl.h | 13 | ||||
-rw-r--r-- | runtime/art_method.h | 11 | ||||
-rw-r--r-- | runtime/base/casts.h | 8 | ||||
-rw-r--r-- | runtime/cdex/compact_dex_file.h | 23 | ||||
-rw-r--r-- | runtime/code_item_accessors-inl.h | 130 | ||||
-rw-r--r-- | runtime/code_item_accessors.h | 122 | ||||
-rw-r--r-- | runtime/code_item_accessors_test.cc | 108 | ||||
-rw-r--r-- | runtime/dex_file-inl.h | 12 | ||||
-rw-r--r-- | runtime/dex_file.cc | 6 | ||||
-rw-r--r-- | runtime/dex_file.h | 20 | ||||
-rw-r--r-- | runtime/jit/profiling_info.cc | 3 | ||||
-rw-r--r-- | runtime/standard_dex_file.cc | 10 | ||||
-rw-r--r-- | runtime/standard_dex_file.h | 24 |
17 files changed, 528 insertions, 81 deletions
diff --git a/compiler/dex/inline_method_analyser.cc b/compiler/dex/inline_method_analyser.cc index 518b0ece73..b409eb2dbb 100644 --- a/compiler/dex/inline_method_analyser.cc +++ b/compiler/dex/inline_method_analyser.cc @@ -20,6 +20,7 @@ #include "art_method-inl.h" #include "base/enums.h" #include "class_linker-inl.h" +#include "code_item_accessors-inl.h" #include "dex_file-inl.h" #include "dex_instruction-inl.h" #include "dex_instruction.h" @@ -43,7 +44,7 @@ class Matcher { typedef bool MatchFn(Matcher* matcher); template <size_t size> - static bool Match(const DexFile::CodeItem* code_item, MatchFn* const (&pattern)[size]); + static bool Match(const CodeItemDataAccessor* code_item, MatchFn* const (&pattern)[size]); // Match and advance. @@ -62,22 +63,20 @@ class Matcher { bool IPutOnThis(); private: - explicit Matcher(const DexFile::CodeItem* code_item) + explicit Matcher(const CodeItemDataAccessor* code_item) : code_item_(code_item), - instruction_(code_item->Instructions().begin()), - pos_(0u), - mark_(0u) { } + instruction_(code_item->begin()) {} - static bool DoMatch(const DexFile::CodeItem* code_item, MatchFn* const* pattern, size_t size); + static bool DoMatch(const CodeItemDataAccessor* code_item, MatchFn* const* pattern, size_t size); - const DexFile::CodeItem* const code_item_; + const CodeItemDataAccessor* const code_item_; DexInstructionIterator instruction_; - size_t pos_; - size_t mark_; + size_t pos_ = 0u; + size_t mark_ = 0u; }; template <size_t size> -bool Matcher::Match(const DexFile::CodeItem* code_item, MatchFn* const (&pattern)[size]) { +bool Matcher::Match(const CodeItemDataAccessor* code_item, MatchFn* const (&pattern)[size]) { return DoMatch(code_item, pattern, size); } @@ -122,12 +121,12 @@ bool Matcher::Const0() { } bool Matcher::IPutOnThis() { - DCHECK_NE(code_item_->ins_size_, 0u); + DCHECK_NE(code_item_->InsSize(), 0u); return IsInstructionIPut(instruction_->Opcode()) && - instruction_->VRegB_22c() == code_item_->registers_size_ - code_item_->ins_size_; + instruction_->VRegB_22c() == code_item_->RegistersSize() - code_item_->InsSize(); } -bool Matcher::DoMatch(const DexFile::CodeItem* code_item, MatchFn* const* pattern, size_t size) { +bool Matcher::DoMatch(const CodeItemDataAccessor* code_item, MatchFn* const* pattern, size_t size) { Matcher matcher(code_item); while (matcher.pos_ != size) { if (!pattern[matcher.pos_](&matcher)) { @@ -158,7 +157,7 @@ ArtMethod* GetTargetConstructor(ArtMethod* method, const Instruction* invoke_dir // Return the forwarded arguments and check that all remaining arguments are zero. // If the check fails, return static_cast<size_t>(-1). -size_t CountForwardedConstructorArguments(const DexFile::CodeItem* code_item, +size_t CountForwardedConstructorArguments(const CodeItemDataAccessor* code_item, const Instruction* invoke_direct, uint16_t zero_vreg_mask) { DCHECK_EQ(invoke_direct->Opcode(), Instruction::INVOKE_DIRECT); @@ -167,7 +166,7 @@ size_t CountForwardedConstructorArguments(const DexFile::CodeItem* code_item, uint32_t args[Instruction::kMaxVarArgRegs]; invoke_direct->GetVarArgs(args); uint16_t this_vreg = args[0]; - DCHECK_EQ(this_vreg, code_item->registers_size_ - code_item->ins_size_); // Checked by verifier. + DCHECK_EQ(this_vreg, code_item->RegistersSize() - code_item->InsSize()); // Checked by verifier. size_t forwarded = 1u; while (forwarded < number_of_args && args[forwarded] == this_vreg + forwarded && @@ -249,7 +248,7 @@ bool RecordConstructorIPut(ArtMethod* method, return true; } -bool DoAnalyseConstructor(const DexFile::CodeItem* code_item, +bool DoAnalyseConstructor(const CodeItemDataAccessor* code_item, ArtMethod* method, /*inout*/ ConstructorIPutData (&iputs)[kMaxConstructorIPuts]) REQUIRES_SHARED(Locks::mutator_lock_) { @@ -292,17 +291,17 @@ bool DoAnalyseConstructor(const DexFile::CodeItem* code_item, DCHECK(method->IsConstructor()); DCHECK(code_item != nullptr); if (!method->GetDeclaringClass()->IsVerified() || - code_item->insns_size_in_code_units_ > kMaxCodeUnits || - code_item->registers_size_ > kMaxVRegs || + code_item->InsnsSizeInCodeUnits() > kMaxCodeUnits || + code_item->RegistersSize() > kMaxVRegs || !Matcher::Match(code_item, kConstructorPattern)) { return false; } // Verify the invoke, prevent a few odd cases and collect IPUTs. - uint16_t this_vreg = code_item->registers_size_ - code_item->ins_size_; + uint16_t this_vreg = code_item->RegistersSize() - code_item->InsSize(); uint16_t zero_vreg_mask = 0u; - for (const DexInstructionPcPair& pair : code_item->Instructions()) { + for (const DexInstructionPcPair& pair : *code_item) { const Instruction& instruction = pair.Inst(); if (instruction.Opcode() == Instruction::RETURN_VOID) { break; @@ -314,7 +313,7 @@ bool DoAnalyseConstructor(const DexFile::CodeItem* code_item, // We allow forwarding constructors only if they pass more arguments // to prevent infinite recursion. if (target_method->GetDeclaringClass() == method->GetDeclaringClass() && - instruction.VRegA_35c() <= code_item->ins_size_) { + instruction.VRegA_35c() <= code_item->InsSize()) { return false; } size_t forwarded = CountForwardedConstructorArguments(code_item, &instruction, zero_vreg_mask); @@ -322,14 +321,13 @@ bool DoAnalyseConstructor(const DexFile::CodeItem* code_item, return false; } if (target_method->GetDeclaringClass()->IsObjectClass()) { - DCHECK_EQ(target_method->GetCodeItem()->Instructions().begin()->Opcode(), - Instruction::RETURN_VOID); + DCHECK_EQ(CodeItemDataAccessor(target_method).begin()->Opcode(), Instruction::RETURN_VOID); } else { - const DexFile::CodeItem* target_code_item = target_method->GetCodeItem(); - if (target_code_item == nullptr) { + CodeItemDataAccessor target_code_item = CodeItemDataAccessor::CreateNullable(target_method); + if (!target_code_item.HasCodeItem()) { return false; // Native constructor? } - if (!DoAnalyseConstructor(target_code_item, target_method, iputs)) { + if (!DoAnalyseConstructor(&target_code_item, target_method, iputs)) { return false; } // Prune IPUTs with zero input. @@ -365,7 +363,7 @@ bool DoAnalyseConstructor(const DexFile::CodeItem* code_item, } // anonymous namespace -bool AnalyseConstructor(const DexFile::CodeItem* code_item, +bool AnalyseConstructor(const CodeItemDataAccessor* code_item, ArtMethod* method, InlineMethod* result) REQUIRES_SHARED(Locks::mutator_lock_) { @@ -429,27 +427,27 @@ static_assert(InlineMethodAnalyser::IGetVariant(Instruction::IGET_SHORT) == InlineMethodAnalyser::IPutVariant(Instruction::IPUT_SHORT), "iget/iput_short variant"); bool InlineMethodAnalyser::AnalyseMethodCode(ArtMethod* method, InlineMethod* result) { - const DexFile::CodeItem* code_item = method->GetCodeItem(); - if (code_item == nullptr) { + CodeItemDataAccessor code_item = CodeItemDataAccessor::CreateNullable(method); + if (!code_item.HasCodeItem()) { // Native or abstract. return false; } - return AnalyseMethodCode(code_item, + return AnalyseMethodCode(&code_item, MethodReference(method->GetDexFile(), method->GetDexMethodIndex()), method->IsStatic(), method, result); } -bool InlineMethodAnalyser::AnalyseMethodCode(const DexFile::CodeItem* code_item, +bool InlineMethodAnalyser::AnalyseMethodCode(const CodeItemDataAccessor* code_item, const MethodReference& method_ref, bool is_static, ArtMethod* method, InlineMethod* result) { // We currently support only plain return or 2-instruction methods. - DCHECK_NE(code_item->insns_size_in_code_units_, 0u); - Instruction::Code opcode = code_item->Instructions().begin()->Opcode(); + DCHECK_NE(code_item->InsnsSizeInCodeUnits(), 0u); + Instruction::Code opcode = code_item->begin()->Opcode(); switch (opcode) { case Instruction::RETURN_VOID: @@ -518,15 +516,15 @@ bool InlineMethodAnalyser::IsSyntheticAccessor(MethodReference ref) { strncmp(method_name, "-", strlen("-")) == 0; } -bool InlineMethodAnalyser::AnalyseReturnMethod(const DexFile::CodeItem* code_item, +bool InlineMethodAnalyser::AnalyseReturnMethod(const CodeItemDataAccessor* code_item, InlineMethod* result) { - DexInstructionIterator return_instruction = code_item->Instructions().begin(); + DexInstructionIterator return_instruction = code_item->begin(); Instruction::Code return_opcode = return_instruction->Opcode(); uint32_t reg = return_instruction->VRegA_11x(); - uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_; + uint32_t arg_start = code_item->RegistersSize() - code_item->InsSize(); DCHECK_GE(reg, arg_start); DCHECK_LT((return_opcode == Instruction::RETURN_WIDE) ? reg + 1 : reg, - code_item->registers_size_); + code_item->RegistersSize()); if (result != nullptr) { result->opcode = kInlineOpReturnArg; @@ -540,9 +538,9 @@ bool InlineMethodAnalyser::AnalyseReturnMethod(const DexFile::CodeItem* code_ite return true; } -bool InlineMethodAnalyser::AnalyseConstMethod(const DexFile::CodeItem* code_item, +bool InlineMethodAnalyser::AnalyseConstMethod(const CodeItemDataAccessor* code_item, InlineMethod* result) { - DexInstructionIterator instruction = code_item->Instructions().begin(); + DexInstructionIterator instruction = code_item->begin(); const Instruction* return_instruction = instruction->Next(); Instruction::Code return_opcode = return_instruction->Opcode(); if (return_opcode != Instruction::RETURN && @@ -551,13 +549,13 @@ bool InlineMethodAnalyser::AnalyseConstMethod(const DexFile::CodeItem* code_item } int32_t return_reg = return_instruction->VRegA_11x(); - DCHECK_LT(return_reg, code_item->registers_size_); + DCHECK_LT(return_reg, code_item->RegistersSize()); int32_t const_value = instruction->VRegB(); if (instruction->Opcode() == Instruction::CONST_HIGH16) { const_value <<= 16; } - DCHECK_LT(instruction->VRegA(), code_item->registers_size_); + DCHECK_LT(instruction->VRegA(), code_item->RegistersSize()); if (instruction->VRegA() != return_reg) { return false; // Not returning the value set by const? } @@ -571,12 +569,12 @@ bool InlineMethodAnalyser::AnalyseConstMethod(const DexFile::CodeItem* code_item return true; } -bool InlineMethodAnalyser::AnalyseIGetMethod(const DexFile::CodeItem* code_item, +bool InlineMethodAnalyser::AnalyseIGetMethod(const CodeItemDataAccessor* code_item, const MethodReference& method_ref, bool is_static, ArtMethod* method, InlineMethod* result) { - DexInstructionIterator instruction = code_item->Instructions().begin(); + DexInstructionIterator instruction = code_item->begin(); Instruction::Code opcode = instruction->Opcode(); DCHECK(IsInstructionIGet(opcode)); @@ -591,17 +589,17 @@ bool InlineMethodAnalyser::AnalyseIGetMethod(const DexFile::CodeItem* code_item, uint32_t return_reg = return_instruction->VRegA_11x(); DCHECK_LT(return_opcode == Instruction::RETURN_WIDE ? return_reg + 1 : return_reg, - code_item->registers_size_); + code_item->RegistersSize()); uint32_t dst_reg = instruction->VRegA_22c(); uint32_t object_reg = instruction->VRegB_22c(); uint32_t field_idx = instruction->VRegC_22c(); - uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_; + uint32_t arg_start = code_item->RegistersSize() - code_item->InsSize(); DCHECK_GE(object_reg, arg_start); - DCHECK_LT(object_reg, code_item->registers_size_); + DCHECK_LT(object_reg, code_item->RegistersSize()); uint32_t object_arg = object_reg - arg_start; - DCHECK_LT(opcode == Instruction::IGET_WIDE ? dst_reg + 1 : dst_reg, code_item->registers_size_); + DCHECK_LT(opcode == Instruction::IGET_WIDE ? dst_reg + 1 : dst_reg, code_item->RegistersSize()); if (dst_reg != return_reg) { return false; // Not returning the value retrieved by IGET? } @@ -635,18 +633,18 @@ bool InlineMethodAnalyser::AnalyseIGetMethod(const DexFile::CodeItem* code_item, return true; } -bool InlineMethodAnalyser::AnalyseIPutMethod(const DexFile::CodeItem* code_item, +bool InlineMethodAnalyser::AnalyseIPutMethod(const CodeItemDataAccessor* code_item, const MethodReference& method_ref, bool is_static, ArtMethod* method, InlineMethod* result) { - DexInstructionIterator instruction = code_item->Instructions().begin(); + DexInstructionIterator instruction = code_item->begin(); Instruction::Code opcode = instruction->Opcode(); DCHECK(IsInstructionIPut(opcode)); const Instruction* return_instruction = instruction->Next(); Instruction::Code return_opcode = return_instruction->Opcode(); - uint32_t arg_start = code_item->registers_size_ - code_item->ins_size_; + uint32_t arg_start = code_item->RegistersSize() - code_item->InsSize(); uint16_t return_arg_plus1 = 0u; if (return_opcode != Instruction::RETURN_VOID) { if (return_opcode != Instruction::RETURN && @@ -658,7 +656,7 @@ bool InlineMethodAnalyser::AnalyseIPutMethod(const DexFile::CodeItem* code_item, uint32_t return_reg = return_instruction->VRegA_11x(); DCHECK_GE(return_reg, arg_start); DCHECK_LT(return_opcode == Instruction::RETURN_WIDE ? return_reg + 1u : return_reg, - code_item->registers_size_); + code_item->RegistersSize()); return_arg_plus1 = return_reg - arg_start + 1u; } @@ -666,9 +664,9 @@ bool InlineMethodAnalyser::AnalyseIPutMethod(const DexFile::CodeItem* code_item, uint32_t object_reg = instruction->VRegB_22c(); uint32_t field_idx = instruction->VRegC_22c(); DCHECK_GE(object_reg, arg_start); - DCHECK_LT(object_reg, code_item->registers_size_); + DCHECK_LT(object_reg, code_item->RegistersSize()); DCHECK_GE(src_reg, arg_start); - DCHECK_LT(opcode == Instruction::IPUT_WIDE ? src_reg + 1 : src_reg, code_item->registers_size_); + DCHECK_LT(opcode == Instruction::IPUT_WIDE ? src_reg + 1 : src_reg, code_item->RegistersSize()); uint32_t object_arg = object_reg - arg_start; uint32_t src_arg = src_reg - arg_start; diff --git a/compiler/dex/inline_method_analyser.h b/compiler/dex/inline_method_analyser.h index a35e97fa11..cde2147995 100644 --- a/compiler/dex/inline_method_analyser.h +++ b/compiler/dex/inline_method_analyser.h @@ -30,6 +30,8 @@ namespace art { +class CodeItemDataAccessor; + namespace verifier { class MethodVerifier; } // namespace verifier @@ -121,21 +123,21 @@ class InlineMethodAnalyser { static bool IsSyntheticAccessor(MethodReference ref); private: - static bool AnalyseMethodCode(const DexFile::CodeItem* code_item, + static bool AnalyseMethodCode(const CodeItemDataAccessor* code_item, const MethodReference& method_ref, bool is_static, ArtMethod* method, InlineMethod* result) REQUIRES_SHARED(Locks::mutator_lock_); - static bool AnalyseReturnMethod(const DexFile::CodeItem* code_item, InlineMethod* result); - static bool AnalyseConstMethod(const DexFile::CodeItem* code_item, InlineMethod* result); - static bool AnalyseIGetMethod(const DexFile::CodeItem* code_item, + static bool AnalyseReturnMethod(const CodeItemDataAccessor* code_item, InlineMethod* result); + static bool AnalyseConstMethod(const CodeItemDataAccessor* code_item, InlineMethod* result); + static bool AnalyseIGetMethod(const CodeItemDataAccessor* code_item, const MethodReference& method_ref, bool is_static, ArtMethod* method, InlineMethod* result) REQUIRES_SHARED(Locks::mutator_lock_); - static bool AnalyseIPutMethod(const DexFile::CodeItem* code_item, + static bool AnalyseIPutMethod(const CodeItemDataAccessor* code_item, const MethodReference& method_ref, bool is_static, ArtMethod* method, diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc index afca26db71..c2556aa4a6 100644 --- a/dex2oat/dex2oat_test.cc +++ b/dex2oat/dex2oat_test.cc @@ -941,7 +941,7 @@ class Dex2oatUnquickenTest : public Dex2oatTest { class_it.Next()) { if (class_it.IsAtMethod() && class_it.GetMethodCodeItem() != nullptr) { for (const DexInstructionPcPair& inst : - class_it.GetMethodCodeItem()->Instructions()) { + class_it.GetMethodCodeItem()->Instructions()) { ASSERT_FALSE(inst->IsQuickened()); } } diff --git a/runtime/Android.bp b/runtime/Android.bp index e032238324..69e4434fbe 100644 --- a/runtime/Android.bp +++ b/runtime/Android.bp @@ -567,6 +567,7 @@ art_cc_test { "class_linker_test.cc", "class_loader_context_test.cc", "class_table_test.cc", + "code_item_accessors_test.cc", "compiler_filter_test.cc", "dex_file_test.cc", "dex_file_verifier_test.cc", diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h index 12b4d16b37..eb16e6eaa2 100644 --- a/runtime/art_method-inl.h +++ b/runtime/art_method-inl.h @@ -23,6 +23,7 @@ #include "base/callee_save_type.h" #include "base/logging.h" #include "class_linker-inl.h" +#include "code_item_accessors-inl.h" #include "common_throws.h" #include "dex_file-inl.h" #include "dex_file_annotations.h" @@ -457,6 +458,18 @@ inline void ArtMethod::UpdateEntrypoints(const Visitor& visitor, PointerSize poi } } +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() }; +} + } // namespace art #endif // ART_RUNTIME_ART_METHOD_INL_H_ diff --git a/runtime/art_method.h b/runtime/art_method.h index 8927481e46..df9b3aa852 100644 --- a/runtime/art_method.h +++ b/runtime/art_method.h @@ -22,8 +22,10 @@ #include "base/bit_utils.h" #include "base/casts.h" #include "base/enums.h" +#include "base/iteration_range.h" #include "base/logging.h" #include "dex_file.h" +#include "dex_instruction_iterator.h" #include "gc_root.h" #include "modifiers.h" #include "obj_ptr.h" @@ -700,6 +702,15 @@ class ArtMethod FINAL { "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() + REQUIRES_SHARED(Locks::mutator_lock_); + protected: // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". // The class we are a part of. diff --git a/runtime/base/casts.h b/runtime/base/casts.h index 0cbabba6df..92c493ace7 100644 --- a/runtime/base/casts.h +++ b/runtime/base/casts.h @@ -77,6 +77,14 @@ inline To down_cast(From* f) { // so we only accept pointers return static_cast<To>(f); } +template<typename To, typename From> // use like this: down_cast<T&>(foo); +inline To down_cast(From& f) { // so we only accept references + static_assert(std::is_base_of<From, typename std::remove_reference<To>::type>::value, + "down_cast unsafe as To is not a subtype of From"); + + return static_cast<To>(f); +} + template <class Dest, class Source> inline Dest bit_cast(const Source& source) { // Compile time assertion: sizeof(Dest) == sizeof(Source) diff --git a/runtime/cdex/compact_dex_file.h b/runtime/cdex/compact_dex_file.h index 8ab9247125..f17f8cf68a 100644 --- a/runtime/cdex/compact_dex_file.h +++ b/runtime/cdex/compact_dex_file.h @@ -24,11 +24,18 @@ namespace art { // CompactDex is a currently ART internal dex file format that aims to reduce storage/RAM usage. class CompactDexFile : public DexFile { public: + static constexpr uint8_t kDexMagic[kDexMagicSize] = { 'c', 'd', 'e', 'x' }; + static constexpr uint8_t kDexMagicVersion[] = {'0', '0', '1', '\0'}; + class Header : public DexFile::Header { // Same for now. }; - static constexpr uint8_t kDexMagic[kDexMagicSize] = { 'c', 'd', 'e', 'x' }; - static constexpr uint8_t kDexMagicVersion[] = {'0', '0', '1', '\0'}; + + struct CodeItem : public DexFile::CodeItem { + private: + // TODO: Insert compact dex specific fields here. + DISALLOW_COPY_AND_ASSIGN(CodeItem); + }; // Write the compact dex specific magic. static void WriteMagic(uint8_t* magic); @@ -44,10 +51,6 @@ class CompactDexFile : public DexFile { static bool IsVersionValid(const uint8_t* magic); virtual bool IsVersionValid() const OVERRIDE; - bool IsCompactDexFile() const OVERRIDE { - return true; - } - private: // Not supported yet. CompactDexFile(const uint8_t* base, @@ -56,7 +59,13 @@ class CompactDexFile : public DexFile { uint32_t location_checksum, const OatDexFile* oat_dex_file, DexFileContainer* container) - : DexFile(base, size, location, location_checksum, oat_dex_file, container) {} + : DexFile(base, + size, + location, + location_checksum, + oat_dex_file, + container, + /*is_compact_dex*/ true) {} friend class DexFile; friend class DexFileLoader; diff --git a/runtime/code_item_accessors-inl.h b/runtime/code_item_accessors-inl.h new file mode 100644 index 0000000000..61b517526d --- /dev/null +++ b/runtime/code_item_accessors-inl.h @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2017 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_CODE_ITEM_ACCESSORS_INL_H_ +#define ART_RUNTIME_CODE_ITEM_ACCESSORS_INL_H_ + +#include "code_item_accessors.h" + +#include "art_method-inl.h" +#include "cdex/compact_dex_file.h" +#include "standard_dex_file.h" + +namespace art { + +inline void CodeItemInstructionAccessor::Init(const CompactDexFile::CodeItem& code_item) { + insns_size_in_code_units_ = code_item.insns_size_in_code_units_; + insns_ = code_item.insns_; +} + +inline void CodeItemInstructionAccessor::Init(const StandardDexFile::CodeItem& code_item) { + insns_size_in_code_units_ = code_item.insns_size_in_code_units_; + insns_ = code_item.insns_; +} + +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)); + } +} + +inline CodeItemInstructionAccessor::CodeItemInstructionAccessor( + const DexFile* dex_file, + const DexFile::CodeItem* code_item) { + Init(dex_file, code_item); +} + +inline CodeItemInstructionAccessor::CodeItemInstructionAccessor(ArtMethod* method) + : CodeItemInstructionAccessor(method->GetDexFile(), method->GetCodeItem()) {} + +inline DexInstructionIterator CodeItemInstructionAccessor::begin() const { + return DexInstructionIterator(insns_, 0u); +} + +inline DexInstructionIterator CodeItemInstructionAccessor::end() const { + return DexInstructionIterator(insns_, insns_size_in_code_units_); +} + +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 void CodeItemDataAccessor::Init(const CompactDexFile::CodeItem& code_item) { + CodeItemInstructionAccessor::Init(code_item); + registers_size_ = code_item.registers_size_; + ins_size_ = code_item.ins_size_; + outs_size_ = code_item.outs_size_; + tries_size_ = code_item.tries_size_; +} + +inline void CodeItemDataAccessor::Init(const StandardDexFile::CodeItem& code_item) { + CodeItemInstructionAccessor::Init(code_item); + registers_size_ = code_item.registers_size_; + ins_size_ = code_item.ins_size_; + outs_size_ = code_item.outs_size_; + tries_size_ = code_item.tries_size_; +} + +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)); + } +} + +inline CodeItemDataAccessor::CodeItemDataAccessor(const DexFile* dex_file, + const DexFile::CodeItem* code_item) { + Init(dex_file, code_item); +} + +inline CodeItemDataAccessor::CodeItemDataAccessor(ArtMethod* method) + : CodeItemDataAccessor(method->GetDexFile(), method->GetCodeItem()) {} + +inline CodeItemDataAccessor CodeItemDataAccessor::CreateNullable(ArtMethod* method) { + DCHECK(method != nullptr); + CodeItemDataAccessor 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; +} + +} // namespace art + +#endif // ART_RUNTIME_CODE_ITEM_ACCESSORS_INL_H_ diff --git a/runtime/code_item_accessors.h b/runtime/code_item_accessors.h new file mode 100644 index 0000000000..fcece3e0ac --- /dev/null +++ b/runtime/code_item_accessors.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2017 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. + */ + +// TODO: Dex helpers have ART specific APIs, we may want to refactor these for use in dexdump. + +#ifndef ART_RUNTIME_CODE_ITEM_ACCESSORS_H_ +#define ART_RUNTIME_CODE_ITEM_ACCESSORS_H_ + +#include "base/mutex.h" +#include "cdex/compact_dex_file.h" +#include "dex_file.h" +#include "dex_instruction_iterator.h" +#include "standard_dex_file.h" + +namespace art { + +class ArtMethod; + +// Abstracts accesses to the instruction fields of code items for CompactDexFile and +// StandardDexFile. +class CodeItemInstructionAccessor { + public: + ALWAYS_INLINE CodeItemInstructionAccessor(const DexFile* dex_file, + const DexFile::CodeItem* code_item); + + ALWAYS_INLINE explicit CodeItemInstructionAccessor(ArtMethod* method); + + ALWAYS_INLINE DexInstructionIterator begin() const; + + ALWAYS_INLINE DexInstructionIterator end() const; + + uint32_t InsnsSizeInCodeUnits() const { + return insns_size_in_code_units_; + } + + const uint16_t* Insns() const { + return insns_; + } + + // Return true if the accessor has a code item. + bool HasCodeItem() const { + 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; + + ALWAYS_INLINE void Init(const CompactDexFile::CodeItem& code_item); + ALWAYS_INLINE void Init(const StandardDexFile::CodeItem& code_item); + ALWAYS_INLINE void Init(const DexFile* dex_file, const DexFile::CodeItem* code_item); + + private: + // size of the insns array, in 2 byte code units. 0 if there is no code item. + uint32_t insns_size_in_code_units_ = 0; + + // Pointer to the instructions, null if there is no code item. + const uint16_t* insns_ = 0; +}; + +// Abstracts accesses to code item fields other than debug info for CompactDexFile and +// StandardDexFile. +class CodeItemDataAccessor : public CodeItemInstructionAccessor { + public: + ALWAYS_INLINE CodeItemDataAccessor(const DexFile* dex_file, const DexFile::CodeItem* code_item); + + ALWAYS_INLINE explicit CodeItemDataAccessor(ArtMethod* method); + + uint16_t RegistersSize() const { + return registers_size_; + } + + uint16_t InsSize() const { + return ins_size_; + } + + uint16_t OutsSize() const { + return outs_size_; + } + + uint16_t TriesSize() const { + return tries_size_; + } + + // CreateNullable allows ArtMethods that have a null code item. + ALWAYS_INLINE static CodeItemDataAccessor CreateNullable(ArtMethod* method) + REQUIRES_SHARED(Locks::mutator_lock_); + + protected: + CodeItemDataAccessor() = default; + + ALWAYS_INLINE void Init(const CompactDexFile::CodeItem& code_item); + ALWAYS_INLINE void Init(const StandardDexFile::CodeItem& code_item); + ALWAYS_INLINE void Init(const DexFile* dex_file, const DexFile::CodeItem* code_item); + + private: + // Fields mirrored from the dex/cdex code item. + uint16_t registers_size_; + uint16_t ins_size_; + uint16_t outs_size_; + uint16_t tries_size_; +}; + +} // namespace art + +#endif // ART_RUNTIME_CODE_ITEM_ACCESSORS_H_ diff --git a/runtime/code_item_accessors_test.cc b/runtime/code_item_accessors_test.cc new file mode 100644 index 0000000000..ef5d246a54 --- /dev/null +++ b/runtime/code_item_accessors_test.cc @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2017 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 "code_item_accessors-inl.h" + +#include <memory> + +#include "common_runtime_test.h" +#include "dex_file_loader.h" +#include "mem_map.h" + +namespace art { + +class CodeItemAccessorsTest : public CommonRuntimeTest {}; + +std::unique_ptr<const DexFile> CreateFakeDex(bool compact_dex) { + std::string error_msg; + std::unique_ptr<MemMap> map( + MemMap::MapAnonymous(/*name*/ "map", + /*addr*/ nullptr, + /*byte_count*/ kPageSize, + PROT_READ | PROT_WRITE, + /*low_4gb*/ false, + /*reuse*/ false, + &error_msg)); + CHECK(map != nullptr) << error_msg; + if (compact_dex) { + CompactDexFile::WriteMagic(map->Begin()); + CompactDexFile::WriteCurrentVersion(map->Begin()); + } else { + StandardDexFile::WriteMagic(map->Begin()); + StandardDexFile::WriteCurrentVersion(map->Begin()); + } + std::unique_ptr<const DexFile> dex( + DexFileLoader::Open("location", + /*location_checksum*/ 123, + std::move(map), + /*verify*/false, + /*verify_checksum*/false, + &error_msg)); + CHECK(dex != nullptr) << error_msg; + return dex; +} + +TEST(CodeItemAccessorsTest, TestDexInstructionsAccessor) { + MemMap::Init(); + std::unique_ptr<const DexFile> standard_dex(CreateFakeDex(/*compact_dex*/false)); + ASSERT_TRUE(standard_dex != nullptr); + std::unique_ptr<const DexFile> compact_dex(CreateFakeDex(/*compact_dex*/true)); + ASSERT_TRUE(compact_dex != nullptr); + static constexpr uint16_t kRegisterSize = 1; + static constexpr uint16_t kInsSize = 2; + static constexpr uint16_t kOutsSize = 3; + static constexpr uint16_t kTriesSize = 4; + // debug_info_off_ is not accessible from the helpers yet. + static constexpr size_t kInsnsSizeInCodeUnits = 5; + + auto verify_code_item = [&](const DexFile* dex, + const DexFile::CodeItem* item, + const uint16_t* insns) { + CodeItemInstructionAccessor insns_accessor(dex, item); + EXPECT_TRUE(insns_accessor.HasCodeItem()); + ASSERT_EQ(insns_accessor.InsnsSizeInCodeUnits(), kInsnsSizeInCodeUnits); + EXPECT_EQ(insns_accessor.Insns(), insns); + + CodeItemDataAccessor data_accessor(dex, item); + EXPECT_TRUE(data_accessor.HasCodeItem()); + EXPECT_EQ(data_accessor.InsnsSizeInCodeUnits(), kInsnsSizeInCodeUnits); + EXPECT_EQ(data_accessor.Insns(), insns); + EXPECT_EQ(data_accessor.RegistersSize(), kRegisterSize); + EXPECT_EQ(data_accessor.InsSize(), kInsSize); + EXPECT_EQ(data_accessor.OutsSize(), kOutsSize); + EXPECT_EQ(data_accessor.TriesSize(), kTriesSize); + }; + + uint8_t buffer1[sizeof(CompactDexFile::CodeItem) + kInsnsSizeInCodeUnits * sizeof(uint16_t)] = {}; + CompactDexFile::CodeItem* dex_code_item = reinterpret_cast<CompactDexFile::CodeItem*>(buffer1); + dex_code_item->registers_size_ = kRegisterSize; + dex_code_item->ins_size_ = kInsSize; + dex_code_item->outs_size_ = kOutsSize; + dex_code_item->tries_size_ = kTriesSize; + dex_code_item->insns_size_in_code_units_ = kInsnsSizeInCodeUnits; + verify_code_item(compact_dex.get(), dex_code_item, dex_code_item->insns_); + + uint8_t buffer2[sizeof(CompactDexFile::CodeItem) + kInsnsSizeInCodeUnits * sizeof(uint16_t)] = {}; + CompactDexFile::CodeItem* cdex_code_item = reinterpret_cast<CompactDexFile::CodeItem*>(buffer2); + cdex_code_item->registers_size_ = kRegisterSize; + cdex_code_item->ins_size_ = kInsSize; + cdex_code_item->outs_size_ = kOutsSize; + cdex_code_item->tries_size_ = kTriesSize; + cdex_code_item->insns_size_in_code_units_ = kInsnsSizeInCodeUnits; + verify_code_item(compact_dex.get(), cdex_code_item, cdex_code_item->insns_); +} + +} // namespace art diff --git a/runtime/dex_file-inl.h b/runtime/dex_file-inl.h index 5dfbd9b6a1..58cd48631d 100644 --- a/runtime/dex_file-inl.h +++ b/runtime/dex_file-inl.h @@ -21,9 +21,11 @@ #include "base/casts.h" #include "base/logging.h" #include "base/stringpiece.h" +#include "cdex/compact_dex_file.h" #include "dex_file.h" #include "invoke_type.h" #include "leb128.h" +#include "standard_dex_file.h" namespace art { @@ -495,6 +497,16 @@ bool DexFile::DecodeDebugPositionInfo(const CodeItem* code_item, context); } +inline const CompactDexFile* DexFile::AsCompactDexFile() const { + DCHECK(IsCompactDexFile()); + return down_cast<const CompactDexFile*>(this); +} + +inline const StandardDexFile* DexFile::AsStandardDexFile() const { + DCHECK(IsStandardDexFile()); + return down_cast<const StandardDexFile*>(this); +} + } // namespace art #endif // ART_RUNTIME_DEX_FILE_INL_H_ diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc index 974c7acbb2..7b0c46bcfe 100644 --- a/runtime/dex_file.cc +++ b/runtime/dex_file.cc @@ -77,7 +77,8 @@ DexFile::DexFile(const uint8_t* base, const std::string& location, uint32_t location_checksum, const OatDexFile* oat_dex_file, - DexFileContainer* container) + DexFileContainer* container, + bool is_compact_dex) : begin_(base), size_(size), location_(location), @@ -94,7 +95,8 @@ DexFile::DexFile(const uint8_t* base, call_site_ids_(nullptr), num_call_site_ids_(0), oat_dex_file_(oat_dex_file), - container_(container) { + container_(container), + is_compact_dex_(is_compact_dex) { CHECK(begin_ != nullptr) << GetLocation(); CHECK_GT(size_, 0U) << GetLocation(); // Check base (=header) alignment. diff --git a/runtime/dex_file.h b/runtime/dex_file.h index 5c9b2585eb..5c0093f323 100644 --- a/runtime/dex_file.h +++ b/runtime/dex_file.h @@ -32,10 +32,12 @@ namespace art { +class CompactDexFile; enum InvokeType : uint32_t; class MemMap; class OatDexFile; class Signature; +class StandardDexFile; class StringPiece; class ZipArchive; @@ -993,13 +995,15 @@ class DexFile { // Returns a human-readable form of the type at an index. std::string PrettyType(dex::TypeIndex type_idx) const; - // Helper functions. - virtual bool IsCompactDexFile() const { - return false; + // Not virtual for performance reasons. + ALWAYS_INLINE bool IsCompactDexFile() const { + return is_compact_dex_; } - virtual bool IsStandardDexFile() const { - return false; + ALWAYS_INLINE bool IsStandardDexFile() const { + return !is_compact_dex_; } + ALWAYS_INLINE const StandardDexFile* AsStandardDexFile() const; + ALWAYS_INLINE const CompactDexFile* AsCompactDexFile() const; protected: DexFile(const uint8_t* base, @@ -1007,7 +1011,8 @@ class DexFile { const std::string& location, uint32_t location_checksum, const OatDexFile* oat_dex_file, - DexFileContainer* container); + DexFileContainer* container, + bool is_compact_dex); // Top-level initializer that calls other Init methods. bool Init(std::string* error_msg); @@ -1073,6 +1078,9 @@ class DexFile { // Manages the underlying memory allocation. std::unique_ptr<DexFileContainer> container_; + // If the dex file is a compact dex file. If false then the dex file is a standard dex file. + const bool is_compact_dex_; + friend class DexFileLoader; friend class DexFileVerifierTest; friend class OatWriter; diff --git a/runtime/jit/profiling_info.cc b/runtime/jit/profiling_info.cc index 1344ca05b4..e54a0179e1 100644 --- a/runtime/jit/profiling_info.cc +++ b/runtime/jit/profiling_info.cc @@ -44,8 +44,7 @@ bool ProfilingInfo::Create(Thread* self, ArtMethod* method, bool retry_allocatio DCHECK(!method->IsNative()); std::vector<uint32_t> entries; - - for (const DexInstructionPcPair& inst : method->GetCodeItem()->Instructions()) { + for (const DexInstructionPcPair& inst : method->DexInstructions()) { switch (inst->Opcode()) { case Instruction::INVOKE_VIRTUAL: case Instruction::INVOKE_VIRTUAL_RANGE: diff --git a/runtime/standard_dex_file.cc b/runtime/standard_dex_file.cc index 36bb37afe9..4c1d3081d8 100644 --- a/runtime/standard_dex_file.cc +++ b/runtime/standard_dex_file.cc @@ -31,6 +31,16 @@ const uint8_t StandardDexFile::kDexMagicVersions[StandardDexFile::kNumDexVersion {'0', '3', '9', '\0'}, }; +void StandardDexFile::WriteMagic(uint8_t* magic) { + std::copy_n(kDexMagic, kDexMagicSize, magic); +} + +void StandardDexFile::WriteCurrentVersion(uint8_t* magic) { + std::copy_n(kDexMagicVersions[StandardDexFile::kDexVersionLen - 1], + kDexVersionLen, + magic + kDexMagicSize); +} + bool StandardDexFile::IsMagicValid(const uint8_t* magic) { return (memcmp(magic, kDexMagic, sizeof(kDexMagic)) == 0); } diff --git a/runtime/standard_dex_file.h b/runtime/standard_dex_file.h index 784ab31821..5d5359776d 100644 --- a/runtime/standard_dex_file.h +++ b/runtime/standard_dex_file.h @@ -32,6 +32,18 @@ class StandardDexFile : public DexFile { // Same for now. }; + struct CodeItem : public DexFile::CodeItem { + private: + // TODO: Insert standard dex specific fields here. + DISALLOW_COPY_AND_ASSIGN(CodeItem); + }; + + // Write the standard dex specific magic. + static void WriteMagic(uint8_t* magic); + + // Write the current version, note that the input is the address of the magic. + static void WriteCurrentVersion(uint8_t* magic); + static const uint8_t kDexMagic[kDexMagicSize]; static constexpr size_t kNumDexVersions = 4; static const uint8_t kDexMagicVersions[kNumDexVersions][kDexVersionLen]; @@ -44,10 +56,6 @@ class StandardDexFile : public DexFile { static bool IsVersionValid(const uint8_t* magic); virtual bool IsVersionValid() const OVERRIDE; - bool IsStandardDexFile() const OVERRIDE { - return true; - } - private: StandardDexFile(const uint8_t* base, size_t size, @@ -55,7 +63,13 @@ class StandardDexFile : public DexFile { uint32_t location_checksum, const OatDexFile* oat_dex_file, DexFileContainer* container) - : DexFile(base, size, location, location_checksum, oat_dex_file, container) {} + : DexFile(base, + size, + location, + location_checksum, + oat_dex_file, + container, + /*is_compact_dex*/ false) {} friend class DexFileLoader; friend class DexFileVerifierTest; |