Java Code Examples for jdk.nashorn.internal.codegen.types.Type#isBoolean()

The following examples show how to use jdk.nashorn.internal.codegen.types.Type#isBoolean() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: MethodEmitter.java    From openjdk-jdk8u-backup with GNU General Public License v2.0 6 votes vote down vote up
/**
 * Generate dynamic getter. Pop scope from stack. Push result
 *
 * @param valueType type of the value to set
 * @param name      name of property
 * @param flags     call site flags
 * @param isMethod  should it prefer retrieving methods
 * @param isIndex   is this an index operation?
 * @return the method emitter
 */
MethodEmitter dynamicGet(final Type valueType, final String name, final int flags, final boolean isMethod, final boolean isIndex) {
    if (name.length() > LARGE_STRING_THRESHOLD) { // use getIndex for extremely long names
        return load(name).dynamicGetIndex(valueType, flags, isMethod);
    }

    debug("dynamic_get", name, valueType, getProgramPoint(flags));

    Type type = valueType;
    if (type.isObject() || type.isBoolean()) {
        type = Type.OBJECT; //promote e.g strings to object generic setter
    }

    popType(Type.SCOPE);
    method.visitInvokeDynamicInsn(dynGetOperation(isMethod, isIndex) + ':' + NameCodec.encode(name),
            Type.getMethodDescriptor(type, Type.OBJECT), LINKERBOOTSTRAP, flags);

    pushType(type);
    convert(valueType); //most probably a nop

    return this;
}
 
Example 2
Source File: MethodEmitter.java    From openjdk-8-source with GNU General Public License v2.0 6 votes vote down vote up
/**
 * Generate dynamic getter. Pop scope from stack. Push result
 *
 * @param valueType type of the value to set
 * @param name      name of property
 * @param flags     call site flags
 * @param isMethod  should it prefer retrieving methods
 *
 * @return the method emitter
 */
MethodEmitter dynamicGet(final Type valueType, final String name, final int flags, final boolean isMethod) {
    debug("dynamic_get", name, valueType);

    Type type = valueType;
    if (type.isObject() || type.isBoolean()) {
        type = Type.OBJECT; //promote e.g strings to object generic setter
    }

    popType(Type.SCOPE);
    method.visitInvokeDynamicInsn((isMethod ? "dyn:getMethod|getProp|getElem:" : "dyn:getProp|getElem|getMethod:") +
            NameCodec.encode(name), Type.getMethodDescriptor(type, Type.OBJECT), LINKERBOOTSTRAP, flags);

    pushType(type);

    convert(valueType); //most probably a nop

    return this;
}
 
Example 3
Source File: MethodEmitter.java    From hottub with GNU General Public License v2.0 6 votes vote down vote up
/**
 * Generate dynamic getter. Pop scope from stack. Push result
 *
 * @param valueType type of the value to set
 * @param name      name of property
 * @param flags     call site flags
 * @param isMethod  should it prefer retrieving methods
 * @param isIndex   is this an index operation?
 * @return the method emitter
 */
MethodEmitter dynamicGet(final Type valueType, final String name, final int flags, final boolean isMethod, final boolean isIndex) {
    if (name.length() > LARGE_STRING_THRESHOLD) { // use getIndex for extremely long names
        return load(name).dynamicGetIndex(valueType, flags, isMethod);
    }

    debug("dynamic_get", name, valueType, getProgramPoint(flags));

    Type type = valueType;
    if (type.isObject() || type.isBoolean()) {
        type = Type.OBJECT; //promote e.g strings to object generic setter
    }

    popType(Type.SCOPE);
    method.visitInvokeDynamicInsn(dynGetOperation(isMethod, isIndex) + ':' + NameCodec.encode(name),
            Type.getMethodDescriptor(type, Type.OBJECT), LINKERBOOTSTRAP, flags);

    pushType(type);
    convert(valueType); //most probably a nop

    return this;
}
 
