This commit is contained in:
Calvin Cheung 2015-04-17 14:37:44 -07:00
commit cd6c611521
14 changed files with 662 additions and 204 deletions

View File

@ -38,7 +38,17 @@ import static com.sun.crypto.provider.AESConstants.AES_BLOCK_SIZE;
* under section 6.5. It needs to be constructed w/ an initialized
* cipher object, and initial counter block(ICB). Given an input X
* of arbitrary length, it processes and returns an output which has
* the same length as X.
* the same length as X. The invariants of this class are:
*
* (1) The length of intialCounterBlk (and also of its clones, e.g.,
* fields counter and counterSave) is equal to AES_BLOCK_SIZE.
*
* (2) After construction, the field counter never becomes null, it
* always contains a byte array of length AES_BLOCK_SIZE.
*
* If any invariant is broken, failures can occur because the
* AESCrypt.encryptBlock method can be intrinsified on the HotSpot VM
* (see JDK-8067648 for details).
*
* <p>This function is used in the implementation of GCM mode.
*
@ -59,6 +69,10 @@ final class GCTR {
// NOTE: cipher should already be initialized
GCTR(SymmetricCipher cipher, byte[] initialCounterBlk) {
this.aes = cipher;
if (initialCounterBlk.length != AES_BLOCK_SIZE) {
throw new RuntimeException("length of initial counter block (" + initialCounterBlk.length +
") not equal to AES_BLOCK_SIZE (" + AES_BLOCK_SIZE + ")");
}
this.icb = initialCounterBlk;
this.counter = icb.clone();
}
@ -137,6 +151,8 @@ final class GCTR {
* Restores the content of this object to the previous saved one.
*/
void restore() {
this.counter = this.counterSave;
if (this.counterSave != null) {
this.counter = this.counterSave;
}
}
}

View File

@ -1312,7 +1312,7 @@ public final class Class<T> implements java.io.Serializable,
// e) Anonymous classes
// JVM Spec 4.8.6: A class must have an EnclosingMethod
// JVM Spec 4.7.7: A class must have an EnclosingMethod
// attribute if and only if it is a local class or an
// anonymous class.
EnclosingMethodInfo enclosingInfo = getEnclosingMethodInfo();
@ -1357,28 +1357,7 @@ public final class Class<T> implements java.io.Serializable,
simpleName = getName();
return simpleName.substring(simpleName.lastIndexOf('.')+1); // strip the package name
}
// According to JLS3 "Binary Compatibility" (13.1) the binary
// name of non-package classes (not top level) is the binary
// name of the immediately enclosing class followed by a '$' followed by:
// (for nested and inner classes): the simple name.
// (for local classes): 1 or more digits followed by the simple name.
// (for anonymous classes): 1 or more digits.
// Since getSimpleBinaryName() will strip the binary name of
// the immediately enclosing class, we are now looking at a
// string that matches the regular expression "\$[0-9]*"
// followed by a simple name (considering the simple of an
// anonymous class to be the empty string).
// Remove leading "\$[0-9]*" from the name
int length = simpleName.length();
if (length < 1 || simpleName.charAt(0) != '$')
throw new InternalError("Malformed class name");
int index = 1;
while (index < length && isAsciiDigit(simpleName.charAt(index)))
index++;
// Eventually, this is the empty string iff this is an anonymous class
return simpleName.substring(index);
return simpleName;
}
/**
@ -1489,20 +1468,20 @@ public final class Class<T> implements java.io.Serializable,
Class<?> enclosingClass = getEnclosingClass();
if (enclosingClass == null) // top level class
return null;
// Otherwise, strip the enclosing class' name
try {
return getName().substring(enclosingClass.getName().length());
} catch (IndexOutOfBoundsException ex) {
throw new InternalError("Malformed class name", ex);
}
String name = getSimpleBinaryName0();
if (name == null) // anonymous class
return "";
return name;
}
private native String getSimpleBinaryName0();
/**
* Returns {@code true} if this is a local class or an anonymous
* class. Returns {@code false} otherwise.
*/
private boolean isLocalOrAnonymousClass() {
// JVM Spec 4.8.6: A class must have an EnclosingMethod
// JVM Spec 4.7.7: A class must have an EnclosingMethod
// attribute if and only if it is a local class or an
// anonymous class.
return getEnclosingMethodInfo() != null;

View File

@ -691,10 +691,4 @@ class DirectMethodHandle extends MethodHandle {
}
}
}
@Override
void customize() {
assert(form.customized == null);
// No need to customize DMHs.
}
}

View File

@ -847,11 +847,7 @@ class InvokerBytecodeGenerator {
refKind = REF_invokeVirtual;
}
if (member.getDeclaringClass().isInterface() && refKind == REF_invokeVirtual) {
// Methods from Object declared in an interface can be resolved by JVM to invokevirtual kind.
// Need to convert it back to invokeinterface to pass verification and make the invocation works as expected.
refKind = REF_invokeInterface;
}
assert(!(member.getDeclaringClass().isInterface() && refKind == REF_invokeVirtual));
// push arguments
emitPushArguments(name);

View File

