/** * Permute all parameters except the names given. Blacklisting to #permute's * whitelisting. * * @param excludeNames parameter patterns to exclude * @return a new SmartBinder with the exclude applied */ public SmartBinder exclude(String... excludeNames) { return permute(signature().exclude(excludeNames)); }
/** * Using the argument names and order in the given targetNames, permute the * arguments in this SmartBinder. Arguments may be duplicated or omitted * in the targetNames array, but all arguments in the target must be * defined in this SmartBinder. * * @param targetNames the array of names from which to derive a new argument * list * @return a new SmartBinder with the permute applied */ public SmartBinder permute(String... targetNames) { return permute(signature().permute(targetNames)); }
private static MethodHandle getBlockEscape(Signature signature) { Signature voidSignature = signature.changeReturn(void.class); MethodHandle escape = BLOCK_ESCAPES.get(voidSignature); if (escape == null) { escape = SmartBinder.from(voidSignature) .permute("block") .invoke(ESCAPE_BLOCK) .handle(); BLOCK_ESCAPES.put(voidSignature, escape); } return escape; }
private static MethodHandle getBlockEscape(Signature signature) { Signature voidSignature = signature.changeReturn(void.class); MethodHandle escape = BLOCK_ESCAPES.get(voidSignature); if (escape == null) { escape = SmartBinder.from(voidSignature) .permute("block") .invoke(ESCAPE_BLOCK) .handle(); BLOCK_ESCAPES.put(voidSignature, escape); } return escape; }
public static MethodHandle getFrameOnlyPre(Signature signature, CallConfiguration callConfig, RubyModule implClass, String name) { Signature inbound = signature.asFold(void.class); SmartBinder binder = SmartBinder .from(inbound); switch (callConfig) { case FrameFullScopeNone: // before logic return binder .permute("context", "self", "block") .insert(1, arrayOf("selfClass", "name"), arrayOf(RubyModule.class, String.class), implClass, name) .invokeVirtualQuiet(lookup(), "preMethodFrameOnly") .handle(); default: throw new RuntimeException("invalid input: " + callConfig); } }
public static MethodHandle getFrameOnlyPre(Signature signature, CallConfiguration callConfig, RubyModule implClass, String name) { Signature inbound = signature.asFold(void.class); SmartBinder binder = SmartBinder .from(inbound); switch (callConfig) { case FrameFullScopeNone: // before logic return binder .permute("context", "self", "block") .insert(1, arrayOf("selfClass", "name"), arrayOf(RubyModule.class, String.class), implClass, name) .invokeVirtualQuiet(lookup(), "preMethodFrameOnly") .handle(); default: throw new RuntimeException("invalid input: " + callConfig); } }
private static MethodHandle dynamicCallTarget(Signature from, Signature to) { return SmartBinder .from(from) .fold("selfClass", from.asFold(RubyClass.class).permuteWith(PGC, "context", "self")) .permute(to) .cast(to) .invokeVirtualQuiet(lookup(), "call") .handle(); }
private static MethodHandle dynamicCallTarget(Signature from, Signature to) { return SmartBinder .from(from) .fold("selfClass", from.asFold(RubyClass.class).permuteWith(PGC, "context", "self")) .permute(to) .cast(to) .invokeVirtualQuiet(lookup(), "call") .handle(); }
SmartBinder binder = SmartBinder .from(inbound) .permute("context");
SmartBinder binder = SmartBinder .from(inbound) .permute("context");
SmartBinder binder = SmartBinder .from(inbound) .permute("context");
.permute("context", "self", "block") .insert(1, arrayOf("selfClass", "name"), arrayOf(RubyModule.class, String.class), implClass, name) .insert(5, arrayOf("scope"), arrayOf(StaticScope.class), scope) .permute("context", "self", "block") .insert(1, arrayOf("selfClass", "name"), arrayOf(RubyModule.class, String.class), implClass, name) .insert(5, arrayOf("scope"), arrayOf(StaticScope.class), scope) .permute("context", "self", "block") .insert(1, arrayOf("selfClass", "name"), arrayOf(RubyModule.class, String.class), implClass, name) .invokeVirtualQuiet(lookup(), "preMethodFrameOnly") .permute("context") .insert(1, arrayOf("selfClass", "scope"), arrayOf(RubyModule.class, StaticScope.class), implClass, scope) .invokeVirtualQuiet(lookup(), "preMethodNoFrameAndDummyScope")
static MethodHandle buildGenericHandle(InvokeSite site, DynamicMethod method, RubyClass dispatchClass) { SmartBinder binder; binder = SmartBinder.from(site.signature) .permute("context", "self", "arg.*", "block") .insert(2, new String[]{"rubyClass", "name"}, new Class[]{RubyModule.class, String.class}, dispatchClass, site.name()) .insert(0, "method", DynamicMethod.class, method); if (site.arity > 3) { binder = binder.collect("args", "arg.*"); } if (Options.INVOKEDYNAMIC_LOG_BINDING.load()) { LOG.info(site.name() + "\tbound indirectly " + method + ", " + Bootstrap.logMethod(method)); } return binder.invokeVirtualQuiet(LOOKUP, "call").handle(); }
static MethodHandle buildGenericHandle(InvokeSite site, DynamicMethod method, RubyClass dispatchClass) { SmartBinder binder; binder = SmartBinder.from(site.signature) .permute("context", "self", "arg.*", "block") .insert(2, new String[]{"rubyClass", "name"}, new Class[]{RubyModule.class, String.class}, dispatchClass, site.name()) .insert(0, "method", DynamicMethod.class, method); if (site.arity > 3) { binder = binder.collect("args", "arg.*"); } if (Options.INVOKEDYNAMIC_LOG_BINDING.load()) { LOG.info(site.name() + "\tbound indirectly " + method + ", " + Bootstrap.logMethod(method)); } return binder.invokeVirtualQuiet(LOOKUP, "call").handle(); }
.permute("throwable") .append("runtime", method.getImplementationClass().getRuntime()) .invokeStaticQuiet(lookup(), Helpers.class, "rewriteStackTraceAndThrow");
.permute("throwable") .append("runtime", method.getImplementationClass().getRuntime()) .invokeStaticQuiet(lookup(), Helpers.class, "rewriteStackTraceAndThrow");
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; }
public IRubyObject invoke(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject[] args, Block block) throws Throwable { RubyClass selfClass = pollAndGetClass(context, self); MethodHandle mh; CacheEntry entry = selfClass.searchWithCache(methodName); DynamicMethod method = entry.method; if (method.isBuiltin() && selfClass == context.runtime.getHash()) { // fast path since we know we're working with a normal hash and have a pre-frozen string mh = SmartBinder.from(signature) .permute("self", "context", "arg0") .cast(IRubyObject.class, RubyHash.class, ThreadContext.class, IRubyObject.class) .invokeVirtual(MethodHandles.publicLookup(), "op_aref") .handle(); SwitchPoint switchPoint = (SwitchPoint) selfClass.getInvalidator().getData(); updateInvocationTarget(mh, self, selfClass, method, switchPoint); return ((RubyHash) self).op_aref(context, args[0]); } else { // slow path follows normal invoke logic with a strDup for the key SwitchPoint switchPoint = (SwitchPoint) selfClass.getInvalidator().getData(); // strdup for this call args[0] = ((RubyString) args[0]).strDup(context.runtime); if (methodMissing(entry, caller)) { return callMethodMissing(entry, callType, context, self, selfClass, methodName, args, block); } mh = getHandle(self, selfClass, method); // strdup for future calls mh = MethodHandles.filterArguments(mh, 3, STRDUP_FILTER); updateInvocationTarget(mh, self, selfClass, entry.method, switchPoint); return method.call(context, self, selfClass, methodName, args, block); } }
public IRubyObject invoke(ThreadContext context, IRubyObject caller, IRubyObject self, IRubyObject[] args, Block block) throws Throwable { RubyClass selfClass = pollAndGetClass(context, self); MethodHandle mh; CacheEntry entry = selfClass.searchWithCache(methodName); DynamicMethod method = entry.method; if (method.isBuiltin() && selfClass == context.runtime.getHash()) { // fast path since we know we're working with a normal hash and have a pre-frozen string mh = SmartBinder.from(signature) .permute("self", "context", "arg0") .cast(IRubyObject.class, RubyHash.class, ThreadContext.class, IRubyObject.class) .invokeVirtual(MethodHandles.publicLookup(), "op_aref") .handle(); SwitchPoint switchPoint = (SwitchPoint) selfClass.getInvalidator().getData(); updateInvocationTarget(mh, self, selfClass, method, switchPoint); return ((RubyHash) self).op_aref(context, args[0]); } else { // slow path follows normal invoke logic with a strDup for the key SwitchPoint switchPoint = (SwitchPoint) selfClass.getInvalidator().getData(); // strdup for this call args[0] = ((RubyString) args[0]).strDup(context.runtime); if (methodMissing(entry, caller)) { return callMethodMissing(entry, callType, context, self, selfClass, methodName, args, block); } mh = getHandle(self, selfClass, method); // strdup for future calls mh = MethodHandles.filterArguments(mh, 3, STRDUP_FILTER); updateInvocationTarget(mh, self, selfClass, entry.method, switchPoint); return method.call(context, self, selfClass, methodName, args, block); } }