Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 1 addition & 9 deletions rhino/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -93,22 +93,14 @@ decycle {
// LiveConnect classes in root package
// TODO: Move them to LiveConnect module
ignoring(
from: "org.mozilla.javascript.(Native*|JavaMembers|MemberBox|AccessorSlot\$MemberBoxSetter|FieldAndMethods|InterfaceAdapter|WrapFactory)",
from: "org.mozilla.javascript.(Native*|JavaMembers|FieldAndMethods|InterfaceAdapter|WrapFactory)",
to: "org.mozilla.javascript.lc.**"
)

// In theory, this is also LiveConnect classes in root package, but Rhino is using one of
// its methods to create instance from compiled script
ignoring from: "org.mozilla.javascript.JavaAdapter", to: "org.mozilla.javascript.lc.**"

// `ScriptableObject#defineProperty(...)` allows using methods to build getter/setter
// Given that its reflection usage is rather simple, we should be able to replace it with a small helper class
ignoring from: "org.mozilla.javascript.ScriptableObject", to: "org.mozilla.javascript.lc.type.TypeInfoFactory"

// `new FunctionObject(String, Member, Scriptable)` allows using method/constructor to build function
// similar to ScriptableObject, its reflection usage is rather basic
ignoring from: "org.mozilla.javascript.FunctionObject", to: "org.mozilla.javascript.lc.type.TypeInfo*"

// `Context#jsToJava(...)` used TypeInfo and TypeInfoFactory
// removing this is absolutely a breaking change, wait until 2.0.0
ignoring from: "org.mozilla.javascript.Context", to: "org.mozilla.javascript.lc.type.TypeInfo*"
Expand Down
6 changes: 3 additions & 3 deletions rhino/src/main/java/org/mozilla/javascript/AccessorSlot.java
Original file line number Diff line number Diff line change
Expand Up @@ -231,9 +231,9 @@ public boolean setValue(Object value, Scriptable owner, Scriptable start) {
var pTypes = member.getArgTypes();
// XXX: cache tag since it is already calculated in
// defineProperty ?
var valueType = pTypes.get(pTypes.size() - 1);
boolean isNullable = member.getArgNullability().isNullable(pTypes.size() - 1);
int tag = valueType.getTypeTag();
var valueType = pTypes[pTypes.length - 1];
boolean isNullable = member.getArgNullability().isNullable(pTypes.length - 1);
int tag = FunctionObject.getTypeTag(valueType);
Object actualArg = FunctionObject.convertArg(cx, start, value, tag, isNullable);

if (member.delegateTo == null) {
Expand Down
42 changes: 18 additions & 24 deletions rhino/src/main/java/org/mozilla/javascript/FunctionObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import org.mozilla.javascript.commonjs.module.ModuleScope;
import org.mozilla.javascript.lc.type.TypeInfo;
import org.mozilla.javascript.lc.type.TypeInfoFactory;

public class FunctionObject extends BaseFunction {
private static final long serialVersionUID = -5332312783643935019L;
Expand Down Expand Up @@ -80,38 +78,34 @@ public class FunctionObject extends BaseFunction {
* @see org.mozilla.javascript.Scriptable
*/
public FunctionObject(String name, Member methodOrConstructor, Scriptable scope) {
// fallback to global factory for compatibility with old behaviour, where the `scope` can be
// an object not yet initialized via `initStandardObject(...)`
var typeInfoFactory = TypeInfoFactory.getOrElse(scope, TypeInfoFactory.GLOBAL);

if (methodOrConstructor instanceof Constructor) {
member = new MemberBox((Constructor<?>) methodOrConstructor, typeInfoFactory);
member = new MemberBox((Constructor<?>) methodOrConstructor);
isStatic = true; // well, doesn't take a 'this'
} else {
member = new MemberBox((Method) methodOrConstructor, typeInfoFactory);
member = new MemberBox((Method) methodOrConstructor);
isStatic = member.isStatic();
}
String methodName = member.getName();
this.functionName = name;
var types = member.getArgTypes();
int arity = types.size();
if (arity == 4 && (types.get(1).isArray() || types.get(2).isArray())) {
int arity = types.length;
if (arity == 4 && (types[1].isArray() || types[2].isArray())) {
// Either variable args or an error.
if (types.get(1).isArray()) {
if (types[1].isArray()) {
if (!isStatic
|| types.get(0).isNot(Context.class)
|| types.get(1).isNot(Object[].class)
|| types.get(2).isNot(Function.class)
|| types.get(3).isNot(boolean.class)) {
|| types[0] != Context.class
|| types[1] != Object[].class
|| types[2] != Function.class
|| types[3] != boolean.class) {
throw Context.reportRuntimeErrorById("msg.varargs.ctor", methodName);
}
parmsLength = VARARGS_CTOR;
} else {
if (!isStatic
|| types.get(0).isNot(Context.class)
|| types.get(1).isNot(Scriptable.class)
|| types.get(2).isNot(Object[].class)
|| types.get(3).isNot(Function.class)) {
|| types[0] != Context.class
|| types[1] != Scriptable.class
|| types[2] != Object[].class
|| types[3] != Function.class) {
throw Context.reportRuntimeErrorById("msg.varargs.fun", methodName);
}
parmsLength = VARARGS_METHOD;
Expand All @@ -121,10 +115,10 @@ public FunctionObject(String name, Member methodOrConstructor, Scriptable scope)
if (arity > 0) {
typeTags = new byte[arity];
for (int i = 0; i != arity; ++i) {
int tag = types.get(i).getTypeTag();
int tag = getTypeTag(types[i]);
if (tag == JAVA_UNSUPPORTED_TYPE) {
throw Context.reportRuntimeErrorById(
"msg.bad.parms", types.get(i).asClass().getName(), methodName);
"msg.bad.parms", types[i].getName(), methodName);
}
typeTags[i] = (byte) tag;
}
Expand Down Expand Up @@ -152,7 +146,7 @@ public FunctionObject(String name, Member methodOrConstructor, Scriptable scope)
/**
* @return One of {@code JAVA_*_TYPE} constants to indicate desired type or {@link
* #JAVA_UNSUPPORTED_TYPE} if the conversion is not possible
* @see TypeInfo#getTypeTag()
* @see org.mozilla.javascript.lc.type.TypeInfo#getTypeTag()
*/
public static int getTypeTag(Class<?> type) {
if (type == ScriptRuntime.StringClass) return JAVA_STRING_TYPE;
Expand Down Expand Up @@ -461,7 +455,7 @@ public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] ar
if (hasVoidReturn) {
result = Undefined.instance;
} else if (returnTypeTag == JAVA_UNSUPPORTED_TYPE) {
result = cx.getWrapFactory().wrap(cx, scope, result, TypeInfo.NONE);
result = cx.getWrapFactory().wrap(cx, scope, result, (Class<?>) null);
}
// XXX: the code assumes that if returnTypeTag == JAVA_OBJECT_TYPE
// then the Java method did a proper job of converting the
Expand Down Expand Up @@ -508,7 +502,7 @@ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundE
var types = member.getArgTypes();
typeTags = new byte[parmsLength];
for (int i = 0; i != parmsLength; ++i) {
typeTags[i] = (byte) types.get(i).getTypeTag();
typeTags[i] = (byte) getTypeTag(types[i]);
}
}
if (member.isMethod()) {
Expand Down
62 changes: 32 additions & 30 deletions rhino/src/main/java/org/mozilla/javascript/JavaMembers.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.mozilla.javascript.lc.ReflectUtils;
import org.mozilla.javascript.lc.member.ExecutableBox;
import org.mozilla.javascript.lc.member.NativeJavaField;
import org.mozilla.javascript.lc.type.TypeInfo;
import org.mozilla.javascript.lc.type.TypeInfoFactory;
Expand Down Expand Up @@ -201,34 +203,34 @@ static String javaSignature(Class<?> type) {
return sb.toString();
}

static String liveConnectSignature(List<TypeInfo> argTypes) {
if (argTypes.isEmpty()) {
static String liveConnectSignature(Class<?>[] argTypes) {
if (argTypes.length == 0) {
return "()";
}

var builder = new StringBuilder();

builder.append('(');
var iter = argTypes.iterator();
var iter = Arrays.asList(argTypes).iterator();
if (iter.hasNext()) {
builder.append(javaSignature(iter.next().asClass()));
builder.append(javaSignature(iter.next()));
while (iter.hasNext()) {
builder.append(',').append(javaSignature(iter.next().asClass()));
builder.append(',').append(javaSignature(iter.next()));
}
}
builder.append(')');

return builder.toString();
}

private MemberBox findExplicitFunction(String name, boolean isStatic) {
private ExecutableBox findExplicitFunction(String name, boolean isStatic) {
int sigStart = name.indexOf('(');
if (sigStart < 0) {
return null;
}

Map<String, Object> ht = isStatic ? staticMembers : members;
MemberBox[] methodsOrCtors = null;
ExecutableBox[] methodsOrCtors = null;
boolean isCtor = (isStatic && sigStart == 0);

if (isCtor) {
Expand All @@ -249,8 +251,8 @@ private MemberBox findExplicitFunction(String name, boolean isStatic) {
}

if (methodsOrCtors != null) {
for (MemberBox methodsOrCtor : methodsOrCtors) {
String sig = liveConnectSignature(methodsOrCtor.getArgTypes());
for (var methodsOrCtor : methodsOrCtors) {
String sig = ReflectUtils.liveConnectSignature(methodsOrCtor.getArgTypes());
if (sigStart + sig.length() == name.length()
&& name.regionMatches(sigStart, sig, 0, sig.length())) {
return methodsOrCtor;
Expand All @@ -265,12 +267,12 @@ private Object getExplicitFunction(
Scriptable scope, String name, Object javaObject, boolean isStatic) {
Map<String, Object> ht = isStatic ? staticMembers : members;
Object member = null;
MemberBox methodOrCtor = findExplicitFunction(name, isStatic);
var methodOrCtor = findExplicitFunction(name, isStatic);

if (methodOrCtor != null) {
Scriptable prototype = ScriptableObject.getFunctionPrototype(scope);

if (methodOrCtor.isCtor()) {
if (methodOrCtor.isConstructor()) {
NativeJavaConstructor fun = new NativeJavaConstructor(methodOrCtor);
fun.setPrototype(prototype);
member = fun;
Expand Down Expand Up @@ -460,19 +462,19 @@ private void reflect(
boolean isStatic = (tableCursor == 0);
Map<String, Object> ht = isStatic ? staticMembers : members;
for (Map.Entry<String, Object> entry : ht.entrySet()) {
MemberBox[] methodBoxes;
ExecutableBox[] methodBoxes;
Object value = entry.getValue();
if (value instanceof Method) {
methodBoxes = new MemberBox[1];
methodBoxes[0] = new MemberBox((Method) value, typeFactory, this.cl);
methodBoxes = new ExecutableBox[1];
methodBoxes[0] = new ExecutableBox((Method) value, typeFactory, this.cl);
} else {
ArrayList<Object> overloadedMethods = (ArrayList<Object>) value;
int N = overloadedMethods.size();
if (N < 2) Kit.codeBug();
methodBoxes = new MemberBox[N];
methodBoxes = new ExecutableBox[N];
for (int i = 0; i != N; ++i) {
Method method = (Method) overloadedMethods.get(i);
methodBoxes[i] = new MemberBox(method, typeFactory, this.cl);
methodBoxes[i] = new ExecutableBox(method, typeFactory, this.cl);
}
}
NativeJavaMethod fun = new NativeJavaMethod(methodBoxes);
Expand Down Expand Up @@ -549,9 +551,9 @@ private void reflect(

// Reflect constructors
Constructor<?>[] constructors = getAccessibleConstructors(includePrivate);
MemberBox[] ctorMembers = new MemberBox[constructors.length];
ExecutableBox[] ctorMembers = new ExecutableBox[constructors.length];
for (int i = 0; i != constructors.length; ++i) {
ctorMembers[i] = new MemberBox(constructors[i], typeFactory);
ctorMembers[i] = new ExecutableBox(constructors[i], typeFactory);
}
ctors = new NativeJavaMethod(ctorMembers, cl.getSimpleName());
}
Expand Down Expand Up @@ -626,7 +628,7 @@ private static Map<String, BeanProperty> extractBeaning(
if (method.methods.length == 1) {
bean.getter = method;
} else {
bean.getter = new NativeJavaMethod(new MemberBox[] {candidate});
bean.getter = new NativeJavaMethod(new ExecutableBox[] {candidate});
}
}
}
Expand All @@ -644,7 +646,7 @@ private static Map<String, BeanProperty> extractBeaning(
continue;
}

MemberBox match;
ExecutableBox match;
var getter = bean.getter;
if (getter != null) {
var type = getter.methods[0].getReturnType();
Expand Down Expand Up @@ -719,10 +721,10 @@ private Field[] getAccessibleFields(boolean includeProtected, boolean includePri
return cl.getFields();
}

private static MemberBox extractGetMethod(MemberBox[] methods, boolean isStatic) {
// Inspect the list of all MemberBox for the only one having no
private static ExecutableBox extractGetMethod(ExecutableBox[] methods, boolean isStatic) {
// Inspect the list of all ExecutableBox for the only one having no
// parameters
for (MemberBox method : methods) {
for (var method : methods) {
// Does getter method have an empty parameter list with a return
// value (eg. a getSomething() or isSomething())?
if (method.getArgTypes().isEmpty() && (!isStatic || method.isStatic())) {
Expand All @@ -736,16 +738,16 @@ private static MemberBox extractGetMethod(MemberBox[] methods, boolean isStatic)
return null;
}

private static MemberBox extractSetMethod(
TypeInfo type, MemberBox[] methods, boolean isStatic) {
private static ExecutableBox extractSetMethod(
TypeInfo type, ExecutableBox[] methods, boolean isStatic) {
//
// Note: it may be preferable to allow NativeJavaMethod.findFunction()
// to find the appropriate setter; unfortunately, it requires an
// instance of the target arg to determine that.
//

MemberBox acceptableMatch = null;
for (MemberBox method : methods) {
ExecutableBox acceptableMatch = null;
for (var method : methods) {
if (!isStatic || method.isStatic()) {
var argTypes = method.getArgTypes();
if (argTypes.size() == 1) {
Expand All @@ -764,9 +766,9 @@ private static MemberBox extractSetMethod(
return acceptableMatch;
}

private static MemberBox extractSetMethod(MemberBox[] methods, boolean isStatic) {
private static ExecutableBox extractSetMethod(ExecutableBox[] methods, boolean isStatic) {

for (MemberBox method : methods) {
for (var method : methods) {
if (!isStatic || method.isStatic()) {
if (method.getReturnType().isVoid()) {
if (method.getArgTypes().size() == 1) {
Expand Down Expand Up @@ -900,7 +902,7 @@ final class BeanProperty {
class FieldAndMethods extends NativeJavaMethod {
private static final long serialVersionUID = -9222428244284796755L;

FieldAndMethods(Scriptable scope, MemberBox[] methods, NativeJavaField field) {
FieldAndMethods(Scriptable scope, ExecutableBox[] methods, NativeJavaField field) {
super(methods);
this.field = field;
setParentScope(scope);
Expand Down
Loading