Merge "Implement Method.Bytecodes." into dalvik-dev
diff --git a/src/debugger.cc b/src/debugger.cc
index 1df7fe9..5db7bf5 100644
--- a/src/debugger.cc
+++ b/src/debugger.cc
@@ -1359,6 +1359,24 @@
   JDWP::Set4BE(expandBufGetBuffer(pReply) + variable_count_offset, context.variable_count);
 }
 
+JDWP::JdwpError Dbg::GetBytecodes(JDWP::RefTypeId, JDWP::MethodId method_id,
+                                  std::vector<uint8_t>& bytecodes)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  AbstractMethod* m = FromMethodId(method_id);
+  if (m == NULL) {
+    return JDWP::ERR_INVALID_METHODID;
+  }
+  MethodHelper mh(m);
+  const DexFile::CodeItem* code_item = mh.GetCodeItem();
+  size_t byte_count = code_item->insns_size_in_code_units_ * 2;
+  const uint8_t* begin = reinterpret_cast<const uint8_t*>(code_item->insns_);
+  const uint8_t* end = begin + byte_count;
+  for (const uint8_t* p = begin; p != end; ++p) {
+    bytecodes.push_back(*p);
+  }
+  return JDWP::ERR_NONE;
+}
+
 JDWP::JdwpTag Dbg::GetFieldBasicTag(JDWP::FieldId field_id) {
   return BasicTagFromDescriptor(FieldHelper(FromFieldId(field_id)).GetTypeDescriptor());
 }
diff --git a/src/debugger.h b/src/debugger.h
index c03adea..b33216b 100644
--- a/src/debugger.h
+++ b/src/debugger.h
@@ -196,9 +196,9 @@
                                              std::vector<JDWP::ObjectId>& referring_objects)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  /*
-   * Method and Field
-   */
+  //
+  // Methods and fields.
+  //
   static std::string GetMethodName(JDWP::RefTypeId ref_type_id, JDWP::MethodId id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static JDWP::JdwpError OutputDeclaredFields(JDWP::RefTypeId ref_type_id, bool with_generic,
@@ -216,6 +216,9 @@
   static void OutputVariableTable(JDWP::RefTypeId ref_type_id, JDWP::MethodId id, bool with_generic,
                                   JDWP::ExpandBuf* pReply)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  static JDWP::JdwpError GetBytecodes(JDWP::RefTypeId class_id, JDWP::MethodId method_id,
+                                      std::vector<uint8_t>& bytecodes)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   static JDWP::JdwpTag GetFieldBasicTag(JDWP::FieldId field_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/src/jdwp/jdwp_handler.cc b/src/jdwp/jdwp_handler.cc
index 23a3130..14dd2a5 100644
--- a/src/jdwp/jdwp_handler.cc
+++ b/src/jdwp/jdwp_handler.cc
@@ -383,7 +383,7 @@
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   expandBufAdd1(reply, false);   // canWatchFieldModification
   expandBufAdd1(reply, false);   // canWatchFieldAccess
-  expandBufAdd1(reply, false);   // canGetBytecodes
+  expandBufAdd1(reply, true);    // canGetBytecodes
   expandBufAdd1(reply, true);    // canGetSyntheticAttribute
   expandBufAdd1(reply, true);    // canGetOwnedMonitorInfo
   expandBufAdd1(reply, true);    // canGetCurrentContendedMonitor
@@ -828,6 +828,25 @@
   return M_VariableTable(state, buf, dataLen, pReply, true);
 }
 
+static JdwpError M_Bytecodes(JdwpState*, const uint8_t* buf, int, ExpandBuf* reply)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  RefTypeId class_id = ReadRefTypeId(&buf);
+  MethodId method_id = ReadMethodId(&buf);
+
+  std::vector<uint8_t> bytecodes;
+  JdwpError rc = Dbg::GetBytecodes(class_id, method_id, bytecodes);
+  if (rc != ERR_NONE) {
+    return rc;
+  }
+
+  expandBufAdd4BE(reply, bytecodes.size());
+  for (size_t i = 0; i < bytecodes.size(); ++i) {
+    expandBufAdd1(reply, bytecodes[i]);
+  }
+
+  return ERR_NONE;
+}
+
 /*
  * Given an object reference, return the runtime type of the object
  * (class or array).
@@ -1680,7 +1699,7 @@
   /* Method command set (6) */
   { 6,    1,  M_LineTable,                "Method.LineTable" },
   { 6,    2,  M_VariableTable,            "Method.VariableTable" },
-  { 6,    3,  NULL,                       "Method.Bytecodes" },
+  { 6,    3,  M_Bytecodes,                "Method.Bytecodes" },
   { 6,    4,  NULL,                       "Method.IsObsolete" },
   { 6,    5,  M_VariableTableWithGeneric, "Method.VariableTableWithGeneric" },