예제 #1
0
  /**
   * Determine which of two signatures is the closer fit. Returns one of PREFERENCE_EQUAL,
   * PREFERENCE_FIRST_ARG, PREFERENCE_SECOND_ARG, or PREFERENCE_AMBIGUOUS.
   */
  private static int preferSignature(
      Object[] args, Class<?>[] sig1, boolean vararg1, Class<?>[] sig2, boolean vararg2) {
    int totalPreference = 0;
    for (int j = 0; j < args.length; j++) {
      Class<?> type1 = vararg1 && j >= sig1.length ? sig1[sig1.length - 1] : sig1[j];
      Class<?> type2 = vararg2 && j >= sig2.length ? sig2[sig2.length - 1] : sig2[j];
      if (type1 == type2) {
        continue;
      }
      Object arg = args[j];

      // Determine which of type1, type2 is easier to convert from arg.

      int rank1 = NativeJavaObject.getConversionWeight(arg, type1);
      int rank2 = NativeJavaObject.getConversionWeight(arg, type2);

      int preference;
      if (rank1 < rank2) {
        preference = PREFERENCE_FIRST_ARG;
      } else if (rank1 > rank2) {
        preference = PREFERENCE_SECOND_ARG;
      } else {
        // Equal ranks
        if (rank1 == NativeJavaObject.CONVERSION_NONTRIVIAL) {
          if (type1.isAssignableFrom(type2)) {
            preference = PREFERENCE_SECOND_ARG;
          } else if (type2.isAssignableFrom(type1)) {
            preference = PREFERENCE_FIRST_ARG;
          } else {
            preference = PREFERENCE_AMBIGUOUS;
          }
        } else {
          preference = PREFERENCE_AMBIGUOUS;
        }
      }

      totalPreference |= preference;

      if (totalPreference == PREFERENCE_AMBIGUOUS) {
        break;
      }
    }
    return totalPreference;
  }
