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
Родитель c1add24197
Коммит dd893acd8d
4 изменённых файлов: 167 добавлений и 102 удалений

Просмотреть файл

@ -120,17 +120,19 @@ class JavaMembers
private Member findExplicitFunction(String name, boolean isStatic) private Member findExplicitFunction(String name, boolean isStatic)
{ {
Hashtable ht = isStatic ? staticMembers : members;
int sigStart = name.indexOf('('); int sigStart = name.indexOf('(');
if (sigStart < 0) { return null; }
Hashtable ht = isStatic ? staticMembers : members;
Member[] methodsOrCtors = null; Member[] methodsOrCtors = null;
NativeJavaMethod method = null; Class[][] methodOrCtorTypes = null;
boolean isCtor = (isStatic && sigStart == 0); boolean isCtor = (isStatic && sigStart == 0);
if (isCtor) { if (isCtor) {
// Explicit request for an overloaded constructor // Explicit request for an overloaded constructor
methodsOrCtors = ctors; methodsOrCtors = ctors;
} methodOrCtorTypes = ctorTypes;
else if (sigStart > 0) { } else {
// Explicit request for an overloaded method // Explicit request for an overloaded method
String trueName = name.substring(0,sigStart); String trueName = name.substring(0,sigStart);
Object obj = ht.get(trueName); Object obj = ht.get(trueName);
@ -138,17 +140,19 @@ class JavaMembers
// Try to get static member from instance (LC3) // Try to get static member from instance (LC3)
obj = staticMembers.get(trueName); obj = staticMembers.get(trueName);
} }
if (obj != null && obj instanceof NativeJavaMethod) { if (obj instanceof NativeJavaMethod) {
method = (NativeJavaMethod)obj; NativeJavaMethod njm = (NativeJavaMethod)obj;
methodsOrCtors = method.methods; methodsOrCtors = njm.methods;
methodOrCtorTypes = njm.methodTypes;
} }
} }
if (methodsOrCtors != null) { if (methodsOrCtors != null) {
for (int i = 0; i < methodsOrCtors.length; i++) { for (int i = 0; i < methodsOrCtors.length; i++) {
Member member = methodsOrCtors[i]; Member member = methodsOrCtors[i];
String nameWithSig = NativeJavaMethod.memberSignature(member); Class[] type = methodOrCtorTypes[i];
if (name.equals(nameWithSig)) { String sig = NativeJavaMethod.memberSignature(member, type);
if (name.equals(sig)) {
return member; return member;
} }
} }
@ -266,7 +270,7 @@ class JavaMembers
makeBeanProperties(scope, false); makeBeanProperties(scope, false);
makeBeanProperties(scope, true); makeBeanProperties(scope, true);
ctors = cl.getConstructors(); reflectCtors();
} }
private void reflectMethods(Scriptable scope) private void reflectMethods(Scriptable scope)
@ -303,30 +307,6 @@ class JavaMembers
initNativeMethods(members, scope); 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) private void reflectFields(Scriptable scope)
{ {
Field[] fields = cl.getFields(); 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) 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, private static Method extractGetMethod(NativeJavaMethod njm,
boolean isStatic) boolean isStatic)
{ {
@ -469,7 +484,7 @@ class JavaMembers
Method method = methods[0]; Method method = methods[0];
// Make sure the method static-ness is preserved for this property. // Make sure the method static-ness is preserved for this property.
if (!isStatic || Modifier.isStatic(method.getModifiers())) { if (!isStatic || Modifier.isStatic(method.getModifiers())) {
Class[] params = method.getParameterTypes(); Class[] params = njm.methodTypes[0];
if (params != null && params.length == 0) { if (params != null && params.length == 0) {
Class type = method.getReturnType(); Class type = method.getReturnType();
if (type != null && type != Void.TYPE) { if (type != null && type != Void.TYPE) {
@ -499,7 +514,7 @@ class JavaMembers
Method method = methods[i]; Method method = methods[i];
if (!isStatic || Modifier.isStatic(method.getModifiers())) { if (!isStatic || Modifier.isStatic(method.getModifiers())) {
if (method.getReturnType() == Void.TYPE) { if (method.getReturnType() == Void.TYPE) {
Class[] params = method.getParameterTypes(); Class[] params = njm.methodTypes[i];
if (params != null && params.length == 1) { if (params != null && params.length == 1) {
if (pass == 1) { if (pass == 1) {
if (params[0] == type) { if (params[0] == type) {
@ -634,6 +649,7 @@ class JavaMembers
private Hashtable staticMembers; private Hashtable staticMembers;
private Hashtable staticFieldAndMethods; private Hashtable staticFieldAndMethods;
Constructor[] ctors; Constructor[] ctors;
Class[][] ctorTypes;
} }
class BeanProperty class BeanProperty

Просмотреть файл

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

Просмотреть файл

@ -38,6 +38,7 @@
package org.mozilla.javascript; package org.mozilla.javascript;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.io.*;
/** /**
* This class reflects a single Java constructor into the JavaScript * This class reflects a single Java constructor into the JavaScript
@ -58,7 +59,8 @@ public class NativeJavaConstructor extends BaseFunction
public NativeJavaConstructor(Constructor ctor) public NativeJavaConstructor(Constructor ctor)
{ {
this.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); this.functionName = "<init>".concat(sig);
} }
@ -71,8 +73,8 @@ public class NativeJavaConstructor extends BaseFunction
throw new RuntimeException("No constructor defined for call"); throw new RuntimeException("No constructor defined for call");
} }
return NativeJavaClass.constructSpecific(cx, scope, return NativeJavaClass.constructSpecific(cx, scope, this, args,
this, constructor, args); constructor, constructorType);
} }
public String toString() public String toString()
@ -80,11 +82,23 @@ public class NativeJavaConstructor extends BaseFunction
return "[JavaConstructor " + constructor.getName() + "]"; 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;
} }

Просмотреть файл

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