aboutsummaryrefslogtreecommitdiffstats
path: root/infrastructure/rhino1_7R1/src/org/mozilla/javascript/JavaAdapter.java
diff options
context:
space:
mode:
Diffstat (limited to 'infrastructure/rhino1_7R1/src/org/mozilla/javascript/JavaAdapter.java')
-rw-r--r--infrastructure/rhino1_7R1/src/org/mozilla/javascript/JavaAdapter.java1129
1 files changed, 0 insertions, 1129 deletions
diff --git a/infrastructure/rhino1_7R1/src/org/mozilla/javascript/JavaAdapter.java b/infrastructure/rhino1_7R1/src/org/mozilla/javascript/JavaAdapter.java
deleted file mode 100644
index 6e0a827..0000000
--- a/infrastructure/rhino1_7R1/src/org/mozilla/javascript/JavaAdapter.java
+++ /dev/null
@@ -1,1129 +0,0 @@
-/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- *
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Rhino code, released
- * May 6, 1999.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1997-1999
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Patrick Beard
- * Norris Boyd
- * Igor Bukanov
- * Mike McCabe
- * Matthias Radestock
- * Andi Vajda
- * Andrew Wason
- * Kemal Bayram
- *
- * Alternatively, the contents of this file may be used under the terms of
- * the GNU General Public License Version 2 or later (the "GPL"), in which
- * case the provisions of the GPL are applicable instead of those above. If
- * you wish to allow use of your version of this file only under the terms of
- * the GPL and not to allow others to use your version of this file under the
- * MPL, indicate your decision by deleting the provisions above and replacing
- * them with the notice and other provisions required by the GPL. If you do
- * not delete the provisions above, a recipient may use your version of this
- * file under either the MPL or the GPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-package org.mozilla.javascript;
-
-import org.mozilla.classfile.*;
-import java.lang.reflect.*;
-import java.io.*;
-import java.security.*;
-import java.util.*;
-
-public final class JavaAdapter implements IdFunctionCall
-{
- /**
- * Provides a key with which to distinguish previously generated
- * adapter classes stored in a hash table.
- */
- static class JavaAdapterSignature
- {
- Class superClass;
- Class[] interfaces;
- ObjToIntMap names;
-
- JavaAdapterSignature(Class superClass, Class[] interfaces,
- ObjToIntMap names)
- {
- this.superClass = superClass;
- this.interfaces = interfaces;
- this.names = names;
- }
-
- public boolean equals(Object obj)
- {
- if (!(obj instanceof JavaAdapterSignature))
- return false;
- JavaAdapterSignature sig = (JavaAdapterSignature) obj;
- if (superClass != sig.superClass)
- return false;
- if (interfaces != sig.interfaces) {
- if (interfaces.length != sig.interfaces.length)
- return false;
- for (int i=0; i < interfaces.length; i++)
- if (interfaces[i] != sig.interfaces[i])
- return false;
- }
- if (names.size() != sig.names.size())
- return false;
- ObjToIntMap.Iterator iter = new ObjToIntMap.Iterator(names);
- for (iter.start(); !iter.done(); iter.next()) {
- String name = (String)iter.getKey();
- int arity = iter.getValue();
- if (arity != names.get(name, arity + 1))
- return false;
- }
- return true;
- }
-
- public int hashCode()
- {
- return superClass.hashCode()
- | (0x9e3779b9 * (names.size() | (interfaces.length << 16)));
- }
- }
-
- public static void init(Context cx, Scriptable scope, boolean sealed)
- {
- JavaAdapter obj = new JavaAdapter();
- IdFunctionObject ctor = new IdFunctionObject(obj, FTAG, Id_JavaAdapter,
- "JavaAdapter", 1, scope);
- ctor.markAsConstructor(null);
- if (sealed) {
- ctor.sealObject();
- }
- ctor.exportAsScopeProperty();
- }
-
- public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope,
- Scriptable thisObj, Object[] args)
- {
- if (f.hasTag(FTAG)) {
- if (f.methodId() == Id_JavaAdapter) {
- return js_createAdapter(cx, scope, args);
- }
- }
- throw f.unknown();
- }
-
- public static Object convertResult(Object result, Class c)
- {
- if (result == Undefined.instance &&
- (c != ScriptRuntime.ObjectClass &&
- c != ScriptRuntime.StringClass))
- {
- // Avoid an error for an undefined value; return null instead.
- return null;
- }
- return Context.jsToJava(result, c);
- }
-
- public static Scriptable createAdapterWrapper(Scriptable obj,
- Object adapter)
- {
- Scriptable scope = ScriptableObject.getTopLevelScope(obj);
- NativeJavaObject res = new NativeJavaObject(scope, adapter, null, true);
- res.setPrototype(obj);
- return res;
- }
-
- public static Object getAdapterSelf(Class adapterClass, Object adapter)
- throws NoSuchFieldException, IllegalAccessException
- {
- Field self = adapterClass.getDeclaredField("self");
- return self.get(adapter);
- }
-
- static Object js_createAdapter(Context cx, Scriptable scope, Object[] args)
- {
- int N = args.length;
- if (N == 0) {
- throw ScriptRuntime.typeError0("msg.adapter.zero.args");
- }
-
- Class superClass = null;
- Class[] intfs = new Class[N - 1];
- int interfaceCount = 0;
- for (int i = 0; i != N - 1; ++i) {
- Object arg = args[i];
- if (!(arg instanceof NativeJavaClass)) {
- throw ScriptRuntime.typeError2("msg.not.java.class.arg",
- String.valueOf(i),
- ScriptRuntime.toString(arg));
- }
- Class c = ((NativeJavaClass) arg).getClassObject();
- if (!c.isInterface()) {
- if (superClass != null) {
- throw ScriptRuntime.typeError2("msg.only.one.super",
- superClass.getName(), c.getName());
- }
- superClass = c;
- } else {
- intfs[interfaceCount++] = c;
- }
- }
-
- if (superClass == null)
- superClass = ScriptRuntime.ObjectClass;
-
- Class[] interfaces = new Class[interfaceCount];
- System.arraycopy(intfs, 0, interfaces, 0, interfaceCount);
- Scriptable obj = ScriptRuntime.toObject(cx, scope, args[N - 1]);
-
- Class adapterClass = getAdapterClass(scope, superClass, interfaces,
- obj);
-
- Class[] ctorParms = {
- ScriptRuntime.ContextFactoryClass,
- ScriptRuntime.ScriptableClass
- };
- Object[] ctorArgs = { cx.getFactory(), obj };
- try {
- Object adapter = adapterClass.getConstructor(ctorParms).
- newInstance(ctorArgs);
- return getAdapterSelf(adapterClass, adapter);
- } catch (Exception ex) {
- throw Context.throwAsScriptRuntimeEx(ex);
- }
- }
-
- // Needed by NativeJavaObject serializer
- public static void writeAdapterObject(Object javaObject,
- ObjectOutputStream out)
- throws IOException
- {
- Class cl = javaObject.getClass();
- out.writeObject(cl.getSuperclass().getName());
-
- Class[] interfaces = cl.getInterfaces();
- String[] interfaceNames = new String[interfaces.length];
-
- for (int i=0; i < interfaces.length; i++)
- interfaceNames[i] = interfaces[i].getName();
-
- out.writeObject(interfaceNames);
-
- try {
- Object delegee = cl.getField("delegee").get(javaObject);
- out.writeObject(delegee);
- return;
- } catch (IllegalAccessException e) {
- } catch (NoSuchFieldException e) {
- }
- throw new IOException();
- }
-
- // Needed by NativeJavaObject de-serializer
- public static Object readAdapterObject(Scriptable self,
- ObjectInputStream in)
- throws IOException, ClassNotFoundException
- {
- ContextFactory factory;
- Context cx = Context.getCurrentContext();
- if (cx != null) {
- factory = cx.getFactory();
- } else {
- factory = null;
- }
-
- Class superClass = Class.forName((String)in.readObject());
-
- String[] interfaceNames = (String[])in.readObject();
- Class[] interfaces = new Class[interfaceNames.length];
-
- for (int i=0; i < interfaceNames.length; i++)
- interfaces[i] = Class.forName(interfaceNames[i]);
-
- Scriptable delegee = (Scriptable)in.readObject();
-
- Class adapterClass = getAdapterClass(self, superClass, interfaces,
- delegee);
-
- Class[] ctorParms = {
- ScriptRuntime.ContextFactoryClass,
- ScriptRuntime.ScriptableClass,
- ScriptRuntime.ScriptableClass
- };
- Object[] ctorArgs = { factory, delegee, self };
- try {
- return adapterClass.getConstructor(ctorParms).newInstance(ctorArgs);
- } catch(InstantiationException e) {
- } catch(IllegalAccessException e) {
- } catch(InvocationTargetException e) {
- } catch(NoSuchMethodException e) {
- }
-
- throw new ClassNotFoundException("adapter");
- }
-
- private static ObjToIntMap getObjectFunctionNames(Scriptable obj)
- {
- Object[] ids = ScriptableObject.getPropertyIds(obj);
- ObjToIntMap map = new ObjToIntMap(ids.length);
- for (int i = 0; i != ids.length; ++i) {
- if (!(ids[i] instanceof String))
- continue;
- String id = (String) ids[i];
- Object value = ScriptableObject.getProperty(obj, id);
- if (value instanceof Function) {
- Function f = (Function)value;
- int length = ScriptRuntime.toInt32(
- ScriptableObject.getProperty(f, "length"));
- if (length < 0) {
- length = 0;
- }
- map.put(id, length);
- }
- }
- return map;
- }
-
- private static Class getAdapterClass(Scriptable scope, Class superClass,
- Class[] interfaces, Scriptable obj)
- {
- ClassCache cache = ClassCache.get(scope);
- Map<JavaAdapterSignature,Class<?>> generated
- = cache.getInterfaceAdapterCacheMap();
-
- ObjToIntMap names = getObjectFunctionNames(obj);
- JavaAdapterSignature sig;
- sig = new JavaAdapterSignature(superClass, interfaces, names);
- Class<?> adapterClass = generated.get(sig);
- if (adapterClass == null) {
- String adapterName = "adapter"
- + cache.newClassSerialNumber();
- byte[] code = createAdapterCode(names, adapterName,
- superClass, interfaces, null);
-
- adapterClass = loadAdapterClass(adapterName, code);
- if (cache.isCachingEnabled()) {
- generated.put(sig, adapterClass);
- }
- }
- return adapterClass;
- }
-
- public static byte[] createAdapterCode(ObjToIntMap functionNames,
- String adapterName,
- Class superClass,
- Class[] interfaces,
- String scriptClassName)
- {
- ClassFileWriter cfw = new ClassFileWriter(adapterName,
- superClass.getName(),
- "<adapter>");
- cfw.addField("factory", "Lorg/mozilla/javascript/ContextFactory;",
- (short) (ClassFileWriter.ACC_PUBLIC |
- ClassFileWriter.ACC_FINAL));
- cfw.addField("delegee", "Lorg/mozilla/javascript/Scriptable;",
- (short) (ClassFileWriter.ACC_PUBLIC |
- ClassFileWriter.ACC_FINAL));
- cfw.addField("self", "Lorg/mozilla/javascript/Scriptable;",
- (short) (ClassFileWriter.ACC_PUBLIC |
- ClassFileWriter.ACC_FINAL));
- int interfacesCount = interfaces == null ? 0 : interfaces.length;
- for (int i=0; i < interfacesCount; i++) {
- if (interfaces[i] != null)
- cfw.addInterface(interfaces[i].getName());
- }
-
- String superName = superClass.getName().replace('.', '/');
- generateCtor(cfw, adapterName, superName);
- generateSerialCtor(cfw, adapterName, superName);
- if (scriptClassName != null)
- generateEmptyCtor(cfw, adapterName, superName, scriptClassName);
-
- ObjToIntMap generatedOverrides = new ObjToIntMap();
- ObjToIntMap generatedMethods = new ObjToIntMap();
-
- // generate methods to satisfy all specified interfaces.
- for (int i = 0; i < interfacesCount; i++) {
- Method[] methods = interfaces[i].getMethods();
- for (int j = 0; j < methods.length; j++) {
- Method method = methods[j];
- int mods = method.getModifiers();
- if (Modifier.isStatic(mods) || Modifier.isFinal(mods)) {
- continue;
- }
- String methodName = method.getName();
- Class[] argTypes = method.getParameterTypes();
- if (!functionNames.has(methodName)) {
- try {
- superClass.getMethod(methodName, argTypes);
- // The class we're extending implements this method and
- // the JavaScript object doesn't have an override. See
- // bug 61226.
- continue;
- } 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) {
- // Create a string of length 1 using the character parameter.
- cfw.add(ByteCode.ILOAD, paramOffset);
- cfw.addInvoke(ByteCode.INVOKESTATIC, "java/lang/String",
- "valueOf", "(C)Ljava/lang/String;");
-
- } else {
- // convert all numeric values to java.lang.Double.
- cfw.add(ByteCode.NEW, "java/lang/Double");
- cfw.add(ByteCode.DUP);
- String typeName = argType.getName();
- switch (typeName.charAt(0)) {
- case 'b':
- case 's':
- case 'i':
- // load an int value, convert to double.
- cfw.add(ByteCode.ILOAD, paramOffset);
- 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 method
-
- // 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;
-}