Commits

Shashank Bharadwaj committed c6f314c

all the files for the calling convention change

Comments (0)

Files changed (15)

src/org/python/compiler/Code.java

 package org.python.compiler;
 
+import static org.python.util.CodegenUtils.sig;
+
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles.Lookup;
 import java.util.BitSet;
 import java.util.Vector;
 
         mv.visitInvokeDynamicInsn(name, descriptor, bsmHandle, bmsArgs);
     }
     
+    public void invokedynamic(String name, String descriptor, Handle bsmHandle, Object... bmsArgs) {
+    	mv.visitInvokeDynamicInsn(name, descriptor, bsmHandle, bmsArgs);
+    }
+    
+    /**
+     * Convinience method to call {@link #visitInvokeDynamicInsn(String, String, MethodHandle, 
+     * Object...)} without having to create method handles. This method assumes that the 
+     * bootstrap method is a static one.
+     * 
+     * @param name name of the function to be invoked dyanmically
+     * @param descriptor method descriptor of the function to be invoked dyanmically
+     * @param bsmOwner owner class of the bootstrap method
+     * @param bsmName name of the bootstrap method
+     * @param bsmAccess how to invoke the bootstrap method. Usually one of
+     *        {@link Opcodes#MH_INVOKESTATIC}, or {@link Opcodes#MH_INVOKEVIRTUAL}. But it can be
+     *        other invokes too I guess. 
+     * @param bsmArgs list of arguments to be passed to bootstrap method
+     */
+    public void invokedynamic(String name, String descriptor, String bsmOwner, String bsmName,
+                              int bsmAccess, Object... bsmArgs) {
+        
+        String signature;
+        if (bsmArgs == null || bsmArgs.length == 0) {
+            signature = sig(CallSite.class, Lookup.class, String.class, 
+                            java.lang.invoke.MethodType.class); 
+        } else if (bsmArgs.length == 1) {
+            signature = sig(CallSite.class, Lookup.class, String.class, 
+                            java.lang.invoke.MethodType.class, Object.class);
+        } else {
+            signature = sig(CallSite.class, Lookup.class, String.class, 
+                            java.lang.invoke.MethodType.class, Object[].class);
+        }
+        
+        Handle bsmHandle = new Handle(bsmAccess, bsmOwner, bsmName, 
+                                                  signature);
+        visitInvokeDynamicInsn(name, descriptor, bsmHandle, bsmArgs);
+    }
+
 }

src/org/python/compiler/CodeCompiler.java

     private static final Object Exit = new Integer(1);
     private static final Object NoExit = null;
     private Module module;
-    private Code code;
+    protected Code code;
     private CompilerFlags cflags;
-    private int temporary;
-    private expr_contextType augmode;
+    protected int temporary;
+    protected expr_contextType augmode;
     private int augtmp1;
     private int augtmp2;
     private int augtmp3;
     private int augtmp4;
-    private boolean fast_locals, print_results;
-    private Map<String, SymInfo> tbl;
-    private ScopeInfo my_scope;
+    protected boolean fast_locals;
+	private boolean print_results;
+    protected Map<String, SymInfo> tbl;
+    protected ScopeInfo my_scope;
     private boolean optimizeGlobals = true;
     private String className;
-    private Stack<Label> continueLabels, breakLabels;
+    protected Stack<Label> continueLabels;
+	protected Stack<Label> breakLabels;
     private Vector<Label> yields = new Vector<Label>();
 
     /*
         return null;
     }
 
-    private void stackProduce() {
+    protected void stackProduce() {
         stackProduce(p(PyObject.class));
     }
 
-    private void stackProduce(String signature) {
+    protected void stackProduce(String signature) {
         stack.push(signature);
     }
 
         stackConsume(1);
     }
 
-    private void stackConsume(int numItems) {
+    protected void stackConsume(int numItems) {
         for (int i = 0; i < numItems; i++) {
             stack.pop();
         }
 
         module.codeConstant(new Suite(node, node.getInternalBody()), name, false, name,
                             getDocStr(node.getInternalBody()), true, false, node.getLine(), scope,
-                            cflags).get(code);
+                            cflags, null).get(code);
 
         //Make class out of name, bases, and code
         if (!makeClosure(scope)) {
         return null;
     }
 
-    private String getName(String name) {
+    protected String getName(String name) {
         if (className != null && name.startsWith("__") &&
                 !name.endsWith("__")) {
             //remove leading '_' from classname

src/org/python/compiler/Module.java

 import org.python.core.PyRunnableBootstrap;
 import org.python.core.PyString;
 import org.python.core.PyUnicode;
+import org.python.core.opt.MethodHandleHelper;
 import org.objectweb.asm.Type;
 import org.python.antlr.ParseException;
 import org.python.antlr.PythonTree;
     final int co_firstlineno;
     final boolean arglist, keywordlist;
     final String fname;
+    final String methodDesc;
     // for nested scopes
     final List<String> cellvars;
     final List<String> freevars;
 
     PyCodeConstant(mod tree, String name, boolean fast_locals, String className, boolean classBody,
             boolean printResults, int firstlineno, ScopeInfo scope, CompilerFlags cflags,
-            Module module)
+            Module module, String mDesc)
             throws Exception {
 
         this.co_name = name;
             names = null;
         }
 
+		if (mDesc == null) {
+			//frameless = false;
+			int count = -1;
+			if (Module.shouldGenerateOptimized(this)) {
+				count = argcount;
+			}
+			mDesc = MethodHandleHelper.getMethodType(count)
+					.toMethodDescriptorString();
+		} else {
+			// frameless = true;
+		}
+		methodDesc = mDesc;
+
         cellvars = toNameAr(scope.cellvars, true);
         freevars = toNameAr(scope.freevars, true);
         jy_npurecell = scope.jy_npurecell;
         this(name, name + ".py", true, org.python.core.imp.NO_MTIME);
     }
 
+    static boolean shouldGenerateOptimized(PyCodeConstant code) {
+        return (!code.fname.startsWith("f$0") && code.argcount < MethodHandleHelper.MAX_ARGUMENT_ARITY/* && !code.keywordlist
+                && !code.arglist */&& code.names != null /*&& !code.fname.startsWith("foo")*/);
+//        return false;
+    }
+
+
     private Constant findConstant(Constant c) {
         Constant ret = constants.get(c);
         if (ret != null) {
                                 boolean classBody, boolean printResults, int firstlineno,
                                 ScopeInfo scope, CompilerFlags cflags) throws Exception {
         return codeConstant(tree, name, fast_locals, className, null, classBody, printResults,
-                            firstlineno, scope, cflags);
+                            firstlineno, scope, cflags, null);
     }
 
     PyCodeConstant codeConstant(mod tree, String name, boolean fast_locals, String className,
                                 Str classDoc, boolean classBody, boolean printResults,
-                                int firstlineno, ScopeInfo scope, CompilerFlags cflags)
+                                int firstlineno, ScopeInfo scope, CompilerFlags cflags, String desc)
         throws Exception {
         PyCodeConstant code = new PyCodeConstant(tree, name, fast_locals,
                 className, classBody, printResults, firstlineno, scope, cflags,
-                this);
+                this, desc);
         codes.add(code);
 
-        CodeCompiler compiler = new CodeCompiler(this, printResults);
+        CodeCompiler compiler = new OptimizedCodeCompiler(this, printResults);
 
-        Code c = classfile.addMethod(
-                code.fname,
-                sig(PyObject.class, PyFrame.class, ThreadState.class),
-                ACC_PUBLIC);
+        Code c = classfile.addMethod(code.fname, code.methodDesc, ACC_PUBLIC);
 
         compiler.parse(tree, c, fast_locals, className, classDoc, classBody, scope, cflags);
         return code;

src/org/python/compiler/OptimizedCodeCompiler.java

