Norris Boyd wrote:

> Igor Bukanov wrote:
>
>
>>Norris Boyd wrote:
>>
>>
>>>The intention was to keep classfile and JavaAdapter optional. Those
>>>dependencies crept in. We can use Invoker optionally--perhaps I should do
>>>some performance numbers to see if it's worth it.
>>>
>>I implemented that patch, it splits Invoker.java into Invoker.java and
>>its implementation in optimizer/InvokerImpl.java The reason to put it
>>into optimizer package is that Invoker is very similar in spirit to
>>NativeScript: it generates classes to speed up access and in this way
>>there is no need to have separated option not to use: one can simply
>>remove optimizer all together.
>>
>
> Yes, that sounds great.
>
>
>>
>>I noticed during implementation that JavaAdapter.DefiningClassLoader and
>>optimizer/JavaScriptClassLoader contains the same code, so maybe they
>>can be moved to org.mozilla.classfile package under one name?
>>
>
> Yes, that sounds like a good change too. Thanks for noticing that.


The update is pretty messy: it touches FunctionObject which I changed to
remove the special treatment of NativeWith in the previous patch, and it
also add/removes files.

Here is a description:
DefiningClassLoader.java should go to org/mozilla/classfile. It is the
same code that was in omj/optimizer/JavaScriptClassLoader.java with
class rename and adding public attribute and correspondingly
omj.optimizer/JavaScriptClassLoader.java should be removed. I guess it
would be nice to preserve logs/history in CVS during the move.

InvokerImpl.java should go to omj/optimizer. It is mostly what
omj.Invoker was.

invoker_changes_patch was generated via
cvs diff -u Invoker.java JavaAdapter.java optimizer/Codegen.java
and contains changes against the current CVS

FunctionObject_invoker_patch was generated via
diff -u ../../mozilla.1/javascript/FunctionObject.java FunctionObject.java
and contains changes against that With patch.

Igor
This commit is contained in:
nboyd%atg.com 2001-05-15 13:10:38 +00:00
parent 4b89ac4b2e
commit 0068a15b8a
6 changed files with 355 additions and 403 deletions

View File