Example 4
Source File: MethodEmitter.java    From openjdk-8 with GNU General Public License v2.0 6 votes vote down vote up
/**
 * Generate dynamic getter. Pop scope from stack. Push result
 *
 * @param valueType type of the value to set
 * @param name      name of property
 * @param flags     call site flags
 * @param isMethod  should it prefer retrieving methods
 *
 * @return the method emitter
 */
MethodEmitter dynamicGet(final Type valueType, final String name, final int flags, final boolean isMethod) {
    debug("dynamic_get", name, valueType);

    Type type = valueType;
    if (type.isObject() || type.isBoolean()) {
        type = Type.OBJECT; //promote e.g strings to object generic setter
    }

    popType(Type.SCOPE);
    method.visitInvokeDynamicInsn((isMethod ? "dyn:getMethod|getProp|getElem:" : "dyn:getProp|getElem|getMethod:") +
            NameCodec.encode(name), Type.getMethodDescriptor(type, Type.OBJECT), LINKERBOOTSTRAP, flags);

    pushType(type);

    convert(valueType); //most probably a nop

    return this;
}
 
Example 5
Source File: LiteralNode.java    From openjdk-jdk8u-backup with GNU General Public License v2.0 6 votes vote down vote up
private static Type computeElementType(final Expression[] value) {
    Type widestElementType = Type.INT;

    for (final Expression elem : value) {
        if (elem == null) {
            widestElementType = widestElementType.widest(Type.OBJECT); //no way to represent undefined as number
            break;
        }

        final Type type = elem.getType().isUnknown() ? Type.OBJECT : elem.getType();
        if (type.isBoolean()) {
            //TODO fix this with explicit boolean types
            widestElementType = widestElementType.widest(Type.OBJECT);
            break;
        }

        widestElementType = widestElementType.widest(type);
        if (widestElementType.isObject()) {
            break;
        }
    }
    return widestElementType;
}
 
Example 6
Source File: MethodEmitter.java    From openjdk-jdk8u with GNU General Public License v2.0 6 votes vote down vote up
/**
 * Generate dynamic getter. Pop scope from stack. Push result
 *
 * @param valueType type of the value to set
 * @param name      name of property
 * @param flags     call site flags
 * @param isMethod  should it prefer retrieving methods
 * @param isIndex   is this an index operation?
 * @return the method emitter
 */
MethodEmitter dynamicGet(final Type valueType, final String name, final int flags, final boolean isMethod, final boolean isIndex) {
    if (name.length() > LARGE_STRING_THRESHOLD) { // use getIndex for extremely long names
        return load(name).dynamicGetIndex(valueType, flags, isMethod);
    }

    debug("dynamic_get", name, valueType, getProgramPoint(flags));

    Type type = valueType;
    if (type.isObject() || type.isBoolean()) {
        type = Type.OBJECT; //promote e.g strings to object generic setter
    }

    popType(Type.SCOPE);
    method.visitInvokeDynamicInsn(dynGetOperation(isMethod, isIndex) + ':' + NameCodec.encode(name),
            Type.getMethodDescriptor(type, Type.OBJECT), LINKERBOOTSTRAP, flags);

    pushType(type);
    convert(valueType); //most probably a nop

    return this;
}
 
Example 7
Source File: MethodEmitter.java    From jdk8u60 with GNU General Public License v2.0 6 votes vote down vote up
/**
 * Generate dynamic getter. Pop scope from stack. Push result
 *
 * @param valueType type of the value to set
 * @param name      name of property
 * @param flags     call site flags
 * @param isMethod  should it prefer retrieving methods
 * @param isIndex   is this an index operation?
 * @return the method emitter
 */