예제 #2
0
  /**
   * Find the index of the correct function to call given the set of methods or constructors and the
   * arguments. If no function can be found to call, return -1.
   */
  static int findFunction(Context cx, MemberBox[] methodsOrCtors, Object[] args) {
    if (methodsOrCtors.length == 0) {
      return -1;
    } else if (methodsOrCtors.length == 1) {
      MemberBox member = methodsOrCtors[0];
      Class<?>[] argTypes = member.argTypes;
      int alength = argTypes.length;

      if (member.vararg) {
        alength--;
        if (alength > args.length) {
          return -1;
        }
      } else {
        if (alength != args.length) {
          return -1;
        }
      }
      for (int j = 0; j != alength; ++j) {
        if (!NativeJavaObject.canConvert(args[j], argTypes[j])) {
          if (debug) printDebug("Rejecting (args can't convert) ", member, args);
          return -1;
        }
      }
      if (debug) printDebug("Found ", member, args);
      return 0;
    }

    int firstBestFit = -1;
    int[] extraBestFits = null;
    int extraBestFitsCount = 0;

    search:
    for (int i = 0; i < methodsOrCtors.length; i++) {
      MemberBox member = methodsOrCtors[i];
      Class<?>[] argTypes = member.argTypes;
      int alength = argTypes.length;
      if (member.vararg) {
        alength--;
        if (alength > args.length) {
          continue search;
        }
      } else {
        if (alength != args.length) {
          continue search;
        }
      }
      for (int j = 0; j < alength; j++) {
        if (!NativeJavaObject.canConvert(args[j], argTypes[j])) {
          if (debug) printDebug("Rejecting (args can't convert) ", member, args);
          continue search;
        }
      }
      if (firstBestFit < 0) {
        if (debug) printDebug("Found first applicable ", member, args);
        firstBestFit = i;
      } else {
        // Compare with all currently fit methods.
        // The loop starts from -1 denoting firstBestFit and proceed
        // until extraBestFitsCount to avoid extraBestFits allocation
        // in the most common case of no ambiguity
        int betterCount = 0; // number of times member was prefered over
        // best fits
        int worseCount = 0; // number of times best fits were prefered
        // over member
        for (int j = -1; j != extraBestFitsCount; ++j) {
          int bestFitIndex;
          if (j == -1) {
            bestFitIndex = firstBestFit;
          } else {
            bestFitIndex = extraBestFits[j];
          }
          MemberBox bestFit = methodsOrCtors[bestFitIndex];
          if (cx.hasFeature(Context.FEATURE_ENHANCED_JAVA_ACCESS)
              && (bestFit.member().getModifiers() & Modifier.PUBLIC)
                  != (member.member().getModifiers() & Modifier.PUBLIC)) {
            // When FEATURE_ENHANCED_JAVA_ACCESS gives us access
            // to non-public members, continue to prefer public
            // methods in overloading
            if ((bestFit.member().getModifiers() & Modifier.PUBLIC) == 0) ++betterCount;
            else ++worseCount;
          } else {
            int preference =
                preferSignature(args, argTypes, member.vararg, bestFit.argTypes, bestFit.vararg);
            if (preference == PREFERENCE_AMBIGUOUS) {
              break;
            } else if (preference == PREFERENCE_FIRST_ARG) {
              ++betterCount;
            } else if (preference == PREFERENCE_SECOND_ARG) {
              ++worseCount;
            } else {
              if (preference != PREFERENCE_EQUAL) Kit.codeBug();
              // This should not happen in theory
              // but on some JVMs, Class.getMethods will return all
              // static methods of the class hierarchy, even if
              // a derived class's parameters match exactly.
              // We want to call the derived class's method.
              if (bestFit.isStatic()
                  && bestFit.getDeclaringClass().isAssignableFrom(member.getDeclaringClass())) {
                // On some JVMs, Class.getMethods will return all
                // static methods of the class hierarchy, even if
                // a derived class's parameters match exactly.
                // We want to call the derived class's method.
                if (debug) printDebug("Substituting (overridden static)", member, args);
                if (j == -1) {
                  firstBestFit = i;
                } else {
                  extraBestFits[j] = i;
                }
              } else {
                if (debug) printDebug("Ignoring same signature member ", member, args);
              }
              continue search;
            }
          }
        }
        if (betterCount == 1 + extraBestFitsCount) {
          // member was prefered over all best fits
          if (debug) printDebug("New first applicable ", member, args);
          firstBestFit = i;
          extraBestFitsCount = 0;
        } else if (worseCount == 1 + extraBestFitsCount) {
          // all best fits were prefered over member, ignore it
          if (debug) printDebug("Rejecting (all current bests better) ", member, args);
        } else {
          // some ambiguity was present, add member to best fit set
          if (debug) printDebug("Added to best fit set ", member, args);
          if (extraBestFits == null) {
            // Allocate maximum possible array
            extraBestFits = new int[methodsOrCtors.length - 1];
          }
          extraBestFits[extraBestFitsCount] = i;
          ++extraBestFitsCount;
        }
      }
    }

    if (firstBestFit < 0) {
      // Nothing was found
      return -1;
    } else if (extraBestFitsCount == 0) {
      // single best fit
      return firstBestFit;
    }

    // report remaining ambiguity
    StringBuffer buf = new StringBuffer();
    for (int j = -1; j != extraBestFitsCount; ++j) {
      int bestFitIndex;
      if (j == -1) {
        bestFitIndex = firstBestFit;
      } else {
        bestFitIndex = extraBestFits[j];
      }
      buf.append("\n    ");
      buf.append(methodsOrCtors[bestFitIndex].toJavaDeclaration());
    }

    MemberBox firstFitMember = methodsOrCtors[firstBestFit];
    String memberName = firstFitMember.getName();
    String memberClass = firstFitMember.getDeclaringClass().getName();

    if (methodsOrCtors[0].isMethod()) {
      throw Context.reportRuntimeError3(
          "msg.constructor.ambiguous", memberName, scriptSignature(args), buf.toString());
    } else {
      throw Context.reportRuntimeError4(
          "msg.method.ambiguous", memberClass, memberName, scriptSignature(args), buf.toString());
    }
  }
예제 #3
0
 public static Scriptable createAdapterWrapper(Scriptable obj, Object adapter) {
   Scriptable scope = ScriptableObject.getTopLevelScope(obj);
   NativeJavaObject res = new NativeJavaObject(scope, adapter, null, true);
   res.setPrototype(obj);
   return res;
 }