Add jvmti GetBytecodes function.

Enables the can_get_bytecodes capability.

Test: ./test.py --host -j40
Bug: 34414073
Change-Id: If74cfcb9ecab1b4e53fa0708cf09285b9f64b5be
diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
index e3768b3..df870bf 100644
--- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
@@ -922,12 +922,12 @@
   }
 
   static jvmtiError GetBytecodes(jvmtiEnv* env,
-                                 jmethodID method ATTRIBUTE_UNUSED,
-                                 jint* bytecode_count_ptr ATTRIBUTE_UNUSED,
-                                 unsigned char** bytecodes_ptr ATTRIBUTE_UNUSED) {
+                                 jmethodID method,
+                                 jint* bytecode_count_ptr,
+                                 unsigned char** bytecodes_ptr) {
     ENSURE_VALID_ENV(env);
     ENSURE_HAS_CAP(env, can_get_bytecodes);
-    return ERR(NOT_IMPLEMENTED);
+    return MethodUtil::GetBytecodes(env, method, bytecode_count_ptr, bytecodes_ptr);
   }
 
   static jvmtiError IsMethodNative(jvmtiEnv* env, jmethodID method, jboolean* is_native_ptr) {
diff --git a/runtime/openjdkjvmti/art_jvmti.h b/runtime/openjdkjvmti/art_jvmti.h
index 2d5d527..c63e502 100644
--- a/runtime/openjdkjvmti/art_jvmti.h
+++ b/runtime/openjdkjvmti/art_jvmti.h
@@ -216,7 +216,7 @@
     .can_tag_objects                                 = 1,
     .can_generate_field_modification_events          = 1,
     .can_generate_field_access_events                = 1,
-    .can_get_bytecodes                               = 0,
+    .can_get_bytecodes                               = 1,
     .can_get_synthetic_attribute                     = 1,
     .can_get_owned_monitor_info                      = 0,
     .can_get_current_contended_monitor               = 0,
diff --git a/runtime/openjdkjvmti/ti_method.cc b/runtime/openjdkjvmti/ti_method.cc
index beb639e..9b5b964 100644
--- a/runtime/openjdkjvmti/ti_method.cc
+++ b/runtime/openjdkjvmti/ti_method.cc
@@ -91,6 +91,40 @@
   runtime->GetRuntimeCallbacks()->RemoveMethodCallback(&gMethodCallback);
 }
 
+jvmtiError MethodUtil::GetBytecodes(jvmtiEnv* env,
+                                    jmethodID method,
+                                    jint* size_ptr,
+                                    unsigned char** bytecode_ptr) {
+  if (method == nullptr) {
+    return ERR(INVALID_METHODID);
+  }
+  art::ArtMethod* art_method = art::jni::DecodeArtMethod(method);
+
+  if (art_method->IsNative()) {
+    return ERR(NATIVE_METHOD);
+  }
+
+  if (size_ptr == nullptr || bytecode_ptr == nullptr) {
+    return ERR(NULL_POINTER);
+  }
+
+  art::ScopedObjectAccess soa(art::Thread::Current());
+  const art::DexFile::CodeItem* code_item = art_method->GetCodeItem();
+  if (code_item == nullptr) {
+    *size_ptr = 0;
+    *bytecode_ptr = nullptr;
+    return OK;
+  }
+  // 2 bytes per instruction for dex code.
+  *size_ptr = code_item->insns_size_in_code_units_ * 2;
+  jvmtiError err = env->Allocate(*size_ptr, bytecode_ptr);
+  if (err != OK) {
+    return err;
+  }
+  memcpy(*bytecode_ptr, code_item->insns_, *size_ptr);
+  return OK;
+}
+
 jvmtiError MethodUtil::GetArgumentsSize(jvmtiEnv* env ATTRIBUTE_UNUSED,
                                         jmethodID method,
                                         jint* size_ptr) {
diff --git a/runtime/openjdkjvmti/ti_method.h b/runtime/openjdkjvmti/ti_method.h
index cc161c8..d95a81b 100644
--- a/runtime/openjdkjvmti/ti_method.h
+++ b/runtime/openjdkjvmti/ti_method.h
@@ -44,6 +44,11 @@
   static void Register(EventHandler* event_handler);
   static void Unregister();
 
+  static jvmtiError GetBytecodes(jvmtiEnv* env,
+                                 jmethodID method,
+                                 jint* count_ptr,
+                                 unsigned char** bytecodes);
+
   static jvmtiError GetArgumentsSize(jvmtiEnv* env, jmethodID method, jint* size_ptr);
 
   static jvmtiError GetMaxLocals(jvmtiEnv* env, jmethodID method, jint* max_ptr);