MethodEmitter dynamicGet(final Type valueType, final String name, final int flags, final boolean isMethod, final boolean isIndex) {
    if (name.length() > LARGE_STRING_THRESHOLD) { // use getIndex for extremely long names
        return load(name).dynamicGetIndex(valueType, flags, isMethod);
    }

    debug("dynamic_get", name, valueType, getProgramPoint(flags));

    Type type = valueType;
    if (type.isObject() || type.isBoolean()) {
        type = Type.OBJECT; //promote e.g strings to object generic setter
    }

    popType(Type.SCOPE);
    method.visitInvokeDynamicInsn(dynGetOperation(isMethod, isIndex) + ':' + NameCodec.encode(name),
            Type.getMethodDescriptor(type, Type.OBJECT), LINKERBOOTSTRAP, flags);

    pushType(type);
    convert(valueType); //most probably a nop

    return this;
}
 
Example 8
Source File: LiteralNode.java    From jdk8u60 with GNU General Public License v2.0 6 votes vote down vote up
private static Type computeElementType(final Expression[] value) {
    Type widestElementType = Type.INT;

    for (final Expression elem : value) {
        if (elem == null) {
            widestElementType = widestElementType.widest(Type.OBJECT); //no way to represent undefined as number
            break;
        }

        final Type type = elem.getType().isUnknown() ? Type.OBJECT : elem.getType();
        if (type.isBoolean()) {
            //TODO fix this with explicit boolean types
            widestElementType = widestElementType.widest(Type.OBJECT);
            break;
        }

        widestElementType = widestElementType.widest(type);
        if (widestElementType.isObject()) {
            break;
        }
    }
    return widestElementType;
}
 
Example 9
Source File: LiteralNode.java    From jdk8u_nashorn with GNU General Public License v2.0 6 votes vote down vote up
private static Type computeElementType(final Expression[] value) {
    Type widestElementType = Type.INT;

    for (final Expression elem : value) {
        if (elem == null) {
            widestElementType = widestElementType.widest(Type.OBJECT); //no way to represent undefined as number
            break;
        }

        final Type type = elem.getType().isUnknown() ? Type.OBJECT : elem.getType();
        if (type.isBoolean()) {
            //TODO fix this with explicit boolean types
            widestElementType = widestElementType.widest(Type.OBJECT);
            break;
        }

        widestElementType = widestElementType.widest(type);
        if (widestElementType.isObject()) {
            break;
        }
    }
    return widestElementType;
}
 
Example 10
Source File: MethodEmitter.java    From openjdk-8 with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Generate dynamic setter. Pop receiver and property from stack.
 *
 * @param valueType the type of the value to set
 * @param name      name of property
 * @param flags     call site flags
 */
 void dynamicSet(final String name, final int flags) {
    debug("dynamic_set", name, peekType());

    Type type = peekType();
    if (type.isObject() || type.isBoolean()) { //promote strings to objects etc
        type = Type.OBJECT;
        convert(Type.OBJECT); //TODO bad- until we specialize boolean setters,
    }
    popType(type);
    popType(Type.SCOPE);

    method.visitInvokeDynamicInsn("dyn:setProp|setElem:" + NameCodec.encode(name), methodDescriptor(void.class, Object.class, type.getTypeClass()), LINKERBOOTSTRAP, flags);
}
 
Example 11
Source File: Attr.java    From openjdk-8-source with GNU General Public License v2.0 5 votes vote down vote up
/**
 * When doing widening for return types of a function or a ternary operator, it is not valid to widen a boolean to
 * anything other than Object. Also, widening a numeric type to an object type must widen to Object proper and not
 * any more specific subclass (e.g. widest of int/long/double and String is Object).
 * @param t1 type 1
 * @param t2 type 2
 * @return wider of t1 and t2, except if one is boolean and the other is neither boolean nor unknown, or if one is
 * numeric and the other is neither numeric nor unknown in which case {@code Type.OBJECT} is returned.
 */
private static Type widestReturnType(final Type t1, final Type t2) {
    if (t1.isUnknown()) {
        return t2;
    } else if (t2.isUnknown()) {
        return t1;
    } else if (t1.isBoolean() != t2.isBoolean() || t1.isNumeric() != t2.isNumeric()) {
        return Type.OBJECT;
    }
    return Type.widest(t1, t2);
}
 
