Merge "Quick compiler: fix register clobbering."
diff --git a/compiler/Android.mk b/compiler/Android.mk
index 274678a..021392c 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -61,7 +61,6 @@
dex/mir_optimization.cc \
dex/bb_optimizations.cc \
dex/pass_driver_me.cc \
- dex/bit_vector_block_iterator.cc \
dex/frontend.cc \
dex/mir_graph.cc \
dex/mir_analysis.cc \
diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h
index fb6c625..5050d4e 100644
--- a/compiler/common_compiler_test.h
+++ b/compiler/common_compiler_test.h
@@ -377,7 +377,7 @@
timings.EndSplit();
}
- void CompileDirectMethod(Handle<mirror::ClassLoader>& class_loader, const char* class_name,
+ void CompileDirectMethod(Handle<mirror::ClassLoader> class_loader, const char* class_name,
const char* method_name, const char* signature)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
std::string class_descriptor(DotToDescriptor(class_name));
@@ -390,7 +390,7 @@
CompileMethod(method);
}
- void CompileVirtualMethod(Handle<mirror::ClassLoader>& class_loader, const char* class_name,
+ void CompileVirtualMethod(Handle<mirror::ClassLoader> class_loader, const char* class_name,
const char* method_name, const char* signature)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
std::string class_descriptor(DotToDescriptor(class_name));
diff --git a/compiler/dex/bb_optimizations.cc b/compiler/dex/bb_optimizations.cc
index 1852f80..8b5eba0 100644
--- a/compiler/dex/bb_optimizations.cc
+++ b/compiler/dex/bb_optimizations.cc
@@ -38,6 +38,13 @@
/*
* SSATransformation pass implementation start.
*/
+void SSATransformation::Start(const PassDataHolder* data) const {
+ DCHECK(data != nullptr);
+ CompilationUnit* cUnit = down_cast<const PassMEDataHolder*>(data)->c_unit;
+ DCHECK(cUnit != nullptr);
+ cUnit->mir_graph->SSATransformationStart();
+}
+
bool SSATransformation::Worker(const PassDataHolder* data) const {
DCHECK(data != nullptr);
const PassMEDataHolder* pass_me_data_holder = down_cast<const PassMEDataHolder*>(data);
@@ -54,10 +61,7 @@
DCHECK(data != nullptr);
CompilationUnit* cUnit = down_cast<const PassMEDataHolder*>(data)->c_unit;
DCHECK(cUnit != nullptr);
- // Verify the dataflow information after the pass.
- if (cUnit->enable_debug & (1 << kDebugVerifyDataflow)) {
- cUnit->mir_graph->VerifyDataflow();
- }
+ cUnit->mir_graph->SSATransformationEnd();
}
/*
diff --git a/compiler/dex/bb_optimizations.h b/compiler/dex/bb_optimizations.h
index 43dcdf4..3a529f2 100644
--- a/compiler/dex/bb_optimizations.h
+++ b/compiler/dex/bb_optimizations.h
@@ -143,12 +143,7 @@
bool Worker(const PassDataHolder* data) const;
- void Start(const PassDataHolder* data) const {
- DCHECK(data != nullptr);
- CompilationUnit* cUnit = down_cast<const PassMEDataHolder*>(data)->c_unit;
- DCHECK(cUnit != nullptr);
- cUnit->mir_graph->InitializeSSATransformation();
- }
+ void Start(const PassDataHolder* data) const;
void End(const PassDataHolder* data) const;
};
diff --git a/compiler/dex/bit_vector_block_iterator.cc b/compiler/dex/bit_vector_block_iterator.cc
deleted file mode 100644
index 32d7d71..0000000
--- a/compiler/dex/bit_vector_block_iterator.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "bit_vector_block_iterator.h"
-#include "mir_graph.h"
-
-namespace art {
-
-BasicBlock* BitVectorBlockIterator::Next() {
- int idx = internal_iterator_.Next();
-
- if (idx == -1) {
- return nullptr;
- }
-
- return mir_graph_->GetBasicBlock(idx);
-}
-
-} // namespace art
diff --git a/compiler/dex/bit_vector_block_iterator.h b/compiler/dex/bit_vector_block_iterator.h
deleted file mode 100644
index 0f1c2b6..0000000
--- a/compiler/dex/bit_vector_block_iterator.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_DEX_BIT_VECTOR_BLOCK_ITERATOR_H_
-#define ART_COMPILER_DEX_BIT_VECTOR_BLOCK_ITERATOR_H_
-
-#include "base/bit_vector.h"
-#include "compiler_enums.h"
-#include "utils/arena_bit_vector.h"
-#include "utils/arena_allocator.h"
-#include "compiler_ir.h"
-
-namespace art {
-
-class MIRGraph;
-
-/**
- * @class BasicBlockIterator
- * @brief Helper class to get the BasicBlocks when iterating through the ArenaBitVector.
- */
-class BitVectorBlockIterator {
- public:
- explicit BitVectorBlockIterator(BitVector* bv, MIRGraph* mir_graph)
- : mir_graph_(mir_graph),
- internal_iterator_(bv) {}
-
- explicit BitVectorBlockIterator(BitVector* bv, CompilationUnit* c_unit)
- : mir_graph_(c_unit->mir_graph.get()),
- internal_iterator_(bv) {}
-
- BasicBlock* Next();
-
- void* operator new(size_t size, ArenaAllocator* arena) {
- return arena->Alloc(size, kArenaAllocGrowableArray);
- };
- void operator delete(void* p) {} // Nop.
-
- private:
- MIRGraph* const mir_graph_;
- BitVector::Iterator internal_iterator_;
-};
-
-} // namespace art
-
-#endif // ART_COMPILER_DEX_BIT_VECTOR_BLOCK_ITERATOR_H_
diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc
index c34a9f5..24fea71 100644
--- a/compiler/dex/mir_graph.cc
+++ b/compiler/dex/mir_graph.cc
@@ -80,7 +80,6 @@
topological_order_(nullptr),
i_dom_list_(NULL),
def_block_matrix_(NULL),
- temp_dalvik_register_v_(NULL),
temp_scoped_alloc_(),
temp_insn_data_(nullptr),
temp_bit_vector_size_(0u),
@@ -151,7 +150,7 @@
if (insn == NULL) {
LOG(FATAL) << "Break split failed";
}
- BasicBlock *bottom_block = NewMemBB(kDalvikByteCode, num_blocks_++);
+ BasicBlock* bottom_block = NewMemBB(kDalvikByteCode, num_blocks_++);
block_list_.Insert(bottom_block);
bottom_block->start_offset = code_offset;
@@ -189,9 +188,9 @@
orig_block->successor_blocks = NULL;
GrowableArray<SuccessorBlockInfo*>::Iterator iterator(bottom_block->successor_blocks);
while (true) {
- SuccessorBlockInfo *successor_block_info = iterator.Next();
+ SuccessorBlockInfo* successor_block_info = iterator.Next();
if (successor_block_info == NULL) break;
- BasicBlock *bb = GetBasicBlock(successor_block_info->block);
+ BasicBlock* bb = GetBasicBlock(successor_block_info->block);
bb->predecessors->Delete(orig_block->id);
bb->predecessors->Insert(bottom_block->id);
}
@@ -299,7 +298,7 @@
}
}
- // Iterate over each of the handlers to enqueue the empty Catch blocks
+ // Iterate over each of the handlers to enqueue the empty Catch blocks.
const byte* handlers_ptr = DexFile::GetCatchHandlerData(*current_code_item_, 0);
uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
for (uint32_t idx = 0; idx < handlers_size; idx++) {
@@ -346,7 +345,7 @@
LOG(FATAL) << "Unexpected opcode(" << insn->dalvikInsn.opcode << ") with kBranch set";
}
CountBranch(target);
- BasicBlock *taken_block = FindBlock(target, /* split */ true, /* create */ true,
+ BasicBlock* taken_block = FindBlock(target, /* split */ true, /* create */ true,
/* immed_pred_block_p */ &cur_block);
cur_block->taken = taken_block->id;
taken_block->predecessors->Insert(cur_block->id);
@@ -406,7 +405,7 @@
size = switch_data[1];
first_key = switch_data[2] | (switch_data[3] << 16);
target_table = reinterpret_cast<const int*>(&switch_data[4]);
- keyTable = NULL; // Make the compiler happy
+ keyTable = NULL; // Make the compiler happy.
/*
* Sparse switch data format:
* ushort ident = 0x0200 magic value
@@ -422,7 +421,7 @@
size = switch_data[1];
keyTable = reinterpret_cast<const int*>(&switch_data[2]);
target_table = reinterpret_cast<const int*>(&switch_data[2 + size*2]);
- first_key = 0; // To make the compiler happy
+ first_key = 0; // To make the compiler happy.
}
if (cur_block->successor_block_list_type != kNotUsed) {
@@ -435,9 +434,9 @@
new (arena_) GrowableArray<SuccessorBlockInfo*>(arena_, size, kGrowableArraySuccessorBlocks);
for (i = 0; i < size; i++) {
- BasicBlock *case_block = FindBlock(cur_offset + target_table[i], /* split */ true,
+ BasicBlock* case_block = FindBlock(cur_offset + target_table[i], /* split */ true,
/* create */ true, /* immed_pred_block_p */ &cur_block);
- SuccessorBlockInfo *successor_block_info =
+ SuccessorBlockInfo* successor_block_info =
static_cast<SuccessorBlockInfo*>(arena_->Alloc(sizeof(SuccessorBlockInfo),
kArenaAllocSuccessor));
successor_block_info->block = case_block->id;
@@ -480,13 +479,13 @@
new (arena_) GrowableArray<SuccessorBlockInfo*>(arena_, 2, kGrowableArraySuccessorBlocks);
for (; iterator.HasNext(); iterator.Next()) {
- BasicBlock *catch_block = FindBlock(iterator.GetHandlerAddress(), false /* split*/,
+ BasicBlock* catch_block = FindBlock(iterator.GetHandlerAddress(), false /* split*/,
false /* creat */, NULL /* immed_pred_block_p */);
catch_block->catch_entry = true;
if (kIsDebugBuild) {
catches_.insert(catch_block->start_offset);
}
- SuccessorBlockInfo *successor_block_info = reinterpret_cast<SuccessorBlockInfo*>
+ SuccessorBlockInfo* successor_block_info = reinterpret_cast<SuccessorBlockInfo*>
(arena_->Alloc(sizeof(SuccessorBlockInfo), kArenaAllocSuccessor));
successor_block_info->block = catch_block->id;
successor_block_info->key = iterator.GetHandlerTypeIndex();
@@ -494,7 +493,7 @@
catch_block->predecessors->Insert(cur_block->id);
}
} else if (build_all_edges) {
- BasicBlock *eh_block = NewMemBB(kExceptionHandling, num_blocks_++);
+ BasicBlock* eh_block = NewMemBB(kExceptionHandling, num_blocks_++);
cur_block->taken = eh_block->id;
block_list_.Insert(eh_block);
eh_block->start_offset = cur_offset;
@@ -504,7 +503,7 @@
if (is_throw) {
cur_block->explicit_throw = true;
if (code_ptr < code_end) {
- // Force creation of new block following THROW via side-effect
+ // Force creation of new block following THROW via side-effect.
FindBlock(cur_offset + width, /* split */ false, /* create */ true,
/* immed_pred_block_p */ NULL);
}
@@ -550,7 +549,7 @@
*new_insn = *insn;
insn->dalvikInsn.opcode =
static_cast<Instruction::Code>(kMirOpCheck);
- // Associate the two halves
+ // Associate the two halves.
insn->meta.throw_insn = new_insn;
new_block->AppendMIR(new_insn);
return new_block;
@@ -617,7 +616,7 @@
}
/* Current block to record parsed instructions */
- BasicBlock *cur_block = NewMemBB(kDalvikByteCode, num_blocks_++);
+ BasicBlock* cur_block = NewMemBB(kDalvikByteCode, num_blocks_++);
DCHECK_EQ(current_offset_, 0U);
cur_block->start_offset = current_offset_;
block_list_.Insert(cur_block);
@@ -655,7 +654,7 @@
cur_block->use_lvn = true; // Run local value numbering on this basic block.
}
- // Check for inline data block signatures
+ // Check for inline data block signatures.
if (opcode == Instruction::NOP) {
// A simple NOP will have a width of 1 at this point, embedded data NOP > 1.
if ((width == 1) && ((current_offset_ & 0x1) == 0x1) && ((code_end - code_ptr) > 1)) {
@@ -799,7 +798,7 @@
for (idx = 0; idx < num_blocks; idx++) {
int block_idx = all_blocks ? idx : dfs_order_->Get(idx);
- BasicBlock *bb = GetBasicBlock(block_idx);
+ BasicBlock* bb = GetBasicBlock(block_idx);
if (bb == NULL) continue;
if (bb->block_type == kDead) continue;
if (bb->block_type == kEntryBlock) {
@@ -809,7 +808,7 @@
} else if (bb->block_type == kDalvikByteCode) {
fprintf(file, " block%04x_%d [shape=record,label = \"{ \\\n",
bb->start_offset, bb->id);
- const MIR *mir;
+ const MIR* mir;
fprintf(file, " {block id %d\\l}%s\\\n", bb->id,
bb->first_mir_insn ? " | " : " ");
for (mir = bb->first_mir_insn; mir; mir = mir->next) {
@@ -871,13 +870,13 @@
bb->start_offset, bb->id,
(bb->successor_block_list_type == kCatch) ? "Mrecord" : "record");
GrowableArray<SuccessorBlockInfo*>::Iterator iterator(bb->successor_blocks);
- SuccessorBlockInfo *successor_block_info = iterator.Next();
+ SuccessorBlockInfo* successor_block_info = iterator.Next();
int succ_id = 0;
while (true) {
if (successor_block_info == NULL) break;
- BasicBlock *dest_block = GetBasicBlock(successor_block_info->block);
+ BasicBlock* dest_block = GetBasicBlock(successor_block_info->block);
SuccessorBlockInfo *next_successor_block_info = iterator.Next();
fprintf(file, " {<f%d> %04x: %04x\\l}%s\\\n",
@@ -899,7 +898,7 @@
succ_id = 0;
while (true) {
- SuccessorBlockInfo *successor_block_info = iter.Next();
+ SuccessorBlockInfo* successor_block_info = iter.Next();
if (successor_block_info == NULL) break;
BasicBlock* dest_block = GetBasicBlock(successor_block_info->block);
@@ -928,44 +927,78 @@
/* Insert an MIR instruction to the end of a basic block. */
void BasicBlock::AppendMIR(MIR* mir) {
- if (first_mir_insn == nullptr) {
- DCHECK(last_mir_insn == nullptr);
- last_mir_insn = first_mir_insn = mir;
- mir->next = nullptr;
- } else {
- last_mir_insn->next = mir;
- mir->next = nullptr;
- last_mir_insn = mir;
- }
-
- mir->bb = id;
+ // Insert it after the last MIR.
+ InsertMIRListAfter(last_mir_insn, mir, mir);
}
-/* Insert an MIR instruction to the head of a basic block. */
-void BasicBlock::PrependMIR(MIR* mir) {
- if (first_mir_insn == nullptr) {
- DCHECK(last_mir_insn == nullptr);
- last_mir_insn = first_mir_insn = mir;
- mir->next = nullptr;
- } else {
- mir->next = first_mir_insn;
- first_mir_insn = mir;
- }
+void BasicBlock::AppendMIRList(MIR* first_list_mir, MIR* last_list_mir) {
+ // Insert it after the last MIR.
+ InsertMIRListAfter(last_mir_insn, first_list_mir, last_list_mir);
+}
- mir->bb = id;
+void BasicBlock::AppendMIRList(const std::vector<MIR*>& insns) {
+ for (std::vector<MIR*>::const_iterator it = insns.begin(); it != insns.end(); it++) {
+ MIR* new_mir = *it;
+
+ // Add a copy of each MIR.
+ InsertMIRListAfter(last_mir_insn, new_mir, new_mir);
+ }
}
/* Insert a MIR instruction after the specified MIR. */
void BasicBlock::InsertMIRAfter(MIR* current_mir, MIR* new_mir) {
- new_mir->next = current_mir->next;
- current_mir->next = new_mir;
+ InsertMIRListAfter(current_mir, new_mir, new_mir);
+}
- if (last_mir_insn == current_mir) {
- /* Is the last MIR in the block? */
- last_mir_insn = new_mir;
+void BasicBlock::InsertMIRListAfter(MIR* insert_after, MIR* first_list_mir, MIR* last_list_mir) {
+ // If no MIR, we are done.
+ if (first_list_mir == nullptr || last_list_mir == nullptr) {
+ return;
}
- new_mir->bb = id;
+ // If insert_after is null, assume BB is empty.
+ if (insert_after == nullptr) {
+ first_mir_insn = first_list_mir;
+ last_mir_insn = last_list_mir;
+ last_list_mir->next = nullptr;
+ } else {
+ MIR* after_list = insert_after->next;
+ insert_after->next = first_list_mir;
+ last_list_mir->next = after_list;
+ if (after_list == nullptr) {
+ last_mir_insn = last_list_mir;
+ }
+ }
+
+ // Set this BB to be the basic block of the MIRs.
+ MIR* last = last_list_mir->next;
+ for (MIR* mir = first_list_mir; mir != last; mir = mir->next) {
+ mir->bb = id;
+ }
+}
+
+/* Insert an MIR instruction to the head of a basic block. */
+void BasicBlock::PrependMIR(MIR* mir) {
+ InsertMIRListBefore(first_mir_insn, mir, mir);
+}
+
+void BasicBlock::PrependMIRList(MIR* first_list_mir, MIR* last_list_mir) {
+ // Insert it before the first MIR.
+ InsertMIRListBefore(first_mir_insn, first_list_mir, last_list_mir);
+}
+
+void BasicBlock::PrependMIRList(const std::vector<MIR*>& to_add) {
+ for (std::vector<MIR*>::const_iterator it = to_add.begin(); it != to_add.end(); it++) {
+ MIR* mir = *it;
+
+ InsertMIRListBefore(first_mir_insn, mir, mir);
+ }
+}
+
+/* Insert a MIR instruction before the specified MIR. */
+void BasicBlock::InsertMIRBefore(MIR* current_mir, MIR* new_mir) {
+ // Insert as a single element list.
+ return InsertMIRListBefore(current_mir, new_mir, new_mir);
}
MIR* BasicBlock::FindPreviousMIR(MIR* mir) {
@@ -984,20 +1017,79 @@
return nullptr;
}
-void BasicBlock::InsertMIRBefore(MIR* current_mir, MIR* new_mir) {
- if (first_mir_insn == current_mir) {
- /* Is the first MIR in the block? */
- first_mir_insn = new_mir;
- new_mir->bb = id;
+void BasicBlock::InsertMIRListBefore(MIR* insert_before, MIR* first_list_mir, MIR* last_list_mir) {
+ // If no MIR, we are done.
+ if (first_list_mir == nullptr || last_list_mir == nullptr) {
+ return;
}
- MIR* prev = FindPreviousMIR(current_mir);
-
- if (prev != nullptr) {
- prev->next = new_mir;
- new_mir->next = current_mir;
- new_mir->bb = id;
+ // If insert_before is null, assume BB is empty.
+ if (insert_before == nullptr) {
+ first_mir_insn = first_list_mir;
+ last_mir_insn = last_list_mir;
+ last_list_mir->next = nullptr;
+ } else {
+ if (first_mir_insn == insert_before) {
+ last_list_mir->next = first_mir_insn;
+ first_mir_insn = first_list_mir;
+ } else {
+ // Find the preceding MIR.
+ MIR* before_list = FindPreviousMIR(insert_before);
+ DCHECK(before_list != nullptr);
+ before_list->next = first_list_mir;
+ last_list_mir->next = insert_before;
+ }
}
+
+ // Set this BB to be the basic block of the MIRs.
+ for (MIR* mir = first_list_mir; mir != last_list_mir->next; mir = mir->next) {
+ mir->bb = id;
+ }
+}
+
+bool BasicBlock::RemoveMIR(MIR* mir) {
+ // Remove as a single element list.
+ return RemoveMIRList(mir, mir);
+}
+
+bool BasicBlock::RemoveMIRList(MIR* first_list_mir, MIR* last_list_mir) {
+ if (first_list_mir == nullptr) {
+ return false;
+ }
+
+ // Try to find the MIR.
+ MIR* before_list = nullptr;
+ MIR* after_list = nullptr;
+
+ // If we are removing from the beginning of the MIR list.
+ if (first_mir_insn == first_list_mir) {
+ before_list = nullptr;
+ } else {
+ before_list = FindPreviousMIR(first_list_mir);
+ if (before_list == nullptr) {
+ // We did not find the mir.
+ return false;
+ }
+ }
+
+ // Remove the BB information and also find the after_list
+ for (MIR* mir = first_list_mir; mir != last_list_mir; mir = mir->next) {
+ mir->bb = NullBasicBlockId;
+ }
+
+ after_list = last_list_mir->next;
+
+ // If there is nothing before the list, after_list is the first_mir
+ if (before_list == nullptr) {
+ first_mir_insn = after_list;
+ }
+
+ // If there is nothing after the list, before_list is last_mir
+ if (after_list == nullptr) {
+ last_mir_insn = before_list;
+ }
+
+ return true;
}
MIR* BasicBlock::GetNextUnconditionalMir(MIRGraph* mir_graph, MIR* current) {
@@ -1025,7 +1117,7 @@
char* ret;
bool nop = false;
SSARepresentation* ssa_rep = mir->ssa_rep;
- Instruction::Format dalvik_format = Instruction::k10x; // Default to no-operand format
+ Instruction::Format dalvik_format = Instruction::k10x; // Default to no-operand format.
int defs = (ssa_rep != NULL) ? ssa_rep->num_defs : 0;
int uses = (ssa_rep != NULL) ? ssa_rep->num_uses : 0;
@@ -1033,7 +1125,7 @@
if ((opcode == kMirOpCheck) || (opcode == kMirOpCheckPart2)) {
str.append(extended_mir_op_names_[opcode - kMirOpFirst]);
str.append(": ");
- // Recover the original Dex instruction
+ // Recover the original Dex instruction.
insn = mir->meta.throw_insn->dalvikInsn;
ssa_rep = mir->meta.throw_insn->ssa_rep;
defs = ssa_rep->num_defs;
@@ -1092,7 +1184,7 @@
str.append(StringPrintf(" 0x%x (%c%x)", mir->offset + offset,
offset > 0 ? '+' : '-', offset > 0 ? offset : -offset));
} else {
- // For invokes-style formats, treat wide regs as a pair of singles
+ // For invokes-style formats, treat wide regs as a pair of singles.
bool show_singles = ((dalvik_format == Instruction::k35c) ||
(dalvik_format == Instruction::k3rc));
if (defs != 0) {
@@ -1113,28 +1205,28 @@
}
}
switch (dalvik_format) {
- case Instruction::k11n: // Add one immediate from vB
+ case Instruction::k11n: // Add one immediate from vB.
case Instruction::k21s:
case Instruction::k31i:
case Instruction::k21h:
str.append(StringPrintf(", #%d", insn.vB));
break;
- case Instruction::k51l: // Add one wide immediate
+ case Instruction::k51l: // Add one wide immediate.
str.append(StringPrintf(", #%" PRId64, insn.vB_wide));
break;
- case Instruction::k21c: // One register, one string/type/method index
+ case Instruction::k21c: // One register, one string/type/method index.
case Instruction::k31c:
str.append(StringPrintf(", index #%d", insn.vB));
break;
- case Instruction::k22c: // Two registers, one string/type/method index
+ case Instruction::k22c: // Two registers, one string/type/method index.
str.append(StringPrintf(", index #%d", insn.vC));
break;
- case Instruction::k22s: // Add one immediate from vC
+ case Instruction::k22s: // Add one immediate from vC.
case Instruction::k22b:
str.append(StringPrintf(", #%d", insn.vC));
break;
default: {
- // Nothing left to print
+ // Nothing left to print.
}
}
}
@@ -1168,7 +1260,7 @@
// Similar to GetSSAName, but if ssa name represents an immediate show that as well.
std::string MIRGraph::GetSSANameWithConst(int ssa_reg, bool singles_only) {
if (reg_location_ == NULL) {
- // Pre-SSA - just use the standard name
+ // Pre-SSA - just use the standard name.
return GetSSAName(ssa_reg);
}
if (IsConst(reg_location_[ssa_reg])) {
@@ -1288,8 +1380,8 @@
// Allocate a new basic block.
BasicBlock* MIRGraph::NewMemBB(BBType block_type, int block_id) {
- BasicBlock* bb = static_cast<BasicBlock*>(arena_->Alloc(sizeof(BasicBlock),
- kArenaAllocBB));
+ BasicBlock* bb = new (arena_) BasicBlock();
+
bb->block_type = block_type;
bb->id = block_id;
// TUNING: better estimate of the exit block predecessors?
@@ -1307,18 +1399,24 @@
}
void MIRGraph::InitializeMethodUses() {
- // The gate starts by initializing the use counts
+ // The gate starts by initializing the use counts.
int num_ssa_regs = GetNumSSARegs();
use_counts_.Resize(num_ssa_regs + 32);
raw_use_counts_.Resize(num_ssa_regs + 32);
- // Initialize list
+ // Initialize list.
for (int i = 0; i < num_ssa_regs; i++) {
use_counts_.Insert(0);
raw_use_counts_.Insert(0);
}
}
-void MIRGraph::InitializeSSATransformation() {
+void MIRGraph::SSATransformationStart() {
+ DCHECK(temp_scoped_alloc_.get() == nullptr);
+ temp_scoped_alloc_.reset(ScopedArenaAllocator::Create(&cu_->arena_stack));
+ temp_bit_vector_size_ = cu_->num_dalvik_registers;
+ temp_bit_vector_ = new (temp_scoped_alloc_.get()) ArenaBitVector(
+ temp_scoped_alloc_.get(), temp_bit_vector_size_, false, kBitMapRegisterV);
+
/* Compute the DFS order */
ComputeDFSOrders();
@@ -1339,6 +1437,18 @@
DoDFSPreOrderSSARename(GetEntryBlock());
}
+void MIRGraph::SSATransformationEnd() {
+ // Verify the dataflow information after the pass.
+ if (cu_->enable_debug & (1 << kDebugVerifyDataflow)) {
+ VerifyDataflow();
+ }
+
+ temp_bit_vector_size_ = 0u;
+ temp_bit_vector_ = nullptr;
+ DCHECK(temp_scoped_alloc_.get() != nullptr);
+ temp_scoped_alloc_.reset();
+}
+
void MIRGraph::ComputeTopologicalSortOrder() {
std::queue<BasicBlock *> q;
std::map<int, int> visited_cnt_values;
@@ -1488,46 +1598,52 @@
return nullptr;
}
-bool BasicBlock::RemoveMIR(MIR* mir) {
- if (mir == nullptr) {
- return false;
- }
+BasicBlock* BasicBlock::Copy(CompilationUnit* c_unit) {
+ MIRGraph* mir_graph = c_unit->mir_graph.get();
+ return Copy(mir_graph);
+}
- // Find the MIR, and the one before it if they exist.
- MIR* current = nullptr;
- MIR* prev = nullptr;
+BasicBlock* BasicBlock::Copy(MIRGraph* mir_graph) {
+ BasicBlock* result_bb = mir_graph->CreateNewBB(block_type);
- // Find the mir we are looking for.
- for (current = first_mir_insn; current != nullptr; prev = current, current = current->next) {
- if (current == mir) {
- break;
+ // We don't do a memcpy style copy here because it would lead to a lot of things
+ // to clean up. Let us do it by hand instead.
+ // Copy in taken and fallthrough.
+ result_bb->fall_through = fall_through;
+ result_bb->taken = taken;
+
+ // Copy successor links if needed.
+ ArenaAllocator* arena = mir_graph->GetArena();
+
+ result_bb->successor_block_list_type = successor_block_list_type;
+ if (result_bb->successor_block_list_type != kNotUsed) {
+ size_t size = successor_blocks->Size();
+ result_bb->successor_blocks = new (arena) GrowableArray<SuccessorBlockInfo*>(arena, size, kGrowableArraySuccessorBlocks);
+ GrowableArray<SuccessorBlockInfo*>::Iterator iterator(successor_blocks);
+ while (true) {
+ SuccessorBlockInfo* sbi_old = iterator.Next();
+ if (sbi_old == nullptr) {
+ break;
+ }
+ SuccessorBlockInfo* sbi_new = static_cast<SuccessorBlockInfo*>(arena->Alloc(sizeof(SuccessorBlockInfo), kArenaAllocSuccessor));
+ memcpy(sbi_new, sbi_old, sizeof(SuccessorBlockInfo));
+ result_bb->successor_blocks->Insert(sbi_new);
}
}
- // Did we find it?
- if (current != nullptr) {
- MIR* next = current->next;
+ // Copy offset, method.
+ result_bb->start_offset = start_offset;
- // Just update the links of prev and next and current is almost gone.
- if (prev != nullptr) {
- prev->next = next;
- }
+ // Now copy instructions.
+ for (MIR* mir = first_mir_insn; mir != 0; mir = mir->next) {
+ // Get a copy first.
+ MIR* copy = mir->Copy(mir_graph);
- // Exceptions are if first or last mirs are invoke.
- if (first_mir_insn == current) {
- first_mir_insn = next;
- }
-
- if (last_mir_insn == current) {
- last_mir_insn = prev;
- }
-
- // Found it and removed it.
- return true;
+ // Append it.
+ result_bb->AppendMIR(copy);
}
- // We did not find it.
- return false;
+ return result_bb;
}
MIR* MIR::Copy(MIRGraph* mir_graph) {
@@ -1590,4 +1706,208 @@
return res;
}
+/**
+ * @brief Given a decoded instruction, it checks whether the instruction
+ * sets a constant and if it does, more information is provided about the
+ * constant being set.
+ * @param ptr_value pointer to a 64-bit holder for the constant.
+ * @param wide Updated by function whether a wide constant is being set by bytecode.
+ * @return Returns false if the decoded instruction does not represent a constant bytecode.
+ */
+bool MIR::DecodedInstruction::GetConstant(int64_t* ptr_value, bool* wide) const {
+ bool sets_const = true;
+ int64_t value = vB;
+
+ DCHECK(ptr_value != nullptr);
+ DCHECK(wide != nullptr);
+
+ switch (opcode) {
+ case Instruction::CONST_4:
+ case Instruction::CONST_16:
+ case Instruction::CONST:
+ *wide = false;
+ value <<= 32; // In order to get the sign extend.
+ value >>= 32;
+ break;
+ case Instruction::CONST_HIGH16:
+ *wide = false;
+ value <<= 48; // In order to get the sign extend.
+ value >>= 32;
+ break;
+ case Instruction::CONST_WIDE_16:
+ case Instruction::CONST_WIDE_32:
+ *wide = true;
+ value <<= 32; // In order to get the sign extend.
+ value >>= 32;
+ break;
+ case Instruction::CONST_WIDE:
+ *wide = true;
+ value = vB_wide;
+ break;
+ case Instruction::CONST_WIDE_HIGH16:
+ *wide = true;
+ value <<= 48; // In order to get the sign extend.
+ break;
+ default:
+ sets_const = false;
+ break;
+ }
+
+ if (sets_const) {
+ *ptr_value = value;
+ }
+
+ return sets_const;
+}
+
+void BasicBlock::ResetOptimizationFlags(uint16_t reset_flags) {
+ // Reset flags for all MIRs in bb.
+ for (MIR* mir = first_mir_insn; mir != NULL; mir = mir->next) {
+ mir->optimization_flags &= (~reset_flags);
+ }
+}
+
+void BasicBlock::Hide(CompilationUnit* c_unit) {
+ // First lets make it a dalvik bytecode block so it doesn't have any special meaning.
+ block_type = kDalvikByteCode;
+
+ // Mark it as hidden.
+ hidden = true;
+
+ // Detach it from its MIRs so we don't generate code for them. Also detached MIRs
+ // are updated to know that they no longer have a parent.
+ for (MIR* mir = first_mir_insn; mir != nullptr; mir = mir->next) {
+ mir->bb = NullBasicBlockId;
+ }
+ first_mir_insn = nullptr;
+ last_mir_insn = nullptr;
+
+ GrowableArray<BasicBlockId>::Iterator iterator(predecessors);
+
+ MIRGraph* mir_graph = c_unit->mir_graph.get();
+ while (true) {
+ BasicBlock* pred_bb = mir_graph->GetBasicBlock(iterator.Next());
+ if (pred_bb == nullptr) {
+ break;
+ }
+
+ // Sadly we have to go through the children by hand here.
+ pred_bb->ReplaceChild(id, NullBasicBlockId);
+ }
+
+ // Iterate through children of bb we are hiding.
+ ChildBlockIterator successorChildIter(this, mir_graph);
+
+ for (BasicBlock* childPtr = successorChildIter.Next(); childPtr != 0; childPtr = successorChildIter.Next()) {
+ // Replace child with null child.
+ childPtr->predecessors->Delete(id);
+ }
+}
+
+bool BasicBlock::IsSSALiveOut(const CompilationUnit* c_unit, int ssa_reg) {
+ // In order to determine if the ssa reg is live out, we scan all the MIRs. We remember
+ // the last SSA number of the same dalvik register. At the end, if it is different than ssa_reg,
+ // then it is not live out of this BB.
+ int dalvik_reg = c_unit->mir_graph->SRegToVReg(ssa_reg);
+
+ int last_ssa_reg = -1;
+
+ // Walk through the MIRs backwards.
+ for (MIR* mir = first_mir_insn; mir != nullptr; mir = mir->next) {
+ // Get ssa rep.
+ SSARepresentation *ssa_rep = mir->ssa_rep;
+
+ // Go through the defines for this MIR.
+ for (int i = 0; i < ssa_rep->num_defs; i++) {
+ DCHECK(ssa_rep->defs != nullptr);
+
+ // Get the ssa reg.
+ int def_ssa_reg = ssa_rep->defs[i];
+
+ // Get dalvik reg.
+ int def_dalvik_reg = c_unit->mir_graph->SRegToVReg(def_ssa_reg);
+
+ // Compare dalvik regs.
+ if (dalvik_reg == def_dalvik_reg) {
+ // We found a def of the register that we are being asked about.
+ // Remember it.
+ last_ssa_reg = def_ssa_reg;
+ }
+ }
+ }
+
+ if (last_ssa_reg == -1) {
+ // If we get to this point we couldn't find a define of register user asked about.
+ // Let's assume the user knows what he's doing so we can be safe and say that if we
+ // couldn't find a def, it is live out.
+ return true;
+ }
+
+ // If it is not -1, we found a match, is it ssa_reg?
+ return (ssa_reg == last_ssa_reg);
+}
+
+bool BasicBlock::ReplaceChild(BasicBlockId old_bb, BasicBlockId new_bb) {
+ // We need to check taken, fall_through, and successor_blocks to replace.
+ bool found = false;
+ if (taken == old_bb) {
+ taken = new_bb;
+ found = true;
+ }
+
+ if (fall_through == old_bb) {
+ fall_through = new_bb;
+ found = true;
+ }
+
+ if (successor_block_list_type != kNotUsed) {
+ GrowableArray<SuccessorBlockInfo*>::Iterator iterator(successor_blocks);
+ while (true) {
+ SuccessorBlockInfo* successor_block_info = iterator.Next();
+ if (successor_block_info == nullptr) {
+ break;
+ }
+ if (successor_block_info->block == old_bb) {
+ successor_block_info->block = new_bb;
+ found = true;
+ }
+ }
+ }
+
+ return found;
+}
+
+void BasicBlock::UpdatePredecessor(BasicBlockId old_parent, BasicBlockId new_parent) {
+ GrowableArray<BasicBlockId>::Iterator iterator(predecessors);
+ bool found = false;
+
+ while (true) {
+ BasicBlockId pred_bb_id = iterator.Next();
+
+ if (pred_bb_id == NullBasicBlockId) {
+ break;
+ }
+
+ if (pred_bb_id == old_parent) {
+ size_t idx = iterator.GetIndex() - 1;
+ predecessors->Put(idx, new_parent);
+ found = true;
+ break;
+ }
+ }
+
+ // If not found, add it.
+ if (found == false) {
+ predecessors->Insert(new_parent);
+ }
+}
+
+// Create a new basic block with block_id as num_blocks_ that is
+// post-incremented.
+BasicBlock* MIRGraph::CreateNewBB(BBType block_type) {
+ BasicBlock* res = NewMemBB(block_type, num_blocks_++);
+ block_list_.Insert(res);
+ return res;
+}
+
} // namespace art
diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h
index 3a00a43..53a997e 100644
--- a/compiler/dex/mir_graph.h
+++ b/compiler/dex/mir_graph.h
@@ -266,6 +266,56 @@
explicit DecodedInstruction():vA(0), vB(0), vB_wide(0), vC(0), opcode(Instruction::NOP) {
}
+
+ /*
+ * Given a decoded instruction representing a const bytecode, it updates
+ * the out arguments with proper values as dictated by the constant bytecode.
+ */
+ bool GetConstant(int64_t* ptr_value, bool* wide) const;
+
+ bool IsStore() const {
+ return ((Instruction::FlagsOf(opcode) & Instruction::kStore) == Instruction::kStore);
+ }
+
+ bool IsLoad() const {
+ return ((Instruction::FlagsOf(opcode) & Instruction::kLoad) == Instruction::kLoad);
+ }
+
+ bool IsConditionalBranch() const {
+ return (Instruction::FlagsOf(opcode) == (Instruction::kContinue | Instruction::kBranch));
+ }
+
+ /**
+ * @brief Is the register C component of the decoded instruction a constant?
+ */
+ bool IsCFieldOrConstant() const {
+ return ((Instruction::FlagsOf(opcode) & Instruction::kRegCFieldOrConstant) == Instruction::kRegCFieldOrConstant);
+ }
+
+ /**
+ * @brief Is the register C component of the decoded instruction a constant?
+ */
+ bool IsBFieldOrConstant() const {
+ return ((Instruction::FlagsOf(opcode) & Instruction::kRegBFieldOrConstant) == Instruction::kRegBFieldOrConstant);
+ }
+
+ bool IsCast() const {
+ return ((Instruction::FlagsOf(opcode) & Instruction::kCast) == Instruction::kCast);
+ }
+
+ /**
+ * @brief Does the instruction clobber memory?
+ * @details Clobber means that the instruction changes the memory not in a punctual way.
+ * Therefore any supposition on memory aliasing or memory contents should be disregarded
+ * when crossing such an instruction.
+ */
+ bool Clobbers() const {
+ return ((Instruction::FlagsOf(opcode) & Instruction::kClobber) == Instruction::kClobber);
+ }
+
+ bool IsLinear() const {
+ return (Instruction::FlagsOf(opcode) & (Instruction::kAdd | Instruction::kSubtract)) != 0;
+ }
} dalvikInsn;
NarrowDexOffset offset; // Offset of the instruction in code units.
@@ -339,10 +389,49 @@
GrowableArray<SuccessorBlockInfo*>* successor_blocks;
void AppendMIR(MIR* mir);
+ void AppendMIRList(MIR* first_list_mir, MIR* last_list_mir);
+ void AppendMIRList(const std::vector<MIR*>& insns);
void PrependMIR(MIR* mir);
+ void PrependMIRList(MIR* first_list_mir, MIR* last_list_mir);
+ void PrependMIRList(const std::vector<MIR*>& to_add);
void InsertMIRAfter(MIR* current_mir, MIR* new_mir);
- void InsertMIRBefore(MIR* current_mir, MIR* new_mir);
+ void InsertMIRListAfter(MIR* insert_after, MIR* first_list_mir, MIR* last_list_mir);
MIR* FindPreviousMIR(MIR* mir);
+ void InsertMIRBefore(MIR* insert_before, MIR* list);
+ void InsertMIRListBefore(MIR* insert_before, MIR* first_list_mir, MIR* last_list_mir);
+ bool RemoveMIR(MIR* mir);
+ bool RemoveMIRList(MIR* first_list_mir, MIR* last_list_mir);
+
+ BasicBlock* Copy(CompilationUnit* c_unit);
+ BasicBlock* Copy(MIRGraph* mir_graph);
+
+ /**
+ * @brief Reset the optimization_flags field of each MIR.
+ */
+ void ResetOptimizationFlags(uint16_t reset_flags);
+
+ /**
+ * @brief Hide the BasicBlock.
+ * @details Set it to kDalvikByteCode, set hidden to true, remove all MIRs,
+ * remove itself from any predecessor edges, remove itself from any
+ * child's predecessor growable array.
+ */
+ void Hide(CompilationUnit* c_unit);
+
+ /**
+ * @brief Is ssa_reg the last SSA definition of that VR in the block?
+ */
+ bool IsSSALiveOut(const CompilationUnit* c_unit, int ssa_reg);
+
+ /**
+ * @brief Replace the edge going to old_bb to now go towards new_bb.
+ */
+ bool ReplaceChild(BasicBlockId old_bb, BasicBlockId new_bb);
+
+ /**
+ * @brief Update the predecessor growable array from old_pred to new_pred.
+ */
+ void UpdatePredecessor(BasicBlockId old_pred, BasicBlockId new_pred);
/**
* @brief Used to obtain the next MIR that follows unconditionally.
@@ -353,8 +442,12 @@
* @return Returns the following MIR if one can be found.
*/
MIR* GetNextUnconditionalMir(MIRGraph* mir_graph, MIR* current);
- bool RemoveMIR(MIR* mir);
bool IsExceptionBlock() const;
+
+ static void* operator new(size_t size, ArenaAllocator* arena) {
+ return arena->Alloc(sizeof(BasicBlock), kArenaAllocBB);
+ }
+ static void operator delete(void* p) {} // Nop.
};
/*
@@ -871,6 +964,7 @@
BasicBlock* NextDominatedBlock(BasicBlock* bb);
bool LayoutBlocks(BasicBlock* bb);
void ComputeTopologicalSortOrder();
+ BasicBlock* CreateNewBB(BBType block_type);
bool InlineCallsGate();
void InlineCallsStart();
@@ -890,7 +984,7 @@
/**
* @brief Perform the initial preparation for the SSA Transformation.
*/
- void InitializeSSATransformation();
+ void SSATransformationStart();
/**
* @brief Insert a the operands for the Phi nodes.
@@ -900,6 +994,11 @@
bool InsertPhiNodeOperands(BasicBlock* bb);
/**
+ * @brief Perform the cleanup after the SSA Transformation.
+ */
+ void SSATransformationEnd();
+
+ /**
* @brief Perform constant propagation on a BasicBlock.
* @param bb the considered BasicBlock.
*/
@@ -1012,7 +1111,6 @@
GrowableArray<BasicBlockId>* topological_order_;
int* i_dom_list_;
ArenaBitVector** def_block_matrix_; // num_dalvik_register x num_blocks.
- ArenaBitVector* temp_dalvik_register_v_;
std::unique_ptr<ScopedArenaAllocator> temp_scoped_alloc_;
uint16_t* temp_insn_data_;
uint32_t temp_bit_vector_size_;
diff --git a/compiler/dex/pass_driver.cc b/compiler/dex/pass_driver.cc
deleted file mode 100644
index ca936cd..0000000
--- a/compiler/dex/pass_driver.cc
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * Copyright (C) 2014 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 <dlfcn.h>
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "bb_optimizations.h"
-#include "compiler_internals.h"
-#include "dataflow_iterator.h"
-#include "dataflow_iterator-inl.h"
-#include "pass.h"
-#include "pass_driver.h"
-
-namespace art {
-
-namespace { // anonymous namespace
-
-/**
- * @brief Helper function to create a single instance of a given Pass and can be shared across
- * the threads.
- */
-template <typename PassType>
-const Pass* GetPassInstance() {
- static const PassType pass;
- return &pass;
-}
-
-void DoWalkBasicBlocks(CompilationUnit* c_unit, const Pass* pass, DataflowIterator* iterator) {
- // Paranoid: Check the iterator before walking the BasicBlocks.
- DCHECK(iterator != nullptr);
-
- bool change = false;
- for (BasicBlock *bb = iterator->Next(change); bb != 0; bb = iterator->Next(change)) {
- change = pass->WalkBasicBlocks(c_unit, bb);
- }
-}
-
-template <typename Iterator>
-inline void DoWalkBasicBlocks(CompilationUnit* c_unit, const Pass* pass) {
- Iterator iterator(c_unit->mir_graph.get());
- DoWalkBasicBlocks(c_unit, pass, &iterator);
-}
-
-} // anonymous namespace
-
-PassDriver::PassDriver(CompilationUnit* cu, bool create_default_passes)
- : cu_(cu), dump_cfg_folder_("/sdcard/") {
- DCHECK(cu != nullptr);
-
- // If need be, create the default passes.
- if (create_default_passes) {
- CreatePasses();
- }
-}
-
-PassDriver::~PassDriver() {
-}
-
-void PassDriver::InsertPass(const Pass* new_pass) {
- DCHECK(new_pass != nullptr);
- DCHECK(new_pass->GetName() != nullptr && new_pass->GetName()[0] != 0);
-
- // It is an error to override an existing pass.
- DCHECK(GetPass(new_pass->GetName()) == nullptr)
- << "Pass name " << new_pass->GetName() << " already used.";
-
- // Now add to the list.
- pass_list_.push_back(new_pass);
-}
-
-/*
- * Create the pass list. These passes are immutable and are shared across the threads.
- *
- * Advantage is that there will be no race conditions here.
- * Disadvantage is the passes can't change their internal states depending on CompilationUnit:
- * - This is not yet an issue: no current pass would require it.
- */
-static const Pass* const gPasses[] = {
- GetPassInstance<CacheFieldLoweringInfo>(),
- GetPassInstance<CacheMethodLoweringInfo>(),
- GetPassInstance<CallInlining>(),
- GetPassInstance<CodeLayout>(),
- GetPassInstance<SSATransformation>(),
- GetPassInstance<ConstantPropagation>(),
- GetPassInstance<InitRegLocations>(),
- GetPassInstance<MethodUseCount>(),
- GetPassInstance<NullCheckEliminationAndTypeInference>(),
- GetPassInstance<ClassInitCheckElimination>(),
- GetPassInstance<BBCombine>(),
- GetPassInstance<BBOptimizations>(),
-};
-
-// The default pass list is used by CreatePasses to initialize pass_list_.
-static std::vector<const Pass*> gDefaultPassList(gPasses, gPasses + arraysize(gPasses));
-
-void PassDriver::CreateDefaultPassList(const std::string& disable_passes) {
- // Insert each pass from gPasses into gDefaultPassList.
- gDefaultPassList.clear();
- gDefaultPassList.reserve(arraysize(gPasses));
- for (const Pass* pass : gPasses) {
- // Check if we should disable this pass.
- if (disable_passes.find(pass->GetName()) != std::string::npos) {
- LOG(INFO) << "Skipping " << pass->GetName();
- } else {
- gDefaultPassList.push_back(pass);
- }
- }
-}
-
-void PassDriver::CreatePasses() {
- // Insert each pass into the list via the InsertPass method.
- pass_list_.reserve(gDefaultPassList.size());
- for (const Pass* pass : gDefaultPassList) {
- InsertPass(pass);
- }
-}
-
-void PassDriver::HandlePassFlag(CompilationUnit* c_unit, const Pass* pass) {
- // Unused parameters for the moment.
- UNUSED(c_unit);
- UNUSED(pass);
-}
-
-void PassDriver::DispatchPass(CompilationUnit* c_unit, const Pass* curPass) {
- VLOG(compiler) << "Dispatching " << curPass->GetName();
-
- DataFlowAnalysisMode mode = curPass->GetTraversal();
-
- switch (mode) {
- case kPreOrderDFSTraversal:
- DoWalkBasicBlocks<PreOrderDfsIterator>(c_unit, curPass);
- break;
- case kRepeatingPreOrderDFSTraversal:
- DoWalkBasicBlocks<RepeatingPreOrderDfsIterator>(c_unit, curPass);
- break;
- case kRepeatingPostOrderDFSTraversal:
- DoWalkBasicBlocks<RepeatingPostOrderDfsIterator>(c_unit, curPass);
- break;
- case kReversePostOrderDFSTraversal:
- DoWalkBasicBlocks<ReversePostOrderDfsIterator>(c_unit, curPass);
- break;
- case kRepeatingReversePostOrderDFSTraversal:
- DoWalkBasicBlocks<RepeatingReversePostOrderDfsIterator>(c_unit, curPass);
- break;
- case kPostOrderDOMTraversal:
- DoWalkBasicBlocks<PostOrderDOMIterator>(c_unit, curPass);
- break;
- case kAllNodes:
- DoWalkBasicBlocks<AllNodesIterator>(c_unit, curPass);
- break;
- case kTopologicalSortTraversal:
- DoWalkBasicBlocks<TopologicalSortIterator>(c_unit, curPass);
- break;
- case kRepeatingTopologicalSortTraversal:
- DoWalkBasicBlocks<RepeatingTopologicalSortIterator>(c_unit, curPass);
- break;
- case kNoNodes:
- break;
- default:
- LOG(FATAL) << "Iterator mode not handled in dispatcher: " << mode;
- break;
- }
-}
-
-void PassDriver::ApplyPass(CompilationUnit* c_unit, const Pass* curPass) {
- curPass->Start(c_unit);
- DispatchPass(c_unit, curPass);
- curPass->End(c_unit);
-}
-
-bool PassDriver::RunPass(CompilationUnit* c_unit, const Pass* pass, bool time_split) {
- // Paranoid: c_unit and pass cannot be nullptr, and the pass should have a name.
- DCHECK(c_unit != nullptr);
- DCHECK(pass != nullptr);
- DCHECK(pass->GetName() != nullptr && pass->GetName()[0] != 0);
-
- // Do we perform a time split
- if (time_split) {
- c_unit->NewTimingSplit(pass->GetName());
- }
-
- // Check the pass gate first.
- bool should_apply_pass = pass->Gate(c_unit);
-
- if (should_apply_pass) {
- // Applying the pass: first start, doWork, and end calls.
- ApplyPass(c_unit, pass);
-
- // Clean up if need be.
- HandlePassFlag(c_unit, pass);
-
- // Do we want to log it?
- if ((c_unit->enable_debug& (1 << kDebugDumpCFG)) != 0) {
- // Do we have a pass folder?
- const char* passFolder = pass->GetDumpCFGFolder();
- DCHECK(passFolder != nullptr);
-
- if (passFolder[0] != 0) {
- // Create directory prefix.
- std::string prefix = GetDumpCFGFolder();
- prefix += passFolder;
- prefix += "/";
-
- c_unit->mir_graph->DumpCFG(prefix.c_str(), false);
- }
- }
- }
-
- // If the pass gate passed, we can declare success.
- return should_apply_pass;
-}
-
-bool PassDriver::RunPass(CompilationUnit* c_unit, const char* pass_name) {
- // Paranoid: c_unit cannot be nullptr and we need a pass name.
- DCHECK(c_unit != nullptr);
- DCHECK(pass_name != nullptr && pass_name[0] != 0);
-
- const Pass* cur_pass = GetPass(pass_name);
-
- if (cur_pass != nullptr) {
- return RunPass(c_unit, cur_pass);
- }
-
- // Return false, we did not find the pass.
- return false;
-}
-
-void PassDriver::Launch() {
- for (const Pass* cur_pass : pass_list_) {
- RunPass(cu_, cur_pass, true);
- }
-}
-
-void PassDriver::PrintPassNames() {
- LOG(INFO) << "Loop Passes are:";
-
- for (const Pass* cur_pass : gPasses) {
- LOG(INFO) << "\t-" << cur_pass->GetName();
- }
-}
-
-const Pass* PassDriver::GetPass(const char* name) const {
- for (const Pass* cur_pass : pass_list_) {
- if (strcmp(name, cur_pass->GetName()) == 0) {
- return cur_pass;
- }
- }
- return nullptr;
-}
-
-} // namespace art
diff --git a/compiler/dex/ssa_transformation.cc b/compiler/dex/ssa_transformation.cc
index 865311b..6f47b8f 100644
--- a/compiler/dex/ssa_transformation.cc
+++ b/compiler/dex/ssa_transformation.cc
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#include "bit_vector_block_iterator.h"
#include "compiler_internals.h"
#include "dataflow_iterator-inl.h"
@@ -127,12 +126,7 @@
return false;
}
- ArenaBitVector::Iterator iterator(bb->data_flow_info->def_v);
- while (true) {
- int idx = iterator.Next();
- if (idx == -1) {
- break;
- }
+ for (uint32_t idx : bb->data_flow_info->def_v->Indexes()) {
/* Block bb defines register idx */
def_block_matrix_[idx]->SetBit(bb->id);
}
@@ -182,22 +176,22 @@
dom_post_order_traversal_->Reset();
}
ClearAllVisitedFlags();
- std::vector<std::pair<BasicBlock*, ArenaBitVector::Iterator*>> work_stack;
+ std::vector<std::pair<BasicBlock*, ArenaBitVector::IndexIterator>> work_stack;
bb->visited = true;
- work_stack.push_back(std::make_pair(bb, bb->i_dominated->GetIterator()));
+ work_stack.push_back(std::make_pair(bb, bb->i_dominated->Indexes().begin()));
while (!work_stack.empty()) {
- const std::pair<BasicBlock*, ArenaBitVector::Iterator*>& curr = work_stack.back();
- BasicBlock* curr_bb = curr.first;
- ArenaBitVector::Iterator* curr_idom_iter = curr.second;
- int bb_idx = curr_idom_iter->Next();
- while ((bb_idx != -1) && (NeedsVisit(GetBasicBlock(bb_idx)) == NULL)) {
- bb_idx = curr_idom_iter->Next();
+ std::pair<BasicBlock*, ArenaBitVector::IndexIterator>* curr = &work_stack.back();
+ BasicBlock* curr_bb = curr->first;
+ ArenaBitVector::IndexIterator* curr_idom_iter = &curr->second;
+ while (!curr_idom_iter->Done() && (NeedsVisit(GetBasicBlock(**curr_idom_iter)) == nullptr)) {
+ ++*curr_idom_iter;
}
- if (bb_idx != -1) {
- BasicBlock* new_bb = GetBasicBlock(bb_idx);
+ // NOTE: work_stack.push_back()/pop_back() invalidate curr and curr_idom_iter.
+ if (!curr_idom_iter->Done()) {
+ BasicBlock* new_bb = GetBasicBlock(**curr_idom_iter);
+ ++*curr_idom_iter;
new_bb->visited = true;
- work_stack.push_back(
- std::make_pair(new_bb, new_bb->i_dominated->GetIterator()));
+ work_stack.push_back(std::make_pair(new_bb, new_bb->i_dominated->Indexes().begin()));
} else {
// no successor/next
if (curr_bb->id != NullBasicBlockId) {
@@ -249,11 +243,10 @@
}
/* Calculate DF_up */
- BitVectorBlockIterator it(bb->i_dominated, cu_);
- for (BasicBlock *dominated_bb = it.Next(); dominated_bb != nullptr; dominated_bb = it.Next()) {
- BitVectorBlockIterator inner_it(dominated_bb->dom_frontier, cu_);
- for (BasicBlock *df_up_block = inner_it.Next(); df_up_block != nullptr;
- df_up_block = inner_it.Next()) {
+ for (uint32_t dominated_idx : bb->i_dominated->Indexes()) {
+ BasicBlock *dominated_bb = GetBasicBlock(dominated_idx);
+ for (uint32_t df_up_block_idx : dominated_bb->dom_frontier->Indexes()) {
+ BasicBlock *df_up_block = GetBasicBlock(df_up_block_idx);
CheckForDominanceFrontier(bb, df_up_block);
}
}
@@ -449,7 +442,8 @@
* insert a phi node if the variable is live-in to the block.
*/
bool MIRGraph::ComputeBlockLiveIns(BasicBlock* bb) {
- ArenaBitVector* temp_dalvik_register_v = temp_dalvik_register_v_;
+ DCHECK_EQ(temp_bit_vector_size_, cu_->num_dalvik_registers);
+ ArenaBitVector* temp_dalvik_register_v = temp_bit_vector_;
if (bb->data_flow_info == NULL) {
return false;
@@ -487,15 +481,10 @@
/* Insert phi nodes to for each variable to the dominance frontiers */
void MIRGraph::InsertPhiNodes() {
int dalvik_reg;
- ArenaBitVector* phi_blocks =
- new (arena_) ArenaBitVector(arena_, GetNumBlocks(), false, kBitMapPhi);
- ArenaBitVector* tmp_blocks =
- new (arena_) ArenaBitVector(arena_, GetNumBlocks(), false, kBitMapTmpBlocks);
- ArenaBitVector* input_blocks =
- new (arena_) ArenaBitVector(arena_, GetNumBlocks(), false, kBitMapInputBlocks);
-
- temp_dalvik_register_v_ =
- new (arena_) ArenaBitVector(arena_, cu_->num_dalvik_registers, false, kBitMapRegisterV);
+ ArenaBitVector* phi_blocks = new (temp_scoped_alloc_.get()) ArenaBitVector(
+ temp_scoped_alloc_.get(), GetNumBlocks(), false, kBitMapPhi);
+ ArenaBitVector* input_blocks = new (temp_scoped_alloc_.get()) ArenaBitVector(
+ temp_scoped_alloc_.get(), GetNumBlocks(), false, kBitMapInputBlocks);
RepeatingPostOrderDfsIterator iter(this);
bool change = false;
@@ -505,53 +494,23 @@
/* Iterate through each Dalvik register */
for (dalvik_reg = cu_->num_dalvik_registers - 1; dalvik_reg >= 0; dalvik_reg--) {
- bool change;
-
input_blocks->Copy(def_block_matrix_[dalvik_reg]);
phi_blocks->ClearAllBits();
-
- /* Calculate the phi blocks for each Dalvik register */
do {
- change = false;
- tmp_blocks->ClearAllBits();
- ArenaBitVector::Iterator iterator(input_blocks);
-
- while (true) {
- int idx = iterator.Next();
- if (idx == -1) {
- break;
- }
+ // TUNING: When we repeat this, we could skip indexes from the previous pass.
+ for (uint32_t idx : input_blocks->Indexes()) {
BasicBlock* def_bb = GetBasicBlock(idx);
-
- /* Merge the dominance frontier to tmp_blocks */
- // TUNING: hot call to Union().
- if (def_bb->dom_frontier != NULL) {
- tmp_blocks->Union(def_bb->dom_frontier);
+ if (def_bb->dom_frontier != nullptr) {
+ phi_blocks->Union(def_bb->dom_frontier);
}
}
- if (!phi_blocks->Equal(tmp_blocks)) {
- change = true;
- phi_blocks->Copy(tmp_blocks);
-
- /*
- * Iterate through the original blocks plus the new ones in
- * the dominance frontier.
- */
- input_blocks->Copy(phi_blocks);
- input_blocks->Union(def_block_matrix_[dalvik_reg]);
- }
- } while (change);
+ } while (input_blocks->Union(phi_blocks));
/*
* Insert a phi node for dalvik_reg in the phi_blocks if the Dalvik
* register is in the live-in set.
*/
- ArenaBitVector::Iterator iterator(phi_blocks);
- while (true) {
- int idx = iterator.Next();
- if (idx == -1) {
- break;
- }
+ for (uint32_t idx : phi_blocks->Indexes()) {
BasicBlock* phi_bb = GetBasicBlock(idx);
/* Variable will be clobbered before being used - no need for phi */
if (!phi_bb->data_flow_info->live_in_v->IsBitSet(dalvik_reg)) {
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h
index 08fd386..45abfcc 100644
--- a/compiler/driver/compiler_driver-inl.h
+++ b/compiler/driver/compiler_driver-inl.h
@@ -42,8 +42,8 @@
}
inline mirror::Class* CompilerDriver::ResolveCompilingMethodsClass(
- ScopedObjectAccess& soa, const Handle<mirror::DexCache>& dex_cache,
- const Handle<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit) {
+ ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit) {
DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile());
DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
const DexFile::MethodId& referrer_method_id =
@@ -59,8 +59,8 @@
}
inline mirror::ArtField* CompilerDriver::ResolveField(
- ScopedObjectAccess& soa, const Handle<mirror::DexCache>& dex_cache,
- const Handle<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit,
+ ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
uint32_t field_idx, bool is_static) {
DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile());
DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
@@ -165,13 +165,14 @@
}
inline mirror::ArtMethod* CompilerDriver::ResolveMethod(
- ScopedObjectAccess& soa, const Handle<mirror::DexCache>& dex_cache,
- const Handle<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit,
+ ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
uint32_t method_idx, InvokeType invoke_type) {
- DCHECK(dex_cache->GetDexFile() == mUnit->GetDexFile());
- DCHECK(class_loader.Get() == soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
+ DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile());
+ DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
mirror::ArtMethod* resolved_method = mUnit->GetClassLinker()->ResolveMethod(
- *mUnit->GetDexFile(), method_idx, dex_cache, class_loader, nullptr, invoke_type);
+ *mUnit->GetDexFile(), method_idx, dex_cache, class_loader, NullHandle<mirror::ArtMethod>(),
+ invoke_type);
DCHECK_EQ(resolved_method == nullptr, soa.Self()->IsExceptionPending());
if (UNLIKELY(resolved_method == nullptr)) {
// Clean up any exception left by type resolution.
@@ -206,8 +207,8 @@
}
inline int CompilerDriver::IsFastInvoke(
- ScopedObjectAccess& soa, const Handle<mirror::DexCache>& dex_cache,
- const Handle<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit,
+ ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
mirror::Class* referrer_class, mirror::ArtMethod* resolved_method, InvokeType* invoke_type,
MethodReference* target_method, const MethodReference* devirt_target,
uintptr_t* direct_code, uintptr_t* direct_method) {
@@ -256,15 +257,17 @@
ClassLinker* class_linker = mUnit->GetClassLinker();
if (LIKELY(devirt_target->dex_file == mUnit->GetDexFile())) {
called_method = class_linker->ResolveMethod(*devirt_target->dex_file,
- devirt_target->dex_method_index,
- dex_cache, class_loader, NULL, kVirtual);
+ devirt_target->dex_method_index, dex_cache,
+ class_loader, NullHandle<mirror::ArtMethod>(),
+ kVirtual);
} else {
StackHandleScope<1> hs(soa.Self());
Handle<mirror::DexCache> target_dex_cache(
hs.NewHandle(class_linker->FindDexCache(*devirt_target->dex_file)));
called_method = class_linker->ResolveMethod(*devirt_target->dex_file,
devirt_target->dex_method_index,
- target_dex_cache, class_loader, NULL, kVirtual);
+ target_dex_cache, class_loader,
+ NullHandle<mirror::ArtMethod>(), kVirtual);
}
CHECK(called_method != NULL);
CHECK(!called_method->IsAbstract());
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 0f41d2b..3304561 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -511,7 +511,7 @@
}
static DexToDexCompilationLevel GetDexToDexCompilationlevel(
- Thread* self, Handle<mirror::ClassLoader>& class_loader, const DexFile& dex_file,
+ Thread* self, Handle<mirror::ClassLoader> class_loader, const DexFile& dex_file,
const DexFile::ClassDef& class_def) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
const char* descriptor = dex_file.GetClassDescriptor(class_def);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
@@ -731,11 +731,11 @@
for (const std::pair<uint16_t, const DexFile*>& exception_type : unresolved_exception_types) {
uint16_t exception_type_idx = exception_type.first;
const DexFile* dex_file = exception_type.second;
- StackHandleScope<3> hs(self);
+ StackHandleScope<2> hs(self);
Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->FindDexCache(*dex_file)));
- auto class_loader(hs.NewHandle<mirror::ClassLoader>(nullptr));
Handle<mirror::Class> klass(hs.NewHandle(
- class_linker->ResolveType(*dex_file, exception_type_idx, dex_cache, class_loader)));
+ class_linker->ResolveType(*dex_file, exception_type_idx, dex_cache,
+ NullHandle<mirror::ClassLoader>())));
if (klass.Get() == NULL) {
const DexFile::TypeId& type_id = dex_file->GetTypeId(exception_type_idx);
const char* descriptor = dex_file->GetTypeDescriptor(type_id);
@@ -1541,7 +1541,8 @@
if (resolve_fields_and_methods) {
while (it.HasNextDirectMethod()) {
mirror::ArtMethod* method = class_linker->ResolveMethod(dex_file, it.GetMemberIndex(),
- dex_cache, class_loader, NULL,
+ dex_cache, class_loader,
+ NullHandle<mirror::ArtMethod>(),
it.GetMethodInvokeType(class_def));
if (method == NULL) {
CHECK(soa.Self()->IsExceptionPending());
@@ -1551,7 +1552,8 @@
}
while (it.HasNextVirtualMethod()) {
mirror::ArtMethod* method = class_linker->ResolveMethod(dex_file, it.GetMemberIndex(),
- dex_cache, class_loader, NULL,
+ dex_cache, class_loader,
+ NullHandle<mirror::ArtMethod>(),
it.GetMethodInvokeType(class_def));
if (method == NULL) {
CHECK(soa.Self()->IsExceptionPending());
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index abca659..14ccb50 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -221,15 +221,15 @@
// Resolve compiling method's class. Returns nullptr on failure.
mirror::Class* ResolveCompilingMethodsClass(
- ScopedObjectAccess& soa, const Handle<mirror::DexCache>& dex_cache,
- const Handle<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit)
+ ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Resolve a field. Returns nullptr on failure, including incompatible class change.
// NOTE: Unlike ClassLinker's ResolveField(), this method enforces is_static.
mirror::ArtField* ResolveField(
- ScopedObjectAccess& soa, const Handle<mirror::DexCache>& dex_cache,
- const Handle<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit,
+ ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
uint32_t field_idx, bool is_static)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -258,8 +258,8 @@
// Resolve a method. Returns nullptr on failure, including incompatible class change.
mirror::ArtMethod* ResolveMethod(
- ScopedObjectAccess& soa, const Handle<mirror::DexCache>& dex_cache,
- const Handle<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit,
+ ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
uint32_t method_idx, InvokeType invoke_type)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -277,8 +277,8 @@
// Can we fast-path an INVOKE? If no, returns 0. If yes, returns a non-zero opaque flags value
// for ProcessedInvoke() and computes the necessary lowering info.
int IsFastInvoke(
- ScopedObjectAccess& soa, const Handle<mirror::DexCache>& dex_cache,
- const Handle<mirror::ClassLoader>& class_loader, const DexCompilationUnit* mUnit,
+ ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
mirror::Class* referrer_class, mirror::ArtMethod* resolved_method, InvokeType* invoke_type,
MethodReference* target_method, const MethodReference* devirt_target,
uintptr_t* direct_code, uintptr_t* direct_method)
diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc
index 4efd27d..964dfeb 100644
--- a/compiler/driver/compiler_driver_test.cc
+++ b/compiler/driver/compiler_driver_test.cc
@@ -152,10 +152,9 @@
jobject class_loader;
{
ScopedObjectAccess soa(Thread::Current());
- StackHandleScope<1> hs(soa.Self());
- auto null_loader(hs.NewHandle<mirror::ClassLoader>(nullptr));
- CompileVirtualMethod(null_loader, "java.lang.Class", "isFinalizable", "()Z");
- CompileDirectMethod(null_loader, "java.lang.Object", "<init>", "()V");
+ CompileVirtualMethod(NullHandle<mirror::ClassLoader>(), "java.lang.Class", "isFinalizable",
+ "()Z");
+ CompileDirectMethod(NullHandle<mirror::ClassLoader>(), "java.lang.Object", "<init>", "()V");
class_loader = LoadDex("AbstractMethod");
}
ASSERT_TRUE(class_loader != NULL);
diff --git a/compiler/elf_writer_mclinker.cc b/compiler/elf_writer_mclinker.cc
index 0e27210..3dba426 100644
--- a/compiler/elf_writer_mclinker.cc
+++ b/compiler/elf_writer_mclinker.cc
@@ -361,10 +361,11 @@
ClassLinker* linker = Runtime::Current()->GetClassLinker();
// Unchecked as we hold mutator_lock_ on entry.
ScopedObjectAccessUnchecked soa(Thread::Current());
- StackHandleScope<2> hs(soa.Self());
+ StackHandleScope<1> hs(soa.Self());
Handle<mirror::DexCache> dex_cache(hs.NewHandle(linker->FindDexCache(dex_file)));
- auto class_loader(hs.NewHandle<mirror::ClassLoader>(nullptr));
- method = linker->ResolveMethod(dex_file, method_idx, dex_cache, class_loader, NULL, invoke_type);
+ method = linker->ResolveMethod(dex_file, method_idx, dex_cache,
+ NullHandle<mirror::ClassLoader>(),
+ NullHandle<mirror::ArtMethod>(), invoke_type);
CHECK(method != NULL);
}
const CompiledMethod* compiled_method =
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 70144c8..be53926 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -695,15 +695,14 @@
static ArtMethod* GetTargetMethod(const CompilerDriver::CallPatchInformation* patch)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- StackHandleScope<2> hs(Thread::Current());
+ StackHandleScope<1> hs(Thread::Current());
Handle<mirror::DexCache> dex_cache(
hs.NewHandle(class_linker->FindDexCache(*patch->GetTargetDexFile())));
- auto class_loader(hs.NewHandle<mirror::ClassLoader>(nullptr));
ArtMethod* method = class_linker->ResolveMethod(*patch->GetTargetDexFile(),
patch->GetTargetMethodIdx(),
dex_cache,
- class_loader,
- NULL,
+ NullHandle<mirror::ClassLoader>(),
+ NullHandle<mirror::ArtMethod>(),
patch->GetTargetInvokeType());
CHECK(method != NULL)
<< patch->GetTargetDexFile()->GetLocation() << " " << patch->GetTargetMethodIdx();
@@ -721,11 +720,8 @@
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
StackHandleScope<2> hs(Thread::Current());
Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->FindDexCache(patch->GetDexFile())));
- auto class_loader(hs.NewHandle<mirror::ClassLoader>(nullptr));
- Class* klass = class_linker->ResolveType(patch->GetDexFile(),
- patch->GetTargetTypeIdx(),
- dex_cache,
- class_loader);
+ Class* klass = class_linker->ResolveType(patch->GetDexFile(), patch->GetTargetTypeIdx(),
+ dex_cache, NullHandle<mirror::ClassLoader>());
CHECK(klass != NULL)
<< patch->GetDexFile().GetLocation() << " " << patch->GetTargetTypeIdx();
CHECK(dex_cache->GetResolvedTypes()->Get(patch->GetTargetTypeIdx()) == klass)
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index a7ee82e..6812f3c 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -154,8 +154,8 @@
}
const char* descriptor = dex_file->GetClassDescriptor(class_def);
StackHandleScope<1> hs(soa.Self());
- auto loader(hs.NewHandle<mirror::ClassLoader>(nullptr));
- mirror::Class* klass = class_linker->FindClass(soa.Self(), descriptor, loader);
+ mirror::Class* klass = class_linker->FindClass(soa.Self(), descriptor,
+ NullHandle<mirror::ClassLoader>());
const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(i);
CHECK_EQ(mirror::Class::Status::kStatusNotReady, oat_class.GetStatus()) << descriptor;
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index bace25c..5d532ab 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -513,9 +513,10 @@
ScopedObjectAccessUnchecked soa(Thread::Current());
StackHandleScope<2> hs(soa.Self());
Handle<mirror::DexCache> dex_cache(hs.NewHandle(linker->FindDexCache(*dex_file_)));
- auto class_loader = hs.NewHandle<mirror::ClassLoader>(nullptr);
mirror::ArtMethod* method = linker->ResolveMethod(*dex_file_, it.GetMemberIndex(), dex_cache,
- class_loader, nullptr, invoke_type);
+ NullHandle<mirror::ClassLoader>(),
+ NullHandle<mirror::ArtMethod>(),
+ invoke_type);
CHECK(method != NULL);
// Portable code offsets are set by ElfWriterMclinker::FixupCompiledCodeOffset after linking.
method->SetQuickOatCodeOffset(offsets.code_offset_);
diff --git a/compiler/optimizing/ssa_liveness_analysis.cc b/compiler/optimizing/ssa_liveness_analysis.cc
index 0f16ad2..938c5ec 100644
--- a/compiler/optimizing/ssa_liveness_analysis.cc
+++ b/compiler/optimizing/ssa_liveness_analysis.cc
@@ -174,28 +174,6 @@
ComputeLiveInAndLiveOutSets();
}
-class InstructionBitVectorIterator : public ValueObject {
- public:
- InstructionBitVectorIterator(const BitVector& vector,
- const GrowableArray<HInstruction*>& instructions)
- : instructions_(instructions),
- iterator_(BitVector::Iterator(&vector)),
- current_bit_index_(iterator_.Next()) {}
-
- bool Done() const { return current_bit_index_ == -1; }
- HInstruction* Current() const { return instructions_.Get(current_bit_index_); }
- void Advance() {
- current_bit_index_ = iterator_.Next();
- }
-
- private:
- const GrowableArray<HInstruction*> instructions_;
- BitVector::Iterator iterator_;
- int32_t current_bit_index_;
-
- DISALLOW_COPY_AND_ASSIGN(InstructionBitVectorIterator);
-};
-
void SsaLivenessAnalysis::ComputeLiveRanges() {
// Do a post order visit, adding inputs of instructions live in the block where
// that instruction is defined, and killing instructions that are being visited.
@@ -218,10 +196,9 @@
}
// Add a range that covers this block to all instructions live_in because of successors.
- for (InstructionBitVectorIterator it(*live_in, instructions_from_ssa_index_);
- !it.Done();
- it.Advance()) {
- it.Current()->GetLiveInterval()->AddRange(block->GetLifetimeStart(), block->GetLifetimeEnd());
+ for (uint32_t idx : live_in->Indexes()) {
+ HInstruction* current = instructions_from_ssa_index_.Get(idx);
+ current->GetLiveInterval()->AddRange(block->GetLifetimeStart(), block->GetLifetimeEnd());
}
for (HBackwardInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
@@ -268,11 +245,10 @@
HBasicBlock* back_edge = block->GetLoopInformation()->GetBackEdges().Get(0);
// For all live_in instructions at the loop header, we need to create a range
// that covers the full loop.
- for (InstructionBitVectorIterator it(*live_in, instructions_from_ssa_index_);
- !it.Done();
- it.Advance()) {
- it.Current()->GetLiveInterval()->AddLoopRange(block->GetLifetimeStart(),
- back_edge->GetLifetimeEnd());
+ for (uint32_t idx : live_in->Indexes()) {
+ HInstruction* current = instructions_from_ssa_index_.Get(idx);
+ current->GetLiveInterval()->AddLoopRange(block->GetLifetimeStart(),
+ back_edge->GetLifetimeEnd());
}
}
}
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index d38f37f..7c76b3c 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -424,13 +424,13 @@
Runtime* runtime = Runtime::Current();
if (runtime != nullptr) {
ScopedObjectAccess soa(Thread::Current());
- StackHandleScope<2> hs(soa.Self());
+ StackHandleScope<1> hs(soa.Self());
Handle<mirror::DexCache> dex_cache(
hs.NewHandle(runtime->GetClassLinker()->FindDexCache(dex_file)));
- auto class_loader(hs.NewHandle<mirror::ClassLoader>(nullptr));
+ NullHandle<mirror::ClassLoader> class_loader;
verifier::MethodVerifier verifier(&dex_file, &dex_cache, &class_loader, &class_def,
code_item, dex_method_idx, nullptr, method_access_flags,
- true, true);
+ true, true, true);
verifier.Verify();
DumpCode(indent2_os, &verifier, oat_method, code_item);
} else {
diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S
index 95fcd73..96e0afd 100644
--- a/runtime/arch/mips/quick_entrypoints_mips.S
+++ b/runtime/arch/mips/quick_entrypoints_mips.S
@@ -298,7 +298,11 @@
l.s $f29, 116($a1)
l.s $f30, 120($a1)
l.s $f31, 124($a1)
+ .set push
+ .set nomacro
+ .set noat
lw $at, 4($a0)
+ .set pop
lw $v0, 8($a0)
lw $v1, 12($a0)
lw $a1, 20($a0)
@@ -322,8 +326,6 @@
lw $s7, 92($a0)
lw $t8, 96($a0)
lw $t9, 100($a0)
- lw $k0, 104($a0)
- lw $k1, 108($a0)
lw $gp, 112($a0)
lw $sp, 116($a0)
lw $fp, 120($a0)
diff --git a/runtime/arch/x86/entrypoints_init_x86.cc b/runtime/arch/x86/entrypoints_init_x86.cc
index c4a7b1b..8ad29dd 100644
--- a/runtime/arch/x86/entrypoints_init_x86.cc
+++ b/runtime/arch/x86/entrypoints_init_x86.cc
@@ -71,11 +71,8 @@
// Math entrypoints.
extern "C" double art_quick_fmod(double, double);
extern "C" float art_quick_fmodf(float, float);
-extern "C" double art_quick_l2d(int64_t);
-extern "C" float art_quick_l2f(int64_t);
extern "C" int64_t art_quick_d2l(double);
extern "C" int64_t art_quick_f2l(float);
-extern "C" int32_t art_quick_idivmod(int32_t, int32_t);
extern "C" int64_t art_quick_ldiv(int64_t, int64_t);
extern "C" int64_t art_quick_lmod(int64_t, int64_t);
extern "C" int64_t art_quick_lmul(int64_t, int64_t);
@@ -181,12 +178,12 @@
// points->pCmplFloat = NULL; // Not needed on x86.
qpoints->pFmod = art_quick_fmod;
// qpoints->pSqrt = NULL; // Not needed on x86.
- qpoints->pL2d = art_quick_l2d;
+ // qpoints->pL2d = NULL; // Not needed on x86.
qpoints->pFmodf = art_quick_fmodf;
- qpoints->pL2f = art_quick_l2f;
+ // qpoints->pL2f = NULL; // Not needed on x86.
// points->pD2iz = NULL; // Not needed on x86.
// points->pF2iz = NULL; // Not needed on x86.
- qpoints->pIdivmod = art_quick_idivmod;
+ // qpoints->pIdivmod = NULL; // Not needed on x86.
qpoints->pD2l = art_quick_d2l;
qpoints->pF2l = art_quick_f2l;
qpoints->pLdiv = art_quick_ldiv;
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 339ed2e..b311ea5 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -763,28 +763,6 @@
ret
END_FUNCTION art_quick_fmodf
-DEFINE_FUNCTION art_quick_l2d
- PUSH ecx // push arg2 a.hi
- PUSH eax // push arg1 a.lo
- fildll (%esp) // load as integer and push into st0
- fstpl (%esp) // pop value off fp stack as double
- movsd (%esp), %xmm0 // place into %xmm0
- addl LITERAL(8), %esp // pop arguments
- CFI_ADJUST_CFA_OFFSET(-8)
- ret
-END_FUNCTION art_quick_l2d
-
-DEFINE_FUNCTION art_quick_l2f
- PUSH ecx // push arg2 a.hi
- PUSH eax // push arg1 a.lo
- fildll (%esp) // load as integer and push into st0
- fstps (%esp) // pop value off fp stack as a single
- movss (%esp), %xmm0 // place into %xmm0
- addl LITERAL(8), %esp // pop argument
- CFI_ADJUST_CFA_OFFSET(-8)
- ret
-END_FUNCTION art_quick_l2f
-
DEFINE_FUNCTION art_quick_d2l
PUSH eax // alignment padding
PUSH ecx // pass arg2 a.hi
@@ -807,20 +785,6 @@
ret
END_FUNCTION art_quick_f2l
-DEFINE_FUNCTION art_quick_idivmod
- cmpl LITERAL(0x80000000), %eax
- je .Lcheck_arg2 // special case
-.Largs_ok:
- cdq // edx:eax = sign extend eax
- idiv %ecx // (edx,eax) = (edx:eax % ecx, edx:eax / ecx)
- ret
-.Lcheck_arg2:
- cmpl LITERAL(-1), %ecx
- jne .Largs_ok
- xorl %edx, %edx
- ret // eax already holds min int
-END_FUNCTION art_quick_idivmod
-
DEFINE_FUNCTION art_quick_ldiv
subl LITERAL(12), %esp // alignment padding
CFI_ADJUST_CFA_OFFSET(12)
diff --git a/runtime/arch/x86_64/entrypoints_init_x86_64.cc b/runtime/arch/x86_64/entrypoints_init_x86_64.cc
index 30067cf..86dcf36 100644
--- a/runtime/arch/x86_64/entrypoints_init_x86_64.cc
+++ b/runtime/arch/x86_64/entrypoints_init_x86_64.cc
@@ -18,6 +18,7 @@
#include "entrypoints/quick/quick_alloc_entrypoints.h"
#include "entrypoints/quick/quick_entrypoints.h"
#include "entrypoints/entrypoint_utils.h"
+#include "entrypoints/math_entrypoints.h"
namespace art {
@@ -34,8 +35,8 @@
extern "C" void art_portable_to_interpreter_bridge(mirror::ArtMethod*);
// Cast entrypoints.
-extern "C" uint32_t art_quick_is_assignable(const mirror::Class* klass,
- const mirror::Class* ref_class);
+extern "C" uint32_t artIsAssignableFromCode(const mirror::Class* klass,
+ const mirror::Class* ref_class);
extern "C" void art_quick_check_cast(void*, void*);
// DexCache entrypoints.
@@ -69,13 +70,8 @@
extern "C" void art_quick_unlock_object(void*);
// Math entrypoints.
-extern "C" double art_quick_fmod(double, double);
-extern "C" float art_quick_fmodf(float, float);
-extern "C" double art_quick_l2d(int64_t);
-extern "C" float art_quick_l2f(int64_t);
extern "C" int64_t art_quick_d2l(double);
extern "C" int64_t art_quick_f2l(float);
-extern "C" int32_t art_quick_idivmod(int32_t, int32_t);
extern "C" int64_t art_quick_ldiv(int64_t, int64_t);
extern "C" int64_t art_quick_lmod(int64_t, int64_t);
extern "C" int64_t art_quick_lmul(int64_t, int64_t);
@@ -85,7 +81,6 @@
// Intrinsic entrypoints.
extern "C" int32_t art_quick_memcmp16(void*, void*, int32_t);
-extern "C" int32_t art_quick_indexof(void*, uint32_t, uint32_t, uint32_t);
extern "C" int32_t art_quick_string_compareto(void*, void*);
extern "C" void* art_quick_memcpy(void*, const void*, size_t);
@@ -133,7 +128,7 @@
ResetQuickAllocEntryPoints(qpoints);
// Cast
- qpoints->pInstanceofNonTrivial = art_quick_is_assignable;
+ qpoints->pInstanceofNonTrivial = artIsAssignableFromCode;
qpoints->pCheckCast = art_quick_check_cast;
// DexCache
@@ -180,16 +175,16 @@
// points->pCmpgFloat = NULL; // Not needed on x86.
// points->pCmplDouble = NULL; // Not needed on x86.
// points->pCmplFloat = NULL; // Not needed on x86.
- qpoints->pFmod = art_quick_fmod;
+ qpoints->pFmod = fmod;
// qpoints->pSqrt = NULL; // Not needed on x86.
- qpoints->pL2d = art_quick_l2d;
- qpoints->pFmodf = art_quick_fmodf;
- qpoints->pL2f = art_quick_l2f;
+ // qpoints->pL2d = NULL; // Not needed on x86.
+ qpoints->pFmodf = fmodf;
+ // qpoints->pL2f = NULL; // Not needed on x86.
// points->pD2iz = NULL; // Not needed on x86.
// points->pF2iz = NULL; // Not needed on x86.
- qpoints->pIdivmod = art_quick_idivmod;
- qpoints->pD2l = art_quick_d2l;
- qpoints->pF2l = art_quick_f2l;
+ // qpoints->pIdivmod = NULL; // Not needed on x86.
+ qpoints->pD2l = art_d2l;
+ qpoints->pF2l = art_f2l;
qpoints->pLdiv = art_quick_ldiv;
qpoints->pLmod = art_quick_lmod;
qpoints->pLmul = art_quick_lmul;
@@ -198,7 +193,7 @@
qpoints->pUshrLong = art_quick_lushr;
// Intrinsics
- qpoints->pIndexOf = art_quick_indexof;
+ // qpoints->pIndexOf = NULL; // Not needed on x86.
qpoints->pMemcmp16 = art_quick_memcmp16;
qpoints->pStringCompareTo = art_quick_string_compareto;
qpoints->pMemcpy = art_quick_memcpy;
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index ed7f246..971688d 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -737,11 +737,6 @@
RETURN_IF_EAX_ZERO
END_FUNCTION art_quick_unlock_object
-DEFINE_FUNCTION art_quick_is_assignable
- int3
- int3
-END_FUNCTION art_quick_is_assignable
-
DEFINE_FUNCTION art_quick_check_cast
PUSH rdi // Save args for exc
PUSH rsi
@@ -876,13 +871,6 @@
NO_ARG_DOWNCALL art_quick_test_suspend, artTestSuspendFromCode, ret
-UNIMPLEMENTED art_quick_fmod
-UNIMPLEMENTED art_quick_fmodf
-UNIMPLEMENTED art_quick_l2d
-UNIMPLEMENTED art_quick_l2f
-UNIMPLEMENTED art_quick_d2l
-UNIMPLEMENTED art_quick_f2l
-UNIMPLEMENTED art_quick_idivmod
UNIMPLEMENTED art_quick_ldiv
UNIMPLEMENTED art_quick_lmod
UNIMPLEMENTED art_quick_lmul
@@ -1301,8 +1289,6 @@
*/
UNIMPLEMENTED art_quick_deoptimize
-UNIMPLEMENTED art_quick_indexof
-
/*
* String's compareTo.
*
diff --git a/runtime/base/bit_vector.cc b/runtime/base/bit_vector.cc
index a3e2b15..0053389 100644
--- a/runtime/base/bit_vector.cc
+++ b/runtime/base/bit_vector.cc
@@ -45,10 +45,11 @@
storage_size_(storage_size),
storage_(storage),
number_of_bits_(start_bits) {
- DCHECK_EQ(sizeof(*storage_), 4U); // Assuming 32-bit units.
+ COMPILE_ASSERT(sizeof(*storage_) == kWordBytes, check_word_bytes);
+ COMPILE_ASSERT(sizeof(*storage_) * 8u == kWordBits, check_word_bits);
if (storage_ == nullptr) {
storage_size_ = BitsToWords(start_bits);
- storage_ = static_cast<uint32_t*>(allocator_->Alloc(storage_size_ * sizeof(*storage_)));
+ storage_ = static_cast<uint32_t*>(allocator_->Alloc(storage_size_ * kWordBytes));
}
}
@@ -61,7 +62,7 @@
*/
bool BitVector::IsBitSet(uint32_t num) const {
// If the index is over the size:
- if (num >= storage_size_ * sizeof(*storage_) * 8) {
+ if (num >= storage_size_ * kWordBits) {
// Whether it is expandable or not, this bit does not exist: thus it is not set.
return false;
}
@@ -71,7 +72,7 @@
// Mark all bits bit as "clear".
void BitVector::ClearAllBits() {
- memset(storage_, 0, storage_size_ * sizeof(*storage_));
+ memset(storage_, 0, storage_size_ * kWordBytes);
}
// Mark the specified bit as "set".
@@ -80,17 +81,17 @@
* not using it badly or change resize mechanism.
*/
void BitVector::SetBit(uint32_t num) {
- if (num >= storage_size_ * sizeof(*storage_) * 8) {
+ if (num >= storage_size_ * kWordBits) {
DCHECK(expandable_) << "Attempted to expand a non-expandable bitmap to position " << num;
/* Round up to word boundaries for "num+1" bits */
uint32_t new_size = BitsToWords(num + 1);
DCHECK_GT(new_size, storage_size_);
uint32_t *new_storage =
- static_cast<uint32_t*>(allocator_->Alloc(new_size * sizeof(*storage_)));
- memcpy(new_storage, storage_, storage_size_ * sizeof(*storage_));
+ static_cast<uint32_t*>(allocator_->Alloc(new_size * kWordBytes));
+ memcpy(new_storage, storage_, storage_size_ * kWordBytes);
// Zero out the new storage words.
- memset(&new_storage[storage_size_], 0, (new_size - storage_size_) * sizeof(*storage_));
+ memset(&new_storage[storage_size_], 0, (new_size - storage_size_) * kWordBytes);
// TOTO: collect stats on space wasted because of resize.
storage_ = new_storage;
storage_size_ = new_size;
@@ -103,7 +104,7 @@
// Mark the specified bit as "unset".
void BitVector::ClearBit(uint32_t num) {
// If the index is over the size, we don't have to do anything, it is cleared.
- if (num < storage_size_ * sizeof(*storage_) * 8) {
+ if (num < storage_size_ * kWordBits) {
// Otherwise, go ahead and clear it.
storage_[num >> 5] &= ~check_masks[num & 0x1f];
}
@@ -132,7 +133,7 @@
// - Therefore, min_size goes up to at least that, we are thus comparing at least what we need to, but not less.
// ie. we are comparing all storage cells that could have difference, if both vectors have cells above our_highest_index,
// they are automatically at 0.
- return (memcmp(storage_, src->GetRawStorage(), our_highest_index * sizeof(*storage_)) == 0);
+ return (memcmp(storage_, src->GetRawStorage(), our_highest_index * kWordBytes) == 0);
}
// Intersect with another bit vector.
@@ -180,7 +181,7 @@
SetBit(highest_bit);
// Paranoid: storage size should be big enough to hold this bit now.
- DCHECK_LT(static_cast<uint32_t> (highest_bit), storage_size_ * sizeof(*(storage_)) * 8);
+ DCHECK_LT(static_cast<uint32_t> (highest_bit), storage_size_ * kWordBits);
}
for (uint32_t idx = 0; idx < src_size; idx++) {
@@ -215,7 +216,7 @@
SetBit(highest_bit);
// Paranoid: storage size should be big enough to hold this bit now.
- DCHECK_LT(static_cast<uint32_t> (highest_bit), storage_size_ * sizeof(*(storage_)) * 8);
+ DCHECK_LT(static_cast<uint32_t> (highest_bit), storage_size_ * kWordBits);
}
uint32_t not_in_size = not_in->GetStorageSize();
@@ -268,14 +269,10 @@
// Count the number of bits that are set in range [0, end).
uint32_t BitVector::NumSetBits(uint32_t end) const {
- DCHECK_LE(end, storage_size_ * sizeof(*storage_) * 8);
+ DCHECK_LE(end, storage_size_ * kWordBits);
return NumSetBits(storage_, end);
}
-BitVector::Iterator* BitVector::GetIterator() const {
- return new (allocator_) Iterator(this);
-}
-
/*
* Mark specified number of bits as "set". Cannot set all bits like ClearAll
* since there might be unused bits - setting those to one will confuse the
@@ -329,7 +326,7 @@
}
// Return cnt + how many storage units still remain * the number of bits per unit.
- int res = cnt + (idx * (sizeof(*storage_) * 8));
+ int res = cnt + (idx * kWordBits);
return res;
}
}
@@ -369,14 +366,14 @@
SetBit(highest_bit);
// Now set until highest bit's storage.
- uint32_t size = 1 + (highest_bit / (sizeof(*storage_) * 8));
- memcpy(storage_, src->GetRawStorage(), sizeof(*storage_) * size);
+ uint32_t size = 1 + (highest_bit / kWordBits);
+ memcpy(storage_, src->GetRawStorage(), kWordBytes * size);
// Set upper bits to 0.
uint32_t left = storage_size_ - size;
if (left > 0) {
- memset(storage_ + size, 0, sizeof(*storage_) * left);
+ memset(storage_ + size, 0, kWordBytes * left);
}
}
@@ -401,14 +398,12 @@
void BitVector::Dump(std::ostream& os, const char *prefix) const {
std::ostringstream buffer;
- DumpHelper(buffer, prefix);
+ DumpHelper(prefix, buffer);
os << buffer.str() << std::endl;
}
-void BitVector::DumpDot(FILE* file, const char* prefix, bool last_entry) const {
- std::ostringstream buffer;
- Dump(buffer, prefix);
+void BitVector::DumpDotHelper(bool last_entry, FILE* file, std::ostringstream& buffer) const {
// Now print it to the file.
fprintf(file, " {%s}", buffer.str().c_str());
@@ -421,7 +416,32 @@
fprintf(file, "\\\n");
}
-void BitVector::DumpHelper(std::ostringstream& buffer, const char* prefix) const {
+void BitVector::DumpDot(FILE* file, const char* prefix, bool last_entry) const {
+ std::ostringstream buffer;
+ DumpHelper(prefix, buffer);
+ DumpDotHelper(last_entry, file, buffer);
+}
+
+void BitVector::DumpIndicesDot(FILE* file, const char* prefix, bool last_entry) const {
+ std::ostringstream buffer;
+ DumpIndicesHelper(prefix, buffer);
+ DumpDotHelper(last_entry, file, buffer);
+}
+
+void BitVector::DumpIndicesHelper(const char* prefix, std::ostringstream& buffer) const {
+ // Initialize it.
+ if (prefix != nullptr) {
+ buffer << prefix;
+ }
+
+ for (size_t i = 0; i < number_of_bits_; i++) {
+ if (IsBitSet(i)) {
+ buffer << i << " ";
+ }
+ }
+}
+
+void BitVector::DumpHelper(const char* prefix, std::ostringstream& buffer) const {
// Initialize it.
if (prefix != nullptr) {
buffer << prefix;
diff --git a/runtime/base/bit_vector.h b/runtime/base/bit_vector.h
index 2a68396..8f9afff 100644
--- a/runtime/base/bit_vector.h
+++ b/runtime/base/bit_vector.h
@@ -32,59 +32,115 @@
*/
class BitVector {
public:
- class Iterator {
+ class IndexContainer;
+
+ /**
+ * @brief Convenient iterator across the indexes of the BitVector's set bits.
+ *
+ * @details IndexIterator is a Forward iterator (C++11: 24.2.5) from the lowest
+ * to the highest index of the BitVector's set bits. Instances can be retrieved
+ * only through BitVector::Indexes() which returns an IndexContainer wrapper
+ * object with begin() and end() suitable for range-based loops:
+ * for (uint32_t idx : bit_vector.Indexes()) {
+ * // Use idx.
+ * }
+ */
+ class IndexIterator
+ : std::iterator<std::forward_iterator_tag, uint32_t, ptrdiff_t, void, uint32_t> {
public:
- explicit Iterator(const BitVector* bit_vector)
- : p_bits_(bit_vector),
- bit_storage_(bit_vector->GetRawStorage()),
- bit_index_(0),
- bit_size_(p_bits_->storage_size_ * sizeof(uint32_t) * 8) {}
-
- // Return the position of the next set bit. -1 means end-of-element reached.
- int32_t Next() {
- // Did anything obviously change since we started?
- DCHECK_EQ(bit_size_, p_bits_->GetStorageSize() * sizeof(uint32_t) * 8);
- DCHECK_EQ(bit_storage_, p_bits_->GetRawStorage());
-
- if (UNLIKELY(bit_index_ >= bit_size_)) {
- return -1;
- }
-
- uint32_t word_index = bit_index_ / 32;
- uint32_t word = bit_storage_[word_index];
- // Mask out any bits in the first word we've already considered.
- word >>= bit_index_ & 0x1f;
- if (word == 0) {
- bit_index_ &= ~0x1f;
- do {
- word_index++;
- if (UNLIKELY((word_index * 32) >= bit_size_)) {
- bit_index_ = bit_size_;
- return -1;
- }
- word = bit_storage_[word_index];
- bit_index_ += 32;
- } while (word == 0);
- }
- bit_index_ += CTZ(word) + 1;
- return bit_index_ - 1;
+ bool operator==(const IndexIterator& other) const {
+ DCHECK(bit_storage_ == other.bit_storage_);
+ DCHECK_EQ(storage_size_, other.storage_size_);
+ return bit_index_ == other.bit_index_;
}
- static void* operator new(size_t size, Allocator* allocator) {
- return allocator->Alloc(sizeof(BitVector::Iterator));
- };
- static void operator delete(void* p) {
- Iterator* it = reinterpret_cast<Iterator*>(p);
- it->p_bits_->allocator_->Free(p);
+ bool operator!=(const IndexIterator& other) const {
+ return !(*this == other);
+ }
+
+ int operator*() const {
+ DCHECK_LT(bit_index_, BitSize());
+ return bit_index_;
+ }
+
+ IndexIterator& operator++() {
+ DCHECK_LT(bit_index_, BitSize());
+ bit_index_ = FindIndex(bit_index_ + 1u);
+ return *this;
+ }
+
+ IndexIterator operator++(int) {
+ IndexIterator result(*this);
+ ++*this;
+ return result;
+ }
+
+ // Helper function to check for end without comparing with bit_vector.Indexes().end().
+ bool Done() const {
+ return bit_index_ == BitSize();
}
private:
- const BitVector* const p_bits_;
- const uint32_t* const bit_storage_;
- uint32_t bit_index_; // Current index (size in bits).
- const uint32_t bit_size_; // Size of vector in bits.
+ struct begin_tag { };
+ struct end_tag { };
- friend class BitVector;
+ IndexIterator(const BitVector* bit_vector, begin_tag)
+ : bit_storage_(bit_vector->GetRawStorage()),
+ storage_size_(bit_vector->storage_size_),
+ bit_index_(FindIndex(0u)) { }
+
+ IndexIterator(const BitVector* bit_vector, end_tag)
+ : bit_storage_(bit_vector->GetRawStorage()),
+ storage_size_(bit_vector->storage_size_),
+ bit_index_(BitSize()) { }
+
+ uint32_t BitSize() const {
+ return storage_size_ * kWordBits;
+ }
+
+ uint32_t FindIndex(uint32_t start_index) const {
+ DCHECK_LE(start_index, BitSize());
+ uint32_t word_index = start_index / kWordBits;
+ if (UNLIKELY(word_index == storage_size_)) {
+ return start_index;
+ }
+ uint32_t word = bit_storage_[word_index];
+ // Mask out any bits in the first word we've already considered.
+ word &= static_cast<uint32_t>(-1) << (start_index & 0x1f);
+ while (word == 0u) {
+ ++word_index;
+ if (UNLIKELY(word_index == storage_size_)) {
+ return BitSize();
+ }
+ word = bit_storage_[word_index];
+ }
+ return word_index * 32u + CTZ(word);
+ }
+
+ const uint32_t* const bit_storage_;
+ const uint32_t storage_size_; // Size of vector in words.
+ uint32_t bit_index_; // Current index (size in bits).
+
+ friend class BitVector::IndexContainer;
+ };
+
+ /**
+ * @brief BitVector wrapper class for iteration across indexes of set bits.
+ */
+ class IndexContainer {
+ public:
+ explicit IndexContainer(const BitVector* bit_vector) : bit_vector_(bit_vector) { }
+
+ IndexIterator begin() const {
+ return IndexIterator(bit_vector_, IndexIterator::begin_tag());
+ }
+
+ IndexIterator end() const {
+ return IndexIterator(bit_vector_, IndexIterator::end_tag());
+ }
+
+ private:
+ const BitVector* const bit_vector_;
};
BitVector(uint32_t start_bits,
@@ -127,14 +183,16 @@
// Number of bits set in range [0, end).
uint32_t NumSetBits(uint32_t end) const;
- Iterator* GetIterator() const;
+ IndexContainer Indexes() const {
+ return IndexContainer(this);
+ }
uint32_t GetStorageSize() const { return storage_size_; }
bool IsExpandable() const { return expandable_; }
uint32_t GetRawStorageWord(size_t idx) const { return storage_[idx]; }
uint32_t* GetRawStorage() { return storage_; }
const uint32_t* GetRawStorage() const { return storage_; }
- size_t GetSizeOf() const { return storage_size_ * sizeof(uint32_t); }
+ size_t GetSizeOf() const { return storage_size_ * kWordBytes; }
/**
* @return the highest bit set, -1 if none are set
@@ -149,12 +207,42 @@
bool EnsureSizeAndClear(unsigned int num);
void Dump(std::ostream& os, const char* prefix) const;
+
+ /**
+ * @brief last_entry is this the last entry for the dot dumping
+ * @details if not, a "|" is appended to the dump.
+ */
void DumpDot(FILE* file, const char* prefix, bool last_entry = false) const;
+ /**
+ * @brief last_entry is this the last entry for the dot dumping
+ * @details if not, a "|" is appended to the dump.
+ */
+ void DumpIndicesDot(FILE* file, const char* prefix, bool last_entry = false) const;
+
protected:
- void DumpHelper(std::ostringstream& buffer, const char* prefix) const;
+ /**
+ * @brief Dump the bitvector into buffer in a 00101..01 format.
+ * @param buffer the ostringstream used to dump the bitvector into.
+ */
+ void DumpHelper(const char* prefix, std::ostringstream& buffer) const;
+
+ /**
+ * @brief Dump the bitvector in a 1 2 5 8 format, where the numbers are the bit set.
+ * @param buffer the ostringstream used to dump the bitvector into.
+ */
+ void DumpIndicesHelper(const char* prefix, std::ostringstream& buffer) const;
+
+ /**
+ * @brief Wrapper to perform the bitvector dumping with the .dot format.
+ * @param buffer the ostringstream used to dump the bitvector into.
+ */
+ void DumpDotHelper(bool last_entry, FILE* file, std::ostringstream& buffer) const;
private:
+ static constexpr uint32_t kWordBytes = sizeof(uint32_t);
+ static constexpr uint32_t kWordBits = kWordBytes * 8;
+
Allocator* const allocator_;
const bool expandable_; // expand bitmap if we run out?
uint32_t storage_size_; // current size, in 32-bit words.
diff --git a/runtime/base/bit_vector_test.cc b/runtime/base/bit_vector_test.cc
index 0f866a4..1403f50 100644
--- a/runtime/base/bit_vector_test.cc
+++ b/runtime/base/bit_vector_test.cc
@@ -38,11 +38,8 @@
EXPECT_EQ(0U, bv.GetRawStorageWord(0));
EXPECT_EQ(0U, *bv.GetRawStorage());
- BitVector::Iterator empty_iterator(&bv);
- EXPECT_EQ(-1, empty_iterator.Next());
-
- std::unique_ptr<BitVector::Iterator> empty_iterator_on_heap(bv.GetIterator());
- EXPECT_EQ(-1, empty_iterator_on_heap->Next());
+ EXPECT_TRUE(bv.Indexes().begin().Done());
+ EXPECT_TRUE(bv.Indexes().begin() == bv.Indexes().end());
bv.SetBit(0);
bv.SetBit(kBits - 1);
@@ -57,10 +54,14 @@
EXPECT_EQ(0x80000001U, bv.GetRawStorageWord(0));
EXPECT_EQ(0x80000001U, *bv.GetRawStorage());
- BitVector::Iterator iterator(&bv);
- EXPECT_EQ(0, iterator.Next());
- EXPECT_EQ(static_cast<int>(kBits - 1), iterator.Next());
- EXPECT_EQ(-1, iterator.Next());
+ BitVector::IndexIterator iterator = bv.Indexes().begin();
+ EXPECT_TRUE(iterator != bv.Indexes().end());
+ EXPECT_EQ(0, *iterator);
+ ++iterator;
+ EXPECT_TRUE(iterator != bv.Indexes().end());
+ EXPECT_EQ(static_cast<int>(kBits - 1), *iterator);
+ ++iterator;
+ EXPECT_TRUE(iterator == bv.Indexes().end());
}
TEST(BitVector, NoopAllocator) {
diff --git a/runtime/base/mutex-inl.h b/runtime/base/mutex-inl.h
index 6c415e7..a9472f7 100644
--- a/runtime/base/mutex-inl.h
+++ b/runtime/base/mutex-inl.h
@@ -146,7 +146,7 @@
// Ignore logging which may or may not have set up thread data structures.
level == kLoggingLock ||
// Avoid recursive death.
- level == kAbortLock);
+ level == kAbortLock) << level;
}
}
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index ac86014..84afb2d 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -34,9 +34,7 @@
}
inline mirror::Class* ClassLinker::FindSystemClass(Thread* self, const char* descriptor) {
- StackHandleScope<1> hs(self);
- auto class_loader = hs.NewHandle<mirror::ClassLoader>(nullptr);
- return FindClass(self, descriptor, class_loader);
+ return FindClass(self, descriptor, NullHandle<mirror::ClassLoader>());
}
inline mirror::Class* ClassLinker::FindArrayClass(Thread* self, mirror::Class* element_class) {
@@ -110,31 +108,47 @@
return resolved_type;
}
-inline mirror::ArtMethod* ClassLinker::ResolveMethod(uint32_t method_idx,
- mirror::ArtMethod* referrer,
- InvokeType type) {
+inline mirror::ArtMethod* ClassLinker::GetResolvedMethod(uint32_t method_idx,
+ mirror::ArtMethod* referrer,
+ InvokeType type) {
mirror::ArtMethod* resolved_method =
referrer->GetDexCacheResolvedMethods()->Get(method_idx);
- if (UNLIKELY(resolved_method == NULL || resolved_method->IsRuntimeMethod())) {
- mirror::Class* declaring_class = referrer->GetDeclaringClass();
- StackHandleScope<2> hs(Thread::Current());
- Handle<mirror::DexCache> dex_cache(hs.NewHandle(declaring_class->GetDexCache()));
- Handle<mirror::ClassLoader> class_loader(hs.NewHandle(declaring_class->GetClassLoader()));
- const DexFile& dex_file = *dex_cache->GetDexFile();
- resolved_method = ResolveMethod(dex_file, method_idx, dex_cache, class_loader, referrer, type);
- if (resolved_method != nullptr) {
- DCHECK_EQ(dex_cache->GetResolvedMethod(method_idx), resolved_method);
- }
+ if (resolved_method == nullptr || resolved_method->IsRuntimeMethod()) {
+ return nullptr;
}
return resolved_method;
}
-inline mirror::ArtField* ClassLinker::ResolveField(uint32_t field_idx,
- mirror::ArtMethod* referrer,
+inline mirror::ArtMethod* ClassLinker::ResolveMethod(Thread* self, uint32_t method_idx,
+ mirror::ArtMethod** referrer,
+ InvokeType type) {
+ mirror::ArtMethod* resolved_method = GetResolvedMethod(method_idx, *referrer, type);
+ if (LIKELY(resolved_method != nullptr)) {
+ return resolved_method;
+ }
+ mirror::Class* declaring_class = (*referrer)->GetDeclaringClass();
+ StackHandleScope<3> hs(self);
+ Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(declaring_class->GetDexCache()));
+ Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(declaring_class->GetClassLoader()));
+ HandleWrapper<mirror::ArtMethod> h_referrer(hs.NewHandleWrapper(referrer));
+ const DexFile* dex_file = h_dex_cache->GetDexFile();
+ resolved_method = ResolveMethod(*dex_file, method_idx, h_dex_cache, h_class_loader, h_referrer,
+ type);
+ if (resolved_method != nullptr) {
+ DCHECK_EQ(h_dex_cache->GetResolvedMethod(method_idx), resolved_method);
+ }
+ return resolved_method;
+}
+
+inline mirror::ArtField* ClassLinker::GetResolvedField(uint32_t field_idx,
+ mirror::Class* field_declaring_class) {
+ return field_declaring_class->GetDexCache()->GetResolvedField(field_idx);
+}
+
+inline mirror::ArtField* ClassLinker::ResolveField(uint32_t field_idx, mirror::ArtMethod* referrer,
bool is_static) {
mirror::Class* declaring_class = referrer->GetDeclaringClass();
- mirror::ArtField* resolved_field =
- declaring_class->GetDexCache()->GetResolvedField(field_idx);
+ mirror::ArtField* resolved_field = GetResolvedField(field_idx, declaring_class);
if (UNLIKELY(resolved_field == NULL)) {
StackHandleScope<2> hs(Thread::Current());
Handle<mirror::DexCache> dex_cache(hs.NewHandle(declaring_class->GetDexCache()));
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index c7302b5..afff7a2 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1369,7 +1369,7 @@
}
mirror::Class* ClassLinker::FindClass(Thread* self, const char* descriptor,
- const Handle<mirror::ClassLoader>& class_loader) {
+ Handle<mirror::ClassLoader> class_loader) {
DCHECK_NE(*descriptor, '\0') << "descriptor is empty string";
DCHECK(self != nullptr);
self->AssertNoPendingException();
@@ -1390,8 +1390,7 @@
DexFile::ClassPathEntry pair = DexFile::FindInClassPath(descriptor, boot_class_path_);
if (pair.second != NULL) {
StackHandleScope<1> hs(self);
- auto class_loader = hs.NewHandle<mirror::ClassLoader>(nullptr);
- return DefineClass(descriptor, class_loader, *pair.first, *pair.second);
+ return DefineClass(descriptor, NullHandle<mirror::ClassLoader>(), *pair.first, *pair.second);
}
} else if (Runtime::Current()->UseCompileTimeClassPath()) {
// First try the boot class path, we check the descriptor first to avoid an unnecessary
@@ -1452,7 +1451,7 @@
}
mirror::Class* ClassLinker::DefineClass(const char* descriptor,
- const Handle<mirror::ClassLoader>& class_loader,
+ Handle<mirror::ClassLoader> class_loader,
const DexFile& dex_file,
const DexFile::ClassDef& dex_class_def) {
Thread* self = Thread::Current();
@@ -1796,10 +1795,9 @@
// Ignore virtual methods on the iterator.
}
-void ClassLinker::LinkCode(const Handle<mirror::ArtMethod>& method,
- const OatFile::OatClass* oat_class,
+void ClassLinker::LinkCode(Handle<mirror::ArtMethod> method, const OatFile::OatClass* oat_class,
const DexFile& dex_file, uint32_t dex_method_index,
- uint32_t method_index) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ uint32_t method_index) {
// Method shouldn't have already been linked.
DCHECK(method->GetEntryPointFromQuickCompiledCode() == nullptr);
DCHECK(method->GetEntryPointFromPortableCompiledCode() == nullptr);
@@ -1871,7 +1869,7 @@
void ClassLinker::LoadClass(const DexFile& dex_file,
const DexFile::ClassDef& dex_class_def,
- const Handle<mirror::Class>& klass,
+ Handle<mirror::Class> klass,
mirror::ClassLoader* class_loader) {
CHECK(klass.Get() != NULL);
CHECK(klass->GetDexCache() != NULL);
@@ -1909,7 +1907,7 @@
void ClassLinker::LoadClassMembers(const DexFile& dex_file,
const byte* class_data,
- const Handle<mirror::Class>& klass,
+ Handle<mirror::Class> klass,
mirror::ClassLoader* class_loader,
const OatFile::OatClass* oat_class) {
// Load fields.
@@ -2007,8 +2005,7 @@
}
void ClassLinker::LoadField(const DexFile& /*dex_file*/, const ClassDataItemIterator& it,
- const Handle<mirror::Class>& klass,
- const Handle<mirror::ArtField>& dst) {
+ Handle<mirror::Class> klass, Handle<mirror::ArtField> dst) {
uint32_t field_idx = it.GetMemberIndex();
dst->SetDexFieldIndex(field_idx);
dst->SetDeclaringClass(klass.Get());
@@ -2017,7 +2014,7 @@
mirror::ArtMethod* ClassLinker::LoadMethod(Thread* self, const DexFile& dex_file,
const ClassDataItemIterator& it,
- const Handle<mirror::Class>& klass) {
+ Handle<mirror::Class> klass) {
uint32_t dex_method_idx = it.GetMemberIndex();
const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx);
const char* method_name = dex_file.StringDataByIdx(method_id.name_idx_);
@@ -2088,7 +2085,7 @@
}
void ClassLinker::AppendToBootClassPath(const DexFile& dex_file,
- const Handle<mirror::DexCache>& dex_cache) {
+ Handle<mirror::DexCache> dex_cache) {
CHECK(dex_cache.Get() != NULL) << dex_file.GetLocation();
boot_class_path_.push_back(&dex_file);
RegisterDexFile(dex_file, dex_cache);
@@ -2110,7 +2107,7 @@
}
void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file,
- const Handle<mirror::DexCache>& dex_cache) {
+ Handle<mirror::DexCache> dex_cache) {
dex_lock_.AssertExclusiveHeld(Thread::Current());
CHECK(dex_cache.Get() != NULL) << dex_file.GetLocation();
CHECK(dex_cache->GetLocation()->Equals(dex_file.GetLocation()))
@@ -2147,7 +2144,7 @@
}
void ClassLinker::RegisterDexFile(const DexFile& dex_file,
- const Handle<mirror::DexCache>& dex_cache) {
+ Handle<mirror::DexCache> dex_cache) {
WriterMutexLock mu(Thread::Current(), dex_lock_);
RegisterDexFileLocked(dex_file, dex_cache);
}
@@ -2224,7 +2221,7 @@
//
// Returns NULL with an exception raised on failure.
mirror::Class* ClassLinker::CreateArrayClass(Thread* self, const char* descriptor,
- const Handle<mirror::ClassLoader>& class_loader) {
+ Handle<mirror::ClassLoader> class_loader) {
// Identify the underlying component type
CHECK_EQ('[', descriptor[0]);
StackHandleScope<2> hs(self);
@@ -2416,7 +2413,7 @@
it != end && it->first == hash;
++it) {
mirror::Class* klass = it->second;
- if (klass->GetClassLoader() == class_loader && descriptor == klass->GetDescriptor()) {
+ if (klass->GetClassLoader() == class_loader && klass->DescriptorEquals(descriptor)) {
class_table_.erase(it);
return true;
}
@@ -2460,13 +2457,13 @@
auto end = class_table_.end();
for (auto it = class_table_.lower_bound(hash); it != end && it->first == hash; ++it) {
mirror::Class* klass = it->second;
- if (klass->GetClassLoader() == class_loader && descriptor == klass->GetDescriptor()) {
+ if (klass->GetClassLoader() == class_loader && klass->DescriptorEquals(descriptor)) {
if (kIsDebugBuild) {
// Check for duplicates in the table.
for (++it; it != end && it->first == hash; ++it) {
mirror::Class* klass2 = it->second;
- CHECK(!((klass2->GetClassLoader() == class_loader) &&
- descriptor == klass2->GetDescriptor()))
+ CHECK(!(klass2->GetClassLoader() == class_loader &&
+ klass2->DescriptorEquals(descriptor)))
<< PrettyClass(klass) << " " << klass << " " << klass->GetClassLoader() << " "
<< PrettyClass(klass2) << " " << klass2 << " " << klass2->GetClassLoader();
}
@@ -2557,13 +2554,13 @@
for (auto it = class_table_.lower_bound(hash), end = class_table_.end();
it != end && it->first == hash; ++it) {
mirror::Class* klass = it->second;
- if (descriptor == klass->GetDescriptor()) {
+ if (klass->DescriptorEquals(descriptor)) {
result.push_back(klass);
}
}
}
-void ClassLinker::VerifyClass(const Handle<mirror::Class>& klass) {
+void ClassLinker::VerifyClass(Handle<mirror::Class> klass) {
// TODO: assert that the monitor on the Class is held
Thread* self = Thread::Current();
ObjectLock<mirror::Class> lock(self, klass);
@@ -2776,7 +2773,7 @@
}
void ClassLinker::ResolveClassExceptionHandlerTypes(const DexFile& dex_file,
- const Handle<mirror::Class>& klass) {
+ Handle<mirror::Class> klass) {
for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
ResolveMethodExceptionHandlerTypes(dex_file, klass->GetDirectMethod(i));
}
@@ -2817,7 +2814,7 @@
static void CheckProxyConstructor(mirror::ArtMethod* constructor);
static void CheckProxyMethod(mirror::ArtMethod* method,
- Handle<mirror::ArtMethod>& prototype);
+ Handle<mirror::ArtMethod> prototype);
mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& soa, jstring name,
jobjectArray interfaces, jobject loader,
@@ -2999,7 +2996,7 @@
mirror::ArtMethod* ClassLinker::CreateProxyConstructor(Thread* self,
- const Handle<mirror::Class>& klass,
+ Handle<mirror::Class> klass,
mirror::Class* proxy_class) {
// Create constructor for Proxy that must initialize h
mirror::ObjectArray<mirror::ArtMethod>* proxy_direct_methods =
@@ -3030,8 +3027,8 @@
}
mirror::ArtMethod* ClassLinker::CreateProxyMethod(Thread* self,
- const Handle<mirror::Class>& klass,
- const Handle<mirror::ArtMethod>& prototype) {
+ Handle<mirror::Class> klass,
+ Handle<mirror::ArtMethod> prototype) {
// Ensure prototype is in dex cache so that we can use the dex cache to look up the overridden
// prototype method
prototype->GetDeclaringClass()->GetDexCache()->SetResolvedMethod(prototype->GetDexMethodIndex(),
@@ -3058,8 +3055,7 @@
return method;
}
-static void CheckProxyMethod(mirror::ArtMethod* method,
- Handle<mirror::ArtMethod>& prototype)
+static void CheckProxyMethod(mirror::ArtMethod* method, Handle<mirror::ArtMethod> prototype)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
// Basic sanity
CHECK(!prototype->IsFinal());
@@ -3119,7 +3115,7 @@
return init_done_;
}
-bool ClassLinker::InitializeClass(const Handle<mirror::Class>& klass, bool can_init_statics,
+bool ClassLinker::InitializeClass(Handle<mirror::Class> klass, bool can_init_statics,
bool can_init_parents) {
// see JLS 3rd edition, 12.4.2 "Detailed Initialization Procedure" for the locking protocol
@@ -3286,7 +3282,7 @@
return success;
}
-bool ClassLinker::WaitForInitializeClass(const Handle<mirror::Class>& klass, Thread* self,
+bool ClassLinker::WaitForInitializeClass(Handle<mirror::Class> klass, Thread* self,
ObjectLock<mirror::Class>& lock)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
while (true) {
@@ -3326,7 +3322,7 @@
LOG(FATAL) << "Not Reached" << PrettyClass(klass.Get());
}
-bool ClassLinker::ValidateSuperClassDescriptors(const Handle<mirror::Class>& klass) {
+bool ClassLinker::ValidateSuperClassDescriptors(Handle<mirror::Class> klass) {
if (klass->IsInterface()) {
return true;
}
@@ -3368,18 +3364,12 @@
return true;
}
-bool ClassLinker::EnsureInitialized(const Handle<mirror::Class>& c, bool can_init_fields,
+bool ClassLinker::EnsureInitialized(Handle<mirror::Class> c, bool can_init_fields,
bool can_init_parents) {
- DCHECK(c.Get() != NULL);
- if (c->IsInitialized()) {
- return true;
- }
-
- bool success = InitializeClass(c, can_init_fields, can_init_parents);
- if (!success) {
- if (can_init_fields && can_init_parents) {
- CHECK(Thread::Current()->IsExceptionPending()) << PrettyClass(c.Get());
- }
+ DCHECK(c.Get() != nullptr);
+ const bool success = c->IsInitialized() || InitializeClass(c, can_init_fields, can_init_parents);
+ if (!success && can_init_fields && can_init_parents) {
+ CHECK(Thread::Current()->IsExceptionPending()) << PrettyClass(c.Get());
}
return success;
}
@@ -3398,8 +3388,8 @@
}
}
-bool ClassLinker::LinkClass(Thread* self, const Handle<mirror::Class>& klass,
- const Handle<mirror::ObjectArray<mirror::Class>>& interfaces) {
+bool ClassLinker::LinkClass(Thread* self, Handle<mirror::Class> klass,
+ Handle<mirror::ObjectArray<mirror::Class>> interfaces) {
CHECK_EQ(mirror::Class::kStatusLoaded, klass->GetStatus());
if (!LinkSuperClass(klass)) {
return false;
@@ -3420,8 +3410,7 @@
return true;
}
-bool ClassLinker::LoadSuperAndInterfaces(const Handle<mirror::Class>& klass,
- const DexFile& dex_file) {
+bool ClassLinker::LoadSuperAndInterfaces(Handle<mirror::Class> klass, const DexFile& dex_file) {
CHECK_EQ(mirror::Class::kStatusIdx, klass->GetStatus());
const DexFile::ClassDef& class_def = dex_file.GetClassDef(klass->GetDexClassDefIndex());
uint16_t super_class_idx = class_def.superclass_idx_;
@@ -3464,7 +3453,7 @@
return true;
}
-bool ClassLinker::LinkSuperClass(const Handle<mirror::Class>& klass) {
+bool ClassLinker::LinkSuperClass(Handle<mirror::Class> klass) {
CHECK(!klass->IsPrimitive());
mirror::Class* super = klass->GetSuperClass();
if (klass.Get() == GetClassRoot(kJavaLangObject)) {
@@ -3524,8 +3513,8 @@
}
// Populate the class vtable and itable. Compute return type indices.
-bool ClassLinker::LinkMethods(const Handle<mirror::Class>& klass,
- const Handle<mirror::ObjectArray<mirror::Class>>& interfaces) {
+bool ClassLinker::LinkMethods(Handle<mirror::Class> klass,
+ Handle<mirror::ObjectArray<mirror::Class>> interfaces) {
if (klass->IsInterface()) {
// No vtable.
size_t count = klass->NumVirtualMethods();
@@ -3545,7 +3534,7 @@
return true;
}
-bool ClassLinker::LinkVirtualMethods(const Handle<mirror::Class>& klass) {
+bool ClassLinker::LinkVirtualMethods(Handle<mirror::Class> klass) {
Thread* self = Thread::Current();
if (klass->HasSuperClass()) {
uint32_t max_count = (klass->NumVirtualMethods() +
@@ -3632,9 +3621,8 @@
return true;
}
-bool ClassLinker::LinkInterfaceMethods(
- const Handle<mirror::Class>& klass,
- const Handle<mirror::ObjectArray<mirror::Class>>& interfaces) {
+bool ClassLinker::LinkInterfaceMethods(Handle<mirror::Class> klass,
+ Handle<mirror::ObjectArray<mirror::Class>> interfaces) {
Thread* const self = Thread::Current();
// Set the imt table to be all conflicts by default.
klass->SetImTable(Runtime::Current()->GetDefaultImt());
@@ -3889,12 +3877,12 @@
return true;
}
-bool ClassLinker::LinkInstanceFields(const Handle<mirror::Class>& klass) {
+bool ClassLinker::LinkInstanceFields(Handle<mirror::Class> klass) {
CHECK(klass.Get() != NULL);
return LinkFields(klass, false);
}
-bool ClassLinker::LinkStaticFields(const Handle<mirror::Class>& klass) {
+bool ClassLinker::LinkStaticFields(Handle<mirror::Class> klass) {
CHECK(klass.Get() != NULL);
size_t allocated_class_size = klass->GetClassSize();
bool success = LinkFields(klass, true);
@@ -3933,7 +3921,7 @@
}
};
-bool ClassLinker::LinkFields(const Handle<mirror::Class>& klass, bool is_static) {
+bool ClassLinker::LinkFields(Handle<mirror::Class> klass, bool is_static) {
size_t num_fields =
is_static ? klass->NumStaticFields() : klass->NumInstanceFields();
@@ -4029,7 +4017,7 @@
}
// We lie to the GC about the java.lang.ref.Reference.referent field, so it doesn't scan it.
- if (!is_static && "Ljava/lang/ref/Reference;" == klass->GetDescriptor()) {
+ if (!is_static && klass->DescriptorEquals("Ljava/lang/ref/Reference;")) {
// We know there are no non-reference fields in the Reference classes, and we know
// that 'referent' is alphabetically last, so this is easy...
CHECK_EQ(num_reference_fields, num_fields) << PrettyClass(klass.Get());
@@ -4054,7 +4042,7 @@
FieldHelper fh(field);
Primitive::Type type = fh.GetTypeAsPrimitiveType();
bool is_primitive = type != Primitive::kPrimNot;
- if ("Ljava/lang/ref/Reference;" == klass->GetDescriptor() &&
+ if (klass->DescriptorEquals("Ljava/lang/ref/Reference;") &&
strcmp("referent", fh.GetName()) == 0) {
is_primitive = true; // We lied above, so we have to expect a lie here.
}
@@ -4093,7 +4081,7 @@
// Set the bitmap of reference offsets, refOffsets, from the ifields
// list.
-void ClassLinker::CreateReferenceInstanceOffsets(const Handle<mirror::Class>& klass) {
+void ClassLinker::CreateReferenceInstanceOffsets(Handle<mirror::Class> klass) {
uint32_t reference_offsets = 0;
mirror::Class* super_class = klass->GetSuperClass();
if (super_class != NULL) {
@@ -4107,11 +4095,11 @@
CreateReferenceOffsets(klass, false, reference_offsets);
}
-void ClassLinker::CreateReferenceStaticOffsets(const Handle<mirror::Class>& klass) {
+void ClassLinker::CreateReferenceStaticOffsets(Handle<mirror::Class> klass) {
CreateReferenceOffsets(klass, true, 0);
}
-void ClassLinker::CreateReferenceOffsets(const Handle<mirror::Class>& klass, bool is_static,
+void ClassLinker::CreateReferenceOffsets(Handle<mirror::Class> klass, bool is_static,
uint32_t reference_offsets) {
size_t num_reference_fields =
is_static ? klass->NumReferenceStaticFieldsDuringLinking()
@@ -4144,7 +4132,7 @@
}
mirror::String* ClassLinker::ResolveString(const DexFile& dex_file, uint32_t string_idx,
- const Handle<mirror::DexCache>& dex_cache) {
+ Handle<mirror::DexCache> dex_cache) {
DCHECK(dex_cache.Get() != nullptr);
mirror::String* resolved = dex_cache->GetResolvedString(string_idx);
if (resolved != NULL) {
@@ -4166,8 +4154,8 @@
}
mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, uint16_t type_idx,
- const Handle<mirror::DexCache>& dex_cache,
- const Handle<mirror::ClassLoader>& class_loader) {
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader) {
DCHECK(dex_cache.Get() != NULL);
mirror::Class* resolved = dex_cache->GetResolvedType(type_idx);
if (resolved == NULL) {
@@ -4198,16 +4186,15 @@
return resolved;
}
-mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file,
- uint32_t method_idx,
- const Handle<mirror::DexCache>& dex_cache,
- const Handle<mirror::ClassLoader>& class_loader,
- mirror::ArtMethod* referrer,
+mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, uint32_t method_idx,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader,
+ Handle<mirror::ArtMethod> referrer,
InvokeType type) {
DCHECK(dex_cache.Get() != NULL);
// Check for hit in the dex cache.
mirror::ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx);
- if (resolved != NULL && !resolved->IsRuntimeMethod()) {
+ if (resolved != nullptr && !resolved->IsRuntimeMethod()) {
return resolved;
}
// Fail, get the declaring class.
@@ -4282,7 +4269,7 @@
}
// If we found something, check that it can be accessed by the referrer.
- if (resolved != NULL && referrer != NULL) {
+ if (resolved != NULL && referrer.Get() != NULL) {
mirror::Class* methods_class = resolved->GetDeclaringClass();
mirror::Class* referring_class = referrer->GetDeclaringClass();
if (!referring_class->CanAccess(methods_class)) {
@@ -4302,11 +4289,11 @@
case kDirect:
case kStatic:
if (resolved != NULL) {
- ThrowIncompatibleClassChangeError(type, kVirtual, resolved, referrer);
+ ThrowIncompatibleClassChangeError(type, kVirtual, resolved, referrer.Get());
} else {
resolved = klass->FindInterfaceMethod(name, signature);
if (resolved != NULL) {
- ThrowIncompatibleClassChangeError(type, kInterface, resolved, referrer);
+ ThrowIncompatibleClassChangeError(type, kInterface, resolved, referrer.Get());
} else {
ThrowNoSuchMethodError(type, klass, name, signature);
}
@@ -4314,11 +4301,11 @@
break;
case kInterface:
if (resolved != NULL) {
- ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer);
+ ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer.Get());
} else {
resolved = klass->FindVirtualMethod(name, signature);
if (resolved != NULL) {
- ThrowIncompatibleClassChangeError(type, kVirtual, resolved, referrer);
+ ThrowIncompatibleClassChangeError(type, kVirtual, resolved, referrer.Get());
} else {
ThrowNoSuchMethodError(type, klass, name, signature);
}
@@ -4329,11 +4316,11 @@
break;
case kVirtual:
if (resolved != NULL) {
- ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer);
+ ThrowIncompatibleClassChangeError(type, kDirect, resolved, referrer.Get());
} else {
resolved = klass->FindInterfaceMethod(name, signature);
if (resolved != NULL) {
- ThrowIncompatibleClassChangeError(type, kInterface, resolved, referrer);
+ ThrowIncompatibleClassChangeError(type, kInterface, resolved, referrer.Get());
} else {
ThrowNoSuchMethodError(type, klass, name, signature);
}
@@ -4346,8 +4333,8 @@
}
mirror::ArtField* ClassLinker::ResolveField(const DexFile& dex_file, uint32_t field_idx,
- const Handle<mirror::DexCache>& dex_cache,
- const Handle<mirror::ClassLoader>& class_loader,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader,
bool is_static) {
DCHECK(dex_cache.Get() != nullptr);
mirror::ArtField* resolved = dex_cache->GetResolvedField(field_idx);
@@ -4389,8 +4376,8 @@
mirror::ArtField* ClassLinker::ResolveFieldJLS(const DexFile& dex_file,
uint32_t field_idx,
- const Handle<mirror::DexCache>& dex_cache,
- const Handle<mirror::ClassLoader>& class_loader) {
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader) {
DCHECK(dex_cache.Get() != nullptr);
mirror::ArtField* resolved = dex_cache->GetResolvedField(field_idx);
if (resolved != NULL) {
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 54805be..a8271ed 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -75,7 +75,7 @@
// Finds a class by its descriptor, loading it if necessary.
// If class_loader is null, searches boot_class_path_.
mirror::Class* FindClass(Thread* self, const char* descriptor,
- const Handle<mirror::ClassLoader>& class_loader)
+ Handle<mirror::ClassLoader> class_loader)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Finds a class by its descriptor using the "system" class loader, ie by searching the
@@ -92,7 +92,7 @@
// Define a new a class based on a ClassDef from a DexFile
mirror::Class* DefineClass(const char* descriptor,
- const Handle<mirror::ClassLoader>& class_loader,
+ Handle<mirror::ClassLoader> class_loader,
const DexFile& dex_file, const DexFile::ClassDef& dex_class_def)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -136,7 +136,7 @@
// Resolve a String with the given index from the DexFile, storing the
// result in the DexCache.
mirror::String* ResolveString(const DexFile& dex_file, uint32_t string_idx,
- const Handle<mirror::DexCache>& dex_cache)
+ Handle<mirror::DexCache> dex_cache)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Resolve a Type with the given index from the DexFile, storing the
@@ -159,8 +159,8 @@
// type, since it may be referenced from but not contained within
// the given DexFile.
mirror::Class* ResolveType(const DexFile& dex_file, uint16_t type_idx,
- const Handle<mirror::DexCache>& dex_cache,
- const Handle<mirror::ClassLoader>& class_loader)
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Resolve a method with a given ID from the DexFile, storing the
@@ -170,16 +170,21 @@
// virtual method.
mirror::ArtMethod* ResolveMethod(const DexFile& dex_file,
uint32_t method_idx,
- const Handle<mirror::DexCache>& dex_cache,
- const Handle<mirror::ClassLoader>& class_loader,
- mirror::ArtMethod* referrer,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader,
+ Handle<mirror::ArtMethod> referrer,
InvokeType type)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- mirror::ArtMethod* ResolveMethod(uint32_t method_idx, mirror::ArtMethod* referrer,
+ mirror::ArtMethod* GetResolvedMethod(uint32_t method_idx, mirror::ArtMethod* referrer,
+ InvokeType type)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ mirror::ArtMethod* ResolveMethod(Thread* self, uint32_t method_idx, mirror::ArtMethod** referrer,
InvokeType type)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ mirror::ArtField* GetResolvedField(uint32_t field_idx, mirror::Class* field_declaring_class)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
mirror::ArtField* ResolveField(uint32_t field_idx, mirror::ArtMethod* referrer,
bool is_static)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -191,8 +196,8 @@
// field.
mirror::ArtField* ResolveField(const DexFile& dex_file,
uint32_t field_idx,
- const Handle<mirror::DexCache>& dex_cache,
- const Handle<mirror::ClassLoader>& class_loader,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader,
bool is_static)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -200,10 +205,9 @@
// result in DexCache. The ClassLinker and ClassLoader are used as
// in ResolveType. No is_static argument is provided so that Java
// field resolution semantics are followed.
- mirror::ArtField* ResolveFieldJLS(const DexFile& dex_file,
- uint32_t field_idx,
- const Handle<mirror::DexCache>& dex_cache,
- const Handle<mirror::ClassLoader>& class_loader)
+ mirror::ArtField* ResolveFieldJLS(const DexFile& dex_file, uint32_t field_idx,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Get shorty from method index without resolution. Used to do handlerization.
@@ -213,8 +217,7 @@
// Returns true on success, false if there's an exception pending.
// can_run_clinit=false allows the compiler to attempt to init a class,
// given the restriction that no <clinit> execution is possible.
- bool EnsureInitialized(const Handle<mirror::Class>& c,
- bool can_init_fields, bool can_init_parents)
+ bool EnsureInitialized(Handle<mirror::Class> c, bool can_init_fields, bool can_init_parents)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Initializes classes that have instances in the image but that have
@@ -224,7 +227,7 @@
void RegisterDexFile(const DexFile& dex_file)
LOCKS_EXCLUDED(dex_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void RegisterDexFile(const DexFile& dex_file, const Handle<mirror::DexCache>& dex_cache)
+ void RegisterDexFile(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache)
LOCKS_EXCLUDED(dex_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -316,12 +319,12 @@
size_t length)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void VerifyClass(const Handle<mirror::Class>& klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void VerifyClass(Handle<mirror::Class> klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool VerifyClassUsingOatFile(const DexFile& dex_file, mirror::Class* klass,
mirror::Class::Status& oat_file_class_status)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void ResolveClassExceptionHandlerTypes(const DexFile& dex_file,
- const Handle<mirror::Class>& klass)
+ Handle<mirror::Class> klass)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void ResolveMethodExceptionHandlerTypes(const DexFile& dex_file, mirror::ArtMethod* klass)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -420,12 +423,12 @@
mirror::Class* CreateArrayClass(Thread* self, const char* descriptor,
- const Handle<mirror::ClassLoader>& class_loader)
+ Handle<mirror::ClassLoader> class_loader)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void AppendToBootClassPath(const DexFile& dex_file)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void AppendToBootClassPath(const DexFile& dex_file, const Handle<mirror::DexCache>& dex_cache)
+ void AppendToBootClassPath(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void ConstructFieldMap(const DexFile& dex_file, const DexFile::ClassDef& dex_class_def,
@@ -437,23 +440,23 @@
void LoadClass(const DexFile& dex_file,
const DexFile::ClassDef& dex_class_def,
- const Handle<mirror::Class>& klass,
+ Handle<mirror::Class> klass,
mirror::ClassLoader* class_loader)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void LoadClassMembers(const DexFile& dex_file,
const byte* class_data,
- const Handle<mirror::Class>& klass,
+ Handle<mirror::Class> klass,
mirror::ClassLoader* class_loader,
const OatFile::OatClass* oat_class)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void LoadField(const DexFile& dex_file, const ClassDataItemIterator& it,
- const Handle<mirror::Class>& klass, const Handle<mirror::ArtField>& dst)
+ Handle<mirror::Class> klass, Handle<mirror::ArtField> dst)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
mirror::ArtMethod* LoadMethod(Thread* self, const DexFile& dex_file,
const ClassDataItemIterator& dex_method,
- const Handle<mirror::Class>& klass)
+ Handle<mirror::Class> klass)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void FixupStaticTrampolines(mirror::Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -462,23 +465,23 @@
OatFile::OatClass GetOatClass(const DexFile& dex_file, uint16_t class_def_idx)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void RegisterDexFileLocked(const DexFile& dex_file, const Handle<mirror::DexCache>& dex_cache)
+ void RegisterDexFileLocked(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache)
EXCLUSIVE_LOCKS_REQUIRED(dex_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool IsDexFileRegisteredLocked(const DexFile& dex_file) const
SHARED_LOCKS_REQUIRED(dex_lock_, Locks::mutator_lock_);
- bool InitializeClass(const Handle<mirror::Class>& klass, bool can_run_clinit,
+ bool InitializeClass(Handle<mirror::Class> klass, bool can_run_clinit,
bool can_init_parents)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool WaitForInitializeClass(const Handle<mirror::Class>& klass, Thread* self,
+ bool WaitForInitializeClass(Handle<mirror::Class> klass, Thread* self,
ObjectLock<mirror::Class>& lock);
- bool ValidateSuperClassDescriptors(const Handle<mirror::Class>& klass)
+ bool ValidateSuperClassDescriptors(Handle<mirror::Class> klass)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool IsSameDescriptorInDifferentClassContexts(Thread* self, const char* descriptor,
- Handle<mirror::ClassLoader>& class_loader1,
- Handle<mirror::ClassLoader>& class_loader2)
+ Handle<mirror::ClassLoader> class_loader1,
+ Handle<mirror::ClassLoader> class_loader2)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool IsSameMethodSignatureInDifferentClassContexts(Thread* self, mirror::ArtMethod* method,
@@ -486,43 +489,43 @@
mirror::Class* klass2)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool LinkClass(Thread* self, const Handle<mirror::Class>& klass,
- const Handle<mirror::ObjectArray<mirror::Class>>& interfaces)
+ bool LinkClass(Thread* self, Handle<mirror::Class> klass,
+ Handle<mirror::ObjectArray<mirror::Class>> interfaces)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool LinkSuperClass(const Handle<mirror::Class>& klass)
+ bool LinkSuperClass(Handle<mirror::Class> klass)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool LoadSuperAndInterfaces(const Handle<mirror::Class>& klass, const DexFile& dex_file)
+ bool LoadSuperAndInterfaces(Handle<mirror::Class> klass, const DexFile& dex_file)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool LinkMethods(const Handle<mirror::Class>& klass,
- const Handle<mirror::ObjectArray<mirror::Class>>& interfaces)
+ bool LinkMethods(Handle<mirror::Class> klass,
+ Handle<mirror::ObjectArray<mirror::Class>> interfaces)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool LinkVirtualMethods(const Handle<mirror::Class>& klass)
+ bool LinkVirtualMethods(Handle<mirror::Class> klass)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool LinkInterfaceMethods(const Handle<mirror::Class>& klass,
- const Handle<mirror::ObjectArray<mirror::Class>>& interfaces)
+ bool LinkInterfaceMethods(Handle<mirror::Class> klass,
+ Handle<mirror::ObjectArray<mirror::Class>> interfaces)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool LinkStaticFields(const Handle<mirror::Class>& klass)
+ bool LinkStaticFields(Handle<mirror::Class> klass)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool LinkInstanceFields(const Handle<mirror::Class>& klass)
+ bool LinkInstanceFields(Handle<mirror::Class> klass)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- bool LinkFields(const Handle<mirror::Class>& klass, bool is_static)
+ bool LinkFields(Handle<mirror::Class> klass, bool is_static)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void LinkCode(const Handle<mirror::ArtMethod>& method, const OatFile::OatClass* oat_class,
+ void LinkCode(Handle<mirror::ArtMethod> method, const OatFile::OatClass* oat_class,
const DexFile& dex_file, uint32_t dex_method_index, uint32_t method_index)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void CreateReferenceInstanceOffsets(const Handle<mirror::Class>& klass)
+ void CreateReferenceInstanceOffsets(Handle<mirror::Class> klass)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void CreateReferenceStaticOffsets(const Handle<mirror::Class>& klass)
+ void CreateReferenceStaticOffsets(Handle<mirror::Class> klass)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void CreateReferenceOffsets(const Handle<mirror::Class>& klass, bool is_static,
+ void CreateReferenceOffsets(Handle<mirror::Class> klass, bool is_static,
uint32_t reference_offsets)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -551,11 +554,11 @@
bool* open_failed)
LOCKS_EXCLUDED(dex_lock_);
- mirror::ArtMethod* CreateProxyConstructor(Thread* self, const Handle<mirror::Class>& klass,
+ mirror::ArtMethod* CreateProxyConstructor(Thread* self, Handle<mirror::Class> klass,
mirror::Class* proxy_class)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- mirror::ArtMethod* CreateProxyMethod(Thread* self, const Handle<mirror::Class>& klass,
- const Handle<mirror::ArtMethod>& prototype)
+ mirror::ArtMethod* CreateProxyMethod(Thread* self, Handle<mirror::Class> klass,
+ Handle<mirror::ArtMethod> prototype)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
std::vector<const DexFile*> boot_class_path_;
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index d04f02b..c11aecc 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -108,7 +108,7 @@
AssertArrayClass(array_descriptor, array);
}
- void AssertArrayClass(const std::string& array_descriptor, const Handle<mirror::Class>& array)
+ void AssertArrayClass(const std::string& array_descriptor, Handle<mirror::Class> array)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
ASSERT_TRUE(array.Get() != NULL);
ASSERT_TRUE(array->GetClass() != NULL);
@@ -178,7 +178,7 @@
EXPECT_TRUE(fh.GetType() != NULL);
}
- void AssertClass(const std::string& descriptor, const Handle<mirror::Class>& klass)
+ void AssertClass(const std::string& descriptor, Handle<mirror::Class> klass)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
EXPECT_STREQ(descriptor.c_str(), klass->GetDescriptor().c_str());
if (descriptor == "Ljava/lang/Object;") {
@@ -846,8 +846,7 @@
// Validate that the "value" field is always the 0th field in each of java.lang's box classes.
// This lets UnboxPrimitive avoid searching for the field by name at runtime.
ScopedObjectAccess soa(Thread::Current());
- StackHandleScope<1> hs(soa.Self());
- auto class_loader(hs.NewHandle<mirror::ClassLoader>(nullptr));
+ NullHandle<mirror::ClassLoader> class_loader;
mirror::Class* c;
c = class_linker_->FindClass(soa.Self(), "Ljava/lang/Boolean;", class_loader);
FieldHelper fh(c->GetIFields()->Get(0));
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 8c8a355..984f287 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -2881,7 +2881,7 @@
Handle<mirror::ClassLoader> class_loader(hs.NewHandle(mh.GetClassLoader()));
verifier::MethodVerifier verifier(&mh.GetDexFile(), &dex_cache, &class_loader,
&mh.GetClassDef(), code_item, m->GetDexMethodIndex(), m,
- m->GetAccessFlags(), false, true);
+ m->GetAccessFlags(), false, true, false);
// Note: we don't need to verify the method.
return InlineMethodAnalyser::AnalyseMethodCode(&verifier, nullptr);
}
diff --git a/runtime/deoptimize_stack_visitor.cc b/runtime/deoptimize_stack_visitor.cc
index c7fbc87..449ccce 100644
--- a/runtime/deoptimize_stack_visitor.cc
+++ b/runtime/deoptimize_stack_visitor.cc
@@ -55,7 +55,7 @@
Handle<mirror::ClassLoader> class_loader(hs.NewHandle(mh.GetClassLoader()));
verifier::MethodVerifier verifier(&mh.GetDexFile(), &dex_cache, &class_loader,
&mh.GetClassDef(), code_item, m->GetDexMethodIndex(), m,
- m->GetAccessFlags(), false, true);
+ m->GetAccessFlags(), false, true, true);
verifier.Verify();
std::vector<int32_t> kinds = verifier.DescribeVRegs(dex_pc);
for (uint16_t reg = 0; reg < num_regs; ++reg) {
diff --git a/runtime/dex_instruction.h b/runtime/dex_instruction.h
index 560e5ff..1ff5c19 100644
--- a/runtime/dex_instruction.h
+++ b/runtime/dex_instruction.h
@@ -118,13 +118,30 @@
};
enum Flags {
- kBranch = 0x01, // conditional or unconditional branch
- kContinue = 0x02, // flow can continue to next statement
- kSwitch = 0x04, // switch statement
- kThrow = 0x08, // could cause an exception to be thrown
- kReturn = 0x10, // returns, no additional statements
- kInvoke = 0x20, // a flavor of invoke
- kUnconditional = 0x40, // unconditional branch
+ kBranch = 0x000001, // conditional or unconditional branch
+ kContinue = 0x000002, // flow can continue to next statement
+ kSwitch = 0x000004, // switch statement
+ kThrow = 0x000008, // could cause an exception to be thrown
+ kReturn = 0x000010, // returns, no additional statements
+ kInvoke = 0x000020, // a flavor of invoke
+ kUnconditional = 0x000040, // unconditional branch
+ kAdd = 0x000080, // addition
+ kSubtract = 0x000100, // subtract
+ kMultiply = 0x000200, // multiply
+ kDivide = 0x000400, // division
+ kRemainder = 0x000800, // remainder
+ kAnd = 0x001000, // and
+ kOr = 0x002000, // or
+ kXor = 0x004000, // xor
+ kShl = 0x008000, // shl
+ kShr = 0x010000, // shr
+ kUshr = 0x020000, // ushr
+ kCast = 0x040000, // cast
+ kStore = 0x080000, // store opcode
+ kLoad = 0x100000, // load opcode
+ kClobber = 0x200000, // clobbers memory in a big way (not just a write)
+ kRegCFieldOrConstant = 0x400000, // is the third virtual register a field or literal constant (vC)
+ kRegBFieldOrConstant = 0x800000, // is the second virtual register a field or literal constant (vB)
};
enum VerifyFlag {
diff --git a/runtime/dex_instruction_list.h b/runtime/dex_instruction_list.h
index c2cd65a..f43e42f 100644
--- a/runtime/dex_instruction_list.h
+++ b/runtime/dex_instruction_list.h
@@ -36,27 +36,27 @@
V(0x0F, RETURN, "return", k11x, false, kNone, kReturn, kVerifyRegA) \
V(0x10, RETURN_WIDE, "return-wide", k11x, false, kNone, kReturn, kVerifyRegAWide) \
V(0x11, RETURN_OBJECT, "return-object", k11x, false, kNone, kReturn, kVerifyRegA) \
- V(0x12, CONST_4, "const/4", k11n, true, kNone, kContinue, kVerifyRegA) \
- V(0x13, CONST_16, "const/16", k21s, true, kNone, kContinue, kVerifyRegA) \
- V(0x14, CONST, "const", k31i, true, kNone, kContinue, kVerifyRegA) \
- V(0x15, CONST_HIGH16, "const/high16", k21h, true, kNone, kContinue, kVerifyRegA) \
- V(0x16, CONST_WIDE_16, "const-wide/16", k21s, true, kNone, kContinue, kVerifyRegAWide) \
- V(0x17, CONST_WIDE_32, "const-wide/32", k31i, true, kNone, kContinue, kVerifyRegAWide) \
- V(0x18, CONST_WIDE, "const-wide", k51l, true, kNone, kContinue, kVerifyRegAWide) \
- V(0x19, CONST_WIDE_HIGH16, "const-wide/high16", k21h, true, kNone, kContinue, kVerifyRegAWide) \
+ V(0x12, CONST_4, "const/4", k11n, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegA) \
+ V(0x13, CONST_16, "const/16", k21s, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegA) \
+ V(0x14, CONST, "const", k31i, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegA) \
+ V(0x15, CONST_HIGH16, "const/high16", k21h, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegA) \
+ V(0x16, CONST_WIDE_16, "const-wide/16", k21s, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegAWide) \
+ V(0x17, CONST_WIDE_32, "const-wide/32", k31i, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegAWide) \
+ V(0x18, CONST_WIDE, "const-wide", k51l, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegAWide) \
+ V(0x19, CONST_WIDE_HIGH16, "const-wide/high16", k21h, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegAWide) \
V(0x1A, CONST_STRING, "const-string", k21c, true, kStringRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBString) \
V(0x1B, CONST_STRING_JUMBO, "const-string/jumbo", k31c, true, kStringRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBString) \
V(0x1C, CONST_CLASS, "const-class", k21c, true, kTypeRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBType) \
- V(0x1D, MONITOR_ENTER, "monitor-enter", k11x, false, kNone, kContinue | kThrow, kVerifyRegA) \
- V(0x1E, MONITOR_EXIT, "monitor-exit", k11x, false, kNone, kContinue | kThrow, kVerifyRegA) \
+ V(0x1D, MONITOR_ENTER, "monitor-enter", k11x, false, kNone, kContinue | kThrow | kClobber, kVerifyRegA) \
+ V(0x1E, MONITOR_EXIT, "monitor-exit", k11x, false, kNone, kContinue | kThrow | kClobber, kVerifyRegA) \
V(0x1F, CHECK_CAST, "check-cast", k21c, true, kTypeRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBType) \
V(0x20, INSTANCE_OF, "instance-of", k22c, true, kTypeRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCType) \
V(0x21, ARRAY_LENGTH, "array-length", k12x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \
- V(0x22, NEW_INSTANCE, "new-instance", k21c, true, kTypeRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBNewInstance) \
- V(0x23, NEW_ARRAY, "new-array", k22c, true, kTypeRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCNewArray) \
- V(0x24, FILLED_NEW_ARRAY, "filled-new-array", k35c, false, kTypeRef, kContinue | kThrow, kVerifyRegBType | kVerifyVarArg) \
- V(0x25, FILLED_NEW_ARRAY_RANGE, "filled-new-array/range", k3rc, false, kTypeRef, kContinue | kThrow, kVerifyRegBType | kVerifyVarArgRange) \
- V(0x26, FILL_ARRAY_DATA, "fill-array-data", k31t, false, kNone, kContinue | kThrow, kVerifyRegA | kVerifyArrayData) \
+ V(0x22, NEW_INSTANCE, "new-instance", k21c, true, kTypeRef, kContinue | kThrow | kClobber, kVerifyRegA | kVerifyRegBNewInstance) \
+ V(0x23, NEW_ARRAY, "new-array", k22c, true, kTypeRef, kContinue | kThrow | kClobber, kVerifyRegA | kVerifyRegB | kVerifyRegCNewArray) \
+ V(0x24, FILLED_NEW_ARRAY, "filled-new-array", k35c, false, kTypeRef, kContinue | kThrow | kClobber, kVerifyRegBType | kVerifyVarArg) \
+ V(0x25, FILLED_NEW_ARRAY_RANGE, "filled-new-array/range", k3rc, false, kTypeRef, kContinue | kThrow | kClobber, kVerifyRegBType | kVerifyVarArgRange) \
+ V(0x26, FILL_ARRAY_DATA, "fill-array-data", k31t, false, kNone, kContinue | kThrow | kClobber, kVerifyRegA | kVerifyArrayData) \
V(0x27, THROW, "throw", k11x, false, kNone, kThrow, kVerifyRegA) \
V(0x28, GOTO, "goto", k10t, false, kNone, kBranch | kUnconditional, kVerifyBranchTarget) \
V(0x29, GOTO_16, "goto/16", k20t, false, kNone, kBranch | kUnconditional, kVerifyBranchTarget) \
@@ -86,48 +86,48 @@
V(0x41, UNUSED_41, "unused-41", k10x, false, kUnknown, 0, kVerifyError) \
V(0x42, UNUSED_42, "unused-42", k10x, false, kUnknown, 0, kVerifyError) \
V(0x43, UNUSED_43, "unused-43", k10x, false, kUnknown, 0, kVerifyError) \
- V(0x44, AGET, "aget", k23x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x45, AGET_WIDE, "aget-wide", k23x, true, kNone, kContinue | kThrow, kVerifyRegAWide | kVerifyRegB | kVerifyRegC) \
- V(0x46, AGET_OBJECT, "aget-object", k23x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x47, AGET_BOOLEAN, "aget-boolean", k23x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x48, AGET_BYTE, "aget-byte", k23x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x49, AGET_CHAR, "aget-char", k23x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x4A, AGET_SHORT, "aget-short", k23x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x4B, APUT, "aput", k23x, false, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x4C, APUT_WIDE, "aput-wide", k23x, false, kNone, kContinue | kThrow, kVerifyRegAWide | kVerifyRegB | kVerifyRegC) \
- V(0x4D, APUT_OBJECT, "aput-object", k23x, false, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x4E, APUT_BOOLEAN, "aput-boolean", k23x, false, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x4F, APUT_BYTE, "aput-byte", k23x, false, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x50, APUT_CHAR, "aput-char", k23x, false, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x51, APUT_SHORT, "aput-short", k23x, false, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x52, IGET, "iget", k22c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
- V(0x53, IGET_WIDE, "iget-wide", k22c, true, kFieldRef, kContinue | kThrow, kVerifyRegAWide | kVerifyRegB | kVerifyRegCField) \
- V(0x54, IGET_OBJECT, "iget-object", k22c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
- V(0x55, IGET_BOOLEAN, "iget-boolean", k22c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
- V(0x56, IGET_BYTE, "iget-byte", k22c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
- V(0x57, IGET_CHAR, "iget-char", k22c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
- V(0x58, IGET_SHORT, "iget-short", k22c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
- V(0x59, IPUT, "iput", k22c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
- V(0x5A, IPUT_WIDE, "iput-wide", k22c, false, kFieldRef, kContinue | kThrow, kVerifyRegAWide | kVerifyRegB | kVerifyRegCField) \
- V(0x5B, IPUT_OBJECT, "iput-object", k22c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
- V(0x5C, IPUT_BOOLEAN, "iput-boolean", k22c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
- V(0x5D, IPUT_BYTE, "iput-byte", k22c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
- V(0x5E, IPUT_CHAR, "iput-char", k22c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
- V(0x5F, IPUT_SHORT, "iput-short", k22c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
- V(0x60, SGET, "sget", k21c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \
- V(0x61, SGET_WIDE, "sget-wide", k21c, true, kFieldRef, kContinue | kThrow, kVerifyRegAWide | kVerifyRegBField) \
- V(0x62, SGET_OBJECT, "sget-object", k21c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \
- V(0x63, SGET_BOOLEAN, "sget-boolean", k21c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \
- V(0x64, SGET_BYTE, "sget-byte", k21c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \
- V(0x65, SGET_CHAR, "sget-char", k21c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \
- V(0x66, SGET_SHORT, "sget-short", k21c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \
- V(0x67, SPUT, "sput", k21c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \
- V(0x68, SPUT_WIDE, "sput-wide", k21c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \
- V(0x69, SPUT_OBJECT, "sput-object", k21c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \
- V(0x6A, SPUT_BOOLEAN, "sput-boolean", k21c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \
- V(0x6B, SPUT_BYTE, "sput-byte", k21c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \
- V(0x6C, SPUT_CHAR, "sput-char", k21c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \
- V(0x6D, SPUT_SHORT, "sput-short", k21c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBField) \
+ V(0x44, AGET, "aget", k23x, true, kNone, kContinue | kThrow | kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+ V(0x45, AGET_WIDE, "aget-wide", k23x, true, kNone, kContinue | kThrow | kLoad, kVerifyRegAWide | kVerifyRegB | kVerifyRegC) \
+ V(0x46, AGET_OBJECT, "aget-object", k23x, true, kNone, kContinue | kThrow | kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+ V(0x47, AGET_BOOLEAN, "aget-boolean", k23x, true, kNone, kContinue | kThrow | kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+ V(0x48, AGET_BYTE, "aget-byte", k23x, true, kNone, kContinue | kThrow | kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+ V(0x49, AGET_CHAR, "aget-char", k23x, true, kNone, kContinue | kThrow | kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+ V(0x4A, AGET_SHORT, "aget-short", k23x, true, kNone, kContinue | kThrow | kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+ V(0x4B, APUT, "aput", k23x, false, kNone, kContinue | kThrow | kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+ V(0x4C, APUT_WIDE, "aput-wide", k23x, false, kNone, kContinue | kThrow | kStore, kVerifyRegAWide | kVerifyRegB | kVerifyRegC) \
+ V(0x4D, APUT_OBJECT, "aput-object", k23x, false, kNone, kContinue | kThrow | kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+ V(0x4E, APUT_BOOLEAN, "aput-boolean", k23x, false, kNone, kContinue | kThrow | kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+ V(0x4F, APUT_BYTE, "aput-byte", k23x, false, kNone, kContinue | kThrow | kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+ V(0x50, APUT_CHAR, "aput-char", k23x, false, kNone, kContinue | kThrow | kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+ V(0x51, APUT_SHORT, "aput-short", k23x, false, kNone, kContinue | kThrow | kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+ V(0x52, IGET, "iget", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+ V(0x53, IGET_WIDE, "iget-wide", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRegCField) \
+ V(0x54, IGET_OBJECT, "iget-object", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+ V(0x55, IGET_BOOLEAN, "iget-boolean", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+ V(0x56, IGET_BYTE, "iget-byte", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+ V(0x57, IGET_CHAR, "iget-char", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+ V(0x58, IGET_SHORT, "iget-short", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+ V(0x59, IPUT, "iput", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+ V(0x5A, IPUT_WIDE, "iput-wide", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRegCField) \
+ V(0x5B, IPUT_OBJECT, "iput-object", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+ V(0x5C, IPUT_BOOLEAN, "iput-boolean", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+ V(0x5D, IPUT_BYTE, "iput-byte", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+ V(0x5E, IPUT_CHAR, "iput-char", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+ V(0x5F, IPUT_SHORT, "iput-short", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
+ V(0x60, SGET, "sget", k21c, true, kFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
+ V(0x61, SGET_WIDE, "sget-wide", k21c, true, kFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegAWide | kVerifyRegBField) \
+ V(0x62, SGET_OBJECT, "sget-object", k21c, true, kFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
+ V(0x63, SGET_BOOLEAN, "sget-boolean", k21c, true, kFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
+ V(0x64, SGET_BYTE, "sget-byte", k21c, true, kFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
+ V(0x65, SGET_CHAR, "sget-char", k21c, true, kFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
+ V(0x66, SGET_SHORT, "sget-short", k21c, true, kFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
+ V(0x67, SPUT, "sput", k21c, false, kFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
+ V(0x68, SPUT_WIDE, "sput-wide", k21c, false, kFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
+ V(0x69, SPUT_OBJECT, "sput-object", k21c, false, kFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
+ V(0x6A, SPUT_BOOLEAN, "sput-boolean", k21c, false, kFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
+ V(0x6B, SPUT_BYTE, "sput-byte", k21c, false, kFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
+ V(0x6C, SPUT_CHAR, "sput-char", k21c, false, kFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
+ V(0x6D, SPUT_SHORT, "sput-short", k21c, false, kFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
V(0x6E, INVOKE_VIRTUAL, "invoke-virtual", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArg) \
V(0x6F, INVOKE_SUPER, "invoke-super", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArg) \
V(0x70, INVOKE_DIRECT, "invoke-direct", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArg) \
@@ -147,110 +147,110 @@
V(0x7E, NOT_LONG, "not-long", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
V(0x7F, NEG_FLOAT, "neg-float", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
V(0x80, NEG_DOUBLE, "neg-double", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
- V(0x81, INT_TO_LONG, "int-to-long", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegB) \
- V(0x82, INT_TO_FLOAT, "int-to-float", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0x83, INT_TO_DOUBLE, "int-to-double", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegB) \
- V(0x84, LONG_TO_INT, "long-to-int", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegBWide) \
- V(0x85, LONG_TO_FLOAT, "long-to-float", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegBWide) \
- V(0x86, LONG_TO_DOUBLE, "long-to-double", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
- V(0x87, FLOAT_TO_INT, "float-to-int", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0x88, FLOAT_TO_LONG, "float-to-long", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegB) \
- V(0x89, FLOAT_TO_DOUBLE, "float-to-double", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegB) \
- V(0x8A, DOUBLE_TO_INT, "double-to-int", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegBWide) \
- V(0x8B, DOUBLE_TO_LONG, "double-to-long", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
- V(0x8C, DOUBLE_TO_FLOAT, "double-to-float", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegBWide) \
- V(0x8D, INT_TO_BYTE, "int-to-byte", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0x8E, INT_TO_CHAR, "int-to-char", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0x8F, INT_TO_SHORT, "int-to-short", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0x90, ADD_INT, "add-int", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x91, SUB_INT, "sub-int", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x92, MUL_INT, "mul-int", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x93, DIV_INT, "div-int", k23x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x94, REM_INT, "rem-int", k23x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x95, AND_INT, "and-int", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x96, OR_INT, "or-int", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x97, XOR_INT, "xor-int", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x98, SHL_INT, "shl-int", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x99, SHR_INT, "shr-int", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x9A, USHR_INT, "ushr-int", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x9B, ADD_LONG, "add-long", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
- V(0x9C, SUB_LONG, "sub-long", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
- V(0x9D, MUL_LONG, "mul-long", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
- V(0x9E, DIV_LONG, "div-long", k23x, true, kNone, kContinue | kThrow, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
- V(0x9F, REM_LONG, "rem-long", k23x, true, kNone, kContinue | kThrow, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
- V(0xA0, AND_LONG, "and-long", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
- V(0xA1, OR_LONG, "or-long", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
- V(0xA2, XOR_LONG, "xor-long", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
- V(0xA3, SHL_LONG, "shl-long", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegC) \
- V(0xA4, SHR_LONG, "shr-long", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegC) \
- V(0xA5, USHR_LONG, "ushr-long", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegC) \
- V(0xA6, ADD_FLOAT, "add-float", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0xA7, SUB_FLOAT, "sub-float", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0xA8, MUL_FLOAT, "mul-float", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0xA9, DIV_FLOAT, "div-float", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0xAA, REM_FLOAT, "rem-float", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0xAB, ADD_DOUBLE, "add-double", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
- V(0xAC, SUB_DOUBLE, "sub-double", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
- V(0xAD, MUL_DOUBLE, "mul-double", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
- V(0xAE, DIV_DOUBLE, "div-double", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
- V(0xAF, REM_DOUBLE, "rem-double", k23x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
- V(0xB0, ADD_INT_2ADDR, "add-int/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0xB1, SUB_INT_2ADDR, "sub-int/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0xB2, MUL_INT_2ADDR, "mul-int/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0xB3, DIV_INT_2ADDR, "div-int/2addr", k12x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \
- V(0xB4, REM_INT_2ADDR, "rem-int/2addr", k12x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \
- V(0xB5, AND_INT_2ADDR, "and-int/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0xB6, OR_INT_2ADDR, "or-int/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0xB7, XOR_INT_2ADDR, "xor-int/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0xB8, SHL_INT_2ADDR, "shl-int/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0xB9, SHR_INT_2ADDR, "shr-int/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0xBA, USHR_INT_2ADDR, "ushr-int/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0xBB, ADD_LONG_2ADDR, "add-long/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
- V(0xBC, SUB_LONG_2ADDR, "sub-long/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
- V(0xBD, MUL_LONG_2ADDR, "mul-long/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
- V(0xBE, DIV_LONG_2ADDR, "div-long/2addr", k12x, true, kNone, kContinue | kThrow, kVerifyRegAWide | kVerifyRegBWide) \
- V(0xBF, REM_LONG_2ADDR, "rem-long/2addr", k12x, true, kNone, kContinue | kThrow, kVerifyRegAWide | kVerifyRegBWide) \
- V(0xC0, AND_LONG_2ADDR, "and-long/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
- V(0xC1, OR_LONG_2ADDR, "or-long/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
- V(0xC2, XOR_LONG_2ADDR, "xor-long/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
- V(0xC3, SHL_LONG_2ADDR, "shl-long/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegB) \
- V(0xC4, SHR_LONG_2ADDR, "shr-long/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegB) \
- V(0xC5, USHR_LONG_2ADDR, "ushr-long/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegB) \
- V(0xC6, ADD_FLOAT_2ADDR, "add-float/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0xC7, SUB_FLOAT_2ADDR, "sub-float/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0xC8, MUL_FLOAT_2ADDR, "mul-float/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0xC9, DIV_FLOAT_2ADDR, "div-float/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0xCA, REM_FLOAT_2ADDR, "rem-float/2addr", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0xCB, ADD_DOUBLE_2ADDR, "add-double/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
- V(0xCC, SUB_DOUBLE_2ADDR, "sub-double/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
- V(0xCD, MUL_DOUBLE_2ADDR, "mul-double/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
- V(0xCE, DIV_DOUBLE_2ADDR, "div-double/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
- V(0xCF, REM_DOUBLE_2ADDR, "rem-double/2addr", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \
- V(0xD0, ADD_INT_LIT16, "add-int/lit16", k22s, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0xD1, RSUB_INT, "rsub-int", k22s, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0xD2, MUL_INT_LIT16, "mul-int/lit16", k22s, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0xD3, DIV_INT_LIT16, "div-int/lit16", k22s, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \
- V(0xD4, REM_INT_LIT16, "rem-int/lit16", k22s, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \
- V(0xD5, AND_INT_LIT16, "and-int/lit16", k22s, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0xD6, OR_INT_LIT16, "or-int/lit16", k22s, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0xD7, XOR_INT_LIT16, "xor-int/lit16", k22s, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0xD8, ADD_INT_LIT8, "add-int/lit8", k22b, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0xD9, RSUB_INT_LIT8, "rsub-int/lit8", k22b, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0xDA, MUL_INT_LIT8, "mul-int/lit8", k22b, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0xDB, DIV_INT_LIT8, "div-int/lit8", k22b, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \
- V(0xDC, REM_INT_LIT8, "rem-int/lit8", k22b, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \
- V(0xDD, AND_INT_LIT8, "and-int/lit8", k22b, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0xDE, OR_INT_LIT8, "or-int/lit8", k22b, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0xDF, XOR_INT_LIT8, "xor-int/lit8", k22b, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0xE0, SHL_INT_LIT8, "shl-int/lit8", k22b, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0xE1, SHR_INT_LIT8, "shr-int/lit8", k22b, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0xE2, USHR_INT_LIT8, "ushr-int/lit8", k22b, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \
- V(0xE3, IGET_QUICK, "iget-quick", k22c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \
- V(0xE4, IGET_WIDE_QUICK, "iget-wide-quick", k22c, true, kFieldRef, kContinue | kThrow, kVerifyRegAWide | kVerifyRegB) \
- V(0xE5, IGET_OBJECT_QUICK, "iget-object-quick", k22c, true, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \
- V(0xE6, IPUT_QUICK, "iput-quick", k22c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \
- V(0xE7, IPUT_WIDE_QUICK, "iput-wide-quick", k22c, false, kFieldRef, kContinue | kThrow, kVerifyRegAWide | kVerifyRegB) \
- V(0xE8, IPUT_OBJECT_QUICK, "iput-object-quick", k22c, false, kFieldRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \
+ V(0x81, INT_TO_LONG, "int-to-long", k12x, true, kNone, kContinue | kCast, kVerifyRegAWide | kVerifyRegB) \
+ V(0x82, INT_TO_FLOAT, "int-to-float", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegB) \
+ V(0x83, INT_TO_DOUBLE, "int-to-double", k12x, true, kNone, kContinue | kCast, kVerifyRegAWide | kVerifyRegB) \
+ V(0x84, LONG_TO_INT, "long-to-int", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegBWide) \
+ V(0x85, LONG_TO_FLOAT, "long-to-float", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegBWide) \
+ V(0x86, LONG_TO_DOUBLE, "long-to-double", k12x, true, kNone, kContinue | kCast, kVerifyRegAWide | kVerifyRegBWide) \
+ V(0x87, FLOAT_TO_INT, "float-to-int", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegB) \
+ V(0x88, FLOAT_TO_LONG, "float-to-long", k12x, true, kNone, kContinue | kCast, kVerifyRegAWide | kVerifyRegB) \
+ V(0x89, FLOAT_TO_DOUBLE, "float-to-double", k12x, true, kNone, kContinue | kCast, kVerifyRegAWide | kVerifyRegB) \
+ V(0x8A, DOUBLE_TO_INT, "double-to-int", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegBWide) \
+ V(0x8B, DOUBLE_TO_LONG, "double-to-long", k12x, true, kNone, kContinue | kCast, kVerifyRegAWide | kVerifyRegBWide) \
+ V(0x8C, DOUBLE_TO_FLOAT, "double-to-float", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegBWide) \
+ V(0x8D, INT_TO_BYTE, "int-to-byte", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegB) \
+ V(0x8E, INT_TO_CHAR, "int-to-char", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegB) \
+ V(0x8F, INT_TO_SHORT, "int-to-short", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegB) \
+ V(0x90, ADD_INT, "add-int", k23x, true, kNone, kContinue | kAdd, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+ V(0x91, SUB_INT, "sub-int", k23x, true, kNone, kContinue | kSubtract, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+ V(0x92, MUL_INT, "mul-int", k23x, true, kNone, kContinue | kMultiply, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+ V(0x93, DIV_INT, "div-int", k23x, true, kNone, kContinue | kThrow | kDivide, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+ V(0x94, REM_INT, "rem-int", k23x, true, kNone, kContinue | kThrow | kRemainder, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+ V(0x95, AND_INT, "and-int", k23x, true, kNone, kContinue | kAnd, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+ V(0x96, OR_INT, "or-int", k23x, true, kNone, kContinue | kOr, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+ V(0x97, XOR_INT, "xor-int", k23x, true, kNone, kContinue | kXor, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+ V(0x98, SHL_INT, "shl-int", k23x, true, kNone, kContinue | kShl, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+ V(0x99, SHR_INT, "shr-int", k23x, true, kNone, kContinue | kShr, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+ V(0x9A, USHR_INT, "ushr-int", k23x, true, kNone, kContinue | kUshr, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+ V(0x9B, ADD_LONG, "add-long", k23x, true, kNone, kContinue | kAdd, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+ V(0x9C, SUB_LONG, "sub-long", k23x, true, kNone, kContinue | kSubtract, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+ V(0x9D, MUL_LONG, "mul-long", k23x, true, kNone, kContinue | kMultiply, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+ V(0x9E, DIV_LONG, "div-long", k23x, true, kNone, kContinue | kThrow | kDivide, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+ V(0x9F, REM_LONG, "rem-long", k23x, true, kNone, kContinue | kThrow | kRemainder, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+ V(0xA0, AND_LONG, "and-long", k23x, true, kNone, kContinue | kAnd, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+ V(0xA1, OR_LONG, "or-long", k23x, true, kNone, kContinue | kOr, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+ V(0xA2, XOR_LONG, "xor-long", k23x, true, kNone, kContinue | kXor, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+ V(0xA3, SHL_LONG, "shl-long", k23x, true, kNone, kContinue | kShl, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegC) \
+ V(0xA4, SHR_LONG, "shr-long", k23x, true, kNone, kContinue | kShr, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegC) \
+ V(0xA5, USHR_LONG, "ushr-long", k23x, true, kNone, kContinue | kUshr, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegC) \
+ V(0xA6, ADD_FLOAT, "add-float", k23x, true, kNone, kContinue | kAdd, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+ V(0xA7, SUB_FLOAT, "sub-float", k23x, true, kNone, kContinue | kSubtract, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+ V(0xA8, MUL_FLOAT, "mul-float", k23x, true, kNone, kContinue | kMultiply, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+ V(0xA9, DIV_FLOAT, "div-float", k23x, true, kNone, kContinue | kDivide, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+ V(0xAA, REM_FLOAT, "rem-float", k23x, true, kNone, kContinue | kRemainder, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
+ V(0xAB, ADD_DOUBLE, "add-double", k23x, true, kNone, kContinue | kAdd, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+ V(0xAC, SUB_DOUBLE, "sub-double", k23x, true, kNone, kContinue | kSubtract, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+ V(0xAD, MUL_DOUBLE, "mul-double", k23x, true, kNone, kContinue | kMultiply, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+ V(0xAE, DIV_DOUBLE, "div-double", k23x, true, kNone, kContinue | kDivide, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+ V(0xAF, REM_DOUBLE, "rem-double", k23x, true, kNone, kContinue | kRemainder, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
+ V(0xB0, ADD_INT_2ADDR, "add-int/2addr", k12x, true, kNone, kContinue | kAdd, kVerifyRegA | kVerifyRegB) \
+ V(0xB1, SUB_INT_2ADDR, "sub-int/2addr", k12x, true, kNone, kContinue | kSubtract, kVerifyRegA | kVerifyRegB) \
+ V(0xB2, MUL_INT_2ADDR, "mul-int/2addr", k12x, true, kNone, kContinue | kMultiply, kVerifyRegA | kVerifyRegB) \
+ V(0xB3, DIV_INT_2ADDR, "div-int/2addr", k12x, true, kNone, kContinue | kThrow | kDivide, kVerifyRegA | kVerifyRegB) \
+ V(0xB4, REM_INT_2ADDR, "rem-int/2addr", k12x, true, kNone, kContinue | kThrow | kRemainder, kVerifyRegA | kVerifyRegB) \
+ V(0xB5, AND_INT_2ADDR, "and-int/2addr", k12x, true, kNone, kContinue | kAnd, kVerifyRegA | kVerifyRegB) \
+ V(0xB6, OR_INT_2ADDR, "or-int/2addr", k12x, true, kNone, kContinue | kOr, kVerifyRegA | kVerifyRegB) \
+ V(0xB7, XOR_INT_2ADDR, "xor-int/2addr", k12x, true, kNone, kContinue | kXor, kVerifyRegA | kVerifyRegB) \
+ V(0xB8, SHL_INT_2ADDR, "shl-int/2addr", k12x, true, kNone, kContinue | kShl, kVerifyRegA | kVerifyRegB) \
+ V(0xB9, SHR_INT_2ADDR, "shr-int/2addr", k12x, true, kNone, kContinue | kShr, kVerifyRegA | kVerifyRegB) \
+ V(0xBA, USHR_INT_2ADDR, "ushr-int/2addr", k12x, true, kNone, kContinue | kUshr, kVerifyRegA | kVerifyRegB) \
+ V(0xBB, ADD_LONG_2ADDR, "add-long/2addr", k12x, true, kNone, kContinue | kAdd, kVerifyRegAWide | kVerifyRegBWide) \
+ V(0xBC, SUB_LONG_2ADDR, "sub-long/2addr", k12x, true, kNone, kContinue | kSubtract, kVerifyRegAWide | kVerifyRegBWide) \
+ V(0xBD, MUL_LONG_2ADDR, "mul-long/2addr", k12x, true, kNone, kContinue | kMultiply, kVerifyRegAWide | kVerifyRegBWide) \
+ V(0xBE, DIV_LONG_2ADDR, "div-long/2addr", k12x, true, kNone, kContinue | kThrow | kDivide, kVerifyRegAWide | kVerifyRegBWide) \
+ V(0xBF, REM_LONG_2ADDR, "rem-long/2addr", k12x, true, kNone, kContinue | kThrow | kRemainder, kVerifyRegAWide | kVerifyRegBWide) \
+ V(0xC0, AND_LONG_2ADDR, "and-long/2addr", k12x, true, kNone, kContinue | kAnd, kVerifyRegAWide | kVerifyRegBWide) \
+ V(0xC1, OR_LONG_2ADDR, "or-long/2addr", k12x, true, kNone, kContinue | kOr, kVerifyRegAWide | kVerifyRegBWide) \
+ V(0xC2, XOR_LONG_2ADDR, "xor-long/2addr", k12x, true, kNone, kContinue | kXor, kVerifyRegAWide | kVerifyRegBWide) \
+ V(0xC3, SHL_LONG_2ADDR, "shl-long/2addr", k12x, true, kNone, kContinue | kShl, kVerifyRegAWide | kVerifyRegB) \
+ V(0xC4, SHR_LONG_2ADDR, "shr-long/2addr", k12x, true, kNone, kContinue | kShr, kVerifyRegAWide | kVerifyRegB) \
+ V(0xC5, USHR_LONG_2ADDR, "ushr-long/2addr", k12x, true, kNone, kContinue | kUshr, kVerifyRegAWide | kVerifyRegB) \
+ V(0xC6, ADD_FLOAT_2ADDR, "add-float/2addr", k12x, true, kNone, kContinue | kAdd, kVerifyRegA | kVerifyRegB) \
+ V(0xC7, SUB_FLOAT_2ADDR, "sub-float/2addr", k12x, true, kNone, kContinue | kSubtract, kVerifyRegA | kVerifyRegB) \
+ V(0xC8, MUL_FLOAT_2ADDR, "mul-float/2addr", k12x, true, kNone, kContinue | kMultiply, kVerifyRegA | kVerifyRegB) \
+ V(0xC9, DIV_FLOAT_2ADDR, "div-float/2addr", k12x, true, kNone, kContinue | kDivide, kVerifyRegA | kVerifyRegB) \
+ V(0xCA, REM_FLOAT_2ADDR, "rem-float/2addr", k12x, true, kNone, kContinue | kRemainder, kVerifyRegA | kVerifyRegB) \
+ V(0xCB, ADD_DOUBLE_2ADDR, "add-double/2addr", k12x, true, kNone, kContinue | kAdd, kVerifyRegAWide | kVerifyRegBWide) \
+ V(0xCC, SUB_DOUBLE_2ADDR, "sub-double/2addr", k12x, true, kNone, kContinue | kSubtract, kVerifyRegAWide | kVerifyRegBWide) \
+ V(0xCD, MUL_DOUBLE_2ADDR, "mul-double/2addr", k12x, true, kNone, kContinue | kMultiply, kVerifyRegAWide | kVerifyRegBWide) \
+ V(0xCE, DIV_DOUBLE_2ADDR, "div-double/2addr", k12x, true, kNone, kContinue | kDivide, kVerifyRegAWide | kVerifyRegBWide) \
+ V(0xCF, REM_DOUBLE_2ADDR, "rem-double/2addr", k12x, true, kNone, kContinue | kRemainder, kVerifyRegAWide | kVerifyRegBWide) \
+ V(0xD0, ADD_INT_LIT16, "add-int/lit16", k22s, true, kNone, kContinue | kAdd | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+ V(0xD1, RSUB_INT, "rsub-int", k22s, true, kNone, kContinue | kSubtract | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+ V(0xD2, MUL_INT_LIT16, "mul-int/lit16", k22s, true, kNone, kContinue | kMultiply | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+ V(0xD3, DIV_INT_LIT16, "div-int/lit16", k22s, true, kNone, kContinue | kThrow | kDivide | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+ V(0xD4, REM_INT_LIT16, "rem-int/lit16", k22s, true, kNone, kContinue | kThrow | kRemainder | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+ V(0xD5, AND_INT_LIT16, "and-int/lit16", k22s, true, kNone, kContinue | kAnd | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+ V(0xD6, OR_INT_LIT16, "or-int/lit16", k22s, true, kNone, kContinue | kOr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+ V(0xD7, XOR_INT_LIT16, "xor-int/lit16", k22s, true, kNone, kContinue | kXor | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+ V(0xD8, ADD_INT_LIT8, "add-int/lit8", k22b, true, kNone, kContinue | kAdd | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+ V(0xD9, RSUB_INT_LIT8, "rsub-int/lit8", k22b, true, kNone, kContinue | kSubtract | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+ V(0xDA, MUL_INT_LIT8, "mul-int/lit8", k22b, true, kNone, kContinue | kMultiply | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+ V(0xDB, DIV_INT_LIT8, "div-int/lit8", k22b, true, kNone, kContinue | kThrow | kDivide | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+ V(0xDC, REM_INT_LIT8, "rem-int/lit8", k22b, true, kNone, kContinue | kThrow | kRemainder | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+ V(0xDD, AND_INT_LIT8, "and-int/lit8", k22b, true, kNone, kContinue | kAnd | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+ V(0xDE, OR_INT_LIT8, "or-int/lit8", k22b, true, kNone, kContinue | kOr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+ V(0xDF, XOR_INT_LIT8, "xor-int/lit8", k22b, true, kNone, kContinue | kXor | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+ V(0xE0, SHL_INT_LIT8, "shl-int/lit8", k22b, true, kNone, kContinue | kShl | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+ V(0xE1, SHR_INT_LIT8, "shr-int/lit8", k22b, true, kNone, kContinue | kShr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+ V(0xE2, USHR_INT_LIT8, "ushr-int/lit8", k22b, true, kNone, kContinue | kUshr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+ V(0xE3, IGET_QUICK, "iget-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+ V(0xE4, IGET_WIDE_QUICK, "iget-wide-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB) \
+ V(0xE5, IGET_OBJECT_QUICK, "iget-object-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+ V(0xE6, IPUT_QUICK, "iput-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
+ V(0xE7, IPUT_WIDE_QUICK, "iput-wide-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB) \
+ V(0xE8, IPUT_OBJECT_QUICK, "iput-object-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
V(0xE9, INVOKE_VIRTUAL_QUICK, "invoke-virtual-quick", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyVarArg) \
V(0xEA, INVOKE_VIRTUAL_RANGE_QUICK, "invoke-virtual/range-quick", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyVarArgRange) \
V(0xEB, UNUSED_EB, "unused-eb", k10x, false, kUnknown, 0, kVerifyError) \
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index f1795a5..58b4286 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -385,31 +385,36 @@
template<InvokeType type, bool access_check>
static inline mirror::ArtMethod* FindMethodFromCode(uint32_t method_idx,
- mirror::Object* this_object,
- mirror::ArtMethod* referrer, Thread* self) {
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- StackHandleScope<1> hs(self);
- Handle<mirror::Object> handle_scope_this(hs.NewHandle(type == kStatic ? nullptr : this_object));
- mirror::ArtMethod* resolved_method = class_linker->ResolveMethod(method_idx, referrer, type);
+ mirror::Object** this_object,
+ mirror::ArtMethod** referrer, Thread* self) {
+ ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
+ mirror::ArtMethod* resolved_method = class_linker->GetResolvedMethod(method_idx, *referrer, type);
+ if (resolved_method == nullptr) {
+ StackHandleScope<1> hs(self);
+ mirror::Object* null_this = nullptr;
+ HandleWrapper<mirror::Object> h_this(
+ hs.NewHandleWrapper(type == kStatic ? &null_this : this_object));
+ resolved_method = class_linker->ResolveMethod(self, method_idx, referrer, type);
+ }
if (UNLIKELY(resolved_method == nullptr)) {
DCHECK(self->IsExceptionPending()); // Throw exception and unwind.
return nullptr; // Failure.
- } else if (UNLIKELY(handle_scope_this.Get() == nullptr && type != kStatic)) {
+ } else if (UNLIKELY(*this_object == nullptr && type != kStatic)) {
// Maintain interpreter-like semantics where NullPointerException is thrown
// after potential NoSuchMethodError from class linker.
ThrowLocation throw_location = self->GetCurrentLocationForThrow();
- DCHECK(referrer == throw_location.GetMethod());
+ DCHECK_EQ(*referrer, throw_location.GetMethod());
ThrowNullPointerExceptionForMethodAccess(throw_location, method_idx, type);
return nullptr; // Failure.
} else if (access_check) {
// Incompatible class change should have been handled in resolve method.
if (UNLIKELY(resolved_method->CheckIncompatibleClassChange(type))) {
ThrowIncompatibleClassChangeError(type, resolved_method->GetInvokeType(), resolved_method,
- referrer);
+ *referrer);
return nullptr; // Failure.
}
mirror::Class* methods_class = resolved_method->GetDeclaringClass();
- mirror::Class* referring_class = referrer->GetDeclaringClass();
+ mirror::Class* referring_class = (*referrer)->GetDeclaringClass();
bool can_access_resolved_method =
referring_class->CheckResolvedMethodAccess<type>(methods_class, resolved_method,
method_idx);
@@ -423,7 +428,7 @@
case kDirect:
return resolved_method;
case kVirtual: {
- mirror::ObjectArray<mirror::ArtMethod>* vtable = handle_scope_this->GetClass()->GetVTable();
+ mirror::ObjectArray<mirror::ArtMethod>* vtable = (*this_object)->GetClass()->GetVTable();
uint16_t vtable_index = resolved_method->GetMethodIndex();
if (access_check &&
(vtable == nullptr || vtable_index >= static_cast<uint32_t>(vtable->GetLength()))) {
@@ -437,7 +442,7 @@
return vtable->GetWithoutChecks(vtable_index);
}
case kSuper: {
- mirror::Class* super_class = referrer->GetDeclaringClass()->GetSuperClass();
+ mirror::Class* super_class = (*referrer)->GetDeclaringClass()->GetSuperClass();
uint16_t vtable_index = resolved_method->GetMethodIndex();
mirror::ObjectArray<mirror::ArtMethod>* vtable;
if (access_check) {
@@ -460,20 +465,19 @@
}
case kInterface: {
uint32_t imt_index = resolved_method->GetDexMethodIndex() % ClassLinker::kImtSize;
- mirror::ObjectArray<mirror::ArtMethod>* imt_table = handle_scope_this->GetClass()->GetImTable();
+ mirror::ObjectArray<mirror::ArtMethod>* imt_table = (*this_object)->GetClass()->GetImTable();
mirror::ArtMethod* imt_method = imt_table->Get(imt_index);
if (!imt_method->IsImtConflictMethod()) {
return imt_method;
} else {
mirror::ArtMethod* interface_method =
- handle_scope_this->GetClass()->FindVirtualMethodForInterface(resolved_method);
+ (*this_object)->GetClass()->FindVirtualMethodForInterface(resolved_method);
if (UNLIKELY(interface_method == nullptr)) {
ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(resolved_method,
- handle_scope_this.Get(), referrer);
+ *this_object, *referrer);
return nullptr; // Failure.
- } else {
- return interface_method;
}
+ return interface_method;
}
}
default:
@@ -486,8 +490,8 @@
#define EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL(_type, _access_check) \
template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE \
mirror::ArtMethod* FindMethodFromCode<_type, _access_check>(uint32_t method_idx, \
- mirror::Object* this_object, \
- mirror::ArtMethod* referrer, \
+ mirror::Object** this_object, \
+ mirror::ArtMethod** referrer, \
Thread* self)
#define EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(_type) \
EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL(_type, false); \
diff --git a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
index 3f02ec7..f2e2bf7 100644
--- a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
+++ b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
@@ -25,6 +25,7 @@
namespace art {
+// TODO: Make the MethodHelper here be compaction safe.
extern "C" void artInterpreterToCompiledCodeBridge(Thread* self, MethodHelper& mh,
const DexFile::CodeItem* code_item,
ShadowFrame* shadow_frame, JValue* result) {
@@ -43,6 +44,8 @@
}
self->PopShadowFrame();
CHECK(h_class->IsInitializing());
+ // Reload from shadow frame in case the method moved, this is faster than adding a handle.
+ method = shadow_frame->GetMethod();
}
}
uint16_t arg_offset = (code_item == NULL) ? 0 : code_item->registers_size_ - code_item->ins_size_;
diff --git a/runtime/entrypoints/portable/portable_invoke_entrypoints.cc b/runtime/entrypoints/portable/portable_invoke_entrypoints.cc
index d34b097..3a898e8 100644
--- a/runtime/entrypoints/portable/portable_invoke_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_invoke_entrypoints.cc
@@ -23,17 +23,20 @@
template<InvokeType type, bool access_check>
mirror::ArtMethod* FindMethodHelper(uint32_t method_idx, mirror::Object* this_object,
- mirror::ArtMethod* caller_method, Thread* thread) {
+ mirror::ArtMethod* caller_method, Thread* self) {
mirror::ArtMethod* method = FindMethodFast(method_idx, this_object, caller_method,
access_check, type);
if (UNLIKELY(method == NULL)) {
- method = FindMethodFromCode<type, access_check>(method_idx, this_object, caller_method, thread);
+ // Note: This can cause thread suspension.
+ self->AssertThreadSuspensionIsAllowable();
+ method = FindMethodFromCode<type, access_check>(method_idx, &this_object, &caller_method,
+ self);
if (UNLIKELY(method == NULL)) {
- CHECK(thread->IsExceptionPending());
+ CHECK(self->IsExceptionPending());
return 0; // failure
}
}
- DCHECK(!thread->IsExceptionPending());
+ DCHECK(!self->IsExceptionPending());
const void* code = method->GetEntryPointFromPortableCompiledCode();
// When we return, the caller will branch to this address, so it had better not be 0!
diff --git a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
index 17c3222..3756f47 100644
--- a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
@@ -317,11 +317,11 @@
// Lazily resolve a method for portable. Called by stub code.
extern "C" const void* artPortableResolutionTrampoline(mirror::ArtMethod* called,
mirror::Object* receiver,
- Thread* thread,
+ Thread* self,
mirror::ArtMethod** called_addr)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
uint32_t dex_pc;
- mirror::ArtMethod* caller = thread->GetCurrentMethod(&dex_pc);
+ mirror::ArtMethod* caller = self->GetCurrentMethod(&dex_pc);
ClassLinker* linker = Runtime::Current()->GetClassLinker();
InvokeType invoke_type;
@@ -379,7 +379,7 @@
is_range = true;
}
uint32_t dex_method_idx = (is_range) ? instr->VRegB_3rc() : instr->VRegB_35c();
- called = linker->ResolveMethod(dex_method_idx, caller, invoke_type);
+ called = linker->ResolveMethod(Thread::Current(), dex_method_idx, &caller, invoke_type);
// Incompatible class change should have been handled in resolve method.
CHECK(!called->CheckIncompatibleClassChange(invoke_type));
// Refine called method based on receiver.
@@ -395,9 +395,9 @@
CHECK(!called->CheckIncompatibleClassChange(invoke_type));
}
const void* code = nullptr;
- if (LIKELY(!thread->IsExceptionPending())) {
+ if (LIKELY(!self->IsExceptionPending())) {
// Ensure that the called method's class is initialized.
- StackHandleScope<1> hs(Thread::Current());
+ StackHandleScope<1> hs(self);
Handle<mirror::Class> called_class(hs.NewHandle(called->GetDeclaringClass()));
linker->EnsureInitialized(called_class, true, true);
if (LIKELY(called_class->IsInitialized())) {
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index ee276c1..554bff4 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -755,11 +755,12 @@
self->EndAssertNoThreadSuspension(old_cause);
bool virtual_or_interface = invoke_type == kVirtual || invoke_type == kInterface;
// Resolve method filling in dex cache.
- if (called->IsRuntimeMethod()) {
+ if (UNLIKELY(called->IsRuntimeMethod())) {
StackHandleScope<1> hs(self);
- Handle<mirror::Object> handle_scope_receiver(hs.NewHandle(virtual_or_interface ? receiver : nullptr));
- called = linker->ResolveMethod(dex_method_idx, caller, invoke_type);
- receiver = handle_scope_receiver.Get();
+ mirror::Object* dummy = nullptr;
+ HandleWrapper<mirror::Object> h_receiver(
+ hs.NewHandleWrapper(virtual_or_interface ? &receiver : &dummy));
+ called = linker->ResolveMethod(self, dex_method_idx, &caller, invoke_type);
}
const void* code = NULL;
if (LIKELY(!self->IsExceptionPending())) {
@@ -1313,7 +1314,7 @@
&cur_stack_arg_, &cur_gpr_reg_, &cur_fpr_reg_, &code_return_,
&alloca_used_size_);
handle_scope_number_of_references_ = 0;
- cur_hs_entry_ = reinterpret_cast<StackReference<mirror::Object>*>(GetFirstHandleScopeEntry());
+ cur_hs_entry_ = GetFirstHandleScopeEntry();
// jni environment is always first argument
sm_.AdvancePointer(self->GetJniEnv());
@@ -1327,7 +1328,13 @@
void FinalizeHandleScope(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- jobject GetFirstHandleScopeEntry() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ StackReference<mirror::Object>* GetFirstHandleScopeEntry()
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return handle_scope_->GetHandle(0).GetReference();
+ }
+
+ jobject GetFirstHandleScopeJObject()
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return handle_scope_->GetHandle(0).ToJObject();
}
@@ -1502,7 +1509,7 @@
// Start JNI, save the cookie.
uint32_t cookie;
if (called->IsSynchronized()) {
- cookie = JniMethodStartSynchronized(visitor.GetFirstHandleScopeEntry(), self);
+ cookie = JniMethodStartSynchronized(visitor.GetFirstHandleScopeJObject(), self);
if (self->IsExceptionPending()) {
self->PopHandleScope();
// A negative value denotes an error.
@@ -1530,7 +1537,7 @@
DCHECK(self->IsExceptionPending()); // There should be an exception pending now.
// End JNI, as the assembly will move to deliver the exception.
- jobject lock = called->IsSynchronized() ? visitor.GetFirstHandleScopeEntry() : nullptr;
+ jobject lock = called->IsSynchronized() ? visitor.GetFirstHandleScopeJObject() : nullptr;
if (mh.GetShorty()[0] == 'L') {
artQuickGenericJniEndJNIRef(self, cookie, nullptr, lock);
} else {
@@ -1681,7 +1688,8 @@
ScopedObjectAccessUnchecked soa(self->GetJniEnv());
RememberForGcArgumentVisitor visitor(sp, type == kStatic, shorty, shorty_len, &soa);
visitor.VisitArguments();
- method = FindMethodFromCode<type, access_check>(method_idx, this_object, caller_method, self);
+ method = FindMethodFromCode<type, access_check>(method_idx, &this_object, &caller_method,
+ self);
visitor.FixupReferences();
}
@@ -1871,7 +1879,7 @@
ScopedObjectAccessUnchecked soa(self->GetJniEnv());
RememberForGcArgumentVisitor visitor(sp, false, shorty, shorty_len, &soa);
visitor.VisitArguments();
- method = FindMethodFromCode<kInterface, false>(dex_method_idx, this_object, caller_method,
+ method = FindMethodFromCode<kInterface, false>(dex_method_idx, &this_object, &caller_method,
self);
visitor.FixupReferences();
}
diff --git a/runtime/gc/accounting/atomic_stack.h b/runtime/gc/accounting/atomic_stack.h
index 979970c..bd04473 100644
--- a/runtime/gc/accounting/atomic_stack.h
+++ b/runtime/gc/accounting/atomic_stack.h
@@ -35,8 +35,8 @@
class AtomicStack {
public:
// Capacity is how many elements we can store in the stack.
- static AtomicStack* Create(const std::string& name, size_t capacity) {
- std::unique_ptr<AtomicStack> mark_stack(new AtomicStack(name, capacity));
+ static AtomicStack* Create(const std::string& name, size_t growth_limit, size_t capacity) {
+ std::unique_ptr<AtomicStack> mark_stack(new AtomicStack(name, growth_limit, capacity));
mark_stack->Init();
return mark_stack.release();
}
@@ -44,7 +44,7 @@
~AtomicStack() {}
void Reset() {
- DCHECK(mem_map_.get() != NULL);
+ DCHECK(mem_map_.get() != nullptr);
DCHECK(begin_ != NULL);
front_index_.StoreRelaxed(0);
back_index_.StoreRelaxed(0);
@@ -58,20 +58,13 @@
// Beware: Mixing atomic pushes and atomic pops will cause ABA problem.
// Returns false if we overflowed the stack.
+ bool AtomicPushBackIgnoreGrowthLimit(const T& value) {
+ return AtomicPushBackInternal(value, capacity_);
+ }
+
+ // Returns false if we overflowed the stack.
bool AtomicPushBack(const T& value) {
- if (kIsDebugBuild) {
- debug_is_sorted_ = false;
- }
- int32_t index;
- do {
- index = back_index_.LoadRelaxed();
- if (UNLIKELY(static_cast<size_t>(index) >= capacity_)) {
- // Stack overflow.
- return false;
- }
- } while (!back_index_.CompareExchangeWeakRelaxed(index, index + 1));
- begin_[index] = value;
- return true;
+ return AtomicPushBackInternal(value, growth_limit_);
}
// Atomically bump the back index by the given number of
@@ -85,7 +78,7 @@
do {
index = back_index_.LoadRelaxed();
new_index = index + num_slots;
- if (UNLIKELY(static_cast<size_t>(new_index) >= capacity_)) {
+ if (UNLIKELY(static_cast<size_t>(new_index) >= growth_limit_)) {
// Stack overflow.
return false;
}
@@ -115,7 +108,7 @@
debug_is_sorted_ = false;
}
int32_t index = back_index_.LoadRelaxed();
- DCHECK_LT(static_cast<size_t>(index), capacity_);
+ DCHECK_LT(static_cast<size_t>(index), growth_limit_);
back_index_.StoreRelaxed(index + 1);
begin_[index] = value;
}
@@ -165,6 +158,7 @@
// Will clear the stack.
void Resize(size_t new_capacity) {
capacity_ = new_capacity;
+ growth_limit_ = new_capacity;
Init();
}
@@ -189,15 +183,33 @@
}
private:
- AtomicStack(const std::string& name, const size_t capacity)
+ AtomicStack(const std::string& name, size_t growth_limit, size_t capacity)
: name_(name),
back_index_(0),
front_index_(0),
- begin_(NULL),
+ begin_(nullptr),
+ growth_limit_(growth_limit),
capacity_(capacity),
debug_is_sorted_(true) {
}
+ // Returns false if we overflowed the stack.
+ bool AtomicPushBackInternal(const T& value, size_t limit) ALWAYS_INLINE {
+ if (kIsDebugBuild) {
+ debug_is_sorted_ = false;
+ }
+ int32_t index;
+ do {
+ index = back_index_.LoadRelaxed();
+ if (UNLIKELY(static_cast<size_t>(index) >= limit)) {
+ // Stack overflow.
+ return false;
+ }
+ } while (!back_index_.CompareExchangeWeakRelaxed(index, index + 1));
+ begin_[index] = value;
+ return true;
+ }
+
// Size in number of elements.
void Init() {
std::string error_msg;
@@ -213,22 +225,18 @@
// Name of the mark stack.
std::string name_;
-
// Memory mapping of the atomic stack.
std::unique_ptr<MemMap> mem_map_;
-
// Back index (index after the last element pushed).
AtomicInteger back_index_;
-
// Front index, used for implementing PopFront.
AtomicInteger front_index_;
-
// Base of the atomic stack.
T* begin_;
-
+ // Current maximum which we can push back to, must be <= capacity_.
+ size_t growth_limit_;
// Maximum number of elements.
size_t capacity_;
-
// Whether or not the stack is sorted, only updated in debug mode to avoid performance overhead.
bool debug_is_sorted_;
diff --git a/runtime/gc/heap-inl.h b/runtime/gc/heap-inl.h
index 03b72b6..58ba61b 100644
--- a/runtime/gc/heap-inl.h
+++ b/runtime/gc/heap-inl.h
@@ -137,33 +137,11 @@
inline void Heap::PushOnAllocationStack(Thread* self, mirror::Object** obj) {
if (kUseThreadLocalAllocationStack) {
- bool success = self->PushOnThreadLocalAllocationStack(*obj);
- if (UNLIKELY(!success)) {
- // Slow path. Allocate a new thread-local allocation stack.
- mirror::Object** start_address;
- mirror::Object** end_address;
- while (!allocation_stack_->AtomicBumpBack(kThreadLocalAllocationStackSize,
- &start_address, &end_address)) {
- // TODO: Add handle VerifyObject.
- StackHandleScope<1> hs(self);
- HandleWrapper<mirror::Object> wrapper(hs.NewHandleWrapper(obj));
- CollectGarbageInternal(collector::kGcTypeSticky, kGcCauseForAlloc, false);
- }
- self->SetThreadLocalAllocationStack(start_address, end_address);
- // Retry on the new thread-local allocation stack.
- success = self->PushOnThreadLocalAllocationStack(*obj);
- // Must succeed.
- CHECK(success);
+ if (UNLIKELY(!self->PushOnThreadLocalAllocationStack(*obj))) {
+ PushOnThreadLocalAllocationStackWithInternalGC(self, obj);
}
- } else {
- // This is safe to do since the GC will never free objects which are neither in the allocation
- // stack or the live bitmap.
- while (!allocation_stack_->AtomicPushBack(*obj)) {
- // TODO: Add handle VerifyObject.
- StackHandleScope<1> hs(self);
- HandleWrapper<mirror::Object> wrapper(hs.NewHandleWrapper(obj));
- CollectGarbageInternal(collector::kGcTypeSticky, kGcCauseForAlloc, false);
- }
+ } else if (UNLIKELY(!allocation_stack_->AtomicPushBack(*obj))) {
+ PushOnAllocationStackWithInternalGC(self, obj);
}
}
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index fdc4367..a6093ca 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -84,9 +84,14 @@
static constexpr double kStickyGcThroughputAdjustment = 1.0;
// Whether or not we use the free list large object space.
static constexpr bool kUseFreeListSpaceForLOS = false;
-// Whtehr or not we compact the zygote in PreZygoteFork.
+// Whether or not we compact the zygote in PreZygoteFork.
static constexpr bool kCompactZygote = kMovingCollector;
static constexpr size_t kNonMovingSpaceCapacity = 64 * MB;
+// How many reserve entries are at the end of the allocation stack, these are only needed if the
+// allocation stack overflows.
+static constexpr size_t kAllocationStackReserveSize = 1024;
+// Default mark stack size in bytes.
+static const size_t kDefaultMarkStackSize = 64 * KB;
Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max_free,
double target_utilization, double foreground_heap_growth_multiplier, size_t capacity,
@@ -295,13 +300,13 @@
// TODO: Count objects in the image space here.
num_bytes_allocated_.StoreRelaxed(0);
- // Default mark stack size in bytes.
- static const size_t default_mark_stack_size = 64 * KB;
- mark_stack_.reset(accounting::ObjectStack::Create("mark stack", default_mark_stack_size));
- allocation_stack_.reset(accounting::ObjectStack::Create("allocation stack",
- max_allocation_stack_size_));
- live_stack_.reset(accounting::ObjectStack::Create("live stack",
- max_allocation_stack_size_));
+ mark_stack_.reset(accounting::ObjectStack::Create("mark stack", kDefaultMarkStackSize,
+ kDefaultMarkStackSize));
+ const size_t alloc_stack_capacity = max_allocation_stack_size_ + kAllocationStackReserveSize;
+ allocation_stack_.reset(accounting::ObjectStack::Create(
+ "allocation stack", max_allocation_stack_size_, alloc_stack_capacity));
+ live_stack_.reset(accounting::ObjectStack::Create(
+ "live stack", max_allocation_stack_size_, alloc_stack_capacity));
// It's still too early to take a lock because there are no threads yet, but we can create locks
// now. We don't create it earlier to make it clear that you can't use locks during heap
@@ -2035,6 +2040,43 @@
const bool verify_referent_;
};
+void Heap::PushOnAllocationStackWithInternalGC(Thread* self, mirror::Object** obj) {
+ // Slow path, the allocation stack push back must have already failed.
+ DCHECK(!allocation_stack_->AtomicPushBack(*obj));
+ do {
+ // TODO: Add handle VerifyObject.
+ StackHandleScope<1> hs(self);
+ HandleWrapper<mirror::Object> wrapper(hs.NewHandleWrapper(obj));
+ // Push our object into the reserve region of the allocaiton stack. This is only required due
+ // to heap verification requiring that roots are live (either in the live bitmap or in the
+ // allocation stack).
+ CHECK(allocation_stack_->AtomicPushBackIgnoreGrowthLimit(*obj));
+ CollectGarbageInternal(collector::kGcTypeSticky, kGcCauseForAlloc, false);
+ } while (!allocation_stack_->AtomicPushBack(*obj));
+}
+
+void Heap::PushOnThreadLocalAllocationStackWithInternalGC(Thread* self, mirror::Object** obj) {
+ // Slow path, the allocation stack push back must have already failed.
+ DCHECK(!self->PushOnThreadLocalAllocationStack(*obj));
+ mirror::Object** start_address;
+ mirror::Object** end_address;
+ while (!allocation_stack_->AtomicBumpBack(kThreadLocalAllocationStackSize, &start_address,
+ &end_address)) {
+ // TODO: Add handle VerifyObject.
+ StackHandleScope<1> hs(self);
+ HandleWrapper<mirror::Object> wrapper(hs.NewHandleWrapper(obj));
+ // Push our object into the reserve region of the allocaiton stack. This is only required due
+ // to heap verification requiring that roots are live (either in the live bitmap or in the
+ // allocation stack).
+ CHECK(allocation_stack_->AtomicPushBackIgnoreGrowthLimit(*obj));
+ // Push into the reserve allocation stack.
+ CollectGarbageInternal(collector::kGcTypeSticky, kGcCauseForAlloc, false);
+ }
+ self->SetThreadLocalAllocationStack(start_address, end_address);
+ // Retry on the new thread-local allocation stack.
+ CHECK(self->PushOnThreadLocalAllocationStack(*obj)); // Must succeed.
+}
+
// Must do this with mutators suspended since we are directly accessing the allocation stacks.
size_t Heap::VerifyHeapReferences(bool verify_referents) {
Thread* self = Thread::Current();
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 887b17e..e11671b 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -698,6 +698,10 @@
// Push an object onto the allocation stack.
void PushOnAllocationStack(Thread* self, mirror::Object** obj)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void PushOnAllocationStackWithInternalGC(Thread* self, mirror::Object** obj)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void PushOnThreadLocalAllocationStackWithInternalGC(Thread* thread, mirror::Object** obj)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// What kind of concurrency behavior is the runtime after? Currently true for concurrent mark
// sweep GC, false for other GC types.
diff --git a/runtime/gc/space/large_object_space.cc b/runtime/gc/space/large_object_space.cc
index e63cc39..54a63f0 100644
--- a/runtime/gc/space/large_object_space.cc
+++ b/runtime/gc/space/large_object_space.cc
@@ -141,8 +141,10 @@
size_t LargeObjectMapSpace::Free(Thread* self, mirror::Object* ptr) {
MutexLock mu(self, lock_);
MemMaps::iterator found = mem_maps_.find(ptr);
- CHECK(found != mem_maps_.end()) << "Attempted to free large object" << ptr
- << "which was not live";
+ if (UNLIKELY(found == mem_maps_.end())) {
+ Runtime::Current()->GetHeap()->DumpSpaces(LOG(ERROR));
+ LOG(FATAL) << "Attempted to free large object " << ptr << " which was not live";
+ }
DCHECK_GE(num_bytes_allocated_, found->second->Size());
size_t allocation_size = found->second->Size();
num_bytes_allocated_ -= allocation_size;
diff --git a/runtime/handle.h b/runtime/handle.h
index 3127864..b70f651 100644
--- a/runtime/handle.h
+++ b/runtime/handle.h
@@ -53,29 +53,48 @@
reference_->Assign(reference);
return old;
}
- jobject ToJObject() const ALWAYS_INLINE {
+ jobject ToJObject() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE {
+ if (UNLIKELY(reference_->AsMirrorPtr() == nullptr)) {
+ // Special case so that we work with NullHandles.
+ return nullptr;
+ }
return reinterpret_cast<jobject>(reference_);
}
- private:
+ protected:
StackReference<T>* reference_;
template<typename S>
explicit Handle(StackReference<S>* reference)
: reference_(reinterpret_cast<StackReference<T>*>(reference)) {
}
-
template<typename S>
explicit Handle(const Handle<S>& handle)
: reference_(reinterpret_cast<StackReference<T>*>(handle.reference_)) {
}
+ StackReference<T>* GetReference() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE {
+ return reference_;
+ }
+
+ private:
+ friend class BuildGenericJniFrameVisitor;
template<class S> friend class Handle;
friend class HandleScope;
template<class S> friend class HandleWrapper;
template<size_t kNumReferences> friend class StackHandleScope;
};
+template<class T>
+class NullHandle : public Handle<T> {
+ public:
+ NullHandle() : Handle<T>(&null_ref_) {
+ }
+
+ private:
+ StackReference<T> null_ref_;
+};
+
} // namespace art
#endif // ART_RUNTIME_HANDLE_H_
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 478c74c..f77a0f6 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -524,16 +524,17 @@
ArtMethod* method = shadow_frame->GetMethod();
// Ensure static methods are initialized.
if (method->IsStatic()) {
- StackHandleScope<1> hs(self);
- Handle<Class> declaringClass(hs.NewHandle(method->GetDeclaringClass()));
- if (UNLIKELY(!declaringClass->IsInitializing())) {
- if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(declaringClass, true,
- true))) {
- DCHECK(Thread::Current()->IsExceptionPending());
+ mirror::Class* declaring_class = method->GetDeclaringClass();
+ if (UNLIKELY(!declaring_class->IsInitializing())) {
+ StackHandleScope<1> hs(self);
+ HandleWrapper<Class> h_declaring_class(hs.NewHandleWrapper(&declaring_class));
+ if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(
+ h_declaring_class, true, true))) {
+ DCHECK(self->IsExceptionPending());
self->PopShadowFrame();
return;
}
- CHECK(declaringClass->IsInitializing());
+ CHECK(h_declaring_class->IsInitializing());
}
}
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 418aff5..63ae6fd 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -296,11 +296,9 @@
// other variants that take more arguments should also be added.
std::string descriptor(DotToDescriptor(shadow_frame->GetVRegReference(arg_offset)->AsString()->ToModifiedUtf8().c_str()));
- StackHandleScope<1> hs(self);
// shadow_frame.GetMethod()->GetDeclaringClass()->GetClassLoader();
- auto class_loader = hs.NewHandle<ClassLoader>(nullptr);
- Class* found = Runtime::Current()->GetClassLinker()->FindClass(self, descriptor.c_str(),
- class_loader);
+ Class* found = Runtime::Current()->GetClassLinker()->FindClass(
+ self, descriptor.c_str(), NullHandle<mirror::ClassLoader>());
CHECK(found != NULL) << "Class.forName failed in un-started runtime for class: "
<< PrettyDescriptor(descriptor);
result->SetL(found);
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index b42af11..cfc90a6 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -29,6 +29,7 @@
#include "dex_instruction.h"
#include "entrypoints/entrypoint_utils.h"
#include "gc/accounting/card_table-inl.h"
+#include "handle_scope-inl.h"
#include "nth_caller_visitor.h"
#include "mirror/art_field-inl.h"
#include "mirror/art_method.h"
@@ -112,9 +113,10 @@
const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
const uint32_t vregC = (is_range) ? inst->VRegC_3rc() : inst->VRegC_35c();
Object* receiver = (type == kStatic) ? nullptr : shadow_frame.GetVRegReference(vregC);
- ArtMethod* const method = FindMethodFromCode<type, do_access_check>(method_idx, receiver,
- shadow_frame.GetMethod(),
- self);
+ mirror::ArtMethod* sf_method = shadow_frame.GetMethod();
+ ArtMethod* const method = FindMethodFromCode<type, do_access_check>(
+ method_idx, &receiver, &sf_method, self);
+ // The shadow frame should already be pushed, so we don't need to update it.
if (UNLIKELY(method == nullptr)) {
CHECK(self->IsExceptionPending());
result->SetJ(0);
@@ -348,6 +350,10 @@
case Primitive::kPrimNot: {
Object* reg = shadow_frame.GetVRegReference(vregA);
if (do_assignability_check && reg != nullptr) {
+ // FieldHelper::GetType can resolve classes, use a handle wrapper which will restore the
+ // object in the destructor.
+ StackHandleScope<1> hs(self);
+ HandleWrapper<mirror::Object> wrapper(hs.NewHandleWrapper(&obj));
Class* field_class = FieldHelper(f).GetType();
if (!reg->VerifierInstanceOf(field_class)) {
// This should never happen.
@@ -372,7 +378,8 @@
// Handles iput-quick, iput-wide-quick and iput-object-quick instructions.
// Returns true on success, otherwise throws an exception and returns false.
template<Primitive::Type field_type, bool transaction_active>
-static SOMETIMES_INLINE_KEYWORD bool DoIPutQuick(const ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) {
+static SOMETIMES_INLINE_KEYWORD bool DoIPutQuick(const ShadowFrame& shadow_frame,
+ const Instruction* inst, uint16_t inst_data) {
Object* obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
if (UNLIKELY(obj == nullptr)) {
// We lost the reference to the field index so we cannot get a more
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index 6f3317d..b51e1d5 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -3138,7 +3138,7 @@
}
bool JavaVMExt::LoadNativeLibrary(const std::string& path,
- const Handle<mirror::ClassLoader>& class_loader,
+ Handle<mirror::ClassLoader> class_loader,
std::string* detail) {
detail->clear();
diff --git a/runtime/jni_internal.h b/runtime/jni_internal.h
index 37195eb..7e76e11 100644
--- a/runtime/jni_internal.h
+++ b/runtime/jni_internal.h
@@ -67,7 +67,7 @@
* Returns 'true' on success. On failure, sets 'detail' to a
* human-readable description of the error.
*/
- bool LoadNativeLibrary(const std::string& path, const Handle<mirror::ClassLoader>& class_loader,
+ bool LoadNativeLibrary(const std::string& path, Handle<mirror::ClassLoader> class_loader,
std::string* detail)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/mirror/array.cc b/runtime/mirror/array.cc
index 552652c..1076643 100644
--- a/runtime/mirror/array.cc
+++ b/runtime/mirror/array.cc
@@ -42,8 +42,8 @@
// Recursively create an array with multiple dimensions. Elements may be
// Objects or primitive types.
static Array* RecursiveCreateMultiArray(Thread* self,
- const Handle<Class>& array_class, int current_dimension,
- const Handle<mirror::IntArray>& dimensions)
+ Handle<Class> array_class, int current_dimension,
+ Handle<mirror::IntArray> dimensions)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
int32_t array_length = dimensions->Get(current_dimension);
StackHandleScope<1> hs(self);
@@ -73,8 +73,8 @@
return new_array.Get();
}
-Array* Array::CreateMultiArray(Thread* self, const Handle<Class>& element_class,
- const Handle<IntArray>& dimensions) {
+Array* Array::CreateMultiArray(Thread* self, Handle<Class> element_class,
+ Handle<IntArray> dimensions) {
// Verify dimensions.
//
// The caller is responsible for verifying that "dimArray" is non-null
diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h
index 1b8106e..64e2317 100644
--- a/runtime/mirror/array.h
+++ b/runtime/mirror/array.h
@@ -38,8 +38,8 @@
bool fill_usable = false)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static Array* CreateMultiArray(Thread* self, const Handle<Class>& element_class,
- const Handle<IntArray>& dimensions)
+ static Array* CreateMultiArray(Thread* self, Handle<Class> element_class,
+ Handle<IntArray> dimensions)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc
index af544fd..e2d3f41 100644
--- a/runtime/mirror/art_method.cc
+++ b/runtime/mirror/art_method.cc
@@ -229,7 +229,7 @@
return 0;
}
-uint32_t ArtMethod::FindCatchBlock(Handle<Class>& exception_type, uint32_t dex_pc,
+uint32_t ArtMethod::FindCatchBlock(Handle<Class> exception_type, uint32_t dex_pc,
bool* has_no_move_exception, bool* exc_changed) {
MethodHelper mh(this);
const DexFile::CodeItem* code_item = mh.GetCodeItem();
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index 34fe0bf..2e8253f 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -401,7 +401,7 @@
// In the process of finding a catch block we might trigger resolution errors. This is flagged
// by exc_changed, which indicates that a different exception is now stored in the thread and
// should be reloaded.
- uint32_t FindCatchBlock(Handle<Class>& exception_type, uint32_t dex_pc,
+ uint32_t FindCatchBlock(Handle<Class> exception_type, uint32_t dex_pc,
bool* has_no_move_exception, bool* exc_changed)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/mirror/stack_trace_element.cc b/runtime/mirror/stack_trace_element.cc
index d8591cc..b1de2b6 100644
--- a/runtime/mirror/stack_trace_element.cc
+++ b/runtime/mirror/stack_trace_element.cc
@@ -39,10 +39,8 @@
java_lang_StackTraceElement_ = NULL;
}
-StackTraceElement* StackTraceElement::Alloc(Thread* self,
- Handle<String>& declaring_class,
- Handle<String>& method_name,
- Handle<String>& file_name,
+StackTraceElement* StackTraceElement::Alloc(Thread* self, Handle<String> declaring_class,
+ Handle<String> method_name, Handle<String> file_name,
int32_t line_number) {
StackTraceElement* trace =
down_cast<StackTraceElement*>(GetStackTraceElement()->AllocObject(self));
@@ -57,8 +55,8 @@
}
template<bool kTransactionActive>
-void StackTraceElement::Init(Handle<String>& declaring_class, Handle<String>& method_name,
- Handle<String>& file_name, int32_t line_number) {
+void StackTraceElement::Init(Handle<String> declaring_class, Handle<String> method_name,
+ Handle<String> file_name, int32_t line_number) {
SetFieldObject<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, declaring_class_),
declaring_class.Get());
SetFieldObject<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, method_name_),
diff --git a/runtime/mirror/stack_trace_element.h b/runtime/mirror/stack_trace_element.h
index 22d9b71..e094e8b 100644
--- a/runtime/mirror/stack_trace_element.h
+++ b/runtime/mirror/stack_trace_element.h
@@ -46,10 +46,8 @@
return GetField32(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, line_number_));
}
- static StackTraceElement* Alloc(Thread* self,
- Handle<String>& declaring_class,
- Handle<String>& method_name,
- Handle<String>& file_name,
+ static StackTraceElement* Alloc(Thread* self, Handle<String> declaring_class,
+ Handle<String> method_name, Handle<String> file_name,
int32_t line_number)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -70,8 +68,8 @@
int32_t line_number_;
template<bool kTransactionActive>
- void Init(Handle<String>& declaring_class, Handle<String>& method_name,
- Handle<String>& file_name, int32_t line_number)
+ void Init(Handle<String> declaring_class, Handle<String> method_name, Handle<String> file_name,
+ int32_t line_number)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static Class* java_lang_StackTraceElement_;
diff --git a/runtime/mirror/string.cc b/runtime/mirror/string.cc
index ee719b4..1d79106 100644
--- a/runtime/mirror/string.cc
+++ b/runtime/mirror/string.cc
@@ -131,7 +131,7 @@
return Alloc(self, array);
}
-String* String::Alloc(Thread* self, const Handle<CharArray>& array) {
+String* String::Alloc(Thread* self, Handle<CharArray> array) {
// Hold reference in case AllocObject causes GC.
String* string = down_cast<String*>(GetJavaLangString()->AllocObject(self));
if (LIKELY(string != nullptr)) {
diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h
index 169b671..6c3015f 100644
--- a/runtime/mirror/string.h
+++ b/runtime/mirror/string.h
@@ -137,7 +137,7 @@
static String* Alloc(Thread* self, int32_t utf16_length)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static String* Alloc(Thread* self, const Handle<CharArray>& array)
+ static String* Alloc(Thread* self, Handle<CharArray> array)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void SetArray(CharArray* new_array) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index c53520d..58e6dd4 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -637,7 +637,7 @@
}
}
-void Monitor::InflateThinLocked(Thread* self, Handle<mirror::Object>& obj, LockWord lock_word,
+void Monitor::InflateThinLocked(Thread* self, Handle<mirror::Object> obj, LockWord lock_word,
uint32_t hash_code) {
DCHECK_EQ(lock_word.GetState(), LockWord::kThinLocked);
uint32_t owner_thread_id = lock_word.ThinLockOwner();
@@ -983,7 +983,7 @@
// Ask the verifier for the dex pcs of all the monitor-enter instructions corresponding to
// the locks held in this stack frame.
std::vector<uint32_t> monitor_enter_dex_pcs;
- verifier::MethodVerifier::FindLocksAtDexPc(m, stack_visitor->GetDexPc(), monitor_enter_dex_pcs);
+ verifier::MethodVerifier::FindLocksAtDexPc(m, stack_visitor->GetDexPc(), &monitor_enter_dex_pcs);
if (monitor_enter_dex_pcs.empty()) {
return;
}
diff --git a/runtime/monitor.h b/runtime/monitor.h
index 7af2d4c..9e6d255 100644
--- a/runtime/monitor.h
+++ b/runtime/monitor.h
@@ -116,7 +116,7 @@
return monitor_id_;
}
- static void InflateThinLocked(Thread* self, Handle<mirror::Object>& obj, LockWord lock_word,
+ static void InflateThinLocked(Thread* self, Handle<mirror::Object> obj, LockWord lock_word,
uint32_t hash_code) NO_THREAD_SAFETY_ANALYSIS;
static bool Deflate(Thread* self, mirror::Object* obj)
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index d9c9b59..d55b545 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -221,7 +221,7 @@
}
// Based on ClassLinker::ResolveString.
-static void PreloadDexCachesResolveString(Handle<mirror::DexCache>& dex_cache, uint32_t string_idx,
+static void PreloadDexCachesResolveString(Handle<mirror::DexCache> dex_cache, uint32_t string_idx,
StringTable& strings)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::String* string = dex_cache->GetResolvedString(string_idx);
@@ -267,8 +267,7 @@
}
// Based on ClassLinker::ResolveField.
-static void PreloadDexCachesResolveField(Handle<mirror::DexCache>& dex_cache,
- uint32_t field_idx,
+static void PreloadDexCachesResolveField(Handle<mirror::DexCache> dex_cache, uint32_t field_idx,
bool is_static)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::ArtField* field = dex_cache->GetResolvedField(field_idx);
@@ -296,8 +295,7 @@
}
// Based on ClassLinker::ResolveMethod.
-static void PreloadDexCachesResolveMethod(Handle<mirror::DexCache>& dex_cache,
- uint32_t method_idx,
+static void PreloadDexCachesResolveMethod(Handle<mirror::DexCache> dex_cache, uint32_t method_idx,
InvokeType invoke_type)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::ArtMethod* method = dex_cache->GetResolvedMethod(method_idx);
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 4863b83..b5c07aa 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -121,8 +121,8 @@
}
MethodVerifier::FailureKind MethodVerifier::VerifyClass(const DexFile* dex_file,
- Handle<mirror::DexCache>& dex_cache,
- Handle<mirror::ClassLoader>& class_loader,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader,
const DexFile::ClassDef* class_def,
bool allow_soft_failures,
std::string* error) {
@@ -151,7 +151,8 @@
previous_direct_method_idx = method_idx;
InvokeType type = it.GetMethodInvokeType(*class_def);
mirror::ArtMethod* method =
- linker->ResolveMethod(*dex_file, method_idx, dex_cache, class_loader, NULL, type);
+ linker->ResolveMethod(*dex_file, method_idx, dex_cache, class_loader,
+ NullHandle<mirror::ArtMethod>(), type);
if (method == NULL) {
DCHECK(Thread::Current()->IsExceptionPending());
// We couldn't resolve the method, but continue regardless.
@@ -165,7 +166,8 @@
it.GetMethodCodeItem(),
method,
it.GetMemberAccessFlags(),
- allow_soft_failures);
+ allow_soft_failures,
+ false);
if (result != kNoFailure) {
if (result == kHardFailure) {
hard_fail = true;
@@ -193,7 +195,8 @@
previous_virtual_method_idx = method_idx;
InvokeType type = it.GetMethodInvokeType(*class_def);
mirror::ArtMethod* method =
- linker->ResolveMethod(*dex_file, method_idx, dex_cache, class_loader, NULL, type);
+ linker->ResolveMethod(*dex_file, method_idx, dex_cache, class_loader,
+ NullHandle<mirror::ArtMethod>(), type);
if (method == NULL) {
DCHECK(Thread::Current()->IsExceptionPending());
// We couldn't resolve the method, but continue regardless.
@@ -207,7 +210,8 @@
it.GetMethodCodeItem(),
method,
it.GetMemberAccessFlags(),
- allow_soft_failures);
+ allow_soft_failures,
+ false);
if (result != kNoFailure) {
if (result == kHardFailure) {
hard_fail = true;
@@ -232,38 +236,40 @@
MethodVerifier::FailureKind MethodVerifier::VerifyMethod(uint32_t method_idx,
const DexFile* dex_file,
- Handle<mirror::DexCache>& dex_cache,
- Handle<mirror::ClassLoader>& class_loader,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader,
const DexFile::ClassDef* class_def,
const DexFile::CodeItem* code_item,
mirror::ArtMethod* method,
uint32_t method_access_flags,
- bool allow_soft_failures) {
+ bool allow_soft_failures,
+ bool need_precise_constants) {
MethodVerifier::FailureKind result = kNoFailure;
uint64_t start_ns = NanoTime();
- MethodVerifier verifier_(dex_file, &dex_cache, &class_loader, class_def, code_item,
- method_idx, method, method_access_flags, true, allow_soft_failures);
- if (verifier_.Verify()) {
+ MethodVerifier verifier(dex_file, &dex_cache, &class_loader, class_def, code_item,
+ method_idx, method, method_access_flags, true, allow_soft_failures,
+ need_precise_constants);
+ if (verifier.Verify()) {
// Verification completed, however failures may be pending that didn't cause the verification
// to hard fail.
- CHECK(!verifier_.have_pending_hard_failure_);
- if (verifier_.failures_.size() != 0) {
+ CHECK(!verifier.have_pending_hard_failure_);
+ if (verifier.failures_.size() != 0) {
if (VLOG_IS_ON(verifier)) {
- verifier_.DumpFailures(VLOG_STREAM(verifier) << "Soft verification failures in "
+ verifier.DumpFailures(VLOG_STREAM(verifier) << "Soft verification failures in "
<< PrettyMethod(method_idx, *dex_file) << "\n");
}
result = kSoftFailure;
}
} else {
// Bad method data.
- CHECK_NE(verifier_.failures_.size(), 0U);
- CHECK(verifier_.have_pending_hard_failure_);
- verifier_.DumpFailures(LOG(INFO) << "Verification error in "
+ CHECK_NE(verifier.failures_.size(), 0U);
+ CHECK(verifier.have_pending_hard_failure_);
+ verifier.DumpFailures(LOG(INFO) << "Verification error in "
<< PrettyMethod(method_idx, *dex_file) << "\n");
if (gDebugVerify) {
- std::cout << "\n" << verifier_.info_messages_.str();
- verifier_.Dump(std::cout);
+ std::cout << "\n" << verifier.info_messages_.str();
+ verifier.Dump(std::cout);
}
result = kHardFailure;
}
@@ -277,14 +283,14 @@
void MethodVerifier::VerifyMethodAndDump(std::ostream& os, uint32_t dex_method_idx,
const DexFile* dex_file,
- Handle<mirror::DexCache>& dex_cache,
- Handle<mirror::ClassLoader>& class_loader,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader,
const DexFile::ClassDef* class_def,
const DexFile::CodeItem* code_item,
mirror::ArtMethod* method,
uint32_t method_access_flags) {
MethodVerifier verifier(dex_file, &dex_cache, &class_loader, class_def, code_item,
- dex_method_idx, method, method_access_flags, true, true);
+ dex_method_idx, method, method_access_flags, true, true, true);
verifier.Verify();
verifier.DumpFailures(os);
os << verifier.info_messages_.str();
@@ -296,7 +302,8 @@
const DexFile::ClassDef* class_def,
const DexFile::CodeItem* code_item, uint32_t dex_method_idx,
mirror::ArtMethod* method, uint32_t method_access_flags,
- bool can_load_classes, bool allow_soft_failures)
+ bool can_load_classes, bool allow_soft_failures,
+ bool need_precise_constants)
: reg_types_(can_load_classes),
work_insn_idx_(-1),
dex_method_idx_(dex_method_idx),
@@ -317,6 +324,7 @@
monitor_enter_count_(0),
can_load_classes_(can_load_classes),
allow_soft_failures_(allow_soft_failures),
+ need_precise_constants_(need_precise_constants),
has_check_casts_(false),
has_virtual_or_interface_invokes_(false) {
Runtime::Current()->AddMethodVerifier(this);
@@ -329,16 +337,16 @@
}
void MethodVerifier::FindLocksAtDexPc(mirror::ArtMethod* m, uint32_t dex_pc,
- std::vector<uint32_t>& monitor_enter_dex_pcs) {
+ std::vector<uint32_t>* monitor_enter_dex_pcs) {
MethodHelper mh(m);
StackHandleScope<2> hs(Thread::Current());
Handle<mirror::DexCache> dex_cache(hs.NewHandle(mh.GetDexCache()));
Handle<mirror::ClassLoader> class_loader(hs.NewHandle(mh.GetClassLoader()));
MethodVerifier verifier(&mh.GetDexFile(), &dex_cache, &class_loader, &mh.GetClassDef(),
mh.GetCodeItem(), m->GetDexMethodIndex(), m, m->GetAccessFlags(), false,
- true);
+ true, false);
verifier.interesting_dex_pc_ = dex_pc;
- verifier.monitor_enter_dex_pcs_ = &monitor_enter_dex_pcs;
+ verifier.monitor_enter_dex_pcs_ = monitor_enter_dex_pcs;
verifier.FindLocksAtDexPc();
}
@@ -354,14 +362,14 @@
}
mirror::ArtField* MethodVerifier::FindAccessedFieldAtDexPc(mirror::ArtMethod* m,
- uint32_t dex_pc) {
+ uint32_t dex_pc) {
MethodHelper mh(m);
StackHandleScope<2> hs(Thread::Current());
Handle<mirror::DexCache> dex_cache(hs.NewHandle(mh.GetDexCache()));
Handle<mirror::ClassLoader> class_loader(hs.NewHandle(mh.GetClassLoader()));
MethodVerifier verifier(&mh.GetDexFile(), &dex_cache, &class_loader, &mh.GetClassDef(),
mh.GetCodeItem(), m->GetDexMethodIndex(), m, m->GetAccessFlags(), true,
- true);
+ true, false);
return verifier.FindAccessedFieldAtDexPc(dex_pc);
}
@@ -392,7 +400,7 @@
Handle<mirror::ClassLoader> class_loader(hs.NewHandle(mh.GetClassLoader()));
MethodVerifier verifier(&mh.GetDexFile(), &dex_cache, &class_loader, &mh.GetClassDef(),
mh.GetCodeItem(), m->GetDexMethodIndex(), m, m->GetAccessFlags(), true,
- true);
+ true, false);
return verifier.FindInvokedMethodAtDexPc(dex_pc);
}
@@ -1436,9 +1444,6 @@
std::unique_ptr<RegisterLine> branch_line;
std::unique_ptr<RegisterLine> fallthrough_line;
- // We need precise constant types only for deoptimization which happens at runtime.
- const bool need_precise_constant = !Runtime::Current()->IsCompiler();
-
switch (inst->Opcode()) {
case Instruction::NOP:
/*
@@ -1590,25 +1595,25 @@
case Instruction::CONST_4: {
int32_t val = static_cast<int32_t>(inst->VRegB_11n() << 28) >> 28;
work_line_->SetRegisterType(inst->VRegA_11n(),
- DetermineCat1Constant(val, need_precise_constant));
+ DetermineCat1Constant(val, need_precise_constants_));
break;
}
case Instruction::CONST_16: {
int16_t val = static_cast<int16_t>(inst->VRegB_21s());
work_line_->SetRegisterType(inst->VRegA_21s(),
- DetermineCat1Constant(val, need_precise_constant));
+ DetermineCat1Constant(val, need_precise_constants_));
break;
}
case Instruction::CONST: {
int32_t val = inst->VRegB_31i();
work_line_->SetRegisterType(inst->VRegA_31i(),
- DetermineCat1Constant(val, need_precise_constant));
+ DetermineCat1Constant(val, need_precise_constants_));
break;
}
case Instruction::CONST_HIGH16: {
int32_t val = static_cast<int32_t>(inst->VRegB_21h() << 16);
work_line_->SetRegisterType(inst->VRegA_21h(),
- DetermineCat1Constant(val, need_precise_constant));
+ DetermineCat1Constant(val, need_precise_constants_));
break;
}
/* could be long or double; resolved upon use */
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index 495d3c5..a23e80d 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -142,15 +142,15 @@
/* Verify a class. Returns "kNoFailure" on success. */
static FailureKind VerifyClass(mirror::Class* klass, bool allow_soft_failures, std::string* error)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- static FailureKind VerifyClass(const DexFile* dex_file, Handle<mirror::DexCache>& dex_cache,
- Handle<mirror::ClassLoader>& class_loader,
+ static FailureKind VerifyClass(const DexFile* dex_file, Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader,
const DexFile::ClassDef* class_def,
bool allow_soft_failures, std::string* error)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static void VerifyMethodAndDump(std::ostream& os, uint32_t method_idx, const DexFile* dex_file,
- Handle<mirror::DexCache>& dex_cache,
- Handle<mirror::ClassLoader>& class_loader,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader,
const DexFile::ClassDef* class_def,
const DexFile::CodeItem* code_item,
mirror::ArtMethod* method, uint32_t method_access_flags)
@@ -185,7 +185,7 @@
// Fills 'monitor_enter_dex_pcs' with the dex pcs of the monitor-enter instructions corresponding
// to the locks held at 'dex_pc' in method 'm'.
static void FindLocksAtDexPc(mirror::ArtMethod* m, uint32_t dex_pc,
- std::vector<uint32_t>& monitor_enter_dex_pcs)
+ std::vector<uint32_t>* monitor_enter_dex_pcs)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Returns the accessed field corresponding to the quick instruction's field
@@ -208,7 +208,8 @@
MethodVerifier(const DexFile* dex_file, Handle<mirror::DexCache>* dex_cache,
Handle<mirror::ClassLoader>* class_loader, const DexFile::ClassDef* class_def,
const DexFile::CodeItem* code_item, uint32_t method_idx, mirror::ArtMethod* method,
- uint32_t access_flags, bool can_load_classes, bool allow_soft_failures)
+ uint32_t access_flags, bool can_load_classes, bool allow_soft_failures,
+ bool need_precise_constants)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
~MethodVerifier();
@@ -255,12 +256,12 @@
* for code flow problems.
*/
static FailureKind VerifyMethod(uint32_t method_idx, const DexFile* dex_file,
- Handle<mirror::DexCache>& dex_cache,
- Handle<mirror::ClassLoader>& class_loader,
+ Handle<mirror::DexCache> dex_cache,
+ Handle<mirror::ClassLoader> class_loader,
const DexFile::ClassDef* class_def_idx,
const DexFile::CodeItem* code_item,
mirror::ArtMethod* method, uint32_t method_access_flags,
- bool allow_soft_failures)
+ bool allow_soft_failures, bool need_precise_constants)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void FindLocksAtDexPc() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -672,6 +673,12 @@
// running and the verifier is called from the class linker.
const bool allow_soft_failures_;
+ // An optimization where instead of generating unique RegTypes for constants we use imprecise
+ // constants that cover a range of constants. This isn't good enough for deoptimization that
+ // avoids loading from registers in the case of a constant as the dex instruction set lost the
+ // notion of whether a value should be in a floating point or general purpose register file.
+ const bool need_precise_constants_;
+
// Indicates the method being verified contains at least one check-cast or aput-object
// instruction. Aput-object operations implicitly check for array-store exceptions, similar to
// check-cast.
diff --git a/test/079-phantom/src/Bitmap.java b/test/079-phantom/src/Bitmap.java
index 9d03cbd..85eb3cc 100644
--- a/test/079-phantom/src/Bitmap.java
+++ b/test/079-phantom/src/Bitmap.java
@@ -29,6 +29,7 @@
new ReferenceQueue<PhantomWrapper>();
private static BitmapWatcher sWatcher = new BitmapWatcher(sPhantomQueue);
static {
+ sWatcher.setDaemon(true);
sWatcher.start();
};