Exemplo n.º 1
0
 private static MethodHandle dropNameAndArgs(
     MethodHandle original, int index, int count, boolean block) {
   switch (count) {
     case -1:
       if (block) {
         return MethodHandles.dropArguments(
             original, index, String.class, IRubyObject[].class, Block.class);
       } else {
         return MethodHandles.dropArguments(original, index, String.class, IRubyObject[].class);
       }
     case 0:
       if (block) {
         return MethodHandles.dropArguments(original, index, String.class, Block.class);
       } else {
         return MethodHandles.dropArguments(original, index, String.class);
       }
     case 1:
       if (block) {
         return MethodHandles.dropArguments(
             original, index, String.class, IRubyObject.class, Block.class);
       } else {
         return MethodHandles.dropArguments(original, index, String.class, IRubyObject.class);
       }
     case 2:
       if (block) {
         return MethodHandles.dropArguments(
             original, index, String.class, IRubyObject.class, IRubyObject.class, Block.class);
       } else {
         return MethodHandles.dropArguments(
             original, index, String.class, IRubyObject.class, IRubyObject.class);
       }
     case 3:
       if (block) {
         return MethodHandles.dropArguments(
             original,
             index,
             String.class,
             IRubyObject.class,
             IRubyObject.class,
             IRubyObject.class,
             Block.class);
       } else {
         return MethodHandles.dropArguments(
             original,
             index,
             String.class,
             IRubyObject.class,
             IRubyObject.class,
             IRubyObject.class);
       }
     default:
       throw new RuntimeException(
           "Invalid arg count (" + count + ") while preparing method handle:\n\t" + original);
   }
 }
Exemplo n.º 2
0
 static {
   MethodHandle getMethod =
       MethodHandles.lookup()
           .findStatic(
               InvokeDynamicSupport.class,
               "getMethod",
               MethodType.make(DynamicMethod.class, CacheEntry.class));
   getMethod = MethodHandles.dropArguments(getMethod, 0, RubyClass.class);
   getMethod =
       MethodHandles.dropArguments(
           getMethod, 2, ThreadContext.class, IRubyObject.class, IRubyObject.class);
   GETMETHOD = getMethod;
 }
Exemplo n.º 3
0
public class InvokeDynamicSupport {
  public static class JRubyCallSite extends CallSite {
    private final CallType callType;

    public JRubyCallSite(Class caller, String name, MethodType type, CallType callType) {
      super(caller, name, type);
      this.callType = callType;
    }

    public CallType callType() {
      return callType;
    }
  }

  public static CallSite bootstrap(Class caller, String name, MethodType type) {
    JRubyCallSite site;

    if (name == "call") {
      site = new JRubyCallSite(caller, name, type, CallType.NORMAL);
    } else {
      site = new JRubyCallSite(caller, name, type, CallType.FUNCTIONAL);
    }

    MethodType fallbackType = type.insertParameterType(0, JRubyCallSite.class);
    MethodHandle myFallback =
        MethodHandles.insertArguments(
            MethodHandles.lookup().findStatic(InvokeDynamicSupport.class, "fallback", fallbackType),
            0,
            site);
    site.setTarget(myFallback);
    return site;
  }

  public static void registerBootstrap(Class cls) {
    Linkage.registerBootstrapMethod(cls, BOOTSTRAP);
  }

  public static void installBytecode(MethodVisitor method, String classname) {
    SkinnyMethodAdapter mv = new SkinnyMethodAdapter(method);
    mv.ldc(c(classname));
    mv.invokestatic(p(Class.class), "forName", sig(Class.class, params(String.class)));
    mv.invokestatic(
        p(InvokeDynamicSupport.class), "registerBootstrap", sig(void.class, Class.class));
  }

  private static MethodHandle createGWT(
      MethodHandle test,
      MethodHandle target,
      MethodHandle fallback,
      CacheEntry entry,
      CallSite site) {
    MethodHandle myTest = MethodHandles.insertArguments(test, 0, entry);
    MethodHandle myTarget = MethodHandles.insertArguments(target, 0, entry);
    MethodHandle myFallback = MethodHandles.insertArguments(fallback, 0, site);
    MethodHandle guardWithTest = MethodHandles.guardWithTest(myTest, myTarget, myFallback);

    return MethodHandles.convertArguments(guardWithTest, site.type());
  }

  public static boolean test(CacheEntry entry, IRubyObject self) {
    return entry.typeOk(self.getMetaClass());
  }

  public static IRubyObject fallback(
      JRubyCallSite site,
      ThreadContext context,
      IRubyObject caller,
      IRubyObject self,
      String name) {
    RubyClass selfClass = pollAndGetClass(context, self);
    CacheEntry entry = selfClass.searchWithCache(name);
    if (methodMissing(entry, site.callType(), name, caller)) {
      return callMethodMissing(entry, site.callType(), context, self, name);
    }
    site.setTarget(createGWT(TEST_0, TARGET_0, FALLBACK_0, entry, site));

    return entry.method.call(context, self, selfClass, name);
  }

  public static IRubyObject fallback(
      JRubyCallSite site,
      ThreadContext context,
      IRubyObject caller,
      IRubyObject self,
      String name,
      IRubyObject arg0) {
    RubyClass selfClass = pollAndGetClass(context, self);
    CacheEntry entry = selfClass.searchWithCache(name);
    if (methodMissing(entry, site.callType(), name, caller)) {
      return callMethodMissing(entry, site.callType(), context, self, name, arg0);
    }
    site.setTarget(createGWT(TEST_1, TARGET_1, FALLBACK_1, entry, site));

    return entry.method.call(context, self, selfClass, name, arg0);
  }

  public static IRubyObject fallback(
      JRubyCallSite site,
      ThreadContext context,
      IRubyObject caller,
      IRubyObject self,
      String name,
      IRubyObject arg0,
      IRubyObject arg1) {
    RubyClass selfClass = pollAndGetClass(context, self);
    CacheEntry entry = selfClass.searchWithCache(name);
    if (methodMissing(entry, site.callType(), name, caller)) {
      return callMethodMissing(entry, site.callType(), context, self, name, arg0, arg1);
    }
    site.setTarget(createGWT(TEST_2, TARGET_2, FALLBACK_2, entry, site));

    return entry.method.call(context, self, selfClass, name, arg0, arg1);
  }

