diff a/src/hotspot/share/runtime/signature.cpp b/src/hotspot/share/runtime/signature.cpp
--- a/src/hotspot/share/runtime/signature.cpp
+++ b/src/hotspot/share/runtime/signature.cpp
@@ -33,12 +33,14 @@
 #include "oops/instanceKlass.hpp"
 #include "oops/klass.inline.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/symbol.hpp"
 #include "oops/typeArrayKlass.hpp"
+#include "oops/inlineKlass.inline.hpp"
 #include "runtime/fieldDescriptor.inline.hpp"
 #include "runtime/handles.inline.hpp"
+#include "runtime/interfaceSupport.inline.hpp"
 #include "runtime/safepointVerifiers.hpp"
 #include "runtime/sharedRuntime.hpp"
 #include "runtime/signature.hpp"
 #include "runtime/sharedRuntime.hpp"
 
@@ -47,11 +49,11 @@
 // Signature syntax:
 //
 // Signature  = "(" {Parameter} ")" ReturnType.
 // Parameter  = FieldType.
 // ReturnType = FieldType | "V".
-// FieldType  = "B" | "C" | "D" | "F" | "I" | "J" | "S" | "Z" | "L" ClassName ";" | "[" FieldType.
+// FieldType  = "B" | "C" | "D" | "F" | "I" | "J" | "S" | "Z" | "L" ClassName ";" | "Q" ValueClassName ";" | "[" FieldType.
 // ClassName  = string.
 
 // The ClassName string can be any JVM-style UTF8 string except:
 //  - an empty string (the empty string is never a name of any kind)
 //  - a string which begins or ends with slash '/' (the package separator)
@@ -499,10 +501,25 @@
   }
   _previous_name = name;
   return name;
 }
 
+InlineKlass* SignatureStream::as_inline_klass(InstanceKlass* holder) {
+  ThreadInVMfromUnknown tiv;
+  JavaThread* THREAD = JavaThread::current();
+  HandleMark hm(THREAD);
+  Handle class_loader(THREAD, holder->class_loader());
+  Handle protection_domain(THREAD, holder->protection_domain());
+  Klass* k = as_klass(class_loader, protection_domain, SignatureStream::CachedOrNull, THREAD);
+  assert(!HAS_PENDING_EXCEPTION, "Should never throw");
+  if (k != nullptr && k->is_inline_klass()) {
+    return InlineKlass::cast(k);
+  } else {
+    return nullptr;
+  }
+}
+
 Klass* SignatureStream::as_klass(Handle class_loader, Handle protection_domain,
                                  FailureMode failure_mode, TRAPS) {
   if (!is_reference()) {
     return nullptr;
   }
@@ -578,11 +595,10 @@
   _class_loader = Handle(current, _load_origin->class_loader());
   _protection_domain = Handle(current, _load_origin->protection_domain());
 }
 
 #ifdef ASSERT
-
 extern bool signature_constants_sane(); // called from basic_types_init()
 
 bool signature_constants_sane() {
   // for the lookup table, test every 8-bit code point, and then some:
   for (int i = -256; i <= 256; i++) {
@@ -597,11 +613,11 @@
     assert(btc == btcode, "misconfigured table: %d => %d not %d", i, btc, btcode);
   }
   return true;
 }
 
-bool SignatureVerifier::is_valid_method_signature(Symbol* sig) {
+bool SignatureVerifier::is_valid_method_signature(const Symbol* sig) {
   const char* method_sig = (const char*)sig->bytes();
   ssize_t len = sig->utf8_length();
   ssize_t index = 0;
   if (method_sig != nullptr && len > 1 && method_sig[index] == JVM_SIGNATURE_FUNC) {
     ++index;
@@ -620,11 +636,11 @@
     }
   }
   return false;
 }
 
-bool SignatureVerifier::is_valid_type_signature(Symbol* sig) {
+bool SignatureVerifier::is_valid_type_signature(const Symbol* sig) {
   const char* type_sig = (const char*)sig->bytes();
   ssize_t len = sig->utf8_length();
   return (type_sig != nullptr && len >= 1 &&
           (is_valid_type(type_sig, len) == len));
 }
@@ -667,5 +683,58 @@
   }
   return -1;
 }
 
 #endif // ASSERT
+
+// Adds an argument to the signature
+void SigEntry::add_entry(GrowableArray<SigEntry>* sig, BasicType bt, Symbol* symbol, int offset) {
+  sig->append(SigEntry(bt, offset, symbol));
+  if (bt == T_LONG || bt == T_DOUBLE) {
+    sig->append(SigEntry(T_VOID, offset, symbol)); // Longs and doubles take two stack slots
+  }
+}
+
+// Returns true if the argument at index 'i' is not an inline type delimiter
+bool SigEntry::skip_value_delimiters(const GrowableArray<SigEntry>* sig, int i) {
+  return (sig->at(i)._bt != T_METADATA &&
+          (sig->at(i)._bt != T_VOID || sig->at(i-1)._bt == T_LONG || sig->at(i-1)._bt == T_DOUBLE));
+}
+
+// Fill basic type array from signature array
+int SigEntry::fill_sig_bt(const GrowableArray<SigEntry>* sig, BasicType* sig_bt) {
+  int count = 0;
+  for (int i = 0; i < sig->length(); i++) {
+    if (skip_value_delimiters(sig, i)) {
+      sig_bt[count++] = sig->at(i)._bt;
+    }
+  }
+  return count;
+}
+
+// Create a temporary symbol from the signature array
+TempNewSymbol SigEntry::create_symbol(const GrowableArray<SigEntry>* sig) {
+  ResourceMark rm;
+  int length = sig->length();
+  char* sig_str = NEW_RESOURCE_ARRAY(char, 2*length + 3);
+  int idx = 0;
+  sig_str[idx++] = '(';
+  for (int i = 0; i < length; i++) {
+    BasicType bt = sig->at(i)._bt;
+    if (bt == T_METADATA || bt == T_VOID) {
+      // Ignore
+    } else {
+      if (bt == T_ARRAY) {
+        bt = T_OBJECT; // We don't know the element type, treat as Object
+      }
+      sig_str[idx++] = type2char(bt);
+      if (bt == T_OBJECT) {
+        sig_str[idx++] = ';';
+      }
+    }
+  }
+  sig_str[idx++] = ')';
+  // Add a dummy return type. It won't be used but SignatureStream needs it.
+  sig_str[idx++] = 'V';
+  sig_str[idx++] = '\0';
+  return SymbolTable::new_symbol(sig_str);
+}