@ -394,6 +394,7 @@ class Invokers {
@ForceInline
void checkCustomized(Object o) {
MethodHandle mh = (MethodHandle)o;
if (MethodHandleImpl.isCompileConstant(mh)) return;
if (mh.form.customized == null) {
maybeCustomize(mh);
}

View File

@ -722,6 +722,13 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
return result;
}
// Intrinsified by C2. Returns true if obj is a compile-time constant.
@LambdaForm.Hidden
static
boolean isCompileConstant(Object obj) {
return false;
}
static
MethodHandle makeGuardWithTest(MethodHandle test,
MethodHandle target,

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2015, 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
@ -55,16 +55,6 @@ class MethodHandleNatives {
static native Object staticFieldBase(MemberName self); // e.g., returns clazz
static native Object getMemberVMInfo(MemberName self); // returns {vmindex,vmtarget}
/// MethodHandle support
/** Fetch MH-related JVM parameter.
* which=0 retrieves MethodHandlePushLimit
* which=1 retrieves stack slot push size (in address units)
*/
static native int getConstant(int which);
static final boolean COUNT_GWT;
/// CallSite support
/** Tell the JVM that we need to change the target of a CallSite. */
@ -74,102 +64,30 @@ class MethodHandleNatives {
private static native void registerNatives();
static {
registerNatives();
COUNT_GWT = getConstant(Constants.GC_COUNT_GWT) != 0;
// The JVM calls MethodHandleNatives.<clinit>. Cascade the <clinit> calls as needed:
MethodHandleImpl.initStatics();
}
// All compile-time constants go here.
// There is an opportunity to check them against the JVM's idea of them.
/**
* Compile-time constants go here. This collection exists not only for
* reference from clients, but also for ensuring the VM and JDK agree on the
* values of these constants (see {@link #verifyConstants()}).
*/
static class Constants {
Constants() { } // static only
// MethodHandleImpl
static final int // for getConstant
GC_COUNT_GWT = 4,
GC_LAMBDA_SUPPORT = 5;
// MemberName
// The JVM uses values of -2 and above for vtable indexes.
// Field values are simple positive offsets.
// Ref: src/share/vm/oops/methodOop.hpp
// This value is negative enough to avoid such numbers,
// but not too negative.
static final int
MN_IS_METHOD = 0x00010000, // method (not constructor)
MN_IS_CONSTRUCTOR = 0x00020000, // constructor
MN_IS_FIELD = 0x00040000, // field
MN_IS_TYPE = 0x00080000, // nested type
MN_CALLER_SENSITIVE = 0x00100000, // @CallerSensitive annotation detected
MN_REFERENCE_KIND_SHIFT = 24, // refKind
MN_REFERENCE_KIND_MASK = 0x0F000000 >> MN_REFERENCE_KIND_SHIFT,
// The SEARCH_* bits are not for MN.flags but for the matchFlags argument of MHN.getMembers:
MN_SEARCH_SUPERCLASSES = 0x00100000,
MN_SEARCH_INTERFACES = 0x00200000;
/**
* Basic types as encoded in the JVM. These code values are not
* intended for use outside this class. They are used as part of
* a private interface between the JVM and this class.
*/
static final int
T_BOOLEAN = 4,
T_CHAR = 5,
T_FLOAT = 6,
T_DOUBLE = 7,
T_BYTE = 8,
T_SHORT = 9,
T_INT = 10,
T_LONG = 11,
T_OBJECT = 12,
//T_ARRAY = 13
T_VOID = 14,
//T_ADDRESS = 15
T_ILLEGAL = 99;
/**
* Constant pool entry types.
*/
static final byte
CONSTANT_Utf8 = 1,
CONSTANT_Integer = 3,
CONSTANT_Float = 4,
CONSTANT_Long = 5,
CONSTANT_Double = 6,
CONSTANT_Class = 7,
CONSTANT_String = 8,
CONSTANT_Fieldref = 9,
CONSTANT_Methodref = 10,
CONSTANT_InterfaceMethodref = 11,
CONSTANT_NameAndType = 12,
CONSTANT_MethodHandle = 15, // JSR 292
CONSTANT_MethodType = 16, // JSR 292
CONSTANT_InvokeDynamic = 18,
CONSTANT_LIMIT = 19; // Limit to tags found in classfiles
/**
* Access modifier flags.
*/
static final char
ACC_PUBLIC = 0x0001,
ACC_PRIVATE = 0x0002,
ACC_PROTECTED = 0x0004,
ACC_STATIC = 0x0008,
ACC_FINAL = 0x0010,
ACC_SYNCHRONIZED = 0x0020,
ACC_VOLATILE = 0x0040,
ACC_TRANSIENT = 0x0080,
ACC_NATIVE = 0x0100,
ACC_INTERFACE = 0x0200,
ACC_ABSTRACT = 0x0400,
ACC_STRICT = 0x0800,
ACC_SYNTHETIC = 0x1000,
ACC_ANNOTATION = 0x2000,
ACC_ENUM = 0x4000,
// aliases:
ACC_SUPER = ACC_SYNCHRONIZED,
ACC_BRIDGE = ACC_VOLATILE,
ACC_VARARGS = ACC_TRANSIENT;
MN_IS_METHOD = 0x00010000, // method (not constructor)
MN_IS_CONSTRUCTOR = 0x00020000, // constructor
MN_IS_FIELD = 0x00040000, // field
MN_IS_TYPE = 0x00080000, // nested type
MN_CALLER_SENSITIVE = 0x00100000, // @CallerSensitive annotation detected
MN_REFERENCE_KIND_SHIFT = 24, // refKind
MN_REFERENCE_KIND_MASK = 0x0F000000 >> MN_REFERENCE_KIND_SHIFT,
// The SEARCH_* bits are not for MN.flags but for the matchFlags argument of MHN.getMembers:
MN_SEARCH_SUPERCLASSES = 0x00100000,
MN_SEARCH_INTERFACES = 0x00200000;
/**
* Constant pool reference-kind codes, as used by CONSTANT_MethodHandle CP entries.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2015, 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
@ -567,32 +567,13 @@ class Bits { // package-private
// -- Processor and memory-system properties --
private static final ByteOrder byteOrder;
private static final ByteOrder byteOrder
= unsafe.isBigEndian() ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN;
static ByteOrder byteOrder() {
if (byteOrder == null)
throw new Error("Unknown byte order");
return byteOrder;
}
static {
long a = unsafe.allocateMemory(8);
try {
unsafe.putLong(a, 0x0102030405060708L);
byte b = unsafe.getByte(a);
switch (b) {
case 0x01: byteOrder = ByteOrder.BIG_ENDIAN; break;
case 0x08: byteOrder = ByteOrder.LITTLE_ENDIAN; break;
default:
assert false;
byteOrder = null;
}
} finally {
unsafe.freeMemory(a);
}
}
private static int pageSize = -1;
static int pageSize() {
@ -605,17 +586,9 @@ class Bits { // package-private
return (int)(size + (long)pageSize() - 1L) / pageSize();
}
private static boolean unaligned;
private static boolean unalignedKnown = false;
private static boolean unaligned = unsafe.unalignedAccess();
static boolean unaligned() {
if (unalignedKnown)
return unaligned;
String arch = AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("os.arch"));
unaligned = arch.equals("i386") || arch.equals("x86")
|| arch.equals("amd64") || arch.equals("x86_64");
unalignedKnown = true;
return unaligned;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2015, 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
@ -27,6 +27,7 @@
package java.nio;
import sun.misc.Unsafe;
/**
#if[rw]
@ -52,6 +53,16 @@ class Heap$Type$Buffer$RW$
#end[rw]
*/
#if[byte]
// Cached unsafe-access object
private static final Unsafe unsafe = Bits.unsafe();
// Cached array base offset
private static final long arrayBaseOffset = unsafe.arrayBaseOffset($type$[].class);
#end[byte]
Heap$Type$Buffer$RW$(int cap, int lim) { // package-private
#if[rw]
super(-1, 0, lim, cap, new $type$[cap], 0);
@ -131,6 +142,12 @@ class Heap$Type$Buffer$RW$
return i + offset;
}
#if[byte]
private long byteOffset(long i) {
return arrayBaseOffset + i + offset;
}
#end[byte]
public $type$ get() {
return hb[ix(nextGetIndex())];
}
@ -256,18 +273,18 @@ class Heap$Type$Buffer$RW$
#if[rw]
public char getChar() {
return Bits.getChar(this, ix(nextGetIndex(2)), bigEndian);
return unsafe.getCharUnaligned(hb, byteOffset(nextGetIndex(2)), bigEndian);
}
public char getChar(int i) {
return Bits.getChar(this, ix(checkIndex(i, 2)), bigEndian);
return unsafe.getCharUnaligned(hb, byteOffset(checkIndex(i, 2)), bigEndian);
}
#end[rw]
public $Type$Buffer putChar(char x) {
#if[rw]
Bits.putChar(this, ix(nextPutIndex(2)), x, bigEndian);
unsafe.putCharUnaligned(hb, byteOffset(nextPutIndex(2)), x, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -276,7 +293,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putChar(int i, char x) {
#if[rw]
Bits.putChar(this, ix(checkIndex(i, 2)), x, bigEndian);
unsafe.putCharUnaligned(hb, byteOffset(checkIndex(i, 2)), x, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -307,18 +324,18 @@ class Heap$Type$Buffer$RW$
#if[rw]
public short getShort() {
return Bits.getShort(this, ix(nextGetIndex(2)), bigEndian);
return unsafe.getShortUnaligned(hb, byteOffset(nextGetIndex(2)), bigEndian);
}
public short getShort(int i) {
return Bits.getShort(this, ix(checkIndex(i, 2)), bigEndian);
return unsafe.getShortUnaligned(hb, byteOffset(checkIndex(i, 2)), bigEndian);
}
#end[rw]
public $Type$Buffer putShort(short x) {
#if[rw]
Bits.putShort(this, ix(nextPutIndex(2)), x, bigEndian);
unsafe.putShortUnaligned(hb, byteOffset(nextPutIndex(2)), x, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -327,7 +344,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putShort(int i, short x) {
#if[rw]
Bits.putShort(this, ix(checkIndex(i, 2)), x, bigEndian);
unsafe.putShortUnaligned(hb, byteOffset(checkIndex(i, 2)), x, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -358,18 +375,18 @@ class Heap$Type$Buffer$RW$
#if[rw]
public int getInt() {
return Bits.getInt(this, ix(nextGetIndex(4)), bigEndian);
return unsafe.getIntUnaligned(hb, byteOffset(nextGetIndex(4)), bigEndian);
}
public int getInt(int i) {
return Bits.getInt(this, ix(checkIndex(i, 4)), bigEndian);
return unsafe.getIntUnaligned(hb, byteOffset(checkIndex(i, 4)), bigEndian);
}
#end[rw]
public $Type$Buffer putInt(int x) {
#if[rw]
Bits.putInt(this, ix(nextPutIndex(4)), x, bigEndian);
unsafe.putIntUnaligned(hb, byteOffset(nextPutIndex(4)), x, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -378,7 +395,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putInt(int i, int x) {
#if[rw]
Bits.putInt(this, ix(checkIndex(i, 4)), x, bigEndian);
unsafe.putIntUnaligned(hb, byteOffset(checkIndex(i, 4)), x, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -409,18 +426,18 @@ class Heap$Type$Buffer$RW$
#if[rw]
public long getLong() {
return Bits.getLong(this, ix(nextGetIndex(8)), bigEndian);
return unsafe.getLongUnaligned(hb, byteOffset(nextGetIndex(8)), bigEndian);
}
public long getLong(int i) {
return Bits.getLong(this, ix(checkIndex(i, 8)), bigEndian);
return unsafe.getLongUnaligned(hb, byteOffset(checkIndex(i, 8)), bigEndian);
}
#end[rw]
public $Type$Buffer putLong(long x) {
#if[rw]
Bits.putLong(this, ix(nextPutIndex(8)), x, bigEndian);
unsafe.putLongUnaligned(hb, byteOffset(nextPutIndex(8)), x, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -429,7 +446,7 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putLong(int i, long x) {
#if[rw]
Bits.putLong(this, ix(checkIndex(i, 8)), x, bigEndian);
unsafe.putLongUnaligned(hb, byteOffset(checkIndex(i, 8)), x, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -460,18 +477,21 @@ class Heap$Type$Buffer$RW$
#if[rw]
public float getFloat() {
return Bits.getFloat(this, ix(nextGetIndex(4)), bigEndian);
int x = unsafe.getIntUnaligned(hb, byteOffset(nextPutIndex(4)), bigEndian);
return Float.intBitsToFloat(x);
}
public float getFloat(int i) {
return Bits.getFloat(this, ix(checkIndex(i, 4)), bigEndian);
int x = unsafe.getIntUnaligned(hb, byteOffset(checkIndex(i, 4)), bigEndian);
return Float.intBitsToFloat(x);
}
#end[rw]
public $Type$Buffer putFloat(float x) {
#if[rw]
Bits.putFloat(this, ix(nextPutIndex(4)), x, bigEndian);
int y = Float.floatToRawIntBits(x);
unsafe.putIntUnaligned(hb, byteOffset(nextPutIndex(4)), y, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -480,7 +500,8 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putFloat(int i, float x) {
#if[rw]
Bits.putFloat(this, ix(checkIndex(i, 4)), x, bigEndian);
int y = Float.floatToRawIntBits(x);
unsafe.putIntUnaligned(hb, byteOffset(checkIndex(i, 4)), y, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -511,18 +532,21 @@ class Heap$Type$Buffer$RW$
#if[rw]
public double getDouble() {
return Bits.getDouble(this, ix(nextGetIndex(8)), bigEndian);
long x = unsafe.getLongUnaligned(hb, byteOffset(nextGetIndex(8)), bigEndian);
return Double.longBitsToDouble(x);
}
public double getDouble(int i) {
return Bits.getDouble(this, ix(checkIndex(i, 8)), bigEndian);
long x = unsafe.getLongUnaligned(hb, byteOffset(checkIndex(i, 8)), bigEndian);
return Double.longBitsToDouble(x);
}
#end[rw]
public $Type$Buffer putDouble(double x) {
#if[rw]
Bits.putDouble(this, ix(nextPutIndex(8)), x, bigEndian);
long y = Double.doubleToRawLongBits(x);
unsafe.putLongUnaligned(hb, byteOffset(nextPutIndex(8)), y, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();
@ -531,7 +555,8 @@ class Heap$Type$Buffer$RW$
public $Type$Buffer putDouble(int i, double x) {
#if[rw]
Bits.putDouble(this, ix(checkIndex(i, 8)), x, bigEndian);
long y = Double.doubleToRawLongBits(x);
unsafe.putLongUnaligned(hb, byteOffset(checkIndex(i, 8)), y, bigEndian);
return this;
#else[rw]
throw new ReadOnlyBufferException();

View File

@ -934,4 +934,347 @@ public final class Unsafe {
private static void throwIllegalAccessError() {
throw new IllegalAccessError();
}
/**
* @return Returns true if the native byte ordering of this
* platform is big-endian, false if it is little-endian.
*/
public final boolean isBigEndian() { return BE; }
/**
* @return Returns true if this platform is capable of performing
* accesses at addresses which are not aligned for the type of the
* primitive type being accessed, false otherwise.
*/
public final boolean unalignedAccess() { return unalignedAccess; }
/**
* Fetches a value at some byte offset into a given Java object.
* More specifically, fetches a value within the given object
* <code>o</code> at the given offset, or (if <code>o</code> is
* null) from the memory address whose numerical value is the
* given offset. <p>
*
* The specification of this method is the same as {@link
* #getLong(Object, long)} except that the offset does not need to
* have been obtained from {@link #objectFieldOffset} on the
* {@link java.lang.reflect.Field} of some Java field. The value
* in memory is raw data, and need not correspond to any Java
* variable. Unless <code>o</code> is null, the value accessed
* must be entirely within the allocated object. The endianness
* of the value in memory is the endianness of the native platform.
*
* <p> The read will be atomic with respect to the largest power
* of two that divides the GCD of the offset and the storage size.
* For example, getLongUnaligned will make atomic reads of 2-, 4-,
* or 8-byte storage units if the offset is zero mod 2, 4, or 8,
* respectively. There are no other guarantees of atomicity.
* <p>
* 8-byte atomicity is only guaranteed on platforms on which
* support atomic accesses to longs.
*
* @param o Java heap object in which the value resides, if any, else
* null
* @param offset The offset in bytes from the start of the object
* @return the value fetched from the indicated object
* @throws RuntimeException No defined exceptions are thrown, not even
* {@link NullPointerException}
* @since 1.9
*/
public final long getLongUnaligned(Object o, long offset) {
if ((offset & 7) == 0) {
return getLong(o, offset);
} else if ((offset & 3) == 0) {
return makeLong(getInt(o, offset),
getInt(o, offset + 4));
} else if ((offset & 1) == 0) {
return makeLong(getShort(o, offset),
getShort(o, offset + 2),
getShort(o, offset + 4),
getShort(o, offset + 6));
} else {
return makeLong(getByte(o, offset),
getByte(o, offset + 1),
getByte(o, offset + 2),
getByte(o, offset + 3),
getByte(o, offset + 4),
getByte(o, offset + 5),
getByte(o, offset + 6),
getByte(o, offset + 7));
}
}
/**
* As {@link #getLongUnaligned(Object, long)} but with an
* additional argument which specifies the endianness of the value
* as stored in memory.
*
* @param o Java heap object in which the variable resides
* @param offset The offset in bytes from the start of the object
* @param bigEndian The endianness of the value
* @return the value fetched from the indicated object
* @since 1.9
*/
public final long getLongUnaligned(Object o, long offset, boolean bigEndian) {
return convEndian(bigEndian, getLongUnaligned(o, offset));
}
/** @see #getLongUnaligned(Object, long) */
public final int getIntUnaligned(Object o, long offset) {
if ((offset & 3) == 0) {
return getInt(o, offset);
} else if ((offset & 1) == 0) {
return makeInt(getShort(o, offset),
getShort(o, offset + 2));
} else {
return makeInt(getByte(o, offset),
getByte(o, offset + 1),
getByte(o, offset + 2),
getByte(o, offset + 3));
}
}
/** @see #getLongUnaligned(Object, long, boolean) */
public final int getIntUnaligned(Object o, long offset, boolean bigEndian) {
return convEndian(bigEndian, getIntUnaligned(o, offset));
}
/** @see #getLongUnaligned(Object, long) */
public final short getShortUnaligned(Object o, long offset) {
if ((offset & 1) == 0) {
return getShort(o, offset);
} else {
return makeShort(getByte(o, offset),
getByte(o, offset + 1));
}
}
/** @see #getLongUnaligned(Object, long, boolean) */
public final short getShortUnaligned(Object o, long offset, boolean bigEndian) {
return convEndian(bigEndian, getShortUnaligned(o, offset));
}
/** @see #getLongUnaligned(Object, long) */
public final char getCharUnaligned(Object o, long offset) {
return (char)getShortUnaligned(o, offset);
}
/** @see #getLongUnaligned(Object, long, boolean) */
public final char getCharUnaligned(Object o, long offset, boolean bigEndian) {
return convEndian(bigEndian, getCharUnaligned(o, offset));
}
/**
* Stores a value at some byte offset into a given Java object.
* <p>
* The specification of this method is the same as {@link
* #getLong(Object, long)} except that the offset does not need to
* have been obtained from {@link #objectFieldOffset} on the
* {@link java.lang.reflect.Field} of some Java field. The value
* in memory is raw data, and need not correspond to any Java
* variable. The endianness of the value in memory is the
* endianness of the native platform.
* <p>
* The write will be atomic with respect to the largest power of
* two that divides the GCD of the offset and the storage size.
* For example, putLongUnaligned will make atomic writes of 2-, 4-,
* or 8-byte storage units if the offset is zero mod 2, 4, or 8,
* respectively. There are no other guarantees of atomicity.
* <p>
* 8-byte atomicity is only guaranteed on platforms on which
* support atomic accesses to longs.
* <p>
*
* @param o Java heap object in which the value resides, if any, else
* null
* @param offset The offset in bytes from the start of the object
* @param x the value to store
* @throws RuntimeException No defined exceptions are thrown, not even
* {@link NullPointerException}
* @since 1.9
*/
public final void putLongUnaligned(Object o, long offset, long x) {
if ((offset & 7) == 0) {
putLong(o, offset, x);
} else if ((offset & 3) == 0) {
putLongParts(o, offset,
(int)(x >> 0),
(int)(x >>> 32));
} else if ((offset & 1) == 0) {
putLongParts(o, offset,
(short)(x >>> 0),
(short)(x >>> 16),
(short)(x >>> 32),
(short)(x >>> 48));
} else {
putLongParts(o, offset,
(byte)(x >>> 0),
(byte)(x >>> 8),
(byte)(x >>> 16),
(byte)(x >>> 24),
(byte)(x >>> 32),
(byte)(x >>> 40),
(byte)(x >>> 48),
(byte)(x >>> 56));
}
}
/**
* As {@link #putLongUnaligned(Object, long, long)} but with an additional
* argument which specifies the endianness of the value as stored in memory.
* @param o Java heap object in which the value resides
* @param offset The offset in bytes from the start of the object
* @param x the value to store
* @param bigEndian The endianness of the value
* @throws RuntimeException No defined exceptions are thrown, not even
* {@link NullPointerException}
* @since 1.9
*/
public final void putLongUnaligned(Object o, long offset, long x, boolean bigEndian) {
putLongUnaligned(o, offset, convEndian(bigEndian, x));
}
/** @see #putLongUnaligned(Object, long, long) */
public final void putIntUnaligned(Object o, long offset, int x) {
if ((offset & 3) == 0) {
putInt(o, offset, x);
} else if ((offset & 1) == 0) {
putIntParts(o, offset,
(short)(x >> 0),
(short)(x >>> 16));
} else {
putIntParts(o, offset,
(byte)(x >>> 0),
(byte)(x >>> 8),
(byte)(x >>> 16),
(byte)(x >>> 24));
}
}
/** @see #putLongUnaligned(Object, long, long, boolean) */
public final void putIntUnaligned(Object o, long offset, int x, boolean bigEndian) {
putIntUnaligned(o, offset, convEndian(bigEndian, x));
}
/** @see #putLongUnaligned(Object, long, long) */
public final void putShortUnaligned(Object o, long offset, short x) {
if ((offset & 1) == 0) {
putShort(o, offset, x);
} else {
putShortParts(o, offset,
(byte)(x >>> 0),
(byte)(x >>> 8));
}
}
/** @see #putLongUnaligned(Object, long, long, boolean) */
public final void putShortUnaligned(Object o, long offset, short x, boolean bigEndian) {
putShortUnaligned(o, offset, convEndian(bigEndian, x));
}
/** @see #putLongUnaligned(Object, long, long) */
public final void putCharUnaligned(Object o, long offset, char x) {
putShortUnaligned(o, offset, (short)x);
}
/** @see #putLongUnaligned(Object, long, long, boolean) */
public final void putCharUnaligned(Object o, long offset, char x, boolean bigEndian) {
putCharUnaligned(o, offset, convEndian(bigEndian, x));
}
// JVM interface methods
private native boolean unalignedAccess0();
private native boolean isBigEndian0();
// BE is true iff the native endianness of this platform is big.
private static final boolean BE = theUnsafe.isBigEndian0();
// unalignedAccess is true iff this platform can perform unaligned accesses.
private static final boolean unalignedAccess = theUnsafe.unalignedAccess0();
private static int pickPos(int top, int pos) { return BE ? top - pos : pos; }
// These methods construct integers from bytes. The byte ordering
// is the native endianness of this platform.
private static long makeLong(byte i0, byte i1, byte i2, byte i3, byte i4, byte i5, byte i6, byte i7) {
return ((toUnsignedLong(i0) << pickPos(56, 0))
| (toUnsignedLong(i1) << pickPos(56, 8))
| (toUnsignedLong(i2) << pickPos(56, 16))
| (toUnsignedLong(i3) << pickPos(56, 24))
| (toUnsignedLong(i4) << pickPos(56, 32))
| (toUnsignedLong(i5) << pickPos(56, 40))
| (toUnsignedLong(i6) << pickPos(56, 48))
| (toUnsignedLong(i7) << pickPos(56, 56)));
}
private static long makeLong(short i0, short i1, short i2, short i3) {
return ((toUnsignedLong(i0) << pickPos(48, 0))
| (toUnsignedLong(i1) << pickPos(48, 16))
| (toUnsignedLong(i2) << pickPos(48, 32))
| (toUnsignedLong(i3) << pickPos(48, 48)));
}
private static long makeLong(int i0, int i1) {
return (toUnsignedLong(i0) << pickPos(32, 0))
| (toUnsignedLong(i1) << pickPos(32, 32));
}
private static int makeInt(short i0, short i1) {
return (toUnsignedInt(i0) << pickPos(16, 0))
| (toUnsignedInt(i1) << pickPos(16, 16));
}
private static int makeInt(byte i0, byte i1, byte i2, byte i3) {
return ((toUnsignedInt(i0) << pickPos(24, 0))
| (toUnsignedInt(i1) << pickPos(24, 8))
| (toUnsignedInt(i2) << pickPos(24, 16))
| (toUnsignedInt(i3) << pickPos(24, 24)));
}
private static short makeShort(byte i0, byte i1) {
return (short)((toUnsignedInt(i0) << pickPos(8, 0))
| (toUnsignedInt(i1) << pickPos(8, 8)));
}
private static byte pick(byte le, byte be) { return BE ? be : le; }
private static short pick(short le, short be) { return BE ? be : le; }
private static int pick(int le, int be) { return BE ? be : le; }
// These methods write integers to memory from smaller parts
// provided by their caller. The ordering in which these parts
// are written is the native endianness of this platform.
private void putLongParts(Object o, long offset, byte i0, byte i1, byte i2, byte i3, byte i4, byte i5, byte i6, byte i7) {
putByte(o, offset + 0, pick(i0, i7));
putByte(o, offset + 1, pick(i1, i6));
putByte(o, offset + 2, pick(i2, i5));
putByte(o, offset + 3, pick(i3, i4));
putByte(o, offset + 4, pick(i4, i3));
putByte(o, offset + 5, pick(i5, i2));
putByte(o, offset + 6, pick(i6, i1));
putByte(o, offset + 7, pick(i7, i0));
}
private void putLongParts(Object o, long offset, short i0, short i1, short i2, short i3) {
putShort(o, offset + 0, pick(i0, i3));
putShort(o, offset + 2, pick(i1, i2));
putShort(o, offset + 4, pick(i2, i1));
putShort(o, offset + 6, pick(i3, i0));
}
private void putLongParts(Object o, long offset, int i0, int i1) {
putInt(o, offset + 0, pick(i0, i1));
putInt(o, offset + 4, pick(i1, i0));
}
private void putIntParts(Object o, long offset, short i0, short i1) {
putShort(o, offset + 0, pick(i0, i1));
putShort(o, offset + 2, pick(i1, i0));
}
private void putIntParts(Object o, long offset, byte i0, byte i1, byte i2, byte i3) {
putByte(o, offset + 0, pick(i0, i3));
putByte(o, offset + 1, pick(i1, i2));
putByte(o, offset + 2, pick(i2, i1));
putByte(o, offset + 3, pick(i3, i0));
}
private void putShortParts(Object o, long offset, byte i0, byte i1) {
putByte(o, offset + 0, pick(i0, i1));
putByte(o, offset + 1, pick(i1, i0));
}
// Zero-extend an integer
private static int toUnsignedInt(byte n) { return n & 0xff; }
private static int toUnsignedInt(short n) { return n & 0xffff; }
private static long toUnsignedLong(byte n) { return n & 0xffl; }
private static long toUnsignedLong(short n) { return n & 0xffffl; }
private static long toUnsignedLong(int n) { return n & 0xffffffffl; }
// Maybe byte-reverse an integer
private static char convEndian(boolean big, char n) { return big == BE ? n : Character.reverseBytes(n); }
private static short convEndian(boolean big, short n) { return big == BE ? n : Short.reverseBytes(n) ; }
private static int convEndian(boolean big, int n) { return big == BE ? n : Integer.reverseBytes(n) ; }
private static long convEndian(boolean big, long n) { return big == BE ? n : Long.reverseBytes(n) ; }
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2006, 2015, 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
@ -88,13 +88,8 @@ final class ByteArrayAccess {
// Return whether this platform supports full speed int/long memory access
// at unaligned addresses.
// This code was copied from java.nio.Bits because there is no equivalent
// public API.
private static boolean unaligned() {
String arch = java.security.AccessController.doPrivileged
(new sun.security.action.GetPropertyAction("os.arch", ""));
return arch.equals("i386") || arch.equals("x86") || arch.equals("amd64")
|| arch.equals("x86_64");
return unsafe.unalignedAccess();
}
/**

View File

@ -395,6 +395,9 @@ JVM_GetDeclaredClasses(JNIEnv *env, jclass ofClass);
JNIEXPORT jclass JNICALL
JVM_GetDeclaringClass(JNIEnv *env, jclass ofClass);
JNIEXPORT jstring JNICALL
JVM_GetSimpleBinaryName(JNIEnv *env, jclass ofClass);
/* Generics support (JDK 1.5) */
JNIEXPORT jstring JNICALL
JVM_GetClassSignature(JNIEnv *env, jclass cls);

View File

@ -67,6 +67,7 @@ static JNINativeMethod methods[] = {
{"getProtectionDomain0", "()" PD, (void *)&JVM_GetProtectionDomain},
{"getDeclaredClasses0", "()[" CLS, (void *)&JVM_GetDeclaredClasses},
{"getDeclaringClass0", "()" CLS, (void *)&JVM_GetDeclaringClass},
{"getSimpleBinaryName0", "()" STR, (void *)&JVM_GetSimpleBinaryName},
{"getGenericSignature0", "()" STR, (void *)&JVM_GetClassSignature},
{"getRawAnnotations", "()" BA, (void *)&JVM_GetClassAnnotations},
{"getConstantPool", "()" CPL, (void *)&JVM_GetClassConstantPool},

View File

@ -0,0 +1,207 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/* @test
* @bug 8057919
* @summary Class.getSimpleName() should work for non-JLS compliant class names
*/
import jdk.internal.org.objectweb.asm.*;
import static jdk.internal.org.objectweb.asm.Opcodes.*;
public class GetSimpleNameTest {
static class NestedClass {}
class InnerClass {}
static Class<?> f1() {
class LocalClass {}
return LocalClass.class;
}
public static void main(String[] args) throws Exception {
assertEquals(NestedClass.class.getSimpleName(), "NestedClass");
assertEquals( InnerClass.class.getSimpleName(), "InnerClass");
assertEquals( f1().getSimpleName(), "LocalClass");
java.io.Serializable anon = new java.io.Serializable() {};
assertEquals(anon.getClass().getSimpleName(), "");
// Java class names, prepended enclosing class name.
testNested("p.Outer$Nested", "p.Outer", "Nested");
testInner( "p.Outer$Inner", "p.Inner", "Inner");
testLocal( "p.Outer$1Local", "p.Outer", "Local");
testAnon( "p.Outer$1", "p.Outer", "");
// Non-Java class names, prepended enclosing class name.
testNested("p.$C1$Nested", "p.$C1$", "Nested");
testInner( "p.$C1$Inner", "p.$C1$", "Inner");
testLocal( "p.$C1$Local", "p.$C1$", "Local");
testAnon( "p.$C1$1", "p.$C1$", "");
// Non-Java class names, unrelated class names.
testNested("p1.$Nested$", "p2.$C1$", "Nested");
testInner( "p1.$Inner$", "p2.$C1$", "Inner");
testLocal( "p1.$Local$", "p2.$C1$", "Local");
testAnon( "p1.$anon$", "p2.$C1$", "");
}
static void testNested(String innerName, String outerName, String simpleName) throws Exception {
BytecodeGenerator bg = new BytecodeGenerator(innerName, outerName, simpleName);
CustomCL cl = new CustomCL(innerName, outerName, bg.getNestedClasses(true), bg.getNestedClasses(false));
assertEquals(cl.loadClass(innerName).getSimpleName(), simpleName);
}
static void testInner(String innerName, String outerName, String simpleName) throws Exception {
BytecodeGenerator bg = new BytecodeGenerator(innerName, outerName, simpleName);
CustomCL cl = new CustomCL(innerName, outerName, bg.getInnerClasses(true), bg.getInnerClasses(false));
assertEquals(cl.loadClass(innerName).getSimpleName(), simpleName);
}
static void testLocal(String innerName, String outerName, String simpleName) throws Exception {
BytecodeGenerator bg = new BytecodeGenerator(innerName, outerName, simpleName);
CustomCL cl = new CustomCL(innerName, outerName, bg.getLocalClasses(true), bg.getLocalClasses(false));
assertEquals(cl.loadClass(innerName).getSimpleName(), simpleName);
}
static void testAnon(String innerName, String outerName, String simpleName) throws Exception {
BytecodeGenerator bg = new BytecodeGenerator(innerName, outerName, simpleName);
CustomCL cl = new CustomCL(innerName, outerName, bg.getAnonymousClasses(true), bg.getAnonymousClasses(false));
assertEquals(cl.loadClass(innerName).getSimpleName(), simpleName);
}
static void assertEquals(Object o1, Object o2) {
if (!java.util.Objects.equals(o1, o2)) {
throw new AssertionError(o1 + " != " + o2);
}
}
static class CustomCL extends ClassLoader {
final String innerName;
final String outerName;
final byte[] innerClassFile;
final byte[] outerClassFile;
CustomCL(String innerName, String outerName, byte[] innerClassFile, byte[] outerClassFile) {
this.innerName = innerName;
this.outerName = outerName;
this.innerClassFile = innerClassFile;
this.outerClassFile = outerClassFile;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
if (innerName.equals(name)) {
return defineClass(innerName, innerClassFile, 0, innerClassFile.length);
} else if (outerName.equals(name)) {
return defineClass(outerName, outerClassFile, 0, outerClassFile.length);
} else {
throw new ClassNotFoundException(name);
}
}
}
static class BytecodeGenerator {
final String innerName;
final String outerName;
final String simpleName;
BytecodeGenerator(String innerName, String outerName, String simpleName) {
this.innerName = intl(innerName);
this.outerName = intl(outerName);
this.simpleName = simpleName;
}
static String intl(String name) { return name.replace('.', '/'); }
static void makeDefaultCtor(ClassWriter cw) {
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
mv.visitInsn(RETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
}
void makeCtxk(ClassWriter cw, boolean isInner) {
if (isInner) {
cw.visitOuterClass(outerName, "f", "()V");
} else {
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "f", "()V", null, null);
mv.visitCode();
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
}
byte[] getNestedClasses(boolean isInner) {
String name = (isInner ? innerName : outerName);
ClassWriter cw = new ClassWriter(0);
cw.visit(V1_7, ACC_PUBLIC + ACC_SUPER, name, null, "java/lang/Object", null);
cw.visitInnerClass(innerName, outerName, simpleName, ACC_PUBLIC | ACC_STATIC);
makeDefaultCtor(cw);
cw.visitEnd();
return cw.toByteArray();
}
byte[] getInnerClasses(boolean isInner) {
String name = (isInner ? innerName : outerName);
ClassWriter cw = new ClassWriter(0);
cw.visit(V1_7, ACC_PUBLIC + ACC_SUPER, name, null, "java/lang/Object", null);
cw.visitInnerClass(innerName, outerName, simpleName, ACC_PUBLIC);
makeDefaultCtor(cw);
cw.visitEnd();
return cw.toByteArray();
}
byte[] getLocalClasses(boolean isInner) {
String name = (isInner ? innerName : outerName);
ClassWriter cw = new ClassWriter(0);
cw.visit(V1_7, ACC_PUBLIC + ACC_SUPER, name, null, "java/lang/Object", null);
cw.visitInnerClass(innerName, null, simpleName, ACC_PUBLIC | ACC_STATIC);
makeCtxk(cw, isInner);
makeDefaultCtor(cw);
cw.visitEnd();
return cw.toByteArray();
}
byte[] getAnonymousClasses(boolean isInner) {
String name = (isInner ? innerName : outerName);
ClassWriter cw = new ClassWriter(0);
cw.visit(V1_7, ACC_PUBLIC + ACC_SUPER, name, null, "java/lang/Object", null);
cw.visitInnerClass(innerName, null, null, ACC_PUBLIC | ACC_STATIC);
makeCtxk(cw, isInner);
makeDefaultCtor(cw);
cw.visitEnd();
return cw.toByteArray();
}
}
}