private static void generateCtor( ClassFileWriter cfw, String adapterName, String superName, Constructor<?> superCtor) { short locals = 3; // this + factory + delegee Class<?>[] parameters = superCtor.getParameterTypes(); // Note that we swapped arguments in app-facing constructors to avoid // conflicting signatures with serial constructor defined below. if (parameters.length == 0) { cfw.startMethod( "<init>", "(Laurora/javascript/Scriptable;" + "Laurora/javascript/ContextFactory;)V", ClassFileWriter.ACC_PUBLIC); // Invoke base class constructor cfw.add(ByteCode.ALOAD_0); // this cfw.addInvoke(ByteCode.INVOKESPECIAL, superName, "<init>", "()V"); } else { StringBuilder sig = new StringBuilder( "(Laurora/javascript/Scriptable;" + "Laurora/javascript/ContextFactory;"); int marker = sig.length(); // lets us reuse buffer for super signature for (Class<?> c : parameters) { appendTypeString(sig, c); } sig.append(")V"); cfw.startMethod("<init>", sig.toString(), ClassFileWriter.ACC_PUBLIC); // Invoke base class constructor cfw.add(ByteCode.ALOAD_0); // this short paramOffset = 3; for (Class<?> parameter : parameters) { paramOffset += generatePushParam(cfw, paramOffset, parameter); } locals = paramOffset; sig.delete(1, marker); cfw.addInvoke(ByteCode.INVOKESPECIAL, superName, "<init>", sig.toString()); } // Save parameter in instance variable "delegee" cfw.add(ByteCode.ALOAD_0); // this cfw.add(ByteCode.ALOAD_1); // first arg: Scriptable delegee cfw.add(ByteCode.PUTFIELD, adapterName, "delegee", "Laurora/javascript/Scriptable;"); // Save parameter in instance variable "factory" cfw.add(ByteCode.ALOAD_0); // this cfw.add(ByteCode.ALOAD_2); // second arg: ContextFactory instance cfw.add(ByteCode.PUTFIELD, adapterName, "factory", "Laurora/javascript/ContextFactory;"); cfw.add(ByteCode.ALOAD_0); // this for the following PUTFIELD for self // create a wrapper object to be used as "this" in method calls cfw.add(ByteCode.ALOAD_1); // the Scriptable delegee cfw.add(ByteCode.ALOAD_0); // this cfw.addInvoke( ByteCode.INVOKESTATIC, "aurora/javascript/JavaAdapter", "createAdapterWrapper", "(Laurora/javascript/Scriptable;" + "Ljava/lang/Object;" + ")Laurora/javascript/Scriptable;"); cfw.add(ByteCode.PUTFIELD, adapterName, "self", "Laurora/javascript/Scriptable;"); cfw.add(ByteCode.RETURN); cfw.stopMethod(locals); }
private static void generateMethod( ClassFileWriter cfw, String genName, String methodName, Class<?>[] parms, Class<?> returnType, boolean convertResult) { StringBuilder sb = new StringBuilder(); int paramsEnd = appendMethodSignature(parms, returnType, sb); String methodSignature = sb.toString(); cfw.startMethod(methodName, methodSignature, ClassFileWriter.ACC_PUBLIC); // Prepare stack to call method // push factory cfw.add(ByteCode.ALOAD_0); cfw.add(ByteCode.GETFIELD, genName, "factory", "Laurora/javascript/ContextFactory;"); // push self cfw.add(ByteCode.ALOAD_0); cfw.add(ByteCode.GETFIELD, genName, "self", "Laurora/javascript/Scriptable;"); // push function cfw.add(ByteCode.ALOAD_0); cfw.add(ByteCode.GETFIELD, genName, "delegee", "Laurora/javascript/Scriptable;"); cfw.addPush(methodName); cfw.addInvoke( ByteCode.INVOKESTATIC, "aurora/javascript/JavaAdapter", "getFunction", "(Laurora/javascript/Scriptable;" + "Ljava/lang/String;" + ")Laurora/javascript/Function;"); // push arguments generatePushWrappedArgs(cfw, parms, parms.length); // push bits to indicate which parameters should be wrapped if (parms.length > 64) { // If it will be an issue, then passing a static boolean array // can be an option, but for now using simple bitmask throw Context.reportRuntimeError0( "JavaAdapter can not subclass methods with more then" + " 64 arguments."); } long convertionMask = 0; for (int i = 0; i != parms.length; ++i) { if (!parms[i].isPrimitive()) { convertionMask |= (1 << i); } } cfw.addPush(convertionMask); // go through utility method, which creates a Context to run the // method in. cfw.addInvoke( ByteCode.INVOKESTATIC, "aurora/javascript/JavaAdapter", "callMethod", "(Laurora/javascript/ContextFactory;" + "Laurora/javascript/Scriptable;" + "Laurora/javascript/Function;" + "[Ljava/lang/Object;" + "J" + ")Ljava/lang/Object;"); generateReturnResult(cfw, returnType, convertResult); cfw.stopMethod((short) paramsEnd); }
/** Returns a fully qualified method name concatenated with its signature. */ private static String getMethodSignature(Method method, Class<?>[] argTypes) { StringBuilder sb = new StringBuilder(); appendMethodSignature(argTypes, method.getReturnType(), sb); return sb.toString(); }