@ -20,6 +20,7 @@
*
* Contributor(s):
* Norris Boyd
* Igor Bukanov
* David C. Navas
* Ted Neward
*
@ -555,13 +556,10 @@ public class FunctionObject extends NativeFunction {
private final Object doInvoke(Object thisObj, Object[] args)
throws IllegalAccessException, InvocationTargetException
{
if (classLoader != null) {
Invoker master = invokerMaster;
if (master != null) {
if (invoker == null) {
invoker = (Invoker) invokersCache.get(method);
if (invoker == null) {
invoker = Invoker.createInvoker(method, types, classLoader);
invokersCache.put(method, invoker);
}
invoker = master.createInvoker(method, types);
}
try {
return invoker.invoke(thisObj, args);
@ -617,23 +615,33 @@ public class FunctionObject extends NativeFunction {
static void setCachingEnabled(boolean enabled) {
if (!enabled) {
methodsCache = null;
classLoader = null;
invokersCache = null;
} else if (classLoader == null) {
classLoader = JavaAdapter.createDefiningClassLoader();
invokersCache = new Hashtable();
invokerMaster = null;
} else if (invokerMaster == null) {
invokerMaster = newInvokerMaster();
}
}
/** Get default master implementation or null if not available */
private static Invoker newInvokerMaster() {
try {
Class cl = Class.forName(INVOKER_MASTER_CLASS);
return (Invoker)cl.newInstance();
}
catch (Exception ex) {}
return null;
}
private static final String
INVOKER_MASTER_CLASS = "org.mozilla.javascript.optimizer.InvokerImpl";
static Invoker invokerMaster = newInvokerMaster();
private static final short VARARGS_METHOD = -1;
private static final short VARARGS_CTOR = -2;
private static boolean sawSecurityException;
static Method[] methodsCache;
static Hashtable invokersCache = new Hashtable();
static JavaAdapter.DefiningClassLoader classLoader
= JavaAdapter.createDefiningClassLoader();
Method method;
Constructor ctor;

View File

@ -18,7 +18,7 @@
* Copyright (C) 1997-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Contributor(s):
* Norris Boyd
* David C. Navas
*
@ -36,259 +36,19 @@
package org.mozilla.javascript;
import java.lang.reflect.*;
import java.io.IOException;
import org.mozilla.classfile.*;
import java.lang.reflect.Method;
/**
* Avoid cost of java.lang.reflect.Method.invoke() by compiling a class to
* Avoid cost of java.lang.reflect.Method.invoke() by compiling a class to
* perform the method call directly.
*/
public abstract class Invoker {
static int classNumber = 0;
public static Invoker createInvoker(Method method, Class[] types,
JavaAdapter.DefiningClassLoader classLoader)
{
Invoker result = null;
String className = "inv" + ++classNumber;
ClassFileWriter cfw = new ClassFileWriter(className,
"org.mozilla.javascript.Invoker", "");
cfw.setFlags((short)(ClassFileWriter.ACC_PUBLIC |
ClassFileWriter.ACC_FINAL));
// Add our instantiator!
cfw.startMethod("<init>", "()V", ClassFileWriter.ACC_PUBLIC);
cfw.add(ByteCode.ALOAD_0);
cfw.add(ByteCode.INVOKESPECIAL,
"org.mozilla.javascript.Invoker",
"<init>", "()", "V");
cfw.add(ByteCode.RETURN);
cfw.stopMethod((short)1, null); // one argument -- this???
// Add the invoke() method call
cfw.startMethod("invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)"+
"Ljava/lang/Object;",
(short)(ClassFileWriter.ACC_PUBLIC |
ClassFileWriter.ACC_FINAL));
// If we return a primitive type, then do something special!
String declaringClassName = method.getDeclaringClass().getName
().replace('.', '/');
Class returnType = method.getReturnType();
String invokeSpecial = null;
String invokeSpecialType = null;
boolean returnsVoid = false;
boolean returnsBoolean = false;
if (returnType.isPrimitive()) {
if (returnType == Boolean.TYPE) {
returnsBoolean = true;
invokeSpecialType = "(Z)";
} else if (returnType == Void.TYPE) {
returnsVoid = true;
invokeSpecialType = "(V)";
} else if (returnType == Integer.TYPE) {
cfw.add(ByteCode.NEW, invokeSpecial = "java/lang/Integer");
cfw.add(ByteCode.DUP);
invokeSpecialType = "(I)";
} else if (returnType == Long.TYPE) {
cfw.add(ByteCode.NEW, invokeSpecial = "java/lang/Long");
cfw.add(ByteCode.DUP);
invokeSpecialType = "(J)";
} else if (returnType == Short.TYPE) {
cfw.add(ByteCode.NEW, invokeSpecial = "java/lang/Short");
cfw.add(ByteCode.DUP);
invokeSpecialType = "(S)";
} else if (returnType == Float.TYPE) {
cfw.add(ByteCode.NEW, invokeSpecial = "java/lang/Float");
cfw.add(ByteCode.DUP);
invokeSpecialType = "(F)";
} else if (returnType == Double.TYPE) {
cfw.add(ByteCode.NEW, invokeSpecial = "java/lang/Double");
cfw.add(ByteCode.DUP);
invokeSpecialType = "(D)";
} else if (returnType == Byte.TYPE) {
cfw.add(ByteCode.NEW, invokeSpecial = "java/lang/Byte");
cfw.add(ByteCode.DUP);
invokeSpecialType = "(B)";
} else if (returnType == Character.TYPE) {
cfw.add(ByteCode.NEW, invokeSpecial
= "java/lang/Character");
cfw.add(ByteCode.DUP);
invokeSpecialType = "(C)";
}
}
// handle setup of call to virtual function (if calling non-static)
if (!java.lang.reflect.Modifier.isStatic(method.getModifiers())) {
cfw.add(ByteCode.ALOAD_1);
cfw.add(ByteCode.CHECKCAST, declaringClassName);
}
// Handle parameters!
StringBuffer params = new StringBuffer(2 + ((types!=null)?(20 *
types.length):0));
params.append("(");
if (types != null) {
for(int i = 0; i < types.length; i++) {
Class type = types[i];
cfw.add(ByteCode.ALOAD_2);
if (i <= 5) {
cfw.add((byte) (ByteCode.ICONST_0 + i));
} else if (i <= Byte.MAX_VALUE) {
cfw.add(ByteCode.BIPUSH, i);
} else if (i <= Short.MAX_VALUE) {
cfw.add(ByteCode.SIPUSH, i);
} else {
cfw.addLoadConstant((int)i);
}
cfw.add(ByteCode.AALOAD);
if (type.isPrimitive()) {
// Convert enclosed type back to primitive.
if (type == Boolean.TYPE) {
cfw.add(ByteCode.CHECKCAST, "java/lang/Boolean");
cfw.add(ByteCode.INVOKEVIRTUAL, "java/lang/Boolean",
"booleanValue", "()", "Z");
params.append("Z");
} else if (type == Integer.TYPE) {
cfw.add(ByteCode.CHECKCAST, "java/lang/Number");
cfw.add(ByteCode.INVOKEVIRTUAL, "java/lang/Number",
"intValue", "()", "I");
params.append("I");
} else if (type == Short.TYPE) {
cfw.add(ByteCode.CHECKCAST, "java/lang/Number");
cfw.add(ByteCode.INVOKEVIRTUAL, "java/lang/Number",
"shortValue", "()", "S");
params.append("S");
} else if (type == Character.TYPE) {
cfw.add(ByteCode.CHECKCAST, "java/lang/Character");
cfw.add(ByteCode.INVOKEVIRTUAL, "java/lang/Character",
"charValue", "()", "C");
params.append("C");
} else if (type == Double.TYPE) {
cfw.add(ByteCode.CHECKCAST, "java/lang/Number");
cfw.add(ByteCode.INVOKEVIRTUAL, "java/lang/Number",
"doubleValue", "()", "D");
params.append("D");
} else if (type == Float.TYPE) {
cfw.add(ByteCode.CHECKCAST, "java/lang/Number");
cfw.add(ByteCode.INVOKEVIRTUAL, "java/lang/Number",
"floatValue", "()", "F");
params.append("F");
} else if (type == Byte.TYPE) {
cfw.add(ByteCode.CHECKCAST, "java/lang/Byte");
cfw.add(ByteCode.INVOKEVIRTUAL, "java/lang/Byte",
"byteValue", "()", "B");
params.append("B");
}
} else {
String typeName = type.getName().replace('.', '/');
cfw.add(ByteCode.CHECKCAST, typeName);
if (!type.isArray()) {
params.append('L');
}
params.append(typeName);
if (!type.isArray()) {
params.append(';');
}
}
}
}
params.append(")");
// Call actual function!
if (!java.lang.reflect.Modifier.isStatic(method.getModifiers())) {
cfw.add(ByteCode.INVOKEVIRTUAL, declaringClassName,
method.getName(), params.toString(),
(invokeSpecialType!=null?invokeSpecialType.substring(1,2)
:returnType.isArray()?
returnType.getName().replace('.','/')
:"L".concat
(returnType.getName().replace('.', '/').concat(";"))));
} else {
cfw.add(ByteCode.INVOKESTATIC, declaringClassName,
method.getName(), params.toString(),
(invokeSpecialType!=null?invokeSpecialType.substring(1,2)
:returnType.isArray()?
returnType.getName().replace('.','/')
:"L".concat
(returnType.getName().replace('.', '/').concat(";"))));
}
// Handle return value
if (returnsVoid) {
cfw.add(ByteCode.ACONST_NULL);
cfw.add(ByteCode.ARETURN);
} else if (returnsBoolean) {
// HACK
//check to see if true;
// '7' is the number of bytes of the ifeq<branch> plus getstatic<TRUE> plus areturn instructions
cfw.add(ByteCode.IFEQ, 7);
cfw.add(ByteCode.GETSTATIC,
"java/lang/Boolean",
"TRUE",
"Ljava/lang/Boolean;");
cfw.add(ByteCode.ARETURN);
cfw.add(ByteCode.GETSTATIC,
"java/lang/Boolean",
"FALSE",
"Ljava/lang/Boolean;");
cfw.add(ByteCode.ARETURN);
} else if (invokeSpecial != null) {
cfw.add(ByteCode.INVOKESPECIAL,
invokeSpecial,
"<init>", invokeSpecialType, "V");
cfw.add(ByteCode.ARETURN);
} else {
cfw.add(ByteCode.ARETURN);
}
cfw.stopMethod((short)3, null); // three arguments, including the this pointer???
// Add class to our classloader.
java.io.ByteArrayOutputStream bos =
new java.io.ByteArrayOutputStream(550);
try {
cfw.write(bos);
}
catch (IOException ioe) {
throw new RuntimeException("unexpected IOException" + ioe.toString());
}
try {
byte[] bytes = bos.toByteArray();
Context cx = Context.getCurrentContext();
classLoader.defineClass(className, bytes);
Class c = classLoader.loadClass(className, true);
result = (Invoker)c.newInstance();
if (false) {
System.out.println("Generated method delegate for: " + method.getName()
+ " on " + method.getDeclaringClass().getName() + " :: " + params.toString()
+ " :: " + types);
}
} catch (ClassNotFoundException e) {
throw new RuntimeException("unexpected " + e.toString());
} catch (InstantiationException e) {
throw new RuntimeException("unexpected " + e.toString());
} catch (IllegalAccessException e) {
throw new RuntimeException("unexpected " + e.toString());
}
return result;
}
public abstract Object invoke(Object that, Object [] args);
/** Factory method to get invoker for given method */
public Invoker createInvoker(Method method, Class[] types) {
return null;
}
}

View File

@ -47,7 +47,7 @@ import java.util.*;
public class JavaAdapter extends ScriptableObject {
public boolean equals(Object obj) {
return super.equals(obj);
return super.equals(obj);
}
public String getClassName() {
@ -167,7 +167,7 @@ public class JavaAdapter extends ScriptableObject {
for (int i = 0; i < interfacesCount; i++) {
Method[] methods = interfaces[i].getMethods();
for (int j = 0; j < methods.length; j++) {
Method method = methods[j];
Method method = methods[j];
int mods = method.getModifiers();
if (Modifier.isStatic(mods) || Modifier.isFinal(mods) ||
jsObj == null)
@ -189,8 +189,8 @@ public class JavaAdapter extends ScriptableObject {
// make sure to generate only one instance of a particular
// method/signature.
String methodName = method.getName();
String methodKey = methodName + getMethodSignature(method);
if (! generatedOverrides.containsKey(methodKey)) {
String methodKey = methodName + getMethodSignature(method);
if (! generatedOverrides.containsKey(methodKey)) {
generateMethod(cfw, adapterName, methodName,
method.getParameterTypes(),
method.getReturnType());
@ -322,15 +322,6 @@ public class JavaAdapter extends ScriptableObject {
return classLoader.loadClass(adapterName, true);
}
public static DefiningClassLoader createDefiningClassLoader() {
try {
return new JavaAdapter.DefiningClassLoader();
} catch (Throwable t) {
// most likely a security exception; just skip this optimization
return null;
}
}
/**
* Utility method which dynamically binds a Context to the current thread,
* if none already exists.
@ -595,7 +586,7 @@ public class JavaAdapter extends ScriptableObject {
{
StringBuffer sb = new StringBuffer();
sb.append('(');
short arrayLocal = 1; // includes this.
short arrayLocal = 1; // includes this.
for (int i = 0; i < parms.length; i++) {
Class type = parms[i];
appendTypeString(sb, type);
@ -753,11 +744,11 @@ public class JavaAdapter extends ScriptableObject {
}
}
/**
* 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.
*/
/**
* 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,
@ -766,10 +757,10 @@ public class JavaAdapter extends ScriptableObject {
cfw.startMethod("super$" + methodName, methodSignature,
ClassFileWriter.ACC_PUBLIC);
// push "this"
// push "this"
cfw.add(ByteCode.ALOAD, 0);
// push the rest of the parameters.
// push the rest of the parameters.
int paramOffset = 1;
for (int i = 0; i < parms.length; i++) {
if (parms[i].isPrimitive()) {
@ -789,12 +780,12 @@ public class JavaAdapter extends ScriptableObject {
methodSignature.substring(0, rightParen + 1),
methodSignature.substring(rightParen + 1));
// now, handle the return type appropriately.
// now, handle the return type appropriately.
Class retType = returnType;
if (!retType.equals(Void.TYPE)) {
generatePopResult(cfw, retType);
} else {
cfw.add(ByteCode.RETURN);
cfw.add(ByteCode.RETURN);
}
cfw.stopMethod((short)(paramOffset + 1), null);
}
@ -839,41 +830,6 @@ public class JavaAdapter extends ScriptableObject {
return sb;
}
static final class DefiningClassLoader extends ClassLoader {
public Class defineClass(String name, byte data[]) {
ClassLoader loader = getClass().getClassLoader();
if (loader != null) {
Class clazz = ClassManager.defineClass(loader, name, data);
if (clazz != null)
return clazz;
}
return super.defineClass(name, data, 0, data.length);
}
protected Class loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
Class clazz;
ClassLoader loader = getClass().getClassLoader();
if (loader != null) {
clazz = ClassManager.loadClass(loader, name, resolve);
if (clazz != null)
return clazz;
}
clazz = findLoadedClass(name);
if (clazz == null) {
try {
clazz = findSystemClass(name);
} catch (ClassNotFoundException e) {
return ScriptRuntime.loadClassName(name);
}
}
if (resolve)
resolveClass(clazz);
return clazz;
}
}
/**
* Provides a key with which to distinguish previously generated
* adapter classes stored in a hash table.

View File

@ -79,7 +79,7 @@ public class Codegen extends Interpreter {
Exception e = null;
Class result = null;
JavaScriptClassLoader classLoader = new JavaScriptClassLoader();
DefiningClassLoader classLoader = new DefiningClassLoader();
try {
if (cx.getOptimizationLevel() > 0) {

View File

@ -0,0 +1,309 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape 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/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
* 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 Netscape are
* Copyright (C) 1997-2000 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Norris Boyd
* David C. Navas
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (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 NPL, indicate your decision by
* deleting the provisions above and replace 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 NPL or the GPL.
*/
package org.mozilla.javascript.optimizer;
import java.util.Hashtable;
import java.io.IOException;
import java.lang.reflect.Method;
import org.mozilla.javascript.Invoker;
import org.mozilla.classfile.ByteCode;
import org.mozilla.classfile.ClassFileWriter;
import org.mozilla.classfile.DefiningClassLoader;
/**
* Avoid cost of java.lang.reflect.Method.invoke() by compiling a class to
* perform the method call directly.
*/
public class InvokerImpl extends Invoker {
public Invoker createInvoker(Method method, Class[] types) {
Invoker result = (Invoker)invokersCache.get(method);
if (result != null) { return result; }
synchronized (this) {
++classNumber;
}
String className = "inv" + classNumber;
ClassFileWriter cfw = new ClassFileWriter(className,
"org.mozilla.javascript.Invoker", "");
cfw.setFlags((short)(ClassFileWriter.ACC_PUBLIC |
ClassFileWriter.ACC_FINAL));
// Add our instantiator!
cfw.startMethod("<init>", "()V", ClassFileWriter.ACC_PUBLIC);
cfw.add(ByteCode.ALOAD_0);
cfw.add(ByteCode.INVOKESPECIAL,
"org.mozilla.javascript.Invoker",
"<init>", "()", "V");
cfw.add(ByteCode.RETURN);
cfw.stopMethod((short)1, null); // one argument -- this???
// Add the invoke() method call
cfw.startMethod("invoke",
"(Ljava/lang/Object;[Ljava/lang/Object;)"+
"Ljava/lang/Object;",
(short)(ClassFileWriter.ACC_PUBLIC |
ClassFileWriter.ACC_FINAL));
// If we return a primitive type, then do something special!
String declaringClassName = method.getDeclaringClass().getName
().replace('.', '/');
Class returnType = method.getReturnType();
String invokeSpecial = null;
String invokeSpecialType = null;
boolean returnsVoid = false;
boolean returnsBoolean = false;
if (returnType.isPrimitive()) {
if (returnType == Boolean.TYPE) {
returnsBoolean = true;
invokeSpecialType = "(Z)";
} else if (returnType == Void.TYPE) {
returnsVoid = true;
invokeSpecialType = "(V)";
} else if (returnType == Integer.TYPE) {
cfw.add(ByteCode.NEW, invokeSpecial = "java/lang/Integer");
cfw.add(ByteCode.DUP);
invokeSpecialType = "(I)";
} else if (returnType == Long.TYPE) {
cfw.add(ByteCode.NEW, invokeSpecial = "java/lang/Long");
cfw.add(ByteCode.DUP);
invokeSpecialType = "(J)";
} else if (returnType == Short.TYPE) {
cfw.add(ByteCode.NEW, invokeSpecial = "java/lang/Short");
cfw.add(ByteCode.DUP);
invokeSpecialType = "(S)";
} else if (returnType == Float.TYPE) {
cfw.add(ByteCode.NEW, invokeSpecial = "java/lang/Float");
cfw.add(ByteCode.DUP);
invokeSpecialType = "(F)";
} else if (returnType == Double.TYPE) {
cfw.add(ByteCode.NEW, invokeSpecial = "java/lang/Double");
cfw.add(ByteCode.DUP);
invokeSpecialType = "(D)";
} else if (returnType == Byte.TYPE) {
cfw.add(ByteCode.NEW, invokeSpecial = "java/lang/Byte");
cfw.add(ByteCode.DUP);
invokeSpecialType = "(B)";
} else if (returnType == Character.TYPE) {
cfw.add(ByteCode.NEW, invokeSpecial
= "java/lang/Character");
cfw.add(ByteCode.DUP);
invokeSpecialType = "(C)";
}
}
// handle setup of call to virtual function (if calling non-static)
if (!java.lang.reflect.Modifier.isStatic(method.getModifiers())) {
cfw.add(ByteCode.ALOAD_1);
cfw.add(ByteCode.CHECKCAST, declaringClassName);
}
// Handle parameters!
StringBuffer params = new StringBuffer(2 + ((types!=null)?(20 *
types.length):0));
params.append("(");
if (types != null) {
for(int i = 0; i < types.length; i++) {
Class type = types[i];
cfw.add(ByteCode.ALOAD_2);
if (i <= 5) {
cfw.add((byte) (ByteCode.ICONST_0 + i));
} else if (i <= Byte.MAX_VALUE) {
cfw.add(ByteCode.BIPUSH, i);
} else if (i <= Short.MAX_VALUE) {
cfw.add(ByteCode.SIPUSH, i);
} else {
cfw.addLoadConstant((int)i);
}
cfw.add(ByteCode.AALOAD);
if (type.isPrimitive()) {
// Convert enclosed type back to primitive.
if (type == Boolean.TYPE) {
cfw.add(ByteCode.CHECKCAST, "java/lang/Boolean");
cfw.add(ByteCode.INVOKEVIRTUAL, "java/lang/Boolean",
"booleanValue", "()", "Z");
params.append("Z");
} else if (type == Integer.TYPE) {
cfw.add(ByteCode.CHECKCAST, "java/lang/Number");
cfw.add(ByteCode.INVOKEVIRTUAL, "java/lang/Number",
"intValue", "()", "I");
params.append("I");
} else if (type == Short.TYPE) {
cfw.add(ByteCode.CHECKCAST, "java/lang/Number");
cfw.add(ByteCode.INVOKEVIRTUAL, "java/lang/Number",
"shortValue", "()", "S");
params.append("S");
} else if (type == Character.TYPE) {
cfw.add(ByteCode.CHECKCAST, "java/lang/Character");
cfw.add(ByteCode.INVOKEVIRTUAL, "java/lang/Character",
"charValue", "()", "C");
params.append("C");
} else if (type == Double.TYPE) {
cfw.add(ByteCode.CHECKCAST, "java/lang/Number");
cfw.add(ByteCode.INVOKEVIRTUAL, "java/lang/Number",
"doubleValue", "()", "D");
params.append("D");
} else if (type == Float.TYPE) {
cfw.add(ByteCode.CHECKCAST, "java/lang/Number");
cfw.add(ByteCode.INVOKEVIRTUAL, "java/lang/Number",
"floatValue", "()", "F");
params.append("F");
} else if (type == Byte.TYPE) {
cfw.add(ByteCode.CHECKCAST, "java/lang/Byte");
cfw.add(ByteCode.INVOKEVIRTUAL, "java/lang/Byte",
"byteValue", "()", "B");
params.append("B");
}
} else {
String typeName = type.getName().replace('.', '/');
cfw.add(ByteCode.CHECKCAST, typeName);
if (!type.isArray()) {
params.append('L');
}
params.append(typeName);
if (!type.isArray()) {
params.append(';');
}
}
}
}
params.append(")");
// Call actual function!
if (!java.lang.reflect.Modifier.isStatic(method.getModifiers())) {
cfw.add(ByteCode.INVOKEVIRTUAL, declaringClassName,
method.getName(), params.toString(),
(invokeSpecialType!=null?invokeSpecialType.substring(1,2)
:returnType.isArray()?
returnType.getName().replace('.','/')
:"L".concat
(returnType.getName().replace('.', '/').concat(";"))));
} else {
cfw.add(ByteCode.INVOKESTATIC, declaringClassName,
method.getName(), params.toString(),
(invokeSpecialType!=null?invokeSpecialType.substring(1,2)
:returnType.isArray()?
returnType.getName().replace('.','/')
:"L".concat
(returnType.getName().replace('.', '/').concat(";"))));
}
// Handle return value
if (returnsVoid) {
cfw.add(ByteCode.ACONST_NULL);
cfw.add(ByteCode.ARETURN);
} else if (returnsBoolean) {
// HACK
//check to see if true;
// '7' is the number of bytes of the ifeq<branch> plus getstatic<TRUE> plus areturn instructions
cfw.add(ByteCode.IFEQ, 7);
cfw.add(ByteCode.GETSTATIC,
"java/lang/Boolean",
"TRUE",
"Ljava/lang/Boolean;");
cfw.add(ByteCode.ARETURN);
cfw.add(ByteCode.GETSTATIC,
"java/lang/Boolean",
"FALSE",
"Ljava/lang/Boolean;");
cfw.add(ByteCode.ARETURN);
} else if (invokeSpecial != null) {
cfw.add(ByteCode.INVOKESPECIAL,
invokeSpecial,
"<init>", invokeSpecialType, "V");
cfw.add(ByteCode.ARETURN);
} else {
cfw.add(ByteCode.ARETURN);
}
cfw.stopMethod((short)3, null); // three arguments, including the this pointer???
// Add class to our classloader.
java.io.ByteArrayOutputStream bos =
new java.io.ByteArrayOutputStream(550);
try {
cfw.write(bos);
}
catch (IOException ioe) {
throw new RuntimeException("unexpected IOException" + ioe.toString());
}
try {
byte[] bytes = bos.toByteArray();
classLoader.defineClass(className, bytes);
Class c = classLoader.loadClass(className, true);
result = (Invoker)c.newInstance();
if (false) {
System.out.println("Generated method delegate for: " + method.getName()
+ " on " + method.getDeclaringClass().getName() + " :: " + params.toString()
+ " :: " + types);
}
} catch (ClassNotFoundException e) {
throw new RuntimeException("unexpected " + e.toString());
} catch (InstantiationException e) {
throw new RuntimeException("unexpected " + e.toString());
} catch (IllegalAccessException e) {
throw new RuntimeException("unexpected " + e.toString());
}
invokersCache.put(method, result);
return result;
}
public Object invoke(Object that, Object [] args) {
return null;
}
int classNumber;
Hashtable invokersCache = new Hashtable();
DefiningClassLoader classLoader = new DefiningClassLoader();
}

View File

@ -1,81 +0,0 @@
/*
* The contents of this file are subject to the Netscape 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/NPL/
*
* 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 Netscape are
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Norris Boyd
* Roger Lawrence
* Patrick Beard
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (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 NPL, indicate your decision by
* deleting the provisions above and replace 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 NPL or the GPL.
*/
package org.mozilla.javascript.optimizer;
import java.util.*;
import org.mozilla.classfile.ClassManager;
/**
* Load generated classes that implement JavaScript scripts
* or functions.
*
* @author Norris Boyd
*/
final class JavaScriptClassLoader extends ClassLoader {
JavaScriptClassLoader() {
}
public Class defineClass(String name, byte data[]) {
ClassLoader loader = getClass().getClassLoader();
if (loader != null) {
Class clazz = ClassManager.defineClass(loader, name, data);
if (clazz != null)
return clazz;
}
return super.defineClass(name, data, 0, data.length);
}
protected Class loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
Class clazz;
ClassLoader loader = getClass().getClassLoader();
if (loader != null) {
clazz = ClassManager.loadClass(loader, name, resolve);
if (clazz != null)
return clazz;
}
clazz = findLoadedClass(name);
if (clazz == null)
clazz = findSystemClass(name);
if (resolve)
resolveClass(clazz);
return clazz;
}
}