diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/JavaMembers.java b/mozilla/js/rhino/src/org/mozilla/javascript/JavaMembers.java index 61404d5185d..def1a03eac4 100644 --- a/mozilla/js/rhino/src/org/mozilla/javascript/JavaMembers.java +++ b/mozilla/js/rhino/src/org/mozilla/javascript/JavaMembers.java @@ -67,8 +67,7 @@ class JavaMembers if (obj != null) { return true; } else { - Member member = this.findExplicitFunction(name, isStatic); - return member != null; + return null != findExplicitFunction(name, isStatic); } } @@ -95,16 +94,8 @@ class JavaMembers try { if (member instanceof BeanProperty) { BeanProperty bp = (BeanProperty) member; - try { - rval = bp.getter.invoke(javaObject, null); - } catch (IllegalAccessException e) { - rval = NativeJavaMethod.retryIllegalAccessInvoke( - bp.getter, - javaObject, - null, - e); - } - type = bp.getter.getReturnType(); + rval = bp.getter.invoke(javaObject, null); + type = bp.getter.method().getReturnType(); } else { Field field = (Field) member; rval = field.get(isStatic ? null : javaObject); @@ -118,84 +109,6 @@ class JavaMembers return cx.getWrapFactory().wrap(cx, scope, rval, type); } - private Member findExplicitFunction(String name, boolean isStatic) - { - int sigStart = name.indexOf('('); - if (sigStart < 0) { return null; } - - Hashtable ht = isStatic ? staticMembers : members; - Member[] methodsOrCtors = null; - Class[][] methodOrCtorTypes = null; - boolean isCtor = (isStatic && sigStart == 0); - - if (isCtor) { - // Explicit request for an overloaded constructor - methodsOrCtors = ctors; - methodOrCtorTypes = ctorTypes; - } else { - // Explicit request for an overloaded method - String trueName = name.substring(0,sigStart); - Object obj = ht.get(trueName); - if (!isStatic && obj == null) { - // Try to get static member from instance (LC3) - obj = staticMembers.get(trueName); - } - 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]; - Class[] type = methodOrCtorTypes[i]; - String sig = NativeJavaMethod.memberSignature(member, type); - if (name.equals(sig)) { - return member; - } - } - } - - return null; - } - - private Object getExplicitFunction(Scriptable scope, String name, - Object javaObject, boolean isStatic) - { - Hashtable ht = isStatic ? staticMembers : members; - Object member = null; - Member methodOrCtor = this.findExplicitFunction(name, isStatic); - - if (methodOrCtor != null) { - Scriptable prototype = - ScriptableObject.getFunctionPrototype(scope); - - if (methodOrCtor instanceof Constructor) { - NativeJavaConstructor fun = - new NativeJavaConstructor((Constructor)methodOrCtor); - fun.setPrototype(prototype); - member = fun; - ht.put(name, fun); - } else { - String trueName = methodOrCtor.getName(); - member = ht.get(trueName); - - if (member instanceof NativeJavaMethod && - ((NativeJavaMethod)member).methods.length > 1 ) { - NativeJavaMethod fun = - new NativeJavaMethod((Method)methodOrCtor, name); - fun.setPrototype(prototype); - ht.put(name, fun); - member = fun; - } - } - } - - return member; - } - public void put(Scriptable scope, String name, Object javaObject, Object value, boolean isStatic) { @@ -214,14 +127,15 @@ class JavaMembers // Is this a bean property "set"? if (member instanceof BeanProperty) { + BeanProperty bp = (BeanProperty)member; + if (bp.setter == null) { + throw reportMemberNotFound(name); + } + Class setType = bp.setter.argTypes[0]; + Object[] args = { NativeJavaObject.coerceType(setType, value, + true) }; try { - Method method = ((BeanProperty) member).setter; - if (method == null) - throw reportMemberNotFound(name); - Class[] types = method.getParameterTypes(); - Object[] args = { NativeJavaObject.coerceType(types[0], value, - true) }; - method.invoke(javaObject, args); + bp.setter.invoke(javaObject, args); } catch (Exception ex) { throw ScriptRuntime.throwAsUncheckedException(ex); } @@ -260,6 +174,125 @@ class JavaMembers return result; } + static String javaSignature(Class type) + { + if (!type.isArray()) { + return type.getName(); + } else { + int arrayDimension = 0; + do { + ++arrayDimension; + type = type.getComponentType(); + } while (type.isArray()); + String name = type.getName(); + String suffix = "[]"; + if (arrayDimension == 1) { + return name.concat(suffix); + } else { + int length = name.length() + arrayDimension * suffix.length(); + StringBuffer sb = new StringBuffer(length); + sb.append(name); + while (arrayDimension != 0) { + --arrayDimension; + sb.append(suffix); + } + return sb.toString(); + } + } + } + + static String liveConnectSignature(Class[] argTypes) + { + int N = argTypes.length; + if (N == 0) { return "()"; } + StringBuffer sb = new StringBuffer(); + sb.append('('); + for (int i = 0; i != N; ++i) { + if (i != 0) { + sb.append(','); + } + sb.append(javaSignature(argTypes[i])); + } + sb.append(')'); + return sb.toString(); + } + + private MemberBox findExplicitFunction(String name, boolean isStatic) + { + int sigStart = name.indexOf('('); + if (sigStart < 0) { return null; } + + Hashtable ht = isStatic ? staticMembers : members; + MemberBox[] methodsOrCtors = null; + boolean isCtor = (isStatic && sigStart == 0); + + if (isCtor) { + // Explicit request for an overloaded constructor + methodsOrCtors = ctors; + } else { + // Explicit request for an overloaded method + String trueName = name.substring(0,sigStart); + Object obj = ht.get(trueName); + if (!isStatic && obj == null) { + // Try to get static member from instance (LC3) + obj = staticMembers.get(trueName); + } + if (obj instanceof NativeJavaMethod) { + NativeJavaMethod njm = (NativeJavaMethod)obj; + methodsOrCtors = njm.methods; + } + } + + if (methodsOrCtors != null) { + for (int i = 0; i < methodsOrCtors.length; i++) { + Class[] type = methodsOrCtors[i].argTypes; + String sig = liveConnectSignature(type); + if (sigStart + sig.length() == name.length() + && name.regionMatches(sigStart, sig, 0, sig.length())) + { + return methodsOrCtors[i]; + } + } + } + + return null; + } + + private Object getExplicitFunction(Scriptable scope, String name, + Object javaObject, boolean isStatic) + { + Hashtable ht = isStatic ? staticMembers : members; + Object member = null; + MemberBox methodOrCtor = findExplicitFunction(name, isStatic); + + if (methodOrCtor != null) { + Scriptable prototype = + ScriptableObject.getFunctionPrototype(scope); + + if (methodOrCtor.isCtor()) { + NativeJavaConstructor fun = + new NativeJavaConstructor(methodOrCtor); + fun.setPrototype(prototype); + member = fun; + ht.put(name, fun); + } else { + String trueName = methodOrCtor.getName(); + member = ht.get(trueName); + + if (member instanceof NativeJavaMethod && + ((NativeJavaMethod)member).methods.length > 1 ) { + NativeJavaMethod fun = + new NativeJavaMethod(methodOrCtor, name); + fun.setPrototype(prototype); + ht.put(name, fun); + member = fun; + } + } + } + + return member; + } + private void reflect(Scriptable scope) { // We reflect methods first, because we want overloaded field/method @@ -388,30 +421,31 @@ class JavaMembers continue; // Get the method by this name. - Object method = ht.get(name); - if (!(method instanceof NativeJavaMethod)) + Object member = ht.get(name); + if (!(member instanceof NativeJavaMethod)) continue; - NativeJavaMethod getJavaMethod = (NativeJavaMethod) method; - Method getMethod = extractGetMethod(getJavaMethod, isStatic); - if (getMethod != null) { + NativeJavaMethod njmGet = (NativeJavaMethod)member; + MemberBox getter = extractGetMethod(njmGet.methods, isStatic); + if (getter != null) { // We have a getter. Now, do we have a setter? - Method setMethod = null; - String setter = "set".concat(nameComponent); - if (ht.containsKey(setter)) { - + NativeJavaMethod njmSet = null; + MemberBox setter = null; + String setterName = "set".concat(nameComponent); + if (ht.containsKey(setterName)) { // Is this value a method? - method = ht.get(setter); - if (method instanceof NativeJavaMethod) { - NativeJavaMethod njm = (NativeJavaMethod) method; - Class type = getMethod.getReturnType(); - setMethod = extractSetMethod(type, njm, isStatic); + member = ht.get(setterName); + if (member instanceof NativeJavaMethod) { + njmSet = (NativeJavaMethod)member; + Class type = getter.method().getReturnType(); + setter = extractSetMethod(type, njmSet.methods, + isStatic); } } // Make the property. - BeanProperty bp = new BeanProperty(getMethod, setMethod); + BeanProperty bp = new BeanProperty(getter, setter); toAdd.put(beanPropertyName, bp); } } @@ -427,11 +461,11 @@ class JavaMembers private void reflectCtors() { - ctors = cl.getConstructors(); - int N = ctors.length; - ctorTypes = new Class[N][]; + Constructor[] constructors = cl.getConstructors(); + int N = constructors.length; + ctors = new MemberBox[N]; for (int i = 0; i != N; ++i) { - ctorTypes[i] = ctors[i].getParameterTypes(); + ctors[i] = new MemberBox(constructors[i]); } } @@ -440,16 +474,20 @@ class JavaMembers Enumeration e = ht.keys(); while (e.hasMoreElements()) { String name = (String)e.nextElement(); - Method[] methods; + MemberBox[] methods; Object value = ht.get(name); if (value instanceof Method) { - methods = new Method[1]; - methods[0] = (Method)value; + methods = new MemberBox[1]; + methods[0] = new MemberBox((Method)value); } else { ObjArray overloadedMethods = (ObjArray)value; - if (overloadedMethods.size() < 2) Context.codeBug(); - methods = new Method[overloadedMethods.size()]; - overloadedMethods.toArray(methods); + int N = overloadedMethods.size(); + if (N < 2) Context.codeBug(); + methods = new MemberBox[N]; + for (int i = 0; i != N; ++i) { + Method method = (Method)overloadedMethods.get(i); + methods[i] = new MemberBox(method); + } } NativeJavaMethod fun = new NativeJavaMethod(methods); if (scope != null) { @@ -474,20 +512,18 @@ class JavaMembers return fmht; } - private static Method extractGetMethod(NativeJavaMethod njm, - boolean isStatic) + private static MemberBox extractGetMethod(MemberBox[] methods, + boolean isStatic) { // Grab and inspect the getter method; does it have an empty parameter // list with a return value (eg. a getSomething() or isSomething())? - Method[] methods = njm.methods; if (methods.length == 1) { - Method method = methods[0]; + MemberBox method = methods[0]; // Make sure the method static-ness is preserved for this property. - if (!isStatic || Modifier.isStatic(method.getModifiers())) { - Class[] params = njm.methodTypes[0]; - if (params != null && params.length == 0) { - Class type = method.getReturnType(); - if (type != null && type != Void.TYPE) { + if (!isStatic || method.isStatic()) { + if (method.argTypes.length == 0) { + Class type = method.method().getReturnType(); + if (type != Void.TYPE) { return method; } } @@ -496,9 +532,8 @@ class JavaMembers return null; } - private static Method extractSetMethod(Class type, - NativeJavaMethod njm, - boolean isStatic) + private static MemberBox extractSetMethod(Class type, MemberBox[] methods, + boolean isStatic) { // // Note: it may be preferable to allow NativeJavaMethod.findFunction() @@ -508,14 +543,13 @@ class JavaMembers // Make two passes: one to find a method with direct type assignment, // and one to find a widening conversion. - Method[] methods = njm.methods; for (int pass = 1; pass <= 2; ++pass) { for (int i = 0; i < methods.length; ++i) { - Method method = methods[i]; - if (!isStatic || Modifier.isStatic(method.getModifiers())) { - if (method.getReturnType() == Void.TYPE) { - Class[] params = njm.methodTypes[i]; - if (params != null && params.length == 1) { + MemberBox method = methods[i]; + if (!isStatic || method.isStatic()) { + if (method.method().getReturnType() == Void.TYPE) { + Class[] params = method.argTypes; + if (params.length == 1) { if (pass == 1) { if (params[0] == type) { return method; @@ -648,26 +682,25 @@ class JavaMembers private Hashtable fieldAndMethods; private Hashtable staticMembers; private Hashtable staticFieldAndMethods; - Constructor[] ctors; - Class[][] ctorTypes; + MemberBox[] ctors; } class BeanProperty { - BeanProperty(Method getter, Method setter) + BeanProperty(MemberBox getter, MemberBox setter) { this.getter = getter; this.setter = setter; } - Method getter; - Method setter; + MemberBox getter; + MemberBox setter; } class FieldAndMethods extends NativeJavaMethod { - FieldAndMethods(Method[] methods, Field field) + FieldAndMethods(MemberBox[] methods, Field field) { super(methods); this.field = field; diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/MemberBox.java b/mozilla/js/rhino/src/org/mozilla/javascript/MemberBox.java new file mode 100644 index 00000000000..76fe2497535 --- /dev/null +++ b/mozilla/js/rhino/src/org/mozilla/javascript/MemberBox.java @@ -0,0 +1,262 @@ +/* -*- 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 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): + * Igor Bukanov + * Felix Meschberger + * + * 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; + +import java.lang.reflect.*; +import java.io.*; + +/** + * Wrappper class for Method and Constructor instances to cache + * getParameterTypes() results and to recover from IllegalAccessException + * in some cases. + * + * @author Igor Bukanov + */ + +final class MemberBox implements Serializable +{ + + MemberBox(Method method) + { + init(method); + } + + MemberBox(Constructor constructor) + { + init(constructor); + } + + private void init(Method method) + { + this.memberObject = method; + this.argTypes = method.getParameterTypes(); + } + + private void init(Constructor constructor) + { + this.memberObject = constructor; + this.argTypes = constructor.getParameterTypes(); + } + + Method method() + { + return (Method)memberObject; + } + + Constructor ctor() + { + return (Constructor)memberObject; + } + + boolean isMethod() + { + return memberObject instanceof Method; + } + + boolean isCtor() + { + return memberObject instanceof Constructor; + } + + boolean isStatic() + { + return Modifier.isStatic(memberObject.getModifiers()); + } + + String getName() + { + return memberObject.getName(); + } + + Class getDeclaringClass() + { + return memberObject.getDeclaringClass(); + } + + String toJavaDeclaration() + { + StringBuffer sb = new StringBuffer(); + if (isMethod()) { + Method method = method(); + sb.append(method.getReturnType()); + sb.append(' '); + sb.append(method.getName()); + } else { + Constructor ctor = ctor(); + String name = ctor.getDeclaringClass().getName(); + int lastDot = name.lastIndexOf('.'); + if (lastDot >= 0) { + name = name.substring(lastDot + 1); + } + sb.append(name); + } + sb.append(JavaMembers.liveConnectSignature(argTypes)); + return sb.toString(); + } + + public String toString() + { + return memberObject.toString(); + } + + Object invoke(Object target, Object[] args) + throws IllegalAccessException, InvocationTargetException + { + 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; + } + } + return method.invoke(target, args); + } + } + + Object newInstance(Object[] args) + throws InvocationTargetException, IllegalAccessException, + InstantiationException + { + Constructor ctor = ctor(); + try { + return ctor.newInstance(args); + } catch (IllegalAccessException ex) { + if (!tryToMakeAccessible(ctor)) { + throw ex; + } + return ctor.newInstance(args); + } + } + + private static Method searchAccessibleMethod(Method method, Class[] params) + { + int modifiers = method.getModifiers(); + if (Modifier.isPublic(modifiers) && !Modifier.isStatic(modifiers)) { + Class c = method.getDeclaringClass(); + if (!Modifier.isPublic(c.getModifiers())) { + String name = method.getName(); + Class[] intfs = c.getInterfaces(); + for (int i = 0, N = intfs.length; i != N; ++i) { + Class intf = intfs[i]; + if (Modifier.isPublic(intf.getModifiers())) { + try { + return intf.getMethod(name, params); + } catch (NoSuchMethodException ex) { + } catch (SecurityException ex) { } + } + } + for (;;) { + c = c.getSuperclass(); + if (c == null) { break; } + if (Modifier.isPublic(c.getModifiers())) { + try { + Method m = c.getMethod(name, params); + int mModifiers = m.getModifiers(); + if (Modifier.isPublic(mModifiers) + && !Modifier.isStatic(mModifiers)) + { + return m; + } + } catch (NoSuchMethodException ex) { + } catch (SecurityException ex) { } + } + } + } + } + return null; + } + + private static boolean tryToMakeAccessible(Member member) + { + /** + * Due to a bug in Sun's VM, public methods in private + * classes are not accessible by default (Sun Bug #4071593). + * We have to explicitly set the method accessible + * via method.setAccessible(true) but we have to use + * reflection because the setAccessible() in Method is + * not available under jdk 1.1. + */ + if (method_setAccessible != null) { + try { + Object[] args_wrapper = { Boolean.TRUE }; + method_setAccessible.invoke(member, args_wrapper); + return true; + } catch (Exception ex) { } + } + return false; + } + + private void readObject(ObjectInputStream in) + throws IOException, ClassNotFoundException + { + in.defaultReadObject(); + Member member = FunctionObject.readMember(in); + if (member instanceof Method) { + init((Method)member); + } else { + init((Constructor)member); + } + } + + private void writeObject(ObjectOutputStream out) + throws IOException + { + FunctionObject.writeMember(out, memberObject); + } + + private transient Member memberObject; + transient Class[] argTypes; + + private static Method method_setAccessible; + + static { + try { + Class MethodClass = Class.forName("java.lang.reflect.Method"); + method_setAccessible = MethodClass.getMethod( + "setAccessible", new Class[] { Boolean.TYPE }); + } catch (Exception ex) { + // Assume any exceptions means the method does not exist. + } + } +} + diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/NativeJavaClass.java b/mozilla/js/rhino/src/org/mozilla/javascript/NativeJavaClass.java index 54a90ac3642..7960a7e0acb 100644 --- a/mozilla/js/rhino/src/org/mozilla/javascript/NativeJavaClass.java +++ b/mozilla/js/rhino/src/org/mozilla/javascript/NativeJavaClass.java @@ -172,9 +172,8 @@ public class NativeJavaClass extends NativeJavaObject implements Function { if (! (Modifier.isInterface(modifiers) || Modifier.isAbstract(modifiers))) { - Constructor[] ctors = members.ctors; - Class[][] ctorTypes = members.ctorTypes; - int index = NativeJavaMethod.findFunction(ctors, ctorTypes, args); + MemberBox[] ctors = members.ctors; + int index = NativeJavaMethod.findFunction(ctors, args); if (index < 0) { String sig = NativeJavaMethod.scriptSignature(args); throw Context.reportRuntimeError2( @@ -182,8 +181,7 @@ public class NativeJavaClass extends NativeJavaObject implements Function { } // Found the constructor, so try invoking it. - return constructSpecific(cx, scope, this, args, - ctors[index], ctorTypes[index]); + return constructSpecific(cx, scope, this, args, ctors[index]); } else { Scriptable topLevel = ScriptableObject.getTopLevelScope(this); String msg = ""; @@ -209,19 +207,25 @@ public class NativeJavaClass extends NativeJavaObject implements Function { } } - public static Scriptable constructSpecific(Context cx, - Scriptable scope, - Scriptable thisObj, - Object[] args, - Constructor ctor, - Class[] paramTypes) + static Scriptable constructSpecific(Context cx, Scriptable scope, + Scriptable thisObj, Object[] args, + MemberBox ctor) throws JavaScriptException { Scriptable topLevel = ScriptableObject.getTopLevelScope(thisObj); Class classObject = ctor.getDeclaringClass(); + Class[] argTypes = ctor.argTypes; + Object[] origArgs = args; for (int i = 0; i < args.length; i++) { - args[i] = NativeJavaObject.coerceType(paramTypes[i], args[i], true); + Object arg = args[i]; + Object x = NativeJavaObject.coerceType(argTypes[i], arg, true); + if (x != arg) { + if (args == origArgs) { + args = (Object[])origArgs.clone(); + } + args[i] = x; + } } Object instance; try { @@ -232,7 +236,7 @@ public class NativeJavaClass extends NativeJavaObject implements Function { instEx.getMessage(), classObject.getName()); } catch (IllegalArgumentException argEx) { String signature = NativeJavaMethod.scriptSignature(args); - String ctorString = ctor.toString(); + String ctorString = ctor.ctor().toString(); throw Context.reportRuntimeError3( "msg.bad.ctor.sig", argEx.getMessage(), ctorString, signature); } catch (IllegalAccessException accessEx) { diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/NativeJavaConstructor.java b/mozilla/js/rhino/src/org/mozilla/javascript/NativeJavaConstructor.java index 41845c28d27..55c94a2c8df 100644 --- a/mozilla/js/rhino/src/org/mozilla/javascript/NativeJavaConstructor.java +++ b/mozilla/js/rhino/src/org/mozilla/javascript/NativeJavaConstructor.java @@ -56,11 +56,10 @@ import java.io.*; public class NativeJavaConstructor extends BaseFunction { - public NativeJavaConstructor(Constructor ctor) + public NativeJavaConstructor(MemberBox ctor) { - this.constructor = ctor; - this.constructorType = ctor.getParameterTypes(); - String sig = NativeJavaMethod.memberSignature(ctor, constructorType); + this.ctor = ctor; + String sig = JavaMembers.liveConnectSignature(ctor.argTypes); this.functionName = "".concat(sig); } @@ -68,37 +67,14 @@ public class NativeJavaConstructor extends BaseFunction Object[] args) throws JavaScriptException { - // Find a method that matches the types given. - if (constructor == null) { - throw new RuntimeException("No constructor defined for call"); - } - - return NativeJavaClass.constructSpecific(cx, scope, this, args, - constructor, constructorType); + return NativeJavaClass.constructSpecific(cx, scope, this, args, ctor); } public String toString() { - return "[JavaConstructor " + constructor.getName() + "]"; + return "[JavaConstructor " + ctor.getName() + "]"; } - private void readObject(ObjectInputStream in) - throws IOException, ClassNotFoundException - { - in.defaultReadObject(); - constructor = (Constructor)FunctionObject.readMember(in); - constructorType = constructor.getParameterTypes(); - } - - private void writeObject(ObjectOutputStream out) - throws IOException - { - out.defaultWriteObject(); - FunctionObject.writeMember(out, constructor); - } - - transient Constructor constructor; - private transient Class[] constructorType; - + MemberBox ctor; } diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/NativeJavaMethod.java b/mozilla/js/rhino/src/org/mozilla/javascript/NativeJavaMethod.java index 28fa6e9f88e..764ae84dea3 100644 --- a/mozilla/js/rhino/src/org/mozilla/javascript/NativeJavaMethod.java +++ b/mozilla/js/rhino/src/org/mozilla/javascript/NativeJavaMethod.java @@ -56,28 +56,16 @@ import java.io.*; public class NativeJavaMethod extends BaseFunction { - public NativeJavaMethod(Method[] methods) + public NativeJavaMethod(MemberBox[] methods) { this.functionName = methods[0].getName(); - init(methods); + this.methods = methods; } - public NativeJavaMethod(Method method, String name) + public NativeJavaMethod(MemberBox method, String 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(); - } + this.methods = new MemberBox[] { method }; } private static String scriptSignature(Object value) @@ -102,7 +90,7 @@ public class NativeJavaMethod extends BaseFunction return "object"; } } else { - return javaSignature(value.getClass()); + return JavaMembers.javaSignature(value.getClass()); } } @@ -117,57 +105,6 @@ public class NativeJavaMethod extends BaseFunction return sig.toString(); } - static String javaSignature(Class type) - { - if (type == null) { - return "null"; - } else if (!type.isArray()) { - return type.getName(); - } else { - int arrayDimension = 0; - do { - ++arrayDimension; - type = type.getComponentType(); - } while (type.isArray()); - String name = type.getName(); - String suffix = "[]"; - if (arrayDimension == 1) { - return name.concat(suffix); - } else { - int length = name.length() + arrayDimension * suffix.length(); - StringBuffer sb = new StringBuffer(length); - sb.append(name); - while (arrayDimension != 0) { - --arrayDimension; - sb.append(suffix); - } - return sb.toString(); - } - } - } - - static String memberSignature(Member member, Class[] paramTypes) - { - String name; - if (member instanceof Method) { - Method method = (Method)member; - name = method.getName(); - } else { - name = ""; - } - StringBuffer sb = new StringBuffer(); - sb.append(name); - sb.append('('); - for (int i = 0, N = paramTypes.length; i != N; ++i) { - if (i != 0) { - sb.append(','); - } - sb.append(javaSignature(paramTypes[i])); - } - sb.append(')'); - return sb.toString(); - } - public String decompile(Context cx, int indent, boolean justbody) { StringBuffer sb = new StringBuffer(); @@ -192,10 +129,11 @@ public class NativeJavaMethod extends BaseFunction private void toString(StringBuffer sb) { for (int i = 0, N = methods.length; i != N; ++i) { - Method method = methods[i]; - sb.append(javaSignature(method.getReturnType())); + Method method = methods[i].method(); + sb.append(JavaMembers.javaSignature(method.getReturnType())); sb.append(' '); - sb.append(memberSignature(method, methodTypes[i])); + sb.append(method.getName()); + sb.append(JavaMembers.liveConnectSignature(methods[i].argTypes)); sb.append('\n'); } } @@ -208,22 +146,23 @@ public class NativeJavaMethod extends BaseFunction if (methods.length == 0) { throw new RuntimeException("No methods defined for call"); } - int index = findFunction(methods, methodTypes, args); + + int index = findFunction(methods, args); if (index < 0) { - Class c = methods[0].getDeclaringClass(); + Class c = methods[0].method().getDeclaringClass(); String sig = c.getName() + '.' + functionName + '(' + scriptSignature(args) + ')'; throw Context.reportRuntimeError1("msg.java.no_such_method", sig); } - Method meth = methods[index]; - Class paramTypes[] = methodTypes[index]; + MemberBox meth = methods[index]; + Class[] argTypes = meth.argTypes; // First, we marshall the args. Object[] origArgs = args; for (int i = 0; i < args.length; i++) { Object arg = args[i]; - Object coerced = NativeJavaObject.coerceType(paramTypes[i], arg, + Object coerced = NativeJavaObject.coerceType(argTypes[i], arg, true); if (coerced != arg) { if (origArgs == args) { @@ -233,7 +172,7 @@ public class NativeJavaMethod extends BaseFunction } } Object javaObject; - if (Modifier.isStatic(meth.getModifiers())) { + if (meth.isStatic()) { javaObject = null; // don't need an object } else { Scriptable o = thisObj; @@ -247,16 +186,12 @@ public class NativeJavaMethod extends BaseFunction javaObject = ((Wrapper) o).unwrap(); } if (debug) { - printDebug("Calling ", meth, paramTypes, args); + printDebug("Calling ", meth, args); } Object retval; try { - try { - retval = meth.invoke(javaObject, args); - } catch (IllegalAccessException e) { - retval = retryIllegalAccessInvoke(meth, javaObject, args, e); - } + retval = meth.invoke(javaObject, args); } catch (IllegalAccessException accessEx) { throw Context.reportRuntimeError( "While attempting to call \"" + meth.getName() + @@ -265,7 +200,7 @@ public class NativeJavaMethod extends BaseFunction } catch (Exception ex) { throw ScriptRuntime.throwAsUncheckedException(ex); } - Class staticType = meth.getReturnType(); + Class staticType = meth.method().getReturnType(); if (debug) { Class actualType = (retval == null) ? null @@ -291,81 +226,33 @@ public class NativeJavaMethod extends BaseFunction return wrapped; } - static Object retryIllegalAccessInvoke(Method method, Object obj, - Object[] args, - IllegalAccessException illegalAccess) - throws IllegalAccessException, InvocationTargetException - { - if (Modifier.isPublic(method.getModifiers())) { - String name = method.getName(); - Class[] parms = method.getParameterTypes(); - Class c = method.getDeclaringClass(); - Class[] intfs = c.getInterfaces(); - for (int i=0; i < intfs.length; i++) { - c = intfs[i]; - try { - Method m = c.getMethod(name, parms); - return m.invoke(obj, args); - } catch (NoSuchMethodException ex) { - continue; - } catch (IllegalAccessException ex) { - continue; - } - } - } - /** - * Due to a bug in Sun's VM, public methods in private - * classes are not accessible by default (Sun Bug #4071593). - * We have to explicitly set the method accessible - * via method.setAccessible(true) but we have to use - * reflection because the setAccessible() in Method is - * not available under jdk 1.1. We wait until a failure - * to retry to avoid the overhead of this call on cases - * that don't require it. - */ - if (method_setAccessible != null) { - Object[] args_wrapper = { Boolean.TRUE }; - try { - method_setAccessible.invoke(method, args_wrapper); - } - catch (IllegalAccessException ex) { } - catch (IllegalArgumentException ex) { } - catch (InvocationTargetException ex) { } - return method.invoke(obj, args); - } - throw illegalAccess; - } - /** * Find the index of the correct function to call given the set of methods * or constructors and the arguments. * If no function can be found to call, return -1. */ - static int findFunction(Member[] methodsOrCtors, Class[][] memberTypes, - Object[] args) + static int findFunction(MemberBox[] methodsOrCtors, Object[] args) { if (methodsOrCtors.length == 0) { return -1; } else if (methodsOrCtors.length == 1) { - Member member = methodsOrCtors[0]; - Class paramTypes[] = memberTypes[0]; - int plength = paramTypes.length; - if (plength != args.length) { + MemberBox member = methodsOrCtors[0]; + Class[] argTypes = member.argTypes; + int alength = argTypes.length; + if (alength != args.length) { return -1; } - for (int j = 0; j != plength; ++j) { - if (!NativeJavaObject.canConvert(args[j], paramTypes[j])) { + for (int j = 0; j != alength; ++j) { + if (!NativeJavaObject.canConvert(args[j], argTypes[j])) { if (debug) printDebug("Rejecting (args can't convert) ", - member, paramTypes, args); + member, args); return -1; } } - if (debug) printDebug("Found ", member, paramTypes, args); + if (debug) printDebug("Found ", member, args); return 0; } - boolean hasMethods = methodsOrCtors[0] instanceof Method; - int bestFit = -1; Class[] bestFitTypes = null; @@ -373,48 +260,45 @@ public class NativeJavaMethod extends BaseFunction int ambiguousMethodCount = 0; for (int i = 0; i < methodsOrCtors.length; i++) { - Member member = methodsOrCtors[i]; - Class paramTypes[] = memberTypes[i]; - if (paramTypes.length != args.length) { + MemberBox member = methodsOrCtors[i]; + Class[] argTypes = member.argTypes; + if (argTypes.length != args.length) { continue; } if (bestFit < 0) { int j; - for (j = 0; j < paramTypes.length; j++) { - if (!NativeJavaObject.canConvert(args[j], paramTypes[j])) { + for (j = 0; j < argTypes.length; j++) { + if (!NativeJavaObject.canConvert(args[j], argTypes[j])) { if (debug) printDebug("Rejecting (args can't convert) ", - member, paramTypes, args); + member, args); break; } } - if (j == paramTypes.length) { - if (debug) printDebug("Found ", member, paramTypes, args); + if (j == argTypes.length) { + if (debug) printDebug("Found ", member, args); bestFit = i; - bestFitTypes = paramTypes; + bestFitTypes = argTypes; } } else { - int preference = preferSignature(args, paramTypes, + int preference = preferSignature(args, argTypes, bestFitTypes); if (preference == PREFERENCE_AMBIGUOUS) { - if (debug) printDebug("Deferring ", - member, paramTypes, args); + if (debug) printDebug("Deferring ", member, 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, paramTypes, args); + if (debug) printDebug("Substituting ", member, args); bestFit = i; - bestFitTypes = paramTypes; + bestFitTypes = argTypes; } else if (preference == PREFERENCE_SECOND_ARG) { - if (debug) printDebug("Rejecting ", - member, paramTypes, args); + if (debug) printDebug("Rejecting ", member, args); } else { if (preference != PREFERENCE_EQUAL) Context.codeBug(); - Member best = methodsOrCtors[bestFit]; - if (Modifier.isStatic(best.getModifiers()) + MemberBox best = methodsOrCtors[bestFit]; + if (best.isStatic() && best.getDeclaringClass().isAssignableFrom( member.getDeclaringClass())) { @@ -423,14 +307,12 @@ 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, paramTypes, args); + "Substituting (overridden static)", member, args); bestFit = i; - bestFitTypes = paramTypes; + bestFitTypes = argTypes; } else { if (debug) printDebug( - "Ignoring same signature member ", - member, paramTypes, args); + "Ignoring same signature member ", member, args); } } } @@ -444,28 +326,25 @@ public class NativeJavaMethod extends BaseFunction int removedCount = 0; for (int k = 0; k != ambiguousMethodCount; ++k) { int i = ambiguousMethods[k]; - Member member = methodsOrCtors[i]; - Class paramTypes[] = memberTypes[i]; - int preference = preferSignature(args, paramTypes, + MemberBox member = methodsOrCtors[i]; + Class[] argTypes = member.argTypes; + int preference = preferSignature(args, argTypes, bestFitTypes); if (preference == PREFERENCE_FIRST_ARG) { - if (debug) printDebug("Substituting ", - member, paramTypes, args); + if (debug) printDebug("Substituting ", member, args); bestFit = i; - bestFitTypes = paramTypes; + bestFitTypes = argTypes; ambiguousMethods[k] = -1; ++removedCount; } else if (preference == PREFERENCE_SECOND_ARG) { - if (debug) printDebug("Rejecting ", - member, paramTypes, args); + if (debug) printDebug("Rejecting ", member, args); ambiguousMethods[k] = -1; ++removedCount; } else { - if (debug) printDebug("UNRESOLVED: ", - member, paramTypes, args); + if (debug) printDebug("UNRESOLVED: ", member, args); } } @@ -484,20 +363,13 @@ public class NativeJavaMethod extends BaseFunction if (!first) { buf.append(", "); } - Member member = methodsOrCtors[i]; - if (hasMethods) { - Method method = (Method)member; - Class rtnType = method.getReturnType(); - buf.append(rtnType); - buf.append(' '); - } - buf.append(memberSignature(member, memberTypes[i])); + buf.append(methodsOrCtors[i].toJavaDeclaration()); first = false; } - Member best = methodsOrCtors[bestFit]; + MemberBox best = methodsOrCtors[bestFit]; - if (!hasMethods) { + if (methodsOrCtors[0].isMethod()) { throw Context.reportRuntimeError3( "msg.constructor.ambiguous", best.getName(), scriptSignature(args), buf.toString()); @@ -579,8 +451,8 @@ public class NativeJavaMethod extends BaseFunction private static final boolean debug = false; - private static void printDebug(String msg, Member member, - Class[] paramTypes, Object[] args) + private static void printDebug(String msg, MemberBox member, + Object[] args) { if (debug) { StringBuffer sb = new StringBuffer(); @@ -588,50 +460,16 @@ public class NativeJavaMethod extends BaseFunction sb.append(msg); sb.append(member.getDeclaringClass().getName()); sb.append('.'); - sb.append(memberSignature(member, paramTypes)); + if (member.isMethod()) { + sb.append(member.getName()); + } + sb.append(JavaMembers.liveConnectSignature(member.argTypes)); sb.append(" for arguments ("); sb.append(scriptSignature(args)); sb.append(')'); } } - 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; - - static { - try { - Class MethodClass = Class.forName("java.lang.reflect.Method"); - method_setAccessible = MethodClass.getMethod( - "setAccessible", new Class[] { Boolean.TYPE }); - } catch (Exception ex) { - // Assume any exceptions means the method does not exist. - } - } - + MemberBox[] methods; } diff --git a/mozilla/js/rhino/src/org/mozilla/javascript/NativeJavaObject.java b/mozilla/js/rhino/src/org/mozilla/javascript/NativeJavaObject.java index 12a51ecbfc5..5c28676560c 100644 --- a/mozilla/js/rhino/src/org/mozilla/javascript/NativeJavaObject.java +++ b/mozilla/js/rhino/src/org/mozilla/javascript/NativeJavaObject.java @@ -865,7 +865,7 @@ WrapFactory#wrap(Context cx, Scriptable scope, Object obj, Class)} } throw Context.reportRuntimeError2 ("msg.conversion.not.allowed", - value.toString(), NativeJavaMethod.javaSignature(type)); + value.toString(), JavaMembers.javaSignature(type)); } public void writeExternal(ObjectOutput out)