  public static IRubyObject fallback(
      JRubyCallSite site,
      ThreadContext context,
      IRubyObject caller,
      IRubyObject self,
      String name,
      IRubyObject arg0,
      IRubyObject arg1,
      IRubyObject arg2) {
    RubyClass selfClass = pollAndGetClass(context, self);
    CacheEntry entry = selfClass.searchWithCache(name);
    if (methodMissing(entry, site.callType(), name, caller)) {
      return callMethodMissing(entry, site.callType(), context, self, name, arg0, arg1, arg2);
    }
    site.setTarget(createGWT(TEST_3, TARGET_3, FALLBACK_3, entry, site));

    return entry.method.call(context, self, selfClass, name, arg0, arg1, arg2);
  }

  public static IRubyObject fallback(
      JRubyCallSite site,
      ThreadContext context,
      IRubyObject caller,
      IRubyObject self,
      String name,
      IRubyObject[] args) {
    RubyClass selfClass = pollAndGetClass(context, self);
    CacheEntry entry = selfClass.searchWithCache(name);
    if (methodMissing(entry, site.callType(), name, caller)) {
      return callMethodMissing(entry, site.callType(), context, self, name, args);
    }
    site.setTarget(createGWT(TEST_N, TARGET_N, FALLBACK_N, entry, site));

    return entry.method.call(context, self, selfClass, name, args);
  }

  public static IRubyObject fallback(
      JRubyCallSite site,
      ThreadContext context,
      IRubyObject caller,
      IRubyObject self,
      String name,
      Block block) {
    RubyClass selfClass = pollAndGetClass(context, self);
    CacheEntry entry = selfClass.searchWithCache(name);

    try {
      if (methodMissing(entry, site.callType(), name, caller)) {
        return callMethodMissing(entry, site.callType(), context, self, name, block);
      }
      site.setTarget(createGWT(TEST_0_B, TARGET_0_B, FALLBACK_0_B, entry, site));
      return entry.method.call(context, self, selfClass, name, block);
    } catch (JumpException.BreakJump bj) {
      return handleBreakJump(context, bj);
    } catch (JumpException.RetryJump rj) {
      return retryJumpError(context);
    } finally {
      block.escape();
    }
  }

  public static IRubyObject fallback(
      JRubyCallSite site,
      ThreadContext context,
      IRubyObject caller,
      IRubyObject self,
      String name,
      IRubyObject arg0,
      Block block) {
    RubyClass selfClass = pollAndGetClass(context, self);
    CacheEntry entry = selfClass.searchWithCache(name);

    try {
      if (methodMissing(entry, site.callType(), name, caller)) {
        return callMethodMissing(entry, site.callType(), context, self, name, arg0, block);
      }
      site.setTarget(createGWT(TEST_1_B, TARGET_1_B, FALLBACK_1_B, entry, site));
      return entry.method.call(context, self, selfClass, name, arg0, block);
    } catch (JumpException.BreakJump bj) {
      return handleBreakJump(context, bj);
    } catch (JumpException.RetryJump rj) {
      return retryJumpError(context);
    } finally {
      block.escape();
    }
  }

  public static IRubyObject fallback(
      JRubyCallSite site,
      ThreadContext context,
      IRubyObject caller,
      IRubyObject self,
      String name,
      IRubyObject arg0,
      IRubyObject arg1,
      Block block) {
    RubyClass selfClass = pollAndGetClass(context, self);
    CacheEntry entry = selfClass.searchWithCache(name);

    try {
      if (methodMissing(entry, site.callType(), name, caller)) {
        return callMethodMissing(entry, site.callType(), context, self, name, arg0, arg1, block);
      }
      site.setTarget(createGWT(TEST_2_B, TARGET_2_B, FALLBACK_2_B, entry, site));
      return entry.method.call(context, self, selfClass, name, arg0, arg1, block);
    } catch (JumpException.BreakJump bj) {
      return handleBreakJump(context, bj);
    } catch (JumpException.RetryJump rj) {
      return retryJumpError(context);
    } finally {
      block.escape();
    }
  }

  public static IRubyObject fallback(
      JRubyCallSite site,
      ThreadContext context,
      IRubyObject caller,
      IRubyObject self,
      String name,
      IRubyObject arg0,
      IRubyObject arg1,
      IRubyObject arg2,
      Block block) {
    RubyClass selfClass = pollAndGetClass(context, self);
    CacheEntry entry = selfClass.searchWithCache(name);

    try {
      if (methodMissing(entry, site.callType(), name, caller)) {
        return callMethodMissing(
            entry, site.callType(), context, self, name, arg0, arg1, arg2, block);
      }
      site.setTarget(createGWT(TEST_3_B, TARGET_3_B, FALLBACK_3_B, entry, site));
      return entry.method.call(context, self, selfClass, name, arg0, arg1, arg2, block);
    } catch (JumpException.BreakJump bj) {
      return handleBreakJump(context, bj);
    } catch (JumpException.RetryJump rj) {
      return retryJumpError(context);
    } finally {
      block.escape();
    }
  }

  public static IRubyObject fallback(
      JRubyCallSite site,
      ThreadContext context,
      IRubyObject caller,
      IRubyObject self,
      String name,
      IRubyObject[] args,
      Block block) {
    RubyClass selfClass = pollAndGetClass(context, self);
    CacheEntry entry = selfClass.searchWithCache(name);

    try {
      if (methodMissing(entry, site.callType(), name, caller)) {
        return callMethodMissing(entry, site.callType(), context, self, name, args, block);
      }
      site.setTarget(createGWT(TEST_N_B, TARGET_N_B, FALLBACK_N_B, entry, site));
      return entry.method.call(context, self, selfClass, name, args, block);
    } catch (JumpException.BreakJump bj) {
      return handleBreakJump(context, bj);
    } catch (JumpException.RetryJump rj) {
      return retryJumpError(context);
    } finally {
      block.escape();
    }
  }