+
+package org.python.compiler;
+
+import static org.python.util.CodegenUtils.ci;
+import static org.python.util.CodegenUtils.p;
+import static org.python.util.CodegenUtils.sig;
+
+import java.io.PrintStream;
+import java.lang.invoke.MethodHandle;
+import java.util.ArrayList;
+
+import org.objectweb.asm.Handle;
+import org.objectweb.asm.Opcodes;
+import org.python.antlr.ast.Call;
+import org.python.antlr.ast.Name;
+import org.python.antlr.ast.expr_contextType;
+import org.python.antlr.base.expr;
+import org.python.core.ThreadState;
+import org.python.core.opt.MethodHandleHelper;
+import org.python.core.opt.SpecializeCallSite;
+
+/**
+ * @author shashank
+ * 
+ */
+public class OptimizedCodeCompiler extends CodeCompiler {
+
+	/** Offset accounting for: <code>this</code> and the common params */
+    protected static final int VAR_OFFSET = MethodHandleHelper.COMMON_PARAMS_SIZE + 1;
+	static String TYPE = "OptimizedCC";
+
+    public OptimizedCodeCompiler(Module module, boolean print_results) {
+        super(module, print_results);
+    }
+    
+    public static int produceMethodHandle(Code code, PyCodeConstant pyCode, String funcName, 
+                                          String className) {
+        int mHandle = code.getLocal(p(MethodHandle.class));
+        funcName = "_" + funcName;
+        Handle handle = new Handle(Opcodes.H_INVOKEVIRTUAL, className, funcName, pyCode.methodDesc);
+        code.ldc(handle);
+        code.aload(0);  // this
+        code.invokevirtual(p(MethodHandle.class), "bindTo", sig(MethodHandle.class, Object.class));
+        code.astore(mHandle);
+        return mHandle;
+    }
+
+    public static void printInJava(Code code, String whatToSay){
+        code.getstatic(p(System.class), "err", ci(PrintStream.class));
+        code.ldc(whatToSay);
+        code.invokevirtual(p(PrintStream.class), "println", sig(Void.TYPE, String.class));
+    }
+    
+    @Override
+    public Object visitCall(Call node) throws Exception {
+        java.util.List<String> keys = new ArrayList<String>();
+        java.util.List<expr> values = new ArrayList<expr>();
+        for (int i = 0; i < node.getInternalArgs().size(); i++) {
+            values.add(node.getInternalArgs().get(i));
+        }
+        for (int i = 0; i < node.getInternalKeywords().size(); i++) {
+            keys.add(node.getInternalKeywords().get(i).getInternalArg());
+            values.add(node.getInternalKeywords().get(i).getInternalValue());
+        }
+        
+        int argLen = values.size();
+        if (node.getInternalStarargs() == null && node.getInternalKwargs() == null 
+                && argLen <= MethodHandleHelper.MAX_ARGUMENT_ARITY) {
+            
+            loadThreadState();
+            stackProduce(p(ThreadState.class));
+            
+            visit(node.getInternalFunc());
+            stackProduce();
+            
+            for (int i = 0; i < argLen; i++) {
+                visit(values.get(i));
+                stackProduce();                
+            }
+            stackConsume(2 + argLen); // ts + pyfunction + args
+//            System.err.println("Generating indy call");
+            code.invokedynamic("_", MethodHandleHelper.getMethodType(argLen).dropParameterTypes(0, 1).toMethodDescriptorString(), 
+                               p(SpecializeCallSite.class), "bootstrap", Opcodes.H_INVOKESTATIC, keys.toArray());
+            return null;
+        }
+//        System.err.println("calling super: " + node.getInternalFunc() + node.getInternalStarargs() == null ? "has starargs " : ""
+//            + (node.getInternalKwargs() == null ? "has kwargs " : "") 
+//            /*+ argLen == 0 ? " exceeds max arg count" : ""*/);  
+        return super.visitCall(node);
+    }
+    
+    @Override
+    public Object visitName(Name node) throws Exception {
+        String name;
+        if (fast_locals) {
+            name = node.getInternalId();
+        } else {
+            name = getName(node.getInternalId());
+        }
+        SymInfo syminf = tbl.get(name);
+        
+        expr_contextType ctx = node.getInternalCtx();
+
+        if (ctx == expr_contextType.AugStore) {
+            ctx = augmode;
+        }
+        
+        switch(ctx){
+            case Load: {
+                if (my_scope != null && my_scope.ac != null && !my_scope.ac.arglist
+                        && !my_scope.ac.keywordlist) {
+                    int argcount = my_scope.ac.names.size();
+//                    if (((syminf.flags & ScopeInfo.BOUND) != 0) && ((syminf.flags & ScopeInfo.FROM_PARAM) != 0) &&
+                    if ((syminf.flags == 13) &&
+                            (syminf.locals_index < argcount) && (argcount <= MethodHandleHelper.MAX_ARGUMENT_ARITY)) {
+                        int i = 0;
+                        for (i = 0; i < argcount; i++) {
+                            if (my_scope.ac.names.get(i).equals(name))
+                                break;
+                        }
+                        if (i < argcount) {
+//                            Py.writeError(TYPE, "loading " + name + " from stack: " + syminf.locals_index);
+                            code.aload(syminf.locals_index + VAR_OFFSET); 
+                            return null;
+                        }
+                    }
+                }
+                break;
+            }
+            case Store: {
+                if (my_scope != null && my_scope.ac != null && !my_scope.ac.arglist
+                        && !my_scope.ac.keywordlist) {
+                    int argcount = my_scope.ac.names.size();
+//                    if (((syminf.flags & ScopeInfo.BOUND) != 0) && ((syminf.flags & ScopeInfo.FROM_PARAM) != 0) && 
+                    if ((syminf.flags == 13) &&
+                            (syminf.locals_index < argcount) && (argcount <= MethodHandleHelper.MAX_ARGUMENT_ARITY)) {
+                        int i = 0;
+                        for (i = 0; i < argcount; i++) {
+                            if (my_scope.ac.names.get(i).equals(name))
+                                break;
+                        }
+                        if (i < argcount) {
+//                            Py.writeError(TYPE, "storing " + name + " to stack: " + syminf.locals_index);
+                            code.aload(temporary);
+                            code.astore(syminf.locals_index + VAR_OFFSET); 
+                            return null;
+                        }
+                    }
+                }
+                break;
+            }
+        }
+        return super.visitName(node);
+    }
+    
+    
+//    @Override
+//    public Object visitOptimizedFor(OptimizedFor node) throws Exception {
+//        java.util.List<expr> values = null;
+//        expr internalFunc = null;
+//        values = ((Call)node.getInternalIter()).getInternalArgs();
+//        internalFunc = ((Call)node.getInternalIter()).getInternalFunc();
+//        int start_value = code.getLocal(p(int.class));
+//        int stop_value = code.getLocal(p(int.class));
+//        int step_value = code.getLocal(p(int.class));
+//        int down_count_flag = code.getLocal(p(int.class));
+//        switch(values.size()){
+//            case 1:
+//                visit(values.get(0));
+//                code.iconst_0();
+//                code.istore(start_value);
+//                // stackProduce();
+//                // stackConsume();
+//                code.invokevirtual(p(PyObject.class), "asInt", sig(int.class));
+//                code.istore(stop_value);
+//                code.iconst_1();
+//                code.istore(step_value);
+//                code.iconst_0();
+//                code.istore(down_count_flag);
+//                break;
+//            case 2:
+//                visit(values.get(0));
+//                // stackProduce();
+//                // stackConsume();
+//                code.invokevirtual(p(PyObject.class), "asInt", sig(int.class));
+//                code.istore(start_value);
+//                visit(values.get(1));
+//                // stackProduce();
+//                // stackConsume();
+//                code.invokevirtual(p(PyObject.class), "asInt", sig(int.class));
+//                code.istore(stop_value);
+//                code.iconst_1();
+//                code.istore(step_value);
+//                code.iconst_0();
+//                code.istore(down_count_flag);
+//                break;
+//            case 3:
+//                visit(values.get(0));
+//                // stackProduce();
+//                // stackConsume();
+//                code.invokevirtual(p(PyObject.class), "asInt", sig(int.class));
+//                code.istore(start_value);
+//                visit(values.get(1));
+//                // stackProduce();
+//                // stackConsume();
+//                code.invokevirtual(p(PyObject.class), "asInt", sig(int.class));
+//                code.istore(stop_value);
+//                visit(values.get(2));
+//                // stackProduce();
+//                // stackConsume();
+//                code.invokevirtual(p(PyObject.class), "asInt", sig(int.class));
+//                code.istore(step_value);
+//                // Since a step is provided, we have to check for down count
+//                // Also we need to throw an error in case step size is 0
+//                Label stepNotZero = new Label();
+//                Label greaterThanZero = new Label();
+//                Label step_end = new Label();
+//                code.iconst_0();
+//                code.iload(step_value);
+//                code.if_icmpne(stepNotZero);
+//                // step == 0: throw error
+//                code.ldc("[x]range() step argument must not be zero");
+//                code.invokestatic(p(Py.class), "ValueError", sig(PyException.class, String.class));
+//                code.athrow();
+//                // step != 0
+//                code.label(stepNotZero);
+//                code.iload(step_value);
+//                code.iconst_0();
+//                code.if_icmpgt(greaterThanZero);
+//                // step < 0, start down count
+//                code.iconst_1();
+//                code.istore(down_count_flag);
+//                code.goto_(step_end);
+//                // step > 0, normal up count
+//                code.label(greaterThanZero);
+//                code.iconst_0();
+//                code.istore(down_count_flag);
+//                code.label(step_end);
+//                break;
+//            default:
+//                break;
+//        }
+//        // Try-catch block for guarding
+//        Label start = new Label();
+//        Label end = new Label();
+//        Label handler_start = new Label();
+//        Label handler_end = new Label();
+//        code.trycatch(start, end, handler_start, p(IndyOptimizerException.class));
+//        code.label(start);
+//        // Do the try-stuff
+//        visit(internalFunc);
+//        // stackProduce();
+//        // stackConsume();
+//        code.invokedynamic("xrangeTarget", sig(Void.TYPE, PyObject.class), 
+//                           RangeOptimizer.className, "xrangeBsm", Opcodes.H_INVOKESTATIC);
+//        
+//        optimizedForLoop(node, start_value, stop_value, step_value, down_count_flag);
+//        code.label(end);
+//        code.goto_(handler_end);
+//        code.label(handler_start);
+//        // Catch block
+//        // TODO: call the pbcvm here
+//        code.new_(p(IndyOptimizerException.class));
+//        code.ldc("Range function Exception!");
+//        code.invokespecial(p(IndyOptimizerException.class), "<init>", sig(Void.TYPE, String.class));
+//        code.athrow();
+//        code.label(handler_end);
+//        code.freeLocal(start_value);
+//        code.freeLocal(stop_value);
+//        code.freeLocal(step_value);
+//        return null;
+//    }
+//
+//    private void optimizedForLoop(For forNode,
+//                                  int start_value,
+//                                  int stop_value,
+//                                  int step_value,
+//                                  int down_count_flag) throws Exception {
+//        // Now the optimized code path for the for loop begins
+//        int savebcf = beginLoop();
+//        Label continue_loop = continueLabels.peek();
+//        Label break_loop = breakLabels.peek();
+//        Label start_loop = new Label();
+//        Label next_loop = new Label();
+//        Label down_count_label = new Label();
+//        Label loop_end = new Label();
+//        setline(forNode);
+//        // reuse the start_value variable as the iter_tmp variable
+//        int iter_tmp = start_value;
+//        int expr_tmp = code.getLocal(p(PyObject.class));
+//        // set up the loop iterator
+//        code.iload(start_value);
+//        code.istore(iter_tmp);
+//        // do check at end of loop. Saves one opcode ;-)
+//        code.goto_(next_loop);
+//        code.label(start_loop);
+//        // set iter variable to current entry in list
+//        set(forNode.getInternalTarget(), expr_tmp);
+//        // evaluate for body
+//        suite(forNode.getInternalBody());
+//        code.label(continue_loop);
+//        setline(forNode);
+//        code.iload(iter_tmp);
+//        code.iload(step_value);
+//        code.iadd();
+//        code.istore(iter_tmp);
+//        code.label(next_loop);
+//        // make the element available in python
+//        code.iload(iter_tmp);
+//        code.invokestatic(p(Py.class), "newInteger", sig(PyInteger.class, int.class));
+//        code.astore(expr_tmp);
+//        // down counting?
+//        code.iload(down_count_flag);
+//        code.iconst_1();
+//        code.if_icmpeq(down_count_label);
+//        // now check if we should go back into the loop
+//        code.iload(iter_tmp);
+//        code.iload(stop_value);
+//        code.if_icmplt(start_loop);
+//        code.goto_(loop_end);
+//        // We are down counting
+//        code.label(down_count_label);
+//        code.iload(iter_tmp);
+//        code.iload(stop_value);
+//        code.if_icmpgt(start_loop);
+//        code.label(loop_end);
+//        finishLoop(savebcf);
+//        if (forNode.getInternalOrelse() != null) {
+//            // Do else clause if provided
+//            suite(forNode.getInternalOrelse());
+//        }
+//        code.label(break_loop);
+//        code.freeLocal(expr_tmp);
+//    }
+}

