Caching of Method/Constructor.getParameterType()

To avoid constant calling of Method/Constructor.getParameterType() which creates a new Class array on each call, NativeJavaMethod stores the parameter types for its methods in methodTypes array and similarly JavaMembers holds all constructor types in ctorTypes array. The cached Class arrays are passed explicitly to methods that previously called getParameterType().
This commit is contained in:
igor%mir2.org 2003-07-06 19:07:00 +00:00
parent c1add24197
commit dd893acd8d
4 changed files with 167 additions and 102 deletions

View File

@ -120,17 +120,19 @@ class JavaMembers
private Member findExplicitFunction(String name, boolean isStatic)
{
Hashtable ht = isStatic ? staticMembers : members;
int sigStart = name.indexOf('(');
if (sigStart < 0) { return null; }
Hashtable ht = isStatic ? staticMembers : members;
Member[] methodsOrCtors = null;
NativeJavaMethod method = null;
Class[][] methodOrCtorTypes = null;
boolean isCtor = (isStatic && sigStart == 0);
if (isCtor) {
// Explicit request for an overloaded constructor
methodsOrCtors = ctors;
}
else if (sigStart > 0) {
methodOrCtorTypes = ctorTypes;
} else {
// Explicit request for an overloaded method
String trueName = name.substring(0,sigStart);
Object obj = ht.get(trueName);
@ -138,17 +140,19 @@ class JavaMembers
// Try to get static member from instance (LC3)
obj = staticMembers.get(trueName);
}
if (obj != null && obj instanceof NativeJavaMethod) {
method = (NativeJavaMethod)obj;
methodsOrCtors = method.methods;
if (obj instanceof NativeJavaMethod) {
NativeJavaMethod njm = (NativeJavaMethod)obj;
methodsOrCtors = njm.methods;
methodOrCtorTypes = njm.methodTypes;
}
}
if (methodsOrCtors != null) {
for (int i = 0; i < methodsOrCtors.length; i++) {
Member member = methodsOrCtors[i];
String nameWithSig = NativeJavaMethod.memberSignature(member);
if (name.equals(nameWithSig)) {
Class[] type = methodOrCtorTypes[i];
String sig = NativeJavaMethod.memberSignature(member, type);
if (name.equals(sig)) {
return member;
}
}
@ -266,7 +270,7 @@ class JavaMembers
makeBeanProperties(scope, false);
makeBeanProperties(scope, true);
ctors = cl.getConstructors();
reflectCtors();
}
private void reflectMethods(Scriptable scope)
@ -303,30 +307,6 @@ class JavaMembers
initNativeMethods(members, scope);
}
private static void initNativeMethods(Hashtable ht, Scriptable scope)
{
Enumeration e = ht.keys();
while (e.hasMoreElements()) {
String name = (String)e.nextElement();
Method[] methods;
Object value = ht.get(name);
if (value instanceof Method) {
methods = new Method[1];
methods[0] = (Method)value;
} else {
ObjArray overloadedMethods = (ObjArray)value;
if (overloadedMethods.size() < 2) Context.codeBug();
methods = new Method[overloadedMethods.size()];
overloadedMethods.toArray(methods);
}
NativeJavaMethod fun = new NativeJavaMethod(methods);
if (scope != null) {
fun.setPrototype(ScriptableObject.getFunctionPrototype(scope));
}
ht.put(name, fun);
}
}
private void reflectFields(Scriptable scope)
{
Field[] fields = cl.getFields();
@ -368,20 +348,6 @@ class JavaMembers
}
}
private Hashtable getFieldAndMethodsTable(boolean isStatic)
{
Hashtable fmht = isStatic ? staticFieldAndMethods
: fieldAndMethods;
if (fmht == null) {
fmht = new Hashtable(11);
if (isStatic)
staticFieldAndMethods = fmht;
else
fieldAndMethods = fmht;
}
return fmht;
}
private void makeBeanProperties(Scriptable scope, boolean isStatic)
{
@ -459,6 +425,55 @@ class JavaMembers
}
}
private void reflectCtors()
{
ctors = cl.getConstructors();
int N = ctors.length;
ctorTypes = new Class[N][];
for (int i = 0; i != N; ++i) {
ctorTypes[i] = ctors[i].getParameterTypes();
}
}
private static void initNativeMethods(Hashtable ht, Scriptable scope)
{
Enumeration e = ht.keys();
while (e.hasMoreElements()) {
String name = (String)e.nextElement();
Method[] methods;
Object value = ht.get(name);
if (value instanceof Method) {
methods = new Method[1];
methods[0] = (Method)value;
} else {
ObjArray overloadedMethods = (ObjArray)value;
if (overloadedMethods.size() < 2) Context.codeBug();
methods = new Method[overloadedMethods.size()];
overloadedMethods.toArray(methods);
}
NativeJavaMethod fun = new NativeJavaMethod(methods);
if (scope != null) {
fun.setPrototype(ScriptableObject.getFunctionPrototype(scope));
}
ht.put(name, fun);
}
}
private Hashtable getFieldAndMethodsTable(boolean isStatic)
{
Hashtable fmht = isStatic ? staticFieldAndMethods
: fieldAndMethods;
if (fmht == null) {
fmht = new Hashtable(11);
if (isStatic)
staticFieldAndMethods = fmht;
else
fieldAndMethods = fmht;
}
return fmht;
}
private static Method extractGetMethod(NativeJavaMethod njm,
boolean isStatic)
{
@ -469,7 +484,7 @@ class JavaMembers
Method method = methods[0];
// Make sure the method static-ness is preserved for this property.
if (!isStatic || Modifier.isStatic(method.getModifiers())) {
Class[] params = method.getParameterTypes();
Class[] params = njm.methodTypes[0];
if (params != null && params.length == 0) {
Class type = method.getReturnType();
if (type != null && type != Void.TYPE) {
@ -480,7 +495,7 @@ class JavaMembers
}
return null;
}
private static Method extractSetMethod(Class type,
NativeJavaMethod njm,
boolean isStatic)
@ -499,7 +514,7 @@ class JavaMembers
Method method = methods[i];
if (!isStatic || Modifier.isStatic(method.getModifiers())) {
if (method.getReturnType() == Void.TYPE) {
Class[] params = method.getParameterTypes();
Class[] params = njm.methodTypes[i];
if (params != null && params.length == 1) {
if (pass == 1) {
if (params[0] == type) {
@ -634,6 +649,7 @@ class JavaMembers
private Hashtable staticMembers;
private Hashtable staticFieldAndMethods;
Constructor[] ctors;
Class[][] ctorTypes;
}
class BeanProperty

View File

@ -173,7 +173,8 @@ public class NativeJavaClass extends NativeJavaObject implements Function {
Modifier.isAbstract(modifiers)))
{
Constructor[] ctors = members.ctors;
int index = NativeJavaMethod.findFunction(ctors, args);
Class[][] ctorTypes = members.ctorTypes;
int index = NativeJavaMethod.findFunction(ctors, ctorTypes, args);
if (index < 0) {
String sig = NativeJavaMethod.scriptSignature(args);
throw Context.reportRuntimeError2(
@ -181,8 +182,8 @@ public class NativeJavaClass extends NativeJavaObject implements Function {
}
// Found the constructor, so try invoking it.
return NativeJavaClass.constructSpecific(cx, scope,
this, ctors[index], args);
return constructSpecific(cx, scope, this, args,
ctors[index], ctorTypes[index]);
} else {
Scriptable topLevel = ScriptableObject.getTopLevelScope(this);
String msg = "";
@ -211,14 +212,14 @@ public class NativeJavaClass extends NativeJavaObject implements Function {
public static Scriptable constructSpecific(Context cx,
Scriptable scope,
Scriptable thisObj,
Object[] args,
Constructor ctor,
Object[] args)
Class[] paramTypes)
throws JavaScriptException
{
Scriptable topLevel = ScriptableObject.getTopLevelScope(thisObj);
Class classObject = ctor.getDeclaringClass();
Class[] paramTypes = ctor.getParameterTypes();
for (int i = 0; i < args.length; i++) {
args[i] = NativeJavaObject.coerceType(paramTypes[i], args[i], true);
}

View File

@ -38,6 +38,7 @@
package org.mozilla.javascript;
import java.lang.reflect.*;
import java.io.*;
/**
* This class reflects a single Java constructor into the JavaScript
@ -58,7 +59,8 @@ public class NativeJavaConstructor extends BaseFunction
public NativeJavaConstructor(Constructor ctor)
{
this.constructor = ctor;
String sig = NativeJavaMethod.memberSignature(ctor);
this.constructorType = ctor.getParameterTypes();
String sig = NativeJavaMethod.memberSignature(ctor, constructorType);
this.functionName = "<init>".concat(sig);
}
@ -71,8 +73,8 @@ public class NativeJavaConstructor extends BaseFunction
throw new RuntimeException("No constructor defined for call");
}
return NativeJavaClass.constructSpecific(cx, scope,
this, constructor, args);
return NativeJavaClass.constructSpecific(cx, scope, this, args,
constructor, constructorType);
}
public String toString()
@ -80,11 +82,23 @@ public class NativeJavaConstructor extends BaseFunction
return "[JavaConstructor " + constructor.getName() + "]";
}
Constructor getConstructor()
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException
{
return constructor;
in.defaultReadObject();
constructor = (Constructor)FunctionObject.readMember(in);
constructorType = constructor.getParameterTypes();
}
Constructor constructor;
private void writeObject(ObjectOutputStream out)
throws IOException
{
out.defaultWriteObject();
FunctionObject.writeMember(out, constructor);
}
transient Constructor constructor;
private transient Class[] constructorType;
}

View File

@ -38,6 +38,7 @@
package org.mozilla.javascript;
import java.lang.reflect.*;
import java.io.*;
/**
* This class reflects Java methods into the JavaScript environment. It
@ -57,15 +58,26 @@ public class NativeJavaMethod extends BaseFunction
public NativeJavaMethod(Method[] methods)
{
this.methods = methods;
this.functionName = methods[0].getName();
init(methods);
}
public NativeJavaMethod(Method method, String name)
{
this.methods = new Method[1];
this.methods[0] = method;
this.functionName = name;
Method[] methods = { method };
init(methods);
}
private void init(Method[] methods)
{
this.methods = methods;
int N = methods.length;
methodTypes = new Class[N][];
for (int i = 0; i != N; ++i) {
methodTypes[i] = methods[i].getParameterTypes();
}
}
private static String scriptSignature(Object value)
@ -134,18 +146,14 @@ public class NativeJavaMethod extends BaseFunction
}
}
static String memberSignature(Member member)
static String memberSignature(Member member, Class[] paramTypes)
{
String name;
Class[] paramTypes;
if (member instanceof Method) {
Method method = (Method)member;
name = method.getName();
paramTypes = method.getParameterTypes();
} else {
Constructor ctor = (Constructor)member;
name = "";
paramTypes = ctor.getParameterTypes();
}
StringBuffer sb = new StringBuffer();
sb.append(name);
@ -187,7 +195,7 @@ public class NativeJavaMethod extends BaseFunction
Method method = methods[i];
sb.append(javaSignature(method.getReturnType()));
sb.append(' ');
sb.append(memberSignature(method));
sb.append(memberSignature(method, methodTypes[i]));
sb.append('\n');
}
}
@ -200,7 +208,7 @@ public class NativeJavaMethod extends BaseFunction
if (methods.length == 0) {
throw new RuntimeException("No methods defined for call");
}
int index = findFunction(methods, args);
int index = findFunction(methods, methodTypes, args);
if (index < 0) {
Class c = methods[0].getDeclaringClass();
String sig = c.getName() + '.' + functionName + '(' +
@ -209,9 +217,7 @@ public class NativeJavaMethod extends BaseFunction
}
Method meth = methods[index];
// OPT: already retrieved in findFunction, so we should inline that
// OPT: or pass it back somehow
Class paramTypes[] = meth.getParameterTypes();
Class paramTypes[] = methodTypes[index];
// First, we marshall the args.
Object[] origArgs = args;
@ -241,7 +247,7 @@ public class NativeJavaMethod extends BaseFunction
javaObject = ((Wrapper) o).unwrap();
}
if (debug) {
printDebug("Calling ", meth, args);
printDebug("Calling ", meth, paramTypes, args);
}
Object retval;
@ -335,15 +341,14 @@ public class NativeJavaMethod extends BaseFunction
* or constructors and the arguments.
* If no function can be found to call, return -1.
*/
static int findFunction(Member[] methodsOrCtors, Object[] args)
static int findFunction(Member[] methodsOrCtors, Class[][] memberTypes,
Object[] args)
{
if (methodsOrCtors.length == 0) {
return -1;
} else if (methodsOrCtors.length == 1) {
Member member = methodsOrCtors[0];
Class paramTypes[] = (member instanceof Method)
? ((Method) member).getParameterTypes()
: ((Constructor) member).getParameterTypes();
Class paramTypes[] = memberTypes[0];
int plength = paramTypes.length;
if (plength != args.length) {
return -1;
@ -351,11 +356,11 @@ public class NativeJavaMethod extends BaseFunction
for (int j = 0; j != plength; ++j) {
if (!NativeJavaObject.canConvert(args[j], paramTypes[j])) {
if (debug) printDebug("Rejecting (args can't convert) ",
member, args);
member, paramTypes, args);
return -1;
}
}
if (debug) printDebug("Found ", member, args);
if (debug) printDebug("Found ", member, paramTypes, args);
return 0;
}
@ -369,9 +374,7 @@ public class NativeJavaMethod extends BaseFunction
for (int i = 0; i < methodsOrCtors.length; i++) {
Member member = methodsOrCtors[i];
Class paramTypes[] = hasMethods
? ((Method) member).getParameterTypes()
: ((Constructor) member).getParameterTypes();
Class paramTypes[] = memberTypes[i];
if (paramTypes.length != args.length) {
continue;
}
@ -380,12 +383,12 @@ public class NativeJavaMethod extends BaseFunction
for (j = 0; j < paramTypes.length; j++) {
if (!NativeJavaObject.canConvert(args[j], paramTypes[j])) {
if (debug) printDebug("Rejecting (args can't convert) ",
member, args);
member, paramTypes, args);
break;
}
}
if (j == paramTypes.length) {
if (debug) printDebug("Found ", member, args);
if (debug) printDebug("Found ", member, paramTypes, args);
bestFit = i;
bestFitTypes = paramTypes;
}
@ -394,17 +397,20 @@ public class NativeJavaMethod extends BaseFunction
int preference = preferSignature(args, paramTypes,
bestFitTypes);
if (preference == PREFERENCE_AMBIGUOUS) {
if (debug) printDebug("Deferring ", member, args);
if (debug) printDebug("Deferring ",
member, paramTypes, args);
// add to "ambiguity list"
if (ambiguousMethods == null)
ambiguousMethods = new int[methodsOrCtors.length];
ambiguousMethods[ambiguousMethodCount++] = i;
} else if (preference == PREFERENCE_FIRST_ARG) {
if (debug) printDebug("Substituting ", member, args);
if (debug) printDebug("Substituting ",
member, paramTypes, args);
bestFit = i;
bestFitTypes = paramTypes;
} else if (preference == PREFERENCE_SECOND_ARG) {
if (debug) printDebug("Rejecting ", member, args);
if (debug) printDebug("Rejecting ",
member, paramTypes, args);
} else {
if (preference != PREFERENCE_EQUAL) Context.codeBug();
Member best = methodsOrCtors[bestFit];
@ -417,12 +423,14 @@ public class NativeJavaMethod extends BaseFunction
// a derived class's parameters match exactly.
// We want to call the dervied class's method.
if (debug) printDebug(
"Substituting (overridden static)", member, args);
"Substituting (overridden static)",
member, paramTypes, args);
bestFit = i;
bestFitTypes = paramTypes;
} else {
if (debug) printDebug(
"Ignoring same signature member ", member, args);
"Ignoring same signature member ",
member, paramTypes, args);
}
}
}
@ -437,26 +445,27 @@ public class NativeJavaMethod extends BaseFunction
for (int k = 0; k != ambiguousMethodCount; ++k) {
int i = ambiguousMethods[k];
Member member = methodsOrCtors[i];
Class paramTypes[] = hasMethods
? ((Method) member).getParameterTypes()
: ((Constructor) member).getParameterTypes();
Class paramTypes[] = memberTypes[i];
int preference = preferSignature(args, paramTypes,
bestFitTypes);
if (preference == PREFERENCE_FIRST_ARG) {
if (debug) printDebug("Substituting ", member, args);
if (debug) printDebug("Substituting ",
member, paramTypes, args);
bestFit = i;
bestFitTypes = paramTypes;
ambiguousMethods[k] = -1;
++removedCount;
}
else if (preference == PREFERENCE_SECOND_ARG) {
if (debug) printDebug("Rejecting ", member, args);
if (debug) printDebug("Rejecting ",
member, paramTypes, args);
ambiguousMethods[k] = -1;
++removedCount;
}
else {
if (debug) printDebug("UNRESOLVED: ", member, args);
if (debug) printDebug("UNRESOLVED: ",
member, paramTypes, args);
}
}
@ -482,7 +491,7 @@ public class NativeJavaMethod extends BaseFunction
buf.append(rtnType);
buf.append(' ');
}
buf.append(memberSignature(member));
buf.append(memberSignature(member, memberTypes[i]));
first = false;
}
@ -570,7 +579,8 @@ public class NativeJavaMethod extends BaseFunction
private static final boolean debug = false;
private static void printDebug(String msg, Member member, Object[] args)
private static void printDebug(String msg, Member member,
Class[] paramTypes, Object[] args)
{
if (debug) {
StringBuffer sb = new StringBuffer();
@ -578,14 +588,38 @@ public class NativeJavaMethod extends BaseFunction
sb.append(msg);
sb.append(member.getDeclaringClass().getName());
sb.append('.');
sb.append(memberSignature(member));
sb.append(memberSignature(member, paramTypes));
sb.append(" for arguments (");
sb.append(scriptSignature(args));
sb.append(')');
}
}
Method methods[];
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException
{
in.defaultReadObject();
int N = in.readInt();
Method[] array = new Method[N];
for (int i = 0; i != N; ++i) {
array[i] = (Method)FunctionObject.readMember(in);
}
init(array);
}
private void writeObject(ObjectOutputStream out)
throws IOException
{
out.defaultWriteObject();
int N = methods.length;
out.writeInt(N);
for (int i = 0; i != N; ++i) {
FunctionObject.writeMember(out, methods[i]);
}
}
transient Method methods[];
transient Class[][] methodTypes;
private static Method method_setAccessible = null;