  protected static boolean methodMissing(
      CacheEntry entry, CallType callType, String name, IRubyObject caller) {
    DynamicMethod method = entry.method;
    return method.isUndefined()
        || (callType == CallType.NORMAL
            && !name.equals("method_missing")
            && !method.isCallableFrom(caller, callType));
  }

  private static IRubyObject callMethodMissing(
      CacheEntry entry,
      CallType callType,
      ThreadContext context,
      IRubyObject self,
      String name,
      IRubyObject[] args) {
    return RuntimeHelpers.selectMethodMissing(
            context, self, entry.method.getVisibility(), name, callType)
        .call(context, self, self.getMetaClass(), name, args, Block.NULL_BLOCK);
  }

  private static IRubyObject callMethodMissing(
      CacheEntry entry, CallType callType, ThreadContext context, IRubyObject self, String name) {
    return RuntimeHelpers.selectMethodMissing(
            context, self, entry.method.getVisibility(), name, callType)
        .call(context, self, self.getMetaClass(), name, Block.NULL_BLOCK);
  }

  private static IRubyObject callMethodMissing(
      CacheEntry entry,
      CallType callType,
      ThreadContext context,
      IRubyObject self,
      String name,
      Block block) {
    return RuntimeHelpers.selectMethodMissing(
            context, self, entry.method.getVisibility(), name, callType)
        .call(context, self, self.getMetaClass(), name, block);
  }

  private static IRubyObject callMethodMissing(
      CacheEntry entry,
      CallType callType,
      ThreadContext context,
      IRubyObject self,
      String name,
      IRubyObject arg) {
    return RuntimeHelpers.selectMethodMissing(
            context, self, entry.method.getVisibility(), name, callType)
        .call(context, self, self.getMetaClass(), name, arg, Block.NULL_BLOCK);
  }

  private static IRubyObject callMethodMissing(
      CacheEntry entry,
      CallType callType,
      ThreadContext context,
      IRubyObject self,
      String name,
      IRubyObject[] args,
      Block block) {
    return RuntimeHelpers.selectMethodMissing(
            context, self, entry.method.getVisibility(), name, callType)
        .call(context, self, self.getMetaClass(), name, args, block);
  }

  private static IRubyObject callMethodMissing(
      CacheEntry entry,
      CallType callType,
      ThreadContext context,
      IRubyObject self,
      String name,
      IRubyObject arg0,
      Block block) {
    return RuntimeHelpers.selectMethodMissing(
            context, self, entry.method.getVisibility(), name, callType)
        .call(context, self, self.getMetaClass(), name, arg0, block);
  }

  private static IRubyObject callMethodMissing(
      CacheEntry entry,
      CallType callType,
      ThreadContext context,
      IRubyObject self,
      String name,
      IRubyObject arg0,
      IRubyObject arg1) {
    return RuntimeHelpers.selectMethodMissing(
            context, self, entry.method.getVisibility(), name, callType)
        .call(context, self, self.getMetaClass(), name, arg0, arg1, Block.NULL_BLOCK);
  }

  private static IRubyObject callMethodMissing(
      CacheEntry entry,
      CallType callType,
      ThreadContext context,
      IRubyObject self,
      String name,
      IRubyObject arg0,
      IRubyObject arg1,
      Block block) {
    return RuntimeHelpers.selectMethodMissing(
            context, self, entry.method.getVisibility(), name, callType)
        .call(context, self, self.getMetaClass(), name, arg0, arg1, block);
  }

  private static IRubyObject callMethodMissing(
      CacheEntry entry,
      CallType callType,
      ThreadContext context,
      IRubyObject self,
      String name,
      IRubyObject arg0,
      IRubyObject arg1,
      IRubyObject arg2) {
    return RuntimeHelpers.selectMethodMissing(
            context, self, entry.method.getVisibility(), name, callType)
        .call(context, self, self.getMetaClass(), name, arg0, arg1, arg2, Block.NULL_BLOCK);
  }

  private static IRubyObject callMethodMissing(
      CacheEntry entry,
      CallType callType,
      ThreadContext context,
      IRubyObject self,
      String name,
      IRubyObject arg0,
      IRubyObject arg1,
      IRubyObject arg2,
      Block block) {
    return RuntimeHelpers.selectMethodMissing(
            context, self, entry.method.getVisibility(), name, callType)
        .call(context, self, self.getMetaClass(), name, arg0, arg1, arg2, block);
  }

  public static RubyClass pollAndGetClass(ThreadContext context, IRubyObject self) {
    context.callThreadPoll();
    RubyClass selfType = self.getMetaClass();
    return selfType;
  }

  public static IRubyObject handleBreakJump(JumpException.BreakJump bj, ThreadContext context)
      throws JumpException.BreakJump {
    if (context.getFrameJumpTarget() == bj.getTarget()) {
      return (IRubyObject) bj.getValue();
    }
    throw bj;
  }

  private static IRubyObject handleBreakJump(ThreadContext context, JumpException.BreakJump bj)
      throws JumpException.BreakJump {
    if (context.getFrameJumpTarget() == bj.getTarget()) {
      return (IRubyObject) bj.getValue();
    }
    throw bj;
  }

  public static IRubyObject retryJumpError(ThreadContext context) {
    throw context
        .getRuntime()
        .newLocalJumpError(
            RubyLocalJumpError.Reason.RETRY,
            context.getRuntime().getNil(),
            "retry outside of rescue not supported");
  }

  private static final MethodType BOOTSTRAP_TYPE =
      MethodType.make(CallSite.class, Class.class, String.class, MethodType.class);
  private static final MethodHandle BOOTSTRAP =
      MethodHandles.lookup().findStatic(InvokeDynamicSupport.class, "bootstrap", BOOTSTRAP_TYPE);

  private static final MethodHandle GETMETHOD;

