intfc, final MethodHandle target) {
if (!intfc.isInterface() || !Modifier.isPublic(intfc.getModifiers()))
throw new IllegalArgumentException("not a public interface: "+intfc.getName());
final MethodHandle mh;
if (System.getSecurityManager() != null) {
- final int CALLER_FRAME = 2; // 0: Reflection, 1: asInterfaceInstance, 2: caller
- final Class> caller = Reflection.getCallerClass(CALLER_FRAME);
+ final Class> caller = Reflection.getCallerClass();
final ClassLoader ccl = caller != null ? caller.getClassLoader() : null;
ReflectUtil.checkProxyPackageAccess(ccl, intfc);
mh = ccl != null ? bindCaller(target, caller) : target;
diff --git a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java
index f4cad4deaa8..fa3cb607855 100644
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java
@@ -26,13 +26,17 @@
package java.lang.invoke;
import java.lang.reflect.*;
-import sun.invoke.util.ValueConversions;
-import sun.invoke.util.VerifyAccess;
-import sun.invoke.util.Wrapper;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
+import sun.invoke.util.ValueConversions;
+import sun.invoke.util.VerifyAccess;
+import sun.invoke.util.Wrapper;
+import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
+import sun.security.util.SecurityConstants;
import static java.lang.invoke.MethodHandleStatics.*;
import static java.lang.invoke.MethodHandleNatives.Constants.*;
@@ -65,8 +69,9 @@ public class MethodHandles {
* This lookup object is a capability which may be delegated to trusted agents.
* Do not store it in place where untrusted code can access it.
*/
+ @CallerSensitive
public static Lookup lookup() {
- return new Lookup();
+ return new Lookup(Reflection.getCallerClass());
}
/**
@@ -416,18 +421,11 @@ public class MethodHandles {
* for method handle creation.
* Must be called by from a method in this package,
* which in turn is called by a method not in this package.
- *
- * Also, don't make it private, lest javac interpose
- * an access$N method.
*/
- Lookup() {
- this(getCallerClassAtEntryPoint(false), ALL_MODES);
- // make sure we haven't accidentally picked up a privileged class:
- checkUnprivilegedlookupClass(lookupClass);
- }
-
Lookup(Class> lookupClass) {
this(lookupClass, ALL_MODES);
+ // make sure we haven't accidentally picked up a privileged class:
+ checkUnprivilegedlookupClass(lookupClass);
}
private Lookup(Class> lookupClass, int allowedModes) {
@@ -554,20 +552,6 @@ public class MethodHandles {
}
}
- /* Obtain the external caller class, when called from Lookup. or a first-level subroutine. */
- private static Class> getCallerClassAtEntryPoint(boolean inSubroutine) {
- final int CALLER_DEPTH = 4;
- // Stack for the constructor entry point (inSubroutine=false):
- // 0: Reflection.getCC, 1: getCallerClassAtEntryPoint,
- // 2: Lookup., 3: MethodHandles.*, 4: caller
- // The stack is slightly different for a subroutine of a Lookup.find* method:
- // 2: Lookup.*, 3: Lookup.find*.*, 4: caller
- // Note: This should be the only use of getCallerClass in this file.
- assert(Reflection.getCallerClass(CALLER_DEPTH-2) == Lookup.class);
- assert(Reflection.getCallerClass(CALLER_DEPTH-1) == (inSubroutine ? Lookup.class : MethodHandles.class));
- return Reflection.getCallerClass(CALLER_DEPTH);
- }
-
/**
* Produces a method handle for a static method.
* The type of the method handle will be that of the method.
@@ -594,12 +578,14 @@ public class MethodHandles {
* refuses access
* @throws NullPointerException if any argument is null
*/
+ @CallerSensitive
public
MethodHandle findStatic(Class> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
MemberName method = resolveOrFail(REF_invokeStatic, refc, name, type);
- checkSecurityManager(refc, method); // stack walk magic: do not refactor
- Class> callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor
- return getDirectMethod(REF_invokeStatic, refc, method, callerClass);
+ Class> callerClass = Reflection.getCallerClass();
+ checkSecurityManager(refc, method, callerClass);
+ return getDirectMethod(REF_invokeStatic, refc, method,
+ findBoundCallerClass(method, callerClass));
}
/**
@@ -645,6 +631,7 @@ public class MethodHandles {
* refuses access
* @throws NullPointerException if any argument is null
*/
+ @CallerSensitive
public MethodHandle findVirtual(Class> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
if (refc == MethodHandle.class) {
MethodHandle mh = findVirtualForMH(name, type);
@@ -652,9 +639,10 @@ public class MethodHandles {
}
byte refKind = (refc.isInterface() ? REF_invokeInterface : REF_invokeVirtual);
MemberName method = resolveOrFail(refKind, refc, name, type);
- checkSecurityManager(refc, method); // stack walk magic: do not refactor
- Class> callerClass = findBoundCallerClass(method);
- return getDirectMethod(refKind, refc, method, callerClass);
+ Class> callerClass = Reflection.getCallerClass();
+ checkSecurityManager(refc, method, callerClass);
+ return getDirectMethod(refKind, refc, method,
+ findBoundCallerClass(method, callerClass));
}
private MethodHandle findVirtualForMH(String name, MethodType type) {
// these names require special lookups because of the implicit MethodType argument
@@ -691,10 +679,11 @@ public class MethodHandles {
* refuses access
* @throws NullPointerException if any argument is null
*/
+ @CallerSensitive
public MethodHandle findConstructor(Class> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException {
String name = "";
MemberName ctor = resolveOrFail(REF_newInvokeSpecial, refc, name, type);
- checkSecurityManager(refc, ctor); // stack walk magic: do not refactor
+ checkSecurityManager(refc, ctor, Reflection.getCallerClass());
return getDirectConstructor(refc, ctor);
}
@@ -732,14 +721,16 @@ public class MethodHandles {
* refuses access
* @throws NullPointerException if any argument is null
*/
+ @CallerSensitive
public MethodHandle findSpecial(Class> refc, String name, MethodType type,
Class> specialCaller) throws NoSuchMethodException, IllegalAccessException {
checkSpecialCaller(specialCaller);
Lookup specialLookup = this.in(specialCaller);
MemberName method = specialLookup.resolveOrFail(REF_invokeSpecial, refc, name, type);
- checkSecurityManager(refc, method); // stack walk magic: do not refactor
- Class> callerClass = findBoundCallerClass(method);
- return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method, callerClass);
+ Class> callerClass = Reflection.getCallerClass();
+ checkSecurityManager(refc, method, callerClass);
+ return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method,
+ findBoundCallerClass(method, callerClass));
}
/**
@@ -759,9 +750,10 @@ public class MethodHandles {
* refuses access
* @throws NullPointerException if any argument is null
*/
+ @CallerSensitive
public MethodHandle findGetter(Class> refc, String name, Class> type) throws NoSuchFieldException, IllegalAccessException {
MemberName field = resolveOrFail(REF_getField, refc, name, type);
- checkSecurityManager(refc, field); // stack walk magic: do not refactor
+ checkSecurityManager(refc, field, Reflection.getCallerClass());
return getDirectField(REF_getField, refc, field);
}
@@ -782,9 +774,10 @@ public class MethodHandles {
* refuses access
* @throws NullPointerException if any argument is null
*/
+ @CallerSensitive
public MethodHandle findSetter(Class> refc, String name, Class> type) throws NoSuchFieldException, IllegalAccessException {
MemberName field = resolveOrFail(REF_putField, refc, name, type);
- checkSecurityManager(refc, field); // stack walk magic: do not refactor
+ checkSecurityManager(refc, field, Reflection.getCallerClass());
return getDirectField(REF_putField, refc, field);
}
@@ -804,9 +797,10 @@ public class MethodHandles {
* refuses access
* @throws NullPointerException if any argument is null
*/
+ @CallerSensitive
public MethodHandle findStaticGetter(Class> refc, String name, Class> type) throws NoSuchFieldException, IllegalAccessException {
MemberName field = resolveOrFail(REF_getStatic, refc, name, type);
- checkSecurityManager(refc, field); // stack walk magic: do not refactor
+ checkSecurityManager(refc, field, Reflection.getCallerClass());
return getDirectField(REF_getStatic, refc, field);
}
@@ -826,9 +820,10 @@ public class MethodHandles {
* refuses access
* @throws NullPointerException if any argument is null
*/
+ @CallerSensitive
public MethodHandle findStaticSetter(Class> refc, String name, Class> type) throws NoSuchFieldException, IllegalAccessException {
MemberName field = resolveOrFail(REF_putStatic, refc, name, type);
- checkSecurityManager(refc, field); // stack walk magic: do not refactor
+ checkSecurityManager(refc, field, Reflection.getCallerClass());
return getDirectField(REF_putStatic, refc, field);
}
@@ -878,12 +873,14 @@ return mh1;
* refuses access
* @throws NullPointerException if any argument is null
*/
+ @CallerSensitive
public MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
Class extends Object> refc = receiver.getClass(); // may get NPE
MemberName method = resolveOrFail(REF_invokeSpecial, refc, name, type);
- checkSecurityManager(refc, method); // stack walk magic: do not refactor
- Class> callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor
- MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method, callerClass);
+ Class> callerClass = Reflection.getCallerClass();
+ checkSecurityManager(refc, method, callerClass);
+ MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method,
+ findBoundCallerClass(method, callerClass));
return mh.bindReceiver(receiver).setVarargs(method);
}
@@ -908,13 +905,14 @@ return mh1;
* is set and {@code asVarargsCollector} fails
* @throws NullPointerException if the argument is null
*/
+ @CallerSensitive
public MethodHandle unreflect(Method m) throws IllegalAccessException {
MemberName method = new MemberName(m);
byte refKind = method.getReferenceKind();
if (refKind == REF_invokeSpecial)
refKind = REF_invokeVirtual;
assert(method.isMethod());
- Class> callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor
+ Class> callerClass = findBoundCallerClass(method, Reflection.getCallerClass());
Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this;
return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, callerClass);
}
@@ -940,12 +938,13 @@ return mh1;
* is set and {@code asVarargsCollector} fails
* @throws NullPointerException if any argument is null
*/
+ @CallerSensitive
public MethodHandle unreflectSpecial(Method m, Class> specialCaller) throws IllegalAccessException {
checkSpecialCaller(specialCaller);
Lookup specialLookup = this.in(specialCaller);
MemberName method = new MemberName(m, true);
assert(method.isMethod());
- Class> callerClass = findBoundCallerClass(method); // stack walk magic: do not refactor
+ Class> callerClass = findBoundCallerClass(method, Reflection.getCallerClass());
// ignore m.isAccessible: this is a new kind of access
return specialLookup.getDirectMethod(REF_invokeSpecial, method.getDeclaringClass(), method, callerClass);
}
@@ -1050,20 +1049,35 @@ return mh1;
* If this lookup object has private access, then the caller class is the lookupClass.
* Otherwise, it is the caller of the currently executing public API method (e.g., findVirtual).
* This is the same caller class as is used by checkSecurityManager.
- * This function performs stack walk magic: do not refactor it.
*/
- Class> findBoundCallerClass(MemberName m) {
+ Class> findBoundCallerClass(MemberName m, Class> callerAtEntryPoint) {
Class> callerClass = null;
if (MethodHandleNatives.isCallerSensitive(m)) {
// Do not refactor this to a more "logical" place, since it is stack walk magic.
// Note that this is the same expression as in Step 2 below in checkSecurityManager.
callerClass = ((allowedModes & PRIVATE) != 0
? lookupClass // for strong access modes, no extra check
- // next line does stack walk magic; do not refactor:
- : getCallerClassAtEntryPoint(true));
+ : callerAtEntryPoint);
}
return callerClass;
}
+
+ /**
+ * Determine whether a security manager has an overridden
+ * SecurityManager.checkMemberAccess method.
+ */
+ private boolean isCheckMemberAccessOverridden(SecurityManager sm) {
+ final Class extends SecurityManager> cls = sm.getClass();
+ if (cls == SecurityManager.class) return false;
+
+ try {
+ return cls.getMethod("checkMemberAccess", Class.class, int.class).
+ getDeclaringClass() != SecurityManager.class;
+ } catch (NoSuchMethodException e) {
+ throw new InternalError("should not reach here");
+ }
+ }
+
/**
* Perform necessary access checks.
* Determines a trustable caller class to compare with refc, the symbolic reference class.
@@ -1071,46 +1085,55 @@ return mh1;
* Otherwise, it is the caller of the currently executing public API method (e.g., findVirtual).
* This function performs stack walk magic: do not refactor it.
*/
- void checkSecurityManager(Class> refc, MemberName m) {
+ void checkSecurityManager(Class> refc, MemberName m, Class> caller) {
SecurityManager smgr = System.getSecurityManager();
if (smgr == null) return;
if (allowedModes == TRUSTED) return;
+
+ final boolean overridden = isCheckMemberAccessOverridden(smgr);
// Step 1:
- smgr.checkMemberAccess(refc, Member.PUBLIC);
+ {
+ // Default policy is to allow Member.PUBLIC; no need to check
+ // permission if SecurityManager is the default implementation
+ final int which = Member.PUBLIC;
+ final Class> clazz = refc;
+ if (overridden) {
+ // Don't refactor; otherwise break the stack depth for
+ // checkMemberAccess of subclasses of SecurityManager as specified.
+ smgr.checkMemberAccess(clazz, which);
+ }
+ }
+
// Step 2:
Class> callerClass = ((allowedModes & PRIVATE) != 0
? lookupClass // for strong access modes, no extra check
- // next line does stack walk magic; do not refactor:
- : getCallerClassAtEntryPoint(true));
+ : caller);
if (!VerifyAccess.classLoaderIsAncestor(lookupClass, refc) ||
(callerClass != lookupClass &&
!VerifyAccess.classLoaderIsAncestor(callerClass, refc)))
smgr.checkPackageAccess(VerifyAccess.getPackageName(refc));
+
// Step 3:
if (m.isPublic()) return;
Class> defc = m.getDeclaringClass();
- smgr.checkMemberAccess(defc, Member.DECLARED); // STACK WALK HERE
+ {
+ // Inline SecurityManager.checkMemberAccess
+ final int which = Member.DECLARED;
+ final Class> clazz = defc;
+ if (!overridden) {
+ if (caller.getClassLoader() != clazz.getClassLoader()) {
+ smgr.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
+ }
+ } else {
+ // Don't refactor; otherwise break the stack depth for
+ // checkMemberAccess of subclasses of SecurityManager as specified.
+ smgr.checkMemberAccess(clazz, which);
+ }
+ }
+
// Step 4:
if (defc != refc)
smgr.checkPackageAccess(VerifyAccess.getPackageName(defc));
-
- // Comment from SM.checkMemberAccess, where which=DECLARED:
- /*
- * stack depth of 4 should be the caller of one of the
- * methods in java.lang.Class that invoke checkMember
- * access. The stack should look like:
- *
- * someCaller [3]
- * java.lang.Class.someReflectionAPI [2]
- * java.lang.Class.checkMemberAccess [1]
- * SecurityManager.checkMemberAccess [0]
- *
- */
- // For us it is this stack:
- // someCaller [3]
- // Lookup.findSomeMember [2]
- // Lookup.checkSecurityManager [1]
- // SecurityManager.checkMemberAccess [0]
}
void checkMethod(byte refKind, Class> refc, MemberName m) throws IllegalAccessException {
@@ -1237,6 +1260,30 @@ return mh1;
checkMethod(refKind, refc, method);
if (method.isMethodHandleInvoke())
return fakeMethodHandleInvoke(method);
+
+ Class> refcAsSuper;
+ if (refKind == REF_invokeSpecial &&
+ refc != lookupClass() &&
+ refc != (refcAsSuper = lookupClass().getSuperclass()) &&
+ refc.isAssignableFrom(lookupClass())) {
+ assert(!method.getName().equals("")); // not this code path
+ // Per JVMS 6.5, desc. of invokespecial instruction:
+ // If the method is in a superclass of the LC,
+ // and if our original search was above LC.super,
+ // repeat the search (symbolic lookup) from LC.super.
+ // FIXME: MemberName.resolve should handle this instead.
+ MemberName m2 = new MemberName(refcAsSuper,
+ method.getName(),
+ method.getMethodType(),
+ REF_invokeSpecial);
+ m2 = IMPL_NAMES.resolveOrNull(refKind, m2, lookupClassOrNull());
+ if (m2 == null) throw new InternalError(method.toString());
+ method = m2;
+ refc = refcAsSuper;
+ // redo basic checks
+ checkMethod(refKind, refc, method);
+ }
+
MethodHandle mh = DirectMethodHandle.make(refKind, refc, method);
mh = maybeBindCaller(method, mh, callerClass);
mh = mh.setVarargs(method);
diff --git a/jdk/src/share/classes/java/lang/ref/Finalizer.java b/jdk/src/share/classes/java/lang/ref/Finalizer.java
index 4e148c28fdc..cdba65e4820 100644
--- a/jdk/src/share/classes/java/lang/ref/Finalizer.java
+++ b/jdk/src/share/classes/java/lang/ref/Finalizer.java
@@ -38,9 +38,9 @@ final class Finalizer extends FinalReference { /* Package-private; must be in
*/
static native void invokeFinalizeMethod(Object o) throws Throwable;
- static private ReferenceQueue queue = new ReferenceQueue();
- static private Finalizer unfinalized = null;
- static private Object lock = new Object();
+ private static ReferenceQueue queue = new ReferenceQueue();
+ private static Finalizer unfinalized = null;
+ private static final Object lock = new Object();
private Finalizer
next = null,
@@ -142,7 +142,11 @@ final class Finalizer extends FinalReference { /* Package-private; must be in
/* Called by Runtime.runFinalization() */
static void runFinalization() {
forkSecondaryFinalizer(new Runnable() {
+ private volatile boolean running;
public void run() {
+ if (running)
+ return;
+ running = true;
for (;;) {
Finalizer f = (Finalizer)queue.poll();
if (f == null) break;
@@ -155,7 +159,11 @@ final class Finalizer extends FinalReference { /* Package-private; must be in
/* Invoked by java.lang.Shutdown */
static void runAllFinalizers() {
forkSecondaryFinalizer(new Runnable() {
+ private volatile boolean running;
public void run() {
+ if (running)
+ return;
+ running = true;
for (;;) {
Finalizer f;
synchronized (lock) {
@@ -168,10 +176,14 @@ final class Finalizer extends FinalReference { /* Package-private; must be in
}
private static class FinalizerThread extends Thread {
+ private volatile boolean running;
FinalizerThread(ThreadGroup g) {
super(g, "Finalizer");
}
public void run() {
+ if (running)
+ return;
+ running = true;
for (;;) {
try {
Finalizer f = (Finalizer)queue.remove();
diff --git a/jdk/src/share/classes/java/lang/reflect/Constructor.java b/jdk/src/share/classes/java/lang/reflect/Constructor.java
index 14a515fe949..0ed60dc375b 100644
--- a/jdk/src/share/classes/java/lang/reflect/Constructor.java
+++ b/jdk/src/share/classes/java/lang/reflect/Constructor.java
@@ -25,6 +25,7 @@
package java.lang.reflect;
+import sun.reflect.CallerSensitive;
import sun.reflect.ConstructorAccessor;
import sun.reflect.Reflection;
import sun.reflect.generics.repository.ConstructorRepository;
@@ -392,14 +393,14 @@ public final class Constructor extends Executable {
* @exception ExceptionInInitializerError if the initialization provoked
* by this method fails.
*/
+ @CallerSensitive
public T newInstance(Object ... initargs)
throws InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
- Class> caller = Reflection.getCallerClass(2);
-
+ Class> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, null, modifiers);
}
}
diff --git a/jdk/src/share/classes/java/lang/reflect/Field.java b/jdk/src/share/classes/java/lang/reflect/Field.java
index bd2b9ef929f..a25223f68c1 100644
--- a/jdk/src/share/classes/java/lang/reflect/Field.java
+++ b/jdk/src/share/classes/java/lang/reflect/Field.java
@@ -25,6 +25,7 @@
package java.lang.reflect;
+import sun.reflect.CallerSensitive;
import sun.reflect.FieldAccessor;
import sun.reflect.Reflection;
import sun.reflect.generics.repository.FieldRepository;
@@ -376,9 +377,16 @@ class Field extends AccessibleObject implements Member {
* @exception ExceptionInInitializerError if the initialization provoked
* by this method fails.
*/
+ @CallerSensitive
public Object get(Object obj)
throws IllegalArgumentException, IllegalAccessException
{
+ if (!override) {
+ if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+ Class> caller = Reflection.getCallerClass();
+ checkAccess(caller, clazz, obj, modifiers);
+ }
+ }
return getFieldAccessor(obj).get(obj);
}
@@ -404,9 +412,16 @@ class Field extends AccessibleObject implements Member {
* by this method fails.
* @see Field#get
*/
+ @CallerSensitive
public boolean getBoolean(Object obj)
throws IllegalArgumentException, IllegalAccessException
{
+ if (!override) {
+ if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+ Class> caller = Reflection.getCallerClass();
+ checkAccess(caller, clazz, obj, modifiers);
+ }
+ }
return getFieldAccessor(obj).getBoolean(obj);
}
@@ -432,9 +447,16 @@ class Field extends AccessibleObject implements Member {
* by this method fails.
* @see Field#get
*/
+ @CallerSensitive
public byte getByte(Object obj)
throws IllegalArgumentException, IllegalAccessException
{
+ if (!override) {
+ if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+ Class> caller = Reflection.getCallerClass();
+ checkAccess(caller, clazz, obj, modifiers);
+ }
+ }
return getFieldAccessor(obj).getByte(obj);
}
@@ -462,9 +484,16 @@ class Field extends AccessibleObject implements Member {
* by this method fails.
* @see Field#get
*/
+ @CallerSensitive
public char getChar(Object obj)
throws IllegalArgumentException, IllegalAccessException
{
+ if (!override) {
+ if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+ Class> caller = Reflection.getCallerClass();
+ checkAccess(caller, clazz, obj, modifiers);
+ }
+ }
return getFieldAccessor(obj).getChar(obj);
}
@@ -492,9 +521,16 @@ class Field extends AccessibleObject implements Member {
* by this method fails.
* @see Field#get
*/
+ @CallerSensitive
public short getShort(Object obj)
throws IllegalArgumentException, IllegalAccessException
{
+ if (!override) {
+ if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+ Class> caller = Reflection.getCallerClass();
+ checkAccess(caller, clazz, obj, modifiers);
+ }
+ }
return getFieldAccessor(obj).getShort(obj);
}
@@ -522,9 +558,16 @@ class Field extends AccessibleObject implements Member {
* by this method fails.
* @see Field#get
*/
+ @CallerSensitive
public int getInt(Object obj)
throws IllegalArgumentException, IllegalAccessException
{
+ if (!override) {
+ if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+ Class> caller = Reflection.getCallerClass();
+ checkAccess(caller, clazz, obj, modifiers);
+ }
+ }
return getFieldAccessor(obj).getInt(obj);
}
@@ -552,9 +595,16 @@ class Field extends AccessibleObject implements Member {
* by this method fails.
* @see Field#get
*/
+ @CallerSensitive
public long getLong(Object obj)
throws IllegalArgumentException, IllegalAccessException
{
+ if (!override) {
+ if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+ Class> caller = Reflection.getCallerClass();
+ checkAccess(caller, clazz, obj, modifiers);
+ }
+ }
return getFieldAccessor(obj).getLong(obj);
}
@@ -582,9 +632,16 @@ class Field extends AccessibleObject implements Member {
* by this method fails.
* @see Field#get
*/
+ @CallerSensitive
public float getFloat(Object obj)
throws IllegalArgumentException, IllegalAccessException
{
+ if (!override) {
+ if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+ Class> caller = Reflection.getCallerClass();
+ checkAccess(caller, clazz, obj, modifiers);
+ }
+ }
return getFieldAccessor(obj).getFloat(obj);
}
@@ -612,9 +669,16 @@ class Field extends AccessibleObject implements Member {
* by this method fails.
* @see Field#get
*/
+ @CallerSensitive
public double getDouble(Object obj)
throws IllegalArgumentException, IllegalAccessException
{
+ if (!override) {
+ if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+ Class> caller = Reflection.getCallerClass();
+ checkAccess(caller, clazz, obj, modifiers);
+ }
+ }
return getFieldAccessor(obj).getDouble(obj);
}
@@ -684,9 +748,16 @@ class Field extends AccessibleObject implements Member {
* @exception ExceptionInInitializerError if the initialization provoked
* by this method fails.
*/
+ @CallerSensitive
public void set(Object obj, Object value)
throws IllegalArgumentException, IllegalAccessException
{
+ if (!override) {
+ if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+ Class> caller = Reflection.getCallerClass();
+ checkAccess(caller, clazz, obj, modifiers);
+ }
+ }
getFieldAccessor(obj).set(obj, value);
}
@@ -714,9 +785,16 @@ class Field extends AccessibleObject implements Member {
* by this method fails.
* @see Field#set
*/
+ @CallerSensitive
public void setBoolean(Object obj, boolean z)
throws IllegalArgumentException, IllegalAccessException
{
+ if (!override) {
+ if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+ Class> caller = Reflection.getCallerClass();
+ checkAccess(caller, clazz, obj, modifiers);
+ }
+ }
getFieldAccessor(obj).setBoolean(obj, z);
}
@@ -744,9 +822,16 @@ class Field extends AccessibleObject implements Member {
* by this method fails.
* @see Field#set
*/
+ @CallerSensitive
public void setByte(Object obj, byte b)
throws IllegalArgumentException, IllegalAccessException
{
+ if (!override) {
+ if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+ Class> caller = Reflection.getCallerClass();
+ checkAccess(caller, clazz, obj, modifiers);
+ }
+ }
getFieldAccessor(obj).setByte(obj, b);
}
@@ -774,9 +859,16 @@ class Field extends AccessibleObject implements Member {
* by this method fails.
* @see Field#set
*/
+ @CallerSensitive
public void setChar(Object obj, char c)
throws IllegalArgumentException, IllegalAccessException
{
+ if (!override) {
+ if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+ Class> caller = Reflection.getCallerClass();
+ checkAccess(caller, clazz, obj, modifiers);
+ }
+ }
getFieldAccessor(obj).setChar(obj, c);
}
@@ -804,9 +896,16 @@ class Field extends AccessibleObject implements Member {
* by this method fails.
* @see Field#set
*/
+ @CallerSensitive
public void setShort(Object obj, short s)
throws IllegalArgumentException, IllegalAccessException
{
+ if (!override) {
+ if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+ Class> caller = Reflection.getCallerClass();
+ checkAccess(caller, clazz, obj, modifiers);
+ }
+ }
getFieldAccessor(obj).setShort(obj, s);
}
@@ -834,9 +933,16 @@ class Field extends AccessibleObject implements Member {
* by this method fails.
* @see Field#set
*/
+ @CallerSensitive
public void setInt(Object obj, int i)
throws IllegalArgumentException, IllegalAccessException
{
+ if (!override) {
+ if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+ Class> caller = Reflection.getCallerClass();
+ checkAccess(caller, clazz, obj, modifiers);
+ }
+ }
getFieldAccessor(obj).setInt(obj, i);
}
@@ -864,9 +970,16 @@ class Field extends AccessibleObject implements Member {
* by this method fails.
* @see Field#set
*/
+ @CallerSensitive
public void setLong(Object obj, long l)
throws IllegalArgumentException, IllegalAccessException
{
+ if (!override) {
+ if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+ Class> caller = Reflection.getCallerClass();
+ checkAccess(caller, clazz, obj, modifiers);
+ }
+ }
getFieldAccessor(obj).setLong(obj, l);
}
@@ -894,9 +1007,16 @@ class Field extends AccessibleObject implements Member {
* by this method fails.
* @see Field#set
*/
+ @CallerSensitive
public void setFloat(Object obj, float f)
throws IllegalArgumentException, IllegalAccessException
{
+ if (!override) {
+ if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+ Class> caller = Reflection.getCallerClass();
+ checkAccess(caller, clazz, obj, modifiers);
+ }
+ }
getFieldAccessor(obj).setFloat(obj, f);
}
@@ -924,20 +1044,26 @@ class Field extends AccessibleObject implements Member {
* by this method fails.
* @see Field#set
*/
+ @CallerSensitive
public void setDouble(Object obj, double d)
throws IllegalArgumentException, IllegalAccessException
{
+ if (!override) {
+ if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
+ Class> caller = Reflection.getCallerClass();
+ checkAccess(caller, clazz, obj, modifiers);
+ }
+ }
getFieldAccessor(obj).setDouble(obj, d);
}
- // Convenience routine which performs security checks
+ // security check is done before calling this method
private FieldAccessor getFieldAccessor(Object obj)
throws IllegalAccessException
{
- doSecurityCheck(obj);
boolean ov = override;
- FieldAccessor a = (ov)? overrideFieldAccessor : fieldAccessor;
- return (a != null)? a : acquireFieldAccessor(ov);
+ FieldAccessor a = (ov) ? overrideFieldAccessor : fieldAccessor;
+ return (a != null) ? a : acquireFieldAccessor(ov);
}
// NOTE that there is no synchronization used here. It is correct
@@ -982,19 +1108,6 @@ class Field extends AccessibleObject implements Member {
}
}
- // NOTE: be very careful if you change the stack depth of this
- // routine. The depth of the "getCallerClass" call is hardwired so
- // that the compiler can have an easier time if this gets inlined.
- private void doSecurityCheck(Object obj) throws IllegalAccessException {
- if (!override) {
- if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
- Class> caller = Reflection.getCallerClass(4);
-
- checkAccess(caller, clazz, obj, modifiers);
- }
- }
- }
-
/**
* @throws NullPointerException {@inheritDoc}
* @since 1.5
diff --git a/jdk/src/share/classes/java/lang/reflect/Method.java b/jdk/src/share/classes/java/lang/reflect/Method.java
index 1caddd6f522..7c7abe43dff 100644
--- a/jdk/src/share/classes/java/lang/reflect/Method.java
+++ b/jdk/src/share/classes/java/lang/reflect/Method.java
@@ -25,6 +25,7 @@
package java.lang.reflect;
+import sun.reflect.CallerSensitive;
import sun.reflect.MethodAccessor;
import sun.reflect.Reflection;
import sun.reflect.generics.repository.MethodRepository;
@@ -472,14 +473,14 @@ public final class Method extends Executable {
* @exception ExceptionInInitializerError if the initialization
* provoked by this method fails.
*/
+ @CallerSensitive
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
- Class> caller = Reflection.getCallerClass(1);
-
+ Class> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
}
}
diff --git a/jdk/src/share/classes/java/lang/reflect/Proxy.java b/jdk/src/share/classes/java/lang/reflect/Proxy.java
index e946ba3226d..2dd06020b26 100644
--- a/jdk/src/share/classes/java/lang/reflect/Proxy.java
+++ b/jdk/src/share/classes/java/lang/reflect/Proxy.java
@@ -39,6 +39,8 @@ import java.util.Set;
import java.util.List;
import java.util.WeakHashMap;
import sun.misc.ProxyGenerator;
+import sun.misc.VM;
+import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
import sun.reflect.misc.ReflectUtil;
import sun.security.util.SecurityConstants;
@@ -408,28 +410,21 @@ public class Proxy implements java.io.Serializable {
* @throws NullPointerException if the {@code interfaces} array
* argument or any of its elements are {@code null}
*/
+ @CallerSensitive
public static Class> getProxyClass(ClassLoader loader,
Class>... interfaces)
throws IllegalArgumentException
- {
- return getProxyClass0(loader, interfaces); // stack walk magic: do not refactor
- }
-
- private static void checkProxyLoader(ClassLoader ccl,
- ClassLoader loader)
{
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
- if (loader == null && ccl != null) {
- if (!ProxyAccessHelper.allowNullLoader) {
- sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
- }
- }
+ checkProxyAccess(Reflection.getCallerClass(), loader, interfaces);
}
+
+ return getProxyClass0(loader, interfaces);
}
/*
- * Generate a proxy class (caller-sensitive).
+ * Check permissions required to create a Proxy class.
*
* To define a proxy class, it performs the access checks as in
* Class.forName (VM will invoke ClassLoader.checkPackageAccess):
@@ -446,17 +441,28 @@ public class Proxy implements java.io.Serializable {
* will throw IllegalAccessError when the generated proxy class is
* being defined via the defineClass0 method.
*/
- private static Class> getProxyClass0(ClassLoader loader,
- Class>... interfaces) {
+ private static void checkProxyAccess(Class> caller,
+ ClassLoader loader,
+ Class>... interfaces)
+ {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
- final int CALLER_FRAME = 3; // 0: Reflection, 1: getProxyClass0 2: Proxy 3: caller
- final Class> caller = Reflection.getCallerClass(CALLER_FRAME);
- final ClassLoader ccl = caller.getClassLoader();
- checkProxyLoader(ccl, loader);
+ ClassLoader ccl = caller.getClassLoader();
+ if (VM.isSystemDomainLoader(loader) && !VM.isSystemDomainLoader(ccl)) {
+ if (!ProxyAccessHelper.allowNullLoader) {
+ sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
+ }
+ }
ReflectUtil.checkProxyPackageAccess(ccl, interfaces);
}
+ }
+ /**
+ * Generate a proxy class. Must call the checkProxyAccess method
+ * to perform permission checks before calling this.
+ */
+ private static Class> getProxyClass0(ClassLoader loader,
+ Class>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
@@ -698,6 +704,7 @@ public class Proxy implements java.io.Serializable {
* if the invocation handler, {@code h}, is
* {@code null}
*/
+ @CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class>[] interfaces,
InvocationHandler h)
@@ -707,10 +714,15 @@ public class Proxy implements java.io.Serializable {
throw new NullPointerException();
}
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ checkProxyAccess(Reflection.getCallerClass(), loader, interfaces);
+ }
+
/*
* Look up or generate the designated proxy class.
*/
- Class> cl = getProxyClass0(loader, interfaces); // stack walk magic: do not refactor
+ Class> cl = getProxyClass0(loader, interfaces);
/*
* Invoke its constructor with the designated invocation handler.
@@ -718,7 +730,6 @@ public class Proxy implements java.io.Serializable {
try {
final Constructor> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
- SecurityManager sm = System.getSecurityManager();
if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
// create proxy instance with doPrivilege as the proxy class may
// implement non-public interfaces that requires a special permission
diff --git a/jdk/src/share/classes/java/net/AbstractPlainDatagramSocketImpl.java b/jdk/src/share/classes/java/net/AbstractPlainDatagramSocketImpl.java
index 349c9a00836..1ef64fbf0b4 100644
--- a/jdk/src/share/classes/java/net/AbstractPlainDatagramSocketImpl.java
+++ b/jdk/src/share/classes/java/net/AbstractPlainDatagramSocketImpl.java
@@ -122,7 +122,7 @@ abstract class AbstractPlainDatagramSocketImpl extends DatagramSocketImpl
* not connected already.
*/
protected void disconnect() {
- disconnect0(connectedAddress.family);
+ disconnect0(connectedAddress.holder().getFamily());
connected = false;
connectedAddress = null;
connectedPort = -1;
diff --git a/jdk/src/share/classes/java/net/Inet4Address.java b/jdk/src/share/classes/java/net/Inet4Address.java
index a9d8dfcb69f..529257fa90d 100644
--- a/jdk/src/share/classes/java/net/Inet4Address.java
+++ b/jdk/src/share/classes/java/net/Inet4Address.java
@@ -100,27 +100,28 @@ class Inet4Address extends InetAddress {
Inet4Address() {
super();
- hostName = null;
- address = 0;
- family = IPv4;
+ holder().hostName = null;
+ holder().address = 0;
+ holder().family = IPv4;
}
Inet4Address(String hostName, byte addr[]) {
- this.hostName = hostName;
- this.family = IPv4;
+ holder().hostName = hostName;
+ holder().family = IPv4;
if (addr != null) {
if (addr.length == INADDRSZ) {
- address = addr[3] & 0xFF;
+ int address = addr[3] & 0xFF;
address |= ((addr[2] << 8) & 0xFF00);
address |= ((addr[1] << 16) & 0xFF0000);
address |= ((addr[0] << 24) & 0xFF000000);
+ holder().address = address;
}
}
}
Inet4Address(String hostName, int address) {
- this.hostName = hostName;
- this.family = IPv4;
- this.address = address;
+ holder().hostName = hostName;
+ holder().family = IPv4;
+ holder().address = address;
}
/**
@@ -134,8 +135,8 @@ class Inet4Address extends InetAddress {
private Object writeReplace() throws ObjectStreamException {
// will replace the to be serialized 'this' object
InetAddress inet = new InetAddress();
- inet.hostName = this.hostName;
- inet.address = this.address;
+ inet.holder().hostName = holder().getHostName();
+ inet.holder().address = holder().getAddress();
/**
* Prior to 1.4 an InetAddress was created with a family
@@ -143,7 +144,7 @@ class Inet4Address extends InetAddress {
* For compatibility reasons we must therefore write the
* the InetAddress with this family.
*/
- inet.family = 2;
+ inet.holder().family = 2;
return inet;
}
@@ -157,7 +158,7 @@ class Inet4Address extends InetAddress {
* @since JDK1.1
*/
public boolean isMulticastAddress() {
- return ((address & 0xf0000000) == 0xe0000000);
+ return ((holder().getAddress() & 0xf0000000) == 0xe0000000);
}
/**
@@ -167,7 +168,7 @@ class Inet4Address extends InetAddress {
* @since 1.4
*/
public boolean isAnyLocalAddress() {
- return address == 0;
+ return holder().getAddress() == 0;
}
/**
@@ -195,6 +196,7 @@ class Inet4Address extends InetAddress {
// defined in "Documenting Special Use IPv4 Address Blocks
// that have been Registered with IANA" by Bill Manning
// draft-manning-dsua-06.txt
+ int address = holder().getAddress();
return (((address >>> 24) & 0xFF) == 169)
&& (((address >>> 16) & 0xFF) == 254);
}
@@ -211,6 +213,7 @@ class Inet4Address extends InetAddress {
// 10/8 prefix
// 172.16/12 prefix
// 192.168/16 prefix
+ int address = holder().getAddress();
return (((address >>> 24) & 0xFF) == 10)
|| ((((address >>> 24) & 0xFF) == 172)
&& (((address >>> 16) & 0xF0) == 16))
@@ -257,6 +260,7 @@ class Inet4Address extends InetAddress {
*/
public boolean isMCLinkLocal() {
// 224.0.0/24 prefix and ttl == 1
+ int address = holder().getAddress();
return (((address >>> 24) & 0xFF) == 224)
&& (((address >>> 16) & 0xFF) == 0)
&& (((address >>> 8) & 0xFF) == 0);
@@ -272,6 +276,7 @@ class Inet4Address extends InetAddress {
*/
public boolean isMCSiteLocal() {
// 239.255/16 prefix or ttl < 32
+ int address = holder().getAddress();
return (((address >>> 24) & 0xFF) == 239)
&& (((address >>> 16) & 0xFF) == 255);
}
@@ -287,6 +292,7 @@ class Inet4Address extends InetAddress {
*/
public boolean isMCOrgLocal() {
// 239.192 - 239.195
+ int address = holder().getAddress();
return (((address >>> 24) & 0xFF) == 239)
&& (((address >>> 16) & 0xFF) >= 192)
&& (((address >>> 16) & 0xFF) <= 195);
@@ -300,6 +306,7 @@ class Inet4Address extends InetAddress {
* @return the raw IP address of this object.
*/
public byte[] getAddress() {
+ int address = holder().getAddress();
byte[] addr = new byte[INADDRSZ];
addr[0] = (byte) ((address >>> 24) & 0xFF);
@@ -325,7 +332,7 @@ class Inet4Address extends InetAddress {
* @return a hash code value for this IP address.
*/
public int hashCode() {
- return address;
+ return holder().getAddress();
}
/**
@@ -346,7 +353,7 @@ class Inet4Address extends InetAddress {
*/
public boolean equals(Object obj) {
return (obj != null) && (obj instanceof Inet4Address) &&
- (((InetAddress)obj).address == address);
+ (((InetAddress)obj).holder().getAddress() == holder().getAddress());
}
// Utilities
diff --git a/jdk/src/share/classes/java/net/Inet4AddressImpl.java b/jdk/src/share/classes/java/net/Inet4AddressImpl.java
index 367ca22b9aa..6ca2d5c7bf0 100644
--- a/jdk/src/share/classes/java/net/Inet4AddressImpl.java
+++ b/jdk/src/share/classes/java/net/Inet4AddressImpl.java
@@ -40,7 +40,7 @@ class Inet4AddressImpl implements InetAddressImpl {
public synchronized InetAddress anyLocalAddress() {
if (anyLocalAddress == null) {
anyLocalAddress = new Inet4Address(); // {0x00,0x00,0x00,0x00}
- anyLocalAddress.hostName = "0.0.0.0";
+ anyLocalAddress.holder().hostName = "0.0.0.0";
}
return anyLocalAddress;
}
diff --git a/jdk/src/share/classes/java/net/Inet6Address.java b/jdk/src/share/classes/java/net/Inet6Address.java
index 7329b2de687..a2e66f09b70 100644
--- a/jdk/src/share/classes/java/net/Inet6Address.java
+++ b/jdk/src/share/classes/java/net/Inet6Address.java
@@ -210,18 +210,18 @@ class Inet6Address extends InetAddress {
Inet6Address() {
super();
- hostName = null;
+ holder().hostName = null;
ipaddress = new byte[INADDRSZ];
- family = IPv6;
+ holder().family = IPv6;
}
/* checking of value for scope_id should be done by caller
* scope_id must be >= 0, or -1 to indicate not being set
*/
Inet6Address(String hostName, byte addr[], int scope_id) {
- this.hostName = hostName;
+ holder().hostName = hostName;
if (addr.length == INADDRSZ) { // normal IPv6 address
- family = IPv6;
+ holder().family = IPv6;
ipaddress = addr.clone();
}
if (scope_id >= 0) {
@@ -335,9 +335,9 @@ class Inet6Address extends InetAddress {
private void initif(String hostName, byte addr[],NetworkInterface nif)
throws UnknownHostException
{
- this.hostName = hostName;
+ holder().hostName = hostName;
if (addr.length == INADDRSZ) { // normal IPv6 address
- family = IPv6;
+ holder().family = IPv6;
ipaddress = addr.clone();
}
if (nif != null) {
@@ -420,6 +420,11 @@ class Inet6Address extends InetAddress {
*/
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
+
+ if (getClass().getClassLoader() != null) {
+ throw new SecurityException ("invalid address type");
+ }
+
s.defaultReadObject();
if (ifname != null && !ifname.equals("")) {
@@ -447,7 +452,7 @@ class Inet6Address extends InetAddress {
ipaddress.length);
}
- if (family != IPv6) {
+ if (holder().getFamily() != IPv6) {
throw new InvalidObjectException("invalid address family type");
}
}
diff --git a/jdk/src/share/classes/java/net/Inet6AddressImpl.java b/jdk/src/share/classes/java/net/Inet6AddressImpl.java
index 663c77ebccc..6512b998712 100644
--- a/jdk/src/share/classes/java/net/Inet6AddressImpl.java
+++ b/jdk/src/share/classes/java/net/Inet6AddressImpl.java
@@ -81,7 +81,7 @@ class Inet6AddressImpl implements InetAddressImpl {
if (anyLocalAddress == null) {
if (InetAddress.preferIPv6Address) {
anyLocalAddress = new Inet6Address();
- anyLocalAddress.hostName = "::";
+ anyLocalAddress.holder().hostName = "::";
} else {
anyLocalAddress = (new Inet4AddressImpl()).anyLocalAddress();
}
diff --git a/jdk/src/share/classes/java/net/InetAddress.java b/jdk/src/share/classes/java/net/InetAddress.java
index e29d1dbc0d9..1154c9a80f4 100644
--- a/jdk/src/share/classes/java/net/InetAddress.java
+++ b/jdk/src/share/classes/java/net/InetAddress.java
@@ -35,8 +35,12 @@ import java.util.ArrayList;
import java.util.ServiceLoader;
import java.security.AccessController;
import java.io.ObjectStreamException;
+import java.io.ObjectStreamField;
import java.io.IOException;
import java.io.ObjectInputStream;
+import java.io.ObjectInputStream.GetField;
+import java.io.ObjectOutputStream;
+import java.io.ObjectOutputStream.PutField;
import sun.security.action.*;
import sun.net.InetAddressCachePolicy;
import sun.net.util.IPAddressUtil;
@@ -199,25 +203,48 @@ class InetAddress implements java.io.Serializable {
/* Specify address family preference */
static transient boolean preferIPv6Address = false;
- /**
- * @serial
- */
- String hostName;
+ static class InetAddressHolder {
- /**
- * Holds a 32-bit IPv4 address.
- *
- * @serial
- */
- int address;
+ InetAddressHolder() {}
- /**
- * Specifies the address family type, for instance, '1' for IPv4
- * addresses, and '2' for IPv6 addresses.
- *
- * @serial
- */
- int family;
+ InetAddressHolder(String hostName, int address, int family) {
+ this.hostName = hostName;
+ this.address = address;
+ this.family = family;
+ }
+
+ String hostName;
+
+ String getHostName() {
+ return hostName;
+ }
+
+ /**
+ * Holds a 32-bit IPv4 address.
+ */
+ int address;
+
+ int getAddress() {
+ return address;
+ }
+
+ /**
+ * Specifies the address family type, for instance, '1' for IPv4
+ * addresses, and '2' for IPv6 addresses.
+ */
+ int family;
+
+ int getFamily() {
+ return family;
+ }
+ }
+
+ /* Used to store the serializable fields of InetAddress */
+ private final transient InetAddressHolder holder;
+
+ InetAddressHolder holder() {
+ return holder;
+ }
/* Used to store the name service provider */
private static List nameServices = null;
@@ -251,6 +278,7 @@ class InetAddress implements java.io.Serializable {
* put in the address cache, since it is not created by name.
*/
InetAddress() {
+ holder = new InetAddressHolder();
}
/**
@@ -263,7 +291,7 @@ class InetAddress implements java.io.Serializable {
*/
private Object readResolve() throws ObjectStreamException {
// will replace the deserialized 'this' object
- return new Inet4Address(this.hostName, this.address);
+ return new Inet4Address(holder().getHostName(), holder().getAddress());
}
/**
@@ -500,10 +528,10 @@ class InetAddress implements java.io.Serializable {
* @see SecurityManager#checkConnect
*/
String getHostName(boolean check) {
- if (hostName == null) {
- hostName = InetAddress.getHostFromNameService(this, check);
+ if (holder().getHostName() == null) {
+ holder().hostName = InetAddress.getHostFromNameService(this, check);
}
- return hostName;
+ return holder().getHostName();
}
/**
@@ -666,6 +694,7 @@ class InetAddress implements java.io.Serializable {
* @return a string representation of this IP address.
*/
public String toString() {
+ String hostName = holder().getHostName();
return ((hostName != null) ? hostName : "")
+ "/" + getHostAddress();
}
@@ -1522,14 +1551,58 @@ class InetAddress implements java.io.Serializable {
}
}
+ private static final long FIELDS_OFFSET;
+ private static final sun.misc.Unsafe UNSAFE;
+
+ static {
+ try {
+ sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
+ FIELDS_OFFSET = unsafe.objectFieldOffset(
+ InetAddress.class.getDeclaredField("holder")
+ );
+ UNSAFE = unsafe;
+ } catch (ReflectiveOperationException e) {
+ throw new Error(e);
+ }
+ }
+
private void readObject (ObjectInputStream s) throws
IOException, ClassNotFoundException {
- s.defaultReadObject ();
if (getClass().getClassLoader() != null) {
- hostName = null;
- address = 0;
throw new SecurityException ("invalid address type");
}
+ GetField gf = s.readFields();
+ String host = (String)gf.get("hostName", null);
+ int address= gf.get("address", 0);
+ int family= gf.get("family", 0);
+ InetAddressHolder h = new InetAddressHolder(host, address, family);
+ UNSAFE.putObject(this, FIELDS_OFFSET, h);
+ }
+
+ /* needed because the serializable fields no longer exist */
+
+ /**
+ * @serialField hostName String
+ * @serialField address int
+ * @serialField family int
+ */
+ private static final ObjectStreamField[] serialPersistentFields = {
+ new ObjectStreamField("hostName", String.class),
+ new ObjectStreamField("address", int.class),
+ new ObjectStreamField("family", int.class),
+ };
+
+ private void writeObject (ObjectOutputStream s) throws
+ IOException {
+ if (getClass().getClassLoader() != null) {
+ throw new SecurityException ("invalid address type");
+ }
+ PutField pf = s.putFields();
+ pf.put("hostName", holder().getHostName());
+ pf.put("address", holder().getAddress());
+ pf.put("family", holder().getFamily());
+ s.writeFields();
+ s.flush();
}
}
diff --git a/jdk/src/share/classes/java/net/InetSocketAddress.java b/jdk/src/share/classes/java/net/InetSocketAddress.java
index d4322e9b427..4ad95043470 100644
--- a/jdk/src/share/classes/java/net/InetSocketAddress.java
+++ b/jdk/src/share/classes/java/net/InetSocketAddress.java
@@ -87,8 +87,8 @@ public class InetSocketAddress
if (hostname != null)
return hostname;
if (addr != null) {
- if (addr.hostName != null)
- return addr.hostName;
+ if (addr.holder().getHostName() != null)
+ return addr.holder().getHostName();
else
return addr.getHostAddress();
}
diff --git a/jdk/src/share/classes/java/rmi/server/LogStream.java b/jdk/src/share/classes/java/rmi/server/LogStream.java
index 625e841ce8f..60adea3d965 100644
--- a/jdk/src/share/classes/java/rmi/server/LogStream.java
+++ b/jdk/src/share/classes/java/rmi/server/LogStream.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2013, 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
@@ -120,6 +120,13 @@ public class LogStream extends PrintStream {
*/
@Deprecated
public static synchronized void setDefaultStream(PrintStream newDefault) {
+ SecurityManager sm = System.getSecurityManager();
+
+ if (sm != null) {
+ sm.checkPermission(
+ new java.util.logging.LoggingPermission("control", null));
+ }
+
defaultStream = newDefault;
}
diff --git a/jdk/src/share/classes/java/security/AccessController.java b/jdk/src/share/classes/java/security/AccessController.java
index 4e790ffc8da..e7fbe737a8e 100644
--- a/jdk/src/share/classes/java/security/AccessController.java
+++ b/jdk/src/share/classes/java/security/AccessController.java
@@ -26,6 +26,8 @@
package java.security;
import sun.security.util.Debug;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
/**
* The AccessController class is used for access control operations
@@ -264,6 +266,7 @@ public final class AccessController {
* @see java.security.DomainCombiner
*/
+ @CallerSensitive
public static native T doPrivileged(PrivilegedAction action);
/**
@@ -288,14 +291,15 @@ public final class AccessController {
*
* @since 1.6
*/
+ @CallerSensitive
public static T doPrivilegedWithCombiner(PrivilegedAction action) {
-
AccessControlContext acc = getStackAccessControlContext();
if (acc == null) {
return AccessController.doPrivileged(action);
}
DomainCombiner dc = acc.getAssignedCombiner();
- return AccessController.doPrivileged(action, preserveCombiner(dc));
+ return AccessController.doPrivileged(action,
+ preserveCombiner(dc, Reflection.getCallerClass()));
}
@@ -326,6 +330,7 @@ public final class AccessController {
* @see #doPrivileged(PrivilegedAction)
* @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
*/
+ @CallerSensitive
public static native T doPrivileged(PrivilegedAction action,
AccessControlContext context);
@@ -353,6 +358,7 @@ public final class AccessController {
* @see #doPrivilegedWithCombiner(PrivilegedExceptionAction)
* @see java.security.DomainCombiner
*/
+ @CallerSensitive
public static native T
doPrivileged(PrivilegedExceptionAction action)
throws PrivilegedActionException;
@@ -383,34 +389,29 @@ public final class AccessController {
*
* @since 1.6
*/
- public static T doPrivilegedWithCombiner
- (PrivilegedExceptionAction action) throws PrivilegedActionException {
-
+ @CallerSensitive
+ public static T doPrivilegedWithCombiner(PrivilegedExceptionAction action)
+ throws PrivilegedActionException
+ {
AccessControlContext acc = getStackAccessControlContext();
if (acc == null) {
return AccessController.doPrivileged(action);
}
DomainCombiner dc = acc.getAssignedCombiner();
- return AccessController.doPrivileged(action, preserveCombiner(dc));
+ return AccessController.doPrivileged(action,
+ preserveCombiner(dc, Reflection.getCallerClass()));
}
/**
* preserve the combiner across the doPrivileged call
*/
- private static AccessControlContext preserveCombiner
- (DomainCombiner combiner) {
-
- /**
- * callerClass[0] = Reflection.getCallerClass
- * callerClass[1] = AccessController.preserveCombiner
- * callerClass[2] = AccessController.doPrivileged
- * callerClass[3] = caller
- */
- final Class> callerClass = sun.reflect.Reflection.getCallerClass(3);
+ private static AccessControlContext preserveCombiner(DomainCombiner combiner,
+ Class> caller)
+ {
ProtectionDomain callerPd = doPrivileged
(new PrivilegedAction() {
public ProtectionDomain run() {
- return callerClass.getProtectionDomain();
+ return caller.getProtectionDomain();
}
});
@@ -455,6 +456,7 @@ public final class AccessController {
* @see #doPrivileged(PrivilegedAction)
* @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
*/
+ @CallerSensitive
public static native T
doPrivileged(PrivilegedExceptionAction action,
AccessControlContext context)
diff --git a/jdk/src/share/classes/java/sql/DriverManager.java b/jdk/src/share/classes/java/sql/DriverManager.java
index b0ca1cd4dea..b0d8decf40b 100644
--- a/jdk/src/share/classes/java/sql/DriverManager.java
+++ b/jdk/src/share/classes/java/sql/DriverManager.java
@@ -30,6 +30,7 @@ import java.util.ServiceLoader;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.concurrent.CopyOnWriteArrayList;
+import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
@@ -192,14 +193,11 @@ public class DriverManager {
* has been exceeded and has at least tried to cancel the
* current database connection attempt
*/
+ @CallerSensitive
public static Connection getConnection(String url,
java.util.Properties info) throws SQLException {
- // Gets the classloader of the code that called this method, may
- // be null.
- ClassLoader callerCL = DriverManager.getCallerClassLoader();
-
- return (getConnection(url, info, callerCL));
+ return (getConnection(url, info, Reflection.getCallerClass()));
}
/**
@@ -226,14 +224,11 @@ public class DriverManager {
* has been exceeded and has at least tried to cancel the
* current database connection attempt
*/
+ @CallerSensitive
public static Connection getConnection(String url,
String user, String password) throws SQLException {
java.util.Properties info = new java.util.Properties();
- // Gets the classloader of the code that called this method, may
- // be null.
- ClassLoader callerCL = DriverManager.getCallerClassLoader();
-
if (user != null) {
info.put("user", user);
}
@@ -241,7 +236,7 @@ public class DriverManager {
info.put("password", password);
}
- return (getConnection(url, info, callerCL));
+ return (getConnection(url, info, Reflection.getCallerClass()));
}
/**
@@ -259,16 +254,12 @@ public class DriverManager {
* has been exceeded and has at least tried to cancel the
* current database connection attempt
*/
+ @CallerSensitive
public static Connection getConnection(String url)
throws SQLException {
java.util.Properties info = new java.util.Properties();
-
- // Gets the classloader of the code that called this method, may
- // be null.
- ClassLoader callerCL = DriverManager.getCallerClassLoader();
-
- return (getConnection(url, info, callerCL));
+ return (getConnection(url, info, Reflection.getCallerClass()));
}
/**
@@ -282,21 +273,20 @@ public class DriverManager {
* that can connect to the given URL
* @exception SQLException if a database access error occurs
*/
+ @CallerSensitive
public static Driver getDriver(String url)
throws SQLException {
println("DriverManager.getDriver(\"" + url + "\")");
- // Gets the classloader of the code that called this method, may
- // be null.
- ClassLoader callerCL = DriverManager.getCallerClassLoader();
+ Class> callerClass = Reflection.getCallerClass();
// Walk through the loaded registeredDrivers attempting to locate someone
// who understands the given URL.
for (DriverInfo aDriver : registeredDrivers) {
// If the caller does not have permission to load the driver then
// skip it.
- if(isDriverAllowed(aDriver.driver, callerCL)) {
+ if(isDriverAllowed(aDriver.driver, callerClass)) {
try {
if(aDriver.driver.acceptsURL(url)) {
// Success!
@@ -350,20 +340,18 @@ public class DriverManager {
* @param driver the JDBC Driver to drop
* @exception SQLException if a database access error occurs
*/
+ @CallerSensitive
public static synchronized void deregisterDriver(Driver driver)
throws SQLException {
if (driver == null) {
return;
}
- // Gets the classloader of the code that called this method,
- // may be null.
- ClassLoader callerCL = DriverManager.getCallerClassLoader();
println("DriverManager.deregisterDriver: " + driver);
DriverInfo aDriver = new DriverInfo(driver);
if(registeredDrivers.contains(aDriver)) {
- if (isDriverAllowed(driver, callerCL)) {
+ if (isDriverAllowed(driver, Reflection.getCallerClass())) {
registeredDrivers.remove(aDriver);
} else {
// If the caller does not have permission to load the driver then
@@ -384,18 +372,17 @@ public class DriverManager {
*
* @return the list of JDBC Drivers loaded by the caller's class loader
*/
+ @CallerSensitive
public static java.util.Enumeration getDrivers() {
java.util.Vector result = new java.util.Vector<>();
- // Gets the classloader of the code that called this method, may
- // be null.
- ClassLoader callerCL = DriverManager.getCallerClassLoader();
+ Class> callerClass = Reflection.getCallerClass();
// Walk through the loaded registeredDrivers.
for(DriverInfo aDriver : registeredDrivers) {
// If the caller does not have permission to load the driver then
// skip it.
- if(isDriverAllowed(aDriver.driver, callerCL)) {
+ if(isDriverAllowed(aDriver.driver, callerClass)) {
result.addElement(aDriver.driver);
} else {
println(" skipping: " + aDriver.getClass().getName());
@@ -493,17 +480,13 @@ public class DriverManager {
//------------------------------------------------------------------------
- // Internal method used to get the caller's class loader.
- // Replaces the call to the native method
- private static ClassLoader getCallerClassLoader() {
- Class> cc = Reflection.getCallerClass(3);
- ClassLoader cl = (cc != null) ? cc.getClassLoader() : null;
- return cl;
- }
-
-
// Indicates whether the class object that would be created if the code calling
// DriverManager is accessible.
+ private static boolean isDriverAllowed(Driver driver, Class> caller) {
+ ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
+ return isDriverAllowed(driver, callerCL);
+ }
+
private static boolean isDriverAllowed(Driver driver, ClassLoader classLoader) {
boolean result = false;
if(driver != null) {
@@ -556,7 +539,7 @@ public class DriverManager {
*/
try{
while(driversIterator.hasNext()) {
- println(" Loading done by the java.util.ServiceLoader : "+driversIterator.next());
+ driversIterator.next();
}
} catch(Throwable t) {
// Do nothing
@@ -586,18 +569,19 @@ public class DriverManager {
// Worker method called by the public getConnection() methods.
private static Connection getConnection(
- String url, java.util.Properties info, ClassLoader callerCL) throws SQLException {
+ String url, java.util.Properties info, Class> caller) throws SQLException {
/*
* When callerCl is null, we should check the application's
* (which is invoking this class indirectly)
* classloader, so that the JDBC driver class outside rt.jar
* can be loaded from here.
*/
+ ClassLoader callerCL = caller != null ? caller.getClassLoader() : null;
synchronized(DriverManager.class) {
- // synchronize loading of the correct classloader.
- if(callerCL == null) {
- callerCL = Thread.currentThread().getContextClassLoader();
- }
+ // synchronize loading of the correct classloader.
+ if (callerCL == null) {
+ callerCL = Thread.currentThread().getContextClassLoader();
+ }
}
if(url == null) {
diff --git a/jdk/src/share/classes/java/util/Collections.java b/jdk/src/share/classes/java/util/Collections.java
index b6bac484dac..ad36637452b 100644
--- a/jdk/src/share/classes/java/util/Collections.java
+++ b/jdk/src/share/classes/java/util/Collections.java
@@ -28,6 +28,9 @@ import java.io.Serializable;
import java.io.ObjectOutputStream;
import java.io.IOException;
import java.lang.reflect.Array;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Function;
/**
* This class consists exclusively of static methods that operate on or return
@@ -264,8 +267,7 @@ public class Collections {
}
private static
- int indexedBinarySearch(List extends Comparable super T>> list, T key)
- {
+ int indexedBinarySearch(List extends Comparable super T>> list, T key) {
int low = 0;
int high = list.size()-1;
@@ -441,21 +443,21 @@ public class Collections {
/**
* Randomly permutes the specified list using a default source of
* randomness. All permutations occur with approximately equal
- * likelihood.
+ * likelihood.
*
- * The hedge "approximately" is used in the foregoing description because
+ *
The hedge "approximately" is used in the foregoing description because
* default source of randomness is only approximately an unbiased source
* of independently chosen bits. If it were a perfect source of randomly
* chosen bits, then the algorithm would choose permutations with perfect
- * uniformity.
+ * uniformity.
*
- * This implementation traverses the list backwards, from the last element
- * up to the second, repeatedly swapping a randomly selected element into
- * the "current position". Elements are randomly selected from the
+ *
This implementation traverses the list backwards, from the last
+ * element up to the second, repeatedly swapping a randomly selected element
+ * into the "current position". Elements are randomly selected from the
* portion of the list that runs from the first element to the current
- * position, inclusive.
+ * position, inclusive.
*
- * This method runs in linear time. If the specified list does not
+ *
This method runs in linear time. If the specified list does not
* implement the {@link RandomAccess} interface and is large, this
* implementation dumps the specified list into an array before shuffling
* it, and dumps the shuffled array back into the list. This avoids the
@@ -469,9 +471,10 @@ public class Collections {
public static void shuffle(List> list) {
Random rnd = r;
if (rnd == null)
- r = rnd = new Random();
+ r = rnd = new Random(); // harmless race.
shuffle(list, rnd);
}
+
private static Random r;
/**
@@ -1391,6 +1394,67 @@ public class Collections {
public int hashCode() {return m.hashCode();}
public String toString() {return m.toString();}
+ // Override default methods in Map
+ @Override
+ @SuppressWarnings("unchecked")
+ public V getOrDefault(Object k, V defaultValue) {
+ // Safe cast as we don't change the value
+ return ((Map)m).getOrDefault(k, defaultValue);
+ }
+
+ @Override
+ public void forEach(BiConsumer super K, ? super V> action) {
+ m.forEach(action);
+ }
+
+ @Override
+ public void replaceAll(BiFunction super K, ? super V, ? extends V> function) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public V putIfAbsent(K key, V value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean remove(Object key, Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean replace(K key, V oldValue, V newValue) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public V replace(K key, V value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public V computeIfAbsent(K key, Function super K, ? extends V> mappingFunction) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public V computeIfPresent(K key,
+ BiFunction super K, ? super V, ? extends V> remappingFunction) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public V compute(K key,
+ BiFunction super K, ? super V, ? extends V> remappingFunction) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public V merge(K key, V value,
+ BiFunction super V, ? super V, ? extends V> remappingFunction) {
+ throw new UnsupportedOperationException();
+ }
+
/**
* We need this class in addition to UnmodifiableSet as
* Map.Entries themselves permit modification of the backing Map
@@ -1590,9 +1654,9 @@ public class Collections {
*
* Failure to follow this advice may result in non-deterministic behavior.
*
- * The returned collection does not pass the hashCode
- * and equals operations through to the backing collection, but
- * relies on Object's equals and hashCode methods. This is
+ *
The returned collection does not pass the {@code hashCode}
+ * and {@code equals} operations through to the backing collection, but
+ * relies on {@code Object}'s equals and hashCode methods. This is
* necessary to preserve the contracts of these operations in the case
* that the backing collection is a set or a list.
*
@@ -2107,6 +2171,57 @@ public class Collections {
public String toString() {
synchronized (mutex) {return m.toString();}
}
+
+ // Override default methods in Map
+ @Override
+ public V getOrDefault(Object k, V defaultValue) {
+ synchronized (mutex) {return m.getOrDefault(k, defaultValue);}
+ }
+ @Override
+ public void forEach(BiConsumer super K, ? super V> action) {
+ synchronized (mutex) {m.forEach(action);}
+ }
+ @Override
+ public void replaceAll(BiFunction super K, ? super V, ? extends V> function) {
+ synchronized (mutex) {m.replaceAll(function);}
+ }
+ @Override
+ public V putIfAbsent(K key, V value) {
+ synchronized (mutex) {return m.putIfAbsent(key, value);}
+ }
+ @Override
+ public boolean remove(Object key, Object value) {
+ synchronized (mutex) {return m.remove(key, value);}
+ }
+ @Override
+ public boolean replace(K key, V oldValue, V newValue) {
+ synchronized (mutex) {return m.replace(key, oldValue, newValue);}
+ }
+ @Override
+ public V replace(K key, V value) {
+ synchronized (mutex) {return m.replace(key, value);}
+ }
+ @Override
+ public V computeIfAbsent(K key,
+ Function super K, ? extends V> mappingFunction) {
+ synchronized (mutex) {return m.computeIfAbsent(key, mappingFunction);}
+ }
+ @Override
+ public V computeIfPresent(K key,
+ BiFunction super K, ? super V, ? extends V> remappingFunction) {
+ synchronized (mutex) {return m.computeIfPresent(key, remappingFunction);}
+ }
+ @Override
+ public V compute(K key,
+ BiFunction super K, ? super V, ? extends V> remappingFunction) {
+ synchronized (mutex) {return m.compute(key, remappingFunction);}
+ }
+ @Override
+ public V merge(K key, V value,
+ BiFunction super V, ? super V, ? extends V> remappingFunction) {
+ synchronized (mutex) {return m.merge(key, value, remappingFunction);}
+ }
+
private void writeObject(ObjectOutputStream s) throws IOException {
synchronized (mutex) {s.defaultWriteObject();}
}
@@ -2326,6 +2441,8 @@ public class Collections {
}
public Iterator iterator() {
+ // JDK-6363904 - unwrapped iterator could be typecast to
+ // ListIterator with unsafe set()
final Iterator it = c.iterator();
return new Iterator() {
public boolean hasNext() { return it.hasNext(); }
@@ -2652,7 +2769,7 @@ public class Collections {
public List subList(int fromIndex, int toIndex) {
return new CheckedRandomAccessList<>(
- list.subList(fromIndex, toIndex), type);
+ list.subList(fromIndex, toIndex), type);
}
}
@@ -2717,14 +2834,24 @@ public class Collections {
throw new ClassCastException(badValueMsg(value));
}
+ private BiFunction super K, ? super V, ? extends V> typeCheck(
+ BiFunction super K, ? super V, ? extends V> func) {
+ Objects.requireNonNull(func);
+ return (k, v) -> {
+ V newValue = func.apply(k, v);
+ typeCheck(k, newValue);
+ return newValue;
+ };
+ }
+
private String badKeyMsg(Object key) {
return "Attempt to insert " + key.getClass() +
- " key into map with key type " + keyType;
+ " key into map with key type " + keyType;
}
private String badValueMsg(Object value) {
return "Attempt to insert " + value.getClass() +
- " value into map with value type " + valueType;
+ " value into map with value type " + valueType;
}
CheckedMap(Map m, Class keyType, Class valueType) {
@@ -2768,7 +2895,7 @@ public class Collections {
Object v = e.getValue();
typeCheck(k, v);
checked.add(
- new AbstractMap.SimpleImmutableEntry<>((K) k, (V) v));
+ new AbstractMap.SimpleImmutableEntry<>((K)k, (V)v));
}
for (Map.Entry e : checked)
m.put(e.getKey(), e.getValue());
@@ -2782,6 +2909,74 @@ public class Collections {
return entrySet;
}
+ // Override default methods in Map
+ @Override
+ public void forEach(BiConsumer super K, ? super V> action) {
+ m.forEach(action);
+ }
+
+ @Override
+ public void replaceAll(BiFunction super K, ? super V, ? extends V> function) {
+ m.replaceAll(typeCheck(function));
+ }
+
+ @Override
+ public V putIfAbsent(K key, V value) {
+ typeCheck(key, value);
+ return m.putIfAbsent(key, value);
+ }
+
+ @Override
+ public boolean remove(Object key, Object value) {
+ return m.remove(key, value);
+ }
+
+ @Override
+ public boolean replace(K key, V oldValue, V newValue) {
+ typeCheck(key, newValue);
+ return m.replace(key, oldValue, newValue);
+ }
+
+ @Override
+ public V replace(K key, V value) {
+ typeCheck(key, value);
+ return m.replace(key, value);
+ }
+
+ @Override
+ public V computeIfAbsent(K key,
+ Function super K, ? extends V> mappingFunction) {
+ Objects.requireNonNull(mappingFunction);
+ return m.computeIfAbsent(key, k -> {
+ V value = mappingFunction.apply(k);
+ typeCheck(k, value);
+ return value;
+ });
+ }
+
+ @Override
+ public V computeIfPresent(K key,
+ BiFunction super K, ? super V, ? extends V> remappingFunction) {
+ return m.computeIfPresent(key, typeCheck(remappingFunction));
+ }
+
+ @Override
+ public V compute(K key,
+ BiFunction super K, ? super V, ? extends V> remappingFunction) {
+ return m.compute(key, typeCheck(remappingFunction));
+ }
+
+ @Override
+ public V merge(K key, V value,
+ BiFunction super V, ? super V, ? extends V> remappingFunction) {
+ Objects.requireNonNull(remappingFunction);
+ return m.merge(key, value, (v1, v2) -> {
+ V newValue = remappingFunction.apply(v1, v2);
+ typeCheck(null, newValue);
+ return newValue;
+ });
+ }
+
/**
* We need this class in addition to CheckedSet as Map.Entry permits
* modification of the backing Map via the setValue operation. This
@@ -3456,6 +3651,67 @@ public class Collections {
public int hashCode() {return 0;}
+ // Override default methods in Map
+ @Override
+ @SuppressWarnings("unchecked")
+ public V getOrDefault(Object k, V defaultValue) {
+ return defaultValue;
+ }
+
+ @Override
+ public void forEach(BiConsumer super K, ? super V> action) {
+ Objects.requireNonNull(action);
+ }
+
+ @Override
+ public void replaceAll(BiFunction super K, ? super V, ? extends V> function) {
+ Objects.requireNonNull(function);
+ }
+
+ @Override
+ public V putIfAbsent(K key, V value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean remove(Object key, Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean replace(K key, V oldValue, V newValue) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public V replace(K key, V value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public V computeIfAbsent(K key,
+ Function super K, ? extends V> mappingFunction) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public V computeIfPresent(K key,
+ BiFunction super K, ? super V, ? extends V> remappingFunction) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public V compute(K key,
+ BiFunction super K, ? super V, ? extends V> remappingFunction) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public V merge(K key, V value,
+ BiFunction super V, ? super V, ? extends V> remappingFunction) {
+ throw new UnsupportedOperationException();
+ }
+
// Preserves singleton property
private Object readResolve() {
return EMPTY_MAP;
@@ -3619,6 +3875,65 @@ public class Collections {
return values;
}
+ // Override default methods in Map
+ @Override
+ public V getOrDefault(Object key, V defaultValue) {
+ return eq(key, k) ? v : defaultValue;
+ }
+
+ @Override
+ public void forEach(BiConsumer super K, ? super V> action) {
+ action.accept(k, v);
+ }
+
+ @Override
+ public void replaceAll(BiFunction super K, ? super V, ? extends V> function) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public V putIfAbsent(K key, V value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean remove(Object key, Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean replace(K key, V oldValue, V newValue) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public V replace(K key, V value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public V computeIfAbsent(K key,
+ Function super K, ? extends V> mappingFunction) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public V computeIfPresent(K key,
+ BiFunction super K, ? super V, ? extends V> remappingFunction) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public V compute(K key,
+ BiFunction super K, ? super V, ? extends V> remappingFunction) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public V merge(K key, V value,
+ BiFunction super V, ? super V, ? extends V> remappingFunction) {
+ throw new UnsupportedOperationException();
+ }
}
// Miscellaneous
diff --git a/jdk/src/share/classes/java/util/CurrencyData.properties b/jdk/src/share/classes/java/util/CurrencyData.properties
index 198558d05a3..4783af39505 100644
--- a/jdk/src/share/classes/java/util/CurrencyData.properties
+++ b/jdk/src/share/classes/java/util/CurrencyData.properties
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2000, 2013, 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,7 +28,7 @@ formatVersion=1
# Version of the currency code information in this class.
# It is a serial number that accompanies with each amendment.
-dataVersion=154
+dataVersion=155
# List of all valid ISO 4217 currency codes.
# To ensure compatibility, do not remove codes.
@@ -585,7 +585,7 @@ ZW=ZWL
minor0=\
ADP-BEF-BIF-BYB-BYR-CLF-CLP-DJF-ESP-GNF-\
GRD-ISK-ITL-JPY-KMF-KRW-LUF-MGF-PYG-PTE-RWF-\
- TPE-TRL-VND-VUV-XAF-XOF-XPF
+ TPE-TRL-UGX-VND-VUV-XAF-XOF-XPF
minor1=
minor3=\
BHD-IQD-JOD-KWD-LYD-OMR-TND
diff --git a/jdk/src/share/classes/java/util/HashMap.java b/jdk/src/share/classes/java/util/HashMap.java
index d1ac0cf16fe..b40c5c92ffa 100644
--- a/jdk/src/share/classes/java/util/HashMap.java
+++ b/jdk/src/share/classes/java/util/HashMap.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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
@@ -24,7 +24,11 @@
*/
package java.util;
+
import java.io.*;
+import java.util.function.Consumer;
+import java.util.function.BiFunction;
+import java.util.function.Function;
/**
* Hash table based implementation of the Map interface. This
@@ -376,6 +380,13 @@ public class HashMap
return null == entry ? null : entry.getValue();
}
+ @Override
+ public V getOrDefault(Object key, V defaultValue) {
+ Entry entry = getEntry(key);
+
+ return (entry == null) ? defaultValue : entry.getValue();
+ }
+
/**
* Returns true if this map contains a mapping for the
* specified key.
@@ -603,6 +614,261 @@ public class HashMap
return (e == null ? null : e.value);
}
+ // optimized implementations of default methods in Map
+
+ @Override
+ public V putIfAbsent(K key, V value) {
+ if (table == EMPTY_TABLE) {
+ inflateTable(threshold);
+ }
+ int hash = (key == null) ? 0 : hash(key);
+ int i = indexFor(hash, table.length);
+ @SuppressWarnings("unchecked")
+ Entry e = (Entry)table[i];
+ for(; e != null; e = e.next) {
+ if (e.hash == hash && Objects.equals(e.key, key)) {
+ if(e.value != null) {
+ return e.value;
+ }
+ e.value = value;
+ modCount++;
+ e.recordAccess(this);
+ return null;
+ }
+ }
+
+ modCount++;
+ addEntry(hash, key, value, i);
+ return null;
+ }
+
+ @Override
+ public boolean remove(Object key, Object value) {
+ if (isEmpty()) {
+ return false;
+ }
+ int hash = (key == null) ? 0 : hash(key);
+ int i = indexFor(hash, table.length);
+ @SuppressWarnings("unchecked")
+ Entry prev = (Entry)table[i];
+ Entry e = prev;
+
+ while (e != null) {
+ Entry next = e.next;
+ if (e.hash == hash && Objects.equals(e.key, key)) {
+ if (!Objects.equals(e.value, value)) {
+ return false;
+ }
+ modCount++;
+ size--;
+ if (prev == e)
+ table[i] = next;
+ else
+ prev.next = next;
+ e.recordRemoval(this);
+ return true;
+ }
+ prev = e;
+ e = next;
+ }
+
+ return false;
+ }
+
+ @Override
+ public boolean replace(K key, V oldValue, V newValue) {
+ if (isEmpty()) {
+ return false;
+ }
+ int hash = (key == null) ? 0 : hash(key);
+ int i = indexFor(hash, table.length);
+ @SuppressWarnings("unchecked")
+ Entry e = (Entry)table[i];
+ for (; e != null; e = e.next) {
+ if (e.hash == hash && Objects.equals(e.key, key) && Objects.equals(e.value, oldValue)) {
+ e.value = newValue;
+ e.recordAccess(this);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public V replace(K key, V value) {
+ if (isEmpty()) {
+ return null;
+ }
+ int hash = (key == null) ? 0 : hash(key);
+ int i = indexFor(hash, table.length);
+ @SuppressWarnings("unchecked")
+ Entry e = (Entry)table[i];
+ for (; e != null; e = e.next) {
+ if (e.hash == hash && Objects.equals(e.key, key)) {
+ V oldValue = e.value;
+ e.value = value;
+ e.recordAccess(this);
+ return oldValue;
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public V computeIfAbsent(K key, Function super K, ? extends V> mappingFunction) {
+ if (table == EMPTY_TABLE) {
+ inflateTable(threshold);
+ }
+ int hash = (key == null) ? 0 : hash(key);
+ int i = indexFor(hash, table.length);
+ @SuppressWarnings("unchecked")
+ Entry e = (Entry)table[i];
+ for (; e != null; e = e.next) {
+ if (e.hash == hash && Objects.equals(e.key, key)) {
+ V oldValue = e.value;
+ return oldValue == null ? (e.value = mappingFunction.apply(key)) : oldValue;
+ }
+ }
+
+ V newValue = mappingFunction.apply(key);
+ if (newValue != null) {
+ modCount++;
+ addEntry(hash, key, newValue, i);
+ }
+
+ return newValue;
+ }
+
+ @Override
+ public V computeIfPresent(K key, BiFunction super K, ? super V, ? extends V> remappingFunction) {
+ if (isEmpty()) {
+ return null;
+ }
+ int hash = (key == null) ? 0 : hash(key);
+ int i = indexFor(hash, table.length);
+ @SuppressWarnings("unchecked")
+ Entry prev = (Entry)table[i];
+ Entry e = prev;
+
+ while (e != null) {
+ Entry next = e.next;
+ if (e.hash == hash && Objects.equals(e.key, key)) {
+ V oldValue = e.value;
+ if (oldValue == null)
+ break;
+ V newValue = remappingFunction.apply(key, oldValue);
+ modCount++;
+ if (newValue == null) {
+ size--;
+ if (prev == e)
+ table[i] = next;
+ else
+ prev.next = next;
+ e.recordRemoval(this);
+ } else {
+ e.value = newValue;
+ e.recordAccess(this);
+ }
+ return newValue;
+ }
+ prev = e;
+ e = next;
+ }
+
+ return null;
+ }
+
+ @Override
+ public V compute(K key, BiFunction super K, ? super V, ? extends V> remappingFunction) {
+ if (table == EMPTY_TABLE) {
+ inflateTable(threshold);
+ }
+ int hash = (key == null) ? 0 : hash(key);
+ int i = indexFor(hash, table.length);
+ @SuppressWarnings("unchecked")
+ Entry prev = (Entry)table[i];
+ Entry e = prev;
+
+ while (e != null) {
+ Entry next = e.next;
+ if (e.hash == hash && Objects.equals(e.key, key)) {
+ V oldValue = e.value;
+ V newValue = remappingFunction.apply(key, oldValue);
+ if (newValue != oldValue) {
+ modCount++;
+ if (newValue == null) {
+ size--;
+ if (prev == e)
+ table[i] = next;
+ else
+ prev.next = next;
+ e.recordRemoval(this);
+ } else {
+ e.value = newValue;
+ e.recordAccess(this);
+ }
+ }
+ return newValue;
+ }
+ prev = e;
+ e = next;
+ }
+
+ V newValue = remappingFunction.apply(key, null);
+ if (newValue != null) {
+ modCount++;
+ addEntry(hash, key, newValue, i);
+ }
+
+ return newValue;
+ }
+
+ @Override
+ public V merge(K key, V value, BiFunction super V, ? super V, ? extends V> remappingFunction) {
+ if (table == EMPTY_TABLE) {
+ inflateTable(threshold);
+ }
+ int hash = (key == null) ? 0 : hash(key);
+ int i = indexFor(hash, table.length);
+ @SuppressWarnings("unchecked")
+ Entry prev = (Entry)table[i];
+ Entry e = prev;
+
+ while (e != null) {
+ Entry next = e.next;
+ if (e.hash == hash && Objects.equals(e.key, key)) {
+ V oldValue = e.value;
+ V newValue = remappingFunction.apply(oldValue, value);
+ modCount++;
+ if (newValue == null) {
+ size--;
+ if (prev == e)
+ table[i] = next;
+ else
+ prev.next = next;
+ e.recordRemoval(this);
+ } else {
+ e.value = newValue;
+ e.recordAccess(this);
+ }
+ return newValue;
+ }
+ prev = e;
+ e = next;
+ }
+
+ if (value != null) {
+ modCount++;
+ addEntry(hash, key, value, i);
+ }
+
+ return value;
+ }
+
+ // end of optimized implementations of default methods in Map
+
/**
* Removes and returns the entry associated with the specified key
* in the HashMap. Returns null if the HashMap contains no mapping
@@ -697,8 +963,8 @@ public class HashMap
return containsNullValue();
Entry,?>[] tab = table;
- for (int i = 0; i < tab.length ; i++)
- for (Entry,?> e = tab[i] ; e != null ; e = e.next)
+ for (int i = 0; i < tab.length; i++)
+ for (Entry,?> e = tab[i]; e != null; e = e.next)
if (value.equals(e.value))
return true;
return false;
@@ -709,8 +975,8 @@ public class HashMap
*/
private boolean containsNullValue() {
Entry,?>[] tab = table;
- for (int i = 0; i < tab.length ; i++)
- for (Entry,?> e = tab[i] ; e != null ; e = e.next)
+ for (int i = 0; i < tab.length; i++)
+ for (Entry,?> e = tab[i]; e != null; e = e.next)
if (e.value == null)
return true;
return false;
diff --git a/jdk/src/share/classes/java/util/Hashtable.java b/jdk/src/share/classes/java/util/Hashtable.java
index f973c3ac718..1e38fcaa43b 100644
--- a/jdk/src/share/classes/java/util/Hashtable.java
+++ b/jdk/src/share/classes/java/util/Hashtable.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2013, 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
@@ -24,7 +24,11 @@
*/
package java.util;
+
import java.io.*;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
+import java.util.function.BiFunction;
/**
* This class implements a hash table, which maps keys to values. Any
@@ -455,6 +459,26 @@ public class Hashtable
}
}
+ private void addEntry(int hash, K key, V value, int index) {
+ modCount++;
+
+ Entry,?> tab[] = table;
+ if (count >= threshold) {
+ // Rehash the table if the threshold is exceeded
+ rehash();
+
+ tab = table;
+ hash = hash(key);
+ index = (hash & 0x7FFFFFFF) % tab.length;
+ }
+
+ // Creates the new entry.
+ @SuppressWarnings("unchecked")
+ Entry e = (Entry) tab[index];
+ tab[index] = new Entry<>(hash, key, value, e);
+ count++;
+ }
+
/**
* Maps the specified key
to the specified
* value
in this hashtable. Neither the key nor the
@@ -492,21 +516,7 @@ public class Hashtable
}
}
- modCount++;
- if (count >= threshold) {
- // Rehash the table if the threshold is exceeded
- rehash();
-
- tab = table;
- hash = hash(key);
- index = (hash & 0x7FFFFFFF) % tab.length;
- }
-
- // Creates the new entry.
- @SuppressWarnings("unchecked")
- Entry e = (Entry)tab[index];
- tab[index] = new Entry<>(hash, key, value, e);
- count++;
+ addEntry(hash, key, value, index);
return null;
}
@@ -892,6 +902,239 @@ public class Hashtable
return h;
}
+ @Override
+ public synchronized V getOrDefault(Object key, V defaultValue) {
+ V result = get(key);
+ return (null == result) ? defaultValue : result;
+ }
+
+ @Override
+ public synchronized void forEach(BiConsumer super K, ? super V> action) {
+ Objects.requireNonNull(action); // explicit check required in case
+ // table is empty.
+ Entry,?>[] tab = table;
+ for (Entry,?> entry : tab) {
+ while (entry != null) {
+ action.accept((K)entry.key, (V)entry.value);
+ entry = entry.next;
+ }
+ }
+ }
+
+ @Override
+ public synchronized void replaceAll(
+ BiFunction super K, ? super V, ? extends V> function) {
+ Map.super.replaceAll(function);
+ }
+
+ @Override
+ public synchronized V putIfAbsent(K key, V value) {
+ Objects.requireNonNull(value);
+
+ // Makes sure the key is not already in the hashtable.
+ Entry,?> tab[] = table;
+ int hash = hash(key);
+ int index = (hash & 0x7FFFFFFF) % tab.length;
+ @SuppressWarnings("unchecked")
+ Entry entry = (Entry)tab[index];
+ for (; entry != null; entry = entry.next) {
+ if ((entry.hash == hash) && entry.key.equals(key)) {
+ V old = entry.value;
+ if (old == null) {
+ entry.value = value;
+ }
+ return old;
+ }
+ }
+
+ addEntry(hash, key, value, index);
+ return null;
+ }
+
+ @Override
+ public synchronized boolean remove(Object key, Object value) {
+ Objects.requireNonNull(value);
+
+ Entry,?> tab[] = table;
+ int hash = hash(key);
+ int index = (hash & 0x7FFFFFFF) % tab.length;
+ @SuppressWarnings("unchecked")
+ Entry e = (Entry)tab[index];
+ for (Entry prev = null; e != null; prev = e, e = e.next) {
+ if ((e.hash == hash) && e.key.equals(key) && e.value.equals(value)) {
+ modCount++;
+ if (prev != null) {
+ prev.next = e.next;
+ } else {
+ tab[index] = e.next;
+ }
+ count--;
+ e.value = null;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public synchronized boolean replace(K key, V oldValue, V newValue) {
+ Entry,?> tab[] = table;
+ int hash = hash(key);
+ int index = (hash & 0x7FFFFFFF) % tab.length;
+ @SuppressWarnings("unchecked")
+ Entry e = (Entry)tab[index];
+ for (; e != null; e = e.next) {
+ if ((e.hash == hash) && e.key.equals(key)) {
+ if (e.value.equals(oldValue)) {
+ e.value = newValue;
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public synchronized V replace(K key, V value) {
+ Entry,?> tab[] = table;
+ int hash = hash(key);
+ int index = (hash & 0x7FFFFFFF) % tab.length;
+ @SuppressWarnings("unchecked")
+ Entry e = (Entry)tab[index];
+ for (; e != null; e = e.next) {
+ if ((e.hash == hash) && e.key.equals(key)) {
+ V oldValue = e.value;
+ e.value = value;
+ return oldValue;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public synchronized V computeIfAbsent(K key, Function super K, ? extends V> mappingFunction) {
+ Objects.requireNonNull(mappingFunction);
+
+ Entry,?> tab[] = table;
+ int hash = hash(key);
+ int index = (hash & 0x7FFFFFFF) % tab.length;
+ @SuppressWarnings("unchecked")
+ Entry e = (Entry)tab[index];
+ for (; e != null; e = e.next) {
+ if (e.hash == hash && e.key.equals(key)) {
+ // Hashtable not accept null value
+ return e.value;
+ }
+ }
+
+ V newValue = mappingFunction.apply(key);
+ if (newValue != null) {
+ addEntry(hash, key, newValue, index);
+ }
+
+ return newValue;
+ }
+
+ @Override
+ public V computeIfPresent(K key, BiFunction super K, ? super V, ? extends V> remappingFunction) {
+ Objects.requireNonNull(remappingFunction);
+
+ Entry,?> tab[] = table;
+ int hash = hash(key);
+ int index = (hash & 0x7FFFFFFF) % tab.length;
+ @SuppressWarnings("unchecked")
+ Entry e = (Entry)tab[index];
+ for (Entry prev = null; e != null; prev = e, e = e.next) {
+ if (e.hash == hash && e.key.equals(key)) {
+ V newValue = remappingFunction.apply(key, e.value);
+ if (newValue == null) {
+ modCount++;
+ if (prev != null) {
+ prev.next = e.next;
+ } else {
+ tab[index] = e.next;
+ }
+ count--;
+ } else {
+ e.value = newValue;
+ }
+ return newValue;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public V compute(K key, BiFunction super K, ? super V, ? extends V> remappingFunction) {
+ Objects.requireNonNull(remappingFunction);
+
+ Entry,?> tab[] = table;
+ int hash = hash(key);
+ int index = (hash & 0x7FFFFFFF) % tab.length;
+ @SuppressWarnings("unchecked")
+ Entry e = (Entry)tab[index];
+ for (Entry prev = null; e != null; prev = e, e = e.next) {
+ if (e.hash == hash && Objects.equals(e.key, key)) {
+ V newValue = remappingFunction.apply(key, e.value);
+ if (newValue == null) {
+ modCount++;
+ if (prev != null) {
+ prev.next = e.next;
+ } else {
+ tab[index] = e.next;
+ }
+ count--;
+ } else {
+ e.value = newValue;
+ }
+ return newValue;
+ }
+ }
+
+ V newValue = remappingFunction.apply(key, null);
+ if (newValue != null) {
+ addEntry(hash, key, newValue, index);
+ }
+
+ return newValue;
+ }
+
+ @Override
+ public V merge(K key, V value, BiFunction super V, ? super V, ? extends V> remappingFunction) {
+ Objects.requireNonNull(remappingFunction);
+
+ Entry,?> tab[] = table;
+ int hash = hash(key);
+ int index = (hash & 0x7FFFFFFF) % tab.length;
+ @SuppressWarnings("unchecked")
+ Entry e = (Entry)tab[index];
+ for (Entry prev = null; e != null; prev = e, e = e.next) {
+ if (e.hash == hash && e.key.equals(key)) {
+ V newValue = remappingFunction.apply(e.value, value);
+ if (newValue == null) {
+ modCount++;
+ if (prev != null) {
+ prev.next = e.next;
+ } else {
+ tab[index] = e.next;
+ }
+ count--;
+ } else {
+ e.value = newValue;
+ }
+ return newValue;
+ }
+ }
+
+ if (value != null) {
+ addEntry(hash, key, value, index);
+ }
+
+ return value;
+ }
+
/**
* Save the state of the Hashtable to a stream (i.e., serialize it).
*
diff --git a/jdk/src/share/classes/java/util/Map.java b/jdk/src/share/classes/java/util/Map.java
index 6615f56daa0..acb595d8f07 100644
--- a/jdk/src/share/classes/java/util/Map.java
+++ b/jdk/src/share/classes/java/util/Map.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, 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,6 +25,10 @@
package java.util;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+
/**
* An object that maps keys to values. A map cannot contain duplicate keys;
* each key can map to at most one value.
@@ -475,4 +479,613 @@ public interface Map {
*/
int hashCode();
+ // Defaultable methods
+
+ /**
+ * Returns the value to which the specified key is mapped,
+ * or {@code defaultValue} if this map contains no mapping
+ * for the key.
+ *
+ * The default implementation makes no guarantees about synchronization
+ * or atomicity properties of this method. Any implementation providing
+ * atomicity guarantees must override this method and document its
+ * concurrency properties.
+ *
+ * @param key the key whose associated value is to be returned
+ * @return the value to which the specified key is mapped, or
+ * {@code defaultValue} if this map contains no mapping for the key
+ * @throws ClassCastException if the key is of an inappropriate type for
+ * this map
+ * (optional)
+ * @throws NullPointerException if the specified key is null and this map
+ * does not permit null keys
+ * (optional)
+ */
+ default V getOrDefault(Object key, V defaultValue) {
+ V v;
+ return (((v = get(key)) != null) || containsKey(key))
+ ? v
+ : defaultValue;
+ }
+
+ /**
+ * Performs the given action on each entry in this map, in the order entries
+ * are returned by an entry set iterator (which may be unspecified), until
+ * all entries have been processed or the action throws an {@code Exception}.
+ * Exceptions thrown by the action are relayed to the caller.
+ *
+ *
The default implementation should be overridden by implementations if
+ * they can provide a more performant implementation than an iterator-based
+ * one.
+ *
+ *
The default implementation makes no guarantees about synchronization
+ * or atomicity properties of this method. Any implementation providing
+ * atomicity guarantees must override this method and document its
+ * concurrency properties.
+ *
+ * @implSpec The default implementation is equivalent to, for this
+ * {@code map}:
+ *
{@code
+ * for ((Map.Entry entry : map.entrySet())
+ * action.accept(entry.getKey(), entry.getValue());
+ * }
+ *
+ * @param action The action to be performed for each entry
+ * @throws NullPointerException if the specified action is null
+ * @throws ConcurrentModificationException if an entry is found to be
+ * removed during iteration
+ * @since 1.8
+ */
+ default void forEach(BiConsumer super K, ? super V> action) {
+ Objects.requireNonNull(action);
+ for (Map.Entry entry : entrySet()) {
+ K k;
+ V v;
+ try {
+ k = entry.getKey();
+ v = entry.getValue();
+ } catch(IllegalStateException ise) {
+ throw new ConcurrentModificationException(ise);
+ }
+ action.accept(k, v);
+ }
+ }
+
+ /**
+ * Replaces each entry's value with the result of invoking the given
+ * function on that entry, in the order entries are returned by an entry
+ * set iterator, until all entries have been processed or the function
+ * throws an exception.
+ *
+ * The default implementation makes no guarantees about synchronization
+ * or atomicity properties of this method. Any implementation providing
+ * atomicity guarantees must override this method and document its
+ * concurrency properties.
+ *
+ * @implSpec
+ *
The default implementation is equivalent to, for this {@code map}:
+ *
{@code
+ * for ((Map.Entry entry : map.entrySet())
+ * entry.setValue(function.apply(entry.getKey(), entry.getValue()));
+ * }
+ *
+ * @param function the function to apply to each entry
+ * @throws UnsupportedOperationException if the {@code set} operation
+ * is not supported by this map's entry set iterator.
+ * @throws ClassCastException if the class of a replacement value
+ * prevents it from being stored in this map
+ * @throws NullPointerException if the specified function is null, or the
+ * specified replacement value is null, and this map does not permit null
+ * values
+ * @throws ClassCastException if a replacement value is of an inappropriate
+ * type for this map
+ * (optional)
+ * @throws NullPointerException if function or a replacement value is null,
+ * and this map does not permit null keys or values
+ * (optional)
+ * @throws IllegalArgumentException if some property of a replacement value
+ * prevents it from being stored in this map
+ * (optional)
+ * @throws ConcurrentModificationException if an entry is found to be
+ * removed during iteration
+ * @since 1.8
+ */
+ default void replaceAll(BiFunction super K, ? super V, ? extends V> function) {
+ Objects.requireNonNull(function);
+ for (Map.Entry entry : entrySet()) {
+ K k;
+ V v;
+ try {
+ k = entry.getKey();
+ v = entry.getValue();
+ } catch(IllegalStateException ise) {
+ throw new ConcurrentModificationException(ise);
+ }
+ entry.setValue(function.apply(k, v));
+ }
+ }
+
+ /**
+ * If the specified key is not already associated with a value (or is mapped
+ * to {@code null}) associates it with the given value and returns
+ * {@code null}, else returns the current value.
+ *
+ * The default implementation makes no guarantees about synchronization
+ * or atomicity properties of this method. Any implementation providing
+ * atomicity guarantees must override this method and document its
+ * concurrency properties.
+ *
+ * @implSpec
+ * The default implementation is equivalent to, for this {@code
+ * map}:
+ *
+ *
{@code
+ * if (map.get(key) == null)
+ * return map.put(key, value);
+ * else
+ * return map.get(key);
+ * }
+ *
+ * @param key key with which the specified value is to be associated
+ * @param value value to be associated with the specified key
+ * @return the previous value associated with the specified key, or
+ * {@code 1} if there was no mapping for the key.
+ * (A {@code null} return can also indicate that the map
+ * previously associated {@code null} with the key,
+ * if the implementation supports null values.)
+ * @throws UnsupportedOperationException if the {@code put} operation
+ * is not supported by this map
+ * (optional)
+ * @throws ClassCastException if the key or value is of an inappropriate
+ * type for this map
+ * (optional)
+ * @throws NullPointerException if the specified key or value is null,
+ * and this map does not permit null keys or values
+ * (optional)
+ * @throws IllegalArgumentException if some property of the specified key
+ * or value prevents it from being stored in this map
+ * (optional)
+ * @throws ConcurrentModificationException if a modification of the map is
+ * detected during insertion of the value.
+ * @since 1.8
+ */
+ default V putIfAbsent(K key, V value) {
+ V v = get(key);
+ if (v == null) {
+ if (put(key, value) != null) {
+ throw new ConcurrentModificationException();
+ }
+ }
+
+ return v;
+ }
+
+ /**
+ * Removes the entry for the specified key only if it is currently
+ * mapped to the specified value.
+ *
+ * The default implementation makes no guarantees about synchronization
+ * or atomicity properties of this method. Any implementation providing
+ * atomicity guarantees must override this method and document its
+ * concurrency properties.
+ *
+ * @implSpec
+ * The default implementation is equivalent to, for this {@code map}:
+ *
+ *
{@code
+ * if (map.containsKey(key) && Objects.equals(map.get(key), value)) {
+ * map.remove(key);
+ * return true;
+ * } else
+ * return false;
+ * }
+ *
+ * @param key key with which the specified value is associated
+ * @param value value expected to be associated with the specified key
+ * @return {@code true} if the value was removed
+ * @throws UnsupportedOperationException if the {@code remove} operation
+ * is not supported by this map
+ * (optional)
+ * @throws ClassCastException if the key or value is of an inappropriate
+ * type for this map
+ * (optional)
+ * @throws NullPointerException if the specified key or value is null,
+ * and this map does not permit null keys or values
+ * (optional)
+ * @since 1.8
+ */
+ default boolean remove(Object key, Object value) {
+ Object curValue = get(key);
+ if (!Objects.equals(curValue, value) ||
+ (curValue == null && !containsKey(key))) {
+ return false;
+ }
+ remove(key);
+ return true;
+ }
+
+ /**
+ * Replaces the entry for the specified key only if currently
+ * mapped to the specified value.
+ *
+ * The default implementation makes no guarantees about synchronization
+ * or atomicity properties of this method. Any implementation providing
+ * atomicity guarantees must override this method and document its
+ * concurrency properties.
+ *
+ * @implSpec
+ * The default implementation is equivalent to, for this {@code map}:
+ *
+ *
{@code
+ * if (map.containsKey(key) && Objects.equals(map.get(key), value)) {
+ * map.put(key, newValue);
+ * return true;
+ * } else
+ * return false;
+ * }
+ *
+ * @param key key with which the specified value is associated
+ * @param oldValue value expected to be associated with the specified key
+ * @param newValue value to be associated with the specified key
+ * @return {@code true} if the value was replaced
+ * @throws UnsupportedOperationException if the {@code put} operation
+ * is not supported by this map
+ * (optional)
+ * @throws ClassCastException if the class of a specified key or value
+ * prevents it from being stored in this map
+ * @throws NullPointerException if a specified key or value is null,
+ * and this map does not permit null keys or values
+ * @throws IllegalArgumentException if some property of a specified key
+ * or value prevents it from being stored in this map
+ * @since 1.8
+ */
+ default boolean replace(K key, V oldValue, V newValue) {
+ Object curValue = get(key);
+ if (!Objects.equals(curValue, oldValue) ||
+ (curValue == null && !containsKey(key))) {
+ return false;
+ }
+ put(key, newValue);
+ return true;
+ }
+
+ /**
+ * Replaces the entry for the specified key only if it is
+ * currently mapped to some value.
+ *
+ * The default implementation makes no guarantees about synchronization
+ * or atomicity properties of this method. Any implementation providing
+ * atomicity guarantees must override this method and document its
+ * concurrency properties.
+ *
+ * @implSpec
+ * The default implementation is equivalent to, for this {@code map}:
+ *
+ *
{@code
+ * if (map.containsKey(key)) {
+ * return map.put(key, value);
+ * } else
+ * return null;
+ * }
+ *
+ * @param key key with which the specified value is associated
+ * @param value value to be associated with the specified key
+ * @return the previous value associated with the specified key, or
+ * {@code null} if there was no mapping for the key.
+ * (A {@code null} return can also indicate that the map
+ * previously associated {@code null} with the key,
+ * if the implementation supports null values.)
+ * @throws UnsupportedOperationException if the {@code put} operation
+ * is not supported by this map
+ * (optional)
+ * @throws ClassCastException if the class of the specified key or value
+ * prevents it from being stored in this map
+ * (optional)
+ * @throws NullPointerException if the specified key or value is null,
+ * and this map does not permit null keys or values
+ * @throws IllegalArgumentException if some property of the specified key
+ * or value prevents it from being stored in this map
+ * @since 1.8
+ */
+ default V replace(K key, V value) {
+ return containsKey(key) ? put(key, value) : null;
+ }
+
+ /**
+ * If the specified key is not already associated with a value (or
+ * is mapped to {@code null}), attempts to compute its value using
+ * the given mapping function and enters it into this map unless
+ * {@code null}.
+ *
+ * If the function returns {@code null} no mapping is recorded. If
+ * the function itself throws an (unchecked) exception, the
+ * exception is rethrown, and no mapping is recorded. The most
+ * common usage is to construct a new object serving as an initial
+ * mapped value or memoized result, as in:
+ *
+ *
{@code
+ * map.computeIfAbsent(key, k -> new Value(f(k)));
+ * }
+ *
+ * The default implementation makes no guarantees about synchronization
+ * or atomicity properties of this method. Any implementation providing
+ * atomicity guarantees must override this method and document its
+ * concurrency properties. In particular, all implementations of
+ * subinterface {@link java.util.concurrent.ConcurrentMap} must document
+ * whether the function is applied once atomically only if the value is not
+ * present. Any class that permits null values must document
+ * whether and how this method distinguishes absence from null mappings.
+ *
+ * @implSpec
+ * The default implementation is equivalent to the following
+ * steps for this {@code map}, then returning the current value or
+ * {@code null} if now absent:
+ *
+ *
{@code
+ * if (map.get(key) == null) {
+ * V newValue = mappingFunction.apply(key);
+ * if (newValue != null)
+ * map.putIfAbsent(key, newValue);
+ * }
+ * }
+ *
+ * @param key key with which the specified value is to be associated
+ * @param mappingFunction the function to compute a value
+ * @return the current (existing or computed) value associated with
+ * the specified key, or null if the computed value is null
+ * @throws NullPointerException if the specified key is null and
+ * this map does not support null keys, or the
+ * mappingFunction is null
+ * @throws UnsupportedOperationException if the {@code put} operation
+ * is not supported by this map
+ * (optional)
+ * @throws ClassCastException if the class of the specified key or value
+ * prevents it from being stored in this map
+ * (optional)
+ * @since 1.8
+ */
+ default V computeIfAbsent(K key,
+ Function super K, ? extends V> mappingFunction) {
+ V v, newValue;
+ return ((v = get(key)) == null &&
+ (newValue = mappingFunction.apply(key)) != null &&
+ (v = putIfAbsent(key, newValue)) == null) ? newValue : v;
+ }
+
+ /**
+ * If the value for the specified key is present and non-null, attempts to
+ * compute a new mapping given the key and its current mapped value.
+ *
+ * If the function returns {@code null}, the mapping is removed. If the
+ * function itself throws an (unchecked) exception, the exception is
+ * rethrown, and the current mapping is left unchanged.
+ *
+ *
The default implementation makes no guarantees about synchronization
+ * or atomicity properties of this method. Any implementation providing
+ * atomicity guarantees must override this method and document its
+ * concurrency properties. In particular, all implementations of
+ * subinterface {@link java.util.concurrent.ConcurrentMap} must document
+ * whether the function is applied once atomically only if the value is not
+ * present. Any class that permits null values must document
+ * whether and how this method distinguishes absence from null mappings.
+ *
+ * @implSpec
+ * The default implementation is equivalent to performing the
+ * following steps for this {@code map}, then returning the
+ * current value or {@code null} if now absent:
+ *
+ *
{@code
+ * if (map.get(key) != null) {
+ * V oldValue = map.get(key);
+ * V newValue = remappingFunction.apply(key, oldValue);
+ * if (newValue != null)
+ * map.replace(key, oldValue, newValue);
+ * else
+ * map.remove(key, oldValue);
+ * }
+ * }
+ *
+ * In concurrent contexts, the default implementation may retry
+ * these steps when multiple threads attempt updates.
+ *
+ * @param key key with which the specified value is to be associated
+ * @param remappingFunction the function to compute a value
+ * @return the new value associated with the specified key, or null if none
+ * @throws NullPointerException if the specified key is null and
+ * this map does not support null keys, or the
+ * remappingFunction is null
+ * @throws UnsupportedOperationException if the {@code put} operation
+ * is not supported by this map
+ * (optional)
+ * @throws ClassCastException if the class of the specified key or value
+ * prevents it from being stored in this map
+ * (optional)
+ * @since 1.8
+ */
+ default V computeIfPresent(K key,
+ BiFunction super K, ? super V, ? extends V> remappingFunction) {
+ V oldValue;
+ while ((oldValue = get(key)) != null) {
+ V newValue = remappingFunction.apply(key, oldValue);
+ if (newValue != null) {
+ if (replace(key, oldValue, newValue))
+ return newValue;
+ } else if (remove(key, oldValue))
+ return null;
+ }
+ return oldValue;
+ }
+
+ /**
+ * Attempts to compute a mapping for the specified key and its
+ * current mapped value (or {@code null} if there is no current
+ * mapping). For example, to either create or append a {@code
+ * String msg} to a value mapping:
+ *
+ * {@code
+ * map.compute(key, (k, v) -> (v == null) ? msg : v.concat(msg))}
+ * (Method {@link #merge merge()} is often simpler to use for such purposes.)
+ *
+ * If the function returns {@code null}, the mapping is removed (or
+ * remains absent if initially absent). If the function itself throws an
+ * (unchecked) exception, the exception is rethrown, and the current mapping
+ * is left unchanged.
+ *
+ *
The default implementation makes no guarantees about synchronization
+ * or atomicity properties of this method. Any implementation providing
+ * atomicity guarantees must override this method and document its
+ * concurrency properties. In particular, all implementations of
+ * subinterface {@link java.util.concurrent.ConcurrentMap} must document
+ * whether the function is applied once atomically only if the value is not
+ * present. Any class that permits null values must document
+ * whether and how this method distinguishes absence from null mappings.
+ *
+ * @implSpec
+ * The default implementation is equivalent to performing the following
+ * steps for this {@code map}, then returning the current value or
+ * {@code null} if absent:
+ *
+ *
{@code
+ * V oldValue = map.get(key);
+ * V newValue = remappingFunction.apply(key, oldValue);
+ * if (oldValue != null ) {
+ * if (newValue != null)
+ * map.replace(key, oldValue, newValue);
+ * else
+ * map.remove(key, oldValue);
+ * } else {
+ * if (newValue != null)
+ * map.putIfAbsent(key, newValue);
+ * else
+ * return null;
+ * }
+ * }
+ *
+ * In concurrent contexts, the default implementation may retry
+ * these steps when multiple threads attempt updates.
+ *
+ * @param key key with which the specified value is to be associated
+ * @param remappingFunction the function to compute a value
+ * @return the new value associated with the specified key, or null if none
+ * @throws NullPointerException if the specified key is null and
+ * this map does not support null keys, or the
+ * remappingFunction is null
+ * @throws UnsupportedOperationException if the {@code put} operation
+ * is not supported by this map
+ * (optional)
+ * @throws ClassCastException if the class of the specified key or value
+ * prevents it from being stored in this map
+ * (optional)
+ * @since 1.8
+ */
+ default V compute(K key,
+ BiFunction super K, ? super V, ? extends V> remappingFunction) {
+ V oldValue = get(key);
+ for (;;) {
+ V newValue = remappingFunction.apply(key, oldValue);
+ if (oldValue != null) {
+ if (newValue != null) {
+ if (replace(key, oldValue, newValue))
+ return newValue;
+ } else if (remove(key, oldValue)) {
+ return null;
+ }
+ oldValue = get(key);
+ } else {
+ if (newValue != null) {
+ if ((oldValue = putIfAbsent(key, newValue)) == null)
+ return newValue;
+ } else {
+ return null;
+ }
+ }
+ }
+ }
+
+ /**
+ * If the specified key is not already associated with a value or is
+ * associated with null, associates it with the given value.
+ * Otherwise, replaces the value with the results of the given
+ * remapping function, or removes if the result is {@code null}. This
+ * method may be of use when combining multiple mapped values for a key.
+ * For example, to either create or append a {@code String msg} to a
+ * value mapping:
+ *
+ * {@code
+ * map.merge(key, msg, String::concat)
+ * }
+ *
+ * If the function returns {@code null}, the mapping is removed (or
+ * remains absent if initially absent). If the function itself throws an
+ * (unchecked) exception, the exception is rethrown, and the current mapping
+ * is left unchanged.
+ *
+ *
The default implementation makes no guarantees about synchronization
+ * or atomicity properties of this method. Any implementation providing
+ * atomicity guarantees must override this method and document its
+ * concurrency properties. In particular, all implementations of
+ * subinterface {@link java.util.concurrent.ConcurrentMap} must document
+ * whether the function is applied once atomically only if the value is not
+ * present. Any class that permits null values must document
+ * whether and how this method distinguishes absence from null mappings.
+ *
+ * @implSpec
+ * The default implementation is equivalent to performing the
+ * following steps for this {@code map}, then returning the
+ * current value or {@code null} if absent:
+ *
+ *
{@code
+ * V oldValue = map.get(key);
+ * V newValue = (oldValue == null) ? value :
+ * remappingFunction.apply(oldValue, value);
+ * if (newValue == null)
+ * map.remove(key, oldValue);
+ * else if (oldValue == null)
+ * map.putIfAbsent(key, newValue);
+ * else
+ * map.replace(key, oldValue, newValue);
+ * }
+ *
+ * In concurrent contexts, the default implementation may retry
+ * these steps when multiple threads attempt updates.
+ *
+ * @param key key with which the specified value is to be associated
+ * @param value the value to use if absent
+ * @param remappingFunction the function to recompute a value if present
+ * @return the new value associated with the specified key, or null if none
+ * @throws UnsupportedOperationException if the {@code put} operation
+ * is not supported by this map
+ * (optional)
+ * @throws ClassCastException if the class of the specified key or value
+ * prevents it from being stored in this map
+ * (optional)
+ * @throws NullPointerException if the specified key is null and
+ * this map does not support null keys, or the
+ * remappingFunction is null
+ * @since 1.8
+ */
+ default V merge(K key, V value,
+ BiFunction super V, ? super V, ? extends V> remappingFunction) {
+ V oldValue = get(key);
+ for (;;) {
+ if (oldValue != null) {
+ V newValue = remappingFunction.apply(oldValue, value);
+ if (newValue != null) {
+ if (replace(key, oldValue, newValue))
+ return newValue;
+ } else if (remove(key, oldValue)) {
+ return null;
+ }
+ oldValue = get(key);
+ } else {
+ if (value == null) {
+ return null;
+ }
+
+ if ((oldValue = putIfAbsent(key, value)) == null) {
+ return value;
+ }
+ }
+ }
+ }
}
diff --git a/jdk/src/share/classes/java/util/ResourceBundle.java b/jdk/src/share/classes/java/util/ResourceBundle.java
index 6d341dc304e..0d52daa9c48 100644
--- a/jdk/src/share/classes/java/util/ResourceBundle.java
+++ b/jdk/src/share/classes/java/util/ResourceBundle.java
@@ -57,6 +57,8 @@ import java.util.concurrent.ConcurrentMap;
import java.util.jar.JarEntry;
import java.util.spi.ResourceBundleControlProvider;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
import sun.util.locale.BaseLocale;
import sun.util.locale.LocaleObjectCache;
@@ -440,14 +442,10 @@ public abstract class ResourceBundle {
/*
* Automatic determination of the ClassLoader to be used to load
- * resources on behalf of the client. N.B. The client is getLoader's
- * caller's caller.
+ * resources on behalf of the client.
*/
- private static ClassLoader getLoader() {
- Class>[] stack = getClassContext();
- /* Magic number 2 identifies our caller's caller */
- Class> c = stack[2];
- ClassLoader cl = (c == null) ? null : c.getClassLoader();
+ private static ClassLoader getLoader(Class> caller) {
+ ClassLoader cl = caller == null ? null : caller.getClassLoader();
if (cl == null) {
// When the caller's loader is the boot class loader, cl is null
// here. In that case, ClassLoader.getSystemClassLoader() may
@@ -461,8 +459,6 @@ public abstract class ResourceBundle {
return cl;
}
- private static native Class>[] getClassContext();
-
/**
* A wrapper of ClassLoader.getSystemClassLoader().
*/
@@ -746,11 +742,11 @@ public abstract class ResourceBundle {
* if no resource bundle for the specified base name can be found
* @return a resource bundle for the given base name and the default locale
*/
+ @CallerSensitive
public static final ResourceBundle getBundle(String baseName)
{
return getBundleImpl(baseName, Locale.getDefault(),
- /* must determine loader here, else we break stack invariant */
- getLoader(),
+ getLoader(Reflection.getCallerClass()),
getDefaultControl(baseName));
}
@@ -788,11 +784,11 @@ public abstract class ResourceBundle {
* needed.
* @since 1.6
*/
+ @CallerSensitive
public static final ResourceBundle getBundle(String baseName,
Control control) {
return getBundleImpl(baseName, Locale.getDefault(),
- /* must determine loader here, else we break stack invariant */
- getLoader(),
+ getLoader(Reflection.getCallerClass()),
control);
}
@@ -817,12 +813,12 @@ public abstract class ResourceBundle {
* if no resource bundle for the specified base name can be found
* @return a resource bundle for the given base name and locale
*/
+ @CallerSensitive
public static final ResourceBundle getBundle(String baseName,
Locale locale)
{
return getBundleImpl(baseName, locale,
- /* must determine loader here, else we break stack invariant */
- getLoader(),
+ getLoader(Reflection.getCallerClass()),
getDefaultControl(baseName));
}
@@ -863,11 +859,11 @@ public abstract class ResourceBundle {
* needed.
* @since 1.6
*/
+ @CallerSensitive
public static final ResourceBundle getBundle(String baseName, Locale targetLocale,
Control control) {
return getBundleImpl(baseName, targetLocale,
- /* must determine loader here, else we break stack invariant */
- getLoader(),
+ getLoader(Reflection.getCallerClass()),
control);
}
@@ -1721,8 +1717,9 @@ public abstract class ResourceBundle {
* @since 1.6
* @see ResourceBundle.Control#getTimeToLive(String,Locale)
*/
+ @CallerSensitive
public static final void clearCache() {
- clearCache(getLoader());
+ clearCache(getLoader(Reflection.getCallerClass()));
}
/**
diff --git a/jdk/src/share/classes/java/util/concurrent/ConcurrentHashMap.java b/jdk/src/share/classes/java/util/concurrent/ConcurrentHashMap.java
index 66ae51667d5..b7c8bde6ba7 100644
--- a/jdk/src/share/classes/java/util/concurrent/ConcurrentHashMap.java
+++ b/jdk/src/share/classes/java/util/concurrent/ConcurrentHashMap.java
@@ -34,6 +34,7 @@
*/
package java.util.concurrent;
+import java.io.ObjectInputStream;
import java.util.concurrent.locks.*;
import java.util.*;
import java.io.Serializable;
@@ -1483,7 +1484,23 @@ public class ConcurrentHashMap extends AbstractMap
@SuppressWarnings("unchecked")
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
- s.defaultReadObject();
+ // Don't call defaultReadObject()
+ ObjectInputStream.GetField oisFields = s.readFields();
+ final Segment[] oisSegments = (Segment[])oisFields.get("segments", null);
+
+ final int ssize = oisSegments.length;
+ if (ssize < 1 || ssize > MAX_SEGMENTS
+ || (ssize & (ssize-1)) != 0 ) // ssize not power of two
+ throw new java.io.InvalidObjectException("Bad number of segments:"
+ + ssize);
+ int sshift = 0, ssizeTmp = ssize;
+ while (ssizeTmp > 1) {
+ ++sshift;
+ ssizeTmp >>>= 1;
+ }
+ UNSAFE.putIntVolatile(this, SEGSHIFT_OFFSET, 32 - sshift);
+ UNSAFE.putIntVolatile(this, SEGMASK_OFFSET, ssize - 1);
+ UNSAFE.putObjectVolatile(this, SEGMENTS_OFFSET, oisSegments);
// set hashMask
UNSAFE.putIntVolatile(this, HASHSEED_OFFSET,
@@ -1517,6 +1534,9 @@ public class ConcurrentHashMap extends AbstractMap
private static final long TBASE;
private static final int TSHIFT;
private static final long HASHSEED_OFFSET;
+ private static final long SEGSHIFT_OFFSET;
+ private static final long SEGMASK_OFFSET;
+ private static final long SEGMENTS_OFFSET;
static {
int ss, ts;
@@ -1530,6 +1550,12 @@ public class ConcurrentHashMap extends AbstractMap
ss = UNSAFE.arrayIndexScale(sc);
HASHSEED_OFFSET = UNSAFE.objectFieldOffset(
ConcurrentHashMap.class.getDeclaredField("hashSeed"));
+ SEGSHIFT_OFFSET = UNSAFE.objectFieldOffset(
+ ConcurrentHashMap.class.getDeclaredField("segmentShift"));
+ SEGMASK_OFFSET = UNSAFE.objectFieldOffset(
+ ConcurrentHashMap.class.getDeclaredField("segmentMask"));
+ SEGMENTS_OFFSET = UNSAFE.objectFieldOffset(
+ ConcurrentHashMap.class.getDeclaredField("segments"));
} catch (Exception e) {
throw new Error(e);
}
diff --git a/jdk/src/share/classes/java/util/concurrent/ConcurrentMap.java b/jdk/src/share/classes/java/util/concurrent/ConcurrentMap.java
index a725db6e674..fee5689db89 100644
--- a/jdk/src/share/classes/java/util/concurrent/ConcurrentMap.java
+++ b/jdk/src/share/classes/java/util/concurrent/ConcurrentMap.java
@@ -38,7 +38,7 @@ import java.util.Map;
/**
* A {@link java.util.Map} providing additional atomic
- * putIfAbsent, remove, and replace methods.
+ * {@code putIfAbsent}, {@code remove}, and {@code replace} methods.
*
* Memory consistency effects: As with other concurrent
* collections, actions in a thread prior to placing an object into a
@@ -57,6 +57,21 @@ import java.util.Map;
* @param the type of mapped values
*/
public interface ConcurrentMap extends Map {
+
+ /**
+ * {@inheritDoc}
+ *
+ * @implNote This implementation assumes that the ConcurrentMap cannot
+ * contain null values and get() returning null unambiguously means the key
+ * is absent. Implementations which support null values must override this
+ * default implementation.
+ */
+ @Override
+ default V getOrDefault(Object key, V defaultValue) {
+ V v;
+ return ((v = get(key)) != null) ? v : defaultValue;
+ }
+
/**
* If the specified key is not already associated
* with a value, associate it with the given value.
@@ -91,7 +106,7 @@ public interface ConcurrentMap extends Map {
* Removes the entry for a key only if currently mapped to a given value.
* This is equivalent to
* {@code
- * if (map.containsKey(key) && map.get(key).equals(value)) {
+ * if (map.containsKey(key) && Objects.equals(map.get(key), value)) {
* map.remove(key);
* return true;
* } else
@@ -101,8 +116,8 @@ public interface ConcurrentMap extends Map {
*
* @param key key with which the specified value is associated
* @param value value expected to be associated with the specified key
- * @return true if the value was removed
- * @throws UnsupportedOperationException if the remove operation
+ * @return {@code true} if the value was removed
+ * @throws UnsupportedOperationException if the {@code remove} operation
* is not supported by this map
* @throws ClassCastException if the key or value is of an inappropriate
* type for this map
@@ -117,7 +132,7 @@ public interface ConcurrentMap extends Map {
* Replaces the entry for a key only if currently mapped to a given value.
* This is equivalent to
* {@code
- * if (map.containsKey(key) && map.get(key).equals(oldValue)) {
+ * if (map.containsKey(key) && Objects.equals(map.get(key), oldValue)) {
* map.put(key, newValue);
* return true;
* } else
@@ -128,8 +143,8 @@ public interface ConcurrentMap extends Map {
* @param key key with which the specified value is associated
* @param oldValue value expected to be associated with the specified key
* @param newValue value to be associated with the specified key
- * @return true if the value was replaced
- * @throws UnsupportedOperationException if the put operation
+ * @return {@code true} if the value was replaced
+ * @throws UnsupportedOperationException if the {@code put} operation
* is not supported by this map
* @throws ClassCastException if the class of a specified key or value
* prevents it from being stored in this map
@@ -154,11 +169,11 @@ public interface ConcurrentMap extends Map {
* @param key key with which the specified value is associated
* @param value value to be associated with the specified key
* @return the previous value associated with the specified key, or
- * null if there was no mapping for the key.
- * (A null return can also indicate that the map
- * previously associated null with the key,
+ * {@code null} if there was no mapping for the key.
+ * (A {@code null} return can also indicate that the map
+ * previously associated {@code null} with the key,
* if the implementation supports null values.)
- * @throws UnsupportedOperationException if the put operation
+ * @throws UnsupportedOperationException if the {@code put} operation
* is not supported by this map
* @throws ClassCastException if the class of the specified key or value
* prevents it from being stored in this map
diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
index 4a8d1df5a63..e761b6ec73d 100644
--- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
+++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
@@ -37,6 +37,9 @@ package java.util.concurrent.atomic;
import java.util.function.IntUnaryOperator;
import java.util.function.IntBinaryOperator;
import sun.misc.Unsafe;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.AccessController;
@@ -77,8 +80,9 @@ public abstract class AtomicIntegerFieldUpdater {
* or the field is inaccessible to the caller according to Java language
* access control
*/
+ @CallerSensitive
public static AtomicIntegerFieldUpdater newUpdater(Class tclass, String fieldName) {
- return new AtomicIntegerFieldUpdaterImpl(tclass, fieldName);
+ return new AtomicIntegerFieldUpdaterImpl(tclass, fieldName, Reflection.getCallerClass());
}
/**
@@ -365,9 +369,11 @@ public abstract class AtomicIntegerFieldUpdater {
private final Class tclass;
private final Class> cclass;
- AtomicIntegerFieldUpdaterImpl(final Class tclass, final String fieldName) {
+ AtomicIntegerFieldUpdaterImpl(final Class tclass,
+ final String fieldName,
+ final Class> caller)
+ {
final Field field;
- final Class> caller;
final int modifiers;
try {
field = AccessController.doPrivileged(
@@ -376,7 +382,6 @@ public abstract class AtomicIntegerFieldUpdater {
return tclass.getDeclaredField(fieldName);
}
});
- caller = sun.reflect.Reflection.getCallerClass(3);
modifiers = field.getModifiers();
sun.reflect.misc.ReflectUtil.ensureMemberAccess(
caller, tclass, null, modifiers);
diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
index e5c6e8a0044..7ac0e73d601 100644
--- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
+++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
@@ -37,6 +37,9 @@ package java.util.concurrent.atomic;
import java.util.function.LongUnaryOperator;
import java.util.function.LongBinaryOperator;
import sun.misc.Unsafe;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.AccessController;
@@ -77,11 +80,13 @@ public abstract class AtomicLongFieldUpdater {
* or the field is inaccessible to the caller according to Java language
* access control
*/
+ @CallerSensitive
public static AtomicLongFieldUpdater newUpdater(Class tclass, String fieldName) {
+ Class> caller = Reflection.getCallerClass();
if (AtomicLong.VM_SUPPORTS_LONG_CAS)
- return new CASUpdater(tclass, fieldName);
+ return new CASUpdater(tclass, fieldName, caller);
else
- return new LockedUpdater(tclass, fieldName);
+ return new LockedUpdater(tclass, fieldName, caller);
}
/**
@@ -365,9 +370,8 @@ public abstract class AtomicLongFieldUpdater {
private final Class tclass;
private final Class> cclass;
- CASUpdater(final Class tclass, final String fieldName) {
+ CASUpdater(final Class tclass, final String fieldName, final Class> caller) {
final Field field;
- final Class> caller;
final int modifiers;
try {
field = AccessController.doPrivileged(
@@ -376,7 +380,6 @@ public abstract class AtomicLongFieldUpdater {
return tclass.getDeclaredField(fieldName);
}
});
- caller = sun.reflect.Reflection.getCallerClass(3);
modifiers = field.getModifiers();
sun.reflect.misc.ReflectUtil.ensureMemberAccess(
caller, tclass, null, modifiers);
@@ -490,9 +493,8 @@ public abstract class AtomicLongFieldUpdater {
private final Class tclass;
private final Class> cclass;
- LockedUpdater(final Class tclass, final String fieldName) {
+ LockedUpdater(final Class tclass, final String fieldName, final Class> caller) {
Field field = null;
- Class> caller = null;
int modifiers = 0;
try {
field = AccessController.doPrivileged(
@@ -501,7 +503,6 @@ public abstract class AtomicLongFieldUpdater {
return tclass.getDeclaredField(fieldName);
}
});
- caller = sun.reflect.Reflection.getCallerClass(3);
modifiers = field.getModifiers();
sun.reflect.misc.ReflectUtil.ensureMemberAccess(
caller, tclass, null, modifiers);
diff --git a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
index 933e5e4fc92..2cd0e1df369 100644
--- a/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
+++ b/jdk/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
@@ -37,6 +37,9 @@ package java.util.concurrent.atomic;
import java.util.function.UnaryOperator;
import java.util.function.BinaryOperator;
import sun.misc.Unsafe;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.AccessController;
@@ -96,10 +99,12 @@ public abstract class AtomicReferenceFieldUpdater {
* or the field is inaccessible to the caller according to Java language
* access control
*/
+ @CallerSensitive
public static AtomicReferenceFieldUpdater newUpdater(Class tclass, Class vclass, String fieldName) {
return new AtomicReferenceFieldUpdaterImpl(tclass,
vclass,
- fieldName);
+ fieldName,
+ Reflection.getCallerClass());
}
/**
@@ -297,10 +302,11 @@ public abstract class AtomicReferenceFieldUpdater {
AtomicReferenceFieldUpdaterImpl(final Class tclass,
Class vclass,
- final String fieldName) {
+ final String fieldName,
+ final Class> caller)
+ {
final Field field;
final Class> fieldClass;
- final Class> caller;
final int modifiers;
try {
field = AccessController.doPrivileged(
@@ -309,7 +315,6 @@ public abstract class AtomicReferenceFieldUpdater {
return tclass.getDeclaredField(fieldName);
}
});
- caller = sun.reflect.Reflection.getCallerClass(3);
modifiers = field.getModifiers();
sun.reflect.misc.ReflectUtil.ensureMemberAccess(
caller, tclass, null, modifiers);
diff --git a/jdk/src/share/classes/java/util/logging/Logger.java b/jdk/src/share/classes/java/util/logging/Logger.java
index c8f8fae0702..20bba2671b6 100644
--- a/jdk/src/share/classes/java/util/logging/Logger.java
+++ b/jdk/src/share/classes/java/util/logging/Logger.java
@@ -36,6 +36,8 @@ import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Supplier;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
/**
* A Logger object is used to log messages for a specific
@@ -333,13 +335,10 @@ public class Logger {
}
}
- private static Logger demandLogger(String name, String resourceBundleName) {
+ private static Logger demandLogger(String name, String resourceBundleName, Class> caller) {
LogManager manager = LogManager.getLogManager();
SecurityManager sm = System.getSecurityManager();
if (sm != null && !SystemLoggerHelper.disableCallerCheck) {
- // 0: Reflection 1: Logger.demandLogger 2: Logger.getLogger 3: caller
- final int SKIP_FRAMES = 3;
- Class> caller = sun.reflect.Reflection.getCallerClass(SKIP_FRAMES);
if (caller.getClassLoader() == null) {
return manager.demandSystemLogger(name, resourceBundleName);
}
@@ -377,6 +376,7 @@ public class Logger {
// Synchronization is not required here. All synchronization for
// adding a new Logger object is handled by LogManager.addLogger().
+ @CallerSensitive
public static Logger getLogger(String name) {
// This method is intentionally not a wrapper around a call
// to getLogger(name, resourceBundleName). If it were then
@@ -388,7 +388,7 @@ public class Logger {
// would throw an IllegalArgumentException in the second call
// because the wrapper would result in an attempt to replace
// the existing "resourceBundleForFoo" with null.
- return demandLogger(name, null);
+ return demandLogger(name, null, Reflection.getCallerClass());
}
/**
@@ -434,8 +434,9 @@ public class Logger {
// Synchronization is not required here. All synchronization for
// adding a new Logger object is handled by LogManager.addLogger().
+ @CallerSensitive
public static Logger getLogger(String name, String resourceBundleName) {
- Logger result = demandLogger(name, resourceBundleName);
+ Logger result = demandLogger(name, resourceBundleName, Reflection.getCallerClass());
// MissingResourceException or IllegalArgumentException can be
// thrown by setupResourceInfo().
diff --git a/jdk/src/share/classes/javax/script/ScriptEngineManager.java b/jdk/src/share/classes/javax/script/ScriptEngineManager.java
index 480c69a605c..7ce42d89298 100644
--- a/jdk/src/share/classes/javax/script/ScriptEngineManager.java
+++ b/jdk/src/share/classes/javax/script/ScriptEngineManager.java
@@ -28,6 +28,7 @@ import java.util.*;
import java.security.*;
import java.util.ServiceLoader;
import java.util.ServiceConfigurationError;
+import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
import sun.security.util.SecurityConstants;
@@ -60,9 +61,10 @@ public class ScriptEngineManager {
*
* @see java.lang.Thread#getContextClassLoader
*/
+ @CallerSensitive
public ScriptEngineManager() {
ClassLoader ctxtLoader = Thread.currentThread().getContextClassLoader();
- if (canCallerAccessLoader(ctxtLoader)) {
+ if (canCallerAccessLoader(ctxtLoader, Reflection.getCallerClass())) {
if (DEBUG) System.out.println("using " + ctxtLoader);
init(ctxtLoader);
} else {
@@ -419,10 +421,10 @@ public class ScriptEngineManager {
/** Global bindings associated with script engines created by this manager. */
private Bindings globalScope;
- private boolean canCallerAccessLoader(ClassLoader loader) {
+ private boolean canCallerAccessLoader(ClassLoader loader, Class> caller) {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
- ClassLoader callerLoader = getCallerClassLoader();
+ ClassLoader callerLoader = getClassLoader(caller);
if (!sun.misc.VM.isSystemDomainLoader(callerLoader)) {
if (loader != callerLoader || !isAncestor(loader, callerLoader)) {
try {
@@ -438,10 +440,9 @@ public class ScriptEngineManager {
return true;
}
- // Note that this code is same as ClassLoader.getCallerClassLoader().
+ // Note that this code is same as ClassLoader.getClassLoader().
// But, that method is package private and hence we can't call here.
- private ClassLoader getCallerClassLoader() {
- Class> caller = Reflection.getCallerClass(3);
+ private ClassLoader getClassLoader(Class> caller) {
if (caller == null) {
return null;
}
diff --git a/jdk/src/share/classes/sun/awt/EmbeddedFrame.java b/jdk/src/share/classes/sun/awt/EmbeddedFrame.java
index aacd8c0d7fe..5ad4293da6f 100644
--- a/jdk/src/share/classes/sun/awt/EmbeddedFrame.java
+++ b/jdk/src/share/classes/sun/awt/EmbeddedFrame.java
@@ -539,7 +539,7 @@ public abstract class EmbeddedFrame extends Frame
public void toBack() {}
public void updateFocusableWindowState() {}
public void updateAlwaysOnTop() {}
- public void setAlwaysOnTop(boolean alwaysOnTop) {}
+ public void updateAlwaysOnTopState() {}
public Component getGlobalHeavyweightFocusOwner() { return null; }
public void setBoundsPrivate(int x, int y, int width, int height) {
setBounds(x, y, width, height, SET_BOUNDS);
diff --git a/jdk/src/share/classes/sun/awt/datatransfer/TransferableProxy.java b/jdk/src/share/classes/sun/awt/datatransfer/TransferableProxy.java
index 295aa20d6a8..ed688aa3362 100644
--- a/jdk/src/share/classes/sun/awt/datatransfer/TransferableProxy.java
+++ b/jdk/src/share/classes/sun/awt/datatransfer/TransferableProxy.java
@@ -102,11 +102,11 @@ public class TransferableProxy implements Transferable {
protected final boolean isLocal;
}
-class ClassLoaderObjectOutputStream extends ObjectOutputStream {
+final class ClassLoaderObjectOutputStream extends ObjectOutputStream {
private final Map, ClassLoader> map =
new HashMap, ClassLoader>();
- public ClassLoaderObjectOutputStream(OutputStream os) throws IOException {
+ ClassLoaderObjectOutputStream(OutputStream os) throws IOException {
super(os);
}
@@ -140,16 +140,16 @@ class ClassLoaderObjectOutputStream extends ObjectOutputStream {
map.put(s, classLoader);
}
- public Map, ClassLoader> getClassLoaderMap() {
+ Map, ClassLoader> getClassLoaderMap() {
return new HashMap(map);
}
}
-class ClassLoaderObjectInputStream extends ObjectInputStream {
+final class ClassLoaderObjectInputStream extends ObjectInputStream {
private final Map, ClassLoader> map;
- public ClassLoaderObjectInputStream(InputStream is,
- Map, ClassLoader> map)
+ ClassLoaderObjectInputStream(InputStream is,
+ Map, ClassLoader> map)
throws IOException {
super(is);
if (map == null) {
@@ -166,8 +166,11 @@ class ClassLoaderObjectInputStream extends ObjectInputStream {
s.add(className);
ClassLoader classLoader = map.get(s);
-
- return Class.forName(className, false, classLoader);
+ if (classLoader != null) {
+ return Class.forName(className, false, classLoader);
+ } else {
+ return super.resolveClass(classDesc);
+ }
}
protected Class> resolveProxyClass(String[] interfaces)
@@ -179,6 +182,9 @@ class ClassLoaderObjectInputStream extends ObjectInputStream {
}
ClassLoader classLoader = map.get(s);
+ if (classLoader == null) {
+ return super.resolveProxyClass(interfaces);
+ }
// The code below is mostly copied from the superclass.
ClassLoader nonPublicLoader = null;
diff --git a/jdk/src/share/classes/sun/awt/image/ByteComponentRaster.java b/jdk/src/share/classes/sun/awt/image/ByteComponentRaster.java
index 49c642e37db..f2675dbf97d 100644
--- a/jdk/src/share/classes/sun/awt/image/ByteComponentRaster.java
+++ b/jdk/src/share/classes/sun/awt/image/ByteComponentRaster.java
@@ -868,6 +868,15 @@ public class ByteComponentRaster extends SunWritableRaster {
* or if data buffer has not enough capacity.
*/
protected final void verify() {
+ /* Need to re-verify the dimensions since a sample model may be
+ * specified to the constructor
+ */
+ if (width <= 0 || height <= 0 ||
+ height > (Integer.MAX_VALUE / width))
+ {
+ throw new RasterFormatException("Invalid raster dimension");
+ }
+
for (int i = 0; i < dataOffsets.length; i++) {
if (dataOffsets[i] < 0) {
throw new RasterFormatException("Data offsets for band " + i
@@ -905,13 +914,14 @@ public class ByteComponentRaster extends SunWritableRaster {
lastPixelOffset += lastScanOffset;
for (int i = 0; i < numDataElements; i++) {
- size = lastPixelOffset + dataOffsets[i];
if (dataOffsets[i] > (Integer.MAX_VALUE - lastPixelOffset)) {
throw new RasterFormatException("Incorrect band offset: "
+ dataOffsets[i]);
}
+ size = lastPixelOffset + dataOffsets[i];
+
if (size > maxSize) {
maxSize = size;
}
diff --git a/jdk/src/share/classes/sun/awt/image/BytePackedRaster.java b/jdk/src/share/classes/sun/awt/image/BytePackedRaster.java
index 8fec29e90b7..598d68dce47 100644
--- a/jdk/src/share/classes/sun/awt/image/BytePackedRaster.java
+++ b/jdk/src/share/classes/sun/awt/image/BytePackedRaster.java
@@ -1368,11 +1368,35 @@ public class BytePackedRaster extends SunWritableRaster {
throw new RasterFormatException("Data offsets must be >= 0");
}
+ /* Need to re-verify the dimensions since a sample model may be
+ * specified to the constructor
+ */
+ if (width <= 0 || height <= 0 ||
+ height > (Integer.MAX_VALUE / width))
+ {
+ throw new RasterFormatException("Invalid raster dimension");
+ }
+
+
+ /*
+ * pixelBitstride was verified in constructor, so just make
+ * sure that it is safe to multiply it by width.
+ */
+ if ((width - 1) > Integer.MAX_VALUE / pixelBitStride) {
+ throw new RasterFormatException("Invalid raster dimension");
+ }
+
+ if (scanlineStride < 0 ||
+ scanlineStride > (Integer.MAX_VALUE / height))
+ {
+ throw new RasterFormatException("Invalid scanline stride");
+ }
+
int lastbit = (dataBitOffset
+ (height-1) * scanlineStride * 8
+ (width-1) * pixelBitStride
+ pixelBitStride - 1);
- if (lastbit / 8 >= data.length) {
+ if (lastbit < 0 || lastbit / 8 >= data.length) {
throw new RasterFormatException("raster dimensions overflow " +
"array bounds");
}
diff --git a/jdk/src/share/classes/sun/awt/image/ImageRepresentation.java b/jdk/src/share/classes/sun/awt/image/ImageRepresentation.java
index 23b33212602..18fb13ed69b 100644
--- a/jdk/src/share/classes/sun/awt/image/ImageRepresentation.java
+++ b/jdk/src/share/classes/sun/awt/image/ImageRepresentation.java
@@ -333,10 +333,10 @@ public class ImageRepresentation extends ImageWatched implements ImageConsumer
hints = h;
}
- private native void setICMpixels(int x, int y, int w, int h, int[] lut,
+ private native boolean setICMpixels(int x, int y, int w, int h, int[] lut,
byte[] pix, int off, int scansize,
IntegerComponentRaster ict);
- private native int setDiffICM(int x, int y, int w, int h, int[] lut,
+ private native boolean setDiffICM(int x, int y, int w, int h, int[] lut,
int transPix, int numLut, IndexColorModel icm,
byte[] pix, int off, int scansize,
ByteComponentRaster bct, int chanOff);
@@ -426,10 +426,10 @@ public class ImageRepresentation extends ImageWatched implements ImageConsumer
IndexColorModel icm = (IndexColorModel) model;
ByteComponentRaster bct = (ByteComponentRaster) biRaster;
int numlut = numSrcLUT;
- if (setDiffICM(x, y, w, h, srcLUT, srcLUTtransIndex,
+ if (!setDiffICM(x, y, w, h, srcLUT, srcLUTtransIndex,
numSrcLUT, icm,
pix, off, scansize, bct,
- bct.getDataOffset(0)) == 0) {
+ bct.getDataOffset(0))) {
convertToRGB();
}
else {
@@ -470,9 +470,14 @@ public class ImageRepresentation extends ImageWatched implements ImageConsumer
if (s_useNative) {
// Note that setICMpixels modifies the raster directly
// so we must mark it as changed afterwards
- setICMpixels(x, y, w, h, srcLUT, pix, off, scansize,
- iraster);
- iraster.markDirty();
+ if (setICMpixels(x, y, w, h, srcLUT, pix, off, scansize,
+ iraster))
+ {
+ iraster.markDirty();
+ } else {
+ abort();
+ return;
+ }
}
else {
int[] storage = new int[w*h];
diff --git a/jdk/src/share/classes/sun/awt/image/IntegerComponentRaster.java b/jdk/src/share/classes/sun/awt/image/IntegerComponentRaster.java
index 1f2c569b5bf..92bec9f944a 100644
--- a/jdk/src/share/classes/sun/awt/image/IntegerComponentRaster.java
+++ b/jdk/src/share/classes/sun/awt/image/IntegerComponentRaster.java
@@ -208,7 +208,7 @@ public class IntegerComponentRaster extends SunWritableRaster {
" SinglePixelPackedSampleModel");
}
- verify(false);
+ verify();
}
@@ -629,16 +629,26 @@ public class IntegerComponentRaster extends SunWritableRaster {
}
/**
- * Verify that the layout parameters are consistent with
- * the data. If strictCheck
- * is false, this method will check for ArrayIndexOutOfBounds conditions. If
- * strictCheck is true, this method will check for additional error
- * conditions such as line wraparound (width of a line greater than
- * the scanline stride).
- * @return String Error string, if the layout is incompatible with
- * the data. Otherwise returns null.
+ * Verify that the layout parameters are consistent with the data.
+ *
+ * The method verifies whether scanline stride and pixel stride do not
+ * cause an integer overflow during calculation of a position of the pixel
+ * in data buffer. It also verifies whether the data buffer has enough data
+ * to correspond the raster layout attributes.
+ *
+ * @throws RasterFormatException if an integer overflow is detected,
+ * or if data buffer has not enough capacity.
*/
- private void verify (boolean strictCheck) {
+ protected final void verify() {
+ /* Need to re-verify the dimensions since a sample model may be
+ * specified to the constructor
+ */
+ if (width <= 0 || height <= 0 ||
+ height > (Integer.MAX_VALUE / width))
+ {
+ throw new RasterFormatException("Invalid raster dimension");
+ }
+
if (dataOffsets[0] < 0) {
throw new RasterFormatException("Data offset ("+dataOffsets[0]+
") must be >= 0");
@@ -647,17 +657,46 @@ public class IntegerComponentRaster extends SunWritableRaster {
int maxSize = 0;
int size;
- for (int i=0; i < numDataElements; i++) {
- size = (height-1)*scanlineStride + (width-1)*pixelStride +
- dataOffsets[i];
+ // we can be sure that width and height are greater than 0
+ if (scanlineStride < 0 ||
+ scanlineStride > (Integer.MAX_VALUE / height))
+ {
+ // integer overflow
+ throw new RasterFormatException("Incorrect scanline stride: "
+ + scanlineStride);
+ }
+ int lastScanOffset = (height - 1) * scanlineStride;
+
+ if (pixelStride < 0 ||
+ pixelStride > (Integer.MAX_VALUE / width))
+ {
+ // integer overflow
+ throw new RasterFormatException("Incorrect pixel stride: "
+ + pixelStride);
+ }
+ int lastPixelOffset = (width - 1) * pixelStride;
+
+ if (lastPixelOffset > (Integer.MAX_VALUE - lastScanOffset)) {
+ // integer overflow
+ throw new RasterFormatException("Incorrect raster attributes");
+ }
+ lastPixelOffset += lastScanOffset;
+
+ for (int i = 0; i < numDataElements; i++) {
+ if (dataOffsets[i] > (Integer.MAX_VALUE - lastPixelOffset)) {
+ throw new RasterFormatException("Incorrect band offset: "
+ + dataOffsets[i]);
+ }
+
+ size = lastPixelOffset + dataOffsets[i];
+
if (size > maxSize) {
maxSize = size;
}
}
if (data.length < maxSize) {
- throw new RasterFormatException("Data array too small (should be "+
- maxSize
- +" but is "+data.length+" )");
+ throw new RasterFormatException("Data array too small (should be "
+ + maxSize + " )");
}
}
diff --git a/jdk/src/share/classes/sun/awt/image/IntegerInterleavedRaster.java b/jdk/src/share/classes/sun/awt/image/IntegerInterleavedRaster.java
index 90238f4cc4e..2d0d22ec59c 100644
--- a/jdk/src/share/classes/sun/awt/image/IntegerInterleavedRaster.java
+++ b/jdk/src/share/classes/sun/awt/image/IntegerInterleavedRaster.java
@@ -151,7 +151,7 @@ public class IntegerInterleavedRaster extends IntegerComponentRaster {
throw new RasterFormatException("IntegerInterleavedRasters must have"+
" SinglePixelPackedSampleModel");
}
- verify(false);
+ verify();
}
@@ -540,31 +540,6 @@ public class IntegerInterleavedRaster extends IntegerComponentRaster {
return createCompatibleWritableRaster(width,height);
}
- /**
- * Verify that the layout parameters are consistent with
- * the data. If strictCheck
- * is false, this method will check for ArrayIndexOutOfBounds conditions. If
- * strictCheck is true, this method will check for additional error
- * conditions such as line wraparound (width of a line greater than
- * the scanline stride).
- * @return String Error string, if the layout is incompatible with
- * the data. Otherwise returns null.
- */
- private void verify (boolean strictCheck) {
- int maxSize = 0;
- int size;
-
- size = (height-1)*scanlineStride + (width-1) + dataOffsets[0];
- if (size > maxSize) {
- maxSize = size;
- }
- if (data.length < maxSize) {
- throw new RasterFormatException("Data array too small (should be "+
- maxSize
- +" but is "+data.length+" )");
- }
- }
-
public String toString() {
return new String ("IntegerInterleavedRaster: width = "+width
+" height = " + height
diff --git a/jdk/src/share/classes/sun/awt/image/ShortComponentRaster.java b/jdk/src/share/classes/sun/awt/image/ShortComponentRaster.java
index df2c0f7d663..3b33595c129 100644
--- a/jdk/src/share/classes/sun/awt/image/ShortComponentRaster.java
+++ b/jdk/src/share/classes/sun/awt/image/ShortComponentRaster.java
@@ -802,6 +802,15 @@ public class ShortComponentRaster extends SunWritableRaster {
* or if data buffer has not enough capacity.
*/
protected final void verify() {
+ /* Need to re-verify the dimensions since a sample model may be
+ * specified to the constructor
+ */
+ if (width <= 0 || height <= 0 ||
+ height > (Integer.MAX_VALUE / width))
+ {
+ throw new RasterFormatException("Invalid raster dimension");
+ }
+
for (int i = 0; i < dataOffsets.length; i++) {
if (dataOffsets[i] < 0) {
throw new RasterFormatException("Data offsets for band " + i
@@ -839,12 +848,13 @@ public class ShortComponentRaster extends SunWritableRaster {
lastPixelOffset += lastScanOffset;
for (int i = 0; i < numDataElements; i++) {
- size = lastPixelOffset + dataOffsets[i];
if (dataOffsets[i] > (Integer.MAX_VALUE - lastPixelOffset)) {
throw new RasterFormatException("Incorrect band offset: "
+ dataOffsets[i]);
}
+ size = lastPixelOffset + dataOffsets[i];
+
if (size > maxSize) {
maxSize = size;
}
diff --git a/jdk/src/share/classes/sun/font/CMap.java b/jdk/src/share/classes/sun/font/CMap.java
index 0dd595ceb9f..f2554bd3b6c 100644
--- a/jdk/src/share/classes/sun/font/CMap.java
+++ b/jdk/src/share/classes/sun/font/CMap.java
@@ -841,7 +841,6 @@ abstract class CMap {
CMapFormat6(ByteBuffer bbuffer, int offset, char[] xlat) {
- System.err.println("WARNING: CMapFormat8 is untested.");
bbuffer.position(offset+6);
CharBuffer buffer = bbuffer.asCharBuffer();
firstCode = buffer.get();
@@ -884,7 +883,6 @@ abstract class CMap {
CMapFormat8(ByteBuffer bbuffer, int offset, char[] xlat) {
- System.err.println("WARNING: CMapFormat8 is untested.");
bbuffer.position(12);
bbuffer.get(is32);
nGroups = bbuffer.getInt();
@@ -915,7 +913,6 @@ abstract class CMap {
CMapFormat10(ByteBuffer bbuffer, int offset, char[] xlat) {
- System.err.println("WARNING: CMapFormat10 is untested.");
firstCode = bbuffer.getInt() & INTMASK;
entryCount = bbuffer.getInt() & INTMASK;
bbuffer.position(offset+20);
diff --git a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java
index b53bd9a45d3..1957b705b59 100644
--- a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java
+++ b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSImageLayout.java
@@ -85,45 +85,72 @@ class LCMSImageLayout {
private boolean imageAtOnce = false;
Object dataArray;
- private LCMSImageLayout(int np, int pixelType, int pixelSize) {
+ private int dataArrayLength; /* in bytes */
+
+ private LCMSImageLayout(int np, int pixelType, int pixelSize)
+ throws ImageLayoutException
+ {
this.pixelType = pixelType;
width = np;
height = 1;
- nextRowOffset = np * pixelSize;
+ nextRowOffset = safeMult(pixelSize, np);
offset = 0;
}
private LCMSImageLayout(int width, int height, int pixelType,
- int pixelSize) {
+ int pixelSize)
+ throws ImageLayoutException
+ {
this.pixelType = pixelType;
this.width = width;
this.height = height;
- nextRowOffset = width * pixelSize;
+ nextRowOffset = safeMult(pixelSize, width);
offset = 0;
}
- public LCMSImageLayout(byte[] data, int np, int pixelType, int pixelSize) {
+
+ public LCMSImageLayout(byte[] data, int np, int pixelType, int pixelSize)
+ throws ImageLayoutException
+ {
this(np, pixelType, pixelSize);
dataType = DT_BYTE;
dataArray = data;
+ dataArrayLength = data.length;
+
+ verify();
}
- public LCMSImageLayout(short[] data, int np, int pixelType, int pixelSize) {
+ public LCMSImageLayout(short[] data, int np, int pixelType, int pixelSize)
+ throws ImageLayoutException
+ {
this(np, pixelType, pixelSize);
dataType = DT_SHORT;
dataArray = data;
+ dataArrayLength = 2 * data.length;
+
+ verify();
}
- public LCMSImageLayout(int[] data, int np, int pixelType, int pixelSize) {
+ public LCMSImageLayout(int[] data, int np, int pixelType, int pixelSize)
+ throws ImageLayoutException
+ {
this(np, pixelType, pixelSize);
dataType = DT_INT;
dataArray = data;
+ dataArrayLength = 4 * data.length;
+
+ verify();
}
- public LCMSImageLayout(double[] data, int np, int pixelType, int pixelSize) {
+ public LCMSImageLayout(double[] data, int np, int pixelType, int pixelSize)
+ throws ImageLayoutException
+ {
this(np, pixelType, pixelSize);
dataType = DT_DOUBLE;
dataArray = data;
+ dataArrayLength = 8 * data.length;
+
+ verify();
}
private LCMSImageLayout() {
@@ -132,7 +159,7 @@ class LCMSImageLayout {
/* This method creates a layout object for given image.
* Returns null if the image is not supported by current implementation.
*/
- public static LCMSImageLayout createImageLayout(BufferedImage image) {
+ public static LCMSImageLayout createImageLayout(BufferedImage image) throws ImageLayoutException {
LCMSImageLayout l = new LCMSImageLayout();
switch (image.getType()) {
@@ -193,9 +220,10 @@ class LCMSImageLayout {
do {
IntegerComponentRaster intRaster = (IntegerComponentRaster)
image.getRaster();
- l.nextRowOffset = intRaster.getScanlineStride() * 4;
- l.offset = intRaster.getDataOffset(0) * 4;
+ l.nextRowOffset = safeMult(4, intRaster.getScanlineStride());
+ l.offset = safeMult(4, intRaster.getDataOffset(0));
l.dataArray = intRaster.getDataStorage();
+ l.dataArrayLength = 4 * intRaster.getDataStorage().length;
l.dataType = DT_INT;
if (l.nextRowOffset == l.width * 4 * intRaster.getPixelStride()) {
@@ -213,6 +241,7 @@ class LCMSImageLayout {
int firstBand = image.getSampleModel().getNumBands() - 1;
l.offset = byteRaster.getDataOffset(firstBand);
l.dataArray = byteRaster.getDataStorage();
+ l.dataArrayLength = byteRaster.getDataStorage().length;
l.dataType = DT_BYTE;
if (l.nextRowOffset == l.width * byteRaster.getPixelStride()) {
l.imageAtOnce = true;
@@ -225,6 +254,7 @@ class LCMSImageLayout {
ByteComponentRaster byteRaster = (ByteComponentRaster)
image.getRaster();
l.nextRowOffset = byteRaster.getScanlineStride();
+ l.dataArrayLength = byteRaster.getDataStorage().length;
l.offset = byteRaster.getDataOffset(0);
l.dataArray = byteRaster.getDataStorage();
l.dataType = DT_BYTE;
@@ -239,9 +269,10 @@ class LCMSImageLayout {
do {
ShortComponentRaster shortRaster = (ShortComponentRaster)
image.getRaster();
- l.nextRowOffset = shortRaster.getScanlineStride() * 2;
- l.offset = shortRaster.getDataOffset(0) * 2;
+ l.nextRowOffset = safeMult(2, shortRaster.getScanlineStride());
+ l.offset = safeMult(2, shortRaster.getDataOffset(0));
l.dataArray = shortRaster.getDataStorage();
+ l.dataArrayLength = 2 * shortRaster.getDataStorage().length;
l.dataType = DT_SHORT;
if (l.nextRowOffset == l.width * 2 * shortRaster.getPixelStride()) {
@@ -252,6 +283,7 @@ class LCMSImageLayout {
default:
return null;
}
+ l.verify();
return l;
}
@@ -293,6 +325,46 @@ class LCMSImageLayout {
}
}
+ private void verify() throws ImageLayoutException {
+
+ if (offset < 0 || offset >= dataArrayLength) {
+ throw new ImageLayoutException("Invalid image layout");
+ }
+
+ int lastPixelOffset = safeMult(nextRowOffset, (height - 1));
+
+ lastPixelOffset = safeAdd(lastPixelOffset, (width - 1));
+
+ int off = safeAdd(offset, lastPixelOffset);
+
+ if (off < 0 || off >= dataArrayLength) {
+ throw new ImageLayoutException("Invalid image layout");
+ }
+ }
+
+ static int safeAdd(int a, int b) throws ImageLayoutException {
+ long res = a;
+ res += b;
+ if (res < Integer.MIN_VALUE || res > Integer.MAX_VALUE) {
+ throw new ImageLayoutException("Invalid image layout");
+ }
+ return (int)res;
+ }
+
+ static int safeMult(int a, int b) throws ImageLayoutException {
+ long res = a;
+ res *= b;
+ if (res < Integer.MIN_VALUE || res > Integer.MAX_VALUE) {
+ throw new ImageLayoutException("Invalid image layout");
+ }
+ return (int)res;
+ }
+
+ public static class ImageLayoutException extends Exception {
+ public ImageLayoutException(String message) {
+ super(message);
+ }
+ }
public static LCMSImageLayout createImageLayout(Raster r) {
LCMSImageLayout l = new LCMSImageLayout();
if (r instanceof ByteComponentRaster) {
diff --git a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java
index de8a77c75f3..28f64dd71e6 100644
--- a/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java
+++ b/jdk/src/share/classes/sun/java2d/cmm/lcms/LCMSTransform.java
@@ -51,6 +51,7 @@ import java.awt.image.SinglePixelPackedSampleModel;
import java.awt.image.ComponentSampleModel;
import sun.java2d.cmm.*;
import sun.java2d.cmm.lcms.*;
+import static sun.java2d.cmm.lcms.LCMSImageLayout.ImageLayoutException;
public class LCMSTransform implements ColorTransform {
@@ -162,15 +163,19 @@ public class LCMSTransform implements ColorTransform {
public void colorConvert(BufferedImage src, BufferedImage dst) {
LCMSImageLayout srcIL, dstIL;
+ try {
- dstIL = LCMSImageLayout.createImageLayout(dst);
+ dstIL = LCMSImageLayout.createImageLayout(dst);
- if (dstIL != null) {
- srcIL = LCMSImageLayout.createImageLayout(src);
- if (srcIL != null) {
- doTransform(srcIL, dstIL);
- return;
+ if (dstIL != null) {
+ srcIL = LCMSImageLayout.createImageLayout(src);
+ if (srcIL != null) {
+ doTransform(srcIL, dstIL);
+ return;
+ }
}
+ } catch (ImageLayoutException e) {
+ throw new CMMException("Unable to convert images");
}
Raster srcRas = src.getRaster();
@@ -228,14 +233,18 @@ public class LCMSTransform implements ColorTransform {
}
int idx;
// TODO check for src npixels = dst npixels
- srcIL = new LCMSImageLayout(
- srcLine, srcLine.length/getNumInComponents(),
- LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
- LCMSImageLayout.BYTES_SH(1), getNumInComponents());
- dstIL = new LCMSImageLayout(
- dstLine, dstLine.length/getNumOutComponents(),
- LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
- LCMSImageLayout.BYTES_SH(1), getNumOutComponents());
+ try {
+ srcIL = new LCMSImageLayout(
+ srcLine, srcLine.length/getNumInComponents(),
+ LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
+ LCMSImageLayout.BYTES_SH(1), getNumInComponents());
+ dstIL = new LCMSImageLayout(
+ dstLine, dstLine.length/getNumOutComponents(),
+ LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
+ LCMSImageLayout.BYTES_SH(1), getNumOutComponents());
+ } catch (ImageLayoutException e) {
+ throw new CMMException("Unable to convert images");
+ }
// process each scanline
for (int y = 0; y < h; y++) {
// convert src scanline
@@ -284,16 +293,19 @@ public class LCMSTransform implements ColorTransform {
alpha = new float[w];
}
int idx;
- srcIL = new LCMSImageLayout(
- srcLine, srcLine.length/getNumInComponents(),
- LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
- LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2);
-
- dstIL = new LCMSImageLayout(
- dstLine, dstLine.length/getNumOutComponents(),
- LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
- LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2);
+ try {
+ srcIL = new LCMSImageLayout(
+ srcLine, srcLine.length/getNumInComponents(),
+ LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
+ LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2);
+ dstIL = new LCMSImageLayout(
+ dstLine, dstLine.length/getNumOutComponents(),
+ LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
+ LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2);
+ } catch (ImageLayoutException e) {
+ throw new CMMException("Unable to convert images");
+ }
// process each scanline
for (int y = 0; y < h; y++) {
// convert src scanline
@@ -402,16 +414,19 @@ public class LCMSTransform implements ColorTransform {
short[] srcLine = new short[w * srcNumBands];
short[] dstLine = new short[w * dstNumBands];
int idx;
- srcIL = new LCMSImageLayout(
- srcLine, srcLine.length/getNumInComponents(),
- LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
- LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2);
-
- dstIL = new LCMSImageLayout(
- dstLine, dstLine.length/getNumOutComponents(),
- LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
- LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2);
+ try {
+ srcIL = new LCMSImageLayout(
+ srcLine, srcLine.length/getNumInComponents(),
+ LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
+ LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2);
+ dstIL = new LCMSImageLayout(
+ dstLine, dstLine.length/getNumOutComponents(),
+ LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
+ LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2);
+ } catch (ImageLayoutException e) {
+ throw new CMMException("Unable to convert rasters");
+ }
// process each scanline
for (int y = 0; y < h; y++, ys++, yd++) {
// get src scanline
@@ -502,15 +517,18 @@ public class LCMSTransform implements ColorTransform {
byte[] dstLine = new byte[w * dstNumBands];
int idx;
// TODO check for src npixels = dst npixels
- srcIL = new LCMSImageLayout(
- srcLine, srcLine.length/getNumInComponents(),
- LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
- LCMSImageLayout.BYTES_SH(1), getNumInComponents());
- dstIL = new LCMSImageLayout(
- dstLine, dstLine.length/getNumOutComponents(),
- LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
- LCMSImageLayout.BYTES_SH(1), getNumOutComponents());
-
+ try {
+ srcIL = new LCMSImageLayout(
+ srcLine, srcLine.length/getNumInComponents(),
+ LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
+ LCMSImageLayout.BYTES_SH(1), getNumInComponents());
+ dstIL = new LCMSImageLayout(
+ dstLine, dstLine.length/getNumOutComponents(),
+ LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
+ LCMSImageLayout.BYTES_SH(1), getNumOutComponents());
+ } catch (ImageLayoutException e) {
+ throw new CMMException("Unable to convert rasters");
+ }
// process each scanline
for (int y = 0; y < h; y++, ys++, yd++) {
// get src scanline
@@ -542,16 +560,20 @@ public class LCMSTransform implements ColorTransform {
short[] srcLine = new short[w * srcNumBands];
short[] dstLine = new short[w * dstNumBands];
int idx;
- srcIL = new LCMSImageLayout(
- srcLine, srcLine.length/getNumInComponents(),
- LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
- LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2);
- dstIL = new LCMSImageLayout(
- dstLine, dstLine.length/getNumOutComponents(),
- LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
- LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2);
+ try {
+ srcIL = new LCMSImageLayout(
+ srcLine, srcLine.length/getNumInComponents(),
+ LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
+ LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2);
+ dstIL = new LCMSImageLayout(
+ dstLine, dstLine.length/getNumOutComponents(),
+ LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
+ LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2);
+ } catch (ImageLayoutException e) {
+ throw new CMMException("Unable to convert rasters");
+ }
// process each scanline
for (int y = 0; y < h; y++, ys++, yd++) {
// get src scanline
@@ -592,19 +614,23 @@ public class LCMSTransform implements ColorTransform {
dst = new short [(src.length/getNumInComponents())*getNumOutComponents()];
}
- LCMSImageLayout srcIL = new LCMSImageLayout(
- src, src.length/getNumInComponents(),
- LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
- LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2);
+ try {
+ LCMSImageLayout srcIL = new LCMSImageLayout(
+ src, src.length/getNumInComponents(),
+ LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
+ LCMSImageLayout.BYTES_SH(2), getNumInComponents()*2);
- LCMSImageLayout dstIL = new LCMSImageLayout(
- dst, dst.length/getNumOutComponents(),
- LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
- LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2);
+ LCMSImageLayout dstIL = new LCMSImageLayout(
+ dst, dst.length/getNumOutComponents(),
+ LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
+ LCMSImageLayout.BYTES_SH(2), getNumOutComponents()*2);
- doTransform(srcIL, dstIL);
+ doTransform(srcIL, dstIL);
- return dst;
+ return dst;
+ } catch (ImageLayoutException e) {
+ throw new CMMException("Unable to convert data");
+ }
}
public byte[] colorConvert(byte[] src, byte[] dst) {
@@ -612,18 +638,22 @@ public class LCMSTransform implements ColorTransform {
dst = new byte [(src.length/getNumInComponents())*getNumOutComponents()];
}
- LCMSImageLayout srcIL = new LCMSImageLayout(
- src, src.length/getNumInComponents(),
- LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
- LCMSImageLayout.BYTES_SH(1), getNumInComponents());
+ try {
+ LCMSImageLayout srcIL = new LCMSImageLayout(
+ src, src.length/getNumInComponents(),
+ LCMSImageLayout.CHANNELS_SH(getNumInComponents()) |
+ LCMSImageLayout.BYTES_SH(1), getNumInComponents());
- LCMSImageLayout dstIL = new LCMSImageLayout(
- dst, dst.length/getNumOutComponents(),
- LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
- LCMSImageLayout.BYTES_SH(1), getNumOutComponents());
+ LCMSImageLayout dstIL = new LCMSImageLayout(
+ dst, dst.length/getNumOutComponents(),
+ LCMSImageLayout.CHANNELS_SH(getNumOutComponents()) |
+ LCMSImageLayout.BYTES_SH(1), getNumOutComponents());
- doTransform(srcIL, dstIL);
+ doTransform(srcIL, dstIL);
- return dst;
+ return dst;
+ } catch (ImageLayoutException e) {
+ throw new CMMException("Unable to convert data");
+ }
}
}
diff --git a/jdk/src/share/classes/sun/misc/Unsafe.java b/jdk/src/share/classes/sun/misc/Unsafe.java
index 8f45c867de0..25fb99e2639 100644
--- a/jdk/src/share/classes/sun/misc/Unsafe.java
+++ b/jdk/src/share/classes/sun/misc/Unsafe.java
@@ -28,6 +28,9 @@ package sun.misc;
import java.security.*;
import java.lang.reflect.*;
+import sun.reflect.CallerSensitive;
+import sun.reflect.Reflection;
+
/**
* A collection of methods for performing low-level, unsafe operations.
@@ -80,9 +83,10 @@ public final class Unsafe {
* checkPropertiesAccess
method doesn't allow
* access to the system properties.
*/
+ @CallerSensitive
public static Unsafe getUnsafe() {
- Class> cc = sun.reflect.Reflection.getCallerClass(2);
- if (!VM.isSystemDomainLoader(cc.getClassLoader()))
+ Class> caller = Reflection.getCallerClass();
+ if (!VM.isSystemDomainLoader(caller.getClassLoader()))
throw new SecurityException("Unsafe");
return theUnsafe;
}
@@ -817,8 +821,6 @@ public final class Unsafe {
ClassLoader loader,
ProtectionDomain protectionDomain);
- public native Class> defineClass(String name, byte[] b, int off, int len);
-
/**
* Define a class but do not make it known to the class loader or system dictionary.
*
diff --git a/jdk/src/share/classes/sun/reflect/CallerSensitive.java b/jdk/src/share/classes/sun/reflect/CallerSensitive.java
new file mode 100644
index 00000000000..19e47cdd5ea
--- /dev/null
+++ b/jdk/src/share/classes/sun/reflect/CallerSensitive.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2013, 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.reflect;
+
+import java.lang.annotation.*;
+import static java.lang.annotation.ElementType.*;
+
+/**
+ * A method annotated @CallerSensitive is sensitive to its calling class,
+ * via {@link sun.reflect.Reflection#getCallerClass Reflection.getCallerClass},
+ * or via some equivalent.
+ *
+ * @author John R. Rose
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({CONSTRUCTOR, METHOD})
+public @interface CallerSensitive {
+}
diff --git a/jdk/src/share/classes/sun/reflect/Reflection.java b/jdk/src/share/classes/sun/reflect/Reflection.java
index fb559826969..274705fc249 100644
--- a/jdk/src/share/classes/sun/reflect/Reflection.java
+++ b/jdk/src/share/classes/sun/reflect/Reflection.java
@@ -51,16 +51,11 @@ public class Reflection {
methodFilterMap = new HashMap<>();
}
- /** Returns the class of the method realFramesToSkip
- frames up the stack (zero-based), ignoring frames associated
- with java.lang.reflect.Method.invoke() and its implementation.
- The first frame is that associated with this method, so
- getCallerClass(0)
returns the Class object for
- sun.reflect.Reflection. Frames associated with
- java.lang.reflect.Method.invoke() and its implementation are
- completely ignored and do not count toward the number of "real"
- frames skipped. */
- public static native Class> getCallerClass(int realFramesToSkip);
+ /** Returns the class of the caller of the method calling this method,
+ ignoring frames associated with java.lang.reflect.Method.invoke()
+ and its implementation. */
+ @CallerSensitive
+ public static native Class> getCallerClass();
/** Retrieves the access flags written to the class file. For
inner classes these flags may differ from those returned by
@@ -321,4 +316,27 @@ public class Reflection {
}
return newMembers;
}
+
+ /**
+ * Tests if the given method is caller-sensitive and the declaring class
+ * is defined by either the bootstrap class loader or extension class loader.
+ */
+ public static boolean isCallerSensitive(Method m) {
+ final ClassLoader loader = m.getDeclaringClass().getClassLoader();
+ if (sun.misc.VM.isSystemDomainLoader(loader) || isExtClassLoader(loader)) {
+ return m.isAnnotationPresent(CallerSensitive.class);
+ }
+ return false;
+ }
+
+ private static boolean isExtClassLoader(ClassLoader loader) {
+ ClassLoader cl = ClassLoader.getSystemClassLoader();
+ while (cl != null) {
+ if (cl.getParent() == null && cl == loader) {
+ return true;
+ }
+ cl = cl.getParent();
+ }
+ return false;
+ }
}
diff --git a/jdk/src/share/classes/sun/reflect/misc/MethodUtil.java b/jdk/src/share/classes/sun/reflect/misc/MethodUtil.java
index 9d9c5ab6015..24abe866761 100644
--- a/jdk/src/share/classes/sun/reflect/misc/MethodUtil.java
+++ b/jdk/src/share/classes/sun/reflect/misc/MethodUtil.java
@@ -46,8 +46,28 @@ import sun.misc.IOUtils;
class Trampoline {
+ static {
+ if (Trampoline.class.getClassLoader() == null) {
+ throw new Error(
+ "Trampoline must not be defined by the bootstrap classloader");
+ }
+ }
+
+ private static void ensureInvocableMethod(Method m)
+ throws InvocationTargetException
+ {
+ Class> clazz = m.getDeclaringClass();
+ if (clazz.equals(AccessController.class) ||
+ clazz.equals(Method.class) ||
+ clazz.getName().startsWith("java.lang.invoke."))
+ throw new InvocationTargetException(
+ new UnsupportedOperationException("invocation not supported"));
+ }
+
private static Object invoke(Method m, Object obj, Object[] params)
- throws InvocationTargetException, IllegalAccessException {
+ throws InvocationTargetException, IllegalAccessException
+ {
+ ensureInvocableMethod(m);
return m.invoke(obj, params);
}
}
@@ -251,16 +271,6 @@ public final class MethodUtil extends SecureClassLoader {
*/
public static Object invoke(Method m, Object obj, Object[] params)
throws InvocationTargetException, IllegalAccessException {
- if (m.getDeclaringClass().equals(AccessController.class) ||
- (m.getDeclaringClass().equals(java.lang.invoke.MethodHandles.class)
- && m.getName().equals("lookup")) ||
- (m.getDeclaringClass().equals(java.lang.invoke.MethodHandles.Lookup.class)
- && (m.getName().startsWith("find") ||
- m.getName().startsWith("bind") ||
- m.getName().startsWith("unreflect"))) ||
- m.getDeclaringClass().equals(Method.class))
- throw new InvocationTargetException(
- new UnsupportedOperationException("invocation not supported"));
try {
return bounce.invoke(null, new Object[] {m, obj, params});
} catch (InvocationTargetException ie) {
@@ -293,10 +303,10 @@ public final class MethodUtil extends SecureClassLoader {
Method.class, Object.class, Object[].class
};
Method b = t.getDeclaredMethod("invoke", types);
- ((AccessibleObject)b).setAccessible(true);
- return b;
- }
- });
+ b.setAccessible(true);
+ return b;
+ }
+ });
} catch (Exception e) {
throw new InternalError("bouncer cannot be found", e);
}
diff --git a/jdk/src/share/classes/sun/rmi/server/MarshalInputStream.java b/jdk/src/share/classes/sun/rmi/server/MarshalInputStream.java
index e24a8fb3fdb..4f67941a5d5 100644
--- a/jdk/src/share/classes/sun/rmi/server/MarshalInputStream.java
+++ b/jdk/src/share/classes/sun/rmi/server/MarshalInputStream.java
@@ -55,13 +55,19 @@ import java.rmi.server.RMIClassLoader;
public class MarshalInputStream extends ObjectInputStream {
/**
- * value of "java.rmi.server.useCodebaseOnly" property,
+ * Value of "java.rmi.server.useCodebaseOnly" property,
* as cached at class initialization time.
+ *
+ * The default value is true. That is, the value is true
+ * if the property is absent or is not equal to "false".
+ * The value is only false when the property is present
+ * and is equal to "false".
*/
private static final boolean useCodebaseOnlyProperty =
- java.security.AccessController.doPrivileged(
- new sun.security.action.GetBooleanAction(
- "java.rmi.server.useCodebaseOnly")).booleanValue();
+ ! java.security.AccessController.doPrivileged(
+ new sun.security.action.GetPropertyAction(
+ "java.rmi.server.useCodebaseOnly", "true"))
+ .equalsIgnoreCase("false");
/** table to hold sun classes to which access is explicitly permitted */
protected static Map> permittedSunClasses
diff --git a/jdk/src/share/classes/sun/security/krb5/KrbApReq.java b/jdk/src/share/classes/sun/security/krb5/KrbApReq.java
index 535bb0dc52f..2bc01f693f5 100644
--- a/jdk/src/share/classes/sun/security/krb5/KrbApReq.java
+++ b/jdk/src/share/classes/sun/security/krb5/KrbApReq.java
@@ -204,7 +204,7 @@ public class KrbApReq {
int usage)
throws KrbException, IOException {
- ctime = new KerberosTime(KerberosTime.NOW);
+ ctime = KerberosTime.now();
init(options,
tgs_creds.ticket,
tgs_creds.key,
@@ -287,14 +287,14 @@ public class KrbApReq {
authenticator = new Authenticator(temp2);
ctime = authenticator.ctime;
cusec = authenticator.cusec;
- authenticator.ctime.setMicroSeconds(authenticator.cusec);
+ authenticator.ctime =
+ authenticator.ctime.withMicroSeconds(authenticator.cusec);
if (!authenticator.cname.equals(enc_ticketPart.cname)) {
throw new KrbApErrException(Krb5.KRB_AP_ERR_BADMATCH);
}
- KerberosTime currTime = new KerberosTime(KerberosTime.NOW);
- if (!authenticator.ctime.inClockSkew(currTime))
+ if (!authenticator.ctime.inClockSkew())
throw new KrbApErrException(Krb5.KRB_AP_ERR_SKEW);
// start to check if it is a replay attack.
@@ -304,7 +304,7 @@ public class KrbApReq {
if (table.get(time, authenticator.cname.toString()) != null) {
throw new KrbApErrException(Krb5.KRB_AP_ERR_REPEAT);
} else {
- table.put(client, time, currTime.getTime());
+ table.put(client, time, System.currentTimeMillis());
}
if (initiator != null) {
@@ -329,7 +329,7 @@ public class KrbApReq {
// else
// save authenticator to check for later
- KerberosTime now = new KerberosTime(KerberosTime.NOW);
+ KerberosTime now = KerberosTime.now();
if ((enc_ticketPart.starttime != null &&
enc_ticketPart.starttime.greaterThanWRTClockSkew(now)) ||
diff --git a/jdk/src/share/classes/sun/security/krb5/KrbAppMessage.java b/jdk/src/share/classes/sun/security/krb5/KrbAppMessage.java
index cf19cf98242..47aa1681a1a 100644
--- a/jdk/src/share/classes/sun/security/krb5/KrbAppMessage.java
+++ b/jdk/src/share/classes/sun/security/krb5/KrbAppMessage.java
@@ -71,12 +71,18 @@ abstract class KrbAppMessage {
}
if (packetTimestamp != null) {
- packetTimestamp.setMicroSeconds(packetUsec);
- if (!packetTimestamp.inClockSkew())
+ if (packetUsec != null) {
+ packetTimestamp =
+ packetTimestamp.withMicroSeconds(packetUsec.intValue());
+ }
+ if (!packetTimestamp.inClockSkew()) {
throw new KrbApErrException(Krb5.KRB_AP_ERR_SKEW);
- } else
- if (timestampRequired)
+ }
+ } else {
+ if (timestampRequired) {
throw new KrbApErrException(Krb5.KRB_AP_ERR_SKEW);
+ }
+ }
// XXX check replay cache
// if (rcache.repeated(packetTimestamp, packetUsec, packetSAddress))
diff --git a/jdk/src/share/classes/sun/security/krb5/KrbCred.java b/jdk/src/share/classes/sun/security/krb5/KrbCred.java
index 9a131811959..64dada1d35e 100644
--- a/jdk/src/share/classes/sun/security/krb5/KrbCred.java
+++ b/jdk/src/share/classes/sun/security/krb5/KrbCred.java
@@ -103,7 +103,7 @@ public class KrbCred {
delegatedCreds.renewTill, tgService,
delegatedCreds.cAddr);
- timeStamp = new KerberosTime(KerberosTime.NOW);
+ timeStamp = KerberosTime.now();
KrbCredInfo[] credInfos = {credInfo};
EncKrbCredPart encPart =
new EncKrbCredPart(credInfos,
diff --git a/jdk/src/share/classes/sun/security/krb5/KrbTgsReq.java b/jdk/src/share/classes/sun/security/krb5/KrbTgsReq.java
index 9cd84c6d9a4..32263b53770 100644
--- a/jdk/src/share/classes/sun/security/krb5/KrbTgsReq.java
+++ b/jdk/src/share/classes/sun/security/krb5/KrbTgsReq.java
@@ -147,8 +147,7 @@ public class KrbTgsReq {
princName = cname;
servName = sname;
- ctime = new KerberosTime(KerberosTime.NOW);
-
+ ctime = KerberosTime.now();
// check if they are valid arguments. The optional fields
// should be consistent with settings in KDCOptions.
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 ce141419f83..3beaac873ce 100644
--- a/jdk/src/share/classes/sun/security/krb5/internal/KerberosTime.java
+++ b/jdk/src/share/classes/sun/security/krb5/internal/KerberosTime.java
@@ -30,18 +30,20 @@
package sun.security.krb5.internal;
-import java.util.TimeZone;
-import sun.security.util.*;
+import sun.security.krb5.Asn1Exception;
import sun.security.krb5.Config;
import sun.security.krb5.KrbException;
-import sun.security.krb5.Asn1Exception;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.Calendar;
+import sun.security.util.DerInputStream;
+import sun.security.util.DerOutputStream;
+import sun.security.util.DerValue;
+
import java.io.IOException;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
/**
- * Implements the ASN.1 KerberosTime type.
+ * Implements the ASN.1 KerberosTime type. This is an immutable class.
*
*
* KerberosTime ::= GeneralizedTime -- with no fractional seconds
@@ -62,55 +64,38 @@ import java.io.IOException;
* same class can be used as a precise timestamp in Authenticator etc.
*/
-public class KerberosTime implements Cloneable {
+public class KerberosTime {
- private long kerberosTime; // milliseconds since epoch, a Date.getTime() value
- private int microSeconds; // the last three digits of the microsecond value
+ private final long kerberosTime; // milliseconds since epoch, Date.getTime()
+ private final int microSeconds; // last 3 digits of the real microsecond
// The time when this class is loaded. Used in setNow()
private static long initMilli = System.currentTimeMillis();
private static long initMicro = System.nanoTime() / 1000;
- private static long syncTime;
private static boolean DEBUG = Krb5.DEBUG;
- public static final boolean NOW = true;
- public static final boolean UNADJUSTED_NOW = false;
-
- public KerberosTime(long time) {
- kerberosTime = time;
- }
-
+ // Do not make this public. It's a little confusing that micro
+ // is only the last 3 digits of microsecond.
private KerberosTime(long time, int micro) {
kerberosTime = time;
microSeconds = micro;
}
- public Object clone() {
- return new KerberosTime(kerberosTime, microSeconds);
+ /**
+ * Creates a KerberosTime object from milliseconds since epoch.
+ */
+ public KerberosTime(long time) {
+ this(time, 0);
}
// This constructor is used in the native code
// src/windows/native/sun/security/krb5/NativeCreds.c
public KerberosTime(String time) throws Asn1Exception {
- kerberosTime = toKerberosTime(time);
- }
-
- /**
- * Constructs a KerberosTime object.
- * @param encoding a DER-encoded data.
- * @exception Asn1Exception if an error occurs while decoding an ASN1 encoded data.
- * @exception IOException if an I/O error occurs while reading encoded data.
- */
- public KerberosTime(DerValue encoding) throws Asn1Exception, IOException {
- GregorianCalendar calendar = new GregorianCalendar();
- Date temp = encoding.getGeneralizedTime();
- kerberosTime = temp.getTime();
+ this(toKerberosTime(time), 0);
}
private static long toKerberosTime(String time) throws Asn1Exception {
- // this method only used by KerberosTime class.
-
// ASN.1 GeneralizedTime format:
// "19700101000000Z"
@@ -133,30 +118,34 @@ public class KerberosTime implements Cloneable {
Integer.parseInt(time.substring(8, 10)),
Integer.parseInt(time.substring(10, 12)),
Integer.parseInt(time.substring(12, 14)));
-
- //The Date constructor assumes the setting are local relative
- //and converts the time to UTC before storing it. Since we
- //want the internal representation to correspond to local
- //and not UTC time we subtract the UTC time offset.
- return (calendar.getTime().getTime());
-
- }
-
- // should be moved to sun.security.krb5.util class
- public static String zeroPad(String s, int length) {
- StringBuffer temp = new StringBuffer(s);
- while (temp.length() < length)
- temp.insert(0, '0');
- return temp.toString();
+ return calendar.getTimeInMillis();
}
+ /**
+ * Creates a KerberosTime object from a Date object.
+ */
public KerberosTime(Date time) {
- kerberosTime = time.getTime(); // (time.getTimezoneOffset() * 60000L);
+ this(time.getTime(), 0);
}
- public KerberosTime(boolean initToNow) {
- if (initToNow) {
- setNow();
+ /**
+ * Creates a KerberosTime object for now. It uses System.nanoTime()
+ * to get a more precise time than "new Date()".
+ */
+ public static KerberosTime now() {
+ 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;
+ return new KerberosTime(newMilli, 0);
+ } else {
+ return new KerberosTime(calcMilli, (int)(microElapsed % 1000));
}
}
@@ -169,13 +158,13 @@ public class KerberosTime implements Cloneable {
calendar.clear();
calendar.setTimeInMillis(kerberosTime);
- return zeroPad(Integer.toString(calendar.get(Calendar.YEAR)), 4) +
- zeroPad(Integer.toString(calendar.get(Calendar.MONTH) + 1), 2) +
- zeroPad(Integer.toString(calendar.get(Calendar.DAY_OF_MONTH)), 2) +
- zeroPad(Integer.toString(calendar.get(Calendar.HOUR_OF_DAY)), 2) +
- zeroPad(Integer.toString(calendar.get(Calendar.MINUTE)), 2) +
- zeroPad(Integer.toString(calendar.get(Calendar.SECOND)), 2) + 'Z';
-
+ return String.format("%04d%02d%02d%02d%02d%02dZ",
+ calendar.get(Calendar.YEAR),
+ calendar.get(Calendar.MONTH) + 1,
+ calendar.get(Calendar.DAY_OF_MONTH),
+ calendar.get(Calendar.HOUR_OF_DAY),
+ calendar.get(Calendar.MINUTE),
+ calendar.get(Calendar.SECOND));
}
/**
@@ -194,40 +183,8 @@ public class KerberosTime implements Cloneable {
return kerberosTime;
}
-
- public void setTime(Date time) {
- kerberosTime = time.getTime(); // (time.getTimezoneOffset() * 60000L);
- microSeconds = 0;
- }
-
- public void setTime(long time) {
- kerberosTime = time;
- microSeconds = 0;
- }
-
public Date toDate() {
- Date temp = new Date(kerberosTime);
- temp.setTime(temp.getTime());
- return temp;
- }
-
- public void setNow() {
- 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);
- }
+ return new Date(kerberosTime);
}
public int getMicroSeconds() {
@@ -235,45 +192,25 @@ public class KerberosTime implements Cloneable {
return temp_long.intValue() + microSeconds;
}
- public void setMicroSeconds(int usec) {
- microSeconds = usec % 1000;
- Integer temp_int = new Integer(usec);
- long temp_long = temp_int.longValue() / 1000L;
- kerberosTime = kerberosTime - (kerberosTime % 1000L) + temp_long;
+ /**
+ * Returns a new KerberosTime object with the original seconds
+ * and the given microseconds.
+ */
+ public KerberosTime withMicroSeconds(int usec) {
+ return new KerberosTime(
+ kerberosTime - kerberosTime%1000L + usec/1000L,
+ usec%1000);
}
- public void setMicroSeconds(Integer usec) {
- if (usec != null) {
- microSeconds = usec.intValue() % 1000;
- long temp_long = usec.longValue() / 1000L;
- kerberosTime = kerberosTime - (kerberosTime % 1000L) + temp_long;
- }
- }
-
- public boolean inClockSkew(int clockSkew) {
- KerberosTime now = new KerberosTime(KerberosTime.NOW);
-
- if (java.lang.Math.abs(kerberosTime - now.kerberosTime) >
- clockSkew * 1000L)
- return false;
- return true;
+ private boolean inClockSkew(int clockSkew) {
+ return java.lang.Math.abs(kerberosTime - System.currentTimeMillis())
+ <= clockSkew * 1000L;
}
public boolean inClockSkew() {
return inClockSkew(getDefaultSkew());
}
- public boolean inClockSkew(int clockSkew, KerberosTime now) {
- if (java.lang.Math.abs(kerberosTime - now.kerberosTime) >
- clockSkew * 1000L)
- return false;
- return true;
- }
-
- public boolean inClockSkew(KerberosTime time) {
- return inClockSkew(getDefaultSkew(), time);
- }
-
public boolean greaterThanWRTClockSkew(KerberosTime time, int clockSkew) {
if ((kerberosTime - time.kerberosTime) > clockSkew * 1000L)
return true;
@@ -317,24 +254,22 @@ public class KerberosTime implements Cloneable {
return temp_long.intValue();
}
- public void setSeconds(int sec) {
- Integer temp_int = new Integer(sec);
- kerberosTime = temp_int.longValue() * 1000L;
- }
-
/**
* Parse (unmarshal) a kerberostime from a DER input stream. This form
* parsing might be used when expanding a value which is part of
* a constructed sequence and uses explicitly tagged type.
*
* @exception Asn1Exception on error.
- * @param data the Der input stream value, which contains one or more marshaled value.
+ * @param data the Der input stream value, which contains
+ * one or more marshaled value.
* @param explicitTag tag number.
* @param optional indicates if this data field is optional
* @return an instance of KerberosTime.
*
*/
- public static KerberosTime parse(DerInputStream data, byte explicitTag, boolean optional) throws Asn1Exception, IOException {
+ public static KerberosTime parse(
+ DerInputStream data, byte explicitTag, boolean optional)
+ throws Asn1Exception, IOException {
if ((optional) && (((byte)data.peekByte() & (byte)0x1F)!= explicitTag))
return null;
DerValue der = data.getDerValue();
@@ -343,7 +278,8 @@ public class KerberosTime implements Cloneable {
}
else {
DerValue subDer = der.getData().getDerValue();
- return new KerberosTime(subDer);
+ Date temp = subDer.getGeneralizedTime();
+ return new KerberosTime(temp.getTime(), 0);
}
}
diff --git a/jdk/src/share/classes/sun/security/krb5/internal/KrbCredInfo.java b/jdk/src/share/classes/sun/security/krb5/internal/KrbCredInfo.java
index 4acf451cc6c..18fa7412fac 100644
--- a/jdk/src/share/classes/sun/security/krb5/internal/KrbCredInfo.java
+++ b/jdk/src/share/classes/sun/security/krb5/internal/KrbCredInfo.java
@@ -187,14 +187,10 @@ public class KrbCredInfo {
kcred.pname = (PrincipalName)pname.clone();
if (flags != null)
kcred.flags = (TicketFlags)flags.clone();
- if (authtime != null)
- kcred.authtime = (KerberosTime)authtime.clone();
- if (starttime != null)
- kcred.starttime = (KerberosTime)starttime.clone();
- if (endtime != null)
- kcred.endtime = (KerberosTime)endtime.clone();
- if (renewTill != null)
- kcred.renewTill = (KerberosTime)renewTill.clone();
+ kcred.authtime = authtime;
+ kcred.starttime = starttime;
+ kcred.endtime = endtime;
+ kcred.renewTill = renewTill;
if (sname != null)
kcred.sname = (PrincipalName)sname.clone();
if (caddr != null)
diff --git a/jdk/src/share/classes/sun/security/krb5/internal/LastReqEntry.java b/jdk/src/share/classes/sun/security/krb5/internal/LastReqEntry.java
index fa4ae0a5e11..396d3b8df03 100644
--- a/jdk/src/share/classes/sun/security/krb5/internal/LastReqEntry.java
+++ b/jdk/src/share/classes/sun/security/krb5/internal/LastReqEntry.java
@@ -90,7 +90,7 @@ public class LastReqEntry {
public Object clone() {
LastReqEntry newEntry = new LastReqEntry();
newEntry.lrType = lrType;
- newEntry.lrValue = (KerberosTime)lrValue.clone();
+ newEntry.lrValue = lrValue;
return newEntry;
}
}
diff --git a/jdk/src/share/classes/sun/security/krb5/internal/PAEncTSEnc.java b/jdk/src/share/classes/sun/security/krb5/internal/PAEncTSEnc.java
index e5f2f755be9..83375647046 100644
--- a/jdk/src/share/classes/sun/security/krb5/internal/PAEncTSEnc.java
+++ b/jdk/src/share/classes/sun/security/krb5/internal/PAEncTSEnc.java
@@ -65,7 +65,7 @@ public class PAEncTSEnc {
}
public PAEncTSEnc() {
- KerberosTime now = new KerberosTime(KerberosTime.NOW);
+ KerberosTime now = KerberosTime.now();
pATimeStamp = now;
pAUSec = new Integer(now.getMicroSeconds());
}
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 f27a1588ec3..7128545a25a 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
@@ -68,14 +68,11 @@ public class Credentials {
sname = (PrincipalName) new_sname.clone();
key = (EncryptionKey) new_key.clone();
- authtime = (KerberosTime) new_authtime.clone();
- if (new_starttime != null) {
- starttime = (KerberosTime) new_starttime.clone();
- }
- endtime = (KerberosTime) new_endtime.clone();
- if (new_renewTill != null) {
- renewTill = (KerberosTime) new_renewTill.clone();
- }
+ authtime = new_authtime;
+ starttime = new_starttime;
+ endtime = new_endtime;
+ renewTill = new_renewTill;
+
if (new_caddr != null) {
caddr = (HostAddresses) new_caddr.clone();
}
@@ -104,14 +101,11 @@ public class Credentials {
ticket = (Ticket) kdcRep.ticket.clone();
key = (EncryptionKey) kdcRep.encKDCRepPart.key.clone();
flags = (TicketFlags) kdcRep.encKDCRepPart.flags.clone();
- authtime = (KerberosTime) kdcRep.encKDCRepPart.authtime.clone();
- if (kdcRep.encKDCRepPart.starttime != null) {
- starttime = (KerberosTime) kdcRep.encKDCRepPart.starttime.clone();
- }
- endtime = (KerberosTime) kdcRep.encKDCRepPart.endtime.clone();
- if (kdcRep.encKDCRepPart.renewTill != null) {
- renewTill = (KerberosTime) kdcRep.encKDCRepPart.renewTill.clone();
- }
+ authtime = kdcRep.encKDCRepPart.authtime;
+ starttime = kdcRep.encKDCRepPart.starttime;
+ endtime = kdcRep.encKDCRepPart.endtime;
+ renewTill = kdcRep.encKDCRepPart.renewTill;
+
sname = (PrincipalName) kdcRep.encKDCRepPart.sname.clone();
caddr = (HostAddresses) kdcRep.encKDCRepPart.caddr.clone();
secondTicket = (Ticket) new_secondTicket.clone();
@@ -128,18 +122,10 @@ public class Credentials {
sname = (PrincipalName) kdcRep.encKDCRepPart.sname.clone();
cname = (PrincipalName) kdcRep.cname.clone();
key = (EncryptionKey) kdcRep.encKDCRepPart.key.clone();
- authtime = (KerberosTime) kdcRep.encKDCRepPart.authtime.clone();
- if (kdcRep.encKDCRepPart.starttime != null) {
- starttime = (KerberosTime) kdcRep.encKDCRepPart.starttime.clone();
- } else {
- starttime = null;
- }
- endtime = (KerberosTime) kdcRep.encKDCRepPart.endtime.clone();
- if (kdcRep.encKDCRepPart.renewTill != null) {
- renewTill = (KerberosTime) kdcRep.encKDCRepPart.renewTill.clone();
- } else {
- renewTill = null;
- }
+ authtime = kdcRep.encKDCRepPart.authtime;
+ starttime = kdcRep.encKDCRepPart.starttime;
+ endtime = kdcRep.encKDCRepPart.endtime;
+ renewTill = kdcRep.encKDCRepPart.renewTill;
// if (kdcRep.msgType == Krb5.KRB_AS_REP) {
// isEncInSKey = false;
// secondTicket = null;
diff --git a/jdk/src/share/classes/sun/security/provider/SHA2.java b/jdk/src/share/classes/sun/security/provider/SHA2.java
index 54f34545918..23007c96527 100644
--- a/jdk/src/share/classes/sun/security/provider/SHA2.java
+++ b/jdk/src/share/classes/sun/security/provider/SHA2.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2013, 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
@@ -101,7 +101,7 @@ abstract class SHA2 extends DigestBase {
i2bBig4((int)bitsProcessed, buffer, 60);
implCompress(buffer, 0);
- i2bBig(state, 0, out, ofs, 32);
+ i2bBig(state, 0, out, ofs, engineGetDigestLength());
}
/**
diff --git a/jdk/src/share/classes/sun/security/util/UntrustedCertificates.java b/jdk/src/share/classes/sun/security/util/UntrustedCertificates.java
index 03fdbc78332..73495df5bcc 100644
--- a/jdk/src/share/classes/sun/security/util/UntrustedCertificates.java
+++ b/jdk/src/share/classes/sun/security/util/UntrustedCertificates.java
@@ -843,5 +843,52 @@ public final class UntrustedCertificates {
"zCOfhbsRWdMLYepauaNZOIMZXmFwcrIl0TGMkTAtATz+XmZc\n" +
"-----END CERTIFICATE-----");
+ //
+ // Revoked code signing certificate w/ a stolen key issued by GoDaddy
+ // used to sign malware
+ //
+
+ // Subject: CN=CLEARESULT CONSULTING INC., OU=Corporate IT,
+ // O=CLEARESULT CONSULTING INC., L=Austin, ST=TX, C=US
+ // Issuer: SERIALNUMBER=07969287,
+ // CN=Go Daddy Secure Certification Authority,
+ // OU=http://certificates.godaddy.com/repository,
+ // O="GoDaddy.com, Inc.",
+ // L=Scottsdale,
+ // ST=Arizona,
+ // C=US
+ // Serial: 2b:73:43:2a:a8:4f:44
+ add("clearesult-consulting-inc-2AA84F44",
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIIFYjCCBEqgAwIBAgIHK3NDKqhPRDANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE\n" +
+ "BhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAY\n" +
+ "BgNVBAoTEUdvRGFkZHkuY29tLCBJbmMuMTMwMQYDVQQLEypodHRwOi8vY2VydGlm\n" +
+ "aWNhdGVzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkxMDAuBgNVBAMTJ0dvIERhZGR5\n" +
+ "IFNlY3VyZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTERMA8GA1UEBRMIMDc5Njky\n" +
+ "ODcwHhcNMTIwMjE1MjEwOTA2WhcNMTQwMjE1MjEwOTA2WjCBjDELMAkGA1UEBgwC\n" +
+ "VVMxCzAJBgNVBAgMAlRYMQ8wDQYDVQQHDAZBdXN0aW4xIzAhBgNVBAoMGkNMRUFS\n" +
+ "RVNVTFQgQ09OU1VMVElORyBJTkMuMRUwEwYDVQQLDAxDb3Jwb3JhdGUgSVQxIzAh\n" +
+ "BgNVBAMMGkNMRUFSRVNVTFQgQ09OU1VMVElORyBJTkMuMIIBIjANBgkqhkiG9w0B\n" +
+ "AQEFAAOCAQ8AMIIBCgKCAQEAtIOjCKeAicull+7ZIzt0/4ya3IeXUFlfypqKMLkU\n" +
+ "IbKjn0P5uMj6VE3rlbZr44RCegxvdnR6umBh1c0ZXoN3o+yc0JKcKcLiApmJJ277\n" +
+ "p7IbLwYDhBXRQNoIJm187IOMRPIxsKN4hL91txn9jGBmW+9zKlJlNhR5R7vjwU2E\n" +
+ "jrH/6oqsc9EM2yYpfjlNv6+3jSwAYZCkSWr+27PQOV+YHKmIxtJjX0upFz5FdIrV\n" +
+ "9CCX+L2Kji1THOkSgG4QTbYxmEcHqGViWz8hXLeNXjcbEsPuIiAu3hknxRHfUTE/\n" +
+ "U0Lh0Ug1e3LrJu+WnxM2SmUY4krsZ22c0yWUW9hzWITIjQIDAQABo4IBhzCCAYMw\n" +
+ "DwYDVR0TAQH/BAUwAwEBADATBgNVHSUEDDAKBggrBgEFBQcDAzAOBgNVHQ8BAf8E\n" +
+ "BAMCB4AwMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5nb2RhZGR5LmNvbS9n\n" +
+ "ZHM1LTE2LmNybDBTBgNVHSAETDBKMEgGC2CGSAGG/W0BBxcCMDkwNwYIKwYBBQUH\n" +
+ "AgEWK2h0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeS8w\n" +
+ "gYAGCCsGAQUFBwEBBHQwcjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZ29kYWRk\n" +
+ "eS5jb20vMEoGCCsGAQUFBzAChj5odHRwOi8vY2VydGlmaWNhdGVzLmdvZGFkZHku\n" +
+ "Y29tL3JlcG9zaXRvcnkvZ2RfaW50ZXJtZWRpYXRlLmNydDAfBgNVHSMEGDAWgBT9\n" +
+ "rGEyk2xF1uLuhV+auud2mWjM5zAdBgNVHQ4EFgQUDtdeKqeN2QkcbEp1HovFieNB\n" +
+ "XiowDQYJKoZIhvcNAQEFBQADggEBAD74Agw5tvi2aBl4/f/s7/VE/BClzDsKMb9K\n" +
+ "v9qpeC45ZA/jelxV11HKbQnVF194gDb7D2H9OsAsRUy8HVKbXEcc/8dKvwOqb+BC\n" +
+ "2i/EmfjLgmCfezNFtLq8xcPxF3zIRc44vPrK0z4YZsaHdH+yTEJ51p5EMdTqaLaP\n" +
+ "4n5m8LX3RfqlQB9dYFe6dUoYZjKm9d/pIRww3VqfOzjl42Edi1w6dWmBVMx1NZuR\n" +
+ "DBabJH1vJ9Gd+KwxMCmBZ6pQPl28JDimhJhI2LNqU349uADQVV0HJosddN/ARyyI\n" +
+ "LSIQO7BnNVKVG9Iujf33bvPNeg0qNz5qw+rKKq97Pqeum+L5oKU=\n" +
+ "-----END CERTIFICATE-----");
}
}
diff --git a/jdk/src/share/javavm/export/jvm.h b/jdk/src/share/javavm/export/jvm.h
index 44b0be576d4..f10019a92ec 100644
--- a/jdk/src/share/javavm/export/jvm.h
+++ b/jdk/src/share/javavm/export/jvm.h
@@ -350,16 +350,21 @@ JVM_NewMultiArray(JNIEnv *env, jclass eltClass, jintArray dim);
/*
* java.lang.Class and java.lang.ClassLoader
*/
+
+#define JVM_DEPTH -1
+
/*
- * Returns the class in which the code invoking the native method
- * belongs.
+ * Returns the immediate caller class of the native method invoking
+ * JVM_GetCallerClass. The Method.invoke and other frames due to
+ * reflection machinery are skipped.
*
- * Note that in JDK 1.1, native methods did not create a frame.
- * In 1.2, they do. Therefore native methods like Class.forName
- * can no longer look at the current frame for the caller class.
+ * The depth parameter must be -1 (JVM_DEPTH). The caller is expected
+ * to be marked with sun.reflect.CallerSensitive. The JVM will throw
+ * an error if it is not marked propertly.
*/
JNIEXPORT jclass JNICALL
-JVM_GetCallerClass(JNIEnv *env, int n);
+JVM_GetCallerClass(JNIEnv *env, int depth);
+
/*
* Find primitive classes
diff --git a/jdk/src/share/lib/security/java.security-linux b/jdk/src/share/lib/security/java.security-linux
index f26efb05284..6a4fe65c042 100644
--- a/jdk/src/share/lib/security/java.security-linux
+++ b/jdk/src/share/lib/security/java.security-linux
@@ -177,23 +177,36 @@ keystore.type=jks
# corresponding RuntimePermission ("accessClassInPackage."+package) has
# been granted.
package.access=sun.,\
- com.sun.xml.internal.bind.,\
- com.sun.xml.internal.org.jvnet.staxex.,\
- com.sun.xml.internal.ws.,\
+ com.sun.xml.internal.,\
com.sun.imageio.,\
com.sun.istack.internal.,\
com.sun.jmx.,\
com.sun.proxy.,\
- com.sun.org.apache.xerces.internal.utils.,\
+ com.sun.org.apache.bcel.internal.,\
+ com.sun.org.apache.regexp.internal.,\
+ com.sun.org.apache.xerces.internal.,\
+ com.sun.org.apache.xpath.internal.,\
+ com.sun.org.apache.xalan.internal.extensions.,\
+ com.sun.org.apache.xalan.internal.lib.,\
+ com.sun.org.apache.xalan.internal.res.,\
+ com.sun.org.apache.xalan.internal.templates.,\
com.sun.org.apache.xalan.internal.utils.,\
- com.sun.org.glassfish.external.,\
- com.sun.org.glassfish.gmbal.,\
+ com.sun.org.apache.xalan.internal.xslt.,\
+ com.sun.org.apache.xalan.internal.xsltc.cmdline.,\
+ com.sun.org.apache.xalan.internal.xsltc.compiler.,\
+ com.sun.org.apache.xalan.internal.xsltc.trax.,\
+ com.sun.org.apache.xalan.internal.xsltc.util.,\
+ com.sun.org.apache.xml.internal.res.,\
+ com.sun.org.apache.xml.internal.serializer.utils.,\
+ com.sun.org.apache.xml.internal.utils.,\
+ com.sun.org.glassfish.,\
com.oracle.xmlns.internal.,\
com.oracle.webservices.internal.,\
jdk.internal.,\
jdk.nashorn.internal.,\
jdk.nashorn.tools.
+
#
# List of comma-separated packages that start with or equal this string
# will cause a security exception to be thrown when
@@ -205,23 +218,36 @@ package.access=sun.,\
# checkPackageDefinition.
#
package.definition=sun.,\
- com.sun.xml.internal.bind.,\
- com.sun.xml.internal.org.jvnet.staxex.,\
- com.sun.xml.internal.ws.,\
+ com.sun.xml.internal.,\
com.sun.imageio.,\
com.sun.istack.internal.,\
com.sun.jmx.,\
com.sun.proxy.,\
- com.sun.org.apache.xerces.internal.utils.,\
+ com.sun.org.apache.bcel.internal.,\
+ com.sun.org.apache.regexp.internal.,\
+ com.sun.org.apache.xerces.internal.,\
+ com.sun.org.apache.xpath.internal.,\
+ com.sun.org.apache.xalan.internal.extensions.,\
+ com.sun.org.apache.xalan.internal.lib.,\
+ com.sun.org.apache.xalan.internal.res.,\
+ com.sun.org.apache.xalan.internal.templates.,\
com.sun.org.apache.xalan.internal.utils.,\
- com.sun.org.glassfish.external.,\
- com.sun.org.glassfish.gmbal.,\
+ com.sun.org.apache.xalan.internal.xslt.,\
+ com.sun.org.apache.xalan.internal.xsltc.cmdline.,\
+ com.sun.org.apache.xalan.internal.xsltc.compiler.,\
+ com.sun.org.apache.xalan.internal.xsltc.trax.,\
+ com.sun.org.apache.xalan.internal.xsltc.util.,\
+ com.sun.org.apache.xml.internal.res.,\
+ com.sun.org.apache.xml.internal.serializer.utils.,\
+ com.sun.org.apache.xml.internal.utils.,\
+ com.sun.org.glassfish.,\
com.oracle.xmlns.internal.,\
com.oracle.webservices.internal.,\
jdk.internal.,\
jdk.nashorn.internal.,\
jdk.nashorn.tools.
+
#
# Determines whether this properties file can be appended to
# or overridden on the command line via -Djava.security.properties
diff --git a/jdk/src/share/lib/security/java.security-macosx b/jdk/src/share/lib/security/java.security-macosx
index 32369dae426..9f7905dd305 100644
--- a/jdk/src/share/lib/security/java.security-macosx
+++ b/jdk/src/share/lib/security/java.security-macosx
@@ -178,17 +178,29 @@ keystore.type=jks
# corresponding RuntimePermission ("accessClassInPackage."+package) has
# been granted.
package.access=sun.,\
- com.sun.xml.internal.bind.,\
- com.sun.xml.internal.org.jvnet.staxex.,\
- com.sun.xml.internal.ws.,\
+ com.sun.xml.internal.,\
com.sun.imageio.,\
com.sun.istack.internal.,\
com.sun.jmx.,\
com.sun.proxy.,\
- com.sun.org.apache.xerces.internal.utils.,\
+ com.sun.org.apache.bcel.internal.,\
+ com.sun.org.apache.regexp.internal.,\
+ com.sun.org.apache.xerces.internal.,\
+ com.sun.org.apache.xpath.internal.,\
+ com.sun.org.apache.xalan.internal.extensions.,\
+ com.sun.org.apache.xalan.internal.lib.,\
+ com.sun.org.apache.xalan.internal.res.,\
+ com.sun.org.apache.xalan.internal.templates.,\
com.sun.org.apache.xalan.internal.utils.,\
- com.sun.org.glassfish.external.,\
- com.sun.org.glassfish.gmbal.,\
+ com.sun.org.apache.xalan.internal.xslt.,\
+ com.sun.org.apache.xalan.internal.xsltc.cmdline.,\
+ com.sun.org.apache.xalan.internal.xsltc.compiler.,\
+ com.sun.org.apache.xalan.internal.xsltc.trax.,\
+ com.sun.org.apache.xalan.internal.xsltc.util.,\
+ com.sun.org.apache.xml.internal.res.,\
+ com.sun.org.apache.xml.internal.serializer.utils.,\
+ com.sun.org.apache.xml.internal.utils.,\
+ com.sun.org.glassfish.,\
com.oracle.xmlns.internal.,\
com.oracle.webservices.internal.,\
jdk.internal.,\
@@ -207,17 +219,29 @@ package.access=sun.,\
# checkPackageDefinition.
#
package.definition=sun.,\
- com.sun.xml.internal.bind.,\
- com.sun.xml.internal.org.jvnet.staxex.,\
- com.sun.xml.internal.ws.,\
+ com.sun.xml.internal.,\
com.sun.imageio.,\
com.sun.istack.internal.,\
com.sun.jmx.,\
com.sun.proxy.,\
- com.sun.org.apache.xerces.internal.utils.,\
+ com.sun.org.apache.bcel.internal.,\
+ com.sun.org.apache.regexp.internal.,\
+ com.sun.org.apache.xerces.internal.,\
+ com.sun.org.apache.xpath.internal.,\
+ com.sun.org.apache.xalan.internal.extensions.,\
+ com.sun.org.apache.xalan.internal.lib.,\
+ com.sun.org.apache.xalan.internal.res.,\
+ com.sun.org.apache.xalan.internal.templates.,\
com.sun.org.apache.xalan.internal.utils.,\
- com.sun.org.glassfish.external.,\
- com.sun.org.glassfish.gmbal.,\
+ com.sun.org.apache.xalan.internal.xslt.,\
+ com.sun.org.apache.xalan.internal.xsltc.cmdline.,\
+ com.sun.org.apache.xalan.internal.xsltc.compiler.,\
+ com.sun.org.apache.xalan.internal.xsltc.trax.,\
+ com.sun.org.apache.xalan.internal.xsltc.util.,\
+ com.sun.org.apache.xml.internal.res.,\
+ com.sun.org.apache.xml.internal.serializer.utils.,\
+ com.sun.org.apache.xml.internal.utils.,\
+ com.sun.org.glassfish.,\
com.oracle.xmlns.internal.,\
com.oracle.webservices.internal.,\
jdk.internal.,\
diff --git a/jdk/src/share/lib/security/java.security-solaris b/jdk/src/share/lib/security/java.security-solaris
index 35452bd1d22..b54d3bea6c2 100644
--- a/jdk/src/share/lib/security/java.security-solaris
+++ b/jdk/src/share/lib/security/java.security-solaris
@@ -179,17 +179,29 @@ keystore.type=jks
# corresponding RuntimePermission ("accessClassInPackage."+package) has
# been granted.
package.access=sun.,\
- com.sun.xml.internal.bind.,\
- com.sun.xml.internal.org.jvnet.staxex.,\
- com.sun.xml.internal.ws.,\
+ com.sun.xml.internal.,\
com.sun.imageio.,\
com.sun.istack.internal.,\
com.sun.jmx.,\
com.sun.proxy.,\
- com.sun.org.apache.xerces.internal.utils.,\
+ com.sun.org.apache.bcel.internal.,\
+ com.sun.org.apache.regexp.internal.,\
+ com.sun.org.apache.xerces.internal.,\
+ com.sun.org.apache.xpath.internal.,\
+ com.sun.org.apache.xalan.internal.extensions.,\
+ com.sun.org.apache.xalan.internal.lib.,\
+ com.sun.org.apache.xalan.internal.res.,\
+ com.sun.org.apache.xalan.internal.templates.,\
com.sun.org.apache.xalan.internal.utils.,\
- com.sun.org.glassfish.external.,\
- com.sun.org.glassfish.gmbal.,\
+ com.sun.org.apache.xalan.internal.xslt.,\
+ com.sun.org.apache.xalan.internal.xsltc.cmdline.,\
+ com.sun.org.apache.xalan.internal.xsltc.compiler.,\
+ com.sun.org.apache.xalan.internal.xsltc.trax.,\
+ com.sun.org.apache.xalan.internal.xsltc.util.,\
+ com.sun.org.apache.xml.internal.res.,\
+ com.sun.org.apache.xml.internal.serializer.utils.,\
+ com.sun.org.apache.xml.internal.utils.,\
+ com.sun.org.glassfish.,\
com.oracle.xmlns.internal.,\
com.oracle.webservices.internal.,\
jdk.internal.,\
@@ -207,17 +219,29 @@ package.access=sun.,\
# checkPackageDefinition.
#
package.definition=sun.,\
- com.sun.xml.internal.bind.,\
- com.sun.xml.internal.org.jvnet.staxex.,\
- com.sun.xml.internal.ws.,\
+ com.sun.xml.internal.,\
com.sun.imageio.,\
com.sun.istack.internal.,\
com.sun.jmx.,\
com.sun.proxy.,\
- com.sun.org.apache.xerces.internal.utils.,\
+ com.sun.org.apache.bcel.internal.,\
+ com.sun.org.apache.regexp.internal.,\
+ com.sun.org.apache.xerces.internal.,\
+ com.sun.org.apache.xpath.internal.,\
+ com.sun.org.apache.xalan.internal.extensions.,\
+ com.sun.org.apache.xalan.internal.lib.,\
+ com.sun.org.apache.xalan.internal.res.,\
+ com.sun.org.apache.xalan.internal.templates.,\
com.sun.org.apache.xalan.internal.utils.,\
- com.sun.org.glassfish.external.,\
- com.sun.org.glassfish.gmbal.,\
+ com.sun.org.apache.xalan.internal.xslt.,\
+ com.sun.org.apache.xalan.internal.xsltc.cmdline.,\
+ com.sun.org.apache.xalan.internal.xsltc.compiler.,\
+ com.sun.org.apache.xalan.internal.xsltc.trax.,\
+ com.sun.org.apache.xalan.internal.xsltc.util.,\
+ com.sun.org.apache.xml.internal.res.,\
+ com.sun.org.apache.xml.internal.serializer.utils.,\
+ com.sun.org.apache.xml.internal.utils.,\
+ com.sun.org.glassfish.,\
com.oracle.xmlns.internal.,\
com.oracle.webservices.internal.,\
jdk.internal.,\
diff --git a/jdk/src/share/lib/security/java.security-windows b/jdk/src/share/lib/security/java.security-windows
index 0fca18c7716..9a455b3bedb 100644
--- a/jdk/src/share/lib/security/java.security-windows
+++ b/jdk/src/share/lib/security/java.security-windows
@@ -178,22 +178,35 @@ keystore.type=jks
# corresponding RuntimePermission ("accessClassInPackage."+package) has
# been granted.
package.access=sun.,\
- com.sun.xml.internal.bind.,\
- com.sun.xml.internal.org.jvnet.staxex.,\
- com.sun.xml.internal.ws.,\
+ com.sun.xml.internal.,\
com.sun.imageio.,\
com.sun.istack.internal.,\
com.sun.jmx.,\
com.sun.proxy.,\
- com.sun.org.apache.xerces.internal.utils.,\
+ com.sun.org.apache.bcel.internal.,\
+ com.sun.org.apache.regexp.internal.,\
+ com.sun.org.apache.xerces.internal.,\
+ com.sun.org.apache.xpath.internal.,\
+ com.sun.org.apache.xalan.internal.extensions.,\
+ com.sun.org.apache.xalan.internal.lib.,\
+ com.sun.org.apache.xalan.internal.res.,\
+ com.sun.org.apache.xalan.internal.templates.,\
com.sun.org.apache.xalan.internal.utils.,\
- com.sun.org.glassfish.external.,\
- com.sun.org.glassfish.gmbal.,\
+ com.sun.org.apache.xalan.internal.xslt.,\
+ com.sun.org.apache.xalan.internal.xsltc.cmdline.,\
+ com.sun.org.apache.xalan.internal.xsltc.compiler.,\
+ com.sun.org.apache.xalan.internal.xsltc.trax.,\
+ com.sun.org.apache.xalan.internal.xsltc.util.,\
+ com.sun.org.apache.xml.internal.res.,\
+ com.sun.org.apache.xml.internal.serializer.utils.,\
+ com.sun.org.apache.xml.internal.utils.,\
+ com.sun.org.glassfish.,\
com.oracle.xmlns.internal.,\
com.oracle.webservices.internal.,\
jdk.internal.,\
jdk.nashorn.internal.,\
- jdk.nashorn.tools.
+ jdk.nashorn.tools.,\
+ com.sun.java.accessibility.
#
# List of comma-separated packages that start with or equal this string
@@ -206,22 +219,35 @@ package.access=sun.,\
# checkPackageDefinition.
#
package.definition=sun.,\
- com.sun.xml.internal.bind.,\
- com.sun.xml.internal.org.jvnet.staxex.,\
- com.sun.xml.internal.ws.,\
+ com.sun.xml.internal.,\
com.sun.imageio.,\
com.sun.istack.internal.,\
com.sun.jmx.,\
com.sun.proxy.,\
- com.sun.org.apache.xerces.internal.utils.,\
+ com.sun.org.apache.bcel.internal.,\
+ com.sun.org.apache.regexp.internal.,\
+ com.sun.org.apache.xerces.internal.,\
+ com.sun.org.apache.xpath.internal.,\
+ com.sun.org.apache.xalan.internal.extensions.,\
+ com.sun.org.apache.xalan.internal.lib.,\
+ com.sun.org.apache.xalan.internal.res.,\
+ com.sun.org.apache.xalan.internal.templates.,\
com.sun.org.apache.xalan.internal.utils.,\
- com.sun.org.glassfish.external.,\
- com.sun.org.glassfish.gmbal.,\
+ com.sun.org.apache.xalan.internal.xslt.,\
+ com.sun.org.apache.xalan.internal.xsltc.cmdline.,\
+ com.sun.org.apache.xalan.internal.xsltc.compiler.,\
+ com.sun.org.apache.xalan.internal.xsltc.trax.,\
+ com.sun.org.apache.xalan.internal.xsltc.util.,\
+ com.sun.org.apache.xml.internal.res.,\
+ com.sun.org.apache.xml.internal.serializer.utils.,\
+ com.sun.org.apache.xml.internal.utils.,\
+ com.sun.org.glassfish.,\
com.oracle.xmlns.internal.,\
com.oracle.webservices.internal.,\
jdk.internal.,\
jdk.nashorn.internal.,\
- jdk.nashorn.tools.
+ jdk.nashorn.tools.,\
+ com.sun.java.accessibility.
#
# Determines whether this properties file can be appended to
diff --git a/jdk/src/share/native/java/lang/ClassLoader.c b/jdk/src/share/native/java/lang/ClassLoader.c
index 776b2dd24e7..f6d0583990c 100644
--- a/jdk/src/share/native/java/lang/ClassLoader.c
+++ b/jdk/src/share/native/java/lang/ClassLoader.c
@@ -492,24 +492,6 @@ Java_java_lang_ClassLoader_00024NativeLibrary_find
(*env)->ReleaseStringUTFChars(env, name, cname);
return res;
}
-
-JNIEXPORT jobject JNICALL
-Java_java_lang_ClassLoader_getCaller(JNIEnv *env, jclass cls, jint index)
-{
- jobjectArray jcallerStack;
- int len;
-
- jcallerStack = JVM_GetClassContext(env);
- if ((*env)->ExceptionCheck(env)) {
- return NULL;
- }
- len = (*env)->GetArrayLength(env, jcallerStack);
- if (index < len) {
- return (*env)->GetObjectArrayElement(env, jcallerStack, index);
- }
- return NULL;
-}
-
/*
* Class: java_lang_ClassLoader_NativeLibrary
* Method: findBuiltinLib
diff --git a/jdk/src/share/native/java/lang/SecurityManager.c b/jdk/src/share/native/java/lang/SecurityManager.c
index 397e30bb99a..a815df5300f 100644
--- a/jdk/src/share/native/java/lang/SecurityManager.c
+++ b/jdk/src/share/native/java/lang/SecurityManager.c
@@ -29,7 +29,6 @@
#include "java_lang_SecurityManager.h"
#include "java_lang_ClassLoader.h"
-#include "java_util_ResourceBundle.h"
/*
* Make sure a security manager instance is initialized.
diff --git a/jdk/src/share/native/java/net/InetAddress.c b/jdk/src/share/native/java/net/InetAddress.c
index 27a4a93d4d6..31115739b7e 100644
--- a/jdk/src/share/native/java/net/InetAddress.c
+++ b/jdk/src/share/native/java/net/InetAddress.c
@@ -33,8 +33,11 @@
*/
jclass ia_class;
-jfieldID ia_addressID;
-jfieldID ia_familyID;
+jclass iac_class;
+jfieldID ia_holderID;
+jfieldID iac_addressID;
+jfieldID iac_familyID;
+jfieldID iac_hostNameID;
jfieldID ia_preferIPv6AddressID;
/*
@@ -48,10 +51,18 @@ Java_java_net_InetAddress_init(JNIEnv *env, jclass cls) {
CHECK_NULL(c);
ia_class = (*env)->NewGlobalRef(env, c);
CHECK_NULL(ia_class);
- ia_addressID = (*env)->GetFieldID(env, ia_class, "address", "I");
- CHECK_NULL(ia_addressID);
- ia_familyID = (*env)->GetFieldID(env, ia_class, "family", "I");
- CHECK_NULL(ia_familyID);
+ c = (*env)->FindClass(env,"java/net/InetAddress$InetAddressHolder");
+ CHECK_NULL(c);
+ iac_class = (*env)->NewGlobalRef(env, c);
+ ia_holderID = (*env)->GetFieldID(env, ia_class, "holder", "Ljava/net/InetAddress$InetAddressHolder;");
+ CHECK_NULL(ia_holderID);
ia_preferIPv6AddressID = (*env)->GetStaticFieldID(env, ia_class, "preferIPv6Address", "Z");
CHECK_NULL(ia_preferIPv6AddressID);
+
+ iac_addressID = (*env)->GetFieldID(env, iac_class, "address", "I");
+ CHECK_NULL(iac_addressID);
+ iac_familyID = (*env)->GetFieldID(env, iac_class, "family", "I");
+ CHECK_NULL(iac_familyID);
+ iac_hostNameID = (*env)->GetFieldID(env, iac_class, "hostName", "Ljava/lang/String;");
+ CHECK_NULL(iac_hostNameID);
}
diff --git a/jdk/src/share/native/java/net/net_util.c b/jdk/src/share/native/java/net/net_util.c
index d7a6de2073d..5d15f9d9b0e 100644
--- a/jdk/src/share/native/java/net/net_util.c
+++ b/jdk/src/share/native/java/net/net_util.c
@@ -84,6 +84,58 @@ void init(JNIEnv *env) {
}
}
+/* The address, and family fields used to be in InetAddress
+ * but are now in an implementation object. So, there is an extra
+ * level of indirection to access them now.
+ */
+
+extern jclass iac_class;
+extern jfieldID ia_holderID;
+extern jfieldID iac_addressID;
+extern jfieldID iac_familyID;
+
+void setInetAddress_addr(JNIEnv *env, jobject iaObj, int address) {
+ jobject holder;
+ init(env);
+ holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
+ (*env)->SetIntField(env, holder, iac_addressID, address);
+}
+
+void setInetAddress_family(JNIEnv *env, jobject iaObj, int family) {
+ jobject holder;
+ init(env);
+ holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
+ (*env)->SetIntField(env, holder, iac_familyID, family);
+}
+
+void setInetAddress_hostName(JNIEnv *env, jobject iaObj, jobject host) {
+ jobject holder;
+ init(env);
+ holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
+ (*env)->SetObjectField(env, holder, iac_hostNameID, host);
+}
+
+int getInetAddress_addr(JNIEnv *env, jobject iaObj) {
+ jobject holder;
+ init(env);
+ holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
+ return (*env)->GetIntField(env, holder, iac_addressID);
+}
+
+int getInetAddress_family(JNIEnv *env, jobject iaObj) {
+ jobject holder;
+ init(env);
+ holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
+ return (*env)->GetIntField(env, holder, iac_familyID);
+}
+
+jobject getInetAddress_hostName(JNIEnv *env, jobject iaObj) {
+ jobject holder;
+ init(env);
+ holder = (*env)->GetObjectField(env, iaObj, ia_holderID);
+ return (*env)->GetObjectField(env, holder, iac_hostNameID);
+}
+
JNIEXPORT jobject JNICALL
NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) {
jobject iaObj;
@@ -110,8 +162,8 @@ NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) {
iaObj = (*env)->NewObject(env, inet4Cls, ia4_ctrID);
CHECK_NULL_RETURN(iaObj, NULL);
address = NET_IPv4MappedToIPv4(caddr);
- (*env)->SetIntField(env, iaObj, ia_addressID, address);
- (*env)->SetIntField(env, iaObj, ia_familyID, IPv4);
+ setInetAddress_addr(env, iaObj, address);
+ setInetAddress_family(env, iaObj, IPv4);
} else {
static jclass inet6Cls = 0;
jint scope;
@@ -131,7 +183,7 @@ NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) {
(*env)->SetObjectField(env, iaObj, ia6_ipaddressID, ipaddress);
- (*env)->SetIntField(env, iaObj, ia_familyID, IPv6);
+ setInetAddress_family(env, iaObj, IPv6);
scope = getScopeID(him);
(*env)->SetIntField(env, iaObj, ia6_scopeidID, scope);
if (scope > 0)
@@ -153,9 +205,8 @@ NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port) {
}
iaObj = (*env)->NewObject(env, inet4Cls, ia4_ctrID);
CHECK_NULL_RETURN(iaObj, NULL);
- (*env)->SetIntField(env, iaObj, ia_familyID, IPv4);
- (*env)->SetIntField(env, iaObj, ia_addressID,
- ntohl(him4->sin_addr.s_addr));
+ setInetAddress_family(env, iaObj, IPv4);
+ setInetAddress_addr(env, iaObj, ntohl(him4->sin_addr.s_addr));
*port = ntohs(him4->sin_port);
}
return iaObj;
@@ -167,8 +218,7 @@ NET_SockaddrEqualsInetAddress(JNIEnv *env, struct sockaddr *him, jobject iaObj)
jint family = AF_INET;
#ifdef AF_INET6
- family = (*env)->GetIntField(env, iaObj, ia_familyID) == IPv4?
- AF_INET : AF_INET6;
+ family = getInetAddress_family(env, iaObj) == IPv4? AF_INET : AF_INET6;
if (him->sa_family == AF_INET6) {
#ifdef WIN32
struct SOCKADDR_IN6 *him6 = (struct SOCKADDR_IN6 *)him;
@@ -183,7 +233,7 @@ NET_SockaddrEqualsInetAddress(JNIEnv *env, struct sockaddr *him, jobject iaObj)
return JNI_FALSE;
}
addrNew = NET_IPv4MappedToIPv4(caddrNew);
- addrCur = (*env)->GetIntField(env, iaObj, ia_addressID);
+ addrCur = getInetAddress_addr(env, iaObj);
if (addrNew == addrCur) {
return JNI_TRUE;
} else {
@@ -215,7 +265,7 @@ NET_SockaddrEqualsInetAddress(JNIEnv *env, struct sockaddr *him, jobject iaObj)
return JNI_FALSE;
}
addrNew = ntohl(him4->sin_addr.s_addr);
- addrCur = (*env)->GetIntField(env, iaObj, ia_addressID);
+ addrCur = getInetAddress_addr(env, iaObj);
if (addrNew == addrCur) {
return JNI_TRUE;
} else {
diff --git a/jdk/src/share/native/java/net/net_util.h b/jdk/src/share/native/java/net/net_util.h
index 6f040fa3ff6..0fd5b6c427f 100644
--- a/jdk/src/share/native/java/net/net_util.h
+++ b/jdk/src/share/native/java/net/net_util.h
@@ -53,10 +53,18 @@
* i.e. psi_timeoutID is PlainSocketImpl's timeout field's ID.
*/
extern jclass ia_class;
-extern jfieldID ia_addressID;
-extern jfieldID ia_familyID;
+extern jfieldID iac_addressID;
+extern jfieldID iac_familyID;
+extern jfieldID iac_hostNameID;
extern jfieldID ia_preferIPv6AddressID;
+extern void setInetAddress_addr(JNIEnv *env, jobject iaObj, int address);
+extern void setInetAddress_family(JNIEnv *env, jobject iaObj, int family);
+extern void setInetAddress_hostName(JNIEnv *env, jobject iaObj, jobject h);
+extern int getInetAddress_addr(JNIEnv *env, jobject iaObj);
+extern int getInetAddress_family(JNIEnv *env, jobject iaObj);
+extern jobject getInetAddress_hostName(JNIEnv *env, jobject iaObj);
+
extern jclass ia4_class;
extern jmethodID ia4_ctrID;
diff --git a/jdk/src/share/native/sun/awt/image/awt_ImageRep.c b/jdk/src/share/native/sun/awt/image/awt_ImageRep.c
index aa1521e42a4..e091be36eab 100644
--- a/jdk/src/share/native/sun/awt/image/awt_ImageRep.c
+++ b/jdk/src/share/native/sun/awt/image/awt_ImageRep.c
@@ -45,6 +45,53 @@ static int findIdx(unsigned int rgb, unsigned int *lut, int numLut1);
# define TRUE 1
#endif
+#define CHECK_STRIDE(yy, hh, ss) \
+ if ((ss) != 0) { \
+ int limit = 0x7fffffff / ((ss) > 0 ? (ss) : -(ss)); \
+ if (limit < (yy) || limit < ((yy) + (hh) - 1)) { \
+ /* integer oveflow */ \
+ return JNI_FALSE; \
+ } \
+ } \
+
+#define CHECK_SRC() \
+ do { \
+ int pixeloffset; \
+ if (off < 0 || off >= srcDataLength) { \
+ return JNI_FALSE; \
+ } \
+ CHECK_STRIDE(0, h, scansize); \
+ \
+ /* check scansize */ \
+ pixeloffset = scansize * (h - 1); \
+ if ((w - 1) > (0x7fffffff - pixeloffset)) { \
+ return JNI_FALSE; \
+ } \
+ pixeloffset += (w - 1); \
+ \
+ if (off > (0x7fffffff - pixeloffset)) { \
+ return JNI_FALSE; \
+ } \
+ } while (0) \
+
+#define CHECK_DST(xx, yy) \
+ do { \
+ int soffset = (yy) * sStride; \
+ int poffset = (xx) * pixelStride; \
+ if (poffset > (0x7fffffff - soffset)) { \
+ return JNI_FALSE; \
+ } \
+ poffset += soffset; \
+ if (dstDataOff > (0x7fffffff - poffset)) { \
+ return JNI_FALSE; \
+ } \
+ poffset += dstDataOff; \
+ \
+ if (poffset < 0 || poffset >= dstDataLength) { \
+ return JNI_FALSE; \
+ } \
+ } while (0) \
+
static jfieldID s_JnumSrcLUTID;
static jfieldID s_JsrcLUTtransIndexID;
@@ -58,7 +105,7 @@ Java_sun_awt_image_ImageRepresentation_initIDs(JNIEnv *env, jclass cls) {
/*
* This routine is used to draw ICM pixels into a default color model
*/
-JNIEXPORT void JNICALL
+JNIEXPORT jboolean JNICALL
Java_sun_awt_image_ImageRepresentation_setICMpixels(JNIEnv *env, jclass cls,
jint x, jint y, jint w,
jint h, jintArray jlut,
@@ -67,7 +114,10 @@ Java_sun_awt_image_ImageRepresentation_setICMpixels(JNIEnv *env, jclass cls,
jobject jict)
{
unsigned char *srcData = NULL;
+ jint srcDataLength;
int *dstData;
+ jint dstDataLength;
+ jint dstDataOff;
int *dstP, *dstyP;
unsigned char *srcyP, *srcP;
int *srcLUT = NULL;
@@ -80,12 +130,20 @@ Java_sun_awt_image_ImageRepresentation_setICMpixels(JNIEnv *env, jclass cls,
if (JNU_IsNull(env, jlut)) {
JNU_ThrowNullPointerException(env, "NullPointerException");
- return;
+ return JNI_FALSE;
}
if (JNU_IsNull(env, jpix)) {
JNU_ThrowNullPointerException(env, "NullPointerException");
- return;
+ return JNI_FALSE;
+ }
+
+ if (x < 0 || w < 1 || (0x7fffffff - x) < w) {
+ return JNI_FALSE;
+ }
+
+ if (y < 0 || h < 1 || (0x7fffffff - y) < h) {
+ return JNI_FALSE;
}
sStride = (*env)->GetIntField(env, jict, g_ICRscanstrID);
@@ -93,10 +151,47 @@ Java_sun_awt_image_ImageRepresentation_setICMpixels(JNIEnv *env, jclass cls,
joffs = (*env)->GetObjectField(env, jict, g_ICRdataOffsetsID);
jdata = (*env)->GetObjectField(env, jict, g_ICRdataID);
+ if (JNU_IsNull(env, jdata)) {
+ /* no destination buffer */
+ return JNI_FALSE;
+ }
+
+ if (JNU_IsNull(env, joffs) || (*env)->GetArrayLength(env, joffs) < 1) {
+ /* invalid data offstes in raster */
+ return JNI_FALSE;
+ }
+
+ srcDataLength = (*env)->GetArrayLength(env, jpix);
+ dstDataLength = (*env)->GetArrayLength(env, jdata);
+
+ cOffs = (int *) (*env)->GetPrimitiveArrayCritical(env, joffs, NULL);
+ if (cOffs == NULL) {
+ JNU_ThrowNullPointerException(env, "Null channel offset array");
+ return JNI_FALSE;
+ }
+
+ dstDataOff = cOffs[0];
+
+ /* the offset array is not needed anymore and can be released */
+ (*env)->ReleasePrimitiveArrayCritical(env, joffs, cOffs, JNI_ABORT);
+ joffs = NULL;
+ cOffs = NULL;
+
+ /* do basic validation: make sure that offsets for
+ * first pixel and for last pixel are safe to calculate and use */
+ CHECK_STRIDE(y, h, sStride);
+ CHECK_STRIDE(x, w, pixelStride);
+
+ CHECK_DST(x, y);
+ CHECK_DST(x + w -1, y + h - 1);
+
+ /* check source array */
+ CHECK_SRC();
+
srcLUT = (int *) (*env)->GetPrimitiveArrayCritical(env, jlut, NULL);
if (srcLUT == NULL) {
JNU_ThrowNullPointerException(env, "Null IndexColorModel LUT");
- return;
+ return JNI_FALSE;
}
srcData = (unsigned char *) (*env)->GetPrimitiveArrayCritical(env, jpix,
@@ -104,27 +199,18 @@ Java_sun_awt_image_ImageRepresentation_setICMpixels(JNIEnv *env, jclass cls,
if (srcData == NULL) {
(*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT, JNI_ABORT);
JNU_ThrowNullPointerException(env, "Null data array");
- return;
- }
-
- cOffs = (int *) (*env)->GetPrimitiveArrayCritical(env, joffs, NULL);
- if (cOffs == NULL) {
- (*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT, JNI_ABORT);
- (*env)->ReleasePrimitiveArrayCritical(env, jpix, srcData, JNI_ABORT);
- JNU_ThrowNullPointerException(env, "Null channel offset array");
- return;
+ return JNI_FALSE;
}
dstData = (int *) (*env)->GetPrimitiveArrayCritical(env, jdata, NULL);
if (dstData == NULL) {
(*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT, JNI_ABORT);
(*env)->ReleasePrimitiveArrayCritical(env, jpix, srcData, JNI_ABORT);
- (*env)->ReleasePrimitiveArrayCritical(env, joffs, cOffs, JNI_ABORT);
JNU_ThrowNullPointerException(env, "Null tile data array");
- return;
+ return JNI_FALSE;
}
- dstyP = dstData + cOffs[0] + y*sStride + x*pixelStride;
+ dstyP = dstData + dstDataOff + y*sStride + x*pixelStride;
srcyP = srcData + off;
for (yIdx = 0; yIdx < h; yIdx++, srcyP += scansize, dstyP+=sStride) {
srcP = srcyP;
@@ -137,12 +223,12 @@ Java_sun_awt_image_ImageRepresentation_setICMpixels(JNIEnv *env, jclass cls,
/* Release the locked arrays */
(*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT, JNI_ABORT);
(*env)->ReleasePrimitiveArrayCritical(env, jpix, srcData, JNI_ABORT);
- (*env)->ReleasePrimitiveArrayCritical(env, joffs, cOffs, JNI_ABORT);
(*env)->ReleasePrimitiveArrayCritical(env, jdata, dstData, JNI_ABORT);
+ return JNI_TRUE;
}
-JNIEXPORT jint JNICALL
+JNIEXPORT jboolean JNICALL
Java_sun_awt_image_ImageRepresentation_setDiffICM(JNIEnv *env, jclass cls,
jint x, jint y, jint w,
jint h, jintArray jlut,
@@ -150,7 +236,7 @@ Java_sun_awt_image_ImageRepresentation_setDiffICM(JNIEnv *env, jclass cls,
jobject jicm,
jbyteArray jpix, jint off,
jint scansize,
- jobject jbct, jint chanOff)
+ jobject jbct, jint dstDataOff)
{
unsigned int *srcLUT = NULL;
unsigned int *newLUT = NULL;
@@ -159,6 +245,8 @@ Java_sun_awt_image_ImageRepresentation_setDiffICM(JNIEnv *env, jclass cls,
int mapSize;
jobject jdata = NULL;
jobject jnewlut = NULL;
+ jint srcDataLength;
+ jint dstDataLength;
unsigned char *srcData;
unsigned char *dstData;
unsigned char *dataP;
@@ -174,14 +262,23 @@ Java_sun_awt_image_ImageRepresentation_setDiffICM(JNIEnv *env, jclass cls,
if (JNU_IsNull(env, jlut)) {
JNU_ThrowNullPointerException(env, "NullPointerException");
- return 0;
+ return JNI_FALSE;
}
if (JNU_IsNull(env, jpix)) {
JNU_ThrowNullPointerException(env, "NullPointerException");
- return 0;
+ return JNI_FALSE;
}
+ if (x < 0 || w < 1 || (0x7fffffff - x) < w) {
+ return JNI_FALSE;
+ }
+
+ if (y < 0 || h < 1 || (0x7fffffff - y) < h) {
+ return JNI_FALSE;
+ }
+
+
sStride = (*env)->GetIntField(env, jbct, g_BCRscanstrID);
pixelStride =(*env)->GetIntField(env, jbct, g_BCRpixstrID);
jdata = (*env)->GetObjectField(env, jbct, g_BCRdataID);
@@ -193,13 +290,31 @@ Java_sun_awt_image_ImageRepresentation_setDiffICM(JNIEnv *env, jclass cls,
of byte data type, so we have to convert the image data
to default representation.
*/
- return 0;
+ return JNI_FALSE;
}
+
+ if (JNU_IsNull(env, jdata)) {
+ /* no destination buffer */
+ return JNI_FALSE;
+ }
+
+ srcDataLength = (*env)->GetArrayLength(env, jpix);
+ dstDataLength = (*env)->GetArrayLength(env, jdata);
+
+ CHECK_STRIDE(y, h, sStride);
+ CHECK_STRIDE(x, w, pixelStride);
+
+ CHECK_DST(x, y);
+ CHECK_DST(x + w -1, y + h - 1);
+
+ /* check source array */
+ CHECK_SRC();
+
srcLUT = (unsigned int *) (*env)->GetPrimitiveArrayCritical(env, jlut,
NULL);
if (srcLUT == NULL) {
/* out of memory error already thrown */
- return 0;
+ return JNI_FALSE;
}
newLUT = (unsigned int *) (*env)->GetPrimitiveArrayCritical(env, jnewlut,
@@ -208,7 +323,7 @@ Java_sun_awt_image_ImageRepresentation_setDiffICM(JNIEnv *env, jclass cls,
(*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT,
JNI_ABORT);
/* out of memory error already thrown */
- return 0;
+ return JNI_FALSE;
}
newNumLut = numLut;
@@ -219,7 +334,7 @@ Java_sun_awt_image_ImageRepresentation_setDiffICM(JNIEnv *env, jclass cls,
(*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT,
JNI_ABORT);
(*env)->ReleasePrimitiveArrayCritical(env, jnewlut, newLUT, JNI_ABORT);
- return 0;
+ return JNI_FALSE;
}
/* Don't need these any more */
@@ -239,7 +354,7 @@ Java_sun_awt_image_ImageRepresentation_setDiffICM(JNIEnv *env, jclass cls,
NULL);
if (srcData == NULL) {
/* out of memory error already thrown */
- return 0;
+ return JNI_FALSE;
}
dstData = (unsigned char *) (*env)->GetPrimitiveArrayCritical(env, jdata,
@@ -247,10 +362,10 @@ Java_sun_awt_image_ImageRepresentation_setDiffICM(JNIEnv *env, jclass cls,
if (dstData == NULL) {
(*env)->ReleasePrimitiveArrayCritical(env, jpix, srcData, JNI_ABORT);
/* out of memory error already thrown */
- return 0;
+ return JNI_FALSE;
}
- ydataP = dstData + chanOff + y*sStride + x*pixelStride;
+ ydataP = dstData + dstDataOff + y*sStride + x*pixelStride;
ypixP = srcData + off;
for (i=0; i < h; i++) {
@@ -268,7 +383,7 @@ Java_sun_awt_image_ImageRepresentation_setDiffICM(JNIEnv *env, jclass cls,
(*env)->ReleasePrimitiveArrayCritical(env, jpix, srcData, JNI_ABORT);
(*env)->ReleasePrimitiveArrayCritical(env, jdata, dstData, JNI_ABORT);
- return 1;
+ return JNI_TRUE;
}
static int compareLUTs(unsigned int *lut1, int numLut1, int transIdx,
diff --git a/jdk/src/share/native/sun/awt/image/awt_parseImage.c b/jdk/src/share/native/sun/awt/image/awt_parseImage.c
index 498ac717913..310866acba3 100644
--- a/jdk/src/share/native/sun/awt/image/awt_parseImage.c
+++ b/jdk/src/share/native/sun/awt/image/awt_parseImage.c
@@ -34,6 +34,7 @@
#include "java_awt_color_ColorSpace.h"
#include "awt_Mlib.h"
#include "safe_alloc.h"
+#include "safe_math.h"
static int setHints(JNIEnv *env, BufImageS_t *imageP);
diff --git a/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c b/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c
index b405618be98..7411c34bb83 100644
--- a/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c
+++ b/jdk/src/share/native/sun/awt/image/jpeg/imageioJPEG.c
@@ -57,8 +57,8 @@
#define MAX(a,b) ((a) > (b) ? (a) : (b))
/* Cached Java method ids */
-static jmethodID ImageInputStream_readID;
-static jmethodID ImageInputStream_skipBytesID;
+static jmethodID JPEGImageReader_readInputDataID;
+static jmethodID JPEGImageReader_skipInputBytesID;
static jmethodID JPEGImageReader_warningOccurredID;
static jmethodID JPEGImageReader_warningWithMessageID;
static jmethodID JPEGImageReader_setImageDataID;
@@ -66,7 +66,7 @@ static jmethodID JPEGImageReader_acceptPixelsID;
static jmethodID JPEGImageReader_pushBackID;
static jmethodID JPEGImageReader_passStartedID;
static jmethodID JPEGImageReader_passCompleteID;
-static jmethodID ImageOutputStream_writeID;
+static jmethodID JPEGImageWriter_writeOutputDataID;
static jmethodID JPEGImageWriter_warningOccurredID;
static jmethodID JPEGImageWriter_warningWithMessageID;
static jmethodID JPEGImageWriter_writeMetadataID;
@@ -923,7 +923,7 @@ imageio_fill_input_buffer(j_decompress_ptr cinfo)
RELEASE_ARRAYS(env, data, src->next_input_byte);
ret = (*env)->CallIntMethod(env,
sb->stream,
- ImageInputStream_readID,
+ JPEGImageReader_readInputDataID,
sb->hstreamBuffer, 0,
sb->bufferLength);
if ((*env)->ExceptionOccurred(env)
@@ -1013,7 +1013,7 @@ imageio_fill_suspended_buffer(j_decompress_ptr cinfo)
}
ret = (*env)->CallIntMethod(env, sb->stream,
- ImageInputStream_readID,
+ JPEGImageReader_readInputDataID,
sb->hstreamBuffer,
offset, buflen);
if ((*env)->ExceptionOccurred(env)
@@ -1107,7 +1107,7 @@ imageio_skip_input_data(j_decompress_ptr cinfo, long num_bytes)
RELEASE_ARRAYS(env, data, src->next_input_byte);
ret = (*env)->CallLongMethod(env,
sb->stream,
- ImageInputStream_skipBytesID,
+ JPEGImageReader_skipInputBytesID,
(jlong) num_bytes);
if ((*env)->ExceptionOccurred(env)
|| !GET_ARRAYS(env, data, &(src->next_input_byte))) {
@@ -1382,13 +1382,13 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_initReaderIDs
jclass qTableClass,
jclass huffClass) {
- ImageInputStream_readID = (*env)->GetMethodID(env,
- ImageInputStreamClass,
- "read",
+ JPEGImageReader_readInputDataID = (*env)->GetMethodID(env,
+ cls,
+ "readInputData",
"([BII)I");
- ImageInputStream_skipBytesID = (*env)->GetMethodID(env,
- ImageInputStreamClass,
- "skipBytes",
+ JPEGImageReader_skipInputBytesID = (*env)->GetMethodID(env,
+ cls,
+ "skipInputBytes",
"(J)J");
JPEGImageReader_warningOccurredID = (*env)->GetMethodID(env,
cls,
@@ -1531,8 +1531,7 @@ JNIEXPORT void JNICALL
Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_setSource
(JNIEnv *env,
jobject this,
- jlong ptr,
- jobject source) {
+ jlong ptr) {
imageIODataPtr data = (imageIODataPtr)jlong_to_ptr(ptr);
j_common_ptr cinfo;
@@ -1546,7 +1545,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageReader_setSource
cinfo = data->jpegObj;
- imageio_set_stream(env, cinfo, data, source);
+ imageio_set_stream(env, cinfo, data, this);
imageio_init_source((j_decompress_ptr) cinfo);
}
@@ -2291,7 +2290,7 @@ imageio_empty_output_buffer (j_compress_ptr cinfo)
(*env)->CallVoidMethod(env,
sb->stream,
- ImageOutputStream_writeID,
+ JPEGImageWriter_writeOutputDataID,
sb->hstreamBuffer,
0,
sb->bufferLength);
@@ -2328,7 +2327,7 @@ imageio_term_destination (j_compress_ptr cinfo)
(*env)->CallVoidMethod(env,
sb->stream,
- ImageOutputStream_writeID,
+ JPEGImageWriter_writeOutputDataID,
sb->hstreamBuffer,
0,
datacount);
@@ -2366,13 +2365,12 @@ JNIEXPORT void JNICALL
Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_initWriterIDs
(JNIEnv *env,
jclass cls,
- jclass IOSClass,
jclass qTableClass,
jclass huffClass) {
- ImageOutputStream_writeID = (*env)->GetMethodID(env,
- IOSClass,
- "write",
+ JPEGImageWriter_writeOutputDataID = (*env)->GetMethodID(env,
+ cls,
+ "writeOutputData",
"([BII)V");
JPEGImageWriter_warningOccurredID = (*env)->GetMethodID(env,
@@ -2496,8 +2494,7 @@ JNIEXPORT void JNICALL
Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_setDest
(JNIEnv *env,
jobject this,
- jlong ptr,
- jobject destination) {
+ jlong ptr) {
imageIODataPtr data = (imageIODataPtr)jlong_to_ptr(ptr);
j_compress_ptr cinfo;
@@ -2511,7 +2508,7 @@ Java_com_sun_imageio_plugins_jpeg_JPEGImageWriter_setDest
cinfo = (j_compress_ptr) data->jpegObj;
- imageio_set_stream(env, data->jpegObj, data, destination);
+ imageio_set_stream(env, data->jpegObj, data, this);
// Don't call the init method, as that depends on pinned arrays
diff --git a/jdk/src/share/native/sun/awt/medialib/awt_ImagingLib.c b/jdk/src/share/native/sun/awt/medialib/awt_ImagingLib.c
index 4f1a2e1609a..5730734cefa 100644
--- a/jdk/src/share/native/sun/awt/medialib/awt_ImagingLib.c
+++ b/jdk/src/share/native/sun/awt/medialib/awt_ImagingLib.c
@@ -42,6 +42,7 @@
#include "awt_Mlib.h"
#include "gdefs.h"
#include "safe_alloc.h"
+#include "safe_math.h"
/***************************************************************************
* Definitions *
@@ -1993,13 +1994,23 @@ cvtCustomToDefault(JNIEnv *env, BufImageS_t *imageP, int component,
unsigned char *dP = dataP;
#define NUM_LINES 10
int numLines = NUM_LINES;
- int nbytes = rasterP->width*4*NUM_LINES;
+ /* it is safe to calculate the scan length, because width has been verified
+ * on creation of the mlib image
+ */
+ int scanLength = rasterP->width * 4;
+
+ int nbytes = 0;
+ if (!SAFE_TO_MULT(numLines, scanLength)) {
+ return -1;
+ }
+
+ nbytes = numLines * scanLength;
for (y=0; y < rasterP->height; y+=numLines) {
/* getData, one scanline at a time */
if (y+numLines > rasterP->height) {
numLines = rasterP->height - y;
- nbytes = rasterP->width*4*numLines;
+ nbytes = numLines * scanLength;
}
jpixels = (*env)->CallObjectMethod(env, imageP->jimage,
g_BImgGetRGBMID, 0, y,
@@ -2129,8 +2140,14 @@ allocateArray(JNIEnv *env, BufImageS_t *imageP,
if (cvtToDefault) {
int status = 0;
*mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, 4, width, height);
+ if (*mlibImagePP == NULL) {
+ return -1;
+ }
cDataP = (unsigned char *) mlib_ImageGetData(*mlibImagePP);
- /* Make sure the image is cleared */
+ /* Make sure the image is cleared.
+ * NB: the image dimension is already verified, so we can
+ * safely calculate the length of the buffer.
+ */
memset(cDataP, 0, width*height*4);
if (!isSrc) {
@@ -2380,6 +2397,9 @@ allocateRasterArray(JNIEnv *env, RasterS_t *rasterP,
case sun_awt_image_IntegerComponentRaster_TYPE_BYTE_PACKED_SAMPLES:
*mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, rasterP->numBands,
width, height);
+ if (*mlibImagePP == NULL) {
+ return -1;
+ }
if (!isSrc) return 0;
cDataP = (unsigned char *) mlib_ImageGetData(*mlibImagePP);
return expandPackedBCR(env, rasterP, -1, cDataP);
@@ -2388,6 +2408,9 @@ allocateRasterArray(JNIEnv *env, RasterS_t *rasterP,
if (rasterP->sppsm.maxBitSize <= 8) {
*mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, rasterP->numBands,
width, height);
+ if (*mlibImagePP == NULL) {
+ return -1;
+ }
if (!isSrc) return 0;
cDataP = (unsigned char *) mlib_ImageGetData(*mlibImagePP);
return expandPackedSCR(env, rasterP, -1, cDataP);
@@ -2397,6 +2420,9 @@ allocateRasterArray(JNIEnv *env, RasterS_t *rasterP,
if (rasterP->sppsm.maxBitSize <= 8) {
*mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, rasterP->numBands,
width, height);
+ if (*mlibImagePP == NULL) {
+ return -1;
+ }
if (!isSrc) return 0;
cDataP = (unsigned char *) mlib_ImageGetData(*mlibImagePP);
return expandPackedICR(env, rasterP, -1, cDataP);
diff --git a/jdk/src/share/native/sun/awt/medialib/mlib_ImageCreate.c b/jdk/src/share/native/sun/awt/medialib/mlib_ImageCreate.c
index 40662d6b8cc..97caaa4bf43 100644
--- a/jdk/src/share/native/sun/awt/medialib/mlib_ImageCreate.c
+++ b/jdk/src/share/native/sun/awt/medialib/mlib_ImageCreate.c
@@ -120,6 +120,7 @@
#include "mlib_image.h"
#include "mlib_ImageRowTable.h"
#include "mlib_ImageCreate.h"
+#include "safe_math.h"
/***************************************************************/
mlib_image* mlib_ImageSet(mlib_image *image,
@@ -247,28 +248,50 @@ mlib_image *mlib_ImageCreate(mlib_type type,
return NULL;
};
+ if (!SAFE_TO_MULT(width, channels)) {
+ return NULL;
+ }
+
+ wb = width * channels;
+
switch (type) {
case MLIB_DOUBLE:
- wb = width * channels * 8;
+ if (!SAFE_TO_MULT(wb, 8)) {
+ return NULL;
+ }
+ wb *= 8;
break;
case MLIB_FLOAT:
case MLIB_INT:
- wb = width * channels * 4;
+ if (!SAFE_TO_MULT(wb, 4)) {
+ return NULL;
+ }
+ wb *= 4;
break;
case MLIB_USHORT:
case MLIB_SHORT:
- wb = width * channels * 2;
+ if (!SAFE_TO_MULT(wb, 4)) {
+ return NULL;
+ }
+ wb *= 2;
break;
case MLIB_BYTE:
- wb = width * channels;
+ // wb is ready
break;
case MLIB_BIT:
- wb = (width * channels + 7) / 8;
+ if (!SAFE_TO_ADD(7, wb)) {
+ return NULL;
+ }
+ wb = (wb + 7) / 8;
break;
default:
return NULL;
}
+ if (!SAFE_TO_MULT(wb, height)) {
+ return NULL;
+ }
+
data = mlib_malloc(wb * height);
if (data == NULL) {
return NULL;
diff --git a/jdk/src/share/native/sun/awt/medialib/safe_alloc.h b/jdk/src/share/native/sun/awt/medialib/safe_alloc.h
index 579d98638dc..6a0320e2179 100644
--- a/jdk/src/share/native/sun/awt/medialib/safe_alloc.h
+++ b/jdk/src/share/native/sun/awt/medialib/safe_alloc.h
@@ -41,10 +41,4 @@
(((w) > 0) && ((h) > 0) && ((sz) > 0) && \
(((0xffffffffu / ((juint)(w))) / ((juint)(h))) > ((juint)(sz))))
-#define SAFE_TO_MULT(a, b) \
- (((a) > 0) && ((b) >= 0) && ((0x7fffffff / (a)) > (b)))
-
-#define SAFE_TO_ADD(a, b) \
- (((a) >= 0) && ((b) >= 0) && ((0x7fffffff - (a)) > (b)))
-
#endif // __SAFE_ALLOC_H__
diff --git a/jdk/src/share/native/java/lang/ResourceBundle.c b/jdk/src/share/native/sun/awt/medialib/safe_math.h
similarity index 78%
rename from jdk/src/share/native/java/lang/ResourceBundle.c
rename to jdk/src/share/native/sun/awt/medialib/safe_math.h
index 8914eb374ff..34c1fc56e9a 100644
--- a/jdk/src/share/native/java/lang/ResourceBundle.c
+++ b/jdk/src/share/native/sun/awt/medialib/safe_math.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 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,13 +23,13 @@
* questions.
*/
-#include "jni.h"
-#include "jvm.h"
+#ifndef __SAFE_MATH_H__
+#define __SAFE_MATH_H__
-#include "java_util_ResourceBundle.h"
+#define SAFE_TO_MULT(a, b) \
+ (((a) > 0) && ((b) >= 0) && ((0x7fffffff / (a)) > (b)))
-JNIEXPORT jobjectArray JNICALL
-Java_java_util_ResourceBundle_getClassContext(JNIEnv *env, jobject this)
-{
- return JVM_GetClassContext(env);
-}
+#define SAFE_TO_ADD(a, b) \
+ (((a) >= 0) && ((b) >= 0) && ((0x7fffffff - (a)) > (b)))
+
+#endif // __SAFE_MATH_H__
diff --git a/jdk/src/share/native/sun/font/FontInstanceAdapter.cpp b/jdk/src/share/native/sun/font/FontInstanceAdapter.cpp
index 824f296cc5c..4214078e06b 100644
--- a/jdk/src/share/native/sun/font/FontInstanceAdapter.cpp
+++ b/jdk/src/share/native/sun/font/FontInstanceAdapter.cpp
@@ -66,8 +66,21 @@ FontInstanceAdapter::FontInstanceAdapter(JNIEnv *theEnv,
yScalePixelsToUnits = upem / yppem;
};
+
const void *FontInstanceAdapter::getFontTable(LETag tableTag) const
{
+ size_t ignored = 0;
+ return getFontTable(tableTag, ignored);
+}
+
+static const LETag cacheMap[LAYOUTCACHE_ENTRIES] = {
+ GPOS_TAG, GDEF_TAG, GSUB_TAG, MORT_TAG, MORX_TAG, KERN_TAG
+};
+
+const void *FontInstanceAdapter::getFontTable(LETag tableTag, size_t &length) const
+{
+ length = 0;
+
if (!layoutTables) { // t1 font
return 0;
}
@@ -75,14 +88,19 @@ const void *FontInstanceAdapter::getFontTable(LETag tableTag) const
// cache in font's pscaler object
// font disposer will handle for us
- switch(tableTag) {
- case GSUB_TAG: if (layoutTables->gsub_len != -1) return (void*)layoutTables->gsub; break;
- case GPOS_TAG: if (layoutTables->gpos_len != -1) return (void*)layoutTables->gpos; break;
- case GDEF_TAG: if (layoutTables->gdef_len != -1) return (void*)layoutTables->gdef; break;
- case MORT_TAG: if (layoutTables->mort_len != -1) return (void*)layoutTables->mort; break;
- case KERN_TAG: if (layoutTables->kern_len != -1) return (void*)layoutTables->kern; break;
- default:
- //fprintf(stderr, "unexpected table request from font instance adapter: %x\n", tableTag);
+ int cacheIdx;
+ for (cacheIdx=0;cacheIdxentries[cacheIdx].len != -1) {
+ length = layoutTables->entries[cacheIdx].len;
+ return layoutTables->entries[cacheIdx].ptr;
+ }
+ } else {
+ //fprintf(stderr, "unexpected table request from font instance adapter: %x\n", tableTag);
+ // (don't load any other tables)
return 0;
}
@@ -96,16 +114,13 @@ const void *FontInstanceAdapter::getFontTable(LETag tableTag) const
env->GetByteArrayRegion(tableBytes, 0, len, result);
}
- switch(tableTag) {
- case GSUB_TAG: layoutTables->gsub = (void*)result; layoutTables->gsub_len = len; break;
- case GPOS_TAG: layoutTables->gpos = (void*)result; layoutTables->gpos_len = len; break;
- case GDEF_TAG: layoutTables->gdef = (void*)result; layoutTables->gdef_len = len; break;
- case MORT_TAG: layoutTables->mort = (void*)result; layoutTables->mort_len = len; break;
- case KERN_TAG: layoutTables->kern = (void*)result; layoutTables->kern_len = len; break;
- default: break;
+ if (cacheIdxentries[cacheIdx].len = len;
+ layoutTables->entries[cacheIdx].ptr = (const void*)result;
}
- return (void*)result;
+ length = len;
+ return (const void*)result;
};
LEGlyphID FontInstanceAdapter::mapCharToGlyph(LEUnicode32 ch, const LECharMapper *mapper) const
diff --git a/jdk/src/share/native/sun/font/FontInstanceAdapter.h b/jdk/src/share/native/sun/font/FontInstanceAdapter.h
index b78bdb4cabd..264cf27bdd6 100644
--- a/jdk/src/share/native/sun/font/FontInstanceAdapter.h
+++ b/jdk/src/share/native/sun/font/FontInstanceAdapter.h
@@ -86,6 +86,7 @@ public:
// tables are cached with the native font scaler data
// only supports gsub, gpos, gdef, mort tables at present
virtual const void *getFontTable(LETag tableTag) const;
+ virtual const void *getFontTable(LETag tableTag, size_t &len) const;
virtual void *getKernPairs() const {
return layoutTables->kernPairs;
diff --git a/jdk/src/share/native/sun/font/fontscalerdefs.h b/jdk/src/share/native/sun/font/fontscalerdefs.h
index 8f142752af9..7d84d84a536 100644
--- a/jdk/src/share/native/sun/font/fontscalerdefs.h
+++ b/jdk/src/share/native/sun/font/fontscalerdefs.h
@@ -120,20 +120,19 @@ typedef struct GlyphInfo {
#define GPOS_TAG 0x47504F53 /* 'GPOS' */
#define GDEF_TAG 0x47444546 /* 'GDEF' */
#define MORT_TAG 0x6D6F7274 /* 'mort' */
+#define MORX_TAG 0x6D6F7278 /* 'morx' */
#define KERN_TAG 0x6B65726E /* 'kern' */
+typedef struct TTLayoutTableCacheEntry {
+ const void* ptr;
+ int len;
+} TTLayoutTableCacheEntry;
+
+#define LAYOUTCACHE_ENTRIES 6
+
typedef struct TTLayoutTableCache {
- void* gsub;
- void* gpos;
- void* gdef;
- void* mort;
- void* kern;
- void* kernPairs;
- int gsub_len;
- int gpos_len;
- int gdef_len;
- int mort_len;
- int kern_len;
+ TTLayoutTableCacheEntry entries[LAYOUTCACHE_ENTRIES];
+ void* kernPairs;
} TTLayoutTableCache;
#include "sunfontids.h"
diff --git a/jdk/src/share/native/sun/font/layout/AlternateSubstSubtables.cpp b/jdk/src/share/native/sun/font/layout/AlternateSubstSubtables.cpp
index c099c25a7a7..493cea36843 100644
--- a/jdk/src/share/native/sun/font/layout/AlternateSubstSubtables.cpp
+++ b/jdk/src/share/native/sun/font/layout/AlternateSubstSubtables.cpp
@@ -39,19 +39,20 @@
U_NAMESPACE_BEGIN
-le_uint32 AlternateSubstitutionSubtable::process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter) const
+le_uint32 AlternateSubstitutionSubtable::process(const LEReferenceTo &base,
+ GlyphIterator *glyphIterator, LEErrorCode &success, const LEGlyphFilter *filter) const
{
// NOTE: For now, we'll just pick the first alternative...
LEGlyphID glyph = glyphIterator->getCurrGlyphID();
- le_int32 coverageIndex = getGlyphCoverage(glyph);
+ le_int32 coverageIndex = getGlyphCoverage(base, glyph, success);
- if (coverageIndex >= 0) {
+ if (coverageIndex >= 0 && LE_SUCCESS(success)) {
le_uint16 altSetCount = SWAPW(alternateSetCount);
if (coverageIndex < altSetCount) {
Offset alternateSetTableOffset = SWAPW(alternateSetTableOffsetArray[coverageIndex]);
- const AlternateSetTable *alternateSetTable =
- (const AlternateSetTable *) ((char *) this + alternateSetTableOffset);
+ const LEReferenceTo alternateSetTable(base, success,
+ (const AlternateSetTable *) ((char *) this + alternateSetTableOffset));
TTGlyphID alternate = SWAPW(alternateSetTable->alternateArray[0]);
if (filter == NULL || filter->accept(LE_SET_GLYPH(glyph, alternate))) {
diff --git a/jdk/src/share/native/sun/font/layout/AlternateSubstSubtables.h b/jdk/src/share/native/sun/font/layout/AlternateSubstSubtables.h
index fbc41212f1a..e2f250e691e 100644
--- a/jdk/src/share/native/sun/font/layout/AlternateSubstSubtables.h
+++ b/jdk/src/share/native/sun/font/layout/AlternateSubstSubtables.h
@@ -51,13 +51,17 @@ struct AlternateSetTable
TTGlyphID alternateArray[ANY_NUMBER];
};
+LE_VAR_ARRAY(AlternateSetTable, alternateArray)
+
struct AlternateSubstitutionSubtable : GlyphSubstitutionSubtable
{
le_uint16 alternateSetCount;
Offset alternateSetTableOffsetArray[ANY_NUMBER];
- le_uint32 process(GlyphIterator *glyphIterator, const LEGlyphFilter *filter = NULL) const;
+ le_uint32 process(const LEReferenceTo &base, GlyphIterator *glyphIterator, LEErrorCode &success, const LEGlyphFilter *filter = NULL) const;
};
+LE_VAR_ARRAY(AlternateSubstitutionSubtable, alternateSetTableOffsetArray)
+
U_NAMESPACE_END
#endif
diff --git a/jdk/src/share/native/sun/font/layout/ArabicLayoutEngine.cpp b/jdk/src/share/native/sun/font/layout/ArabicLayoutEngine.cpp
index 807a072410c..834a253a4b4 100644
--- a/jdk/src/share/native/sun/font/layout/ArabicLayoutEngine.cpp
+++ b/jdk/src/share/native/sun/font/layout/ArabicLayoutEngine.cpp
@@ -26,7 +26,7 @@
/*
*
- * (C) Copyright IBM Corp. 1998-2005 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved
*
*/
@@ -58,15 +58,18 @@ le_bool CharSubstitutionFilter::accept(LEGlyphID glyph) const
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ArabicOpenTypeLayoutEngine)
-ArabicOpenTypeLayoutEngine::ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
- le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success)
+ArabicOpenTypeLayoutEngine::ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode,
+ le_int32 languageCode, le_int32 typoFlags,
+ const LEReferenceTo &gsubTable,
+ LEErrorCode &success)
: OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success)
{
fFeatureMap = ArabicShaping::getFeatureMap(fFeatureMapCount);
fFeatureOrder = TRUE;
}
-ArabicOpenTypeLayoutEngine::ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
+ArabicOpenTypeLayoutEngine::ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode,
+ le_int32 languageCode,
le_int32 typoFlags, LEErrorCode &success)
: OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success)
{
@@ -88,8 +91,9 @@ ArabicOpenTypeLayoutEngine::~ArabicOpenTypeLayoutEngine()
// Input: characters
// Output: characters, char indices, tags
// Returns: output character count
-le_int32 ArabicOpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft,
- LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success)
+le_int32 ArabicOpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count,
+ le_int32 max, le_bool rightToLeft, LEUnicode *&outChars,
+ LEGlyphStorage &glyphStorage, LEErrorCode &success)
{
if (LE_FAILURE(success)) {
return 0;
@@ -137,32 +141,30 @@ void ArabicOpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], l
return;
}
- if (fGPOSTable != NULL) {
+ if (!fGPOSTable.isEmpty()) {
OpenTypeLayoutEngine::adjustGlyphPositions(chars, offset, count, reverse, glyphStorage, success);
- } else if (fGDEFTable != NULL) {
- GDEFMarkFilter filter(fGDEFTable);
-
+ } else if (!fGDEFTable.isEmpty()) {
+ GDEFMarkFilter filter(fGDEFTable, success);
adjustMarkGlyphs(glyphStorage, &filter, success);
} else {
- GlyphDefinitionTableHeader *gdefTable = (GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable;
- GDEFMarkFilter filter(gdefTable);
+ LEReferenceTo gdefTable(CanonShaping::glyphDefinitionTable, CanonShaping::glyphDefinitionTableLen);
+ GDEFMarkFilter filter(gdefTable, success);
adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success);
}
}
UnicodeArabicOpenTypeLayoutEngine::UnicodeArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success)
- : ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success)
+ : ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags | LE_CHAR_FILTER_FEATURE_FLAG, success)
{
fGSUBTable = (const GlyphSubstitutionTableHeader *) CanonShaping::glyphSubstitutionTable;
fGDEFTable = (const GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable;
-
- fSubstitutionFilter = new CharSubstitutionFilter(fontInstance);
+ /* OpenTypeLayoutEngine will allocate a substitution filter */
}
UnicodeArabicOpenTypeLayoutEngine::~UnicodeArabicOpenTypeLayoutEngine()
{
- delete fSubstitutionFilter;
+ /* OpenTypeLayoutEngine will cleanup the substitution filter */
}
// "glyphs", "indices" -> glyphs, indices
@@ -233,7 +235,7 @@ void UnicodeArabicOpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode cha
return;
}
- GDEFMarkFilter filter(fGDEFTable);
+ GDEFMarkFilter filter(fGDEFTable, success);
adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success);
}
diff --git a/jdk/src/share/native/sun/font/layout/ArabicLayoutEngine.h b/jdk/src/share/native/sun/font/layout/ArabicLayoutEngine.h
index 956b3d50f8c..239ae1816b4 100644
--- a/jdk/src/share/native/sun/font/layout/ArabicLayoutEngine.h
+++ b/jdk/src/share/native/sun/font/layout/ArabicLayoutEngine.h
@@ -75,7 +75,7 @@ public:
* @internal
*/
ArabicOpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode,
- le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success);
+ le_int32 typoFlags, const LEReferenceTo &gsubTable, LEErrorCode &success);
/**
* This constructor is used when the font requires a "canned" GSUB table which can't be known
diff --git a/jdk/src/share/native/sun/font/layout/ArabicShaping.cpp b/jdk/src/share/native/sun/font/layout/ArabicShaping.cpp
index 7c91f4f9721..0b56b4bacf2 100644
--- a/jdk/src/share/native/sun/font/layout/ArabicShaping.cpp
+++ b/jdk/src/share/native/sun/font/layout/ArabicShaping.cpp
@@ -58,14 +58,16 @@ const ArabicShaping::ShapeType ArabicShaping::shapeTypes[] =
*/
ArabicShaping::ShapeType ArabicShaping::getShapeType(LEUnicode c)
{
- const ClassDefinitionTable *joiningTypes = (const ClassDefinitionTable *) ArabicShaping::shapingTypeTable;
- le_int32 joiningType = joiningTypes->getGlyphClass(c);
+ LEErrorCode success = LE_NO_ERROR;
+ const LEReferenceTo joiningTypes((const ClassDefinitionTable *) ArabicShaping::shapingTypeTable,
+ ArabicShaping::shapingTypeTableLen);
+ le_int32 joiningType = joiningTypes->getGlyphClass(joiningTypes, c, success);
- if (joiningType >= 0 && joiningType < ArabicShaping::JT_COUNT) {
- return ArabicShaping::shapeTypes[joiningType];
- }
+ if (joiningType >= 0 && joiningType < ArabicShaping::JT_COUNT && LE_SUCCESS(success)) {
+ return ArabicShaping::shapeTypes[joiningType];
+ }
- return ArabicShaping::ST_NOSHAPE_NONE;
+ return ArabicShaping::ST_NOSHAPE_NONE;
}
#define isolFeatureTag LE_ISOL_FEATURE_TAG
diff --git a/jdk/src/share/native/sun/font/layout/ArabicShaping.h b/jdk/src/share/native/sun/font/layout/ArabicShaping.h
index 3838e168d41..40923ecb496 100644
--- a/jdk/src/share/native/sun/font/layout/ArabicShaping.h
+++ b/jdk/src/share/native/sun/font/layout/ArabicShaping.h
@@ -93,6 +93,8 @@ private:
static ShapeType getShapeType(LEUnicode c);
static const le_uint8 shapingTypeTable[];
+ static const size_t shapingTypeTableLen;
+
static const ShapeType shapeTypes[];
static void adjustTags(le_int32 outIndex, le_int32 shapeOffset, LEGlyphStorage &glyphStorage);
diff --git a/jdk/src/share/native/sun/font/layout/AttachmentPosnSubtables.h b/jdk/src/share/native/sun/font/layout/AttachmentPosnSubtables.h
index 2ed8d9d270c..e7a27608ff4 100644
--- a/jdk/src/share/native/sun/font/layout/AttachmentPosnSubtables.h
+++ b/jdk/src/share/native/sun/font/layout/AttachmentPosnSubtables.h
@@ -52,14 +52,14 @@ struct AttachmentPositioningSubtable : GlyphPositioningSubtable
Offset markArrayOffset;
Offset baseArrayOffset;
- inline le_int32 getBaseCoverage(LEGlyphID baseGlyphId) const;
+ inline le_int32 getBaseCoverage(const LETableReference &base, LEGlyphID baseGlyphId, LEErrorCode &success) const;
le_uint32 process(GlyphIterator *glyphIterator) const;
};
-inline le_int32 AttachmentPositioningSubtable::getBaseCoverage(LEGlyphID baseGlyphID) const
+inline le_int32 AttachmentPositioningSubtable::getBaseCoverage(const LETableReference &base, LEGlyphID baseGlyphID, LEErrorCode &success) const
{
- return getGlyphCoverage(baseCoverageTableOffset, baseGlyphID);
+ return getGlyphCoverage(base, baseCoverageTableOffset, baseGlyphID, success);
}
U_NAMESPACE_END
diff --git a/jdk/src/share/native/sun/font/layout/CanonData.cpp b/jdk/src/share/native/sun/font/layout/CanonData.cpp
index 41d4bc213ae..49b13ab1c10 100644
--- a/jdk/src/share/native/sun/font/layout/CanonData.cpp
+++ b/jdk/src/share/native/sun/font/layout/CanonData.cpp
@@ -3641,4 +3641,9 @@ const le_uint8 CanonShaping::glyphDefinitionTable[] = {
0x00, 0xE6, 0xD2, 0x42, 0xD2, 0x44, 0x00, 0xE6
};
+
+const size_t CanonShaping::glyphSubstitutionTableLen = sizeof(glyphSubstitutionTable)/sizeof(glyphSubstitutionTable[0]);
+
+const size_t CanonShaping::glyphDefinitionTableLen = sizeof(glyphDefinitionTable)/sizeof(glyphDefinitionTable[0]);
+
U_NAMESPACE_END
diff --git a/jdk/src/share/native/sun/font/layout/CanonShaping.cpp b/jdk/src/share/native/sun/font/layout/CanonShaping.cpp
index 498ffa8f2de..86f2ebc89c1 100644
--- a/jdk/src/share/native/sun/font/layout/CanonShaping.cpp
+++ b/jdk/src/share/native/sun/font/layout/CanonShaping.cpp
@@ -59,15 +59,15 @@ void CanonShaping::sortMarks(le_int32 *indices, const le_int32 *combiningClasses
void CanonShaping::reorderMarks(const LEUnicode *inChars, le_int32 charCount, le_bool rightToLeft,
LEUnicode *outChars, LEGlyphStorage &glyphStorage)
{
- const GlyphDefinitionTableHeader *gdefTable = (const GlyphDefinitionTableHeader *) glyphDefinitionTable;
- const ClassDefinitionTable *classTable = gdefTable->getMarkAttachClassDefinitionTable();
+ LEErrorCode success = LE_NO_ERROR;
+ LEReferenceTo gdefTable(CanonShaping::glyphDefinitionTable, CanonShaping::glyphDefinitionTableLen);
+ LEReferenceTo classTable = gdefTable->getMarkAttachClassDefinitionTable(gdefTable, success);
le_int32 *combiningClasses = LE_NEW_ARRAY(le_int32, charCount);
le_int32 *indices = LE_NEW_ARRAY(le_int32, charCount);
- LEErrorCode status = LE_NO_ERROR;
le_int32 i;
for (i = 0; i < charCount; i += 1) {
- combiningClasses[i] = classTable->getGlyphClass((LEGlyphID) inChars[i]);
+ combiningClasses[i] = classTable->getGlyphClass(classTable, (LEGlyphID) inChars[i], success);
indices[i] = i;
}
@@ -96,7 +96,7 @@ void CanonShaping::reorderMarks(const LEUnicode *inChars, le_int32 charCount, le
le_int32 index = indices[i];
outChars[i] = inChars[index];
- glyphStorage.setCharIndex(out, index, status);
+ glyphStorage.setCharIndex(out, index, success);
}
LE_DELETE_ARRAY(indices);
diff --git a/jdk/src/share/native/sun/font/layout/CanonShaping.h b/jdk/src/share/native/sun/font/layout/CanonShaping.h
index 62ad919b965..5d6a097e11c 100644
--- a/jdk/src/share/native/sun/font/layout/CanonShaping.h
+++ b/jdk/src/share/native/sun/font/layout/CanonShaping.h
@@ -42,7 +42,9 @@ class U_LAYOUT_API CanonShaping /* not : public UObject because all members are
{
public:
static const le_uint8 glyphSubstitutionTable[];
+ static const size_t glyphSubstitutionTableLen;
static const le_uint8 glyphDefinitionTable[];
+ static const size_t glyphDefinitionTableLen;
static void reorderMarks(const LEUnicode *inChars, le_int32 charCount, le_bool rightToLeft,
LEUnicode *outChars, LEGlyphStorage &glyphStorage);
diff --git a/jdk/src/share/native/sun/font/layout/ClassDefinitionTables.cpp b/jdk/src/share/native/sun/font/layout/ClassDefinitionTables.cpp
index af600444007..08e7f7732c8 100644
--- a/jdk/src/share/native/sun/font/layout/ClassDefinitionTables.cpp
+++ b/jdk/src/share/native/sun/font/layout/ClassDefinitionTables.cpp
@@ -37,24 +37,51 @@
U_NAMESPACE_BEGIN
-le_int32 ClassDefinitionTable::getGlyphClass(LEGlyphID glyphID) const
+le_int32 ClassDefinitionTable::getGlyphClass(const LETableReference& base, LEGlyphID glyphID, LEErrorCode &success) const
{
+ LEReferenceTo thisRef(base, success);
+ if (LE_FAILURE(success)) return 0;
+
+ switch(SWAPW(classFormat)) {
+ case 0:
+ return 0;
+
+ case 1:
+ {
+ const LEReferenceTo f1Table(thisRef, success);
+ return f1Table->getGlyphClass(f1Table, glyphID, success);
+ }
+
+ case 2:
+ {
+ const LEReferenceTo f2Table(thisRef, success);
+ return f2Table->getGlyphClass(f2Table, glyphID, success);
+ }
+
+ default:
+ return 0;
+ }
+}
+
+le_bool ClassDefinitionTable::hasGlyphClass(const LETableReference &base, le_int32 glyphClass, LEErrorCode &success) const
+{
+ LEReferenceTo thisRef(base, success);
+ if (LE_FAILURE(success)) return 0;
+
switch(SWAPW(classFormat)) {
case 0:
return 0;
case 1:
{
- const ClassDefFormat1Table *f1Table = (const ClassDefFormat1Table *) this;
-
- return f1Table->getGlyphClass(glyphID);
+ const LEReferenceTo f1Table(thisRef, success);
+ return f1Table->hasGlyphClass(f1Table, glyphClass, success);
}
case 2:
{
- const ClassDefFormat2Table *f2Table = (const ClassDefFormat2Table *) this;
-
- return f2Table->getGlyphClass(glyphID);
+ const LEReferenceTo f2Table(thisRef, success);
+ return f2Table->hasGlyphClass(f2Table, glyphClass, success);
}
default:
@@ -62,51 +89,32 @@ le_int32 ClassDefinitionTable::getGlyphClass(LEGlyphID glyphID) const
}
}
-le_bool ClassDefinitionTable::hasGlyphClass(le_int32 glyphClass) const
+le_int32 ClassDefFormat1Table::getGlyphClass(const LETableReference& base, LEGlyphID glyphID, LEErrorCode &success) const
{
- switch(SWAPW(classFormat)) {
- case 0:
- return 0;
+ if(LE_FAILURE(success)) return 0;
- case 1:
- {
- const ClassDefFormat1Table *f1Table = (const ClassDefFormat1Table *) this;
-
- return f1Table->hasGlyphClass(glyphClass);
- }
-
- case 2:
- {
- const ClassDefFormat2Table *f2Table = (const ClassDefFormat2Table *) this;
-
- return f2Table->hasGlyphClass(glyphClass);
- }
-
- default:
- return 0;
- }
-}
-
-le_int32 ClassDefFormat1Table::getGlyphClass(LEGlyphID glyphID) const
-{
+ le_uint16 count = SWAPW(glyphCount);
+ LEReferenceToArrayOf classValueArrayRef(base, success, &classValueArray[0], count);
TTGlyphID ttGlyphID = (TTGlyphID) LE_GET_GLYPH(glyphID);
TTGlyphID firstGlyph = SWAPW(startGlyph);
- TTGlyphID lastGlyph = firstGlyph + SWAPW(glyphCount);
+ TTGlyphID lastGlyph = firstGlyph + count;
- if (ttGlyphID >= firstGlyph && ttGlyphID < lastGlyph) {
- return SWAPW(classValueArray[ttGlyphID - firstGlyph]);
+ if (LE_SUCCESS(success) && ttGlyphID >= firstGlyph && ttGlyphID < lastGlyph) {
+ return SWAPW( classValueArrayRef(ttGlyphID - firstGlyph, success) );
}
return 0;
}
-le_bool ClassDefFormat1Table::hasGlyphClass(le_int32 glyphClass) const
+le_bool ClassDefFormat1Table::hasGlyphClass(const LETableReference &base, le_int32 glyphClass, LEErrorCode &success) const
{
- le_uint16 count = SWAPW(glyphCount);
+ if(LE_FAILURE(success)) return 0;
+ le_uint16 count = SWAPW(glyphCount);
+ LEReferenceToArrayOf classValueArrayRef(base, success, &classValueArray[0], count);
int i;
- for (i = 0; i < count; i += 1) {
- if (SWAPW(classValueArray[i]) == glyphClass) {
+ for (i = 0; LE_SUCCESS(success)&& (i < count); i += 1) {
+ if (SWAPW(classValueArrayRef(i,success)) == glyphClass) {
return TRUE;
}
}
@@ -114,27 +122,31 @@ le_bool ClassDefFormat1Table::hasGlyphClass(le_int32 glyphClass) const
return FALSE;
}
-le_int32 ClassDefFormat2Table::getGlyphClass(LEGlyphID glyphID) const
+le_int32 ClassDefFormat2Table::getGlyphClass(const LETableReference& base, LEGlyphID glyphID, LEErrorCode &success) const
{
+ if(LE_FAILURE(success)) return 0;
TTGlyphID ttGlyph = (TTGlyphID) LE_GET_GLYPH(glyphID);
le_uint16 rangeCount = SWAPW(classRangeCount);
+ LEReferenceToArrayOf classRangeRecordArrayRef(base, success, &classRangeRecordArray[0], rangeCount);
le_int32 rangeIndex =
- OpenTypeUtilities::getGlyphRangeIndex(ttGlyph, classRangeRecordArray, rangeCount);
+ OpenTypeUtilities::getGlyphRangeIndex(ttGlyph, classRangeRecordArrayRef, success);
- if (rangeIndex < 0) {
+ if (rangeIndex < 0 || LE_FAILURE(success)) {
return 0;
}
- return SWAPW(classRangeRecordArray[rangeIndex].rangeValue);
+ return SWAPW(classRangeRecordArrayRef(rangeIndex, success).rangeValue);
}
-le_bool ClassDefFormat2Table::hasGlyphClass(le_int32 glyphClass) const
+le_bool ClassDefFormat2Table::hasGlyphClass(const LETableReference &base, le_int32 glyphClass, LEErrorCode &success) const
{
+ if(LE_FAILURE(success)) return 0;
le_uint16 rangeCount = SWAPW(classRangeCount);
+ LEReferenceToArrayOf classRangeRecordArrayRef(base, success, &classRangeRecordArray[0], rangeCount);
int i;
- for (i = 0; i < rangeCount; i += 1) {
- if (SWAPW(classRangeRecordArray[i].rangeValue) == glyphClass) {
+ for (i = 0; i < rangeCount && LE_SUCCESS(success); i += 1) {
+ if (SWAPW(classRangeRecordArrayRef(i,success).rangeValue) == glyphClass) {
return TRUE;
}
}
diff --git a/jdk/src/share/native/sun/font/layout/ClassDefinitionTables.h b/jdk/src/share/native/sun/font/layout/ClassDefinitionTables.h
index a298e85c626..410119145a5 100644
--- a/jdk/src/share/native/sun/font/layout/ClassDefinitionTables.h
+++ b/jdk/src/share/native/sun/font/layout/ClassDefinitionTables.h
@@ -46,8 +46,20 @@ struct ClassDefinitionTable
{
le_uint16 classFormat;
- le_int32 getGlyphClass(LEGlyphID glyphID) const;
- le_bool hasGlyphClass(le_int32 glyphClass) const;
+ le_int32 getGlyphClass(const LETableReference &base, LEGlyphID glyphID, LEErrorCode &success) const;
+ le_bool hasGlyphClass(const LETableReference &base, le_int32 glyphClass, LEErrorCode &success) const;
+
+ le_int32 getGlyphClass(LEGlyphID glyphID) const {
+ LETableReference base((const le_uint8*)this);
+ LEErrorCode ignored = LE_NO_ERROR;
+ return getGlyphClass(base,glyphID,ignored);
+ }
+
+ le_bool hasGlyphClass(le_int32 glyphClass) const {
+ LETableReference base((const le_uint8*)this);
+ LEErrorCode ignored = LE_NO_ERROR;
+ return hasGlyphClass(base,glyphClass,ignored);
+ }
};
struct ClassDefFormat1Table : ClassDefinitionTable
@@ -56,9 +68,11 @@ struct ClassDefFormat1Table : ClassDefinitionTable
le_uint16 glyphCount;
le_uint16 classValueArray[ANY_NUMBER];
- le_int32 getGlyphClass(LEGlyphID glyphID) const;
- le_bool hasGlyphClass(le_int32 glyphClass) const;
+ le_int32 getGlyphClass(const LETableReference &base, LEGlyphID glyphID, LEErrorCode &success) const;
+ le_bool hasGlyphClass(const LETableReference &base, le_int32 glyphClass, LEErrorCode &success) const;
};
+LE_VAR_ARRAY(ClassDefFormat1Table, classValueArray)
+
struct ClassRangeRecord
{
@@ -72,9 +86,10 @@ struct ClassDefFormat2Table : ClassDefinitionTable
le_uint16 classRangeCount;
GlyphRangeRecord classRangeRecordArray[ANY_NUMBER];
- le_int32 getGlyphClass(LEGlyphID glyphID) const;
- le_bool hasGlyphClass(le_int32 glyphClass) const;
+ le_int32 getGlyphClass(const LETableReference &base, LEGlyphID glyphID, LEErrorCode &success) const;
+ le_bool hasGlyphClass(const LETableReference &base, le_int32 glyphClass, LEErrorCode &success) const;
};
+LE_VAR_ARRAY(ClassDefFormat2Table, classRangeRecordArray)
U_NAMESPACE_END
#endif
diff --git a/jdk/src/share/native/sun/font/layout/ContextualGlyphInsertion.h b/jdk/src/share/native/sun/font/layout/ContextualGlyphInsertion.h
index 40f47afcc0e..2285711b0a7 100644
--- a/jdk/src/share/native/sun/font/layout/ContextualGlyphInsertion.h
+++ b/jdk/src/share/native/sun/font/layout/ContextualGlyphInsertion.h
@@ -25,7 +25,7 @@
/*
*
- * (C) Copyright IBM Corp. 1998-2004 - All Rights Reserved
+ * (C) Copyright IBM Corp. 1998-2013 - All Rights Reserved
*
*/
@@ -49,6 +49,11 @@ struct ContextualGlyphInsertionHeader : MorphStateTableHeader
{
};
+struct ContextualGlyphInsertionHeader2 : MorphStateTableHeader2
+{
+ le_uint32 insertionTableOffset;
+};
+
enum ContextualGlyphInsertionFlags
{
cgiSetMark = 0x8000,
@@ -61,11 +66,17 @@ enum ContextualGlyphInsertionFlags
cgiMarkedInsertCountMask = 0x001F
};
-struct LigatureSubstitutionStateEntry : StateEntry
+struct ContextualGlyphInsertionStateEntry : StateEntry
{
ByteOffset currentInsertionListOffset;
ByteOffset markedInsertionListOffset;
};
+struct ContextualGlyphInsertionStateEntry2 : StateEntry2
+{
+ le_uint16 currentInsertionListIndex;
+ le_uint16 markedInsertionListIndex;
+};
+
U_NAMESPACE_END
#endif
diff --git a/jdk/src/share/native/sun/font/layout/ContextualGlyphInsertionProc2.cpp b/jdk/src/share/native/sun/font/layout/ContextualGlyphInsertionProc2.cpp
new file mode 100644
index 00000000000..85f9fc7ab22
--- /dev/null
+++ b/jdk/src/share/native/sun/font/layout/ContextualGlyphInsertionProc2.cpp
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ *
+ */
+
+/*
+ *
+ * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved
+ *
+ */
+
+#include "LETypes.h"
+#include "MorphTables.h"
+#include "StateTables.h"
+#include "MorphStateTables.h"
+#include "SubtableProcessor2.h"
+#include "StateTableProcessor2.h"
+#include "ContextualGlyphInsertionProc2.h"
+#include "LEGlyphStorage.h"
+#include "LESwaps.h"
+
+U_NAMESPACE_BEGIN
+
+UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ContextualGlyphInsertionProcessor2)
+
+ContextualGlyphInsertionProcessor2::ContextualGlyphInsertionProcessor2(
+ const LEReferenceTo &morphSubtableHeader, LEErrorCode &success)
+ : StateTableProcessor2(morphSubtableHeader, success)
+{
+ contextualGlyphHeader = LEReferenceTo(morphSubtableHeader, success);
+ if(LE_FAILURE(success) || !contextualGlyphHeader.isValid()) return;
+ le_uint32 insertionTableOffset = SWAPL(contextualGlyphHeader->insertionTableOffset);
+ insertionTable = LEReferenceToArrayOf(stHeader, success, insertionTableOffset, LE_UNBOUNDED_ARRAY);
+ entryTable = LEReferenceToArrayOf(stHeader, success, entryTableOffset, LE_UNBOUNDED_ARRAY);
+}
+
+ContextualGlyphInsertionProcessor2::~ContextualGlyphInsertionProcessor2()
+{
+}
+
+void ContextualGlyphInsertionProcessor2::beginStateTable()
+{
+ markGlyph = 0;
+}
+
+void ContextualGlyphInsertionProcessor2::doInsertion(LEGlyphStorage &glyphStorage,
+ le_int16 atGlyph,
+ le_int16 &index,
+ le_int16 count,
+ le_bool /* isKashidaLike */,
+ le_bool isBefore,
+ LEErrorCode &success) {
+ LEGlyphID *insertGlyphs = glyphStorage.insertGlyphs(atGlyph, count + 1, success);
+
+ if(LE_FAILURE(success) || insertGlyphs==NULL) {
+ return;
+ }
+
+ // Note: Kashida vs Split Vowel seems to only affect selection and highlighting.
+ // We note the flag, but do not layout different.
+ // https://developer.apple.com/fonts/TTRefMan/RM06/Chap6mort.html
+
+ le_int16 targetIndex = 0;
+ if(isBefore) {
+ // insert at beginning
+ insertGlyphs[targetIndex++] = glyphStorage[atGlyph];
+ } else {
+ // insert at end
+ insertGlyphs[count] = glyphStorage[atGlyph];
+ }
+
+ while(count--) {
+ insertGlyphs[targetIndex++] = insertionTable.getObject(index++, success);
+ }
+ glyphStorage.applyInsertions();
+}
+
+le_uint16 ContextualGlyphInsertionProcessor2::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph,
+ EntryTableIndex2 index, LEErrorCode &success)
+{
+ const ContextualGlyphInsertionStateEntry2 *entry = entryTable.getAlias(index, success);
+
+ if(LE_FAILURE(success)) return 0; // TODO- which state?
+
+ le_uint16 newState = SWAPW(entry->newStateIndex);
+ le_uint16 flags = SWAPW(entry->flags);
+
+ le_int16 markIndex = SWAPW(entry->markedInsertionListIndex);
+ if (markIndex > 0) {
+ le_int16 count = (flags & cgiMarkedInsertCountMask) >> 5;
+ le_bool isKashidaLike = (flags & cgiMarkedIsKashidaLike);
+ le_bool isBefore = (flags & cgiMarkInsertBefore);
+ doInsertion(glyphStorage, markGlyph, markIndex, count, isKashidaLike, isBefore, success);
+ }
+
+ le_int16 currIndex = SWAPW(entry->currentInsertionListIndex);
+ if (currIndex > 0) {
+ le_int16 count = flags & cgiCurrentInsertCountMask;
+ le_bool isKashidaLike = (flags & cgiCurrentIsKashidaLike);
+ le_bool isBefore = (flags & cgiCurrentInsertBefore);
+ doInsertion(glyphStorage, currGlyph, currIndex, count, isKashidaLike, isBefore, success);
+ }
+
+ if (flags & cgiSetMark) {
+ markGlyph = currGlyph;
+ }
+
+ if (!(flags & cgiDontAdvance)) {
+ currGlyph += dir;
+ }
+
+ return newState;
+}
+
+void ContextualGlyphInsertionProcessor2::endStateTable()
+{
+}
+
+U_NAMESPACE_END
diff --git a/jdk/src/share/native/sun/font/layout/ContextualGlyphInsertionProc2.h b/jdk/src/share/native/sun/font/layout/ContextualGlyphInsertionProc2.h
new file mode 100644
index 00000000000..c02da35ed6d
--- /dev/null
+++ b/jdk/src/share/native/sun/font/layout/ContextualGlyphInsertionProc2.h
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ *
+ */
+
+/*
+ *
+ * (C) Copyright IBM Corp. and others 2013 - All Rights Reserved
+ *
+ */
+
+#ifndef __CONTEXTUALGLYPHINSERTIONPROCESSOR2_H
+#define __CONTEXTUALGLYPHINSERTIONPROCESSOR2_H
+
+/**
+ * \file
+ * \internal
+ */
+
+#include "LETypes.h"
+#include "MorphTables.h"
+#include "SubtableProcessor2.h"
+#include "StateTableProcessor2.h"
+#include "ContextualGlyphInsertionProc2.h"
+#include "ContextualGlyphInsertion.h"
+
+U_NAMESPACE_BEGIN
+
+class LEGlyphStorage;
+
+class ContextualGlyphInsertionProcessor2 : public StateTableProcessor2
+{
+public:
+ virtual void beginStateTable();
+
+ virtual le_uint16 processStateEntry(LEGlyphStorage &glyphStorage,
+ le_int32 &currGlyph, EntryTableIndex2 index, LEErrorCode &success);
+
+ virtual void endStateTable();
+
+ ContextualGlyphInsertionProcessor2(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success);
+ virtual ~ContextualGlyphInsertionProcessor2();
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for the actual class.
+ *
+ * @stable ICU 2.8
+ */
+ virtual UClassID getDynamicClassID() const;
+
+ /**
+ * ICU "poor man's RTTI", returns a UClassID for this class.
+ *
+ * @stable ICU 2.8
+ */
+ static UClassID getStaticClassID();
+
+private:
+ ContextualGlyphInsertionProcessor2();
+
+ /**
+ * Perform the actual insertion
+ * @param atGlyph index of glyph to insert at
+ * @param index index into the insertionTable (in/out)
+ * @param count number of insertions
+ * @param isKashidaLike Kashida like (vs Split Vowel like). No effect currently.
+ * @param isBefore if true, insert extra glyphs before the marked glyph
+ */
+ void doInsertion(LEGlyphStorage &glyphStorage,
+ le_int16 atGlyph,
+ le_int16 &index,
+ le_int16 count,
+ le_bool isKashidaLike,
+ le_bool isBefore,
+ LEErrorCode &success);
+
+
+protected:
+ le_int32 markGlyph;
+ LEReferenceToArrayOf insertionTable;
+ LEReferenceToArrayOf entryTable;
+ LEReferenceTo contextualGlyphHeader;
+};
+
+U_NAMESPACE_END
+#endif
diff --git a/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc.cpp b/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc.cpp
index 7c659534f09..87fdf4d3aab 100644
--- a/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc.cpp
+++ b/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc.cpp
@@ -43,13 +43,18 @@ U_NAMESPACE_BEGIN
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ContextualGlyphSubstitutionProcessor)
-ContextualGlyphSubstitutionProcessor::ContextualGlyphSubstitutionProcessor(const MorphSubtableHeader *morphSubtableHeader)
- : StateTableProcessor(morphSubtableHeader)
+ContextualGlyphSubstitutionProcessor::ContextualGlyphSubstitutionProcessor(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success)
+ : StateTableProcessor(morphSubtableHeader, success), entryTable(), contextualGlyphSubstitutionHeader(morphSubtableHeader, success)
{
- contextualGlyphSubstitutionHeader = (const ContextualGlyphSubstitutionHeader *) morphSubtableHeader;
- substitutionTableOffset = SWAPW(contextualGlyphSubstitutionHeader->substitutionTableOffset);
+ contextualGlyphSubstitutionHeader.orphan();
+ substitutionTableOffset = SWAPW(contextualGlyphSubstitutionHeader->substitutionTableOffset);
- entryTable = (const ContextualGlyphSubstitutionStateEntry *) ((char *) &stateTableHeader->stHeader + entryTableOffset);
+
+ entryTable = LEReferenceToArrayOf(stateTableHeader, success,
+ (const ContextualGlyphSubstitutionStateEntry*)(&stateTableHeader->stHeader),
+ entryTableOffset, LE_UNBOUNDED_ARRAY);
+ int16Table = LEReferenceToArrayOf(stateTableHeader, success, (const le_int16*)(&stateTableHeader->stHeader),
+ 0, LE_UNBOUNDED_ARRAY); // rest of the table as le_int16s
}
ContextualGlyphSubstitutionProcessor::~ContextualGlyphSubstitutionProcessor()
@@ -63,27 +68,26 @@ void ContextualGlyphSubstitutionProcessor::beginStateTable()
ByteOffset ContextualGlyphSubstitutionProcessor::processStateEntry(LEGlyphStorage &glyphStorage, le_int32 &currGlyph, EntryTableIndex index)
{
- const ContextualGlyphSubstitutionStateEntry *entry = &entryTable[index];
- ByteOffset newState = SWAPW(entry->newStateOffset);
- le_int16 flags = SWAPW(entry->flags);
- WordOffset markOffset = SWAPW(entry->markOffset);
- WordOffset currOffset = SWAPW(entry->currOffset);
+ LEErrorCode success = LE_NO_ERROR;
+ const ContextualGlyphSubstitutionStateEntry *entry = entryTable.getAlias(index, success);
+ ByteOffset newState = SWAPW(entry->newStateOffset);
+ le_int16 flags = SWAPW(entry->flags);
+ WordOffset markOffset = SWAPW(entry->markOffset);
+ WordOffset currOffset = SWAPW(entry->currOffset);
- if (markOffset != 0) {
- const le_int16 *table = (const le_int16 *) ((char *) &stateTableHeader->stHeader + markOffset * 2);
- LEGlyphID mGlyph = glyphStorage[markGlyph];
- TTGlyphID newGlyph = SWAPW(table[LE_GET_GLYPH(mGlyph)]);
+ if (markOffset != 0 && LE_SUCCESS(success)) {
+ LEGlyphID mGlyph = glyphStorage[markGlyph];
+ TTGlyphID newGlyph = SWAPW(int16Table.getObject(markOffset + LE_GET_GLYPH(mGlyph), success)); // whew.
- glyphStorage[markGlyph] = LE_SET_GLYPH(mGlyph, newGlyph);
- }
+ glyphStorage[markGlyph] = LE_SET_GLYPH(mGlyph, newGlyph);
+ }
- if (currOffset != 0) {
- const le_int16 *table = (const le_int16 *) ((char *) &stateTableHeader->stHeader + currOffset * 2);
- LEGlyphID thisGlyph = glyphStorage[currGlyph];
- TTGlyphID newGlyph = SWAPW(table[LE_GET_GLYPH(thisGlyph)]);
+ if (currOffset != 0) {
+ LEGlyphID thisGlyph = glyphStorage[currGlyph];
+ TTGlyphID newGlyph = SWAPW(int16Table.getObject(currOffset + LE_GET_GLYPH(thisGlyph), success)); // whew.
- glyphStorage[currGlyph] = LE_SET_GLYPH(thisGlyph, newGlyph);
- }
+ glyphStorage[currGlyph] = LE_SET_GLYPH(thisGlyph, newGlyph);
+ }
if (flags & cgsSetMark) {
markGlyph = currGlyph;
diff --git a/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc.h b/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc.h
index e93585e9bcb..136398f7661 100644
--- a/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc.h
+++ b/jdk/src/share/native/sun/font/layout/ContextualGlyphSubstProc.h
@@ -56,7 +56,7 @@ public:
virtual void endStateTable();
- ContextualGlyphSubstitutionProcessor(const MorphSubtableHeader *morphSubtableHeader);
+ ContextualGlyphSubstitutionProcessor(const LEReferenceTo &morphSubtableHeader, LEErrorCode &success);
virtual ~ContextualGlyphSubstitutionProcessor();
/**
@@ -78,11 +78,11 @@ private:
protected:
ByteOffset substitutionTableOffset;
- const ContextualGlyphSubstitutionStateEntry *entryTable;
-
+ LEReferenceToArrayOf entryTable;
+ LEReferenceToArrayOf