Skip to content

Commit

Permalink
Added TypeInfo, replacing Class+Type pairs everywhere
Browse files Browse the repository at this point in the history
  • Loading branch information
LatvianModder committed May 22, 2024
1 parent 8c7aee1 commit c2dea59
Show file tree
Hide file tree
Showing 33 changed files with 773 additions and 560 deletions.
426 changes: 162 additions & 264 deletions src/main/java/dev/latvian/mods/rhino/Context.java

Large diffs are not rendered by default.

30 changes: 6 additions & 24 deletions src/main/java/dev/latvian/mods/rhino/CustomFunction.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,16 @@
package dev.latvian.mods.rhino;

import java.lang.reflect.Type;
import dev.latvian.mods.rhino.type.TypeInfo;

public class CustomFunction extends BaseFunction {
public static final Class<?>[] NO_ARGS = new Class<?>[0];
private final String functionName;
private final Func func;
private final Class<?>[] argTypes;
private final Type[] genericArgTypes;
private final TypeInfo[] argTypes;

public CustomFunction(String functionName, Func func, Class<?>[] argTypes, Type[] genericArgTypes) {
public CustomFunction(String functionName, Func func, TypeInfo[] argTypes) {
this.functionName = functionName;
this.func = func;
this.argTypes = argTypes;
this.genericArgTypes = genericArgTypes == null || genericArgTypes.length == 0 || genericArgTypes.length != argTypes.length ? null : genericArgTypes;
}

public CustomFunction(String functionName, Func func, Class<?>[] argTypes) {
this(functionName, func, argTypes, null);
this.argTypes = argTypes.length == 0 ? TypeInfo.EMPTY_ARRAY : argTypes;
}

@Override
Expand All @@ -31,7 +24,7 @@ public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] ar
Object[] origArgs = args;
for (int i = 0; i < args.length; i++) {
Object arg = args[i];
Object coerced = cx.jsToJava(arg, argTypes[i], genericArgTypes == null ? argTypes[i] : genericArgTypes[i]);
Object coerced = cx.jsToJava(arg, argTypes[i]);

if (coerced != arg) {
if (origArgs == args) {
Expand All @@ -41,18 +34,7 @@ public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] ar
}
}

Object retval = func.call(cx, args);

if (retval == null) {
return Undefined.INSTANCE;
}

Object wrapped = cx.wrap(scope, retval, retval.getClass());

if (wrapped == null) {
wrapped = Undefined.INSTANCE;
}
return wrapped;
return func.call(cx, args);
}

@FunctionalInterface
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/dev/latvian/mods/rhino/CustomMember.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package dev.latvian.mods.rhino;

import dev.latvian.mods.rhino.type.TypeInfo;

public record CustomMember(String name, TypeInfo type, Object value) {
}
14 changes: 8 additions & 6 deletions src/main/java/dev/latvian/mods/rhino/FieldAndMethods.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package dev.latvian.mods.rhino;

import dev.latvian.mods.rhino.type.TypeInfo;
import dev.latvian.mods.rhino.util.DefaultValueTypeHint;

import java.lang.reflect.Field;
import java.lang.reflect.Type;

public class FieldAndMethods extends NativeJavaMethod {
public transient Field field;
public transient TypeInfo fieldType;
public transient Object javaObject;

FieldAndMethods(Scriptable scope, MemberBox[] methods, Field field, Context cx) {
Expand All @@ -22,16 +23,17 @@ public Object getDefaultValue(Context cx, DefaultValueTypeHint hint) {
return this;
}
Object rval;
Class<?> type;
Type genericType;
try {
rval = field.get(javaObject);
type = field.getType();
genericType = field.getGenericType();
} catch (IllegalAccessException accEx) {
throw Context.reportRuntimeError1("msg.java.internal.private", field.getName(), cx);
}
rval = cx.wrap(this, rval, type, genericType);

if (fieldType == null) {
this.fieldType = TypeInfo.of(field.getGenericType());
}

rval = cx.wrap(this, rval, fieldType);
if (rval instanceof Scriptable) {
rval = ((Scriptable) rval).getDefaultValue(cx, hint);
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/dev/latvian/mods/rhino/FunctionObject.java
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,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.wrap(scope, result);
result = cx.wrap(scope, result, member.returnType);
}
// XXX: the code assumes that if returnTypeTag == JAVA_OBJECT_TYPE
// then the Java method did a proper job of converting the
Expand Down
12 changes: 7 additions & 5 deletions src/main/java/dev/latvian/mods/rhino/InterfaceAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

package dev.latvian.mods.rhino;

import dev.latvian.mods.rhino.type.TypeInfo;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

Expand Down Expand Up @@ -101,14 +103,14 @@ public Object invoke(Context cx, Object target, Scriptable topScope, Object this
if (resultType == Void.TYPE) {
return null;
}
return cx.jsToJava(null, resultType, method.getGenericReturnType());
return cx.jsToJava(null, TypeInfo.of(method.getGenericReturnType()));
}
if (!(value instanceof Callable)) {
throw Context.reportRuntimeError1("msg.not.function.interface", methodName, cx);
}
function = (Callable) value;
}
if (args == null) {
if (args == null || args.length == 0) {
args = ScriptRuntime.EMPTY_OBJECTS;
} else {
for (int i = 0, N = args.length; i != N; ++i) {
Expand All @@ -119,14 +121,14 @@ public Object invoke(Context cx, Object target, Scriptable topScope, Object this
}
}
}
Scriptable thisObj = cx.wrapAsJavaObject(topScope, thisObject, null, null);
Scriptable thisObj = cx.wrapAsJavaObject(topScope, thisObject, TypeInfo.NONE);

Object result = cx.callSync(function, topScope, thisObj, args);
Class<?> javaResultType = method.getReturnType();
var javaResultType = method.getGenericReturnType();
if (javaResultType == Void.TYPE) {
result = null;
} else {
result = cx.jsToJava(result, javaResultType, method.getGenericReturnType());
result = cx.jsToJava(result, TypeInfo.of(javaResultType));
}
return result;
}
Expand Down
11 changes: 4 additions & 7 deletions src/main/java/dev/latvian/mods/rhino/JavaAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import dev.latvian.mods.rhino.classfile.ByteCode;
import dev.latvian.mods.rhino.classfile.ClassFileWriter;
import dev.latvian.mods.rhino.type.TypeInfo;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
Expand Down Expand Up @@ -85,17 +86,13 @@ public static void init(Context cx, Scriptable scope, boolean sealed) {
ctor.exportAsScopeProperty(cx);
}

public static Object convertResult(Context cx, Object result, Class<?> c) {
if (result == Undefined.INSTANCE && (c != ScriptRuntime.ObjectClass && c != ScriptRuntime.StringClass)) {
public static Object convertResult(Context cx, Object result, TypeInfo c) {
if (result == Undefined.INSTANCE && (c != TypeInfo.OBJECT && c != TypeInfo.STRING)) {
// Avoid an error for an undefined value; return null instead.
return null;
}

if (c == null) {
return result;
}

return cx.jsToJava(result, c);
return c == null ? result : cx.jsToJava(result, c);
}

public static Scriptable createAdapterWrapper(Scriptable obj, Object adapter, Context cx) {
Expand Down
18 changes: 8 additions & 10 deletions src/main/java/dev/latvian/mods/rhino/JavaMembers.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

package dev.latvian.mods.rhino;

import dev.latvian.mods.rhino.type.TypeInfo;
import dev.latvian.mods.rhino.util.ClassVisibilityContext;
import dev.latvian.mods.rhino.util.HideFromJS;
import dev.latvian.mods.rhino.util.RemapForJS;
Expand All @@ -15,7 +16,6 @@
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
Expand Down Expand Up @@ -288,28 +288,25 @@ public Object get(Scriptable scope, String name, Object javaObject, boolean isSt
return member;
}
Object rval;
Class<?> type;
Type genericType;
TypeInfo type;
try {
if (member instanceof BeanProperty bp) {
if (bp.getter == null) {
return Scriptable.NOT_FOUND;
}
rval = bp.getter.invoke(javaObject, ScriptRuntime.EMPTY_OBJECTS, cx, scope);
type = bp.getter.getReturnType();
genericType = bp.getter.getGenericReturnType();
type = TypeInfo.of(bp.getter.getGenericReturnType());
} else {
Field field = (Field) member;
rval = field.get(isStatic ? null : javaObject);
type = field.getType();
genericType = field.getGenericType();
type = TypeInfo.of(field.getGenericType());
}
} catch (Exception ex) {
throw Context.throwAsScriptRuntimeEx(ex, cx);
}
// Need to wrap the object before we return it.
scope = ScriptableObject.getTopLevelScope(scope);
return cx.wrap(scope, rval, type, genericType);
return cx.wrap(scope, rval, type);
}

public void put(Scriptable scope, String name, Object javaObject, Object value, boolean isStatic, Context cx) {
Expand All @@ -336,7 +333,7 @@ public void put(Scriptable scope, String name, Object javaObject, Object value,
// main setter. Otherwise, let the NativeJavaMethod decide which
// setter to use:
if (bp.setters == null || value == null) {
Object[] args = {cx.jsToJava(value, bp.setter.argTypes[0], bp.setter.genericArgTypes[0])};
Object[] args = {cx.jsToJava(value, bp.setter.argTypeInfos[0])};
try {
bp.setter.invoke(javaObject, args, cx, scope);
} catch (Exception ex) {
Expand All @@ -358,7 +355,8 @@ public void put(Scriptable scope, String name, Object javaObject, Object value,
throw Context.throwAsScriptRuntimeEx(new IllegalAccessException("Can't modify final field " + field.getName()), cx);
}

Object javaValue = cx.jsToJava(value, field.getType(), field.getGenericType());
// This definitely could use some cache
Object javaValue = cx.jsToJava(value, TypeInfo.of(field.getGenericType()));
try {
field.set(javaObject, javaValue);
} catch (IllegalAccessException accessEx) {
Expand Down
13 changes: 9 additions & 4 deletions src/main/java/dev/latvian/mods/rhino/MemberBox.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

package dev.latvian.mods.rhino;

import dev.latvian.mods.rhino.type.TypeInfo;

import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.InvocationTargetException;
Expand Down Expand Up @@ -62,8 +64,9 @@ private static Method searchAccessibleMethod(Method method, Class<?>[] params) {
return null;
}

transient Class<?>[] argTypes;
transient Type[] genericArgTypes;
transient Class[] argTypes;
transient TypeInfo[] argTypeInfos;
transient TypeInfo returnType;
transient Object delegateTo;
transient boolean vararg;
public transient Executable executable;
Expand All @@ -72,7 +75,8 @@ private static Method searchAccessibleMethod(Method method, Class<?>[] params) {
MemberBox(Executable executable) {
this.executable = executable;
this.argTypes = executable.getParameterTypes();
this.genericArgTypes = executable.getGenericParameterTypes();
this.argTypeInfos = TypeInfo.ofArray(executable.getGenericParameterTypes());
this.returnType = executable instanceof Method m ? TypeInfo.of(m.getGenericReturnType()) : executable instanceof Constructor<?> c ? TypeInfo.of(c.getDeclaringClass()) : TypeInfo.NONE;
this.vararg = executable.isVarArgs();
}

Expand All @@ -82,7 +86,8 @@ private static Method searchAccessibleMethod(Method method, Class<?>[] params) {
if (executable != null) {
this.executable = executable;
this.argTypes = executable.getParameterTypes();
this.genericArgTypes = executable.getGenericParameterTypes();
this.argTypeInfos = TypeInfo.ofArray(executable.getGenericParameterTypes());
this.returnType = executable instanceof Method m ? TypeInfo.of(m.getGenericReturnType()) : executable instanceof Constructor<?> c ? TypeInfo.of(c.getDeclaringClass()) : TypeInfo.NONE;
this.vararg = executable.isVarArgs();
} else {
this.wrappedExecutable = wrappedExecutable;
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/dev/latvian/mods/rhino/NativeIterator.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

package dev.latvian.mods.rhino;

import dev.latvian.mods.rhino.type.TypeInfo;

import java.util.Iterator;

/**
Expand Down Expand Up @@ -130,7 +132,7 @@ private static Object jsConstructor(Context cx, Scriptable scope, Scriptable thi
Iterator<?> iterator = getJavaIterator(obj);
if (iterator != null) {
scope = getTopLevelScope(scope);
return cx.wrap(scope, new WrappedJavaIterator(cx, iterator, scope), WrappedJavaIterator.class);
return cx.wrap(scope, new WrappedJavaIterator(cx, iterator, scope), TypeInfo.of(WrappedJavaIterator.class));
}

// Otherwise, just call the runtime routine
Expand Down
18 changes: 8 additions & 10 deletions src/main/java/dev/latvian/mods/rhino/NativeJavaArray.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@

package dev.latvian.mods.rhino;

import dev.latvian.mods.rhino.type.TypeInfo;
import dev.latvian.mods.rhino.util.DefaultValueTypeHint;

import java.lang.reflect.Array;
import java.lang.reflect.Type;

/**
* This class reflects Java arrays into the JavaScript environment.
Expand All @@ -22,15 +22,13 @@
public class NativeJavaArray extends NativeJavaObject implements SymbolScriptable {
Object array;
int length;
Class<?> componentType;
Type genericComponentType;
TypeInfo componentType;

public NativeJavaArray(Scriptable scope, Object array, Class<?> componentType, Type genericComponentType, Context cx) {
super(scope, null, ScriptRuntime.ObjectClass, cx);
public NativeJavaArray(Scriptable scope, Object array, TypeInfo type, Context cx) {
super(scope, null, type, cx);
this.array = array;
this.length = Array.getLength(array);
this.componentType = componentType;
this.genericComponentType = genericComponentType;
this.componentType = type.componentType();
}

@Override
Expand Down Expand Up @@ -74,7 +72,7 @@ public Object get(Context cx, String id, Scriptable start) {
public Object get(Context cx, int index, Scriptable start) {
if (0 <= index && index < length) {
Object obj = Array.get(array, index);
return cx.wrap(this, obj, componentType, genericComponentType);
return cx.wrap(this, obj, componentType);
}
return Undefined.INSTANCE;
}
Expand All @@ -98,7 +96,7 @@ public void put(Context cx, String id, Scriptable start, Object value) {
@Override
public void put(Context cx, int index, Scriptable start, Object value) {
if (0 <= index && index < length) {
Array.set(array, index, cx.jsToJava(value, componentType, genericComponentType));
Array.set(array, index, cx.jsToJava(value, componentType));
} else {
throw Context.reportRuntimeError2("msg.java.array.index.out.of.bounds", String.valueOf(index), String.valueOf(length - 1), cx);
}
Expand Down Expand Up @@ -139,7 +137,7 @@ public boolean hasInstance(Context cx, Scriptable value) {
return false;
}
Object instance = ((Wrapper) value).unwrap();
return componentType.isInstance(instance);
return componentType.asClass().isInstance(instance);
}

@Override
Expand Down
Loading

0 comments on commit c2dea59

Please sign in to comment.