  static {
    MethodHandle getMethod =
        MethodHandles.lookup()
            .findStatic(
                InvokeDynamicSupport.class,
                "getMethod",
                MethodType.make(DynamicMethod.class, CacheEntry.class));
    getMethod = MethodHandles.dropArguments(getMethod, 0, RubyClass.class);
    getMethod =
        MethodHandles.dropArguments(
            getMethod, 2, ThreadContext.class, IRubyObject.class, IRubyObject.class);
    GETMETHOD = getMethod;
  }

  public static final DynamicMethod getMethod(CacheEntry entry) {
    return entry.method;
  }

  private static final MethodHandle PGC =
      MethodHandles.dropArguments(
          MethodHandles.dropArguments(
              MethodHandles.lookup()
                  .findStatic(
                      InvokeDynamicSupport.class,
                      "pollAndGetClass",
                      MethodType.make(RubyClass.class, ThreadContext.class, IRubyObject.class)),
              1,
              IRubyObject.class),
          0,
          CacheEntry.class);

  private static final MethodHandle TEST =
      MethodHandles.dropArguments(
          MethodHandles.lookup()
              .findStatic(
                  InvokeDynamicSupport.class,
                  "test",
                  MethodType.make(boolean.class, CacheEntry.class, IRubyObject.class)),
          1,
          ThreadContext.class,
          IRubyObject.class);

  private static MethodHandle dropNameAndArgs(
      MethodHandle original, int index, int count, boolean block) {
    switch (count) {
      case -1:
        if (block) {
          return MethodHandles.dropArguments(
              original, index, String.class, IRubyObject[].class, Block.class);
        } else {
          return MethodHandles.dropArguments(original, index, String.class, IRubyObject[].class);
        }
      case 0:
        if (block) {
          return MethodHandles.dropArguments(original, index, String.class, Block.class);
        } else {
          return MethodHandles.dropArguments(original, index, String.class);
        }
      case 1:
        if (block) {
          return MethodHandles.dropArguments(
              original, index, String.class, IRubyObject.class, Block.class);
        } else {
          return MethodHandles.dropArguments(original, index, String.class, IRubyObject.class);
        }
      case 2:
        if (block) {
          return MethodHandles.dropArguments(
              original, index, String.class, IRubyObject.class, IRubyObject.class, Block.class);
        } else {
          return MethodHandles.dropArguments(
              original, index, String.class, IRubyObject.class, IRubyObject.class);
        }
      case 3:
        if (block) {
          return MethodHandles.dropArguments(
              original,
              index,
              String.class,
              IRubyObject.class,
              IRubyObject.class,
              IRubyObject.class,
              Block.class);
        } else {
          return MethodHandles.dropArguments(
              original,
              index,
              String.class,
              IRubyObject.class,
              IRubyObject.class,
              IRubyObject.class);
        }
      default:
        throw new RuntimeException(
            "Invalid arg count (" + count + ") while preparing method handle:\n\t" + original);
    }
  }

  private static final MethodHandle PGC_0 = dropNameAndArgs(PGC, 4, 0, false);
  private static final MethodHandle GETMETHOD_0 = dropNameAndArgs(GETMETHOD, 5, 0, false);
  private static final MethodHandle TEST_0 = dropNameAndArgs(TEST, 4, 0, false);
  private static final MethodHandle TARGET_0;

  static {
    MethodHandle target =
        MethodHandles.lookup()
            .findVirtual(
                DynamicMethod.class,
                "call",
                MethodType.make(
                    IRubyObject.class,
                    ThreadContext.class,
                    IRubyObject.class,
                    RubyModule.class,
                    String.class));
    target =
        MethodHandles.convertArguments(
            target,
            MethodType.make(
                IRubyObject.class,
                DynamicMethod.class,
                ThreadContext.class,
                IRubyObject.class,
                RubyClass.class,
                String.class));
    target =
        MethodHandles.permuteArguments(
            target,
            MethodType.make(
                IRubyObject.class,
                DynamicMethod.class,
                RubyClass.class,
                CacheEntry.class,
                ThreadContext.class,
                IRubyObject.class,
                IRubyObject.class,
                String.class),
            new int[] {0, 3, 5, 1, 6});
    // IRubyObject, DynamicMethod, RubyClass, CacheEntry, ThreadContext, IRubyObject, IRubyObject,
    // String
    target = MethodHandles.foldArguments(target, GETMETHOD_0);
    // IRubyObject, RubyClass, CacheEntry, ThreadContext, IRubyObject, IRubyObject, String
    target = MethodHandles.foldArguments(target, PGC_0);
    // IRubyObject, CacheEntry, ThreadContext, IRubyObject, IRubyObject, String
    TARGET_0 = target;
  }

  private static final MethodHandle FALLBACK_0 =
      MethodHandles.lookup()
          .findStatic(
              InvokeDynamicSupport.class,
              "fallback",
              MethodType.make(
                  IRubyObject.class,
                  JRubyCallSite.class,
                  ThreadContext.class,
                  IRubyObject.class,
                  IRubyObject.class,
                  String.class));

  private static final MethodHandle PGC_1 = dropNameAndArgs(PGC, 4, 1, false);
  private static final MethodHandle GETMETHOD_1 = dropNameAndArgs(GETMETHOD, 5, 1, false);
  private static final MethodHandle TEST_1 = dropNameAndArgs(TEST, 4, 1, false);
  private static final MethodHandle TARGET_1;

