From 80da503482d0a60dd88b6122026520b1beeca650 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Wed, 15 Jun 2011 14:49:25 +0100 Subject: [PATCH 001/107] 7000600: InputStream.skip() makes sensitive data accessible to malicious code Reviewed-by: hawtin, chegar --- jdk/src/share/classes/java/io/InputStream.java | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/jdk/src/share/classes/java/io/InputStream.java b/jdk/src/share/classes/java/io/InputStream.java index 23c166ed673..63d31d51f99 100644 --- a/jdk/src/share/classes/java/io/InputStream.java +++ b/jdk/src/share/classes/java/io/InputStream.java @@ -44,10 +44,9 @@ package java.io; */ public abstract class InputStream implements Closeable { - // SKIP_BUFFER_SIZE is used to determine the size of skipBuffer - private static final int SKIP_BUFFER_SIZE = 2048; - // skipBuffer is initialized in skip(long), if needed. - private static byte[] skipBuffer; + // MAX_SKIP_BUFFER_SIZE is used to determine the maximum buffer size to + // use when skipping. + private static final int MAX_SKIP_BUFFER_SIZE = 2048; /** * Reads the next byte of data from the input stream. The value byte is @@ -212,18 +211,15 @@ public abstract class InputStream implements Closeable { long remaining = n; int nr; - if (skipBuffer == null) - skipBuffer = new byte[SKIP_BUFFER_SIZE]; - - byte[] localSkipBuffer = skipBuffer; if (n <= 0) { return 0; } + int size = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining); + byte[] skipBuffer = new byte[size]; while (remaining > 0) { - nr = read(localSkipBuffer, 0, - (int) Math.min(SKIP_BUFFER_SIZE, remaining)); + nr = read(skipBuffer, 0, (int)Math.min(size, remaining)); if (nr < 0) { break; } From a2a420e7dee5dc5c8abcb11cfb9244370803f8a4 Mon Sep 17 00:00:00 2001 From: Anthony Petrov Date: Tue, 21 Jun 2011 20:20:58 +0400 Subject: [PATCH 002/107] 7022113: Security icon can be moved behind the window using the com.sun.SecurityWarning.setPosition() method Reviewed-by: art, dcherepanov --- jdk/src/windows/native/sun/windows/awt_Window.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdk/src/windows/native/sun/windows/awt_Window.cpp b/jdk/src/windows/native/sun/windows/awt_Window.cpp index c742aca9000..83f6f0b9b1c 100644 --- a/jdk/src/windows/native/sun/windows/awt_Window.cpp +++ b/jdk/src/windows/native/sun/windows/awt_Window.cpp @@ -355,7 +355,7 @@ void AwtWindow::RepositionSecurityWarning(JNIEnv *env) RECT rect; CalculateWarningWindowBounds(env, &rect); - ::SetWindowPos(warningWindow, IsAlwaysOnTop() ? HWND_TOPMOST : GetHWnd(), + ::SetWindowPos(warningWindow, IsAlwaysOnTop() ? HWND_TOPMOST : HWND_NOTOPMOST, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE | @@ -835,7 +835,7 @@ void AwtWindow::StartSecurityAnimation(AnimationKind kind) if (securityAnimationKind == akShow) { ::SetWindowPos(warningWindow, - IsAlwaysOnTop() ? HWND_TOPMOST : GetHWnd(), + IsAlwaysOnTop() ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW | SWP_NOOWNERZORDER); From c3c22d1d74259100925343f69c9ceaba581c16c5 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Mon, 27 Jun 2011 20:30:40 +0100 Subject: [PATCH 003/107] 7059259: (process) ProcessBuilder.start permission check should be improved when redirecting output to append Reviewed-by: hawtin --- jdk/src/windows/classes/java/lang/ProcessImpl.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/jdk/src/windows/classes/java/lang/ProcessImpl.java b/jdk/src/windows/classes/java/lang/ProcessImpl.java index 05891161a42..88486e5f472 100644 --- a/jdk/src/windows/classes/java/lang/ProcessImpl.java +++ b/jdk/src/windows/classes/java/lang/ProcessImpl.java @@ -60,10 +60,11 @@ final class ProcessImpl extends Process { throws IOException { if (append) { + String path = f.getPath(); SecurityManager sm = System.getSecurityManager(); if (sm != null) - sm.checkWrite(f.getPath()); - long handle = openForAtomicAppend(f.getPath()); + sm.checkWrite(path); + long handle = openForAtomicAppend(path); final FileDescriptor fd = new FileDescriptor(); fdAccess.setHandle(fd, handle); return AccessController.doPrivileged( From 0a5bf67eff72bf1e0098386e2d8a54f4444269b0 Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Fri, 15 Jul 2011 13:57:57 -0700 Subject: [PATCH 004/107] 7057857: SIGSEGV [libunpack.so] store_Utf8_char(signed char*, unsigned short) in java.util.jar.pack200 Reviewed-by: jrose, asaha, hawtin --- jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp | 5 +++++ jdk/src/share/native/com/sun/java/util/jar/pack/utils.cpp | 4 ++-- jdk/src/share/native/com/sun/java/util/jar/pack/utils.h | 4 ++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp b/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp index 17c48a4ceac..cee146d4db4 100644 --- a/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp +++ b/jdk/src/share/native/com/sun/java/util/jar/pack/unpack.cpp @@ -1112,11 +1112,14 @@ void unpacker::read_Utf8_values(entry* cpMap, int len) { uint size3 = suffix * 3; if (suffix == 0) continue; // done with empty string chars.malloc(size3); + CHECK; byte* chp = chars.ptr; band saved_band = cp_Utf8_big_chars; cp_Utf8_big_chars.readData(suffix); + CHECK; for (int j = 0; j < suffix; j++) { unsigned short ch = cp_Utf8_big_chars.getInt(); + CHECK; chp = store_Utf8_char(chp, ch); } chars.realloc(chp - chars.ptr); @@ -1134,10 +1137,12 @@ void unpacker::read_Utf8_values(entry* cpMap, int len) { CHECK; int prevlen = 0; // previous string length (in chars) tmallocs.add(bigbuf.ptr); // free after this block + CHECK; cp_Utf8_prefix.rewind(); for (i = 0; i < len; i++) { bytes& chars = allsuffixes[i]; int prefix = (i < PREFIX_SKIP_2)? 0: cp_Utf8_prefix.getInt(); + CHECK; int suffix = (int)chars.len; byte* fillp; // by induction, the buffer is already filled with the prefix diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/utils.cpp b/jdk/src/share/native/com/sun/java/util/jar/pack/utils.cpp index 0f770d8064a..e5197e1a3f1 100644 --- a/jdk/src/share/native/com/sun/java/util/jar/pack/utils.cpp +++ b/jdk/src/share/native/com/sun/java/util/jar/pack/utils.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, 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 @@ -52,7 +52,7 @@ void* must_malloc(size_t size) { if (msize >= 0 && msize < sizeof(int)) msize = sizeof(int); // see 0xbaadf00d below #endif - void* ptr = (msize > PSIZE_MAX) ? null : malloc(msize); + void* ptr = (msize > PSIZE_MAX || msize <= 0) ? null : malloc(msize); if (ptr != null) { memset(ptr, 0, size); } else { diff --git a/jdk/src/share/native/com/sun/java/util/jar/pack/utils.h b/jdk/src/share/native/com/sun/java/util/jar/pack/utils.h index d24e5b50ea8..89619316a0e 100644 --- a/jdk/src/share/native/com/sun/java/util/jar/pack/utils.h +++ b/jdk/src/share/native/com/sun/java/util/jar/pack/utils.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, 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 @@ -33,7 +33,7 @@ void mtrace(char c, void* ptr, size_t size); #endif // overflow management -#define OVERFLOW ((size_t)-1) +#define OVERFLOW ((uint)-1) #define PSIZE_MAX (OVERFLOW/2) /* normal size limit */ inline size_t scale_size(size_t size, size_t scale) { From 7faffd3edc7cedcfe8f788e335b5dcee3adc586a Mon Sep 17 00:00:00 2001 From: Abhijit Saha Date: Wed, 20 Jul 2011 09:01:04 -0700 Subject: [PATCH 005/107] 7032417: Fix for 6981922 does not address multiple VM case Reviewed-by: michaelm --- jdk/src/share/classes/sun/net/ResourceManager.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/jdk/src/share/classes/sun/net/ResourceManager.java b/jdk/src/share/classes/sun/net/ResourceManager.java index 11bfc464819..068b8484728 100644 --- a/jdk/src/share/classes/sun/net/ResourceManager.java +++ b/jdk/src/share/classes/sun/net/ResourceManager.java @@ -41,13 +41,14 @@ public class ResourceManager { /* default maximum number of udp sockets per VM * when a security manager is enabled. - * The default is 1024 which is high enough to be useful + * The default is 25 which is high enough to be useful * but low enough to be well below the maximum number - * of port numbers actually available on all OSes for - * such sockets (5000 on some versions of windows) + * of port numbers actually available on all OSes + * when multiplied by the maximum feasible number of VM processes + * that could practically be spawned. */ - private static final int DEFAULT_MAX_SOCKETS = 1024; + private static final int DEFAULT_MAX_SOCKETS = 25; private static final int maxSockets; private static final AtomicInteger numSockets; From fa11842c276cb2a58ce6fbaefbf08fbeecb35ee4 Mon Sep 17 00:00:00 2001 From: Abhijit Saha Date: Wed, 20 Jul 2011 14:45:44 -0700 Subject: [PATCH 006/107] 7023640: calculation for malloc size in TransformHelper.c could overflow an integer Reviewed-by: flar --- .../native/sun/java2d/loops/TransformHelper.c | 57 +++++++++++++------ 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/jdk/src/share/native/sun/java2d/loops/TransformHelper.c b/jdk/src/share/native/sun/java2d/loops/TransformHelper.c index a5117747476..23bba354756 100644 --- a/jdk/src/share/native/sun/java2d/loops/TransformHelper.c +++ b/jdk/src/share/native/sun/java2d/loops/TransformHelper.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2011, 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 @@ -284,7 +284,7 @@ Java_sun_java2d_loops_TransformHelper_Transform TransformHelperFunc *pHelperFunc; TransformInterpFunc *pInterpFunc; jdouble xorig, yorig; - jint numedges; + jlong numedges; jint *pEdges; jint edgebuf[2 + MAXEDGES * 2]; union { @@ -379,19 +379,44 @@ Java_sun_java2d_loops_TransformHelper_Transform } Region_IntersectBounds(&clipInfo, &dstInfo.bounds); - numedges = (dstInfo.bounds.y2 - dstInfo.bounds.y1); - if (numedges > MAXEDGES) { - pEdges = malloc((2 + 2 * numedges) * sizeof (*pEdges)); - if (pEdges == NULL) { - SurfaceData_InvokeUnlock(env, dstOps, &dstInfo); - SurfaceData_InvokeUnlock(env, srcOps, &srcInfo); - /* edgeArray should already contain zeros for min/maxy */ - return; - } + numedges = (((jlong) dstInfo.bounds.y2) - ((jlong) dstInfo.bounds.y1)); + if (numedges <= 0) { + pEdges = NULL; + } else if (!JNU_IsNull(env, edgeArray)) { + /* + * Ideally Java should allocate an array large enough, but if + * we ever have a miscommunication about the number of edge + * lines, or if the Java array calculation should overflow to + * a positive number and succeed in allocating an array that + * is too small, we need to verify that it can still hold the + * number of integers that we plan to store to be safe. + */ + jsize edgesize = (*env)->GetArrayLength(env, edgeArray); + /* (edgesize/2 - 1) should avoid any overflow or underflow. */ + pEdges = (((edgesize / 2) - 1) >= numedges) + ? (*env)->GetPrimitiveArrayCritical(env, edgeArray, NULL) + : NULL; + } else if (numedges > MAXEDGES) { + /* numedges variable (jlong) can be at most ((1<<32)-1) */ + /* memsize can overflow a jint, but not a jlong */ + jlong memsize = ((numedges * 2) + 2) * sizeof(*pEdges); + pEdges = (memsize == ((size_t) memsize)) + ? malloc((size_t) memsize) + : NULL; } else { pEdges = edgebuf; } + if (pEdges == NULL) { + if (numedges > 0) { + JNU_ThrowInternalError(env, "Unable to allocate edge list"); + } + SurfaceData_InvokeUnlock(env, dstOps, &dstInfo); + SurfaceData_InvokeUnlock(env, srcOps, &srcInfo); + /* edgeArray should already contain zeros for min/maxy */ + return; + } + Transform_GetInfo(env, itxform, &itxInfo); if (!Region_IsEmpty(&clipInfo)) { @@ -500,14 +525,14 @@ Java_sun_java2d_loops_TransformHelper_Transform } else { pEdges[0] = pEdges[1] = 0; } - SurfaceData_InvokeUnlock(env, dstOps, &dstInfo); - SurfaceData_InvokeUnlock(env, srcOps, &srcInfo); + if (!JNU_IsNull(env, edgeArray)) { - (*env)->SetIntArrayRegion(env, edgeArray, 0, 2+numedges*2, pEdges); - } - if (pEdges != edgebuf) { + (*env)->ReleasePrimitiveArrayCritical(env, edgeArray, pEdges, 0); + } else if (pEdges != edgebuf) { free(pEdges); } + SurfaceData_InvokeUnlock(env, dstOps, &dstInfo); + SurfaceData_InvokeUnlock(env, srcOps, &srcInfo); } static void From 096686792a8122cf8bac84bc9e5d2b7d489cffd1 Mon Sep 17 00:00:00 2001 From: Denis Fokin Date: Fri, 22 Jul 2011 21:14:56 +0400 Subject: [PATCH 007/107] 7019773: AWTKeyStroke.ctor is a mutable static Reviewed-by: art --- .../share/classes/java/awt/AWTKeyStroke.java | 52 ++++++++++++++----- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/jdk/src/share/classes/java/awt/AWTKeyStroke.java b/jdk/src/share/classes/java/awt/AWTKeyStroke.java index 1f91e4298f6..7ce063df0f4 100644 --- a/jdk/src/share/classes/java/awt/AWTKeyStroke.java +++ b/jdk/src/share/classes/java/awt/AWTKeyStroke.java @@ -25,6 +25,7 @@ package java.awt; import java.awt.event.KeyEvent; +import sun.awt.AppContext; import java.awt.event.InputEvent; import java.util.Collections; import java.util.HashMap; @@ -66,9 +67,6 @@ import java.lang.reflect.Field; public class AWTKeyStroke implements Serializable { static final long serialVersionUID = -6430539691155161871L; - private static Map cache; - private static AWTKeyStroke cacheKey; - private static Constructor ctor = getCtor(AWTKeyStroke.class); private static Map modifierKeywords; /** * Associates VK_XXX (as a String) with code (as Integer). This is @@ -77,6 +75,25 @@ public class AWTKeyStroke implements Serializable { */ private static VKCollection vks; + //A key for the collection of AWTKeyStrokes within AppContext. + private static Object APP_CONTEXT_CACHE_KEY = new Object(); + //A key withing the cache + private static AWTKeyStroke APP_CONTEXT_KEYSTROKE_KEY = new AWTKeyStroke(); + + /* + * Reads keystroke class from AppContext and if null, puts there the + * AWTKeyStroke class. + * Must be called under locked AWTKeyStro + */ + private static Class getAWTKeyStrokeClass() { + Class clazz = (Class)AppContext.getAppContext().get(AWTKeyStroke.class); + if (clazz == null) { + clazz = AWTKeyStroke.class; + AppContext.getAppContext().put(AWTKeyStroke.class, AWTKeyStroke.class); + } + return clazz; + } + private char keyChar = KeyEvent.CHAR_UNDEFINED; private int keyCode = KeyEvent.VK_UNDEFINED; private int modifiers; @@ -164,9 +181,12 @@ public class AWTKeyStroke implements Serializable { if (subclass == null) { throw new IllegalArgumentException("subclass cannot be null"); } - if (AWTKeyStroke.ctor.getDeclaringClass().equals(subclass)) { - // Already registered - return; + synchronized (AWTKeyStroke.class) { + Class keyStrokeClass = (Class)AppContext.getAppContext().get(AWTKeyStroke.class); + if (keyStrokeClass != null && keyStrokeClass.equals(subclass)){ + // Already registered + return; + } } if (!AWTKeyStroke.class.isAssignableFrom(subclass)) { throw new ClassCastException("subclass is not derived from AWTKeyStroke"); @@ -197,9 +217,9 @@ public class AWTKeyStroke implements Serializable { } synchronized (AWTKeyStroke.class) { - AWTKeyStroke.ctor = ctor; - cache = null; - cacheKey = null; + AppContext.getAppContext().put(AWTKeyStroke.class, subclass); + AppContext.getAppContext().remove(APP_CONTEXT_CACHE_KEY); + AppContext.getAppContext().remove(APP_CONTEXT_KEYSTROKE_KEY); } } @@ -229,13 +249,19 @@ public class AWTKeyStroke implements Serializable { private static synchronized AWTKeyStroke getCachedStroke (char keyChar, int keyCode, int modifiers, boolean onKeyRelease) { + Map cache = (Map)AppContext.getAppContext().get(APP_CONTEXT_CACHE_KEY); + AWTKeyStroke cacheKey = (AWTKeyStroke)AppContext.getAppContext().get(APP_CONTEXT_KEYSTROKE_KEY); + if (cache == null) { cache = new HashMap(); + AppContext.getAppContext().put(APP_CONTEXT_CACHE_KEY, cache); } if (cacheKey == null) { try { - cacheKey = (AWTKeyStroke)ctor.newInstance((Object[]) null); + Class clazz = getAWTKeyStrokeClass(); + cacheKey = (AWTKeyStroke)getCtor(clazz).newInstance((Object[]) null); + AppContext.getAppContext().put(APP_CONTEXT_KEYSTROKE_KEY, cacheKey); } catch (InstantiationException e) { assert(false); } catch (IllegalAccessException e) { @@ -253,9 +279,8 @@ public class AWTKeyStroke implements Serializable { if (stroke == null) { stroke = cacheKey; cache.put(stroke, stroke); - cacheKey = null; + AppContext.getAppContext().remove(APP_CONTEXT_KEYSTROKE_KEY); } - return stroke; } @@ -778,7 +803,8 @@ public class AWTKeyStroke implements Serializable { protected Object readResolve() throws java.io.ObjectStreamException { synchronized (AWTKeyStroke.class) { Class newClass = getClass(); - if (!newClass.equals(ctor.getDeclaringClass())) { + Class awtKeyStrokeClass = getAWTKeyStrokeClass(); + if (!newClass.equals(awtKeyStrokeClass)) { registerSubclass(newClass); } return getCachedStroke(keyChar, keyCode, modifiers, onKeyRelease); From 5fb55770ffd02aa0b3848a4bed25499783b66d31 Mon Sep 17 00:00:00 2001 From: Abhijit Saha Date: Mon, 25 Jul 2011 11:38:25 -0700 Subject: [PATCH 008/107] 7046794: Configurable behavior for server-side stacktraces Reviewed-by: ramap --- jaxws/jaxws.properties | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/jaxws/jaxws.properties b/jaxws/jaxws.properties index bd6e153899b..96dab59ffd8 100644 --- a/jaxws/jaxws.properties +++ b/jaxws/jaxws.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2007, 2011, 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 @@ -25,15 +25,15 @@ drops.master.copy.base=${drops.dir} -jaxws_src.bundle.name=jdk7-jaxws2_2_4-b03-2011_05_27.zip -jaxws_src.bundle.md5.checksum=2f5b829ade70f67fe272d0b322e3e702 +jaxws_src.bundle.name=jdk8-jaxws2_2_4-b01-2011_07_22.zip +jaxws_src.bundle.md5.checksum=f64bedd3c512e6b1ca265fda2feb0905 jaxws_src.master.bundle.dir=${drops.master.copy.base} -jaxws_src.master.bundle.url.base=http://download.java.net/glassfish/components/jax-ws/openjdk/jdk7 +jaxws_src.master.bundle.url.base=http://download.java.net/glassfish/components/jax-ws/openjdk/jdk8 -jaf_src.bundle.name=jdk7-jaf-2010_08_19.zip +jaf_src.bundle.name=jdk8-jaf-2011_07_22.zip jaf_src.bundle.md5.checksum=18d15dfd71117daadb332af003d08212 jaf_src.master.bundle.dir=${drops.master.copy.base} -jaf_src.master.bundle.url.base=https://java.net/downloads/jax-ws/JDK7 +jaf_src.master.bundle.url.base=https://java.net/downloads/jax-ws/jdk8 #jaxws_tests.bundle.name=jdk7-jaxws-tests-2009_08_28.zip #jaxws_tests.master.bundle.dir=${drops.master.copy.base} From 28a1130e8ec34d7f03ad230195a8caab3cb70e53 Mon Sep 17 00:00:00 2001 From: Mala Bankal Date: Tue, 9 Aug 2011 05:39:54 -0700 Subject: [PATCH 009/107] 7055902: Oracle Java IIOP Deserialization Type Confusion Remote Code Execution Vulnerability Reviewed-by: coffeys --- .../com/sun/corba/se/impl/io/IIOPInputStream.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/corba/src/share/classes/com/sun/corba/se/impl/io/IIOPInputStream.java b/corba/src/share/classes/com/sun/corba/se/impl/io/IIOPInputStream.java index 1992c25a3c1..9f7008a16f8 100644 --- a/corba/src/share/classes/com/sun/corba/se/impl/io/IIOPInputStream.java +++ b/corba/src/share/classes/com/sun/corba/se/impl/io/IIOPInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2011, 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 @@ -2243,6 +2243,10 @@ public class IIOPInputStream } try { + Class fieldCl = fields[i].getClazz(); + if (objectValue != null && !fieldCl.isInstance(objectValue)) { + throw new IllegalArgumentException(); + } bridge.putObject( o, fields[i].getFieldID(), objectValue ) ; // reflective code: fields[i].getField().set( o, objectValue ) ; } catch (IllegalArgumentException e) { @@ -2553,6 +2557,10 @@ public class IIOPInputStream { try { Field fld = c.getDeclaredField( fieldName ) ; + Class fieldCl = fld.getType(); + if(v != null && !fieldCl.isInstance(v)) { + throw new Exception(); + } long key = bridge.objectFieldOffset( fld ) ; bridge.putObject( o, key, v ) ; } catch (Exception e) { From fcee5390dbb9d0a1fde7753fecb1e89cd58ac811 Mon Sep 17 00:00:00 2001 From: Stuart Marks Date: Tue, 30 Aug 2011 14:30:03 -0700 Subject: [PATCH 010/107] 7077466: fix for RMI DGC Reviewed-by: valeriep --- jdk/src/share/classes/sun/rmi/server/UnicastServerRef.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/jdk/src/share/classes/sun/rmi/server/UnicastServerRef.java b/jdk/src/share/classes/sun/rmi/server/UnicastServerRef.java index 9a0c1afb578..fe199a23137 100644 --- a/jdk/src/share/classes/sun/rmi/server/UnicastServerRef.java +++ b/jdk/src/share/classes/sun/rmi/server/UnicastServerRef.java @@ -390,6 +390,12 @@ public class UnicastServerRef extends UnicastRef ObjectInput in; try { in = call.getInputStream(); + try { + Class clazz = Class.forName("sun.rmi.transport.DGCImpl_Skel"); + if (clazz.isAssignableFrom(skel.getClass())) { + ((MarshalInputStream)in).useCodebaseOnly(); + } + } catch (ClassNotFoundException ignore) { } hash = in.readLong(); } catch (Exception readEx) { throw new UnmarshalException("error unmarshalling call header", From 97583c8f0d159288497d7f8ec43d20105ec2647a Mon Sep 17 00:00:00 2001 From: Stuart Marks Date: Tue, 30 Aug 2011 17:29:36 -0700 Subject: [PATCH 011/107] 7083012: fix for RMI Registry Reviewed-by: jdn, valeriep --- .../sun/rmi/registry/RegistryImpl.java | 81 ++++++++++++++++++- .../classes/sun/rmi/server/LoaderHandler.java | 6 +- 2 files changed, 80 insertions(+), 7 deletions(-) diff --git a/jdk/src/share/classes/sun/rmi/registry/RegistryImpl.java b/jdk/src/share/classes/sun/rmi/registry/RegistryImpl.java index 4878609c088..465260da87b 100644 --- a/jdk/src/share/classes/sun/rmi/registry/RegistryImpl.java +++ b/jdk/src/share/classes/sun/rmi/registry/RegistryImpl.java @@ -38,13 +38,23 @@ import java.rmi.server.ServerNotActiveException; import java.rmi.registry.Registry; import java.rmi.server.RMIClientSocketFactory; import java.rmi.server.RMIServerSocketFactory; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.CodeSource; +import java.security.Policy; import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.security.PermissionCollection; +import java.security.Permissions; +import java.security.ProtectionDomain; import java.text.MessageFormat; +import sun.rmi.server.LoaderHandler; import sun.rmi.server.UnicastServerRef; import sun.rmi.server.UnicastServerRef2; import sun.rmi.transport.LiveRef; import sun.rmi.transport.ObjectTable; import sun.rmi.transport.Target; +import sun.security.action.GetPropertyAction; /** * A "registry" exists on every node that allows RMI connections to @@ -325,6 +335,19 @@ public class RegistryImpl extends java.rmi.server.RemoteServer URL[] urls = sun.misc.URLClassPath.pathToURLs(envcp); ClassLoader cl = new URLClassLoader(urls); + String codebaseProperty = null; + String prop = java.security.AccessController.doPrivileged( + new GetPropertyAction("java.rmi.server.codebase")); + if (prop != null && prop.trim().length() > 0) { + codebaseProperty = prop; + } + URL[] codebaseURLs = null; + if (codebaseProperty != null) { + codebaseURLs = sun.misc.URLClassPath.pathToURLs(codebaseProperty); + } else { + codebaseURLs = new URL[0]; + } + /* * Fix bugid 4242317: Classes defined by this class loader should * be annotated with the value of the "java.rmi.server.codebase" @@ -334,11 +357,19 @@ public class RegistryImpl extends java.rmi.server.RemoteServer Thread.currentThread().setContextClassLoader(cl); - int regPort = Registry.REGISTRY_PORT; - if (args.length >= 1) { - regPort = Integer.parseInt(args[0]); + final int regPort = (args.length >= 1) ? Integer.parseInt(args[0]) + : Registry.REGISTRY_PORT; + try { + registry = AccessController.doPrivileged( + new PrivilegedExceptionAction() { + public RegistryImpl run() throws RemoteException { + return new RegistryImpl(regPort); + } + }, getAccessControlContext(codebaseURLs)); + } catch (PrivilegedActionException ex) { + throw (RemoteException) ex.getException(); } - registry = new RegistryImpl(regPort); + // prevent registry from exiting while (true) { try { @@ -358,4 +389,46 @@ public class RegistryImpl extends java.rmi.server.RemoteServer } System.exit(1); } + + /** + * Generates an AccessControlContext from several URLs. + * The approach used here is taken from the similar method + * getAccessControlContext() in the sun.applet.AppletPanel class. + */ + private static AccessControlContext getAccessControlContext(URL[] urls) { + // begin with permissions granted to all code in current policy + PermissionCollection perms = AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public PermissionCollection run() { + CodeSource codesource = new CodeSource(null, + (java.security.cert.Certificate[]) null); + Policy p = java.security.Policy.getPolicy(); + if (p != null) { + return p.getPermissions(codesource); + } else { + return new Permissions(); + } + } + }); + + /* + * Anyone can connect to the registry and the registry can connect + * to and possibly download stubs from anywhere. Downloaded stubs and + * related classes themselves are more tightly limited by RMI. + */ + perms.add(new SocketPermission("*", "connect,accept")); + + // add permissions required to load from codebase URL path + LoaderHandler.addPermissionsForURLs(urls, perms, false); + + /* + * Create an AccessControlContext that consists of a single + * protection domain with only the permissions calculated above. + */ + ProtectionDomain pd = new ProtectionDomain( + new CodeSource((urls.length > 0 ? urls[0] : null), + (java.security.cert.Certificate[]) null), + perms); + return new AccessControlContext(new ProtectionDomain[] { pd }); + } } diff --git a/jdk/src/share/classes/sun/rmi/server/LoaderHandler.java b/jdk/src/share/classes/sun/rmi/server/LoaderHandler.java index 541c7840e08..52d9ee55172 100644 --- a/jdk/src/share/classes/sun/rmi/server/LoaderHandler.java +++ b/jdk/src/share/classes/sun/rmi/server/LoaderHandler.java @@ -1031,9 +1031,9 @@ public final class LoaderHandler { * loader. A given permission is only added to the collection if * it is not already implied by the collection. */ - private static void addPermissionsForURLs(URL[] urls, - PermissionCollection perms, - boolean forLoader) + public static void addPermissionsForURLs(URL[] urls, + PermissionCollection perms, + boolean forLoader) { for (int i = 0; i < urls.length; i++) { URL url = urls[i]; From 40ce6ba310c438fe4a7608c98feafeb8e5825180 Mon Sep 17 00:00:00 2001 From: Sean Chou Date: Thu, 15 Sep 2011 19:29:07 +0100 Subject: [PATCH 012/107] 6988099: jvmti demos missing Publisher (COMPANY resource) in dlls/exes on windows Add creation/linking of resource data to link step for demos on Windows Reviewed-by: dcubed, zgu, ngmr, ohair --- jdk/make/common/Demo.gmk | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/jdk/make/common/Demo.gmk b/jdk/make/common/Demo.gmk index a3788aea7d5..429c4e546c9 100644 --- a/jdk/make/common/Demo.gmk +++ b/jdk/make/common/Demo.gmk @@ -158,6 +158,8 @@ ifneq ($(strip $(DEMO_ALL_NATIVE_SOURCES)),) # bit between them. LINK.demo = $(LINK.c) LDLIBS.demo = $(EXTRA_LIBS) $(LFLAGS_$(COMPILER_VERSION)) + DEMO_VERSION_INFO = $(OBJDIR)/$(LIBRARY).res + LDLIBS.demo += $(DEMO_VERSION_INFO) else ifneq ($(DEMO_NEEDS_CPP),) LINK.demo = $(LINK.cpp) @@ -288,6 +290,13 @@ ifndef DEMO_SKIP_SRCZIP $(install-file) endif +ifeq ($(PLATFORM),windows) +# JDK name required here +RC_FLAGS += /D "JDK_FNAME=$(LIBRARY).dll" \ + /D "JDK_INTERNAL_NAME=$(LIBRARY)" \ + /D "JDK_FTYPE=0x2L" +endif + # Native library building ifdef DEMO_LIBRARY @@ -308,6 +317,9 @@ $(OBJDIR)/%.$(OBJECT_SUFFIX): $(DEMO_BUILD_SRCDIR)/%.cpp # Actual creation of the native shared library (C++ and C are different) $(DEMO_LIBRARY): $(DEMO_FULL_OBJECTS) @$(prep-target) + ifeq ($(PLATFORM),windows) + $(RC) $(RC_FLAGS) $(CC_OBJECT_OUTPUT_FLAG)$(DEMO_VERSION_INFO) $(VERSIONINFO_RESOURCE) + endif $(LINK.demo) $(SHARED_LIBRARY_FLAG) $(CC_PROGRAM_OUTPUT_FLAG)$@ \ $(DEMO_FULL_OBJECTS) $(LDLIBS.demo) @$(call binary_file_verification,$@) From 6f12fe9039fe90b89f270d444af49f5a01fc1bd7 Mon Sep 17 00:00:00 2001 From: Stuart Marks Date: Wed, 21 Sep 2011 15:37:52 -0700 Subject: [PATCH 013/107] 7092186: adjust package access in rmiregistry Reviewed-by: asaha, coffeys --- jdk/src/share/classes/sun/rmi/registry/RegistryImpl.java | 2 ++ jdk/test/sun/tools/jstatd/jstatdExternalRegistry.sh | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/jdk/src/share/classes/sun/rmi/registry/RegistryImpl.java b/jdk/src/share/classes/sun/rmi/registry/RegistryImpl.java index 465260da87b..db18eb3364d 100644 --- a/jdk/src/share/classes/sun/rmi/registry/RegistryImpl.java +++ b/jdk/src/share/classes/sun/rmi/registry/RegistryImpl.java @@ -418,6 +418,8 @@ public class RegistryImpl extends java.rmi.server.RemoteServer */ perms.add(new SocketPermission("*", "connect,accept")); + perms.add(new RuntimePermission("accessClassInPackage.sun.*")); + // add permissions required to load from codebase URL path LoaderHandler.addPermissionsForURLs(urls, perms, false); diff --git a/jdk/test/sun/tools/jstatd/jstatdExternalRegistry.sh b/jdk/test/sun/tools/jstatd/jstatdExternalRegistry.sh index ba960c26dd8..55786096b40 100644 --- a/jdk/test/sun/tools/jstatd/jstatdExternalRegistry.sh +++ b/jdk/test/sun/tools/jstatd/jstatdExternalRegistry.sh @@ -22,7 +22,7 @@ # # @test -# @bug 4990825 +# @bug 4990825 7092186 # @run shell/timeout=90 jstatdExternalRegistry.sh # @summary Test functionality of 'jstatd -p&' with an external RMI registry From 2a7fbdb25b205e1bc5050f32b2d0a43c31e78e25 Mon Sep 17 00:00:00 2001 From: Neil Richards Date: Fri, 23 Sep 2011 15:18:32 +0100 Subject: [PATCH 014/107] 7105640: Unix printing does not check the result of exec'd lpr/lp command Add checking, exception for spool process failure Reviewed-by: prr, jgodinez --- .../share/classes/sun/print/PSPrinterJob.java | 43 ++++++++++++++++--- .../classes/sun/print/UnixPrintJob.java | 41 +++++++++++++++--- 2 files changed, 72 insertions(+), 12 deletions(-) diff --git a/jdk/src/share/classes/sun/print/PSPrinterJob.java b/jdk/src/share/classes/sun/print/PSPrinterJob.java index 722537ea571..d4a0ffacb20 100644 --- a/jdk/src/share/classes/sun/print/PSPrinterJob.java +++ b/jdk/src/share/classes/sun/print/PSPrinterJob.java @@ -68,14 +68,18 @@ import javax.print.attribute.standard.Sides; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; +import java.io.BufferedReader; import java.io.CharConversionException; import java.io.File; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.IOException; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.OutputStream; import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.StringWriter; import java.util.ArrayList; import java.util.Enumeration; @@ -673,15 +677,38 @@ public class PSPrinterJob extends RasterPrinterJob { private class PrinterSpooler implements java.security.PrivilegedAction { PrinterException pex; + private void handleProcessFailure(final Process failedProcess, + final String[] execCmd, final int result) throws IOException { + try (StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw)) { + pw.append("error=").append(Integer.toString(result)); + pw.append(" running:"); + for (String arg: execCmd) { + pw.append(" '").append(arg).append("'"); + } + try (InputStream is = failedProcess.getErrorStream(); + InputStreamReader isr = new InputStreamReader(is); + BufferedReader br = new BufferedReader(isr)) { + while (br.ready()) { + pw.println(); + pw.append("\t\t").append(br.readLine()); + } + } finally { + pw.flush(); + throw new IOException(sw.toString()); + } + } + } + public Object run() { + if (spoolFile == null || !spoolFile.exists()) { + pex = new PrinterException("No spool file"); + return null; + } try { /** * Spool to the printer. */ - if (spoolFile == null || !spoolFile.exists()) { - pex = new PrinterException("No spool file"); - return null; - } String fileName = spoolFile.getAbsolutePath(); String execCmd[] = printExecCmd(mDestination, mOptions, mNoJobSheet, getJobNameInt(), @@ -689,12 +716,16 @@ public class PSPrinterJob extends RasterPrinterJob { Process process = Runtime.getRuntime().exec(execCmd); process.waitFor(); - spoolFile.delete(); - + final int result = process.exitValue(); + if (0 != result) { + handleProcessFailure(process, execCmd, result); + } } catch (IOException ex) { pex = new PrinterIOException(ex); } catch (InterruptedException ie) { pex = new PrinterException(ie.toString()); + } finally { + spoolFile.delete(); } return null; } diff --git a/jdk/src/solaris/classes/sun/print/UnixPrintJob.java b/jdk/src/solaris/classes/sun/print/UnixPrintJob.java index 912442a6540..206650de40e 100644 --- a/jdk/src/solaris/classes/sun/print/UnixPrintJob.java +++ b/jdk/src/solaris/classes/sun/print/UnixPrintJob.java @@ -38,7 +38,9 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.IOException; +import java.io.PrintWriter; import java.io.Reader; +import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.util.Vector; @@ -955,23 +957,49 @@ public class UnixPrintJob implements CancelablePrintJob { private class PrinterSpooler implements java.security.PrivilegedAction { PrintException pex; + private void handleProcessFailure(final Process failedProcess, + final String[] execCmd, final int result) throws IOException { + try (StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw)) { + pw.append("error=").append(Integer.toString(result)); + pw.append(" running:"); + for (String arg: execCmd) { + pw.append(" '").append(arg).append("'"); + } + try (InputStream is = failedProcess.getErrorStream(); + InputStreamReader isr = new InputStreamReader(is); + BufferedReader br = new BufferedReader(isr)) { + while (br.ready()) { + pw.println(); + pw.append("\t\t").append(br.readLine()); + } + } finally { + pw.flush(); + throw new IOException(sw.toString()); + } + } + } + public Object run() { + if (spoolFile == null || !spoolFile.exists()) { + pex = new PrintException("No spool file"); + notifyEvent(PrintJobEvent.JOB_FAILED); + return null; + } try { /** * Spool to the printer. */ - if (spoolFile == null || !spoolFile.exists()) { - pex = new PrintException("No spool file"); - notifyEvent(PrintJobEvent.JOB_FAILED); - return null; - } String fileName = spoolFile.getAbsolutePath(); String execCmd[] = printExecCmd(mDestination, mOptions, mNoJobSheet, jobName, copies, fileName); Process process = Runtime.getRuntime().exec(execCmd); process.waitFor(); - spoolFile.delete(); + final int result = process.exitValue(); + if (0 != result) { + handleProcessFailure(process, execCmd, result); + } notifyEvent(PrintJobEvent.DATA_TRANSFER_COMPLETE); } catch (IOException ex) { notifyEvent(PrintJobEvent.JOB_FAILED); @@ -981,6 +1009,7 @@ public class UnixPrintJob implements CancelablePrintJob { notifyEvent(PrintJobEvent.JOB_FAILED); pex = new PrintException(ie); } finally { + spoolFile.delete(); notifyEvent(PrintJobEvent.NO_MORE_EVENTS); } return null; From 73b50710f031dbd89f75e56a8f03c008bdc3255a Mon Sep 17 00:00:00 2001 From: Xue-Lei Andrew Fan Date: Thu, 29 Sep 2011 17:31:30 -0700 Subject: [PATCH 015/107] 7064341: jsse/runtime security problem Reviewed-by: wetmore --- .../classes/javax/net/ssl/SSLEngine.java | 4 +- .../sun/security/ssl/AppOutputStream.java | 30 +++++++++++- .../classes/sun/security/ssl/CipherBox.java | 17 ++++++- .../classes/sun/security/ssl/CipherSuite.java | 13 ++++- .../sun/security/ssl/EngineOutputRecord.java | 47 +++++++++++++++++-- .../classes/sun/security/ssl/Record.java | 19 +++++++- .../sun/security/ssl/SSLEngineImpl.java | 34 ++++++++++++++ .../sun/security/ssl/SSLSocketImpl.java | 35 ++++++++++++++ .../ssl/NewAPIs/SSLEngine/CheckStatus.java | 4 +- .../net/ssl/NewAPIs/SSLEngine/LargeBufs.java | 4 +- .../ssl/NewAPIs/SSLEngine/LargePacket.java | 4 +- 11 files changed, 197 insertions(+), 14 deletions(-) diff --git a/jdk/src/share/classes/javax/net/ssl/SSLEngine.java b/jdk/src/share/classes/javax/net/ssl/SSLEngine.java index 2eea55121cb..411626cd7a1 100644 --- a/jdk/src/share/classes/javax/net/ssl/SSLEngine.java +++ b/jdk/src/share/classes/javax/net/ssl/SSLEngine.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2011, 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 @@ -538,7 +538,7 @@ public abstract class SSLEngine { * If this SSLEngine has not yet started its initial * handshake, this method will automatically start the handshake. *

- * This method will attempt to produce one SSL/TLS packet, and will + * This method will attempt to produce SSL/TLS records, and will * consume as much source data as possible, but will never consume * more than the sum of the bytes remaining in each buffer. Each * ByteBuffer's position is updated to reflect the diff --git a/jdk/src/share/classes/sun/security/ssl/AppOutputStream.java b/jdk/src/share/classes/sun/security/ssl/AppOutputStream.java index 34f3be6d6a5..6be00b8e2d1 100644 --- a/jdk/src/share/classes/sun/security/ssl/AppOutputStream.java +++ b/jdk/src/share/classes/sun/security/ssl/AppOutputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2011, 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 @@ -69,12 +69,38 @@ class AppOutputStream extends OutputStream { // check if the Socket is invalid (error or closed) c.checkWrite(); + /* + * By default, we counter chosen plaintext issues on CBC mode + * ciphersuites in SSLv3/TLS1.0 by sending one byte of application + * data in the first record of every payload, and the rest in + * subsequent record(s). Note that the issues have been solved in + * TLS 1.1 or later. + * + * It is not necessary to split the very first application record of + * a freshly negotiated TLS session, as there is no previous + * application data to guess. To improve compatibility, we will not + * split such records. + * + * This avoids issues in the outbound direction. For a full fix, + * the peer must have similar protections. + */ + boolean isFirstRecordOfThePayload = true; + // Always flush at the end of each application level record. // This lets application synchronize read and write streams // however they like; if we buffered here, they couldn't. try { do { - int howmuch = Math.min(len, r.availableDataBytes()); + int howmuch; + if (isFirstRecordOfThePayload && c.needToSplitPayload()) { + howmuch = Math.min(0x01, r.availableDataBytes()); + } else { + howmuch = Math.min(len, r.availableDataBytes()); + } + + if (isFirstRecordOfThePayload && howmuch != 0) { + isFirstRecordOfThePayload = false; + } // NOTE: *must* call c.writeRecord() even for howmuch == 0 if (howmuch > 0) { diff --git a/jdk/src/share/classes/sun/security/ssl/CipherBox.java b/jdk/src/share/classes/sun/security/ssl/CipherBox.java index 91f9f36198d..22ef091eee6 100644 --- a/jdk/src/share/classes/sun/security/ssl/CipherBox.java +++ b/jdk/src/share/classes/sun/security/ssl/CipherBox.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2011, 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 @@ -112,6 +112,11 @@ final class CipherBox { */ private SecureRandom random; + /** + * Is the cipher of CBC mode? + */ + private final boolean isCBCMode; + /** * Fixed masks of various block size, as the initial decryption IVs * for TLS 1.1 or later. @@ -128,6 +133,7 @@ final class CipherBox { private CipherBox() { this.protocolVersion = ProtocolVersion.DEFAULT; this.cipher = null; + this.isCBCMode = false; } /** @@ -148,6 +154,7 @@ final class CipherBox { random = JsseJce.getSecureRandom(); } this.random = random; + this.isCBCMode = bulkCipher.isCBCMode; /* * RFC 4346 recommends two algorithms used to generated the @@ -691,4 +698,12 @@ final class CipherBox { } } + /* + * Does the cipher use CBC mode? + * + * @return true if the cipher use CBC mode, false otherwise. + */ + boolean isCBCMode() { + return isCBCMode; + } } diff --git a/jdk/src/share/classes/sun/security/ssl/CipherSuite.java b/jdk/src/share/classes/sun/security/ssl/CipherSuite.java index 38734b75bf6..b87ddb173db 100644 --- a/jdk/src/share/classes/sun/security/ssl/CipherSuite.java +++ b/jdk/src/share/classes/sun/security/ssl/CipherSuite.java @@ -420,10 +420,16 @@ final class CipherSuite implements Comparable { // exportable under 512/40 bit rules final boolean exportable; + // Is the cipher algorithm of Cipher Block Chaining (CBC) mode? + final boolean isCBCMode; + BulkCipher(String transformation, int keySize, int expandedKeySize, int ivSize, boolean allowed) { this.transformation = transformation; - this.algorithm = transformation.split("/")[0]; + String[] splits = transformation.split("/"); + this.algorithm = splits[0]; + this.isCBCMode = + splits.length <= 1 ? false : "CBC".equalsIgnoreCase(splits[1]); this.description = this.algorithm + "/" + (keySize << 3); this.keySize = keySize; this.ivSize = ivSize; @@ -436,7 +442,10 @@ final class CipherSuite implements Comparable { BulkCipher(String transformation, int keySize, int ivSize, boolean allowed) { this.transformation = transformation; - this.algorithm = transformation.split("/")[0]; + String[] splits = transformation.split("/"); + this.algorithm = splits[0]; + this.isCBCMode = + splits.length <= 1 ? false : "CBC".equalsIgnoreCase(splits[1]); this.description = this.algorithm + "/" + (keySize << 3); this.keySize = keySize; this.ivSize = ivSize; diff --git a/jdk/src/share/classes/sun/security/ssl/EngineOutputRecord.java b/jdk/src/share/classes/sun/security/ssl/EngineOutputRecord.java index 60a428396e4..707fd04f8d3 100644 --- a/jdk/src/share/classes/sun/security/ssl/EngineOutputRecord.java +++ b/jdk/src/share/classes/sun/security/ssl/EngineOutputRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2011, 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 @@ -46,6 +46,7 @@ import sun.misc.HexDumpEncoder; */ final class EngineOutputRecord extends OutputRecord { + private SSLEngineImpl engine; private EngineWriter writer; private boolean finishedMsg = false; @@ -62,6 +63,7 @@ final class EngineOutputRecord extends OutputRecord { */ EngineOutputRecord(byte type, SSLEngineImpl engine) { super(type, recordSize(type)); + this.engine = engine; writer = engine.writer; } @@ -227,11 +229,50 @@ final class EngineOutputRecord extends OutputRecord { * implementations are fragile and don't like to see empty * records, so this increases robustness. */ - int length = Math.min(ea.getAppRemaining(), maxDataSize); - if (length == 0) { + if (ea.getAppRemaining() == 0) { return; } + /* + * By default, we counter chosen plaintext issues on CBC mode + * ciphersuites in SSLv3/TLS1.0 by sending one byte of application + * data in the first record of every payload, and the rest in + * subsequent record(s). Note that the issues have been solved in + * TLS 1.1 or later. + * + * It is not necessary to split the very first application record of + * a freshly negotiated TLS session, as there is no previous + * application data to guess. To improve compatibility, we will not + * split such records. + * + * Because of the compatibility, we'd better produce no more than + * SSLSession.getPacketBufferSize() net data for each wrap. As we + * need a one-byte record at first, the 2nd record size should be + * equal to or less than Record.maxDataSizeMinusOneByteRecord. + * + * This avoids issues in the outbound direction. For a full fix, + * the peer must have similar protections. + */ + int length; + if (engine.needToSplitPayload(writeCipher, protocolVersion)) { + write(ea, writeMAC, writeCipher, 0x01); + ea.resetLim(); // reset application data buffer limit + length = Math.min(ea.getAppRemaining(), + maxDataSizeMinusOneByteRecord); + } else { + length = Math.min(ea.getAppRemaining(), maxDataSize); + } + + // Don't bother to really write empty records. + if (length > 0) { + write(ea, writeMAC, writeCipher, length); + } + + return; + } + + void write(EngineArgs ea, MAC writeMAC, CipherBox writeCipher, + int length) throws IOException { /* * Copy out existing buffer values. */ diff --git a/jdk/src/share/classes/sun/security/ssl/Record.java b/jdk/src/share/classes/sun/security/ssl/Record.java index 1378e107afc..92c8a3ebbe0 100644 --- a/jdk/src/share/classes/sun/security/ssl/Record.java +++ b/jdk/src/share/classes/sun/security/ssl/Record.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2011, 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 @@ -67,6 +67,23 @@ interface Record { + maxPadding // padding + trailerSize; // MAC + static final boolean enableCBCProtection = + Debug.getBooleanProperty("jsse.enableCBCProtection", true); + + /* + * For CBC protection in SSL3/TLS1, we break some plaintext into two + * packets. Max application data size for the second packet. + */ + static final int maxDataSizeMinusOneByteRecord = + maxDataSize // max data size + - ( // max one byte record size + headerSize // header + + maxIVLength // iv + + 1 // one byte data + + maxPadding // padding + + trailerSize // MAC + ); + /* * The maximum large record size. * diff --git a/jdk/src/share/classes/sun/security/ssl/SSLEngineImpl.java b/jdk/src/share/classes/sun/security/ssl/SSLEngineImpl.java index ce78c10cc3c..c9df474a4eb 100644 --- a/jdk/src/share/classes/sun/security/ssl/SSLEngineImpl.java +++ b/jdk/src/share/classes/sun/security/ssl/SSLEngineImpl.java @@ -311,6 +311,11 @@ final public class SSLEngineImpl extends SSLEngine { private Object unwrapLock; Object writeLock; + /* + * Is it the first application record to write? + */ + private boolean isFirstAppOutputRecord = true; + /* * Class and subclass dynamic debugging support */ @@ -617,6 +622,9 @@ final public class SSLEngineImpl extends SSLEngine { // See comment above. oldCipher.dispose(); + + // reset the flag of the first application record + isFirstAppOutputRecord = true; } /* @@ -1295,9 +1303,35 @@ final public class SSLEngineImpl extends SSLEngine { } } + /* + * turn off the flag of the first application record if we really + * consumed at least byte. + */ + if (isFirstAppOutputRecord && ea.deltaApp() > 0) { + isFirstAppOutputRecord = false; + } + return hsStatus; } + /* + * Need to split the payload except the following cases: + * + * 1. protocol version is TLS 1.1 or later; + * 2. bulk cipher does not use CBC mode, including null bulk cipher suites. + * 3. the payload is the first application record of a freshly + * negotiated TLS session. + * 4. the CBC protection is disabled; + * + * More details, please refer to + * EngineOutputRecord.write(EngineArgs, MAC, CipherBox). + */ + boolean needToSplitPayload(CipherBox cipher, ProtocolVersion protocol) { + return (protocol.v <= ProtocolVersion.TLS10.v) && + cipher.isCBCMode() && !isFirstAppOutputRecord && + Record.enableCBCProtection; + } + /* * Non-application OutputRecords go through here. */ diff --git a/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java b/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java index d12eaf1c091..193a45fc3be 100644 --- a/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java +++ b/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java @@ -371,6 +371,11 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { /* Class and subclass dynamic debugging support */ private static final Debug debug = Debug.getInstance("ssl"); + /* + * Is it the first application record to write? + */ + private boolean isFirstAppOutputRecord = true; + // // CONSTRUCTORS AND INITIALIZATION CODE // @@ -804,8 +809,35 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { if (connectionState < cs_ERROR) { checkSequenceNumber(writeMAC, r.contentType()); } + + // turn off the flag of the first application record + if (isFirstAppOutputRecord && + r.contentType() == Record.ct_application_data) { + isFirstAppOutputRecord = false; + } } + /* + * Need to split the payload except the following cases: + * + * 1. protocol version is TLS 1.1 or later; + * 2. bulk cipher does not use CBC mode, including null bulk cipher suites. + * 3. the payload is the first application record of a freshly + * negotiated TLS session. + * 4. the CBC protection is disabled; + * + * More details, please refer to AppOutputStream.write(byte[], int, int). + */ + boolean needToSplitPayload() { + writeLock.lock(); + try { + return (protocolVersion.v <= ProtocolVersion.TLS10.v) && + writeCipher.isCBCMode() && !isFirstAppOutputRecord && + Record.enableCBCProtection; + } finally { + writeLock.unlock(); + } + } /* * Read an application data record. Alerts and handshake @@ -2034,6 +2066,9 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { // See comment above. oldCipher.dispose(); + + // reset the flag of the first application record + isFirstAppOutputRecord = true; } /* diff --git a/jdk/test/sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/CheckStatus.java b/jdk/test/sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/CheckStatus.java index c29f55a04b9..dfdefa9f1f7 100644 --- a/jdk/test/sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/CheckStatus.java +++ b/jdk/test/sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/CheckStatus.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2011, 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 @@ -29,6 +29,8 @@ * This is a simple hack to test a bunch of conditions and check * their return codes. * + * @run main/othervm -Djsse.enableCBCProtection=false CheckStatus + * * @author Brad Wetmore */ diff --git a/jdk/test/sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/LargeBufs.java b/jdk/test/sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/LargeBufs.java index 849e739c823..5960ea63992 100644 --- a/jdk/test/sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/LargeBufs.java +++ b/jdk/test/sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/LargeBufs.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2011, 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 @@ -30,6 +30,8 @@ * This is to test larger buffer arrays, and make sure the maximum * is being passed. * + * @run main/othervm -Djsse.enableCBCProtection=false LargeBufs + * * @author Brad R. Wetmore */ diff --git a/jdk/test/sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/LargePacket.java b/jdk/test/sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/LargePacket.java index 4699958dcfa..a58e19a1aa8 100644 --- a/jdk/test/sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/LargePacket.java +++ b/jdk/test/sun/security/ssl/javax/net/ssl/NewAPIs/SSLEngine/LargePacket.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2011, 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 @@ -28,6 +28,8 @@ * @summary Need adjustable TLS max record size for interoperability * with non-compliant * + * @run main/othervm -Djsse.enableCBCProtection=false LargePacket + * * @author Xuelei Fan */ From 3c41c66fb1445711847ba8150a3dbf912ef7e8c3 Mon Sep 17 00:00:00 2001 From: Xue-Lei Andrew Fan Date: Fri, 30 Sep 2011 18:47:53 -0700 Subject: [PATCH 016/107] 7096936: issue in jsse/runtime 7096937: TEST: com/sun/net/ssl/internal/ssl/GenSSLConfigs/main.java need modification as a result of TLS fix Reviewed-by: wetmore, jdn, xuelei --- .../classes/com/sun/net/ssl/HttpsURLConnection.java | 8 +++++++- .../share/classes/javax/net/ssl/HttpsURLConnection.java | 9 ++++++++- .../com/sun/net/ssl/internal/ssl/GenSSLConfigs/main.java | 2 +- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/jdk/src/share/classes/com/sun/net/ssl/HttpsURLConnection.java b/jdk/src/share/classes/com/sun/net/ssl/HttpsURLConnection.java index c17fcf72136..c60435331ec 100644 --- a/jdk/src/share/classes/com/sun/net/ssl/HttpsURLConnection.java +++ b/jdk/src/share/classes/com/sun/net/ssl/HttpsURLConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2011, 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 @@ -179,6 +179,12 @@ class HttpsURLConnection extends HttpURLConnection throw new IllegalArgumentException( "no SSLSocketFactory specified"); } + + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkSetFactory(); + } + sslSocketFactory = sf; } diff --git a/jdk/src/share/classes/javax/net/ssl/HttpsURLConnection.java b/jdk/src/share/classes/javax/net/ssl/HttpsURLConnection.java index 6d799e3ff5f..791401ff555 100644 --- a/jdk/src/share/classes/javax/net/ssl/HttpsURLConnection.java +++ b/jdk/src/share/classes/javax/net/ssl/HttpsURLConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2011, 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 @@ -349,6 +349,9 @@ class HttpsURLConnection extends HttpURLConnection * @param sf the SSL socket factory * @throws IllegalArgumentException if the SSLSocketFactory * parameter is null. + * @throws SecurityException if a security manager exists and its + * checkSetFactory method does not allow + * a socket factory to be specified. * @see #getSSLSocketFactory() */ public void setSSLSocketFactory(SSLSocketFactory sf) { @@ -357,6 +360,10 @@ class HttpsURLConnection extends HttpURLConnection "no SSLSocketFactory specified"); } + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkSetFactory(); + } sslSocketFactory = sf; } diff --git a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/GenSSLConfigs/main.java b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/GenSSLConfigs/main.java index 5cd66b21ca8..432aed4ffe3 100644 --- a/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/GenSSLConfigs/main.java +++ b/jdk/test/sun/security/ssl/com/sun/net/ssl/internal/ssl/GenSSLConfigs/main.java @@ -1,7 +1,7 @@ /* * @test * @build TestThread Traffic Handler ServerHandler ServerThread ClientThread - * @run main/timeout=140 main + * @run main/othervm/timeout=140 -Djsse.enableCBCProtection=false main * @summary Make sure that different configurations of SSL sockets work */ From 224bf60e3077ccba0a008805ef3aea70725f5cae Mon Sep 17 00:00:00 2001 From: Alexandr Scherbatiy Date: Mon, 17 Oct 2011 15:10:42 +0400 Subject: [PATCH 017/107] 7099251: javax.swing.text.html.HTMLDocument.insertAfterStart(null, something) throws NPE Reviewed-by: rupashka --- .../share/classes/javax/swing/text/html/HTMLDocument.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/jdk/src/share/classes/javax/swing/text/html/HTMLDocument.java b/jdk/src/share/classes/javax/swing/text/html/HTMLDocument.java index 5fc8c0f2bf4..a1f99e9cae8 100644 --- a/jdk/src/share/classes/javax/swing/text/html/HTMLDocument.java +++ b/jdk/src/share/classes/javax/swing/text/html/HTMLDocument.java @@ -1181,7 +1181,12 @@ public class HTMLDocument extends DefaultStyledDocument { public void insertAfterStart(Element elem, String htmlText) throws BadLocationException, IOException { verifyParser(); - if (elem != null && elem.isLeaf()) { + + if (elem == null || htmlText == null) { + return; + } + + if (elem.isLeaf()) { throw new IllegalArgumentException ("Can not insert HTML after start of a leaf"); } From 0819253023952f7a9de44a3f6b88134ddf75758d Mon Sep 17 00:00:00 2001 From: Alexandr Scherbatiy Date: Mon, 17 Oct 2011 16:40:34 +0400 Subject: [PATCH 018/107] 7100004: javax.swing.JTable.setAutoCreateRowSorter(boolean autoCreateRowSorter) should mention default value Reviewed-by: rupashka --- jdk/src/share/classes/javax/swing/JTable.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jdk/src/share/classes/javax/swing/JTable.java b/jdk/src/share/classes/javax/swing/JTable.java index 386b2a4628a..6314cb0a207 100644 --- a/jdk/src/share/classes/javax/swing/JTable.java +++ b/jdk/src/share/classes/javax/swing/JTable.java @@ -1828,6 +1828,8 @@ public class JTable extends JComponent implements TableModelListener, Scrollable * table. While the {@code autoCreateRowSorter} property remains * {@code true}, every time the model is changed, a new {@code * TableRowSorter} is created and set as the table's row sorter. + * The default value for the {@code autoCreateRowSorter} + * property is {@code false}. * * @param autoCreateRowSorter whether or not a {@code RowSorter} * should be automatically created From 45109520ef121f3e1b1fdab0025e0eb3d98f4041 Mon Sep 17 00:00:00 2001 From: Alexandr Scherbatiy Date: Mon, 17 Oct 2011 17:19:43 +0400 Subject: [PATCH 019/107] 7077293: javax/swing/JComponent/4337267/bug4337267.java failed on windows 2003 Reviewed-by: rupashka --- .../classes/sun/swing/SwingUtilities2.java | 77 +++++++++++-------- 1 file changed, 44 insertions(+), 33 deletions(-) diff --git a/jdk/src/share/classes/sun/swing/SwingUtilities2.java b/jdk/src/share/classes/sun/swing/SwingUtilities2.java index fc7fbf43f13..2094ec0c11d 100644 --- a/jdk/src/share/classes/sun/swing/SwingUtilities2.java +++ b/jdk/src/share/classes/sun/swing/SwingUtilities2.java @@ -524,56 +524,67 @@ public class SwingUtilities2 { } // If we get here we're not printing - AATextInfo info = drawTextAntialiased(c); - if (info != null && (g instanceof Graphics2D)) { + if (g instanceof Graphics2D) { + AATextInfo info = drawTextAntialiased(c); Graphics2D g2 = (Graphics2D)g; - Object oldContrast = null; - Object oldAAValue = g2.getRenderingHint(KEY_TEXT_ANTIALIASING); - if (info.aaHint != oldAAValue) { - g2.setRenderingHint(KEY_TEXT_ANTIALIASING, info.aaHint); - } else { - oldAAValue = null; - } - if (info.lcdContrastHint != null) { - oldContrast = g2.getRenderingHint(KEY_TEXT_LCD_CONTRAST); - if (info.lcdContrastHint.equals(oldContrast)) { - oldContrast = null; - } else { - g2.setRenderingHint(KEY_TEXT_LCD_CONTRAST, - info.lcdContrastHint); - } - } - boolean needsTextLayout = ((c != null) && (c.getClientProperty(TextAttribute.NUMERIC_SHAPING) != null)); + if (needsTextLayout) { synchronized(charsBufferLock) { int length = syncCharsBuffer(text); needsTextLayout = isComplexLayout(charsBuffer, 0, length); } } - if (needsTextLayout) { + + if (info != null) { + Object oldContrast = null; + Object oldAAValue = g2.getRenderingHint(KEY_TEXT_ANTIALIASING); + if (info.aaHint != oldAAValue) { + g2.setRenderingHint(KEY_TEXT_ANTIALIASING, info.aaHint); + } else { + oldAAValue = null; + } + if (info.lcdContrastHint != null) { + oldContrast = g2.getRenderingHint(KEY_TEXT_LCD_CONTRAST); + if (info.lcdContrastHint.equals(oldContrast)) { + oldContrast = null; + } else { + g2.setRenderingHint(KEY_TEXT_LCD_CONTRAST, + info.lcdContrastHint); + } + } + + if (needsTextLayout) { + TextLayout layout = createTextLayout(c, text, g2.getFont(), + g2.getFontRenderContext()); + layout.draw(g2, x, y); + } else { + g.drawString(text, x, y); + } + + if (oldAAValue != null) { + g2.setRenderingHint(KEY_TEXT_ANTIALIASING, oldAAValue); + } + if (oldContrast != null) { + g2.setRenderingHint(KEY_TEXT_LCD_CONTRAST, oldContrast); + } + + return; + } + + if (needsTextLayout){ TextLayout layout = createTextLayout(c, text, g2.getFont(), g2.getFontRenderContext()); layout.draw(g2, x, y); - } else { - g.drawString(text, x, y); + return; } + } - if (oldAAValue != null) { - g2.setRenderingHint(KEY_TEXT_ANTIALIASING, oldAAValue); - } - if (oldContrast != null) { - g2.setRenderingHint(KEY_TEXT_LCD_CONTRAST, oldContrast); - } - } - else { - g.drawString(text, x, y); - } + g.drawString(text, x, y); } - /** * Draws the string at the specified location underlining the specified * character. From 756974b448e19de1a4f6858e6f528cefd478c0d0 Mon Sep 17 00:00:00 2001 From: David Buck Date: Mon, 17 Oct 2011 19:06:24 -0700 Subject: [PATCH 020/107] 6887286: StackOverflowError at sun.awt.image.ImageWatched$WeakLink.isWatcher Fixed OffScreenImageSource to call imageComplete() with SINGLEFAMEDONE, not STATICIMAGEDONE. This fixed memory leak (that caused SOFE when we use recursion to iterate over linked list). Reviewed-by: bae --- jdk/src/share/classes/sun/awt/image/OffScreenImageSource.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdk/src/share/classes/sun/awt/image/OffScreenImageSource.java b/jdk/src/share/classes/sun/awt/image/OffScreenImageSource.java index 7e8e2dbc795..2b85b6b6d84 100644 --- a/jdk/src/share/classes/sun/awt/image/OffScreenImageSource.java +++ b/jdk/src/share/classes/sun/awt/image/OffScreenImageSource.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2011, 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 @@ -185,7 +185,7 @@ public class OffScreenImageSource implements ImageProducer { theConsumer.setDimensions(image.getWidth(), image.getHeight()); theConsumer.setProperties(properties); sendPixels(); - theConsumer.imageComplete(ImageConsumer.SINGLEFRAMEDONE); + theConsumer.imageComplete(ImageConsumer.STATICIMAGEDONE); } catch (NullPointerException e) { if (theConsumer != null) { theConsumer.imageComplete(ImageConsumer.IMAGEERROR); From 60689cf49bbd52f9daaab6443621686bf4dacbbf Mon Sep 17 00:00:00 2001 From: Federico Tello Gentile Date: Tue, 1 Nov 2011 18:01:58 +0300 Subject: [PATCH 021/107] 7104625: sun.awt.X11.XEvent is creating 600 MB of char[] for no good reason Wrap logging calls with if(){} statements Reviewed-by: anthony, son --- .../classes/sun/awt/X11/XComponentPeer.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/jdk/src/solaris/classes/sun/awt/X11/XComponentPeer.java b/jdk/src/solaris/classes/sun/awt/X11/XComponentPeer.java index 7dd3812899e..6375a7b0cfb 100644 --- a/jdk/src/solaris/classes/sun/awt/X11/XComponentPeer.java +++ b/jdk/src/solaris/classes/sun/awt/X11/XComponentPeer.java @@ -466,12 +466,16 @@ public class XComponentPeer extends XWindow implements ComponentPeer, DropTarget if (true) { switch(e.getID()) { case PaintEvent.UPDATE: - log.finer("XCP coalescePaintEvent : UPDATE : add : x = " + + if (log.isLoggable(PlatformLogger.FINER)) { + log.finer("XCP coalescePaintEvent : UPDATE : add : x = " + r.x + ", y = " + r.y + ", width = " + r.width + ",height = " + r.height); + } return; case PaintEvent.PAINT: - log.finer("XCP coalescePaintEvent : PAINT : add : x = " + + if (log.isLoggable(PlatformLogger.FINER)) { + log.finer("XCP coalescePaintEvent : PAINT : add : x = " + r.x + ", y = " + r.y + ", width = " + r.width + ",height = " + r.height); + } return; } } @@ -1248,7 +1252,9 @@ public class XComponentPeer extends XWindow implements ComponentPeer, DropTarget * ButtonPress, ButtonRelease, KeyPress, KeyRelease, EnterNotify, LeaveNotify, MotionNotify */ protected boolean isEventDisabled(XEvent e) { - enableLog.finest("Component is {1}, checking for disabled event {0}", e, (isEnabled()?"enabled":"disable")); + if (enableLog.isLoggable(PlatformLogger.FINEST)) { + enableLog.finest("Component is {1}, checking for disabled event {0}", e, (isEnabled()?"enabled":"disable")); + } if (!isEnabled()) { switch (e.get_type()) { case XConstants.ButtonPress: @@ -1258,7 +1264,9 @@ public class XComponentPeer extends XWindow implements ComponentPeer, DropTarget case XConstants.EnterNotify: case XConstants.LeaveNotify: case XConstants.MotionNotify: - enableLog.finer("Event {0} is disable", e); + if (enableLog.isLoggable(PlatformLogger.FINER)) { + enableLog.finer("Event {0} is disable", e); + } return true; } } From d3cb1a4bdd713c692faed95e6457235bd4806a5b Mon Sep 17 00:00:00 2001 From: Federico Tello Gentile Date: Tue, 1 Nov 2011 18:03:56 +0300 Subject: [PATCH 022/107] 7105529: XAWT: Optimize getFieldsAsString() methods generated by WrapperGenerator Replace string concatenation with StringBuilder.append() Reviewed-by: anthony, son --- .../awt/X11/generator/WrapperGenerator.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/jdk/src/solaris/classes/sun/awt/X11/generator/WrapperGenerator.java b/jdk/src/solaris/classes/sun/awt/X11/generator/WrapperGenerator.java index 272fda8d702..7ad7386070a 100644 --- a/jdk/src/solaris/classes/sun/awt/X11/generator/WrapperGenerator.java +++ b/jdk/src/solaris/classes/sun/awt/X11/generator/WrapperGenerator.java @@ -678,7 +678,7 @@ public class WrapperGenerator { public void writeToString(StructType stp, PrintWriter pw) { int type; pw.println("\n\n\tString getName() {\n\t\treturn \"" + stp.getName()+ "\"; \n\t}"); - pw.println("\n\n\tString getFieldsAsString() {\n\t\tString ret=\"\";\n"); + pw.println("\n\n\tString getFieldsAsString() {\n\t\tStringBuilder ret = new StringBuilder(" + stp.getNumFields() * 40 + ");\n"); for (Enumeration e = stp.getMembers() ; e.hasMoreElements() ;) { AtomicType tp = (AtomicType) e.nextElement(); @@ -688,24 +688,24 @@ public class WrapperGenerator { if ((name != null) && (name.length() > 0)) { if (type == AtomicType.TYPE_ATOM) { - pw.println("\t\tret += \"\"+\"" + name + " = \" + XAtom.get(get_" + name + "()) +\", \";"); + pw.println("\t\tret.append(\"" + name + " = \" ).append( XAtom.get(get_" + name + "()) ).append(\", \");"); } else if (name.equals("type")) { - pw.println("\t\tret += \"\"+\"type = \" + XlibWrapper.eventToString[get_type()] +\", \";"); + pw.println("\t\tret.append(\"type = \").append( XlibWrapper.eventToString[get_type()] ).append(\", \");"); } else if (name.equals("window")){ - pw.println("\t\tret += \"\"+\"window = \" + getWindow(get_window()) + \", \";"); + pw.println("\t\tret.append(\"window = \" ).append( getWindow(get_window()) ).append(\", \");"); } else if (type == AtomicType.TYPE_ARRAY) { - pw.print("\t\tret += \"{\""); + pw.print("\t\tret.append(\"{\")"); for (int i = 0; i < tp.getArrayLength(); i++) { - pw.print(" + get_" + name + "(" + i + ") + \" \""); + pw.print("\n\t\t.append( get_" + name + "(" + i + ") ).append(\" \")"); } - pw.println(" + \"}\";"); + pw.println(".append( \"}\");"); } else { - pw.println("\t\tret += \"\"+\"" + name +" = \" + get_"+ name+"() +\", \";"); + pw.println("\t\tret.append(\"" + name +" = \").append( get_"+ name+"() ).append(\", \");"); } } } - pw.println("\t\treturn ret;\n\t}\n\n"); + pw.println("\t\treturn ret.toString();\n\t}\n\n"); } public void writeStubs(StructType stp, PrintWriter pw) { From 6612f2a7e637d3d88037ba70eca840159e3cd73e Mon Sep 17 00:00:00 2001 From: Alexandr Scherbatiy Date: Wed, 2 Nov 2011 14:17:16 +0400 Subject: [PATCH 023/107] 6624077: Regression test fails: closed/javax/swing/ToolTipManager/6256140/bug6256140.java Reviewed-by: rupashka --- .../swing/ToolTipManager/Test6256140.java | 143 ++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 jdk/test/javax/swing/ToolTipManager/Test6256140.java diff --git a/jdk/test/javax/swing/ToolTipManager/Test6256140.java b/jdk/test/javax/swing/ToolTipManager/Test6256140.java new file mode 100644 index 00000000000..12d5df8be03 --- /dev/null +++ b/jdk/test/javax/swing/ToolTipManager/Test6256140.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2007, 2011, 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 6256140 + * @summary Esc key doesn't restore old value in JFormattedtextField when ToolTip is set + * @author Alexander Potochkin + * @run main Test6256140 + */ + +import sun.awt.SunToolkit; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.KeyEvent; + +public class Test6256140 { + + private static volatile JFormattedTextField ft; + + private final static String initialText = "value"; + private final static JLabel toolTipLabel = new JLabel("tip"); + + public static void main(String[] args) throws Exception { + + Robot robot = new Robot(); + robot.setAutoDelay(10); + SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit(); + + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + createAndShowGUI(); + } + }); + toolkit.realSync(); + + Point point = ft.getLocationOnScreen(); + robot.mouseMove(point.x, point.y); + robot.mouseMove(point.x + 3, point.y + 3); + + robot.keyPress(KeyEvent.VK_A); + robot.keyRelease(KeyEvent.VK_A); + toolkit.realSync(); + + if (!isTooltipShowning()) { + throw new RuntimeException("Tooltip is not shown"); + } + + robot.keyPress(KeyEvent.VK_ESCAPE); + robot.keyRelease(KeyEvent.VK_ESCAPE); + toolkit.realSync(); + + if (isTooltipShowning()) { + throw new RuntimeException("Tooltip must be hidden now"); + } + + if (isTextEqual()) { + throw new RuntimeException("FormattedTextField must *not* cancel the updated value this time"); + } + + robot.keyPress(KeyEvent.VK_ESCAPE); + robot.keyRelease(KeyEvent.VK_ESCAPE); + toolkit.realSync(); + + if (!isTextEqual()) { + throw new RuntimeException("FormattedTextField must cancel the updated value"); + } + } + + private static boolean isTooltipShowning() throws Exception { + final boolean[] result = new boolean[1]; + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + result[0] = toolTipLabel.isShowing(); + } + }); + + return result[0]; + } + + private static boolean isTextEqual() throws Exception { + final boolean[] result = new boolean[1]; + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + result[0] = initialText.equals(ft.getText()); + } + }); + + return result[0]; + } + + private static void createAndShowGUI() { + ToolTipManager.sharedInstance().setDismissDelay(Integer.MAX_VALUE); + ToolTipManager.sharedInstance().setInitialDelay(0); + + final JFrame frame = new JFrame(); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setLayout(new FlowLayout()); + + ft = new JFormattedTextField() { + + public JToolTip createToolTip() { + JToolTip toolTip = super.createToolTip(); + toolTip.setLayout(new BorderLayout()); + toolTip.add(toolTipLabel); + return toolTip; + } + }; + ft.setToolTipText(" "); + ft.setValue(initialText); + frame.add(ft); + + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + ft.requestFocus(); + } +} From 34c1a2b71680d900c65e93103f2160301b4a51e4 Mon Sep 17 00:00:00 2001 From: Alexander Kouznetsov Date: Wed, 2 Nov 2011 17:39:30 +0400 Subject: [PATCH 024/107] 7074853: TransparentRuler demos Readme should mention the correct jar file name Reviewed-by: rupashka --- jdk/src/share/demo/jfc/TransparentRuler/README.txt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/jdk/src/share/demo/jfc/TransparentRuler/README.txt b/jdk/src/share/demo/jfc/TransparentRuler/README.txt index ddcf9de1d5e..0b66bd213c2 100644 --- a/jdk/src/share/demo/jfc/TransparentRuler/README.txt +++ b/jdk/src/share/demo/jfc/TransparentRuler/README.txt @@ -1,14 +1,10 @@ To run the Ruler demo: - java -jar Ruler.jar + java -jar TransparentRuler.jar These instructions assume that this installation's version of the java command is in your path. If it isn't, then you should either specify the complete path to the java command or update your PATH environment variable as described in the installation instructions for the Java(TM) SE Development Kit. - -KNOWN ISSUES: -Context menu is clipped with the window shape. The issues are: -CR 7027486 JPopupMenu doesn't take window shape into account From c59424668d06bf7916ca34f7da2e87b12bc7f18b Mon Sep 17 00:00:00 2001 From: Sean Chou Date: Wed, 2 Nov 2011 23:53:16 +0300 Subject: [PATCH 025/107] 7049024: DnD fails with JTextArea and JTextField Reviewed-by: rupashka --- .../javax/swing/text/DefaultCaret.java | 2 +- .../swing/JTextArea/7049024/bug7049024.java | 134 ++++++++++++++++++ 2 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 jdk/test/javax/swing/JTextArea/7049024/bug7049024.java diff --git a/jdk/src/share/classes/javax/swing/text/DefaultCaret.java b/jdk/src/share/classes/javax/swing/text/DefaultCaret.java index ecbfdf0d6f4..464fff6822e 100644 --- a/jdk/src/share/classes/javax/swing/text/DefaultCaret.java +++ b/jdk/src/share/classes/javax/swing/text/DefaultCaret.java @@ -1326,7 +1326,7 @@ public class DefaultCaret extends Rectangle implements Caret, FocusListener, Mou if ( ! SwingUtilities2.canCurrentEventAccessSystemClipboard() ) { return; } - if (this.dot != this.mark && component != null) { + if (this.dot != this.mark && component != null && component.hasFocus()) { Clipboard clip = getSystemSelection(); if (clip != null) { String selectedText; diff --git a/jdk/test/javax/swing/JTextArea/7049024/bug7049024.java b/jdk/test/javax/swing/JTextArea/7049024/bug7049024.java new file mode 100644 index 00000000000..e6398b2f07c --- /dev/null +++ b/jdk/test/javax/swing/JTextArea/7049024/bug7049024.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2011 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. + */ + +/* + * Portions Copyright (c) 2011 IBM Corporation + */ + +/* @test + * @bug 7049024 + * @summary DnD fails with JTextArea and JTextField + * @author Sean Chou + */ + +import sun.awt.SunToolkit; + +import javax.swing.*; +import javax.swing.text.DefaultCaret; +import java.awt.*; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.DataFlavor; + +public class bug7049024 { + public static Clipboard clipboard = null; + + public static JTextField textField = null; + + // This button is used to move focus away from textField. + public static JButton button = null; + + public static JFrame frame = null; + + public static DefaultCaret caret = null; + + public static void main(String[] args) throws Exception { + + SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit(); + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + frame = new JFrame("Test"); + textField = new JTextField("test selection for textfield"); + button = new JButton("To compete the focus"); + + frame.setLayout(new FlowLayout()); + frame.getContentPane().add(textField); + frame.getContentPane().add(button); + + frame.pack(); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setVisible(true); + } + }); + toolkit.realSync(); + + clipboard = textField.getToolkit().getSystemSelection(); + if (null == clipboard) { + return; + } + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + textField.requestFocusInWindow(); + } + }); + toolkit.realSync(); + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + caret = (DefaultCaret) textField.getCaret(); + caret.setDot(2); + caret.moveDot(4); + } + }); + toolkit.realSync(); + + String oldSelection = (String) clipboard.getData(DataFlavor.stringFlavor); + System.out.println("oldSelection is " + oldSelection); + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + button.requestFocusInWindow(); + } + }); + toolkit.realSync(); // So JTextField loses the focus. + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + caret.setDot(4); + caret.moveDot(6); + } + }); + toolkit.realSync(); + + String newSelection = (String) clipboard.getData(DataFlavor.stringFlavor); + System.out.println("newSelection is " + newSelection); + + boolean passed = newSelection.equals(oldSelection); + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + frame.dispose(); + } + }); + + if (!passed) { + throw new RuntimeException("The test for bug 7049024 failed"); + } + } +} From bd73f1cc1d21831afb09ea298abe159c22b5bb8f Mon Sep 17 00:00:00 2001 From: Alexandr Scherbatiy Date: Thu, 3 Nov 2011 14:14:36 +0400 Subject: [PATCH 026/107] 6955919: Intermittent ClassCastException in bug4492274 test Reviewed-by: rupashka --- .../swing/JEditorPane/4492274/bug4492274.java | 111 ++++++++++++++++++ .../javax/swing/JEditorPane/4492274/test.html | 7 ++ 2 files changed, 118 insertions(+) create mode 100644 jdk/test/javax/swing/JEditorPane/4492274/bug4492274.java create mode 100644 jdk/test/javax/swing/JEditorPane/4492274/test.html diff --git a/jdk/test/javax/swing/JEditorPane/4492274/bug4492274.java b/jdk/test/javax/swing/JEditorPane/4492274/bug4492274.java new file mode 100644 index 00000000000..cf732a9c5f2 --- /dev/null +++ b/jdk/test/javax/swing/JEditorPane/4492274/bug4492274.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2007, 2011, 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 4492274 + * @summary Tests if JEditorPane.getPage() correctly returns anchor reference. + * @author Denis Sharypov + */ + +import sun.awt.SunToolkit; + +import javax.swing.*; +import javax.swing.text.html.HTMLEditorKit; +import java.awt.*; +import java.io.File; +import java.net.URL; + +public class bug4492274 { + + private static URL page; + + private static JEditorPane jep; + + public static void main(String args[]) throws Exception { + SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit(); + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + createAndShowGUI(); + } + }); + + toolkit.realSync(); + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + try { + page = new URL(page, "#linkname"); + jep.setPage(page); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + }); + + toolkit.realSync(); + + if (getPageAnchor() == null) { + throw new RuntimeException("JEditorPane.getPage() returns null anchor reference"); + } + + } + + private static String getPageAnchor() throws Exception { + final String[] result = new String[1]; + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + result[0] = jep.getPage().getRef(); + } + }); + + return result[0]; + } + + private static void createAndShowGUI() { + try { + File file = new File(System.getProperty("test.src", "."), "test.html"); + page = file.toURI().toURL(); + + JFrame f = new JFrame(); + + jep = new JEditorPane(); + jep.setEditorKit(new HTMLEditorKit()); + jep.setEditable(false); + jep.setPage(page); + + JScrollPane sp = new JScrollPane(jep); + + f.getContentPane().add(sp); + f.setSize(500, 500); + f.setVisible(true); + + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/jdk/test/javax/swing/JEditorPane/4492274/test.html b/jdk/test/javax/swing/JEditorPane/4492274/test.html new file mode 100644 index 00000000000..2186cc326c8 --- /dev/null +++ b/jdk/test/javax/swing/JEditorPane/4492274/test.html @@ -0,0 +1,7 @@ + + +top + +bottom + + From 16b47aa1774a3c3d0c2887f94edab4d21a1e2230 Mon Sep 17 00:00:00 2001 From: Charles Lee Date: Thu, 13 Oct 2011 13:02:37 +0100 Subject: [PATCH 027/107] 7107957: AWT: Native code should include fcntl.h and unistd.h rather than sys/fcntl.h and sys/unistd.h Use POSIX defined includes for unistd.h and fcntl.h Reviewed-by: anthony, ngmr --- .../solaris/native/sun/awt/splashscreen/splashscreen_config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/solaris/native/sun/awt/splashscreen/splashscreen_config.h b/jdk/src/solaris/native/sun/awt/splashscreen/splashscreen_config.h index bb031656aee..e312c2bc6dc 100644 --- a/jdk/src/solaris/native/sun/awt/splashscreen/splashscreen_config.h +++ b/jdk/src/solaris/native/sun/awt/splashscreen/splashscreen_config.h @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include #include From 8863ec439e47eea77a616aef9adfa9ede1c0c825 Mon Sep 17 00:00:00 2001 From: Andrew Brygin Date: Mon, 17 Oct 2011 15:20:51 +0400 Subject: [PATCH 028/107] 6997116: The case automatically failed due to java.lang.ClassCastException Reviewed-by: jgodinez, prr --- .../sun/java2d/d3d/D3DSurfaceData.java | 2 +- .../DirectX/DrawBitmaskToSurfaceTest.java | 104 ++++++++++++++++++ 2 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 jdk/test/sun/java2d/DirectX/DrawBitmaskToSurfaceTest.java diff --git a/jdk/src/windows/classes/sun/java2d/d3d/D3DSurfaceData.java b/jdk/src/windows/classes/sun/java2d/d3d/D3DSurfaceData.java index 50a51a6f94b..d37db9e925b 100644 --- a/jdk/src/windows/classes/sun/java2d/d3d/D3DSurfaceData.java +++ b/jdk/src/windows/classes/sun/java2d/d3d/D3DSurfaceData.java @@ -486,7 +486,7 @@ public class D3DSurfaceData extends SurfaceData implements AccelSurface { int dataType = 0; int scanStride = width; - if (dcm.getPixelSize() == 24 || dcm.getPixelSize() == 32) { + if (dcm.getPixelSize() > 16) { dataType = DataBuffer.TYPE_INT; } else { // 15, 16 diff --git a/jdk/test/sun/java2d/DirectX/DrawBitmaskToSurfaceTest.java b/jdk/test/sun/java2d/DirectX/DrawBitmaskToSurfaceTest.java new file mode 100644 index 00000000000..3f37e5c215e --- /dev/null +++ b/jdk/test/sun/java2d/DirectX/DrawBitmaskToSurfaceTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2011, 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 6997116 + * @summary Test verifies that rendering of images with bitmap transparency + * to a D3D surface does not cause an ClassCastException. + * + * @run main/othervm -Dsun.java2d.d3d=True DrawBitmaskToSurfaceTest + */ + +import java.awt.Graphics; +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.awt.image.IndexColorModel; +import java.util.concurrent.CountDownLatch; +import javax.swing.JFrame; + +public class DrawBitmaskToSurfaceTest extends JFrame { + + private final Image src; + private static java.util.concurrent.CountDownLatch latch = null; + private static Throwable theError = null; + + public DrawBitmaskToSurfaceTest() { + src = createTestImage(); + } + + private static Image createTestImage() { + byte[] r = new byte[]{(byte)0x00, (byte)0x80, (byte)0xff, (byte)0xff}; + byte[] g = new byte[]{(byte)0x00, (byte)0x80, (byte)0xff, (byte)0x00}; + byte[] b = new byte[]{(byte)0x00, (byte)0x80, (byte)0xff, (byte)0x00}; + + IndexColorModel icm = new IndexColorModel(2, 4, r, g, b, 3); + + BufferedImage img = new BufferedImage(100, 100, + BufferedImage.TYPE_BYTE_INDEXED, + icm); + return img; + } + + @Override + public void paint(final Graphics g) { + try { + System.err.println("paint frame...."); + g.drawImage(src, 30, 30, this); + } catch (Throwable e) { + theError = e; + } finally { + if (latch != null) { + latch.countDown(); + } + } + } + + public static void main(final String[] args) throws Exception { + final JFrame frame = new DrawBitmaskToSurfaceTest(); + frame.setBounds(10, 350, 200, 200); + frame.setVisible(true); + + Thread.sleep(2000); + + System.err.println("Change frame bounds..."); + latch = new CountDownLatch(1); + frame.setBounds(10, 350, 90, 90); + frame.repaint(); + + try { + if (latch.getCount() > 0) { + latch.await(); + } + } catch (InterruptedException e) { + } + + frame.dispose(); + + if (theError != null) { + throw new RuntimeException("Test failed.", theError); + } + + System.err.println("Test passed"); + } +} From 1a335eb0477f953f65cad1e8747c3e682b59d779 Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Mon, 17 Oct 2011 12:54:33 +0100 Subject: [PATCH 029/107] 7097436: Project Coin: duplicate varargs warnings on method annotated with @SafeVarargs Duplicate aliasing check during subtyping leads to spurious varargs diagnostic Reviewed-by: jjg --- .../com/sun/tools/javac/code/Types.java | 107 ++++---- .../tools/javac/varargs/7097436/T7097436.java | 18 ++ .../tools/javac/varargs/7097436/T7097436.out | 6 + .../tools/javac/varargs/warning/Warn5.java | 244 ++++++++++-------- 4 files changed, 215 insertions(+), 160 deletions(-) create mode 100644 langtools/test/tools/javac/varargs/7097436/T7097436.java create mode 100644 langtools/test/tools/javac/varargs/7097436/T7097436.out diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java index 55dc74d659a..5fc9d4547ed 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/Types.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Types.java @@ -278,7 +278,6 @@ public class Types { boolean tPrimitive = t.isPrimitive(); boolean sPrimitive = s.isPrimitive(); if (tPrimitive == sPrimitive) { - checkUnsafeVarargsConversion(t, s, warn); return isSubtypeUnchecked(t, s, warn); } if (!allowBoxing) return false; @@ -286,27 +285,6 @@ public class Types { ? isSubtype(boxedClass(t).type, s) : isSubtype(unboxedType(t), s); } - //where - private void checkUnsafeVarargsConversion(Type t, Type s, Warner warn) { - if (t.tag != ARRAY || isReifiable(t)) return; - ArrayType from = (ArrayType)t; - boolean shouldWarn = false; - switch (s.tag) { - case ARRAY: - ArrayType to = (ArrayType)s; - shouldWarn = from.isVarargs() && - !to.isVarargs() && - !isReifiable(from); - break; - case CLASS: - shouldWarn = from.isVarargs() && - isSubtype(from, s); - break; - } - if (shouldWarn) { - warn.warn(LintCategory.VARARGS); - } - } /** * Is t a subtype of or convertiable via boxing/unboxing @@ -328,42 +306,63 @@ public class Types { * Is t an unchecked subtype of s? */ public boolean isSubtypeUnchecked(Type t, Type s, Warner warn) { - if (t.tag == ARRAY && s.tag == ARRAY) { - if (((ArrayType)t).elemtype.tag <= lastBaseTag) { - return isSameType(elemtype(t), elemtype(s)); - } else { - ArrayType from = (ArrayType)t; - ArrayType to = (ArrayType)s; - if (from.isVarargs() && - !to.isVarargs() && - !isReifiable(from)) { - warn.warn(LintCategory.VARARGS); + boolean result = isSubtypeUncheckedInternal(t, s, warn); + if (result) { + checkUnsafeVarargsConversion(t, s, warn); + } + return result; + } + //where + private boolean isSubtypeUncheckedInternal(Type t, Type s, Warner warn) { + if (t.tag == ARRAY && s.tag == ARRAY) { + if (((ArrayType)t).elemtype.tag <= lastBaseTag) { + return isSameType(elemtype(t), elemtype(s)); + } else { + return isSubtypeUnchecked(elemtype(t), elemtype(s), warn); } - return isSubtypeUnchecked(elemtype(t), elemtype(s), warn); - } - } else if (isSubtype(t, s)) { - return true; - } - else if (t.tag == TYPEVAR) { - return isSubtypeUnchecked(t.getUpperBound(), s, warn); - } - else if (s.tag == UNDETVAR) { - UndetVar uv = (UndetVar)s; - if (uv.inst != null) - return isSubtypeUnchecked(t, uv.inst, warn); - } - else if (!s.isRaw()) { - Type t2 = asSuper(t, s.tsym); - if (t2 != null && t2.isRaw()) { - if (isReifiable(s)) - warn.silentWarn(LintCategory.UNCHECKED); - else - warn.warn(LintCategory.UNCHECKED); + } else if (isSubtype(t, s)) { return true; } + else if (t.tag == TYPEVAR) { + return isSubtypeUnchecked(t.getUpperBound(), s, warn); + } + else if (s.tag == UNDETVAR) { + UndetVar uv = (UndetVar)s; + if (uv.inst != null) + return isSubtypeUnchecked(t, uv.inst, warn); + } + else if (!s.isRaw()) { + Type t2 = asSuper(t, s.tsym); + if (t2 != null && t2.isRaw()) { + if (isReifiable(s)) + warn.silentWarn(LintCategory.UNCHECKED); + else + warn.warn(LintCategory.UNCHECKED); + return true; + } + } + return false; + } + + private void checkUnsafeVarargsConversion(Type t, Type s, Warner warn) { + if (t.tag != ARRAY || isReifiable(t)) return; + ArrayType from = (ArrayType)t; + boolean shouldWarn = false; + switch (s.tag) { + case ARRAY: + ArrayType to = (ArrayType)s; + shouldWarn = from.isVarargs() && + !to.isVarargs() && + !isReifiable(from); + break; + case CLASS: + shouldWarn = from.isVarargs(); + break; + } + if (shouldWarn) { + warn.warn(LintCategory.VARARGS); + } } - return false; - } /** * Is t a subtype of s?
diff --git a/langtools/test/tools/javac/varargs/7097436/T7097436.java b/langtools/test/tools/javac/varargs/7097436/T7097436.java new file mode 100644 index 00000000000..cf64baa48dd --- /dev/null +++ b/langtools/test/tools/javac/varargs/7097436/T7097436.java @@ -0,0 +1,18 @@ +/* + * @test /nodynamiccopyright/ + * @bug 7097436 + * @summary ClassCastException occurs in assignment expressions without any heap pollutions + * @compile/fail/ref=T7097436.out -Xlint:varargs -Werror -XDrawDiagnostics T7097436.java + */ + +import java.util.List; + +class T7097436 { + @SafeVarargs + static void m(List... ls) { + Object o = ls; //warning + Object[] oArr = ls; //warning + String s = ls; // no warning + Integer[] iArr = ls; // no warning + } +} diff --git a/langtools/test/tools/javac/varargs/7097436/T7097436.out b/langtools/test/tools/javac/varargs/7097436/T7097436.out new file mode 100644 index 00000000000..6428cdfa497 --- /dev/null +++ b/langtools/test/tools/javac/varargs/7097436/T7097436.out @@ -0,0 +1,6 @@ +T7097436.java:13:20: compiler.warn.varargs.unsafe.use.varargs.param: ls +T7097436.java:14:25: compiler.warn.varargs.unsafe.use.varargs.param: ls +T7097436.java:15:20: compiler.err.prob.found.req: (compiler.misc.incompatible.types), java.util.List[], java.lang.String +T7097436.java:16:26: compiler.err.prob.found.req: (compiler.misc.incompatible.types), java.util.List[], java.lang.Integer[] +2 errors +2 warnings diff --git a/langtools/test/tools/javac/varargs/warning/Warn5.java b/langtools/test/tools/javac/varargs/warning/Warn5.java index be7618f760a..966cefa78a8 100644 --- a/langtools/test/tools/javac/varargs/warning/Warn5.java +++ b/langtools/test/tools/javac/varargs/warning/Warn5.java @@ -23,7 +23,7 @@ /** * @test - * @bug 6993978 + * @bug 6993978 7097436 * @summary Project Coin: Annotation to reduce varargs warnings * @author mcimadamore * @run main Warn5 @@ -31,8 +31,8 @@ import com.sun.source.util.JavacTask; import com.sun.tools.javac.api.JavacTool; import java.net.URI; -import java.util.ArrayList; import java.util.Arrays; +import java.util.EnumSet; import javax.tools.Diagnostic; import javax.tools.JavaCompiler; import javax.tools.JavaFileObject; @@ -95,7 +95,6 @@ public class Warn5 { METHOD("void m"), CONSTRUCTOR("Test"); - String name; MethodKind(String name) { @@ -155,7 +154,124 @@ public class Warn5 { } } - static class JavaSource extends SimpleJavaFileObject { + enum WarningKind { + UNSAFE_BODY, + UNSAFE_DECL, + MALFORMED_SAFEVARARGS, + REDUNDANT_SAFEVARARGS; + } + + // Create a single file manager and reuse it for each compile to save time. + static StandardJavaFileManager fm = JavacTool.create().getStandardFileManager(null, null, null); + + public static void main(String... args) throws Exception { + for (SourceLevel sourceLevel : SourceLevel.values()) { + for (XlintOption xlint : XlintOption.values()) { + for (TrustMe trustMe : TrustMe.values()) { + for (SuppressLevel suppressLevel : SuppressLevel.values()) { + for (ModifierKind modKind : ModifierKind.values()) { + for (MethodKind methKind : MethodKind.values()) { + for (SignatureKind sig : SignatureKind.values()) { + for (BodyKind body : BodyKind.values()) { + new Warn5(sourceLevel, + xlint, + trustMe, + suppressLevel, + modKind, + methKind, + sig, + body).test(); + } + } + } + } + } + } + } + } + } + + final SourceLevel sourceLevel; + final XlintOption xlint; + final TrustMe trustMe; + final SuppressLevel suppressLevel; + final ModifierKind modKind; + final MethodKind methKind; + final SignatureKind sig; + final BodyKind body; + final JavaSource source; + final DiagnosticChecker dc; + + public Warn5(SourceLevel sourceLevel, XlintOption xlint, TrustMe trustMe, SuppressLevel suppressLevel, ModifierKind modKind, MethodKind methKind, SignatureKind sig, BodyKind body) { + this.sourceLevel = sourceLevel; + this.xlint = xlint; + this.trustMe = trustMe; + this.suppressLevel = suppressLevel; + this.modKind = modKind; + this.methKind = methKind; + this.sig = sig; + this.body = body; + this.source = new JavaSource(); + this.dc = new DiagnosticChecker(); + } + + void test() throws Exception { + final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); + JavacTask ct = (JavacTask)tool.getTask(null, fm, dc, + Arrays.asList(xlint.getXlintOption(), "-source", sourceLevel.sourceKey), null, Arrays.asList(source)); + ct.analyze(); + check(); + } + + void check() { + + EnumSet expectedWarnings = EnumSet.noneOf(WarningKind.class); + + if (sourceLevel == SourceLevel.JDK_7 && + trustMe == TrustMe.TRUST && + suppressLevel != SuppressLevel.VARARGS && + xlint != XlintOption.NONE && + sig.isVarargs && !sig.isReifiableArg && body.hasAliasing && + (methKind == MethodKind.CONSTRUCTOR || (methKind == MethodKind.METHOD && modKind != ModifierKind.NONE))) { + expectedWarnings.add(WarningKind.UNSAFE_BODY); + } + + if (sourceLevel == SourceLevel.JDK_7 && + trustMe == TrustMe.DONT_TRUST && + sig.isVarargs && + !sig.isReifiableArg && + xlint == XlintOption.ALL) { + expectedWarnings.add(WarningKind.UNSAFE_DECL); + } + + if (sourceLevel == SourceLevel.JDK_7 && + trustMe == TrustMe.TRUST && + (!sig.isVarargs || + (modKind == ModifierKind.NONE && methKind == MethodKind.METHOD))) { + expectedWarnings.add(WarningKind.MALFORMED_SAFEVARARGS); + } + + if (sourceLevel == SourceLevel.JDK_7 && + trustMe == TrustMe.TRUST && + xlint != XlintOption.NONE && + suppressLevel != SuppressLevel.VARARGS && + (modKind != ModifierKind.NONE || methKind == MethodKind.CONSTRUCTOR) && + sig.isVarargs && + sig.isReifiableArg) { + expectedWarnings.add(WarningKind.REDUNDANT_SAFEVARARGS); + } + + if (!expectedWarnings.containsAll(dc.warnings) || + !dc.warnings.containsAll(expectedWarnings)) { + throw new Error("invalid diagnostics for source:\n" + + source.getCharContent(true) + + "\nOptions: " + xlint.getXlintOption() + + "\nExpected warnings: " + expectedWarnings + + "\nFound warnings: " + dc.warnings); + } + } + + class JavaSource extends SimpleJavaFileObject { String template = "import com.sun.tools.javac.api.*;\n" + "import java.util.List;\n" + @@ -167,12 +283,11 @@ public class Warn5 { String source; - public JavaSource(TrustMe trustMe, SuppressLevel suppressLevel, ModifierKind modKind, - MethodKind methKind, SignatureKind meth, BodyKind body) { + public JavaSource() { super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); source = template.replace("#T", trustMe.anno). replace("#S", suppressLevel.getSuppressAnno()). - replace("#M", meth.getSignature(modKind, methKind)). + replace("#M", sig.getSignature(modKind, methKind)). replace("#B", body.body); } @@ -182,117 +297,34 @@ public class Warn5 { } } - public static void main(String... args) throws Exception { - for (SourceLevel sourceLevel : SourceLevel.values()) { - for (XlintOption xlint : XlintOption.values()) { - for (TrustMe trustMe : TrustMe.values()) { - for (SuppressLevel suppressLevel : SuppressLevel.values()) { - for (ModifierKind modKind : ModifierKind.values()) { - for (MethodKind methKind : MethodKind.values()) { - for (SignatureKind sig : SignatureKind.values()) { - for (BodyKind body : BodyKind.values()) { - test(sourceLevel, - xlint, - trustMe, - suppressLevel, - modKind, - methKind, - sig, - body); - } - } - } - } - } - } - } - } - } + class DiagnosticChecker implements javax.tools.DiagnosticListener { - // Create a single file manager and reuse it for each compile to save time. - static StandardJavaFileManager fm = JavacTool.create().getStandardFileManager(null, null, null); - - static void test(SourceLevel sourceLevel, XlintOption xlint, TrustMe trustMe, SuppressLevel suppressLevel, - ModifierKind modKind, MethodKind methKind, SignatureKind sig, BodyKind body) throws Exception { - final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); - JavaSource source = new JavaSource(trustMe, suppressLevel, modKind, methKind, sig, body); - DiagnosticChecker dc = new DiagnosticChecker(); - JavacTask ct = (JavacTask)tool.getTask(null, fm, dc, - Arrays.asList(xlint.getXlintOption(), "-source", sourceLevel.sourceKey), null, Arrays.asList(source)); - ct.analyze(); - check(sourceLevel, dc, source, xlint, trustMe, - suppressLevel, modKind, methKind, sig, body); - } - - static void check(SourceLevel sourceLevel, DiagnosticChecker dc, JavaSource source, - XlintOption xlint, TrustMe trustMe, SuppressLevel suppressLevel, ModifierKind modKind, - MethodKind methKind, SignatureKind meth, BodyKind body) { - - boolean hasPotentiallyUnsafeBody = sourceLevel == SourceLevel.JDK_7 && - trustMe == TrustMe.TRUST && - suppressLevel != SuppressLevel.VARARGS && - xlint != XlintOption.NONE && - meth.isVarargs && !meth.isReifiableArg && body.hasAliasing && - (methKind == MethodKind.CONSTRUCTOR || (methKind == MethodKind.METHOD && modKind != ModifierKind.NONE)); - - boolean hasPotentiallyPollutingDecl = sourceLevel == SourceLevel.JDK_7 && - trustMe == TrustMe.DONT_TRUST && - meth.isVarargs && - !meth.isReifiableArg && - xlint == XlintOption.ALL; - - boolean hasMalformedAnnoInDecl = sourceLevel == SourceLevel.JDK_7 && - trustMe == TrustMe.TRUST && - (!meth.isVarargs || - (modKind == ModifierKind.NONE && methKind == MethodKind.METHOD)); - - boolean hasRedundantAnnoInDecl = sourceLevel == SourceLevel.JDK_7 && - trustMe == TrustMe.TRUST && - xlint != XlintOption.NONE && - suppressLevel != SuppressLevel.VARARGS && - (modKind != ModifierKind.NONE || methKind == MethodKind.CONSTRUCTOR) && - meth.isVarargs && - meth.isReifiableArg; - - if (hasPotentiallyUnsafeBody != dc.hasPotentiallyUnsafeBody || - hasPotentiallyPollutingDecl != dc.hasPotentiallyPollutingDecl || - hasMalformedAnnoInDecl != dc.hasMalformedAnnoInDecl || - hasRedundantAnnoInDecl != dc.hasRedundantAnnoInDecl) { - throw new Error("invalid diagnostics for source:\n" + - source.getCharContent(true) + - "\nOptions: " + xlint.getXlintOption() + - "\nExpected potentially unsafe body warning: " + hasPotentiallyUnsafeBody + - "\nExpected potentially polluting decl warning: " + hasPotentiallyPollutingDecl + - "\nExpected malformed anno error: " + hasMalformedAnnoInDecl + - "\nExpected redundant anno warning: " + hasRedundantAnnoInDecl + - "\nFound potentially unsafe body warning: " + dc.hasPotentiallyUnsafeBody + - "\nFound potentially polluting decl warning: " + dc.hasPotentiallyPollutingDecl + - "\nFound malformed anno error: " + dc.hasMalformedAnnoInDecl + - "\nFound redundant anno warning: " + dc.hasRedundantAnnoInDecl); - } - } - - static class DiagnosticChecker implements javax.tools.DiagnosticListener { - - boolean hasPotentiallyUnsafeBody = false; - boolean hasPotentiallyPollutingDecl = false; - boolean hasMalformedAnnoInDecl = false; - boolean hasRedundantAnnoInDecl = false; + EnumSet warnings = EnumSet.noneOf(WarningKind.class); public void report(Diagnostic diagnostic) { if (diagnostic.getKind() == Diagnostic.Kind.WARNING) { if (diagnostic.getCode().contains("unsafe.use.varargs.param")) { - hasPotentiallyUnsafeBody = true; + setWarning(WarningKind.UNSAFE_BODY); } else if (diagnostic.getCode().contains("redundant.trustme")) { - hasRedundantAnnoInDecl = true; + setWarning(WarningKind.REDUNDANT_SAFEVARARGS); } } else if (diagnostic.getKind() == Diagnostic.Kind.MANDATORY_WARNING && diagnostic.getCode().contains("varargs.non.reifiable.type")) { - hasPotentiallyPollutingDecl = true; + setWarning(WarningKind.UNSAFE_DECL); } else if (diagnostic.getKind() == Diagnostic.Kind.ERROR && diagnostic.getCode().contains("invalid.trustme")) { - hasMalformedAnnoInDecl = true; + setWarning(WarningKind.MALFORMED_SAFEVARARGS); } } + + void setWarning(WarningKind wk) { + if (!warnings.add(wk)) { + throw new AssertionError("Duplicate warning of kind " + wk + " in source:\n" + source); + } + } + + boolean hasWarning(WarningKind wk) { + return warnings.contains(wk); + } } } From d3efececf329fb3ff0f811f5e34be0929f3a8cdc Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Mon, 17 Oct 2011 12:57:36 +0100 Subject: [PATCH 030/107] 7093325: Redundant entry in bytecode exception table Inlining of finalizers does not update gaps list accordingly Reviewed-by: jjg --- .../classes/com/sun/tools/javac/jvm/Code.java | 23 +- .../classes/com/sun/tools/javac/jvm/Gen.java | 34 +-- langtools/test/tools/javac/T7093325.java | 262 ++++++++++++++++++ 3 files changed, 301 insertions(+), 18 deletions(-) create mode 100644 langtools/test/tools/javac/T7093325.java diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/Code.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/Code.java index ec080df41e7..59f0fc167f6 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/jvm/Code.java +++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/Code.java @@ -1542,7 +1542,28 @@ public class Code { */ public void addCatch( char startPc, char endPc, char handlerPc, char catchType) { - catchInfo.append(new char[]{startPc, endPc, handlerPc, catchType}); + catchInfo.append(new char[]{startPc, endPc, handlerPc, catchType}); + } + + + public void compressCatchTable() { + ListBuffer compressedCatchInfo = ListBuffer.lb(); + List handlerPcs = List.nil(); + for (char[] catchEntry : catchInfo.elems) { + handlerPcs = handlerPcs.prepend((int)catchEntry[2]); + } + for (char[] catchEntry : catchInfo.elems) { + int startpc = catchEntry[0]; + int endpc = catchEntry[1]; + if (startpc == endpc || + (startpc == (endpc - 1) && + handlerPcs.contains(startpc))) { + continue; + } else { + compressedCatchInfo.append(catchEntry); + } + } + catchInfo = compressedCatchInfo; } diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java index 618700ec83f..f1a2a71f2d6 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java +++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java @@ -959,6 +959,9 @@ public class Gen extends JCTree.Visitor { code.lastFrame = null; code.frameBeforeLast = null; } + + //compress exception table + code.compressCatchTable(); } } @@ -1437,7 +1440,6 @@ public class Gen extends JCTree.Visitor { code.markDead(); } } - // Resolve all breaks. code.resolve(exitChain); @@ -1496,23 +1498,21 @@ public class Gen extends JCTree.Visitor { void registerCatch(DiagnosticPosition pos, int startpc, int endpc, int handler_pc, int catch_type) { - if (startpc != endpc) { - char startpc1 = (char)startpc; - char endpc1 = (char)endpc; - char handler_pc1 = (char)handler_pc; - if (startpc1 == startpc && - endpc1 == endpc && - handler_pc1 == handler_pc) { - code.addCatch(startpc1, endpc1, handler_pc1, - (char)catch_type); + char startpc1 = (char)startpc; + char endpc1 = (char)endpc; + char handler_pc1 = (char)handler_pc; + if (startpc1 == startpc && + endpc1 == endpc && + handler_pc1 == handler_pc) { + code.addCatch(startpc1, endpc1, handler_pc1, + (char)catch_type); + } else { + if (!useJsrLocally && !target.generateStackMapTable()) { + useJsrLocally = true; + throw new CodeSizeOverflow(); } else { - if (!useJsrLocally && !target.generateStackMapTable()) { - useJsrLocally = true; - throw new CodeSizeOverflow(); - } else { - log.error(pos, "limit.code.too.large.for.try.stmt"); - nerrs++; - } + log.error(pos, "limit.code.too.large.for.try.stmt"); + nerrs++; } } } diff --git a/langtools/test/tools/javac/T7093325.java b/langtools/test/tools/javac/T7093325.java new file mode 100644 index 00000000000..42ea3bc0705 --- /dev/null +++ b/langtools/test/tools/javac/T7093325.java @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2011, 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 7093325 + * @summary Redundant entry in bytecode exception table + */ + +import com.sun.source.util.JavacTask; +import com.sun.tools.classfile.Attribute; +import com.sun.tools.classfile.ClassFile; +import com.sun.tools.classfile.Code_attribute; +import com.sun.tools.classfile.ConstantPool.*; +import com.sun.tools.classfile.Method; +import com.sun.tools.javac.api.JavacTool; + +import java.io.File; +import java.net.URI; +import java.util.Arrays; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.SimpleJavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; + + +public class T7093325 { + + /** global decls ***/ + + // Create a single file manager and reuse it for each compile to save time. + static StandardJavaFileManager fm = JavacTool.create().getStandardFileManager(null, null, null); + + //statistics + static int checkCount = 0; + + enum StatementKind { + THROW("throw new RuntimeException();", false, false), + RETURN_NONEMPTY("System.out.println(); return;", true, false), + RETURN_EMPTY("return;", true, true), + APPLY("System.out.println();", true, false); + + String stmt; + boolean canInline; + boolean empty; + + private StatementKind(String stmt, boolean canInline, boolean empty) { + this.stmt = stmt; + this.canInline = canInline; + this.empty = empty; + } + } + + enum CatchArity { + NONE(""), + ONE("catch (A a) { #S1 }"), + TWO("catch (B b) { #S2 }"), + THREE("catch (C c) { #S3 }"), + FOUR("catch (D d) { #S4 }"); + + String catchStr; + + private CatchArity(String catchStr) { + this.catchStr = catchStr; + } + + String catchers() { + if (this.ordinal() == 0) { + return catchStr; + } else { + return CatchArity.values()[this.ordinal() - 1].catchers() + catchStr; + } + } + } + + public static void main(String... args) throws Exception { + for (CatchArity ca : CatchArity.values()) { + for (StatementKind stmt0 : StatementKind.values()) { + if (ca.ordinal() == 0) { + new T7093325(ca, stmt0).compileAndCheck(); + continue; + } + for (StatementKind stmt1 : StatementKind.values()) { + if (ca.ordinal() == 1) { + new T7093325(ca, stmt0, stmt1).compileAndCheck(); + continue; + } + for (StatementKind stmt2 : StatementKind.values()) { + if (ca.ordinal() == 2) { + new T7093325(ca, stmt0, stmt1, stmt2).compileAndCheck(); + continue; + } + for (StatementKind stmt3 : StatementKind.values()) { + if (ca.ordinal() == 3) { + new T7093325(ca, stmt0, stmt1, stmt2, stmt3).compileAndCheck(); + continue; + } + for (StatementKind stmt4 : StatementKind.values()) { + if (ca.ordinal() == 4) { + new T7093325(ca, stmt0, stmt1, stmt2, stmt3, stmt4).compileAndCheck(); + continue; + } + for (StatementKind stmt5 : StatementKind.values()) { + new T7093325(ca, stmt0, stmt1, stmt2, stmt3, stmt4, stmt5).compileAndCheck(); + } + } + } + } + } + } + } + + System.out.println("Total checks made: " + checkCount); + } + + /** instance decls **/ + + CatchArity ca; + StatementKind[] stmts; + + public T7093325(CatchArity ca, StatementKind... stmts) { + this.ca = ca; + this.stmts = stmts; + } + + void compileAndCheck() throws Exception { + final JavaCompiler tool = ToolProvider.getSystemJavaCompiler(); + JavaSource source = new JavaSource(); + JavacTask ct = (JavacTask)tool.getTask(null, fm, null, + null, null, Arrays.asList(source)); + ct.call(); + verifyBytecode(source); + } + + void verifyBytecode(JavaSource source) { + checkCount++; + boolean lastInlined = false; + boolean hasCode = false; + int gapsCount = 0; + for (int i = 0; i < stmts.length ; i++) { + lastInlined = stmts[i].canInline; + hasCode = hasCode || !stmts[i].empty; + if (lastInlined && hasCode) { + hasCode = false; + gapsCount++; + } + } + if (!lastInlined) { + gapsCount++; + } + + //System.out.printf("gaps %d \n %s \n", gapsCount, source.toString()); + + File compiledTest = new File("Test.class"); + try { + ClassFile cf = ClassFile.read(compiledTest); + if (cf == null) { + throw new Error("Classfile not found: " + compiledTest.getName()); + } + + Method test_method = null; + for (Method m : cf.methods) { + if (m.getName(cf.constant_pool).equals("test")) { + test_method = m; + break; + } + } + + if (test_method == null) { + throw new Error("Method test() not found in class Test"); + } + + Code_attribute code = null; + for (Attribute a : test_method.attributes) { + if (a.getName(cf.constant_pool).equals(Attribute.Code)) { + code = (Code_attribute)a; + break; + } + } + + if (code == null) { + throw new Error("Code attribute not found in method test()"); + } + + int actualGapsCount = 0; + for (int i = 0; i < code.exception_table_langth ; i++) { + int catchType = code.exception_table[i].catch_type; + if (catchType == 0) { //any + actualGapsCount++; + } + } + + if (actualGapsCount != gapsCount) { + throw new Error("Bad exception table for test()\n" + + "expected gaps: " + gapsCount + "\n" + + "found gaps: " + actualGapsCount + "\n" + + source); + } + } catch (Exception e) { + e.printStackTrace(); + throw new Error("error reading " + compiledTest +": " + e); + } + + } + + class JavaSource extends SimpleJavaFileObject { + + static final String source_template = + "class A extends RuntimeException {} \n" + + "class B extends RuntimeException {} \n" + + "class C extends RuntimeException {} \n" + + "class D extends RuntimeException {} \n" + + "class E extends RuntimeException {} \n" + + "class Test {\n" + + " void test() {\n" + + " try { #S0 } #C finally { System.out.println(); }\n" + + " }\n" + + "}"; + + String source; + + public JavaSource() { + super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); + source = source_template.replace("#C", ca.catchers()); + source = source.replace("#S0", stmts[0].stmt); + for (int i = 1; i < ca.ordinal() + 1; i++) { + source = source.replace("#S" + i, stmts[i].stmt); + } + } + + @Override + public String toString() { + return source; + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return source; + } + } +} From 747169f70ef9947c6e6f1b2fa4c666bddc0d7021 Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Wed, 19 Oct 2011 16:56:05 +0100 Subject: [PATCH 031/107] 7102515: javac running very very long and not returning Verbose resolution diagnostics slow down with operator resolution Reviewed-by: jjg --- .../classes/com/sun/tools/javac/comp/Resolve.java | 2 ++ langtools/test/tools/javac/7102515/T7102515.java | 11 +++++++++++ langtools/test/tools/javac/7102515/T7102515.out | 3 +++ 3 files changed, 16 insertions(+) create mode 100644 langtools/test/tools/javac/7102515/T7102515.java create mode 100644 langtools/test/tools/javac/7102515/T7102515.out diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java index 43a8977d537..0c37d015188 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java @@ -691,6 +691,7 @@ public class Resolve { case ABSENT_MTH: return wrongMethod.setWrongSym(sym, ex.getDiagnostic()); case WRONG_MTH: + if (operator) return bestSoFar; wrongMethods.addCandidate(currentStep, wrongMethod.sym, wrongMethod.explanation); case WRONG_MTHS: return wrongMethods.addCandidate(currentStep, sym, ex.getDiagnostic()); @@ -1685,6 +1686,7 @@ public class Resolve { */ Symbol resolveOperator(DiagnosticPosition pos, int optag, Env env, List argtypes) { + startResolution(); Name name = treeinfo.operatorName(optag); Symbol sym = findMethod(env, syms.predefClass.type, name, argtypes, null, false, false, true); diff --git a/langtools/test/tools/javac/7102515/T7102515.java b/langtools/test/tools/javac/7102515/T7102515.java new file mode 100644 index 00000000000..da9ec633cb2 --- /dev/null +++ b/langtools/test/tools/javac/7102515/T7102515.java @@ -0,0 +1,11 @@ +/* + * @test /nodynamiccopyright/ + * @bug 7102515 + * @summary javac running very very long and not returning + * @compile/fail/ref=T7102515.out -XDrawDiagnostics T7102515.java + */ + +class T7102515 { + T7102515 badBinary = new T7102515() + new T7102515(); + Object badUnary = badBinary++; +} diff --git a/langtools/test/tools/javac/7102515/T7102515.out b/langtools/test/tools/javac/7102515/T7102515.out new file mode 100644 index 00000000000..00df5201cf4 --- /dev/null +++ b/langtools/test/tools/javac/7102515/T7102515.out @@ -0,0 +1,3 @@ +T7102515.java:9:41: compiler.err.operator.cant.be.applied.1: +, T7102515, T7102515 +T7102515.java:10:32: compiler.err.operator.cant.be.applied: ++, T7102515, null +2 errors From 6c299173e18093413a1b9e02790eae18181df4aa Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Wed, 19 Oct 2011 15:29:46 -0700 Subject: [PATCH 032/107] 7101146: Paths should more directly managed by BaseFileManager Reviewed-by: mcimadamore --- .../tools/javac/file/JavacFileManager.java | 28 ++++++----------- .../com/sun/tools/javac/file/Paths.java | 30 ++++--------------- .../tools/javac/nio/JavacPathFileManager.java | 7 +---- .../sun/tools/javac/util/BaseFileManager.java | 24 +++++++++++---- 4 files changed, 34 insertions(+), 55 deletions(-) diff --git a/langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java b/langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java index ff10fd3ed36..ae6cf2d2757 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java +++ b/langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java @@ -25,7 +25,6 @@ package com.sun.tools.javac.file; -import java.util.Comparator; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileNotFoundException; @@ -41,6 +40,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.EnumSet; import java.util.HashMap; import java.util.Iterator; @@ -54,6 +54,7 @@ import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; +import com.sun.tools.javac.code.Lint; import com.sun.tools.javac.file.RelativePath.RelativeFile; import com.sun.tools.javac.file.RelativePath.RelativeDirectory; import com.sun.tools.javac.main.OptionName; @@ -83,10 +84,6 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil return buffer.toString().toCharArray(); } - /** Encapsulates knowledge of paths - */ - private Paths paths; - private FSInfo fsInfo; private boolean contextUseOptimizedZip; @@ -154,13 +151,6 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil @Override public void setContext(Context context) { super.setContext(context); - if (paths == null) { - paths = Paths.instance(context); - } else { - // Reuse the Paths object as it stores the locations that - // have been set with setLocation, etc. - paths.setContext(context); - } fsInfo = FSInfo.instance(context); @@ -179,7 +169,7 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil @Override public boolean isDefaultBootClassPath() { - return paths.isDefaultBootClassPath(); + return searchPaths.isDefaultBootClassPath(); } public JavaFileObject getFileForInput(String name) { @@ -493,7 +483,7 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil */ private Archive openArchive(File zipFileName, boolean useOptimizedZip) throws IOException { File origZipFileName = zipFileName; - if (!ignoreSymbolFile && paths.isDefaultBootClassPathRtJar(zipFileName)) { + if (!ignoreSymbolFile && searchPaths.isDefaultBootClassPathRtJar(zipFileName)) { File file = zipFileName.getParentFile().getParentFile(); // ${java.home} if (new File(file.getName()).equals(new File("jre"))) file = file.getParentFile(); @@ -780,7 +770,7 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil } else if (location == SOURCE_OUTPUT) { dir = (getSourceOutDir() != null ? getSourceOutDir() : getClassOutDir()); } else { - Iterable path = paths.getPathForLocation(location); + Iterable path = searchPaths.getPathForLocation(location); dir = null; for (File f: path) { dir = f; @@ -815,7 +805,7 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil throws IOException { nullCheck(location); - paths.lazy(); + searchPaths.lazy(); final File dir = location.isOutputLocation() ? getOutputDirectory(path) : null; @@ -824,7 +814,7 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil else if (location == SOURCE_OUTPUT) sourceOutDir = getOutputLocation(dir, S); else - paths.setPathForLocation(location, path); + searchPaths.setPathForLocation(location, path); } // where private File getOutputDirectory(Iterable path) throws IOException { @@ -854,13 +844,13 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil public Iterable getLocation(Location location) { nullCheck(location); - paths.lazy(); + searchPaths.lazy(); if (location == CLASS_OUTPUT) { return (getClassOutDir() == null ? null : List.of(getClassOutDir())); } else if (location == SOURCE_OUTPUT) { return (getSourceOutDir() == null ? null : List.of(getSourceOutDir())); } else - return paths.getPathForLocation(location); + return searchPaths.getPathForLocation(location); } private File getClassOutDir() { diff --git a/langtools/src/share/classes/com/sun/tools/javac/file/Paths.java b/langtools/src/share/classes/com/sun/tools/javac/file/Paths.java index 3e0ec5abd15..69a74cc79f5 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/file/Paths.java +++ b/langtools/src/share/classes/com/sun/tools/javac/file/Paths.java @@ -41,7 +41,6 @@ import java.util.zip.ZipFile; import javax.tools.JavaFileManager.Location; import com.sun.tools.javac.code.Lint; -import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Log; import com.sun.tools.javac.util.Options; @@ -61,21 +60,6 @@ import static com.sun.tools.javac.main.OptionName.*; */ public class Paths { - /** The context key for the todo list */ - protected static final Context.Key pathsKey = - new Context.Key(); - - /** Get the Paths instance for this context. - * @param context the context - * @return the Paths instance for this context - */ - public static Paths instance(Context context) { - Paths instance = context.get(pathsKey); - if (instance == null) - instance = new Paths(context); - return instance; - } - /** The log to use for warning output */ private Log log; @@ -88,17 +72,15 @@ public class Paths { /** Access to (possibly cached) file info */ private FSInfo fsInfo; - protected Paths(Context context) { - context.put(pathsKey, this); + public Paths() { pathsForLocation = new HashMap(16); - setContext(context); } - void setContext(Context context) { - log = Log.instance(context); - options = Options.instance(context); - lint = Lint.instance(context); - fsInfo = FSInfo.instance(context); + public void update(Log log, Options options, Lint lint, FSInfo fsInfo) { + this.log = log; + this.options = options; + this.lint = lint; + this.fsInfo = fsInfo; } /** Whether to warn about non-existent path elements */ diff --git a/langtools/src/share/classes/com/sun/tools/javac/nio/JavacPathFileManager.java b/langtools/src/share/classes/com/sun/tools/javac/nio/JavacPathFileManager.java index bb0c6205a10..5ed6334cb41 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/nio/JavacPathFileManager.java +++ b/langtools/src/share/classes/com/sun/tools/javac/nio/JavacPathFileManager.java @@ -25,9 +25,7 @@ package com.sun.tools.javac.nio; - import java.io.File; -import java.io.FileNotFoundException; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; @@ -60,7 +58,6 @@ import javax.tools.StandardLocation; import static java.nio.file.FileVisitOption.*; import static javax.tools.StandardLocation.*; -import com.sun.tools.javac.file.Paths; import com.sun.tools.javac.util.BaseFileManager; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.List; @@ -125,9 +122,8 @@ public class JavacPathFileManager extends BaseFileManager implements PathFileMan * Set the context for JavacPathFileManager. */ @Override - protected void setContext(Context context) { + public void setContext(Context context) { super.setContext(context); - searchPaths = Paths.instance(context); } @Override @@ -272,7 +268,6 @@ public class JavacPathFileManager extends BaseFileManager implements PathFileMan private boolean inited = false; private Map pathsForLocation; - private Paths searchPaths; private static class PathsForLocation extends LinkedHashSet { private static final long serialVersionUID = 6788510222394486733L; diff --git a/langtools/src/share/classes/com/sun/tools/javac/util/BaseFileManager.java b/langtools/src/share/classes/com/sun/tools/javac/util/BaseFileManager.java index c9d7d8b2b4c..d393088c414 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/util/BaseFileManager.java +++ b/langtools/src/share/classes/com/sun/tools/javac/util/BaseFileManager.java @@ -25,11 +25,6 @@ package com.sun.tools.javac.util; -import com.sun.tools.javac.code.Source; -import com.sun.tools.javac.main.JavacOption; -import com.sun.tools.javac.main.OptionName; -import com.sun.tools.javac.main.RecognizedOptions; -import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition; import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.IOException; @@ -54,6 +49,15 @@ import java.util.Map; import javax.tools.JavaFileObject; import javax.tools.JavaFileObject.Kind; +import com.sun.tools.javac.code.Lint; +import com.sun.tools.javac.code.Source; +import com.sun.tools.javac.file.FSInfo; +import com.sun.tools.javac.file.Paths; +import com.sun.tools.javac.main.JavacOption; +import com.sun.tools.javac.main.OptionName; +import com.sun.tools.javac.main.RecognizedOptions; +import com.sun.tools.javac.util.JCDiagnostic.SimpleDiagnosticPosition; + /** * Utility methods for building a filemanager. * There are no references here to file-system specific objects such as @@ -63,15 +67,21 @@ public abstract class BaseFileManager { protected BaseFileManager(Charset charset) { this.charset = charset; byteBufferCache = new ByteBufferCache(); + searchPaths = createPaths(); } /** * Set the context for JavacPathFileManager. */ - protected void setContext(Context context) { + public void setContext(Context context) { log = Log.instance(context); options = Options.instance(context); classLoaderClass = options.get("procloader"); + searchPaths.update(log, options, Lint.instance(context), FSInfo.instance(context)); + } + + protected Paths createPaths() { + return new Paths(); } /** @@ -88,6 +98,8 @@ public abstract class BaseFileManager { protected String classLoaderClass; + protected Paths searchPaths; + protected Source getSource() { String sourceName = options.get(OptionName.SOURCE); Source source = null; From 8fb3eec82e4ec24502f6212f4cde57f015524d93 Mon Sep 17 00:00:00 2001 From: Bengt Rutisson Date: Thu, 20 Oct 2011 10:21:35 +0200 Subject: [PATCH 033/107] 7097516: G1: assert(0<= from_card && from_cardis_in_reserved(from)) { + // If the table used to belong to a continues humongous region and is + // now reused for the corresponding start humongous region, we need to + // make sure that we detect this. Thus, we call is_in_reserved_raw() + // instead of just is_in_reserved() here. + if (loc_hr->is_in_reserved_raw(from)) { size_t hw_offset = pointer_delta((HeapWord*)from, loc_hr->bottom()); CardIdx_t from_card = (CardIdx_t) hw_offset >> (CardTableModRefBS::card_shift - LogHeapWordSize); From c8143a724ef6213977d9b5bbfe5071e114397a7a Mon Sep 17 00:00:00 2001 From: John Cuthbertson Date: Thu, 20 Oct 2011 12:06:20 -0700 Subject: [PATCH 034/107] 7099824: G1: we should take the pending list lock before doing the remark pause Acquire the pending list lock in the prologue method of G1's concurrent VM_Operation and release the lock in the epilogue() method. The locking/unlocking order of the pending list lock and the Heap_lock should match that in the prologue and epilogue methods of VM_GC_Operation. Reviewed-by: tonyp, ysr --- .../g1/concurrentMarkThread.cpp | 19 ++++++++-------- .../gc_implementation/g1/vm_operations_g1.cpp | 22 +++++++++++++++++++ .../gc_implementation/g1/vm_operations_g1.hpp | 8 ++++++- .../shared/concurrentGCThread.cpp | 2 ++ 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp index 4e4e6422956..0a4c81a2f46 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMarkThread.cpp @@ -147,12 +147,8 @@ void ConcurrentMarkThread::run() { } } } while (cm()->restart_for_overflow()); + double counting_start_time = os::elapsedVTime(); - - // YSR: These look dubious (i.e. redundant) !!! FIX ME - slt()->manipulatePLL(SurrogateLockerThread::acquirePLL); - slt()->manipulatePLL(SurrogateLockerThread::releaseAndNotifyPLL); - if (!cm()->has_aborted()) { double count_start_sec = os::elapsedTime(); if (PrintGC) { @@ -175,6 +171,7 @@ void ConcurrentMarkThread::run() { } } } + double end_time = os::elapsedVTime(); _vtime_count_accum += (end_time - counting_start_time); // Update the total virtual time before doing this, since it will try @@ -335,13 +332,15 @@ void ConcurrentMarkThread::sleepBeforeNextCycle() { clear_started(); } -// Note: this method, although exported by the ConcurrentMarkSweepThread, -// which is a non-JavaThread, can only be called by a JavaThread. -// Currently this is done at vm creation time (post-vm-init) by the -// main/Primordial (Java)Thread. -// XXX Consider changing this in the future to allow the CMS thread +// Note: As is the case with CMS - this method, although exported +// by the ConcurrentMarkThread, which is a non-JavaThread, can only +// be called by a JavaThread. Currently this is done at vm creation +// time (post-vm-init) by the main/Primordial (Java)Thread. +// XXX Consider changing this in the future to allow the CM thread // itself to create this thread? void ConcurrentMarkThread::makeSurrogateLockerThread(TRAPS) { + assert(UseG1GC, "SLT thread needed only for concurrent GC"); + assert(THREAD->is_Java_thread(), "must be a Java thread"); assert(_slt == NULL, "SLT already created"); _slt = SurrogateLockerThread::make(THREAD); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp b/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp index 04d051b8443..befacd69e5e 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "gc_implementation/g1/concurrentMarkThread.inline.hpp" #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1CollectorPolicy.hpp" #include "gc_implementation/g1/vm_operations_g1.hpp" @@ -165,6 +166,20 @@ void VM_G1IncCollectionPause::doit_epilogue() { } } +void VM_CGC_Operation::acquire_pending_list_lock() { + // The caller may block while communicating + // with the SLT thread in order to acquire/release the PLL. + ConcurrentMarkThread::slt()-> + manipulatePLL(SurrogateLockerThread::acquirePLL); +} + +void VM_CGC_Operation::release_and_notify_pending_list_lock() { + // The caller may block while communicating + // with the SLT thread in order to acquire/release the PLL. + ConcurrentMarkThread::slt()-> + manipulatePLL(SurrogateLockerThread::releaseAndNotifyPLL); +} + void VM_CGC_Operation::doit() { gclog_or_tty->date_stamp(PrintGC && PrintGCDateStamps); TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); @@ -180,12 +195,19 @@ void VM_CGC_Operation::doit() { } bool VM_CGC_Operation::doit_prologue() { + // Note the relative order of the locks must match that in + // VM_GC_Operation::doit_prologue() or deadlocks can occur + acquire_pending_list_lock(); + Heap_lock->lock(); SharedHeap::heap()->_thread_holds_heap_lock_for_gc = true; return true; } void VM_CGC_Operation::doit_epilogue() { + // Note the relative order of the unlocks must match that in + // VM_GC_Operation::doit_epilogue() SharedHeap::heap()->_thread_holds_heap_lock_for_gc = false; Heap_lock->unlock(); + release_and_notify_pending_list_lock(); } diff --git a/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.hpp b/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.hpp index 825818dd4e6..c8bbe06198f 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.hpp @@ -93,11 +93,17 @@ public: } }; -// Concurrent GC stop-the-world operations such as initial and final mark; +// Concurrent GC stop-the-world operations such as remark and cleanup; // consider sharing these with CMS's counterparts. class VM_CGC_Operation: public VM_Operation { VoidClosure* _cl; const char* _printGCMessage; + +protected: + // java.lang.ref.Reference support + void acquire_pending_list_lock(); + void release_and_notify_pending_list_lock(); + public: VM_CGC_Operation(VoidClosure* cl, const char *printGCMsg) : _cl(cl), _printGCMessage(printGCMsg) { } diff --git a/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.cpp b/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.cpp index a231e5d8169..0dea4208091 100644 --- a/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.cpp +++ b/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.cpp @@ -224,6 +224,8 @@ void SurrogateLockerThread::manipulatePLL(SLT_msg_type msg) { MutexLockerEx x(&_monitor, Mutex::_no_safepoint_check_flag); assert(_buffer == empty, "Should be empty"); assert(msg != empty, "empty message"); + assert(!Heap_lock->owned_by_self(), "Heap_lock owned by requesting thread"); + _buffer = msg; while (_buffer != empty) { _monitor.notify(); From 5955806228a2303d22f38bb6f129bc51fc6a132a Mon Sep 17 00:00:00 2001 From: Jim Holmlund Date: Fri, 21 Oct 2011 14:14:29 -0700 Subject: [PATCH 035/107] 7098530: tools/javac/javazip/Test.sh can fail on Windows Fix cygpath command to properly convert path Reviewed-by: jjg --- langtools/test/tools/javac/javazip/Test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/langtools/test/tools/javac/javazip/Test.sh b/langtools/test/tools/javac/javazip/Test.sh index 896b6a8d77a..c8a59a600be 100644 --- a/langtools/test/tools/javac/javazip/Test.sh +++ b/langtools/test/tools/javac/javazip/Test.sh @@ -47,7 +47,7 @@ case "$OS" in ;; CYGWIN* ) FS="/" - SCR=`pwd | cygpath -d` + SCR=`pwd | cygpath -d -f -` ;; Windows* ) FS="\\" From 1c38082fccfcb172e86417305953116bf4a88c75 Mon Sep 17 00:00:00 2001 From: Alejandro Murillo Date: Fri, 21 Oct 2011 16:00:50 -0700 Subject: [PATCH 036/107] 7103619: Bump the hs23 build number to 04 Reviewed-by: johnc --- hotspot/make/hotspot_version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/make/hotspot_version b/hotspot/make/hotspot_version index 72ac0d3920e..09ea6779834 100644 --- a/hotspot/make/hotspot_version +++ b/hotspot/make/hotspot_version @@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2011 HS_MAJOR_VER=23 HS_MINOR_VER=0 -HS_BUILD_NUMBER=03 +HS_BUILD_NUMBER=04 JDK_MAJOR_VER=1 JDK_MINOR_VER=8 From 72c2cfef4f2fd0ba9ec3d84d9f544c4a488560f5 Mon Sep 17 00:00:00 2001 From: John Cuthbertson Date: Sun, 23 Oct 2011 23:06:06 -0700 Subject: [PATCH 037/107] 7096030: G1: PrintGCDetails enhancements 7102445: G1: Unnecessary Resource allocations during RSet scanning Add a new per-worker thread line in the PrintGCDetails output. GC Worker Other is the difference between the elapsed time for the parallel phase of the evacuation pause and the sum of the times of the sub-phases (external root scanning, mark stack scanning, RSet updating, RSet scanning, object copying, and termination) for that worker. During RSet scanning, stack allocate DirtyCardToOopClosure objects; allocating these in a resource area was causing abnormally high GC Worker Other times while the worker thread freed ResourceArea chunks. Reviewed-by: tonyp, jwilhelm, brutisso --- .../gc_implementation/g1/g1CollectedHeap.cpp | 44 ++-- .../g1/g1CollectorPolicy.cpp | 213 ++++++++++-------- .../g1/g1CollectorPolicy.hpp | 13 +- .../vm/gc_implementation/g1/g1RemSet.cpp | 10 +- .../vm/gc_implementation/g1/heapRegion.cpp | 8 - .../vm/gc_implementation/g1/heapRegion.hpp | 5 - 6 files changed, 159 insertions(+), 134 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp index b8b80ae9e5d..62a5bb57b19 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -5502,34 +5502,36 @@ void G1CollectedHeap::cleanUpCardTable() { CardTableModRefBS* ct_bs = (CardTableModRefBS*) (barrier_set()); double start = os::elapsedTime(); - // Iterate over the dirty cards region list. - G1ParCleanupCTTask cleanup_task(ct_bs, this); + { + // Iterate over the dirty cards region list. + G1ParCleanupCTTask cleanup_task(ct_bs, this); - if (ParallelGCThreads > 0) { - set_par_threads(workers()->total_workers()); - workers()->run_task(&cleanup_task); - set_par_threads(0); - } else { - while (_dirty_cards_region_list) { - HeapRegion* r = _dirty_cards_region_list; - cleanup_task.clear_cards(r); - _dirty_cards_region_list = r->get_next_dirty_cards_region(); - if (_dirty_cards_region_list == r) { - // The last region. - _dirty_cards_region_list = NULL; + if (ParallelGCThreads > 0) { + set_par_threads(workers()->total_workers()); + workers()->run_task(&cleanup_task); + set_par_threads(0); + } else { + while (_dirty_cards_region_list) { + HeapRegion* r = _dirty_cards_region_list; + cleanup_task.clear_cards(r); + _dirty_cards_region_list = r->get_next_dirty_cards_region(); + if (_dirty_cards_region_list == r) { + // The last region. + _dirty_cards_region_list = NULL; + } + r->set_next_dirty_cards_region(NULL); } - r->set_next_dirty_cards_region(NULL); } +#ifndef PRODUCT + if (G1VerifyCTCleanup || VerifyAfterGC) { + G1VerifyCardTableCleanup cleanup_verifier(this, ct_bs); + heap_region_iterate(&cleanup_verifier); + } +#endif } double elapsed = os::elapsedTime() - start; g1_policy()->record_clear_ct_time(elapsed * 1000.0); -#ifndef PRODUCT - if (G1VerifyCTCleanup || VerifyAfterGC) { - G1VerifyCardTableCleanup cleanup_verifier(this, ct_bs); - heap_region_iterate(&cleanup_verifier); - } -#endif } void G1CollectedHeap::free_collection_set(HeapRegion* cs_head) { diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp index bc575fa673e..b7fd0c190f7 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp @@ -320,6 +320,7 @@ G1CollectorPolicy::G1CollectorPolicy() : _par_last_termination_attempts = new double[_parallel_gc_threads]; _par_last_gc_worker_end_times_ms = new double[_parallel_gc_threads]; _par_last_gc_worker_times_ms = new double[_parallel_gc_threads]; + _par_last_gc_worker_other_times_ms = new double[_parallel_gc_threads]; // start conservatively _expensive_region_limit_ms = 0.5 * (double) MaxGCPauseMillis; @@ -976,6 +977,7 @@ void G1CollectorPolicy::record_collection_pause_start(double start_time_sec, _par_last_termination_attempts[i] = -1234.0; _par_last_gc_worker_end_times_ms[i] = -1234.0; _par_last_gc_worker_times_ms[i] = -1234.0; + _par_last_gc_worker_other_times_ms[i] = -1234.0; } #endif @@ -984,8 +986,10 @@ void G1CollectorPolicy::record_collection_pause_start(double start_time_sec, _cur_aux_times_set[i] = false; } - _satb_drain_time_set = false; - _last_satb_drain_processed_buffers = -1; + // These are initialized to zero here and they are set during + // the evacuation pause if marking is in progress. + _cur_satb_drain_time_ms = 0.0; + _last_satb_drain_processed_buffers = 0; _last_young_gc_full = false; @@ -1097,61 +1101,65 @@ void G1CollectorPolicy::print_par_sizes(int level, (int)total, (int)avg, (int)min, (int)max, (int)max - (int)min); } -void G1CollectorPolicy::print_stats (int level, - const char* str, - double value) { +void G1CollectorPolicy::print_stats(int level, + const char* str, + double value) { LineBuffer(level).append_and_print_cr("[%s: %5.1lf ms]", str, value); } -void G1CollectorPolicy::print_stats (int level, - const char* str, - int value) { +void G1CollectorPolicy::print_stats(int level, + const char* str, + int value) { LineBuffer(level).append_and_print_cr("[%s: %d]", str, value); } -double G1CollectorPolicy::avg_value (double* data) { +double G1CollectorPolicy::avg_value(double* data) { if (G1CollectedHeap::use_parallel_gc_threads()) { double ret = 0.0; - for (uint i = 0; i < ParallelGCThreads; ++i) + for (uint i = 0; i < ParallelGCThreads; ++i) { ret += data[i]; + } return ret / (double) ParallelGCThreads; } else { return data[0]; } } -double G1CollectorPolicy::max_value (double* data) { +double G1CollectorPolicy::max_value(double* data) { if (G1CollectedHeap::use_parallel_gc_threads()) { double ret = data[0]; - for (uint i = 1; i < ParallelGCThreads; ++i) - if (data[i] > ret) + for (uint i = 1; i < ParallelGCThreads; ++i) { + if (data[i] > ret) { ret = data[i]; + } + } return ret; } else { return data[0]; } } -double G1CollectorPolicy::sum_of_values (double* data) { +double G1CollectorPolicy::sum_of_values(double* data) { if (G1CollectedHeap::use_parallel_gc_threads()) { double sum = 0.0; - for (uint i = 0; i < ParallelGCThreads; i++) + for (uint i = 0; i < ParallelGCThreads; i++) { sum += data[i]; + } return sum; } else { return data[0]; } } -double G1CollectorPolicy::max_sum (double* data1, - double* data2) { +double G1CollectorPolicy::max_sum(double* data1, double* data2) { double ret = data1[0] + data2[0]; if (G1CollectedHeap::use_parallel_gc_threads()) { for (uint i = 1; i < ParallelGCThreads; ++i) { double data = data1[i] + data2[i]; - if (data > ret) + if (data > ret) { ret = data; + } } } return ret; @@ -1251,6 +1259,10 @@ void G1CollectorPolicy::record_collection_pause_end() { _n_pauses++; + // These values are used to update the summary information that is + // displayed when TraceGen0Time is enabled, and are output as part + // of the PrintGCDetails output, in the non-parallel case. + double ext_root_scan_time = avg_value(_par_last_ext_root_scan_times_ms); double mark_stack_scan_time = avg_value(_par_last_mark_stack_scan_times_ms); double update_rs_time = avg_value(_par_last_update_rs_times_ms); @@ -1260,42 +1272,68 @@ void G1CollectorPolicy::record_collection_pause_end() { double obj_copy_time = avg_value(_par_last_obj_copy_times_ms); double termination_time = avg_value(_par_last_termination_times_ms); - double parallel_known_time = update_rs_time + - ext_root_scan_time + - mark_stack_scan_time + - scan_rs_time + - obj_copy_time + - termination_time; + double known_time = ext_root_scan_time + + mark_stack_scan_time + + update_rs_time + + scan_rs_time + + obj_copy_time; - double parallel_other_time = _cur_collection_par_time_ms - parallel_known_time; + double other_time_ms = elapsed_ms; - PauseSummary* summary = _summary; + // Subtract the SATB drain time. It's initialized to zero at the + // start of the pause and is updated during the pause if marking + // is in progress. + other_time_ms -= _cur_satb_drain_time_ms; + + if (parallel) { + other_time_ms -= _cur_collection_par_time_ms; + } else { + other_time_ms -= known_time; + } + + // Subtract the time taken to clean the card table from the + // current value of "other time" + other_time_ms -= _cur_clear_ct_time_ms; + + // TraceGen0Time and TraceGen1Time summary info updating. + _all_pause_times_ms->add(elapsed_ms); if (update_stats) { _recent_rs_scan_times_ms->add(scan_rs_time); _recent_pause_times_ms->add(elapsed_ms); _recent_rs_sizes->add(rs_size); - MainBodySummary* body_summary = summary->main_body_summary(); - guarantee(body_summary != NULL, "should not be null!"); + _summary->record_total_time_ms(elapsed_ms); + _summary->record_other_time_ms(other_time_ms); - if (_satb_drain_time_set) - body_summary->record_satb_drain_time_ms(_cur_satb_drain_time_ms); - else - body_summary->record_satb_drain_time_ms(0.0); + MainBodySummary* body_summary = _summary->main_body_summary(); + assert(body_summary != NULL, "should not be null!"); + + // This will be non-zero iff marking is currently in progress (i.e. + // _g1->mark_in_progress() == true) and the currrent pause was not + // an initial mark pause. Since the body_summary items are NumberSeqs, + // however, they have to be consistent and updated in lock-step with + // each other. Therefore we unconditionally record the SATB drain + // time - even if it's zero. + body_summary->record_satb_drain_time_ms(_cur_satb_drain_time_ms); body_summary->record_ext_root_scan_time_ms(ext_root_scan_time); body_summary->record_mark_stack_scan_time_ms(mark_stack_scan_time); body_summary->record_update_rs_time_ms(update_rs_time); body_summary->record_scan_rs_time_ms(scan_rs_time); body_summary->record_obj_copy_time_ms(obj_copy_time); + if (parallel) { body_summary->record_parallel_time_ms(_cur_collection_par_time_ms); - body_summary->record_clear_ct_time_ms(_cur_clear_ct_time_ms); body_summary->record_termination_time_ms(termination_time); + + double parallel_known_time = known_time + termination_time; + double parallel_other_time = _cur_collection_par_time_ms - parallel_known_time; body_summary->record_parallel_other_time_ms(parallel_other_time); } + body_summary->record_mark_closure_time_ms(_mark_closure_time_ms); + body_summary->record_clear_ct_time_ms(_cur_clear_ct_time_ms); // We exempt parallel collection from this check because Alloc Buffer // fragmentation can produce negative collections. Same with evac @@ -1307,6 +1345,7 @@ void G1CollectorPolicy::record_collection_pause_end() { || _g1->evacuation_failed() || surviving_bytes <= _collection_set_bytes_used_before, "Or else negative collection!"); + _recent_CS_bytes_used_before->add(_collection_set_bytes_used_before); _recent_CS_bytes_surviving->add(surviving_bytes); @@ -1357,6 +1396,13 @@ void G1CollectorPolicy::record_collection_pause_end() { } } + for (int i = 0; i < _aux_num; ++i) { + if (_cur_aux_times_set[i]) { + _all_aux_times_ms[i].add(_cur_aux_times_ms[i]); + } + } + + if (G1PolicyVerbose > 1) { gclog_or_tty->print_cr(" Recording collection pause(%d)", _n_pauses); } @@ -1383,61 +1429,60 @@ void G1CollectorPolicy::record_collection_pause_end() { recent_avg_pause_time_ratio() * 100.0); } - double other_time_ms = elapsed_ms; - - if (_satb_drain_time_set) { - other_time_ms -= _cur_satb_drain_time_ms; - } - - if (parallel) { - other_time_ms -= _cur_collection_par_time_ms + _cur_clear_ct_time_ms; - } else { - other_time_ms -= - update_rs_time + - ext_root_scan_time + mark_stack_scan_time + - scan_rs_time + obj_copy_time; - } - + // PrintGCDetails output if (PrintGCDetails) { + bool print_marking_info = + _g1->mark_in_progress() && !last_pause_included_initial_mark; + gclog_or_tty->print_cr("%s, %1.8lf secs]", (last_pause_included_initial_mark) ? " (initial-mark)" : "", elapsed_ms / 1000.0); - if (_satb_drain_time_set) { + if (print_marking_info) { print_stats(1, "SATB Drain Time", _cur_satb_drain_time_ms); - } - if (_last_satb_drain_processed_buffers >= 0) { print_stats(2, "Processed Buffers", _last_satb_drain_processed_buffers); } + if (parallel) { print_stats(1, "Parallel Time", _cur_collection_par_time_ms); - print_par_stats(2, "GC Worker Start Time", _par_last_gc_worker_start_times_ms); + print_par_stats(2, "GC Worker Start", _par_last_gc_worker_start_times_ms); + print_par_stats(2, "Ext Root Scanning", _par_last_ext_root_scan_times_ms); + if (print_marking_info) { + print_par_stats(2, "Mark Stack Scanning", _par_last_mark_stack_scan_times_ms); + } print_par_stats(2, "Update RS", _par_last_update_rs_times_ms); print_par_sizes(3, "Processed Buffers", _par_last_update_rs_processed_buffers); - print_par_stats(2, "Ext Root Scanning", _par_last_ext_root_scan_times_ms); - print_par_stats(2, "Mark Stack Scanning", _par_last_mark_stack_scan_times_ms); print_par_stats(2, "Scan RS", _par_last_scan_rs_times_ms); print_par_stats(2, "Object Copy", _par_last_obj_copy_times_ms); print_par_stats(2, "Termination", _par_last_termination_times_ms); print_par_sizes(3, "Termination Attempts", _par_last_termination_attempts); - print_par_stats(2, "GC Worker End Time", _par_last_gc_worker_end_times_ms); + print_par_stats(2, "GC Worker End", _par_last_gc_worker_end_times_ms); for (int i = 0; i < _parallel_gc_threads; i++) { _par_last_gc_worker_times_ms[i] = _par_last_gc_worker_end_times_ms[i] - _par_last_gc_worker_start_times_ms[i]; - } - print_par_stats(2, "GC Worker Times", _par_last_gc_worker_times_ms); - print_stats(2, "Parallel Other", parallel_other_time); - print_stats(1, "Clear CT", _cur_clear_ct_time_ms); + double worker_known_time = _par_last_ext_root_scan_times_ms[i] + + _par_last_mark_stack_scan_times_ms[i] + + _par_last_update_rs_times_ms[i] + + _par_last_scan_rs_times_ms[i] + + _par_last_obj_copy_times_ms[i] + + _par_last_termination_times_ms[i]; + + _par_last_gc_worker_other_times_ms[i] = _cur_collection_par_time_ms - worker_known_time; + } + print_par_stats(2, "GC Worker", _par_last_gc_worker_times_ms); + print_par_stats(2, "GC Worker Other", _par_last_gc_worker_other_times_ms); } else { - print_stats(1, "Update RS", update_rs_time); - print_stats(2, "Processed Buffers", - (int)update_rs_processed_buffers); print_stats(1, "Ext Root Scanning", ext_root_scan_time); - print_stats(1, "Mark Stack Scanning", mark_stack_scan_time); + if (print_marking_info) { + print_stats(1, "Mark Stack Scanning", mark_stack_scan_time); + } + print_stats(1, "Update RS", update_rs_time); + print_stats(2, "Processed Buffers", (int)update_rs_processed_buffers); print_stats(1, "Scan RS", scan_rs_time); print_stats(1, "Object Copying", obj_copy_time); } + print_stats(1, "Clear CT", _cur_clear_ct_time_ms); #ifndef PRODUCT print_stats(1, "Cur Clear CC", _cur_clear_cc_time_ms); print_stats(1, "Cum Clear CC", _cum_clear_cc_time_ms); @@ -1461,16 +1506,6 @@ void G1CollectorPolicy::record_collection_pause_end() { } } - _all_pause_times_ms->add(elapsed_ms); - if (update_stats) { - summary->record_total_time_ms(elapsed_ms); - summary->record_other_time_ms(other_time_ms); - } - for (int i = 0; i < _aux_num; ++i) - if (_cur_aux_times_set[i]) { - _all_aux_times_ms[i].add(_cur_aux_times_ms[i]); - } - // Update the efficiency-since-mark vars. double proc_ms = elapsed_ms * (double) _parallel_gc_threads; if (elapsed_ms < MIN_TIMER_GRANULARITY) { @@ -2138,17 +2173,17 @@ void G1CollectorPolicy::count_CS_bytes_used() { _g1->collection_set_iterate(&cs_closure); } -void G1CollectorPolicy::print_summary (int level, - const char* str, - NumberSeq* seq) const { +void G1CollectorPolicy::print_summary(int level, + const char* str, + NumberSeq* seq) const { double sum = seq->sum(); LineBuffer(level + 1).append_and_print_cr("%-24s = %8.2lf s (avg = %8.2lf ms)", str, sum / 1000.0, seq->avg()); } -void G1CollectorPolicy::print_summary_sd (int level, - const char* str, - NumberSeq* seq) const { +void G1CollectorPolicy::print_summary_sd(int level, + const char* str, + NumberSeq* seq) const { print_summary(level, str, seq); LineBuffer(level + 6).append_and_print_cr("(num = %5d, std dev = %8.2lf ms, max = %8.2lf ms)", seq->num(), seq->sd(), seq->maximum()); @@ -2211,20 +2246,18 @@ void G1CollectorPolicy::print_summary(PauseSummary* summary) const { print_summary(1, "SATB Drain", body_summary->get_satb_drain_seq()); if (parallel) { print_summary(1, "Parallel Time", body_summary->get_parallel_seq()); + print_summary(2, "Ext Root Scanning", body_summary->get_ext_root_scan_seq()); + print_summary(2, "Mark Stack Scanning", body_summary->get_mark_stack_scan_seq()); print_summary(2, "Update RS", body_summary->get_update_rs_seq()); - print_summary(2, "Ext Root Scanning", - body_summary->get_ext_root_scan_seq()); - print_summary(2, "Mark Stack Scanning", - body_summary->get_mark_stack_scan_seq()); print_summary(2, "Scan RS", body_summary->get_scan_rs_seq()); print_summary(2, "Object Copy", body_summary->get_obj_copy_seq()); print_summary(2, "Termination", body_summary->get_termination_seq()); - print_summary(2, "Other", body_summary->get_parallel_other_seq()); + print_summary(2, "Parallel Other", body_summary->get_parallel_other_seq()); { NumberSeq* other_parts[] = { - body_summary->get_update_rs_seq(), body_summary->get_ext_root_scan_seq(), body_summary->get_mark_stack_scan_seq(), + body_summary->get_update_rs_seq(), body_summary->get_scan_rs_seq(), body_summary->get_obj_copy_seq(), body_summary->get_termination_seq() @@ -2234,18 +2267,16 @@ void G1CollectorPolicy::print_summary(PauseSummary* summary) const { check_other_times(2, body_summary->get_parallel_other_seq(), &calc_other_times_ms); } - print_summary(1, "Mark Closure", body_summary->get_mark_closure_seq()); - print_summary(1, "Clear CT", body_summary->get_clear_ct_seq()); } else { + print_summary(1, "Ext Root Scanning", body_summary->get_ext_root_scan_seq()); + print_summary(1, "Mark Stack Scanning", body_summary->get_mark_stack_scan_seq()); print_summary(1, "Update RS", body_summary->get_update_rs_seq()); - print_summary(1, "Ext Root Scanning", - body_summary->get_ext_root_scan_seq()); - print_summary(1, "Mark Stack Scanning", - body_summary->get_mark_stack_scan_seq()); print_summary(1, "Scan RS", body_summary->get_scan_rs_seq()); print_summary(1, "Object Copy", body_summary->get_obj_copy_seq()); } } + print_summary(1, "Mark Closure", body_summary->get_mark_closure_seq()); + print_summary(1, "Clear CT", body_summary->get_clear_ct_seq()); print_summary(1, "Other", summary->get_other_seq()); { if (body_summary != NULL) { diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp index eae256f6e1a..cff48707abc 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp @@ -74,7 +74,7 @@ class MainBodySummary: public CHeapObj { define_num_seq(termination) // parallel only define_num_seq(parallel_other) // parallel only define_num_seq(mark_closure) - define_num_seq(clear_ct) // parallel only + define_num_seq(clear_ct) }; class Summary: public PauseSummary, @@ -115,7 +115,6 @@ private: double _cur_collection_par_time_ms; double _cur_satb_drain_time_ms; double _cur_clear_ct_time_ms; - bool _satb_drain_time_set; double _cur_ref_proc_time_ms; double _cur_ref_enq_time_ms; @@ -176,6 +175,11 @@ private: double* _par_last_gc_worker_end_times_ms; double* _par_last_gc_worker_times_ms; + // Each workers 'other' time i.e. the elapsed time of the parallel + // phase of the pause minus the sum of the individual sub-phase + // times for a given worker thread. + double* _par_last_gc_worker_other_times_ms; + // indicates whether we are in full young or partially young GC mode bool _full_young_gcs; @@ -892,11 +896,12 @@ public: } void record_satb_drain_time(double ms) { + assert(_g1->mark_in_progress(), "shouldn't be here otherwise"); _cur_satb_drain_time_ms = ms; - _satb_drain_time_set = true; } - void record_satb_drain_processed_buffers (int processed_buffers) { + void record_satb_drain_processed_buffers(int processed_buffers) { + assert(_g1->mark_in_progress(), "shouldn't be here otherwise"); _last_satb_drain_processed_buffers = processed_buffers; } diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp index 1e6373cf709..c24597b0b32 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1RemSet.cpp @@ -122,10 +122,10 @@ public: void set_try_claimed() { _try_claimed = true; } void scanCard(size_t index, HeapRegion *r) { - DirtyCardToOopClosure* cl = - r->new_dcto_closure(_oc, - CardTableModRefBS::Precise, - HeapRegionDCTOC::IntoCSFilterKind); + // Stack allocate the DirtyCardToOopClosure instance + HeapRegionDCTOC cl(_g1h, r, _oc, + CardTableModRefBS::Precise, + HeapRegionDCTOC::IntoCSFilterKind); // Set the "from" region in the closure. _oc->set_region(r); @@ -140,7 +140,7 @@ public: // scans (the rsets of the regions in the cset can intersect). _ct_bs->set_card_claimed(index); _cards_done++; - cl->do_MemRegion(mr); + cl.do_MemRegion(mr); } } diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp index 8230e6187c7..c85611f84ac 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.cpp @@ -340,14 +340,6 @@ void HeapRegion::reset_after_compaction() { init_top_at_mark_start(); } -DirtyCardToOopClosure* -HeapRegion::new_dcto_closure(OopClosure* cl, - CardTableModRefBS::PrecisionStyle precision, - HeapRegionDCTOC::FilterKind fk) { - return new HeapRegionDCTOC(G1CollectedHeap::heap(), - this, cl, precision, fk); -} - void HeapRegion::hr_clear(bool par, bool clear_space) { assert(_humongous_type == NotHumongous, "we should have already filtered out humongous regions"); diff --git a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp index 67e9d8905bb..7071ad495be 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp +++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.hpp @@ -577,11 +577,6 @@ class HeapRegion: public G1OffsetTableContigSpace { // allocated in the current region before the last call to "save_mark". void oop_before_save_marks_iterate(OopClosure* cl); - DirtyCardToOopClosure* - new_dcto_closure(OopClosure* cl, - CardTableModRefBS::PrecisionStyle precision, - HeapRegionDCTOC::FilterKind fk); - // Note the start or end of marking. This tells the heap region // that the collector is about to start or has finished (concurrently) // marking the heap. From 063b622daf428d6d78988fb3adba57cdbff5154a Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Mon, 24 Oct 2011 13:00:20 +0100 Subject: [PATCH 038/107] 7096014: Javac tokens should retain state Refactor javac tokens from enum constants to stateful instances (to keep track of position, comments, etc.) Reviewed-by: jjg --- .../sun/tools/apt/main/AptJavaCompiler.java | 1 - .../sun/tools/javac/parser/EndPosParser.java | 6 +- .../sun/tools/javac/parser/JavaTokenizer.java | 896 ++++++++++++++ .../sun/tools/javac/parser/JavacParser.java | 1033 ++++++++-------- ...mentScanner.java => JavadocTokenizer.java} | 46 +- .../com/sun/tools/javac/parser/Keywords.java | 98 -- .../com/sun/tools/javac/parser/Lexer.java | 89 +- .../sun/tools/javac/parser/ParserFactory.java | 4 +- .../com/sun/tools/javac/parser/Scanner.java | 1085 +---------------- .../tools/javac/parser/ScannerFactory.java | 8 +- .../com/sun/tools/javac/parser/Token.java | 198 --- .../com/sun/tools/javac/parser/Tokens.java | 423 +++++++ .../sun/tools/javac/parser/UnicodeReader.java | 227 ++++ .../JavacProcessingEnvironment.java | 6 +- .../com/sun/tools/javadoc/JavadocTool.java | 1 - .../tools/javac/api/TestJavacTaskScanner.java | 6 +- .../depDocComment/DeprecatedDocComment3.java | 41 + .../javac/tree/DocCommentToplevelTest.java | 196 +++ 18 files changed, 2370 insertions(+), 1994 deletions(-) create mode 100644 langtools/src/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java rename langtools/src/share/classes/com/sun/tools/javac/parser/{DocCommentScanner.java => JavadocTokenizer.java} (94%) delete mode 100644 langtools/src/share/classes/com/sun/tools/javac/parser/Keywords.java delete mode 100644 langtools/src/share/classes/com/sun/tools/javac/parser/Token.java create mode 100644 langtools/src/share/classes/com/sun/tools/javac/parser/Tokens.java create mode 100644 langtools/src/share/classes/com/sun/tools/javac/parser/UnicodeReader.java create mode 100644 langtools/test/tools/javac/depDocComment/DeprecatedDocComment3.java create mode 100644 langtools/test/tools/javac/tree/DocCommentToplevelTest.java diff --git a/langtools/src/share/classes/com/sun/tools/apt/main/AptJavaCompiler.java b/langtools/src/share/classes/com/sun/tools/apt/main/AptJavaCompiler.java index 89658e2bfe3..32d10ab50c5 100644 --- a/langtools/src/share/classes/com/sun/tools/apt/main/AptJavaCompiler.java +++ b/langtools/src/share/classes/com/sun/tools/apt/main/AptJavaCompiler.java @@ -42,7 +42,6 @@ import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.apt.comp.*; import com.sun.tools.apt.util.Bark; import com.sun.mirror.apt.AnnotationProcessorFactory; -import com.sun.tools.javac.parser.DocCommentScanner; /** *

This is NOT part of any supported API. diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/EndPosParser.java b/langtools/src/share/classes/com/sun/tools/javac/parser/EndPosParser.java index 715839bd776..e428f6e0b54 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/parser/EndPosParser.java +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/EndPosParser.java @@ -67,14 +67,14 @@ public class EndPosParser extends JavacParser { /** {@inheritDoc} */ @Override protected T to(T t) { - storeEnd(t, S.endPos()); + storeEnd(t, token.endPos); return t; } /** {@inheritDoc} */ @Override protected T toP(T t) { - storeEnd(t, S.prevEndPos()); + storeEnd(t, S.prevToken().endPos); return t; } @@ -88,7 +88,7 @@ public class EndPosParser extends JavacParser { /** {@inheritDoc} */ @Override JCExpression parExpression() { - int pos = S.pos(); + int pos = token.pos; JCExpression t = super.parExpression(); return toP(F.at(pos).Parens(t)); } diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java b/langtools/src/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java new file mode 100644 index 00000000000..f5a99ae9fa4 --- /dev/null +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java @@ -0,0 +1,896 @@ +/* + * Copyright (c) 1999, 2011, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package com.sun.tools.javac.parser; + +import java.nio.CharBuffer; +import com.sun.tools.javac.code.Source; +import com.sun.tools.javac.util.*; + + +import static com.sun.tools.javac.parser.Tokens.*; +import static com.sun.tools.javac.util.LayoutCharacters.*; + +/** The lexical analyzer maps an input stream consisting of + * ASCII characters and Unicode escapes into a token sequence. + * + *

This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + */ +public class JavaTokenizer { + + private static boolean scannerDebug = false; + + /** Allow hex floating-point literals. + */ + private boolean allowHexFloats; + + /** Allow binary literals. + */ + private boolean allowBinaryLiterals; + + /** Allow underscores in literals. + */ + private boolean allowUnderscoresInLiterals; + + /** The source language setting. + */ + private Source source; + + /** The log to be used for error reporting. + */ + private final Log log; + + /** The name table. */ + private final Names names; + + /** The token factory. */ + private final Tokens tokens; + + /** The token kind, set by nextToken(). + */ + protected TokenKind tk; + + /** The token's radix, set by nextToken(). + */ + protected int radix; + + /** The token's name, set by nextToken(). + */ + protected Name name; + + /** The position where a lexical error occurred; + */ + protected int errPos = Position.NOPOS; + + /** Has a @deprecated been encountered in last doc comment? + * this needs to be reset by client. + */ + protected boolean deprecatedFlag = false; + + /** A character buffer for saved chars. + */ + protected char[] sbuf = new char[128]; + protected int sp; + + protected UnicodeReader reader; + + private static final boolean hexFloatsWork = hexFloatsWork(); + private static boolean hexFloatsWork() { + try { + Float.valueOf("0x1.0p1"); + return true; + } catch (NumberFormatException ex) { + return false; + } + } + + /** + * Create a scanner from the input array. This method might + * modify the array. To avoid copying the input array, ensure + * that {@code inputLength < input.length} or + * {@code input[input.length -1]} is a white space character. + * + * @param fac the factory which created this Scanner + * @param input the input, might be modified + * @param inputLength the size of the input. + * Must be positive and less than or equal to input.length. + */ + protected JavaTokenizer(ScannerFactory fac, CharBuffer buf) { + this(fac, new UnicodeReader(fac, buf)); + } + + protected JavaTokenizer(ScannerFactory fac, char[] buf, int inputLength) { + this(fac, new UnicodeReader(fac, buf, inputLength)); + } + + protected JavaTokenizer(ScannerFactory fac, UnicodeReader reader) { + log = fac.log; + names = fac.names; + tokens = fac.tokens; + source = fac.source; + this.reader = reader; + allowBinaryLiterals = source.allowBinaryLiterals(); + allowHexFloats = source.allowHexFloats(); + allowUnderscoresInLiterals = source.allowUnderscoresInLiterals(); + } + + /** Report an error at the given position using the provided arguments. + */ + protected void lexError(int pos, String key, Object... args) { + log.error(pos, key, args); + tk = TokenKind.ERROR; + errPos = pos; + } + + /** Read next character in comment, skipping over double '\' characters. + */ + protected void scanCommentChar() { + reader.scanChar(); + if (reader.ch == '\\') { + if (reader.peekChar() == '\\' && !reader.isUnicode()) { + reader.skipChar(); + } else { + reader.convertUnicode(); + } + } + } + + /** Append a character to sbuf. + */ + private void putChar(char ch) { + if (sp == sbuf.length) { + char[] newsbuf = new char[sbuf.length * 2]; + System.arraycopy(sbuf, 0, newsbuf, 0, sbuf.length); + sbuf = newsbuf; + } + sbuf[sp++] = ch; + } + + /** Read next character in character or string literal and copy into sbuf. + */ + private void scanLitChar(int pos) { + if (reader.ch == '\\') { + if (reader.peekChar() == '\\' && !reader.isUnicode()) { + reader.skipChar(); + putChar('\\'); + reader.scanChar(); + } else { + reader.scanChar(); + switch (reader.ch) { + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + char leadch = reader.ch; + int oct = reader.digit(pos, 8); + reader.scanChar(); + if ('0' <= reader.ch && reader.ch <= '7') { + oct = oct * 8 + reader.digit(pos, 8); + reader.scanChar(); + if (leadch <= '3' && '0' <= reader.ch && reader.ch <= '7') { + oct = oct * 8 + reader.digit(pos, 8); + reader.scanChar(); + } + } + putChar((char)oct); + break; + case 'b': + putChar('\b'); reader.scanChar(); break; + case 't': + putChar('\t'); reader.scanChar(); break; + case 'n': + putChar('\n'); reader.scanChar(); break; + case 'f': + putChar('\f'); reader.scanChar(); break; + case 'r': + putChar('\r'); reader.scanChar(); break; + case '\'': + putChar('\''); reader.scanChar(); break; + case '\"': + putChar('\"'); reader.scanChar(); break; + case '\\': + putChar('\\'); reader.scanChar(); break; + default: + lexError(reader.bp, "illegal.esc.char"); + } + } + } else if (reader.bp != reader.buflen) { + putChar(reader.ch); reader.scanChar(); + } + } + + private void scanDigits(int pos, int digitRadix) { + char saveCh; + int savePos; + do { + if (reader.ch != '_') { + putChar(reader.ch); + } else { + if (!allowUnderscoresInLiterals) { + lexError(pos, "unsupported.underscore.lit", source.name); + allowUnderscoresInLiterals = true; + } + } + saveCh = reader.ch; + savePos = reader.bp; + reader.scanChar(); + } while (reader.digit(pos, digitRadix) >= 0 || reader.ch == '_'); + if (saveCh == '_') + lexError(savePos, "illegal.underscore"); + } + + /** Read fractional part of hexadecimal floating point number. + */ + private void scanHexExponentAndSuffix(int pos) { + if (reader.ch == 'p' || reader.ch == 'P') { + putChar(reader.ch); + reader.scanChar(); + skipIllegalUnderscores(); + if (reader.ch == '+' || reader.ch == '-') { + putChar(reader.ch); + reader.scanChar(); + } + skipIllegalUnderscores(); + if ('0' <= reader.ch && reader.ch <= '9') { + scanDigits(pos, 10); + if (!allowHexFloats) { + lexError(pos, "unsupported.fp.lit", source.name); + allowHexFloats = true; + } + else if (!hexFloatsWork) + lexError(pos, "unsupported.cross.fp.lit"); + } else + lexError(pos, "malformed.fp.lit"); + } else { + lexError(pos, "malformed.fp.lit"); + } + if (reader.ch == 'f' || reader.ch == 'F') { + putChar(reader.ch); + reader.scanChar(); + tk = TokenKind.FLOATLITERAL; + radix = 16; + } else { + if (reader.ch == 'd' || reader.ch == 'D') { + putChar(reader.ch); + reader.scanChar(); + } + tk = TokenKind.DOUBLELITERAL; + radix = 16; + } + } + + /** Read fractional part of floating point number. + */ + private void scanFraction(int pos) { + skipIllegalUnderscores(); + if ('0' <= reader.ch && reader.ch <= '9') { + scanDigits(pos, 10); + } + int sp1 = sp; + if (reader.ch == 'e' || reader.ch == 'E') { + putChar(reader.ch); + reader.scanChar(); + skipIllegalUnderscores(); + if (reader.ch == '+' || reader.ch == '-') { + putChar(reader.ch); + reader.scanChar(); + } + skipIllegalUnderscores(); + if ('0' <= reader.ch && reader.ch <= '9') { + scanDigits(pos, 10); + return; + } + lexError(pos, "malformed.fp.lit"); + sp = sp1; + } + } + + /** Read fractional part and 'd' or 'f' suffix of floating point number. + */ + private void scanFractionAndSuffix(int pos) { + radix = 10; + scanFraction(pos); + if (reader.ch == 'f' || reader.ch == 'F') { + putChar(reader.ch); + reader.scanChar(); + tk = TokenKind.FLOATLITERAL; + } else { + if (reader.ch == 'd' || reader.ch == 'D') { + putChar(reader.ch); + reader.scanChar(); + } + tk = TokenKind.DOUBLELITERAL; + } + } + + /** Read fractional part and 'd' or 'f' suffix of floating point number. + */ + private void scanHexFractionAndSuffix(int pos, boolean seendigit) { + radix = 16; + Assert.check(reader.ch == '.'); + putChar(reader.ch); + reader.scanChar(); + skipIllegalUnderscores(); + if (reader.digit(pos, 16) >= 0) { + seendigit = true; + scanDigits(pos, 16); + } + if (!seendigit) + lexError(pos, "invalid.hex.number"); + else + scanHexExponentAndSuffix(pos); + } + + private void skipIllegalUnderscores() { + if (reader.ch == '_') { + lexError(reader.bp, "illegal.underscore"); + while (reader.ch == '_') + reader.scanChar(); + } + } + + /** Read a number. + * @param radix The radix of the number; one of 2, j8, 10, 16. + */ + private void scanNumber(int pos, int radix) { + // for octal, allow base-10 digit in case it's a float literal + this.radix = radix; + int digitRadix = (radix == 8 ? 10 : radix); + boolean seendigit = false; + if (reader.digit(pos, digitRadix) >= 0) { + seendigit = true; + scanDigits(pos, digitRadix); + } + if (radix == 16 && reader.ch == '.') { + scanHexFractionAndSuffix(pos, seendigit); + } else if (seendigit && radix == 16 && (reader.ch == 'p' || reader.ch == 'P')) { + scanHexExponentAndSuffix(pos); + } else if (digitRadix == 10 && reader.ch == '.') { + putChar(reader.ch); + reader.scanChar(); + scanFractionAndSuffix(pos); + } else if (digitRadix == 10 && + (reader.ch == 'e' || reader.ch == 'E' || + reader.ch == 'f' || reader.ch == 'F' || + reader.ch == 'd' || reader.ch == 'D')) { + scanFractionAndSuffix(pos); + } else { + if (reader.ch == 'l' || reader.ch == 'L') { + reader.scanChar(); + tk = TokenKind.LONGLITERAL; + } else { + tk = TokenKind.INTLITERAL; + } + } + } + + /** Read an identifier. + */ + private void scanIdent() { + boolean isJavaIdentifierPart; + char high; + do { + if (sp == sbuf.length) putChar(reader.ch); else sbuf[sp++] = reader.ch; + // optimization, was: putChar(reader.ch); + + reader.scanChar(); + switch (reader.ch) { + case 'A': case 'B': case 'C': case 'D': case 'E': + case 'F': case 'G': case 'H': case 'I': case 'J': + case 'K': case 'L': case 'M': case 'N': case 'O': + case 'P': case 'Q': case 'R': case 'S': case 'T': + case 'U': case 'V': case 'W': case 'X': case 'Y': + case 'Z': + case 'a': case 'b': case 'c': case 'd': case 'e': + case 'f': case 'g': case 'h': case 'i': case 'j': + case 'k': case 'l': case 'm': case 'n': case 'o': + case 'p': case 'q': case 'r': case 's': case 't': + case 'u': case 'v': case 'w': case 'x': case 'y': + case 'z': + case '$': case '_': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case '\u0000': case '\u0001': case '\u0002': case '\u0003': + case '\u0004': case '\u0005': case '\u0006': case '\u0007': + case '\u0008': case '\u000E': case '\u000F': case '\u0010': + case '\u0011': case '\u0012': case '\u0013': case '\u0014': + case '\u0015': case '\u0016': case '\u0017': + case '\u0018': case '\u0019': case '\u001B': + case '\u007F': + break; + case '\u001A': // EOI is also a legal identifier part + if (reader.bp >= reader.buflen) { + name = names.fromChars(sbuf, 0, sp); + tk = tokens.lookupKind(name); + return; + } + break; + default: + if (reader.ch < '\u0080') { + // all ASCII range chars already handled, above + isJavaIdentifierPart = false; + } else { + high = reader.scanSurrogates(); + if (high != 0) { + if (sp == sbuf.length) { + putChar(high); + } else { + sbuf[sp++] = high; + } + isJavaIdentifierPart = Character.isJavaIdentifierPart( + Character.toCodePoint(high, reader.ch)); + } else { + isJavaIdentifierPart = Character.isJavaIdentifierPart(reader.ch); + } + } + if (!isJavaIdentifierPart) { + name = names.fromChars(sbuf, 0, sp); + tk = tokens.lookupKind(name); + return; + } + } + } while (true); + } + + /** Return true if reader.ch can be part of an operator. + */ + private boolean isSpecial(char ch) { + switch (ch) { + case '!': case '%': case '&': case '*': case '?': + case '+': case '-': case ':': case '<': case '=': + case '>': case '^': case '|': case '~': + case '@': + return true; + default: + return false; + } + } + + /** Read longest possible sequence of special characters and convert + * to token. + */ + private void scanOperator() { + while (true) { + putChar(reader.ch); + Name newname = names.fromChars(sbuf, 0, sp); + TokenKind tk1 = tokens.lookupKind(newname); + if (tk1 == TokenKind.IDENTIFIER) { + sp--; + break; + } + tk = tk1; + reader.scanChar(); + if (!isSpecial(reader.ch)) break; + } + } + + /** + * Scan a documentation comment; determine if a deprecated tag is present. + * Called once the initial /, * have been skipped, positioned at the second * + * (which is treated as the beginning of the first line). + * Stops positioned at the closing '/'. + */ + @SuppressWarnings("fallthrough") + private void scanDocComment() { + boolean deprecatedPrefix = false; + + forEachLine: + while (reader.bp < reader.buflen) { + + // Skip optional WhiteSpace at beginning of line + while (reader.bp < reader.buflen && (reader.ch == ' ' || reader.ch == '\t' || reader.ch == FF)) { + scanCommentChar(); + } + + // Skip optional consecutive Stars + while (reader.bp < reader.buflen && reader.ch == '*') { + scanCommentChar(); + if (reader.ch == '/') { + return; + } + } + + // Skip optional WhiteSpace after Stars + while (reader.bp < reader.buflen && (reader.ch == ' ' || reader.ch == '\t' || reader.ch == FF)) { + scanCommentChar(); + } + + deprecatedPrefix = false; + // At beginning of line in the JavaDoc sense. + if (reader.bp < reader.buflen && reader.ch == '@' && !deprecatedFlag) { + scanCommentChar(); + if (reader.bp < reader.buflen && reader.ch == 'd') { + scanCommentChar(); + if (reader.bp < reader.buflen && reader.ch == 'e') { + scanCommentChar(); + if (reader.bp < reader.buflen && reader.ch == 'p') { + scanCommentChar(); + if (reader.bp < reader.buflen && reader.ch == 'r') { + scanCommentChar(); + if (reader.bp < reader.buflen && reader.ch == 'e') { + scanCommentChar(); + if (reader.bp < reader.buflen && reader.ch == 'c') { + scanCommentChar(); + if (reader.bp < reader.buflen && reader.ch == 'a') { + scanCommentChar(); + if (reader.bp < reader.buflen && reader.ch == 't') { + scanCommentChar(); + if (reader.bp < reader.buflen && reader.ch == 'e') { + scanCommentChar(); + if (reader.bp < reader.buflen && reader.ch == 'd') { + deprecatedPrefix = true; + scanCommentChar(); + }}}}}}}}}}} + if (deprecatedPrefix && reader.bp < reader.buflen) { + if (Character.isWhitespace(reader.ch)) { + deprecatedFlag = true; + } else if (reader.ch == '*') { + scanCommentChar(); + if (reader.ch == '/') { + deprecatedFlag = true; + return; + } + } + } + + // Skip rest of line + while (reader.bp < reader.buflen) { + switch (reader.ch) { + case '*': + scanCommentChar(); + if (reader.ch == '/') { + return; + } + break; + case CR: // (Spec 3.4) + scanCommentChar(); + if (reader.ch != LF) { + continue forEachLine; + } + /* fall through to LF case */ + case LF: // (Spec 3.4) + scanCommentChar(); + continue forEachLine; + default: + scanCommentChar(); + } + } // rest of line + } // forEachLine + return; + } + + /** Read token. + */ + public Token readToken() { + + sp = 0; + name = null; + deprecatedFlag = false; + radix = 0; + int pos = 0; + int endPos = 0; + + try { + loop: while (true) { + pos = reader.bp; + switch (reader.ch) { + case ' ': // (Spec 3.6) + case '\t': // (Spec 3.6) + case FF: // (Spec 3.6) + do { + reader.scanChar(); + } while (reader.ch == ' ' || reader.ch == '\t' || reader.ch == FF); + processWhiteSpace(pos, reader.bp); + break; + case LF: // (Spec 3.4) + reader.scanChar(); + processLineTerminator(pos, reader.bp); + break; + case CR: // (Spec 3.4) + reader.scanChar(); + if (reader.ch == LF) { + reader.scanChar(); + } + processLineTerminator(pos, reader.bp); + break; + case 'A': case 'B': case 'C': case 'D': case 'E': + case 'F': case 'G': case 'H': case 'I': case 'J': + case 'K': case 'L': case 'M': case 'N': case 'O': + case 'P': case 'Q': case 'R': case 'S': case 'T': + case 'U': case 'V': case 'W': case 'X': case 'Y': + case 'Z': + case 'a': case 'b': case 'c': case 'd': case 'e': + case 'f': case 'g': case 'h': case 'i': case 'j': + case 'k': case 'l': case 'm': case 'n': case 'o': + case 'p': case 'q': case 'r': case 's': case 't': + case 'u': case 'v': case 'w': case 'x': case 'y': + case 'z': + case '$': case '_': + scanIdent(); + break loop; + case '0': + reader.scanChar(); + if (reader.ch == 'x' || reader.ch == 'X') { + reader.scanChar(); + skipIllegalUnderscores(); + if (reader.ch == '.') { + scanHexFractionAndSuffix(pos, false); + } else if (reader.digit(pos, 16) < 0) { + lexError(pos, "invalid.hex.number"); + } else { + scanNumber(pos, 16); + } + } else if (reader.ch == 'b' || reader.ch == 'B') { + if (!allowBinaryLiterals) { + lexError(pos, "unsupported.binary.lit", source.name); + allowBinaryLiterals = true; + } + reader.scanChar(); + skipIllegalUnderscores(); + if (reader.digit(pos, 2) < 0) { + lexError(pos, "invalid.binary.number"); + } else { + scanNumber(pos, 2); + } + } else { + putChar('0'); + if (reader.ch == '_') { + int savePos = reader.bp; + do { + reader.scanChar(); + } while (reader.ch == '_'); + if (reader.digit(pos, 10) < 0) { + lexError(savePos, "illegal.underscore"); + } + } + scanNumber(pos, 8); + } + break loop; + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + scanNumber(pos, 10); + break loop; + case '.': + reader.scanChar(); + if ('0' <= reader.ch && reader.ch <= '9') { + putChar('.'); + scanFractionAndSuffix(pos); + } else if (reader.ch == '.') { + putChar('.'); putChar('.'); + reader.scanChar(); + if (reader.ch == '.') { + reader.scanChar(); + putChar('.'); + tk = TokenKind.ELLIPSIS; + } else { + lexError(pos, "malformed.fp.lit"); + } + } else { + tk = TokenKind.DOT; + } + break loop; + case ',': + reader.scanChar(); tk = TokenKind.COMMA; break loop; + case ';': + reader.scanChar(); tk = TokenKind.SEMI; break loop; + case '(': + reader.scanChar(); tk = TokenKind.LPAREN; break loop; + case ')': + reader.scanChar(); tk = TokenKind.RPAREN; break loop; + case '[': + reader.scanChar(); tk = TokenKind.LBRACKET; break loop; + case ']': + reader.scanChar(); tk = TokenKind.RBRACKET; break loop; + case '{': + reader.scanChar(); tk = TokenKind.LBRACE; break loop; + case '}': + reader.scanChar(); tk = TokenKind.RBRACE; break loop; + case '/': + reader.scanChar(); + if (reader.ch == '/') { + do { + scanCommentChar(); + } while (reader.ch != CR && reader.ch != LF && reader.bp < reader.buflen); + if (reader.bp < reader.buflen) { + processComment(pos, reader.bp, CommentStyle.LINE); + } + break; + } else if (reader.ch == '*') { + reader.scanChar(); + CommentStyle style; + if (reader.ch == '*') { + style = CommentStyle.JAVADOC; + scanDocComment(); + } else { + style = CommentStyle.BLOCK; + while (reader.bp < reader.buflen) { + if (reader.ch == '*') { + reader.scanChar(); + if (reader.ch == '/') break; + } else { + scanCommentChar(); + } + } + } + if (reader.ch == '/') { + reader.scanChar(); + processComment(pos, reader.bp, style); + break; + } else { + lexError(pos, "unclosed.comment"); + break loop; + } + } else if (reader.ch == '=') { + tk = TokenKind.SLASHEQ; + reader.scanChar(); + } else { + tk = TokenKind.SLASH; + } + break loop; + case '\'': + reader.scanChar(); + if (reader.ch == '\'') { + lexError(pos, "empty.char.lit"); + } else { + if (reader.ch == CR || reader.ch == LF) + lexError(pos, "illegal.line.end.in.char.lit"); + scanLitChar(pos); + char ch2 = reader.ch; + if (reader.ch == '\'') { + reader.scanChar(); + tk = TokenKind.CHARLITERAL; + } else { + lexError(pos, "unclosed.char.lit"); + } + } + break loop; + case '\"': + reader.scanChar(); + while (reader.ch != '\"' && reader.ch != CR && reader.ch != LF && reader.bp < reader.buflen) + scanLitChar(pos); + if (reader.ch == '\"') { + tk = TokenKind.STRINGLITERAL; + reader.scanChar(); + } else { + lexError(pos, "unclosed.str.lit"); + } + break loop; + default: + if (isSpecial(reader.ch)) { + scanOperator(); + } else { + boolean isJavaIdentifierStart; + if (reader.ch < '\u0080') { + // all ASCII range chars already handled, above + isJavaIdentifierStart = false; + } else { + char high = reader.scanSurrogates(); + if (high != 0) { + if (sp == sbuf.length) { + putChar(high); + } else { + sbuf[sp++] = high; + } + + isJavaIdentifierStart = Character.isJavaIdentifierStart( + Character.toCodePoint(high, reader.ch)); + } else { + isJavaIdentifierStart = Character.isJavaIdentifierStart(reader.ch); + } + } + if (isJavaIdentifierStart) { + scanIdent(); + } else if (reader.bp == reader.buflen || reader.ch == EOI && reader.bp + 1 == reader.buflen) { // JLS 3.5 + tk = TokenKind.EOF; + pos = reader.buflen; + } else { + lexError(pos, "illegal.char", String.valueOf((int)reader.ch)); + reader.scanChar(); + } + } + break loop; + } + } + endPos = reader.bp; + switch (tk.tag) { + case DEFAULT: return new Token(tk, pos, endPos, deprecatedFlag); + case NAMED: return new NamedToken(tk, pos, endPos, name, deprecatedFlag); + case STRING: return new StringToken(tk, pos, endPos, new String(sbuf, 0, sp), deprecatedFlag); + case NUMERIC: return new NumericToken(tk, pos, endPos, new String(sbuf, 0, sp), radix, deprecatedFlag); + default: throw new AssertionError(); + } + } + finally { + if (scannerDebug) { + System.out.println("nextToken(" + pos + + "," + endPos + ")=|" + + new String(reader.getRawCharacters(pos, endPos)) + + "|"); + } + } + } + + /** Return the position where a lexical error occurred; + */ + public int errPos() { + return errPos; + } + + /** Set the position where a lexical error occurred; + */ + public void errPos(int pos) { + errPos = pos; + } + + public enum CommentStyle { + LINE, + BLOCK, + JAVADOC, + } + + /** + * Called when a complete comment has been scanned. pos and endPos + * will mark the comment boundary. + */ + protected void processComment(int pos, int endPos, CommentStyle style) { + if (scannerDebug) + System.out.println("processComment(" + pos + + "," + endPos + "," + style + ")=|" + + new String(reader.getRawCharacters(pos, endPos)) + + "|"); + } + + /** + * Called when a complete whitespace run has been scanned. pos and endPos + * will mark the whitespace boundary. + */ + protected void processWhiteSpace(int pos, int endPos) { + if (scannerDebug) + System.out.println("processWhitespace(" + pos + + "," + endPos + ")=|" + + new String(reader.getRawCharacters(pos, endPos)) + + "|"); + } + + /** + * Called when a line terminator has been processed. + */ + protected void processLineTerminator(int pos, int endPos) { + if (scannerDebug) + System.out.println("processTerminator(" + pos + + "," + endPos + ")=|" + + new String(reader.getRawCharacters(pos, endPos)) + + "|"); + } + + /** Build a map for translating between line numbers and + * positions in the input. + * + * @return a LineMap */ + public Position.LineMap getLineMap() { + return Position.makeLineMap(reader.getRawCharacters(), reader.buflen, false); + } +} diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java index 2151a67cdd5..9c754978a56 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -28,6 +28,7 @@ package com.sun.tools.javac.parser; import java.util.*; import com.sun.tools.javac.code.*; +import com.sun.tools.javac.parser.Tokens.*; import com.sun.tools.javac.tree.*; import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.util.*; @@ -36,7 +37,7 @@ import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.List; import static com.sun.tools.javac.util.ListBuffer.lb; -import static com.sun.tools.javac.parser.Token.*; +import static com.sun.tools.javac.parser.Tokens.TokenKind.*; /** The parser maps a token sequence into an abstract syntax * tree. It operates by recursive descent, with code derived @@ -67,9 +68,6 @@ public class JavacParser implements Parser { */ private Log log; - /** The keyword table. */ - private Keywords keywords; - /** The Source language setting. */ private Source source; @@ -83,11 +81,10 @@ public class JavacParser implements Parser { boolean keepDocComments, boolean keepLineMap) { this.S = S; - S.nextToken(); // prime the pump + nextToken(); // prime the pump this.F = fac.F; this.log = fac.log; this.names = fac.names; - this.keywords = fac.keywords; this.source = fac.source; this.allowGenerics = source.allowGenerics(); this.allowVarargs = source.allowVarargs(); @@ -178,7 +175,16 @@ public class JavacParser implements Parser { */ private int lastmode = 0; -/* ---------- error recovery -------------- */ + /* ---------- token management -------------- */ + + protected Token token; + + protected void nextToken() { + S.nextToken(); + token = S.token(); + } + + /* ---------- error recovery -------------- */ private JCErroneous errorTree; @@ -186,9 +192,9 @@ public class JavacParser implements Parser { */ private void skip(boolean stopAtImport, boolean stopAtMemberDecl, boolean stopAtIdentifier, boolean stopAtStatement) { while (true) { - switch (S.token()) { + switch (token.kind) { case SEMI: - S.nextToken(); + nextToken(); return; case PUBLIC: case FINAL: @@ -249,15 +255,15 @@ public class JavacParser implements Parser { return; break; } - S.nextToken(); + nextToken(); } } - private JCErroneous syntaxError(int pos, String key, Token... args) { + private JCErroneous syntaxError(int pos, String key, TokenKind... args) { return syntaxError(pos, List.nil(), key, args); } - private JCErroneous syntaxError(int pos, List errs, String key, Token... args) { + private JCErroneous syntaxError(int pos, List errs, String key, TokenKind... args) { setErrorEndPos(pos); JCErroneous err = F.at(pos).Erroneous(errs); reportSyntaxError(err, key, (Object[])args); @@ -287,16 +293,16 @@ public class JavacParser implements Parser { private void reportSyntaxError(JCDiagnostic.DiagnosticPosition diagPos, String key, Object... args) { int pos = diagPos.getPreferredPosition(); if (pos > S.errPos() || pos == Position.NOPOS) { - if (S.token() == EOF) { + if (token.kind == EOF) { error(diagPos, "premature.eof"); } else { error(diagPos, key, args); } } S.errPos(pos); - if (S.pos() == errorPos) - S.nextToken(); // guarantee progress - errorPos = S.pos(); + if (token.pos == errorPos) + nextToken(); // guarantee progress + errorPos = token.pos; } @@ -304,25 +310,25 @@ public class JavacParser implements Parser { * reported at the same position. */ private JCErroneous syntaxError(String key) { - return syntaxError(S.pos(), key); + return syntaxError(token.pos, key); } /** Generate a syntax error at current position unless one was * already reported at the same position. */ - private JCErroneous syntaxError(String key, Token arg) { - return syntaxError(S.pos(), key, arg); + private JCErroneous syntaxError(String key, TokenKind arg) { + return syntaxError(token.pos, key, arg); } /** If next input token matches given token, skip it, otherwise report * an error. */ - public void accept(Token token) { - if (S.token() == token) { - S.nextToken(); + public void accept(TokenKind tk) { + if (token.kind == tk) { + nextToken(); } else { - setErrorEndPos(S.pos()); - reportSyntaxError(S.prevEndPos(), "expected", token); + setErrorEndPos(token.pos); + reportSyntaxError(S.prevToken().endPos, "expected", tk); } } @@ -340,14 +346,14 @@ public class JavacParser implements Parser { /** Report an illegal start of expression/type error at current position. */ JCExpression illegal() { - return illegal(S.pos()); + return illegal(token.pos); } /** Diagnose a modifier flag from the set, if any. */ void checkNoMods(long mods) { if (mods != 0) { long lowestMod = mods & -mods; - error(S.pos(), "mod.not.allowed.here", + error(token.pos, "mod.not.allowed.here", Flags.asFlagSet(lowestMod)); } } @@ -435,30 +441,30 @@ public class JavacParser implements Parser { * Ident = IDENTIFIER */ Name ident() { - if (S.token() == IDENTIFIER) { - Name name = S.name(); - S.nextToken(); + if (token.kind == IDENTIFIER) { + Name name = token.name(); + nextToken(); return name; - } else if (S.token() == ASSERT) { + } else if (token.kind == ASSERT) { if (allowAsserts) { - error(S.pos(), "assert.as.identifier"); - S.nextToken(); + error(token.pos, "assert.as.identifier"); + nextToken(); return names.error; } else { - warning(S.pos(), "assert.as.identifier"); - Name name = S.name(); - S.nextToken(); + warning(token.pos, "assert.as.identifier"); + Name name = token.name(); + nextToken(); return name; } - } else if (S.token() == ENUM) { + } else if (token.kind == ENUM) { if (allowEnums) { - error(S.pos(), "enum.as.identifier"); - S.nextToken(); + error(token.pos, "enum.as.identifier"); + nextToken(); return names.error; } else { - warning(S.pos(), "enum.as.identifier"); - Name name = S.name(); - S.nextToken(); + warning(token.pos, "enum.as.identifier"); + Name name = token.name(); + nextToken(); return name; } } else { @@ -471,17 +477,17 @@ public class JavacParser implements Parser { * Qualident = Ident { DOT Ident } */ public JCExpression qualident() { - JCExpression t = toP(F.at(S.pos()).Ident(ident())); - while (S.token() == DOT) { - int pos = S.pos(); - S.nextToken(); + JCExpression t = toP(F.at(token.pos).Ident(ident())); + while (token.kind == DOT) { + int pos = token.pos; + nextToken(); t = toP(F.at(pos).Select(t, ident())); } return t; } JCExpression literal(Name prefix) { - return literal(prefix, S.pos()); + return literal(prefix, token.pos); } /** @@ -498,27 +504,29 @@ public class JavacParser implements Parser { */ JCExpression literal(Name prefix, int pos) { JCExpression t = errorTree; - switch (S.token()) { + switch (token.kind) { case INTLITERAL: try { t = F.at(pos).Literal( TypeTags.INT, - Convert.string2int(strval(prefix), S.radix())); + Convert.string2int(strval(prefix), token.radix())); } catch (NumberFormatException ex) { - error(S.pos(), "int.number.too.large", strval(prefix)); + error(token.pos, "int.number.too.large", strval(prefix)); } break; case LONGLITERAL: try { t = F.at(pos).Literal( TypeTags.LONG, - new Long(Convert.string2long(strval(prefix), S.radix()))); + new Long(Convert.string2long(strval(prefix), token.radix()))); } catch (NumberFormatException ex) { - error(S.pos(), "int.number.too.large", strval(prefix)); + error(token.pos, "int.number.too.large", strval(prefix)); } break; case FLOATLITERAL: { - String proper = (S.radix() == 16 ? ("0x"+ S.stringVal()) : S.stringVal()); + String proper = token.radix() == 16 ? + ("0x"+ token.stringVal()) : + token.stringVal(); Float n; try { n = Float.valueOf(proper); @@ -527,15 +535,17 @@ public class JavacParser implements Parser { n = Float.NaN; } if (n.floatValue() == 0.0f && !isZero(proper)) - error(S.pos(), "fp.number.too.small"); + error(token.pos, "fp.number.too.small"); else if (n.floatValue() == Float.POSITIVE_INFINITY) - error(S.pos(), "fp.number.too.large"); + error(token.pos, "fp.number.too.large"); else t = F.at(pos).Literal(TypeTags.FLOAT, n); break; } case DOUBLELITERAL: { - String proper = (S.radix() == 16 ? ("0x"+ S.stringVal()) : S.stringVal()); + String proper = token.radix() == 16 ? + ("0x"+ token.stringVal()) : + token.stringVal(); Double n; try { n = Double.valueOf(proper); @@ -544,9 +554,9 @@ public class JavacParser implements Parser { n = Double.NaN; } if (n.doubleValue() == 0.0d && !isZero(proper)) - error(S.pos(), "fp.number.too.small"); + error(token.pos, "fp.number.too.small"); else if (n.doubleValue() == Double.POSITIVE_INFINITY) - error(S.pos(), "fp.number.too.large"); + error(token.pos, "fp.number.too.large"); else t = F.at(pos).Literal(TypeTags.DOUBLE, n); break; @@ -554,17 +564,17 @@ public class JavacParser implements Parser { case CHARLITERAL: t = F.at(pos).Literal( TypeTags.CHAR, - S.stringVal().charAt(0) + 0); + token.stringVal().charAt(0) + 0); break; case STRINGLITERAL: t = F.at(pos).Literal( TypeTags.CLASS, - S.stringVal()); + token.stringVal()); break; case TRUE: case FALSE: t = F.at(pos).Literal( TypeTags.BOOLEAN, - (S.token() == TRUE ? 1 : 0)); + (token.kind == TRUE ? 1 : 0)); break; case NULL: t = F.at(pos).Literal( @@ -576,8 +586,8 @@ public class JavacParser implements Parser { } if (t == errorTree) t = F.at(pos).Erroneous(); - storeEnd(t, S.endPos()); - S.nextToken(); + storeEnd(t, token.endPos); + nextToken(); return t; } //where @@ -590,7 +600,7 @@ public class JavacParser implements Parser { } String strval(Name prefix) { - String s = S.stringVal(); + String s = token.stringVal(); return prefix.isEmpty() ? s : prefix + s; } @@ -627,17 +637,17 @@ public class JavacParser implements Parser { JCExpression term() { JCExpression t = term1(); if ((mode & EXPR) != 0 && - S.token() == EQ || PLUSEQ.compareTo(S.token()) <= 0 && S.token().compareTo(GTGTGTEQ) <= 0) + token.kind == EQ || PLUSEQ.compareTo(token.kind) <= 0 && token.kind.compareTo(GTGTGTEQ) <= 0) return termRest(t); else return t; } JCExpression termRest(JCExpression t) { - switch (S.token()) { + switch (token.kind) { case EQ: { - int pos = S.pos(); - S.nextToken(); + int pos = token.pos; + nextToken(); mode = EXPR; JCExpression t1 = term(); return toP(F.at(pos).Assign(t, t1)); @@ -653,12 +663,12 @@ public class JavacParser implements Parser { case LTLTEQ: case GTGTEQ: case GTGTGTEQ: - int pos = S.pos(); - Token token = S.token(); - S.nextToken(); + int pos = token.pos; + TokenKind tk = token.kind; + nextToken(); mode = EXPR; JCExpression t1 = term(); - return F.at(pos).Assignop(optag(token), t, t1); + return F.at(pos).Assignop(optag(tk), t, t1); default: return t; } @@ -670,7 +680,7 @@ public class JavacParser implements Parser { */ JCExpression term1() { JCExpression t = term2(); - if ((mode & EXPR) != 0 && S.token() == QUES) { + if ((mode & EXPR) != 0 && token.kind == QUES) { mode = EXPR; return term1Rest(t); } else { @@ -681,9 +691,9 @@ public class JavacParser implements Parser { /** Expression1Rest = ["?" Expression ":" Expression1] */ JCExpression term1Rest(JCExpression t) { - if (S.token() == QUES) { - int pos = S.pos(); - S.nextToken(); + if (token.kind == QUES) { + int pos = token.pos; + nextToken(); JCExpression t1 = term(); accept(COLON); JCExpression t2 = term1(); @@ -699,7 +709,7 @@ public class JavacParser implements Parser { */ JCExpression term2() { JCExpression t = term3(); - if ((mode & EXPR) != 0 && prec(S.token()) >= TreeInfo.orPrec) { + if ((mode & EXPR) != 0 && prec(token.kind) >= TreeInfo.orPrec) { mode = EXPR; return term2Rest(t, TreeInfo.orPrec); } else { @@ -725,28 +735,23 @@ public class JavacParser implements Parser { JCExpression[] odStack = newOdStack(); List savedOp = opStackSupply.elems; Token[] opStack = newOpStack(); - List savedPos = posStackSupply.elems; - int[] posStack = newPosStack(); + // optimization, was odStack = new Tree[...]; opStack = new Tree[...]; int top = 0; odStack[0] = t; - int startPos = S.pos(); - Token topOp = ERROR; - int topOpPos = Position.NOPOS; - while (prec(S.token()) >= minprec) { - posStack[top] = topOpPos; + int startPos = token.pos; + Token topOp = Tokens.DUMMY; + while (prec(token.kind) >= minprec) { opStack[top] = topOp; top++; - topOp = S.token(); - topOpPos = S.pos(); - S.nextToken(); - odStack[top] = (topOp == INSTANCEOF) ? parseType() : term3(); - while (top > 0 && prec(topOp) >= prec(S.token())) { - odStack[top-1] = makeOp(topOpPos, topOp, odStack[top-1], + topOp = token; + nextToken(); + odStack[top] = (topOp.kind == INSTANCEOF) ? parseType() : term3(); + while (top > 0 && prec(topOp.kind) >= prec(token.kind)) { + odStack[top-1] = makeOp(topOp.pos, topOp.kind, odStack[top-1], odStack[top]); top--; topOp = opStack[top]; - topOpPos = posStack[top]; } } Assert.check(top == 0); @@ -761,14 +766,13 @@ public class JavacParser implements Parser { odStackSupply.elems = savedOd; // optimization opStackSupply.elems = savedOp; // optimization - posStackSupply.elems = savedPos; // optimization return t; } //where /** Construct a binary or type test node. */ private JCExpression makeOp(int pos, - Token topOp, + TokenKind topOp, JCExpression od1, JCExpression od2) { @@ -817,7 +821,6 @@ public class JavacParser implements Parser { */ ListBuffer odStackSupply = new ListBuffer(); ListBuffer opStackSupply = new ListBuffer(); - ListBuffer posStackSupply = new ListBuffer(); private JCExpression[] newOdStack() { if (odStackSupply.elems == odStackSupply.last) @@ -835,14 +838,6 @@ public class JavacParser implements Parser { return opStack; } - private int[] newPosStack() { - if (posStackSupply.elems == posStackSupply.last) - posStackSupply.append(new int[infixPrecedenceLevels + 1]); - int[] posStack = posStackSupply.elems.head; - posStackSupply.elems = posStackSupply.elems.tail; - return posStack; - } - /** Expression3 = PrefixOp Expression3 * | "(" Expr | TypeNoParams ")" Expression3 * | Primary {Selector} {PostfixOp} @@ -871,10 +866,10 @@ public class JavacParser implements Parser { * SuperSuffix = Arguments | "." Ident [Arguments] */ protected JCExpression term3() { - int pos = S.pos(); + int pos = token.pos; JCExpression t; List typeArgs = typeArgumentsOpt(EXPR); - switch (S.token()) { + switch (token.kind) { case QUES: if ((mode & TYPE) != 0 && (mode & (TYPEARG|NOPARAMS)) == TYPEARG) { mode = TYPE; @@ -883,49 +878,49 @@ public class JavacParser implements Parser { return illegal(); case PLUSPLUS: case SUBSUB: case BANG: case TILDE: case PLUS: case SUB: if (typeArgs == null && (mode & EXPR) != 0) { - Token token = S.token(); - S.nextToken(); + TokenKind tk = token.kind; + nextToken(); mode = EXPR; - if (token == SUB && - (S.token() == INTLITERAL || S.token() == LONGLITERAL) && - S.radix() == 10) { + if (tk == SUB && + (token.kind == INTLITERAL || token.kind == LONGLITERAL) && + token.radix() == 10) { mode = EXPR; t = literal(names.hyphen, pos); } else { t = term3(); - return F.at(pos).Unary(unoptag(token), t); + return F.at(pos).Unary(unoptag(tk), t); } } else return illegal(); break; case LPAREN: if (typeArgs == null && (mode & EXPR) != 0) { - S.nextToken(); + nextToken(); mode = EXPR | TYPE | NOPARAMS; t = term3(); - if ((mode & TYPE) != 0 && S.token() == LT) { + if ((mode & TYPE) != 0 && token.kind == LT) { // Could be a cast to a parameterized type int op = JCTree.LT; - int pos1 = S.pos(); - S.nextToken(); + int pos1 = token.pos; + nextToken(); mode &= (EXPR | TYPE); mode |= TYPEARG; JCExpression t1 = term3(); if ((mode & TYPE) != 0 && - (S.token() == COMMA || S.token() == GT)) { + (token.kind == COMMA || token.kind == GT)) { mode = TYPE; ListBuffer args = new ListBuffer(); args.append(t1); - while (S.token() == COMMA) { - S.nextToken(); + while (token.kind == COMMA) { + nextToken(); args.append(typeArgument()); } accept(GT); t = toP(F.at(pos1).TypeApply(t, args.toList())); checkGenerics(); - while (S.token() == DOT) { - S.nextToken(); + while (token.kind == DOT) { + nextToken(); mode = TYPE; - t = toP(F.at(S.pos()).Select(t, ident())); + t = toP(F.at(token.pos).Select(t, ident())); t = typeArgumentsOpt(t); } t = bracketsOpt(toP(t)); @@ -948,7 +943,7 @@ public class JavacParser implements Parser { JCExpression t1 = term3(); return F.at(pos).TypeCast(t, t1); } else if ((lastmode & TYPE) != 0) { - switch (S.token()) { + switch (token.kind) { /*case PLUSPLUS: case SUBSUB: */ case BANG: case TILDE: case LPAREN: case THIS: case SUPER: @@ -969,7 +964,7 @@ public class JavacParser implements Parser { if ((mode & EXPR) != 0) { mode = EXPR; t = to(F.at(pos).Ident(names._this)); - S.nextToken(); + nextToken(); if (typeArgs == null) t = argumentsOpt(null, t); else @@ -997,22 +992,22 @@ public class JavacParser implements Parser { if (typeArgs != null) return illegal(); if ((mode & EXPR) != 0) { mode = EXPR; - S.nextToken(); - if (S.token() == LT) typeArgs = typeArguments(false); + nextToken(); + if (token.kind == LT) typeArgs = typeArguments(false); t = creator(pos, typeArgs); typeArgs = null; } else return illegal(); break; case IDENTIFIER: case ASSERT: case ENUM: if (typeArgs != null) return illegal(); - t = toP(F.at(S.pos()).Ident(ident())); + t = toP(F.at(token.pos).Ident(ident())); loop: while (true) { - pos = S.pos(); - switch (S.token()) { + pos = token.pos; + switch (token.kind) { case LBRACKET: - S.nextToken(); - if (S.token() == RBRACKET) { - S.nextToken(); + nextToken(); + if (token.kind == RBRACKET) { + nextToken(); t = bracketsOpt(t); t = toP(F.at(pos).TypeArray(t)); t = bracketsSuffix(t); @@ -1033,24 +1028,24 @@ public class JavacParser implements Parser { } break loop; case DOT: - S.nextToken(); + nextToken(); int oldmode = mode; mode &= ~NOPARAMS; typeArgs = typeArgumentsOpt(EXPR); mode = oldmode; if ((mode & EXPR) != 0) { - switch (S.token()) { + switch (token.kind) { case CLASS: if (typeArgs != null) return illegal(); mode = EXPR; t = to(F.at(pos).Select(t, names._class)); - S.nextToken(); + nextToken(); break loop; case THIS: if (typeArgs != null) return illegal(); mode = EXPR; t = to(F.at(pos).Select(t, names._this)); - S.nextToken(); + nextToken(); break loop; case SUPER: mode = EXPR; @@ -1061,9 +1056,9 @@ public class JavacParser implements Parser { case NEW: if (typeArgs != null) return illegal(); mode = EXPR; - int pos1 = S.pos(); - S.nextToken(); - if (S.token() == LT) typeArgs = typeArguments(false); + int pos1 = token.pos; + nextToken(); + if (token.kind == LT) typeArgs = typeArguments(false); t = innerCreator(pos1, typeArgs, t); typeArgs = null; break loop; @@ -1087,8 +1082,8 @@ public class JavacParser implements Parser { case VOID: if (typeArgs != null) illegal(); if ((mode & EXPR) != 0) { - S.nextToken(); - if (S.token() == DOT) { + nextToken(); + if (token.kind == DOT) { JCPrimitiveTypeTree ti = toP(F.at(pos).TypeIdent(TypeTags.VOID)); t = bracketsSuffix(ti); } else { @@ -1099,7 +1094,7 @@ public class JavacParser implements Parser { // 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(); + nextToken(); return ti; //return illegal(); } @@ -1109,14 +1104,14 @@ public class JavacParser implements Parser { } if (typeArgs != null) illegal(); while (true) { - int pos1 = S.pos(); - if (S.token() == LBRACKET) { - S.nextToken(); + int pos1 = token.pos; + if (token.kind == LBRACKET) { + nextToken(); if ((mode & TYPE) != 0) { int oldmode = mode; mode = TYPE; - if (S.token() == RBRACKET) { - S.nextToken(); + if (token.kind == RBRACKET) { + nextToken(); t = bracketsOpt(t); t = toP(F.at(pos1).TypeArray(t)); return t; @@ -1129,21 +1124,21 @@ public class JavacParser implements Parser { t = to(F.at(pos1).Indexed(t, t1)); } accept(RBRACKET); - } else if (S.token() == DOT) { - S.nextToken(); + } else if (token.kind == DOT) { + nextToken(); typeArgs = typeArgumentsOpt(EXPR); - if (S.token() == SUPER && (mode & EXPR) != 0) { + if (token.kind == SUPER && (mode & EXPR) != 0) { mode = EXPR; t = to(F.at(pos1).Select(t, names._super)); - S.nextToken(); + nextToken(); t = arguments(typeArgs, t); typeArgs = null; - } else if (S.token() == NEW && (mode & EXPR) != 0) { + } else if (token.kind == NEW && (mode & EXPR) != 0) { if (typeArgs != null) return illegal(); mode = EXPR; - int pos2 = S.pos(); - S.nextToken(); - if (S.token() == LT) typeArgs = typeArguments(false); + int pos2 = token.pos; + nextToken(); + if (token.kind == LT) typeArgs = typeArguments(false); t = innerCreator(pos2, typeArgs, t); typeArgs = null; } else { @@ -1155,11 +1150,11 @@ public class JavacParser implements Parser { break; } } - while ((S.token() == PLUSPLUS || S.token() == SUBSUB) && (mode & EXPR) != 0) { + while ((token.kind == PLUSPLUS || token.kind == SUBSUB) && (mode & EXPR) != 0) { mode = EXPR; - t = to(F.at(S.pos()).Unary( - S.token() == PLUSPLUS ? JCTree.POSTINC : JCTree.POSTDEC, t)); - S.nextToken(); + t = to(F.at(token.pos).Unary( + token.kind == PLUSPLUS ? JCTree.POSTINC : JCTree.POSTDEC, t)); + nextToken(); } return toP(t); } @@ -1167,13 +1162,13 @@ public class JavacParser implements Parser { /** SuperSuffix = Arguments | "." [TypeArguments] Ident [Arguments] */ JCExpression superSuffix(List typeArgs, JCExpression t) { - S.nextToken(); - if (S.token() == LPAREN || typeArgs != null) { + nextToken(); + if (token.kind == LPAREN || typeArgs != null) { t = arguments(typeArgs, t); } else { - int pos = S.pos(); + int pos = token.pos; accept(DOT); - typeArgs = (S.token() == LT) ? typeArguments(false) : null; + typeArgs = (token.kind == LT) ? typeArguments(false) : null; t = toP(F.at(pos).Select(t, ident())); t = argumentsOpt(typeArgs, t); } @@ -1183,15 +1178,15 @@ public class JavacParser implements Parser { /** BasicType = BYTE | SHORT | CHAR | INT | LONG | FLOAT | DOUBLE | BOOLEAN */ JCPrimitiveTypeTree basicType() { - JCPrimitiveTypeTree t = to(F.at(S.pos()).TypeIdent(typetag(S.token()))); - S.nextToken(); + JCPrimitiveTypeTree t = to(F.at(token.pos).TypeIdent(typetag(token.kind))); + nextToken(); return t; } /** ArgumentsOpt = [ Arguments ] */ JCExpression argumentsOpt(List typeArgs, JCExpression t) { - if ((mode & EXPR) != 0 && S.token() == LPAREN || typeArgs != null) { + if ((mode & EXPR) != 0 && token.kind == LPAREN || typeArgs != null) { mode = EXPR; return arguments(typeArgs, t); } else { @@ -1203,24 +1198,24 @@ public class JavacParser implements Parser { */ List arguments() { ListBuffer args = lb(); - if (S.token() == LPAREN) { - S.nextToken(); - if (S.token() != RPAREN) { + if (token.kind == LPAREN) { + nextToken(); + if (token.kind != RPAREN) { args.append(parseExpression()); - while (S.token() == COMMA) { - S.nextToken(); + while (token.kind == COMMA) { + nextToken(); args.append(parseExpression()); } } accept(RPAREN); } else { - syntaxError(S.pos(), "expected", LPAREN); + syntaxError(token.pos, "expected", LPAREN); } return args.toList(); } JCMethodInvocation arguments(List typeArgs, JCExpression t) { - int pos = S.pos(); + int pos = token.pos; List args = arguments(); return toP(F.at(pos).Apply(typeArgs, t, args)); } @@ -1228,7 +1223,7 @@ public class JavacParser implements Parser { /** TypeArgumentsOpt = [ TypeArguments ] */ JCExpression typeArgumentsOpt(JCExpression t) { - if (S.token() == LT && + if (token.kind == LT && (mode & TYPE) != 0 && (mode & NOPARAMS) == 0) { mode = TYPE; @@ -1243,7 +1238,7 @@ public class JavacParser implements Parser { } List typeArgumentsOpt(int useMode) { - if (S.token() == LT) { + if (token.kind == LT) { checkGenerics(); if ((mode & useMode) == 0 || (mode & NOPARAMS) != 0) { @@ -1258,47 +1253,37 @@ public class JavacParser implements Parser { /** TypeArguments = "<" TypeArgument {"," TypeArgument} ">" */ List typeArguments(boolean diamondAllowed) { - if (S.token() == LT) { - S.nextToken(); - if (S.token() == GT && diamondAllowed) { + if (token.kind == LT) { + nextToken(); + if (token.kind == GT && diamondAllowed) { checkDiamond(); mode |= DIAMOND; - S.nextToken(); + nextToken(); return List.nil(); } else { ListBuffer args = ListBuffer.lb(); args.append(((mode & EXPR) == 0) ? typeArgument() : parseType()); - while (S.token() == COMMA) { - S.nextToken(); + while (token.kind == COMMA) { + nextToken(); args.append(((mode & EXPR) == 0) ? typeArgument() : parseType()); } - switch (S.token()) { - case GTGTGTEQ: - S.token(GTGTEQ); - break; - case GTGTEQ: - S.token(GTEQ); - break; - case GTEQ: - S.token(EQ); - break; - case GTGTGT: - S.token(GTGT); - break; - case GTGT: - S.token(GT); + switch (token.kind) { + + case GTGTGTEQ: case GTGTEQ: case GTEQ: + case GTGTGT: case GTGT: + token = S.split(); break; case GT: - S.nextToken(); + nextToken(); break; default: - args.append(syntaxError(S.pos(), "expected", GT)); + args.append(syntaxError(token.pos, "expected", GT)); break; } return args.toList(); } } else { - return List.of(syntaxError(S.pos(), "expected", LT)); + return List.of(syntaxError(token.pos, "expected", LT)); } } @@ -1308,24 +1293,24 @@ public class JavacParser implements Parser { * | "?" SUPER Type */ JCExpression typeArgument() { - if (S.token() != QUES) return parseType(); - int pos = S.pos(); - S.nextToken(); - if (S.token() == EXTENDS) { + if (token.kind != QUES) return parseType(); + int pos = token.pos; + nextToken(); + if (token.kind == EXTENDS) { TypeBoundKind t = to(F.at(pos).TypeBoundKind(BoundKind.EXTENDS)); - S.nextToken(); + nextToken(); JCExpression bound = parseType(); return F.at(pos).Wildcard(t, bound); - } else if (S.token() == SUPER) { + } else if (token.kind == SUPER) { TypeBoundKind t = to(F.at(pos).TypeBoundKind(BoundKind.SUPER)); - S.nextToken(); + nextToken(); JCExpression bound = parseType(); return F.at(pos).Wildcard(t, bound); - } else if (S.token() == IDENTIFIER) { + } else if (token.kind == IDENTIFIER) { //error recovery TypeBoundKind t = F.at(Position.NOPOS).TypeBoundKind(BoundKind.UNBOUND); JCExpression wc = toP(F.at(pos).Wildcard(t, null)); - JCIdent id = toP(F.at(S.pos()).Ident(ident())); + JCIdent id = toP(F.at(token.pos).Ident(ident())); JCErroneous err = F.at(pos).Erroneous(List.of(wc, id)); reportSyntaxError(err, "expected3", GT, EXTENDS, SUPER); return err; @@ -1336,7 +1321,7 @@ public class JavacParser implements Parser { } JCTypeApply typeArguments(JCExpression t, boolean diamondAllowed) { - int pos = S.pos(); + int pos = token.pos; List args = typeArguments(diamondAllowed); return toP(F.at(pos).TypeApply(t, args)); } @@ -1344,9 +1329,9 @@ public class JavacParser implements Parser { /** BracketsOpt = {"[" "]"} */ private JCExpression bracketsOpt(JCExpression t) { - if (S.token() == LBRACKET) { - int pos = S.pos(); - S.nextToken(); + if (token.kind == LBRACKET) { + int pos = token.pos; + nextToken(); t = bracketsOptCont(t, pos); F.at(pos); } @@ -1363,17 +1348,17 @@ public class JavacParser implements Parser { * BracketsSuffixType = */ JCExpression bracketsSuffix(JCExpression t) { - if ((mode & EXPR) != 0 && S.token() == DOT) { + if ((mode & EXPR) != 0 && token.kind == DOT) { mode = EXPR; - int pos = S.pos(); - S.nextToken(); + int pos = token.pos; + nextToken(); accept(CLASS); - if (S.pos() == errorEndPos) { + if (token.pos == errorEndPos) { // error recovery Name name = null; - if (S.token() == IDENTIFIER) { - name = S.name(); - S.nextToken(); + if (token.kind == IDENTIFIER) { + name = token.name(); + nextToken(); } else { name = names.error; } @@ -1384,7 +1369,7 @@ public class JavacParser implements Parser { } else if ((mode & TYPE) != 0) { mode = TYPE; } else { - syntaxError(S.pos(), "dot.class.expected"); + syntaxError(token.pos, "dot.class.expected"); } return t; } @@ -1392,7 +1377,7 @@ public class JavacParser implements Parser { /** Creator = Qualident [TypeArguments] ( ArrayCreatorRest | ClassCreatorRest ) */ JCExpression creator(int newpos, List typeArgs) { - switch (S.token()) { + switch (token.kind) { case BYTE: case SHORT: case CHAR: case INT: case LONG: case FLOAT: case DOUBLE: case BOOLEAN: if (typeArgs == null) @@ -1405,29 +1390,29 @@ public class JavacParser implements Parser { mode = TYPE; boolean diamondFound = false; int lastTypeargsPos = -1; - if (S.token() == LT) { + if (token.kind == LT) { checkGenerics(); - lastTypeargsPos = S.pos(); + lastTypeargsPos = token.pos; t = typeArguments(t, true); diamondFound = (mode & DIAMOND) != 0; } - while (S.token() == DOT) { + while (token.kind == DOT) { if (diamondFound) { //cannot select after a diamond illegal(); } - int pos = S.pos(); - S.nextToken(); + int pos = token.pos; + nextToken(); t = toP(F.at(pos).Select(t, ident())); - if (S.token() == LT) { - lastTypeargsPos = S.pos(); + if (token.kind == LT) { + lastTypeargsPos = token.pos; checkGenerics(); t = typeArguments(t, true); diamondFound = (mode & DIAMOND) != 0; } } mode = oldmode; - if (S.token() == LBRACKET) { + if (token.kind == LBRACKET) { JCExpression e = arrayCreatorRest(newpos, t); if (diamondFound) { reportSyntaxError(lastTypeargsPos, "cannot.create.array.with.diamond"); @@ -1441,17 +1426,17 @@ public class JavacParser implements Parser { // modified to improve error recovery. pos = typeArgs.head.pos; } - setErrorEndPos(S.prevEndPos()); + setErrorEndPos(S.prevToken().endPos); JCErroneous err = F.at(pos).Erroneous(typeArgs.prepend(e)); reportSyntaxError(err, "cannot.create.array.with.type.arguments"); return toP(err); } return e; - } else if (S.token() == LPAREN) { + } else if (token.kind == LPAREN) { return classCreatorRest(newpos, null, typeArgs, t); } else { - setErrorEndPos(S.pos()); - reportSyntaxError(S.pos(), "expected2", LPAREN, LBRACKET); + setErrorEndPos(token.pos); + reportSyntaxError(token.pos, "expected2", LPAREN, LBRACKET); t = toP(F.at(newpos).NewClass(null, typeArgs, t, List.nil(), null)); return toP(F.at(newpos).Erroneous(List.of(t))); } @@ -1460,8 +1445,8 @@ public class JavacParser implements Parser { /** InnerCreator = Ident [TypeArguments] ClassCreatorRest */ JCExpression innerCreator(int newpos, List typeArgs, JCExpression encl) { - JCExpression t = toP(F.at(S.pos()).Ident(ident())); - if (S.token() == LT) { + JCExpression t = toP(F.at(token.pos).Ident(ident())); + if (token.kind == LT) { int oldmode = mode; checkGenerics(); t = typeArguments(t, true); @@ -1475,23 +1460,23 @@ public class JavacParser implements Parser { */ JCExpression arrayCreatorRest(int newpos, JCExpression elemtype) { accept(LBRACKET); - if (S.token() == RBRACKET) { + if (token.kind == RBRACKET) { accept(RBRACKET); elemtype = bracketsOpt(elemtype); - if (S.token() == LBRACE) { + if (token.kind == LBRACE) { return arrayInitializer(newpos, elemtype); } else { JCExpression t = toP(F.at(newpos).NewArray(elemtype, List.nil(), null)); - return syntaxError(S.pos(), List.of(t), "array.dimension.missing"); + return syntaxError(token.pos, List.of(t), "array.dimension.missing"); } } else { ListBuffer dims = new ListBuffer(); dims.append(parseExpression()); accept(RBRACKET); - while (S.token() == LBRACKET) { - int pos = S.pos(); - S.nextToken(); - if (S.token() == RBRACKET) { + while (token.kind == LBRACKET) { + int pos = token.pos; + nextToken(); + if (token.kind == RBRACKET) { elemtype = bracketsOptCont(elemtype, pos); } else { dims.append(parseExpression()); @@ -1511,8 +1496,8 @@ public class JavacParser implements Parser { { List args = arguments(); JCClassDecl body = null; - if (S.token() == LBRACE) { - int pos = S.pos(); + if (token.kind == LBRACE) { + int pos = token.pos; List defs = classOrInterfaceBody(names.empty, false); JCModifiers mods = F.at(Position.NOPOS).Modifiers(0); body = toP(F.at(pos).AnonymousClassDef(mods, defs)); @@ -1525,13 +1510,13 @@ public class JavacParser implements Parser { JCExpression arrayInitializer(int newpos, JCExpression t) { accept(LBRACE); ListBuffer elems = new ListBuffer(); - if (S.token() == COMMA) { - S.nextToken(); - } else if (S.token() != RBRACE) { + if (token.kind == COMMA) { + nextToken(); + } else if (token.kind != RBRACE) { elems.append(variableInitializer()); - while (S.token() == COMMA) { - S.nextToken(); - if (S.token() == RBRACE) break; + while (token.kind == COMMA) { + nextToken(); + if (token.kind == RBRACE) break; elems.append(variableInitializer()); } } @@ -1542,7 +1527,7 @@ public class JavacParser implements Parser { /** VariableInitializer = ArrayInitializer | Expression */ public JCExpression variableInitializer() { - return S.token() == LBRACE ? arrayInitializer(S.pos(), null) : parseExpression(); + return token.kind == LBRACE ? arrayInitializer(token.pos, null) : parseExpression(); } /** ParExpression = "(" Expression ")" @@ -1560,19 +1545,19 @@ public class JavacParser implements Parser { accept(LBRACE); List stats = blockStatements(); JCBlock t = F.at(pos).Block(flags, stats); - while (S.token() == CASE || S.token() == DEFAULT) { - syntaxError("orphaned", S.token()); + while (token.kind == CASE || token.kind == DEFAULT) { + syntaxError("orphaned", token.kind); switchBlockStatementGroups(); } // the Block node has a field "endpos" for first char of last token, which is // usually but not necessarily the last char of the last token. - t.endpos = S.pos(); + t.endpos = token.pos; accept(RBRACE); return toP(t); } public JCBlock block() { - return block(S.pos(), 0); + return block(token.pos, 0); } /** BlockStatements = { BlockStatement } @@ -1588,8 +1573,8 @@ public class JavacParser implements Parser { int lastErrPos = -1; ListBuffer stats = new ListBuffer(); while (true) { - int pos = S.pos(); - switch (S.token()) { + int pos = token.pos; + switch (token.kind) { case RBRACE: case CASE: case DEFAULT: case EOF: return stats.toList(); case LBRACE: case IF: case FOR: case WHILE: case DO: case TRY: @@ -1599,64 +1584,63 @@ public class JavacParser implements Parser { break; case MONKEYS_AT: case FINAL: { - String dc = S.docComment(); + String dc = token.docComment; JCModifiers mods = modifiersOpt(); - if (S.token() == INTERFACE || - S.token() == CLASS || - allowEnums && S.token() == ENUM) { + if (token.kind == INTERFACE || + token.kind == CLASS || + allowEnums && token.kind == ENUM) { stats.append(classOrInterfaceOrEnumDeclaration(mods, dc)); } else { JCExpression t = parseType(); stats.appendList(variableDeclarators(mods, t, new ListBuffer())); // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon - storeEnd(stats.elems.last(), S.endPos()); + storeEnd(stats.elems.last(), token.endPos); accept(SEMI); } break; } case ABSTRACT: case STRICTFP: { - String dc = S.docComment(); + String dc = token.docComment; JCModifiers mods = modifiersOpt(); stats.append(classOrInterfaceOrEnumDeclaration(mods, dc)); break; } case INTERFACE: case CLASS: - stats.append(classOrInterfaceOrEnumDeclaration(modifiersOpt(), - S.docComment())); + String dc = token.docComment; + stats.append(classOrInterfaceOrEnumDeclaration(modifiersOpt(), dc)); break; case ENUM: case ASSERT: - if (allowEnums && S.token() == ENUM) { - error(S.pos(), "local.enum"); - stats. - append(classOrInterfaceOrEnumDeclaration(modifiersOpt(), - S.docComment())); + if (allowEnums && token.kind == ENUM) { + error(token.pos, "local.enum"); + dc = token.docComment; + stats.append(classOrInterfaceOrEnumDeclaration(modifiersOpt(), dc)); break; - } else if (allowAsserts && S.token() == ASSERT) { + } else if (allowAsserts && token.kind == ASSERT) { stats.append(parseStatement()); break; } /* fall through to default */ default: - Name name = S.name(); + Token prevToken = token; JCExpression t = term(EXPR | TYPE); - if (S.token() == COLON && t.getTag() == JCTree.IDENT) { - S.nextToken(); + if (token.kind == COLON && t.getTag() == JCTree.IDENT) { + nextToken(); JCStatement stat = parseStatement(); - stats.append(F.at(pos).Labelled(name, stat)); + stats.append(F.at(pos).Labelled(prevToken.name(), stat)); } else if ((lastmode & TYPE) != 0 && - (S.token() == IDENTIFIER || - S.token() == ASSERT || - S.token() == ENUM)) { - pos = S.pos(); + (token.kind == IDENTIFIER || + token.kind == ASSERT || + token.kind == ENUM)) { + pos = token.pos; JCModifiers mods = F.at(Position.NOPOS).Modifiers(0); F.at(pos); stats.appendList(variableDeclarators(mods, t, new ListBuffer())); // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon - storeEnd(stats.elems.last(), S.endPos()); + storeEnd(stats.elems.last(), token.endPos); accept(SEMI); } else { // This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon @@ -1666,15 +1650,12 @@ public class JavacParser implements Parser { } // error recovery - if (S.pos() == lastErrPos) + if (token.pos == lastErrPos) return stats.toList(); - if (S.pos() <= errorEndPos) { + if (token.pos <= errorEndPos) { skip(false, true, true, true); - lastErrPos = S.pos(); + lastErrPos = token.pos; } - - // ensure no dangling /** @deprecated */ active - S.resetDeprecatedFlag(); } } @@ -1700,29 +1681,29 @@ public class JavacParser implements Parser { */ @SuppressWarnings("fallthrough") public JCStatement parseStatement() { - int pos = S.pos(); - switch (S.token()) { + int pos = token.pos; + switch (token.kind) { case LBRACE: return block(); case IF: { - S.nextToken(); + nextToken(); JCExpression cond = parExpression(); JCStatement thenpart = parseStatement(); JCStatement elsepart = null; - if (S.token() == ELSE) { - S.nextToken(); + if (token.kind == ELSE) { + nextToken(); elsepart = parseStatement(); } return F.at(pos).If(cond, thenpart, elsepart); } case FOR: { - S.nextToken(); + nextToken(); accept(LPAREN); - List inits = S.token() == SEMI ? List.nil() : forInit(); + List inits = token.kind == SEMI ? List.nil() : forInit(); if (inits.length() == 1 && inits.head.getTag() == JCTree.VARDEF && ((JCVariableDecl) inits.head).init == null && - S.token() == COLON) { + token.kind == COLON) { checkForeach(); JCVariableDecl var = (JCVariableDecl)inits.head; accept(COLON); @@ -1732,22 +1713,22 @@ public class JavacParser implements Parser { return F.at(pos).ForeachLoop(var, expr, body); } else { accept(SEMI); - JCExpression cond = S.token() == SEMI ? null : parseExpression(); + JCExpression cond = token.kind == SEMI ? null : parseExpression(); accept(SEMI); - List steps = S.token() == RPAREN ? List.nil() : forUpdate(); + List steps = token.kind == RPAREN ? List.nil() : forUpdate(); accept(RPAREN); JCStatement body = parseStatement(); return F.at(pos).ForLoop(inits, cond, steps, body); } } case WHILE: { - S.nextToken(); + nextToken(); JCExpression cond = parExpression(); JCStatement body = parseStatement(); return F.at(pos).WhileLoop(cond, body); } case DO: { - S.nextToken(); + nextToken(); JCStatement body = parseStatement(); accept(WHILE); JCExpression cond = parExpression(); @@ -1756,21 +1737,21 @@ public class JavacParser implements Parser { return t; } case TRY: { - S.nextToken(); + nextToken(); List resources = List.nil(); - if (S.token() == LPAREN) { + if (token.kind == LPAREN) { checkTryWithResources(); - S.nextToken(); + nextToken(); resources = resources(); accept(RPAREN); } JCBlock body = block(); ListBuffer catchers = new ListBuffer(); JCBlock finalizer = null; - if (S.token() == CATCH || S.token() == FINALLY) { - while (S.token() == CATCH) catchers.append(catchClause()); - if (S.token() == FINALLY) { - S.nextToken(); + if (token.kind == CATCH || token.kind == FINALLY) { + while (token.kind == CATCH) catchers.append(catchClause()); + if (token.kind == FINALLY) { + nextToken(); finalizer = block(); } } else { @@ -1783,7 +1764,7 @@ public class JavacParser implements Parser { return F.at(pos).Try(resources, body, catchers.toList(), finalizer); } case SWITCH: { - S.nextToken(); + nextToken(); JCExpression selector = parExpression(); accept(LBRACE); List cases = switchBlockStatementGroups(); @@ -1792,41 +1773,41 @@ public class JavacParser implements Parser { return t; } case SYNCHRONIZED: { - S.nextToken(); + nextToken(); JCExpression lock = parExpression(); JCBlock body = block(); return F.at(pos).Synchronized(lock, body); } case RETURN: { - S.nextToken(); - JCExpression result = S.token() == SEMI ? null : parseExpression(); + nextToken(); + JCExpression result = token.kind == SEMI ? null : parseExpression(); JCReturn t = to(F.at(pos).Return(result)); accept(SEMI); return t; } case THROW: { - S.nextToken(); + nextToken(); JCExpression exc = parseExpression(); JCThrow t = to(F.at(pos).Throw(exc)); accept(SEMI); return t; } case BREAK: { - S.nextToken(); - Name label = (S.token() == IDENTIFIER || S.token() == ASSERT || S.token() == ENUM) ? ident() : null; + nextToken(); + Name label = (token.kind == IDENTIFIER || token.kind == ASSERT || token.kind == ENUM) ? ident() : null; JCBreak t = to(F.at(pos).Break(label)); accept(SEMI); return t; } case CONTINUE: { - S.nextToken(); - Name label = (S.token() == IDENTIFIER || S.token() == ASSERT || S.token() == ENUM) ? ident() : null; + nextToken(); + Name label = (token.kind == IDENTIFIER || token.kind == ASSERT || token.kind == ENUM) ? ident() : null; JCContinue t = to(F.at(pos).Continue(label)); accept(SEMI); return t; } case SEMI: - S.nextToken(); + nextToken(); return toP(F.at(pos).Skip()); case ELSE: return toP(F.Exec(syntaxError("else.without.if"))); @@ -1835,12 +1816,12 @@ public class JavacParser implements Parser { case CATCH: return toP(F.Exec(syntaxError("catch.without.try"))); case ASSERT: { - if (allowAsserts && S.token() == ASSERT) { - S.nextToken(); + if (allowAsserts && token.kind == ASSERT) { + nextToken(); JCExpression assertion = parseExpression(); JCExpression message = null; - if (S.token() == COLON) { - S.nextToken(); + if (token.kind == COLON) { + nextToken(); message = parseExpression(); } JCAssert t = to(F.at(pos).Assert(assertion, message)); @@ -1851,12 +1832,12 @@ public class JavacParser implements Parser { } case ENUM: default: - Name name = S.name(); + Token prevToken = token; JCExpression expr = parseExpression(); - if (S.token() == COLON && expr.getTag() == JCTree.IDENT) { - S.nextToken(); + if (token.kind == COLON && expr.getTag() == JCTree.IDENT) { + nextToken(); JCStatement stat = parseStatement(); - return F.at(pos).Labelled(name, stat); + return F.at(pos).Labelled(prevToken.name(), stat); } else { // This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon JCExpressionStatement stat = to(F.at(pos).Exec(checkExprStat(expr))); @@ -1869,7 +1850,7 @@ public class JavacParser implements Parser { /** CatchClause = CATCH "(" FormalParameter ")" Block */ protected JCCatch catchClause() { - int pos = S.pos(); + int pos = token.pos; accept(CATCH); accept(LPAREN); JCModifiers mods = optFinal(Flags.PARAMETER); @@ -1886,9 +1867,9 @@ public class JavacParser implements Parser { List catchTypes() { ListBuffer catchTypes = ListBuffer.lb(); catchTypes.add(parseType()); - while (S.token() == BAR) { + while (token.kind == BAR) { checkMulticatch(); - S.nextToken(); + nextToken(); catchTypes.add(qualident()); } return catchTypes.toList(); @@ -1901,33 +1882,33 @@ public class JavacParser implements Parser { List switchBlockStatementGroups() { ListBuffer cases = new ListBuffer(); while (true) { - int pos = S.pos(); - switch (S.token()) { + int pos = token.pos; + switch (token.kind) { case CASE: { - S.nextToken(); + nextToken(); JCExpression pat = parseExpression(); accept(COLON); List stats = blockStatements(); JCCase c = F.at(pos).Case(pat, stats); if (stats.isEmpty()) - storeEnd(c, S.prevEndPos()); + storeEnd(c, S.prevToken().endPos); cases.append(c); break; } case DEFAULT: { - S.nextToken(); + nextToken(); accept(COLON); List stats = blockStatements(); JCCase c = F.at(pos).Case(null, stats); if (stats.isEmpty()) - storeEnd(c, S.prevEndPos()); + storeEnd(c, S.prevToken().endPos); cases.append(c); break; } case RBRACE: case EOF: return cases.toList(); default: - S.nextToken(); // to ensure progress + nextToken(); // to ensure progress syntaxError(pos, "expected3", CASE, DEFAULT, RBRACE); } @@ -1941,9 +1922,9 @@ public class JavacParser implements Parser { T stats) { // This Exec is a "StatementExpression"; it subsumes no terminating token stats.append(toP(F.at(pos).Exec(checkExprStat(first)))); - while (S.token() == COMMA) { - S.nextToken(); - pos = S.pos(); + while (token.kind == COMMA) { + nextToken(); + pos = token.pos; JCExpression t = parseExpression(); // This Exec is a "StatementExpression"; it subsumes no terminating token stats.append(toP(F.at(pos).Exec(checkExprStat(t)))); @@ -1956,13 +1937,13 @@ public class JavacParser implements Parser { */ List forInit() { ListBuffer stats = lb(); - int pos = S.pos(); - if (S.token() == FINAL || S.token() == MONKEYS_AT) { + int pos = token.pos; + if (token.kind == FINAL || token.kind == MONKEYS_AT) { return variableDeclarators(optFinal(0), parseType(), stats).toList(); } else { JCExpression t = term(EXPR | TYPE); if ((lastmode & TYPE) != 0 && - (S.token() == IDENTIFIER || S.token() == ASSERT || S.token() == ENUM)) + (token.kind == IDENTIFIER || token.kind == ASSERT || token.kind == ENUM)) return variableDeclarators(modifiersOpt(), t, stats).toList(); else return moreStatementExpressions(pos, t, stats).toList(); @@ -1972,7 +1953,7 @@ public class JavacParser implements Parser { /** ForUpdate = StatementExpression MoreStatementExpressions */ List forUpdate() { - return moreStatementExpressions(S.pos(), + return moreStatementExpressions(token.pos, parseExpression(), new ListBuffer()).toList(); } @@ -1980,11 +1961,11 @@ public class JavacParser implements Parser { /** AnnotationsOpt = { '@' Annotation } */ List annotationsOpt() { - if (S.token() != MONKEYS_AT) return List.nil(); // optimization + if (token.kind != MONKEYS_AT) return List.nil(); // optimization ListBuffer buf = new ListBuffer(); - while (S.token() == MONKEYS_AT) { - int pos = S.pos(); - S.nextToken(); + while (token.kind == MONKEYS_AT) { + int pos = token.pos; + nextToken(); buf.append(annotation(pos)); } return buf.toList(); @@ -2004,21 +1985,20 @@ public class JavacParser implements Parser { int pos; if (partial == null) { flags = 0; - pos = S.pos(); + pos = token.pos; } else { flags = partial.flags; annotations.appendList(partial.annotations); pos = partial.pos; } - if (S.deprecatedFlag()) { + if (token.deprecatedFlag) { flags |= Flags.DEPRECATED; - S.resetDeprecatedFlag(); } int lastPos = Position.NOPOS; loop: while (true) { long flag; - switch (S.token()) { + switch (token.kind) { case PRIVATE : flag = Flags.PRIVATE; break; case PROTECTED : flag = Flags.PROTECTED; break; case PUBLIC : flag = Flags.PUBLIC; break; @@ -2031,15 +2011,15 @@ public class JavacParser implements Parser { case SYNCHRONIZED: flag = Flags.SYNCHRONIZED; break; case STRICTFP : flag = Flags.STRICTFP; break; case MONKEYS_AT : flag = Flags.ANNOTATION; break; - case ERROR : flag = 0; S.nextToken(); break; + case ERROR : flag = 0; nextToken(); break; default: break loop; } - if ((flags & flag) != 0) error(S.pos(), "repeated.modifier"); - lastPos = S.pos(); - S.nextToken(); + if ((flags & flag) != 0) error(token.pos, "repeated.modifier"); + lastPos = token.pos; + nextToken(); if (flag == Flags.ANNOTATION) { checkAnnotations(); - if (S.token() != INTERFACE) { + if (token.kind != INTERFACE) { JCAnnotation ann = annotation(lastPos); // if first modifier is an annotation, set pos to annotation's. if (flags == 0 && annotations.isEmpty()) @@ -2051,7 +2031,7 @@ public class JavacParser implements Parser { } flags |= flag; } - switch (S.token()) { + switch (token.kind) { case ENUM: flags |= Flags.ENUM; break; case INTERFACE: flags |= Flags.INTERFACE; break; default: break; @@ -2064,7 +2044,7 @@ public class JavacParser implements Parser { JCModifiers mods = F.at(pos).Modifiers(flags, annotations.toList()); if (pos != Position.NOPOS) - storeEnd(mods, S.prevEndPos()); + storeEnd(mods, S.prevToken().endPos); return mods; } @@ -2077,22 +2057,22 @@ public class JavacParser implements Parser { JCTree ident = qualident(); List fieldValues = annotationFieldValuesOpt(); JCAnnotation ann = F.at(pos).Annotation(ident, fieldValues); - storeEnd(ann, S.prevEndPos()); + storeEnd(ann, S.prevToken().endPos); return ann; } List annotationFieldValuesOpt() { - return (S.token() == LPAREN) ? annotationFieldValues() : List.nil(); + return (token.kind == LPAREN) ? annotationFieldValues() : List.nil(); } /** AnnotationFieldValues = "(" [ AnnotationFieldValue { "," AnnotationFieldValue } ] ")" */ List annotationFieldValues() { accept(LPAREN); ListBuffer buf = new ListBuffer(); - if (S.token() != RPAREN) { + if (token.kind != RPAREN) { buf.append(annotationFieldValue()); - while (S.token() == COMMA) { - S.nextToken(); + while (token.kind == COMMA) { + nextToken(); buf.append(annotationFieldValue()); } } @@ -2104,11 +2084,11 @@ public class JavacParser implements Parser { * | Identifier "=" AnnotationValue */ JCExpression annotationFieldValue() { - if (S.token() == IDENTIFIER) { + if (token.kind == IDENTIFIER) { mode = EXPR; JCExpression t1 = term1(); - if (t1.getTag() == JCTree.IDENT && S.token() == EQ) { - int pos = S.pos(); + if (t1.getTag() == JCTree.IDENT && token.kind == EQ) { + int pos = token.pos; accept(EQ); JCExpression v = annotationValue(); return toP(F.at(pos).Assign(t1, v)); @@ -2125,20 +2105,20 @@ public class JavacParser implements Parser { */ JCExpression annotationValue() { int pos; - switch (S.token()) { + switch (token.kind) { case MONKEYS_AT: - pos = S.pos(); - S.nextToken(); + pos = token.pos; + nextToken(); return annotation(pos); case LBRACE: - pos = S.pos(); + pos = token.pos; accept(LBRACE); ListBuffer buf = new ListBuffer(); - if (S.token() != RBRACE) { + if (token.kind != RBRACE) { buf.append(annotationValue()); - while (S.token() == COMMA) { - S.nextToken(); - if (S.token() == RBRACE) break; + while (token.kind == COMMA) { + nextToken(); + if (token.kind == RBRACE) break; buf.append(annotationValue()); } } @@ -2156,7 +2136,7 @@ public class JavacParser implements Parser { JCExpression type, T vdefs) { - return variableDeclaratorsRest(S.pos(), mods, type, ident(), false, null, vdefs); + return variableDeclaratorsRest(token.pos, mods, type, ident(), false, null, vdefs); } /** VariableDeclaratorsRest = VariableDeclaratorRest { "," VariableDeclarator } @@ -2174,10 +2154,10 @@ public class JavacParser implements Parser { T vdefs) { vdefs.append(variableDeclaratorRest(pos, mods, type, name, reqInit, dc)); - while (S.token() == COMMA) { + while (token.kind == COMMA) { // All but last of multiple declarators subsume a comma - storeEnd((JCTree)vdefs.elems.last(), S.endPos()); - S.nextToken(); + storeEnd((JCTree)vdefs.elems.last(), token.endPos); + nextToken(); vdefs.append(variableDeclarator(mods, type, reqInit, dc)); } return vdefs; @@ -2187,7 +2167,7 @@ public class JavacParser implements Parser { * ConstantDeclarator = Ident ConstantDeclaratorRest */ JCVariableDecl variableDeclarator(JCModifiers mods, JCExpression type, boolean reqInit, String dc) { - return variableDeclaratorRest(S.pos(), mods, type, ident(), reqInit, dc); + return variableDeclaratorRest(token.pos, mods, type, ident(), reqInit, dc); } /** VariableDeclaratorRest = BracketsOpt ["=" VariableInitializer] @@ -2200,11 +2180,11 @@ public class JavacParser implements Parser { boolean reqInit, String dc) { type = bracketsOpt(type); JCExpression init = null; - if (S.token() == EQ) { - S.nextToken(); + if (token.kind == EQ) { + nextToken(); init = variableInitializer(); } - else if (reqInit) syntaxError(S.pos(), "expected", EQ); + else if (reqInit) syntaxError(token.pos, "expected", EQ); JCVariableDecl result = toP(F.at(pos).VarDef(mods, name, type, init)); attach(result, dc); @@ -2214,11 +2194,11 @@ public class JavacParser implements Parser { /** VariableDeclaratorId = Ident BracketsOpt */ JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type) { - int pos = S.pos(); + int pos = token.pos; Name name = ident(); if ((mods.flags & Flags.VARARGS) != 0 && - S.token() == LBRACKET) { - log.error(S.pos(), "varargs.and.old.array.syntax"); + token.kind == LBRACKET) { + log.error(token.pos, "varargs.and.old.array.syntax"); } type = bracketsOpt(type); return toP(F.at(pos).VarDef(mods, name, type, null)); @@ -2229,12 +2209,12 @@ public class JavacParser implements Parser { List resources() { ListBuffer defs = new ListBuffer(); defs.append(resource()); - while (S.token() == SEMI) { + while (token.kind == SEMI) { // All but last of multiple declarators must subsume a semicolon - storeEnd(defs.elems.last(), S.endPos()); - int semiColonPos = S.pos(); - S.nextToken(); - if (S.token() == RPAREN) { // Optional trailing semicolon + storeEnd(defs.elems.last(), token.endPos); + int semiColonPos = token.pos; + nextToken(); + if (token.kind == RPAREN) { // Optional trailing semicolon // after last resource break; } @@ -2248,7 +2228,7 @@ public class JavacParser implements Parser { protected JCTree resource() { JCModifiers optFinal = optFinal(Flags.FINAL); JCExpression type = parseType(); - int pos = S.pos(); + int pos = token.pos; Name ident = ident(); return variableDeclaratorRest(pos, optFinal, type, ident, true, null); } @@ -2256,54 +2236,61 @@ public class JavacParser implements Parser { /** CompilationUnit = [ { "@" Annotation } PACKAGE Qualident ";"] {ImportDeclaration} {TypeDeclaration} */ public JCTree.JCCompilationUnit parseCompilationUnit() { - int pos = S.pos(); + Token firstToken = token; JCExpression pid = null; - String dc = S.docComment(); JCModifiers mods = null; + boolean consumedToplevelDoc = false; + boolean seenImport = false; + boolean seenPackage = false; List packageAnnotations = List.nil(); - if (S.token() == MONKEYS_AT) + if (token.kind == MONKEYS_AT) mods = modifiersOpt(); - if (S.token() == PACKAGE) { + if (token.kind == PACKAGE) { + seenPackage = true; if (mods != null) { checkNoMods(mods.flags); packageAnnotations = mods.annotations; mods = null; } - S.nextToken(); + nextToken(); pid = qualident(); accept(SEMI); } ListBuffer defs = new ListBuffer(); boolean checkForImports = true; - while (S.token() != EOF) { - if (S.pos() <= errorEndPos) { + boolean firstTypeDecl = true; + while (token.kind != EOF) { + if (token.pos <= errorEndPos) { // error recovery skip(checkForImports, false, false, false); - if (S.token() == EOF) + if (token.kind == EOF) break; } - if (checkForImports && mods == null && S.token() == IMPORT) { + if (checkForImports && mods == null && token.kind == IMPORT) { + seenImport = true; defs.append(importDeclaration()); } else { - JCTree def = typeDeclaration(mods); - if (keepDocComments && dc != null && docComments.get(def) == dc) { - // If the first type declaration has consumed the first doc - // comment, then don't use it for the top level comment as well. - dc = null; + String docComment = token.docComment; + if (firstTypeDecl && !seenImport && !seenPackage) { + docComment = firstToken.docComment; + consumedToplevelDoc = true; } + JCTree def = typeDeclaration(mods, docComment); if (def instanceof JCExpressionStatement) def = ((JCExpressionStatement)def).expr; defs.append(def); if (def instanceof JCClassDecl) checkForImports = false; mods = null; + firstTypeDecl = false; } } - JCTree.JCCompilationUnit toplevel = F.at(pos).TopLevel(packageAnnotations, pid, defs.toList()); - attach(toplevel, dc); + JCTree.JCCompilationUnit toplevel = F.at(firstToken.pos).TopLevel(packageAnnotations, pid, defs.toList()); + if (!consumedToplevelDoc) + attach(toplevel, firstToken.docComment); if (defs.elems.isEmpty()) - storeEnd(toplevel, S.prevEndPos()); + storeEnd(toplevel, S.prevToken().endPos); if (keepDocComments) toplevel.docComments = docComments; if (keepLineMap) @@ -2314,26 +2301,26 @@ public class JavacParser implements Parser { /** ImportDeclaration = IMPORT [ STATIC ] Ident { "." Ident } [ "." "*" ] ";" */ JCTree importDeclaration() { - int pos = S.pos(); - S.nextToken(); + int pos = token.pos; + nextToken(); boolean importStatic = false; - if (S.token() == STATIC) { + if (token.kind == STATIC) { checkStaticImports(); importStatic = true; - S.nextToken(); + nextToken(); } - JCExpression pid = toP(F.at(S.pos()).Ident(ident())); + JCExpression pid = toP(F.at(token.pos).Ident(ident())); do { - int pos1 = S.pos(); + int pos1 = token.pos; accept(DOT); - if (S.token() == STAR) { + if (token.kind == STAR) { pid = to(F.at(pos1).Select(pid, names.asterisk)); - S.nextToken(); + nextToken(); break; } else { pid = toP(F.at(pos1).Select(pid, ident())); } - } while (S.token() == DOT); + } while (token.kind == DOT); accept(SEMI); return toP(F.at(pos).Import(pid, importStatic)); } @@ -2341,14 +2328,13 @@ public class JavacParser implements Parser { /** TypeDeclaration = ClassOrInterfaceOrEnumDeclaration * | ";" */ - JCTree typeDeclaration(JCModifiers mods) { - int pos = S.pos(); - if (mods == null && S.token() == SEMI) { - S.nextToken(); + JCTree typeDeclaration(JCModifiers mods, String docComment) { + int pos = token.pos; + if (mods == null && token.kind == SEMI) { + nextToken(); return toP(F.at(pos).Skip()); } else { - String dc = S.docComment(); - return classOrInterfaceOrEnumDeclaration(modifiersOpt(mods), dc); + return classOrInterfaceOrEnumDeclaration(modifiersOpt(mods), docComment); } } @@ -2358,19 +2344,19 @@ public class JavacParser implements Parser { * @param dc The documentation comment for the class, or null. */ JCStatement classOrInterfaceOrEnumDeclaration(JCModifiers mods, String dc) { - if (S.token() == CLASS) { + if (token.kind == CLASS) { return classDeclaration(mods, dc); - } else if (S.token() == INTERFACE) { + } else if (token.kind == INTERFACE) { return interfaceDeclaration(mods, dc); } else if (allowEnums) { - if (S.token() == ENUM) { + if (token.kind == ENUM) { return enumDeclaration(mods, dc); } else { - int pos = S.pos(); + int pos = token.pos; List errs; - if (S.token() == IDENTIFIER) { + if (token.kind == IDENTIFIER) { errs = List.of(mods, toP(F.at(pos).Ident(ident()))); - setErrorEndPos(S.pos()); + setErrorEndPos(token.pos); } else { errs = List.of(mods); } @@ -2378,16 +2364,16 @@ public class JavacParser implements Parser { CLASS, INTERFACE, ENUM))); } } else { - if (S.token() == ENUM) { - error(S.pos(), "enums.not.supported.in.source", source.name); + if (token.kind == ENUM) { + error(token.pos, "enums.not.supported.in.source", source.name); allowEnums = true; return enumDeclaration(mods, dc); } - int pos = S.pos(); + int pos = token.pos; List errs; - if (S.token() == IDENTIFIER) { + if (token.kind == IDENTIFIER) { errs = List.of(mods, toP(F.at(pos).Ident(ident()))); - setErrorEndPos(S.pos()); + setErrorEndPos(token.pos); } else { errs = List.of(mods); } @@ -2402,20 +2388,20 @@ public class JavacParser implements Parser { * @param dc The documentation comment for the class, or null. */ JCClassDecl classDeclaration(JCModifiers mods, String dc) { - int pos = S.pos(); + int pos = token.pos; accept(CLASS); Name name = ident(); List typarams = typeParametersOpt(); JCExpression extending = null; - if (S.token() == EXTENDS) { - S.nextToken(); + if (token.kind == EXTENDS) { + nextToken(); extending = parseType(); } List implementing = List.nil(); - if (S.token() == IMPLEMENTS) { - S.nextToken(); + if (token.kind == IMPLEMENTS) { + nextToken(); implementing = typeList(); } List defs = classOrInterfaceBody(name, false); @@ -2431,15 +2417,15 @@ public class JavacParser implements Parser { * @param dc The documentation comment for the interface, or null. */ JCClassDecl interfaceDeclaration(JCModifiers mods, String dc) { - int pos = S.pos(); + int pos = token.pos; accept(INTERFACE); Name name = ident(); List typarams = typeParametersOpt(); List extending = List.nil(); - if (S.token() == EXTENDS) { - S.nextToken(); + if (token.kind == EXTENDS) { + nextToken(); extending = typeList(); } List defs = classOrInterfaceBody(name, true); @@ -2454,13 +2440,13 @@ public class JavacParser implements Parser { * @param dc The documentation comment for the enum, or null. */ JCClassDecl enumDeclaration(JCModifiers mods, String dc) { - int pos = S.pos(); + int pos = token.pos; accept(ENUM); Name name = ident(); List implementing = List.nil(); - if (S.token() == IMPLEMENTS) { - S.nextToken(); + if (token.kind == IMPLEMENTS) { + nextToken(); implementing = typeList(); } @@ -2479,27 +2465,27 @@ public class JavacParser implements Parser { List enumBody(Name enumName) { accept(LBRACE); ListBuffer defs = new ListBuffer(); - if (S.token() == COMMA) { - S.nextToken(); - } else if (S.token() != RBRACE && S.token() != SEMI) { + if (token.kind == COMMA) { + nextToken(); + } else if (token.kind != RBRACE && token.kind != SEMI) { defs.append(enumeratorDeclaration(enumName)); - while (S.token() == COMMA) { - S.nextToken(); - if (S.token() == RBRACE || S.token() == SEMI) break; + while (token.kind == COMMA) { + nextToken(); + if (token.kind == RBRACE || token.kind == SEMI) break; defs.append(enumeratorDeclaration(enumName)); } - if (S.token() != SEMI && S.token() != RBRACE) { - defs.append(syntaxError(S.pos(), "expected3", + if (token.kind != SEMI && token.kind != RBRACE) { + defs.append(syntaxError(token.pos, "expected3", COMMA, RBRACE, SEMI)); - S.nextToken(); + nextToken(); } } - if (S.token() == SEMI) { - S.nextToken(); - while (S.token() != RBRACE && S.token() != EOF) { + if (token.kind == SEMI) { + nextToken(); + while (token.kind != RBRACE && token.kind != EOF) { defs.appendList(classOrInterfaceBodyDeclaration(enumName, false)); - if (S.pos() <= errorEndPos) { + if (token.pos <= errorEndPos) { // error recovery skip(false, true, true, false); } @@ -2512,23 +2498,22 @@ public class JavacParser implements Parser { /** EnumeratorDeclaration = AnnotationsOpt [TypeArguments] IDENTIFIER [ Arguments ] [ "{" ClassBody "}" ] */ JCTree enumeratorDeclaration(Name enumName) { - String dc = S.docComment(); + String dc = token.docComment; int flags = Flags.PUBLIC|Flags.STATIC|Flags.FINAL|Flags.ENUM; - if (S.deprecatedFlag()) { + if (token.deprecatedFlag) { flags |= Flags.DEPRECATED; - S.resetDeprecatedFlag(); } - int pos = S.pos(); + int pos = token.pos; List annotations = annotationsOpt(); JCModifiers mods = F.at(annotations.isEmpty() ? Position.NOPOS : pos).Modifiers(flags, annotations); List typeArgs = typeArgumentsOpt(); - int identPos = S.pos(); + int identPos = token.pos; Name name = ident(); - int createPos = S.pos(); - List args = (S.token() == LPAREN) + int createPos = token.pos; + List args = (token.kind == LPAREN) ? arguments() : List.nil(); JCClassDecl body = null; - if (S.token() == LBRACE) { + if (token.kind == LBRACE) { JCModifiers mods1 = F.at(Position.NOPOS).Modifiers(Flags.ENUM | Flags.STATIC); List defs = classOrInterfaceBody(names.empty, false); body = toP(F.at(identPos).AnonymousClassDef(mods1, defs)); @@ -2538,7 +2523,7 @@ public class JavacParser implements Parser { JCIdent ident = F.at(identPos).Ident(enumName); JCNewClass create = F.at(createPos).NewClass(null, typeArgs, ident, args, body); if (createPos != identPos) - storeEnd(create, S.prevEndPos()); + storeEnd(create, S.prevToken().endPos); ident = F.at(identPos).Ident(enumName); JCTree result = toP(F.at(pos).VarDef(mods, name, ident, create)); attach(result, dc); @@ -2550,8 +2535,8 @@ public class JavacParser implements Parser { List typeList() { ListBuffer ts = new ListBuffer(); ts.append(parseType()); - while (S.token() == COMMA) { - S.nextToken(); + while (token.kind == COMMA) { + nextToken(); ts.append(parseType()); } return ts.toList(); @@ -2562,16 +2547,16 @@ public class JavacParser implements Parser { */ List classOrInterfaceBody(Name className, boolean isInterface) { accept(LBRACE); - if (S.pos() <= errorEndPos) { + if (token.pos <= errorEndPos) { // error recovery skip(false, true, false, false); - if (S.token() == LBRACE) - S.nextToken(); + if (token.kind == LBRACE) + nextToken(); } ListBuffer defs = new ListBuffer(); - while (S.token() != RBRACE && S.token() != EOF) { + while (token.kind != RBRACE && token.kind != EOF) { defs.appendList(classOrInterfaceBodyDeclaration(className, isInterface)); - if (S.pos() <= errorEndPos) { + if (token.pos <= errorEndPos) { // error recovery skip(false, true, true, false); } @@ -2598,23 +2583,23 @@ public class JavacParser implements Parser { * ( ConstantDeclaratorsRest | InterfaceMethodDeclaratorRest ";" ) */ protected List classOrInterfaceBodyDeclaration(Name className, boolean isInterface) { - if (S.token() == SEMI) { - S.nextToken(); + if (token.kind == SEMI) { + nextToken(); return List.nil(); } else { - String dc = S.docComment(); - int pos = S.pos(); + String dc = token.docComment; + int pos = token.pos; JCModifiers mods = modifiersOpt(); - if (S.token() == CLASS || - S.token() == INTERFACE || - allowEnums && S.token() == ENUM) { + if (token.kind == CLASS || + token.kind == INTERFACE || + allowEnums && token.kind == ENUM) { return List.of(classOrInterfaceOrEnumDeclaration(mods, dc)); - } else if (S.token() == LBRACE && !isInterface && + } else if (token.kind == LBRACE && !isInterface && (mods.flags & Flags.StandardFlags & ~Flags.STATIC) == 0 && mods.annotations.isEmpty()) { return List.of(block(pos, mods.flags)); } else { - pos = S.pos(); + pos = token.pos; List typarams = typeParametersOpt(); // if there are type parameters but no modifiers, save the start // position of the method in the modifiers. @@ -2622,26 +2607,26 @@ public class JavacParser implements Parser { mods.pos = pos; storeEnd(mods, pos); } - Name name = S.name(); - pos = S.pos(); + Token tk = token; + pos = token.pos; JCExpression type; - boolean isVoid = S.token() == VOID; + boolean isVoid = token.kind == VOID; if (isVoid) { type = to(F.at(pos).TypeIdent(TypeTags.VOID)); - S.nextToken(); + nextToken(); } else { type = parseType(); } - if (S.token() == LPAREN && !isInterface && type.getTag() == JCTree.IDENT) { - if (isInterface || name != className) + if (token.kind == LPAREN && !isInterface && type.getTag() == JCTree.IDENT) { + if (isInterface || tk.name() != className) error(pos, "invalid.meth.decl.ret.type.req"); return List.of(methodDeclaratorRest( pos, mods, null, names.init, typarams, isInterface, true, dc)); } else { - pos = S.pos(); - name = ident(); - if (S.token() == LPAREN) { + pos = token.pos; + Name name = ident(); + if (token.kind == LPAREN) { return List.of(methodDeclaratorRest( pos, mods, type, name, typarams, isInterface, isVoid, dc)); @@ -2649,16 +2634,16 @@ public class JavacParser implements Parser { List defs = variableDeclaratorsRest(pos, mods, type, name, isInterface, dc, new ListBuffer()).toList(); - storeEnd(defs.last(), S.endPos()); + storeEnd(defs.last(), token.endPos); accept(SEMI); return defs; } else { - pos = S.pos(); + pos = token.pos; List err = isVoid ? List.of(toP(F.at(pos).MethodDef(mods, name, type, typarams, List.nil(), List.nil(), null, null))) : null; - return List.of(syntaxError(S.pos(), err, "expected", LPAREN)); + return List.of(syntaxError(token.pos, err, "expected", LPAREN)); } } } @@ -2686,27 +2671,27 @@ public class JavacParser implements Parser { List params = formalParameters(); if (!isVoid) type = bracketsOpt(type); List thrown = List.nil(); - if (S.token() == THROWS) { - S.nextToken(); + if (token.kind == THROWS) { + nextToken(); thrown = qualidentList(); } JCBlock body = null; JCExpression defaultValue; - if (S.token() == LBRACE) { + if (token.kind == LBRACE) { body = block(); defaultValue = null; } else { - if (S.token() == DEFAULT) { + if (token.kind == DEFAULT) { accept(DEFAULT); defaultValue = annotationValue(); } else { defaultValue = null; } accept(SEMI); - if (S.pos() <= errorEndPos) { + if (token.pos <= errorEndPos) { // error recovery skip(false, true, false, false); - if (S.token() == LBRACE) { + if (token.kind == LBRACE) { body = block(); } } @@ -2725,8 +2710,8 @@ public class JavacParser implements Parser { List qualidentList() { ListBuffer ts = new ListBuffer(); ts.append(qualident()); - while (S.token() == COMMA) { - S.nextToken(); + while (token.kind == COMMA) { + nextToken(); ts.append(qualident()); } return ts.toList(); @@ -2735,13 +2720,13 @@ public class JavacParser implements Parser { /** TypeParametersOpt = ["<" TypeParameter {"," TypeParameter} ">"] */ List typeParametersOpt() { - if (S.token() == LT) { + if (token.kind == LT) { checkGenerics(); ListBuffer typarams = new ListBuffer(); - S.nextToken(); + nextToken(); typarams.append(typeParameter()); - while (S.token() == COMMA) { - S.nextToken(); + while (token.kind == COMMA) { + nextToken(); typarams.append(typeParameter()); } accept(GT); @@ -2756,14 +2741,14 @@ public class JavacParser implements Parser { * TypeVariable = Ident */ JCTypeParameter typeParameter() { - int pos = S.pos(); + int pos = token.pos; Name name = ident(); ListBuffer bounds = new ListBuffer(); - if (S.token() == EXTENDS) { - S.nextToken(); + if (token.kind == EXTENDS) { + nextToken(); bounds.append(parseType()); - while (S.token() == AMP) { - S.nextToken(); + while (token.kind == AMP) { + nextToken(); bounds.append(parseType()); } } @@ -2778,10 +2763,10 @@ public class JavacParser implements Parser { ListBuffer params = new ListBuffer(); JCVariableDecl lastParam = null; accept(LPAREN); - if (S.token() != RPAREN) { + if (token.kind != RPAREN) { params.append(lastParam = formalParameter()); - while ((lastParam.mods.flags & Flags.VARARGS) == 0 && S.token() == COMMA) { - S.nextToken(); + while ((lastParam.mods.flags & Flags.VARARGS) == 0 && token.kind == COMMA) { + nextToken(); params.append(lastParam = formalParameter()); } } @@ -2802,11 +2787,11 @@ public class JavacParser implements Parser { protected JCVariableDecl formalParameter() { JCModifiers mods = optFinal(Flags.PARAMETER); JCExpression type = parseType(); - if (S.token() == ELLIPSIS) { + if (token.kind == ELLIPSIS) { checkVarargs(); mods.flags |= Flags.VARARGS; - type = to(F.at(S.pos()).TypeArray(type)); - S.nextToken(); + type = to(F.at(token.pos).TypeArray(type)); + nextToken(); } return variableDeclaratorId(mods, type); } @@ -2849,7 +2834,7 @@ public class JavacParser implements Parser { /** Return precedence of operator represented by token, * -1 if token is not a binary operator. @see TreeInfo.opPrec */ - static int prec(Token token) { + static int prec(TokenKind token) { int oc = optag(token); return (oc >= 0) ? TreeInfo.opPrec(oc) : -1; } @@ -2869,7 +2854,7 @@ public class JavacParser implements Parser { /** Return operation tag of binary operator represented by token, * -1 if token is not a binary operator. */ - static int optag(Token token) { + static int optag(TokenKind token) { switch (token) { case BARBAR: return JCTree.OR; @@ -2941,7 +2926,7 @@ public class JavacParser implements Parser { /** Return operation tag of unary operator represented by token, * -1 if token is not a binary operator. */ - static int unoptag(Token token) { + static int unoptag(TokenKind token) { switch (token) { case PLUS: return JCTree.POS; @@ -2963,7 +2948,7 @@ public class JavacParser implements Parser { /** Return type tag of basic type represented by token, * -1 if token is not a basic type identifier. */ - static int typetag(Token token) { + static int typetag(TokenKind token) { switch (token) { case BYTE: return TypeTags.BYTE; @@ -2988,49 +2973,49 @@ public class JavacParser implements Parser { void checkGenerics() { if (!allowGenerics) { - error(S.pos(), "generics.not.supported.in.source", source.name); + error(token.pos, "generics.not.supported.in.source", source.name); allowGenerics = true; } } void checkVarargs() { if (!allowVarargs) { - error(S.pos(), "varargs.not.supported.in.source", source.name); + error(token.pos, "varargs.not.supported.in.source", source.name); allowVarargs = true; } } void checkForeach() { if (!allowForeach) { - error(S.pos(), "foreach.not.supported.in.source", source.name); + error(token.pos, "foreach.not.supported.in.source", source.name); allowForeach = true; } } void checkStaticImports() { if (!allowStaticImport) { - error(S.pos(), "static.import.not.supported.in.source", source.name); + error(token.pos, "static.import.not.supported.in.source", source.name); allowStaticImport = true; } } void checkAnnotations() { if (!allowAnnotations) { - error(S.pos(), "annotations.not.supported.in.source", source.name); + error(token.pos, "annotations.not.supported.in.source", source.name); allowAnnotations = true; } } void checkDiamond() { if (!allowDiamond) { - error(S.pos(), "diamond.not.supported.in.source", source.name); + error(token.pos, "diamond.not.supported.in.source", source.name); allowDiamond = true; } } void checkMulticatch() { if (!allowMulticatch) { - error(S.pos(), "multicatch.not.supported.in.source", source.name); + error(token.pos, "multicatch.not.supported.in.source", source.name); allowMulticatch = true; } } void checkTryWithResources() { if (!allowTWR) { - error(S.pos(), "try.with.resources.not.supported.in.source", source.name); + error(token.pos, "try.with.resources.not.supported.in.source", source.name); allowTWR = true; } } diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/DocCommentScanner.java b/langtools/src/share/classes/com/sun/tools/javac/parser/JavadocTokenizer.java similarity index 94% rename from langtools/src/share/classes/com/sun/tools/javac/parser/DocCommentScanner.java rename to langtools/src/share/classes/com/sun/tools/javac/parser/JavadocTokenizer.java index e6d687d4ca9..680485efddb 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/parser/DocCommentScanner.java +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavadocTokenizer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2011, 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 @@ -25,9 +25,12 @@ package com.sun.tools.javac.parser; +import com.sun.tools.javac.file.JavacFileManager; +import com.sun.tools.javac.parser.Tokens.Token; +import com.sun.tools.javac.util.*; + import java.nio.*; -import com.sun.tools.javac.util.*; import static com.sun.tools.javac.util.LayoutCharacters.*; /** An extension to the base lexical analyzer that captures @@ -40,26 +43,22 @@ import static com.sun.tools.javac.util.LayoutCharacters.*; * This code and its internal interfaces are subject to change or * deletion without notice. */ -public class DocCommentScanner extends Scanner { +public class JavadocTokenizer extends JavaTokenizer { /** Create a scanner from the input buffer. buffer must implement * array() and compact(), and remaining() must be less than limit(). */ - protected DocCommentScanner(ScannerFactory fac, CharBuffer buffer) { + protected JavadocTokenizer(ScannerFactory fac, CharBuffer buffer) { super(fac, buffer); } /** Create a scanner from the input array. The array must have at * least a single character of extra space. */ - protected DocCommentScanner(ScannerFactory fac, char[] input, int inputLength) { + protected JavadocTokenizer(ScannerFactory fac, char[] input, int inputLength) { super(fac, input, inputLength); } - /** Starting position of the comment in original source - */ - private int pos; - /** The comment input buffer, index of next chacter to be read, * index of one past last character in buffer. */ @@ -178,6 +177,14 @@ public class DocCommentScanner extends Scanner { } } + @Override + public Token readToken() { + docComment = null; + Token tk = super.readToken(); + tk.docComment = docComment; + return tk; + } + /** * Read next character in doc comment, skipping over double '\' characters. * If a double '\' is skipped, put in the buffer and update buffer count. @@ -196,32 +203,17 @@ public class DocCommentScanner extends Scanner { } } - /* Reset doc comment before reading each new token - */ - public void nextToken() { - docComment = null; - super.nextToken(); - } - - /** - * Returns the documentation string of the current token. - */ - public String docComment() { - return docComment; - } - /** * Process a doc comment and make the string content available. * Strips leading whitespace and stars. */ @SuppressWarnings("fallthrough") - protected void processComment(CommentStyle style) { + protected void processComment(int pos, int endPos, CommentStyle style) { if (style != CommentStyle.JAVADOC) { return; } - pos = pos(); - buf = getRawCharacters(pos, endPos()); + buf = reader.getRawCharacters(pos, endPos); buflen = buf.length; bp = 0; col = 0; @@ -414,7 +406,7 @@ public class DocCommentScanner extends Scanner { * * @return a LineMap */ public Position.LineMap getLineMap() { - char[] buf = getRawCharacters(); + char[] buf = reader.getRawCharacters(); return Position.makeLineMap(buf, buf.length, true); } } diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/Keywords.java b/langtools/src/share/classes/com/sun/tools/javac/parser/Keywords.java deleted file mode 100644 index 43386bf93f5..00000000000 --- a/langtools/src/share/classes/com/sun/tools/javac/parser/Keywords.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2002, 2010, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ - -package com.sun.tools.javac.parser; - -import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.Log; -import com.sun.tools.javac.util.Name; -import com.sun.tools.javac.util.Names; - -import static com.sun.tools.javac.parser.Token.*; - -/** - * Map from Name to Token and Token to String. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class Keywords { - public static final Context.Key keywordsKey = - new Context.Key(); - - public static Keywords instance(Context context) { - Keywords instance = context.get(keywordsKey); - if (instance == null) - instance = new Keywords(context); - return instance; - } - - private final Names names; - - protected Keywords(Context context) { - context.put(keywordsKey, this); - names = Names.instance(context); - - for (Token t : Token.values()) { - if (t.name != null) - enterKeyword(t.name, t); - else - tokenName[t.ordinal()] = null; - } - - key = new Token[maxKey+1]; - for (int i = 0; i <= maxKey; i++) key[i] = IDENTIFIER; - for (Token t : Token.values()) { - if (t.name != null) - key[tokenName[t.ordinal()].getIndex()] = t; - } - } - - - public Token key(Name name) { - return (name.getIndex() > maxKey) ? IDENTIFIER : key[name.getIndex()]; - } - - /** - * Keyword array. Maps name indices to Token. - */ - private final Token[] key; - - /** The number of the last entered keyword. - */ - private int maxKey = 0; - - /** The names of all tokens. - */ - private Name[] tokenName = new Name[Token.values().length]; - - private void enterKeyword(String s, Token token) { - Name n = names.fromString(s); - tokenName[token.ordinal()] = n; - if (n.getIndex() > maxKey) maxKey = n.getIndex(); - } -} diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/Lexer.java b/langtools/src/share/classes/com/sun/tools/javac/parser/Lexer.java index 90f6afe124d..57d7a985e63 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/parser/Lexer.java +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/Lexer.java @@ -25,7 +25,7 @@ package com.sun.tools.javac.parser; -import com.sun.tools.javac.util.*; +import com.sun.tools.javac.parser.Tokens.*; import com.sun.tools.javac.util.Position.LineMap; /** @@ -40,22 +40,26 @@ import com.sun.tools.javac.util.Position.LineMap; public interface Lexer { /** - * Has a @deprecated been encountered in last doc comment? - * This needs to be reset by client with resetDeprecatedFlag. + * Consume the next token. */ - boolean deprecatedFlag(); - - void resetDeprecatedFlag(); + void nextToken(); /** - * Returns the documentation string of the current token. + * Return current token. */ - String docComment(); + Token token(); /** - * Return the last character position of the current token. + * Return the last character position of the previous token. */ - int endPos(); + Token prevToken(); + + /** + * Splits the current token in two and return the first (splitted) token. + * For instance '<<<' is splitted into two tokens '<' and '<<' respectively, + * and the latter is returned. + */ + Token split(); /** * Return the position where a lexical error occurred; @@ -74,69 +78,4 @@ public interface Lexer { * @return a LineMap */ LineMap getLineMap(); - - /** - * Returns a copy of the input buffer, up to its inputLength. - * Unicode escape sequences are not translated. - */ - char[] getRawCharacters(); - - /** - * Returns a copy of a character array subset of the input buffer. - * The returned array begins at the beginIndex and - * extends to the character at index endIndex - 1. - * Thus the length of the substring is endIndex-beginIndex. - * This behavior is like - * String.substring(beginIndex, endIndex). - * Unicode escape sequences are not translated. - * - * @param beginIndex the beginning index, inclusive. - * @param endIndex the ending index, exclusive. - * @throws IndexOutOfBounds if either offset is outside of the - * array bounds - */ - char[] getRawCharacters(int beginIndex, int endIndex); - - /** - * Return the name of an identifier or token for the current token. - */ - Name name(); - - /** - * Read token. - */ - void nextToken(); - - /** - * Return the current token's position: a 0-based - * offset from beginning of the raw input stream - * (before unicode translation) - */ - int pos(); - - /** - * Return the last character position of the previous token. - */ - int prevEndPos(); - - /** - * Return the radix of a numeric literal token. - */ - int radix(); - - /** - * The value of a literal token, recorded as a string. - * For integers, leading 0x and 'l' suffixes are suppressed. - */ - String stringVal(); - - /** - * Return the current token, set by nextToken(). - */ - Token token(); - - /** - * Sets the current token. - */ - void token(Token token); } diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/ParserFactory.java b/langtools/src/share/classes/com/sun/tools/javac/parser/ParserFactory.java index 709bd5f1018..ed70d0b27df 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/parser/ParserFactory.java +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/ParserFactory.java @@ -55,7 +55,7 @@ public class ParserFactory { final TreeMaker F; final Log log; - final Keywords keywords; + final Tokens tokens; final Source source; final Names names; final Options options; @@ -67,7 +67,7 @@ public class ParserFactory { this.F = TreeMaker.instance(context); this.log = Log.instance(context); this.names = Names.instance(context); - this.keywords = Keywords.instance(context); + this.tokens = Tokens.instance(context); this.source = Source.instance(context); this.options = Options.instance(context); this.scannerFactory = ScannerFactory.instance(context); diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/Scanner.java b/langtools/src/share/classes/com/sun/tools/javac/parser/Scanner.java index f2d62db7fe8..41f50cb0110 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/parser/Scanner.java +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/Scanner.java @@ -27,13 +27,11 @@ package com.sun.tools.javac.parser; import java.nio.*; -import com.sun.tools.javac.code.Source; -import com.sun.tools.javac.file.JavacFileManager; import com.sun.tools.javac.util.*; +import com.sun.tools.javac.util.Position.LineMap; +import com.sun.tools.javac.parser.JavaTokenizer.*; - -import static com.sun.tools.javac.parser.Token.*; -import static com.sun.tools.javac.util.LayoutCharacters.*; +import static com.sun.tools.javac.parser.Tokens.*; /** The lexical analyzer maps an input stream consisting of * ASCII characters and Unicode escapes into a token sequence. @@ -45,119 +43,17 @@ import static com.sun.tools.javac.util.LayoutCharacters.*; */ public class Scanner implements Lexer { - private static boolean scannerDebug = false; - - /* Output variables; set by nextToken(): - */ + private Tokens tokens; /** The token, set by nextToken(). */ private Token token; - /** Allow hex floating-point literals. + /** The previous token, set by nextToken(). */ - private boolean allowHexFloats; - - /** Allow binary literals. - */ - private boolean allowBinaryLiterals; - - /** Allow underscores in literals. - */ - private boolean allowUnderscoresInLiterals; - - /** The source language setting. - */ - private Source source; - - /** The token's position, 0-based offset from beginning of text. - */ - private int pos; - - /** Character position just after the last character of the token. - */ - private int endPos; - - /** The last character position of the previous token. - */ - private int prevEndPos; - - /** The position where a lexical error occurred; - */ - private int errPos = Position.NOPOS; - - /** The name of an identifier or token: - */ - private Name name; - - /** The radix of a numeric literal token. - */ - private int radix; - - /** Has a @deprecated been encountered in last doc comment? - * this needs to be reset by client. - */ - protected boolean deprecatedFlag = false; - - /** A character buffer for literals. - */ - private char[] sbuf = new char[128]; - private int sp; - - /** The input buffer, index of next chacter to be read, - * index of one past last character in buffer. - */ - private char[] buf; - private int bp; - private int buflen; - private int eofPos; - - /** The current character. - */ - private char ch; - - /** The buffer index of the last converted unicode character - */ - private int unicodeConversionBp = -1; - - /** The log to be used for error reporting. - */ - private final Log log; - - /** The name table. */ - private final Names names; - - /** The keyword table. */ - private final Keywords keywords; - - /** Common code for constructors. */ - private Scanner(ScannerFactory fac) { - log = fac.log; - names = fac.names; - keywords = fac.keywords; - source = fac.source; - allowBinaryLiterals = source.allowBinaryLiterals(); - allowHexFloats = source.allowHexFloats(); - allowUnderscoresInLiterals = source.allowUnderscoresInLiterals(); - } - - private static final boolean hexFloatsWork = hexFloatsWork(); - private static boolean hexFloatsWork() { - try { - Float.valueOf("0x1.0p1"); - return true; - } catch (NumberFormatException ex) { - return false; - } - } - - /** Create a scanner from the input buffer. buffer must implement - * array() and compact(), and remaining() must be less than limit(). - */ - protected Scanner(ScannerFactory fac, CharBuffer buffer) { - this(fac, JavacFileManager.toArray(buffer), buffer.limit()); - } + private Token prevToken; + private JavaTokenizer tokenizer; /** * Create a scanner from the input array. This method might * modify the array. To avoid copying the input array, ensure @@ -169,972 +65,49 @@ public class Scanner implements Lexer { * @param inputLength the size of the input. * Must be positive and less than or equal to input.length. */ - protected Scanner(ScannerFactory fac, char[] input, int inputLength) { - this(fac); - eofPos = inputLength; - if (inputLength == input.length) { - if (input.length > 0 && Character.isWhitespace(input[input.length - 1])) { - inputLength--; - } else { - char[] newInput = new char[inputLength + 1]; - System.arraycopy(input, 0, newInput, 0, input.length); - input = newInput; - } - } - buf = input; - buflen = inputLength; - buf[buflen] = EOI; - bp = -1; - scanChar(); + protected Scanner(ScannerFactory fac, CharBuffer buf) { + this(fac, new JavaTokenizer(fac, buf)); } - /** Report an error at the given position using the provided arguments. - */ - private void lexError(int pos, String key, Object... args) { - log.error(pos, key, args); - token = ERROR; - errPos = pos; + protected Scanner(ScannerFactory fac, char[] buf, int inputLength) { + this(fac, new JavaTokenizer(fac, buf, inputLength)); } - /** Report an error at the current token position using the provided - * arguments. - */ - private void lexError(String key, Object... args) { - lexError(pos, key, args); + protected Scanner(ScannerFactory fac, JavaTokenizer tokenizer) { + this.tokenizer = tokenizer; + tokens = fac.tokens; + token = prevToken = DUMMY; } - /** Convert an ASCII digit from its base (8, 10, or 16) - * to its value. - */ - private int digit(int base) { - char c = ch; - int result = Character.digit(c, base); - if (result >= 0 && c > 0x7f) { - lexError(pos+1, "illegal.nonascii.digit"); - ch = "0123456789abcdef".charAt(result); - } - return result; - } - - /** Convert unicode escape; bp points to initial '\' character - * (Spec 3.3). - */ - private void convertUnicode() { - if (ch == '\\' && unicodeConversionBp != bp) { - bp++; ch = buf[bp]; - if (ch == 'u') { - do { - bp++; ch = buf[bp]; - } while (ch == 'u'); - int limit = bp + 3; - if (limit < buflen) { - int d = digit(16); - int code = d; - while (bp < limit && d >= 0) { - bp++; ch = buf[bp]; - d = digit(16); - code = (code << 4) + d; - } - if (d >= 0) { - ch = (char)code; - unicodeConversionBp = bp; - return; - } - } - lexError(bp, "illegal.unicode.esc"); - } else { - bp--; - ch = '\\'; - } - } - } - - /** Read next character. - */ - private void scanChar() { - ch = buf[++bp]; - if (ch == '\\') { - convertUnicode(); - } - } - - /** Read next character in comment, skipping over double '\' characters. - */ - private void scanCommentChar() { - scanChar(); - if (ch == '\\') { - if (buf[bp+1] == '\\' && unicodeConversionBp != bp) { - bp++; - } else { - convertUnicode(); - } - } - } - - /** Append a character to sbuf. - */ - private void putChar(char ch) { - if (sp == sbuf.length) { - char[] newsbuf = new char[sbuf.length * 2]; - System.arraycopy(sbuf, 0, newsbuf, 0, sbuf.length); - sbuf = newsbuf; - } - sbuf[sp++] = ch; - } - - /** Read next character in character or string literal and copy into sbuf. - */ - private void scanLitChar() { - if (ch == '\\') { - if (buf[bp+1] == '\\' && unicodeConversionBp != bp) { - bp++; - putChar('\\'); - scanChar(); - } else { - scanChar(); - switch (ch) { - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - char leadch = ch; - int oct = digit(8); - scanChar(); - if ('0' <= ch && ch <= '7') { - oct = oct * 8 + digit(8); - scanChar(); - if (leadch <= '3' && '0' <= ch && ch <= '7') { - oct = oct * 8 + digit(8); - scanChar(); - } - } - putChar((char)oct); - break; - case 'b': - putChar('\b'); scanChar(); break; - case 't': - putChar('\t'); scanChar(); break; - case 'n': - putChar('\n'); scanChar(); break; - case 'f': - putChar('\f'); scanChar(); break; - case 'r': - putChar('\r'); scanChar(); break; - case '\'': - putChar('\''); scanChar(); break; - case '\"': - putChar('\"'); scanChar(); break; - case '\\': - putChar('\\'); scanChar(); break; - default: - lexError(bp, "illegal.esc.char"); - } - } - } else if (bp != buflen) { - putChar(ch); scanChar(); - } - } - - private void scanDigits(int digitRadix) { - char saveCh; - int savePos; - do { - if (ch != '_') { - putChar(ch); - } else { - if (!allowUnderscoresInLiterals) { - lexError("unsupported.underscore.lit", source.name); - allowUnderscoresInLiterals = true; - } - } - saveCh = ch; - savePos = bp; - scanChar(); - } while (digit(digitRadix) >= 0 || ch == '_'); - if (saveCh == '_') - lexError(savePos, "illegal.underscore"); - } - - /** Read fractional part of hexadecimal floating point number. - */ - private void scanHexExponentAndSuffix() { - if (ch == 'p' || ch == 'P') { - putChar(ch); - scanChar(); - skipIllegalUnderscores(); - if (ch == '+' || ch == '-') { - putChar(ch); - scanChar(); - } - skipIllegalUnderscores(); - if ('0' <= ch && ch <= '9') { - scanDigits(10); - if (!allowHexFloats) { - lexError("unsupported.fp.lit", source.name); - allowHexFloats = true; - } - else if (!hexFloatsWork) - lexError("unsupported.cross.fp.lit"); - } else - lexError("malformed.fp.lit"); - } else { - lexError("malformed.fp.lit"); - } - if (ch == 'f' || ch == 'F') { - putChar(ch); - scanChar(); - token = FLOATLITERAL; - } else { - if (ch == 'd' || ch == 'D') { - putChar(ch); - scanChar(); - } - token = DOUBLELITERAL; - } - } - - /** Read fractional part of floating point number. - */ - private void scanFraction() { - skipIllegalUnderscores(); - if ('0' <= ch && ch <= '9') { - scanDigits(10); - } - int sp1 = sp; - if (ch == 'e' || ch == 'E') { - putChar(ch); - scanChar(); - skipIllegalUnderscores(); - if (ch == '+' || ch == '-') { - putChar(ch); - scanChar(); - } - skipIllegalUnderscores(); - if ('0' <= ch && ch <= '9') { - scanDigits(10); - return; - } - lexError("malformed.fp.lit"); - sp = sp1; - } - } - - /** Read fractional part and 'd' or 'f' suffix of floating point number. - */ - private void scanFractionAndSuffix() { - this.radix = 10; - scanFraction(); - if (ch == 'f' || ch == 'F') { - putChar(ch); - scanChar(); - token = FLOATLITERAL; - } else { - if (ch == 'd' || ch == 'D') { - putChar(ch); - scanChar(); - } - token = DOUBLELITERAL; - } - } - - /** Read fractional part and 'd' or 'f' suffix of floating point number. - */ - private void scanHexFractionAndSuffix(boolean seendigit) { - this.radix = 16; - Assert.check(ch == '.'); - putChar(ch); - scanChar(); - skipIllegalUnderscores(); - if (digit(16) >= 0) { - seendigit = true; - scanDigits(16); - } - if (!seendigit) - lexError("invalid.hex.number"); - else - scanHexExponentAndSuffix(); - } - - private void skipIllegalUnderscores() { - if (ch == '_') { - lexError(bp, "illegal.underscore"); - while (ch == '_') - scanChar(); - } - } - - /** Read a number. - * @param radix The radix of the number; one of 2, j8, 10, 16. - */ - private void scanNumber(int radix) { - this.radix = radix; - // for octal, allow base-10 digit in case it's a float literal - int digitRadix = (radix == 8 ? 10 : radix); - boolean seendigit = false; - if (digit(digitRadix) >= 0) { - seendigit = true; - scanDigits(digitRadix); - } - if (radix == 16 && ch == '.') { - scanHexFractionAndSuffix(seendigit); - } else if (seendigit && radix == 16 && (ch == 'p' || ch == 'P')) { - scanHexExponentAndSuffix(); - } else if (digitRadix == 10 && ch == '.') { - putChar(ch); - scanChar(); - scanFractionAndSuffix(); - } else if (digitRadix == 10 && - (ch == 'e' || ch == 'E' || - ch == 'f' || ch == 'F' || - ch == 'd' || ch == 'D')) { - scanFractionAndSuffix(); - } else { - if (ch == 'l' || ch == 'L') { - scanChar(); - token = LONGLITERAL; - } else { - token = INTLITERAL; - } - } - } - - /** Read an identifier. - */ - private void scanIdent() { - boolean isJavaIdentifierPart; - char high; - do { - if (sp == sbuf.length) putChar(ch); else sbuf[sp++] = ch; - // optimization, was: putChar(ch); - - scanChar(); - switch (ch) { - case 'A': case 'B': case 'C': case 'D': case 'E': - case 'F': case 'G': case 'H': case 'I': case 'J': - case 'K': case 'L': case 'M': case 'N': case 'O': - case 'P': case 'Q': case 'R': case 'S': case 'T': - case 'U': case 'V': case 'W': case 'X': case 'Y': - case 'Z': - case 'a': case 'b': case 'c': case 'd': case 'e': - case 'f': case 'g': case 'h': case 'i': case 'j': - case 'k': case 'l': case 'm': case 'n': case 'o': - case 'p': case 'q': case 'r': case 's': case 't': - case 'u': case 'v': case 'w': case 'x': case 'y': - case 'z': - case '$': case '_': - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - case '\u0000': case '\u0001': case '\u0002': case '\u0003': - case '\u0004': case '\u0005': case '\u0006': case '\u0007': - case '\u0008': case '\u000E': case '\u000F': case '\u0010': - case '\u0011': case '\u0012': case '\u0013': case '\u0014': - case '\u0015': case '\u0016': case '\u0017': - case '\u0018': case '\u0019': case '\u001B': - case '\u007F': - break; - case '\u001A': // EOI is also a legal identifier part - if (bp >= buflen) { - name = names.fromChars(sbuf, 0, sp); - token = keywords.key(name); - return; - } - break; - default: - if (ch < '\u0080') { - // all ASCII range chars already handled, above - isJavaIdentifierPart = false; - } else { - high = scanSurrogates(); - if (high != 0) { - if (sp == sbuf.length) { - putChar(high); - } else { - sbuf[sp++] = high; - } - isJavaIdentifierPart = Character.isJavaIdentifierPart( - Character.toCodePoint(high, ch)); - } else { - isJavaIdentifierPart = Character.isJavaIdentifierPart(ch); - } - } - if (!isJavaIdentifierPart) { - name = names.fromChars(sbuf, 0, sp); - token = keywords.key(name); - return; - } - } - } while (true); - } - - /** Are surrogates supported? - */ - final static boolean surrogatesSupported = surrogatesSupported(); - private static boolean surrogatesSupported() { - try { - Character.isHighSurrogate('a'); - return true; - } catch (NoSuchMethodError ex) { - return false; - } - } - - /** Scan surrogate pairs. If 'ch' is a high surrogate and - * the next character is a low surrogate, then put the low - * surrogate in 'ch', and return the high surrogate. - * otherwise, just return 0. - */ - private char scanSurrogates() { - if (surrogatesSupported && Character.isHighSurrogate(ch)) { - char high = ch; - - scanChar(); - - if (Character.isLowSurrogate(ch)) { - return high; - } - - ch = high; - } - - return 0; - } - - /** Return true if ch can be part of an operator. - */ - private boolean isSpecial(char ch) { - switch (ch) { - case '!': case '%': case '&': case '*': case '?': - case '+': case '-': case ':': case '<': case '=': - case '>': case '^': case '|': case '~': - case '@': - return true; - default: - return false; - } - } - - /** Read longest possible sequence of special characters and convert - * to token. - */ - private void scanOperator() { - while (true) { - putChar(ch); - Name newname = names.fromChars(sbuf, 0, sp); - if (keywords.key(newname) == IDENTIFIER) { - sp--; - break; - } - name = newname; - token = keywords.key(newname); - scanChar(); - if (!isSpecial(ch)) break; - } - } - - /** - * Scan a documention comment; determine if a deprecated tag is present. - * Called once the initial /, * have been skipped, positioned at the second * - * (which is treated as the beginning of the first line). - * Stops positioned at the closing '/'. - */ - @SuppressWarnings("fallthrough") - private void scanDocComment() { - boolean deprecatedPrefix = false; - - forEachLine: - while (bp < buflen) { - - // Skip optional WhiteSpace at beginning of line - while (bp < buflen && (ch == ' ' || ch == '\t' || ch == FF)) { - scanCommentChar(); - } - - // Skip optional consecutive Stars - while (bp < buflen && ch == '*') { - scanCommentChar(); - if (ch == '/') { - return; - } - } - - // Skip optional WhiteSpace after Stars - while (bp < buflen && (ch == ' ' || ch == '\t' || ch == FF)) { - scanCommentChar(); - } - - deprecatedPrefix = false; - // At beginning of line in the JavaDoc sense. - if (bp < buflen && ch == '@' && !deprecatedFlag) { - scanCommentChar(); - if (bp < buflen && ch == 'd') { - scanCommentChar(); - if (bp < buflen && ch == 'e') { - scanCommentChar(); - if (bp < buflen && ch == 'p') { - scanCommentChar(); - if (bp < buflen && ch == 'r') { - scanCommentChar(); - if (bp < buflen && ch == 'e') { - scanCommentChar(); - if (bp < buflen && ch == 'c') { - scanCommentChar(); - if (bp < buflen && ch == 'a') { - scanCommentChar(); - if (bp < buflen && ch == 't') { - scanCommentChar(); - if (bp < buflen && ch == 'e') { - scanCommentChar(); - if (bp < buflen && ch == 'd') { - deprecatedPrefix = true; - scanCommentChar(); - }}}}}}}}}}} - if (deprecatedPrefix && bp < buflen) { - if (Character.isWhitespace(ch)) { - deprecatedFlag = true; - } else if (ch == '*') { - scanCommentChar(); - if (ch == '/') { - deprecatedFlag = true; - return; - } - } - } - - // Skip rest of line - while (bp < buflen) { - switch (ch) { - case '*': - scanCommentChar(); - if (ch == '/') { - return; - } - break; - case CR: // (Spec 3.4) - scanCommentChar(); - if (ch != LF) { - continue forEachLine; - } - /* fall through to LF case */ - case LF: // (Spec 3.4) - scanCommentChar(); - continue forEachLine; - default: - scanCommentChar(); - } - } // rest of line - } // forEachLine - return; - } - - /** The value of a literal token, recorded as a string. - * For integers, leading 0x and 'l' suffixes are suppressed. - */ - public String stringVal() { - return new String(sbuf, 0, sp); - } - - /** Read token. - */ - public void nextToken() { - - try { - prevEndPos = endPos; - sp = 0; - - while (true) { - pos = bp; - switch (ch) { - case ' ': // (Spec 3.6) - case '\t': // (Spec 3.6) - case FF: // (Spec 3.6) - do { - scanChar(); - } while (ch == ' ' || ch == '\t' || ch == FF); - endPos = bp; - processWhiteSpace(); - break; - case LF: // (Spec 3.4) - scanChar(); - endPos = bp; - processLineTerminator(); - break; - case CR: // (Spec 3.4) - scanChar(); - if (ch == LF) { - scanChar(); - } - endPos = bp; - processLineTerminator(); - break; - case 'A': case 'B': case 'C': case 'D': case 'E': - case 'F': case 'G': case 'H': case 'I': case 'J': - case 'K': case 'L': case 'M': case 'N': case 'O': - case 'P': case 'Q': case 'R': case 'S': case 'T': - case 'U': case 'V': case 'W': case 'X': case 'Y': - case 'Z': - case 'a': case 'b': case 'c': case 'd': case 'e': - case 'f': case 'g': case 'h': case 'i': case 'j': - case 'k': case 'l': case 'm': case 'n': case 'o': - case 'p': case 'q': case 'r': case 's': case 't': - case 'u': case 'v': case 'w': case 'x': case 'y': - case 'z': - case '$': case '_': - scanIdent(); - return; - case '0': - scanChar(); - if (ch == 'x' || ch == 'X') { - scanChar(); - skipIllegalUnderscores(); - if (ch == '.') { - scanHexFractionAndSuffix(false); - } else if (digit(16) < 0) { - lexError("invalid.hex.number"); - } else { - scanNumber(16); - } - } else if (ch == 'b' || ch == 'B') { - if (!allowBinaryLiterals) { - lexError("unsupported.binary.lit", source.name); - allowBinaryLiterals = true; - } - scanChar(); - skipIllegalUnderscores(); - if (digit(2) < 0) { - lexError("invalid.binary.number"); - } else { - scanNumber(2); - } - } else { - putChar('0'); - if (ch == '_') { - int savePos = bp; - do { - scanChar(); - } while (ch == '_'); - if (digit(10) < 0) { - lexError(savePos, "illegal.underscore"); - } - } - scanNumber(8); - } - return; - case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - scanNumber(10); - return; - case '.': - scanChar(); - if ('0' <= ch && ch <= '9') { - putChar('.'); - scanFractionAndSuffix(); - } else if (ch == '.') { - putChar('.'); putChar('.'); - scanChar(); - if (ch == '.') { - scanChar(); - putChar('.'); - token = ELLIPSIS; - } else { - lexError("malformed.fp.lit"); - } - } else { - token = DOT; - } - return; - case ',': - scanChar(); token = COMMA; return; - case ';': - scanChar(); token = SEMI; return; - case '(': - scanChar(); token = LPAREN; return; - case ')': - scanChar(); token = RPAREN; return; - case '[': - scanChar(); token = LBRACKET; return; - case ']': - scanChar(); token = RBRACKET; return; - case '{': - scanChar(); token = LBRACE; return; - case '}': - scanChar(); token = RBRACE; return; - case '/': - scanChar(); - if (ch == '/') { - do { - scanCommentChar(); - } while (ch != CR && ch != LF && bp < buflen); - if (bp < buflen) { - endPos = bp; - processComment(CommentStyle.LINE); - } - break; - } else if (ch == '*') { - scanChar(); - CommentStyle style; - if (ch == '*') { - style = CommentStyle.JAVADOC; - scanDocComment(); - } else { - style = CommentStyle.BLOCK; - while (bp < buflen) { - if (ch == '*') { - scanChar(); - if (ch == '/') break; - } else { - scanCommentChar(); - } - } - } - if (ch == '/') { - scanChar(); - endPos = bp; - processComment(style); - break; - } else { - lexError("unclosed.comment"); - return; - } - } else if (ch == '=') { - name = names.slashequals; - token = SLASHEQ; - scanChar(); - } else { - name = names.slash; - token = SLASH; - } - return; - case '\'': - scanChar(); - if (ch == '\'') { - lexError("empty.char.lit"); - } else { - if (ch == CR || ch == LF) - lexError(pos, "illegal.line.end.in.char.lit"); - scanLitChar(); - if (ch == '\'') { - scanChar(); - token = CHARLITERAL; - } else { - lexError(pos, "unclosed.char.lit"); - } - } - return; - case '\"': - scanChar(); - while (ch != '\"' && ch != CR && ch != LF && bp < buflen) - scanLitChar(); - if (ch == '\"') { - token = STRINGLITERAL; - scanChar(); - } else { - lexError(pos, "unclosed.str.lit"); - } - return; - default: - if (isSpecial(ch)) { - scanOperator(); - } else { - boolean isJavaIdentifierStart; - if (ch < '\u0080') { - // all ASCII range chars already handled, above - isJavaIdentifierStart = false; - } else { - char high = scanSurrogates(); - if (high != 0) { - if (sp == sbuf.length) { - putChar(high); - } else { - sbuf[sp++] = high; - } - - isJavaIdentifierStart = Character.isJavaIdentifierStart( - Character.toCodePoint(high, ch)); - } else { - isJavaIdentifierStart = Character.isJavaIdentifierStart(ch); - } - } - if (isJavaIdentifierStart) { - scanIdent(); - } else if (bp == buflen || ch == EOI && bp+1 == buflen) { // JLS 3.5 - token = EOF; - pos = bp = eofPos; - } else { - lexError("illegal.char", String.valueOf((int)ch)); - scanChar(); - } - } - return; - } - } - } finally { - endPos = bp; - if (scannerDebug) - System.out.println("nextToken(" + pos - + "," + endPos + ")=|" + - new String(getRawCharacters(pos, endPos)) - + "|"); - } - } - - /** Return the current token, set by nextToken(). - */ public Token token() { return token; } - /** Sets the current token. - * This method is primarily used to update the token stream when the - * parser is handling the end of nested type arguments such as - * {@code List>} and needs to disambiguate between - * repeated use of ">" and relation operators such as ">>" and ">>>". Noting - * that this does not handle arbitrary tokens containing Unicode escape - * sequences. - */ - public void token(Token token) { - pos += this.token.name.length() - token.name.length(); - prevEndPos = pos; - this.token = token; + public Token prevToken() { + return prevToken; } - /** Return the current token's position: a 0-based - * offset from beginning of the raw input stream - * (before unicode translation) - */ - public int pos() { - return pos; + public void nextToken() { + prevToken = token; + token = tokenizer.readToken(); } - /** Return the last character position of the current token. - */ - public int endPos() { - return endPos; + public Token split() { + Token[] splitTokens = token.split(tokens); + prevToken = splitTokens[0]; + token = splitTokens[1]; + return token; } - /** Return the last character position of the previous token. - */ - public int prevEndPos() { - return prevEndPos; + public LineMap getLineMap() { + return tokenizer.getLineMap(); } - /** Return the position where a lexical error occurred; - */ public int errPos() { - return errPos; + return tokenizer.errPos(); } - /** Set the position where a lexical error occurred; - */ public void errPos(int pos) { - errPos = pos; + tokenizer.errPos(pos); } - - /** Return the name of an identifier or token for the current token. - */ - public Name name() { - return name; - } - - /** Return the radix of a numeric literal token. - */ - public int radix() { - return radix; - } - - /** Has a @deprecated been encountered in last doc comment? - * This needs to be reset by client with resetDeprecatedFlag. - */ - public boolean deprecatedFlag() { - return deprecatedFlag; - } - - public void resetDeprecatedFlag() { - deprecatedFlag = false; - } - - /** - * Returns the documentation string of the current token. - */ - public String docComment() { - return null; - } - - /** - * Returns a copy of the input buffer, up to its inputLength. - * Unicode escape sequences are not translated. - */ - public char[] getRawCharacters() { - char[] chars = new char[buflen]; - System.arraycopy(buf, 0, chars, 0, buflen); - return chars; - } - - /** - * Returns a copy of a character array subset of the input buffer. - * The returned array begins at the beginIndex and - * extends to the character at index endIndex - 1. - * Thus the length of the substring is endIndex-beginIndex. - * This behavior is like - * String.substring(beginIndex, endIndex). - * Unicode escape sequences are not translated. - * - * @param beginIndex the beginning index, inclusive. - * @param endIndex the ending index, exclusive. - * @throws IndexOutOfBounds if either offset is outside of the - * array bounds - */ - public char[] getRawCharacters(int beginIndex, int endIndex) { - int length = endIndex - beginIndex; - char[] chars = new char[length]; - System.arraycopy(buf, beginIndex, chars, 0, length); - return chars; - } - - public enum CommentStyle { - LINE, - BLOCK, - JAVADOC, - } - - /** - * Called when a complete comment has been scanned. pos and endPos - * will mark the comment boundary. - */ - protected void processComment(CommentStyle style) { - if (scannerDebug) - System.out.println("processComment(" + pos - + "," + endPos + "," + style + ")=|" - + new String(getRawCharacters(pos, endPos)) - + "|"); - } - - /** - * Called when a complete whitespace run has been scanned. pos and endPos - * will mark the whitespace boundary. - */ - protected void processWhiteSpace() { - if (scannerDebug) - System.out.println("processWhitespace(" + pos - + "," + endPos + ")=|" + - new String(getRawCharacters(pos, endPos)) - + "|"); - } - - /** - * Called when a line terminator has been processed. - */ - protected void processLineTerminator() { - if (scannerDebug) - System.out.println("processTerminator(" + pos - + "," + endPos + ")=|" + - new String(getRawCharacters(pos, endPos)) - + "|"); - } - - /** Build a map for translating between line numbers and - * positions in the input. - * - * @return a LineMap */ - public Position.LineMap getLineMap() { - return Position.makeLineMap(buf, buflen, false); - } - } diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/ScannerFactory.java b/langtools/src/share/classes/com/sun/tools/javac/parser/ScannerFactory.java index 86c9bb2b11c..d03d77b62cd 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/parser/ScannerFactory.java +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/ScannerFactory.java @@ -57,7 +57,7 @@ public class ScannerFactory { final Log log; final Names names; final Source source; - final Keywords keywords; + final Tokens tokens; /** Create a new scanner factory. */ protected ScannerFactory(Context context) { @@ -65,14 +65,14 @@ public class ScannerFactory { this.log = Log.instance(context); this.names = Names.instance(context); this.source = Source.instance(context); - this.keywords = Keywords.instance(context); + this.tokens = Tokens.instance(context); } public Scanner newScanner(CharSequence input, boolean keepDocComments) { if (input instanceof CharBuffer) { CharBuffer buf = (CharBuffer) input; if (keepDocComments) - return new DocCommentScanner(this, buf); + return new Scanner(this, new JavadocTokenizer(this, buf)); else return new Scanner(this, buf); } else { @@ -83,7 +83,7 @@ public class ScannerFactory { public Scanner newScanner(char[] input, int inputLength, boolean keepDocComments) { if (keepDocComments) - return new DocCommentScanner(this, input, inputLength); + return new Scanner(this, new JavadocTokenizer(this, input, inputLength)); else return new Scanner(this, input, inputLength); } diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/Token.java b/langtools/src/share/classes/com/sun/tools/javac/parser/Token.java deleted file mode 100644 index 8fec6f8aeb7..00000000000 --- a/langtools/src/share/classes/com/sun/tools/javac/parser/Token.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (c) 1999, 2008, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ - -package com.sun.tools.javac.parser; - -import java.util.Locale; - -import com.sun.tools.javac.api.Formattable; -import com.sun.tools.javac.api.Messages; - -/** An interface that defines codes for Java source tokens - * returned from lexical analysis. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public enum Token implements Formattable { - EOF, - ERROR, - IDENTIFIER, - ABSTRACT("abstract"), - ASSERT("assert"), - BOOLEAN("boolean"), - BREAK("break"), - BYTE("byte"), - CASE("case"), - CATCH("catch"), - CHAR("char"), - CLASS("class"), - CONST("const"), - CONTINUE("continue"), - DEFAULT("default"), - DO("do"), - DOUBLE("double"), - ELSE("else"), - ENUM("enum"), - EXTENDS("extends"), - FINAL("final"), - FINALLY("finally"), - FLOAT("float"), - FOR("for"), - GOTO("goto"), - IF("if"), - IMPLEMENTS("implements"), - IMPORT("import"), - INSTANCEOF("instanceof"), - INT("int"), - INTERFACE("interface"), - LONG("long"), - NATIVE("native"), - NEW("new"), - PACKAGE("package"), - PRIVATE("private"), - PROTECTED("protected"), - PUBLIC("public"), - RETURN("return"), - SHORT("short"), - STATIC("static"), - STRICTFP("strictfp"), - SUPER("super"), - SWITCH("switch"), - SYNCHRONIZED("synchronized"), - THIS("this"), - THROW("throw"), - THROWS("throws"), - TRANSIENT("transient"), - TRY("try"), - VOID("void"), - VOLATILE("volatile"), - WHILE("while"), - INTLITERAL, - LONGLITERAL, - FLOATLITERAL, - DOUBLELITERAL, - CHARLITERAL, - STRINGLITERAL, - TRUE("true"), - FALSE("false"), - NULL("null"), - LPAREN("("), - RPAREN(")"), - LBRACE("{"), - RBRACE("}"), - LBRACKET("["), - RBRACKET("]"), - SEMI(";"), - COMMA(","), - DOT("."), - ELLIPSIS("..."), - EQ("="), - GT(">"), - LT("<"), - BANG("!"), - TILDE("~"), - QUES("?"), - COLON(":"), - EQEQ("=="), - LTEQ("<="), - GTEQ(">="), - BANGEQ("!="), - AMPAMP("&&"), - BARBAR("||"), - PLUSPLUS("++"), - SUBSUB("--"), - PLUS("+"), - SUB("-"), - STAR("*"), - SLASH("/"), - AMP("&"), - BAR("|"), - CARET("^"), - PERCENT("%"), - LTLT("<<"), - GTGT(">>"), - GTGTGT(">>>"), - PLUSEQ("+="), - SUBEQ("-="), - STAREQ("*="), - SLASHEQ("/="), - AMPEQ("&="), - BAREQ("|="), - CARETEQ("^="), - PERCENTEQ("%="), - LTLTEQ("<<="), - GTGTEQ(">>="), - GTGTGTEQ(">>>="), - MONKEYS_AT("@"), - CUSTOM; - - Token() { - this(null); - } - Token(String name) { - this.name = name; - } - - public final String name; - - public String toString() { - switch (this) { - case IDENTIFIER: - return "token.identifier"; - case CHARLITERAL: - return "token.character"; - case STRINGLITERAL: - return "token.string"; - case INTLITERAL: - return "token.integer"; - case LONGLITERAL: - return "token.long-integer"; - case FLOATLITERAL: - return "token.float"; - case DOUBLELITERAL: - return "token.double"; - case ERROR: - return "token.bad-symbol"; - case EOF: - return "token.end-of-input"; - case DOT: case COMMA: case SEMI: case LPAREN: case RPAREN: - case LBRACKET: case RBRACKET: case LBRACE: case RBRACE: - return "'" + name + "'"; - default: - return name; - } - } - - public String getKind() { - return "Token"; - } - - public String toString(Locale locale, Messages messages) { - return name != null ? toString() : messages.getLocalizedString(locale, "compiler.misc." + toString()); - } -} diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/Tokens.java b/langtools/src/share/classes/com/sun/tools/javac/parser/Tokens.java new file mode 100644 index 00000000000..934dfb90520 --- /dev/null +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/Tokens.java @@ -0,0 +1,423 @@ +/* + * Copyright (c) 1999, 2011, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package com.sun.tools.javac.parser; + +import java.util.Locale; + +import com.sun.tools.javac.api.Formattable; +import com.sun.tools.javac.api.Messages; +import com.sun.tools.javac.parser.Tokens.Token.Tag; +import com.sun.tools.javac.util.Name; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.Names; + +/** A class that defines codes/utilities for Java source tokens + * returned from lexical analysis. + * + *

This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + */ +public class Tokens { + + private final Names names; + + /** + * Keyword array. Maps name indices to Token. + */ + private final TokenKind[] key; + + /** The number of the last entered keyword. + */ + private int maxKey = 0; + + /** The names of all tokens. + */ + private Name[] tokenName = new Name[TokenKind.values().length]; + + public static final Context.Key tokensKey = + new Context.Key(); + + public static Tokens instance(Context context) { + Tokens instance = context.get(tokensKey); + if (instance == null) + instance = new Tokens(context); + return instance; + } + + protected Tokens(Context context) { + context.put(tokensKey, this); + names = Names.instance(context); + + for (TokenKind t : TokenKind.values()) { + if (t.name != null) + enterKeyword(t.name, t); + else + tokenName[t.ordinal()] = null; + } + + key = new TokenKind[maxKey+1]; + for (int i = 0; i <= maxKey; i++) key[i] = TokenKind.IDENTIFIER; + for (TokenKind t : TokenKind.values()) { + if (t.name != null) + key[tokenName[t.ordinal()].getIndex()] = t; + } + } + + private void enterKeyword(String s, TokenKind token) { + Name n = names.fromString(s); + tokenName[token.ordinal()] = n; + if (n.getIndex() > maxKey) maxKey = n.getIndex(); + } + + /** + * Create a new token given a name; if the name corresponds to a token name, + * a new token of the corresponding kind is returned; otherwise, an + * identifier token is returned. + */ + TokenKind lookupKind(Name name) { + return (name.getIndex() > maxKey) ? TokenKind.IDENTIFIER : key[name.getIndex()]; + } + + TokenKind lookupKind(String name) { + return lookupKind(names.fromString(name)); + } + + /** + * This enum defines all tokens used by the javac scanner. A token is + * optionally associated with a name. + */ + public enum TokenKind implements Formattable { + EOF(), + ERROR(), + IDENTIFIER(Tag.NAMED), + ABSTRACT("abstract"), + ASSERT("assert", Tag.NAMED), + BOOLEAN("boolean", Tag.NAMED), + BREAK("break"), + BYTE("byte", Tag.NAMED), + CASE("case"), + CATCH("catch"), + CHAR("char", Tag.NAMED), + CLASS("class"), + CONST("const"), + CONTINUE("continue"), + DEFAULT("default"), + DO("do"), + DOUBLE("double", Tag.NAMED), + ELSE("else"), + ENUM("enum", Tag.NAMED), + EXTENDS("extends"), + FINAL("final"), + FINALLY("finally"), + FLOAT("float", Tag.NAMED), + FOR("for"), + GOTO("goto"), + IF("if"), + IMPLEMENTS("implements"), + IMPORT("import"), + INSTANCEOF("instanceof"), + INT("int", Tag.NAMED), + INTERFACE("interface"), + LONG("long", Tag.NAMED), + NATIVE("native"), + NEW("new"), + PACKAGE("package"), + PRIVATE("private"), + PROTECTED("protected"), + PUBLIC("public"), + RETURN("return"), + SHORT("short", Tag.NAMED), + STATIC("static"), + STRICTFP("strictfp"), + SUPER("super", Tag.NAMED), + SWITCH("switch"), + SYNCHRONIZED("synchronized"), + THIS("this", Tag.NAMED), + THROW("throw"), + THROWS("throws"), + TRANSIENT("transient"), + TRY("try"), + VOID("void", Tag.NAMED), + VOLATILE("volatile"), + WHILE("while"), + INTLITERAL(Tag.NUMERIC), + LONGLITERAL(Tag.NUMERIC), + FLOATLITERAL(Tag.NUMERIC), + DOUBLELITERAL(Tag.NUMERIC), + CHARLITERAL(Tag.NUMERIC), + STRINGLITERAL(Tag.STRING), + TRUE("true", Tag.NAMED), + FALSE("false", Tag.NAMED), + NULL("null", Tag.NAMED), + LPAREN("("), + RPAREN(")"), + LBRACE("{"), + RBRACE("}"), + LBRACKET("["), + RBRACKET("]"), + SEMI(";"), + COMMA(","), + DOT("."), + ELLIPSIS("..."), + EQ("="), + GT(">"), + LT("<"), + BANG("!"), + TILDE("~"), + QUES("?"), + COLON(":"), + EQEQ("=="), + LTEQ("<="), + GTEQ(">="), + BANGEQ("!="), + AMPAMP("&&"), + BARBAR("||"), + PLUSPLUS("++"), + SUBSUB("--"), + PLUS("+"), + SUB("-"), + STAR("*"), + SLASH("/"), + AMP("&"), + BAR("|"), + CARET("^"), + PERCENT("%"), + LTLT("<<"), + GTGT(">>"), + GTGTGT(">>>"), + PLUSEQ("+="), + SUBEQ("-="), + STAREQ("*="), + SLASHEQ("/="), + AMPEQ("&="), + BAREQ("|="), + CARETEQ("^="), + PERCENTEQ("%="), + LTLTEQ("<<="), + GTGTEQ(">>="), + GTGTGTEQ(">>>="), + MONKEYS_AT("@"), + CUSTOM; + + public final String name; + public final Tag tag; + + TokenKind() { + this(null, Tag.DEFAULT); + } + + TokenKind(String name) { + this(name, Tag.DEFAULT); + } + + TokenKind(Tag tag) { + this(null, tag); + } + + TokenKind(String name, Tag tag) { + this.name = name; + this.tag = tag; + } + + public String toString() { + switch (this) { + case IDENTIFIER: + return "token.identifier"; + case CHARLITERAL: + return "token.character"; + case STRINGLITERAL: + return "token.string"; + case INTLITERAL: + return "token.integer"; + case LONGLITERAL: + return "token.long-integer"; + case FLOATLITERAL: + return "token.float"; + case DOUBLELITERAL: + return "token.double"; + case ERROR: + return "token.bad-symbol"; + case EOF: + return "token.end-of-input"; + case DOT: case COMMA: case SEMI: case LPAREN: case RPAREN: + case LBRACKET: case RBRACKET: case LBRACE: case RBRACE: + return "'" + name + "'"; + default: + return name; + } + } + + public String getKind() { + return "Token"; + } + + public String toString(Locale locale, Messages messages) { + return name != null ? toString() : messages.getLocalizedString(locale, "compiler.misc." + toString()); + } + } + + /** + * This is the class representing a javac token. Each token has several fields + * that are set by the javac lexer (i.e. start/end position, string value, etc). + */ + public static class Token { + + /** tags constants **/ + enum Tag { + DEFAULT, + NAMED, + STRING, + NUMERIC; + } + + /** The token kind */ + public final TokenKind kind; + + /** The start position of this token */ + public final int pos; + + /** The end position of this token */ + public final int endPos; + + /** Is this token preceeded by a deprecated comment? */ + public final boolean deprecatedFlag; + + /** Is this token preceeded by a deprecated comment? */ + public String docComment; + + Token(TokenKind kind, int pos, int endPos, + boolean deprecatedFlag) { + this.kind = kind; + this.pos = pos; + this.endPos = endPos; + this.deprecatedFlag = deprecatedFlag; + checkKind(); + } + + Token[] split(Tokens tokens) { + if (kind.name.length() < 2 || kind.tag != Tag.DEFAULT) { + throw new AssertionError("Cant split" + kind); + } + + TokenKind t1 = tokens.lookupKind(kind.name.substring(0, 1)); + TokenKind t2 = tokens.lookupKind(kind.name.substring(1)); + + if (t1 == null || t2 == null) { + throw new AssertionError("Cant split - bad subtokens"); + } + return new Token[] { + new Token(t1, pos, pos + t1.name.length(), deprecatedFlag), + new Token(t2, pos + t1.name.length(), endPos, false) + }; + } + + protected void checkKind() { + if (kind.tag != Tag.DEFAULT) { + throw new AssertionError("Bad token kind - expected " + Tag.STRING); + } + } + + public Name name() { + throw new UnsupportedOperationException(); + } + + public String stringVal() { + throw new UnsupportedOperationException(); + } + + public int radix() { + throw new UnsupportedOperationException(); + } + } + + final static class NamedToken extends Token { + /** The name of this token */ + public final Name name; + + public NamedToken(TokenKind kind, int pos, int endPos, Name name, boolean deprecatedFlag) { + super(kind, pos, endPos, deprecatedFlag); + this.name = name; + } + + protected void checkKind() { + if (kind.tag != Tag.NAMED) { + throw new AssertionError("Bad token kind - expected " + Tag.NAMED); + } + } + + @Override + public Name name() { + return name; + } + } + + static class StringToken extends Token { + /** The string value of this token */ + public final String stringVal; + + public StringToken(TokenKind kind, int pos, int endPos, String stringVal, boolean deprecatedFlag) { + super(kind, pos, endPos, deprecatedFlag); + this.stringVal = stringVal; + } + + protected void checkKind() { + if (kind.tag != Tag.STRING) { + throw new AssertionError("Bad token kind - expected " + Tag.STRING); + } + } + + @Override + public String stringVal() { + return stringVal; + } + } + + final static class NumericToken extends StringToken { + /** The 'radix' value of this token */ + public final int radix; + + public NumericToken(TokenKind kind, int pos, int endPos, String stringVal, int radix, boolean deprecatedFlag) { + super(kind, pos, endPos, stringVal, deprecatedFlag); + this.radix = radix; + } + + protected void checkKind() { + if (kind.tag != Tag.NUMERIC) { + throw new AssertionError("Bad token kind - expected " + Tag.NUMERIC); + } + } + + @Override + public int radix() { + return radix; + } + } + + public static final Token DUMMY = + new Token(TokenKind.ERROR, 0, 0, false); +} diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/UnicodeReader.java b/langtools/src/share/classes/com/sun/tools/javac/parser/UnicodeReader.java new file mode 100644 index 00000000000..c5718c6fc47 --- /dev/null +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/UnicodeReader.java @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2011, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package com.sun.tools.javac.parser; + +import com.sun.tools.javac.file.JavacFileManager; +import java.nio.CharBuffer; +import com.sun.tools.javac.util.Log; +import static com.sun.tools.javac.util.LayoutCharacters.*; + +/** The char reader used by the javac lexer/tokenizer. Returns the sequence of + * characters contained in the input stream, handling unicode escape accordingly. + * Additionally, it provide features for saving chars into a buffer and to retrieve + * them at a later stage. + * + *

This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + */ +public class UnicodeReader { + + /** The input buffer, index of next character to be read, + * index of one past last character in buffer. + */ + protected char[] buf; + protected int bp; + protected final int buflen; + + /** The current character. + */ + protected char ch; + + /** The buffer index of the last converted unicode character + */ + protected int unicodeConversionBp = -1; + + protected Log log; + + /** + * Create a scanner from the input array. This method might + * modify the array. To avoid copying the input array, ensure + * that {@code inputLength < input.length} or + * {@code input[input.length -1]} is a white space character. + * + * @param fac the factory which created this Scanner + * @param input the input, might be modified + * @param inputLength the size of the input. + * Must be positive and less than or equal to input.length. + */ + protected UnicodeReader(ScannerFactory sf, CharBuffer buffer) { + this(sf, JavacFileManager.toArray(buffer), buffer.limit()); + } + + protected UnicodeReader(ScannerFactory sf, char[] input, int inputLength) { + log = sf.log; + if (inputLength == input.length) { + if (input.length > 0 && Character.isWhitespace(input[input.length - 1])) { + inputLength--; + } else { + char[] newInput = new char[inputLength + 1]; + System.arraycopy(input, 0, newInput, 0, input.length); + input = newInput; + } + } + buf = input; + buflen = inputLength; + buf[buflen] = EOI; + bp = -1; + scanChar(); + } + + /** Read next character. + */ + protected void scanChar() { + if (bp < buflen) { + ch = buf[++bp]; + if (ch == '\\') { + convertUnicode(); + } + } + } + + /** Convert unicode escape; bp points to initial '\' character + * (Spec 3.3). + */ + protected void convertUnicode() { + if (ch == '\\' && unicodeConversionBp != bp) { + bp++; ch = buf[bp]; + if (ch == 'u') { + do { + bp++; ch = buf[bp]; + } while (ch == 'u'); + int limit = bp + 3; + if (limit < buflen) { + int d = digit(bp, 16); + int code = d; + while (bp < limit && d >= 0) { + bp++; ch = buf[bp]; + d = digit(bp, 16); + code = (code << 4) + d; + } + if (d >= 0) { + ch = (char)code; + unicodeConversionBp = bp; + return; + } + } + log.error(bp, "illegal.unicode.esc"); + } else { + bp--; + ch = '\\'; + } + } + } + + /** Are surrogates supported? + */ + final static boolean surrogatesSupported = surrogatesSupported(); + private static boolean surrogatesSupported() { + try { + Character.isHighSurrogate('a'); + return true; + } catch (NoSuchMethodError ex) { + return false; + } + } + + /** Scan surrogate pairs. If 'ch' is a high surrogate and + * the next character is a low surrogate, then put the low + * surrogate in 'ch', and return the high surrogate. + * otherwise, just return 0. + */ + protected char scanSurrogates() { + if (surrogatesSupported && Character.isHighSurrogate(ch)) { + char high = ch; + + scanChar(); + + if (Character.isLowSurrogate(ch)) { + return high; + } + + ch = high; + } + + return 0; + } + + /** Convert an ASCII digit from its base (8, 10, or 16) + * to its value. + */ + protected int digit(int pos, int base) { + char c = ch; + int result = Character.digit(c, base); + if (result >= 0 && c > 0x7f) { + log.error(pos + 1, "illegal.nonascii.digit"); + ch = "0123456789abcdef".charAt(result); + } + return result; + } + + protected boolean isUnicode() { + return unicodeConversionBp == bp; + } + + protected void skipChar() { + bp++; + } + + protected char peekChar() { + return buf[bp + 1]; + } + + /** + * Returns a copy of the input buffer, up to its inputLength. + * Unicode escape sequences are not translated. + */ + public char[] getRawCharacters() { + char[] chars = new char[buflen]; + System.arraycopy(buf, 0, chars, 0, buflen); + return chars; + } + + /** + * Returns a copy of a character array subset of the input buffer. + * The returned array begins at the beginIndex and + * extends to the character at index endIndex - 1. + * Thus the length of the substring is endIndex-beginIndex. + * This behavior is like + * String.substring(beginIndex, endIndex). + * Unicode escape sequences are not translated. + * + * @param beginIndex the beginning index, inclusive. + * @param endIndex the ending index, exclusive. + * @throws IndexOutOfBounds if either offset is outside of the + * array bounds + */ + public char[] getRawCharacters(int beginIndex, int endIndex) { + int length = endIndex - beginIndex; + char[] chars = new char[length]; + System.arraycopy(buf, beginIndex, chars, 0, length); + return chars; + } +} diff --git a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java index e8040766280..ce16646eea1 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java +++ b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java @@ -1072,9 +1072,9 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea Assert.checkNonNull(names); next.put(Names.namesKey, names); - Keywords keywords = Keywords.instance(context); - Assert.checkNonNull(keywords); - next.put(Keywords.keywordsKey, keywords); + Tokens tokens = Tokens.instance(context); + Assert.checkNonNull(tokens); + next.put(Tokens.tokensKey, tokens); JavaCompiler oldCompiler = JavaCompiler.instance(context); JavaCompiler nextCompiler = JavaCompiler.instance(next); diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/JavadocTool.java b/langtools/src/share/classes/com/sun/tools/javadoc/JavadocTool.java index 12096869f4f..a5592acf8ad 100644 --- a/langtools/src/share/classes/com/sun/tools/javadoc/JavadocTool.java +++ b/langtools/src/share/classes/com/sun/tools/javadoc/JavadocTool.java @@ -39,7 +39,6 @@ import javax.tools.StandardLocation; import com.sun.tools.javac.code.Symbol.CompletionFailure; import com.sun.tools.javac.comp.Annotate; -import com.sun.tools.javac.parser.DocCommentScanner; import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCClassDecl; import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; diff --git a/langtools/test/tools/javac/api/TestJavacTaskScanner.java b/langtools/test/tools/javac/api/TestJavacTaskScanner.java index 40bde1679e5..ba50138ecc1 100644 --- a/langtools/test/tools/javac/api/TestJavacTaskScanner.java +++ b/langtools/test/tools/javac/api/TestJavacTaskScanner.java @@ -32,6 +32,7 @@ import com.sun.tools.javac.api.JavacTaskImpl; import com.sun.tools.javac.parser.*; +import com.sun.tools.javac.parser.Tokens.Token; import com.sun.tools.javac.util.*; import java.io.*; import java.net.*; @@ -93,7 +94,7 @@ public class TestJavacTaskScanner extends ToolTester { check(numTokens, "#Tokens", 1222); check(numParseTypeElements, "#parseTypeElements", 136); - check(numAllMembers, "#allMembers", 67); + check(numAllMembers, "#allMembers", 52); } void check(int value, String name, int expected) { @@ -206,7 +207,8 @@ class MyScanner extends Scanner { public void nextToken() { super.nextToken(); - System.err.format("Saw token %s (%s)%n", token(), name()); + Token tk = token(); + System.err.format("Saw token %s %n", tk.kind); test.numTokens++; } diff --git a/langtools/test/tools/javac/depDocComment/DeprecatedDocComment3.java b/langtools/test/tools/javac/depDocComment/DeprecatedDocComment3.java new file mode 100644 index 00000000000..d7f4dbc0f2c --- /dev/null +++ b/langtools/test/tools/javac/depDocComment/DeprecatedDocComment3.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2011, 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 7096014 + * @summary Javac tokens should retain state + * @compile -Xlint -Werror DeprecatedDocComment3.java + */ + +class DeprecatedDocComment3 { + static class Foo { } + + ; /** @deprecated */ ; + + static class A {} + + static class B { + A a; //not deprecated! + } +} diff --git a/langtools/test/tools/javac/tree/DocCommentToplevelTest.java b/langtools/test/tools/javac/tree/DocCommentToplevelTest.java new file mode 100644 index 00000000000..ff236024f0f --- /dev/null +++ b/langtools/test/tools/javac/tree/DocCommentToplevelTest.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2011, 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 7096014 + * @summary Javac tokens should retain state + */ + +import com.sun.source.tree.*; +import com.sun.source.util.*; +import com.sun.tools.javac.tree.JCTree; + +import java.net.URI; +import java.util.*; +import javax.tools.*; + + +public class DocCommentToplevelTest { + + enum PackageKind { + HAS_PKG("package pkg;"), + NO_PKG(""); + + String pkgStr; + + PackageKind(String pkgStr) { + this.pkgStr = pkgStr; + } + } + + enum ImportKind { + ZERO(""), + ONE("import java.lang.*;"), + TWO("import java.lang.*; import java.util.*;"); + + String importStr; + + ImportKind(String importStr) { + this.importStr = importStr; + } + } + + enum ModifierKind { + DEFAULT(""), + PUBLIC("public"); + + String modStr; + + ModifierKind(String modStr) { + this.modStr = modStr; + } + } + + enum ToplevelDocKind { + HAS_DOC("/** Toplevel! */"), + NO_DOC(""); + + String docStr; + + ToplevelDocKind(String docStr) { + this.docStr = docStr; + } + } + + static int errors; + static int checks; + + public static void main(String... args) throws Exception { + //create default shared JavaCompiler - reused across multiple compilations + JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); + StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null); + + for (PackageKind pk : PackageKind.values()) { + for (ImportKind ik : ImportKind.values()) { + for (ModifierKind mk1 : ModifierKind.values()) { + for (ModifierKind mk2 : ModifierKind.values()) { + for (ToplevelDocKind tdk : ToplevelDocKind.values()) { + new DocCommentToplevelTest(pk, ik, mk1, mk2, tdk).run(comp, fm); + } + } + } + } + } + + if (errors > 0) + throw new AssertionError(errors + " errors found"); + + System.out.println(checks + " checks were made"); + } + + PackageKind pk; + ImportKind ik; + ModifierKind mk1; + ModifierKind mk2; + ToplevelDocKind tdk; + JavaSource source; + + DocCommentToplevelTest(PackageKind pk, ImportKind ik, ModifierKind mk1, ModifierKind mk2, ToplevelDocKind tdk) { + this.pk = pk; + this.ik = ik; + this.mk1 = mk1; + this.mk2 = mk2; + this.tdk = tdk; + source = new JavaSource(); + } + + void run(JavaCompiler comp, JavaFileManager fm) throws Exception { + JavacTask task = (JavacTask)comp.getTask(null, fm, null, Arrays.asList("-printsource"), null, Arrays.asList(source)); + for (CompilationUnitTree cu: task.parse()) { + check(cu); + } + } + + void check(CompilationUnitTree cu) { + checks++; + + new TreeScanner() { + + Map docComments; + + @Override + public ClassTree visitCompilationUnit(CompilationUnitTree node, Void unused) { + docComments = ((JCTree.JCCompilationUnit)node).docComments; + boolean expectedComment = tdk == ToplevelDocKind.HAS_DOC && + (pk != PackageKind.NO_PKG || ik != ImportKind.ZERO); + boolean foundComment = docComments.get(node) != null; + if (expectedComment != foundComment) { + error("Unexpected comment " + docComments.get(node) + " on toplevel"); + } + return super.visitCompilationUnit(node, null); + } + + @Override + public ClassTree visitClass(ClassTree node, Void unused) { + boolean expectedComment = tdk == ToplevelDocKind.HAS_DOC && + pk == PackageKind.NO_PKG && ik == ImportKind.ZERO && + node.getSimpleName().toString().equals("First"); + boolean foundComment = docComments.get(node) != null; + if (expectedComment != foundComment) { + error("Unexpected comment " + docComments.get(node) + " on class " + node.getSimpleName()); + } + return super.visitClass(node, unused); + } + }.scan(cu, null); + } + + void error(String msg) { + System.err.println("Error: " + msg); + System.err.println("Source: " + source.source); + errors++; + } + + class JavaSource extends SimpleJavaFileObject { + + String template = "#D\n#P\n#I\n" + + "#M1 class First { }\n" + + "#M2 class Second { }\n"; + + String source; + + public JavaSource() { + super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE); + source = template.replace("#P", pk.pkgStr) + .replace("#I", ik.importStr) + .replace("#M1", mk1.modStr) + .replace("#M2", mk2.modStr) + .replace("#D", tdk.docStr); + } + + @Override + public CharSequence getCharContent(boolean ignoreEncodingErrors) { + return source; + } + } +} From 7873cba6b26b7d3332a005ab998930d85ca8c844 Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Mon, 24 Oct 2011 13:00:30 +0100 Subject: [PATCH 039/107] 7098660: Write better overload resolution/inference tests Add overload/inference debug diagnostics - added test harness using annotations to check outcome of overload resolution/inference Reviewed-by: jjg --- .../com/sun/tools/javac/code/Printer.java | 2 +- .../com/sun/tools/javac/comp/Infer.java | 18 +- .../com/sun/tools/javac/comp/Resolve.java | 165 +++++- .../tools/javac/resources/compiler.properties | 49 ++ .../diags/examples/ApplicableMethodFound.java | 33 ++ .../examples/ApplicableMethodFound1.java | 34 ++ .../diags/examples/DeferredMethodInst.java | 35 ++ .../javac/diags/examples/FullInstSig.java | 34 ++ .../examples/NotApplicableMethodFound.java | 35 ++ .../javac/diags/examples/PartialInstSig.java | 34 ++ .../diags/examples/VerboseResolveMulti.java | 33 ++ .../diags/examples/VerboseResolveMulti1.java | 35 ++ .../test/tools/javac/resolve/Candidate.java | 68 +++ langtools/test/tools/javac/resolve/Pos.java | 31 ++ .../tools/javac/resolve/ResolveHarness.java | 475 ++++++++++++++++++ .../tools/javac/resolve/TraceResolve.java | 29 ++ .../tests/BoxedReturnTypeInference.java | 60 +++ .../PrimitiveOverReferenceOverInferred.java | 92 ++++ .../PrimitiveOverReferenceOverVarargs.java | 108 ++++ ...rimitiveOverReferenceVarargsAmbiguous.java | 76 +++ .../resolve/tests/PrimitiveOverload.java | 113 +++++ .../tests/PrimitiveReturnTypeInference.java | 60 +++ .../resolve/tests/ReferenceOverInferred.java | 76 +++ .../resolve/tests/ReferenceOverVarargs.java | 93 ++++ .../resolve/tests/ReferenceOverload.java | 95 ++++ 25 files changed, 1854 insertions(+), 29 deletions(-) create mode 100644 langtools/test/tools/javac/diags/examples/ApplicableMethodFound.java create mode 100644 langtools/test/tools/javac/diags/examples/ApplicableMethodFound1.java create mode 100644 langtools/test/tools/javac/diags/examples/DeferredMethodInst.java create mode 100644 langtools/test/tools/javac/diags/examples/FullInstSig.java create mode 100644 langtools/test/tools/javac/diags/examples/NotApplicableMethodFound.java create mode 100644 langtools/test/tools/javac/diags/examples/PartialInstSig.java create mode 100644 langtools/test/tools/javac/diags/examples/VerboseResolveMulti.java create mode 100644 langtools/test/tools/javac/diags/examples/VerboseResolveMulti1.java create mode 100644 langtools/test/tools/javac/resolve/Candidate.java create mode 100644 langtools/test/tools/javac/resolve/Pos.java create mode 100644 langtools/test/tools/javac/resolve/ResolveHarness.java create mode 100644 langtools/test/tools/javac/resolve/TraceResolve.java create mode 100644 langtools/test/tools/javac/resolve/tests/BoxedReturnTypeInference.java create mode 100644 langtools/test/tools/javac/resolve/tests/PrimitiveOverReferenceOverInferred.java create mode 100644 langtools/test/tools/javac/resolve/tests/PrimitiveOverReferenceOverVarargs.java create mode 100644 langtools/test/tools/javac/resolve/tests/PrimitiveOverReferenceVarargsAmbiguous.java create mode 100644 langtools/test/tools/javac/resolve/tests/PrimitiveOverload.java create mode 100644 langtools/test/tools/javac/resolve/tests/PrimitiveReturnTypeInference.java create mode 100644 langtools/test/tools/javac/resolve/tests/ReferenceOverInferred.java create mode 100644 langtools/test/tools/javac/resolve/tests/ReferenceOverVarargs.java create mode 100644 langtools/test/tools/javac/resolve/tests/ReferenceOverload.java diff --git a/langtools/src/share/classes/com/sun/tools/javac/code/Printer.java b/langtools/src/share/classes/com/sun/tools/javac/code/Printer.java index 59aa924385d..f639caeef45 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/code/Printer.java +++ b/langtools/src/share/classes/com/sun/tools/javac/code/Printer.java @@ -258,7 +258,7 @@ public abstract class Printer implements Type.Visitor, Symbol.Vi ClassType norm = (ClassType) t.tsym.type; if (norm == null) { s = localize(locale, "compiler.misc.anonymous.class", (Object) null); - } else if (norm.interfaces_field.nonEmpty()) { + } else if (norm.interfaces_field != null && norm.interfaces_field.nonEmpty()) { s = localize(locale, "compiler.misc.anonymous.class", visit(norm.interfaces_field.head, locale)); } else { diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java index 3c9ed3af15d..cc5ed20727e 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java @@ -34,7 +34,8 @@ import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Type.*; import com.sun.tools.javac.code.Type.ForAll.ConstraintKind; import com.sun.tools.javac.code.Symbol.*; -import com.sun.tools.javac.util.JCDiagnostic; +import com.sun.tools.javac.comp.Resolve.VerboseResolutionMode; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import static com.sun.tools.javac.code.TypeTags.*; @@ -56,6 +57,7 @@ public class Infer { Types types; Check chk; Resolve rs; + Log log; JCDiagnostic.Factory diags; public static Infer instance(Context context) { @@ -70,6 +72,7 @@ public class Infer { syms = Symtab.instance(context); types = Types.instance(context); rs = Resolve.instance(context); + log = Log.instance(context); chk = Check.instance(context); diags = JCDiagnostic.Factory.instance(context); ambiguousNoInstanceException = @@ -460,7 +463,7 @@ public class Infer { // quantify result type with them final List inferredTypes = insttypes.toList(); final List all_tvars = tvars; //this is the wrong tvars - return new UninferredMethodType(mt, restvars.toList()) { + return new UninferredMethodType(env.tree.pos(), msym, mt, restvars.toList()) { @Override List getConstraints(TypeVar tv, ConstraintKind ck) { for (Type t : restundet.toList()) { @@ -502,13 +505,17 @@ public class Infer { * type - when the return type is instantiated (see Infer.instantiateExpr) * the underlying method type is also updated. */ - static abstract class UninferredMethodType extends DelegatedType { + abstract class UninferredMethodType extends DelegatedType { final List tvars; + final Symbol msym; + final DiagnosticPosition pos; - public UninferredMethodType(MethodType mtype, List tvars) { + public UninferredMethodType(DiagnosticPosition pos, Symbol msym, MethodType mtype, List tvars) { super(METHOD, new MethodType(mtype.argtypes, null, mtype.thrown, mtype.tsym)); this.tvars = tvars; + this.msym = msym; + this.pos = pos; asMethodType().restype = new UninferredReturnType(tvars, mtype.restype); } @@ -543,6 +550,9 @@ public class Infer { public Type inst(List actuals, Types types) { Type newRestype = super.inst(actuals, types); instantiateReturnType(newRestype, actuals, types); + if (rs.verboseResolutionMode.contains(VerboseResolutionMode.DEFERRED_INST)) { + log.note(pos, "deferred.method.inst", msym, UninferredMethodType.this.qtype, newRestype); + } return newRestype; } @Override diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java index 0c37d015188..3d6374dbaf1 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java @@ -25,29 +25,33 @@ package com.sun.tools.javac.comp; -import com.sun.tools.javac.util.*; -import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; -import com.sun.tools.javac.code.*; -import com.sun.tools.javac.jvm.*; -import com.sun.tools.javac.tree.*; import com.sun.tools.javac.api.Formattable.LocalizedString; -import static com.sun.tools.javac.comp.Resolve.MethodResolutionPhase.*; - +import com.sun.tools.javac.code.*; import com.sun.tools.javac.code.Type.*; import com.sun.tools.javac.code.Symbol.*; +import com.sun.tools.javac.jvm.*; +import com.sun.tools.javac.tree.*; import com.sun.tools.javac.tree.JCTree.*; +import com.sun.tools.javac.util.*; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; +import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType; + +import java.util.Arrays; +import java.util.Collection; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import javax.lang.model.element.ElementVisitor; import static com.sun.tools.javac.code.Flags.*; import static com.sun.tools.javac.code.Kinds.*; import static com.sun.tools.javac.code.TypeTags.*; -import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag; -import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType; -import javax.lang.model.element.ElementVisitor; - -import java.util.Map; -import java.util.Set; -import java.util.HashMap; -import java.util.HashSet; +import static com.sun.tools.javac.comp.Resolve.MethodResolutionPhase.*; /** Helper class for name resolution, used mostly by the attribution phase. * @@ -73,9 +77,45 @@ public class Resolve { public final boolean varargsEnabled; // = source.allowVarargs(); public final boolean allowMethodHandles; private final boolean debugResolve; + final EnumSet verboseResolutionMode; Scope polymorphicSignatureScope; + enum VerboseResolutionMode { + SUCCESS("success"), + FAILURE("failure"), + APPLICABLE("applicable"), + INAPPLICABLE("inapplicable"), + DEFERRED_INST("deferred-inference"), + PREDEF("predef"), + OBJECT_INIT("object-init"), + INTERNAL("internal"); + + String opt; + + private VerboseResolutionMode(String opt) { + this.opt = opt; + } + + static EnumSet getVerboseResolutionMode(Options opts) { + String s = opts.get("verboseResolution"); + EnumSet res = EnumSet.noneOf(VerboseResolutionMode.class); + if (s == null) return res; + if (s.contains("all")) { + res = EnumSet.allOf(VerboseResolutionMode.class); + } + Collection args = Arrays.asList(s.split(",")); + for (VerboseResolutionMode mode : values()) { + if (args.contains(mode.opt)) { + res.add(mode); + } else if (args.contains("-" + mode.opt)) { + res.remove(mode); + } + } + return res; + } + } + public static Resolve instance(Context context) { Resolve instance = context.get(resolveKey); if (instance == null) @@ -111,6 +151,7 @@ public class Resolve { varargsEnabled = source.allowVarargs(); Options options = Options.instance(context); debugResolve = options.isSet("debugresolve"); + verboseResolutionMode = VerboseResolutionMode.getVerboseResolutionMode(options); Target target = Target.instance(context); allowMethodHandles = target.hasMethodHandles(); polymorphicSignatureScope = new Scope(syms.noSymbol); @@ -684,9 +725,11 @@ public class Resolve { if (!sym.isInheritedIn(site.tsym, types)) return bestSoFar; Assert.check(sym.kind < AMBIGUOUS); try { - rawInstantiate(env, site, sym, argtypes, typeargtypes, + Type mt = rawInstantiate(env, site, sym, argtypes, typeargtypes, allowBoxing, useVarargs, Warner.noWarnings); + if (!operator) addVerboseApplicableCandidateDiag(sym ,mt); } catch (InapplicableMethodException ex) { + if (!operator) addVerboseInapplicableCandidateDiag(sym, ex.getDiagnostic()); switch (bestSoFar.kind) { case ABSENT_MTH: return wrongMethod.setWrongSym(sym, ex.getDiagnostic()); @@ -709,6 +752,34 @@ public class Resolve { : mostSpecific(sym, bestSoFar, env, site, allowBoxing && operator, useVarargs); } + //where + void addVerboseApplicableCandidateDiag(Symbol sym, Type inst) { + if (!verboseResolutionMode.contains(VerboseResolutionMode.APPLICABLE)) + return; + + JCDiagnostic subDiag = null; + if (inst.getReturnType().tag == FORALL) { + Type diagType = types.createMethodTypeWithReturn(inst.asMethodType(), + ((ForAll)inst.getReturnType()).qtype); + subDiag = diags.fragment("partial.inst.sig", diagType); + } else if (sym.type.tag == FORALL) { + subDiag = diags.fragment("full.inst.sig", inst.asMethodType()); + } + + String key = subDiag == null ? + "applicable.method.found" : + "applicable.method.found.1"; + + verboseResolutionCandidateDiags.put(sym, + diags.fragment(key, verboseResolutionCandidateDiags.size(), sym, subDiag)); + } + + void addVerboseInapplicableCandidateDiag(Symbol sym, JCDiagnostic subDiag) { + if (!verboseResolutionMode.contains(VerboseResolutionMode.INAPPLICABLE)) + return; + verboseResolutionCandidateDiags.put(sym, + diags.fragment("not.applicable.method.found", verboseResolutionCandidateDiags.size(), sym, subDiag)); + } /* Return the most specific of the two methods for a call, * given that both are accessible and applicable. @@ -906,8 +977,9 @@ public class Resolve { boolean allowBoxing, boolean useVarargs, boolean operator) { + verboseResolutionCandidateDiags.clear(); Symbol bestSoFar = methodNotFound; - return findMethod(env, + bestSoFar = findMethod(env, site, name, argtypes, @@ -919,6 +991,8 @@ public class Resolve { useVarargs, operator, new HashSet()); + reportVerboseResolutionDiagnostic(env.tree.pos(), name, site, argtypes, typeargtypes, bestSoFar); + return bestSoFar; } // where private Symbol findMethod(Env env, @@ -976,6 +1050,37 @@ public class Resolve { } return bestSoFar; } + //where + void reportVerboseResolutionDiagnostic(DiagnosticPosition dpos, Name name, Type site, List argtypes, List typeargtypes, Symbol bestSoFar) { + boolean success = bestSoFar.kind < ERRONEOUS; + + if (success && !verboseResolutionMode.contains(VerboseResolutionMode.SUCCESS)) { + return; + } else if (!success && !verboseResolutionMode.contains(VerboseResolutionMode.FAILURE)) { + return; + } + + if (bestSoFar.name == names.init && + bestSoFar.owner == syms.objectType.tsym && + !verboseResolutionMode.contains(VerboseResolutionMode.OBJECT_INIT)) { + return; //skip diags for Object constructor resolution + } else if (site == syms.predefClass.type && !verboseResolutionMode.contains(VerboseResolutionMode.PREDEF)) { + return; //skip spurious diags for predef symbols (i.e. operators) + } else if (internalResolution && !verboseResolutionMode.contains(VerboseResolutionMode.INTERNAL)) { + return; + } + + int pos = 0; + for (Symbol s : verboseResolutionCandidateDiags.keySet()) { + if (s == bestSoFar) break; + pos++; + } + String key = success ? "verbose.resolve.multi" : "verbose.resolve.multi.1"; + JCDiagnostic main = diags.note(log.currentSource(), dpos, key, name, site.tsym, pos, currentStep, + methodArguments(argtypes), methodArguments(typeargtypes)); + JCDiagnostic d = new JCDiagnostic.MultilineDiagnostic(main, List.from(verboseResolutionCandidateDiags.values().toArray(new JCDiagnostic[verboseResolutionCandidateDiags.size()]))); + log.report(d); + } /** Find unqualified method matching given name, type and value arguments. * @param env The current environment. @@ -1544,12 +1649,19 @@ public class Resolve { Type site, Name name, List argtypes, List typeargtypes) { - Symbol sym = resolveQualifiedMethod( - pos, env, site.tsym, site, name, argtypes, typeargtypes); - if (sym.kind == MTH) return (MethodSymbol)sym; - else throw new FatalError( - diags.fragment("fatal.err.cant.locate.meth", - name)); + boolean prevInternal = internalResolution; + try { + internalResolution = true; + Symbol sym = resolveQualifiedMethod( + pos, env, site.tsym, site, name, argtypes, typeargtypes); + if (sym.kind == MTH) return (MethodSymbol)sym; + else throw new FatalError( + diags.fragment("fatal.err.cant.locate.meth", + name)); + } + finally { + internalResolution = prevInternal; + } } /** Resolve constructor. @@ -1830,7 +1942,7 @@ public class Resolve { private final LocalizedString noArgs = new LocalizedString("compiler.misc.no.args"); public Object methodArguments(List argtypes) { - return argtypes.isEmpty() ? noArgs : argtypes; + return argtypes == null || argtypes.isEmpty() ? noArgs : argtypes; } /** @@ -2377,10 +2489,15 @@ public class Resolve { private Map methodResolutionCache = new HashMap(MethodResolutionPhase.values().length); + private Map verboseResolutionCandidateDiags = + new LinkedHashMap(); + final List methodResolutionSteps = List.of(BASIC, BOX, VARARITY); private MethodResolutionPhase currentStep = null; + private boolean internalResolution = false; + private MethodResolutionPhase firstErroneousResolutionPhase() { MethodResolutionPhase bestSoFar = BASIC; Symbol sym = methodNotFound; diff --git a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties index 7fab25ee989..9b3574e7abd 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -1943,6 +1943,55 @@ compiler.err.string.switch.not.supported.in.source=\ strings in switch are not supported in -source {0}\n\ (use -source 7 or higher to enable strings in switch) +######################################## +# Diagnostics for verbose resolution +# used by Resolve (debug only) +######################################## + +# 0: number, 1: symbol, 2: unused +compiler.misc.applicable.method.found=\ + #{0} applicable method found: {1} + +# 0: number, 1: symbol, 2: message segment +compiler.misc.applicable.method.found.1=\ + #{0} applicable method found: {1}\n\ + ({2}) + +# 0: number, 1: symbol, 2: message segment +compiler.misc.not.applicable.method.found=\ + #{0} not applicable method found: {1}\n\ + ({2}) + +# 0: type +compiler.misc.full.inst.sig=\ + fully instantiated to: {0} + +# 0: type +compiler.misc.partial.inst.sig=\ + partially instantiated to: {0} + +# 0: name, 1: symbol, 2: number, 3: MethodResolutionPhase, 4: list of type or message segment, 5: list of type or message segment +compiler.note.verbose.resolve.multi=\ + resolving method {0} in type {1} to candidate {2}\n\ + phase: {3}\n\ + with actuals: {4}\n\ + with type-args: {5}\n\ + candidates: + +# 0: name, 1: symbol, 2: unused, 3: MethodResolutionPhase, 4: list of type or message segment, 5: list of type or message segment +compiler.note.verbose.resolve.multi.1=\ + erroneous resolution for method {0} in type {1}\n\ + phase: {3}\n\ + with actuals: {4}\n\ + with type-args: {5}\n\ + candidates: + +# 0: symbol, 1: type, 2: type +compiler.note.deferred.method.inst=\ + Deferred instantiation of method {0}\n\ + instantiated signature: {1}\n\ + target-type: {2} + ######################################## # Diagnostics for where clause implementation # used by the RichDiagnosticFormatter. diff --git a/langtools/test/tools/javac/diags/examples/ApplicableMethodFound.java b/langtools/test/tools/javac/diags/examples/ApplicableMethodFound.java new file mode 100644 index 00000000000..675544939b3 --- /dev/null +++ b/langtools/test/tools/javac/diags/examples/ApplicableMethodFound.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2011, 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. + */ + +// key: compiler.misc.applicable.method.found +// key: compiler.note.verbose.resolve.multi +// options: -XDverboseResolution=applicable,success + +class ApplicableMethodFound { + + void m() {} + + { m(); } +} diff --git a/langtools/test/tools/javac/diags/examples/ApplicableMethodFound1.java b/langtools/test/tools/javac/diags/examples/ApplicableMethodFound1.java new file mode 100644 index 00000000000..7764d50e518 --- /dev/null +++ b/langtools/test/tools/javac/diags/examples/ApplicableMethodFound1.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011, 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. + */ + +// key: compiler.misc.applicable.method.found.1 +// key: compiler.note.verbose.resolve.multi +// key: compiler.misc.full.inst.sig +// options: -XDverboseResolution=applicable,success + +class ApplicableMethodFound1 { + + void m(X x) {} + + { m(1); } +} diff --git a/langtools/test/tools/javac/diags/examples/DeferredMethodInst.java b/langtools/test/tools/javac/diags/examples/DeferredMethodInst.java new file mode 100644 index 00000000000..ff56e5e0212 --- /dev/null +++ b/langtools/test/tools/javac/diags/examples/DeferredMethodInst.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011, 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. + */ + +// key: compiler.misc.applicable.method.found.1 +// key: compiler.note.verbose.resolve.multi +// key: compiler.note.deferred.method.inst +// key: compiler.misc.partial.inst.sig +// options: -XDverboseResolution=applicable,success,deferred-inference + +class DeferredMethodInst { + + X m() { return null; } + + { Integer i = m(); } +} diff --git a/langtools/test/tools/javac/diags/examples/FullInstSig.java b/langtools/test/tools/javac/diags/examples/FullInstSig.java new file mode 100644 index 00000000000..fc0d642b278 --- /dev/null +++ b/langtools/test/tools/javac/diags/examples/FullInstSig.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011, 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. + */ + +// key: compiler.misc.applicable.method.found.1 +// key: compiler.note.verbose.resolve.multi +// key: compiler.misc.full.inst.sig +// options: -XDverboseResolution=applicable,success + +class FullInstSig { + + void m(X x) {} + + { m(1); } +} diff --git a/langtools/test/tools/javac/diags/examples/NotApplicableMethodFound.java b/langtools/test/tools/javac/diags/examples/NotApplicableMethodFound.java new file mode 100644 index 00000000000..bfd2bfb35b7 --- /dev/null +++ b/langtools/test/tools/javac/diags/examples/NotApplicableMethodFound.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011, 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. + */ + +// key: compiler.misc.not.applicable.method.found +// key: compiler.note.verbose.resolve.multi.1 +// key: compiler.err.cant.apply.symbol.1 +// key: compiler.misc.no.conforming.assignment.exists +// options: -XDverboseResolution=inapplicable,failure + +class NotApplicableMethodFound { + + void m(int i) {} + + { m(""); } +} diff --git a/langtools/test/tools/javac/diags/examples/PartialInstSig.java b/langtools/test/tools/javac/diags/examples/PartialInstSig.java new file mode 100644 index 00000000000..c095bdd1c9b --- /dev/null +++ b/langtools/test/tools/javac/diags/examples/PartialInstSig.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011, 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. + */ + +// key: compiler.misc.applicable.method.found.1 +// key: compiler.note.verbose.resolve.multi +// key: compiler.misc.partial.inst.sig +// options: -XDverboseResolution=applicable,success + +class PartialInstSig { + + X m() { return null; } + + { m(); } +} diff --git a/langtools/test/tools/javac/diags/examples/VerboseResolveMulti.java b/langtools/test/tools/javac/diags/examples/VerboseResolveMulti.java new file mode 100644 index 00000000000..59a8d3c8716 --- /dev/null +++ b/langtools/test/tools/javac/diags/examples/VerboseResolveMulti.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2011, 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. + */ + +// key: compiler.misc.applicable.method.found +// key: compiler.note.verbose.resolve.multi +// options: -XDverboseResolution=applicable,success + +class VerboseResolveMulti { + + void m() {} + + { m(); } +} diff --git a/langtools/test/tools/javac/diags/examples/VerboseResolveMulti1.java b/langtools/test/tools/javac/diags/examples/VerboseResolveMulti1.java new file mode 100644 index 00000000000..b72f416dccf --- /dev/null +++ b/langtools/test/tools/javac/diags/examples/VerboseResolveMulti1.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011, 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. + */ + +// key: compiler.misc.not.applicable.method.found +// key: compiler.note.verbose.resolve.multi.1 +// key: compiler.err.cant.apply.symbol.1 +// key: compiler.misc.no.conforming.assignment.exists +// options: -XDverboseResolution=inapplicable,failure + +class VerboseResolveMulti1 { + + void m(int i) {} + + { m(""); } +} diff --git a/langtools/test/tools/javac/resolve/Candidate.java b/langtools/test/tools/javac/resolve/Candidate.java new file mode 100644 index 00000000000..a36208b56fa --- /dev/null +++ b/langtools/test/tools/javac/resolve/Candidate.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2011, 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. + */ +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD, ElementType.CONSTRUCTOR}) +@interface Candidate { + /** + * the candidate position (line/col of the method call for which this candidate + * is a potential overload candidate) + */ + Pos pos() default @Pos(userDefined=false); + /** + * resolution phases for which this candidate is applicable + */ + Phase[] applicable() default { }; + /** + * is this candidate the most specific (in the resolution phases for which it + * is also applicable) + */ + boolean mostSpecific() default false; + /** + * this candidate inferred signature (in the resolution phases for which it + * is also applicable, in case it corresponds to a generic method) + */ + String sig() default ""; +} + +enum Phase { + BASIC("BASIC"), + BOX("BOX"), + VARARGS("VARARITY"); + + final String javacString; + + private Phase(String javacString) { + this.javacString = javacString; + } + + static Phase fromString(String s) { + for (Phase phase : Phase.values()) { + if (phase.javacString.equals(s)) { + return phase; + } + } + throw new AssertionError("Invalid resolution phase string " + s); + } +} diff --git a/langtools/test/tools/javac/resolve/Pos.java b/langtools/test/tools/javac/resolve/Pos.java new file mode 100644 index 00000000000..d778536e9f0 --- /dev/null +++ b/langtools/test/tools/javac/resolve/Pos.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011, 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. + */ +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +@Target(ElementType.ANNOTATION_TYPE) +@interface Pos { + long line() default -1; + long col() default -1; + boolean userDefined() default true; +} \ No newline at end of file diff --git a/langtools/test/tools/javac/resolve/ResolveHarness.java b/langtools/test/tools/javac/resolve/ResolveHarness.java new file mode 100644 index 00000000000..609b3d84d13 --- /dev/null +++ b/langtools/test/tools/javac/resolve/ResolveHarness.java @@ -0,0 +1,475 @@ +/* + * Copyright (c) 2011, 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 7098660 + * @summary Write better overload resolution/inference tests + * @library ../lib + * @build JavacTestingAbstractProcessor ResolveHarness + * @run main ResolveHarness + */ + +import com.sun.source.util.JavacTask; +import com.sun.tools.javac.api.ClientCodeWrapper.DiagnosticSourceUnwrapper; +import com.sun.tools.javac.code.Type.MethodType; +import com.sun.tools.javac.util.JCDiagnostic; + +import java.io.File; +import java.util.Set; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.lang.model.element.Element; +import javax.lang.model.element.TypeElement; +import javax.tools.Diagnostic; +import javax.tools.Diagnostic.Kind; +import javax.tools.DiagnosticListener; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileObject; +import javax.tools.StandardJavaFileManager; +import javax.tools.ToolProvider; + +import static javax.tools.StandardLocation.*; + +public class ResolveHarness implements javax.tools.DiagnosticListener { + + static int nerrors = 0; + + static final JavaCompiler comp = ToolProvider.getSystemJavaCompiler(); + static final StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null); + + public static void main(String[] args) throws Exception { + fm.setLocation(SOURCE_PATH, + Arrays.asList(new File(System.getProperty("test.src"), "tests"))); + for (JavaFileObject jfo : fm.list(SOURCE_PATH, "", Collections.singleton(JavaFileObject.Kind.SOURCE), true)) { + new ResolveHarness(jfo).check(); + } + if (nerrors > 0) { + throw new AssertionError("Errors were found"); + } + } + + + JavaFileObject jfo; + DiagnosticProcessor[] diagProcessors; + Map candidatesMap = new HashMap(); + Set declaredKeys = new HashSet<>(); + List> diags = new ArrayList<>(); + List seenCandidates = new ArrayList<>(); + + protected ResolveHarness(JavaFileObject jfo) { + this.jfo = jfo; + this.diagProcessors = new DiagnosticProcessor[] { + new VerboseResolutionNoteProcessor(), + new VerboseDeferredInferenceNoteProcessor(), + new ErrorProcessor() + }; + } + + protected void check() throws Exception { + String[] options = { + "-XDshouldStopPolicy=ATTR", + "-XDverboseResolution=success,failure,applicable,inapplicable,deferred-inference" + }; + + AbstractProcessor[] processors = { new ResolveCandidateFinder(), null }; + + @SuppressWarnings("unchecked") + DiagnosticListener[] diagListeners = + new DiagnosticListener[] { new DiagnosticHandler(false), new DiagnosticHandler(true) }; + + for (int i = 0 ; i < options.length ; i ++) { + JavacTask ct = (JavacTask)comp.getTask(null, fm, diagListeners[i], + Arrays.asList(options[i]), null, Arrays.asList(jfo)); + if (processors[i] != null) { + ct.setProcessors(Collections.singleton(processors[i])); + } + ct.analyze(); + } + + //check diags + for (Diagnostic diag : diags) { + for (DiagnosticProcessor proc : diagProcessors) { + if (proc.matches(diag)) { + proc.process(diag); + break; + } + } + } + //check all candidates have been used up + for (Map.Entry entry : candidatesMap.entrySet()) { + if (!seenCandidates.contains(entry.getKey())) { + error("Redundant @Candidate annotation on method " + entry.getKey().elem); + } + } + } + + public void report(Diagnostic diagnostic) { + diags.add(diagnostic); + } + + Candidate getCandidateAtPos(Element methodSym, long line, long col) { + Candidate c = candidatesMap.get(new ElementKey(methodSym)); + if (c != null) { + Pos pos = c.pos(); + if (!pos.userDefined() || + (pos.line() == line && pos.col() == col)) { + seenCandidates.add(new ElementKey(methodSym)); + return c; + } + } else { + error("Missing @Candidate annotation on method " + methodSym); + } + return null; + } + + void checkSig(Candidate c, Element methodSym, MethodType mtype) { + if (c.sig().length() > 0 && !c.sig().equals(mtype.toString())) { + error("Inferred type mismatch for method: " + methodSym); + } + } + + protected void error(String msg) { + nerrors++; + System.err.printf("Error occurred while checking file: %s\nreason: %s\n", jfo.getName(), msg); + } + + /** + * Base class for diagnostic processor. It provides methods for matching and + * processing a given diagnostic object (overridden by subclasses). + */ + abstract class DiagnosticProcessor { + + List codes; + Diagnostic.Kind kind; + + public DiagnosticProcessor(Kind kind, String... codes) { + this.codes = Arrays.asList(codes); + this.kind = kind; + } + + abstract void process(Diagnostic diagnostic); + + boolean matches(Diagnostic diagnostic) { + return (codes.isEmpty() || codes.contains(diagnostic.getCode())) && + diagnostic.getKind() == kind; + } + + JCDiagnostic asJCDiagnostic(Diagnostic diagnostic) { + if (diagnostic instanceof JCDiagnostic) { + return (JCDiagnostic)diagnostic; + } else if (diagnostic instanceof DiagnosticSourceUnwrapper) { + return ((DiagnosticSourceUnwrapper)diagnostic).d; + } else { + throw new AssertionError("Cannot convert diagnostic to JCDiagnostic: " + diagnostic.getClass().getName()); + } + } + + List subDiagnostics(Diagnostic diagnostic) { + JCDiagnostic diag = asJCDiagnostic(diagnostic); + if (diag instanceof JCDiagnostic.MultilineDiagnostic) { + return ((JCDiagnostic.MultilineDiagnostic)diag).getSubdiagnostics(); + } else { + throw new AssertionError("Cannot extract subdiagnostics: " + diag.getClass().getName()); + } + } + } + + /** + * Processor for verbose resolution notes generated by javac. The processor + * checks that the diagnostic is associated with a method declared by + * a class annotated with the special @TraceResolve marker annotation. If + * that's the case, all subdiagnostics (one for each resolution candidate) + * are checked against the corresponding @Candidate annotations, using + * a VerboseCandidateSubdiagProcessor. + */ + class VerboseResolutionNoteProcessor extends DiagnosticProcessor { + + VerboseResolutionNoteProcessor() { + super(Kind.NOTE, + "compiler.note.verbose.resolve.multi", + "compiler.note.verbose.resolve.multi.1"); + } + + @Override + void process(Diagnostic diagnostic) { + Element siteSym = getSiteSym(diagnostic); + if (siteSym.getAnnotation(TraceResolve.class) == null) { + return; + } + int candidateIdx = 0; + for (JCDiagnostic d : subDiagnostics(diagnostic)) { + boolean isMostSpecific = candidateIdx++ == mostSpecific(diagnostic); + VerboseCandidateSubdiagProcessor subProc = + new VerboseCandidateSubdiagProcessor(isMostSpecific, phase(diagnostic), success(diagnostic)); + if (subProc.matches(d)) { + subProc.process(d); + } else { + throw new AssertionError("Bad subdiagnostic: " + d.getCode()); + } + } + } + + Element getSiteSym(Diagnostic diagnostic) { + return (Element)asJCDiagnostic(diagnostic).getArgs()[1]; + } + + int mostSpecific(Diagnostic diagnostic) { + return success(diagnostic) ? + (Integer)asJCDiagnostic(diagnostic).getArgs()[2] : -1; + } + + boolean success(Diagnostic diagnostic) { + return diagnostic.getCode().equals("compiler.note.verbose.resolve.multi"); + } + + Phase phase(Diagnostic diagnostic) { + return Phase.fromString(asJCDiagnostic(diagnostic).getArgs()[3].toString()); + } + } + + /** + * Processor for verbose resolution subdiagnostic notes generated by javac. + * The processor checks that the details of the overload candidate + * match against the info contained in the corresponding @Candidate + * annotation (if any). + */ + class VerboseCandidateSubdiagProcessor extends DiagnosticProcessor { + + boolean mostSpecific; + Phase phase; + boolean success; + + public VerboseCandidateSubdiagProcessor(boolean mostSpecific, Phase phase, boolean success) { + super(Kind.OTHER, + "compiler.misc.applicable.method.found", + "compiler.misc.applicable.method.found.1", + "compiler.misc.not.applicable.method.found"); + this.mostSpecific = mostSpecific; + this.phase = phase; + this.success = success; + } + + @Override + void process(Diagnostic diagnostic) { + Element methodSym = methodSym(diagnostic); + Candidate c = getCandidateAtPos(methodSym, + asJCDiagnostic(diagnostic).getLineNumber(), + asJCDiagnostic(diagnostic).getColumnNumber()); + if (c == null) { + return; //nothing to check + } + + if (c.applicable().length == 0 && c.mostSpecific()) { + error("Inapplicable method cannot be most specific " + methodSym); + } + + if (isApplicable(diagnostic) != Arrays.asList(c.applicable()).contains(phase)) { + error("Invalid candidate's applicability " + methodSym); + } + + if (success) { + for (Phase p : c.applicable()) { + if (phase.ordinal() < p.ordinal()) { + error("Invalid phase " + p + " on method " + methodSym); + } + } + } + + if (Arrays.asList(c.applicable()).contains(phase)) { //applicable + if (c.mostSpecific() != mostSpecific) { + error("Invalid most specific value for method " + methodSym); + } + MethodType mtype = getSig(diagnostic); + if (mtype != null) { + checkSig(c, methodSym, mtype); + } + } + } + + boolean isApplicable(Diagnostic diagnostic) { + return !diagnostic.getCode().equals("compiler.misc.not.applicable.method.found"); + } + + Element methodSym(Diagnostic diagnostic) { + return (Element)asJCDiagnostic(diagnostic).getArgs()[1]; + } + + MethodType getSig(Diagnostic diagnostic) { + JCDiagnostic details = (JCDiagnostic)asJCDiagnostic(diagnostic).getArgs()[2]; + if (details == null) { + return null; + } else if (details instanceof JCDiagnostic) { + return details.getCode().equals("compiler.misc.full.inst.sig") ? + (MethodType)details.getArgs()[0] : null; + } else { + throw new AssertionError("Bad diagnostic arg: " + details); + } + } + } + + /** + * Processor for verbose deferred inference notes generated by javac. The + * processor checks that the inferred signature for a given generic method + * call corresponds to the one (if any) declared in the @Candidate annotation. + */ + class VerboseDeferredInferenceNoteProcessor extends DiagnosticProcessor { + + public VerboseDeferredInferenceNoteProcessor() { + super(Kind.NOTE, "compiler.note.deferred.method.inst"); + } + + @Override + void process(Diagnostic diagnostic) { + Element methodSym = methodSym(diagnostic); + Candidate c = getCandidateAtPos(methodSym, + asJCDiagnostic(diagnostic).getLineNumber(), + asJCDiagnostic(diagnostic).getColumnNumber()); + MethodType sig = sig(diagnostic); + if (c != null && sig != null) { + checkSig(c, methodSym, sig); + } + } + + Element methodSym(Diagnostic diagnostic) { + return (Element)asJCDiagnostic(diagnostic).getArgs()[0]; + } + + MethodType sig(Diagnostic diagnostic) { + return (MethodType)asJCDiagnostic(diagnostic).getArgs()[1]; + } + } + + /** + * Processor for all error diagnostics; if the error key is not declared in + * the test file header, the processor reports an error. + */ + class ErrorProcessor extends DiagnosticProcessor { + + public ErrorProcessor() { + super(Diagnostic.Kind.ERROR); + } + + @Override + void process(Diagnostic diagnostic) { + if (!declaredKeys.contains(diagnostic.getCode())) { + error("Unexpected compilation error key '" + diagnostic.getCode() + "'"); + } + } + } + + @SupportedAnnotationTypes({"Candidate","TraceResolve"}) + class ResolveCandidateFinder extends JavacTestingAbstractProcessor { + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + if (roundEnv.processingOver()) + return true; + + TypeElement traceResolveAnno = elements.getTypeElement("TraceResolve"); + TypeElement candidateAnno = elements.getTypeElement("Candidate"); + + if (!annotations.contains(traceResolveAnno)) { + error("no @TraceResolve annotation found in test class"); + } + + if (!annotations.contains(candidateAnno)) { + error("no @candidate annotation found in test class"); + } + + for (Element elem: roundEnv.getElementsAnnotatedWith(traceResolveAnno)) { + TraceResolve traceResolve = elem.getAnnotation(TraceResolve.class); + declaredKeys.addAll(Arrays.asList(traceResolve.keys())); + } + + for (Element elem: roundEnv.getElementsAnnotatedWith(candidateAnno)) { + candidatesMap.put(new ElementKey(elem), elem.getAnnotation(Candidate.class)); + } + return true; + } + } + + class ElementKey { + + String key; + Element elem; + + public ElementKey(Element elem) { + this.elem = elem; + this.key = computeKey(elem); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ElementKey) { + ElementKey other = (ElementKey)obj; + return other.key.equals(key); + } + return false; + } + + @Override + public int hashCode() { + return key.hashCode(); + } + + String computeKey(Element e) { + StringBuilder buf = new StringBuilder(); + while (e != null) { + buf.append(e.toString()); + e = e.getEnclosingElement(); + } + buf.append(jfo.getName()); + return buf.toString(); + } + + @Override + public String toString() { + return "Key{"+key+"}"; + } + } + + class DiagnosticHandler implements DiagnosticListener { + + boolean shouldRecordDiags; + + DiagnosticHandler(boolean shouldRecordDiags) { + this.shouldRecordDiags = shouldRecordDiags; + } + + public void report(Diagnostic diagnostic) { + if (shouldRecordDiags) + diags.add(diagnostic); + } + + } +} diff --git a/langtools/test/tools/javac/resolve/TraceResolve.java b/langtools/test/tools/javac/resolve/TraceResolve.java new file mode 100644 index 00000000000..ddc83996e80 --- /dev/null +++ b/langtools/test/tools/javac/resolve/TraceResolve.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2011, 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. + */ +import java.lang.annotation.ElementType; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@interface TraceResolve { + String[] keys() default {}; +} diff --git a/langtools/test/tools/javac/resolve/tests/BoxedReturnTypeInference.java b/langtools/test/tools/javac/resolve/tests/BoxedReturnTypeInference.java new file mode 100644 index 00000000000..dcde2567192 --- /dev/null +++ b/langtools/test/tools/javac/resolve/tests/BoxedReturnTypeInference.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011, 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. + */ + +@TraceResolve +class BoxedReturnTypeInference { + @Candidate(applicable=Phase.BASIC, sig="()java.lang.Byte", mostSpecific=true) + static B m_byte() { return null; } + + @Candidate(applicable=Phase.BASIC, sig="()java.lang.Short", mostSpecific=true) + static S m_short() { return null; } + + @Candidate(applicable=Phase.BASIC, sig="()java.lang.Integer", mostSpecific=true) + static I m_int() { return null; } + + @Candidate(applicable=Phase.BASIC, sig="()java.lang.Long", mostSpecific=true) + static L m_long() { return null; } + + @Candidate(applicable=Phase.BASIC, sig="()java.lang.Float", mostSpecific=true) + static F m_float() { return null; } + + @Candidate(applicable=Phase.BASIC, sig="()java.lang.Double", mostSpecific=true) + static D m_double() { return null; } + + @Candidate(applicable=Phase.BASIC, sig="()java.lang.Character", mostSpecific=true) + static C m_char() { return null; } + + @Candidate(applicable=Phase.BASIC, sig="()java.lang.Boolean", mostSpecific=true) + static Z m_bool() { return null; } + + { + Byte b = m_byte(); + Short s = m_short(); + Integer i = m_int(); + Long l = m_long(); + Float f = m_float(); + Double d = m_double(); + Character c= m_char(); + Boolean z = m_bool(); + } +} diff --git a/langtools/test/tools/javac/resolve/tests/PrimitiveOverReferenceOverInferred.java b/langtools/test/tools/javac/resolve/tests/PrimitiveOverReferenceOverInferred.java new file mode 100644 index 00000000000..843169cf35c --- /dev/null +++ b/langtools/test/tools/javac/resolve/tests/PrimitiveOverReferenceOverInferred.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2011, 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. + */ + +@TraceResolve +class PrimitiveOverReference { + @Candidate(applicable=Phase.BASIC, mostSpecific=true) + static void m_byte(byte b) {} + @Candidate + static void m_byte(Byte b) {} + @Candidate + static void m_byte(B b) {} + + @Candidate(applicable=Phase.BASIC, mostSpecific=true) + static void m_short(short s) {} + @Candidate + static void m_short(Short s) {} + @Candidate + static void m_short(S s) {} + + @Candidate(applicable=Phase.BASIC, mostSpecific=true) + static void m_int(int i) {} + @Candidate + static void m_int(Integer i) {} + @Candidate + static void m_int(I i) {} + + @Candidate(applicable=Phase.BASIC, mostSpecific=true) + static void m_long(long l) {} + @Candidate + static void m_long(Long l) {} + @Candidate + static void m_long(L l) {} + + @Candidate(applicable=Phase.BASIC, mostSpecific=true) + static void m_float(float f) {} + @Candidate + static void m_float(Float f) {} + @Candidate + static void m_float(F f) {} + + @Candidate(applicable=Phase.BASIC, mostSpecific=true) + static void m_double(double d) {} + @Candidate + static void m_double(Double d) {} + @Candidate + static void m_double(D d) {} + + @Candidate(applicable=Phase.BASIC, mostSpecific=true) + static void m_char(char c) {} + @Candidate + static void m_char(Character c) {} + @Candidate + static void m_char(C c) {} + + @Candidate(applicable=Phase.BASIC, mostSpecific=true) + static void m_bool(boolean z) {} + @Candidate + static void m_bool(Boolean z) {} + @Candidate + static void m_bool(Z z) {} + + { + m_byte((byte)0); + m_short((short)0); + m_int(0); + m_long(0L); + m_float(0.0f); + m_double(0.0); + m_char('?'); + m_bool(false); + } +} diff --git a/langtools/test/tools/javac/resolve/tests/PrimitiveOverReferenceOverVarargs.java b/langtools/test/tools/javac/resolve/tests/PrimitiveOverReferenceOverVarargs.java new file mode 100644 index 00000000000..a07909ede0b --- /dev/null +++ b/langtools/test/tools/javac/resolve/tests/PrimitiveOverReferenceOverVarargs.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2011, 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. + */ + +@TraceResolve +class PrimitiveOverReference { + @Candidate(applicable=Phase.BASIC, mostSpecific=true) + static void m_byte(byte b) {} + @Candidate + static void m_byte(Byte b) {} + @Candidate + static void m_byte(byte... b) {} + @Candidate + static void m_byte(Byte... b) {} + + @Candidate(applicable=Phase.BASIC, mostSpecific=true) + static void m_short(short s) {} + @Candidate + static void m_short(Short s) {} + @Candidate + static void m_short(short... s) {} + @Candidate + static void m_short(Short... s) {} + + @Candidate(applicable=Phase.BASIC, mostSpecific=true) + static void m_int(int i) {} + @Candidate + static void m_int(Integer i) {} + @Candidate + static void m_int(int... i) {} + @Candidate + static void m_int(Integer... i) {} + + @Candidate(applicable=Phase.BASIC, mostSpecific=true) + static void m_long(long l) {} + @Candidate + static void m_long(Long l) {} + @Candidate + static void m_long(long... l) {} + @Candidate + static void m_long(Long... l) {} + + @Candidate(applicable=Phase.BASIC, mostSpecific=true) + static void m_float(float f) {} + @Candidate + static void m_float(Float f) {} + @Candidate + static void m_float(float... f) {} + @Candidate + static void m_float(Float... f) {} + + @Candidate(applicable=Phase.BASIC, mostSpecific=true) + static void m_double(double d) {} + @Candidate + static void m_double(Double d) {} + @Candidate + static void m_double(double... d) {} + @Candidate + static void m_double(Double... d) {} + + @Candidate(applicable=Phase.BASIC, mostSpecific=true) + static void m_char(char c) {} + @Candidate + static void m_char(Character c) {} + @Candidate + static void m_char(char... c) {} + @Candidate + static void m_char(Character... c) {} + + @Candidate(applicable=Phase.BASIC, mostSpecific=true) + static void m_bool(boolean z) {} + @Candidate + static void m_bool(Boolean z) {} + @Candidate + static void m_bool(boolean... z) {} + @Candidate + static void m_bool(Boolean... z) {} + + { + m_byte((byte)0); + m_short((short)0); + m_int(0); + m_long(0L); + m_float(0.0f); + m_double(0.0); + m_char('?'); + m_bool(false); + } +} diff --git a/langtools/test/tools/javac/resolve/tests/PrimitiveOverReferenceVarargsAmbiguous.java b/langtools/test/tools/javac/resolve/tests/PrimitiveOverReferenceVarargsAmbiguous.java new file mode 100644 index 00000000000..80ac69dd95d --- /dev/null +++ b/langtools/test/tools/javac/resolve/tests/PrimitiveOverReferenceVarargsAmbiguous.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2011, 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. + */ + +@TraceResolve(keys={"compiler.err.ref.ambiguous"}) +class PrimitiveOverReferenceVarargsAmbiguous { + @Candidate(applicable=Phase.VARARGS, mostSpecific=false) + static void m_byte(byte... b) {} + @Candidate(applicable=Phase.VARARGS, mostSpecific=false) + static void m_byte(Byte... b) {} + + @Candidate(applicable=Phase.VARARGS, mostSpecific=false) + static void m_short(short... s) {} + @Candidate(applicable=Phase.VARARGS, mostSpecific=false) + static void m_short(Short... s) {} + + @Candidate(applicable=Phase.VARARGS, mostSpecific=false) + static void m_int(int... i) {} + @Candidate(applicable=Phase.VARARGS, mostSpecific=false) + static void m_int(Integer... i) {} + + @Candidate(applicable=Phase.VARARGS, mostSpecific=false) + static void m_long(long... l) {} + @Candidate(applicable=Phase.VARARGS, mostSpecific=false) + static void m_long(Long... l) {} + + @Candidate(applicable=Phase.VARARGS, mostSpecific=false) + static void m_float(float... f) {} + @Candidate(applicable=Phase.VARARGS, mostSpecific=false) + static void m_float(Float... f) {} + + @Candidate(applicable=Phase.VARARGS, mostSpecific=false) + static void m_double(double... d) {} + @Candidate(applicable=Phase.VARARGS, mostSpecific=false) + static void m_double(Double... d) {} + + @Candidate(applicable=Phase.VARARGS, mostSpecific=false) + static void m_char(char... c) {} + @Candidate(applicable=Phase.VARARGS, mostSpecific=false) + static void m_char(Character... c) {} + + @Candidate(applicable=Phase.VARARGS, mostSpecific=false) + static void m_bool(boolean... z) {} + @Candidate(applicable=Phase.VARARGS, mostSpecific=false) + static void m_bool(Boolean... z) {} + + { + m_byte((byte)0); + m_short((short)0); + m_int(0); + m_long(0L); + m_float(0.0f); + m_double(0.0); + m_char('?'); + m_bool(false); + } +} diff --git a/langtools/test/tools/javac/resolve/tests/PrimitiveOverload.java b/langtools/test/tools/javac/resolve/tests/PrimitiveOverload.java new file mode 100644 index 00000000000..752b697f4cb --- /dev/null +++ b/langtools/test/tools/javac/resolve/tests/PrimitiveOverload.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2011, 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. + */ + +@TraceResolve +class PrimitiveOverload { + + @Candidate(applicable=Phase.BASIC, mostSpecific=true) + static void m_byte(byte b) {} + @Candidate(applicable=Phase.BASIC, mostSpecific=false) + static void m_byte(short b) {} + @Candidate(applicable=Phase.BASIC, mostSpecific=false) + static void m_byte(int b) {} + @Candidate(applicable=Phase.BASIC, mostSpecific=false) + static void m_byte(long b) {} + @Candidate(applicable=Phase.BASIC, mostSpecific=false) + static void m_byte(float b) {} + @Candidate(applicable=Phase.BASIC, mostSpecific=false) + static void m_byte(double b) {} + + @Candidate + static void m_short(byte b) {} + @Candidate(applicable=Phase.BASIC, mostSpecific=true) + static void m_short(short b) {} + @Candidate(applicable=Phase.BASIC, mostSpecific=false) + static void m_short(int b) {} + @Candidate(applicable=Phase.BASIC, mostSpecific=false) + static void m_short(long b) {} + @Candidate(applicable=Phase.BASIC, mostSpecific=false) + static void m_short(float b) {} + @Candidate(applicable=Phase.BASIC, mostSpecific=false) + static void m_short(double b) {} + + @Candidate + static void m_int(byte b) {} + @Candidate + static void m_int(short b) {} + @Candidate(applicable=Phase.BASIC, mostSpecific=true) + static void m_int(int b) {} + @Candidate(applicable=Phase.BASIC, mostSpecific=false) + static void m_int(long b) {} + @Candidate(applicable=Phase.BASIC, mostSpecific=false) + static void m_int(float b) {} + @Candidate(applicable=Phase.BASIC, mostSpecific=false) + static void m_int(double b) {} + + @Candidate + static void m_long(byte b) {} + @Candidate + static void m_long(short b) {} + @Candidate + static void m_long(int b) {} + @Candidate(applicable=Phase.BASIC, mostSpecific=true) + static void m_long(long b) {} + @Candidate(applicable=Phase.BASIC, mostSpecific=false) + static void m_long(float b) {} + @Candidate(applicable=Phase.BASIC, mostSpecific=false) + static void m_long(double b) {} + + @Candidate + static void m_float(byte b) {} + @Candidate + static void m_float(short b) {} + @Candidate + static void m_float(int b) {} + @Candidate + static void m_float(long b) {} + @Candidate(applicable=Phase.BASIC, mostSpecific=true) + static void m_float(float b) {} + @Candidate(applicable=Phase.BASIC, mostSpecific=false) + static void m_float(double b) {} + + @Candidate + static void m_double(byte b) {} + @Candidate + static void m_double(short b) {} + @Candidate + static void m_double(int b) {} + @Candidate + static void m_double(long b) {} + @Candidate + static void m_double(float b) {} + @Candidate(applicable=Phase.BASIC, mostSpecific=true) + static void m_double(double b) {} + + { + m_byte((byte)0); + m_short((short)0); + m_int(0); + m_long(0L); + m_float(0.0f); + m_double(0.0); + } +} diff --git a/langtools/test/tools/javac/resolve/tests/PrimitiveReturnTypeInference.java b/langtools/test/tools/javac/resolve/tests/PrimitiveReturnTypeInference.java new file mode 100644 index 00000000000..04a15066cbb --- /dev/null +++ b/langtools/test/tools/javac/resolve/tests/PrimitiveReturnTypeInference.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011, 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. + */ + +@TraceResolve +class PrimitiveReturnTypeInference { + @Candidate(applicable=Phase.BASIC, sig="()java.lang.Byte", mostSpecific=true) + static B m_byte() { return null; } + + @Candidate(applicable=Phase.BASIC, sig="()java.lang.Short", mostSpecific=true) + static S m_short() { return null; } + + @Candidate(applicable=Phase.BASIC, sig="()java.lang.Integer", mostSpecific=true) + static I m_int() { return null; } + + @Candidate(applicable=Phase.BASIC, sig="()java.lang.Long", mostSpecific=true) + static L m_long() { return null; } + + @Candidate(applicable=Phase.BASIC, sig="()java.lang.Float", mostSpecific=true) + static F m_float() { return null; } + + @Candidate(applicable=Phase.BASIC, sig="()java.lang.Double", mostSpecific=true) + static D m_double() { return null; } + + @Candidate(applicable=Phase.BASIC, sig="()java.lang.Character", mostSpecific=true) + static C m_char() { return null; } + + @Candidate(applicable=Phase.BASIC, sig="()java.lang.Boolean", mostSpecific=true) + static Z m_bool() { return null; } + + { + byte b = m_byte(); + short s = m_short(); + int i = m_int(); + long l = m_long(); + float f = m_float(); + double d = m_double(); + char c= m_char(); + boolean z = m_bool(); + } +} diff --git a/langtools/test/tools/javac/resolve/tests/ReferenceOverInferred.java b/langtools/test/tools/javac/resolve/tests/ReferenceOverInferred.java new file mode 100644 index 00000000000..ed687739f0e --- /dev/null +++ b/langtools/test/tools/javac/resolve/tests/ReferenceOverInferred.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2011, 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. + */ + +@TraceResolve +class PrimitiveOverInferred { + @Candidate(applicable=Phase.BOX, mostSpecific=true) + static void m_byte(Byte b) {} + @Candidate(applicable=Phase.BOX, sig="(java.lang.Byte)void") + static void m_byte(B b) {} + + @Candidate(applicable=Phase.BOX, mostSpecific=true) + static void m_short(Short s) {} + @Candidate(applicable=Phase.BOX, sig="(java.lang.Short)void") + static void m_short(S s) {} + + @Candidate(applicable=Phase.BOX, mostSpecific=true) + static void m_int(Integer i) {} + @Candidate(applicable=Phase.BOX, sig="(java.lang.Integer)void") + static void m_int(I i) {} + + @Candidate(applicable=Phase.BOX, mostSpecific=true) + static void m_long(Long l) {} + @Candidate(applicable=Phase.BOX, sig="(java.lang.Long)void") + static void m_long(L l) {} + + @Candidate(applicable=Phase.BOX, mostSpecific=true) + static void m_float(Float f) {} + @Candidate(applicable=Phase.BOX, sig="(java.lang.Float)void") + static void m_float(F f) {} + + @Candidate(applicable=Phase.BOX, mostSpecific=true) + static void m_double(Double d) {} + @Candidate(applicable=Phase.BOX, sig="(java.lang.Double)void") + static void m_double(D d) {} + + @Candidate(applicable=Phase.BOX, mostSpecific=true) + static void m_char(Character c) {} + @Candidate(applicable=Phase.BOX, sig="(java.lang.Character)void") + static void m_char(C c) {} + + @Candidate(applicable=Phase.BOX, mostSpecific=true) + static void m_bool(Boolean z) {} + @Candidate(applicable=Phase.BOX, sig="(java.lang.Boolean)void") + static void m_bool(Z z) {} + + { + m_byte((byte)0); + m_short((short)0); + m_int(0); + m_long(0L); + m_float(0.0f); + m_double(0.0); + m_char('?'); + m_bool(false); + } +} diff --git a/langtools/test/tools/javac/resolve/tests/ReferenceOverVarargs.java b/langtools/test/tools/javac/resolve/tests/ReferenceOverVarargs.java new file mode 100644 index 00000000000..c089e2d3e6c --- /dev/null +++ b/langtools/test/tools/javac/resolve/tests/ReferenceOverVarargs.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2011, 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. + */ + +@TraceResolve +class ReferenceOverVarargs { + + @Candidate(applicable=Phase.BOX, mostSpecific=true) + static void m_byte(Byte b) {} + @Candidate + static void m_byte(byte... b) {} + @Candidate + static void m_byte(Byte... b) {} + + @Candidate(applicable=Phase.BOX, mostSpecific=true) + static void m_short(Short s) {} + @Candidate + static void m_short(short... s) {} + @Candidate + static void m_short(Short... s) {} + + @Candidate(applicable=Phase.BOX, mostSpecific=true) + static void m_int(Integer i) {} + @Candidate + static void m_int(int... i) {} + @Candidate + static void m_int(Integer... i) {} + + @Candidate(applicable=Phase.BOX, mostSpecific=true) + static void m_long(Long l) {} + @Candidate + static void m_long(long... l) {} + @Candidate + static void m_long(Long... l) {} + + @Candidate(applicable=Phase.BOX, mostSpecific=true) + static void m_float(Float f) {} + @Candidate + static void m_float(float... f) {} + @Candidate + static void m_float(Float... f) {} + + @Candidate(applicable=Phase.BOX, mostSpecific=true) + static void m_double(Double d) {} + @Candidate + static void m_double(double... d) {} + @Candidate + static void m_double(Double... d) {} + + @Candidate(applicable=Phase.BOX, mostSpecific=true) + static void m_char(Character c) {} + @Candidate + static void m_char(char... c) {} + @Candidate + static void m_char(Character... c) {} + + @Candidate(applicable=Phase.BOX, mostSpecific=true) + static void m_bool(Boolean z) {} + @Candidate + static void m_bool(boolean... z) {} + @Candidate + static void m_bool(Boolean... z) {} + + { + m_byte((byte)0); + m_short((short)0); + m_int(0); + m_long(0L); + m_float(0.0f); + m_double(0.0); + m_char('?'); + m_bool(false); + } +} diff --git a/langtools/test/tools/javac/resolve/tests/ReferenceOverload.java b/langtools/test/tools/javac/resolve/tests/ReferenceOverload.java new file mode 100644 index 00000000000..578bc51a68c --- /dev/null +++ b/langtools/test/tools/javac/resolve/tests/ReferenceOverload.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2011, 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. + */ + +@TraceResolve +class ReferenceOverload { + + static class A {} + static class B extends A {} + static class C extends B {} + static class D extends C {} + static class E extends D {} + + @Candidate(applicable=Phase.BASIC, mostSpecific=true) + static void m_A(A a) {} + @Candidate + static void m_A(B a) {} + @Candidate + static void m_A(C a) {} + @Candidate + static void m_A(D a) {} + @Candidate + static void m_A(E a) {} + + @Candidate(applicable=Phase.BASIC, mostSpecific=false) + static void m_B(A b) {} + @Candidate(applicable=Phase.BASIC, mostSpecific=true) + static void m_B(B b) {} + @Candidate + static void m_B(C b) {} + @Candidate + static void m_B(D b) {} + @Candidate + static void m_B(E b) {} + + @Candidate(applicable=Phase.BASIC, mostSpecific=false) + static void m_C(A c) {} + @Candidate(applicable=Phase.BASIC, mostSpecific=false) + static void m_C(B c) {} + @Candidate(applicable=Phase.BASIC, mostSpecific=true) + static void m_C(C c) {} + @Candidate + static void m_C(D c) {} + @Candidate + static void m_C(E c) {} + + @Candidate(applicable=Phase.BASIC, mostSpecific=false) + static void m_D(A d) {} + @Candidate(applicable=Phase.BASIC, mostSpecific=false) + static void m_D(B d) {} + @Candidate(applicable=Phase.BASIC, mostSpecific=false) + static void m_D(C d) {} + @Candidate(applicable=Phase.BASIC, mostSpecific=true) + static void m_D(D d) {} + @Candidate + static void m_D(E d) {} + + @Candidate(applicable=Phase.BASIC, mostSpecific=false) + static void m_E(A e) {} + @Candidate(applicable=Phase.BASIC, mostSpecific=false) + static void m_E(B e) {} + @Candidate(applicable=Phase.BASIC, mostSpecific=false) + static void m_E(C e) {} + @Candidate(applicable=Phase.BASIC, mostSpecific=false) + static void m_E(D e) {} + @Candidate(applicable=Phase.BASIC, mostSpecific=true) + static void m_E(E e) {} + + { + m_A((A)null); + m_B((B)null); + m_C((C)null); + m_D((D)null); + m_E((E)null); + } +} From 51c07ae53a07b7d715912d077d8b6273111a40d4 Mon Sep 17 00:00:00 2001 From: Jennifer Godinez Date: Mon, 24 Oct 2011 09:58:47 -0700 Subject: [PATCH 040/107] 6604109: javax.print.PrintServiceLookup.lookupPrintServices fails SOMETIMES for Cups Reviewed-by: bae, prr --- jdk/src/solaris/classes/sun/print/UnixPrintServiceLookup.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/solaris/classes/sun/print/UnixPrintServiceLookup.java b/jdk/src/solaris/classes/sun/print/UnixPrintServiceLookup.java index f65a571abd2..e60765900b5 100644 --- a/jdk/src/solaris/classes/sun/print/UnixPrintServiceLookup.java +++ b/jdk/src/solaris/classes/sun/print/UnixPrintServiceLookup.java @@ -189,7 +189,7 @@ public class UnixPrintServiceLookup extends PrintServiceLookup if (printServices == null) { return new PrintService[0]; } else { - return printServices; + return (PrintService[])printServices.clone(); } } From 1469ebc6da4d8b22ee13ce081f850111af281f24 Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Tue, 25 Oct 2011 15:40:34 +0100 Subject: [PATCH 041/107] 7104618: MessageInfo.java is failing after lexer changes Two langtools regression tests cannot be built due to a bad import statement Reviewed-by: jjg --- langtools/test/tools/javac/diags/ArgTypeCompilerFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/langtools/test/tools/javac/diags/ArgTypeCompilerFactory.java b/langtools/test/tools/javac/diags/ArgTypeCompilerFactory.java index 0c8c2153817..1544e57773b 100644 --- a/langtools/test/tools/javac/diags/ArgTypeCompilerFactory.java +++ b/langtools/test/tools/javac/diags/ArgTypeCompilerFactory.java @@ -35,7 +35,7 @@ import com.sun.tools.javac.code.*; import com.sun.tools.javac.file.*; import com.sun.tools.javac.main.Main; import com.sun.tools.javac.main.JavaCompiler; -import com.sun.tools.javac.parser.Token; +import com.sun.tools.javac.parser.Tokens.TokenKind; import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.AbstractDiagnosticFormatter.SimpleConfiguration; import javax.lang.model.SourceVersion; @@ -319,7 +319,7 @@ class ArgTypeCompilerFactory implements Example.Compiler.Factory { return "modifier"; if (o instanceof KindName) return "symbol kind"; - if (o instanceof Token) + if (o instanceof TokenKind) return "token"; if (o instanceof Symbol) return "symbol"; From d20f9f51bc1fa35eee20112666867386912cd62c Mon Sep 17 00:00:00 2001 From: Jonathan Gibbons Date: Tue, 25 Oct 2011 10:48:05 -0700 Subject: [PATCH 042/107] 7104039: refactor/cleanup javac Paths class Reviewed-by: mcimadamore --- .../classes/com/sun/tools/apt/main/Main.java | 4 +- .../tools/javac/file/JavacFileManager.java | 75 +- .../com/sun/tools/javac/file/Locations.java | 769 ++++++++++++++++++ .../com/sun/tools/javac/file/Paths.java | 540 ------------ .../tools/javac/nio/JavacPathFileManager.java | 8 +- .../sun/tools/javac/util/BaseFileManager.java | 12 +- .../com/sun/tools/javadoc/DocletInvoker.java | 2 +- 7 files changed, 789 insertions(+), 621 deletions(-) create mode 100644 langtools/src/share/classes/com/sun/tools/javac/file/Locations.java delete mode 100644 langtools/src/share/classes/com/sun/tools/javac/file/Paths.java diff --git a/langtools/src/share/classes/com/sun/tools/apt/main/Main.java b/langtools/src/share/classes/com/sun/tools/apt/main/Main.java index 5c2cfcc4b7d..80e7e1dbda5 100644 --- a/langtools/src/share/classes/com/sun/tools/apt/main/Main.java +++ b/langtools/src/share/classes/com/sun/tools/apt/main/Main.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2011, 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 @@ -56,7 +56,7 @@ import com.sun.tools.apt.comp.UsageMessageNeededException; import com.sun.tools.apt.util.Bark; import com.sun.mirror.apt.AnnotationProcessorFactory; -import static com.sun.tools.javac.file.Paths.pathToURLs; +import static com.sun.tools.javac.file.Locations.pathToURLs; /** This class provides a commandline interface to the apt build-time * tool. diff --git a/langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java b/langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java index ae6cf2d2757..78774566915 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java +++ b/langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java @@ -54,17 +54,14 @@ import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; -import com.sun.tools.javac.code.Lint; import com.sun.tools.javac.file.RelativePath.RelativeFile; import com.sun.tools.javac.file.RelativePath.RelativeDirectory; -import com.sun.tools.javac.main.OptionName; import com.sun.tools.javac.util.BaseFileManager; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.ListBuffer; import static javax.tools.StandardLocation.*; -import static com.sun.tools.javac.main.OptionName.*; /** * This class provides access to the source, class and other files @@ -89,23 +86,9 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil private boolean contextUseOptimizedZip; private ZipFileIndexCache zipFileIndexCache; - private final File uninited = new File("U N I N I T E D"); - private final Set sourceOrClass = EnumSet.of(JavaFileObject.Kind.SOURCE, JavaFileObject.Kind.CLASS); - /** The standard output directory, primarily used for classes. - * Initialized by the "-d" option. - * If classOutDir = null, files are written into same directory as the sources - * they were generated from. - */ - private File classOutDir = uninited; - - /** The output directory, used when generating sources while processing annotations. - * Initialized by the "-s" option. - */ - private File sourceOutDir = uninited; - protected boolean mmappedIO; protected boolean ignoreSymbolFile; @@ -169,7 +152,7 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil @Override public boolean isDefaultBootClassPath() { - return searchPaths.isDefaultBootClassPath(); + return locations.isDefaultBootClassPath(); } public JavaFileObject getFileForInput(String name) { @@ -483,7 +466,7 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil */ private Archive openArchive(File zipFileName, boolean useOptimizedZip) throws IOException { File origZipFileName = zipFileName; - if (!ignoreSymbolFile && searchPaths.isDefaultBootClassPathRtJar(zipFileName)) { + if (!ignoreSymbolFile && locations.isDefaultBootClassPathRtJar(zipFileName)) { File file = zipFileName.getParentFile().getParentFile(); // ${java.home} if (new File(file.getName()).equals(new File("jre"))) file = file.getParentFile(); @@ -770,7 +753,7 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil } else if (location == SOURCE_OUTPUT) { dir = (getSourceOutDir() != null ? getSourceOutDir() : getClassOutDir()); } else { - Iterable path = searchPaths.getPathForLocation(location); + Iterable path = locations.getLocation(location); dir = null; for (File f: path) { dir = f; @@ -805,64 +788,20 @@ public class JavacFileManager extends BaseFileManager implements StandardJavaFil throws IOException { nullCheck(location); - searchPaths.lazy(); - - final File dir = location.isOutputLocation() ? getOutputDirectory(path) : null; - - if (location == CLASS_OUTPUT) - classOutDir = getOutputLocation(dir, D); - else if (location == SOURCE_OUTPUT) - sourceOutDir = getOutputLocation(dir, S); - else - searchPaths.setPathForLocation(location, path); - } - // where - private File getOutputDirectory(Iterable path) throws IOException { - if (path == null) - return null; - Iterator pathIter = path.iterator(); - if (!pathIter.hasNext()) - throw new IllegalArgumentException("empty path for directory"); - File dir = pathIter.next(); - if (pathIter.hasNext()) - throw new IllegalArgumentException("path too long for directory"); - if (!dir.exists()) - throw new FileNotFoundException(dir + ": does not exist"); - else if (!dir.isDirectory()) - throw new IOException(dir + ": not a directory"); - return dir; - } - - private File getOutputLocation(File dir, OptionName defaultOptionName) { - if (dir != null) - return dir; - String arg = options.get(defaultOptionName); - if (arg == null) - return null; - return new File(arg); + locations.setLocation(location, path); } public Iterable getLocation(Location location) { nullCheck(location); - searchPaths.lazy(); - if (location == CLASS_OUTPUT) { - return (getClassOutDir() == null ? null : List.of(getClassOutDir())); - } else if (location == SOURCE_OUTPUT) { - return (getSourceOutDir() == null ? null : List.of(getSourceOutDir())); - } else - return searchPaths.getPathForLocation(location); + return locations.getLocation(location); } private File getClassOutDir() { - if (classOutDir == uninited) - classOutDir = getOutputLocation(null, D); - return classOutDir; + return locations.getOutputLocation(CLASS_OUTPUT); } private File getSourceOutDir() { - if (sourceOutDir == uninited) - sourceOutDir = getOutputLocation(null, S); - return sourceOutDir; + return locations.getOutputLocation(SOURCE_OUTPUT); } /** diff --git a/langtools/src/share/classes/com/sun/tools/javac/file/Locations.java b/langtools/src/share/classes/com/sun/tools/javac/file/Locations.java new file mode 100644 index 00000000000..8ef1eeef7f4 --- /dev/null +++ b/langtools/src/share/classes/com/sun/tools/javac/file/Locations.java @@ -0,0 +1,769 @@ +/* + * Copyright (c) 2003, 2011, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package com.sun.tools.javac.file; + +import java.io.FileNotFoundException; +import java.util.Iterator; +import java.io.File; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumMap; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.zip.ZipFile; +import javax.tools.JavaFileManager.Location; +import javax.tools.StandardLocation; + +import com.sun.tools.javac.code.Lint; +import com.sun.tools.javac.main.OptionName; +import com.sun.tools.javac.util.ListBuffer; +import com.sun.tools.javac.util.Log; +import com.sun.tools.javac.util.Options; + +import javax.tools.JavaFileManager; +import static javax.tools.StandardLocation.*; +import static com.sun.tools.javac.main.OptionName.*; + +/** This class converts command line arguments, environment variables + * and system properties (in File.pathSeparator-separated String form) + * into a boot class path, user class path, and source path (in + * Collection form). + * + *

This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + */ +public class Locations { + + /** The log to use for warning output */ + private Log log; + + /** Collection of command-line options */ + private Options options; + + /** Handler for -Xlint options */ + private Lint lint; + + /** Access to (possibly cached) file info */ + private FSInfo fsInfo; + + /** Whether to warn about non-existent path elements */ + private boolean warn; + + // TODO: remove need for this + private boolean inited = false; // TODO? caching bad? + + public Locations() { + initHandlers(); + } + + public void update(Log log, Options options, Lint lint, FSInfo fsInfo) { + this.log = log; + this.options = options; + this.lint = lint; + this.fsInfo = fsInfo; + } + + public Collection bootClassPath() { + return getLocation(PLATFORM_CLASS_PATH); + } + + public boolean isDefaultBootClassPath() { + BootClassPathLocationHandler h = + (BootClassPathLocationHandler) getHandler(PLATFORM_CLASS_PATH); + return h.isDefault(); + } + + boolean isDefaultBootClassPathRtJar(File file) { + BootClassPathLocationHandler h = + (BootClassPathLocationHandler) getHandler(PLATFORM_CLASS_PATH); + return h.isDefaultRtJar(file); + } + + public Collection userClassPath() { + return getLocation(CLASS_PATH); + } + + public Collection sourcePath() { + Collection p = getLocation(SOURCE_PATH); + // TODO: this should be handled by the LocationHandler + return p == null || p.isEmpty() ? null : p; + } + + /** + * Split a path into its elements. Empty path elements will be ignored. + * @param path The path to be split + * @return The elements of the path + */ + private static Iterable getPathEntries(String path) { + return getPathEntries(path, null); + } + + /** + * Split a path into its elements. If emptyPathDefault is not null, all + * empty elements in the path, including empty elements at either end of + * the path, will be replaced with the value of emptyPathDefault. + * @param path The path to be split + * @param emptyPathDefault The value to substitute for empty path elements, + * or null, to ignore empty path elements + * @return The elements of the path + */ + private static Iterable getPathEntries(String path, File emptyPathDefault) { + ListBuffer entries = new ListBuffer(); + int start = 0; + while (start <= path.length()) { + int sep = path.indexOf(File.pathSeparatorChar, start); + if (sep == -1) + sep = path.length(); + if (start < sep) + entries.add(new File(path.substring(start, sep))); + else if (emptyPathDefault != null) + entries.add(emptyPathDefault); + start = sep + 1; + } + return entries; + } + + /** + * Utility class to help evaluate a path option. + * Duplicate entries are ignored, jar class paths can be expanded. + */ + private class Path extends LinkedHashSet { + private static final long serialVersionUID = 0; + + private boolean expandJarClassPaths = false; + private Set canonicalValues = new HashSet(); + + public Path expandJarClassPaths(boolean x) { + expandJarClassPaths = x; + return this; + } + + /** What to use when path element is the empty string */ + private File emptyPathDefault = null; + + public Path emptyPathDefault(File x) { + emptyPathDefault = x; + return this; + } + + public Path() { super(); } + + public Path addDirectories(String dirs, boolean warn) { + boolean prev = expandJarClassPaths; + expandJarClassPaths = true; + try { + if (dirs != null) + for (File dir : getPathEntries(dirs)) + addDirectory(dir, warn); + return this; + } finally { + expandJarClassPaths = prev; + } + } + + public Path addDirectories(String dirs) { + return addDirectories(dirs, warn); + } + + private void addDirectory(File dir, boolean warn) { + if (!dir.isDirectory()) { + if (warn) + log.warning(Lint.LintCategory.PATH, + "dir.path.element.not.found", dir); + return; + } + + File[] files = dir.listFiles(); + if (files == null) + return; + + for (File direntry : files) { + if (isArchive(direntry)) + addFile(direntry, warn); + } + } + + public Path addFiles(String files, boolean warn) { + if (files != null) { + addFiles(getPathEntries(files, emptyPathDefault), warn); + } + return this; + } + + public Path addFiles(String files) { + return addFiles(files, warn); + } + + public Path addFiles(Iterable files, boolean warn) { + if (files != null) { + for (File file: files) + addFile(file, warn); + } + return this; + } + + public Path addFiles(Iterable files) { + return addFiles(files, warn); + } + + public void addFile(File file, boolean warn) { + if (contains(file)) { + // discard duplicates + return; + } + + if (! fsInfo.exists(file)) { + /* No such file or directory exists */ + if (warn) { + log.warning(Lint.LintCategory.PATH, + "path.element.not.found", file); + } + super.add(file); + return; + } + + File canonFile = fsInfo.getCanonicalFile(file); + if (canonicalValues.contains(canonFile)) { + /* Discard duplicates and avoid infinite recursion */ + return; + } + + if (fsInfo.isFile(file)) { + /* File is an ordinary file. */ + if (!isArchive(file)) { + /* Not a recognized extension; open it to see if + it looks like a valid zip file. */ + try { + ZipFile z = new ZipFile(file); + z.close(); + if (warn) { + log.warning(Lint.LintCategory.PATH, + "unexpected.archive.file", file); + } + } catch (IOException e) { + // FIXME: include e.getLocalizedMessage in warning + if (warn) { + log.warning(Lint.LintCategory.PATH, + "invalid.archive.file", file); + } + return; + } + } + } + + /* Now what we have left is either a directory or a file name + conforming to archive naming convention */ + super.add(file); + canonicalValues.add(canonFile); + + if (expandJarClassPaths && fsInfo.isFile(file)) + addJarClassPath(file, warn); + } + + // Adds referenced classpath elements from a jar's Class-Path + // Manifest entry. In some future release, we may want to + // update this code to recognize URLs rather than simple + // filenames, but if we do, we should redo all path-related code. + private void addJarClassPath(File jarFile, boolean warn) { + try { + for (File f: fsInfo.getJarClassPath(jarFile)) { + addFile(f, warn); + } + } catch (IOException e) { + log.error("error.reading.file", jarFile, JavacFileManager.getMessage(e)); + } + } + } + + /** + * Base class for handling support for the representation of Locations. + * Implementations are responsible for handling the interactions between + * the command line options for a location, and API access via setLocation. + * @see #initHandlers + * @see #getHandler + */ + protected abstract class LocationHandler { + final Location location; + final Set options; + + /** + * Create a handler. The location and options provide a way to map + * from a location or an option to the corresponding handler. + * @see #initHandlers + */ + protected LocationHandler(Location location, OptionName... options) { + this.location = location; + this.options = EnumSet.copyOf(Arrays.asList(options)); + } + + // TODO: TEMPORARY, while Options still used for command line options + void update(Options optionTable) { + for (OptionName o: options) { + String v = optionTable.get(o); + if (v != null) { + handleOption(o, v); + } + } + } + + /** @see JavaFileManager#handleOption. */ + abstract boolean handleOption(OptionName option, String value); + /** @see JavaFileManager#getLocation. */ + abstract Collection getLocation(); + /** @see JavaFileManager#setLocation. */ + abstract void setLocation(Iterable files) throws IOException; + } + + /** + * General purpose implementation for output locations, + * such as -d/CLASS_OUTPUT and -s/SOURCE_OUTPUT. + * All options are treated as equivalent (i.e. aliases.) + * The value is a single file, possibly null. + */ + private class OutputLocationHandler extends LocationHandler { + private File outputDir; + + OutputLocationHandler(Location location, OptionName... options) { + super(location, options); + } + + @Override + boolean handleOption(OptionName option, String value) { + if (!options.contains(option)) + return false; + + // TODO: could/should validate outputDir exists and is a directory + // need to decide how best to report issue for benefit of + // direct API call on JavaFileManager.handleOption(specifies IAE) + // vs. command line decoding. + outputDir = new File(value); + return true; + } + + @Override + Collection getLocation() { + return (outputDir == null) ? null : Collections.singleton(outputDir); + } + + @Override + void setLocation(Iterable files) throws IOException { + if (files == null) { + outputDir = null; + } else { + Iterator pathIter = files.iterator(); + if (!pathIter.hasNext()) + throw new IllegalArgumentException("empty path for directory"); + File dir = pathIter.next(); + if (pathIter.hasNext()) + throw new IllegalArgumentException("path too long for directory"); + if (!dir.exists()) + throw new FileNotFoundException(dir + ": does not exist"); + else if (!dir.isDirectory()) + throw new IOException(dir + ": not a directory"); + outputDir = dir; + } + } + } + + /** + * General purpose implementation for search path locations, + * such as -sourcepath/SOURCE_PATH and -processorPath/ANNOTATION_PROCESS_PATH. + * All options are treated as equivalent (i.e. aliases.) + * The value is an ordered set of files and/or directories. + */ + private class SimpleLocationHandler extends LocationHandler { + protected Collection searchPath; + + SimpleLocationHandler(Location location, OptionName... options) { + super(location, options); + } + + @Override + boolean handleOption(OptionName option, String value) { + if (!options.contains(option)) + return false; + searchPath = value == null ? null : + Collections.unmodifiableCollection(computePath(value)); + return true; + } + + protected Path computePath(String value) { + return new Path().addFiles(value); + } + + @Override + Collection getLocation() { + return searchPath; + } + + @Override + void setLocation(Iterable files) { + Path p; + if (files == null) { + p = computePath(null); + } else { + p = new Path().addFiles(files); + } + searchPath = Collections.unmodifiableCollection(p); + } + } + + /** + * Subtype of SimpleLocationHandler for -classpath/CLASS_PATH. + * If no value is given, a default is provided, based on system properties + * and other values. + */ + private class ClassPathLocationHandler extends SimpleLocationHandler { + ClassPathLocationHandler() { + super(StandardLocation.CLASS_PATH, + OptionName.CLASSPATH, OptionName.CP); + } + + @Override + Collection getLocation() { + lazy(); + return searchPath; + } + + @Override + protected Path computePath(String value) { + String cp = value; + + // CLASSPATH environment variable when run from `javac'. + if (cp == null) cp = System.getProperty("env.class.path"); + + // If invoked via a java VM (not the javac launcher), use the + // platform class path + if (cp == null && System.getProperty("application.home") == null) + cp = System.getProperty("java.class.path"); + + // Default to current working directory. + if (cp == null) cp = "."; + + return new Path() + .expandJarClassPaths(true) // Only search user jars for Class-Paths + .emptyPathDefault(new File(".")) // Empty path elt ==> current directory + .addFiles(cp); + } + + private void lazy() { + if (searchPath == null) + setLocation(null); + } + } + + /** + * Custom subtype of LocationHandler for PLATFORM_CLASS_PATH. + * Various options are supported for different components of the + * platform class path. + * Setting a value with setLocation overrides all existing option values. + * Setting any option overrides any value set with setLocation, and reverts + * to using default values for options that have not been set. + * Setting -bootclasspath or -Xbootclasspath overrides any existing + * value for -Xbootclasspath/p: and -Xbootclasspath/a:. + */ + private class BootClassPathLocationHandler extends LocationHandler { + private Collection searchPath; + final Map optionValues = new EnumMap(OptionName.class); + + /** + * rt.jar as found on the default bootclasspath. + * If the user specified a bootclasspath, null is used. + */ + private File defaultBootClassPathRtJar = null; + + /** + * Is bootclasspath the default? + */ + private boolean isDefaultBootClassPath; + + BootClassPathLocationHandler() { + super(StandardLocation.PLATFORM_CLASS_PATH, + OptionName.BOOTCLASSPATH, OptionName.XBOOTCLASSPATH, + OptionName.XBOOTCLASSPATH_PREPEND, + OptionName.XBOOTCLASSPATH_APPEND, + OptionName.ENDORSEDDIRS, OptionName.DJAVA_ENDORSED_DIRS, + OptionName.EXTDIRS, OptionName.DJAVA_EXT_DIRS); + } + + boolean isDefault() { + lazy(); + return isDefaultBootClassPath; + } + + boolean isDefaultRtJar(File file) { + lazy(); + return file.equals(defaultBootClassPathRtJar); + } + + @Override + boolean handleOption(OptionName option, String value) { + if (!options.contains(option)) + return false; + + option = canonicalize(option); + optionValues.put(option, value); + if (option == BOOTCLASSPATH) { + optionValues.remove(XBOOTCLASSPATH_PREPEND); + optionValues.remove(XBOOTCLASSPATH_APPEND); + } + searchPath = null; // reset to "uninitialized" + return true; + } + // where + // TODO: would be better if option aliasing was handled at a higher + // level + private OptionName canonicalize(OptionName option) { + switch (option) { + case XBOOTCLASSPATH: + return OptionName.BOOTCLASSPATH; + case DJAVA_ENDORSED_DIRS: + return OptionName.ENDORSEDDIRS; + case DJAVA_EXT_DIRS: + return OptionName.EXTDIRS; + default: + return option; + } + } + + @Override + Collection getLocation() { + lazy(); + return searchPath; + } + + @Override + void setLocation(Iterable files) { + if (files == null) { + searchPath = null; // reset to "uninitialized" + } else { + defaultBootClassPathRtJar = null; + isDefaultBootClassPath = false; + Path p = new Path().addFiles(files, false); + searchPath = Collections.unmodifiableCollection(p); + optionValues.clear(); + } + } + + Path computePath() { + defaultBootClassPathRtJar = null; + Path path = new Path(); + + String bootclasspathOpt = optionValues.get(BOOTCLASSPATH); + String endorseddirsOpt = optionValues.get(ENDORSEDDIRS); + String extdirsOpt = optionValues.get(EXTDIRS); + String xbootclasspathPrependOpt = optionValues.get(XBOOTCLASSPATH_PREPEND); + String xbootclasspathAppendOpt = optionValues.get(XBOOTCLASSPATH_APPEND); + + path.addFiles(xbootclasspathPrependOpt); + + if (endorseddirsOpt != null) + path.addDirectories(endorseddirsOpt); + else + path.addDirectories(System.getProperty("java.endorsed.dirs"), false); + + if (bootclasspathOpt != null) { + path.addFiles(bootclasspathOpt); + } else { + // Standard system classes for this compiler's release. + String files = System.getProperty("sun.boot.class.path"); + path.addFiles(files, false); + File rt_jar = new File("rt.jar"); + for (File file : getPathEntries(files)) { + if (new File(file.getName()).equals(rt_jar)) + defaultBootClassPathRtJar = file; + } + } + + path.addFiles(xbootclasspathAppendOpt); + + // Strictly speaking, standard extensions are not bootstrap + // classes, but we treat them identically, so we'll pretend + // that they are. + if (extdirsOpt != null) + path.addDirectories(extdirsOpt); + else + path.addDirectories(System.getProperty("java.ext.dirs"), false); + + isDefaultBootClassPath = + (xbootclasspathPrependOpt == null) && + (bootclasspathOpt == null) && + (xbootclasspathAppendOpt == null); + + return path; + } + + private void lazy() { + if (searchPath == null) + searchPath = Collections.unmodifiableCollection(computePath()); + } + } + + Map handlersForLocation; + Map handlersForOption; + + void initHandlers() { + handlersForLocation = new HashMap(); + handlersForOption = new EnumMap(OptionName.class); + + LocationHandler[] handlers = { + new BootClassPathLocationHandler(), + new ClassPathLocationHandler(), + new SimpleLocationHandler(StandardLocation.SOURCE_PATH, OptionName.SOURCEPATH), + new SimpleLocationHandler(StandardLocation.ANNOTATION_PROCESSOR_PATH, OptionName.PROCESSORPATH), + new OutputLocationHandler((StandardLocation.CLASS_OUTPUT), OptionName.D), + new OutputLocationHandler((StandardLocation.SOURCE_OUTPUT), OptionName.S) + }; + + for (LocationHandler h: handlers) { + handlersForLocation.put(h.location, h); + for (OptionName o: h.options) + handlersForOption.put(o, h); + } + } + + boolean handleOption(OptionName option, String value) { + LocationHandler h = handlersForOption.get(option); + return (h == null ? false : h.handleOption(option, value)); + } + + Collection getLocation(Location location) { + LocationHandler h = getHandler(location); + return (h == null ? null : h.getLocation()); + } + + File getOutputLocation(Location location) { + if (!location.isOutputLocation()) + throw new IllegalArgumentException(); + LocationHandler h = getHandler(location); + return ((OutputLocationHandler) h).outputDir; + } + + void setLocation(Location location, Iterable files) throws IOException { + LocationHandler h = getHandler(location); + if (h == null) { + if (location.isOutputLocation()) + h = new OutputLocationHandler(location); + else + h = new SimpleLocationHandler(location); + handlersForLocation.put(location, h); + } + h.setLocation(files); + } + + protected LocationHandler getHandler(Location location) { + location.getClass(); // null check + lazy(); + return handlersForLocation.get(location); + } + +// TOGO + protected void lazy() { + if (!inited) { + warn = lint.isEnabled(Lint.LintCategory.PATH); + + for (LocationHandler h: handlersForLocation.values()) { + h.update(options); + } + + inited = true; + } + } + + /** Is this the name of an archive file? */ + private boolean isArchive(File file) { + String n = file.getName().toLowerCase(); + return fsInfo.isFile(file) + && (n.endsWith(".jar") || n.endsWith(".zip")); + } + + /** + * Utility method for converting a search path string to an array + * of directory and JAR file URLs. + * + * Note that this method is called by apt and the DocletInvoker. + * + * @param path the search path string + * @return the resulting array of directory and JAR file URLs + */ + public static URL[] pathToURLs(String path) { + StringTokenizer st = new StringTokenizer(path, File.pathSeparator); + URL[] urls = new URL[st.countTokens()]; + int count = 0; + while (st.hasMoreTokens()) { + URL url = fileToURL(new File(st.nextToken())); + if (url != null) { + urls[count++] = url; + } + } + if (urls.length != count) { + URL[] tmp = new URL[count]; + System.arraycopy(urls, 0, tmp, 0, count); + urls = tmp; + } + return urls; + } + + /** + * Returns the directory or JAR file URL corresponding to the specified + * local file name. + * + * @param file the File object + * @return the resulting directory or JAR file URL, or null if unknown + */ + private static URL fileToURL(File file) { + String name; + try { + name = file.getCanonicalPath(); + } catch (IOException e) { + name = file.getAbsolutePath(); + } + name = name.replace(File.separatorChar, '/'); + if (!name.startsWith("/")) { + name = "/" + name; + } + // If the file does not exist, then assume that it's a directory + if (!file.isFile()) { + name = name + "/"; + } + try { + return new URL("file", "", name); + } catch (MalformedURLException e) { + throw new IllegalArgumentException(file.toString()); + } + } +} diff --git a/langtools/src/share/classes/com/sun/tools/javac/file/Paths.java b/langtools/src/share/classes/com/sun/tools/javac/file/Paths.java deleted file mode 100644 index 69a74cc79f5..00000000000 --- a/langtools/src/share/classes/com/sun/tools/javac/file/Paths.java +++ /dev/null @@ -1,540 +0,0 @@ -/* - * Copyright (c) 2003, 2011, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ - -package com.sun.tools.javac.file; - -import java.io.File; -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.StringTokenizer; -import java.util.zip.ZipFile; -import javax.tools.JavaFileManager.Location; - -import com.sun.tools.javac.code.Lint; -import com.sun.tools.javac.util.ListBuffer; -import com.sun.tools.javac.util.Log; -import com.sun.tools.javac.util.Options; - -import static javax.tools.StandardLocation.*; -import static com.sun.tools.javac.main.OptionName.*; - -/** This class converts command line arguments, environment variables - * and system properties (in File.pathSeparator-separated String form) - * into a boot class path, user class path, and source path (in - * Collection form). - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class Paths { - - /** The log to use for warning output */ - private Log log; - - /** Collection of command-line options */ - private Options options; - - /** Handler for -Xlint options */ - private Lint lint; - - /** Access to (possibly cached) file info */ - private FSInfo fsInfo; - - public Paths() { - pathsForLocation = new HashMap(16); - } - - public void update(Log log, Options options, Lint lint, FSInfo fsInfo) { - this.log = log; - this.options = options; - this.lint = lint; - this.fsInfo = fsInfo; - } - - /** Whether to warn about non-existent path elements */ - private boolean warn; - - private Map pathsForLocation; - - private boolean inited = false; // TODO? caching bad? - - /** - * rt.jar as found on the default bootclass path. If the user specified a - * bootclasspath, null is used. - */ - private File defaultBootClassPathRtJar = null; - - /** - * Is bootclasspath the default? - */ - private boolean isDefaultBootClassPath; - - Path getPathForLocation(Location location) { - Path path = pathsForLocation.get(location); - if (path == null) - setPathForLocation(location, null); - return pathsForLocation.get(location); - } - - void setPathForLocation(Location location, Iterable path) { - // TODO? if (inited) throw new IllegalStateException - // TODO: otherwise reset sourceSearchPath, classSearchPath as needed - Path p; - if (path == null) { - if (location == CLASS_PATH) - p = computeUserClassPath(); - else if (location == PLATFORM_CLASS_PATH) - p = computeBootClassPath(); // sets isDefaultBootClassPath - else if (location == ANNOTATION_PROCESSOR_PATH) - p = computeAnnotationProcessorPath(); - else if (location == SOURCE_PATH) - p = computeSourcePath(); - else - // no defaults for other paths - p = null; - } else { - if (location == PLATFORM_CLASS_PATH) { - defaultBootClassPathRtJar = null; - isDefaultBootClassPath = false; - } - p = new Path(); - for (File f: path) - p.addFile(f, warn); // TODO: is use of warn appropriate? - } - pathsForLocation.put(location, p); - } - - public boolean isDefaultBootClassPath() { - lazy(); - return isDefaultBootClassPath; - } - - protected void lazy() { - if (!inited) { - warn = lint.isEnabled(Lint.LintCategory.PATH); - - pathsForLocation.put(PLATFORM_CLASS_PATH, computeBootClassPath()); - pathsForLocation.put(CLASS_PATH, computeUserClassPath()); - pathsForLocation.put(SOURCE_PATH, computeSourcePath()); - - inited = true; - } - } - - public Collection bootClassPath() { - lazy(); - return Collections.unmodifiableCollection(getPathForLocation(PLATFORM_CLASS_PATH)); - } - public Collection userClassPath() { - lazy(); - return Collections.unmodifiableCollection(getPathForLocation(CLASS_PATH)); - } - public Collection sourcePath() { - lazy(); - Path p = getPathForLocation(SOURCE_PATH); - return p == null || p.size() == 0 - ? null - : Collections.unmodifiableCollection(p); - } - - boolean isDefaultBootClassPathRtJar(File file) { - return file.equals(defaultBootClassPathRtJar); - } - - /** - * Split a path into its elements. Empty path elements will be ignored. - * @param path The path to be split - * @return The elements of the path - */ - private static Iterable getPathEntries(String path) { - return getPathEntries(path, null); - } - - /** - * Split a path into its elements. If emptyPathDefault is not null, all - * empty elements in the path, including empty elements at either end of - * the path, will be replaced with the value of emptyPathDefault. - * @param path The path to be split - * @param emptyPathDefault The value to substitute for empty path elements, - * or null, to ignore empty path elements - * @return The elements of the path - */ - private static Iterable getPathEntries(String path, File emptyPathDefault) { - ListBuffer entries = new ListBuffer(); - int start = 0; - while (start <= path.length()) { - int sep = path.indexOf(File.pathSeparatorChar, start); - if (sep == -1) - sep = path.length(); - if (start < sep) - entries.add(new File(path.substring(start, sep))); - else if (emptyPathDefault != null) - entries.add(emptyPathDefault); - start = sep + 1; - } - return entries; - } - - private class Path extends LinkedHashSet { - private static final long serialVersionUID = 0; - - private boolean expandJarClassPaths = false; - private Set canonicalValues = new HashSet(); - - public Path expandJarClassPaths(boolean x) { - expandJarClassPaths = x; - return this; - } - - /** What to use when path element is the empty string */ - private File emptyPathDefault = null; - - public Path emptyPathDefault(File x) { - emptyPathDefault = x; - return this; - } - - public Path() { super(); } - - public Path addDirectories(String dirs, boolean warn) { - boolean prev = expandJarClassPaths; - expandJarClassPaths = true; - try { - if (dirs != null) - for (File dir : getPathEntries(dirs)) - addDirectory(dir, warn); - return this; - } finally { - expandJarClassPaths = prev; - } - } - - public Path addDirectories(String dirs) { - return addDirectories(dirs, warn); - } - - private void addDirectory(File dir, boolean warn) { - if (!dir.isDirectory()) { - if (warn) - log.warning(Lint.LintCategory.PATH, - "dir.path.element.not.found", dir); - return; - } - - File[] files = dir.listFiles(); - if (files == null) - return; - - for (File direntry : files) { - if (isArchive(direntry)) - addFile(direntry, warn); - } - } - - public Path addFiles(String files, boolean warn) { - if (files != null) { - for (File file : getPathEntries(files, emptyPathDefault)) - addFile(file, warn); - } - return this; - } - - public Path addFiles(String files) { - return addFiles(files, warn); - } - - public void addFile(File file, boolean warn) { - if (contains(file)) { - // discard duplicates - return; - } - - if (! fsInfo.exists(file)) { - /* No such file or directory exists */ - if (warn) { - log.warning(Lint.LintCategory.PATH, - "path.element.not.found", file); - } - super.add(file); - return; - } - - File canonFile = fsInfo.getCanonicalFile(file); - if (canonicalValues.contains(canonFile)) { - /* Discard duplicates and avoid infinite recursion */ - return; - } - - if (fsInfo.isFile(file)) { - /* File is an ordinary file. */ - if (!isArchive(file)) { - /* Not a recognized extension; open it to see if - it looks like a valid zip file. */ - try { - ZipFile z = new ZipFile(file); - z.close(); - if (warn) { - log.warning(Lint.LintCategory.PATH, - "unexpected.archive.file", file); - } - } catch (IOException e) { - // FIXME: include e.getLocalizedMessage in warning - if (warn) { - log.warning(Lint.LintCategory.PATH, - "invalid.archive.file", file); - } - return; - } - } - } - - /* Now what we have left is either a directory or a file name - conforming to archive naming convention */ - super.add(file); - canonicalValues.add(canonFile); - - if (expandJarClassPaths && fsInfo.isFile(file)) - addJarClassPath(file, warn); - } - - // Adds referenced classpath elements from a jar's Class-Path - // Manifest entry. In some future release, we may want to - // update this code to recognize URLs rather than simple - // filenames, but if we do, we should redo all path-related code. - private void addJarClassPath(File jarFile, boolean warn) { - try { - for (File f: fsInfo.getJarClassPath(jarFile)) { - addFile(f, warn); - } - } catch (IOException e) { - log.error("error.reading.file", jarFile, JavacFileManager.getMessage(e)); - } - } - } - - private Path computeBootClassPath() { - defaultBootClassPathRtJar = null; - Path path = new Path(); - - String bootclasspathOpt = options.get(BOOTCLASSPATH); - String endorseddirsOpt = options.get(ENDORSEDDIRS); - String extdirsOpt = options.get(EXTDIRS); - String xbootclasspathPrependOpt = options.get(XBOOTCLASSPATH_PREPEND); - String xbootclasspathAppendOpt = options.get(XBOOTCLASSPATH_APPEND); - - path.addFiles(xbootclasspathPrependOpt); - - if (endorseddirsOpt != null) - path.addDirectories(endorseddirsOpt); - else - path.addDirectories(System.getProperty("java.endorsed.dirs"), false); - - if (bootclasspathOpt != null) { - path.addFiles(bootclasspathOpt); - } else { - // Standard system classes for this compiler's release. - String files = System.getProperty("sun.boot.class.path"); - path.addFiles(files, false); - File rt_jar = new File("rt.jar"); - for (File file : getPathEntries(files)) { - if (new File(file.getName()).equals(rt_jar)) - defaultBootClassPathRtJar = file; - } - } - - path.addFiles(xbootclasspathAppendOpt); - - // Strictly speaking, standard extensions are not bootstrap - // classes, but we treat them identically, so we'll pretend - // that they are. - if (extdirsOpt != null) - path.addDirectories(extdirsOpt); - else - path.addDirectories(System.getProperty("java.ext.dirs"), false); - - isDefaultBootClassPath = - (xbootclasspathPrependOpt == null) && - (bootclasspathOpt == null) && - (xbootclasspathAppendOpt == null); - - return path; - } - - private Path computeUserClassPath() { - String cp = options.get(CLASSPATH); - - // CLASSPATH environment variable when run from `javac'. - if (cp == null) cp = System.getProperty("env.class.path"); - - // If invoked via a java VM (not the javac launcher), use the - // platform class path - if (cp == null && System.getProperty("application.home") == null) - cp = System.getProperty("java.class.path"); - - // Default to current working directory. - if (cp == null) cp = "."; - - return new Path() - .expandJarClassPaths(true) // Only search user jars for Class-Paths - .emptyPathDefault(new File(".")) // Empty path elt ==> current directory - .addFiles(cp); - } - - private Path computeSourcePath() { - String sourcePathArg = options.get(SOURCEPATH); - if (sourcePathArg == null) - return null; - - return new Path().addFiles(sourcePathArg); - } - - private Path computeAnnotationProcessorPath() { - String processorPathArg = options.get(PROCESSORPATH); - if (processorPathArg == null) - return null; - - return new Path().addFiles(processorPathArg); - } - - /** The actual effective locations searched for sources */ - private Path sourceSearchPath; - - public Collection sourceSearchPath() { - if (sourceSearchPath == null) { - lazy(); - Path sourcePath = getPathForLocation(SOURCE_PATH); - Path userClassPath = getPathForLocation(CLASS_PATH); - sourceSearchPath = sourcePath != null ? sourcePath : userClassPath; - } - return Collections.unmodifiableCollection(sourceSearchPath); - } - - /** The actual effective locations searched for classes */ - private Path classSearchPath; - - public Collection classSearchPath() { - if (classSearchPath == null) { - lazy(); - Path bootClassPath = getPathForLocation(PLATFORM_CLASS_PATH); - Path userClassPath = getPathForLocation(CLASS_PATH); - classSearchPath = new Path(); - classSearchPath.addAll(bootClassPath); - classSearchPath.addAll(userClassPath); - } - return Collections.unmodifiableCollection(classSearchPath); - } - - /** The actual effective locations for non-source, non-class files */ - private Path otherSearchPath; - - Collection otherSearchPath() { - if (otherSearchPath == null) { - lazy(); - Path userClassPath = getPathForLocation(CLASS_PATH); - Path sourcePath = getPathForLocation(SOURCE_PATH); - if (sourcePath == null) - otherSearchPath = userClassPath; - else { - otherSearchPath = new Path(); - otherSearchPath.addAll(userClassPath); - otherSearchPath.addAll(sourcePath); - } - } - return Collections.unmodifiableCollection(otherSearchPath); - } - - /** Is this the name of an archive file? */ - private boolean isArchive(File file) { - String n = file.getName().toLowerCase(); - return fsInfo.isFile(file) - && (n.endsWith(".jar") || n.endsWith(".zip")); - } - - /** - * Utility method for converting a search path string to an array - * of directory and JAR file URLs. - * - * Note that this method is called by apt and the DocletInvoker. - * - * @param path the search path string - * @return the resulting array of directory and JAR file URLs - */ - public static URL[] pathToURLs(String path) { - StringTokenizer st = new StringTokenizer(path, File.pathSeparator); - URL[] urls = new URL[st.countTokens()]; - int count = 0; - while (st.hasMoreTokens()) { - URL url = fileToURL(new File(st.nextToken())); - if (url != null) { - urls[count++] = url; - } - } - if (urls.length != count) { - URL[] tmp = new URL[count]; - System.arraycopy(urls, 0, tmp, 0, count); - urls = tmp; - } - return urls; - } - - /** - * Returns the directory or JAR file URL corresponding to the specified - * local file name. - * - * @param file the File object - * @return the resulting directory or JAR file URL, or null if unknown - */ - private static URL fileToURL(File file) { - String name; - try { - name = file.getCanonicalPath(); - } catch (IOException e) { - name = file.getAbsolutePath(); - } - name = name.replace(File.separatorChar, '/'); - if (!name.startsWith("/")) { - name = "/" + name; - } - // If the file does not exist, then assume that it's a directory - if (!file.isFile()) { - name = name + "/"; - } - try { - return new URL("file", "", name); - } catch (MalformedURLException e) { - throw new IllegalArgumentException(file.toString()); - } - } -} diff --git a/langtools/src/share/classes/com/sun/tools/javac/nio/JavacPathFileManager.java b/langtools/src/share/classes/com/sun/tools/javac/nio/JavacPathFileManager.java index 5ed6334cb41..9a57d4a55d9 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/nio/JavacPathFileManager.java +++ b/langtools/src/share/classes/com/sun/tools/javac/nio/JavacPathFileManager.java @@ -169,7 +169,7 @@ public class JavacPathFileManager extends BaseFileManager implements PathFileMan @Override public boolean isDefaultBootClassPath() { - return searchPaths.isDefaultBootClassPath(); + return locations.isDefaultBootClassPath(); } // @@ -227,13 +227,13 @@ public class JavacPathFileManager extends BaseFileManager implements PathFileMan if (locn instanceof StandardLocation) { switch ((StandardLocation) locn) { case CLASS_PATH: - files = searchPaths.userClassPath(); + files = locations.userClassPath(); break; case PLATFORM_CLASS_PATH: - files = searchPaths.bootClassPath(); + files = locations.bootClassPath(); break; case SOURCE_PATH: - files = searchPaths.sourcePath(); + files = locations.sourcePath(); break; case CLASS_OUTPUT: { String arg = options.get(D); diff --git a/langtools/src/share/classes/com/sun/tools/javac/util/BaseFileManager.java b/langtools/src/share/classes/com/sun/tools/javac/util/BaseFileManager.java index d393088c414..d3340fe32fd 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/util/BaseFileManager.java +++ b/langtools/src/share/classes/com/sun/tools/javac/util/BaseFileManager.java @@ -52,7 +52,7 @@ import javax.tools.JavaFileObject.Kind; import com.sun.tools.javac.code.Lint; import com.sun.tools.javac.code.Source; import com.sun.tools.javac.file.FSInfo; -import com.sun.tools.javac.file.Paths; +import com.sun.tools.javac.file.Locations; import com.sun.tools.javac.main.JavacOption; import com.sun.tools.javac.main.OptionName; import com.sun.tools.javac.main.RecognizedOptions; @@ -67,7 +67,7 @@ public abstract class BaseFileManager { protected BaseFileManager(Charset charset) { this.charset = charset; byteBufferCache = new ByteBufferCache(); - searchPaths = createPaths(); + locations = createLocations(); } /** @@ -77,11 +77,11 @@ public abstract class BaseFileManager { log = Log.instance(context); options = Options.instance(context); classLoaderClass = options.get("procloader"); - searchPaths.update(log, options, Lint.instance(context), FSInfo.instance(context)); + locations.update(log, options, Lint.instance(context), FSInfo.instance(context)); } - protected Paths createPaths() { - return new Paths(); + protected Locations createLocations() { + return new Locations(); } /** @@ -98,7 +98,7 @@ public abstract class BaseFileManager { protected String classLoaderClass; - protected Paths searchPaths; + protected Locations locations; protected Source getSource() { String sourceName = options.get(OptionName.SOURCE); diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/DocletInvoker.java b/langtools/src/share/classes/com/sun/tools/javadoc/DocletInvoker.java index 07402f90421..d9b2e69b9e4 100644 --- a/langtools/src/share/classes/com/sun/tools/javadoc/DocletInvoker.java +++ b/langtools/src/share/classes/com/sun/tools/javadoc/DocletInvoker.java @@ -80,7 +80,7 @@ public class DocletInvoker { cpString = appendPath(System.getProperty("env.class.path"), cpString); cpString = appendPath(System.getProperty("java.class.path"), cpString); cpString = appendPath(docletPath, cpString); - URL[] urls = com.sun.tools.javac.file.Paths.pathToURLs(cpString); + URL[] urls = com.sun.tools.javac.file.Locations.pathToURLs(cpString); if (docletParentClassLoader == null) appClassLoader = new URLClassLoader(urls, getDelegationClassLoader(docletClassName)); else From b171ddacd069cb90efe26f34b66e2d37fa018612 Mon Sep 17 00:00:00 2001 From: Jim Holmlund Date: Tue, 25 Oct 2011 19:18:32 -0700 Subject: [PATCH 043/107] 7104905: Java SE build fails on call to CreateSymbols Reviewed-by: jjg --- .../src/share/classes/com/sun/tools/javac/file/Locations.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/langtools/src/share/classes/com/sun/tools/javac/file/Locations.java b/langtools/src/share/classes/com/sun/tools/javac/file/Locations.java index 8ef1eeef7f4..8ce5c4af18a 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/file/Locations.java +++ b/langtools/src/share/classes/com/sun/tools/javac/file/Locations.java @@ -327,7 +327,9 @@ public class Locations { */ protected LocationHandler(Location location, OptionName... options) { this.location = location; - this.options = EnumSet.copyOf(Arrays.asList(options)); + this.options = options.length == 0 ? + EnumSet.noneOf(OptionName.class): + EnumSet.copyOf(Arrays.asList(options)); } // TODO: TEMPORARY, while Options still used for command line options From 9181202876c7785e040f822615629b935149e9f7 Mon Sep 17 00:00:00 2001 From: "Y. Srinivas Ramakrishna" Date: Tue, 25 Oct 2011 20:15:41 -0700 Subject: [PATCH 044/107] 7099817: CMS: +FLSVerifyLists +FLSVerifyIndexTable asserts: odd slot non-empty, chunk not on free list Suitably weaken asserts that were in each case a tad too strong; fix up some loose uses of parameters in code related to size-indexed free list table. Reviewed-by: jmasa, brutisso, stefank --- .../compactibleFreeListSpace.cpp | 55 +++++++++++-------- .../compactibleFreeListSpace.hpp | 8 ++- 2 files changed, 37 insertions(+), 26 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp index c989486cf76..34ef09fa449 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp @@ -62,7 +62,7 @@ void CompactibleFreeListSpace::set_cms_values() { MinChunkSize = numQuanta(sizeof(FreeChunk), MinObjAlignmentInBytes) * MinObjAlignment; assert(IndexSetStart == 0 && IndexSetStride == 0, "already set"); - IndexSetStart = MinObjAlignment; + IndexSetStart = (int) MinChunkSize; IndexSetStride = MinObjAlignment; } @@ -138,7 +138,7 @@ CompactibleFreeListSpace::CompactibleFreeListSpace(BlockOffsetSharedArray* bs, } else { _fitStrategy = FreeBlockStrategyNone; } - checkFreeListConsistency(); + check_free_list_consistency(); // Initialize locks for parallel case. @@ -1358,17 +1358,29 @@ FreeChunk* CompactibleFreeListSpace::getChunkFromGreater(size_t numWords) { ShouldNotReachHere(); } -bool CompactibleFreeListSpace::verifyChunkInIndexedFreeLists(FreeChunk* fc) - const { +bool CompactibleFreeListSpace::verifyChunkInIndexedFreeLists(FreeChunk* fc) const { assert(fc->size() < IndexSetSize, "Size of chunk is too large"); return _indexedFreeList[fc->size()].verifyChunkInFreeLists(fc); } +bool CompactibleFreeListSpace::verify_chunk_is_linear_alloc_block(FreeChunk* fc) const { + assert((_smallLinearAllocBlock._ptr != (HeapWord*)fc) || + (_smallLinearAllocBlock._word_size == fc->size()), + "Linear allocation block shows incorrect size"); + return ((_smallLinearAllocBlock._ptr == (HeapWord*)fc) && + (_smallLinearAllocBlock._word_size == fc->size())); +} + +// Check if the purported free chunk is present either as a linear +// allocation block, the size-indexed table of (smaller) free blocks, +// or the larger free blocks kept in the binary tree dictionary. bool CompactibleFreeListSpace::verifyChunkInFreeLists(FreeChunk* fc) const { - if (fc->size() >= IndexSetSize) { - return dictionary()->verifyChunkInFreeLists(fc); - } else { + if (verify_chunk_is_linear_alloc_block(fc)) { + return true; + } else if (fc->size() < IndexSetSize) { return verifyChunkInIndexedFreeLists(fc); + } else { + return dictionary()->verifyChunkInFreeLists(fc); } } @@ -2495,7 +2507,8 @@ void CompactibleFreeListSpace::verifyIndexedFreeList(size_t size) const { FreeChunk* tail = _indexedFreeList[size].tail(); size_t num = _indexedFreeList[size].count(); size_t n = 0; - guarantee((size % 2 == 0) || fc == NULL, "Odd slots should be empty"); + guarantee(((size >= MinChunkSize) && (size % IndexSetStride == 0)) || fc == NULL, + "Slot should have been empty"); for (; fc != NULL; fc = fc->next(), n++) { guarantee(fc->size() == size, "Size inconsistency"); guarantee(fc->isFree(), "!free?"); @@ -2506,14 +2519,14 @@ void CompactibleFreeListSpace::verifyIndexedFreeList(size_t size) const { } #ifndef PRODUCT -void CompactibleFreeListSpace::checkFreeListConsistency() const { +void CompactibleFreeListSpace::check_free_list_consistency() const { assert(_dictionary->minSize() <= IndexSetSize, "Some sizes can't be allocated without recourse to" " linear allocation buffers"); assert(MIN_TREE_CHUNK_SIZE*HeapWordSize == sizeof(TreeChunk), "else MIN_TREE_CHUNK_SIZE is wrong"); - assert((IndexSetStride == 2 && IndexSetStart == 2) || - (IndexSetStride == 1 && IndexSetStart == 1), "just checking"); + assert((IndexSetStride == 2 && IndexSetStart == 4) || // 32-bit + (IndexSetStride == 1 && IndexSetStart == 3), "just checking"); // 64-bit assert((IndexSetStride != 2) || (MinChunkSize % 2 == 0), "Some for-loops may be incorrectly initialized"); assert((IndexSetStride != 2) || (IndexSetSize % 2 == 1), @@ -2688,33 +2701,27 @@ void CFLS_LAB::compute_desired_plab_size() { } } +// If this is changed in the future to allow parallel +// access, one would need to take the FL locks and, +// depending on how it is used, stagger access from +// parallel threads to reduce contention. void CFLS_LAB::retire(int tid) { // We run this single threaded with the world stopped; // so no need for locks and such. -#define CFLS_LAB_PARALLEL_ACCESS 0 NOT_PRODUCT(Thread* t = Thread::current();) assert(Thread::current()->is_VM_thread(), "Error"); - assert(CompactibleFreeListSpace::IndexSetStart == CompactibleFreeListSpace::IndexSetStride, - "Will access to uninitialized slot below"); -#if CFLS_LAB_PARALLEL_ACCESS - for (size_t i = CompactibleFreeListSpace::IndexSetSize - 1; - i > 0; - i -= CompactibleFreeListSpace::IndexSetStride) { -#else // CFLS_LAB_PARALLEL_ACCESS for (size_t i = CompactibleFreeListSpace::IndexSetStart; i < CompactibleFreeListSpace::IndexSetSize; i += CompactibleFreeListSpace::IndexSetStride) { -#endif // !CFLS_LAB_PARALLEL_ACCESS assert(_num_blocks[i] >= (size_t)_indexedFreeList[i].count(), "Can't retire more than what we obtained"); if (_num_blocks[i] > 0) { size_t num_retire = _indexedFreeList[i].count(); assert(_num_blocks[i] > num_retire, "Should have used at least one"); { -#if CFLS_LAB_PARALLEL_ACCESS - MutexLockerEx x(_cfls->_indexedFreeListParLocks[i], - Mutex::_no_safepoint_check_flag); -#endif // CFLS_LAB_PARALLEL_ACCESS + // MutexLockerEx x(_cfls->_indexedFreeListParLocks[i], + // Mutex::_no_safepoint_check_flag); + // Update globals stats for num_blocks used _global_num_blocks[i] += (_num_blocks[i] - num_retire); _global_num_workers[i]++; diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp index 3f3643262df..8adfd667011 100644 --- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp +++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp @@ -502,10 +502,14 @@ class CompactibleFreeListSpace: public CompactibleSpace { void verifyFreeLists() const PRODUCT_RETURN; void verifyIndexedFreeLists() const; void verifyIndexedFreeList(size_t size) const; - // verify that the given chunk is in the free lists. + // Verify that the given chunk is in the free lists: + // i.e. either the binary tree dictionary, the indexed free lists + // or the linear allocation block. bool verifyChunkInFreeLists(FreeChunk* fc) const; + // Verify that the given chunk is the linear allocation block + bool verify_chunk_is_linear_alloc_block(FreeChunk* fc) const; // Do some basic checks on the the free lists. - void checkFreeListConsistency() const PRODUCT_RETURN; + void check_free_list_consistency() const PRODUCT_RETURN; // Printing support void dump_at_safepoint_with_locks(CMSCollector* c, outputStream* st); From 868cfdb5f406eb840ca744ab3232f781ae579f6a Mon Sep 17 00:00:00 2001 From: Bengt Rutisson Date: Wed, 26 Oct 2011 08:44:53 +0200 Subject: [PATCH 045/107] 7102191: G1: assert(_min_desired_young_length <= initial_region_num) failed: Initial young gen size too small Initial_region_num actually not needed. Reviewed-by: tonyp, johnc --- .../share/vm/gc_implementation/g1/g1CollectorPolicy.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp index b7fd0c190f7..68c70510fc1 100644 --- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp +++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp @@ -498,7 +498,6 @@ void G1CollectorPolicy::init() { initialize_gc_policy_counters(); G1YoungGenSizer sizer; - size_t initial_region_num = sizer.initial_young_region_num(); _min_desired_young_length = sizer.min_young_region_num(); _max_desired_young_length = sizer.max_young_region_num(); @@ -512,17 +511,14 @@ void G1CollectorPolicy::init() { } } - // GenCollectorPolicy guarantees that min <= initial <= max. - // Asserting here just to state that we rely on this property. assert(_min_desired_young_length <= _max_desired_young_length, "Invalid min/max young gen size values"); - assert(initial_region_num <= _max_desired_young_length, "Initial young gen size too large"); - assert(_min_desired_young_length <= initial_region_num, "Initial young gen size too small"); set_adaptive_young_list_length(_min_desired_young_length < _max_desired_young_length); if (adaptive_young_list_length()) { _young_list_fixed_length = 0; } else { - _young_list_fixed_length = initial_region_num; + assert(_min_desired_young_length == _max_desired_young_length, "Min and max young size differ"); + _young_list_fixed_length = _min_desired_young_length; } _free_regions_at_end_of_collection = _g1->free_regions(); update_young_list_target_length(); From b58a00d8055438246844e7f645db153090bd6953 Mon Sep 17 00:00:00 2001 From: David Katleman Date: Thu, 27 Oct 2011 13:54:24 -0700 Subject: [PATCH 046/107] Added tag jdk8-b11 for changeset 541e4b0cf4f9 --- .hgtags-top-repo | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags-top-repo b/.hgtags-top-repo index 46967b5b185..bb8cba99e8b 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -132,3 +132,4 @@ b910aac18c772b823b1f7da03e2c6528725cc6de jdk8-b05 fb1bc13260d76447e269e843859eb593fe2a8ab2 jdk8-b08 8adb70647b5af5273dfe6a540f07be667cd50216 jdk8-b09 a6c4c248e8fa350c35014fa94bab5ac1a1ac3299 jdk8-b10 +1defbc57940a56f0aa41e9dee87b71e8c8b71103 jdk8-b11 From 467fe2be8011dac36e2655e9223f03d6f68d4feb Mon Sep 17 00:00:00 2001 From: David Katleman Date: Thu, 27 Oct 2011 13:54:26 -0700 Subject: [PATCH 047/107] Added tag jdk8-b11 for changeset 30a16214b365 --- corba/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/corba/.hgtags b/corba/.hgtags index 13f844c008b..bd2e17921d4 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -132,3 +132,4 @@ cc1b599b986a37cb57de4584c5e58169766ca535 jdk8-b05 0d52b1c87aa8fdea7fdc9c4126ea58f95ca6b351 jdk8-b08 a891732c1a83082177ff7a4cf1506068d9cc0a47 jdk8-b09 cda87f7fefcee3b89742a57ce5ad9b03a54c210d jdk8-b10 +0199e4fef5cc2bd234c65b93220459ef7a3bb3b1 jdk8-b11 From d471bfae9b878d81038dfa15be4510a673c5f41b Mon Sep 17 00:00:00 2001 From: David Katleman Date: Thu, 27 Oct 2011 13:54:31 -0700 Subject: [PATCH 048/107] Added tag jdk8-b11 for changeset 719fbe1902a0 --- hotspot/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/.hgtags b/hotspot/.hgtags index 8b3cab36b40..fd0ca9ba4ce 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -193,3 +193,4 @@ da883b9e6d3788057f9577e72712998ed82c9b7e hs23-b01 e4f412d2b75d2c797acff965aa2c420e3d358f09 hs23-b02 d815de2e85e511b7deab2a83cf80c0224d011da9 jdk8-b10 4d3850d9d326ac3a9bee2d867727e954322d014e hs23-b03 +4538caeef7b6cbd4302bebced805d65e68ccf301 jdk8-b11 From 96ca36886a7233c816802faa61f5da8465836549 Mon Sep 17 00:00:00 2001 From: David Katleman Date: Thu, 27 Oct 2011 13:54:37 -0700 Subject: [PATCH 049/107] Added tag jdk8-b11 for changeset 1c9f26d85678 --- jaxp/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jaxp/.hgtags b/jaxp/.hgtags index 7c209cbed58..e0ff678bbaa 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -132,3 +132,4 @@ c114306576dcc1cb871a48058b41bf7d87ce882a jdk8-b07 de4794dd69c48b08029d158a972993ff9d5627df jdk8-b08 93554324c014282571aeeb48552ad00d3fedb089 jdk8-b09 d21a4d5141c04bc9e88f2c0253121d449b66d667 jdk8-b10 +d1b7a4f6dd2065fdeafbcdfd9dcc0072da8c6881 jdk8-b11 From e0e7783359a9bb73e90246d6f5c48a83717c7477 Mon Sep 17 00:00:00 2001 From: David Katleman Date: Thu, 27 Oct 2011 13:54:38 -0700 Subject: [PATCH 050/107] Added tag jdk8-b11 for changeset df5d402bd8f5 --- jaxws/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jaxws/.hgtags b/jaxws/.hgtags index de87c6c7cc9..3eec004d4a8 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -132,3 +132,4 @@ acffff22a9465005e8eb206224fae9f2ea4fd469 jdk8-b06 1c9d4f59acf8f71477473c170239b43b2c9dee24 jdk8-b08 70172e57cf29efe271b068987eefb601c2a77780 jdk8-b09 8e7fdc8e3c758644ca6d0fd70bb255e9d2e64cda jdk8-b10 +a12ab897a249feb7859a6e6cd84b49411f4c06ac jdk8-b11 From 83c35d376a114c85fc6646032397a858a3d43626 Mon Sep 17 00:00:00 2001 From: David Katleman Date: Thu, 27 Oct 2011 13:54:42 -0700 Subject: [PATCH 051/107] Added tag jdk8-b11 for changeset 7116fbba4c13 --- jdk/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/.hgtags b/jdk/.hgtags index ebca091558f..515e0f72fbc 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -132,3 +132,4 @@ bdb870cc269ef8b221d17a217be89092400b59d2 jdk8-b06 1c023bcd0c5a01ac07bc7eea728aafbb0d8991e9 jdk8-b08 f1ec21b8142168ff40f3278d2f6b5fe4bd5f3b26 jdk8-b09 4788745572ef2bde34924ef34e7e4d55ba07e979 jdk8-b10 +7ab0d613cd1a271a9763ffb894dc1f0a5b95a7e4 jdk8-b11 From 31ff82c1c8b27d1141f566a0da15dfe8fb0e1eee Mon Sep 17 00:00:00 2001 From: David Katleman Date: Thu, 27 Oct 2011 13:54:50 -0700 Subject: [PATCH 052/107] Added tag jdk8-b11 for changeset b44e4293ec86 --- langtools/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/langtools/.hgtags b/langtools/.hgtags index 9c596017a4a..06958e1b0c5 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -132,3 +132,4 @@ d2422276f9dabc848b7a079025719826d2f9a30f jdk8-b06 e8acc2d6c32f0c8321e642e1a86672a2e196a056 jdk8-b08 b7a7e47c8d3daf7822abf7c37e5179ccbbf53008 jdk8-b09 f6c783e18bdf4d46a0ab273868afebbf32600ff7 jdk8-b10 +4bf01f1c4e3464f378959d10f3983a0469181d94 jdk8-b11 From ad3a8d27914dbe4ca96a49f1e50915fa13c34df8 Mon Sep 17 00:00:00 2001 From: David Holmes Date: Thu, 27 Oct 2011 18:04:25 -0400 Subject: [PATCH 053/107] 7104173: sun/tools tests fail with debug build after 7012206 Disable PrintVMOptions in embedded debug builds so tests are unaffected by extra output Reviewed-by: twisti, coleenp, phh, fparain, dsamersoff --- hotspot/src/share/vm/runtime/globals.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp index 78334da4ff4..f770102ab48 100644 --- a/hotspot/src/share/vm/runtime/globals.hpp +++ b/hotspot/src/share/vm/runtime/globals.hpp @@ -2580,7 +2580,7 @@ class CommandLineFlags { diagnostic(bool, DebugInlinedCalls, true, \ "If false, restricts profiled locations to the root method only") \ \ - product(bool, PrintVMOptions, trueInDebug, \ + product(bool, PrintVMOptions, NOT_EMBEDDED(trueInDebug) EMBEDDED_ONLY(false),\ "Print flags that appeared on the command line") \ \ product(bool, IgnoreUnrecognizedVMOptions, false, \ From d61593bed3ebf2249b54ed6324473b2634a5d5f1 Mon Sep 17 00:00:00 2001 From: John Coomes Date: Fri, 28 Oct 2011 15:41:29 -0700 Subject: [PATCH 054/107] Added tag hs23-b04 for changeset 721977078d6e --- hotspot/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/.hgtags b/hotspot/.hgtags index fd0ca9ba4ce..46612cd8947 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -194,3 +194,4 @@ e4f412d2b75d2c797acff965aa2c420e3d358f09 hs23-b02 d815de2e85e511b7deab2a83cf80c0224d011da9 jdk8-b10 4d3850d9d326ac3a9bee2d867727e954322d014e hs23-b03 4538caeef7b6cbd4302bebced805d65e68ccf301 jdk8-b11 +6534482ff68ad79066dfe15dfb6d8905f09681bd hs23-b04 From 84066778b8be52c168f676f8f782c00253495b00 Mon Sep 17 00:00:00 2001 From: Alejandro Murillo Date: Fri, 28 Oct 2011 18:30:47 -0700 Subject: [PATCH 055/107] 7106092: Bump the hs23 build number to 05 Reviewed-by: johnc --- hotspot/make/hotspot_version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hotspot/make/hotspot_version b/hotspot/make/hotspot_version index 09ea6779834..dbe6ad9b9bb 100644 --- a/hotspot/make/hotspot_version +++ b/hotspot/make/hotspot_version @@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2011 HS_MAJOR_VER=23 HS_MINOR_VER=0 -HS_BUILD_NUMBER=04 +HS_BUILD_NUMBER=05 JDK_MAJOR_VER=1 JDK_MINOR_VER=8 From 089b5b16e3cc95583b1c389fbf50cfa630e1cac6 Mon Sep 17 00:00:00 2001 From: Bradford Wetmore Date: Mon, 31 Oct 2011 11:54:19 -0700 Subject: [PATCH 056/107] 7105780: Add SSLSocket client/SSLEngine server to templates directory Reviewed-by: xuelei --- .../templates/SSLSocketSSLEngineTemplate.java | 479 ++++++++++++++++++ 1 file changed, 479 insertions(+) create mode 100644 jdk/test/sun/security/ssl/templates/SSLSocketSSLEngineTemplate.java diff --git a/jdk/test/sun/security/ssl/templates/SSLSocketSSLEngineTemplate.java b/jdk/test/sun/security/ssl/templates/SSLSocketSSLEngineTemplate.java new file mode 100644 index 00000000000..e31409a0f74 --- /dev/null +++ b/jdk/test/sun/security/ssl/templates/SSLSocketSSLEngineTemplate.java @@ -0,0 +1,479 @@ +/* + * Copyright (c) 2011, 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 7105780 + * @summary Add SSLSocket client/SSLEngine server to templates directory. + * + * SunJSSE does not support dynamic system properties, no way to re-use + * system properties in samevm/agentvm mode. + * + * @run main/othervm SSLSocketSSLEngineTemplate + */ + +/** + * A SSLSocket/SSLEngine interop test case. This is not the way to + * code SSLEngine-based servers, but works for what we need to do here, + * which is to make sure that SSLEngine/SSLSockets can talk to each other. + * SSLEngines can use direct or indirect buffers, and different code + * is used to get at the buffer contents internally, so we test that here. + * + * The test creates one SSLSocket (client) and one SSLEngine (server). + * The SSLSocket talks to a raw ServerSocket, and the server code + * does the translation between byte [] and ByteBuffers that the SSLEngine + * can use. The "transport" layer consists of a Socket Input/OutputStream + * and two byte buffers for the SSLEngines: think of them + * as directly connected pipes. + * + * Again, this is a *very* simple example: real code will be much more + * involved. For example, different threading and I/O models could be + * used, transport mechanisms could close unexpectedly, and so on. + * + * When this application runs, notice that several messages + * (wrap/unwrap) pass before any application data is consumed or + * produced. (For more information, please see the SSL/TLS + * specifications.) There may several steps for a successful handshake, + * so it's typical to see the following series of operations: + * + * client server message + * ====== ====== ======= + * write() ... ClientHello + * ... unwrap() ClientHello + * ... wrap() ServerHello/Certificate + * read() ... ServerHello/Certificate + * write() ... ClientKeyExchange + * write() ... ChangeCipherSpec + * write() ... Finished + * ... unwrap() ClientKeyExchange + * ... unwrap() ChangeCipherSpec + * ... unwrap() Finished + * ... wrap() ChangeCipherSpec + * ... wrap() Finished + * read() ... ChangeCipherSpec + * read() ... Finished + */ +import javax.net.ssl.*; +import javax.net.ssl.SSLEngineResult.*; +import java.io.*; +import java.net.*; +import java.security.*; +import java.nio.*; + +public class SSLSocketSSLEngineTemplate { + + /* + * Enables logging of the SSL/TLS operations. + */ + private static boolean logging = true; + + /* + * Enables the JSSE system debugging system property: + * + * -Djavax.net.debug=all + * + * This gives a lot of low-level information about operations underway, + * including specific handshake messages, and might be best examined + * after gaining some familiarity with this application. + */ + private static boolean debug = false; + private SSLContext sslc; + private SSLEngine serverEngine; // server-side SSLEngine + private SSLSocket sslSocket; // client-side socket + private ServerSocket serverSocket; // server-side Socket, generates the... + private Socket socket; // server-side socket that will read + + private final byte[] serverMsg = + "Hi there Client, I'm a Server.".getBytes(); + private final byte[] clientMsg = + "Hello Server, I'm a Client! Pleased to meet you!".getBytes(); + + private ByteBuffer serverOut; // write side of serverEngine + private ByteBuffer serverIn; // read side of serverEngine + + private volatile Exception clientException; + private volatile Exception serverException; + + /* + * For data transport, this example uses local ByteBuffers. + */ + private ByteBuffer cTOs; // "reliable" transport client->server + private ByteBuffer sTOc; // "reliable" transport server->client + + /* + * The following is to set up the keystores/trust material. + */ + private static final String pathToStores = "../etc/"; + private static final String keyStoreFile = "keystore"; + private static final String trustStoreFile = "truststore"; + private static final String passwd = "passphrase"; + private static String keyFilename = + System.getProperty("test.src", ".") + "/" + pathToStores + + "/" + keyStoreFile; + private static String trustFilename = + System.getProperty("test.src", ".") + "/" + pathToStores + + "/" + trustStoreFile; + + /* + * Main entry point for this test. + */ + public static void main(String args[]) throws Exception { + if (debug) { + System.setProperty("javax.net.debug", "all"); + } + + String [] protocols = new String [] { + "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2" }; + + for (String protocol : protocols) { + log("Testing " + protocol); + /* + * Run the tests with direct and indirect buffers. + */ + SSLSocketSSLEngineTemplate test = + new SSLSocketSSLEngineTemplate(protocol); + test.runTest(true); + test.runTest(false); + } + + System.out.println("Test Passed."); + } + + /* + * Create an initialized SSLContext to use for these tests. + */ + public SSLSocketSSLEngineTemplate(String protocol) throws Exception { + + KeyStore ks = KeyStore.getInstance("JKS"); + KeyStore ts = KeyStore.getInstance("JKS"); + + char[] passphrase = "passphrase".toCharArray(); + + ks.load(new FileInputStream(keyFilename), passphrase); + ts.load(new FileInputStream(trustFilename), passphrase); + + KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); + kmf.init(ks, passphrase); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509"); + tmf.init(ts); + + SSLContext sslCtx = SSLContext.getInstance(protocol); + + sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); + + sslc = sslCtx; + } + + /* + * Run the test. + * + * Sit in a tight loop, with the server engine calling wrap/unwrap + * regardless of whether data is available or not. We do this until + * we get the application data. Then we shutdown and go to the next one. + * + * The main loop handles all of the I/O phases of the SSLEngine's + * lifetime: + * + * initial handshaking + * application data transfer + * engine closing + * + * One could easily separate these phases into separate + * sections of code. + */ + private void runTest(boolean direct) throws Exception { + boolean serverClose = direct; + + serverSocket = new ServerSocket(0); + int port = serverSocket.getLocalPort(); + Thread thread = createClientThread(port, serverClose); + + socket = serverSocket.accept(); + socket.setSoTimeout(500); + serverSocket.close(); + + createSSLEngine(); + createBuffers(direct); + + try { + boolean closed = false; + + InputStream is = socket.getInputStream(); + OutputStream os = socket.getOutputStream(); + + SSLEngineResult serverResult; // results from last operation + + /* + * Examining the SSLEngineResults could be much more involved, + * and may alter the overall flow of the application. + * + * For example, if we received a BUFFER_OVERFLOW when trying + * to write to the output pipe, we could reallocate a larger + * pipe, but instead we wait for the peer to drain it. + */ + byte[] inbound = new byte[8192]; + byte[] outbound = new byte[8192]; + + while (!isEngineClosed(serverEngine)) { + int len = 0; + + // Inbound data + log("================"); + + // Read from the Client side. + try { + len = is.read(inbound); + if (len == -1) { + throw new Exception("Unexpected EOF"); + } + cTOs.put(inbound, 0, len); + } catch (SocketTimeoutException ste) { + // swallow. Nothing yet, probably waiting on us. + } + + cTOs.flip(); + + serverResult = serverEngine.unwrap(cTOs, serverIn); + log("server unwrap: ", serverResult); + runDelegatedTasks(serverResult, serverEngine); + cTOs.compact(); + + // Outbound data + log("----"); + + serverResult = serverEngine.wrap(serverOut, sTOc); + log("server wrap: ", serverResult); + runDelegatedTasks(serverResult, serverEngine); + + sTOc.flip(); + + if ((len = sTOc.remaining()) != 0) { + sTOc.get(outbound, 0, len); + os.write(outbound, 0, len); + // Give the other side a chance to process + } + + sTOc.compact(); + + if (!closed && (serverOut.remaining() == 0)) { + closed = true; + + /* + * We'll alternate initiatating the shutdown. + * When the server initiates, it will take one more + * loop, but tests the orderly shutdown. + */ + if (serverClose) { + serverEngine.closeOutbound(); + } + serverIn.flip(); + + /* + * A sanity check to ensure we got what was sent. + */ + if (serverIn.remaining() != clientMsg.length) { + throw new Exception("Client: Data length error"); + } + + for (int i = 0; i < clientMsg.length; i++) { + if (clientMsg[i] != serverIn.get()) { + throw new Exception("Client: Data content error"); + } + } + serverIn.compact(); + } + } + return; + } catch (Exception e) { + serverException = e; + } finally { + socket.close(); + + // Wait for the client to join up with us. + thread.join(); + if (serverException != null) { + throw serverException; + } + if (clientException != null) { + throw clientException; + } + } + } + + /* + * Create a client thread which does simple SSLSocket operations. + * We'll write and read one data packet. + */ + private Thread createClientThread(final int port, + final boolean serverClose) throws Exception { + + Thread t = new Thread("ClientThread") { + + @Override + public void run() { + try { + Thread.sleep(1000); // Give server time to finish setup. + + sslSocket = (SSLSocket) sslc.getSocketFactory(). + createSocket("localhost", port); + OutputStream os = sslSocket.getOutputStream(); + InputStream is = sslSocket.getInputStream(); + + // write(byte[]) goes in one shot. + os.write(clientMsg); + + byte[] inbound = new byte[2048]; + int pos = 0; + + int len; +done: + while ((len = is.read(inbound, pos, 2048 - pos)) != -1) { + pos += len; + // Let the client do the closing. + if ((pos == serverMsg.length) && !serverClose) { + sslSocket.close(); + break done; + } + } + + if (pos != serverMsg.length) { + throw new Exception("Client: Data length error"); + } + + for (int i = 0; i < serverMsg.length; i++) { + if (inbound[i] != serverMsg[i]) { + throw new Exception("Client: Data content error"); + } + } + } catch (Exception e) { + clientException = e; + } + } + }; + t.start(); + return t; + } + + /* + * Using the SSLContext created during object creation, + * create/configure the SSLEngines we'll use for this test. + */ + private void createSSLEngine() throws Exception { + /* + * Configure the serverEngine to act as a server in the SSL/TLS + * handshake. + */ + serverEngine = sslc.createSSLEngine(); + serverEngine.setUseClientMode(false); + serverEngine.getNeedClientAuth(); + } + + /* + * Create and size the buffers appropriately. + */ + private void createBuffers(boolean direct) { + + SSLSession session = serverEngine.getSession(); + int appBufferMax = session.getApplicationBufferSize(); + int netBufferMax = session.getPacketBufferSize(); + + /* + * We'll make the input buffers a bit bigger than the max needed + * size, so that unwrap()s following a successful data transfer + * won't generate BUFFER_OVERFLOWS. + * + * We'll use a mix of direct and indirect ByteBuffers for + * tutorial purposes only. In reality, only use direct + * ByteBuffers when they give a clear performance enhancement. + */ + if (direct) { + serverIn = ByteBuffer.allocateDirect(appBufferMax + 50); + cTOs = ByteBuffer.allocateDirect(netBufferMax); + sTOc = ByteBuffer.allocateDirect(netBufferMax); + } else { + serverIn = ByteBuffer.allocate(appBufferMax + 50); + cTOs = ByteBuffer.allocate(netBufferMax); + sTOc = ByteBuffer.allocate(netBufferMax); + } + + serverOut = ByteBuffer.wrap(serverMsg); + } + + /* + * If the result indicates that we have outstanding tasks to do, + * go ahead and run them in this thread. + */ + private static void runDelegatedTasks(SSLEngineResult result, + SSLEngine engine) throws Exception { + + if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) { + Runnable runnable; + while ((runnable = engine.getDelegatedTask()) != null) { + log("\trunning delegated task..."); + runnable.run(); + } + HandshakeStatus hsStatus = engine.getHandshakeStatus(); + if (hsStatus == HandshakeStatus.NEED_TASK) { + throw new Exception( + "handshake shouldn't need additional tasks"); + } + log("\tnew HandshakeStatus: " + hsStatus); + } + } + + private static boolean isEngineClosed(SSLEngine engine) { + return (engine.isOutboundDone() && engine.isInboundDone()); + } + + /* + * Logging code + */ + private static boolean resultOnce = true; + + private static void log(String str, SSLEngineResult result) { + if (!logging) { + return; + } + if (resultOnce) { + resultOnce = false; + System.out.println("The format of the SSLEngineResult is: \n" + + "\t\"getStatus() / getHandshakeStatus()\" +\n" + + "\t\"bytesConsumed() / bytesProduced()\"\n"); + } + HandshakeStatus hsStatus = result.getHandshakeStatus(); + log(str + + result.getStatus() + "/" + hsStatus + ", " + + result.bytesConsumed() + "/" + result.bytesProduced() + + " bytes"); + if (hsStatus == HandshakeStatus.FINISHED) { + log("\t...ready for application data"); + } + } + + private static void log(String str) { + if (logging) { + System.out.println(str); + } + } +} From becccc16ec5c14b03f6e33c77be086d6304a095f Mon Sep 17 00:00:00 2001 From: Bradford Wetmore Date: Mon, 31 Oct 2011 16:23:43 -0700 Subject: [PATCH 057/107] 7053252: New regression test does not compile on windows-amd64 Reviewed-by: valeriep --- jdk/test/ProblemList.txt | 3 --- jdk/test/sun/security/pkcs11/Provider/Absolute.java | 1 - 2 files changed, 4 deletions(-) diff --git a/jdk/test/ProblemList.txt b/jdk/test/ProblemList.txt index 9f91b1879b2..5b483f97cb4 100644 --- a/jdk/test/ProblemList.txt +++ b/jdk/test/ProblemList.txt @@ -490,9 +490,6 @@ sun/security/pkcs11/ec/TestECDSA.java solaris-i586 #sun/security/pkcs11/ec/TestKeyFactory.java solaris-i586 sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java solaris-i586 -# Directly references PKCS11 class -sun/security/pkcs11/Provider/Absolute.java windows-x64 - # Fails on Fedora 9/Ubuntu 10.04 64bit, PKCS11Exception: CKR_DEVICE_ERROR sun/security/pkcs11/KeyAgreement/TestDH.java generic-all diff --git a/jdk/test/sun/security/pkcs11/Provider/Absolute.java b/jdk/test/sun/security/pkcs11/Provider/Absolute.java index e35f9c60c58..fc035dc7c73 100644 --- a/jdk/test/sun/security/pkcs11/Provider/Absolute.java +++ b/jdk/test/sun/security/pkcs11/Provider/Absolute.java @@ -27,7 +27,6 @@ */ import java.security.*; import java.lang.reflect.*; -import sun.security.pkcs11.*; public class Absolute { From e9207384c5ab9afc9d6b62db505cd2e4f40980a1 Mon Sep 17 00:00:00 2001 From: "Y. Srinivas Ramakrishna" Date: Mon, 31 Oct 2011 17:38:15 -0700 Subject: [PATCH 058/107] 4243978: (ref) Race condition in Reference.enqueue() 4268317: (ref) Reference.isEnqueued() can return true when instance not enqueued The reference handler now declares, and assumes, that the discovered field, rather than the next field, is (to be) used to link the entries in the pending list, thus allowing a reference object to be safely enqueued even while it is in the pending state. Also added slightly modified regression tests from the two bug reports. Reviewed-by: mchung, alanb, jcoomes --- .../classes/java/lang/ref/Reference.java | 31 +-- jdk/src/share/javavm/export/jvm.h | 3 +- jdk/src/share/native/common/jdk_util.c | 2 +- jdk/test/java/lang/ref/ReferenceEnqueue.java | 79 +++++++ .../lang/ref/ReferenceEnqueuePending.java | 201 ++++++++++++++++++ 5 files changed, 302 insertions(+), 14 deletions(-) create mode 100644 jdk/test/java/lang/ref/ReferenceEnqueue.java create mode 100644 jdk/test/java/lang/ref/ReferenceEnqueuePending.java diff --git a/jdk/src/share/classes/java/lang/ref/Reference.java b/jdk/src/share/classes/java/lang/ref/Reference.java index f483edf58d2..6d3d9c3bd1a 100644 --- a/jdk/src/share/classes/java/lang/ref/Reference.java +++ b/jdk/src/share/classes/java/lang/ref/Reference.java @@ -27,7 +27,6 @@ package java.lang.ref; import sun.misc.Cleaner; - /** * Abstract base class for reference objects. This class defines the * operations common to all reference objects. Because reference objects are @@ -69,7 +68,7 @@ public abstract class Reference { * null. * * Pending: queue = ReferenceQueue with which instance is registered; - * next = Following instance in queue, or this if at end of list. + * next = this * * Enqueued: queue = ReferenceQueue.ENQUEUED; next = Following instance * in queue, or this if at end of list. @@ -81,17 +80,28 @@ public abstract class Reference { * the next field is null then the instance is active; if it is non-null, * then the collector should treat the instance normally. * - * To ensure that concurrent collector can discover active Reference + * To ensure that a concurrent collector can discover active Reference * objects without interfering with application threads that may apply * the enqueue() method to those objects, collectors should link - * discovered objects through the discovered field. + * discovered objects through the discovered field. The discovered + * field is also used for linking Reference objects in the pending list. */ private T referent; /* Treated specially by GC */ ReferenceQueue queue; + /* When active: NULL + * pending: this + * Enqueued: next reference in queue (or this if last) + * Inactive: this + */ Reference next; + + /* When active: next element in a discovered reference list maintained by GC (or this if last) + * pending: next element in the pending list (or null if last) + * otherwise: NULL + */ transient private Reference discovered; /* used by VM */ @@ -106,7 +116,8 @@ public abstract class Reference { /* List of References waiting to be enqueued. The collector adds * References to this list, while the Reference-handler thread removes - * them. This list is protected by the above lock object. + * them. This list is protected by the above lock object. The + * list uses the discovered field to link its elements. */ private static Reference pending = null; @@ -120,14 +131,12 @@ public abstract class Reference { public void run() { for (;;) { - Reference r; synchronized (lock) { if (pending != null) { r = pending; - Reference rn = r.next; - pending = (rn == r) ? null : rn; - r.next = r; + pending = r.discovered; + r.discovered = null; } else { try { lock.wait(); @@ -201,10 +210,8 @@ public abstract class Reference { * been enqueued */ public boolean isEnqueued() { - /* In terms of the internal states, this predicate actually tests - whether the instance is either Pending or Enqueued */ synchronized (this) { - return (this.queue != ReferenceQueue.NULL) && (this.next != null); + return (this.next != null && this.queue == ReferenceQueue.ENQUEUED); } } diff --git a/jdk/src/share/javavm/export/jvm.h b/jdk/src/share/javavm/export/jvm.h index d1dfefca47f..8d833ebeeac 100644 --- a/jdk/src/share/javavm/export/jvm.h +++ b/jdk/src/share/javavm/export/jvm.h @@ -1424,7 +1424,8 @@ typedef struct { */ unsigned int thread_park_blocker : 1; unsigned int post_vm_init_hook_enabled : 1; - unsigned int : 30; + unsigned int pending_list_uses_discovered_field : 1; + unsigned int : 29; unsigned int : 32; unsigned int : 32; } jdk_version_info; diff --git a/jdk/src/share/native/common/jdk_util.c b/jdk/src/share/native/common/jdk_util.c index e737982893e..8fe32bfcfaf 100644 --- a/jdk/src/share/native/common/jdk_util.c +++ b/jdk/src/share/native/common/jdk_util.c @@ -101,5 +101,5 @@ JDK_GetVersionInfo0(jdk_version_info* info, size_t info_size) { // Advertise presence of sun.misc.PostVMInitHook: // future optimization: detect if this is enabled. info->post_vm_init_hook_enabled = 1; - + info->pending_list_uses_discovered_field = 1; } diff --git a/jdk/test/java/lang/ref/ReferenceEnqueue.java b/jdk/test/java/lang/ref/ReferenceEnqueue.java new file mode 100644 index 00000000000..25907a034cc --- /dev/null +++ b/jdk/test/java/lang/ref/ReferenceEnqueue.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2011, 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 4268317 + * @summary Test if Reference.enqueue() works properly with GC + */ + +import java.lang.ref.*; + +public class ReferenceEnqueue { + + public static void main(String args[]) throws Exception { + for (int i=0; i < 5; i++) + new WeakRef().run(); + System.out.println("Test passed."); + } + + static class WeakRef { + final ReferenceQueue queue = new ReferenceQueue(); + final Reference ref; + final int iterations = 1000; + + WeakRef() { + this.ref = new WeakReference(new Object(), queue); + } + + void run() throws InterruptedException { + System.gc(); + for (int i = 0; i < iterations; i++) { + System.gc(); + if (ref.isEnqueued()) { + break; + } + + Thread.sleep(100); + } + + if (ref.isEnqueued() == false) { + // GC have not enqueued refWeak for the timeout period + System.out.println("Reference not enqueued yet"); + return; + } + + if (ref.enqueue() == true) { + // enqueue() should return false since + // ref is already enqueued by the GC + throw new RuntimeException("Error: enqueue() returned true;" + + " expected false"); + } + + if (queue.poll() == null) { + // poll() should return ref enqueued by the GC + throw new RuntimeException("Error: poll() returned null;" + + " expected ref object"); + } + } + } +} diff --git a/jdk/test/java/lang/ref/ReferenceEnqueuePending.java b/jdk/test/java/lang/ref/ReferenceEnqueuePending.java new file mode 100644 index 00000000000..0e8868fa9fd --- /dev/null +++ b/jdk/test/java/lang/ref/ReferenceEnqueuePending.java @@ -0,0 +1,201 @@ +/* Copyright (c) 2011, 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 4243978 + * @summary Test if Reference.enqueue() works properly with pending references + */ +import java.lang.ref.*; + +public class ReferenceEnqueuePending { + static class NumberedWeakReference extends WeakReference { + // Add an integer to identify the weak reference object. + int number; + + NumberedWeakReference(Integer referent, ReferenceQueue q, int i) { + super(referent, q); + number = i; + } + } + + final static boolean debug = System.getProperty("test.debug") != null; + final static int iterations = 1000; + final static int gc_trigger = 99; + static int[] a = new int[2 * iterations]; + // Keep all weak references alive with the following array. + static NumberedWeakReference[] b = new NumberedWeakReference[iterations]; + + public static void main(String[] argv) throws Exception { + if (debug) { + System.out.println("Starting the test."); + } + // Raise thread priority to match the referenceHandler + // priority, so that they can race also on a uniprocessor. + raisePriority(); + + ReferenceQueue refQueue = new ReferenceQueue<>(); + + // Our objective is to let the mutator enqueue + // a Reference object that may already be in the + // pending state because of having been identified + // as weakly reachable at a previous garbage collection. + // To this end, we create many Reference objects, each with a + // a unique integer object as its referant. + // We let the referents become eligible for collection, + // while racing with the garbage collector which may + // have pended some of these Reference objects. + // Finally we check that all of the Reference objects + // end up on the their queue. The test was originally + // submitted to show that such races could break the + // pending list and/or the reference queue, because of sharing + // the same link ("next") for maintaining both lists, thus + // losing some of the Reference objects on either queue. + + Integer obj = new Integer(0); + NumberedWeakReference weaky = new NumberedWeakReference(obj, refQueue, 0); + for (int i = 1; i < iterations; i++) { + // Create a new object, dropping the onlY strong reference to + // the previous Integer object. + obj = new Integer(i); + // Trigger gc each gc_trigger iterations. + if ((i % gc_trigger) == 0) { + forceGc(0); + } + // Enqueue every other weaky. + if ((i % 2) == 0) { + weaky.enqueue(); + } + // Remember the Reference objects, for testing later. + b[i - 1] = weaky; + // Get a new weaky for the Integer object just + // created, which may be explicitly enqueued in + // our next trip around the loop. + weaky = new NumberedWeakReference(obj, refQueue, i); + } + + // Do a final collection to discover and process all + // Reference objects created above, allowing enough time + // for the ReferenceHandler thread to queue the References. + forceGc(100); + forceGc(100); + + // Verify that all WeakReference objects ended up queued. + checkResult(refQueue, obj, iterations-1); + System.out.println("Test passed."); + } + + private static void checkResult(ReferenceQueue queue, + Integer obj, + int expected) { + if (debug) { + System.out.println("Reading the queue"); + } + + // Empty the queue and record numbers into a[]; + NumberedWeakReference weakRead = (NumberedWeakReference) queue.poll(); + int length = 0; + while (weakRead != null) { + a[length++] = weakRead.number; + weakRead = (NumberedWeakReference) queue.poll(); + } + if (debug) { + System.out.println("Reference Queue had " + length + " elements"); + } + // Use the last Reference object of those created above, so as to keep it "alive". + System.out.println("I must write " + obj + " to prevent compiler optimizations."); + + + // verify the queued references: all but the last Reference object + // should have been in the queue. + if (debug) { + System.out.println("Start of final check"); + } + + // Sort the first "length" elements in array "a[]". + sort(length); + + boolean fail = (length != expected); + for (int i = 0; i < length; i++) { + if (a[i] != i) { + if (debug) { + System.out.println("a[" + i + "] is not " + i + " but " + a[i]); + } + fail = true; + } + } + if (fail) { + printMissingElements(length, expected); + throw new RuntimeException("TEST FAILED: only " + length + + " reference objects have been queued out of " + + expected); + } + } + + private static void printMissingElements(int length, int expected) { + System.out.println("The following numbers were not found in the reference queue: "); + int missing = 0; + int element = 0; + for (int i = 0; i < length; i++) { + while ((a[i] != element) & (element < expected)) { + System.out.print(element + " "); + if (missing % 20 == 19) { + System.out.println(" "); + } + missing++; + element++; + } + element++; + } + System.out.print("\n"); + } + + private static void forceGc(long millis) throws InterruptedException { + Runtime.getRuntime().gc(); + Thread.sleep(millis); + } + + // Bubble sort the first "length" elements in array "a". + private static void sort(int length) { + int hold; + if (debug) { + System.out.println("Sorting. Length=" + length); + } + for (int pass = 1; pass < length; pass++) { // passes over the array + for (int i = 0; i < length - pass; i++) { // a single pass + if (a[i] > a[i + 1]) { // then swap + hold = a[i]; + a[i] = a[i + 1]; + a[i + 1] = hold; + } + } // End of i loop + } // End of pass loop + } + + // Raise thread priority so as to increase the + // probability of the mutator succeeding in enqueueing + // an object that is still in the pending state. + // This is (probably) only required for a uniprocessor. + static void raisePriority() { + Thread tr = Thread.currentThread(); + tr.setPriority(Thread.MAX_PRIORITY); + } +} // End of class ReferenceEnqueuePending From c24783568eecb0cee8d220d87e0500b24edc3032 Mon Sep 17 00:00:00 2001 From: Yong Jeffrey Huang Date: Mon, 31 Oct 2011 20:14:12 -0700 Subject: [PATCH 059/107] 7077119: remove past transition dates from CurrencyData.properties file Reviewed-by: naoto --- .../classes/java/util/CurrencyData.properties | 12 ++++----- jdk/test/java/util/Currency/CurrencyTest.java | 26 ++++++++++--------- .../java/util/Currency/ValidateISO4217.java | 2 +- jdk/test/java/util/Currency/tablea1.txt | 10 +++---- 4 files changed, 26 insertions(+), 24 deletions(-) diff --git a/jdk/src/share/classes/java/util/CurrencyData.properties b/jdk/src/share/classes/java/util/CurrencyData.properties index 5cfc1397e6e..b943993522f 100644 --- a/jdk/src/share/classes/java/util/CurrencyData.properties +++ b/jdk/src/share/classes/java/util/CurrencyData.properties @@ -71,7 +71,7 @@ all=ADP020-AED784-AFA004-AFN971-ALL008-AMD051-ANG532-AOA973-ARS032-ATS040-AUD036 # # The table is based on the following web sites: # http://www.din.de/gremien/nas/nabd/iso3166ma/codlstp1/db_en.html -# http://www.bsi-global.com/iso4217currency +# http://www.currency-iso.org/iso_index/iso_tables.htm # http://www.cia.gov/cia/publications/factbook/indexgeo.html # AFGHANISTAN @@ -105,7 +105,7 @@ AU=AUD # AUSTRIA AT=EUR # AZERBAIJAN -AZ=AZM;2005-12-31-20-00-00;AZN +AZ=AZN # BAHAMAS BS=BSD # BAHRAIN @@ -378,7 +378,7 @@ MS=XCD # MOROCCO MA=MAD # MOZAMBIQUE -MZ=MZM;2006-06-30-22-00-00;MZN +MZ=MZN # MYANMAR MM=MMK # NAMIBIA @@ -440,7 +440,7 @@ QA=QAR # REUNION RE=EUR # ROMANIA -RO=ROL;2005-06-30-21-00-00;RON +RO=RON # RUSSIAN FEDERATION RU=RUB # RWANDA @@ -532,7 +532,7 @@ TT=TTD # TUNISIA TN=TND # TURKEY -TR=TRL;2004-12-31-22-00-00;TRY +TR=TRY # TURKMENISTAN TM=TMT # TURKS AND CAICOS ISLANDS @@ -558,7 +558,7 @@ UZ=UZS # VANUATU VU=VUV # VENEZUELA -VE=VEB;2008-01-01-04-00-00;VEF +VE=VEF # VIET NAM VN=VND # VIRGIN ISLANDS, BRITISH diff --git a/jdk/test/java/util/Currency/CurrencyTest.java b/jdk/test/java/util/Currency/CurrencyTest.java index e7ae4fd79fc..c22813845ce 100644 --- a/jdk/test/java/util/Currency/CurrencyTest.java +++ b/jdk/test/java/util/Currency/CurrencyTest.java @@ -128,18 +128,20 @@ public class CurrencyTest { checkCountryCurrency(country1[i], currency1[i]); } - // check currency changes - String[] switchOverCtry = {"DE", "FR", "ES", "IT", "NL", "BE", "TR", "RO", "AZ", "MZ", "GH", "VE"}; - String[] switchOverOld = {"DEM", "FRF", "ESP", "ITL", "NLG", "BEF", "TRL", "ROL", "AZM", "MZM", "GHC", "VEB"}; - String[] switchOverNew = {"EUR", "EUR", "EUR", "EUR", "EUR", "EUR", "TRY", "RON", "AZN", "MZN", "GHS", "VEF"}; - String[] switchOverTZ = {"Europe/Paris", "Europe/Paris", "Europe/Paris", "Europe/Paris", - "Europe/Paris", "Europe/Paris", "Asia/Istanbul", "Europe/Bucharest", - "Asia/Baku", "Africa/Maputo", "Africa/Accra", "America/Caracas"}; - int[] switchOverYear = {2002, 2002, 2002, 2002, 2002, 2002, 2005, 2005, 2006, 2006, 2007, 2008}; - int[] switchOverMonth = {Calendar.JANUARY, Calendar.JANUARY, Calendar.JANUARY, Calendar.JANUARY, - Calendar.JANUARY, Calendar.JANUARY, Calendar.JANUARY, Calendar.JULY, - Calendar.JANUARY, Calendar.JULY, Calendar.JULY, Calendar.JANUARY}; - int[] switchOverDay = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + /* + * check currency changes + * In current implementation, there is no data of old currency and transition date at jdk/src/share/classes/java/util/CurrencyData.properties. + * So, all the switch data arrays are empty. In the future, if data of old currency and transition date are necessary for any country, the + * arrays here can be updated so that the program can check the currency switch. + */ + String[] switchOverCtry = {}; + String[] switchOverOld = {}; + String[] switchOverNew = {}; + String[] switchOverTZ = {}; + int[] switchOverYear = {}; + int[] switchOverMonth = {}; + int[] switchOverDay = {}; + for (int i = 0; i < switchOverCtry.length; i++) { TimeZone.setDefault(TimeZone.getTimeZone(switchOverTZ[i])); Calendar date = new GregorianCalendar(switchOverYear[i], switchOverMonth[i], switchOverDay[i]); diff --git a/jdk/test/java/util/Currency/ValidateISO4217.java b/jdk/test/java/util/Currency/ValidateISO4217.java index 3f5078060d4..679acfa20a9 100644 --- a/jdk/test/java/util/Currency/ValidateISO4217.java +++ b/jdk/test/java/util/Currency/ValidateISO4217.java @@ -92,7 +92,7 @@ public class ValidateISO4217 { /* Codes that are obsolete, do not have related country */ static final String otherCodes = - "ADP-AFA-ATS-AYM-BEF-BGL-BOV-BYB-CLF-CUC-CYP-DEM-EEK-ESP-FIM-FRF-GRD-GWP-IEP-ITL-LUF-MGF-MTL-MXV-NLG-PTE-RUR-SDD-SIT-SKK-SRG-TMM-TPE-TRL-VEF-USN-USS-XAG-XAU-XBA-XBB-XBC-XBD-XDR-XFO-XFU-XPD-XPT-XSU-XTS-XUA-XXX-YUM-ZWD-ZWN-ZWR"; + "ADP-AFA-ATS-AYM-AZM-BEF-BGL-BOV-BYB-CLF-CUC-CYP-DEM-EEK-ESP-FIM-FRF-GHC-GRD-GWP-IEP-ITL-LUF-MGF-MTL-MXV-MZM-NLG-PTE-ROL-RUR-SDD-SIT-SKK-SRG-TMM-TPE-TRL-VEF-USN-USS-VEB-XAG-XAU-XBA-XBB-XBC-XBD-XDR-XFO-XFU-XPD-XPT-XSU-XTS-XUA-XXX-YUM-ZWD-ZWN-ZWR"; static boolean err = false; diff --git a/jdk/test/java/util/Currency/tablea1.txt b/jdk/test/java/util/Currency/tablea1.txt index 898af09b538..8b2e1b5871f 100644 --- a/jdk/test/java/util/Currency/tablea1.txt +++ b/jdk/test/java/util/Currency/tablea1.txt @@ -23,7 +23,7 @@ AW AWG 533 2 AU AUD 36 2 AT EUR 978 2 # MA 129 -AZ AZM 31 2 2005-12-31-20-00-00 AZN 944 2 +AZ AZN 944 2 BS BSD 44 2 BH BHD 48 3 BD BDT 50 2 @@ -96,7 +96,7 @@ GA XAF 950 0 GM GMD 270 2 GE GEL 981 2 DE EUR 978 2 -GH GHC 288 2 2007-07-01-00-00-00 GHS 936 2 +GH GHS 936 2 GI GIP 292 2 GR EUR 978 2 GL DKK 208 2 @@ -166,7 +166,7 @@ MN MNT 496 2 MS XCD 951 2 MA MAD 504 2 # MA 130 -MZ MZM 508 2 2006-06-30-22-00-00 MZN 943 2 +MZ MZN 943 2 MM MMK 104 2 # MA 134 ME EUR 978 2 @@ -200,7 +200,7 @@ PT EUR 978 2 PR USD 840 2 QA QAR 634 2 RE EUR 978 2 -RO ROL 946 2 2005-06-30-21-00-00 RON 946 2 +RO RON 946 2 RU RUB 643 2 RW RWF 646 0 SH SHP 654 2 @@ -266,7 +266,7 @@ UM USD 840 2 UY UYU 858 2 UZ UZS 860 2 VU VUV 548 0 -VE VEB 862 2 2008-01-01-04-00-00 VEF 937 2 +VE VEF 937 2 VN VND 704 2 VG USD 840 2 VI USD 840 2 From 0db43a9227678e1b7b03bdb2008cc43ac645dcc4 Mon Sep 17 00:00:00 2001 From: Yong Jeffrey Huang Date: Mon, 31 Oct 2011 21:30:11 -0700 Subject: [PATCH 060/107] 6755060: Collator.compare() does not compare correctly for the Thai locale Reviewed-by: naoto --- .../sun/text/resources/CollationData_th.java | 93 ++++++++-------- .../text/resources/Collator/Bug6755060.java | 100 ++++++++++++++++++ 2 files changed, 142 insertions(+), 51 deletions(-) create mode 100644 jdk/test/sun/text/resources/Collator/Bug6755060.java diff --git a/jdk/src/share/classes/sun/text/resources/CollationData_th.java b/jdk/src/share/classes/sun/text/resources/CollationData_th.java index 0adc262c4db..311a11f1a0b 100644 --- a/jdk/src/share/classes/sun/text/resources/CollationData_th.java +++ b/jdk/src/share/classes/sun/text/resources/CollationData_th.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -103,18 +103,13 @@ public class CollationData_th extends ListResourceBundle { // // Normal vowels // + + "< \u0E4D " // NIKHAHIT + "< \u0E30 " // SARA A + "< \u0E31 " // MAI HAN-AKAT + "< \u0E32 " // SARA AA - // Normalizer will decompose this character to \u0e4d\u0e32. This is - // a Bad Thing, because we want the separate characters to sort - // differently than this individual one. Since there's no public way to - // set the decomposition to be used when creating a collator, there's - // no way around this right now. - // It's best to go ahead and leave the character in, because it occurs - // this way a lot more often than it occurs as separate characters. - + "< \u0E33 " // SARA AM + // Normalizer will decompose this character to \u0e4d\u0e32. + + "< \u0E33 = \u0E4D\u0E32 " // SARA AM + "< \u0E34 " // SARA I @@ -133,62 +128,58 @@ public class CollationData_th extends ListResourceBundle { + "< \u0E43 " // SARA AI MAIMUAN + "< \u0E44 " // SARA AI MAIMALAI - // - // Digits - // - + "< \u0E50 " // DIGIT ZERO - + "< \u0E51 " // DIGIT ONE - + "< \u0E52 " // DIGIT TWO - + "< \u0E53 " // DIGIT THREE - + "< \u0E54 " // DIGIT FOUR - + "< \u0E55 " // DIGIT FIVE - + "< \u0E56 " // DIGIT SIX - + "< \u0E57 " // DIGIT SEVEN - + "< \u0E58 " // DIGIT EIGHT - + "< \u0E59 " // DIGIT NINE - // Sorta tonal marks, but maybe not really - + "< \u0E4D " // NIKHAHIT + //according to CLDR, it's after 0e44 + + "< \u0E3A " // PHINTHU - // - // Thai symbols are supposed to sort "after white space". - // I'm treating this as making them sort just after the normal Latin-1 - // symbols, which are in turn after the white space. - // - + "&'\u007d'" // right-brace - + "< \u0E2F " // PAIYANNOI (ellipsis, abbreviation) - + "< \u0E46 " // MAIYAMOK - + "< \u0E4F " // FONGMAN - + "< \u0E5A " // ANGKHANKHU - + "< \u0E5B " // KHOMUT - + "< \u0E3F " // CURRENCY SYMBOL BAHT - // These symbols are supposed to be "after all characters" - + "< \u0E4E " // YAMAKKAN - // This rare symbol also comes after all characters. But when it is - // used in combination with RU and LU, the combination is treated as - // a separate letter, ala "CH" sorting after "C" in traditional Spanish. + // This rare symbol comes after all characters. + "< \u0E45 " // LAKKHANGYAO - + "& \u0E24 < \u0E24\u0E45 " - + "& \u0E26 < \u0E26\u0E45 " + + "& \u0E32 , \0E45 " // According to CLDR, 0E45 is after 0E32 in tertiary level - // Tonal marks are primary ignorables but are treated as secondary - // differences + + + + // Below are thai puntuation marks and Tonal(Accent) marks. According to CLDR 1.9 and + // ISO/IEC 14651, Annex C, C.2.1 Thai ordering principles, 0E2F to 0E5B are punctuaion marks that need to be ignored + // in the first three leveles. 0E4E to 0E4B are tonal marks to be compared in secondary level. + // In real implmentation, set puncutation marks in tertiary as there is no fourth level in Java. + // Set all these special marks after \u0301, the accute accent. + "& \u0301 " // acute accent + + //puncutation marks + + ", \u0E2F " // PAIYANNOI (ellipsis, abbreviation) + + ", \u0E46 " // MAIYAMOK + + ", \u0E4F " // FONGMAN + + ", \u0E5A " // ANGKHANKHU + + ", \u0E5B " // KHOMUT + + //tonal marks + + "; \u0E4E " // YAMAKKAN + + "; \u0E4C " // THANTHAKHAT + "; \u0E47 " // MAITAIKHU + "; \u0E48 " // MAI EK + "; \u0E49 " // MAI THO + "; \u0E4A " // MAI TRI + "; \u0E4B " // MAI CHATTAWA - + "; \u0E4C " // THANTHAKHAT + + // + // Digits are equal to their corresponding Arabic digits in the first level + // + + "& 0 = \u0E50 " // DIGIT ZERO + + "& 1 = \u0E51 " // DIGIT ONE + + "& 2 = \u0E52 " // DIGIT TWO + + "& 3 = \u0E53 " // DIGIT THREE + + "& 4 = \u0E54 " // DIGIT FOUR + + "& 5 = \u0E55 " // DIGIT FIVE + + "& 6 = \u0E56 " // DIGIT SIX + + "& 7 = \u0E57 " // DIGIT SEVEN + + "& 8 = \u0E58 " // DIGIT EIGHT + + "& 9 = \u0E59 " // DIGIT NINE - // These are supposed to be ignored, so I'm treating them as controls - + "& \u0001 " - + "= \u0E3A " // PHINTHU - + "= '.' " // period - } + } }; } } diff --git a/jdk/test/sun/text/resources/Collator/Bug6755060.java b/jdk/test/sun/text/resources/Collator/Bug6755060.java new file mode 100644 index 00000000000..ee23487d44b --- /dev/null +++ b/jdk/test/sun/text/resources/Collator/Bug6755060.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2011, 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 6755060 + * @summary updating collation tables for thai to make it consistent with CLDR 1.9 + */ + +import java.text.*; +import java.util.*; + +public class Bug6755060 { + + /******************************************************** + *********************************************************/ + public static void main (String[] args) { + + Locale reservedLocale = Locale.getDefault(); + + try{ + + int errors=0; + + Locale loc = new Locale ("th", "TH"); // Thai + + Locale.setDefault (loc); + Collator col = Collator.getInstance (); + + /* + * The original data "data" are the data to be sorted provided by the submitter of the CR. + * It's in correct order in accord with thai collation in CLDR 1.9. If we use old Java without this fix, + * the output order will be incorrect. Correct order will be turned into incorrect order. + + * If fix is there, "data" after sorting will be unchanged, same as "sortedData". If fix is lost (regression), + * "data" after sorting will be changed, not as "sortedData".(not correct anymore) + + * The submitter of the CR also gives a expected "sortedData" in the CR, but it's in accord with collation in CLDR 1.4. + * His data to be sorted are actually well sorted in accord with CLDR 1.9. + */ + + String[] data = {"\u0e01", "\u0e01\u0e2f", "\u0e01\u0e46", "\u0e01\u0e4f", "\u0e01\u0e5a", "\u0e01\u0e5b", "\u0e01\u0e4e", "\u0e01\u0e4c", "\u0e01\u0e48", "\u0e01\u0e01", "\u0e01\u0e4b\u0e01", "\u0e01\u0e4d", "\u0e01\u0e30", "\u0e01\u0e31\u0e01", "\u0e01\u0e32", "\u0e01\u0e33", "\u0e01\u0e34", "\u0e01\u0e35", "\u0e01\u0e36", "\u0e01\u0e37", "\u0e01\u0e38", "\u0e01\u0e39", "\u0e40\u0e01", "\u0e40\u0e01\u0e48", "\u0e40\u0e01\u0e49", "\u0e40\u0e01\u0e4b", "\u0e41\u0e01", "\u0e42\u0e01", "\u0e43\u0e01", "\u0e44\u0e01", "\u0e01\u0e3a", "\u0e24\u0e32", "\u0e24\u0e45", "\u0e40\u0e25", "\u0e44\u0e26"}; + + String[] sortedData = {"\u0e01", "\u0e01\u0e2f", "\u0e01\u0e46", "\u0e01\u0e4f", "\u0e01\u0e5a", "\u0e01\u0e5b", "\u0e01\u0e4e", "\u0e01\u0e4c", "\u0e01\u0e48", "\u0e01\u0e01", "\u0e01\u0e4b\u0e01", "\u0e01\u0e4d", "\u0e01\u0e30", "\u0e01\u0e31\u0e01", "\u0e01\u0e32", "\u0e01\u0e33", "\u0e01\u0e34", "\u0e01\u0e35", "\u0e01\u0e36", "\u0e01\u0e37", "\u0e01\u0e38", "\u0e01\u0e39", "\u0e40\u0e01", "\u0e40\u0e01\u0e48", "\u0e40\u0e01\u0e49", "\u0e40\u0e01\u0e4b", "\u0e41\u0e01", "\u0e42\u0e01", "\u0e43\u0e01", "\u0e44\u0e01", "\u0e01\u0e3a", "\u0e24\u0e32", "\u0e24\u0e45", "\u0e40\u0e25", "\u0e44\u0e26"}; + + Arrays.sort (data, col); + + System.out.println ("Using " + loc.getDisplayName()); + for (int i = 0; i < data.length; i++) { + System.out.println(data[i] + " : " + sortedData[i]); + if (sortedData[i].compareTo(data[i]) != 0) { + errors++; + } + }//end for + + if (errors > 0){ + StringBuffer expected = new StringBuffer(), actual = new StringBuffer(); + expected.append(sortedData[0]); + actual.append(data[0]); + + for (int i=1; i Date: Mon, 31 Oct 2011 21:43:07 -0700 Subject: [PATCH 061/107] 7101495: In Latvia first day of week is Monday Reviewed-by: naoto, peytoia --- .../util/resources/CalendarData_lv.properties | 56 +++++++++++++------ jdk/test/sun/text/resources/LocaleData | 4 ++ .../sun/text/resources/LocaleDataTest.java | 2 +- 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/jdk/src/share/classes/sun/util/resources/CalendarData_lv.properties b/jdk/src/share/classes/sun/util/resources/CalendarData_lv.properties index 36167c9c604..126532a799c 100644 --- a/jdk/src/share/classes/sun/util/resources/CalendarData_lv.properties +++ b/jdk/src/share/classes/sun/util/resources/CalendarData_lv.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2011, 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,21 +23,45 @@ # questions. # -# (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved -# (C) Copyright IBM Corp. 1996 - 1999 - All Rights Reserved # -# The original version of this source code and documentation -# is copyrighted and owned by Taligent, Inc., a wholly-owned -# subsidiary of IBM. These materials are provided under terms -# of a License Agreement between Taligent and Sun. This technology -# is protected by multiple US and International patents. +# COPYRIGHT AND PERMISSION NOTICE # -# This notice and attribution to Taligent may not be removed. -# Taligent is a registered trademark of Taligent, Inc. +# Copyright (C) 1991-2011 Unicode, Inc. All rights reserved. +# Distributed under the Terms of Use in http://www.unicode.org/copyright.html. +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of the Unicode data files and any associated documentation (the +# "Data Files") or Unicode software and any associated documentation +# (the "Software") to deal in the Data Files or Software without +# restriction, including without limitation the rights to use, copy, +# modify, merge, publish, distribute, and/or sell copies of the Data +# Files or Software, and to permit persons to whom the Data Files or +# Software are furnished to do so, provided that (a) the above copyright +# notice(s) and this permission notice appear with all copies of the +# Data Files or Software, (b) both the above copyright notice(s) and +# this permission notice appear in associated documentation, and (c) +# there is clear notice in each modified Data File or in the Software as +# well as in the documentation associated with the Data File(s) or +# Software that the data or software has been modified. +# +# THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF +# ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT +# HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR +# ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THE DATA FILES OR +# SOFTWARE. +# +# Except as contained in this notice, the name of a copyright holder +# shall not be used in advertising or otherwise to promote the sale, use +# or other dealings in these Data Files or Software without prior +# written authorization of the copyright holder. - -# This bundle is empty because the data of the base bundle -# is adequate for this locale. -# The bundle is necessary to prevent the resource -# bundle lookup from falling back to the default -# locale. +# +# Generated automatically from the Common Locale Data Repository. DO NOT EDIT! +# +firstDayOfWeek=2 +minimalDaysInFirstWeek=4 diff --git a/jdk/test/sun/text/resources/LocaleData b/jdk/test/sun/text/resources/LocaleData index 00960071bd0..2c66a972a28 100644 --- a/jdk/test/sun/text/resources/LocaleData +++ b/jdk/test/sun/text/resources/LocaleData @@ -7006,3 +7006,7 @@ CurrencyNames/zh_CN/zwl=\u6d25\u5df4\u5e03\u97e6\u5143 (2009) CurrencyNames/zh_TW/cuc=\u53e4\u5df4\u53ef\u8f49\u63db\u62ab\u7d22 CurrencyNames/zh_TW/tmt=\u571f\u5eab\u66fc\u65b0\u99ac\u7d0d\u7279 CurrencyNames/zh_TW/zwl=\u8f9b\u5df4\u5a01\u5143 (2009) + +# bug 7101495 +CalendarData/lv/firstDayOfWeek=2 +CalendarData/lv/minimalDaysInFirstWeek=4 diff --git a/jdk/test/sun/text/resources/LocaleDataTest.java b/jdk/test/sun/text/resources/LocaleDataTest.java index 6ec423627bd..836b1b2763e 100644 --- a/jdk/test/sun/text/resources/LocaleDataTest.java +++ b/jdk/test/sun/text/resources/LocaleDataTest.java @@ -33,7 +33,7 @@ * 6379214 6485516 6486607 4225362 4494727 6533691 6531591 6531593 6570259 * 6509039 6609737 6610748 6645271 6507067 6873931 6450945 6645268 6646611 * 6645405 6650730 6910489 6573250 6870908 6585666 6716626 6914413 6916787 - * 6919624 6998391 7019267 7020960 7025837 7020583 7036905 7066203 + * 6919624 6998391 7019267 7020960 7025837 7020583 7036905 7066203 7101495 * @summary Verify locale data * */ From 2c5cec930abf2a9c31be9d7c1a88548374ee623d Mon Sep 17 00:00:00 2001 From: Rickard Backman Date: Tue, 1 Nov 2011 13:44:40 +0100 Subject: [PATCH 062/107] 7106766: Move the precompiled header from the src/share/vm directory Moved precompiled.hpp to src/share/vm/precompiled Reviewed-by: coleenp, dholmes --- hotspot/make/bsd/makefiles/buildtree.make | 2 ++ hotspot/make/bsd/makefiles/gcc.make | 2 +- hotspot/make/linux/makefiles/buildtree.make | 2 ++ hotspot/make/linux/makefiles/gcc.make | 2 +- hotspot/make/solaris/makefiles/buildtree.make | 2 ++ hotspot/make/solaris/makefiles/gcc.make | 4 ++-- hotspot/make/windows/makefiles/vm.make | 1 + hotspot/src/share/vm/{ => precompiled}/precompiled.hpp | 0 8 files changed, 11 insertions(+), 4 deletions(-) rename hotspot/src/share/vm/{ => precompiled}/precompiled.hpp (100%) diff --git a/hotspot/make/bsd/makefiles/buildtree.make b/hotspot/make/bsd/makefiles/buildtree.make index 094332012e1..f412310f9aa 100644 --- a/hotspot/make/bsd/makefiles/buildtree.make +++ b/hotspot/make/bsd/makefiles/buildtree.make @@ -234,6 +234,8 @@ flags.make: $(BUILDTREE_MAKE) ../shared_dirs.lst echo "$(call gamma-path,commonsrc,share/vm/prims) \\"; \ echo "$(call gamma-path,altsrc,share/vm) \\"; \ echo "$(call gamma-path,commonsrc,share/vm) \\"; \ + echo "$(call gamma-path,altsrc,share/vm/precompiled) \\"; \ + echo "$(call gamma-path,commonsrc,share/vm/precompiled) \\"; \ echo "$(call gamma-path,altsrc,cpu/$(SRCARCH)/vm) \\"; \ echo "$(call gamma-path,commonsrc,cpu/$(SRCARCH)/vm) \\"; \ echo "$(call gamma-path,altsrc,os_cpu/$(OS_FAMILY)_$(SRCARCH)/vm) \\"; \ diff --git a/hotspot/make/bsd/makefiles/gcc.make b/hotspot/make/bsd/makefiles/gcc.make index be09894628f..62148457083 100644 --- a/hotspot/make/bsd/makefiles/gcc.make +++ b/hotspot/make/bsd/makefiles/gcc.make @@ -88,7 +88,7 @@ ifneq "$(shell expr \( $(CC_VER_MAJOR) \> 3 \) \| \( \( $(CC_VER_MAJOR) = 3 \) \ ifneq ($(USE_PRECOMPILED_HEADER),0) USE_PRECOMPILED_HEADER=1 PRECOMPILED_HEADER_DIR=. -PRECOMPILED_HEADER_SRC=$(GAMMADIR)/src/share/vm/precompiled.hpp +PRECOMPILED_HEADER_SRC=$(GAMMADIR)/src/share/vm/precompiled/precompiled.hpp PRECOMPILED_HEADER=$(PRECOMPILED_HEADER_DIR)/precompiled.hpp.gch endif endif diff --git a/hotspot/make/linux/makefiles/buildtree.make b/hotspot/make/linux/makefiles/buildtree.make index f8a1e885c5f..b1eb00bb98c 100644 --- a/hotspot/make/linux/makefiles/buildtree.make +++ b/hotspot/make/linux/makefiles/buildtree.make @@ -223,6 +223,8 @@ flags.make: $(BUILDTREE_MAKE) ../shared_dirs.lst echo "$(call gamma-path,commonsrc,share/vm/prims) \\"; \ echo "$(call gamma-path,altsrc,share/vm) \\"; \ echo "$(call gamma-path,commonsrc,share/vm) \\"; \ + echo "$(call gamma-path,altsrc,share/vm/precompiled) \\"; \ + echo "$(call gamma-path,commonsrc,share/vm/precompiled) \\"; \ echo "$(call gamma-path,altsrc,cpu/$(SRCARCH)/vm) \\"; \ echo "$(call gamma-path,commonsrc,cpu/$(SRCARCH)/vm) \\"; \ echo "$(call gamma-path,altsrc,os_cpu/$(OS_FAMILY)_$(SRCARCH)/vm) \\"; \ diff --git a/hotspot/make/linux/makefiles/gcc.make b/hotspot/make/linux/makefiles/gcc.make index e36cec66f76..2da52739b6a 100644 --- a/hotspot/make/linux/makefiles/gcc.make +++ b/hotspot/make/linux/makefiles/gcc.make @@ -52,7 +52,7 @@ ifneq "$(shell expr \( $(CC_VER_MAJOR) \> 3 \) \| \( \( $(CC_VER_MAJOR) = 3 \) \ ifneq ($(USE_PRECOMPILED_HEADER),0) USE_PRECOMPILED_HEADER=1 PRECOMPILED_HEADER_DIR=. -PRECOMPILED_HEADER_SRC=$(GAMMADIR)/src/share/vm/precompiled.hpp +PRECOMPILED_HEADER_SRC=$(GAMMADIR)/src/share/vm/precompiled/precompiled.hpp PRECOMPILED_HEADER=$(PRECOMPILED_HEADER_DIR)/precompiled.hpp.gch endif endif diff --git a/hotspot/make/solaris/makefiles/buildtree.make b/hotspot/make/solaris/makefiles/buildtree.make index 30e03bedb8b..a46d6b3378f 100644 --- a/hotspot/make/solaris/makefiles/buildtree.make +++ b/hotspot/make/solaris/makefiles/buildtree.make @@ -216,6 +216,8 @@ flags.make: $(BUILDTREE_MAKE) ../shared_dirs.lst echo "$(call gamma-path,commonsrc,share/vm/prims) \\"; \ echo "$(call gamma-path,altsrc,share/vm) \\"; \ echo "$(call gamma-path,commonsrc,share/vm) \\"; \ + echo "$(call gamma-path,altsrc,share/vm/precompiled) \\"; \ + echo "$(call gamma-path,commonsrc,share/vm/precompiled) \\"; \ echo "$(call gamma-path,altsrc,cpu/$(ARCH)/vm) \\"; \ echo "$(call gamma-path,commonsrc,cpu/$(ARCH)/vm) \\"; \ echo "$(call gamma-path,altsrc,os_cpu/$(OS_FAMILY)_$(ARCH)/vm) \\"; \ diff --git a/hotspot/make/solaris/makefiles/gcc.make b/hotspot/make/solaris/makefiles/gcc.make index b0cdfc9a231..15e43ea8d66 100644 --- a/hotspot/make/solaris/makefiles/gcc.make +++ b/hotspot/make/solaris/makefiles/gcc.make @@ -1,5 +1,5 @@ # -# Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1998, 2011, 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 @@ -51,7 +51,7 @@ ifneq "$(shell expr \( $(CC_VER_MAJOR) \> 3 \) \| \( \( $(CC_VER_MAJOR) = 3 \) \ ifneq ($(USE_PRECOMPILED_HEADER),0) USE_PRECOMPILED_HEADER=1 PRECOMPILED_HEADER_DIR=. -PRECOMPILED_HEADER_SRC=$(GAMMADIR)/src/share/vm/precompiled.hpp +PRECOMPILED_HEADER_SRC=$(GAMMADIR)/src/share/vm/precompiled/precompiled.hpp PRECOMPILED_HEADER=$(PRECOMPILED_HEADER_DIR)/precompiled.hpp.gch endif endif diff --git a/hotspot/make/windows/makefiles/vm.make b/hotspot/make/windows/makefiles/vm.make index 1ee86646137..f0b1b933630 100644 --- a/hotspot/make/windows/makefiles/vm.make +++ b/hotspot/make/windows/makefiles/vm.make @@ -134,6 +134,7 @@ CPP_INCLUDE_DIRS=$(CPP_INCLUDE_DIRS) /I "$(ALTSRC)\cpu\$(Platform_arch)\vm" CPP_INCLUDE_DIRS=$(CPP_INCLUDE_DIRS) \ /I "$(COMMONSRC)\share\vm" \ + /I "$(COMMONSRC)\share\vm\precompiled" \ /I "$(COMMONSRC)\share\vm\prims" \ /I "$(COMMONSRC)\os\windows\vm" \ /I "$(COMMONSRC)\os_cpu\windows_$(Platform_arch)\vm" \ diff --git a/hotspot/src/share/vm/precompiled.hpp b/hotspot/src/share/vm/precompiled/precompiled.hpp similarity index 100% rename from hotspot/src/share/vm/precompiled.hpp rename to hotspot/src/share/vm/precompiled/precompiled.hpp From dae561e3ea7bf36f567cd68b2ea619d31bc8d58a Mon Sep 17 00:00:00 2001 From: Jim Holmlund Date: Tue, 1 Nov 2011 15:49:45 -0700 Subject: [PATCH 063/107] 7101933: langtools jtreg tests do not work with jprt on windows Fixed langtools/test/Makefile to work on cygwin. Updated jtreg to 4.1 and JCK to JCK8. Reviewed-by: jjg, ohair --- langtools/test/Makefile | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/langtools/test/Makefile b/langtools/test/Makefile index 7f6435f037c..8964a006ffb 100644 --- a/langtools/test/Makefile +++ b/langtools/test/Makefile @@ -19,6 +19,7 @@ # Get OS/ARCH specifics OSNAME = $(shell uname -s) ifeq ($(OSNAME), SunOS) + SLASH_JAVA = /java PLATFORM = solaris JT_PLATFORM = solaris ARCH = $(shell uname -p) @@ -27,6 +28,7 @@ ifeq ($(OSNAME), SunOS) endif endif ifeq ($(OSNAME), Linux) + SLASH_JAVA = /java PLATFORM = linux JT_PLATFORM = linux ARCH = $(shell uname -m) @@ -35,7 +37,16 @@ ifeq ($(OSNAME), Linux) endif endif ifeq ($(OSNAME), Windows_NT) + # MKS + PLATFORM=windows +endif +ifeq ($(PLATFORM),) PLATFORM = windows + CYGPATH = | cygpath -m -s -f - +endif + +ifeq ($(PLATFORM), windows) + SLASH_JAVA = J: JT_PLATFORM = win32 ifeq ($(word 1, $(PROCESSOR_IDENTIFIER)),ia64) ARCH=ia64 @@ -54,7 +65,7 @@ ifeq ($(OSNAME), Windows_NT) endif # Root of this test area (important to use full paths in some places) -TEST_ROOT := $(shell pwd) +TEST_ROOT := $(shell pwd $(CYGPATH) ) # Default bundle of all test results (passed or not) (JPRT only) ifdef JPRT_JOB_ID @@ -72,7 +83,7 @@ endif ifdef JPRT_JTREG_HOME JTREG_HOME = $(JPRT_JTREG_HOME) else - JTREG_HOME = $(SLASH_JAVA)/re/jtreg/4.0/promoted/latest/binaries/jtreg + JTREG_HOME = $(SLASH_JAVA)/re/jtreg/4.1/promoted/latest/binaries/jtreg endif JTREG = $(JTREG_HOME)/$(JT_PLATFORM)/bin/jtreg JTDIFF = $(JTREG_HOME)/$(JT_PLATFORM)/bin/jtdiff @@ -81,7 +92,7 @@ JTDIFF = $(JTREG_HOME)/$(JT_PLATFORM)/bin/jtdiff ifdef JPRT_JCK_HOME JCK_HOME = $(JPRT_JCK_HOME) else - JCK_HOME = $(SLASH_JAVA)/re/jck/7/promoted/latest/binaries + JCK_HOME = $(SLASH_JAVA)/re/jck/8/promoted/latest/binaries endif # Default JDK for JTREG and JCK @@ -93,7 +104,7 @@ endif ifdef JPRT_JAVA_HOME JT_JAVA = $(JPRT_JAVA_HOME) else - JT_JAVA = $(SLASH_JAVA)/re/jdk/1.6.0/archive/fcs/binaries/$(PLATFORM)-$(ARCH) + JT_JAVA = $(SLASH_JAVA)/re/jdk/1.7.0/archive/fcs/binaries/$(PLATFORM)-$(ARCH) endif # Default JDK to test @@ -195,7 +206,7 @@ TEST_OUTPUT_DIR = $(TEST_ROOT)/../build/$(PLATFORM)-$(ARCH)/test/langtools ABS_TEST_OUTPUT_DIR := \ $(shell mkdir -p $(TEST_ROOT)/../build/$(PLATFORM)-$(ARCH)/test/langtools; \ cd $(TEST_ROOT)/../build/$(PLATFORM)-$(ARCH)/test/langtools; \ - pwd ) + pwd $(CYGPATH)) # Subdirectories for different test runs JTREG_OUTPUT_DIR = $(ABS_TEST_OUTPUT_DIR)/jtreg JCK_COMPILER_OUTPUT_DIR = $(ABS_TEST_OUTPUT_DIR)/jck-compiler @@ -272,15 +283,17 @@ jtreg-summary: FRC fi # Check to make sure these directories exist -check-jtreg: $(JT_HOME) $(PRODUCT_HOME) $(JTREG) +check-jtreg: $(PRODUCT_HOME) $(JTREG) # Run JCK-compiler tests # # JCK_HOME # Installed location of JCK: should include JCK-compiler, and JCK-extras +# Default is JCK 8. # JT_JAVA # Version of java used to run JCK. Should normally be the same as TESTJAVA +# Default is JDK 7 # TESTJAVA # Version of java to be tested. # JCK_COMPILER_OPTIONS @@ -297,7 +310,7 @@ jck-compiler-tests: check-jck FRC $(JCK_COMPILER_OUTPUT_DIR)/diff.html $(JCK_COMPILER_OUTPUT_DIR)/status.txt @mkdir -p $(JCK_COMPILER_OUTPUT_DIR) $(JT_JAVA)/bin/java -XX:MaxPermSize=256m -Xmx512m \ - -jar $(JCK_HOME)/JCK-compiler-7/lib/jtjck.jar \ + -jar $(JCK_HOME)/JCK-compiler-8/lib/jtjck.jar \ -v:non-pass \ -r:$(JCK_COMPILER_OUTPUT_DIR)/report \ -w:$(JCK_COMPILER_OUTPUT_DIR)/work \ @@ -346,7 +359,7 @@ jck-runtime-tests: check-jck FRC $(JCK_RUNTIME_OUTPUT_DIR)/diff.html $(JCK_RUNTIME_OUTPUT_DIR)/status.txt @mkdir -p $(JCK_RUNTIME_OUTPUT_DIR) $(JT_JAVA)/bin/java -XX:MaxPermSize=256m -Xmx512m \ - -jar $(JCK_HOME)/JCK-runtime-7/lib/jtjck.jar \ + -jar $(JCK_HOME)/JCK-runtime-8/lib/jtjck.jar \ -v:non-pass \ -r:$(JCK_RUNTIME_OUTPUT_DIR)/report \ -w:$(JCK_RUNTIME_OUTPUT_DIR)/work \ @@ -373,7 +386,7 @@ jck-runtime-summary: FRC fi # Check to make sure these directories exist -check-jck: $(JT_HOME) $(JCK_HOME) $(PRODUCT_HOME) +check-jck: $(JCK_HOME) $(PRODUCT_HOME) all-summary: FRC if [ -n "`find $(TEST_OUTPUT_DIR) -name status.txt`" ]; then From acf5a65a3675b2e426dee5244cd8cd476bd58617 Mon Sep 17 00:00:00 2001 From: David Katleman Date: Thu, 3 Nov 2011 10:32:05 -0700 Subject: [PATCH 064/107] Added tag jdk8-b12 for changeset f0f8f1159227 --- .hgtags-top-repo | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags-top-repo b/.hgtags-top-repo index bb8cba99e8b..55fb765ce49 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -133,3 +133,4 @@ fb1bc13260d76447e269e843859eb593fe2a8ab2 jdk8-b08 8adb70647b5af5273dfe6a540f07be667cd50216 jdk8-b09 a6c4c248e8fa350c35014fa94bab5ac1a1ac3299 jdk8-b10 1defbc57940a56f0aa41e9dee87b71e8c8b71103 jdk8-b11 +8e2104d565baee473895d5eba20e39f85ab4bf9f jdk8-b12 From c7cad98c9d93a6d077ad9283bfeb7592e1b1fade Mon Sep 17 00:00:00 2001 From: David Katleman Date: Thu, 3 Nov 2011 10:32:11 -0700 Subject: [PATCH 065/107] Added tag jdk8-b12 for changeset 0023f3816a1f --- corba/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/corba/.hgtags b/corba/.hgtags index bd2e17921d4..551fa0151c5 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -133,3 +133,4 @@ cc1b599b986a37cb57de4584c5e58169766ca535 jdk8-b05 a891732c1a83082177ff7a4cf1506068d9cc0a47 jdk8-b09 cda87f7fefcee3b89742a57ce5ad9b03a54c210d jdk8-b10 0199e4fef5cc2bd234c65b93220459ef7a3bb3b1 jdk8-b11 +31d70911b712c6b4e580a3110363d5f044cfed7a jdk8-b12 From 169afafaf7d4a3c06117e716d72d21816a5d630a Mon Sep 17 00:00:00 2001 From: David Katleman Date: Thu, 3 Nov 2011 10:32:16 -0700 Subject: [PATCH 066/107] Added tag jdk8-b12 for changeset dbb81ca736fc --- hotspot/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/.hgtags b/hotspot/.hgtags index 46612cd8947..cbcd9bb10e5 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -195,3 +195,4 @@ d815de2e85e511b7deab2a83cf80c0224d011da9 jdk8-b10 4d3850d9d326ac3a9bee2d867727e954322d014e hs23-b03 4538caeef7b6cbd4302bebced805d65e68ccf301 jdk8-b11 6534482ff68ad79066dfe15dfb6d8905f09681bd hs23-b04 +1d3900713a67a0a39faf4e12c9c158d55aebef87 jdk8-b12 From ab91a77f0c6c406058e299347a14634375fb74ca Mon Sep 17 00:00:00 2001 From: David Katleman Date: Thu, 3 Nov 2011 10:32:23 -0700 Subject: [PATCH 067/107] Added tag jdk8-b12 for changeset 043062d0d76a --- jaxp/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jaxp/.hgtags b/jaxp/.hgtags index e0ff678bbaa..b1a3e0eacf7 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -133,3 +133,4 @@ de4794dd69c48b08029d158a972993ff9d5627df jdk8-b08 93554324c014282571aeeb48552ad00d3fedb089 jdk8-b09 d21a4d5141c04bc9e88f2c0253121d449b66d667 jdk8-b10 d1b7a4f6dd2065fdeafbcdfd9dcc0072da8c6881 jdk8-b11 +ca977d167697a561c04894187fc1c4d927582ffa jdk8-b12 From 4af82ec8870c879b417e15ea151dce0af1db322b Mon Sep 17 00:00:00 2001 From: David Katleman Date: Thu, 3 Nov 2011 10:32:24 -0700 Subject: [PATCH 068/107] Added tag jdk8-b12 for changeset cc748b263c6f --- jaxws/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jaxws/.hgtags b/jaxws/.hgtags index 3eec004d4a8..712808d6c18 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -133,3 +133,4 @@ acffff22a9465005e8eb206224fae9f2ea4fd469 jdk8-b06 70172e57cf29efe271b068987eefb601c2a77780 jdk8-b09 8e7fdc8e3c758644ca6d0fd70bb255e9d2e64cda jdk8-b10 a12ab897a249feb7859a6e6cd84b49411f4c06ac jdk8-b11 +e6eed2ff5d5f62bdc815beb5276d23347600c760 jdk8-b12 From 7982aae1c43d44e6d9bafc3f853b54a35d9531ae Mon Sep 17 00:00:00 2001 From: David Katleman Date: Thu, 3 Nov 2011 10:32:29 -0700 Subject: [PATCH 069/107] Added tag jdk8-b12 for changeset 7e570cc378fb --- jdk/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/.hgtags b/jdk/.hgtags index 515e0f72fbc..e1e7ba132b7 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -133,3 +133,4 @@ bdb870cc269ef8b221d17a217be89092400b59d2 jdk8-b06 f1ec21b8142168ff40f3278d2f6b5fe4bd5f3b26 jdk8-b09 4788745572ef2bde34924ef34e7e4d55ba07e979 jdk8-b10 7ab0d613cd1a271a9763ffb894dc1f0a5b95a7e4 jdk8-b11 +09fd2067f715e4505c44b01c301258a4e8f8964e jdk8-b12 From 524b8ef2fef43014eb402e6449c19d8506fca1f2 Mon Sep 17 00:00:00 2001 From: David Katleman Date: Thu, 3 Nov 2011 10:32:39 -0700 Subject: [PATCH 070/107] Added tag jdk8-b12 for changeset 5ec6698ec5a9 --- langtools/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/langtools/.hgtags b/langtools/.hgtags index 06958e1b0c5..cbf5eea7c0e 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -133,3 +133,4 @@ e8acc2d6c32f0c8321e642e1a86672a2e196a056 jdk8-b08 b7a7e47c8d3daf7822abf7c37e5179ccbbf53008 jdk8-b09 f6c783e18bdf4d46a0ab273868afebbf32600ff7 jdk8-b10 4bf01f1c4e3464f378959d10f3983a0469181d94 jdk8-b11 +f2d6ed25857dfa7f269ac66e13666d648cb988c6 jdk8-b12 From bc9976349418993a7f16f87980c46ee6bf021567 Mon Sep 17 00:00:00 2001 From: Darryl Mocek Date: Thu, 3 Nov 2011 13:26:57 -0700 Subject: [PATCH 071/107] 4533691: Add Collections.emptySortedSet() Reviewed-by: mduigou, alanb, dholmes --- .../share/classes/java/util/Collections.java | 96 +++++ .../java/util/Collections/EmptySortedSet.java | 351 ++++++++++++++++++ 2 files changed, 447 insertions(+) create mode 100644 jdk/test/java/util/Collections/EmptySortedSet.java diff --git a/jdk/src/share/classes/java/util/Collections.java b/jdk/src/share/classes/java/util/Collections.java index e55eb59296e..04e642e1c00 100644 --- a/jdk/src/share/classes/java/util/Collections.java +++ b/jdk/src/share/classes/java/util/Collections.java @@ -3201,6 +3201,102 @@ public class Collections { } } + /** + * Returns the empty sorted set (immutable). This set is serializable. + * + *

This example illustrates the type-safe way to obtain an empty sorted + * set: + *

+     *     SortedSet<String> s = Collections.emptySortedSet();
+     * 
+ * Implementation note: Implementations of this method need not + * create a separate SortedSet object for each call. + * + * @since 1.8 + */ + @SuppressWarnings("unchecked") + public static final SortedSet emptySortedSet() { + return (SortedSet) new EmptySortedSet<>(); + } + + /** + * @serial include + */ + private static class EmptySortedSet + extends AbstractSet + implements SortedSet, Serializable + { + private static final long serialVersionUID = 6316515401502265487L; + public Iterator iterator() { return emptyIterator(); } + public int size() {return 0;} + public boolean isEmpty() {return true;} + public boolean contains(Object obj) {return false;} + public boolean containsAll(Collection c) { return c.isEmpty(); } + public Object[] toArray() { return new Object[0]; } + + public E[] toArray(E[] a) { + if (a.length > 0) + a[0] = null; + return a; + } + + // Preserves singleton property + private Object readResolve() { + return new EmptySortedSet<>(); + } + + public Comparator comparator() { + return null; + } + + public SortedSet subSet(Object fromElement, Object toElement) { + Objects.requireNonNull(fromElement); + Objects.requireNonNull(toElement); + + if (!(fromElement instanceof Comparable) || + !(toElement instanceof Comparable)) + { + throw new ClassCastException(); + } + + if ((((Comparable)fromElement).compareTo(toElement) >= 0) || + (((Comparable)toElement).compareTo(fromElement) < 0)) + { + throw new IllegalArgumentException(); + } + + return emptySortedSet(); + } + + public SortedSet headSet(Object toElement) { + Objects.requireNonNull(toElement); + + if (!(toElement instanceof Comparable)) { + throw new ClassCastException(); + } + + return emptySortedSet(); + } + + public SortedSet tailSet(Object fromElement) { + Objects.requireNonNull(fromElement); + + if (!(fromElement instanceof Comparable)) { + throw new ClassCastException(); + } + + return emptySortedSet(); + } + + public E first() { + throw new NoSuchElementException(); + } + + public E last() { + throw new NoSuchElementException(); + } + } + /** * The empty list (immutable). This list is serializable. * diff --git a/jdk/test/java/util/Collections/EmptySortedSet.java b/jdk/test/java/util/Collections/EmptySortedSet.java new file mode 100644 index 00000000000..224400ec7a8 --- /dev/null +++ b/jdk/test/java/util/Collections/EmptySortedSet.java @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2011, 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 4533691 + * @summary Unit test for Collections.emptySortedSet + */ + +import java.lang.reflect.Method; +import java.math.BigInteger; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.SortedSet; +import java.util.TreeSet; + +public class EmptySortedSet { + static int status = 0; + private static final String FAILED = " failed. "; + private static final String PERIOD = "."; + private final String thisClassName = this.getClass().getName(); + + public static void main(String[] args) throws Exception { + new EmptySortedSet(); + } + + public EmptySortedSet() throws Exception { + run(); + } + + /** + * Returns {@code true} if the {@link Object} passed in is an empty + * {@link SortedSet}. + * + * @param obj the object to test + * @return {@code true} if the {@link Object} is an empty {@link SortedSet} + * otherwise {@code false}. + */ + private boolean isEmptySortedSet(Object obj) { + boolean isEmptySortedSet = false; + + // We determine if the object is an empty sorted set by testing if it's + // an instance of SortedSet, and if so, if it's empty. Currently the + // testing doesn't include checks of the other methods. + if (obj instanceof SortedSet) { + SortedSet ss = (SortedSet) obj; + + if ((ss.isEmpty()) && (ss.size() == 0)) { + isEmptySortedSet = true; + } + } + + return isEmptySortedSet; + } + + private void run() throws Exception { + Method[] methods = this.getClass().getDeclaredMethods(); + + for (int i = 0; i < methods.length; i++) { + Method method = methods[i]; + String methodName = method.getName(); + + if (methodName.startsWith("test")) { + try { + Object obj = method.invoke(this, new Object[0]); + } catch(Exception e) { + throw new Exception(this.getClass().getName() + "." + + methodName + " test failed, test exception " + + "follows\n" + e.getCause()); + } + } + } + } + + private void throwException(String methodName, String reason) + throws Exception + { + StringBuilder sb = new StringBuilder(thisClassName); + sb.append(PERIOD); + sb.append(methodName); + sb.append(FAILED); + sb.append(reason); + throw new Exception(sb.toString()); + } + + /** + * + */ + private void test00() throws Exception { + //throwException("test00", "This test has not been implemented yet."); + } + + /** + * Tests that the comparator is {@code null}. + */ + private void testComparatorIsNull() throws Exception { + SortedSet sortedSet = Collections.emptySortedSet(); + Comparator comparator = sortedSet.comparator(); + + if (comparator != null) { + throwException("testComparatorIsNull", "Comparator is not null."); + } + } + + /** + * Tests that the contains method returns {@code false}. + */ + private void testContains() throws Exception { + SortedSet sortedSet = Collections.emptySortedSet(); + + if (sortedSet.contains(new Object())) { + throwException("testContains", "Should not contain any elements."); + } + } + + /** + * Tests that the containsAll method returns {@code false}. + */ + private void testContainsAll() throws Exception { + SortedSet sortedSet = Collections.emptySortedSet(); + TreeSet treeSet = new TreeSet(); + treeSet.add("1"); + treeSet.add("2"); + treeSet.add("3"); + + if (sortedSet.containsAll(treeSet)) { + throwException("testContainsAll", + "Should not contain any elements."); + } + } + + /** + * Tests that the iterator is empty. + */ + private void testEmptyIterator() throws Exception { + SortedSet sortedSet = Collections.emptySortedSet(); + Iterator emptyIterator = sortedSet.iterator(); + + if ((emptyIterator != null) && (emptyIterator.hasNext())) { + throwException("testEmptyIterator", "The iterator is not empty."); + } + } + + /** + * Tests that the set is empty. + */ + private void testIsEmpty() throws Exception { + SortedSet sortedSet = Collections.emptySortedSet(); + + if ((sortedSet != null) && (!sortedSet.isEmpty())) { + throwException("testSizeIsZero", "The set is not empty."); + } + } + + /** + * Tests that the first() method throws NoSuchElementException + */ + private void testFirst() throws Exception { + SortedSet sortedSet = Collections.emptySortedSet(); + + try { + sortedSet.first(); + throwException("testFirst", + "NoSuchElemenException was not thrown."); + } catch(NoSuchElementException nsee) { + // Do nothing + } + } + + /** + * Tests the headSet() method. + */ + private void testHeadSet() throws Exception { + SortedSet sortedSet = Collections.emptySortedSet(); + SortedSet ss; + + try { + ss = sortedSet.headSet(null); + throwException("testHeadSet", + "Must throw NullPointerException for null element"); + } catch(NullPointerException npe) { + // Do nothing + } + + try { + ss = sortedSet.headSet(new Object()); + throwException("testHeadSet", + "Must throw ClassCastException for non-Comparable element"); + } catch(ClassCastException cce) { + // Do nothing. + } + + ss = sortedSet.headSet("1"); + + if ((ss == null) || !isEmptySortedSet(ss)) { + throwException("testHeadSet", + "Returned value is null or not an EmptySortedSet."); + } + } + + /** + * Tests that the last() method throws NoSuchElementException + */ + private void testLast() throws Exception { + SortedSet sortedSet = Collections.emptySortedSet(); + + try { + sortedSet.last(); + throwException("testLast", + "NoSuchElemenException was not thrown."); + } catch(NoSuchElementException nsee) { + // Do nothing + } + } + + /** + * Tests that the size is 0. + */ + private void testSizeIsZero() throws Exception { + SortedSet sortedSet = Collections.emptySortedSet(); + int size = sortedSet.size(); + + if (size > 0) { + throwException("testSizeIsZero", + "The size of the set is greater then 0."); + } + } + + /** + * Tests the subSet() method. + */ + private void testSubSet() throws Exception { + SortedSet sortedSet = Collections.emptySortedSet(); + SortedSet ss = sortedSet.headSet("1"); + + try { + ss = sortedSet.subSet(null, BigInteger.TEN); + ss = sortedSet.subSet(BigInteger.ZERO, null); + ss = sortedSet.subSet(null, null); + throwException("testSubSet", + "Must throw NullPointerException for null element"); + } catch(NullPointerException npe) { + // Do nothing + } + + try { + Object obj1 = new Object(); + Object obj2 = new Object(); + ss = sortedSet.subSet(obj1, BigInteger.TEN); + ss = sortedSet.subSet(BigInteger.ZERO, obj2); + ss = sortedSet.subSet(obj1, obj2); + throwException("testSubSet", + "Must throw ClassCastException for parameter which is " + + "not Comparable."); + } catch(ClassCastException cce) { + // Do nothing. + } + + try { + ss = sortedSet.subSet(BigInteger.ZERO, BigInteger.ZERO); + ss = sortedSet.subSet(BigInteger.TEN, BigInteger.ZERO); + throwException("testSubSet", + "Must throw IllegalArgumentException when fromElement is " + + "not less then then toElement."); + } catch(IllegalArgumentException iae) { + // Do nothing. + } + + ss = sortedSet.subSet(BigInteger.ZERO, BigInteger.TEN); + + if (!isEmptySortedSet(ss)) { + throw new Exception("Returned value is not empty sorted set."); + } + } + + /** + * Tests the tailSet() method. + */ + private void testTailSet() throws Exception { + SortedSet sortedSet = Collections.emptySortedSet(); + SortedSet ss; + + try { + ss = sortedSet.tailSet(null); + throwException("testTailSet", + "Must throw NullPointerException for null element"); + } catch(NullPointerException npe) { + // Do nothing + } + + try { + SortedSet ss2 = sortedSet.tailSet(new Object()); + throwException("testTailSet", + "Must throw ClassCastException for non-Comparable element"); + } catch(ClassCastException cce) { + // Do nothing. + } + + ss = sortedSet.tailSet("1"); + + if ((ss == null) || !isEmptySortedSet(ss)) { + throwException("testTailSet", + "Returned value is null or not an EmptySortedSet."); + } + } + + /** + * Tests that the array has a size of 0. + */ + private void testToArray() throws Exception { + SortedSet sortedSet = Collections.emptySortedSet(); + Object[] emptySortedSetArray = sortedSet.toArray(); + + if ((emptySortedSetArray == null) || (emptySortedSetArray.length > 0)) { + throwException("testToArray", + "Returned null array or array with length > 0."); + } + + String[] strings = new String[2]; + strings[0] = "1"; + strings[1] = "2"; + emptySortedSetArray = sortedSet.toArray(strings); + + if ((emptySortedSetArray == null) || (emptySortedSetArray[0] != null)) { + throwException("testToArray", + "Returned null array or array with length > 0."); + } + } +} From be5a83c8ce8997bd7c57ba67b5ee310f664b3b5a Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Fri, 4 Nov 2011 12:36:40 +0000 Subject: [PATCH 072/107] 7104201: Refactor DocCommentScanner Add new Comment helper class to parse contents of comments in source code Reviewed-by: jjg --- .../sun/tools/javac/parser/JavaTokenizer.java | 422 ++++++------ .../sun/tools/javac/parser/JavacParser.java | 23 +- .../tools/javac/parser/JavadocTokenizer.java | 617 ++++++++---------- .../com/sun/tools/javac/parser/Tokens.java | 83 ++- .../sun/tools/javac/parser/UnicodeReader.java | 55 +- .../depDocComment/DeprecatedDocComment4.java | 20 + .../depDocComment/DeprecatedDocComment4.out | 6 + 7 files changed, 638 insertions(+), 588 deletions(-) create mode 100644 langtools/test/tools/javac/depDocComment/DeprecatedDocComment4.java create mode 100644 langtools/test/tools/javac/depDocComment/DeprecatedDocComment4.out diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java b/langtools/src/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java index f5a99ae9fa4..f9ce7a251de 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java @@ -25,10 +25,11 @@ package com.sun.tools.javac.parser; -import java.nio.CharBuffer; import com.sun.tools.javac.code.Source; +import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle; import com.sun.tools.javac.util.*; +import java.nio.CharBuffer; import static com.sun.tools.javac.parser.Tokens.*; import static com.sun.tools.javac.util.LayoutCharacters.*; @@ -65,9 +66,6 @@ public class JavaTokenizer { */ private final Log log; - /** The name table. */ - private final Names names; - /** The token factory. */ private final Tokens tokens; @@ -87,18 +85,12 @@ public class JavaTokenizer { */ protected int errPos = Position.NOPOS; - /** Has a @deprecated been encountered in last doc comment? - * this needs to be reset by client. + /** The Unicode reader (low-level stream reader). */ - protected boolean deprecatedFlag = false; - - /** A character buffer for saved chars. - */ - protected char[] sbuf = new char[128]; - protected int sp; - protected UnicodeReader reader; + protected ScannerFactory fac; + private static final boolean hexFloatsWork = hexFloatsWork(); private static boolean hexFloatsWork() { try { @@ -129,14 +121,14 @@ public class JavaTokenizer { } protected JavaTokenizer(ScannerFactory fac, UnicodeReader reader) { - log = fac.log; - names = fac.names; - tokens = fac.tokens; - source = fac.source; + this.fac = fac; + this.log = fac.log; + this.tokens = fac.tokens; + this.source = fac.source; this.reader = reader; - allowBinaryLiterals = source.allowBinaryLiterals(); - allowHexFloats = source.allowHexFloats(); - allowUnderscoresInLiterals = source.allowUnderscoresInLiterals(); + this.allowBinaryLiterals = source.allowBinaryLiterals(); + this.allowHexFloats = source.allowHexFloats(); + this.allowUnderscoresInLiterals = source.allowUnderscoresInLiterals(); } /** Report an error at the given position using the provided arguments. @@ -147,38 +139,13 @@ public class JavaTokenizer { errPos = pos; } - /** Read next character in comment, skipping over double '\' characters. - */ - protected void scanCommentChar() { - reader.scanChar(); - if (reader.ch == '\\') { - if (reader.peekChar() == '\\' && !reader.isUnicode()) { - reader.skipChar(); - } else { - reader.convertUnicode(); - } - } - } - - /** Append a character to sbuf. - */ - private void putChar(char ch) { - if (sp == sbuf.length) { - char[] newsbuf = new char[sbuf.length * 2]; - System.arraycopy(sbuf, 0, newsbuf, 0, sbuf.length); - sbuf = newsbuf; - } - sbuf[sp++] = ch; - } - /** Read next character in character or string literal and copy into sbuf. */ private void scanLitChar(int pos) { if (reader.ch == '\\') { if (reader.peekChar() == '\\' && !reader.isUnicode()) { reader.skipChar(); - putChar('\\'); - reader.scanChar(); + reader.putChar('\\', true); } else { reader.scanChar(); switch (reader.ch) { @@ -195,30 +162,30 @@ public class JavaTokenizer { reader.scanChar(); } } - putChar((char)oct); + reader.putChar((char)oct); break; case 'b': - putChar('\b'); reader.scanChar(); break; + reader.putChar('\b', true); break; case 't': - putChar('\t'); reader.scanChar(); break; + reader.putChar('\t', true); break; case 'n': - putChar('\n'); reader.scanChar(); break; + reader.putChar('\n', true); break; case 'f': - putChar('\f'); reader.scanChar(); break; + reader.putChar('\f', true); break; case 'r': - putChar('\r'); reader.scanChar(); break; + reader.putChar('\r', true); break; case '\'': - putChar('\''); reader.scanChar(); break; + reader.putChar('\'', true); break; case '\"': - putChar('\"'); reader.scanChar(); break; + reader.putChar('\"', true); break; case '\\': - putChar('\\'); reader.scanChar(); break; + reader.putChar('\\', true); break; default: lexError(reader.bp, "illegal.esc.char"); } } } else if (reader.bp != reader.buflen) { - putChar(reader.ch); reader.scanChar(); + reader.putChar(true); } } @@ -227,7 +194,7 @@ public class JavaTokenizer { int savePos; do { if (reader.ch != '_') { - putChar(reader.ch); + reader.putChar(false); } else { if (!allowUnderscoresInLiterals) { lexError(pos, "unsupported.underscore.lit", source.name); @@ -246,12 +213,10 @@ public class JavaTokenizer { */ private void scanHexExponentAndSuffix(int pos) { if (reader.ch == 'p' || reader.ch == 'P') { - putChar(reader.ch); - reader.scanChar(); + reader.putChar(true); skipIllegalUnderscores(); if (reader.ch == '+' || reader.ch == '-') { - putChar(reader.ch); - reader.scanChar(); + reader.putChar(true); } skipIllegalUnderscores(); if ('0' <= reader.ch && reader.ch <= '9') { @@ -268,14 +233,12 @@ public class JavaTokenizer { lexError(pos, "malformed.fp.lit"); } if (reader.ch == 'f' || reader.ch == 'F') { - putChar(reader.ch); - reader.scanChar(); + reader.putChar(true); tk = TokenKind.FLOATLITERAL; radix = 16; } else { if (reader.ch == 'd' || reader.ch == 'D') { - putChar(reader.ch); - reader.scanChar(); + reader.putChar(true); } tk = TokenKind.DOUBLELITERAL; radix = 16; @@ -289,14 +252,12 @@ public class JavaTokenizer { if ('0' <= reader.ch && reader.ch <= '9') { scanDigits(pos, 10); } - int sp1 = sp; + int sp1 = reader.sp; if (reader.ch == 'e' || reader.ch == 'E') { - putChar(reader.ch); - reader.scanChar(); + reader.putChar(true); skipIllegalUnderscores(); if (reader.ch == '+' || reader.ch == '-') { - putChar(reader.ch); - reader.scanChar(); + reader.putChar(true); } skipIllegalUnderscores(); if ('0' <= reader.ch && reader.ch <= '9') { @@ -304,7 +265,7 @@ public class JavaTokenizer { return; } lexError(pos, "malformed.fp.lit"); - sp = sp1; + reader.sp = sp1; } } @@ -314,13 +275,11 @@ public class JavaTokenizer { radix = 10; scanFraction(pos); if (reader.ch == 'f' || reader.ch == 'F') { - putChar(reader.ch); - reader.scanChar(); + reader.putChar(true); tk = TokenKind.FLOATLITERAL; } else { if (reader.ch == 'd' || reader.ch == 'D') { - putChar(reader.ch); - reader.scanChar(); + reader.putChar(true); } tk = TokenKind.DOUBLELITERAL; } @@ -331,8 +290,7 @@ public class JavaTokenizer { private void scanHexFractionAndSuffix(int pos, boolean seendigit) { radix = 16; Assert.check(reader.ch == '.'); - putChar(reader.ch); - reader.scanChar(); + reader.putChar(true); skipIllegalUnderscores(); if (reader.digit(pos, 16) >= 0) { seendigit = true; @@ -369,8 +327,7 @@ public class JavaTokenizer { } else if (seendigit && radix == 16 && (reader.ch == 'p' || reader.ch == 'P')) { scanHexExponentAndSuffix(pos); } else if (digitRadix == 10 && reader.ch == '.') { - putChar(reader.ch); - reader.scanChar(); + reader.putChar(true); scanFractionAndSuffix(pos); } else if (digitRadix == 10 && (reader.ch == 'e' || reader.ch == 'E' || @@ -393,10 +350,7 @@ public class JavaTokenizer { boolean isJavaIdentifierPart; char high; do { - if (sp == sbuf.length) putChar(reader.ch); else sbuf[sp++] = reader.ch; - // optimization, was: putChar(reader.ch); - - reader.scanChar(); + reader.putChar(true); switch (reader.ch) { case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': @@ -423,7 +377,7 @@ public class JavaTokenizer { break; case '\u001A': // EOI is also a legal identifier part if (reader.bp >= reader.buflen) { - name = names.fromChars(sbuf, 0, sp); + name = reader.name(); tk = tokens.lookupKind(name); return; } @@ -435,11 +389,7 @@ public class JavaTokenizer { } else { high = reader.scanSurrogates(); if (high != 0) { - if (sp == sbuf.length) { - putChar(high); - } else { - sbuf[sp++] = high; - } + reader.putChar(high); isJavaIdentifierPart = Character.isJavaIdentifierPart( Character.toCodePoint(high, reader.ch)); } else { @@ -447,7 +397,7 @@ public class JavaTokenizer { } } if (!isJavaIdentifierPart) { - name = names.fromChars(sbuf, 0, sp); + name = reader.name(); tk = tokens.lookupKind(name); return; } @@ -474,11 +424,11 @@ public class JavaTokenizer { */ private void scanOperator() { while (true) { - putChar(reader.ch); - Name newname = names.fromChars(sbuf, 0, sp); + reader.putChar(false); + Name newname = reader.name(); TokenKind tk1 = tokens.lookupKind(newname); if (tk1 == TokenKind.IDENTIFIER) { - sp--; + reader.sp--; break; } tk = tk1; @@ -487,111 +437,17 @@ public class JavaTokenizer { } } - /** - * Scan a documentation comment; determine if a deprecated tag is present. - * Called once the initial /, * have been skipped, positioned at the second * - * (which is treated as the beginning of the first line). - * Stops positioned at the closing '/'. - */ - @SuppressWarnings("fallthrough") - private void scanDocComment() { - boolean deprecatedPrefix = false; - - forEachLine: - while (reader.bp < reader.buflen) { - - // Skip optional WhiteSpace at beginning of line - while (reader.bp < reader.buflen && (reader.ch == ' ' || reader.ch == '\t' || reader.ch == FF)) { - scanCommentChar(); - } - - // Skip optional consecutive Stars - while (reader.bp < reader.buflen && reader.ch == '*') { - scanCommentChar(); - if (reader.ch == '/') { - return; - } - } - - // Skip optional WhiteSpace after Stars - while (reader.bp < reader.buflen && (reader.ch == ' ' || reader.ch == '\t' || reader.ch == FF)) { - scanCommentChar(); - } - - deprecatedPrefix = false; - // At beginning of line in the JavaDoc sense. - if (reader.bp < reader.buflen && reader.ch == '@' && !deprecatedFlag) { - scanCommentChar(); - if (reader.bp < reader.buflen && reader.ch == 'd') { - scanCommentChar(); - if (reader.bp < reader.buflen && reader.ch == 'e') { - scanCommentChar(); - if (reader.bp < reader.buflen && reader.ch == 'p') { - scanCommentChar(); - if (reader.bp < reader.buflen && reader.ch == 'r') { - scanCommentChar(); - if (reader.bp < reader.buflen && reader.ch == 'e') { - scanCommentChar(); - if (reader.bp < reader.buflen && reader.ch == 'c') { - scanCommentChar(); - if (reader.bp < reader.buflen && reader.ch == 'a') { - scanCommentChar(); - if (reader.bp < reader.buflen && reader.ch == 't') { - scanCommentChar(); - if (reader.bp < reader.buflen && reader.ch == 'e') { - scanCommentChar(); - if (reader.bp < reader.buflen && reader.ch == 'd') { - deprecatedPrefix = true; - scanCommentChar(); - }}}}}}}}}}} - if (deprecatedPrefix && reader.bp < reader.buflen) { - if (Character.isWhitespace(reader.ch)) { - deprecatedFlag = true; - } else if (reader.ch == '*') { - scanCommentChar(); - if (reader.ch == '/') { - deprecatedFlag = true; - return; - } - } - } - - // Skip rest of line - while (reader.bp < reader.buflen) { - switch (reader.ch) { - case '*': - scanCommentChar(); - if (reader.ch == '/') { - return; - } - break; - case CR: // (Spec 3.4) - scanCommentChar(); - if (reader.ch != LF) { - continue forEachLine; - } - /* fall through to LF case */ - case LF: // (Spec 3.4) - scanCommentChar(); - continue forEachLine; - default: - scanCommentChar(); - } - } // rest of line - } // forEachLine - return; - } - /** Read token. */ public Token readToken() { - sp = 0; + reader.sp = 0; name = null; - deprecatedFlag = false; radix = 0; + int pos = 0; int endPos = 0; + List comments = null; try { loop: while (true) { @@ -656,7 +512,7 @@ public class JavaTokenizer { scanNumber(pos, 2); } } else { - putChar('0'); + reader.putChar('0'); if (reader.ch == '_') { int savePos = reader.bp; do { @@ -676,14 +532,13 @@ public class JavaTokenizer { case '.': reader.scanChar(); if ('0' <= reader.ch && reader.ch <= '9') { - putChar('.'); + reader.putChar('.'); scanFractionAndSuffix(pos); } else if (reader.ch == '.') { - putChar('.'); putChar('.'); - reader.scanChar(); + reader.putChar('.'); reader.putChar('.', true); if (reader.ch == '.') { reader.scanChar(); - putChar('.'); + reader.putChar('.'); tk = TokenKind.ELLIPSIS; } else { lexError(pos, "malformed.fp.lit"); @@ -712,32 +567,36 @@ public class JavaTokenizer { reader.scanChar(); if (reader.ch == '/') { do { - scanCommentChar(); + reader.scanCommentChar(); } while (reader.ch != CR && reader.ch != LF && reader.bp < reader.buflen); if (reader.bp < reader.buflen) { - processComment(pos, reader.bp, CommentStyle.LINE); + comments = addDocReader(comments, processComment(pos, reader.bp, CommentStyle.LINE)); } break; } else if (reader.ch == '*') { + boolean isEmpty = false; reader.scanChar(); CommentStyle style; if (reader.ch == '*') { style = CommentStyle.JAVADOC; - scanDocComment(); + reader.scanCommentChar(); + if (reader.ch == '/') { + isEmpty = true; + } } else { style = CommentStyle.BLOCK; - while (reader.bp < reader.buflen) { - if (reader.ch == '*') { - reader.scanChar(); - if (reader.ch == '/') break; - } else { - scanCommentChar(); - } + } + while (!isEmpty && reader.bp < reader.buflen) { + if (reader.ch == '*') { + reader.scanChar(); + if (reader.ch == '/') break; + } else { + reader.scanCommentChar(); } } if (reader.ch == '/') { reader.scanChar(); - processComment(pos, reader.bp, style); + comments = addDocReader(comments, processComment(pos, reader.bp, style)); break; } else { lexError(pos, "unclosed.comment"); @@ -789,11 +648,7 @@ public class JavaTokenizer { } else { char high = reader.scanSurrogates(); if (high != 0) { - if (sp == sbuf.length) { - putChar(high); - } else { - sbuf[sp++] = high; - } + reader.putChar(high); isJavaIdentifierStart = Character.isJavaIdentifierStart( Character.toCodePoint(high, reader.ch)); @@ -816,10 +671,10 @@ public class JavaTokenizer { } endPos = reader.bp; switch (tk.tag) { - case DEFAULT: return new Token(tk, pos, endPos, deprecatedFlag); - case NAMED: return new NamedToken(tk, pos, endPos, name, deprecatedFlag); - case STRING: return new StringToken(tk, pos, endPos, new String(sbuf, 0, sp), deprecatedFlag); - case NUMERIC: return new NumericToken(tk, pos, endPos, new String(sbuf, 0, sp), radix, deprecatedFlag); + case DEFAULT: return new Token(tk, pos, endPos, comments); + case NAMED: return new NamedToken(tk, pos, endPos, name, comments); + case STRING: return new StringToken(tk, pos, endPos, reader.chars(), comments); + case NUMERIC: return new NumericToken(tk, pos, endPos, reader.chars(), radix, comments); default: throw new AssertionError(); } } @@ -832,6 +687,12 @@ public class JavaTokenizer { } } } + //where + List addDocReader(List docReaders, Comment docReader) { + return docReaders == null ? + List.of(docReader) : + docReaders.prepend(docReader); + } /** Return the position where a lexical error occurred; */ @@ -845,22 +706,18 @@ public class JavaTokenizer { errPos = pos; } - public enum CommentStyle { - LINE, - BLOCK, - JAVADOC, - } - /** * Called when a complete comment has been scanned. pos and endPos * will mark the comment boundary. */ - protected void processComment(int pos, int endPos, CommentStyle style) { + protected Tokens.Comment processComment(int pos, int endPos, CommentStyle style) { if (scannerDebug) System.out.println("processComment(" + pos + "," + endPos + "," + style + ")=|" + new String(reader.getRawCharacters(pos, endPos)) + "|"); + char[] buf = reader.getRawCharacters(pos, endPos); + return new BasicComment(new UnicodeReader(fac, buf, buf.length), style); } /** @@ -893,4 +750,125 @@ public class JavaTokenizer { public Position.LineMap getLineMap() { return Position.makeLineMap(reader.getRawCharacters(), reader.buflen, false); } + + + /** + * Scan a documentation comment; determine if a deprecated tag is present. + * Called once the initial /, * have been skipped, positioned at the second * + * (which is treated as the beginning of the first line). + * Stops positioned at the closing '/'. + */ + protected class BasicComment implements Comment { + + CommentStyle cs; + U comment_reader; + + protected boolean deprecatedFlag = false; + protected boolean scanned = false; + + protected BasicComment(U comment_reader, CommentStyle cs) { + this.comment_reader = comment_reader; + this.cs = cs; + } + + public String getText() { + return null; + } + + public CommentStyle getStyle() { + return cs; + } + + public boolean isDeprecated() { + if (!scanned && cs == CommentStyle.JAVADOC) { + scanDocComment(); + } + return deprecatedFlag; + } + + @SuppressWarnings("fallthrough") + protected void scanDocComment() { + try { + boolean deprecatedPrefix = false; + + comment_reader.bp += 3; // '/**' + comment_reader.ch = comment_reader.buf[comment_reader.bp]; + + forEachLine: + while (comment_reader.bp < comment_reader.buflen) { + + // Skip optional WhiteSpace at beginning of line + while (comment_reader.bp < comment_reader.buflen && (comment_reader.ch == ' ' || comment_reader.ch == '\t' || comment_reader.ch == FF)) { + comment_reader.scanCommentChar(); + } + + // Skip optional consecutive Stars + while (comment_reader.bp < comment_reader.buflen && comment_reader.ch == '*') { + comment_reader.scanCommentChar(); + if (comment_reader.ch == '/') { + return; + } + } + + // Skip optional WhiteSpace after Stars + while (comment_reader.bp < comment_reader.buflen && (comment_reader.ch == ' ' || comment_reader.ch == '\t' || comment_reader.ch == FF)) { + comment_reader.scanCommentChar(); + } + + deprecatedPrefix = false; + // At beginning of line in the JavaDoc sense. + if (!deprecatedFlag) { + String deprecated = "@deprecated"; + int i = 0; + while (comment_reader.bp < comment_reader.buflen && comment_reader.ch == deprecated.charAt(i)) { + comment_reader.scanCommentChar(); + i++; + if (i == deprecated.length()) { + deprecatedPrefix = true; + break; + } + } + } + + if (deprecatedPrefix && comment_reader.bp < comment_reader.buflen) { + if (Character.isWhitespace(comment_reader.ch)) { + deprecatedFlag = true; + } else if (comment_reader.ch == '*') { + comment_reader.scanCommentChar(); + if (comment_reader.ch == '/') { + deprecatedFlag = true; + return; + } + } + } + + // Skip rest of line + while (comment_reader.bp < comment_reader.buflen) { + switch (comment_reader.ch) { + case '*': + comment_reader.scanCommentChar(); + if (comment_reader.ch == '/') { + return; + } + break; + case CR: // (Spec 3.4) + comment_reader.scanCommentChar(); + if (comment_reader.ch != LF) { + continue forEachLine; + } + /* fall through to LF case */ + case LF: // (Spec 3.4) + comment_reader.scanCommentChar(); + continue forEachLine; + default: + comment_reader.scanCommentChar(); + } + } // rest of line + } // forEachLine + return; + } finally { + scanned = true; + } + } + } } diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java index 9c754978a56..841a30de493 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -29,6 +29,7 @@ import java.util.*; import com.sun.tools.javac.code.*; import com.sun.tools.javac.parser.Tokens.*; +import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle; import com.sun.tools.javac.tree.*; import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.util.*; @@ -1584,7 +1585,7 @@ public class JavacParser implements Parser { break; case MONKEYS_AT: case FINAL: { - String dc = token.docComment; + String dc = token.comment(CommentStyle.JAVADOC); JCModifiers mods = modifiersOpt(); if (token.kind == INTERFACE || token.kind == CLASS || @@ -1601,21 +1602,21 @@ public class JavacParser implements Parser { break; } case ABSTRACT: case STRICTFP: { - String dc = token.docComment; + String dc = token.comment(CommentStyle.JAVADOC); JCModifiers mods = modifiersOpt(); stats.append(classOrInterfaceOrEnumDeclaration(mods, dc)); break; } case INTERFACE: case CLASS: - String dc = token.docComment; + String dc = token.comment(CommentStyle.JAVADOC); stats.append(classOrInterfaceOrEnumDeclaration(modifiersOpt(), dc)); break; case ENUM: case ASSERT: if (allowEnums && token.kind == ENUM) { error(token.pos, "local.enum"); - dc = token.docComment; + dc = token.comment(CommentStyle.JAVADOC); stats.append(classOrInterfaceOrEnumDeclaration(modifiersOpt(), dc)); break; } else if (allowAsserts && token.kind == ASSERT) { @@ -1991,7 +1992,7 @@ public class JavacParser implements Parser { annotations.appendList(partial.annotations); pos = partial.pos; } - if (token.deprecatedFlag) { + if (token.deprecatedFlag()) { flags |= Flags.DEPRECATED; } int lastPos = Position.NOPOS; @@ -2271,9 +2272,9 @@ public class JavacParser implements Parser { seenImport = true; defs.append(importDeclaration()); } else { - String docComment = token.docComment; + String docComment = token.comment(CommentStyle.JAVADOC); if (firstTypeDecl && !seenImport && !seenPackage) { - docComment = firstToken.docComment; + docComment = firstToken.comment(CommentStyle.JAVADOC); consumedToplevelDoc = true; } JCTree def = typeDeclaration(mods, docComment); @@ -2288,7 +2289,7 @@ public class JavacParser implements Parser { } JCTree.JCCompilationUnit toplevel = F.at(firstToken.pos).TopLevel(packageAnnotations, pid, defs.toList()); if (!consumedToplevelDoc) - attach(toplevel, firstToken.docComment); + attach(toplevel, firstToken.comment(CommentStyle.JAVADOC)); if (defs.elems.isEmpty()) storeEnd(toplevel, S.prevToken().endPos); if (keepDocComments) @@ -2498,9 +2499,9 @@ public class JavacParser implements Parser { /** EnumeratorDeclaration = AnnotationsOpt [TypeArguments] IDENTIFIER [ Arguments ] [ "{" ClassBody "}" ] */ JCTree enumeratorDeclaration(Name enumName) { - String dc = token.docComment; + String dc = token.comment(CommentStyle.JAVADOC); int flags = Flags.PUBLIC|Flags.STATIC|Flags.FINAL|Flags.ENUM; - if (token.deprecatedFlag) { + if (token.deprecatedFlag()) { flags |= Flags.DEPRECATED; } int pos = token.pos; @@ -2587,7 +2588,7 @@ public class JavacParser implements Parser { nextToken(); return List.nil(); } else { - String dc = token.docComment; + String dc = token.comment(CommentStyle.JAVADOC); int pos = token.pos; JCModifiers mods = modifiersOpt(); if (token.kind == CLASS || diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/JavadocTokenizer.java b/langtools/src/share/classes/com/sun/tools/javac/parser/JavadocTokenizer.java index 680485efddb..4aac62cd109 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/parser/JavadocTokenizer.java +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavadocTokenizer.java @@ -25,8 +25,8 @@ package com.sun.tools.javac.parser; -import com.sun.tools.javac.file.JavacFileManager; -import com.sun.tools.javac.parser.Tokens.Token; +import com.sun.tools.javac.parser.Tokens.Comment; +import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle; import com.sun.tools.javac.util.*; import java.nio.*; @@ -59,352 +59,295 @@ public class JavadocTokenizer extends JavaTokenizer { super(fac, input, inputLength); } - /** The comment input buffer, index of next chacter to be read, - * index of one past last character in buffer. - */ - private char[] buf; - private int bp; - private int buflen; - - /** The current character. - */ - private char ch; - - /** The column number position of the current character. - */ - private int col; - - /** The buffer index of the last converted Unicode character - */ - private int unicodeConversionBp = 0; - - /** - * Buffer for doc comment. - */ - private char[] docCommentBuffer = new char[1024]; - - /** - * Number of characters in doc comment buffer. - */ - private int docCommentCount; - - /** - * Translated and stripped contents of doc comment - */ - private String docComment = null; - - - /** Unconditionally expand the comment buffer. - */ - private void expandCommentBuffer() { - char[] newBuffer = new char[docCommentBuffer.length * 2]; - System.arraycopy(docCommentBuffer, 0, newBuffer, - 0, docCommentBuffer.length); - docCommentBuffer = newBuffer; + @Override + protected Comment processComment(int pos, int endPos, CommentStyle style) { + char[] buf = reader.getRawCharacters(pos, endPos); + return new JavadocComment(new ColReader(fac, buf, buf.length), style); } - /** Convert an ASCII digit from its base (8, 10, or 16) - * to its value. + /** + * This is a specialized version of UnicodeReader that keeps track of the + * column position within a given character stream (used for Javadoc processing). */ - private int digit(int base) { - char c = ch; - int result = Character.digit(c, base); - if (result >= 0 && c > 0x7f) { - ch = "0123456789abcdef".charAt(result); + static class ColReader extends UnicodeReader { + + int col; + + ColReader(ScannerFactory fac, char[] input, int inputLength) { + super(fac, input, inputLength); + } + + @Override + protected void convertUnicode() { + if (ch == '\\' && unicodeConversionBp != bp) { + bp++; ch = buf[bp]; col++; + if (ch == 'u') { + do { + bp++; ch = buf[bp]; col++; + } while (ch == 'u'); + int limit = bp + 3; + if (limit < buflen) { + int d = digit(bp, 16); + int code = d; + while (bp < limit && d >= 0) { + bp++; ch = buf[bp]; col++; + d = digit(bp, 16); + code = (code << 4) + d; + } + if (d >= 0) { + ch = (char)code; + unicodeConversionBp = bp; + return; + } + } + // "illegal.Unicode.esc", reported by base scanner + } else { + bp--; + ch = '\\'; + col--; + } + } + } + + @Override + protected void scanCommentChar() { + scanChar(); + if (ch == '\\') { + if (peekChar() == '\\' && !isUnicode()) { + putChar(ch, false); + bp++; col++; + } else { + convertUnicode(); + } + } + } + + @Override + protected void scanChar() { + bp++; + ch = buf[bp]; + switch (ch) { + case '\r': // return + col = 0; + break; + case '\n': // newline + if (bp == 0 || buf[bp-1] != '\r') { + col = 0; + } + break; + case '\t': // tab + col = (col / TabInc * TabInc) + TabInc; + break; + case '\\': // possible Unicode + col++; + convertUnicode(); + break; + default: + col++; + break; + } + } + } + + protected class JavadocComment extends JavaTokenizer.BasicComment { + + /** + * Translated and stripped contents of doc comment + */ + private String docComment = null; + + JavadocComment(ColReader comment_reader, CommentStyle cs) { + super(comment_reader, cs); } - return result; - } - /** Convert Unicode escape; bp points to initial '\' character - * (Spec 3.3). - */ - private void convertUnicode() { - if (ch == '\\' && unicodeConversionBp != bp) { - bp++; ch = buf[bp]; col++; - if (ch == 'u') { - do { - bp++; ch = buf[bp]; col++; - } while (ch == 'u'); - int limit = bp + 3; - if (limit < buflen) { - int d = digit(16); - int code = d; - while (bp < limit && d >= 0) { - bp++; ch = buf[bp]; col++; - d = digit(16); - code = (code << 4) + d; - } - if (d >= 0) { - ch = (char)code; - unicodeConversionBp = bp; - return; - } + public String getText() { + if (!scanned && cs == CommentStyle.JAVADOC) { + scanDocComment(); + } + return docComment; + } + + @Override + @SuppressWarnings("fallthrough") + protected void scanDocComment() { + try { + boolean firstLine = true; + + // Skip over first slash + comment_reader.scanCommentChar(); + // Skip over first star + comment_reader.scanCommentChar(); + + // consume any number of stars + while (comment_reader.bp < comment_reader.buflen && comment_reader.ch == '*') { + comment_reader.scanCommentChar(); + } + // is the comment in the form /**/, /***/, /****/, etc. ? + if (comment_reader.bp < comment_reader.buflen && comment_reader.ch == '/') { + docComment = ""; + return; + } + + // skip a newline on the first line of the comment. + if (comment_reader.bp < comment_reader.buflen) { + if (comment_reader.ch == LF) { + comment_reader.scanCommentChar(); + firstLine = false; + } else if (comment_reader.ch == CR) { + comment_reader.scanCommentChar(); + if (comment_reader.ch == LF) { + comment_reader.scanCommentChar(); + firstLine = false; + } + } + } + + outerLoop: + + // The outerLoop processes the doc comment, looping once + // for each line. For each line, it first strips off + // whitespace, then it consumes any stars, then it + // puts the rest of the line into our buffer. + while (comment_reader.bp < comment_reader.buflen) { + + // The wsLoop consumes whitespace from the beginning + // of each line. + wsLoop: + + while (comment_reader.bp < comment_reader.buflen) { + switch(comment_reader.ch) { + case ' ': + comment_reader.scanCommentChar(); + break; + case '\t': + comment_reader.col = ((comment_reader.col - 1) / TabInc * TabInc) + TabInc; + comment_reader.scanCommentChar(); + break; + case FF: + comment_reader.col = 0; + comment_reader.scanCommentChar(); + break; + // Treat newline at beginning of line (blank line, no star) + // as comment text. Old Javadoc compatibility requires this. + /*---------------------------------* + case CR: // (Spec 3.4) + doc_reader.scanCommentChar(); + if (ch == LF) { + col = 0; + doc_reader.scanCommentChar(); + } + break; + case LF: // (Spec 3.4) + doc_reader.scanCommentChar(); + break; + *---------------------------------*/ + default: + // we've seen something that isn't whitespace; + // jump out. + break wsLoop; + } + } + + // Are there stars here? If so, consume them all + // and check for the end of comment. + if (comment_reader.ch == '*') { + // skip all of the stars + do { + comment_reader.scanCommentChar(); + } while (comment_reader.ch == '*'); + + // check for the closing slash. + if (comment_reader.ch == '/') { + // We're done with the doc comment + // scanChar() and breakout. + break outerLoop; + } + } else if (! firstLine) { + //The current line does not begin with a '*' so we will indent it. + for (int i = 1; i < comment_reader.col; i++) { + comment_reader.putChar(' ', false); + } + } + // The textLoop processes the rest of the characters + // on the line, adding them to our buffer. + textLoop: + while (comment_reader.bp < comment_reader.buflen) { + switch (comment_reader.ch) { + case '*': + // Is this just a star? Or is this the + // end of a comment? + comment_reader.scanCommentChar(); + if (comment_reader.ch == '/') { + // This is the end of the comment, + // set ch and return our buffer. + break outerLoop; + } + // This is just an ordinary star. Add it to + // the buffer. + comment_reader.putChar('*', false); + break; + case ' ': + case '\t': + comment_reader.putChar(comment_reader.ch, false); + comment_reader.scanCommentChar(); + break; + case FF: + comment_reader.scanCommentChar(); + break textLoop; // treat as end of line + case CR: // (Spec 3.4) + comment_reader.scanCommentChar(); + if (comment_reader.ch != LF) { + // Canonicalize CR-only line terminator to LF + comment_reader.putChar((char)LF, false); + break textLoop; + } + /* fall through to LF case */ + case LF: // (Spec 3.4) + // We've seen a newline. Add it to our + // buffer and break out of this loop, + // starting fresh on a new line. + comment_reader.putChar(comment_reader.ch, false); + comment_reader.scanCommentChar(); + break textLoop; + default: + // Add the character to our buffer. + comment_reader.putChar(comment_reader.ch, false); + comment_reader.scanCommentChar(); + } + } // end textLoop + firstLine = false; + } // end outerLoop + + if (comment_reader.sp > 0) { + int i = comment_reader.sp - 1; + trailLoop: + while (i > -1) { + switch (comment_reader.sbuf[i]) { + case '*': + i--; + break; + default: + break trailLoop; + } + } + comment_reader.sp = i + 1; + + // Store the text of the doc comment + docComment = comment_reader.chars(); + } else { + docComment = ""; + } + } finally { + scanned = true; + if (docComment != null && + docComment.matches("(?sm).*^\\s*@deprecated( |$).*")) { + deprecatedFlag = true; } - // "illegal.Unicode.esc", reported by base scanner - } else { - bp--; - ch = '\\'; - col--; } } } - - /** Read next character. - */ - private void scanChar() { - bp++; - ch = buf[bp]; - switch (ch) { - case '\r': // return - col = 0; - break; - case '\n': // newline - if (bp == 0 || buf[bp-1] != '\r') { - col = 0; - } - break; - case '\t': // tab - col = (col / TabInc * TabInc) + TabInc; - break; - case '\\': // possible Unicode - col++; - convertUnicode(); - break; - default: - col++; - break; - } - } - @Override - public Token readToken() { - docComment = null; - Token tk = super.readToken(); - tk.docComment = docComment; - return tk; - } - - /** - * Read next character in doc comment, skipping over double '\' characters. - * If a double '\' is skipped, put in the buffer and update buffer count. - */ - private void scanDocCommentChar() { - scanChar(); - if (ch == '\\') { - if (buf[bp+1] == '\\' && unicodeConversionBp != bp) { - if (docCommentCount == docCommentBuffer.length) - expandCommentBuffer(); - docCommentBuffer[docCommentCount++] = ch; - bp++; col++; - } else { - convertUnicode(); - } - } - } - - /** - * Process a doc comment and make the string content available. - * Strips leading whitespace and stars. - */ - @SuppressWarnings("fallthrough") - protected void processComment(int pos, int endPos, CommentStyle style) { - if (style != CommentStyle.JAVADOC) { - return; - } - - buf = reader.getRawCharacters(pos, endPos); - buflen = buf.length; - bp = 0; - col = 0; - - docCommentCount = 0; - - boolean firstLine = true; - - // Skip over first slash - scanDocCommentChar(); - // Skip over first star - scanDocCommentChar(); - - // consume any number of stars - while (bp < buflen && ch == '*') { - scanDocCommentChar(); - } - // is the comment in the form /**/, /***/, /****/, etc. ? - if (bp < buflen && ch == '/') { - docComment = ""; - return; - } - - // skip a newline on the first line of the comment. - if (bp < buflen) { - if (ch == LF) { - scanDocCommentChar(); - firstLine = false; - } else if (ch == CR) { - scanDocCommentChar(); - if (ch == LF) { - scanDocCommentChar(); - firstLine = false; - } - } - } - - outerLoop: - - // The outerLoop processes the doc comment, looping once - // for each line. For each line, it first strips off - // whitespace, then it consumes any stars, then it - // puts the rest of the line into our buffer. - while (bp < buflen) { - - // The wsLoop consumes whitespace from the beginning - // of each line. - wsLoop: - - while (bp < buflen) { - switch(ch) { - case ' ': - scanDocCommentChar(); - break; - case '\t': - col = ((col - 1) / TabInc * TabInc) + TabInc; - scanDocCommentChar(); - break; - case FF: - col = 0; - scanDocCommentChar(); - break; -// Treat newline at beginning of line (blank line, no star) -// as comment text. Old Javadoc compatibility requires this. -/*---------------------------------* - case CR: // (Spec 3.4) - scanDocCommentChar(); - if (ch == LF) { - col = 0; - scanDocCommentChar(); - } - break; - case LF: // (Spec 3.4) - scanDocCommentChar(); - break; -*---------------------------------*/ - default: - // we've seen something that isn't whitespace; - // jump out. - break wsLoop; - } - } - - // Are there stars here? If so, consume them all - // and check for the end of comment. - if (ch == '*') { - // skip all of the stars - do { - scanDocCommentChar(); - } while (ch == '*'); - - // check for the closing slash. - if (ch == '/') { - // We're done with the doc comment - // scanChar() and breakout. - break outerLoop; - } - } else if (! firstLine) { - //The current line does not begin with a '*' so we will indent it. - for (int i = 1; i < col; i++) { - if (docCommentCount == docCommentBuffer.length) - expandCommentBuffer(); - docCommentBuffer[docCommentCount++] = ' '; - } - } - - // The textLoop processes the rest of the characters - // on the line, adding them to our buffer. - textLoop: - while (bp < buflen) { - switch (ch) { - case '*': - // Is this just a star? Or is this the - // end of a comment? - scanDocCommentChar(); - if (ch == '/') { - // This is the end of the comment, - // set ch and return our buffer. - break outerLoop; - } - // This is just an ordinary star. Add it to - // the buffer. - if (docCommentCount == docCommentBuffer.length) - expandCommentBuffer(); - docCommentBuffer[docCommentCount++] = '*'; - break; - case ' ': - case '\t': - if (docCommentCount == docCommentBuffer.length) - expandCommentBuffer(); - docCommentBuffer[docCommentCount++] = ch; - scanDocCommentChar(); - break; - case FF: - scanDocCommentChar(); - break textLoop; // treat as end of line - case CR: // (Spec 3.4) - scanDocCommentChar(); - if (ch != LF) { - // Canonicalize CR-only line terminator to LF - if (docCommentCount == docCommentBuffer.length) - expandCommentBuffer(); - docCommentBuffer[docCommentCount++] = (char)LF; - break textLoop; - } - /* fall through to LF case */ - case LF: // (Spec 3.4) - // We've seen a newline. Add it to our - // buffer and break out of this loop, - // starting fresh on a new line. - if (docCommentCount == docCommentBuffer.length) - expandCommentBuffer(); - docCommentBuffer[docCommentCount++] = ch; - scanDocCommentChar(); - break textLoop; - default: - // Add the character to our buffer. - if (docCommentCount == docCommentBuffer.length) - expandCommentBuffer(); - docCommentBuffer[docCommentCount++] = ch; - scanDocCommentChar(); - } - } // end textLoop - firstLine = false; - } // end outerLoop - - if (docCommentCount > 0) { - int i = docCommentCount - 1; - trailLoop: - while (i > -1) { - switch (docCommentBuffer[i]) { - case '*': - i--; - break; - default: - break trailLoop; - } - } - docCommentCount = i + 1; - - // Store the text of the doc comment - docComment = new String(docCommentBuffer, 0 , docCommentCount); - } else { - docComment = ""; - } - } - - /** Build a map for translating between line numbers and - * positions in the input. - * - * @return a LineMap */ public Position.LineMap getLineMap() { char[] buf = reader.getRawCharacters(); return Position.makeLineMap(buf, buf.length, true); diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/Tokens.java b/langtools/src/share/classes/com/sun/tools/javac/parser/Tokens.java index 934dfb90520..db2e1ec3c63 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/parser/Tokens.java +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/Tokens.java @@ -30,8 +30,10 @@ import java.util.Locale; import com.sun.tools.javac.api.Formattable; import com.sun.tools.javac.api.Messages; import com.sun.tools.javac.parser.Tokens.Token.Tag; +import com.sun.tools.javac.util.List; import com.sun.tools.javac.util.Name; import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Names; /** A class that defines codes/utilities for Java source tokens @@ -281,6 +283,19 @@ public class Tokens { } } + public interface Comment { + + enum CommentStyle { + LINE, + BLOCK, + JAVADOC, + } + + String getText(); + CommentStyle getStyle(); + boolean isDeprecated(); + } + /** * This is the class representing a javac token. Each token has several fields * that are set by the javac lexer (i.e. start/end position, string value, etc). @@ -304,18 +319,14 @@ public class Tokens { /** The end position of this token */ public final int endPos; - /** Is this token preceeded by a deprecated comment? */ - public final boolean deprecatedFlag; + /** Comment reader associated with this token */ + public final List comments; - /** Is this token preceeded by a deprecated comment? */ - public String docComment; - - Token(TokenKind kind, int pos, int endPos, - boolean deprecatedFlag) { + Token(TokenKind kind, int pos, int endPos, List comments) { this.kind = kind; this.pos = pos; this.endPos = endPos; - this.deprecatedFlag = deprecatedFlag; + this.comments = comments; checkKind(); } @@ -331,8 +342,8 @@ public class Tokens { throw new AssertionError("Cant split - bad subtokens"); } return new Token[] { - new Token(t1, pos, pos + t1.name.length(), deprecatedFlag), - new Token(t2, pos + t1.name.length(), endPos, false) + new Token(t1, pos, pos + t1.name.length(), comments), + new Token(t2, pos + t1.name.length(), endPos, null) }; } @@ -353,14 +364,52 @@ public class Tokens { public int radix() { throw new UnsupportedOperationException(); } + + /** + * Preserve classic semantics - if multiple javadocs are found on the token + * the last one is returned + */ + public String comment(Comment.CommentStyle style) { + List readers = getReaders(Comment.CommentStyle.JAVADOC); + return readers.isEmpty() ? + null : + readers.head.getText(); + } + + /** + * Preserve classic semantics - deprecated should be set if at least one + * javadoc comment attached to this token contains the '@deprecated' string + */ + public boolean deprecatedFlag() { + for (Comment r : getReaders(Comment.CommentStyle.JAVADOC)) { + if (r.isDeprecated()) { + return true; + } + } + return false; + } + + private List getReaders(Comment.CommentStyle style) { + if (comments == null) { + return List.nil(); + } else { + ListBuffer buf = ListBuffer.lb(); + for (Comment r : comments) { + if (r.getStyle() == style) { + buf.add(r); + } + } + return buf.toList(); + } + } } final static class NamedToken extends Token { /** The name of this token */ public final Name name; - public NamedToken(TokenKind kind, int pos, int endPos, Name name, boolean deprecatedFlag) { - super(kind, pos, endPos, deprecatedFlag); + public NamedToken(TokenKind kind, int pos, int endPos, Name name, List comments) { + super(kind, pos, endPos, comments); this.name = name; } @@ -380,8 +429,8 @@ public class Tokens { /** The string value of this token */ public final String stringVal; - public StringToken(TokenKind kind, int pos, int endPos, String stringVal, boolean deprecatedFlag) { - super(kind, pos, endPos, deprecatedFlag); + public StringToken(TokenKind kind, int pos, int endPos, String stringVal, List comments) { + super(kind, pos, endPos, comments); this.stringVal = stringVal; } @@ -401,8 +450,8 @@ public class Tokens { /** The 'radix' value of this token */ public final int radix; - public NumericToken(TokenKind kind, int pos, int endPos, String stringVal, int radix, boolean deprecatedFlag) { - super(kind, pos, endPos, stringVal, deprecatedFlag); + public NumericToken(TokenKind kind, int pos, int endPos, String stringVal, int radix, List comments) { + super(kind, pos, endPos, stringVal, comments); this.radix = radix; } @@ -419,5 +468,5 @@ public class Tokens { } public static final Token DUMMY = - new Token(TokenKind.ERROR, 0, 0, false); + new Token(TokenKind.ERROR, 0, 0, null); } diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/UnicodeReader.java b/langtools/src/share/classes/com/sun/tools/javac/parser/UnicodeReader.java index c5718c6fc47..f1b6d8b12d6 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/parser/UnicodeReader.java +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/UnicodeReader.java @@ -26,8 +26,12 @@ package com.sun.tools.javac.parser; import com.sun.tools.javac.file.JavacFileManager; -import java.nio.CharBuffer; import com.sun.tools.javac.util.Log; +import com.sun.tools.javac.util.Name; +import com.sun.tools.javac.util.Names; + +import java.nio.CharBuffer; + import static com.sun.tools.javac.util.LayoutCharacters.*; /** The char reader used by the javac lexer/tokenizer. Returns the sequence of @@ -58,6 +62,12 @@ public class UnicodeReader { protected int unicodeConversionBp = -1; protected Log log; + protected Names names; + + /** A character buffer for saved chars. + */ + protected char[] sbuf = new char[128]; + protected int sp; /** * Create a scanner from the input array. This method might @@ -76,6 +86,7 @@ public class UnicodeReader { protected UnicodeReader(ScannerFactory sf, char[] input, int inputLength) { log = sf.log; + names = sf.names; if (inputLength == input.length) { if (input.length > 0 && Character.isWhitespace(input[input.length - 1])) { inputLength--; @@ -103,6 +114,48 @@ public class UnicodeReader { } } + /** Read next character in comment, skipping over double '\' characters. + */ + protected void scanCommentChar() { + scanChar(); + if (ch == '\\') { + if (peekChar() == '\\' && !isUnicode()) { + skipChar(); + } else { + convertUnicode(); + } + } + } + + /** Append a character to sbuf. + */ + protected void putChar(char ch, boolean scan) { + if (sp == sbuf.length) { + char[] newsbuf = new char[sbuf.length * 2]; + System.arraycopy(sbuf, 0, newsbuf, 0, sbuf.length); + sbuf = newsbuf; + } + sbuf[sp++] = ch; + if (scan) + scanChar(); + } + + protected void putChar(char ch) { + putChar(ch, false); + } + + protected void putChar(boolean scan) { + putChar(ch, scan); + } + + Name name() { + return names.fromChars(sbuf, 0, sp); + } + + String chars() { + return new String(sbuf, 0, sp); + } + /** Convert unicode escape; bp points to initial '\' character * (Spec 3.3). */ diff --git a/langtools/test/tools/javac/depDocComment/DeprecatedDocComment4.java b/langtools/test/tools/javac/depDocComment/DeprecatedDocComment4.java new file mode 100644 index 00000000000..9e7d93662e3 --- /dev/null +++ b/langtools/test/tools/javac/depDocComment/DeprecatedDocComment4.java @@ -0,0 +1,20 @@ +/** + * @test /nodynamiccopyright/ + * @bug 7104201 + * @summary Refactor DocCommentScanner + * @compile/fail/ref=DeprecatedDocComment4.out -XDrawDiagnostics -Werror -Xlint:dep-ann DeprecatedDocComment4.java + */ + +class DeprecatedDocComment4 { + /** @deprecated **/ + /* block */ + void test1() {}; + + /** @deprecated **/ + /** double javadoc */ + void test2() {}; + + /** @deprecated **/ + //line comment + void test3() {}; +} diff --git a/langtools/test/tools/javac/depDocComment/DeprecatedDocComment4.out b/langtools/test/tools/javac/depDocComment/DeprecatedDocComment4.out new file mode 100644 index 00000000000..88622ac0015 --- /dev/null +++ b/langtools/test/tools/javac/depDocComment/DeprecatedDocComment4.out @@ -0,0 +1,6 @@ +DeprecatedDocComment4.java:11:10: compiler.warn.missing.deprecated.annotation +DeprecatedDocComment4.java:15:10: compiler.warn.missing.deprecated.annotation +DeprecatedDocComment4.java:19:10: compiler.warn.missing.deprecated.annotation +- compiler.err.warnings.and.werror +1 error +3 warnings From 232b9d793fae6a94d612e7577309c88253bab3e8 Mon Sep 17 00:00:00 2001 From: John Coomes Date: Fri, 4 Nov 2011 12:43:41 -0700 Subject: [PATCH 073/107] Added tag hs23-b05 for changeset 38f5bbc6cd8d --- hotspot/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/.hgtags b/hotspot/.hgtags index cbcd9bb10e5..ee81b3c5fa8 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -196,3 +196,4 @@ d815de2e85e511b7deab2a83cf80c0224d011da9 jdk8-b10 4538caeef7b6cbd4302bebced805d65e68ccf301 jdk8-b11 6534482ff68ad79066dfe15dfb6d8905f09681bd hs23-b04 1d3900713a67a0a39faf4e12c9c158d55aebef87 jdk8-b12 +3e609627e780736f372eb14d29bb9b5e53b21fbf hs23-b05 From a346c5d21d0754eb9773be8bcb30b02e640bfe94 Mon Sep 17 00:00:00 2001 From: Pavel Porvatov Date: Mon, 7 Nov 2011 16:50:41 +0400 Subject: [PATCH 074/107] 7080203: JTree.getSelectionPaths() now returns empty array instead of null Reviewed-by: malenkov --- jdk/src/share/classes/javax/swing/JTree.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/jdk/src/share/classes/javax/swing/JTree.java b/jdk/src/share/classes/javax/swing/JTree.java index 13a40562ebe..c5ca4b6dc70 100644 --- a/jdk/src/share/classes/javax/swing/JTree.java +++ b/jdk/src/share/classes/javax/swing/JTree.java @@ -1838,7 +1838,9 @@ public class JTree extends JComponent implements Scrollable, Accessible * nodes, or null if nothing is currently selected */ public TreePath[] getSelectionPaths() { - return getSelectionModel().getSelectionPaths(); + TreePath[] selectionPaths = getSelectionModel().getSelectionPaths(); + + return (selectionPaths != null && selectionPaths.length > 0) ? selectionPaths : null; } /** From b1408532df6b0adfb18ec628eb7c0ee61bf1f9e4 Mon Sep 17 00:00:00 2001 From: Xueming Shen Date: Mon, 7 Nov 2011 13:46:02 -0800 Subject: [PATCH 075/107] 7096080: UTF8 update and new CESU-8 charset 7082884: Incorrect UTF8 conversion for sequence ED 31 7082883: Incorrect UTF8 conversion for sequence fc 80 80 8f bf bf Updated UTF8 and added CESU-8 to following the latest Standard Reviewed-by: alanb --- jdk/make/java/nio/FILES_java.gmk | 1 + jdk/src/share/classes/sun/nio/cs/CESU_8.java | 604 ++++++++++++++++++ jdk/src/share/classes/sun/nio/cs/UTF_8.java | 185 ++++-- .../classes/sun/nio/cs/standard-charsets | 4 + jdk/test/java/nio/charset/coders/Errors.java | 4 +- jdk/test/sun/nio/cs/TestStringCoding.java | 6 +- jdk/test/sun/nio/cs/TestStringCodingUTF8.java | 10 +- jdk/test/sun/nio/cs/TestUTF8.java | 201 ++++-- 8 files changed, 904 insertions(+), 111 deletions(-) create mode 100644 jdk/src/share/classes/sun/nio/cs/CESU_8.java diff --git a/jdk/make/java/nio/FILES_java.gmk b/jdk/make/java/nio/FILES_java.gmk index 41397cacdc0..b394b89e483 100644 --- a/jdk/make/java/nio/FILES_java.gmk +++ b/jdk/make/java/nio/FILES_java.gmk @@ -232,6 +232,7 @@ FILES_src = \ sun/nio/cs/UTF_16BE.java \ sun/nio/cs/UTF_16LE.java \ sun/nio/cs/UTF_8.java \ + sun/nio/cs/CESU_8.java \ sun/nio/cs/Unicode.java \ sun/nio/cs/UnicodeDecoder.java \ sun/nio/cs/UnicodeEncoder.java \ diff --git a/jdk/src/share/classes/sun/nio/cs/CESU_8.java b/jdk/src/share/classes/sun/nio/cs/CESU_8.java new file mode 100644 index 00000000000..40711f83d86 --- /dev/null +++ b/jdk/src/share/classes/sun/nio/cs/CESU_8.java @@ -0,0 +1,604 @@ +/* + * Copyright (c) 2011, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.nio.cs; + +import java.nio.Buffer; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; +import java.nio.charset.CodingErrorAction; + +/* Legal CESU-8 Byte Sequences + * + * # Code Points Bits Bit/Byte pattern + * 1 7 0xxxxxxx + * U+0000..U+007F 00..7F + * + * 2 11 110xxxxx 10xxxxxx + * U+0080..U+07FF C2..DF 80..BF + * + * 3 16 1110xxxx 10xxxxxx 10xxxxxx + * U+0800..U+0FFF E0 A0..BF 80..BF + * U+1000..U+FFFF E1..EF 80..BF 80..BF + * + */ + +class CESU_8 extends Unicode +{ + public CESU_8() { + super("CESU-8", StandardCharsets.aliases_CESU_8); + } + + public String historicalName() { + return "CESU8"; + } + + public CharsetDecoder newDecoder() { + return new Decoder(this); + } + + public CharsetEncoder newEncoder() { + return new Encoder(this); + } + + private static final void updatePositions(Buffer src, int sp, + Buffer dst, int dp) { + src.position(sp - src.arrayOffset()); + dst.position(dp - dst.arrayOffset()); + } + + private static class Decoder extends CharsetDecoder + implements ArrayDecoder { + private Decoder(Charset cs) { + super(cs, 1.0f, 1.0f); + } + + private static boolean isNotContinuation(int b) { + return (b & 0xc0) != 0x80; + } + + // [E0] [A0..BF] [80..BF] + // [E1..EF] [80..BF] [80..BF] + private static boolean isMalformed3(int b1, int b2, int b3) { + return (b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) || + (b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80; + } + + // only used when there is only one byte left in src buffer + private static boolean isMalformed3_2(int b1, int b2) { + return (b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) || + (b2 & 0xc0) != 0x80; + } + + + // [F0] [90..BF] [80..BF] [80..BF] + // [F1..F3] [80..BF] [80..BF] [80..BF] + // [F4] [80..8F] [80..BF] [80..BF] + // only check 80-be range here, the [0xf0,0x80...] and [0xf4,0x90-...] + // will be checked by Character.isSupplementaryCodePoint(uc) + private static boolean isMalformed4(int b2, int b3, int b4) { + return (b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80 || + (b4 & 0xc0) != 0x80; + } + + // only used when there is less than 4 bytes left in src buffer + private static boolean isMalformed4_2(int b1, int b2) { + return (b1 == 0xf0 && b2 == 0x90) || + (b2 & 0xc0) != 0x80; + } + + private static boolean isMalformed4_3(int b3) { + return (b3 & 0xc0) != 0x80; + } + + private static CoderResult malformedN(ByteBuffer src, int nb) { + switch (nb) { + case 1: + case 2: // always 1 + return CoderResult.malformedForLength(1); + case 3: + int b1 = src.get(); + int b2 = src.get(); // no need to lookup b3 + return CoderResult.malformedForLength( + ((b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) || + isNotContinuation(b2)) ? 1 : 2); + case 4: // we don't care the speed here + b1 = src.get() & 0xff; + b2 = src.get() & 0xff; + if (b1 > 0xf4 || + (b1 == 0xf0 && (b2 < 0x90 || b2 > 0xbf)) || + (b1 == 0xf4 && (b2 & 0xf0) != 0x80) || + isNotContinuation(b2)) + return CoderResult.malformedForLength(1); + if (isNotContinuation(src.get())) + return CoderResult.malformedForLength(2); + return CoderResult.malformedForLength(3); + default: + assert false; + return null; + } + } + + private static CoderResult malformed(ByteBuffer src, int sp, + CharBuffer dst, int dp, + int nb) + { + src.position(sp - src.arrayOffset()); + CoderResult cr = malformedN(src, nb); + updatePositions(src, sp, dst, dp); + return cr; + } + + + private static CoderResult malformed(ByteBuffer src, + int mark, int nb) + { + src.position(mark); + CoderResult cr = malformedN(src, nb); + src.position(mark); + return cr; + } + + private static CoderResult malformedForLength(ByteBuffer src, + int sp, + CharBuffer dst, + int dp, + int malformedNB) + { + updatePositions(src, sp, dst, dp); + return CoderResult.malformedForLength(malformedNB); + } + + private static CoderResult malformedForLength(ByteBuffer src, + int mark, + int malformedNB) + { + src.position(mark); + return CoderResult.malformedForLength(malformedNB); + } + + + private static CoderResult xflow(Buffer src, int sp, int sl, + Buffer dst, int dp, int nb) { + updatePositions(src, sp, dst, dp); + return (nb == 0 || sl - sp < nb) + ? CoderResult.UNDERFLOW : CoderResult.OVERFLOW; + } + + private static CoderResult xflow(Buffer src, int mark, int nb) { + src.position(mark); + return (nb == 0 || src.remaining() < nb) + ? CoderResult.UNDERFLOW : CoderResult.OVERFLOW; + } + + private CoderResult decodeArrayLoop(ByteBuffer src, + CharBuffer dst) + { + // This method is optimized for ASCII input. + byte[] sa = src.array(); + int sp = src.arrayOffset() + src.position(); + int sl = src.arrayOffset() + src.limit(); + + char[] da = dst.array(); + int dp = dst.arrayOffset() + dst.position(); + int dl = dst.arrayOffset() + dst.limit(); + int dlASCII = dp + Math.min(sl - sp, dl - dp); + + // ASCII only loop + while (dp < dlASCII && sa[sp] >= 0) + da[dp++] = (char) sa[sp++]; + while (sp < sl) { + int b1 = sa[sp]; + if (b1 >= 0) { + // 1 byte, 7 bits: 0xxxxxxx + if (dp >= dl) + return xflow(src, sp, sl, dst, dp, 1); + da[dp++] = (char) b1; + sp++; + } else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) { + // 2 bytes, 11 bits: 110xxxxx 10xxxxxx + if (sl - sp < 2 || dp >= dl) + return xflow(src, sp, sl, dst, dp, 2); + int b2 = sa[sp + 1]; + if (isNotContinuation(b2)) + return malformedForLength(src, sp, dst, dp, 1); + da[dp++] = (char) (((b1 << 6) ^ b2) + ^ + (((byte) 0xC0 << 6) ^ + ((byte) 0x80 << 0))); + sp += 2; + } else if ((b1 >> 4) == -2) { + // 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx + int srcRemaining = sl - sp; + if (srcRemaining < 3 || dp >= dl) { + if (srcRemaining > 1 && isMalformed3_2(b1, sa[sp + 1])) + return malformedForLength(src, sp, dst, dp, 1); + return xflow(src, sp, sl, dst, dp, 3); + } + int b2 = sa[sp + 1]; + int b3 = sa[sp + 2]; + if (isMalformed3(b1, b2, b3)) + return malformed(src, sp, dst, dp, 3); + da[dp++] = (char) + ((b1 << 12) ^ + (b2 << 6) ^ + (b3 ^ + (((byte) 0xE0 << 12) ^ + ((byte) 0x80 << 6) ^ + ((byte) 0x80 << 0)))); + sp += 3; + } else { + return malformed(src, sp, dst, dp, 1); + } + } + return xflow(src, sp, sl, dst, dp, 0); + } + + private CoderResult decodeBufferLoop(ByteBuffer src, + CharBuffer dst) + { + int mark = src.position(); + int limit = src.limit(); + while (mark < limit) { + int b1 = src.get(); + if (b1 >= 0) { + // 1 byte, 7 bits: 0xxxxxxx + if (dst.remaining() < 1) + return xflow(src, mark, 1); // overflow + dst.put((char) b1); + mark++; + } else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) { + // 2 bytes, 11 bits: 110xxxxx 10xxxxxx + if (limit - mark < 2|| dst.remaining() < 1) + return xflow(src, mark, 2); + int b2 = src.get(); + if (isNotContinuation(b2)) + return malformedForLength(src, mark, 1); + dst.put((char) (((b1 << 6) ^ b2) + ^ + (((byte) 0xC0 << 6) ^ + ((byte) 0x80 << 0)))); + mark += 2; + } else if ((b1 >> 4) == -2) { + // 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx + int srcRemaining = limit - mark; + if (srcRemaining < 3 || dst.remaining() < 1) { + if (srcRemaining > 1 && isMalformed3_2(b1, src.get())) + return malformedForLength(src, mark, 1); + return xflow(src, mark, 3); + } + int b2 = src.get(); + int b3 = src.get(); + if (isMalformed3(b1, b2, b3)) + return malformed(src, mark, 3); + dst.put((char) + ((b1 << 12) ^ + (b2 << 6) ^ + (b3 ^ + (((byte) 0xE0 << 12) ^ + ((byte) 0x80 << 6) ^ + ((byte) 0x80 << 0))))); + mark += 3; + } else { + return malformed(src, mark, 1); + } + } + return xflow(src, mark, 0); + } + + protected CoderResult decodeLoop(ByteBuffer src, + CharBuffer dst) + { + if (src.hasArray() && dst.hasArray()) + return decodeArrayLoop(src, dst); + else + return decodeBufferLoop(src, dst); + } + + private static ByteBuffer getByteBuffer(ByteBuffer bb, byte[] ba, int sp) + { + if (bb == null) + bb = ByteBuffer.wrap(ba); + bb.position(sp); + return bb; + } + + // returns -1 if there is/are malformed byte(s) and the + // "action" for malformed input is not REPLACE. + public int decode(byte[] sa, int sp, int len, char[] da) { + final int sl = sp + len; + int dp = 0; + int dlASCII = Math.min(len, da.length); + ByteBuffer bb = null; // only necessary if malformed + + // ASCII only optimized loop + while (dp < dlASCII && sa[sp] >= 0) + da[dp++] = (char) sa[sp++]; + + while (sp < sl) { + int b1 = sa[sp++]; + if (b1 >= 0) { + // 1 byte, 7 bits: 0xxxxxxx + da[dp++] = (char) b1; + } else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) { + // 2 bytes, 11 bits: 110xxxxx 10xxxxxx + if (sp < sl) { + int b2 = sa[sp++]; + if (isNotContinuation(b2)) { + if (malformedInputAction() != CodingErrorAction.REPLACE) + return -1; + da[dp++] = replacement().charAt(0); + sp--; // malformedN(bb, 2) always returns 1 + } else { + da[dp++] = (char) (((b1 << 6) ^ b2)^ + (((byte) 0xC0 << 6) ^ + ((byte) 0x80 << 0))); + } + continue; + } + if (malformedInputAction() != CodingErrorAction.REPLACE) + return -1; + da[dp++] = replacement().charAt(0); + return dp; + } else if ((b1 >> 4) == -2) { + // 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx + if (sp + 1 < sl) { + int b2 = sa[sp++]; + int b3 = sa[sp++]; + if (isMalformed3(b1, b2, b3)) { + if (malformedInputAction() != CodingErrorAction.REPLACE) + return -1; + da[dp++] = replacement().charAt(0); + sp -=3; + bb = getByteBuffer(bb, sa, sp); + sp += malformedN(bb, 3).length(); + } else { + da[dp++] = (char)((b1 << 12) ^ + (b2 << 6) ^ + (b3 ^ + (((byte) 0xE0 << 12) ^ + ((byte) 0x80 << 6) ^ + ((byte) 0x80 << 0)))); + } + continue; + } + if (malformedInputAction() != CodingErrorAction.REPLACE) + return -1; + if (sp < sl && isMalformed3_2(b1, sa[sp])) { + da[dp++] = replacement().charAt(0); + continue; + + } + da[dp++] = replacement().charAt(0); + return dp; + } else { + if (malformedInputAction() != CodingErrorAction.REPLACE) + return -1; + da[dp++] = replacement().charAt(0); + } + } + return dp; + } + } + + private static class Encoder extends CharsetEncoder + implements ArrayEncoder { + + private Encoder(Charset cs) { + super(cs, 1.1f, 3.0f); + } + + public boolean canEncode(char c) { + return !Character.isSurrogate(c); + } + + public boolean isLegalReplacement(byte[] repl) { + return ((repl.length == 1 && repl[0] >= 0) || + super.isLegalReplacement(repl)); + } + + private static CoderResult overflow(CharBuffer src, int sp, + ByteBuffer dst, int dp) { + updatePositions(src, sp, dst, dp); + return CoderResult.OVERFLOW; + } + + private static CoderResult overflow(CharBuffer src, int mark) { + src.position(mark); + return CoderResult.OVERFLOW; + } + + private static void to3Bytes(byte[] da, int dp, char c) { + da[dp] = (byte)(0xe0 | ((c >> 12))); + da[dp + 1] = (byte)(0x80 | ((c >> 6) & 0x3f)); + da[dp + 2] = (byte)(0x80 | (c & 0x3f)); + } + + private static void to3Bytes(ByteBuffer dst, char c) { + dst.put((byte)(0xe0 | ((c >> 12)))); + dst.put((byte)(0x80 | ((c >> 6) & 0x3f))); + dst.put((byte)(0x80 | (c & 0x3f))); + } + + private Surrogate.Parser sgp; + private char[] c2; + private CoderResult encodeArrayLoop(CharBuffer src, + ByteBuffer dst) + { + char[] sa = src.array(); + int sp = src.arrayOffset() + src.position(); + int sl = src.arrayOffset() + src.limit(); + + byte[] da = dst.array(); + int dp = dst.arrayOffset() + dst.position(); + int dl = dst.arrayOffset() + dst.limit(); + int dlASCII = dp + Math.min(sl - sp, dl - dp); + + // ASCII only loop + while (dp < dlASCII && sa[sp] < '\u0080') + da[dp++] = (byte) sa[sp++]; + while (sp < sl) { + char c = sa[sp]; + if (c < 0x80) { + // Have at most seven bits + if (dp >= dl) + return overflow(src, sp, dst, dp); + da[dp++] = (byte)c; + } else if (c < 0x800) { + // 2 bytes, 11 bits + if (dl - dp < 2) + return overflow(src, sp, dst, dp); + da[dp++] = (byte)(0xc0 | (c >> 6)); + da[dp++] = (byte)(0x80 | (c & 0x3f)); + } else if (Character.isSurrogate(c)) { + // Have a surrogate pair + if (sgp == null) + sgp = new Surrogate.Parser(); + int uc = sgp.parse(c, sa, sp, sl); + if (uc < 0) { + updatePositions(src, sp, dst, dp); + return sgp.error(); + } + if (dl - dp < 6) + return overflow(src, sp, dst, dp); + to3Bytes(da, dp, Character.highSurrogate(uc)); + dp += 3; + to3Bytes(da, dp, Character.lowSurrogate(uc)); + dp += 3; + sp++; // 2 chars + } else { + // 3 bytes, 16 bits + if (dl - dp < 3) + return overflow(src, sp, dst, dp); + to3Bytes(da, dp, c); + dp += 3; + } + sp++; + } + updatePositions(src, sp, dst, dp); + return CoderResult.UNDERFLOW; + } + + private CoderResult encodeBufferLoop(CharBuffer src, + ByteBuffer dst) + { + int mark = src.position(); + while (src.hasRemaining()) { + char c = src.get(); + if (c < 0x80) { + // Have at most seven bits + if (!dst.hasRemaining()) + return overflow(src, mark); + dst.put((byte)c); + } else if (c < 0x800) { + // 2 bytes, 11 bits + if (dst.remaining() < 2) + return overflow(src, mark); + dst.put((byte)(0xc0 | (c >> 6))); + dst.put((byte)(0x80 | (c & 0x3f))); + } else if (Character.isSurrogate(c)) { + // Have a surrogate pair + if (sgp == null) + sgp = new Surrogate.Parser(); + int uc = sgp.parse(c, src); + if (uc < 0) { + src.position(mark); + return sgp.error(); + } + if (dst.remaining() < 6) + return overflow(src, mark); + to3Bytes(dst, Character.highSurrogate(uc)); + to3Bytes(dst, Character.lowSurrogate(uc)); + mark++; // 2 chars + } else { + // 3 bytes, 16 bits + if (dst.remaining() < 3) + return overflow(src, mark); + to3Bytes(dst, c); + } + mark++; + } + src.position(mark); + return CoderResult.UNDERFLOW; + } + + protected final CoderResult encodeLoop(CharBuffer src, + ByteBuffer dst) + { + if (src.hasArray() && dst.hasArray()) + return encodeArrayLoop(src, dst); + else + return encodeBufferLoop(src, dst); + } + + // returns -1 if there is malformed char(s) and the + // "action" for malformed input is not REPLACE. + public int encode(char[] sa, int sp, int len, byte[] da) { + int sl = sp + len; + int dp = 0; + int dlASCII = dp + Math.min(len, da.length); + + // ASCII only optimized loop + while (dp < dlASCII && sa[sp] < '\u0080') + da[dp++] = (byte) sa[sp++]; + + while (sp < sl) { + char c = sa[sp++]; + if (c < 0x80) { + // Have at most seven bits + da[dp++] = (byte)c; + } else if (c < 0x800) { + // 2 bytes, 11 bits + da[dp++] = (byte)(0xc0 | (c >> 6)); + da[dp++] = (byte)(0x80 | (c & 0x3f)); + } else if (Character.isSurrogate(c)) { + if (sgp == null) + sgp = new Surrogate.Parser(); + int uc = sgp.parse(c, sa, sp - 1, sl); + if (uc < 0) { + if (malformedInputAction() != CodingErrorAction.REPLACE) + return -1; + da[dp++] = replacement()[0]; + } else { + to3Bytes(da, dp, Character.highSurrogate(uc)); + dp += 3; + to3Bytes(da, dp, Character.lowSurrogate(uc)); + dp += 3; + sp++; // 2 chars + } + } else { + // 3 bytes, 16 bits + to3Bytes(da, dp, c); + dp += 3; + } + } + return dp; + } + } +} diff --git a/jdk/src/share/classes/sun/nio/cs/UTF_8.java b/jdk/src/share/classes/sun/nio/cs/UTF_8.java index 56d6bcc7b6d..1f7edaad2d8 100644 --- a/jdk/src/share/classes/sun/nio/cs/UTF_8.java +++ b/jdk/src/share/classes/sun/nio/cs/UTF_8.java @@ -72,8 +72,8 @@ class UTF_8 extends Unicode return new Encoder(this); } - static final void updatePositions(Buffer src, int sp, - Buffer dst, int dp) { + private static final void updatePositions(Buffer src, int sp, + Buffer dst, int dp) { src.position(sp - src.arrayOffset()); dst.position(dp - dst.arrayOffset()); } @@ -88,11 +88,6 @@ class UTF_8 extends Unicode return (b & 0xc0) != 0x80; } - // [C2..DF] [80..BF] - private static boolean isMalformed2(int b1, int b2) { - return (b1 & 0x1e) == 0x0 || (b2 & 0xc0) != 0x80; - } - // [E0] [A0..BF] [80..BF] // [E1..EF] [80..BF] [80..BF] private static boolean isMalformed3(int b1, int b2, int b3) { @@ -100,6 +95,12 @@ class UTF_8 extends Unicode (b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80; } + // only used when there is only one byte left in src buffer + private static boolean isMalformed3_2(int b1, int b2) { + return (b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) || + (b2 & 0xc0) != 0x80; + } + // [F0] [90..BF] [80..BF] [80..BF] // [F1..F3] [80..BF] [80..BF] [80..BF] // [F4] [80..8F] [80..BF] [80..BF] @@ -110,6 +111,16 @@ class UTF_8 extends Unicode (b4 & 0xc0) != 0x80; } + // only used when there is less than 4 bytes left in src buffer + private static boolean isMalformed4_2(int b1, int b2) { + return (b1 == 0xf0 && b2 == 0x90) || + (b2 & 0xc0) != 0x80; + } + + private static boolean isMalformed4_3(int b3) { + return (b3 & 0xc0) != 0x80; + } + private static CoderResult lookupN(ByteBuffer src, int n) { for (int i = 1; i < n; i++) { @@ -122,28 +133,14 @@ class UTF_8 extends Unicode private static CoderResult malformedN(ByteBuffer src, int nb) { switch (nb) { case 1: - int b1 = src.get(); - if ((b1 >> 2) == -2) { - // 5 bytes 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - if (src.remaining() < 4) - return CoderResult.UNDERFLOW; - return lookupN(src, 5); - } - if ((b1 >> 1) == -2) { - // 6 bytes 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - if (src.remaining() < 5) - return CoderResult.UNDERFLOW; - return lookupN(src, 6); - } - return CoderResult.malformedForLength(1); case 2: // always 1 return CoderResult.malformedForLength(1); case 3: - b1 = src.get(); + int b1 = src.get(); int b2 = src.get(); // no need to lookup b3 return CoderResult.malformedForLength( ((b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) || - isNotContinuation(b2))?1:2); + isNotContinuation(b2)) ? 1 : 2); case 4: // we don't care the speed here b1 = src.get() & 0xff; b2 = src.get() & 0xff; @@ -171,6 +168,7 @@ class UTF_8 extends Unicode return cr; } + private static CoderResult malformed(ByteBuffer src, int mark, int nb) { @@ -180,18 +178,36 @@ class UTF_8 extends Unicode return cr; } + private static CoderResult malformedForLength(ByteBuffer src, + int sp, + CharBuffer dst, + int dp, + int malformedNB) + { + updatePositions(src, sp, dst, dp); + return CoderResult.malformedForLength(malformedNB); + } + + private static CoderResult malformedForLength(ByteBuffer src, + int mark, + int malformedNB) + { + src.position(mark); + return CoderResult.malformedForLength(malformedNB); + } + + private static CoderResult xflow(Buffer src, int sp, int sl, Buffer dst, int dp, int nb) { updatePositions(src, sp, dst, dp); return (nb == 0 || sl - sp < nb) - ?CoderResult.UNDERFLOW:CoderResult.OVERFLOW; + ? CoderResult.UNDERFLOW : CoderResult.OVERFLOW; } private static CoderResult xflow(Buffer src, int mark, int nb) { - CoderResult cr = (nb == 0 || src.remaining() < (nb - 1)) - ?CoderResult.UNDERFLOW:CoderResult.OVERFLOW; src.position(mark); - return cr; + return (nb == 0 || src.remaining() < nb) + ? CoderResult.UNDERFLOW : CoderResult.OVERFLOW; } private CoderResult decodeArrayLoop(ByteBuffer src, @@ -210,7 +226,6 @@ class UTF_8 extends Unicode // ASCII only loop while (dp < dlASCII && sa[sp] >= 0) da[dp++] = (char) sa[sp++]; - while (sp < sl) { int b1 = sa[sp]; if (b1 >= 0) { @@ -219,13 +234,20 @@ class UTF_8 extends Unicode return xflow(src, sp, sl, dst, dp, 1); da[dp++] = (char) b1; sp++; - } else if ((b1 >> 5) == -2) { + } else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) { // 2 bytes, 11 bits: 110xxxxx 10xxxxxx + // [C2..DF] [80..BF] if (sl - sp < 2 || dp >= dl) return xflow(src, sp, sl, dst, dp, 2); int b2 = sa[sp + 1]; - if (isMalformed2(b1, b2)) - return malformed(src, sp, dst, dp, 2); + // Now we check the first byte of 2-byte sequence as + // if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) + // no longer need to check b1 against c1 & c0 for + // malformed as we did in previous version + // (b1 & 0x1e) == 0x0 || (b2 & 0xc0) != 0x80; + // only need to check the second byte b2. + if (isNotContinuation(b2)) + return malformedForLength(src, sp, dst, dp, 1); da[dp++] = (char) (((b1 << 6) ^ b2) ^ (((byte) 0xC0 << 6) ^ @@ -233,24 +255,37 @@ class UTF_8 extends Unicode sp += 2; } else if ((b1 >> 4) == -2) { // 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx - if (sl - sp < 3 || dp >= dl) + int srcRemaining = sl - sp; + if (srcRemaining < 3 || dp >= dl) { + if (srcRemaining > 1 && isMalformed3_2(b1, sa[sp + 1])) + return malformedForLength(src, sp, dst, dp, 1); return xflow(src, sp, sl, dst, dp, 3); + } int b2 = sa[sp + 1]; int b3 = sa[sp + 2]; if (isMalformed3(b1, b2, b3)) return malformed(src, sp, dst, dp, 3); - da[dp++] = (char) + char c = (char) ((b1 << 12) ^ (b2 << 6) ^ (b3 ^ (((byte) 0xE0 << 12) ^ ((byte) 0x80 << 6) ^ ((byte) 0x80 << 0)))); + if (Character.isSurrogate(c)) + return malformedForLength(src, sp, dst, dp, 3); + da[dp++] = c; sp += 3; } else if ((b1 >> 3) == -2) { // 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - if (sl - sp < 4 || dl - dp < 2) + int srcRemaining = sl - sp; + if (srcRemaining < 4 || dl - dp < 2) { + if (srcRemaining > 1 && isMalformed4_2(b1, sa[sp + 1])) + return malformedForLength(src, sp, dst, dp, 1); + if (srcRemaining > 2 && isMalformed4_3(sa[sp + 2])) + return malformedForLength(src, sp, dst, dp, 2); return xflow(src, sp, sl, dst, dp, 4); + } int b2 = sa[sp + 1]; int b3 = sa[sp + 2]; int b4 = sa[sp + 3]; @@ -289,38 +324,51 @@ class UTF_8 extends Unicode return xflow(src, mark, 1); // overflow dst.put((char) b1); mark++; - } else if ((b1 >> 5) == -2) { + } else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) { // 2 bytes, 11 bits: 110xxxxx 10xxxxxx if (limit - mark < 2|| dst.remaining() < 1) return xflow(src, mark, 2); int b2 = src.get(); - if (isMalformed2(b1, b2)) - return malformed(src, mark, 2); - dst.put((char) (((b1 << 6) ^ b2) + if (isNotContinuation(b2)) + return malformedForLength(src, mark, 1); + dst.put((char) (((b1 << 6) ^ b2) ^ (((byte) 0xC0 << 6) ^ ((byte) 0x80 << 0)))); mark += 2; } else if ((b1 >> 4) == -2) { // 3 bytes, 16 bits: 1110xxxx 10xxxxxx 10xxxxxx - if (limit - mark < 3 || dst.remaining() < 1) + int srcRemaining = limit - mark; + if (srcRemaining < 3 || dst.remaining() < 1) { + if (srcRemaining > 1 && isMalformed3_2(b1, src.get())) + return malformedForLength(src, mark, 1); return xflow(src, mark, 3); + } int b2 = src.get(); int b3 = src.get(); if (isMalformed3(b1, b2, b3)) return malformed(src, mark, 3); - dst.put((char) - ((b1 << 12) ^ - (b2 << 6) ^ - (b3 ^ - (((byte) 0xE0 << 12) ^ - ((byte) 0x80 << 6) ^ - ((byte) 0x80 << 0))))); + char c = (char) + ((b1 << 12) ^ + (b2 << 6) ^ + (b3 ^ + (((byte) 0xE0 << 12) ^ + ((byte) 0x80 << 6) ^ + ((byte) 0x80 << 0)))); + if (Character.isSurrogate(c)) + return malformedForLength(src, mark, 3); + dst.put(c); mark += 3; } else if ((b1 >> 3) == -2) { // 4 bytes, 21 bits: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - if (limit - mark < 4 || dst.remaining() < 2) + int srcRemaining = limit - mark; + if (srcRemaining < 4 || dst.remaining() < 2) { + if (srcRemaining > 1 && isMalformed4_2(b1, src.get())) + return malformedForLength(src, mark, 1); + if (srcRemaining > 2 && isMalformed4_3(src.get())) + return malformedForLength(src, mark, 2); return xflow(src, mark, 4); + } int b2 = src.get(); int b3 = src.get(); int b4 = src.get(); @@ -364,7 +412,7 @@ class UTF_8 extends Unicode return bb; } - // returns -1 if there is malformed byte(s) and the + // returns -1 if there is/are malformed byte(s) and the // "action" for malformed input is not REPLACE. public int decode(byte[] sa, int sp, int len, char[] da) { final int sl = sp + len; @@ -381,11 +429,11 @@ class UTF_8 extends Unicode if (b1 >= 0) { // 1 byte, 7 bits: 0xxxxxxx da[dp++] = (char) b1; - } else if ((b1 >> 5) == -2) { + } else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) { // 2 bytes, 11 bits: 110xxxxx 10xxxxxx if (sp < sl) { int b2 = sa[sp++]; - if (isMalformed2(b1, b2)) { + if (isNotContinuation(b2)) { if (malformedInputAction() != CodingErrorAction.REPLACE) return -1; da[dp++] = replacement().charAt(0); @@ -410,21 +458,33 @@ class UTF_8 extends Unicode if (malformedInputAction() != CodingErrorAction.REPLACE) return -1; da[dp++] = replacement().charAt(0); - sp -=3; + sp -= 3; bb = getByteBuffer(bb, sa, sp); sp += malformedN(bb, 3).length(); } else { - da[dp++] = (char)((b1 << 12) ^ + char c = (char)((b1 << 12) ^ (b2 << 6) ^ (b3 ^ (((byte) 0xE0 << 12) ^ ((byte) 0x80 << 6) ^ ((byte) 0x80 << 0)))); + if (Character.isSurrogate(c)) { + if (malformedInputAction() != CodingErrorAction.REPLACE) + return -1; + da[dp++] = replacement().charAt(0); + } else { + da[dp++] = c; + } } continue; } if (malformedInputAction() != CodingErrorAction.REPLACE) return -1; + if (sp < sl && isMalformed3_2(b1, sa[sp])) { + da[dp++] = replacement().charAt(0); + continue; + + } da[dp++] = replacement().charAt(0); return dp; } else if ((b1 >> 3) == -2) { @@ -458,28 +518,29 @@ class UTF_8 extends Unicode } if (malformedInputAction() != CodingErrorAction.REPLACE) return -1; + + if (sp < sl && isMalformed4_2(b1, sa[sp])) { + da[dp++] = replacement().charAt(0); + continue; + } + sp++; + if (sp < sl && isMalformed4_3(sa[sp])) { + da[dp++] = replacement().charAt(0); + continue; + } da[dp++] = replacement().charAt(0); return dp; } else { if (malformedInputAction() != CodingErrorAction.REPLACE) return -1; da[dp++] = replacement().charAt(0); - sp--; - bb = getByteBuffer(bb, sa, sp); - CoderResult cr = malformedN(bb, 1); - if (!cr.isError()) { - // leading byte for 5 or 6-byte, but don't have enough - // bytes in buffer to check. Consumed rest as malformed. - return dp; - } - sp += cr.length(); } } return dp; } } - private static class Encoder extends CharsetEncoder + private static final class Encoder extends CharsetEncoder implements ArrayEncoder { private Encoder(Charset cs) { diff --git a/jdk/src/share/classes/sun/nio/cs/standard-charsets b/jdk/src/share/classes/sun/nio/cs/standard-charsets index 06120fee8f3..245713500a6 100644 --- a/jdk/src/share/classes/sun/nio/cs/standard-charsets +++ b/jdk/src/share/classes/sun/nio/cs/standard-charsets @@ -63,6 +63,10 @@ charset UTF-8 UTF_8 alias UTF8 # JDK historical alias unicode-1-1-utf-8 +charset CESU-8 CESU_8 + alias CESU8 + alias csCESU-8 + charset UTF-16 UTF_16 alias UTF_16 # JDK historical alias utf16 diff --git a/jdk/test/java/nio/charset/coders/Errors.java b/jdk/test/java/nio/charset/coders/Errors.java index be19c0b403d..0b74001dd6e 100644 --- a/jdk/test/java/nio/charset/coders/Errors.java +++ b/jdk/test/java/nio/charset/coders/Errors.java @@ -23,7 +23,7 @@ /* @test * @summary Check that error cases are replaced correctly in String/ISR/OSW - * @bug 4457851 + * @bug 4457851 7096080 * * @build Errors Util * @run main Errors @@ -193,11 +193,9 @@ public class Errors { t.test("\uFFFF", new byte[] { (byte)0xEF, (byte)0xBF, (byte)0xBF }); t.test(new byte[] { X, (byte)0x7f, Y }, "x\u007Fy"); t.test(new byte[] { X, (byte)0x80, Y }, "x\uFFFDy"); - t.test(new byte[] { (byte)0xf0, (byte)0xf0 }, "\uFFFD"); } public static void main(String[] args) throws Exception { - test_US_ASCII(new TestString("US-ASCII")); test_US_ASCII(new TestStream("US-ASCII")); diff --git a/jdk/test/sun/nio/cs/TestStringCoding.java b/jdk/test/sun/nio/cs/TestStringCoding.java index c4837e956ae..09e61444889 100644 --- a/jdk/test/sun/nio/cs/TestStringCoding.java +++ b/jdk/test/sun/nio/cs/TestStringCoding.java @@ -24,7 +24,7 @@ */ /* @test - @bug 6636323 6636319 7040220 + @bug 6636323 6636319 7040220 7096080 @summary Test if StringCoding and NIO result have the same de/encoding result * @run main/othervm/timeout=2000 TestStringCoding */ @@ -111,7 +111,8 @@ public class TestStringCoding { //encode unmappable surrogates if (enc instanceof sun.nio.cs.ArrayEncoder && cs.contains(Charset.forName("ASCII"))) { - if (cs.name().equals("UTF-8")) // utf8 handles surrogates + if (cs.name().equals("UTF-8") || // utf8 handles surrogates + cs.name().equals("CESU-8")) // utf8 handles surrogates return; enc.replaceWith(new byte[] { (byte)'A'}); sun.nio.cs.ArrayEncoder cae = (sun.nio.cs.ArrayEncoder)enc; @@ -136,7 +137,6 @@ public class TestStringCoding { cs.name()))) throw new RuntimeException("encode3(surrogates) failed -> " + cs.name()); - ba = new byte[str.length() - 1]; n = cae.encode(str.toCharArray(), 0, str.length(), ba); if (n != 7 || !"abABABc".equals(new String(ba, 0, n, diff --git a/jdk/test/sun/nio/cs/TestStringCodingUTF8.java b/jdk/test/sun/nio/cs/TestStringCodingUTF8.java index fdc204849b7..d1f69950684 100644 --- a/jdk/test/sun/nio/cs/TestStringCodingUTF8.java +++ b/jdk/test/sun/nio/cs/TestStringCodingUTF8.java @@ -33,14 +33,16 @@ import java.nio.charset.*; public class TestStringCodingUTF8 { public static void main(String[] args) throws Throwable { - test(); + test("UTF-8"); + test("CESU-8"); // security manager on System.setSecurityManager(new PermissiveSecurityManger()); - test(); + test("UTF-8"); + test("CESU-8"); } - static void test() throws Throwable { - Charset cs = Charset.forName("UTF-8"); + static void test(String csn) throws Throwable { + Charset cs = Charset.forName(csn); char[] bmp = new char[0x10000]; for (int i = 0; i < 0x10000; i++) { bmp[i] = (char)i; diff --git a/jdk/test/sun/nio/cs/TestUTF8.java b/jdk/test/sun/nio/cs/TestUTF8.java index f339eae046b..e83f8fbb51a 100644 --- a/jdk/test/sun/nio/cs/TestUTF8.java +++ b/jdk/test/sun/nio/cs/TestUTF8.java @@ -23,7 +23,7 @@ /* * @test - * @bug 4486841 7040220 + * @bug 4486841 7040220 7096080 * @summary Test UTF-8 charset */ @@ -156,15 +156,22 @@ public class TestUTF8 { return 3; } + static int to4ByteUTF8(int uc, byte[] bb, int pos) { + bb[pos++] = (byte)(0xf0 | ((uc >> 18))); + bb[pos++] = (byte)(0x80 | ((uc >> 12) & 0x3f)); + bb[pos++] = (byte)(0x80 | ((uc >> 6) & 0x3f)); + bb[pos++] = (byte)(0x80 | (uc & 0x3f)); + return 4; + } + static void checkRoundtrip(String csn) throws Exception { System.out.printf(" Check roundtrip <%s>...", csn); char[] cc = getUTFChars(); byte[] bb = encode(cc, csn, false); char[] ccO = decode(bb, csn, false); - if (!Arrays.equals(cc, ccO)) { + if (!Arrays.equals(cc, ccO)) System.out.printf(" non-direct failed"); - } bb = encode(cc, csn, true); ccO = decode(bb, csn, true); if (!Arrays.equals(cc, ccO)) { @@ -180,6 +187,40 @@ public class TestUTF8 { System.out.println(); } + static void check4ByteSurrs(String csn) throws Exception { + System.out.printf(" Check 4-byte Surrogates <%s>...%n", csn); + byte[] bb = new byte[(0x110000 - 0x10000) * 4]; + char[] cc = new char[(0x110000 - 0x10000) * 2]; + int bpos = 0; + int cpos = 0; + for (int i = 0x10000; i < 0x110000; i++) { + Character.toChars(i, cc, cpos); + bpos += to4ByteUTF8(i, bb, bpos); + cpos += 2; + } + checkSurrs(csn, bb, cc); + } + + + static void checkSurrs(String csn, byte[] bb, char[] cc) + throws Exception + { + char[] ccO = decode(bb, csn, false); + if (!Arrays.equals(cc, ccO)) { + System.out.printf(" decoding failed%n"); + } + ccO = decode(bb, csn, true); + if (!Arrays.equals(cc, ccO)) { + System.out.printf(" decoding(direct) failed%n"); + } + if (!Arrays.equals(cc, new String(bb, csn).toCharArray())) { + System.out.printf(" String.toCharArray() failed"); + } + if (!Arrays.equals(bb, new String(cc).getBytes(csn))) { + System.out.printf(" String.getBytes() failed"); + } + } + static void check6ByteSurrs(String csn) throws Exception { System.out.printf(" Check 6-byte Surrogates <%s>...%n", csn); byte[] bb = new byte[(0x110000 - 0x10000) * 6]; @@ -192,23 +233,10 @@ public class TestUTF8 { bpos += to3ByteUTF8(cc[cpos + 1], bb, bpos); cpos += 2; } - - char[] ccO = decode(bb, csn, false); - if (!Arrays.equals(cc, ccO)) { - System.out.printf(" decoding failed%n"); - } - ccO = decode(bb, csn, true); - if (!Arrays.equals(cc, ccO)) { - System.out.printf(" decoding(direct) failed%n"); - } - // new String(bb, csn).getBytes(csn) will not return - // the 6 bytes surrogates as in bb, so only test - // toCharArray() here. - if (!Arrays.equals(cc, new String(bb, csn).toCharArray())) { - System.out.printf(" String.toCharArray() failed"); - } + checkSurrs(csn, bb, cc); } + static void compare(String csn1, String csn2) throws Exception { System.out.printf(" Diff <%s> <%s>...%n", csn1, csn2); char[] cc = getUTFChars(); @@ -266,6 +294,10 @@ public class TestUTF8 { {1, (byte)0xFF, (byte)0xFF, (byte)0xFF }, // all ones {1, (byte)0xE0, (byte)0xC0, (byte)0x80 }, // invalid second byte {1, (byte)0xE0, (byte)0x80, (byte)0xC0 }, // invalid first byte + {1, (byte)0xE0, (byte)0x41,}, // invalid second byte & 2 bytes + {3, (byte)0xED, (byte)0xAE, (byte)0x80 }, // 3 bytes surrogate + {3, (byte)0xED, (byte)0xB0, (byte)0x80 }, // 3 bytes surrogate + // Four-byte sequences {1, (byte)0xF0, (byte)0x80, (byte)0x80, (byte)0x80 }, // U+0000 zero-padded @@ -276,8 +308,13 @@ public class TestUTF8 { {1, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF }, // all ones {1, (byte)0xF0, (byte)0x80, (byte)0x80, (byte)0x80}, // invalid second byte {1, (byte)0xF0, (byte)0xC0, (byte)0x80, (byte)0x80 }, // invalid second byte + {1, (byte)0xF0, (byte)41 }, // invalid second byte + // & only 2 bytes + {2, (byte)0xF0, (byte)0x90, (byte)0xC0, (byte)0x80 }, // invalid third byte - {3, (byte)0xF0, (byte)0x90, (byte)0x80, (byte)0xC0 }, // invalid third byte + {3, (byte)0xF0, (byte)0x90, (byte)0x80, (byte)0xC0 }, // invalid forth byte + {2, (byte)0xF0, (byte)0x90, (byte)0x41 }, // invalid third byte + // & 3 bytes input {1, (byte)0xF1, (byte)0xC0, (byte)0x80, (byte)0x80 }, // invalid second byte {2, (byte)0xF1, (byte)0x80, (byte)0xC0, (byte)0x80 }, // invalid third byte @@ -287,30 +324,113 @@ public class TestUTF8 { {1, (byte)0xF5, (byte)0x80, (byte)0x80, (byte)0xC0 }, // out-range 4-byte // Five-byte sequences - {5, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80}, // invalid first byte - {5, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80 }, // U+0000 zero-padded - {5, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x81, (byte)0xBF }, // U+007F zero-padded - {5, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x9F, (byte)0xBF }, // U+07FF zero-padded - {5, (byte)0xF8, (byte)0x80, (byte)0x8F, (byte)0xBF, (byte)0xBF }, // U+FFFF zero-padded + {1, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80}, // invalid first byte + {1, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80 }, // U+0000 zero-padded + {1, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x81, (byte)0xBF }, // U+007F zero-padded + {1, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x9F, (byte)0xBF }, // U+07FF zero-padded + {1, (byte)0xF8, (byte)0x80, (byte)0x8F, (byte)0xBF, (byte)0xBF }, // U+FFFF zero-padded {1, (byte)0xF8, (byte)0xC0, (byte)0x80, (byte)0x80, (byte)0x80}, - {2, (byte)0xF8, (byte)0x80, (byte)0xC0, (byte)0x80, (byte)0x80 }, - {3, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0xC1, (byte)0xBF }, - {4, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x9F, (byte)0xC0 }, + {1, (byte)0xF8, (byte)0x80, (byte)0xC0, (byte)0x80, (byte)0x80 }, + {1, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0xC1, (byte)0xBF }, + {1, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x9F, (byte)0xC0 }, // Six-byte sequences - {6, (byte)0xFC, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80 }, // U+0000 zero-padded - {6, (byte)0xFC, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x81, (byte)0xBF }, // U+007F zero-padded - {6, (byte)0xFC, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x9F, (byte)0xBF }, // U+07FF zero-padded - {6, (byte)0xFC, (byte)0x80, (byte)0x80, (byte)0x8F, (byte)0xBF, (byte)0xBF }, // U+FFFF zero-padded + {1, (byte)0xFC, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80 }, // U+0000 zero-padded + {1, (byte)0xFC, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x81, (byte)0xBF }, // U+007F zero-padded + {1, (byte)0xFC, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x9F, (byte)0xBF }, // U+07FF zero-padded + {1, (byte)0xFC, (byte)0x80, (byte)0x80, (byte)0x8F, (byte)0xBF, (byte)0xBF }, // U+FFFF zero-padded {1, (byte)0xF8, (byte)0xC0, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80 }, - {2, (byte)0xF8, (byte)0x80, (byte)0xC0, (byte)0x80, (byte)0x80, (byte)0x80 }, - {3, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0xC1, (byte)0xBF, (byte)0x80 }, - {4, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x9F, (byte)0xC0, (byte)0x80 }, - {5, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x9F, (byte)0x80, (byte)0xC0 }, + {1, (byte)0xF8, (byte)0x80, (byte)0xC0, (byte)0x80, (byte)0x80, (byte)0x80 }, + {1, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0xC1, (byte)0xBF, (byte)0x80 }, + {1, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x9F, (byte)0xC0, (byte)0x80 }, + {1, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x9F, (byte)0x80, (byte)0xC0 }, }; - static void checkMalformed(String csn) throws Exception { + // The first byte is the length of malformed bytes + static byte[][] malformed_cesu8 = { + // One-byte sequences: + {1, (byte)0xFF }, + {1, (byte)0xC0 }, + {1, (byte)0x80 }, + + {1, (byte)0xFF, (byte)0xFF}, // all ones + {1, (byte)0xA0, (byte)0x80}, // 101x first byte first nibble + + // Two-byte sequences: + {1, (byte)0xC0, (byte)0x80}, // invalid first byte + {1, (byte)0xC1, (byte)0xBF}, // invalid first byte + {1, (byte)0xC2, (byte)0x00}, // invalid second byte + {1, (byte)0xC2, (byte)0xC0}, // invalid second byte + {1, (byte)0xD0, (byte)0x00}, // invalid second byte + {1, (byte)0xD0, (byte)0xC0}, // invalid second byte + {1, (byte)0xDF, (byte)0x00}, // invalid second byte + {1, (byte)0xDF, (byte)0xC0}, // invalid second byte + + // Three-byte sequences + {1, (byte)0xE0, (byte)0x80, (byte)0x80}, // 111x first byte first nibble + {1, (byte)0xE0, (byte)0x80, (byte)0x80 }, // U+0000 zero-padded + {1, (byte)0xE0, (byte)0x81, (byte)0xBF }, // U+007F zero-padded + {1, (byte)0xE0, (byte)0x9F, (byte)0xBF }, // U+07FF zero-padded + + {1, (byte)0xE0, (byte)0xC0, (byte)0xBF }, // invalid second byte + {2, (byte)0xE0, (byte)0xA0, (byte)0x7F }, // invalid third byte + {2, (byte)0xE0, (byte)0xA0, (byte)0xC0 }, // invalid third byte + {1, (byte)0xFF, (byte)0xFF, (byte)0xFF }, // all ones + {1, (byte)0xE0, (byte)0xC0, (byte)0x80 }, // invalid second byte + {1, (byte)0xE0, (byte)0x80, (byte)0xC0 }, // invalid first byte + {1, (byte)0xE0, (byte)0x41,}, // invalid second byte & 2 bytes + + // CESU-8 does not have 4, 5, 6 bytes sequenc + // Four-byte sequences + {1, (byte)0xF0, (byte)0x80, (byte)0x80, (byte)0x80 }, // U+0000 zero-padded + {1, (byte)0xF0, (byte)0x80, (byte)0x81, (byte)0xBF }, // U+007F zero-padded + {1, (byte)0xF0, (byte)0x80, (byte)0x9F, (byte)0xBF }, // U+007F zero-padded + {1, (byte)0xF0, (byte)0x8F, (byte)0xBF, (byte)0xBF }, // U+07FF zero-padded + + {1, (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF }, // all ones + {1, (byte)0xF0, (byte)0x80, (byte)0x80, (byte)0x80}, // invalid second byte + {1, (byte)0xF0, (byte)0xC0, (byte)0x80, (byte)0x80 }, // invalid second byte + {1, (byte)0xF0, (byte)41 }, // invalid second byte + // & only 2 bytes + {1, (byte)0xF0, (byte)0x90, (byte)0xC0, (byte)0x80 }, // invalid third byte + {1, (byte)0xF0, (byte)0x90, (byte)0x80, (byte)0xC0 }, // invalid forth byte + {1, (byte)0xF0, (byte)0x90, (byte)0x41 }, // invalid third byte + // & 3 bytes input + + {1, (byte)0xF1, (byte)0xC0, (byte)0x80, (byte)0x80 }, // invalid second byte + {1, (byte)0xF1, (byte)0x80, (byte)0xC0, (byte)0x80 }, // invalid third byte + {1, (byte)0xF1, (byte)0x80, (byte)0x80, (byte)0xC0 }, // invalid forth byte + {1, (byte)0xF4, (byte)0x90, (byte)0x80, (byte)0xC0 }, // out-range 4-byte + {1, (byte)0xF4, (byte)0xC0, (byte)0x80, (byte)0xC0 }, // out-range 4-byte + {1, (byte)0xF5, (byte)0x80, (byte)0x80, (byte)0xC0 }, // out-range 4-byte + + // Five-byte sequences + {1, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80}, // invalid first byte + {1, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80 }, // U+0000 zero-padded + {1, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x81, (byte)0xBF }, // U+007F zero-padded + {1, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x9F, (byte)0xBF }, // U+07FF zero-padded + {1, (byte)0xF8, (byte)0x80, (byte)0x8F, (byte)0xBF, (byte)0xBF }, // U+FFFF zero-padded + + {1, (byte)0xF8, (byte)0xC0, (byte)0x80, (byte)0x80, (byte)0x80}, + {1, (byte)0xF8, (byte)0x80, (byte)0xC0, (byte)0x80, (byte)0x80 }, + {1, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0xC1, (byte)0xBF }, + {1, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x9F, (byte)0xC0 }, + + // Six-byte sequences + {1, (byte)0xFC, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80 }, // U+0000 zero-padded + {1, (byte)0xFC, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x81, (byte)0xBF }, // U+007F zero-padded + {1, (byte)0xFC, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x9F, (byte)0xBF }, // U+07FF zero-padded + {1, (byte)0xFC, (byte)0x80, (byte)0x80, (byte)0x8F, (byte)0xBF, (byte)0xBF }, // U+FFFF zero-padded + {1, (byte)0xF8, (byte)0xC0, (byte)0x80, (byte)0x80, (byte)0x80, (byte)0x80 }, + {1, (byte)0xF8, (byte)0x80, (byte)0xC0, (byte)0x80, (byte)0x80, (byte)0x80 }, + {1, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0xC1, (byte)0xBF, (byte)0x80 }, + {1, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x9F, (byte)0xC0, (byte)0x80 }, + {1, (byte)0xF8, (byte)0x80, (byte)0x80, (byte)0x9F, (byte)0x80, (byte)0xC0 }, + }; + + + static void checkMalformed(String csn, byte[][] malformed) throws Exception { boolean failed = false; System.out.printf(" Check malformed <%s>...%n", csn); Charset cs = Charset.forName(csn); @@ -430,9 +550,12 @@ public class TestUTF8 { public static void main(String[] args) throws Exception { checkRoundtrip("UTF-8"); - check6ByteSurrs("UTF-8"); - //compare("UTF-8", "UTF-8-OLD"); - checkMalformed("UTF-8"); + check4ByteSurrs("UTF-8"); + checkMalformed("UTF-8", malformed); checkUnderOverflow("UTF-8"); + + checkRoundtrip("CESU-8"); + check6ByteSurrs("CESU-8"); + checkMalformed("CESU-8", malformed_cesu8); } } From 856768a6c088ecb15649058e56d9384e629d2e0f Mon Sep 17 00:00:00 2001 From: Alexandr Scherbatiy Date: Tue, 8 Nov 2011 14:36:50 +0300 Subject: [PATCH 076/107] 7107585: Test incorrect calculate position of object on frame Reviewed-by: rupashka --- .../swing/JSlider/6348946/bug6348946.java | 172 ++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 jdk/test/javax/swing/JSlider/6348946/bug6348946.java diff --git a/jdk/test/javax/swing/JSlider/6348946/bug6348946.java b/jdk/test/javax/swing/JSlider/6348946/bug6348946.java new file mode 100644 index 00000000000..7183debcb5e --- /dev/null +++ b/jdk/test/javax/swing/JSlider/6348946/bug6348946.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2007, 2011, 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 6348946 + * @summary Tests that JSlider's thumb moves in the right direction + * when it is used as a JTable cell editor. + * @author Mikhail Lapshin +*/ + +import sun.awt.SunToolkit; + +import java.awt.*; +import java.awt.event.InputEvent; +import javax.swing.*; +import javax.swing.event.*; +import javax.swing.table.*; + +public class bug6348946 { + + private static JFrame frame; + + private static JPanel panel; + + private static volatile boolean passed = false; + + public static void main(String[] args) throws Exception { + String lf = "javax.swing.plaf.metal.MetalLookAndFeel"; + UIManager.setLookAndFeel(lf); + SunToolkit toolkit = (SunToolkit) Toolkit.getDefaultToolkit(); + + try { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + setupUI(); + } + }); + toolkit.realSync(); + clickOnSlider(); + toolkit.realSync(); + checkResult(); + } finally { + stopEDT(); + } + } + + private static void setupUI() { + frame = new JFrame(); + + panel = new JPanel(); + panel.setLayout(new BorderLayout()); + panel.add(new ParameterTable(), BorderLayout.CENTER); + frame.getContentPane().add(panel); + + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + private static void clickOnSlider() throws Exception { + Robot robot = new Robot(); + robot.setAutoDelay(10); + + Rectangle rect = getPanelRectangle(); + + double clickX = rect.getX() + rect.getWidth() / 4; + double clickY = rect.getY() + rect.getHeight() / 2; + robot.mouseMove((int) clickX, (int) clickY); + + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + } + + private static void checkResult(){ + if (passed) { + System.out.println("Test passed"); + } else { + throw new RuntimeException("The thumb moved " + + "to the right instead of the left!"); + } + } + + private static void stopEDT() { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + frame.dispose(); + } + }); + } + + private static class ParameterTable extends JTable { + public ParameterTable() { + super(new Object[][]{{5}}, new String[]{"Value"}); + getColumnModel().getColumn(0).setCellRenderer(new Renderer()); + getColumnModel().getColumn(0).setCellEditor(new Editor()); + } + } + + private static class Renderer implements TableCellRenderer { + private JSlider slider = new JSlider(0, 10); + + public Component getTableCellRendererComponent(JTable table, + Object value, + boolean isSelected, + boolean hasFocus, + int row, int col) { + int val = (Integer) value; + slider.setValue(val); + return slider; + } + } + + private static class Editor extends AbstractCellEditor implements TableCellEditor { + private JSlider slider = new JSlider(0, 10); + + public Component getTableCellEditorComponent(JTable table, Object value, + boolean isSelected, + int row, int col) { + int val = (Integer) value; + slider.setValue(val); + return slider; + } + + public Editor() { + slider.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + if (!slider.getValueIsAdjusting()) { + passed = slider.getValue() <= 5; + } + } + }); + } + + public Object getCellEditorValue() { + return slider.getValue(); + } + } + + private static Rectangle getPanelRectangle() throws Exception{ + final Rectangle[] result = new Rectangle[1]; + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + result[0] = new Rectangle(panel.getLocationOnScreen(), panel.getSize()); + } + }); + + return result[0]; + } +} From 399b71b9f0854079ec68b73738c03cc5754cc62f Mon Sep 17 00:00:00 2001 From: Vicente Romero Date: Tue, 8 Nov 2011 11:51:05 -0800 Subject: [PATCH 077/107] 6921494: provide way to print javac tree tag values Reviewed-by: jjg, mcimadamore --- .../sun/tools/javac/api/JavacTaskImpl.java | 6 +- .../com/sun/tools/javac/api/JavacTrees.java | 2 +- .../com/sun/tools/javac/comp/Annotate.java | 14 +- .../com/sun/tools/javac/comp/Attr.java | 95 +-- .../com/sun/tools/javac/comp/Check.java | 23 +- .../com/sun/tools/javac/comp/Enter.java | 2 +- .../classes/com/sun/tools/javac/comp/Env.java | 6 +- .../com/sun/tools/javac/comp/Flow.java | 40 +- .../com/sun/tools/javac/comp/Infer.java | 4 +- .../com/sun/tools/javac/comp/Lower.java | 172 +++-- .../com/sun/tools/javac/comp/MemberEnter.java | 6 +- .../com/sun/tools/javac/comp/Resolve.java | 11 +- .../com/sun/tools/javac/jvm/CRTable.java | 2 +- .../classes/com/sun/tools/javac/jvm/Gen.java | 56 +- .../sun/tools/javac/main/JavaCompiler.java | 6 +- .../sun/tools/javac/model/JavacElements.java | 7 +- .../sun/tools/javac/parser/JavacParser.java | 140 ++-- .../JavacProcessingEnvironment.java | 2 +- .../com/sun/tools/javac/tree/JCTree.java | 557 ++++++++-------- .../com/sun/tools/javac/tree/Pretty.java | 90 +-- .../com/sun/tools/javac/tree/TreeCopier.java | 2 +- .../com/sun/tools/javac/tree/TreeInfo.java | 608 +++++++++--------- .../com/sun/tools/javac/tree/TreeMaker.java | 6 +- .../com/sun/tools/javadoc/ClassDocImpl.java | 5 +- .../com/sun/tools/javadoc/JavadocTool.java | 2 +- .../javac/failover/CheckAttributedTree.java | 39 +- .../javac/tree/AbstractTreeScannerTest.java | 4 +- .../test/tools/javac/tree/TreePosTest.java | 70 +- 28 files changed, 1030 insertions(+), 947 deletions(-) diff --git a/langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java b/langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java index 1b1e331dae9..e1a82e6cc54 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java +++ b/langtools/src/share/classes/com/sun/tools/javac/api/JavacTaskImpl.java @@ -325,7 +325,7 @@ public class JavacTaskImpl extends JavacTask { ListBuffer elements = new ListBuffer(); for (JCCompilationUnit unit : units) { for (JCTree node : unit.defs) { - if (node.getTag() == JCTree.CLASSDEF) { + if (node.hasTag(JCTree.Tag.CLASSDEF)) { JCClassDecl cdef = (JCClassDecl) node; if (cdef.sym != null) // maybe null if errors in anno processing elements.append(cdef.sym); @@ -383,12 +383,12 @@ public class JavacTaskImpl extends JavacTask { private void handleFlowResults(Queue> queue, ListBuffer elems) { for (Env env: queue) { switch (env.tree.getTag()) { - case JCTree.CLASSDEF: + case CLASSDEF: JCClassDecl cdef = (JCClassDecl) env.tree; if (cdef.sym != null) elems.append(cdef.sym); break; - case JCTree.TOPLEVEL: + case TOPLEVEL: JCCompilationUnit unit = (JCCompilationUnit) env.tree; if (unit.packge != null) elems.append(unit.packge); diff --git a/langtools/src/share/classes/com/sun/tools/javac/api/JavacTrees.java b/langtools/src/share/classes/com/sun/tools/javac/api/JavacTrees.java index 7bd384bb5ac..1c6f7302751 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/api/JavacTrees.java +++ b/langtools/src/share/classes/com/sun/tools/javac/api/JavacTrees.java @@ -207,7 +207,7 @@ public class JavacTrees extends Trees { if (sym == null && TreeInfo.isDeclaration(tree)) { for (TreePath p = path; p != null; p = p.getParentPath()) { JCTree t = (JCTree) p.getLeaf(); - if (t.getTag() == JCTree.CLASSDEF) { + if (t.hasTag(JCTree.Tag.CLASSDEF)) { JCClassDecl ct = (JCClassDecl) t; if (ct.sym != null) { if ((ct.sym.flags_field & Flags.UNATTRIBUTED) != 0) { diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java index 3d13527da8c..724481e54ae 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Annotate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2011, 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 @@ -31,6 +31,8 @@ import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.tree.*; import com.sun.tools.javac.tree.JCTree.*; +import static com.sun.tools.javac.tree.JCTree.Tag.*; + /** Enter annotations on symbols. Annotations accumulate in a queue, * which is processed at the top level of any set of recursive calls * requesting it be processed. @@ -148,7 +150,7 @@ public class Annotate { return new Attribute.Compound(a.type, List.>nil()); } List args = a.args; - if (args.length() == 1 && args.head.getTag() != JCTree.ASSIGN) { + if (args.length() == 1 && !args.head.hasTag(ASSIGN)) { // special case: elided "value=" assumed args.head = make.at(args.head.pos). Assign(make.Ident(names.value), args.head); @@ -157,12 +159,12 @@ public class Annotate { new ListBuffer>(); for (List tl = args; tl.nonEmpty(); tl = tl.tail) { JCExpression t = tl.head; - if (t.getTag() != JCTree.ASSIGN) { + if (!t.hasTag(ASSIGN)) { log.error(t.pos(), "annotation.value.must.be.name.value"); continue; } JCAssign assign = (JCAssign)t; - if (assign.lhs.getTag() != JCTree.IDENT) { + if (!assign.lhs.hasTag(IDENT)) { log.error(t.pos(), "annotation.value.must.be.name.value"); continue; } @@ -222,14 +224,14 @@ public class Annotate { (((JCFieldAccess) tree).selected).type); } if ((expected.tsym.flags() & Flags.ANNOTATION) != 0) { - if (tree.getTag() != JCTree.ANNOTATION) { + if (!tree.hasTag(ANNOTATION)) { log.error(tree.pos(), "annotation.value.must.be.annotation"); expected = syms.errorType; } return enterAnnotation((JCAnnotation)tree, expected, env); } if (expected.tag == TypeTags.ARRAY) { // should really be isArray() - if (tree.getTag() != JCTree.NEWARRAY) { + if (!tree.hasTag(NEWARRAY)) { tree = make.at(tree.pos). NewArray(null, List.nil(), List.of(tree)); } diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java index 68b782f44ed..ebecb033566 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Attr.java @@ -49,8 +49,13 @@ import com.sun.source.tree.TreeVisitor; import com.sun.source.util.SimpleTreeVisitor; import static com.sun.tools.javac.code.Flags.*; +import static com.sun.tools.javac.code.Flags.ANNOTATION; +import static com.sun.tools.javac.code.Flags.BLOCK; import static com.sun.tools.javac.code.Kinds.*; +import static com.sun.tools.javac.code.Kinds.ERRONEOUS; import static com.sun.tools.javac.code.TypeTags.*; +import static com.sun.tools.javac.code.TypeTags.WILDCARD; +import static com.sun.tools.javac.tree.JCTree.Tag.*; /** This is the main context-dependent analysis phase in GJC. It * encompasses name resolution, type checking and constant folding as @@ -245,7 +250,7 @@ public class Attr extends JCTree.Visitor { ((v.flags() & HASINIT) != 0 || !((base == null || - (base.getTag() == JCTree.IDENT && TreeInfo.name(base) == names._this)) && + (base.hasTag(IDENT) && TreeInfo.name(base) == names._this)) && isAssignableAsBlankFinal(v, env)))) { if (v.isResourceVariable()) { //TWR resource log.error(pos, "try.resource.may.not.be.assigned", v); @@ -263,7 +268,7 @@ public class Attr extends JCTree.Visitor { * @param tree The candidate tree. */ boolean isStaticReference(JCTree tree) { - if (tree.getTag() == JCTree.SELECT) { + if (tree.hasTag(SELECT)) { Symbol lsym = TreeInfo.symbol(((JCFieldAccess) tree).selected); if (lsym == null || lsym.kind != TYP) { return false; @@ -693,7 +698,7 @@ public class Attr extends JCTree.Visitor { // disable implicit outer instance from being passed. // (This would be an illegal access to "this before super"). if (env.info.isSelfCall && - env.tree.getTag() == JCTree.NEWCLASS && + env.tree.hasTag(NEWCLASS) && ((JCNewClass) env.tree).encl == null) { c.flags_field |= NOOUTERTHIS; @@ -863,7 +868,7 @@ public class Attr extends JCTree.Visitor { chk.checkDeprecatedAnnotation(tree.pos(), v); if (tree.init != null) { - if ((v.flags_field & FINAL) != 0 && tree.init.getTag() != JCTree.NEWCLASS) { + if ((v.flags_field & FINAL) != 0 && !tree.init.hasTag(NEWCLASS)) { // In this case, `v' is final. Ensure that it's initializer is // evaluated. v.getConstValue(); // ensure initializer is evaluated @@ -971,8 +976,8 @@ public class Attr extends JCTree.Visitor { public void visitLabelled(JCLabeledStatement tree) { // Check that label is not used in an enclosing statement Env env1 = env; - while (env1 != null && env1.tree.getTag() != JCTree.CLASSDEF) { - if (env1.tree.getTag() == JCTree.LABELLED && + while (env1 != null && !env1.tree.hasTag(CLASSDEF)) { + if (env1.tree.hasTag(LABELLED) && ((JCLabeledStatement) env1.tree).label == tree.label) { log.error(tree.pos(), "label.already.in.use", tree.label); @@ -1052,14 +1057,14 @@ public class Attr extends JCTree.Visitor { private static void addVars(List stats, Scope switchScope) { for (;stats.nonEmpty(); stats = stats.tail) { JCTree stat = stats.head; - if (stat.getTag() == JCTree.VARDEF) + if (stat.hasTag(VARDEF)) switchScope.enter(((JCVariableDecl) stat).sym); } } // where /** Return the selected enumeration constant symbol, or null. */ private Symbol enumConstant(JCTree tree, Type enumType) { - if (tree.getTag() != JCTree.IDENT) { + if (!tree.hasTag(IDENT)) { log.error(tree.pos(), "enum.label.must.be.unqualified.enum"); return syms.errSymbol; } @@ -1094,7 +1099,7 @@ public class Attr extends JCTree.Visitor { localEnv; // Attribute resource declarations for (JCTree resource : tree.resources) { - if (resource.getTag() == JCTree.VARDEF) { + if (resource.hasTag(VARDEF)) { attribStat(resource, tryEnv); chk.checkType(resource, resource.type, syms.autoCloseableType, "try.not.applicable.to.type"); @@ -1312,7 +1317,7 @@ public class Attr extends JCTree.Visitor { * @param env The environment current at the jump statement. */ private JCTree findJumpTarget(DiagnosticPosition pos, - int tag, + JCTree.Tag tag, Name label, Env env) { // Search environments outwards from the point of jump. @@ -1320,15 +1325,15 @@ public class Attr extends JCTree.Visitor { LOOP: while (env1 != null) { switch (env1.tree.getTag()) { - case JCTree.LABELLED: + case LABELLED: JCLabeledStatement labelled = (JCLabeledStatement)env1.tree; if (label == labelled.label) { // If jump is a continue, check that target is a loop. - if (tag == JCTree.CONTINUE) { - if (labelled.body.getTag() != JCTree.DOLOOP && - labelled.body.getTag() != JCTree.WHILELOOP && - labelled.body.getTag() != JCTree.FORLOOP && - labelled.body.getTag() != JCTree.FOREACHLOOP) + if (tag == CONTINUE) { + if (!labelled.body.hasTag(DOLOOP) && + !labelled.body.hasTag(WHILELOOP) && + !labelled.body.hasTag(FORLOOP) && + !labelled.body.hasTag(FOREACHLOOP)) log.error(pos, "not.loop.label", label); // Found labelled statement target, now go inwards // to next non-labelled tree. @@ -1338,17 +1343,17 @@ public class Attr extends JCTree.Visitor { } } break; - case JCTree.DOLOOP: - case JCTree.WHILELOOP: - case JCTree.FORLOOP: - case JCTree.FOREACHLOOP: + case DOLOOP: + case WHILELOOP: + case FORLOOP: + case FOREACHLOOP: if (label == null) return env1.tree; break; - case JCTree.SWITCH: - if (label == null && tag == JCTree.BREAK) return env1.tree; + case SWITCH: + if (label == null && tag == BREAK) return env1.tree; break; - case JCTree.METHODDEF: - case JCTree.CLASSDEF: + case METHODDEF: + case CLASSDEF: break LOOP; default: } @@ -1356,7 +1361,7 @@ public class Attr extends JCTree.Visitor { } if (label != null) log.error(pos, "undef.label", label); - else if (tag == JCTree.CONTINUE) + else if (tag == CONTINUE) log.error(pos, "cont.outside.loop"); else log.error(pos, "break.outside.switch.loop"); @@ -1452,7 +1457,7 @@ public class Attr extends JCTree.Visitor { if (encl.tag == CLASS) { // we are calling a nested class - if (tree.meth.getTag() == JCTree.SELECT) { + if (tree.meth.hasTag(SELECT)) { JCTree qualifier = ((JCFieldAccess) tree.meth).selected; // We are seeing a prefixed call, of the form @@ -1468,7 +1473,7 @@ public class Attr extends JCTree.Visitor { rs.resolveImplicitThis(tree.meth.pos(), localEnv, site, true); } - } else if (tree.meth.getTag() == JCTree.SELECT) { + } else if (tree.meth.hasTag(SELECT)) { log.error(tree.meth.pos(), "illegal.qual.not.icls", site.tsym); } @@ -1522,7 +1527,7 @@ public class Attr extends JCTree.Visitor { // as a special case, array.clone() has a result that is // the same as static type of the array being cloned - if (tree.meth.getTag() == JCTree.SELECT && + if (tree.meth.hasTag(SELECT) && allowCovariantReturns && methName == names.clone && types.isArray(((JCFieldAccess) tree.meth).selected.type)) @@ -1531,7 +1536,7 @@ public class Attr extends JCTree.Visitor { // as a special case, x.getClass() has type Class if (allowGenerics && methName == names.getClass && tree.args.isEmpty()) { - Type qualifier = (tree.meth.getTag() == JCTree.SELECT) + Type qualifier = (tree.meth.hasTag(SELECT)) ? ((JCFieldAccess) tree.meth).selected.type : env.enclClass.sym.type; restype = new @@ -1560,7 +1565,7 @@ public class Attr extends JCTree.Visitor { JCMethodDecl enclMethod = env.enclMethod; if (enclMethod != null && enclMethod.name == names.init) { JCBlock body = enclMethod.body; - if (body.stats.head.getTag() == JCTree.EXEC && + if (body.stats.head.hasTag(EXEC) && ((JCExpressionStatement) body.stats.head).expr == tree) return true; } @@ -1591,7 +1596,7 @@ public class Attr extends JCTree.Visitor { // complete class name to be fully qualified JCExpression clazz = tree.clazz; // Class field following new JCExpression clazzid = // Identifier in class field - (clazz.getTag() == JCTree.TYPEAPPLY) + (clazz.hasTag(TYPEAPPLY)) ? ((JCTypeApply) clazz).clazz : clazz; @@ -1610,7 +1615,7 @@ public class Attr extends JCTree.Visitor { attribExpr(tree.encl, env)); clazzid1 = make.at(clazz.pos).Select(make.Type(encltype), ((JCIdent) clazzid).name); - if (clazz.getTag() == JCTree.TYPEAPPLY) + if (clazz.hasTag(TYPEAPPLY)) clazz = make.at(tree.pos). TypeApply(clazzid1, ((JCTypeApply) clazz).arguments); @@ -1689,7 +1694,7 @@ public class Attr extends JCTree.Visitor { // Enums may not be instantiated except implicitly if (allowEnums && (clazztype.tsym.flags_field&Flags.ENUM) != 0 && - (env.tree.getTag() != JCTree.VARDEF || + (!env.tree.hasTag(VARDEF) || (((JCVariableDecl) env.tree).mods.flags&Flags.ENUM) == 0 || ((JCVariableDecl) env.tree).init != tree)) log.error(tree.pos(), "enum.cant.be.instantiated"); @@ -1930,7 +1935,7 @@ public class Attr extends JCTree.Visitor { Name name = TreeInfo.name(arg); if (name == names._this || name == names._super) return arg; - int optag = JCTree.NULLCHK; + JCTree.Tag optag = NULLCHK; JCUnary tree = make.at(arg.pos).Unary(optag, arg); tree.operator = syms.nullcheck; tree.type = arg.type; @@ -1991,7 +1996,7 @@ public class Attr extends JCTree.Visitor { Type operand = attribExpr(tree.rhs, env); // Find operator. Symbol operator = tree.operator = rs.resolveBinaryOperator( - tree.pos(), tree.getTag() - JCTree.ASGOffset, env, + tree.pos(), tree.getTag().noAssignOp(), env, owntype, operand); if (operator.kind == MTH && @@ -1999,7 +2004,7 @@ public class Attr extends JCTree.Visitor { !operand.isErroneous()) { chk.checkOperator(tree.pos(), (OperatorSymbol)operator, - tree.getTag() - JCTree.ASGOffset, + tree.getTag().noAssignOp(), owntype, operand); chk.checkDivZero(tree.rhs.pos(), operator, operand); @@ -2012,7 +2017,7 @@ public class Attr extends JCTree.Visitor { public void visitUnary(JCUnary tree) { // Attribute arguments. - Type argtype = (JCTree.PREINC <= tree.getTag() && tree.getTag() <= JCTree.POSTDEC) + Type argtype = (tree.getTag().isIncOrDecUnaryOp()) ? attribTree(tree.arg, env, VAR, Type.noType) : chk.checkNonVoid(tree.arg.pos(), attribExpr(tree.arg, env)); @@ -2023,7 +2028,7 @@ public class Attr extends JCTree.Visitor { Type owntype = types.createErrorType(tree.type); if (operator.kind == MTH && !argtype.isErroneous()) { - owntype = (JCTree.PREINC <= tree.getTag() && tree.getTag() <= JCTree.POSTDEC) + owntype = (tree.getTag().isIncOrDecUnaryOp()) ? tree.arg.type : operator.type.getReturnType(); int opc = ((OperatorSymbol)operator).opcode; @@ -2621,7 +2626,7 @@ public class Attr extends JCTree.Visitor { canOwnInitializer(env.info.scope.owner) && v.owner == env.info.scope.owner.enclClass() && ((v.flags() & STATIC) != 0) == Resolve.isStatic(env) && - (env.tree.getTag() != JCTree.ASSIGN || + (!env.tree.hasTag(ASSIGN) || TreeInfo.skipParens(((JCAssign) env.tree).lhs) != tree)) { String suffix = (env.info.enclVar == v) ? "self.ref" : "forward.ref"; @@ -2812,10 +2817,10 @@ public class Attr extends JCTree.Visitor { } Type elemtype = types.elemtype(argtype); switch (tree.getTag()) { - case JCTree.APPLY: + case APPLY: ((JCMethodInvocation) tree).varargsElement = elemtype; break; - case JCTree.NEWCLASS: + case NEWCLASS: ((JCNewClass) tree).varargsElement = elemtype; break; default: @@ -2896,9 +2901,9 @@ public class Attr extends JCTree.Visitor { if (clazzOuter.tag == CLASS) { Type site; JCExpression clazz = TreeInfo.typeIn(tree.clazz); - if (clazz.getTag() == JCTree.IDENT) { + if (clazz.hasTag(IDENT)) { site = env.enclClass.sym.type; - } else if (clazz.getTag() == JCTree.SELECT) { + } else if (clazz.hasTag(SELECT)) { site = ((JCFieldAccess) clazz).selected.type; } else throw new AssertionError(""+tree); if (clazzOuter.tag == CLASS && site != clazzOuter) { @@ -3068,7 +3073,7 @@ public class Attr extends JCTree.Visitor { * Attribute an env for either a top level tree or class declaration. */ public void attrib(Env env) { - if (env.tree.getTag() == JCTree.TOPLEVEL) + if (env.tree.hasTag(TOPLEVEL)) attribTopLevel(env); else attribClass(env.tree.pos(), env.enclClass.sym); @@ -3245,7 +3250,7 @@ public class Attr extends JCTree.Visitor { ((c.flags() & STATIC) == 0 || c.name == names.empty) && (TreeInfo.flags(l.head) & (STATIC | INTERFACE)) != 0) { Symbol sym = null; - if (l.head.getTag() == JCTree.VARDEF) sym = ((JCVariableDecl) l.head).sym; + if (l.head.hasTag(VARDEF)) sym = ((JCVariableDecl) l.head).sym; if (sym == null || sym.kind != VAR || ((VarSymbol) sym).getConstValue() == null) diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java index cd5ced051fd..e384efa9022 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Check.java @@ -42,10 +42,14 @@ import com.sun.tools.javac.code.Type.*; import com.sun.tools.javac.code.Symbol.*; import static com.sun.tools.javac.code.Flags.*; +import static com.sun.tools.javac.code.Flags.ANNOTATION; +import static com.sun.tools.javac.code.Flags.SYNCHRONIZED; import static com.sun.tools.javac.code.Kinds.*; import static com.sun.tools.javac.code.TypeTags.*; +import static com.sun.tools.javac.code.TypeTags.WILDCARD; import static com.sun.tools.javac.main.OptionName.*; +import static com.sun.tools.javac.tree.JCTree.Tag.*; /** Type checking helper class for the attribution phase. * @@ -987,7 +991,7 @@ public class Check { * not final. */ private long implicitEnumFinalFlag(JCTree tree) { - if (tree.getTag() != JCTree.CLASSDEF) return 0; + if (!tree.hasTag(CLASSDEF)) return 0; class SpecialTreeVisitor extends JCTree.Visitor { boolean specialized; SpecialTreeVisitor() { @@ -1099,7 +1103,7 @@ public class Check { // not parameterized at all. if (tree.type.getEnclosingType().isRaw()) log.error(tree.pos(), "improperly.formed.type.inner.raw.param"); - if (tree.clazz.getTag() == JCTree.SELECT) + if (tree.clazz.hasTag(SELECT)) visitSelectInternal((JCFieldAccess)tree.clazz); } } @@ -2413,7 +2417,7 @@ public class Check { // count them off as they're annotated for (JCTree arg : a.args) { - if (arg.getTag() != JCTree.ASSIGN) continue; // recovery + if (!arg.hasTag(ASSIGN)) continue; // recovery JCAssign assign = (JCAssign) arg; Symbol m = TreeInfo.symbol(assign.lhs); if (m == null || m.type.isErroneous()) continue; @@ -2442,12 +2446,12 @@ public class Check { a.args.tail == null) return; - if (a.args.head.getTag() != JCTree.ASSIGN) return; // error recovery + if (!a.args.head.hasTag(ASSIGN)) return; // error recovery JCAssign assign = (JCAssign) a.args.head; Symbol m = TreeInfo.symbol(assign.lhs); if (m.name != names.value) return; JCTree rhs = assign.rhs; - if (rhs.getTag() != JCTree.NEWARRAY) return; + if (!rhs.hasTag(NEWARRAY)) return; JCNewArray na = (JCNewArray) rhs; Set targets = new HashSet(); for (JCTree elem : na.elems) { @@ -2506,7 +2510,7 @@ public class Check { try { tree.sym.flags_field |= LOCKED; for (JCTree def : tree.defs) { - if (def.getTag() != JCTree.METHODDEF) continue; + if (!def.hasTag(METHODDEF)) continue; JCMethodDecl meth = (JCMethodDecl)def; checkAnnotationResType(meth.pos(), meth.restype.type); } @@ -2614,7 +2618,7 @@ public class Check { */ int checkOperator(DiagnosticPosition pos, OperatorSymbol operator, - int tag, + JCTree.Tag tag, Type left, Type right) { if (operator.opcode == ByteCodes.error) { @@ -2650,7 +2654,8 @@ public class Check { * Check for empty statements after if */ void checkEmptyIf(JCIf tree) { - if (tree.thenpart.getTag() == JCTree.SKIP && tree.elsepart == null && lint.isEnabled(LintCategory.EMPTY)) + if (tree.thenpart.hasTag(SKIP) && tree.elsepart == null && + lint.isEnabled(LintCategory.EMPTY)) log.warning(LintCategory.EMPTY, tree.thenpart.pos(), "empty.if"); } @@ -2754,7 +2759,7 @@ public class Check { } // where private boolean isCanonical(JCTree tree) { - while (tree.getTag() == JCTree.SELECT) { + while (tree.hasTag(SELECT)) { JCFieldAccess s = (JCFieldAccess) tree; if (s.sym.owner != TreeInfo.symbol(s.selected)) return false; diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Enter.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Enter.java index 864698458fc..ac8ce840afb 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Enter.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Enter.java @@ -228,7 +228,7 @@ public class Enter extends JCTree.Visitor { * only, and members go into the class member scope. */ Scope enterScope(Env env) { - return (env.tree.getTag() == JCTree.CLASSDEF) + return (env.tree.hasTag(JCTree.Tag.CLASSDEF)) ? ((JCClassDecl) env.tree).sym.members_field : env.info.scope; } diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Env.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Env.java index c46cafe0396..f61ed700e0b 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Env.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Env.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2011, 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 @@ -116,9 +116,9 @@ public class Env implements Iterable> { /** Return closest enclosing environment which points to a tree with given tag. */ - public Env enclosing(int tag) { + public Env enclosing(JCTree.Tag tag) { Env env1 = this; - while (env1 != null && env1.tree.getTag() != tag) env1 = env1.next; + while (env1 != null && !env1.tree.hasTag(tag)) env1 = env1.next; return env1; } diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java index 0c685f932e4..d54a295b9b0 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java @@ -40,8 +40,10 @@ import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.tree.JCTree.*; import static com.sun.tools.javac.code.Flags.*; +import static com.sun.tools.javac.code.Flags.BLOCK; import static com.sun.tools.javac.code.Kinds.*; import static com.sun.tools.javac.code.TypeTags.*; +import static com.sun.tools.javac.tree.JCTree.Tag.*; /** This pass implements dataflow analysis for Java programs. * Liveness analysis checks that every statement is reachable. @@ -321,7 +323,7 @@ public class Flow extends TreeScanner { log.error(exit.tree.pos(), "unreported.exception.default.constructor", exit.thrown); - } else if (exit.tree.getTag() == JCTree.VARDEF && + } else if (exit.tree.hasTag(VARDEF) && ((JCVariableDecl)exit.tree).sym.isResourceVariable()) { log.error(exit.tree.pos(), "unreported.exception.implicit.close", @@ -416,7 +418,7 @@ public class Flow extends TreeScanner { */ void letInit(JCTree tree) { tree = TreeInfo.skipParens(tree); - if (tree.getTag() == JCTree.IDENT || tree.getTag() == JCTree.SELECT) { + if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) { Symbol sym = TreeInfo.symbol(tree); if (sym.kind == VAR) { letInit(tree.pos(), (VarSymbol)sym); @@ -452,7 +454,7 @@ public class Flow extends TreeScanner { pendingExits = oldPendingExits; for (; exits.nonEmpty(); exits = exits.tail) { PendingExit exit = exits.head; - if (exit.tree.getTag() == JCTree.BREAK && + if (exit.tree.hasTag(BREAK) && ((JCBreak) exit.tree).target == tree) { inits.andSet(exit.inits); uninits.andSet(exit.uninits); @@ -471,7 +473,7 @@ public class Flow extends TreeScanner { pendingExits = new ListBuffer(); for (; exits.nonEmpty(); exits = exits.tail) { PendingExit exit = exits.head; - if (exit.tree.getTag() == JCTree.CONTINUE && + if (exit.tree.hasTag(CONTINUE) && ((JCContinue) exit.tree).target == tree) { inits.andSet(exit.inits); uninits.andSet(exit.uninits); @@ -517,7 +519,7 @@ public class Flow extends TreeScanner { */ void scanDef(JCTree tree) { scanStat(tree); - if (tree != null && tree.getTag() == JCTree.BLOCK && !alive) { + if (tree != null && tree.hasTag(JCTree.Tag.BLOCK) && !alive) { log.error(tree.pos(), "initializer.must.be.able.to.complete.normally"); } @@ -528,7 +530,7 @@ public class Flow extends TreeScanner { void scanStat(JCTree tree) { if (!alive && tree != null) { log.error(tree.pos(), "unreachable.stmt"); - if (tree.getTag() != JCTree.SKIP) alive = true; + if (!tree.hasTag(SKIP)) alive = true; } scan(tree); } @@ -614,7 +616,7 @@ public class Flow extends TreeScanner { try { // define all the static fields for (List l = tree.defs; l.nonEmpty(); l = l.tail) { - if (l.head.getTag() == JCTree.VARDEF) { + if (l.head.hasTag(VARDEF)) { JCVariableDecl def = (JCVariableDecl)l.head; if ((def.mods.flags & STATIC) != 0) { VarSymbol sym = def.sym; @@ -626,7 +628,7 @@ public class Flow extends TreeScanner { // process all the static initializers for (List l = tree.defs; l.nonEmpty(); l = l.tail) { - if (l.head.getTag() != JCTree.METHODDEF && + if (!l.head.hasTag(METHODDEF) && (TreeInfo.flags(l.head) & STATIC) != 0) { scanDef(l.head); errorUncaught(); @@ -653,7 +655,7 @@ public class Flow extends TreeScanner { // define all the instance fields for (List l = tree.defs; l.nonEmpty(); l = l.tail) { - if (l.head.getTag() == JCTree.VARDEF) { + if (l.head.hasTag(VARDEF)) { JCVariableDecl def = (JCVariableDecl)l.head; if ((def.mods.flags & STATIC) == 0) { VarSymbol sym = def.sym; @@ -665,7 +667,7 @@ public class Flow extends TreeScanner { // process all the instance initializers for (List l = tree.defs; l.nonEmpty(); l = l.tail) { - if (l.head.getTag() != JCTree.METHODDEF && + if (!l.head.hasTag(METHODDEF) && (TreeInfo.flags(l.head) & STATIC) == 0) { scanDef(l.head); errorUncaught(); @@ -691,7 +693,7 @@ public class Flow extends TreeScanner { // process all the methods for (List l = tree.defs; l.nonEmpty(); l = l.tail) { - if (l.head.getTag() == JCTree.METHODDEF) { + if (l.head.hasTag(METHODDEF)) { scan(l.head); errorUncaught(); } @@ -760,7 +762,7 @@ public class Flow extends TreeScanner { PendingExit exit = exits.head; exits = exits.tail; if (exit.thrown == null) { - Assert.check(exit.tree.getTag() == JCTree.RETURN); + Assert.check(exit.tree.hasTag(RETURN)); if (isInitialConstructor) { inits = exit.inits; for (int i = firstadr; i < nextadr; i++) @@ -989,7 +991,7 @@ public class Flow extends TreeScanner { Bits uninits) { for (;stats.nonEmpty(); stats = stats.tail) { JCTree stat = stats.head; - if (stat.getTag() == JCTree.VARDEF) { + if (stat.hasTag(VARDEF)) { int adr = ((JCVariableDecl) stat).sym.adr; inits.excl(adr); uninits.incl(adr); @@ -1346,7 +1348,7 @@ public class Flow extends TreeScanner { public void visitUnary(JCUnary tree) { switch (tree.getTag()) { - case JCTree.NOT: + case NOT: scanCond(tree.arg); Bits t = initsWhenFalse; initsWhenFalse = initsWhenTrue; @@ -1355,8 +1357,8 @@ public class Flow extends TreeScanner { uninitsWhenFalse = uninitsWhenTrue; uninitsWhenTrue = t; break; - case JCTree.PREINC: case JCTree.POSTINC: - case JCTree.PREDEC: case JCTree.POSTDEC: + case PREINC: case POSTINC: + case PREDEC: case POSTDEC: scanExpr(tree.arg); letInit(tree.arg); break; @@ -1367,7 +1369,7 @@ public class Flow extends TreeScanner { public void visitBinary(JCBinary tree) { switch (tree.getTag()) { - case JCTree.AND: + case AND: scanCond(tree.lhs); Bits initsWhenFalseLeft = initsWhenFalse; Bits uninitsWhenFalseLeft = uninitsWhenFalse; @@ -1377,7 +1379,7 @@ public class Flow extends TreeScanner { initsWhenFalse.andSet(initsWhenFalseLeft); uninitsWhenFalse.andSet(uninitsWhenFalseLeft); break; - case JCTree.OR: + case OR: scanCond(tree.lhs); Bits initsWhenTrueLeft = initsWhenTrue; Bits uninitsWhenTrueLeft = uninitsWhenTrue; @@ -1418,7 +1420,7 @@ public class Flow extends TreeScanner { private boolean is292targetTypeCast(JCTypeCast tree) { boolean is292targetTypeCast = false; JCExpression expr = TreeInfo.skipParens(tree.expr); - if (expr.getTag() == JCTree.APPLY) { + if (expr.hasTag(APPLY)) { JCMethodInvocation apply = (JCMethodInvocation)expr; Symbol sym = TreeInfo.symbol(apply.meth); is292targetTypeCast = sym != null && diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java index cc5ed20727e..00564d9e5f7 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Infer.java @@ -633,13 +633,13 @@ public class Infer { //the polymorphic signature call environment is nested. switch (env.next.tree.getTag()) { - case JCTree.TYPECAST: + case TYPECAST: JCTypeCast castTree = (JCTypeCast)env.next.tree; restype = (TreeInfo.skipParens(castTree.expr) == env.tree) ? castTree.clazz.type : syms.objectType; break; - case JCTree.EXEC: + case EXEC: JCTree.JCExpressionStatement execTree = (JCTree.JCExpressionStatement)env.next.tree; restype = (TreeInfo.skipParens(execTree.expr) == env.tree) ? diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java index 6c687fb7c4d..d4bb9fc8ded 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Lower.java @@ -42,9 +42,11 @@ import com.sun.tools.javac.code.Type.*; import com.sun.tools.javac.jvm.Target; import static com.sun.tools.javac.code.Flags.*; +import static com.sun.tools.javac.code.Flags.BLOCK; import static com.sun.tools.javac.code.Kinds.*; import static com.sun.tools.javac.code.TypeTags.*; import static com.sun.tools.javac.jvm.ByteCodes.*; +import static com.sun.tools.javac.tree.JCTree.Tag.*; /** This pass translates away some syntactic sugar: inner classes, * class literals, assertions, foreach loops, etc. @@ -303,7 +305,7 @@ public class Lower extends TreeTranslator { Symbol constructor = TreeInfo.symbol(tree.meth); ClassSymbol c = (ClassSymbol)constructor.owner; if (c.hasOuterInstance() && - tree.meth.getTag() != JCTree.SELECT && + !tree.meth.hasTag(SELECT) && outerThisStack.head != null) visitSymbol(outerThisStack.head); } @@ -508,7 +510,7 @@ public class Lower extends TreeTranslator { * @param optag The operators tree tag. * @param arg The operator's argument. */ - JCUnary makeUnary(int optag, JCExpression arg) { + JCUnary makeUnary(JCTree.Tag optag, JCExpression arg) { JCUnary tree = make.Unary(optag, arg); tree.operator = rs.resolveUnaryOperator( make_pos, optag, attrEnv, arg.type); @@ -521,7 +523,7 @@ public class Lower extends TreeTranslator { * @param lhs The operator's left argument. * @param rhs The operator's right argument. */ - JCBinary makeBinary(int optag, JCExpression lhs, JCExpression rhs) { + JCBinary makeBinary(JCTree.Tag optag, JCExpression lhs, JCExpression rhs) { JCBinary tree = make.Binary(optag, lhs, rhs); tree.operator = rs.resolveBinaryOperator( make_pos, optag, attrEnv, lhs.type, rhs.type); @@ -534,10 +536,10 @@ public class Lower extends TreeTranslator { * @param lhs The operator's left argument. * @param rhs The operator's right argument. */ - JCAssignOp makeAssignop(int optag, JCTree lhs, JCTree rhs) { + JCAssignOp makeAssignop(JCTree.Tag optag, JCTree lhs, JCTree rhs) { JCAssignOp tree = make.Assignop(optag, lhs, rhs); tree.operator = rs.resolveBinaryOperator( - make_pos, tree.getTag() - JCTree.ASGOffset, attrEnv, lhs.type, rhs.type); + make_pos, tree.getTag().noAssignOp(), attrEnv, lhs.type, rhs.type); tree.type = lhs.type; return tree; } @@ -720,7 +722,7 @@ public class Lower extends TreeTranslator { // where private boolean isTranslatedClassAvailable(ClassSymbol c) { for (JCTree tree: translated) { - if (tree.getTag() == JCTree.CLASSDEF + if (tree.hasTag(CLASSDEF) && ((JCClassDecl) tree).sym == c) { return true; } @@ -802,13 +804,13 @@ public class Lower extends TreeTranslator { private static int accessCode(JCTree tree, JCTree enclOp) { if (enclOp == null) return DEREFcode; - else if (enclOp.getTag() == JCTree.ASSIGN && + else if (enclOp.hasTag(ASSIGN) && tree == TreeInfo.skipParens(((JCAssign) enclOp).lhs)) return ASSIGNcode; - else if (JCTree.PREINC <= enclOp.getTag() && enclOp.getTag() <= JCTree.POSTDEC && + else if (enclOp.getTag().isIncOrDecUnaryOp() && tree == TreeInfo.skipParens(((JCUnary) enclOp).arg)) - return (enclOp.getTag() - JCTree.PREINC) * 2 + PREINCcode; - else if (JCTree.BITOR_ASG <= enclOp.getTag() && enclOp.getTag() <= JCTree.MOD_ASG && + return mapTagToUnaryOpCode(enclOp.getTag()); + else if (enclOp.getTag().isAssignop() && tree == TreeInfo.skipParens(((JCAssignOp) enclOp).lhs)) return accessCode(((OperatorSymbol) ((JCAssignOp) enclOp).operator).opcode); else @@ -832,39 +834,39 @@ public class Lower extends TreeTranslator { /** Return tree tag for assignment operation corresponding * to given binary operator. */ - private static int treeTag(OperatorSymbol operator) { + private static JCTree.Tag treeTag(OperatorSymbol operator) { switch (operator.opcode) { case ByteCodes.ior: case ByteCodes.lor: - return JCTree.BITOR_ASG; + return BITOR_ASG; case ByteCodes.ixor: case ByteCodes.lxor: - return JCTree.BITXOR_ASG; + return BITXOR_ASG; case ByteCodes.iand: case ByteCodes.land: - return JCTree.BITAND_ASG; + return BITAND_ASG; case ByteCodes.ishl: case ByteCodes.lshl: case ByteCodes.ishll: case ByteCodes.lshll: - return JCTree.SL_ASG; + return SL_ASG; case ByteCodes.ishr: case ByteCodes.lshr: case ByteCodes.ishrl: case ByteCodes.lshrl: - return JCTree.SR_ASG; + return SR_ASG; case ByteCodes.iushr: case ByteCodes.lushr: case ByteCodes.iushrl: case ByteCodes.lushrl: - return JCTree.USR_ASG; + return USR_ASG; case ByteCodes.iadd: case ByteCodes.ladd: case ByteCodes.fadd: case ByteCodes.dadd: case ByteCodes.string_add: - return JCTree.PLUS_ASG; + return PLUS_ASG; case ByteCodes.isub: case ByteCodes.lsub: case ByteCodes.fsub: case ByteCodes.dsub: - return JCTree.MINUS_ASG; + return MINUS_ASG; case ByteCodes.imul: case ByteCodes.lmul: case ByteCodes.fmul: case ByteCodes.dmul: - return JCTree.MUL_ASG; + return MUL_ASG; case ByteCodes.idiv: case ByteCodes.ldiv: case ByteCodes.fdiv: case ByteCodes.ddiv: - return JCTree.DIV_ASG; + return DIV_ASG; case ByteCodes.imod: case ByteCodes.lmod: case ByteCodes.fmod: case ByteCodes.dmod: - return JCTree.MOD_ASG; + return MOD_ASG; default: throw new AssertionError(); } @@ -1003,7 +1005,7 @@ public class Lower extends TreeTranslator { if (!currentClass.isSubClass(sym.owner, types)) return true; if ((sym.flags() & STATIC) != 0 || - tree.getTag() != JCTree.SELECT || + !tree.hasTag(SELECT) || TreeInfo.name(((JCFieldAccess) tree).selected) == names._super) return false; return !((JCFieldAccess) tree).selected.type.tsym.isSubClass(currentClass, types); @@ -1018,7 +1020,7 @@ public class Lower extends TreeTranslator { if (protAccess) { Symbol qualifier = null; ClassSymbol c = currentClass; - if (tree.getTag() == JCTree.SELECT && (sym.flags() & STATIC) == 0) { + if (tree.hasTag(SELECT) && (sym.flags() & STATIC) == 0) { qualifier = ((JCFieldAccess) tree).selected.type.tsym; while (!qualifier.isSubClass(c, types)) { c = c.owner.enclClass(); @@ -1058,7 +1060,7 @@ public class Lower extends TreeTranslator { Assert.check(sym != null && (sym.flags_field & FINAL) != 0); tree = make.at(tree.pos).Ident(sym); } - JCExpression base = (tree.getTag() == JCTree.SELECT) ? ((JCFieldAccess) tree).selected : null; + JCExpression base = (tree.hasTag(SELECT)) ? ((JCFieldAccess) tree).selected : null; switch (sym.kind) { case TYP: if (sym.owner.kind != PCK) { @@ -1068,11 +1070,11 @@ public class Lower extends TreeTranslator { while (base != null && TreeInfo.symbol(base) != null && TreeInfo.symbol(base).kind != PCK) { - base = (base.getTag() == JCTree.SELECT) + base = (base.hasTag(SELECT)) ? ((JCFieldAccess) base).selected : null; } - if (tree.getTag() == JCTree.IDENT) { + if (tree.hasTag(IDENT)) { ((JCIdent) tree).name = flatname; } else if (base == null) { tree = make.at(tree.pos).Ident(sym); @@ -1220,6 +1222,42 @@ public class Lower extends TreeTranslator { } } + /** Maps unary operator integer codes to JCTree.Tag objects + * @param unaryOpCode the unary operator code + */ + private static Tag mapUnaryOpCodeToTag(int unaryOpCode){ + switch (unaryOpCode){ + case PREINCcode: + return PREINC; + case PREDECcode: + return PREDEC; + case POSTINCcode: + return POSTINC; + case POSTDECcode: + return POSTDEC; + default: + return NO_TAG; + } + } + + /** Maps JCTree.Tag objects to unary operator integer codes + * @param tag the JCTree.Tag + */ + private static int mapTagToUnaryOpCode(Tag tag){ + switch (tag){ + case PREINC: + return PREINCcode; + case PREDEC: + return PREDECcode; + case POSTINC: + return POSTINCcode; + case POSTDEC: + return POSTDECcode; + default: + return -1; + } + } + /** Construct definition of an access method. * @param pos The source code position of the definition. * @param vsym The private or protected symbol. @@ -1259,8 +1297,7 @@ public class Lower extends TreeTranslator { expr = make.Assign(ref, args.head); break; case PREINCcode: case POSTINCcode: case PREDECcode: case POSTDECcode: - expr = makeUnary( - ((acode1 - PREINCcode) >> 1) + JCTree.PREINC, ref); + expr = makeUnary(mapUnaryOpCodeToTag(acode1), ref); break; default: expr = make.Assignop( @@ -1576,7 +1613,7 @@ public class Lower extends TreeTranslator { } private JCExpression makeNonNullCheck(JCExpression expression) { - return makeBinary(JCTree.NE, expression, makeNull()); + return makeBinary(NE, expression, makeNull()); } /** Construct a tree that represents the outer instance @@ -1808,7 +1845,7 @@ public class Lower extends TreeTranslator { // $newcache.getClass().getComponentType().getClassLoader() : cl$" JCExpression clvalue = make.Conditional( - makeBinary(JCTree.EQ, make.Ident(clsym), makeNull()), + makeBinary(EQ, make.Ident(clsym), makeNull()), make.Assign( make.Ident(clsym), makeCall( @@ -1976,7 +2013,7 @@ public class Lower extends TreeTranslator { writer.xClassName(type).toString().replace('/', '.'); Symbol cs = cacheSym(pos, sig); return make_at(pos).Conditional( - makeBinary(JCTree.EQ, make.Ident(cs), makeNull()), + makeBinary(EQ, make.Ident(cs), makeNull()), make.Assign( make.Ident(cs), make.App( @@ -2023,7 +2060,7 @@ public class Lower extends TreeTranslator { List.nil()); JCClassDecl containerDef = classDef(container); make_at(containerDef.pos()); - JCExpression notStatus = makeUnary(JCTree.NOT, make.App(make.Select( + JCExpression notStatus = makeUnary(NOT, make.App(make.Select( classOfType(types.erasure(outermostClass.type), containerDef.pos()), desiredAssertionStatusSym))); @@ -2032,7 +2069,7 @@ public class Lower extends TreeTranslator { containerDef.defs = containerDef.defs.prepend(assertDisabledDef); } make_at(pos); - return makeUnary(JCTree.NOT, make.Ident(assertDisabledSym)); + return makeUnary(NOT, make.Ident(assertDisabledSym)); } @@ -2062,9 +2099,9 @@ public class Lower extends TreeTranslator { JCTree abstractRval(JCTree rval, Type type, TreeBuilder builder) { rval = TreeInfo.skipParens(rval); switch (rval.getTag()) { - case JCTree.LITERAL: + case LITERAL: return builder.build(rval); - case JCTree.IDENT: + case IDENT: JCIdent id = (JCIdent) rval; if ((id.sym.flags() & FINAL) != 0 && id.sym.owner.kind == MTH) return builder.build(rval); @@ -2097,9 +2134,9 @@ public class Lower extends TreeTranslator { JCTree abstractLval(JCTree lval, final TreeBuilder builder) { lval = TreeInfo.skipParens(lval); switch (lval.getTag()) { - case JCTree.IDENT: + case IDENT: return builder.build(lval); - case JCTree.SELECT: { + case SELECT: { final JCFieldAccess s = (JCFieldAccess)lval; JCTree selected = TreeInfo.skipParens(s.selected); Symbol lid = TreeInfo.symbol(s.selected); @@ -2110,7 +2147,7 @@ public class Lower extends TreeTranslator { } }); } - case JCTree.INDEXED: { + case INDEXED: { final JCArrayAccess i = (JCArrayAccess)lval; return abstractRval(i.indexed, new TreeBuilder() { public JCTree build(final JCTree indexed) { @@ -2125,7 +2162,7 @@ public class Lower extends TreeTranslator { } }); } - case JCTree.TYPECAST: { + case TYPECAST: { return abstractLval(((JCTypeCast)lval).expr, builder); } } @@ -2345,7 +2382,7 @@ public class Lower extends TreeTranslator { for (List defs = tree.defs; defs.nonEmpty(); defs=defs.tail) { - if (defs.head.getTag() == JCTree.VARDEF && (((JCVariableDecl) defs.head).mods.flags & ENUM) != 0) { + if (defs.head.hasTag(VARDEF) && (((JCVariableDecl) defs.head).mods.flags & ENUM) != 0) { JCVariableDecl var = (JCVariableDecl)defs.head; visitEnumConstantDef(var, nextOrdinal++); values.append(make.QualIdent(var.sym)); @@ -2757,9 +2794,9 @@ public class Lower extends TreeTranslator { List.nil() : List.of(translate(tree.detail)); if (!tree.cond.type.isFalse()) { cond = makeBinary - (JCTree.AND, + (AND, cond, - makeUnary(JCTree.NOT, tree.cond)); + makeUnary(NOT, tree.cond)); } result = make.If(cond, @@ -2816,7 +2853,7 @@ public class Lower extends TreeTranslator { // first argument. if (c.hasOuterInstance()) { JCExpression thisArg; - if (tree.meth.getTag() == JCTree.SELECT) { + if (tree.meth.hasTag(SELECT)) { thisArg = attr. makeNullCheck(translate(((JCFieldAccess) tree.meth).selected)); tree.meth = make.Ident(constructor); @@ -2837,7 +2874,7 @@ public class Lower extends TreeTranslator { // If the translated method itself is an Apply tree, we are // seeing an access method invocation. In this case, append // the method arguments to the arguments of the access method. - if (tree.meth.getTag() == JCTree.APPLY) { + if (tree.meth.hasTag(APPLY)) { JCMethodInvocation app = (JCMethodInvocation)tree.meth; app.args = tree.args.prependList(app.args); result = app; @@ -2971,7 +3008,7 @@ public class Lower extends TreeTranslator { // If translated left hand side is an Apply, we are // seeing an access method invocation. In this case, append // right hand side as last argument of the access method. - if (tree.lhs.getTag() == JCTree.APPLY) { + if (tree.lhs.hasTag(APPLY)) { JCMethodInvocation app = (JCMethodInvocation)tree.lhs; app.args = List.of(tree.rhs).prependList(app.args); result = app; @@ -2988,7 +3025,7 @@ public class Lower extends TreeTranslator { // (but without recomputing x) JCTree newTree = abstractLval(tree.lhs, new TreeBuilder() { public JCTree build(final JCTree lhs) { - int newTag = tree.getTag() - JCTree.ASGOffset; + JCTree.Tag newTag = tree.getTag().noAssignOp(); // Erasure (TransTypes) can change the type of // tree.lhs. However, we can still get the // unerased type of tree.lhs as it is stored @@ -3018,7 +3055,7 @@ public class Lower extends TreeTranslator { // If translated left hand side is an Apply, we are // seeing an access method invocation. In this case, append // right hand side as last argument of the access method. - if (tree.lhs.getTag() == JCTree.APPLY) { + if (tree.lhs.hasTag(APPLY)) { JCMethodInvocation app = (JCMethodInvocation)tree.lhs; // if operation is a += on strings, // make sure to convert argument to string @@ -3038,13 +3075,13 @@ public class Lower extends TreeTranslator { // or // translate to tmp1=lval(e); tmp2=tmp1; (typeof tree)tmp1 OP 1; tmp2 // where OP is += or -= - final boolean cast = TreeInfo.skipParens(tree.arg).getTag() == JCTree.TYPECAST; + final boolean cast = TreeInfo.skipParens(tree.arg).hasTag(TYPECAST); return abstractLval(tree.arg, new TreeBuilder() { public JCTree build(final JCTree tmp1) { return abstractRval(tmp1, tree.arg.type, new TreeBuilder() { public JCTree build(final JCTree tmp2) { - int opcode = (tree.getTag() == JCTree.POSTINC) - ? JCTree.PLUS_ASG : JCTree.MINUS_ASG; + JCTree.Tag opcode = (tree.hasTag(POSTINC)) + ? PLUS_ASG : MINUS_ASG; JCTree lhs = cast ? make.TypeCast(tree.arg.type, (JCExpression)tmp1) : tmp1; @@ -3059,25 +3096,24 @@ public class Lower extends TreeTranslator { } public void visitUnary(JCUnary tree) { - boolean isUpdateOperator = - JCTree.PREINC <= tree.getTag() && tree.getTag() <= JCTree.POSTDEC; + boolean isUpdateOperator = tree.getTag().isIncOrDecUnaryOp(); if (isUpdateOperator && !tree.arg.type.isPrimitive()) { switch(tree.getTag()) { - case JCTree.PREINC: // ++ e + case PREINC: // ++ e // translate to e += 1 - case JCTree.PREDEC: // -- e + case PREDEC: // -- e // translate to e -= 1 { - int opcode = (tree.getTag() == JCTree.PREINC) - ? JCTree.PLUS_ASG : JCTree.MINUS_ASG; + JCTree.Tag opcode = (tree.hasTag(PREINC)) + ? PLUS_ASG : MINUS_ASG; JCAssignOp newTree = makeAssignop(opcode, tree.arg, make.Literal(1)); result = translate(newTree, tree.type); return; } - case JCTree.POSTINC: // e ++ - case JCTree.POSTDEC: // e -- + case POSTINC: // e ++ + case POSTDEC: // e -- { result = translate(lowerBoxedPostop(tree), tree.type); return; @@ -3088,14 +3124,14 @@ public class Lower extends TreeTranslator { tree.arg = boxIfNeeded(translate(tree.arg, tree), tree.type); - if (tree.getTag() == JCTree.NOT && tree.arg.type.constValue() != null) { + if (tree.hasTag(NOT) && tree.arg.type.constValue() != null) { tree.type = cfolder.fold1(bool_not, tree.arg.type); } // If translated left hand side is an Apply, we are // seeing an access method invocation. In this case, return // that access method invocation as result. - if (isUpdateOperator && tree.arg.getTag() == JCTree.APPLY) { + if (isUpdateOperator && tree.arg.hasTag(APPLY)) { result = tree.arg; } else { result = tree; @@ -3106,7 +3142,7 @@ public class Lower extends TreeTranslator { List formals = tree.operator.type.getParameterTypes(); JCTree lhs = tree.lhs = translate(tree.lhs, formals.head); switch (tree.getTag()) { - case JCTree.OR: + case OR: if (lhs.type.isTrue()) { result = lhs; return; @@ -3116,7 +3152,7 @@ public class Lower extends TreeTranslator { return; } break; - case JCTree.AND: + case AND: if (lhs.type.isFalse()) { result = lhs; return; @@ -3186,9 +3222,9 @@ public class Lower extends TreeTranslator { indexdef.init.type = indexdef.type = syms.intType.constType(0); List loopinit = List.of(arraycachedef, lencachedef, indexdef); - JCBinary cond = makeBinary(JCTree.LT, make.Ident(index), make.Ident(lencache)); + JCBinary cond = makeBinary(LT, make.Ident(index), make.Ident(lencache)); - JCExpressionStatement step = make.Exec(makeUnary(JCTree.PREINC, make.Ident(index))); + JCExpressionStatement step = make.Exec(makeUnary(PREINC, make.Ident(index))); Type elemtype = types.elemtype(tree.expr.type); JCExpression loopvarinit = make.Indexed(make.Ident(arraycache), @@ -3592,7 +3628,7 @@ public class Lower extends TreeTranslator { // need to special case-access of the form C.super.x // these will always need an access method. boolean qualifiedSuperAccess = - tree.selected.getTag() == JCTree.SELECT && + tree.selected.hasTag(SELECT) && TreeInfo.name(tree.selected) == names._super; tree.selected = translate(tree.selected); if (tree.name == names._class) @@ -3642,7 +3678,7 @@ public class Lower extends TreeTranslator { endPositions = env.toplevel.endPositions; currentClass = null; currentMethodDef = null; - outermostClassDef = (cdef.getTag() == JCTree.CLASSDEF) ? (JCClassDecl)cdef : null; + outermostClassDef = (cdef.hasTag(CLASSDEF)) ? (JCClassDecl)cdef : null; outermostMemberDef = null; this.translated = new ListBuffer(); classdefs = new HashMap(); @@ -3838,7 +3874,7 @@ public class Lower extends TreeTranslator { JCIdent fLocUsageId = make.Ident(otherVarSym); JCExpression sel = make.Select(fLocUsageId, ordinalSymbol); - JCBinary bin = makeBinary(JCTree.MINUS, id1, sel); + JCBinary bin = makeBinary(MINUS, id1, sel); JCReturn ret = make.Return(bin); blockStatements.append(ret); JCMethodDecl compareToMethod = make.MethodDef((MethodSymbol)compareToSym, diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java b/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java index d7583989614..a30c97b9120 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/MemberEnter.java @@ -40,8 +40,10 @@ import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.tree.JCTree.*; import static com.sun.tools.javac.code.Flags.*; +import static com.sun.tools.javac.code.Flags.ANNOTATION; import static com.sun.tools.javac.code.Kinds.*; import static com.sun.tools.javac.code.TypeTags.*; +import static com.sun.tools.javac.tree.JCTree.Tag.*; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; /** This is the second phase of Enter, in which classes are completed @@ -644,7 +646,7 @@ public class MemberEnter extends JCTree.Visitor implements Completer { tree.sym = v; if (tree.init != null) { v.flags_field |= HASINIT; - if ((v.flags_field & FINAL) != 0 && tree.init.getTag() != JCTree.NEWCLASS) { + if ((v.flags_field & FINAL) != 0 && !tree.init.hasTag(NEWCLASS)) { Env initEnv = getInitEnv(tree, env); initEnv.info.enclVar = v; v.setLazyConstValue(initEnv(tree, initEnv), attr, tree.init); @@ -868,7 +870,7 @@ public class MemberEnter extends JCTree.Visitor implements Completer { // If this is a toplevel-class, make sure any preceding import // clauses have been seen. if (c.owner.kind == PCK) { - memberEnter(env.toplevel, env.enclosing(JCTree.TOPLEVEL)); + memberEnter(env.toplevel, env.enclosing(TOPLEVEL)); todo.append(env); } diff --git a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java index 3d6374dbaf1..bb7a5351a9e 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java +++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Resolve.java @@ -49,9 +49,12 @@ import java.util.Set; import javax.lang.model.element.ElementVisitor; import static com.sun.tools.javac.code.Flags.*; +import static com.sun.tools.javac.code.Flags.BLOCK; import static com.sun.tools.javac.code.Kinds.*; +import static com.sun.tools.javac.code.Kinds.ERRONEOUS; import static com.sun.tools.javac.code.TypeTags.*; import static com.sun.tools.javac.comp.Resolve.MethodResolutionPhase.*; +import static com.sun.tools.javac.tree.JCTree.Tag.*; /** Helper class for name resolution, used mostly by the attribution phase. * @@ -1269,7 +1272,7 @@ public class Resolve { staticOnly = true; } - if (env.tree.getTag() != JCTree.IMPORT) { + if (!env.tree.hasTag(IMPORT)) { sym = findGlobalType(env, env.toplevel.namedImportScope, name); if (sym.exists()) return sym; else if (sym.kind < bestSoFar.kind) bestSoFar = sym; @@ -1796,7 +1799,7 @@ public class Resolve { * @param env The environment current at the operation. * @param argtypes The types of the operands. */ - Symbol resolveOperator(DiagnosticPosition pos, int optag, + Symbol resolveOperator(DiagnosticPosition pos, JCTree.Tag optag, Env env, List argtypes) { startResolution(); Name name = treeinfo.operatorName(optag); @@ -1815,7 +1818,7 @@ public class Resolve { * @param env The environment current at the operation. * @param arg The type of the operand. */ - Symbol resolveUnaryOperator(DiagnosticPosition pos, int optag, Env env, Type arg) { + Symbol resolveUnaryOperator(DiagnosticPosition pos, JCTree.Tag optag, Env env, Type arg) { return resolveOperator(pos, optag, env, List.of(arg)); } @@ -1827,7 +1830,7 @@ public class Resolve { * @param right The types of the right operand. */ Symbol resolveBinaryOperator(DiagnosticPosition pos, - int optag, + JCTree.Tag optag, Env env, Type left, Type right) { diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/CRTable.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/CRTable.java index a2c1edc9735..92c02113f25 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/jvm/CRTable.java +++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/CRTable.java @@ -532,7 +532,7 @@ implements CRTFlags { */ public int endPos(JCTree tree) { if (tree == null) return Position.NOPOS; - if (tree.getTag() == JCTree.BLOCK) + if (tree.hasTag(JCTree.Tag.BLOCK)) return ((JCBlock) tree).endpos; Integer endpos = endPositions.get(tree); if (endpos != null) diff --git a/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java b/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java index f1a2a71f2d6..9b745c33305 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java +++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/Gen.java @@ -47,6 +47,8 @@ import static com.sun.tools.javac.code.TypeTags.*; import static com.sun.tools.javac.jvm.ByteCodes.*; import static com.sun.tools.javac.jvm.CRTFlags.*; import static com.sun.tools.javac.main.OptionName.*; +import static com.sun.tools.javac.tree.JCTree.Tag.*; +import static com.sun.tools.javac.tree.JCTree.Tag.BLOCK; /** This pass maps flat Java (i.e. without inner classes) to bytecodes. * @@ -433,7 +435,7 @@ public class Gen extends JCTree.Visitor { */ boolean hasFinally(JCTree target, Env env) { while (env.tree != target) { - if (env.tree.getTag() == JCTree.TRY && env.info.finalize.hasFinalizer()) + if (env.tree.hasTag(TRY) && env.info.finalize.hasFinalizer()) return true; env = env.next; } @@ -460,17 +462,17 @@ public class Gen extends JCTree.Visitor { for (List l = defs; l.nonEmpty(); l = l.tail) { JCTree def = l.head; switch (def.getTag()) { - case JCTree.BLOCK: + case BLOCK: JCBlock block = (JCBlock)def; if ((block.flags & STATIC) != 0) clinitCode.append(block); else initCode.append(block); break; - case JCTree.METHODDEF: + case METHODDEF: methodDefs.append(def); break; - case JCTree.VARDEF: + case VARDEF: JCVariableDecl vdef = (JCVariableDecl) def; VarSymbol sym = vdef.sym; checkDimension(vdef.pos(), sym.type); @@ -707,7 +709,7 @@ public class Gen extends JCTree.Visitor { } int startpc = code.curPc(); genStat(tree, env); - if (tree.getTag() == JCTree.BLOCK) crtFlags |= CRT_BLOCK; + if (tree.hasTag(BLOCK)) crtFlags |= CRT_BLOCK; code.crt.put(tree, crtFlags, startpc, code.curPc()); } @@ -717,7 +719,7 @@ public class Gen extends JCTree.Visitor { if (code.isAlive()) { code.statBegin(tree.pos); genDef(tree, env); - } else if (env.info.isSwitch && tree.getTag() == JCTree.VARDEF) { + } else if (env.info.isSwitch && tree.hasTag(VARDEF)) { // variables whose declarations are in a switch // can be used even if the decl is unreachable. code.newLocal(((JCVariableDecl) tree).sym); @@ -784,7 +786,7 @@ public class Gen extends JCTree.Visitor { */ public CondItem genCond(JCTree _tree, boolean markBranches) { JCTree inner_tree = TreeInfo.skipParens(_tree); - if (inner_tree.getTag() == JCTree.CONDEXPR) { + if (inner_tree.hasTag(CONDEXPR)) { JCConditional tree = (JCConditional)inner_tree; CondItem cond = genCond(tree.cond, CRT_FLOW_CONTROLLER); if (cond.isTrue()) { @@ -1033,7 +1035,7 @@ public class Gen extends JCTree.Visitor { Env localEnv = env.dup(tree, new GenContext()); genStats(tree.stats, localEnv); // End the scope of all block-local variables in variable info. - if (env.tree.getTag() != JCTree.METHODDEF) { + if (!env.tree.hasTag(METHODDEF)) { code.statBegin(tree.endpos); code.endScopes(limit); code.pendingStatPos = Position.NOPOS; @@ -1628,11 +1630,11 @@ public class Gen extends JCTree.Visitor { // Optimize x++ to ++x and x-- to --x. JCExpression e = tree.expr; switch (e.getTag()) { - case JCTree.POSTINC: - ((JCUnary) e).setTag(JCTree.PREINC); + case POSTINC: + ((JCUnary) e).setTag(PREINC); break; - case JCTree.POSTDEC: - ((JCUnary) e).setTag(JCTree.PREDEC); + case POSTDEC: + ((JCUnary) e).setTag(PREDEC); break; } genExpr(tree.expr, tree.expr.type).drop(); @@ -1819,13 +1821,13 @@ public class Gen extends JCTree.Visitor { // If we have an increment of -32768 to +32767 of a local // int variable we can use an incr instruction instead of // proceeding further. - if ((tree.getTag() == JCTree.PLUS_ASG || tree.getTag() == JCTree.MINUS_ASG) && + if ((tree.hasTag(PLUS_ASG) || tree.hasTag(MINUS_ASG)) && l instanceof LocalItem && tree.lhs.type.tag <= INT && tree.rhs.type.tag <= INT && tree.rhs.type.constValue() != null) { int ival = ((Number) tree.rhs.type.constValue()).intValue(); - if (tree.getTag() == JCTree.MINUS_ASG) ival = -ival; + if (tree.hasTag(MINUS_ASG)) ival = -ival; ((LocalItem)l).incr(ival); result = l; return; @@ -1841,29 +1843,29 @@ public class Gen extends JCTree.Visitor { public void visitUnary(JCUnary tree) { OperatorSymbol operator = (OperatorSymbol)tree.operator; - if (tree.getTag() == JCTree.NOT) { + if (tree.hasTag(NOT)) { CondItem od = genCond(tree.arg, false); result = od.negate(); } else { Item od = genExpr(tree.arg, operator.type.getParameterTypes().head); switch (tree.getTag()) { - case JCTree.POS: + case POS: result = od.load(); break; - case JCTree.NEG: + case NEG: result = od.load(); code.emitop0(operator.opcode); break; - case JCTree.COMPL: + case COMPL: result = od.load(); emitMinusOne(od.typecode); code.emitop0(operator.opcode); break; - case JCTree.PREINC: case JCTree.PREDEC: + case PREINC: case PREDEC: od.duplicate(); if (od instanceof LocalItem && (operator.opcode == iadd || operator.opcode == isub)) { - ((LocalItem)od).incr(tree.getTag() == JCTree.PREINC ? 1 : -1); + ((LocalItem)od).incr(tree.hasTag(PREINC) ? 1 : -1); result = od; } else { od.load(); @@ -1877,12 +1879,12 @@ public class Gen extends JCTree.Visitor { result = items.makeAssignItem(od); } break; - case JCTree.POSTINC: case JCTree.POSTDEC: + case POSTINC: case POSTDEC: od.duplicate(); if (od instanceof LocalItem && (operator.opcode == iadd || operator.opcode == isub)) { Item res = od.load(); - ((LocalItem)od).incr(tree.getTag() == JCTree.POSTINC ? 1 : -1); + ((LocalItem)od).incr(tree.hasTag(POSTINC) ? 1 : -1); result = res; } else { Item res = od.load(); @@ -1898,7 +1900,7 @@ public class Gen extends JCTree.Visitor { result = res; } break; - case JCTree.NULLCHK: + case NULLCHK: result = od.load(); code.emitop0(dup); genNullCheck(tree.pos()); @@ -1926,7 +1928,7 @@ public class Gen extends JCTree.Visitor { // Convert buffer to string. bufferToString(tree.pos()); result = items.makeStackItem(syms.stringType); - } else if (tree.getTag() == JCTree.AND) { + } else if (tree.hasTag(AND)) { CondItem lcond = genCond(tree.lhs, CRT_FLOW_CONTROLLER); if (!lcond.isFalse()) { Chain falseJumps = lcond.jumpFalse(); @@ -1940,7 +1942,7 @@ public class Gen extends JCTree.Visitor { } else { result = lcond; } - } else if (tree.getTag() == JCTree.OR) { + } else if (tree.hasTag(OR)) { CondItem lcond = genCond(tree.lhs, CRT_FLOW_CONTROLLER); if (!lcond.isTrue()) { Chain trueJumps = lcond.jumpTrue(); @@ -1997,7 +1999,7 @@ public class Gen extends JCTree.Visitor { */ void appendStrings(JCTree tree) { tree = TreeInfo.skipParens(tree); - if (tree.getTag() == JCTree.PLUS && tree.type.constValue() == null) { + if (tree.hasTag(PLUS) && tree.type.constValue() == null) { JCBinary op = (JCBinary) tree; if (op.operator.kind == MTH && ((OperatorSymbol) op.operator).opcode == string_add) { @@ -2240,7 +2242,7 @@ public class Gen extends JCTree.Visitor { if (nerrs != 0) { // if errors, discard code for (List l = cdef.defs; l.nonEmpty(); l = l.tail) { - if (l.head.getTag() == JCTree.METHODDEF) + if (l.head.hasTag(METHODDEF)) ((JCMethodDecl) l.head).sym.code = null; } } diff --git a/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java b/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java index a1190b08909..232419d0231 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java +++ b/langtools/src/share/classes/com/sun/tools/javac/main/JavaCompiler.java @@ -1506,20 +1506,20 @@ public class JavaCompiler implements ClassReader.SourceCompleter { for (List it = tree.defs; it.tail != null; it = it.tail) { JCTree t = it.head; switch (t.getTag()) { - case JCTree.CLASSDEF: + case CLASSDEF: if (isInterface || (((JCClassDecl) t).mods.flags & (Flags.PROTECTED|Flags.PUBLIC)) != 0 || (((JCClassDecl) t).mods.flags & (Flags.PRIVATE)) == 0 && ((JCClassDecl) t).sym.packge().getQualifiedName() == names.java_lang) newdefs.append(t); break; - case JCTree.METHODDEF: + case METHODDEF: if (isInterface || (((JCMethodDecl) t).mods.flags & (Flags.PROTECTED|Flags.PUBLIC)) != 0 || ((JCMethodDecl) t).sym.name == names.init || (((JCMethodDecl) t).mods.flags & (Flags.PRIVATE)) == 0 && ((JCMethodDecl) t).sym.packge().getQualifiedName() == names.java_lang) newdefs.append(t); break; - case JCTree.VARDEF: + case VARDEF: if (isInterface || (((JCVariableDecl) t).mods.flags & (Flags.PROTECTED|Flags.PUBLIC)) != 0 || (((JCVariableDecl) t).mods.flags & (Flags.PRIVATE)) == 0 && ((JCVariableDecl) t).sym.packge().getQualifiedName() == names.java_lang) newdefs.append(t); diff --git a/langtools/src/share/classes/com/sun/tools/javac/model/JavacElements.java b/langtools/src/share/classes/com/sun/tools/javac/model/JavacElements.java index c00a3728d4a..cb9c1650863 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/model/JavacElements.java +++ b/langtools/src/share/classes/com/sun/tools/javac/model/JavacElements.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2011, 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 @@ -48,6 +48,7 @@ import com.sun.tools.javac.tree.TreeScanner; import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.Name; +import static com.sun.tools.javac.tree.JCTree.Tag.*; import static javax.lang.model.util.ElementFilter.methodsIn; /** @@ -288,7 +289,7 @@ public class JavacElements implements Elements { } } public void visitArray(Attribute.Array array) { - if (tree.getTag() == JCTree.NEWARRAY && + if (tree.hasTag(NEWARRAY) && types.elemtype(array.type).tsym == findme.type.tsym) { List elems = ((JCNewArray) tree).elems; for (Attribute value : array.values) { @@ -327,7 +328,7 @@ public class JavacElements implements Elements { scan(t.args); } public void visitAssign(JCAssign t) { - if (t.lhs.getTag() == JCTree.IDENT) { + if (t.lhs.hasTag(IDENT)) { JCIdent ident = (JCIdent) t.lhs; if (ident.sym == sym) result = t.rhs; diff --git a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java index 841a30de493..bbec01c8e7e 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -37,8 +37,16 @@ import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.List; -import static com.sun.tools.javac.util.ListBuffer.lb; import static com.sun.tools.javac.parser.Tokens.TokenKind.*; +import static com.sun.tools.javac.parser.Tokens.TokenKind.ASSERT; +import static com.sun.tools.javac.parser.Tokens.TokenKind.CASE; +import static com.sun.tools.javac.parser.Tokens.TokenKind.CATCH; +import static com.sun.tools.javac.parser.Tokens.TokenKind.EQ; +import static com.sun.tools.javac.parser.Tokens.TokenKind.GT; +import static com.sun.tools.javac.parser.Tokens.TokenKind.IMPORT; +import static com.sun.tools.javac.parser.Tokens.TokenKind.LT; +import static com.sun.tools.javac.util.ListBuffer.lb; +import static com.sun.tools.javac.tree.JCTree.Tag.*; /** The parser maps a token sequence into an abstract syntax * tree. It operates by recursive descent, with code derived @@ -758,7 +766,7 @@ public class JavacParser implements Parser { Assert.check(top == 0); t = odStack[0]; - if (t.getTag() == JCTree.PLUS) { + if (t.hasTag(JCTree.Tag.PLUS)) { StringBuffer buf = foldStrings(t); if (buf != null) { t = toP(F.at(startPos).Literal(TypeTags.CLASS, buf.toString())); @@ -791,7 +799,7 @@ public class JavacParser implements Parser { return null; List buf = List.nil(); while (true) { - if (tree.getTag() == JCTree.LITERAL) { + if (tree.hasTag(LITERAL)) { JCLiteral lit = (JCLiteral) tree; if (lit.typetag == TypeTags.CLASS) { StringBuffer sbuf = @@ -802,9 +810,9 @@ public class JavacParser implements Parser { } return sbuf; } - } else if (tree.getTag() == JCTree.PLUS) { + } else if (tree.hasTag(JCTree.Tag.PLUS)) { JCBinary op = (JCBinary)tree; - if (op.rhs.getTag() == JCTree.LITERAL) { + if (op.rhs.hasTag(LITERAL)) { JCLiteral lit = (JCLiteral) op.rhs; if (lit.typetag == TypeTags.CLASS) { buf = buf.prepend((String) lit.value); @@ -900,7 +908,7 @@ public class JavacParser implements Parser { t = term3(); if ((mode & TYPE) != 0 && token.kind == LT) { // Could be a cast to a parameterized type - int op = JCTree.LT; + JCTree.Tag op = JCTree.Tag.LT; int pos1 = token.pos; nextToken(); mode &= (EXPR | TYPE); @@ -1154,7 +1162,7 @@ public class JavacParser implements Parser { while ((token.kind == PLUSPLUS || token.kind == SUBSUB) && (mode & EXPR) != 0) { mode = EXPR; t = to(F.at(token.pos).Unary( - token.kind == PLUSPLUS ? JCTree.POSTINC : JCTree.POSTDEC, t)); + token.kind == PLUSPLUS ? POSTINC : POSTDEC, t)); nextToken(); } return toP(t); @@ -1627,7 +1635,7 @@ public class JavacParser implements Parser { default: Token prevToken = token; JCExpression t = term(EXPR | TYPE); - if (token.kind == COLON && t.getTag() == JCTree.IDENT) { + if (token.kind == COLON && t.hasTag(IDENT)) { nextToken(); JCStatement stat = parseStatement(); stats.append(F.at(pos).Labelled(prevToken.name(), stat)); @@ -1702,7 +1710,7 @@ public class JavacParser implements Parser { accept(LPAREN); List inits = token.kind == SEMI ? List.nil() : forInit(); if (inits.length() == 1 && - inits.head.getTag() == JCTree.VARDEF && + inits.head.hasTag(VARDEF) && ((JCVariableDecl) inits.head).init == null && token.kind == COLON) { checkForeach(); @@ -1835,7 +1843,7 @@ public class JavacParser implements Parser { default: Token prevToken = token; JCExpression expr = parseExpression(); - if (token.kind == COLON && expr.getTag() == JCTree.IDENT) { + if (token.kind == COLON && expr.hasTag(IDENT)) { nextToken(); JCStatement stat = parseStatement(); return F.at(pos).Labelled(prevToken.name(), stat); @@ -2088,7 +2096,7 @@ public class JavacParser implements Parser { if (token.kind == IDENTIFIER) { mode = EXPR; JCExpression t1 = term1(); - if (t1.getTag() == JCTree.IDENT && token.kind == EQ) { + if (t1.hasTag(IDENT) && token.kind == EQ) { int pos = token.pos; accept(EQ); JCExpression v = annotationValue(); @@ -2618,7 +2626,7 @@ public class JavacParser implements Parser { } else { type = parseType(); } - if (token.kind == LPAREN && !isInterface && type.getTag() == JCTree.IDENT) { + if (token.kind == LPAREN && !isInterface && type.hasTag(IDENT)) { if (isInterface || tk.name() != className) error(pos, "invalid.meth.decl.ret.type.req"); return List.of(methodDeclaratorRest( @@ -2815,15 +2823,15 @@ public class JavacParser implements Parser { */ protected JCExpression checkExprStat(JCExpression t) { switch(t.getTag()) { - case JCTree.PREINC: case JCTree.PREDEC: - case JCTree.POSTINC: case JCTree.POSTDEC: - case JCTree.ASSIGN: - case JCTree.BITOR_ASG: case JCTree.BITXOR_ASG: case JCTree.BITAND_ASG: - case JCTree.SL_ASG: case JCTree.SR_ASG: case JCTree.USR_ASG: - case JCTree.PLUS_ASG: case JCTree.MINUS_ASG: - case JCTree.MUL_ASG: case JCTree.DIV_ASG: case JCTree.MOD_ASG: - case JCTree.APPLY: case JCTree.NEWCLASS: - case JCTree.ERRONEOUS: + case PREINC: case PREDEC: + case POSTINC: case POSTDEC: + case ASSIGN: + case BITOR_ASG: case BITXOR_ASG: case BITAND_ASG: + case SL_ASG: case SR_ASG: case USR_ASG: + case PLUS_ASG: case MINUS_ASG: + case MUL_ASG: case DIV_ASG: case MOD_ASG: + case APPLY: case NEWCLASS: + case ERRONEOUS: return t; default: JCExpression ret = F.at(t.pos).Erroneous(List.of(t)); @@ -2836,8 +2844,8 @@ public class JavacParser implements Parser { * -1 if token is not a binary operator. @see TreeInfo.opPrec */ static int prec(TokenKind token) { - int oc = optag(token); - return (oc >= 0) ? TreeInfo.opPrec(oc) : -1; + JCTree.Tag oc = optag(token); + return (oc != NO_TAG) ? TreeInfo.opPrec(oc) : -1; } /** @@ -2853,96 +2861,96 @@ public class JavacParser implements Parser { } /** Return operation tag of binary operator represented by token, - * -1 if token is not a binary operator. + * No_TAG if token is not a binary operator. */ - static int optag(TokenKind token) { + static JCTree.Tag optag(TokenKind token) { switch (token) { case BARBAR: - return JCTree.OR; + return OR; case AMPAMP: - return JCTree.AND; + return AND; case BAR: - return JCTree.BITOR; + return BITOR; case BAREQ: - return JCTree.BITOR_ASG; + return BITOR_ASG; case CARET: - return JCTree.BITXOR; + return BITXOR; case CARETEQ: - return JCTree.BITXOR_ASG; + return BITXOR_ASG; case AMP: - return JCTree.BITAND; + return BITAND; case AMPEQ: - return JCTree.BITAND_ASG; + return BITAND_ASG; case EQEQ: - return JCTree.EQ; + return JCTree.Tag.EQ; case BANGEQ: - return JCTree.NE; + return NE; case LT: - return JCTree.LT; + return JCTree.Tag.LT; case GT: - return JCTree.GT; + return JCTree.Tag.GT; case LTEQ: - return JCTree.LE; + return LE; case GTEQ: - return JCTree.GE; + return GE; case LTLT: - return JCTree.SL; + return SL; case LTLTEQ: - return JCTree.SL_ASG; + return SL_ASG; case GTGT: - return JCTree.SR; + return SR; case GTGTEQ: - return JCTree.SR_ASG; + return SR_ASG; case GTGTGT: - return JCTree.USR; + return USR; case GTGTGTEQ: - return JCTree.USR_ASG; + return USR_ASG; case PLUS: - return JCTree.PLUS; + return JCTree.Tag.PLUS; case PLUSEQ: - return JCTree.PLUS_ASG; + return PLUS_ASG; case SUB: - return JCTree.MINUS; + return MINUS; case SUBEQ: - return JCTree.MINUS_ASG; + return MINUS_ASG; case STAR: - return JCTree.MUL; + return MUL; case STAREQ: - return JCTree.MUL_ASG; + return MUL_ASG; case SLASH: - return JCTree.DIV; + return DIV; case SLASHEQ: - return JCTree.DIV_ASG; + return DIV_ASG; case PERCENT: - return JCTree.MOD; + return MOD; case PERCENTEQ: - return JCTree.MOD_ASG; + return MOD_ASG; case INSTANCEOF: - return JCTree.TYPETEST; + return TYPETEST; default: - return -1; + return NO_TAG; } } /** Return operation tag of unary operator represented by token, - * -1 if token is not a binary operator. + * No_TAG if token is not a binary operator. */ - static int unoptag(TokenKind token) { + static JCTree.Tag unoptag(TokenKind token) { switch (token) { case PLUS: - return JCTree.POS; + return POS; case SUB: - return JCTree.NEG; + return NEG; case BANG: - return JCTree.NOT; + return NOT; case TILDE: - return JCTree.COMPL; + return COMPL; case PLUSPLUS: - return JCTree.PREINC; + return PREINC; case SUBSUB: - return JCTree.PREDEC; + return PREDEC; default: - return -1; + return NO_TAG; } } diff --git a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java index ce16646eea1..e4d9de27afb 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java +++ b/langtools/src/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java @@ -1222,7 +1222,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea List classes = List.nil(); for (JCCompilationUnit unit : units) { for (JCTree node : unit.defs) { - if (node.getTag() == JCTree.CLASSDEF) { + if (node.hasTag(JCTree.Tag.CLASSDEF)) { ClassSymbol sym = ((JCClassDecl) node).sym; Assert.checkNonNull(sym); classes = classes.prepend(sym); diff --git a/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java b/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java index 564e63cd30e..c23a4df458e 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java +++ b/langtools/src/share/classes/com/sun/tools/javac/tree/JCTree.java @@ -42,6 +42,7 @@ import com.sun.tools.javac.code.Symbol.*; import com.sun.source.tree.*; import static com.sun.tools.javac.code.BoundKind.*; +import static com.sun.tools.javac.tree.JCTree.Tag.*; /** * Root class for abstract syntax tree nodes. It provides definitions @@ -79,253 +80,289 @@ import static com.sun.tools.javac.code.BoundKind.*; public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { /* Tree tag values, identifying kinds of trees */ + public enum Tag{ + /** For methods that return an invalid tag if a given condition is not met + */ + NO_TAG, - /** Toplevel nodes, of type TopLevel, representing entire source files. - */ - public static final int TOPLEVEL = 1; + /** Toplevel nodes, of type TopLevel, representing entire source files. + */ + TOPLEVEL, - /** Import clauses, of type Import. - */ - public static final int IMPORT = TOPLEVEL + 1; + /** Import clauses, of type Import. + */ + IMPORT, - /** Class definitions, of type ClassDef. - */ - public static final int CLASSDEF = IMPORT + 1; + /** Class definitions, of type ClassDef. + */ + CLASSDEF, - /** Method definitions, of type MethodDef. - */ - public static final int METHODDEF = CLASSDEF + 1; + /** Method definitions, of type MethodDef. + */ + METHODDEF, - /** Variable definitions, of type VarDef. - */ - public static final int VARDEF = METHODDEF + 1; + /** Variable definitions, of type VarDef. + */ + VARDEF, - /** The no-op statement ";", of type Skip - */ - public static final int SKIP = VARDEF + 1; + /** The no-op statement ";", of type Skip + */ + SKIP, - /** Blocks, of type Block. - */ - public static final int BLOCK = SKIP + 1; + /** Blocks, of type Block. + */ + BLOCK, - /** Do-while loops, of type DoLoop. - */ - public static final int DOLOOP = BLOCK + 1; + /** Do-while loops, of type DoLoop. + */ + DOLOOP, - /** While-loops, of type WhileLoop. - */ - public static final int WHILELOOP = DOLOOP + 1; + /** While-loops, of type WhileLoop. + */ + WHILELOOP, - /** For-loops, of type ForLoop. - */ - public static final int FORLOOP = WHILELOOP + 1; + /** For-loops, of type ForLoop. + */ + FORLOOP, - /** Foreach-loops, of type ForeachLoop. - */ - public static final int FOREACHLOOP = FORLOOP + 1; + /** Foreach-loops, of type ForeachLoop. + */ + FOREACHLOOP, - /** Labelled statements, of type Labelled. - */ - public static final int LABELLED = FOREACHLOOP + 1; + /** Labelled statements, of type Labelled. + */ + LABELLED, - /** Switch statements, of type Switch. - */ - public static final int SWITCH = LABELLED + 1; + /** Switch statements, of type Switch. + */ + SWITCH, - /** Case parts in switch statements, of type Case. - */ - public static final int CASE = SWITCH + 1; + /** Case parts in switch statements, of type Case. + */ + CASE, - /** Synchronized statements, of type Synchonized. - */ - public static final int SYNCHRONIZED = CASE + 1; + /** Synchronized statements, of type Synchonized. + */ + SYNCHRONIZED, - /** Try statements, of type Try. - */ - public static final int TRY = SYNCHRONIZED + 1; + /** Try statements, of type Try. + */ + TRY, - /** Catch clauses in try statements, of type Catch. - */ - public static final int CATCH = TRY + 1; + /** Catch clauses in try statements, of type Catch. + */ + CATCH, - /** Conditional expressions, of type Conditional. - */ - public static final int CONDEXPR = CATCH + 1; + /** Conditional expressions, of type Conditional. + */ + CONDEXPR, - /** Conditional statements, of type If. - */ - public static final int IF = CONDEXPR + 1; + /** Conditional statements, of type If. + */ + IF, - /** Expression statements, of type Exec. - */ - public static final int EXEC = IF + 1; + /** Expression statements, of type Exec. + */ + EXEC, - /** Break statements, of type Break. - */ - public static final int BREAK = EXEC + 1; + /** Break statements, of type Break. + */ + BREAK, - /** Continue statements, of type Continue. - */ - public static final int CONTINUE = BREAK + 1; + /** Continue statements, of type Continue. + */ + CONTINUE, - /** Return statements, of type Return. - */ - public static final int RETURN = CONTINUE + 1; + /** Return statements, of type Return. + */ + RETURN, - /** Throw statements, of type Throw. - */ - public static final int THROW = RETURN + 1; + /** Throw statements, of type Throw. + */ + THROW, - /** Assert statements, of type Assert. - */ - public static final int ASSERT = THROW + 1; + /** Assert statements, of type Assert. + */ + ASSERT, - /** Method invocation expressions, of type Apply. - */ - public static final int APPLY = ASSERT + 1; + /** Method invocation expressions, of type Apply. + */ + APPLY, - /** Class instance creation expressions, of type NewClass. - */ - public static final int NEWCLASS = APPLY + 1; + /** Class instance creation expressions, of type NewClass. + */ + NEWCLASS, - /** Array creation expressions, of type NewArray. - */ - public static final int NEWARRAY = NEWCLASS + 1; + /** Array creation expressions, of type NewArray. + */ + NEWARRAY, - /** Parenthesized subexpressions, of type Parens. - */ - public static final int PARENS = NEWARRAY + 1; + /** Parenthesized subexpressions, of type Parens. + */ + PARENS, - /** Assignment expressions, of type Assign. - */ - public static final int ASSIGN = PARENS + 1; + /** Assignment expressions, of type Assign. + */ + ASSIGN, - /** Type cast expressions, of type TypeCast. - */ - public static final int TYPECAST = ASSIGN + 1; + /** Type cast expressions, of type TypeCast. + */ + TYPECAST, - /** Type test expressions, of type TypeTest. - */ - public static final int TYPETEST = TYPECAST + 1; + /** Type test expressions, of type TypeTest. + */ + TYPETEST, - /** Indexed array expressions, of type Indexed. - */ - public static final int INDEXED = TYPETEST + 1; + /** Indexed array expressions, of type Indexed. + */ + INDEXED, - /** Selections, of type Select. - */ - public static final int SELECT = INDEXED + 1; + /** Selections, of type Select. + */ + SELECT, - /** Simple identifiers, of type Ident. - */ - public static final int IDENT = SELECT + 1; + /** Simple identifiers, of type Ident. + */ + IDENT, - /** Literals, of type Literal. - */ - public static final int LITERAL = IDENT + 1; + /** Literals, of type Literal. + */ + LITERAL, - /** Basic type identifiers, of type TypeIdent. - */ - public static final int TYPEIDENT = LITERAL + 1; + /** Basic type identifiers, of type TypeIdent. + */ + TYPEIDENT, - /** Array types, of type TypeArray. - */ - public static final int TYPEARRAY = TYPEIDENT + 1; + /** Array types, of type TypeArray. + */ + TYPEARRAY, - /** Parameterized types, of type TypeApply. - */ - public static final int TYPEAPPLY = TYPEARRAY + 1; + /** Parameterized types, of type TypeApply. + */ + TYPEAPPLY, - /** Union types, of type TypeUnion - */ - public static final int TYPEUNION = TYPEAPPLY + 1; + /** Union types, of type TypeUnion + */ + TYPEUNION, - /** Formal type parameters, of type TypeParameter. - */ - public static final int TYPEPARAMETER = TYPEUNION + 1; + /** Formal type parameters, of type TypeParameter. + */ + TYPEPARAMETER, - /** Type argument. - */ - public static final int WILDCARD = TYPEPARAMETER + 1; + /** Type argument. + */ + WILDCARD, - /** Bound kind: extends, super, exact, or unbound - */ - public static final int TYPEBOUNDKIND = WILDCARD + 1; + /** Bound kind: extends, super, exact, or unbound + */ + TYPEBOUNDKIND, - /** metadata: Annotation. - */ - public static final int ANNOTATION = TYPEBOUNDKIND + 1; + /** metadata: Annotation. + */ + ANNOTATION, - /** metadata: Modifiers - */ - public static final int MODIFIERS = ANNOTATION + 1; + /** metadata: Modifiers + */ + MODIFIERS, - public static final int ANNOTATED_TYPE = MODIFIERS + 1; + ANNOTATED_TYPE, - /** Error trees, of type Erroneous. - */ - public static final int ERRONEOUS = ANNOTATED_TYPE + 1; + /** Error trees, of type Erroneous. + */ + ERRONEOUS, - /** Unary operators, of type Unary. - */ - public static final int POS = ERRONEOUS + 1; // + - public static final int NEG = POS + 1; // - - public static final int NOT = NEG + 1; // ! - public static final int COMPL = NOT + 1; // ~ - public static final int PREINC = COMPL + 1; // ++ _ - public static final int PREDEC = PREINC + 1; // -- _ - public static final int POSTINC = PREDEC + 1; // _ ++ - public static final int POSTDEC = POSTINC + 1; // _ -- + /** Unary operators, of type Unary. + */ + POS, // + + NEG, // - + NOT, // ! + COMPL, // ~ + PREINC, // ++ _ + PREDEC, // -- _ + POSTINC, // _ ++ + POSTDEC, // _ -- - /** unary operator for null reference checks, only used internally. - */ - public static final int NULLCHK = POSTDEC + 1; + /** unary operator for null reference checks, only used internally. + */ + NULLCHK, - /** Binary operators, of type Binary. - */ - public static final int OR = NULLCHK + 1; // || - public static final int AND = OR + 1; // && - public static final int BITOR = AND + 1; // | - public static final int BITXOR = BITOR + 1; // ^ - public static final int BITAND = BITXOR + 1; // & - public static final int EQ = BITAND + 1; // == - public static final int NE = EQ + 1; // != - public static final int LT = NE + 1; // < - public static final int GT = LT + 1; // > - public static final int LE = GT + 1; // <= - public static final int GE = LE + 1; // >= - public static final int SL = GE + 1; // << - public static final int SR = SL + 1; // >> - public static final int USR = SR + 1; // >>> - public static final int PLUS = USR + 1; // + - public static final int MINUS = PLUS + 1; // - - public static final int MUL = MINUS + 1; // * - public static final int DIV = MUL + 1; // / - public static final int MOD = DIV + 1; // % + /** Binary operators, of type Binary. + */ + OR, // || + AND, // && + BITOR, // | + BITXOR, // ^ + BITAND, // & + EQ, // == + NE, // != + LT, // < + GT, // > + LE, // <= + GE, // >= + SL, // << + SR, // >> + USR, // >>> + PLUS, // + + MINUS, // - + MUL, // * + DIV, // / + MOD, // % - /** Assignment operators, of type Assignop. - */ - public static final int BITOR_ASG = MOD + 1; // |= - public static final int BITXOR_ASG = BITOR_ASG + 1; // ^= - public static final int BITAND_ASG = BITXOR_ASG + 1; // &= + /** Assignment operators, of type Assignop. + */ + BITOR_ASG(BITOR), // |= + BITXOR_ASG(BITXOR), // ^= + BITAND_ASG(BITAND), // &= - public static final int SL_ASG = SL + BITOR_ASG - BITOR; // <<= - public static final int SR_ASG = SL_ASG + 1; // >>= - public static final int USR_ASG = SR_ASG + 1; // >>>= - public static final int PLUS_ASG = USR_ASG + 1; // += - public static final int MINUS_ASG = PLUS_ASG + 1; // -= - public static final int MUL_ASG = MINUS_ASG + 1; // *= - public static final int DIV_ASG = MUL_ASG + 1; // /= - public static final int MOD_ASG = DIV_ASG + 1; // %= + SL_ASG(SL), // <<= + SR_ASG(SR), // >>= + USR_ASG(USR), // >>>= + PLUS_ASG(PLUS), // += + MINUS_ASG(MINUS), // -= + MUL_ASG(MUL), // *= + DIV_ASG(DIV), // /= + MOD_ASG(MOD), // %= - /** A synthetic let expression, of type LetExpr. - */ - public static final int LETEXPR = MOD_ASG + 1; // ala scheme + /** A synthetic let expression, of type LetExpr. + */ + LETEXPR; // ala scheme + private Tag noAssignTag; - /** The offset between assignment operators and normal operators. - */ - public static final int ASGOffset = BITOR_ASG - BITOR; + private static int numberOfOperators = MOD.ordinal() - POS.ordinal() + 1; + + private Tag(Tag noAssignTag) { + this.noAssignTag = noAssignTag; + } + + private Tag() { } + + public static int getNumberOfOperators() { + return numberOfOperators; + } + + public Tag noAssignOp() { + if (noAssignTag != null) + return noAssignTag; + throw new AssertionError("noAssignOp() method is not available for non assignment tags"); + } + + public boolean isPostUnaryOp() { + return (this == POSTINC || this == POSTDEC); + } + + public boolean isIncOrDecUnaryOp() { + return (this == PREINC || this == PREDEC || this == POSTINC || this == POSTDEC); + } + + public boolean isAssignop() { + return noAssignTag != null; + } + + public int operatorIndex() { + return (this.ordinal() - POS.ordinal()); + } + } /* The (encoded) position in the source file. @see util.Position. */ @@ -337,7 +374,13 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { /* The tag of this node -- one of the constants declared above. */ - public abstract int getTag(); + public abstract Tag getTag(); + + /* Returns true if the tag of this node is equals to tag. + */ + public boolean hasTag(Tag tag) { + return tag == getTag(); + } /** Convert a tree to a pretty-printed string. */ @Override @@ -464,10 +507,9 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { public List getImports() { ListBuffer imports = new ListBuffer(); for (JCTree tree : defs) { - int tag = tree.getTag(); - if (tag == IMPORT) + if (tree.hasTag(IMPORT)) imports.append((JCImport)tree); - else if (tag != SKIP) + else if (!tree.hasTag(SKIP)) break; } return imports.toList(); @@ -482,7 +524,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { public List getTypeDecls() { List typeDefs; for (typeDefs = defs; !typeDefs.isEmpty(); typeDefs = typeDefs.tail) - if (typeDefs.head.getTag() != IMPORT) + if (!typeDefs.head.hasTag(IMPORT)) break; return typeDefs; } @@ -492,7 +534,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { } @Override - public int getTag() { + public Tag getTag() { return TOPLEVEL; } } @@ -521,7 +563,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { } @Override - public int getTag() { + public Tag getTag() { return IMPORT; } } @@ -618,7 +660,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { } @Override - public int getTag() { + public Tag getTag() { return CLASSDEF; } } @@ -690,7 +732,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { } @Override - public int getTag() { + public Tag getTag() { return METHODDEF; } } @@ -736,7 +778,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { } @Override - public int getTag() { + public Tag getTag() { return VARDEF; } } @@ -757,7 +799,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { } @Override - public int getTag() { + public Tag getTag() { return SKIP; } } @@ -790,7 +832,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { } @Override - public int getTag() { + public Tag getTag() { return BLOCK; } } @@ -817,7 +859,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { } @Override - public int getTag() { + public Tag getTag() { return DOLOOP; } } @@ -844,7 +886,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { } @Override - public int getTag() { + public Tag getTag() { return WHILELOOP; } } @@ -885,7 +927,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { } @Override - public int getTag() { + public Tag getTag() { return FORLOOP; } } @@ -914,7 +956,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitEnhancedForLoop(this, d); } @Override - public int getTag() { + public Tag getTag() { return FOREACHLOOP; } } @@ -939,7 +981,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitLabeledStatement(this, d); } @Override - public int getTag() { + public Tag getTag() { return LABELLED; } } @@ -965,7 +1007,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitSwitch(this, d); } @Override - public int getTag() { + public Tag getTag() { return SWITCH; } } @@ -991,7 +1033,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitCase(this, d); } @Override - public int getTag() { + public Tag getTag() { return CASE; } } @@ -1017,7 +1059,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitSynchronized(this, d); } @Override - public int getTag() { + public Tag getTag() { return SYNCHRONIZED; } } @@ -1057,7 +1099,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return resources; } @Override - public int getTag() { + public Tag getTag() { return TRY; } } @@ -1083,7 +1125,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitCatch(this, d); } @Override - public int getTag() { + public Tag getTag() { return CATCH; } } @@ -1115,7 +1157,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitConditionalExpression(this, d); } @Override - public int getTag() { + public Tag getTag() { return CONDEXPR; } } @@ -1147,7 +1189,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitIf(this, d); } @Override - public int getTag() { + public Tag getTag() { return IF; } } @@ -1172,7 +1214,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitExpressionStatement(this, d); } @Override - public int getTag() { + public Tag getTag() { return EXEC; } @@ -1212,7 +1254,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitBreak(this, d); } @Override - public int getTag() { + public Tag getTag() { return BREAK; } } @@ -1237,7 +1279,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitContinue(this, d); } @Override - public int getTag() { + public Tag getTag() { return CONTINUE; } } @@ -1260,7 +1302,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitReturn(this, d); } @Override - public int getTag() { + public Tag getTag() { return RETURN; } } @@ -1283,7 +1325,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitThrow(this, d); } @Override - public int getTag() { + public Tag getTag() { return THROW; } } @@ -1309,7 +1351,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitAssert(this, d); } @Override - public int getTag() { + public Tag getTag() { return ASSERT; } } @@ -1352,7 +1394,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return this; } @Override - public int getTag() { + public Tag getTag() { return(APPLY); } } @@ -1402,7 +1444,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitNewClass(this, d); } @Override - public int getTag() { + public Tag getTag() { return NEWCLASS; } } @@ -1438,7 +1480,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitNewArray(this, d); } @Override - public int getTag() { + public Tag getTag() { return NEWARRAY; } } @@ -1461,7 +1503,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitParenthesized(this, d); } @Override - public int getTag() { + public Tag getTag() { return PARENS; } } @@ -1487,7 +1529,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitAssignment(this, d); } @Override - public int getTag() { + public Tag getTag() { return ASSIGN; } } @@ -1496,11 +1538,11 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { * An assignment with "+=", "|=" ... */ public static class JCAssignOp extends JCExpression implements CompoundAssignmentTree { - private int opcode; + private Tag opcode; public JCExpression lhs; public JCExpression rhs; public Symbol operator; - protected JCAssignOp(int opcode, JCTree lhs, JCTree rhs, Symbol operator) { + protected JCAssignOp(Tag opcode, JCTree lhs, JCTree rhs, Symbol operator) { this.opcode = opcode; this.lhs = (JCExpression)lhs; this.rhs = (JCExpression)rhs; @@ -1520,7 +1562,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitCompoundAssignment(this, d); } @Override - public int getTag() { + public Tag getTag() { return opcode; } } @@ -1529,10 +1571,10 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { * A unary operation. */ public static class JCUnary extends JCExpression implements UnaryTree { - private int opcode; + private Tag opcode; public JCExpression arg; public Symbol operator; - protected JCUnary(int opcode, JCExpression arg) { + protected JCUnary(Tag opcode, JCExpression arg) { this.opcode = opcode; this.arg = arg; } @@ -1549,11 +1591,11 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitUnary(this, d); } @Override - public int getTag() { + public Tag getTag() { return opcode; } - public void setTag(int tag) { + public void setTag(Tag tag) { opcode = tag; } } @@ -1562,11 +1604,11 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { * A binary operation. */ public static class JCBinary extends JCExpression implements BinaryTree { - private int opcode; + private Tag opcode; public JCExpression lhs; public JCExpression rhs; public Symbol operator; - protected JCBinary(int opcode, + protected JCBinary(Tag opcode, JCExpression lhs, JCExpression rhs, Symbol operator) { @@ -1589,7 +1631,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitBinary(this, d); } @Override - public int getTag() { + public Tag getTag() { return opcode; } } @@ -1615,7 +1657,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitTypeCast(this, d); } @Override - public int getTag() { + public Tag getTag() { return TYPECAST; } } @@ -1641,7 +1683,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitInstanceOf(this, d); } @Override - public int getTag() { + public Tag getTag() { return TYPETEST; } } @@ -1667,7 +1709,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitArrayAccess(this, d); } @Override - public int getTag() { + public Tag getTag() { return INDEXED; } } @@ -1698,7 +1740,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { } public Name getIdentifier() { return name; } @Override - public int getTag() { + public Tag getTag() { return SELECT; } } @@ -1724,7 +1766,8 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { public R accept(TreeVisitor v, D d) { return v.visitIdentifier(this, d); } - public int getTag() { + @Override + public Tag getTag() { return IDENT; } } @@ -1790,7 +1833,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return this; } @Override - public int getTag() { + public Tag getTag() { return LITERAL; } } @@ -1838,7 +1881,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitPrimitiveType(this, d); } @Override - public int getTag() { + public Tag getTag() { return TYPEIDENT; } } @@ -1861,7 +1904,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitArrayType(this, d); } @Override - public int getTag() { + public Tag getTag() { return TYPEARRAY; } } @@ -1889,7 +1932,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitParameterizedType(this, d); } @Override - public int getTag() { + public Tag getTag() { return TYPEAPPLY; } } @@ -1917,7 +1960,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitUnionType(this, d); } @Override - public int getTag() { + public Tag getTag() { return TYPEUNION; } } @@ -1947,7 +1990,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitTypeParameter(this, d); } @Override - public int getTag() { + public Tag getTag() { return TYPEPARAMETER; } } @@ -1981,7 +2024,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitWildcard(this, d); } @Override - public int getTag() { + public Tag getTag() { return WILDCARD; } } @@ -2002,7 +2045,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { throw new AssertionError("TypeBoundKind is not part of a public API"); } @Override - public int getTag() { + public Tag getTag() { return TYPEBOUNDKIND; } } @@ -2027,7 +2070,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitAnnotation(this, d); } @Override - public int getTag() { + public Tag getTag() { return ANNOTATION; } } @@ -2054,7 +2097,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitModifiers(this, d); } @Override - public int getTag() { + public Tag getTag() { return MODIFIERS; } } @@ -2079,7 +2122,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { return v.visitErroneous(this, d); } @Override - public int getTag() { + public Tag getTag() { return ERRONEOUS; } } @@ -2103,7 +2146,7 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { throw new AssertionError("LetExpr is not part of a public API"); } @Override - public int getTag() { + public Tag getTag() { return LETEXPR; } } @@ -2175,9 +2218,9 @@ public abstract class JCTree implements Tree, Cloneable, DiagnosticPosition { List elems); JCParens Parens(JCExpression expr); JCAssign Assign(JCExpression lhs, JCExpression rhs); - JCAssignOp Assignop(int opcode, JCTree lhs, JCTree rhs); - JCUnary Unary(int opcode, JCExpression arg); - JCBinary Binary(int opcode, JCExpression lhs, JCExpression rhs); + JCAssignOp Assignop(Tag opcode, JCTree lhs, JCTree rhs); + JCUnary Unary(Tag opcode, JCExpression arg); + JCBinary Binary(Tag opcode, JCExpression lhs, JCExpression rhs); JCTypeCast TypeCast(JCTree expr, JCExpression type); JCInstanceOf TypeTest(JCExpression expr, JCTree clazz); JCArrayAccess Indexed(JCExpression indexed, JCExpression index); diff --git a/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java b/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java index a332cdeb0f8..e781fd130e6 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java +++ b/langtools/src/share/classes/com/sun/tools/javac/tree/Pretty.java @@ -36,6 +36,8 @@ import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.tree.JCTree.*; import static com.sun.tools.javac.code.Flags.*; +import static com.sun.tools.javac.code.Flags.ANNOTATION; +import static com.sun.tools.javac.tree.JCTree.Tag.*; /** Prints out a tree as an indented Java source program. * @@ -310,7 +312,7 @@ public class Pretty extends JCTree.Visitor { /** Is the given tree an enumerator definition? */ boolean isEnumerator(JCTree t) { - return t.getTag() == JCTree.VARDEF && (((JCVariableDecl) t).mods.flags & ENUM) != 0; + return t.hasTag(VARDEF) && (((JCVariableDecl) t).mods.flags & ENUM) != 0; } /** Print unit consisting of package clause and import statements in toplevel, @@ -331,9 +333,9 @@ public class Pretty extends JCTree.Visitor { } boolean firstImport = true; for (List l = tree.defs; - l.nonEmpty() && (cdef == null || l.head.getTag() == JCTree.IMPORT); + l.nonEmpty() && (cdef == null || l.head.hasTag(IMPORT)); l = l.tail) { - if (l.head.getTag() == JCTree.IMPORT) { + if (l.head.hasTag(IMPORT)) { JCImport imp = (JCImport)l.head; Name name = TreeInfo.name(imp.qualid); if (name == name.table.names.asterisk || @@ -484,7 +486,7 @@ public class Pretty extends JCTree.Visitor { print("/*public static final*/ "); print(tree.name); if (tree.init != null) { - if (sourceOutput && tree.init.getTag() == JCTree.NEWCLASS) { + if (sourceOutput && tree.init.hasTag(NEWCLASS)) { print(" /*enum*/ "); JCNewClass init = (JCNewClass) tree.init; if (init.args != null && init.args.nonEmpty()) { @@ -545,7 +547,7 @@ public class Pretty extends JCTree.Visitor { printStat(tree.body); align(); print(" while "); - if (tree.cond.getTag() == JCTree.PARENS) { + if (tree.cond.hasTag(PARENS)) { printExpr(tree.cond); } else { print("("); @@ -561,7 +563,7 @@ public class Pretty extends JCTree.Visitor { public void visitWhileLoop(JCWhileLoop tree) { try { print("while "); - if (tree.cond.getTag() == JCTree.PARENS) { + if (tree.cond.hasTag(PARENS)) { printExpr(tree.cond); } else { print("("); @@ -579,7 +581,7 @@ public class Pretty extends JCTree.Visitor { try { print("for ("); if (tree.init.nonEmpty()) { - if (tree.init.head.getTag() == JCTree.VARDEF) { + if (tree.init.head.hasTag(VARDEF)) { printExpr(tree.init.head); for (List l = tree.init.tail; l.nonEmpty(); l = l.tail) { JCVariableDecl vdef = (JCVariableDecl)l.head; @@ -626,7 +628,7 @@ public class Pretty extends JCTree.Visitor { public void visitSwitch(JCSwitch tree) { try { print("switch "); - if (tree.selector.getTag() == JCTree.PARENS) { + if (tree.selector.hasTag(PARENS)) { printExpr(tree.selector); } else { print("("); @@ -665,7 +667,7 @@ public class Pretty extends JCTree.Visitor { public void visitSynchronized(JCSynchronized tree) { try { print("synchronized "); - if (tree.lock.getTag() == JCTree.PARENS) { + if (tree.lock.hasTag(PARENS)) { printExpr(tree.lock); } else { print("("); @@ -736,7 +738,7 @@ public class Pretty extends JCTree.Visitor { public void visitIf(JCIf tree) { try { print("if "); - if (tree.cond.getTag() == JCTree.PARENS) { + if (tree.cond.hasTag(PARENS)) { printExpr(tree.cond); } else { print("("); @@ -823,7 +825,7 @@ public class Pretty extends JCTree.Visitor { public void visitApply(JCMethodInvocation tree) { try { if (!tree.typeargs.isEmpty()) { - if (tree.meth.getTag() == JCTree.SELECT) { + if (tree.meth.hasTag(SELECT)) { JCFieldAccess left = (JCFieldAccess)tree.meth; printExpr(left.selected); print(".<"); @@ -882,7 +884,7 @@ public class Pretty extends JCTree.Visitor { if (tree.elemtype != null) { print("new "); JCTree elem = tree.elemtype; - if (elem.getTag() == JCTree.TYPEARRAY) + if (elem.hasTag(TYPEARRAY)) printBaseElementType((JCArrayTypeTree) elem); else printExpr(elem); @@ -927,36 +929,36 @@ public class Pretty extends JCTree.Visitor { } } - public String operatorName(int tag) { + public String operatorName(JCTree.Tag tag) { switch(tag) { - case JCTree.POS: return "+"; - case JCTree.NEG: return "-"; - case JCTree.NOT: return "!"; - case JCTree.COMPL: return "~"; - case JCTree.PREINC: return "++"; - case JCTree.PREDEC: return "--"; - case JCTree.POSTINC: return "++"; - case JCTree.POSTDEC: return "--"; - case JCTree.NULLCHK: return "<*nullchk*>"; - case JCTree.OR: return "||"; - case JCTree.AND: return "&&"; - case JCTree.EQ: return "=="; - case JCTree.NE: return "!="; - case JCTree.LT: return "<"; - case JCTree.GT: return ">"; - case JCTree.LE: return "<="; - case JCTree.GE: return ">="; - case JCTree.BITOR: return "|"; - case JCTree.BITXOR: return "^"; - case JCTree.BITAND: return "&"; - case JCTree.SL: return "<<"; - case JCTree.SR: return ">>"; - case JCTree.USR: return ">>>"; - case JCTree.PLUS: return "+"; - case JCTree.MINUS: return "-"; - case JCTree.MUL: return "*"; - case JCTree.DIV: return "/"; - case JCTree.MOD: return "%"; + case POS: return "+"; + case NEG: return "-"; + case NOT: return "!"; + case COMPL: return "~"; + case PREINC: return "++"; + case PREDEC: return "--"; + case POSTINC: return "++"; + case POSTDEC: return "--"; + case NULLCHK: return "<*nullchk*>"; + case OR: return "||"; + case AND: return "&&"; + case EQ: return "=="; + case NE: return "!="; + case LT: return "<"; + case GT: return ">"; + case LE: return "<="; + case GE: return ">="; + case BITOR: return "|"; + case BITXOR: return "^"; + case BITAND: return "&"; + case SL: return "<<"; + case SR: return ">>"; + case USR: return ">>>"; + case PLUS: return "+"; + case MINUS: return "-"; + case MUL: return "*"; + case DIV: return "/"; + case MOD: return "%"; default: throw new Error(); } } @@ -965,7 +967,7 @@ public class Pretty extends JCTree.Visitor { try { open(prec, TreeInfo.assignopPrec); printExpr(tree.lhs, TreeInfo.assignopPrec + 1); - print(" " + operatorName(tree.getTag() - JCTree.ASGOffset) + "= "); + print(" " + operatorName(tree.getTag().noAssignOp()) + "= "); printExpr(tree.rhs, TreeInfo.assignopPrec); close(prec, TreeInfo.assignopPrec); } catch (IOException e) { @@ -978,7 +980,7 @@ public class Pretty extends JCTree.Visitor { int ownprec = TreeInfo.opPrec(tree.getTag()); String opname = operatorName(tree.getTag()); open(prec, ownprec); - if (tree.getTag() <= JCTree.PREDEC) { + if (!tree.getTag().isPostUnaryOp()) { print(opname); printExpr(tree.arg, ownprec); } else { @@ -1153,7 +1155,7 @@ public class Pretty extends JCTree.Visitor { while (true) { elem = tree.elemtype; print("[]"); - if (elem.getTag() != JCTree.TYPEARRAY) break; + if (!elem.hasTag(TYPEARRAY)) break; tree = (JCArrayTypeTree) elem; } } diff --git a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java index 4b96be6d98a..158abc4f161 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java +++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeCopier.java @@ -406,7 +406,7 @@ public class TreeCopier

implements TreeVisitor { public JCTree visitOther(Tree node, P p) { JCTree tree = (JCTree) node; switch (tree.getTag()) { - case JCTree.LETEXPR: { + case LETEXPR: { LetExpr t = (LetExpr) node; List defs = copy(t.defs, p); JCTree expr = copy(t.expr, p); diff --git a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java index c37a561990c..0a9aa02bc54 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java +++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeInfo.java @@ -35,6 +35,9 @@ import com.sun.tools.javac.code.*; import com.sun.tools.javac.tree.JCTree.*; import static com.sun.tools.javac.code.Flags.*; +import static com.sun.tools.javac.tree.JCTree.Tag.*; +import static com.sun.tools.javac.tree.JCTree.Tag.BLOCK; +import static com.sun.tools.javac.tree.JCTree.Tag.SYNCHRONIZED; /** Utility class containing inspector methods for trees. * @@ -56,53 +59,60 @@ public class TreeInfo { /** The names of all operators. */ - private Name[] opname = new Name[JCTree.MOD - JCTree.POS + 1]; + private Name[] opname = new Name[Tag.getNumberOfOperators()]; + + private void setOpname(Tag tag, String name, Names names) { + setOpname(tag, names.fromString(name)); + } + private void setOpname(Tag tag, Name name) { + opname[tag.operatorIndex()] = name; + } private TreeInfo(Context context) { context.put(treeInfoKey, this); Names names = Names.instance(context); - opname[JCTree.POS - JCTree.POS] = names.fromString("+"); - opname[JCTree.NEG - JCTree.POS] = names.hyphen; - opname[JCTree.NOT - JCTree.POS] = names.fromString("!"); - opname[JCTree.COMPL - JCTree.POS] = names.fromString("~"); - opname[JCTree.PREINC - JCTree.POS] = names.fromString("++"); - opname[JCTree.PREDEC - JCTree.POS] = names.fromString("--"); - opname[JCTree.POSTINC - JCTree.POS] = names.fromString("++"); - opname[JCTree.POSTDEC - JCTree.POS] = names.fromString("--"); - opname[JCTree.NULLCHK - JCTree.POS] = names.fromString("<*nullchk*>"); - opname[JCTree.OR - JCTree.POS] = names.fromString("||"); - opname[JCTree.AND - JCTree.POS] = names.fromString("&&"); - opname[JCTree.EQ - JCTree.POS] = names.fromString("=="); - opname[JCTree.NE - JCTree.POS] = names.fromString("!="); - opname[JCTree.LT - JCTree.POS] = names.fromString("<"); - opname[JCTree.GT - JCTree.POS] = names.fromString(">"); - opname[JCTree.LE - JCTree.POS] = names.fromString("<="); - opname[JCTree.GE - JCTree.POS] = names.fromString(">="); - opname[JCTree.BITOR - JCTree.POS] = names.fromString("|"); - opname[JCTree.BITXOR - JCTree.POS] = names.fromString("^"); - opname[JCTree.BITAND - JCTree.POS] = names.fromString("&"); - opname[JCTree.SL - JCTree.POS] = names.fromString("<<"); - opname[JCTree.SR - JCTree.POS] = names.fromString(">>"); - opname[JCTree.USR - JCTree.POS] = names.fromString(">>>"); - opname[JCTree.PLUS - JCTree.POS] = names.fromString("+"); - opname[JCTree.MINUS - JCTree.POS] = names.hyphen; - opname[JCTree.MUL - JCTree.POS] = names.asterisk; - opname[JCTree.DIV - JCTree.POS] = names.slash; - opname[JCTree.MOD - JCTree.POS] = names.fromString("%"); + setOpname(POS, "+", names); + setOpname(NEG, names.hyphen); + setOpname(NOT, "!", names); + setOpname(COMPL, "~", names); + setOpname(PREINC, "++", names); + setOpname(PREDEC, "--", names); + setOpname(POSTINC, "++", names); + setOpname(POSTDEC, "--", names); + setOpname(NULLCHK, "<*nullchk*>", names); + setOpname(OR, "||", names); + setOpname(AND, "&&", names); + setOpname(EQ, "==", names); + setOpname(NE, "!=", names); + setOpname(LT, "<", names); + setOpname(GT, ">", names); + setOpname(LE, "<=", names); + setOpname(GE, ">=", names); + setOpname(BITOR, "|", names); + setOpname(BITXOR, "^", names); + setOpname(BITAND, "&", names); + setOpname(SL, "<<", names); + setOpname(SR, ">>", names); + setOpname(USR, ">>>", names); + setOpname(PLUS, "+", names); + setOpname(MINUS, names.hyphen); + setOpname(MUL, names.asterisk); + setOpname(DIV, names.slash); + setOpname(MOD, "%", names); } /** Return name of operator with given tree tag. */ - public Name operatorName(int tag) { - return opname[tag - JCTree.POS]; + public Name operatorName(JCTree.Tag tag) { + return opname[tag.operatorIndex()]; } /** Is tree a constructor declaration? */ public static boolean isConstructor(JCTree tree) { - if (tree.getTag() == JCTree.METHODDEF) { + if (tree.hasTag(METHODDEF)) { Name name = ((JCMethodDecl) tree).name; return name == name.table.names.init; } else { @@ -119,17 +129,17 @@ public class TreeInfo { } public static boolean isMultiCatch(JCCatch catchClause) { - return catchClause.param.vartype.getTag() == JCTree.TYPEUNION; + return catchClause.param.vartype.hasTag(TYPEUNION); } /** Is statement an initializer for a synthetic field? */ public static boolean isSyntheticInit(JCTree stat) { - if (stat.getTag() == JCTree.EXEC) { + if (stat.hasTag(EXEC)) { JCExpressionStatement exec = (JCExpressionStatement)stat; - if (exec.expr.getTag() == JCTree.ASSIGN) { + if (exec.expr.hasTag(ASSIGN)) { JCAssign assign = (JCAssign)exec.expr; - if (assign.lhs.getTag() == JCTree.SELECT) { + if (assign.lhs.hasTag(SELECT)) { JCFieldAccess select = (JCFieldAccess)assign.lhs; if (select.sym != null && (select.sym.flags() & SYNTHETIC) != 0) { @@ -146,9 +156,9 @@ public class TreeInfo { /** If the expression is a method call, return the method name, null * otherwise. */ public static Name calledMethodName(JCTree tree) { - if (tree.getTag() == JCTree.EXEC) { + if (tree.hasTag(EXEC)) { JCExpressionStatement exec = (JCExpressionStatement)tree; - if (exec.expr.getTag() == JCTree.APPLY) { + if (exec.expr.hasTag(APPLY)) { Name mname = TreeInfo.name(((JCMethodInvocation) exec.expr).meth); return mname; } @@ -192,7 +202,7 @@ public class TreeInfo { /** Return the first call in a constructor definition. */ public static JCMethodInvocation firstConstructorCall(JCTree tree) { - if (tree.getTag() != JCTree.METHODDEF) return null; + if (!tree.hasTag(METHODDEF)) return null; JCMethodDecl md = (JCMethodDecl) tree; Names names = md.name.table.names; if (md.name != names.init) return null; @@ -202,24 +212,24 @@ public class TreeInfo { while (stats.nonEmpty() && isSyntheticInit(stats.head)) stats = stats.tail; if (stats.isEmpty()) return null; - if (stats.head.getTag() != JCTree.EXEC) return null; + if (!stats.head.hasTag(EXEC)) return null; JCExpressionStatement exec = (JCExpressionStatement) stats.head; - if (exec.expr.getTag() != JCTree.APPLY) return null; + if (!exec.expr.hasTag(APPLY)) return null; return (JCMethodInvocation)exec.expr; } /** Return true if a tree represents a diamond new expr. */ public static boolean isDiamond(JCTree tree) { switch(tree.getTag()) { - case JCTree.TYPEAPPLY: return ((JCTypeApply)tree).getTypeArguments().isEmpty(); - case JCTree.NEWCLASS: return isDiamond(((JCNewClass)tree).clazz); + case TYPEAPPLY: return ((JCTypeApply)tree).getTypeArguments().isEmpty(); + case NEWCLASS: return isDiamond(((JCNewClass)tree).clazz); default: return false; } } /** Return true if a tree represents the null literal. */ public static boolean isNull(JCTree tree) { - if (tree.getTag() != JCTree.LITERAL) + if (!tree.hasTag(LITERAL)) return false; JCLiteral lit = (JCLiteral) tree; return (lit.typetag == TypeTags.BOT); @@ -229,7 +239,7 @@ public class TreeInfo { * the block itself if it is empty. */ public static int firstStatPos(JCTree tree) { - if (tree.getTag() == JCTree.BLOCK && ((JCBlock) tree).stats.nonEmpty()) + if (tree.hasTag(BLOCK) && ((JCBlock) tree).stats.nonEmpty()) return ((JCBlock) tree).stats.head.pos; else return tree.pos; @@ -239,11 +249,11 @@ public class TreeInfo { * defined endpos. */ public static int endPos(JCTree tree) { - if (tree.getTag() == JCTree.BLOCK && ((JCBlock) tree).endpos != Position.NOPOS) + if (tree.hasTag(BLOCK) && ((JCBlock) tree).endpos != Position.NOPOS) return ((JCBlock) tree).endpos; - else if (tree.getTag() == JCTree.SYNCHRONIZED) + else if (tree.hasTag(SYNCHRONIZED)) return endPos(((JCSynchronized) tree).body); - else if (tree.getTag() == JCTree.TRY) { + else if (tree.hasTag(TRY)) { JCTry t = (JCTry) tree; return endPos((t.finalizer != null) ? t.finalizer @@ -263,73 +273,73 @@ public class TreeInfo { return Position.NOPOS; switch(tree.getTag()) { - case(JCTree.APPLY): - return getStartPos(((JCMethodInvocation) tree).meth); - case(JCTree.ASSIGN): - return getStartPos(((JCAssign) tree).lhs); - case(JCTree.BITOR_ASG): case(JCTree.BITXOR_ASG): case(JCTree.BITAND_ASG): - case(JCTree.SL_ASG): case(JCTree.SR_ASG): case(JCTree.USR_ASG): - case(JCTree.PLUS_ASG): case(JCTree.MINUS_ASG): case(JCTree.MUL_ASG): - case(JCTree.DIV_ASG): case(JCTree.MOD_ASG): - return getStartPos(((JCAssignOp) tree).lhs); - case(JCTree.OR): case(JCTree.AND): case(JCTree.BITOR): - case(JCTree.BITXOR): case(JCTree.BITAND): case(JCTree.EQ): - case(JCTree.NE): case(JCTree.LT): case(JCTree.GT): - case(JCTree.LE): case(JCTree.GE): case(JCTree.SL): - case(JCTree.SR): case(JCTree.USR): case(JCTree.PLUS): - case(JCTree.MINUS): case(JCTree.MUL): case(JCTree.DIV): - case(JCTree.MOD): - return getStartPos(((JCBinary) tree).lhs); - case(JCTree.CLASSDEF): { - JCClassDecl node = (JCClassDecl)tree; - if (node.mods.pos != Position.NOPOS) - return node.mods.pos; - break; - } - case(JCTree.CONDEXPR): - return getStartPos(((JCConditional) tree).cond); - case(JCTree.EXEC): - return getStartPos(((JCExpressionStatement) tree).expr); - case(JCTree.INDEXED): - return getStartPos(((JCArrayAccess) tree).indexed); - case(JCTree.METHODDEF): { - JCMethodDecl node = (JCMethodDecl)tree; - if (node.mods.pos != Position.NOPOS) - return node.mods.pos; - if (node.typarams.nonEmpty()) // List.nil() used for no typarams - return getStartPos(node.typarams.head); - return node.restype == null ? node.pos : getStartPos(node.restype); - } - case(JCTree.SELECT): - return getStartPos(((JCFieldAccess) tree).selected); - case(JCTree.TYPEAPPLY): - return getStartPos(((JCTypeApply) tree).clazz); - case(JCTree.TYPEARRAY): - return getStartPos(((JCArrayTypeTree) tree).elemtype); - case(JCTree.TYPETEST): - return getStartPos(((JCInstanceOf) tree).expr); - case(JCTree.POSTINC): - case(JCTree.POSTDEC): - return getStartPos(((JCUnary) tree).arg); - case(JCTree.NEWCLASS): { - JCNewClass node = (JCNewClass)tree; - if (node.encl != null) - return getStartPos(node.encl); - break; - } - case(JCTree.VARDEF): { - JCVariableDecl node = (JCVariableDecl)tree; - if (node.mods.pos != Position.NOPOS) { - return node.mods.pos; - } else { - return getStartPos(node.vartype); + case APPLY: + return getStartPos(((JCMethodInvocation) tree).meth); + case ASSIGN: + return getStartPos(((JCAssign) tree).lhs); + case BITOR_ASG: case BITXOR_ASG: case BITAND_ASG: + case SL_ASG: case SR_ASG: case USR_ASG: + case PLUS_ASG: case MINUS_ASG: case MUL_ASG: + case DIV_ASG: case MOD_ASG: + return getStartPos(((JCAssignOp) tree).lhs); + case OR: case AND: case BITOR: + case BITXOR: case BITAND: case EQ: + case NE: case LT: case GT: + case LE: case GE: case SL: + case SR: case USR: case PLUS: + case MINUS: case MUL: case DIV: + case MOD: + return getStartPos(((JCBinary) tree).lhs); + case CLASSDEF: { + JCClassDecl node = (JCClassDecl)tree; + if (node.mods.pos != Position.NOPOS) + return node.mods.pos; + break; + } + case CONDEXPR: + return getStartPos(((JCConditional) tree).cond); + case EXEC: + return getStartPos(((JCExpressionStatement) tree).expr); + case INDEXED: + return getStartPos(((JCArrayAccess) tree).indexed); + case METHODDEF: { + JCMethodDecl node = (JCMethodDecl)tree; + if (node.mods.pos != Position.NOPOS) + return node.mods.pos; + if (node.typarams.nonEmpty()) // List.nil() used for no typarams + return getStartPos(node.typarams.head); + return node.restype == null ? node.pos : getStartPos(node.restype); + } + case SELECT: + return getStartPos(((JCFieldAccess) tree).selected); + case TYPEAPPLY: + return getStartPos(((JCTypeApply) tree).clazz); + case TYPEARRAY: + return getStartPos(((JCArrayTypeTree) tree).elemtype); + case TYPETEST: + return getStartPos(((JCInstanceOf) tree).expr); + case POSTINC: + case POSTDEC: + return getStartPos(((JCUnary) tree).arg); + case NEWCLASS: { + JCNewClass node = (JCNewClass)tree; + if (node.encl != null) + return getStartPos(node.encl); + break; + } + case VARDEF: { + JCVariableDecl node = (JCVariableDecl)tree; + if (node.mods.pos != Position.NOPOS) { + return node.mods.pos; + } else { + return getStartPos(node.vartype); + } + } + case ERRONEOUS: { + JCErroneous node = (JCErroneous)tree; + if (node.errs != null && node.errs.nonEmpty()) + return getStartPos(node.errs.head); } - } - case(JCTree.ERRONEOUS): { - JCErroneous node = (JCErroneous)tree; - if (node.errs != null && node.errs.nonEmpty()) - return getStartPos(node.errs.head); - } } return tree.pos; } @@ -350,75 +360,75 @@ public class TreeInfo { return mapPos; switch(tree.getTag()) { - case(JCTree.BITOR_ASG): case(JCTree.BITXOR_ASG): case(JCTree.BITAND_ASG): - case(JCTree.SL_ASG): case(JCTree.SR_ASG): case(JCTree.USR_ASG): - case(JCTree.PLUS_ASG): case(JCTree.MINUS_ASG): case(JCTree.MUL_ASG): - case(JCTree.DIV_ASG): case(JCTree.MOD_ASG): - return getEndPos(((JCAssignOp) tree).rhs, endPositions); - case(JCTree.OR): case(JCTree.AND): case(JCTree.BITOR): - case(JCTree.BITXOR): case(JCTree.BITAND): case(JCTree.EQ): - case(JCTree.NE): case(JCTree.LT): case(JCTree.GT): - case(JCTree.LE): case(JCTree.GE): case(JCTree.SL): - case(JCTree.SR): case(JCTree.USR): case(JCTree.PLUS): - case(JCTree.MINUS): case(JCTree.MUL): case(JCTree.DIV): - case(JCTree.MOD): - return getEndPos(((JCBinary) tree).rhs, endPositions); - case(JCTree.CASE): - return getEndPos(((JCCase) tree).stats.last(), endPositions); - case(JCTree.CATCH): - return getEndPos(((JCCatch) tree).body, endPositions); - case(JCTree.CONDEXPR): - return getEndPos(((JCConditional) tree).falsepart, endPositions); - case(JCTree.FORLOOP): - return getEndPos(((JCForLoop) tree).body, endPositions); - case(JCTree.FOREACHLOOP): - return getEndPos(((JCEnhancedForLoop) tree).body, endPositions); - case(JCTree.IF): { - JCIf node = (JCIf)tree; - if (node.elsepart == null) { - return getEndPos(node.thenpart, endPositions); - } else { - return getEndPos(node.elsepart, endPositions); + case BITOR_ASG: case BITXOR_ASG: case BITAND_ASG: + case SL_ASG: case SR_ASG: case USR_ASG: + case PLUS_ASG: case MINUS_ASG: case MUL_ASG: + case DIV_ASG: case MOD_ASG: + return getEndPos(((JCAssignOp) tree).rhs, endPositions); + case OR: case AND: case BITOR: + case BITXOR: case BITAND: case EQ: + case NE: case LT: case GT: + case LE: case GE: case SL: + case SR: case USR: case PLUS: + case MINUS: case MUL: case DIV: + case MOD: + return getEndPos(((JCBinary) tree).rhs, endPositions); + case CASE: + return getEndPos(((JCCase) tree).stats.last(), endPositions); + case CATCH: + return getEndPos(((JCCatch) tree).body, endPositions); + case CONDEXPR: + return getEndPos(((JCConditional) tree).falsepart, endPositions); + case FORLOOP: + return getEndPos(((JCForLoop) tree).body, endPositions); + case FOREACHLOOP: + return getEndPos(((JCEnhancedForLoop) tree).body, endPositions); + case IF: { + JCIf node = (JCIf)tree; + if (node.elsepart == null) { + return getEndPos(node.thenpart, endPositions); + } else { + return getEndPos(node.elsepart, endPositions); + } } - } - case(JCTree.LABELLED): - return getEndPos(((JCLabeledStatement) tree).body, endPositions); - case(JCTree.MODIFIERS): - return getEndPos(((JCModifiers) tree).annotations.last(), endPositions); - case(JCTree.SYNCHRONIZED): - return getEndPos(((JCSynchronized) tree).body, endPositions); - case(JCTree.TOPLEVEL): - return getEndPos(((JCCompilationUnit) tree).defs.last(), endPositions); - case(JCTree.TRY): { - JCTry node = (JCTry)tree; - if (node.finalizer != null) { - return getEndPos(node.finalizer, endPositions); - } else if (!node.catchers.isEmpty()) { - return getEndPos(node.catchers.last(), endPositions); - } else { - return getEndPos(node.body, endPositions); + case LABELLED: + return getEndPos(((JCLabeledStatement) tree).body, endPositions); + case MODIFIERS: + return getEndPos(((JCModifiers) tree).annotations.last(), endPositions); + case SYNCHRONIZED: + return getEndPos(((JCSynchronized) tree).body, endPositions); + case TOPLEVEL: + return getEndPos(((JCCompilationUnit) tree).defs.last(), endPositions); + case TRY: { + JCTry node = (JCTry)tree; + if (node.finalizer != null) { + return getEndPos(node.finalizer, endPositions); + } else if (!node.catchers.isEmpty()) { + return getEndPos(node.catchers.last(), endPositions); + } else { + return getEndPos(node.body, endPositions); + } + } + case WILDCARD: + return getEndPos(((JCWildcard) tree).inner, endPositions); + case TYPECAST: + return getEndPos(((JCTypeCast) tree).expr, endPositions); + case TYPETEST: + return getEndPos(((JCInstanceOf) tree).clazz, endPositions); + case POS: + case NEG: + case NOT: + case COMPL: + case PREINC: + case PREDEC: + return getEndPos(((JCUnary) tree).arg, endPositions); + case WHILELOOP: + return getEndPos(((JCWhileLoop) tree).body, endPositions); + case ERRONEOUS: { + JCErroneous node = (JCErroneous)tree; + if (node.errs != null && node.errs.nonEmpty()) + return getEndPos(node.errs.last(), endPositions); } - } - case(JCTree.WILDCARD): - return getEndPos(((JCWildcard) tree).inner, endPositions); - case(JCTree.TYPECAST): - return getEndPos(((JCTypeCast) tree).expr, endPositions); - case(JCTree.TYPETEST): - return getEndPos(((JCInstanceOf) tree).clazz, endPositions); - case(JCTree.POS): - case(JCTree.NEG): - case(JCTree.NOT): - case(JCTree.COMPL): - case(JCTree.PREINC): - case(JCTree.PREDEC): - return getEndPos(((JCUnary) tree).arg, endPositions); - case(JCTree.WHILELOOP): - return getEndPos(((JCWhileLoop) tree).body, endPositions); - case(JCTree.ERRONEOUS): { - JCErroneous node = (JCErroneous)tree; - if (node.errs != null && node.errs.nonEmpty()) - return getEndPos(node.errs.last(), endPositions); - } } return Position.NOPOS; } @@ -443,11 +453,11 @@ public class TreeInfo { /** The position of the finalizer of given try/synchronized statement. */ public static int finalizerPos(JCTree tree) { - if (tree.getTag() == JCTree.TRY) { + if (tree.hasTag(TRY)) { JCTry t = (JCTry) tree; Assert.checkNonNull(t.finalizer); return firstStatPos(t.finalizer); - } else if (tree.getTag() == JCTree.SYNCHRONIZED) { + } else if (tree.hasTag(SYNCHRONIZED)) { return endPos(((JCSynchronized) tree).body); } else { throw new AssertionError(); @@ -547,9 +557,9 @@ public class TreeInfo { public static JCTree referencedStatement(JCLabeledStatement tree) { JCTree t = tree; do t = ((JCLabeledStatement) t).body; - while (t.getTag() == JCTree.LABELLED); + while (t.hasTag(LABELLED)); switch (t.getTag()) { - case JCTree.DOLOOP: case JCTree.WHILELOOP: case JCTree.FORLOOP: case JCTree.FOREACHLOOP: case JCTree.SWITCH: + case DOLOOP: case WHILELOOP: case FORLOOP: case FOREACHLOOP: case SWITCH: return t; default: return tree; @@ -559,7 +569,7 @@ public class TreeInfo { /** Skip parens and return the enclosed expression */ public static JCExpression skipParens(JCExpression tree) { - while (tree.getTag() == JCTree.PARENS) { + while (tree.hasTag(PARENS)) { tree = ((JCParens) tree).expr; } return tree; @@ -568,7 +578,7 @@ public class TreeInfo { /** Skip parens and return the enclosed expression */ public static JCTree skipParens(JCTree tree) { - if (tree.getTag() == JCTree.PARENS) + if (tree.hasTag(PARENS)) return skipParens((JCParens)tree); else return tree; @@ -588,11 +598,11 @@ public class TreeInfo { */ public static Name name(JCTree tree) { switch (tree.getTag()) { - case JCTree.IDENT: + case IDENT: return ((JCIdent) tree).name; - case JCTree.SELECT: + case SELECT: return ((JCFieldAccess) tree).name; - case JCTree.TYPEAPPLY: + case TYPEAPPLY: return name(((JCTypeApply) tree).clazz); default: return null; @@ -605,9 +615,9 @@ public class TreeInfo { public static Name fullName(JCTree tree) { tree = skipParens(tree); switch (tree.getTag()) { - case JCTree.IDENT: + case IDENT: return ((JCIdent) tree).name; - case JCTree.SELECT: + case SELECT: Name sname = fullName(((JCFieldAccess) tree).selected); return sname == null ? null : sname.append('.', name(tree)); default: @@ -618,11 +628,11 @@ public class TreeInfo { public static Symbol symbolFor(JCTree node) { node = skipParens(node); switch (node.getTag()) { - case JCTree.CLASSDEF: + case CLASSDEF: return ((JCClassDecl) node).sym; - case JCTree.METHODDEF: + case METHODDEF: return ((JCMethodDecl) node).sym; - case JCTree.VARDEF: + case VARDEF: return ((JCVariableDecl) node).sym; default: return null; @@ -632,9 +642,9 @@ public class TreeInfo { public static boolean isDeclaration(JCTree node) { node = skipParens(node); switch (node.getTag()) { - case JCTree.CLASSDEF: - case JCTree.METHODDEF: - case JCTree.VARDEF: + case CLASSDEF: + case METHODDEF: + case VARDEF: return true; default: return false; @@ -647,11 +657,11 @@ public class TreeInfo { public static Symbol symbol(JCTree tree) { tree = skipParens(tree); switch (tree.getTag()) { - case JCTree.IDENT: + case IDENT: return ((JCIdent) tree).sym; - case JCTree.SELECT: + case SELECT: return ((JCFieldAccess) tree).sym; - case JCTree.TYPEAPPLY: + case TYPEAPPLY: return symbol(((JCTypeApply) tree).clazz); default: return null; @@ -661,7 +671,7 @@ public class TreeInfo { /** Return true if this is a nonstatic selection. */ public static boolean nonstaticSelect(JCTree tree) { tree = skipParens(tree); - if (tree.getTag() != JCTree.SELECT) return false; + if (!tree.hasTag(SELECT)) return false; JCFieldAccess s = (JCFieldAccess) tree; Symbol e = symbol(s.selected); return e == null || (e.kind != Kinds.PCK && e.kind != Kinds.TYP); @@ -672,9 +682,9 @@ public class TreeInfo { public static void setSymbol(JCTree tree, Symbol sym) { tree = skipParens(tree); switch (tree.getTag()) { - case JCTree.IDENT: + case IDENT: ((JCIdent) tree).sym = sym; break; - case JCTree.SELECT: + case SELECT: ((JCFieldAccess) tree).sym = sym; break; default: } @@ -685,13 +695,13 @@ public class TreeInfo { */ public static long flags(JCTree tree) { switch (tree.getTag()) { - case JCTree.VARDEF: + case VARDEF: return ((JCVariableDecl) tree).mods.flags; - case JCTree.METHODDEF: + case METHODDEF: return ((JCMethodDecl) tree).mods.flags; - case JCTree.CLASSDEF: + case CLASSDEF: return ((JCClassDecl) tree).mods.flags; - case JCTree.BLOCK: + case BLOCK: return ((JCBlock) tree).flags; default: return 0; @@ -739,155 +749,155 @@ public class TreeInfo { /** Map operators to their precedence levels. */ - public static int opPrec(int op) { + public static int opPrec(JCTree.Tag op) { switch(op) { - case JCTree.POS: - case JCTree.NEG: - case JCTree.NOT: - case JCTree.COMPL: - case JCTree.PREINC: - case JCTree.PREDEC: return prefixPrec; - case JCTree.POSTINC: - case JCTree.POSTDEC: - case JCTree.NULLCHK: return postfixPrec; - case JCTree.ASSIGN: return assignPrec; - case JCTree.BITOR_ASG: - case JCTree.BITXOR_ASG: - case JCTree.BITAND_ASG: - case JCTree.SL_ASG: - case JCTree.SR_ASG: - case JCTree.USR_ASG: - case JCTree.PLUS_ASG: - case JCTree.MINUS_ASG: - case JCTree.MUL_ASG: - case JCTree.DIV_ASG: - case JCTree.MOD_ASG: return assignopPrec; - case JCTree.OR: return orPrec; - case JCTree.AND: return andPrec; - case JCTree.EQ: - case JCTree.NE: return eqPrec; - case JCTree.LT: - case JCTree.GT: - case JCTree.LE: - case JCTree.GE: return ordPrec; - case JCTree.BITOR: return bitorPrec; - case JCTree.BITXOR: return bitxorPrec; - case JCTree.BITAND: return bitandPrec; - case JCTree.SL: - case JCTree.SR: - case JCTree.USR: return shiftPrec; - case JCTree.PLUS: - case JCTree.MINUS: return addPrec; - case JCTree.MUL: - case JCTree.DIV: - case JCTree.MOD: return mulPrec; - case JCTree.TYPETEST: return ordPrec; + case POS: + case NEG: + case NOT: + case COMPL: + case PREINC: + case PREDEC: return prefixPrec; + case POSTINC: + case POSTDEC: + case NULLCHK: return postfixPrec; + case ASSIGN: return assignPrec; + case BITOR_ASG: + case BITXOR_ASG: + case BITAND_ASG: + case SL_ASG: + case SR_ASG: + case USR_ASG: + case PLUS_ASG: + case MINUS_ASG: + case MUL_ASG: + case DIV_ASG: + case MOD_ASG: return assignopPrec; + case OR: return orPrec; + case AND: return andPrec; + case EQ: + case NE: return eqPrec; + case LT: + case GT: + case LE: + case GE: return ordPrec; + case BITOR: return bitorPrec; + case BITXOR: return bitxorPrec; + case BITAND: return bitandPrec; + case SL: + case SR: + case USR: return shiftPrec; + case PLUS: + case MINUS: return addPrec; + case MUL: + case DIV: + case MOD: return mulPrec; + case TYPETEST: return ordPrec; default: throw new AssertionError(); } } - static Tree.Kind tagToKind(int tag) { + static Tree.Kind tagToKind(JCTree.Tag tag) { switch (tag) { // Postfix expressions - case JCTree.POSTINC: // _ ++ + case POSTINC: // _ ++ return Tree.Kind.POSTFIX_INCREMENT; - case JCTree.POSTDEC: // _ -- + case POSTDEC: // _ -- return Tree.Kind.POSTFIX_DECREMENT; // Unary operators - case JCTree.PREINC: // ++ _ + case PREINC: // ++ _ return Tree.Kind.PREFIX_INCREMENT; - case JCTree.PREDEC: // -- _ + case PREDEC: // -- _ return Tree.Kind.PREFIX_DECREMENT; - case JCTree.POS: // + + case POS: // + return Tree.Kind.UNARY_PLUS; - case JCTree.NEG: // - + case NEG: // - return Tree.Kind.UNARY_MINUS; - case JCTree.COMPL: // ~ + case COMPL: // ~ return Tree.Kind.BITWISE_COMPLEMENT; - case JCTree.NOT: // ! + case NOT: // ! return Tree.Kind.LOGICAL_COMPLEMENT; // Binary operators // Multiplicative operators - case JCTree.MUL: // * + case MUL: // * return Tree.Kind.MULTIPLY; - case JCTree.DIV: // / + case DIV: // / return Tree.Kind.DIVIDE; - case JCTree.MOD: // % + case MOD: // % return Tree.Kind.REMAINDER; // Additive operators - case JCTree.PLUS: // + + case PLUS: // + return Tree.Kind.PLUS; - case JCTree.MINUS: // - + case MINUS: // - return Tree.Kind.MINUS; // Shift operators - case JCTree.SL: // << + case SL: // << return Tree.Kind.LEFT_SHIFT; - case JCTree.SR: // >> + case SR: // >> return Tree.Kind.RIGHT_SHIFT; - case JCTree.USR: // >>> + case USR: // >>> return Tree.Kind.UNSIGNED_RIGHT_SHIFT; // Relational operators - case JCTree.LT: // < + case LT: // < return Tree.Kind.LESS_THAN; - case JCTree.GT: // > + case GT: // > return Tree.Kind.GREATER_THAN; - case JCTree.LE: // <= + case LE: // <= return Tree.Kind.LESS_THAN_EQUAL; - case JCTree.GE: // >= + case GE: // >= return Tree.Kind.GREATER_THAN_EQUAL; // Equality operators - case JCTree.EQ: // == + case EQ: // == return Tree.Kind.EQUAL_TO; - case JCTree.NE: // != + case NE: // != return Tree.Kind.NOT_EQUAL_TO; // Bitwise and logical operators - case JCTree.BITAND: // & + case BITAND: // & return Tree.Kind.AND; - case JCTree.BITXOR: // ^ + case BITXOR: // ^ return Tree.Kind.XOR; - case JCTree.BITOR: // | + case BITOR: // | return Tree.Kind.OR; // Conditional operators - case JCTree.AND: // && + case AND: // && return Tree.Kind.CONDITIONAL_AND; - case JCTree.OR: // || + case OR: // || return Tree.Kind.CONDITIONAL_OR; // Assignment operators - case JCTree.MUL_ASG: // *= + case MUL_ASG: // *= return Tree.Kind.MULTIPLY_ASSIGNMENT; - case JCTree.DIV_ASG: // /= + case DIV_ASG: // /= return Tree.Kind.DIVIDE_ASSIGNMENT; - case JCTree.MOD_ASG: // %= + case MOD_ASG: // %= return Tree.Kind.REMAINDER_ASSIGNMENT; - case JCTree.PLUS_ASG: // += + case PLUS_ASG: // += return Tree.Kind.PLUS_ASSIGNMENT; - case JCTree.MINUS_ASG: // -= + case MINUS_ASG: // -= return Tree.Kind.MINUS_ASSIGNMENT; - case JCTree.SL_ASG: // <<= + case SL_ASG: // <<= return Tree.Kind.LEFT_SHIFT_ASSIGNMENT; - case JCTree.SR_ASG: // >>= + case SR_ASG: // >>= return Tree.Kind.RIGHT_SHIFT_ASSIGNMENT; - case JCTree.USR_ASG: // >>>= + case USR_ASG: // >>>= return Tree.Kind.UNSIGNED_RIGHT_SHIFT_ASSIGNMENT; - case JCTree.BITAND_ASG: // &= + case BITAND_ASG: // &= return Tree.Kind.AND_ASSIGNMENT; - case JCTree.BITXOR_ASG: // ^= + case BITXOR_ASG: // ^= return Tree.Kind.XOR_ASSIGNMENT; - case JCTree.BITOR_ASG: // |= + case BITOR_ASG: // |= return Tree.Kind.OR_ASSIGNMENT; // Null check (implementation detail), for example, __.getClass() - case JCTree.NULLCHK: + case NULLCHK: return Tree.Kind.OTHER; default: @@ -901,13 +911,13 @@ public class TreeInfo { */ public static JCExpression typeIn(JCExpression tree) { switch (tree.getTag()) { - case JCTree.IDENT: /* simple names */ - case JCTree.TYPEIDENT: /* primitive name */ - case JCTree.SELECT: /* qualified name */ - case JCTree.TYPEARRAY: /* array types */ - case JCTree.WILDCARD: /* wild cards */ - case JCTree.TYPEPARAMETER: /* type parameters */ - case JCTree.TYPEAPPLY: /* parameterized types */ + case IDENT: /* simple names */ + case TYPEIDENT: /* primitive name */ + case SELECT: /* qualified name */ + case TYPEARRAY: /* array types */ + case WILDCARD: /* wild cards */ + case TYPEPARAMETER: /* type parameters */ + case TYPEAPPLY: /* parameterized types */ return tree; default: throw new AssertionError("Unexpected type tree: " + tree); @@ -916,9 +926,9 @@ public class TreeInfo { public static JCTree innermostType(JCTree type) { switch (type.getTag()) { - case JCTree.TYPEARRAY: + case TYPEARRAY: return innermostType(((JCArrayTypeTree)type).elemtype); - case JCTree.WILDCARD: + case WILDCARD: return innermostType(((JCWildcard)type).inner); default: return type; diff --git a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java index e3f18a08043..7f673023def 100644 --- a/langtools/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java +++ b/langtools/src/share/classes/com/sun/tools/javac/tree/TreeMaker.java @@ -363,19 +363,19 @@ public class TreeMaker implements JCTree.Factory { return tree; } - public JCAssignOp Assignop(int opcode, JCTree lhs, JCTree rhs) { + public JCAssignOp Assignop(JCTree.Tag opcode, JCTree lhs, JCTree rhs) { JCAssignOp tree = new JCAssignOp(opcode, lhs, rhs, null); tree.pos = pos; return tree; } - public JCUnary Unary(int opcode, JCExpression arg) { + public JCUnary Unary(JCTree.Tag opcode, JCExpression arg) { JCUnary tree = new JCUnary(opcode, arg); tree.pos = pos; return tree; } - public JCBinary Binary(int opcode, JCExpression lhs, JCExpression rhs) { + public JCBinary Binary(JCTree.Tag opcode, JCExpression lhs, JCExpression rhs) { JCBinary tree = new JCBinary(opcode, lhs, rhs, null); tree.pos = pos; return tree; diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java b/langtools/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java index 592d0beb6e5..a5fed4b059c 100644 --- a/langtools/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java +++ b/langtools/src/share/classes/com/sun/tools/javadoc/ClassDocImpl.java @@ -65,6 +65,7 @@ import com.sun.tools.javac.util.Names; import com.sun.tools.javac.util.Position; import static com.sun.tools.javac.code.Kinds.*; +import static com.sun.tools.javac.tree.JCTree.Tag.*; /** * Represents a java class and provides access to information @@ -1083,7 +1084,7 @@ public class ClassDocImpl extends ProgramElementDocImpl implements ClassDoc { Name asterisk = tsym.name.table.names.asterisk; for (JCTree t : compenv.toplevel.defs) { - if (t.getTag() == JCTree.IMPORT) { + if (t.hasTag(IMPORT)) { JCTree imp = ((JCImport) t).qualid; if ((TreeInfo.name(imp) != asterisk) && (imp.type.tsym.kind & Kinds.TYP) != 0) { @@ -1124,7 +1125,7 @@ public class ClassDocImpl extends ProgramElementDocImpl implements ClassDoc { if (compenv == null) return new PackageDocImpl[0]; for (JCTree t : compenv.toplevel.defs) { - if (t.getTag() == JCTree.IMPORT) { + if (t.hasTag(IMPORT)) { JCTree imp = ((JCImport) t).qualid; if (TreeInfo.name(imp) == names.asterisk) { JCFieldAccess sel = (JCFieldAccess)imp; diff --git a/langtools/src/share/classes/com/sun/tools/javadoc/JavadocTool.java b/langtools/src/share/classes/com/sun/tools/javadoc/JavadocTool.java index a5592acf8ad..81bcdbd3008 100644 --- a/langtools/src/share/classes/com/sun/tools/javadoc/JavadocTool.java +++ b/langtools/src/share/classes/com/sun/tools/javadoc/JavadocTool.java @@ -419,7 +419,7 @@ public class JavadocTool extends com.sun.tools.javac.main.JavaCompiler { ListBuffer result = new ListBuffer(); for (JCCompilationUnit t : trees) { for (JCTree def : t.defs) { - if (def.getTag() == JCTree.CLASSDEF) + if (def.hasTag(JCTree.Tag.CLASSDEF)) result.append((JCClassDecl)def); } } diff --git a/langtools/test/tools/javac/failover/CheckAttributedTree.java b/langtools/test/tools/javac/failover/CheckAttributedTree.java index e249689a41a..a134c8ac4e2 100644 --- a/langtools/test/tools/javac/failover/CheckAttributedTree.java +++ b/langtools/test/tools/javac/failover/CheckAttributedTree.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2011, 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 @@ -85,6 +85,8 @@ import java.util.HashSet; import java.util.Set; import javax.lang.model.element.Element; +import static com.sun.tools.javac.tree.JCTree.Tag.*; + /** * Utility and test program to check validity of tree positions for tree nodes. * The program can be run standalone, or as a jtreg test. In standalone mode, @@ -289,7 +291,7 @@ public class CheckAttributedTree { for (CompilationUnitTree t : trees) { JCCompilationUnit cu = (JCCompilationUnit)t; for (JCTree def : cu.defs) { - if (def.getTag() == JCTree.CLASSDEF && + if (def.hasTag(CLASSDEF) && analyzedElems.contains(((JCTree.JCClassDecl)def).sym)) { //System.out.println("Adding pair..."); res.add(new Pair<>(cu, def)); @@ -373,9 +375,9 @@ public class CheckAttributedTree { private boolean mandatoryType(JCTree that) { return that instanceof JCTree.JCExpression || - that.getTag() == JCTree.VARDEF || - that.getTag() == JCTree.METHODDEF || - that.getTag() == JCTree.CLASSDEF; + that.hasTag(VARDEF) || + that.hasTag(METHODDEF) || + that.hasTag(CLASSDEF); } private final List excludedFields = Arrays.asList("varargsElement"); @@ -429,7 +431,7 @@ public class CheckAttributedTree { private class Info { Info() { tree = null; - tag = JCTree.ERRONEOUS; + tag = ERRONEOUS; start = 0; pos = 0; end = Integer.MAX_VALUE; @@ -449,7 +451,7 @@ public class CheckAttributedTree { } final JCTree tree; - final int tag; + final JCTree.Tag tag; final int start; final int pos; final int end; @@ -457,27 +459,10 @@ public class CheckAttributedTree { /** * Names for tree tags. - * javac does not provide an API to convert tag values to strings, so this class uses - * reflection to determine names of public static final int values in JCTree. */ private static class TreeUtil { - String nameFromTag(int tag) { - if (names == null) { - names = new HashMap(); - Class c = JCTree.class; - for (Field f : c.getDeclaredFields()) { - if (f.getType().equals(int.class)) { - int mods = f.getModifiers(); - if (Modifier.isPublic(mods) && Modifier.isStatic(mods) && Modifier.isFinal(mods)) { - try { - names.put(f.getInt(null), f.getName()); - } catch (IllegalAccessException e) { - } - } - } - } - } - String name = names.get(tag); + String nameFromTag(JCTree.Tag tag) { + String name = tag.name(); return (name == null) ? "??" : name; } @@ -496,8 +481,6 @@ public class CheckAttributedTree { } return buf; } - - private Map names; } /** diff --git a/langtools/test/tools/javac/tree/AbstractTreeScannerTest.java b/langtools/test/tools/javac/tree/AbstractTreeScannerTest.java index b0fe687fdff..1d5ec84716f 100644 --- a/langtools/test/tools/javac/tree/AbstractTreeScannerTest.java +++ b/langtools/test/tools/javac/tree/AbstractTreeScannerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2011, 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 @@ -274,7 +274,7 @@ public abstract class AbstractTreeScannerTest { return fields; } // where - Map> map = new HashMap>(); + Map> map = new HashMap>(); /** Get the line number for the primary position for a tree. * The code is intended to be simple, although not necessarily efficient. diff --git a/langtools/test/tools/javac/tree/TreePosTest.java b/langtools/test/tools/javac/tree/TreePosTest.java index bb6e466b557..d32e5f0d990 100644 --- a/langtools/test/tools/javac/tree/TreePosTest.java +++ b/langtools/test/tools/javac/tree/TreePosTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2011, 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 @@ -80,6 +80,7 @@ import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.tree.TreeInfo; import com.sun.tools.javac.tree.TreeScanner; +import static com.sun.tools.javac.tree.JCTree.Tag.*; import static com.sun.tools.javac.util.Position.NOPOS; /** @@ -291,6 +292,14 @@ public class TreePosTest { errors++; } + /** + * Names for tree tags. + */ + private static String getTagName(JCTree.Tag tag) { + String name = tag.name(); + return (name == null) ? "??" : name; + } + /** Number of files that have been analyzed. */ int fileCount; /** Number of errors reported. */ @@ -312,8 +321,6 @@ public class TreePosTest { Set excludeFiles = new HashSet(); /** Set of tag names to be excluded from analysis. */ Set excludeTags = new HashSet(); - /** Table of printable names for tree tag values. */ - TagNames tagNames = new TagNames(); /** * Main class for testing assertions concerning tree positions for tree nodes. @@ -337,7 +344,7 @@ public class TreePosTest { // there is no corresponding source text. // Redundant semicolons in a class definition can cause empty // initializer blocks with no positions. - if ((self.tag == JCTree.MODIFIERS || self.tag == JCTree.BLOCK) + if ((self.tag == MODIFIERS || self.tag == BLOCK) && self.pos == NOPOS) { // If pos is NOPOS, so should be the start and end positions check("start == NOPOS", encl, self, self.start == NOPOS); @@ -359,15 +366,15 @@ public class TreePosTest { // e.g. int[][] a = new int[2][]; check("encl.start <= start", encl, self, encl.start <= self.start); check("start <= pos", encl, self, self.start <= self.pos); - if (!(self.tag == JCTree.TYPEARRAY - && (encl.tag == JCTree.VARDEF || - encl.tag == JCTree.METHODDEF || - encl.tag == JCTree.TYPEARRAY))) { + if (!(self.tag == TYPEARRAY + && (encl.tag == VARDEF || + encl.tag == METHODDEF || + encl.tag == TYPEARRAY))) { check("encl.pos <= start || end <= encl.pos", encl, self, encl.pos <= self.start || self.end <= encl.pos); } check("pos <= end", encl, self, self.pos <= self.end); - if (!(self.tag == JCTree.TYPEARRAY && encl.tag == JCTree.TYPEARRAY)) { + if (!(self.tag == TYPEARRAY && encl.tag == TYPEARRAY)) { check("end <= encl.end", encl, self, self.end <= encl.end); } } @@ -388,7 +395,7 @@ public class TreePosTest { if ((tree.mods.flags & Flags.ENUM) != 0) { scan(tree.mods); if (tree.init != null) { - if (tree.init.getTag() == JCTree.NEWCLASS) { + if (tree.init.hasTag(NEWCLASS)) { JCNewClass init = (JCNewClass) tree.init; if (init.args != null && init.args.nonEmpty()) { scan(init.args); @@ -404,11 +411,11 @@ public class TreePosTest { boolean check(Info encl, Info self) { if (excludeTags.size() > 0) { - if (encl != null && excludeTags.contains(tagNames.get(encl.tag)) - || excludeTags.contains(tagNames.get(self.tag))) + if (encl != null && excludeTags.contains(getTagName(encl.tag)) + || excludeTags.contains(getTagName(self.tag))) return false; } - return tags.size() == 0 || tags.contains(tagNames.get(self.tag)); + return tags.size() == 0 || tags.contains(getTagName(self.tag)); } void check(String label, Info encl, Info self, boolean ok) { @@ -439,7 +446,7 @@ public class TreePosTest { private class Info { Info() { tree = null; - tag = JCTree.ERRONEOUS; + tag = ERRONEOUS; start = 0; pos = 0; end = Integer.MAX_VALUE; @@ -455,45 +462,16 @@ public class TreePosTest { @Override public String toString() { - return tagNames.get(tree.getTag()) + "[start:" + start + ",pos:" + pos + ",end:" + end + "]"; + return getTagName(tree.getTag()) + "[start:" + start + ",pos:" + pos + ",end:" + end + "]"; } final JCTree tree; - final int tag; + final JCTree.Tag tag; final int start; final int pos; final int end; } - /** - * Names for tree tags. - * javac does not provide an API to convert tag values to strings, so this class uses - * reflection to determine names of public static final int values in JCTree. - */ - private static class TagNames { - String get(int tag) { - if (map == null) { - map = new HashMap(); - Class c = JCTree.class; - for (Field f : c.getDeclaredFields()) { - if (f.getType().equals(int.class)) { - int mods = f.getModifiers(); - if (Modifier.isPublic(mods) && Modifier.isStatic(mods) && Modifier.isFinal(mods)) { - try { - map.put(f.getInt(null), f.getName()); - } catch (IllegalAccessException e) { - } - } - } - } - } - String name = map.get(tag); - return (name == null) ? "??" : name; - } - - private Map map; - } - /** * Thrown when errors are found parsing a java file. */ @@ -719,7 +697,7 @@ public class TreePosTest { void setInfo(Info info) { this.info = info; - tagName.setText(tagNames.get(info.tag)); + tagName.setText(getTagName(info.tag)); start.setText(String.valueOf(info.start)); pos.setText(String.valueOf(info.pos)); end.setText(String.valueOf(info.end)); From 890f9e288476bf003408579fb90c2656daadcdf1 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Wed, 9 Nov 2011 09:30:13 +0800 Subject: [PATCH 078/107] 7107019: sun.security.krb5.internal.ccache.CCacheInputStream.readCred does not use auth data Reviewed-by: valeriep --- .../krb5/internal/ccache/CCacheInputStream.java | 2 +- .../sun/security/krb5/internal/ccache/Credentials.java | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/jdk/src/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java b/jdk/src/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java index 4f387b99f96..ef7088f371b 100644 --- a/jdk/src/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java +++ b/jdk/src/share/classes/sun/security/krb5/internal/ccache/CCacheInputStream.java @@ -375,7 +375,7 @@ public class CCacheInputStream extends KrbDataInputStream implements FileCCacheC } AuthorizationDataEntry[] auDataEntry = readAuth(); AuthorizationData auData = null; - if (auData != null) { + if (auDataEntry != null) { auData = new AuthorizationData(auDataEntry); } byte[] ticketData = readData(); diff --git a/jdk/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java b/jdk/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java index b02cc6de787..da45410dbe0 100644 --- a/jdk/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java +++ b/jdk/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java @@ -209,6 +209,16 @@ public class Credentials { } public sun.security.krb5.Credentials setKrbCreds() { + // Note: We will not pass authorizationData to s.s.k.Credentials. The + // field in that class will be passed to Krb5Context as the return + // value of ExtendedGSSContext.inquireSecContext(KRB5_GET_AUTHZ_DATA), + // which is documented as the authData in the service ticket. That + // is on the acceptor side. + // + // This class is for the initiator side. Also, authdata inside a ccache + // is most likely to be the one in Authenticator in PA-TGS-REQ encoded + // in TGS-REQ, therefore only stored with a service ticket. Currently + // in Java, we only reads TGTs. return new sun.security.krb5.Credentials(ticket, cname, sname, key, flags, authtime, starttime, endtime, renewTill, caddr); } From 54229dbc547931ba8a88bb3472ce44b7971424b8 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Wed, 9 Nov 2011 15:51:18 +0800 Subject: [PATCH 079/107] 7109096: keytool -genkeypair needn't call -selfcert Reviewed-by: xuelei --- .../sun/security/tools/CertAndKeyGen.java | 41 +++++++++++++------ .../classes/sun/security/tools/KeyTool.java | 12 ++++-- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/jdk/src/share/classes/sun/security/tools/CertAndKeyGen.java b/jdk/src/share/classes/sun/security/tools/CertAndKeyGen.java index 4c32a33b4f7..fad412e9f9a 100644 --- a/jdk/src/share/classes/sun/security/tools/CertAndKeyGen.java +++ b/jdk/src/share/classes/sun/security/tools/CertAndKeyGen.java @@ -33,18 +33,7 @@ import java.security.*; import java.util.Date; import sun.security.pkcs10.PKCS10; -import sun.security.x509.AlgorithmId; -import sun.security.x509.CertificateAlgorithmId; -import sun.security.x509.CertificateIssuerName; -import sun.security.x509.CertificateSerialNumber; -import sun.security.x509.CertificateSubjectName; -import sun.security.x509.CertificateValidity; -import sun.security.x509.CertificateVersion; -import sun.security.x509.CertificateX509Key; -import sun.security.x509.X500Name; -import sun.security.x509.X509CertImpl; -import sun.security.x509.X509CertInfo; -import sun.security.x509.X509Key; +import sun.security.x509.*; /** @@ -165,6 +154,13 @@ public final class CertAndKeyGen { publicKey = pair.getPublic(); privateKey = pair.getPrivate(); + + // publicKey's format must be X.509 otherwise + // the whole CertGen part of this class is broken. + if (!"X.509".equalsIgnoreCase(publicKey.getFormat())) { + throw new IllegalArgumentException("publicKey's is not X.509, but " + + publicKey.getFormat()); + } } @@ -186,6 +182,16 @@ public final class CertAndKeyGen { return (X509Key)publicKey; } + /** + * Always returns the public key of the generated key pair. Used + * by KeyTool only. + * + * The publicKey is not necessarily to be an instance of + * X509Key in some JCA/JCE providers, for example SunPKCS11. + */ + public PublicKey getPublicKeyAnyway() { + return publicKey; + } /** * Returns the private key of the generated key pair. @@ -200,7 +206,6 @@ public final class CertAndKeyGen { return privateKey; } - /** * Returns a self-signed X.509v3 certificate for the public key. * The certificate is immediately valid. No extensions. @@ -224,6 +229,15 @@ public final class CertAndKeyGen { X500Name myname, Date firstDate, long validity) throws CertificateException, InvalidKeyException, SignatureException, NoSuchAlgorithmException, NoSuchProviderException + { + return getSelfCertificate(myname, firstDate, validity, null); + } + + // Like above, plus a CertificateExtensions argument, which can be null. + public X509Certificate getSelfCertificate (X500Name myname, Date firstDate, + long validity, CertificateExtensions ext) + throws CertificateException, InvalidKeyException, SignatureException, + NoSuchAlgorithmException, NoSuchProviderException { X509CertImpl cert; Date lastDate; @@ -248,6 +262,7 @@ public final class CertAndKeyGen { info.set(X509CertInfo.KEY, new CertificateX509Key(publicKey)); info.set(X509CertInfo.VALIDITY, interval); info.set(X509CertInfo.ISSUER, new CertificateIssuerName(myname)); + if (ext != null) info.set(X509CertInfo.EXTENSIONS, ext); cert = new X509CertImpl(info); cert.sign(privateKey, this.sigAlg); diff --git a/jdk/src/share/classes/sun/security/tools/KeyTool.java b/jdk/src/share/classes/sun/security/tools/KeyTool.java index 0d928209807..3125f6f54c7 100644 --- a/jdk/src/share/classes/sun/security/tools/KeyTool.java +++ b/jdk/src/share/classes/sun/security/tools/KeyTool.java @@ -1518,9 +1518,16 @@ public final class KeyTool { keypair.generate(keysize); PrivateKey privKey = keypair.getPrivateKey(); + CertificateExtensions ext = createV3Extensions( + null, + null, + v3ext, + keypair.getPublicKeyAnyway(), + null); + X509Certificate[] chain = new X509Certificate[1]; chain[0] = keypair.getSelfCertificate( - x500Name, getStartDate(startDate), validity*24L*60L*60L); + x500Name, getStartDate(startDate), validity*24L*60L*60L, ext); if (verbose) { MessageFormat form = new MessageFormat(rb.getString @@ -1537,9 +1544,6 @@ public final class KeyTool { keyPass = promptForKeyPass(alias, null, storePass); } keyStore.setKeyEntry(alias, privKey, keyPass, chain); - - // resign so that -ext are applied. - doSelfCert(alias, null, sigAlgName); } /** From 26cb79b7bbb504f95cf680f3051676141481a75f Mon Sep 17 00:00:00 2001 From: Doug Lea Date: Thu, 10 Nov 2011 12:21:49 +0000 Subject: [PATCH 080/107] 7107516: LinkedBlockingQueue/Deque.drainTo(Collection, int) returns 'maxElements' if its value is negative Reviewed-by: chegar, mduigou, dholmes --- .../classes/java/util/concurrent/LinkedBlockingDeque.java | 2 ++ .../classes/java/util/concurrent/LinkedBlockingQueue.java | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/jdk/src/share/classes/java/util/concurrent/LinkedBlockingDeque.java b/jdk/src/share/classes/java/util/concurrent/LinkedBlockingDeque.java index c1978c8e331..60a18d0dba3 100644 --- a/jdk/src/share/classes/java/util/concurrent/LinkedBlockingDeque.java +++ b/jdk/src/share/classes/java/util/concurrent/LinkedBlockingDeque.java @@ -742,6 +742,8 @@ public class LinkedBlockingDeque throw new NullPointerException(); if (c == this) throw new IllegalArgumentException(); + if (maxElements <= 0) + return 0; final ReentrantLock lock = this.lock; lock.lock(); try { diff --git a/jdk/src/share/classes/java/util/concurrent/LinkedBlockingQueue.java b/jdk/src/share/classes/java/util/concurrent/LinkedBlockingQueue.java index ae4d43594dd..d1a6d5a0b58 100644 --- a/jdk/src/share/classes/java/util/concurrent/LinkedBlockingQueue.java +++ b/jdk/src/share/classes/java/util/concurrent/LinkedBlockingQueue.java @@ -332,7 +332,7 @@ public class LinkedBlockingQueue extends AbstractQueue // Note: convention in all put/take/etc is to preset local var // holding count negative to indicate failure unless set. int c = -1; - Node node = new Node(e); + Node node = new Node(e); final ReentrantLock putLock = this.putLock; final AtomicInteger count = this.count; putLock.lockInterruptibly(); @@ -412,7 +412,7 @@ public class LinkedBlockingQueue extends AbstractQueue if (count.get() == capacity) return false; int c = -1; - Node node = new Node(e); + Node node = new Node(e); final ReentrantLock putLock = this.putLock; putLock.lock(); try { @@ -728,6 +728,8 @@ public class LinkedBlockingQueue extends AbstractQueue throw new NullPointerException(); if (c == this) throw new IllegalArgumentException(); + if (maxElements <= 0) + return 0; boolean signalNotFull = false; final ReentrantLock takeLock = this.takeLock; takeLock.lock(); From bac4f6c7ac680a9c4aa9fc362758229f46045699 Mon Sep 17 00:00:00 2001 From: Michael McMahon Date: Thu, 10 Nov 2011 15:30:45 +0000 Subject: [PATCH 081/107] 7110484: HttpServer.stop() not closing selector Reviewed-by: chegar --- jdk/src/share/classes/sun/net/httpserver/ServerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/share/classes/sun/net/httpserver/ServerImpl.java b/jdk/src/share/classes/sun/net/httpserver/ServerImpl.java index cce9c136e8a..69a9e6586ec 100644 --- a/jdk/src/share/classes/sun/net/httpserver/ServerImpl.java +++ b/jdk/src/share/classes/sun/net/httpserver/ServerImpl.java @@ -402,10 +402,10 @@ class ServerImpl implements TimeSource { } catch (IOException e) { logger.log (Level.FINER, "Dispatcher (4)", e); } catch (Exception e) { - e.printStackTrace(); logger.log (Level.FINER, "Dispatcher (7)", e); } } + try {selector.close(); } catch (Exception e) {} } private void handleException (SelectionKey key, Exception e) { From f6f5a14a328ab267e5d9951ecac3e2ca6dbb8068 Mon Sep 17 00:00:00 2001 From: Martin Desruisseaux Date: Thu, 10 Nov 2011 11:41:27 -0500 Subject: [PATCH 082/107] 7110111: Minor Java SE javadoc & Constructor clean up Reviewed-by: alanb, darcy --- jdk/src/share/classes/java/io/Writer.java | 8 ++++---- .../share/classes/java/lang/AssertionError.java | 14 +++++++------- jdk/src/share/classes/java/lang/Class.java | 2 +- jdk/src/share/classes/java/lang/Double.java | 3 +-- jdk/src/share/classes/java/lang/Float.java | 3 +-- .../share/classes/java/sql/PreparedStatement.java | 2 +- jdk/src/share/classes/java/sql/Statement.java | 2 +- .../share/classes/java/util/jar/Attributes.java | 2 +- 8 files changed, 17 insertions(+), 19 deletions(-) diff --git a/jdk/src/share/classes/java/io/Writer.java b/jdk/src/share/classes/java/io/Writer.java index f0c6db46319..fcab562d76b 100644 --- a/jdk/src/share/classes/java/io/Writer.java +++ b/jdk/src/share/classes/java/io/Writer.java @@ -57,7 +57,7 @@ public abstract class Writer implements Appendable, Closeable, Flushable { /** * Size of writeBuffer, must be >= 1 */ - private final int writeBufferSize = 1024; + private static final int WRITE_BUFFER_SIZE = 1024; /** * The object used to synchronize operations on this stream. For @@ -107,7 +107,7 @@ public abstract class Writer implements Appendable, Closeable, Flushable { public void write(int c) throws IOException { synchronized (lock) { if (writeBuffer == null){ - writeBuffer = new char[writeBufferSize]; + writeBuffer = new char[WRITE_BUFFER_SIZE]; } writeBuffer[0] = (char) c; write(writeBuffer, 0, 1); @@ -180,9 +180,9 @@ public abstract class Writer implements Appendable, Closeable, Flushable { public void write(String str, int off, int len) throws IOException { synchronized (lock) { char cbuf[]; - if (len <= writeBufferSize) { + if (len <= WRITE_BUFFER_SIZE) { if (writeBuffer == null) { - writeBuffer = new char[writeBufferSize]; + writeBuffer = new char[WRITE_BUFFER_SIZE]; } cbuf = writeBuffer; } else { // Don't permanently allocate very large buffers. diff --git a/jdk/src/share/classes/java/lang/AssertionError.java b/jdk/src/share/classes/java/lang/AssertionError.java index 984c3e4f00b..926f71141cd 100644 --- a/jdk/src/share/classes/java/lang/AssertionError.java +++ b/jdk/src/share/classes/java/lang/AssertionError.java @@ -71,7 +71,7 @@ public class AssertionError extends Error { * @see Throwable#getCause() */ public AssertionError(Object detailMessage) { - this("" + detailMessage); + this(String.valueOf(detailMessage)); if (detailMessage instanceof Throwable) initCause((Throwable) detailMessage); } @@ -85,7 +85,7 @@ public class AssertionError extends Error { * @param detailMessage value to be used in constructing detail message */ public AssertionError(boolean detailMessage) { - this("" + detailMessage); + this(String.valueOf(detailMessage)); } /** @@ -97,7 +97,7 @@ public class AssertionError extends Error { * @param detailMessage value to be used in constructing detail message */ public AssertionError(char detailMessage) { - this("" + detailMessage); + this(String.valueOf(detailMessage)); } /** @@ -109,7 +109,7 @@ public class AssertionError extends Error { * @param detailMessage value to be used in constructing detail message */ public AssertionError(int detailMessage) { - this("" + detailMessage); + this(String.valueOf(detailMessage)); } /** @@ -121,7 +121,7 @@ public class AssertionError extends Error { * @param detailMessage value to be used in constructing detail message */ public AssertionError(long detailMessage) { - this("" + detailMessage); + this(String.valueOf(detailMessage)); } /** @@ -133,7 +133,7 @@ public class AssertionError extends Error { * @param detailMessage value to be used in constructing detail message */ public AssertionError(float detailMessage) { - this("" + detailMessage); + this(String.valueOf(detailMessage)); } /** @@ -145,7 +145,7 @@ public class AssertionError extends Error { * @param detailMessage value to be used in constructing detail message */ public AssertionError(double detailMessage) { - this("" + detailMessage); + this(String.valueOf(detailMessage)); } /** diff --git a/jdk/src/share/classes/java/lang/Class.java b/jdk/src/share/classes/java/lang/Class.java index 01e21b9a030..ca7f1be7927 100644 --- a/jdk/src/share/classes/java/lang/Class.java +++ b/jdk/src/share/classes/java/lang/Class.java @@ -3008,7 +3008,7 @@ public final /** * Casts this {@code Class} object to represent a subclass of the class - * represented by the specified class object. Checks that that the cast + * represented by the specified class object. Checks that the cast * is valid, and throws a {@code ClassCastException} if it is not. If * this method succeeds, it always returns a reference to this class object. * diff --git a/jdk/src/share/classes/java/lang/Double.java b/jdk/src/share/classes/java/lang/Double.java index 7d426180c5d..70e6a7c60f3 100644 --- a/jdk/src/share/classes/java/lang/Double.java +++ b/jdk/src/share/classes/java/lang/Double.java @@ -607,8 +607,7 @@ public final class Double extends Number implements Comparable { * @see java.lang.Double#valueOf(java.lang.String) */ public Double(String s) throws NumberFormatException { - // REMIND: this is inefficient - this(valueOf(s).doubleValue()); + value = parseDouble(s); } /** diff --git a/jdk/src/share/classes/java/lang/Float.java b/jdk/src/share/classes/java/lang/Float.java index 6aa381ccebd..bd32e366a3d 100644 --- a/jdk/src/share/classes/java/lang/Float.java +++ b/jdk/src/share/classes/java/lang/Float.java @@ -529,8 +529,7 @@ public final class Float extends Number implements Comparable { * @see java.lang.Float#valueOf(java.lang.String) */ public Float(String s) throws NumberFormatException { - // REMIND: this is inefficient - this(valueOf(s).floatValue()); + value = parseFloat(s); } /** diff --git a/jdk/src/share/classes/java/sql/PreparedStatement.java b/jdk/src/share/classes/java/sql/PreparedStatement.java index 1d32c3dd0b9..8d6ca60360c 100644 --- a/jdk/src/share/classes/java/sql/PreparedStatement.java +++ b/jdk/src/share/classes/java/sql/PreparedStatement.java @@ -767,7 +767,7 @@ public interface PreparedStatement extends Statement { /** - * Sets the designated paramter to the given String object. + * Sets the designated parameter to the given String object. * The driver converts this to a SQL NCHAR or * NVARCHAR or LONGNVARCHAR value * (depending on the argument's diff --git a/jdk/src/share/classes/java/sql/Statement.java b/jdk/src/share/classes/java/sql/Statement.java index da7285e5f3f..0b467fb7e02 100644 --- a/jdk/src/share/classes/java/sql/Statement.java +++ b/jdk/src/share/classes/java/sql/Statement.java @@ -991,7 +991,7 @@ public interface Statement extends Wrapper, AutoCloseable { /** * Requests that a Statement be pooled or not pooled. The value * specified is a hint to the statement pool implementation indicating - * whether the applicaiton wants the statement to be pooled. It is up to + * whether the application wants the statement to be pooled. It is up to * the statement pool manager as to whether the hint is used. *

* The poolable value of a statement is applicable to both internal diff --git a/jdk/src/share/classes/java/util/jar/Attributes.java b/jdk/src/share/classes/java/util/jar/Attributes.java index 58856420035..e09071172b6 100644 --- a/jdk/src/share/classes/java/util/jar/Attributes.java +++ b/jdk/src/share/classes/java/util/jar/Attributes.java @@ -629,7 +629,7 @@ public class Attributes implements Map, Cloneable { public static final Name IMPLEMENTATION_VENDOR_ID = new Name("Implementation-Vendor-Id"); /** - * Name object for Implementation-Vendor-URL + * Name object for Implementation-URL * manifest attribute used for package versioning. * @see * Java Product Versioning Specification From 0357c1c07798790e8389e041cd9e158e4f178a0e Mon Sep 17 00:00:00 2001 From: David Katleman Date: Thu, 10 Nov 2011 11:45:41 -0800 Subject: [PATCH 083/107] Added tag jdk8-b13 for changeset c3b8ec8ea08d --- .hgtags-top-repo | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags-top-repo b/.hgtags-top-repo index 55fb765ce49..adfe73a17a9 100644 --- a/.hgtags-top-repo +++ b/.hgtags-top-repo @@ -134,3 +134,4 @@ fb1bc13260d76447e269e843859eb593fe2a8ab2 jdk8-b08 a6c4c248e8fa350c35014fa94bab5ac1a1ac3299 jdk8-b10 1defbc57940a56f0aa41e9dee87b71e8c8b71103 jdk8-b11 8e2104d565baee473895d5eba20e39f85ab4bf9f jdk8-b12 +26fb81a1e9ceb9baffba216acd9ded62e9e9d5ab jdk8-b13 From 75f0f16626b6edca91565487db3a10b24e5e5fba Mon Sep 17 00:00:00 2001 From: David Katleman Date: Thu, 10 Nov 2011 11:45:56 -0800 Subject: [PATCH 084/107] Added tag jdk8-b13 for changeset e0e566b9d2b2 --- corba/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/corba/.hgtags b/corba/.hgtags index 551fa0151c5..1ab8b2c2344 100644 --- a/corba/.hgtags +++ b/corba/.hgtags @@ -134,3 +134,4 @@ a891732c1a83082177ff7a4cf1506068d9cc0a47 jdk8-b09 cda87f7fefcee3b89742a57ce5ad9b03a54c210d jdk8-b10 0199e4fef5cc2bd234c65b93220459ef7a3bb3b1 jdk8-b11 31d70911b712c6b4e580a3110363d5f044cfed7a jdk8-b12 +5b9d9b839d3d7fe02347827221c97c6d242a6f96 jdk8-b13 From 6e1ccb9a07dcc802e94145551ad26281b13630fc Mon Sep 17 00:00:00 2001 From: David Katleman Date: Thu, 10 Nov 2011 11:46:05 -0800 Subject: [PATCH 085/107] Added tag jdk8-b13 for changeset 660da5b5870e --- hotspot/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/hotspot/.hgtags b/hotspot/.hgtags index ee81b3c5fa8..662b51ccb8a 100644 --- a/hotspot/.hgtags +++ b/hotspot/.hgtags @@ -197,3 +197,4 @@ d815de2e85e511b7deab2a83cf80c0224d011da9 jdk8-b10 6534482ff68ad79066dfe15dfb6d8905f09681bd hs23-b04 1d3900713a67a0a39faf4e12c9c158d55aebef87 jdk8-b12 3e609627e780736f372eb14d29bb9b5e53b21fbf hs23-b05 +b92ca8e229d29004f840c67e620833d23a346761 jdk8-b13 From fc6d47bc5cbdadf0d39b77345cf579e772767e1f Mon Sep 17 00:00:00 2001 From: David Katleman Date: Thu, 10 Nov 2011 11:46:28 -0800 Subject: [PATCH 086/107] Added tag jdk8-b13 for changeset 5002669612fc --- jaxp/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jaxp/.hgtags b/jaxp/.hgtags index b1a3e0eacf7..e037f606480 100644 --- a/jaxp/.hgtags +++ b/jaxp/.hgtags @@ -134,3 +134,4 @@ de4794dd69c48b08029d158a972993ff9d5627df jdk8-b08 d21a4d5141c04bc9e88f2c0253121d449b66d667 jdk8-b10 d1b7a4f6dd2065fdeafbcdfd9dcc0072da8c6881 jdk8-b11 ca977d167697a561c04894187fc1c4d927582ffa jdk8-b12 +bcc739229f6384786c7ac0b52c1822c85674dcf1 jdk8-b13 From c39cff6af7dd4c6ab1e6840fcae186cf55eaa82e Mon Sep 17 00:00:00 2001 From: David Katleman Date: Thu, 10 Nov 2011 11:46:33 -0800 Subject: [PATCH 087/107] Added tag jdk8-b13 for changeset d4e4b5f54af7 --- jaxws/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jaxws/.hgtags b/jaxws/.hgtags index 712808d6c18..67d2711e9d2 100644 --- a/jaxws/.hgtags +++ b/jaxws/.hgtags @@ -134,3 +134,4 @@ acffff22a9465005e8eb206224fae9f2ea4fd469 jdk8-b06 8e7fdc8e3c758644ca6d0fd70bb255e9d2e64cda jdk8-b10 a12ab897a249feb7859a6e6cd84b49411f4c06ac jdk8-b11 e6eed2ff5d5f62bdc815beb5276d23347600c760 jdk8-b12 +adf2a6b5fde14090beb9ebc40c4114132ddee731 jdk8-b13 From 5ffc2022066bac62065062bd5d30cd54d7a72f03 Mon Sep 17 00:00:00 2001 From: David Katleman Date: Thu, 10 Nov 2011 11:46:54 -0800 Subject: [PATCH 088/107] Added tag jdk8-b13 for changeset 8f6f084a8666 --- jdk/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/.hgtags b/jdk/.hgtags index e1e7ba132b7..540640922bc 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -134,3 +134,4 @@ f1ec21b8142168ff40f3278d2f6b5fe4bd5f3b26 jdk8-b09 4788745572ef2bde34924ef34e7e4d55ba07e979 jdk8-b10 7ab0d613cd1a271a9763ffb894dc1f0a5b95a7e4 jdk8-b11 09fd2067f715e4505c44b01c301258a4e8f8964e jdk8-b12 +4cb2e8679b27432854690cb688ea06d3b2d8e008 jdk8-b13 From 1269b98a270a5bce28aab83587a7f88d92b99ef6 Mon Sep 17 00:00:00 2001 From: David Katleman Date: Thu, 10 Nov 2011 11:47:25 -0800 Subject: [PATCH 089/107] Added tag jdk8-b13 for changeset 7e7229cae97b --- langtools/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/langtools/.hgtags b/langtools/.hgtags index cbf5eea7c0e..ffd905c4f03 100644 --- a/langtools/.hgtags +++ b/langtools/.hgtags @@ -134,3 +134,4 @@ b7a7e47c8d3daf7822abf7c37e5179ccbbf53008 jdk8-b09 f6c783e18bdf4d46a0ab273868afebbf32600ff7 jdk8-b10 4bf01f1c4e3464f378959d10f3983a0469181d94 jdk8-b11 f2d6ed25857dfa7f269ac66e13666d648cb988c6 jdk8-b12 +ae25163501bc7477cd907e26a006a6f1b05fdb6d jdk8-b13 From b83a25de977494e9864707fdfe2f0cccab5fdb0b Mon Sep 17 00:00:00 2001 From: Abhijit Saha Date: Thu, 10 Nov 2011 13:38:47 -0800 Subject: [PATCH 090/107] 7110676: Update jaf source download url for jaxws Reviewed-by: ramap --- jaxws/jaxws.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jaxws/jaxws.properties b/jaxws/jaxws.properties index 96dab59ffd8..f3952bbddc5 100644 --- a/jaxws/jaxws.properties +++ b/jaxws/jaxws.properties @@ -26,14 +26,14 @@ drops.master.copy.base=${drops.dir} jaxws_src.bundle.name=jdk8-jaxws2_2_4-b01-2011_07_22.zip -jaxws_src.bundle.md5.checksum=f64bedd3c512e6b1ca265fda2feb0905 +jaxws_src.bundle.md5.checksum=f64bedd3c512e6b1ca265fda2feb0905 jaxws_src.master.bundle.dir=${drops.master.copy.base} jaxws_src.master.bundle.url.base=http://download.java.net/glassfish/components/jax-ws/openjdk/jdk8 jaf_src.bundle.name=jdk8-jaf-2011_07_22.zip jaf_src.bundle.md5.checksum=18d15dfd71117daadb332af003d08212 jaf_src.master.bundle.dir=${drops.master.copy.base} -jaf_src.master.bundle.url.base=https://java.net/downloads/jax-ws/jdk8 +jaf_src.master.bundle.url.base=http://download.java.net/glassfish/components/jax-ws/openjdk/jdk8 #jaxws_tests.bundle.name=jdk7-jaxws-tests-2009_08_28.zip #jaxws_tests.master.bundle.dir=${drops.master.copy.base} From 9e42e3d20a3e360138984749c71afab9a87de5e2 Mon Sep 17 00:00:00 2001 From: Sean Coffey Date: Fri, 11 Nov 2011 10:08:40 +0000 Subject: [PATCH 091/107] 7105952: Improve finalisation for FileInputStream/FileOutputStream/RandomAccessFile Reviewed-by: alanb --- .../classes/java/io/FileInputStream.java | 48 +++--- .../classes/java/io/FileOutputStream.java | 50 ++----- .../classes/java/io/RandomAccessFile.java | 41 ++--- .../classes/java/io/FileDescriptor.java | 80 ++++++++-- .../classes/java/io/FileDescriptor.java | 80 ++++++++-- .../io/FileDescriptor/FileChannelFDTest.java | 92 ------------ .../Sharing.java} | 140 +++++++++++++----- 7 files changed, 278 insertions(+), 253 deletions(-) delete mode 100644 jdk/test/java/io/FileDescriptor/FileChannelFDTest.java rename jdk/test/java/io/{etc/FileDescriptorSharing.java => FileDescriptor/Sharing.java} (72%) diff --git a/jdk/src/share/classes/java/io/FileInputStream.java b/jdk/src/share/classes/java/io/FileInputStream.java index 9dc19557e54..d796bf090f0 100644 --- a/jdk/src/share/classes/java/io/FileInputStream.java +++ b/jdk/src/share/classes/java/io/FileInputStream.java @@ -124,7 +124,7 @@ class FileInputStream extends InputStream throw new NullPointerException(); } fd = new FileDescriptor(); - fd.incrementAndGetUseCount(); + fd.attach(this); open(name); } @@ -164,10 +164,9 @@ class FileInputStream extends InputStream /* * FileDescriptor is being shared by streams. - * Ensure that it's GC'ed only when all the streams/channels are done - * using it. + * Register this stream with FileDescriptor tracker. */ - fd.incrementAndGetUseCount(); + fd.attach(this); } /** @@ -294,27 +293,14 @@ class FileInputStream extends InputStream closed = true; } if (channel != null) { - /* - * Decrement the FD use count associated with the channel - * The use count is incremented whenever a new channel - * is obtained from this stream. - */ - fd.decrementAndGetUseCount(); channel.close(); } - /* - * Decrement the FD use count associated with this stream - */ - int useCount = fd.decrementAndGetUseCount(); - - /* - * If FileDescriptor is still in use by another stream, we - * will not close it. - */ - if (useCount <= 0) { - close0(); - } + fd.closeAll(new Closeable() { + public void close() throws IOException { + close0(); + } + }); } /** @@ -328,7 +314,9 @@ class FileInputStream extends InputStream * @see java.io.FileDescriptor */ public final FileDescriptor getFD() throws IOException { - if (fd != null) return fd; + if (fd != null) { + return fd; + } throw new IOException(); } @@ -352,13 +340,6 @@ class FileInputStream extends InputStream synchronized (this) { if (channel == null) { channel = FileChannelImpl.open(fd, true, false, this); - - /* - * Increment fd's use count. Invoking the channel's close() - * method will result in decrementing the use count set for - * the channel. - */ - fd.incrementAndGetUseCount(); } return channel; } @@ -381,7 +362,12 @@ class FileInputStream extends InputStream */ protected void finalize() throws IOException { if ((fd != null) && (fd != FileDescriptor.in)) { - close(); + /* if fd is shared, the references in FileDescriptor + * will ensure that finalizer is only called when + * safe to do so. All references using the fd have + * become unreachable. We can call close() + */ + close(); } } } diff --git a/jdk/src/share/classes/java/io/FileOutputStream.java b/jdk/src/share/classes/java/io/FileOutputStream.java index 4a8a724ba15..50bd29bef5f 100644 --- a/jdk/src/share/classes/java/io/FileOutputStream.java +++ b/jdk/src/share/classes/java/io/FileOutputStream.java @@ -197,9 +197,9 @@ class FileOutputStream extends OutputStream throw new NullPointerException(); } this.fd = new FileDescriptor(); + fd.attach(this); this.append = append; - fd.incrementAndGetUseCount(); open(name, append); } @@ -237,12 +237,7 @@ class FileOutputStream extends OutputStream this.fd = fdObj; this.append = false; - /* - * FileDescriptor is being shared by streams. - * Ensure that it's GC'ed only when all the streams/channels are done - * using it. - */ - fd.incrementAndGetUseCount(); + fd.attach(this); } /** @@ -331,27 +326,14 @@ class FileOutputStream extends OutputStream } if (channel != null) { - /* - * Decrement FD use count associated with the channel - * The use count is incremented whenever a new channel - * is obtained from this stream. - */ - fd.decrementAndGetUseCount(); channel.close(); } - /* - * Decrement FD use count associated with this stream - */ - int useCount = fd.decrementAndGetUseCount(); - - /* - * If FileDescriptor is still in use by another stream, we - * will not close it. - */ - if (useCount <= 0) { - close0(); - } + fd.closeAll(new Closeable() { + public void close() throws IOException { + close0(); + } + }); } /** @@ -365,7 +347,9 @@ class FileOutputStream extends OutputStream * @see java.io.FileDescriptor */ public final FileDescriptor getFD() throws IOException { - if (fd != null) return fd; + if (fd != null) { + return fd; + } throw new IOException(); } @@ -390,13 +374,6 @@ class FileOutputStream extends OutputStream synchronized (this) { if (channel == null) { channel = FileChannelImpl.open(fd, false, true, append, this); - - /* - * Increment fd's use count. Invoking the channel's close() - * method will result in decrementing the use count set for - * the channel. - */ - fd.incrementAndGetUseCount(); } return channel; } @@ -415,7 +392,12 @@ class FileOutputStream extends OutputStream if (fd == FileDescriptor.out || fd == FileDescriptor.err) { flush(); } else { - close(); + /* if fd is shared, the references in FileDescriptor + * will ensure that finalizer is only called when + * safe to do so. All references using the fd have + * become unreachable. We can call close() + */ + close(); } } } diff --git a/jdk/src/share/classes/java/io/RandomAccessFile.java b/jdk/src/share/classes/java/io/RandomAccessFile.java index a2863c59a08..65bfbf46c79 100644 --- a/jdk/src/share/classes/java/io/RandomAccessFile.java +++ b/jdk/src/share/classes/java/io/RandomAccessFile.java @@ -229,7 +229,7 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable { throw new NullPointerException(); } fd = new FileDescriptor(); - fd.incrementAndGetUseCount(); + fd.attach(this); open(name, imode); } @@ -242,7 +242,9 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable { * @see java.io.FileDescriptor */ public final FileDescriptor getFD() throws IOException { - if (fd != null) return fd; + if (fd != null) { + return fd; + } throw new IOException(); } @@ -268,17 +270,6 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable { synchronized (this) { if (channel == null) { channel = FileChannelImpl.open(fd, true, rw, this); - - /* - * FileDescriptor could be shared by FileInputStream or - * FileOutputStream. - * Ensure that FD is GC'ed only when all the streams/channels - * are done using it. - * Increment fd's use count. Invoking the channel's close() - * method will result in decrementing the use count set for - * the channel. - */ - fd.incrementAndGetUseCount(); } return channel; } @@ -577,28 +568,14 @@ public class RandomAccessFile implements DataOutput, DataInput, Closeable { closed = true; } if (channel != null) { - /* - * Decrement FD use count associated with the channel. The FD use - * count is incremented whenever a new channel is obtained from - * this stream. - */ - fd.decrementAndGetUseCount(); channel.close(); } - /* - * Decrement FD use count associated with this stream. - * The count got incremented by FileDescriptor during its construction. - */ - int useCount = fd.decrementAndGetUseCount(); - - /* - * If FileDescriptor is still in use by another stream, we - * will not close it. - */ - if (useCount <= 0) { - close0(); - } + fd.closeAll(new Closeable() { + public void close() throws IOException { + close0(); + } + }); } // diff --git a/jdk/src/solaris/classes/java/io/FileDescriptor.java b/jdk/src/solaris/classes/java/io/FileDescriptor.java index 9e7390d8548..1f0d086d745 100644 --- a/jdk/src/solaris/classes/java/io/FileDescriptor.java +++ b/jdk/src/solaris/classes/java/io/FileDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2011, 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 @@ -25,7 +25,8 @@ package java.io; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.ArrayList; +import java.util.List; /** * Instances of the file descriptor class serve as an opaque handle @@ -46,12 +47,9 @@ public final class FileDescriptor { private int fd; - /** - * A counter for tracking the FIS/FOS/RAF instances that - * use this FileDescriptor. The FIS/FOS.finalize() will not release - * the FileDescriptor if it is still under user by a stream. - */ - private AtomicInteger useCount; + private Closeable parent; + private List otherParents; + private boolean closed; /** * Constructs an (invalid) FileDescriptor @@ -59,12 +57,10 @@ public final class FileDescriptor { */ public /**/ FileDescriptor() { fd = -1; - useCount = new AtomicInteger(); } private /* */ FileDescriptor(int fd) { this.fd = fd; - useCount = new AtomicInteger(); } /** @@ -164,13 +160,67 @@ public final class FileDescriptor { ); } - // package private methods used by FIS, FOS and RAF + /* + * Package private methods to track referents. + * If multiple streams point to the same FileDescriptor, we cycle + * through the list of all referents and call close() + */ - int incrementAndGetUseCount() { - return useCount.incrementAndGet(); + /** + * Attach a Closeable to this FD for tracking. + * parent reference is added to otherParents when + * needed to make closeAll simpler. + */ + synchronized void attach(Closeable c) { + if (parent == null) { + // first caller gets to do this + parent = c; + } else if (otherParents == null) { + otherParents = new ArrayList<>(); + otherParents.add(parent); + otherParents.add(c); + } else { + otherParents.add(c); + } } - int decrementAndGetUseCount() { - return useCount.decrementAndGet(); + /** + * Cycle through all Closeables sharing this FD and call + * close() on each one. + * + * The caller closeable gets to call close0(). + */ + @SuppressWarnings("try") + synchronized void closeAll(Closeable releaser) throws IOException { + if (!closed) { + closed = true; + IOException ioe = null; + try (Closeable c = releaser) { + if (otherParents != null) { + for (Closeable referent : otherParents) { + try { + referent.close(); + } catch(IOException x) { + if (ioe == null) { + ioe = x; + } else { + ioe.addSuppressed(x); + } + } + } + } + } catch(IOException ex) { + /* + * If releaser close() throws IOException + * add other exceptions as suppressed. + */ + if (ioe != null) + ex.addSuppressed(ioe); + ioe = ex; + } finally { + if (ioe != null) + throw ioe; + } + } } } diff --git a/jdk/src/windows/classes/java/io/FileDescriptor.java b/jdk/src/windows/classes/java/io/FileDescriptor.java index 606d080989e..bfcda5b497e 100644 --- a/jdk/src/windows/classes/java/io/FileDescriptor.java +++ b/jdk/src/windows/classes/java/io/FileDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2011, 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 @@ -25,7 +25,8 @@ package java.io; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.ArrayList; +import java.util.List; /** * Instances of the file descriptor class serve as an opaque handle @@ -45,13 +46,9 @@ public final class FileDescriptor { private long handle; - /** - * A use counter for tracking the FIS/FOS/RAF instances that - * use this FileDescriptor. The FIS/FOS.finalize() will not release - * the FileDescriptor if it is still under use by any stream. - */ - private AtomicInteger useCount; - + private Closeable parent; + private List otherParents; + private boolean closed; /** * Constructs an (invalid) FileDescriptor @@ -60,7 +57,6 @@ public final class FileDescriptor { public /**/ FileDescriptor() { fd = -1; handle = -1; - useCount = new AtomicInteger(); } static { @@ -168,13 +164,67 @@ public final class FileDescriptor { return desc; } - // package private methods used by FIS, FOS and RAF. + /* + * Package private methods to track referents. + * If multiple streams point to the same FileDescriptor, we cycle + * through the list of all referents and call close() + */ - int incrementAndGetUseCount() { - return useCount.incrementAndGet(); + /** + * Attach a Closeable to this FD for tracking. + * parent reference is added to otherParents when + * needed to make closeAll simpler. + */ + synchronized void attach(Closeable c) { + if (parent == null) { + // first caller gets to do this + parent = c; + } else if (otherParents == null) { + otherParents = new ArrayList<>(); + otherParents.add(parent); + otherParents.add(c); + } else { + otherParents.add(c); + } } - int decrementAndGetUseCount() { - return useCount.decrementAndGet(); + /** + * Cycle through all Closeables sharing this FD and call + * close() on each one. + * + * The caller closeable gets to call close0(). + */ + @SuppressWarnings("try") + synchronized void closeAll(Closeable releaser) throws IOException { + if (!closed) { + closed = true; + IOException ioe = null; + try (Closeable c = releaser) { + if (otherParents != null) { + for (Closeable referent : otherParents) { + try { + referent.close(); + } catch(IOException x) { + if (ioe == null) { + ioe = x; + } else { + ioe.addSuppressed(x); + } + } + } + } + } catch(IOException ex) { + /* + * If releaser close() throws IOException + * add other exceptions as suppressed. + */ + if (ioe != null) + ex.addSuppressed(ioe); + ioe = ex; + } finally { + if (ioe != null) + throw ioe; + } + } } } diff --git a/jdk/test/java/io/FileDescriptor/FileChannelFDTest.java b/jdk/test/java/io/FileDescriptor/FileChannelFDTest.java deleted file mode 100644 index 8a44859079b..00000000000 --- a/jdk/test/java/io/FileDescriptor/FileChannelFDTest.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2006, 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 6322678 - * @summary Test for making sure that fd is closed during - * finalization of a stream, when an associated - * file channel is not available - */ - -import java.io.*; -import java.nio.*; -import java.nio.channels.*; - -public class FileChannelFDTest { - - static byte data[] = new byte[] {48, 49, 50, 51, 52, 53, 54, 55, 56, 57,}; - static String inFileName = "fd-in-test.txt"; - static String outFileName = "fd-out-test.txt"; - static File inFile; - static File outFile; - - private static void writeToInFile() throws IOException { - FileOutputStream out = new FileOutputStream(inFile); - out.write(data); - out.close(); - } - - public static void main(String[] args) - throws Exception { - - inFile= new File(System.getProperty("test.dir", "."), - inFileName); - inFile.createNewFile(); - inFile.deleteOnExit(); - writeToInFile(); - - outFile = new File(System.getProperty("test.dir", "."), - outFileName); - outFile.createNewFile(); - outFile.deleteOnExit(); - - doFileChannel(); - } - - private static void doFileChannel() throws Exception { - - FileInputStream fis = new FileInputStream(inFile); - FileDescriptor fd = fis.getFD(); - FileChannel fc = fis.getChannel(); - System.out.println("Created fis:" + fis); - - /** - * Encourage the GC - */ - fis = null; - fc = null; - System.gc(); - Thread.sleep(500); - - if (fd.valid()) { - throw new Exception("Finalizer either didn't run --" + - "try increasing the Thread's sleep time after System.gc();" + - "or the finalizer didn't close the file"); - } - - System.out.println("File Closed successfully"); - System.out.println(); - } -} diff --git a/jdk/test/java/io/etc/FileDescriptorSharing.java b/jdk/test/java/io/FileDescriptor/Sharing.java similarity index 72% rename from jdk/test/java/io/etc/FileDescriptorSharing.java rename to jdk/test/java/io/FileDescriptor/Sharing.java index d46f61a5282..c340a983ebe 100644 --- a/jdk/test/java/io/etc/FileDescriptorSharing.java +++ b/jdk/test/java/io/FileDescriptor/Sharing.java @@ -23,10 +23,9 @@ /* * @test - * @bug 6322678 7082769 - * @summary FileInputStream/FileOutputStream/RandomAccessFile allow file descriptor - * to be closed while still in use. - * @run main/othervm FileDescriptorSharing + * @bug 7105952 6322678 7082769 + * @summary Improve finalisation for FileInputStream/FileOutputStream/RandomAccessFile + * @run main/othervm Sharing */ import java.io.*; @@ -34,7 +33,7 @@ import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.util.concurrent.CountDownLatch; -public class FileDescriptorSharing { +public class Sharing { final static int numFiles = 10; volatile static boolean fail; @@ -44,11 +43,12 @@ public class FileDescriptorSharing { TestMultipleFD(); TestIsValid(); MultiThreadedFD(); + TestCloseAll(); } /** - * We shouldn't discard a file descriptor until all streams have - * finished with it + * Finalizer shouldn't discard a file descriptor until all streams have + * finished with it. */ private static void TestFinalizer() throws Exception { FileDescriptor fd = null; @@ -96,9 +96,6 @@ public class FileDescriptorSharing { System.out.print("."); ret = fis3.read(); } - if(!fd.valid()) { - throw new RuntimeException("TestFinalizer() : FileDescriptor should be valid"); - } } finally { testFinalizerFile.delete(); } @@ -194,23 +191,19 @@ public class FileDescriptorSharing { } finally { try { if (fis != null) fis.close(); - if (fos != null) fos.close(); - if (!fd.valid()) { - throw new RuntimeException("FileDescriptor should be valid"); - } - if (raf != null) raf.close(); if (fd.valid()) { - throw new RuntimeException("close() called and FileDescriptor still valid"); + throw new RuntimeException("[FIS close()] FileDescriptor shouldn't be valid"); } - } finally { + if (fos != null) fos.close(); if (raf != null) raf.close(); + } finally { test1.delete(); } } /* - * Close out in different order to ensure FD is not - * closed out too early + * Close out in different order to ensure FD is + * closed correctly. */ File test2 = new File("test2"); try { @@ -221,14 +214,11 @@ public class FileDescriptorSharing { } finally { try { if (raf != null) raf.close(); - if (fos != null) fos.close(); - if (!fd.valid()) { - throw new RuntimeException("FileDescriptor should be valid"); - } - if (fis != null) fis.close(); if (fd.valid()) { - throw new RuntimeException("close() called and FileDescriptor still valid"); + throw new RuntimeException("[RAF close()] FileDescriptor shouldn't be valid"); } + if (fos != null) fos.close(); + if (fis != null) fis.close(); } finally { test2.delete(); } @@ -244,14 +234,11 @@ public class FileDescriptorSharing { } finally { try { if (fos != null) fos.close(); - if (raf != null) raf.close(); - if (!fd.valid()) { - throw new RuntimeException("FileDescriptor should be valid"); - } - if (fis != null) fis.close(); if (fd.valid()) { - throw new RuntimeException("close() called and FileDescriptor still valid"); + throw new RuntimeException("[FOS close()] FileDescriptor shouldn't be valid"); } + if (raf != null) raf.close(); + if (fis != null) fis.close(); } finally { test3.delete(); } @@ -259,7 +246,7 @@ public class FileDescriptorSharing { } /** - * Test concurrent access to the same fd.useCount field + * Test concurrent access to the same FileDescriptor */ private static void MultiThreadedFD() throws Exception { RandomAccessFile raf = null; @@ -293,6 +280,68 @@ public class FileDescriptorSharing { } } + /** + * Test closeAll handling in FileDescriptor + */ + private static void TestCloseAll() throws Exception { + File testFile = new File("test"); + testFile.deleteOnExit(); + RandomAccessFile raf = new RandomAccessFile(testFile, "rw"); + FileInputStream fis = new FileInputStream(raf.getFD()); + fis.close(); + if (raf.getFD().valid()) { + throw new RuntimeException("FD should not be valid."); + } + + // Test the suppressed exception handling - FileInputStream + + raf = new RandomAccessFile(testFile, "rw"); + fis = new FileInputStream(raf.getFD()); + BadFileInputStream bfis1 = new BadFileInputStream(raf.getFD()); + BadFileInputStream bfis2 = new BadFileInputStream(raf.getFD()); + BadFileInputStream bfis3 = new BadFileInputStream(raf.getFD()); + // extra test - set bfis3 to null + bfis3 = null; + try { + fis.close(); + } catch (IOException ioe) { + ioe.printStackTrace(); + if (ioe.getSuppressed().length != 2) { + throw new RuntimeException("[FIS]Incorrect number of suppressed " + + "exceptions received : " + ioe.getSuppressed().length); + } + } + if (raf.getFD().valid()) { + // we should still have closed the FD + // even with the exception. + throw new RuntimeException("[FIS]TestCloseAll : FD still valid."); + } + + // Now test with FileOutputStream + + raf = new RandomAccessFile(testFile, "rw"); + FileOutputStream fos = new FileOutputStream(raf.getFD()); + BadFileOutputStream bfos1 = new BadFileOutputStream(raf.getFD()); + BadFileOutputStream bfos2 = new BadFileOutputStream(raf.getFD()); + BadFileOutputStream bfos3 = new BadFileOutputStream(raf.getFD()); + // extra test - set bfos3 to null + bfos3 = null; + try { + fos.close(); + } catch (IOException ioe) { + ioe.printStackTrace(); + if (ioe.getSuppressed().length != 2) { + throw new RuntimeException("[FOS]Incorrect number of suppressed " + + "exceptions received : " + ioe.getSuppressed().length); + } + } + if (raf.getFD().valid()) { + // we should still have closed the FD + // even with the exception. + throw new RuntimeException("[FOS]TestCloseAll : FD still valid."); + } + } + /** * A thread which will open and close a number of FileInputStreams and * FileOutputStreams referencing the same native file descriptor. @@ -325,12 +374,35 @@ public class FileDescriptorSharing { System.out.println("OpenClose encountered IO issue :" + ioe); fail = true; } finally { - if (!fd.valid()) { // fd should still be valid given RAF reference - System.out.println("OpenClose: FileDescriptor should be valid"); + if (fd.valid()) { // fd should not be valid after first close() call + System.out.println("OpenClose: FileDescriptor shouldn't be valid"); fail = true; } done.countDown(); } } } + + private static class BadFileInputStream extends FileInputStream { + + BadFileInputStream(FileDescriptor fd) { + super(fd); + } + + public void close() throws IOException { + throw new IOException("Bad close operation"); + } + } + + private static class BadFileOutputStream extends FileOutputStream { + + BadFileOutputStream(FileDescriptor fd) { + super(fd); + } + + public void close() throws IOException { + throw new IOException("Bad close operation"); + } + } + } From ab7852e1295ddef22a8b8c72a00b91aea32b4f8e Mon Sep 17 00:00:00 2001 From: Xue-Lei Andrew Fan Date: Mon, 14 Nov 2011 01:21:20 -0800 Subject: [PATCH 092/107] 7111548: unexpected debug log message Reviewed-by: wetmore --- jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java b/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java index 5bfdd46c074..acc7b4b5a32 100644 --- a/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java +++ b/jdk/src/share/classes/sun/security/ssl/SSLSocketImpl.java @@ -1453,7 +1453,8 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl { private void closeSocket(boolean selfInitiated) throws IOException { if ((debug != null) && Debug.isOn("ssl")) { - System.out.println(threadName() + ", called closeSocket(selfInitiated)"); + System.out.println(threadName() + + ", called closeSocket(" + selfInitiated + ")"); } if (self == this) { super.close(); From 1dc8937659fccee0f99748fb3cd155e3b6428bce Mon Sep 17 00:00:00 2001 From: Kurchi Subhra Hazra Date: Mon, 14 Nov 2011 10:06:56 +0000 Subject: [PATCH 093/107] 7107020: java.net.PlainSocketImpl.socketSetOption() calls itself Reviewed-by: alanb, chegar --- jdk/src/windows/classes/java/net/PlainSocketImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/src/windows/classes/java/net/PlainSocketImpl.java b/jdk/src/windows/classes/java/net/PlainSocketImpl.java index ea11fa609d8..bcb01f1846b 100644 --- a/jdk/src/windows/classes/java/net/PlainSocketImpl.java +++ b/jdk/src/windows/classes/java/net/PlainSocketImpl.java @@ -314,7 +314,7 @@ class PlainSocketImpl extends AbstractPlainSocketImpl void socketSetOption(int cmd, boolean on, Object value) throws SocketException { - socketSetOption(cmd, on, value); + impl.socketSetOption(cmd, on, value); } int socketGetOption(int opt, Object iaContainerObj) throws SocketException { From 44dd83da701e3c8c22f061e4863dd0720b649b82 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Wed, 16 Nov 2011 11:53:40 +0800 Subject: [PATCH 094/107] 7111579: klist starttime, renewtill, ticket etype Reviewed-by: mullan --- .../krb5/internal/ccache/Credentials.java | 12 +++++ .../security/krb5/internal/tools/Klist.java | 44 ++++++++++++------- 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/jdk/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java b/jdk/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java index da45410dbe0..e040788c68e 100644 --- a/jdk/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java +++ b/jdk/src/share/classes/sun/security/krb5/internal/ccache/Credentials.java @@ -223,6 +223,10 @@ public class Credentials { cname, sname, key, flags, authtime, starttime, endtime, renewTill, caddr); } + public KerberosTime getStartTime() { + return starttime; + } + public KerberosTime getAuthTime() { return authtime; } @@ -231,6 +235,10 @@ public class Credentials { return endtime; } + public KerberosTime getRenewTill() { + return renewTill; + } + public TicketFlags getTicketFlags() { return flags; } @@ -238,4 +246,8 @@ public class Credentials { public int getEType() { return key.getEType(); } + + public int getTktEType() { + return ticket.encPart.getEType(); + } } diff --git a/jdk/src/windows/classes/sun/security/krb5/internal/tools/Klist.java b/jdk/src/windows/classes/sun/security/krb5/internal/tools/Klist.java index ddfe95cd2ff..e892353c482 100644 --- a/jdk/src/windows/classes/sun/security/krb5/internal/tools/Klist.java +++ b/jdk/src/windows/classes/sun/security/krb5/internal/tools/Klist.java @@ -207,7 +207,7 @@ public class Klist { } if (options[2] == 't') { System.out.println("\t Time stamp: " + - reformat(entries[i].getTimeStamp().toDate().toString())); + format(entries[i].getTimeStamp())); } } } @@ -234,30 +234,39 @@ public class Klist { System.out.println("\nDefault principal: " + defaultPrincipal + ", " + creds.length + " entries found.\n"); - String starttime = null; - String endtime = null; - String servicePrincipal = null; - String etype = null; if (creds != null) { for (int i = 0; i < creds.length; i++) { try { - starttime = - reformat(creds[i].getAuthTime().toDate().toString()); - endtime = - reformat(creds[i].getEndTime().toDate().toString()); + String starttime; + String endtime; + String renewTill; + String servicePrincipal; + if (creds[i].getStartTime() != null) { + starttime = format(creds[i].getStartTime()); + } else { + starttime = format(creds[i].getAuthTime()); + } + endtime = format(creds[i].getEndTime()); servicePrincipal = creds[i].getServicePrincipal().toString(); System.out.println("[" + (i + 1) + "] " + " Service Principal: " + servicePrincipal); - System.out.println(" Valid starting: " + starttime); - System.out.println(" Expires: " + endtime); + System.out.println(" Valid starting: " + starttime); + System.out.println(" Expires: " + endtime); + if (creds[i].getRenewTill() != null) { + renewTill = format(creds[i].getRenewTill()); + System.out.println( + " Renew until: " + renewTill); + } if (options[0] == 'e') { - etype = EType.toString(creds[i].getEType()); - System.out.println(" Encryption type: " + etype); + String eskey = EType.toString(creds[i].getEType()); + String etkt = EType.toString(creds[i].getTktEType()); + System.out.println(" EType (skey, tkt): " + + eskey + ", " + etkt); } if (options[1] == 'f') { - System.out.println(" Flags: " + + System.out.println(" Flags: " + creds[i].getTicketFlags().toString()); } if (options[2] == 'a') { @@ -312,13 +321,14 @@ public class Klist { * and yyyy is the year. * @param date the string form of Date object. */ - String reformat(String date) { + private String format(KerberosTime kt) { + String date = kt.toDate().toString(); return (date.substring(4, 7) + " " + date.substring(8, 10) + ", " + date.substring(24) - + " " + date.substring(11, 16)); + + " " + date.substring(11, 19)); } /** - * Printes out the help information. + * Prints out the help information. */ void printHelp() { System.out.println("\nUsage: klist " + From 7e7549fdebf6aff3f2b6af1650a6dad629ae7541 Mon Sep 17 00:00:00 2001 From: Masayoshi Okutsu Date: Wed, 16 Nov 2011 12:57:54 +0900 Subject: [PATCH 095/107] 7111903: (tz) Windows-only: tzmappings needs update for KB2570791 Reviewed-by: peytoia --- jdk/src/windows/lib/tzmappings | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/jdk/src/windows/lib/tzmappings b/jdk/src/windows/lib/tzmappings index 7f6f0d36052..2f34a639b64 100644 --- a/jdk/src/windows/lib/tzmappings +++ b/jdk/src/windows/lib/tzmappings @@ -167,7 +167,7 @@ Greenwich Standard Time:88,89::GMT: Argentina Standard Time:900,900::America/Buenos_Aires: Azerbaijan Standard Time:901,901:AZ:Asia/Baku: Bangladesh Standard Time:902,902::Asia/Dhaka: -Central Brazilian Standard Time:903,903:BR:America/Manaus: +Central Brazilian Standard Time:903,903:BR:America/Cuiaba: Central Standard Time (Mexico):904,904::America/Mexico_City: Georgian Standard Time:905,905:GE:Asia/Tbilisi: Jordan Standard Time:906,906:JO:Asia/Amman: @@ -189,5 +189,7 @@ UTC-11:921,921::GMT-1100: Ulaanbaatar Standard Time:922,922::Asia/Ulaanbaatar: Venezuela Standard Time:923,923::America/Caracas: Magadan Standard Time:924,924::Asia/Magadan: -Western Brazilian Standard Time:925,925:BR:America/Rio_Branco: -Armenian Standard Time:926,926:AM:Asia/Yerevan: +Kaliningrad Standard Time:925,925:RU:Europe/Kaliningrad: +Turkey Standard Time:926,926::Asia/Istanbul: +Western Brazilian Standard Time:927,927:BR:America/Rio_Branco: +Armenian Standard Time:928,928:AM:Asia/Yerevan: From 70b9eef84e07dd73bcec6c3e5811c0aaf5cc062b Mon Sep 17 00:00:00 2001 From: Kumar Srinivasan Date: Wed, 16 Nov 2011 12:23:53 -0800 Subject: [PATCH 096/107] 7112160: jdk8 javadoc failure in jdk/make/docs javadoc: error - java.lang.OutOfMemoryError Reviewed-by: ohair, katleman --- jdk/make/docs/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdk/make/docs/Makefile b/jdk/make/docs/Makefile index 8517654153d..61756eab7e9 100644 --- a/jdk/make/docs/Makefile +++ b/jdk/make/docs/Makefile @@ -71,7 +71,7 @@ include $(BUILDDIR)/common/internal/ImportComponents.gmk ifeq ($(ARCH_DATA_MODEL),64) MAX_VM_MEMORY = 1024 else - MAX_VM_MEMORY = 512 + MAX_VM_MEMORY = 612 endif # List of all possible directories for javadoc to look for sources From f5a4ed3bccf59fae7861a100ffd9664315398619 Mon Sep 17 00:00:00 2001 From: "J. Duke" Date: Wed, 5 Jul 2017 17:53:51 +0200 Subject: [PATCH 097/107] Added tag jdk8-b11 for changeset cc1f5ce8e504 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 8b7157fc99a..07ac4027b55 100644 --- a/.hgtags +++ b/.hgtags @@ -132,3 +132,4 @@ bc5710332b294676661103bb20d47d2ea3ba8def jdk8-b07 24ee504f80412770c6874836cd9e55b536427b1d jdk8-b08 fbf3cabc9e3bb1fcf710941d777cb0400505fbe6 jdk8-b09 f651ce87127980c58e3599daba964eba2f3b4026 jdk8-b10 +cc1f5ce8e504d350e0b0c28c5f84333f8d540132 jdk8-b11 From c17726339a354e520e8b943a3ceb59f0a5460f56 Mon Sep 17 00:00:00 2001 From: "J. Duke" Date: Wed, 5 Jul 2017 17:54:25 +0200 Subject: [PATCH 098/107] Added tag jdk8-b12 for changeset 86db042b3385 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 07ac4027b55..1a5394cb9b0 100644 --- a/.hgtags +++ b/.hgtags @@ -133,3 +133,4 @@ bc5710332b294676661103bb20d47d2ea3ba8def jdk8-b07 fbf3cabc9e3bb1fcf710941d777cb0400505fbe6 jdk8-b09 f651ce87127980c58e3599daba964eba2f3b4026 jdk8-b10 cc1f5ce8e504d350e0b0c28c5f84333f8d540132 jdk8-b11 +86db042b3385c338e17f7664447fdc7d406dd19e jdk8-b12 From 700143865e7b2de65d283db3f573df7fdb36091b Mon Sep 17 00:00:00 2001 From: "J. Duke" Date: Wed, 5 Jul 2017 17:54:56 +0200 Subject: [PATCH 099/107] Added tag jdk8-b13 for changeset 4cc0ef72c812 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index 1a5394cb9b0..7584fc7f74d 100644 --- a/.hgtags +++ b/.hgtags @@ -134,3 +134,4 @@ fbf3cabc9e3bb1fcf710941d777cb0400505fbe6 jdk8-b09 f651ce87127980c58e3599daba964eba2f3b4026 jdk8-b10 cc1f5ce8e504d350e0b0c28c5f84333f8d540132 jdk8-b11 86db042b3385c338e17f7664447fdc7d406dd19e jdk8-b12 +4cc0ef72c812943743ef4765f1100e2fbe2b1a08 jdk8-b13 From 67feae118cd9d9d3f805f5f74e4d4607c1734ecc Mon Sep 17 00:00:00 2001 From: David Katleman Date: Thu, 17 Nov 2011 10:46:02 -0800 Subject: [PATCH 100/107] Added tag jdk8-b14 for changeset 21d97162fe47 --- jdk/.hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/jdk/.hgtags b/jdk/.hgtags index 540640922bc..472ceb82660 100644 --- a/jdk/.hgtags +++ b/jdk/.hgtags @@ -135,3 +135,4 @@ f1ec21b8142168ff40f3278d2f6b5fe4bd5f3b26 jdk8-b09 7ab0d613cd1a271a9763ffb894dc1f0a5b95a7e4 jdk8-b11 09fd2067f715e4505c44b01c301258a4e8f8964e jdk8-b12 4cb2e8679b27432854690cb688ea06d3b2d8e008 jdk8-b13 +99632935785e2038b2fc836da9f2ede69dea294b jdk8-b14 From 29ad75ff833cb4f575276c79bf2223f0f7625475 Mon Sep 17 00:00:00 2001 From: Gary Adams Date: Thu, 17 Nov 2011 15:47:34 -0800 Subject: [PATCH 101/107] 7067691: java/lang/management/PlatformLoggingMXBean/LoggingMXBeanTest.java failing intermittently Reviewed-by: alanb, mchung --- .../LoggingMXBeanTest.java | 21 ++++++++++++++----- .../PlatformLoggingMXBeanTest.java | 13 ++++++++---- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/jdk/test/java/lang/management/PlatformLoggingMXBean/LoggingMXBeanTest.java b/jdk/test/java/lang/management/PlatformLoggingMXBean/LoggingMXBeanTest.java index 17569b4cec1..26b3b661531 100644 --- a/jdk/test/java/lang/management/PlatformLoggingMXBean/LoggingMXBeanTest.java +++ b/jdk/test/java/lang/management/PlatformLoggingMXBean/LoggingMXBeanTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 7024172 + * @bug 7024172 7067691 * @summary Test if proxy for PlatformLoggingMXBean is equivalent * to proxy for LoggingMXBean * @@ -43,6 +43,13 @@ public class LoggingMXBeanTest static String LOGGER_NAME_2 = "com.sun.management.Logger.Logger2"; static String UNKNOWN_LOGGER_NAME = "com.sun.management.Unknown"; + // These instance variables prevent premature logger garbage collection + // See getLogger() weak reference warnings. + Logger logger1; + Logger logger2; + + static LoggingMXBeanTest test; + public static void main(String[] argv) throws Exception { MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); LoggingMXBean proxy = @@ -51,7 +58,7 @@ public class LoggingMXBeanTest LoggingMXBean.class); // test LoggingMXBean proxy - LoggingMXBeanTest p = new LoggingMXBeanTest(proxy); + test = new LoggingMXBeanTest(proxy); // check if the attributes implemented by PlatformLoggingMXBean // and LoggingMXBean return the same value @@ -64,9 +71,9 @@ public class LoggingMXBeanTest // same verification as in java/util/logging/LoggingMXBeanTest2 public LoggingMXBeanTest(LoggingMXBean mbean) throws Exception { - Logger logger1 = Logger.getLogger( LOGGER_NAME_1 ); + logger1 = Logger.getLogger( LOGGER_NAME_1 ); logger1.setLevel(Level.FINE); - Logger logger2 = Logger.getLogger( LOGGER_NAME_2 ); + logger2 = Logger.getLogger( LOGGER_NAME_2 ); logger2.setLevel(null); /* @@ -207,6 +214,7 @@ public class LoggingMXBeanTest // verify logger names List loggers1 = mxbean1.getLoggerNames(); List loggers2 = mxbean2.getLoggerNames(); + if (loggers1.size() != loggers2.size()) throw new RuntimeException("LoggerNames: unmatched number of entries"); List loggers3 = new ArrayList<>(loggers1); @@ -219,7 +227,10 @@ public class LoggingMXBeanTest if (!mxbean1.getLoggerLevel(logger) .equals(mxbean2.getLoggerLevel(logger))) throw new RuntimeException( - "LoggerLevel: unmatched level for " + logger); + "LoggerLevel: unmatched level for " + logger + + ", " + mxbean1.getLoggerLevel(logger) + + ", " + mxbean2.getLoggerLevel(logger)); + if (!mxbean1.getParentLoggerName(logger) .equals(mxbean2.getParentLoggerName(logger))) throw new RuntimeException( diff --git a/jdk/test/java/lang/management/PlatformLoggingMXBean/PlatformLoggingMXBeanTest.java b/jdk/test/java/lang/management/PlatformLoggingMXBean/PlatformLoggingMXBeanTest.java index 3694641351d..9d13b954c14 100644 --- a/jdk/test/java/lang/management/PlatformLoggingMXBean/PlatformLoggingMXBeanTest.java +++ b/jdk/test/java/lang/management/PlatformLoggingMXBean/PlatformLoggingMXBeanTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 6876135 7024172 + * @bug 6876135 7024172 7067691 * * @summary Test PlatformLoggingMXBean * This test performs similar testing as @@ -41,11 +41,15 @@ import java.util.List; public class PlatformLoggingMXBeanTest { - ObjectName objectName = null; static String LOGGER_NAME_1 = "com.sun.management.Logger1"; static String LOGGER_NAME_2 = "com.sun.management.Logger2"; + // Use Logger instance variables to prevent premature garbage collection + // of weak references. + Logger logger1; + Logger logger2; + public PlatformLoggingMXBeanTest() throws Exception { } @@ -135,8 +139,8 @@ public class PlatformLoggingMXBeanTest System.out.println( "*********** Phase 3 ***********" ); System.out.println( "*******************************" ); System.out.println( " Create and test new Loggers" ); - Logger logger1 = Logger.getLogger( LOGGER_NAME_1 ); - Logger logger2 = Logger.getLogger( LOGGER_NAME_2 ); + logger1 = Logger.getLogger( LOGGER_NAME_1 ); + logger2 = Logger.getLogger( LOGGER_NAME_2 ); // check that Level object are returned properly try { @@ -187,6 +191,7 @@ public class PlatformLoggingMXBeanTest System.out.println( " Set and Check the Logger Level" ); log1 = false; log2 = false; + try { // Set the level of logger1 to ALL params = new Object[2]; From 9111a2a768ef2bd5f4e265e0bac73e781abdb214 Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Fri, 18 Nov 2011 16:13:39 +0800 Subject: [PATCH 102/107] 7077172: KerberosTime does not take into account system clock adjustement Reviewed-by: valeriep --- .../security/krb5/internal/KerberosTime.java | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/jdk/src/share/classes/sun/security/krb5/internal/KerberosTime.java b/jdk/src/share/classes/sun/security/krb5/internal/KerberosTime.java index eae48e173ed..1ad85ec50bd 100644 --- a/jdk/src/share/classes/sun/security/krb5/internal/KerberosTime.java +++ b/jdk/src/share/classes/sun/security/krb5/internal/KerberosTime.java @@ -68,8 +68,8 @@ public class KerberosTime implements Cloneable { private int microSeconds; // the last three digits of the microsecond value // The time when this class is loaded. Used in setNow() - private static final long initMilli = System.currentTimeMillis(); - private static final long initMicro = System.nanoTime() / 1000; + private static long initMilli = System.currentTimeMillis(); + private static long initMicro = System.nanoTime() / 1000; private static long syncTime; private static boolean DEBUG = Krb5.DEBUG; @@ -212,9 +212,22 @@ public class KerberosTime implements Cloneable { } public void setNow() { - long microElapsed = System.nanoTime() / 1000 - initMicro; - setTime(initMilli + microElapsed/1000); - microSeconds = (int)(microElapsed % 1000); + long newMilli = System.currentTimeMillis(); + long newMicro = System.nanoTime() / 1000; + long microElapsed = newMicro - initMicro; + long calcMilli = initMilli + microElapsed/1000; + if (calcMilli - newMilli > 100 || newMilli - calcMilli > 100) { + if (DEBUG) { + System.out.println("System time adjusted"); + } + initMilli = newMilli; + initMicro = newMicro; + setTime(newMilli); + microSeconds = 0; + } else { + setTime(calcMilli); + microSeconds = (int)(microElapsed % 1000); + } } public int getMicroSeconds() { From 673ab99f166463480d1fc437861450fc84b533d6 Mon Sep 17 00:00:00 2001 From: Gary Adams Date: Sat, 19 Nov 2011 19:55:19 +0000 Subject: [PATCH 103/107] 6818464: TEST_BUG: java/util/Timer/KillThread.java failing intermittently Reviewed-by: dholmes, alanb, forax --- jdk/test/java/util/Timer/KillThread.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/jdk/test/java/util/Timer/KillThread.java b/jdk/test/java/util/Timer/KillThread.java index 386e569719e..e815c8c2475 100644 --- a/jdk/test/java/util/Timer/KillThread.java +++ b/jdk/test/java/util/Timer/KillThread.java @@ -32,20 +32,25 @@ import java.util.*; public class KillThread { public static void main (String[] args) throws Exception { + final Thread[] tdThread = new Thread[1]; Timer t = new Timer(); // Start a mean event that kills the timer thread t.schedule(new TimerTask() { public void run() { + tdThread[0] = Thread.currentThread(); throw new ThreadDeath(); } }, 0); // Wait for mean event to do the deed and thread to die. try { - Thread.sleep(100); + do { + Thread.sleep(100); + } while(tdThread[0] == null); } catch(InterruptedException e) { } + tdThread[0].join(); // Try to start another event try { From e0de33a847c94aae42b7e9d382b688da19b7482e Mon Sep 17 00:00:00 2001 From: Gary Adams Date: Sat, 19 Nov 2011 19:59:33 +0000 Subject: [PATCH 104/107] 6731620: TEST_BUG: java/util/Timer/Args.java is too optimistic about the execution time of System.out.printf Reviewed-by: dholmes, forax --- jdk/test/java/util/Timer/Args.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/jdk/test/java/util/Timer/Args.java b/jdk/test/java/util/Timer/Args.java index ca3077d3a32..ab8065c8670 100644 --- a/jdk/test/java/util/Timer/Args.java +++ b/jdk/test/java/util/Timer/Args.java @@ -92,19 +92,22 @@ public class Args { new F(){void f(){ t.scheduleAtFixedRate(x, (Date)null, 42); }} ); - final long start = System.currentTimeMillis(); - final Date past = new Date(start - 10500); final CountDownLatch y1 = new CountDownLatch(1); final CountDownLatch y2 = new CountDownLatch(1); final CountDownLatch y3 = new CountDownLatch(11); + final long start = System.currentTimeMillis(); + final Date past = new Date(start - 10500); + schedule( t, counter(y1), past); schedule( t, counter(y2), past, 1000); scheduleAtFixedRate(t, counter(y3), past, 1000); y3.await(); y1.await(); y2.await(); - System.out.printf("elapsed=%d%n", System.currentTimeMillis() - start); - check(System.currentTimeMillis() - start < 500); + + final long elapsed = System.currentTimeMillis() - start; + System.out.printf("elapsed=%d%n", elapsed); + check(elapsed < 500); t.cancel(); From 325b9e4abbb40de1dc83020f5dd955ceed1366e4 Mon Sep 17 00:00:00 2001 From: Gary Adams Date: Sat, 19 Nov 2011 20:03:00 +0000 Subject: [PATCH 105/107] 6860309: TEST_BUG: Insufficient sleep time in java/lang/Runtime/exec/StreamsSurviveDestroy.java Reviewed-by: alanb, dholmes, forax --- .../Runtime/exec/StreamsSurviveDestroy.java | 47 +++++++++++++------ 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/jdk/test/java/lang/Runtime/exec/StreamsSurviveDestroy.java b/jdk/test/java/lang/Runtime/exec/StreamsSurviveDestroy.java index 82d9f9fc0ad..3b51171fd1c 100644 --- a/jdk/test/java/lang/Runtime/exec/StreamsSurviveDestroy.java +++ b/jdk/test/java/lang/Runtime/exec/StreamsSurviveDestroy.java @@ -28,6 +28,7 @@ */ import java.io.*; +import java.util.concurrent.*; public class StreamsSurviveDestroy { @@ -40,15 +41,17 @@ public class StreamsSurviveDestroy { boolean wantInterrupt; boolean acceptException; Exception exc = null; + CountDownLatch latch; Copier(String name, InputStream in, OutputStream out, - boolean ae, boolean wi) + boolean ae, boolean wi, CountDownLatch l) { this.name = name; this.in = in; this.out = out; this.acceptException = ae; this.wantInterrupt = wi; + this.latch = l; setName(name); start(); } @@ -59,6 +62,7 @@ public class StreamsSurviveDestroy { public void run() { byte[] buf = new byte[4242]; + latch.countDown(); for (;;) { try { int n = in.read(buf); @@ -95,13 +99,17 @@ public class StreamsSurviveDestroy { } static void test() throws Exception { + CountDownLatch latch = new CountDownLatch(2); + System.err.println("test"); Process p = Runtime.getRuntime().exec("/bin/cat"); Copier cp1 = new Copier("out", p.getInputStream(), System.err, - false, false); + false, false, latch); Copier cp2 = new Copier("err", p.getErrorStream(), System.err, - false, false); - Thread.sleep(100); + false, false, latch); + latch.await(); // Wait till both Copiers about to read + Thread.sleep(100);// Give both Copiers a chance to start read + p.destroy(); System.err.println(" exit: " + p.waitFor()); cp1.join(); @@ -111,13 +119,17 @@ public class StreamsSurviveDestroy { } static void testCloseBeforeDestroy() throws Exception { + CountDownLatch latch = new CountDownLatch(2); + System.err.println("testCloseBeforeDestroy"); Process p = Runtime.getRuntime().exec("/bin/cat"); Copier cp1 = new Copier("out", p.getInputStream(), System.err, - true, false); + true, false, latch); Copier cp2 = new Copier("err", p.getErrorStream(), System.err, - true, false); - Thread.sleep(100); + true, false, latch); + latch.await(); // Wait till both Copiers about to read + Thread.sleep(100);// Give both Copiers a chance to start read + p.getInputStream().close(); p.getErrorStream().close(); p.destroy(); @@ -129,13 +141,17 @@ public class StreamsSurviveDestroy { } static void testCloseAfterDestroy() throws Exception { + CountDownLatch latch = new CountDownLatch(2); System.err.println("testCloseAfterDestroy"); Process p = Runtime.getRuntime().exec("/bin/cat"); Copier cp1 = new Copier("out", p.getInputStream(), System.err, - true, false); + true, false,latch); Copier cp2 = new Copier("err", p.getErrorStream(), System.err, - true, false); - Thread.sleep(100); + true, false, latch); + + latch.await(); // Wait till both Copiers about to read + Thread.sleep(100);// Give both Copiers a chance to start read + p.destroy(); p.getInputStream().close(); p.getErrorStream().close(); @@ -147,13 +163,16 @@ public class StreamsSurviveDestroy { } static void testInterrupt() throws Exception { + CountDownLatch latch = new CountDownLatch(2); System.err.println("testInterrupt"); Process p = Runtime.getRuntime().exec("/bin/cat"); Copier cp1 = new Copier("out", p.getInputStream(), System.err, - false, true); + false, true, latch); Copier cp2 = new Copier("err", p.getErrorStream(), System.err, - false, true); - Thread.sleep(100); + false, true, latch); + latch.await(); // Wait till both Copiers about to read + Thread.sleep(100);// Give both Copiers a chance to start read + cp1.interrupt(); cp2.interrupt(); Thread.sleep(100); @@ -176,7 +195,5 @@ public class StreamsSurviveDestroy { testCloseBeforeDestroy(); testCloseAfterDestroy(); testInterrupt(); - } - } From 0a416094b606ab2b02e245a4a35aed9bea32060c Mon Sep 17 00:00:00 2001 From: Gary Adams Date: Mon, 21 Nov 2011 12:51:30 +0000 Subject: [PATCH 106/107] 7084033: TEST_BUG: test/java/lang/ThreadGroup/Stop.java fails intermittently Reviewed-by: forax, chegar, dholmes --- jdk/test/java/lang/ThreadGroup/Stop.java | 61 ++++++++++++++++-------- 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/jdk/test/java/lang/ThreadGroup/Stop.java b/jdk/test/java/lang/ThreadGroup/Stop.java index 9c663c31241..4763acc8036 100644 --- a/jdk/test/java/lang/ThreadGroup/Stop.java +++ b/jdk/test/java/lang/ThreadGroup/Stop.java @@ -29,37 +29,58 @@ */ public class Stop implements Runnable { - private static Thread first=null; - private static Thread second=null; - private static ThreadGroup group = new ThreadGroup(""); + private static boolean groupStopped = false ; + private static final Object lock = new Object(); - Stop() { - Thread thread = new Thread(group, this); - if (first == null) - first = thread; - else - second = thread; - - thread.start(); - } + private static final ThreadGroup group = new ThreadGroup(""); + private static final Thread first = new Thread(group, new Stop()); + private static final Thread second = new Thread(group, new Stop()); public void run() { while (true) { + // Give the other thread a chance to start try { - Thread.sleep(1000); // Give other thread a chance to start - if (Thread.currentThread() == first) - group.stop(); - } catch(InterruptedException e){ + Thread.sleep(1000); + } catch (InterruptedException e) { + } + + // When the first thread runs, it will stop the group. + if (Thread.currentThread() == first) { + synchronized (lock) { + try { + group.stop(); + } finally { + // Signal the main thread it is time to check + // that the stopped thread group was successful + groupStopped = true; + lock.notifyAll(); + } + } } } } public static void main(String[] args) throws Exception { - for (int i=0; i<2; i++) - new Stop(); - Thread.sleep(3000); + // Launch two threads as part of the same thread group + first.start(); + second.start(); + + // Wait for the thread group stop to be issued + synchronized(lock){ + while (!groupStopped) { + lock.wait(); + // Give the other thread a chance to stop + Thread.sleep(1000); + } + } + + // Check that the second thread is terminated when the + // first thread terminates the thread group. boolean failed = second.isAlive(); - first.stop(); second.stop(); + + // Clean up any threads that may have not been terminated + first.stop(); + second.stop(); if (failed) throw new RuntimeException("Failure."); } From dbdf12e6a57bfc2ce6a7367784878577b8092f36 Mon Sep 17 00:00:00 2001 From: Gary Adams Date: Mon, 21 Nov 2011 12:57:36 +0000 Subject: [PATCH 107/107] 7114125: TEST_BUG: java/util/Timer/KillThread.java should use volatile cross thread variable declaration Reviewed-by: dholmes, alanb --- jdk/test/java/util/Timer/KillThread.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/jdk/test/java/util/Timer/KillThread.java b/jdk/test/java/util/Timer/KillThread.java index e815c8c2475..dee5eeea208 100644 --- a/jdk/test/java/util/Timer/KillThread.java +++ b/jdk/test/java/util/Timer/KillThread.java @@ -31,14 +31,14 @@ import java.util.*; public class KillThread { + static volatile Thread tdThread; public static void main (String[] args) throws Exception { - final Thread[] tdThread = new Thread[1]; Timer t = new Timer(); // Start a mean event that kills the timer thread t.schedule(new TimerTask() { public void run() { - tdThread[0] = Thread.currentThread(); + tdThread = Thread.currentThread(); throw new ThreadDeath(); } }, 0); @@ -47,10 +47,10 @@ public class KillThread { try { do { Thread.sleep(100); - } while(tdThread[0] == null); + } while(tdThread == null); } catch(InterruptedException e) { } - tdThread[0].join(); + tdThread.join(); // Try to start another event try {