# HG changeset patch # User ccheung # Date 1429306664 25200 # Node ID a56e57aad51f8df66ce0c41c40b90463d73e6060 # Parent e37c7eba132fb18518fd779d6b09c30c7c9205a2# Parent a0bacb211630a943f390ed2c889ed7e6f07e157a Merge diff -r e37c7eba132f -r a56e57aad51f jdk/src/java.base/share/classes/com/sun/crypto/provider/GCTR.java --- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/GCTR.java Fri Apr 17 09:40:02 2015 +0200 +++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/GCTR.java Fri Apr 17 14:37:44 2015 -0700 @@ -38,7 +38,17 @@ * 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). * *

This function is used in the implementation of GCM mode. * @@ -59,6 +69,10 @@ // 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 @@ * 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; + } } } diff -r e37c7eba132f -r a56e57aad51f jdk/src/java.base/share/classes/java/lang/Class.java --- a/jdk/src/java.base/share/classes/java/lang/Class.java Fri Apr 17 09:40:02 2015 +0200 +++ b/jdk/src/java.base/share/classes/java/lang/Class.java Fri Apr 17 14:37:44 2015 -0700 @@ -1312,7 +1312,7 @@ // 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 @@ 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 @@ 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; diff -r e37c7eba132f -r a56e57aad51f jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java --- a/jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java Fri Apr 17 09:40:02 2015 +0200 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java Fri Apr 17 14:37:44 2015 -0700 @@ -691,10 +691,4 @@ } } } - - @Override - void customize() { - assert(form.customized == null); - // No need to customize DMHs. - } } diff -r e37c7eba132f -r a56e57aad51f jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java --- a/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Fri Apr 17 09:40:02 2015 +0200 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java Fri Apr 17 14:37:44 2015 -0700 @@ -847,11 +847,7 @@ 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); diff -r e37c7eba132f -r a56e57aad51f jdk/src/java.base/share/classes/java/lang/invoke/Invokers.java --- a/jdk/src/java.base/share/classes/java/lang/invoke/Invokers.java Fri Apr 17 09:40:02 2015 +0200 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/Invokers.java Fri Apr 17 14:37:44 2015 -0700 @@ -394,6 +394,7 @@ @ForceInline void checkCustomized(Object o) { MethodHandle mh = (MethodHandle)o; + if (MethodHandleImpl.isCompileConstant(mh)) return; if (mh.form.customized == null) { maybeCustomize(mh); } diff -r e37c7eba132f -r a56e57aad51f jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Fri Apr 17 09:40:02 2015 +0200 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java Fri Apr 17 14:37:44 2015 -0700 @@ -722,6 +722,13 @@ 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, diff -r e37c7eba132f -r a56e57aad51f jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java --- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java Fri Apr 17 09:40:02 2015 +0200 +++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java Fri Apr 17 14:37:44 2015 -0700 @@ -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 @@ 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 @@ private static native void registerNatives(); static { registerNatives(); - COUNT_GWT = getConstant(Constants.GC_COUNT_GWT) != 0; // The JVM calls MethodHandleNatives.. Cascade the 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. diff -r e37c7eba132f -r a56e57aad51f jdk/src/java.base/share/classes/java/nio/Bits.java --- a/jdk/src/java.base/share/classes/java/nio/Bits.java Fri Apr 17 09:40:02 2015 +0200 +++ b/jdk/src/java.base/share/classes/java/nio/Bits.java Fri Apr 17 14:37:44 2015 -0700 @@ -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 @@ // -- 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 @@ 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; } diff -r e37c7eba132f -r a56e57aad51f jdk/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template --- a/jdk/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template Fri Apr 17 09:40:02 2015 +0200 +++ b/jdk/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template Fri Apr 17 14:37:44 2015 -0700 @@ -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 @@ #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 @@ 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 @@ #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 @@ 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 @@ #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 @@ 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 @@ #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 @@ 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 @@ #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 @@ 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 @@ #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 @@ 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 @@ #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 @@ 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(); diff -r e37c7eba132f -r a56e57aad51f jdk/src/java.base/share/classes/sun/misc/Unsafe.java --- a/jdk/src/java.base/share/classes/sun/misc/Unsafe.java Fri Apr 17 09:40:02 2015 +0200 +++ b/jdk/src/java.base/share/classes/sun/misc/Unsafe.java Fri Apr 17 14:37:44 2015 -0700 @@ -934,4 +934,347 @@ 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 + * o at the given offset, or (if o is + * null) from the memory address whose numerical value is the + * given offset.

+ * + * 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 o 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. + * + *

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. + *

+ * 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. + *

+ * 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. + *

+ * 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. + *

+ * 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 + * @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) ; } } diff -r e37c7eba132f -r a56e57aad51f jdk/src/java.base/share/classes/sun/security/provider/ByteArrayAccess.java --- a/jdk/src/java.base/share/classes/sun/security/provider/ByteArrayAccess.java Fri Apr 17 09:40:02 2015 +0200 +++ b/jdk/src/java.base/share/classes/sun/security/provider/ByteArrayAccess.java Fri Apr 17 14:37:44 2015 -0700 @@ -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 @@ // 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(); } /** diff -r e37c7eba132f -r a56e57aad51f jdk/src/java.base/share/native/include/jvm.h --- a/jdk/src/java.base/share/native/include/jvm.h Fri Apr 17 09:40:02 2015 +0200 +++ b/jdk/src/java.base/share/native/include/jvm.h Fri Apr 17 14:37:44 2015 -0700 @@ -395,6 +395,9 @@ 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); diff -r e37c7eba132f -r a56e57aad51f jdk/src/java.base/share/native/libjava/Class.c --- a/jdk/src/java.base/share/native/libjava/Class.c Fri Apr 17 09:40:02 2015 +0200 +++ b/jdk/src/java.base/share/native/libjava/Class.c Fri Apr 17 14:37:44 2015 -0700 @@ -67,6 +67,7 @@ {"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}, diff -r e37c7eba132f -r a56e57aad51f jdk/test/java/lang/Class/getSimpleName/GetSimpleNameTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/Class/getSimpleName/GetSimpleNameTest.java Fri Apr 17 14:37:44 2015 -0700 @@ -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, "", "()V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()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(); + } + } +}