  static {
    MethodHandle target =
        MethodHandles.lookup()
            .findVirtual(
                DynamicMethod.class,
                "call",
                MethodType.make(
                    IRubyObject.class,
                    ThreadContext.class,
                    IRubyObject.class,
                    RubyModule.class,
                    String.class,
                    IRubyObject.class));
    // IRubyObject, DynamicMethod, ThreadContext, IRubyObject, RubyModule, String, IRubyObject
    target =
        MethodHandles.convertArguments(
            target,
            MethodType.make(
                IRubyObject.class,
                DynamicMethod.class,
                ThreadContext.class,
                IRubyObject.class,
                RubyClass.class,
                String.class,
                IRubyObject.class));
    // IRubyObject, DynamicMethod, ThreadContext, IRubyObject, RubyClass, String, IRubyObject
    target =
        MethodHandles.permuteArguments(
            target,
            MethodType.make(
                IRubyObject.class,
                DynamicMethod.class,
                RubyClass.class,
                CacheEntry.class,
                ThreadContext.class,
                IRubyObject.class,
                IRubyObject.class,
                String.class,
                IRubyObject.class),
            new int[] {0, 3, 5, 1, 6, 7});
    // IRubyObject, DynamicMethod, RubyClass, CacheEntry, ThreadContext, IRubyObject, IRubyObject,
    // String, IRubyObject
    target = MethodHandles.foldArguments(target, GETMETHOD_1);
    // IRubyObject, RubyClass, CacheEntry, ThreadContext, IRubyObject, IRubyObject, String,
    // IRubyObject
    target = MethodHandles.foldArguments(target, PGC_1);
    // IRubyObject, CacheEntry, ThreadContext, IRubyObject, IRubyObject, String, IRubyObject
    TARGET_1 = target;
  }

  private static final MethodHandle FALLBACK_1 =
      MethodHandles.lookup()
          .findStatic(
              InvokeDynamicSupport.class,
              "fallback",
              MethodType.make(
                  IRubyObject.class,
                  JRubyCallSite.class,
                  ThreadContext.class,
                  IRubyObject.class,
                  IRubyObject.class,
                  String.class,
                  IRubyObject.class));

  private static final MethodHandle PGC_2 = dropNameAndArgs(PGC, 4, 2, false);
  private static final MethodHandle GETMETHOD_2 = dropNameAndArgs(GETMETHOD, 5, 2, false);
  private static final MethodHandle TEST_2 = dropNameAndArgs(TEST, 4, 2, false);
  private static final MethodHandle TARGET_2;

  static {
    MethodHandle target =
        MethodHandles.lookup()
            .findVirtual(
                DynamicMethod.class,
                "call",
                MethodType.make(
                    IRubyObject.class,
                    ThreadContext.class,
                    IRubyObject.class,
                    RubyModule.class,
                    String.class,
                    IRubyObject.class,
                    IRubyObject.class));
    target =
        MethodHandles.convertArguments(
            target,
            MethodType.make(
                IRubyObject.class,
                DynamicMethod.class,
                ThreadContext.class,
                IRubyObject.class,
                RubyClass.class,
                String.class,
                IRubyObject.class,
                IRubyObject.class));
    target =
        MethodHandles.permuteArguments(
            target,
            MethodType.make(
                IRubyObject.class,
                DynamicMethod.class,
                RubyClass.class,
                CacheEntry.class,
                ThreadContext.class,
                IRubyObject.class,
                IRubyObject.class,
                String.class,
                IRubyObject.class,
                IRubyObject.class),
            new int[] {0, 3, 5, 1, 6, 7, 8});
    // IRubyObject, DynamicMethod, RubyClass, CacheEntry, ThreadContext, IRubyObject, IRubyObject,
    // String, args
    target = MethodHandles.foldArguments(target, GETMETHOD_2);
    // IRubyObject, RubyClass, CacheEntry, ThreadContext, IRubyObject, IRubyObject, String, args
    target = MethodHandles.foldArguments(target, PGC_2);
    // IRubyObject, CacheEntry, ThreadContext, IRubyObject, IRubyObject, String, args
    TARGET_2 = target;
  }

  private static final MethodHandle FALLBACK_2 =
      MethodHandles.lookup()
          .findStatic(
              InvokeDynamicSupport.class,
              "fallback",
              MethodType.make(
                  IRubyObject.class,
                  JRubyCallSite.class,
                  ThreadContext.class,
                  IRubyObject.class,
                  IRubyObject.class,
                  String.class,
                  IRubyObject.class,
                  IRubyObject.class));

  private static final MethodHandle PGC_3 = dropNameAndArgs(PGC, 4, 3, false);
  private static final MethodHandle GETMETHOD_3 = dropNameAndArgs(GETMETHOD, 5, 3, false);
  private static final MethodHandle TEST_3 = dropNameAndArgs(TEST, 4, 3, false);
  private static final MethodHandle TARGET_3;

  static {
    MethodHandle target =
        MethodHandles.lookup()
            .findVirtual(
                DynamicMethod.class,
                "call",
                MethodType.make(
                    IRubyObject.class,
                    ThreadContext.class,
                    IRubyObject.class,
                    RubyModule.class,
                    String.class,
                    IRubyObject.class,
                    IRubyObject.class,
                    IRubyObject.class));
    target =
        MethodHandles.convertArguments(
            target,
            MethodType.make(
                IRubyObject.class,
                DynamicMethod.class,
                ThreadContext.class,
                IRubyObject.class,
                RubyClass.class,
                String.class,
                IRubyObject.class,
                IRubyObject.class,
                IRubyObject.class));
    target =
        MethodHandles.permuteArguments(
            target,
            MethodType.make(
                IRubyObject.class,
                DynamicMethod.class,
                RubyClass.class,
                CacheEntry.class,
                ThreadContext.class,
                IRubyObject.class,
                IRubyObject.class,
                String.class,
                IRubyObject.class,
                IRubyObject.class,
                IRubyObject.class),
            new int[] {0, 3, 5, 1, 6, 7, 8, 9});
    // IRubyObject, DynamicMethod, RubyClass, CacheEntry, ThreadContext, IRubyObject, IRubyObject,
    // String, args
    target = MethodHandles.foldArguments(target, GETMETHOD_3);
    // IRubyObject, RubyClass, CacheEntry, ThreadContext, IRubyObject, IRubyObject, String, args
    target = MethodHandles.foldArguments(target, PGC_3);
    // IRubyObject, CacheEntry, ThreadContext, IRubyObject, IRubyObject, String, args
    TARGET_3 = target;
  }

