/** * Cast the incoming arguments to the types in the given signature. The * argument count must match, but the names in the target signature are * ignored. * * @param target the Signature to which arguments should be cast * @return a new SmartBinder with the cast applied */ public SmartBinder cast(Signature target) { return new SmartBinder(target, binder.cast(target.type())); }
public static CallSite fixnum(Lookup lookup, String name, MethodType type, long value) { MutableCallSite site = new MutableCallSite(type); MethodHandle handle = Binder .from(IRubyObject.class, ThreadContext.class) .insert(0, site, value) .cast(IRubyObject.class, MutableCallSite.class, long.class, ThreadContext.class) .invokeStaticQuiet(MethodHandles.lookup(), Bootstrap.class, "fixnum"); site.setTarget(handle); return site; }
public static CallSite flote(Lookup lookup, String name, MethodType type, double value) { MutableCallSite site = new MutableCallSite(type); MethodHandle handle = Binder .from(IRubyObject.class, ThreadContext.class) .insert(0, site, value) .cast(IRubyObject.class, MutableCallSite.class, double.class, ThreadContext.class) .invokeStaticQuiet(MethodHandles.lookup(), Bootstrap.class, "flote"); site.setTarget(handle); return site; }
public static CallSite fixnum(Lookup lookup, String name, MethodType type, long value) { MutableCallSite site = new MutableCallSite(type); MethodHandle handle = Binder .from(IRubyObject.class, ThreadContext.class) .insert(0, site, value) .cast(IRubyObject.class, MutableCallSite.class, long.class, ThreadContext.class) .invokeStaticQuiet(MethodHandles.lookup(), Bootstrap.class, "fixnum"); site.setTarget(handle); return site; }
public static CallSite flote(Lookup lookup, String name, MethodType type, double value) { MutableCallSite site = new MutableCallSite(type); MethodHandle handle = Binder .from(IRubyObject.class, ThreadContext.class) .insert(0, site, value) .cast(IRubyObject.class, MutableCallSite.class, double.class, ThreadContext.class) .invokeStaticQuiet(MethodHandles.lookup(), Bootstrap.class, "flote"); site.setTarget(handle); return site; }
/** * Cast the named argument to the given type. * * @param name the name of the argument to cast * @param type the type to which that argument will be cast * @return a new SmartBinder with the cast applied */ public SmartBinder castArg(String name, Class<?> type) { Signature newSig = signature().replaceArg(name, name, type); return new SmartBinder(this, newSig, binder.cast(newSig.type())); }
/** * Cast the incoming arguments to the return and argument types given. The * argument count must match. * * @param returnType the return type for the casted signature * @param argTypes the types of the arguments for the casted signature * @return a new SmartBinder with the cast applied */ public SmartBinder cast(Class<?> returnType, Class<?>... argTypes) { return new SmartBinder(this, new Signature(returnType, argTypes, signature().argNames()), binder.cast(returnType, argTypes)); }
private static MethodHandle createAttrReaderHandle(InvokeSite site, IRubyObject self, RubyClass cls, VariableAccessor accessor) { MethodHandle nativeTarget; MethodHandle filter = cls.getClassRuntime().getNullToNilHandle(); MethodHandle getValue; if (accessor instanceof FieldVariableAccessor) { MethodHandle getter = ((FieldVariableAccessor)accessor).getGetter(); getValue = Binder.from(site.type()) .drop(0, 2) .filterReturn(filter) .cast(methodType(Object.class, self.getClass())) .invoke(getter); } else { getValue = Binder.from(site.type()) .drop(0, 2) .filterReturn(filter) .cast(methodType(Object.class, Object.class)) .prepend(accessor) .invokeVirtualQuiet(LOOKUP, "get"); } // NOTE: Must not cache the fully-bound handle in the method, since it's specific to this class return getValue; }
/** * Cast the return value to the given type. * * Example: Our current signature is (String)String but the method this * handle will eventually call returns CharSequence. * * <code>binder = binder.castReturn(CharSequence.class);</code> * * Our handle will now successfully find and call the target method and * propagate the returned CharSequence as a String. * * @param type the new type for the return value * @return a new SmartBinder */ public SmartBinder castReturn(Class<?> type) { return new SmartBinder(this, signature().changeReturn(type), binder.cast(type, binder.type().parameterArray())); }
private static MethodHandle createAttrReaderHandle(InvokeSite site, IRubyObject self, RubyClass cls, VariableAccessor accessor) { MethodHandle nativeTarget; MethodHandle filter = cls.getClassRuntime().getNullToNilHandle(); MethodHandle getValue; if (accessor instanceof FieldVariableAccessor) { MethodHandle getter = ((FieldVariableAccessor)accessor).getGetter(); getValue = Binder.from(site.type()) .drop(0, 2) .filterReturn(filter) .cast(methodType(Object.class, self.getClass())) .invoke(getter); } else { getValue = Binder.from(site.type()) .drop(0, 2) .filterReturn(filter) .cast(methodType(Object.class, Object.class)) .prepend(accessor) .invokeVirtualQuiet(LOOKUP, "get"); } // NOTE: Must not cache the fully-bound handle in the method, since it's specific to this class return getValue; }
.from(IRubyObject.class, IRubyObject.class) .insert(1, cls.getRuntime().getNil()) .cast(IRubyObject.class, IRubyObject.class, IRubyObject.class) .invokeStaticQuiet(lookup(), InvocationLinker.class, "valueOrNil"); Class objCls = InvokeDynamicSupport.REIFIED_OBJECT_CLASSES[offset]; nativeTarget = b .cast(Object.class, objCls) .getFieldQuiet(lookup(), "var" + offset); } else { .filterReturn(filter) .insert(1, accessor.getIndex()) .cast(Object.class, RubyBasicObject.class, int.class) .invokeStaticQuiet(lookup(), VariableAccessor.class, "getVariable");
.from(IRubyObject.class, IRubyObject.class) .insert(1, cls.getRuntime().getNil()) .cast(IRubyObject.class, IRubyObject.class, IRubyObject.class) .invokeStaticQuiet(lookup(), InvocationLinker.class, "valueOrNil"); Class objCls = InvokeDynamicSupport.REIFIED_OBJECT_CLASSES[offset]; nativeTarget = b .cast(Object.class, objCls) .getFieldQuiet(lookup(), "var" + offset); } else { .filterReturn(filter) .insert(1, accessor.getIndex()) .cast(Object.class, RubyBasicObject.class, int.class) .invokeStaticQuiet(lookup(), VariableAccessor.class, "getVariable");
private static MethodHandle createAttrWriterHandle(InvokeSite site, IRubyObject self, RubyClass cls, VariableAccessor accessor) { MethodHandle nativeTarget; MethodHandle filter = Binder .from(IRubyObject.class, Object.class) .drop(0) .constant(cls.getRuntime().getNil()); MethodHandle setValue; if (accessor instanceof FieldVariableAccessor) { MethodHandle setter = ((FieldVariableAccessor)accessor).getSetter(); setValue = Binder.from(site.type()) .drop(0, 2) .filterReturn(filter) .cast(methodType(void.class, self.getClass(), Object.class)) .invoke(setter); } else { setValue = Binder.from(site.type()) .drop(0, 2) .filterReturn(filter) .cast(methodType(void.class, Object.class, Object.class)) .prepend(accessor) .invokeVirtualQuiet(LOOKUP, "set"); } return setValue; }
private static MethodHandle createAttrWriterHandle(InvokeSite site, IRubyObject self, RubyClass cls, VariableAccessor accessor) { MethodHandle nativeTarget; MethodHandle filter = Binder .from(IRubyObject.class, Object.class) .drop(0) .constant(cls.getRuntime().getNil()); MethodHandle setValue; if (accessor instanceof FieldVariableAccessor) { MethodHandle setter = ((FieldVariableAccessor)accessor).getSetter(); setValue = Binder.from(site.type()) .drop(0, 2) .filterReturn(filter) .cast(methodType(void.class, self.getClass(), Object.class)) .invoke(setter); } else { setValue = Binder.from(site.type()) .drop(0, 2) .filterReturn(filter) .cast(methodType(void.class, Object.class, Object.class)) .prepend(accessor) .invokeVirtualQuiet(LOOKUP, "set"); } return setValue; }
.cast(Object.class, IRubyObject.class) .invokeStaticQuiet(lookup(), JavaUtil.class, "objectFromJavaProxy"); .filter(0, receiverConverter) .filterReturn(filter) .cast(fieldHandle.type()) .invoke(fieldHandle); .cast(Object.class, IRubyObject.class) .invokeStaticQuiet(lookup(), JavaUtil.class, "objectFromJavaProxy"); .filter(0, receiverConverter) .filterReturn(constant(IRubyObject.class, self.getRuntime().getNil())) .cast(fieldHandle.type()) .invoke(fieldHandle);
Class objCls = InvokeDynamicSupport.REIFIED_OBJECT_CLASSES[offset]; nativeTarget = b .cast(void.class, objCls, Object.class) .invokeStaticQuiet(lookup(), objCls, "setVariableChecked"); } else { .filterReturn(filter) .insert(1, cls.getRealClass(), accessor.getIndex()) .cast(void.class, RubyBasicObject.class, RubyClass.class, int.class, Object.class) .invokeStaticQuiet(lookup(), accessor.getClass(), "setVariableChecked");
Class objCls = InvokeDynamicSupport.REIFIED_OBJECT_CLASSES[offset]; nativeTarget = b .cast(void.class, objCls, Object.class) .invokeStaticQuiet(lookup(), objCls, "setVariableChecked"); } else { .filterReturn(filter) .insert(1, cls.getRealClass(), accessor.getIndex()) .cast(void.class, RubyBasicObject.class, RubyClass.class, int.class, Object.class) .invokeStaticQuiet(lookup(), accessor.getClass(), "setVariableChecked");
/** * Apply all transforms to an endpoint that does absolutely nothing. Useful for * creating exception handlers in void methods that simply ignore the exception. * * @return a handle that has all transforms applied and does nothing at its endpoint */ public MethodHandle nop() { if (type().returnType() != void.class) { throw new InvalidTransformException("must have void return type to nop: " + type()); } return invoke(Binder .from(type()) .drop(0, type().parameterCount()) .cast(Object.class) .constant(null)); }
MethodHandle buildNewInstanceHandle(DynamicMethod method, IRubyObject self) { MethodHandle mh = null; if (method == self.getRuntime().getBaseNewMethod()) { RubyClass recvClass = (RubyClass) self; // Bind a second site as a dynamic invoker to guard against changes in new object's type CallSite initSite = SelfInvokeSite.bootstrap(LOOKUP, "callFunctional:initialize", type(), literalClosure ? 1 : 0, file, line); MethodHandle initHandle = initSite.dynamicInvoker(); MethodHandle allocFilter = Binder.from(IRubyObject.class, IRubyObject.class) .cast(IRubyObject.class, RubyClass.class) .insert(0, new Class[] {ObjectAllocator.class, Ruby.class}, recvClass.getAllocator(), self.getRuntime()) .invokeVirtualQuiet(LOOKUP, "allocate"); mh = SmartBinder.from(LOOKUP, signature) .filter("self", allocFilter) .fold("dummy", initHandle) .permute("self") .identity() .handle(); if (Options.INVOKEDYNAMIC_LOG_BINDING.load()) { LOG.info(name() + "\tbound as new instance creation " + Bootstrap.logMethod(method)); } } return mh; }
MethodHandle buildNewInstanceHandle(DynamicMethod method, IRubyObject self) { MethodHandle mh = null; if (method == self.getRuntime().getBaseNewMethod()) { RubyClass recvClass = (RubyClass) self; // Bind a second site as a dynamic invoker to guard against changes in new object's type CallSite initSite = SelfInvokeSite.bootstrap(LOOKUP, "callFunctional:initialize", type(), literalClosure ? 1 : 0, file, line); MethodHandle initHandle = initSite.dynamicInvoker(); MethodHandle allocFilter = Binder.from(IRubyObject.class, IRubyObject.class) .cast(IRubyObject.class, RubyClass.class) .insert(0, new Class[] {ObjectAllocator.class, Ruby.class}, recvClass.getAllocator(), self.getRuntime()) .invokeVirtualQuiet(LOOKUP, "allocate"); mh = SmartBinder.from(LOOKUP, signature) .filter("self", allocFilter) .fold("dummy", initHandle) .permute("self") .identity() .handle(); if (Options.INVOKEDYNAMIC_LOG_BINDING.load()) { LOG.info(name() + "\tbound as new instance creation " + Bootstrap.logMethod(method)); } } return mh; }