Example 12
Source File: MethodEmitter.java    From nashorn with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Dynamic getter for indexed structures. Pop index and receiver from stack,
 * generate appropriate signatures based on types
 *
 * @param result result type for getter
 * @param flags call site flags for getter
 * @param isMethod should it prefer retrieving methods
 *
 * @return the method emitter
 */
MethodEmitter dynamicGetIndex(final Type result, final int flags, final boolean isMethod) {
    debug("dynamic_get_index", peekType(1), "[", peekType(), "]");

    Type resultType = result;
    if (result.isBoolean()) {
        resultType = Type.OBJECT; // INT->OBJECT to avoid another dimension of cross products in the getters. TODO
    }

    Type index = peekType();
    if (index.isObject() || index.isBoolean()) {
        index = Type.OBJECT; //e.g. string->object
        convert(Type.OBJECT);
    }
    popType();

    popType(Type.OBJECT);

    final String signature = Type.getMethodDescriptor(resultType, Type.OBJECT /*e.g STRING->OBJECT*/, index);

    method.visitInvokeDynamicInsn(isMethod ? "dyn:getMethod|getElem|getProp" : "dyn:getElem|getProp|getMethod",
            signature, LINKERBOOTSTRAP, flags);
    pushType(resultType);

    if (result.isBoolean()) {
        convert(Type.BOOLEAN);
    }

    return this;
}
 
Example 13
Source File: MethodEmitter.java    From openjdk-8-source with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Dynamic getter for indexed structures. Pop index and receiver from stack,
 * generate appropriate signatures based on types
 *
 * @param result result type for getter
 * @param flags call site flags for getter
 * @param isMethod should it prefer retrieving methods
 *
 * @return the method emitter
 */
MethodEmitter dynamicGetIndex(final Type result, final int flags, final boolean isMethod) {
    debug("dynamic_get_index", peekType(1), "[", peekType(), "]");

    Type resultType = result;
    if (result.isBoolean()) {
        resultType = Type.OBJECT; // INT->OBJECT to avoid another dimension of cross products in the getters. TODO
    }

    Type index = peekType();
    if (index.isObject() || index.isBoolean()) {
        index = Type.OBJECT; //e.g. string->object
        convert(Type.OBJECT);
    }
    popType();

    popType(Type.OBJECT);

    final String signature = Type.getMethodDescriptor(resultType, Type.OBJECT /*e.g STRING->OBJECT*/, index);

    method.visitInvokeDynamicInsn(isMethod ? "dyn:getMethod|getElem|getProp" : "dyn:getElem|getProp|getMethod",
            signature, LINKERBOOTSTRAP, flags);
    pushType(resultType);

    if (result.isBoolean()) {
        convert(Type.BOOLEAN);
    }

    return this;
}
 
Example 14
Source File: FoldConstants.java    From jdk8u_nashorn with GNU General Public License v2.0 4 votes vote down vote up
@Override
protected LiteralNode<?> eval() {
    final Node rhsNode = parent.getExpression();

    if (!(rhsNode instanceof LiteralNode)) {
        return null;
    }

    if (rhsNode instanceof ArrayLiteralNode) {
        return null;
    }

    final LiteralNode<?> rhs = (LiteralNode<?>)rhsNode;
    final Type rhsType = rhs.getType();
    final boolean rhsInteger = rhsType.isInteger() || rhsType.isBoolean();

    LiteralNode<?> literalNode;

    switch (parent.tokenType()) {
    case ADD:
        if (rhsInteger) {
            literalNode = LiteralNode.newInstance(token, finish, rhs.getInt32());
        } else if (rhsType.isLong()) {
            literalNode = LiteralNode.newInstance(token, finish, rhs.getLong());
        } else {
            literalNode = LiteralNode.newInstance(token, finish, rhs.getNumber());
        }
        break;
    case SUB:
        if (rhsInteger && rhs.getInt32() != 0) { // @see test/script/basic/minuszero.js
            literalNode = LiteralNode.newInstance(token, finish, -rhs.getInt32());
        } else if (rhsType.isLong() && rhs.getLong() != 0L) {
            literalNode = LiteralNode.newInstance(token, finish, -rhs.getLong());
        } else {
            literalNode = LiteralNode.newInstance(token, finish, -rhs.getNumber());
        }
        break;
    case NOT:
        literalNode = LiteralNode.newInstance(token, finish, !rhs.getBoolean());
        break;
    case BIT_NOT:
        literalNode = LiteralNode.newInstance(token, finish, ~rhs.getInt32());
        break;
    default:
        return null;
    }

    return literalNode;
}
 
