diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ArrayTypeImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ArrayTypeImpl.java
index 246733c3e03..e544c81ae3e 100644
--- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ArrayTypeImpl.java
+++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ArrayTypeImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -59,7 +59,8 @@ public class ArrayTypeImpl extends ReferenceTypeImpl
     }
 
     public String componentSignature() {
-        return signature().substring(1); // Just skip the leading '['
+        JNITypeParser sig = new JNITypeParser(signature());
+        return sig.componentSignature();
     }
 
     public String componentTypeName() {
@@ -90,8 +91,9 @@ public class ArrayTypeImpl extends ReferenceTypeImpl
      * this method is sometimes needed for proper type checking.
      */
     Type findComponentType(String signature) throws ClassNotLoadedException {
-        byte tag = (byte)signature.charAt(0);
-        if (PacketStream.isObjectTag(tag)) {
+
+        JNITypeParser sig = new JNITypeParser(signature);
+        if (sig.isReference()) {
             // It's a reference type
             JNITypeParser parser = new JNITypeParser(componentSignature());
             List<ReferenceType> list = vm.classesByName(parser.typeName());
@@ -109,7 +111,7 @@ public class ArrayTypeImpl extends ReferenceTypeImpl
             throw new ClassNotLoadedException(componentTypeName());
         } else {
             // It's a primitive type
-            return vm.primitiveTypeMirror(tag);
+            return vm.primitiveTypeMirror(sig.jdwpTag());
         }
     }
 
diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/EventSetImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/EventSetImpl.java
index 8c562a7c739..846d7343823 100644
--- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/EventSetImpl.java
+++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/EventSetImpl.java
@@ -425,19 +425,7 @@ public class EventSetImpl extends ArrayList<Event> implements EventSet {
         }
 
         public String className() {
-            assert classSignature.startsWith("L") && classSignature.endsWith(";");
-
-            // trim leading "L" and trailing ";"
-            String name = classSignature.substring(1, classSignature.length() - 1);
-            int index = name.indexOf(".");  // check if it is a hidden class
-            if (index < 0) {
-                return name.replace('/', '.');
-            }  else {
-                // map the type descriptor from: "L" + N + "." + <suffix> + ";"
-                // to class name: N.replace('/', '.') + "/" + <suffix>
-                return name.substring(0, index).replace('/', '.')
-                        + "/" + name.substring(index + 1);
-            }
+            return JNITypeParser.convertSignatureToClassname(classSignature);
         }
 
         public String classSignature() {
diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/JNITypeParser.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/JNITypeParser.java
index 197c2d291d4..a31656d0755 100644
--- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/JNITypeParser.java
+++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/JNITypeParser.java
@@ -113,10 +113,69 @@ public class JNITypeParser {
         return count;
     }
 
+    byte jdwpTag() {
+        return (byte) signature().charAt(0);
+    }
+
     String componentSignature(int level) {
+        assert level <= dimensionCount();
         return signature().substring(level);
     }
 
+    String componentSignature() {
+        assert isArray();
+        return componentSignature(1);
+    }
+
+    boolean isArray() {
+        return jdwpTag() == JDWP.Tag.ARRAY;
+    }
+
+    boolean isVoid() {
+        return jdwpTag() == JDWP.Tag.VOID;
+    }
+
+    boolean isBoolean() {
+        return jdwpTag() == JDWP.Tag.BOOLEAN;
+    }
+
+    boolean isReference() {
+        byte tag = jdwpTag();
+        return tag == JDWP.Tag.ARRAY ||
+                tag == JDWP.Tag.OBJECT;
+    }
+
+    boolean isPrimitive() {
+        switch (jdwpTag()) {
+            case (JDWP.Tag.BOOLEAN):
+            case (JDWP.Tag.BYTE):
+            case (JDWP.Tag.CHAR):
+            case (JDWP.Tag.SHORT):
+            case (JDWP.Tag.INT):
+            case (JDWP.Tag.LONG):
+            case (JDWP.Tag.FLOAT):
+            case (JDWP.Tag.DOUBLE):
+                return true;
+        }
+        return false;
+    }
+
+    static String convertSignatureToClassname(String classSignature) {
+        assert classSignature.startsWith("L") && classSignature.endsWith(";");
+
+        // trim leading "L" and trailing ";"
+        String name = classSignature.substring(1, classSignature.length() - 1);
+        int index = name.indexOf(".");  // check if it is a hidden class
+        if (index < 0) {
+            return name.replace('/', '.');
+        } else {
+            // map the type descriptor from: "L" + N + "." + <suffix> + ";"
+            // to class name: N.replace('/', '.') + "/" + <suffix>
+            return name.substring(0, index).replace('/', '.')
+                    + "/" + name.substring(index + 1);
+        }
+    }
+
     private synchronized List<String> signatureList() {
         if (signatureList == null) {
             signatureList = new ArrayList<>(10);
diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ObjectReferenceImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ObjectReferenceImpl.java
index 67807e935a4..f714e22a529 100644
--- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ObjectReferenceImpl.java
+++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ObjectReferenceImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -584,17 +584,16 @@ public class ObjectReferenceImpl extends ValueImpl
          * type which might cause a confusing ClassNotLoadedException if
          * the destination is primitive or an array.
          */
-        /*
-         * TO DO: Centralize JNI signature knowledge
-         */
-        if (destination.signature().length() == 1) {
+
+        JNITypeParser destSig = new JNITypeParser(destination.signature());
+        JNITypeParser sourceSig = new JNITypeParser(type().signature());
+        if (destSig.isPrimitive()) {
             throw new InvalidTypeException("Can't assign object value to primitive");
         }
-        if ((destination.signature().charAt(0) == '[') &&
-            (type().signature().charAt(0) != '[')) {
+        if (destSig.isArray() && !sourceSig.isArray()) {
             throw new InvalidTypeException("Can't assign non-array value to an array");
         }
-        if ("void".equals(destination.typeName())) {
+        if (destSig.isVoid()) {
             throw new InvalidTypeException("Can't assign object value to a void");
         }
 
diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/PrimitiveValueImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/PrimitiveValueImpl.java
index 1c15160b4b9..72a3295019e 100644
--- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/PrimitiveValueImpl.java
+++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/PrimitiveValueImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -105,24 +105,22 @@ public abstract class PrimitiveValueImpl extends ValueImpl
     ValueImpl convertForAssignmentTo(ValueContainer destination)
         throws InvalidTypeException
     {
-        /*
-         * TO DO: Centralize JNI signature knowledge
-         */
-        if (destination.signature().length() > 1) {
+        JNITypeParser destSig = new JNITypeParser(destination.signature());
+        JNITypeParser sourceSig = new JNITypeParser(type().signature());
+
+        if (destSig.isReference()) {
             throw new InvalidTypeException("Can't assign primitive value to object");
         }
 
-        if ((destination.signature().charAt(0) == 'Z') &&
-            (type().signature().charAt(0) != 'Z')) {
+        if (destSig.isBoolean() && !sourceSig.isBoolean()) {
             throw new InvalidTypeException("Can't assign non-boolean value to a boolean");
         }
 
-        if ((destination.signature().charAt(0) != 'Z') &&
-            (type().signature().charAt(0) == 'Z')) {
+        if (!destSig.isBoolean() && sourceSig.isBoolean()) {
             throw new InvalidTypeException("Can't assign boolean value to an non-boolean");
         }
 
-        if ("void".equals(destination.typeName())) {
+        if (destSig.isVoid()) {
             throw new InvalidTypeException("Can't assign primitive value to a void");
         }
 
diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java
index ff443ae14c0..3c3be9adbe6 100644
--- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java
+++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ReferenceTypeImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -1151,40 +1151,28 @@ public abstract class ReferenceTypeImpl extends TypeImpl implements ReferenceTyp
     }
 
     private static boolean isOneDimensionalPrimitiveArray(String signature) {
-        int i = signature.lastIndexOf('[');
-        /*
-         * TO DO: Centralize JNI signature knowledge.
-         *
-         * Ref:
-         *  jdk1.4/doc/guide/jpda/jdi/com/sun/jdi/doc-files/signature.html
-         */
-        boolean isPA;
-        if (i < 0 || signature.startsWith("[[")) {
-            isPA = false;
-        } else {
-            char c = signature.charAt(i + 1);
-            isPA = (c != 'L');
+        JNITypeParser sig = new JNITypeParser(signature);
+        if (sig.isArray()) {
+            JNITypeParser componentSig = new JNITypeParser(sig.componentSignature());
+            return componentSig.isPrimitive();
         }
-        return isPA;
+        return false;
     }
 
     Type findType(String signature) throws ClassNotLoadedException {
         Type type;
-        if (signature.length() == 1) {
-            /* OTI FIX: Must be a primitive type or the void type */
-            char sig = signature.charAt(0);
-            if (sig == 'V') {
-                type = vm.theVoidType();
-            } else {
-                type = vm.primitiveTypeMirror((byte)sig);
-            }
+        JNITypeParser sig = new JNITypeParser(signature);
+        if (sig.isVoid()) {
+            type = vm.theVoidType();
+        } else if (sig.isPrimitive()) {
+            type = vm.primitiveTypeMirror(sig.jdwpTag());
         } else {
             // Must be a reference type.
             ClassLoaderReferenceImpl loader =
-                       (ClassLoaderReferenceImpl)classLoader();
+                    (ClassLoaderReferenceImpl) classLoader();
             if ((loader == null) ||
-                (isOneDimensionalPrimitiveArray(signature)) //Work around 4450091
-                ) {
+                    (isOneDimensionalPrimitiveArray(signature)) //Work around 4450091
+            ) {
                 // Caller wants type of boot class field
                 type = vm.findBootType(signature);
             } else {
diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ValueImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ValueImpl.java
index 79444fffb1a..1f9e91e070b 100644
--- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/ValueImpl.java
+++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/ValueImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -40,10 +40,8 @@ abstract class ValueImpl extends MirrorImpl implements Value {
                                           ValueContainer destination)
                   throws InvalidTypeException, ClassNotLoadedException {
         if (value == null) {
-            /*
-             * TO DO: Centralize JNI signature knowledge
-             */
-            if (destination.signature().length() == 1) {
+            JNITypeParser sig = new JNITypeParser(destination.signature());
+            if (sig.isPrimitive()) {
                 throw new InvalidTypeException("Can't set a primitive type to null");
             }
             return null;    // no further checking or conversion necessary
diff --git a/src/jdk.jdi/share/classes/com/sun/tools/jdi/VoidValueImpl.java b/src/jdk.jdi/share/classes/com/sun/tools/jdi/VoidValueImpl.java
index e6c24982684..2d9ebf47dae 100644
--- a/src/jdk.jdi/share/classes/com/sun/tools/jdi/VoidValueImpl.java
+++ b/src/jdk.jdi/share/classes/com/sun/tools/jdi/VoidValueImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -54,7 +54,8 @@ public class VoidValueImpl extends ValueImpl implements VoidValue {
     ValueImpl prepareForAssignmentTo(ValueContainer destination)
         throws InvalidTypeException
     {
-        if ("void".equals(destination.typeName())) {
+        JNITypeParser sig = new JNITypeParser(destination.signature());
+        if (sig.isVoid()) {
             return this;
         }
         throw new InvalidTypeException();
diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/ArrayReferenceImpl.c b/src/jdk.jdwp.agent/share/native/libjdwp/ArrayReferenceImpl.c
index a997dfd6334..e200de0df00 100644
--- a/src/jdk.jdwp.agent/share/native/libjdwp/ArrayReferenceImpl.c
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/ArrayReferenceImpl.c
@@ -27,6 +27,7 @@
 #include "ArrayReferenceImpl.h"
 #include "inStream.h"
 #include "outStream.h"
+#include "signature.h"
 
 static jboolean
 length(PacketInputStream *in, PacketOutputStream *out)
@@ -204,7 +205,7 @@ writeDoubleComponents(JNIEnv *env, PacketOutputStream *out,
 
 static void
 writeObjectComponents(JNIEnv *env, PacketOutputStream *out,
-                    jarray array, jint index, jint length)
+                      jarray array, jint index, jint length)
 {
 
     WITH_LOCAL_REFS(env, length) {
@@ -225,6 +226,9 @@ writeObjectComponents(JNIEnv *env, PacketOutputStream *out,
     } END_WITH_LOCAL_REFS(env);
 }
 
+static void writeComponents(JNIEnv *env, PacketOutputStream *out, char *signature,
+                            jarray array, jint index, jint length);
+
 static jboolean
 getValues(PacketInputStream *in, PacketOutputStream *out)
 {
@@ -265,68 +269,14 @@ getValues(PacketInputStream *in, PacketOutputStream *out)
 
     WITH_LOCAL_REFS(env, 1) {
 
-        jclass arrayClass;
         char *signature = NULL;
-        char *componentSignature;
-        jbyte typeKey;
-        jvmtiError error;
 
-        arrayClass = JNI_FUNC_PTR(env,GetObjectClass)(env, array);
-        error = classSignature(arrayClass, &signature, NULL);
-        if (error != JVMTI_ERROR_NONE) {
-            goto err;
+        jclass arrayClass = JNI_FUNC_PTR(env,GetObjectClass)(env, array);
+        jvmtiError error = classSignature(arrayClass, &signature, NULL);
+        if (error == JVMTI_ERROR_NONE) {
+            writeComponents(env, out, signature, array, index, length);
+            jvmtiDeallocate(signature);
         }
-        componentSignature = &signature[1];
-        typeKey = componentSignature[0];
-
-        (void)outStream_writeByte(out, typeKey);
-        (void)outStream_writeInt(out, length);
-
-        if (isObjectTag(typeKey)) {
-            writeObjectComponents(env, out, array, index, length);
-        } else {
-            switch (typeKey) {
-                case JDWP_TAG(BYTE):
-                    writeByteComponents(env, out, array, index, length);
-                    break;
-
-                case JDWP_TAG(CHAR):
-                    writeCharComponents(env, out, array, index, length);
-                    break;
-
-                case JDWP_TAG(FLOAT):
-                    writeFloatComponents(env, out, array, index, length);
-                    break;
-
-                case JDWP_TAG(DOUBLE):
-                    writeDoubleComponents(env, out, array, index, length);
-                    break;
-
-                case JDWP_TAG(INT):
-                    writeIntComponents(env, out, array, index, length);
-                    break;
-
-                case JDWP_TAG(LONG):
-                    writeLongComponents(env, out, array, index, length);
-                    break;
-
-                case JDWP_TAG(SHORT):
-                    writeShortComponents(env, out, array, index, length);
-                    break;
-
-                case JDWP_TAG(BOOLEAN):
-                    writeBooleanComponents(env, out, array, index, length);
-                    break;
-
-                default:
-                    outStream_setError(out, JDWP_ERROR(INVALID_TAG));
-                    break;
-            }
-        }
-
-        jvmtiDeallocate(signature);
-
-    err:;
 
     } END_WITH_LOCAL_REFS(env);
 
@@ -338,6 +288,58 @@ getValues(PacketInputStream *in, PacketOutputStream *out)
     return JNI_TRUE;
 }
 
+static void writeComponents(JNIEnv *env, PacketOutputStream *out, char *signature,
+                            jarray array, jint index, jint length) {
+
+    char * componentSignature = componentTypeSignature(signature);
+    jbyte typeKey = jdwpTag(componentSignature);
+
+    (void)outStream_writeByte(out, typeKey);
+    (void)outStream_writeInt(out, length);
+
+    if (isReferenceTag(typeKey)) {
+        writeObjectComponents(env, out, array, index, length);
+        return;
+    }
+    switch (typeKey) {
+        case JDWP_TAG(BYTE):
+            writeByteComponents(env, out, array, index, length);
+            break;
+
+        case JDWP_TAG(CHAR):
+            writeCharComponents(env, out, array, index, length);
+            break;
+
+        case JDWP_TAG(FLOAT):
+            writeFloatComponents(env, out, array, index, length);
+            break;
+
+        case JDWP_TAG(DOUBLE):
+            writeDoubleComponents(env, out, array, index, length);
+            break;
+
+        case JDWP_TAG(INT):
+            writeIntComponents(env, out, array, index, length);
+            break;
+
+        case JDWP_TAG(LONG):
+            writeLongComponents(env, out, array, index, length);
+            break;
+
+        case JDWP_TAG(SHORT):
+            writeShortComponents(env, out, array, index, length);
+            break;
+
+        case JDWP_TAG(BOOLEAN):
+            writeBooleanComponents(env, out, array, index, length);
+            break;
+
+        default:
+            outStream_setError(out, JDWP_ERROR(INVALID_TAG));
+            break;
+    }
+}
+
 static jdwpError
 readBooleanComponents(JNIEnv *env, PacketInputStream *in,
                    jarray array, int index, int length)
@@ -477,6 +479,8 @@ readObjectComponents(JNIEnv *env, PacketInputStream *in,
     return JDWP_ERROR(NONE);
 }
 
+static jdwpError readComponents(JNIEnv *env, PacketInputStream *in, char *signature,
+                                jarray array, jint index, jint length);
 
 static jboolean
 setValues(PacketInputStream *in, PacketOutputStream *out)
@@ -515,69 +519,14 @@ setValues(PacketInputStream *in, PacketOutputStream *out)
 
     WITH_LOCAL_REFS(env, 1)  {
 
-        jclass arrayClass;
         char *signature = NULL;
-        char *componentSignature;
-        jvmtiError error;
 
-        arrayClass = JNI_FUNC_PTR(env,GetObjectClass)(env, array);
-        error = classSignature(arrayClass, &signature, NULL);
-        if (error != JVMTI_ERROR_NONE) {
-            goto err;
+        jclass arrayClass = JNI_FUNC_PTR(env,GetObjectClass)(env, array);
+        jvmtiError error = classSignature(arrayClass, &signature, NULL);
+        if (error == JVMTI_ERROR_NONE) {
+            serror = readComponents(env, in, signature, array, index, length);
+            jvmtiDeallocate(signature);
         }
-        componentSignature = &signature[1];
-
-        switch (componentSignature[0]) {
-            case JDWP_TAG(OBJECT):
-            case JDWP_TAG(ARRAY):
-                serror = readObjectComponents(env, in, array, index, length);
-                break;
-
-            case JDWP_TAG(BYTE):
-                serror = readByteComponents(env, in, array, index, length);
-                break;
-
-            case JDWP_TAG(CHAR):
-                serror = readCharComponents(env, in, array, index, length);
-                break;
-
-            case JDWP_TAG(FLOAT):
-                serror = readFloatComponents(env, in, array, index, length);
-                break;
-
-            case JDWP_TAG(DOUBLE):
-                serror = readDoubleComponents(env, in, array, index, length);
-                break;
-
-            case JDWP_TAG(INT):
-                serror = readIntComponents(env, in, array, index, length);
-                break;
-
-            case JDWP_TAG(LONG):
-                serror = readLongComponents(env, in, array, index, length);
-                break;
-
-            case JDWP_TAG(SHORT):
-                serror = readShortComponents(env, in, array, index, length);
-                break;
-
-            case JDWP_TAG(BOOLEAN):
-                serror = readBooleanComponents(env, in, array, index, length);
-                break;
-
-            default:
-                {
-                    ERROR_MESSAGE(("Invalid array component signature: %s",
-                                        componentSignature));
-                    EXIT_ERROR(AGENT_ERROR_INVALID_OBJECT,NULL);
-                }
-                break;
-        }
-
-        jvmtiDeallocate(signature);
-
-    err:;
-
     } END_WITH_LOCAL_REFS(env);
 
     if (JNI_FUNC_PTR(env,ExceptionOccurred)(env)) {
@@ -592,6 +541,61 @@ setValues(PacketInputStream *in, PacketOutputStream *out)
     return JNI_TRUE;
 }
 
+static jdwpError readComponents(JNIEnv *env, PacketInputStream *in, char *signature,
+jarray array, jint index, jint length) {
+    jdwpError serror = JDWP_ERROR(NONE);
+
+    char *componentSignature = componentTypeSignature(signature);
+    jbyte typeKey = jdwpTag(componentSignature);
+    if (isReferenceTag(typeKey)) {
+        serror = readObjectComponents(env, in, array, index, length);
+        return serror;
+    }
+    switch (typeKey) {
+        case JDWP_TAG(BYTE):
+            serror = readByteComponents(env, in, array, index, length);
+            break;
+
+        case JDWP_TAG(CHAR):
+            serror = readCharComponents(env, in, array, index, length);
+            break;
+
+        case JDWP_TAG(FLOAT):
+            serror = readFloatComponents(env, in, array, index, length);
+            break;
+
+        case JDWP_TAG(DOUBLE):
+            serror = readDoubleComponents(env, in, array, index, length);
+            break;
+
+        case JDWP_TAG(INT):
+            serror = readIntComponents(env, in, array, index, length);
+            break;
+
+        case JDWP_TAG(LONG):
+            serror = readLongComponents(env, in, array, index, length);
+            break;
+
+        case JDWP_TAG(SHORT):
+            serror = readShortComponents(env, in, array, index, length);
+            break;
+
+        case JDWP_TAG(BOOLEAN):
+            serror = readBooleanComponents(env, in, array, index, length);
+            break;
+
+        default:
+            {
+                ERROR_MESSAGE(("Invalid array component signature: %s",
+                                    componentSignature));
+                EXIT_ERROR(AGENT_ERROR_INVALID_OBJECT,NULL);
+            }
+            break;
+    }
+
+    return serror;
+}
+
 Command ArrayReference_Commands[] = {
     {length, "Length"},
     {getValues, "GetValues"},
diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/ArrayTypeImpl.c b/src/jdk.jdwp.agent/share/native/libjdwp/ArrayTypeImpl.c
index 3d33ee533df..c1631c29938 100644
--- a/src/jdk.jdwp.agent/share/native/libjdwp/ArrayTypeImpl.c
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/ArrayTypeImpl.c
@@ -27,6 +27,8 @@
 #include "util.h"
 #include "inStream.h"
 #include "outStream.h"
+#include "signature.h"
+
 
 /*
  * Determine the component class by looking thru all classes for
@@ -148,7 +150,7 @@ writeNewPrimitiveArray(JNIEnv *env, PacketOutputStream *out,
 
         jarray array = NULL;
 
-        switch (componentSignature[0]) {
+        switch (jdwpTag(componentSignature)) {
             case JDWP_TAG(BYTE):
                 array = JNI_FUNC_PTR(env,NewByteArray)(env, size);
                 break;
@@ -227,10 +229,10 @@ newInstance(PacketInputStream *in, PacketOutputStream *out)
         outStream_setError(out, map2jdwpError(error));
         return JNI_FALSE;
     }
-    componentSignature = &signature[1];
+    componentSignature = componentTypeSignature(signature);
 
-    if ((componentSignature[0] == JDWP_TAG(OBJECT)) ||
-        (componentSignature[0] == JDWP_TAG(ARRAY))) {
+    jbyte typeKey = jdwpTag(componentSignature);
+    if (isReferenceTag(typeKey)) {
         writeNewObjectArray(env, out, arrayClass, size, componentSignature);
     } else {
         writeNewPrimitiveArray(env, out, arrayClass, size, componentSignature);
diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/ClassTypeImpl.c b/src/jdk.jdwp.agent/share/native/libjdwp/ClassTypeImpl.c
index e7e8d453663..fa22cf21038 100644
--- a/src/jdk.jdwp.agent/share/native/libjdwp/ClassTypeImpl.c
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/ClassTypeImpl.c
@@ -27,6 +27,7 @@
 #include "ClassTypeImpl.h"
 #include "inStream.h"
 #include "outStream.h"
+#include "signature.h"
 
 static jboolean
 superclass(PacketInputStream *in, PacketOutputStream *out)
@@ -58,15 +59,18 @@ readStaticFieldValue(JNIEnv *env, PacketInputStream *in, jclass clazz,
                      jfieldID field, char *signature)
 {
     jvalue value;
-    jdwpError serror = JDWP_ERROR(NONE);
+    jbyte typeKey = jdwpTag(signature);
 
-    switch (signature[0]) {
-        case JDWP_TAG(ARRAY):
-        case JDWP_TAG(OBJECT):
-            value.l = inStream_readObjectRef(env, in);
-            JNI_FUNC_PTR(env,SetStaticObjectField)(env, clazz, field, value.l);
-            break;
+    if (isReferenceTag(typeKey)) {
+        value.l = inStream_readObjectRef(env, in);
+        JNI_FUNC_PTR(env,SetStaticObjectField)(env, clazz, field, value.l);
+        if (JNI_FUNC_PTR(env,ExceptionOccurred)(env)) {
+            return JDWP_ERROR(INTERNAL);
+        }
+        return JDWP_ERROR(NONE);
+    }
 
+    switch (typeKey) {
         case JDWP_TAG(BYTE):
             value.b = inStream_readByte(in);
             JNI_FUNC_PTR(env,SetStaticByteField)(env, clazz, field, value.b);
@@ -109,10 +113,9 @@ readStaticFieldValue(JNIEnv *env, PacketInputStream *in, jclass clazz,
     }
 
     if (JNI_FUNC_PTR(env,ExceptionOccurred)(env)) {
-        serror = JDWP_ERROR(INTERNAL);
+        return JDWP_ERROR(INTERNAL);
     }
-
-    return serror;
+    return JDWP_ERROR(NONE);
 }
 
 static jboolean
diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/ObjectReferenceImpl.c b/src/jdk.jdwp.agent/share/native/libjdwp/ObjectReferenceImpl.c
index 9bf19bc5e67..71d9ea8c0ed 100644
--- a/src/jdk.jdwp.agent/share/native/libjdwp/ObjectReferenceImpl.c
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/ObjectReferenceImpl.c
@@ -28,6 +28,7 @@
 #include "commonRef.h"
 #include "inStream.h"
 #include "outStream.h"
+#include "signature.h"
 
 static jboolean
 referenceType(PacketInputStream *in, PacketOutputStream *out)
@@ -65,21 +66,22 @@ getValues(PacketInputStream *in, PacketOutputStream *out)
     return JNI_TRUE;
 }
 
-
 static jvmtiError
 readFieldValue(JNIEnv *env, PacketInputStream *in, jclass clazz,
                jobject object, jfieldID field, char *signature)
 {
     jvalue value;
-    jvmtiError error;
-
-    switch (signature[0]) {
-        case JDWP_TAG(ARRAY):
-        case JDWP_TAG(OBJECT):
-            value.l = inStream_readObjectRef(env, in);
-            JNI_FUNC_PTR(env,SetObjectField)(env, object, field, value.l);
-            break;
 
+    jbyte typeKey = jdwpTag(signature);
+    if (isReferenceTag(typeKey)) {
+        value.l = inStream_readObjectRef(env, in);
+        JNI_FUNC_PTR(env,SetObjectField)(env, object, field, value.l);
+        if (JNI_FUNC_PTR(env,ExceptionOccurred)(env)) {
+            return AGENT_ERROR_JNI_EXCEPTION;
+        }
+        return JVMTI_ERROR_NONE;
+    }
+    switch (typeKey) {
         case JDWP_TAG(BYTE):
             value.b = inStream_readByte(in);
             JNI_FUNC_PTR(env,SetByteField)(env, object, field, value.b);
@@ -121,12 +123,10 @@ readFieldValue(JNIEnv *env, PacketInputStream *in, jclass clazz,
             break;
     }
 
-    error = JVMTI_ERROR_NONE;
     if (JNI_FUNC_PTR(env,ExceptionOccurred)(env)) {
-        error = AGENT_ERROR_JNI_EXCEPTION;
+        return AGENT_ERROR_JNI_EXCEPTION;
     }
-
-    return error;
+    return JVMTI_ERROR_NONE;
 }
 
 static jboolean
diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.c b/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.c
index 65811fecb20..38cd8e16f9d 100644
--- a/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.c
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -67,6 +67,7 @@
 #include "classTrack.h"
 #include "commonRef.h"
 #include "debugLoop.h"
+#include "signature.h"
 
 static HandlerID requestIdCounter;
 static jbyte currentSessionID;
diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/eventHelper.c b/src/jdk.jdwp.agent/share/native/libjdwp/eventHelper.c
index 5d39bcc0323..11c6e5a72b9 100644
--- a/src/jdk.jdwp.agent/share/native/libjdwp/eventHelper.c
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/eventHelper.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,7 @@
 #include "eventHandler.h"
 #include "threadControl.h"
 #include "invoker.h"
+#include "signature.h"
 
 
 #define COMMAND_LOOP_THREAD_NAME "JDWP Event Helper Thread"
@@ -479,7 +480,7 @@ handleFrameEventCommandSingle(JNIEnv* env, PacketOutputStream *out,
     writeCodeLocation(out, command->clazz, command->method, command->location);
     if (command->typeKey) {
         (void)outStream_writeValue(env, out, command->typeKey, command->returnValue);
-        if (isObjectTag(command->typeKey) &&
+        if (isReferenceTag(command->typeKey) &&
             command->returnValue.l != NULL) {
             tossGlobalRef(env, &(command->returnValue.l));
         }
@@ -851,7 +852,7 @@ saveEventInfoRefs(JNIEnv *env, EventInfo *evinfo)
                 saveGlobalRef(env, clazz, pclazz);
             }
             sig = evinfo->u.field_modification.signature_type;
-            if ((sig == JDWP_TAG(ARRAY)) || (sig == JDWP_TAG(OBJECT))) {
+            if (isReferenceTag(sig)) {
                 if ( evinfo->u.field_modification.new_value.l != NULL ) {
                     pobject = &(evinfo->u.field_modification.new_value.l);
                     object = *pobject;
@@ -904,7 +905,7 @@ tossEventInfoRefs(JNIEnv *env, EventInfo *evinfo)
                 tossGlobalRef(env, &(evinfo->u.field_modification.field_clazz));
             }
             sig = evinfo->u.field_modification.signature_type;
-            if ((sig == JDWP_TAG(ARRAY)) || (sig == JDWP_TAG(OBJECT))) {
+            if (isReferenceTag(sig)) {
                 if ( evinfo->u.field_modification.new_value.l != NULL ) {
                     tossGlobalRef(env, &(evinfo->u.field_modification.new_value.l));
                 }
@@ -1108,7 +1109,7 @@ eventHelper_recordFrameEvent(jint id, jbyte suspendPolicy, EventIndex ei,
         /*
          * V or B C D F I J S Z L <classname> ;    [ ComponentType
          */
-        if (isObjectTag(frameCommand->typeKey) &&
+        if (isReferenceTag(frameCommand->typeKey) &&
             returnValue.l != NULL) {
             saveGlobalRef(env, returnValue.l, &(frameCommand->returnValue.l));
         } else {
diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/inStream.c b/src/jdk.jdwp.agent/share/native/libjdwp/inStream.c
index e9853afb200..232da2cb348 100644
--- a/src/jdk.jdwp.agent/share/native/libjdwp/inStream.c
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/inStream.c
@@ -424,7 +424,7 @@ inStream_clearError(PacketInputStream *stream)
 }
 
 jvalue
-inStream_readValue(PacketInputStream *stream, jbyte *typeKeyPtr)
+inStream_readValue(PacketInputStream *stream)
 {
     jvalue value;
     jbyte typeKey = inStream_readByte(stream);
@@ -473,9 +473,6 @@ inStream_readValue(PacketInputStream *stream, jbyte *typeKeyPtr)
                 break;
         }
     }
-    if (typeKeyPtr) {
-        *typeKeyPtr = typeKey;
-    }
     return value;
 }
 
diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/inStream.h b/src/jdk.jdwp.agent/share/native/libjdwp/inStream.h
index 4a409fe19c1..fa2b3eb888d 100644
--- a/src/jdk.jdwp.agent/share/native/libjdwp/inStream.h
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/inStream.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -70,7 +70,7 @@ jstring inStream_readStringRef(JNIEnv *env, PacketInputStream *stream);
 jarray inStream_readArrayRef(JNIEnv *env, PacketInputStream *stream);
 
 char *inStream_readString(PacketInputStream *stream);
-jvalue inStream_readValue(struct PacketInputStream *in, jbyte *typeKeyPtr);
+jvalue inStream_readValue(struct PacketInputStream *in);
 
 jdwpError inStream_skipBytes(PacketInputStream *stream, jint count);
 
diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/invoker.c b/src/jdk.jdwp.agent/share/native/libjdwp/invoker.c
index 8e2981d9fa3..fdc7a0bc613 100644
--- a/src/jdk.jdwp.agent/share/native/libjdwp/invoker.c
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/invoker.c
@@ -28,6 +28,7 @@
 #include "eventHandler.h"
 #include "threadControl.h"
 #include "outStream.h"
+#include "signature.h"
 
 static jrawMonitorID invokerLock;
 
@@ -52,66 +53,21 @@ void invoker_unlock(void)
     debugMonitorExit(invokerLock);
 }
 
-static jbyte
-returnTypeTag(char *signature)
-{
-    char *tagPtr = strchr(signature, SIGNATURE_END_ARGS);
-    JDI_ASSERT(tagPtr);
-    tagPtr++;    /* 1st character after the end of args */
-    return (jbyte)*tagPtr;
-}
-
-static jbyte
-nextArgumentTypeTag(void **cursor)
-{
-    char *tagPtr = *cursor;
-    jbyte argumentTag = (jbyte)*tagPtr;
-
-    if (*tagPtr != SIGNATURE_END_ARGS) {
-        /* Skip any array modifiers */
-        while (*tagPtr == JDWP_TAG(ARRAY)) {
-            tagPtr++;
-        }
-        /* Skip class name */
-        if (*tagPtr == JDWP_TAG(OBJECT)) {
-            tagPtr = strchr(tagPtr, SIGNATURE_END_CLASS) + 1;
-            JDI_ASSERT(tagPtr);
-        } else {
-            /* Skip primitive sig */
-            tagPtr++;
-        }
-    }
-
-    *cursor = tagPtr;
-    return argumentTag;
-}
-
-static jbyte
-firstArgumentTypeTag(char *signature, void **cursor)
-{
-    JDI_ASSERT(signature[0] == SIGNATURE_BEGIN_ARGS);
-    *cursor = signature + 1; /* skip to the first arg */
-    return nextArgumentTypeTag(cursor);
-}
-
-
 /*
  * Note: argument refs may be destroyed on out-of-memory error
  */
 static jvmtiError
 createGlobalRefs(JNIEnv *env, InvokeRequest *request)
 {
-    jvmtiError error;
+    jvmtiError error = JVMTI_ERROR_NONE;
+    void *cursor = NULL;
+    jbyte argumentTag = 0;
+    jint argIndex = 0;
+    jvalue *argument = request->arguments;
     jclass clazz = NULL;
     jobject instance = NULL;
-    jint argIndex;
-    jbyte argumentTag;
-    jvalue *argument;
-    void *cursor;
     jobject *argRefs = NULL;
 
-    error = JVMTI_ERROR_NONE;
-
     if ( request->argumentCount > 0 ) {
         /*LINTED*/
         argRefs = jvmtiAllocate((jint)(request->argumentCount*sizeof(jobject)));
@@ -138,15 +94,12 @@ createGlobalRefs(JNIEnv *env, InvokeRequest *request)
     }
 
     if ( error == JVMTI_ERROR_NONE && argRefs!=NULL ) {
-        argIndex = 0;
-        argumentTag = firstArgumentTypeTag(request->methodSignature, &cursor);
-        argument = request->arguments;
-        while (argumentTag != SIGNATURE_END_ARGS) {
+        methodSignature_init(request->methodSignature, &cursor);
+        while (methodSignature_nextArgumentExists(&cursor, &argumentTag)) {
             if ( argIndex > request->argumentCount ) {
                 break;
             }
-            if ((argumentTag == JDWP_TAG(OBJECT)) ||
-                (argumentTag == JDWP_TAG(ARRAY))) {
+            if (isReferenceTag(argumentTag)) {
                 /* Create a global ref for any non-null argument */
                 if (argument->l != NULL) {
                     saveGlobalRef(env, argument->l, &argRefs[argIndex]);
@@ -158,7 +111,6 @@ createGlobalRefs(JNIEnv *env, InvokeRequest *request)
             }
             argument++;
             argIndex++;
-            argumentTag = nextArgumentTypeTag(&cursor);
         }
     }
 
@@ -175,16 +127,15 @@ createGlobalRefs(JNIEnv *env, InvokeRequest *request)
         request->instance = instance;
         if ( argRefs!=NULL ) {
             argIndex = 0;
-            argumentTag = firstArgumentTypeTag(request->methodSignature, &cursor);
+            methodSignature_init(request->methodSignature, &cursor);
             argument = request->arguments;
-            while ( argIndex < request->argumentCount ) {
-                if ((argumentTag == JDWP_TAG(OBJECT)) ||
-                    (argumentTag == JDWP_TAG(ARRAY))) {
+            while ( methodSignature_nextArgumentExists(&cursor, &argumentTag) &&
+                   argIndex < request->argumentCount ) {
+                if ( isReferenceTag(argumentTag) ) {
                     argument->l = argRefs[argIndex];
                 }
                 argument++;
                 argIndex++;
-                argumentTag = nextArgumentTypeTag(&cursor);
             }
             jvmtiDeallocate(argRefs);
         }
@@ -218,10 +169,11 @@ createGlobalRefs(JNIEnv *env, InvokeRequest *request)
 static void
 deleteGlobalArgumentRefs(JNIEnv *env, InvokeRequest *request)
 {
-    void *cursor;
+    void *cursor = NULL;
     jint argIndex = 0;
+    jbyte argumentTag = 0;
     jvalue *argument = request->arguments;
-    jbyte argumentTag = firstArgumentTypeTag(request->methodSignature, &cursor);
+    methodSignature_init(request->methodSignature, &cursor);
 
     if (request->clazz != NULL) {
         tossGlobalRef(env, &(request->clazz));
@@ -230,16 +182,15 @@ deleteGlobalArgumentRefs(JNIEnv *env, InvokeRequest *request)
         tossGlobalRef(env, &(request->instance));
     }
     /* Delete global argument references */
-    while (argIndex < request->argumentCount) {
-        if ((argumentTag == JDWP_TAG(OBJECT)) ||
-            (argumentTag == JDWP_TAG(ARRAY))) {
+    while (methodSignature_nextArgumentExists(&cursor, &argumentTag) &&
+           argIndex < request->argumentCount) {
+        if (isReferenceTag(argumentTag)) {
             if (argument->l != NULL) {
                 tossGlobalRef(env, &(argument->l));
             }
         }
         argument++;
         argIndex++;
-        argumentTag = nextArgumentTypeTag(&cursor);
     }
 }
 
@@ -404,23 +355,23 @@ invokeConstructor(JNIEnv *env, InvokeRequest *request)
 static void
 invokeStatic(JNIEnv *env, InvokeRequest *request)
 {
-    switch(returnTypeTag(request->methodSignature)) {
-        case JDWP_TAG(OBJECT):
-        case JDWP_TAG(ARRAY): {
-            jobject object;
-            JDI_ASSERT_MSG(request->clazz, "Request clazz null");
-            object = JNI_FUNC_PTR(env,CallStaticObjectMethodA)(env,
-                                       request->clazz,
-                                       request->method,
-                                       request->arguments);
-            request->returnValue.l = NULL;
-            if (object != NULL) {
-                saveGlobalRef(env, object, &(request->returnValue.l));
-            }
-            break;
+    jbyte returnType = methodSignature_returnTag(request->methodSignature);
+
+    if (isReferenceTag(returnType)) {
+        jobject object;
+        JDI_ASSERT_MSG(request->clazz, "Request clazz null");
+        object = JNI_FUNC_PTR(env,CallStaticObjectMethodA)(env,
+                                   request->clazz,
+                                   request->method,
+                                   request->arguments);
+        request->returnValue.l = NULL;
+        if (object != NULL) {
+            saveGlobalRef(env, object, &(request->returnValue.l));
         }
+        return;
+    }
 
-
+    switch (returnType) {
         case JDWP_TAG(BYTE):
             request->returnValue.b = JNI_FUNC_PTR(env,CallStaticByteMethodA)(env,
                                                        request->clazz,
@@ -493,22 +444,22 @@ invokeStatic(JNIEnv *env, InvokeRequest *request)
 static void
 invokeVirtual(JNIEnv *env, InvokeRequest *request)
 {
-    switch(returnTypeTag(request->methodSignature)) {
-        case JDWP_TAG(OBJECT):
-        case JDWP_TAG(ARRAY): {
-            jobject object;
-            JDI_ASSERT_MSG(request->instance, "Request instance null");
-            object = JNI_FUNC_PTR(env,CallObjectMethodA)(env,
-                                 request->instance,
-                                 request->method,
-                                 request->arguments);
-            request->returnValue.l = NULL;
-            if (object != NULL) {
-                saveGlobalRef(env, object, &(request->returnValue.l));
-            }
-            break;
+    jbyte returnType = methodSignature_returnTag(request->methodSignature);
+    if (isReferenceTag(returnType)) {
+        jobject object;
+        JDI_ASSERT_MSG(request->instance, "Request instance null");
+        object = JNI_FUNC_PTR(env,CallObjectMethodA)(env,
+                             request->instance,
+                             request->method,
+                             request->arguments);
+        request->returnValue.l = NULL;
+        if (object != NULL) {
+            saveGlobalRef(env, object, &(request->returnValue.l));
         }
+        return;
+    }
 
+    switch (returnType) {
         case JDWP_TAG(BYTE):
             request->returnValue.b = JNI_FUNC_PTR(env,CallByteMethodA)(env,
                                                  request->instance,
@@ -581,24 +532,24 @@ invokeVirtual(JNIEnv *env, InvokeRequest *request)
 static void
 invokeNonvirtual(JNIEnv *env, InvokeRequest *request)
 {
-    switch(returnTypeTag(request->methodSignature)) {
-        case JDWP_TAG(OBJECT):
-        case JDWP_TAG(ARRAY): {
-            jobject object;
-            JDI_ASSERT_MSG(request->clazz, "Request clazz null");
-            JDI_ASSERT_MSG(request->instance, "Request instance null");
-            object = JNI_FUNC_PTR(env,CallNonvirtualObjectMethodA)(env,
-                                           request->instance,
-                                           request->clazz,
-                                           request->method,
-                                           request->arguments);
-            request->returnValue.l = NULL;
-            if (object != NULL) {
-                saveGlobalRef(env, object, &(request->returnValue.l));
-            }
-            break;
+    jbyte returnType = methodSignature_returnTag(request->methodSignature);
+    if (isReferenceTag(returnType)) {
+        jobject object;
+        JDI_ASSERT_MSG(request->clazz, "Request clazz null");
+        JDI_ASSERT_MSG(request->instance, "Request instance null");
+        object = JNI_FUNC_PTR(env,CallNonvirtualObjectMethodA)(env,
+                                       request->instance,
+                                       request->clazz,
+                                       request->method,
+                                       request->arguments);
+        request->returnValue.l = NULL;
+        if (object != NULL) {
+            saveGlobalRef(env, object, &(request->returnValue.l));
         }
+        return;
+    }
 
+    switch (returnType) {
         case JDWP_TAG(BYTE):
             request->returnValue.b = JNI_FUNC_PTR(env,CallNonvirtualByteMethodA)(env,
                                                  request->instance,
@@ -797,7 +748,7 @@ invoker_completeInvokeRequest(jthread thread)
              */
             tag = specificTypeKey(env, request->returnValue.l);
         } else {
-            tag = returnTypeTag(request->methodSignature);
+            tag = methodSignature_returnTag(request->methodSignature);
         }
         id = request->id;
         exc = request->exception;
@@ -805,9 +756,9 @@ invoker_completeInvokeRequest(jthread thread)
 
         /* Release return value and exception references, but delay the release
          * until after the return packet was sent. */
+        jbyte returnType = methodSignature_returnTag(request->methodSignature);
         mustReleaseReturnValue = request->invokeType == INVOKE_CONSTRUCTOR ||
-           returnTypeTag(request->methodSignature) == JDWP_TAG(OBJECT) ||
-           returnTypeTag(request->methodSignature) == JDWP_TAG(ARRAY);
+           isReferenceTag(returnType);
     }
 
     /*
diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/signature.c b/src/jdk.jdwp.agent/share/native/libjdwp/signature.c
new file mode 100644
index 00000000000..6f68e14896f
--- /dev/null
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/signature.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "util.h"
+#include "signature.h"
+
+
+/*
+ * JNI signature constants, beyond those defined in JVM_TYPE(*)
+ */
+#define SIGNATURE_BEGIN_ARGS    '('
+#define SIGNATURE_END_ARGS      ')'
+#define SIGNATURE_END_CLASS     ';'
+
+char* componentTypeSignature(const char *signature) {
+     jbyte typeKey = jdwpTag(signature);
+     JDI_ASSERT(isArrayTag(typeKey));
+     JVM_TYPE_ASSERT(signature[1]);
+     return (char*)&signature[1];
+}
+
+jbyte methodSignature_returnTag(char *signature)
+{
+    char *tagPtr = strchr(signature, SIGNATURE_END_ARGS);
+    JDI_ASSERT(tagPtr);
+    tagPtr++;    /* 1st character after the end of args */
+    JVM_TYPE_ASSERT((jbyte)*tagPtr);
+    return (jbyte)*tagPtr;
+}
+
+void methodSignature_init(char *signature, void **cursor)
+{
+     JDI_ASSERT(signature[0] == SIGNATURE_BEGIN_ARGS);
+     *cursor = signature + 1; /* skip to the first arg */
+}
+
+
+jboolean methodSignature_nextArgumentExists(void **cursor, jbyte *argumentTag)
+{
+    char *tagPtr = *cursor;
+    jbyte nextType = (jbyte)*tagPtr;
+
+    if (*tagPtr != SIGNATURE_END_ARGS) {
+        /* Skip any array modifiers */
+        while (*tagPtr == JDWP_TAG(ARRAY)) {
+            tagPtr++;
+        }
+        /* Skip class name */
+        if (*tagPtr == JDWP_TAG(OBJECT)) {
+            tagPtr = strchr(tagPtr, SIGNATURE_END_CLASS) + 1;
+            JDI_ASSERT(tagPtr);
+        } else {
+            /* Skip primitive sig */
+            tagPtr++;
+        }
+    }
+    *cursor = tagPtr;
+    if (nextType != SIGNATURE_END_ARGS) {
+        JVM_TYPE_ASSERT(nextType);
+        *argumentTag = nextType;
+        return JNI_TRUE;
+    }
+    return JNI_FALSE;
+}
+
+/*
+ * Convert the signature "Ljava/lang/Foo;" to a
+ * classname "java.lang.Foo" compatible with the pattern.
+ * Signature is overwritten in-place.
+ */
+void convertSignatureToClassname(char *convert)
+{
+    char *p;
+
+    p = convert + 1;
+    while ((*p != ';') && (*p != '\0')) {
+        char c = *p;
+        if (c == '/') {
+            *(p-1) = '.';
+        } else if (c == '.') {
+            // class signature of a hidden class is "Ljava/lang/Foo.1234;"
+            // map to "java.lang.Foo/1234"
+            *(p-1) = '/';
+        } else {
+            *(p-1) = c;
+        }
+        p++;
+    }
+    *(p-1) = '\0';
+}
diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/signature.h b/src/jdk.jdwp.agent/share/native/libjdwp/signature.h
new file mode 100644
index 00000000000..ceb12769a89
--- /dev/null
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/signature.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef JDWP_SIGNATURE_H
+#define JDWP_SIGNATURE_H
+
+#define JVM_TYPE_ASSERT(typeKey)\
+JDI_ASSERT_MSG(JDWP_Tag_OBJECT == typeKey || \
+               JDWP_Tag_ARRAY == typeKey || \
+               JDWP_Tag_BOOLEAN == typeKey || \
+               JDWP_Tag_BYTE == typeKey || \
+               JDWP_Tag_CHAR == typeKey || \
+               JDWP_Tag_DOUBLE == typeKey || \
+               JDWP_Tag_FLOAT == typeKey || \
+               JDWP_Tag_INT == typeKey || \
+               JDWP_Tag_LONG == typeKey || \
+               JDWP_Tag_SHORT == typeKey || \
+               JDWP_Tag_VOID == typeKey, \
+               "Tag is not a JVM basic type")
+
+static inline jbyte jdwpTag(const char *signature) {
+     JVM_TYPE_ASSERT(signature[0]);
+     return signature[0];
+}
+
+static inline jboolean isReferenceTag(jbyte typeKey) {
+    JVM_TYPE_ASSERT(typeKey);
+    return (typeKey == JDWP_TAG(OBJECT)) || (typeKey == JDWP_TAG(ARRAY));
+}
+
+static inline jboolean isArrayTag(jbyte typeKey) {
+    JVM_TYPE_ASSERT(typeKey);
+    return (typeKey == JDWP_TAG(ARRAY));
+}
+
+char* componentTypeSignature(const char *signature);
+
+void convertSignatureToClassname(char *convert);
+
+void methodSignature_init(char *signature, void **cursor);
+jboolean methodSignature_nextArgumentExists(void **cursor, jbyte *argumentTag);
+jbyte methodSignature_returnTag(char *signature);
+
+#endif
diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/util.c b/src/jdk.jdwp.agent/share/native/libjdwp/util.c
index 429760218fa..5f7962b92af 100644
--- a/src/jdk.jdwp.agent/share/native/libjdwp/util.c
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/util.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,8 @@
 #include "outStream.h"
 #include "inStream.h"
 #include "invoker.h"
+#include "signature.h"
+
 
 /* Global data area */
 BackendGlobalData *gdata = NULL;
@@ -171,6 +173,8 @@ getStaticMethod(JNIEnv *env, jclass clazz, const char * name, const char *signat
     return method;
 }
 
+
+
 void
 util_initialize(JNIEnv *env)
 {
@@ -343,26 +347,25 @@ writeFieldValue(JNIEnv *env, PacketOutputStream *out, jobject object,
         outStream_setError(out, map2jdwpError(error));
         return;
     }
-    typeKey = signature[0];
+    typeKey = jdwpTag(signature);
     jvmtiDeallocate(signature);
 
-    /*
-     * For primitive types, the type key is bounced back as is. Objects
-     * are handled in the switch statement below.
-     */
-    if ((typeKey != JDWP_TAG(OBJECT)) && (typeKey != JDWP_TAG(ARRAY))) {
-        (void)outStream_writeByte(out, typeKey);
+    if (isReferenceTag(typeKey)) {
+
+        jobject value = JNI_FUNC_PTR(env,GetObjectField)(env, object, field);
+        (void)outStream_writeByte(out, specificTypeKey(env, value));
+        (void)outStream_writeObjectRef(env, out, value);
+        return;
+
     }
 
-    switch (typeKey) {
-        case JDWP_TAG(OBJECT):
-        case JDWP_TAG(ARRAY):   {
-            jobject value = JNI_FUNC_PTR(env,GetObjectField)(env, object, field);
-            (void)outStream_writeByte(out, specificTypeKey(env, value));
-            (void)outStream_writeObjectRef(env, out, value);
-            break;
-        }
+    /*
+     * For primitive types, the type key is bounced back as is.
+     */
 
+    (void)outStream_writeByte(out, typeKey);
+
+    switch (typeKey) {
         case JDWP_TAG(BYTE):
             (void)outStream_writeByte(out,
                       JNI_FUNC_PTR(env,GetByteField)(env, object, field));
@@ -418,26 +421,24 @@ writeStaticFieldValue(JNIEnv *env, PacketOutputStream *out, jclass clazz,
         outStream_setError(out, map2jdwpError(error));
         return;
     }
-    typeKey = signature[0];
+    typeKey = jdwpTag(signature);
     jvmtiDeallocate(signature);
 
-    /*
-     * For primitive types, the type key is bounced back as is. Objects
-     * are handled in the switch statement below.
-     */
-    if ((typeKey != JDWP_TAG(OBJECT)) && (typeKey != JDWP_TAG(ARRAY))) {
-        (void)outStream_writeByte(out, typeKey);
+
+    if (isReferenceTag(typeKey)) {
+
+        jobject value = JNI_FUNC_PTR(env,GetStaticObjectField)(env, clazz, field);
+        (void)outStream_writeByte(out, specificTypeKey(env, value));
+        (void)outStream_writeObjectRef(env, out, value);
+
+        return;
     }
 
+    /*
+     * For primitive types, the type key is bounced back as is.
+     */
+    (void)outStream_writeByte(out, typeKey);
     switch (typeKey) {
-        case JDWP_TAG(OBJECT):
-        case JDWP_TAG(ARRAY):   {
-            jobject value = JNI_FUNC_PTR(env,GetStaticObjectField)(env, clazz, field);
-            (void)outStream_writeByte(out, specificTypeKey(env, value));
-            (void)outStream_writeObjectRef(env, out, value);
-            break;
-        }
-
         case JDWP_TAG(BYTE):
             (void)outStream_writeByte(out,
                       JNI_FUNC_PTR(env,GetStaticByteField)(env, clazz, field));
@@ -570,7 +571,7 @@ sharedInvoke(PacketInputStream *in, PacketOutputStream *out)
             return JNI_TRUE;
         }
         for (i = 0; (i < argumentCount) && !inStream_error(in); i++) {
-            arguments[i] = inStream_readValue(in, NULL);
+            arguments[i] = inStream_readValue(in);
         }
         if (inStream_error(in)) {
             return JNI_TRUE;
@@ -977,32 +978,6 @@ getSourceDebugExtension(jclass clazz, char **extensionPtr)
                 (gdata->jvmti, clazz, extensionPtr);
 }
 
-/*
- * Convert the signature "Ljava/lang/Foo;" to a
- * classname "java.lang.Foo" compatible with the pattern.
- * Signature is overwritten in-place.
- */
-void
-convertSignatureToClassname(char *convert)
-{
-    char *p;
-
-    p = convert + 1;
-    while ((*p != ';') && (*p != '\0')) {
-        char c = *p;
-        if (c == '/') {
-            *(p-1) = '.';
-        } else if (c == '.') {
-            // class signature of a hidden class is "Ljava/lang/Foo.1234;"
-            // map to "java.lang.Foo/1234"
-            *(p-1) = '/';
-        } else {
-            *(p-1) = c;
-        }
-        p++;
-    }
-    *(p-1) = '\0';
-}
 
 static void
 handleInterrupt(void)
diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/util.h b/src/jdk.jdwp.agent/share/native/libjdwp/util.h
index bcb59457120..97f01629921 100644
--- a/src/jdk.jdwp.agent/share/native/libjdwp/util.h
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/util.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -251,13 +251,6 @@ typedef struct ObjectBatch {
     jint     count;
 } ObjectBatch;
 
-/*
- * JNI signature constants, beyond those defined in JDWP_TAG(*)
- */
-#define SIGNATURE_BEGIN_ARGS    '('
-#define SIGNATURE_END_ARGS      ')'
-#define SIGNATURE_END_CLASS     ';'
-
 /*
  * Modifier flags for classes, fields, methods
  */
@@ -291,7 +284,6 @@ jbyte referenceTypeTag(jclass clazz);
 jbyte specificTypeKey(JNIEnv *env, jobject object);
 jboolean isObjectTag(jbyte tag);
 jvmtiError spawnNewThread(jvmtiStartFunction func, void *arg, char *name);
-void convertSignatureToClassname(char *convert);
 void writeCodeLocation(struct PacketOutputStream *out, jclass clazz,
                        jmethodID method, jlocation location);