  private static final MethodHandle FALLBACK_3 =
      MethodHandles.lookup()
          .findStatic(
              InvokeDynamicSupport.class,
              "fallback",
              MethodType.make(
                  IRubyObject.class,
                  JRubyCallSite.class,
                  ThreadContext.class,
                  IRubyObject.class,
                  IRubyObject.class,
                  String.class,
                  IRubyObject.class,
                  IRubyObject.class,
                  IRubyObject.class));

  private static final MethodHandle PGC_N = dropNameAndArgs(PGC, 4, -1, false);
  private static final MethodHandle GETMETHOD_N = dropNameAndArgs(GETMETHOD, 5, -1, false);
  private static final MethodHandle TEST_N = dropNameAndArgs(TEST, 4, -1, false);
  private static final MethodHandle TARGET_N;

  static {
    MethodHandle target =
        MethodHandles.lookup()
            .findVirtual(
                DynamicMethod.class,
                "call",
                MethodType.make(
                    IRubyObject.class,
                    ThreadContext.class,
                    IRubyObject.class,
                    RubyModule.class,
                    String.class,
                    IRubyObject[].class));
    target =
        MethodHandles.convertArguments(
            target,
            MethodType.make(
                IRubyObject.class,
                DynamicMethod.class,
                ThreadContext.class,
                IRubyObject.class,
                RubyClass.class,
                String.class,
                IRubyObject[].class));
    target =
        MethodHandles.permuteArguments(
            target,
            MethodType.make(
                IRubyObject.class,
                DynamicMethod.class,
                RubyClass.class,
                CacheEntry.class,
                ThreadContext.class,
                IRubyObject.class,
                IRubyObject.class,
                String.class,
                IRubyObject[].class),
            new int[] {0, 3, 5, 1, 6, 7});
    // IRubyObject, DynamicMethod, RubyClass, CacheEntry, ThreadContext, IRubyObject, IRubyObject,
    // String, args
    target = MethodHandles.foldArguments(target, GETMETHOD_N);
    // IRubyObject, RubyClass, CacheEntry, ThreadContext, IRubyObject, IRubyObject, String, args
    target = MethodHandles.foldArguments(target, PGC_N);
    // IRubyObject, CacheEntry, ThreadContext, IRubyObject, IRubyObject, String, args
    TARGET_N = target;
  }

  private static final MethodHandle FALLBACK_N =
      MethodHandles.lookup()
          .findStatic(
              InvokeDynamicSupport.class,
              "fallback",
              MethodType.make(
                  IRubyObject.class,
                  JRubyCallSite.class,
                  ThreadContext.class,
                  IRubyObject.class,
                  IRubyObject.class,
                  String.class,
                  IRubyObject[].class));

  private static final MethodHandle BREAKJUMP;

  static {
    MethodHandle breakJump =
        MethodHandles.lookup()
            .findStatic(
                InvokeDynamicSupport.class,
                "handleBreakJump",
                MethodType.make(
                    IRubyObject.class, JumpException.BreakJump.class, ThreadContext.class));
    // BreakJump, ThreadContext
    breakJump =
        MethodHandles.permuteArguments(
            breakJump,
            MethodType.make(
                IRubyObject.class,
                JumpException.BreakJump.class,
                CacheEntry.class,
                ThreadContext.class,
                IRubyObject.class,
                IRubyObject.class),
            new int[] {0, 2});
    // BreakJump, CacheEntry, ThreadContext, IRubyObject, IRubyObject
    BREAKJUMP = breakJump;
  }

  private static final MethodHandle RETRYJUMP;

  static {
    MethodHandle retryJump =
        MethodHandles.lookup()
            .findStatic(
                InvokeDynamicSupport.class,
                "retryJumpError",
                MethodType.make(IRubyObject.class, ThreadContext.class));
    // ThreadContext
    retryJump =
        MethodHandles.permuteArguments(
            retryJump,
            MethodType.make(
                IRubyObject.class,
                JumpException.RetryJump.class,
                CacheEntry.class,
                ThreadContext.class,
                IRubyObject.class,
                IRubyObject.class),
            new int[] {2});
    // RetryJump, CacheEntry, ThreadContext, IRubyObject, IRubyObject
    RETRYJUMP = retryJump;
  }

  private static final MethodHandle PGC_0_B = dropNameAndArgs(PGC, 4, 0, true);
  private static final MethodHandle GETMETHOD_0_B = dropNameAndArgs(GETMETHOD, 5, 0, true);
  private static final MethodHandle TEST_0_B = dropNameAndArgs(TEST, 4, 0, true);
  private static final MethodHandle TARGET_0_B;

  static {
    MethodHandle target =
        MethodHandles.lookup()
            .findVirtual(
                DynamicMethod.class,
                "call",
                MethodType.make(
                    IRubyObject.class,
                    ThreadContext.class,
                    IRubyObject.class,
                    RubyModule.class,
                    String.class,
                    Block.class));
    target =
        MethodHandles.convertArguments(
            target,
            MethodType.make(
                IRubyObject.class,
                DynamicMethod.class,
                ThreadContext.class,
                IRubyObject.class,
                RubyClass.class,
                String.class,
                Block.class));
    target =
        MethodHandles.permuteArguments(
            target,
            MethodType.make(
                IRubyObject.class,
                DynamicMethod.class,
                RubyClass.class,
                CacheEntry.class,
                ThreadContext.class,
                IRubyObject.class,
                IRubyObject.class,
                String.class,
                Block.class),
            new int[] {0, 3, 5, 1, 6, 7});
    // IRubyObject, DynamicMethod, RubyClass, CacheEntry, ThreadContext, IRubyObject, IRubyObject,
    // String, args
    target = MethodHandles.foldArguments(target, GETMETHOD_0_B);
    // IRubyObject, RubyClass, CacheEntry, ThreadContext, IRubyObject, IRubyObject, String, args
    target = MethodHandles.foldArguments(target, PGC_0_B);
    // IRubyObject, CacheEntry, ThreadContext, IRubyObject, IRubyObject, String, args

    MethodHandle breakJump = dropNameAndArgs(BREAKJUMP, 5, 0, true);
    MethodHandle retryJump = dropNameAndArgs(RETRYJUMP, 5, 0, true);
    target = MethodHandles.catchException(target, JumpException.BreakJump.class, breakJump);
    target = MethodHandles.catchException(target, JumpException.RetryJump.class, retryJump);

    TARGET_0_B = target;
  }