Example 15
Source File: FoldConstants.java    From jdk8u60 with GNU General Public License v2.0 4 votes vote down vote up
@Override
protected LiteralNode<?> eval() {
    final Node rhsNode = parent.getExpression();

    if (!(rhsNode instanceof LiteralNode)) {
        return null;
    }

    if (rhsNode instanceof ArrayLiteralNode) {
        return null;
    }

    final LiteralNode<?> rhs = (LiteralNode<?>)rhsNode;
    final Type rhsType = rhs.getType();
    final boolean rhsInteger = rhsType.isInteger() || rhsType.isBoolean();

    LiteralNode<?> literalNode;

    switch (parent.tokenType()) {
    case ADD:
        if (rhsInteger) {
            literalNode = LiteralNode.newInstance(token, finish, rhs.getInt32());
        } else {
            literalNode = LiteralNode.newInstance(token, finish, rhs.getNumber());
        }
        break;
    case SUB:
        if (rhsInteger && rhs.getInt32() != 0) { // @see test/script/basic/minuszero.js
            literalNode = LiteralNode.newInstance(token, finish, -rhs.getInt32());
        } else {
            literalNode = LiteralNode.newInstance(token, finish, -rhs.getNumber());
        }
        break;
    case NOT:
        literalNode = LiteralNode.newInstance(token, finish, !rhs.getBoolean());
        break;
    case BIT_NOT:
        literalNode = LiteralNode.newInstance(token, finish, ~rhs.getInt32());
        break;
    default:
        return null;
    }

    return literalNode;
}
 
Example 16
Source File: Attr.java    From openjdk-8-source with GNU General Public License v2.0 4 votes vote down vote up
@Override
public Node leaveSwitchNode(final SwitchNode switchNode) {
    Type type = Type.UNKNOWN;

    final List<CaseNode> newCases = new ArrayList<>();
    for (final CaseNode caseNode : switchNode.getCases()) {
        final Node test = caseNode.getTest();

        CaseNode newCaseNode = caseNode;
        if (test != null) {
            if (test instanceof LiteralNode) {
                //go down to integers if we can
                final LiteralNode<?> lit = (LiteralNode<?>)test;
                if (lit.isNumeric() && !(lit.getValue() instanceof Integer)) {
                    if (JSType.isRepresentableAsInt(lit.getNumber())) {
                        newCaseNode = caseNode.setTest((Expression)LiteralNode.newInstance(lit, lit.getInt32()).accept(this));
                    }
                }
            } else {
                // the "all integer" case that CodeGenerator optimizes for currently assumes literals only
                type = Type.OBJECT;
            }

            final Type newCaseType = newCaseNode.getTest().getType();
            if (newCaseType.isBoolean()) {
                type = Type.OBJECT; //booleans and integers aren't assignment compatible
            } else {
                type = Type.widest(type, newCaseType);
            }
        }

        newCases.add(newCaseNode);
    }

    //only optimize for all integers
    if (!type.isInteger()) {
        type = Type.OBJECT;
    }

    switchNode.setTag(newInternal(lc.getCurrentFunction().uniqueName(SWITCH_TAG_PREFIX.symbolName()), type));

    end(switchNode);

    return switchNode.setCases(lc, newCases);
}
 
Example 17
Source File: FoldConstants.java    From openjdk-jdk8u-backup with GNU General Public License v2.0 4 votes vote down vote up
@Override
protected LiteralNode<?> eval() {
    final Node rhsNode = parent.getExpression();

    if (!(rhsNode instanceof LiteralNode)) {
        return null;
    }

    if (rhsNode instanceof ArrayLiteralNode) {
        return null;
    }

    final LiteralNode<?> rhs = (LiteralNode<?>)rhsNode;
    final Type rhsType = rhs.getType();
    final boolean rhsInteger = rhsType.isInteger() || rhsType.isBoolean();

    LiteralNode<?> literalNode;

    switch (parent.tokenType()) {
    case ADD:
        if (rhsInteger) {
            literalNode = LiteralNode.newInstance(token, finish, rhs.getInt32());
        } else if (rhsType.isLong()) {
            literalNode = LiteralNode.newInstance(token, finish, rhs.getLong());
        } else {
            literalNode = LiteralNode.newInstance(token, finish, rhs.getNumber());
        }
        break;
    case SUB:
        if (rhsInteger && rhs.getInt32() != 0) { // @see test/script/basic/minuszero.js
            literalNode = LiteralNode.newInstance(token, finish, -rhs.getInt32());
        } else if (rhsType.isLong() && rhs.getLong() != 0L) {
            literalNode = LiteralNode.newInstance(token, finish, -rhs.getLong());
        } else {
            literalNode = LiteralNode.newInstance(token, finish, -rhs.getNumber());
        }
        break;
    case NOT:
        literalNode = LiteralNode.newInstance(token, finish, !rhs.getBoolean());
        break;
    case BIT_NOT:
        literalNode = LiteralNode.newInstance(token, finish, ~rhs.getInt32());
        break;
    default:
        return null;
    }

    return literalNode;
}
 
Example 18
Source File: FoldConstants.java    From openjdk-jdk9 with GNU General Public License v2.0 4 votes vote down vote up
@Override
protected LiteralNode<?> eval() {
    final Node rhsNode = parent.getExpression();

    if (!(rhsNode instanceof LiteralNode)) {
        return null;
    }

    if (rhsNode instanceof ArrayLiteralNode) {
        return null;
    }

    final LiteralNode<?> rhs = (LiteralNode<?>)rhsNode;
    final Type rhsType = rhs.getType();
    final boolean rhsInteger = rhsType.isInteger() || rhsType.isBoolean();

    LiteralNode<?> literalNode;

    switch (parent.tokenType()) {
    case ADD:
        if (rhsInteger) {
            literalNode = LiteralNode.newInstance(token, finish, rhs.getInt32());
        } else if (rhsType.isLong()) {
            literalNode = LiteralNode.newInstance(token, finish, rhs.getLong());
        } else {
            literalNode = LiteralNode.newInstance(token, finish, rhs.getNumber());
        }
        break;
    case SUB:
        if (rhsInteger && rhs.getInt32() != 0) { // @see test/script/basic/minuszero.js
            literalNode = LiteralNode.newInstance(token, finish, -rhs.getInt32());
        } else if (rhsType.isLong() && rhs.getLong() != 0L) {
            literalNode = LiteralNode.newInstance(token, finish, -rhs.getLong());
        } else {
            literalNode = LiteralNode.newInstance(token, finish, -rhs.getNumber());
        }
        break;
    case NOT:
        literalNode = LiteralNode.newInstance(token, finish, !rhs.getBoolean());
        break;
    case BIT_NOT:
        literalNode = LiteralNode.newInstance(token, finish, ~rhs.getInt32());
        break;
    default:
        return null;
    }

    return literalNode;
}
 
