mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-21 03:24:38 +02:00
6829189: Java programming with JSR 292 needs language support
Language changes documented in http://wikis.sun.com/display/mlvm/ProjectCoinProposal Reviewed-by: jjg, darcy, mcimadamore
This commit is contained in:
parent
21694f8b3f
commit
5ba10ad9ad
25 changed files with 881 additions and 13 deletions
|
@ -226,7 +226,7 @@ public enum Opcode {
|
||||||
INVOKESPECIAL(0xb7, CPREF_W),
|
INVOKESPECIAL(0xb7, CPREF_W),
|
||||||
INVOKESTATIC(0xb8, CPREF_W),
|
INVOKESTATIC(0xb8, CPREF_W),
|
||||||
INVOKEINTERFACE(0xb9, CPREF_W_UBYTE_ZERO),
|
INVOKEINTERFACE(0xb9, CPREF_W_UBYTE_ZERO),
|
||||||
// unused 0xba
|
INVOKEDYNAMIC(0xba, CPREF_W_UBYTE_ZERO),
|
||||||
NEW(0xbb, CPREF_W),
|
NEW(0xbb, CPREF_W),
|
||||||
NEWARRAY(0xbc, ATYPE),
|
NEWARRAY(0xbc, ATYPE),
|
||||||
ANEWARRAY(0xbd, CPREF_W),
|
ANEWARRAY(0xbd, CPREF_W),
|
||||||
|
|
|
@ -119,6 +119,8 @@ public class Symtab {
|
||||||
public final Type stringBuilderType;
|
public final Type stringBuilderType;
|
||||||
public final Type cloneableType;
|
public final Type cloneableType;
|
||||||
public final Type serializableType;
|
public final Type serializableType;
|
||||||
|
public final Type methodHandleType;
|
||||||
|
public final Type invokeDynamicType;
|
||||||
public final Type throwableType;
|
public final Type throwableType;
|
||||||
public final Type errorType;
|
public final Type errorType;
|
||||||
public final Type illegalArgumentExceptionType;
|
public final Type illegalArgumentExceptionType;
|
||||||
|
@ -289,6 +291,24 @@ public class Symtab {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void synthesizeMHTypeIfMissing(final Type type) {
|
||||||
|
final Completer completer = type.tsym.completer;
|
||||||
|
if (completer != null) {
|
||||||
|
type.tsym.completer = new Completer() {
|
||||||
|
public void complete(Symbol sym) throws CompletionFailure {
|
||||||
|
try {
|
||||||
|
completer.complete(sym);
|
||||||
|
} catch (CompletionFailure e) {
|
||||||
|
sym.flags_field |= (PUBLIC | ABSTRACT);
|
||||||
|
((ClassType) sym.type).supertype_field = objectType;
|
||||||
|
// do not bother to create MH.type if not visibly declared
|
||||||
|
// this sym just accumulates invoke(...) methods
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void synthesizeBoxTypeIfMissing(final Type type) {
|
public void synthesizeBoxTypeIfMissing(final Type type) {
|
||||||
ClassSymbol sym = reader.enterClass(boxedName[type.tag]);
|
ClassSymbol sym = reader.enterClass(boxedName[type.tag]);
|
||||||
final Completer completer = sym.completer;
|
final Completer completer = sym.completer;
|
||||||
|
@ -405,6 +425,8 @@ public class Symtab {
|
||||||
cloneableType = enterClass("java.lang.Cloneable");
|
cloneableType = enterClass("java.lang.Cloneable");
|
||||||
throwableType = enterClass("java.lang.Throwable");
|
throwableType = enterClass("java.lang.Throwable");
|
||||||
serializableType = enterClass("java.io.Serializable");
|
serializableType = enterClass("java.io.Serializable");
|
||||||
|
methodHandleType = enterClass("java.dyn.MethodHandle");
|
||||||
|
invokeDynamicType = enterClass("java.dyn.InvokeDynamic");
|
||||||
errorType = enterClass("java.lang.Error");
|
errorType = enterClass("java.lang.Error");
|
||||||
illegalArgumentExceptionType = enterClass("java.lang.IllegalArgumentException");
|
illegalArgumentExceptionType = enterClass("java.lang.IllegalArgumentException");
|
||||||
exceptionType = enterClass("java.lang.Exception");
|
exceptionType = enterClass("java.lang.Exception");
|
||||||
|
@ -441,6 +463,8 @@ public class Symtab {
|
||||||
|
|
||||||
synthesizeEmptyInterfaceIfMissing(cloneableType);
|
synthesizeEmptyInterfaceIfMissing(cloneableType);
|
||||||
synthesizeEmptyInterfaceIfMissing(serializableType);
|
synthesizeEmptyInterfaceIfMissing(serializableType);
|
||||||
|
synthesizeMHTypeIfMissing(methodHandleType);
|
||||||
|
synthesizeMHTypeIfMissing(invokeDynamicType);
|
||||||
synthesizeBoxTypeIfMissing(doubleType);
|
synthesizeBoxTypeIfMissing(doubleType);
|
||||||
synthesizeBoxTypeIfMissing(floatType);
|
synthesizeBoxTypeIfMissing(floatType);
|
||||||
|
|
||||||
|
|
|
@ -118,6 +118,7 @@ public class Attr extends JCTree.Visitor {
|
||||||
relax = (options.get("-retrofit") != null ||
|
relax = (options.get("-retrofit") != null ||
|
||||||
options.get("-relax") != null);
|
options.get("-relax") != null);
|
||||||
useBeforeDeclarationWarning = options.get("useBeforeDeclarationWarning") != null;
|
useBeforeDeclarationWarning = options.get("useBeforeDeclarationWarning") != null;
|
||||||
|
allowInvokedynamic = options.get("invokedynamic") != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Switch: relax some constraints for retrofit mode.
|
/** Switch: relax some constraints for retrofit mode.
|
||||||
|
@ -149,6 +150,10 @@ public class Attr extends JCTree.Visitor {
|
||||||
*/
|
*/
|
||||||
boolean allowAnonOuterThis;
|
boolean allowAnonOuterThis;
|
||||||
|
|
||||||
|
/** Switch: allow invokedynamic syntax
|
||||||
|
*/
|
||||||
|
boolean allowInvokedynamic;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Switch: warn about use of variable before declaration?
|
* Switch: warn about use of variable before declaration?
|
||||||
* RFE: 6425594
|
* RFE: 6425594
|
||||||
|
@ -438,14 +443,22 @@ public class Attr extends JCTree.Visitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Attribute a type argument list, returning a list of types.
|
/** Attribute a type argument list, returning a list of types.
|
||||||
|
* Caller is responsible for calling checkRefTypes.
|
||||||
*/
|
*/
|
||||||
List<Type> attribTypes(List<JCExpression> trees, Env<AttrContext> env) {
|
List<Type> attribAnyTypes(List<JCExpression> trees, Env<AttrContext> env) {
|
||||||
ListBuffer<Type> argtypes = new ListBuffer<Type>();
|
ListBuffer<Type> argtypes = new ListBuffer<Type>();
|
||||||
for (List<JCExpression> l = trees; l.nonEmpty(); l = l.tail)
|
for (List<JCExpression> l = trees; l.nonEmpty(); l = l.tail)
|
||||||
argtypes.append(chk.checkRefType(l.head.pos(), attribType(l.head, env)));
|
argtypes.append(attribType(l.head, env));
|
||||||
return argtypes.toList();
|
return argtypes.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Attribute a type argument list, returning a list of types.
|
||||||
|
* Check that all the types are references.
|
||||||
|
*/
|
||||||
|
List<Type> attribTypes(List<JCExpression> trees, Env<AttrContext> env) {
|
||||||
|
List<Type> types = attribAnyTypes(trees, env);
|
||||||
|
return chk.checkRefTypes(trees, types);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attribute type variables (of generic classes or methods).
|
* Attribute type variables (of generic classes or methods).
|
||||||
|
@ -1194,6 +1207,7 @@ public class Attr extends JCTree.Visitor {
|
||||||
|
|
||||||
// The types of the actual method type arguments.
|
// The types of the actual method type arguments.
|
||||||
List<Type> typeargtypes = null;
|
List<Type> typeargtypes = null;
|
||||||
|
boolean typeargtypesNonRefOK = false;
|
||||||
|
|
||||||
Name methName = TreeInfo.name(tree.meth);
|
Name methName = TreeInfo.name(tree.meth);
|
||||||
|
|
||||||
|
@ -1281,7 +1295,7 @@ public class Attr extends JCTree.Visitor {
|
||||||
// Otherwise, we are seeing a regular method call.
|
// Otherwise, we are seeing a regular method call.
|
||||||
// Attribute the arguments, yielding list of argument types, ...
|
// Attribute the arguments, yielding list of argument types, ...
|
||||||
argtypes = attribArgs(tree.args, localEnv);
|
argtypes = attribArgs(tree.args, localEnv);
|
||||||
typeargtypes = attribTypes(tree.typeargs, localEnv);
|
typeargtypes = attribAnyTypes(tree.typeargs, localEnv);
|
||||||
|
|
||||||
// ... and attribute the method using as a prototype a methodtype
|
// ... and attribute the method using as a prototype a methodtype
|
||||||
// whose formal argument types is exactly the list of actual
|
// whose formal argument types is exactly the list of actual
|
||||||
|
@ -1318,6 +1332,20 @@ public class Attr extends JCTree.Visitor {
|
||||||
restype.tsym);
|
restype.tsym);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// as a special case, MethodHandle.<T>invoke(abc) and InvokeDynamic.<T>foo(abc)
|
||||||
|
// has type <T>, and T can be a primitive type.
|
||||||
|
if (tree.meth.getTag() == JCTree.SELECT && !typeargtypes.isEmpty()) {
|
||||||
|
Type selt = ((JCFieldAccess) tree.meth).selected.type;
|
||||||
|
if ((selt == syms.methodHandleType && methName == names.invoke) || selt == syms.invokeDynamicType) {
|
||||||
|
assert types.isSameType(restype, typeargtypes.head) : mtype;
|
||||||
|
typeargtypesNonRefOK = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!typeargtypesNonRefOK) {
|
||||||
|
chk.checkRefTypes(tree.typeargs, typeargtypes);
|
||||||
|
}
|
||||||
|
|
||||||
// Check that value of resulting type is admissible in the
|
// Check that value of resulting type is admissible in the
|
||||||
// current context. Also, capture the return type
|
// current context. Also, capture the return type
|
||||||
result = check(tree, capture(restype), VAL, pkind, pt);
|
result = check(tree, capture(restype), VAL, pkind, pt);
|
||||||
|
|
|
@ -207,6 +207,12 @@ public class Check {
|
||||||
* @param found The type that was found.
|
* @param found The type that was found.
|
||||||
*/
|
*/
|
||||||
Type typeTagError(DiagnosticPosition pos, Object required, Object found) {
|
Type typeTagError(DiagnosticPosition pos, Object required, Object found) {
|
||||||
|
// this error used to be raised by the parser,
|
||||||
|
// but has been delayed to this point:
|
||||||
|
if (found instanceof Type && ((Type)found).tag == VOID) {
|
||||||
|
log.error(pos, "illegal.start.of.type");
|
||||||
|
return syms.errType;
|
||||||
|
}
|
||||||
log.error(pos, "type.found.req", found, required);
|
log.error(pos, "type.found.req", found, required);
|
||||||
return types.createErrorType(found instanceof Type ? (Type)found : syms.errType);
|
return types.createErrorType(found instanceof Type ? (Type)found : syms.errType);
|
||||||
}
|
}
|
||||||
|
@ -547,6 +553,20 @@ public class Check {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Check that each type is a reference type, i.e. a class, interface or array type
|
||||||
|
* or a type variable.
|
||||||
|
* @param trees Original trees, used for error reporting.
|
||||||
|
* @param types The types to be checked.
|
||||||
|
*/
|
||||||
|
List<Type> checkRefTypes(List<JCExpression> trees, List<Type> types) {
|
||||||
|
List<JCExpression> tl = trees;
|
||||||
|
for (List<Type> l = types; l.nonEmpty(); l = l.tail) {
|
||||||
|
l.head = checkRefType(tl.head.pos(), l.head);
|
||||||
|
tl = tl.tail;
|
||||||
|
}
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
/** Check that type is a null or reference type.
|
/** Check that type is a null or reference type.
|
||||||
* @param pos Position to be used for error reporting.
|
* @param pos Position to be used for error reporting.
|
||||||
* @param t The type to be checked.
|
* @param t The type to be checked.
|
||||||
|
|
|
@ -67,6 +67,7 @@ public class Resolve {
|
||||||
JCDiagnostic.Factory diags;
|
JCDiagnostic.Factory diags;
|
||||||
public final boolean boxingEnabled; // = source.allowBoxing();
|
public final boolean boxingEnabled; // = source.allowBoxing();
|
||||||
public final boolean varargsEnabled; // = source.allowVarargs();
|
public final boolean varargsEnabled; // = source.allowVarargs();
|
||||||
|
public final boolean allowInvokedynamic; // = options.get("invokedynamic");
|
||||||
private final boolean debugResolve;
|
private final boolean debugResolve;
|
||||||
|
|
||||||
public static Resolve instance(Context context) {
|
public static Resolve instance(Context context) {
|
||||||
|
@ -104,6 +105,7 @@ public class Resolve {
|
||||||
varargsEnabled = source.allowVarargs();
|
varargsEnabled = source.allowVarargs();
|
||||||
Options options = Options.instance(context);
|
Options options = Options.instance(context);
|
||||||
debugResolve = options.get("debugresolve") != null;
|
debugResolve = options.get("debugresolve") != null;
|
||||||
|
allowInvokedynamic = options.get("invokedynamic") != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** error symbols, which are returned when resolution fails
|
/** error symbols, which are returned when resolution fails
|
||||||
|
@ -881,6 +883,79 @@ public class Resolve {
|
||||||
return bestSoFar;
|
return bestSoFar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Find or create an implicit method of exactly the given type (after erasure).
|
||||||
|
* Searches in a side table, not the main scope of the site.
|
||||||
|
* This emulates the lookup process required by JSR 292 in JVM.
|
||||||
|
* @param env The current environment.
|
||||||
|
* @param site The original type from where the selection
|
||||||
|
* takes place.
|
||||||
|
* @param name The method's name.
|
||||||
|
* @param argtypes The method's value arguments.
|
||||||
|
* @param typeargtypes The method's type arguments
|
||||||
|
*/
|
||||||
|
Symbol findImplicitMethod(Env<AttrContext> env,
|
||||||
|
Type site,
|
||||||
|
Name name,
|
||||||
|
List<Type> argtypes,
|
||||||
|
List<Type> typeargtypes) {
|
||||||
|
assert allowInvokedynamic;
|
||||||
|
assert site == syms.invokeDynamicType || (site == syms.methodHandleType && name == names.invoke);
|
||||||
|
ClassSymbol c = (ClassSymbol) site.tsym;
|
||||||
|
Scope implicit = c.members().next;
|
||||||
|
if (implicit == null) {
|
||||||
|
c.members().next = implicit = new Scope(c);
|
||||||
|
}
|
||||||
|
Type restype;
|
||||||
|
if (typeargtypes.isEmpty()) {
|
||||||
|
restype = syms.objectType;
|
||||||
|
} else {
|
||||||
|
restype = typeargtypes.head;
|
||||||
|
if (!typeargtypes.tail.isEmpty())
|
||||||
|
return methodNotFound;
|
||||||
|
}
|
||||||
|
List<Type> paramtypes = Type.map(argtypes, implicitArgType);
|
||||||
|
MethodType mtype = new MethodType(paramtypes,
|
||||||
|
restype,
|
||||||
|
List.<Type>nil(),
|
||||||
|
syms.methodClass);
|
||||||
|
int flags = PUBLIC | ABSTRACT;
|
||||||
|
if (site == syms.invokeDynamicType) flags |= STATIC;
|
||||||
|
Symbol m = null;
|
||||||
|
for (Scope.Entry e = implicit.lookup(name);
|
||||||
|
e.scope != null;
|
||||||
|
e = e.next()) {
|
||||||
|
Symbol sym = e.sym;
|
||||||
|
assert sym.kind == MTH;
|
||||||
|
if (types.isSameType(mtype, sym.type)
|
||||||
|
&& (sym.flags() & STATIC) == (flags & STATIC)) {
|
||||||
|
m = sym;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (m == null) {
|
||||||
|
// create the desired method
|
||||||
|
m = new MethodSymbol(flags, name, mtype, c);
|
||||||
|
implicit.enter(m);
|
||||||
|
}
|
||||||
|
assert argumentsAcceptable(argtypes, types.memberType(site, m).getParameterTypes(),
|
||||||
|
false, false, Warner.noWarnings);
|
||||||
|
assert null != instantiate(env, site, m, argtypes, typeargtypes, false, false, Warner.noWarnings);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
//where
|
||||||
|
Mapping implicitArgType = new Mapping ("implicitArgType") {
|
||||||
|
public Type apply(Type t) { return implicitArgType(t); }
|
||||||
|
};
|
||||||
|
Type implicitArgType(Type argType) {
|
||||||
|
argType = types.erasure(argType);
|
||||||
|
if (argType.tag == BOT)
|
||||||
|
// nulls type as the marker type Null (which has no instances)
|
||||||
|
// TO DO: figure out how to access java.lang.Null safely, else throw nice error
|
||||||
|
//argType = types.boxedClass(syms.botType).type;
|
||||||
|
argType = types.boxedClass(syms.voidType).type; // REMOVE
|
||||||
|
return argType;
|
||||||
|
}
|
||||||
|
|
||||||
/** Load toplevel or member class with given fully qualified name and
|
/** Load toplevel or member class with given fully qualified name and
|
||||||
* verify that it is accessible.
|
* verify that it is accessible.
|
||||||
* @param env The current environment.
|
* @param env The current environment.
|
||||||
|
@ -1265,6 +1340,14 @@ public class Resolve {
|
||||||
methodResolutionCache.put(steps.head, sym);
|
methodResolutionCache.put(steps.head, sym);
|
||||||
steps = steps.tail;
|
steps = steps.tail;
|
||||||
}
|
}
|
||||||
|
if (sym.kind >= AMBIGUOUS &&
|
||||||
|
allowInvokedynamic &&
|
||||||
|
(site == syms.invokeDynamicType ||
|
||||||
|
site == syms.methodHandleType && name == names.invoke)) {
|
||||||
|
// lookup failed; supply an exactly-typed implicit method
|
||||||
|
sym = findImplicitMethod(env, site, name, argtypes, typeargtypes);
|
||||||
|
env.info.varArgs = false;
|
||||||
|
}
|
||||||
if (sym.kind >= AMBIGUOUS) {//if nothing is found return the 'first' error
|
if (sym.kind >= AMBIGUOUS) {//if nothing is found return the 'first' error
|
||||||
MethodResolutionPhase errPhase =
|
MethodResolutionPhase errPhase =
|
||||||
firstErroneousResolutionPhase();
|
firstErroneousResolutionPhase();
|
||||||
|
|
|
@ -225,7 +225,7 @@ public interface ByteCodes {
|
||||||
invokespecial = 183,
|
invokespecial = 183,
|
||||||
invokestatic = 184,
|
invokestatic = 184,
|
||||||
invokeinterface = 185,
|
invokeinterface = 185,
|
||||||
// ___unused___ = 186,
|
invokedynamic = 186,
|
||||||
new_ = 187,
|
new_ = 187,
|
||||||
newarray = 188,
|
newarray = 188,
|
||||||
anewarray = 189,
|
anewarray = 189,
|
||||||
|
|
|
@ -2309,6 +2309,7 @@ public class ClassReader implements Completer {
|
||||||
String binaryName = fileManager.inferBinaryName(currentLoc, fo);
|
String binaryName = fileManager.inferBinaryName(currentLoc, fo);
|
||||||
String simpleName = binaryName.substring(binaryName.lastIndexOf(".") + 1);
|
String simpleName = binaryName.substring(binaryName.lastIndexOf(".") + 1);
|
||||||
if (SourceVersion.isIdentifier(simpleName) ||
|
if (SourceVersion.isIdentifier(simpleName) ||
|
||||||
|
fo.getKind() == JavaFileObject.Kind.CLASS ||
|
||||||
simpleName.equals("package-info"))
|
simpleName.equals("package-info"))
|
||||||
includeClassFile(p, fo);
|
includeClassFile(p, fo);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -456,6 +456,19 @@ public class Code {
|
||||||
state.push(mtype.getReturnType());
|
state.push(mtype.getReturnType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Emit an invokedynamic instruction.
|
||||||
|
*/
|
||||||
|
public void emitInvokedynamic(int desc, Type mtype) {
|
||||||
|
// N.B. this format is under consideration by the JSR 292 EG
|
||||||
|
int argsize = width(mtype.getParameterTypes());
|
||||||
|
emitop(invokedynamic);
|
||||||
|
if (!alive) return;
|
||||||
|
emit2(desc);
|
||||||
|
emit2(0);
|
||||||
|
state.pop(argsize);
|
||||||
|
state.push(mtype.getReturnType());
|
||||||
|
}
|
||||||
|
|
||||||
/** Emit an opcode with no operand field.
|
/** Emit an opcode with no operand field.
|
||||||
*/
|
*/
|
||||||
public void emitop0(int op) {
|
public void emitop0(int op) {
|
||||||
|
@ -2156,7 +2169,7 @@ public class Code {
|
||||||
mnem[invokespecial] = "invokespecial";
|
mnem[invokespecial] = "invokespecial";
|
||||||
mnem[invokestatic] = "invokestatic";
|
mnem[invokestatic] = "invokestatic";
|
||||||
mnem[invokeinterface] = "invokeinterface";
|
mnem[invokeinterface] = "invokeinterface";
|
||||||
// mnem[___unused___] = "___unused___";
|
mnem[invokedynamic] = "invokedynamic";
|
||||||
mnem[new_] = "new_";
|
mnem[new_] = "new_";
|
||||||
mnem[newarray] = "newarray";
|
mnem[newarray] = "newarray";
|
||||||
mnem[anewarray] = "anewarray";
|
mnem[anewarray] = "anewarray";
|
||||||
|
|
|
@ -119,6 +119,7 @@ public class Gen extends JCTree.Visitor {
|
||||||
: options.get("-g:vars") != null;
|
: options.get("-g:vars") != null;
|
||||||
genCrt = options.get("-Xjcov") != null;
|
genCrt = options.get("-Xjcov") != null;
|
||||||
debugCode = options.get("debugcode") != null;
|
debugCode = options.get("debugcode") != null;
|
||||||
|
allowInvokedynamic = options.get("invokedynamic") != null;
|
||||||
|
|
||||||
generateIproxies =
|
generateIproxies =
|
||||||
target.requiresIproxy() ||
|
target.requiresIproxy() ||
|
||||||
|
@ -155,6 +156,7 @@ public class Gen extends JCTree.Visitor {
|
||||||
private final boolean varDebugInfo;
|
private final boolean varDebugInfo;
|
||||||
private final boolean genCrt;
|
private final boolean genCrt;
|
||||||
private final boolean debugCode;
|
private final boolean debugCode;
|
||||||
|
private final boolean allowInvokedynamic;
|
||||||
|
|
||||||
/** Default limit of (approximate) size of finalizer to inline.
|
/** Default limit of (approximate) size of finalizer to inline.
|
||||||
* Zero means always use jsr. 100 or greater means never use
|
* Zero means always use jsr. 100 or greater means never use
|
||||||
|
@ -2140,6 +2142,9 @@ public class Gen extends JCTree.Visitor {
|
||||||
}
|
}
|
||||||
result = items.
|
result = items.
|
||||||
makeImmediateItem(sym.type, ((VarSymbol) sym).getConstValue());
|
makeImmediateItem(sym.type, ((VarSymbol) sym).getConstValue());
|
||||||
|
} else if (allowInvokedynamic && sym.kind == MTH && ssym == syms.invokeDynamicType.tsym) {
|
||||||
|
base.drop();
|
||||||
|
result = items.makeDynamicItem(sym);
|
||||||
} else {
|
} else {
|
||||||
if (!accessSuper)
|
if (!accessSuper)
|
||||||
sym = binaryQualifier(sym, tree.selected.type);
|
sym = binaryQualifier(sym, tree.selected.type);
|
||||||
|
|
|
@ -139,6 +139,13 @@ public class Items {
|
||||||
return new StaticItem(member);
|
return new StaticItem(member);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Make an item representing a dynamically invoked method.
|
||||||
|
* @param member The represented symbol.
|
||||||
|
*/
|
||||||
|
Item makeDynamicItem(Symbol member) {
|
||||||
|
return new DynamicItem(member);
|
||||||
|
}
|
||||||
|
|
||||||
/** Make an item representing an instance variable or method.
|
/** Make an item representing an instance variable or method.
|
||||||
* @param member The represented symbol.
|
* @param member The represented symbol.
|
||||||
* @param nonvirtual Is the reference not virtual? (true for constructors
|
* @param nonvirtual Is the reference not virtual? (true for constructors
|
||||||
|
@ -457,6 +464,38 @@ public class Items {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** An item representing a dynamic call site.
|
||||||
|
*/
|
||||||
|
class DynamicItem extends StaticItem {
|
||||||
|
DynamicItem(Symbol member) {
|
||||||
|
super(member);
|
||||||
|
assert member.owner == syms.invokeDynamicType.tsym;
|
||||||
|
}
|
||||||
|
|
||||||
|
Item load() {
|
||||||
|
assert false;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void store() {
|
||||||
|
assert false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Item invoke() {
|
||||||
|
// assert target.hasNativeInvokeDynamic();
|
||||||
|
MethodType mtype = (MethodType)member.erasure(types);
|
||||||
|
int rescode = Code.typecode(mtype.restype);
|
||||||
|
ClassFile.NameAndType descr = new ClassFile.NameAndType(member.name, mtype);
|
||||||
|
code.emitInvokedynamic(pool.put(descr), mtype);
|
||||||
|
return stackItem[rescode];
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return "dynamic(" + member + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** An item representing an instance variable or method.
|
/** An item representing an instance variable or method.
|
||||||
*/
|
*/
|
||||||
class MemberItem extends Item {
|
class MemberItem extends Item {
|
||||||
|
|
|
@ -253,6 +253,12 @@ public enum Target {
|
||||||
return compareTo(JDK1_5) >= 0;
|
return compareTo(JDK1_5) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Does the VM support an invokedynamic instruction?
|
||||||
|
*/
|
||||||
|
public boolean hasInvokedynamic() {
|
||||||
|
return compareTo(JDK1_7) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
/** Although we may not have support for class literals, should we
|
/** Although we may not have support for class literals, should we
|
||||||
* avoid initializing the class that the literal refers to?
|
* avoid initializing the class that the literal refers to?
|
||||||
* See 4468823
|
* See 4468823
|
||||||
|
|
|
@ -268,14 +268,19 @@ public class Main {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
options.put("-target", source.requiredTarget().name);
|
target = source.requiredTarget();
|
||||||
|
options.put("-target", target.name);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (targetString == null && !source.allowGenerics()) {
|
if (targetString == null && !source.allowGenerics()) {
|
||||||
options.put("-target", Target.JDK1_4.name);
|
target = Target.JDK1_4;
|
||||||
|
options.put("-target", target.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (target.hasInvokedynamic()) {
|
||||||
|
options.put("invokedynamic", "invokedynamic");
|
||||||
|
}
|
||||||
return filenames.toList();
|
return filenames.toList();
|
||||||
}
|
}
|
||||||
// where
|
// where
|
||||||
|
|
|
@ -1034,7 +1034,13 @@ public class JavacParser implements Parser {
|
||||||
return illegal(pos);
|
return illegal(pos);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return illegal();
|
// Support the corner case of myMethodHandle.<void>invoke() by passing
|
||||||
|
// a void type (like other primitive types) to the next phase.
|
||||||
|
// The error will be reported in Attr.attribTypes or Attr.visitApply.
|
||||||
|
JCPrimitiveTypeTree ti = to(F.at(pos).TypeIdent(TypeTags.VOID));
|
||||||
|
S.nextToken();
|
||||||
|
return ti;
|
||||||
|
//return illegal();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -317,7 +317,7 @@ public class Scanner implements Lexer {
|
||||||
|
|
||||||
/** Read next character in character or string literal and copy into sbuf.
|
/** Read next character in character or string literal and copy into sbuf.
|
||||||
*/
|
*/
|
||||||
private void scanLitChar() {
|
private void scanLitChar(boolean forBytecodeName) {
|
||||||
if (ch == '\\') {
|
if (ch == '\\') {
|
||||||
if (buf[bp+1] == '\\' && unicodeConversionBp != bp) {
|
if (buf[bp+1] == '\\' && unicodeConversionBp != bp) {
|
||||||
bp++;
|
bp++;
|
||||||
|
@ -357,6 +357,18 @@ public class Scanner implements Lexer {
|
||||||
putChar('\"'); scanChar(); break;
|
putChar('\"'); scanChar(); break;
|
||||||
case '\\':
|
case '\\':
|
||||||
putChar('\\'); scanChar(); break;
|
putChar('\\'); scanChar(); break;
|
||||||
|
case '|': case ',': case '?': case '%':
|
||||||
|
case '^': case '_': case '{': case '}':
|
||||||
|
case '!': case '-': case '=':
|
||||||
|
if (forBytecodeName) {
|
||||||
|
// Accept escape sequences for dangerous bytecode chars.
|
||||||
|
// This is illegal in normal Java string or character literals.
|
||||||
|
// Note that the escape sequence itself is passed through.
|
||||||
|
putChar('\\'); putChar(ch); scanChar();
|
||||||
|
} else {
|
||||||
|
lexError(bp, "illegal.esc.char");
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
lexError(bp, "illegal.esc.char");
|
lexError(bp, "illegal.esc.char");
|
||||||
}
|
}
|
||||||
|
@ -365,6 +377,24 @@ public class Scanner implements Lexer {
|
||||||
putChar(ch); scanChar();
|
putChar(ch); scanChar();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private void scanLitChar() {
|
||||||
|
scanLitChar(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Read next character in an exotic name #"foo"
|
||||||
|
*/
|
||||||
|
private void scanBytecodeNameChar() {
|
||||||
|
switch (ch) {
|
||||||
|
// reject any "dangerous" char which is illegal somewhere in the JVM spec
|
||||||
|
// cf. http://blogs.sun.com/jrose/entry/symbolic_freedom_in_the_vm
|
||||||
|
case '/': case '.': case ';': // illegal everywhere
|
||||||
|
case '<': case '>': // illegal in methods, dangerous in classes
|
||||||
|
case '[': // illegal in classes
|
||||||
|
lexError(bp, "illegal.bytecode.ident.char", String.valueOf((int)ch));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
scanLitChar(true);
|
||||||
|
}
|
||||||
|
|
||||||
/** Read fractional part of hexadecimal floating point number.
|
/** Read fractional part of hexadecimal floating point number.
|
||||||
*/
|
*/
|
||||||
|
@ -915,6 +945,26 @@ public class Scanner implements Lexer {
|
||||||
lexError(pos, "unclosed.str.lit");
|
lexError(pos, "unclosed.str.lit");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
case '#':
|
||||||
|
scanChar();
|
||||||
|
if (ch == '\"') {
|
||||||
|
scanChar();
|
||||||
|
if (ch == '\"')
|
||||||
|
lexError(pos, "empty.bytecode.ident");
|
||||||
|
while (ch != '\"' && ch != CR && ch != LF && bp < buflen) {
|
||||||
|
scanBytecodeNameChar();
|
||||||
|
}
|
||||||
|
if (ch == '\"') {
|
||||||
|
name = names.fromChars(sbuf, 0, sp);
|
||||||
|
token = IDENTIFIER; // even if #"int" or #"do"
|
||||||
|
scanChar();
|
||||||
|
} else {
|
||||||
|
lexError(pos, "unclosed.bytecode.ident");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lexError("illegal.char", String.valueOf((int)'#'));
|
||||||
|
}
|
||||||
|
return;
|
||||||
default:
|
default:
|
||||||
if (isSpecial(ch)) {
|
if (isSpecial(ch)) {
|
||||||
scanOperator();
|
scanOperator();
|
||||||
|
|
|
@ -144,6 +144,8 @@ compiler.err.duplicate.default.label=\
|
||||||
|
|
||||||
compiler.err.else.without.if=\
|
compiler.err.else.without.if=\
|
||||||
''else'' without ''if''
|
''else'' without ''if''
|
||||||
|
compiler.err.empty.bytecode.ident=\
|
||||||
|
empty bytecode identifier
|
||||||
compiler.err.empty.char.lit=\
|
compiler.err.empty.char.lit=\
|
||||||
empty character literal
|
empty character literal
|
||||||
compiler.err.encl.class.required=\
|
compiler.err.encl.class.required=\
|
||||||
|
@ -186,6 +188,8 @@ compiler.err.generic.throwable=\
|
||||||
|
|
||||||
compiler.err.icls.cant.have.static.decl=\
|
compiler.err.icls.cant.have.static.decl=\
|
||||||
inner classes cannot have static declarations
|
inner classes cannot have static declarations
|
||||||
|
compiler.err.illegal.bytecode.ident.char=\
|
||||||
|
illegal bytecode identifier character: \\{0}
|
||||||
compiler.err.illegal.char=\
|
compiler.err.illegal.char=\
|
||||||
illegal character: \\{0}
|
illegal character: \\{0}
|
||||||
compiler.err.illegal.char.for.encoding=\
|
compiler.err.illegal.char.for.encoding=\
|
||||||
|
@ -445,6 +449,8 @@ compiler.err.type.var.more.than.once.in.result=\
|
||||||
compiler.err.types.incompatible.diff.ret=\
|
compiler.err.types.incompatible.diff.ret=\
|
||||||
types {0} and {1} are incompatible; both define {2}, but with unrelated return types
|
types {0} and {1} are incompatible; both define {2}, but with unrelated return types
|
||||||
|
|
||||||
|
compiler.err.unclosed.bytecode.ident=\
|
||||||
|
unclosed bytecode identifier
|
||||||
compiler.err.unclosed.char.lit=\
|
compiler.err.unclosed.char.lit=\
|
||||||
unclosed character literal
|
unclosed character literal
|
||||||
compiler.err.unclosed.comment=\
|
compiler.err.unclosed.comment=\
|
||||||
|
|
|
@ -73,6 +73,8 @@ public class Names {
|
||||||
public final Name java_io_Serializable;
|
public final Name java_io_Serializable;
|
||||||
public final Name serialVersionUID;
|
public final Name serialVersionUID;
|
||||||
public final Name java_lang_Enum;
|
public final Name java_lang_Enum;
|
||||||
|
public final Name java_dyn_MethodHandle;
|
||||||
|
public final Name java_dyn_InvokeDynamic;
|
||||||
public final Name package_info;
|
public final Name package_info;
|
||||||
public final Name ConstantValue;
|
public final Name ConstantValue;
|
||||||
public final Name LineNumberTable;
|
public final Name LineNumberTable;
|
||||||
|
@ -111,6 +113,7 @@ public class Names {
|
||||||
public final Name value;
|
public final Name value;
|
||||||
public final Name getMessage;
|
public final Name getMessage;
|
||||||
public final Name getClass;
|
public final Name getClass;
|
||||||
|
public final Name invoke;
|
||||||
public final Name TYPE;
|
public final Name TYPE;
|
||||||
public final Name FIELD;
|
public final Name FIELD;
|
||||||
public final Name METHOD;
|
public final Name METHOD;
|
||||||
|
@ -175,6 +178,8 @@ public class Names {
|
||||||
java_lang_Cloneable = fromString("java.lang.Cloneable");
|
java_lang_Cloneable = fromString("java.lang.Cloneable");
|
||||||
java_io_Serializable = fromString("java.io.Serializable");
|
java_io_Serializable = fromString("java.io.Serializable");
|
||||||
java_lang_Enum = fromString("java.lang.Enum");
|
java_lang_Enum = fromString("java.lang.Enum");
|
||||||
|
java_dyn_MethodHandle = fromString("java.dyn.MethodHandle");
|
||||||
|
java_dyn_InvokeDynamic = fromString("java.dyn.InvokeDynamic");
|
||||||
package_info = fromString("package-info");
|
package_info = fromString("package-info");
|
||||||
serialVersionUID = fromString("serialVersionUID");
|
serialVersionUID = fromString("serialVersionUID");
|
||||||
ConstantValue = fromString("ConstantValue");
|
ConstantValue = fromString("ConstantValue");
|
||||||
|
@ -216,6 +221,7 @@ public class Names {
|
||||||
value = fromString("value");
|
value = fromString("value");
|
||||||
getMessage = fromString("getMessage");
|
getMessage = fromString("getMessage");
|
||||||
getClass = fromString("getClass");
|
getClass = fromString("getClass");
|
||||||
|
invoke = fromString("invoke");
|
||||||
|
|
||||||
TYPE = fromString("TYPE");
|
TYPE = fromString("TYPE");
|
||||||
FIELD = fromString("FIELD");
|
FIELD = fromString("FIELD");
|
||||||
|
|
|
@ -339,7 +339,7 @@ public class ConstantWriter extends BasicWriter {
|
||||||
cp = name.codePointAt(k);
|
cp = name.codePointAt(k);
|
||||||
if ((cc == '/' && !Character.isJavaIdentifierStart(cp))
|
if ((cc == '/' && !Character.isJavaIdentifierStart(cp))
|
||||||
|| (cp != '/' && !Character.isJavaIdentifierPart(cp))) {
|
|| (cp != '/' && !Character.isJavaIdentifierPart(cp))) {
|
||||||
return "\"" + name + "\"";
|
return "\"" + addEscapes(name) + "\"";
|
||||||
}
|
}
|
||||||
cc = cp;
|
cc = cp;
|
||||||
}
|
}
|
||||||
|
@ -347,6 +347,33 @@ public class ConstantWriter extends BasicWriter {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If name requires escapes, put them in, so it can be a string body. */
|
||||||
|
private static String addEscapes(String name) {
|
||||||
|
String esc = "\\\"\n\t";
|
||||||
|
String rep = "\\\"nt";
|
||||||
|
StringBuilder buf = null;
|
||||||
|
int nextk = 0;
|
||||||
|
int len = name.length();
|
||||||
|
for (int k = 0; k < len; k++) {
|
||||||
|
char cp = name.charAt(k);
|
||||||
|
int n = esc.indexOf(cp);
|
||||||
|
if (n >= 0) {
|
||||||
|
if (buf == null)
|
||||||
|
buf = new StringBuilder(len * 2);
|
||||||
|
if (nextk < k)
|
||||||
|
buf.append(name, nextk, k);
|
||||||
|
buf.append('\\');
|
||||||
|
buf.append(rep.charAt(n));
|
||||||
|
nextk = k+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (buf == null)
|
||||||
|
return name;
|
||||||
|
if (nextk < len)
|
||||||
|
buf.append(name, nextk, len);
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
private ClassWriter classWriter;
|
private ClassWriter classWriter;
|
||||||
private Options options;
|
private Options options;
|
||||||
}
|
}
|
||||||
|
|
|
@ -475,6 +475,13 @@ public class JavapPrinter {
|
||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case opc_invokedynamic: {
|
||||||
|
int index = getUShort(pc+1);
|
||||||
|
out.print("\t#"+index+"; //");
|
||||||
|
PrintConstant(index);
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
case opc_multianewarray: {
|
case opc_multianewarray: {
|
||||||
int index = getUShort(pc+1), dimensions=getUbyte(pc+3);
|
int index = getUShort(pc+1), dimensions=getUbyte(pc+3);
|
||||||
out.print("\t#"+index+", "+dimensions+"; //");
|
out.print("\t#"+index+", "+dimensions+"; //");
|
||||||
|
|
|
@ -318,7 +318,7 @@ public interface RuntimeConstants {
|
||||||
public static final int opc_invokespecial = 183;
|
public static final int opc_invokespecial = 183;
|
||||||
public static final int opc_invokestatic = 184;
|
public static final int opc_invokestatic = 184;
|
||||||
public static final int opc_invokeinterface = 185;
|
public static final int opc_invokeinterface = 185;
|
||||||
// public static final int opc_xxxunusedxxx = 186;
|
public static final int opc_invokedynamic = 186;
|
||||||
public static final int opc_new = 187;
|
public static final int opc_new = 187;
|
||||||
public static final int opc_newarray = 188;
|
public static final int opc_newarray = 188;
|
||||||
public static final int opc_anewarray = 189;
|
public static final int opc_anewarray = 189;
|
||||||
|
@ -549,7 +549,7 @@ public interface RuntimeConstants {
|
||||||
"invokespecial", // was "invokenonvirtual",
|
"invokespecial", // was "invokenonvirtual",
|
||||||
"invokestatic",
|
"invokestatic",
|
||||||
"invokeinterface",
|
"invokeinterface",
|
||||||
"bytecode 186", //"xxxunusedxxx",
|
"invokedynamic",
|
||||||
"new",
|
"new",
|
||||||
"newarray",
|
"newarray",
|
||||||
"anewarray",
|
"anewarray",
|
||||||
|
|
59
langtools/test/tools/javac/meth/InvokeDyn.java
Normal file
59
langtools/test/tools/javac/meth/InvokeDyn.java
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||||
|
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||||
|
* have any questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 6754038
|
||||||
|
* @summary Generate call sites for method handle
|
||||||
|
* @author jrose
|
||||||
|
*
|
||||||
|
* @library ..
|
||||||
|
* @compile -source 7 -target 7 InvokeDyn.java
|
||||||
|
*/
|
||||||
|
//No: @run main/othervm -XX:+EnableInvokeDynamic meth.InvokeDyn
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Standalone testing:
|
||||||
|
* <code>
|
||||||
|
* $ cd $MY_REPO_DIR/langtools
|
||||||
|
* $ (cd make; make)
|
||||||
|
* $ ./dist/bootstrap/bin/javac -d dist test/tools/javac/meth/InvokeDyn.java
|
||||||
|
* $ javap -c -classpath dist meth.InvokeDyn
|
||||||
|
* </code>
|
||||||
|
*/
|
||||||
|
|
||||||
|
package meth;
|
||||||
|
|
||||||
|
import java.dyn.InvokeDynamic;
|
||||||
|
|
||||||
|
public class InvokeDyn {
|
||||||
|
void test() {
|
||||||
|
Object x = "hello";
|
||||||
|
InvokeDynamic.greet(x, "world", 123);
|
||||||
|
InvokeDynamic.greet(x, "mundus", 456);
|
||||||
|
InvokeDynamic.greet(x, "kosmos", 789);
|
||||||
|
InvokeDynamic.<String>cogitate(10.11121, 3.14);
|
||||||
|
InvokeDynamic.<void>#"yow: what I mean to say is, please treat this one specially"(null);
|
||||||
|
InvokeDynamic.<int>invoke("goodbye");
|
||||||
|
}
|
||||||
|
}
|
75
langtools/test/tools/javac/meth/InvokeMH.java
Normal file
75
langtools/test/tools/javac/meth/InvokeMH.java
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||||
|
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||||
|
* have any questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 6754038
|
||||||
|
* @summary Generate call sites for method handle
|
||||||
|
* @author jrose
|
||||||
|
*
|
||||||
|
* @compile -source 7 -target 7 InvokeMH.java
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Standalone testing:
|
||||||
|
* <code>
|
||||||
|
* $ cd $MY_REPO_DIR/langtools
|
||||||
|
* $ (cd make; make)
|
||||||
|
* $ ./dist/bootstrap/bin/javac -d dist test/tools/javac/meth/InvokeMH.java
|
||||||
|
* $ javap -c -classpath dist meth.InvokeMH
|
||||||
|
* </code>
|
||||||
|
*/
|
||||||
|
|
||||||
|
package meth;
|
||||||
|
|
||||||
|
import java.dyn.MethodHandle;
|
||||||
|
|
||||||
|
public class InvokeMH {
|
||||||
|
void test(MethodHandle mh_SiO,
|
||||||
|
MethodHandle mh_vS,
|
||||||
|
MethodHandle mh_vi,
|
||||||
|
MethodHandle mh_vv) {
|
||||||
|
Object o; String s; int i; // for return type testing
|
||||||
|
|
||||||
|
// next five must have sig = (String,int)Object
|
||||||
|
mh_SiO.invoke("world", 123);
|
||||||
|
mh_SiO.invoke("mundus", 456);
|
||||||
|
Object k = "kosmos";
|
||||||
|
mh_SiO.invoke((String)k, 789);
|
||||||
|
o = mh_SiO.invoke((String)null, 000);
|
||||||
|
o = mh_SiO.<Object>invoke("arda", -123);
|
||||||
|
|
||||||
|
// sig = ()String
|
||||||
|
s = mh_vS.<String>invoke();
|
||||||
|
|
||||||
|
// sig = ()int
|
||||||
|
i = mh_vi.<int>invoke();
|
||||||
|
o = mh_vi.<int>invoke();
|
||||||
|
//s = mh_vi.<int>invoke(); //BAD
|
||||||
|
mh_vi.<int>invoke();
|
||||||
|
|
||||||
|
// sig = ()void
|
||||||
|
//o = mh_vv.<void>invoke(); //BAD
|
||||||
|
mh_vv.<void>invoke();
|
||||||
|
}
|
||||||
|
}
|
98
langtools/test/tools/javac/meth/MakeNegTests.sh
Normal file
98
langtools/test/tools/javac/meth/MakeNegTests.sh
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||||
|
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
#
|
||||||
|
# This code is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU General Public License version 2 only, as
|
||||||
|
# published by the Free Software Foundation.
|
||||||
|
#
|
||||||
|
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
# version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
# accompanied this code).
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License version
|
||||||
|
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
#
|
||||||
|
# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||||
|
# CA 95054 USA or visit www.sun.com if you need additional information or
|
||||||
|
# have any questions.
|
||||||
|
#
|
||||||
|
|
||||||
|
# @test
|
||||||
|
# @bug 6754038
|
||||||
|
# @summary Verify correct rejection of strongly typed return values
|
||||||
|
# @run shell MakeNegTests.sh
|
||||||
|
|
||||||
|
default_template=InvokeMH.java
|
||||||
|
javacflags='-source 7 -target 7'
|
||||||
|
# the rest of this file is a generic "//BAD"-line tester
|
||||||
|
|
||||||
|
: ${TESTSRC=.} ${TESTCLASSES=.}
|
||||||
|
javac="${TESTJAVA+${TESTJAVA}/bin/}javac"
|
||||||
|
|
||||||
|
verbose=false quiet=false
|
||||||
|
|
||||||
|
main() {
|
||||||
|
case "${@-}" in
|
||||||
|
*.java*)
|
||||||
|
for template in "$@"; do
|
||||||
|
expand_and_test "$template"
|
||||||
|
done;;
|
||||||
|
*) expand_and_test "${TESTSRC}/$default_template";;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
expand_and_test() {
|
||||||
|
template=$1
|
||||||
|
expand "$@"
|
||||||
|
testneg "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
expand() {
|
||||||
|
template=$1
|
||||||
|
badlines=` grep -n < "$template" '//BAD' `
|
||||||
|
badcount=` echo "$badlines" | wc -l `
|
||||||
|
[ $badcount -gt 0 ] || { echo "No negative test cases in $template"; exit 1; }
|
||||||
|
$quiet || echo "Expanding $badcount negative test cases from $template:"
|
||||||
|
$quiet || echo "$badlines"
|
||||||
|
badnums=` echo "$badlines" | sed 's/:.*//' `
|
||||||
|
casestem=` getcasestem "$template" `
|
||||||
|
tclassname=` basename "$template" .java `
|
||||||
|
rm -f "$casestem"*.java
|
||||||
|
for badnum in $badnums; do
|
||||||
|
casefile="$casestem"${badnum}.java
|
||||||
|
cclassname=` basename "$casefile" .java `
|
||||||
|
sed < "$template" > "$casefile" "
|
||||||
|
s|@compile|@compile/fail|
|
||||||
|
/ @[a-z]/s|@|##|
|
||||||
|
${badnum}s:^ *[/*]*: :
|
||||||
|
s/${tclassname}/${cclassname}/g
|
||||||
|
"
|
||||||
|
$verbose && diff -u "$template" "$casefile"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
getcasestem() {
|
||||||
|
echo "$1" | sed 's/\.java$//;s/_BAD[0-9]*$//;s/$/_BAD/'
|
||||||
|
}
|
||||||
|
|
||||||
|
testneg() {
|
||||||
|
template=$1
|
||||||
|
for casefile in ` getcasestem "$template" `*.java; do
|
||||||
|
$quiet || echo -------- $javac $javacflags "$casefile"
|
||||||
|
$javac $javacflags "$casefile" > "$casefile".errlog 2>&1 && {
|
||||||
|
echo "*** Compilation unexpectedly succeeded: $casefile"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
$quiet || echo "Compilation failed as expected"
|
||||||
|
$quiet || head ` $verbose || echo -3 ` < "$casefile".errlog
|
||||||
|
rm "$casefile".errlog
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
97
langtools/test/tools/javac/quid/MakeNegTests.sh
Normal file
97
langtools/test/tools/javac/quid/MakeNegTests.sh
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||||
|
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
#
|
||||||
|
# This code is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms of the GNU General Public License version 2 only, as
|
||||||
|
# published by the Free Software Foundation.
|
||||||
|
#
|
||||||
|
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
# version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
# accompanied this code).
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License version
|
||||||
|
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
#
|
||||||
|
# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||||
|
# CA 95054 USA or visit www.sun.com if you need additional information or
|
||||||
|
# have any questions.
|
||||||
|
#
|
||||||
|
|
||||||
|
# @test
|
||||||
|
# @bug 6746458
|
||||||
|
# @summary Verify correct rejection of illegal quoted identifiers.
|
||||||
|
# @run shell MakeNegTests.sh
|
||||||
|
|
||||||
|
default_template=QuotedIdent.java
|
||||||
|
# the rest of this file is a generic "//BAD"-line tester
|
||||||
|
|
||||||
|
: ${TESTSRC=.} ${TESTCLASSES=.}
|
||||||
|
javac="${TESTJAVA+${TESTJAVA}/bin/}javac"
|
||||||
|
|
||||||
|
verbose=false quiet=false
|
||||||
|
|
||||||
|
main() {
|
||||||
|
case "${@-}" in
|
||||||
|
*.java*)
|
||||||
|
for template in "$@"; do
|
||||||
|
expand_and_test "$template"
|
||||||
|
done;;
|
||||||
|
*) expand_and_test "${TESTSRC}/$default_template";;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
expand_and_test() {
|
||||||
|
template=$1
|
||||||
|
expand "$@"
|
||||||
|
testneg "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
expand() {
|
||||||
|
template=$1
|
||||||
|
badlines=` grep -n < "$template" '//BAD' `
|
||||||
|
badcount=` echo "$badlines" | wc -l `
|
||||||
|
[ $badcount -gt 0 ] || { echo "No negative test cases in $template"; exit 1; }
|
||||||
|
$quiet || echo "Expanding $badcount negative test cases from $template:"
|
||||||
|
$quiet || echo "$badlines"
|
||||||
|
badnums=` echo "$badlines" | sed 's/:.*//' `
|
||||||
|
casestem=` getcasestem "$template" `
|
||||||
|
tclassname=` basename "$template" .java `
|
||||||
|
rm "$casestem"*.java
|
||||||
|
for badnum in $badnums; do
|
||||||
|
casefile="$casestem"${badnum}.java
|
||||||
|
cclassname=` basename "$casefile" .java `
|
||||||
|
sed < "$template" > "$casefile" "
|
||||||
|
s|@compile|@compile/fail|
|
||||||
|
/ @[a-z]/s|@|##|
|
||||||
|
${badnum}s:^ *[/*]*: :
|
||||||
|
s/${tclassname}/${cclassname}/g
|
||||||
|
"
|
||||||
|
$verbose && diff -u "$template" "$casefile"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
getcasestem() {
|
||||||
|
echo "$1" | sed 's/\.java$//;s/_BAD[0-9]*$//;s/$/_BAD/'
|
||||||
|
}
|
||||||
|
|
||||||
|
testneg() {
|
||||||
|
template=$1
|
||||||
|
for casefile in ` getcasestem "$template" `*.java; do
|
||||||
|
$quiet || echo -------- $javac "$casefile"
|
||||||
|
$javac "$casefile" > "$casefile".errlog 2>&1 && {
|
||||||
|
echo "*** Compilation unexpectedly succeeded: $casefile"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
$quiet || echo "Compilation failed as expected"
|
||||||
|
$quiet || head ` $verbose || echo -3 ` < "$casefile".errlog
|
||||||
|
rm "$casefile".errlog
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
132
langtools/test/tools/javac/quid/QuotedIdent.java
Normal file
132
langtools/test/tools/javac/quid/QuotedIdent.java
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||||
|
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||||
|
* have any questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 6746458
|
||||||
|
* @summary Verify correct lexing of quoted identifiers.
|
||||||
|
* @author jrose
|
||||||
|
*
|
||||||
|
* @library ..
|
||||||
|
* @run main quid.QuotedIdent
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Standalone testing:
|
||||||
|
* <code>
|
||||||
|
* $ cd $MY_REPO_DIR/langtools
|
||||||
|
* $ (cd make; make)
|
||||||
|
* $ ./dist/bootstrap/bin/javac -d dist test/tools/javac/quid/QuotedIdent.java
|
||||||
|
* $ java -version # should print 1.6 or later
|
||||||
|
* $ java -cp dist quid.QuotedIdent
|
||||||
|
* </code>
|
||||||
|
*/
|
||||||
|
|
||||||
|
package quid;
|
||||||
|
|
||||||
|
public class QuotedIdent {
|
||||||
|
static void check(int testid, String have, String expect)
|
||||||
|
throws RuntimeException {
|
||||||
|
if ((have == null && have != expect) ||
|
||||||
|
(have != null && !have.equals(expect))) {
|
||||||
|
String msg =
|
||||||
|
"TEST " + testid + ": HAVE \"" +
|
||||||
|
have + "\" EXPECT \"" + expect + "\"";
|
||||||
|
System.out.println("StringConversion: " + msg);
|
||||||
|
throw new RuntimeException(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// negative tests:
|
||||||
|
//static class #"" { } //BAD empty ident name
|
||||||
|
//static class #"<foo>" { } //BAD bad char in ident name
|
||||||
|
/*static class /*(//BAD ident name interrupted by newline) #"jump:
|
||||||
|
" { } /* uncomment previous line to attempt class w/ bad name */
|
||||||
|
|
||||||
|
static class #"int" extends Number {
|
||||||
|
final int #"int";
|
||||||
|
#"int"(int #"int") {
|
||||||
|
this.#"int" = #"int";
|
||||||
|
}
|
||||||
|
static #"int" valueOf(int #"int") {
|
||||||
|
return new #"int"(#"int");
|
||||||
|
}
|
||||||
|
public int intValue() { return #"int"; }
|
||||||
|
public long longValue() { return #"int"; }
|
||||||
|
public float floatValue() { return #"int"; }
|
||||||
|
public double doubleValue() { return #"int"; }
|
||||||
|
public String toString() { return String.valueOf(#"int"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
class #"*86" {
|
||||||
|
String #"555-1212"() { return "[*86.555-1212]"; }
|
||||||
|
}
|
||||||
|
static#"*86"#"MAKE-*86"() { // note close spacing
|
||||||
|
return new QuotedIdent().new#"*86"();
|
||||||
|
}
|
||||||
|
|
||||||
|
static String bar() { return "[bar]"; }
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
String s;
|
||||||
|
|
||||||
|
String #"sticky \' wicket" = "wicked ' stick";
|
||||||
|
s = #"sticky ' wicket";
|
||||||
|
check(11, s, "wicked \' stick");
|
||||||
|
check(12, #"s", s);
|
||||||
|
check(13, #"\163", s);
|
||||||
|
|
||||||
|
s = #"QuotedIdent".bar();
|
||||||
|
check(21, s, "[bar]");
|
||||||
|
|
||||||
|
s = #"int".valueOf(123).toString();
|
||||||
|
check(22, s, "123");
|
||||||
|
|
||||||
|
s = #"MAKE-*86"().#"555-1212"();
|
||||||
|
check(23, s, "[*86.555-1212]");
|
||||||
|
|
||||||
|
class#"{{{inmost}}}" { }
|
||||||
|
s = new#"{{{inmost}}}"().getClass().getName();
|
||||||
|
if (!s.endsWith("{{{inmost}}}"))
|
||||||
|
check(24, s, "should end with \"{{{inmost}}}\"");
|
||||||
|
|
||||||
|
s = #"Yog-Shoggoth".#"(nameless ululation)";
|
||||||
|
check(25, s, "Tekeli-li!");
|
||||||
|
|
||||||
|
s = #"int".class.getName();
|
||||||
|
check(31, s, QuotedIdent.class.getName()+"$int");
|
||||||
|
|
||||||
|
Class x86 = Class.forName(QuotedIdent.class.getName()+"$*86");
|
||||||
|
if (x86 != #"*86".class)
|
||||||
|
check(32, "reflected "+x86, "static "+#"*86".class);
|
||||||
|
|
||||||
|
s = (String) x86.getDeclaredMethod("555-1212").invoke(#"MAKE-*86"());
|
||||||
|
check(31, s, "[*86.555-1212]");
|
||||||
|
|
||||||
|
System.out.println("OK");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface #"Yog-Shoggoth" {
|
||||||
|
final String #"(nameless ululation)" = "Tekeli-li!";
|
||||||
|
}
|
81
langtools/test/tools/javac/quid/QuotedIdent2.java
Normal file
81
langtools/test/tools/javac/quid/QuotedIdent2.java
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||||
|
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||||
|
* have any questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 6746458
|
||||||
|
* @summary Verify correct separate compilation of classes with extended identifiers.
|
||||||
|
* @author jrose
|
||||||
|
*
|
||||||
|
* @library ..
|
||||||
|
* @run main quid.QuotedIdent2
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Standalone testing:
|
||||||
|
* <code>
|
||||||
|
* $ cd $MY_REPO_DIR/langtools
|
||||||
|
* $ (cd make; make)
|
||||||
|
* $ ./dist/bootstrap/bin/javac -d dist test/tools/javac/quid/QuotedIdent.java
|
||||||
|
* $ ./dist/bootstrap/bin/javac -d dist -cp dist test/tools/javac/quid/QuotedIdent2.java
|
||||||
|
* $ java -version # should print 1.6 or later
|
||||||
|
* $ java -cp dist QuotedIdent2
|
||||||
|
* </code>
|
||||||
|
*/
|
||||||
|
|
||||||
|
package quid;
|
||||||
|
|
||||||
|
import quid.QuotedIdent.*;
|
||||||
|
import quid.QuotedIdent.#"*86";
|
||||||
|
import static quid.QuotedIdent.#"MAKE-*86";
|
||||||
|
|
||||||
|
public class QuotedIdent2 {
|
||||||
|
static void check(int testid, String have, String expect)
|
||||||
|
throws RuntimeException {
|
||||||
|
QuotedIdent.check(testid, have, expect);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
String s;
|
||||||
|
|
||||||
|
s = #"int".valueOf(123).toString();
|
||||||
|
check(22, s, "123");
|
||||||
|
|
||||||
|
s = #"MAKE-*86"().#"555-1212"();
|
||||||
|
check(23, s, "[*86.555-1212]");
|
||||||
|
|
||||||
|
s = #"Yog-Shoggoth".#"(nameless ululation)";
|
||||||
|
check(25, s, "Tekeli-li!");
|
||||||
|
|
||||||
|
s = QuotedIdent.#"int".class.getName();
|
||||||
|
check(31, s, QuotedIdent.class.getName()+"$int");
|
||||||
|
|
||||||
|
Class x86 = Class.forName(QuotedIdent.class.getName()+"$*86");
|
||||||
|
if (x86 != #"*86".class)
|
||||||
|
check(32, "reflected "+x86, "static "+#"*86".class);
|
||||||
|
|
||||||
|
s = (String) x86.getDeclaredMethod("555-1212").invoke(QuotedIdent.#"MAKE-*86"());
|
||||||
|
check(31, s, "[*86.555-1212]");
|
||||||
|
|
||||||
|
System.out.println("OK");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue