?? javaadapter.java
字號:
cfw.add(ByteCode.I2D); break; case 'l': // load a long, convert to double. cfw.add(ByteCode.LLOAD, paramOffset); cfw.add(ByteCode.L2D); size = 2; break; case 'f': // load a float, convert to double. cfw.add(ByteCode.FLOAD, paramOffset); cfw.add(ByteCode.F2D); break; case 'd': cfw.add(ByteCode.DLOAD, paramOffset); size = 2; break; } cfw.addInvoke(ByteCode.INVOKESPECIAL, "java/lang/Double", "<init>", "(D)V"); } return size; } /** * Generates code to convert a wrapped value type to a primitive type. * Handles unwrapping java.lang.Boolean, and java.lang.Number types. * Generates the appropriate RETURN bytecode. */ static void generateReturnResult(ClassFileWriter cfw, Class retType, boolean callConvertResult) { // wrap boolean values with java.lang.Boolean, convert all other // primitive values to java.lang.Double. if (retType == Void.TYPE) { cfw.add(ByteCode.POP); cfw.add(ByteCode.RETURN); } else if (retType == Boolean.TYPE) { cfw.addInvoke(ByteCode.INVOKESTATIC, "org/mozilla/javascript/Context", "toBoolean", "(Ljava/lang/Object;)Z"); cfw.add(ByteCode.IRETURN); } else if (retType == Character.TYPE) { // characters are represented as strings in JavaScript. // return the first character. // first convert the value to a string if possible. cfw.addInvoke(ByteCode.INVOKESTATIC, "org/mozilla/javascript/Context", "toString", "(Ljava/lang/Object;)Ljava/lang/String;"); cfw.add(ByteCode.ICONST_0); cfw.addInvoke(ByteCode.INVOKEVIRTUAL, "java/lang/String", "charAt", "(I)C"); cfw.add(ByteCode.IRETURN); } else if (retType.isPrimitive()) { cfw.addInvoke(ByteCode.INVOKESTATIC, "org/mozilla/javascript/Context", "toNumber", "(Ljava/lang/Object;)D"); String typeName = retType.getName(); switch (typeName.charAt(0)) { case 'b': case 's': case 'i': cfw.add(ByteCode.D2I); cfw.add(ByteCode.IRETURN); break; case 'l': cfw.add(ByteCode.D2L); cfw.add(ByteCode.LRETURN); break; case 'f': cfw.add(ByteCode.D2F); cfw.add(ByteCode.FRETURN); break; case 'd': cfw.add(ByteCode.DRETURN); break; default: throw new RuntimeException("Unexpected return type " + retType.toString()); } } else { String retTypeStr = retType.getName(); if (callConvertResult) { cfw.addLoadConstant(retTypeStr); cfw.addInvoke(ByteCode.INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;"); cfw.addInvoke(ByteCode.INVOKESTATIC, "org/mozilla/javascript/JavaAdapter", "convertResult", "(Ljava/lang/Object;" +"Ljava/lang/Class;" +")Ljava/lang/Object;"); } // Now cast to return type cfw.add(ByteCode.CHECKCAST, retTypeStr); cfw.add(ByteCode.ARETURN); } } private static void generateMethod(ClassFileWriter cfw, String genName, String methodName, Class[] parms, Class returnType) { StringBuffer sb = new StringBuffer(); int paramsEnd = appendMethodSignature(parms, returnType, sb); String methodSignature = sb.toString(); cfw.startMethod(methodName, methodSignature, ClassFileWriter.ACC_PUBLIC); // Prepare stack to call calMethod // push factory cfw.add(ByteCode.ALOAD_0); cfw.add(ByteCode.GETFIELD, genName, "factory", "Lorg/mozilla/javascript/ContextFactory;"); // push self cfw.add(ByteCode.ALOAD_0); cfw.add(ByteCode.GETFIELD, genName, "self", "Lorg/mozilla/javascript/Scriptable;"); // push function cfw.add(ByteCode.ALOAD_0); cfw.add(ByteCode.GETFIELD, genName, "delegee", "Lorg/mozilla/javascript/Scriptable;"); cfw.addPush(methodName); cfw.addInvoke(ByteCode.INVOKESTATIC, "org/mozilla/javascript/JavaAdapter", "getFunction", "(Lorg/mozilla/javascript/Scriptable;" +"Ljava/lang/String;" +")Lorg/mozilla/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, "org/mozilla/javascript/JavaAdapter", "callMethod", "(Lorg/mozilla/javascript/ContextFactory;" +"Lorg/mozilla/javascript/Scriptable;" +"Lorg/mozilla/javascript/Function;" +"[Ljava/lang/Object;" +"J" +")Ljava/lang/Object;"); generateReturnResult(cfw, returnType, true); cfw.stopMethod((short)paramsEnd); } /** * Generates code to push typed parameters onto the operand stack * prior to a direct Java method call. */ private static int generatePushParam(ClassFileWriter cfw, int paramOffset, Class paramType) { if (!paramType.isPrimitive()) { cfw.addALoad(paramOffset); return 1; } String typeName = paramType.getName(); switch (typeName.charAt(0)) { case 'z': case 'b': case 'c': case 's': case 'i': // load an int value, convert to double. cfw.addILoad(paramOffset); return 1; case 'l': // load a long, convert to double. cfw.addLLoad(paramOffset); return 2; case 'f': // load a float, convert to double. cfw.addFLoad(paramOffset); return 1; case 'd': cfw.addDLoad(paramOffset); return 2; } throw Kit.codeBug(); } /** * Generates code to return a Java type, after calling a Java method * that returns the same type. * Generates the appropriate RETURN bytecode. */ private static void generatePopResult(ClassFileWriter cfw, Class retType) { if (retType.isPrimitive()) { String typeName = retType.getName(); switch (typeName.charAt(0)) { case 'b': case 'c': case 's': case 'i': case 'z': cfw.add(ByteCode.IRETURN); break; case 'l': cfw.add(ByteCode.LRETURN); break; case 'f': cfw.add(ByteCode.FRETURN); break; case 'd': cfw.add(ByteCode.DRETURN); break; } } else { cfw.add(ByteCode.ARETURN); } } /** * Generates a method called "super$methodName()" which can be called * from JavaScript that is equivalent to calling "super.methodName()" * from Java. Eventually, this may be supported directly in JavaScript. */ private static void generateSuper(ClassFileWriter cfw, String genName, String superName, String methodName, String methodSignature, Class[] parms, Class returnType) { cfw.startMethod("super$" + methodName, methodSignature, ClassFileWriter.ACC_PUBLIC); // push "this" cfw.add(ByteCode.ALOAD, 0); // push the rest of the parameters. int paramOffset = 1; for (int i = 0; i < parms.length; i++) { paramOffset += generatePushParam(cfw, paramOffset, parms[i]); } // call the superclass implementation of the method. cfw.addInvoke(ByteCode.INVOKESPECIAL, superName, methodName, methodSignature); // now, handle the return type appropriately. Class retType = returnType; if (!retType.equals(Void.TYPE)) { generatePopResult(cfw, retType); } else { cfw.add(ByteCode.RETURN); } cfw.stopMethod((short)(paramOffset + 1)); } /** * Returns a fully qualified method name concatenated with its signature. */ private static String getMethodSignature(Method method, Class[] argTypes) { StringBuffer sb = new StringBuffer(); appendMethodSignature(argTypes, method.getReturnType(), sb); return sb.toString(); } static int appendMethodSignature(Class[] argTypes, Class returnType, StringBuffer sb) { sb.append('('); int firstLocal = 1 + argTypes.length; // includes this. for (int i = 0; i < argTypes.length; i++) { Class type = argTypes[i]; appendTypeString(sb, type); if (type == Long.TYPE || type == Double.TYPE) { // adjust for duble slot ++firstLocal; } } sb.append(')'); appendTypeString(sb, returnType); return firstLocal; } private static StringBuffer appendTypeString(StringBuffer 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; } static int[] getArgsToConvert(Class[] argTypes) { int count = 0; for (int i = 0; i != argTypes.length; ++i) { if (!argTypes[i].isPrimitive()) ++count; } if (count == 0) return null; int[] array = new int[count]; count = 0; for (int i = 0; i != argTypes.length; ++i) { if (!argTypes[i].isPrimitive()) array[count++] = i; } return array; } private static final Object FTAG = new Object(); private static final int Id_JavaAdapter = 1;}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -