package pl.shockah.shocky.js; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.util.ArrayList; import jdk.nashorn.internal.lookup.Lookup; import jdk.nashorn.internal.objects.Global; import jdk.nashorn.internal.runtime.AccessorProperty; import jdk.nashorn.internal.runtime.Property; import jdk.nashorn.internal.runtime.PropertyMap; import jdk.nashorn.internal.runtime.ScriptFunction; import jdk.nashorn.internal.runtime.ScriptFunctionData; import jdk.nashorn.internal.runtime.ScriptObject; import jdk.nashorn.internal.runtime.ScriptRuntime; import jdk.nashorn.internal.runtime.Specialization; public class ShockyScriptFunction extends ScriptFunction { private Object prototype; private static final PropertyMap map; static { ArrayList<Property> properties = new ArrayList<Property>(3); properties.add(AccessorProperty.create("prototype", 6, G$PROTOTYPE, S$PROTOTYPE)); properties.add(AccessorProperty.create("length", 7, G$LENGTH, null)); properties.add(AccessorProperty.create("name", 7, G$NAME, null)); map = PropertyMap.newMap(properties); } public ShockyScriptFunction(String name, MethodHandle methodHandle, Global global, Specialization[] specs, int flags) { super(name, methodHandle, map, global, specs, flags); this.setProto(ScriptFunction.getPrototype((ScriptFunction)global.function)); this.setPrototype(ScriptRuntime.UNDEFINED); } @Override protected ScriptObject getObjectPrototype() { return Global.objectPrototype(); } @Override public Object getPrototype() { return this.prototype; } @Override protected ScriptFunction makeBoundFunction(ScriptFunctionData arg0) { return null; } @Override public ScriptFunction makeSynchronizedFunction(Object arg0) { return null; } @Override public void setPrototype(Object arg0) { this.prototype = arg0; } public static ShockyScriptFunction makeFunction(Global global, int flags, Class<?> c, String name, Class<?> r, Class<?>... a) { MethodHandle mh = Lookup.MH.findStatic(MethodHandles.lookup(), c, name, Lookup.MH.type(r, a)); return (mh == null) ? null : new ShockyScriptFunction(name, mh, global, null, flags); } public ShockyProperty makeProperty(int flags, boolean writable) { return new ShockyProperty(this.getName(), flags, writable, this); } public static class ShockyProperty { private static final MethodHandle GET = Lookup.MH.findVirtual(MethodHandles.lookup(), ShockyProperty.class, "get", Lookup.MH.type(Object.class, Object.class)); private static final MethodHandle SET = Lookup.MH.findVirtual(MethodHandles.lookup(), ShockyProperty.class, "set", Lookup.MH.type(Void.TYPE, Object.class, Object.class)); private final String name; private final int flags; private final boolean writable; private Object reference; public ShockyProperty(String name, int flags, boolean writable, Object reference) { this.name = name; this.flags = flags; this.writable = writable; this.reference = reference; } public Property getProperty() { return AccessorProperty.create(name, flags, GET.bindTo(this), this.writable ? SET.bindTo(this) : null); } public Object get(Object self) { return this.reference == null ? ScriptRuntime.UNDEFINED : this.reference; } public void set(Object self, Object reference) { this.reference = reference; } } }