  private static final MethodHandle FALLBACK_0_B =
      MethodHandles.lookup()
          .findStatic(
              InvokeDynamicSupport.class,
              "fallback",
              MethodType.make(
                  IRubyObject.class,
                  JRubyCallSite.class,
                  ThreadContext.class,
                  IRubyObject.class,
                  IRubyObject.class,
                  String.class,
                  Block.class));

  private static final MethodHandle PGC_1_B = dropNameAndArgs(PGC, 4, 1, true);
  private static final MethodHandle GETMETHOD_1_B = dropNameAndArgs(GETMETHOD, 5, 1, true);
  private static final MethodHandle TEST_1_B = dropNameAndArgs(TEST, 4, 1, true);
  private static final MethodHandle TARGET_1_B;

  static {
    MethodHandle target =
        MethodHandles.lookup()
            .findVirtual(
                DynamicMethod.class,
                "call",
                MethodType.make(
                    IRubyObject.class,
                    ThreadContext.class,
                    IRubyObject.class,
                    RubyModule.class,
                    String.class,
                    IRubyObject.class,
                    Block.class));
    target =
        MethodHandles.convertArguments(
            target,
            MethodType.make(
                IRubyObject.class,
                DynamicMethod.class,
                ThreadContext.class,
                IRubyObject.class,
                RubyClass.class,
                String.class,
                IRubyObject.class,
                Block.class));
    target =
        MethodHandles.permuteArguments(
            target,
            MethodType.make(
                IRubyObject.class,
                DynamicMethod.class,
                RubyClass.class,
                CacheEntry.class,
                ThreadContext.class,
                IRubyObject.class,
                IRubyObject.class,
                String.class,
                IRubyObject.class,
                Block.class),
            new int[] {0, 3, 5, 1, 6, 7, 8});
    // IRubyObject, DynamicMethod, RubyClass, CacheEntry, ThreadContext, IRubyObject, IRubyObject,
    // String, args
    target = MethodHandles.foldArguments(target, GETMETHOD_1_B);
    // IRubyObject, RubyClass, CacheEntry, ThreadContext, IRubyObject, IRubyObject, String, args
    target = MethodHandles.foldArguments(target, PGC_1_B);
    // IRubyObject, CacheEntry, ThreadContext, IRubyObject, IRubyObject, String, args

    MethodHandle breakJump = dropNameAndArgs(BREAKJUMP, 5, 1, true);
    MethodHandle retryJump = dropNameAndArgs(RETRYJUMP, 5, 1, true);
    target = MethodHandles.catchException(target, JumpException.BreakJump.class, breakJump);
    target = MethodHandles.catchException(target, JumpException.RetryJump.class, retryJump);

    TARGET_1_B = target;
  }

  private static final MethodHandle FALLBACK_1_B =
      MethodHandles.lookup()
          .findStatic(
              InvokeDynamicSupport.class,
              "fallback",
              MethodType.make(
                  IRubyObject.class,
                  JRubyCallSite.class,
                  ThreadContext.class,
                  IRubyObject.class,
                  IRubyObject.class,
                  String.class,
                  IRubyObject.class,
                  Block.class));

  private static final MethodHandle PGC_2_B = dropNameAndArgs(PGC, 4, 2, true);
  private static final MethodHandle GETMETHOD_2_B = dropNameAndArgs(GETMETHOD, 5, 2, true);
  private static final MethodHandle TEST_2_B = dropNameAndArgs(TEST, 4, 2, true);
  private static final MethodHandle TARGET_2_B;

  static {
    MethodHandle target =
        MethodHandles.lookup()
            .findVirtual(
                DynamicMethod.class,
                "call",
                MethodType.make(
                    IRubyObject.class,
                    ThreadContext.class,
                    IRubyObject.class,
                    RubyModule.class,
                    String.class,
                    IRubyObject.class,
                    IRubyObject.class,
                    Block.class));
    target =
        MethodHandles.convertArguments(
            target,
            MethodType.make(
                IRubyObject.class,
                DynamicMethod.class,
                ThreadContext.class,
                IRubyObject.class,
                RubyClass.class,
                String.class,
                IRubyObject.class,
                IRubyObject.class,
                Block.class));
    target =
        MethodHandles.permuteArguments(
            target,
            MethodType.make(
                IRubyObject.class,
                DynamicMethod.class,
                RubyClass.class,
                CacheEntry.class,
                ThreadContext.class,
                IRubyObject.class,
                IRubyObject.class,
                String.class,
                IRubyObject.class,
                IRubyObject.class,
                Block.class),
            new int[] {0, 3, 5, 1, 6, 7, 8, 9});
    // IRubyObject, DynamicMethod, RubyClass, CacheEntry, ThreadContext, IRubyObject, IRubyObject,
    // String, args
    target = MethodHandles.foldArguments(target, GETMETHOD_2_B);
    // IRubyObject, RubyClass, CacheEntry, ThreadContext, IRubyObject, IRubyObject, String, args
    target = MethodHandles.foldArguments(target, PGC_2_B);
    // IRubyObject, CacheEntry, ThreadContext, IRubyObject, IRubyObject, String, args

    MethodHandle breakJump = dropNameAndArgs(BREAKJUMP, 5, 2, true);
    MethodHandle retryJump = dropNameAndArgs(RETRYJUMP, 5, 2, true);
    target = MethodHandles.catchException(target, JumpException.BreakJump.class, breakJump);
    target = MethodHandles.catchException(target, JumpException.RetryJump.class, retryJump);

    TARGET_2_B = target;
  }

