// 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);
  }
Example #2
0
  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);
 }
Example #4
0
 /*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;
 }
Example #5
0
  @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);
  }
Example #6
0
 /**
  * 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);
 }