This commit is contained in:
Lana Steuck 2014-05-30 09:25:52 -07:00
commit a7ab489c5a
8 changed files with 345 additions and 75 deletions

View File

@ -4696,7 +4696,7 @@ public class Types {
assembleClassSig(rawOuter
? types.erasure(outer)
: outer);
append('.');
append(rawOuter ? '$' : '.');
Assert.check(c.flatname.startsWith(c.owner.enclClass().flatname));
append(rawOuter
? c.flatname.subName(c.owner.enclClass().flatname.getByteLength() + 1, c.flatname.getByteLength())

View File

@ -1221,25 +1221,102 @@ public class DeferredAttr extends JCTree.Visitor {
}
//slow path
Symbol sym = quicklyResolveMethod(env, tree);
if (sym == null) {
result = ArgumentExpressionKind.POLY;
return;
}
result = analyzeCandidateMethods(sym, ArgumentExpressionKind.PRIMITIVE,
argumentKindAnalyzer);
}
//where
private boolean isSimpleReceiver(JCTree rec) {
switch (rec.getTag()) {
case IDENT:
return true;
case SELECT:
return isSimpleReceiver(((JCFieldAccess)rec).selected);
case TYPEAPPLY:
case TYPEARRAY:
return true;
case ANNOTATED_TYPE:
return isSimpleReceiver(((JCAnnotatedType)rec).underlyingType);
case APPLY:
return true;
default:
return false;
}
}
private ArgumentExpressionKind reduce(ArgumentExpressionKind kind) {
return argumentKindAnalyzer.reduce(result, kind);
}
MethodAnalyzer<ArgumentExpressionKind> argumentKindAnalyzer =
new MethodAnalyzer<ArgumentExpressionKind>() {
@Override
public ArgumentExpressionKind process(MethodSymbol ms) {
return ArgumentExpressionKind.methodKind(ms, types);
}
@Override
public ArgumentExpressionKind reduce(ArgumentExpressionKind kind1,
ArgumentExpressionKind kind2) {
switch (kind1) {
case PRIMITIVE: return kind2;
case NO_POLY: return kind2.isPoly() ? kind2 : kind1;
case POLY: return kind1;
default:
Assert.error();
return null;
}
}
@Override
public boolean shouldStop(ArgumentExpressionKind result) {
return result.isPoly();
}
};
@Override
public void visitLiteral(JCLiteral tree) {
Type litType = attr.litType(tree.typetag);
result = ArgumentExpressionKind.standaloneKind(litType, types);
}
@Override
void skip(JCTree tree) {
result = ArgumentExpressionKind.NO_POLY;
}
private Symbol quicklyResolveMethod(Env<AttrContext> env, final JCMethodInvocation tree) {
final JCExpression rec = tree.meth.hasTag(SELECT) ?
((JCFieldAccess)tree.meth).selected :
null;
if (rec != null && !isSimpleReceiver(rec)) {
//give up if receiver is too complex (to cut down analysis time)
result = ArgumentExpressionKind.POLY;
return;
return null;
}
Type site = rec != null ?
attribSpeculative(rec, env, attr.unknownTypeExprInfo).type :
env.enclClass.sym.type;
Type site;
while (site.hasTag(TYPEVAR)) {
site = site.getUpperBound();
if (rec != null) {
if (rec.hasTag(APPLY)) {
Symbol recSym = quicklyResolveMethod(env, (JCMethodInvocation) rec);
if (recSym == null)
return null;
Symbol resolvedReturnType =
analyzeCandidateMethods(recSym, syms.errSymbol, returnSymbolAnalyzer);
if (resolvedReturnType == null)
return null;
site = resolvedReturnType.type;
} else {
site = attribSpeculative(rec, env, attr.unknownTypeExprInfo).type;
}
} else {
site = env.enclClass.sym.type;
}
List<Type> args = rs.dummyArgs(tree.args.length());
Name name = TreeInfo.name(tree.meth);
Resolve.LookupHelper lh = rs.new LookupHelper(name, site, args, List.<Type>nil(), MethodResolutionPhase.VARARITY) {
@Override
@ -1254,61 +1331,60 @@ public class DeferredAttr extends JCTree.Visitor {
}
};
Symbol sym = rs.lookupMethod(env, tree, site.tsym, rs.arityMethodCheck, lh);
return rs.lookupMethod(env, tree, site.tsym, rs.arityMethodCheck, lh);
}
//where:
MethodAnalyzer<Symbol> returnSymbolAnalyzer = new MethodAnalyzer<Symbol>() {
@Override
public Symbol process(MethodSymbol ms) {
ArgumentExpressionKind kind = ArgumentExpressionKind.methodKind(ms, types);
return kind != ArgumentExpressionKind.POLY ? ms.getReturnType().tsym : null;
}
@Override
public Symbol reduce(Symbol s1, Symbol s2) {
return s1 == syms.errSymbol ? s2 : s1 == s2 ? s1 : null;
}
@Override
public boolean shouldStop(Symbol result) {
return result == null;
}
};
if (sym.kind == Kinds.AMBIGUOUS) {
Resolve.AmbiguityError err = (Resolve.AmbiguityError)sym.baseSymbol();
result = ArgumentExpressionKind.PRIMITIVE;
for (Symbol s : err.ambiguousSyms) {
if (result.isPoly()) break;
if (s.kind == Kinds.MTH) {
result = reduce(ArgumentExpressionKind.methodKind(s, types));
/**
* Process the result of Resolve.lookupMethod. If sym is a method symbol, the result of
* MethodAnalyzer.process is returned. If sym is an ambiguous symbol, all the candidate
* methods are inspected one by one, using MethodAnalyzer.process. The outcomes are
* reduced using MethodAnalyzer.reduce (using defaultValue as the first value over which
* the reduction runs). MethodAnalyzer.shouldStop can be used to stop the inspection early.
*/
<E> E analyzeCandidateMethods(Symbol sym, E defaultValue, MethodAnalyzer<E> analyzer) {
switch (sym.kind) {
case Kinds.MTH:
return analyzer.process((MethodSymbol) sym);
case Kinds.AMBIGUOUS:
Resolve.AmbiguityError err = (Resolve.AmbiguityError)sym.baseSymbol();
E res = defaultValue;
for (Symbol s : err.ambiguousSyms) {
if (s.kind == Kinds.MTH) {
res = analyzer.reduce(res, analyzer.process((MethodSymbol) s));
if (analyzer.shouldStop(res))
return res;
}
}
}
} else {
result = (sym.kind == Kinds.MTH) ?
ArgumentExpressionKind.methodKind(sym, types) :
ArgumentExpressionKind.NO_POLY;
return res;
default:
return defaultValue;
}
}
//where
private boolean isSimpleReceiver(JCTree rec) {
switch (rec.getTag()) {
case IDENT:
return true;
case SELECT:
return isSimpleReceiver(((JCFieldAccess)rec).selected);
case TYPEAPPLY:
case TYPEARRAY:
return true;
case ANNOTATED_TYPE:
return isSimpleReceiver(((JCAnnotatedType)rec).underlyingType);
default:
return false;
}
}
private ArgumentExpressionKind reduce(ArgumentExpressionKind kind) {
switch (result) {
case PRIMITIVE: return kind;
case NO_POLY: return kind.isPoly() ? kind : result;
case POLY: return result;
default:
Assert.error();
return null;
}
}
@Override
public void visitLiteral(JCLiteral tree) {
Type litType = attr.litType(tree.typetag);
result = ArgumentExpressionKind.standaloneKind(litType, types);
}
@Override
void skip(JCTree tree) {
result = ArgumentExpressionKind.NO_POLY;
}
}
/** Analyzer for methods - used by analyzeCandidateMethods. */
interface MethodAnalyzer<E> {
E process(MethodSymbol ms);
E reduce(E e1, E e2);
boolean shouldStop(E result);
}
//where
private EnumSet<JCTree.Tag> deferredCheckerTags =
EnumSet.of(LAMBDA, REFERENCE, PARENS, TYPECAST,

View File

@ -1925,6 +1925,13 @@ public class Code {
return aliveRanges.isEmpty() ? null : aliveRanges.get(aliveRanges.size() - 1);
}
void removeLastRange() {
Range lastRange = lastRange();
if (lastRange != null) {
aliveRanges.remove(lastRange);
}
}
@Override
public String toString() {
if (aliveRanges == null) {
@ -1955,9 +1962,7 @@ public class Code {
}
}
} else {
if (!aliveRanges.isEmpty()) {
aliveRanges.remove(aliveRanges.size() - 1);
}
removeLastRange();
}
}
@ -1965,16 +1970,14 @@ public class Code {
if (aliveRanges.isEmpty()) {
return false;
}
Range range = lastRange();
return range.length == Character.MAX_VALUE;
return lastRange().length == Character.MAX_VALUE;
}
public boolean isLastRangeInitialized() {
if (aliveRanges.isEmpty()) {
return false;
}
Range range = lastRange();
return range.start_pc != Character.MAX_VALUE;
return lastRange().start_pc != Character.MAX_VALUE;
}
public Range getWidestRange() {
@ -2095,7 +2098,7 @@ public class Code {
v.closeRange(length);
putVar(v);
} else {
v.lastRange().start_pc = Character.MAX_VALUE;
v.removeLastRange();
}
}
}

View File

@ -1800,8 +1800,7 @@ public class Gen extends JCTree.Visitor {
genStat(tree.thenpart, env, CRT_STATEMENT | CRT_FLOW_TARGET);
thenExit = code.branch(goto_);
if (varDebugInfo && lvtRanges.containsKey(code.meth, tree.thenpart)) {
code.closeAliveRanges(tree.thenpart,
thenExit != null && tree.elsepart == null ? thenExit.pc : code.cp);
code.closeAliveRanges(tree.thenpart, code.cp);
}
}
if (elseChain != null) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2014, Oracle and/or its affiliates. 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
@ -23,8 +23,8 @@
/*
* @test
* @bug 7047734 8027660
* @summary The LVT is not generated correctly during some try/catch scenarios;
* @bug 7047734 8027660 8037937
* @summary The LVT is not generated correctly during some try/catch scenarios
* javac crash while creating LVT entry for a local variable defined in
* an inner block
* @library /tools/javac/lib
@ -120,7 +120,7 @@ public class LVTHarness {
for (Map.Entry<ElementKey, AliveRanges> entry : aliveRangeMap.entrySet()) {
if (!seenAliveRanges.contains(entry.getKey())) {
error("Redundant @AliveRanges annotation on method " +
entry.getKey().elem);
entry.getKey().elem + " with key " + entry.getKey());
}
}
}
@ -134,7 +134,7 @@ public class LVTHarness {
for (Method method : classFile.methods) {
for (ElementKey elementKey: aliveRangeMap.keySet()) {
String methodDesc = method.getName(constantPool) +
method.descriptor.getParameterTypes(constantPool);
method.descriptor.getParameterTypes(constantPool).replace(" ", "");
if (methodDesc.equals(elementKey.elem.toString())) {
checkMethod(constantPool, method, aliveRangeMap.get(elementKey));
seenAliveRanges.add(elementKey);

View File

@ -33,7 +33,7 @@ public class TestCaseIfElse {
@AliveRange(varName="o", bytecodeStart=10, bytecodeLength=8)
@AliveRange(varName="o", bytecodeStart=21, bytecodeLength=9)
void m2(String[] args) {
void m2() {
Object o;
int i = 5;
if (i != 5) {
@ -45,4 +45,19 @@ public class TestCaseIfElse {
}
o = "finish";
}
@AliveRange(varName="o", bytecodeStart=11, bytecodeLength=3)
@AliveRange(varName="o", bytecodeStart=17, bytecodeLength=2)
Object m3(boolean cond1, boolean cond2) {
Object o;
if (cond1) {
if (cond2) {
o = "then";
} else {
o = "else";
return null;
}
}
return null;
}
}

View File

@ -0,0 +1,137 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8031967
* @summary Ensure javac can handle very deeply nested chain of method invocations occurring as
* a parameter to other method invocations.
* @run main T8031967
*/
import java.io.IOException;
import java.net.URI;
import java.util.Arrays;
import java.util.List;
import javax.tools.DiagnosticListener;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.ToolProvider;
import com.sun.source.util.JavacTask;
public class T8031967 {
public static void main(String... args) throws IOException {
new T8031967().run();
}
final int depth = 50;
private void run() throws IOException {
runTestCase(true);
runTestCase(false);
}
private void runTestCase(boolean withErrors) throws IOException {
StringBuilder code = new StringBuilder();
code.append("public class Test {\n" +
" private void test() {\n" +
" GroupLayout l = new GroupLayout();\n" +
" l.setHorizontalGroup(\n");
gen(code, depth);
code.append(" );\n" +
" }\n");
if (!withErrors) {
code.append(" class GroupLayout {\n" +
" ParallelGroup createParallelGroup() {return null;}\n" +
" ParallelGroup createParallelGroup(int i) {return null;}\n" +
" ParallelGroup createParallelGroup(int i, int j) {return null;}\n" +
" void setHorizontalGroup(Group g) { }\n" +
" }\n" +
" \n" +
" class Group {\n" +
" Group addGroup(Group g) { return this; }\n" +
" Group addGroup(int i, Group g) { return this; }\n" +
" Group addGap(int i) { return this; }\n" +
" Group addGap(long l) { return this; }\n" +
" Group addGap(int i, int j) { return this; }\n" +
" Group addComponent(Object c) { return this; }\n" +
" Group addComponent(int i, Object c) { return this; }\n" +
" }\n" +
" class ParallelGroup extends Group {\n" +
" Group addGroup(Group g) { return this; }\n" +
" Group addGroup(int i, Group g) { return this; }\n" +
" Group addGap(int i) { return this; }\n" +
" Group addGap(int i, int j) { return this; }\n" +
" Group addComponent(Object c) { return this; }\n" +
" Group addComponent(int i, Object c) { return this; }\n" +
" }\n");
}
code.append("}\n");
JavaSource source = new JavaSource(code.toString());
List<JavaSource> sourceList = Arrays.asList(source);
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticListener<JavaFileObject> noErrors = (diagnostic) -> {
throw new IllegalStateException("Should not produce errors: " + diagnostic);
};
JavacTask task = (JavacTask) compiler.getTask(null, null, withErrors ? null : noErrors,
null, null, sourceList);
task.analyze();
}
private void gen(StringBuilder code, int depth) {
code.append("l.createParallelGroup()\n");
if (depth > 0) {
code.append(".addGroup(\n");
gen(code, depth - 1);
code.append(")");
}
code.append(".addGap(1)\n" +
".addComponent(new Object())\n" +
".addGap(1)\n" +
".addComponent(new Object())");
}
class JavaSource extends SimpleJavaFileObject {
final String code;
public JavaSource(String code) {
super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
this.code = code;
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return code;
}
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2014, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8037934
* @summary Javac generates invalid signatures for local types
* @run main BadSigTest
*/
public class BadSigTest<Outer> {
void m(){
class Local1{}
class Local2 extends Local1{}
Local2.class.getTypeParameters();
}
public static void main(String[] args) {
new BadSigTest().m();
}
}