Skip to content

Instantly share code, notes, and snippets.

@jruby
Created May 27, 2009 07:28
Show Gist options
  • Save jruby/118504 to your computer and use it in GitHub Desktop.
Save jruby/118504 to your computer and use it in GitHub Desktop.
package org.jruby.runtime.invokedynamic;
import java.dyn.CallSite;
import java.dyn.Linkage;
import java.dyn.MethodHandle;
import java.dyn.MethodHandles;
import java.dyn.MethodType;
import org.jruby.compiler.impl.SkinnyMethodAdapter;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.callsite.CacheEntry;
import static org.jruby.util.CodegenUtils.*;
import org.objectweb.asm.MethodVisitor;
public class InvokeDynamicSupport {
public static CallSite bootstrap(Class caller, String name, MethodType type) {
CallSite site = new CallSite(caller, name, type);
MethodHandle myFallback = MethodHandles.insertArgument(FALLBACK, 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));
}
public static boolean test(CacheEntry entry, ThreadContext context, IRubyObject caller, IRubyObject self, String name, IRubyObject arg0) {
return entry.typeOk(self.getMetaClass());
}
public static IRubyObject target(CacheEntry entry, ThreadContext context, IRubyObject caller, IRubyObject self, String name, IRubyObject arg0) {
return entry.method.call(context, self, self.getMetaClass(), name, arg0);
}
public static IRubyObject fallback(CallSite site, ThreadContext context, IRubyObject caller, IRubyObject self, String name, IRubyObject arg0) {
CacheEntry newEntry = self.getMetaClass().searchWithCache(name);
MethodHandle myTest = MethodHandles.insertArgument(TEST, 0, newEntry);
MethodHandle myTarget = MethodHandles.insertArgument(TARGET, 0, newEntry);
MethodHandle myFallback = MethodHandles.insertArgument(FALLBACK, 0, site);
MethodHandle guardWithTest = MethodHandles.guardWithTest(myTest, myTarget, myFallback);
site.setTarget(MethodHandles.convertArguments(guardWithTest, site.type()));
return newEntry.method.call(context, self, self.getMetaClass(), name, arg0);
}
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 TEST = MethodHandles.lookup().findStatic(InvokeDynamicSupport.class, "test",
MethodType.make(boolean.class, CacheEntry.class, ThreadContext.class, IRubyObject.class, IRubyObject.class, String.class, IRubyObject.class));
private static final MethodHandle TARGET = MethodHandles.lookup().findStatic(InvokeDynamicSupport.class, "target",
MethodType.make(IRubyObject.class, CacheEntry.class, ThreadContext.class, IRubyObject.class, IRubyObject.class, String.class, IRubyObject.class));
private static final MethodHandle FALLBACK = MethodHandles.lookup().findStatic(InvokeDynamicSupport.class, "fallback",
MethodType.make(IRubyObject.class, CallSite.class, ThreadContext.class, IRubyObject.class, IRubyObject.class, String.class, IRubyObject.class));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment