예제 #1
0
 /**
  * Return a method handle that takes the indicated number of typed arguments and returns an array
  * of them. The type argument is the array type.
  */
 public static MethodHandle varargsArray(Class<?> arrayType, int nargs) {
   Class<?> elemType = arrayType.getComponentType();
   if (elemType == null) throw new IllegalArgumentException("not an array: " + arrayType);
   // FIXME: Need more special casing and caching here.
   if (nargs >= MAX_JVM_ARITY / 2 - 1) {
     int slots = nargs;
     final int MAX_ARRAY_SLOTS = MAX_JVM_ARITY - 1; // 1 for receiver MH
     if (arrayType == double[].class || arrayType == long[].class) slots *= 2;
     if (slots > MAX_ARRAY_SLOTS)
       throw new IllegalArgumentException(
           "too many arguments: " + arrayType.getSimpleName() + ", length " + nargs);
   }
   if (elemType == Object.class) return varargsArray(nargs);
   // other cases:  primitive arrays, subtypes of Object[]
   MethodHandle cache[] = TYPED_COLLECTORS.get(elemType);
   MethodHandle mh = nargs < cache.length ? cache[nargs] : null;
   if (mh != null) return mh;
   if (elemType.isPrimitive()) {
     MethodHandle builder = FILL_NEW_ARRAY;
     MethodHandle producer = buildArrayProducer(arrayType);
     mh = buildVarargsArray(builder, producer, nargs);
   } else {
     @SuppressWarnings("unchecked")
     Class<? extends Object[]> objArrayType = (Class<? extends Object[]>) arrayType;
     Object[] example = Arrays.copyOf(NO_ARGS_ARRAY, 0, objArrayType);
     MethodHandle builder = FILL_NEW_TYPED_ARRAY.bindTo(example);
     MethodHandle producer = ARRAY_IDENTITY;
     mh = buildVarargsArray(builder, producer, nargs);
   }
   mh =
       mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType)));
   assert (assertCorrectArity(mh, nargs));
   if (nargs < cache.length) cache[nargs] = mh;
   return mh;
 }
예제 #2
0
  private static MethodHandle buildFiller(int nargs) {
    if (nargs <= LEFT_ARGS) return ARRAY_IDENTITY; // no args to fill; return the array unchanged
    // we need room for both mh and a in mh.invoke(a, arg*[nargs])
    final int CHUNK = LEFT_ARGS;
    int rightLen = nargs % CHUNK;
    int midLen = nargs - rightLen;
    if (rightLen == 0) {
      midLen = nargs - (rightLen = CHUNK);
      if (FILL_ARRAY_TO_RIGHT[midLen] == null) {
        // build some precursors from left to right
        for (int j = LEFT_ARGS % CHUNK; j < midLen; j += CHUNK) if (j > LEFT_ARGS) fillToRight(j);
      }
    }
    if (midLen < LEFT_ARGS) rightLen = nargs - (midLen = LEFT_ARGS);
    assert (rightLen > 0);
    MethodHandle midFill = fillToRight(midLen); // recursive fill
    MethodHandle rightFill = FILL_ARRAYS[rightLen].bindTo(midLen); // [midLen..nargs-1]
    assert (midFill.type().parameterCount() == 1 + midLen - LEFT_ARGS);
    assert (rightFill.type().parameterCount() == 1 + rightLen);

    // Combine the two fills:
    //   right(mid(a, x10..x19), x20..x23)
    // The final product will look like this:
    //   right(mid(newArrayLeft(24, x0..x9), x10..x19), x20..x23)
    if (midLen == LEFT_ARGS) return rightFill;
    else return MethodHandles.collectArguments(rightFill, 0, midFill);
  }
예제 #3
0
  public static MethodHandle convertPrimitive(Wrapper wsrc, Wrapper wdst) {
    EnumMap<Wrapper, MethodHandle> cache = CONVERT_PRIMITIVE_FUNCTIONS[wsrc.ordinal()];
    MethodHandle mh = cache.get(wdst);
    if (mh != null) {
      return mh;
    }
    // slow path
    Class<?> src = wsrc.primitiveType();
    Class<?> dst = wdst.primitiveType();
    MethodType type =
        src == void.class ? MethodType.methodType(dst) : MethodType.methodType(dst, src);
    if (wsrc == wdst) {
      mh = identity(src);
    } else if (wsrc == Wrapper.VOID) {
      mh = zeroConstantFunction(wdst);
    } else if (wdst == Wrapper.VOID) {
      mh = MethodHandles.dropArguments(EMPTY, 0, src); // Defer back to MethodHandles.
    } else if (wsrc == Wrapper.OBJECT) {
      mh = unboxCast(dst);
    } else if (wdst == Wrapper.OBJECT) {
      mh = box(src);
    } else {
      assert (src.isPrimitive() && dst.isPrimitive());
      try {
        mh =
            IMPL_LOOKUP.findStatic(
                THIS_CLASS, src.getSimpleName() + "To" + capitalize(dst.getSimpleName()), type);
      } catch (ReflectiveOperationException ex) {
        mh = null;
      }
    }
    if (mh != null) {
      assert (mh.type() == type) : mh;
      cache.put(wdst, mh);
      return mh;
    }

    throw new IllegalArgumentException(
        "cannot find primitive conversion function for "
            + src.getSimpleName()
            + " -> "
            + dst.getSimpleName());
  }
예제 #4
0
 private static MethodHandle buildVarargsArray(
     MethodHandle newArray, MethodHandle finisher, int nargs) {
   // Build up the result mh as a sequence of fills like this:
   //   finisher(fill(fill(newArrayWA(23,x1..x10),10,x11..x20),20,x21..x23))
   // The various fill(_,10*I,___*[J]) are reusable.
   int leftLen = Math.min(nargs, LEFT_ARGS); // absorb some arguments immediately
   int rightLen = nargs - leftLen;
   MethodHandle leftCollector = newArray.bindTo(nargs);
   leftCollector = leftCollector.asCollector(Object[].class, leftLen);
   MethodHandle mh = finisher;
   if (rightLen > 0) {
     MethodHandle rightFiller = fillToRight(LEFT_ARGS + rightLen);
     if (mh == ARRAY_IDENTITY) mh = rightFiller;
     else mh = MethodHandles.collectArguments(mh, 0, rightFiller);
   }
   if (mh == ARRAY_IDENTITY) mh = leftCollector;
   else mh = MethodHandles.collectArguments(mh, 0, leftCollector);
   return mh;
 }
예제 #5
0
 private static boolean assertCorrectArity(MethodHandle mh, int arity) {
   assert (mh.type().parameterCount() == arity) : "arity != " + arity + ": " + mh;
   return true;
 }