// warning ! stolen code ahead ! (http://code.google.com/p/jsr292-cookbook) public static CallSite myBSM(Lookup lookup, String name, MethodType type, Class<?> staticType) throws ReflectiveOperationException { MethodHandle target = lookup.findStatic(staticType, name, type); HashMap<String, HashMap<Object, Object>> cacheTable = cacheTables.get(staticType); String selector = name + type.toMethodDescriptorString(); HashMap<Object, Object> cache = cacheTable.get(selector); if (cache == null) { cache = new HashMap<Object, Object>(); cacheTable.put(selector, cache); } MethodHandle identity = MethodHandles.identity(type.returnType()); identity = identity.asType(identity.type().changeParameterType(0, Object.class)); identity = MethodHandles.dropArguments(identity, 1, type.parameterType(0)); MethodHandle update = UPDATE.bindTo(cache); update = update.asType(type.insertParameterTypes(0, type.returnType())); MethodHandle fallback = MethodHandles.foldArguments(update, target); fallback = MethodHandles.dropArguments(fallback, 0, Object.class); MethodHandle combiner = MethodHandles.guardWithTest(NOT_NULL, identity, fallback); MethodHandle cacheQuerier = MAP_GET.bindTo(cache); cacheQuerier = cacheQuerier.asType(MethodType.methodType(Object.class, type.parameterType(0))); MethodHandle memoize = MethodHandles.foldArguments(combiner, cacheQuerier); return new ConstantCallSite(memoize); }
public InvokeSite(MethodType type, String name, CallType callType) { super(type); this.methodName = name; this.callType = callType; Signature startSig; if (callType == CallType.SUPER) { // super calls receive current class argument, so offsets and signature are different startSig = JRubyCallSite.STANDARD_SUPER_SIG; argOffset = 4; } else { startSig = JRubyCallSite.STANDARD_SITE_SIG; argOffset = 3; } int arity; if (type.parameterType(type.parameterCount() - 1) == Block.class) { arity = type.parameterCount() - (argOffset + 1); if (arity == 1 && type.parameterType(argOffset) == IRubyObject[].class) { arity = -1; startSig = startSig.appendArg("args", IRubyObject[].class); } else { for (int i = 0; i < arity; i++) { startSig = startSig.appendArg("arg" + i, IRubyObject.class); } } startSig = startSig.appendArg("block", Block.class); fullSignature = signature = startSig; } else { arity = type.parameterCount() - argOffset; if (arity == 1 && type.parameterType(argOffset) == IRubyObject[].class) { arity = -1; startSig = startSig.appendArg("args", IRubyObject[].class); } else { for (int i = 0; i < arity; i++) { startSig = startSig.appendArg("arg" + i, IRubyObject.class); } } signature = startSig; fullSignature = startSig.appendArg("block", Block.class); } this.arity = arity; this.fallback = prepareBinder().invokeVirtualQuiet(Bootstrap.LOOKUP, "invoke"); }
public CatchExceptionTest( TestCase testCase, final boolean isVararg, final int argsCount, final int catchDrops) { this.testCase = testCase; this.dropped = catchDrops; if (Helper.IS_VERBOSE) { System.out.printf( "CatchException::CatchException(%s, isVararg=%b " + "argsCount=%d catchDrops=%d)%n", testCase, isVararg, argsCount, catchDrops); } MethodHandle thrower = testCase.thrower; int throwerLen = thrower.type().parameterCount(); List<Class<?>> classes; int extra = Math.max(0, argsCount - throwerLen); classes = getThrowerParams(isVararg, extra); this.argsCount = throwerLen + classes.size(); thrower = Helper.addTrailingArgs(thrower, this.argsCount, classes); if (isVararg && argsCount > throwerLen) { MethodType mt = thrower.type(); Class<?> lastParam = mt.parameterType(mt.parameterCount() - 1); thrower = thrower.asVarargsCollector(lastParam); } this.thrower = thrower; this.dropped = Math.min(this.argsCount, catchDrops); catcher = testCase.getCatcher(getCatcherParams()); nargs = Math.max(2, this.argsCount); }
/*non-public*/ boolean isConvertibleTo(MethodType newType) { if (!canConvert(returnType(), newType.returnType())) return false; int argc = parameterCount(); if (argc != newType.parameterCount()) return false; for (int i = 0; i < argc; i++) { if (!canConvert(newType.parameterType(i), parameterType(i))) return false; } return true; }
@Override public CompletableFuture<?> execute( Call call, TransactionManager transactionManager, Metadata metadata, AccessControl accessControl, QueryStateMachine stateMachine) { if (!stateMachine.isAutoCommit()) { throw new PrestoException( NOT_SUPPORTED, "Procedures cannot be called within a transaction (use autocommit mode)"); } Session session = stateMachine.getSession(); QualifiedObjectName procedureName = createQualifiedObjectName(session, call, call.getName()); Procedure procedure = metadata.getProcedureRegistry().resolve(procedureName); // map declared argument names to positions Map<String, Integer> positions = new HashMap<>(); for (int i = 0; i < procedure.getArguments().size(); i++) { positions.put(procedure.getArguments().get(i).getName(), i); } // per specification, do not allow mixing argument types Predicate<CallArgument> hasName = argument -> argument.getName().isPresent(); boolean anyNamed = call.getArguments().stream().anyMatch(hasName); boolean allNamed = call.getArguments().stream().allMatch(hasName); if (anyNamed && !allNamed) { throw new SemanticException( INVALID_PROCEDURE_ARGUMENTS, call, "Named and positional arguments cannot be mixed"); } // get the argument names in call order Map<String, CallArgument> names = new LinkedHashMap<>(); for (int i = 0; i < call.getArguments().size(); i++) { CallArgument argument = call.getArguments().get(i); if (argument.getName().isPresent()) { String name = argument.getName().get(); if (names.put(name, argument) != null) { throw new SemanticException( INVALID_PROCEDURE_ARGUMENTS, argument, "Duplicate procedure argument: %s", name); } if (!positions.containsKey(name)) { throw new SemanticException( INVALID_PROCEDURE_ARGUMENTS, argument, "Unknown argument name: %s", name); } } else if (i < procedure.getArguments().size()) { names.put(procedure.getArguments().get(i).getName(), argument); } else { throw new SemanticException( INVALID_PROCEDURE_ARGUMENTS, call, "Too many arguments for procedure"); } } // verify argument count if (names.size() < positions.size()) { throw new SemanticException( INVALID_PROCEDURE_ARGUMENTS, call, "Too few arguments for procedure"); } // get argument values Object[] values = new Object[procedure.getArguments().size()]; for (Entry<String, CallArgument> entry : names.entrySet()) { CallArgument callArgument = entry.getValue(); int index = positions.get(entry.getKey()); Argument argument = procedure.getArguments().get(index); Expression expression = callArgument.getValue(); Type type = argument.getType(); Object value = evaluateConstantExpression(expression, type, metadata, session); values[index] = toTypeObjectValue(session, type, value); } // validate arguments MethodType methodType = procedure.getMethodHandle().type(); for (int i = 0; i < procedure.getArguments().size(); i++) { if ((values[i] == null) && methodType.parameterType(i).isPrimitive()) { String name = procedure.getArguments().get(i).getName(); throw new PrestoException( INVALID_PROCEDURE_ARGUMENT, "Procedure argument cannot be null: " + name); } } // insert session argument List<Object> arguments = new ArrayList<>(); Iterator<Object> valuesIterator = asList(values).iterator(); for (Class<?> type : methodType.parameterList()) { if (ConnectorSession.class.isAssignableFrom(type)) { arguments.add(session.toConnectorSession(procedureName.getCatalogName())); } else { arguments.add(valuesIterator.next()); } } try { procedure.getMethodHandle().invokeWithArguments(arguments); } catch (Throwable t) { if (t instanceof InterruptedException) { Thread.currentThread().interrupt(); } propagateIfInstanceOf(t, PrestoException.class); throw new PrestoException(PROCEDURE_CALL_FAILED, t); } return completedFuture(null); }
/** * Reports the number of JVM stack slots which carry all parameters including and after the given * position, which must be in the range of 0 to {@code parameterCount} inclusive. Successive * parameters are more shallowly stacked, and parameters are indexed in the bytecodes according to * their trailing edge. Thus, to obtain the depth in the outgoing call stack of parameter {@code * N}, obtain the {@code parameterSlotDepth} of its trailing edge at position {@code N+1}. * * <p>Parameters of type {@code long} and {@code double} occupy two stack slots (for historical * reasons) and all others occupy one. Therefore, the number returned is the number of arguments * <em>including</em> and <em>after</em> the given parameter, <em>plus</em> the number of long or * double arguments at or after after the argument for the given parameter. * * <p>This method is included for the benfit of applications that must generate bytecodes that * process method handles and invokedynamic. * * @param num an index (zero-based, inclusive) within the parameter types * @return the index of the (shallowest) JVM stack slot transmitting the given parameter * @throws IllegalArgumentException if {@code num} is negative or greater than {@code * parameterCount()} */ /*non-public*/ int parameterSlotDepth(int num) { if (num < 0 || num > ptypes.length) parameterType(num); // force a range check return form.parameterToArgSlot(num - 1); }