📄 javaadapter.java
字号:
} catch (NoSuchMethodException e) { // Not implemented by superclass; fall through } } // make sure to generate only one instance of a particular // method/signature. String methodSignature = getMethodSignature(method, argTypes); String methodKey = methodName + methodSignature; if (! generatedOverrides.has(methodKey)) { generateMethod(cfw, adapterName, methodName, argTypes, method.getReturnType()); generatedOverrides.put(methodKey, 0); generatedMethods.put(methodName, 0); } } } // Now, go through the superclass's methods, checking for abstract // methods or additional methods to override. // generate any additional overrides that the object might contain. Method[] methods = getOverridableMethods(superClass); for (int j = 0; j < methods.length; j++) { Method method = methods[j]; int mods = method.getModifiers(); // if a method is marked abstract, must implement it or the // resulting class won't be instantiable. otherwise, if the object // has a property of the same name, then an override is intended. boolean isAbstractMethod = Modifier.isAbstract(mods); String methodName = method.getName(); if (isAbstractMethod || functionNames.has(methodName)) { // make sure to generate only one instance of a particular // method/signature. Class[] argTypes = method.getParameterTypes(); String methodSignature = getMethodSignature(method, argTypes); String methodKey = methodName + methodSignature; if (! generatedOverrides.has(methodKey)) { generateMethod(cfw, adapterName, methodName, argTypes, method.getReturnType()); generatedOverrides.put(methodKey, 0); generatedMethods.put(methodName, 0); // if a method was overridden, generate a "super$method" // which lets the delegate call the superclass' version. if (!isAbstractMethod) { generateSuper(cfw, adapterName, superName, methodName, methodSignature, argTypes, method.getReturnType()); } } } } // Generate Java methods for remaining properties that are not // overrides. ObjToIntMap.Iterator iter = new ObjToIntMap.Iterator(functionNames); for (iter.start(); !iter.done(); iter.next()) { String functionName = (String)iter.getKey(); if (generatedMethods.has(functionName)) continue; int length = iter.getValue(); Class[] parms = new Class[length]; for (int k=0; k < length; k++) parms[k] = ScriptRuntime.ObjectClass; generateMethod(cfw, adapterName, functionName, parms, ScriptRuntime.ObjectClass); } return cfw.toByteArray(); } static Method[] getOverridableMethods(Class c) { ArrayList<Method> list = new ArrayList<Method>(); HashSet<String> skip = new HashSet<String>(); while (c != null) { Method[] methods = c.getDeclaredMethods(); for (int i = 0; i < methods.length; i++) { String methodKey = methods[i].getName() + getMethodSignature(methods[i], methods[i].getParameterTypes()); if (skip.contains(methodKey)) continue; // skip this method int mods = methods[i].getModifiers(); if (Modifier.isStatic(mods)) continue; if (Modifier.isFinal(mods)) { // Make sure we don't add a final method to the list // of overridable methods. skip.add(methodKey); continue; } if (Modifier.isPublic(mods) || Modifier.isProtected(mods)) { list.add(methods[i]); skip.add(methodKey); } } c = c.getSuperclass(); } return list.toArray(new Method[list.size()]); } static Class loadAdapterClass(String className, byte[] classBytes) { Object staticDomain; Class domainClass = SecurityController.getStaticSecurityDomainClass(); if(domainClass == CodeSource.class || domainClass == ProtectionDomain.class) { ProtectionDomain protectionDomain = JavaAdapter.class.getProtectionDomain(); if(domainClass == CodeSource.class) { staticDomain = protectionDomain == null ? null : protectionDomain.getCodeSource(); } else { staticDomain = protectionDomain; } } else { staticDomain = null; } GeneratedClassLoader loader = SecurityController.createLoader(null, staticDomain); Class result = loader.defineClass(className, classBytes); loader.linkClass(result); return result; } public static Function getFunction(Scriptable obj, String functionName) { Object x = ScriptableObject.getProperty(obj, functionName); if (x == Scriptable.NOT_FOUND) { // This method used to swallow the exception from calling // an undefined method. People have come to depend on this // somewhat dubious behavior. It allows people to avoid // implementing listener methods that they don't care about, // for instance. return null; } if (!(x instanceof Function)) throw ScriptRuntime.notFunctionError(x, functionName); return (Function)x; } /** * Utility method which dynamically binds a Context to the current thread, * if none already exists. */ public static Object callMethod(ContextFactory factory, final Scriptable thisObj, final Function f, final Object[] args, final long argsToWrap) { if (f == null) { // See comments in getFunction return Undefined.instance; } if (factory == null) { factory = ContextFactory.getGlobal(); } final Scriptable scope = f.getParentScope(); if (argsToWrap == 0) { return Context.call(factory, f, scope, thisObj, args); } Context cx = Context.getCurrentContext(); if (cx != null) { return doCall(cx, scope, thisObj, f, args, argsToWrap); } else { return factory.call(new ContextAction() { public Object run(Context cx) { return doCall(cx, scope, thisObj, f, args, argsToWrap); } }); } } private static Object doCall(Context cx, Scriptable scope, Scriptable thisObj, Function f, Object[] args, long argsToWrap) { // Wrap the rest of objects for (int i = 0; i != args.length; ++i) { if (0 != (argsToWrap & (1 << i))) { Object arg = args[i]; if (!(arg instanceof Scriptable)) { args[i] = cx.getWrapFactory().wrap(cx, scope, arg, null); } } } return f.call(cx, scope, thisObj, args); } public static Scriptable runScript(final Script script) { return (Scriptable)Context.call(new ContextAction() { public Object run(Context cx) { ScriptableObject global = ScriptRuntime.getGlobal(cx); script.exec(cx, global); return global; } }); } private static void generateCtor(ClassFileWriter cfw, String adapterName, String superName) { cfw.startMethod("<init>", "(Lorg/mozilla/javascript/ContextFactory;" +"Lorg/mozilla/javascript/Scriptable;)V", ClassFileWriter.ACC_PUBLIC); // Invoke base class constructor cfw.add(ByteCode.ALOAD_0); // this cfw.addInvoke(ByteCode.INVOKESPECIAL, superName, "<init>", "()V"); // Save parameter in instance variable "factory" cfw.add(ByteCode.ALOAD_0); // this cfw.add(ByteCode.ALOAD_1); // first arg: ContextFactory instance cfw.add(ByteCode.PUTFIELD, adapterName, "factory", "Lorg/mozilla/javascript/ContextFactory;"); // Save parameter in instance variable "delegee" cfw.add(ByteCode.ALOAD_0); // this cfw.add(ByteCode.ALOAD_2); // second arg: Scriptable delegee cfw.add(ByteCode.PUTFIELD, adapterName, "delegee", "Lorg/mozilla/javascript/Scriptable;"); 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_2); // the Scriptable delegee cfw.add(ByteCode.ALOAD_0); // this cfw.addInvoke(ByteCode.INVOKESTATIC, "org/mozilla/javascript/JavaAdapter", "createAdapterWrapper", "(Lorg/mozilla/javascript/Scriptable;" +"Ljava/lang/Object;" +")Lorg/mozilla/javascript/Scriptable;"); cfw.add(ByteCode.PUTFIELD, adapterName, "self", "Lorg/mozilla/javascript/Scriptable;"); cfw.add(ByteCode.RETURN); cfw.stopMethod((short)3); // 3: this + factory + delegee } private static void generateSerialCtor(ClassFileWriter cfw, String adapterName, String superName) { cfw.startMethod("<init>", "(Lorg/mozilla/javascript/ContextFactory;" +"Lorg/mozilla/javascript/Scriptable;" +"Lorg/mozilla/javascript/Scriptable;" +")V", ClassFileWriter.ACC_PUBLIC); // Invoke base class constructor cfw.add(ByteCode.ALOAD_0); // this cfw.addInvoke(ByteCode.INVOKESPECIAL, superName, "<init>", "()V"); // Save parameter in instance variable "factory" cfw.add(ByteCode.ALOAD_0); // this cfw.add(ByteCode.ALOAD_1); // first arg: ContextFactory instance cfw.add(ByteCode.PUTFIELD, adapterName, "factory", "Lorg/mozilla/javascript/ContextFactory;"); // Save parameter in instance variable "delegee" cfw.add(ByteCode.ALOAD_0); // this cfw.add(ByteCode.ALOAD_2); // second arg: Scriptable delegee cfw.add(ByteCode.PUTFIELD, adapterName, "delegee", "Lorg/mozilla/javascript/Scriptable;"); // save self cfw.add(ByteCode.ALOAD_0); // this cfw.add(ByteCode.ALOAD_3); // second arg: Scriptable self cfw.add(ByteCode.PUTFIELD, adapterName, "self", "Lorg/mozilla/javascript/Scriptable;"); cfw.add(ByteCode.RETURN); cfw.stopMethod((short)4); // 4: this + factory + delegee + self } private static void generateEmptyCtor(ClassFileWriter cfw, String adapterName, String superName, String scriptClassName) { cfw.startMethod("<init>", "()V", ClassFileWriter.ACC_PUBLIC); // Invoke base class constructor cfw.add(ByteCode.ALOAD_0); // this cfw.addInvoke(ByteCode.INVOKESPECIAL, superName, "<init>", "()V"); // Set factory to null to use current global when necessary cfw.add(ByteCode.ALOAD_0); cfw.add(ByteCode.ACONST_NULL); cfw.add(ByteCode.PUTFIELD, adapterName, "factory", "Lorg/mozilla/javascript/ContextFactory;"); // Load script class cfw.add(ByteCode.NEW, scriptClassName); cfw.add(ByteCode.DUP); cfw.addInvoke(ByteCode.INVOKESPECIAL, scriptClassName, "<init>", "()V"); // Run script and save resulting scope cfw.addInvoke(ByteCode.INVOKESTATIC, "org/mozilla/javascript/JavaAdapter", "runScript", "(Lorg/mozilla/javascript/Script;" +")Lorg/mozilla/javascript/Scriptable;"); cfw.add(ByteCode.ASTORE_1); // Save the Scriptable in instance variable "delegee" cfw.add(ByteCode.ALOAD_0); // this cfw.add(ByteCode.ALOAD_1); // the Scriptable cfw.add(ByteCode.PUTFIELD, adapterName, "delegee", "Lorg/mozilla/javascript/Scriptable;"); 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 cfw.add(ByteCode.ALOAD_0); // this cfw.addInvoke(ByteCode.INVOKESTATIC, "org/mozilla/javascript/JavaAdapter", "createAdapterWrapper", "(Lorg/mozilla/javascript/Scriptable;" +"Ljava/lang/Object;" +")Lorg/mozilla/javascript/Scriptable;"); cfw.add(ByteCode.PUTFIELD, adapterName, "self", "Lorg/mozilla/javascript/Scriptable;"); cfw.add(ByteCode.RETURN); cfw.stopMethod((short)2); // this + delegee } /** * Generates code to wrap Java arguments into Object[]. * Non-primitive Java types are left as-is pending conversion * in the helper method. Leaves the array object on the top of the stack. */ static void generatePushWrappedArgs(ClassFileWriter cfw, Class[] argTypes, int arrayLength) { // push arguments cfw.addPush(arrayLength); cfw.add(ByteCode.ANEWARRAY, "java/lang/Object"); int paramOffset = 1; for (int i = 0; i != argTypes.length; ++i) { cfw.add(ByteCode.DUP); // duplicate array reference cfw.addPush(i); paramOffset += generateWrapArg(cfw, paramOffset, argTypes[i]); cfw.add(ByteCode.AASTORE); } } /** * Generates code to wrap Java argument into Object. * Non-primitive Java types are left unconverted pending conversion * in the helper method. Leaves the wrapper object on the top of the stack. */ private static int generateWrapArg(ClassFileWriter cfw, int paramOffset, Class argType) { int size = 1; if (!argType.isPrimitive()) { cfw.add(ByteCode.ALOAD, paramOffset); } else if (argType == Boolean.TYPE) { // wrap boolean values with java.lang.Boolean. cfw.add(ByteCode.NEW, "java/lang/Boolean"); cfw.add(ByteCode.DUP); cfw.add(ByteCode.ILOAD, paramOffset); cfw.addInvoke(ByteCode.INVOKESPECIAL, "java/lang/Boolean", "<init>", "(Z)V"); } else if (argType == Character.TYPE) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -