Compare commits

...

2 Commits

Author SHA1 Message Date
b5b63c4342 fix: make global cache of native wrappers 2024-03-28 16:08:07 +02:00
18f70a0d58 fix: i hate wrappers 2024-03-28 15:10:21 +02:00
3 changed files with 64 additions and 28 deletions

View File

@@ -1,8 +1,13 @@
package me.topchetoeu.jscript.runtime.values;
import java.util.WeakHashMap;
import me.topchetoeu.jscript.runtime.Context;
import me.topchetoeu.jscript.runtime.Extensions;
import me.topchetoeu.jscript.runtime.Key;
public class NativeWrapper extends ObjectValue {
private static final Key<WeakHashMap<Object, NativeWrapper>> WRAPPERS = new Key<>();
private static final Object NATIVE_PROTO = new Object();
public final Object wrapped;
@@ -10,12 +15,8 @@ public class NativeWrapper extends ObjectValue {
public ObjectValue getPrototype(Context ctx) {
if (ctx.environment != null && prototype == NATIVE_PROTO) {
var clazz = wrapped.getClass();
while (true) {
var res = ctx.environment.wrappers.getProto(clazz);
if (res != null) return res;
clazz = clazz.getSuperclass();
}
var res = ctx.environment.wrappers.getProto(clazz);
if (res != null) return res;
}
return super.getPrototype(ctx);
}
@@ -33,8 +34,20 @@ public class NativeWrapper extends ObjectValue {
return wrapped.hashCode();
}
public NativeWrapper(Object wrapped) {
private NativeWrapper(Object wrapped) {
this.wrapped = wrapped;
prototype = NATIVE_PROTO;
}
public static NativeWrapper of(Extensions exts, Object wrapped) {
var wrappers = exts == null ? null : exts.get(WRAPPERS);
if (wrappers == null) return new NativeWrapper(wrapped);
if (wrappers.containsKey(wrapped)) return wrappers.get(wrapped);
var res = new NativeWrapper(wrapped);
wrappers.put(wrapped, res);
return res;
}
}

View File

@@ -58,9 +58,8 @@ public class Values {
@SuppressWarnings("unchecked")
public static <T> T wrapper(Object val, Class<T> clazz) {
if (!isWrapper(val)) val = new NativeWrapper(val);
var res = (NativeWrapper)val;
if (res != null && clazz.isInstance(res.wrapped)) return (T)res.wrapped;
if (isWrapper(val)) val = ((NativeWrapper)val).wrapped;
if (val != null && clazz.isInstance(val)) return (T)val;
else return null;
}
@@ -471,7 +470,7 @@ public class Values {
else return ctx.environment.wrappers.getConstr((Class<?>)val);
}
return new NativeWrapper(val);
return NativeWrapper.of(ctx, val);
}
@SuppressWarnings("unchecked")
@@ -536,7 +535,7 @@ public class Values {
if (obj == null) return null;
if (clazz.isInstance(obj)) return (T)obj;
if (clazz.isAssignableFrom(NativeWrapper.class)) {
return (T)new NativeWrapper(obj);
return (T)NativeWrapper.of(ctx, obj);
}
throw new ConvertException(type(obj), clazz.getSimpleName());

View File

@@ -288,6 +288,21 @@ public class NativeWrapperProvider implements WrapperProvider {
return res;
}
private void updateProtoChain(Class<?> clazz, ObjectValue proto, FunctionValue constr) {
var parent = clazz;
while (true) {
parent = parent.getSuperclass();
if (parent == null) return;
var parentProto = getProto(parent);
var parentConstr = getConstr(parent);
if (parentProto != null) Values.setPrototype(Context.NULL, proto, parentProto);
if (parentConstr != null) Values.setPrototype(Context.NULL, constr, parentConstr);
}
}
private void initType(Class<?> clazz, FunctionValue constr, ObjectValue proto) {
if (constr != null && proto != null || ignore.contains(clazz)) return;
// i vomit
@@ -316,32 +331,35 @@ public class NativeWrapperProvider implements WrapperProvider {
prototypes.put(clazz, proto);
constructors.put(clazz, constr);
var parent = clazz;
while (true) {
parent = parent.getSuperclass();
if (parent == null) return;
var parentProto = getProto(parent);
var parentConstr = getConstr(parent);
if (parentProto != null) Values.setPrototype(Context.NULL, proto, parentProto);
if (parentConstr != null) Values.setPrototype(Context.NULL, constr, parentConstr);
}
updateProtoChain(clazz, proto, constr);
}
public ObjectValue getProto(Class<?> clazz) {
initType(clazz, constructors.get(clazz), prototypes.get(clazz));
return prototypes.get(clazz);
while (clazz != null) {
var res = prototypes.get(clazz);
if (res != null) return res;
clazz = clazz.getSuperclass();
}
return null;
}
public ObjectValue getNamespace(Class<?> clazz) {
if (!namespaces.containsKey(clazz)) namespaces.put(clazz, makeNamespace(env, clazz));
return namespaces.get(clazz);
while (clazz != null) {
var res = namespaces.get(clazz);
if (res != null) return res;
clazz = clazz.getSuperclass();
}
return null;
}
public FunctionValue getConstr(Class<?> clazz) {
initType(clazz, constructors.get(clazz), prototypes.get(clazz));
return constructors.get(clazz);
while (clazz != null) {
var res = constructors.get(clazz);
if (res != null) return res;
clazz = clazz.getSuperclass();
}
return null;
}
@Override public WrapperProvider fork(Environment env) {
@@ -357,6 +375,12 @@ public class NativeWrapperProvider implements WrapperProvider {
prototypes.put(clazz, proto);
constructors.put(clazz, constructor);
ignore.remove(clazz);
for (var el : prototypes.keySet()) {
if (clazz.isAssignableFrom(el)) {
updateProtoChain(el, getProto(el), getConstr(el));
}
}
}
else {
prototypes.remove(clazz);