Example 19
Source File: CompiledFunction.java    From openjdk-8 with GNU General Public License v2.0 4 votes vote down vote up
/**
 * Check whether a given method descriptor is compatible with this invocation.
 * It is compatible if the types are narrower than the invocation type so that
 * a semantically equivalent linkage can be performed.
 *
 * @param mt type to check against
 * @return true if types are compatible
 */
boolean typeCompatible(final MethodType mt) {
    final int wantedParamCount   = mt.parameterCount();
    final int existingParamCount = type.parameterCount();

    //if we are not examining a varargs type, the number of parameters must be the same
    if (wantedParamCount != existingParamCount && !isVarArgsType(mt)) {
        return false;
    }

    //we only go as far as the shortest array. the only chance to make this work if
    //parameters lengths do not match is if our type ends with a varargs argument.
    //then every trailing parameter in the given callsite can be folded into it, making
    //us compatible (albeit slower than a direct specialization)
    final int lastParamIndex = Math.min(wantedParamCount, existingParamCount);
    for (int i = 0; i < lastParamIndex; i++) {
        final Type w = Type.typeFor(mt.parameterType(i));
        final Type e = Type.typeFor(type.parameterType(i));

        //don't specialize on booleans, we have the "true" vs int 1 ambiguity in resolution
        //we also currently don't support boolean as a javascript function callsite type.
        //it will always box.
        if (w.isBoolean()) {
            return false;
        }

        //This callsite type has a vararg here. it will swallow all remaining args.
        //for consistency, check that it's the last argument
        if (e.isArray()) {
            return true;
        }

        //Our arguments must be at least as wide as the wanted one, if not wider
        if (Type.widest(w, e) != e) {
            //e.g. this invocation takes double and callsite says "object". reject. won't fit
            //but if invocation takes a double and callsite says "int" or "long" or "double", that's fine
            return false;
        }
    }

    return true; // anything goes for return type, take the convenient one and it will be upcasted thru dynalink magic.
}
 
Example 20
Source File: CompiledFunction.java    From openjdk-8-source with GNU General Public License v2.0 4 votes vote down vote up
/**
 * Check whether a given method descriptor is compatible with this invocation.
 * It is compatible if the types are narrower than the invocation type so that
 * a semantically equivalent linkage can be performed.
 *
 * @param mt type to check against
 * @return true if types are compatible
 */
boolean typeCompatible(final MethodType mt) {
    final int wantedParamCount   = mt.parameterCount();
    final int existingParamCount = type.parameterCount();

    //if we are not examining a varargs type, the number of parameters must be the same
    if (wantedParamCount != existingParamCount && !isVarArgsType(mt)) {
        return false;
    }

    //we only go as far as the shortest array. the only chance to make this work if
    //parameters lengths do not match is if our type ends with a varargs argument.
    //then every trailing parameter in the given callsite can be folded into it, making
    //us compatible (albeit slower than a direct specialization)
    final int lastParamIndex = Math.min(wantedParamCount, existingParamCount);
    for (int i = 0; i < lastParamIndex; i++) {
        final Type w = Type.typeFor(mt.parameterType(i));
        final Type e = Type.typeFor(type.parameterType(i));

        //don't specialize on booleans, we have the "true" vs int 1 ambiguity in resolution
        //we also currently don't support boolean as a javascript function callsite type.
        //it will always box.
        if (w.isBoolean()) {
            return false;
        }

        //This callsite type has a vararg here. it will swallow all remaining args.
        //for consistency, check that it's the last argument
        if (e.isArray()) {
            return true;
        }

        //Our arguments must be at least as wide as the wanted one, if not wider
        if (Type.widest(w, e) != e) {
            //e.g. this invocation takes double and callsite says "object". reject. won't fit
            //but if invocation takes a double and callsite says "int" or "long" or "double", that's fine
            return false;
        }
    }

    return true; // anything goes for return type, take the convenient one and it will be upcasted thru dynalink magic.
}