src/org/python/core/PyBaseCode.java

     public CompilerFlags co_flags = new CompilerFlags();
     public int co_nlocals;
     public boolean varargs,  varkwargs;
-
+    protected boolean simple_case = true;
 
     public boolean hasFreevars() {
         return co_freevars != null && co_freevars.length > 0;

src/org/python/core/PyCode.java

 // Copyright (c) Corporation for National Research Initiatives
 package org.python.core;
 
+import java.lang.invoke.MethodHandle;
+
+import org.python.core.opt.SpecializeCallSite;
+
 /**
  * A super class for all python code implementations.
  */
 public abstract class PyCode extends PyObject
 {
     public String co_name;
+    
+    public class RuntimeInfo {
+        public MethodHandle mHandle = null;
+        public boolean frameless = false;
+    }
+    
+    public RuntimeInfo runtimeInfo = new RuntimeInfo();
 
     abstract public PyObject call(ThreadState state, PyFrame frame, PyObject closure);
 

src/org/python/core/PyFunction.java

 
     @Override
     public boolean isSequenceType() { return false; }
+
+    public PyFrame createFrame(){
+//      Py.writeWarning("PyFunction", func_code.co_name + ": Creating frame");
+      PyFrame frame = new PyFrame((PyBaseCode)__code__, __globals__);
+      frame.setupEnv((PyTuple)func_closure);
+      return frame;
+  }
+
 }

src/org/python/core/PyMethodCode.java

+package org.python.core;
+
+import java.lang.invoke.MethodHandle;
+
+import org.python.core.opt.SpecializeCallSite;
+import org.python.modules._systemrestart;
+
+public class PyMethodCode extends PyTableCode {
+
+    public PyMethodCode(int argcount, String varnames[], String filename, String name,
+                       int firstlineno, boolean varargs, boolean varkwargs, PyFunctionTable funcs, 
+                       int func_id, String[] cellvars, String[] freevars, int npurecell,
+                       int moreflags, MethodHandle mHandle, boolean frameless) {
+        super(argcount, varnames, filename, name, firstlineno, varargs, varkwargs, funcs, func_id, 
+              cellvars, freevars, npurecell, moreflags);
+        this.runtimeInfo.mHandle = mHandle;
+        this.runtimeInfo.frameless = frameless;
+//        System.err.println("pymethodcode!");
+    }
+    
+//    @Override
+    public PyObject call(ThreadState ts, PyFrame frame, PyFunction func, PyObject[] args, String[] kws) {
+        
+        int argcount = args.length - kws.length;
+        PyObject[] defs = func.func_defaults;
+        if (co_argcount > 0 || (varargs || varkwargs)) {
+            int i;
+            int n = argcount;
+            PyObject kwdict = null;
+            PyObject[] fastlocals = frame.f_fastlocals;
+            if (varkwargs) {
+                kwdict = new PyDictionary();
+                i = co_argcount;
+                if (varargs) {
+                    i++;
+                }
+                fastlocals[i] = kwdict;
+            }
+            if (argcount > co_argcount) {
+                if (!varargs) {
+                    int defcount = defs != null ? defs.length : 0;
+                    String msg = String.format("%.200s() takes %s %d %sargument%s (%d given)",
+                                               co_name,
+                                               defcount > 0 ? "at most" : "exactly",
+                                               co_argcount,
+                                               kws.length > 0 ? "non-keyword " : "",
+                                               co_argcount == 1 ? "" : "s",
+                                               argcount);
+                    throw Py.TypeError(msg);
+                }
+                n = co_argcount;
+            }
+
+            System.arraycopy(args, 0, fastlocals, 0, n);
+
+            if (varargs) {
+                PyObject[] u = new PyObject[argcount - n];
+                System.arraycopy(args, n, u, 0, argcount - n);
+                PyObject uTuple = new PyTuple(u);
+                fastlocals[co_argcount] = uTuple;
+            }
+            for (i = 0; i < kws.length; i++) {
+                String keyword = kws[i];
+                PyObject value = args[i + argcount];
+                int j;
+                // XXX: keywords aren't PyObjects, can't ensure strings
+                //if (keyword == null || keyword.getClass() != PyString.class) {
+                //    throw Py.TypeError(String.format("%.200s() keywords must be strings",
+                //                                     co_name));
+                //}
+                for (j = 0; j < co_argcount; j++) {
+                    if (co_varnames[j].equals(keyword)) {
+                        break;
+                    }
+                }
+                if (j >= co_argcount) {
+                    if (kwdict == null) {
+                        throw Py.TypeError(String.format("%.200s() got an unexpected keyword "
+                                                         + "argument '%.400s'",
+                                                         co_name, keyword));
+                    }
+                    kwdict.__setitem__(keyword, value);
+                } else {
+                    if (fastlocals[j] != null) {
+                        throw Py.TypeError(String.format("%.200s() got multiple values for "
+                                                         + "keyword argument '%.400s'",
+                                                         co_name, keyword));
+                    }
+                    fastlocals[j] = value;
+                }
+            }
+            if (argcount < co_argcount) {
+                int defcount = defs != null ? defs.length : 0;
+                int m = co_argcount - defcount;
+                for (i = argcount; i < m; i++) {
+                    if (fastlocals[i] == null) {
+                        String msg =
+                                String.format("%.200s() takes %s %d %sargument%s (%d given)",
+                                              co_name, (varargs || defcount > 0) ?
+                                              "at least" : "exactly",
+                                              m, kws.length > 0 ? "non-keyword " : "",
+                                              m == 1 ? "" : "s", i);
+                        throw Py.TypeError(msg);
+                    }
+                }
+                if (n > m) {
+                    i = n - m;
+                } else {
+                    i = 0;
+                }
+                for (; i < defcount; i++) {
+                    if (fastlocals[m + i] == null) {
+                        fastlocals[m + i] = defs[i];
+                    }
+                }
+            }
+        } else if (argcount > 0) {
+            throw Py.TypeError(String.format("%.200s() takes no arguments (%d given)",
+                                             co_name, argcount));
+        }
+
+        if (co_flags.isFlagSet(CodeFlag.CO_GENERATOR)) {
+            return new PyGenerator(frame, func.func_closure);
+        }
+        return call(ts, frame, func.func_closure);
+    }
+    
+    
+    
+    @Override
+    public PyObject call(ThreadState state, PyObject globals, PyObject[] defaults, PyObject closure) {
+        if (co_argcount == 0 && !varargs && !varkwargs && runtimeInfo.mHandle != null){
+            PyFrame frame = new PyFrame(this, globals);
+            if (co_flags.isFlagSet(CodeFlag.CO_GENERATOR)) {
+                return new PyGenerator(frame, closure);
+            }
+            return special_call(state, frame, closure);
+        }
+        return super.call(state, globals, defaults, closure);
+    }
+    
+    @Override
+    public PyObject call(ThreadState state, PyObject arg1, PyObject globals, PyObject[] defaults, PyObject closure) {
+        if (co_argcount == 1 && !varargs && !varkwargs && runtimeInfo.mHandle != null){
+            PyFrame frame = new PyFrame(this, globals);
+            frame.f_fastlocals[0] = arg1;
+            if (co_flags.isFlagSet(CodeFlag.CO_GENERATOR)) {
+                return new PyGenerator(frame, closure);
+            }
+            return special_call(state, frame, closure, arg1);
+        }
+        return super.call(state, arg1, globals, defaults, closure);
+    }
+    
+    @Override
+    public PyObject call(ThreadState state, PyObject arg1, PyObject arg2, PyObject globals, PyObject[] defaults, 
+                         PyObject closure) {
+        if (co_argcount == 2 && !varargs && !varkwargs && runtimeInfo.mHandle != null){
+            PyFrame frame = new PyFrame(this, globals);
+            frame.f_fastlocals[0] = arg1;
+            frame.f_fastlocals[1] = arg2;
+            if (co_flags.isFlagSet(CodeFlag.CO_GENERATOR)) {
+                return new PyGenerator(frame, closure);
+            }
+            return special_call(state, frame, closure, arg1, arg2);
+        }
+        return super.call(state, arg1, arg2, globals, defaults, closure);
+    }
+    
+    @Override
+    public PyObject call(ThreadState state, PyObject arg1, PyObject arg2, PyObject arg3, PyObject globals, 
+                         PyObject[] defaults, PyObject closure) {
+        if (co_argcount == 3 && !varargs && !varkwargs && runtimeInfo.mHandle != null){
+            PyFrame frame = new PyFrame(this, globals);
+            frame.f_fastlocals[0] = arg1;
+            frame.f_fastlocals[1] = arg2;
+            frame.f_fastlocals[2] = arg3;
+            if (co_flags.isFlagSet(CodeFlag.CO_GENERATOR)) {
+                return new PyGenerator(frame, closure);
+            }
+            return special_call(state, frame, closure, arg1, arg2, arg3);
+        }
+        return super.call(state, arg1, arg2, arg3, globals, defaults, closure);
+    }
+    
+
+    @Override
+    public PyObject call(ThreadState state, PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4, 
+                         PyObject globals, PyObject[] defaults, PyObject closure) {
+        if (co_argcount == 4 && !varargs && !varkwargs && runtimeInfo.mHandle != null){
+            PyFrame frame = new PyFrame(this, globals);
+            frame.f_fastlocals[0] = arg1;
+            frame.f_fastlocals[1] = arg2;
+            frame.f_fastlocals[2] = arg3;
+            frame.f_fastlocals[3] = arg4;
+            if (co_flags.isFlagSet(CodeFlag.CO_GENERATOR)) {
+                return new PyGenerator(frame, closure);
+            }
+            return special_call(state, frame, closure, arg1, arg2, arg3, arg4);
+        }
+        return super.call(state, arg1, arg2, arg3, arg4, globals, defaults, closure);
+    }
+    
+    
+    public PyObject special_call(ThreadState ts, PyFrame frame, PyObject closure, PyObject... args) {
+        
+//        Py.writeWarning("PyMethodCode", "MethodHandle: " + runtimeInfo.mHandle + " frame: " + frame.f_fastlocals.length);
+        
+        if (ts.systemState == null) {
+            ts.systemState = Py.defaultSystemState;
+        }
+
+        // Cache previously defined exception
+        PyException previous_exception = ts.exception;
+
+        // Push frame
+        frame.f_back = ts.frame;
+        if (frame.f_builtins == null) {
+            if (frame.f_back != null) {
+                frame.f_builtins = frame.f_back.f_builtins;
+            } else {
+                frame.f_builtins = PySystemState.builtins;
+            }
+        }
+        // nested scopes: setup env with closure
+        // this should only be done once, so let the frame take care of it
+        frame.setupEnv((PyTuple)closure);
+
+        ts.frame = frame;
+
+        PyObject ret = null;
+        try {
+            ret = callUsingMethodHandle(ts, frame, args);
+            
+        }catch (NoSuchMethodException e) {
+            ret = fallback(ts, frame, args);
+        } catch (Throwable t) {
+            // Convert exceptions that occured in Java code to PyExceptions
+            PyException pye = Py.JavaError(t);
+            pye.tracebackHere(frame);
+
+            frame.f_lasti = -1;
+
+            // Rethrow the exception to the next stack frame
+            ts.exception = previous_exception;
+            ts.frame = ts.frame.f_back;
+            throw pye;
+        }
+
+        // Restore previously defined exception
+        ts.exception = previous_exception;
+
+        ts.frame = ts.frame.f_back;
+
+        return ret;
+    }
+
+    private PyObject callUsingMethodHandle(ThreadState ts, PyFrame frame, PyObject... args) throws Throwable {
+        PyObject ret = null;
+        int arglen = 0;
+        if(args != null){
+            arglen = args.length;
+        }
+        MethodHandle mHandle = runtimeInfo.mHandle;
+//        Py.writeWarning("PyMethodCode:" + co_name, "callUsingMH:args: " + arglen);
+        switch (arglen) {
+            case 0:
+                ret = (PyObject)mHandle.invokeExact(frame, ts, (PyObject) null);
+                break;
+            case 1:
+                ret = (PyObject)mHandle.invokeExact(frame, ts, (PyObject) null, args[0]);
+                break;
+            case 2:
+                ret = (PyObject)mHandle.invokeExact(frame, ts, (PyObject) null, args[0], args[1]);
+                break;
+            case 3:
+                ret = (PyObject)mHandle.invokeExact(frame, ts, (PyObject) null, args[0], args[1], args[2]);
+                break;
+            case 4:
+                ret = (PyObject)mHandle.invokeExact(frame, ts, (PyObject) null, args[0], args[1], args[2],
+                                                    args[3]);
+                break;
+            case 5:
+                ret = (PyObject)mHandle.invokeExact(frame, ts, (PyObject) null, args[0], args[1], args[2],
+                                                    args[3], args[4]);
+                break;
+            case 6:
+                ret = (PyObject)mHandle.invokeExact(frame, ts, (PyObject) null, args[0], args[1], args[2],
+                                                    args[3], args[4], args[5]);
+                break;
+            case 7:
+                ret = (PyObject)mHandle.invokeExact(frame, ts, (PyObject) null, args[0], args[1], args[2],
+                                                    args[3], args[4], args[5], args[6]);
+                break;
+            case 8:
+                ret = (PyObject)mHandle.invokeExact(frame, ts, (PyObject) null, args[0], args[1], args[2],
+                                                    args[3], args[4], args[5], args[6], args[7]);
+                break;
+            case 9:
+                ret = (PyObject)mHandle.invokeExact(frame, ts, (PyObject) null, args[0], args[1], args[2],
+                                                    args[3], args[4], args[5], args[6], args[7], args[8]);
+                break;
+            case 10:
+                ret = (PyObject)mHandle.invokeExact(frame, ts, (PyObject) null, args[0], args[1], args[2],
+                                                    args[3], args[4], args[5], args[6], args[7], args[8],
+                                                    args[9]);
+                break;
+        }
+        return ret;
+    }
+    
+    /**
+     * This is the interface that calls the selected python function from the call-site. This
+     * implementation uses {@link MethodHandle} from Java7 to invoke the function. 
+     */
+    @Override
+    public PyObject call(ThreadState ts, PyFrame frame, PyObject closure) {
+        if(runtimeInfo.mHandle == null){
+            return super.call(ts, frame, closure);
+        }
+        
+//         System.err.println("tablecode call: "+co_name);
+        if (ts.systemState == null) {
+            ts.systemState = Py.defaultSystemState;
+        }
+        //System.err.println("got ts: "+ts+", "+ts.systemState);
+
+        // Cache previously defined exception
+        PyException previous_exception = ts.exception;
+
+        // Push frame
+        frame.f_back = ts.frame;
+        if (frame.f_builtins == null) {
+            if (frame.f_back != null) {
+                frame.f_builtins = frame.f_back.f_builtins;
+            } else {
+                //System.err.println("ts: "+ts);
+                //System.err.println("ss: "+ts.systemState);
+                frame.f_builtins = PySystemState.builtins;
+            }
+        }
+        // nested scopes: setup env with closure
+        // this should only be done once, so let the frame take care of it
+        frame.setupEnv((PyTuple)closure);
+
+        ts.frame = frame;
+
+        // Handle trace function for debugging
+        if (ts.tracefunc != null) {
+            frame.f_lineno = co_firstlineno;
+            frame.tracefunc = ts.tracefunc.traceCall(frame);
+        }
+
+        // Handle trace function for profiling
+        if (ts.profilefunc != null) {
+            ts.profilefunc.traceCall(frame);
+        }
+
+        PyObject ret = null;
+        try {
+//            Py.writeWarning("PyMethodCode:: in default case", "MethodHandle: " + mHandle + " frame: " + frame.f_fastlocals.length);
+            if(/*mHandle.type().parameterCount() == 3 || frame.f_fastlocals != null*/ simple_case){
+                String msg = null;
+                if(frame.f_fastlocals == null) msg = " null";
+                else msg = " " + frame.f_fastlocals.length;
+                
+//                Py.writeWarning("PyMethodCode:" +co_name, "argcount is: " + co_argcount + " locals:" + msg
+//                                + " mh takes: " + (mHandle.type().parameterCount() - 3));
+                int mhArgs = runtimeInfo.mHandle.type().parameterCount() - 3;
+                PyObject[] locals = new PyObject[mhArgs];
+                if (frame.f_fastlocals != null) {
+                    System.arraycopy(frame.f_fastlocals, 0, locals, 0, mhArgs);
+                    for (int i = 0; i < frame.f_fastlocals.length; i++) {
+//                        Py.writeWarning("Locals:", "" + frame.f_fastlocals[i]);
+                    }
+                }
+                ret = callUsingMethodHandle(ts, frame, locals);
+            } else {
+                int arglen = runtimeInfo.mHandle.type().parameterCount() - 3;
+                PyObject[] args = new PyObject[arglen];
+                for (int i = 0; i < args.length; i++) {
+                    args[i] = frame.getlocal(i);
+                }
+//                Py.writeWarning("PyMethodCode:" +co_name, "fill from frame: " + arglen + " co_argcout:" + co_argcount);
+                ret = callUsingMethodHandle(ts, frame, args);
+            }
+        } catch (Throwable t) {
+            // Convert exceptions that occured in Java code to PyExceptions
+            PyException pye = Py.JavaError(t);
+            pye.tracebackHere(frame);
+
+            frame.f_lasti = -1;
+
+            if (frame.tracefunc != null) {
+                frame.tracefunc.traceException(frame, pye);
+            }
+            if (ts.profilefunc != null) {
+                ts.profilefunc.traceException(frame, pye);
+            }
+
+            // Rethrow the exception to the next stack frame
+            ts.exception = previous_exception;
+            ts.frame = ts.frame.f_back;
+            throw pye;
+        }
+
+        if (frame.tracefunc != null) {
+            frame.tracefunc.traceReturn(frame, ret);
+        }
+        // Handle trace function for profiling
+        if (ts.profilefunc != null) {
+            ts.profilefunc.traceReturn(frame, ret);
+        }
+
+        // Restore previously defined exception
+        ts.exception = previous_exception;
+
+        ts.frame = ts.frame.f_back;
+
+        // Check for interruption, which is used for restarting the interpreter
+        // on Jython
+        if (ts.systemState._systemRestart && Thread.currentThread().isInterrupted()) {
+            throw new PyException(_systemrestart.SystemRestart);
+        }
+        return ret;
+    }
+
+    private PyObject fallback(ThreadState ts, PyFrame frame, PyObject[] args) {
+        for (int i = 0; i < args.length; i++) {
+            frame.setlocal(i, args[i]);
+        }
+        return funcs.call_function(func_id, frame, ts);
+    }
+}

src/org/python/core/opt/IndyOptimizerException.java

+package org.python.core.opt;
+
+public class IndyOptimizerException extends RuntimeException {
+
+    public IndyOptimizerException(String message) {
+        super(message);
+    }
+}

src/org/python/core/opt/InvokeDynamicSupport.java

+package org.python.core.opt;
+
+import static java.lang.invoke.MethodHandles.constant;
+import static java.lang.invoke.MethodHandles.dropArguments;
+import static java.lang.invoke.MethodHandles.insertArguments;
+import static java.lang.invoke.MethodHandles.lookup;
+import static java.lang.invoke.MethodType.methodType;
+import static org.python.util.CodegenUtils.p;
+import static org.python.util.CodegenUtils.sig;
+
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles.Lookup;
+import java.lang.invoke.MethodType;
+import java.lang.invoke.SwitchPoint;
+
+import org.objectweb.asm.Handle;
+import org.objectweb.asm.Opcodes;
+import org.python.core.PyFunctionTable;
+import org.python.core.PyObject;
+
+public class InvokeDynamicSupport {
+
+
+	private static final String BSM_SIG_BASIC = sig(CallSite.class, Lookup.class, String.class, MethodType.class);
+	
+	public static final Handle HAN_GET_GLOBAL_BSM = makeIndySupportHandle("getGlobalBootstrap", BSM_SIG_BASIC);
+	
+	private static final MethodType MT_INIT_GET_GLOBAL = MethodType.methodType(PyObject.class, GetGlobalCallSite.class, 
+																			   PyFunctionTable.class, String.class);
+	
+	public static final MethodHandle MH_GET_GLOBAL = lookupStatic("initGetGlobal", MT_INIT_GET_GLOBAL);
+
+	public static final MethodHandle MH_GET_GLOBAL_FALLBACK = lookupVirtual("getglobal", MethodType.methodType(PyObject.class, String.class));
+
+	public static Handle makeHandle(String name, String sig, Class<?> methodsClass){
+		return new Handle(Opcodes.H_INVOKESTATIC, p(methodsClass), name, sig);
+	}
+
+	private static MethodHandle lookupVirtual(String name, MethodType type) {
+		try {
+			return lookup().findVirtual(PyFunctionTable.class, name, type);
+		} catch (ReflectiveOperationException e) {
+			throw (AssertionError) new AssertionError().initCause(e);
+		}
+	}
+
+	public static Handle makeIndySupportHandle(String name, String sig) {
+		return makeHandle(name, sig, InvokeDynamicSupport.class);
+	}
+	
+	private static MethodHandle lookupStatic(String name, MethodType type) {
+		try {
+			return lookup().findStatic(InvokeDynamicSupport.class, name, type);
+		} catch (ReflectiveOperationException e) {
+			throw (AssertionError) new AssertionError().initCause(e);
+		}
+	}
+
+	public static CallSite getGlobalBootstrap(Lookup lookup, String name, MethodType type) 
+			throws NoSuchMethodException, IllegalAccessException {
+        GetGlobalCallSite site = new GetGlobalCallSite(type);
+        MethodHandle init = lookup.findStatic(InvokeDynamicSupport.class, "initGetGlobal", 
+        		methodType(PyObject.class, GetGlobalCallSite.class, PyFunctionTable.class, String.class));
+        init = insertArguments(init, 0, site);
+        site.setTarget(init);
+        return site;
+	}
+	
+    public static PyObject initGetGlobal(GetGlobalCallSite site, PyFunctionTable self, String index) throws Throwable {
+//        PyObject value = self.getglobal(index);
+//        MethodHandle target = dropArguments(constant(PyObject.class, value), 0, GetGlobalCallSite.class, PyFunctionTable.class, String.class);
+//        SwitchPoint sp = new SwitchPoint();
+//        target = sp.guardWithTest(target, MH_GET_GLOBAL);
+//        target = insertArguments(target, 0, site);
+//        self.global_sps.put(index, sp);
+//		site.setTarget(target);
+//		if(site.changedCount == GetGlobalCallSite.MAX_CHANGE_COUNT){
+//			self.global_sps.remove(index);
+//			site.setTarget(MH_GET_GLOBAL_FALLBACK);
+//		}
+//        return value;
+    	return null;
+    }
+}

src/org/python/core/opt/JythonCallSite.java

+package org.python.core.opt;
+
+import static org.python.core.opt.SpecializeCallSite.FALLBACK_KW_CS;
+import static org.python.core.opt.SpecializeCallSite.INSTALL_CS;
+import static org.python.core.opt.SpecializeCallSite.INSTALL_TYPED_CS;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles.Lookup;
+import java.lang.invoke.MethodType;
+import java.lang.invoke.MutableCallSite;
+
+class JythonCallsite extends MutableCallSite {
+
+	final String name;
+
+	final Lookup lookup;
+
+	long funcId;
+
+	public JythonCallsite(Lookup lookup, String name, MethodType type) {
+		super(type);
+		this.lookup = lookup;
+		this.name = name;
+
+		setup();
+	}
+
+	private void setup() {
+		MethodHandle target = INSTALL_CS.bindTo(this);
+		target = target.asCollector(Object[].class, type().parameterCount());
+		target = target.asType(type());
+		this.setTarget(target);
+	}
+}
+
+class KeywordCallSite extends JythonCallsite {
+
+	final String[] kws;
+
+	public KeywordCallSite(Lookup lookup, String name, MethodType type,
+			Object[] kws) {
+		super(lookup, name, type);
+		this.kws = new String[kws.length];
+		for (int i = 0; i < kws.length; i++) {
+			this.kws[i] = (String) kws[i];
+		}
+		setup();
+	}
+
+	private void setup() {
+		MethodHandle target = FALLBACK_KW_CS.bindTo(this);
+		target = target.asCollector(Object[].class, this.type()
+				.parameterCount());
+		target = target.asType(this.type());
+		this.setTarget(target);
+	}
+}
+
+class TypedCallSite extends JythonCallsite {
+
+	final String funcType;
+
+	public TypedCallSite(Lookup lookup, String name, MethodType type, Object funcType) {
+		super(lookup, name, type);
+		this.funcType = (String) funcType;
+		setup();
+	}
+
+	private void setup() {
+		MethodHandle target = INSTALL_TYPED_CS.bindTo(this);
+		target = target.asCollector(Object[].class, this.type()
+				.parameterCount());
+		target = target.asType(this.type());
+		this.setTarget(target);
+	}
+}
+
+class GetGlobalCallSite extends MutableCallSite {
+
+	public int changedCount = 0;
+
+	public static final int MAX_CHANGE_COUNT = 12;
+
+	public GetGlobalCallSite(MethodType type) {
+		super(type);
+	}
+
+	@Override
+	public void setTarget(MethodHandle newTarget) {
+		changedCount++;
+		super.setTarget(newTarget);
+	}
+}

src/org/python/core/opt/MethodHandleHelper.java

+package org.python.core.opt;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+
+import org.python.core.PyFrame;
+import org.python.core.PyObject;
+import org.python.core.ThreadState;
+
+
+public class MethodHandleHelper {
+    
+    /** Leading params: <code>PyFrame</code>, <code>ThreadState</code> and <code>PyObject</code> (PyFunction)*/
+    public static final int COMMON_PARAMS_SIZE = 3;
+    
+    public static final int MAX_ARGUMENT_ARITY = 10;
+    
+    public static MethodType getMethodType(int count){
+        
+        if(count > MAX_ARGUMENT_ARITY){
+            count = 0;  // put all the args on the frame.
+        }
+        if(count < 0){
+            return MethodType.methodType(PyObject.class, PyFrame.class, ThreadState.class);
+        }
+        
+        Class[] params = new Class[count + COMMON_PARAMS_SIZE];
+        params[0] = PyFrame.class;      // frame
+        params[1] = ThreadState.class;  // ts
+        params[2] = PyObject.class;     // the PyFunction here
+        
+        for (int i = 0; i < count; i++) {
+            params[COMMON_PARAMS_SIZE + i] = PyObject.class;
+        }
+        
+        return MethodType.methodType(PyObject.class, params);
+    }
+    
+    public static MethodHandle before(MethodHandle target, MethodHandle before) {
+        MethodType beforeType = before.type();
+        if (beforeType.returnType() != void.class) {
+            throw new IllegalArgumentException("before must return void " + beforeType);
+        }
+        MethodType targetType = target.type();
+        if (beforeType.parameterCount() != targetType.parameterCount()) {
+            if (beforeType.parameterCount() > targetType.parameterCount()) {
+                throw new IllegalArgumentException("before has too much parameter compare to target "
+                        + beforeType + " " + targetType);
+            }
+            before = MethodHandles.dropArguments(before,
+                                                 beforeType.parameterCount(),
+                                                 targetType.parameterList()
+                                                         .subList(beforeType.parameterCount(),
+                                                                  targetType.parameterCount()));
+        }
+        if (!before.type().equals(targetType.changeReturnType(void.class))) {
+            throw new IllegalArgumentException("before parameter types are not compatible with target "
+                    + beforeType + " " + targetType);
+        }
+        return MethodHandles.foldArguments(target, before);
+    }
+    
+    
+    public static MethodHandle after(MethodHandle target, MethodHandle after) {
+        //FIXME just use filterReturnValue instead !!, when bug fixed
+        
+        MethodType afterType = after.type();
+        if (afterType.returnType() != void.class) {
+          throw new IllegalArgumentException("after must return void "+afterType);
+        }
+        
+        MethodType targetType = target.type();
+        boolean voidReturnType = targetType.returnType() == void.class;
+        MethodType idealAfterType = (voidReturnType)? targetType:
+            MethodType.methodType(void.class, targetType.returnType()).
+                appendParameterTypes(targetType.parameterList());
+        if (afterType.parameterCount() != idealAfterType.parameterCount()) {
+          if (afterType.parameterCount() > idealAfterType.parameterCount()) {
+            throw new IllegalArgumentException("after has too much parameter compare to return value + target "+afterType+" "+idealAfterType);
+          }
+          
+          after = MethodHandles.dropArguments(after,
+              afterType.parameterCount(),
+              idealAfterType.parameterList().subList(afterType.parameterCount(), idealAfterType.parameterCount()));  
+        }
+        
+        if (!after.type().equals(idealAfterType)) {
+          throw new IllegalArgumentException("after parameter types are not compatible with return value + target "+afterType+" "+idealAfterType);
+        }
+      
+        if (!voidReturnType) {
+          MethodHandle identity = MethodHandles.identity(targetType.returnType());
+          identity = MethodHandles.dropArguments(identity, 1, target.type().parameterList());
+          after = before(identity, after);
+        }  
+        
+        return MethodHandles.foldArguments(after, target);
+    }
+
+    
+}

src/org/python/core/opt/RangeOptimizer.java

+package org.python.core.opt;
+
+import java.lang.invoke.CallSite;
+import java.lang.invoke.ConstantCallSite;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles.Lookup;
+import java.lang.invoke.MethodType;
+import java.lang.invoke.SwitchPoint;
+
+import org.python.core.PyObject;
+
+public abstract class RangeOptimizer {
+
+    public static String className = "org/python/core/opt/RangeOptimizer";
+
+    /**
+     * this switchpoint is accessible from everywhere.. make sure its
+     * invalidated properly FIXME
+     */
+    public static SwitchPoint rangeSwitchPoint = null;
+
+    /**
+     * The bootstrap method for the optimized range and xrange functions inside
+     * a <code>for</code> loop.
+     * 
+     * @param caller
+     * @param name
+     * @param type
+     * @return a ConstantCallSite with a GWT
+     * @throws NoSuchMethodException
+     * @throws IllegalAccessException
+     * @throws ClassNotFoundException
+     */
+    public static CallSite xrangeBsm(Lookup caller, String name, MethodType type)
+            throws NoSuchMethodException, IllegalAccessException,
+            ClassNotFoundException {
+        if (rangeSwitchPoint == null) {
+            rangeSwitchPoint = new SwitchPoint();
+        }
+        MethodHandle fallback = caller.findStatic(RangeOptimizer.class, "xrangeFallback", type);
+        MethodHandle target = caller.findStatic(RangeOptimizer.class, "xrangeTarget", type);
+        return new ConstantCallSite(rangeSwitchPoint.guardWithTest(target, fallback));
+    }
+
+    public static void xrangeFallback(PyObject self) throws Exception {
+        throw new IndyOptimizerException("Need to fall back out of [x]range");
+    }
+
+    public static void xrangeTarget(PyObject self) {
+        return;
+    }
+
+}

src/org/python/core/opt/RuntimeCallHelper.java

+package org.python.core.opt;
+
+import static java.lang.invoke.MethodHandles.dropArguments;
+import static java.lang.invoke.MethodHandles.foldArguments;
+import static java.lang.invoke.MethodHandles.guardWithTest;
+import static java.lang.invoke.MethodHandles.lookup;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodType;
+
+import org.python.core.Py;
+import org.python.core.PyException;
+import org.python.core.PyFrame;
+import org.python.core.PyFunction;
+import org.python.core.PyMethod;
+import org.python.core.PyObject;
+import org.python.core.PySystemState;
+import org.python.core.ThreadState;
+
+
+public class RuntimeCallHelper {
+    
+    public static final int LEADING_NON_ARGS = MethodHandleHelper.COMMON_PARAMS_SIZE;
+    
+    public static final MethodHandle MH_CALL_BEFORE =lookupStatic("callBefore",
+		    MethodType.methodType(PyFrame.class, ThreadState.class, PyObject.class, PyObject[].class));
+
+    public static final MethodHandle MH_CALL_AFTER = lookupStatic("callAfter",
+            MethodType.methodType(Void.TYPE, PyObject.class, ThreadState.class, PyObject.class));
+    
+    public static final MethodHandle MH_CATCH_HANDLER =  lookupStatic("callCatchHandler",
+                MethodHandleHelper.getMethodType(0).insertParameterTypes(0, Throwable.class));
+
+    private static MethodHandle lookupStatic(String name, MethodType type) {
+    	try{
+    		return lookup().findStatic(RuntimeCallHelper.class, name, type);
+    	} catch (ReflectiveOperationException e) {
+			throw (AssertionError)new AssertionError().initCause(e);
+		}
+	}
+
+	public static MethodHandle setupMHForCall(MethodHandle target) {
+        MethodType targetType = target.type();
+        MethodHandle before = MH_CALL_BEFORE.asCollector(PyObject[].class, targetType.parameterCount() - LEADING_NON_ARGS);
+//        Py.writeWarning("SCS", "before collector: " + before);
+//        before = before.asType(targetType.changeReturnType(PyFrame.class));
+//        Py.writeWarning("SCS", "after asType: " + before);
+//        MethodHandle before = MethodHandles.dropArguments(MH_CALL_BEFORE, beforeType.parameterCount(),
+//                                                          targetType.parameterList().subList(3, targetType.parameterCount()));
+        MethodHandle targetWithBefore = foldArguments(target, before);
+        // Py.writeWarning("SCS", "targetWithBefore: " + targetWithBefore);
+        MethodHandle targetWithBF = MethodHandleHelper.after(targetWithBefore, MH_CALL_AFTER);
+        // Py.writeWarning("SCS", "targetWithBF: " + targetWithBF);
+        MethodHandle gwt = setupGWT(targetWithBF, target.type().parameterCount() - LEADING_NON_ARGS);
+        return gwt;
+    }
+    
+    private static MethodHandle setupGWT(MethodHandle target, int paramCount) {
+        target = dropArguments(target, 0, JythonCallsite.class);
+        MethodHandle fallback = SpecializeCallSite.MH_FALLBACK.asCollector(Object[].class, target.type().parameterCount() - 1);
+        fallback = fallback.asType(target.type());
+
+        MethodHandle gwt;
+        MethodHandle test = SpecializeCallSite.MH_TEST.asVarargsCollector(PyObject[].class);
+        test = test.asType(target.type().changeReturnType(boolean.class));
+        gwt = guardWithTest(test, target, fallback);
+        return gwt;
+    }
+
+    
+    public static PyFrame callBefore(ThreadState ts, PyObject func, PyObject[] args){
+        PyFunction pyFunc = null;
+        if (func instanceof PyFunction) {
+            pyFunc = (PyFunction) func;
+        } else if (func instanceof PyMethod) {
+            pyFunc = (PyFunction) ((PyMethod) func).__func__;
+        }
+        PyFrame frame = pyFunc.createFrame();
+//        Py.writeWarning("SCS", "in callBefore");
+        if (ts.systemState == null) {
+            ts.systemState = Py.defaultSystemState;
+        }
+
+        // Push frame
+        frame.f_back = ts.frame;
+        if (frame.f_builtins == null) {
+            if (frame.f_back != null) {
+                frame.f_builtins = frame.f_back.f_builtins;
+            } else {
+                frame.f_builtins = PySystemState.builtins;
+            }
+        }
+        // nested scopes: setup env with closure
+        // this should only be done once, so let the frame take care of it
+//        frame.setupEnv((PyTuple)closure);
+
+        ts.frame = frame;
+        
+        // Cache previously defined exception
+        // previously_exception = ts.exception;
+        for (int i = 0; i < args.length; i++) {
+            frame.f_fastlocals[i] = args[i];
+        }
+        return frame;
+    }
+    
+    public static PyObject callCatchHandler(Throwable t, PyFrame frame, ThreadState ts, PyObject func){
+        // Py.writeWarning("SCS", "in callCatchHandler");
+        // Convert exceptions that occured in Java code to PyExceptions
+        PyException pye = Py.JavaError(t);
+        pye.tracebackHere(frame);
+
+        frame.f_lasti = -1;
+
+        // Rethrow the exception to the next stack frame
+//        ts.exception = previous_exception;
+        ts.frame = ts.frame.f_back;
+        throw pye;
+    }
+    
+    public static void callAfter(PyObject retValue, ThreadState ts, PyObject func){
+//         Py.writeWarning("SCS", "in callAfter");
+        // Restore previously defined exception
+//        ts.exception = previous_exception;
+
+        ts.frame = ts.frame.f_back;        
+    }
+    
+    public static PyObject getSelf(PyMethod method){
+        return method.__self__;
+    }
+    public static PyObject getFunc(PyMethod method){
+        return method.__func__;
+    }
+}

src/org/python/core/opt/SpecializeCallSite.java

+package org.python.core.opt;
+
+import static java.lang.invoke.MethodHandles.lookup;
+
+import java.lang.invoke.CallSite;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import java.lang.invoke.MethodType;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import org.python.core.CodeFlag;
+import org.python.core.Py;
+import org.python.core.PyBaseCode;
+import org.python.core.PyCode;
+import org.python.core.PyFrame;
+import org.python.core.PyFunction;
+import org.python.core.PyFunctionTable;
+import org.python.core.PyMethod;
+import org.python.core.PyMethodCode;
+import org.python.core.PyObject;
+import org.python.core.PyTableCode;
+import org.python.core.PyTuple;
+import org.python.core.ThreadState;
+
+public class SpecializeCallSite {
+    
+    /**
+     * Creates a new PyTableCode object at runtime. Does not a use a MethodHandle.
+     */
+    public static PyCode newCode(int argcount, String varnames[], String filename, String name,
+                                 boolean args, boolean keywords, PyFunctionTable funcs, int func_id,
+                                 String[] cellvars, String[] freevars, int npurecell, int moreflags) {
+         return new PyTableCode(argcount, varnames, filename, name, 0, args, keywords, funcs,
+                 func_id, cellvars, freevars, npurecell, moreflags);
+    }
+
+    /**
+     * Creates a new PyMethodCode object at runtime. Requires a mh to be passed. 
+     */        
+    public static PyCode newCode(int argcount, String varnames[], String filename, String name,
+                                 int firstlineno, boolean args, boolean keywords, PyFunctionTable funcs, 
+                                 int func_id, String[] cellvars, String[] freevars, int npurecell, 
+                                 int moreflags, MethodHandle mHandle, boolean frameless) {
+         return new PyMethodCode(argcount, varnames, filename, name, firstlineno, args, keywords,
+                                     funcs, func_id, cellvars, freevars, npurecell, moreflags, mHandle, 
+                                     frameless);
+    }
+
+    public static CallSite bootstrap(Lookup lookup, String name, MethodType type){
+        return new JythonCallsite(lookup, name, type);
+    }
+    
+    public static CallSite bootstrap(Lookup lookup, String name, MethodType type, Object keyword){
+        return bootstrap(lookup, name, type, new Object[]{keyword});
+    }
+    
+    public static CallSite bootstrap(Lookup lookup, String name, MethodType type, Object[] kws){
+        return new KeywordCallSite(lookup, name, type, kws);
+    }
+    
+    public static CallSite typedBSM(Lookup lookup, String name, MethodType type, Object funcType){
+        return new TypedCallSite(lookup, name, type, funcType);
+    }
+
+    
+    /**
+     * Installs a Keyword version of the Jython Call Site. This looks for defaults and keywords in
+     * the callsite and handles them properly. In every other case, the
+     * {@link #fallback(KeywordCallSite, Object[])} is called.
+     */
+    public static Object installKeywordCS(KeywordCallSite callSite, Object[] args) throws Throwable {
+        if (args[1] instanceof PyFunction) {
+            PyFunction pyFunc = (PyFunction)args[1];
+            PyBaseCode funcCode = (PyBaseCode)pyFunc.__code__;
+            if(funcCode.runtimeInfo.mHandle != null){
+
+                String[] varnames = funcCode.co_varnames;
+                int argCountOfTarget = funcCode.co_argcount + 3;
+                int[] reorder = new int[argCountOfTarget];  // cs, ts, pyfunc + args
+                int argcount = args.length - callSite.kws.length + 1;   // account for cs
+
+//                Py.writeWarning("SCS", "Len: " + callSite.kws.length + " argcount: " + argcount);
+                for (int i = 0; i < argcount; i++) {
+                    reorder[i] = i;
+                }
+
+                for (int i = 0; i < callSite.kws.length; i++) {
+                    String keyword = callSite.kws[i];
+//                PyObject value = args[i + argcount - 1];  // account for callsite by -1
+                    int j;
+                    for (j = 0; j < funcCode.co_argcount; j++) {
+                        if (varnames[j].equals(keyword)) {
+                            break;
+                        }
+                    }
+//                    Py.writeWarning("SCS", "i: " + i + " j: " + j + " Key: " + varnames[j]);
+                    reorder[j + 3] = i + argcount;
+                }
+
+//                System.err.print("installKWCS " + "reorder array: ");
+                int defaults = 0;
+                for (int i = 1; i < reorder.length; i++) {
+                    if(reorder[i] == 0){
+                        defaults ++;
+                    }
+                }
+                int[] permuteArray = new int[reorder.length - defaults];
+                permuteArray[0] = reorder[0];
+                for (int i = 1, j = 1; i < reorder.length; i++) {
+//                    System.err.print(i);
+//                    System.err.print(" ");
+                    if(reorder[i] != 0){
+                        permuteArray[j] = reorder[i];
+                        j++;
+                    }
+                }
+
+                MethodHandle target = getCachedMH(callSite, pyFunc);
+//                Py.writeWarning("installKWCS", "target: " + target);
+                target = fillInDefaults(callSite, pyFunc, target, reorder);
+                target = MethodHandles.permuteArguments(target, target.type(), permuteArray);
+                callSite.funcId = Py.id(pyFunc);
+                target = target.bindTo(callSite);
+                target = target.asType(callSite.type());
+
+                callSite.setTarget(target);
+                return target.invokeWithArguments(args);
+            }
+        }
+//        Py.writeWarning("SCS", "Falling back");
+        return fallback(callSite, args);
+    }
+
+    private static MethodHandle fillInDefaults(KeywordCallSite callSite, PyFunction pyFunc, MethodHandle target, int[] reorder) {
+        int inserted = 0;
+        for (int i = 1; i < reorder.length; i++) {
+            if(reorder[i] == 0){
+                // must be a default
+//                Py.writeWarning("fillInDefault", "inserting def at: " + i + " value: " + pyFunc.func_defaults[i - 3]);
+                target = MethodHandles.insertArguments(target, i - inserted, pyFunc.func_defaults[i - 3]);
+                inserted++;
+            }
+        }
+        return target;
+    }
+    
+    private static MethodHandle fillInDefaults(JythonCallsite callSite, PyFunction pyFunc, MethodHandle target, int argsGiven) {
+        int inserted = 0;
+        int targetCount = ((PyBaseCode)pyFunc.__code__).co_argcount;
+        int defCount = pyFunc.func_defaults == null ? 0 : pyFunc.func_defaults.length; 
+//        System.err.println("Given: " + argsGiven + " targetCount: " + targetCount + " defCount: " + defCount + " mh.params: " + target.type().parameterCount());
+        for (int i = targetCount; i > argsGiven; i--) {
+            int pos = 1 + i /*- inserted*/;
+//            Py.writeWarning("fillInDefault", "inserting def at: " + pos + " value: " + pyFunc.func_defaults[i - argsGiven - 1]);
+            target = MethodHandles.insertArguments(target, pos, pyFunc.func_defaults[i - argsGiven -1]);
+            inserted++;
+        }
+        return target;
+    }
+
+    private static final HashMap<Long, MethodHandle> cachedMHs = new HashMap<Long, MethodHandle>();
+
+    /**
+     * Installs a normal Jython Call Site. A normal Jython Class Site does not have any keywords. If
+     * the called function accepts varargs, then the {@link #varargInvocation()} is invoked, else if
+     * number of arguments passed equals the number of parameters accepted by the callee function,
+     * the target method handle is invoked using the passed args. In all other cases,
+     * {@link #fallback(JythonCallsite, Object[])} is invoked.
+     */
+    public static Object installCS(JythonCallsite callSite, Object[] args) throws Throwable {
+    	// System.err.println("In installCS: " + args[1]);
+
+		if (args[1] instanceof PyFunction) {
+			PyFunction pyFunc = (PyFunction) args[1];
+			int noOfArgs = args.length - 2;
+			if (pyFunc.__code__.runtimeInfo.mHandle != null && commonTest(pyFunc, noOfArgs)) {
+			    if (pyFunc.__code__ instanceof PyBaseCode) {
+	                PyBaseCode fcode = (PyBaseCode)pyFunc.__code__;
+	                if(fcode.varkwargs){
+	                    return fallback(callSite, args);
+	                }
+	                if(fcode.varargs){
+//	                    return fallback(callSite, args);
+                       return varargInvocation(callSite, args);
+	                }
+	                if(noOfArgs == fcode.co_argcount){
+	                    MethodHandle target = getCachedMH(callSite, pyFunc);
+	                    // System.err.println("Target type: " + target);
+	                    target = target.bindTo(callSite);
+	                    target = target.asType(callSite.type());
+	                    // System.err.println("Target: " + target + " callsite type: " + callSite.type());
+	                    
+	                    callSite.setTarget(target);
+	                    return target.invokeWithArguments(args);
+	                }
+			    }
+			}
+		}
+    	return fallback(callSite, args);
+    }
+
+    /**
+     * Invokes a target which expects a vararg in it's parameters. For example consider a function
+     * like this:
+     * 
+     * <pre>
+     *  def foo(a, b, *rest):
+     *      pass
+     * </pre>
+     * 
+     * This method handles all calls to such a function.
+     */
+    private static Object varargInvocation(JythonCallsite callSite, Object[] args) throws Throwable {
+        PyFunction pyFunc = (PyFunction) args[1];
+        PyBaseCode fcode = (PyBaseCode)pyFunc.__code__;
+        
+        MethodHandle target = getCachedMH(callSite, pyFunc);
+        target = target.bindTo(callSite);
+        
+        List<Class<?>> classList = new ArrayList<Class<?>>();
+        int argLen = args.length - 2;   // no of args passed at call site
+        if(argLen > fcode.co_argcount){
+            int dropCount = argLen - fcode.co_argcount; // no of dummy 
+            for (int i = 0; i < dropCount; i++) {
+                classList.add(PyObject.class);
+            }
+            target = MethodHandles.dropArguments(target, fcode.co_argcount + 3, classList);
+        }else{
+            // This call is to a function with default arguments
+            target = fillInDefaults(callSite, pyFunc, target, argLen);
+            // Add a dummy arg for taking the VarArgTuple
+            target = MethodHandles.insertArguments(target, target.type().parameterCount() -1 , new PyTuple());
+            target = target.asType(callSite.type());
+            callSite.setTarget(target);
+            return target.invokeWithArguments(args);
+        }
+        
+        int targetParam = target.type().parameterCount();
+        MethodType desiredType = target.type().insertParameterTypes(0, PyObject.class)
+                                              .dropParameterTypes(targetParam - 1, targetParam);
+        MethodHandle targetWithPermute = MethodHandles.permuteArguments(target, desiredType,
+                                 getVargPermuteArray(desiredType.parameterCount(), fcode.co_argcount));
+        
+        MethodHandle tupleCreator = MH_VARG_TUPLE_CREATOR.asVarargsCollector(PyObject[].class);
+        
+        tupleCreator = tupleCreator.asType(desiredType.dropParameterTypes(0, 1));
+        target = MethodHandles.foldArguments(targetWithPermute, tupleCreator);
+        
+        target = target.asType(callSite.type());
+        callSite.setTarget(target);
+        return target.invokeWithArguments(args);
+    }
+    
+    private static int[] getVargPermuteArray(int paramCount, int co_argcount) {
+        int[] permuteArray = new int[paramCount];
+        int i = 0;
+        // first ts, pyfunc and the required params
+        for (i = 0; i < co_argcount + 2; i++) {
+            permuteArray[i] = i + 1;
+        }
+        
+        // now the varg
+        permuteArray[i] = 0;
+        i++;
+        
+        // finally the dummy args
+        for (; i < permuteArray.length; i++) {
+            permuteArray[i] = i;
+        }
+        return permuteArray;
+    }
+    
+    public static final MethodHandle MH_VARG_TUPLE_CREATOR;
+    
+    static {
+        Lookup lookup = MethodHandles.lookup();
+        try {
+            MH_VARG_TUPLE_CREATOR = lookup.findStatic(SpecializeCallSite.class, "vargTupleCreator",  
+                MethodType.methodType(PyObject.class, ThreadState.class, PyObject.class, PyObject[].class));
+        } catch (ReflectiveOperationException e) {
+          throw (AssertionError)new AssertionError().initCause(e);
+        }
+    }
+    
+    public static PyObject vargTupleCreator(ThreadState ts, PyObject func, PyObject[] args){
+        PyFunction pyFunc = (PyFunction)func;
+        PyBaseCode fcode = (PyBaseCode)pyFunc.__code__;
+        
+        int noOfVarargs = args.length - fcode.co_argcount; // account for ts and pyfunc
+        PyObject[] u = new PyObject[noOfVarargs];
+        System.arraycopy(args, args.length - noOfVarargs, u, 0, noOfVarargs);
+        PyObject uTuple = new PyTuple(u);
+        return uTuple;
+    }
+
+    /**
+     * 
+     * @param callSite
+     * @param args
+     * @return
+     * @throws Throwable
+     */
+    public static Object installTypedCS(TypedCallSite callSite, Object[] args) throws Throwable {
+    	 Object function = args[1];
+    	 int noOfArgs = args.length - 2;
+    	 boolean isPyMethod = false;
+    	 if(function instanceof PyMethod) {
+    	     isPyMethod = true;
+    	     PyMethod method = (PyMethod) function;
+    	     if(method.__self__ != null){
+    	         args[1] = method.__func__;
+    	         noOfArgs++;
+    	     } else {
+    	         // TODO(shashank): handle the unbounded case.
+    	         // TODO(shashank): be sure to check self.
+    	     }
+    	 }
+//    	 System.err.println("In installCS: " + function);
+
+		if (args[1] instanceof PyFunction) {
+			PyFunction pyFunc = (PyFunction) args[1];
+//			System.err.println("installTypedCS: handle: " + pyFunc.__code__.runtimeInfo.mHandle +
+//			        " noOfArgs: " + noOfArgs + " pyFunc: " + ((PyBaseCode) pyFunc.__code__).co_argcount);
+			if (pyFunc.__code__.runtimeInfo.mHandle != null && commonTest(pyFunc, noOfArgs)) {
+			    if (pyFunc.__code__ instanceof PyBaseCode) {
+                    PyBaseCode fcode = (PyBaseCode) pyFunc.__code__;
+	                // TODO(shashank): Handle fcode.varkwargs and fcode.varargs  
+//	                if(fcode.varkwargs){
+//	                    return fallback(callSite, args);
+//	                }
+//	                if(fcode.varargs){
+////	                    return fallback(callSite, args);
+//                       return varargInvocation(callSite, args);
+//	                }
+	                if(noOfArgs == fcode.co_argcount){
+	                    MethodHandle target = getCachedMH(callSite, pyFunc);
+//	                     System.err.println("Target type: " + target);
+//	                     System.err.println("Callsite: " + callSite.type());
+	                    // System.err.println("Installing typedCS");
+//	                    String[] pTypes = callSite.funcType.split(",");
+//	                    for (int i = 0; i < pTypes.length; i++) {
+//	                    	System.err.println("pType: " + pTypes[i] + " arg: " + args[i + 2]);
+//						}
+	                    target = target.bindTo(callSite);
+	                    if(isPyMethod){
+	                        target = MethodHandles.insertArguments(target, 2,
+	                                ((PyMethod) function).__self__);
+	                    }
+//	                    System.err.println("Target: " + target + " callsite type: " + callSite.type());
+	                    target = target.asType(callSite.type());
+
+	                    callSite.setTarget(target);
+	                    return target.invokeWithArguments(args);
+	                }
+			    }
+			}
+		}
+    	return fallback(callSite, args);
+    }
+    
+    private static MethodHandle getCachedMH(JythonCallsite callSite, PyFunction pyFunc)
+            throws Exception {
+        MethodHandle target = cachedMHs.get(Py.id(pyFunc));
+        if (target == null) {
+            target = pyFunc.__code__.runtimeInfo.mHandle;
+            if (!((PyBaseCode) pyFunc.__code__).runtimeInfo.frameless) {
+                target = RuntimeCallHelper.setupMHForCall(target);
+            } else {
+                // System.err.println("Frameless code! (dispatching via MHs) target: "
+                // + target);
+                // PyFrame is null
+                target = target.bindTo(null);
+                // System.err.println("After binding target to PyFrame:" +
+                // target);
+                target = MethodHandles.dropArguments(target, 0, JythonCallsite.class);
+            }
+            callSite.funcId = Py.id(pyFunc);
+            cachedMHs.put(Py.id(pyFunc), target);
+//            System.err.println("before cast: " + target);
+            target = pyFunc.__code__.runtimeInfo.mHandle;
+//            System.err.println("after cast: " + target);
+        }
+        if (callSite.funcId == 0) {
+            callSite.funcId = Py.id(pyFunc);
+        }
+        return target;
+    }
+
+    /**
+     * Fallback to using internal Jython logic to dispatc