Merge "Allow early abort logging"
diff --git a/benchmark/jobject-benchmark/jobject_benchmark.cc b/benchmark/jobject-benchmark/jobject_benchmark.cc
index de43f73..7e0a536 100644
--- a/benchmark/jobject-benchmark/jobject_benchmark.cc
+++ b/benchmark/jobject-benchmark/jobject_benchmark.cc
@@ -29,7 +29,7 @@
ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(jobj);
CHECK(obj != nullptr);
for (jint i = 0; i < reps; ++i) {
- jobject ref = soa.Env()->AddLocalReference<jobject>(obj.Ptr());
+ jobject ref = soa.Env()->AddLocalReference<jobject>(obj);
soa.Env()->DeleteLocalRef(ref);
}
}
@@ -39,7 +39,7 @@
ScopedObjectAccess soa(env);
ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(jobj);
CHECK(obj != nullptr);
- jobject ref = soa.Env()->AddLocalReference<jobject>(obj.Ptr());
+ jobject ref = soa.Env()->AddLocalReference<jobject>(obj);
for (jint i = 0; i < reps; ++i) {
CHECK_EQ(soa.Decode<mirror::Object>(ref), obj);
}
diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc
index dca290c..6b56fe0 100644
--- a/compiler/jni/jni_compiler_test.cc
+++ b/compiler/jni/jni_compiler_test.cc
@@ -392,11 +392,13 @@
// -- TODO: We can support (1) if we remove the mutator lock assert during stub lookup.
# define JNI_TEST_NORMAL_ONLY(TestName) \
TEST_F(JniCompilerTest, TestName ## NormalCompiler) { \
+ ScopedCheckHandleScope top_handle_scope_check; \
SCOPED_TRACE("Normal JNI with compiler"); \
gCurrentJni = static_cast<uint32_t>(JniKind::kNormal); \
TestName ## Impl(); \
} \
TEST_F(JniCompilerTest, TestName ## NormalGeneric) { \
+ ScopedCheckHandleScope top_handle_scope_check; \
SCOPED_TRACE("Normal JNI with generic"); \
gCurrentJni = static_cast<uint32_t>(JniKind::kNormal); \
TEST_DISABLED_FOR_MIPS(); \
@@ -408,12 +410,14 @@
#define JNI_TEST(TestName) \
JNI_TEST_NORMAL_ONLY(TestName) \
TEST_F(JniCompilerTest, TestName ## FastCompiler) { \
+ ScopedCheckHandleScope top_handle_scope_check; \
SCOPED_TRACE("@FastNative JNI with compiler"); \
gCurrentJni = static_cast<uint32_t>(JniKind::kFast); \
TestName ## Impl(); \
} \
\
TEST_F(JniCompilerTest, TestName ## FastGeneric) { \
+ ScopedCheckHandleScope top_handle_scope_check; \
SCOPED_TRACE("@FastNative JNI with generic"); \
gCurrentJni = static_cast<uint32_t>(JniKind::kFast); \
TEST_DISABLED_FOR_MIPS(); \
@@ -424,11 +428,13 @@
// Test (@CriticalNative) x (compiler, generic) only.
#define JNI_TEST_CRITICAL_ONLY(TestName) \
TEST_F(JniCompilerTest, TestName ## CriticalCompiler) { \
+ ScopedCheckHandleScope top_handle_scope_check; \
SCOPED_TRACE("@CriticalNative JNI with compiler"); \
gCurrentJni = static_cast<uint32_t>(JniKind::kCritical); \
TestName ## Impl(); \
} \
TEST_F(JniCompilerTest, TestName ## CriticalGeneric) { \
+ ScopedCheckHandleScope top_handle_scope_check; \
SCOPED_TRACE("@CriticalNative JNI with generic"); \
gCurrentJni = static_cast<uint32_t>(JniKind::kCritical); \
SetCheckGenericJni(true); \
@@ -515,6 +521,21 @@
bool ScopedDisableCheckNumStackReferences::sCheckNumStackReferences = true;
+// Check that the handle scope at the start of this block is the same as the handle scope at the end of the block.
+struct ScopedCheckHandleScope {
+ ScopedCheckHandleScope() {
+ handle_scope_ = Thread::Current()->GetTopHandleScope();
+ }
+
+ ~ScopedCheckHandleScope() {
+ EXPECT_EQ(handle_scope_, Thread::Current()->GetTopHandleScope())
+ << "Top-most handle scope must be the same after all the JNI "
+ << "invocations have finished (as before they were invoked).";
+ }
+
+ HandleScope* handle_scope_;
+};
+
static void expectNumStackReferences(size_t val1, size_t val2) {
// In rare cases when JNI functions call themselves recursively,
// disable this test because it will have a false negative.
diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp
index 0987df7..b9266f7 100644
--- a/dexlayout/Android.bp
+++ b/dexlayout/Android.bp
@@ -21,6 +21,7 @@
"dex_ir.cc",
"dex_ir_builder.cc",
"dex_visualize.cc",
+ "dex_writer.cc",
],
cflags: ["-Wall"],
shared_libs: [
diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc
index aff03cd..bc909c3 100644
--- a/dexlayout/dex_ir.cc
+++ b/dexlayout/dex_ir.cc
@@ -55,6 +55,54 @@
entry.end_address_, entry.reg_)));
}
+static uint32_t GetDebugInfoStreamSize(const uint8_t* debug_info_stream) {
+ const uint8_t* stream = debug_info_stream;
+ DecodeUnsignedLeb128(&stream); // line_start
+ uint32_t parameters_size = DecodeUnsignedLeb128(&stream);
+ for (uint32_t i = 0; i < parameters_size; ++i) {
+ DecodeUnsignedLeb128P1(&stream); // Parameter name.
+ }
+
+ for (;;) {
+ uint8_t opcode = *stream++;
+ switch (opcode) {
+ case DexFile::DBG_END_SEQUENCE:
+ return stream - debug_info_stream; // end of stream.
+ case DexFile::DBG_ADVANCE_PC:
+ DecodeUnsignedLeb128(&stream); // addr_diff
+ break;
+ case DexFile::DBG_ADVANCE_LINE:
+ DecodeSignedLeb128(&stream); // line_diff
+ break;
+ case DexFile::DBG_START_LOCAL:
+ DecodeUnsignedLeb128(&stream); // register_num
+ DecodeUnsignedLeb128P1(&stream); // name_idx
+ DecodeUnsignedLeb128P1(&stream); // type_idx
+ break;
+ case DexFile::DBG_START_LOCAL_EXTENDED:
+ DecodeUnsignedLeb128(&stream); // register_num
+ DecodeUnsignedLeb128P1(&stream); // name_idx
+ DecodeUnsignedLeb128P1(&stream); // type_idx
+ DecodeUnsignedLeb128P1(&stream); // sig_idx
+ break;
+ case DexFile::DBG_END_LOCAL:
+ case DexFile::DBG_RESTART_LOCAL:
+ DecodeUnsignedLeb128(&stream); // register_num
+ break;
+ case DexFile::DBG_SET_PROLOGUE_END:
+ case DexFile::DBG_SET_EPILOGUE_BEGIN:
+ break;
+ case DexFile::DBG_SET_FILE: {
+ DecodeUnsignedLeb128P1(&stream); // name_idx
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+}
+
EncodedValue* Collections::ReadEncodedValue(const uint8_t** data) {
const uint8_t encoded_value = *(*data)++;
const uint8_t type = encoded_value & 0x1f;
@@ -179,7 +227,7 @@
void Collections::CreateProtoId(const DexFile& dex_file, uint32_t i) {
const DexFile::ProtoId& disk_proto_id = dex_file.GetProtoId(i);
const DexFile::TypeList* type_list = dex_file.GetProtoParameters(disk_proto_id);
- TypeList* parameter_type_list = CreateTypeList(type_list, disk_proto_id.parameters_off_, true);
+ TypeList* parameter_type_list = CreateTypeList(type_list, disk_proto_id.parameters_off_);
ProtoId* proto_id = new ProtoId(GetStringId(disk_proto_id.shorty_idx_),
GetTypeId(disk_proto_id.return_type_idx_),
@@ -210,7 +258,7 @@
const TypeId* superclass = GetTypeIdOrNullPtr(disk_class_def.superclass_idx_);
const DexFile::TypeList* type_list = dex_file.GetInterfacesList(disk_class_def);
- TypeList* interfaces_type_list = CreateTypeList(type_list, disk_class_def.interfaces_off_, false);
+ TypeList* interfaces_type_list = CreateTypeList(type_list, disk_class_def.interfaces_off_);
const StringId* source_file = GetStringIdOrNullPtr(disk_class_def.source_file_idx_);
// Annotations.
@@ -232,9 +280,8 @@
class_defs_.AddIndexedItem(class_def, ClassDefsOffset() + i * ClassDef::ItemSize(), i);
}
-TypeList* Collections::CreateTypeList(
- const DexFile::TypeList* dex_type_list, uint32_t offset, bool allow_empty) {
- if (dex_type_list == nullptr && !allow_empty) {
+TypeList* Collections::CreateTypeList(const DexFile::TypeList* dex_type_list, uint32_t offset) {
+ if (dex_type_list == nullptr) {
return nullptr;
}
// TODO: Create more efficient lookup for existing type lists.
@@ -244,7 +291,7 @@
}
}
TypeIdVector* type_vector = new TypeIdVector();
- uint32_t size = dex_type_list == nullptr ? 0 : dex_type_list->Size();
+ uint32_t size = dex_type_list->Size();
for (uint32_t index = 0; index < size; ++index) {
type_vector->push_back(GetTypeId(dex_type_list->GetTypeItem(index).type_idx_));
}
@@ -257,6 +304,11 @@
if (static_data == nullptr) {
return nullptr;
}
+ for (std::unique_ptr<EncodedArrayItem>& existing_array_item : EncodedArrayItems()) {
+ if (existing_array_item->GetOffset() == offset) {
+ return existing_array_item.get();
+ }
+ }
uint32_t size = DecodeUnsignedLeb128(&static_data);
EncodedValueVector* values = new EncodedValueVector();
for (uint32_t i = 0; i < size; ++i) {
@@ -270,6 +322,11 @@
AnnotationItem* Collections::CreateAnnotationItem(const DexFile::AnnotationItem* annotation,
uint32_t offset) {
+ for (std::unique_ptr<AnnotationItem>& existing_annotation_item : AnnotationItems()) {
+ if (existing_annotation_item->GetOffset() == offset) {
+ return existing_annotation_item.get();
+ }
+ }
uint8_t visibility = annotation->visibility_;
const uint8_t* annotation_data = annotation->annotation_;
EncodedValue* encoded_value =
@@ -284,9 +341,14 @@
AnnotationSetItem* Collections::CreateAnnotationSetItem(const DexFile& dex_file,
const DexFile::AnnotationSetItem& disk_annotations_item, uint32_t offset) {
- if (disk_annotations_item.size_ == 0) {
+ if (disk_annotations_item.size_ == 0 && offset == 0) {
return nullptr;
}
+ for (std::unique_ptr<AnnotationSetItem>& existing_anno_set_item : AnnotationSetItems()) {
+ if (existing_anno_set_item->GetOffset() == offset) {
+ return existing_anno_set_item.get();
+ }
+ }
std::vector<AnnotationItem*>* items = new std::vector<AnnotationItem*>();
for (uint32_t i = 0; i < disk_annotations_item.size_; ++i) {
const DexFile::AnnotationItem* annotation =
@@ -305,6 +367,11 @@
AnnotationsDirectoryItem* Collections::CreateAnnotationsDirectoryItem(const DexFile& dex_file,
const DexFile::AnnotationsDirectoryItem* disk_annotations_item, uint32_t offset) {
+ for (std::unique_ptr<AnnotationsDirectoryItem>& anno_dir_item : AnnotationsDirectoryItems()) {
+ if (anno_dir_item->GetOffset() == offset) {
+ return anno_dir_item.get();
+ }
+ }
const DexFile::AnnotationSetItem* class_set_item =
dex_file.GetClassAnnotationSet(disk_annotations_item);
AnnotationSetItem* class_annotation = nullptr;
@@ -367,16 +434,25 @@
ParameterAnnotation* Collections::GenerateParameterAnnotation(
const DexFile& dex_file, MethodId* method_id,
const DexFile::AnnotationSetRefList* annotation_set_ref_list, uint32_t offset) {
- std::vector<AnnotationSetItem*>* annotations = new std::vector<AnnotationSetItem*>();
- for (uint32_t i = 0; i < annotation_set_ref_list->size_; ++i) {
- const DexFile::AnnotationSetItem* annotation_set_item =
- dex_file.GetSetRefItemItem(&annotation_set_ref_list->list_[i]);
- uint32_t set_offset = annotation_set_ref_list->list_[i].annotations_off_;
- annotations->push_back(CreateAnnotationSetItem(dex_file, *annotation_set_item, set_offset));
+ AnnotationSetRefList* set_ref_list = nullptr;
+ for (std::unique_ptr<AnnotationSetRefList>& existing_set_ref_list : AnnotationSetRefLists()) {
+ if (existing_set_ref_list->GetOffset() == offset) {
+ set_ref_list = existing_set_ref_list.get();
+ break;
+ }
}
- AnnotationSetRefList* new_ref_list = new AnnotationSetRefList(annotations);
- annotation_set_ref_lists_.AddItem(new_ref_list, offset);
- return new ParameterAnnotation(method_id, new_ref_list);
+ if (set_ref_list == nullptr) {
+ std::vector<AnnotationSetItem*>* annotations = new std::vector<AnnotationSetItem*>();
+ for (uint32_t i = 0; i < annotation_set_ref_list->size_; ++i) {
+ const DexFile::AnnotationSetItem* annotation_set_item =
+ dex_file.GetSetRefItemItem(&annotation_set_ref_list->list_[i]);
+ uint32_t set_offset = annotation_set_ref_list->list_[i].annotations_off_;
+ annotations->push_back(CreateAnnotationSetItem(dex_file, *annotation_set_item, set_offset));
+ }
+ set_ref_list = new AnnotationSetRefList(annotations);
+ annotation_set_ref_lists_.AddItem(set_ref_list, offset);
+ }
+ return new ParameterAnnotation(method_id, set_ref_list);
}
CodeItem* Collections::CreateCodeItem(const DexFile& dex_file,
@@ -390,7 +466,10 @@
const uint8_t* debug_info_stream = dex_file.GetDebugInfoStream(&disk_code_item);
DebugInfoItem* debug_info = nullptr;
if (debug_info_stream != nullptr) {
- debug_info = new DebugInfoItem();
+ uint32_t debug_info_size = GetDebugInfoStreamSize(debug_info_stream);
+ uint8_t* debug_info_buffer = new uint8_t[debug_info_size];
+ memcpy(debug_info_buffer, debug_info_stream, debug_info_size);
+ debug_info = new DebugInfoItem(debug_info_size, debug_info_buffer);
debug_info_items_.AddItem(debug_info, disk_code_item.debug_info_off_);
}
@@ -399,26 +478,41 @@
memcpy(insns, disk_code_item.insns_, insns_size * sizeof(uint16_t));
TryItemVector* tries = nullptr;
+ CatchHandlerVector* handler_list = nullptr;
if (tries_size > 0) {
tries = new TryItemVector();
+ handler_list = new CatchHandlerVector();
for (uint32_t i = 0; i < tries_size; ++i) {
const DexFile::TryItem* disk_try_item = dex_file.GetTryItems(disk_code_item, i);
uint32_t start_addr = disk_try_item->start_addr_;
uint16_t insn_count = disk_try_item->insn_count_;
- CatchHandlerVector* handlers = new CatchHandlerVector();
- for (CatchHandlerIterator it(disk_code_item, *disk_try_item); it.HasNext(); it.Next()) {
- const uint16_t type_index = it.GetHandlerTypeIndex();
- const TypeId* type_id = GetTypeIdOrNullPtr(type_index);
- handlers->push_back(std::unique_ptr<const CatchHandler>(
- new CatchHandler(type_id, it.GetHandlerAddress())));
+ uint16_t handler_off = disk_try_item->handler_off_;
+ const CatchHandler* handlers = nullptr;
+ for (std::unique_ptr<const CatchHandler>& existing_handlers : *handler_list) {
+ if (handler_off == existing_handlers->GetListOffset()) {
+ handlers = existing_handlers.get();
+ }
+ }
+ if (handlers == nullptr) {
+ bool catch_all = false;
+ TypeAddrPairVector* addr_pairs = new TypeAddrPairVector();
+ for (CatchHandlerIterator it(disk_code_item, *disk_try_item); it.HasNext(); it.Next()) {
+ const uint16_t type_index = it.GetHandlerTypeIndex();
+ const TypeId* type_id = GetTypeIdOrNullPtr(type_index);
+ catch_all |= type_id == nullptr;
+ addr_pairs->push_back(std::unique_ptr<const TypeAddrPair>(
+ new TypeAddrPair(type_id, it.GetHandlerAddress())));
+ }
+ handlers = new CatchHandler(catch_all, handler_off, addr_pairs);
+ handler_list->push_back(std::unique_ptr<const CatchHandler>(handlers));
}
TryItem* try_item = new TryItem(start_addr, insn_count, handlers);
tries->push_back(std::unique_ptr<const TryItem>(try_item));
}
}
// TODO: Calculate the size of the code item.
- CodeItem* code_item =
- new CodeItem(registers_size, ins_size, outs_size, debug_info, insns_size, insns, tries);
+ CodeItem* code_item = new CodeItem(
+ registers_size, ins_size, outs_size, debug_info, insns_size, insns, tries, handler_list);
code_items_.AddItem(code_item, offset);
return code_item;
}
diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h
index f3d2c90..5e686d3 100644
--- a/dexlayout/dex_ir.h
+++ b/dexlayout/dex_ir.h
@@ -24,6 +24,7 @@
#include "dex_file-inl.h"
#include "leb128.h"
+#include "utf.h"
namespace art {
namespace dex_ir {
@@ -137,10 +138,22 @@
std::vector<std::unique_ptr<FieldId>>& FieldIds() { return field_ids_.Collection(); }
std::vector<std::unique_ptr<MethodId>>& MethodIds() { return method_ids_.Collection(); }
std::vector<std::unique_ptr<ClassDef>>& ClassDefs() { return class_defs_.Collection(); }
-
+ std::vector<std::unique_ptr<StringData>>& StringDatas() { return string_datas_.Collection(); }
std::vector<std::unique_ptr<TypeList>>& TypeLists() { return type_lists_.Collection(); }
std::vector<std::unique_ptr<EncodedArrayItem>>& EncodedArrayItems()
{ return encoded_array_items_.Collection(); }
+ std::vector<std::unique_ptr<AnnotationItem>>& AnnotationItems()
+ { return annotation_items_.Collection(); }
+ std::vector<std::unique_ptr<AnnotationSetItem>>& AnnotationSetItems()
+ { return annotation_set_items_.Collection(); }
+ std::vector<std::unique_ptr<AnnotationSetRefList>>& AnnotationSetRefLists()
+ { return annotation_set_ref_lists_.Collection(); }
+ std::vector<std::unique_ptr<AnnotationsDirectoryItem>>& AnnotationsDirectoryItems()
+ { return annotations_directory_items_.Collection(); }
+ std::vector<std::unique_ptr<DebugInfoItem>>& DebugInfoItems()
+ { return debug_info_items_.Collection(); }
+ std::vector<std::unique_ptr<CodeItem>>& CodeItems() { return code_items_.Collection(); }
+ std::vector<std::unique_ptr<ClassData>>& ClassDatas() { return class_datas_.Collection(); }
void CreateStringId(const DexFile& dex_file, uint32_t i);
void CreateTypeId(const DexFile& dex_file, uint32_t i);
@@ -149,7 +162,7 @@
void CreateMethodId(const DexFile& dex_file, uint32_t i);
void CreateClassDef(const DexFile& dex_file, uint32_t i);
- TypeList* CreateTypeList(const DexFile::TypeList* type_list, uint32_t offset, bool allow_empty);
+ TypeList* CreateTypeList(const DexFile::TypeList* type_list, uint32_t offset);
EncodedArrayItem* CreateEncodedArrayItem(const uint8_t* static_data, uint32_t offset);
AnnotationItem* CreateAnnotationItem(const DexFile::AnnotationItem* annotation, uint32_t offset);
AnnotationSetItem* CreateAnnotationSetItem(const DexFile& dex_file,
@@ -182,14 +195,16 @@
uint32_t ClassDefsOffset() const { return class_defs_.GetOffset(); }
uint32_t StringDatasOffset() const { return string_datas_.GetOffset(); }
uint32_t TypeListsOffset() const { return type_lists_.GetOffset(); }
- uint32_t EncodedArrayOffset() const { return encoded_array_items_.GetOffset(); }
- uint32_t AnnotationOffset() const { return annotation_items_.GetOffset(); }
- uint32_t AnnotationSetOffset() const { return annotation_set_items_.GetOffset(); }
+ uint32_t EncodedArrayItemsOffset() const { return encoded_array_items_.GetOffset(); }
+ uint32_t AnnotationItemsOffset() const { return annotation_items_.GetOffset(); }
+ uint32_t AnnotationSetItemsOffset() const { return annotation_set_items_.GetOffset(); }
uint32_t AnnotationSetRefListsOffset() const { return annotation_set_ref_lists_.GetOffset(); }
- uint32_t AnnotationsDirectoryOffset() const { return annotations_directory_items_.GetOffset(); }
- uint32_t DebugInfoOffset() const { return debug_info_items_.GetOffset(); }
+ uint32_t AnnotationsDirectoryItemsOffset() const
+ { return annotations_directory_items_.GetOffset(); }
+ uint32_t DebugInfoItemsOffset() const { return debug_info_items_.GetOffset(); }
uint32_t CodeItemsOffset() const { return code_items_.GetOffset(); }
uint32_t ClassDatasOffset() const { return class_datas_.GetOffset(); }
+ uint32_t MapItemOffset() const { return map_item_offset_; }
void SetStringIdsOffset(uint32_t new_offset) { string_ids_.SetOffset(new_offset); }
void SetTypeIdsOffset(uint32_t new_offset) { type_ids_.SetOffset(new_offset); }
@@ -199,16 +214,19 @@
void SetClassDefsOffset(uint32_t new_offset) { class_defs_.SetOffset(new_offset); }
void SetStringDatasOffset(uint32_t new_offset) { string_datas_.SetOffset(new_offset); }
void SetTypeListsOffset(uint32_t new_offset) { type_lists_.SetOffset(new_offset); }
- void SetEncodedArrayOffset(uint32_t new_offset) { encoded_array_items_.SetOffset(new_offset); }
- void SetAnnotationOffset(uint32_t new_offset) { annotation_items_.SetOffset(new_offset); }
- void SetAnnotationSetOffset(uint32_t new_offset) { annotation_set_items_.SetOffset(new_offset); }
+ void SetEncodedArrayItemsOffset(uint32_t new_offset)
+ { encoded_array_items_.SetOffset(new_offset); }
+ void SetAnnotationItemsOffset(uint32_t new_offset) { annotation_items_.SetOffset(new_offset); }
+ void SetAnnotationSetItemsOffset(uint32_t new_offset)
+ { annotation_set_items_.SetOffset(new_offset); }
void SetAnnotationSetRefListsOffset(uint32_t new_offset)
{ annotation_set_ref_lists_.SetOffset(new_offset); }
- void SetAnnotationsDirectoryOffset(uint32_t new_offset)
+ void SetAnnotationsDirectoryItemsOffset(uint32_t new_offset)
{ annotations_directory_items_.SetOffset(new_offset); }
- void SetDebugInfoOffset(uint32_t new_offset) { debug_info_items_.SetOffset(new_offset); }
+ void SetDebugInfoItemsOffset(uint32_t new_offset) { debug_info_items_.SetOffset(new_offset); }
void SetCodeItemsOffset(uint32_t new_offset) { code_items_.SetOffset(new_offset); }
void SetClassDatasOffset(uint32_t new_offset) { class_datas_.SetOffset(new_offset); }
+ void SetMapItemOffset(uint32_t new_offset) { map_item_offset_ = new_offset; }
uint32_t StringIdsSize() const { return string_ids_.Size(); }
uint32_t TypeIdsSize() const { return type_ids_.Size(); }
@@ -216,15 +234,14 @@
uint32_t FieldIdsSize() const { return field_ids_.Size(); }
uint32_t MethodIdsSize() const { return method_ids_.Size(); }
uint32_t ClassDefsSize() const { return class_defs_.Size(); }
-
uint32_t StringDatasSize() const { return string_datas_.Size(); }
uint32_t TypeListsSize() const { return type_lists_.Size(); }
- uint32_t EncodedArraySize() const { return encoded_array_items_.Size(); }
- uint32_t AnnotationSize() const { return annotation_items_.Size(); }
- uint32_t AnnotationSetSize() const { return annotation_set_items_.Size(); }
+ uint32_t EncodedArrayItemsSize() const { return encoded_array_items_.Size(); }
+ uint32_t AnnotationItemsSize() const { return annotation_items_.Size(); }
+ uint32_t AnnotationSetItemsSize() const { return annotation_set_items_.Size(); }
uint32_t AnnotationSetRefListsSize() const { return annotation_set_ref_lists_.Size(); }
- uint32_t AnnotationsDirectorySize() const { return annotations_directory_items_.Size(); }
- uint32_t DebugInfoSize() const { return debug_info_items_.Size(); }
+ uint32_t AnnotationsDirectoryItemsSize() const { return annotations_directory_items_.Size(); }
+ uint32_t DebugInfoItemsSize() const { return debug_info_items_.Size(); }
uint32_t CodeItemsSize() const { return code_items_.Size(); }
uint32_t ClassDatasSize() const { return class_datas_.Size(); }
@@ -255,6 +272,8 @@
CollectionWithOffset<CodeItem> code_items_;
CollectionWithOffset<ClassData> class_datas_;
+ uint32_t map_item_offset_ = 0;
+
DISALLOW_COPY_AND_ASSIGN(Collections);
};
@@ -364,7 +383,7 @@
class StringData : public Item {
public:
explicit StringData(const char* data) : data_(strdup(data)) {
- size_ = UnsignedLeb128Size(strlen(data)) + strlen(data);
+ size_ = UnsignedLeb128Size(CountModifiedUtf8Chars(data)) + strlen(data);
}
const char* Data() const { return data_.get(); }
@@ -372,7 +391,7 @@
void Accept(AbstractDispatcher* dispatch) const { dispatch->Dispatch(this); }
private:
- std::unique_ptr<const char> data_;
+ UniqueCPtr<const char> data_;
DISALLOW_COPY_AND_ASSIGN(StringData);
};
@@ -442,14 +461,14 @@
const StringId* Shorty() const { return shorty_; }
const TypeId* ReturnType() const { return return_type_; }
- const TypeIdVector& Parameters() const { return *parameters_->GetTypeList(); }
+ const TypeList* Parameters() const { return parameters_; }
void Accept(AbstractDispatcher* dispatch) const { dispatch->Dispatch(this); }
private:
const StringId* shorty_;
const TypeId* return_type_;
- TypeList* parameters_;
+ TypeList* parameters_; // This can be nullptr.
DISALLOW_COPY_AND_ASSIGN(ProtoId);
};
@@ -533,7 +552,7 @@
private:
uint32_t access_flags_;
const MethodId* method_id_;
- const CodeItem* code_;
+ const CodeItem* code_; // This can be nullptr.
DISALLOW_COPY_AND_ASSIGN(MethodItem);
};
@@ -691,8 +710,8 @@
interfaces_(interfaces),
source_file_(source_file),
annotations_(annotations),
- static_values_(static_values),
- class_data_(class_data) { size_ = kClassDefItemSize; }
+ class_data_(class_data),
+ static_values_(static_values) { size_ = kClassDefItemSize; }
~ClassDef() OVERRIDE { }
@@ -706,8 +725,8 @@
uint32_t InterfacesOffset() { return interfaces_ == nullptr ? 0 : interfaces_->GetOffset(); }
const StringId* SourceFile() const { return source_file_; }
AnnotationsDirectoryItem* Annotations() const { return annotations_; }
- EncodedArrayItem* StaticValues() { return static_values_; }
ClassData* GetClassData() { return class_data_; }
+ EncodedArrayItem* StaticValues() { return static_values_; }
MethodItem* GenerateMethodItem(Header& header, ClassDataItemIterator& cdii);
@@ -716,19 +735,19 @@
private:
const TypeId* class_type_;
uint32_t access_flags_;
- const TypeId* superclass_;
- TypeList* interfaces_;
- const StringId* source_file_;
- AnnotationsDirectoryItem* annotations_;
- EncodedArrayItem* static_values_;
- ClassData* class_data_;
+ const TypeId* superclass_; // This can be nullptr.
+ TypeList* interfaces_; // This can be nullptr.
+ const StringId* source_file_; // This can be nullptr.
+ AnnotationsDirectoryItem* annotations_; // This can be nullptr.
+ ClassData* class_data_; // This can be nullptr.
+ EncodedArrayItem* static_values_; // This can be nullptr.
DISALLOW_COPY_AND_ASSIGN(ClassDef);
};
-class CatchHandler {
+class TypeAddrPair {
public:
- CatchHandler(const TypeId* type_id, uint32_t address) : type_id_(type_id), address_(address) { }
+ TypeAddrPair(const TypeId* type_id, uint32_t address) : type_id_(type_id), address_(address) { }
const TypeId* GetTypeId() const { return type_id_; }
uint32_t GetAddress() const { return address_; }
@@ -737,6 +756,25 @@
const TypeId* type_id_;
uint32_t address_;
+ DISALLOW_COPY_AND_ASSIGN(TypeAddrPair);
+};
+
+using TypeAddrPairVector = std::vector<std::unique_ptr<const TypeAddrPair>>;
+
+class CatchHandler {
+ public:
+ explicit CatchHandler(bool catch_all, uint16_t list_offset, TypeAddrPairVector* handlers)
+ : catch_all_(catch_all), list_offset_(list_offset), handlers_(handlers) { }
+
+ bool HasCatchAll() const { return catch_all_; }
+ uint16_t GetListOffset() const { return list_offset_; }
+ TypeAddrPairVector* GetHandlers() const { return handlers_.get(); }
+
+ private:
+ bool catch_all_;
+ uint16_t list_offset_;
+ std::unique_ptr<TypeAddrPairVector> handlers_;
+
DISALLOW_COPY_AND_ASSIGN(CatchHandler);
};
@@ -744,20 +782,20 @@
class TryItem : public Item {
public:
- TryItem(uint32_t start_addr, uint16_t insn_count, CatchHandlerVector* handlers)
+ TryItem(uint32_t start_addr, uint16_t insn_count, const CatchHandler* handlers)
: start_addr_(start_addr), insn_count_(insn_count), handlers_(handlers) { }
~TryItem() OVERRIDE { }
uint32_t StartAddr() const { return start_addr_; }
uint16_t InsnCount() const { return insn_count_; }
- const CatchHandlerVector& GetHandlers() const { return *handlers_.get(); }
+ const CatchHandler* GetHandlers() const { return handlers_; }
void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); }
private:
uint32_t start_addr_;
uint16_t insn_count_;
- std::unique_ptr<CatchHandlerVector> handlers_;
+ const CatchHandler* handlers_;
DISALLOW_COPY_AND_ASSIGN(TryItem);
};
@@ -772,14 +810,16 @@
DebugInfoItem* debug_info,
uint32_t insns_size,
uint16_t* insns,
- TryItemVector* tries)
+ TryItemVector* tries,
+ CatchHandlerVector* handlers)
: registers_size_(registers_size),
ins_size_(ins_size),
outs_size_(outs_size),
debug_info_(debug_info),
insns_size_(insns_size),
insns_(insns),
- tries_(tries) { }
+ tries_(tries),
+ handlers_(handlers) { }
~CodeItem() OVERRIDE { }
@@ -791,6 +831,7 @@
uint32_t InsnsSize() const { return insns_size_; }
uint16_t* Insns() const { return insns_.get(); }
TryItemVector* Tries() const { return tries_.get(); }
+ CatchHandlerVector* Handlers() const { return handlers_.get(); }
void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); }
@@ -798,10 +839,11 @@
uint16_t registers_size_;
uint16_t ins_size_;
uint16_t outs_size_;
- DebugInfoItem* debug_info_;
+ DebugInfoItem* debug_info_; // This can be nullptr.
uint32_t insns_size_;
std::unique_ptr<uint16_t[]> insns_;
- std::unique_ptr<TryItemVector> tries_;
+ std::unique_ptr<TryItemVector> tries_; // This can be nullptr.
+ std::unique_ptr<CatchHandlerVector> handlers_; // This can be nullptr.
DISALLOW_COPY_AND_ASSIGN(CodeItem);
};
@@ -841,12 +883,19 @@
class DebugInfoItem : public Item {
public:
- DebugInfoItem() = default;
+ DebugInfoItem(uint32_t debug_info_size, uint8_t* debug_info)
+ : debug_info_size_(debug_info_size), debug_info_(debug_info) { }
+
+ uint32_t GetDebugInfoSize() const { return debug_info_size_; }
+ uint8_t* GetDebugInfo() const { return debug_info_.get(); }
PositionInfoVector& GetPositionInfo() { return positions_; }
LocalInfoVector& GetLocalInfo() { return locals_; }
private:
+ uint32_t debug_info_size_;
+ std::unique_ptr<uint8_t[]> debug_info_;
+
PositionInfoVector positions_;
LocalInfoVector locals_;
@@ -899,7 +948,7 @@
void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); }
private:
- std::unique_ptr<std::vector<AnnotationSetItem*>> items_;
+ std::unique_ptr<std::vector<AnnotationSetItem*>> items_; // Elements of vector can be nullptr.
DISALLOW_COPY_AND_ASSIGN(AnnotationSetRefList);
};
@@ -974,10 +1023,10 @@
void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); }
private:
- AnnotationSetItem* class_annotation_;
- std::unique_ptr<FieldAnnotationVector> field_annotations_;
- std::unique_ptr<MethodAnnotationVector> method_annotations_;
- std::unique_ptr<ParameterAnnotationVector> parameter_annotations_;
+ AnnotationSetItem* class_annotation_; // This can be nullptr.
+ std::unique_ptr<FieldAnnotationVector> field_annotations_; // This can be nullptr.
+ std::unique_ptr<MethodAnnotationVector> method_annotations_; // This can be nullptr.
+ std::unique_ptr<ParameterAnnotationVector> parameter_annotations_; // This can be nullptr.
DISALLOW_COPY_AND_ASSIGN(AnnotationsDirectoryItem);
};
diff --git a/dexlayout/dex_ir_builder.cc b/dexlayout/dex_ir_builder.cc
index 599f48b..68ff2a2 100644
--- a/dexlayout/dex_ir_builder.cc
+++ b/dexlayout/dex_ir_builder.cc
@@ -70,6 +70,8 @@
for (uint32_t i = 0; i < dex_file.NumClassDefs(); ++i) {
collections.CreateClassDef(dex_file, i);
}
+ // MapItem.
+ collections.SetMapItemOffset(disk_header.map_off_);
CheckAndSetRemainingOffsets(dex_file, &collections);
@@ -124,7 +126,7 @@
collections->SetAnnotationSetRefListsOffset(item->offset_);
break;
case DexFile::kDexTypeAnnotationSetItem:
- collections->SetAnnotationSetOffset(item->offset_);
+ collections->SetAnnotationSetItemsOffset(item->offset_);
break;
case DexFile::kDexTypeClassDataItem:
collections->SetClassDatasOffset(item->offset_);
@@ -136,16 +138,16 @@
collections->SetStringDatasOffset(item->offset_);
break;
case DexFile::kDexTypeDebugInfoItem:
- collections->SetDebugInfoOffset(item->offset_);
+ collections->SetDebugInfoItemsOffset(item->offset_);
break;
case DexFile::kDexTypeAnnotationItem:
- collections->SetAnnotationOffset(item->offset_);
+ collections->SetAnnotationItemsOffset(item->offset_);
break;
case DexFile::kDexTypeEncodedArrayItem:
- collections->SetEncodedArrayOffset(item->offset_);
+ collections->SetEncodedArrayItemsOffset(item->offset_);
break;
case DexFile::kDexTypeAnnotationsDirectoryItem:
- collections->SetAnnotationsDirectoryOffset(item->offset_);
+ collections->SetAnnotationsDirectoryItemsOffset(item->offset_);
break;
default:
LOG(ERROR) << "Unknown map list item type.";
diff --git a/dexlayout/dex_visualize.cc b/dexlayout/dex_visualize.cc
index be7bade..46dff5f 100644
--- a/dexlayout/dex_visualize.cc
+++ b/dexlayout/dex_visualize.cc
@@ -87,18 +87,18 @@
}, {
"EncArr",
DexFile::kDexTypeEncodedArrayItem,
- &dex_ir::Collections::EncodedArraySize,
- &dex_ir::Collections::EncodedArrayOffset
+ &dex_ir::Collections::EncodedArrayItemsSize,
+ &dex_ir::Collections::EncodedArrayItemsOffset
}, {
"Annotation",
DexFile::kDexTypeAnnotationItem,
- &dex_ir::Collections::AnnotationSize,
- &dex_ir::Collections::AnnotationOffset
+ &dex_ir::Collections::AnnotationItemsSize,
+ &dex_ir::Collections::AnnotationItemsOffset
}, {
"AnnoSet",
DexFile::kDexTypeAnnotationSetItem,
- &dex_ir::Collections::AnnotationSetSize,
- &dex_ir::Collections::AnnotationSetOffset
+ &dex_ir::Collections::AnnotationSetItemsSize,
+ &dex_ir::Collections::AnnotationSetItemsOffset
}, {
"AnnoSetRL",
DexFile::kDexTypeAnnotationSetRefList,
@@ -107,13 +107,13 @@
}, {
"AnnoDir",
DexFile::kDexTypeAnnotationsDirectoryItem,
- &dex_ir::Collections::AnnotationsDirectorySize,
- &dex_ir::Collections::AnnotationsDirectoryOffset
+ &dex_ir::Collections::AnnotationsDirectoryItemsSize,
+ &dex_ir::Collections::AnnotationsDirectoryItemsOffset
}, {
"DebugInfo",
DexFile::kDexTypeDebugInfoItem,
- &dex_ir::Collections::DebugInfoSize,
- &dex_ir::Collections::DebugInfoOffset
+ &dex_ir::Collections::DebugInfoItemsSize,
+ &dex_ir::Collections::DebugInfoItemsOffset
}, {
"CodeItem",
DexFile::kDexTypeCodeItem,
@@ -244,9 +244,11 @@
return;
}
DumpStringId(proto_id->Shorty(), class_index);
- const dex_ir::TypeIdVector& parameters = proto_id->Parameters();
- for (const dex_ir::TypeId* t : parameters) {
- DumpTypeId(t, class_index);
+ const dex_ir::TypeList* type_list = proto_id->Parameters();
+ if (type_list != nullptr) {
+ for (const dex_ir::TypeId* t : *type_list->GetTypeList()) {
+ DumpTypeId(t, class_index);
+ }
}
DumpTypeId(proto_id->ReturnType(), class_index);
}
diff --git a/dexlayout/dex_writer.cc b/dexlayout/dex_writer.cc
new file mode 100644
index 0000000..dba5da0
--- /dev/null
+++ b/dexlayout/dex_writer.cc
@@ -0,0 +1,648 @@
+/*
+ * Copyright (C) 2016 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.
+ *
+ * Header file of an in-memory representation of DEX files.
+ */
+
+#include <stdint.h>
+
+#include <queue>
+#include <vector>
+
+#include "dex_writer.h"
+#include "utf.h"
+
+namespace art {
+
+size_t EncodeIntValue(int32_t value, uint8_t* buffer) {
+ size_t length = 0;
+ if (value >= 0) {
+ while (value > 0x7f) {
+ buffer[length++] = static_cast<uint8_t>(value);
+ value >>= 8;
+ }
+ } else {
+ while (value < -0x80) {
+ buffer[length++] = static_cast<uint8_t>(value);
+ value >>= 8;
+ }
+ }
+ buffer[length++] = static_cast<uint8_t>(value);
+ return length;
+}
+
+size_t EncodeUIntValue(uint32_t value, uint8_t* buffer) {
+ size_t length = 0;
+ do {
+ buffer[length++] = static_cast<uint8_t>(value);
+ value >>= 8;
+ } while (value != 0);
+ return length;
+}
+
+size_t EncodeLongValue(int64_t value, uint8_t* buffer) {
+ size_t length = 0;
+ if (value >= 0) {
+ while (value > 0x7f) {
+ buffer[length++] = static_cast<uint8_t>(value);
+ value >>= 8;
+ }
+ } else {
+ while (value < -0x80) {
+ buffer[length++] = static_cast<uint8_t>(value);
+ value >>= 8;
+ }
+ }
+ buffer[length++] = static_cast<uint8_t>(value);
+ return length;
+}
+
+union FloatUnion {
+ float f_;
+ uint32_t i_;
+};
+
+size_t EncodeFloatValue(float value, uint8_t* buffer) {
+ FloatUnion float_union;
+ float_union.f_ = value;
+ uint32_t int_value = float_union.i_;
+ size_t index = 3;
+ do {
+ buffer[index--] = int_value >> 24;
+ int_value <<= 8;
+ } while (int_value != 0);
+ return 3 - index;
+}
+
+union DoubleUnion {
+ double d_;
+ uint64_t l_;
+};
+
+size_t EncodeDoubleValue(double value, uint8_t* buffer) {
+ DoubleUnion double_union;
+ double_union.d_ = value;
+ uint64_t long_value = double_union.l_;
+ size_t index = 7;
+ do {
+ buffer[index--] = long_value >> 56;
+ long_value <<= 8;
+ } while (long_value != 0);
+ return 7 - index;
+}
+
+size_t DexWriter::Write(const void* buffer, size_t length, size_t offset) {
+ return dex_file_->PwriteFully(buffer, length, offset) ? length : 0;
+}
+
+size_t DexWriter::WriteSleb128(uint32_t value, size_t offset) {
+ uint8_t buffer[8];
+ EncodeSignedLeb128(buffer, value);
+ return Write(buffer, SignedLeb128Size(value), offset);
+}
+
+size_t DexWriter::WriteUleb128(uint32_t value, size_t offset) {
+ uint8_t buffer[8];
+ EncodeUnsignedLeb128(buffer, value);
+ return Write(buffer, UnsignedLeb128Size(value), offset);
+}
+
+size_t DexWriter::WriteEncodedValue(dex_ir::EncodedValue* encoded_value, size_t offset) {
+ size_t original_offset = offset;
+ size_t start = 0;
+ size_t length;
+ uint8_t buffer[8];
+ int8_t type = encoded_value->Type();
+ switch (type) {
+ case DexFile::kDexAnnotationByte:
+ length = EncodeIntValue(encoded_value->GetByte(), buffer);
+ break;
+ case DexFile::kDexAnnotationShort:
+ length = EncodeIntValue(encoded_value->GetShort(), buffer);
+ break;
+ case DexFile::kDexAnnotationChar:
+ length = EncodeUIntValue(encoded_value->GetChar(), buffer);
+ break;
+ case DexFile::kDexAnnotationInt:
+ length = EncodeIntValue(encoded_value->GetInt(), buffer);
+ break;
+ case DexFile::kDexAnnotationLong:
+ length = EncodeLongValue(encoded_value->GetLong(), buffer);
+ break;
+ case DexFile::kDexAnnotationFloat:
+ length = EncodeFloatValue(encoded_value->GetFloat(), buffer);
+ start = 4 - length;
+ break;
+ case DexFile::kDexAnnotationDouble:
+ length = EncodeDoubleValue(encoded_value->GetDouble(), buffer);
+ start = 8 - length;
+ break;
+ case DexFile::kDexAnnotationString:
+ length = EncodeUIntValue(encoded_value->GetStringId()->GetIndex(), buffer);
+ break;
+ case DexFile::kDexAnnotationType:
+ length = EncodeUIntValue(encoded_value->GetTypeId()->GetIndex(), buffer);
+ break;
+ case DexFile::kDexAnnotationField:
+ case DexFile::kDexAnnotationEnum:
+ length = EncodeUIntValue(encoded_value->GetFieldId()->GetIndex(), buffer);
+ break;
+ case DexFile::kDexAnnotationMethod:
+ length = EncodeUIntValue(encoded_value->GetMethodId()->GetIndex(), buffer);
+ break;
+ case DexFile::kDexAnnotationArray:
+ offset += WriteEncodedValueHeader(type, 0, offset);
+ offset += WriteEncodedArray(encoded_value->GetEncodedArray()->GetEncodedValues(), offset);
+ return offset - original_offset;
+ case DexFile::kDexAnnotationAnnotation:
+ offset += WriteEncodedValueHeader(type, 0, offset);
+ offset += WriteEncodedAnnotation(encoded_value->GetEncodedAnnotation(), offset);
+ return offset - original_offset;
+ case DexFile::kDexAnnotationNull:
+ return WriteEncodedValueHeader(type, 0, offset);
+ case DexFile::kDexAnnotationBoolean:
+ return WriteEncodedValueHeader(type, encoded_value->GetBoolean() ? 1 : 0, offset);
+ default:
+ return 0;
+ }
+ offset += WriteEncodedValueHeader(type, length - 1, offset);
+ offset += Write(buffer + start, length, offset);
+ return offset - original_offset;
+}
+
+size_t DexWriter::WriteEncodedValueHeader(int8_t value_type, size_t value_arg, size_t offset) {
+ uint8_t buffer[1] = { static_cast<uint8_t>((value_arg << 5) | value_type) };
+ return Write(buffer, sizeof(uint8_t), offset);
+}
+
+size_t DexWriter::WriteEncodedArray(dex_ir::EncodedValueVector* values, size_t offset) {
+ size_t original_offset = offset;
+ offset += WriteUleb128(values->size(), offset);
+ for (std::unique_ptr<dex_ir::EncodedValue>& value : *values) {
+ offset += WriteEncodedValue(value.get(), offset);
+ }
+ return offset - original_offset;
+}
+
+size_t DexWriter::WriteEncodedAnnotation(dex_ir::EncodedAnnotation* annotation, size_t offset) {
+ size_t original_offset = offset;
+ offset += WriteUleb128(annotation->GetType()->GetIndex(), offset);
+ offset += WriteUleb128(annotation->GetAnnotationElements()->size(), offset);
+ for (std::unique_ptr<dex_ir::AnnotationElement>& annotation_element :
+ *annotation->GetAnnotationElements()) {
+ offset += WriteUleb128(annotation_element->GetName()->GetIndex(), offset);
+ offset += WriteEncodedValue(annotation_element->GetValue(), offset);
+ }
+ return offset - original_offset;
+}
+
+size_t DexWriter::WriteEncodedFields(dex_ir::FieldItemVector* fields, size_t offset) {
+ size_t original_offset = offset;
+ uint32_t prev_index = 0;
+ for (std::unique_ptr<dex_ir::FieldItem>& field : *fields) {
+ uint32_t index = field->GetFieldId()->GetIndex();
+ offset += WriteUleb128(index - prev_index, offset);
+ offset += WriteUleb128(field->GetAccessFlags(), offset);
+ prev_index = index;
+ }
+ return offset - original_offset;
+}
+
+size_t DexWriter::WriteEncodedMethods(dex_ir::MethodItemVector* methods, size_t offset) {
+ size_t original_offset = offset;
+ uint32_t prev_index = 0;
+ for (std::unique_ptr<dex_ir::MethodItem>& method : *methods) {
+ uint32_t index = method->GetMethodId()->GetIndex();
+ uint32_t code_off = method->GetCodeItem() == nullptr ? 0 : method->GetCodeItem()->GetOffset();
+ offset += WriteUleb128(index - prev_index, offset);
+ offset += WriteUleb128(method->GetAccessFlags(), offset);
+ offset += WriteUleb128(code_off, offset);
+ prev_index = index;
+ }
+ return offset - original_offset;
+}
+
+void DexWriter::WriteStrings() {
+ uint32_t string_data_off[1];
+ for (std::unique_ptr<dex_ir::StringId>& string_id : header_.GetCollections().StringIds()) {
+ string_data_off[0] = string_id->DataItem()->GetOffset();
+ Write(string_data_off, string_id->GetSize(), string_id->GetOffset());
+ }
+
+ for (std::unique_ptr<dex_ir::StringData>& string_data : header_.GetCollections().StringDatas()) {
+ uint32_t offset = string_data->GetOffset();
+ offset += WriteUleb128(CountModifiedUtf8Chars(string_data->Data()), offset);
+ Write(string_data->Data(), strlen(string_data->Data()), offset);
+ }
+}
+
+void DexWriter::WriteTypes() {
+ uint32_t descriptor_idx[1];
+ for (std::unique_ptr<dex_ir::TypeId>& type_id : header_.GetCollections().TypeIds()) {
+ descriptor_idx[0] = type_id->GetStringId()->GetIndex();
+ Write(descriptor_idx, type_id->GetSize(), type_id->GetOffset());
+ }
+}
+
+void DexWriter::WriteTypeLists() {
+ uint32_t size[1];
+ uint16_t list[1];
+ for (std::unique_ptr<dex_ir::TypeList>& type_list : header_.GetCollections().TypeLists()) {
+ size[0] = type_list->GetTypeList()->size();
+ uint32_t offset = type_list->GetOffset();
+ offset += Write(size, sizeof(uint32_t), offset);
+ for (const dex_ir::TypeId* type_id : *type_list->GetTypeList()) {
+ list[0] = type_id->GetIndex();
+ offset += Write(list, sizeof(uint16_t), offset);
+ }
+ }
+}
+
+void DexWriter::WriteProtos() {
+ uint32_t buffer[3];
+ for (std::unique_ptr<dex_ir::ProtoId>& proto_id : header_.GetCollections().ProtoIds()) {
+ buffer[0] = proto_id->Shorty()->GetIndex();
+ buffer[1] = proto_id->ReturnType()->GetIndex();
+ buffer[2] = proto_id->Parameters() == nullptr ? 0 : proto_id->Parameters()->GetOffset();
+ Write(buffer, proto_id->GetSize(), proto_id->GetOffset());
+ }
+}
+
+void DexWriter::WriteFields() {
+ uint16_t buffer[4];
+ for (std::unique_ptr<dex_ir::FieldId>& field_id : header_.GetCollections().FieldIds()) {
+ buffer[0] = field_id->Class()->GetIndex();
+ buffer[1] = field_id->Type()->GetIndex();
+ buffer[2] = field_id->Name()->GetIndex();
+ buffer[3] = field_id->Name()->GetIndex() >> 16;
+ Write(buffer, field_id->GetSize(), field_id->GetOffset());
+ }
+}
+
+void DexWriter::WriteMethods() {
+ uint16_t buffer[4];
+ for (std::unique_ptr<dex_ir::MethodId>& method_id : header_.GetCollections().MethodIds()) {
+ buffer[0] = method_id->Class()->GetIndex();
+ buffer[1] = method_id->Proto()->GetIndex();
+ buffer[2] = method_id->Name()->GetIndex();
+ buffer[3] = method_id->Name()->GetIndex() >> 16;
+ Write(buffer, method_id->GetSize(), method_id->GetOffset());
+ }
+}
+
+void DexWriter::WriteEncodedArrays() {
+ for (std::unique_ptr<dex_ir::EncodedArrayItem>& encoded_array :
+ header_.GetCollections().EncodedArrayItems()) {
+ WriteEncodedArray(encoded_array->GetEncodedValues(), encoded_array->GetOffset());
+ }
+}
+
+void DexWriter::WriteAnnotations() {
+ uint8_t visibility[1];
+ for (std::unique_ptr<dex_ir::AnnotationItem>& annotation :
+ header_.GetCollections().AnnotationItems()) {
+ visibility[0] = annotation->GetVisibility();
+ size_t offset = annotation->GetOffset();
+ offset += Write(visibility, sizeof(uint8_t), offset);
+ WriteEncodedAnnotation(annotation->GetAnnotation(), offset);
+ }
+}
+
+void DexWriter::WriteAnnotationSets() {
+ uint32_t size[1];
+ uint32_t annotation_off[1];
+ for (std::unique_ptr<dex_ir::AnnotationSetItem>& annotation_set :
+ header_.GetCollections().AnnotationSetItems()) {
+ size[0] = annotation_set->GetItems()->size();
+ size_t offset = annotation_set->GetOffset();
+ offset += Write(size, sizeof(uint32_t), offset);
+ for (dex_ir::AnnotationItem* annotation : *annotation_set->GetItems()) {
+ annotation_off[0] = annotation->GetOffset();
+ offset += Write(annotation_off, sizeof(uint32_t), offset);
+ }
+ }
+}
+
+void DexWriter::WriteAnnotationSetRefs() {
+ uint32_t size[1];
+ uint32_t annotations_off[1];
+ for (std::unique_ptr<dex_ir::AnnotationSetRefList>& annotation_set_ref :
+ header_.GetCollections().AnnotationSetRefLists()) {
+ size[0] = annotation_set_ref->GetItems()->size();
+ size_t offset = annotation_set_ref->GetOffset();
+ offset += Write(size, sizeof(uint32_t), offset);
+ for (dex_ir::AnnotationSetItem* annotation_set : *annotation_set_ref->GetItems()) {
+ annotations_off[0] = annotation_set == nullptr ? 0 : annotation_set->GetOffset();
+ offset += Write(annotations_off, sizeof(uint32_t), offset);
+ }
+ }
+}
+
+void DexWriter::WriteAnnotationsDirectories() {
+ uint32_t directory_buffer[4];
+ uint32_t annotation_buffer[2];
+ for (std::unique_ptr<dex_ir::AnnotationsDirectoryItem>& annotations_directory :
+ header_.GetCollections().AnnotationsDirectoryItems()) {
+ directory_buffer[0] = annotations_directory->GetClassAnnotation() == nullptr ? 0 :
+ annotations_directory->GetClassAnnotation()->GetOffset();
+ directory_buffer[1] = annotations_directory->GetFieldAnnotations() == nullptr ? 0 :
+ annotations_directory->GetFieldAnnotations()->size();
+ directory_buffer[2] = annotations_directory->GetMethodAnnotations() == nullptr ? 0 :
+ annotations_directory->GetMethodAnnotations()->size();
+ directory_buffer[3] = annotations_directory->GetParameterAnnotations() == nullptr ? 0 :
+ annotations_directory->GetParameterAnnotations()->size();
+ uint32_t offset = annotations_directory->GetOffset();
+ offset += Write(directory_buffer, 4 * sizeof(uint32_t), offset);
+ if (annotations_directory->GetFieldAnnotations() != nullptr) {
+ for (std::unique_ptr<dex_ir::FieldAnnotation>& field :
+ *annotations_directory->GetFieldAnnotations()) {
+ annotation_buffer[0] = field->GetFieldId()->GetIndex();
+ annotation_buffer[1] = field->GetAnnotationSetItem()->GetOffset();
+ offset += Write(annotation_buffer, 2 * sizeof(uint32_t), offset);
+ }
+ }
+ if (annotations_directory->GetMethodAnnotations() != nullptr) {
+ for (std::unique_ptr<dex_ir::MethodAnnotation>& method :
+ *annotations_directory->GetMethodAnnotations()) {
+ annotation_buffer[0] = method->GetMethodId()->GetIndex();
+ annotation_buffer[1] = method->GetAnnotationSetItem()->GetOffset();
+ offset += Write(annotation_buffer, 2 * sizeof(uint32_t), offset);
+ }
+ }
+ if (annotations_directory->GetParameterAnnotations() != nullptr) {
+ for (std::unique_ptr<dex_ir::ParameterAnnotation>& parameter :
+ *annotations_directory->GetParameterAnnotations()) {
+ annotation_buffer[0] = parameter->GetMethodId()->GetIndex();
+ annotation_buffer[1] = parameter->GetAnnotations()->GetOffset();
+ offset += Write(annotation_buffer, 2 * sizeof(uint32_t), offset);
+ }
+ }
+ }
+}
+
+void DexWriter::WriteDebugInfoItems() {
+ for (std::unique_ptr<dex_ir::DebugInfoItem>& info : header_.GetCollections().DebugInfoItems()) {
+ Write(info->GetDebugInfo(), info->GetDebugInfoSize(), info->GetOffset());
+ }
+}
+
+void DexWriter::WriteCodeItems() {
+ uint16_t uint16_buffer[4];
+ uint32_t uint32_buffer[2];
+ for (std::unique_ptr<dex_ir::CodeItem>& code_item : header_.GetCollections().CodeItems()) {
+ uint16_buffer[0] = code_item->RegistersSize();
+ uint16_buffer[1] = code_item->InsSize();
+ uint16_buffer[2] = code_item->OutsSize();
+ uint16_buffer[3] = code_item->TriesSize();
+ uint32_buffer[0] = code_item->DebugInfo() == nullptr ? 0 : code_item->DebugInfo()->GetOffset();
+ uint32_buffer[1] = code_item->InsnsSize();
+ size_t offset = code_item->GetOffset();
+ offset += Write(uint16_buffer, 4 * sizeof(uint16_t), offset);
+ offset += Write(uint32_buffer, 2 * sizeof(uint32_t), offset);
+ offset += Write(code_item->Insns(), code_item->InsnsSize() * sizeof(uint16_t), offset);
+ if (code_item->TriesSize() != 0) {
+ if (code_item->InsnsSize() % 2 != 0) {
+ uint16_t padding[1] = { 0 };
+ offset += Write(padding, sizeof(uint16_t), offset);
+ }
+ uint32_t start_addr[1];
+ uint16_t insn_count_and_handler_off[2];
+ for (std::unique_ptr<const dex_ir::TryItem>& try_item : *code_item->Tries()) {
+ start_addr[0] = try_item->StartAddr();
+ insn_count_and_handler_off[0] = try_item->InsnCount();
+ insn_count_and_handler_off[1] = try_item->GetHandlers()->GetListOffset();
+ offset += Write(start_addr, sizeof(uint32_t), offset);
+ offset += Write(insn_count_and_handler_off, 2 * sizeof(uint16_t), offset);
+ }
+ // Leave offset pointing to the end of the try items.
+ WriteUleb128(code_item->Handlers()->size(), offset);
+ for (std::unique_ptr<const dex_ir::CatchHandler>& handlers : *code_item->Handlers()) {
+ size_t list_offset = offset + handlers->GetListOffset();
+ uint32_t size = handlers->HasCatchAll() ? (handlers->GetHandlers()->size() - 1) * -1 :
+ handlers->GetHandlers()->size();
+ list_offset += WriteSleb128(size, list_offset);
+ for (std::unique_ptr<const dex_ir::TypeAddrPair>& handler : *handlers->GetHandlers()) {
+ if (handler->GetTypeId() != nullptr) {
+ list_offset += WriteUleb128(handler->GetTypeId()->GetIndex(), list_offset);
+ }
+ list_offset += WriteUleb128(handler->GetAddress(), list_offset);
+ }
+ }
+ }
+ }
+}
+
+void DexWriter::WriteClasses() {
+ uint32_t class_def_buffer[8];
+ for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_.GetCollections().ClassDefs()) {
+ class_def_buffer[0] = class_def->ClassType()->GetIndex();
+ class_def_buffer[1] = class_def->GetAccessFlags();
+ class_def_buffer[2] = class_def->Superclass() == nullptr ? DexFile::kDexNoIndex :
+ class_def->Superclass()->GetIndex();
+ class_def_buffer[3] = class_def->InterfacesOffset();
+ class_def_buffer[4] = class_def->SourceFile() == nullptr ? DexFile::kDexNoIndex :
+ class_def->SourceFile()->GetIndex();
+ class_def_buffer[5] = class_def->Annotations() == nullptr ? 0 :
+ class_def->Annotations()->GetOffset();
+ class_def_buffer[6] = class_def->GetClassData() == nullptr ? 0 :
+ class_def->GetClassData()->GetOffset();
+ class_def_buffer[7] = class_def->StaticValues() == nullptr ? 0 :
+ class_def->StaticValues()->GetOffset();
+ size_t offset = class_def->GetOffset();
+ Write(class_def_buffer, class_def->GetSize(), offset);
+ }
+
+ for (std::unique_ptr<dex_ir::ClassData>& class_data : header_.GetCollections().ClassDatas()) {
+ size_t offset = class_data->GetOffset();
+ offset += WriteUleb128(class_data->StaticFields()->size(), offset);
+ offset += WriteUleb128(class_data->InstanceFields()->size(), offset);
+ offset += WriteUleb128(class_data->DirectMethods()->size(), offset);
+ offset += WriteUleb128(class_data->VirtualMethods()->size(), offset);
+ offset += WriteEncodedFields(class_data->StaticFields(), offset);
+ offset += WriteEncodedFields(class_data->InstanceFields(), offset);
+ offset += WriteEncodedMethods(class_data->DirectMethods(), offset);
+ offset += WriteEncodedMethods(class_data->VirtualMethods(), offset);
+ }
+}
+
+struct MapItemContainer {
+ MapItemContainer(uint32_t type, uint32_t size, uint32_t offset)
+ : type_(type), size_(size), offset_(offset) { }
+
+ bool operator<(const MapItemContainer& other) const {
+ return offset_ > other.offset_;
+ }
+
+ uint32_t type_;
+ uint32_t size_;
+ uint32_t offset_;
+};
+
+void DexWriter::WriteMapItem() {
+ dex_ir::Collections& collection = header_.GetCollections();
+ std::priority_queue<MapItemContainer> queue;
+
+ // Header and index section.
+ queue.push(MapItemContainer(DexFile::kDexTypeHeaderItem, 1, 0));
+ if (collection.StringIdsSize() != 0) {
+ queue.push(MapItemContainer(DexFile::kDexTypeStringIdItem, collection.StringIdsSize(),
+ collection.StringIdsOffset()));
+ }
+ if (collection.TypeIdsSize() != 0) {
+ queue.push(MapItemContainer(DexFile::kDexTypeTypeIdItem, collection.TypeIdsSize(),
+ collection.TypeIdsOffset()));
+ }
+ if (collection.ProtoIdsSize() != 0) {
+ queue.push(MapItemContainer(DexFile::kDexTypeProtoIdItem, collection.ProtoIdsSize(),
+ collection.ProtoIdsOffset()));
+ }
+ if (collection.FieldIdsSize() != 0) {
+ queue.push(MapItemContainer(DexFile::kDexTypeFieldIdItem, collection.FieldIdsSize(),
+ collection.FieldIdsOffset()));
+ }
+ if (collection.MethodIdsSize() != 0) {
+ queue.push(MapItemContainer(DexFile::kDexTypeMethodIdItem, collection.MethodIdsSize(),
+ collection.MethodIdsOffset()));
+ }
+ if (collection.ClassDefsSize() != 0) {
+ queue.push(MapItemContainer(DexFile::kDexTypeClassDefItem, collection.ClassDefsSize(),
+ collection.ClassDefsOffset()));
+ }
+
+ // Data section.
+ queue.push(MapItemContainer(DexFile::kDexTypeMapList, 1, collection.MapItemOffset()));
+ if (collection.TypeListsSize() != 0) {
+ queue.push(MapItemContainer(DexFile::kDexTypeTypeList, collection.TypeListsSize(),
+ collection.TypeListsOffset()));
+ }
+ if (collection.AnnotationSetRefListsSize() != 0) {
+ queue.push(MapItemContainer(DexFile::kDexTypeAnnotationSetRefList,
+ collection.AnnotationSetRefListsSize(), collection.AnnotationSetRefListsOffset()));
+ }
+ if (collection.AnnotationSetItemsSize() != 0) {
+ queue.push(MapItemContainer(DexFile::kDexTypeAnnotationSetItem,
+ collection.AnnotationSetItemsSize(), collection.AnnotationSetItemsOffset()));
+ }
+ if (collection.ClassDatasSize() != 0) {
+ queue.push(MapItemContainer(DexFile::kDexTypeClassDataItem, collection.ClassDatasSize(),
+ collection.ClassDatasOffset()));
+ }
+ if (collection.CodeItemsSize() != 0) {
+ queue.push(MapItemContainer(DexFile::kDexTypeCodeItem, collection.CodeItemsSize(),
+ collection.CodeItemsOffset()));
+ }
+ if (collection.StringDatasSize() != 0) {
+ queue.push(MapItemContainer(DexFile::kDexTypeStringDataItem, collection.StringDatasSize(),
+ collection.StringDatasOffset()));
+ }
+ if (collection.DebugInfoItemsSize() != 0) {
+ queue.push(MapItemContainer(DexFile::kDexTypeDebugInfoItem, collection.DebugInfoItemsSize(),
+ collection.DebugInfoItemsOffset()));
+ }
+ if (collection.AnnotationItemsSize() != 0) {
+ queue.push(MapItemContainer(DexFile::kDexTypeAnnotationItem, collection.AnnotationItemsSize(),
+ collection.AnnotationItemsOffset()));
+ }
+ if (collection.EncodedArrayItemsSize() != 0) {
+ queue.push(MapItemContainer(DexFile::kDexTypeEncodedArrayItem,
+ collection.EncodedArrayItemsSize(), collection.EncodedArrayItemsOffset()));
+ }
+ if (collection.AnnotationsDirectoryItemsSize() != 0) {
+ queue.push(MapItemContainer(DexFile::kDexTypeAnnotationsDirectoryItem,
+ collection.AnnotationsDirectoryItemsSize(), collection.AnnotationsDirectoryItemsOffset()));
+ }
+
+ uint32_t offset = collection.MapItemOffset();
+ uint16_t uint16_buffer[2];
+ uint32_t uint32_buffer[2];
+ uint16_buffer[1] = 0;
+ uint32_buffer[0] = queue.size();
+ offset += Write(uint32_buffer, sizeof(uint32_t), offset);
+ while (!queue.empty()) {
+ const MapItemContainer& map_item = queue.top();
+ uint16_buffer[0] = map_item.type_;
+ uint32_buffer[0] = map_item.size_;
+ uint32_buffer[1] = map_item.offset_;
+ offset += Write(uint16_buffer, 2 * sizeof(uint16_t), offset);
+ offset += Write(uint32_buffer, 2 * sizeof(uint32_t), offset);
+ queue.pop();
+ }
+}
+
+void DexWriter::WriteHeader() {
+ uint32_t buffer[20];
+ dex_ir::Collections& collections = header_.GetCollections();
+ size_t offset = 0;
+ offset += Write(header_.Magic(), 8 * sizeof(uint8_t), offset);
+ buffer[0] = header_.Checksum();
+ offset += Write(buffer, sizeof(uint32_t), offset);
+ offset += Write(header_.Signature(), 20 * sizeof(uint8_t), offset);
+ uint32_t file_size = header_.FileSize();
+ buffer[0] = file_size;
+ buffer[1] = header_.GetSize();
+ buffer[2] = header_.EndianTag();
+ buffer[3] = header_.LinkSize();
+ buffer[4] = header_.LinkOffset();
+ buffer[5] = collections.MapItemOffset();
+ buffer[6] = collections.StringIdsSize();
+ buffer[7] = collections.StringIdsOffset();
+ buffer[8] = collections.TypeIdsSize();
+ buffer[9] = collections.TypeIdsOffset();
+ buffer[10] = collections.ProtoIdsSize();
+ buffer[11] = collections.ProtoIdsOffset();
+ buffer[12] = collections.FieldIdsSize();
+ buffer[13] = collections.FieldIdsOffset();
+ buffer[14] = collections.MethodIdsSize();
+ buffer[15] = collections.MethodIdsOffset();
+ uint32_t class_defs_size = collections.ClassDefsSize();
+ uint32_t class_defs_off = collections.ClassDefsOffset();
+ buffer[16] = class_defs_size;
+ buffer[17] = class_defs_off;
+ uint32_t data_off = class_defs_off + class_defs_size * dex_ir::ClassDef::ItemSize();
+ uint32_t data_size = file_size - data_off;
+ buffer[18] = data_size;
+ buffer[19] = data_off;
+ Write(buffer, 20 * sizeof(uint32_t), offset);
+}
+
+void DexWriter::WriteFile() {
+ if (dex_file_.get() == nullptr) {
+ fprintf(stderr, "Can't open output dex file\n");
+ return;
+ }
+
+ WriteStrings();
+ WriteTypes();
+ WriteTypeLists();
+ WriteProtos();
+ WriteFields();
+ WriteMethods();
+ WriteEncodedArrays();
+ WriteAnnotations();
+ WriteAnnotationSets();
+ WriteAnnotationSetRefs();
+ WriteAnnotationsDirectories();
+ WriteDebugInfoItems();
+ WriteCodeItems();
+ WriteClasses();
+ WriteMapItem();
+ WriteHeader();
+}
+
+void DexWriter::OutputDexFile(dex_ir::Header& header, const char* file_name) {
+ (new DexWriter(header, file_name))->WriteFile();
+}
+
+} // namespace art
diff --git a/dexlayout/dex_writer.h b/dexlayout/dex_writer.h
new file mode 100644
index 0000000..9104295
--- /dev/null
+++ b/dexlayout/dex_writer.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2016 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.
+ *
+ * Header file of an in-memory representation of DEX files.
+ */
+
+#ifndef ART_DEXLAYOUT_DEX_WRITER_H_
+#define ART_DEXLAYOUT_DEX_WRITER_H_
+
+#include "base/unix_file/fd_file.h"
+#include "dex_ir.h"
+#include "os.h"
+
+namespace art {
+
+class DexWriter {
+ public:
+ DexWriter(dex_ir::Header& header, const char* file_name) : header_(header),
+ dex_file_(OS::CreateEmptyFileWriteOnly(file_name)) { }
+
+ static void OutputDexFile(dex_ir::Header& header, const char* file_name);
+
+ private:
+ void WriteFile();
+
+ size_t Write(const void* buffer, size_t length, size_t offset);
+ size_t WriteSleb128(uint32_t value, size_t offset);
+ size_t WriteUleb128(uint32_t value, size_t offset);
+ size_t WriteEncodedValue(dex_ir::EncodedValue* encoded_value, size_t offset);
+ size_t WriteEncodedValueHeader(int8_t value_type, size_t value_arg, size_t offset);
+ size_t WriteEncodedArray(dex_ir::EncodedValueVector* values, size_t offset);
+ size_t WriteEncodedAnnotation(dex_ir::EncodedAnnotation* annotation, size_t offset);
+ size_t WriteEncodedFields(dex_ir::FieldItemVector* fields, size_t offset);
+ size_t WriteEncodedMethods(dex_ir::MethodItemVector* methods, size_t offset);
+
+ void WriteStrings();
+ void WriteTypes();
+ void WriteTypeLists();
+ void WriteProtos();
+ void WriteFields();
+ void WriteMethods();
+ void WriteEncodedArrays();
+ void WriteAnnotations();
+ void WriteAnnotationSets();
+ void WriteAnnotationSetRefs();
+ void WriteAnnotationsDirectories();
+ void WriteDebugInfoItems();
+ void WriteCodeItems();
+ void WriteClasses();
+ void WriteMapItem();
+ void WriteHeader();
+
+ dex_ir::Header& header_;
+ std::unique_ptr<File> dex_file_;
+
+ DISALLOW_COPY_AND_ASSIGN(DexWriter);
+};
+
+
+} // namespace art
+
+#endif // ART_DEXLAYOUT_DEX_WRITER_H_
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index e614137..a9ae55f 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -30,11 +30,11 @@
#include <sstream>
#include <vector>
-#include "base/unix_file/fd_file.h"
#include "dex_ir_builder.h"
#include "dex_file-inl.h"
#include "dex_instruction-inl.h"
#include "dex_visualize.h"
+#include "dex_writer.h"
#include "jit/offline_profiling_info.h"
#include "os.h"
#include "utils.h"
@@ -251,10 +251,12 @@
return "<no signature>";
}
- const std::vector<const dex_ir::TypeId*>& params = proto->Parameters();
std::string result("(");
- for (uint32_t i = 0; i < params.size(); ++i) {
- result += params[i]->GetStringId()->Data();
+ const dex_ir::TypeList* type_list = proto->Parameters();
+ if (type_list != nullptr) {
+ for (const dex_ir::TypeId* type_id : *type_list->GetTypeList()) {
+ result += type_id->GetStringId()->Data();
+ }
}
result += ")";
result += proto->ReturnType()->GetStringId()->Data();
@@ -673,7 +675,7 @@
const uint32_t start = try_item->StartAddr();
const uint32_t end = start + try_item->InsnCount();
fprintf(out_file_, " 0x%04x - 0x%04x\n", start, end);
- for (auto& handler : try_item->GetHandlers()) {
+ for (auto& handler : *try_item->GetHandlers()->GetHandlers()) {
const dex_ir::TypeId* type_id = handler->GetTypeId();
const char* descriptor = (type_id == nullptr) ? "<any>" : type_id->GetStringId()->Data();
fprintf(out_file_, " %s -> 0x%04x\n", descriptor, handler->GetAddress());
@@ -1502,96 +1504,6 @@
}
/*
-static uint32_t GetDataSectionOffset(dex_ir::Header& header) {
- return dex_ir::Header::ItemSize() +
- header.GetCollections().StringIdsSize() * dex_ir::StringId::ItemSize() +
- header.GetCollections().TypeIdsSize() * dex_ir::TypeId::ItemSize() +
- header.GetCollections().ProtoIdsSize() * dex_ir::ProtoId::ItemSize() +
- header.GetCollections().FieldIdsSize() * dex_ir::FieldId::ItemSize() +
- header.GetCollections().MethodIdsSize() * dex_ir::MethodId::ItemSize() +
- header.GetCollections().ClassDefsSize() * dex_ir::ClassDef::ItemSize();
-}
-
-static bool Align(File* file, uint32_t& offset) {
- uint8_t zero_buffer[] = { 0, 0, 0 };
- uint32_t zeroes = (-offset) & 3;
- if (zeroes > 0) {
- if (!file->PwriteFully(zero_buffer, zeroes, offset)) {
- return false;
- }
- offset += zeroes;
- }
- return true;
-}
-
-static bool WriteStrings(File* dex_file, dex_ir::Header& header,
- uint32_t& index_offset, uint32_t& data_offset) {
- uint32_t index = 0;
- uint32_t index_buffer[1];
- uint32_t string_length;
- uint32_t length_length;
- uint8_t length_buffer[8];
- for (std::unique_ptr<dex_ir::StringId>& string_id : header.GetCollections().StringIds()) {
- string_id->SetOffset(index);
- index_buffer[0] = data_offset;
- string_length = strlen(string_id->Data());
- length_length = UnsignedLeb128Size(string_length);
- EncodeUnsignedLeb128(length_buffer, string_length);
-
- if (!dex_file->PwriteFully(index_buffer, 4, index_offset) ||
- !dex_file->PwriteFully(length_buffer, length_length, data_offset) ||
- !dex_file->PwriteFully(string_id->Data(), string_length, data_offset + length_length)) {
- return false;
- }
-
- index++;
- index_offset += 4;
- data_offset += string_length + length_length;
- }
- return true;
-}
-
-static bool WriteTypes(File* dex_file, dex_ir::Header& header, uint32_t& index_offset) {
- uint32_t index = 0;
- uint32_t index_buffer[1];
- for (std::unique_ptr<dex_ir::TypeId>& type_id : header.GetCollections().TypeIds()) {
- type_id->SetIndex(index);
- index_buffer[0] = type_id->GetStringId()->GetOffset();
-
- if (!dex_file->PwriteFully(index_buffer, 4, index_offset)) {
- return false;
- }
-
- index++;
- index_offset += 4;
- }
- return true;
-}
-
-static bool WriteTypeLists(File* dex_file, dex_ir::Header& header, uint32_t& data_offset) {
- if (!Align(dex_file, data_offset)) {
- return false;
- }
-
- return true;
-}
-
-static void OutputDexFile(dex_ir::Header& header, const char* file_name) {
- LOG(INFO) << "FILE NAME: " << file_name;
- std::unique_ptr<File> dex_file(OS::CreateEmptyFileWriteOnly(file_name));
- if (dex_file == nullptr) {
- fprintf(stderr, "Can't open %s\n", file_name);
- return;
- }
-
- uint32_t index_offset = dex_ir::Header::ItemSize();
- uint32_t data_offset = GetDataSectionOffset(header);
- WriteStrings(dex_file.get(), header, index_offset, data_offset);
- WriteTypes(dex_file.get(), header, index_offset);
-}
-*/
-
-/*
* Dumps the requested sections of the file.
*/
static void ProcessDexFile(const char* file_name, const DexFile* dex_file, size_t dex_file_index) {
@@ -1634,13 +1546,13 @@
fprintf(out_file_, "</api>\n");
}
- /*
// Output dex file.
- if (options_.output_dex_files_) {
- std::string output_dex_filename = dex_file->GetLocation() + ".out";
- OutputDexFile(*header, output_dex_filename.c_str());
+ if (options_.output_dex_directory_ != nullptr) {
+ std::string output_location(options_.output_dex_directory_);
+ size_t last_slash = dex_file->GetLocation().rfind("/");
+ output_location.append(dex_file->GetLocation().substr(last_slash));
+ DexWriter::OutputDexFile(*header, output_location.c_str());
}
- */
}
/*
diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h
index c4892d2..c01eb79 100644
--- a/dexlayout/dexlayout.h
+++ b/dexlayout/dexlayout.h
@@ -43,7 +43,6 @@
bool disassemble_;
bool exports_only_;
bool ignore_bad_checksum_;
- bool output_dex_files_;
bool show_annotations_;
bool show_cfg_;
bool show_file_headers_;
@@ -51,6 +50,7 @@
bool verbose_;
bool visualize_pattern_;
OutputFormat output_format_;
+ const char* output_dex_directory_;
const char* output_file_name_;
const char* profile_file_name_;
};
diff --git a/dexlayout/dexlayout_main.cc b/dexlayout/dexlayout_main.cc
index f385b09..728e389 100644
--- a/dexlayout/dexlayout_main.cc
+++ b/dexlayout/dexlayout_main.cc
@@ -43,7 +43,7 @@
static void Usage(void) {
fprintf(stderr, "Copyright (C) 2016 The Android Open Source Project\n\n");
fprintf(stderr, "%s: [-a] [-c] [-d] [-e] [-f] [-h] [-i] [-l layout] [-o outfile] [-p profile]"
- " [-s] [-w] dexfile...\n\n", kProgramName);
+ " [-s] [-w directory] dexfile...\n\n", kProgramName);
fprintf(stderr, " -a : display annotations\n");
fprintf(stderr, " -b : build dex_ir\n");
fprintf(stderr, " -c : verify checksum and exit\n");
@@ -57,7 +57,7 @@
fprintf(stderr, " -o : output file name (defaults to stdout)\n");
fprintf(stderr, " -p : profile file name (defaults to no profile)\n");
fprintf(stderr, " -s : visualize reference pattern\n");
- fprintf(stderr, " -w : output dex files\n");
+ fprintf(stderr, " -w : output dex directory \n");
}
/*
@@ -75,7 +75,7 @@
// Parse all arguments.
while (1) {
- const int ic = getopt(argc, argv, "abcdefghil:o:p:sw");
+ const int ic = getopt(argc, argv, "abcdefghil:o:p:sw:");
if (ic < 0) {
break; // done
}
@@ -127,8 +127,8 @@
options_.visualize_pattern_ = true;
options_.verbose_ = false;
break;
- case 'w': // output dex files
- options_.output_dex_files_ = true;
+ case 'w': // output dex files directory
+ options_.output_dex_directory_ = optarg;
break;
default:
want_usage = true;
diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc
index 42b64c3..89544d7 100644
--- a/dexlayout/dexlayout_test.cc
+++ b/dexlayout/dexlayout_test.cc
@@ -31,43 +31,83 @@
protected:
virtual void SetUp() {
CommonRuntimeTest::SetUp();
- // TODO: Test with other dex files for improved coverage.
- // Dogfood our own lib core dex file.
- dex_file_ = GetLibCoreDexFileNames()[0];
}
- // Runs test with given arguments.
- bool Exec(std::string* error_msg) {
+ // Runs FullPlainOutput test.
+ bool FullPlainOutputExec(std::string* error_msg) {
// TODO: dexdump2 -> dexdump ?
ScratchFile dexdump_output;
std::string dexdump_filename = dexdump_output.GetFilename();
std::string dexdump = GetTestAndroidRoot() + "/bin/dexdump2";
EXPECT_TRUE(OS::FileExists(dexdump.c_str())) << dexdump << " should be a valid file path";
- std::vector<std::string> dexdump_exec_argv =
- { dexdump, "-d", "-f", "-h", "-l", "plain", "-o", dexdump_filename, dex_file_ };
ScratchFile dexlayout_output;
std::string dexlayout_filename = dexlayout_output.GetFilename();
std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
- std::vector<std::string> dexlayout_exec_argv =
- { dexlayout, "-d", "-f", "-h", "-l", "plain", "-o", dexlayout_filename, dex_file_ };
- if (!::art::Exec(dexdump_exec_argv, error_msg)) {
- return false;
- }
- if (!::art::Exec(dexlayout_exec_argv, error_msg)) {
- return false;
- }
- std::vector<std::string> diff_exec_argv =
- { "/usr/bin/diff", dexdump_filename, dexlayout_filename };
- if (!::art::Exec(diff_exec_argv, error_msg)) {
- return false;
+ for (const std::string &dex_file : GetLibCoreDexFileNames()) {
+ std::vector<std::string> dexdump_exec_argv =
+ { dexdump, "-d", "-f", "-h", "-l", "plain", "-o", dexdump_filename, dex_file };
+ std::vector<std::string> dexlayout_exec_argv =
+ { dexlayout, "-d", "-f", "-h", "-l", "plain", "-o", dexlayout_filename, dex_file };
+
+ if (!::art::Exec(dexdump_exec_argv, error_msg)) {
+ return false;
+ }
+ if (!::art::Exec(dexlayout_exec_argv, error_msg)) {
+ return false;
+ }
+ std::vector<std::string> diff_exec_argv =
+ { "/usr/bin/diff", dexdump_filename, dexlayout_filename };
+ if (!::art::Exec(diff_exec_argv, error_msg)) {
+ return false;
+ }
}
return true;
}
- std::string dex_file_;
+ // Runs DexFileOutput test.
+ bool DexFileOutputExec(std::string* error_msg) {
+ ScratchFile tmp_file;
+ std::string tmp_name = tmp_file.GetFilename();
+ size_t tmp_last_slash = tmp_name.rfind("/");
+ std::string tmp_dir = tmp_name.substr(0, tmp_last_slash + 1);
+ std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
+ EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
+
+ for (const std::string &dex_file : GetLibCoreDexFileNames()) {
+ std::vector<std::string> dexlayout_exec_argv =
+ { dexlayout, "-d", "-f", "-h", "-l", "plain", "-w", tmp_dir, "-o", tmp_name, dex_file };
+
+ if (!::art::Exec(dexlayout_exec_argv, error_msg)) {
+ return false;
+ }
+
+ size_t dex_file_last_slash = dex_file.rfind("/");
+ std::string dex_file_name = dex_file.substr(dex_file_last_slash + 1);
+ std::vector<std::string> unzip_exec_argv =
+ { "/usr/bin/unzip", dex_file, "classes.dex", "-d", tmp_dir};
+ if (!::art::Exec(unzip_exec_argv, error_msg)) {
+ return false;
+ }
+ std::vector<std::string> diff_exec_argv =
+ { "/usr/bin/diff", tmp_dir + "classes.dex" , tmp_dir + dex_file_name };
+ if (!::art::Exec(diff_exec_argv, error_msg)) {
+ return false;
+ }
+ std::vector<std::string> rm_zip_exec_argv = { "/bin/rm", tmp_dir + "classes.dex" };
+ if (!::art::Exec(rm_zip_exec_argv, error_msg)) {
+ return false;
+ }
+ std::vector<std::string> rm_out_exec_argv = { "/bin/rm", tmp_dir + dex_file_name };
+ if (!::art::Exec(rm_out_exec_argv, error_msg)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
};
@@ -75,7 +115,14 @@
// Disable test on target.
TEST_DISABLED_FOR_TARGET();
std::string error_msg;
- ASSERT_TRUE(Exec(&error_msg)) << error_msg;
+ ASSERT_TRUE(FullPlainOutputExec(&error_msg)) << error_msg;
+}
+
+TEST_F(DexLayoutTest, DexFileOutput) {
+ // Disable test on target.
+ TEST_DISABLED_FOR_TARGET();
+ std::string error_msg;
+ ASSERT_TRUE(DexFileOutputExec(&error_msg)) << error_msg;
}
} // namespace art
diff --git a/runtime/base/dumpable-inl.h b/runtime/base/dumpable-inl.h
new file mode 100644
index 0000000..2cdf083
--- /dev/null
+++ b/runtime/base/dumpable-inl.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_BASE_DUMPABLE_INL_H_
+#define ART_RUNTIME_BASE_DUMPABLE_INL_H_
+
+#include "base/dumpable.h"
+#include "base/mutex.h"
+#include "thread-inl.h"
+
+namespace art {
+
+template<typename T>
+inline std::ostream& operator<<(std::ostream& os, const MutatorLockedDumpable<T>& rhs) {
+ Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
+ rhs.Dump(os);
+ return os;
+}
+
+} // namespace art
+
+#endif // ART_RUNTIME_BASE_DUMPABLE_INL_H_
diff --git a/runtime/base/dumpable.h b/runtime/base/dumpable.h
index 9bc4089..9ef8d69 100644
--- a/runtime/base/dumpable.h
+++ b/runtime/base/dumpable.h
@@ -20,6 +20,7 @@
#include <ostream>
#include "base/macros.h"
+#include "base/mutex.h"
namespace art {
@@ -50,6 +51,27 @@
return os;
}
+template<typename T>
+class MutatorLockedDumpable {
+ public:
+ explicit MutatorLockedDumpable(T& value) REQUIRES_SHARED(Locks::mutator_lock_) : value_(value) {}
+
+ void Dump(std::ostream& os) const REQUIRES_SHARED(Locks::mutator_lock_) {
+ value_.Dump(os);
+ }
+
+ private:
+ const T& value_;
+
+ DISALLOW_COPY_AND_ASSIGN(MutatorLockedDumpable);
+};
+
+template<typename T>
+std::ostream& operator<<(std::ostream& os, const MutatorLockedDumpable<T>& rhs)
+ // TODO: should be REQUIRES_SHARED(Locks::mutator_lock_) however annotalysis
+ // currently fails for this.
+ NO_THREAD_SAFETY_ANALYSIS;
+
} // namespace art
#endif // ART_RUNTIME_BASE_DUMPABLE_H_
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 53135b6..ed0f0c0 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -4297,11 +4297,11 @@
CHECK_EQ(interfaces_sfield.GetDeclaringClass(), klass.Get());
interfaces_sfield.SetObject<false>(
klass.Get(),
- soa.Decode<mirror::ObjectArray<mirror::Class>>(interfaces).Ptr());
+ soa.Decode<mirror::ObjectArray<mirror::Class>>(interfaces));
CHECK_EQ(throws_sfield.GetDeclaringClass(), klass.Get());
throws_sfield.SetObject<false>(
klass.Get(),
- soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class>>>(throws).Ptr());
+ soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class>>>(throws));
{
// Lock on klass is released. Lock new class object.
@@ -4331,9 +4331,9 @@
CHECK_EQ(PrettyField(klass->GetStaticField(1)), throws_field_name);
CHECK_EQ(klass.Get()->GetInterfaces(),
- soa.Decode<mirror::ObjectArray<mirror::Class>>(interfaces).Ptr());
+ soa.Decode<mirror::ObjectArray<mirror::Class>>(interfaces));
CHECK_EQ(klass.Get()->GetThrows(),
- soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class>>>(throws).Ptr());
+ soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class>>>(throws));
}
return klass.Get();
}
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 5466539..d45495c 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -875,7 +875,7 @@
uint32_t type_idx = klass->GetClassDef()->class_idx_;
ObjPtr<mirror::DexCache> dex_cache = klass->GetDexCache();
const DexFile& dex_file = klass->GetDexFile();
- EXPECT_EQ(dex_cache->GetResolvedType(type_idx), klass.Ptr());
+ EXPECT_OBJ_PTR_EQ(dex_cache->GetResolvedType(type_idx), klass);
EXPECT_OBJ_PTR_EQ(
class_linker_->LookupResolvedType(dex_file, type_idx, dex_cache, class_loader.Get()),
klass);
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index a7feeef..7006f70 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -1995,7 +1995,7 @@
CHECK(thread_object != nullptr) << error;
ArtField* java_lang_Thread_name_field =
soa.DecodeField(WellKnownClasses::java_lang_Thread_name);
- ObjPtr<mirror::String> s(java_lang_Thread_name_field->GetObject(thread_object));
+ ObjPtr<mirror::String> s(java_lang_Thread_name_field->GetObject(thread_object)->AsString());
if (s != nullptr) {
*name = s->ToModifiedUtf8();
}
diff --git a/runtime/indirect_reference_table-inl.h b/runtime/indirect_reference_table-inl.h
index 5cc1de2..e05f8f3 100644
--- a/runtime/indirect_reference_table-inl.h
+++ b/runtime/indirect_reference_table-inl.h
@@ -19,7 +19,9 @@
#include "indirect_reference_table.h"
+#include "base/dumpable.h"
#include "gc_root-inl.h"
+#include "obj_ptr-inl.h"
#include "runtime-inl.h"
#include "verify_object-inl.h"
@@ -82,17 +84,17 @@
}
template<ReadBarrierOption kReadBarrierOption>
-inline mirror::Object* IndirectReferenceTable::Get(IndirectRef iref) const {
+inline ObjPtr<mirror::Object> IndirectReferenceTable::Get(IndirectRef iref) const {
if (!GetChecked(iref)) {
return nullptr;
}
uint32_t idx = ExtractIndex(iref);
- mirror::Object* obj = table_[idx].GetReference()->Read<kReadBarrierOption>();
- VerifyObject(obj);
+ ObjPtr<mirror::Object> obj = table_[idx].GetReference()->Read<kReadBarrierOption>();
+ VerifyObject(obj.Ptr());
return obj;
}
-inline void IndirectReferenceTable::Update(IndirectRef iref, mirror::Object* obj) {
+inline void IndirectReferenceTable::Update(IndirectRef iref, ObjPtr<mirror::Object> obj) {
if (!GetChecked(iref)) {
LOG(WARNING) << "IndirectReferenceTable Update failed to find reference " << iref;
return;
@@ -101,6 +103,19 @@
table_[idx].SetReference(obj);
}
+inline void IrtEntry::Add(ObjPtr<mirror::Object> obj) {
+ ++serial_;
+ if (serial_ == kIRTPrevCount) {
+ serial_ = 0;
+ }
+ references_[serial_] = GcRoot<mirror::Object>(obj);
+}
+
+inline void IrtEntry::SetReference(ObjPtr<mirror::Object> obj) {
+ DCHECK_LT(serial_, kIRTPrevCount);
+ references_[serial_] = GcRoot<mirror::Object>(obj);
+}
+
} // namespace art
#endif // ART_RUNTIME_INDIRECT_REFERENCE_TABLE_INL_H_
diff --git a/runtime/indirect_reference_table.cc b/runtime/indirect_reference_table.cc
index b742ccc..d59bb39 100644
--- a/runtime/indirect_reference_table.cc
+++ b/runtime/indirect_reference_table.cc
@@ -16,6 +16,7 @@
#include "indirect_reference_table-inl.h"
+#include "base/dumpable-inl.h"
#include "base/systrace.h"
#include "jni_internal.h"
#include "nth_caller_visitor.h"
@@ -46,32 +47,6 @@
return "IndirectRefKind Error";
}
-template<typename T>
-class MutatorLockedDumpable {
- public:
- explicit MutatorLockedDumpable(T& value)
- REQUIRES_SHARED(Locks::mutator_lock_) : value_(value) {
- }
-
- void Dump(std::ostream& os) const REQUIRES_SHARED(Locks::mutator_lock_) {
- value_.Dump(os);
- }
-
- private:
- T& value_;
-
- DISALLOW_COPY_AND_ASSIGN(MutatorLockedDumpable);
-};
-
-template<typename T>
-std::ostream& operator<<(std::ostream& os, const MutatorLockedDumpable<T>& rhs)
-// TODO: should be REQUIRES_SHARED(Locks::mutator_lock_) however annotalysis
-// currently fails for this.
- NO_THREAD_SAFETY_ANALYSIS {
- rhs.Dump(os);
- return os;
-}
-
void IndirectReferenceTable::AbortIfNoCheckJNI(const std::string& msg) {
// If -Xcheck:jni is on, it'll give a more detailed error before aborting.
JavaVMExt* vm = Runtime::Current()->GetJavaVM();
@@ -118,13 +93,13 @@
return table_mem_map_.get() != nullptr;
}
-IndirectRef IndirectReferenceTable::Add(uint32_t cookie, mirror::Object* obj) {
+IndirectRef IndirectReferenceTable::Add(uint32_t cookie, ObjPtr<mirror::Object> obj) {
IRTSegmentState prevState;
prevState.all = cookie;
size_t topIndex = segment_state_.parts.topIndex;
CHECK(obj != nullptr);
- VerifyObject(obj);
+ VerifyObject(obj.Ptr());
DCHECK(table_ != nullptr);
DCHECK_GE(segment_state_.parts.numHoles, prevState.parts.numHoles);
@@ -171,9 +146,9 @@
void IndirectReferenceTable::AssertEmpty() {
for (size_t i = 0; i < Capacity(); ++i) {
if (!table_[i].GetReference()->IsNull()) {
- ScopedObjectAccess soa(Thread::Current());
LOG(FATAL) << "Internal Error: non-empty local reference table\n"
<< MutatorLockedDumpable<IndirectReferenceTable>(*this);
+ UNREACHABLE();
}
}
}
@@ -299,7 +274,7 @@
os << kind_ << " table dump:\n";
ReferenceTable::Table entries;
for (size_t i = 0; i < Capacity(); ++i) {
- mirror::Object* obj = table_[i].GetReference()->Read<kWithoutReadBarrier>();
+ ObjPtr<mirror::Object> obj = table_[i].GetReference()->Read<kWithoutReadBarrier>();
if (obj != nullptr) {
obj = table_[i].GetReference()->Read();
entries.push_back(GcRoot<mirror::Object>(obj));
diff --git a/runtime/indirect_reference_table.h b/runtime/indirect_reference_table.h
index e194f79..64de7a8 100644
--- a/runtime/indirect_reference_table.h
+++ b/runtime/indirect_reference_table.h
@@ -25,6 +25,7 @@
#include "base/logging.h"
#include "base/mutex.h"
#include "gc_root.h"
+#include "obj_ptr.h"
#include "object_callbacks.h"
#include "offsets.h"
#include "read_barrier_option.h"
@@ -200,24 +201,18 @@
static const size_t kIRTPrevCount = kIsDebugBuild ? 7 : 3;
class IrtEntry {
public:
- void Add(mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) {
- ++serial_;
- if (serial_ == kIRTPrevCount) {
- serial_ = 0;
- }
- references_[serial_] = GcRoot<mirror::Object>(obj);
- }
+ void Add(ObjPtr<mirror::Object> obj) REQUIRES_SHARED(Locks::mutator_lock_);
+
GcRoot<mirror::Object>* GetReference() {
DCHECK_LT(serial_, kIRTPrevCount);
return &references_[serial_];
}
+
uint32_t GetSerial() const {
return serial_;
}
- void SetReference(mirror::Object* obj) {
- DCHECK_LT(serial_, kIRTPrevCount);
- references_[serial_] = GcRoot<mirror::Object>(obj);
- }
+
+ void SetReference(ObjPtr<mirror::Object> obj) REQUIRES_SHARED(Locks::mutator_lock_);
private:
uint32_t serial_;
@@ -237,7 +232,7 @@
return *this;
}
- GcRoot<mirror::Object>* operator*() {
+ GcRoot<mirror::Object>* operator*() REQUIRES_SHARED(Locks::mutator_lock_) {
// This does not have a read barrier as this is used to visit roots.
return table_[i_].GetReference();
}
@@ -277,7 +272,7 @@
* Returns nullptr if the table is full (max entries reached, or alloc
* failed during expansion).
*/
- IndirectRef Add(uint32_t cookie, mirror::Object* obj)
+ IndirectRef Add(uint32_t cookie, ObjPtr<mirror::Object> obj)
REQUIRES_SHARED(Locks::mutator_lock_);
/*
@@ -286,12 +281,13 @@
* Returns kInvalidIndirectRefObject if iref is invalid.
*/
template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
- mirror::Object* Get(IndirectRef iref) const REQUIRES_SHARED(Locks::mutator_lock_)
+ ObjPtr<mirror::Object> Get(IndirectRef iref) const REQUIRES_SHARED(Locks::mutator_lock_)
ALWAYS_INLINE;
// Synchronized get which reads a reference, acquiring a lock if necessary.
template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
- mirror::Object* SynchronizedGet(IndirectRef iref) const REQUIRES_SHARED(Locks::mutator_lock_) {
+ ObjPtr<mirror::Object> SynchronizedGet(IndirectRef iref) const
+ REQUIRES_SHARED(Locks::mutator_lock_) {
return Get<kReadBarrierOption>(iref);
}
@@ -300,7 +296,7 @@
*
* Updates an existing indirect reference to point to a new object.
*/
- void Update(IndirectRef iref, mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_);
+ void Update(IndirectRef iref, ObjPtr<mirror::Object> obj) REQUIRES_SHARED(Locks::mutator_lock_);
/*
* Remove an existing entry.
@@ -313,7 +309,7 @@
*/
bool Remove(uint32_t cookie, IndirectRef iref);
- void AssertEmpty();
+ void AssertEmpty() REQUIRES_SHARED(Locks::mutator_lock_);
void Dump(std::ostream& os) const REQUIRES_SHARED(Locks::mutator_lock_);
@@ -377,7 +373,7 @@
static void AbortIfNoCheckJNI(const std::string& msg);
/* extra debugging checks */
- bool GetChecked(IndirectRef) const;
+ bool GetChecked(IndirectRef) const REQUIRES_SHARED(Locks::mutator_lock_);
bool CheckEntry(const char*, IndirectRef, int) const;
/* semi-public - read/write by jni down calls */
diff --git a/runtime/indirect_reference_table_test.cc b/runtime/indirect_reference_table_test.cc
index 58d487d..0380f3e 100644
--- a/runtime/indirect_reference_table_test.cc
+++ b/runtime/indirect_reference_table_test.cc
@@ -81,9 +81,9 @@
EXPECT_TRUE(iref2 != nullptr);
CheckDump(&irt, 3, 3);
- EXPECT_EQ(obj0, irt.Get(iref0));
- EXPECT_EQ(obj1, irt.Get(iref1));
- EXPECT_EQ(obj2, irt.Get(iref2));
+ EXPECT_OBJ_PTR_EQ(obj0, irt.Get(iref0));
+ EXPECT_OBJ_PTR_EQ(obj1, irt.Get(iref1));
+ EXPECT_OBJ_PTR_EQ(obj2, irt.Get(iref2));
EXPECT_TRUE(irt.Remove(cookie, iref0));
CheckDump(&irt, 2, 2);
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 6b28110..7d54d0a 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -185,6 +185,13 @@
return false;
}
const uint32_t vtable_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
+ // Debug code for b/31357497. To be removed.
+ if (kUseReadBarrier) {
+ CHECK(receiver->GetClass() != nullptr)
+ << "Null class found in object " << receiver << " in region type "
+ << Runtime::Current()->GetHeap()->ConcurrentCopyingCollector()->
+ RegionSpace()->GetRegionType(receiver);
+ }
CHECK(receiver->GetClass()->ShouldHaveEmbeddedVTable());
ArtMethod* const called_method = receiver->GetClass()->GetEmbeddedVTableEntry(
vtable_idx, kRuntimePointerSize);
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index 89cbbe6..ac5401f 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -1441,15 +1441,15 @@
JNIEnvExt* env = self->GetJniEnv();
ScopedObjectAccessUnchecked soa(self);
- mirror::Object* java_method_obj = shadow_frame->GetVRegReference(arg_offset);
+ ObjPtr<mirror::Object> java_method_obj = shadow_frame->GetVRegReference(arg_offset);
ScopedLocalRef<jobject> java_method(env,
java_method_obj == nullptr ? nullptr :env->AddLocalReference<jobject>(java_method_obj));
- mirror::Object* java_receiver_obj = shadow_frame->GetVRegReference(arg_offset + 1);
+ ObjPtr<mirror::Object> java_receiver_obj = shadow_frame->GetVRegReference(arg_offset + 1);
ScopedLocalRef<jobject> java_receiver(env,
java_receiver_obj == nullptr ? nullptr : env->AddLocalReference<jobject>(java_receiver_obj));
- mirror::Object* java_args_obj = shadow_frame->GetVRegReference(arg_offset + 2);
+ ObjPtr<mirror::Object> java_args_obj = shadow_frame->GetVRegReference(arg_offset + 2);
ScopedLocalRef<jobject> java_args(env,
java_args_obj == nullptr ? nullptr : env->AddLocalReference<jobject>(java_args_obj));
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc
index 215f2b3..101c146 100644
--- a/runtime/java_vm_ext.cc
+++ b/runtime/java_vm_ext.cc
@@ -538,7 +538,7 @@
return nullptr;
}
WriterMutexLock mu(self, globals_lock_);
- IndirectRef ref = globals_.Add(IRT_FIRST_SEGMENT, obj.Ptr());
+ IndirectRef ref = globals_.Add(IRT_FIRST_SEGMENT, obj);
return reinterpret_cast<jobject>(ref);
}
@@ -550,7 +550,7 @@
while (UNLIKELY(!MayAccessWeakGlobals(self))) {
weak_globals_add_condition_.WaitHoldingLocks(self);
}
- IndirectRef ref = weak_globals_.Add(IRT_FIRST_SEGMENT, obj.Ptr());
+ IndirectRef ref = weak_globals_.Add(IRT_FIRST_SEGMENT, obj);
return reinterpret_cast<jweak>(ref);
}
@@ -641,7 +641,7 @@
}
mirror::Object* JavaVMExt::DecodeGlobal(IndirectRef ref) {
- return globals_.SynchronizedGet(ref);
+ return globals_.SynchronizedGet(ref).Ptr();
}
void JavaVMExt::UpdateGlobal(Thread* self, IndirectRef ref, mirror::Object* result) {
@@ -669,7 +669,7 @@
// if MayAccessWeakGlobals is false.
DCHECK_EQ(GetIndirectRefKind(ref), kWeakGlobal);
if (LIKELY(MayAccessWeakGlobalsUnlocked(self))) {
- return weak_globals_.SynchronizedGet(ref);
+ return weak_globals_.SynchronizedGet(ref).Ptr();
}
MutexLock mu(self, weak_globals_lock_);
return DecodeWeakGlobalLocked(self, ref);
@@ -682,7 +682,7 @@
while (UNLIKELY(!MayAccessWeakGlobals(self))) {
weak_globals_add_condition_.WaitHoldingLocks(self);
}
- return weak_globals_.Get(ref);
+ return weak_globals_.Get(ref).Ptr();
}
mirror::Object* JavaVMExt::DecodeWeakGlobalDuringShutdown(Thread* self, IndirectRef ref) {
@@ -695,7 +695,7 @@
if (!kUseReadBarrier) {
DCHECK(allow_accessing_weak_globals_.LoadSequentiallyConsistent());
}
- return weak_globals_.SynchronizedGet(ref);
+ return weak_globals_.SynchronizedGet(ref).Ptr();
}
bool JavaVMExt::IsWeakGlobalCleared(Thread* self, IndirectRef ref) {
diff --git a/runtime/jni_env_ext-inl.h b/runtime/jni_env_ext-inl.h
index 685b056..2cc7342 100644
--- a/runtime/jni_env_ext-inl.h
+++ b/runtime/jni_env_ext-inl.h
@@ -19,12 +19,14 @@
#include "jni_env_ext.h"
+#include "indirect_reference_table-inl.h"
+#include "obj_ptr-inl.h"
#include "utils.h"
namespace art {
template<typename T>
-inline T JNIEnvExt::AddLocalReference(mirror::Object* obj) {
+inline T JNIEnvExt::AddLocalReference(ObjPtr<mirror::Object> obj) {
IndirectRef ref = locals.Add(local_ref_cookie, obj);
// TODO: fix this to understand PushLocalFrame, so we can turn it on.
diff --git a/runtime/jni_env_ext.h b/runtime/jni_env_ext.h
index 79dfb0d..121f848 100644
--- a/runtime/jni_env_ext.h
+++ b/runtime/jni_env_ext.h
@@ -47,8 +47,7 @@
void PopFrame() REQUIRES_SHARED(Locks::mutator_lock_);
template<typename T>
- T AddLocalReference(mirror::Object* obj)
- REQUIRES_SHARED(Locks::mutator_lock_);
+ T AddLocalReference(ObjPtr<mirror::Object> obj) REQUIRES_SHARED(Locks::mutator_lock_);
static Offset SegmentStateOffset(size_t pointer_size);
static Offset LocalRefCookieOffset(size_t pointer_size);
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 1cfed74..cc088b8 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -448,7 +448,7 @@
inline bool Class::CheckResolvedFieldAccess(ObjPtr<Class> access_to,
ArtField* field,
uint32_t field_idx) {
- return ResolvedFieldAccessTest<true, true>(access_to.Ptr(), field, field_idx, nullptr);
+ return ResolvedFieldAccessTest<true, true>(access_to, field, field_idx, nullptr);
}
inline bool Class::CanAccessResolvedMethod(Class* access_to, ArtMethod* method,
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 87bff5f..2a5c04d 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -677,11 +677,10 @@
if (caller.Get() == nullptr) {
caller.Assign(GetCallingClass(soa.Self(), 1));
}
- if (UNLIKELY(caller.Get() != nullptr && !VerifyAccess(
- MakeObjPtr(receiver.Get()),
- MakeObjPtr(declaring_class),
- constructor->GetAccessFlags(),
- MakeObjPtr(caller.Get())))) {
+ if (UNLIKELY(caller.Get() != nullptr && !VerifyAccess(receiver.Get(),
+ declaring_class,
+ constructor->GetAccessFlags(),
+ caller.Get()))) {
soa.Self()->ThrowNewExceptionF(
"Ljava/lang/IllegalAccessException;", "%s is not accessible from %s",
PrettyMethod(constructor).c_str(), PrettyClass(caller.Get()).c_str());
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index 07b59dd..90def44 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -31,8 +31,9 @@
namespace art {
template<bool kIsSet>
-ALWAYS_INLINE inline static bool VerifyFieldAccess(Thread* self, mirror::Field* field,
- mirror::Object* obj)
+ALWAYS_INLINE inline static bool VerifyFieldAccess(Thread* self,
+ ObjPtr<mirror::Field> field,
+ ObjPtr<mirror::Object> obj)
REQUIRES_SHARED(Locks::mutator_lock_) {
if (kIsSet && field->IsFinal()) {
ThrowIllegalAccessException(
@@ -45,8 +46,8 @@
}
ObjPtr<mirror::Class> calling_class;
if (!VerifyAccess(self,
- MakeObjPtr(obj),
- MakeObjPtr(field->GetDeclaringClass()),
+ obj,
+ field->GetDeclaringClass(),
field->GetAccessFlags(),
&calling_class,
1)) {
@@ -63,8 +64,10 @@
}
template<bool kAllowReferences>
-ALWAYS_INLINE inline static bool GetFieldValue(mirror::Object* o, mirror::Field* f,
- Primitive::Type field_type, JValue* value)
+ALWAYS_INLINE inline static bool GetFieldValue(ObjPtr<mirror::Object> o,
+ ObjPtr<mirror::Field> f,
+ Primitive::Type field_type,
+ JValue* value)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK_EQ(value->GetJ(), INT64_C(0));
MemberOffset offset(f->GetOffset());
@@ -108,27 +111,28 @@
}
ALWAYS_INLINE inline static bool CheckReceiver(const ScopedFastNativeObjectAccess& soa,
- jobject j_rcvr, mirror::Field** f,
- mirror::Object** class_or_rcvr)
+ jobject j_rcvr,
+ ObjPtr<mirror::Field>* f,
+ ObjPtr<mirror::Object>* class_or_rcvr)
REQUIRES_SHARED(Locks::mutator_lock_) {
soa.Self()->AssertThreadSuspensionIsAllowable();
- mirror::Class* declaringClass = (*f)->GetDeclaringClass();
+ ObjPtr<mirror::Class> declaring_class = (*f)->GetDeclaringClass();
if ((*f)->IsStatic()) {
- if (UNLIKELY(!declaringClass->IsInitialized())) {
+ if (UNLIKELY(!declaring_class->IsInitialized())) {
StackHandleScope<2> hs(soa.Self());
- HandleWrapper<mirror::Field> h_f(hs.NewHandleWrapper(f));
- HandleWrapper<mirror::Class> h_klass(hs.NewHandleWrapper(&declaringClass));
+ HandleWrapperObjPtr<mirror::Field> h_f(hs.NewHandleWrapper(f));
+ HandleWrapperObjPtr<mirror::Class> h_klass(hs.NewHandleWrapper(&declaring_class));
ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
if (UNLIKELY(!class_linker->EnsureInitialized(soa.Self(), h_klass, true, true))) {
DCHECK(soa.Self()->IsExceptionPending());
return false;
}
}
- *class_or_rcvr = declaringClass;
+ *class_or_rcvr = declaring_class;
return true;
}
- *class_or_rcvr = soa.Decode<mirror::Object>(j_rcvr).Ptr();
- if (!VerifyObjectIsClass(MakeObjPtr(*class_or_rcvr), MakeObjPtr(declaringClass))) {
+ *class_or_rcvr = soa.Decode<mirror::Object>(j_rcvr);
+ if (!VerifyObjectIsClass(*class_or_rcvr, declaring_class)) {
DCHECK(soa.Self()->IsExceptionPending());
return false;
}
@@ -137,8 +141,8 @@
static jobject Field_get(JNIEnv* env, jobject javaField, jobject javaObj) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Field* f = soa.Decode<mirror::Field>(javaField).Ptr();
- mirror::Object* o = nullptr;
+ ObjPtr<mirror::Field> f = soa.Decode<mirror::Field>(javaField);
+ ObjPtr<mirror::Object> o;
if (!CheckReceiver(soa, javaObj, &f, &o)) {
DCHECK(soa.Self()->IsExceptionPending());
return nullptr;
@@ -156,15 +160,16 @@
DCHECK(soa.Self()->IsExceptionPending());
return nullptr;
}
- return soa.AddLocalReference<jobject>(BoxPrimitive(field_type, value).Ptr());
+ return soa.AddLocalReference<jobject>(BoxPrimitive(field_type, value));
}
template<Primitive::Type kPrimitiveType>
-ALWAYS_INLINE inline static JValue GetPrimitiveField(JNIEnv* env, jobject javaField,
+ALWAYS_INLINE inline static JValue GetPrimitiveField(JNIEnv* env,
+ jobject javaField,
jobject javaObj) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Field* f = soa.Decode<mirror::Field>(javaField).Ptr();
- mirror::Object* o = nullptr;
+ ObjPtr<mirror::Field> f = soa.Decode<mirror::Field>(javaField);
+ ObjPtr<mirror::Object> o;
if (!CheckReceiver(soa, javaObj, &f, &o)) {
DCHECK(soa.Self()->IsExceptionPending());
return JValue();
@@ -234,8 +239,10 @@
return GetPrimitiveField<Primitive::kPrimShort>(env, javaField, javaObj).GetS();
}
-ALWAYS_INLINE inline static void SetFieldValue(mirror::Object* o, mirror::Field* f,
- Primitive::Type field_type, bool allow_references,
+ALWAYS_INLINE inline static void SetFieldValue(ObjPtr<mirror::Object> o,
+ ObjPtr<mirror::Field> f,
+ Primitive::Type field_type,
+ bool allow_references,
const JValue& new_value)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(f->GetDeclaringClass()->IsInitialized());
@@ -307,14 +314,14 @@
static void Field_set(JNIEnv* env, jobject javaField, jobject javaObj, jobject javaValue) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Field* f = soa.Decode<mirror::Field>(javaField).Ptr();
+ ObjPtr<mirror::Field> f = soa.Decode<mirror::Field>(javaField);
// Check that the receiver is non-null and an instance of the field's declaring class.
- mirror::Object* o = nullptr;
+ ObjPtr<mirror::Object> o;
if (!CheckReceiver(soa, javaObj, &f, &o)) {
DCHECK(soa.Self()->IsExceptionPending());
return;
}
- mirror::Class* field_type;
+ ObjPtr<mirror::Class> field_type;
const char* field_type_desciptor = f->GetArtField()->GetTypeDescriptor();
Primitive::Type field_prim_type = Primitive::GetType(field_type_desciptor[0]);
if (field_prim_type == Primitive::kPrimNot) {
@@ -328,7 +335,7 @@
ObjPtr<mirror::Object> boxed_value = soa.Decode<mirror::Object>(javaValue);
JValue unboxed_value;
if (!UnboxPrimitiveForField(boxed_value,
- MakeObjPtr(field_type),
+ field_type,
f->GetArtField(),
&unboxed_value)) {
DCHECK(soa.Self()->IsExceptionPending());
@@ -343,11 +350,13 @@
}
template<Primitive::Type kPrimitiveType>
-static void SetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj,
+static void SetPrimitiveField(JNIEnv* env,
+ jobject javaField,
+ jobject javaObj,
const JValue& new_value) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Field* f = soa.Decode<mirror::Field>(javaField).Ptr();
- mirror::Object* o = nullptr;
+ ObjPtr<mirror::Field> f = soa.Decode<mirror::Field>(javaField);
+ ObjPtr<mirror::Object> o;
if (!CheckReceiver(soa, javaObj, &f, &o)) {
return;
}
@@ -439,11 +448,10 @@
ArtField* field = soa.Decode<mirror::Field>(javaField)->GetArtField();
if (field->GetDeclaringClass()->IsProxyClass()) {
// Return an empty array instead of a null pointer.
- mirror::Class* annotation_array_class =
- soa.Decode<mirror::Class>(
- WellKnownClasses::java_lang_annotation_Annotation__array).Ptr();
- mirror::ObjectArray<mirror::Object>* empty_array =
- mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), annotation_array_class, 0);
+ ObjPtr<mirror::Class> annotation_array_class =
+ soa.Decode<mirror::Class>(WellKnownClasses::java_lang_annotation_Annotation__array);
+ ObjPtr<mirror::ObjectArray<mirror::Object>> empty_array =
+ mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), annotation_array_class.Ptr(), 0);
return soa.AddLocalReference<jobjectArray>(empty_array);
}
return soa.AddLocalReference<jobjectArray>(annotations::GetAnnotationsForField(field));
@@ -458,7 +466,8 @@
return soa.AddLocalReference<jobjectArray>(annotations::GetSignatureAnnotationForField(field));
}
-static jboolean Field_isAnnotationPresentNative(JNIEnv* env, jobject javaField,
+static jboolean Field_isAnnotationPresentNative(JNIEnv* env,
+ jobject javaField,
jclass annotationType) {
ScopedFastNativeObjectAccess soa(env);
StackHandleScope<1> hs(soa.Self());
diff --git a/runtime/obj_ptr.h b/runtime/obj_ptr.h
index beb4d33..6688ba7 100644
--- a/runtime/obj_ptr.h
+++ b/runtime/obj_ptr.h
@@ -18,6 +18,7 @@
#define ART_RUNTIME_OBJ_PTR_H_
#include <ostream>
+#include <type_traits>
#include "base/mutex.h" // For Locks::mutator_lock_.
#include "globals.h"
@@ -45,14 +46,23 @@
template <typename Type>
ALWAYS_INLINE ObjPtr(Type* ptr) REQUIRES_SHARED(Locks::mutator_lock_)
- : reference_(Encode(static_cast<MirrorType*>(ptr))) {}
+ : reference_(Encode(static_cast<MirrorType*>(ptr))) {
+ static_assert(std::is_base_of<MirrorType, Type>::value,
+ "Input type must be a subtype of the ObjPtr type");
+ }
template <typename Type>
- ALWAYS_INLINE ObjPtr(const ObjPtr<Type>& other) REQUIRES_SHARED(Locks::mutator_lock_)
- : reference_(Encode(static_cast<MirrorType*>(other.Ptr()))) {}
+ ALWAYS_INLINE ObjPtr(const ObjPtr<Type, kPoison>& other) REQUIRES_SHARED(Locks::mutator_lock_)
+ : reference_(Encode(static_cast<MirrorType*>(other.Ptr()))) {
+ static_assert(std::is_base_of<MirrorType, Type>::value,
+ "Input type must be a subtype of the ObjPtr type");
+ }
template <typename Type>
- ALWAYS_INLINE ObjPtr& operator=(const ObjPtr& other) {
+ ALWAYS_INLINE ObjPtr& operator=(const ObjPtr<Type, kPoison>& other)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ static_assert(std::is_base_of<MirrorType, Type>::value,
+ "Input type must be a subtype of the ObjPtr type");
reference_ = Encode(static_cast<MirrorType*>(other.Ptr()));
return *this;
}
diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
index a1a2361..bebc2fc 100644
--- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
@@ -38,7 +38,11 @@
#include "art_jvmti.h"
#include "jni_env_ext-inl.h"
+#include "object_tagging.h"
+#include "obj_ptr-inl.h"
#include "runtime.h"
+#include "scoped_thread_state_change-inl.h"
+#include "thread_list.h"
#include "transform.h"
// TODO Remove this at some point by annotating all the methods. It was put in to make the skeleton
@@ -47,6 +51,8 @@
namespace openjdkjvmti {
+ObjectTagTable gObjectTagTable;
+
class JvmtiFunctions {
private:
static bool IsValidEnv(jvmtiEnv* env) {
@@ -270,11 +276,42 @@
}
static jvmtiError GetTag(jvmtiEnv* env, jobject object, jlong* tag_ptr) {
- return ERR(NOT_IMPLEMENTED);
+ if (object == nullptr || tag_ptr == nullptr) {
+ return ERR(NULL_POINTER);
+ }
+
+ JNIEnv* jni_env = GetJniEnv(env);
+ if (jni_env == nullptr) {
+ return ERR(INTERNAL);
+ }
+
+ art::ScopedObjectAccess soa(jni_env);
+ art::ObjPtr<art::mirror::Object> obj = soa.Decode<art::mirror::Object>(object);
+ if (!gObjectTagTable.GetTag(obj.Ptr(), tag_ptr)) {
+ *tag_ptr = 0;
+ }
+
+ return ERR(NONE);
}
static jvmtiError SetTag(jvmtiEnv* env, jobject object, jlong tag) {
- return ERR(NOT_IMPLEMENTED);
+ if (object == nullptr) {
+ return ERR(NULL_POINTER);
+ }
+
+ JNIEnv* jni_env = GetJniEnv(env);
+ if (jni_env == nullptr) {
+ return ERR(INTERNAL);
+ }
+
+ art::ScopedObjectAccess soa(jni_env);
+ art::ObjPtr<art::mirror::Object> obj = soa.Decode<art::mirror::Object>(object);
+ gObjectTagTable.Remove(obj.Ptr(), /* tag* */ nullptr);
+ if (tag != 0) {
+ gObjectTagTable.Add(obj.Ptr(), tag);
+ }
+
+ return ERR(NONE);
}
static jvmtiError GetObjectsWithTags(jvmtiEnv* env,
diff --git a/runtime/openjdkjvmti/object_tagging.h b/runtime/openjdkjvmti/object_tagging.h
new file mode 100644
index 0000000..e276c52
--- /dev/null
+++ b/runtime/openjdkjvmti/object_tagging.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_OPENJDKJVMTI_OBJECT_TAGGING_H_
+#define ART_RUNTIME_OPENJDKJVMTI_OBJECT_TAGGING_H_
+
+#include "base/mutex.h"
+#include "gc/system_weak.h"
+#include "gc_root-inl.h"
+#include "mirror/object.h"
+#include "thread-inl.h"
+
+namespace openjdkjvmti {
+
+class ObjectTagTable : public art::gc::SystemWeakHolder {
+ public:
+ ObjectTagTable() : art::gc::SystemWeakHolder(art::LockLevel::kAllocTrackerLock) {
+ }
+
+ void Add(art::mirror::Object* obj, jlong tag)
+ REQUIRES_SHARED(art::Locks::mutator_lock_)
+ REQUIRES(!allow_disallow_lock_) {
+ art::Thread* self = art::Thread::Current();
+ art::MutexLock mu(self, allow_disallow_lock_);
+ Wait(self);
+
+ if (first_free_ == tagged_objects_.size()) {
+ tagged_objects_.push_back(Entry(art::GcRoot<art::mirror::Object>(obj), tag));
+ first_free_++;
+ } else {
+ DCHECK_LT(first_free_, tagged_objects_.size());
+ DCHECK(tagged_objects_[first_free_].first.IsNull());
+ tagged_objects_[first_free_] = Entry(art::GcRoot<art::mirror::Object>(obj), tag);
+ // TODO: scan for free elements.
+ first_free_ = tagged_objects_.size();
+ }
+ }
+
+ bool GetTag(art::mirror::Object* obj, jlong* result)
+ REQUIRES_SHARED(art::Locks::mutator_lock_)
+ REQUIRES(!allow_disallow_lock_) {
+ art::Thread* self = art::Thread::Current();
+ art::MutexLock mu(self, allow_disallow_lock_);
+ Wait(self);
+
+ for (const auto& pair : tagged_objects_) {
+ if (pair.first.Read(nullptr) == obj) {
+ *result = pair.second;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ bool Remove(art::mirror::Object* obj, jlong* tag)
+ REQUIRES_SHARED(art::Locks::mutator_lock_)
+ REQUIRES(!allow_disallow_lock_) {
+ art::Thread* self = art::Thread::Current();
+ art::MutexLock mu(self, allow_disallow_lock_);
+ Wait(self);
+
+ for (auto it = tagged_objects_.begin(); it != tagged_objects_.end(); ++it) {
+ if (it->first.Read(nullptr) == obj) {
+ if (tag != nullptr) {
+ *tag = it->second;
+ }
+ it->first = art::GcRoot<art::mirror::Object>(nullptr);
+
+ size_t index = it - tagged_objects_.begin();
+ if (index < first_free_) {
+ first_free_ = index;
+ }
+
+ // TODO: compaction.
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ void Sweep(art::IsMarkedVisitor* visitor)
+ REQUIRES_SHARED(art::Locks::mutator_lock_)
+ REQUIRES(!allow_disallow_lock_) {
+ art::Thread* self = art::Thread::Current();
+ art::MutexLock mu(self, allow_disallow_lock_);
+
+ for (auto it = tagged_objects_.begin(); it != tagged_objects_.end(); ++it) {
+ if (!it->first.IsNull()) {
+ art::mirror::Object* original_obj = it->first.Read();
+ art::mirror::Object* target_obj = visitor->IsMarked(original_obj);
+ if (original_obj != target_obj) {
+ it->first = art::GcRoot<art::mirror::Object>(target_obj);
+
+ if (target_obj == nullptr) {
+ HandleNullSweep(it->second);
+ }
+ }
+ } else {
+ size_t index = it - tagged_objects_.begin();
+ if (index < first_free_) {
+ first_free_ = index;
+ }
+ }
+ }
+ }
+
+ private:
+ using Entry = std::pair<art::GcRoot<art::mirror::Object>, jlong>;
+
+ void HandleNullSweep(jlong tag ATTRIBUTE_UNUSED) {
+ // TODO: Handle deallocation reporting here. We'll have to enqueue tags temporarily, as we
+ // probably shouldn't call the callbacks directly (to avoid any issues).
+ }
+
+ std::vector<Entry> tagged_objects_ GUARDED_BY(allow_disallow_lock_);
+ size_t first_free_ = 0;
+};
+
+} // namespace openjdkjvmti
+
+#endif // ART_RUNTIME_OPENJDKJVMTI_OBJECT_TAGGING_H_
diff --git a/runtime/proxy_test.cc b/runtime/proxy_test.cc
index 1119ccf..84985c2 100644
--- a/runtime/proxy_test.cc
+++ b/runtime/proxy_test.cc
@@ -180,7 +180,7 @@
ArtField* field = &static_fields->At(0);
EXPECT_STREQ("interfaces", field->GetName());
EXPECT_STREQ("[Ljava/lang/Class;", field->GetTypeDescriptor());
- EXPECT_OBJ_PTR_EQ(MakeObjPtr(interfacesFieldClass.Get()), field->GetType<true>());
+ EXPECT_OBJ_PTR_EQ(interfacesFieldClass.Get(), field->GetType<true>());
std::string temp;
EXPECT_STREQ("L$Proxy1234;", field->GetDeclaringClass()->GetDescriptor(&temp));
EXPECT_FALSE(field->IsPrimitiveType());
@@ -189,7 +189,7 @@
field = &static_fields->At(1);
EXPECT_STREQ("throws", field->GetName());
EXPECT_STREQ("[[Ljava/lang/Class;", field->GetTypeDescriptor());
- EXPECT_OBJ_PTR_EQ(MakeObjPtr(throwsFieldClass.Get()), field->GetType<true>());
+ EXPECT_OBJ_PTR_EQ(throwsFieldClass.Get(), field->GetType<true>());
EXPECT_STREQ("L$Proxy1234;", field->GetDeclaringClass()->GetDescriptor(&temp));
EXPECT_FALSE(field->IsPrimitiveType());
}
@@ -224,10 +224,10 @@
ASSERT_TRUE(static_fields1 != nullptr);
ASSERT_EQ(2u, static_fields1->size());
- EXPECT_OBJ_PTR_EQ(static_fields0->At(0).GetDeclaringClass(), MakeObjPtr(proxyClass0.Get()));
- EXPECT_OBJ_PTR_EQ(static_fields0->At(1).GetDeclaringClass(), MakeObjPtr(proxyClass0.Get()));
- EXPECT_OBJ_PTR_EQ(static_fields1->At(0).GetDeclaringClass(), MakeObjPtr(proxyClass1.Get()));
- EXPECT_OBJ_PTR_EQ(static_fields1->At(1).GetDeclaringClass(), MakeObjPtr(proxyClass1.Get()));
+ EXPECT_OBJ_PTR_EQ(static_fields0->At(0).GetDeclaringClass(), proxyClass0.Get());
+ EXPECT_OBJ_PTR_EQ(static_fields0->At(1).GetDeclaringClass(), proxyClass0.Get());
+ EXPECT_OBJ_PTR_EQ(static_fields1->At(0).GetDeclaringClass(), proxyClass1.Get());
+ EXPECT_OBJ_PTR_EQ(static_fields1->At(1).GetDeclaringClass(), proxyClass1.Get());
ASSERT_EQ(Runtime::Current()->GetClassLinker()->GetImagePointerSize(), kRuntimePointerSize);
ASSERT_FALSE(Runtime::Current()->IsActiveTransaction());
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index de003e5..d34b701 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -676,8 +676,7 @@
}
// Box if necessary and return.
- return soa.AddLocalReference<jobject>(
- BoxPrimitive(Primitive::GetType(shorty[0]), result).Ptr());
+ return soa.AddLocalReference<jobject>(BoxPrimitive(Primitive::GetType(shorty[0]), result));
}
ObjPtr<mirror::Object> BoxPrimitive(Primitive::Type src_class, const JValue& value) {
@@ -911,7 +910,7 @@
IndirectRef ref = reinterpret_cast<IndirectRef>(obj);
IndirectRefKind kind = GetIndirectRefKind(ref);
if (kind == kLocal) {
- self->GetJniEnv()->locals.Update(obj, result.Ptr());
+ self->GetJniEnv()->locals.Update(obj, result);
} else if (kind == kHandleScopeOrInvalid) {
LOG(FATAL) << "Unsupported UpdateReference for kind kHandleScopeOrInvalid";
} else if (kind == kGlobal) {
diff --git a/runtime/runtime-inl.h b/runtime/runtime-inl.h
index 2eb0bf7..8346550 100644
--- a/runtime/runtime-inl.h
+++ b/runtime/runtime-inl.h
@@ -21,11 +21,12 @@
#include "art_method.h"
#include "class_linker.h"
+#include "obj_ptr-inl.h"
#include "read_barrier-inl.h"
namespace art {
-inline bool Runtime::IsClearedJniWeakGlobal(mirror::Object* obj) {
+inline bool Runtime::IsClearedJniWeakGlobal(ObjPtr<mirror::Object> obj) {
return obj == GetClearedJniWeakGlobal();
}
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 84c6b6f..5a95f78 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -33,6 +33,7 @@
#include "instrumentation.h"
#include "jobject_comparator.h"
#include "method_reference.h"
+#include "obj_ptr.h"
#include "object_callbacks.h"
#include "offsets.h"
#include "process_state.h"
@@ -292,7 +293,7 @@
}
// Is the given object the special object used to mark a cleared JNI weak global?
- bool IsClearedJniWeakGlobal(mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_);
+ bool IsClearedJniWeakGlobal(ObjPtr<mirror::Object> obj) REQUIRES_SHARED(Locks::mutator_lock_);
// Get the special object used to mark a cleared JNI weak global.
mirror::Object* GetClearedJniWeakGlobal() REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/scoped_thread_state_change-inl.h b/runtime/scoped_thread_state_change-inl.h
index 1d9f132..ac25757 100644
--- a/runtime/scoped_thread_state_change-inl.h
+++ b/runtime/scoped_thread_state_change-inl.h
@@ -72,19 +72,13 @@
}
template<typename T>
-inline T ScopedObjectAccessAlreadyRunnable::AddLocalReference(mirror::Object* obj) const {
+inline T ScopedObjectAccessAlreadyRunnable::AddLocalReference(ObjPtr<mirror::Object> obj) const {
Locks::mutator_lock_->AssertSharedHeld(Self());
DCHECK(IsRunnable()); // Don't work with raw objects in non-runnable states.
DCHECK_NE(obj, Runtime::Current()->GetClearedJniWeakGlobal());
return obj == nullptr ? nullptr : Env()->AddLocalReference<T>(obj);
}
-template<typename T, typename MirrorType, bool kPoison>
-inline T ScopedObjectAccessAlreadyRunnable::AddLocalReference(
- ObjPtr<MirrorType, kPoison> obj) const {
- return AddLocalReference<T>(obj.Ptr());
-}
-
template<typename T, bool kPoison>
inline ObjPtr<T, kPoison> ScopedObjectAccessAlreadyRunnable::Decode(jobject obj) const {
Locks::mutator_lock_->AssertSharedHeld(Self());
diff --git a/runtime/scoped_thread_state_change.h b/runtime/scoped_thread_state_change.h
index 175bec5..04fd914 100644
--- a/runtime/scoped_thread_state_change.h
+++ b/runtime/scoped_thread_state_change.h
@@ -87,13 +87,8 @@
* This will be called on otherwise unreferenced objects. We cannot do GC allocations here, and
* it's best if we don't grab a mutex.
*/
- template<typename T, typename MirrorType, bool kPoison = kIsDebugBuild>
- T AddLocalReference(ObjPtr<MirrorType, kPoison> obj) const
- REQUIRES_SHARED(Locks::mutator_lock_);
-
- // TODO: Delete
template<typename T>
- T AddLocalReference(mirror::Object* obj) const
+ T AddLocalReference(ObjPtr<mirror::Object> obj) const
REQUIRES_SHARED(Locks::mutator_lock_);
template<typename T, bool kPoison = kIsDebugBuild>
diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h
index d75a788..6c3811b 100644
--- a/runtime/thread-inl.h
+++ b/runtime/thread-inl.h
@@ -312,6 +312,37 @@
}
}
+inline bool Thread::ModifySuspendCount(Thread* self,
+ int delta,
+ AtomicInteger* suspend_barrier,
+ bool for_debugger) {
+ if (delta > 0 && ((kUseReadBarrier && this != self) || suspend_barrier != nullptr)) {
+ // When delta > 0 (requesting a suspend), ModifySuspendCountInternal() may fail either if
+ // active_suspend_barriers is full or we are in the middle of a thread flip. Retry in a loop.
+ while (true) {
+ if (LIKELY(ModifySuspendCountInternal(self, delta, suspend_barrier, for_debugger))) {
+ return true;
+ } else {
+ // Failure means the list of active_suspend_barriers is full or we are in the middle of a
+ // thread flip, we should release the thread_suspend_count_lock_ (to avoid deadlock) and
+ // wait till the target thread has executed or Thread::PassActiveSuspendBarriers() or the
+ // flip function. Note that we could not simply wait for the thread to change to a suspended
+ // state, because it might need to run checkpoint function before the state change or
+ // resumes from the resume_cond_, which also needs thread_suspend_count_lock_.
+ //
+ // The list of active_suspend_barriers is very unlikely to be full since more than
+ // kMaxSuspendBarriers threads need to execute SuspendAllInternal() simultaneously, and
+ // target thread stays in kRunnable in the mean time.
+ Locks::thread_suspend_count_lock_->ExclusiveUnlock(self);
+ NanoSleep(100000);
+ Locks::thread_suspend_count_lock_->ExclusiveLock(self);
+ }
+ }
+ } else {
+ return ModifySuspendCountInternal(self, delta, suspend_barrier, for_debugger);
+ }
+}
+
} // namespace art
#endif // ART_RUNTIME_THREAD_INL_H_
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 80542e8..7335e40 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -991,8 +991,10 @@
LOG(FATAL) << ss.str();
}
-bool Thread::ModifySuspendCount(Thread* self, int delta, AtomicInteger* suspend_barrier,
- bool for_debugger) {
+bool Thread::ModifySuspendCountInternal(Thread* self,
+ int delta,
+ AtomicInteger* suspend_barrier,
+ bool for_debugger) {
if (kIsDebugBuild) {
DCHECK(delta == -1 || delta == +1 || delta == -tls32_.debug_suspend_count)
<< delta << " " << tls32_.debug_suspend_count << " " << this;
@@ -1007,6 +1009,12 @@
return false;
}
+ if (kUseReadBarrier && delta > 0 && this != self && tlsPtr_.flip_function != nullptr) {
+ // Force retry of a suspend request if it's in the middle of a thread flip to avoid a
+ // deadlock. b/31683379.
+ return false;
+ }
+
uint16_t flags = kSuspendRequest;
if (delta > 0 && suspend_barrier != nullptr) {
uint32_t available_barrier = kMaxSuspendBarriers;
@@ -1854,7 +1862,7 @@
}
IndirectRef ref = reinterpret_cast<IndirectRef>(obj);
IndirectRefKind kind = GetIndirectRefKind(ref);
- mirror::Object* result;
+ ObjPtr<mirror::Object> result;
bool expect_null = false;
// The "kinds" below are sorted by the frequency we expect to encounter them.
if (kind == kLocal) {
@@ -1867,7 +1875,7 @@
if (LIKELY(HandleScopeContains(obj))) {
// Read from handle scope.
result = reinterpret_cast<StackReference<mirror::Object>*>(obj)->AsMirrorPtr();
- VerifyObject(result);
+ VerifyObject(result.Ptr());
} else {
tlsPtr_.jni_env->vm->JniAbortF(nullptr, "use of invalid jobject %p", obj);
expect_null = true;
@@ -1889,7 +1897,7 @@
tlsPtr_.jni_env->vm->JniAbortF(nullptr, "use of deleted %s %p",
ToStr<IndirectRefKind>(kind).c_str(), obj);
}
- return result;
+ return result.Ptr();
}
bool Thread::IsJWeakCleared(jweak obj) const {
diff --git a/runtime/thread.h b/runtime/thread.h
index f2c22d1..97053de 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -226,7 +226,13 @@
(state_and_flags.as_struct.flags & kSuspendRequest) != 0;
}
- bool ModifySuspendCount(Thread* self, int delta, AtomicInteger* suspend_barrier, bool for_debugger)
+ // If delta > 0 and (this != self or suspend_barrier is not null), this function may temporarily
+ // release thread_suspend_count_lock_ internally.
+ ALWAYS_INLINE
+ bool ModifySuspendCount(Thread* self,
+ int delta,
+ AtomicInteger* suspend_barrier,
+ bool for_debugger)
REQUIRES(Locks::thread_suspend_count_lock_);
bool RequestCheckpoint(Closure* function)
@@ -1220,6 +1226,12 @@
is_sensitive_thread_hook_ = is_sensitive_thread_hook;
}
+ bool ModifySuspendCountInternal(Thread* self,
+ int delta,
+ AtomicInteger* suspend_barrier,
+ bool for_debugger)
+ REQUIRES(Locks::thread_suspend_count_lock_);
+
// 32 bits of atomically changed state and flags. Keeping as 32 bits allows and atomic CAS to
// change from being Suspended to Runnable without a suspend request occurring.
union PACKED(4) StateAndFlags {
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index 6f952c4..eba6666 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -590,24 +590,7 @@
continue;
}
VLOG(threads) << "requesting thread suspend: " << *thread;
- while (true) {
- if (LIKELY(thread->ModifySuspendCount(self, +1, &pending_threads, debug_suspend))) {
- break;
- } else {
- // Failure means the list of active_suspend_barriers is full, we should release the
- // thread_suspend_count_lock_ (to avoid deadlock) and wait till the target thread has
- // executed Thread::PassActiveSuspendBarriers(). Note that we could not simply wait for
- // the thread to change to a suspended state, because it might need to run checkpoint
- // function before the state change, which also needs thread_suspend_count_lock_.
-
- // This is very unlikely to happen since more than kMaxSuspendBarriers threads need to
- // execute SuspendAllInternal() simultaneously, and target thread stays in kRunnable
- // in the mean time.
- Locks::thread_suspend_count_lock_->ExclusiveUnlock(self);
- NanoSleep(100000);
- Locks::thread_suspend_count_lock_->ExclusiveLock(self);
- }
- }
+ thread->ModifySuspendCount(self, +1, &pending_threads, debug_suspend);
// Must install the pending_threads counter first, then check thread->IsSuspend() and clear
// the counter. Otherwise there's a race with Thread::TransitionFromRunnableToSuspended()
diff --git a/test/903-hello-tagging/build b/test/903-hello-tagging/build
new file mode 100755
index 0000000..898e2e5
--- /dev/null
+++ b/test/903-hello-tagging/build
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Copyright 2016 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.
+
+./default-build "$@" --experimental agents
diff --git a/test/903-hello-tagging/expected.txt b/test/903-hello-tagging/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/903-hello-tagging/expected.txt
diff --git a/test/903-hello-tagging/info.txt b/test/903-hello-tagging/info.txt
new file mode 100644
index 0000000..875a5f6
--- /dev/null
+++ b/test/903-hello-tagging/info.txt
@@ -0,0 +1 @@
+Tests basic functions in the jvmti plugin.
diff --git a/test/903-hello-tagging/run b/test/903-hello-tagging/run
new file mode 100755
index 0000000..5e3c0bd
--- /dev/null
+++ b/test/903-hello-tagging/run
@@ -0,0 +1,43 @@
+#!/bin/bash
+#
+# Copyright 2016 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.
+
+plugin=libopenjdkjvmtid.so
+agent=libtiagentd.so
+lib=tiagentd
+if [[ "$@" == *"-O"* ]]; then
+ agent=libtiagent.so
+ plugin=libopenjdkjvmti.so
+ lib=tiagent
+fi
+
+if [[ "$@" == *"--jvm"* ]]; then
+ arg="jvm"
+else
+ arg="art"
+fi
+
+if [[ "$@" != *"--debuggable"* ]]; then
+ other_args=" -Xcompiler-option --debuggable "
+else
+ other_args=""
+fi
+
+./default-run "$@" --experimental agents \
+ --experimental runtime-plugins \
+ --runtime-option -agentpath:${agent}=903-hello-tagging,${arg} \
+ --android-runtime-option -Xplugin:${plugin} \
+ ${other_args} \
+ --args ${lib}
diff --git a/test/903-hello-tagging/src/Main.java b/test/903-hello-tagging/src/Main.java
new file mode 100644
index 0000000..2856a39
--- /dev/null
+++ b/test/903-hello-tagging/src/Main.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+import java.lang.ref.WeakReference;
+
+public class Main {
+ public static void main(String[] args) {
+ System.loadLibrary(args[1]);
+ doTest();
+ }
+
+ public static void doTest() {
+ WeakReference<Object> weak = test();
+
+ Runtime.getRuntime().gc();
+ Runtime.getRuntime().gc();
+
+ if (weak.get() != null) {
+ throw new RuntimeException("WeakReference not cleared");
+ }
+ }
+
+ private static WeakReference<Object> test() {
+ Object o1 = new Object();
+ setTag(o1, 1);
+
+ Object o2 = new Object();
+ setTag(o2, 2);
+
+ checkTag(o1, 1);
+ checkTag(o2, 2);
+
+ Runtime.getRuntime().gc();
+ Runtime.getRuntime().gc();
+
+ checkTag(o1, 1);
+ checkTag(o2, 2);
+
+ Runtime.getRuntime().gc();
+ Runtime.getRuntime().gc();
+
+ setTag(o1, 10);
+ setTag(o2, 20);
+
+ checkTag(o1, 10);
+ checkTag(o2, 20);
+
+ return new WeakReference<Object>(o1);
+ }
+
+ private static void checkTag(Object o, long expectedTag) {
+ long tag = getTag(o);
+ if (expectedTag != tag) {
+ throw new RuntimeException("Unexpected tag " + tag + ", expected " + expectedTag);
+ }
+ }
+
+ private static native void setTag(Object o, long tag);
+ private static native long getTag(Object o);
+}
diff --git a/test/903-hello-tagging/tagging.cc b/test/903-hello-tagging/tagging.cc
new file mode 100644
index 0000000..8ccdf49
--- /dev/null
+++ b/test/903-hello-tagging/tagging.cc
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "tagging.h"
+
+#include <iostream>
+#include <pthread.h>
+#include <stdio.h>
+#include <vector>
+
+#include "art_method-inl.h"
+#include "base/logging.h"
+#include "jni.h"
+#include "openjdkjvmti/jvmti.h"
+#include "utils.h"
+
+namespace art {
+namespace Test903HelloTagging {
+
+static jvmtiEnv* jvmti_env;
+
+extern "C" JNIEXPORT void JNICALL Java_Main_setTag(JNIEnv* env ATTRIBUTE_UNUSED,
+ jclass,
+ jobject obj,
+ jlong tag) {
+ jvmtiError ret = jvmti_env->SetTag(obj, tag);
+ if (ret != JVMTI_ERROR_NONE) {
+ char* err;
+ jvmti_env->GetErrorName(ret, &err);
+ printf("Error setting tag: %s\n", err);
+ }
+}
+
+extern "C" JNIEXPORT jlong JNICALL Java_Main_getTag(JNIEnv* env ATTRIBUTE_UNUSED,
+ jclass,
+ jobject obj) {
+ jlong tag = 0;
+ jvmtiError ret = jvmti_env->GetTag(obj, &tag);
+ if (ret != JVMTI_ERROR_NONE) {
+ char* err;
+ jvmti_env->GetErrorName(ret, &err);
+ printf("Error getting tag: %s\n", err);
+ }
+ return tag;
+}
+
+// Don't do anything
+jint OnLoad(JavaVM* vm,
+ char* options ATTRIBUTE_UNUSED,
+ void* reserved ATTRIBUTE_UNUSED) {
+ if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
+ printf("Unable to get jvmti env!\n");
+ return 1;
+ }
+ return 0;
+}
+
+} // namespace Test903HelloTagging
+} // namespace art
+
diff --git a/test/903-hello-tagging/tagging.h b/test/903-hello-tagging/tagging.h
new file mode 100644
index 0000000..f062d44
--- /dev/null
+++ b/test/903-hello-tagging/tagging.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 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_TEST_903_HELLO_TAGGING_TAGGING_H_
+#define ART_TEST_903_HELLO_TAGGING_TAGGING_H_
+
+#include <jni.h>
+
+namespace art {
+namespace Test903HelloTagging {
+
+jint OnLoad(JavaVM* vm, char* options, void* reserved);
+
+} // namespace Test903HelloTagging
+} // namespace art
+
+#endif // ART_TEST_903_HELLO_TAGGING_TAGGING_H_
diff --git a/test/Android.bp b/test/Android.bp
index 628f377..d17261c 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -245,6 +245,7 @@
"ti-agent/common_load.cc",
"901-hello-ti-agent/basics.cc",
"902-hello-transformation/transform.cc",
+ "903-hello-tagging/tagging.cc",
],
shared_libs: [
"libart",
@@ -263,9 +264,11 @@
"ti-agent/common_load.cc",
"901-hello-ti-agent/basics.cc",
"902-hello-transformation/transform.cc",
+ "903-hello-tagging/tagging.cc",
],
shared_libs: [
"libartd",
+ "libbase",
"libopenjdkjvmtid",
],
}
diff --git a/test/ti-agent/common_load.cc b/test/ti-agent/common_load.cc
index 53bb153..4c7df97 100644
--- a/test/ti-agent/common_load.cc
+++ b/test/ti-agent/common_load.cc
@@ -25,6 +25,7 @@
#include "901-hello-ti-agent/basics.h"
#include "902-hello-transformation/transform.h"
+#include "903-hello-tagging/tagging.h"
namespace art {
@@ -41,6 +42,7 @@
AgentLib agents[] = {
{ "901-hello-ti-agent", Test901HelloTi::OnLoad, nullptr },
{ "902-hello-transformation", Test902HelloTransformation::OnLoad, nullptr },
+ { "903-hello-tagging", Test903HelloTagging::OnLoad, nullptr },
};
static AgentLib* FindAgent(char* name) {
diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt
index 7b5e9ed..53fe8fe 100644
--- a/tools/libcore_failures.txt
+++ b/tools/libcore_failures.txt
@@ -233,11 +233,5 @@
modes: [device],
names: ["libcore.java.lang.ProcessBuilderTest#testRedirectInherit",
"libcore.java.lang.ProcessBuilderTest#testRedirect_nullStreams"]
-},
-{
- description: "Sometimes timeouts",
- result: EXEC_FAILED,
- bug: 31258002,
- names: ["libcore.net.NetworkSecurityPolicyTest#testCleartextTrafficPolicyWithJarHttpURLConnection"]
}
]