Tuesday, May 27, 2008

Proof-of-Concept Backport Invokedynamic in Groovy

It is my first day of Google Summer of Code, and here is what I've done today ;-)

I have been reading hard and trying to understand Invokedynamic EDR since last week. It is quite difficult for me, who has little background of this kind of things. However, I have got some good sources for studying how invokedynamic work from John Rose's blog, Alex Tkachman's Method Handle code, Jeroen Frijters's blog, and Rémi Forax's blog.

Although, there is no something complex like Jeroen's sample, here is a working version of Hello World that uses my backport of invokedynamic APIs.


package groovy.dyn.subject.vm5;

import groovy.dyn.CallSite;
import groovy.dyn.Linkage;
import groovy.dyn.MethodHandle;
import groovy.dyn.MethodHandles;
import groovy.dyn.MethodType;
import groovy.dyn.StaticContext;
import groovy.dyn.internal.CallSiteImpl;
import groovy.dyn.internal.StaticContextImpl;

import java.io.PrintStream;
import java.lang.reflect.Method;

public class InvokeDynamicSubject {

private static CallSite[] callsites;
private static final int NUM_OF_CALLSITES = 1;

static {
initCallSites();
try {
Method method = InvokeDynamicSubject.class
.getDeclaredMethod("bootstrapInvokeDynamic",
CallSite.class, Object.class, Object[].class);
MethodHandle mh = MethodHandles.unreflect(method);
Linkage.registerBootstrapMethod(InvokeDynamicSubject.class, mh);
} catch (Throwable e) {
// do nothing now
}
}

private static void initCallSites() {
callsites = new CallSite[NUM_OF_CALLSITES];
callsites[0] = new CallSiteImpl(0,
new StaticContextImpl(
PrintStream.class,
"println",
MethodType.make(void.class, String.class)
)
);
}

private static Object bootstrapInvokeDynamic(CallSite cs,
Object receiver, Object[] args) throws Throwable {
Method method=null;
CallSiteImpl csi = (CallSiteImpl)cs; // down cast: language specific
switch(csi.index()) {
case 0: {
StaticContext sc = cs.getStaticContext();
Class<?> c = sc.getCallingClass();
method = c.getDeclaredMethod(
sc.getName(),
sc.getType().parameterType(1));
MethodHandle mh = MethodHandles.unreflect(method);
cs.setTarget(mh);
return mh.invoke(receiver, args);
}
}
return null;
}

public void test() throws Throwable {
// System.out.println("Hello World");
MethodHandle mh = callsites[0].getTarget();
if(mh == null) {
bootstrapInvokeDynamic(callsites[0], System.out, new Object[]{"Hello World"});
} else {
mh.invoke(System.out, "Hello World");
}
}
}

Sunday, May 18, 2008

Groovy, Bazaar and bzr-svn

In the past, I was wondering how could I manage my Groovy fork (SVN is not good to do that because it's centralized nature). I was thinking to use SVK, but failed to set it up.

Today, Russel posted to groovy-dev that he set up a branch of Groovy on Launchpad. I have heard about Launchpad, but never tried to be its user. More that 2 hours that I have tried to set everything up.

I registered to be a Launchpad user, then forked my branch from Russel's one. OK, then what's next?
I'm still on Windows XP, so I need a set of putty programs for SSH. Later, I use PUTTYGEN to generate my public key and import it into Launchpad.

The next step is to download Python 2.5, Bazaar for Windows. Then, I installed bazaar and was able to branch Russel's trunk locally.

bzr branch http://bazaar.launchpad.net/~russel/groovy/trunk



After that I pushed it back to my branch.

bzr push bzr+ssh://chanwit@bazaar.launchpad.net/~chanwit/groovy/ck1



Then, something went wrong. I did not setup SSH properly. bazaar blamed me that I forgot to set BZR_SSH.

set BZR_SSH=plink



OK, here we go. Now everything went smoothly. I can push my local codes back to Launchpad. So I did clean and re-build Groovy to see if everything was fine. But hey !, the branch of Russel is out-of-date. I need the latest patch Alex just committed. So what to do?

I checked some docs on bazaar wiki and they said it is able to merge code from SVN using bzr-svn plugin. That sounds great to me. So I downloaded bzr-svn, but thing did not go smooth again. I need Python-Subversion binding with the special patches. Come on, where on the earth it is? Alright ! It seems I got everything to run bzr-svn.

I ran this command:

bzr merge http://svn.codehaus.org/groovy/trunk/groovy/groovy-core/



but it was not successful. The document said it should be svn+http. How silly I am. I tried merging again:

bzr merge svn+http://svn.codehaus.org/groovy/trunk/groovy/groovy-core/



And it worked ! After that I did commit.

bzr commit -m "message goes here"



and push all committed code back to Launchpad again:

bzr push



Wow, it was fun and cool!. Now I can have my experiment branch without missing any new patch from the main trunk! That's great, isn't it?