/** * Terminate this binder by returning its sole remaining argument. The * signature must take only one argument whose type matches the return * type. * * Invoking the resulting handle will (eventually) return the argument * passed in at this point. * * @return a new SmartHandle with this binder's starting signature that * simply returns its sole received argument */ public SmartHandle identity() { return new SmartHandle(start, binder.identity()); }
private MethodHandle nativeTryFinally(MethodHandle target, MethodHandle post) { MethodType targetType = target.type(); boolean voidReturn = targetType.returnType() == Void.TYPE; MethodType finallyType = targetType.insertParameterTypes(0, Throwable.class); int dropCount = 1; if (!voidReturn) { finallyType = finallyType.insertParameterTypes(1, targetType.returnType()); dropCount = 2; } MethodHandle wrapPost = Binder .from(finallyType) .drop(0, dropCount) .invoke(post); if (!voidReturn) { wrapPost = Binder.from(finallyType) .foldVoid(wrapPost) .permute(1) .identity(); } try { return (MethodHandle) tryFinallyJava9.invokeExact(target, wrapPost); } catch (Throwable t) { throw new RuntimeException("Java 9 detected but MethodHandles.tryFinally missing", t); } }
public static IRubyObject attrAssign(InvokeSite site, ThreadContext context, IRubyObject self, IRubyObject arg0) throws Throwable { RubyClass selfClass = self.getMetaClass(); String methodName = site.name; SwitchPoint switchPoint = (SwitchPoint)selfClass.getInvalidator().getData(); CacheEntry entry = selfClass.searchWithCache(methodName); DynamicMethod method = entry.method; if (methodMissing(entry, CallType.NORMAL, methodName, self)) { return callMethodMissing(entry, CallType.NORMAL, context, self, methodName, arg0); } MethodHandle mh = getHandle(selfClass, switchPoint, site, method, 1, false); mh = foldArguments( mh, Binder.from(site.type()) .drop(0, 2) .identity()); site.setTarget(mh); mh.invokeWithArguments(context, self, arg0); return arg0; }
public static IRubyObject attrAssign(InvokeSite site, ThreadContext context, IRubyObject self, IRubyObject arg0) throws Throwable { RubyClass selfClass = self.getMetaClass(); String methodName = site.name; SwitchPoint switchPoint = (SwitchPoint)selfClass.getInvalidator().getData(); CacheEntry entry = selfClass.searchWithCache(methodName); DynamicMethod method = entry.method; if (methodMissing(entry, CallType.NORMAL, methodName, self)) { return callMethodMissing(entry, CallType.NORMAL, context, self, methodName, arg0); } MethodHandle mh = getHandle(selfClass, switchPoint, site, method, 1, false); mh = foldArguments( mh, Binder.from(site.type()) .drop(0, 2) .identity()); site.setTarget(mh); mh.invokeWithArguments(context, self, arg0); return arg0; }
public MethodHandle up(MethodHandle target) { if (Util.isJava9()) return nativeTryFinally(target, post); MethodHandle exceptionHandler = Binder .from(target.type().insertParameterTypes(0, Throwable.class).changeReturnType(void.class)) .drop(0) .invoke(post); MethodHandle rethrow = Binder .from(target.type().insertParameterTypes(0, Throwable.class)) .fold(exceptionHandler) .drop(1, target.type().parameterCount()) .throwException(); target = MethodHandles.catchException(target, Throwable.class, rethrow); // if target returns a value, we must return it regardless of post MethodHandle realPost = post; if (target.type().returnType() != void.class) { // modify post to ignore return value MethodHandle newPost = Binder .from(target.type().insertParameterTypes(0, target.type().returnType()).changeReturnType(void.class)) .drop(0) .invoke(post); // fold post into an identity chain that only returns the value realPost = Binder .from(target.type().insertParameterTypes(0, target.type().returnType())) .fold(newPost) .drop(1, target.type().parameterCount()) .identity(); } return MethodHandles.foldArguments(realPost, target); }