  private static final MethodHandle FALLBACK_2_B =
      MethodHandles.lookup()
          .findStatic(
              InvokeDynamicSupport.class,
              "fallback",
              MethodType.make(
                  IRubyObject.class,
                  JRubyCallSite.class,
                  ThreadContext.class,
                  IRubyObject.class,
                  IRubyObject.class,
                  String.class,
                  IRubyObject.class,
                  IRubyObject.class,
                  Block.class));

  private static final MethodHandle PGC_3_B = dropNameAndArgs(PGC, 4, 3, true);
  private static final MethodHandle GETMETHOD_3_B = dropNameAndArgs(GETMETHOD, 5, 3, true);
  private static final MethodHandle TEST_3_B = dropNameAndArgs(TEST, 4, 3, true);
  private static final MethodHandle TARGET_3_B;

  static {
    MethodHandle target =
        MethodHandles.lookup()
            .findVirtual(
                DynamicMethod.class,
                "call",
                MethodType.make(
                    IRubyObject.class,
                    ThreadContext.class,
                    IRubyObject.class,
                    RubyModule.class,
                    String.class,
                    IRubyObject.class,
                    IRubyObject.class,
                    IRubyObject.class,
                    Block.class));
    target =
        MethodHandles.convertArguments(
            target,
            MethodType.make(
                IRubyObject.class,
                DynamicMethod.class,
                ThreadContext.class,
                IRubyObject.class,
                RubyClass.class,
                String.class,
                IRubyObject.class,
                IRubyObject.class,
                IRubyObject.class,
                Block.class));
    target =
        MethodHandles.permuteArguments(
            target,
            MethodType.make(
                IRubyObject.class,
                DynamicMethod.class,
                RubyClass.class,
                CacheEntry.class,
                ThreadContext.class,
                IRubyObject.class,
                IRubyObject.class,
                String.class,
                IRubyObject.class,
                IRubyObject.class,
                IRubyObject.class,
                Block.class),
            new int[] {0, 3, 5, 1, 6, 7, 8, 9, 10});
    // IRubyObject, DynamicMethod, RubyClass, CacheEntry, ThreadContext, IRubyObject, IRubyObject,
    // String, args
    target = MethodHandles.foldArguments(target, GETMETHOD_3_B);
    // IRubyObject, RubyClass, CacheEntry, ThreadContext, IRubyObject, IRubyObject, String, args
    target = MethodHandles.foldArguments(target, PGC_3_B);
    // IRubyObject, CacheEntry, ThreadContext, IRubyObject, IRubyObject, String, args

    MethodHandle breakJump = dropNameAndArgs(BREAKJUMP, 5, 3, true);
    MethodHandle retryJump = dropNameAndArgs(RETRYJUMP, 5, 3, true);
    target = MethodHandles.catchException(target, JumpException.BreakJump.class, breakJump);
    target = MethodHandles.catchException(target, JumpException.RetryJump.class, retryJump);

    TARGET_3_B = target;
  }

  private static final MethodHandle FALLBACK_3_B =
      MethodHandles.lookup()
          .findStatic(
              InvokeDynamicSupport.class,
              "fallback",
              MethodType.make(
                  IRubyObject.class,
                  JRubyCallSite.class,
                  ThreadContext.class,
                  IRubyObject.class,
                  IRubyObject.class,
                  String.class,
                  IRubyObject.class,
                  IRubyObject.class,
                  IRubyObject.class,
                  Block.class));

  private static final MethodHandle PGC_N_B = dropNameAndArgs(PGC, 4, -1, true);
  private static final MethodHandle GETMETHOD_N_B = dropNameAndArgs(GETMETHOD, 5, -1, true);
  private static final MethodHandle TEST_N_B = dropNameAndArgs(TEST, 4, -1, true);
  private static final MethodHandle TARGET_N_B;

  static {
    MethodHandle target =
        MethodHandles.lookup()
            .findVirtual(
                DynamicMethod.class,
                "call",
                MethodType.make(
                    IRubyObject.class,
                    ThreadContext.class,
                    IRubyObject.class,
                    RubyModule.class,
                    String.class,
                    IRubyObject[].class,
                    Block.class));
    target =
        MethodHandles.convertArguments(
            target,
            MethodType.make(
                IRubyObject.class,
                DynamicMethod.class,
                ThreadContext.class,
                IRubyObject.class,
                RubyClass.class,
                String.class,
                IRubyObject[].class,
                Block.class));
    target =
        MethodHandles.permuteArguments(
            target,
            MethodType.make(
                IRubyObject.class,
                DynamicMethod.class,
                RubyClass.class,
                CacheEntry.class,
                ThreadContext.class,
                IRubyObject.class,
                IRubyObject.class,
                String.class,
                IRubyObject[].class,
                Block.class),
            new int[] {0, 3, 5, 1, 6, 7, 8});
    // IRubyObject, DynamicMethod, RubyClass, CacheEntry, ThreadContext, IRubyObject, IRubyObject,
    // String, args
    target = MethodHandles.foldArguments(target, GETMETHOD_N_B);
    // IRubyObject, RubyClass, CacheEntry, ThreadContext, IRubyObject, IRubyObject, String, args
    target = MethodHandles.foldArguments(target, PGC_N_B);
    // IRubyObject, CacheEntry, ThreadContext, IRubyObject, IRubyObject, String, args

    MethodHandle breakJump = dropNameAndArgs(BREAKJUMP, 5, -1, true);
    MethodHandle retryJump = dropNameAndArgs(RETRYJUMP, 5, -1, true);
    target = MethodHandles.catchException(target, JumpException.BreakJump.class, breakJump);
    target = MethodHandles.catchException(target, JumpException.RetryJump.class, retryJump);

    TARGET_N_B = target;
  }

  private static final MethodHandle FALLBACK_N_B =
      MethodHandles.lookup()
          .findStatic(
              InvokeDynamicSupport.class,
              "fallback",
              MethodType.make(
                  IRubyObject.class,
                  JRubyCallSite.class,
                  ThreadContext.class,
                  IRubyObject.class,
                  IRubyObject.class,
                  String.class,
                  IRubyObject[].class,
                  Block.class));
}