Add MethodHandle and CallSite to dexlayout
Test: test/testrunner/run_build_test_target.py -j80 art-test
Change-Id: I5fb7190bb0a1c7d1e53be6380fa8535a1dbfe4d2
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index d2d31ac..9152c18 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -25,16 +25,17 @@
#include <inttypes.h>
#include <stdio.h>
+#include <cstdint>
#include <iostream>
+#include <iterator>
#include <memory>
#include <sstream>
#include <unordered_set>
#include <vector>
#include "android-base/stringprintf.h"
-
-#include "base/logging.h" // For VLOG_IS_ON.
#include "base/hiddenapi_flags.h"
+#include "base/logging.h" // For VLOG_IS_ON.
#include "base/mem_map.h"
#include "base/mman.h" // For the PROT_* and MAP_* constants.
#include "base/os.h"
@@ -47,6 +48,7 @@
#include "dex/dex_file_types.h"
#include "dex/dex_file_verifier.h"
#include "dex/dex_instruction-inl.h"
+#include "dex_ir.h"
#include "dex_ir_builder.h"
#include "dex_verify.h"
#include "dex_visualize.h"
@@ -533,6 +535,9 @@
method.c_str(), proto.c_str(), width, index, width, secondary_index);
}
break;
+ case Instruction::kIndexCallSiteRef:
+ outSize = snprintf(buf.get(), buf_size, "call_site@%0*x", width, index);
+ break;
// SOME NOT SUPPORTED:
// case Instruction::kIndexVaries:
// case Instruction::kIndexInlineMethod:
@@ -1607,6 +1612,226 @@
free(access_str);
}
+void DexLayout::DumpMethodHandle(int idx) {
+ const dex_ir::MethodHandleItem* mh = header_->MethodHandleItems()[idx];
+ const char* type = nullptr;
+ bool is_instance = false;
+ bool is_invoke = false;
+
+ switch (mh->GetMethodHandleType()) {
+ case DexFile::MethodHandleType::kStaticPut:
+ type = "put-static";
+ is_instance = false;
+ is_invoke = false;
+ break;
+ case DexFile::MethodHandleType::kStaticGet:
+ type = "get-static";
+ is_instance = false;
+ is_invoke = false;
+ break;
+ case DexFile::MethodHandleType::kInstancePut:
+ type = "put-instance";
+ is_instance = true;
+ is_invoke = false;
+ break;
+ case DexFile::MethodHandleType::kInstanceGet:
+ type = "get-instance";
+ is_instance = true;
+ is_invoke = false;
+ break;
+ case DexFile::MethodHandleType::kInvokeStatic:
+ type = "invoke-static";
+ is_instance = false;
+ is_invoke = true;
+ break;
+ case DexFile::MethodHandleType::kInvokeInstance:
+ type = "invoke-instance";
+ is_instance = true;
+ is_invoke = true;
+ break;
+ case DexFile::MethodHandleType::kInvokeConstructor:
+ type = "invoke-constructor";
+ is_instance = true;
+ is_invoke = true;
+ break;
+ case DexFile::MethodHandleType::kInvokeDirect:
+ type = "invoke-direct";
+ is_instance = true;
+ is_invoke = true;
+ break;
+ case DexFile::MethodHandleType::kInvokeInterface:
+ type = "invoke-interface";
+ is_instance = true;
+ is_invoke = true;
+ break;
+ default:
+ type = "????";
+ break;
+ } // switch
+
+ const char* declaring_class;
+ const char* member;
+ std::string member_type;
+ if (type != nullptr) {
+ if (is_invoke) {
+ auto method_id = static_cast<dex_ir::MethodId*>(mh->GetFieldOrMethodId());
+ declaring_class = method_id->Class()->GetStringId()->Data();
+ member = method_id->Name()->Data();
+ auto proto_id = method_id->Proto();
+ member_type = GetSignatureForProtoId(proto_id);
+ } else {
+ auto field_id = static_cast<dex_ir::FieldId*>(mh->GetFieldOrMethodId());
+ declaring_class = field_id->Class()->GetStringId()->Data();
+ member = field_id->Name()->Data();
+ member_type = field_id->Type()->GetStringId()->Data();
+ }
+ if (is_instance) {
+ member_type = android::base::StringPrintf("(%s%s", declaring_class, member_type.c_str() + 1);
+ }
+ } else {
+ type = "?";
+ declaring_class = "?";
+ member = "?";
+ member_type = "?";
+ }
+
+ if (options_.output_format_ == kOutputPlain) {
+ fprintf(out_file_, "Method handle #%u:\n", idx);
+ fprintf(out_file_, " type : %s\n", type);
+ fprintf(out_file_, " target : %s %s\n", declaring_class, member);
+ fprintf(out_file_, " target_type : %s\n", member_type.c_str());
+ }
+}
+
+void DexLayout::DumpCallSite(int idx) {
+ const dex_ir::CallSiteId* call_site_id = header_->CallSiteIds()[idx];
+ auto call_site_items = call_site_id->CallSiteItem()->GetEncodedValues();
+ if (call_site_items->size() < 3) {
+ LOG(ERROR) << "ERROR: Call site " << idx << " has too few values.";
+ return;
+ }
+ uint32_t offset = call_site_id->CallSiteItem()->GetOffset();
+
+ auto it = call_site_items->begin();
+ if ((*it)->Type() != EncodedArrayValueIterator::ValueType::kMethodHandle) {
+ LOG(ERROR) << "ERROR: Call site " << idx << " needs to have a MethodHandle as its first item."
+ << " Found " << (*it)->Type();
+ return;
+ }
+ auto method_handle = (*it)->GetMethodHandle();
+ uint32_t method_handle_idx = method_handle->GetIndex();
+
+ it++;
+ if ((*it)->Type() != EncodedArrayValueIterator::ValueType::kString) {
+ LOG(ERROR) << "ERROR: Call site " << idx << " needs to have a String for method name "
+ << "as its second item."
+ << " Found " << (*it)->Type();
+ return;
+ }
+ const char* method_name = (*it)->GetStringId()->Data();
+
+ it++;
+ if ((*it)->Type() != EncodedArrayValueIterator::ValueType::kMethodType) {
+ LOG(ERROR) << "ERROR: Call site " << idx << " needs to have a Prototype as its third item."
+ << " Found " << (*it)->Type();
+ return;
+ }
+ auto proto_id = (*it)->GetProtoId();
+ std::string method_type = GetSignatureForProtoId(proto_id);
+
+ it++;
+ if (options_.output_format_ == kOutputPlain) {
+ fprintf(out_file_, "Call site #%u: // offset %u\n", idx, offset);
+ fprintf(out_file_, " link_argument[0] : %u (MethodHandle)\n", method_handle_idx);
+ fprintf(out_file_, " link_argument[1] : %s (String)\n", method_name);
+ fprintf(out_file_, " link_argument[2] : %s (MethodType)\n", method_type.c_str());
+ }
+
+ size_t argument = 3;
+
+ while (it != call_site_items->end()) {
+ const char* type;
+ std::string value;
+ switch ((*it)->Type()) {
+ case EncodedArrayValueIterator::ValueType::kByte:
+ type = "byte";
+ value = android::base::StringPrintf("%u", (*it)->GetByte());
+ break;
+ case EncodedArrayValueIterator::ValueType::kShort:
+ type = "short";
+ value = android::base::StringPrintf("%d", (*it)->GetShort());
+ break;
+ case EncodedArrayValueIterator::ValueType::kChar:
+ type = "char";
+ value = android::base::StringPrintf("%u", (*it)->GetChar());
+ break;
+ case EncodedArrayValueIterator::ValueType::kInt:
+ type = "int";
+ value = android::base::StringPrintf("%d", (*it)->GetInt());
+ break;
+ case EncodedArrayValueIterator::ValueType::kLong:
+ type = "long";
+ value = android::base::StringPrintf("%" PRId64, (*it)->GetLong());
+ break;
+ case EncodedArrayValueIterator::ValueType::kFloat:
+ type = "float";
+ value = android::base::StringPrintf("%g", (*it)->GetFloat());
+ break;
+ case EncodedArrayValueIterator::ValueType::kDouble:
+ type = "double";
+ value = android::base::StringPrintf("%g", (*it)->GetDouble());
+ break;
+ case EncodedArrayValueIterator::ValueType::kMethodType: {
+ type = "MethodType";
+ auto proto_id_item = (*it)->GetProtoId();
+ value = GetSignatureForProtoId(proto_id_item);
+ break;
+ }
+ case EncodedArrayValueIterator::ValueType::kMethodHandle: {
+ type = "MethodHandle";
+ auto method_handle_item = (*it)->GetMethodHandle();
+ value = android::base::StringPrintf("%d", method_handle_item->GetIndex());
+ break;
+ }
+ case EncodedArrayValueIterator::ValueType::kString: {
+ type = "String";
+ auto string_id = (*it)->GetStringId();
+ value = string_id->Data();
+ break;
+ }
+ case EncodedArrayValueIterator::ValueType::kType: {
+ type = "Class";
+ auto type_id = (*it)->GetTypeId();
+ value = type_id->GetStringId()->Data();
+ break;
+ }
+ case EncodedArrayValueIterator::ValueType::kField:
+ case EncodedArrayValueIterator::ValueType::kMethod:
+ case EncodedArrayValueIterator::ValueType::kEnum:
+ case EncodedArrayValueIterator::ValueType::kArray:
+ case EncodedArrayValueIterator::ValueType::kAnnotation:
+ // Unreachable based on current EncodedArrayValueIterator::Next().
+ UNIMPLEMENTED(FATAL) << " type " << (*it)->Type();
+ UNREACHABLE();
+ case EncodedArrayValueIterator::ValueType::kNull:
+ type = "Null";
+ value = "null";
+ break;
+ case EncodedArrayValueIterator::ValueType::kBoolean:
+ type = "boolean";
+ value = (*it)->GetBoolean() ? "true" : "false";
+ break;
+ }
+
+ if (options_.output_format_ == kOutputPlain) {
+ fprintf(out_file_, " link_argument[%zu] : %s (%s)\n", argument, value.c_str(), type);
+ }
+
+ it++;
+ argument++;
+ }
+}
+
void DexLayout::DumpDexFile() {
// Headers.
if (options_.show_file_headers_) {
@@ -1625,6 +1850,16 @@
DumpClass(i, &package);
} // for
+ const uint32_t mh_items_size = header_->MethodHandleItems().Size();
+ for (uint32_t i = 0; i < mh_items_size; i++) {
+ DumpMethodHandle(i);
+ }
+
+ const uint32_t call_sites_size = header_->CallSiteIds().Size();
+ for (uint32_t i = 0; i < call_sites_size; i++) {
+ DumpCallSite(i);
+ }
+
// Free the last package allocated.
if (package != nullptr) {
fprintf(out_file_, "</package>\n");
diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h
index d8896b3..c6f76e5 100644
--- a/dexlayout/dexlayout.h
+++ b/dexlayout/dexlayout.h
@@ -140,6 +140,8 @@
void DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset);
void DumpCatches(const dex_ir::CodeItem* code);
void DumpClass(int idx, char** last_package);
+ void DumpMethodHandle(int idx);
+ void DumpCallSite(int idx);
void DumpClassAnnotations(int idx);
void DumpClassDef(int idx);
void DumpCode(uint32_t idx,