diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp
index 09b3cb26203d1..ba4744e1f4cd9 100644
--- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp
+++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp
@@ -770,9 +770,11 @@ C2V_VMENTRY_NULL(jobjectArray, resolveBootstrapMethod, (JNIEnv* env, jobject, AR
   }
   // Get the indy entry based on CP index
   int indy_index = -1;
-  for (int i = 0; i < cp->resolved_indy_entries_length(); i++) {
-    if (cp->resolved_indy_entry_at(i)->constant_pool_index() == index) {
-      indy_index = i;
+  if (is_indy) {
+    for (int i = 0; i < cp->resolved_indy_entries_length(); i++) {
+      if (cp->resolved_indy_entry_at(i)->constant_pool_index() == index) {
+        indy_index = i;
+      }
     }
   }
   // Resolve the bootstrap specifier, its name, type, and static arguments
@@ -838,6 +840,11 @@ C2V_VMENTRY_NULL(jobjectArray, resolveBootstrapMethod, (JNIEnv* env, jobject, AR
   return JVMCIENV->get_jobjectArray(bsmi);
 C2V_END
 
+C2V_VMENTRY_0(jint, bootstrapArgumentIndexAt, (JNIEnv* env, jobject, ARGUMENT_PAIR(cp), jint cpi, jint index))
+  constantPoolHandle cp(THREAD, UNPACK_PAIR(ConstantPool, cp));
+  return cp->bootstrap_argument_index_at(cpi, index);
+C2V_END
+
 C2V_VMENTRY_0(jint, lookupNameAndTypeRefIndexInPool, (JNIEnv* env, jobject, ARGUMENT_PAIR(cp), jint index, jint opcode))
   constantPoolHandle cp(THREAD, UNPACK_PAIR(ConstantPool, cp));
   return cp->name_and_type_ref_index_at(index, (Bytecodes::Code)opcode);
@@ -3134,6 +3141,7 @@ JNINativeMethod CompilerToVM::methods[] = {
   {CC "lookupConstantInPool",                         CC "(" HS_CONSTANT_POOL2 "IZ)" JAVACONSTANT,                                          FN_PTR(lookupConstantInPool)},
   {CC "constantPoolRemapInstructionOperandFromCache", CC "(" HS_CONSTANT_POOL2 "I)I",                                                       FN_PTR(constantPoolRemapInstructionOperandFromCache)},
   {CC "resolveBootstrapMethod",                       CC "(" HS_CONSTANT_POOL2 "I)[" OBJECT,                                                FN_PTR(resolveBootstrapMethod)},
+  {CC "bootstrapArgumentIndexAt",                     CC "(" HS_CONSTANT_POOL2 "II)I",                                                      FN_PTR(bootstrapArgumentIndexAt)},
   {CC "getUncachedStringInPool",                      CC "(" HS_CONSTANT_POOL2 "I)" JAVACONSTANT,                                           FN_PTR(getUncachedStringInPool)},
   {CC "resolveTypeInPool",                            CC "(" HS_CONSTANT_POOL2 "I)" HS_KLASS,                                               FN_PTR(resolveTypeInPool)},
   {CC "resolveFieldInPool",                           CC "(" HS_CONSTANT_POOL2 "I" HS_METHOD2 "B[I)" HS_KLASS,                              FN_PTR(resolveFieldInPool)},
diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java
index f50207ac13a05..d20d4d5c5af89 100644
--- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java
+++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java
@@ -476,6 +476,28 @@ Object[] resolveBootstrapMethod(HotSpotConstantPool constantPool, int cpi) {
 
     private native Object[] resolveBootstrapMethod(HotSpotConstantPool constantPool, long constantPoolPointer, int cpi);
 
+    /**
+     * Gets the constant pool index of a static argument of a {@code CONSTANT_Dynamic_info} or
+     * @{code CONSTANT_InvokeDynamic_info} entry. Used when the list of static arguments in the
+     * {@link BootstrapMethodInvocation} is a {@code List<PrimitiveConstant>} of the form
+     * {{@code arg_count}, {@code pool_index}}, meaning the arguments are not already resolved and that
+     * the JDK has to lookup the arguments when they are needed. The {@code cpi} corresponds to
+     * {@code pool_index} and the {@code index} has to be smaller than {@code arg_count}.
+     *
+     * The behavior of this method is undefined if {@code cpi} does not denote an entry representing
+     * a {@code CONSTANT_Dynamic_info} or a @{code CONSTANT_InvokeDynamic_info}, or if the index
+     * is out of bounds.
+     *
+     * @param cpi the index of a {@code CONSTANT_Dynamic_info} or @{code CONSTANT_InvokeDynamic_info} entry
+     * @param index the index of the static argument in the list of static arguments
+     * @return the constant pool index associated with the static argument
+     */
+    int bootstrapArgumentIndexAt(HotSpotConstantPool constantPool, int cpi, int index) {
+        return bootstrapArgumentIndexAt(constantPool, constantPool.getConstantPoolPointer(), cpi, index);
+    }
+
+    private native int bootstrapArgumentIndexAt(HotSpotConstantPool constantPool, long constantPoolPointer, int cpi, int index);
+
     /**
      * If {@code cpi} denotes an entry representing a signature polymorphic method ({@jvms 2.9}),
      * this method ensures that the type referenced by the entry is loaded and initialized. It
diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstantPool.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstantPool.java
index d4bb97f03c4cc..12d1b24a3df4a 100644
--- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstantPool.java
+++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstantPool.java
@@ -27,6 +27,8 @@
 import static jdk.vm.ci.hotspot.HotSpotVMConfig.config;
 import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE;
 
+import java.util.AbstractList;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.stream.Collectors;
@@ -38,6 +40,7 @@
 import jdk.vm.ci.meta.JavaField;
 import jdk.vm.ci.meta.JavaMethod;
 import jdk.vm.ci.meta.JavaType;
+import jdk.vm.ci.meta.PrimitiveConstant;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
 import jdk.vm.ci.meta.Signature;
@@ -526,6 +529,60 @@ private int flags() {
         return UNSAFE.getInt(getConstantPoolPointer() + config().constantPoolFlagsOffset);
     }
 
+    /**
+     * Represents a list of static arguments from a {@link BootstrapMethodInvocation} of the form
+     * {{@code arg_count}, {@code pool_index}}, meaning the arguments are not already resolved
+     * and that the JDK has to lookup the arguments when they are needed. The {@code bssIndex}
+     * corresponds to {@code pool_index} and the {@code size} corresponds to {@code arg_count}.
+     */
+    static class CachedBSMArgs extends AbstractList<JavaConstant> {
+        private final JavaConstant[] cache;
+        private final HotSpotConstantPool cp;
+        private final int bssIndex;
+
+        CachedBSMArgs(HotSpotConstantPool cp, int bssIndex, int size) {
+            this.cp = cp;
+            this.bssIndex = bssIndex;
+            this.cache = new JavaConstant[size];
+        }
+
+        /**
+         * Lazily resolves and caches the argument at the given index and returns it. The method
+         * {@link CompilerToVM#bootstrapArgumentIndexAt} is used to obtain the constant pool
+         * index of the entry and the method {@link ConstantPool#lookupConstant} is used to
+         * resolve it. If the resolution failed, the index is returned as a
+         * {@link PrimitiveConstant}.
+         *
+         * @param index index of the element to return
+         * @return A {@link JavaConstant} corresponding to the static argument requested. A return
+         * value of type {@link PrimitiveConstant} represents an unresolved constant pool entry
+         */
+        @Override
+        public JavaConstant get(int index) {
+            JavaConstant res = cache[index];
+            if (res == null) {
+                int argCpi = compilerToVM().bootstrapArgumentIndexAt(cp, bssIndex, index);
+                Object object = cp.lookupConstant(argCpi, false);
+                if (object instanceof PrimitiveConstant primitiveConstant) {
+                    res = runtime().getReflection().boxPrimitive(primitiveConstant);
+                } else if (object instanceof JavaConstant javaConstant) {
+                    res = javaConstant;
+                } else if (object instanceof JavaType type) {
+                    res = runtime().getReflection().forObject(type);
+                } else {
+                    res = JavaConstant.forInt(argCpi);
+                }
+                cache[index] = res;
+            }
+            return res;
+        }
+
+        @Override
+        public int size() {
+            return cache.length;
+        }
+    }
+
     static class BootstrapMethodInvocationImpl implements BootstrapMethodInvocation {
         private final boolean indy;
         private final ResolvedJavaMethod method;
@@ -604,8 +661,9 @@ public BootstrapMethodInvocation lookupBootstrapMethodInvocation(int index, int
                     staticArgumentsList = List.of((JavaConstant[]) staticArguments);
                 } else {
                     int[] bsciArgs = (int[]) staticArguments;
-                    String message = String.format("Resolving bootstrap static arguments for %s using BootstrapCallInfo %s not supported", method.format("%H.%n(%p)"), Arrays.toString(bsciArgs));
-                    throw new IllegalArgumentException(message);
+                    int argCount = bsciArgs[0];
+                    int bss_index = bsciArgs[1];
+                    staticArgumentsList = new CachedBSMArgs(this, bss_index, argCount);
                 }
                 return new BootstrapMethodInvocationImpl(tag.name.equals("InvokeDynamic"), method, name, type, staticArgumentsList);
             default:
diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ConstantPool.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ConstantPool.java
index 5a53de47f6aeb..2273b256f0315 100644
--- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ConstantPool.java
+++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ConstantPool.java
@@ -131,7 +131,7 @@ default JavaMethod lookupMethod(int cpi, int opcode) {
 
     /**
      * The details for invoking a bootstrap method associated with a {@code CONSTANT_Dynamic_info}
-     * or {@code CONSTANT_InvokeDynamic_info} pool entry .
+     * or {@code CONSTANT_InvokeDynamic_info} pool entry.
      *
      * @jvms 4.4.10 The {@code CONSTANT_Dynamic_info} and {@code CONSTANT_InvokeDynamic_info}
      *       Structures
@@ -165,6 +165,29 @@ interface BootstrapMethodInvocation {
         /**
          * Gets the static arguments with which the bootstrap method will be invoked.
          *
+         * The {@linkplain JavaConstant#getJavaKind kind} of each argument will be
+         * {@link JavaKind#Object} or {@link JavaKind#Int}. The latter represents an
+         * unresolved {@code CONSTANT_Dynamic_info} entry. To resolve this entry, the
+         * corresponding bootstrap method has to be called first:
+         *
+         * <pre>
+         * List<JavaConstant> args = bmi.getStaticArguments();
+         * List<JavaConstant> resolvedArgs = new ArrayList<>(args.size());
+         * for (JavaConstant c : args) {
+         *     JavaConstant r = c;
+         *     if (c.getJavaKind() == JavaKind.Int) {
+         *         // If needed, access corresponding BootstrapMethodInvocation using
+         *         // cp.lookupBootstrapMethodInvocation(pc.asInt(), -1)
+         *         r = cp.lookupConstant(c.asInt(), true);
+         *     } else {
+         *         assert c.getJavaKind() == JavaKind.Object;
+         *     }
+         *     resolvedArgs.append(r);
+         * }
+         * </pre>
+         *
+         * The other types of entries are already resolved an can be used directly.
+         *
          * @jvms 5.4.3.6
          */
         List<JavaConstant> getStaticArguments();
@@ -182,8 +205,6 @@ interface BootstrapMethodInvocation {
      *            {@code index} was not decoded from a bytecode stream
      * @return the bootstrap method invocation details or {@code null} if the entry specified by {@code index}
      *         is not a {@code CONSTANT_Dynamic_info} or @{code CONSTANT_InvokeDynamic_info}
-     * @throws IllegalArgumentException if the bootstrap method invocation makes use of
-     *             {@code java.lang.invoke.BootstrapCallInfo}
      * @jvms 4.7.23 The {@code BootstrapMethods} Attribute
      */
     default BootstrapMethodInvocation lookupBootstrapMethodInvocation(int index, int opcode) {
diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestDynamicConstant.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestDynamicConstant.java
index c69c4e5a34556..32135e46bc1bf 100644
--- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestDynamicConstant.java
+++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestDynamicConstant.java
@@ -32,6 +32,9 @@
  * @run testng/othervm
  *      -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler
  *      jdk.vm.ci.hotspot.test.TestDynamicConstant
+ * @run testng/othervm
+ *      -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler -XX:UseBootstrapCallInfo=3
+ *      jdk.vm.ci.hotspot.test.TestDynamicConstant
  */
 
 package jdk.vm.ci.hotspot.test;
@@ -61,6 +64,7 @@
 import jdk.vm.ci.hotspot.HotSpotConstantPool;
 import jdk.vm.ci.meta.ConstantPool;
 import jdk.vm.ci.meta.ConstantPool.BootstrapMethodInvocation;
+import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.PrimitiveConstant;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -86,6 +90,12 @@ enum CondyType {
          */
         CALL_DIRECT_BSM,
 
+        /**
+         * Condy whose bootstrap method is one of the {@code TestDynamicConstant.get<type>BSM(<type> constant, int i)}
+         * methods with one condy arg and one int arg.
+         */
+        CALL_DIRECT_WITH_ARGS_BSM,
+
         /**
          * Condy whose bootstrap method is {@link ConstantBootstraps#invoke} that invokes one of the
          * {@code TestDynamicConstant.get<type>()} methods.
@@ -164,6 +174,24 @@ byte[] generateClassfile() {
                 run.visitInsn(type.getOpcode(IRETURN));
                 run.visitMaxs(0, 0);
                 run.visitEnd();
+             } else if (condyType == CondyType.CALL_DIRECT_WITH_ARGS_BSM) {
+                // Example: int TestDynamicConstant.getIntBSM(MethodHandles.Lookup l, String name,
+                // Class<?> type, int constant, int i)
+                String sig1 = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;)" + desc;
+                String sig2 = "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;" + desc + "I)" + desc;
+
+                Handle handle1 = new Handle(H_INVOKESTATIC, testClassInternalName, getter + "BSM", sig1, false);
+                Handle handle2 = new Handle(H_INVOKESTATIC, testClassInternalName, getter + "BSM", sig2, false);
+
+                ConstantDynamic condy1 = new ConstantDynamic("const1", desc, handle1);
+                ConstantDynamic condy2 = new ConstantDynamic("const2", desc, handle2, condy1, Integer.MAX_VALUE);
+
+                condy = condy2;
+                MethodVisitor run = cw.visitMethod(PUBLIC_STATIC, "run", "()" + desc, null, null);
+                run.visitLdcInsn(condy);
+                run.visitInsn(type.getOpcode(IRETURN));
+                run.visitMaxs(0, 0);
+                run.visitEnd();
             } else if (condyType == CondyType.CALL_INDIRECT_BSM) {
                 // Example: int TestDynamicConstant.getInt()
                 Handle handle = new Handle(H_INVOKESTATIC, testClassInternalName, getter, "()" + desc, false);
@@ -309,6 +337,12 @@ public void test() throws Throwable {
                 assertNoEagerConstantResolution(testClass, cp, getTagAt);
                 assertLookupBMIDoesNotInvokeBM(metaAccess, testClass);
 
+                if (type != Object.class) {
+                    testLookupBootstrapMethodInvocation(condyType, metaAccess, testClass, getTagAt);
+                } else {
+                    // StringConcatFactoryStringConcatFactory cannot accept null constants
+                }
+
                 Object lastConstant = null;
                 for (int cpi = 1; cpi < cp.length(); cpi++) {
                     String tag = String.valueOf(getTagAt.invoke(cp, cpi));
@@ -330,12 +364,6 @@ public void test() throws Throwable {
                     actual = ((HotSpotObjectConstant) lastConstant).asObject(type);
                 }
                 Assert.assertEquals(actual, expect, m + ":");
-
-                if (type != Object.class) {
-                    testLookupBootstrapMethodInvocation(condyType, metaAccess, testClass, getTagAt);
-                } else {
-                    // StringConcatFactoryStringConcatFactory cannot accept null constants
-                }
             }
         }
     }
@@ -364,10 +392,29 @@ private void testLookupBootstrapMethodInvocation(CondyType condyType, MetaAccess
                     Assert.assertTrue(expectedBSMs.contains(bsm), expectedBSMs.toString());
                 } else {
                     Assert.assertFalse(bsmi.isInvokeDynamic());
-                    if (condyType == CondyType.CALL_DIRECT_BSM) {
-                        Assert.assertTrue(bsm.startsWith("jdk.vm.ci.hotspot.test.TestDynamicConstant.get") && bsm.endsWith("BSM"), bsm);
-                    } else {
-                        Assert.assertEquals(bsm, "java.lang.invoke.ConstantBootstraps.invoke");
+                    checkBsmName(condyType, bsm);
+                    List<JavaConstant> staticArguments = bsmi.getStaticArguments();
+                    for (int i = 0; i < staticArguments.size(); ++i) {
+                        JavaConstant constant = staticArguments.get(i);
+                        if (constant instanceof PrimitiveConstant) {
+                            String innerTag = String.valueOf(getTagAt.invoke(cp, constant.asInt()));
+                            if (condyType == CondyType.CALL_DIRECT_WITH_ARGS_BSM) {
+                                Assert.assertEquals(i, 0);
+                                Assert.assertEquals(innerTag, "Dynamic");
+                            }
+                            if (innerTag.equals("Dynamic")) {
+                                BootstrapMethodInvocation innerBsmi = cp.lookupBootstrapMethodInvocation(constant.asInt(), -1);
+                                String innerBsm = innerBsmi.getMethod().format("%H.%n");
+                                checkBsmName(condyType, innerBsm);
+                            } else {
+                                Assert.assertEquals(innerTag, "MethodHandle");
+                            }
+                        } else {
+                            if (condyType == CondyType.CALL_DIRECT_WITH_ARGS_BSM) {
+                                Assert.assertEquals(i, 1);
+                            }
+                            Assert.assertTrue(staticArguments.get(i) instanceof HotSpotObjectConstant);
+                        }
                     }
                 }
             } else {
@@ -378,6 +425,14 @@ private void testLookupBootstrapMethodInvocation(CondyType condyType, MetaAccess
         testLoadReferencedType(concat, cp);
     }
 
+    private static void checkBsmName(CondyType condyType, String bsm) {
+        if (condyType == CondyType.CALL_DIRECT_BSM || condyType == CondyType.CALL_DIRECT_WITH_ARGS_BSM) {
+            Assert.assertTrue(bsm.startsWith("jdk.vm.ci.hotspot.test.TestDynamicConstant.get") && bsm.endsWith("BSM"), bsm);
+        } else {
+            Assert.assertEquals(bsm, "java.lang.invoke.ConstantBootstraps.invoke");
+        }
+    }
+
     private static int beS4(byte[] data, int bci) {
         return (data[bci] << 24) | ((data[bci + 1] & 0xff) << 16) | ((data[bci + 2] & 0xff) << 8) | (data[bci + 3] & 0xff);
     }
@@ -425,6 +480,18 @@ private static void testLoadReferencedType(ResolvedJavaMethod method, ConstantPo
     @SuppressWarnings("unused") public static Object  getObjectBSM (MethodHandles.Lookup l, String name, Class<?> type) { return null; }
     @SuppressWarnings("unused") public static List<?> getListBSM   (MethodHandles.Lookup l, String name, Class<?> type) { return List.of("element"); }
 
+    @SuppressWarnings("unused") public static boolean getBooleanBSM(MethodHandles.Lookup l, String name, Class<?> type, boolean constant, int i) { return true; }
+    @SuppressWarnings("unused") public static char    getCharBSM   (MethodHandles.Lookup l, String name, Class<?> type, char constant, int i) { return '*'; }
+    @SuppressWarnings("unused") public static short   getShortBSM  (MethodHandles.Lookup l, String name, Class<?> type, short constant, int i) { return Short.MAX_VALUE; }
+    @SuppressWarnings("unused") public static byte    getByteBSM   (MethodHandles.Lookup l, String name, Class<?> type, byte constant, int i) { return Byte.MAX_VALUE; }
+    @SuppressWarnings("unused") public static int     getIntBSM    (MethodHandles.Lookup l, String name, Class<?> type, int constant, int i) { return Integer.MAX_VALUE; }
+    @SuppressWarnings("unused") public static float   getFloatBSM  (MethodHandles.Lookup l, String name, Class<?> type, float constant, int i) { return Float.MAX_VALUE; }
+    @SuppressWarnings("unused") public static long    getLongBSM   (MethodHandles.Lookup l, String name, Class<?> type, long constant, int i) { return Long.MAX_VALUE; }
+    @SuppressWarnings("unused") public static double  getDoubleBSM (MethodHandles.Lookup l, String name, Class<?> type, double constant, int i) { return Double.MAX_VALUE; }
+    @SuppressWarnings("unused") public static String  getStringBSM (MethodHandles.Lookup l, String name, Class<?> type, String constant, int i) { return "a string"; }
+    @SuppressWarnings("unused") public static Object  getObjectBSM (MethodHandles.Lookup l, String name, Class<?> type, Object constant, int i) { return null; }
+    @SuppressWarnings("unused") public static List<?> getListBSM   (MethodHandles.Lookup l, String name, Class<?> type, List<?> constant, int i) { return List.of("element"); }
+
 
     public static boolean getBoolean() { return true; }
     public static char    getChar   () { return '*'; }