Merge "cpplint: Cleanup errors"
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index a94dbe9..cc452fc 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -112,9 +112,10 @@
void DexCompiler::Compile() {
DCHECK_EQ(dex_to_dex_compilation_level_, DexToDexCompilationLevel::kOptimize);
- for (CodeItemIterator it(*unit_.GetCodeItem()); !it.Done(); it.Advance()) {
- Instruction* inst = const_cast<Instruction*>(&it.CurrentInstruction());
- const uint32_t dex_pc = it.CurrentDexPc();
+ IterationRange<DexInstructionIterator> instructions = unit_.GetCodeItem()->Instructions();
+ for (DexInstructionIterator it = instructions.begin(); it != instructions.end(); ++it) {
+ const uint32_t dex_pc = it.DexPc();
+ Instruction* inst = const_cast<Instruction*>(&it.Inst());
switch (inst->Opcode()) {
case Instruction::RETURN_VOID:
CompileReturnVoid(inst, dex_pc);
@@ -125,7 +126,7 @@
if (inst->Opcode() == Instruction::NOP) {
// We turned the CHECK_CAST into two NOPs, avoid visiting the second NOP twice since this
// would add 2 quickening info entries.
- it.Advance();
+ ++it;
}
break;
@@ -362,8 +363,8 @@
if (kIsDebugBuild) {
// Double check that the counts line up with the size of the quicken info.
size_t quicken_count = 0;
- for (CodeItemIterator it(*code_item); !it.Done(); it.Advance()) {
- if (QuickenInfoTable::NeedsIndexForInstruction(&it.CurrentInstruction())) {
+ for (const DexInstructionPcPair& pair : code_item->Instructions()) {
+ if (QuickenInfoTable::NeedsIndexForInstruction(&pair.Inst())) {
++quicken_count;
}
}
diff --git a/compiler/optimizing/block_builder.cc b/compiler/optimizing/block_builder.cc
index d7def77..595dd4d 100644
--- a/compiler/optimizing/block_builder.cc
+++ b/compiler/optimizing/block_builder.cc
@@ -76,9 +76,10 @@
// Iterate over all instructions and find branching instructions. Create blocks for
// the locations these instructions branch to.
- for (CodeItemIterator it(code_item_); !it.Done(); it.Advance()) {
- uint32_t dex_pc = it.CurrentDexPc();
- const Instruction& instruction = it.CurrentInstruction();
+ IterationRange<DexInstructionIterator> instructions = code_item_.Instructions();
+ for (const DexInstructionPcPair& pair : instructions) {
+ const uint32_t dex_pc = pair.DexPc();
+ const Instruction& instruction = pair.Inst();
if (instruction.IsBranch()) {
number_of_branches_++;
@@ -105,13 +106,13 @@
}
if (instruction.CanFlowThrough()) {
- if (it.IsLast()) {
+ DexInstructionIterator next(std::next(DexInstructionIterator(pair)));
+ if (next == instructions.end()) {
// In the normal case we should never hit this but someone can artificially forge a dex
// file to fall-through out the method code. In this case we bail out compilation.
return false;
- } else {
- MaybeCreateBlockAt(dex_pc + it.CurrentInstruction().SizeInCodeUnits());
}
+ MaybeCreateBlockAt(next.DexPc());
}
}
@@ -126,8 +127,9 @@
bool is_throwing_block = false;
// Calculate the qucikening index here instead of CreateBranchTargets since it's easier to
// calculate in dex_pc order.
- for (CodeItemIterator it(code_item_); !it.Done(); it.Advance()) {
- uint32_t dex_pc = it.CurrentDexPc();
+ for (const DexInstructionPcPair& pair : code_item_.Instructions()) {
+ const uint32_t dex_pc = pair.DexPc();
+ const Instruction& instruction = pair.Inst();
// Check if this dex_pc address starts a new basic block.
HBasicBlock* next_block = GetBlockAt(dex_pc);
@@ -144,7 +146,7 @@
graph_->AddBlock(block);
}
// Make sure to increment this before the continues.
- if (QuickenInfoTable::NeedsIndexForInstruction(&it.CurrentInstruction())) {
+ if (QuickenInfoTable::NeedsIndexForInstruction(&instruction)) {
++quicken_index;
}
@@ -153,8 +155,6 @@
continue;
}
- const Instruction& instruction = it.CurrentInstruction();
-
if (!is_throwing_block && IsThrowingDexInstruction(instruction)) {
DCHECK(!ContainsElement(throwing_blocks_, block));
is_throwing_block = true;
@@ -185,9 +185,9 @@
continue;
}
+ // Go to the next instruction in case we read dex PC below.
if (instruction.CanFlowThrough()) {
- uint32_t next_dex_pc = dex_pc + instruction.SizeInCodeUnits();
- block->AddSuccessor(GetBlockAt(next_dex_pc));
+ block->AddSuccessor(GetBlockAt(std::next(DexInstructionIterator(pair)).DexPc()));
}
// The basic block ends here. Do not add any more instructions.
@@ -229,7 +229,7 @@
}
}
- const Instruction& first = GetDexInstructionAt(code_item_, catch_block->GetDexPc());
+ const Instruction& first = code_item_.InstructionAt(catch_block->GetDexPc());
if (first.Opcode() == Instruction::MOVE_EXCEPTION) {
// Verifier guarantees that if a catch block begins with MOVE_EXCEPTION then
// it has no live normal predecessors.
diff --git a/compiler/optimizing/escape.cc b/compiler/optimizing/escape.cc
index 9df5bf1..0a92703 100644
--- a/compiler/optimizing/escape.cc
+++ b/compiler/optimizing/escape.cc
@@ -36,6 +36,12 @@
*is_singleton = true;
*is_singleton_and_not_returned = true;
*is_singleton_and_not_deopt_visible = true;
+
+ if (reference->IsNewInstance() && reference->AsNewInstance()->IsFinalizable()) {
+ // Finalizable reference is treated as being returned in the end.
+ *is_singleton_and_not_returned = false;
+ }
+
// Visit all uses to determine if this reference can escape into the heap,
// a method call, an alias, etc.
for (const HUseListNode<HInstruction*>& use : reference->GetUses()) {
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 0f0be20..8e9b818 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -321,19 +321,19 @@
quicken_index = block_builder_->GetQuickenIndex(block_dex_pc);
}
- for (CodeItemIterator it(code_item_, block_dex_pc); !it.Done(); it.Advance()) {
+ for (const DexInstructionPcPair& pair : code_item_.Instructions(block_dex_pc)) {
if (current_block_ == nullptr) {
// The previous instruction ended this block.
break;
}
- uint32_t dex_pc = it.CurrentDexPc();
+ const uint32_t dex_pc = pair.DexPc();
if (dex_pc != block_dex_pc && FindBlockStartingAt(dex_pc) != nullptr) {
// This dex_pc starts a new basic block.
break;
}
- if (current_block_->IsTryBlock() && IsThrowingDexInstruction(it.CurrentInstruction())) {
+ if (current_block_->IsTryBlock() && IsThrowingDexInstruction(pair.Inst())) {
PropagateLocalsToCatchBlocks();
}
@@ -341,11 +341,11 @@
AppendInstruction(new (allocator_) HNativeDebugInfo(dex_pc));
}
- if (!ProcessDexInstruction(it.CurrentInstruction(), dex_pc, quicken_index)) {
+ if (!ProcessDexInstruction(pair.Inst(), dex_pc, quicken_index)) {
return false;
}
- if (QuickenInfoTable::NeedsIndexForInstruction(&it.CurrentInstruction())) {
+ if (QuickenInfoTable::NeedsIndexForInstruction(&pair.Inst())) {
++quicken_index;
}
}
@@ -382,16 +382,15 @@
dex_file_->DecodeDebugPositionInfo(&code_item_, Callback::Position, locations);
// Instruction-specific tweaks.
IterationRange<DexInstructionIterator> instructions = code_item_.Instructions();
- for (DexInstructionIterator it = instructions.begin(); it != instructions.end(); ++it) {
- switch (it->Opcode()) {
+ for (const DexInstructionPcPair& inst : instructions) {
+ switch (inst->Opcode()) {
case Instruction::MOVE_EXCEPTION: {
// Stop in native debugger after the exception has been moved.
// The compiler also expects the move at the start of basic block so
// we do not want to interfere by inserting native-debug-info before it.
- locations->ClearBit(it.DexPc());
- DexInstructionIterator next = it;
- ++next;
- DCHECK(next != it);
+ locations->ClearBit(inst.DexPc());
+ DexInstructionIterator next = std::next(DexInstructionIterator(inst));
+ DCHECK(next.DexPc() != inst.DexPc());
if (next != instructions.end()) {
locations->SetBit(next.DexPc());
}
diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc
index 7dff696..a16fdc2 100644
--- a/compiler/optimizing/load_store_elimination.cc
+++ b/compiler/optimizing/load_store_elimination.cc
@@ -183,7 +183,6 @@
!location->IsValueKilledByLoopSideEffects()) {
// A removable singleton's field that's not stored into inside a loop is
// invariant throughout the loop. Nothing to do.
- DCHECK(ref_info->IsSingletonAndRemovable());
} else {
// heap value is killed by loop side effects (stored into directly, or
// due to aliasing). Or the heap value may be needed after method return
@@ -386,7 +385,7 @@
} else if (index != nullptr && ref_info->HasIndexAliasing()) {
// For array element, don't eliminate stores if the index can be aliased.
} else if (ref_info->IsSingleton()) {
- // Store into a field of a singleton. The value cannot be killed due to
+ // Store into a field/element of a singleton. The value cannot be killed due to
// aliasing/invocation. It can be redundant since future loads can
// directly get the value set by this instruction. The value can still be killed due to
// merging or loop side effects. Stores whose values are killed due to merging/loop side
@@ -394,24 +393,18 @@
// Stores whose values may be needed after method return or deoptimization
// are also removed from possibly_removed_stores_ when that is detected.
possibly_redundant = true;
- HNewInstance* new_instance = ref_info->GetReference()->AsNewInstance();
- if (new_instance != nullptr && new_instance->IsFinalizable()) {
- // Finalizable objects escape globally. Need to keep the store.
- possibly_redundant = false;
- } else {
- HLoopInformation* loop_info = instruction->GetBlock()->GetLoopInformation();
- if (loop_info != nullptr) {
- // instruction is a store in the loop so the loop must does write.
- DCHECK(side_effects_.GetLoopEffects(loop_info->GetHeader()).DoesAnyWrite());
+ HLoopInformation* loop_info = instruction->GetBlock()->GetLoopInformation();
+ if (loop_info != nullptr) {
+ // instruction is a store in the loop so the loop must does write.
+ DCHECK(side_effects_.GetLoopEffects(loop_info->GetHeader()).DoesAnyWrite());
- if (loop_info->IsDefinedOutOfTheLoop(original_ref)) {
- DCHECK(original_ref->GetBlock()->Dominates(loop_info->GetPreHeader()));
- // Keep the store since its value may be needed at the loop header.
- possibly_redundant = false;
- } else {
- // The singleton is created inside the loop. Value stored to it isn't needed at
- // the loop header. This is true for outer loops also.
- }
+ if (loop_info->IsDefinedOutOfTheLoop(original_ref)) {
+ DCHECK(original_ref->GetBlock()->Dominates(loop_info->GetPreHeader()));
+ // Keep the store since its value may be needed at the loop header.
+ possibly_redundant = false;
+ } else {
+ // The singleton is created inside the loop. Value stored to it isn't needed at
+ // the loop header. This is true for outer loops also.
}
}
}
@@ -575,9 +568,8 @@
// new_instance isn't used for field accesses. No need to process it.
return;
}
- if (ref_info->IsSingletonAndRemovable() &&
- !new_instance->IsFinalizable() &&
- !new_instance->NeedsChecks()) {
+ if (ref_info->IsSingletonAndRemovable() && !new_instance->NeedsChecks()) {
+ DCHECK(!new_instance->IsFinalizable());
singleton_new_instances_.push_back(new_instance);
}
ScopedArenaVector<HInstruction*>& heap_values =
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index a1f825b..afca26d 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -940,8 +940,8 @@
class_it.HasNext();
class_it.Next()) {
if (class_it.IsAtMethod() && class_it.GetMethodCodeItem() != nullptr) {
- for (CodeItemIterator it(*class_it.GetMethodCodeItem()); !it.Done(); it.Advance()) {
- Instruction* inst = const_cast<Instruction*>(&it.CurrentInstruction());
+ for (const DexInstructionPcPair& inst :
+ class_it.GetMethodCodeItem()->Instructions()) {
ASSERT_FALSE(inst->IsQuickened());
}
}
diff --git a/openjdkjvmti/Android.bp b/openjdkjvmti/Android.bp
index c6090ef..aef4dfc 100644
--- a/openjdkjvmti/Android.bp
+++ b/openjdkjvmti/Android.bp
@@ -35,6 +35,7 @@
"ti_class_definition.cc",
"ti_class_loader.cc",
"ti_dump.cc",
+ "ti_extension.cc",
"ti_field.cc",
"ti_heap.cc",
"ti_jni.cc",
diff --git a/openjdkjvmti/OpenjdkJvmTi.cc b/openjdkjvmti/OpenjdkJvmTi.cc
index 5f726b1..4814924 100644
--- a/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/openjdkjvmti/OpenjdkJvmTi.cc
@@ -52,6 +52,7 @@
#include "ti_breakpoint.h"
#include "ti_class.h"
#include "ti_dump.h"
+#include "ti_extension.h"
#include "ti_field.h"
#include "ti_heap.h"
#include "ti_jni.h"
@@ -1060,216 +1061,24 @@
ENSURE_VALID_ENV(env);
ENSURE_NON_NULL(extension_count_ptr);
ENSURE_NON_NULL(extensions);
-
- std::vector<jvmtiExtensionFunctionInfo> ext_vector;
-
- // Holders for allocated values.
- std::vector<JvmtiUniquePtr<char[]>> char_buffers;
- std::vector<JvmtiUniquePtr<jvmtiParamInfo[]>> param_buffers;
- std::vector<JvmtiUniquePtr<jvmtiError[]>> error_buffers;
-
- // Add a helper struct that takes an arbitrary const char*. add_extension will use Allocate
- // appropriately.
- struct CParamInfo {
- const char* name;
- jvmtiParamKind kind;
- jvmtiParamTypes base_type;
- jboolean null_ok;
- };
-
- auto add_extension = [&](jvmtiExtensionFunction func,
- const char* id,
- const char* short_description,
- jint param_count,
- const std::vector<CParamInfo>& params,
- jint error_count,
- const std::vector<jvmtiError>& errors) {
- jvmtiExtensionFunctionInfo func_info;
- jvmtiError error;
-
- func_info.func = func;
-
- JvmtiUniquePtr<char[]> id_ptr = CopyString(env, id, &error);
- if (id_ptr == nullptr) {
- return error;
- }
- func_info.id = id_ptr.get();
- char_buffers.push_back(std::move(id_ptr));
-
- JvmtiUniquePtr<char[]> descr = CopyString(env, short_description, &error);
- if (descr == nullptr) {
- return error;
- }
- func_info.short_description = descr.get();
- char_buffers.push_back(std::move(descr));
-
- func_info.param_count = param_count;
- if (param_count > 0) {
- JvmtiUniquePtr<jvmtiParamInfo[]> params_ptr =
- AllocJvmtiUniquePtr<jvmtiParamInfo[]>(env, param_count, &error);
- if (params_ptr == nullptr) {
- return error;
- }
- func_info.params = params_ptr.get();
- param_buffers.push_back(std::move(params_ptr));
-
- for (jint i = 0; i != param_count; ++i) {
- JvmtiUniquePtr<char[]> param_name = CopyString(env, params[i].name, &error);
- if (param_name == nullptr) {
- return error;
- }
- func_info.params[i].name = param_name.get();
- char_buffers.push_back(std::move(param_name));
-
- func_info.params[i].kind = params[i].kind;
- func_info.params[i].base_type = params[i].base_type;
- func_info.params[i].null_ok = params[i].null_ok;
- }
- } else {
- func_info.params = nullptr;
- }
-
- func_info.error_count = error_count;
- if (error_count > 0) {
- JvmtiUniquePtr<jvmtiError[]> errors_ptr =
- AllocJvmtiUniquePtr<jvmtiError[]>(env, error_count, &error);
- if (errors_ptr == nullptr) {
- return error;
- }
- func_info.errors = errors_ptr.get();
- error_buffers.push_back(std::move(errors_ptr));
-
- for (jint i = 0; i != error_count; ++i) {
- func_info.errors[i] = errors[i];
- }
- } else {
- func_info.errors = nullptr;
- }
-
- ext_vector.push_back(func_info);
-
- return ERR(NONE);
- };
-
- jvmtiError error;
-
- // Heap extensions.
- error = add_extension(
- reinterpret_cast<jvmtiExtensionFunction>(HeapExtensions::GetObjectHeapId),
- "com.android.art.heap.get_object_heap_id",
- "Retrieve the heap id of the the object tagged with the given argument. An "
- "arbitrary object is chosen if multiple objects exist with the same tag.",
- 2,
- { // NOLINT [whitespace/braces] [4]
- { "tag", JVMTI_KIND_IN, JVMTI_TYPE_JLONG, false},
- { "heap_id", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false}
- },
- 1,
- { JVMTI_ERROR_NOT_FOUND });
- if (error != ERR(NONE)) {
- return error;
- }
-
- error = add_extension(
- reinterpret_cast<jvmtiExtensionFunction>(HeapExtensions::GetHeapName),
- "com.android.art.heap.get_heap_name",
- "Retrieve the name of the heap with the given id.",
- 2,
- { // NOLINT [whitespace/braces] [4]
- { "heap_id", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false},
- { "heap_name", JVMTI_KIND_ALLOC_BUF, JVMTI_TYPE_CCHAR, false}
- },
- 1,
- { JVMTI_ERROR_ILLEGAL_ARGUMENT });
- if (error != ERR(NONE)) {
- return error;
- }
-
- error = add_extension(
- reinterpret_cast<jvmtiExtensionFunction>(HeapExtensions::IterateThroughHeapExt),
- "com.android.art.heap.iterate_through_heap_ext",
- "Iterate through a heap. This is equivalent to the standard IterateThroughHeap function,"
- " except for additionally passing the heap id of the current object. The jvmtiHeapCallbacks"
- " structure is reused, with the callbacks field overloaded to a signature of "
- "jint (*)(jlong, jlong, jlong*, jint length, void*, jint).",
- 4,
- { // NOLINT [whitespace/braces] [4]
- { "heap_filter", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false},
- { "klass", JVMTI_KIND_IN, JVMTI_TYPE_JCLASS, true},
- { "callbacks", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CVOID, false},
- { "user_data", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CVOID, true}
- },
- 3,
- { // NOLINT [whitespace/braces] [4]
- JVMTI_ERROR_MUST_POSSESS_CAPABILITY,
- JVMTI_ERROR_INVALID_CLASS,
- JVMTI_ERROR_NULL_POINTER
- });
- if (error != ERR(NONE)) {
- return error;
- }
-
- error = add_extension(
- reinterpret_cast<jvmtiExtensionFunction>(AllocUtil::GetGlobalJvmtiAllocationState),
- "com.android.art.alloc.get_global_jvmti_allocation_state",
- "Returns the total amount of memory currently allocated by all jvmtiEnvs through the"
- " 'Allocate' jvmti function. This does not include any memory that has been deallocated"
- " through the 'Deallocate' function. This number is approximate and might not correspond"
- " exactly to the sum of the sizes of all not freed allocations.",
- 1,
- { // NOLINT [whitespace/braces] [4]
- { "currently_allocated", JVMTI_KIND_OUT, JVMTI_TYPE_JLONG, false},
- },
- 1,
- { ERR(NULL_POINTER) });
- if (error != ERR(NONE)) {
- return error;
- }
-
- // Copy into output buffer.
-
- *extension_count_ptr = ext_vector.size();
- JvmtiUniquePtr<jvmtiExtensionFunctionInfo[]> out_data =
- AllocJvmtiUniquePtr<jvmtiExtensionFunctionInfo[]>(env, ext_vector.size(), &error);
- if (out_data == nullptr) {
- return error;
- }
- memcpy(out_data.get(),
- ext_vector.data(),
- ext_vector.size() * sizeof(jvmtiExtensionFunctionInfo));
- *extensions = out_data.release();
-
- // Release all the buffer holders, we're OK now.
- for (auto& holder : char_buffers) {
- holder.release();
- }
- for (auto& holder : param_buffers) {
- holder.release();
- }
- for (auto& holder : error_buffers) {
- holder.release();
- }
-
- return ERR(NONE);
+ return ExtensionUtil::GetExtensionFunctions(env, extension_count_ptr, extensions);
}
static jvmtiError GetExtensionEvents(jvmtiEnv* env,
jint* extension_count_ptr,
jvmtiExtensionEventInfo** extensions) {
ENSURE_VALID_ENV(env);
- // We do not have any extension events.
- *extension_count_ptr = 0;
- *extensions = nullptr;
-
- return ERR(NONE);
+ ENSURE_NON_NULL(extension_count_ptr);
+ ENSURE_NON_NULL(extensions);
+ return ExtensionUtil::GetExtensionEvents(env, extension_count_ptr, extensions);
}
static jvmtiError SetExtensionEventCallback(jvmtiEnv* env,
- jint extension_event_index ATTRIBUTE_UNUSED,
- jvmtiExtensionEvent callback ATTRIBUTE_UNUSED) {
+ jint extension_event_index,
+ jvmtiExtensionEvent callback) {
ENSURE_VALID_ENV(env);
// We do not have any extension events, so any call is illegal.
- return ERR(ILLEGAL_ARGUMENT);
+ return ExtensionUtil::SetExtensionEventCallback(env, extension_event_index, callback);
}
static jvmtiError GetPotentialCapabilities(jvmtiEnv* env, jvmtiCapabilities* capabilities_ptr) {
diff --git a/openjdkjvmti/ti_extension.cc b/openjdkjvmti/ti_extension.cc
new file mode 100644
index 0000000..fbed964
--- /dev/null
+++ b/openjdkjvmti/ti_extension.cc
@@ -0,0 +1,249 @@
+/* Copyright (C) 2017 The Android Open Source Project
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This file implements interfaces from the file jvmti.h. This implementation
+ * is licensed under the same terms as the file jvmti.h. The
+ * copyright and license information for the file jvmti.h follows.
+ *
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <vector>
+
+#include "ti_extension.h"
+
+#include "art_jvmti.h"
+#include "ti_allocator.h"
+#include "ti_heap.h"
+
+namespace openjdkjvmti {
+
+struct CParamInfo {
+ const char* name;
+ jvmtiParamKind kind;
+ jvmtiParamTypes base_type;
+ jboolean null_ok;
+
+ jvmtiParamInfo ToParamInfo(jvmtiEnv* env,
+ /*out*/std::vector<JvmtiUniquePtr<char[]>>* char_buffers,
+ /*out*/jvmtiError* err) const {
+ JvmtiUniquePtr<char[]> param_name = CopyString(env, name, err);
+ char* name_ptr = param_name.get();
+ char_buffers->push_back(std::move(param_name));
+ return jvmtiParamInfo { name_ptr, kind, base_type, null_ok }; // NOLINT [whitespace/braces] [4]
+ }
+};
+
+jvmtiError ExtensionUtil::GetExtensionFunctions(jvmtiEnv* env,
+ jint* extension_count_ptr,
+ jvmtiExtensionFunctionInfo** extensions) {
+ if (extension_count_ptr == nullptr || extensions == nullptr) {
+ return ERR(NULL_POINTER);
+ }
+
+ std::vector<jvmtiExtensionFunctionInfo> ext_vector;
+
+ // Holders for allocated values.
+ std::vector<JvmtiUniquePtr<char[]>> char_buffers;
+ std::vector<JvmtiUniquePtr<jvmtiParamInfo[]>> param_buffers;
+ std::vector<JvmtiUniquePtr<jvmtiError[]>> error_buffers;
+
+ auto add_extension = [&](jvmtiExtensionFunction func,
+ const char* id,
+ const char* short_description,
+ const std::vector<CParamInfo>& params,
+ const std::vector<jvmtiError>& errors) {
+ jvmtiExtensionFunctionInfo func_info;
+ jvmtiError error;
+
+ func_info.func = func;
+
+ JvmtiUniquePtr<char[]> id_ptr = CopyString(env, id, &error);
+ if (id_ptr == nullptr) {
+ return error;
+ }
+ func_info.id = id_ptr.get();
+ char_buffers.push_back(std::move(id_ptr));
+
+ JvmtiUniquePtr<char[]> descr = CopyString(env, short_description, &error);
+ if (descr == nullptr) {
+ return error;
+ }
+ func_info.short_description = descr.get();
+ char_buffers.push_back(std::move(descr));
+
+ func_info.param_count = params.size();
+ if (!params.empty()) {
+ JvmtiUniquePtr<jvmtiParamInfo[]> params_ptr =
+ AllocJvmtiUniquePtr<jvmtiParamInfo[]>(env, params.size(), &error);
+ if (params_ptr == nullptr) {
+ return error;
+ }
+ func_info.params = params_ptr.get();
+ param_buffers.push_back(std::move(params_ptr));
+
+ for (jint i = 0; i != func_info.param_count; ++i) {
+ func_info.params[i] = params[i].ToParamInfo(env, &char_buffers, &error);
+ if (error != OK) {
+ return error;
+ }
+ }
+ } else {
+ func_info.params = nullptr;
+ }
+
+ func_info.error_count = errors.size();
+ if (!errors.empty()) {
+ JvmtiUniquePtr<jvmtiError[]> errors_ptr =
+ AllocJvmtiUniquePtr<jvmtiError[]>(env, errors.size(), &error);
+ if (errors_ptr == nullptr) {
+ return error;
+ }
+ func_info.errors = errors_ptr.get();
+ error_buffers.push_back(std::move(errors_ptr));
+
+ for (jint i = 0; i != func_info.error_count; ++i) {
+ func_info.errors[i] = errors[i];
+ }
+ } else {
+ func_info.errors = nullptr;
+ }
+
+ ext_vector.push_back(func_info);
+
+ return ERR(NONE);
+ };
+
+ jvmtiError error;
+
+ // Heap extensions.
+ error = add_extension(
+ reinterpret_cast<jvmtiExtensionFunction>(HeapExtensions::GetObjectHeapId),
+ "com.android.art.heap.get_object_heap_id",
+ "Retrieve the heap id of the the object tagged with the given argument. An "
+ "arbitrary object is chosen if multiple objects exist with the same tag.",
+ { // NOLINT [whitespace/braces] [4]
+ { "tag", JVMTI_KIND_IN, JVMTI_TYPE_JLONG, false},
+ { "heap_id", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false}
+ },
+ { JVMTI_ERROR_NOT_FOUND });
+ if (error != ERR(NONE)) {
+ return error;
+ }
+
+ error = add_extension(
+ reinterpret_cast<jvmtiExtensionFunction>(HeapExtensions::GetHeapName),
+ "com.android.art.heap.get_heap_name",
+ "Retrieve the name of the heap with the given id.",
+ { // NOLINT [whitespace/braces] [4]
+ { "heap_id", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false},
+ { "heap_name", JVMTI_KIND_ALLOC_BUF, JVMTI_TYPE_CCHAR, false}
+ },
+ { JVMTI_ERROR_ILLEGAL_ARGUMENT });
+ if (error != ERR(NONE)) {
+ return error;
+ }
+
+ error = add_extension(
+ reinterpret_cast<jvmtiExtensionFunction>(HeapExtensions::IterateThroughHeapExt),
+ "com.android.art.heap.iterate_through_heap_ext",
+ "Iterate through a heap. This is equivalent to the standard IterateThroughHeap function,"
+ " except for additionally passing the heap id of the current object. The jvmtiHeapCallbacks"
+ " structure is reused, with the callbacks field overloaded to a signature of "
+ "jint (*)(jlong, jlong, jlong*, jint length, void*, jint).",
+ { // NOLINT [whitespace/braces] [4]
+ { "heap_filter", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false},
+ { "klass", JVMTI_KIND_IN, JVMTI_TYPE_JCLASS, true},
+ { "callbacks", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CVOID, false},
+ { "user_data", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CVOID, true}
+ },
+ { // NOLINT [whitespace/braces] [4]
+ ERR(MUST_POSSESS_CAPABILITY),
+ ERR(INVALID_CLASS),
+ ERR(NULL_POINTER),
+ });
+ if (error != ERR(NONE)) {
+ return error;
+ }
+
+ error = add_extension(
+ reinterpret_cast<jvmtiExtensionFunction>(AllocUtil::GetGlobalJvmtiAllocationState),
+ "com.android.art.alloc.get_global_jvmti_allocation_state",
+ "Returns the total amount of memory currently allocated by all jvmtiEnvs through the"
+ " 'Allocate' jvmti function. This does not include any memory that has been deallocated"
+ " through the 'Deallocate' function. This number is approximate and might not correspond"
+ " exactly to the sum of the sizes of all not freed allocations.",
+ { // NOLINT [whitespace/braces] [4]
+ { "currently_allocated", JVMTI_KIND_OUT, JVMTI_TYPE_JLONG, false},
+ },
+ { ERR(NULL_POINTER) });
+ if (error != ERR(NONE)) {
+ return error;
+ }
+
+ // Copy into output buffer.
+
+ *extension_count_ptr = ext_vector.size();
+ JvmtiUniquePtr<jvmtiExtensionFunctionInfo[]> out_data =
+ AllocJvmtiUniquePtr<jvmtiExtensionFunctionInfo[]>(env, ext_vector.size(), &error);
+ if (out_data == nullptr) {
+ return error;
+ }
+ memcpy(out_data.get(),
+ ext_vector.data(),
+ ext_vector.size() * sizeof(jvmtiExtensionFunctionInfo));
+ *extensions = out_data.release();
+
+ // Release all the buffer holders, we're OK now.
+ for (auto& holder : char_buffers) {
+ holder.release();
+ }
+ for (auto& holder : param_buffers) {
+ holder.release();
+ }
+ for (auto& holder : error_buffers) {
+ holder.release();
+ }
+
+ return OK;
+}
+
+
+jvmtiError ExtensionUtil::GetExtensionEvents(jvmtiEnv* env ATTRIBUTE_UNUSED,
+ jint* extension_count_ptr,
+ jvmtiExtensionEventInfo** extensions) {
+ // We don't have any extension events at the moment.
+ *extension_count_ptr = 0;
+ *extensions = nullptr;
+ return OK;
+}
+
+jvmtiError ExtensionUtil::SetExtensionEventCallback(jvmtiEnv* env ATTRIBUTE_UNUSED,
+ jint extension_event_index ATTRIBUTE_UNUSED,
+ jvmtiExtensionEvent callback ATTRIBUTE_UNUSED) {
+ // We do not have any extension events, so any call is illegal.
+ return ERR(ILLEGAL_ARGUMENT);
+}
+
+} // namespace openjdkjvmti
diff --git a/openjdkjvmti/ti_extension.h b/openjdkjvmti/ti_extension.h
new file mode 100644
index 0000000..d705ba7
--- /dev/null
+++ b/openjdkjvmti/ti_extension.h
@@ -0,0 +1,57 @@
+/* Copyright (C) 2017 The Android Open Source Project
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This file implements interfaces from the file jvmti.h. This implementation
+ * is licensed under the same terms as the file jvmti.h. The
+ * copyright and license information for the file jvmti.h follows.
+ *
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef ART_OPENJDKJVMTI_TI_EXTENSION_H_
+#define ART_OPENJDKJVMTI_TI_EXTENSION_H_
+
+#include "jni.h"
+#include "jvmti.h"
+
+namespace openjdkjvmti {
+
+class ExtensionUtil {
+ public:
+ static jvmtiError GetExtensionFunctions(jvmtiEnv* env,
+ jint* extension_count_ptr,
+ jvmtiExtensionFunctionInfo** extensions);
+
+ static jvmtiError GetExtensionEvents(jvmtiEnv* env,
+ jint* extension_count_ptr,
+ jvmtiExtensionEventInfo** extensions);
+
+ static jvmtiError SetExtensionEventCallback(jvmtiEnv* env,
+ jint extension_event_index,
+ jvmtiExtensionEvent callback);
+};
+
+} // namespace openjdkjvmti
+
+#endif // ART_OPENJDKJVMTI_TI_EXTENSION_H_
diff --git a/profman/profman.cc b/profman/profman.cc
index ae07784..1c50645 100644
--- a/profman/profman.cc
+++ b/profman/profman.cc
@@ -725,15 +725,15 @@
const DexFile::CodeItem* code_item = dex_file->GetCodeItem(offset);
bool found_invoke = false;
- for (CodeItemIterator it(*code_item); !it.Done(); it.Advance()) {
- if (it.CurrentInstruction().Opcode() == Instruction::INVOKE_VIRTUAL) {
+ for (const DexInstructionPcPair& inst : code_item->Instructions()) {
+ if (inst->Opcode() == Instruction::INVOKE_VIRTUAL) {
if (found_invoke) {
LOG(ERROR) << "Multiple invoke INVOKE_VIRTUAL found: "
<< dex_file->PrettyMethod(method_index);
return false;
}
found_invoke = true;
- *dex_pc = it.CurrentDexPc();
+ *dex_pc = inst.DexPc();
}
}
if (!found_invoke) {
diff --git a/runtime/bytecode_utils.h b/runtime/bytecode_utils.h
index b6a3c03..815e0ba 100644
--- a/runtime/bytecode_utils.h
+++ b/runtime/bytecode_utils.h
@@ -24,35 +24,6 @@
namespace art {
-class CodeItemIterator : public ValueObject {
- public:
- explicit CodeItemIterator(const DexFile::CodeItem& code_item) : CodeItemIterator(code_item, 0u) {}
- CodeItemIterator(const DexFile::CodeItem& code_item, uint32_t start_dex_pc)
- : code_ptr_(code_item.insns_ + start_dex_pc),
- code_end_(code_item.insns_ + code_item.insns_size_in_code_units_),
- dex_pc_(start_dex_pc) {}
-
- bool Done() const { return code_ptr_ >= code_end_; }
- bool IsLast() const { return code_ptr_ + CurrentInstruction().SizeInCodeUnits() >= code_end_; }
-
- const Instruction& CurrentInstruction() const { return *Instruction::At(code_ptr_); }
- uint32_t CurrentDexPc() const { return dex_pc_; }
-
- void Advance() {
- DCHECK(!Done());
- size_t instruction_size = CurrentInstruction().SizeInCodeUnits();
- code_ptr_ += instruction_size;
- dex_pc_ += instruction_size;
- }
-
- private:
- const uint16_t* code_ptr_;
- const uint16_t* const code_end_;
- uint32_t dex_pc_;
-
- DISALLOW_COPY_AND_ASSIGN(CodeItemIterator);
-};
-
class DexSwitchTable : public ValueObject {
public:
DexSwitchTable(const Instruction& instruction, uint32_t dex_pc)
@@ -164,10 +135,6 @@
size_t index_;
};
-inline const Instruction& GetDexInstructionAt(const DexFile::CodeItem& code_item, uint32_t dex_pc) {
- return CodeItemIterator(code_item, dex_pc).CurrentInstruction();
-}
-
inline bool IsThrowingDexInstruction(const Instruction& instruction) {
// Special-case MONITOR_EXIT which is a throwing instruction but the verifier
// guarantees that it will never throw. This is necessary to avoid rejecting
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index f239edc..5c9b258 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -301,8 +301,9 @@
// Raw code_item.
struct CodeItem {
- IterationRange<DexInstructionIterator> Instructions() const {
- return { DexInstructionIterator(insns_, 0u),
+ IterationRange<DexInstructionIterator> Instructions(uint32_t start_dex_pc = 0u) const {
+ DCHECK_LE(start_dex_pc, insns_size_in_code_units_);
+ return { DexInstructionIterator(insns_, start_dex_pc),
DexInstructionIterator(insns_, insns_size_in_code_units_) };
}
diff --git a/runtime/dex_instruction_iterator.h b/runtime/dex_instruction_iterator.h
index f77908c..be583a2 100644
--- a/runtime/dex_instruction_iterator.h
+++ b/runtime/dex_instruction_iterator.h
@@ -123,6 +123,9 @@
explicit DexInstructionIterator(const uint16_t* inst, uint32_t dex_pc)
: DexInstructionIteratorBase(Instruction::At(inst), dex_pc) {}
+ explicit DexInstructionIterator(const DexInstructionPcPair& pair)
+ : DexInstructionIterator(pair.Instructions(), pair.DexPc()) {}
+
// Value after modification.
DexInstructionIterator& operator++() {
data_.dex_pc_ += Inst().SizeInCodeUnits();
diff --git a/runtime/dex_to_dex_decompiler.cc b/runtime/dex_to_dex_decompiler.cc
index 908405b..a5ebade 100644
--- a/runtime/dex_to_dex_decompiler.cc
+++ b/runtime/dex_to_dex_decompiler.cc
@@ -89,8 +89,8 @@
// because the RETURN_VOID quickening is not encoded in the quickening data. Because
// unquickening is a rare need and not performance sensitive, it is not worth the
// added storage to also add the RETURN_VOID quickening in the quickened data.
- for (CodeItemIterator it(code_item_); !it.Done(); it.Advance()) {
- Instruction* inst = const_cast<Instruction*>(&it.CurrentInstruction());
+ for (const DexInstructionPcPair& pair : code_item_.Instructions()) {
+ Instruction* inst = const_cast<Instruction*>(&pair.Inst());
switch (inst->Opcode()) {
case Instruction::RETURN_VOID_NO_BARRIER:
diff --git a/test/530-checker-lse/src/Main.java b/test/530-checker-lse/src/Main.java
index 7ae873a..30d4970 100644
--- a/test/530-checker-lse/src/Main.java
+++ b/test/530-checker-lse/src/Main.java
@@ -62,11 +62,12 @@
class Finalizable {
static boolean sVisited = false;
- static final int VALUE = 0xbeef;
+ static final int VALUE1 = 0xbeef;
+ static final int VALUE2 = 0xcafe;
int i;
protected void finalize() {
- if (i != VALUE) {
+ if (i != VALUE1) {
System.out.println("Where is the beef?");
}
sVisited = true;
@@ -620,15 +621,18 @@
/// CHECK-START: void Main.testFinalizable() load_store_elimination (before)
/// CHECK: NewInstance
/// CHECK: InstanceFieldSet
+ /// CHECK: InstanceFieldSet
/// CHECK-START: void Main.testFinalizable() load_store_elimination (after)
/// CHECK: NewInstance
/// CHECK: InstanceFieldSet
+ /// CHECK-NOT: InstanceFieldSet
- // Allocations and stores into finalizable objects cannot be eliminated.
+ // Allocations of finalizable objects cannot be eliminated.
static void testFinalizable() {
Finalizable finalizable = new Finalizable();
- finalizable.i = Finalizable.VALUE;
+ finalizable.i = Finalizable.VALUE2;
+ finalizable.i = Finalizable.VALUE1;
}
static java.lang.ref.WeakReference<Object> getWeakReference() {
diff --git a/test/983-source-transform-verify/source_transform.cc b/test/983-source-transform-verify/source_transform.cc
index ef67ace..ca3f88b 100644
--- a/test/983-source-transform-verify/source_transform.cc
+++ b/test/983-source-transform-verify/source_transform.cc
@@ -89,13 +89,13 @@
if (!it.IsAtMethod() || it.GetMethodCodeItem() == nullptr) {
continue;
}
- for (CodeItemIterator code_it(*it.GetMethodCodeItem()); !code_it.Done(); code_it.Advance()) {
- const Instruction& inst = code_it.CurrentInstruction();
+ for (const DexInstructionPcPair& pair : it.GetMethodCodeItem()->Instructions()) {
+ const Instruction& inst = pair.Inst();
int forbiden_flags = (Instruction::kVerifyError | Instruction::kVerifyRuntimeOnly);
if (inst.Opcode() == Instruction::RETURN_VOID_NO_BARRIER ||
(inst.GetVerifyExtraFlags() & forbiden_flags) != 0) {
std::cout << "Unexpected instruction found in " << dex->PrettyMethod(it.GetMemberIndex())
- << " [Dex PC: 0x" << std::hex << code_it.CurrentDexPc() << std::dec << "] : "
+ << " [Dex PC: 0x" << std::hex << pair.DexPc() << std::dec << "] : "
<< inst.DumpString(dex.get()) << std::endl;
continue;
}
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 753fc39..31f43fc 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -545,9 +545,17 @@
bpath="${bpath}:${framework}/bouncycastle${bpath_suffix}.jar"
# Pass down the bootclasspath
FLAGS="${FLAGS} -Xbootclasspath:${bpath}"
- # Add 5 minutes to give some time to generate the boot image.
- TIME_OUT_VALUE=$((${TIME_OUT_VALUE} + 300))
- DALVIKVM_BOOT_OPT="-Ximage:/system/non-existant/core.art"
+ # Disable image dex2oat - this will forbid the runtime to patch or compile an image.
+ FLAGS="${FLAGS} -Xnoimage-dex2oat"
+
+ # We'll abuse a second flag here to test different behavior. If --relocate, use the
+ # existing image - relocation will fail as patching is disallowed. If --no-relocate,
+ # pass a non-existent image - compilation will fail as dex2oat is disallowed.
+ if [ "${RELOCATE}" = "y" ] ; then
+ DALVIKVM_BOOT_OPT="-Ximage:${BOOT_IMAGE}"
+ else
+ DALVIKVM_BOOT_OPT="-Ximage:/system/non-existant/core.art"
+ fi
else
DALVIKVM_BOOT_OPT="-Ximage:${BOOT_IMAGE}"
fi
@@ -935,6 +943,10 @@
# All tests would log the error of failing dex2oat/patchoat. Be silent here and only
# log fatal events.
export ANDROID_LOG_TAGS='*:s'
+ elif [ "$HAVE_IMAGE" = "n" ]; then
+ # All tests would log the error of missing image. Be silent here and only log fatal
+ # events.
+ export ANDROID_LOG_TAGS='*:s'
else
# We are interested in LOG(ERROR) output.
export ANDROID_LOG_TAGS='*:e'
diff --git a/test/knownfailures.json b/test/knownfailures.json
index 47b2f22..c6b6574 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -384,6 +384,12 @@
"variant": "jvmti-stress & jit | redefine-stress & jit"
},
{
+ "test_patterns": ["616-cha"],
+ "description": ["The test assumes a boot image exists."],
+ "bug": "http://b/34193647",
+ "variant": "no-image"
+ },
+ {
"tests": [ "663-odd-dex-size",
"663-odd-dex-size2",
"663-odd-dex-size3",