Beispiel #1
0
 static int appendMethodSignature(Class<?>[] argTypes, Class<?> returnType, StringBuilder sb) {
   sb.append('(');
   int firstLocal = 1 + argTypes.length; // includes this.
   for (Class<?> type : argTypes) {
     appendTypeString(sb, type);
     if (type == Long.TYPE || type == Double.TYPE) {
       // adjust for double slot
       ++firstLocal;
     }
   }
   sb.append(')');
   appendTypeString(sb, returnType);
   return firstLocal;
 }
Beispiel #2
0
 private static StringBuilder appendTypeString(StringBuilder sb, Class<?> type) {
   while (type.isArray()) {
     sb.append('[');
     type = type.getComponentType();
   }
   if (type.isPrimitive()) {
     char typeLetter;
     if (type == Boolean.TYPE) {
       typeLetter = 'Z';
     } else if (type == Long.TYPE) {
       typeLetter = 'J';
     } else {
       String typeName = type.getName();
       typeLetter = Character.toUpperCase(typeName.charAt(0));
     }
     sb.append(typeLetter);
   } else {
     sb.append('L');
     sb.append(type.getName().replace('.', '/'));
     sb.append(';');
   }
   return sb;
 }
Beispiel #3
0
  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);
  }
Beispiel #4
0
  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);
  }
Beispiel #5
0
 /** 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();
 }