зеркало из https://github.com/mozilla/pjs.git
I changed FunctionObject and ScriptableObject to use MemberBox wrapper for native methods, getters and setters that allowed to get following:
1. Method serialization code in MemberBox takes care of all serialization so ScriptableObject and FunctionObject does not need anything on its own. 2. Invoker optimization is extended to getters and setters in ScriptableObject. 3. Recovery from IllegalAccessException is extended to all cases of method invocation via reflection. 4. All error wrapping happens in a single class so FunctionObject and ScriptableObject does not need to wary about it.
This commit is contained in:
Родитель
0de430b20c
Коммит
cb7cd3ec6f
|
@ -115,20 +115,17 @@ public class FunctionObject extends BaseFunction
|
|||
public FunctionObject(String name, Member methodOrConstructor,
|
||||
Scriptable scope)
|
||||
{
|
||||
String methodName;
|
||||
Class[] types;
|
||||
GlobalScope global = GlobalScope.get(scope);
|
||||
if (methodOrConstructor instanceof Constructor) {
|
||||
ctor = (Constructor) methodOrConstructor;
|
||||
member = new MemberBox((Constructor) methodOrConstructor, global);
|
||||
isStatic = true; // well, doesn't take a 'this'
|
||||
types = ctor.getParameterTypes();
|
||||
methodName = ctor.getName();
|
||||
} else {
|
||||
method = (Method) methodOrConstructor;
|
||||
isStatic = Modifier.isStatic(method.getModifiers());
|
||||
types = method.getParameterTypes();
|
||||
methodName = method.getName();
|
||||
member = new MemberBox((Method) methodOrConstructor, global);
|
||||
isStatic = member.isStatic();
|
||||
}
|
||||
String methodName = member.getName();
|
||||
this.functionName = name;
|
||||
Class[] types = member.argTypes;
|
||||
int arity = types.length;
|
||||
if (arity == 4 && (types[1].isArray() || types[2].isArray())) {
|
||||
// Either variable args or an error.
|
||||
|
@ -170,7 +167,8 @@ public class FunctionObject extends BaseFunction
|
|||
}
|
||||
}
|
||||
|
||||
if (method != null) {
|
||||
if (member.isMethod()) {
|
||||
Method method = member.method();
|
||||
Class returnType = method.getReturnType();
|
||||
if (returnType == Void.TYPE) {
|
||||
hasVoidReturn = true;
|
||||
|
@ -182,8 +180,9 @@ public class FunctionObject extends BaseFunction
|
|||
returnType.getName(), methodName);
|
||||
}
|
||||
}
|
||||
member.prepareInvokerOptimization();
|
||||
} else {
|
||||
Class ctorType = ctor.getDeclaringClass();
|
||||
Class ctorType = member.getDeclaringClass();
|
||||
if (!ScriptRuntime.ScriptableClass.isAssignableFrom(ctorType)) {
|
||||
throw Context.reportRuntimeError1(
|
||||
"msg.bad.ctor.return", ctorType.getName());
|
||||
|
@ -191,31 +190,6 @@ public class FunctionObject extends BaseFunction
|
|||
}
|
||||
|
||||
ScriptRuntime.setFunctionProtoAndParent(scope, this);
|
||||
|
||||
if (method != null) {
|
||||
GlobalScope global = GlobalScope.get(scope);
|
||||
if (global.invokerOptimization) {
|
||||
Invoker master = (Invoker)global.invokerMaster;
|
||||
if (master == null) {
|
||||
master = Invoker.makeMaster();
|
||||
if (master == null) {
|
||||
global.invokerOptimization = false;
|
||||
} else {
|
||||
global.invokerMaster = master;
|
||||
}
|
||||
}
|
||||
if (master != null) {
|
||||
Context cx = Context.getContext();
|
||||
try {
|
||||
invoker = master.createInvoker(cx, method, types);
|
||||
} catch (SecurityException ex) {
|
||||
// Ignore invoker optimization in case of
|
||||
// SecurityException which can be the case if class
|
||||
// loader creation is disabled.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -299,10 +273,10 @@ public class FunctionObject extends BaseFunction
|
|||
*/
|
||||
public Member getMethodOrConstructor()
|
||||
{
|
||||
if (method != null) {
|
||||
return method;
|
||||
if (member.isMethod()) {
|
||||
return member.method();
|
||||
} else {
|
||||
return ctor;
|
||||
return member.ctor();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -423,9 +397,8 @@ public class FunctionObject extends BaseFunction
|
|||
if (parmsLength < 0) {
|
||||
return callVarargs(cx, thisObj, args);
|
||||
}
|
||||
if (!isStatic && method != null) {
|
||||
// OPT: cache "clazz"?
|
||||
Class clazz = method.getDeclaringClass();
|
||||
if (!isStatic) {
|
||||
Class clazz = member.getDeclaringClass();
|
||||
if (!clazz.isInstance(thisObj)) {
|
||||
boolean compatible = false;
|
||||
if (thisObj == scope) {
|
||||
|
@ -475,21 +448,12 @@ public class FunctionObject extends BaseFunction
|
|||
}
|
||||
|
||||
Object result;
|
||||
if (invoker != null) {
|
||||
if (method == null) Context.codeBug();
|
||||
try {
|
||||
result = invoker.invoke(thisObj, invokeArgs);
|
||||
} catch (Exception ex) {
|
||||
throw ScriptRuntime.throwAsUncheckedException(ex);
|
||||
}
|
||||
if (member.isMethod()) {
|
||||
result = member.invoke(thisObj, invokeArgs);
|
||||
} else {
|
||||
try {
|
||||
result = (method == null) ? ctor.newInstance(invokeArgs)
|
||||
: method.invoke(thisObj, invokeArgs);
|
||||
} catch (Exception ex) {
|
||||
throw ScriptRuntime.throwAsUncheckedException(ex);
|
||||
}
|
||||
result = member.newInstance(invokeArgs);
|
||||
}
|
||||
|
||||
return hasVoidReturn ? Undefined.instance : result;
|
||||
}
|
||||
|
||||
|
@ -500,12 +464,12 @@ public class FunctionObject extends BaseFunction
|
|||
* new objects.
|
||||
*/
|
||||
public Scriptable createObject(Context cx, Scriptable scope) {
|
||||
if (method == null || parmsLength == VARARGS_CTOR) {
|
||||
if (member.isCtor() || parmsLength == VARARGS_CTOR) {
|
||||
return null;
|
||||
}
|
||||
Scriptable result;
|
||||
try {
|
||||
result = (Scriptable) method.getDeclaringClass().newInstance();
|
||||
result = (Scriptable) member.getDeclaringClass().newInstance();
|
||||
} catch (Exception ex) {
|
||||
throw ScriptRuntime.throwAsUncheckedException(ex);
|
||||
}
|
||||
|
@ -517,21 +481,17 @@ public class FunctionObject extends BaseFunction
|
|||
|
||||
private Object callVarargs(Context cx, Scriptable thisObj, Object[] args)
|
||||
{
|
||||
try {
|
||||
if (parmsLength == VARARGS_METHOD) {
|
||||
Object[] invokeArgs = { cx, thisObj, args, this };
|
||||
Object result = method.invoke(null, invokeArgs);
|
||||
return hasVoidReturn ? Undefined.instance : result;
|
||||
} else {
|
||||
boolean inNewExpr = (thisObj == null);
|
||||
Boolean b = inNewExpr ? Boolean.TRUE : Boolean.FALSE;
|
||||
Object[] invokeArgs = { cx, args, this, b };
|
||||
return (method == null)
|
||||
? ctor.newInstance(invokeArgs)
|
||||
: method.invoke(null, invokeArgs);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw ScriptRuntime.throwAsUncheckedException(ex);
|
||||
if (parmsLength == VARARGS_METHOD) {
|
||||
Object[] invokeArgs = { cx, thisObj, args, this };
|
||||
Object result = member.invoke(null, invokeArgs);
|
||||
return hasVoidReturn ? Undefined.instance : result;
|
||||
} else {
|
||||
boolean inNewExpr = (thisObj == null);
|
||||
Boolean b = inNewExpr ? Boolean.TRUE : Boolean.FALSE;
|
||||
Object[] invokeArgs = { cx, args, this, b };
|
||||
return (member.isCtor())
|
||||
? member.newInstance(invokeArgs)
|
||||
: member.invoke(null, invokeArgs);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -543,32 +503,12 @@ public class FunctionObject extends BaseFunction
|
|||
return parmsLength == VARARGS_CTOR;
|
||||
}
|
||||
|
||||
private void writeObject(ObjectOutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
out.defaultWriteObject();
|
||||
boolean hasConstructor = ctor != null;
|
||||
Member member = hasConstructor ? (Member)ctor : (Member)method;
|
||||
writeMember(out, member);
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
in.defaultReadObject();
|
||||
Member member = readMember(in);
|
||||
if (member instanceof Method) {
|
||||
method = (Method) member;
|
||||
} else {
|
||||
ctor = (Constructor) member;
|
||||
}
|
||||
if (parmsLength > 0) {
|
||||
Class[] types;
|
||||
if (method != null) {
|
||||
types = method.getParameterTypes();
|
||||
} else {
|
||||
types = ctor.getParameterTypes();
|
||||
}
|
||||
Class[] types = member.argTypes;
|
||||
typeTags = new byte[parmsLength];
|
||||
for (int i = 0; i != parmsLength; ++i) {
|
||||
typeTags[i] = (byte)getTypeTag(types[i]);
|
||||
|
@ -576,114 +516,6 @@ public class FunctionObject extends BaseFunction
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a Constructor or Method object.
|
||||
*
|
||||
* Methods and Constructors are not serializable, so we must serialize
|
||||
* information about the class, the name, and the parameters and
|
||||
* recreate upon deserialization.
|
||||
*/
|
||||
static void writeMember(ObjectOutputStream out, Member member)
|
||||
throws IOException
|
||||
{
|
||||
if (member == null) {
|
||||
out.writeBoolean(false);
|
||||
return;
|
||||
}
|
||||
out.writeBoolean(true);
|
||||
if (!(member instanceof Method || member instanceof Constructor))
|
||||
throw new IllegalArgumentException("not Method or Constructor");
|
||||
out.writeBoolean(member instanceof Method);
|
||||
out.writeObject(member.getName());
|
||||
out.writeObject(member.getDeclaringClass());
|
||||
if (member instanceof Method) {
|
||||
writeParameters(out, ((Method) member).getParameterTypes());
|
||||
} else {
|
||||
writeParameters(out, ((Constructor) member).getParameterTypes());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a Method or a Constructor from the stream.
|
||||
*/
|
||||
static Member readMember(ObjectInputStream in)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
if (!in.readBoolean())
|
||||
return null;
|
||||
boolean isMethod = in.readBoolean();
|
||||
String name = (String) in.readObject();
|
||||
Class declaring = (Class) in.readObject();
|
||||
Class[] parms = readParameters(in);
|
||||
try {
|
||||
if (isMethod) {
|
||||
return declaring.getMethod(name, parms);
|
||||
} else {
|
||||
return declaring.getConstructor(parms);
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new IOException("Cannot find member: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
private static final Class[] primitives = {
|
||||
Boolean.TYPE,
|
||||
Byte.TYPE,
|
||||
Character.TYPE,
|
||||
Double.TYPE,
|
||||
Float.TYPE,
|
||||
Integer.TYPE,
|
||||
Long.TYPE,
|
||||
Short.TYPE,
|
||||
Void.TYPE
|
||||
};
|
||||
|
||||
/**
|
||||
* Writes an array of parameter types to the stream.
|
||||
*
|
||||
* Requires special handling because primitive types cannot be
|
||||
* found upon deserialization by the default Java implementation.
|
||||
*/
|
||||
static void writeParameters(ObjectOutputStream out, Class[] parms)
|
||||
throws IOException
|
||||
{
|
||||
out.writeShort(parms.length);
|
||||
outer:
|
||||
for (int i=0; i < parms.length; i++) {
|
||||
Class parm = parms[i];
|
||||
out.writeBoolean(parm.isPrimitive());
|
||||
if (!parm.isPrimitive()) {
|
||||
out.writeObject(parm);
|
||||
continue;
|
||||
}
|
||||
for (int j=0; j < primitives.length; j++) {
|
||||
if (parm.equals(primitives[j])) {
|
||||
out.writeByte(j);
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Primitive " + parm +
|
||||
" not found");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an array of parameter types from the stream.
|
||||
*/
|
||||
static Class[] readParameters(ObjectInputStream in)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
Class[] result = new Class[in.readShort()];
|
||||
for (int i=0; i < result.length; i++) {
|
||||
if (!in.readBoolean()) {
|
||||
result[i] = (Class) in.readObject();
|
||||
continue;
|
||||
}
|
||||
result[i] = primitives[in.readByte()];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static final short VARARGS_METHOD = -1;
|
||||
private static final short VARARGS_CTOR = -2;
|
||||
|
||||
|
@ -697,9 +529,7 @@ public class FunctionObject extends BaseFunction
|
|||
public static final int JAVA_SCRIPTABLE_TYPE = 5;
|
||||
public static final int JAVA_OBJECT_TYPE = 6;
|
||||
|
||||
transient Method method;
|
||||
transient Constructor ctor;
|
||||
transient Invoker invoker;
|
||||
MemberBox member;
|
||||
transient private byte[] typeTags;
|
||||
private int parmsLength;
|
||||
private boolean hasVoidReturn;
|
||||
|
|
|
@ -1571,7 +1571,7 @@ public class Interpreter
|
|||
}
|
||||
}
|
||||
|
||||
static int[] getLineNumbers(InterpreterData data)
|
||||
static int[] getLineNumbers(InterpreterData data)
|
||||
{
|
||||
UintMap presentLines = new UintMap();
|
||||
|
||||
|
@ -1590,8 +1590,8 @@ public class Interpreter
|
|||
|
||||
return presentLines.getKeys();
|
||||
}
|
||||
|
||||
static String getSourcePositionFromStack(Context cx, int[] linep)
|
||||
|
||||
static String getSourcePositionFromStack(Context cx, int[] linep)
|
||||
{
|
||||
InterpreterData idata = cx.interpreterData;
|
||||
linep[0] = getShort(idata.itsICode, cx.interpreterLineIndex);
|
||||
|
|
|
@ -48,8 +48,10 @@ public abstract class Invoker {
|
|||
public abstract Object invoke(Object that, Object [] args);
|
||||
|
||||
/** Factory method to get invoker for given method */
|
||||
public Invoker createInvoker(Context cx, Method method, Class[] types) {
|
||||
return null;
|
||||
public Invoker createInvoker(Method method, Class[] types)
|
||||
{
|
||||
// should not be called unless master
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
public static Invoker makeMaster()
|
||||
|
|
|
@ -303,7 +303,7 @@ class JavaMembers
|
|||
makeBeanProperties(scope, false);
|
||||
makeBeanProperties(scope, true);
|
||||
|
||||
reflectCtors();
|
||||
reflectCtors(scope);
|
||||
}
|
||||
|
||||
private void reflectMethods(Scriptable scope)
|
||||
|
@ -459,26 +459,28 @@ class JavaMembers
|
|||
}
|
||||
}
|
||||
|
||||
private void reflectCtors()
|
||||
private void reflectCtors(Scriptable scope)
|
||||
{
|
||||
Constructor[] constructors = cl.getConstructors();
|
||||
int N = constructors.length;
|
||||
ctors = new MemberBox[N];
|
||||
GlobalScope global = GlobalScope.get(scope);
|
||||
for (int i = 0; i != N; ++i) {
|
||||
ctors[i] = new MemberBox(constructors[i]);
|
||||
ctors[i] = new MemberBox(constructors[i], global);
|
||||
}
|
||||
}
|
||||
|
||||
private static void initNativeMethods(Hashtable ht, Scriptable scope)
|
||||
{
|
||||
Enumeration e = ht.keys();
|
||||
GlobalScope global = GlobalScope.get(scope);
|
||||
while (e.hasMoreElements()) {
|
||||
String name = (String)e.nextElement();
|
||||
MemberBox[] methods;
|
||||
Object value = ht.get(name);
|
||||
if (value instanceof Method) {
|
||||
methods = new MemberBox[1];
|
||||
methods[0] = new MemberBox((Method)value);
|
||||
methods[0] = new MemberBox((Method)value, global);
|
||||
} else {
|
||||
ObjArray overloadedMethods = (ObjArray)value;
|
||||
int N = overloadedMethods.size();
|
||||
|
@ -486,7 +488,7 @@ class JavaMembers
|
|||
methods = new MemberBox[N];
|
||||
for (int i = 0; i != N; ++i) {
|
||||
Method method = (Method)overloadedMethods.get(i);
|
||||
methods[i] = new MemberBox(method);
|
||||
methods[i] = new MemberBox(method, global);
|
||||
}
|
||||
}
|
||||
NativeJavaMethod fun = new NativeJavaMethod(methods);
|
||||
|
|
|
@ -41,8 +41,8 @@ import java.io.*;
|
|||
|
||||
/**
|
||||
* Wrappper class for Method and Constructor instances to cache
|
||||
* getParameterTypes() results and to recover from IllegalAccessException
|
||||
* in some cases.
|
||||
* getParameterTypes() results, recover from IllegalAccessException
|
||||
* in some cases and provide serialization support.
|
||||
*
|
||||
* @author Igor Bukanov
|
||||
*/
|
||||
|
@ -50,13 +50,15 @@ import java.io.*;
|
|||
final class MemberBox implements Serializable
|
||||
{
|
||||
|
||||
MemberBox(Method method)
|
||||
MemberBox(Method method, GlobalScope scope)
|
||||
{
|
||||
this.scope = scope;
|
||||
init(method);
|
||||
}
|
||||
|
||||
MemberBox(Constructor constructor)
|
||||
MemberBox(Constructor constructor, GlobalScope scope)
|
||||
{
|
||||
this.scope = scope;
|
||||
init(constructor);
|
||||
}
|
||||
|
||||
|
@ -66,6 +68,25 @@ final class MemberBox implements Serializable
|
|||
this.argTypes = method.getParameterTypes();
|
||||
}
|
||||
|
||||
void prepareInvokerOptimization()
|
||||
{
|
||||
if (scope.invokerOptimization) {
|
||||
Invoker master = (Invoker)scope.invokerMaster;
|
||||
if (master == null) {
|
||||
master = Invoker.makeMaster();
|
||||
if (master == null) {
|
||||
scope.invokerOptimization = false;
|
||||
} else {
|
||||
scope.invokerMaster = master;
|
||||
}
|
||||
}
|
||||
if (master != null) {
|
||||
invoker = master.createInvoker(method(), argTypes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void init(Constructor constructor)
|
||||
{
|
||||
this.memberObject = constructor;
|
||||
|
@ -134,37 +155,58 @@ final class MemberBox implements Serializable
|
|||
}
|
||||
|
||||
Object invoke(Object target, Object[] args)
|
||||
throws IllegalAccessException, InvocationTargetException
|
||||
{
|
||||
if (invoker != null) {
|
||||
try {
|
||||
return invoker.invoke(target, args);
|
||||
} catch (Exception ex) {
|
||||
throw ScriptRuntime.throwAsUncheckedException(ex);
|
||||
} catch (LinkageError ex) {
|
||||
invoker = null;
|
||||
}
|
||||
}
|
||||
Method method = method();
|
||||
try {
|
||||
return method.invoke(target, args);
|
||||
} catch (IllegalAccessException ex) {
|
||||
Method accessible = searchAccessibleMethod(method, argTypes);
|
||||
if (accessible != null) {
|
||||
memberObject = accessible;
|
||||
method = accessible;
|
||||
} else {
|
||||
if (!tryToMakeAccessible(method)) {
|
||||
throw ex;
|
||||
try {
|
||||
return method.invoke(target, args);
|
||||
} catch (IllegalAccessException ex) {
|
||||
Method accessible = searchAccessibleMethod(method, argTypes);
|
||||
if (accessible != null) {
|
||||
memberObject = accessible;
|
||||
method = accessible;
|
||||
} else {
|
||||
if (!tryToMakeAccessible(method)) {
|
||||
throw ScriptRuntime.throwAsUncheckedException(ex);
|
||||
}
|
||||
}
|
||||
// Retry after recovery
|
||||
return method.invoke(target, args);
|
||||
}
|
||||
return method.invoke(target, args);
|
||||
} catch (IllegalAccessException ex) {
|
||||
throw ScriptRuntime.throwAsUncheckedException(ex);
|
||||
} catch (InvocationTargetException ex) {
|
||||
throw ScriptRuntime.throwAsUncheckedException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
Object newInstance(Object[] args)
|
||||
throws InvocationTargetException, IllegalAccessException,
|
||||
InstantiationException
|
||||
{
|
||||
Constructor ctor = ctor();
|
||||
try {
|
||||
return ctor.newInstance(args);
|
||||
} catch (IllegalAccessException ex) {
|
||||
if (!tryToMakeAccessible(ctor)) {
|
||||
throw ex;
|
||||
try {
|
||||
return ctor.newInstance(args);
|
||||
} catch (IllegalAccessException ex) {
|
||||
if (!tryToMakeAccessible(ctor)) {
|
||||
throw ScriptRuntime.throwAsUncheckedException(ex);
|
||||
}
|
||||
}
|
||||
return ctor.newInstance(args);
|
||||
} catch (IllegalAccessException ex) {
|
||||
throw ScriptRuntime.throwAsUncheckedException(ex);
|
||||
} catch (InvocationTargetException ex) {
|
||||
throw ScriptRuntime.throwAsUncheckedException(ex);
|
||||
} catch (InstantiationException ex) {
|
||||
throw ScriptRuntime.throwAsUncheckedException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -230,7 +272,7 @@ final class MemberBox implements Serializable
|
|||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
in.defaultReadObject();
|
||||
Member member = FunctionObject.readMember(in);
|
||||
Member member = readMember(in);
|
||||
if (member instanceof Method) {
|
||||
init((Method)member);
|
||||
} else {
|
||||
|
@ -241,11 +283,121 @@ final class MemberBox implements Serializable
|
|||
private void writeObject(ObjectOutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
FunctionObject.writeMember(out, memberObject);
|
||||
writeMember(out, memberObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a Constructor or Method object.
|
||||
*
|
||||
* Methods and Constructors are not serializable, so we must serialize
|
||||
* information about the class, the name, and the parameters and
|
||||
* recreate upon deserialization.
|
||||
*/
|
||||
private static void writeMember(ObjectOutputStream out, Member member)
|
||||
throws IOException
|
||||
{
|
||||
if (member == null) {
|
||||
out.writeBoolean(false);
|
||||
return;
|
||||
}
|
||||
out.writeBoolean(true);
|
||||
if (!(member instanceof Method || member instanceof Constructor))
|
||||
throw new IllegalArgumentException("not Method or Constructor");
|
||||
out.writeBoolean(member instanceof Method);
|
||||
out.writeObject(member.getName());
|
||||
out.writeObject(member.getDeclaringClass());
|
||||
if (member instanceof Method) {
|
||||
writeParameters(out, ((Method) member).getParameterTypes());
|
||||
} else {
|
||||
writeParameters(out, ((Constructor) member).getParameterTypes());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a Method or a Constructor from the stream.
|
||||
*/
|
||||
private static Member readMember(ObjectInputStream in)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
if (!in.readBoolean())
|
||||
return null;
|
||||
boolean isMethod = in.readBoolean();
|
||||
String name = (String) in.readObject();
|
||||
Class declaring = (Class) in.readObject();
|
||||
Class[] parms = readParameters(in);
|
||||
try {
|
||||
if (isMethod) {
|
||||
return declaring.getMethod(name, parms);
|
||||
} else {
|
||||
return declaring.getConstructor(parms);
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new IOException("Cannot find member: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
private static final Class[] primitives = {
|
||||
Boolean.TYPE,
|
||||
Byte.TYPE,
|
||||
Character.TYPE,
|
||||
Double.TYPE,
|
||||
Float.TYPE,
|
||||
Integer.TYPE,
|
||||
Long.TYPE,
|
||||
Short.TYPE,
|
||||
Void.TYPE
|
||||
};
|
||||
|
||||
/**
|
||||
* Writes an array of parameter types to the stream.
|
||||
*
|
||||
* Requires special handling because primitive types cannot be
|
||||
* found upon deserialization by the default Java implementation.
|
||||
*/
|
||||
private static void writeParameters(ObjectOutputStream out, Class[] parms)
|
||||
throws IOException
|
||||
{
|
||||
out.writeShort(parms.length);
|
||||
outer:
|
||||
for (int i=0; i < parms.length; i++) {
|
||||
Class parm = parms[i];
|
||||
out.writeBoolean(parm.isPrimitive());
|
||||
if (!parm.isPrimitive()) {
|
||||
out.writeObject(parm);
|
||||
continue;
|
||||
}
|
||||
for (int j=0; j < primitives.length; j++) {
|
||||
if (parm.equals(primitives[j])) {
|
||||
out.writeByte(j);
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Primitive " + parm +
|
||||
" not found");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an array of parameter types from the stream.
|
||||
*/
|
||||
private static Class[] readParameters(ObjectInputStream in)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
Class[] result = new Class[in.readShort()];
|
||||
for (int i=0; i < result.length; i++) {
|
||||
if (!in.readBoolean()) {
|
||||
result[i] = (Class) in.readObject();
|
||||
continue;
|
||||
}
|
||||
result[i] = primitives[in.readByte()];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private GlobalScope scope;
|
||||
private transient Member memberObject;
|
||||
transient Class[] argTypes;
|
||||
transient Invoker invoker;
|
||||
|
||||
private static Method method_setAccessible;
|
||||
|
||||
|
|
|
@ -227,24 +227,7 @@ public class NativeJavaClass extends NativeJavaObject implements Function {
|
|||
args[i] = x;
|
||||
}
|
||||
}
|
||||
Object instance;
|
||||
try {
|
||||
instance = ctor.newInstance(args);
|
||||
} catch (InstantiationException instEx) {
|
||||
throw Context.reportRuntimeError2(
|
||||
"msg.cant.instantiate",
|
||||
instEx.getMessage(), classObject.getName());
|
||||
} catch (IllegalArgumentException argEx) {
|
||||
String signature = NativeJavaMethod.scriptSignature(args);
|
||||
String ctorString = ctor.ctor().toString();
|
||||
throw Context.reportRuntimeError3(
|
||||
"msg.bad.ctor.sig", argEx.getMessage(), ctorString, signature);
|
||||
} catch (IllegalAccessException accessEx) {
|
||||
throw Context.reportRuntimeError1(
|
||||
"msg.java.internal.private", accessEx.getMessage());
|
||||
} catch (Exception ex) {
|
||||
throw ScriptRuntime.throwAsUncheckedException(ex);
|
||||
}
|
||||
Object instance = ctor.newInstance(args);
|
||||
// we need to force this to be wrapped, because construct _has_
|
||||
// to return a scriptable
|
||||
return cx.getWrapFactory().wrapNewObject(cx, topLevel, instance);
|
||||
|
|
|
@ -67,7 +67,7 @@ public class NativeJavaMethod extends BaseFunction
|
|||
|
||||
public NativeJavaMethod(Method method, String name)
|
||||
{
|
||||
this(new MemberBox(method), name);
|
||||
this(new MemberBox(method, null), name);
|
||||
}
|
||||
|
||||
private static String scriptSignature(Object value)
|
||||
|
@ -198,17 +198,7 @@ public class NativeJavaMethod extends BaseFunction
|
|||
printDebug("Calling ", meth, args);
|
||||
}
|
||||
|
||||
Object retval;
|
||||
try {
|
||||
retval = meth.invoke(javaObject, args);
|
||||
} catch (IllegalAccessException accessEx) {
|
||||
throw Context.reportRuntimeError(
|
||||
"While attempting to call \"" + meth.getName() +
|
||||
"\" in class \"" + meth.getDeclaringClass().getName() +
|
||||
"\" receieved " + accessEx.toString());
|
||||
} catch (Exception ex) {
|
||||
throw ScriptRuntime.throwAsUncheckedException(ex);
|
||||
}
|
||||
Object retval = meth.invoke(javaObject, args);
|
||||
Class staticType = meth.method().getReturnType();
|
||||
|
||||
if (debug) {
|
||||
|
|
|
@ -204,11 +204,7 @@ public abstract class ScriptableObject implements Scriptable, Serializable,
|
|||
args = new Object[] { this };
|
||||
}
|
||||
|
||||
try {
|
||||
return slot.getter.invoke(getterThis, args);
|
||||
} catch (Exception e) {
|
||||
throw ScriptRuntime.throwAsUncheckedException(e);
|
||||
}
|
||||
return slot.getter.invoke(getterThis, args);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -285,7 +281,7 @@ public abstract class ScriptableObject implements Scriptable, Serializable,
|
|||
Object[] args;
|
||||
Object setterResult;
|
||||
Context cx = Context.getContext();
|
||||
Class pTypes[] = slot.setter.getParameterTypes();
|
||||
Class pTypes[] = slot.setter.argTypes;
|
||||
Class desired = pTypes[pTypes.length - 1];
|
||||
// ALERT: cache tag since it is already calculated in defineProperty ?
|
||||
int tag = FunctionObject.getTypeTag(desired);
|
||||
|
@ -305,11 +301,7 @@ public abstract class ScriptableObject implements Scriptable, Serializable,
|
|||
slot.stringKey);
|
||||
}
|
||||
|
||||
try {
|
||||
setterResult = slot.setter.invoke(setterThis, args);
|
||||
} catch (Exception e) {
|
||||
throw ScriptRuntime.throwAsUncheckedException(e);
|
||||
}
|
||||
setterResult = slot.setter.invoke(setterThis, args);
|
||||
|
||||
if (slot.setterReturnsValue) {
|
||||
// Replace Getter slot by a simple one
|
||||
|
@ -1158,15 +1150,19 @@ public abstract class ScriptableObject implements Scriptable, Serializable,
|
|||
}
|
||||
}
|
||||
|
||||
GlobalScope global = GlobalScope.get(this);
|
||||
GetterSlot slot = new GetterSlot();
|
||||
slot.delegateTo = delegateTo;
|
||||
slot.getter = getter;
|
||||
slot.setter = setter;
|
||||
slot.setterReturnsValue = setter != null && setter.getReturnType() != Void.TYPE;
|
||||
slot.getter = new MemberBox(getter, global);
|
||||
slot.getter.prepareInvokerOptimization();
|
||||
if (setter != null) {
|
||||
slot.setter = new MemberBox(setter, global);
|
||||
slot.setter.prepareInvokerOptimization();
|
||||
slot.setterReturnsValue = setter.getReturnType() != Void.TYPE;
|
||||
}
|
||||
slot.value = null;
|
||||
slot.attributes = (short) attributes;
|
||||
slot.flags = (byte)flags;
|
||||
|
||||
Slot inserted = addSlot(propertyName, propertyName.hashCode(), slot);
|
||||
if (inserted != slot) {
|
||||
throw new RuntimeException("Property already exists");
|
||||
|
@ -1829,26 +1825,11 @@ public abstract class ScriptableObject implements Scriptable, Serializable,
|
|||
transient byte wasDeleted;
|
||||
}
|
||||
|
||||
static class GetterSlot extends Slot implements Serializable {
|
||||
static class GetterSlot extends Slot
|
||||
{
|
||||
Object delegateTo; // OPT: merge with "value"
|
||||
transient Method getter;
|
||||
transient Method setter;
|
||||
MemberBox getter;
|
||||
MemberBox setter;
|
||||
boolean setterReturnsValue;
|
||||
|
||||
private void writeObject(ObjectOutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
out.defaultWriteObject();
|
||||
FunctionObject.writeMember(out, getter);
|
||||
FunctionObject.writeMember(out, setter);
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
in.defaultReadObject();
|
||||
getter = (Method) FunctionObject.readMember(in);
|
||||
setter = (Method) FunctionObject.readMember(in);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,12 +51,13 @@ import org.mozilla.classfile.ClassFileWriter;
|
|||
*/
|
||||
public class InvokerImpl extends Invoker {
|
||||
|
||||
public Invoker createInvoker(Context cx, Method method, Class[] types) {
|
||||
public Invoker createInvoker(Method method, Class[] types) {
|
||||
|
||||
Invoker result;
|
||||
int classNum;
|
||||
synchronized (this) {
|
||||
if (invokersCache == null) {
|
||||
Context cx = Context.getCurrentContext();
|
||||
ClassLoader parentLoader = cx.getApplicationClassLoader();
|
||||
classLoader = cx.createClassLoader(parentLoader);
|
||||
// Initialize invokersCache after creation of classloader
|
||||
|
|
Загрузка…
Ссылка в новой задаче