Merge jdk7-b56
authorduke
Wed, 05 Jul 2017 16:51:35 +0200
changeset 2553 a8134c4ee2cf
parent 2552 be3e9eb55ce0 (diff)
parent 2522 7d5540f627ca (current diff)
child 2554 fd7502231683
child 2555 94f4dd0f0b3b
child 2560 6ed73835812f
child 2562 53c0175d93ae
child 2583 a1675856311f
child 2635 c78403167ab7
child 2663 01a7af32d19f
child 2664 a0a22a8f16bd
child 2668 fd0d6a85709b
child 2670 a8af70ae4727
child 2674 4b54fe2ec39f
child 2677 cd181222973b
child 2683 2a90767f9ef0
child 2723 b659ca23d5f5
child 2778 6df702c8ca19
child 2791 c84bf0caab7f
child 2830 2c7571fb9056
child 2839 668ff342c026
child 2848 98fc22703cbc
Merge
--- a/.hgtags-top-repo	Wed Jul 05 16:51:11 2017 +0200
+++ b/.hgtags-top-repo	Wed Jul 05 16:51:35 2017 +0200
@@ -29,3 +29,4 @@
 4264c2fe66493e57c411045a1b61377796641e45 jdk7-b52
 c235f4a8559d196879c56af80159f67ee5d0e720 jdk7-b53
 2ef382b1bbd58a68e668391c6145a4b2066c5b96 jdk7-b54
+aea0ace7a1e43619800931d42bbf69c579361c2d jdk7-b55
--- a/corba/.hgtags	Wed Jul 05 16:51:11 2017 +0200
+++ b/corba/.hgtags	Wed Jul 05 16:51:35 2017 +0200
@@ -29,3 +29,4 @@
 bec82237d694f9802b820fa11bbb4f7fa9bf8e77 jdk7-b52
 3c4d73194f6f89f040ae3b2d257335dfa8a1b2b5 jdk7-b53
 8130ac858d6789d5853d23044ba4a992afda574a jdk7-b54
+7a869f16ba83060c34b77620406cfa89d1cd7084 jdk7-b55
--- a/hotspot/.hgtags	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/.hgtags	Wed Jul 05 16:51:35 2017 +0200
@@ -29,3 +29,4 @@
 1b1e8f1a4fe8cebc01c022484f78148e17b62a0d jdk7-b52
 032c6af894dae8d939b3dd31d82042549e7793e0 jdk7-b53
 fafab5d5349c7c066d677538db67a1ee0fb33bd2 jdk7-b54
+f8e839c086152da70d6ec5913ba6f9f509282e8d jdk7-b55
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/ClassConstants.java	Wed Jul 05 16:51:35 2017 +0200
@@ -142,34 +142,35 @@
     // from jvm.h
 
     public static final long JVM_RECOGNIZED_CLASS_MODIFIERS   = (JVM_ACC_PUBLIC |
-                                        JVM_ACC_FINAL |
-                                        JVM_ACC_SUPER |
-                                        JVM_ACC_INTERFACE |
-                                        JVM_ACC_ABSTRACT |
-                                        JVM_ACC_ANNOTATION |
-                                        JVM_ACC_SYNTHETIC);
+                                                                 JVM_ACC_FINAL |
+                                                                 JVM_ACC_SUPER |
+                                                                 JVM_ACC_INTERFACE |
+                                                                 JVM_ACC_ABSTRACT |
+                                                                 JVM_ACC_ANNOTATION |
+                                                                 JVM_ACC_ENUM |
+                                                                 JVM_ACC_SYNTHETIC);
 
 
     public static final long JVM_RECOGNIZED_FIELD_MODIFIERS  = (JVM_ACC_PUBLIC |
-                                        JVM_ACC_PRIVATE |
-                                        JVM_ACC_PROTECTED |
-                                        JVM_ACC_STATIC |
-                                        JVM_ACC_FINAL |
-                                        JVM_ACC_VOLATILE |
-                                        JVM_ACC_TRANSIENT |
-                                        JVM_ACC_ENUM |
-                                        JVM_ACC_SYNTHETIC);
+                                                                JVM_ACC_PRIVATE |
+                                                                JVM_ACC_PROTECTED |
+                                                                JVM_ACC_STATIC |
+                                                                JVM_ACC_FINAL |
+                                                                JVM_ACC_VOLATILE |
+                                                                JVM_ACC_TRANSIENT |
+                                                                JVM_ACC_ENUM |
+                                                                JVM_ACC_SYNTHETIC);
 
     public static final long JVM_RECOGNIZED_METHOD_MODIFIERS  = (JVM_ACC_PUBLIC |
-                                         JVM_ACC_PRIVATE |
-                                         JVM_ACC_PROTECTED |
-                                         JVM_ACC_STATIC |
-                                         JVM_ACC_FINAL |
-                                         JVM_ACC_SYNCHRONIZED |
-                                         JVM_ACC_BRIDGE |
-                                         JVM_ACC_VARARGS |
-                                         JVM_ACC_NATIVE |
-                                         JVM_ACC_ABSTRACT |
-                                         JVM_ACC_STRICT |
-                                         JVM_ACC_SYNTHETIC);
+                                                                 JVM_ACC_PRIVATE |
+                                                                 JVM_ACC_PROTECTED |
+                                                                 JVM_ACC_STATIC |
+                                                                 JVM_ACC_FINAL |
+                                                                 JVM_ACC_SYNCHRONIZED |
+                                                                 JVM_ACC_BRIDGE |
+                                                                 JVM_ACC_VARARGS |
+                                                                 JVM_ACC_NATIVE |
+                                                                 JVM_ACC_ABSTRACT |
+                                                                 JVM_ACC_STRICT |
+                                                                 JVM_ACC_SYNTHETIC);
 }
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java	Wed Jul 05 16:51:35 2017 +0200
@@ -48,6 +48,8 @@
   private static AddressField  lastJavaPCField;
   private static CIntegerField threadStateField;
   private static AddressField  osThreadField;
+  private static AddressField  stackBaseField;
+  private static CIntegerField stackSizeField;
 
   private static JavaThreadPDAccess access;
 
@@ -83,6 +85,8 @@
     lastJavaPCField   = anchorType.getAddressField("_last_Java_pc");
     threadStateField  = type.getCIntegerField("_thread_state");
     osThreadField     = type.getAddressField("_osthread");
+    stackBaseField    = type.getAddressField("_stack_base");
+    stackSizeField    = type.getCIntegerField("_stack_size");
 
     UNINITIALIZED     = db.lookupIntConstant("_thread_uninitialized").intValue();
     NEW               = db.lookupIntConstant("_thread_new").intValue();
@@ -312,6 +316,14 @@
     return (OSThread) VMObjectFactory.newObject(OSThread.class, osThreadField.getValue(addr));
   }
 
+  public Address getStackBase() {
+    return stackBaseField.getValue();
+  }
+
+  public long getStackSize() {
+    return stackSizeField.getValue();
+  }
+
   /** Gets the Java-side thread object for this JavaThread */
   public Oop getThreadObj() {
     return VM.getVM().getObjectHeap().newOop(threadObjField.getValue(addr));
@@ -345,11 +357,18 @@
     if (Assert.ASSERTS_ENABLED) {
       Assert.that(VM.getVM().isDebugging(), "Not yet implemented for non-debugging system");
     }
-    Address highest = highestLock();
     Address sp      = lastSPDbg();
+    Address stackBase = getStackBase();
     // Be robust
-    if ((highest == null) || (sp == null)) return false;
-    return (highest.greaterThanOrEqual(a) && sp.lessThanOrEqual(a));
+    if (sp == null) return false;
+    return stackBase.greaterThanOrEqual(a) && sp.lessThanOrEqual(a);
+  }
+
+  public boolean isLockOwned(Address a) {
+    Address stackBase = getStackBase();
+    Address stackLimit = stackBase.addOffsetTo(-getStackSize());
+
+    return stackBase.greaterThanOrEqual(a) && stackLimit.lessThanOrEqual(a);
 
     // FIXME: should traverse MonitorArray/MonitorChunks as in VM
   }
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Thread.java	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Thread.java	Wed Jul 05 16:51:35 2017 +0200
@@ -38,7 +38,6 @@
   private static int HAS_ASYNC_EXCEPTION;
 
   private static AddressField activeHandlesField;
-  private static AddressField highestLockField;
   private static AddressField currentPendingMonitorField;
   private static AddressField currentWaitingMonitorField;
 
@@ -60,7 +59,6 @@
 
     tlabFieldOffset    = type.getField("_tlab").getOffset();
     activeHandlesField = type.getAddressField("_active_handles");
-    highestLockField   = type.getAddressField("_highest_lock");
     currentPendingMonitorField = type.getAddressField("_current_pending_monitor");
     currentWaitingMonitorField = type.getAddressField("_current_waiting_monitor");
   }
@@ -121,10 +119,6 @@
     // pending exception
   }
 
-  public Address highestLock() {
-    return highestLockField.getValue(addr);
-  }
-
   public ObjectMonitor getCurrentPendingMonitor() {
     Address monitorAddr = currentPendingMonitorField.getValue(addr);
     if (monitorAddr == null) {
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/Threads.java	Wed Jul 05 16:51:35 2017 +0200
@@ -164,20 +164,11 @@
             }
         }
 
-        long leastDiff = 0;
-        boolean leastDiffInitialized = false;
-        JavaThread theOwner = null;
         for (JavaThread thread = first(); thread != null; thread = thread.next()) {
-            Address addr = thread.highestLock();
-            if (addr == null || addr.lessThan(o)) continue;
-            long diff = addr.minus(o);
-            if (!leastDiffInitialized || diff < leastDiff) {
-                leastDiffInitialized = true;
-                leastDiff = diff;
-                theOwner = thread;
-            }
+          if (thread.isLockOwned(o))
+            return thread;
         }
-        return theOwner;
+        return null;
     }
 
     public JavaThread owningThreadFromMonitor(ObjectMonitor monitor) {
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ByteCodeRewriter.java	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ByteCodeRewriter.java	Wed Jul 05 16:51:35 2017 +0200
@@ -89,29 +89,6 @@
             // update the code buffer hotspot specific bytecode with the jvm bytecode
             code[bci] = (byte) (0xFF & bytecode);
 
-            // RewriteFrequentPairs
-            if(hotspotcode == Bytecodes._fast_iaccess_0 ||
-               hotspotcode == Bytecodes._fast_aaccess_0 ||
-               hotspotcode == Bytecodes._fast_faccess_0) {
-               // rewrite next bytecode as _getfield
-                bci++;
-               code[bci] = (byte) (0xFF & Bytecodes._getfield);
-               bytecode  = Bytecodes._getfield;
-               hotspotcode  = Bytecodes._getfield;
-            } else if (hotspotcode == Bytecodes._fast_iload2) {
-               // rewrite next bytecode as _iload
-               bci++;
-               code[bci] = (byte) (0xFF & Bytecodes._iload);
-               bytecode = Bytecodes._iload;
-               hotspotcode = Bytecodes._iload;
-            } else if (hotspotcode == Bytecodes._fast_icaload) {
-               // rewrite next bytecode as _caload
-               bci++;
-               code[bci] = (byte) (0xFF & Bytecodes._caload);
-               bytecode = Bytecodes._caload;
-               bytecode = Bytecodes._caload;
-            }
-
             short cpoolIndex = 0;
             switch (bytecode) {
                 // bytecodes with ConstantPoolCache index
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassDump.java	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassDump.java	Wed Jul 05 16:51:35 2017 +0200
@@ -59,8 +59,14 @@
             SystemDictionary dict = VM.getVM().getSystemDictionary();
             dict.classesDo(new SystemDictionary.ClassVisitor() {
                     public void visit(Klass k) {
-                        if (k instanceof InstanceKlass)
-                            dumpKlass((InstanceKlass) k);
+                        if (k instanceof InstanceKlass) {
+                            try {
+                                dumpKlass((InstanceKlass) k);
+                            } catch (Exception e) {
+                                System.out.println(k.getName().asString());
+                                e.printStackTrace();
+                            }
+                        }
                     }
                 });
         }
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ClassWriter.java	Wed Jul 05 16:51:35 2017 +0200
@@ -40,7 +40,6 @@
     protected InstanceKlass     klass;
     protected DataOutputStream  dos;
     protected ConstantPool      cpool;
-    protected boolean           is15Format;
 
     // Map between class name to index of type CONSTANT_Class
     protected Map               classToIndex = new HashMap();
@@ -73,7 +72,6 @@
         klass = kls;
         dos = new DataOutputStream(os);
         cpool = klass.getConstants();
-        is15Format = is15ClassFile();
     }
 
     public void write() throws IOException {
@@ -82,7 +80,7 @@
         // write magic
         dos.writeInt(0xCAFEBABE);
 
-        writeVersion(is15Format);
+        writeVersion();
         writeConstantPool();
         writeClassAccessFlags();
         writeThisClass();
@@ -96,43 +94,14 @@
         dos.flush();
     }
 
-    protected boolean is15ClassFile() {
-        // if klass has generic signature, then it is 1.5  class file.
-        if (klass.getGenericSignature() != null) {
-           return true;
-        }
-
-        // if atleast one method has generic signature
-        // , then we have 1.5 class file.
-        ObjArray methods = klass.getMethods();
-        final int numMethods = (int) methods.getLength();
-        for (int m = 0; m < numMethods; m++) {
-           Method curMethod = (Method) methods.getObjAt(m);
-           if (curMethod.getGenericSignature() != null) {
-              return true;
-           }
-        }
-
-        // if atleast one field has non-zero generic signature index, then we have
-        // 1.5 class file
-        TypeArray fields = klass.getFields();
-        final int numFields = (int) fields.getLength();
-        for (int f = 0; f < numFields; f += InstanceKlass.NEXT_OFFSET) {
-           short genSigIndex = fields.getShortAt(f + InstanceKlass.GENERIC_SIGNATURE_INDEX_OFFSET);
-           if (genSigIndex != (short)0) return true;
-        }
-
-        return false;
+    protected void writeVersion() throws IOException {
+        dos.writeShort((short)klass.minorVersion());
+        dos.writeShort((short)klass.majorVersion());
     }
 
-    protected void writeVersion(boolean is15Format) throws IOException {
-        if (is15Format) {
-           dos.writeShort(MINOR_VERSION);
-           dos.writeShort(MAJOR_VERSION);
-        } else {
-           dos.writeShort(MINOR_VERSION_OLD);
-           dos.writeShort(MAJOR_VERSION_OLD);
-        }
+    protected void writeIndex(int index) throws IOException {
+        if (index == 0) throw new InternalError();
+        dos.writeShort(index);
     }
 
     protected void writeConstantPool() throws IOException {
@@ -392,8 +361,8 @@
             if (DEBUG) debugMessage("\tfield name = " + nameIndex + ", signature = " + signatureIndex);
 
             short fieldAttributeCount = 0;
-            boolean isSyn = isSynthetic(accessFlags);
-            if (isSyn)
+            boolean hasSyn = hasSyntheticAttribute(accessFlags);
+            if (hasSyn)
                 fieldAttributeCount++;
 
             short initvalIndex = fields.getShortAt(index + InstanceKlass.INITVAL_INDEX_OFFSET);
@@ -407,18 +376,18 @@
             dos.writeShort(fieldAttributeCount);
 
             // write synthetic, if applicable
-            if (isSyn)
+            if (hasSyn)
                 writeSynthetic();
 
             if (initvalIndex != 0) {
-                dos.writeShort(_constantValueIndex);
+                writeIndex(_constantValueIndex);
                 dos.writeInt(2);
                 dos.writeShort(initvalIndex);
                 if (DEBUG) debugMessage("\tfield init value = " + initvalIndex);
             }
 
             if (genSigIndex != 0) {
-                dos.writeShort(_signatureIndex);
+                writeIndex(_signatureIndex);
                 dos.writeInt(2);
                 dos.writeShort(genSigIndex);
                 if (DEBUG) debugMessage("\tfield generic signature index " + genSigIndex);
@@ -430,8 +399,13 @@
         return (accessFlags & (short) JVM_ACC_SYNTHETIC) != 0;
     }
 
+    protected boolean hasSyntheticAttribute(short accessFlags) {
+        // Check if flags have the attribute and if the constant pool contains an entry for it.
+        return isSynthetic(accessFlags) && _syntheticIndex != 0;
+    }
+
     protected void writeSynthetic() throws IOException {
-        dos.writeShort(_syntheticIndex);
+        writeIndex(_syntheticIndex);
         dos.writeInt(0);
     }
 
@@ -459,8 +433,8 @@
 
         short methodAttributeCount = 0;
 
-        final boolean isSyn = isSynthetic((short)accessFlags);
-        if (isSyn)
+        final boolean hasSyn = hasSyntheticAttribute((short)accessFlags);
+        if (hasSyn)
             methodAttributeCount++;
 
         final boolean hasCheckedExceptions = m.hasCheckedExceptions();
@@ -478,27 +452,11 @@
         dos.writeShort(methodAttributeCount);
         if (DEBUG) debugMessage("\tmethod attribute count = " + methodAttributeCount);
 
-        if (isSyn) {
+        if (hasSyn) {
             if (DEBUG) debugMessage("\tmethod is synthetic");
             writeSynthetic();
         }
 
-        if (hasCheckedExceptions) {
-            CheckedExceptionElement[] exceptions = m.getCheckedExceptions();
-            dos.writeShort(_exceptionsIndex);
-
-            int attrSize = 2 /* number_of_exceptions */ +
-                           exceptions.length * 2 /* exception_index */;
-            dos.writeInt(attrSize);
-            dos.writeShort(exceptions.length);
-            if (DEBUG) debugMessage("\tmethod has " + exceptions.length
-                                        +  " checked exception(s)");
-            for (int e = 0; e < exceptions.length; e++) {
-                 short cpIndex = (short) exceptions[e].getClassCPIndex();
-                 dos.writeShort(cpIndex);
-            }
-        }
-
         if (isCodeAvailable) {
             byte[] code = m.getByteCode();
             short codeAttrCount = 0;
@@ -574,7 +532,7 @@
 
             // start writing Code
 
-            dos.writeShort(_codeIndex);
+            writeIndex(_codeIndex);
 
             dos.writeInt(codeSize);
             if (DEBUG) debugMessage("\tcode attribute length = " + codeSize);
@@ -608,7 +566,7 @@
 
             // write LineNumberTable, if available.
             if (hasLineNumberTable) {
-                dos.writeShort(_lineNumberTableIndex);
+                writeIndex(_lineNumberTableIndex);
                 dos.writeInt(lineNumberAttrLen);
                 dos.writeShort((short) lineNumberTable.length);
                 for (int l = 0; l < lineNumberTable.length; l++) {
@@ -619,7 +577,7 @@
 
             // write LocalVariableTable, if available.
             if (hasLocalVariableTable) {
-                dos.writeShort((short) _localVariableTableIndex);
+                writeIndex((short) _localVariableTableIndex);
                 dos.writeInt(localVarAttrLen);
                 dos.writeShort((short) localVariableTable.length);
                 for (int l = 0; l < localVariableTable.length; l++) {
@@ -632,6 +590,22 @@
             }
         }
 
+        if (hasCheckedExceptions) {
+            CheckedExceptionElement[] exceptions = m.getCheckedExceptions();
+            writeIndex(_exceptionsIndex);
+
+            int attrSize = 2 /* number_of_exceptions */ +
+                           exceptions.length * 2 /* exception_index */;
+            dos.writeInt(attrSize);
+            dos.writeShort(exceptions.length);
+            if (DEBUG) debugMessage("\tmethod has " + exceptions.length
+                                        +  " checked exception(s)");
+            for (int e = 0; e < exceptions.length; e++) {
+                 short cpIndex = (short) exceptions[e].getClassCPIndex();
+                 dos.writeShort(cpIndex);
+            }
+        }
+
         if (isGeneric) {
            writeGenericSignature(m.getGenericSignature().asString());
         }
@@ -643,7 +617,7 @@
     }
 
     protected void writeGenericSignature(String signature) throws IOException {
-        dos.writeShort(_signatureIndex);
+        writeIndex(_signatureIndex);
         if (DEBUG) debugMessage("signature attribute = " + _signatureIndex);
         dos.writeInt(2);
         Short index = (Short) utf8ToIndex.get(signature);
@@ -653,12 +627,12 @@
 
     protected void writeClassAttributes() throws IOException {
         final long flags = klass.getAccessFlags();
-        final boolean isSyn = isSynthetic((short) flags);
+        final boolean hasSyn = hasSyntheticAttribute((short) flags);
 
         // check for source file
         short classAttributeCount = 0;
 
-        if (isSyn)
+        if (hasSyn)
             classAttributeCount++;
 
         Symbol sourceFileName = klass.getSourceFileName();
@@ -677,12 +651,12 @@
         dos.writeShort(classAttributeCount);
         if (DEBUG) debugMessage("class attribute count = " + classAttributeCount);
 
-        if (isSyn)
+        if (hasSyn)
             writeSynthetic();
 
         // write SourceFile, if any
         if (sourceFileName != null) {
-            dos.writeShort(_sourceFileIndex);
+            writeIndex(_sourceFileIndex);
             if (DEBUG) debugMessage("source file attribute = " + _sourceFileIndex);
             dos.writeInt(2);
             Short index = (Short) utf8ToIndex.get(sourceFileName.asString());
@@ -697,7 +671,7 @@
 
         // write inner classes, if any
         if (numInnerClasses != 0) {
-            dos.writeShort(_innerClassesIndex);
+            writeIndex(_innerClassesIndex);
             final int innerAttrLen = 2 /* number_of_inner_classes */ +
                                      numInnerClasses * (
                                                  2 /* inner_class_info_index */ +
--- a/hotspot/make/hotspot_version	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/make/hotspot_version	Wed Jul 05 16:51:35 2017 +0200
@@ -33,9 +33,9 @@
 # Don't put quotes (fail windows build).
 HOTSPOT_VM_COPYRIGHT=Copyright 2009
 
-HS_MAJOR_VER=15
+HS_MAJOR_VER=16
 HS_MINOR_VER=0
-HS_BUILD_NUMBER=05
+HS_BUILD_NUMBER=01
 
 JDK_MAJOR_VER=1
 JDK_MINOR_VER=7
--- a/hotspot/make/jprt.config	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/make/jprt.config	Wed Jul 05 16:51:35 2017 +0200
@@ -73,6 +73,7 @@
     else
         if [ "${JPRT_JOB_PRODUCT_RELEASE}" = "jdk6"      -o \
              "${JPRT_JOB_PRODUCT_RELEASE}" = "jdk6u10"   -o \
+             "${JPRT_JOB_PRODUCT_RELEASE}" = "jdk6u14"   -o \
              "${JPRT_JOB_PRODUCT_RELEASE}" = "jdk6perf" ] ; then
             # All jdk6 builds use SS11
             compiler_name=SS11
--- a/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -3029,6 +3029,58 @@
 
 
 
+void MacroAssembler::check_method_handle_type(Register mtype_reg, Register mh_reg,
+                                              Register temp_reg,
+                                              Label& wrong_method_type) {
+  assert_different_registers(mtype_reg, mh_reg, temp_reg);
+  // compare method type against that of the receiver
+  RegisterOrConstant mhtype_offset = delayed_value(java_dyn_MethodHandle::type_offset_in_bytes, temp_reg);
+  ld_ptr(mh_reg, mhtype_offset, temp_reg);
+  cmp(temp_reg, mtype_reg);
+  br(Assembler::notEqual, false, Assembler::pn, wrong_method_type);
+  delayed()->nop();
+}
+
+
+void MacroAssembler::jump_to_method_handle_entry(Register mh_reg, Register temp_reg) {
+  assert(mh_reg == G3_method_handle, "caller must put MH object in G3");
+  assert_different_registers(mh_reg, temp_reg);
+
+  // pick out the interpreted side of the handler
+  ld_ptr(mh_reg, delayed_value(java_dyn_MethodHandle::vmentry_offset_in_bytes, temp_reg), temp_reg);
+
+  // off we go...
+  ld_ptr(temp_reg, MethodHandleEntry::from_interpreted_entry_offset_in_bytes(), temp_reg);
+  jmp(temp_reg, 0);
+
+  // for the various stubs which take control at this point,
+  // see MethodHandles::generate_method_handle_stub
+
+  // (Can any caller use this delay slot?  If so, add an option for supression.)
+  delayed()->nop();
+}
+
+RegisterOrConstant MacroAssembler::argument_offset(RegisterOrConstant arg_slot,
+                                                   int extra_slot_offset) {
+  // cf. TemplateTable::prepare_invoke(), if (load_receiver).
+  int stackElementSize = Interpreter::stackElementWords() * wordSize;
+  int offset = Interpreter::expr_offset_in_bytes(extra_slot_offset+0);
+  int offset1 = Interpreter::expr_offset_in_bytes(extra_slot_offset+1);
+  assert(offset1 - offset == stackElementSize, "correct arithmetic");
+  if (arg_slot.is_constant()) {
+    offset += arg_slot.as_constant() * stackElementSize;
+    return offset;
+  } else {
+    Register temp = arg_slot.as_register();
+    sll_ptr(temp, exact_log2(stackElementSize), temp);
+    if (offset != 0)
+      add(temp, offset, temp);
+    return temp;
+  }
+}
+
+
+
 void MacroAssembler::biased_locking_enter(Register obj_reg, Register mark_reg,
                                           Register temp_reg,
                                           Label& done, Label* slow_case,
--- a/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.hpp	Wed Jul 05 16:51:35 2017 +0200
@@ -84,6 +84,10 @@
 
 REGISTER_DECLARATION(Register, Gtemp  , G5);
 
+// JSR 292 fixed register usages:
+REGISTER_DECLARATION(Register, G5_method_type        , G5);
+REGISTER_DECLARATION(Register, G3_method_handle      , G3);
+
 // The compiler requires that G5_megamorphic_method is G5_inline_cache_klass,
 // because a single patchable "set" instruction (NativeMovConstReg,
 // or NativeMovConstPatching for compiler1) instruction
@@ -91,9 +95,13 @@
 // call site is an inline cache or is megamorphic.  See the function
 // CompiledIC::set_to_megamorphic.
 //
-// On the other hand, G5_inline_cache_klass must differ from G5_method,
-// because both registers are needed for an inline cache that calls
-// an interpreted method.
+// If a inline cache targets an interpreted method, then the
+// G5 register will be used twice during the call.  First,
+// the call site will be patched to load a compiledICHolder
+// into G5. (This is an ordered pair of ic_klass, method.)
+// The c2i adapter will first check the ic_klass, then load
+// G5_method with the method part of the pair just before
+// jumping into the interpreter.
 //
 // Note that G5_method is only the method-self for the interpreter,
 // and is logically unrelated to G5_megamorphic_method.
@@ -1931,6 +1939,7 @@
   inline void store_ptr_contents( Register s, Address& a, int offset = 0 );
   inline void jumpl_to( Address& a, Register d, int offset = 0 );
   inline void jump_to(  Address& a,             int offset = 0 );
+  inline void jump_indirect_to(  Address& a, Register temp, int ld_offset = 0, int jmp_offset = 0 );
 
   // ring buffer traceable jumps
 
@@ -2366,6 +2375,16 @@
                            Register temp2_reg,
                            Label& L_success);
 
+  // method handles (JSR 292)
+  void check_method_handle_type(Register mtype_reg, Register mh_reg,
+                                Register temp_reg,
+                                Label& wrong_method_type);
+  void jump_to_method_handle_entry(Register mh_reg, Register temp_reg);
+  // offset relative to Gargs of argument at tos[arg_slot].
+  // (arg_slot == 0 means the last argument, not the first).
+  RegisterOrConstant argument_offset(RegisterOrConstant arg_slot,
+                                     int extra_slot_offset = 0);
+
 
   // Stack overflow checking
 
--- a/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/cpu/sparc/vm/assembler_sparc.inline.hpp	Wed Jul 05 16:51:35 2017 +0200
@@ -671,6 +671,15 @@
 }
 
 
+inline void MacroAssembler::jump_indirect_to(  Address& a, Register temp,
+                                               int ld_offset, int jmp_offset ) {
+  assert_not_delayed();
+  //sethi(a);                   // sethi is caller responsibility for this one
+  ld_ptr(a, temp, ld_offset);
+  jmp(temp, jmp_offset);
+}
+
+
 inline void MacroAssembler::set_oop( jobject obj, Register d ) {
   set_oop(allocate_oop_address(obj, d));
 }
--- a/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/cpu/sparc/vm/cppInterpreter_sparc.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2007-2009 Sun Microsystems, Inc.  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
@@ -1017,6 +1017,7 @@
   const int slop_factor = 2*wordSize;
 
   const int fixed_size = ((sizeof(BytecodeInterpreter) + slop_factor) >> LogBytesPerWord) + // what is the slop factor?
+                         //6815692//methodOopDesc::extra_stack_words() +  // extra push slots for MH adapters
                          frame::memory_parameter_word_sp_offset +  // register save area + param window
                          (native ?  frame::interpreter_frame_extra_outgoing_argument_words : 0); // JNI, class
 
@@ -1163,6 +1164,9 @@
   __ st_ptr(O2, XXX_STATE(_stack));                // PREPUSH
 
   __ lduh(max_stack, O3);                      // Full size expression stack
+  guarantee(!EnableMethodHandles, "no support yet for java.dyn.MethodHandle"); //6815692
+  //6815692//if (EnableMethodHandles)
+  //6815692//  __ inc(O3, methodOopDesc::extra_stack_entries());
   __ sll(O3, LogBytesPerWord, O3);
   __ sub(O2, O3, O3);
 //  __ sub(O3, wordSize, O3);                    // so prepush doesn't look out of bounds
@@ -2017,7 +2021,9 @@
 
   const int fixed_size = sizeof(BytecodeInterpreter)/wordSize +           // interpreter state object
                          frame::memory_parameter_word_sp_offset;   // register save area + param window
+  const int extra_stack = 0; //6815692//methodOopDesc::extra_stack_entries();
   return (round_to(max_stack +
+                   extra_stack +
                    slop_factor +
                    fixed_size +
                    monitor_size +
@@ -2104,7 +2110,8 @@
   // Need +1 here because stack_base points to the word just above the first expr stack entry
   // and stack_limit is supposed to point to the word just below the last expr stack entry.
   // See generate_compute_interpreter_state.
-  to_fill->_stack_limit = stack_base - (method->max_stack() + 1);
+  int extra_stack = 0; //6815692//methodOopDesc::extra_stack_entries();
+  to_fill->_stack_limit = stack_base - (method->max_stack() + 1 + extra_stack);
   to_fill->_monitor_base = (BasicObjectLock*) monitor_base;
 
   // sparc specific
--- a/hotspot/src/cpu/sparc/vm/interpreterGenerator_sparc.hpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/cpu/sparc/vm/interpreterGenerator_sparc.hpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc.  All Rights Reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,7 @@
   address generate_normal_entry(bool synchronized);
   address generate_native_entry(bool synchronized);
   address generate_abstract_entry(void);
+  address generate_method_handle_entry(void);
   address generate_math_entry(AbstractInterpreter::MethodKind kind);
   address generate_empty_entry(void);
   address generate_accessor_entry(void);
--- a/hotspot/src/cpu/sparc/vm/interpreter_sparc.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/cpu/sparc/vm/interpreter_sparc.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc.  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
@@ -235,6 +235,19 @@
 }
 
 
+
+// Method handle invoker
+// Dispatch a method of the form java.dyn.MethodHandles::invoke(...)
+address InterpreterGenerator::generate_method_handle_entry(void) {
+  if (!EnableMethodHandles) {
+    return generate_abstract_entry();
+  }
+  return generate_abstract_entry(); //6815692//
+}
+
+
+
+
 //----------------------------------------------------------------------------------------------------
 // Entry points & stack frame layout
 //
@@ -364,6 +377,7 @@
     case Interpreter::empty                  : entry_point = ((InterpreterGenerator*)this)->generate_empty_entry();        break;
     case Interpreter::accessor               : entry_point = ((InterpreterGenerator*)this)->generate_accessor_entry();     break;
     case Interpreter::abstract               : entry_point = ((InterpreterGenerator*)this)->generate_abstract_entry();     break;
+    case Interpreter::method_handle          : entry_point = ((InterpreterGenerator*)this)->generate_method_handle_entry(); break;
     case Interpreter::java_lang_math_sin     :                                                                             break;
     case Interpreter::java_lang_math_cos     :                                                                             break;
     case Interpreter::java_lang_math_tan     :                                                                             break;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/cpu/sparc/vm/methodHandles_sparc.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,70 @@
+/*
+ * Copyright 1997-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+#include "incls/_precompiled.incl"
+#include "incls/_methodHandles_sparc.cpp.incl"
+
+#define __ _masm->
+
+address MethodHandleEntry::start_compiled_entry(MacroAssembler* _masm,
+                                                address interpreted_entry) {
+  __ align(wordSize);
+  address target = __ pc() + sizeof(Data);
+  while (__ pc() < target) {
+    __ nop();
+    __ align(wordSize);
+  }
+
+  MethodHandleEntry* me = (MethodHandleEntry*) __ pc();
+  me->set_end_address(__ pc());         // set a temporary end_address
+  me->set_from_interpreted_entry(interpreted_entry);
+  me->set_type_checking_entry(NULL);
+
+  return (address) me;
+}
+
+MethodHandleEntry* MethodHandleEntry::finish_compiled_entry(MacroAssembler* _masm,
+                                                address start_addr) {
+  MethodHandleEntry* me = (MethodHandleEntry*) start_addr;
+  assert(me->end_address() == start_addr, "valid ME");
+
+  // Fill in the real end_address:
+  __ align(wordSize);
+  me->set_end_address(__ pc());
+
+  return me;
+}
+
+
+// Code generation
+address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm) {
+  ShouldNotReachHere(); //NYI, 6815692
+  return NULL;
+}
+
+// Generate an "entry" field for a method handle.
+// This determines how the method handle will respond to calls.
+void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHandles::EntryKind ek) {
+  ShouldNotReachHere(); //NYI, 6815692
+}
--- a/hotspot/src/cpu/sparc/vm/register_definitions_sparc.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/cpu/sparc/vm/register_definitions_sparc.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2002-2009 Sun Microsystems, Inc.  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
@@ -142,6 +142,8 @@
 REGISTER_DEFINITION(Register, G3_scratch);
 REGISTER_DEFINITION(Register, G4_scratch);
 REGISTER_DEFINITION(Register, Gtemp);
+REGISTER_DEFINITION(Register, G5_method_type);
+REGISTER_DEFINITION(Register, G3_method_handle);
 REGISTER_DEFINITION(Register, Lentry_args);
 
 #ifdef CC_INTERP
--- a/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/cpu/sparc/vm/sharedRuntime_sparc.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2003-2009 Sun Microsystems, Inc.  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
@@ -937,12 +937,12 @@
   // Inputs:
   // G2_thread      - TLS
   // G5_method      - Method oop
-  // O0             - Flag telling us to restore SP from O5
-  // O4_args        - Pointer to interpreter's args
-  // O5             - Caller's saved SP, to be restored if needed
+  // G4 (Gargs)     - Pointer to interpreter's args
+  // O0..O4         - free for scratch
+  // O5_savedSP     - Caller's saved SP, to be restored if needed
   // O6             - Current SP!
   // O7             - Valid return address
-  // L0-L7, I0-I7    - Caller's temps (no frame pushed yet)
+  // L0-L7, I0-I7   - Caller's temps (no frame pushed yet)
 
   // Outputs:
   // G2_thread      - TLS
@@ -954,7 +954,7 @@
   // F0-F7          - more outgoing args
 
 
-  // O4 is about to get loaded up with compiled callee's args
+  // Gargs is the incoming argument base, and also an outgoing argument.
   __ sub(Gargs, BytesPerWord, Gargs);
 
 #ifdef ASSERT
--- a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc.  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
@@ -108,6 +108,24 @@
 }
 
 
+// Arguments are: required type in G5_method_type, and
+// failing object (or NULL) in G3_method_handle.
+address TemplateInterpreterGenerator::generate_WrongMethodType_handler() {
+  address entry = __ pc();
+  // expression stack must be empty before entering the VM if an exception
+  // happened
+  __ empty_expression_stack();
+  // load exception object
+  __ call_VM(Oexception,
+             CAST_FROM_FN_PTR(address,
+                              InterpreterRuntime::throw_WrongMethodTypeException),
+             G5_method_type,    // required
+             G3_method_handle); // actual
+  __ should_not_reach_here();
+  return entry;
+}
+
+
 address TemplateInterpreterGenerator::generate_ArrayIndexOutOfBounds_handler(const char* name) {
   address entry = __ pc();
   // expression stack must be empty before entering the VM if an exception happened
@@ -448,6 +466,7 @@
 
   const int extra_space =
     rounded_vm_local_words +                   // frame local scratch space
+    //6815692//methodOopDesc::extra_stack_words() +       // extra push slots for MH adapters
     frame::memory_parameter_word_sp_offset +   // register save area
     (native_call ? frame::interpreter_frame_extra_outgoing_argument_words : 0);
 
@@ -1447,6 +1466,7 @@
        round_to(callee_extra_locals * Interpreter::stackElementWords(), WordsPerLong);
   const int max_stack_words = max_stack * Interpreter::stackElementWords();
   return (round_to((max_stack_words
+                   //6815692//+ methodOopDesc::extra_stack_words()
                    + rounded_vm_local_words
                    + frame::memory_parameter_word_sp_offset), WordsPerLong)
                    // already rounded
--- a/hotspot/src/cpu/sparc/vm/vtableStubs_sparc.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/cpu/sparc/vm/vtableStubs_sparc.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -114,6 +114,9 @@
                   (int)(s->code_end() - __ pc()));
   }
   guarantee(__ pc() <= s->code_end(), "overflowed buffer");
+  // shut the door on sizing bugs
+  int slop = 2*BytesPerInstWord;  // 32-bit offset is this much larger than a 13-bit one
+  assert(vtable_index > 10 || __ pc() + slop <= s->code_end(), "room for sethi;add");
 
   s->set_exception_points(npe_addr, ame_addr);
   return s;
@@ -208,6 +211,9 @@
                   (int)(s->code_end() - __ pc()));
   }
   guarantee(__ pc() <= s->code_end(), "overflowed buffer");
+  // shut the door on sizing bugs
+  int slop = 2*BytesPerInstWord;  // 32-bit offset is this much larger than a 13-bit one
+  assert(itable_index > 10 || __ pc() + slop <= s->code_end(), "room for sethi;add");
 
   s->set_exception_points(npe_addr, ame_addr);
   return s;
@@ -233,6 +239,50 @@
       return (basic + slop);
     }
   }
+
+  // In order to tune these parameters, run the JVM with VM options
+  // +PrintMiscellaneous and +WizardMode to see information about
+  // actual itable stubs.  Look for lines like this:
+  //   itable #1 at 0x5551212[116] left over: 8
+  // Reduce the constants so that the "left over" number is 8
+  // Do not aim at a left-over number of zero, because a very
+  // large vtable or itable offset (> 4K) will require an extra
+  // sethi/or pair of instructions.
+  //
+  // The JVM98 app. _202_jess has a megamorphic interface call.
+  // The itable code looks like this:
+  // Decoding VtableStub itbl[1]@16
+  //   ld  [ %o0 + 4 ], %g3
+  //   save  %sp, -64, %sp
+  //   ld  [ %g3 + 0xe8 ], %l2
+  //   sll  %l2, 2, %l2
+  //   add  %l2, 0x134, %l2
+  //   and  %l2, -8, %l2        ! NOT_LP64 only
+  //   add  %g3, %l2, %l2
+  //   add  %g3, 4, %g3
+  //   ld  [ %l2 ], %l5
+  //   brz,pn   %l5, throw_icce
+  //   cmp  %l5, %g5
+  //   be  %icc, success
+  //   add  %l2, 8, %l2
+  // loop:
+  //   ld  [ %l2 ], %l5
+  //   brz,pn   %l5, throw_icce
+  //   cmp  %l5, %g5
+  //   bne,pn   %icc, loop
+  //   add  %l2, 8, %l2
+  // success:
+  //   ld  [ %l2 + -4 ], %l2
+  //   ld  [ %g3 + %l2 ], %l5
+  //   restore  %l5, 0, %g5
+  //   ld  [ %g5 + 0x44 ], %g3
+  //   jmp  %g3
+  //   nop
+  // throw_icce:
+  //   sethi  %hi(throw_ICCE_entry), %g3
+  //   ! 5 more instructions here, LP64_ONLY
+  //   jmp  %g3 + %lo(throw_ICCE_entry)
+  //   restore
 }
 
 
--- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/cpu/x86/vm/assembler_x86.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -7609,6 +7609,83 @@
 }
 
 
+// registers on entry:
+//  - rax ('check' register): required MethodType
+//  - rcx: method handle
+//  - rdx, rsi, or ?: killable temp
+void MacroAssembler::check_method_handle_type(Register mtype_reg, Register mh_reg,
+                                              Register temp_reg,
+                                              Label& wrong_method_type) {
+  if (UseCompressedOops)  unimplemented();  // field accesses must decode
+  // compare method type against that of the receiver
+  cmpptr(mtype_reg, Address(mh_reg, delayed_value(java_dyn_MethodHandle::type_offset_in_bytes, temp_reg)));
+  jcc(Assembler::notEqual, wrong_method_type);
+}
+
+
+// A method handle has a "vmslots" field which gives the size of its
+// argument list in JVM stack slots.  This field is either located directly
+// in every method handle, or else is indirectly accessed through the
+// method handle's MethodType.  This macro hides the distinction.
+void MacroAssembler::load_method_handle_vmslots(Register vmslots_reg, Register mh_reg,
+                                                Register temp_reg) {
+  if (UseCompressedOops)  unimplemented();  // field accesses must decode
+  // load mh.type.form.vmslots
+  if (java_dyn_MethodHandle::vmslots_offset_in_bytes() != 0) {
+    // hoist vmslots into every mh to avoid dependent load chain
+    movl(vmslots_reg, Address(mh_reg, delayed_value(java_dyn_MethodHandle::vmslots_offset_in_bytes, temp_reg)));
+  } else {
+    Register temp2_reg = vmslots_reg;
+    movptr(temp2_reg, Address(mh_reg,    delayed_value(java_dyn_MethodHandle::type_offset_in_bytes, temp_reg)));
+    movptr(temp2_reg, Address(temp2_reg, delayed_value(java_dyn_MethodType::form_offset_in_bytes, temp_reg)));
+    movl(vmslots_reg, Address(temp2_reg, delayed_value(java_dyn_MethodTypeForm::vmslots_offset_in_bytes, temp_reg)));
+  }
+}
+
+
+// registers on entry:
+//  - rcx: method handle
+//  - rdx: killable temp (interpreted only)
+//  - rax: killable temp (compiled only)
+void MacroAssembler::jump_to_method_handle_entry(Register mh_reg, Register temp_reg) {
+  assert(mh_reg == rcx, "caller must put MH object in rcx");
+  assert_different_registers(mh_reg, temp_reg);
+
+  if (UseCompressedOops)  unimplemented();  // field accesses must decode
+
+  // pick out the interpreted side of the handler
+  movptr(temp_reg, Address(mh_reg, delayed_value(java_dyn_MethodHandle::vmentry_offset_in_bytes, temp_reg)));
+
+  // off we go...
+  jmp(Address(temp_reg, MethodHandleEntry::from_interpreted_entry_offset_in_bytes()));
+
+  // for the various stubs which take control at this point,
+  // see MethodHandles::generate_method_handle_stub
+}
+
+
+Address MacroAssembler::argument_address(RegisterOrConstant arg_slot,
+                                         int extra_slot_offset) {
+  // cf. TemplateTable::prepare_invoke(), if (load_receiver).
+  int stackElementSize = Interpreter::stackElementSize();
+  int offset = Interpreter::expr_offset_in_bytes(extra_slot_offset+0);
+#ifdef ASSERT
+  int offset1 = Interpreter::expr_offset_in_bytes(extra_slot_offset+1);
+  assert(offset1 - offset == stackElementSize, "correct arithmetic");
+#endif
+  Register             scale_reg    = noreg;
+  Address::ScaleFactor scale_factor = Address::no_scale;
+  if (arg_slot.is_constant()) {
+    offset += arg_slot.as_constant() * stackElementSize;
+  } else {
+    scale_reg    = arg_slot.as_register();
+    scale_factor = Address::times(stackElementSize);
+  }
+  offset += wordSize;           // return PC is on stack
+  return Address(rsp, scale_reg, scale_factor, offset);
+}
+
+
 void MacroAssembler::verify_oop_addr(Address addr, const char* s) {
   if (!VerifyOops) return;
 
--- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/cpu/x86/vm/assembler_x86.hpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1857,6 +1857,16 @@
                            Register temp_reg,
                            Label& L_success);
 
+  // method handles (JSR 292)
+  void check_method_handle_type(Register mtype_reg, Register mh_reg,
+                                Register temp_reg,
+                                Label& wrong_method_type);
+  void load_method_handle_vmslots(Register vmslots_reg, Register mh_reg,
+                                  Register temp_reg);
+  void jump_to_method_handle_entry(Register mh_reg, Register temp_reg);
+  Address argument_address(RegisterOrConstant arg_slot, int extra_slot_offset = 0);
+
+
   //----
   void set_word_if_not_zero(Register reg); // sets reg to 1 if not zero, otherwise 0
 
--- a/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/cpu/x86/vm/cppInterpreter_x86.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -513,10 +513,11 @@
     // compute full expression stack limit
 
     const Address size_of_stack    (rbx, methodOopDesc::max_stack_offset());
+    const int extra_stack = 0; //6815692//methodOopDesc::extra_stack_words();
     __ load_unsigned_short(rdx, size_of_stack);                           // get size of expression stack in words
     __ negptr(rdx);                                                       // so we can subtract in next step
     // Allocate expression stack
-    __ lea(rsp, Address(rsp, rdx, Address::times_ptr));
+    __ lea(rsp, Address(rsp, rdx, Address::times_ptr, -extra_stack));
     __ movptr(STATE(_stack_limit), rsp);
   }
 
@@ -659,8 +660,9 @@
     // Always give one monitor to allow us to start interp if sync method.
     // Any additional monitors need a check when moving the expression stack
     const int one_monitor = frame::interpreter_frame_monitor_size() * wordSize;
+    const int extra_stack = 0; //6815692//methodOopDesc::extra_stack_entries();
   __ load_unsigned_short(rax, size_of_stack);                           // get size of expression stack in words
-  __ lea(rax, Address(noreg, rax, Interpreter::stackElementScale(), one_monitor));
+  __ lea(rax, Address(noreg, rax, Interpreter::stackElementScale(), extra_stack + one_monitor));
   __ lea(rax, Address(rax, rdx, Interpreter::stackElementScale(), overhead_size));
 
 #ifdef ASSERT
@@ -2185,6 +2187,7 @@
     case Interpreter::empty                  : entry_point = ((InterpreterGenerator*)this)->generate_empty_entry();        break;
     case Interpreter::accessor               : entry_point = ((InterpreterGenerator*)this)->generate_accessor_entry();     break;
     case Interpreter::abstract               : entry_point = ((InterpreterGenerator*)this)->generate_abstract_entry();     break;
+    case Interpreter::method_handle          : entry_point = ((InterpreterGenerator*)this)->generate_method_handle_entry(); break;
 
     case Interpreter::java_lang_math_sin     : // fall thru
     case Interpreter::java_lang_math_cos     : // fall thru
@@ -2224,7 +2227,8 @@
   const int overhead_size = sizeof(BytecodeInterpreter)/wordSize +
     ( frame::sender_sp_offset - frame::link_offset) + 2;
 
-  const int method_stack = (method->max_locals() + method->max_stack()) *
+  const int extra_stack = 0; //6815692//methodOopDesc::extra_stack_entries();
+  const int method_stack = (method->max_locals() + method->max_stack() + extra_stack) *
                            Interpreter::stackElementWords();
   return overhead_size + method_stack + stub_code;
 }
@@ -2289,7 +2293,8 @@
   // Need +1 here because stack_base points to the word just above the first expr stack entry
   // and stack_limit is supposed to point to the word just below the last expr stack entry.
   // See generate_compute_interpreter_state.
-  to_fill->_stack_limit = stack_base - (method->max_stack() + 1);
+  int extra_stack = 0; //6815692//methodOopDesc::extra_stack_entries();
+  to_fill->_stack_limit = stack_base - (method->max_stack() + extra_stack + 1);
   to_fill->_monitor_base = (BasicObjectLock*) monitor_base;
 
   to_fill->_self_link = to_fill;
@@ -2335,7 +2340,8 @@
                                                 monitor_size);
 
   // Now with full size expression stack
-  int full_frame_size = short_frame_size + method->max_stack() * BytesPerWord;
+  int extra_stack = 0; //6815692//methodOopDesc::extra_stack_entries();
+  int full_frame_size = short_frame_size + (method->max_stack() + extra_stack) * BytesPerWord;
 
   // and now with only live portion of the expression stack
   short_frame_size = short_frame_size + tempcount * BytesPerWord;
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -555,13 +555,18 @@
 }
 
 
-// Jump to from_interpreted entry of a call unless single stepping is possible
-// in this thread in which case we must call the i2i entry
-void InterpreterMacroAssembler::jump_from_interpreted(Register method, Register temp) {
+void InterpreterMacroAssembler::prepare_to_jump_from_interpreted() {
   // set sender sp
   lea(rsi, Address(rsp, wordSize));
   // record last_sp
   movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), rsi);
+}
+
+
+// Jump to from_interpreted entry of a call unless single stepping is possible
+// in this thread in which case we must call the i2i entry
+void InterpreterMacroAssembler::jump_from_interpreted(Register method, Register temp) {
+  prepare_to_jump_from_interpreted();
 
   if (JvmtiExport::can_post_interpreter_events()) {
     Label run_compiled_code;
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp	Wed Jul 05 16:51:35 2017 +0200
@@ -161,6 +161,7 @@
 
 
   // jump to an invoked target
+  void prepare_to_jump_from_interpreted();
   void jump_from_interpreted(Register method, Register temp);
 
   // Returning from interpreted functions
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -551,13 +551,18 @@
   MacroAssembler::call_VM_leaf_base(entry_point, 3);
 }
 
-// Jump to from_interpreted entry of a call unless single stepping is possible
-// in this thread in which case we must call the i2i entry
-void InterpreterMacroAssembler::jump_from_interpreted(Register method, Register temp) {
+void InterpreterMacroAssembler::prepare_to_jump_from_interpreted() {
   // set sender sp
   lea(r13, Address(rsp, wordSize));
   // record last_sp
   movptr(Address(rbp, frame::interpreter_frame_last_sp_offset * wordSize), r13);
+}
+
+
+// Jump to from_interpreted entry of a call unless single stepping is possible
+// in this thread in which case we must call the i2i entry
+void InterpreterMacroAssembler::jump_from_interpreted(Register method, Register temp) {
+  prepare_to_jump_from_interpreted();
 
   if (JvmtiExport::can_post_interpreter_events()) {
     Label run_compiled_code;
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2003-2009 Sun Microsystems, Inc.  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
@@ -176,6 +176,7 @@
   void dispatch_via (TosState state, address* table);
 
   // jump to an invoked target
+  void prepare_to_jump_from_interpreted();
   void jump_from_interpreted(Register method, Register temp);
 
 
--- a/hotspot/src/cpu/x86/vm/interpreterGenerator_x86.hpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/cpu/x86/vm/interpreterGenerator_x86.hpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc.  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
@@ -32,6 +32,7 @@
   address generate_normal_entry(bool synchronized);
   address generate_native_entry(bool synchronized);
   address generate_abstract_entry(void);
+  address generate_method_handle_entry(void);
   address generate_math_entry(AbstractInterpreter::MethodKind kind);
   address generate_empty_entry(void);
   address generate_accessor_entry(void);
--- a/hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/cpu/x86/vm/interpreter_x86_32.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc.  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
@@ -201,11 +201,12 @@
   address entry_point = __ pc();
 
   // abstract method entry
-  // remove return address. Not really needed, since exception handling throws away expression stack
-  __ pop(rbx);
 
-  // adjust stack to what a normal return would do
-  __ mov(rsp, rsi);
+  //  pop return address, reset last_sp to NULL
+  __ empty_expression_stack();
+  __ restore_bcp();      // rsi must be correct for exception handler   (was destroyed)
+  __ restore_locals();   // make sure locals pointer is correct as well (was destroyed)
+
   // throw exception
   __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::throw_AbstractMethodError));
   // the call_VM checks for exception, so we should never return here.
@@ -214,6 +215,20 @@
   return entry_point;
 }
 
+
+// Method handle invoker
+// Dispatch a method of the form java.dyn.MethodHandles::invoke(...)
+address InterpreterGenerator::generate_method_handle_entry(void) {
+  if (!EnableMethodHandles) {
+    return generate_abstract_entry();
+  }
+
+  address entry_point = MethodHandles::generate_method_handle_interpreter_entry(_masm);
+
+  return entry_point;
+}
+
+
 // This method tells the deoptimizer how big an interpreted frame must be:
 int AbstractInterpreter::size_activation(methodOop method,
                                          int tempcount,
--- a/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/cpu/x86/vm/interpreter_x86_64.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2003-2009 Sun Microsystems, Inc.  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
@@ -294,6 +294,16 @@
 }
 
 
+// Method handle invoker
+// Dispatch a method of the form java.dyn.MethodHandles::invoke(...)
+address InterpreterGenerator::generate_method_handle_entry(void) {
+  if (!EnableMethodHandles) {
+    return generate_abstract_entry();
+  }
+  return generate_abstract_entry(); //6815692//
+}
+
+
 // Empty method, generate a very fast return.
 
 address InterpreterGenerator::generate_empty_entry(void) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/cpu/x86/vm/methodHandles_x86.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,1133 @@
+/*
+ * Copyright 1997-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+#include "incls/_precompiled.incl"
+#include "incls/_methodHandles_x86.cpp.incl"
+
+#define __ _masm->
+
+address MethodHandleEntry::start_compiled_entry(MacroAssembler* _masm,
+                                                address interpreted_entry) {
+  // Just before the actual machine code entry point, allocate space
+  // for a MethodHandleEntry::Data record, so that we can manage everything
+  // from one base pointer.
+  __ align(wordSize);
+  address target = __ pc() + sizeof(Data);
+  while (__ pc() < target) {
+    __ nop();
+    __ align(wordSize);
+  }
+
+  MethodHandleEntry* me = (MethodHandleEntry*) __ pc();
+  me->set_end_address(__ pc());         // set a temporary end_address
+  me->set_from_interpreted_entry(interpreted_entry);
+  me->set_type_checking_entry(NULL);
+
+  return (address) me;
+}
+
+MethodHandleEntry* MethodHandleEntry::finish_compiled_entry(MacroAssembler* _masm,
+                                                address start_addr) {
+  MethodHandleEntry* me = (MethodHandleEntry*) start_addr;
+  assert(me->end_address() == start_addr, "valid ME");
+
+  // Fill in the real end_address:
+  __ align(wordSize);
+  me->set_end_address(__ pc());
+
+  return me;
+}
+
+#ifdef ASSERT
+static void verify_argslot(MacroAssembler* _masm, Register rax_argslot,
+                           const char* error_message) {
+  // Verify that argslot lies within (rsp, rbp].
+  Label L_ok, L_bad;
+  __ cmpptr(rax_argslot, rbp);
+  __ jcc(Assembler::above, L_bad);
+  __ cmpptr(rsp, rax_argslot);
+  __ jcc(Assembler::below, L_ok);
+  __ bind(L_bad);
+  __ stop(error_message);
+  __ bind(L_ok);
+}
+#endif
+
+
+// Code generation
+address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm) {
+  // rbx: methodOop
+  // rcx: receiver method handle (must load from sp[MethodTypeForm.vmslots])
+  // rsi/r13: sender SP (must preserve; see prepare_to_jump_from_interpreted)
+  // rdx: garbage temp, blown away
+
+  Register rbx_method = rbx;
+  Register rcx_recv   = rcx;
+  Register rax_mtype  = rax;
+  Register rdx_temp   = rdx;
+
+  // emit WrongMethodType path first, to enable jccb back-branch from main path
+  Label wrong_method_type;
+  __ bind(wrong_method_type);
+  __ push(rax_mtype);       // required mtype
+  __ push(rcx_recv);        // bad mh (1st stacked argument)
+  __ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry()));
+
+  // here's where control starts out:
+  __ align(CodeEntryAlignment);
+  address entry_point = __ pc();
+
+  // fetch the MethodType from the method handle into rax (the 'check' register)
+  {
+    Register tem = rbx_method;
+    for (jint* pchase = methodOopDesc::method_type_offsets_chain(); (*pchase) != -1; pchase++) {
+      __ movptr(rax_mtype, Address(tem, *pchase));
+      tem = rax_mtype;          // in case there is another indirection
+    }
+  }
+  Register rbx_temp = rbx_method; // done with incoming methodOop
+
+  // given the MethodType, find out where the MH argument is buried
+  __ movptr(rdx_temp, Address(rax_mtype,
+                              __ delayed_value(java_dyn_MethodType::form_offset_in_bytes, rbx_temp)));
+  __ movl(rdx_temp, Address(rdx_temp,
+                            __ delayed_value(java_dyn_MethodTypeForm::vmslots_offset_in_bytes, rbx_temp)));
+  __ movptr(rcx_recv, __ argument_address(rdx_temp));
+
+  __ check_method_handle_type(rax_mtype, rcx_recv, rdx_temp, wrong_method_type);
+  __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
+
+  return entry_point;
+}
+
+// Helper to insert argument slots into the stack.
+// arg_slots must be a multiple of stack_move_unit() and <= 0
+void MethodHandles::insert_arg_slots(MacroAssembler* _masm,
+                                     RegisterOrConstant arg_slots,
+                                     int arg_mask,
+                                     Register rax_argslot,
+                                     Register rbx_temp, Register rdx_temp) {
+  assert_different_registers(rax_argslot, rbx_temp, rdx_temp,
+                             (!arg_slots.is_register() ? rsp : arg_slots.as_register()));
+
+#ifdef ASSERT
+  verify_argslot(_masm, rax_argslot, "insertion point must fall within current frame");
+  if (arg_slots.is_register()) {
+    Label L_ok, L_bad;
+    __ cmpptr(arg_slots.as_register(), (int32_t) NULL_WORD);
+    __ jcc(Assembler::greater, L_bad);
+    __ testl(arg_slots.as_register(), -stack_move_unit() - 1);
+    __ jcc(Assembler::zero, L_ok);
+    __ bind(L_bad);
+    __ stop("assert arg_slots <= 0 and clear low bits");
+    __ bind(L_ok);
+  } else {
+    assert(arg_slots.as_constant() <= 0, "");
+    assert(arg_slots.as_constant() % -stack_move_unit() == 0, "");
+  }
+#endif //ASSERT
+
+#ifdef _LP64
+  if (arg_slots.is_register()) {
+    // clean high bits of stack motion register (was loaded as an int)
+    __ movslq(arg_slots.as_register(), arg_slots.as_register());
+  }
+#endif
+
+  // Make space on the stack for the inserted argument(s).
+  // Then pull down everything shallower than rax_argslot.
+  // The stacked return address gets pulled down with everything else.
+  // That is, copy [rsp, argslot) downward by -size words.  In pseudo-code:
+  //   rsp -= size;
+  //   for (rdx = rsp + size; rdx < argslot; rdx++)
+  //     rdx[-size] = rdx[0]
+  //   argslot -= size;
+  __ mov(rdx_temp, rsp);                        // source pointer for copy
+  __ lea(rsp, Address(rsp, arg_slots, Address::times_ptr));
+  {
+    Label loop;
+    __ bind(loop);
+    // pull one word down each time through the loop
+    __ movptr(rbx_temp, Address(rdx_temp, 0));
+    __ movptr(Address(rdx_temp, arg_slots, Address::times_ptr), rbx_temp);
+    __ addptr(rdx_temp, wordSize);
+    __ cmpptr(rdx_temp, rax_argslot);
+    __ jcc(Assembler::less, loop);
+  }
+
+  // Now move the argslot down, to point to the opened-up space.
+  __ lea(rax_argslot, Address(rax_argslot, arg_slots, Address::times_ptr));
+
+  if (TaggedStackInterpreter && arg_mask != _INSERT_NO_MASK) {
+    // The caller has specified a bitmask of tags to put into the opened space.
+    // This only works when the arg_slots value is an assembly-time constant.
+    int constant_arg_slots = arg_slots.as_constant() / stack_move_unit();
+    int tag_offset = Interpreter::tag_offset_in_bytes() - Interpreter::value_offset_in_bytes();
+    for (int slot = 0; slot < constant_arg_slots; slot++) {
+      BasicType slot_type   = ((arg_mask & (1 << slot)) == 0 ? T_OBJECT : T_INT);
+      int       slot_offset = Interpreter::stackElementSize() * slot;
+      Address   tag_addr(rax_argslot, slot_offset + tag_offset);
+      __ movptr(tag_addr, frame::tag_for_basic_type(slot_type));
+    }
+    // Note that the new argument slots are tagged properly but contain
+    // garbage at this point.  The value portions must be initialized
+    // by the caller.  (Especially references!)
+  }
+}
+
+// Helper to remove argument slots from the stack.
+// arg_slots must be a multiple of stack_move_unit() and >= 0
+void MethodHandles::remove_arg_slots(MacroAssembler* _masm,
+                                    RegisterOrConstant arg_slots,
+                                    Register rax_argslot,
+                                    Register rbx_temp, Register rdx_temp) {
+  assert_different_registers(rax_argslot, rbx_temp, rdx_temp,
+                             (!arg_slots.is_register() ? rsp : arg_slots.as_register()));
+
+#ifdef ASSERT
+  {
+    // Verify that [argslot..argslot+size) lies within (rsp, rbp).
+    Label L_ok, L_bad;
+    __ lea(rbx_temp, Address(rax_argslot, arg_slots, Address::times_ptr));
+    __ cmpptr(rbx_temp, rbp);
+    __ jcc(Assembler::above, L_bad);
+    __ cmpptr(rsp, rax_argslot);
+    __ jcc(Assembler::below, L_ok);
+    __ bind(L_bad);
+    __ stop("deleted argument(s) must fall within current frame");
+    __ bind(L_ok);
+  }
+  if (arg_slots.is_register()) {
+    Label L_ok, L_bad;
+    __ cmpptr(arg_slots.as_register(), (int32_t) NULL_WORD);
+    __ jcc(Assembler::less, L_bad);
+    __ testl(arg_slots.as_register(), -stack_move_unit() - 1);
+    __ jcc(Assembler::zero, L_ok);
+    __ bind(L_bad);
+    __ stop("assert arg_slots >= 0 and clear low bits");
+    __ bind(L_ok);
+  } else {
+    assert(arg_slots.as_constant() >= 0, "");
+    assert(arg_slots.as_constant() % -stack_move_unit() == 0, "");
+  }
+#endif //ASSERT
+
+#ifdef _LP64
+  if (false) {                  // not needed, since register is positive
+    // clean high bits of stack motion register (was loaded as an int)
+    if (arg_slots.is_register())
+      __ movslq(arg_slots.as_register(), arg_slots.as_register());
+  }
+#endif
+
+  // Pull up everything shallower than rax_argslot.
+  // Then remove the excess space on the stack.
+  // The stacked return address gets pulled up with everything else.
+  // That is, copy [rsp, argslot) upward by size words.  In pseudo-code:
+  //   for (rdx = argslot-1; rdx >= rsp; --rdx)
+  //     rdx[size] = rdx[0]
+  //   argslot += size;
+  //   rsp += size;
+  __ lea(rdx_temp, Address(rax_argslot, -wordSize)); // source pointer for copy
+  {
+    Label loop;
+    __ bind(loop);
+    // pull one word up each time through the loop
+    __ movptr(rbx_temp, Address(rdx_temp, 0));
+    __ movptr(Address(rdx_temp, arg_slots, Address::times_ptr), rbx_temp);
+    __ addptr(rdx_temp, -wordSize);
+    __ cmpptr(rdx_temp, rsp);
+    __ jcc(Assembler::greaterEqual, loop);
+  }
+
+  // Now move the argslot up, to point to the just-copied block.
+  __ lea(rsp, Address(rsp, arg_slots, Address::times_ptr));
+  // And adjust the argslot address to point at the deletion point.
+  __ lea(rax_argslot, Address(rax_argslot, arg_slots, Address::times_ptr));
+}
+
+#ifndef PRODUCT
+void trace_method_handle_stub(const char* adaptername,
+                              oop mh,
+                              intptr_t* entry_sp,
+                              intptr_t* saved_sp) {
+  // called as a leaf from native code: do not block the JVM!
+  printf("MH %s "PTR_FORMAT" "PTR_FORMAT" "INTX_FORMAT"\n", adaptername, mh, entry_sp, entry_sp - saved_sp);
+}
+#endif //PRODUCT
+
+// Generate an "entry" field for a method handle.
+// This determines how the method handle will respond to calls.
+void MethodHandles::generate_method_handle_stub(MacroAssembler* _masm, MethodHandles::EntryKind ek) {
+  // Here is the register state during an interpreted call,
+  // as set up by generate_method_handle_interpreter_entry():
+  // - rbx: garbage temp (was MethodHandle.invoke methodOop, unused)
+  // - rcx: receiver method handle
+  // - rax: method handle type (only used by the check_mtype entry point)
+  // - rsi/r13: sender SP (must preserve; see prepare_to_jump_from_interpreted)
+  // - rdx: garbage temp, can blow away
+
+  Register rcx_recv    = rcx;
+  Register rax_argslot = rax;
+  Register rbx_temp    = rbx;
+  Register rdx_temp    = rdx;
+
+  guarantee(java_dyn_MethodHandle::vmentry_offset_in_bytes() != 0, "must have offsets");
+
+  // some handy addresses
+  Address rbx_method_fie(     rbx,      methodOopDesc::from_interpreted_offset() );
+
+  Address rcx_mh_vmtarget(    rcx_recv, java_dyn_MethodHandle::vmtarget_offset_in_bytes() );
+  Address rcx_dmh_vmindex(    rcx_recv, sun_dyn_DirectMethodHandle::vmindex_offset_in_bytes() );
+
+  Address rcx_bmh_vmargslot(  rcx_recv, sun_dyn_BoundMethodHandle::vmargslot_offset_in_bytes() );
+  Address rcx_bmh_argument(   rcx_recv, sun_dyn_BoundMethodHandle::argument_offset_in_bytes() );
+
+  Address rcx_amh_vmargslot(  rcx_recv, sun_dyn_AdapterMethodHandle::vmargslot_offset_in_bytes() );
+  Address rcx_amh_argument(   rcx_recv, sun_dyn_AdapterMethodHandle::argument_offset_in_bytes() );
+  Address rcx_amh_conversion( rcx_recv, sun_dyn_AdapterMethodHandle::conversion_offset_in_bytes() );
+  Address vmarg;                // __ argument_address(vmargslot)
+
+  int tag_offset = -1;
+  if (TaggedStackInterpreter) {
+    tag_offset = Interpreter::tag_offset_in_bytes() - Interpreter::value_offset_in_bytes();
+    assert(tag_offset = wordSize, "stack grows as expected");
+  }
+
+  if (have_entry(ek)) {
+    __ nop();                   // empty stubs make SG sick
+    return;
+  }
+
+  address interp_entry = __ pc();
+  if (UseCompressedOops)  __ unimplemented("UseCompressedOops");
+
+#ifndef PRODUCT
+  if (TraceMethodHandles) {
+    __ push(rax); __ push(rbx); __ push(rcx); __ push(rdx); __ push(rsi); __ push(rdi);
+    __ lea(rax, Address(rsp, wordSize*6)); // entry_sp
+    // arguments:
+    __ push(rsi);               // saved_sp
+    __ push(rax);               // entry_sp
+    __ push(rcx);               // mh
+    __ push(rcx);
+    __ movptr(Address(rsp, 0), (intptr_t)entry_name(ek));
+    __ call_VM_leaf(CAST_FROM_FN_PTR(address, trace_method_handle_stub), 4);
+    __ pop(rdi); __ pop(rsi); __ pop(rdx); __ pop(rcx); __ pop(rbx); __ pop(rax);
+  }
+#endif //PRODUCT
+
+  switch ((int) ek) {
+  case _check_mtype:
+    {
+      // this stub is special, because it requires a live mtype argument
+      Register rax_mtype = rax;
+
+      // emit WrongMethodType path first, to enable jccb back-branch
+      Label wrong_method_type;
+      __ bind(wrong_method_type);
+      __ movptr(rdx_temp, ExternalAddress((address) &_entries[_wrong_method_type]));
+      __ jmp(Address(rdx_temp, MethodHandleEntry::from_interpreted_entry_offset_in_bytes()));
+      __ hlt();
+
+      interp_entry = __ pc();
+      __ check_method_handle_type(rax_mtype, rcx_recv, rdx_temp, wrong_method_type);
+      // now rax_mtype is dead; subsequent stubs will use it as a temp
+
+      __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
+    }
+    break;
+
+  case _wrong_method_type:
+    {
+      // this stub is special, because it requires a live mtype argument
+      Register rax_mtype = rax;
+
+      interp_entry = __ pc();
+      __ push(rax_mtype);       // required mtype
+      __ push(rcx_recv);        // random mh (1st stacked argument)
+      __ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry()));
+    }
+    break;
+
+  case _invokestatic_mh:
+  case _invokespecial_mh:
+    {
+      Register rbx_method = rbx_temp;
+      __ movptr(rbx_method, rcx_mh_vmtarget); // target is a methodOop
+      __ verify_oop(rbx_method);
+      // same as TemplateTable::invokestatic or invokespecial,
+      // minus the CP setup and profiling:
+      if (ek == _invokespecial_mh) {
+        // Must load & check the first argument before entering the target method.
+        __ load_method_handle_vmslots(rax_argslot, rcx_recv, rdx_temp);
+        __ movptr(rcx_recv, __ argument_address(rax_argslot, -1));
+        __ null_check(rcx_recv);
+        __ verify_oop(rcx_recv);
+      }
+      __ jmp(rbx_method_fie);
+    }
+    break;
+
+  case _invokevirtual_mh:
+    {
+      // same as TemplateTable::invokevirtual,
+      // minus the CP setup and profiling:
+
+      // pick out the vtable index and receiver offset from the MH,
+      // and then we can discard it:
+      __ load_method_handle_vmslots(rax_argslot, rcx_recv, rdx_temp);
+      Register rbx_index = rbx_temp;
+      __ movl(rbx_index, rcx_dmh_vmindex);
+      // Note:  The verifier allows us to ignore rcx_mh_vmtarget.
+      __ movptr(rcx_recv, __ argument_address(rax_argslot, -1));
+      __ null_check(rcx_recv, oopDesc::klass_offset_in_bytes());
+
+      // get receiver klass
+      Register rax_klass = rax_argslot;
+      __ load_klass(rax_klass, rcx_recv);
+      __ verify_oop(rax_klass);
+
+      // get target methodOop & entry point
+      const int base = instanceKlass::vtable_start_offset() * wordSize;
+      assert(vtableEntry::size() * wordSize == wordSize, "adjust the scaling in the code below");
+      Address vtable_entry_addr(rax_klass,
+                                rbx_index, Address::times_ptr,
+                                base + vtableEntry::method_offset_in_bytes());
+      Register rbx_method = rbx_temp;
+      __ movl(rbx_method, vtable_entry_addr);
+
+      __ verify_oop(rbx_method);
+      __ jmp(rbx_method_fie);
+    }
+    break;
+
+  case _invokeinterface_mh:
+    {
+      // same as TemplateTable::invokeinterface,
+      // minus the CP setup and profiling:
+
+      // pick out the interface and itable index from the MH.
+      __ load_method_handle_vmslots(rax_argslot, rcx_recv, rdx_temp);
+      Register rdx_intf  = rdx_temp;
+      Register rbx_index = rbx_temp;
+      __ movptr(rdx_intf,  rcx_mh_vmtarget);
+      __ movl(rbx_index,   rcx_dmh_vmindex);
+      __ movptr(rcx_recv, __ argument_address(rax_argslot, -1));
+      __ null_check(rcx_recv, oopDesc::klass_offset_in_bytes());
+
+      // get receiver klass
+      Register rax_klass = rax_argslot;
+      __ load_klass(rax_klass, rcx_recv);
+      __ verify_oop(rax_klass);
+
+      Register rcx_temp   = rcx_recv;
+      Register rbx_method = rbx_index;
+
+      // get interface klass
+      Label no_such_interface;
+      __ verify_oop(rdx_intf);
+      __ lookup_interface_method(rax_klass, rdx_intf,
+                                 // note: next two args must be the same:
+                                 rbx_index, rbx_method,
+                                 rcx_temp,
+                                 no_such_interface);
+
+      __ verify_oop(rbx_method);
+      __ jmp(rbx_method_fie);
+      __ hlt();
+
+      __ bind(no_such_interface);
+      // Throw an exception.
+      // For historical reasons, it will be IncompatibleClassChangeError.
+      __ should_not_reach_here(); // %%% FIXME NYI
+    }
+    break;
+
+  case _bound_ref_mh:
+  case _bound_int_mh:
+  case _bound_long_mh:
+  case _bound_ref_direct_mh:
+  case _bound_int_direct_mh:
+  case _bound_long_direct_mh:
+    {
+      bool direct_to_method = (ek >= _bound_ref_direct_mh);
+      BasicType arg_type = T_ILLEGAL;
+      if (ek == _bound_long_mh || ek == _bound_long_direct_mh) {
+        arg_type = T_LONG;
+      } else if (ek == _bound_int_mh || ek == _bound_int_direct_mh) {
+        arg_type = T_INT;
+      } else {
+        assert(ek == _bound_ref_mh || ek == _bound_ref_direct_mh, "must be ref");
+        arg_type = T_OBJECT;
+      }
+      int arg_slots = type2size[arg_type];
+      int arg_mask  = (arg_type == T_OBJECT ? _INSERT_REF_MASK :
+                       arg_slots == 1       ? _INSERT_INT_MASK :  _INSERT_LONG_MASK);
+
+      // make room for the new argument:
+      __ movl(rax_argslot, rcx_bmh_vmargslot);
+      __ lea(rax_argslot, __ argument_address(rax_argslot));
+      insert_arg_slots(_masm, arg_slots * stack_move_unit(), arg_mask,
+                       rax_argslot, rbx_temp, rdx_temp);
+
+      // store bound argument into the new stack slot:
+      __ movptr(rbx_temp, rcx_bmh_argument);
+      Address prim_value_addr(rbx_temp, java_lang_boxing_object::value_offset_in_bytes(arg_type));
+      if (arg_type == T_OBJECT) {
+        __ movptr(Address(rax_argslot, 0), rbx_temp);
+      } else {
+        __ load_sized_value(rbx_temp, prim_value_addr,
+                            type2aelembytes(arg_type), is_signed_subword_type(arg_type));
+        __ movptr(Address(rax_argslot, 0), rbx_temp);
+#ifndef _LP64
+        if (arg_slots == 2) {
+          __ movl(rbx_temp, prim_value_addr.plus_disp(wordSize));
+          __ movl(Address(rax_argslot, Interpreter::stackElementSize()), rbx_temp);
+        }
+#endif //_LP64
+        break;
+      }
+
+      if (direct_to_method) {
+        Register rbx_method = rbx_temp;
+        __ movptr(rbx_method, rcx_mh_vmtarget);
+        __ verify_oop(rbx_method);
+        __ jmp(rbx_method_fie);
+      } else {
+        __ movptr(rcx_recv, rcx_mh_vmtarget);
+        __ verify_oop(rcx_recv);
+        __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
+      }
+    }
+    break;
+
+  case _adapter_retype_only:
+    // immediately jump to the next MH layer:
+    __ movptr(rcx_recv, rcx_mh_vmtarget);
+    __ verify_oop(rcx_recv);
+    __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
+    // This is OK when all parameter types widen.
+    // It is also OK when a return type narrows.
+    break;
+
+  case _adapter_check_cast:
+    {
+      // temps:
+      Register rbx_klass = rbx_temp; // interesting AMH data
+
+      // check a reference argument before jumping to the next layer of MH:
+      __ movl(rax_argslot, rcx_amh_vmargslot);
+      vmarg = __ argument_address(rax_argslot);
+
+      // What class are we casting to?
+      __ movptr(rbx_klass, rcx_amh_argument); // this is a Class object!
+      __ movptr(rbx_klass, Address(rbx_klass, java_lang_Class::klass_offset_in_bytes()));
+
+      // get the new MH:
+      __ movptr(rcx_recv, rcx_mh_vmtarget);
+      // (now we are done with the old MH)
+
+      Label done;
+      __ movptr(rdx_temp, vmarg);
+      __ testl(rdx_temp, rdx_temp);
+      __ jcc(Assembler::zero, done);          // no cast if null
+      __ load_klass(rdx_temp, rdx_temp);
+
+      // live at this point:
+      // - rbx_klass:  klass required by the target method
+      // - rdx_temp:   argument klass to test
+      // - rcx_recv:   method handle to invoke (after cast succeeds)
+      __ check_klass_subtype(rdx_temp, rbx_klass, rax_argslot, done);
+
+      // If we get here, the type check failed!
+      // Call the wrong_method_type stub, passing the failing argument type in rax.
+      Register rax_mtype = rax_argslot;
+      __ push(rbx_klass);       // missed klass (required type)
+      __ push(rdx_temp);        // bad actual type (1st stacked argument)
+      __ jump(ExternalAddress(Interpreter::throw_WrongMethodType_entry()));
+
+      __ bind(done);
+      __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
+    }
+    break;
+
+  case _adapter_prim_to_prim:
+  case _adapter_ref_to_prim:
+    // handled completely by optimized cases
+    __ stop("init_AdapterMethodHandle should not issue this");
+    break;
+
+  case _adapter_opt_i2i:        // optimized subcase of adapt_prim_to_prim
+//case _adapter_opt_f2i:        // optimized subcase of adapt_prim_to_prim
+  case _adapter_opt_l2i:        // optimized subcase of adapt_prim_to_prim
+  case _adapter_opt_unboxi:     // optimized subcase of adapt_ref_to_prim
+    {
+      // perform an in-place conversion to int or an int subword
+      __ movl(rax_argslot, rcx_amh_vmargslot);
+      vmarg = __ argument_address(rax_argslot);
+
+      switch (ek) {
+      case _adapter_opt_i2i:
+        __ movl(rdx_temp, vmarg);
+        break;
+      case _adapter_opt_l2i:
+        {
+          // just delete the extra slot; on a little-endian machine we keep the first
+          __ lea(rax_argslot, __ argument_address(rax_argslot, 1));
+          remove_arg_slots(_masm, -stack_move_unit(),
+                           rax_argslot, rbx_temp, rdx_temp);
+          vmarg = Address(rax_argslot, -Interpreter::stackElementSize());
+          __ movl(rdx_temp, vmarg);
+        }
+        break;
+      case _adapter_opt_unboxi:
+        {
+          // Load the value up from the heap.
+          __ movptr(rdx_temp, vmarg);
+          int value_offset = java_lang_boxing_object::value_offset_in_bytes(T_INT);
+#ifdef ASSERT
+          for (int bt = T_BOOLEAN; bt < T_INT; bt++) {
+            if (is_subword_type(BasicType(bt)))
+              assert(value_offset == java_lang_boxing_object::value_offset_in_bytes(BasicType(bt)), "");
+          }
+#endif
+          __ null_check(rdx_temp, value_offset);
+          __ movl(rdx_temp, Address(rdx_temp, value_offset));
+          // We load this as a word.  Because we are little-endian,
+          // the low bits will be correct, but the high bits may need cleaning.
+          // The vminfo will guide us to clean those bits.
+        }
+        break;
+      default:
+        assert(false, "");
+      }
+      goto finish_int_conversion;
+    }
+
+  finish_int_conversion:
+    {
+      Register rbx_vminfo = rbx_temp;
+      __ movl(rbx_vminfo, rcx_amh_conversion);
+      assert(CONV_VMINFO_SHIFT == 0, "preshifted");
+
+      // get the new MH:
+      __ movptr(rcx_recv, rcx_mh_vmtarget);
+      // (now we are done with the old MH)
+
+      // original 32-bit vmdata word must be of this form:
+      //    | MBZ:16 | signBitCount:8 | srcDstTypes:8 | conversionOp:8 |
+      __ xchgl(rcx, rbx_vminfo);                // free rcx for shifts
+      __ shll(rdx_temp /*, rcx*/);
+      Label zero_extend, done;
+      __ testl(rcx, CONV_VMINFO_SIGN_FLAG);
+      __ jcc(Assembler::zero, zero_extend);
+
+      // this path is taken for int->byte, int->short
+      __ sarl(rdx_temp /*, rcx*/);
+      __ jmp(done);
+
+      __ bind(zero_extend);
+      // this is taken for int->char
+      __ shrl(rdx_temp /*, rcx*/);
+
+      __ bind(done);
+      __ movptr(vmarg, rdx_temp);
+      __ xchgl(rcx, rbx_vminfo);                // restore rcx_recv
+
+      __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
+    }
+    break;
+
+  case _adapter_opt_i2l:        // optimized subcase of adapt_prim_to_prim
+  case _adapter_opt_unboxl:     // optimized subcase of adapt_ref_to_prim
+    {
+      // perform an in-place int-to-long or ref-to-long conversion
+      __ movl(rax_argslot, rcx_amh_vmargslot);
+
+      // on a little-endian machine we keep the first slot and add another after
+      __ lea(rax_argslot, __ argument_address(rax_argslot, 1));
+      insert_arg_slots(_masm, stack_move_unit(), _INSERT_INT_MASK,
+                       rax_argslot, rbx_temp, rdx_temp);
+      Address vmarg1(rax_argslot, -Interpreter::stackElementSize());
+      Address vmarg2 = vmarg1.plus_disp(Interpreter::stackElementSize());
+
+      switch (ek) {
+      case _adapter_opt_i2l:
+        {
+          __ movl(rdx_temp, vmarg1);
+          __ sarl(rdx_temp, 31);  // __ extend_sign()
+          __ movl(vmarg2, rdx_temp); // store second word
+        }
+        break;
+      case _adapter_opt_unboxl:
+        {
+          // Load the value up from the heap.
+          __ movptr(rdx_temp, vmarg1);
+          int value_offset = java_lang_boxing_object::value_offset_in_bytes(T_LONG);
+          assert(value_offset == java_lang_boxing_object::value_offset_in_bytes(T_DOUBLE), "");
+          __ null_check(rdx_temp, value_offset);
+          __ movl(rbx_temp, Address(rdx_temp, value_offset + 0*BytesPerInt));
+          __ movl(rdx_temp, Address(rdx_temp, value_offset + 1*BytesPerInt));
+          __ movl(vmarg1, rbx_temp);
+          __ movl(vmarg2, rdx_temp);
+        }
+        break;
+      default:
+        assert(false, "");
+      }
+
+      __ movptr(rcx_recv, rcx_mh_vmtarget);
+      __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
+    }
+    break;
+
+  case _adapter_opt_f2d:        // optimized subcase of adapt_prim_to_prim
+  case _adapter_opt_d2f:        // optimized subcase of adapt_prim_to_prim
+    {
+      // perform an in-place floating primitive conversion
+      __ movl(rax_argslot, rcx_amh_vmargslot);
+      __ lea(rax_argslot, __ argument_address(rax_argslot, 1));
+      if (ek == _adapter_opt_f2d) {
+        insert_arg_slots(_masm, stack_move_unit(), _INSERT_INT_MASK,
+                         rax_argslot, rbx_temp, rdx_temp);
+      }
+      Address vmarg(rax_argslot, -Interpreter::stackElementSize());
+
+#ifdef _LP64
+      if (ek == _adapter_opt_f2d) {
+        __ movflt(xmm0, vmarg);
+        __ cvtss2sd(xmm0, xmm0);
+        __ movdbl(vmarg, xmm0);
+      } else {
+        __ movdbl(xmm0, vmarg);
+        __ cvtsd2ss(xmm0, xmm0);
+        __ movflt(vmarg, xmm0);
+      }
+#else //_LP64
+      if (ek == _adapter_opt_f2d) {
+        __ fld_s(vmarg);        // load float to ST0
+        __ fstp_s(vmarg);       // store single
+      } else if (!TaggedStackInterpreter) {
+        __ fld_d(vmarg);        // load double to ST0
+        __ fstp_s(vmarg);       // store single
+      } else {
+        Address vmarg_tag = vmarg.plus_disp(tag_offset);
+        Address vmarg2    = vmarg.plus_disp(Interpreter::stackElementSize());
+        // vmarg2_tag does not participate in this code
+        Register rbx_tag = rbx_temp;
+        __ movl(rbx_tag, vmarg_tag); // preserve tag
+        __ movl(rdx_temp, vmarg2); // get second word of double
+        __ movl(vmarg_tag, rdx_temp); // align with first word
+        __ fld_d(vmarg);        // load double to ST0
+        __ movl(vmarg_tag, rbx_tag); // restore tag
+        __ fstp_s(vmarg);       // store single
+      }
+#endif //_LP64
+
+      if (ek == _adapter_opt_d2f) {
+        remove_arg_slots(_masm, -stack_move_unit(),
+                         rax_argslot, rbx_temp, rdx_temp);
+      }
+
+      __ movptr(rcx_recv, rcx_mh_vmtarget);
+      __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
+    }
+    break;
+
+  case _adapter_prim_to_ref:
+    __ unimplemented(entry_name(ek)); // %%% FIXME: NYI
+    break;
+
+  case _adapter_swap_args:
+  case _adapter_rot_args:
+    // handled completely by optimized cases
+    __ stop("init_AdapterMethodHandle should not issue this");
+    break;
+
+  case _adapter_opt_swap_1:
+  case _adapter_opt_swap_2:
+  case _adapter_opt_rot_1_up:
+  case _adapter_opt_rot_1_down:
+  case _adapter_opt_rot_2_up:
+  case _adapter_opt_rot_2_down:
+    {
+      int rotate = 0, swap_slots = 0;
+      switch ((int)ek) {
+      case _adapter_opt_swap_1:     swap_slots = 1; break;
+      case _adapter_opt_swap_2:     swap_slots = 2; break;
+      case _adapter_opt_rot_1_up:   swap_slots = 1; rotate++; break;
+      case _adapter_opt_rot_1_down: swap_slots = 1; rotate--; break;
+      case _adapter_opt_rot_2_up:   swap_slots = 2; rotate++; break;
+      case _adapter_opt_rot_2_down: swap_slots = 2; rotate--; break;
+      default: assert(false, "");
+      }
+
+      // the real size of the move must be doubled if TaggedStackInterpreter:
+      int swap_bytes = (int)( swap_slots * Interpreter::stackElementWords() * wordSize );
+
+      // 'argslot' is the position of the first argument to swap
+      __ movl(rax_argslot, rcx_amh_vmargslot);
+      __ lea(rax_argslot, __ argument_address(rax_argslot));
+
+      // 'vminfo' is the second
+      Register rbx_destslot = rbx_temp;
+      __ movl(rbx_destslot, rcx_amh_conversion);
+      assert(CONV_VMINFO_SHIFT == 0, "preshifted");
+      __ andl(rbx_destslot, CONV_VMINFO_MASK);
+      __ lea(rbx_destslot, __ argument_address(rbx_destslot));
+      DEBUG_ONLY(verify_argslot(_masm, rbx_destslot, "swap point must fall within current frame"));
+
+      if (!rotate) {
+        for (int i = 0; i < swap_bytes; i += wordSize) {
+          __ movptr(rdx_temp, Address(rax_argslot , i));
+          __ push(rdx_temp);
+          __ movptr(rdx_temp, Address(rbx_destslot, i));
+          __ movptr(Address(rax_argslot, i), rdx_temp);
+          __ pop(rdx_temp);
+          __ movptr(Address(rbx_destslot, i), rdx_temp);
+        }
+      } else {
+        // push the first chunk, which is going to get overwritten
+        for (int i = swap_bytes; (i -= wordSize) >= 0; ) {
+          __ movptr(rdx_temp, Address(rax_argslot, i));
+          __ push(rdx_temp);
+        }
+
+        if (rotate > 0) {
+          // rotate upward
+          __ subptr(rax_argslot, swap_bytes);
+#ifdef ASSERT
+          {
+            // Verify that argslot > destslot, by at least swap_bytes.
+            Label L_ok;
+            __ cmpptr(rax_argslot, rbx_destslot);
+            __ jcc(Assembler::aboveEqual, L_ok);
+            __ stop("source must be above destination (upward rotation)");
+            __ bind(L_ok);
+          }
+#endif
+          // work argslot down to destslot, copying contiguous data upwards
+          // pseudo-code:
+          //   rax = src_addr - swap_bytes
+          //   rbx = dest_addr
+          //   while (rax >= rbx) *(rax + swap_bytes) = *(rax + 0), rax--;
+          Label loop;
+          __ bind(loop);
+          __ movptr(rdx_temp, Address(rax_argslot, 0));
+          __ movptr(Address(rax_argslot, swap_bytes), rdx_temp);
+          __ addptr(rax_argslot, -wordSize);
+          __ cmpptr(rax_argslot, rbx_destslot);
+          __ jcc(Assembler::aboveEqual, loop);
+        } else {
+          __ addptr(rax_argslot, swap_bytes);
+#ifdef ASSERT
+          {
+            // Verify that argslot < destslot, by at least swap_bytes.
+            Label L_ok;
+            __ cmpptr(rax_argslot, rbx_destslot);
+            __ jcc(Assembler::belowEqual, L_ok);
+            __ stop("source must be below destination (downward rotation)");
+            __ bind(L_ok);
+          }
+#endif
+          // work argslot up to destslot, copying contiguous data downwards
+          // pseudo-code:
+          //   rax = src_addr + swap_bytes
+          //   rbx = dest_addr
+          //   while (rax <= rbx) *(rax - swap_bytes) = *(rax + 0), rax++;
+          Label loop;
+          __ bind(loop);
+          __ movptr(rdx_temp, Address(rax_argslot, 0));
+          __ movptr(Address(rax_argslot, -swap_bytes), rdx_temp);
+          __ addptr(rax_argslot, wordSize);
+          __ cmpptr(rax_argslot, rbx_destslot);
+          __ jcc(Assembler::belowEqual, loop);
+        }
+
+        // pop the original first chunk into the destination slot, now free
+        for (int i = 0; i < swap_bytes; i += wordSize) {
+          __ pop(rdx_temp);
+          __ movptr(Address(rbx_destslot, i), rdx_temp);
+        }
+      }
+
+      __ movptr(rcx_recv, rcx_mh_vmtarget);
+      __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
+    }
+    break;
+
+  case _adapter_dup_args:
+    {
+      // 'argslot' is the position of the first argument to duplicate
+      __ movl(rax_argslot, rcx_amh_vmargslot);
+      __ lea(rax_argslot, __ argument_address(rax_argslot));
+
+      // 'stack_move' is negative number of words to duplicate
+      Register rdx_stack_move = rdx_temp;
+      __ movl(rdx_stack_move, rcx_amh_conversion);
+      __ sarl(rdx_stack_move, CONV_STACK_MOVE_SHIFT);
+
+      int argslot0_num = 0;
+      Address argslot0 = __ argument_address(RegisterOrConstant(argslot0_num));
+      assert(argslot0.base() == rsp, "");
+      int pre_arg_size = argslot0.disp();
+      assert(pre_arg_size % wordSize == 0, "");
+      assert(pre_arg_size > 0, "must include PC");
+
+      // remember the old rsp+1 (argslot[0])
+      Register rbx_oldarg = rbx_temp;
+      __ lea(rbx_oldarg, argslot0);
+
+      // move rsp down to make room for dups
+      __ lea(rsp, Address(rsp, rdx_stack_move, Address::times_ptr));
+
+      // compute the new rsp+1 (argslot[0])
+      Register rdx_newarg = rdx_temp;
+      __ lea(rdx_newarg, argslot0);
+
+      __ push(rdi);             // need a temp
+      // (preceding push must be done after arg addresses are taken!)
+
+      // pull down the pre_arg_size data (PC)
+      for (int i = -pre_arg_size; i < 0; i += wordSize) {
+        __ movptr(rdi, Address(rbx_oldarg, i));
+        __ movptr(Address(rdx_newarg, i), rdi);
+      }
+
+      // copy from rax_argslot[0...] down to new_rsp[1...]
+      // pseudo-code:
+      //   rbx = old_rsp+1
+      //   rdx = new_rsp+1
+      //   rax = argslot
+      //   while (rdx < rbx) *rdx++ = *rax++
+      Label loop;
+      __ bind(loop);
+      __ movptr(rdi, Address(rax_argslot, 0));
+      __ movptr(Address(rdx_newarg, 0), rdi);
+      __ addptr(rax_argslot, wordSize);
+      __ addptr(rdx_newarg, wordSize);
+      __ cmpptr(rdx_newarg, rbx_oldarg);
+      __ jcc(Assembler::less, loop);
+
+      __ pop(rdi);              // restore temp
+
+      __ movptr(rcx_recv, rcx_mh_vmtarget);
+      __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
+    }
+    break;
+
+  case _adapter_drop_args:
+    {
+      // 'argslot' is the position of the first argument to nuke
+      __ movl(rax_argslot, rcx_amh_vmargslot);
+      __ lea(rax_argslot, __ argument_address(rax_argslot));
+
+      __ push(rdi);             // need a temp
+      // (must do previous push after argslot address is taken)
+
+      // 'stack_move' is number of words to drop
+      Register rdi_stack_move = rdi;
+      __ movl(rdi_stack_move, rcx_amh_conversion);
+      __ sarl(rdi_stack_move, CONV_STACK_MOVE_SHIFT);
+      remove_arg_slots(_masm, rdi_stack_move,
+                       rax_argslot, rbx_temp, rdx_temp);
+
+      __ pop(rdi);              // restore temp
+
+      __ movptr(rcx_recv, rcx_mh_vmtarget);
+      __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
+    }
+    break;
+
+  case _adapter_collect_args:
+    __ unimplemented(entry_name(ek)); // %%% FIXME: NYI
+    break;
+
+  case _adapter_spread_args:
+    // handled completely by optimized cases
+    __ stop("init_AdapterMethodHandle should not issue this");
+    break;
+
+  case _adapter_opt_spread_0:
+  case _adapter_opt_spread_1:
+  case _adapter_opt_spread_more:
+    {
+      // spread an array out into a group of arguments
+      int length_constant = -1;
+      switch (ek) {
+      case _adapter_opt_spread_0: length_constant = 0; break;
+      case _adapter_opt_spread_1: length_constant = 1; break;
+      }
+
+      // find the address of the array argument
+      __ movl(rax_argslot, rcx_amh_vmargslot);
+      __ lea(rax_argslot, __ argument_address(rax_argslot));
+
+      // grab some temps
+      { __ push(rsi); __ push(rdi); }
+      // (preceding pushes must be done after argslot address is taken!)
+#define UNPUSH_RSI_RDI \
+      { __ pop(rdi); __ pop(rsi); }
+
+      // arx_argslot points both to the array and to the first output arg
+      vmarg = Address(rax_argslot, 0);
+
+      // Get the array value.
+      Register  rsi_array       = rsi;
+      Register  rdx_array_klass = rdx_temp;
+      BasicType elem_type       = T_OBJECT;
+      int       length_offset   = arrayOopDesc::length_offset_in_bytes();
+      int       elem0_offset    = arrayOopDesc::base_offset_in_bytes(elem_type);
+      __ movptr(rsi_array, vmarg);
+      Label skip_array_check;
+      if (length_constant == 0) {
+        __ testptr(rsi_array, rsi_array);
+        __ jcc(Assembler::zero, skip_array_check);
+      }
+      __ null_check(rsi_array, oopDesc::klass_offset_in_bytes());
+      __ load_klass(rdx_array_klass, rsi_array);
+
+      // Check the array type.
+      Register rbx_klass = rbx_temp;
+      __ movptr(rbx_klass, rcx_amh_argument); // this is a Class object!
+      __ movptr(rbx_klass, Address(rbx_klass, java_lang_Class::klass_offset_in_bytes()));
+
+      Label ok_array_klass, bad_array_klass, bad_array_length;
+      __ check_klass_subtype(rdx_array_klass, rbx_klass, rdi, ok_array_klass);
+      // If we get here, the type check failed!
+      __ jmp(bad_array_klass);
+      __ bind(ok_array_klass);
+
+      // Check length.
+      if (length_constant >= 0) {
+        __ cmpl(Address(rsi_array, length_offset), length_constant);
+      } else {
+        Register rbx_vminfo = rbx_temp;
+        __ movl(rbx_vminfo, rcx_amh_conversion);
+        assert(CONV_VMINFO_SHIFT == 0, "preshifted");
+        __ andl(rbx_vminfo, CONV_VMINFO_MASK);
+        __ cmpl(rbx_vminfo, Address(rsi_array, length_offset));
+      }
+      __ jcc(Assembler::notEqual, bad_array_length);
+
+      Register rdx_argslot_limit = rdx_temp;
+
+      // Array length checks out.  Now insert any required stack slots.
+      if (length_constant == -1) {
+        // Form a pointer to the end of the affected region.
+        __ lea(rdx_argslot_limit, Address(rax_argslot, Interpreter::stackElementSize()));
+        // 'stack_move' is negative number of words to insert
+        Register rdi_stack_move = rdi;
+        __ movl(rdi_stack_move, rcx_amh_conversion);
+        __ sarl(rdi_stack_move, CONV_STACK_MOVE_SHIFT);
+        Register rsi_temp = rsi_array;  // spill this
+        insert_arg_slots(_masm, rdi_stack_move, -1,
+                         rax_argslot, rbx_temp, rsi_temp);
+        // reload the array (since rsi was killed)
+        __ movptr(rsi_array, vmarg);
+      } else if (length_constant > 1) {
+        int arg_mask = 0;
+        int new_slots = (length_constant - 1);
+        for (int i = 0; i < new_slots; i++) {
+          arg_mask <<= 1;
+          arg_mask |= _INSERT_REF_MASK;
+        }
+        insert_arg_slots(_masm, new_slots * stack_move_unit(), arg_mask,
+                         rax_argslot, rbx_temp, rdx_temp);
+      } else if (length_constant == 1) {
+        // no stack resizing required
+      } else if (length_constant == 0) {
+        remove_arg_slots(_masm, -stack_move_unit(),
+                         rax_argslot, rbx_temp, rdx_temp);
+      }
+
+      // Copy from the array to the new slots.
+      // Note: Stack change code preserves integrity of rax_argslot pointer.
+      // So even after slot insertions, rax_argslot still points to first argument.
+      if (length_constant == -1) {
+        // [rax_argslot, rdx_argslot_limit) is the area we are inserting into.
+        Register rsi_source = rsi_array;
+        __ lea(rsi_source, Address(rsi_array, elem0_offset));
+        Label loop;
+        __ bind(loop);
+        __ movptr(rbx_temp, Address(rsi_source, 0));
+        __ movptr(Address(rax_argslot, 0), rbx_temp);
+        __ addptr(rsi_source, type2aelembytes(elem_type));
+        if (TaggedStackInterpreter) {
+          __ movptr(Address(rax_argslot, tag_offset),
+                    frame::tag_for_basic_type(elem_type));
+        }
+        __ addptr(rax_argslot, Interpreter::stackElementSize());
+        __ cmpptr(rax_argslot, rdx_argslot_limit);
+        __ jcc(Assembler::less, loop);
+      } else if (length_constant == 0) {
+        __ bind(skip_array_check);
+        // nothing to copy
+      } else {
+        int elem_offset = elem0_offset;
+        int slot_offset = 0;
+        for (int index = 0; index < length_constant; index++) {
+          __ movptr(rbx_temp, Address(rsi_array, elem_offset));
+          __ movptr(Address(rax_argslot, slot_offset), rbx_temp);
+          elem_offset += type2aelembytes(elem_type);
+          if (TaggedStackInterpreter) {
+            __ movptr(Address(rax_argslot, slot_offset + tag_offset),
+                      frame::tag_for_basic_type(elem_type));
+          }
+          slot_offset += Interpreter::stackElementSize();
+        }
+      }
+
+      // Arguments are spread.  Move to next method handle.
+      UNPUSH_RSI_RDI;
+      __ movptr(rcx_recv, rcx_mh_vmtarget);
+      __ jump_to_method_handle_entry(rcx_recv, rdx_temp);
+
+      __ bind(bad_array_klass);
+      UNPUSH_RSI_RDI;
+      __ stop("bad array klass NYI");
+
+      __ bind(bad_array_length);
+      UNPUSH_RSI_RDI;
+      __ stop("bad array length NYI");
+
+#undef UNPUSH_RSI_RDI
+    }
+    break;
+
+  case _adapter_flyby:
+  case _adapter_ricochet:
+    __ unimplemented(entry_name(ek)); // %%% FIXME: NYI
+    break;
+
+  default:  ShouldNotReachHere();
+  }
+  __ hlt();
+
+  address me_cookie = MethodHandleEntry::start_compiled_entry(_masm, interp_entry);
+  __ unimplemented(entry_name(ek)); // %%% FIXME: NYI
+
+  init_entry(ek, MethodHandleEntry::finish_compiled_entry(_masm, me_cookie));
+}
--- a/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/cpu/x86/vm/stubGenerator_x86_32.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -2219,6 +2219,16 @@
 
     // arraycopy stubs used by compilers
     generate_arraycopy_stubs();
+
+    // generic method handle stubs
+    if (EnableMethodHandles && SystemDictionary::MethodHandle_klass() != NULL) {
+      for (MethodHandles::EntryKind ek = MethodHandles::_EK_FIRST;
+           ek < MethodHandles::_EK_LIMIT;
+           ek = MethodHandles::EntryKind(1 + (int)ek)) {
+        StubCodeMark mark(this, "MethodHandle", MethodHandles::entry_name(ek));
+        MethodHandles::generate_method_handle_stub(_masm, ek);
+      }
+    }
   }
 
 
--- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -92,6 +92,33 @@
   return entry;
 }
 
+// Arguments are: required type at TOS+8, failing object (or NULL) at TOS+4.
+// pc at TOS (just for debugging)
+address TemplateInterpreterGenerator::generate_WrongMethodType_handler() {
+  address entry = __ pc();
+
+  __ pop(rbx);                  // actual failing object is at TOS
+  __ pop(rax);                  // required type is at TOS+4
+
+  __ verify_oop(rbx);
+  __ verify_oop(rax);
+
+  // Various method handle types use interpreter registers as temps.
+  __ restore_bcp();
+  __ restore_locals();
+
+  // Expression stack must be empty before entering the VM for an exception.
+  __ empty_expression_stack();
+  __ empty_FPU_stack();
+  __ call_VM(noreg,
+             CAST_FROM_FN_PTR(address,
+                              InterpreterRuntime::throw_WrongMethodTypeException),
+             // pass required type, failing object (or NULL)
+             rax, rbx);
+  return entry;
+}
+
+
 address TemplateInterpreterGenerator::generate_exception_handler_common(const char* name, const char* message, bool pass_oop) {
   assert(!pass_oop || message == NULL, "either oop or message but not both");
   address entry = __ pc();
@@ -1370,6 +1397,7 @@
     case Interpreter::empty                  : entry_point = ((InterpreterGenerator*)this)->generate_empty_entry();        break;
     case Interpreter::accessor               : entry_point = ((InterpreterGenerator*)this)->generate_accessor_entry();     break;
     case Interpreter::abstract               : entry_point = ((InterpreterGenerator*)this)->generate_abstract_entry();     break;
+    case Interpreter::method_handle          : entry_point = ((InterpreterGenerator*)this)->generate_method_handle_entry(); break;
 
     case Interpreter::java_lang_math_sin     : // fall thru
     case Interpreter::java_lang_math_cos     : // fall thru
@@ -1400,7 +1428,8 @@
   // be sure to change this if you add/subtract anything to/from the overhead area
   const int overhead_size = -frame::interpreter_frame_initial_sp_offset;
 
-  const int method_stack = (method->max_locals() + method->max_stack()) *
+  const int extra_stack = methodOopDesc::extra_stack_entries();
+  const int method_stack = (method->max_locals() + method->max_stack() + extra_stack) *
                            Interpreter::stackElementWords();
   return overhead_size + method_stack + stub_code;
 }
--- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2003-2009 Sun Microsystems, Inc.  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
@@ -100,6 +100,26 @@
   return entry;
 }
 
+// Arguments are: required type in rarg1, failing object (or NULL) in rarg2
+address TemplateInterpreterGenerator::generate_WrongMethodType_handler() {
+  address entry = __ pc();
+
+  __ pop(c_rarg2);              // failing object is at TOS
+  __ pop(c_rarg1);              // required type is at TOS+8
+
+  // expression stack must be empty before entering the VM if an
+  // exception happened
+  __ empty_expression_stack();
+
+  __ call_VM(noreg,
+             CAST_FROM_FN_PTR(address,
+                              InterpreterRuntime::
+                              throw_WrongMethodTypeException),
+             // pass required type, failing object (or NULL)
+             c_rarg1, c_rarg2);
+  return entry;
+}
+
 address TemplateInterpreterGenerator::generate_exception_handler_common(
         const char* name, const char* message, bool pass_oop) {
   assert(!pass_oop || message == NULL, "either oop or message but not both");
@@ -1393,12 +1413,14 @@
   case Interpreter::empty                  : entry_point = ((InterpreterGenerator*) this)->generate_empty_entry();       break;
   case Interpreter::accessor               : entry_point = ((InterpreterGenerator*) this)->generate_accessor_entry();    break;
   case Interpreter::abstract               : entry_point = ((InterpreterGenerator*) this)->generate_abstract_entry();    break;
-  case Interpreter::java_lang_math_sin     :                                                                             break;
-  case Interpreter::java_lang_math_cos     :                                                                             break;
-  case Interpreter::java_lang_math_tan     :                                                                             break;
-  case Interpreter::java_lang_math_abs     :                                                                             break;
-  case Interpreter::java_lang_math_log     :                                                                             break;
-  case Interpreter::java_lang_math_log10   :                                                                             break;
+  case Interpreter::method_handle          : entry_point = ((InterpreterGenerator*) this)->generate_method_handle_entry();break;
+
+  case Interpreter::java_lang_math_sin     : // fall thru
+  case Interpreter::java_lang_math_cos     : // fall thru
+  case Interpreter::java_lang_math_tan     : // fall thru
+  case Interpreter::java_lang_math_abs     : // fall thru
+  case Interpreter::java_lang_math_log     : // fall thru
+  case Interpreter::java_lang_math_log10   : // fall thru
   case Interpreter::java_lang_math_sqrt    : entry_point = ((InterpreterGenerator*) this)->generate_math_entry(kind);    break;
   default                                  : ShouldNotReachHere();                                                       break;
   }
@@ -1422,7 +1444,8 @@
     -(frame::interpreter_frame_initial_sp_offset) + entry_size;
 
   const int stub_code = frame::entry_frame_after_call_words;
-  const int method_stack = (method->max_locals() + method->max_stack()) *
+  const int extra_stack = methodOopDesc::extra_stack_entries();
+  const int method_stack = (method->max_locals() + method->max_stack() + extra_stack) *
                            Interpreter::stackElementWords();
   return (overhead_size + method_stack + stub_code);
 }
--- a/hotspot/src/cpu/x86/vm/vtableStubs_x86_32.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/cpu/x86/vm/vtableStubs_x86_32.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -108,6 +108,9 @@
                   (int)(s->code_end() - __ pc()));
   }
   guarantee(__ pc() <= s->code_end(), "overflowed buffer");
+  // shut the door on sizing bugs
+  int slop = 3;  // 32-bit offset is this much larger than an 8-bit one
+  assert(vtable_index > 10 || __ pc() + slop <= s->code_end(), "room for 32-bit offset");
 
   s->set_exception_points(npe_addr, ame_addr);
   return s;
@@ -181,6 +184,9 @@
                   (int)(s->code_end() - __ pc()));
   }
   guarantee(__ pc() <= s->code_end(), "overflowed buffer");
+  // shut the door on sizing bugs
+  int slop = 3;  // 32-bit offset is this much larger than an 8-bit one
+  assert(itable_index > 10 || __ pc() + slop <= s->code_end(), "room for 32-bit offset");
 
   s->set_exception_points(npe_addr, ame_addr);
   return s;
@@ -196,6 +202,41 @@
     // Itable stub size
     return (DebugVtables ? 256 : 66) + (CountCompiledCalls ? 6 : 0);
   }
+  // In order to tune these parameters, run the JVM with VM options
+  // +PrintMiscellaneous and +WizardMode to see information about
+  // actual itable stubs.  Look for lines like this:
+  //   itable #1 at 0x5551212[65] left over: 3
+  // Reduce the constants so that the "left over" number is >=3
+  // for the common cases.
+  // Do not aim at a left-over number of zero, because a
+  // large vtable or itable index (> 16) will require a 32-bit
+  // immediate displacement instead of an 8-bit one.
+  //
+  // The JVM98 app. _202_jess has a megamorphic interface call.
+  // The itable code looks like this:
+  // Decoding VtableStub itbl[1]@1
+  //   mov    0x4(%ecx),%esi
+  //   mov    0xe8(%esi),%edi
+  //   lea    0x130(%esi,%edi,4),%edi
+  //   add    $0x7,%edi
+  //   and    $0xfffffff8,%edi
+  //   lea    0x4(%esi),%esi
+  //   mov    (%edi),%ebx
+  //   cmp    %ebx,%eax
+  //   je     success
+  // loop:
+  //   test   %ebx,%ebx
+  //   je     throw_icce
+  //   add    $0x8,%edi
+  //   mov    (%edi),%ebx
+  //   cmp    %ebx,%eax
+  //   jne    loop
+  // success:
+  //   mov    0x4(%edi),%edi
+  //   mov    (%esi,%edi,1),%ebx
+  //   jmp    *0x44(%ebx)
+  // throw_icce:
+  //   jmp    throw_ICCE_entry
 }
 
 int VtableStub::pd_code_alignment() {
--- a/hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/cpu/x86/vm/vtableStubs_x86_64.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -106,6 +106,9 @@
                   (int)(s->code_end() - __ pc()));
   }
   guarantee(__ pc() <= s->code_end(), "overflowed buffer");
+  // shut the door on sizing bugs
+  int slop = 3;  // 32-bit offset is this much larger than an 8-bit one
+  assert(vtable_index > 10 || __ pc() + slop <= s->code_end(), "room for 32-bit offset");
 
   s->set_exception_points(npe_addr, ame_addr);
   return s;
@@ -191,6 +194,9 @@
                   (int)(s->code_end() - __ pc()));
   }
   guarantee(__ pc() <= s->code_end(), "overflowed buffer");
+  // shut the door on sizing bugs
+  int slop = 3;  // 32-bit offset is this much larger than an 8-bit one
+  assert(itable_index > 10 || __ pc() + slop <= s->code_end(), "room for 32-bit offset");
 
   s->set_exception_points(npe_addr, ame_addr);
   return s;
@@ -206,6 +212,39 @@
     return (DebugVtables ? 512 : 72) + (CountCompiledCalls ? 13 : 0) +
            (UseCompressedOops ? 32 : 0);  // 2 leaqs
   }
+  // In order to tune these parameters, run the JVM with VM options
+  // +PrintMiscellaneous and +WizardMode to see information about
+  // actual itable stubs.  Look for lines like this:
+  //   itable #1 at 0x5551212[71] left over: 3
+  // Reduce the constants so that the "left over" number is >=3
+  // for the common cases.
+  // Do not aim at a left-over number of zero, because a
+  // large vtable or itable index (>= 32) will require a 32-bit
+  // immediate displacement instead of an 8-bit one.
+  //
+  // The JVM98 app. _202_jess has a megamorphic interface call.
+  // The itable code looks like this:
+  // Decoding VtableStub itbl[1]@12
+  //   mov    0x8(%rsi),%r10
+  //   mov    0x198(%r10),%r11d
+  //   lea    0x218(%r10,%r11,8),%r11
+  //   lea    0x8(%r10),%r10
+  //   mov    (%r11),%rbx
+  //   cmp    %rbx,%rax
+  //   je     success
+  // loop:
+  //   test   %rbx,%rbx
+  //   je     throw_icce
+  //   add    $0x10,%r11
+  //   mov    (%r11),%rbx
+  //   cmp    %rbx,%rax
+  //   jne    loop
+  // success:
+  //   mov    0x8(%r11),%r11d
+  //   mov    (%r10,%r11,1),%rbx
+  //   jmpq   *0x60(%rbx)
+  // throw_icce:
+  //   jmpq   throw_ICCE_entry
 }
 
 int VtableStub::pd_code_alignment() {
--- a/hotspot/src/share/vm/ci/ciMethod.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/ci/ciMethod.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 1999-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1999-2009 Sun Microsystems, Inc.  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
@@ -675,6 +675,30 @@
 }
 
 // ------------------------------------------------------------------
+// invokedynamic support
+//
+bool ciMethod::is_method_handle_invoke() {
+  check_is_loaded();
+  bool flag = ((flags().as_int() & JVM_MH_INVOKE_BITS) == JVM_MH_INVOKE_BITS);
+#ifdef ASSERT
+  {
+    VM_ENTRY_MARK;
+    bool flag2 = get_methodOop()->is_method_handle_invoke();
+    assert(flag == flag2, "consistent");
+  }
+#endif //ASSERT
+  return flag;
+}
+
+ciInstance* ciMethod::method_handle_type() {
+  check_is_loaded();
+  VM_ENTRY_MARK;
+  oop mtype = get_methodOop()->method_handle_type();
+  return CURRENT_THREAD_ENV->get_object(mtype)->as_instance();
+}
+
+
+// ------------------------------------------------------------------
 // ciMethod::build_method_data
 //
 // Generate new methodDataOop objects at compile time.
--- a/hotspot/src/share/vm/ci/ciMethod.hpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/ci/ciMethod.hpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 1999-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1999-2009 Sun Microsystems, Inc.  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
@@ -207,6 +207,8 @@
   bool check_call(int refinfo_index, bool is_static) const;
   void build_method_data();  // make sure it exists in the VM also
   int scale_count(int count, float prof_factor = 1.);  // make MDO count commensurate with IIC
+  bool is_method_handle_invoke();
+  ciInstance* method_handle_type();
 
   // What kind of ciObject is this?
   bool is_method()                               { return true; }
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1842,6 +1842,11 @@
     _has_vanilla_constructor = true;
   }
 
+  if (EnableMethodHandles && m->is_method_handle_invoke()) {
+    THROW_MSG_(vmSymbols::java_lang_VirtualMachineError(),
+               "Method handle invokers must be defined internally to the VM", nullHandle);
+  }
+
   return m;
 }
 
@@ -2465,9 +2470,84 @@
 }
 
 
+// Force MethodHandle.vmentry to be an unmanaged pointer.
+// There is no way for a classfile to express this, so we must help it.
+void ClassFileParser::java_dyn_MethodHandle_fix_pre(constantPoolHandle cp,
+                                                    typeArrayHandle* fields_ptr,
+                                                    FieldAllocationCount *fac_ptr,
+                                                    TRAPS) {
+  // Add fake fields for java.dyn.MethodHandle instances
+  //
+  // This is not particularly nice, but since there is no way to express
+  // a native wordSize field in Java, we must do it at this level.
+
+  if (!EnableMethodHandles)  return;
+
+  int word_sig_index = 0;
+  const int cp_size = cp->length();
+  for (int index = 1; index < cp_size; index++) {
+    if (cp->tag_at(index).is_utf8() &&
+        cp->symbol_at(index) == vmSymbols::machine_word_signature()) {
+      word_sig_index = index;
+      break;
+    }
+  }
+
+  if (word_sig_index == 0)
+    THROW_MSG(vmSymbols::java_lang_VirtualMachineError(),
+              "missing I or J signature (for vmentry) in java.dyn.MethodHandle");
+
+  bool found_vmentry = false;
+
+  const int n = (*fields_ptr)()->length();
+  for (int i = 0; i < n; i += instanceKlass::next_offset) {
+    int name_index = (*fields_ptr)->ushort_at(i + instanceKlass::name_index_offset);
+    int sig_index  = (*fields_ptr)->ushort_at(i + instanceKlass::signature_index_offset);
+    int acc_flags  = (*fields_ptr)->ushort_at(i + instanceKlass::access_flags_offset);
+    symbolOop f_name = cp->symbol_at(name_index);
+    symbolOop f_sig  = cp->symbol_at(sig_index);
+    if (f_sig == vmSymbols::byte_signature() &&
+        f_name == vmSymbols::vmentry_name() &&
+        (acc_flags & JVM_ACC_STATIC) == 0) {
+      // Adjust the field type from byte to an unmanaged pointer.
+      assert(fac_ptr->nonstatic_byte_count > 0, "");
+      fac_ptr->nonstatic_byte_count -= 1;
+      (*fields_ptr)->ushort_at_put(i + instanceKlass::signature_index_offset,
+                                   word_sig_index);
+      if (wordSize == jintSize) {
+        fac_ptr->nonstatic_word_count += 1;
+      } else {
+        fac_ptr->nonstatic_double_count += 1;
+      }
+
+      FieldAllocationType atype = (FieldAllocationType) (*fields_ptr)->ushort_at(i+4);
+      assert(atype == NONSTATIC_BYTE, "");
+      FieldAllocationType new_atype = NONSTATIC_WORD;
+      if (wordSize > jintSize) {
+        if (Universe::field_type_should_be_aligned(T_LONG)) {
+          atype = NONSTATIC_ALIGNED_DOUBLE;
+        } else {
+          atype = NONSTATIC_DOUBLE;
+        }
+      }
+      (*fields_ptr)->ushort_at_put(i+4, new_atype);
+
+      found_vmentry = true;
+      break;
+    }
+  }
+
+  if (!found_vmentry)
+    THROW_MSG(vmSymbols::java_lang_VirtualMachineError(),
+              "missing vmentry byte field in java.dyn.MethodHandle");
+
+}
+
+
 instanceKlassHandle ClassFileParser::parseClassFile(symbolHandle name,
                                                     Handle class_loader,
                                                     Handle protection_domain,
+                                                    KlassHandle host_klass,
                                                     GrowableArray<Handle>* cp_patches,
                                                     symbolHandle& parsed_name,
                                                     TRAPS) {
@@ -2500,6 +2580,7 @@
     }
   }
 
+  _host_klass = host_klass;
   _cp_patches = cp_patches;
 
   instanceKlassHandle nullHandle;
@@ -2808,6 +2889,11 @@
       java_lang_Class_fix_pre(&methods, &fac, CHECK_(nullHandle));
     }
 
+    // adjust the vmentry field declaration in java.dyn.MethodHandle
+    if (EnableMethodHandles && class_name() == vmSymbols::sun_dyn_MethodHandleImpl() && class_loader.is_null()) {
+      java_dyn_MethodHandle_fix_pre(cp, &fields, &fac, CHECK_(nullHandle));
+    }
+
     // Add a fake "discovered" field if it is not present
     // for compatibility with earlier jdk's.
     if (class_name() == vmSymbols::java_lang_ref_Reference()
@@ -3134,7 +3220,7 @@
     this_klass->set_method_ordering(method_ordering());
     this_klass->set_initial_method_idnum(methods->length());
     this_klass->set_name(cp->klass_name_at(this_class_index));
-    if (LinkWellKnownClasses)  // I am well known to myself
+    if (LinkWellKnownClasses || is_anonymous())  // I am well known to myself
       cp->klass_at_put(this_class_index, this_klass()); // eagerly resolve
     this_klass->set_protection_domain(protection_domain());
     this_klass->set_fields_annotations(fields_annotations());
--- a/hotspot/src/share/vm/classfile/classFileParser.hpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/classfile/classFileParser.hpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc.  All Rights Reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,7 @@
   u2   _major_version;
   u2   _minor_version;
   symbolHandle _class_name;
+  KlassHandle _host_klass;
   GrowableArray<Handle>* _cp_patches; // overrides for CP entries
 
   bool _has_finalizer;
@@ -145,6 +146,11 @@
   // Adjust the next_nonstatic_oop_offset to place the fake fields
   // before any Java fields.
   void java_lang_Class_fix_post(int* next_nonstatic_oop_offset);
+  // Adjust the field allocation counts for java.dyn.MethodHandle to add
+  // a fake address (void*) field.
+  void java_dyn_MethodHandle_fix_pre(constantPoolHandle cp,
+                                     typeArrayHandle* fields_ptr,
+                                     FieldAllocationCount *fac_ptr, TRAPS);
 
   // Format checker methods
   void classfile_parse_error(const char* msg, TRAPS);
@@ -204,6 +210,10 @@
   char* skip_over_field_name(char* name, bool slash_ok, unsigned int length);
   char* skip_over_field_signature(char* signature, bool void_ok, unsigned int length, TRAPS);
 
+  bool is_anonymous() {
+    assert(AnonymousClasses || _host_klass.is_null(), "");
+    return _host_klass.not_null();
+  }
   bool has_cp_patch_at(int index) {
     assert(AnonymousClasses, "");
     assert(index >= 0, "oob");
@@ -249,11 +259,13 @@
                                      Handle protection_domain,
                                      symbolHandle& parsed_name,
                                      TRAPS) {
-    return parseClassFile(name, class_loader, protection_domain, NULL, parsed_name, THREAD);
+    KlassHandle no_host_klass;
+    return parseClassFile(name, class_loader, protection_domain, no_host_klass, NULL, parsed_name, THREAD);
   }
   instanceKlassHandle parseClassFile(symbolHandle name,
                                      Handle class_loader,
                                      Handle protection_domain,
+                                     KlassHandle host_klass,
                                      GrowableArray<Handle>* cp_patches,
                                      symbolHandle& parsed_name,
                                      TRAPS);
--- a/hotspot/src/share/vm/classfile/dictionary.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/classfile/dictionary.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2003-2009 Sun Microsystems, Inc.  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
@@ -549,6 +549,63 @@
   }
 }
 
+SymbolPropertyTable::SymbolPropertyTable(int table_size)
+  : Hashtable(table_size, sizeof(SymbolPropertyEntry))
+{
+}
+SymbolPropertyTable::SymbolPropertyTable(int table_size, HashtableBucket* t,
+                                         int number_of_entries)
+  : Hashtable(table_size, sizeof(SymbolPropertyEntry), t, number_of_entries)
+{
+}
+
+
+SymbolPropertyEntry* SymbolPropertyTable::find_entry(int index, unsigned int hash,
+                                                     symbolHandle sym) {
+  assert(index == index_for(sym), "incorrect index?");
+  for (SymbolPropertyEntry* p = bucket(index); p != NULL; p = p->next()) {
+    if (p->hash() == hash && p->symbol() == sym()) {
+      return p;
+    }
+  }
+  return NULL;
+}
+
+
+SymbolPropertyEntry* SymbolPropertyTable::add_entry(int index, unsigned int hash,
+                                                    symbolHandle sym) {
+  assert_locked_or_safepoint(SystemDictionary_lock);
+  assert(index == index_for(sym), "incorrect index?");
+  assert(find_entry(index, hash, sym) == NULL, "no double entry");
+
+  SymbolPropertyEntry* p = new_entry(hash, sym());
+  Hashtable::add_entry(index, p);
+  return p;
+}
+
+
+void SymbolPropertyTable::oops_do(OopClosure* f) {
+  for (int index = 0; index < table_size(); index++) {
+    for (SymbolPropertyEntry* p = bucket(index); p != NULL; p = p->next()) {
+      f->do_oop((oop*) p->symbol_addr());
+      if (p->property_oop() != NULL) {
+        f->do_oop(p->property_oop_addr());
+      }
+    }
+  }
+}
+
+void SymbolPropertyTable::methods_do(void f(methodOop)) {
+  for (int index = 0; index < table_size(); index++) {
+    for (SymbolPropertyEntry* p = bucket(index); p != NULL; p = p->next()) {
+      oop prop = p->property_oop();
+      if (prop != NULL && prop->is_method()) {
+        f((methodOop)prop);
+      }
+    }
+  }
+}
+
 
 // ----------------------------------------------------------------------------
 #ifndef PRODUCT
--- a/hotspot/src/share/vm/classfile/dictionary.hpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/classfile/dictionary.hpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2003-2009 Sun Microsystems, Inc.  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
@@ -217,3 +217,112 @@
     tty->print_cr("pd set = #%d", count);
   }
 };
+
+// Entry in a SymbolPropertyTable, mapping a single symbolOop
+// to a managed and an unmanaged pointer.
+class SymbolPropertyEntry : public HashtableEntry {
+  friend class VMStructs;
+ private:
+  oop     _property_oop;
+  address _property_data;
+
+ public:
+  symbolOop symbol() const          { return (symbolOop) literal(); }
+
+  oop      property_oop() const     { return _property_oop; }
+  void set_property_oop(oop p)      { _property_oop = p; }
+
+  address  property_data() const    { return _property_data; }
+  void set_property_data(address p) { _property_data = p; }
+
+  SymbolPropertyEntry* next() const {
+    return (SymbolPropertyEntry*)HashtableEntry::next();
+  }
+
+  SymbolPropertyEntry** next_addr() {
+    return (SymbolPropertyEntry**)HashtableEntry::next_addr();
+  }
+
+  oop* symbol_addr()                { return literal_addr(); }
+  oop* property_oop_addr()          { return &_property_oop; }
+
+  void print_on(outputStream* st) const {
+    symbol()->print_value_on(st);
+    st->print(" -> ");
+    bool printed = false;
+    if (property_oop() != NULL) {
+      property_oop()->print_value_on(st);
+      printed = true;
+    }
+    if (property_data() != NULL) {
+      if (printed)  st->print(" and ");
+      st->print(INTPTR_FORMAT, property_data());
+      printed = true;
+    }
+    st->print_cr(printed ? "" : "(empty)");
+  }
+};
+
+// A system-internal mapping of symbols to pointers, both managed
+// and unmanaged.  Used to record the auto-generation of each method
+// MethodHandle.invoke(S)T, for all signatures (S)T.
+class SymbolPropertyTable : public Hashtable {
+  friend class VMStructs;
+private:
+  SymbolPropertyEntry* bucket(int i) {
+    return (SymbolPropertyEntry*) Hashtable::bucket(i);
+  }
+
+  // The following method is not MT-safe and must be done under lock.
+  SymbolPropertyEntry** bucket_addr(int i) {
+    return (SymbolPropertyEntry**) Hashtable::bucket_addr(i);
+  }
+
+  void add_entry(int index, SymbolPropertyEntry* new_entry) {
+    ShouldNotReachHere();
+  }
+  void set_entry(int index, SymbolPropertyEntry* new_entry) {
+    ShouldNotReachHere();
+  }
+
+  SymbolPropertyEntry* new_entry(unsigned int hash, symbolOop symbol) {
+    SymbolPropertyEntry* entry = (SymbolPropertyEntry*) Hashtable::new_entry(hash, symbol);
+    entry->set_property_oop(NULL);
+    entry->set_property_data(NULL);
+    return entry;
+  }
+
+public:
+  SymbolPropertyTable(int table_size);
+  SymbolPropertyTable(int table_size, HashtableBucket* t, int number_of_entries);
+
+  void free_entry(SymbolPropertyEntry* entry) {
+    Hashtable::free_entry(entry);
+  }
+
+  unsigned int compute_hash(symbolHandle sym) {
+    // Use the regular identity_hash.
+    return Hashtable::compute_hash(sym);
+  }
+
+  // need not be locked; no state change
+  SymbolPropertyEntry* find_entry(int index, unsigned int hash, symbolHandle name);
+
+  // must be done under SystemDictionary_lock
+  SymbolPropertyEntry* add_entry(int index, unsigned int hash, symbolHandle name);
+
+  // GC support
+  void oops_do(OopClosure* f);
+  void methods_do(void f(methodOop));
+
+  // Sharing support
+  void dump(SerializeOopClosure* soc);
+  void restore(SerializeOopClosure* soc);
+  void reorder_dictionary();
+
+#ifndef PRODUCT
+  void print();
+#endif
+  void verify();
+};
+
--- a/hotspot/src/share/vm/classfile/javaClasses.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/classfile/javaClasses.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -25,13 +25,24 @@
 # include "incls/_precompiled.incl"
 # include "incls/_javaClasses.cpp.incl"
 
+static bool find_field(instanceKlass* ik,
+                       symbolOop name_symbol, symbolOop signature_symbol,
+                       fieldDescriptor* fd,
+                       bool allow_super = false) {
+  if (allow_super)
+    return ik->find_field(name_symbol, signature_symbol, fd) != NULL;
+  else
+    return ik->find_local_field(name_symbol, signature_symbol, fd);
+}
+
 // Helpful routine for computing field offsets at run time rather than hardcoding them
 static void
 compute_offset(int &dest_offset,
-               klassOop klass_oop, symbolOop name_symbol, symbolOop signature_symbol) {
+               klassOop klass_oop, symbolOop name_symbol, symbolOop signature_symbol,
+               bool allow_super = false) {
   fieldDescriptor fd;
   instanceKlass* ik = instanceKlass::cast(klass_oop);
-  if (!ik->find_local_field(name_symbol, signature_symbol, &fd)) {
+  if (!find_field(ik, name_symbol, signature_symbol, &fd, allow_super)) {
     ResourceMark rm;
     tty->print_cr("Invalid layout of %s at %s", ik->external_name(), name_symbol->as_C_string());
     fatal("Invalid layout of preloaded class");
@@ -42,14 +53,16 @@
 // Same as above but for "optional" offsets that might not be present in certain JDK versions
 static void
 compute_optional_offset(int& dest_offset,
-                        klassOop klass_oop, symbolOop name_symbol, symbolOop signature_symbol) {
+                        klassOop klass_oop, symbolOop name_symbol, symbolOop signature_symbol,
+                        bool allow_super = false) {
   fieldDescriptor fd;
   instanceKlass* ik = instanceKlass::cast(klass_oop);
-  if (ik->find_local_field(name_symbol, signature_symbol, &fd)) {
+  if (find_field(ik, name_symbol, signature_symbol, &fd, allow_super)) {
     dest_offset = fd.offset();
   }
 }
 
+
 Handle java_lang_String::basic_create(int length, bool tenured, TRAPS) {
   // Create the String object first, so there's a chance that the String
   // and the char array it points to end up in the same cache line.
@@ -2107,13 +2120,324 @@
 }
 
 
+// Support for java_dyn_MethodHandle
+
+int java_dyn_MethodHandle::_type_offset;
+int java_dyn_MethodHandle::_vmtarget_offset;
+int java_dyn_MethodHandle::_vmentry_offset;
+int java_dyn_MethodHandle::_vmslots_offset;
+
+int sun_dyn_MemberName::_clazz_offset;
+int sun_dyn_MemberName::_name_offset;
+int sun_dyn_MemberName::_type_offset;
+int sun_dyn_MemberName::_flags_offset;
+int sun_dyn_MemberName::_vmtarget_offset;
+int sun_dyn_MemberName::_vmindex_offset;
+
+int sun_dyn_DirectMethodHandle::_vmindex_offset;
+
+int sun_dyn_BoundMethodHandle::_argument_offset;
+int sun_dyn_BoundMethodHandle::_vmargslot_offset;
+
+int sun_dyn_AdapterMethodHandle::_conversion_offset;
+
+void java_dyn_MethodHandle::compute_offsets() {
+  klassOop k = SystemDictionary::MethodHandle_klass();
+  if (k != NULL && EnableMethodHandles) {
+    compute_offset(_type_offset,      k, vmSymbols::type_name(),      vmSymbols::java_dyn_MethodType_signature(), true);
+    compute_offset(_vmtarget_offset,  k, vmSymbols::vmtarget_name(),  vmSymbols::object_signature(), true);
+    compute_offset(_vmentry_offset,   k, vmSymbols::vmentry_name(),   vmSymbols::machine_word_signature(), true);
+
+    // Note:  MH.vmslots (if it is present) is a hoisted copy of MH.type.form.vmslots.
+    // It is optional pending experiments to keep or toss.
+    compute_optional_offset(_vmslots_offset, k, vmSymbols::vmslots_name(), vmSymbols::int_signature(), true);
+  }
+}
+
+void sun_dyn_MemberName::compute_offsets() {
+  klassOop k = SystemDictionary::MemberName_klass();
+  if (k != NULL && EnableMethodHandles) {
+    compute_offset(_clazz_offset,     k, vmSymbols::clazz_name(),     vmSymbols::class_signature());
+    compute_offset(_name_offset,      k, vmSymbols::name_name(),      vmSymbols::string_signature());
+    compute_offset(_type_offset,      k, vmSymbols::type_name(),      vmSymbols::object_signature());
+    compute_offset(_flags_offset,     k, vmSymbols::flags_name(),     vmSymbols::int_signature());
+    compute_offset(_vmtarget_offset,  k, vmSymbols::vmtarget_name(),  vmSymbols::object_signature());
+    compute_offset(_vmindex_offset,   k, vmSymbols::vmindex_name(),   vmSymbols::int_signature());
+  }
+}
+
+void sun_dyn_DirectMethodHandle::compute_offsets() {
+  klassOop k = SystemDictionary::DirectMethodHandle_klass();
+  if (k != NULL && EnableMethodHandles) {
+    compute_offset(_vmindex_offset,   k, vmSymbols::vmindex_name(),   vmSymbols::int_signature(),    true);
+  }
+}
+
+void sun_dyn_BoundMethodHandle::compute_offsets() {
+  klassOop k = SystemDictionary::BoundMethodHandle_klass();
+  if (k != NULL && EnableMethodHandles) {
+    compute_offset(_vmargslot_offset, k, vmSymbols::vmargslot_name(), vmSymbols::int_signature(),    true);
+    compute_offset(_argument_offset,  k, vmSymbols::argument_name(),  vmSymbols::object_signature(), true);
+  }
+}
+
+void sun_dyn_AdapterMethodHandle::compute_offsets() {
+  klassOop k = SystemDictionary::AdapterMethodHandle_klass();
+  if (k != NULL && EnableMethodHandles) {
+    compute_offset(_conversion_offset, k, vmSymbols::conversion_name(), vmSymbols::int_signature(), true);
+  }
+}
+
+oop java_dyn_MethodHandle::type(oop mh) {
+  return mh->obj_field(_type_offset);
+}
+
+void java_dyn_MethodHandle::set_type(oop mh, oop mtype) {
+  mh->obj_field_put(_type_offset, mtype);
+}
+
+int java_dyn_MethodHandle::vmslots(oop mh) {
+  int vmslots_offset = _vmslots_offset;
+  if (vmslots_offset != 0) {
+#ifdef ASSERT
+    int x = mh->int_field(vmslots_offset);
+    int y = compute_vmslots(mh);
+    assert(x == y, "correct hoisted value");
+#endif
+    return mh->int_field(vmslots_offset);
+  } else {
+    return compute_vmslots(mh);
+  }
+}
+
+// if MH.vmslots exists, hoist into it the value of type.form.vmslots
+void java_dyn_MethodHandle::init_vmslots(oop mh) {
+  int vmslots_offset = _vmslots_offset;
+  if (vmslots_offset != 0) {
+    mh->int_field_put(vmslots_offset, compute_vmslots(mh));
+  }
+}
+
+// fetch type.form.vmslots, which is the number of JVM stack slots
+// required to carry the arguments of this MH
+int java_dyn_MethodHandle::compute_vmslots(oop mh) {
+  oop mtype = type(mh);
+  if (mtype == NULL)  return 0;  // Java code would get NPE
+  oop form = java_dyn_MethodType::form(mtype);
+  if (form == NULL)   return 0;  // Java code would get NPE
+  return java_dyn_MethodTypeForm::vmslots(form);
+}
+
+// fetch the low-level entry point for this mh
+MethodHandleEntry* java_dyn_MethodHandle::vmentry(oop mh) {
+  return (MethodHandleEntry*) mh->address_field(_vmentry_offset);
+}
+
+void java_dyn_MethodHandle::set_vmentry(oop mh, MethodHandleEntry* me) {
+  assert(_vmentry_offset != 0, "must be present");
+
+  // This is always the final step that initializes a valid method handle:
+  mh->release_address_field_put(_vmentry_offset, (address) me);
+
+  // There should be enough memory barriers on exit from native methods
+  // to ensure that the MH is fully initialized to all threads before
+  // Java code can publish it in global data structures.
+  // But just in case, we use release_address_field_put.
+}
+
+/// MemberName accessors
+
+oop sun_dyn_MemberName::clazz(oop mname) {
+  assert(is_instance(mname), "wrong type");
+  return mname->obj_field(_clazz_offset);
+}
+
+void sun_dyn_MemberName::set_clazz(oop mname, oop clazz) {
+  assert(is_instance(mname), "wrong type");
+  mname->obj_field_put(_clazz_offset, clazz);
+}
+
+oop sun_dyn_MemberName::name(oop mname) {
+  assert(is_instance(mname), "wrong type");
+  return mname->obj_field(_name_offset);
+}
+
+void sun_dyn_MemberName::set_name(oop mname, oop name) {
+  assert(is_instance(mname), "wrong type");
+  mname->obj_field_put(_name_offset, name);
+}
+
+oop sun_dyn_MemberName::type(oop mname) {
+  assert(is_instance(mname), "wrong type");
+  return mname->obj_field(_type_offset);
+}
+
+void sun_dyn_MemberName::set_type(oop mname, oop type) {
+  assert(is_instance(mname), "wrong type");
+  mname->obj_field_put(_type_offset, type);
+}
+
+int sun_dyn_MemberName::flags(oop mname) {
+  assert(is_instance(mname), "wrong type");
+  return mname->int_field(_flags_offset);
+}
+
+void sun_dyn_MemberName::set_flags(oop mname, int flags) {
+  assert(is_instance(mname), "wrong type");
+  mname->int_field_put(_flags_offset, flags);
+}
+
+oop sun_dyn_MemberName::vmtarget(oop mname) {
+  assert(is_instance(mname), "wrong type");
+  return mname->obj_field(_vmtarget_offset);
+}
+
+void sun_dyn_MemberName::set_vmtarget(oop mname, oop ref) {
+  assert(is_instance(mname), "wrong type");
+  mname->obj_field_put(_vmtarget_offset, ref);
+}
+
+int sun_dyn_MemberName::vmindex(oop mname) {
+  assert(is_instance(mname), "wrong type");
+  return mname->int_field(_vmindex_offset);
+}
+
+void sun_dyn_MemberName::set_vmindex(oop mname, int index) {
+  assert(is_instance(mname), "wrong type");
+  mname->int_field_put(_vmindex_offset, index);
+}
+
+oop java_dyn_MethodHandle::vmtarget(oop mh) {
+  assert(is_instance(mh), "MH only");
+  return mh->obj_field(_vmtarget_offset);
+}
+
+void java_dyn_MethodHandle::set_vmtarget(oop mh, oop ref) {
+  assert(is_instance(mh), "MH only");
+  mh->obj_field_put(_vmtarget_offset, ref);
+}
+
+int sun_dyn_DirectMethodHandle::vmindex(oop mh) {
+  assert(is_instance(mh), "DMH only");
+  return mh->int_field(_vmindex_offset);
+}
+
+void sun_dyn_DirectMethodHandle::set_vmindex(oop mh, int index) {
+  assert(is_instance(mh), "DMH only");
+  mh->int_field_put(_vmindex_offset, index);
+}
+
+int sun_dyn_BoundMethodHandle::vmargslot(oop mh) {
+  assert(is_instance(mh), "BMH only");
+  return mh->int_field(_vmargslot_offset);
+}
+
+oop sun_dyn_BoundMethodHandle::argument(oop mh) {
+  assert(is_instance(mh), "BMH only");
+  return mh->obj_field(_argument_offset);
+}
+
+int sun_dyn_AdapterMethodHandle::conversion(oop mh) {
+  assert(is_instance(mh), "AMH only");
+  return mh->int_field(_conversion_offset);
+}
+
+void sun_dyn_AdapterMethodHandle::set_conversion(oop mh, int conv) {
+  assert(is_instance(mh), "AMH only");
+  mh->int_field_put(_conversion_offset, conv);
+}
+
+
+// Support for java_dyn_MethodType
+
+int java_dyn_MethodType::_rtype_offset;
+int java_dyn_MethodType::_ptypes_offset;
+int java_dyn_MethodType::_form_offset;
+
+void java_dyn_MethodType::compute_offsets() {
+  klassOop k = SystemDictionary::MethodType_klass();
+  if (k != NULL) {
+    compute_offset(_rtype_offset,  k, vmSymbols::rtype_name(),  vmSymbols::class_signature());
+    compute_offset(_ptypes_offset, k, vmSymbols::ptypes_name(), vmSymbols::class_array_signature());
+    compute_offset(_form_offset,   k, vmSymbols::form_name(),   vmSymbols::java_dyn_MethodTypeForm_signature());
+  }
+}
+
+void java_dyn_MethodType::print_signature(oop mt, outputStream* st) {
+  st->print("(");
+  objArrayOop pts = ptypes(mt);
+  for (int i = 0, limit = pts->length(); i < limit; i++) {
+    java_lang_Class::print_signature(pts->obj_at(i), st);
+  }
+  st->print(")");
+  java_lang_Class::print_signature(rtype(mt), st);
+}
+
+symbolOop java_dyn_MethodType::as_signature(oop mt, bool intern_if_not_found, TRAPS) {
+  ResourceMark rm;
+  stringStream buffer(128);
+  print_signature(mt, &buffer);
+  const char* sigstr =       buffer.base();
+  int         siglen = (int) buffer.size();
+  if (!intern_if_not_found)
+    return SymbolTable::probe(sigstr, siglen);
+  else
+    return oopFactory::new_symbol(sigstr, siglen, THREAD);
+}
+
+oop java_dyn_MethodType::rtype(oop mt) {
+  assert(is_instance(mt), "must be a MethodType");
+  return mt->obj_field(_rtype_offset);
+}
+
+objArrayOop java_dyn_MethodType::ptypes(oop mt) {
+  assert(is_instance(mt), "must be a MethodType");
+  return (objArrayOop) mt->obj_field(_ptypes_offset);
+}
+
+oop java_dyn_MethodType::form(oop mt) {
+  assert(is_instance(mt), "must be a MethodType");
+  return mt->obj_field(_form_offset);
+}
+
+oop java_dyn_MethodType::ptype(oop mt, int idx) {
+  return ptypes(mt)->obj_at(idx);
+}
+
+
+
+// Support for java_dyn_MethodTypeForm
+
+int java_dyn_MethodTypeForm::_vmslots_offset;
+int java_dyn_MethodTypeForm::_erasedType_offset;
+
+void java_dyn_MethodTypeForm::compute_offsets() {
+  klassOop k = SystemDictionary::MethodTypeForm_klass();
+  if (k != NULL) {
+    compute_optional_offset(_vmslots_offset,    k, vmSymbols::vmslots_name(),    vmSymbols::int_signature(), true);
+    compute_optional_offset(_erasedType_offset, k, vmSymbols::erasedType_name(), vmSymbols::java_dyn_MethodType_signature(), true);
+  }
+}
+
+int java_dyn_MethodTypeForm::vmslots(oop mtform) {
+  assert(mtform->klass() == SystemDictionary::MethodTypeForm_klass(), "MTForm only");
+  return mtform->int_field(_vmslots_offset);
+}
+
+oop java_dyn_MethodTypeForm::erasedType(oop mtform) {
+  assert(mtform->klass() == SystemDictionary::MethodTypeForm_klass(), "MTForm only");
+  return mtform->obj_field(_erasedType_offset);
+}
+
+
+
+
 // Support for java_security_AccessControlContext
 
 int java_security_AccessControlContext::_context_offset = 0;
 int java_security_AccessControlContext::_privilegedContext_offset = 0;
 int java_security_AccessControlContext::_isPrivileged_offset = 0;
 
-
 void java_security_AccessControlContext::compute_offsets() {
   assert(_isPrivileged_offset == 0, "offsets should be initialized only once");
   fieldDescriptor fd;
@@ -2442,6 +2766,15 @@
   java_lang_System::compute_offsets();
   java_lang_Thread::compute_offsets();
   java_lang_ThreadGroup::compute_offsets();
+  if (EnableMethodHandles) {
+    java_dyn_MethodHandle::compute_offsets();
+    sun_dyn_MemberName::compute_offsets();
+    sun_dyn_DirectMethodHandle::compute_offsets();
+    sun_dyn_BoundMethodHandle::compute_offsets();
+    sun_dyn_AdapterMethodHandle::compute_offsets();
+    java_dyn_MethodType::compute_offsets();
+    java_dyn_MethodTypeForm::compute_offsets();
+  }
   java_security_AccessControlContext::compute_offsets();
   // Initialize reflection classes. The layouts of these classes
   // changed with the new reflection implementation in JDK 1.4, and
@@ -2459,6 +2792,9 @@
     sun_reflect_UnsafeStaticFieldAccessorImpl::compute_offsets();
   }
   sun_misc_AtomicLongCSImpl::compute_offsets();
+
+  // generated interpreter code wants to know about the offsets we just computed:
+  AbstractAssembler::update_delayed_values();
 }
 
 #ifndef PRODUCT
--- a/hotspot/src/share/vm/classfile/javaClasses.hpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/classfile/javaClasses.hpp	Wed Jul 05 16:51:35 2017 +0200
@@ -151,6 +151,12 @@
   // Conversion
   static klassOop as_klassOop(oop java_class);
   static BasicType as_BasicType(oop java_class, klassOop* reference_klass = NULL);
+  static BasicType as_BasicType(oop java_class, KlassHandle* reference_klass) {
+    klassOop refk_oop = NULL;
+    BasicType result = as_BasicType(java_class, &refk_oop);
+    (*reference_klass) = KlassHandle(refk_oop);
+    return result;
+  }
   static symbolOop as_signature(oop java_class, bool intern_if_not_found, TRAPS);
   static void print_signature(oop java_class, outputStream *st);
   // Testing
@@ -778,6 +784,284 @@
 };
 
 
+// Interface to java.dyn.MethodHandle objects
+
+class MethodHandleEntry;
+
+class java_dyn_MethodHandle: AllStatic {
+  friend class JavaClasses;
+
+ private:
+  static int _vmentry_offset;           // assembly code trampoline for MH
+  static int _vmtarget_offset;          // class-specific target reference
+  static int _type_offset;              // the MethodType of this MH
+  static int _vmslots_offset;           // OPTIONAL hoisted type.form.vmslots
+
+  static void compute_offsets();
+
+ public:
+  // Accessors
+  static oop            type(oop mh);
+  static void       set_type(oop mh, oop mtype);
+
+  static oop            vmtarget(oop mh);
+  static void       set_vmtarget(oop mh, oop target);
+
+  static MethodHandleEntry* vmentry(oop mh);
+  static void       set_vmentry(oop mh, MethodHandleEntry* data);
+
+  static int            vmslots(oop mh);
+  static void      init_vmslots(oop mh);
+  static int    compute_vmslots(oop mh);
+
+  // Testers
+  static bool is_subclass(klassOop klass) {
+    return Klass::cast(klass)->is_subclass_of(SystemDictionary::MethodHandle_klass());
+  }
+  static bool is_instance(oop obj) {
+    return obj != NULL && is_subclass(obj->klass());
+  }
+
+  // Accessors for code generation:
+  static int type_offset_in_bytes()             { return _type_offset; }
+  static int vmtarget_offset_in_bytes()         { return _vmtarget_offset; }
+  static int vmentry_offset_in_bytes()          { return _vmentry_offset; }
+  static int vmslots_offset_in_bytes()          { return _vmslots_offset; }
+};
+
+class sun_dyn_DirectMethodHandle: public java_dyn_MethodHandle {
+  friend class JavaClasses;
+
+ private:
+  //         _vmtarget_offset;          // method   or class      or interface
+  static int _vmindex_offset;           // negative or vtable idx or itable idx
+  static void compute_offsets();
+
+ public:
+  // Accessors
+  static int            vmindex(oop mh);
+  static void       set_vmindex(oop mh, int index);
+
+  // Testers
+  static bool is_subclass(klassOop klass) {
+    return Klass::cast(klass)->is_subclass_of(SystemDictionary::DirectMethodHandle_klass());
+  }
+  static bool is_instance(oop obj) {
+    return obj != NULL && is_subclass(obj->klass());
+  }
+
+  // Accessors for code generation:
+  static int vmindex_offset_in_bytes()          { return _vmindex_offset; }
+};
+
+class sun_dyn_BoundMethodHandle: public java_dyn_MethodHandle {
+  friend class JavaClasses;
+
+ private:
+  static int _argument_offset;          // argument value bound into this MH
+  static int _vmargslot_offset;         // relevant argument slot (<= vmslots)
+  static void compute_offsets();
+
+public:
+  static oop            argument(oop mh);
+  static void       set_argument(oop mh, oop ref);
+
+  static jint           vmargslot(oop mh);
+  static void       set_vmargslot(oop mh, jint slot);
+
+  // Testers
+  static bool is_subclass(klassOop klass) {
+    return Klass::cast(klass)->is_subclass_of(SystemDictionary::BoundMethodHandle_klass());
+  }
+  static bool is_instance(oop obj) {
+    return obj != NULL && is_subclass(obj->klass());
+  }
+
+  static int argument_offset_in_bytes()         { return _argument_offset; }
+  static int vmargslot_offset_in_bytes()        { return _vmargslot_offset; }
+};
+
+class sun_dyn_AdapterMethodHandle: public sun_dyn_BoundMethodHandle {
+  friend class JavaClasses;
+
+ private:
+  static int _conversion_offset;        // type of conversion to apply
+  static void compute_offsets();
+
+ public:
+  static int            conversion(oop mh);
+  static void       set_conversion(oop mh, int conv);
+
+  // Testers
+  static bool is_subclass(klassOop klass) {
+    return Klass::cast(klass)->is_subclass_of(SystemDictionary::AdapterMethodHandle_klass());
+  }
+  static bool is_instance(oop obj) {
+    return obj != NULL && is_subclass(obj->klass());
+  }
+
+  // Relevant integer codes (keep these in synch. with MethodHandleNatives.Constants):
+  enum {
+    OP_RETYPE_ONLY   = 0x0, // no argument changes; straight retype
+    OP_CHECK_CAST    = 0x1, // ref-to-ref conversion; requires a Class argument
+    OP_PRIM_TO_PRIM  = 0x2, // converts from one primitive to another
+    OP_REF_TO_PRIM   = 0x3, // unboxes a wrapper to produce a primitive
+    OP_PRIM_TO_REF   = 0x4, // boxes a primitive into a wrapper (NYI)
+    OP_SWAP_ARGS     = 0x5, // swap arguments (vminfo is 2nd arg)
+    OP_ROT_ARGS      = 0x6, // rotate arguments (vminfo is displaced arg)
+    OP_DUP_ARGS      = 0x7, // duplicates one or more arguments (at TOS)
+    OP_DROP_ARGS     = 0x8, // remove one or more argument slots
+    OP_COLLECT_ARGS  = 0x9, // combine one or more arguments into a varargs (NYI)
+    OP_SPREAD_ARGS   = 0xA, // expand in place a varargs array (of known size)
+    OP_FLYBY         = 0xB, // operate first on reified argument list (NYI)
+    OP_RICOCHET      = 0xC, // run an adapter chain on the return value (NYI)
+    CONV_OP_LIMIT    = 0xD, // limit of CONV_OP enumeration
+
+    CONV_OP_MASK     = 0xF00, // this nybble contains the conversion op field
+    CONV_VMINFO_MASK = 0x0FF, // LSB is reserved for JVM use
+    CONV_VMINFO_SHIFT     =  0, // position of bits in CONV_VMINFO_MASK
+    CONV_OP_SHIFT         =  8, // position of bits in CONV_OP_MASK
+    CONV_DEST_TYPE_SHIFT  = 12, // byte 2 has the adapter BasicType (if needed)
+    CONV_SRC_TYPE_SHIFT   = 16, // byte 2 has the source BasicType (if needed)
+    CONV_STACK_MOVE_SHIFT = 20, // high 12 bits give signed SP change
+    CONV_STACK_MOVE_MASK  = (1 << (32 - CONV_STACK_MOVE_SHIFT)) - 1
+  };
+
+  static int conversion_offset_in_bytes()       { return _conversion_offset; }
+};
+
+
+// Interface to sun.dyn.MemberName objects
+// (These are a private interface for Java code to query the class hierarchy.)
+
+class sun_dyn_MemberName: AllStatic {
+  friend class JavaClasses;
+
+ private:
+  // From java.dyn.MemberName:
+  //    private Class<?>   clazz;       // class in which the method is defined
+  //    private String     name;        // may be null if not yet materialized
+  //    private Object     type;        // may be null if not yet materialized
+  //    private int        flags;       // modifier bits; see reflect.Modifier
+  //    private Object     vmtarget;    // VM-specific target value
+  //    private int        vmindex;     // method index within class or interface
+  static int _clazz_offset;
+  static int _name_offset;
+  static int _type_offset;
+  static int _flags_offset;
+  static int _vmtarget_offset;
+  static int _vmindex_offset;
+
+  static void compute_offsets();
+
+ public:
+  // Accessors
+  static oop            clazz(oop mname);
+  static void       set_clazz(oop mname, oop clazz);
+
+  static oop            type(oop mname);
+  static void       set_type(oop mname, oop type);
+
+  static oop            name(oop mname);
+  static void       set_name(oop mname, oop name);
+
+  static int            flags(oop mname);
+  static void       set_flags(oop mname, int flags);
+
+  static int            modifiers(oop mname) { return (u2) flags(mname); }
+  static void       set_modifiers(oop mname, int mods)
+                                { set_flags(mname, (flags(mname) &~ (u2)-1) | (u2)mods); }
+
+  static oop            vmtarget(oop mname);
+  static void       set_vmtarget(oop mname, oop target);
+
+  static int            vmindex(oop mname);
+  static void       set_vmindex(oop mname, int index);
+
+  // Testers
+  static bool is_subclass(klassOop klass) {
+    return Klass::cast(klass)->is_subclass_of(SystemDictionary::MemberName_klass());
+  }
+  static bool is_instance(oop obj) {
+    return obj != NULL && is_subclass(obj->klass());
+  }
+
+  // Relevant integer codes (keep these in synch. with MethodHandleNatives.Constants):
+  enum {
+    MN_IS_METHOD           = 0x00010000, // method (not constructor)
+    MN_IS_CONSTRUCTOR      = 0x00020000, // constructor
+    MN_IS_FIELD            = 0x00040000, // field
+    MN_IS_TYPE             = 0x00080000, // nested type
+    MN_SEARCH_SUPERCLASSES = 0x00100000, // for MHN.getMembers
+    MN_SEARCH_INTERFACES   = 0x00200000, // for MHN.getMembers
+    VM_INDEX_UNINITIALIZED = -99
+  };
+
+  // Accessors for code generation:
+  static int clazz_offset_in_bytes()            { return _clazz_offset; }
+  static int type_offset_in_bytes()             { return _type_offset; }
+  static int name_offset_in_bytes()             { return _name_offset; }
+  static int flags_offset_in_bytes()            { return _flags_offset; }
+  static int vmtarget_offset_in_bytes()         { return _vmtarget_offset; }
+  static int vmindex_offset_in_bytes()          { return _vmindex_offset; }
+};
+
+
+// Interface to java.dyn.MethodType objects
+
+class java_dyn_MethodType: AllStatic {
+  friend class JavaClasses;
+
+ private:
+  static int _rtype_offset;
+  static int _ptypes_offset;
+  static int _form_offset;
+
+  static void compute_offsets();
+
+ public:
+  // Accessors
+  static oop            rtype(oop mt);
+  static objArrayOop    ptypes(oop mt);
+  static oop            form(oop mt);
+
+  static oop            ptype(oop mt, int index);
+
+  static symbolOop      as_signature(oop mt, bool intern_if_not_found, TRAPS);
+  static void           print_signature(oop mt, outputStream* st);
+
+  static bool is_instance(oop obj) {
+    return obj != NULL && obj->klass() == SystemDictionary::MethodType_klass();
+  }
+
+  // Accessors for code generation:
+  static int rtype_offset_in_bytes()            { return _rtype_offset; }
+  static int ptypes_offset_in_bytes()           { return _ptypes_offset; }
+  static int form_offset_in_bytes()             { return _form_offset; }
+};
+
+class java_dyn_MethodTypeForm: AllStatic {
+  friend class JavaClasses;
+
+ private:
+  static int _vmslots_offset;           // number of argument slots needed
+  static int _erasedType_offset;        // erasedType = canonical MethodType
+
+  static void compute_offsets();
+
+ public:
+  // Accessors
+  static int            vmslots(oop mtform);
+  static oop            erasedType(oop mtform);
+
+  // Accessors for code generation:
+  static int vmslots_offset_in_bytes()          { return _vmslots_offset; }
+  static int erasedType_offset_in_bytes()       { return _erasedType_offset; }
+};
+
+
+
+
 // Interface to java.security.AccessControlContext objects
 
 class java_security_AccessControlContext: AllStatic {
--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -31,6 +31,7 @@
 Dictionary*       SystemDictionary::_shared_dictionary = NULL;
 LoaderConstraintTable* SystemDictionary::_loader_constraints = NULL;
 ResolutionErrorTable* SystemDictionary::_resolution_errors = NULL;
+SymbolPropertyTable* SystemDictionary::_invoke_method_table = NULL;
 
 
 int         SystemDictionary::_number_of_modifications = 0;
@@ -966,6 +967,8 @@
   instanceKlassHandle k = ClassFileParser(st).parseClassFile(class_name,
                                                              class_loader,
                                                              protection_domain,
+                                                             host_klass,
+                                                             cp_patches,
                                                              parsed_name,
                                                              THREAD);
 
@@ -1691,6 +1694,10 @@
   // represent classes we're actively loading.
   placeholders_do(blk);
 
+  // Visit extra methods
+  if (invoke_method_table() != NULL)
+    invoke_method_table()->oops_do(blk);
+
   // Loader constraints. We must keep the symbolOop used in the name alive.
   constraints()->always_strong_classes_do(blk);
 
@@ -1726,6 +1733,10 @@
   // Adjust dictionary
   dictionary()->oops_do(f);
 
+  // Visit extra methods
+  if (invoke_method_table() != NULL)
+    invoke_method_table()->oops_do(f);
+
   // Partially loaded classes
   placeholders()->oops_do(f);
 
@@ -1798,6 +1809,8 @@
 
 void SystemDictionary::methods_do(void f(methodOop)) {
   dictionary()->methods_do(f);
+  if (invoke_method_table() != NULL)
+    invoke_method_table()->methods_do(f);
 }
 
 // ----------------------------------------------------------------------------
@@ -1830,6 +1843,7 @@
   _number_of_modifications = 0;
   _loader_constraints = new LoaderConstraintTable(_loader_constraint_size);
   _resolution_errors = new ResolutionErrorTable(_resolution_error_size);
+  // _invoke_method_table is allocated lazily in find_method_handle_invoke()
 
   // Allocate private object used as system class loader lock
   _system_loader_lock_obj = oopFactory::new_system_objArray(0, CHECK);
@@ -1891,6 +1905,9 @@
       wk_klass_name_limits[0] = s;
     }
   }
+
+  // move the starting value forward to the limit:
+  start_id = limit_id;
 }
 
 
@@ -1924,6 +1941,17 @@
   instanceKlass::cast(WK_KLASS(final_reference_klass))->set_reference_type(REF_FINAL);
   instanceKlass::cast(WK_KLASS(phantom_reference_klass))->set_reference_type(REF_PHANTOM);
 
+  WKID meth_group_start = WK_KLASS_ENUM_NAME(MethodHandle_klass);
+  WKID meth_group_end   = WK_KLASS_ENUM_NAME(WrongMethodTypeException_klass);
+  initialize_wk_klasses_until(meth_group_start, scan, CHECK);
+  if (EnableMethodHandles) {
+    initialize_wk_klasses_through(meth_group_start, scan, CHECK);
+  }
+  if (_well_known_klasses[meth_group_start] == NULL) {
+    // Skip the rest of the method handle classes, if MethodHandle is not loaded.
+    scan = WKID(meth_group_end+1);
+  }
+
   initialize_wk_klasses_until(WKID_LIMIT, scan, CHECK);
 
   _box_klasses[T_BOOLEAN] = WK_KLASS(boolean_klass);
@@ -2254,6 +2282,91 @@
 }
 
 
+methodOop SystemDictionary::find_method_handle_invoke(symbolHandle signature,
+                                                      Handle class_loader,
+                                                      Handle protection_domain,
+                                                      TRAPS) {
+  if (!EnableMethodHandles)  return NULL;
+  assert(class_loader.is_null() && protection_domain.is_null(),
+         "cannot load specialized versions of MethodHandle.invoke");
+  if (invoke_method_table() == NULL) {
+    // create this side table lazily
+    _invoke_method_table = new SymbolPropertyTable(_invoke_method_size);
+  }
+  unsigned int hash  = invoke_method_table()->compute_hash(signature);
+  int          index = invoke_method_table()->hash_to_index(hash);
+  SymbolPropertyEntry* spe = invoke_method_table()->find_entry(index, hash, signature);
+  if (spe == NULL || spe->property_oop() == NULL) {
+    // Must create lots of stuff here, but outside of the SystemDictionary lock.
+    Handle mt = compute_method_handle_type(signature(),
+                                           class_loader, protection_domain,
+                                           CHECK_NULL);
+    KlassHandle  mh_klass = SystemDictionaryHandles::MethodHandle_klass();
+    methodHandle m = methodOopDesc::make_invoke_method(mh_klass, signature,
+                                                       mt, CHECK_NULL);
+    // Now grab the lock.  We might have to throw away the new method,
+    // if a racing thread has managed to install one at the same time.
+    {
+      MutexLocker ml(SystemDictionary_lock, Thread::current());
+      spe = invoke_method_table()->find_entry(index, hash, signature);
+      if (spe == NULL)
+        spe = invoke_method_table()->add_entry(index, hash, signature);
+      if (spe->property_oop() == NULL)
+        spe->set_property_oop(m());
+    }
+  }
+  methodOop m = (methodOop) spe->property_oop();
+  assert(m->is_method(), "");
+  return m;
+}
+
+// Ask Java code to find or construct a java.dyn.MethodType for the given
+// signature, as interpreted relative to the given class loader.
+// Because of class loader constraints, all method handle usage must be
+// consistent with this loader.
+Handle SystemDictionary::compute_method_handle_type(symbolHandle signature,
+                                                    Handle class_loader,
+                                                    Handle protection_domain,
+                                                    TRAPS) {
+  Handle empty;
+  int npts = ArgumentCount(signature()).size();
+  objArrayHandle pts = oopFactory::new_objArray(SystemDictionary::class_klass(), npts, CHECK_(empty));
+  int arg = 0;
+  Handle rt;                            // the return type from the signature
+  for (SignatureStream ss(signature()); !ss.is_done(); ss.next()) {
+    oop mirror;
+    if (!ss.is_object()) {
+      mirror = Universe::java_mirror(ss.type());
+    } else {
+      symbolOop    name_oop = ss.as_symbol(CHECK_(empty));
+      symbolHandle name(THREAD, name_oop);
+      klassOop klass = resolve_or_fail(name,
+                                       class_loader, protection_domain,
+                                       true, CHECK_(empty));
+      mirror = Klass::cast(klass)->java_mirror();
+    }
+    if (ss.at_return_type())
+      rt = Handle(THREAD, mirror);
+    else
+      pts->obj_at_put(arg++, mirror);
+  }
+  assert(arg == npts, "");
+
+  // call MethodType java.dyn.MethodType::makeImpl(Class rt, Class[] pts, false, true)
+  bool varargs = false, trusted = true;
+  JavaCallArguments args(Handle(THREAD, rt()));
+  args.push_oop(pts());
+  args.push_int(false);
+  args.push_int(trusted);
+  JavaValue result(T_OBJECT);
+  JavaCalls::call_static(&result,
+                         SystemDictionary::MethodType_klass(),
+                         vmSymbols::makeImpl_name(), vmSymbols::makeImpl_signature(),
+                         &args, CHECK_(empty));
+  return Handle(THREAD, (oop) result.get_jobject());
+}
+
+
 // Since the identity hash code for symbols changes when the symbols are
 // moved from the regular perm gen (hash in the mark word) to the shared
 // spaces (hash is the address), the classes loaded into the dictionary
--- a/hotspot/src/share/vm/classfile/systemDictionary.hpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp	Wed Jul 05 16:51:35 2017 +0200
@@ -63,6 +63,7 @@
 class LoaderConstraintTable;
 class HashtableBucket;
 class ResolutionErrorTable;
+class SymbolPropertyTable;
 
 // Certain classes are preloaded, such as java.lang.Object and java.lang.String.
 // They are all "well-known", in the sense that no class loader is allowed
@@ -131,6 +132,16 @@
   template(reflect_constant_pool_klass,  sun_reflect_ConstantPool,       Opt_Only_JDK15) \
   template(reflect_unsafe_static_field_accessor_impl_klass, sun_reflect_UnsafeStaticFieldAccessorImpl, Opt_Only_JDK15) \
                                                                               \
+  /* support for dynamic typing; it's OK if these are NULL in earlier JDKs */ \
+  template(MethodHandle_klass,           java_dyn_MethodHandle,          Opt) \
+  template(MemberName_klass,             sun_dyn_MemberName,             Opt) \
+  template(MethodHandleImpl_klass,       sun_dyn_MethodHandleImpl,       Opt) \
+  template(AdapterMethodHandle_klass,    sun_dyn_AdapterMethodHandle,    Opt) \
+  template(BoundMethodHandle_klass,      sun_dyn_BoundMethodHandle,      Opt) \
+  template(DirectMethodHandle_klass,     sun_dyn_DirectMethodHandle,     Opt) \
+  template(MethodType_klass,             java_dyn_MethodType,            Opt) \
+  template(MethodTypeForm_klass,         java_dyn_MethodTypeForm,        Opt) \
+  template(WrongMethodTypeException_klass, java_dyn_WrongMethodTypeException, Opt) \
   template(vector_klass,                 java_util_Vector,               Pre) \
   template(hashtable_klass,              java_util_Hashtable,            Pre) \
   template(stringBuffer_klass,           java_lang_StringBuffer,         Pre) \
@@ -444,6 +455,17 @@
   static char* check_signature_loaders(symbolHandle signature, Handle loader1,
                                        Handle loader2, bool is_method, TRAPS);
 
+  // JSR 292
+  // find the java.dyn.MethodHandles::invoke method for a given signature
+  static methodOop find_method_handle_invoke(symbolHandle signature,
+                                             Handle class_loader,
+                                             Handle protection_domain,
+                                             TRAPS);
+  // ask Java to compute the java.dyn.MethodType object for a given signature
+  static Handle    compute_method_handle_type(symbolHandle signature,
+                                              Handle class_loader,
+                                              Handle protection_domain,
+                                              TRAPS);
   // Utility for printing loader "name" as part of tracing constraints
   static const char* loader_name(oop loader) {
     return ((loader) == NULL ? "<bootloader>" :
@@ -460,6 +482,7 @@
   enum Constants {
     _loader_constraint_size = 107,                     // number of entries in constraint table
     _resolution_error_size  = 107,                     // number of entries in resolution error table
+    _invoke_method_size     = 139,                     // number of entries in invoke method table
     _nof_buckets            = 1009                     // number of buckets in hash table
   };
 
@@ -489,6 +512,9 @@
   // Resolution errors
   static ResolutionErrorTable*   _resolution_errors;
 
+  // Invoke methods (JSR 292)
+  static SymbolPropertyTable*    _invoke_method_table;
+
 public:
   // for VM_CounterDecay iteration support
   friend class CounterDecay;
@@ -506,6 +532,7 @@
   static PlaceholderTable*   placeholders() { return _placeholders; }
   static LoaderConstraintTable* constraints() { return _loader_constraints; }
   static ResolutionErrorTable* resolution_errors() { return _resolution_errors; }
+  static SymbolPropertyTable* invoke_method_table() { return _invoke_method_table; }
 
   // Basic loading operations
   static klassOop resolve_instance_class_or_null(symbolHandle class_name, Handle class_loader, Handle protection_domain, TRAPS);
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp	Wed Jul 05 16:51:35 2017 +0200
@@ -216,7 +216,26 @@
   template(sun_reflect_UnsafeStaticFieldAccessorImpl, "sun/reflect/UnsafeStaticFieldAccessorImpl")\
   template(base_name,                                 "base")                                     \
                                                                                                   \
-  /* common method names */                                                                       \
+  /* Support for JSR 292 & invokedynamic (JDK 1.7 and above) */                                   \
+  template(java_dyn_MethodHandle,                     "java/dyn/MethodHandle")                    \
+  template(java_dyn_MethodType,                       "java/dyn/MethodType")                      \
+  template(java_dyn_WrongMethodTypeException,         "java/dyn/WrongMethodTypeException")        \
+  template(java_dyn_MethodType_signature,             "Ljava/dyn/MethodType;")                    \
+  template(java_dyn_MethodHandle_signature,           "Ljava/dyn/MethodHandle;")                  \
+  /* internal classes known only to the JVM: */                                                   \
+  template(java_dyn_MethodTypeForm,                   "java/dyn/MethodTypeForm")                  \
+  template(java_dyn_MethodTypeForm_signature,         "Ljava/dyn/MethodTypeForm;")                \
+  template(sun_dyn_MemberName,                        "sun/dyn/MemberName")                       \
+  template(sun_dyn_MethodHandleImpl,                  "sun/dyn/MethodHandleImpl")                 \
+  template(sun_dyn_AdapterMethodHandle,               "sun/dyn/AdapterMethodHandle")              \
+  template(sun_dyn_BoundMethodHandle,                 "sun/dyn/BoundMethodHandle")                \
+  template(sun_dyn_DirectMethodHandle,                "sun/dyn/DirectMethodHandle")               \
+  template(makeImpl_name,                             "makeImpl") /*MethodType::makeImpl*/        \
+  template(makeImpl_signature,    "(Ljava/lang/Class;[Ljava/lang/Class;ZZ)Ljava/dyn/MethodType;") \
+  NOT_LP64(  do_alias(machine_word_signature,         int_signature)  )                           \
+  LP64_ONLY( do_alias(machine_word_signature,         long_signature) )                           \
+                                                                                                  \
+  /* common method and field names */                                                             \
   template(object_initializer_name,                   "<init>")                                   \
   template(class_initializer_name,                    "<clinit>")                                 \
   template(println_name,                              "println")                                  \
@@ -289,6 +308,21 @@
   template(bitCount_name,                             "bitCount")                                 \
   template(profile_name,                              "profile")                                  \
   template(equals_name,                               "equals")                                   \
+  template(toString_name,                             "toString")                                 \
+  template(values_name,                               "values")                                   \
+  template(receiver_name,                             "receiver")                                 \
+  template(vmtarget_name,                             "vmtarget")                                 \
+  template(vmentry_name,                              "vmentry")                                  \
+  template(vmslots_name,                              "vmslots")                                  \
+  template(vmindex_name,                              "vmindex")                                  \
+  template(vmargslot_name,                            "vmargslot")                                \
+  template(flags_name,                                "flags")                                    \
+  template(argument_name,                             "argument")                                 \
+  template(conversion_name,                           "conversion")                               \
+  template(rtype_name,                                "rtype")                                    \
+  template(ptypes_name,                               "ptypes")                                   \
+  template(form_name,                                 "form")                                     \
+  template(erasedType_name,                           "erasedType")                               \
                                                                                                   \
   /* non-intrinsic name/signature pairs: */                                                       \
   template(register_method_name,                      "register")                                 \
@@ -353,6 +387,7 @@
   template(void_classloader_signature,                "()Ljava/lang/ClassLoader;")                                \
   template(void_object_signature,                     "()Ljava/lang/Object;")                                     \
   template(void_class_signature,                      "()Ljava/lang/Class;")                                      \
+  template(void_string_signature,                     "()Ljava/lang/String;")                                      \
   template(object_array_object_object_signature,      "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;")\
   template(exception_void_signature,                  "(Ljava/lang/Exception;)V")                                 \
   template(protectiondomain_signature,                "[Ljava/security/ProtectionDomain;")                        \
--- a/hotspot/src/share/vm/code/vtableStubs.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/code/vtableStubs.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -107,13 +107,11 @@
       s = create_itable_stub(vtable_index);
     }
     enter(is_vtable_stub, vtable_index, s);
-#ifndef PRODUCT
     if (PrintAdapterHandlers) {
       tty->print_cr("Decoding VtableStub %s[%d]@%d",
                     is_vtable_stub? "vtbl": "itbl", vtable_index, VtableStub::receiver_location());
       Disassembler::decode(s->code_begin(), s->code_end());
     }
-#endif
   }
   return s->entry_point();
 }
--- a/hotspot/src/share/vm/includeDB_core	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/includeDB_core	Wed Jul 05 16:51:35 2017 +0200
@@ -254,6 +254,7 @@
 assembler_<arch>.cpp              collectedHeap.inline.hpp
 assembler_<arch>.cpp              interfaceSupport.hpp
 assembler_<arch>.cpp              interpreter.hpp
+assembler_<arch>.cpp              methodHandles.hpp
 assembler_<arch>.cpp              objectMonitor.hpp
 assembler_<arch>.cpp              os.hpp
 assembler_<arch>.cpp              resourceArea.hpp
@@ -1274,6 +1275,7 @@
 cpCacheKlass.cpp                        collectedHeap.hpp
 cpCacheKlass.cpp                        constantPoolOop.hpp
 cpCacheKlass.cpp                        cpCacheKlass.hpp
+cpCacheKlass.cpp                        genOopClosures.inline.hpp
 cpCacheKlass.cpp                        handles.inline.hpp
 cpCacheKlass.cpp                        javaClasses.hpp
 cpCacheKlass.cpp                        markSweep.inline.hpp
@@ -2202,6 +2204,7 @@
 interpreter_<arch_model>.cpp            jvmtiExport.hpp
 interpreter_<arch_model>.cpp            jvmtiThreadState.hpp
 interpreter_<arch_model>.cpp            methodDataOop.hpp
+interpreter_<arch_model>.cpp            methodHandles.hpp
 interpreter_<arch_model>.cpp            methodOop.hpp
 interpreter_<arch_model>.cpp            oop.inline.hpp
 interpreter_<arch_model>.cpp            sharedRuntime.hpp
@@ -2596,6 +2599,7 @@
 linkResolver.cpp                        instanceKlass.hpp
 linkResolver.cpp                        interpreterRuntime.hpp
 linkResolver.cpp                        linkResolver.hpp
+linkResolver.cpp                        methodHandles.hpp
 linkResolver.cpp                        nativeLookup.hpp
 linkResolver.cpp                        objArrayOop.hpp
 linkResolver.cpp                        reflection.hpp
@@ -2812,6 +2816,25 @@
 methodDataOop.hpp                       orderAccess.hpp
 methodDataOop.hpp                       universe.hpp
 
+methodHandles.hpp                       frame.inline.hpp
+methodHandles.hpp                       globals.hpp
+methodHandles.hpp                       interfaceSupport.hpp
+methodHandles.hpp                       javaClasses.hpp
+methodHandles.hpp                       vmSymbols.hpp
+
+methodHandles.cpp                       allocation.inline.hpp
+methodHandles.cpp                       interpreter.hpp
+methodHandles.cpp                       javaCalls.hpp
+methodHandles.cpp                       methodHandles.hpp
+methodHandles.cpp                       oopFactory.hpp
+methodHandles.cpp                       reflection.hpp
+methodHandles.cpp                       signature.hpp
+methodHandles.cpp                       symbolTable.hpp
+
+methodHandles_<arch>.cpp                allocation.inline.hpp
+methodHandles_<arch>.cpp                interpreter.hpp
+methodHandles_<arch>.cpp                methodHandles.hpp
+
 methodKlass.cpp                         collectedHeap.inline.hpp
 methodKlass.cpp                         constMethodKlass.hpp
 methodKlass.cpp                         gcLocker.hpp
@@ -3061,6 +3084,7 @@
 oop.inline.hpp                          arrayOop.hpp
 oop.inline.hpp                          atomic.hpp
 oop.inline.hpp                          barrierSet.inline.hpp
+oop.inline.hpp                          bytes_<arch>.hpp
 oop.inline.hpp                          cardTableModRefBS.hpp
 oop.inline.hpp                          collectedHeap.inline.hpp
 oop.inline.hpp                          compactingPermGenGen.hpp
@@ -3674,6 +3698,7 @@
 sharedRuntime.cpp                       interpreter.hpp
 sharedRuntime.cpp                       javaCalls.hpp
 sharedRuntime.cpp                       jvmtiExport.hpp
+sharedRuntime.cpp                       methodHandles.hpp
 sharedRuntime.cpp                       jvmtiRedefineClassesTrace.hpp
 sharedRuntime.cpp                       nativeInst_<arch>.hpp
 sharedRuntime.cpp                       nativeLookup.hpp
@@ -3862,6 +3887,7 @@
 stubGenerator_<arch_model>.cpp          handles.inline.hpp
 stubGenerator_<arch_model>.cpp          instanceOop.hpp
 stubGenerator_<arch_model>.cpp          interpreter.hpp
+stubGenerator_<arch_model>.cpp          methodHandles.hpp
 stubGenerator_<arch_model>.cpp          methodOop.hpp
 stubGenerator_<arch_model>.cpp          nativeInst_<arch>.hpp
 stubGenerator_<arch_model>.cpp          objArrayKlass.hpp
--- a/hotspot/src/share/vm/includeDB_gc_parallel	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/includeDB_gc_parallel	Wed Jul 05 16:51:35 2017 +0200
@@ -36,6 +36,12 @@
 constantPoolKlass.cpp                   psScavenge.inline.hpp
 constantPoolKlass.cpp                   parOopClosures.inline.hpp
 
+constantPoolKlass.cpp                   cardTableRS.hpp
+constantPoolKlass.cpp                   oop.pcgc.inline.hpp
+constantPoolKlass.cpp                   psPromotionManager.inline.hpp
+constantPoolKlass.cpp                   psScavenge.inline.hpp
+constantPoolKlass.cpp                   parOopClosures.inline.hpp
+
 genCollectedHeap.cpp                    concurrentMarkSweepThread.hpp
 genCollectedHeap.cpp                    vmCMSOperations.hpp
 
--- a/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/interpreter/abstractInterpreter.hpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc.  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
@@ -61,6 +61,7 @@
     empty,                                                      // empty method (code: _return)
     accessor,                                                   // accessor method (code: _aload_0, _getfield, _(a|i)return)
     abstract,                                                   // abstract method (throws an AbstractMethodException)
+    method_handle,                                              // java.dyn.MethodHandles::invoke
     java_lang_math_sin,                                         // implementation of java.lang.Math.sin   (x)
     java_lang_math_cos,                                         // implementation of java.lang.Math.cos   (x)
     java_lang_math_tan,                                         // implementation of java.lang.Math.tan   (x)
@@ -91,8 +92,6 @@
 
   static address    _rethrow_exception_entry;                   // rethrows an activation in previous frame
 
-
-
   friend class      AbstractInterpreterGenerator;
   friend class              InterpreterGenerator;
   friend class      InterpreterMacroAssembler;
--- a/hotspot/src/share/vm/interpreter/cppInterpreter.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/interpreter/cppInterpreter.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc.  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
@@ -114,6 +114,7 @@
     method_entry(empty);
     method_entry(accessor);
     method_entry(abstract);
+    method_entry(method_handle);
     method_entry(java_lang_math_sin   );
     method_entry(java_lang_math_cos   );
     method_entry(java_lang_math_tan   );
--- a/hotspot/src/share/vm/interpreter/interpreter.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/interpreter/interpreter.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc.  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
@@ -168,10 +168,14 @@
   // Abstract method?
   if (m->is_abstract()) return abstract;
 
+  // Invoker for method handles?
+  if (m->is_method_handle_invoke())  return method_handle;
+
   // Native method?
   // Note: This test must come _before_ the test for intrinsic
   //       methods. See also comments below.
   if (m->is_native()) {
+    assert(!m->is_method_handle_invoke(), "overlapping bits here, watch out");
     return m->is_synchronized() ? native_synchronized : native;
   }
 
@@ -249,6 +253,7 @@
     case empty                  : tty->print("empty"                  ); break;
     case accessor               : tty->print("accessor"               ); break;
     case abstract               : tty->print("abstract"               ); break;
+    case method_handle          : tty->print("method_handle"          ); break;
     case java_lang_math_sin     : tty->print("java_lang_math_sin"     ); break;
     case java_lang_math_cos     : tty->print("java_lang_math_cos"     ); break;
     case java_lang_math_tan     : tty->print("java_lang_math_tan"     ); break;
--- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc.  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
@@ -293,6 +293,24 @@
   THROW_MSG(vmSymbols::java_lang_ClassCastException(), message);
 IRT_END
 
+// required can be either a MethodType, or a Class (for a single argument)
+// actual (if not null) can be either a MethodHandle, or an arbitrary value (for a single argument)
+IRT_ENTRY(void, InterpreterRuntime::throw_WrongMethodTypeException(JavaThread* thread,
+                                                                   oopDesc* required,
+                                                                   oopDesc* actual)) {
+  ResourceMark rm(thread);
+  char* message = SharedRuntime::generate_wrong_method_type_message(thread, required, actual);
+
+  if (ProfileTraps) {
+    note_trap(thread, Deoptimization::Reason_constraint, CHECK);
+  }
+
+  // create exception
+  THROW_MSG(vmSymbols::java_dyn_WrongMethodTypeException(), message);
+}
+IRT_END
+
+
 
 // exception_handler_for_exception(...) returns the continuation address,
 // the exception oop (via TLS) and sets the bci/bcp for the continuation.
--- a/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc.  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
@@ -66,6 +66,7 @@
   static void    throw_StackOverflowError(JavaThread* thread);
   static void    throw_ArrayIndexOutOfBoundsException(JavaThread* thread, char* name, jint index);
   static void    throw_ClassCastException(JavaThread* thread, oopDesc* obj);
+  static void    throw_WrongMethodTypeException(JavaThread* thread, oopDesc* mtype = NULL, oopDesc* mhandle = NULL);
   static void    create_exception(JavaThread* thread, char* name, char* message);
   static void    create_klass_exception(JavaThread* thread, char* name, oopDesc* obj);
   static address exception_handler_for_exception(JavaThread* thread, oopDesc* exception);
--- a/hotspot/src/share/vm/interpreter/linkResolver.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc.  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
@@ -151,6 +151,20 @@
   result = methodHandle(THREAD, ik->lookup_method_in_all_interfaces(name(), signature()));
 }
 
+void LinkResolver::lookup_implicit_method(methodHandle& result, KlassHandle klass, symbolHandle name, symbolHandle signature, TRAPS) {
+  if (EnableMethodHandles && MethodHandles::enabled() &&
+      name == vmSymbolHandles::invoke_name() && klass() == SystemDictionary::MethodHandle_klass()) {
+    methodOop result_oop = SystemDictionary::find_method_handle_invoke(signature,
+                                                                       Handle(),
+                                                                       Handle(),
+                                                                       CHECK);
+    if (result_oop != NULL) {
+      assert(result_oop->is_method_handle_invoke() && result_oop->signature() == signature(), "consistent");
+      result = methodHandle(THREAD, result_oop);
+    }
+  }
+}
+
 void LinkResolver::check_method_accessability(KlassHandle ref_klass,
                                               KlassHandle resolved_klass,
                                               KlassHandle sel_klass,
@@ -240,6 +254,11 @@
     lookup_method_in_interfaces(resolved_method, resolved_klass, method_name, method_signature, CHECK);
 
     if (resolved_method.is_null()) {
+      // JSR 292:  see if this is an implicitly generated method MethodHandle.invoke(*...)
+      lookup_implicit_method(resolved_method, resolved_klass, method_name, method_signature, CHECK);
+    }
+
+    if (resolved_method.is_null()) {
       // 4. method lookup failed
       ResourceMark rm(THREAD);
       THROW_MSG(vmSymbols::java_lang_NoSuchMethodError(),
--- a/hotspot/src/share/vm/interpreter/linkResolver.hpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/interpreter/linkResolver.hpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2005 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc.  All Rights Reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -103,6 +103,7 @@
   static void lookup_method_in_klasses          (methodHandle& result, KlassHandle klass, symbolHandle name, symbolHandle signature, TRAPS);
   static void lookup_instance_method_in_klasses (methodHandle& result, KlassHandle klass, symbolHandle name, symbolHandle signature, TRAPS);
   static void lookup_method_in_interfaces       (methodHandle& result, KlassHandle klass, symbolHandle name, symbolHandle signature, TRAPS);
+  static void lookup_implicit_method            (methodHandle& result, KlassHandle klass, symbolHandle name, symbolHandle signature, TRAPS);
 
   static int vtable_index_of_miranda_method(KlassHandle klass, symbolHandle name, symbolHandle signature, TRAPS);
 
--- a/hotspot/src/share/vm/interpreter/templateInterpreter.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/interpreter/templateInterpreter.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc.  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
@@ -168,6 +168,7 @@
 address    TemplateInterpreter::_throw_ArrayStoreException_entry            = NULL;
 address    TemplateInterpreter::_throw_ArithmeticException_entry            = NULL;
 address    TemplateInterpreter::_throw_ClassCastException_entry             = NULL;
+address    TemplateInterpreter::_throw_WrongMethodType_entry                = NULL;
 address    TemplateInterpreter::_throw_NullPointerException_entry           = NULL;
 address    TemplateInterpreter::_throw_StackOverflowError_entry             = NULL;
 address    TemplateInterpreter::_throw_exception_entry                      = NULL;
@@ -341,6 +342,7 @@
     Interpreter::_throw_ArrayStoreException_entry            = generate_klass_exception_handler("java/lang/ArrayStoreException"                 );
     Interpreter::_throw_ArithmeticException_entry            = generate_exception_handler("java/lang/ArithmeticException"           , "/ by zero");
     Interpreter::_throw_ClassCastException_entry             = generate_ClassCastException_handler();
+    Interpreter::_throw_WrongMethodType_entry                = generate_WrongMethodType_handler();
     Interpreter::_throw_NullPointerException_entry           = generate_exception_handler("java/lang/NullPointerException"          , NULL       );
     Interpreter::_throw_StackOverflowError_entry             = generate_StackOverflowError_handler();
   }
@@ -358,6 +360,7 @@
   method_entry(empty)
   method_entry(accessor)
   method_entry(abstract)
+  method_entry(method_handle)
   method_entry(java_lang_math_sin  )
   method_entry(java_lang_math_cos  )
   method_entry(java_lang_math_tan  )
--- a/hotspot/src/share/vm/interpreter/templateInterpreter.hpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/interpreter/templateInterpreter.hpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc.  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
@@ -77,6 +77,7 @@
   friend class VMStructs;
   friend class InterpreterMacroAssembler;
   friend class TemplateInterpreterGenerator;
+  friend class InterpreterGenerator;
   friend class TemplateTable;
   // friend class Interpreter;
  public:
@@ -93,6 +94,7 @@
   static address    _throw_ArrayStoreException_entry;
   static address    _throw_ArithmeticException_entry;
   static address    _throw_ClassCastException_entry;
+  static address    _throw_WrongMethodType_entry;
   static address    _throw_NullPointerException_entry;
   static address    _throw_exception_entry;
 
@@ -137,6 +139,7 @@
   static address    remove_activation_entry()                   { return _remove_activation_entry; }
   static address    throw_exception_entry()                     { return _throw_exception_entry; }
   static address    throw_ArithmeticException_entry()           { return _throw_ArithmeticException_entry; }
+  static address    throw_WrongMethodType_entry()               { return _throw_WrongMethodType_entry; }
   static address    throw_NullPointerException_entry()          { return _throw_NullPointerException_entry; }
   static address    throw_StackOverflowError_entry()            { return _throw_StackOverflowError_entry; }
 
--- a/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.hpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.hpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc.  All Rights Reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -48,6 +48,7 @@
   }
   address generate_exception_handler_common(const char* name, const char* message, bool pass_oop);
   address generate_ClassCastException_handler();
+  address generate_WrongMethodType_handler();
   address generate_ArrayIndexOutOfBounds_handler(const char* name);
   address generate_continuation_for(TosState state);
   address generate_return_entry_for(TosState state, int step);
--- a/hotspot/src/share/vm/memory/dump.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/memory/dump.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2008 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 2003-2009 Sun Microsystems, Inc.  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
@@ -928,6 +928,10 @@
     // shared classes at runtime, where constraints were previously created.
     guarantee(SystemDictionary::constraints()->number_of_entries() == 0,
               "loader constraints are not saved");
+    // Revisit and implement this if we prelink method handle call sites:
+    guarantee(SystemDictionary::invoke_method_table() == NULL ||
+              SystemDictionary::invoke_method_table()->number_of_entries() == 0,
+              "invoke method table is not saved");
     GenCollectedHeap* gch = GenCollectedHeap::heap();
 
     // At this point, many classes have been loaded.
--- a/hotspot/src/share/vm/oops/methodKlass.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/oops/methodKlass.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -298,7 +298,11 @@
     m->code()->print_value_on(st);
     st->cr();
   }
-  if (m->is_native()) {
+  if (m->is_method_handle_invoke()) {
+    st->print_cr(" - invoke method type: " INTPTR_FORMAT, (address) m->method_handle_type());
+    // m is classified as native, but it does not have an interesting
+    // native_function or signature handler
+  } else if (m->is_native()) {
     st->print_cr(" - native function:   " INTPTR_FORMAT, m->native_function());
     st->print_cr(" - signature handler: " INTPTR_FORMAT, m->signature_handler());
   }
--- a/hotspot/src/share/vm/oops/methodOop.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/oops/methodOop.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -304,6 +304,12 @@
 }
 
 
+int methodOopDesc::extra_stack_words() {
+  // not an inline function, to avoid a header dependency on Interpreter
+  return extra_stack_entries() * Interpreter::stackElementSize();
+}
+
+
 void methodOopDesc::compute_size_of_parameters(Thread *thread) {
   symbolHandle h_signature(thread, signature());
   ArgumentSizeComputer asc(h_signature);
@@ -564,6 +570,11 @@
 
 
 bool methodOopDesc::is_not_compilable(int comp_level) const {
+  if (is_method_handle_invoke()) {
+    // compilers must recognize this method specially, or not at all
+    return true;
+  }
+
   methodDataOop mdo = method_data();
   if (mdo != NULL
       && (uint)mdo->decompile_count() > (uint)PerMethodRecompilationCutoff) {
@@ -651,7 +662,7 @@
   assert(entry != NULL, "interpreter entry must be non-null");
   // Sets both _i2i_entry and _from_interpreted_entry
   set_interpreter_entry(entry);
-  if (is_native()) {
+  if (is_native() && !is_method_handle_invoke()) {
     set_native_function(
       SharedRuntime::native_method_throw_unsatisfied_link_error_entry(),
       !native_bind_event_is_interesting);
@@ -783,6 +794,100 @@
   return false;
 }
 
+// Constant pool structure for invoke methods:
+enum {
+  _imcp_invoke_name = 1,        // utf8: 'invoke'
+  _imcp_invoke_signature,       // utf8: (variable symbolOop)
+  _imcp_method_type_value,      // string: (variable java/dyn/MethodType, sic)
+  _imcp_limit
+};
+
+oop methodOopDesc::method_handle_type() const {
+  if (!is_method_handle_invoke()) { assert(false, "caller resp."); return NULL; }
+  oop mt = constants()->resolved_string_at(_imcp_method_type_value);
+  assert(mt->klass() == SystemDictionary::MethodType_klass(), "");
+  return mt;
+}
+
+jint* methodOopDesc::method_type_offsets_chain() {
+  static jint pchase[] = { -1, -1, -1 };
+  if (pchase[0] == -1) {
+    jint step0 = in_bytes(constants_offset());
+    jint step1 = (constantPoolOopDesc::header_size() + _imcp_method_type_value) * HeapWordSize;
+    // do this in reverse to avoid races:
+    OrderAccess::release_store(&pchase[1], step1);
+    OrderAccess::release_store(&pchase[0], step0);
+  }
+  return pchase;
+}
+
+methodHandle methodOopDesc::make_invoke_method(KlassHandle holder,
+                                               symbolHandle signature,
+                                               Handle method_type, TRAPS) {
+  methodHandle empty;
+
+  assert(holder() == SystemDictionary::MethodHandle_klass(),
+         "must be a JSR 292 magic type");
+
+  if (TraceMethodHandles) {
+    tty->print("Creating invoke method for ");
+    signature->print_value();
+    tty->cr();
+  }
+
+  constantPoolHandle cp;
+  {
+    constantPoolOop cp_oop = oopFactory::new_constantPool(_imcp_limit, IsSafeConc, CHECK_(empty));
+    cp = constantPoolHandle(THREAD, cp_oop);
+  }
+  cp->symbol_at_put(_imcp_invoke_name,       vmSymbols::invoke_name());
+  cp->symbol_at_put(_imcp_invoke_signature,  signature());
+  cp->string_at_put(_imcp_method_type_value, vmSymbols::void_signature());
+  cp->set_pool_holder(holder());
+
+  // set up the fancy stuff:
+  cp->pseudo_string_at_put(_imcp_method_type_value, method_type());
+  methodHandle m;
+  {
+    int flags_bits = (JVM_MH_INVOKE_BITS | JVM_ACC_PUBLIC | JVM_ACC_FINAL);
+    methodOop m_oop = oopFactory::new_method(0, accessFlags_from(flags_bits),
+                                             0, 0, 0, IsSafeConc, CHECK_(empty));
+    m = methodHandle(THREAD, m_oop);
+  }
+  m->set_constants(cp());
+  m->set_name_index(_imcp_invoke_name);
+  m->set_signature_index(_imcp_invoke_signature);
+  assert(m->name() == vmSymbols::invoke_name(), "");
+  assert(m->signature() == signature(), "");
+#ifdef CC_INTERP
+  ResultTypeFinder rtf(signature());
+  m->set_result_index(rtf.type());
+#endif
+  m->compute_size_of_parameters(THREAD);
+  m->set_exception_table(Universe::the_empty_int_array());
+
+  // Finally, set up its entry points.
+  assert(m->method_handle_type() == method_type(), "");
+  assert(m->can_be_statically_bound(), "");
+  m->set_vtable_index(methodOopDesc::nonvirtual_vtable_index);
+  m->link_method(m, CHECK_(empty));
+
+#ifdef ASSERT
+  // Make sure the pointer chase works.
+  address p = (address) m();
+  for (jint* pchase = method_type_offsets_chain(); (*pchase) != -1; pchase++) {
+    p = *(address*)(p + (*pchase));
+  }
+  assert((oop)p == method_type(), "pointer chase is correct");
+#endif
+
+  if (TraceMethodHandles)
+    m->print_on(tty);
+
+  return m;
+}
+
+
 
 methodHandle methodOopDesc:: clone_with_new_data(methodHandle m, u_char* new_code, int new_code_length,
                                                 u_char* new_compressed_linenumber_table, int new_compressed_linenumber_size, TRAPS) {
--- a/hotspot/src/share/vm/oops/methodOop.hpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/oops/methodOop.hpp	Wed Jul 05 16:51:35 2017 +0200
@@ -320,6 +320,7 @@
   enum VtableIndexFlag {
     // Valid vtable indexes are non-negative (>= 0).
     // These few negative values are used as sentinels.
+    highest_unused_vtable_index_value = -5,
     invalid_vtable_index    = -4,  // distinct from any valid vtable index
     garbage_vtable_index    = -3,  // not yet linked; no vtable layout yet
     nonvirtual_vtable_index = -2   // there is no need for vtable dispatch
@@ -523,6 +524,18 @@
   // Reflection support
   bool is_overridden_in(klassOop k) const;
 
+  // JSR 292 support
+  bool is_method_handle_invoke() const              { return access_flags().is_method_handle_invoke(); }
+  static methodHandle make_invoke_method(KlassHandle holder,
+                                         symbolHandle signature,
+                                         Handle method_type,
+                                         TRAPS);
+  // these operate only on invoke methods:
+  oop method_handle_type() const;
+  static jint* method_type_offsets_chain();  // series of pointer-offsets, terminated by -1
+  // presize interpreter frames for extra interpreter stack entries, if needed
+  static int extra_stack_entries() { return EnableMethodHandles ? (int)MethodHandlePushLimit : 0; }
+  static int extra_stack_words();  // = extra_stack_entries() * Interpreter::stackElementSize()
   // RedefineClasses() support:
   bool is_old() const                               { return access_flags().is_old(); }
   void set_is_old()                                 { _access_flags.set_is_old(); }
--- a/hotspot/src/share/vm/oops/oop.hpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/oops/oop.hpp	Wed Jul 05 16:51:35 2017 +0200
@@ -263,6 +263,9 @@
   jdouble double_field_acquire(int offset) const;
   void release_double_field_put(int offset, jdouble contents);
 
+  address address_field_acquire(int offset) const;
+  void release_address_field_put(int offset, address contents);
+
   // printing functions for VM debugging
   void print_on(outputStream* st) const;         // First level print
   void print_value_on(outputStream* st) const;   // Second level print.
--- a/hotspot/src/share/vm/oops/oop.inline.hpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/oops/oop.inline.hpp	Wed Jul 05 16:51:35 2017 +0200
@@ -349,6 +349,9 @@
 inline jdouble oopDesc::double_field_acquire(int offset) const              { return OrderAccess::load_acquire(double_field_addr(offset));     }
 inline void oopDesc::release_double_field_put(int offset, jdouble contents) { OrderAccess::release_store(double_field_addr(offset), contents); }
 
+inline address oopDesc::address_field_acquire(int offset) const             { return (address) OrderAccess::load_ptr_acquire(address_field_addr(offset)); }
+inline void oopDesc::release_address_field_put(int offset, address contents) { OrderAccess::release_store_ptr(address_field_addr(offset), contents); }
+
 inline int oopDesc::size_given_klass(Klass* klass)  {
   int lh = klass->layout_helper();
   int s  = lh >> LogHeapWordSize;  // deliver size scaled by wordSize
--- a/hotspot/src/share/vm/opto/callnode.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/opto/callnode.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1043,6 +1043,51 @@
 //=============================================================================
 uint AllocateArrayNode::size_of() const { return sizeof(*this); }
 
+Node* AllocateArrayNode::Ideal(PhaseGVN *phase, bool can_reshape) {
+  if (remove_dead_region(phase, can_reshape))  return this;
+
+  const Type* type = phase->type(Ideal_length());
+  if (type->isa_int() && type->is_int()->_hi < 0) {
+    if (can_reshape) {
+      PhaseIterGVN *igvn = phase->is_IterGVN();
+      // Unreachable fall through path (negative array length),
+      // the allocation can only throw so disconnect it.
+      Node* proj = proj_out(TypeFunc::Control);
+      Node* catchproj = NULL;
+      if (proj != NULL) {
+        for (DUIterator_Fast imax, i = proj->fast_outs(imax); i < imax; i++) {
+          Node *cn = proj->fast_out(i);
+          if (cn->is_Catch()) {
+            catchproj = cn->as_Multi()->proj_out(CatchProjNode::fall_through_index);
+            break;
+          }
+        }
+      }
+      if (catchproj != NULL && catchproj->outcnt() > 0 &&
+          (catchproj->outcnt() > 1 ||
+           catchproj->unique_out()->Opcode() != Op_Halt)) {
+        assert(catchproj->is_CatchProj(), "must be a CatchProjNode");
+        Node* nproj = catchproj->clone();
+        igvn->register_new_node_with_optimizer(nproj);
+
+        Node *frame = new (phase->C, 1) ParmNode( phase->C->start(), TypeFunc::FramePtr );
+        frame = phase->transform(frame);
+        // Halt & Catch Fire
+        Node *halt = new (phase->C, TypeFunc::Parms) HaltNode( nproj, frame );
+        phase->C->root()->add_req(halt);
+        phase->transform(halt);
+
+        igvn->replace_node(catchproj, phase->C->top());
+        return this;
+      }
+    } else {
+      // Can't correct it during regular GVN so register for IGVN
+      phase->C->record_for_igvn(this);
+    }
+  }
+  return NULL;
+}
+
 // Retrieve the length from the AllocateArrayNode. Narrow the type with a
 // CastII, if appropriate.  If we are not allowed to create new nodes, and
 // a CastII is appropriate, return NULL.
--- a/hotspot/src/share/vm/opto/callnode.hpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/opto/callnode.hpp	Wed Jul 05 16:51:35 2017 +0200
@@ -762,6 +762,7 @@
   }
   virtual int Opcode() const;
   virtual uint size_of() const; // Size is bigger
+  virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
 
   // Dig the length operand out of a array allocation site.
   Node* Ideal_length() {
--- a/hotspot/src/share/vm/opto/macro.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/opto/macro.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -806,8 +806,7 @@
         }
       } else if (use->is_AddP()) {
         // raw memory addresses used only by the initialization
-        _igvn.hash_delete(use);
-        _igvn.subsume_node(use, C->top());
+        _igvn.replace_node(use, C->top());
       } else  {
         assert(false, "only Initialize or AddP expected");
       }
@@ -1291,8 +1290,7 @@
   if (_fallthroughcatchproj != NULL) {
     ctrl = _fallthroughcatchproj->clone();
     transform_later(ctrl);
-    _igvn.hash_delete(_fallthroughcatchproj);
-    _igvn.subsume_node(_fallthroughcatchproj, result_region);
+    _igvn.replace_node(_fallthroughcatchproj, result_region);
   } else {
     ctrl = top();
   }
@@ -1303,8 +1301,7 @@
   } else {
     slow_result = _resproj->clone();
     transform_later(slow_result);
-    _igvn.hash_delete(_resproj);
-    _igvn.subsume_node(_resproj, result_phi_rawoop);
+    _igvn.replace_node(_resproj, result_phi_rawoop);
   }
 
   // Plug slow-path into result merge point
@@ -1613,18 +1610,15 @@
     assert(membar != NULL && membar->Opcode() == Op_MemBarAcquire, "");
     Node* ctrlproj = membar->proj_out(TypeFunc::Control);
     Node* memproj = membar->proj_out(TypeFunc::Memory);
-    _igvn.hash_delete(ctrlproj);
-    _igvn.subsume_node(ctrlproj, fallthroughproj);
-    _igvn.hash_delete(memproj);
-    _igvn.subsume_node(memproj, memproj_fallthrough);
+    _igvn.replace_node(ctrlproj, fallthroughproj);
+    _igvn.replace_node(memproj, memproj_fallthrough);
 
     // Delete FastLock node also if this Lock node is unique user
     // (a loop peeling may clone a Lock node).
     Node* flock = alock->as_Lock()->fastlock_node();
     if (flock->outcnt() == 1) {
       assert(flock->unique_out() == alock, "sanity");
-      _igvn.hash_delete(flock);
-      _igvn.subsume_node(flock, top());
+      _igvn.replace_node(flock, top());
     }
   }
 
@@ -1634,20 +1628,16 @@
     MemBarNode* membar = ctrl->in(0)->as_MemBar();
     assert(membar->Opcode() == Op_MemBarRelease &&
            mem->is_Proj() && membar == mem->in(0), "");
-    _igvn.hash_delete(fallthroughproj);
-    _igvn.subsume_node(fallthroughproj, ctrl);
-    _igvn.hash_delete(memproj_fallthrough);
-    _igvn.subsume_node(memproj_fallthrough, mem);
+    _igvn.replace_node(fallthroughproj, ctrl);
+    _igvn.replace_node(memproj_fallthrough, mem);
     fallthroughproj = ctrl;
     memproj_fallthrough = mem;
     ctrl = membar->in(TypeFunc::Control);
     mem  = membar->in(TypeFunc::Memory);
   }
 
-  _igvn.hash_delete(fallthroughproj);
-  _igvn.subsume_node(fallthroughproj, ctrl);
-  _igvn.hash_delete(memproj_fallthrough);
-  _igvn.subsume_node(memproj_fallthrough, mem);
+  _igvn.replace_node(fallthroughproj, ctrl);
+  _igvn.replace_node(memproj_fallthrough, mem);
   return true;
 }
 
@@ -1879,13 +1869,12 @@
   region->init_req(1, slow_ctrl);
   // region inputs are now complete
   transform_later(region);
-  _igvn.subsume_node(_fallthroughproj, region);
+  _igvn.replace_node(_fallthroughproj, region);
 
   Node *memproj = transform_later( new(C, 1) ProjNode(call, TypeFunc::Memory) );
   mem_phi->init_req(1, memproj );
   transform_later(mem_phi);
-  _igvn.hash_delete(_memproj_fallthrough);
-  _igvn.subsume_node(_memproj_fallthrough, mem_phi);
+  _igvn.replace_node(_memproj_fallthrough, mem_phi);
 }
 
 //------------------------------expand_unlock_node----------------------
@@ -1943,14 +1932,13 @@
   region->init_req(1, slow_ctrl);
   // region inputs are now complete
   transform_later(region);
-  _igvn.subsume_node(_fallthroughproj, region);
+  _igvn.replace_node(_fallthroughproj, region);
 
   Node *memproj = transform_later( new(C, 1) ProjNode(call, TypeFunc::Memory) );
   mem_phi->init_req(1, memproj );
   mem_phi->init_req(2, mem);
   transform_later(mem_phi);
-  _igvn.hash_delete(_memproj_fallthrough);
-  _igvn.subsume_node(_memproj_fallthrough, mem_phi);
+  _igvn.replace_node(_memproj_fallthrough, mem_phi);
 }
 
 //------------------------------expand_macro_nodes----------------------
@@ -1969,9 +1957,7 @@
       if (n->is_AbstractLock()) {
         success = eliminate_locking_node(n->as_AbstractLock());
       } else if (n->Opcode() == Op_Opaque1 || n->Opcode() == Op_Opaque2) {
-        _igvn.add_users_to_worklist(n);
-        _igvn.hash_delete(n);
-        _igvn.subsume_node(n, n->in(1));
+        _igvn.replace_node(n, n->in(1));
         success = true;
       }
       assert(success == (C->macro_count() < old_macro_count), "elimination reduces macro count");
--- a/hotspot/src/share/vm/opto/memnode.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/opto/memnode.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -218,6 +218,26 @@
   // Don't bother trying to transform a dead node
   if( ctl && ctl->is_top() )  return NodeSentinel;
 
+  PhaseIterGVN *igvn = phase->is_IterGVN();
+  // Wait if control on the worklist.
+  if (ctl && can_reshape && igvn != NULL) {
+    Node* bol = NULL;
+    Node* cmp = NULL;
+    if (ctl->in(0)->is_If()) {
+      assert(ctl->is_IfTrue() || ctl->is_IfFalse(), "sanity");
+      bol = ctl->in(0)->in(1);
+      if (bol->is_Bool())
+        cmp = ctl->in(0)->in(1)->in(1);
+    }
+    if (igvn->_worklist.member(ctl) ||
+        (bol != NULL && igvn->_worklist.member(bol)) ||
+        (cmp != NULL && igvn->_worklist.member(cmp)) ) {
+      // This control path may be dead.
+      // Delay this memory node transformation until the control is processed.
+      phase->is_IterGVN()->_worklist.push(this);
+      return NodeSentinel; // caller will return NULL
+    }
+  }
   // Ignore if memory is dead, or self-loop
   Node *mem = in(MemNode::Memory);
   if( phase->type( mem ) == Type::TOP ) return NodeSentinel; // caller will return NULL
@@ -227,14 +247,22 @@
   const Type *t_adr = phase->type( address );
   if( t_adr == Type::TOP )              return NodeSentinel; // caller will return NULL
 
-  PhaseIterGVN *igvn = phase->is_IterGVN();
-  if( can_reshape && igvn != NULL && igvn->_worklist.member(address) ) {
+  if( can_reshape && igvn != NULL &&
+      (igvn->_worklist.member(address) || phase->type(address) != adr_type()) ) {
     // The address's base and type may change when the address is processed.
     // Delay this mem node transformation until the address is processed.
     phase->is_IterGVN()->_worklist.push(this);
     return NodeSentinel; // caller will return NULL
   }
 
+#ifdef ASSERT
+  Node* base = NULL;
+  if (address->is_AddP())
+    base = address->in(AddPNode::Base);
+  assert(base == NULL || t_adr->isa_rawptr() ||
+        !phase->type(base)->higher_equal(TypePtr::NULL_PTR), "NULL+offs not RAW address?");
+#endif
+
   // Avoid independent memory operations
   Node* old_mem = mem;
 
@@ -1307,22 +1335,20 @@
     set_req(MemNode::Control,ctrl);
   }
 
-  // Check for useless control edge in some common special cases
-  if (in(MemNode::Control) != NULL) {
-    intptr_t ignore = 0;
-    Node*    base   = AddPNode::Ideal_base_and_offset(address, phase, ignore);
-    if (base != NULL
+  intptr_t ignore = 0;
+  Node*    base   = AddPNode::Ideal_base_and_offset(address, phase, ignore);
+  if (base != NULL
+      && phase->C->get_alias_index(phase->type(address)->is_ptr()) != Compile::AliasIdxRaw) {
+    // Check for useless control edge in some common special cases
+    if (in(MemNode::Control) != NULL
         && phase->type(base)->higher_equal(TypePtr::NOTNULL)
-        && phase->C->get_alias_index(phase->type(address)->is_ptr()) != Compile::AliasIdxRaw
         && all_controls_dominate(base, phase->C->start())) {
       // A method-invariant, non-null address (constant or 'this' argument).
       set_req(MemNode::Control, NULL);
     }
-  }
-
-  if (EliminateAutoBox && can_reshape && in(Address)->is_AddP()) {
-    Node* base = in(Address)->in(AddPNode::Base);
-    if (base != NULL) {
+
+    if (EliminateAutoBox && can_reshape) {
+      assert(!phase->type(base)->higher_equal(TypePtr::NULL_PTR), "the autobox pointer should be non-null");
       Compile::AliasType* atp = phase->C->alias_type(adr_type());
       if (is_autobox_object(atp)) {
         Node* result = eliminate_autobox(phase);
@@ -1455,10 +1481,11 @@
           jt = _type;
         }
 
-        if (EliminateAutoBox) {
+        if (EliminateAutoBox && adr->is_AddP()) {
           // The pointers in the autobox arrays are always non-null
-          Node* base = in(Address)->in(AddPNode::Base);
-          if (base != NULL) {
+          Node* base = adr->in(AddPNode::Base);
+          if (base != NULL &&
+              !phase->type(base)->higher_equal(TypePtr::NULL_PTR)) {
             Compile::AliasType* atp = phase->C->alias_type(base->adr_type());
             if (is_autobox_cache(atp)) {
               return jt->join(TypePtr::NOTNULL)->is_ptr();
--- a/hotspot/src/share/vm/opto/output.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/opto/output.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -2256,7 +2256,8 @@
     // bother scheduling them.
     Node *last = bb->_nodes[_bb_end];
     if( last->is_Catch() ||
-       (last->is_Mach() && last->as_Mach()->ideal_Opcode() == Op_Halt) ) {
+       // Exclude unreachable path case when Halt node is in a separate block.
+       (_bb_end > 1 && last->is_Mach() && last->as_Mach()->ideal_Opcode() == Op_Halt) ) {
       // There must be a prior call.  Skip it.
       while( !bb->_nodes[--_bb_end]->is_Call() ) {
         assert( bb->_nodes[_bb_end]->is_Proj(), "skipping projections after expected call" );
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/prims/methodHandles.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,2347 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+/*
+ * JSR 292 reference implementation: method handles
+ */
+
+#include "incls/_precompiled.incl"
+#include "incls/_methodHandles.cpp.incl"
+
+bool MethodHandles::_enabled = false; // set true after successful native linkage
+
+MethodHandleEntry* MethodHandles::_entries[MethodHandles::_EK_LIMIT] = {NULL};
+const char*        MethodHandles::_entry_names[_EK_LIMIT+1] = {
+  "check_mtype",
+  "wrong_method_type",          // what happens when there is a type mismatch
+  "invokestatic",               // how a MH emulates invokestatic
+  "invokespecial",              // ditto for the other invokes...
+  "invokevirtual",
+  "invokeinterface",
+  "bound_ref",                  // these are for BMH...
+  "bound_int",
+  "bound_long",
+  "bound_ref_direct",           // (direct versions have a direct methodOop)
+  "bound_int_direct",
+  "bound_long_direct",
+
+  // starting at _adapter_mh_first:
+  "adapter_retype_only",       // these are for AMH...
+  "adapter_check_cast",
+  "adapter_prim_to_prim",
+  "adapter_ref_to_prim",
+  "adapter_prim_to_ref",
+  "adapter_swap_args",
+  "adapter_rot_args",
+  "adapter_dup_args",
+  "adapter_drop_args",
+  "adapter_collect_args",
+  "adapter_spread_args",
+  "adapter_flyby",
+  "adapter_ricochet",
+
+  // optimized adapter types:
+  "adapter_swap_args/1",
+  "adapter_swap_args/2",
+  "adapter_rot_args/1,up",
+  "adapter_rot_args/1,down",
+  "adapter_rot_args/2,up",
+  "adapter_rot_args/2,down",
+  "adapter_prim_to_prim/i2i",
+  "adapter_prim_to_prim/l2i",
+  "adapter_prim_to_prim/d2f",
+  "adapter_prim_to_prim/i2l",
+  "adapter_prim_to_prim/f2d",
+  "adapter_ref_to_prim/unboxi",
+  "adapter_ref_to_prim/unboxl",
+  "adapter_spread_args/0",
+  "adapter_spread_args/1",
+  "adapter_spread_args/more",
+
+  NULL
+};
+
+#ifdef ASSERT
+bool MethodHandles::spot_check_entry_names() {
+  assert(!strcmp(entry_name(_invokestatic_mh), "invokestatic"), "");
+  assert(!strcmp(entry_name(_bound_ref_mh), "bound_ref"), "");
+  assert(!strcmp(entry_name(_adapter_retype_only), "adapter_retype_only"), "");
+  assert(!strcmp(entry_name(_adapter_ricochet), "adapter_ricochet"), "");
+  assert(!strcmp(entry_name(_adapter_opt_unboxi), "adapter_ref_to_prim/unboxi"), "");
+  return true;
+}
+#endif
+
+void MethodHandles::set_enabled(bool z) {
+  if (_enabled != z) {
+    guarantee(z && EnableMethodHandles, "can only enable once, and only if -XX:+EnableMethodHandles");
+    _enabled = z;
+  }
+}
+
+// Note: A method which does not have a TRAPS argument cannot block in the GC
+// or throw exceptions.  Such methods are used in this file to do something quick
+// and local, like parse a data structure.  For speed, such methods work on plain
+// oops, not handles.  Trapping methods uniformly operate on handles.
+
+methodOop MethodHandles::decode_vmtarget(oop vmtarget, int vmindex, oop mtype,
+                                         klassOop& receiver_limit_result, int& decode_flags_result) {
+  if (vmtarget == NULL)  return NULL;
+  assert(methodOopDesc::nonvirtual_vtable_index < 0, "encoding");
+  if (vmindex < 0) {
+    // this DMH performs no dispatch; it is directly bound to a methodOop
+    // A MemberName may either be directly bound to a methodOop,
+    // or it may use the klass/index form; both forms mean the same thing.
+    methodOop m = decode_methodOop(methodOop(vmtarget), decode_flags_result);
+    if ((decode_flags_result & _dmf_has_receiver) != 0
+        && java_dyn_MethodType::is_instance(mtype)) {
+      // Extract receiver type restriction from mtype.ptypes[0].
+      objArrayOop ptypes = java_dyn_MethodType::ptypes(mtype);
+      oop ptype0 = (ptypes == NULL || ptypes->length() < 1) ? oop(NULL) : ptypes->obj_at(0);
+      if (java_lang_Class::is_instance(ptype0))
+        receiver_limit_result = java_lang_Class::as_klassOop(ptype0);
+    }
+    if (vmindex == methodOopDesc::nonvirtual_vtable_index) {
+      // this DMH can be an "invokespecial" version
+      decode_flags_result &= ~_dmf_does_dispatch;
+    } else {
+      assert(vmindex == methodOopDesc::invalid_vtable_index, "random vmindex?");
+    }
+    return m;
+  } else {
+    decode_flags_result |= MethodHandles::_dmf_does_dispatch;
+    assert(vmtarget->is_klass(), "must be class or interface");
+    receiver_limit_result = (klassOop)vmtarget;
+    Klass* tk = Klass::cast((klassOop)vmtarget);
+    if (tk->is_interface()) {
+      // an itable linkage is <interface, itable index>
+      decode_flags_result |= MethodHandles::_dmf_from_interface;
+      return klassItable::method_for_itable_index((klassOop)vmtarget, vmindex);
+    } else {
+      if (!tk->oop_is_instance())
+        tk = instanceKlass::cast(SystemDictionary::object_klass());
+      return ((instanceKlass*)tk)->method_at_vtable(vmindex);
+    }
+  }
+}
+
+// MemberName and DirectMethodHandle have the same linkage to the JVM internals.
+// (MemberName is the non-operational name used for queries and setup.)
+
+methodOop MethodHandles::decode_DirectMethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result) {
+  oop vmtarget = sun_dyn_DirectMethodHandle::vmtarget(mh);
+  int vmindex  = sun_dyn_DirectMethodHandle::vmindex(mh);
+  oop mtype    = sun_dyn_DirectMethodHandle::type(mh);
+  return decode_vmtarget(vmtarget, vmindex, mtype, receiver_limit_result, decode_flags_result);
+}
+
+methodOop MethodHandles::decode_BoundMethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result) {
+  assert(mh->klass() == SystemDictionary::BoundMethodHandle_klass(), "");
+  for (oop bmh = mh;;) {
+    // Bound MHs can be stacked to bind several arguments.
+    oop target = java_dyn_MethodHandle::vmtarget(bmh);
+    if (target == NULL)  return NULL;
+    decode_flags_result |= MethodHandles::_dmf_binds_argument;
+    klassOop tk = target->klass();
+    if (tk == SystemDictionary::BoundMethodHandle_klass()) {
+      bmh = target;
+      continue;
+    } else {
+      if (java_dyn_MethodHandle::is_subclass(tk)) {
+        //assert(tk == SystemDictionary::DirectMethodHandle_klass(), "end of BMH chain must be DMH");
+        return decode_MethodHandle(target, receiver_limit_result, decode_flags_result);
+      } else {
+        // Optimized case:  binding a receiver to a non-dispatched DMH
+        // short-circuits directly to the methodOop.
+        assert(target->is_method(), "must be a simple method");
+        methodOop m = (methodOop) target;
+        DEBUG_ONLY(int argslot = sun_dyn_BoundMethodHandle::vmargslot(bmh));
+        assert(argslot == m->size_of_parameters() - 1, "must be initial argument (receiver)");
+        decode_flags_result |= MethodHandles::_dmf_binds_method;
+        return m;
+      }
+    }
+  }
+}
+
+methodOop MethodHandles::decode_AdapterMethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result) {
+  assert(mh->klass() == SystemDictionary::AdapterMethodHandle_klass(), "");
+  for (oop amh = mh;;) {
+    // Adapter MHs can be stacked to convert several arguments.
+    int conv_op = adapter_conversion_op(sun_dyn_AdapterMethodHandle::conversion(amh));
+    decode_flags_result |= (_dmf_adapter_lsb << conv_op) & _DMF_ADAPTER_MASK;
+    oop target = java_dyn_MethodHandle::vmtarget(amh);
+    if (target == NULL)  return NULL;
+    klassOop tk = target->klass();
+    if (tk == SystemDictionary::AdapterMethodHandle_klass()) {
+      amh = target;
+      continue;
+    } else {
+      // must be a BMH (which will bind some more arguments) or a DMH (for the final call)
+      return MethodHandles::decode_MethodHandle(target, receiver_limit_result, decode_flags_result);
+    }
+  }
+}
+
+methodOop MethodHandles::decode_MethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result) {
+  if (mh == NULL)  return NULL;
+  klassOop mhk = mh->klass();
+  assert(java_dyn_MethodHandle::is_subclass(mhk), "must be a MethodHandle");
+  if (mhk == SystemDictionary::DirectMethodHandle_klass()) {
+    return decode_DirectMethodHandle(mh, receiver_limit_result, decode_flags_result);
+  } else if (mhk == SystemDictionary::BoundMethodHandle_klass()) {
+    return decode_BoundMethodHandle(mh, receiver_limit_result, decode_flags_result);
+  } else if (mhk == SystemDictionary::AdapterMethodHandle_klass()) {
+    return decode_AdapterMethodHandle(mh, receiver_limit_result, decode_flags_result);
+  } else {
+    assert(false, "cannot parse this MH");
+    return NULL;              // random MH?
+  }
+}
+
+methodOop MethodHandles::decode_methodOop(methodOop m, int& decode_flags_result) {
+  assert(m->is_method(), "");
+  if (m->is_static()) {
+    // check that signature begins '(L' or '([' (not '(I', '()', etc.)
+    symbolOop sig = m->signature();
+    BasicType recv_bt = char2type(sig->byte_at(1));
+    // Note: recv_bt might be T_ILLEGAL if byte_at(2) is ')'
+    assert(sig->byte_at(0) == '(', "must be method sig");
+    if (recv_bt == T_OBJECT || recv_bt == T_ARRAY)
+      decode_flags_result |= _dmf_has_receiver;
+  } else {
+    // non-static method
+    decode_flags_result |= _dmf_has_receiver;
+    if (!m->can_be_statically_bound() && !m->is_initializer()) {
+      decode_flags_result |= _dmf_does_dispatch;
+      if (Klass::cast(m->method_holder())->is_interface())
+        decode_flags_result |= _dmf_from_interface;
+    }
+  }
+  return m;
+}
+
+
+// A trusted party is handing us a cookie to determine a method.
+// Let's boil it down to the method oop they really want.
+methodOop MethodHandles::decode_method(oop x, klassOop& receiver_limit_result, int& decode_flags_result) {
+  decode_flags_result = 0;
+  receiver_limit_result = NULL;
+  klassOop xk = x->klass();
+  if (xk == Universe::methodKlassObj()) {
+    return decode_methodOop((methodOop) x, decode_flags_result);
+  } else if (xk == SystemDictionary::MemberName_klass()) {
+    // Note: This only works if the MemberName has already been resolved.
+    return decode_MemberName(x, receiver_limit_result, decode_flags_result);
+  } else if (java_dyn_MethodHandle::is_subclass(xk)) {
+    return decode_MethodHandle(x, receiver_limit_result, decode_flags_result);
+  } else if (xk == SystemDictionary::reflect_method_klass()) {
+    oop clazz  = java_lang_reflect_Method::clazz(x);
+    int slot   = java_lang_reflect_Method::slot(x);
+    klassOop k = java_lang_Class::as_klassOop(clazz);
+    if (k != NULL && Klass::cast(k)->oop_is_instance())
+      return decode_methodOop(instanceKlass::cast(k)->method_with_idnum(slot),
+                              decode_flags_result);
+  } else if (xk == SystemDictionary::reflect_constructor_klass()) {
+    oop clazz  = java_lang_reflect_Constructor::clazz(x);
+    int slot   = java_lang_reflect_Constructor::slot(x);
+    klassOop k = java_lang_Class::as_klassOop(clazz);
+    if (k != NULL && Klass::cast(k)->oop_is_instance())
+      return decode_methodOop(instanceKlass::cast(k)->method_with_idnum(slot),
+                              decode_flags_result);
+  } else {
+    // unrecognized object
+    assert(!x->is_method(), "already checked");
+    assert(!sun_dyn_MemberName::is_instance(x), "already checked");
+  }
+  return NULL;
+}
+
+
+int MethodHandles::decode_MethodHandle_stack_pushes(oop mh) {
+  if (mh->klass() == SystemDictionary::DirectMethodHandle_klass())
+    return 0;                   // no push/pop
+  int this_vmslots = java_dyn_MethodHandle::vmslots(mh);
+  int last_vmslots = 0;
+  oop last_mh = mh;
+  for (;;) {
+    oop target = java_dyn_MethodHandle::vmtarget(last_mh);
+    if (target->klass() == SystemDictionary::DirectMethodHandle_klass()) {
+      last_vmslots = java_dyn_MethodHandle::vmslots(target);
+      break;
+    } else if (!java_dyn_MethodHandle::is_instance(target)) {
+      // might be klass or method
+      assert(target->is_method(), "must get here with a direct ref to method");
+      last_vmslots = methodOop(target)->size_of_parameters();
+      break;
+    }
+    last_mh = target;
+  }
+  // If I am called with fewer VM slots than my ultimate callee,
+  // it must be that I push the additionally needed slots.
+  // Likewise if am called with more VM slots, I will pop them.
+  return (last_vmslots - this_vmslots);
+}
+
+
+// MemberName support
+
+// import sun_dyn_MemberName.*
+enum {
+  IS_METHOD      = sun_dyn_MemberName::MN_IS_METHOD,
+  IS_CONSTRUCTOR = sun_dyn_MemberName::MN_IS_CONSTRUCTOR,
+  IS_FIELD       = sun_dyn_MemberName::MN_IS_FIELD,
+  IS_TYPE        = sun_dyn_MemberName::MN_IS_TYPE,
+  SEARCH_SUPERCLASSES = sun_dyn_MemberName::MN_SEARCH_SUPERCLASSES,
+  SEARCH_INTERFACES   = sun_dyn_MemberName::MN_SEARCH_INTERFACES,
+  ALL_KINDS      = IS_METHOD | IS_CONSTRUCTOR | IS_FIELD | IS_TYPE,
+  VM_INDEX_UNINITIALIZED = sun_dyn_MemberName::VM_INDEX_UNINITIALIZED
+};
+
+void MethodHandles::init_MemberName(oop mname_oop, oop target_oop) {
+  if (target_oop->klass() == SystemDictionary::reflect_field_klass()) {
+    oop clazz = java_lang_reflect_Field::clazz(target_oop); // fd.field_holder()
+    int slot  = java_lang_reflect_Field::slot(target_oop);  // fd.index()
+    int mods  = java_lang_reflect_Field::modifiers(target_oop);
+    klassOop k = java_lang_Class::as_klassOop(clazz);
+    int offset = instanceKlass::cast(k)->offset_from_fields(slot);
+    init_MemberName(mname_oop, k, accessFlags_from(mods), offset);
+  } else {
+    int decode_flags = 0; klassOop receiver_limit = NULL;
+    methodOop m = MethodHandles::decode_method(target_oop,
+                                               receiver_limit, decode_flags);
+    bool do_dispatch = ((decode_flags & MethodHandles::_dmf_does_dispatch) != 0);
+    init_MemberName(mname_oop, m, do_dispatch);
+  }
+}
+
+void MethodHandles::init_MemberName(oop mname_oop, methodOop m, bool do_dispatch) {
+  int flags = ((m->is_initializer() ? IS_CONSTRUCTOR : IS_METHOD)
+               | (jushort)( m->access_flags().as_short() & JVM_RECOGNIZED_METHOD_MODIFIERS ));
+  oop vmtarget = m;
+  int vmindex  = methodOopDesc::invalid_vtable_index;  // implies no info yet
+  if (!do_dispatch || (flags & IS_CONSTRUCTOR) || m->can_be_statically_bound())
+    vmindex = methodOopDesc::nonvirtual_vtable_index; // implies never any dispatch
+  assert(vmindex != VM_INDEX_UNINITIALIZED, "Java sentinel value");
+  sun_dyn_MemberName::set_vmtarget(mname_oop, vmtarget);
+  sun_dyn_MemberName::set_vmindex(mname_oop,  vmindex);
+  sun_dyn_MemberName::set_flags(mname_oop,    flags);
+}
+
+void MethodHandles::init_MemberName(oop mname_oop, klassOop field_holder, AccessFlags mods, int offset) {
+  int flags = (IS_FIELD | (jushort)( mods.as_short() & JVM_RECOGNIZED_FIELD_MODIFIERS ));
+  oop vmtarget = field_holder;
+  int vmindex  = offset;  // implies no info yet
+  assert(vmindex != VM_INDEX_UNINITIALIZED, "bad alias on vmindex");
+  sun_dyn_MemberName::set_vmtarget(mname_oop, vmtarget);
+  sun_dyn_MemberName::set_vmindex(mname_oop,  vmindex);
+  sun_dyn_MemberName::set_flags(mname_oop,    flags);
+}
+
+
+methodOop MethodHandles::decode_MemberName(oop mname, klassOop& receiver_limit_result, int& decode_flags_result) {
+  int flags  = sun_dyn_MemberName::flags(mname);
+  if ((flags & (IS_METHOD | IS_CONSTRUCTOR)) == 0)  return NULL;  // not invocable
+  oop vmtarget = sun_dyn_MemberName::vmtarget(mname);
+  int vmindex  = sun_dyn_MemberName::vmindex(mname);
+  if (vmindex == VM_INDEX_UNINITIALIZED)  return NULL; // not resolved
+  return decode_vmtarget(vmtarget, vmindex, NULL, receiver_limit_result, decode_flags_result);
+}
+
+// An unresolved member name is a mere symbolic reference.
+// Resolving it plants a vmtarget/vmindex in it,
+// which refers dirctly to JVM internals.
+void MethodHandles::resolve_MemberName(Handle mname, TRAPS) {
+  assert(sun_dyn_MemberName::is_instance(mname()), "");
+#ifdef ASSERT
+  // If this assert throws, renegotiate the sentinel value used by the Java code,
+  // so that it is distinct from any valid vtable index value, and any special
+  // values defined in methodOopDesc::VtableIndexFlag.
+  // The point of the slop is to give the Java code and the JVM some room
+  // to independently specify sentinel values.
+  const int sentinel_slop  = 10;
+  const int sentinel_limit = methodOopDesc::highest_unused_vtable_index_value - sentinel_slop;
+  assert(VM_INDEX_UNINITIALIZED < sentinel_limit, "Java sentinel != JVM sentinels");
+#endif
+  if (sun_dyn_MemberName::vmindex(mname()) != VM_INDEX_UNINITIALIZED)
+    return;  // already resolved
+  oop defc_oop = sun_dyn_MemberName::clazz(mname());
+  oop name_str = sun_dyn_MemberName::name(mname());
+  oop type_str = sun_dyn_MemberName::type(mname());
+  int flags    = sun_dyn_MemberName::flags(mname());
+
+  if (defc_oop == NULL || name_str == NULL || type_str == NULL) {
+    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "nothing to resolve");
+  }
+  klassOop defc_klassOop = java_lang_Class::as_klassOop(defc_oop);
+  defc_oop = NULL;  // safety
+  if (defc_klassOop == NULL)  return;  // a primitive; no resolution possible
+  if (!Klass::cast(defc_klassOop)->oop_is_instance()) {
+    if (!Klass::cast(defc_klassOop)->oop_is_array())  return;
+    defc_klassOop = SystemDictionary::object_klass();
+  }
+  instanceKlassHandle defc(THREAD, defc_klassOop);
+  defc_klassOop = NULL;  // safety
+  if (defc.is_null()) {
+    THROW_MSG(vmSymbols::java_lang_InternalError(), "primitive class");
+  }
+  defc->link_class(CHECK);
+
+  // convert the external string name to an internal symbol
+  symbolHandle name(THREAD, java_lang_String::as_symbol_or_null(name_str));
+  if (name.is_null())  return;  // no such name
+  name_str = NULL;  // safety
+
+  // convert the external string or reflective type to an internal signature
+  bool force_signature = (name() == vmSymbols::invoke_name());
+  symbolHandle type; {
+    symbolOop type_sym = NULL;
+    if (java_dyn_MethodType::is_instance(type_str)) {
+      type_sym = java_dyn_MethodType::as_signature(type_str, force_signature, CHECK);
+    } else if (java_lang_Class::is_instance(type_str)) {
+      type_sym = java_lang_Class::as_signature(type_str, force_signature, CHECK);
+    } else if (java_lang_String::is_instance(type_str)) {
+      if (force_signature) {
+        type     = java_lang_String::as_symbol(type_str, CHECK);
+      } else {
+        type_sym = java_lang_String::as_symbol_or_null(type_str);
+      }
+    } else {
+      THROW_MSG(vmSymbols::java_lang_InternalError(), "unrecognized type");
+    }
+    if (type_sym != NULL)
+      type = symbolHandle(THREAD, type_sym);
+  }
+  if (type.is_null())  return;  // no such signature exists in the VM
+  type_str = NULL; // safety
+
+  // Time to do the lookup.
+  switch (flags & ALL_KINDS) {
+  case IS_METHOD:
+    {
+      CallInfo result;
+      {
+        EXCEPTION_MARK;
+        if ((flags & JVM_ACC_STATIC) != 0) {
+          LinkResolver::resolve_static_call(result,
+                        defc, name, type, KlassHandle(), false, false, THREAD);
+        } else if (defc->is_interface()) {
+          LinkResolver::resolve_interface_call(result, Handle(), defc,
+                        defc, name, type, KlassHandle(), false, false, THREAD);
+        } else {
+          LinkResolver::resolve_virtual_call(result, Handle(), defc,
+                        defc, name, type, KlassHandle(), false, false, THREAD);
+        }
+        if (HAS_PENDING_EXCEPTION) {
+          CLEAR_PENDING_EXCEPTION;
+          return;
+        }
+      }
+      methodHandle m = result.resolved_method();
+      oop vmtarget = NULL;
+      int vmindex = methodOopDesc::nonvirtual_vtable_index;
+      if (defc->is_interface()) {
+        vmindex = klassItable::compute_itable_index(m());
+        assert(vmindex >= 0, "");
+      } else if (result.has_vtable_index()) {
+        vmindex = result.vtable_index();
+        assert(vmindex >= 0, "");
+      }
+      assert(vmindex != VM_INDEX_UNINITIALIZED, "");
+      if (vmindex < 0) {
+        assert(result.is_statically_bound(), "");
+        vmtarget = m();
+      } else {
+        vmtarget = result.resolved_klass()->as_klassOop();
+      }
+      int mods = (m->access_flags().as_short() & JVM_RECOGNIZED_METHOD_MODIFIERS);
+      sun_dyn_MemberName::set_vmtarget(mname(), vmtarget);
+      sun_dyn_MemberName::set_vmindex(mname(),  vmindex);
+      sun_dyn_MemberName::set_modifiers(mname(), mods);
+      DEBUG_ONLY(int junk; klassOop junk2);
+      assert(decode_MemberName(mname(), junk2, junk) == result.resolved_method()(),
+             "properly stored for later decoding");
+      return;
+    }
+  case IS_CONSTRUCTOR:
+    {
+      CallInfo result;
+      {
+        EXCEPTION_MARK;
+        if (name() == vmSymbols::object_initializer_name()) {
+          LinkResolver::resolve_special_call(result,
+                        defc, name, type, KlassHandle(), false, THREAD);
+        } else {
+          break;                // will throw after end of switch
+        }
+        if (HAS_PENDING_EXCEPTION) {
+          CLEAR_PENDING_EXCEPTION;
+          return;
+        }
+      }
+      assert(result.is_statically_bound(), "");
+      methodHandle m = result.resolved_method();
+      oop vmtarget = m();
+      int vmindex  = methodOopDesc::nonvirtual_vtable_index;
+      int mods     = (m->access_flags().as_short() & JVM_RECOGNIZED_METHOD_MODIFIERS);
+      sun_dyn_MemberName::set_vmtarget(mname(), vmtarget);
+      sun_dyn_MemberName::set_vmindex(mname(),  vmindex);
+      sun_dyn_MemberName::set_modifiers(mname(), mods);
+      DEBUG_ONLY(int junk; klassOop junk2);
+      assert(decode_MemberName(mname(), junk2, junk) == result.resolved_method()(),
+             "properly stored for later decoding");
+      return;
+    }
+  case IS_FIELD:
+    {
+      // This is taken from LinkResolver::resolve_field, sans access checks.
+      fieldDescriptor fd; // find_field initializes fd if found
+      KlassHandle sel_klass(THREAD, instanceKlass::cast(defc())->find_field(name(), type(), &fd));
+      // check if field exists; i.e., if a klass containing the field def has been selected
+      if (sel_klass.is_null())  return;
+      oop vmtarget = sel_klass->as_klassOop();
+      int vmindex  = fd.offset();
+      int mods     = (fd.access_flags().as_short() & JVM_RECOGNIZED_FIELD_MODIFIERS);
+      if (vmindex == VM_INDEX_UNINITIALIZED)  break;  // should not happen
+      sun_dyn_MemberName::set_vmtarget(mname(),  vmtarget);
+      sun_dyn_MemberName::set_vmindex(mname(),   vmindex);
+      sun_dyn_MemberName::set_modifiers(mname(), mods);
+      return;
+    }
+  }
+  THROW_MSG(vmSymbols::java_lang_InternalError(), "unrecognized MemberName format");
+}
+
+// Conversely, a member name which is only initialized from JVM internals
+// may have null defc, name, and type fields.
+// Resolving it plants a vmtarget/vmindex in it,
+// which refers directly to JVM internals.
+void MethodHandles::expand_MemberName(Handle mname, int suppress, TRAPS) {
+  assert(sun_dyn_MemberName::is_instance(mname()), "");
+  oop vmtarget = sun_dyn_MemberName::vmtarget(mname());
+  int vmindex  = sun_dyn_MemberName::vmindex(mname());
+  if (vmtarget == NULL || vmindex == VM_INDEX_UNINITIALIZED) {
+    THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "nothing to expand");
+  }
+
+  bool have_defc = (sun_dyn_MemberName::clazz(mname()) != NULL);
+  bool have_name = (sun_dyn_MemberName::name(mname()) != NULL);
+  bool have_type = (sun_dyn_MemberName::type(mname()) != NULL);
+  int flags      = sun_dyn_MemberName::flags(mname());
+
+  if (suppress != 0) {
+    if (suppress & _suppress_defc)  have_defc = true;
+    if (suppress & _suppress_name)  have_name = true;
+    if (suppress & _suppress_type)  have_type = true;
+  }
+
+  if (have_defc && have_name && have_type)  return;  // nothing needed
+
+  switch (flags & ALL_KINDS) {
+  case IS_METHOD:
+  case IS_CONSTRUCTOR:
+    {
+      klassOop receiver_limit = NULL;
+      int      decode_flags   = 0;
+      methodHandle m(THREAD, decode_vmtarget(vmtarget, vmindex, NULL,
+                                             receiver_limit, decode_flags));
+      if (m.is_null())  break;
+      if (!have_defc) {
+        klassOop defc = m->method_holder();
+        if (receiver_limit != NULL && receiver_limit != defc
+            && Klass::cast(receiver_limit)->is_subtype_of(defc))
+          defc = receiver_limit;
+        sun_dyn_MemberName::set_clazz(mname(), Klass::cast(defc)->java_mirror());
+      }
+      if (!have_name) {
+        //not java_lang_String::create_from_symbol; let's intern member names
+        Handle name = StringTable::intern(m->name(), CHECK);
+        sun_dyn_MemberName::set_name(mname(), name());
+      }
+      if (!have_type) {
+        Handle type = java_lang_String::create_from_symbol(m->signature(), CHECK);
+        sun_dyn_MemberName::set_type(mname(), type());
+      }
+      return;
+    }
+  case IS_FIELD:
+    {
+      // This is taken from LinkResolver::resolve_field, sans access checks.
+      if (!vmtarget->is_klass())  break;
+      if (!Klass::cast((klassOop) vmtarget)->oop_is_instance())  break;
+      instanceKlassHandle defc(THREAD, (klassOop) vmtarget);
+      bool is_static = ((flags & JVM_ACC_STATIC) != 0);
+      fieldDescriptor fd; // find_field initializes fd if found
+      if (!defc->find_field_from_offset(vmindex, is_static, &fd))
+        break;                  // cannot expand
+      if (!have_defc) {
+        sun_dyn_MemberName::set_clazz(mname(), defc->java_mirror());
+      }
+      if (!have_name) {
+        //not java_lang_String::create_from_symbol; let's intern member names
+        Handle name = StringTable::intern(fd.name(), CHECK);
+        sun_dyn_MemberName::set_name(mname(), name());
+      }
+      if (!have_type) {
+        Handle type = java_lang_String::create_from_symbol(fd.signature(), CHECK);
+        sun_dyn_MemberName::set_type(mname(), type());
+      }
+      return;
+    }
+  }
+  THROW_MSG(vmSymbols::java_lang_InternalError(), "unrecognized MemberName format");
+}
+
+int MethodHandles::find_MemberNames(klassOop k,
+                                    symbolOop name, symbolOop sig,
+                                    int mflags, klassOop caller,
+                                    int skip, objArrayOop results) {
+  DEBUG_ONLY(No_Safepoint_Verifier nsv);
+  // this code contains no safepoints!
+
+  // %%% take caller into account!
+
+  if (k == NULL || !Klass::cast(k)->oop_is_instance())  return -1;
+
+  int rfill = 0, rlimit = results->length(), rskip = skip;
+  // overflow measurement:
+  int overflow = 0, overflow_limit = MAX2(1000, rlimit);
+
+  int match_flags = mflags;
+  bool search_superc = ((match_flags & SEARCH_SUPERCLASSES) != 0);
+  bool search_intfc  = ((match_flags & SEARCH_INTERFACES)   != 0);
+  bool local_only = !(search_superc | search_intfc);
+  bool classes_only = false;
+
+  if (name != NULL) {
+    if (name->utf8_length() == 0)  return 0; // a match is not possible
+  }
+  if (sig != NULL) {
+    if (sig->utf8_length() == 0)  return 0; // a match is not possible
+    if (sig->byte_at(0) == '(')
+      match_flags &= ~(IS_FIELD | IS_TYPE);
+    else
+      match_flags &= ~(IS_CONSTRUCTOR | IS_METHOD);
+  }
+
+  if ((match_flags & IS_TYPE) != 0) {
+    // NYI, and Core Reflection works quite well for this query
+  }
+
+  if ((match_flags & IS_FIELD) != 0) {
+    for (FieldStream st(k, local_only, !search_intfc); !st.eos(); st.next()) {
+      if (name != NULL && st.name() != name)
+          continue;
+      if (sig != NULL && st.signature() != sig)
+        continue;
+      // passed the filters
+      if (rskip > 0) {
+        --rskip;
+      } else if (rfill < rlimit) {
+        oop result = results->obj_at(rfill++);
+        if (!sun_dyn_MemberName::is_instance(result))
+          return -99;  // caller bug!
+        MethodHandles::init_MemberName(result, st.klass()->as_klassOop(), st.access_flags(), st.offset());
+      } else if (++overflow >= overflow_limit) {
+        match_flags = 0; break; // got tired of looking at overflow
+      }
+    }
+  }
+
+  if ((match_flags & (IS_METHOD | IS_CONSTRUCTOR)) != 0) {
+    // watch out for these guys:
+    symbolOop init_name   = vmSymbols::object_initializer_name();
+    symbolOop clinit_name = vmSymbols::class_initializer_name();
+    if (name == clinit_name)  clinit_name = NULL; // hack for exposing <clinit>
+    bool negate_name_test = false;
+    // fix name so that it captures the intention of IS_CONSTRUCTOR
+    if (!(match_flags & IS_METHOD)) {
+      // constructors only
+      if (name == NULL) {
+        name = init_name;
+      } else if (name != init_name) {
+        return 0;               // no constructors of this method name
+      }
+    } else if (!(match_flags & IS_CONSTRUCTOR)) {
+      // methods only
+      if (name == NULL) {
+        name = init_name;
+        negate_name_test = true; // if we see the name, we *omit* the entry
+      } else if (name == init_name) {
+        return 0;               // no methods of this constructor name
+      }
+    } else {
+      // caller will accept either sort; no need to adjust name
+    }
+    for (MethodStream st(k, local_only, !search_intfc); !st.eos(); st.next()) {
+      methodOop m = st.method();
+      symbolOop m_name = m->name();
+      if (m_name == clinit_name)
+        continue;
+      if (name != NULL && ((m_name != name) ^ negate_name_test))
+          continue;
+      if (sig != NULL && m->signature() != sig)
+        continue;
+      // passed the filters
+      if (rskip > 0) {
+        --rskip;
+      } else if (rfill < rlimit) {
+        oop result = results->obj_at(rfill++);
+        if (!sun_dyn_MemberName::is_instance(result))
+          return -99;  // caller bug!
+        MethodHandles::init_MemberName(result, m, true);
+      } else if (++overflow >= overflow_limit) {
+        match_flags = 0; break; // got tired of looking at overflow
+      }
+    }
+  }
+
+  // return number of elements we at leasted wanted to initialize
+  return rfill + overflow;
+}
+
+
+
+
+// Decode the vmtarget field of a method handle.
+// Sanitize out methodOops, klassOops, and any other non-Java data.
+// This is for debugging and reflection.
+oop MethodHandles::encode_target(Handle mh, int format, TRAPS) {
+  assert(java_dyn_MethodHandle::is_instance(mh()), "must be a MH");
+  if (format == ETF_HANDLE_OR_METHOD_NAME) {
+    oop target = java_dyn_MethodHandle::vmtarget(mh());
+    if (target == NULL) {
+      return NULL;                // unformed MH
+    }
+    klassOop tklass = target->klass();
+    if (Klass::cast(tklass)->is_subclass_of(SystemDictionary::object_klass())) {
+      return target;              // target is another MH (or something else?)
+    }
+  }
+  if (format == ETF_DIRECT_HANDLE) {
+    oop target = mh();
+    for (;;) {
+      if (target->klass() == SystemDictionary::DirectMethodHandle_klass()) {
+        return target;
+      }
+      if (!java_dyn_MethodHandle::is_instance(target)){
+        return NULL;                // unformed MH
+      }
+      target = java_dyn_MethodHandle::vmtarget(target);
+    }
+  }
+  // cases of metadata in MH.vmtarget:
+  // - AMH can have methodOop for static invoke with bound receiver
+  // - DMH can have methodOop for static invoke (on variable receiver)
+  // - DMH can have klassOop for dispatched (non-static) invoke
+  klassOop receiver_limit = NULL;
+  int decode_flags = 0;
+  methodOop m = decode_MethodHandle(mh(), receiver_limit, decode_flags);
+  if (m == NULL)  return NULL;
+  switch (format) {
+  case ETF_REFLECT_METHOD:
+    // same as jni_ToReflectedMethod:
+    if (m->is_initializer()) {
+      return Reflection::new_constructor(m, THREAD);
+    } else {
+      return Reflection::new_method(m, UseNewReflection, false, THREAD);
+    }
+
+  case ETF_HANDLE_OR_METHOD_NAME:   // method, not handle
+  case ETF_METHOD_NAME:
+    {
+      if (SystemDictionary::MemberName_klass() == NULL)  break;
+      instanceKlassHandle mname_klass(THREAD, SystemDictionary::MemberName_klass());
+      mname_klass->initialize(CHECK_NULL);
+      Handle mname = mname_klass->allocate_instance_handle(CHECK_NULL);
+      sun_dyn_MemberName::set_vmindex(mname(), VM_INDEX_UNINITIALIZED);
+      bool do_dispatch = ((decode_flags & MethodHandles::_dmf_does_dispatch) != 0);
+      init_MemberName(mname(), m, do_dispatch);
+      expand_MemberName(mname, 0, CHECK_NULL);
+      return mname();
+    }
+  }
+
+  // Unknown format code.
+  char msg[50];
+  jio_snprintf(msg, sizeof(msg), "unknown getTarget format=%d", format);
+  THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), msg);
+}
+
+bool MethodHandles::class_cast_needed(klassOop src, klassOop dst) {
+  if (src == dst || dst == SystemDictionary::object_klass())
+    return false;                               // quickest checks
+  Klass* srck = Klass::cast(src);
+  Klass* dstk = Klass::cast(dst);
+  if (dstk->is_interface()) {
+    // interface receivers can safely be viewed as untyped,
+    // because interface calls always include a dynamic check
+    //dstk = Klass::cast(SystemDictionary::object_klass());
+    return false;
+  }
+  if (srck->is_interface()) {
+    // interface arguments must be viewed as untyped
+    //srck = Klass::cast(SystemDictionary::object_klass());
+    return true;
+  }
+  return !srck->is_subclass_of(dstk->as_klassOop());
+}
+
+static oop object_java_mirror() {
+  return Klass::cast(SystemDictionary::object_klass())->java_mirror();
+}
+
+bool MethodHandles::same_basic_type_for_arguments(BasicType src,
+                                                  BasicType dst,
+                                                  bool for_return) {
+  // return values can always be forgotten:
+  if (for_return && dst == T_VOID)  return true;
+  assert(src != T_VOID && dst != T_VOID, "should not be here");
+  if (src == dst)  return true;
+  if (type2size[src] != type2size[dst])  return false;
+  // allow reinterpretation casts for integral widening
+  if (is_subword_type(src)) { // subwords can fit in int or other subwords
+    if (dst == T_INT)         // any subword fits in an int
+      return true;
+    if (src == T_BOOLEAN)     // boolean fits in any subword
+      return is_subword_type(dst);
+    if (src == T_BYTE && dst == T_SHORT)
+      return true;            // remaining case: byte fits in short
+  }
+  // allow float/fixed reinterpretation casts
+  if (src == T_FLOAT)   return dst == T_INT;
+  if (src == T_INT)     return dst == T_FLOAT;
+  if (src == T_DOUBLE)  return dst == T_LONG;
+  if (src == T_LONG)    return dst == T_DOUBLE;
+  return false;
+}
+
+const char* MethodHandles::check_method_receiver(methodOop m,
+                                                 klassOop passed_recv_type) {
+  assert(!m->is_static(), "caller resp.");
+  if (passed_recv_type == NULL)
+    return "receiver type is primitive";
+  if (class_cast_needed(passed_recv_type, m->method_holder())) {
+    Klass* formal = Klass::cast(m->method_holder());
+    return SharedRuntime::generate_class_cast_message("receiver type",
+                                                      formal->external_name());
+  }
+  return NULL;                  // checks passed
+}
+
+// Verify that m's signature can be called type-safely by a method handle
+// of the given method type 'mtype'.
+// It takes a TRAPS argument because it must perform symbol lookups.
+void MethodHandles::verify_method_signature(methodHandle m,
+                                            Handle mtype,
+                                            int first_ptype_pos,
+                                            KlassHandle insert_ptype,
+                                            TRAPS) {
+  objArrayHandle ptypes(THREAD, java_dyn_MethodType::ptypes(mtype()));
+  int pnum = first_ptype_pos;
+  int pmax = ptypes->length();
+  int mnum = 0;                 // method argument
+  const char* err = NULL;
+  for (SignatureStream ss(m->signature()); !ss.is_done(); ss.next()) {
+    oop ptype_oop = NULL;
+    if (ss.at_return_type()) {
+      if (pnum != pmax)
+        { err = "too many arguments"; break; }
+      ptype_oop = java_dyn_MethodType::rtype(mtype());
+    } else {
+      if (pnum >= pmax)
+        { err = "not enough arguments"; break; }
+      if (pnum >= 0)
+        ptype_oop = ptypes->obj_at(pnum);
+      else if (insert_ptype.is_null())
+        ptype_oop = NULL;
+      else
+        ptype_oop = insert_ptype->java_mirror();
+      pnum += 1;
+      mnum += 1;
+    }
+    klassOop  mklass = NULL;
+    BasicType mtype  = ss.type();
+    if (mtype == T_ARRAY)  mtype = T_OBJECT; // fold all refs to T_OBJECT
+    if (mtype == T_OBJECT) {
+      if (ptype_oop == NULL) {
+        // null matches any reference
+        continue;
+      }
+      // If we fail to resolve types at this point, we will throw an error.
+      symbolOop    name_oop = ss.as_symbol(CHECK);
+      symbolHandle name(THREAD, name_oop);
+      instanceKlass* mk = instanceKlass::cast(m->method_holder());
+      Handle loader(THREAD, mk->class_loader());
+      Handle domain(THREAD, mk->protection_domain());
+      mklass = SystemDictionary::resolve_or_fail(name, loader, domain,
+                                                 true, CHECK);
+    }
+    if (ptype_oop == NULL) {
+      // null does not match any non-reference; use Object to report the error
+      ptype_oop = object_java_mirror();
+    }
+    klassOop  pklass = NULL;
+    BasicType ptype  = java_lang_Class::as_BasicType(ptype_oop, &pklass);
+    if (!ss.at_return_type()) {
+      err = check_argument_type_change(ptype, pklass, mtype, mklass, mnum);
+    } else {
+      err = check_return_type_change(mtype, mklass, ptype, pklass); // note reversal!
+    }
+    if (err != NULL)  break;
+  }
+
+  if (err != NULL) {
+    THROW_MSG(vmSymbols::java_lang_InternalError(), err);
+  }
+}
+
+// Main routine for verifying the MethodHandle.type of a proposed
+// direct or bound-direct method handle.
+void MethodHandles::verify_method_type(methodHandle m,
+                                       Handle mtype,
+                                       bool has_bound_recv,
+                                       KlassHandle bound_recv_type,
+                                       TRAPS) {
+  bool m_needs_receiver = !m->is_static();
+
+  const char* err = NULL;
+
+  int first_ptype_pos = m_needs_receiver ? 1 : 0;
+  if (has_bound_recv && err == NULL) {
+    first_ptype_pos -= 1;
+    if (m_needs_receiver && bound_recv_type.is_null())
+      { err = "bound receiver is not an object"; goto die; }
+  }
+
+  if (m_needs_receiver && err == NULL) {
+    objArrayOop ptypes = java_dyn_MethodType::ptypes(mtype());
+    if (ptypes->length() < first_ptype_pos)
+      { err = "receiver argument is missing"; goto die; }
+    if (first_ptype_pos == -1)
+      err = check_method_receiver(m(), bound_recv_type->as_klassOop());
+    else
+      err = check_method_receiver(m(), java_lang_Class::as_klassOop(ptypes->obj_at(0)));
+    if (err != NULL)  goto die;
+  }
+
+  // Check the other arguments for mistypes.
+  verify_method_signature(m, mtype, first_ptype_pos, bound_recv_type, CHECK);
+  return;
+
+ die:
+  THROW_MSG(vmSymbols::java_lang_InternalError(), err);
+}
+
+void MethodHandles::verify_vmslots(Handle mh, TRAPS) {
+  // Verify vmslots.
+  int check_slots = argument_slot_count(java_dyn_MethodHandle::type(mh()));
+  if (java_dyn_MethodHandle::vmslots(mh()) != check_slots) {
+    THROW_MSG(vmSymbols::java_lang_InternalError(), "bad vmslots in BMH");
+  }
+}
+
+void MethodHandles::verify_vmargslot(Handle mh, int argnum, int argslot, TRAPS) {
+  // Verify that argslot points at the given argnum.
+  int check_slot = argument_slot(java_dyn_MethodHandle::type(mh()), argnum);
+  if (argslot != check_slot || argslot < 0) {
+    const char* fmt = "for argnum of %d, vmargslot is %d, should be %d";
+    size_t msglen = strlen(fmt) + 3*11 + 1;
+    char* msg = NEW_RESOURCE_ARRAY(char, msglen);
+    jio_snprintf(msg, msglen, fmt, argnum, argslot, check_slot);
+    THROW_MSG(vmSymbols::java_lang_InternalError(), msg);
+  }
+}
+
+// Verify the correspondence between two method types.
+// Apart from the advertised changes, caller method type X must
+// be able to invoke the callee method Y type with no violations
+// of type integrity.
+// Return NULL if all is well, else a short error message.
+const char* MethodHandles::check_method_type_change(oop src_mtype, int src_beg, int src_end,
+                                                    int insert_argnum, oop insert_type,
+                                                    int change_argnum, oop change_type,
+                                                    int delete_argnum,
+                                                    oop dst_mtype, int dst_beg, int dst_end) {
+  objArrayOop src_ptypes = java_dyn_MethodType::ptypes(src_mtype);
+  objArrayOop dst_ptypes = java_dyn_MethodType::ptypes(dst_mtype);
+
+  int src_max = src_ptypes->length();
+  int dst_max = dst_ptypes->length();
+
+  if (src_end == -1)  src_end = src_max;
+  if (dst_end == -1)  dst_end = dst_max;
+
+  assert(0 <= src_beg && src_beg <= src_end && src_end <= src_max, "oob");
+  assert(0 <= dst_beg && dst_beg <= dst_end && dst_end <= dst_max, "oob");
+
+  // pending actions; set to -1 when done:
+  int ins_idx = insert_argnum, chg_idx = change_argnum, del_idx = delete_argnum;
+
+  const char* err = NULL;
+
+  // Walk along each array of parameter types, including a virtual
+  // NULL end marker at the end of each.
+  for (int src_idx = src_beg, dst_idx = dst_beg;
+       (src_idx <= src_end && dst_idx <= dst_end);
+       src_idx++, dst_idx++) {
+    oop src_type = (src_idx == src_end) ? oop(NULL) : src_ptypes->obj_at(src_idx);
+    oop dst_type = (dst_idx == dst_end) ? oop(NULL) : dst_ptypes->obj_at(dst_idx);
+    bool fix_null_src_type = false;
+
+    // Perform requested edits.
+    if (ins_idx == src_idx) {
+      // note that the inserted guy is never affected by a change or deletion
+      ins_idx = -1;
+      src_type = insert_type;
+      fix_null_src_type = true;
+      --src_idx;                // back up to process src type on next loop
+      src_idx = src_end;
+    } else {
+      // note that the changed guy can be immediately deleted
+      if (chg_idx == src_idx) {
+        chg_idx = -1;
+        assert(src_idx < src_end, "oob");
+        src_type = change_type;
+        fix_null_src_type = true;
+      }
+      if (del_idx == src_idx) {
+        del_idx = -1;
+        assert(src_idx < src_end, "oob");
+        --dst_idx;
+        continue;               // rerun loop after skipping this position
+      }
+    }
+
+    if (src_type == NULL && fix_null_src_type)
+      // explicit null in this case matches any dest reference
+      src_type = (java_lang_Class::is_primitive(dst_type) ? object_java_mirror() : dst_type);
+
+    // Compare the two argument types.
+    if (src_type != dst_type) {
+      if (src_type == NULL)  return "not enough arguments";
+      if (dst_type == NULL)  return "too many arguments";
+      err = check_argument_type_change(src_type, dst_type, dst_idx);
+      if (err != NULL)  return err;
+    }
+  }
+
+  // Now compare return types also.
+  oop src_rtype = java_dyn_MethodType::rtype(src_mtype);
+  oop dst_rtype = java_dyn_MethodType::rtype(dst_mtype);
+  if (src_rtype != dst_rtype) {
+    err = check_return_type_change(dst_rtype, src_rtype); // note reversal!
+    if (err != NULL)  return err;
+  }
+
+  assert(err == NULL, "");
+  return NULL;  // all is well
+}
+
+
+const char* MethodHandles::check_argument_type_change(BasicType src_type,
+                                                     klassOop src_klass,
+                                                     BasicType dst_type,
+                                                     klassOop dst_klass,
+                                                     int argnum) {
+  const char* err = NULL;
+
+  // just in case:
+  if (src_type == T_ARRAY)  src_type = T_OBJECT;
+  if (dst_type == T_ARRAY)  dst_type = T_OBJECT;
+
+  // Produce some nice messages if VerifyMethodHandles is turned on:
+  if (!same_basic_type_for_arguments(src_type, dst_type, (argnum < 0))) {
+    if (src_type == T_OBJECT) {
+      err = ((argnum >= 0)
+             ? "type mismatch: passing a %s for method argument #%d, which expects primitive %s"
+             : "type mismatch: returning a %s, but caller expects primitive %s");
+    } else if (dst_type == T_OBJECT) {
+      err = ((argnum < 0)
+             ? "type mismatch: passing a primitive %s for method argument #%d, which expects %s"
+             : "type mismatch: returning a primitive %s, but caller expects %s");
+    } else {
+      err = ((argnum < 0)
+             ? "type mismatch: passing a %s for method argument #%d, which expects %s"
+             : "type mismatch: returning a %s, but caller expects %s");
+    }
+  } else if (src_type == T_OBJECT && class_cast_needed(src_klass, dst_klass)) {
+    if (!class_cast_needed(dst_klass, src_klass)) {
+      err = ((argnum < 0)
+             ? "cast required: passing a %s for method argument #%d, which expects %s"
+             : "cast required: returning a %s, but caller expects %s");
+    } else {
+      err = ((argnum < 0)
+             ? "reference mismatch: passing a %s for method argument #%d, which expects %s"
+             : "reference mismatch: returning a %s, but caller expects %s");
+    }
+  } else {
+    // passed the obstacle course
+    return NULL;
+  }
+
+  // format, format, format
+  const char* src_name = type2name(src_type);
+  const char* dst_name = type2name(dst_type);
+  if (src_type == T_OBJECT)  src_name = Klass::cast(src_klass)->external_name();
+  if (dst_type == T_OBJECT)  dst_name = Klass::cast(dst_klass)->external_name();
+  if (src_name == NULL)  src_name = "unknown type";
+  if (dst_name == NULL)  dst_name = "unknown type";
+
+  size_t msglen = strlen(err) + strlen(src_name) + strlen(dst_name) + (argnum < 10 ? 1 : 11);
+  char* msg = NEW_RESOURCE_ARRAY(char, msglen + 1);
+  if (argnum >= 0) {
+    assert(strstr(err, "%d") != NULL, "");
+    jio_snprintf(msg, msglen, err, src_name, argnum, dst_name);
+  } else {
+    assert(strstr(err, "%d") == NULL, "");
+    jio_snprintf(msg, msglen, err, src_name,         dst_name);
+  }
+  return msg;
+}
+
+// Compute the depth within the stack of the given argument, i.e.,
+// the combined size of arguments to the right of the given argument.
+// For the last argument (ptypes.length-1) this will be zero.
+// For the first argument (0) this will be the size of all
+// arguments but that one.  For the special number -1, this
+// will be the size of all arguments, including the first.
+// If the argument is neither -1 nor a valid argument index,
+// then return a negative number.  Otherwise, the result
+// is in the range [0..vmslots] inclusive.
+int MethodHandles::argument_slot(oop method_type, int arg) {
+  objArrayOop ptypes = java_dyn_MethodType::ptypes(method_type);
+  int argslot = 0;
+  int len = ptypes->length();
+  if (arg < -1 || arg >= len)  return -99;
+  for (int i = len-1; i > arg; i--) {
+    BasicType bt = java_lang_Class::as_BasicType(ptypes->obj_at(i));
+    argslot += type2size[bt];
+  }
+  assert(argument_slot_to_argnum(method_type, argslot) == arg, "inverse works");
+  return argslot;
+}
+
+// Given a slot number, return the argument number.
+int MethodHandles::argument_slot_to_argnum(oop method_type, int query_argslot) {
+  objArrayOop ptypes = java_dyn_MethodType::ptypes(method_type);
+  int argslot = 0;
+  int len = ptypes->length();
+  for (int i = len-1; i >= 0; i--) {
+    if (query_argslot == argslot)  return i;
+    BasicType bt = java_lang_Class::as_BasicType(ptypes->obj_at(i));
+    argslot += type2size[bt];
+  }
+  // return pseudo-arg deepest in stack:
+  if (query_argslot == argslot)  return -1;
+  return -99;                   // oob slot, or splitting a double-slot arg
+}
+
+methodHandle MethodHandles::dispatch_decoded_method(methodHandle m,
+                                                    KlassHandle receiver_limit,
+                                                    int decode_flags,
+                                                    KlassHandle receiver_klass,
+                                                    TRAPS) {
+  assert((decode_flags & ~_DMF_DIRECT_MASK) == 0, "must be direct method reference");
+  assert((decode_flags & _dmf_has_receiver) != 0, "must have a receiver or first reference argument");
+
+  if (!m->is_static() &&
+      (receiver_klass.is_null() || !receiver_klass->is_subtype_of(m->method_holder())))
+    // given type does not match class of method, or receiver is null!
+    // caller should have checked this, but let's be extra careful...
+    return methodHandle();
+
+  if (receiver_limit.not_null() &&
+      (receiver_klass.not_null() && !receiver_klass->is_subtype_of(receiver_limit())))
+    // given type is not limited to the receiver type
+    // note that a null receiver can match any reference value, for a static method
+    return methodHandle();
+
+  if (!(decode_flags & MethodHandles::_dmf_does_dispatch)) {
+    // pre-dispatched or static method (null receiver is OK for static)
+    return m;
+
+  } else if (receiver_klass.is_null()) {
+    // null receiver value; cannot dispatch
+    return methodHandle();
+
+  } else if (!(decode_flags & MethodHandles::_dmf_from_interface)) {
+    // perform virtual dispatch
+    int vtable_index = m->vtable_index();
+    guarantee(vtable_index >= 0, "valid vtable index");
+
+    // receiver_klass might be an arrayKlassOop but all vtables start at
+    // the same place. The cast is to avoid virtual call and assertion.
+    // See also LinkResolver::runtime_resolve_virtual_method.
+    instanceKlass* inst = (instanceKlass*)Klass::cast(receiver_klass());
+    DEBUG_ONLY(inst->verify_vtable_index(vtable_index));
+    methodOop m_oop = inst->method_at_vtable(vtable_index);
+    return methodHandle(THREAD, m_oop);
+
+  } else {
+    // perform interface dispatch
+    int itable_index = klassItable::compute_itable_index(m());
+    guarantee(itable_index >= 0, "valid itable index");
+    instanceKlass* inst = instanceKlass::cast(receiver_klass());
+    methodOop m_oop = inst->method_at_itable(m->method_holder(), itable_index, THREAD);
+    return methodHandle(THREAD, m_oop);
+  }
+}
+
+void MethodHandles::verify_DirectMethodHandle(Handle mh, methodHandle m, TRAPS) {
+  // Verify type.
+  Handle mtype(THREAD, java_dyn_MethodHandle::type(mh()));
+  verify_method_type(m, mtype, false, KlassHandle(), CHECK);
+
+  // Verify vmslots.
+  if (java_dyn_MethodHandle::vmslots(mh()) != m->size_of_parameters()) {
+    THROW_MSG(vmSymbols::java_lang_InternalError(), "bad vmslots in DMH");
+  }
+}
+
+void MethodHandles::init_DirectMethodHandle(Handle mh, methodHandle m, bool do_dispatch, TRAPS) {
+  // Check arguments.
+  if (mh.is_null() || m.is_null() ||
+      (!do_dispatch && m->is_abstract())) {
+    THROW(vmSymbols::java_lang_InternalError());
+  }
+
+  java_dyn_MethodHandle::init_vmslots(mh());
+
+  if (VerifyMethodHandles) {
+    // The privileged code which invokes this routine should not make
+    // a mistake about types, but it's better to verify.
+    verify_DirectMethodHandle(mh, m, CHECK);
+  }
+
+  // Finally, after safety checks are done, link to the target method.
+  // We will follow the same path as the latter part of
+  // InterpreterRuntime::resolve_invoke(), which first finds the method
+  // and then decides how to populate the constant pool cache entry
+  // that links the interpreter calls to the method.  We need the same
+  // bits, and will use the same calling sequence code.
+
+  int vmindex = methodOopDesc::garbage_vtable_index;
+  oop vmtarget = NULL;
+
+  instanceKlass::cast(m->method_holder())->link_class(CHECK);
+
+  MethodHandleEntry* me = NULL;
+  if (do_dispatch && Klass::cast(m->method_holder())->is_interface()) {
+    // We are simulating an invokeinterface instruction.
+    // (We might also be simulating an invokevirtual on a miranda method,
+    // but it is safe to treat it as an invokeinterface.)
+    assert(!m->can_be_statically_bound(), "no final methods on interfaces");
+    vmindex = klassItable::compute_itable_index(m());
+    assert(vmindex >= 0, "(>=0) == do_dispatch");
+    // Set up same bits as ConstantPoolCacheEntry::set_interface_call().
+    vmtarget = m->method_holder(); // the interface
+    me = MethodHandles::entry(MethodHandles::_invokeinterface_mh);
+  } else if (!do_dispatch || m->can_be_statically_bound()) {
+    // We are simulating an invokestatic or invokespecial instruction.
+    // Set up the method pointer, just like ConstantPoolCacheEntry::set_method().
+    vmtarget = m();
+    // this does not help dispatch, but it will make it possible to parse this MH:
+    vmindex  = methodOopDesc::nonvirtual_vtable_index;
+    assert(vmindex < 0, "(>=0) == do_dispatch");
+    if (!m->is_static()) {
+      me = MethodHandles::entry(MethodHandles::_invokespecial_mh);
+    } else {
+      me = MethodHandles::entry(MethodHandles::_invokestatic_mh);
+      // Part of the semantics of a static call is an initialization barrier.
+      // For a DMH, it is done now, when the handle is created.
+      Klass* k = Klass::cast(m->method_holder());
+      if (k->should_be_initialized()) {
+        k->initialize(CHECK);
+      }
+    }
+  } else {
+    // We are simulating an invokevirtual instruction.
+    // Set up the vtable index, just like ConstantPoolCacheEntry::set_method().
+    // The key logic is LinkResolver::runtime_resolve_virtual_method.
+    vmindex  = m->vtable_index();
+    vmtarget = m->method_holder();
+    me = MethodHandles::entry(MethodHandles::_invokevirtual_mh);
+  }
+
+  if (me == NULL) { THROW(vmSymbols::java_lang_InternalError()); }
+
+  sun_dyn_DirectMethodHandle::set_vmtarget(mh(), vmtarget);
+  sun_dyn_DirectMethodHandle::set_vmindex(mh(),  vmindex);
+  DEBUG_ONLY(int flags; klassOop rlimit);
+  assert(MethodHandles::decode_method(mh(), rlimit, flags) == m(),
+         "properly stored for later decoding");
+  DEBUG_ONLY(bool actual_do_dispatch = ((flags & _dmf_does_dispatch) != 0));
+  assert(!(actual_do_dispatch && !do_dispatch),
+         "do not perform dispatch if !do_dispatch specified");
+  assert(actual_do_dispatch == (vmindex >= 0), "proper later decoding of do_dispatch");
+  assert(decode_MethodHandle_stack_pushes(mh()) == 0, "DMH does not move stack");
+
+  // Done!
+  java_dyn_MethodHandle::set_vmentry(mh(), me);
+}
+
+void MethodHandles::verify_BoundMethodHandle_with_receiver(Handle mh,
+                                                           methodHandle m,
+                                                           TRAPS) {
+  // Verify type.
+  oop receiver = sun_dyn_BoundMethodHandle::argument(mh());
+  Handle mtype(THREAD, java_dyn_MethodHandle::type(mh()));
+  KlassHandle bound_recv_type;
+  if (receiver != NULL)  bound_recv_type = KlassHandle(THREAD, receiver->klass());
+  verify_method_type(m, mtype, true, bound_recv_type, CHECK);
+
+  int receiver_pos = m->size_of_parameters() - 1;
+
+  // Verify MH.vmargslot, which should point at the bound receiver.
+  verify_vmargslot(mh, -1, sun_dyn_BoundMethodHandle::vmargslot(mh()), CHECK);
+  //verify_vmslots(mh, CHECK);
+
+  // Verify vmslots.
+  if (java_dyn_MethodHandle::vmslots(mh()) != receiver_pos) {
+    THROW_MSG(vmSymbols::java_lang_InternalError(), "bad vmslots in BMH (receiver)");
+  }
+}
+
+// Initialize a BMH with a receiver bound directly to a methodOop.
+void MethodHandles::init_BoundMethodHandle_with_receiver(Handle mh,
+                                                         methodHandle original_m,
+                                                         KlassHandle receiver_limit,
+                                                         int decode_flags,
+                                                         TRAPS) {
+  // Check arguments.
+  if (mh.is_null() || original_m.is_null()) {
+    THROW(vmSymbols::java_lang_InternalError());
+  }
+
+  KlassHandle receiver_klass;
+  {
+    oop receiver_oop = sun_dyn_BoundMethodHandle::argument(mh());
+    if (receiver_oop != NULL)
+      receiver_klass = KlassHandle(THREAD, receiver_oop->klass());
+  }
+  methodHandle m = dispatch_decoded_method(original_m,
+                                           receiver_limit, decode_flags,
+                                           receiver_klass,
+                                           CHECK);
+  if (m.is_null())      { THROW(vmSymbols::java_lang_InternalError()); }
+  if (m->is_abstract()) { THROW(vmSymbols::java_lang_AbstractMethodError()); }
+
+  java_dyn_MethodHandle::init_vmslots(mh());
+
+  if (VerifyMethodHandles) {
+    verify_BoundMethodHandle_with_receiver(mh, m, CHECK);
+  }
+
+  sun_dyn_BoundMethodHandle::set_vmtarget(mh(), m());
+
+  DEBUG_ONLY(int junk; klassOop junk2);
+  assert(MethodHandles::decode_method(mh(), junk2, junk) == m(), "properly stored for later decoding");
+  assert(decode_MethodHandle_stack_pushes(mh()) == 1, "BMH pushes one stack slot");
+
+  // Done!
+  java_dyn_MethodHandle::set_vmentry(mh(), MethodHandles::entry(MethodHandles::_bound_ref_direct_mh));
+}
+
+void MethodHandles::verify_BoundMethodHandle(Handle mh, Handle target, int argnum,
+                                             bool direct_to_method, TRAPS) {
+  Handle ptype_handle(THREAD,
+                           java_dyn_MethodType::ptype(java_dyn_MethodHandle::type(target()), argnum));
+  KlassHandle ptype_klass;
+  BasicType ptype = java_lang_Class::as_BasicType(ptype_handle(), &ptype_klass);
+  int slots_pushed = type2size[ptype];
+
+  oop argument = sun_dyn_BoundMethodHandle::argument(mh());
+
+  const char* err = NULL;
+
+  switch (ptype) {
+  case T_OBJECT:
+    if (argument != NULL)
+      // we must implicitly convert from the arg type to the outgoing ptype
+      err = check_argument_type_change(T_OBJECT, argument->klass(), ptype, ptype_klass(), argnum);
+    break;
+
+  case T_ARRAY: case T_VOID:
+    assert(false, "array, void do not appear here");
+  default:
+    if (ptype != T_INT && !is_subword_type(ptype)) {
+      err = "unexpected parameter type";
+      break;
+    }
+    // check subrange of Integer.value, if necessary
+    if (argument == NULL || argument->klass() != SystemDictionary::int_klass()) {
+      err = "bound integer argument must be of type java.lang.Integer";
+      break;
+    }
+    if (ptype != T_INT) {
+      int value_offset = java_lang_boxing_object::value_offset_in_bytes(T_INT);
+      jint value = argument->int_field(value_offset);
+      int vminfo = adapter_subword_vminfo(ptype);
+      jint subword = truncate_subword_from_vminfo(value, vminfo);
+      if (value != subword) {
+        err = "bound subword value does not fit into the subword type";
+        break;
+      }
+    }
+    break;
+  case T_FLOAT:
+  case T_DOUBLE:
+  case T_LONG:
+    {
+      // we must implicitly convert from the unboxed arg type to the outgoing ptype
+      BasicType argbox = java_lang_boxing_object::basic_type(argument);
+      if (argbox != ptype) {
+        err = check_argument_type_change(T_OBJECT, (argument == NULL
+                                                    ? SystemDictionary::object_klass()
+                                                    : argument->klass()),
+                                         ptype, ptype_klass(), argnum);
+        assert(err != NULL, "this must be an error");
+      }
+      break;
+    }
+  }
+
+  if (err == NULL) {
+    DEBUG_ONLY(int this_pushes = decode_MethodHandle_stack_pushes(mh()));
+    if (direct_to_method) {
+      assert(this_pushes == slots_pushed, "BMH pushes one or two stack slots");
+      assert(slots_pushed <= MethodHandlePushLimit, "");
+    } else {
+      int prev_pushes = decode_MethodHandle_stack_pushes(target());
+      assert(this_pushes == slots_pushed + prev_pushes, "BMH stack motion must be correct");
+      // do not blow the stack; use a Java-based adapter if this limit is exceeded
+      if (slots_pushed + prev_pushes > MethodHandlePushLimit)
+        err = "too many bound parameters";
+    }
+  }
+
+  if (err == NULL) {
+    // Verify the rest of the method type.
+    err = check_method_type_insertion(java_dyn_MethodHandle::type(mh()),
+                                      argnum, ptype_handle(),
+                                      java_dyn_MethodHandle::type(target()));
+  }
+
+  if (err != NULL) {
+    THROW_MSG(vmSymbols::java_lang_InternalError(), err);
+  }
+}
+
+void MethodHandles::init_BoundMethodHandle(Handle mh, Handle target, int argnum, TRAPS) {
+  // Check arguments.
+  if (mh.is_null() || target.is_null() || !java_dyn_MethodHandle::is_instance(target())) {
+    THROW(vmSymbols::java_lang_InternalError());
+  }
+
+  java_dyn_MethodHandle::init_vmslots(mh());
+
+  if (VerifyMethodHandles) {
+    int insert_after = argnum - 1;
+    verify_vmargslot(mh, insert_after, sun_dyn_BoundMethodHandle::vmargslot(mh()), CHECK);
+    verify_vmslots(mh, CHECK);
+  }
+
+  // If (a) the target is a direct non-dispatched method handle,
+  // or (b) the target is a dispatched direct method handle and we
+  // are binding the receiver, cut out the middle-man.
+  // Do this by decoding the DMH and using its methodOop directly as vmtarget.
+  bool direct_to_method = false;
+  if (OptimizeMethodHandles &&
+      target->klass() == SystemDictionary::DirectMethodHandle_klass() &&
+      (argnum == 0 || sun_dyn_DirectMethodHandle::vmindex(target()) < 0)) {
+    int decode_flags = 0; klassOop receiver_limit_oop = NULL;
+    methodHandle m(THREAD, decode_method(target(), receiver_limit_oop, decode_flags));
+    if (m.is_null()) { THROW_MSG(vmSymbols::java_lang_InternalError(), "DMH failed to decode"); }
+    DEBUG_ONLY(int m_vmslots = m->size_of_parameters() - 1); // pos. of 1st arg.
+    assert(sun_dyn_BoundMethodHandle::vmslots(mh()) == m_vmslots, "type w/ m sig");
+    if (argnum == 0 && (decode_flags & _dmf_has_receiver) != 0) {
+      KlassHandle receiver_limit(THREAD, receiver_limit_oop);
+      init_BoundMethodHandle_with_receiver(mh, m,
+                                           receiver_limit, decode_flags,
+                                           CHECK);
+      return;
+    }
+
+    // Even if it is not a bound receiver, we still might be able
+    // to bind another argument and still invoke the methodOop directly.
+    if (!(decode_flags & _dmf_does_dispatch)) {
+      direct_to_method = true;
+      sun_dyn_BoundMethodHandle::set_vmtarget(mh(), m());
+    }
+  }
+  if (!direct_to_method)
+    sun_dyn_BoundMethodHandle::set_vmtarget(mh(), target());
+
+  if (VerifyMethodHandles) {
+    verify_BoundMethodHandle(mh, target, argnum, direct_to_method, CHECK);
+  }
+
+  // Next question:  Is this a ref, int, or long bound value?
+  oop ptype_oop = java_dyn_MethodType::ptype(java_dyn_MethodHandle::type(target()), argnum);
+  BasicType ptype = java_lang_Class::as_BasicType(ptype_oop);
+  int slots_pushed = type2size[ptype];
+
+  MethodHandleEntry* me = NULL;
+  if (ptype == T_OBJECT) {
+    if (direct_to_method)  me = MethodHandles::entry(_bound_ref_direct_mh);
+    else                   me = MethodHandles::entry(_bound_ref_mh);
+  } else if (slots_pushed == 2) {
+    if (direct_to_method)  me = MethodHandles::entry(_bound_long_direct_mh);
+    else                   me = MethodHandles::entry(_bound_long_mh);
+  } else if (slots_pushed == 1) {
+    if (direct_to_method)  me = MethodHandles::entry(_bound_int_direct_mh);
+    else                   me = MethodHandles::entry(_bound_int_mh);
+  } else {
+    assert(false, "");
+  }
+
+  // Done!
+  java_dyn_MethodHandle::set_vmentry(mh(), me);
+}
+
+static void throw_InternalError_for_bad_conversion(int conversion, const char* err, TRAPS) {
+  char msg[200];
+  jio_snprintf(msg, sizeof(msg), "bad adapter (conversion=0x%08x): %s", conversion, err);
+  THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), msg);
+}
+
+void MethodHandles::verify_AdapterMethodHandle(Handle mh, int argnum, TRAPS) {
+  jint conversion = sun_dyn_AdapterMethodHandle::conversion(mh());
+  int  argslot    = sun_dyn_AdapterMethodHandle::vmargslot(mh());
+
+  verify_vmargslot(mh, argnum, argslot, CHECK);
+  verify_vmslots(mh, CHECK);
+
+  jint conv_op    = adapter_conversion_op(conversion);
+  if (!conv_op_valid(conv_op)) {
+    throw_InternalError_for_bad_conversion(conversion, "unknown conversion op", THREAD);
+    return;
+  }
+  EntryKind ek = adapter_entry_kind(conv_op);
+
+  int stack_move = adapter_conversion_stack_move(conversion);
+  BasicType src  = adapter_conversion_src_type(conversion);
+  BasicType dest = adapter_conversion_dest_type(conversion);
+  int vminfo     = adapter_conversion_vminfo(conversion); // should be zero
+
+  Handle argument(THREAD,  sun_dyn_AdapterMethodHandle::argument(mh()));
+  Handle target(THREAD,    sun_dyn_AdapterMethodHandle::vmtarget(mh()));
+  Handle src_mtype(THREAD, java_dyn_MethodHandle::type(mh()));
+  Handle dst_mtype(THREAD, java_dyn_MethodHandle::type(target()));
+
+  const char* err = NULL;
+
+  if (err == NULL) {
+    // Check that the correct argument is supplied, but only if it is required.
+    switch (ek) {
+    case _adapter_check_cast:     // target type of cast
+    case _adapter_ref_to_prim:    // wrapper type from which to unbox
+    case _adapter_prim_to_ref:    // wrapper type to box into
+    case _adapter_collect_args:   // array type to collect into
+    case _adapter_spread_args:    // array type to spread from
+      if (!java_lang_Class::is_instance(argument())
+          || java_lang_Class::is_primitive(argument()))
+        { err = "adapter requires argument of type java.lang.Class"; break; }
+      if (ek == _adapter_collect_args ||
+          ek == _adapter_spread_args) {
+        // Make sure it is a suitable collection type.  (Array, for now.)
+        Klass* ak = Klass::cast(java_lang_Class::as_klassOop(argument()));
+        if (!ak->oop_is_objArray()) {
+          { err = "adapter requires argument of type java.lang.Class<Object[]>"; break; }
+        }
+      }
+      break;
+    case _adapter_flyby:
+    case _adapter_ricochet:
+      if (!java_dyn_MethodHandle::is_instance(argument()))
+        { err = "MethodHandle adapter argument required"; break; }
+      break;
+    default:
+      if (argument.not_null())
+        { err = "adapter has spurious argument"; break; }
+      break;
+    }
+  }
+
+  if (err == NULL) {
+    // Check that the src/dest types are supplied if needed.
+    switch (ek) {
+    case _adapter_prim_to_prim:
+      if (!is_java_primitive(src) || !is_java_primitive(dest) || src == dest) {
+        err = "adapter requires primitive src/dest conversion subfields"; break;
+      }
+      if ( (src == T_FLOAT || src == T_DOUBLE) && !(dest == T_FLOAT || dest == T_DOUBLE) ||
+          !(src == T_FLOAT || src == T_DOUBLE) &&  (dest == T_FLOAT || dest == T_DOUBLE)) {
+        err = "adapter cannot convert beween floating and fixed-point"; break;
+      }
+      break;
+    case _adapter_ref_to_prim:
+      if (src != T_OBJECT || !is_java_primitive(dest)
+          || argument() != Klass::cast(SystemDictionary::box_klass(dest))->java_mirror()) {
+        err = "adapter requires primitive dest conversion subfield"; break;
+      }
+      break;
+    case _adapter_prim_to_ref:
+      if (!is_java_primitive(src) || dest != T_OBJECT
+          || argument() != Klass::cast(SystemDictionary::box_klass(src))->java_mirror()) {
+        err = "adapter requires primitive src conversion subfield"; break;
+      }
+      break;
+    case _adapter_swap_args:
+    case _adapter_rot_args:
+      {
+        if (!src || src != dest) {
+          err = "adapter requires src/dest conversion subfields for swap"; break;
+        }
+        int swap_size = type2size[src];
+        oop src_mtype  = sun_dyn_AdapterMethodHandle::type(target());
+        oop dest_mtype = sun_dyn_AdapterMethodHandle::type(mh());
+        int slot_limit = sun_dyn_AdapterMethodHandle::vmslots(src_mtype);
+        int src_slot   = argslot;
+        int dest_slot  = vminfo;
+        bool rotate_up = (src_slot > dest_slot); // upward rotation
+        int src_arg    = argnum;
+        int dest_arg   = argument_slot_to_argnum(dest_mtype, dest_slot);
+        verify_vmargslot(mh, dest_arg, dest_slot, CHECK);
+        if (!(dest_slot >= src_slot + swap_size) &&
+            !(src_slot >= dest_slot + swap_size)) {
+          err = "source, destination slots must be distinct";
+        } else if (ek == _adapter_swap_args && !(src_slot > dest_slot)) {
+          err = "source of swap must be deeper in stack";
+        } else if (ek == _adapter_swap_args) {
+          err = check_argument_type_change(java_dyn_MethodType::ptype(src_mtype, dest_arg),
+                                           java_dyn_MethodType::ptype(dest_mtype, src_arg),
+                                           dest_arg);
+        } else if (ek == _adapter_rot_args) {
+          if (rotate_up) {
+            assert((src_slot > dest_slot) && (src_arg < dest_arg), "");
+            // rotate up: [dest_slot..src_slot-ss] --> [dest_slot+ss..src_slot]
+            // that is:   [src_arg+1..dest_arg] --> [src_arg..dest_arg-1]
+            for (int i = src_arg+1; i <= dest_arg && err == NULL; i++) {
+              err = check_argument_type_change(java_dyn_MethodType::ptype(src_mtype, i),
+                                               java_dyn_MethodType::ptype(dest_mtype, i-1),
+                                               i);
+            }
+          } else { // rotate down
+            assert((src_slot < dest_slot) && (src_arg > dest_arg), "");
+            // rotate down: [src_slot+ss..dest_slot] --> [src_slot..dest_slot-ss]
+            // that is:     [dest_arg..src_arg-1] --> [dst_arg+1..src_arg]
+            for (int i = dest_arg; i <= src_arg-1 && err == NULL; i++) {
+              err = check_argument_type_change(java_dyn_MethodType::ptype(src_mtype, i),
+                                               java_dyn_MethodType::ptype(dest_mtype, i+1),
+                                               i);
+            }
+          }
+        }
+        if (err == NULL)
+          err = check_argument_type_change(java_dyn_MethodType::ptype(src_mtype, src_arg),
+                                           java_dyn_MethodType::ptype(dest_mtype, dest_arg),
+                                           src_arg);
+      }
+      break;
+    case _adapter_collect_args:
+    case _adapter_spread_args:
+      {
+        BasicType coll_type = (ek == _adapter_collect_args) ? dest : src;
+        BasicType elem_type = (ek == _adapter_collect_args) ? src : dest;
+        if (coll_type != T_OBJECT || elem_type != T_OBJECT) {
+          err = "adapter requires src/dest subfields"; break;
+          // later:
+          // - consider making coll be a primitive array
+          // - consider making coll be a heterogeneous collection
+        }
+      }
+      break;
+    default:
+      if (src != 0 || dest != 0) {
+        err = "adapter has spurious src/dest conversion subfields"; break;
+      }
+      break;
+    }
+  }
+
+  if (err == NULL) {
+    // Check the stack_move subfield.
+    // It must always report the net change in stack size, positive or negative.
+    int slots_pushed = stack_move / stack_move_unit();
+    switch (ek) {
+    case _adapter_prim_to_prim:
+    case _adapter_ref_to_prim:
+    case _adapter_prim_to_ref:
+      if (slots_pushed != type2size[dest] - type2size[src]) {
+        err = "wrong stack motion for primitive conversion";
+      }
+      break;
+    case _adapter_dup_args:
+      if (slots_pushed <= 0) {
+        err = "adapter requires conversion subfield slots_pushed > 0";
+      }
+      break;
+    case _adapter_drop_args:
+      if (slots_pushed >= 0) {
+        err = "adapter requires conversion subfield slots_pushed < 0";
+      }
+      break;
+    case _adapter_collect_args:
+      if (slots_pushed > 1) {
+        err = "adapter requires conversion subfield slots_pushed <= 1";
+      }
+      break;
+    case _adapter_spread_args:
+      if (slots_pushed < -1) {
+        err = "adapter requires conversion subfield slots_pushed >= -1";
+      }
+      break;
+    default:
+      if (stack_move != 0) {
+        err = "adapter has spurious stack_move conversion subfield";
+      }
+      break;
+    }
+    if (err == NULL && stack_move != slots_pushed * stack_move_unit()) {
+      err = "stack_move conversion subfield must be multiple of stack_move_unit";
+    }
+  }
+
+  if (err == NULL) {
+    // Make sure this adapter does not push too deeply.
+    int slots_pushed = stack_move / stack_move_unit();
+    int this_vmslots = java_dyn_MethodHandle::vmslots(mh());
+    int prev_vmslots = java_dyn_MethodHandle::vmslots(target());
+    if (slots_pushed != (this_vmslots - prev_vmslots)) {
+      err = "stack_move inconsistent with previous and current MethodType vmslots";
+    } else if (slots_pushed > 0)  {
+      // verify stack_move against MethodHandlePushLimit
+      int prev_pushes = decode_MethodHandle_stack_pushes(target());
+      // do not blow the stack; use a Java-based adapter if this limit is exceeded
+      if (slots_pushed + prev_pushes > MethodHandlePushLimit) {
+        err = "adapter pushes too many parameters";
+      }
+    }
+
+    // While we're at it, check that the stack motion decoder works:
+    DEBUG_ONLY(int prev_pushes = decode_MethodHandle_stack_pushes(target()));
+    DEBUG_ONLY(int this_pushes = decode_MethodHandle_stack_pushes(mh()));
+    assert(this_pushes == slots_pushed + prev_pushes, "AMH stack motion must be correct");
+  }
+
+  if (err == NULL && vminfo != 0) {
+    switch (ek) {
+      case _adapter_swap_args:
+      case _adapter_rot_args:
+        break;                // OK
+    default:
+      err = "vminfo subfield is reserved to the JVM";
+    }
+  }
+
+  // Do additional ad hoc checks.
+  if (err == NULL) {
+    switch (ek) {
+    case _adapter_retype_only:
+      err = check_method_type_passthrough(src_mtype(), dst_mtype());
+      break;
+
+    case _adapter_check_cast:
+      {
+        // The actual value being checked must be a reference:
+        err = check_argument_type_change(java_dyn_MethodType::ptype(src_mtype(), argnum),
+                                         object_java_mirror(), argnum);
+        if (err != NULL)  break;
+
+        // The output of the cast must fit with the destination argument:
+        Handle cast_class = argument;
+        err = check_method_type_conversion(src_mtype(),
+                                           argnum, cast_class(),
+                                           dst_mtype());
+      }
+      break;
+
+      // %%% TO DO: continue in remaining cases to verify src/dst_mtype if VerifyMethodHandles
+    }
+  }
+
+  if (err != NULL) {
+    throw_InternalError_for_bad_conversion(conversion, err, THREAD);
+    return;
+  }
+
+}
+
+void MethodHandles::init_AdapterMethodHandle(Handle mh, Handle target, int argnum, TRAPS) {
+  oop  argument   = sun_dyn_AdapterMethodHandle::argument(mh());
+  int  argslot    = sun_dyn_AdapterMethodHandle::vmargslot(mh());
+  jint conversion = sun_dyn_AdapterMethodHandle::conversion(mh());
+  jint conv_op    = adapter_conversion_op(conversion);
+
+  // adjust the adapter code to the internal EntryKind enumeration:
+  EntryKind ek_orig = adapter_entry_kind(conv_op);
+  EntryKind ek_opt  = ek_orig;  // may be optimized
+
+  // Finalize the vmtarget field (Java initialized it to null).
+  if (!java_dyn_MethodHandle::is_instance(target())) {
+    throw_InternalError_for_bad_conversion(conversion, "bad target", THREAD);
+    return;
+  }
+  sun_dyn_AdapterMethodHandle::set_vmtarget(mh(), target());
+
+  if (VerifyMethodHandles) {
+    verify_AdapterMethodHandle(mh, argnum, CHECK);
+  }
+
+  int stack_move = adapter_conversion_stack_move(conversion);
+  BasicType src  = adapter_conversion_src_type(conversion);
+  BasicType dest = adapter_conversion_dest_type(conversion);
+  int vminfo     = adapter_conversion_vminfo(conversion); // should be zero
+
+  const char* err = NULL;
+
+  // Now it's time to finish the case analysis and pick a MethodHandleEntry.
+  switch (ek_orig) {
+  case _adapter_retype_only:
+  case _adapter_check_cast:
+  case _adapter_dup_args:
+  case _adapter_drop_args:
+    // these work fine via general case code
+    break;
+
+  case _adapter_prim_to_prim:
+    {
+      // Non-subword cases are {int,float,long,double} -> {int,float,long,double}.
+      // And, the {float,double} -> {int,long} cases must be handled by Java.
+      switch (type2size[src] *4+ type2size[dest]) {
+      case 1 *4+ 1:
+        assert(src == T_INT || is_subword_type(src), "source is not float");
+        // Subword-related cases are int -> {boolean,byte,char,short}.
+        ek_opt = _adapter_opt_i2i;
+        vminfo = adapter_subword_vminfo(dest);
+        break;
+      case 2 *4+ 1:
+        if (src == T_LONG && (dest == T_INT || is_subword_type(dest))) {
+          ek_opt = _adapter_opt_l2i;
+          vminfo = adapter_subword_vminfo(dest);
+        } else if (src == T_DOUBLE && dest == T_FLOAT) {
+          ek_opt = _adapter_opt_d2f;
+        } else {
+          assert(false, "");
+        }
+        break;
+      case 1 *4+ 2:
+        if (src == T_INT && dest == T_LONG) {
+          ek_opt = _adapter_opt_i2l;
+        } else if (src == T_FLOAT && dest == T_DOUBLE) {
+          ek_opt = _adapter_opt_f2d;
+        } else {
+          assert(false, "");
+        }
+        break;
+      default:
+        assert(false, "");
+        break;
+      }
+    }
+    break;
+
+  case _adapter_ref_to_prim:
+    {
+      switch (type2size[dest]) {
+      case 1:
+        ek_opt = _adapter_opt_unboxi;
+        vminfo = adapter_subword_vminfo(dest);
+        break;
+      case 2:
+        ek_opt = _adapter_opt_unboxl;
+        break;
+      default:
+        assert(false, "");
+        break;
+      }
+    }
+    break;
+
+  case _adapter_prim_to_ref:
+    goto throw_not_impl;        // allocates, hence could block
+
+  case _adapter_swap_args:
+  case _adapter_rot_args:
+    {
+      int swap_slots = type2size[src];
+      oop mtype      = sun_dyn_AdapterMethodHandle::type(mh());
+      int slot_limit = sun_dyn_AdapterMethodHandle::vmslots(mtype);
+      int src_slot   = argslot;
+      int dest_slot  = vminfo;
+      int rotate     = (ek_orig == _adapter_swap_args) ? 0 : (src_slot > dest_slot) ? 1 : -1;
+      switch (swap_slots) {
+      case 1:
+        ek_opt = (!rotate    ? _adapter_opt_swap_1 :
+                  rotate > 0 ? _adapter_opt_rot_1_up : _adapter_opt_rot_1_down);
+        break;
+      case 2:
+        ek_opt = (!rotate    ? _adapter_opt_swap_2 :
+                  rotate > 0 ? _adapter_opt_rot_2_up : _adapter_opt_rot_2_down);
+        break;
+      default:
+        assert(false, "");
+        break;
+      }
+    }
+    break;
+
+  case _adapter_collect_args:
+    goto throw_not_impl;        // allocates, hence could block
+
+  case _adapter_spread_args:
+    {
+      // vminfo will be the required length of the array
+      int slots_pushed = stack_move / stack_move_unit();
+      int array_size   = slots_pushed + 1;
+      assert(array_size >= 0, "");
+      vminfo = array_size;
+      switch (array_size) {
+      case 0:   ek_opt = _adapter_opt_spread_0;       break;
+      case 1:   ek_opt = _adapter_opt_spread_1;       break;
+      default:  ek_opt = _adapter_opt_spread_more;    break;
+      }
+      if ((vminfo & CONV_VMINFO_MASK) != vminfo)
+        goto throw_not_impl;    // overflow
+    }
+    break;
+
+  case _adapter_flyby:
+  case _adapter_ricochet:
+    goto throw_not_impl;        // runs Java code, hence could block
+
+  default:
+    // should have failed much earlier; must be a missing case here
+    assert(false, "incomplete switch");
+    // and fall through:
+
+  throw_not_impl:
+    // FIXME: these adapters are NYI
+    err = "adapter not yet implemented in the JVM";
+    break;
+  }
+
+  if (err != NULL) {
+    throw_InternalError_for_bad_conversion(conversion, err, THREAD);
+    return;
+  }
+
+  // Rebuild the conversion value; maybe parts of it were changed.
+  jint new_conversion = adapter_conversion(conv_op, src, dest, stack_move, vminfo);
+
+  // Finalize the conversion field.  (Note that it is final to Java code.)
+  sun_dyn_AdapterMethodHandle::set_conversion(mh(), new_conversion);
+
+  // Done!
+  java_dyn_MethodHandle::set_vmentry(mh(), entry(ek_opt));
+
+  // There should be enough memory barriers on exit from native methods
+  // to ensure that the MH is fully initialized to all threads before
+  // Java code can publish it in global data structures.
+}
+
+//
+// Here are the native methods on sun.dyn.MethodHandleImpl.
+// They are the private interface between this JVM and the HotSpot-specific
+// Java code that implements JSR 292 method handles.
+//
+// Note:  We use a JVM_ENTRY macro to define each of these, for this is the way
+// that intrinsic (non-JNI) native methods are defined in HotSpot.
+//
+
+// direct method handles for invokestatic or invokespecial
+// void init(DirectMethodHandle self, MemberName ref, boolean doDispatch, Class<?> caller);
+JVM_ENTRY(void, MHI_init_DMH(JNIEnv *env, jobject igcls, jobject mh_jh,
+                             jobject target_jh, jboolean do_dispatch, jobject caller_jh)) {
+  ResourceMark rm;              // for error messages
+
+  // This is the guy we are initializing:
+  if (mh_jh == NULL) { THROW(vmSymbols::java_lang_InternalError()); }
+  Handle mh(THREAD, JNIHandles::resolve_non_null(mh_jh));
+
+  // Early returns out of this method leave the DMH in an unfinished state.
+  assert(java_dyn_MethodHandle::vmentry(mh()) == NULL, "must be safely null");
+
+  // which method are we really talking about?
+  if (target_jh == NULL) { THROW(vmSymbols::java_lang_InternalError()); }
+  oop target_oop = JNIHandles::resolve_non_null(target_jh);
+  if (sun_dyn_MemberName::is_instance(target_oop) &&
+      sun_dyn_MemberName::vmindex(target_oop) == VM_INDEX_UNINITIALIZED) {
+    Handle mname(THREAD, target_oop);
+    MethodHandles::resolve_MemberName(mname, CHECK);
+    target_oop = mname(); // in case of GC
+  }
+
+  int decode_flags = 0; klassOop receiver_limit = NULL;
+  methodHandle m(THREAD,
+                 MethodHandles::decode_method(target_oop,
+                                              receiver_limit, decode_flags));
+  if (m.is_null()) { THROW_MSG(vmSymbols::java_lang_InternalError(), "no such method"); }
+
+  // The trusted Java code that calls this method should already have performed
+  // access checks on behalf of the given caller.  But, we can verify this.
+  if (VerifyMethodHandles && caller_jh != NULL) {
+    KlassHandle caller(THREAD, java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(caller_jh)));
+    // If this were a bytecode, the first access check would be against
+    // the "reference class" mentioned in the CONSTANT_Methodref.
+    // For that class, we use the defining class of m,
+    // or a more specific receiver limit if available.
+    klassOop reference_klass = m->method_holder();  // OK approximation
+    if (receiver_limit != NULL && receiver_limit != reference_klass) {
+      if (!Klass::cast(receiver_limit)->is_subtype_of(reference_klass))
+        THROW_MSG(vmSymbols::java_lang_InternalError(), "receiver limit out of bounds");  // Java code bug
+      reference_klass = receiver_limit;
+    }
+    // Emulate LinkResolver::check_klass_accessability.
+    if (!Reflection::verify_class_access(caller->as_klassOop(),
+                                         reference_klass,
+                                         true)) {
+      THROW_MSG(vmSymbols::java_lang_InternalError(), Klass::cast(m->method_holder())->external_name());
+    }
+    // If there were a bytecode, the next step would be to lookup the method
+    // in the reference class, then then check the method's access bits.
+    // Emulate LinkResolver::check_method_accessability.
+    klassOop resolved_klass = m->method_holder();
+    if (!Reflection::verify_field_access(caller->as_klassOop(),
+                                         resolved_klass, reference_klass,
+                                         m->access_flags(),
+                                         true)) {
+      // %%% following cutout belongs in Reflection::verify_field_access?
+      bool same_pm = Reflection::is_same_package_member(caller->as_klassOop(),
+                                                        reference_klass, THREAD);
+      if (!same_pm) {
+        THROW_MSG(vmSymbols::java_lang_InternalError(), m->name_and_sig_as_C_string());
+      }
+    }
+  }
+
+  MethodHandles::init_DirectMethodHandle(mh, m, (do_dispatch != JNI_FALSE), CHECK);
+}
+JVM_END
+
+// bound method handles
+JVM_ENTRY(void, MHI_init_BMH(JNIEnv *env, jobject igcls, jobject mh_jh,
+                             jobject target_jh, int argnum)) {
+  ResourceMark rm;              // for error messages
+
+  // This is the guy we are initializing:
+  if (mh_jh == NULL) { THROW(vmSymbols::java_lang_InternalError()); }
+  Handle mh(THREAD, JNIHandles::resolve_non_null(mh_jh));
+
+  // Early returns out of this method leave the BMH in an unfinished state.
+  assert(java_dyn_MethodHandle::vmentry(mh()) == NULL, "must be safely null");
+
+  if (target_jh == NULL) { THROW(vmSymbols::java_lang_InternalError()); }
+  Handle target(THREAD, JNIHandles::resolve_non_null(target_jh));
+
+  if (!java_dyn_MethodHandle::is_instance(target())) {
+    // Target object is a reflective method.  (%%% Do we need this alternate path?)
+    Untested("init_BMH of non-MH");
+    if (argnum != 0) { THROW(vmSymbols::java_lang_InternalError()); }
+    int decode_flags = 0; klassOop receiver_limit_oop = NULL;
+    methodHandle m(THREAD,
+                   MethodHandles::decode_method(target(),
+                                                receiver_limit_oop,
+                                                decode_flags));
+    KlassHandle receiver_limit(THREAD, receiver_limit_oop);
+    MethodHandles::init_BoundMethodHandle_with_receiver(mh, m,
+                                                       receiver_limit,
+                                                       decode_flags,
+                                                       CHECK);
+    return;
+  }
+
+  // Build a BMH on top of a DMH or another BMH:
+  MethodHandles::init_BoundMethodHandle(mh, target, argnum, CHECK);
+}
+JVM_END
+
+// adapter method handles
+JVM_ENTRY(void, MHI_init_AMH(JNIEnv *env, jobject igcls, jobject mh_jh,
+                             jobject target_jh, int argnum)) {
+  // This is the guy we are initializing:
+  if (mh_jh == NULL || target_jh == NULL) {
+    THROW(vmSymbols::java_lang_InternalError());
+  }
+  Handle mh(THREAD, JNIHandles::resolve_non_null(mh_jh));
+  Handle target(THREAD, JNIHandles::resolve_non_null(target_jh));
+
+  // Early returns out of this method leave the AMH in an unfinished state.
+  assert(java_dyn_MethodHandle::vmentry(mh()) == NULL, "must be safely null");
+
+  MethodHandles::init_AdapterMethodHandle(mh, target, argnum, CHECK);
+}
+JVM_END
+
+// method type forms
+JVM_ENTRY(void, MHI_init_MT(JNIEnv *env, jobject igcls, jobject erased_jh)) {
+  if (erased_jh == NULL)  return;
+  if (TraceMethodHandles) {
+    tty->print("creating MethodType form ");
+    if (WizardMode || Verbose) {   // Warning: this calls Java code on the MH!
+      // call Object.toString()
+      symbolOop name = vmSymbols::toString_name(), sig = vmSymbols::void_string_signature();
+      JavaCallArguments args(Handle(THREAD, JNIHandles::resolve_non_null(erased_jh)));
+      JavaValue result(T_OBJECT);
+      JavaCalls::call_virtual(&result, SystemDictionary::object_klass(), name, sig,
+                              &args, CHECK);
+      Handle str(THREAD, (oop)result.get_jobject());
+      java_lang_String::print(str, tty);
+    }
+    tty->cr();
+  }
+}
+JVM_END
+
+// debugging and reflection
+JVM_ENTRY(jobject, MHI_getTarget(JNIEnv *env, jobject igcls, jobject mh_jh, jint format)) {
+  Handle mh(THREAD, JNIHandles::resolve(mh_jh));
+  if (!java_dyn_MethodHandle::is_instance(mh())) {
+    THROW_NULL(vmSymbols::java_lang_IllegalArgumentException());
+  }
+  oop target = MethodHandles::encode_target(mh, format, CHECK_NULL);
+  return JNIHandles::make_local(THREAD, target);
+}
+JVM_END
+
+JVM_ENTRY(jint, MHI_getConstant(JNIEnv *env, jobject igcls, jint which)) {
+  switch (which) {
+  case MethodHandles::GC_JVM_PUSH_LIMIT:
+    guarantee(MethodHandlePushLimit >= 2 && MethodHandlePushLimit <= 0xFF,
+              "MethodHandlePushLimit parameter must be in valid range");
+    return MethodHandlePushLimit;
+  case MethodHandles::GC_JVM_STACK_MOVE_LIMIT:
+    // return number of words per slot, signed according to stack direction
+    return MethodHandles::stack_move_unit();
+  }
+  return 0;
+}
+JVM_END
+
+#ifndef PRODUCT
+#define EACH_NAMED_CON(template) \
+    template(MethodHandles,GC_JVM_PUSH_LIMIT) \
+    template(MethodHandles,GC_JVM_STACK_MOVE_LIMIT) \
+    template(MethodHandles,ETF_HANDLE_OR_METHOD_NAME) \
+    template(MethodHandles,ETF_DIRECT_HANDLE) \
+    template(MethodHandles,ETF_METHOD_NAME) \
+    template(MethodHandles,ETF_REFLECT_METHOD) \
+    template(sun_dyn_MemberName,MN_IS_METHOD) \
+    template(sun_dyn_MemberName,MN_IS_CONSTRUCTOR) \
+    template(sun_dyn_MemberName,MN_IS_FIELD) \
+    template(sun_dyn_MemberName,MN_IS_TYPE) \
+    template(sun_dyn_MemberName,MN_SEARCH_SUPERCLASSES) \
+    template(sun_dyn_MemberName,MN_SEARCH_INTERFACES) \
+    template(sun_dyn_MemberName,VM_INDEX_UNINITIALIZED) \
+    template(sun_dyn_AdapterMethodHandle,OP_RETYPE_ONLY) \
+    template(sun_dyn_AdapterMethodHandle,OP_CHECK_CAST) \
+    template(sun_dyn_AdapterMethodHandle,OP_PRIM_TO_PRIM) \
+    template(sun_dyn_AdapterMethodHandle,OP_REF_TO_PRIM) \
+    template(sun_dyn_AdapterMethodHandle,OP_PRIM_TO_REF) \
+    template(sun_dyn_AdapterMethodHandle,OP_SWAP_ARGS) \
+    template(sun_dyn_AdapterMethodHandle,OP_ROT_ARGS) \
+    template(sun_dyn_AdapterMethodHandle,OP_DUP_ARGS) \
+    template(sun_dyn_AdapterMethodHandle,OP_DROP_ARGS) \
+    template(sun_dyn_AdapterMethodHandle,OP_COLLECT_ARGS) \
+    template(sun_dyn_AdapterMethodHandle,OP_SPREAD_ARGS) \
+    template(sun_dyn_AdapterMethodHandle,OP_FLYBY) \
+    template(sun_dyn_AdapterMethodHandle,OP_RICOCHET) \
+    template(sun_dyn_AdapterMethodHandle,CONV_OP_LIMIT) \
+    template(sun_dyn_AdapterMethodHandle,CONV_OP_MASK) \
+    template(sun_dyn_AdapterMethodHandle,CONV_VMINFO_MASK) \
+    template(sun_dyn_AdapterMethodHandle,CONV_VMINFO_SHIFT) \
+    template(sun_dyn_AdapterMethodHandle,CONV_OP_SHIFT) \
+    template(sun_dyn_AdapterMethodHandle,CONV_DEST_TYPE_SHIFT) \
+    template(sun_dyn_AdapterMethodHandle,CONV_SRC_TYPE_SHIFT) \
+    template(sun_dyn_AdapterMethodHandle,CONV_STACK_MOVE_SHIFT) \
+    template(sun_dyn_AdapterMethodHandle,CONV_STACK_MOVE_MASK) \
+    /*end*/
+
+#define ONE_PLUS(scope,value) 1+
+static const int con_value_count = EACH_NAMED_CON(ONE_PLUS) 0;
+#define VALUE_COMMA(scope,value) scope::value,
+static const int con_values[con_value_count+1] = { EACH_NAMED_CON(VALUE_COMMA) 0 };
+#define STRING_NULL(scope,value) #value "\0"
+static const char con_names[] = { EACH_NAMED_CON(STRING_NULL) };
+
+#undef ONE_PLUS
+#undef VALUE_COMMA
+#undef STRING_NULL
+#undef EACH_NAMED_CON
+#endif
+
+JVM_ENTRY(jint, MHI_getNamedCon(JNIEnv *env, jobject igcls, jint which, jobjectArray box_jh)) {
+#ifndef PRODUCT
+  if (which >= 0 && which < con_value_count) {
+    int con = con_values[which];
+    objArrayOop box = (objArrayOop) JNIHandles::resolve(box_jh);
+    if (box != NULL && box->klass() == Universe::objectArrayKlassObj() && box->length() > 0) {
+      const char* str = &con_names[0];
+      for (int i = 0; i < which; i++)
+        str += strlen(str) + 1;   // skip name and null
+      oop name = java_lang_String::create_oop_from_str(str, CHECK_0);
+      box->obj_at_put(0, name);
+    }
+    return con;
+  }
+#endif
+  return 0;
+}
+JVM_END
+
+// void init(MemberName self, AccessibleObject ref)
+JVM_ENTRY(void, MHI_init_Mem(JNIEnv *env, jobject igcls, jobject mname_jh, jobject target_jh)) {
+  if (mname_jh == NULL || target_jh == NULL) { THROW(vmSymbols::java_lang_InternalError()); }
+  Handle mname(THREAD, JNIHandles::resolve_non_null(mname_jh));
+  oop target_oop = JNIHandles::resolve_non_null(target_jh);
+  MethodHandles::init_MemberName(mname(), target_oop);
+}
+JVM_END
+
+// void expand(MemberName self)
+JVM_ENTRY(void, MHI_expand_Mem(JNIEnv *env, jobject igcls, jobject mname_jh)) {
+  if (mname_jh == NULL) { THROW(vmSymbols::java_lang_InternalError()); }
+  Handle mname(THREAD, JNIHandles::resolve_non_null(mname_jh));
+  MethodHandles::expand_MemberName(mname, 0, CHECK);
+}
+JVM_END
+
+// void resolve(MemberName self, Class<?> caller)
+JVM_ENTRY(void, MHI_resolve_Mem(JNIEnv *env, jobject igcls, jobject mname_jh, jclass caller_jh)) {
+  if (mname_jh == NULL) { THROW(vmSymbols::java_lang_InternalError()); }
+  Handle mname(THREAD, JNIHandles::resolve_non_null(mname_jh));
+  // %%% take caller into account!
+  MethodHandles::resolve_MemberName(mname, CHECK);
+}
+JVM_END
+
+//  static native int getMembers(Class<?> defc, String matchName, String matchSig,
+//          int matchFlags, Class<?> caller, int skip, MemberName[] results);
+JVM_ENTRY(jint, MHI_getMembers(JNIEnv *env, jobject igcls,
+                               jclass clazz_jh, jstring name_jh, jstring sig_jh,
+                               int mflags, jclass caller_jh, jint skip, jobjectArray results_jh)) {
+  if (clazz_jh == NULL || results_jh == NULL)  return -1;
+  klassOop k_oop = java_lang_Class::as_klassOop(JNIHandles::resolve_non_null(clazz_jh));
+
+  objArrayOop results = (objArrayOop) JNIHandles::resolve(results_jh);
+  if (results == NULL || !results->is_objArray())       return -1;
+
+  symbolOop name = NULL, sig = NULL;
+  if (name_jh != NULL) {
+    name = java_lang_String::as_symbol_or_null(JNIHandles::resolve_non_null(name_jh));
+    if (name == NULL)  return 0; // a match is not possible
+  }
+  if (sig_jh != NULL) {
+    sig = java_lang_String::as_symbol_or_null(JNIHandles::resolve_non_null(sig_jh));
+    if (sig == NULL)  return 0; // a match is not possible
+  }
+
+  klassOop caller = NULL;
+  if (caller_jh != NULL) {
+    oop caller_oop = JNIHandles::resolve_non_null(caller_jh);
+    if (!java_lang_Class::is_instance(caller_oop))  return -1;
+    caller = java_lang_Class::as_klassOop(caller_oop);
+  }
+
+  if (name != NULL && sig != NULL && results != NULL) {
+    // try a direct resolve
+    // %%% TO DO
+  }
+
+  int res = MethodHandles::find_MemberNames(k_oop, name, sig, mflags,
+                                            caller, skip, results);
+  // TO DO: expand at least some of the MemberNames, to avoid massive callbacks
+  return res;
+}
+JVM_END
+
+
+/// JVM_RegisterMethodHandleMethods
+
+#define ADR "J"
+
+#define LANG "Ljava/lang/"
+#define JDYN "Ljava/dyn/"
+#define IDYN "Lsun/dyn/"
+
+#define OBJ   LANG"Object;"
+#define CLS   LANG"Class;"
+#define STRG  LANG"String;"
+#define MT    JDYN"MethodType;"
+#define MH    JDYN"MethodHandle;"
+#define MHI   IDYN"MethodHandleImpl;"
+#define MEM   IDYN"MemberName;"
+#define AMH   IDYN"AdapterMethodHandle;"
+#define BMH   IDYN"BoundMethodHandle;"
+#define DMH   IDYN"DirectMethodHandle;"
+
+#define CC (char*)  /*cast a literal from (const char*)*/
+#define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f)
+
+// These are the native methods on sun.dyn.MethodHandleNatives.
+static JNINativeMethod methods[] = {
+  // void init(MemberName self, AccessibleObject ref)
+  {CC"init",                    CC"("AMH""MH"I)V",              FN_PTR(MHI_init_AMH)},
+  {CC"init",                    CC"("BMH""OBJ"I)V",             FN_PTR(MHI_init_BMH)},
+  {CC"init",                    CC"("DMH""OBJ"Z"CLS")V",        FN_PTR(MHI_init_DMH)},
+  {CC"init",                    CC"("MT")V",                    FN_PTR(MHI_init_MT)},
+  {CC"init",                    CC"("MEM""OBJ")V",              FN_PTR(MHI_init_Mem)},
+  {CC"expand",                  CC"("MEM")V",                   FN_PTR(MHI_expand_Mem)},
+  {CC"resolve",                 CC"("MEM""CLS")V",              FN_PTR(MHI_resolve_Mem)},
+  {CC"getTarget",               CC"("MH"I)"OBJ,                 FN_PTR(MHI_getTarget)},
+  {CC"getConstant",             CC"(I)I",                       FN_PTR(MHI_getConstant)},
+  //  static native int getNamedCon(int which, Object[] name)
+  {CC"getNamedCon",             CC"(I["OBJ")I",                 FN_PTR(MHI_getNamedCon)},
+  //  static native int getMembers(Class<?> defc, String matchName, String matchSig,
+  //          int matchFlags, Class<?> caller, int skip, MemberName[] results);
+  {CC"getMembers",              CC"("CLS""STRG""STRG"I"CLS"I["MEM")I",  FN_PTR(MHI_getMembers)}
+};
+
+
+// This one function is exported, used by NativeLookup.
+
+JVM_ENTRY(void, JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass MHN_class)) {
+  assert(MethodHandles::spot_check_entry_names(), "entry enum is OK");
+
+  if (!EnableMethodHandles) {
+    warning("JSR 292 method handles are disabled in this JVM.  Use -XX:+EnableMethodHandles to enable.");
+    return;  // bind nothing
+  }
+
+  {
+    ThreadToNativeFromVM ttnfv(thread);
+
+    int status = env->RegisterNatives(MHN_class, methods, sizeof(methods)/sizeof(JNINativeMethod));
+    if (env->ExceptionOccurred()) {
+      MethodHandles::set_enabled(false);
+      warning("JSR 292 method handle code is mismatched to this JVM.  Disabling support.");
+      env->ExceptionClear();
+    } else {
+      MethodHandles::set_enabled(true);
+    }
+  }
+}
+JVM_END
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/prims/methodHandles.hpp	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,435 @@
+/*
+ * Copyright 2008-2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+class MacroAssembler;
+class Label;
+class MethodHandleEntry;
+
+class MethodHandles: AllStatic {
+  // JVM support for MethodHandle, MethodType, and related types
+  // in java.dyn and java.dyn.hotspot.
+  // See also  javaClasses for layouts java_dyn_Method{Handle,Type,Type::Form}.
+ public:
+  enum EntryKind {
+    _check_mtype,               // how a caller calls a MH
+    _wrong_method_type,         // what happens when there is a type mismatch
+    _invokestatic_mh,           // how a MH emulates invokestatic
+    _invokespecial_mh,          // ditto for the other invokes...
+    _invokevirtual_mh,
+    _invokeinterface_mh,
+    _bound_ref_mh,              // reference argument is bound
+    _bound_int_mh,              // int argument is bound (via an Integer or Float)
+    _bound_long_mh,             // long argument is bound (via a Long or Double)
+    _bound_ref_direct_mh,       // same as above, with direct linkage to methodOop
+    _bound_int_direct_mh,
+    _bound_long_direct_mh,
+
+    _adapter_mh_first,     // adapter sequence goes here...
+    _adapter_retype_only   = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_RETYPE_ONLY,
+    _adapter_check_cast    = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_CHECK_CAST,
+    _adapter_prim_to_prim  = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_PRIM_TO_PRIM,
+    _adapter_ref_to_prim   = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_REF_TO_PRIM,
+    _adapter_prim_to_ref   = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_PRIM_TO_REF,
+    _adapter_swap_args     = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_SWAP_ARGS,
+    _adapter_rot_args      = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_ROT_ARGS,
+    _adapter_dup_args      = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_DUP_ARGS,
+    _adapter_drop_args     = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_DROP_ARGS,
+    _adapter_collect_args  = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_COLLECT_ARGS,
+    _adapter_spread_args   = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_SPREAD_ARGS,
+    _adapter_flyby         = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_FLYBY,
+    _adapter_ricochet      = _adapter_mh_first + sun_dyn_AdapterMethodHandle::OP_RICOCHET,
+    _adapter_mh_last       = _adapter_mh_first + sun_dyn_AdapterMethodHandle::CONV_OP_LIMIT - 1,
+
+    // Optimized adapter types
+
+    // argument list reordering
+    _adapter_opt_swap_1,
+    _adapter_opt_swap_2,
+    _adapter_opt_rot_1_up,
+    _adapter_opt_rot_1_down,
+    _adapter_opt_rot_2_up,
+    _adapter_opt_rot_2_down,
+    // primitive single to single:
+    _adapter_opt_i2i,           // i2c, i2z, i2b, i2s
+    // primitive double to single:
+    _adapter_opt_l2i,
+    _adapter_opt_d2f,
+    // primitive single to double:
+    _adapter_opt_i2l,
+    _adapter_opt_f2d,
+    // conversion between floating point and integer type is handled by Java
+
+    // reference to primitive:
+    _adapter_opt_unboxi,
+    _adapter_opt_unboxl,
+
+    // spreading (array length cases 0, 1, >=2)
+    _adapter_opt_spread_0,
+    _adapter_opt_spread_1,
+    _adapter_opt_spread_more,
+
+    _EK_LIMIT,
+    _EK_FIRST = 0
+  };
+
+ public:
+  static bool enabled()                         { return _enabled; }
+  static void set_enabled(bool z);
+
+ private:
+  enum {  // import sun_dyn_AdapterMethodHandle::CONV_OP_*
+    CONV_OP_LIMIT         = sun_dyn_AdapterMethodHandle::CONV_OP_LIMIT,
+    CONV_OP_MASK          = sun_dyn_AdapterMethodHandle::CONV_OP_MASK,
+    CONV_VMINFO_MASK      = sun_dyn_AdapterMethodHandle::CONV_VMINFO_MASK,
+    CONV_VMINFO_SHIFT     = sun_dyn_AdapterMethodHandle::CONV_VMINFO_SHIFT,
+    CONV_OP_SHIFT         = sun_dyn_AdapterMethodHandle::CONV_OP_SHIFT,
+    CONV_DEST_TYPE_SHIFT  = sun_dyn_AdapterMethodHandle::CONV_DEST_TYPE_SHIFT,
+    CONV_SRC_TYPE_SHIFT   = sun_dyn_AdapterMethodHandle::CONV_SRC_TYPE_SHIFT,
+    CONV_STACK_MOVE_SHIFT = sun_dyn_AdapterMethodHandle::CONV_STACK_MOVE_SHIFT,
+    CONV_STACK_MOVE_MASK  = sun_dyn_AdapterMethodHandle::CONV_STACK_MOVE_MASK
+  };
+
+  static bool _enabled;
+  static MethodHandleEntry* _entries[_EK_LIMIT];
+  static const char*        _entry_names[_EK_LIMIT+1];
+  static bool ek_valid(EntryKind ek)            { return (uint)ek < (uint)_EK_LIMIT; }
+  static bool conv_op_valid(int op)             { return (uint)op < (uint)CONV_OP_LIMIT; }
+
+ public:
+  static bool    have_entry(EntryKind ek)       { return ek_valid(ek) && _entries[ek] != NULL; }
+  static MethodHandleEntry* entry(EntryKind ek) { assert(ek_valid(ek), "initialized");
+                                                  return _entries[ek]; }
+  static const char* entry_name(EntryKind ek)   { assert(ek_valid(ek), "oob");
+                                                  return _entry_names[ek]; }
+  static EntryKind adapter_entry_kind(int op)   { assert(conv_op_valid(op), "oob");
+                                                  return EntryKind(_adapter_mh_first + op); }
+
+  static void init_entry(EntryKind ek, MethodHandleEntry* me) {
+    assert(ek_valid(ek), "oob");
+    assert(_entries[ek] == NULL, "no double initialization");
+    _entries[ek] = me;
+  }
+
+  static jint adapter_conversion(int conv_op, BasicType src, BasicType dest,
+                                 int stack_move = 0, int vminfo = 0) {
+    assert(conv_op_valid(conv_op), "oob");
+    jint conv = ((conv_op      << CONV_OP_SHIFT)
+                 | (src        << CONV_SRC_TYPE_SHIFT)
+                 | (dest       << CONV_DEST_TYPE_SHIFT)
+                 | (stack_move << CONV_STACK_MOVE_SHIFT)
+                 | (vminfo     << CONV_VMINFO_SHIFT)
+                 );
+    assert(adapter_conversion_op(conv) == conv_op, "decode conv_op");
+    assert(adapter_conversion_src_type(conv) == src, "decode src");
+    assert(adapter_conversion_dest_type(conv) == dest, "decode dest");
+    assert(adapter_conversion_stack_move(conv) == stack_move, "decode stack_move");
+    assert(adapter_conversion_vminfo(conv) == vminfo, "decode vminfo");
+    return conv;
+  }
+  static int adapter_conversion_op(jint conv) {
+    return ((conv >> CONV_OP_SHIFT) & 0xF);
+  }
+  static BasicType adapter_conversion_src_type(jint conv) {
+    return (BasicType)((conv >> CONV_SRC_TYPE_SHIFT) & 0xF);
+  }
+  static BasicType adapter_conversion_dest_type(jint conv) {
+    return (BasicType)((conv >> CONV_DEST_TYPE_SHIFT) & 0xF);
+  }
+  static int adapter_conversion_stack_move(jint conv) {
+    return (conv >> CONV_STACK_MOVE_SHIFT);
+  }
+  static int adapter_conversion_vminfo(jint conv) {
+    return (conv >> CONV_VMINFO_SHIFT) & CONV_VMINFO_MASK;
+  }
+
+  // Offset in words that the interpreter stack pointer moves when an argument is pushed.
+  // The stack_move value must always be a multiple of this.
+  static int stack_move_unit() {
+    return frame::interpreter_frame_expression_stack_direction() * Interpreter::stackElementWords();
+  }
+
+  enum { CONV_VMINFO_SIGN_FLAG = 0x80 };
+  static int adapter_subword_vminfo(BasicType dest) {
+    if (dest == T_BOOLEAN) return (BitsPerInt -  1);
+    if (dest == T_CHAR)    return (BitsPerInt - 16);
+    if (dest == T_BYTE)    return (BitsPerInt -  8) | CONV_VMINFO_SIGN_FLAG;
+    if (dest == T_SHORT)   return (BitsPerInt - 16) | CONV_VMINFO_SIGN_FLAG;
+    return 0;                   // case T_INT
+  }
+  // Here is the transformation the i2i adapter must perform:
+  static int truncate_subword_from_vminfo(jint value, int vminfo) {
+    jint tem = value << vminfo;
+    if ((vminfo & CONV_VMINFO_SIGN_FLAG) != 0) {
+      return (jint)tem >> vminfo;
+    } else {
+      return (juint)tem >> vminfo;
+    }
+  }
+
+  static inline address from_compiled_entry(EntryKind ek);
+  static inline address from_interpreted_entry(EntryKind ek);
+
+  // helpers for decode_method.
+  static methodOop decode_methodOop(methodOop m, int& decode_flags_result);
+  static methodOop decode_vmtarget(oop vmtarget, int vmindex, oop mtype, klassOop& receiver_limit_result, int& decode_flags_result);
+  static methodOop decode_MemberName(oop mname, klassOop& receiver_limit_result, int& decode_flags_result);
+  static methodOop decode_MethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result);
+  static methodOop decode_DirectMethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result);
+  static methodOop decode_BoundMethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result);
+  static methodOop decode_AdapterMethodHandle(oop mh, klassOop& receiver_limit_result, int& decode_flags_result);
+
+  // Find out how many stack slots an mh pushes or pops.
+  // The result is *not* reported as a multiple of stack_move_unit();
+  // It is a signed net number of pushes (a difference in vmslots).
+  // To compare with a stack_move value, first multiply by stack_move_unit().
+  static int decode_MethodHandle_stack_pushes(oop mh);
+
+ public:
+  // working with member names
+  static void resolve_MemberName(Handle mname, TRAPS); // compute vmtarget/vmindex from name/type
+  static void expand_MemberName(Handle mname, int suppress, TRAPS);  // expand defc/name/type if missing
+  static void init_MemberName(oop mname_oop, oop target); // compute vmtarget/vmindex from target
+  static void init_MemberName(oop mname_oop, methodOop m, bool do_dispatch);
+  static void init_MemberName(oop mname_oop, klassOop field_holder, AccessFlags mods, int offset);
+  static int find_MemberNames(klassOop k, symbolOop name, symbolOop sig,
+                              int mflags, klassOop caller,
+                              int skip, objArrayOop results);
+  // bit values for suppress argument to expand_MemberName:
+  enum { _suppress_defc = 1, _suppress_name = 2, _suppress_type = 4 };
+
+  // called from InterpreterGenerator and StubGenerator
+  static address generate_method_handle_interpreter_entry(MacroAssembler* _masm);
+  static void generate_method_handle_stub(MacroAssembler* _masm, EntryKind ek);
+
+  // argument list parsing
+  static int argument_slot(oop method_type, int arg);
+  static int argument_slot_count(oop method_type) { return argument_slot(method_type, -1); }
+  static int argument_slot_to_argnum(oop method_type, int argslot);
+
+  // Runtime support
+  enum {                        // bit-encoded flags from decode_method or decode_vmref
+    _dmf_has_receiver   = 0x01, // target method has leading reference argument
+    _dmf_does_dispatch  = 0x02, // method handle performs virtual or interface dispatch
+    _dmf_from_interface = 0x04, // peforms interface dispatch
+    _DMF_DIRECT_MASK    = (_dmf_from_interface*2 - _dmf_has_receiver),
+    _dmf_binds_method   = 0x08,
+    _dmf_binds_argument = 0x10,
+    _DMF_BOUND_MASK     = (_dmf_binds_argument*2 - _dmf_binds_method),
+    _dmf_adapter_lsb    = 0x20,
+    _DMF_ADAPTER_MASK   = (_dmf_adapter_lsb << CONV_OP_LIMIT) - _dmf_adapter_lsb
+  };
+  static methodOop decode_method(oop x, klassOop& receiver_limit_result, int& decode_flags_result);
+  enum {
+    // format of query to getConstant:
+    GC_JVM_PUSH_LIMIT = 0,
+    GC_JVM_STACK_MOVE_LIMIT = 1,
+
+    // format of result from getTarget / encode_target:
+    ETF_HANDLE_OR_METHOD_NAME = 0, // all available data (immediate MH or method)
+    ETF_DIRECT_HANDLE         = 1, // ultimate method handle (will be a DMH, may be self)
+    ETF_METHOD_NAME           = 2, // ultimate method as MemberName
+    ETF_REFLECT_METHOD        = 3  // ultimate method as java.lang.reflect object (sans refClass)
+  };
+  static int get_named_constant(int which, Handle name_box, TRAPS);
+  static oop encode_target(Handle mh, int format, TRAPS); // report vmtarget (to Java code)
+  static bool class_cast_needed(klassOop src, klassOop dst);
+
+ private:
+  // These checkers operate on a pair of whole MethodTypes:
+  static const char* check_method_type_change(oop src_mtype, int src_beg, int src_end,
+                                              int insert_argnum, oop insert_type,
+                                              int change_argnum, oop change_type,
+                                              int delete_argnum,
+                                              oop dst_mtype, int dst_beg, int dst_end);
+  static const char* check_method_type_insertion(oop src_mtype,
+                                                 int insert_argnum, oop insert_type,
+                                                 oop dst_mtype) {
+    oop no_ref = NULL;
+    return check_method_type_change(src_mtype, 0, -1,
+                                    insert_argnum, insert_type,
+                                    -1, no_ref, -1, dst_mtype, 0, -1);
+  }
+  static const char* check_method_type_conversion(oop src_mtype,
+                                                  int change_argnum, oop change_type,
+                                                  oop dst_mtype) {
+    oop no_ref = NULL;
+    return check_method_type_change(src_mtype, 0, -1, -1, no_ref,
+                                    change_argnum, change_type,
+                                    -1, dst_mtype, 0, -1);
+  }
+  static const char* check_method_type_passthrough(oop src_mtype, oop dst_mtype) {
+    oop no_ref = NULL;
+    return check_method_type_change(src_mtype, 0, -1,
+                                    -1, no_ref, -1, no_ref, -1,
+                                    dst_mtype, 0, -1);
+  }
+
+  // These checkers operate on pairs of argument or return types:
+  static const char* check_argument_type_change(BasicType src_type, klassOop src_klass,
+                                                BasicType dst_type, klassOop dst_klass,
+                                                int argnum);
+
+  static const char* check_argument_type_change(oop src_type, oop dst_type,
+                                                int argnum) {
+    klassOop src_klass = NULL, dst_klass = NULL;
+    BasicType src_bt = java_lang_Class::as_BasicType(src_type, &src_klass);
+    BasicType dst_bt = java_lang_Class::as_BasicType(dst_type, &dst_klass);
+    return check_argument_type_change(src_bt, src_klass,
+                                      dst_bt, dst_klass, argnum);
+  }
+
+  static const char* check_return_type_change(oop src_type, oop dst_type) {
+    return check_argument_type_change(src_type, dst_type, -1);
+  }
+
+  static const char* check_return_type_change(BasicType src_type, klassOop src_klass,
+                                              BasicType dst_type, klassOop dst_klass) {
+    return check_argument_type_change(src_type, src_klass, dst_type, dst_klass, -1);
+  }
+
+  static const char* check_method_receiver(methodOop m, klassOop passed_recv_type);
+
+  // These verifiers can block, and will throw an error if the checking fails:
+  static void verify_vmslots(Handle mh, TRAPS);
+  static void verify_vmargslot(Handle mh, int argnum, int argslot, TRAPS);
+
+  static void verify_method_type(methodHandle m, Handle mtype,
+                                 bool has_bound_oop,
+                                 KlassHandle bound_oop_type,
+                                 TRAPS);
+
+  static void verify_method_signature(methodHandle m, Handle mtype,
+                                      int first_ptype_pos,
+                                      KlassHandle insert_ptype, TRAPS);
+
+  static void verify_DirectMethodHandle(Handle mh, methodHandle m, TRAPS);
+  static void verify_BoundMethodHandle(Handle mh, Handle target, int argnum,
+                                       bool direct_to_method, TRAPS);
+  static void verify_BoundMethodHandle_with_receiver(Handle mh, methodHandle m, TRAPS);
+  static void verify_AdapterMethodHandle(Handle mh, int argnum, TRAPS);
+
+ public:
+
+  // Fill in the fields of a DirectMethodHandle mh.  (MH.type must be pre-filled.)
+  static void init_DirectMethodHandle(Handle mh, methodHandle method, bool do_dispatch, TRAPS);
+
+  // Fill in the fields of a BoundMethodHandle mh.  (MH.type, BMH.argument must be pre-filled.)
+  static void init_BoundMethodHandle(Handle mh, Handle target, int argnum, TRAPS);
+  static void init_BoundMethodHandle_with_receiver(Handle mh,
+                                                   methodHandle original_m,
+                                                   KlassHandle receiver_limit,
+                                                   int decode_flags,
+                                                   TRAPS);
+
+  // Fill in the fields of an AdapterMethodHandle mh.  (MH.type must be pre-filled.)
+  static void init_AdapterMethodHandle(Handle mh, Handle target, int argnum, TRAPS);
+
+#ifdef ASSERT
+  static bool spot_check_entry_names();
+#endif
+
+ private:
+  static methodHandle dispatch_decoded_method(methodHandle m,
+                                              KlassHandle receiver_limit,
+                                              int decode_flags,
+                                              KlassHandle receiver_klass,
+                                              TRAPS);
+
+  static bool same_basic_type_for_arguments(BasicType src, BasicType dst,
+                                            bool for_return = false);
+  static bool same_basic_type_for_returns(BasicType src, BasicType dst) {
+    return same_basic_type_for_arguments(src, dst, true);
+  }
+
+  enum {                        // arg_mask values
+    _INSERT_NO_MASK   = -1,
+    _INSERT_REF_MASK  = 0,
+    _INSERT_INT_MASK  = 1,
+    _INSERT_LONG_MASK = 3
+  };
+  static void insert_arg_slots(MacroAssembler* _masm,
+                               RegisterOrConstant arg_slots,
+                               int arg_mask,
+                               Register rax_argslot,
+                               Register rbx_temp, Register rdx_temp);
+
+  static void remove_arg_slots(MacroAssembler* _masm,
+                               RegisterOrConstant arg_slots,
+                               Register rax_argslot,
+                               Register rbx_temp, Register rdx_temp);
+};
+
+
+// Access methods for the "entry" field of a java.dyn.MethodHandle.
+// The field is primarily a jump target for compiled calls.
+// However, we squirrel away some nice pointers for other uses,
+// just before the jump target.
+// Aspects of a method handle entry:
+//  - from_compiled_entry - stub used when compiled code calls the MH
+//  - from_interpreted_entry - stub used when the interpreter calls the MH
+//  - type_checking_entry - stub for runtime casting between MHForm siblings (NYI)
+class MethodHandleEntry {
+ public:
+  class Data {
+    friend class MethodHandleEntry;
+    size_t              _total_size; // size including Data and code stub
+    MethodHandleEntry*  _type_checking_entry;
+    address             _from_interpreted_entry;
+    MethodHandleEntry* method_entry() { return (MethodHandleEntry*)(this + 1); }
+  };
+
+  Data*     data()                              { return (Data*)this - 1; }
+
+  address   start_address()                     { return (address) data(); }
+  address   end_address()                       { return start_address() + data()->_total_size; }
+
+  address   from_compiled_entry()               { return (address) this; }
+
+  address   from_interpreted_entry()            { return data()->_from_interpreted_entry; }
+  void  set_from_interpreted_entry(address e)   { data()->_from_interpreted_entry = e; }
+
+  MethodHandleEntry* type_checking_entry()           { return data()->_type_checking_entry; }
+  void set_type_checking_entry(MethodHandleEntry* e) { data()->_type_checking_entry = e; }
+
+  void set_end_address(address end_addr) {
+    size_t total_size = end_addr - start_address();
+    assert(total_size > 0 && total_size < 0x1000, "reasonable end address");
+    data()->_total_size = total_size;
+  }
+
+  // Compiler support:
+  static int from_interpreted_entry_offset_in_bytes() {
+    return (int)( offset_of(Data, _from_interpreted_entry) - sizeof(Data) );
+  }
+  static int type_checking_entry_offset_in_bytes() {
+    return (int)( offset_of(Data, _from_interpreted_entry) - sizeof(Data) );
+  }
+
+  static address            start_compiled_entry(MacroAssembler* _masm,
+                                                 address interpreted_entry = NULL);
+  static MethodHandleEntry* finish_compiled_entry(MacroAssembler* masm, address start_addr);
+};
+
+address MethodHandles::from_compiled_entry(EntryKind ek) { return entry(ek)->from_compiled_entry(); }
+address MethodHandles::from_interpreted_entry(EntryKind ek) { return entry(ek)->from_interpreted_entry(); }
--- a/hotspot/src/share/vm/prims/nativeLookup.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/prims/nativeLookup.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2006 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc.  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
@@ -78,6 +78,7 @@
 
 extern "C" {
   void JNICALL JVM_RegisterUnsafeMethods(JNIEnv *env, jclass unsafecls);
+  void JNICALL JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass unsafecls);
   void JNICALL JVM_RegisterPerfMethods(JNIEnv *env, jclass perfclass);
 }
 
@@ -97,6 +98,9 @@
   if (strstr(jni_name, "Java_sun_misc_Unsafe_registerNatives") != NULL) {
     return CAST_FROM_FN_PTR(address, JVM_RegisterUnsafeMethods);
   }
+  if (strstr(jni_name, "Java_sun_dyn_MethodHandleNatives_registerNatives") != NULL) {
+    return CAST_FROM_FN_PTR(address, JVM_RegisterMethodHandleMethods);
+  }
   if (strstr(jni_name, "Java_sun_misc_Perf_registerNatives") != NULL) {
     return CAST_FROM_FN_PTR(address, JVM_RegisterPerfMethods);
   }
--- a/hotspot/src/share/vm/runtime/arguments.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/runtime/arguments.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -2627,6 +2627,13 @@
   }
 #endif // PRODUCT
 
+  if (EnableMethodHandles && !AnonymousClasses) {
+    if (!FLAG_IS_DEFAULT(AnonymousClasses)) {
+      warning("forcing AnonymousClasses true to enable EnableMethodHandles");
+    }
+    AnonymousClasses = true;
+  }
+
   if (PrintGCDetails) {
     // Turn on -verbose:gc options as well
     PrintGC = true;
--- a/hotspot/src/share/vm/runtime/globals.hpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/runtime/globals.hpp	Wed Jul 05 16:51:35 2017 +0200
@@ -3301,6 +3301,21 @@
   product(bool, AnonymousClasses, false,                                    \
           "support sun.misc.Unsafe.defineAnonymousClass")                   \
                                                                             \
+  product(bool, EnableMethodHandles, false,                                 \
+          "support method handles (true by default under JSR 292)")         \
+                                                                            \
+  diagnostic(intx, MethodHandlePushLimit, 3,                                \
+          "number of additional stack slots a method handle may push")      \
+                                                                            \
+  develop(bool, TraceMethodHandles, false,                                  \
+          "trace internal method handle operations")                        \
+                                                                            \
+  diagnostic(bool, VerifyMethodHandles, trueInDebug,                        \
+          "perform extra checks when constructing method handles")          \
+                                                                            \
+  diagnostic(bool, OptimizeMethodHandles, true,                             \
+          "when constructing method handles, try to improve them")          \
+                                                                            \
   product(bool, TaggedStackInterpreter, false,                              \
           "Insert tags in interpreter execution stack for oopmap generaion")\
                                                                             \
--- a/hotspot/src/share/vm/runtime/javaCalls.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/runtime/javaCalls.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -37,11 +37,6 @@
   guarantee(!thread->is_Compiler_thread(), "cannot make java calls from the compiler");
   _result   = result;
 
-  // Make sure that that the value of the  higest_lock is at least the same as the current stackpointer,
-  // since, the Java code is highly likely to use locks.
-  // Use '(address)this' to guarantee that highest_lock address is conservative and inside our thread
-  thread->update_highest_lock((address)this);
-
   // Allocate handle block for Java code. This must be done before we change thread_state to _thread_in_Java_or_stub,
   // since it can potentially block.
   JNIHandleBlock* new_handles = JNIHandleBlock::allocate_block(thread);
--- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1471,9 +1471,73 @@
   return generate_class_cast_message(objName, targetKlass->external_name());
 }
 
+char* SharedRuntime::generate_wrong_method_type_message(JavaThread* thread,
+                                                        oopDesc* required,
+                                                        oopDesc* actual) {
+  assert(EnableMethodHandles, "");
+  oop singleKlass = wrong_method_type_is_for_single_argument(thread, required);
+  if (singleKlass != NULL) {
+    const char* objName = "argument or return value";
+    if (actual != NULL) {
+      // be flexible about the junk passed in:
+      klassOop ak = (actual->is_klass()
+                     ? (klassOop)actual
+                     : actual->klass());
+      objName = Klass::cast(ak)->external_name();
+    }
+    Klass* targetKlass = Klass::cast(required->is_klass()
+                                     ? (klassOop)required
+                                     : java_lang_Class::as_klassOop(required));
+    return generate_class_cast_message(objName, targetKlass->external_name());
+  } else {
+    // %%% need to get the MethodType string, without messing around too much
+    // Get a signature from the invoke instruction
+    const char* mhName = "method handle";
+    const char* targetType = "the required signature";
+    vframeStream vfst(thread, true);
+    if (!vfst.at_end()) {
+      Bytecode_invoke* call = Bytecode_invoke_at(vfst.method(), vfst.bci());
+      methodHandle target;
+      {
+        EXCEPTION_MARK;
+        target = call->static_target(THREAD);
+        if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; }
+      }
+      if (target.not_null()
+          && target->is_method_handle_invoke()
+          && required == target->method_handle_type()) {
+        targetType = target->signature()->as_C_string();
+      }
+    }
+    klassOop kignore; int fignore;
+    methodOop actual_method = MethodHandles::decode_method(actual,
+                                                          kignore, fignore);
+    if (actual_method != NULL) {
+      if (actual_method->name() == vmSymbols::invoke_name())
+        mhName = "$";
+      else
+        mhName = actual_method->signature()->as_C_string();
+      if (mhName[0] == '$')
+        mhName = actual_method->signature()->as_C_string();
+    }
+    return generate_class_cast_message(mhName, targetType,
+                                       " cannot be called as ");
+  }
+}
+
+oop SharedRuntime::wrong_method_type_is_for_single_argument(JavaThread* thr,
+                                                            oopDesc* required) {
+  if (required == NULL)  return NULL;
+  if (required->klass() == SystemDictionary::class_klass())
+    return required;
+  if (required->is_klass())
+    return Klass::cast(klassOop(required))->java_mirror();
+  return NULL;
+}
+
+
 char* SharedRuntime::generate_class_cast_message(
-    const char* objName, const char* targetKlassName) {
-  const char* desc = " cannot be cast to ";
+    const char* objName, const char* targetKlassName, const char* desc) {
   size_t msglen = strlen(objName) + strlen(desc) + strlen(targetKlassName) + 1;
 
   char* message = NEW_RESOURCE_ARRAY(char, msglen);
--- a/hotspot/src/share/vm/runtime/sharedRuntime.hpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/runtime/sharedRuntime.hpp	Wed Jul 05 16:51:35 2017 +0200
@@ -212,10 +212,32 @@
   static char* generate_class_cast_message(JavaThread* thr, const char* name);
 
   /**
+   * Fill in the message for a WrongMethodTypeException
+   *
+   * @param thr the current thread
+   * @param mtype (optional) expected method type (or argument class)
+   * @param mhandle (optional) actual method handle (or argument)
+   * @return the dynamically allocated exception message
+   *
+   * BCP for the frame on top of the stack must refer to an
+   * 'invokevirtual' op for a method handle, or an 'invokedyamic' op.
+   * The caller (or one of its callers) must use a ResourceMark
+   * in order to correctly free the result.
+   */
+  static char* generate_wrong_method_type_message(JavaThread* thr,
+                                                  oopDesc* mtype = NULL,
+                                                  oopDesc* mhandle = NULL);
+
+  /** Return non-null if the mtype is a klass or Class, not a MethodType. */
+  static oop wrong_method_type_is_for_single_argument(JavaThread* thr,
+                                                      oopDesc* mtype);
+
+  /**
    * Fill in the "X cannot be cast to a Y" message for ClassCastException
    *
    * @param name the name of the class of the object attempted to be cast
    * @param klass the name of the target klass attempt
+   * @param gripe the specific kind of problem being reported
    * @return the dynamically allocated exception message (must be freed
    * by the caller using a resource mark)
    *
@@ -224,7 +246,8 @@
    * The caller (or one of it's callers) must use a ResourceMark
    * in order to correctly free the result.
    */
-  static char* generate_class_cast_message(const char* name, const char* klass);
+  static char* generate_class_cast_message(const char* name, const char* klass,
+                                           const char* gripe = " cannot be cast to ");
 
   // Resolves a call site- may patch in the destination of the call into the
   // compiled code.
--- a/hotspot/src/share/vm/runtime/synchronizer.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/runtime/synchronizer.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1117,10 +1117,10 @@
 
           // Optimization: if the mark->locker stack address is associated
           // with this thread we could simply set m->_owner = Self and
-          // m->OwnerIsThread = 1.  Note that a thread can inflate an object
+          // m->OwnerIsThread = 1. Note that a thread can inflate an object
           // that it has stack-locked -- as might happen in wait() -- directly
           // with CAS.  That is, we can avoid the xchg-NULL .... ST idiom.
-          m->set_owner (mark->locker());
+          m->set_owner(mark->locker());
           m->set_object(object);
           // TODO-FIXME: assert BasicLock->dhw != 0.
 
@@ -1214,10 +1214,9 @@
       BiasedLocking::revoke_at_safepoint(obj);
     }
     assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
-  }
-
-  THREAD->update_highest_lock((address)lock);
-  slow_enter (obj, lock, THREAD) ;
+ }
+
+ slow_enter (obj, lock, THREAD) ;
 }
 
 void ObjectSynchronizer::fast_exit(oop object, BasicLock* lock, TRAPS) {
--- a/hotspot/src/share/vm/runtime/thread.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/runtime/thread.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -128,7 +128,6 @@
   debug_only(_allow_allocation_count = 0;)
   NOT_PRODUCT(_allow_safepoint_count = 0;)
   CHECK_UNHANDLED_OOPS_ONLY(_gc_locked_out_count = 0;)
-  _highest_lock = NULL;
   _jvmti_env_iteration_count = 0;
   _vm_operation_started_count = 0;
   _vm_operation_completed_count = 0;
@@ -790,19 +789,6 @@
 }
 #endif
 
-bool Thread::lock_is_in_stack(address adr) const {
-  assert(Thread::current() == this, "lock_is_in_stack can only be called from current thread");
-  // High limit: highest_lock is set during thread execution
-  // Low  limit: address of the local variable dummy, rounded to 4K boundary.
-  // (The rounding helps finding threads in unsafe mode, even if the particular stack
-  // frame has been popped already.  Correct as long as stacks are at least 4K long and aligned.)
-  address end = os::current_stack_pointer();
-  if (_highest_lock >= adr && adr >= end) return true;
-
-  return false;
-}
-
-
 bool Thread::is_in_stack(address adr) const {
   assert(Thread::current() == this, "is_in_stack can only be called from current thread");
   address end = os::current_stack_pointer();
@@ -818,8 +804,7 @@
 // should be revisited, and they should be removed if possible.
 
 bool Thread::is_lock_owned(address adr) const {
-  if (lock_is_in_stack(adr) ) return true;
-  return false;
+  return (_stack_base >= adr && adr >= (_stack_base - _stack_size));
 }
 
 bool Thread::set_as_starting_thread() {
@@ -1664,7 +1649,7 @@
 }
 
 bool JavaThread::is_lock_owned(address adr) const {
-  if (lock_is_in_stack(adr)) return true;
+  if (Thread::is_lock_owned(adr)) return true;
 
   for (MonitorChunk* chunk = monitor_chunks(); chunk != NULL; chunk = chunk->next()) {
     if (chunk->contains(adr)) return true;
@@ -2443,7 +2428,7 @@
   if (thread_oop != NULL && java_lang_Thread::is_daemon(thread_oop))  st->print("daemon ");
   Thread::print_on(st);
   // print guess for valid stack memory region (assume 4K pages); helps lock debugging
-  st->print_cr("[" INTPTR_FORMAT ".." INTPTR_FORMAT "]", (intptr_t)last_Java_sp() & ~right_n_bits(12), highest_lock());
+  st->print_cr("[" INTPTR_FORMAT "]", (intptr_t)last_Java_sp() & ~right_n_bits(12));
   if (thread_oop != NULL && JDK_Version::is_gte_jdk15x_version()) {
     st->print_cr("   java.lang.Thread.State: %s", java_lang_Thread::thread_status_name(thread_oop));
   }
@@ -3733,25 +3718,13 @@
   // heavyweight monitors, then the owner is the stack address of the
   // Lock Word in the owning Java thread's stack.
   //
-  // We can't use Thread::is_lock_owned() or Thread::lock_is_in_stack() because
-  // those routines rely on the "current" stack pointer. That would be our
-  // stack pointer which is not relevant to the question. Instead we use the
-  // highest lock ever entered by the thread and find the thread that is
-  // higher than and closest to our target stack address.
-  //
-  address    least_diff = 0;
-  bool       least_diff_initialized = false;
   JavaThread* the_owner = NULL;
   {
     MutexLockerEx ml(doLock ? Threads_lock : NULL);
     ALL_JAVA_THREADS(q) {
-      address addr = q->highest_lock();
-      if (addr == NULL || addr < owner) continue;  // thread has entered no monitors or is too low
-      address diff = (address)(addr - owner);
-      if (!least_diff_initialized || diff < least_diff) {
-        least_diff_initialized = true;
-        least_diff = diff;
+      if (q->is_lock_owned(owner)) {
         the_owner = q;
+        break;
       }
     }
   }
--- a/hotspot/src/share/vm/runtime/thread.hpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/runtime/thread.hpp	Wed Jul 05 16:51:35 2017 +0200
@@ -200,14 +200,6 @@
   friend class ThreadLocalStorage;
   friend class GC_locker;
 
-  // In order for all threads to be able to use fast locking, we need to know the highest stack
-  // address of where a lock is on the stack (stacks normally grow towards lower addresses). This
-  // variable is initially set to NULL, indicating no locks are used by the thread. During the thread's
-  // execution, it will be set whenever locking can happen, i.e., when we call out to Java code or use
-  // an ObjectLocker. The value is never decreased, hence, it will over the lifetime of a thread
-  // approximate the real stackbase.
-  address _highest_lock;                         // Highest stack address where a JavaLock exist
-
   ThreadLocalAllocBuffer _tlab;                  // Thread-local eden
 
   int   _vm_operation_started_count;             // VM_Operation support
@@ -400,18 +392,14 @@
   // Sweeper support
   void nmethods_do();
 
-  // Fast-locking support
-  address highest_lock() const                   { return _highest_lock; }
-  void update_highest_lock(address base)         { if (base > _highest_lock) _highest_lock = base; }
-
   // Tells if adr belong to this thread. This is used
   // for checking if a lock is owned by the running thread.
-  // Warning: the method can only be used on the running thread
-  // Fast lock support uses these methods
-  virtual bool lock_is_in_stack(address adr) const;
+
+  // Used by fast lock support
   virtual bool is_lock_owned(address adr) const;
 
   // Check if address is in the stack of the thread (not just for locks).
+  // Warning: the method can only be used on the running thread
   bool is_in_stack(address adr) const;
 
   // Sets this thread as starting thread. Returns failure if thread
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp	Wed Jul 05 16:51:35 2017 +0200
@@ -656,7 +656,6 @@
                                                                                                                                      \
    volatile_nonstatic_field(Thread,            _suspend_flags,                                uint32_t)                              \
   nonstatic_field(Thread,                      _active_handles,                               JNIHandleBlock*)                       \
-  nonstatic_field(Thread,                      _highest_lock,                                 address)                               \
   nonstatic_field(Thread,                      _tlab,                                         ThreadLocalAllocBuffer)                \
   nonstatic_field(Thread,                      _current_pending_monitor,                      ObjectMonitor*)                        \
   nonstatic_field(Thread,                      _current_pending_monitor_is_from_java,         bool)                                  \
--- a/hotspot/src/share/vm/utilities/accessFlags.hpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/utilities/accessFlags.hpp	Wed Jul 05 16:51:35 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright 1997-2007 Sun Microsystems, Inc.  All Rights Reserved.
+ * Copyright 1997-2009 Sun Microsystems, Inc.  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
@@ -47,6 +47,8 @@
   JVM_ACC_IS_OLD                  = 0x00010000,     // RedefineClasses() has replaced this method
   JVM_ACC_IS_OBSOLETE             = 0x00020000,     // RedefineClasses() has made method obsolete
   JVM_ACC_IS_PREFIXED_NATIVE      = 0x00040000,     // JVMTI has prefixed this native method
+  JVM_MH_INVOKE_BITS           // = 0x10001100      // MethodHandle.invoke quasi-native
+                                  = (JVM_ACC_NATIVE | JVM_ACC_SYNTHETIC | JVM_ACC_MONITOR_MATCH),
 
   // klassOop flags
   JVM_ACC_HAS_MIRANDA_METHODS     = 0x10000000,     // True if this class has miranda methods in it's vtable
@@ -72,6 +74,7 @@
 
                                                     // flags accepted by set_field_flags()
   JVM_ACC_FIELD_FLAGS                = 0x00008000 | JVM_ACC_WRITTEN_FLAGS
+
 };
 
 
@@ -114,6 +117,15 @@
   bool is_obsolete             () const { return (_flags & JVM_ACC_IS_OBSOLETE            ) != 0; }
   bool is_prefixed_native      () const { return (_flags & JVM_ACC_IS_PREFIXED_NATIVE     ) != 0; }
 
+  // JSR 292:  A method of the form MethodHandle.invoke(A...)R method is
+  // neither bytecoded nor a JNI native, but rather a fast call through
+  // a lightweight method handle object.  Because it is not bytecoded,
+  // it has the native bit set, but the monitor-match bit is also set
+  // to distinguish it from a JNI native (which never has the match bit set).
+  // The synthetic bit is also present, because such a method is never
+  // explicitly defined in Java code.
+  bool is_method_handle_invoke () const { return (_flags & JVM_MH_INVOKE_BITS) == JVM_MH_INVOKE_BITS; }
+
   // klassOop flags
   bool has_miranda_methods     () const { return (_flags & JVM_ACC_HAS_MIRANDA_METHODS    ) != 0; }
   bool has_vanilla_constructor () const { return (_flags & JVM_ACC_HAS_VANILLA_CONSTRUCTOR) != 0; }
@@ -199,6 +211,14 @@
   jshort as_short()                    { return (jshort)_flags; }
   jint   as_int()                      { return _flags; }
 
+  inline friend AccessFlags accessFlags_from(jint flags);
+
   // Printing/debugging
   void print_on(outputStream* st) const PRODUCT_RETURN;
 };
+
+inline AccessFlags accessFlags_from(jint flags) {
+  AccessFlags af;
+  af._flags = flags;
+  return af;
+}
--- a/hotspot/src/share/vm/utilities/exceptions.hpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/utilities/exceptions.hpp	Wed Jul 05 16:51:35 2017 +0200
@@ -237,6 +237,9 @@
 #define THROW_ARG_0(name, signature, arg)   THROW_ARG_(name, signature, arg, 0)
 #define THROW_MSG_CAUSE_0(name, message, cause) THROW_MSG_CAUSE_(name, message, cause, 0)
 
+#define THROW_NULL(name)                    THROW_(name, NULL)
+#define THROW_MSG_NULL(name, message)       THROW_MSG_(name, message, NULL)
+
 // The CATCH macro checks that no exception has been thrown by a function; it is used at
 // call sites about which is statically known that the callee cannot throw an exception
 // even though it is declared with TRAPS.
--- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp	Wed Jul 05 16:51:35 2017 +0200
@@ -408,6 +408,15 @@
   return T_BOOLEAN <= t && t <= T_LONG;
 }
 
+inline bool is_subword_type(BasicType t) {
+  // these guys are processed exactly like T_INT in calling sequences:
+  return (t == T_BOOLEAN || t == T_CHAR || t == T_BYTE || t == T_SHORT);
+}
+
+inline bool is_signed_subword_type(BasicType t) {
+  return (t == T_BYTE || t == T_SHORT);
+}
+
 // Convert a char from a classfile signature to a BasicType
 inline BasicType char2type(char c) {
   switch( c ) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6539464/Test.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**
+ * @test
+ * @bug 6539464
+ * @summary Math.log() produces inconsistent results between successive runs.
+ *
+ * @run main/othervm -Xcomp -XX:CompileOnly=Test.main Test
+ */
+
+public class Test {
+    static double log_value = 17197;
+    static double log_result = Math.log(log_value);
+
+    public static void main(String[] args) throws Exception {
+        for (int i = 0; i < 1000000; i++) {
+            double log_result2 = Math.log(log_value);
+            if (log_result2 != log_result) {
+                throw new InternalError("Math.log produces inconsistent results: " + log_result2 + " != " + log_result);
+            }
+        }
+    }
+}
--- a/hotspot/test/compiler/6636138/Test1.java	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/test/compiler/6636138/Test1.java	Wed Jul 05 16:51:35 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 6636138
  * @summary SuperWord::co_locate_pack(Node_List* p) generates memory graph that leads to memory order violation.
  *
- * @run main/othervm -server -Xbatch -XX:CompileOnly=Test1.init -XX:+UseSuperword Test1
+ * @run main/othervm -server -Xbatch -XX:CompileOnly=Test1.init Test1
  */
 
 class Test1 {
--- a/hotspot/test/compiler/6636138/Test2.java	Wed Jul 05 16:51:11 2017 +0200
+++ b/hotspot/test/compiler/6636138/Test2.java	Wed Jul 05 16:51:35 2017 +0200
@@ -26,7 +26,7 @@
  * @bug 6636138
  * @summary SuperWord::co_locate_pack(Node_List* p) generates memory graph that leads to memory order violation.
  *
- * @run main/othervm -server -Xbatch -XX:CompileOnly=Test2.shift -XX:+UseSuperword Test2
+ * @run main/othervm -server -Xbatch -XX:CompileOnly=Test2.shift Test2
  */
 
 class Test2 {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6711117/Test.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,849 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+/*
+ * @test
+ * @bug 6711117
+ * @summary Assertion in 64bit server vm (flat != TypePtr::BOTTOM,"cannot alias-analyze an untyped ptr")
+ * @run main/othervm -Xcomp -XX:+IgnoreUnrecognizedVMOptions -XX:+AggressiveOpts -XX:+UseCompressedOops Test
+ */
+
+final class Test_Class_0 {
+    final static char var_1 = 'E';
+    short var_2 = 16213;
+    final static String var_3 = "jiiibmmsk";
+
+
+    public Test_Class_0()
+    {
+        var_2 ^= 'M';
+        final String var_18 = var_3;
+        var_2--;
+        var_2 |= (byte)('D' / (byte)var_2) - ((byte)1.6680514E38F << + ((byte)'O') & 7320241275829036032L);
+        func_2(((!false & false | false ? true : false) ? true : true | !true) ? var_2 : 834513107);
+        var_2 >>>= var_1;
+        "smiosoebk".codePointCount(true ^ (false ^ ! !false) ? (byte)- ((byte)430513598) : + ((byte)'_'), ~ (true ? (byte)']' : (byte)-2.8272547997066827E307));
+        var_2 -= true ? var_1 : var_1;
+        var_2 ^= var_1;
+        var_2 &= (var_2 |= ~ ((byte)(var_2 *= var_2)));
+        long var_19 = 0L;
+        short var_20 = var_2 += 'P';
+        while (var_19 < 1)
+        {
+            var_2 ^= true ? (byte)- +1.2219539475209E308 : (byte)1.2748408476894178E308;
+            var_19++;
+            var_2 = (byte)((1489358000 == (var_20 | 7816908224315289600L) ? var_1 : var_1) ^ var_19);
+            var_20--;
+        }
+        var_20 -= 'f';
+        var_20 <<= (((new Test_Class_0[(byte)var_20])[(byte)var_2]).var_2 *= false ? 'g' : 'x');
+    }
+
+
+
+
+    static float func_0()
+    {
+        ((new Test_Class_0[(byte)7.774490796987995E307])[(byte)'v']).var_2 <<= false ^ !false ? (short)'v' : "".codePointCount(594464985, 579036736);
+        ((new Test_Class_0[(byte)(((new Test_Class_0[(byte)1361657519])[(byte)2.3703713E38F]).var_2-- - (short)3.5589388134844986E307)])[((true ? !true : false) ^ (!false ? true : !true) ? !false : false) ? (byte)7.047289E37F : (byte)- ((byte)2.6620062118475144E307)]).var_2 *= 3273943364390983680L;
+        --((new Test_Class_0[false ? (byte)(short)1.4965069E36F : (byte)286322022])[(byte)- ((byte)2.742619E38F)]).var_2;
+        long var_4;
+        {
+            double var_5;
+        }
+        var_4 = (byte)1.3509231E38F;
+        ((new Test_Class_0[(byte)'_'])[('g' | 1427123046096105472L) < var_1 >> (byte)(int)(byte)7697616672011068416L ? (byte)var_1 : (byte)1251856579]).var_2--;
+        switch (--((new Test_Class_0[(byte)5.0656327E37F])[(byte)'e']).var_2 != ++((new Test_Class_0[(byte)(int)1.3728667270920175E308])[(byte)+ + -1.6338179407381788E308]).var_2 | !var_3.equalsIgnoreCase("iiwwwln") ? (false ? (byte)1.8291216E38F : (byte)4.778575546584698E307) : (byte)1048254181)
+        {
+            case 99:
+
+        }
+        {
+            byte var_6 = 13;
+        }
+        var_4 = --((new Test_Class_0[!var_3.endsWith("qaoioore") ^ false ? (byte)2.827362738392923E307 : (byte)~4890175967151316992L])[(byte)(short)var_1]).var_2;
+        ++((new Test_Class_0[(byte)(1.0075552E38F + (short)2083553541)])[(byte)(short)(byte)(short)1.6872205E38F]).var_2;
+        return ((new Test_Class_0[(byte)var_1])[(byte)+ +5760973323384750080L]).var_2 - (false ? (byte)'i' : (var_4 = (short)1.2458781351126844E308) + 2.131006E38F);
+    }
+
+    public static long func_1(String arg_0, Object arg_1, final long arg_2)
+    {
+        arg_0 = false ? arg_0 : "fgbrpgsq";
+        ((new Test_Class_0[(byte)- ((byte)']')])[false ? (byte)757239006 : (byte)1866002020]).var_2 ^= (short)(true ? (byte)(((new Test_Class_0[(byte)1416194866])[(byte)1.2309887362692395E308]).var_2 >>= (int)~ ~ ~arg_2) : (byte)5804970709284726784L);
+        final long var_7 = (long)(- + ((long)+ - + - -2.5396583E38F) - - +1.8770165E38F % 2472404173160781824L < --((new Test_Class_0[(byte)5.569360482341752E307])[(byte)(double)(byte)8131142397821553664L]).var_2 ^ true ? (false ? (byte)- -1.163275451591927E308 : (byte)var_1) : (false ? (byte)1843746036 : (byte)1.0209668642291047E308));
+        arg_0 = (arg_0 = arg_0.substring(699480935));
+        switch (((new Test_Class_0[(byte)(5415649243316856832L >> 861936806)])[true | true & !false ? (byte)(short)- -7.785169683394908E307 : (byte)+ ((byte)arg_2)]).var_2++)
+        {
+            case 42:
+
+            case 102:
+
+        }
+        arg_1 = (true || false ? false : true) ? (arg_0 = (arg_0 = "jbfaru")) : arg_0;
+        arg_1 = new byte[(byte)2.669957E38F];
+        boolean var_8 = ! ((false ? (short)1.4259420861834744E308 : (short)7.352115508157158E307) != 1.7635658130722812E308);
+        arg_1 = new Object[(byte)- ((byte)(short)1.8950693E38F)];
+        arg_0 = arg_0;
+        return (byte)1.4762239057269886E308 & 4923938844759802880L;
+    }
+
+    double[][] func_2(final int arg_0)
+    {
+        var_2 >>>= (var_2 >>= var_2++);
+        float var_9 = 0F;
+        var_2 %= var_2;
+        do
+        {
+            ++var_2;
+            var_9++;
+            var_2++;
+        } while (true && (var_9 < 1 && false));
+        double var_10 = 0;
+        final int var_11 = 11903395;
+        do
+        {
+            --var_2;
+            var_10++;
+            ++var_2;
+        } while ((false & true || false) && (var_10 < 2 && ~ ((byte)'[') == (byte)(1.1943192E38F % ('c' << var_1) % (byte)((var_2 |= var_2) + 591679039 / ~5932100696448264192L))));
+        String var_12 = "jkwnk";
+        var_12 = var_3;
+        var_12 = (var_12 = (var_12 = var_3));
+        var_12 = "qrhdwx";
+        var_12 = var_12;
+        short var_13 = (true && true) ^ true | ! (!true || 1646418779 <= (byte)var_1) ? var_2 : var_2;
+        return new double[(byte)var_1][true || false ^ !true ^ true ? (byte)arg_0 : (byte)var_10];
+    }
+
+    private final int func_3()
+    {
+        long var_14 = 's' * (~ ~6656240461354863616L * 3151744928387344384L) << ~ (((var_2 >>>= 6600935261424147456L) % 1798503219359364096L | - ~3832249967647077376L / - ((byte)~1529201870915276800L)) / var_2);
+        {
+            var_14 |= !false | (byte)1078230528 >= (byte)1.3972878565417081E308 | (true | !true & !true & !false) ? var_1 : '_';
+        }
+        long var_15 = 7589204885152164864L;
+        var_2 ^= (var_1 < (byte)'r' ? 475314139 : 'Z') <= 1943074698 ? 'h' : var_1;
+        return 'V' * (false ? (byte)5.498204E37F : (byte)1.0137001669765466E308);
+    }
+
+    protected static boolean func_4(boolean arg_0, byte arg_1, boolean arg_2)
+    {
+        arg_1++;
+        arg_1 &= (((((new Test_Class_0[arg_1][arg_1][arg_1])[arg_1])[arg_1])[arg_1]).var_2 |= arg_2 ? (short)~3038084056596854784L : (short)+ (arg_1 = arg_1));
+        arg_0 |= true;
+        arg_1 %= (arg_1 |= ((new Test_Class_0[arg_1])[arg_1]).var_2--);
+        if (false)
+        {
+            arg_0 |= arg_2;
+        }
+        else
+        {
+            ++(((new Test_Class_0[arg_1][arg_1][arg_1])[arg_1 += var_1])[(!arg_2 | (arg_0 &= false)) ^ (arg_0 | arg_0) ? arg_1 : (arg_1 <<= 3192041751921364992L)][arg_1 /= arg_1]).var_2;
+        }
+        arg_1 &= +(new byte[arg_1])[arg_1];
+        arg_1 <<= 3632133838014908416L;
+        byte[] var_16 = (new byte[arg_1][arg_1--])[arg_1];
+        long var_17;
+        arg_1 ^= ~ arg_1--;
+        arg_0 ^= (arg_2 ^= 1186877294 >= ((new Test_Class_0[arg_1][arg_1])[arg_1][arg_1]).var_2) & arg_2;
+        return var_3.startsWith(var_3);
+    }
+
+    public String toString()
+    {
+        String result =  "[\n";
+        result += "Test_Class_0.var_2 = "; result += Test.Printer.print(var_2);
+        result += "\n";
+        result += "Test_Class_0.var_1 = "; result += Test.Printer.print(var_1);
+        result += "\n";
+        result += "Test_Class_0.var_3 = "; result += Test.Printer.print(var_3);
+        result += "";
+        result += "\n]";
+        return result;
+    }
+}
+
+
+class Test_Class_1 {
+    static int var_21 = 670918363;
+    final float var_22 = 8.650798E37F;
+    static int var_23 = 1774228457;
+    final int var_24 = 1282736974;
+    final byte var_25 = !false & false | true ? (byte)7.677121016144275E307 : (byte)'r';
+    static long var_26 = 2939310115459338240L;
+    final long var_27 = var_25 - 7555453173456381952L;
+    double var_28;
+    static String var_29;
+
+
+    public Test_Class_1()
+    {
+        var_29 = Test_Class_0.var_3;
+        ((false ? false || ! !true : ! (! !true & !true)) ? new Test_Class_0() : new Test_Class_0()).var_2++;
+        var_23 -= 2.963694E38F;
+    }
+
+
+
+
+    public String toString()
+    {
+        String result =  "[\n";
+        result += "Test_Class_1.var_21 = "; result += Test.Printer.print(var_21);
+        result += "\n";
+        result += "Test_Class_1.var_23 = "; result += Test.Printer.print(var_23);
+        result += "\n";
+        result += "Test_Class_1.var_24 = "; result += Test.Printer.print(var_24);
+        result += "\n";
+        result += "Test_Class_1.var_26 = "; result += Test.Printer.print(var_26);
+        result += "\n";
+        result += "Test_Class_1.var_27 = "; result += Test.Printer.print(var_27);
+        result += "\n";
+        result += "Test_Class_1.var_28 = "; result += Test.Printer.print(var_28);
+        result += "\n";
+        result += "Test_Class_1.var_22 = "; result += Test.Printer.print(var_22);
+        result += "\n";
+        result += "Test_Class_1.var_25 = "; result += Test.Printer.print(var_25);
+        result += "\n";
+        result += "Test_Class_1.var_29 = "; result += Test.Printer.print(var_29);
+        result += "";
+        result += "\n]";
+        return result;
+    }
+}
+
+
+class Test_Class_2 {
+    double var_30;
+    static byte var_31;
+    static char var_32;
+    float var_33;
+    double var_34 = !false & (true ? true : ! !true && false) ? 'q' - 4789231433793305600L - (var_33 = -1.0677024E38F) : 2.65473560313378E307;
+    final double var_35 = ~Test_Class_1.var_26 == 5.145660681364723E307 | false ? 1.4134775E38F : 1.77223030708671E308;
+    final int var_36 = Test_Class_1.var_23 |= Test_Class_1.var_21++;
+
+
+    public Test_Class_2()
+    {
+        Test_Class_0.var_3.replace(Test_Class_0.var_1, 'Q');
+        var_32 = (var_32 = (var_32 = '_'));
+        Test_Class_1.var_26 |= Test_Class_0.var_1;
+        Test_Class_1.var_29 = (Test_Class_1.var_29 = Test_Class_0.var_3);
+        var_32 = Test_Class_0.var_1;
+        var_33 = ((new Test_Class_0[(byte)851412948463452160L])[var_31 = new Test_Class_1().var_25]).var_2;
+        var_33 = ! (((!false | false) & (false || !true) ? false : ! !false) | false) ? new Test_Class_1().var_25 : (var_31 = new Test_Class_1().var_25);
+        float var_38 = 0F;
+        var_34 /= 5336005797857974272L;
+        for ("ccnyq".endsWith((new String[(byte)Test_Class_1.var_26])[var_31 = (var_31 = (var_31 = (byte)4.7927775E37F))]); var_38 < 2; var_32 = '^' <= Test_Class_0.var_1 ^ true ? (var_32 = Test_Class_0.var_1) : (var_32 = 'V'))
+        {
+            var_32 = true ? 'a' : (var_32 = Test_Class_0.var_1);
+            var_38++;
+            var_33 = new Test_Class_1().var_24;
+            var_32 = ! (true || true ? !false : (short)3.2844383E37F < 2.1400662E38F) ? (char)1.2691096999143248E308 : (! !false ^ true ? 's' : 'q');
+        }
+        var_32 = 'B';
+        {
+            var_32 = Test_Class_0.var_1;
+        }
+        var_32 = Test_Class_0.var_1;
+        Test_Class_1.var_29 = "ov";
+        Test_Class_1.var_29 = "smtolghw";
+    }
+
+
+
+
+
+    protected final static String func_0(final long[][] arg_0, byte arg_1, char arg_2)
+    {
+        arg_1 <<= (((new Test_Class_2[arg_1])[arg_1]).var_34 > new Test_Class_0().var_2 | true ? new Test_Class_0() : (new Test_Class_0[arg_1][arg_1])[new Test_Class_1().var_25][new Test_Class_1().var_25]).var_2;
+        Test_Class_1.var_26 >>>= (!true | !true | (new boolean[arg_1])[arg_1] || true ? (new Test_Class_1[arg_1])[arg_1] : new Test_Class_1()).var_27;
+        float var_37 = 0F;
+        arg_2 >>= ((new Test_Class_1[arg_1][arg_1])[arg_1][arg_1]).var_25;
+        do
+        {
+            ((new Test_Class_2[arg_1 /= 2055714081])[arg_1]).var_34 = 'l';
+            var_37++;
+            Test_Class_1.var_29 = Test_Class_0.var_3;
+        } while ((false ? false : false) && var_37 < 7);
+        Test_Class_1.var_29 = Test_Class_0.var_3 + "";
+        ((new Test_Class_2[new Test_Class_1().var_25][new Test_Class_1().var_25])[new Test_Class_1().var_25][arg_1 |= new Test_Class_0().var_2]).var_34 += Test_Class_0.var_1;
+        return "esb";
+    }
+
+    public String toString()
+    {
+        String result =  "[\n";
+        result += "Test_Class_2.var_32 = "; result += Test.Printer.print(var_32);
+        result += "\n";
+        result += "Test_Class_2.var_36 = "; result += Test.Printer.print(var_36);
+        result += "\n";
+        result += "Test_Class_2.var_30 = "; result += Test.Printer.print(var_30);
+        result += "\n";
+        result += "Test_Class_2.var_34 = "; result += Test.Printer.print(var_34);
+        result += "\n";
+        result += "Test_Class_2.var_35 = "; result += Test.Printer.print(var_35);
+        result += "\n";
+        result += "Test_Class_2.var_33 = "; result += Test.Printer.print(var_33);
+        result += "\n";
+        result += "Test_Class_2.var_31 = "; result += Test.Printer.print(var_31);
+        result += "";
+        result += "\n]";
+        return result;
+    }
+}
+
+
+final class Test_Class_3 extends Test_Class_2 {
+    byte var_39 = 23;
+    static boolean var_40 = false;
+
+
+    public Test_Class_3()
+    {
+        if (true)
+        {
+            Test_Class_1.var_21 |= new Test_Class_1().var_27;
+        }
+        else
+        {
+            final float var_46 = 7.9266674E37F;
+            ++Test_Class_1.var_26;
+        }
+        {
+            Test_Class_1.var_23++;
+        }
+        var_30 = ((new Test_Class_1[var_39][var_39])[var_39][var_39]).var_25;
+        if (var_40 &= (var_40 |= (var_40 |= var_40)))
+        {
+            Test_Class_0.var_3.indexOf(Test_Class_1.var_29 = "xfgyblg", 'X' >>> ((Test_Class_1)(new Object[var_39])[((new Test_Class_1[var_39])[var_39]).var_25]).var_27);
+        }
+        else
+        {
+            var_40 &= var_40 && var_40;
+        }
+        ((Test_Class_2)(((new boolean[var_39])[var_39++] ? (var_40 &= var_40) : (var_40 &= false)) ? (new Test_Class_2[var_39][var_39])[var_39][var_39] : (new Object[var_39][var_39])[var_39][var_39])).var_33 = (var_40 ? new Test_Class_1() : new Test_Class_1()).var_25;
+        switch (var_39)
+        {
+            case 24:
+
+        }
+        var_39 += (((var_40 ^= true) ? new Test_Class_0() : new Test_Class_0()).var_2 ^= var_40 & (var_40 | false) ? var_39-- : var_36);
+        new Test_Class_0().var_2 %= (new Test_Class_0().var_2 += (var_39 ^= Test_Class_1.var_26));
+    }
+
+
+
+
+    private static String func_0()
+    {
+        --Test_Class_1.var_26;
+        {
+            Test_Class_1.var_29 = var_40 ? Test_Class_0.var_3 : "rahqjhqf";
+        }
+        if (var_40 ^= var_40)
+        {
+            Test_Class_1.var_26 >>= (Test_Class_2.var_32 = Test_Class_0.var_1) / new Test_Class_0().var_2;
+        }
+        else
+        {
+            ++Test_Class_1.var_21;
+        }
+        ++Test_Class_1.var_26;
+        int var_41 = 0;
+        ++Test_Class_1.var_26;
+        do
+        {
+            var_40 = (var_40 = true);
+            var_41++;
+            Test_Class_0 var_42 = new Test_Class_0();
+        } while (var_41 < 1);
+        Test_Class_1.var_29 = "f";
+        Test_Class_1 var_43;
+        var_43 = (var_43 = new Test_Class_1());
+        Test_Class_2.var_32 = 'V';
+        long var_44 = 0L;
+        Test_Class_1.var_23--;
+        while (var_40 && (var_44 < 1 && var_40))
+        {
+            Test_Class_1.var_29 = "bsgewkmk";
+            var_44++;
+            Test_Class_1.var_29 = "ktegattny";
+            var_40 &= var_40 ^ (var_40 |= (short)4.4487427E37F < 'n') & true;
+        }
+        Test_Class_1.var_23 %= (((var_40 |= true & (var_40 &= var_40)) ^ true ? new Test_Class_0() : new Test_Class_0()).var_2 -= 1.6638270827800162E308);
+        float var_45;
+        var_32 = (Test_Class_2.var_32 = Test_Class_0.var_1);
+        return false ? "fluk" : "wt";
+    }
+
+    public String toString()
+    {
+        String result =  "[\n";
+        result += "Test_Class_3.var_32 = "; result += Test.Printer.print(var_32);
+        result += "\n";
+        result += "Test_Class_3.var_36 = "; result += Test.Printer.print(var_36);
+        result += "\n";
+        result += "Test_Class_3.var_30 = "; result += Test.Printer.print(var_30);
+        result += "\n";
+        result += "Test_Class_3.var_34 = "; result += Test.Printer.print(var_34);
+        result += "\n";
+        result += "Test_Class_3.var_35 = "; result += Test.Printer.print(var_35);
+        result += "\n";
+        result += "Test_Class_3.var_33 = "; result += Test.Printer.print(var_33);
+        result += "\n";
+        result += "Test_Class_3.var_31 = "; result += Test.Printer.print(var_31);
+        result += "\n";
+        result += "Test_Class_3.var_39 = "; result += Test.Printer.print(var_39);
+        result += "\n";
+        result += "Test_Class_3.var_40 = "; result += Test.Printer.print(var_40);
+        result += "";
+        result += "\n]";
+        return result;
+    }
+}
+
+
+class Test_Class_4 {
+    final float var_47 = 1.9043434E38F;
+    final byte var_48 = 32;
+    final float var_49 = 2.8176504E38F;
+    final char var_50 = 'r';
+    final String var_51 = "uwgmnjpg";
+    static int var_52;
+    short[] var_53;
+    Test_Class_1 var_54;
+
+
+    public Test_Class_4()
+    {
+        final float var_55 = (3.1554042E38F == var_50 ^ (Test_Class_3.var_40 |= true) ? (Test_Class_3.var_40 ^= Test_Class_3.var_40) ^ true : Test_Class_3.var_40) ? new Test_Class_0().var_2 : 2.965321E38F;
+        new Test_Class_0().var_2 = (new Test_Class_0().var_2 >>= +new Test_Class_1().var_25);
+        ((Test_Class_1.var_29 = (Test_Class_1.var_29 = (Test_Class_1.var_29 = "l"))) + "").equalsIgnoreCase(Test_Class_1.var_29 = "garnio");
+        double var_56 = 0;
+        Test_Class_1.var_29 = var_51;
+        while (var_56 < 1)
+        {
+            ((Test_Class_3)(Test_Class_2)(new Object[var_48])[var_48]).var_33 = ++Test_Class_1.var_26;
+            var_56++;
+            Test_Class_1.var_29 = (Test_Class_1.var_29 = "fvyjrih");
+            float[] var_57;
+        }
+        {
+            ((new Test_Class_2[var_48])[((new Test_Class_3[var_48][var_48])[var_48][var_48]).var_39]).var_34 *= 2.2119221943262553E307;
+            Test_Class_2.var_32 = true ? 'q' : 't';
+            ((new Test_Class_3[--((Test_Class_3)new Test_Class_2()).var_39])[var_48]).var_33 = new Test_Class_0().var_2;
+            int var_58 = 'i' >> (var_48 << Test_Class_0.var_1);
+        }
+        Test_Class_3.var_40 &= true && var_51.equalsIgnoreCase(var_51) || new Test_Class_0().var_2 < --((new Test_Class_3[var_48])[var_48]).var_39;
+        ((Test_Class_3)(Test_Class_2)(new Object[var_48][var_48])[var_48][var_48]).var_34 += Test_Class_1.var_26--;
+        var_54 = new Test_Class_1();
+        Test_Class_3.var_40 |= (long)(!true ^ var_47 > ((Test_Class_2)(new Object[var_48])[var_48]).var_34 ? (Test_Class_2.var_31 = (Test_Class_3.var_31 = (Test_Class_3.var_31 = var_48))) : (var_54 = new Test_Class_1()).var_25) <= var_48;
+        (Test_Class_3.var_40 ? (true ? new Test_Class_0() : new Test_Class_0()) : new Test_Class_0()).var_2 &= var_48;
+        (Test_Class_3.var_40 ? (Test_Class_3)new Test_Class_2() : (new Test_Class_3[var_48][var_48])[var_48][var_48]).var_34 += Test_Class_1.var_21;
+        Test_Class_3 var_59;
+        Test_Class_2.var_32 = 'H';
+        --Test_Class_1.var_26;
+    }
+
+
+
+
+
+    public String toString()
+    {
+        String result =  "[\n";
+        result += "Test_Class_4.var_50 = "; result += Test.Printer.print(var_50);
+        result += "\n";
+        result += "Test_Class_4.var_52 = "; result += Test.Printer.print(var_52);
+        result += "\n";
+        result += "Test_Class_4.var_53 = "; result += Test.Printer.print(var_53);
+        result += "\n";
+        result += "Test_Class_4.var_47 = "; result += Test.Printer.print(var_47);
+        result += "\n";
+        result += "Test_Class_4.var_49 = "; result += Test.Printer.print(var_49);
+        result += "\n";
+        result += "Test_Class_4.var_48 = "; result += Test.Printer.print(var_48);
+        result += "\n";
+        result += "Test_Class_4.var_51 = "; result += Test.Printer.print(var_51);
+        result += "\n";
+        result += "Test_Class_4.var_54 = "; result += Test.Printer.print(var_54);
+        result += "";
+        result += "\n]";
+        return result;
+    }
+}
+
+
+class Test_Class_5 extends Test_Class_4 {
+    char var_60 = '_';
+    final byte var_61 = 101;
+
+
+    public Test_Class_5()
+    {
+        Test_Class_0.var_3.indexOf(Test_Class_1.var_21, (Test_Class_3.var_40 |= Test_Class_3.var_40) ? new Test_Class_1().var_24 : 'i');
+    }
+
+
+
+
+    final char func_0(Test_Class_1 arg_0, final Test_Class_1 arg_1)
+    {
+        long var_62 = 0L;
+        "aoal".toLowerCase();
+        for (byte var_63 = arg_0.var_25; var_62 < 1 && "ji".startsWith("dikrs".endsWith("va") ? (Test_Class_1.var_29 = "mvp") : Test_Class_0.var_3, Test_Class_1.var_23); ((Test_Class_2)(new Object[arg_0.var_25])[var_63]).var_34 -= new Test_Class_2().var_36)
+        {
+            ((Test_Class_3.var_40 ? false : Test_Class_3.var_40) ? (Test_Class_0)(new Object[arg_1.var_25][arg_1.var_25])[arg_1.var_25][var_63] : (Test_Class_0)(new Object[var_48][var_48])[var_63][var_63]).var_2 += true ^ Test_Class_3.var_40 ^ (((new Test_Class_3[var_63][var_63])[var_63][var_61]).var_35 != 2.1423512E38F | ! !false) ? var_49 + ~var_48 : 3.1549515E38F;
+            var_62++;
+            (!false & ((Test_Class_3.var_40 |= (Test_Class_3.var_40 ^= true)) & true) ? (Test_Class_2)(new Object[var_63])[var_63] : (new Test_Class_2[var_63][var_61])[var_63][arg_0.var_25]).var_33 = (var_60 *= (var_60 *= ((new Test_Class_3[var_48][var_61])[var_61][var_63]).var_35));
+            float var_64;
+        }
+        Test_Class_1.var_29 = "xyenjknu";
+        Test_Class_3.var_40 ^= (Test_Class_3.var_40 = !false & true) ? Test_Class_3.var_40 : Test_Class_3.var_40;
+        ((new Test_Class_2[var_48][arg_1.var_25])[arg_0.var_25][var_48]).var_33 = var_61;
+        Test_Class_1.var_21 |= --(((new Test_Class_3[Test_Class_3.var_31 = arg_0.var_25][var_61])[var_61])[(((new Test_Class_3[var_48][var_61])[var_48])[((Test_Class_3)(new Test_Class_2[var_48][arg_0.var_25])[var_61][var_48]).var_39]).var_39 >>>= var_60]).var_39;
+        var_51.compareToIgnoreCase("hgcaybk");
+        Test_Class_0 var_65 = (Test_Class_1.var_29 = "t").codePointBefore(1602805584) >= (float)((new Test_Class_3[var_48][var_61])[var_48][Test_Class_2.var_31 = arg_1.var_25]).var_39 - 7.256386549028811E307 ? new Test_Class_0() : ((new Test_Class_0[arg_0.var_25][var_48][var_48])[arg_0.var_25])[arg_0.var_25][Test_Class_2.var_31 = arg_1.var_25];
+        return 'U';
+    }
+
+    protected static Test_Class_1 func_1(final short arg_0, long arg_1)
+    {
+        --new Test_Class_0().var_2;
+        "xb".length();
+        if ((Test_Class_3.var_40 ^= (Test_Class_2.var_32 = Test_Class_0.var_1) == 1.2609472E38F) ? (Test_Class_3.var_40 = (Test_Class_3.var_40 = Test_Class_3.var_40)) : true)
+        {
+            --Test_Class_1.var_26;
+        }
+        else
+        {
+            "ybbe".substring(209378562, var_52 = (Test_Class_1.var_21 |= (Test_Class_2.var_31 = (byte)'a')));
+        }
+        Test_Class_3.var_40 &= (Test_Class_3.var_40 &= true) && (Test_Class_1.var_29 = (Test_Class_1.var_29 = Test_Class_0.var_3)).endsWith(Test_Class_0.var_3);
+        (false ? new Test_Class_0() : new Test_Class_0()).var_2 >>= new Test_Class_1().var_25;
+        return 9.430116214455637E307 <= (true ? (Test_Class_3)new Test_Class_2() : (Test_Class_3)new Test_Class_2()).var_34 ? new Test_Class_1() : new Test_Class_1();
+    }
+
+    public String toString()
+    {
+        String result =  "[\n";
+        result += "Test_Class_5.var_50 = "; result += Test.Printer.print(var_50);
+        result += "\n";
+        result += "Test_Class_5.var_60 = "; result += Test.Printer.print(var_60);
+        result += "\n";
+        result += "Test_Class_5.var_52 = "; result += Test.Printer.print(var_52);
+        result += "\n";
+        result += "Test_Class_5.var_53 = "; result += Test.Printer.print(var_53);
+        result += "\n";
+        result += "Test_Class_5.var_47 = "; result += Test.Printer.print(var_47);
+        result += "\n";
+        result += "Test_Class_5.var_49 = "; result += Test.Printer.print(var_49);
+        result += "\n";
+        result += "Test_Class_5.var_48 = "; result += Test.Printer.print(var_48);
+        result += "\n";
+        result += "Test_Class_5.var_61 = "; result += Test.Printer.print(var_61);
+        result += "\n";
+        result += "Test_Class_5.var_51 = "; result += Test.Printer.print(var_51);
+        result += "\n";
+        result += "Test_Class_5.var_54 = "; result += Test.Printer.print(var_54);
+        result += "";
+        result += "\n]";
+        return result;
+    }
+}
+
+public class Test {
+    Test_Class_4 var_66;
+    Test_Class_3 var_67;
+    Test_Class_5 var_68;
+    Test_Class_2[] var_69;
+    long var_70 = ++Test_Class_1.var_26 & Test_Class_1.var_21++;
+    final static double var_71 = 3.566207721984698E307;
+    static boolean var_72;
+    final static String var_73 = "nmxx";
+
+
+    private final char func_0(Test_Class_3 arg_0, final boolean[] arg_1)
+    {
+        ((Test_Class_5)(arg_1[arg_0.var_39++] ? new Test_Class_2[(var_67 = arg_0).var_39] : (new Object[arg_0.var_39])[arg_0.var_39])).var_54 = new Test_Class_1();
+        new Test_Class_0();
+        (((new Test[arg_0.var_39][arg_0.var_39][arg_0.var_39])[++arg_0.var_39])[arg_0.var_39][arg_0.var_39]).var_66 = (var_68 = (new Test_Class_5[arg_0.var_39][arg_0.var_39])[arg_0.var_39][arg_0.var_39]);
+        ((new Test[arg_0.var_39])[(arg_0 = (var_67 = (arg_0 = arg_0))).var_39]).var_70 = ((new long[arg_0.var_39][arg_0.var_39])[arg_0.var_39])[arg_0.var_39 = ((var_67 = (arg_0 = arg_0)).var_39 -= new Test_Class_0().var_2)] << ']';
+        arg_0 = (new Test_Class_0().var_2 *= ((new Test_Class_2[arg_0.var_39])[arg_0.var_39]).var_34) >= arg_0.var_39 ? (var_67 = arg_0) : (arg_0 = arg_0);
+        Test_Class_1.var_26--;
+        Test_Class_4 var_74 = var_66 = (Test_Class_5)(new Test_Class_4[arg_0.var_39])[arg_0.var_39];
+        Test_Class_3.var_40 ^= ! (Test_Class_3.var_40 &= (Test_Class_3.var_40 ^= Test_Class_3.var_40) | (Test_Class_3.var_40 &= Test_Class_3.var_40));
+        var_72 = (arg_1[(var_67 = arg_0).var_39] | !Test_Class_3.var_40 & !Test_Class_3.var_40 ? (Test_Class_1.var_29 = var_73).endsWith((var_66 = var_74).var_51) && (Test_Class_3.var_40 ^= Test_Class_3.var_40) : (Test_Class_3.var_40 ^= Test_Class_3.var_40)) ^ !Test_Class_3.var_40;
+        Test_Class_3.var_40 &= (Test_Class_3.var_40 &= (Test_Class_3.var_40 = Test_Class_3.var_40) & Test_Class_3.var_40 ^ Test_Class_3.var_40);
+        arg_0.var_39 -= --var_70;
+        int var_75;
+        double var_76;
+        {
+            boolean var_77;
+            var_70 ^= new Test_Class_0().var_2++;
+        }
+        Test_Class_1.var_26 /= Test_Class_0.var_3.lastIndexOf(~new Test_Class_1().var_25, Test_Class_1.var_21);
+        Test_Class_1.var_26 |= Test_Class_1.var_21;
+        (((new Test_Class_3[arg_0.var_39][arg_0.var_39][var_74.var_48])[arg_0.var_39])[arg_0.var_39][arg_0.var_39]).var_34 %= (var_67 = arg_0).var_39;
+        Test_Class_1.var_21 &= arg_0.var_39;
+        var_68 = (var_68 = (Test_Class_5)var_74);
+        var_72 = false;
+        return new Test_Class_5().var_60 ^= 'v';
+    }
+
+    public static Test_Class_2 func_1(byte[][] arg_0, final int arg_1, Test_Class_1 arg_2, final Test_Class_1 arg_3)
+    {
+        ((new Test[arg_3.var_25])[((Test_Class_3)new Test_Class_2()).var_39 *= --Test_Class_1.var_26]).var_67 = (((new Test[arg_2.var_25])[(((new Test[arg_2.var_25][arg_2.var_25])[arg_3.var_25][arg_3.var_25]).var_67 = (new Test_Class_3[arg_2.var_25][arg_2.var_25])[arg_2.var_25][arg_3.var_25]).var_39 %= Test_Class_1.var_26]).var_67 = (((new Test[arg_3.var_25][arg_2.var_25])[arg_3.var_25][arg_2.var_25]).var_67 = (((new Test[arg_3.var_25])[arg_2.var_25]).var_67 = (Test_Class_3)new Test_Class_2())));
+        {
+            --Test_Class_1.var_26;
+        }
+        if (!Test_Class_3.var_40)
+        {
+            "jfqj".replaceAll("ac", Test_Class_0.var_3);
+        }
+        else
+        {
+            arg_2 = (((new Test_Class_5[arg_3.var_25][arg_2.var_25])[((new Test_Class_3[arg_2.var_25])[arg_3.var_25]).var_39][((Test_Class_3)(new Test_Class_2[arg_2.var_25])[arg_3.var_25]).var_39]).var_54 = arg_3);
+            new Test_Class_1();
+        }
+        if (true)
+        {
+            Test_Class_0.func_0();
+        }
+        else
+        {
+            Test_Class_1.var_23 /= Test_Class_1.var_26;
+        }
+        Test_Class_1.var_26--;
+        Test_Class_1.var_23 ^= Test_Class_0.var_1;
+        return new Test_Class_2();
+    }
+
+    public static String execute()
+    {
+        try {
+            Test t = new Test();
+            try { t.test(); }
+            catch(Throwable e) { }
+            try { return t.toString(); }
+            catch (Throwable e) { return "Error during result conversion to String"; }
+        } catch (Throwable e) { return "Error during test execution"; }
+    }
+
+    public static void main(String[] args)
+    {
+        try {
+            Test t = new Test();
+            try { t.test(); }
+            catch(Throwable e) { }
+            try { System.out.println(t); }
+            catch(Throwable e) { }
+        } catch (Throwable e) { }
+    }
+
+    private void test()
+    {
+        double var_78 = 0;
+        --Test_Class_1.var_26;
+        long var_79;
+        for (var_70 /= 8.089457748637276E307; var_78 < 162 && !true & (true ? Test_Class_3.var_40 : (Test_Class_3.var_40 ^= Test_Class_3.var_40)); Test_Class_1.var_26 -= 1.2513521E38F)
+        {
+            short var_80 = 10682;
+            Test_Class_1.var_21--;
+            var_78++;
+            var_72 = (Test_Class_3.var_40 |= (Test_Class_3.var_40 ^= false));
+            ++Test_Class_1.var_26;
+        }
+        Test_Class_2 var_81;
+        new Test_Class_4();
+        int var_82 = 0;
+        ++Test_Class_1.var_23;
+        do
+        {
+            --Test_Class_1.var_26;
+            var_82++;
+            ++Test_Class_1.var_21;
+        } while ((Test_Class_3.var_40 ^= false & false) && var_82 < 256);
+        Test_Class_1.var_23 |= (var_68 = (var_68 = (Test_Class_5)(var_66 = new Test_Class_4()))).var_48 + (Test_Class_1.var_26 >>> new Test_Class_0().var_2);
+        (true ? new Test_Class_5() : (var_68 = (var_68 = new Test_Class_5()))).var_60 *= Test_Class_0.var_1;
+    }
+    public String toString()
+    {
+        String result =  "[\n";
+        result += "Test.var_69 = "; result += Printer.print(var_69);
+        result += "\n";
+        result += "Test.var_70 = "; result += Printer.print(var_70);
+        result += "\n";
+        result += "Test.var_71 = "; result += Printer.print(var_71);
+        result += "\n";
+        result += "Test.var_73 = "; result += Printer.print(var_73);
+        result += "\n";
+        result += "Test.var_68 = "; result += Printer.print(var_68);
+        result += "\n";
+        result += "Test.var_66 = "; result += Printer.print(var_66);
+        result += "\n";
+        result += "Test.var_72 = "; result += Printer.print(var_72);
+        result += "\n";
+        result += "Test.var_67 = "; result += Printer.print(var_67);
+        result += "";
+        result += "\n]";
+        return result;
+    }
+    static class Printer
+    {
+        public static String print(boolean arg) { return String.valueOf(arg); }
+        public static String print(byte arg)    { return String.valueOf(arg); }
+        public static String print(short arg)   { return String.valueOf(arg); }
+        public static String print(char arg)    { return String.valueOf((int)arg); }
+        public static String print(int arg)     { return String.valueOf(arg); }
+        public static String print(long arg)    { return String.valueOf(arg); }
+        public static String print(float arg)   { return String.valueOf(arg); }
+        public static String print(double arg)  { return String.valueOf(arg); }
+
+
+        public static String print(Object arg)
+        {
+            return print_r(new java.util.Stack(), arg);
+        }
+
+        private static String print_r(java.util.Stack visitedObjects, Object arg)
+        {
+            String result = "";
+            if (arg == null)
+                result += "null";
+            else
+            if (arg.getClass().isArray())
+            {
+                for (int i = 0; i < visitedObjects.size(); i++)
+                    if (visitedObjects.elementAt(i) == arg) return "<recursive>";
+
+                visitedObjects.push(arg);
+
+                final String delimiter = ", ";
+                result += "[";
+
+                if (arg instanceof Object[])
+                {
+                    Object[] array = (Object[]) arg;
+                    for (int i = 0; i < array.length; i++)
+                    {
+                        result += print_r(visitedObjects, array[i]);
+                        if (i < array.length - 1) result += delimiter;
+                    }
+                }
+                else
+                if (arg instanceof boolean[])
+                {
+                    boolean[] array = (boolean[]) arg;
+                    for (int i = 0; i < array.length; i++)
+                    {
+                        result += print(array[i]);
+                        if (i < array.length - 1) result += delimiter;
+                    }
+                }
+                else
+                if (arg instanceof byte[])
+                {
+                    byte[] array = (byte[]) arg;
+                    for (int i = 0; i < array.length; i++)
+                    {
+                        result += print(array[i]);
+                        if (i < array.length - 1) result += delimiter;
+                    }
+                }
+                else
+                if (arg instanceof short[])
+                {
+                    short[] array = (short[]) arg;
+                    for (int i = 0; i < array.length; i++)
+                    {
+                        result += print(array[i]);
+                        if (i < array.length - 1) result += delimiter;
+                    }
+                }
+                else
+                if (arg instanceof char[])
+                {
+                    char[] array = (char[]) arg;
+                    for (int i = 0; i < array.length; i++)
+                    {
+                        result += print(array[i]);
+                        if (i < array.length - 1) result += delimiter;
+                    }
+                }
+                else
+                if (arg instanceof int[])
+                {
+                     int[] array = (int[]) arg;
+                     for (int i = 0; i < array.length; i++)
+                     {
+                        result += print(array[i]);
+                        if (i < array.length - 1) result += delimiter;
+                     }
+                }
+                else
+                if (arg instanceof long[])
+                {
+                    long[] array = (long[]) arg;
+                    for (int i = 0; i < array.length; i++)
+                    {
+                        result += print(array[i]);
+                        if (i < array.length - 1) result += delimiter;
+                    }
+                }
+                else
+                if (arg instanceof float[])
+                {
+                    float[] array = (float[]) arg;
+                    for (int i = 0; i < array.length; i++)
+                    {
+                        result += print(array[i]);
+                        if (i < array.length - 1) result += delimiter;
+                    }
+                }
+                else
+                if (arg instanceof double[])
+                {
+                    double[] array = (double[]) arg;
+                    for (int i = 0; i < array.length; i++)
+                    {
+                        result += print(array[i]);
+                        if (i < array.length - 1) result += delimiter;
+                    }
+                }
+
+                result += "]";
+                visitedObjects.pop();
+
+            } else
+            {
+                result += arg.toString();
+            }
+
+            return result;
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/6823453/Test.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+/*
+ * @test
+ * @bug 6823453
+ * @summary DeoptimizeALot causes fastdebug server jvm to fail with assert(false,"unscheduable graph")
+ * @run main/othervm -Xcomp -XX:CompileOnly=Test -XX:+DeoptimizeALot Test
+ */
+
+public class Test {
+
+   static long vara_1 = 1L;
+
+   static void testa() {
+      short var_2 = (byte) 1.0E10;
+
+      for ( Object temp = new byte[(byte)1.0E10];  true ;
+            var_2 = "1".equals("0") ? ((byte) vara_1) : 1 ) {}
+   }
+
+   static void testb() {
+      long var_1 = -1L;
+
+      short var_2 = (byte) 1.0E10;
+
+      for ( Object temp = new byte[(byte)1.0E10];  true ;
+            var_2 = "1".equals("0") ? ((byte) var_1) : 1 ) {}
+   }
+
+   static void testc() {
+      long var_1 = -1L;
+      if (vara_1 > 0)  var_1 = 1L;
+
+      int var_2 = (byte)var_1 - 128;
+
+      for ( Object temp = new byte[var_2];  true ;
+            var_2 = "1".equals("0") ? 2 : 1 ) {}
+   }
+
+   static void testd() {
+      long var_1 = 0L;
+
+      int var_2 = (byte)var_1 + 1;
+      for (int i=0; i<2 ; i++)  var_2 = var_2 - 1;
+
+      for ( Object temp = new byte[var_2];  true ;
+            var_2 = "1".equals("0") ? 2 : 1 ) {}
+   }
+
+   public static void main(String[] args) throws Exception {
+      int nex = 0;
+
+      try {
+         testa();
+      }
+      catch (java.lang.NegativeArraySizeException ex) { nex++; }
+      try {
+         testb();
+      }
+      catch (java.lang.NegativeArraySizeException ex) { nex++; }
+      try {
+         testc();
+      }
+      catch (java.lang.NegativeArraySizeException ex) { nex++; }
+      try {
+         testd();
+      }
+      catch (java.lang.NegativeArraySizeException ex) { nex++; }
+
+      if (nex != 4)
+        System.exit(97);
+   }
+}
+
--- a/jaxp/.hgtags	Wed Jul 05 16:51:11 2017 +0200
+++ b/jaxp/.hgtags	Wed Jul 05 16:51:35 2017 +0200
@@ -29,3 +29,4 @@
 69ad87dc25cbcaaaded4727199395ad0c78bc427 jdk7-b52
 e8837366d3fd72f7c7a47ebfdbd5106c16156f12 jdk7-b53
 946a9f0c493261fa6a010dc33e61b9b535ba80c1 jdk7-b54
+039945fba683ee6773a721e2bd4e449f6133769a jdk7-b55
--- a/jaxws/.hgtags	Wed Jul 05 16:51:11 2017 +0200
+++ b/jaxws/.hgtags	Wed Jul 05 16:51:35 2017 +0200
@@ -29,3 +29,4 @@
 e646890d18b770f625f14ed4ad5c50554d8d3d8b jdk7-b52
 b250218eb2e534384667ec73e3713e684667fd4c jdk7-b53
 50ea00dc5f143fe00025233e704903c37f8464aa jdk7-b54
+e0eebd978b830c09e7862cff3f77a914c15651c9 jdk7-b55
--- a/jdk/.hgtags	Wed Jul 05 16:51:11 2017 +0200
+++ b/jdk/.hgtags	Wed Jul 05 16:51:35 2017 +0200
@@ -29,3 +29,4 @@
 bcbeadb4a5d759b29e876ee2c83401e91ff22f60 jdk7-b52
 a2033addca678f9e4c0d92ffa1e389171cc9321d jdk7-b53
 d1c43d1f5676a24ba86221ac7cad5694f3a9afda jdk7-b54
+522bb5aa17e0c0cff00b1ed7d1b51bc4db2cfef9 jdk7-b55
--- a/jdk/make/com/sun/Makefile	Wed Jul 05 16:51:11 2017 +0200
+++ b/jdk/make/com/sun/Makefile	Wed Jul 05 16:51:35 2017 +0200
@@ -41,7 +41,7 @@
 # Omit mirror since it's built with the apt tool.
 SUBDIRS = $(SCRIPT_SUBDIR) image security crypto/provider jndi jmx \
     java inputmethods org xml rowset net/httpserver net/ssl demo \
-    tools jarsigner tracing servicetag
+    tools jarsigner tracing servicetag nio
 
 all build clean clobber::
 	$(SUBDIRS-loop)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/com/sun/nio/Makefile	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,38 @@
+#
+# Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+#
+
+# 
+# Makefile for com.sun.nio packages.
+#
+
+BUILDDIR = ../../..
+include $(BUILDDIR)/common/Defs.gmk
+
+SUBDIRS = sctp
+all build clean clobber::
+	$(SUBDIRS-loop)
+
+clean clobber::
+	$(RM) -r $(CLASSDESTDIR)/com/sun/nio
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/com/sun/nio/sctp/Exportedfiles.gmk	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,39 @@
+#
+# Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+#
+
+#
+# These are the names of Java classes for which we will make .h files.
+#
+
+ifneq ($(PLATFORM), windows)
+FILES_export = \
+    sun/nio/ch/SctpAssocChange.java \
+    sun/nio/ch/SctpChannelImpl.java \
+    sun/nio/ch/SctpNet.java \
+    sun/nio/ch/SctpPeerAddrChange.java \
+    sun/nio/ch/SctpResultContainer.java \
+    sun/nio/ch/SctpServerChannelImpl.java \
+    sun/nio/ch/SctpStdSocketOption.java
+endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/com/sun/nio/sctp/FILES_c.gmk	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,31 @@
+#
+# Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+#
+
+ifneq ($(PLATFORM),windows)
+FILES_c = \
+	SctpNet.c \
+        SctpChannelImpl.c \
+        SctpServerChannelImpl.c
+endif	
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/com/sun/nio/sctp/FILES_java.gmk	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,67 @@
+#
+# Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+#
+FILES_java = \
+        com/sun/nio/sctp/AbstractNotificationHandler.java \
+	com/sun/nio/sctp/Association.java \
+	com/sun/nio/sctp/AssociationChangeNotification.java \
+	com/sun/nio/sctp/HandlerResult.java \
+	com/sun/nio/sctp/IllegalReceiveException.java \
+	com/sun/nio/sctp/IllegalUnbindException.java \
+	com/sun/nio/sctp/InvalidStreamException.java \
+	com/sun/nio/sctp/MessageInfo.java \
+	com/sun/nio/sctp/Notification.java \
+	com/sun/nio/sctp/NotificationHandler.java \
+	com/sun/nio/sctp/PeerAddressChangeNotification.java \
+	com/sun/nio/sctp/SctpChannel.java \
+	com/sun/nio/sctp/SctpMultiChannel.java \
+	com/sun/nio/sctp/SctpServerChannel.java \
+	com/sun/nio/sctp/SctpSocketOption.java \
+	com/sun/nio/sctp/SctpStandardSocketOption.java \
+	com/sun/nio/sctp/SendFailedNotification.java \
+	com/sun/nio/sctp/ShutdownNotification.java \
+	\
+	sun/nio/ch/SctpMessageInfoImpl.java \
+	sun/nio/ch/SctpStdSocketOption.java
+
+ifneq ($(PLATFORM), windows)
+FILES_java += \
+	sun/nio/ch/SctpAssocChange.java \
+	sun/nio/ch/SctpAssociationImpl.java \
+	sun/nio/ch/SctpChannelImpl.java \
+	sun/nio/ch/SctpMultiChannelImpl.java \
+	sun/nio/ch/SctpNet.java \
+	sun/nio/ch/SctpNotification.java \
+	sun/nio/ch/SctpPeerAddrChange.java \
+	sun/nio/ch/SctpResultContainer.java \
+	sun/nio/ch/SctpSendFailed.java \
+	sun/nio/ch/SctpServerChannelImpl.java \
+	sun/nio/ch/SctpShutdown.java \
+	sun/nio/ch/SctpSocketDispatcher.java
+else
+FILES_java += \
+	sun/nio/ch/SctpChannelImpl.java \
+	sun/nio/ch/SctpMultiChannelImpl.java \
+	sun/nio/ch/SctpServerChannelImpl.java
+endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/com/sun/nio/sctp/Makefile	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,80 @@
+#
+# Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+#
+
+#
+# Makefile for com.sun.nio.sctp
+#
+
+BUILDDIR = ../../../..
+PACKAGE = com.sun.nio.sctp
+LIBRARY = sctp
+PRODUCT = sun
+#OTHER_JAVACFLAGS += -Xmaxwarns 1000 -Xlint
+include $(BUILDDIR)/common/Defs.gmk
+
+#
+# Files to compile
+#
+include FILES_c.gmk
+include FILES_java.gmk
+include Exportedfiles.gmk
+
+ifneq ($(PLATFORM), windows)
+include $(BUILDDIR)/common/Mapfile-vers.gmk
+include $(BUILDDIR)/common/Library.gmk
+
+#
+# Find platform-specific C source files
+#
+vpath %.c $(PLATFORM_SRC)/native/sun/nio/ch
+
+#
+# Include nio.h, net_util.h, sun_nio_ch_IOStatus.h, etc
+#
+OTHER_INCLUDES += \
+  -I$(SHARE_SRC)/native/sun/nio/ch \
+  -I$(SHARE_SRC)/native/java/net \
+  -I$(PLATFORM_SRC)/native/java/net \
+  -I$(CLASSHDRDIR)/../../../../java/java.nio/nio/CClassHeaders
+
+ifeq ($(PLATFORM), linux)
+COMPILER_WARNINGS_FATAL=true
+#OTHER_LDLIBS += -L$(LIBDIR)/$(LIBARCH) -ljava -lnet -lpthread -ldl
+OTHER_LDLIBS += -L$(LIBDIR)/$(LIBARCH) -lnio -lnet -lpthread -ldl
+endif
+ifeq ($(PLATFORM), solaris)
+#LIBSCTP = -lsctp
+OTHER_LDLIBS += $(LIBSOCKET) -L$(LIBDIR)/$(LIBARCH) -lnet -lnio
+endif # PLATFORM
+
+else # windows
+include $(BUILDDIR)/common/Classes.gmk
+endif # ifneq windows
+
+
+clean clobber::
+	$(RM) -r $(CLASSDESTDIR)/com/sun/nio/sctp
+	$(RM) -r $(CLASSDESTDIR)/sun/nio/ch
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/make/com/sun/nio/sctp/mapfile-vers	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,49 @@
+#
+# Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+#
+
+SUNWprivate_1.1 {
+	global:
+		Java_sun_nio_ch_SctpNet_socket0;
+		Java_sun_nio_ch_SctpNet_bindx;
+		Java_sun_nio_ch_SctpNet_getLocalAddresses0;
+		Java_sun_nio_ch_SctpNet_getRemoteAddresses0;
+		Java_sun_nio_ch_SctpNet_getPrimAddrOption0;
+		Java_sun_nio_ch_SctpNet_setPrimAddrOption0;
+		Java_sun_nio_ch_SctpNet_setPeerPrimAddrOption0;
+		Java_sun_nio_ch_SctpNet_getInitMsgOption0;
+		Java_sun_nio_ch_SctpNet_setInitMsgOption0;
+		Java_sun_nio_ch_SctpNet_getIntOption0;
+		Java_sun_nio_ch_SctpNet_setIntOption0;
+		Java_sun_nio_ch_SctpNet_shutdown0;
+		Java_sun_nio_ch_SctpChannelImpl_initIDs;
+		Java_sun_nio_ch_SctpChannelImpl_checkConnect;
+		Java_sun_nio_ch_SctpChannelImpl_receive0;
+		Java_sun_nio_ch_SctpChannelImpl_send0;
+		Java_sun_nio_ch_SctpServerChannelImpl_initIDs;
+		Java_sun_nio_ch_SctpServerChannelImpl_accept0;
+                JNI_OnLoad;
+	local:
+		*;
+};
--- a/jdk/make/docs/NON_CORE_PKGS.gmk	Wed Jul 05 16:51:11 2017 +0200
+++ b/jdk/make/docs/NON_CORE_PKGS.gmk	Wed Jul 05 16:51:35 2017 +0200
@@ -86,6 +86,8 @@
 
 SMARTCARDIO_PKGS = javax.smartcardio
 
+SCTPAPI_PKGS     = com.sun.nio.sctp
+
 TRACING_PKGS     = com.sun.tracing         \
                    com.sun.tracing.dtrace
 
@@ -98,4 +100,6 @@
                    $(OLD_JSSE_PKGS) \
                    $(HTTPSERVER_PKGS) \
                    $(SMARTCARDIO_PKGS) \
-                   $(TRACING_PKGS)
+                   $(TRACING_PKGS) \
+                   $(SCTPAPI_PKGS)
+
--- a/jdk/make/java/nio/mapfile-linux	Wed Jul 05 16:51:11 2017 +0200
+++ b/jdk/make/java/nio/mapfile-linux	Wed Jul 05 16:51:35 2017 +0200
@@ -189,6 +189,7 @@
 		Java_sun_nio_fs_UnixNativeDispatcher_getgrnam0;
 		Java_sun_nio_fs_UnixNativeDispatcher_getextmntent;
 		Java_sun_nio_fs_UnixCopyFile_transfer;
+		handleSocketError;
 
 	local:
 		*;
--- a/jdk/make/java/nio/mapfile-solaris	Wed Jul 05 16:51:11 2017 +0200
+++ b/jdk/make/java/nio/mapfile-solaris	Wed Jul 05 16:51:35 2017 +0200
@@ -175,6 +175,7 @@
 		Java_sun_nio_fs_SolarisWatchService_portDissociate;
 		Java_sun_nio_fs_SolarisWatchService_portSend;
 		Java_sun_nio_fs_SolarisWatchService_portGetn;
+		handleSocketError;
 
 	local:
 		*;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/nio/sctp/AbstractNotificationHandler.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.nio.sctp;
+
+/**
+ * A skeletal handler that consumes notifications and continues.
+ *
+ * <P> This class trivially implements the {@code handleNotification} methods to
+ * return {@link HandlerResult#CONTINUE CONTINUE} so that all notifications are
+ * consumed and the channel continues to try and receive a message.
+ *
+ * <P> It also provides overloaded versions of the {@code handleNotification}
+ * methods, one for each of the required supported notification types, {@link
+ * AssociationChangeNotification}, {@link PeerAddressChangeNotification},
+ * {@link SendFailedNotification}, and {@link ShutdownNotification}. The
+ * appropriate method will be invoked when the notification is received.
+ *
+ * @since 1.7
+ */
+public class AbstractNotificationHandler<T>
+    implements NotificationHandler<T>
+{
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected AbstractNotificationHandler() {}
+
+    /**
+     * Invoked when an implementation specific notification is received from the
+     * SCTP stack.
+     *
+     * @param  notification
+     *         The notification
+     *
+     * @param  attachment
+     *         The object attached to the {@code receive} operation when it was
+     *         initiated.
+     *
+     * @return  The handler result
+     */
+    @Override
+    public HandlerResult handleNotification(Notification notification,
+                                            T attachment) {
+        return HandlerResult.CONTINUE;
+    }
+
+    /**
+     * Invoked when an {@link AssociationChangeNotification} is received from
+     * the SCTP stack.
+     *
+     * @param  notification
+     *         The notification
+     *
+     * @param  attachment
+     *         The object attached to the {@code receive} operation when it was
+     *         initiated.
+     *
+     * @return  The handler result
+     */
+    public HandlerResult handleNotification(AssociationChangeNotification notification,
+                                            T attachment) {
+        return HandlerResult.CONTINUE;
+    }
+
+    /**
+     * Invoked when an {@link PeerAddressChangeNotification} is received from
+     * the SCTP stack.
+     *
+     * @param  notification
+     *         The notification
+     *
+     * @param  attachment
+     *         The object attached to the {@code receive} operation when it was
+     *         initiated.
+     *
+     * @return  The handler result
+     */
+    public HandlerResult handleNotification(PeerAddressChangeNotification notification,
+                                            T attachment) {
+        return HandlerResult.CONTINUE;
+    }
+
+    /**
+     * Invoked when an {@link SendFailedNotification} is received from
+     * the SCTP stack.
+     *
+     * @param  notification
+     *         The notification
+     *
+     * @param  attachment
+     *         The object attached to the {@code receive} operation when it was
+     *         initiated.
+     *
+     * @return  The handler result
+     */
+    public HandlerResult handleNotification(SendFailedNotification notification,
+                                            T attachment) {
+        return HandlerResult.CONTINUE;
+    }
+
+    /**
+     * Invoked when an {@link ShutdownNotification} is received from
+     * the SCTP stack.
+     *
+     * @param  notification
+     *         The notification
+     *
+     * @param  attachment
+     *         The object attached to the {@code receive} operation when it was
+     *         initiated.
+     *
+     * @return  The handler result
+     */
+    public HandlerResult handleNotification(ShutdownNotification notification,
+                                            T attachment) {
+        return HandlerResult.CONTINUE;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/nio/sctp/Association.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.nio.sctp;
+
+/**
+ * A class that represents an SCTP association.
+ *
+ * <P> An association exists between two SCTP endpoints. Each endpoint is
+ * represented by a list of transport addresses through which that endpoint can
+ * be reached and from which it will originate SCTP messages. The association
+ * spans over all of the possible source/destination combinations which may be
+ * generated from each endpoint's lists of addresses.
+ *
+ * <P> Associations are identified by their Association ID.
+ * Association ID's are guaranteed to be unique for the lifetime of the
+ * association. An association ID may be reused after the association has been
+ * shutdown. An association ID is not unique across multiple SCTP channels.
+ * An Association's local and remote addresses may change if the SCTP
+ * implementation supports <I>Dynamic Address Reconfiguration</I> as defined by
+ * <A HREF="http://tools.ietf.org/html/rfc5061">RFC5061</A>, see the
+ * {@code bindAddress} and {@code unbindAddress} methods of {@link SctpChannel},
+ * {@link SctpServerChannel}, and {@link SctpMultiChannel}.
+ *
+ * <P> An {@code Association} is returned from an {@link
+ * SctpChannel#association SctpChannel} or an {@link
+ * SctpMultiChannel#associations SctpMultiChannel}, as well
+ * as being given as a parameter to {@link NotificationHandler
+ * NotificationHandler} methods.
+ *
+ * @since 1.7
+ */
+public class Association {
+    private final int associationID;
+    private final int maxInStreams;
+    private final int maxOutStreams;
+
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected Association(int associationID,
+                          int maxInStreams,
+                          int maxOutStreams) {
+        this.associationID = associationID;
+        this.maxInStreams = maxInStreams;
+        this.maxOutStreams = maxOutStreams;
+    }
+
+    /**
+     * Returns the associationID.
+     *
+     * @return  The association ID
+     */
+    public final int associationID() {
+        return associationID;
+    };
+
+    /**
+     * Returns the maximum number of inbound streams that this association
+     * supports.
+     *
+     * <P> Data received on this association will be on stream number
+     * {@code s}, where {@code 0 <= s < maxInboundStreams()}.
+     *
+     * @return  The maximum number of inbound streams
+     */
+    public final int maxInboundStreams() {
+        return maxInStreams;
+    };
+
+    /**
+     * Returns the maximum number of outbound streams that this association
+     * supports.
+     *
+     * <P> Data sent on this association must be on stream number
+     * {@code s}, where {@code 0 <= s < maxOutboundStreams()}.
+     *
+     * @return  The maximum number of outbound streams
+     */
+    public final int maxOutboundStreams() {
+        return maxOutStreams;
+    };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/nio/sctp/AssociationChangeNotification.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.nio.sctp;
+
+/**
+ * Notification emitted when an association has either opened or closed.
+ *
+ * @since 1.7
+ */
+public abstract class AssociationChangeNotification
+    implements Notification
+{
+    /**
+     * Defines the type of change event that happened to the association.
+     *
+     * @since 1.7
+     */
+    public enum AssocChangeEvent
+    {
+        /**
+         * A new association is now ready and data may be exchanged with this peer.
+         */
+        COMM_UP,
+
+        /**
+         * The association has failed. A series of SCTP send failed notifications
+         * will follow this notification, one for each outstanding message.
+         */
+       COMM_LOST,
+
+        /**
+         * SCTP has detected that the peer has restarted.
+         */
+       RESTART,
+
+        /**
+         * The association has gracefully closed.
+         */
+       SHUTDOWN,
+
+        /**
+         * The association failed to setup. If a message was sent on a {@link
+         * SctpMultiChannel} in non-blocking mode, an
+         * SCTP send failed notification will follow this notification for the
+         * outstanding message.
+         */
+       CANT_START
+    }
+
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected AssociationChangeNotification() {}
+
+    /**
+     * Returns the association that this notification is applicable to.
+     *
+     * @return  The association whose state has changed, or {@code null} if
+     *          there is no association, that is {@linkplain
+     *          AssocChangeEvent#CANT_START CANT_START}
+     */
+    public abstract Association association();
+
+    /**
+     * Returns the type of change event.
+     *
+     * @return  The event
+     */
+    public abstract AssocChangeEvent event();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/nio/sctp/HandlerResult.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.nio.sctp;
+
+/**
+ * Defines notification handler results.
+ *
+ * <P> The {@code HandlerResult} is used to determine the behavior of the
+ * channel after it handles a notification from the SCTP stack. Essentially its
+ * value determines if the channel should try to receive another notificaiton or
+ * a message before returning.
+ *
+ * @since 1.7
+ */
+public enum HandlerResult {
+    /**
+     * Try to receieve another message or notification.
+     */
+    CONTINUE,
+
+    /**
+     * Return without trying to receive any more data.
+     */
+    RETURN;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/nio/sctp/IllegalReceiveException.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.nio.sctp;
+
+/**
+ * Unchecked exception thrown when an attempt is made to invoke the
+ * {@code receive} method of {@link SctpChannel} or {@link SctpMultiChannel}
+ * from a notification handler.
+ *
+ * @since 1.7
+ */
+public class IllegalReceiveException extends IllegalStateException {
+    private static final long serialVersionUID = 2296619040988576224L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public IllegalReceiveException() { }
+
+    /**
+     * Constructs an instance of this class with the specified message.
+     */
+    public IllegalReceiveException(String msg) {
+        super(msg);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/nio/sctp/IllegalUnbindException.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.nio.sctp;
+
+/**
+ * Unchecked exception thrown when an attempt is made to remove an
+ * address that is not bound to the channel, or remove an address from a
+ * channel that has only one address bound to it.
+ *
+ * @since 1.7
+ */
+public class IllegalUnbindException extends IllegalStateException {
+    private static final long serialVersionUID = -310540883995532224L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public IllegalUnbindException() { }
+
+    /**
+     * Constructs an instance of this class with the specified detailed message.
+     */
+    public IllegalUnbindException(String msg) {
+        super(msg);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/nio/sctp/InvalidStreamException.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.nio.sctp;
+
+/**
+ * Unchecked exception thrown when an attempt is made to send a
+ * message to an invalid stream.
+ *
+ * @since 1.7
+ */
+public class InvalidStreamException extends IllegalArgumentException {
+    private static final long serialVersionUID = -9172703378046665558L;
+
+    /**
+     * Constructs an instance of this class.
+     */
+    public InvalidStreamException() { }
+
+    /**
+     * Constructs an instance of this class with the specified detailed message.
+     */
+    public InvalidStreamException(String msg) {
+        super(msg);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/nio/sctp/MessageInfo.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.nio.sctp;
+
+import java.net.SocketAddress;
+
+/**
+ * The {@code MessageInfo} class provides additional ancillary information about
+ * messages.
+ *
+ * <P> Received SCTP messages, returned by
+ * {@link SctpChannel#receive SctpChannel.receive} and {@link
+ * SctpMultiChannel#receive SctpMultiChannel.receive},
+ * return a {@code MessageInfo} instance that can be queried to determine
+ * ancillary information about the received message. Messages being sent should
+ * use one of the {@link #createOutgoing(java.net.SocketAddress,int)
+ * createOutgoing} methods to provide ancillary data for the message being
+ * sent, and may use the appropriate setter methods to override the default
+ * values provided for {@link #isUnordered() unordered}, {@link #timeToLive()
+ * timeToLive}, {@link #isComplete() complete} and {@link #payloadProtocolID()
+ * payloadProtocolID}, before sending the message.
+ *
+ * <P> For out going messages the {@code timeToLive} parameter is a time period
+ * that the sending side SCTP stack may expire the message if it has not been
+ * sent. This time period is an indication to the stack that the message is no
+ * longer required to be sent after the time period expires. It is not a hard
+ * timeout and may be influenced by whether the association supports the partial
+ * reliability extension, <a href=http://www.ietf.org/rfc/rfc3758.txt>RFC 3758
+ * <a>
+ *
+ * <P> {@code MessageInfo} instances are not safe for use by multiple concurrent
+ * threads. If a MessageInfo is to be used by more than one thread then access
+ * to the MessageInfo should be controlled by appropriate synchronization.
+ *
+ * @since 1.7
+ */
+public abstract class MessageInfo {
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected MessageInfo() {}
+
+    /**
+     * Creates a {@code MessageInfo} instance suitable for use when
+     * sending a message.
+     *
+     * <P> The returned instance will have its {@link #isUnordered() unordered}
+     * value set to {@code false}, its {@link #timeToLive() timeToLive} value
+     * set to {@code 0}, its {@link #isComplete() complete} value set
+     * to {@code true}, and its {@link #payloadProtocolID() payloadProtocolID}
+     * value set to {@code 0}. These values, if required, can be set through
+     * the appropriate setter method before sending the message.
+     *
+     * @param  address
+     *         For a connected {@code SctpChannel} the address is the
+     *         preferred peer address of the association to send the message
+     *         to, or {@code null} to use the peer primary address. For an
+     *         {@code SctpMultiChannel} the address is used to determine
+     *         the association, or if no association exists with a peer of that
+     *         address then one is setup.
+     *
+     * @param  streamNumber
+     *         The stream number that the message will be sent on
+     *
+     * @return  The outgoing message info
+     *
+     * @throws  IllegalArgumentException
+     *          If the streamNumber is negative or greater than {@code 65536}
+     */
+    public static MessageInfo createOutgoing(SocketAddress address,
+                                             int streamNumber) {
+        if (streamNumber < 0 || streamNumber > 65536)
+            throw new IllegalArgumentException("Invalid stream number");
+
+        return new sun.nio.ch.SctpMessageInfoImpl(null, address, streamNumber);
+    }
+    /**
+     * Creates a {@code MessageInfo} instance suitable for use when
+     * sending a message to a given association. Typically used for
+     * {@code SctpMultiChannel} when an association has already been setup.
+     *
+     * <P> The returned instance will have its {@link #isUnordered() unordered}
+     * value set to {@code false}, its {@link #timeToLive() timeToLive} value
+     * set to {@code 0}, its {@link #isComplete() complete} value set
+     * to {@code true}, and its {@link #payloadProtocolID() payloadProtocolID}
+     * value set to {@code 0}. These values, if required, can be set through
+     * the appropriate setter method before sending the message.
+     *
+     * @param  association
+     *         The association to send the message on
+     *
+     * @param  address
+     *         The preferred peer address of the association to send the message
+     *         to, or {@code null} to use the peer primary address
+     *
+     * @param  streamNumber
+     *         The stream number that the message will be sent on.
+     *
+     * @return  The outgoing message info
+     *
+     * @throws  IllegalArgumentException
+     *          If {@code association} is {@code null}, or the streamNumber is
+     *          negative or greater than {@code 65536}
+     */
+    public static MessageInfo createOutgoing(Association association,
+                                             SocketAddress address,
+                                             int streamNumber) {
+        if (association == null)
+            throw new IllegalArgumentException("association cannot be null");
+
+        if (streamNumber < 0 || streamNumber > 65536)
+            throw new IllegalArgumentException("Invalid stream number");
+
+        return new sun.nio.ch.SctpMessageInfoImpl(association, address,
+                streamNumber);
+    }
+
+    /**
+     * Returns the source socket address if the message has been received,
+     * otherwise the preferred destination of the message to be sent.
+     *
+     * @return  The socket address, or {@code null} if this instance is to be
+     *          used for sending a message and has been construced without
+     *          specifying a preferred destination address
+     *
+     */
+    public abstract SocketAddress address();
+
+    /**
+     * Returns the association that the message was received on, if the message
+     * has been received, otherwise the association that the message is to be
+     * sent on.
+     *
+     * @return The association, or {@code null} if this instance is to be
+     *         used for sending a message and has been construced using the
+     *         the {@link #createOutgoing(SocketAddress,int)
+     *         createOutgoing(SocketAddress,int)} static factory method
+     */
+    public abstract Association association();
+
+    /**
+     * Returns the number of bytes read for the received message.
+     *
+     * <P> This method is only appicable for received messages, it has no
+     * meaning for messages being sent.
+     *
+     * @return  The number of bytes read, {@code -1} if the channel is an {@link
+     *          SctpChannel} that has reached end-of-stream, otherwise
+     *          {@code 0}
+     */
+    public abstract int bytes();
+
+    /**
+     * Tells whether or not the message is complete.
+     *
+     * <P> For received messages {@code true} indicates that the message was
+     * completely received. For messages being sent {@code true} indicates that
+     * the message is complete, {@code false} indicates that the message is not
+     * complete. How the send channel interprets this value depends on the value
+     * of its {@link SctpStandardSocketOption#SCTP_EXPLICIT_COMPLETE
+     * SCTP_EXPLICIT_COMPLETE} socket option.
+     *
+     * @return  {@code true} if, and only if, the message is complete
+     */
+    public abstract boolean isComplete();
+
+    /**
+     * Sets whether or not the message is complete.
+     *
+     * <P> For messages being sent {@code true} indicates that
+     * the message is complete, {@code false} indicates that the message is not
+     * complete. How the send channel interprets this value depends on the value
+     * of its {@link SctpStandardSocketOption#SCTP_EXPLICIT_COMPLETE
+     * SCTP_EXPLICIT_COMPLETE} socket option.
+     *
+     * @param  complete
+     *         {@code true} if, and only if, the message is complete
+     *
+     * @return  This MessageInfo
+     *
+     * @see  MessageInfo#isComplete()
+     */
+    public abstract MessageInfo complete(boolean complete);
+
+    /**
+     * Tells whether or not the message is unordered. For received messages
+     * {@code true} indicates that the message was sent non-ordered. For
+     * messages being sent {@code true} requests the un-ordered delivery of the
+     * message, {@code false} indicates that the message is ordered.
+     *
+     * @return  {@code true} if the message is unordered, otherwise
+     *          {@code false}
+     */
+    public abstract boolean isUnordered();
+
+    /**
+     * Sets whether or not the message is unordered.
+     *
+     * @param  unordered
+     *         {@code true} requests the un-ordered delivery of the message,
+     *         {@code false} indicates that the message is ordered.
+     *
+     * @return  This MessageInfo
+     *
+     * @see  MessageInfo#isUnordered()
+     */
+    public abstract MessageInfo unordered(boolean unordered);
+
+    /**
+     * Returns the payload protocol Identifier.
+     *
+     * <P> A value indicating the type of payload protocol data being
+     * transmitted/received. This value is passed as opaque data by SCTP.
+     * {@code 0} indicates an unspecified payload protocol identifier.
+     *
+     * @return  The Payload Protocol Identifier
+     */
+    public abstract int payloadProtocolID();
+
+    /**
+     * Sets the payload protocol Identifier.
+     *
+     * <P> A value indicating the type of payload protocol data being
+     * transmitted. This value is passed as opaque data by SCTP.
+     *
+     * @param  ppid
+     *         The Payload Protocol Identifier, or {@code 0} indicate an
+     *         unspecified payload protocol identifier.
+     *
+     * @return  This MessageInfo
+     *
+     * @see  MessageInfo#payloadProtocolID()
+     */
+    public abstract MessageInfo payloadProtocolID(int ppid);
+
+    /**
+     * Returns the stream number that the message was received on, if the
+     * message has been received, otherwise the stream number that the message
+     * is to be sent on.
+     *
+     * @return  The stream number
+     */
+    public abstract int streamNumber();
+
+    /**
+     * Sets the stream number that the message is to be sent on.
+     *
+     * @param  streamNumber
+     *         The stream number
+     *
+     * @throws  IllegalArgumentException
+     *          If the streamNumber is negative or greater than {@code 65536}
+     *
+     * @return  This MessageInfo
+     */
+    public abstract MessageInfo streamNumber(int streamNumber);
+
+    /**
+     * The time period that the sending side may expire the message if it has
+     * not been sent, or {@code 0} to indicate that no timeout should occur. This
+     * value is only applicable for messages being sent, it has no meaning for
+     * received messages.
+     *
+     * @return  The time period in milliseconds, or {@code 0}
+     */
+    public abstract long timeToLive();
+
+    /**
+     * Sets the time period that the sending side may expire the message if it
+     * has not been sent.
+     *
+     * @param  millis
+     *         The time period in milliseconds, or {@code 0} to indicate that no
+     *         timeout should occur
+     *
+     * @return  This MessageInfo
+     *
+     * @see MessageInfo#timeToLive()
+     */
+    public abstract MessageInfo timeToLive(long millis);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/nio/sctp/Notification.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.nio.sctp;
+
+/**
+ * A notification from the SCTP stack.
+ *
+ * <P> Objects of this type are passed to the {@link NotificationHandler} when
+ * a notification is received.
+ *
+ * <P> An SCTP channel supports the following notifications: {@link
+ * AssociationChangeNotification}, {@link PeerAddressChangeNotification},
+ * {@link SendFailedNotification}, {@link ShutdownNotification}, and may support
+ * additional implementation specific notifications.
+ *
+ * @since 1.7
+ */
+public interface Notification {
+    /**
+     * Returns the association that this notification is applicable to.
+     */
+    public Association association();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/nio/sctp/NotificationHandler.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.nio.sctp;
+
+/**
+ * A handler for consuming notifications from the SCTP stack.
+ *
+ * <P> The SCTP channels defined in this package allow a notification handler to
+ * be specified to consume notifications from the SCTP stack. When a
+ * notification is received the {@linkplain #handleNotification
+ * handleNotification} method of the handler is invoked to handle that
+ * notification.
+ *
+ * <P> Additionally, an attachment object can be attached to the {@code receive}
+ * operation to provide context when consuming the notification. The
+ * attachment is important for cases where a <i>state-less</i> {@code
+ * NotificationHandler} is used to consume the result of many {@code receive}
+ * operations.
+ *
+ * <P> Handler implementations are encouraged to extend the {@link
+ * AbstractNotificationHandler} class which implements this interface and
+ * provide notification specific methods. However, an API should generally use
+ * this handler interface as the type for parameters, return type, etc. rather
+ * than the abstract class.
+ *
+ * @param  T  The type of the object attached to the receive operation
+ *
+ * @since 1.7
+ */
+public interface NotificationHandler<T> {
+    /**
+     * Invoked when a notification is received from the SCTP stack.
+     *
+     * @param  notification
+     *         The notification
+     *
+     * @param  attachment
+     *         The object attached to the receive operation when it was initiated.
+     *
+     * @return  The handler result
+     */
+    HandlerResult handleNotification(Notification notification, T attachment);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/nio/sctp/PeerAddressChangeNotification.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.nio.sctp;
+
+import java.net.SocketAddress;
+
+/**
+ * Notification emitted when a destination address on a multi-homed peer
+ * encounters a change.
+ *
+ * @since 1.7
+ */
+public abstract class PeerAddressChangeNotification
+    implements Notification
+{
+    /**
+     * Defines the type of address change event that occurred to the destination
+     * address on a multi-homed peer when it encounters a change of interface
+     * details.
+     *
+     * <P> Some of these events types are only generated when the association
+     * supports dynamic address reconfiguration, e.g. {@code SCTP_ADDR_ADDED},
+     * {@code SCTP_ADDR_REMOVED}, etc.
+     *
+     * @since 1.7
+     */
+    public enum AddressChangeEvent {
+        /**
+         * This address is now reachable.
+         */
+       ADDR_AVAILABLE,
+
+       /**
+        * The address specified can no longer be reached. Any data sent to this
+        * address is rerouted to an alternate until this address becomes reachable.
+        */
+       ADDR_UNREACHABLE,
+
+       /**
+        * The address is no longer part of the association.
+        */
+       ADDR_REMOVED,
+
+       /**
+        * The address is now part of the association.
+        */
+       ADDR_ADDED,
+
+       /**
+        * This address has now been made to be the primary destination address.
+        */
+       ADDR_MADE_PRIMARY,
+
+       /**
+        * This address has now been confirmed as a valid address.
+        */
+       ADDR_CONFIRMED;
+    }
+
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected PeerAddressChangeNotification() {}
+
+    /**
+     * Returns the peer address.
+     *
+     * @return  The peer address
+     */
+    public abstract SocketAddress address();
+
+    /**
+     * Returns the association that this notification is applicable to.
+     *
+     * @return  The association whose peer address changed
+     */
+    public abstract Association association();
+
+    /**
+     * Returns the type of change event.
+     *
+     * @return  The event
+     */
+    public abstract AddressChangeEvent event();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/nio/sctp/SctpChannel.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,859 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.nio.sctp;
+
+import java.net.SocketAddress;
+import java.net.InetAddress;
+import java.io.IOException;
+import java.util.Set;
+import java.nio.ByteBuffer;
+import java.nio.channels.spi.AbstractSelectableChannel;
+import java.nio.channels.spi.SelectorProvider;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.SelectionKey;
+
+/**
+ * A selectable channel for message-oriented connected SCTP sockets.
+ *
+ * <P> An SCTP channel can only control one SCTP association.
+ * An {@code SCTPChannel} is created by invoking one of the
+ * {@link #open open} methods of this class. A newly-created channel is open but
+ * not yet connected, that is, there is no association setup with a remote peer.
+ * An attempt to invoke an I/O operation upon an unconnected
+ * channel will cause a {@link java.nio.channels.NotYetConnectedException} to be
+ * thrown. An association can be setup by connecting the channel using one of
+ * its {@link #connect connect} methods. Once connected, the channel remains
+ * connected until it is closed. Whether or not a channel is connected may be
+ * determined by invoking {@link #getRemoteAddresses getRemoteAddresses}.
+ *
+ * <p> SCTP channels support <i>non-blocking connection:</i>&nbsp;A
+ * channel may be created and the process of establishing the link to
+ * the remote socket may be initiated via the {@link #connect connect} method
+ * for later completion by the {@link #finishConnect finishConnect} method.
+ * Whether or not a connection operation is in progress may be determined by
+ * invoking the {@link #isConnectionPending isConnectionPending} method.
+ *
+ * <p> Socket options are configured using the
+ * {@link #setOption(SctpSocketOption,Object) setOption} method. An SCTP
+ * channel support the following options:
+ * <blockquote>
+ * <table border>
+ *   <tr>
+ *     <th>Option Name</th>
+ *     <th>Description</th>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link SctpStandardSocketOption#SCTP_DISABLE_FRAGMENTS
+ *                                          SCTP_DISABLE_FRAGMENTS} </td>
+ *     <td> Enables or disables message fragmentation </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link SctpStandardSocketOption#SCTP_EXPLICIT_COMPLETE
+ *                                          SCTP_EXPLICIT_COMPLETE} </td>
+ *     <td> Enables or disables explicit message completion </td>
+ *   </tr>
+ *    <tr>
+ *     <td> {@link SctpStandardSocketOption#SCTP_FRAGMENT_INTERLEAVE
+ *                                          SCTP_FRAGMENT_INTERLEAVE} </td>
+ *     <td> Controls how the presentation of messages occur for the message
+ *          receiver </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link SctpStandardSocketOption#SCTP_INIT_MAXSTREAMS
+ *                                          SCTP_INIT_MAXSTREAMS} </td>
+ *     <td> The maximum number of streams requested by the local endpoint during
+ *          association initialization </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link SctpStandardSocketOption#SCTP_NODELAY SCTP_NODELAY} </td>
+ *     <td> Enables or disable a Nagle-like algorithm </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link SctpStandardSocketOption#SCTP_PRIMARY_ADDR
+ *                                          SCTP_PRIMARY_ADDR} </td>
+ *     <td> Requests that the local SCTP stack use the given peer address as the
+ *          association primary </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link SctpStandardSocketOption#SCTP_SET_PEER_PRIMARY_ADDR
+ *                                          SCTP_SET_PEER_PRIMARY_ADDR} </td>
+ *     <td> Requests that the peer mark the enclosed address as the association
+ *          primary </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link SctpStandardSocketOption#SO_SNDBUF
+ *                                          SO_SNDBUF} </td>
+ *     <td> The size of the socket send buffer </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link SctpStandardSocketOption#SO_RCVBUF
+ *                                          SO_RCVBUF} </td>
+ *     <td> The size of the socket receive buffer </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link SctpStandardSocketOption#SO_LINGER
+ *                                          SO_LINGER} </td>
+ *     <td> Linger on close if data is present (when configured in blocking mode
+ *          only) </td>
+ *   </tr>
+ * </table>
+ * </blockquote>
+ * Additional (implementation specific) options may also be supported. The list
+ * of options supported is obtained by invoking the {@link #supportedOptions()
+ * supportedOptions}  method.
+ *
+ * <p> SCTP channels are safe for use by multiple concurrent threads.
+ * They support concurrent reading and writing, though at most one thread may be
+ * reading and at most one thread may be writing at any given time. The
+ * {@link #connect connect} and {@link #finishConnect
+ * finishConnect} methods are mutually synchronized against each other, and
+ * an attempt to initiate a send or receive operation while an invocation of one
+ * of these methods is in progress will block until that invocation is complete.
+ *
+ * @since 1.7
+ */
+public abstract class SctpChannel
+    extends AbstractSelectableChannel
+{
+    /**
+     * Initializes a new instance of this class.
+     *
+     * @param  provider
+     *         The selector provider for this channel
+     */
+    protected SctpChannel(SelectorProvider provider) {
+        super(provider);
+    }
+
+    /**
+     * Opens an SCTP channel.
+     *
+     * <P> The new channel is unbound and unconnected.
+     *
+     * @return  A new SCTP channel
+     *
+     * @throws  UnsupportedOperationException
+     *          If the SCTP protocol is not supported
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public static SctpChannel open() throws
+        IOException {
+        return new sun.nio.ch.SctpChannelImpl((SelectorProvider)null);
+    }
+
+    /**
+     * Opens an SCTP channel and connects it to a remote address.
+     *
+     * <P> This is a convenience method and is equivalent to evaluating the
+     * following expression:
+     * <blockquote><pre>
+     * open().connect(remote, maxOutStreams, maxInStreams);
+     * </pre></blockquote>
+     *
+     * @param  remote
+     *         The remote address to which the new channel is to be connected
+     *
+     * @param  maxOutStreams
+     *         The number of streams that the application wishes to be able
+     *         to send to. Must be non negative and no larger than {@code 65536}.
+     *         {@code 0} to use the endpoints default value.
+     *
+     * @param  maxInStreams
+     *         The maximum number of inbound streams the application is prepared
+     *         to support. Must be non negative and no larger than {@code 65536}.
+     *         {@code 0} to use the endpoints default value.
+     *
+     * @return  A new SCTP channel connected to the given address
+     *
+     * @throws  java.nio.channels.AsynchronousCloseException
+     *          If another thread closes this channel
+     *          while the connect operation is in progress
+     *
+     * @throws  java.nio.channels.ClosedByInterruptException
+     *          If another thread interrupts the current thread
+     *          while the connect operation is in progress, thereby
+     *          closing the channel and setting the current thread's
+     *          interrupt status
+     *
+     * @throws  java.nio.channels.UnresolvedAddressException
+     *          If the given remote address is not fully resolved
+     *
+     * @throws  java.nio.channels.UnsupportedAddressTypeException
+     *          If the type of the given remote address is not supported
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed
+     *          and it does not permit access to the given remote peer
+     *
+     * @throws  UnsupportedOperationException
+     *          If the SCTP protocol is not supported
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public static SctpChannel open(SocketAddress remote, int maxOutStreams,
+                   int maxInStreams) throws IOException {
+        SctpChannel ssc = SctpChannel.open();
+        ssc.connect(remote, maxOutStreams, maxInStreams);
+        return ssc;
+    }
+
+    /**
+     * Returns the association on this channel's socket.
+     *
+     * @return  the association, or {@code null} if the channel's socket is not
+     *          connected.
+     *
+     * @throws  ClosedChannelException
+     *          If the channel is closed
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract Association association() throws IOException;
+
+    /**
+     * Binds the channel's socket to a local address.
+     *
+     * <P> This method is used to establish a relationship between the socket
+     * and the local addresses. Once a relationship is established then
+     * the socket remains bound until the channel is closed. This relationship
+     * may not necesssarily be with the address {@code local} as it may be removed
+     * by {@link #unbindAddress unbindAddress}, but there will always be at least
+     * one local address bound to the channel's socket once an invocation of
+     * this method successfully completes.
+     *
+     * <P> Once the channel's socket has been successfully bound to a specific
+     * address, that is not automatically assigned, more addresses
+     * may be bound to it using {@link #bindAddress bindAddress}, or removed
+     * using {@link #unbindAddress unbindAddress}.
+     *
+     * @param  local
+     *         The local address to bind the socket, or {@code null} to
+     *         bind the socket to an automatically assigned socket address
+     *
+     * @return  This channel
+     *
+     * @throws  java.nio.channels.AlreadyConnectedException
+     *          If this channel is already connected
+     *
+     * @throws  java.nio.channels.ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  java.nio.channels.ConnectionPendingException
+     *          If a non-blocking connection operation is already in progress on this channel
+     *
+     * @throws  java.nio.channels.AlreadyBoundException
+     *          If this channel is already bound
+     *
+     * @throws  java.nio.channels.UnsupportedAddressTypeException
+     *          If the type of the given address is not supported
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract SctpChannel bind(SocketAddress local)
+        throws IOException;
+
+    /**
+     * Adds the given address to the bound addresses for the channel's
+     * socket.
+     *
+     * <P> The given address must not be the {@link
+     * java.net.InetAddress#isAnyLocalAddress wildcard} address.
+     * The channel must be first bound using {@link #bind bind} before
+     * invoking this method, otherwise {@link
+     * java.nio.channels.NotYetBoundException} is thrown. The {@link #bind bind}
+     * method takes a {@code SocketAddress} as its argument which typically
+     * contains a port number as well as an address. Addresses subquently bound
+     * using this method are simply addresses as the SCTP port number remains
+     * the same for the lifetime of the channel.
+     *
+     * <P> Adding addresses to a connected association is optional functionality.
+     * If the endpoint supports dynamic address reconfiguration then it may
+     * send the appropriate message to the peer to change the peers address
+     * lists.
+     *
+     * @param  address
+     *         The address to add to the bound addresses for the socket
+     *
+     * @return  This channel
+     *
+     * @throws  java.nio.channels.ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  java.nio.channels.ConnectionPendingException
+     *          If a non-blocking connection operation is already in progress on
+     *          this channel
+     *
+     * @throws  java.nio.channels.NotYetBoundException
+     *          If this channel is not yet bound
+     *
+     * @throws  java.nio.channels.AlreadyBoundException
+     *          If this channel is already bound to the given address
+     *
+     * @throws  IllegalArgumentException
+     *          If address is {@code null} or the {@link
+     *          java.net.InetAddress#isAnyLocalAddress wildcard} address
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract SctpChannel bindAddress(InetAddress address)
+         throws IOException;
+
+    /**
+     * Removes the given address from the bound addresses for the channel's
+     * socket.
+     *
+     * <P> The given address must not be the {@link
+     * java.net.InetAddress#isAnyLocalAddress wildcard} address.
+     * The channel must be first bound using {@link #bind bind} before
+     * invoking this method, otherwise {@link java.nio.channels.NotYetBoundException}
+     * is thrown. If this method is invoked on a channel that does not have
+     * {@code address} as one of its bound addresses or that has only one
+     * local address bound to it, then this method throws
+     * {@link IllegalUnbindException}.
+     * The initial address that the channel's socket is bound to using {@link
+     * #bind bind} may be removed from the bound addresses for the channel's socket.
+     *
+     * <P> Removing addresses from a connected association is optional
+     * functionality. If the endpoint supports dynamic address reconfiguration
+     * then it may send the appropriate message to the peer to change the peers
+     * address lists.
+     *
+     * @param  address
+     *         The address to remove from the bound addresses for the socket
+     *
+     * @return  This channel
+     *
+     * @throws  java.nio.channels.ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  java.nio.channels.ConnectionPendingException
+     *          If a non-blocking connection operation is already in progress on
+     *          this channel
+     *
+     * @throws  java.nio.channels.NotYetBoundException
+     *          If this channel is not yet bound
+     *
+     * @throws  IllegalArgumentException
+     *          If address is {@code null} or the {@link
+     *          java.net.InetAddress#isAnyLocalAddress wildcard} address
+     *
+     * @throws  IllegalUnbindException
+     *          If {@code address} is not bound to the channel's socket. or
+     *          the channel has only one address bound to it
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract SctpChannel unbindAddress(InetAddress address)
+         throws IOException;
+
+    /**
+     * Connects this channel's socket.
+     *
+     * <P> If this channel is in non-blocking mode then an invocation of this
+     * method initiates a non-blocking connection operation.  If the connection
+     * is established immediately, as can happen with a local connection, then
+     * this method returns {@code true}.  Otherwise this method returns
+     * {@code false} and the connection operation must later be completed by
+     * invoking the {@link #finishConnect finishConnect} method.
+     *
+     * <P> If this channel is in blocking mode then an invocation of this
+     * method will block until the connection is established or an I/O error
+     * occurs.
+     *
+     * <P> If a security manager has been installed then this method verifies
+     * that its {@link java.lang.SecurityManager#checkConnect checkConnect}
+     * method permits connecting to the address and port number of the given
+     * remote peer.
+     *
+     * <p> This method may be invoked at any time. If a {@link #send send} or
+     * {@link #receive receive} operation upon this channel is invoked while an
+     * invocation of this method is in progress then that operation will first
+     * block until this invocation is complete.  If a connection attempt is
+     * initiated but fails, that is, if an invocation of this method throws a
+     * checked exception, then the channel will be closed.
+     *
+     * @param  remote
+     *         The remote peer to which this channel is to be connected
+     *
+     * @return  {@code true} if a connection was established, {@code false} if
+     *          this channel is in non-blocking mode and the connection
+     *          operation is in progress
+     *
+     * @throws  java.nio.channels.AlreadyConnectedException
+     *          If this channel is already connected
+     *
+     * @throws  java.nio.channels.ConnectionPendingException
+     *          If a non-blocking connection operation is already in progress on
+     *          this channel
+     *
+     * @throws  java.nio.channels.ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  java.nio.channels.AsynchronousCloseException
+     *          If another thread closes this channel
+     *          while the connect operation is in progress
+     *
+     * @throws  java.nio.channels.ClosedByInterruptException
+     *          If another thread interrupts the current thread
+     *          while the connect operation is in progress, thereby
+     *          closing the channel and setting the current thread's
+     *          interrupt status
+     *
+     * @throws  java.nio.channels.UnresolvedAddressException
+     *          If the given remote address is not fully resolved
+     *
+     * @throws  java.nio.channels.UnsupportedAddressTypeException
+     *          If the type of the given remote address is not supported
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed
+     *          and it does not permit access to the given remote peer
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract boolean connect(SocketAddress remote) throws IOException;
+
+    /**
+     * Connects this channel's socket.
+     *
+     * <P> This is a convience method and is equivalent to evaluating the
+     * following expression:
+     * <blockquote><pre>
+     * setOption(SctpStandardSocketOption.SCTP_INIT_MAXSTREAMS, SctpStandardSocketOption.InitMaxStreams.create(maxInStreams, maxOutStreams))
+     *  .connect(remote);
+     * </pre></blockquote>
+     *
+     * <P> The {@code maxOutStreams} and {@code maxInStreams} parameters
+     * represent the maximum number of streams that the application wishes to be
+     * able to send to and receive from. They are negotiated with the remote
+     * peer and may be limited by the operating system.
+     *
+     * @param  remote
+     *         The remote peer to which this channel is to be connected
+     *
+     * @param  maxOutStreams
+     *         Must be non negative and no larger than {@code 65536}.
+     *         {@code 0} to use the endpoints default value.
+     *
+     * @param  maxInStreams
+     *         Must be non negative and no larger than {@code 65536}.
+     *         {@code 0} to use the endpoints default value.
+     *
+     * @return  {@code true} if a connection was established, {@code false} if
+     *          this channel is in non-blocking mode and the connection operation
+     *          is in progress
+     *
+     * @throws  java.nio.channels.AlreadyConnectedException
+     *          If this channel is already connected
+     *
+     * @throws  java.nio.channels.ConnectionPendingException
+     *          If a non-blocking connection operation is already in progress on
+     *          this channel
+     *
+     * @throws  java.nio.channels.ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  java.nio.channels.AsynchronousCloseException
+     *          If another thread closes this channel
+     *          while the connect operation is in progress
+     *
+     * @throws  java.nio.channels.ClosedByInterruptException
+     *          If another thread interrupts the current thread
+     *          while the connect operation is in progress, thereby
+     *          closing the channel and setting the current thread's
+     *          interrupt status
+     *
+     * @throws  java.nio.channels.UnresolvedAddressException
+     *          If the given remote address is not fully resolved
+     *
+     * @throws  java.nio.channels.UnsupportedAddressTypeException
+     *          If the type of the given remote address is not supported
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed
+     *          and it does not permit access to the given remote peer
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract boolean connect(SocketAddress remote,
+                                    int maxOutStreams,
+                                    int maxInStreams)
+        throws IOException;
+
+    /**
+     * Tells whether or not a connection operation is in progress on this channel.
+     *
+     * @return  {@code true} if, and only if, a connection operation has been initiated
+     *          on this channel but not yet completed by invoking the
+     *          {@link #finishConnect} method
+     */
+    public abstract boolean isConnectionPending();
+
+    /**
+     * Finishes the process of connecting an SCTP channel.
+     *
+     * <P> A non-blocking connection operation is initiated by placing a socket
+     * channel in non-blocking mode and then invoking one of its {@link #connect
+     * connect} methods.  Once the connection is established, or the attempt has
+     * failed, the channel will become connectable and this method may
+     * be invoked to complete the connection sequence.  If the connection
+     * operation failed then invoking this method will cause an appropriate
+     * {@link java.io.IOException} to be thrown.
+     *
+     * <P> If this channel is already connected then this method will not block
+     * and will immediately return <tt>true</tt>.  If this channel is in
+     * non-blocking mode then this method will return <tt>false</tt> if the
+     * connection process is not yet complete.  If this channel is in blocking
+     * mode then this method will block until the connection either completes
+     * or fails, and will always either return <tt>true</tt> or throw a checked
+     * exception describing the failure.
+     *
+     * <P> This method may be invoked at any time. If a {@link #send send} or {@link #receive receive}
+     * operation upon this channel is invoked while an invocation of this
+     * method is in progress then that operation will first block until this
+     * invocation is complete.  If a connection attempt fails, that is, if an
+     * invocation of this method throws a checked exception, then the channel
+     * will be closed.
+     *
+     * @return  {@code true} if, and only if, this channel's socket is now
+     *          connected
+     *
+     * @throws  java.nio.channels.NoConnectionPendingException
+     *          If this channel is not connected and a connection operation
+     *          has not been initiated
+     *
+     * @throws  java.nio.channels.ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  java.nio.channels.AsynchronousCloseException
+     *          If another thread closes this channel
+     *          while the connect operation is in progress
+     *
+     * @throws  java.nio.channels.ClosedByInterruptException
+     *          If another thread interrupts the current thread
+     *          while the connect operation is in progress, thereby
+     *          closing the channel and setting the current thread's
+     *          interrupt status
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract boolean finishConnect() throws IOException;
+
+    /**
+     * Returns all of the socket addresses to which this channel's socket is
+     * bound.
+     *
+     * @return  All the socket addresses that this channel's socket is
+     *          bound to, or an empty {@code Set} if the channel's socket is not
+     *          bound
+     *
+     * @throws  ClosedChannelException
+     *          If the channel is closed
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public abstract Set<SocketAddress> getAllLocalAddresses()
+        throws IOException;
+
+    /**
+     * Returns all of the remote addresses to which this channel's socket
+     * is connected.
+     *
+     * <P> If the channel is connected to a remote peer that is bound to
+     * multiple addresses then it is these addresses that the channel's socket
+     * is connected.
+     *
+     * @return  All of the remote addresses to which this channel's socket
+     *          is connected, or an empty {@code Set} if the channel's socket is
+     *          not connected
+     *
+     * @throws  ClosedChannelException
+     *          If the channel is closed
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public abstract Set<SocketAddress> getRemoteAddresses()
+        throws IOException;
+
+    /**
+     * Shutdown a connection without closing the channel.
+     *
+     * <P> Sends a shutdown command to the remote peer, effectively preventing
+     * any new data from being written to the socket by either peer. Further
+     * sends will throw {@link java.nio.channels.ClosedChannelException}. The
+     * channel remains open to allow the for any data (and notifications) to be
+     * received that may have been sent by the peer before it received the
+     * shutdown command. If the channel is already shutdown then invoking this
+     * method has no effect.
+     *
+     * @return  This channel
+     *
+     * @throws  java.nio.channels.NotYetConnectedException
+     *          If this channel is not yet connected
+     *
+     * @throws  java.nio.channels.ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract SctpChannel shutdown() throws IOException;
+
+    /**
+     * Returns the value of a socket option.
+     *
+     * @param   name
+     *          The socket option
+     *
+     * @return  The value of the socket option. A value of {@code null} may be
+     *          a valid value for some socket options.
+     *
+     * @throws  UnsupportedOperationException
+     *          If the socket option is not supported by this channel
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @see SctpStandardSocketOption
+     */
+    public abstract <T> T getOption(SctpSocketOption<T> name)
+        throws IOException;
+
+    /**
+     * Sets the value of a socket option.
+     *
+     * @param   name
+     *          The socket option
+     *
+     * @param   value
+     *          The value of the socket option. A value of {@code null} may be
+     *          a valid value for some socket options.
+     *
+     * @return  This channel
+     *
+     * @throws  UnsupportedOperationException
+     *          If the socket option is not supported by this channel
+     *
+     * @throws  IllegalArgumentException
+     *          If the value is not a valid value for this socket option
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @see SctpStandardSocketOption
+     */
+    public abstract <T> SctpChannel setOption(SctpSocketOption<T> name, T value)
+        throws IOException;
+
+    /**
+     * Returns a set of the socket options supported by this channel.
+     *
+     * <P> This method will continue to return the set of options even after the
+     * channel has been closed.
+     *
+     * @return  A set of the socket options supported by this channel
+     */
+    public abstract Set<SctpSocketOption<?>> supportedOptions();
+
+    /**
+     * Returns an operation set identifying this channel's supported operations.
+     *
+     * <P> SCTP channels support connecting, reading, and writing, so this
+     * method returns <tt>(</tt>{@link SelectionKey#OP_CONNECT}
+     * <tt>|</tt>&nbsp;{@link SelectionKey#OP_READ} <tt>|</tt>&nbsp;{@link
+     * SelectionKey#OP_WRITE}<tt>)</tt>.  </p>
+     *
+     * @return  The valid-operation set
+     */
+    @Override
+    public final int validOps() {
+        return (SelectionKey.OP_READ |
+                SelectionKey.OP_WRITE |
+                SelectionKey.OP_CONNECT);
+    }
+
+    /**
+     * Receives a message into the given buffer and/or handles a notification.
+     *
+     * <P> If a message or notification is immediately available, or if this
+     * channel is in blocking mode and one eventually becomes available, then
+     * the message or notification is returned or handled, respectively. If this
+     * channel is in non-blocking mode and a message or notification is not
+     * immediately available then this method immediately returns {@code null}.
+     *
+     * <P> If this method receives a message it is copied into the given byte
+     * buffer. The message is transferred into the given byte buffer starting at
+     * its current position and the buffers position is incremented by the
+     * number of bytes read. If there are fewer bytes remaining in the buffer
+     * than are required to hold the message, or the underlying input buffer
+     * does not contain the complete message, then an invocation of {@link
+     * MessageInfo#isComplete isComplete} on the returned {@code
+     * MessageInfo} will return {@code false}, and more invocations of this
+     * method will be necessary to completely consume the messgae. Only
+     * one message at a time will be partially delivered in any stream. The
+     * socket option {@link SctpStandardSocketOption#SCTP_FRAGMENT_INTERLEAVE
+     * SCTP_FRAGMENT_INTERLEAVE} controls various aspects of what interlacing of
+     * messages occurs.
+     *
+     * <P> If this method receives a notification then the appropriate method of
+     * the given handler, if there is one, is invoked. If the handler returns
+     * {@link HandlerResult#CONTINUE CONTINUE} then this method will try to
+     * receive another message/notification, otherwise, if {@link
+     * HandlerResult#RETURN RETURN} is returned this method will return {@code
+     * null}. If an uncaught exception is thrown by the handler it will be
+     * propagated up the stack through this method.
+     *
+     * <P> This method may be invoked at any time. If another thread has
+     * already initiated a receive operation upon this channel, then an
+     * invocation of this method will block until the first operation is
+     * complete. The given handler is invoked without holding any locks used
+     * to enforce the above synchronization policy, that way handlers
+     * will not stall other threads from receiving. A handler should not invoke
+     * the {@code receive} method of this channel, if it does an
+     * {@link IllegalReceiveException} will be thrown.
+     *
+     * @param  dst
+     *         The buffer into which message bytes are to be transferred
+     *
+     * @param  attachment
+     *         The object to attach to the receive operation; can be
+     *         {@code null}
+     *
+     * @param  handler
+     *         A handler to handle notifications from the SCTP stack, or {@code
+     *         null} to ignore any notifications.
+     *
+     * @return  The {@code MessageInfo}, {@code null} if this channel is in
+     *          non-blocking mode and no messages are immediately available or
+     *          the notification handler returns {@link HandlerResult#RETURN
+     *          RETURN} after handling a notification
+     *
+     * @throws  java.nio.channels.ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  java.nio.channels.AsynchronousCloseException
+     *          If another thread closes this channel
+     *          while the read operation is in progress
+     *
+     * @throws  java.nio.channels.ClosedByInterruptException
+     *          If another thread interrupts the current thread
+     *          while the read operation is in progress, thereby
+     *          closing the channel and setting the current thread's
+     *          interrupt status
+     *
+     * @throws  java.nio.channels.NotYetConnectedException
+     *          If this channel is not yet connected
+     *
+     * @throws  IllegalReceiveException
+     *          If the given handler invokes the {@code receive} method of this
+     *          channel
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract <T> MessageInfo receive(ByteBuffer dst,
+                                            T attachment,
+                                            NotificationHandler<T> handler)
+        throws IOException;
+
+    /**
+     * Sends a message via this channel.
+     *
+     * <P> If this channel is in non-blocking mode and there is sufficient room
+     * in the underlying output buffer, or if this channel is in blocking mode
+     * and sufficient room becomes available, then the remaining bytes in the
+     * given byte buffer are transmitted as a single message. Sending a message
+     * is atomic unless explicit message completion {@link
+     * SctpStandardSocketOption#SCTP_EXPLICIT_COMPLETE SCTP_EXPLICIT_COMPLETE}
+     * socket option is enabled on this channel's socket.
+     *
+     * <P> The message is transferred from the byte buffer as if by a regular
+     * {@link java.nio.channels.WritableByteChannel#write(java.nio.ByteBuffer)
+     * write} operation.
+     *
+     * <P> The bytes will be written to the stream number that is specified by
+     * {@link MessageInfo#streamNumber streamNumber} in the given {@code
+     * messageInfo}.
+     *
+     * <P> This method may be invoked at any time. If another thread has already
+     * initiated a send operation upon this channel, then an invocation of
+     * this method will block until the first operation is complete.
+     *
+     * @param  src
+     *         The buffer containing the message to be sent
+     *
+     * @param  messageInfo
+     *         Ancillary data about the message to be sent
+     *
+     * @return  The number of bytes sent, which will be either the number of
+     *          bytes that were remaining in the messages buffer when this method
+     *          was invoked or, if this channel is non-blocking, may be zero if
+     *          there was insufficient room for the message in the underlying
+     *          output buffer
+     *
+     * @throws  InvalidStreamExcepton
+     *          If {@code streamNumner} is negative or greater than or equal to
+     *          the maximum number of outgoing streams
+     *
+     * @throws  java.nio.channels.ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  java.nio.channels.AsynchronousCloseException
+     *          If another thread closes this channel
+     *          while the read operation is in progress
+     *
+     * @throws  java.nio.channels.ClosedByInterruptException
+     *          If another thread interrupts the current thread
+     *          while the read operation is in progress, thereby
+     *          closing the channel and setting the current thread's
+     *          interrupt status
+     *
+     * @throws  java.nio.channels.NotYetConnectedException
+     *          If this channel is not yet connected
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract int send(ByteBuffer src, MessageInfo messageInfo)
+        throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/nio/sctp/SctpMultiChannel.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,731 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.nio.sctp;
+
+import java.net.SocketAddress;
+import java.net.InetAddress;
+import java.io.IOException;
+import java.util.Set;
+import java.nio.ByteBuffer;
+import java.nio.channels.spi.AbstractSelectableChannel;
+import java.nio.channels.spi.SelectorProvider;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.NotYetBoundException;
+import java.nio.channels.SelectionKey;
+
+/**
+ * A selectable channel for message-oriented SCTP sockets.
+ *
+ * <P> An SCTP multi channel supports many associations on a single socket.
+ * An {@code SctpMultiChannel} is created by invoking the
+ * {@link #open open} method of this class. A newly-created channel is open but
+ * not yet bound. An attempt to invoke the {@link #receive receive} method of an
+ * unbound channel will cause the {@link NotYetBoundException}
+ * to be thrown. An attempt to invoke the {@link #send send} method of an
+ * unbound channel will cause it to first invoke the {@link #bind bind} method.
+ * The address(es) that the channel's socket is bound to can be retrieved by
+ * calling {@link #getAllLocalAddresses getAllLocalAddresses}.
+ *
+ * <P> Messages may be sent and received without explicitly setting up an
+ * association with the remote peer. The channel will implicitly setup
+ * a new association whenever it sends or receives a message from a remote
+ * peer if there is not already an association with that peer. Upon successful
+ * association setup, an {@link AssociationChangeNotification
+ * association changed} notification will be put to the SCTP stack with its
+ * {@code event} parameter set to {@link
+ * AssociationChangeNotification.AssocChangeEvent#COMM_UP
+ * COMM_UP}. This notification can be received by invoking {@link #receive
+ * receive}.
+ *
+ * <P> Socket options are configured using the
+ * {@link #setOption(SctpSocketOption,Object,Association) setOption} method. An
+ * {@code SctpMultiChannel} supports the following options:
+ * <blockquote>
+ * <table border>
+ *   <tr>
+ *     <th>Option Name</th>
+ *     <th>Description</th>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link SctpStandardSocketOption#SCTP_DISABLE_FRAGMENTS
+ *                                          SCTP_DISABLE_FRAGMENTS} </td>
+ *     <td> Enables or disables message fragmentation </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link SctpStandardSocketOption#SCTP_EXPLICIT_COMPLETE
+ *                                          SCTP_EXPLICIT_COMPLETE} </td>
+ *     <td> Enables or disables explicit message completion </td>
+ *   </tr>
+ *    <tr>
+ *     <td> {@link SctpStandardSocketOption#SCTP_FRAGMENT_INTERLEAVE
+ *                                          SCTP_FRAGMENT_INTERLEAVE} </td>
+ *     <td> Controls how the presentation of messages occur for the message
+ *          receiver </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link SctpStandardSocketOption#SCTP_INIT_MAXSTREAMS
+ *                                          SCTP_INIT_MAXSTREAMS} </td>
+ *     <td> The maximum number of streams requested by the local endpoint during
+ *          association initialization </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link SctpStandardSocketOption#SCTP_NODELAY SCTP_NODELAY} </td>
+ *     <td> Enables or disable a Nagle-like algorithm </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link SctpStandardSocketOption#SCTP_PRIMARY_ADDR
+ *                                          SCTP_PRIMARY_ADDR} </td>
+ *     <td> Requests that the local SCTP stack use the given peer address as the
+ *          association primary </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link SctpStandardSocketOption#SCTP_SET_PEER_PRIMARY_ADDR
+ *                                          SCTP_SET_PEER_PRIMARY_ADDR} </td>
+ *     <td> Requests that the peer mark the enclosed address as the association
+ *          primary </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link SctpStandardSocketOption#SO_SNDBUF
+ *                                          SO_SNDBUF} </td>
+ *     <td> The size of the socket send buffer </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link SctpStandardSocketOption#SO_RCVBUF
+ *                                          SO_RCVBUF} </td>
+ *     <td> The size of the socket receive buffer </td>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link SctpStandardSocketOption#SO_LINGER
+ *                                          SO_LINGER} </td>
+ *     <td> Linger on close if data is present (when configured in blocking mode
+ *          only) </td>
+ *   </tr>
+ * </table>
+ * </blockquote>
+ * Additional (implementation specific) options may also be supported. The list
+ * of options supported is obtained by invoking the {@link #supportedOptions()
+ * supportedOptions} method.
+ *
+ * <p> SCTP multi channels are safe for use by multiple concurrent threads.
+ * They support concurrent sending and receiving, though at most one thread may be
+ * sending and at most one thread may be receiving at any given time.
+ *
+ * @since 1.7
+ */
+public abstract class SctpMultiChannel
+    extends AbstractSelectableChannel
+{
+    /**
+     * Initializes a new instance of this class.
+     *
+     * @param  provider
+     *         The selector provider for this channel
+     */
+    protected SctpMultiChannel(SelectorProvider provider) {
+        super(provider);
+    }
+
+    /**
+     * Opens an SCTP multi channel.
+     *
+     * <P> The new channel is unbound.
+     *
+     * @return  A new SCTP multi channel
+     *
+     * @throws UnsupportedOperationException
+     *         If the SCTP protocol is not supported
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public static SctpMultiChannel open() throws
+        IOException {
+        return new sun.nio.ch.SctpMultiChannelImpl((SelectorProvider)null);
+    }
+
+    /**
+     * Returns the open associations on this channel's socket.
+     *
+     * <P> Only associations whose {@link AssociationChangeNotification.AssocChangeEvent#COMM_UP
+     * COMM_UP} association change event has been received are included
+     * in the returned set of associations. Associations for which a
+     * {@link AssociationChangeNotification.AssocChangeEvent#COMM_LOST COMM_LOST} or {@link
+     * AssociationChangeNotification.AssocChangeEvent#SHUTDOWN SHUTDOWN} association change
+     * event have been receive are removed from the set of associations.
+     *
+     * <P> The returned set of associations is a snapshot of the open
+     * associations at the time that this method is invoked.
+     *
+     * @return  A {@code Set} containing the open associations, or an empty
+     *          {@code Set} if there are none.
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract Set<Association> associations()
+        throws IOException;
+
+    /**
+     * Binds the channel's socket to a local address and configures the socket
+     * to listen for connections.
+     *
+     * <P> This method is used to establish a relationship between the socket
+     * and the local address. Once a relationship is established then
+     * the socket remains bound until the channel is closed. This relationship
+     * may not necesssarily be with the address {@code local} as it may be removed
+     * by {@link #unbindAddress unbindAddress}, but there will always be at least one local
+     * address bound to the channel's socket once an invocation of this method
+     * successfully completes.
+     *
+     * <P> Once the channel's socket has been successfully bound to a specific
+     * address, that is not automatically assigned, more addresses
+     * may be bound to it using {@link #bindAddress bindAddress}, or removed
+     * using {@link #unbindAddress unbindAddress}.
+     *
+     * <P> The backlog parameter is the maximum number of pending connections on
+     * the socket. Its exact semantics are implementation specific. An implementation
+     * may impose an implementation specific maximum length or may choose to ignore
+     * the parameter. If the backlog parameter has the value {@code 0}, or a negative
+     * value, then an implementation specific default is used.
+     *
+     * @param  local
+     *         The local address to bind the socket, or {@code null} to
+     *         bind the socket to an automatically assigned socket address
+     *
+     * @param  backlog
+     *         The maximum number number of pending connections
+     *
+     * @return  This channel
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  java.nio.channels.AlreadyBoundException
+     *          If this channel is already bound
+     *
+     * @throws  java.nio.channels.UnsupportedAddressTypeException
+     *          If the type of the given address is not supported
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed and its {@link
+     *          java.lang.SecurityManager#checkListen(int) checkListen} method
+     *          denies the operation
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract SctpMultiChannel bind(SocketAddress local,
+                                          int backlog)
+        throws IOException;
+
+    /**
+     * Binds the channel's socket to a local address and configures the socket
+     * to listen for connections.
+     *
+     * <P> This method works as if invoking it were equivalent to evaluating the
+     * expression:
+     * <blockquote><pre>
+     * bind(local, 0);
+     * </pre></blockquote>
+     *
+     * @param  local
+     *         The local address to bind the socket, or {@code null} to
+     *         bind the socket to an automatically assigned socket address
+     *
+     * @return  This channel
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  java.nio.channels.AlreadyBoundException
+     *          If this channel is already bound
+     *
+     * @throws  java.nio.channels.UnsupportedAddressTypeException
+     *          If the type of the given address is not supported
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed and its {@link
+     *          java.lang.SecurityManager#checkListen(int) checkListen} method
+     *          denies the operation
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public final SctpMultiChannel bind(SocketAddress local)
+        throws IOException {
+        return bind(local, 0);
+    }
+
+    /**
+     * Adds the given address to the bound addresses for the channel's
+     * socket.
+     *
+     * <P> The given address must not be the {@link
+     * java.net.InetAddress#isAnyLocalAddress wildcard} address.
+     * The channel must be first bound using {@link #bind bind} before
+     * invoking this method, otherwise {@link NotYetBoundException} is thrown.
+     * The {@link #bind bind} method takes a {@code SocketAddress} as its
+     * argument which typically contains a port number as well as an address.
+     * Addresses subquently bound using this method are simply addresses as the
+     * SCTP port number remains the same for the lifetime of the channel.
+     *
+     * <P> New associations setup after this method successfully completes
+     * will be associated with the given address. Adding addresses to existing
+     * associations is optional functionality. If the endpoint supports
+     * dynamic address reconfiguration then it may send the appropriate message
+     * to the peer to change the peers address lists.
+     *
+     * @param  address
+     *         The address to add to the bound addresses for the socket
+     *
+     * @return  This channel
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  NotYetBoundException
+     *          If this channel is not yet bound
+     *
+     * @throws  java.nio.channels.AlreadyBoundException
+     *          If this channel is already bound to the given address
+     *
+     * @throws  IllegalArgumentException
+     *          If address is {@code null} or the {@link
+     *          java.net.InetAddress#isAnyLocalAddress wildcard} address
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract SctpMultiChannel bindAddress(InetAddress address)
+         throws IOException;
+
+    /**
+     * Removes the given address from the bound addresses for the channel's
+     * socket.
+     *
+     * <P> The given address must not be the {@link
+     * java.net.InetAddress#isAnyLocalAddress wildcard} address.
+     * The channel must be first bound using {@link #bind bind} before
+     * invoking this method, otherwise {@link NotYetBoundException} is thrown.
+     *
+     * <P> If this method is invoked on a channel that does
+     * not have {@code address} as one of its bound addresses, or that has only
+     * one local address bound to it, then this method throws
+     * {@link IllegalUnbindException}.
+     *
+     * <P> The initial address that the channel's socket is bound to using
+     * {@link #bind bind} may be removed from the bound addresses for the
+     * channel's socket.
+     *
+     * <P> New associations setup after this method successfully completes
+     * will not be associated with the given address. Removing addresses from
+     * existing associations is optional functionality. If the endpoint supports
+     * dynamic address reconfiguration then it may send the appropriate message
+     * to the peer to change the peers address lists.
+     *
+     * @param  address
+     *         The address to remove from the bound addresses for the socket
+     *
+     * @return  This channel
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  NotYetBoundException
+     *          If this channel is not yet bound
+     *
+     * @throws  IllegalUnbindException
+     *          {@code address} is not bound to the channel's socket, or the
+     *          channel has only one address  bound to it
+     *
+     * @throws  IllegalArgumentException
+     *          If address is {@code null} or the {@link
+     *          java.net.InetAddress#isAnyLocalAddress wildcard} address
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract SctpMultiChannel unbindAddress(InetAddress address)
+         throws IOException;
+
+    /**
+     * Returns all of the socket addresses to which this channel's socket is
+     * bound.
+     *
+     * @return  All the socket addresses that this channel's socket is
+     *          bound to, or an empty {@code Set} if the channel's socket is not
+     *          bound
+     *
+     * @throws  ClosedChannelException
+     *          If the channel is closed
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public abstract Set<SocketAddress> getAllLocalAddresses()
+        throws IOException;
+
+    /**
+     * Returns all of the remote addresses to which the given association on
+     * this channel's socket is connected.
+     *
+     * @return  All of the remote addresses for the given association, or
+     *          an empty {@code Set} if the association has been shutdown
+     *
+     * @throws  ClosedChannelException
+     *          If the channel is closed
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public abstract Set<SocketAddress> getRemoteAddresses(Association association)
+        throws IOException;
+
+    /**
+     * Shutdown an association without closing the channel.
+     *
+     * @param  association
+     *         The association to shutdown
+     *
+     * @return  This channel
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract SctpMultiChannel shutdown(Association association)
+            throws IOException;
+
+    /**
+     * Returns the value of a socket option.
+     *
+     * <P> Note that some options are retrieved on the channel's socket,
+     * therefore the {@code association} parameter is not applicable and will be
+     * ignored if given. However, if the option is association specific then the
+     * association must be given.
+     *
+     * @param  name
+     *         The socket option
+     *
+     * @param  association
+     *         The association whose option should be retrieved, or {@code null}
+     *         if this option should be retrieved at the channel's socket level.
+     *
+     * @return  The value of the socket option. A value of {@code null} may be
+     *          a valid value for some socket options.
+     *
+     * @throws  UnsupportedOperationException
+     *          If the socket option is not supported by this channel
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @see SctpStandardSocketOption
+     */
+    public abstract <T> T getOption(SctpSocketOption<T> name,
+                                    Association association)
+        throws IOException;
+
+    /**
+     * Sets the value of a socket option.
+     *
+     * <P> Note that some options are retrieved on the channel's socket,
+     * therefore the {@code association} parameter is not applicable and will be
+     * ignored if given. However, if the option is association specific then the
+     * association must be given.
+     *
+     * @param   name
+     *          The socket option
+     *
+     * @param  association
+     *         The association whose option should be set, or {@code null}
+     *         if this option should be set at the channel's socket level.
+     *
+     * @param   value
+     *          The value of the socket option. A value of {@code null} may be
+     *          a valid value for some socket options.
+     *
+     * @return  This channel
+     *
+     * @throws  UnsupportedOperationException
+     *          If the socket option is not supported by this channel
+     *
+     * @throws  IllegalArgumentException
+     *          If the value is not a valid value for this socket option
+     *
+     * @throws  ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @see SctpStandardSocketOption
+     */
+    public abstract <T> SctpMultiChannel setOption(SctpSocketOption<T> name,
+                                                   T value,
+                                                   Association association)
+         throws IOException;
+
+     /**
+     * Returns a set of the socket options supported by this channel.
+     *
+     * <P> This method will continue to return the set of options even after the
+     * channel has been closed.
+     *
+     * @return  A set of the socket options supported by this channel
+     */
+    public abstract Set<SctpSocketOption<?>> supportedOptions();
+
+    /**
+     * Returns an operation set identifying this channel's supported operations.
+     *
+     * <P> SCTP multi channels support reading, and writing, so this
+     * method returns
+     * {@code (}{@link SelectionKey#OP_READ} {@code |}&nbsp;{@link
+     * SelectionKey#OP_WRITE}{@code )}.  </p>
+     *
+     * @return  The valid-operation set
+     */
+    @Override
+    public final int validOps() {
+        return (SelectionKey.OP_READ |
+                SelectionKey.OP_WRITE );
+    }
+
+    /**
+     * Receives a message and/or handles a notification via this channel.
+     *
+     * <P> If a message or notification is immediately available, or if this
+     * channel is in blocking mode and one eventually becomes available, then
+     * the message or notification is returned or handled, respectively. If this
+     * channel is in non-blocking mode and a message or notification is not
+     * immediately available then this method immediately returns {@code null}.
+     *
+     * <P> If this method receives a message it is copied into the given byte
+     * buffer and an {@link MessageInfo} is returned.
+     * The message is transferred into the given byte buffer starting at its
+     * current position and the buffers position is incremented by the number of
+     * bytes read. If there are fewer bytes remaining in the buffer than are
+     * required to hold the message, or the underlying input buffer does not
+     * contain the complete message, then an invocation of {@link
+     * MessageInfo#isComplete isComplete} on the returned {@code
+     * MessageInfo} will return {@code false}, and more invocations of this
+     * method will be necessary to completely consume the messgae. Only
+     * one message at a time will be partially delivered in any stream. The
+     * socket option {@link SctpStandardSocketOption#SCTP_FRAGMENT_INTERLEAVE
+     * SCTP_FRAGMENT_INTERLEAVE} controls various aspects of what interlacing of
+     * messages occurs.
+     *
+     * <P> If this method receives a notification then the appropriate method of
+     * the given handler, if there is one, is invoked. If the handler returns {@link
+     * HandlerResult#CONTINUE CONTINUE} then this method will try to receive another
+     * message/notification, otherwise, if {@link HandlerResult#RETURN RETURN} is returned
+     * this method will return {@code null}. If an uncaught exception is thrown by the
+     * handler it will be propagated up the stack through this method.
+     *
+     * <P> If a security manager has been installed then for each new association
+     * setup this method verifies that the associations source address and port
+     * number are permitted by the security manager's {@link
+     * java.lang.SecurityManager#checkAccept(String,int) checkAccept} method.
+     *
+     * <P> This method may be invoked at any time. If another thread has
+     * already initiated a receive operation upon this channel, then an
+     * invocation of this method will block until the first operation is
+     * complete. The given handler is invoked without holding any locks used
+     * to enforce the above synchronization policy, that way handlers
+     * will not stall other threads from receiving. A handler should not invoke
+     * the {@code receive} method of this channel, if it does an
+     * {@link IllegalReceiveException} will be thrown.
+     *
+     * @param  buffer
+     *         The buffer into which bytes are to be transferred
+     *
+     * @param  attachment
+     *         The object to attach to the receive operation; can be
+     *         {@code null}
+     *
+     * @param  handler
+     *         A handler to handle notifications from the SCTP stack, or
+     *         {@code null} to ignore any notifications.
+     *
+     * @return  The {@code MessageInfo}, {@code null} if this channel is in
+     *          non-blocking mode and no messages are immediately available or
+     *          the notification handler returns {@code RETURN} after handling
+     *          a notification
+     *
+     * @throws  java.nio.channels.ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  java.nio.channels.AsynchronousCloseException
+     *          If another thread closes this channel
+     *          while the read operation is in progress
+     *
+     * @throws  java.nio.channels.ClosedByInterruptException
+     *          If another thread interrupts the current thread
+     *          while the read operation is in progress, thereby
+     *          closing the channel and setting the current thread's
+     *          interrupt status
+     *
+     * @throws  NotYetBoundException
+     *          If this channel is not yet bound
+     *
+     * @throws  IllegalReceiveException
+     *          If the given handler invokes the {@code receive} method of this
+     *          channel
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed and it does not permit
+     *          new associations to be accepted from the message's sender
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract <T> MessageInfo receive(ByteBuffer buffer,
+                                            T attachment,
+                                            NotificationHandler<T> handler)
+        throws IOException;
+
+    /**
+     * Sends a message via this channel.
+     *
+     * <P> If this channel is unbound then this method will invoke {@link
+     * #bind(SocketAddress, int) bind(null, 0)} before sending any data.
+     *
+     * <P> If there is no association existing between this channel's socket
+     * and the intended receiver, identified by the address in the given messageInfo, then one
+     * will be automatically setup to the intended receiver. This is considered
+     * to be Implicit Association Setup. Upon successful association setup, an
+     * {@link AssociationChangeNotification association changed}
+     * notification will be put to the SCTP stack with its {@code event} parameter set
+     * to {@link AssociationChangeNotification.AssocChangeEvent#COMM_UP COMM_UP}
+     * . This notification can be received by invoking {@link #receive
+     * receive}.
+     *
+     * <P> If this channel is in blocking mode, there is sufficient room in the
+     * underlying output buffer, then the remaining bytes in the given byte
+     * buffer are transmitted as a single message. Sending a message
+     * is atomic unless explicit message completion {@link
+     * SctpStandardSocketOption#SCTP_EXPLICIT_COMPLETE SCTP_EXPLICIT_COMPLETE}
+     * socket option is enabled on this channel's socket.
+     *
+     * <P> If this channel is in non-blocking mode, there is sufficient room
+     * in the underlying output buffer, and an implicit association setup is
+     * required, then the remaining bytes in the given byte buffer are
+     * transmitted as a single message, subject to {@link
+     * SctpStandardSocketOption#SCTP_EXPLICIT_COMPLETE SCTP_EXPLICIT_COMPLETE}.
+     * If for any reason the message cannot
+     * be delivered an {@link AssociationChangeNotification association
+     * changed} notification is put on the SCTP stack with its {@code event} parameter set
+     * to {@link AssociationChangeNotification.AssocChangeEvent#CANT_START CANT_START}.
+     *
+     * <P> The message is transferred from the byte buffer as if by a regular
+     * {@link java.nio.channels.WritableByteChannel#write(java.nio.ByteBuffer)
+     * write} operation.
+     *
+     * <P> If a security manager has been installed then for each new association
+     * setup this method verifies that the given remote peers address and port
+     * number are permitted by the security manager's {@link
+     * java.lang.SecurityManager#checkConnect(String,int) checkConnect} method.
+     *
+     * <P> This method may be invoked at any time. If another thread has already
+     * initiated a send operation upon this channel, then an invocation of
+     * this method will block until the first operation is complete.
+     *
+     * @param  buffer
+     *         The buffer containing the message to be sent
+     *
+     * @param  messageInfo
+     *         Ancillary data about the message to be sent
+     *
+     * @return  The number of bytes sent, which will be either the number of
+     *          bytes that were remaining in the messages buffer when this method
+     *          was invoked or, if this channel is non-blocking, may be zero if
+     *          there was insufficient room for the message in the underlying
+     *          output buffer
+     *
+     * @throws  InvalidStreamExcepton
+     *          If {@code streamNumber} is negative, or if an association already
+     *          exists and {@code streamNumber} is greater than the maximum number
+     *          of outgoing streams
+     *
+     * @throws  java.nio.channels.ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  java.nio.channels.AsynchronousCloseException
+     *          If another thread closes this channel
+     *          while the read operation is in progress
+     *
+     * @throws  java.nio.channels.ClosedByInterruptException
+     *          If another thread interrupts the current thread
+     *          while the read operation is in progress, thereby
+     *          closing the channel and setting the current thread's
+     *          interrupt status
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed and it does not permit
+     *          new associations to be setup with the the messages's address
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract int send(ByteBuffer buffer, MessageInfo messageInfo)
+        throws IOException;
+
+    /**
+     * Branches off an association.
+     *
+     * <P> An application can invoke this method to branch off an association
+     * into a separate channel. The new bound and connected {@link SctpChannel}
+     * will be created for the association. The branched off association will no
+     * longer be part of this channel.
+     *
+     * <P> This is particularly useful when, for instance, the application
+     * wishes to have a number of sporadic message senders/receivers remain
+     * under the original SCTP multi channel but branch off those
+     * associations carrying high volume data traffic into their own
+     * separate SCTP channels.
+     *
+     * @param  association
+     *         The association to branch off
+     *
+     * @return  The {@code SctpChannel}
+     *
+     * @throws  java.nio.channels.ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract SctpChannel branch(Association association)
+        throws IOException;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/nio/sctp/SctpServerChannel.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,421 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.nio.sctp;
+
+import java.net.SocketAddress;
+import java.net.InetAddress;
+import java.io.IOException;
+import java.util.Set;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.spi.SelectorProvider;
+import java.nio.channels.spi.AbstractSelectableChannel;
+
+/**
+ * A selectable channel for message-oriented listening SCTP sockets.
+ *
+ * <p> An {@code SCTPServerChannel} is created by invoking the
+ * {@link #open open} method of this class. A newly-created SCTP server
+ * channel is open but not yet bound. An attempt to invoke the
+ * {@link #accept accept} method of an unbound channel will cause the
+ * {@link java.nio.channels.NotYetBoundException} to be thrown. An SCTP server
+ * channel can be bound by invoking one of the
+ * {@link #bind(java.net.SocketAddress,int) bind} methods defined by this class.
+ *
+ * <p> Socket options are configured using the
+ * {@link #setOption(SctpSocketOption,Object) setOption} method. SCTP server socket
+ * channels support the following options:
+ * <blockquote>
+ * <table border>
+ *   <tr>
+ *     <th>Option Name</th>
+ *     <th>Description</th>
+ *   </tr>
+ *   <tr>
+ *     <td> {@link SctpStandardSocketOption#SCTP_INIT_MAXSTREAMS
+ *                                          SCTP_INIT_MAXSTREAMS} </td>
+ *     <td> The maximum number of streams requested by the local endpoint during
+ *          association initialization </td>
+ *   </tr>
+ * </table>
+ * </blockquote>
+ * Additional (implementation specific) options may also be supported. The list
+ * of options supported is obtained by invoking the {@link #supportedOptions()
+ * supportedOptions} method.
+ *
+ * <p>SCTP server channels are safe for use by multiple concurrent threads.
+ *
+ * @since 1.7
+ */
+public abstract class SctpServerChannel
+    extends AbstractSelectableChannel
+{
+    /**
+     * Initializes a new instance of this class.
+     *
+     * @param  provider
+     *         The selector provider for this channel
+     */
+    protected SctpServerChannel(SelectorProvider provider) {
+        super(provider);
+    }
+
+    /**
+     * Opens an SCTP server channel.
+     *
+     * <P> The new channel's socket is initially unbound; it must be bound
+     * to a specific address via one of its socket's {@link #bind bind}
+     * methods before associations can be accepted.
+     *
+     * @return  A new SCTP server channel
+     *
+     * @throws  UnsupportedOperationException
+     *          If the SCTP protocol is not supported
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public static SctpServerChannel open() throws
+        IOException {
+        return new sun.nio.ch.SctpServerChannelImpl((SelectorProvider)null);
+    }
+
+    /**
+     * Accepts an association on this channel's socket.
+     *
+     * <P> If this channel is in non-blocking mode then this method will
+     * immediately return {@code null} if there are no pending associations.
+     * Otherwise it will block indefinitely until a new association is
+     * available or an I/O error occurs.
+     *
+     * <P> The {@code SCTPChannel} returned by this method, if any, will be in
+     *  blocking mode regardless of the blocking mode of this channel.
+     *
+     * <P> If a security manager has been installed then for each new
+     * association this method verifies that the address and port number of the
+     * assocaitions's remote peer are permitted by the security manager's {@link
+     * java.lang.SecurityManager#checkAccept(String,int) checkAccept} method.
+     *
+     * @return  The SCTP channel for the new association, or {@code null}
+     *          if this channel is in non-blocking mode and no association is
+     *          available to be accepted
+     *
+     * @throws  java.nio.channels.ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  java.nio.channels.AsynchronousCloseException
+     *          If another thread closes this channel
+     *          while the accept operation is in progress
+     *
+     * @throws  java.nio.channels.ClosedByInterruptException
+     *          If another thread interrupts the current thread
+     *          while the accept operation is in progress, thereby
+     *          closing the channel and setting the current thread's
+     *          interrupt status
+     *
+     * @throws  java.nio.channels.NotYetBoundException
+     *          If this channel's socket has not yet been bound
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed and it does not permit
+     *          access to the remote peer of the new association
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract SctpChannel accept() throws IOException;
+
+    /**
+     * Binds the channel's socket to a local address and configures the socket
+     * to listen for associations.
+     *
+     * <P> This method works as if invoking it were equivalent to evaluating the
+     * expression:
+     * <blockquote><pre>
+     * bind(local, 0);
+     * </pre></blockquote>
+     *
+     * @param  local
+     *         The local address to bind the socket, or {@code null} to
+     *         bind the socket to an automatically assigned socket address
+     *
+     * @return  This channel
+     *
+     * @throws  java.nio.channels.ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  java.nio.channels.AlreadyBoundException
+     *          If this channel is already bound
+     *
+     * @throws  java.nio.channels.UnsupportedAddressTypeException
+     *          If the type of the given address is not supported
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed and its {@link
+     *          java.lang.SecurityManager#checkListen(int) checkListen} method
+     *          denies the operation
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public final SctpServerChannel bind(SocketAddress local)
+        throws IOException {
+        return bind(local, 0);
+    }
+
+    /**
+     * Binds the channel's socket to a local address and configures the socket
+     * to listen for associations.
+     *
+     * <P> This method is used to establish a relationship between the socket
+     * and the local address. Once a relationship is established then
+     * the socket remains bound until the channel is closed. This relationship
+     * may not necesssarily be with the address {@code local} as it may be
+     * removed by {@link #unbindAddress unbindAddress}, but there will always be
+     * at least one local address bound to the channel's socket once an
+     * invocation of this method successfully completes.
+     *
+     * <P> Once the channel's socket has been successfully bound to a specific
+     * address, that is not automatically assigned, more addresses
+     * may be bound to it using {@link #bindAddress bindAddress}, or removed
+     * using {@link #unbindAddress unbindAddress}.
+     *
+     * <P> The backlog parameter is the maximum number of pending associations
+     * on the socket. Its exact semantics are implementation specific. An
+     * implementation may impose an implementation specific maximum length or
+     * may choose to ignore the parameter. If the backlog parameter has the
+     * value {@code 0}, or a negative value, then an implementation specific
+     * default is used.
+     *
+     * @param  local
+     *         The local address to bind the socket, or {@code null} to
+     *         bind the socket to an automatically assigned socket address
+     *
+     * @param  backlog
+     *         The maximum number number of pending associations
+     *
+     * @return  This channel
+     *
+     * @throws  java.nio.channels.ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  java.nio.channels.AlreadyBoundException
+     *          If this channel is already bound
+     *
+     * @throws  java.nio.channels.UnsupportedAddressTypeException
+     *          If the type of the given address is not supported
+     *
+     * @throws  SecurityException
+     *          If a security manager has been installed and its {@link
+     *          java.lang.SecurityManager#checkListen(int) checkListen} method
+     *          denies the operation
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract SctpServerChannel bind(SocketAddress local,
+                                           int backlog)
+        throws IOException;
+
+    /**
+     * Adds the given address to the bound addresses for the channel's
+     * socket.
+     *
+     * <P> The given address must not be the {@link
+     * java.net.InetAddress#isAnyLocalAddress wildcard} address.
+     * The channel must be first bound using {@link #bind bind} before
+     * invoking this method, otherwise {@link
+     * java.nio.channels.NotYetBoundException} is thrown. The {@link #bind bind}
+     * method takes a {@code SocketAddress} as its argument which typically
+     * contains a port number as well as an address. Addresses subquently bound
+     * using this method are simply addresses as the SCTP port number remains
+     * the same for the lifetime of the channel.
+     *
+     * <P> New associations accepted after this method successfully completes
+     * will be associated with the given address.
+     *
+     * @param  address
+     *         The address to add to the bound addresses for the socket
+     *
+     * @return  This channel
+     *
+     * @throws  java.nio.channels.ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  java.nio.channels.NotYetBoundException
+     *          If this channel is not yet bound
+     *
+     * @throws  java.nio.channels.AlreadyBoundException
+     *          If this channel is already bound to the given address
+     *
+     * @throws  IllegalArgumentException
+     *          If address is {@code null} or the {@link
+     *          java.net.InetAddress#isAnyLocalAddress wildcard} address
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract SctpServerChannel bindAddress(InetAddress address)
+         throws IOException;
+
+    /**
+     * Removes the given address from the bound addresses for the channel's
+     * socket.
+     *
+     * <P> The given address must not be the {@link
+     * java.net.InetAddress#isAnyLocalAddress wildcard} address.
+     * The channel must be first bound using {@link #bind bind} before
+     * invoking this method, otherwise
+     * {@link java.nio.channels.NotYetBoundException} is thrown.
+     * If this method is invoked on a channel that does not have
+     * {@code address} as one of its bound addresses, or that has only one
+     * local address bound to it, then this method throws {@link
+     * IllegalUnbindException}.
+     * The initial address that the channel's socket is bound to using
+     * {@link #bind bind} may be removed from the bound addresses for the
+     * channel's socket.
+     *
+     * <P> New associations accepted after this method successfully completes
+     * will not be associated with the given address.
+     *
+     * @param  address
+     *         The address to remove from the bound addresses for the socket
+     *
+     * @return  This channel
+     *
+     * @throws  java.nio.channels.ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  java.nio.channels.NotYetBoundException
+     *          If this channel is not yet bound
+     *
+     * @throws  IllegalArgumentException
+     *          If address is {@code null} or the {@link
+     *          java.net.InetAddress#isAnyLocalAddress wildcard} address
+     *
+     * @throws  IllegalUnbindException
+     *          If the implementation does not support removing addresses from a
+     *          listening socket, {@code address} is not bound to the channel's
+     *          socket, or the channel has only one address bound to it
+     *
+     * @throws  IOException
+     *          If some other I/O error occurs
+     */
+    public abstract SctpServerChannel unbindAddress(InetAddress address)
+         throws IOException;
+
+    /**
+     * Returns all of the socket addresses to which this channel's socket is
+     * bound.
+     *
+     * @return  All the socket addresses that this channel's socket is
+     *          bound to, or an empty {@code Set} if the channel's socket is not
+     *          bound
+     *
+     * @throws  java.nio.channels.ClosedChannelException
+     *          If the channel is closed
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     */
+    public abstract Set<SocketAddress> getAllLocalAddresses()
+        throws IOException;
+
+    /**
+     * Returns the value of a socket option.
+     *
+     * @param   name
+     *          The socket option
+     *
+     * @return  The value of the socket option. A value of {@code null} may be
+     *          a valid value for some socket options.
+     *
+     * @throws  UnsupportedOperationException
+     *          If the socket option is not supported by this channel
+     *
+     * @throws  java.nio.channels.ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @see SctpStandardSocketOption
+     */
+    public abstract <T> T getOption(SctpSocketOption<T> name) throws IOException;
+
+    /**
+     * Sets the value of a socket option.
+     *
+     * @param   name
+     *          The socket option
+     *
+     * @param   value
+     *          The value of the socket option. A value of {@code null} may be
+     *          a valid value for some socket options.
+     *
+     * @return  This channel
+     *
+     * @throws  UnsupportedOperationException
+     *          If the socket option is not supported by this channel
+     *
+     * @throws  IllegalArgumentException
+     *          If the value is not a valid value for this socket option
+     *
+     * @throws  java.nio.channels.ClosedChannelException
+     *          If this channel is closed
+     *
+     * @throws  IOException
+     *          If an I/O error occurs
+     *
+     * @see SctpStandardSocketOption
+     */
+    public abstract <T> SctpServerChannel setOption(SctpSocketOption<T> name,
+                                                    T value)
+        throws IOException;
+
+    /**
+     * Returns a set of the socket options supported by this channel.
+     *
+     * <P> This method will continue to return the set of options even after the
+     * channel has been closed.
+     *
+     * @return  A set of the socket options supported by this channel
+     */
+    public abstract Set<SctpSocketOption<?>> supportedOptions();
+
+    /**
+     * Returns an operation set identifying this channel's supported
+     * operations.
+     *
+     * <P> SCTP server channels only support the accepting of new
+     * associations, so this method returns
+     * {@link java.nio.channels.SelectionKey#OP_ACCEPT}.
+     *
+     * @return  The valid-operation set
+     */
+    @Override
+    public final int validOps() {
+        return SelectionKey.OP_ACCEPT;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/nio/sctp/SctpSocketOption.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.nio.sctp;
+
+import java.net.SocketOption;
+
+/**
+ * A socket option associated with an SCTP channel.
+ *
+ * @param   <T>     The type of the socket option value.
+ *
+ * @since 1.7
+ *
+ * @see SctpStandardSocketOption
+ */
+public interface SctpSocketOption<T> extends SocketOption<T> { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/nio/sctp/SctpStandardSocketOption.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,419 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.nio.sctp;
+
+import java.net.SocketAddress;
+import sun.nio.ch.SctpStdSocketOption;
+
+/**
+ * SCTP channels supports the socket options defined by this class
+ * (as well as those listed in the particular channel class) and may support
+ * additional Implementation specific socket options.
+ *
+ * @since 1.7
+ */
+public class SctpStandardSocketOption {
+    private SctpStandardSocketOption() {}
+    /**
+     * Enables or disables message fragmentation.
+     *
+     * <P> The value of this socket option is a {@code Boolean} that represents
+     * whether the option is enabled or disabled. If enabled no SCTP message
+     * fragmentation will be performed. Instead if a message being sent
+     * exceeds the current PMTU size, the message will NOT be sent and
+     * an error will be indicated to the user.
+     *
+     * <P> It is implementation specific whether or not this option is
+     * supported.
+     */
+    public static final SctpSocketOption<Boolean> SCTP_DISABLE_FRAGMENTS = new
+        SctpStdSocketOption<Boolean>("SCTP_DISABLE_FRAGMENTS", Boolean.class,
+        sun.nio.ch.SctpStdSocketOption.SCTP_DISABLE_FRAGMENTS);
+
+    /**
+     * Enables or disables explicit message completion.
+     *
+     * <p> The value of this socket option is a {@code Boolean} that represents
+     * whether the option is enabled or disabled. When this option is enabled,
+     * the {@code send} method may be invoked multiple times to a send message.
+     * The {@code isComplete} parameter of the {@link MessageInfo} must only
+     * be set to {@code true} for the final send to indicate that the message is
+     * complete. If this option is disabled then each individual {@code send}
+     * invocation is considered complete.
+     *
+     * <P> The default value of the option is {@code false} indicating that the
+     * option is disabled. It is implementation specific whether or not this
+     * option is supported.
+     */
+    public static final SctpSocketOption<Boolean> SCTP_EXPLICIT_COMPLETE = new
+        SctpStdSocketOption<Boolean>("SCTP_EXPLICIT_COMPLETE", Boolean.class,
+        sun.nio.ch.SctpStdSocketOption.SCTP_EXPLICIT_COMPLETE);
+
+    /**
+     * Fragmented interleave controls how the presentation of messages occur
+     * for the message receiver. There are three levels of fragment interleave
+     * defined. Two of the levels effect {@link SctpChannel}, while
+     * {@link SctpMultiChannel} is effected by all three levels.
+     *
+     * <P> This option takes an {@code Integer} value. It can be set to a value
+     * of {@code 0}, {@code 1} or {@code 2}.
+     *
+     * <P> Setting the three levels provides the following receiver
+     * interactions:
+     *
+     * <P> {@code level 0} - Prevents the interleaving of any messages. This
+     * means that when a partial delivery begins, no other messages will be
+     * received except the message being partially delivered. If another message
+     * arrives on a different stream (or association) that could be delivered,
+     * it will be blocked waiting for the user to read all of the partially
+     * delivered message.
+     *
+     * <P> {@code level 1} - Allows interleaving of messages that are from
+     * different associations. For {@code SctpChannel}, level 0 and
+     * level 1 have the same meaning since an {@code SctpChannel} always
+     * receives messages from the same association. Note that setting an {@code
+     * SctpMultiChannel} to this level may cause multiple partial
+     * delivers from different associations but for any given association, only
+     * one message will be delivered until all parts of a message have been
+     * delivered. This means that one large message, being read with an
+     * association identification of "X", will block other messages from
+     * association "X" from being delivered.
+     *
+     * <P> {@code level 2} - Allows complete interleaving of messages. This
+     * level requires that the sender carefully observe not only the peer
+     * {@code Association} but also must pay careful attention to the stream
+     * number. With this option enabled a partially delivered message may begin
+     * being delivered for association "X" stream "Y" and the next subsequent
+     * receive may return a message from association "X" stream "Z". Note that
+     * no other messages would be delivered for association "X" stream "Y"
+     * until all of stream "Y"'s partially delivered message was read.
+     * Note that this option effects both channel types.  Also note that
+     * for an {@code SctpMultiChannel} not only may another streams
+     * message from the same association be delivered from the next receive,
+     * some other associations message may be delivered upon the next receive.
+     *
+     * <P> It is implementation specific whether or not this option is
+     * supported.
+     */
+    public static final SctpSocketOption<Integer> SCTP_FRAGMENT_INTERLEAVE =
+            new SctpStdSocketOption<Integer>("SCTP_FRAGMENT_INTERLEAVE",
+                  Integer.class,
+                  sun.nio.ch.SctpStdSocketOption.SCTP_FRAGMENT_INTERLEAVE);
+
+    /**
+     * The maximum number of streams requested by the local endpoint during
+     * association initialization.
+     *
+     * <P> The value of this socket option is an {@link
+     * SctpStandardSocketOption.InitMaxStreams InitMaxStreams}, that represents
+     * the maximum number of inbound and outbound streams that an association
+     * on the channel is prepared to support.
+     *
+     * <P> For an {@link SctpChannel} this option may only be used to
+     * change the number of inbound/outbound streams prior to connecting.
+     *
+     * <P> For an {@link SctpMultiChannel} this option determines
+     * the maximum number of inbound/outbound streams new associations setup
+     * on the channel will be prepared to support.
+     *
+     * <P> For an {@link SctpServerChannel} this option determines the
+     * maximum number of inbound/outbound streams accepted sockets will
+     * negotiate with their connecting peer.
+     *
+     * <P> In all cases the value set by this option is used in the negotiation
+     * of new associations setup on the channel's socket and the actual
+     * maximum number of inbound/outbound streams that have been negotiated
+     * with the peer can be retrieved from the appropriate {@link
+     * Association}. The {@code Association} can be retrieved from the
+     * {@link AssociationChangeNotification.AssocChangeEvent#COMM_UP COMM_UP}
+     * {@link AssociationChangeNotification} belonging to that association.
+     *
+     * <p> This value is bounded by the actual implementation. In other
+     * words the user may be able to support more streams than the Operating
+     * System. In such a case, the Operating System limit may override the
+     * value requested by the user. The default value of 0 indicates to use
+     * the endpoints default value.
+     */
+    public static final SctpSocketOption
+        <SctpStandardSocketOption.InitMaxStreams> SCTP_INIT_MAXSTREAMS =
+        new SctpStdSocketOption<SctpStandardSocketOption.InitMaxStreams>(
+        "SCTP_INIT_MAXSTREAMS", SctpStandardSocketOption.InitMaxStreams.class);
+
+    /**
+     * Enables or disables a Nagle-like algorithm.
+     *
+     * <P> The value of this socket option is a {@code Boolean} that represents
+     * whether the option is enabled or disabled. SCTP uses an algorithm like
+     * <em>The Nagle Algorithm</em> to coalesce short segments and
+     * improve network efficiency.
+     */
+    public static final SctpSocketOption<Boolean> SCTP_NODELAY =
+        new SctpStdSocketOption<Boolean>("SCTP_NODELAY", Boolean.class,
+        sun.nio.ch.SctpStdSocketOption.SCTP_NODELAY);
+
+    /**
+     * Requests that the local SCTP stack use the given peer address as
+     * the association primary.
+     *
+     * <P> The value of this socket option is a {@code SocketAddress}
+     * that represents the peer address that the local SCTP stack should use as
+     * the association primary. The address must be one of the association
+     * peer's addresses.
+     *
+     * <P> An {@code SctpMultiChannel} can control more than one
+     * association, the association parameter must be given when setting or
+     * retrieving this option.
+     *
+     * <P> Since {@code SctpChannel} only controls one association,
+     * the association parameter is not required and this option can be
+     * set or queried directly.
+     */
+     public static final SctpSocketOption<SocketAddress> SCTP_PRIMARY_ADDR =
+             new SctpStdSocketOption<SocketAddress>
+             ("SCTP_PRIMARY_ADDR", SocketAddress.class);
+
+     /**
+     * Requests that the peer mark the enclosed address as the association
+     * primary.
+     *
+     * <P> The value of this socket option is a {@code SocketAddress}
+     * that represents the local address that the peer should use as its
+     * primary address. The given address must be one of the association's
+     * locally bound addresses.
+     *
+     * <P> An {@code SctpMultiChannel} can control more than one
+     * association, the association parameter must be given when setting or
+     * retrieving this option.
+     *
+     * <P> Since {@code SctpChannel} only controls one association,
+     * the association parameter is not required and this option can be
+     * queried directly.
+     *
+     * <P> Note, this is a set only option and cannot be retrieved by {@code
+     * getOption}. It is implementation specific whether or not this
+     * option is supported.
+     */
+    public static final SctpSocketOption<SocketAddress> SCTP_SET_PEER_PRIMARY_ADDR =
+            new SctpStdSocketOption<SocketAddress>
+            ("SCTP_SET_PEER_PRIMARY_ADDR", SocketAddress.class);
+
+    /**
+     * The size of the socket send buffer.
+     *
+     * <p> The value of this socket option is an {@code Integer} that is the
+     * size of the socket send buffer in bytes. The socket send buffer is an
+     * output buffer used by the networking implementation. It may need to be
+     * increased for high-volume connections. The value of the socket option is
+     * a <em>hint</em> to the implementation to size the buffer and the actual
+     * size may differ. The socket option can be queried to retrieve the actual
+     * size.
+     *
+     * <p> For {@code SctpChannel}, this controls the amount of data
+     * the SCTP stack may have waiting in internal buffers to be sent. This
+     * option therefore bounds the maximum size of data that can be sent in a
+     * single send call.
+     *
+     * <P> For {@code SctpMultiChannel}, the effect is the same as for {@code
+     * SctpChannel}, except that it applies to all associations. The option
+     * applies to each association's window size separately.
+     *
+     * <p> An implementation allows this socket option to be set before the
+     * socket is bound or connected. Whether an implementation allows the
+     * socket send buffer to be changed after the socket is bound is system
+     * dependent.
+     */
+    public static final SctpSocketOption<Integer> SO_SNDBUF =
+        new SctpStdSocketOption<Integer>("SO_SNDBUF", Integer.class,
+        sun.nio.ch.SctpStdSocketOption.SO_SNDBUF);
+
+    /**
+     * The size of the socket receive buffer.
+     *
+     * <P> The value of this socket option is an {@code Integer} that is the
+     * size of the socket receive buffer in bytes. The socket receive buffer is
+     * an input buffer used by the networking implementation. It may need to be
+     * increased for high-volume connections or decreased to limit the possible
+     * backlog of incoming data. The value of the socket option is a
+     * <em>hint</em> to the implementation to size the buffer and the actual
+     * size may differ.
+     *
+     * <P> For {@code SctpChannel}, this controls the receiver window size.
+     *
+     * <P> For {@code SctpMultiChannel}, the meaning is implementation
+     * dependent. It might control the receive buffer for each association bound
+     * to the socket descriptor or it might control the receive buffer for the
+     * whole socket.
+     *
+     * <p> An implementation allows this socket option to be set before the
+     * socket is bound or connected. Whether an implementation allows the
+     * socket receive buffer to be changed after the socket is bound is system
+     * dependent.
+     */
+    public static final SctpSocketOption<Integer> SO_RCVBUF =
+        new SctpStdSocketOption<Integer>("SO_RCVBUF", Integer.class,
+        sun.nio.ch.SctpStdSocketOption.SO_RCVBUF);
+
+    /**
+     * Linger on close if data is present.
+     *
+     * <p> The value of this socket option is an {@code Integer} that controls
+     * the action taken when unsent data is queued on the socket and a method
+     * to close the socket is invoked. If the value of the socket option is zero
+     * or greater, then it represents a timeout value, in seconds, known as the
+     * <em>linger interval</em>. The linger interval is the timeout for the
+     * {@code close} method to block while the operating system attempts to
+     * transmit the unsent data or it decides that it is unable to transmit the
+     * data. If the value of the socket option is less than zero then the option
+     * is disabled. In that case the {@code close} method does not wait until
+     * unsent data is transmitted; if possible the operating system will transmit
+     * any unsent data before the connection is closed.
+     *
+     * <p> This socket option is intended for use with sockets that are configured
+     * in {@link java.nio.channels.SelectableChannel#isBlocking() blocking} mode
+     * only. The behavior of the {@code close} method when this option is
+     * enabled on a non-blocking socket is not defined.
+     *
+     * <p> The initial value of this socket option is a negative value, meaning
+     * that the option is disabled. The option may be enabled, or the linger
+     * interval changed, at any time. The maximum value of the linger interval
+     * is system dependent. Setting the linger interval to a value that is
+     * greater than its maximum value causes the linger interval to be set to
+     * its maximum value.
+     */
+    public static final SctpSocketOption<Integer> SO_LINGER =
+        new SctpStdSocketOption<Integer>("SO_LINGER", Integer.class,
+        sun.nio.ch.SctpStdSocketOption.SO_LINGER);
+
+    /**
+     * This class is used to set the maximum number of inbound/outbound streams
+     * used by the local endpoint during association initialization. An
+     * instance of this class is used to set the {@link
+     * SctpStandardSocketOption#SCTP_INIT_MAXSTREAMS SCTP_INIT_MAXSTREAMS}
+     * socket option.
+     *
+     * @since 1.7
+     */
+    public static class InitMaxStreams {
+        private int maxInStreams;
+        private int maxOutStreams;
+
+        private InitMaxStreams(int maxInStreams, int maxOutStreams) {
+           this.maxInStreams = maxInStreams;
+           this.maxOutStreams = maxOutStreams;
+        }
+
+        /**
+         * Creates an InitMaxStreams instance.
+         *
+         * @param  maxInStreams
+         *         The maximum number of inbound streams, where
+         *         {@code 0 <= maxInStreams <= 65536}
+         *
+         * @param  maxOutStreams
+         *         The maximum number of outbound streams, where
+         *         {@code 0 <= maxOutStreams <= 65536}
+         *
+         * @return  An {@code InitMaxStreams} instance
+         *
+         * @throws  IllegalArgumentException
+         *          If an argument is outside of specified bounds
+         */
+        public static InitMaxStreams create
+              (int maxInStreams, int maxOutStreams) {
+            if (maxOutStreams < 0 || maxOutStreams > 65535)
+                throw new IllegalArgumentException(
+                      "Invalid maxOutStreams value");
+            if (maxInStreams < 0 || maxInStreams > 65535)
+                throw new IllegalArgumentException(
+                      "Invalid maxInStreams value");
+
+            return new InitMaxStreams(maxInStreams, maxOutStreams);
+        }
+
+        /**
+         * Returns the maximum number of inbound streams.
+         *
+         * @return  Maximum inbound streams
+         */
+        public int maxInStreams() {
+            return maxInStreams;
+        }
+
+        /**
+         * Returns the maximum number of outbound streams.
+         *
+         * @return  Maximum outbound streams
+         */
+        public int maxOutStreams() {
+            return maxOutStreams;
+        }
+
+        /**
+         * Returns a string representation of this init max streams, including
+         * the maximum in and out bound streams.
+         *
+         * @return  A string representation of this init max streams
+         */
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append(super.toString()).append(" [");
+            sb.append("maxInStreams:").append(maxInStreams);
+            sb.append("maxOutStreams:").append(maxOutStreams).append("]");
+            return sb.toString();
+        }
+
+        /**
+         * Returns true if the specified object is another {@code InitMaxStreams}
+         * instance with the same number of in and out bound streams.
+         *
+         * @param  obj
+         *         The object to be compared with this init max streams
+         *
+         * @return  true if the specified object is another
+         *          {@code InitMaxStreams} instance with the same number of in
+         *          and out bound streams
+         */
+        @Override
+        public boolean equals(Object obj) {
+            if (obj != null && obj instanceof InitMaxStreams) {
+                InitMaxStreams that = (InitMaxStreams) obj;
+                if (this.maxInStreams == that.maxInStreams &&
+                    this.maxOutStreams == that.maxOutStreams)
+                    return true;
+            }
+            return false;
+        }
+
+        /**
+         * Returns a hash code value for this init max streams.
+         */
+        @Override
+        public int hashCode() {
+            int hash = 7 ^ maxInStreams ^ maxOutStreams;
+            return hash;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/nio/sctp/SendFailedNotification.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.nio.sctp;
+
+import java.nio.ByteBuffer;
+import java.net.SocketAddress;
+
+/**
+ * Notification emitted when a send failed notification has been received.
+ *
+ * <P> A send failed notification indicates that a message cannot be delivered.
+ * Typically this is because the association has been shutdown with unsent data
+ * in the socket output buffer, or in the case of a {@link SctpMultiChannel}
+ * the association failed to setup.
+ *
+ * @since 1.7
+ */
+public abstract class SendFailedNotification implements Notification {
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected SendFailedNotification() {}
+
+    /**
+     * Returns the association that this notification is applicable to.
+     *
+     * @return  The association that failed to send, or {@code null} if
+     *          there is no association, that is, the notification follows a
+     *          {@linkplain
+     *          com.sun.nio.sctp.AssociationChangeNotification.AssocChangeEvent#CANT_START}
+     */
+    @Override
+    public abstract Association association();
+
+    /**
+     * Returns the address.
+     *
+     * @return  The peer primary address of the association or the address that
+     *          the message was sent to
+     */
+    public abstract SocketAddress address();
+
+    /**
+     * Returns the data that was to be sent.
+     *
+     * @return  The user data. The buffers position will be {@code 0} and its
+     *          limit will be set to the end of the data.
+     */
+    public abstract ByteBuffer buffer();
+
+    /**
+     * Returns the error code.
+     *
+     * <P> The errorCode gives the reason why the send failed, and if set, will
+     * be a SCTP protocol error code as defined in RFC2960 section 3.3.10
+     *
+     * @return  The error code
+     */
+    public abstract int errorCode();
+
+    /**
+     * Returns the stream number that the messge was to be sent on.
+     *
+     * @return  The stream number
+     */
+    public abstract int streamNumber();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/nio/sctp/ShutdownNotification.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package com.sun.nio.sctp;
+
+/**
+ * Notification emitted when a peers shutdowns an the association.
+ *
+ * <P> When a peer sends a <i>SHUTDOWN</i>, the SCTP stack delivers this
+ * notification to inform the application that it should cease sending data.
+ *
+ * @since 1.7
+ */
+public abstract class ShutdownNotification implements Notification {
+    /**
+     * Initializes a new instance of this class.
+     */
+    protected ShutdownNotification() {}
+
+    /**
+     * Returns the association that this notification is applicable to.
+     *
+     * @return  The association that received the shutdown
+     */
+    public abstract Association association();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/nio/sctp/package-info.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**
+ * A Java API for Stream Control Transport Protocol.
+ *
+ * <P> The Stream Control Transport Protocol (SCTP) is a reliable,
+ * message-oriented, transport protocol existing at an equivalent level with UDP
+ * (User Datagram Protocol) and TCP (Transmission Control Protocol). SCTP is
+ * session oriented and an association between the endpoints must be established
+ * before any data can be transmitted.
+ *
+ * <P> SCTP has direct support for multi-homing, meaning than an endpoint may be
+ * represented by more than one address and each address may be used for sending
+ * and receiving data, thus providing network redundancy. The connection between
+ * two endpoints is referred to as an association between those endpoints.
+ * Endpoints can exchange a list of addresses during association setup. One
+ * address is designated as the primary address, this is the default address that
+ * the peer will use for sending data. A single port number is used across the
+ * entire address list at an endpoint for a specific session.
+ *
+ * <P> SCTP is message based. I/O operations operate upon messages and message
+ * boundaries are preserved. Each association may support multiple independant
+ * logical streams. Each stream represents a sequence of messages within a single
+ * association and streams are independant of one another, meaning that stream
+ * identifiers and sequence numbers are included in the data packet to allow
+ * sequencing of messages on a per-stream basis.
+ *
+ * <P> This package provides two programming model styles. The one-to-one style
+ * supported by {@link com.sun.nio.sctp.SctpChannel} and {@link
+ * com.sun.nio.sctp.SctpServerChannel}, and the one-to-many
+ * style supported by {@link com.sun.nio.sctp.SctpMultiChannel}.
+ * The semantics of the one-to-one style interface are very similar to TCP.
+ * An {@code SctpChannel} can only control one SCTP association. The
+ * semantics of the one-to-many style interface are very similar to UDP. An
+ * {@code SctpMutliChannel} can control multiple SCTP associations.
+ *
+ * <P> Applications can send and receive per-message ancillary information through
+ * {@link com.sun.nio.sctp.MessageInfo}. For example, the stream number that
+ * the message it is to be sent or received from. The SCTP stack is event driven
+ * and applications can receive notifications of certain SCTP events by invoking
+ * the {@code receive} method of the SCTP channel with an appropriate {@link
+ * com.sun.nio.sctp.NotificationHandler notification handler}.
+ *
+ * <P> The SCTP protocol is defined by
+ * <A HREF="http://tools.ietf.org/html/rfc4960">RFC4960</A>, and the optional
+ * extension for <I>Dynamic Address Reconfiguration</I> is defined by
+ * <A HREF="http://tools.ietf.org/html/rfc5061">RFC5061</A>.
+ *
+ * @since 1.7
+ */
+
+package com.sun.nio.sctp;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/SctpMessageInfoImpl.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package sun.nio.ch;
+
+import java.net.SocketAddress;
+import com.sun.nio.sctp.MessageInfo;
+import com.sun.nio.sctp.Association;
+
+/**
+ * An implementation of a MessageInfo.
+ */
+public class SctpMessageInfoImpl extends MessageInfo {
+    private final SocketAddress address;
+    private final int bytes;          /* 0 */
+
+    private Association association;
+    private int assocId;
+    private int streamNumber;
+    private boolean complete = true;
+    private boolean unordered;  /* false */
+    private long timeToLive;    /* 0L */
+    private int ppid;           /* 0 */
+
+    public SctpMessageInfoImpl(Association association,
+                               SocketAddress address,
+                               int streamNumber) {
+        this.association = association;
+        this.address = address;
+        this.streamNumber = streamNumber;
+        bytes = 0;
+    }
+
+    /* Invoked from native */
+    private SctpMessageInfoImpl(int assocId,
+                                SocketAddress address,
+                                int bytes,
+                                int streamNumber,
+                                boolean complete,
+                                boolean unordered,
+                                int ppid) {
+        this.assocId = assocId;
+        this.address = address;
+        this.bytes = bytes;
+        this.streamNumber = streamNumber;
+        this.complete = complete;
+        this.unordered = unordered;
+        this.ppid = ppid;
+    }
+
+    @Override
+    public Association association() {
+        return association;
+    }
+
+    /**
+     * SctpMessageInfoImpl instances created from native will need to have their
+     * association set from the channel.
+     */
+    void setAssociation(Association association) {
+        this.association = association;
+    }
+
+    int associationID() {
+        return assocId;
+    }
+
+    @Override
+    public SocketAddress address() {
+        return address;
+    }
+
+    @Override
+    public int bytes() {
+        return bytes;
+    }
+
+    @Override
+    public int streamNumber() {
+        return streamNumber;
+    }
+
+    @Override
+    public MessageInfo streamNumber(int streamNumber) {
+        if (streamNumber < 0 || streamNumber > 65536)
+            throw new IllegalArgumentException("Invalid stream number");
+
+        this.streamNumber = streamNumber;
+        return this;
+    }
+
+    @Override
+    public int payloadProtocolID() {
+        return ppid;
+    }
+
+    @Override
+    public MessageInfo payloadProtocolID(int ppid) {
+        this.ppid = ppid;
+        return this;
+    }
+
+    @Override
+    public boolean isComplete() {
+        return complete;
+    }
+
+    @Override
+    public MessageInfo complete(boolean complete) {
+        this.complete = complete;
+        return this;
+    }
+
+    @Override
+    public boolean isUnordered() {
+        return unordered;
+    }
+
+    @Override
+    public MessageInfo unordered(boolean unordered) {
+        this.unordered = unordered;
+        return this;
+    }
+
+    @Override
+    public long timeToLive() {
+        return timeToLive;
+    }
+
+    @Override
+    public MessageInfo timeToLive(long millis) {
+        timeToLive = millis;
+        return this;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder(super.toString());
+        sb.append( "[Address: ").append(address)
+          .append(", Association: ").append(association)
+          .append(", Assoc ID: ").append(assocId)
+          .append(", Bytes: ").append(bytes)
+          .append(", Stream Number: ").append(streamNumber)
+          .append(", Complete: ").append(complete)
+          .append(", isUnordered: ").append(unordered)
+          .append("]");
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/nio/ch/SctpStdSocketOption.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package sun.nio.ch;
+
+import com.sun.nio.sctp.SctpSocketOption;
+
+public class SctpStdSocketOption<T>
+    implements SctpSocketOption<T>
+{
+    /* for native mapping of int options */
+    public static final int SCTP_DISABLE_FRAGMENTS = 1;
+    public static final int SCTP_EXPLICIT_COMPLETE = 2;
+    public static final int SCTP_FRAGMENT_INTERLEAVE = 3;
+    public static final int SCTP_NODELAY = 4;
+    public static final int SO_SNDBUF = 5;
+    public static final int SO_RCVBUF = 6;
+    public static final int SO_LINGER = 7;
+
+    private final String name;
+    private final Class<T> type;
+
+    /* for native mapping of int options */
+    private int constValue;
+
+    public SctpStdSocketOption(String name, Class<T> type) {
+        this.name = name;
+        this.type = type;
+    }
+
+    public SctpStdSocketOption(String name, Class<T> type, int constValue) {
+        this.name = name;
+        this.type = type;
+        this.constValue = constValue;
+    }
+
+    @Override
+    public String name() {
+        return name;
+    }
+
+    @Override
+    public Class<T> type() {
+        return type;
+    }
+
+    @Override
+    public String toString() {
+        return name;
+    }
+
+    int constValue() {
+        return constValue;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/SctpAssocChange.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package sun.nio.ch;
+
+import com.sun.nio.sctp.Association;
+import com.sun.nio.sctp.AssociationChangeNotification;
+
+/**
+ * An implementation of AssociationChangeNotification
+ */
+public class SctpAssocChange extends AssociationChangeNotification
+    implements SctpNotification
+{
+    /* static final ints so that they can be referenced from native */
+    private final static int SCTP_COMM_UP = 1;
+    private final static int SCTP_COMM_LOST = 2;
+    private final static int SCTP_RESTART = 3;
+    private final static int SCTP_SHUTDOWN = 4;
+    private final static int SCTP_CANT_START = 5;
+
+    private Association association;
+
+    /* assocId is used to lookup the association before the notification is
+     * returned to user code */
+    private int assocId;
+    private AssocChangeEvent event;
+    private int maxOutStreams;
+    private int maxInStreams;
+
+    /* Invoked from native */
+    private SctpAssocChange(int assocId,
+                            int intEvent,
+                            int maxOutStreams,
+                            int maxInStreams) {
+        switch (intEvent) {
+            case SCTP_COMM_UP :
+                this.event = AssocChangeEvent.COMM_UP;
+                break;
+            case SCTP_COMM_LOST :
+                this.event = AssocChangeEvent.COMM_LOST;
+                break;
+            case SCTP_RESTART :
+                this.event = AssocChangeEvent.RESTART;
+                break;
+            case SCTP_SHUTDOWN :
+                this.event = AssocChangeEvent.SHUTDOWN;
+                break;
+            case SCTP_CANT_START :
+                this.event = AssocChangeEvent.CANT_START;
+                break;
+            default :
+                throw new AssertionError(
+                      "Unknown Association Change Event type: " + intEvent);
+        }
+
+        this.assocId = assocId;
+        this.maxOutStreams = maxOutStreams;
+        this.maxInStreams = maxInStreams;
+    }
+
+    @Override
+    public int assocId() {
+        return assocId;
+    }
+
+    @Override
+    public void setAssociation(Association association) {
+        this.association = association;
+    }
+
+    @Override
+    public Association association() {
+        assert association != null;
+        return association;
+    }
+
+    @Override
+    public AssocChangeEvent event() {
+        return event;
+    }
+
+    int maxOutStreams() {
+        return maxOutStreams;
+    }
+
+    int maxInStreams() {
+        return maxInStreams;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(super.toString()).append(" [");
+        sb.append("Association:").append(association);
+        sb.append(", Event: ").append(event).append("]");
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/SctpAssociationImpl.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package sun.nio.ch;
+
+import com.sun.nio.sctp.Association;
+
+/**
+ * An implementation of Association
+ */
+public class SctpAssociationImpl extends Association {
+    public SctpAssociationImpl(int associationID,
+                               int maxInStreams,
+                               int maxOutStreams) {
+        super(associationID, maxInStreams, maxOutStreams);
+    }
+
+    @Override
+    public String toString() {
+        StringBuffer sb = new StringBuffer(super.toString());
+        return sb.append("[associationID:")
+                 .append(associationID())
+                 .append(", maxIn:")
+                 .append(maxInboundStreams())
+                 .append(", maxOut:")
+                 .append(maxOutboundStreams())
+                 .append("]")
+                 .toString();
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/SctpChannelImpl.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,1073 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package sun.nio.ch;
+
+import java.net.InetAddress;
+import java.net.SocketAddress;
+import java.net.InetSocketAddress;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Set;
+import java.util.HashSet;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.ConnectionPendingException;
+import java.nio.channels.NoConnectionPendingException;
+import java.nio.channels.AlreadyBoundException;
+import java.nio.channels.AlreadyConnectedException;
+import java.nio.channels.NotYetBoundException;
+import java.nio.channels.NotYetConnectedException;
+import java.nio.channels.spi.SelectorProvider;
+import com.sun.nio.sctp.AbstractNotificationHandler;
+import com.sun.nio.sctp.Association;
+import com.sun.nio.sctp.AssociationChangeNotification;
+import com.sun.nio.sctp.HandlerResult;
+import com.sun.nio.sctp.IllegalReceiveException;
+import com.sun.nio.sctp.InvalidStreamException;
+import com.sun.nio.sctp.IllegalUnbindException;
+import com.sun.nio.sctp.MessageInfo;
+import com.sun.nio.sctp.NotificationHandler;
+import com.sun.nio.sctp.SctpChannel;
+import com.sun.nio.sctp.SctpSocketOption;
+import sun.nio.ch.NativeDispatcher;
+import sun.nio.ch.PollArrayWrapper;
+import sun.nio.ch.SelChImpl;
+import static com.sun.nio.sctp.SctpStandardSocketOption.*;
+import static sun.nio.ch.SctpResultContainer.SEND_FAILED;
+import static sun.nio.ch.SctpResultContainer.ASSOCIATION_CHANGED;
+import static sun.nio.ch.SctpResultContainer.PEER_ADDRESS_CHANGED;
+import static sun.nio.ch.SctpResultContainer.SHUTDOWN;
+
+/**
+ * An implementation of an SctpChannel
+ */
+public class SctpChannelImpl extends SctpChannel
+    implements SelChImpl
+{
+    /* Used to make native close and preClose calls */
+    private static NativeDispatcher nd;
+
+    private final FileDescriptor fd;
+
+    private final int fdVal;
+
+    /* IDs of native threads doing send and receivess, for signalling */
+    private volatile long receiverThread = 0;
+    private volatile long senderThread = 0;
+
+    /* Lock held by current receiving or connecting thread */
+    private final Object receiveLock = new Object();
+
+    /* Lock held by current sending or connecting thread */
+    private final Object sendLock = new Object();
+
+    private final ThreadLocal<Boolean> receiveInvoked =
+        new ThreadLocal<Boolean>() {
+             @Override protected Boolean initialValue() {
+                 return Boolean.FALSE;
+            }
+    };
+
+    /* Lock held by any thread that modifies the state fields declared below
+       DO NOT invoke a blocking I/O operation while holding this lock! */
+    private final Object stateLock = new Object();
+
+    private enum ChannelState {
+        UNINITIALIZED,
+        UNCONNECTED,
+        PENDING,
+        CONNECTED,
+        KILLPENDING,
+        KILLED,
+    }
+    /* -- The following fields are protected by stateLock -- */
+    private ChannelState state = ChannelState.UNINITIALIZED;
+
+    /* Binding; Once bound the port will remain constant. */
+    int port = -1;
+    private HashSet<InetSocketAddress> localAddresses = new HashSet<InetSocketAddress>();
+    /* Has the channel been bound to the wildcard address */
+    private boolean wildcard; /* false */
+    //private InetSocketAddress remoteAddress = null;
+
+    /* Input/Output open */
+    private boolean readyToConnect;
+
+    /* Shutdown */
+    private boolean isShutdown;
+
+    private Association association;
+
+    /* -- End of fields protected by stateLock -- */
+
+    private SctpResultContainer commUpResultContainer;  /* null */
+
+    /**
+     * Constructor for normal connecting sockets
+     */
+    public SctpChannelImpl(SelectorProvider provider) throws IOException {
+        //TODO: update provider remove public modifier
+        super(provider);
+        this.fd = SctpNet.socket(true);
+        this.fdVal = IOUtil.fdVal(fd);
+        this.state = ChannelState.UNCONNECTED;
+    }
+
+    /**
+     * Constructor for sockets obtained from server sockets
+     */
+    public SctpChannelImpl(SelectorProvider provider, FileDescriptor fd)
+         throws IOException {
+        super(provider);
+        this.fd = fd;
+        this.fdVal = IOUtil.fdVal(fd);
+        this.state = ChannelState.CONNECTED;
+        port = (Net.localAddress(fd)).getPort();
+
+        /* Receive COMM_UP */
+        ByteBuffer buf = Util.getTemporaryDirectBuffer(50);
+        try {
+            receive(buf, null, null, true);
+        } finally {
+            Util.releaseTemporaryDirectBuffer(buf);
+        }
+    }
+
+    /**
+     * Binds the channel's socket to a local address.
+     */
+    @Override
+    public SctpChannel bind(SocketAddress local) throws IOException {
+        synchronized (receiveLock) {
+            synchronized (sendLock) {
+                synchronized (stateLock) {
+                    ensureOpenAndUnconnected();
+                    if (isBound())
+                        throw new AlreadyBoundException();
+                    InetSocketAddress isa = (local == null) ?
+                        new InetSocketAddress(0) : Net.checkAddress(local);
+                    Net.bind(fd, isa.getAddress(), isa.getPort());
+                    InetSocketAddress boundIsa = Net.localAddress(fd);
+                    port = boundIsa.getPort();
+                    localAddresses.add(isa);
+                    if (isa.getAddress().isAnyLocalAddress())
+                        wildcard = true;
+                }
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public SctpChannel bindAddress(InetAddress address)
+            throws IOException {
+        bindUnbindAddress(address, true);
+        localAddresses.add(new InetSocketAddress(address, port));
+        return this;
+    }
+
+    @Override
+    public SctpChannel unbindAddress(InetAddress address)
+            throws IOException {
+        bindUnbindAddress(address, false);
+        localAddresses.remove(new InetSocketAddress(address, port));
+        return this;
+    }
+
+    private SctpChannel bindUnbindAddress(InetAddress address, boolean add)
+            throws IOException {
+        if (address == null)
+            throw new IllegalArgumentException();
+
+        synchronized (receiveLock) {
+            synchronized (sendLock) {
+                synchronized (stateLock) {
+                    if (!isOpen())
+                        throw new ClosedChannelException();
+                    if (!isBound())
+                        throw new NotYetBoundException();
+                    if (wildcard)
+                        throw new IllegalStateException(
+                                "Cannot add or remove addresses from a channel that is bound to the wildcard address");
+                    if (address.isAnyLocalAddress())
+                        throw new IllegalArgumentException(
+                                "Cannot add or remove the wildcard address");
+                    if (add) {
+                        for (InetSocketAddress addr : localAddresses) {
+                            if (addr.getAddress().equals(address)) {
+                                throw new AlreadyBoundException();
+                            }
+                        }
+                    } else { /*removing */
+                        /* Verify that there is more than one address
+                         * and that address is already bound */
+                        if (localAddresses.size() <= 1)
+                            throw new IllegalUnbindException("Cannot remove address from a channel with only one address bound");
+                        boolean foundAddress = false;
+                        for (InetSocketAddress addr : localAddresses) {
+                            if (addr.getAddress().equals(address)) {
+                                foundAddress = true;
+                                break;
+                            }
+                        }
+                        if (!foundAddress )
+                            throw new IllegalUnbindException("Cannot remove address from a channel that is not bound to that address");
+                    }
+
+                    SctpNet.bindx(fdVal, new InetAddress[]{address}, port, add);
+
+                    /* Update our internal Set to reflect the addition/removal */
+                    if (add)
+                        localAddresses.add(new InetSocketAddress(address, port));
+                    else {
+                        for (InetSocketAddress addr : localAddresses) {
+                            if (addr.getAddress().equals(address)) {
+                                localAddresses.remove(addr);
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return this;
+    }
+
+    private boolean isBound() {
+        synchronized (stateLock) {
+            return port == -1 ? false : true;
+        }
+    }
+
+    private boolean isConnected() {
+        synchronized (stateLock) {
+            return (state == ChannelState.CONNECTED);
+        }
+    }
+
+    private void ensureOpenAndUnconnected() throws IOException {
+        synchronized (stateLock) {
+            if (!isOpen())
+                throw new ClosedChannelException();
+            if (isConnected())
+                throw new AlreadyConnectedException();
+            if (state == ChannelState.PENDING)
+                throw new ConnectionPendingException();
+        }
+    }
+
+    private boolean ensureReceiveOpen() throws ClosedChannelException {
+        synchronized (stateLock) {
+            if (!isOpen())
+                throw new ClosedChannelException();
+            if (!isConnected())
+                throw new NotYetConnectedException();
+            else
+                return true;
+        }
+    }
+
+    private void ensureSendOpen() throws ClosedChannelException {
+        synchronized (stateLock) {
+            if (!isOpen())
+                throw new ClosedChannelException();
+            if (isShutdown)
+                throw new ClosedChannelException();
+            if (!isConnected())
+                throw new NotYetConnectedException();
+        }
+    }
+
+    private void receiverCleanup() throws IOException {
+        synchronized (stateLock) {
+            receiverThread = 0;
+            if (state == ChannelState.KILLPENDING)
+                kill();
+        }
+    }
+
+    private void senderCleanup() throws IOException {
+        synchronized (stateLock) {
+            senderThread = 0;
+            if (state == ChannelState.KILLPENDING)
+                kill();
+        }
+    }
+
+    @Override
+    public Association association() throws ClosedChannelException {
+        synchronized (stateLock) {
+            if (!isOpen())
+                throw new ClosedChannelException();
+            if (!isConnected())
+                return null;
+
+            return association;
+        }
+    }
+
+    @Override
+    public boolean connect(SocketAddress endpoint) throws IOException {
+        synchronized (receiveLock) {
+            synchronized (sendLock) {
+                ensureOpenAndUnconnected();
+                InetSocketAddress isa = Net.checkAddress(endpoint);
+                SecurityManager sm = System.getSecurityManager();
+                if (sm != null)
+                    sm.checkConnect(isa.getAddress().getHostAddress(),
+                                    isa.getPort());
+                synchronized (blockingLock()) {
+                    int n = 0;
+                    try {
+                        try {
+                            begin();
+                            synchronized (stateLock) {
+                                if (!isOpen()) {
+                                    return false;
+                                }
+                                receiverThread = NativeThread.current();
+                            }
+                            for (;;) {
+                                InetAddress ia = isa.getAddress();
+                                if (ia.isAnyLocalAddress())
+                                    ia = InetAddress.getLocalHost();
+                                n = Net.connect(fd, ia, isa.getPort());
+                                if (  (n == IOStatus.INTERRUPTED)
+                                      && isOpen())
+                                    continue;
+                                break;
+                            }
+                        } finally {
+                            receiverCleanup();
+                            end((n > 0) || (n == IOStatus.UNAVAILABLE));
+                            assert IOStatus.check(n);
+                        }
+                    } catch (IOException x) {
+                        /* If an exception was thrown, close the channel after
+                         * invoking end() so as to avoid bogus
+                         * AsynchronousCloseExceptions */
+                        close();
+                        throw x;
+                    }
+
+                    if (n > 0) {
+                        synchronized (stateLock) {
+                            /* Connection succeeded */
+                            state = ChannelState.CONNECTED;
+                            if (!isBound()) {
+                                InetSocketAddress boundIsa =
+                                        Net.localAddress(fd);
+                                port = boundIsa.getPort();
+                            }
+
+                            /* Receive COMM_UP */
+                            ByteBuffer buf = Util.getTemporaryDirectBuffer(50);
+                            try {
+                                receive(buf, null, null, true);
+                            } finally {
+                                Util.releaseTemporaryDirectBuffer(buf);
+                            }
+                            return true;
+                        }
+                    } else  {
+                        synchronized (stateLock) {
+                            /* If nonblocking and no exception then connection
+                             * pending; disallow another invocation */
+                            if (!isBlocking())
+                                state = ChannelState.PENDING;
+                            else
+                                assert false;
+                        }
+                    }
+                }
+                return false;
+            }
+        }
+    }
+
+    @Override
+    public boolean connect(SocketAddress endpoint,
+                           int maxOutStreams,
+                           int maxInStreams)
+            throws IOException {
+        return setOption(SCTP_INIT_MAXSTREAMS, InitMaxStreams.
+                create(maxInStreams, maxOutStreams)).connect(endpoint);
+
+    }
+
+    @Override
+    public boolean isConnectionPending() {
+        synchronized (stateLock) {
+            return (state == ChannelState.PENDING);
+        }
+    }
+
+    @Override
+    public boolean finishConnect() throws IOException {
+        synchronized (receiveLock) {
+            synchronized (sendLock) {
+                synchronized (stateLock) {
+                    if (!isOpen())
+                        throw new ClosedChannelException();
+                    if (isConnected())
+                        return true;
+                    if (state != ChannelState.PENDING)
+                        throw new NoConnectionPendingException();
+                }
+                int n = 0;
+                try {
+                    try {
+                        begin();
+                        synchronized (blockingLock()) {
+                            synchronized (stateLock) {
+                                if (!isOpen()) {
+                                    return false;
+                                }
+                                receiverThread = NativeThread.current();
+                            }
+                            if (!isBlocking()) {
+                                for (;;) {
+                                    n = checkConnect(fd, false, readyToConnect);
+                                    if (  (n == IOStatus.INTERRUPTED)
+                                          && isOpen())
+                                        continue;
+                                    break;
+                                }
+                            } else {
+                                for (;;) {
+                                    n = checkConnect(fd, true, readyToConnect);
+                                    if (n == 0) {
+                                        // Loop in case of
+                                        // spurious notifications
+                                        continue;
+                                    }
+                                    if (  (n == IOStatus.INTERRUPTED)
+                                          && isOpen())
+                                        continue;
+                                    break;
+                                }
+                            }
+                        }
+                    } finally {
+                        synchronized (stateLock) {
+                            receiverThread = 0;
+                            if (state == ChannelState.KILLPENDING) {
+                                kill();
+                                /* poll()/getsockopt() does not report
+                                 * error (throws exception, with n = 0)
+                                 * on Linux platform after dup2 and
+                                 * signal-wakeup. Force n to 0 so the
+                                 * end() can throw appropriate exception */
+                                n = 0;
+                            }
+                        }
+                        end((n > 0) || (n == IOStatus.UNAVAILABLE));
+                        assert IOStatus.check(n);
+                    }
+                } catch (IOException x) {
+                    /* If an exception was thrown, close the channel after
+                     * invoking end() so as to avoid bogus
+                     * AsynchronousCloseExceptions */
+                    close();
+                    throw x;
+                }
+
+                if (n > 0) {
+                    synchronized (stateLock) {
+                        state = ChannelState.CONNECTED;
+                        if (!isBound()) {
+                            InetSocketAddress boundIsa =
+                                    Net.localAddress(fd);
+                            port = boundIsa.getPort();
+                        }
+
+                        /* Receive COMM_UP */
+                        ByteBuffer buf = Util.getTemporaryDirectBuffer(50);
+                        try {
+                            receive(buf, null, null, true);
+                        } finally {
+                            Util.releaseTemporaryDirectBuffer(buf);
+                        }
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    protected void implConfigureBlocking(boolean block) throws IOException {
+        IOUtil.configureBlocking(fd, block);
+    }
+
+    @Override
+    public void implCloseSelectableChannel() throws IOException {
+        synchronized (stateLock) {
+            nd.preClose(fd);
+
+            if (receiverThread != 0)
+                NativeThread.signal(receiverThread);
+
+            if (senderThread != 0)
+                NativeThread.signal(senderThread);
+
+            if (!isRegistered())
+                kill();
+        }
+    }
+
+    @Override
+    public FileDescriptor getFD() {
+        return fd;
+    }
+
+    @Override
+    public int getFDVal() {
+        return fdVal;
+    }
+
+    /**
+     * Translates native poll revent ops into a ready operation ops
+     */
+    private boolean translateReadyOps(int ops, int initialOps, SelectionKeyImpl sk) {
+        int intOps = sk.nioInterestOps();
+        int oldOps = sk.nioReadyOps();
+        int newOps = initialOps;
+
+        if ((ops & PollArrayWrapper.POLLNVAL) != 0) {
+            /* This should only happen if this channel is pre-closed while a
+             * selection operation is in progress
+             * ## Throw an error if this channel has not been pre-closed */
+            return false;
+        }
+
+        if ((ops & (PollArrayWrapper.POLLERR
+                    | PollArrayWrapper.POLLHUP)) != 0) {
+            newOps = intOps;
+            sk.nioReadyOps(newOps);
+            /* No need to poll again in checkConnect,
+             * the error will be detected there */
+            readyToConnect = true;
+            return (newOps & ~oldOps) != 0;
+        }
+
+        if (((ops & PollArrayWrapper.POLLIN) != 0) &&
+            ((intOps & SelectionKey.OP_READ) != 0) &&
+            isConnected())
+            newOps |= SelectionKey.OP_READ;
+
+        if (((ops & PollArrayWrapper.POLLCONN) != 0) &&
+            ((intOps & SelectionKey.OP_CONNECT) != 0) &&
+            ((state == ChannelState.UNCONNECTED) || (state == ChannelState.PENDING))) {
+            newOps |= SelectionKey.OP_CONNECT;
+            readyToConnect = true;
+        }
+
+        if (((ops & PollArrayWrapper.POLLOUT) != 0) &&
+            ((intOps & SelectionKey.OP_WRITE) != 0) &&
+            isConnected())
+            newOps |= SelectionKey.OP_WRITE;
+
+        sk.nioReadyOps(newOps);
+        return (newOps & ~oldOps) != 0;
+    }
+
+    @Override
+    public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
+        return translateReadyOps(ops, sk.nioReadyOps(), sk);
+    }
+
+    @Override
+    @SuppressWarnings("all")
+    public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
+        return translateReadyOps(ops, 0, sk);
+    }
+
+    @Override
+    public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
+        int newOps = 0;
+        if ((ops & SelectionKey.OP_READ) != 0)
+            newOps |= PollArrayWrapper.POLLIN;
+        if ((ops & SelectionKey.OP_WRITE) != 0)
+            newOps |= PollArrayWrapper.POLLOUT;
+        if ((ops & SelectionKey.OP_CONNECT) != 0)
+            newOps |= PollArrayWrapper.POLLCONN;
+        sk.selector.putEventOps(sk, newOps);
+    }
+
+    @Override
+    public void kill() throws IOException {
+        synchronized (stateLock) {
+            if (state == ChannelState.KILLED)
+                return;
+            if (state == ChannelState.UNINITIALIZED) {
+                state = ChannelState.KILLED;
+                return;
+            }
+            assert !isOpen() && !isRegistered();
+
+            /* Postpone the kill if there is a waiting reader
+             * or writer thread. */
+            if (receiverThread == 0 && senderThread == 0) {
+                nd.close(fd);
+                state = ChannelState.KILLED;
+            } else {
+                state = ChannelState.KILLPENDING;
+            }
+        }
+    }
+
+    @Override
+    public <T> SctpChannel setOption(SctpSocketOption<T> name, T value)
+            throws IOException {
+        if (name == null)
+            throw new NullPointerException();
+        if (!supportedOptions().contains(name))
+            throw new UnsupportedOperationException("'" + name + "' not supported");
+
+        synchronized (stateLock) {
+            if (!isOpen())
+                throw new ClosedChannelException();
+
+            SctpNet.setSocketOption(fdVal, name, value, 0 /*oneToOne*/);
+        }
+        return this;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <T> T getOption(SctpSocketOption<T> name) throws IOException {
+        if (name == null)
+            throw new NullPointerException();
+        if (!supportedOptions().contains(name))
+            throw new UnsupportedOperationException("'" + name + "' not supported");
+
+        synchronized (stateLock) {
+            if (!isOpen())
+                throw new ClosedChannelException();
+
+            return (T)SctpNet.getSocketOption(fdVal, name, 0 /*oneToOne*/);
+        }
+    }
+
+    private static class DefaultOptionsHolder {
+        static final Set<SctpSocketOption<?>> defaultOptions = defaultOptions();
+
+        private static Set<SctpSocketOption<?>> defaultOptions() {
+            HashSet<SctpSocketOption<?>> set = new HashSet<SctpSocketOption<?>>(10);
+            set.add(SCTP_DISABLE_FRAGMENTS);
+            set.add(SCTP_EXPLICIT_COMPLETE);
+            set.add(SCTP_FRAGMENT_INTERLEAVE);
+            set.add(SCTP_INIT_MAXSTREAMS);
+            set.add(SCTP_NODELAY);
+            set.add(SCTP_PRIMARY_ADDR);
+            set.add(SCTP_SET_PEER_PRIMARY_ADDR);
+            set.add(SO_SNDBUF);
+            set.add(SO_RCVBUF);
+            set.add(SO_LINGER);
+            return Collections.unmodifiableSet(set);
+        }
+    }
+
+    @Override
+    public final Set<SctpSocketOption<?>> supportedOptions() {
+        return DefaultOptionsHolder.defaultOptions;
+    }
+
+    @Override
+    public <T> MessageInfo receive(ByteBuffer buffer,
+                                   T attachment,
+                                   NotificationHandler<T> handler)
+            throws IOException {
+        return receive(buffer, attachment, handler, false);
+    }
+
+    private <T> MessageInfo receive(ByteBuffer buffer,
+                                    T attachment,
+                                    NotificationHandler<T> handler,
+                                    boolean fromConnect)
+            throws IOException {
+        if (buffer == null)
+            throw new IllegalArgumentException("buffer cannot be null");
+
+        if (buffer.isReadOnly())
+            throw new IllegalArgumentException("Read-only buffer");
+
+        if (receiveInvoked.get())
+            throw new IllegalReceiveException(
+                    "cannot invoke receive from handler");
+        receiveInvoked.set(Boolean.TRUE);
+
+        try {
+            SctpResultContainer resultContainer = new SctpResultContainer();
+            do {
+                resultContainer.clear();
+                synchronized (receiveLock) {
+                    if (!ensureReceiveOpen())
+                        return null;
+
+                    if (commUpResultContainer != null) {
+                        resultContainer = commUpResultContainer;
+                        commUpResultContainer = null;
+                        continue;
+                    }
+
+                    int n = 0;
+                    try {
+                        begin();
+
+                        synchronized (stateLock) {
+                            if(!isOpen())
+                                return null;
+                            receiverThread = NativeThread.current();
+                        }
+
+                        do {
+                            n = receive(fdVal, buffer, resultContainer);
+                        } while ((n == IOStatus.INTERRUPTED) && isOpen());
+                    } finally {
+                        receiverCleanup();
+                        end((n > 0) || (n == IOStatus.UNAVAILABLE));
+                        assert IOStatus.check(n);
+                    }
+
+                    if (!resultContainer.isNotification()) {
+                        /* message or nothing */
+                        if (resultContainer.hasSomething()) {
+                            /* Set the association before returning */
+                            SctpMessageInfoImpl info =
+                                    resultContainer.getMessageInfo();
+                            synchronized (stateLock) {
+                                assert association != null;
+                                info.setAssociation(association);
+                            }
+                            return info;
+                        } else
+                            /* Non-blocking may return null if nothing available*/
+                            return null;
+                    } else { /* notification */
+                        synchronized (stateLock) {
+                            handleNotificationInternal(
+                                    resultContainer);
+                        }
+                    }
+
+                    if (fromConnect)  {
+                        /* If we reach here, then it was connect that invoked
+                         * receive an received the COMM_UP. Save it and allow
+                         * the user handler to process it upon next receive. */
+                        commUpResultContainer = resultContainer;
+                        return null;
+                    }
+                }  /* receiveLock */
+            } while (handler == null ? true :
+                (invokeNotificationHandler(resultContainer, handler, attachment)
+                 == HandlerResult.CONTINUE));
+
+            return null;
+        } finally {
+            receiveInvoked.set(Boolean.FALSE);
+        }
+    }
+
+    private int receive(int fd,
+                        ByteBuffer dst,
+                        SctpResultContainer resultContainer)
+            throws IOException {
+        int pos = dst.position();
+        int lim = dst.limit();
+        assert (pos <= lim);
+        int rem = (pos <= lim ? lim - pos : 0);
+        if (dst instanceof DirectBuffer && rem > 0)
+            return receiveIntoNativeBuffer(fd, resultContainer, dst, rem, pos);
+
+        /* Substitute a native buffer */
+        int newSize = Math.max(rem, 1);
+        ByteBuffer bb = Util.getTemporaryDirectBuffer(newSize);
+        try {
+            int n = receiveIntoNativeBuffer(fd, resultContainer, bb, newSize, 0);
+            bb.flip();
+            if (n > 0 && rem > 0)
+                dst.put(bb);
+            return n;
+        } finally {
+            Util.releaseTemporaryDirectBuffer(bb);
+        }
+    }
+
+    private int receiveIntoNativeBuffer(int fd,
+                                        SctpResultContainer resultContainer,
+                                        ByteBuffer bb,
+                                        int rem,
+                                        int pos)
+        throws IOException
+    {
+        int n = receive0(fd, resultContainer, ((DirectBuffer)bb).address() + pos, rem);
+
+        if (n > 0)
+            bb.position(pos + n);
+        return n;
+    }
+
+    private InternalNotificationHandler<?> internalNotificationHandler =
+            new InternalNotificationHandler();
+
+    private void handleNotificationInternal(SctpResultContainer resultContainer)
+    {
+        invokeNotificationHandler(resultContainer,
+                internalNotificationHandler, null);
+    }
+
+    private class InternalNotificationHandler<T>
+            extends AbstractNotificationHandler<T>
+    {
+        @Override
+        public HandlerResult handleNotification(
+                AssociationChangeNotification not, T unused) {
+            if (not.event().equals(
+                    AssociationChangeNotification.AssocChangeEvent.COMM_UP)) {
+                assert association == null;
+                SctpAssocChange sac = (SctpAssocChange) not;
+                association = new SctpAssociationImpl
+                       (sac.assocId(), sac.maxInStreams(), sac.maxOutStreams());
+            }
+            return HandlerResult.CONTINUE;
+        }
+    }
+
+    private <T> HandlerResult invokeNotificationHandler
+                                 (SctpResultContainer resultContainer,
+                                  NotificationHandler<T> handler,
+                                  T attachment) {
+        SctpNotification notification = resultContainer.notification();
+        synchronized (stateLock) {
+            notification.setAssociation(association);
+        }
+
+        if (!(handler instanceof AbstractNotificationHandler)) {
+            return handler.handleNotification(notification, attachment);
+        }
+
+        /* AbstractNotificationHandler */
+        AbstractNotificationHandler absHandler =
+                (AbstractNotificationHandler)handler;
+        switch(resultContainer.type()) {
+            case ASSOCIATION_CHANGED :
+                return absHandler.handleNotification(
+                        resultContainer.getAssociationChanged(), attachment);
+            case PEER_ADDRESS_CHANGED :
+                return absHandler.handleNotification(
+                        resultContainer.getPeerAddressChanged(), attachment);
+            case SEND_FAILED :
+                return absHandler.handleNotification(
+                        resultContainer.getSendFailed(), attachment);
+            case SHUTDOWN :
+                return absHandler.handleNotification(
+                        resultContainer.getShutdown(), attachment);
+            default :
+                /* implementation specific handlers */
+                return absHandler.handleNotification(
+                        resultContainer.notification(), attachment);
+        }
+    }
+
+    private void checkAssociation(Association sendAssociation) {
+        synchronized (stateLock) {
+            if (sendAssociation != null && !sendAssociation.equals(association)) {
+                throw new IllegalArgumentException(
+                        "Cannot send to another association");
+            }
+        }
+    }
+
+    private void checkStreamNumber(int streamNumber) {
+        synchronized (stateLock) {
+            if (association != null) {
+                if (streamNumber < 0 ||
+                      streamNumber >= association.maxOutboundStreams())
+                    throw new InvalidStreamException();
+            }
+        }
+    }
+
+    /* TODO: Add support for ttl and isComplete to both 121 12M
+     *       SCTP_EOR not yet supported on reference platforms
+     *       TTL support limited...
+     */
+    @Override
+    public int send(ByteBuffer buffer, MessageInfo messageInfo)
+            throws IOException {
+        if (buffer == null)
+            throw new IllegalArgumentException("buffer cannot be null");
+
+        if (messageInfo == null)
+            throw new IllegalArgumentException("messageInfo cannot be null");
+
+        checkAssociation(messageInfo.association());
+        checkStreamNumber(messageInfo.streamNumber());
+
+        synchronized (sendLock) {
+            ensureSendOpen();
+
+            int n = 0;
+            try {
+                begin();
+
+                synchronized (stateLock) {
+                    if(!isOpen())
+                        return 0;
+                    senderThread = NativeThread.current();
+                }
+
+                do {
+                    n = send(fdVal, buffer, messageInfo);
+                } while ((n == IOStatus.INTERRUPTED) && isOpen());
+
+                return IOStatus.normalize(n);
+            } finally {
+                senderCleanup();
+                end((n > 0) || (n == IOStatus.UNAVAILABLE));
+                assert IOStatus.check(n);
+            }
+        }
+    }
+
+    private int send(int fd, ByteBuffer src, MessageInfo messageInfo)
+            throws IOException {
+        int streamNumber = messageInfo.streamNumber();
+        SocketAddress target = messageInfo.address();
+        boolean unordered = messageInfo.isUnordered();
+        int ppid = messageInfo.payloadProtocolID();
+        int pos = src.position();
+        int lim = src.limit();
+
+        assert (pos <= lim && streamNumber > 0);
+        int rem = (pos <= lim ? lim - pos : 0);
+
+        if (src instanceof DirectBuffer)
+            return sendFromNativeBuffer(fd, src, rem, pos, target, streamNumber,
+                    unordered, ppid);
+
+        /* Substitute a native buffer */
+        ByteBuffer bb = Util.getTemporaryDirectBuffer(rem);
+        try {
+            bb.put(src);
+            bb.flip();
+            /* Do not update src until we see how many bytes were written */
+            src.position(pos);
+
+            int n = sendFromNativeBuffer(fd, bb, rem, pos, target, streamNumber,
+                    unordered, ppid);
+            if (n > 0) {
+                /* now update src */
+                src.position(pos + n);
+            }
+            return n;
+        } finally {
+            Util.releaseTemporaryDirectBuffer(bb);
+        }
+    }
+
+    private int sendFromNativeBuffer(int fd,
+                                     ByteBuffer bb,
+                                     int rem,
+                                     int pos,
+                                     SocketAddress target,
+                                     int streamNumber,
+                                     boolean unordered,
+                                     int ppid)
+            throws IOException {
+        int written = send0(fd, ((DirectBuffer)bb).address() + pos,
+                            rem, target, -1 /*121*/, streamNumber, unordered, ppid);
+        if (written > 0)
+            bb.position(pos + written);
+        return written;
+    }
+
+    @Override
+    public SctpChannel shutdown() throws IOException {
+        synchronized(stateLock) {
+            if (isShutdown)
+                return this;
+
+            ensureSendOpen();
+            SctpNet.shutdown(fdVal, -1);
+            if (senderThread != 0)
+                NativeThread.signal(senderThread);
+            isShutdown = true;
+        }
+        return this;
+    }
+
+    @Override
+    public Set<SocketAddress> getAllLocalAddresses()
+            throws IOException {
+        synchronized (stateLock) {
+            if (!isOpen())
+                throw new ClosedChannelException();
+            if (!isBound())
+                return Collections.EMPTY_SET;
+
+            return SctpNet.getLocalAddresses(fdVal);
+        }
+    }
+
+    @Override
+    public Set<SocketAddress> getRemoteAddresses()
+            throws IOException {
+        synchronized (stateLock) {
+            if (!isOpen())
+                throw new ClosedChannelException();
+            if (!isConnected())
+                return Collections.EMPTY_SET;
+
+            return SctpNet.getRemoteAddresses(fdVal, 0/*unused*/);
+        }
+    }
+
+    /* Native */
+    private static native void initIDs();
+
+    static native int receive0(int fd, SctpResultContainer resultContainer,
+            long address, int length) throws IOException;
+
+    static native int send0(int fd, long address, int length,
+            SocketAddress target, int assocId, int streamNumber,
+            boolean unordered, int ppid) throws IOException;
+
+    private static native int checkConnect(FileDescriptor fd, boolean block,
+            boolean ready) throws IOException;
+
+    static {
+        Util.load();   /* loads nio & net native libraries */
+        java.security.AccessController.doPrivileged(
+                new sun.security.action.LoadLibraryAction("sctp"));
+        initIDs();
+        nd = new SctpSocketDispatcher();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/SctpMultiChannelImpl.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,959 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package sun.nio.ch;
+
+import java.net.InetAddress;
+import java.net.SocketAddress;
+import java.net.InetSocketAddress;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.HashMap;
+import java.nio.ByteBuffer;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.AlreadyBoundException;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.NotYetBoundException;
+import java.nio.channels.spi.SelectorProvider;
+import com.sun.nio.sctp.AbstractNotificationHandler;
+import com.sun.nio.sctp.Association;
+import com.sun.nio.sctp.AssociationChangeNotification;
+import com.sun.nio.sctp.HandlerResult;
+import com.sun.nio.sctp.IllegalReceiveException;
+import com.sun.nio.sctp.InvalidStreamException;
+import com.sun.nio.sctp.IllegalUnbindException;
+import com.sun.nio.sctp.NotificationHandler;
+import com.sun.nio.sctp.MessageInfo;
+import com.sun.nio.sctp.SctpChannel;
+import com.sun.nio.sctp.SctpMultiChannel;
+import com.sun.nio.sctp.SctpSocketOption;
+import static com.sun.nio.sctp.SctpStandardSocketOption.*;
+import static sun.nio.ch.SctpResultContainer.*;
+
+/**
+ * An implementation of SctpMultiChannel
+ */
+public class SctpMultiChannelImpl extends SctpMultiChannel
+    implements SelChImpl
+{
+    /* Used to make native close and preClose calls */
+    private static NativeDispatcher nd;
+
+    private final FileDescriptor fd;
+
+    private final int fdVal;
+
+    /* IDs of native threads doing send and receives, for signalling */
+    private volatile long receiverThread = 0;
+    private volatile long senderThread = 0;
+
+    /* Lock held by current receiving thread */
+    private final Object receiveLock = new Object();
+
+    /* Lock held by current sending thread */
+    private final Object sendLock = new Object();
+
+    /* Lock held by any thread that modifies the state fields declared below
+     * DO NOT invoke a blocking I/O operation while holding this lock! */
+    private final Object stateLock = new Object();
+
+    private enum ChannelState {
+        UNINITIALIZED,
+        KILLPENDING,
+        KILLED,
+    }
+
+    /* -- The following fields are protected by stateLock -- */
+    private ChannelState state = ChannelState.UNINITIALIZED;
+
+    /* Binding: Once bound the port will remain constant. */
+    int port = -1;
+    private HashSet<InetSocketAddress> localAddresses = new HashSet<InetSocketAddress>();
+    /* Has the channel been bound to the wildcard address */
+    private boolean wildcard; /* false */
+
+    /* Keeps a map of addresses to association, and visa versa */
+    private HashMap<SocketAddress, Association> addressMap =
+                         new HashMap<SocketAddress, Association>();
+    private HashMap<Association, Set<SocketAddress>> associationMap =
+                         new HashMap<Association, Set<SocketAddress>>();
+
+    /* -- End of fields protected by stateLock -- */
+
+    /* If an association has been shutdown mark it for removal after
+     * the user handler has been invoked */
+    private final ThreadLocal<Association> associationToRemove =
+        new ThreadLocal<Association>() {
+             @Override protected Association initialValue() {
+                 return null;
+            }
+    };
+
+    /* A notification handler cannot invoke receive */
+    private final ThreadLocal<Boolean> receiveInvoked =
+        new ThreadLocal<Boolean>() {
+             @Override protected Boolean initialValue() {
+                 return Boolean.FALSE;
+            }
+    };
+
+    public SctpMultiChannelImpl(SelectorProvider provider)
+            throws IOException {
+        //TODO: update provider, remove public modifier
+        super(provider);
+        this.fd = SctpNet.socket(false /*one-to-many*/);
+        this.fdVal = IOUtil.fdVal(fd);
+    }
+
+    @Override
+    public SctpMultiChannel bind(SocketAddress local, int backlog)
+            throws IOException {
+        synchronized (receiveLock) {
+            synchronized (sendLock) {
+                synchronized (stateLock) {
+                    ensureOpen();
+                    if (isBound())
+                        throw new AlreadyBoundException();
+                    InetSocketAddress isa = (local == null) ?
+                        new InetSocketAddress(0) : Net.checkAddress(local);
+
+                    SecurityManager sm = System.getSecurityManager();
+                    if (sm != null)
+                        sm.checkListen(isa.getPort());
+                    Net.bind(fd, isa.getAddress(), isa.getPort());
+
+                    InetSocketAddress boundIsa = Net.localAddress(fd);
+                    port = boundIsa.getPort();
+                    localAddresses.add(isa);
+                    if (isa.getAddress().isAnyLocalAddress())
+                        wildcard = true;
+
+                    Net.listen(fd, backlog < 1 ? 50 : backlog);
+                }
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public SctpMultiChannel bindAddress(InetAddress address)
+            throws IOException {
+        return bindUnbindAddress(address, true);
+    }
+
+    @Override
+    public SctpMultiChannel unbindAddress(InetAddress address)
+            throws IOException {
+        return bindUnbindAddress(address, false);
+    }
+
+    private SctpMultiChannel bindUnbindAddress(InetAddress address,
+                                               boolean add)
+            throws IOException {
+        if (address == null)
+            throw new IllegalArgumentException();
+
+        synchronized (receiveLock) {
+            synchronized (sendLock) {
+                synchronized (stateLock) {
+                    if (!isOpen())
+                        throw new ClosedChannelException();
+                    if (!isBound())
+                        throw new NotYetBoundException();
+                    if (wildcard)
+                        throw new IllegalStateException(
+                                "Cannot add or remove addresses from a channel that is bound to the wildcard address");
+                    if (address.isAnyLocalAddress())
+                        throw new IllegalArgumentException(
+                                "Cannot add or remove the wildcard address");
+                    if (add) {
+                        for (InetSocketAddress addr : localAddresses) {
+                            if (addr.getAddress().equals(address)) {
+                                throw new AlreadyBoundException();
+                            }
+                        }
+                    } else { /*removing */
+                        /* Verify that there is more than one address
+                         * and that address is already bound */
+                        if (localAddresses.size() <= 1)
+                            throw new IllegalUnbindException("Cannot remove address from a channel with only one address bound");
+                        boolean foundAddress = false;
+                        for (InetSocketAddress addr : localAddresses) {
+                            if (addr.getAddress().equals(address)) {
+                                foundAddress = true;
+                                break;
+                            }
+                        }
+                        if (!foundAddress )
+                            throw new IllegalUnbindException("Cannot remove address from a channel that is not bound to that address");
+                    }
+
+                    SctpNet.bindx(fdVal, new InetAddress[]{address}, port, add);
+
+                    /* Update our internal Set to reflect the addition/removal */
+                    if (add)
+                        localAddresses.add(new InetSocketAddress(address, port));
+                    else {
+                        for (InetSocketAddress addr : localAddresses) {
+                            if (addr.getAddress().equals(address)) {
+                                localAddresses.remove(addr);
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public Set<Association> associations()
+            throws ClosedChannelException, NotYetBoundException {
+        synchronized (stateLock) {
+            if (!isOpen())
+                throw new ClosedChannelException();
+            if (!isBound())
+                throw new NotYetBoundException();
+
+            return Collections.unmodifiableSet(associationMap.keySet());
+        }
+    }
+
+    private boolean isBound() {
+        synchronized (stateLock) {
+            return port == -1 ? false : true;
+        }
+    }
+
+    private void ensureOpen() throws IOException {
+        synchronized (stateLock) {
+            if (!isOpen())
+                throw new ClosedChannelException();
+        }
+    }
+
+    private void receiverCleanup() throws IOException {
+        synchronized (stateLock) {
+            receiverThread = 0;
+            if (state == ChannelState.KILLPENDING)
+                kill();
+        }
+    }
+
+    private void senderCleanup() throws IOException {
+        synchronized (stateLock) {
+            senderThread = 0;
+            if (state == ChannelState.KILLPENDING)
+                kill();
+        }
+    }
+
+    @Override
+    protected void implConfigureBlocking(boolean block) throws IOException {
+        IOUtil.configureBlocking(fd, block);
+    }
+
+    @Override
+    public void implCloseSelectableChannel() throws IOException {
+        synchronized (stateLock) {
+            nd.preClose(fd);
+
+            if (receiverThread != 0)
+                NativeThread.signal(receiverThread);
+
+            if (senderThread != 0)
+                NativeThread.signal(senderThread);
+
+            if (!isRegistered())
+                kill();
+        }
+    }
+
+    @Override
+    public FileDescriptor getFD() {
+        return fd;
+    }
+
+    @Override
+    public int getFDVal() {
+        return fdVal;
+    }
+
+    /**
+     * Translates native poll revent ops into a ready operation ops
+     */
+    private boolean translateReadyOps(int ops, int initialOps,
+                                      SelectionKeyImpl sk) {
+        int intOps = sk.nioInterestOps();
+        int oldOps = sk.nioReadyOps();
+        int newOps = initialOps;
+
+        if ((ops & PollArrayWrapper.POLLNVAL) != 0) {
+            /* This should only happen if this channel is pre-closed while a
+             * selection operation is in progress
+             * ## Throw an error if this channel has not been pre-closed */
+            return false;
+        }
+
+        if ((ops & (PollArrayWrapper.POLLERR
+                    | PollArrayWrapper.POLLHUP)) != 0) {
+            newOps = intOps;
+            sk.nioReadyOps(newOps);
+            return (newOps & ~oldOps) != 0;
+        }
+
+        if (((ops & PollArrayWrapper.POLLIN) != 0) &&
+            ((intOps & SelectionKey.OP_READ) != 0))
+            newOps |= SelectionKey.OP_READ;
+
+        if (((ops & PollArrayWrapper.POLLOUT) != 0) &&
+            ((intOps & SelectionKey.OP_WRITE) != 0))
+            newOps |= SelectionKey.OP_WRITE;
+
+        sk.nioReadyOps(newOps);
+        return (newOps & ~oldOps) != 0;
+    }
+
+    @Override
+    public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
+        return translateReadyOps(ops, sk.nioReadyOps(), sk);
+    }
+
+    @Override
+    public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
+        return translateReadyOps(ops, 0, sk);
+    }
+
+    @Override
+    public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
+        int newOps = 0;
+        if ((ops & SelectionKey.OP_READ) != 0)
+            newOps |= PollArrayWrapper.POLLIN;
+        if ((ops & SelectionKey.OP_WRITE) != 0)
+            newOps |= PollArrayWrapper.POLLOUT;
+        sk.selector.putEventOps(sk, newOps);
+    }
+
+    @Override
+    public void kill() throws IOException {
+        synchronized (stateLock) {
+            if (state == ChannelState.KILLED)
+                return;
+            if (state == ChannelState.UNINITIALIZED) {
+                state = ChannelState.KILLED;
+                return;
+            }
+            assert !isOpen() && !isRegistered();
+
+            /* Postpone the kill if there is a thread sending or receiving. */
+            if (receiverThread == 0 && senderThread == 0) {
+                nd.close(fd);
+                state = ChannelState.KILLED;
+            } else {
+                state = ChannelState.KILLPENDING;
+            }
+        }
+    }
+
+    @Override
+    public <T> SctpMultiChannel setOption(SctpSocketOption<T> name,
+                                          T value,
+                                          Association association)
+            throws IOException {
+        if (name == null)
+            throw new NullPointerException();
+        if (!(supportedOptions().contains(name)))
+            throw new UnsupportedOperationException("'" + name + "' not supported");
+
+        synchronized (stateLock) {
+            if (association != null && (name.equals(SCTP_PRIMARY_ADDR) ||
+                    name.equals(SCTP_SET_PEER_PRIMARY_ADDR))) {
+                checkAssociation(association);
+            }
+            if (!isOpen())
+                throw new ClosedChannelException();
+
+            SctpNet.setSocketOption(fdVal, name, value,
+                    association.associationID());
+        }
+        return this;
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <T> T getOption(SctpSocketOption<T> name, Association association)
+            throws IOException {
+        if (name == null)
+            throw new NullPointerException();
+        if (!supportedOptions().contains(name))
+            throw new UnsupportedOperationException("'" + name + "' not supported");
+
+        synchronized (stateLock) {
+            checkAssociation(association);
+            if (!isOpen())
+                throw new ClosedChannelException();
+
+            return (T)SctpNet.getSocketOption(fdVal, name,
+                    association.associationID());
+        }
+    }
+
+    private static class DefaultOptionsHolder {
+        static final Set<SctpSocketOption<?>> defaultOptions = defaultOptions();
+
+        private static Set<SctpSocketOption<?>> defaultOptions() {
+            HashSet<SctpSocketOption<?>> set = new HashSet<SctpSocketOption<?>>(10);
+            set.add(SCTP_DISABLE_FRAGMENTS);
+            set.add(SCTP_EXPLICIT_COMPLETE);
+            set.add(SCTP_FRAGMENT_INTERLEAVE);
+            set.add(SCTP_INIT_MAXSTREAMS);
+            set.add(SCTP_NODELAY);
+            set.add(SCTP_PRIMARY_ADDR);
+            set.add(SCTP_SET_PEER_PRIMARY_ADDR);
+            set.add(SO_SNDBUF);
+            set.add(SO_RCVBUF);
+            set.add(SO_LINGER);
+            return Collections.unmodifiableSet(set);
+        }
+    }
+
+    @Override
+    public final Set<SctpSocketOption<?>> supportedOptions() {
+        return DefaultOptionsHolder.defaultOptions;
+    }
+
+    @Override
+    public <T> MessageInfo receive(ByteBuffer buffer,
+                                   T attachment,
+                                   NotificationHandler<T> handler)
+            throws IOException {
+        if (buffer == null)
+            throw new IllegalArgumentException("buffer cannot be null");
+
+        if (buffer.isReadOnly())
+            throw new IllegalArgumentException("Read-only buffer");
+
+        if (receiveInvoked.get())
+            throw new IllegalReceiveException(
+                    "cannot invoke receive from handler");
+        receiveInvoked.set(Boolean.TRUE);
+
+        try {
+            SctpResultContainer resultContainer = new SctpResultContainer();
+            do {
+                resultContainer.clear();
+                synchronized (receiveLock) {
+                    ensureOpen();
+                    if (!isBound())
+                        throw new NotYetBoundException();
+
+                    int n = 0;
+                    try {
+                        begin();
+
+                        synchronized (stateLock) {
+                            if(!isOpen())
+                                return null;
+                            receiverThread = NativeThread.current();
+                        }
+
+                        do {
+                            n = receive(fdVal, buffer, resultContainer);
+                        } while ((n == IOStatus.INTERRUPTED) && isOpen());
+
+                    } finally {
+                        receiverCleanup();
+                        end((n > 0) || (n == IOStatus.UNAVAILABLE));
+                        assert IOStatus.check(n);
+                    }
+
+                    if (!resultContainer.isNotification()) {
+                        /* message or nothing */
+                        if (resultContainer.hasSomething()) {
+                            /* Set the association before returning */
+                            SctpMessageInfoImpl info =
+                                    resultContainer.getMessageInfo();
+                            info.setAssociation(lookupAssociation(info.
+                                    associationID()));
+                            SecurityManager sm = System.getSecurityManager();
+                            if (sm != null) {
+                                InetSocketAddress isa  = (InetSocketAddress)info.address();
+                                if (!addressMap.containsKey(isa)) {
+                                    /* must be a new association */
+                                    try {
+                                        sm.checkAccept(isa.getAddress().getHostAddress(),
+                                                       isa.getPort());
+                                    } catch (SecurityException se) {
+                                        buffer.clear();
+                                        throw se;
+                                    }
+                                }
+                            }
+
+                            assert info.association() != null;
+                            return info;
+                        } else  {
+                          /* Non-blocking may return null if nothing available*/
+                            return null;
+                        }
+                    } else { /* notification */
+                        synchronized (stateLock) {
+                            handleNotificationInternal(
+                                    resultContainer);
+                        }
+                    }
+                } /* receiveLock */
+            } while (handler == null ? true :
+                (invokeNotificationHandler(resultContainer, handler, attachment)
+                 == HandlerResult.CONTINUE));
+        } finally {
+            receiveInvoked.set(Boolean.FALSE);
+        }
+
+        return null;
+    }
+
+    private int receive(int fd,
+                        ByteBuffer dst,
+                        SctpResultContainer resultContainer)
+            throws IOException {
+        int pos = dst.position();
+        int lim = dst.limit();
+        assert (pos <= lim);
+        int rem = (pos <= lim ? lim - pos : 0);
+        if (dst instanceof DirectBuffer && rem > 0)
+            return receiveIntoNativeBuffer(fd, resultContainer, dst, rem, pos);
+
+        /* Substitute a native buffer. */
+        int newSize = Math.max(rem, 1);
+        ByteBuffer bb = Util.getTemporaryDirectBuffer(newSize);
+        try {
+            int n = receiveIntoNativeBuffer(fd, resultContainer, bb, newSize, 0);
+            bb.flip();
+            if (n > 0 && rem > 0)
+                dst.put(bb);
+            return n;
+        } finally {
+            Util.releaseTemporaryDirectBuffer(bb);
+        }
+    }
+
+    private int receiveIntoNativeBuffer(int fd,
+                                        SctpResultContainer resultContainer,
+                                        ByteBuffer bb,
+                                        int rem,
+                                        int pos)
+            throws IOException {
+        int n = receive0(fd, resultContainer, ((DirectBuffer)bb).address() + pos, rem);
+        if (n > 0)
+            bb.position(pos + n);
+        return n;
+    }
+
+    private InternalNotificationHandler internalNotificationHandler =
+            new InternalNotificationHandler();
+
+    private void handleNotificationInternal(SctpResultContainer resultContainer)
+    {
+        invokeNotificationHandler(resultContainer,
+                internalNotificationHandler, null);
+    }
+
+    private class InternalNotificationHandler<T>
+            extends AbstractNotificationHandler<T>
+    {
+        @Override
+        public HandlerResult handleNotification(
+                AssociationChangeNotification not, T unused) {
+            SctpAssocChange sac = (SctpAssocChange) not;
+
+            /* Update map to reflect change in association */
+            switch (not.event()) {
+                case COMM_UP :
+                    Association newAssociation = new SctpAssociationImpl
+                       (sac.assocId(), sac.maxInStreams(), sac.maxOutStreams());
+                    addAssociation(newAssociation);
+                    break;
+                case SHUTDOWN :
+                case COMM_LOST :
+                //case RESTART: ???
+                    /* mark association for removal after user handler invoked*/
+                    associationToRemove.set(lookupAssociation(sac.assocId()));
+            }
+            return HandlerResult.CONTINUE;
+        }
+    }
+
+    private <T> HandlerResult invokeNotificationHandler(
+                                   SctpResultContainer resultContainer,
+                                   NotificationHandler<T> handler,
+                                   T attachment) {
+        HandlerResult result;
+        SctpNotification notification = resultContainer.notification();
+        notification.setAssociation(lookupAssociation(notification.assocId()));
+
+        if (!(handler instanceof AbstractNotificationHandler)) {
+            result = handler.handleNotification(notification, attachment);
+        } else { /* AbstractNotificationHandler */
+            AbstractNotificationHandler absHandler =
+                    (AbstractNotificationHandler)handler;
+            switch(resultContainer.type()) {
+                case ASSOCIATION_CHANGED :
+                    result = absHandler.handleNotification(
+                            resultContainer.getAssociationChanged(), attachment);
+                case PEER_ADDRESS_CHANGED :
+                    result = absHandler.handleNotification(
+                            resultContainer.getPeerAddressChanged(), attachment);
+                case SEND_FAILED :
+                    result = absHandler.handleNotification(
+                            resultContainer.getSendFailed(), attachment);
+                case SHUTDOWN :
+                    result =  absHandler.handleNotification(
+                            resultContainer.getShutdown(), attachment);
+                default :
+                    /* implementation specific handlers */
+                    result =  absHandler.handleNotification(
+                            resultContainer.notification(), attachment);
+            }
+        }
+
+        if (!(handler instanceof InternalNotificationHandler)) {
+            /* Only remove associations after user handler
+             * has finished with them */
+            Association assoc = associationToRemove.get();
+            if (assoc != null) {
+                removeAssociation(assoc);
+                associationToRemove.set(null);
+            }
+
+        }
+
+        return result;
+    }
+
+    private Association lookupAssociation(int assocId) {
+        /* Lookup the association in our internal map */
+        synchronized (stateLock) {
+            Set<Association> assocs = associationMap.keySet();
+            for (Association a : assocs) {
+                if (a.associationID() == assocId) {
+                    return a;
+                }
+            }
+        }
+        return null;
+    }
+
+    private void addAssociation(Association association) {
+        synchronized (stateLock) {
+            int assocId = association.associationID();
+            Set<SocketAddress> addresses = null;
+
+            try {
+                addresses = SctpNet.getRemoteAddresses(fdVal, assocId);
+            } catch (IOException unused) {
+                /* OK, determining connected addresses may not be possible
+                 * shutdown, connection lost, etc */
+            }
+
+            associationMap.put(association, addresses);
+            if (addresses != null) {
+                for (SocketAddress addr : addresses)
+                    addressMap.put(addr, association);
+            }
+        }
+    }
+
+    private void removeAssociation(Association association) {
+        synchronized (stateLock) {
+            int assocId = association.associationID();
+            Set<SocketAddress> addresses = null;
+
+            try {
+                addresses = SctpNet.getRemoteAddresses(fdVal, assocId);
+            } catch (IOException unused) {
+                /* OK, determining connected addresses may not be possible
+                 * shutdown, connection lost, etc */
+            }
+
+            Set<Association> assocs = associationMap.keySet();
+            for (Association a : assocs) {
+                if (a.associationID() == assocId) {
+                    associationMap.remove(a);
+                    break;
+                }
+            }
+            if (addresses != null) {
+                for (SocketAddress addr : addresses)
+                    addressMap.remove(addr);
+            } else {
+                /* We cannot determine the connected addresses */
+                Set<java.util.Map.Entry<SocketAddress, Association>> addrAssocs =
+                        addressMap.entrySet();
+                for (java.util.Map.Entry<SocketAddress, Association> entry : addrAssocs) {
+                    if (entry.getValue().equals(association)) {
+                        addressMap.remove(entry.getKey());
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * @throws  IllegalArgumentException
+     *          If the given association is not controlled by this channel
+     *
+     * @return  {@code true} if, and only if, the given association is one
+     *          of the current associations controlled by this channel
+     */
+    private boolean checkAssociation(Association messageAssoc) {
+        synchronized (stateLock) {
+            for (Association association : associationMap.keySet()) {
+                if (messageAssoc.equals(association)) {
+                    return true;
+                }
+            }
+        }
+        throw new IllegalArgumentException(
+              "Given Association is not controlled by this channel");
+    }
+
+    private void checkStreamNumber(Association assoc, int streamNumber) {
+        synchronized (stateLock) {
+            if (streamNumber < 0 || streamNumber >= assoc.maxOutboundStreams())
+                throw new InvalidStreamException();
+        }
+    }
+
+    /* TODO: Add support for ttl and isComplete to both 121 12M
+     *       SCTP_EOR not yet supported on reference platforms
+     *       TTL support limited...
+     */
+    @Override
+    public int send(ByteBuffer buffer, MessageInfo messageInfo)
+            throws IOException {
+        if (buffer == null)
+            throw new IllegalArgumentException("buffer cannot be null");
+
+        if (messageInfo == null)
+            throw new IllegalArgumentException("messageInfo cannot be null");
+
+        synchronized (sendLock) {
+            ensureOpen();
+
+            if (!isBound())
+                bind(null, 0);
+
+            int n = 0;
+            try {
+                int assocId = -1;
+                SocketAddress address = null;
+                begin();
+
+                synchronized (stateLock) {
+                    if(!isOpen())
+                        return 0;
+                    senderThread = NativeThread.current();
+
+                    /* Determine what address or association to send to */
+                    Association assoc = messageInfo.association();
+                    InetSocketAddress addr = (InetSocketAddress)messageInfo.address();
+                    if (assoc != null) {
+                        checkAssociation(assoc);
+                        checkStreamNumber(assoc, messageInfo.streamNumber());
+                        assocId = assoc.associationID();
+                        /* have we also got a preferred address */
+                        if (addr != null) {
+                            if (!assoc.equals(addressMap.get(addr)))
+                                throw new IllegalArgumentException("given preferred address is not part of this association");
+                            address = addr;
+                        }
+                    } else if (addr != null) {
+                        address = addr;
+                        Association association = addressMap.get(addr);
+                        if (association != null) {
+                            checkStreamNumber(association, messageInfo.streamNumber());
+                            assocId = association.associationID();
+
+                        } else { /* must be new association */
+                            SecurityManager sm = System.getSecurityManager();
+                            if (sm != null)
+                                sm.checkConnect(addr.getAddress().getHostAddress(),
+                                                addr.getPort());
+                        }
+                    } else {
+                        throw new AssertionError(
+                            "Both association and address cannot be null");
+                    }
+                }
+
+                do {
+                    n = send(fdVal, buffer, assocId, address, messageInfo);
+                } while ((n == IOStatus.INTERRUPTED) && isOpen());
+
+                return IOStatus.normalize(n);
+            } finally {
+                senderCleanup();
+                end((n > 0) || (n == IOStatus.UNAVAILABLE));
+                assert IOStatus.check(n);
+            }
+        }
+    }
+
+    private int send(int fd,
+                     ByteBuffer src,
+                     int assocId,
+                     SocketAddress target,
+                     MessageInfo messageInfo)
+            throws IOException {
+        int streamNumber = messageInfo.streamNumber();
+        boolean unordered = messageInfo.isUnordered();
+        int ppid = messageInfo.payloadProtocolID();
+        int pos = src.position();
+        int lim = src.limit();
+        assert (pos <= lim && streamNumber > 0);
+        int rem = (pos <= lim ? lim - pos : 0);
+
+        if (src instanceof DirectBuffer)
+            return sendFromNativeBuffer(fd, src, rem, pos, target, assocId,
+                    streamNumber, unordered, ppid);
+
+        /* Substitute a native buffer */
+        ByteBuffer bb = Util.getTemporaryDirectBuffer(rem);
+        try {
+            bb.put(src);
+            bb.flip();
+            /* Do not update src until we see how many bytes were written */
+            src.position(pos);
+
+            int n = sendFromNativeBuffer(fd, bb, rem, pos, target, assocId,
+                    streamNumber, unordered, ppid);
+            if (n > 0) {
+                /* now update src */
+                src.position(pos + n);
+            }
+            return n;
+        } finally {
+            Util.releaseTemporaryDirectBuffer(bb);
+        }
+    }
+
+    private int sendFromNativeBuffer(int fd,
+                                     ByteBuffer bb,
+                                     int rem,
+                                     int pos,
+                                     SocketAddress target,
+                                     int assocId,
+                                     int streamNumber,
+                                     boolean unordered,
+                                     int ppid)
+            throws IOException {
+        int written = send0(fd, ((DirectBuffer)bb).address() + pos,
+                            rem, target, assocId, streamNumber, unordered, ppid);
+        if (written > 0)
+            bb.position(pos + written);
+        return written;
+    }
+
+    @Override
+    public SctpMultiChannel shutdown(Association association)
+            throws IOException {
+        synchronized (stateLock) {
+            checkAssociation(association);
+            if (!isOpen())
+                throw new ClosedChannelException();
+
+            SctpNet.shutdown(fdVal, association.associationID());
+        }
+        return this;
+    }
+
+    @Override
+    public Set<SocketAddress> getAllLocalAddresses()
+            throws IOException {
+        synchronized (stateLock) {
+            if (!isOpen())
+                throw new ClosedChannelException();
+            if (!isBound())
+                return Collections.EMPTY_SET;
+
+            return SctpNet.getLocalAddresses(fdVal);
+        }
+    }
+
+    @Override
+    public Set<SocketAddress> getRemoteAddresses(Association association)
+            throws IOException {
+        synchronized (stateLock) {
+            checkAssociation(association);
+            if (!isOpen())
+                throw new ClosedChannelException();
+
+            return SctpNet.getRemoteAddresses(fdVal, association.associationID());
+        }
+    }
+
+    @Override
+    public SctpChannel branch(Association association)
+            throws IOException {
+        synchronized (stateLock) {
+            return null;  //TODO: implement
+        }
+    }
+
+    /* Use common native implementation shared between
+     * one-to-one and one-to-many */
+    private static int receive0(int fd,
+                                SctpResultContainer resultContainer,
+                                long address,
+                                int length)
+            throws IOException{
+        return SctpChannelImpl.receive0(fd, resultContainer, address,
+                length);
+    }
+
+    private static int send0(int fd,
+                             long address,
+                             int length,
+                             SocketAddress target,
+                             int assocId,
+                             int streamNumber,
+                             boolean unordered,
+                             int ppid)
+            throws IOException {
+        return SctpChannelImpl.send0(fd, address, length, target, assocId,
+                streamNumber, unordered, ppid);
+    }
+
+    static {
+        Util.load();   /* loads nio & net native libraries */
+        java.security.AccessController.doPrivileged(
+                new sun.security.action.LoadLibraryAction("sctp"));
+        nd = new SctpSocketDispatcher();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/SctpNet.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,268 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package sun.nio.ch;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.util.Set;
+import java.util.HashSet;
+import java.security.AccessController;
+import sun.security.action.GetPropertyAction;
+import com.sun.nio.sctp.SctpSocketOption;
+import static com.sun.nio.sctp.SctpStandardSocketOption.*;
+
+public class SctpNet {
+    static final String osName = AccessController.doPrivileged(
+                    new GetPropertyAction("os.name"));
+
+    /* -- Miscellaneous SCTP utilities -- */
+
+    static boolean bindxIPv4MappedAddresses() {
+        if ("SunOS".equals(osName)) {
+            /* Solaris supports IPv4Mapped Addresses with bindx */
+            return true;
+        } /* else {  //other OS/implementations  */
+
+        /* lksctp/linux requires Ipv4 addresses */
+        return false;
+    }
+
+    /**
+     * @param  oneToone
+     *         if {@code true} returns a one-to-one sctp socket, otherwise
+     *         returns a one-to-many sctp socket
+     */
+    static FileDescriptor socket(boolean oneToOne) throws IOException {
+        int nativefd = socket0(oneToOne);
+        return IOUtil.newFD(nativefd);
+    }
+
+    static void bindx(int fd, InetAddress[] addrs, int port, boolean add)
+            throws IOException {
+        bindx(fd, addrs, port, addrs.length, add,
+                bindxIPv4MappedAddresses());
+    }
+
+    static Set<SocketAddress> getLocalAddresses(int fd)
+            throws IOException {
+        HashSet<SocketAddress> set = null;
+        SocketAddress[] saa = getLocalAddresses0(fd);
+
+        if (saa != null) {
+            set = new HashSet<SocketAddress>(saa.length);
+            for (SocketAddress sa : saa)
+                set.add(sa);
+        }
+
+        return set;
+    }
+
+    static Set<SocketAddress> getRemoteAddresses(int fd, int assocId)
+            throws IOException {
+        HashSet<SocketAddress> set = null;
+        SocketAddress[] saa = getRemoteAddresses0(fd, assocId);
+
+        if (saa != null) {
+            set = new HashSet<SocketAddress>(saa.length);
+            for (SocketAddress sa : saa)
+                set.add(sa);
+        }
+
+        return set;
+    }
+
+    static void setSocketOption(int fd,
+                                SctpSocketOption name,
+                                Object value,
+                                int assocId)
+            throws IOException {
+        if (value == null)
+            throw new IllegalArgumentException("Invalid option value");
+
+        Class<?> type = name.type();
+        if (!type.isInstance(value))
+            throw new IllegalArgumentException("Invalid option value");
+
+        if (name.equals(SCTP_INIT_MAXSTREAMS)) {
+            InitMaxStreams maxStreamValue = (InitMaxStreams)value;
+            SctpNet.setInitMsgOption0(fd,
+                 maxStreamValue.maxInStreams(), maxStreamValue.maxOutStreams());
+        } else if (name.equals(SCTP_PRIMARY_ADDR) ||
+                   name.equals(SCTP_SET_PEER_PRIMARY_ADDR)) {
+
+            SocketAddress addr  = (SocketAddress) value;
+            if (addr == null)
+                throw new IllegalArgumentException("Invalid option value");
+
+            Net.checkAddress(addr);
+            InetSocketAddress netAddr = (InetSocketAddress)addr;
+
+            if (name.equals(SCTP_PRIMARY_ADDR)) {
+                setPrimAddrOption0(fd, assocId,
+                        netAddr.getAddress(), netAddr.getPort());
+            } else {
+                setPeerPrimAddrOption0(fd, assocId,
+                        netAddr.getAddress(), netAddr.getPort());
+            }
+        } else if (name.equals(SCTP_DISABLE_FRAGMENTS) ||
+            name.equals(SCTP_EXPLICIT_COMPLETE) ||
+            name.equals(SCTP_FRAGMENT_INTERLEAVE) ||
+            name.equals(SCTP_NODELAY) ||
+            name.equals(SO_SNDBUF) ||
+            name.equals(SO_RCVBUF) ||
+            name.equals(SO_LINGER)) {
+            setIntOption(fd, name, value);
+        } else {
+            throw new AssertionError("Unknown socket option");
+        }
+    }
+
+    static Object getSocketOption(int fd, SctpSocketOption name, int assocId)
+             throws IOException {
+         if (name.equals(SCTP_SET_PEER_PRIMARY_ADDR)) {
+            throw new IllegalArgumentException(
+                    "SCTP_SET_PEER_PRIMARY_ADDR cannot be retrieved");
+        } else if (name.equals(SCTP_INIT_MAXSTREAMS)) {
+            /* container for holding maxIn/Out streams */
+            int[] values = new int[2];
+            SctpNet.getInitMsgOption0(fd, values);
+            return InitMaxStreams.create(values[0], values[1]);
+        } else if (name.equals(SCTP_PRIMARY_ADDR)) {
+            return getPrimAddrOption0(fd, assocId);
+        } else if (name.equals(SCTP_DISABLE_FRAGMENTS) ||
+            name.equals(SCTP_EXPLICIT_COMPLETE) ||
+            name.equals(SCTP_FRAGMENT_INTERLEAVE) ||
+            name.equals(SCTP_NODELAY) ||
+            name.equals(SO_SNDBUF) ||
+            name.equals(SO_RCVBUF) ||
+            name.equals(SO_LINGER)) {
+            return getIntOption(fd, name);
+        } else {
+            throw new AssertionError("Unknown socket option");
+        }
+    }
+
+    static void setIntOption(int fd, SctpSocketOption name, Object value)
+            throws IOException {
+        if (value == null)
+            throw new IllegalArgumentException("Invalid option value");
+
+        Class<?> type = name.type();
+        if (type != Integer.class && type != Boolean.class)
+            throw new AssertionError("Should not reach here");
+
+        if (name == SO_RCVBUF ||
+            name == SO_SNDBUF)
+        {
+            int i = ((Integer)value).intValue();
+            if (i < 0)
+                throw new IllegalArgumentException(
+                        "Invalid send/receive buffer size");
+        } else if (name == SO_LINGER) {
+            int i = ((Integer)value).intValue();
+            if (i < 0)
+                value = Integer.valueOf(-1);
+            if (i > 65535)
+                value = Integer.valueOf(65535);
+        } else if (name.equals(SCTP_FRAGMENT_INTERLEAVE)) {
+            int i = ((Integer)value).intValue();
+            if (i < 0 || i > 2)
+                throw new IllegalArgumentException(
+                        "Invalid value for SCTP_FRAGMENT_INTERLEAVE");
+        }
+
+        int arg;
+        if (type == Integer.class) {
+            arg = ((Integer)value).intValue();
+        } else {
+            boolean b = ((Boolean)value).booleanValue();
+            arg = (b) ? 1 : 0;
+        }
+
+        setIntOption0(fd, ((SctpStdSocketOption)name).constValue(), arg);
+    }
+
+    static Object getIntOption(int fd, SctpSocketOption name)
+            throws IOException {
+        Class<?> type = name.type();
+
+        if (type != Integer.class && type != Boolean.class)
+            throw new AssertionError("Should not reach here");
+
+        if (!(name instanceof SctpStdSocketOption))
+            throw new AssertionError("Should not reach here");
+
+        int value = getIntOption0(fd,
+                ((SctpStdSocketOption)name).constValue());
+
+        if (type == Integer.class) {
+            return Integer.valueOf(value);
+        } else {
+            return (value == 0) ? Boolean.FALSE : Boolean.TRUE;
+        }
+    }
+
+    static void shutdown(int fd, int assocId)
+            throws IOException {
+        shutdown0(fd, assocId);
+    }
+
+    /* Native Methods */
+    static native int socket0(boolean oneToOne) throws IOException;
+
+    static native void bindx(int fd, InetAddress[] addrs, int port, int length,
+            boolean add, boolean preferIPv6) throws IOException;
+
+    static native int getIntOption0(int fd, int opt) throws IOException;
+
+    static native void setIntOption0(int fd, int opt, int arg)
+        throws IOException;
+
+    static native SocketAddress[] getLocalAddresses0(int fd) throws IOException;
+
+    static native SocketAddress[] getRemoteAddresses0(int fd, int assocId)
+            throws IOException;
+
+    static native void setPrimAddrOption0(int fd, int assocId, InetAddress ia,
+            int port) throws IOException;
+
+    static native void setPeerPrimAddrOption0(int fd, int assocId,
+            InetAddress ia, int port) throws IOException;
+
+    static native SocketAddress getPrimAddrOption0(int fd, int assocId)
+            throws IOException;
+
+    /* retVals [0] maxInStreams, [1] maxOutStreams */
+    static native void getInitMsgOption0(int fd, int[] retVals) throws IOException;
+
+    static native void setInitMsgOption0(int fd, int arg1, int arg2)
+            throws IOException;
+
+    static native void shutdown0(int fd, int assocId);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/SctpNotification.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package sun.nio.ch;
+
+import com.sun.nio.sctp.Association;
+import com.sun.nio.sctp.Notification;
+
+/**
+ * All Notification implemenations MUST implement this interface to provide
+ * access to the native association identidier.
+ */
+interface SctpNotification extends Notification {
+    int assocId();
+    void setAssociation(Association association);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/SctpPeerAddrChange.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package sun.nio.ch;
+
+import java.net.SocketAddress;
+import com.sun.nio.sctp.Association;
+import com.sun.nio.sctp.PeerAddressChangeNotification;
+
+/**
+ * An implementation of PeerAddressChangeNotification
+ */
+public class SctpPeerAddrChange extends PeerAddressChangeNotification
+    implements SctpNotification
+{
+    /* static final ints so that they can be referenced from native */
+    private final static int SCTP_ADDR_AVAILABLE = 1;
+    private final static int SCTP_ADDR_UNREACHABLE = 2;
+    private final static int SCTP_ADDR_REMOVED = 3;
+    private final static int SCTP_ADDR_ADDED = 4;
+    private final static int SCTP_ADDR_MADE_PRIM = 5;
+    private final static int SCTP_ADDR_CONFIRMED =6;
+
+    private Association association;
+
+    /* assocId is used to lookup the association before the notification is
+     * returned to user code */
+    private int assocId;
+    private SocketAddress address;
+    private AddressChangeEvent event;
+
+    /* Invoked from native */
+    private SctpPeerAddrChange(int assocId, SocketAddress address, int intEvent) {
+        switch (intEvent) {
+            case SCTP_ADDR_AVAILABLE :
+                this.event = AddressChangeEvent.ADDR_AVAILABLE;
+                break;
+            case SCTP_ADDR_UNREACHABLE :
+                this.event = AddressChangeEvent.ADDR_UNREACHABLE;
+                break;
+            case SCTP_ADDR_REMOVED :
+                this.event = AddressChangeEvent.ADDR_REMOVED;
+                break;
+            case SCTP_ADDR_ADDED :
+                this.event = AddressChangeEvent.ADDR_ADDED;
+                break;
+            case SCTP_ADDR_MADE_PRIM :
+                this.event = AddressChangeEvent.ADDR_MADE_PRIMARY;
+                break;
+            case SCTP_ADDR_CONFIRMED :
+                this.event = AddressChangeEvent.ADDR_CONFIRMED;
+                break;
+            default:
+                throw new AssertionError("Unknown event type");
+        }
+        this.assocId = assocId;
+        this.address = address;
+    }
+
+    @Override
+    public int assocId() {
+        return assocId;
+    }
+
+    @Override
+    public void setAssociation(Association association) {
+        this.association = association;
+    }
+
+    @Override
+    public SocketAddress address() {
+        assert address != null;
+        return address;
+    }
+
+    @Override
+    public Association association() {
+        assert association != null;
+        return association;
+    }
+
+    @Override
+    public AddressChangeEvent event() {
+        assert event != null;
+        return event;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(super.toString()).append(" [");
+        sb.append("Address: ").append(address);
+        sb.append(", Association:").append(association);
+        sb.append(", Event: ").append(event).append("]");
+        return sb.toString();
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/SctpResultContainer.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package sun.nio.ch;
+
+/**
+ * Wraps the actual message or notification so that it can be
+ * set and returned from the native receive implementation.
+ */
+public class SctpResultContainer {
+    /* static final ints so that they can be referenced from native */
+    static final int NOTHING = 0;
+    static final int MESSAGE = 1;
+    static final int SEND_FAILED = 2;
+    static final int ASSOCIATION_CHANGED = 3;
+    static final int PEER_ADDRESS_CHANGED = 4;
+    static final int SHUTDOWN = 5;
+
+    private Object value;
+    private int type;
+
+    int type() {
+        return type;
+    }
+
+    boolean hasSomething() {
+        return type() != NOTHING;
+    }
+
+    boolean isNotification() {
+        return type() != MESSAGE && type() != NOTHING ? true : false;
+    }
+
+    void clear() {
+        type = NOTHING;
+        value = null;
+    }
+
+    SctpNotification notification() {
+        assert type() != MESSAGE && type() != NOTHING;
+
+        return (SctpNotification) value;
+    }
+
+    SctpMessageInfoImpl getMessageInfo() {
+        assert type() == MESSAGE;
+
+        if (value instanceof SctpMessageInfoImpl)
+            return (SctpMessageInfoImpl) value;
+
+        return null;
+    }
+
+    SctpSendFailed getSendFailed() {
+        assert type() == SEND_FAILED;
+
+        if (value instanceof SctpSendFailed)
+            return (SctpSendFailed) value;
+
+        return null;
+    }
+
+    SctpAssocChange getAssociationChanged() {
+        assert type() == ASSOCIATION_CHANGED;
+
+        if (value instanceof SctpAssocChange)
+            return (SctpAssocChange) value;
+
+        return null;
+    }
+
+    SctpPeerAddrChange getPeerAddressChanged() {
+        assert type() == PEER_ADDRESS_CHANGED;
+
+        if (value instanceof SctpPeerAddrChange)
+            return (SctpPeerAddrChange) value;
+
+        return null;
+    }
+
+    SctpShutdown getShutdown() {
+        assert type() == SHUTDOWN;
+
+        if (value instanceof SctpShutdown)
+            return (SctpShutdown) value;
+
+        return null;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("Type: ");
+        switch (type) {
+            case NOTHING:              sb.append("NOTHING");             break;
+            case MESSAGE:              sb.append("MESSAGE");             break;
+            case SEND_FAILED:          sb.append("SEND FAILED");         break;
+            case ASSOCIATION_CHANGED:  sb.append("ASSOCIATION CHANGE");  break;
+            case PEER_ADDRESS_CHANGED: sb.append("PEER ADDRESS CHANGE"); break;
+            case SHUTDOWN:             sb.append("SHUTDOWN");            break;
+            default :                  sb.append("Unknown result type");
+        }
+       return sb.append(", Value: ").append(value.toString()).toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/SctpSendFailed.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package sun.nio.ch;
+
+import java.nio.ByteBuffer;
+import java.net.SocketAddress;
+import com.sun.nio.sctp.Association;
+import com.sun.nio.sctp.SendFailedNotification;
+
+/**
+ * An implementation of SendFailedNotification
+ */
+public class SctpSendFailed extends SendFailedNotification
+    implements SctpNotification
+{
+    private Association association;
+    /* assocId is used to lookup the association before the notification is
+     * returned to user code */
+    private int assocId;
+    private SocketAddress address;
+    private ByteBuffer buffer;
+    private int errorCode;
+    private int streamNumber;
+
+    /* Invoked from native */
+    private SctpSendFailed(int assocId,
+                           SocketAddress address,
+                           ByteBuffer buffer,
+                           int errorCode,
+                           int streamNumber) {
+        this.assocId = assocId;
+        this.errorCode = errorCode;
+        this.streamNumber = streamNumber;
+        this.address = address;
+        this.buffer = buffer;
+    }
+
+    @Override
+    public int assocId() {
+        return assocId;
+    }
+
+    @Override
+    public void setAssociation(Association association) {
+        this.association = association;
+    }
+
+    @Override
+    public Association association() {
+        /* may be null */
+        return association;
+    }
+
+    @Override
+    public SocketAddress address() {
+        assert address != null;
+        return address;
+    }
+
+    @Override
+    public ByteBuffer buffer() {
+        assert buffer != null;
+        return buffer;
+    }
+
+    @Override
+    public int errorCode() {
+        return errorCode;
+    }
+
+    @Override
+    public int streamNumber() {
+        return streamNumber;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(super.toString()).append(" [");
+        sb.append("Association:").append(association);
+        sb.append(", Address: ").append(address);
+        sb.append(", buffer: ").append(buffer);
+        sb.append(", errorCode: ").append(errorCode);
+        sb.append(", streamNumber: ").append(streamNumber);
+        sb.append("]");
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/SctpServerChannelImpl.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,429 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package sun.nio.ch;
+
+import java.net.SocketAddress;
+import java.net.InetSocketAddress;
+import java.net.InetAddress;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Set;
+import java.util.HashSet;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.AlreadyBoundException;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.NotYetBoundException;
+import java.nio.channels.spi.SelectorProvider;
+import com.sun.nio.sctp.IllegalUnbindException;
+import com.sun.nio.sctp.SctpChannel;
+import com.sun.nio.sctp.SctpServerChannel;
+import com.sun.nio.sctp.SctpSocketOption;
+import com.sun.nio.sctp.SctpStandardSocketOption;
+
+/**
+ * An implementation of SctpServerChannel
+ */
+public class SctpServerChannelImpl extends SctpServerChannel
+    implements SelChImpl
+{
+    /* Used to make native close and preClose calls */
+    private static NativeDispatcher nd;
+
+    private final FileDescriptor fd;
+
+    private final int fdVal;
+
+    /* IDs of native thread doing accept, for signalling */
+    private volatile long thread = 0;
+
+    /* Lock held by thread currently blocked in this channel */
+    private final Object lock = new Object();
+
+    /* Lock held by any thread that modifies the state fields declared below
+     * DO NOT invoke a blocking I/O operation while holding this lock! */
+    private final Object stateLock = new Object();
+
+    private enum ChannelState {
+        UNINITIALIZED,
+        INUSE,
+        KILLPENDING,
+        KILLED,
+    }
+    /* -- The following fields are protected by stateLock -- */
+    private ChannelState state = ChannelState.UNINITIALIZED;
+
+    /* Binding: Once bound the port will remain constant. */
+    int port = -1;
+    private HashSet<InetSocketAddress> localAddresses = new HashSet<InetSocketAddress>();
+    /* Has the channel been bound to the wildcard address */
+    private boolean wildcard; /* false */
+
+    /* -- End of fields protected by stateLock -- */
+
+    /**
+     * Initializes a new instance of this class.
+     */
+    public SctpServerChannelImpl(SelectorProvider provider)
+            throws IOException {
+        //TODO: update provider remove public modifier
+        super(provider);
+        this.fd = SctpNet.socket(true);
+        this.fdVal = IOUtil.fdVal(fd);
+        this.state = ChannelState.INUSE;
+    }
+
+    @Override
+    public SctpServerChannel bind(SocketAddress local, int backlog)
+            throws IOException {
+        synchronized (lock) {
+            synchronized (stateLock) {
+                if (!isOpen())
+                    throw new ClosedChannelException();
+                if (isBound())
+                    throw new AlreadyBoundException();
+
+                InetSocketAddress isa = (local == null) ?
+                    new InetSocketAddress(0) : Net.checkAddress(local);
+                SecurityManager sm = System.getSecurityManager();
+                if (sm != null)
+                    sm.checkListen(isa.getPort());
+                Net.bind(fd, isa.getAddress(), isa.getPort());
+
+                InetSocketAddress boundIsa = Net.localAddress(fd);
+                port = boundIsa.getPort();
+                localAddresses.add(isa);
+                    if (isa.getAddress().isAnyLocalAddress())
+                        wildcard = true;
+
+                Net.listen(fd, backlog < 1 ? 50 : backlog);
+            }
+        }
+        return this;
+    }
+
+    @Override
+    public SctpServerChannel bindAddress(InetAddress address)
+            throws IOException {
+        return bindUnbindAddress(address, true);
+    }
+
+    @Override
+    public SctpServerChannel unbindAddress(InetAddress address)
+            throws IOException {
+        return bindUnbindAddress(address, false);
+    }
+
+    private SctpServerChannel bindUnbindAddress(InetAddress address, boolean add)
+            throws IOException {
+        if (address == null)
+            throw new IllegalArgumentException();
+
+        synchronized (lock) {
+            synchronized (stateLock) {
+                if (!isOpen())
+                    throw new ClosedChannelException();
+                if (!isBound())
+                    throw new NotYetBoundException();
+                if (wildcard)
+                    throw new IllegalStateException(
+                            "Cannot add or remove addresses from a channel that is bound to the wildcard address");
+                if (address.isAnyLocalAddress())
+                    throw new IllegalArgumentException(
+                            "Cannot add or remove the wildcard address");
+                if (add) {
+                    for (InetSocketAddress addr : localAddresses) {
+                        if (addr.getAddress().equals(address)) {
+                            throw new AlreadyBoundException();
+                        }
+                    }
+                } else { /*removing */
+                    /* Verify that there is more than one address
+                     * and that address is already bound */
+                    if (localAddresses.size() <= 1)
+                        throw new IllegalUnbindException("Cannot remove address from a channel with only one address bound");
+                    boolean foundAddress = false;
+                    for (InetSocketAddress addr : localAddresses) {
+                        if (addr.getAddress().equals(address)) {
+                            foundAddress = true;
+                            break;
+                        }
+                    }
+                    if (!foundAddress )
+                        throw new IllegalUnbindException("Cannot remove address from a channel that is not bound to that address");
+                }
+
+                SctpNet.bindx(fdVal, new InetAddress[]{address}, port, add);
+
+                /* Update our internal Set to reflect the addition/removal */
+                if (add)
+                    localAddresses.add(new InetSocketAddress(address, port));
+                else {
+                    for (InetSocketAddress addr : localAddresses) {
+                        if (addr.getAddress().equals(address)) {
+                            localAddresses.remove(addr);
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+        return this;
+    }
+
+    private boolean isBound() {
+        synchronized (stateLock) {
+            return port == -1 ? false : true;
+        }
+    }
+
+    private void acceptCleanup() throws IOException {
+        synchronized (stateLock) {
+            thread = 0;
+            if (state == ChannelState.KILLPENDING)
+                kill();
+        }
+    }
+
+    @Override
+    public SctpChannel accept() throws IOException {
+        synchronized (lock) {
+            if (!isOpen())
+                throw new ClosedChannelException();
+            if (!isBound())
+                throw new NotYetBoundException();
+            SctpChannel sc = null;
+
+            int n = 0;
+            FileDescriptor newfd = new FileDescriptor();
+            InetSocketAddress[] isaa = new InetSocketAddress[1];
+
+            try {
+                begin();
+                if (!isOpen())
+                    return null;
+                thread = NativeThread.current();
+                for (;;) {
+                    n = accept0(fd, newfd, isaa);
+                    if ((n == IOStatus.INTERRUPTED) && isOpen())
+                        continue;
+                    break;
+                }
+            } finally {
+                acceptCleanup();
+                end(n > 0);
+                assert IOStatus.check(n);
+            }
+
+            if (n < 1)
+                return null;
+
+            IOUtil.configureBlocking(newfd, true);
+            InetSocketAddress isa = isaa[0];
+            sc = new SctpChannelImpl(provider(), newfd);
+
+            SecurityManager sm = System.getSecurityManager();
+            if (sm != null)
+                sm.checkAccept(isa.getAddress().getHostAddress(),
+                               isa.getPort());
+
+            return sc;
+        }
+    }
+
+    @Override
+    protected void implConfigureBlocking(boolean block) throws IOException {
+        IOUtil.configureBlocking(fd, block);
+    }
+
+    @Override
+    public void implCloseSelectableChannel() throws IOException {
+        synchronized (stateLock) {
+            nd.preClose(fd);
+            if (thread != 0)
+                NativeThread.signal(thread);
+            if (!isRegistered())
+                kill();
+        }
+    }
+
+    @Override
+    public void kill() throws IOException {
+        synchronized (stateLock) {
+            if (state == ChannelState.KILLED)
+                return;
+            if (state == ChannelState.UNINITIALIZED) {
+                state = ChannelState.KILLED;
+                return;
+            }
+            assert !isOpen() && !isRegistered();
+
+            // Postpone the kill if there is a thread in accept
+            if (thread == 0) {
+                nd.close(fd);
+                state = ChannelState.KILLED;
+            } else {
+                state = ChannelState.KILLPENDING;
+            }
+        }
+    }
+
+    @Override
+    public FileDescriptor getFD() {
+        return fd;
+    }
+
+    @Override
+    public int getFDVal() {
+        return fdVal;
+    }
+
+    /**
+     * Translates native poll revent ops into a ready operation ops
+     */
+    private boolean translateReadyOps(int ops, int initialOps,
+                                     SelectionKeyImpl sk) {
+        int intOps = sk.nioInterestOps();
+        int oldOps = sk.nioReadyOps();
+        int newOps = initialOps;
+
+        if ((ops & PollArrayWrapper.POLLNVAL) != 0) {
+            /* This should only happen if this channel is pre-closed while a
+             * selection operation is in progress
+             * ## Throw an error if this channel has not been pre-closed */
+            return false;
+        }
+
+        if ((ops & (PollArrayWrapper.POLLERR
+                    | PollArrayWrapper.POLLHUP)) != 0) {
+            newOps = intOps;
+            sk.nioReadyOps(newOps);
+            return (newOps & ~oldOps) != 0;
+        }
+
+        if (((ops & PollArrayWrapper.POLLIN) != 0) &&
+            ((intOps & SelectionKey.OP_ACCEPT) != 0))
+                newOps |= SelectionKey.OP_ACCEPT;
+
+        sk.nioReadyOps(newOps);
+        return (newOps & ~oldOps) != 0;
+    }
+
+    @Override
+    public boolean translateAndUpdateReadyOps(int ops, SelectionKeyImpl sk) {
+        return translateReadyOps(ops, sk.nioReadyOps(), sk);
+    }
+
+    @Override
+    public boolean translateAndSetReadyOps(int ops, SelectionKeyImpl sk) {
+        return translateReadyOps(ops, 0, sk);
+    }
+
+    @Override
+    public void translateAndSetInterestOps(int ops, SelectionKeyImpl sk) {
+        int newOps = 0;
+
+        /* Translate ops */
+        if ((ops & SelectionKey.OP_ACCEPT) != 0)
+            newOps |= PollArrayWrapper.POLLIN;
+        /* Place ops into pollfd array */
+        sk.selector.putEventOps(sk, newOps);
+
+    }
+
+    @Override
+    public <T> SctpServerChannel setOption(SctpSocketOption<T> name, T value)
+            throws IOException {
+        if (name == null)
+            throw new NullPointerException();
+        if (!supportedOptions().contains(name))
+            throw new UnsupportedOperationException("'" + name + "' not supported");
+
+        synchronized (stateLock) {
+            if (!isOpen())
+                throw new ClosedChannelException();
+
+            SctpNet.setSocketOption(fdVal, name, value, 0 /*oneToOne*/);
+            return this;
+        }
+    }
+
+    @Override
+    public <T> T getOption(SctpSocketOption<T> name) throws IOException {
+        if (name == null)
+            throw new NullPointerException();
+        if (!supportedOptions().contains(name))
+            throw new UnsupportedOperationException("'" + name + "' not supported");
+
+        synchronized (stateLock) {
+            if (!isOpen())
+                throw new ClosedChannelException();
+
+            return (T) SctpNet.getSocketOption(fdVal, name, 0 /*oneToOne*/);
+        }
+    }
+
+    private static class DefaultOptionsHolder {
+        static final Set<SctpSocketOption<?>> defaultOptions = defaultOptions();
+
+        private static Set<SctpSocketOption<?>> defaultOptions() {
+            HashSet<SctpSocketOption<?>> set = new HashSet<SctpSocketOption<?>>(1);
+            set.add(SctpStandardSocketOption.SCTP_INIT_MAXSTREAMS);
+            return Collections.unmodifiableSet(set);
+        }
+    }
+
+    @Override
+    public final Set<SctpSocketOption<?>> supportedOptions() {
+        return DefaultOptionsHolder.defaultOptions;
+    }
+
+    @Override
+    public Set<SocketAddress> getAllLocalAddresses()
+            throws IOException {
+        synchronized (stateLock) {
+            if (!isOpen())
+                throw new ClosedChannelException();
+            if (!isBound())
+                return null;
+
+            return SctpNet.getLocalAddresses(fdVal);
+        }
+    }
+
+    /* Native */
+    private static native void initIDs();
+
+    private static native int accept0(FileDescriptor ssfd,
+        FileDescriptor newfd, InetSocketAddress[] isaa) throws IOException;
+
+    static {
+        Util.load();   // loads nio & net native libraries
+        java.security.AccessController.doPrivileged(
+                new sun.security.action.LoadLibraryAction("sctp"));
+        nd = new SctpSocketDispatcher();
+        initIDs();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/SctpShutdown.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package sun.nio.ch;
+
+import com.sun.nio.sctp.Association;
+import com.sun.nio.sctp.ShutdownNotification;
+
+/**
+ * An implementation of ShutdownNotification
+ */
+public class SctpShutdown extends ShutdownNotification
+    implements SctpNotification
+{
+    private Association association;
+    /* assocId is used to lookup the association before the notification is
+     * returned to user code */
+    private int assocId;
+
+    /* Invoked from native */
+    private SctpShutdown(int assocId) {
+        this.assocId = assocId;
+    }
+
+    @Override
+    public int assocId() {
+        return assocId;
+    }
+
+    @Override
+    public void setAssociation(Association association) {
+        this.association = association;
+    }
+
+    @Override
+    public Association association() {
+        assert association != null;
+        return association;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(super.toString()).append(" [");
+        sb.append("Association:").append(association).append("]");
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/classes/sun/nio/ch/SctpSocketDispatcher.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package sun.nio.ch;
+
+import java.io.IOException;
+import java.io.FileDescriptor;
+
+/**
+ * Only used for {@code close} and {@code preclose}. All other methods
+ * throw {@code IOException}.
+ */
+class SctpSocketDispatcher extends NativeDispatcher {
+    @Override
+    @SuppressWarnings("unused")
+    int read(FileDescriptor fd, long address, int len) throws IOException {
+         throw new IOException("Operation Unsupported");
+    }
+
+    @Override
+    @SuppressWarnings("unused")
+    long readv(FileDescriptor fd, long address, int len) throws IOException {
+         throw new IOException("Operation Unsupported");
+    }
+
+    @Override
+    @SuppressWarnings("unused")
+    int write(FileDescriptor fd, long address, int len) throws IOException {
+         throw new IOException("Operation Unsupported");
+    }
+
+    @Override
+    @SuppressWarnings("unused")
+    long writev(FileDescriptor fd, long address, int len) throws IOException {
+         throw new IOException("Operation Unsupported");
+    }
+
+    @Override
+    void close(FileDescriptor fd) throws IOException {
+        FileDispatcherImpl.close0(fd);
+    }
+
+    @Override
+    void preClose(FileDescriptor fd) throws IOException {
+        FileDispatcherImpl.preClose0(fd);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/native/sun/nio/ch/Sctp.h	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,329 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#ifndef SUN_NIO_CH_SCTP_H
+#define SUN_NIO_CH_SCTP_H
+
+#ifdef __solaris__
+
+#define _XPG4_2
+#define __EXTENSIONS__
+#include <sys/socket.h>
+#include <netinet/sctp.h>
+#include "jni.h"
+
+/* Current Solaris headers don't comply with draft rfc */
+#ifndef SCTP_EOF
+#define SCTP_EOF MSG_EOF
+#endif
+
+#ifndef SCTP_UNORDERED
+#define SCTP_UNORDERED MSG_UNORDERED
+#endif
+
+/* The current version of the socket API extension shipped with Solaris does
+ * not define the following options that the Java API (optionally) supports */
+#ifndef SCTP_EXPLICIT_EOR
+#define SCTP_EXPLICIT_EOR -1
+#endif
+#ifndef SCTP_FRAGMENT_INTERLEAVE
+#define SCTP_FRAGMENT_INTERLEAVE -1
+#endif
+#ifndef SCTP_SET_PEER_PRIMARY_ADDR
+#define SCTP_SET_PEER_PRIMARY_ADDR -1
+#endif
+
+/* Function types to support dynamic linking of socket API extension functions
+ * for SCTP. This is so that there is no linkage depandancy during build or
+ * runtime for libsctp.*/
+typedef int sctp_getladdrs_func(int sock, sctp_assoc_t id, void **addrs);
+typedef int sctp_freeladdrs_func(void* addrs);
+typedef int sctp_getpaddrs_func(int sock, sctp_assoc_t id, void **addrs);
+typedef int sctp_freepaddrs_func(void *addrs);
+typedef int sctp_bindx_func(int sock, void *addrs, int addrcnt, int flags);
+
+
+#else /* __linux__ */
+#include <stdint.h>
+#include <linux/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include "jni.h"
+
+//Causes compiler error if not found, should make warning and uncomment
+/*#include <netinet/sctp.h>*/
+
+#ifndef IPPROTO_SCTP
+#define IPPROTO_SCTP    132
+#endif
+
+/* The current version of lksctp does
+ * not define the following option that the Java API (optionally) supports */
+#ifndef SCTP_EXPLICIT_EOR
+#define SCTP_EXPLICIT_EOR -1
+#endif
+
+/* Definitions taken from lksctp-tools-1.0.8/src/include/netinet/sctp.h */
+#ifndef SCTP_INITMSG
+
+enum sctp_optname {
+        SCTP_RTOINFO,
+#define SCTP_RTOINFO SCTP_RTOINFO
+        SCTP_ASSOCINFO,
+#define SCTP_ASSOCINFO SCTP_ASSOCINFO
+        SCTP_INITMSG,
+#define SCTP_INITMSG SCTP_INITMSG
+        SCTP_NODELAY,   /* Get/set nodelay option. */
+#define SCTP_NODELAY    SCTP_NODELAY
+        SCTP_AUTOCLOSE,
+#define SCTP_AUTOCLOSE SCTP_AUTOCLOSE
+        SCTP_SET_PEER_PRIMARY_ADDR,
+#define SCTP_SET_PEER_PRIMARY_ADDR SCTP_SET_PEER_PRIMARY_ADDR
+        SCTP_PRIMARY_ADDR,
+#define SCTP_PRIMARY_ADDR SCTP_PRIMARY_ADDR
+        SCTP_ADAPTATION_LAYER,
+#define SCTP_ADAPTATION_LAYER SCTP_ADAPTATION_LAYER
+        SCTP_DISABLE_FRAGMENTS,
+#define SCTP_DISABLE_FRAGMENTS SCTP_DISABLE_FRAGMENTS
+        SCTP_PEER_ADDR_PARAMS,
+#define SCTP_PEER_ADDR_PARAMS SCTP_PEER_ADDR_PARAMS
+        SCTP_DEFAULT_SEND_PARAM,
+#define SCTP_DEFAULT_SEND_PARAM SCTP_DEFAULT_SEND_PARAM
+        SCTP_EVENTS,
+#define SCTP_EVENTS SCTP_EVENTS
+        SCTP_I_WANT_MAPPED_V4_ADDR,  /* Turn on/off mapped v4 addresses  */
+#define SCTP_I_WANT_MAPPED_V4_ADDR SCTP_I_WANT_MAPPED_V4_ADDR
+        SCTP_MAXSEG,    /* Get/set maximum fragment. */
+#define SCTP_MAXSEG     SCTP_MAXSEG
+        SCTP_STATUS,
+#define SCTP_STATUS SCTP_STATUS
+        SCTP_GET_PEER_ADDR_INFO,
+#define SCTP_GET_PEER_ADDR_INFO SCTP_GET_PEER_ADDR_INFO
+        SCTP_DELAYED_ACK_TIME,
+#define SCTP_DELAYED_ACK_TIME SCTP_DELAYED_ACK_TIME
+        SCTP_CONTEXT,   /* Receive Context */
+#define SCTP_CONTEXT SCTP_CONTEXT
+        SCTP_FRAGMENT_INTERLEAVE,
+#define SCTP_FRAGMENT_INTERLEAVE SCTP_FRAGMENT_INTERLEAVE
+        SCTP_PARTIAL_DELIVERY_POINT,    /* Set/Get partial delivery point */
+#define SCTP_PARTIAL_DELIVERY_POINT SCTP_PARTIAL_DELIVERY_POINT
+        SCTP_MAX_BURST,         /* Set/Get max burst */
+#define SCTP_MAX_BURST SCTP_MAX_BURST
+};
+
+enum sctp_sac_state {
+        SCTP_COMM_UP,
+        SCTP_COMM_LOST,
+        SCTP_RESTART,
+        SCTP_SHUTDOWN_COMP,
+        SCTP_CANT_STR_ASSOC,
+};
+
+enum sctp_spc_state {
+        SCTP_ADDR_AVAILABLE,
+        SCTP_ADDR_UNREACHABLE,
+        SCTP_ADDR_REMOVED,
+        SCTP_ADDR_ADDED,
+        SCTP_ADDR_MADE_PRIM,
+        SCTP_ADDR_CONFIRMED,
+};
+
+enum sctp_sinfo_flags {
+        SCTP_UNORDERED = 1,  /* Send/receive message unordered. */
+        SCTP_ADDR_OVER = 2,  /* Override the primary destination. */
+        SCTP_ABORT=4,        /* Send an ABORT message to the peer. */
+        SCTP_EOF=MSG_FIN,    /* Initiate graceful shutdown process. */
+};
+
+enum sctp_sn_type {
+        SCTP_SN_TYPE_BASE     = (1<<15),
+        SCTP_ASSOC_CHANGE,
+        SCTP_PEER_ADDR_CHANGE,
+        SCTP_SEND_FAILED,
+        SCTP_REMOTE_ERROR,
+        SCTP_SHUTDOWN_EVENT,
+        SCTP_PARTIAL_DELIVERY_EVENT,
+        SCTP_ADAPTATION_INDICATION,
+};
+
+typedef enum sctp_cmsg_type {
+        SCTP_INIT,              /* 5.2.1 SCTP Initiation Structure */
+#define SCTP_INIT SCTP_INIT
+        SCTP_SNDRCV,            /* 5.2.2 SCTP Header Information Structure */
+#define SCTP_SNDRCV SCTP_SNDRCV
+} sctp_cmsg_t;
+
+enum sctp_msg_flags {
+        MSG_NOTIFICATION = 0x8000,
+#define MSG_NOTIFICATION MSG_NOTIFICATION
+};
+
+#define SCTP_BINDX_ADD_ADDR 0x01
+#define SCTP_BINDX_REM_ADDR 0x02
+
+typedef __s32 sctp_assoc_t;
+
+struct sctp_initmsg {
+        __u16 sinit_num_ostreams;
+        __u16 sinit_max_instreams;
+        __u16 sinit_max_attempts;
+        __u16 sinit_max_init_timeo;
+};
+
+struct sctp_sndrcvinfo {
+        __u16 sinfo_stream;
+        __u16 sinfo_ssn;
+        __u16 sinfo_flags;
+        __u32 sinfo_ppid;
+        __u32 sinfo_context;
+        __u32 sinfo_timetolive;
+        __u32 sinfo_tsn;
+        __u32 sinfo_cumtsn;
+        sctp_assoc_t sinfo_assoc_id;
+};
+
+struct sctp_event_subscribe {
+        __u8 sctp_data_io_event;
+        __u8 sctp_association_event;
+        __u8 sctp_address_event;
+        __u8 sctp_send_failure_event;
+        __u8 sctp_peer_error_event;
+        __u8 sctp_shutdown_event;
+        __u8 sctp_partial_delivery_event;
+        __u8 sctp_adaptation_layer_event;
+};
+
+struct sctp_send_failed {
+        __u16 ssf_type;
+        __u16 ssf_flags;
+        __u32 ssf_length;
+        __u32 ssf_error;
+        struct sctp_sndrcvinfo ssf_info;
+        sctp_assoc_t ssf_assoc_id;
+        __u8 ssf_data[0];
+};
+
+struct sctp_assoc_change {
+        __u16 sac_type;
+        __u16 sac_flags;
+        __u32 sac_length;
+        __u16 sac_state;
+        __u16 sac_error;
+        __u16 sac_outbound_streams;
+        __u16 sac_inbound_streams;
+        sctp_assoc_t sac_assoc_id;
+        __u8 sac_info[0];
+};
+
+struct sctp_shutdown_event {
+        __u16 sse_type;
+        __u16 sse_flags;
+        __u32 sse_length;
+        sctp_assoc_t sse_assoc_id;
+};
+
+struct sctp_paddr_change {
+        __u16 spc_type;
+        __u16 spc_flags;
+        __u32 spc_length;
+        struct sockaddr_storage spc_aaddr;
+        int spc_state;
+        int spc_error;
+        sctp_assoc_t spc_assoc_id;
+} __attribute__((packed, aligned(4)));
+
+struct sctp_remote_error {
+        __u16 sre_type;
+        __u16 sre_flags;
+        __u32 sre_length;
+        __u16 sre_error;
+        sctp_assoc_t sre_assoc_id;
+        __u8 sre_data[0];
+};
+
+struct sctp_adaptation_event {
+        __u16 sai_type;
+        __u16 sai_flags;
+        __u32 sai_length;
+        __u32 sai_adaptation_ind;
+        sctp_assoc_t sai_assoc_id;
+};
+
+struct sctp_setprim {
+        sctp_assoc_t            ssp_assoc_id;
+        struct sockaddr_storage ssp_addr;
+} __attribute__((packed, aligned(4)));
+
+struct sctp_setpeerprim {
+        sctp_assoc_t            sspp_assoc_id;
+        struct sockaddr_storage sspp_addr;
+} __attribute__((packed, aligned(4)));
+
+
+struct sctp_pdapi_event {
+        __u16 pdapi_type;
+        __u16 pdapi_flags;
+        __u32 pdapi_length;
+        __u32 pdapi_indication;
+        sctp_assoc_t pdapi_assoc_id;
+};
+
+union sctp_notification {
+        struct {
+                __u16 sn_type;             /* Notification type. */
+                __u16 sn_flags;
+                __u32 sn_length;
+        } sn_header;
+        struct sctp_assoc_change sn_assoc_change;
+        struct sctp_paddr_change sn_paddr_change;
+        struct sctp_remote_error sn_remote_error;
+        struct sctp_send_failed sn_send_failed;
+        struct sctp_shutdown_event sn_shutdown_event;
+        struct sctp_adaptation_event sn_adaptation_event;
+        struct sctp_pdapi_event sn_pdapi_event;
+};
+
+#endif /* SCTP_INITMSG */
+
+/* Function types to support dynamic linking of socket API extension functions
+ * for SCTP. This is so that there is no linkage depandancy during build or
+ * runtime for libsctp.*/
+typedef int sctp_getladdrs_func(int sd, sctp_assoc_t id, struct sockaddr **addrs);
+typedef int sctp_freeladdrs_func(struct sockaddr *addrs);
+typedef int sctp_getpaddrs_func(int sd, sctp_assoc_t id, struct sockaddr **addrs);
+typedef int sctp_freepaddrs_func(struct sockaddr *addrs);
+typedef int sctp_bindx_func(int sd, struct sockaddr *addrs, int addrcnt, int flags);
+
+#endif /* __linux__ */
+
+sctp_getladdrs_func* nio_sctp_getladdrs;
+sctp_freeladdrs_func* nio_sctp_freeladdrs;
+sctp_getpaddrs_func* nio_sctp_getpaddrs;
+sctp_freepaddrs_func* nio_sctp_freepaddrs;
+sctp_bindx_func* nio_sctp_bindx;
+
+jboolean loadSocketExtensionFuncs(JNIEnv* env);
+
+#endif /* !SUN_NIO_CH_SCTP_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/native/sun/nio/ch/SctpChannelImpl.c	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,594 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "Sctp.h"
+
+#include "jni.h"
+#include "nio_util.h"
+#include "nio.h"
+#include "net_util.h"
+#include "net_util_md.h"
+#include "sun_nio_ch_SctpNet.h"
+#include "sun_nio_ch_SctpChannelImpl.h"
+#include "sun_nio_ch_SctpAssocChange.h"
+#include "sun_nio_ch_SctpResultContainer.h"
+#include "sun_nio_ch_SctpPeerAddrChange.h"
+
+/* sizeof(union sctp_notification */
+#define NOTIFICATION_BUFFER_SIZE 280
+
+#define MESSAGE_IMPL_CLASS              "sun/nio/ch/SctpMessageInfoImpl"
+#define RESULT_CONTAINER_CLASS          "sun/nio/ch/SctpResultContainer"
+#define SEND_FAILED_CLASS               "sun/nio/ch/SctpSendFailed"
+#define ASSOC_CHANGE_CLASS              "sun/nio/ch/SctpAssocChange"
+#define PEER_CHANGE_CLASS               "sun/nio/ch/SctpPeerAddrChange"
+#define SHUTDOWN_CLASS                  "sun/nio/ch/SctpShutdown"
+
+struct controlData {
+    int assocId;
+    unsigned short streamNumber;
+    jboolean unordered;
+    unsigned int ppid;
+};
+
+static jclass    smi_class;    /* sun.nio.ch.SctpMessageInfoImpl            */
+static jmethodID smi_ctrID;    /* sun.nio.ch.SctpMessageInfoImpl.<init>     */
+static jfieldID  src_valueID;  /* sun.nio.ch.SctpResultContainer.value      */
+static jfieldID  src_typeID;   /* sun.nio.ch.SctpResultContainer.type       */
+static jclass    ssf_class;    /* sun.nio.ch.SctpSendFailed                 */
+static jmethodID ssf_ctrID;    /* sun.nio.ch.SctpSendFailed.<init>          */
+static jclass    sac_class;    /* sun.nio.ch.SctpAssociationChanged         */
+static jmethodID sac_ctrID;    /* sun.nio.ch.SctpAssociationChanged.<init>  */
+static jclass    spc_class;    /* sun.nio.ch.SctpPeerAddressChanged         */
+static jmethodID spc_ctrID;    /* sun.nio.ch.SctpPeerAddressChanged.<init>  */
+static jclass    ss_class;     /* sun.nio.ch.SctpShutdown                   */
+static jmethodID ss_ctrID;     /* sun.nio.ch.SctpShutdown.<init>            */
+static jfieldID  isa_addrID;   /* java.net.InetSocketAddress.addr           */
+static jfieldID  isa_portID;   /* java.net.InetSocketAddress.port           */
+
+/* defined in SctpNet.c */
+jobject SockAddrToInetSocketAddress(JNIEnv* env, struct sockaddr* addr);
+
+/* use SocketChannelImpl's checkConnect implementation */
+extern jint Java_sun_nio_ch_SocketChannelImpl_checkConnect(JNIEnv* env,
+    jobject this, jobject fdo, jboolean block, jboolean ready);
+
+/*
+ * Class:     sun_nio_ch_SctpChannelImpl
+ * Method:    initIDs
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_sun_nio_ch_SctpChannelImpl_initIDs
+  (JNIEnv *env, jclass klass) {
+    jclass cls;
+
+    /* SctpMessageInfoImpl */
+    cls = (*env)->FindClass(env, MESSAGE_IMPL_CLASS);
+    CHECK_NULL(cls);
+    smi_class = (*env)->NewGlobalRef(env, cls);
+    CHECK_NULL(smi_class);
+    smi_ctrID = (*env)->GetMethodID(env, cls, "<init>",
+            "(ILjava/net/SocketAddress;IIZZI)V");
+    CHECK_NULL(smi_ctrID);
+
+    /* SctpResultContainer */
+    cls = (*env)->FindClass(env, RESULT_CONTAINER_CLASS);
+    CHECK_NULL(cls);
+    src_valueID = (*env)->GetFieldID(env, cls, "value", "Ljava/lang/Object;");
+    CHECK_NULL(src_valueID);
+    src_typeID = (*env)->GetFieldID(env, cls, "type", "I");
+    CHECK_NULL(src_typeID);
+
+    /* SctpSendFailed */
+    cls = (*env)->FindClass(env, SEND_FAILED_CLASS);
+    CHECK_NULL(cls);
+    ssf_class = (*env)->NewGlobalRef(env, cls);
+    CHECK_NULL(ssf_class);
+    ssf_ctrID = (*env)->GetMethodID(env, cls, "<init>",
+        "(ILjava/net/SocketAddress;Ljava/nio/ByteBuffer;II)V");
+    CHECK_NULL(ssf_ctrID);
+
+    /* SctpAssocChange */
+    cls = (*env)->FindClass(env, ASSOC_CHANGE_CLASS);
+    CHECK_NULL(cls);
+    sac_class = (*env)->NewGlobalRef(env, cls);
+    CHECK_NULL(sac_class);
+    sac_ctrID = (*env)->GetMethodID(env, cls, "<init>", "(IIII)V");
+    CHECK_NULL(sac_ctrID);
+
+    /* SctpPeerAddrChange */
+    cls = (*env)->FindClass(env, PEER_CHANGE_CLASS);
+    CHECK_NULL(cls);
+    spc_class = (*env)->NewGlobalRef(env, cls);
+    CHECK_NULL(spc_class);
+    spc_ctrID = (*env)->GetMethodID(env, cls, "<init>",
+            "(ILjava/net/SocketAddress;I)V");
+    CHECK_NULL(spc_ctrID);
+
+    /* sun.nio.ch.SctpShutdown */
+    cls = (*env)->FindClass(env, SHUTDOWN_CLASS);
+    CHECK_NULL(cls);
+    ss_class = (*env)->NewGlobalRef(env, cls);
+    CHECK_NULL(ss_class);
+    ss_ctrID = (*env)->GetMethodID(env, cls, "<init>", "(I)V");
+    CHECK_NULL(ss_ctrID);
+
+    /* InetSocketAddress */
+    cls = (*env)->FindClass(env, "java/net/InetSocketAddress");
+    CHECK_NULL(cls);
+    isa_addrID = (*env)->GetFieldID(env, cls, "addr", "Ljava/net/InetAddress;");
+    CHECK_NULL(isa_addrID);
+    isa_portID = (*env)->GetFieldID(env, cls, "port", "I");
+}
+
+void getControlData
+  (struct msghdr* msg, struct controlData* cdata) {
+    struct cmsghdr* cmsg;
+
+    for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+        if (cmsg->cmsg_level == IPPROTO_SCTP && cmsg->cmsg_type == SCTP_SNDRCV) {
+            struct sctp_sndrcvinfo *sri;
+
+            sri = (struct sctp_sndrcvinfo *) CMSG_DATA(cmsg);
+            cdata->assocId = sri->sinfo_assoc_id;
+            cdata->streamNumber = sri->sinfo_stream;
+            cdata->unordered = (sri->sinfo_flags & SCTP_UNORDERED) ? JNI_TRUE :
+                JNI_FALSE;
+            cdata->ppid = ntohl(sri->sinfo_ppid);
+
+            return;
+        }
+    }
+    return;
+}
+
+void setControlData
+  (struct msghdr* msg, struct controlData* cdata) {
+    struct cmsghdr* cmsg;
+    struct sctp_sndrcvinfo *sri;
+
+    cmsg = CMSG_FIRSTHDR(msg);
+    cmsg->cmsg_level = IPPROTO_SCTP;
+    cmsg->cmsg_type = SCTP_SNDRCV;
+    cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+
+    /* Initialize the payload */
+    sri = (struct sctp_sndrcvinfo*) CMSG_DATA(cmsg);
+    memset(sri, 0, sizeof (*sri));
+
+    if (cdata->streamNumber > 0) {
+        sri->sinfo_stream = cdata->streamNumber;
+    }
+    if (cdata->assocId > 0) {
+        sri->sinfo_assoc_id = cdata->assocId;
+    }
+    if (cdata->unordered == JNI_TRUE) {
+        sri->sinfo_flags = sri->sinfo_flags | SCTP_UNORDERED;
+    }
+
+    if (cdata->ppid > 0) {
+        sri->sinfo_ppid = htonl(cdata->ppid);
+    }
+
+    /* Sum of the length of all control messages in the buffer. */
+    msg->msg_controllen = cmsg->cmsg_len;
+}
+
+// TODO: test: can create send failed without any data? if so need to
+// update API so that buffer can be null if no data.
+void handleSendFailed
+  (JNIEnv* env, int fd, jobject resultContainerObj, struct sctp_send_failed *ssf,
+   int read, jboolean isEOR, struct sockaddr* sap) {
+    jobject bufferObj = NULL, resultObj, isaObj;
+    char *addressP;
+    struct sctp_sndrcvinfo *sri;
+    int remaining, dataLength;
+
+    /* the actual undelivered message data is directly after the ssf */
+    int dataOffset = sizeof(struct sctp_send_failed);
+
+    sri = (struct sctp_sndrcvinfo*) &ssf->ssf_info;
+
+    /* the number of bytes remaining to be read in the sctp_send_failed notif*/
+    remaining = ssf->ssf_length - read;
+
+    /* the size of the actual undelivered message */
+    dataLength = ssf->ssf_length - dataOffset;
+
+    /* retrieved address from sockaddr */
+    isaObj = SockAddrToInetSocketAddress(env, sap);
+
+    /* data retrieved from sff_data */
+    if (dataLength > 0) {
+        struct iovec iov[1];
+        struct msghdr msg[1];
+        int rv, alreadyRead;
+        char *dataP = (char*) ssf;
+        dataP += dataOffset;
+
+        if ((addressP = malloc(dataLength)) == NULL) {
+            JNU_ThrowOutOfMemoryError(env, "handleSendFailed");
+            return;
+        }
+
+        memset(msg, 0, sizeof (*msg));
+        msg->msg_iov = iov;
+        msg->msg_iovlen = 1;
+
+        bufferObj = (*env)->NewDirectByteBuffer(env, addressP, dataLength);
+        CHECK_NULL(bufferObj);
+
+        alreadyRead = read - dataOffset;
+        if (alreadyRead > 0) {
+            memcpy(addressP, /*ssf->ssf_data*/ dataP, alreadyRead);
+            iov->iov_base = addressP + alreadyRead;
+            iov->iov_len = dataLength - alreadyRead;
+        } else {
+            iov->iov_base = addressP;
+            iov->iov_len = dataLength;
+        }
+
+        if (remaining > 0) {
+            if ((rv = recvmsg(fd, msg, 0)) < 0) {
+                fprintf(stdout, "\nNative: handleSFN: recvmsg failed: errno = %d  ", errno);
+                handleSocketError(env, errno);
+                return;
+            }
+
+            if (rv != (dataLength - alreadyRead) || !(msg->msg_flags & MSG_EOR)) {
+                //TODO: assert false: "should not reach here";
+                return;
+            }
+            // TODO: Set and document (in API) buffers position.
+        }
+    }
+
+    /* create SctpSendFailed */
+    resultObj = (*env)->NewObject(env, ssf_class, ssf_ctrID, ssf->ssf_assoc_id,
+            sri->sinfo_stream, ssf->ssf_error, isaObj, bufferObj);
+    CHECK_NULL(resultObj);
+    (*env)->SetObjectField(env, resultContainerObj, src_valueID, resultObj);
+    (*env)->SetIntField(env, resultContainerObj, src_typeID,
+            sun_nio_ch_SctpResultContainer_SEND_FAILED);
+}
+
+void handleAssocChange
+  (JNIEnv* env, jobject resultContainerObj, struct sctp_assoc_change *sac) {
+    jobject resultObj;
+    int state = 0;
+
+    switch (sac->sac_state) {
+        case SCTP_COMM_UP :
+            state = sun_nio_ch_SctpAssocChange_SCTP_COMM_UP;
+            break;
+        case SCTP_COMM_LOST :
+            state = sun_nio_ch_SctpAssocChange_SCTP_COMM_LOST;
+            break;
+        case SCTP_RESTART :
+            state = sun_nio_ch_SctpAssocChange_SCTP_RESTART;
+            break;
+        case SCTP_SHUTDOWN_COMP :
+            state = sun_nio_ch_SctpAssocChange_SCTP_SHUTDOWN;
+            break;
+        case SCTP_CANT_STR_ASSOC :
+            state = sun_nio_ch_SctpAssocChange_SCTP_CANT_START;
+    }
+
+    /* create SctpAssociationChanged */
+    resultObj = (*env)->NewObject(env, sac_class, sac_ctrID, sac->sac_assoc_id,
+        state, sac->sac_outbound_streams, sac->sac_inbound_streams);
+    CHECK_NULL(resultObj);
+    (*env)->SetObjectField(env, resultContainerObj, src_valueID, resultObj);
+    (*env)->SetIntField(env, resultContainerObj, src_typeID,
+            sun_nio_ch_SctpResultContainer_ASSOCIATION_CHANGED);
+}
+
+void handleShutdown
+  (JNIEnv* env, jobject resultContainerObj, struct sctp_shutdown_event* sse) {
+    /* create SctpShutdown */
+    jobject resultObj = (*env)->NewObject(env, ss_class, ss_ctrID, sse->sse_assoc_id);
+    CHECK_NULL(resultObj);
+    (*env)->SetObjectField(env, resultContainerObj, src_valueID, resultObj);
+    (*env)->SetIntField(env, resultContainerObj, src_typeID,
+            sun_nio_ch_SctpResultContainer_SHUTDOWN);
+}
+
+void handlePeerAddrChange
+  (JNIEnv* env, jobject resultContainerObj, struct sctp_paddr_change* spc) {
+    int event = 0;
+    jobject addressObj, resultObj;
+    unsigned int state = spc->spc_state;
+
+    switch (state) {
+        case SCTP_ADDR_AVAILABLE :
+            event = sun_nio_ch_SctpPeerAddrChange_SCTP_ADDR_AVAILABLE;
+            break;
+        case SCTP_ADDR_UNREACHABLE :
+            event = sun_nio_ch_SctpPeerAddrChange_SCTP_ADDR_UNREACHABLE;
+            break;
+        case SCTP_ADDR_REMOVED :
+            event = sun_nio_ch_SctpPeerAddrChange_SCTP_ADDR_REMOVED;
+            break;
+        case SCTP_ADDR_ADDED :
+            event = sun_nio_ch_SctpPeerAddrChange_SCTP_ADDR_ADDED;
+            break;
+        case SCTP_ADDR_MADE_PRIM :
+            event = sun_nio_ch_SctpPeerAddrChange_SCTP_ADDR_MADE_PRIM;
+#ifdef __linux__  /* Solaris currently doesn't support SCTP_ADDR_CONFIRMED */
+            break;
+        case SCTP_ADDR_CONFIRMED :
+            event = sun_nio_ch_SctpPeerAddrChange_SCTP_ADDR_CONFIRMED;
+#endif  /* __linux__ */
+    }
+
+    addressObj = SockAddrToInetSocketAddress(env, (struct sockaddr*)&spc->spc_aaddr);
+
+    /* create SctpPeerAddressChanged */
+    resultObj = (*env)->NewObject(env, spc_class, spc_ctrID, spc->spc_assoc_id,
+            addressObj, event);
+    CHECK_NULL(resultObj);
+    (*env)->SetObjectField(env, resultContainerObj, src_valueID, resultObj);
+    (*env)->SetIntField(env, resultContainerObj, src_typeID,
+            sun_nio_ch_SctpResultContainer_PEER_ADDRESS_CHANGED);
+}
+
+void handleUninteresting
+  (union sctp_notification *snp) {
+    //fprintf(stdout,"\nNative: handleUninterestingNotification: Receive notification type [%u]", snp->sn_header.sn_type);
+}
+
+/**
+ * Handle notifications from the SCTP stack.
+ * Returns JNI_TRUE if the notification is one that is of interest to the
+ * Java API, otherwise JNI_FALSE.
+ */
+jboolean handleNotification
+  (JNIEnv* env, int fd, jobject resultContainerObj, union sctp_notification* snp,
+   int read, jboolean isEOR, struct sockaddr* sap) {
+    switch (snp->sn_header.sn_type) {
+        case SCTP_SEND_FAILED:
+            handleSendFailed(env, fd, resultContainerObj, &snp->sn_send_failed,
+                    read, isEOR, sap);
+            return JNI_TRUE;
+        case SCTP_ASSOC_CHANGE:
+            handleAssocChange(env, resultContainerObj, &snp->sn_assoc_change);
+            return JNI_TRUE;
+        case SCTP_SHUTDOWN_EVENT:
+            handleShutdown(env, resultContainerObj, &snp->sn_shutdown_event);
+            return JNI_TRUE;
+        case SCTP_PEER_ADDR_CHANGE:
+            handlePeerAddrChange(env, resultContainerObj, &snp->sn_paddr_change);
+            return JNI_TRUE;
+        default :
+            /* the Java API is not interested in this event, maybe we are? */
+            handleUninteresting(snp);
+    }
+    return JNI_FALSE;
+}
+
+void handleMessage
+  (JNIEnv* env, jobject resultContainerObj, struct msghdr* msg,int read,
+   jboolean isEOR, struct sockaddr* sap) {
+    jobject isa, resultObj;
+    struct controlData cdata[1];
+
+    if (read == 0) {
+        /* we reached EOF */
+        read = -1;
+    }
+
+    isa = SockAddrToInetSocketAddress(env, sap);
+    getControlData(msg, cdata);
+
+    /* create SctpMessageInfoImpl */
+    resultObj = (*env)->NewObject(env, smi_class, smi_ctrID, cdata->assocId,
+                                  isa, read, cdata->streamNumber,
+                                  isEOR ? JNI_TRUE : JNI_FALSE,
+                                  cdata->unordered, cdata->ppid);
+    CHECK_NULL(resultObj);
+    (*env)->SetObjectField(env, resultContainerObj, src_valueID, resultObj);
+    (*env)->SetIntField(env, resultContainerObj, src_typeID,
+                        sun_nio_ch_SctpResultContainer_MESSAGE);
+}
+
+/*
+ * Class:     sun_nio_ch_SctpChannelImpl
+ * Method:    receive0
+ * Signature: (ILsun/nio/ch/SctpResultContainer;JI)I
+ */
+JNIEXPORT jint JNICALL Java_sun_nio_ch_SctpChannelImpl_receive0
+  (JNIEnv *env, jclass klass, jint fd, jobject resultContainerObj,
+   jlong address, jint length) {
+    SOCKADDR sa;
+    int sa_len = sizeof(sa);
+    ssize_t rv = 0;
+    jlong *addr = jlong_to_ptr(address);
+    struct iovec iov[1];
+    struct msghdr msg[1];
+    char cbuf[CMSG_SPACE(sizeof (struct sctp_sndrcvinfo))];
+
+    /* Set up the msghdr structure for receiving */
+    memset(msg, 0, sizeof (*msg));
+    msg->msg_name = &sa;
+    msg->msg_namelen = sa_len;
+    iov->iov_base = addr;
+    iov->iov_len = length;
+    msg->msg_iov = iov;
+    msg->msg_iovlen = 1;
+    msg->msg_control = cbuf;
+    msg->msg_controllen = sizeof(cbuf);
+    msg->msg_flags = 0;
+
+    do {
+        if ((rv = recvmsg(fd, msg, 0)) < 0) {
+            if (errno == EWOULDBLOCK) {
+                return IOS_UNAVAILABLE;
+            } else if (errno == EINTR) {
+                return IOS_INTERRUPTED;
+
+#ifdef __linux__
+            } else if (errno == ENOTCONN) {
+                /* ENOTCONN when EOF reached */
+                rv = 0;
+                /* there will be no control data */
+                msg->msg_controllen = 0;
+#endif /* __linux__ */
+
+            } else {
+                handleSocketError(env, errno);
+                return 0;
+            }
+        }
+
+        if (msg->msg_flags & MSG_NOTIFICATION) {
+            char *bufp = (char*)addr;
+            union sctp_notification *snp;
+
+            if (!(msg->msg_flags & MSG_EOR) && length < NOTIFICATION_BUFFER_SIZE) {
+                char buf[NOTIFICATION_BUFFER_SIZE];
+                int rvSAVE = rv;
+                memcpy(buf, addr, rv);
+                iov->iov_base = buf + rv;
+                iov->iov_len = NOTIFICATION_BUFFER_SIZE - rv;
+                if ((rv = recvmsg(fd, msg, 0)) < 0) {
+                    handleSocketError(env, errno);
+                    return 0;
+                }
+                bufp = buf;
+                rv += rvSAVE;
+            }
+            snp = (union sctp_notification *) bufp;
+            if (handleNotification(env, fd, resultContainerObj, snp, rv,
+                                   (msg->msg_flags & MSG_EOR),
+                                   (struct sockaddr*)&sa ) == JNI_TRUE) {
+                /* We have received a notification that is of interest to
+                   to the Java API. The appropriate notification will be
+                   set in the result container. */
+                return 0;
+            }
+
+            // set iov back to addr, and reset msg_controllen
+            iov->iov_base = addr;
+            iov->iov_len = length;
+            msg->msg_control = cbuf;
+            msg->msg_controllen = sizeof(cbuf);
+        }
+    } while (msg->msg_flags & MSG_NOTIFICATION);
+
+    handleMessage(env, resultContainerObj, msg, rv,
+            (msg->msg_flags & MSG_EOR), (struct sockaddr*)&sa);
+    return rv;
+}
+
+/*
+ * Class:     sun_nio_ch_SctpChannelImpl
+ * Method:    send0
+ * Signature: (IJILjava/net/SocketAddress;IIZI)I
+ */
+JNIEXPORT jint JNICALL Java_sun_nio_ch_SctpChannelImpl_send0
+  (JNIEnv *env, jclass klass, jint fd, jlong address, jint length,
+   jobject saTarget, jint assocId, jint streamNumber, jboolean unordered,
+   jint ppid) {
+    SOCKADDR sa;
+    int sa_len = sizeof(sa);
+    ssize_t rv = 0;
+    jlong *addr = jlong_to_ptr(address);
+    struct iovec iov[1];
+    struct msghdr msg[1];
+    int cbuf_size = CMSG_SPACE(sizeof (struct sctp_sndrcvinfo));
+    char cbuf[CMSG_SPACE(sizeof (struct sctp_sndrcvinfo))];
+    struct controlData cdata[1];
+
+    /* SctpChannel:
+     *    saTarget may contain the preferred address or NULL to use primary,
+     *    assocId will always be -1
+     * SctpMultiChannell:
+     *    Setup new association, saTarget will contain address, assocId = -1
+     *    Association already existing, assocId != -1, saTarget = preferred addr
+     */
+    if (saTarget != NULL /*&& assocId <= 0*/) {
+
+        jobject targetAddress = (*env)->GetObjectField(env, saTarget, isa_addrID);
+        jint targetPort = (*env)->GetIntField(env, saTarget, isa_portID);
+
+        if (NET_InetAddressToSockaddr(env, targetAddress, targetPort,
+                                      (struct sockaddr *)&sa,
+                                      &sa_len, JNI_TRUE) != 0) {
+            return IOS_THROWN;
+        }
+    } else {
+        memset(&sa, '\x0', sa_len);
+        sa_len = 0;
+    }
+
+    /* Set up the msghdr structure for sending */
+    memset(msg, 0, sizeof (*msg));
+    memset(cbuf, 0, cbuf_size);
+    msg->msg_name = &sa;
+    msg->msg_namelen = sa_len;
+    iov->iov_base = addr;
+    iov->iov_len = length;
+    msg->msg_iov = iov;
+    msg->msg_iovlen = 1;
+    msg->msg_control = cbuf;
+    msg->msg_controllen = cbuf_size;
+    msg->msg_flags = 0;
+
+    cdata->streamNumber = streamNumber;
+    cdata->assocId = assocId;
+    cdata->unordered = unordered;
+    cdata->ppid = ppid;
+    setControlData(msg, cdata);
+
+    if ((rv = sendmsg(fd, msg, 0)) < 0) {
+        if (errno == EWOULDBLOCK) {
+            return IOS_UNAVAILABLE;
+        } else if (errno == EINTR) {
+            return IOS_INTERRUPTED;
+        } else if (errno == EPIPE) {
+            JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+                            "Socket is shutdown for writing");
+        } else {
+            handleSocketError(env, errno);
+            return 0;
+        }
+    }
+
+    return rv;
+}
+
+/*
+ * Class:     sun_nio_ch_SctpChannelImpl
+ * Method:    checkConnect
+ * Signature: (Ljava/io/FileDescriptor;ZZ)I
+ */
+JNIEXPORT jint JNICALL Java_sun_nio_ch_SctpChannelImpl_checkConnect
+  (JNIEnv* env, jobject this, jobject fdo, jboolean block, jboolean ready) {
+    return Java_sun_nio_ch_SocketChannelImpl_checkConnect(env, this,
+                                                          fdo, block, ready);
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/native/sun/nio/ch/SctpNet.c	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,609 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <dlfcn.h>
+
+#include "Sctp.h"
+#include "jni.h"
+#include "jni_util.h"
+#include "nio_util.h"
+#include "nio.h"
+#include "net_util.h"
+#include "net_util_md.h"
+#include "sun_nio_ch_SctpNet.h"
+#include "sun_nio_ch_SctpStdSocketOption.h"
+
+static jclass isaCls = 0;
+static jmethodID isaCtrID = 0;
+
+static const char* nativeSctpLib = "libsctp.so.1";
+static jboolean funcsLoaded = JNI_FALSE;
+
+JNIEXPORT jint JNICALL JNI_OnLoad
+  (JavaVM *vm, void *reserved) {
+    return JNI_VERSION_1_2;
+}
+
+/**
+ * Loads the native sctp library that contains the socket extension
+ * functions, as well as locating the individual functions.
+ * There will be a pending exception if this method returns false.
+ */
+jboolean loadSocketExtensionFuncs
+  (JNIEnv* env) {
+    if (dlopen(nativeSctpLib, RTLD_GLOBAL | RTLD_LAZY) == NULL) {
+        JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+              dlerror());
+        return JNI_FALSE;
+    }
+
+    if ((nio_sctp_getladdrs = (sctp_getladdrs_func*)
+            dlsym(RTLD_DEFAULT, "sctp_getladdrs")) == NULL) {
+        JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+              dlerror());
+        return JNI_FALSE;
+    }
+
+    if ((nio_sctp_freeladdrs = (sctp_freeladdrs_func*)
+            dlsym(RTLD_DEFAULT, "sctp_freeladdrs")) == NULL) {
+        JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+              dlerror());
+        return JNI_FALSE;
+    }
+
+    if ((nio_sctp_getpaddrs = (sctp_getpaddrs_func*)
+            dlsym(RTLD_DEFAULT, "sctp_getpaddrs")) == NULL) {
+        JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+              dlerror());
+        return JNI_FALSE;
+    }
+
+    if ((nio_sctp_freepaddrs = (sctp_freepaddrs_func*)
+            dlsym(RTLD_DEFAULT, "sctp_freepaddrs")) == NULL) {
+        JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+              dlerror());
+        return JNI_FALSE;
+    }
+
+    if ((nio_sctp_bindx = (sctp_bindx_func*)
+            dlsym(RTLD_DEFAULT, "sctp_bindx")) == NULL) {
+        JNU_ThrowByName(env, "java/lang/UnsupportedOperationException",
+              dlerror());
+        return JNI_FALSE;
+    }
+
+    funcsLoaded = JNI_TRUE;
+    return JNI_TRUE;
+}
+
+/*
+ * Class:     sun_nio_ch_SctpNet
+ * Method:    socket0
+ * Signature: (Z)I
+ */
+JNIEXPORT jint JNICALL Java_sun_nio_ch_SctpNet_socket0
+  (JNIEnv *env, jclass klass, jboolean oneToOne) {
+    int fd;
+    struct sctp_event_subscribe event;
+
+    /* Try to load the socket API extension functions */
+    if (!funcsLoaded && !loadSocketExtensionFuncs(env)) {
+        return 0;
+    }
+
+    fd = socket(ipv6_available() ? AF_INET6 : AF_INET,
+            (oneToOne ? SOCK_STREAM : SOCK_SEQPACKET), IPPROTO_SCTP);
+
+    if (fd < 0) {
+        return handleSocketError(env, errno);
+    }
+
+    /* Enable events */
+    memset(&event, 0, sizeof(event));
+    event.sctp_data_io_event = 1;
+    event.sctp_association_event = 1;
+    event.sctp_address_event = 1;
+    event.sctp_send_failure_event = 1;
+    //event.sctp_peer_error_event = 1;
+    event.sctp_shutdown_event = 1;
+    //event.sctp_partial_delivery_event = 1;
+    //event.sctp_adaptation_layer_event = 1;
+    if (setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(event)) != 0) {
+       handleSocketError(env, errno);
+    }
+    return fd;
+}
+
+/*
+ * Class:     sun_nio_ch_SctpNet
+ * Method:    bindx
+ * Signature: (I[Ljava/net/InetAddress;IIZ)V
+ */
+JNIEXPORT void JNICALL Java_sun_nio_ch_SctpNet_bindx
+  (JNIEnv *env, jclass klass, jint fd, jobjectArray addrs, jint port,
+   jint addrsLength, jboolean add, jboolean preferIPv6) {
+    SOCKADDR *sap, *tmpSap;
+    int i, sa_len = sizeof(SOCKADDR);
+    jobject ia;
+
+    if (addrsLength < 1)
+        return;
+
+    if ((sap = calloc(addrsLength,  sa_len)) == NULL) {
+          JNU_ThrowOutOfMemoryError(env, "heap allocation failure");
+        return;
+    }
+
+    tmpSap = sap;
+    for (i=0; i<addrsLength; i++) {
+        ia = (*env)->GetObjectArrayElement(env, addrs, i);
+        if (NET_InetAddressToSockaddr(env, ia, port, (struct sockaddr*)tmpSap,
+                                      &sa_len, preferIPv6) != 0) {
+            free(sap);
+            return;
+        }
+        tmpSap++;
+    }
+
+    if (nio_sctp_bindx(fd, (void*)sap, addrsLength, add ? SCTP_BINDX_ADD_ADDR :
+                       SCTP_BINDX_REM_ADDR) != 0) {
+        handleSocketError(env, errno);
+    }
+
+    free(sap);
+}
+
+void initializeISA
+  (JNIEnv* env) {
+    if (isaCls == 0) {
+        jclass c = (*env)->FindClass(env, "java/net/InetSocketAddress");
+        CHECK_NULL(c);
+        isaCls = (*env)->NewGlobalRef(env, c);
+        CHECK_NULL(isaCls);
+        (*env)->DeleteLocalRef(env, c);
+        isaCtrID = (*env)->GetMethodID(env, isaCls, "<init>",
+                                     "(Ljava/net/InetAddress;I)V");
+    }
+}
+
+jobject SockAddrToInetSocketAddress
+  (JNIEnv *env, struct sockaddr* sap) {
+    int port = 0;
+
+    jobject ia = NET_SockaddrToInetAddress(env, sap, &port);
+    if (ia == NULL)
+        return NULL;
+
+    if (isaCls == 0) {
+        initializeISA(env);
+        CHECK_NULL_RETURN(isaCls, NULL);
+    }
+
+    return (*env)->NewObject(env, isaCls, isaCtrID, ia, port);
+}
+
+/*
+ * Class:     sun_nio_ch_SctpNet
+ * Method:    getLocalAddresses0
+ * Signature: (I)[Ljava/net/SocketAddress;
+ */
+JNIEXPORT jobjectArray JNICALL Java_sun_nio_ch_SctpNet_getLocalAddresses0
+  (JNIEnv *env, jclass klass, jint fd) {
+    void *addr_buf, *laddr;
+    struct sockaddr* sap;
+    int i, addrCount;
+    jobjectArray isaa;
+
+#ifdef __solaris__
+    if ((addrCount = nio_sctp_getladdrs(fd, 0, (void **)&addr_buf)) == -1) {
+#else /* __linux__ */
+    if ((addrCount = nio_sctp_getladdrs(fd, 0, (struct sockaddr **)&addr_buf)) == -1) {
+#endif
+        handleSocketError(env, errno);
+        return NULL;
+    }
+
+    if (addrCount < 1)
+        return NULL;
+
+    if (isaCls == 0) {
+        initializeISA(env);
+        CHECK_NULL_RETURN(isaCls, NULL);
+    }
+
+    isaa = (*env)->NewObjectArray(env, addrCount, isaCls, NULL);
+    if (isaa == NULL) {
+        nio_sctp_freeladdrs(addr_buf);
+        return NULL;
+    }
+
+    laddr = addr_buf;
+    for (i=0; i<addrCount; i++) {
+        int port = 0;
+        jobject isa = NULL, ia;
+        sap = (struct sockaddr*)addr_buf;
+        ia = NET_SockaddrToInetAddress(env, sap, &port);
+        if (ia != NULL)
+            isa = (*env)->NewObject(env, isaCls, isaCtrID, ia, port);
+        if (isa != NULL)
+            (*env)->SetObjectArrayElement(env, isaa, i, isa);
+
+        if (sap->sa_family == AF_INET)
+            addr_buf = ((struct sockaddr_in*)addr_buf) + 1;
+        else
+            addr_buf = ((struct sockaddr_in6*)addr_buf) + 1;
+    }
+
+    nio_sctp_freeladdrs(laddr);
+    return isaa;
+}
+
+jobjectArray getRemoteAddresses
+  (JNIEnv *env, jint fd, sctp_assoc_t id) {
+    void *addr_buf, *paddr;
+    struct sockaddr* sap;
+    int i, addrCount;
+    jobjectArray isaa;
+
+#if __solaris__
+    if ((addrCount = nio_sctp_getpaddrs(fd, id, (void **)&addr_buf)) == -1) {
+#else /* __linux__ */
+    if ((addrCount = nio_sctp_getpaddrs(fd, id, (struct sockaddr**)&addr_buf)) == -1) {
+#endif
+        handleSocketError(env, errno);
+        return NULL;
+    }
+
+    if (addrCount < 1)
+        return NULL;
+
+    if (isaCls == 0) {
+        initializeISA(env);
+        CHECK_NULL_RETURN(isaCls, NULL);
+    }
+
+    isaa = (*env)->NewObjectArray(env, addrCount, isaCls, NULL);
+    if (isaa == NULL) {
+        nio_sctp_freepaddrs(addr_buf);
+        return NULL;
+    }
+
+    paddr = addr_buf;
+    for (i=0; i<addrCount; i++) {
+        jobject ia, isa = NULL;
+        int port;
+        sap = (struct sockaddr*)addr_buf;
+        ia = NET_SockaddrToInetAddress(env, sap, &port);
+        if (ia != NULL)
+            isa = (*env)->NewObject(env, isaCls, isaCtrID, ia, port);
+        if (isa != NULL)
+            (*env)->SetObjectArrayElement(env, isaa, i, isa);
+
+        if (sap->sa_family == AF_INET)
+            addr_buf = ((struct sockaddr_in*)addr_buf) + 1;
+        else
+            addr_buf = ((struct sockaddr_in6*)addr_buf) + 1;
+    }
+
+    nio_sctp_freepaddrs(paddr);
+
+    return isaa;
+}
+
+ /*
+ * Class:     sun_nio_ch_SctpNet
+ * Method:    getRemoteAddresses0
+ * Signature: (II)[Ljava/net/SocketAddress;
+ */
+JNIEXPORT jobjectArray JNICALL Java_sun_nio_ch_SctpNet_getRemoteAddresses0
+  (JNIEnv *env, jclass klass, jint fd, jint assocId) {
+    return getRemoteAddresses(env, fd, assocId);
+}
+
+/* Map the Java level option to the native level */
+int mapSocketOption
+  (jint cmd, int *level, int *optname) {
+    static struct {
+        jint cmd;
+        int level;
+        int optname;
+    } const opts[] = {
+        { sun_nio_ch_SctpStdSocketOption_SCTP_DISABLE_FRAGMENTS,   IPPROTO_SCTP, SCTP_DISABLE_FRAGMENTS },
+        { sun_nio_ch_SctpStdSocketOption_SCTP_EXPLICIT_COMPLETE,   IPPROTO_SCTP, SCTP_EXPLICIT_EOR },
+        { sun_nio_ch_SctpStdSocketOption_SCTP_FRAGMENT_INTERLEAVE, IPPROTO_SCTP, SCTP_FRAGMENT_INTERLEAVE },
+        { sun_nio_ch_SctpStdSocketOption_SCTP_NODELAY,             IPPROTO_SCTP, SCTP_NODELAY },
+        { sun_nio_ch_SctpStdSocketOption_SO_SNDBUF,                SOL_SOCKET,   SO_SNDBUF },
+        { sun_nio_ch_SctpStdSocketOption_SO_RCVBUF,                SOL_SOCKET,   SO_RCVBUF },
+        { sun_nio_ch_SctpStdSocketOption_SO_LINGER,                SOL_SOCKET,   SO_LINGER } };
+
+    int i;
+    for (i=0; i<(int)(sizeof(opts) / sizeof(opts[0])); i++) {
+        if (cmd == opts[i].cmd) {
+            *level = opts[i].level;
+            *optname = opts[i].optname;
+            return 0;
+        }
+    }
+
+    /* not found */
+    return -1;
+}
+
+/*
+ * Class:     sun_nio_ch_SctpNet
+ * Method:    setIntOption0
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL Java_sun_nio_ch_SctpNet_setIntOption0
+  (JNIEnv *env, jclass klass, jint fd, jint opt, int arg) {
+    int klevel, kopt;
+    int result;
+    struct linger linger;
+    void *parg;
+    int arglen;
+
+    if (mapSocketOption(opt, &klevel, &kopt) < 0) {
+        JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
+                                     "Unsupported socket option");
+        return;
+    }
+
+    if (opt == sun_nio_ch_SctpStdSocketOption_SO_LINGER) {
+        parg = (void *)&linger;
+        arglen = sizeof(linger);
+        if (arg >= 0) {
+            linger.l_onoff = 1;
+            linger.l_linger = arg;
+        } else {
+            linger.l_onoff = 0;
+            linger.l_linger = 0;
+        }
+    } else {
+        parg = (void *)&arg;
+        arglen = sizeof(arg);
+    }
+
+    if (setsockopt(fd, klevel, kopt, parg, arglen) < 0) {
+        JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
+                                     "sun_nio_ch_SctpNet.setIntOption0");
+    }
+}
+
+/*
+ * Class:     sun_nio_ch_SctpNet
+ * Method:    getIntOption0
+ * Signature: (II)I
+ */
+JNIEXPORT int JNICALL Java_sun_nio_ch_SctpNet_getIntOption0
+  (JNIEnv *env, jclass klass, jint fd, jint opt) {
+    int klevel, kopt;
+    int result;
+    struct linger linger;
+    void *arg;
+    unsigned int arglen;
+
+    if (mapSocketOption(opt, &klevel, &kopt) < 0) {
+        JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
+                                     "Unsupported socket option");
+        return -1;
+    }
+
+    if (opt == sun_nio_ch_SctpStdSocketOption_SO_LINGER) {
+        arg = (void *)&linger;
+        arglen = sizeof(linger);
+    } else {
+        arg = (void *)&result;
+        arglen = sizeof(result);
+    }
+
+    if (getsockopt(fd, klevel, kopt, arg, &arglen) < 0) {
+        JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
+                                     "sun.nio.ch.Net.getIntOption");
+        return -1;
+    }
+
+    if (opt == sun_nio_ch_SctpStdSocketOption_SO_LINGER)
+        return linger.l_onoff ? linger.l_linger : -1;
+    else
+        return result;
+}
+
+/*
+ * Class:     sun_nio_ch_SctpNet
+ * Method:    getPrimAddrOption0
+ * Signature: (II)Ljava/net/SocketAddress;
+ */
+JNIEXPORT jobject JNICALL Java_sun_nio_ch_SctpNet_getPrimAddrOption0
+  (JNIEnv *env, jclass klass, jint fd, jint assocId) {
+    struct sctp_setprim prim;
+    struct sockaddr_storage ss;
+    int ss_len = sizeof(ss);
+    unsigned int prim_len = sizeof(prim);
+
+    prim.ssp_assoc_id = assocId;
+    prim.ssp_addr = ss;
+
+    if (getsockopt(fd, IPPROTO_SCTP, SCTP_PRIMARY_ADDR, &prim, &prim_len) < 0) {
+        JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
+                                     "sun.nio.ch.SctpNet.getPrimAddrOption0");
+        return NULL;
+    }
+
+    return SockAddrToInetSocketAddress(env, (struct sockaddr*)&ss);
+}
+
+/*
+ * Class:     sun_nio_ch_SctpNet
+ * Method:    setPrimAddrOption0
+ * Signature: (IILjava/net/InetAddress;I)V
+ */
+JNIEXPORT void JNICALL Java_sun_nio_ch_SctpNet_setPrimAddrOption0
+  (JNIEnv *env, jclass klass, jint fd, jint assocId, jobject iaObj, jint port) {
+    struct sctp_setprim prim;
+    struct sockaddr_storage ss;
+    int ss_len = sizeof(ss);
+
+    if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&ss,
+                                  &ss_len, JNI_TRUE) != 0) {
+        return;
+    }
+
+    prim.ssp_assoc_id = assocId;
+    prim.ssp_addr = ss;
+
+    if (setsockopt(fd, IPPROTO_SCTP, SCTP_PRIMARY_ADDR, &prim, sizeof(prim)) < 0) {
+        JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
+                                     "sun.nio.ch.SctpNet.setPrimAddrOption0");
+    }
+}
+
+/*
+ * Class:     sun_nio_ch_SctpNet
+ * Method:    setPeerPrimAddrOption0
+ * Signature: (IILjava/net/InetAddress;I)V
+ */
+JNIEXPORT void JNICALL Java_sun_nio_ch_SctpNet_setPeerPrimAddrOption0
+  (JNIEnv *env, jclass klass, jint fd, jint assocId, jobject iaObj, jint port) {
+    struct sctp_setpeerprim prim;
+    struct sockaddr_storage ss;
+    int ss_len = sizeof(ss);
+
+    if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&ss,
+                                  &ss_len, JNI_TRUE) != 0) {
+        return;
+    }
+
+    prim.sspp_assoc_id = assocId;
+    prim.sspp_addr = ss;
+
+    if (setsockopt(fd, IPPROTO_SCTP, SCTP_SET_PEER_PRIMARY_ADDR, &prim,
+            sizeof(prim)) < 0) {
+        JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
+                                     "sun.nio.ch.SctpNet.setPeerPrimAddrOption0");
+    }
+}
+
+/*
+ * Class:     sun_nio_ch_SctpNet
+ * Method:    getInitMsgOption0
+ * Signature: (I[I)V
+ */
+JNIEXPORT void JNICALL Java_sun_nio_ch_SctpNet_getInitMsgOption0
+  (JNIEnv *env, jclass klass, jint fd, jintArray retVal) {
+    struct sctp_initmsg sctp_initmsg;
+    unsigned int sim_len = sizeof(sctp_initmsg);
+    int vals[2];
+
+    if (getsockopt(fd, IPPROTO_SCTP, SCTP_INITMSG, &sctp_initmsg,
+            &sim_len) < 0) {
+        JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
+                                     "sun.nio.ch.SctpNet.getInitMsgOption0");
+        return;
+    }
+
+    vals[0] = sctp_initmsg.sinit_max_instreams;
+    vals[1] = sctp_initmsg.sinit_num_ostreams;
+    (*env)->SetIntArrayRegion(env, retVal, 0, 2, vals);
+}
+
+/*
+ * Class:     sun_nio_ch_SctpNet
+ * Method:    setInitMsgOption0
+ * Signature: (III)V
+ */
+JNIEXPORT void JNICALL Java_sun_nio_ch_SctpNet_setInitMsgOption0
+  (JNIEnv *env, jclass klass, jint fd, jint inArg, jint outArg) {
+    struct sctp_initmsg sctp_initmsg;
+
+    sctp_initmsg.sinit_max_instreams = (unsigned int)inArg;
+    sctp_initmsg.sinit_num_ostreams = (unsigned int)outArg;
+    sctp_initmsg.sinit_max_attempts = 0;  // default
+    sctp_initmsg.sinit_max_init_timeo = 0;  // default
+
+    if (setsockopt(fd, IPPROTO_SCTP, SCTP_INITMSG, &sctp_initmsg,
+          sizeof(sctp_initmsg)) < 0) {
+        JNU_ThrowByNameWithLastError(env, JNU_JAVANETPKG "SocketException",
+                                     "sun.nio.ch.SctpNet.setInitMsgOption0");
+    }
+}
+
+/*
+ * Class:     sun_nio_ch_SctpNet
+ * Method:    shutdown0
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL Java_sun_nio_ch_SctpNet_shutdown0
+  (JNIEnv *env, jclass klass, jint fd, jint assocId) {
+    int rv;
+    struct msghdr msg[1];
+    struct iovec iov[1];
+    int cbuf_size = CMSG_SPACE(sizeof (struct sctp_sndrcvinfo));
+    char cbuf[CMSG_SPACE(sizeof (struct sctp_sndrcvinfo))];
+    struct cmsghdr* cmsg;
+    struct sctp_sndrcvinfo *sri;
+
+    /* SctpSocketChannel */
+    if (assocId < 0) {
+        shutdown(fd, SHUT_WR);
+        return;
+    }
+
+    memset(msg, 0, sizeof (*msg));
+    memset(cbuf, 0, cbuf_size);
+    msg->msg_name = NULL;
+    msg->msg_namelen = 0;
+    iov->iov_base = NULL;
+    iov->iov_len = 0;
+    msg->msg_iov = iov;
+    msg->msg_iovlen = 1;
+    msg->msg_control = cbuf;
+    msg->msg_controllen = cbuf_size;
+    msg->msg_flags = 0;
+
+    cmsg = CMSG_FIRSTHDR(msg);
+    cmsg->cmsg_level = IPPROTO_SCTP;
+    cmsg->cmsg_type = SCTP_SNDRCV;
+    cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+
+    /* Initialize the payload: */
+    sri = (struct sctp_sndrcvinfo*) CMSG_DATA(cmsg);
+    memset(sri, 0, sizeof (*sri));
+
+    if (assocId > 0) {
+        sri->sinfo_assoc_id = assocId;
+    }
+
+    sri->sinfo_flags = sri->sinfo_flags | SCTP_EOF;
+
+    /* Sum of the length of all control messages in the buffer. */
+    msg->msg_controllen = cmsg->cmsg_len;
+
+    if ((rv = sendmsg(fd, msg, 0)) < 0) {
+        handleSocketError(env, errno);
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/solaris/native/sun/nio/ch/SctpServerChannelImpl.c	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+#include "sun_nio_ch_SctpServerChannelImpl.h"
+
+extern void Java_sun_nio_ch_ServerSocketChannelImpl_initIDs(JNIEnv* env,
+    jclass c);
+
+extern jint Java_sun_nio_ch_ServerSocketChannelImpl_accept0(JNIEnv* env,
+    jobject this, jobject ssfdo, jobject newfdo, jobjectArray isaa);
+
+/*
+ * Class:     sun_nio_ch_SctpServerChannelImpl
+ * Method:    initIDs
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_sun_nio_ch_SctpServerChannelImpl_initIDs
+  (JNIEnv* env, jclass c) {
+    Java_sun_nio_ch_ServerSocketChannelImpl_initIDs(env, c);
+}
+
+/*
+ * Class:     sun_nio_ch_SctpServerChannelImpl
+ * Method:    accept0
+ * Signature: (Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;[Ljava/net/InetSocketAddress;)I
+ */
+JNIEXPORT jint JNICALL Java_sun_nio_ch_SctpServerChannelImpl_accept0
+  (JNIEnv* env, jobject this, jobject ssfdo, jobject newfdo, jobjectArray isaa) {
+    return Java_sun_nio_ch_ServerSocketChannelImpl_accept0(env, this,
+                                                           ssfdo, newfdo, isaa);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/ch/SctpChannelImpl.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package sun.nio.ch;
+
+import java.net.SocketAddress;
+import java.net.InetAddress;
+import java.io.IOException;
+import java.util.Set;
+import java.nio.ByteBuffer;
+import java.nio.channels.spi.SelectorProvider;
+import com.sun.nio.sctp.Association;
+import com.sun.nio.sctp.MessageInfo;
+import com.sun.nio.sctp.NotificationHandler;
+import com.sun.nio.sctp.SctpChannel;
+import com.sun.nio.sctp.SctpSocketOption;
+
+/**
+ * Unimplemented.
+ */
+public class SctpChannelImpl extends SctpChannel
+{
+    private static final String message = "SCTP not supported on this platform";
+
+    public SctpChannelImpl(SelectorProvider provider) {
+        super(provider);
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public Association association() {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public SctpChannel bind(SocketAddress local)
+                            throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public SctpChannel bindAddress(InetAddress address)
+         throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public SctpChannel unbindAddress(InetAddress address)
+         throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public boolean connect(SocketAddress remote) throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public boolean connect(SocketAddress remote, int maxOutStreams,
+       int maxInStreams) throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public boolean isConnectionPending() {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public boolean finishConnect() throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public Set<SocketAddress> getAllLocalAddresses()
+            throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public Set<SocketAddress> getRemoteAddresses()
+            throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public SctpChannel shutdown() throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public <T> T getOption(SctpSocketOption<T> name)
+            throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public <T> SctpChannel setOption(SctpSocketOption<T> name, T value)
+        throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public Set<SctpSocketOption<?>> supportedOptions() {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public <T> MessageInfo receive(ByteBuffer dst, T attachment,
+            NotificationHandler<T> handler) throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public int send(ByteBuffer src, MessageInfo messageInfo)
+            throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    protected void implConfigureBlocking(boolean block) throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public void implCloseSelectableChannel() throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/ch/SctpMultiChannelImpl.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package sun.nio.ch;
+
+import java.net.SocketAddress;
+import java.net.InetAddress;
+import java.io.IOException;
+import java.util.Set;
+import java.nio.ByteBuffer;
+import java.nio.channels.spi.SelectorProvider;
+import com.sun.nio.sctp.Association;
+import com.sun.nio.sctp.SctpChannel;
+import com.sun.nio.sctp.MessageInfo;
+import com.sun.nio.sctp.NotificationHandler;
+import com.sun.nio.sctp.SctpMultiChannel;
+import com.sun.nio.sctp.SctpSocketOption;
+
+/**
+ * Unimplemented.
+ */
+public class SctpMultiChannelImpl extends SctpMultiChannel
+{
+    private static final String message = "SCTP not supported on this platform";
+
+    public SctpMultiChannelImpl(SelectorProvider provider) {
+        super(provider);
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public Set<Association> associations() {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public SctpMultiChannel bind(SocketAddress local,
+            int backlog) throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public SctpMultiChannel bindAddress(InetAddress address)
+         throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public SctpMultiChannel unbindAddress(InetAddress address)
+         throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public Set<SocketAddress> getAllLocalAddresses()
+            throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public Set<SocketAddress> getRemoteAddresses
+            (Association association) throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public SctpMultiChannel shutdown(Association association)
+            throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public <T> T getOption(SctpSocketOption<T> name,
+            Association association) throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public <T> SctpMultiChannel setOption(SctpSocketOption<T> name,
+            T value, Association association) throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public Set<SctpSocketOption<?>> supportedOptions() {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public <T> MessageInfo receive(ByteBuffer buffer, T attachment,
+            NotificationHandler<T> handler) throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public int send(ByteBuffer buffer, MessageInfo messageInfo)
+            throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public SctpChannel branch(Association association)
+            throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    protected void implConfigureBlocking(boolean block) throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public void implCloseSelectableChannel() throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/windows/classes/sun/nio/ch/SctpServerChannelImpl.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package sun.nio.ch;
+
+import java.net.SocketAddress;
+import java.net.InetAddress;
+import java.io.IOException;
+import java.util.Set;
+import java.nio.channels.spi.SelectorProvider;
+import com.sun.nio.sctp.SctpChannel;
+import com.sun.nio.sctp.SctpServerChannel;
+import com.sun.nio.sctp.SctpSocketOption;
+
+/**
+ * Unimplemented.
+ */
+public class SctpServerChannelImpl extends SctpServerChannel
+{
+    private static final String message = "SCTP not supported on this platform";
+
+    public SctpServerChannelImpl(SelectorProvider provider) {
+        super(provider);
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public SctpChannel accept() throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public SctpServerChannel bind(SocketAddress local,
+            int backlog) throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public SctpServerChannel bindAddress(InetAddress address)
+         throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public SctpServerChannel unbindAddress(InetAddress address)
+         throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public Set<SocketAddress> getAllLocalAddresses()
+            throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public <T> T getOption(SctpSocketOption<T> name) throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public <T> SctpServerChannel setOption(SctpSocketOption<T> name,
+            T value) throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public Set<SctpSocketOption<?>> supportedOptions() {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    protected void implConfigureBlocking(boolean block) throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+
+    @Override
+    public void implCloseSelectableChannel() throws IOException {
+        throw new UnsupportedOperationException(message);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/nio/sctp/MessageInfoTests.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4927640
+ * @summary Tests the SCTP protocol implementation
+ * @author chegar
+ */
+
+import java.net.SocketAddress;
+import com.sun.nio.sctp.Association;
+import com.sun.nio.sctp.MessageInfo;
+
+public class MessageInfoTests {
+    static final int DEFAULT_STREAM_NUMBER = 14;
+    static final int TEST_STREAM_NUMBER = 15;
+    static final int TEST_PPID = 8;
+    static final long TEST_TTL = 10000L;
+    static final SocketAddress addr = new TestSocketAddress();
+    static final Association assoc = new TestAssociation(1, 1, 1);
+
+    void test(String[] args) {
+        /* TEST 1 : createOutGoing(SocketAddress,int) */
+        MessageInfo info = MessageInfo.createOutgoing(addr,
+                                                      DEFAULT_STREAM_NUMBER);
+        checkDefaults(info);
+        checkGetterSetters(info);
+
+        /* TEST 2 : createOutGoing(Association,SocketAddress,int) */
+        info = MessageInfo.createOutgoing(assoc, addr, DEFAULT_STREAM_NUMBER);
+        checkDefaults(info);
+        check(info.association().equals(assoc), "incorrect association");
+        checkGetterSetters(info);
+
+        /* TEST 3: null values */
+        info = MessageInfo.createOutgoing(null, 0);
+        check(info.address() == null, "address should be null");
+        check(info.association() == null, "association should be null");
+        info = MessageInfo.createOutgoing(assoc, null, 0);
+        check(info.address() == null, "address should be null");
+
+        /* Test 4: IllegalArgumentException */
+        testIAE(new Runnable() {
+          public void run() { MessageInfo.createOutgoing(addr, -1); } });
+        testIAE(new Runnable() {
+          public void run() { MessageInfo.createOutgoing(addr, 65537); } });
+        testIAE(new Runnable() {
+          public void run() { MessageInfo.createOutgoing(null, addr, 0); } });
+        testIAE(new Runnable() {
+          public void run() { MessageInfo.createOutgoing(assoc, addr, -1); } });
+        testIAE(new Runnable() {
+          public void run() { MessageInfo.createOutgoing(assoc, addr, 65537);}});
+
+        final MessageInfo iaeInfo = MessageInfo.createOutgoing(assoc, addr, 0);
+        testIAE(new Runnable() {
+          public void run() { iaeInfo.streamNumber(-1); } });
+        testIAE(new Runnable() {
+          public void run() { iaeInfo.streamNumber(65537); } });
+    }
+
+   /* TEST : unordered = false, timeToLive = 0, complete = true,
+    *        payloadProtocolID = 0. */
+    void checkDefaults(MessageInfo info) {
+        check(info.isUnordered() == false, "default unordered value not false");
+        check(info.timeToLive() == 0L, "timeToLive should be 0L");
+        check(info.isComplete() == true, "default complete value not true");
+        check(info.payloadProtocolID() == 0, "default PPID not 0");
+        check(info.bytes() == 0, "default bytes value not 0");
+        check(info.streamNumber() == DEFAULT_STREAM_NUMBER,
+                "incorrect default stream number");
+        check(info.address().equals(addr), "incorrect address");
+    }
+
+    void checkGetterSetters(MessageInfo info) {
+        check(info.streamNumber(TEST_STREAM_NUMBER).streamNumber() ==
+                TEST_STREAM_NUMBER, "stream number not being set correctly");
+
+        check(info.complete(false).isComplete() == false,
+                "complete not being set correctly");
+
+        check(info.unordered(true).isUnordered() == true,
+                "unordered not being set correctly");
+
+        check(info.payloadProtocolID(TEST_PPID).payloadProtocolID() ==
+                                  TEST_PPID, "PPID not being set correctly");
+
+        check(info.timeToLive(TEST_TTL).timeToLive() == TEST_TTL,
+                "TTL not being set correctly");
+    }
+
+    void testIAE(Runnable runnable) {
+        try {
+            runnable.run();
+            fail("IllegalArgumentException should have been thrown");
+        } catch(IllegalArgumentException iae) {
+            pass();
+        }
+    }
+
+    static class TestSocketAddress extends SocketAddress {}
+
+    static class TestAssociation extends Association {
+        TestAssociation(int assocID, int maxInStreams, int maxOutStreams) {
+            super(assocID, maxInStreams, maxOutStreams);
+        }
+    }
+
+          //--------------------- Infrastructure ---------------------------
+    boolean debug = true;
+    volatile int passed = 0, failed = 0;
+    void pass() {passed++;}
+    void fail() {failed++; Thread.dumpStack();}
+    void fail(String msg) {System.err.println(msg); fail();}
+    void unexpected(Throwable t) {failed++; t.printStackTrace();}
+    void check(boolean cond) {if (cond) pass(); else fail();}
+    void check(boolean cond, String failMessage) {if (cond) pass();
+          else fail(failMessage);}
+    void debug(String message) {if(debug) { System.out.println(message); }  }
+    public static void main(String[] args) throws Throwable {
+        Class<?> k = new Object(){}.getClass().getEnclosingClass();
+        try {k.getMethod("instanceMain",String[].class)
+                .invoke( k.newInstance(), (Object) args);}
+        catch (Throwable e) {throw e.getCause();}}
+    public void instanceMain(String[] args) throws Throwable {
+        try {test(args);} catch (Throwable t) {unexpected(t);}
+        System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
+        if (failed > 0) throw new AssertionError("Some tests failed");}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/nio/sctp/SctpChannel/Bind.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,350 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4927640
+ * @summary Tests the SCTP protocol implementation
+ * @author chegar
+ */
+
+import java.net.*;
+import java.io.*;
+import java.util.List;
+import java.util.Set;
+import java.util.Iterator;
+import java.nio.ByteBuffer;
+import java.nio.channels.AlreadyBoundException;
+import java.nio.channels.AlreadyConnectedException;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.UnsupportedAddressTypeException;
+import com.sun.nio.sctp.AssociationChangeNotification;
+import com.sun.nio.sctp.AbstractNotificationHandler;
+import com.sun.nio.sctp.HandlerResult;
+import com.sun.nio.sctp.IllegalUnbindException;
+import com.sun.nio.sctp.MessageInfo;
+import com.sun.nio.sctp.PeerAddressChangeNotification;
+import com.sun.nio.sctp.SctpChannel;
+import com.sun.nio.sctp.SctpServerChannel;
+import com.sun.nio.sctp.ShutdownNotification;
+import static java.lang.System.out;
+
+/**
+ * Tests bind, bindAddress, unbindAddress, getLocalAddress, and
+ * getAllLocalAddresses.
+ */
+public class Bind {
+     void test(String[] args) {
+        if (!Util.isSCTPSupported()) {
+            out.println("SCTP protocol is not supported");
+            out.println("Test cannot be run");
+            return;
+        }
+
+        /* Simply bind tests */
+        testBind();
+
+        /* Test unconnected */
+        testBindUnbind(false);
+
+        /* Test connected */
+        /* Adding/Removing addresses from a connected association is optional.
+         * This test can be run on systems that support dynamic address
+         * reconfiguration */
+        //testBindUnbind(true);
+    }
+
+    void testBind() {
+        SctpChannel channel = null;
+        try {
+            channel = SctpChannel.open();
+
+            /* TEST 1: empty set if channel is not bound */
+            check(channel.getAllLocalAddresses().isEmpty(),
+                    "getAllLocalAddresses returned non empty set for unbound channel");
+
+            /* TEST 2: null to bind the channel to an automatically assigned
+             *         socket address */
+            channel.bind(null);
+
+            /* TEST 3: non empty set if the channel is bound */
+            check(!channel.getAllLocalAddresses().isEmpty(),
+                    "getAllLocalAddresses returned empty set for bound channel");
+            debug("getAllLocalAddresses on channel bound to the wildcard:\n"
+                    + channel.getAllLocalAddresses());
+
+            /* TEST 4: AlreadyBoundException if this channel is already bound */
+            try { channel.bind(null); }
+            catch (AlreadyBoundException unused) { pass(); }
+            catch (IOException ioe) { unexpected(ioe); }
+
+            /* TEST 5: UnsupportedAddressTypeException */
+            try {
+                channel.close();  /* open a new unbound channel for test */
+                channel = SctpChannel.open();
+                channel.bind(new UnsupportedSocketAddress());
+                fail("UnsupportedSocketAddress expected");
+            } catch (UnsupportedAddressTypeException unused) { pass();
+            } catch (IOException ioe) { unexpected(ioe); }
+
+            /* TEST 6: AlreadyConnectedException */
+            try {
+                channel.close();  /* open a new unbound channel for test */
+                channel = SctpChannel.open();
+                connectChannel(channel);
+                channel.bind(null);
+                fail("AlreadyConnectedException expected");
+            } catch (AlreadyConnectedException unused) { pass();
+            } catch (IOException ioe) { unexpected(ioe); }
+
+            /* TEST 7: ClosedChannelException - If this channel is closed */
+            try {
+                channel.close();  /* open a new unbound channel for test */
+                channel = SctpChannel.open();
+                channel.close();
+                channel.bind(null);
+                fail("ClosedChannelException expected");
+            } catch (ClosedChannelException unused) { pass();
+            } catch (IOException ioe) { unexpected(ioe); }
+
+            /* TEST 8: ClosedChannelException if channel is closed */
+            try {
+                channel.getAllLocalAddresses();
+                fail("should have thrown ClosedChannelException");
+            } catch (ClosedChannelException cce) {
+               pass();
+            } catch (Exception ioe) {
+                unexpected(ioe);
+            }
+        } catch (IOException ioe) {
+            unexpected(ioe);
+        } finally {
+            try { channel.close(); }
+            catch (IOException ioe) { unexpected(ioe); }
+        }
+    }
+
+    void testBindUnbind(boolean connected) {
+        SctpChannel channel = null;
+        SctpChannel peerChannel = null;
+
+        debug("testBindUnbind, connected: " + connected);
+        try {
+            channel = SctpChannel.open();
+
+            List<InetAddress> addresses = Util.getAddresses(true, false);
+            Iterator iterator = addresses.iterator();
+            InetSocketAddress a = new InetSocketAddress((InetAddress)iterator.next(), 0);
+            debug("channel.bind( " + a + ")");
+            channel.bind(a);
+            while (iterator.hasNext()) {
+                InetAddress ia = (InetAddress)iterator.next();
+                debug("channel.bindAddress(" + ia + ")");
+                channel.bindAddress(ia);
+            }
+            if (debug) {Util.dumpAddresses(channel, out);}
+
+            if (connected) {
+                /* Test with connected channel */
+                peerChannel = connectChannel(channel);
+            }
+
+            /* TEST 1: bind/unbindAddresses on the system addresses */
+            debug("bind/unbindAddresses on the system addresses");
+            List<InetAddress> addrs = Util.getAddresses(true, false);
+            for (InetAddress addr : addrs) {
+                try {
+                    debug("unbindAddress: " + addr);
+                    check(boundAddress(channel, addr), "trying to remove address that is not bound");
+                    channel.unbindAddress(addr);
+                    if (debug) {Util.dumpAddresses(channel, out);}
+                    check(!boundAddress(channel, addr), "address was not removed");
+
+                    debug("bindAddress: " + addr);
+                    channel.bindAddress(addr);
+                    if (debug) {Util.dumpAddresses(channel, out);}
+                    check(boundAddress(channel, addr), "address is not bound");
+                } catch (IOException ioe) {
+                    unexpected(ioe);
+                }
+            }
+
+            /* TEST 2: bindAddress - already bound address. */
+            InetAddress againAddress = addrs.get(0);
+            try {
+                debug("bind already bound address " + againAddress);
+                channel.bindAddress(againAddress);
+            } catch (AlreadyBoundException unused) {
+                debug("Caught AlreadyBoundException - OK");
+                pass();
+            } catch (IOException ioe) {
+                unexpected(ioe);
+            }
+
+            /* TEST 3: bind non local address */
+            try {
+                InetAddress nla = InetAddress.getByName("123.123.123.123");
+                debug("bind non local address " + nla);
+                channel.bindAddress(nla);
+            } catch (IOException ioe) {
+                debug("Informative only " + ioe);
+            }
+
+            /* TEST 4: unbind address that is not bound */
+            try {
+                debug("unbind address that is not bound " + againAddress);
+                /* remove address first then again */
+                channel.unbindAddress(againAddress);
+                channel.unbindAddress(againAddress);
+            } catch (IllegalUnbindException unused) {
+                debug("Caught IllegalUnbindException - OK");
+                pass();
+            } catch (IOException ioe) {
+                unexpected(ioe);
+            }
+
+            /* TEST 5: unbind address that is not bound */
+            try {
+                InetAddress nla = InetAddress.getByName("123.123.123.123");
+                debug("unbind address that is not bound " + nla);
+                channel.unbindAddress(nla);
+
+            } catch (IllegalUnbindException unused) {
+                debug("Caught IllegalUnbindException - OK");
+                pass();
+            } catch (IOException ioe) {
+                unexpected(ioe);
+            }
+
+            if (connected) {
+                channel.shutdown();
+
+                BindNotificationHandler handler = new BindNotificationHandler();
+                ByteBuffer buffer = ByteBuffer.allocate(10);
+                MessageInfo info;
+                while((info = peerChannel.receive(buffer, null, handler)) != null) {
+                    if (info != null) {
+                        if (info.bytes() == -1) {
+                            debug("peerChannel Reached EOF");
+                            break;
+                        }
+                    }
+                }
+
+                while((info = channel.receive(buffer, null, handler)) != null) {
+                    if (info != null) {
+                        if (info.bytes() == -1) {
+                            debug("channel Reached EOF");
+                            break;
+                        }
+                    }
+                }
+            }
+        } catch (IOException ioe) {
+            ioe.printStackTrace();
+        } finally {
+            try { if (channel != null) channel.close(); }
+            catch (IOException ioe) { unexpected(ioe); }
+        }
+    }
+
+    boolean boundAddress(SctpChannel channel, InetAddress addr)
+        throws IOException {
+        for (SocketAddress boundAddr : channel.getAllLocalAddresses()) {
+            if (((InetSocketAddress) boundAddr).getAddress().equals(addr))
+                return true;
+        }
+        return false;
+    }
+
+    SctpChannel connectChannel(SctpChannel channel)
+        throws IOException {
+        debug("connecting channel...");
+        try {
+            SctpServerChannel ssc = SctpServerChannel.open();
+            ssc.bind(null);
+            Set<SocketAddress> addrs = ssc.getAllLocalAddresses();
+            Iterator<SocketAddress> iterator = addrs.iterator();
+            SocketAddress addr = iterator.next();
+            debug("using " + addr + "...");
+            channel.connect(addr);
+            SctpChannel peerChannel = ssc.accept();
+            ssc.close();
+            debug("connected");
+            return peerChannel;
+        } catch (IOException ioe) {
+            debug("Cannot connect channel");
+            unexpected(ioe);
+            throw ioe;
+        }
+    }
+
+    class BindNotificationHandler extends AbstractNotificationHandler<Object>
+    {
+        @Override
+        public HandlerResult handleNotification(
+                AssociationChangeNotification acn, Object unused)
+        {
+            debug("AssociationChangeNotification: " +  acn);
+            return HandlerResult.CONTINUE;
+        }
+
+        @Override
+        public HandlerResult handleNotification(
+                PeerAddressChangeNotification pacn, Object unused)
+        {
+            debug("PeerAddressChangeNotification: " +  pacn);
+            return HandlerResult.CONTINUE;
+        }
+
+        @Override
+        public HandlerResult handleNotification(
+                ShutdownNotification sn, Object unused)
+        {
+            debug("ShutdownNotification: " +  sn);
+            return HandlerResult.CONTINUE;
+        }
+    }
+
+    class UnsupportedSocketAddress extends SocketAddress { }
+
+    //--------------------- Infrastructure ---------------------------
+    boolean debug = true;
+    volatile int passed = 0, failed = 0;
+    void pass() {passed++;}
+    void fail() {failed++; Thread.dumpStack();}
+    void fail(String msg) {System.err.println(msg); fail();}
+    void unexpected(Throwable t) {failed++; t.printStackTrace();}
+    void check(boolean cond) {if (cond) pass(); else fail();}
+    void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);}
+    void debug(String message) {if(debug) { System.out.println(message); }  }
+    public static void main(String[] args) throws Throwable {
+        Class<?> k = new Object(){}.getClass().getEnclosingClass();
+        try {k.getMethod("instanceMain",String[].class)
+                .invoke( k.newInstance(), (Object) args);}
+        catch (Throwable e) {throw e.getCause();}}
+    public void instanceMain(String[] args) throws Throwable {
+        try {test(args);} catch (Throwable t) {unexpected(t);}
+        System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
+        if (failed > 0) throw new AssertionError("Some tests failed");}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/nio/sctp/SctpChannel/Connect.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,283 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4927640
+ * @summary Tests the SCTP protocol implementation
+ * @author chegar
+ */
+
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.io.IOException;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.nio.channels.AlreadyConnectedException;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.ConnectionPendingException;
+import java.nio.channels.NoConnectionPendingException;
+import java.nio.channels.UnresolvedAddressException;
+import java.nio.channels.UnsupportedAddressTypeException;
+import com.sun.nio.sctp.SctpChannel;
+import com.sun.nio.sctp.SctpServerChannel;
+import static java.lang.System.out;
+import static java.lang.System.err;
+
+/**
+ * Tests connect, finishConnect, isConnectionPending,
+ * getRemoteAddresses and association.
+ */
+public class Connect {
+    final CountDownLatch finishedLatch = new CountDownLatch(1);
+
+    void test(String[] args) {
+        SocketAddress address = null;
+        Server server = null;
+
+        if (!Util.isSCTPSupported()) {
+            out.println("SCTP protocol is not supported");
+            out.println("Test cannot be run");
+            return;
+        }
+
+        if (args.length == 2) {
+            /* requested to connect to a specific address */
+            try {
+                int port = Integer.valueOf(args[1]);
+                address = new InetSocketAddress(args[0], port);
+            } catch (NumberFormatException nfe) {
+                err.println(nfe);
+            }
+        } else {
+            /* start server on local machine, default */
+            try {
+                server = new Server();
+                server.start();
+                address = server.address();
+                debug("Server started and listening on " + address);
+            } catch (IOException ioe) {
+                ioe.printStackTrace();
+                return;
+            }
+        }
+
+        doTest(address);
+    }
+
+    void doTest(SocketAddress addr) {
+        SctpChannel channel = null;
+        final SocketAddress peerAddress = addr;
+
+        try {
+            channel = SctpChannel.open();
+
+            /* TEST 0.5 Verify default values for new/unconnected channel */
+            check(channel.getRemoteAddresses().isEmpty(),
+                    "non empty set for unconnected channel");
+            check(channel.association() == null,
+                    "non-null association for unconnected channel");
+            check(!channel.isConnectionPending(),
+                    "should not have a connection pending");
+
+            /* TEST 1: non-blocking connect */
+            channel.configureBlocking(false);
+            if (channel.connect(peerAddress) != true) {
+                debug("non-blocking connect did not immediately succeed");
+                check(channel.isConnectionPending(),
+                        "should return true for isConnectionPending");
+                try {
+                    channel.connect(peerAddress);
+                    fail("should have thrown ConnectionPendingException");
+                } catch (ConnectionPendingException cpe) {
+                    pass();
+                } catch (IOException ioe) {
+                    unexpected(ioe);
+                }
+                channel.configureBlocking(true);
+                check(channel.finishConnect(),
+                        "finishConnect should have returned true");
+            }
+
+            /* TEST 1.5 Verify after connect */
+            check(!channel.getRemoteAddresses().isEmpty(),
+                    "empty set for connected channel");
+            check(channel.association() != null,
+                    "null association for connected channel");
+            check(!channel.isConnectionPending(),
+                    "pending connection for connected channel");
+
+            /* TEST 2: Verify AlreadyConnectedException thrown */
+            try {
+                channel.connect(peerAddress);
+                fail("should have thrown AlreadyConnectedException");
+            } catch (AlreadyConnectedException unused) {
+                pass();
+            }  catch (IOException ioe) {
+                unexpected(ioe);
+            }
+
+            /* TEST 3: UnresolvedAddressException */
+            channel.close();
+            channel = SctpChannel.open();
+            InetSocketAddress unresolved =
+                    InetSocketAddress.createUnresolved("xxyyzzabc", 4567);
+            try {
+                channel.connect(unresolved);
+                fail("should have thrown UnresolvedAddressException");
+            } catch (UnresolvedAddressException unused) {
+                pass();
+            }  catch (IOException ioe) {
+                unexpected(ioe);
+            }
+
+            /* TEST 4: UnsupportedAddressTypeException */
+            SocketAddress unsupported = new UnsupportedSocketAddress();
+            try {
+                channel.connect(unsupported);
+                fail("should have thrown UnsupportedAddressTypeException");
+            } catch (UnsupportedAddressTypeException unused) {
+                pass();
+            }  catch (IOException ioe) {
+                unexpected(ioe);
+            }
+
+            /* TEST 5: ClosedChannelException */
+            channel.close();
+            final SctpChannel closedChannel = channel;
+            testCCE(new Callable<Void>() {
+                public Void call() throws IOException {
+                    closedChannel.connect(peerAddress); return null; } });
+
+            /* TEST 5.5 getRemoteAddresses */
+            testCCE(new Callable<Void>() {
+                public Void call() throws IOException {
+                    closedChannel.getRemoteAddresses(); return null; } });
+            testCCE(new Callable<Void>() {
+                public Void call() throws IOException {
+                    closedChannel.association(); return null; } });
+            check(!channel.isConnectionPending(),
+                    "pending connection for closed channel");
+
+            /* Run some more finishConnect tests */
+
+            /* TEST 6: NoConnectionPendingException */
+            channel = SctpChannel.open();
+            try {
+                channel.finishConnect();
+                fail("should have thrown NoConnectionPendingException");
+            } catch (NoConnectionPendingException unused) {
+                pass();
+            }  catch (IOException ioe) {
+                unexpected(ioe);
+            }
+
+            /* TEST 7: ClosedChannelException */
+            channel.close();
+            final SctpChannel cceChannel = channel;
+            testCCE(new Callable<Void>() {
+                public Void call() throws IOException {
+                    cceChannel.finishConnect(); return null; } });
+        } catch (IOException ioe) {
+            unexpected(ioe);
+        } finally {
+            finishedLatch.countDown();
+            try { if (channel != null) channel.close(); }
+            catch (IOException e) { unexpected(e);}
+        }
+    }
+
+    class UnsupportedSocketAddress extends SocketAddress { }
+
+    void testCCE(Callable callable) {
+        try {
+            callable.call();
+            fail("should have thrown ClosedChannelException");
+        } catch (ClosedChannelException cce) {
+           pass();
+        } catch (Exception ioe) {
+            unexpected(ioe);
+        }
+    }
+
+    class Server implements Runnable
+    {
+        final InetSocketAddress serverAddr;
+        private SctpServerChannel ssc;
+
+        public Server() throws IOException {
+            ssc = SctpServerChannel.open().bind(null);
+            java.util.Set<SocketAddress> addrs = ssc.getAllLocalAddresses();
+            if (addrs.isEmpty())
+                debug("addrs should not be empty");
+
+            serverAddr = (InetSocketAddress) addrs.iterator().next();
+        }
+
+        public void start() {
+            (new Thread(this, "Server-"  + serverAddr.getPort())).start();
+        }
+
+        public InetSocketAddress address() {
+            return serverAddr;
+        }
+
+        @Override
+        public void run() {
+            SctpChannel sc = null;
+            try {
+                sc = ssc.accept();
+                finishedLatch.await();
+            } catch (IOException ioe) {
+                unexpected(ioe);
+            } catch (InterruptedException ie) {
+                unexpected(ie);
+            } finally {
+                try { if (ssc != null) ssc.close(); }
+                catch (IOException  ioe) { unexpected(ioe); }
+                try { if (sc != null) sc.close(); }
+                catch (IOException  ioe) { unexpected(ioe); }
+            }
+        }
+    }
+
+        //--------------------- Infrastructure ---------------------------
+    boolean debug = true;
+    volatile int passed = 0, failed = 0;
+    void pass() {passed++;}
+    void fail() {failed++; Thread.dumpStack();}
+    void fail(String msg) {System.err.println(msg); fail();}
+    void unexpected(Throwable t) {failed++; t.printStackTrace();}
+    void check(boolean cond) {if (cond) pass(); else fail();}
+    void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);}
+    void debug(String message) {if(debug) { System.out.println(message); }  }
+    public static void main(String[] args) throws Throwable {
+        Class<?> k = new Object(){}.getClass().getEnclosingClass();
+        try {k.getMethod("instanceMain",String[].class)
+                .invoke( k.newInstance(), (Object) args);}
+        catch (Throwable e) {throw e.getCause();}}
+    public void instanceMain(String[] args) throws Throwable {
+        try {test(args);} catch (Throwable t) {unexpected(t);}
+        System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
+        if (failed > 0) throw new AssertionError("Some tests failed");}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/nio/sctp/SctpChannel/Receive.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,361 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4927640
+ * @summary Tests the SCTP protocol implementation
+ * @author chegar
+ */
+
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.nio.ByteBuffer;
+import java.nio.channels.NotYetConnectedException;
+import java.nio.channels.ClosedChannelException;
+import com.sun.nio.sctp.AbstractNotificationHandler;
+import com.sun.nio.sctp.AssociationChangeNotification;
+import com.sun.nio.sctp.AssociationChangeNotification.AssocChangeEvent;
+import com.sun.nio.sctp.HandlerResult;
+import com.sun.nio.sctp.IllegalReceiveException;
+import com.sun.nio.sctp.MessageInfo;
+import com.sun.nio.sctp.Notification;
+import com.sun.nio.sctp.SctpChannel;
+import com.sun.nio.sctp.SctpServerChannel;
+import com.sun.nio.sctp.ShutdownNotification;
+import static java.lang.System.out;
+import static java.lang.System.err;
+
+public class Receive {
+    /* Latches used to synchronize between the client and server so that
+     * connections without any IO may not be closed without being accepted */
+    final CountDownLatch clientFinishedLatch = new CountDownLatch(1);
+    final CountDownLatch serverFinishedLatch = new CountDownLatch(1);
+
+    /* Used to verify that the ppid is being sent and received correctly */
+    static final int PPID = 5;
+
+    void test(String[] args) {
+        SocketAddress address = null;
+        Server server;
+
+
+        if (!Util.isSCTPSupported()) {
+            out.println("SCTP protocol is not supported");
+            out.println("Test cannot be run");
+            return;
+        }
+
+        if (args.length == 2) {
+            /* requested to connecct to a specific address */
+            try {
+                int port = Integer.valueOf(args[1]);
+                address = new InetSocketAddress(args[0], port);
+            } catch (NumberFormatException nfe) {
+                err.println(nfe);
+            }
+        } else {
+            /* start server on local machine, default */
+            try {
+                server = new Server();
+                server.start();
+                address = server.address();
+                debug("Server started and listening on " + address);
+            } catch (IOException ioe) {
+                ioe.printStackTrace();
+                return;
+            }
+        }
+
+        doTest(address);
+    }
+
+    void doTest(SocketAddress peerAddress) {
+        SctpChannel channel = null;
+        ByteBuffer buffer = ByteBuffer.allocate(Util.LARGE_BUFFER);
+        MessageInfo info;
+
+        try {
+            channel = SctpChannel.open();
+            ReceiveNotificationHandler handler =
+                new ReceiveNotificationHandler(channel);
+
+            /* TEST 1: Verify NotYetConnectedException thrown */
+            try {
+                channel.receive(buffer, null, handler);
+                fail("should have thrown NotYetConnectedException");
+            } catch (NotYetConnectedException unused) {
+                pass();
+            }  catch (IOException ioe) {
+                unexpected(ioe);
+            }
+
+            channel.connect(peerAddress);
+
+            /* TEST 2: receive small message */
+            do {
+                debug("Test 2: invoking receive");
+                info = channel.receive(buffer, null, handler);
+                if (info == null) {
+                    fail("unexpected null from receive");
+                    return;
+                }
+            } while (!info.isComplete());
+
+            buffer.flip();
+            check(handler.receivedCommUp(), "SCTP_COMM_UP not received");
+            check(info != null, "info is null");
+            check(info.address() != null, "address is null");
+            check(info.association() != null, "association is null");
+            check(info.isComplete(), "message is not complete");
+            check(info.isUnordered() != true,
+                  "message should not be unordered");
+            check(info.streamNumber() >= 0, "invalid stream number");
+            check(info.payloadProtocolID() == PPID, "PPID incorrect");
+            check(info.bytes() == Util.SMALL_MESSAGE.getBytes("ISO-8859-1").
+                  length, "bytes received not equal to message length");
+            check(info.bytes() == buffer.remaining(), "bytes != remaining");
+            check(Util.compare(buffer, Util.SMALL_MESSAGE),
+                  "received message not the same as sent message");
+
+            buffer.clear();
+
+             /* TEST 3: receive large message */
+            do {
+                debug("Test 3: invoking receive");
+                info = channel.receive(buffer, null, handler);
+                if (info == null) {
+                    fail("unexpected null from receive");
+                    return;
+                }
+            } while (!info.isComplete());
+
+            buffer.flip();
+            check(info != null, "info is null");
+            check(info.address() != null, "address is null");
+            check(info.association() != null, "association is null");
+            check(info.isComplete(), "message is not complete");
+            check(info.isUnordered() != true,
+                  "message should not be unordered");
+            check(info.streamNumber() >= 0, "invalid stream number");
+            check(info.bytes() == Util.LARGE_MESSAGE.getBytes("ISO-8859-1").
+                  length, "bytes received not equal to message length");
+            check(info.bytes() == buffer.remaining(), "bytes != remaining");
+            check(Util.compare(buffer, Util.LARGE_MESSAGE),
+                  "received message not the same as sent message");
+
+            buffer.clear();
+
+            /* TEST 4: EOF */
+            buffer.clear();  // buffer position 0
+            info = channel.receive(buffer,null, handler);
+            check(info != null, "info is null");
+            check(info.bytes() == -1, "should have received EOF");
+            check(buffer.position() == 0, "buffer position should be unchanged");
+
+            /* TEST 5: ClosedChannelException */
+            channel.close();
+            try {
+                channel.receive(buffer, null, null);
+                fail("should have thrown ClosedChannelException");
+            } catch (ClosedChannelException cce) {
+               pass();
+            } catch (IOException ioe) {
+                unexpected(ioe);
+            }
+            handler = null;
+
+            /* TEST 6: handler returns RETURN after handling a notification */
+            ReceiveNotificationHandler handler2 =
+                new ReceiveNotificationHandler(null); /* HandlerResult.RETURN */
+            channel = SctpChannel.open(peerAddress, 0, 0);
+            info = channel.receive(buffer, null, handler2);
+            check(info == null, "channel should return null");
+            check(handler2.receivedCommUp(), "SCTP_COMM_UP not received");
+            check(buffer.position() == 0, "buffer position should be unchanged");
+
+            /* TEST 7: Non blocking channel return null if no data */
+            channel.configureBlocking(false);
+            info = channel.receive(buffer, null, null);
+            check(info == null, "non-blocking channel should return null");
+            check(buffer.position() == 0, "buffer position should be unchanged");
+        } catch (IOException ioe) {
+            unexpected(ioe);
+        } finally {
+            clientFinishedLatch.countDown();
+            try { serverFinishedLatch.await(10L, TimeUnit.SECONDS); }
+            catch (InterruptedException ie) { unexpected(ie); }
+            if (channel != null) {
+                try { channel.close(); }
+                catch (IOException e) { unexpected (e);}
+            }
+        }
+    }
+
+    class Server implements Runnable
+    {
+        final InetSocketAddress serverAddr;
+        private SctpServerChannel ssc;
+
+        public Server() throws IOException {
+            ssc = SctpServerChannel.open().bind(null);
+            java.util.Set<SocketAddress> addrs = ssc.getAllLocalAddresses();
+            if (addrs.isEmpty())
+                debug("addrs should not be empty");
+
+            serverAddr = (InetSocketAddress) addrs.iterator().next();
+        }
+
+        public void start() {
+            (new Thread(this, "Server-"  + serverAddr.getPort())).start();
+        }
+
+        public InetSocketAddress address() {
+            return serverAddr;
+        }
+
+        @Override
+        public void run() {
+            try {
+                SctpChannel sc = ssc.accept();
+
+                /* send a small message */
+                MessageInfo info = MessageInfo.createOutgoing(null, 0)
+                        .payloadProtocolID(PPID);
+                ByteBuffer buf = ByteBuffer.allocateDirect(Util.SMALL_BUFFER);
+                buf.put(Util.SMALL_MESSAGE.getBytes("ISO-8859-1"));
+                buf.flip();
+
+                debug("sending small message: " + buf);
+                sc.send(buf, info);
+
+                /* send a large message */
+                buf = ByteBuffer.allocateDirect(Util.LARGE_BUFFER);
+                buf.put(Util.LARGE_MESSAGE.getBytes("ISO-8859-1"));
+                buf.flip();
+
+                debug("sending large message: " + buf);
+                sc.send(buf, info);
+                sc.shutdown();
+                debug("shutdown");
+                ReceiveNotificationHandler handler =
+                    new ReceiveNotificationHandler(sc);
+                sc.receive(buf, null, handler);
+                sc.close();
+
+                /* accept another socket for the TEST 6 */
+                sc = ssc.accept();
+                ssc.close();
+
+                clientFinishedLatch.await(10L, TimeUnit.SECONDS);
+                serverFinishedLatch.countDown();
+                sc.close();
+            } catch (IOException ioe) {
+                unexpected(ioe);
+            } catch (InterruptedException ie) {
+                unexpected(ie);
+            }
+        }
+    }
+
+    class ReceiveNotificationHandler extends AbstractNotificationHandler<Object>
+    {
+        SctpChannel channel;
+        boolean receivedCommUp;  // false
+
+        public ReceiveNotificationHandler(SctpChannel channel) {
+            this.channel = channel;
+        }
+
+        public boolean receivedCommUp() {
+            return receivedCommUp;
+        }
+
+        @Override
+        public HandlerResult handleNotification(
+                Notification notification, Object attachment) {
+            fail("Unknown notification type");
+            return HandlerResult.CONTINUE;
+        }
+
+        @Override
+        public HandlerResult handleNotification(
+                AssociationChangeNotification notification, Object attachment) {
+            AssocChangeEvent event = notification.event();
+            debug("AssociationChangeNotification");
+            debug("  Association: " + notification.association());
+            debug("  Event: " + event);
+
+            if (event.equals(AssocChangeEvent.COMM_UP))
+                receivedCommUp = true;
+
+            if (channel == null)
+                return HandlerResult.RETURN;
+
+            /* TEST 4: IllegalReceiveException - If the given handler invokes
+             * the receive method of this channel*/
+            ByteBuffer buffer = ByteBuffer.allocate(10);
+            try {
+                channel.receive(buffer, null, this);
+                fail("IllegalReceiveException expected");
+            } catch (IllegalReceiveException unused) {
+                pass();
+            } catch (IOException ioe) {
+                unexpected(ioe);
+            }
+
+            return HandlerResult.CONTINUE;
+        }
+
+        @Override
+        public HandlerResult handleNotification(
+                ShutdownNotification notification, Object attachment) {
+            debug("ShutdownNotification");
+            debug("  Association: " + notification.association());
+            return HandlerResult.CONTINUE;
+        }
+    }
+        //--------------------- Infrastructure ---------------------------
+    boolean debug = true;
+    volatile int passed = 0, failed = 0;
+    void pass() {passed++;}
+    void fail() {failed++; Thread.dumpStack();}
+    void fail(String msg) {System.err.println(msg); fail();}
+    void unexpected(Throwable t) {failed++; t.printStackTrace();}
+    void check(boolean cond) {if (cond) pass(); else fail();}
+    void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);}
+    void debug(String message) {if(debug) {
+          System.out.println(Thread.currentThread() + " " + message); } }
+    public static void main(String[] args) throws Throwable {
+        Class<?> k = new Object(){}.getClass().getEnclosingClass();
+        try {k.getMethod("instanceMain",String[].class)
+                .invoke( k.newInstance(), (Object) args);}
+        catch (Throwable e) {throw e.getCause();}}
+    public void instanceMain(String[] args) throws Throwable {
+        try {test(args);} catch (Throwable t) {unexpected(t);}
+        System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
+        if (failed > 0) throw new AssertionError("Some tests failed");}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/nio/sctp/SctpChannel/Send.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,419 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4927640
+ * @summary Tests the SCTP protocol implementation
+ * @author chegar
+ */
+
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.nio.ByteBuffer;
+import java.nio.channels.NotYetConnectedException;
+import java.nio.channels.ClosedChannelException;
+import com.sun.nio.sctp.AbstractNotificationHandler;
+import com.sun.nio.sctp.Association;
+import com.sun.nio.sctp.AssociationChangeNotification;
+import com.sun.nio.sctp.AssociationChangeNotification.AssocChangeEvent;
+import com.sun.nio.sctp.HandlerResult;
+import com.sun.nio.sctp.InvalidStreamException;
+import com.sun.nio.sctp.MessageInfo;
+import com.sun.nio.sctp.Notification;
+import com.sun.nio.sctp.SctpChannel;
+import com.sun.nio.sctp.SctpServerChannel;
+import static java.lang.System.out;
+import static java.lang.System.err;
+
+public class Send {
+    /* Latches used to synchronize between the client and server so that
+     * connections without any IO may not be closed without being accepted */
+    final CountDownLatch clientFinishedLatch = new CountDownLatch(1);
+    final CountDownLatch serverFinishedLatch = new CountDownLatch(1);
+
+    SendNotificationHandler handler = new SendNotificationHandler();
+
+    void test(String[] args) {
+        SocketAddress address = null;
+        Server server = null;
+
+        if (!Util.isSCTPSupported()) {
+            out.println("SCTP protocol is not supported");
+            out.println("Test cannot be run");
+            return;
+        }
+
+        if (args.length == 2) {
+            /* requested to connecct to a specific address */
+            try {
+                int port = Integer.valueOf(args[1]);
+                address = new InetSocketAddress(args[0], port);
+            } catch (NumberFormatException nfe) {
+                err.println(nfe);
+            }
+        } else {
+            /* start server on local machine, default */
+            try {
+                server = new Server();
+                server.start();
+                address = server.address();
+                debug("Server started and listening on " + address);
+            } catch (IOException ioe) {
+                ioe.printStackTrace();
+                return;
+            }
+        }
+
+        doTest(address);
+    }
+
+    void doTest(SocketAddress peerAddress) {
+        SctpChannel channel = null;
+        ByteBuffer buffer = ByteBuffer.allocate(Util.LARGE_BUFFER);
+        MessageInfo info = MessageInfo.createOutgoing(null, 0);
+
+        try {
+            channel = SctpChannel.open();
+
+            /* TEST 1: Verify NotYetConnectedException thrown */
+            try {
+                channel.send(buffer, info);
+                fail("should have thrown NotYetConnectedException");
+            } catch (NotYetConnectedException unused) {
+                pass();
+            }  catch (IOException ioe) {
+                unexpected(ioe);
+            }
+
+            channel.connect(peerAddress);
+            /* Receive CommUp */
+            channel.receive(buffer, null, handler);
+
+            /* save for TEST 8 */
+            Association association = channel.association();
+
+            /* TEST 2: send small message */
+            int streamNumber = 0;
+            debug("sending on stream number: " + streamNumber);
+            info = MessageInfo.createOutgoing(null, streamNumber);
+            buffer.put(Util.SMALL_MESSAGE.getBytes("ISO-8859-1"));
+            buffer.flip();
+            int position = buffer.position();
+            int remaining = buffer.remaining();
+
+            debug("sending small message: " + buffer);
+            int sent = channel.send(buffer, info);
+
+            check(sent == remaining, "sent should be equal to remaining");
+            check(buffer.position() == (position + sent),
+                    "buffers position should have been incremented by sent");
+
+            buffer.clear();
+
+            /* TEST 3: send large message */
+            streamNumber = handler.maxOutStreams() - 1;
+            debug("sending on stream number: " + streamNumber);
+            info = MessageInfo.createOutgoing(null, streamNumber);
+            buffer.put(Util.LARGE_MESSAGE.getBytes("ISO-8859-1"));
+            buffer.flip();
+            position = buffer.position();
+            remaining = buffer.remaining();
+
+            debug("sending large message: " + buffer);
+            sent = channel.send(buffer, info);
+
+            check(sent == remaining, "sent should be equal to remaining");
+            check(buffer.position() == (position + sent),
+                    "buffers position should have been incremented by sent");
+
+            /* TEST 4: InvalidStreamExcepton */
+            streamNumber = handler.maxInStreams;
+            info = MessageInfo.createOutgoing(null, streamNumber);
+            buffer.clear();
+            buffer.put(Util.SMALL_MESSAGE.getBytes("ISO-8859-1"));
+            buffer.flip();
+            position = buffer.position();
+            remaining = buffer.remaining();
+
+            debug("sending on stream number: " + streamNumber);
+            debug("sending small message: " + buffer);
+            try {
+                sent = channel.send(buffer, info);
+                fail("should have thrown InvalidStreamExcepton");
+            } catch (InvalidStreamException ise){
+                pass();
+            } catch (IOException ioe) {
+                unexpected(ioe);
+            }
+            check(buffer.remaining() == remaining,
+                    "remaining should not be changed");
+            check(buffer.position() == position,
+                    "buffers position should not be changed");
+
+            /* TEST 5: Non blocking send should return zero if there is
+               insufficient room in the underlying output buffer */
+            buffer.clear();
+            channel.configureBlocking(false);
+            info = MessageInfo.createOutgoing(null, 1);
+            buffer.put(Util.LARGE_MESSAGE.getBytes("ISO-8859-1"));
+            buffer.flip();
+
+            int count = 0;  // do not loop forever
+            do {
+                position = buffer.position();
+                remaining = buffer.remaining();
+                debug("sending large message: " + buffer);
+                sent = channel.send(buffer, info);
+                if (sent == 0) {
+                    check(buffer.remaining() == remaining,
+                          "remaining should not be changed");
+                    check(buffer.position() == position,
+                          "buffers position should not be changed");
+                }
+                buffer.rewind();
+            } while (sent != 0 && count++ < 100);
+
+            /* TEST 6: ClosedChannelException */
+            channel.close();
+            try {
+                channel.send(buffer, info);
+                fail("should have thrown ClosedChannelException");
+            } catch (ClosedChannelException cce) {
+               pass();
+            } catch (IOException ioe) {
+                unexpected(ioe);
+            }
+
+            /* TEST 7: send without previous receive.
+             * Verify that send can still throw InvalidStreamExcepton */
+            debug("Opening new channel.");
+            channel = SctpChannel.open(peerAddress, 0, 0);
+            streamNumber = Short.MAX_VALUE - 1;
+            info = MessageInfo.createOutgoing(null, streamNumber);
+            buffer.clear();
+            buffer.put(Util.SMALL_MESSAGE.getBytes("ISO-8859-1"));
+            buffer.flip();
+            position = buffer.position();
+            remaining = buffer.remaining();
+
+            debug("sending on stream number: " + streamNumber);
+            debug("sending small message: " + buffer);
+            try {
+                sent = channel.send(buffer, info);
+                fail("should have thrown InvalidStreamExcepton");
+            } catch (InvalidStreamException ise){
+                pass();
+            } catch (IOException ioe) {
+                unexpected(ioe);
+            }
+            check(buffer.remaining() == remaining,
+                    "remaining should not be changed");
+            check(buffer.position() == position,
+                    "buffers position should not be changed");
+
+            /* Receive CommUp */
+            channel.receive(buffer, null, handler);
+            check(handler.receivedCommUp(), "should have received COMM_UP");
+
+            /* TEST 8: Send to an invalid preferred SocketAddress */
+            SocketAddress addr = new InetSocketAddress("123.123.123.123", 3456);
+            info = MessageInfo.createOutgoing(addr, 0);
+            debug("sending to " + addr);
+            debug("sending small message: " + buffer);
+            try {
+                sent = channel.send(buffer, info);
+                fail("Invalid address should have thrown an Exception.");
+            } catch (Exception e){
+                pass();
+                debug("OK, caught " + e);
+            }
+        } catch (IOException ioe) {
+            unexpected(ioe);
+        } finally {
+            clientFinishedLatch.countDown();
+            try { serverFinishedLatch.await(10L, TimeUnit.SECONDS); }
+            catch (InterruptedException ie) { unexpected(ie); }
+            if (channel != null) {
+                try { channel.close(); }
+                catch (IOException e) { unexpected (e);}
+            }
+        }
+    }
+
+    class Server implements Runnable
+    {
+        final InetSocketAddress serverAddr;
+        private SctpServerChannel ssc;
+
+        public Server() throws IOException {
+            ssc = SctpServerChannel.open().bind(null);
+            java.util.Set<SocketAddress> addrs = ssc.getAllLocalAddresses();
+            if (addrs.isEmpty())
+                debug("addrs should not be empty");
+
+            serverAddr = (InetSocketAddress) addrs.iterator().next();
+        }
+
+        public void start() {
+            (new Thread(this, "Server-"  + serverAddr.getPort())).start();
+        }
+
+        public InetSocketAddress address() {
+            return serverAddr;
+        }
+
+        @Override
+        public void run() {
+            ByteBuffer buffer = ByteBuffer.allocateDirect(Util.LARGE_BUFFER);
+            SctpChannel sc1 = null, sc2 = null;
+            try {
+                sc1 = ssc.accept();
+
+                /* receive a small message */
+                MessageInfo info;
+                do {
+                    info = sc1.receive(buffer, null, null);
+                    if (info == null) {
+                        fail("Server: unexpected null from receive");
+                            return;
+                    }
+                } while (!info.isComplete());
+
+                buffer.flip();
+                check(info != null, "info is null");
+                check(info.streamNumber() == 0,
+                        "message not sent on the correct stream");
+                check(info.bytes() == Util.SMALL_MESSAGE.getBytes("ISO-8859-1").
+                      length, "bytes received not equal to message length");
+                check(info.bytes() == buffer.remaining(), "bytes != remaining");
+                check(Util.compare(buffer, Util.SMALL_MESSAGE),
+                  "received message not the same as sent message");
+
+                /* receive a large message */
+                buffer.clear();
+                do {
+                    info = sc1.receive(buffer, null, null);
+                    if (info == null) {
+                        fail("Server: unexpected null from receive");
+                            return;
+                    }
+                } while (!info.isComplete());
+
+                buffer.flip();
+                check(info != null, "info is null");
+                check(info.streamNumber() == handler.maxOutStreams() - 1,
+                        "message not sent on the correct stream");
+                check(info.bytes() == Util.LARGE_MESSAGE.getBytes("ISO-8859-1").
+                      length, "bytes received not equal to message length");
+                check(info.bytes() == buffer.remaining(), "bytes != remaining");
+                check(Util.compare(buffer, Util.LARGE_MESSAGE),
+                  "received message not the same as sent message");
+
+                /* TEST 7 ++ */
+                sc2 = ssc.accept();
+
+                clientFinishedLatch.await(10L, TimeUnit.SECONDS);
+                serverFinishedLatch.countDown();
+            } catch (IOException ioe) {
+                unexpected(ioe);
+            } catch (InterruptedException ie) {
+                unexpected(ie);
+            } finally {
+                try { if (ssc != null) ssc.close(); }
+                catch (IOException  unused) {}
+                try { if (sc1 != null) sc1.close(); }
+                catch (IOException  unused) {}
+                try { if (sc2 != null) sc2.close(); }
+                catch (IOException  unused) {}
+            }
+        }
+    }
+
+    class SendNotificationHandler extends AbstractNotificationHandler<Void>
+    {
+        boolean receivedCommUp;  // false
+        int maxInStreams;
+        int maxOutStreams;
+
+        public boolean receivedCommUp() {
+            return receivedCommUp;
+        }
+
+        public int maxInStreams() {
+            return maxInStreams;
+        }
+
+        public int maxOutStreams(){
+            return maxOutStreams;
+        }
+
+        @Override
+        public HandlerResult handleNotification(
+                Notification notification, Void attachment) {
+            fail("Unknown notification type");
+            return HandlerResult.CONTINUE;
+        }
+
+        @Override
+        public HandlerResult handleNotification(
+                AssociationChangeNotification notification, Void attachment) {
+            AssocChangeEvent event = notification.event();
+            Association association = notification.association();
+            debug("AssociationChangeNotification");
+            debug("  Association: " + notification.association());
+            debug("  Event: " + event);
+
+            if (event.equals(AssocChangeEvent.COMM_UP))
+                receivedCommUp = true;
+
+            this.maxInStreams = association.maxInboundStreams();
+            this.maxOutStreams = association.maxOutboundStreams();
+
+            return HandlerResult.RETURN;
+        }
+    }
+
+        //--------------------- Infrastructure ---------------------------
+    boolean debug = true;
+    volatile int passed = 0, failed = 0;
+    void pass() {passed++;}
+    void fail() {failed++; Thread.dumpStack();}
+    void fail(String msg) {System.err.println(msg); fail();}
+    void unexpected(Throwable t) {failed++; t.printStackTrace();}
+    void check(boolean cond) {if (cond) pass(); else fail();}
+    void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);}
+    void debug(String message) {if(debug) { System.out.println(message); }  }
+    public static void main(String[] args) throws Throwable {
+        Class<?> k = new Object(){}.getClass().getEnclosingClass();
+        try {k.getMethod("instanceMain",String[].class)
+                .invoke( k.newInstance(), (Object) args);}
+        catch (Throwable e) {throw e.getCause();}}
+    public void instanceMain(String[] args) throws Throwable {
+        try {test(args);} catch (Throwable t) {unexpected(t);}
+        System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
+        if (failed > 0) throw new AssertionError("Some tests failed");}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/nio/sctp/SctpChannel/Shutdown.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,274 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4927640
+ * @summary Tests the SCTP protocol implementation
+ * @author chegar
+ */
+
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+import java.nio.ByteBuffer;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.NotYetConnectedException;
+import com.sun.nio.sctp.AbstractNotificationHandler;
+import com.sun.nio.sctp.HandlerResult;
+import com.sun.nio.sctp.MessageInfo;
+import com.sun.nio.sctp.SctpChannel;
+import com.sun.nio.sctp.SctpServerChannel;
+import com.sun.nio.sctp.ShutdownNotification;
+import static java.lang.System.out;
+import static java.lang.System.err;
+
+public class Shutdown {
+    static CountDownLatch finishedLatch = new CountDownLatch(1);
+    static CountDownLatch sentLatch = new CountDownLatch(1);
+
+    void test(String[] args) {
+        SocketAddress address = null;
+        ShutdownServer server = null;
+
+        if (!Util.isSCTPSupported()) {
+            out.println("SCTP protocol is not supported");
+            out.println("Test cannot be run");
+            return;
+        }
+
+        if (args.length == 2) {
+            /* requested to connecct to a specific address */
+            try {
+                int port = Integer.valueOf(args[1]);
+                address = new InetSocketAddress(args[0], port);
+            } catch (NumberFormatException nfe) {
+                err.println(nfe);
+            }
+        } else {
+            /* start server on local machine, default */
+            try {
+                server = new ShutdownServer();
+                server.start();
+                address = server.address();
+                debug("Server started and listening on " + address);
+            } catch (IOException ioe) {
+                ioe.printStackTrace();
+                return;
+            }
+        }
+
+        doTest(address);
+    }
+
+    void doTest(SocketAddress peerAddress) {
+        SctpChannel channel = null;
+        ByteBuffer buffer = ByteBuffer.allocate(Util.SMALL_BUFFER);
+        MessageInfo info;
+
+        try {
+            channel = SctpChannel.open();
+
+            /* TEST 1: Verify NotYetConnectedException thrown */
+            debug("Test 1: NotYetConnectedException");
+            try {
+                channel.shutdown();
+                fail("shutdown not throwing expected NotYetConnectedException");
+            } catch (NotYetConnectedException unused) {
+                pass();
+            }  catch (IOException ioe) {
+                unexpected(ioe);
+            }
+
+            channel.connect(peerAddress);
+            sentLatch.await();
+            channel.shutdown();
+
+            /* TEST 2: receive data sent before shutdown */
+            do {
+                debug("Test 2: invoking receive");
+                info = channel.receive(buffer, null, null);
+                if (info == null) {
+                    fail("unexpected null from receive");
+                    return;
+                }
+            } while (!info.isComplete());
+
+            buffer.flip();
+            check(info != null, "info is null");
+            check(info.bytes() == Util.SMALL_MESSAGE.getBytes("ISO-8859-1").
+                  length, "bytes received not equal to message length");
+            check(info.bytes() == buffer.remaining(), "bytes != remaining");
+            check(Util.compare(buffer, Util.SMALL_MESSAGE),
+                  "received message not the same as sent message");
+
+            buffer.clear();
+
+            /* TEST 3: receive notifications on the SCTP stack */
+            debug("Test 3: receive notifications");
+            while ((info = channel.receive(buffer, null, null )) != null &&
+                    info.bytes() != -1 );
+
+
+            /* TEST 4: If the channel is already shutdown then invoking this
+             * method has no effect. */
+            debug("Test 4: no-op");
+            try {
+                channel.shutdown();
+                pass();
+            } catch (IOException ioe) {
+                unexpected(ioe);
+            }
+
+            /* TEST 5: Further sends will throw ClosedChannelException */
+            debug("Test 5: ClosedChannelException");
+            info = MessageInfo.createOutgoing(null, 1);
+            try {
+                channel.send(buffer, info);
+                fail("shutdown not throwing expected ClosedChannelException");
+            } catch (ClosedChannelException unused) {
+                pass();
+            } catch (IOException ioe) {
+                unexpected(ioe);
+            }
+        } catch (IOException ioe) {
+            unexpected(ioe);
+        } catch (InterruptedException ie) {
+            unexpected(ie);
+        }finally {
+            finishedLatch.countDown();
+            try { if (channel != null) channel.close(); }
+            catch (IOException e) { unexpected(e);}
+        }
+    }
+
+    class ShutdownServer implements Runnable
+    {
+        final InetSocketAddress serverAddr;
+        private SctpServerChannel ssc;
+
+        public ShutdownServer() throws IOException {
+            ssc = SctpServerChannel.open().bind(null);
+            //serverAddr = (InetSocketAddress)(ssc.getAllLocalAddresses().iterator().next());
+
+            java.util.Set<SocketAddress> addrs = ssc.getAllLocalAddresses();
+            if (addrs.isEmpty())
+                debug("addrs should not be empty");
+
+            serverAddr = (InetSocketAddress) addrs.iterator().next();
+
+        }
+
+        public void start() {
+            (new Thread(this, "ShutdownServer-"  + serverAddr.getPort())).start();
+        }
+
+        public InetSocketAddress address() {
+            return serverAddr;
+        }
+
+        @Override
+        public void run() {
+            SctpChannel sc = null;
+            try {
+                sc = ssc.accept();
+
+                /* send a message */
+                MessageInfo info = MessageInfo.createOutgoing(null, 1);
+                ByteBuffer buf = ByteBuffer.allocateDirect(Util.SMALL_BUFFER);
+                buf.put(Util.SMALL_MESSAGE.getBytes("ISO-8859-1"));
+                buf.flip();
+                sc.send(buf, info);
+
+                /* notify client that the data has been sent */
+                sentLatch.countDown();
+
+                /* wait until after the client has finished its tests */
+                finishedLatch.await();
+
+                buf.clear();
+                ShutdownNotificationHandler handler =
+                        new ShutdownNotificationHandler();
+                BooleanWrapper bool = new BooleanWrapper();
+                sc.configureBlocking(false);
+                sc.receive(buf, bool, handler);
+                check(bool.booleanValue(), "SHUTDOWN not received on Server");
+
+            } catch (IOException ioe) {
+                ioe.printStackTrace();
+            } catch (InterruptedException ie) {
+                ie.printStackTrace();
+            } finally {
+                try { if (ssc != null) ssc.close(); }
+                catch (IOException  ioe) { unexpected(ioe); }
+                try { if (sc != null) sc.close(); }
+                catch (IOException  ioe) { unexpected(ioe); }
+            }
+        }
+    }
+
+    class BooleanWrapper {
+        boolean bool;
+
+        boolean booleanValue() {
+            return bool;
+        }
+
+        void booleanValue(boolean value) {
+            bool = value;
+        }
+    }
+
+    class ShutdownNotificationHandler extends AbstractNotificationHandler<BooleanWrapper>
+    {
+        @Override
+        public HandlerResult handleNotification(
+                ShutdownNotification sn, BooleanWrapper bool)
+        {
+            bool.booleanValue(true);
+            debug(sn.toString());
+            return HandlerResult.RETURN;
+        }
+    }
+
+        //--------------------- Infrastructure ---------------------------
+    boolean debug = true;
+    volatile int passed = 0, failed = 0;
+    void pass() {passed++;}
+    void fail() {failed++; Thread.dumpStack();}
+    void fail(String msg) {System.err.println(msg); fail();}
+    void unexpected(Throwable t) {failed++; t.printStackTrace();}
+    void check(boolean cond) {if (cond) pass(); else fail();}
+    void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);}
+    void debug(String message) {if(debug) { System.out.println(message); }  }
+    public static void main(String[] args) throws Throwable {
+        Class<?> k = new Object(){}.getClass().getEnclosingClass();
+        try {k.getMethod("instanceMain",String[].class)
+                .invoke( k.newInstance(), (Object) args);}
+        catch (Throwable e) {throw e.getCause();}}
+    public void instanceMain(String[] args) throws Throwable {
+        try {test(args);} catch (Throwable t) {unexpected(t);}
+        System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
+        if (failed > 0) throw new AssertionError("Some tests failed");}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/nio/sctp/SctpChannel/SocketOptionTests.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4927640
+ * @summary Tests the SCTP protocol implementation
+ * @author chegar
+ */
+
+import java.io.IOException;
+import java.util.Set;
+import java.util.List;
+import java.util.Arrays;
+import java.nio.channels.ClosedChannelException;
+import com.sun.nio.sctp.SctpChannel;
+import com.sun.nio.sctp.SctpSocketOption;
+import static com.sun.nio.sctp.SctpStandardSocketOption.*;
+import static java.lang.System.out;
+
+public class SocketOptionTests {
+    <T> void checkOption(SctpChannel sc, SctpSocketOption<T> name,
+            T expectedValue) throws IOException {
+        T value = sc.getOption(name);
+        check(value.equals(expectedValue), name + ": value (" + value +
+                ") not as expected (" + expectedValue + ")");
+       }
+
+    <T> void optionalSupport(SctpChannel sc, SctpSocketOption<T> name,
+            T value) {
+        try {
+            sc.setOption(name, value);
+            checkOption(sc, name, value);
+        } catch (IOException e) {
+            /* Informational only, not all options have native support */
+            out.println(name + " not supported. " + e);
+        }
+    }
+
+    void test(String[] args) {
+        if (!Util.isSCTPSupported()) {
+            out.println("SCTP protocol is not supported");
+            out.println("Test cannot be run");
+            return;
+        }
+
+        try {
+            SctpChannel sc = SctpChannel.open();
+
+            /* check supported options */
+            Set<SctpSocketOption<?>> options = sc.supportedOptions();
+            List<? extends SctpSocketOption<?>> expected = Arrays.<SctpSocketOption<?>>asList(
+                    SCTP_DISABLE_FRAGMENTS, SCTP_EXPLICIT_COMPLETE,
+                    SCTP_FRAGMENT_INTERLEAVE, SCTP_INIT_MAXSTREAMS,
+                    SCTP_NODELAY, SCTP_PRIMARY_ADDR, SCTP_SET_PEER_PRIMARY_ADDR,
+                    SO_SNDBUF, SO_RCVBUF, SO_LINGER);
+
+            for (SctpSocketOption opt: expected) {
+                if (!options.contains(opt))
+                    fail(opt.name() + " should be supported");
+            }
+
+            InitMaxStreams streams = InitMaxStreams.create(1024, 1024);
+            sc.setOption(SCTP_INIT_MAXSTREAMS, streams);
+            checkOption(sc, SCTP_INIT_MAXSTREAMS, streams);
+            streams = sc.getOption(SCTP_INIT_MAXSTREAMS);
+            check(streams.maxInStreams() == 1024, "Max in streams: value: "
+                    + streams.maxInStreams() + ", expected 1024 ");
+            check(streams.maxOutStreams() == 1024, "Max out streams: value: "
+                    + streams.maxOutStreams() + ", expected 1024 ");
+
+            optionalSupport(sc, SCTP_DISABLE_FRAGMENTS, true);
+            optionalSupport(sc, SCTP_EXPLICIT_COMPLETE, true);
+            optionalSupport(sc, SCTP_FRAGMENT_INTERLEAVE, 1);
+
+
+            //TODO: SCTP_PRIMARY_ADDR
+            //sc.bind(null);
+            //connect
+            //InetSocketAddress addr = new InetSocketAddress(0);
+            //sc.setOption(SCTP_PRIMARY_ADDR, addr);
+
+            sc.setOption(SCTP_NODELAY, true);
+            checkOption(sc, SCTP_NODELAY, true);
+            sc.setOption(SO_SNDBUF, 16*1024);
+            sc.setOption(SO_RCVBUF, 16*1024);
+            checkOption(sc, SO_LINGER, -1);  /* default should be negative */
+            sc.setOption(SO_LINGER, 2000);
+            checkOption(sc, SO_LINGER, 2000);
+
+
+            /* NullPointerException */
+            try {
+                sc.setOption(null, "value");
+                fail("NullPointerException not thrown for setOption");
+            } catch (NullPointerException unused) {
+                pass();
+            }
+            try {
+               sc.getOption(null);
+               fail("NullPointerException not thrown for getOption");
+            } catch (NullPointerException unused) {
+               pass();
+            }
+
+            /* ClosedChannelException */
+            sc.close();
+            try {
+               sc.setOption(SCTP_INIT_MAXSTREAMS, streams);
+               fail("ClosedChannelException not thrown");
+            } catch (ClosedChannelException unused) {
+                pass();
+            }
+        } catch (IOException ioe) {
+            unexpected(ioe);
+        }
+    }
+
+            //--------------------- Infrastructure ---------------------------
+    boolean debug = true;
+    volatile int passed = 0, failed = 0;
+    void pass() {passed++;}
+    void fail() {failed++; Thread.dumpStack();}
+    void fail(String msg) {System.err.println(msg); fail();}
+    void unexpected(Throwable t) {failed++; t.printStackTrace();}
+    void check(boolean cond) {if (cond) pass(); else fail();}
+    void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);}
+    void debug(String message) {if(debug) { System.out.println(message); }  }
+    public static void main(String[] args) throws Throwable {
+        Class<?> k = new Object(){}.getClass().getEnclosingClass();
+        try {k.getMethod("instanceMain",String[].class)
+                .invoke( k.newInstance(), (Object) args);}
+        catch (Throwable e) {throw e.getCause();}}
+    public void instanceMain(String[] args) throws Throwable {
+        try {test(args);} catch (Throwable t) {unexpected(t);}
+        System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
+        if (failed > 0) throw new AssertionError("Some tests failed");}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/nio/sctp/SctpChannel/Util.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.net.NetworkInterface;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.net.InetAddress;
+import java.net.Inet4Address;
+import java.net.SocketException;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Set;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.nio.ByteBuffer;
+import com.sun.nio.sctp.SctpChannel;
+import static java.lang.System.out;
+
+public class Util {
+    static final int SMALL_BUFFER = 128;
+    static final String SMALL_MESSAGE =
+      "Under the bridge and over the dam, looking for berries, berries for jam";
+
+    static final int LARGE_BUFFER = 32768;
+    static final String LARGE_MESSAGE;
+
+    static {
+        StringBuffer sb = new StringBuffer(LARGE_BUFFER);
+        for (int i=0; i<460; i++)
+          sb.append(SMALL_MESSAGE);
+
+        LARGE_MESSAGE = sb.toString();
+    }
+
+    static boolean isSCTPSupported() {
+        try {
+            SctpChannel c = SctpChannel.open();
+            c.close();
+            return true;
+        } catch (IOException ioe) {
+            ioe.printStackTrace();
+        } catch (UnsupportedOperationException e) {
+            out.println(e);
+        }
+
+        return false;
+    }
+    /**
+     * Returns a list of all the addresses on the system.
+     * @param  inclLoopback
+     *         if {@code true}, include the loopback addresses
+     * @param  ipv4Only
+     *         it {@code true}, only IPv4 addresses will be included
+     */
+    static List<InetAddress> getAddresses(boolean inclLoopback,
+                                          boolean ipv4Only)
+        throws SocketException {
+        ArrayList<InetAddress> list = new ArrayList<InetAddress>();
+        Enumeration<NetworkInterface> nets =
+                 NetworkInterface.getNetworkInterfaces();
+        for (NetworkInterface netInf : Collections.list(nets)) {
+            Enumeration<InetAddress> addrs = netInf.getInetAddresses();
+            for (InetAddress addr : Collections.list(addrs)) {
+                if (!list.contains(addr) &&
+                        (inclLoopback ? true : !addr.isLoopbackAddress()) &&
+                        (ipv4Only ? (addr instanceof Inet4Address) : true)) {
+                    list.add(addr);
+                }
+            }
+        }
+
+        return list;
+    }
+
+    static void dumpAddresses(SctpChannel channel,
+                              PrintStream printStream)
+        throws IOException {
+        Set<SocketAddress> addrs = channel.getAllLocalAddresses();
+        printStream.println("Local Addresses: ");
+        for (Iterator<SocketAddress> it = addrs.iterator(); it.hasNext(); ) {
+            InetSocketAddress addr = (InetSocketAddress)it.next();
+            printStream.println("\t" + addr);
+        }
+    }
+
+    /**
+     * Compare the contents of the given ByteBuffer with the contens of the
+     * given byte array. true if, and only if, the contents are the same.
+     */
+    static boolean compare(ByteBuffer bb, byte[] message) {
+        if (message.length != bb.remaining()) {
+            out.println("Compare failed, byte array length != to buffer remaining");
+            return false;
+        }
+
+        for (int i=0; i<message.length; i++) {
+            byte b = bb.get();
+            if (message[i] != b) {
+                out.println("Position " + i + ": " + message[i] + " != " + b);
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    static boolean compare(ByteBuffer bb, String str) {
+        try{
+            return Util.compare(bb, str.getBytes("ISO-8859-1"));
+        } catch (UnsupportedEncodingException unsupported) {
+            throw new AssertionError(unsupported);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/nio/sctp/SctpMultiChannel/Send.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,320 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4927640
+ * @summary Tests the SCTP protocol implementation
+ * @author chegar
+ */
+
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.io.IOException;
+import java.util.Set;
+import java.util.Iterator;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.nio.ByteBuffer;
+import com.sun.nio.sctp.Association;
+import com.sun.nio.sctp.InvalidStreamException;
+import com.sun.nio.sctp.MessageInfo;
+import com.sun.nio.sctp.SctpMultiChannel;
+import static java.lang.System.out;
+import static java.lang.System.err;
+
+public class Send {
+    /* Latches used to synchronize between the client and server so that
+     * connections without any IO may not be closed without being accepted */
+    final CountDownLatch clientFinishedLatch = new CountDownLatch(1);
+    final CountDownLatch serverFinishedLatch = new CountDownLatch(1);
+
+    void test(String[] args) {
+        SocketAddress address = null;
+        Server server = null;
+
+        if (!Util.isSCTPSupported()) {
+            out.println("SCTP protocol is not supported");
+            out.println("Test cannot be run");
+            return;
+        }
+
+        if (args.length == 2) {
+            /* requested to connecct to a specific address */
+            try {
+                int port = Integer.valueOf(args[1]);
+                address = new InetSocketAddress(args[0], port);
+            } catch (NumberFormatException nfe) {
+                err.println(nfe);
+            }
+        } else {
+            /* start server on local machine, default */
+            try {
+                server = new Server();
+                server.start();
+                address = server.address();
+                debug("Server started and listening on " + address);
+            } catch (IOException ioe) {
+                ioe.printStackTrace();
+                return;
+            }
+        }
+
+        doTest(address);
+    }
+
+    void doTest(SocketAddress peerAddress) {
+        SctpMultiChannel channel = null;
+        ByteBuffer buffer = ByteBuffer.allocate(Util.LARGE_BUFFER);
+        MessageInfo info = MessageInfo.createOutgoing(null, 0);
+
+        try {
+            channel = SctpMultiChannel.open();
+
+            /* TEST 1: send small message */
+            int streamNumber = 0;
+            debug("sending to " + peerAddress + " on stream number: " + streamNumber);
+            info = MessageInfo.createOutgoing(peerAddress, streamNumber);
+            buffer.put(Util.SMALL_MESSAGE.getBytes("ISO-8859-1"));
+            buffer.flip();
+            int position = buffer.position();
+            int remaining = buffer.remaining();
+
+            debug("sending small message: " + buffer);
+            int sent = channel.send(buffer, info);
+
+            check(sent == remaining, "sent should be equal to remaining");
+            check(buffer.position() == (position + sent),
+                    "buffers position should have been incremented by sent");
+
+            /* TEST 2: receive the echoed message */
+            buffer.clear();
+            info = channel.receive(buffer, null, null);
+            buffer.flip();
+            check(info != null, "info is null");
+            check(info.streamNumber() == streamNumber,
+                    "message not sent on the correct stream");
+            check(info.bytes() == Util.SMALL_MESSAGE.getBytes("ISO-8859-1").
+                  length, "bytes received not equal to message length");
+            check(info.bytes() == buffer.remaining(), "bytes != remaining");
+            check(Util.compare(buffer, Util.SMALL_MESSAGE),
+              "received message not the same as sent message");
+
+
+            /* TEST 3: send large message */
+            Set<Association> assocs = channel.associations();
+            check(assocs.size() == 1, "there should be only one association");
+            Iterator<Association> it = assocs.iterator();
+            check(it.hasNext());
+            Association assoc = it.next();
+            streamNumber = assoc.maxOutboundStreams() - 1;
+
+            debug("sending on stream number: " + streamNumber);
+            info = MessageInfo.createOutgoing(assoc, null, streamNumber);
+            buffer.clear();
+            buffer.put(Util.LARGE_MESSAGE.getBytes("ISO-8859-1"));
+            buffer.flip();
+            position = buffer.position();
+            remaining = buffer.remaining();
+
+            debug("sending large message: " + buffer);
+            sent = channel.send(buffer, info);
+
+            check(sent == remaining, "sent should be equal to remaining");
+            check(buffer.position() == (position + sent),
+                    "buffers position should have been incremented by sent");
+
+            /* TEST 4: receive the echoed message */
+            buffer.clear();
+            info = channel.receive(buffer, null, null);
+            buffer.flip();
+            check(info != null, "info is null");
+            check(info.streamNumber() == streamNumber,
+                    "message not sent on the correct stream");
+            check(info.bytes() == Util.LARGE_MESSAGE.getBytes("ISO-8859-1").
+                  length, "bytes received not equal to message length");
+            check(info.bytes() == buffer.remaining(), "bytes != remaining");
+            check(Util.compare(buffer, Util.LARGE_MESSAGE),
+              "received message not the same as sent message");
+
+
+            /* TEST 5: InvalidStreamExcepton */
+            streamNumber = assoc.maxOutboundStreams() + 1;
+            info = MessageInfo.createOutgoing(assoc, null, streamNumber);
+            buffer.clear();
+            buffer.put(Util.SMALL_MESSAGE.getBytes("ISO-8859-1"));
+            buffer.flip();
+            position = buffer.position();
+            remaining = buffer.remaining();
+
+            debug("sending on stream number: " + streamNumber);
+            debug("sending small message: " + buffer);
+            try {
+                sent = channel.send(buffer, info);
+                fail("should have thrown InvalidStreamExcepton");
+            } catch (InvalidStreamException ise){
+                pass();
+            } catch (IOException ioe) {
+                unexpected(ioe);
+            }
+            check(buffer.remaining() == remaining,
+                    "remaining should not be changed");
+            check(buffer.position() == position,
+                    "buffers position should not be changed");
+
+
+            /* TEST 5: getRemoteAddresses(Association) */
+            channel.getRemoteAddresses(assoc);
+
+        } catch (IOException ioe) {
+            unexpected(ioe);
+        } finally {
+            clientFinishedLatch.countDown();
+            try { serverFinishedLatch.await(10L, TimeUnit.SECONDS); }
+            catch (InterruptedException ie) { unexpected(ie); }
+            if (channel != null) {
+                try { channel.close(); }
+                catch (IOException e) { unexpected (e);}
+            }
+        }
+    }
+
+    class Server implements Runnable
+    {
+        final InetSocketAddress serverAddr;
+        private SctpMultiChannel serverChannel;
+
+        public Server() throws IOException {
+            serverChannel = SctpMultiChannel.open().bind(null);
+            java.util.Set<SocketAddress> addrs = serverChannel.getAllLocalAddresses();
+            if (addrs.isEmpty())
+                debug("addrs should not be empty");
+
+            serverAddr = (InetSocketAddress) addrs.iterator().next();
+        }
+
+        public void start() {
+            (new Thread(this, "Server-"  + serverAddr.getPort())).start();
+        }
+
+        public InetSocketAddress address() {
+            return serverAddr;
+        }
+
+        @Override
+        public void run() {
+            ByteBuffer buffer = ByteBuffer.allocateDirect(Util.LARGE_BUFFER);
+            try {
+                MessageInfo info;
+
+                /* receive a small message */
+                do {
+                    info = serverChannel.receive(buffer, null, null);
+                    if (info == null) {
+                        fail("Server: unexpected null from receive");
+                            return;
+                    }
+                } while (!info.isComplete());
+
+                buffer.flip();
+                check(info != null, "info is null");
+                check(info.streamNumber() == 0,
+                        "message not sent on the correct stream");
+                check(info.bytes() == Util.SMALL_MESSAGE.getBytes("ISO-8859-1").
+                      length, "bytes received not equal to message length");
+                check(info.bytes() == buffer.remaining(), "bytes != remaining");
+                check(Util.compare(buffer, Util.SMALL_MESSAGE),
+                  "received message not the same as sent message");
+
+                check(info != null, "info is null");
+                Set<Association> assocs = serverChannel.associations();
+                check(assocs.size() == 1, "there should be only one association");
+                Iterator<Association> it = assocs.iterator();
+                check(it.hasNext());
+                Association assoc = it.next();
+
+                /* echo the message */
+                debug("Server: echoing first message");
+                buffer.flip();
+                int bytes = serverChannel.send(buffer, info);
+                debug("Server: sent " + bytes + "bytes");
+
+                /* receive a large message */
+                buffer.clear();
+                do {
+                    info = serverChannel.receive(buffer, null, null);
+                    if (info == null) {
+                        fail("Server: unexpected null from receive");
+                            return;
+                    }
+                } while (!info.isComplete());
+
+                buffer.flip();
+
+                check(info.streamNumber() == assoc.maxInboundStreams() - 1,
+                        "message not sent on the correct stream");
+                check(info.bytes() == Util.LARGE_MESSAGE.getBytes("ISO-8859-1").
+                      length, "bytes received not equal to message length");
+                check(info.bytes() == buffer.remaining(), "bytes != remaining");
+                check(Util.compare(buffer, Util.LARGE_MESSAGE),
+                  "received message not the same as sent message");
+
+                /* echo the message */
+                debug("Server: echoing second message");
+                buffer.flip();
+                bytes = serverChannel.send(buffer, info);
+                debug("Server: sent " + bytes + "bytes");
+
+                clientFinishedLatch.await(10L, TimeUnit.SECONDS);
+                serverFinishedLatch.countDown();
+            } catch (IOException ioe) {
+                unexpected(ioe);
+            } catch (InterruptedException ie) {
+                unexpected(ie);
+            } finally {
+                try { if (serverChannel != null) serverChannel.close(); }
+                catch (IOException  unused) {}
+            }
+        }
+    }
+
+        //--------------------- Infrastructure ---------------------------
+    boolean debug = true;
+    volatile int passed = 0, failed = 0;
+    void pass() {passed++;}
+    void fail() {failed++; Thread.dumpStack();}
+    void fail(String msg) {System.err.println(msg); fail();}
+    void unexpected(Throwable t) {failed++; t.printStackTrace();}
+    void check(boolean cond) {if (cond) pass(); else fail();}
+    void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);}
+    void debug(String message) {if(debug) { System.out.println(message); }  }
+    public static void main(String[] args) throws Throwable {
+        Class<?> k = new Object(){}.getClass().getEnclosingClass();
+        try {k.getMethod("instanceMain",String[].class)
+                .invoke( k.newInstance(), (Object) args);}
+        catch (Throwable e) {throw e.getCause();}}
+    public void instanceMain(String[] args) throws Throwable {
+        try {test(args);} catch (Throwable t) {unexpected(t);}
+        System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
+        if (failed > 0) throw new AssertionError("Some tests failed");}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/nio/sctp/SctpMultiChannel/Util.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.net.NetworkInterface;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.net.InetAddress;
+import java.net.Inet4Address;
+import java.net.SocketException;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Set;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.nio.ByteBuffer;
+import com.sun.nio.sctp.SctpChannel;
+import static java.lang.System.out;
+
+public class Util {
+    static final int SMALL_BUFFER = 128;
+    static final String SMALL_MESSAGE =
+      "Under the bridge and over the dam, looking for berries, berries for jam";
+
+    static final int LARGE_BUFFER = 32768;
+    static final String LARGE_MESSAGE;
+
+    static {
+        StringBuffer sb = new StringBuffer(LARGE_BUFFER);
+        for (int i=0; i<460; i++)
+          sb.append(SMALL_MESSAGE);
+
+        LARGE_MESSAGE = sb.toString();
+    }
+
+    static boolean isSCTPSupported() {
+        try {
+            SctpChannel c = SctpChannel.open();
+            c.close();
+            return true;
+        } catch (IOException ioe) {
+            ioe.printStackTrace();
+        } catch (UnsupportedOperationException e) {
+            out.println(e);
+        }
+
+        return false;
+    }
+    /**
+     * Returns a list of all the addresses on the system.
+     * @param  inclLoopback
+     *         if {@code true}, include the loopback addresses
+     * @param  ipv4Only
+     *         it {@code true}, only IPv4 addresses will be included
+     */
+    static List<InetAddress> getAddresses(boolean inclLoopback,
+                                          boolean ipv4Only)
+        throws SocketException {
+        ArrayList<InetAddress> list = new ArrayList<InetAddress>();
+        Enumeration<NetworkInterface> nets =
+                 NetworkInterface.getNetworkInterfaces();
+        for (NetworkInterface netInf : Collections.list(nets)) {
+            Enumeration<InetAddress> addrs = netInf.getInetAddresses();
+            for (InetAddress addr : Collections.list(addrs)) {
+                if (!list.contains(addr) &&
+                        (inclLoopback ? true : !addr.isLoopbackAddress()) &&
+                        (ipv4Only ? (addr instanceof Inet4Address) : true)) {
+                    list.add(addr);
+                }
+            }
+        }
+
+        return list;
+    }
+
+    static void dumpAddresses(SctpChannel channel,
+                              PrintStream printStream)
+        throws IOException {
+        Set<SocketAddress> addrs = channel.getAllLocalAddresses();
+        printStream.println("Local Addresses: ");
+        for (Iterator<SocketAddress> it = addrs.iterator(); it.hasNext(); ) {
+            InetSocketAddress addr = (InetSocketAddress)it.next();
+            printStream.println("\t" + addr);
+        }
+    }
+
+    /**
+     * Compare the contents of the given ByteBuffer with the contens of the
+     * given byte array. true if, and only if, the contents are the same.
+     */
+    static boolean compare(ByteBuffer bb, byte[] message) {
+        if (message.length != bb.remaining()) {
+            out.println("Compare failed, byte array length != to buffer remaining");
+            return false;
+        }
+
+        for (int i=0; i<message.length; i++) {
+            byte b = bb.get();
+            if (message[i] != b) {
+                out.println("Position " + i + ": " + message[i] + " != " + b);
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    static boolean compare(ByteBuffer bb, String str) {
+        try{
+            return Util.compare(bb, str.getBytes("ISO-8859-1"));
+        } catch (UnsupportedEncodingException unsupported) {
+            throw new AssertionError(unsupported);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/nio/sctp/SctpServerChannel/Accept.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,274 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4927640
+ * @summary Tests the SCTP protocol implementation
+ * @author chegar
+ */
+
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+import java.nio.channels.AlreadyConnectedException;
+import java.nio.channels.AsynchronousCloseException;
+import java.nio.channels.NotYetBoundException;
+import java.nio.channels.ClosedByInterruptException;
+import java.nio.channels.ClosedChannelException;
+import com.sun.nio.sctp.SctpChannel;
+import com.sun.nio.sctp.SctpServerChannel;
+import static java.lang.System.out;
+import static java.lang.System.err;
+
+public class Accept {
+    static CountDownLatch acceptLatch = new CountDownLatch(1);
+    static CountDownLatch closeByIntLatch = new CountDownLatch(1);
+    static CountDownLatch asyncCloseLatch = new CountDownLatch(1);
+    AcceptServer server = null;
+
+    void test(String[] args) {
+        SocketAddress address = null;
+
+        if (!Util.isSCTPSupported()) {
+            out.println("SCTP protocol is not supported");
+            out.println("Test cannot be run");
+            return;
+        }
+
+        if (args.length == 2) {
+            /* requested to connecct to a specific address */
+            try {
+                int port = Integer.valueOf(args[1]);
+                address = new InetSocketAddress(args[0], port);
+            } catch (NumberFormatException nfe) {
+                err.println(nfe);
+            }
+        } else {
+            /* start server on local machine, default */
+            try {
+                server = new AcceptServer();
+                server.start();
+                address = server.address();
+                debug("Server started and listening on " + address);
+            } catch (IOException ioe) {
+                ioe.printStackTrace();
+                return;
+            }
+        }
+
+        doClient(address);
+    }
+
+    void doClient(SocketAddress peerAddress) {
+        SctpChannel channel = null;
+
+        try {
+            channel = SctpChannel.open(peerAddress, 0, 0);
+            acceptLatch.await();
+
+            /* for test 4 */
+            closeByIntLatch.await();
+            sleep(500);
+            server.thread().interrupt();
+
+            /* for test 5 */
+            asyncCloseLatch.await();
+            sleep(500);
+            server.channel().close();
+
+            /* wait for the server thread to finish */
+            join(server.thread(), 10000);
+        } catch (IOException ioe) {
+            unexpected(ioe);
+        } catch (InterruptedException ie) {
+            unexpected(ie);
+        } finally {
+            try { if (channel != null) channel.close(); }
+            catch (IOException e) { unexpected(e);}
+        }
+    }
+
+    class AcceptServer implements Runnable
+    {
+        final InetSocketAddress serverAddr;
+        private SctpServerChannel ssc;
+        private Thread serverThread;
+
+        public AcceptServer() throws IOException {
+            ssc = SctpServerChannel.open();
+
+            /* TEST 1: NotYetBoundException */
+            debug("TEST 1: NotYetBoundException");
+            try {
+                ssc.accept();
+                fail();
+            } catch (NotYetBoundException nybe) {
+                debug("  caught NotYetBoundException");
+                pass();
+            } catch (IOException ioe) {
+                unexpected(ioe);
+            }
+
+            ssc.bind(null);
+            java.util.Set<SocketAddress> addrs = ssc.getAllLocalAddresses();
+            if (addrs.isEmpty())
+                debug("addrs should not be empty");
+
+            serverAddr = (InetSocketAddress) addrs.iterator().next();
+
+            /* TEST 2: null if this channel is in non-blocking mode and no
+             *         association is available to be accepted  */
+            ssc.configureBlocking(false);
+            debug("TEST 2: non-blocking mode null");
+            try {
+                SctpChannel sc = ssc.accept();
+                check(sc == null, "non-blocking mode should return null");
+            } catch (IOException ioe) {
+                unexpected(ioe);
+            } finally {
+                ssc.configureBlocking(true);
+            }
+        }
+
+        void start() {
+            serverThread = new Thread(this, "AcceptServer-"  +
+                                              serverAddr.getPort());
+            serverThread.start();
+        }
+
+        InetSocketAddress address() {
+            return serverAddr;
+        }
+
+        SctpServerChannel channel() {
+            return ssc;
+        }
+
+        Thread thread() {
+            return serverThread;
+        }
+
+        @Override
+        public void run() {
+            SctpChannel sc = null;
+            try {
+                /* TEST 3: accepted channel */
+                debug("TEST 3: accepted channel");
+                sc = ssc.accept();
+
+                checkAcceptedChannel(sc);
+                acceptLatch.countDown();
+
+                /* TEST 4: ClosedByInterruptException */
+                debug("TEST 4: ClosedByInterruptException");
+                try {
+                    closeByIntLatch.countDown();
+                    ssc.accept();
+                    fail();
+                } catch (ClosedByInterruptException unused) {
+                    debug("  caught ClosedByInterruptException");
+                    pass();
+                }
+
+                /* TEST 5: AsynchronousCloseException */
+                debug("TEST 5: AsynchronousCloseException");
+                /* reset thread interrupt status */
+                Thread.currentThread().interrupted();
+
+                ssc = SctpServerChannel.open().bind(null);
+                try {
+                    asyncCloseLatch.countDown();
+                    ssc.accept();
+                    fail();
+                } catch (AsynchronousCloseException unused) {
+                    debug("  caught AsynchronousCloseException");
+                    pass();
+                }
+
+                /* TEST 6: ClosedChannelException */
+                debug("TEST 6: ClosedChannelException");
+                try {
+                    ssc.accept();
+                    fail();
+                } catch (ClosedChannelException unused) {
+                    debug("  caught ClosedChannelException");
+                    pass();
+                }
+                ssc = null;
+            } catch (IOException ioe) {
+                ioe.printStackTrace();
+            } finally {
+                try { if (ssc != null) ssc.close(); }
+                catch (IOException  ioe) { unexpected(ioe); }
+                try { if (sc != null) sc.close(); }
+                catch (IOException  ioe) { unexpected(ioe); }
+            }
+        }
+    }
+
+    void checkAcceptedChannel(SctpChannel sc) {
+        try {
+            debug("Checking accepted SctpChannel");
+            check(sc.association() != null,
+                  "accepted channel should have an association");
+            check(!(sc.getRemoteAddresses().isEmpty()),
+                  "accepted channel should be connected");
+            check(!(sc.isConnectionPending()),
+                  "accepted channel should not have a connection pending");
+            check(sc.isBlocking(),
+                  "accepted channel should be blocking");
+            try { sc.connect(new TestSocketAddress()); fail(); }
+            catch (AlreadyConnectedException unused) { pass(); }
+            try { sc.bind(new TestSocketAddress()); fail(); }
+            catch (AlreadyConnectedException unused) { pass(); }
+        } catch (IOException unused) { fail(); }
+    }
+
+    static class TestSocketAddress extends SocketAddress {}
+
+        //--------------------- Infrastructure ---------------------------
+    boolean debug = true;
+    volatile int passed = 0, failed = 0;
+    void pass() {passed++;}
+    void fail() {failed++; Thread.dumpStack();}
+    void fail(String msg) {err.println(msg); fail();}
+    void unexpected(Throwable t) {failed++; t.printStackTrace();}
+    void check(boolean cond) {if (cond) pass(); else fail();}
+    void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);}
+    void debug(String message) {if(debug) { out.println(message); }  }
+    void sleep(long millis) { try { Thread.currentThread().sleep(millis); }
+                          catch(InterruptedException ie) { unexpected(ie); }}
+    void join(Thread thread, long millis) { try { thread.join(millis); }
+                          catch(InterruptedException ie) { unexpected(ie); }}
+    public static void main(String[] args) throws Throwable {
+        Class<?> k = new Object(){}.getClass().getEnclosingClass();
+        try {k.getMethod("instanceMain",String[].class)
+                .invoke( k.newInstance(), (Object) args);}
+        catch (Throwable e) {throw e.getCause();}}
+    public void instanceMain(String[] args) throws Throwable {
+        try {test(args);} catch (Throwable t) {unexpected(t);}
+        out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
+        if (failed > 0) throw new AssertionError("Some tests failed");}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/nio/sctp/SctpServerChannel/NonBlockingAccept.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/* @test
+ * @bug 4927640
+ * @summary Tests the SCTP protocol implementation
+ * @author chegar
+ */
+
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+import java.nio.channels.AlreadyConnectedException;
+import java.nio.channels.Selector;
+import java.nio.channels.SelectionKey;
+import com.sun.nio.sctp.SctpChannel;
+import com.sun.nio.sctp.SctpServerChannel;
+import static java.lang.System.out;
+import static java.lang.System.err;
+
+public class NonBlockingAccept {
+    static CountDownLatch acceptLatch = new CountDownLatch(1);
+    static final int SEL_TIMEOUT = 10000;
+    static final int NUM_TEST_CONNECTIONS = 10;
+
+    void test(String[] args) {
+        SocketAddress address = null;
+        NonblockingServer server;
+
+        if (!Util.isSCTPSupported()) {
+            out.println("SCTP protocol is not supported");
+            out.println("Test cannot be run");
+            return;
+        }
+
+        if (args.length == 2) {
+            /* requested to connecct to a specific address */
+            try {
+                int port = Integer.valueOf(args[1]);
+                address = new InetSocketAddress(args[0], port);
+            } catch (NumberFormatException nfe) {
+                err.println(nfe);
+            }
+        } else {
+            /* start server on local machine, default */
+            try {
+                server = new NonblockingServer();
+                server.start();
+                address = server.address();
+                debug("Server started and listening on " + address);
+            } catch (IOException ioe) {
+                ioe.printStackTrace();
+                return;
+            }
+        }
+
+        doClient(address);
+    }
+
+    void doClient(SocketAddress peerAddress) {
+        Set<SctpChannel> channels = new HashSet<SctpChannel>(NUM_TEST_CONNECTIONS);
+
+        try {
+            for (int i=0; i<NUM_TEST_CONNECTIONS;) {
+                debug("connecting " + ++i);
+                channels.add(SctpChannel.open(peerAddress, 0, 0));
+                sleep(100);
+            }
+
+            /* don't close the channels until they have been accepted */
+            acceptLatch.await();
+
+            for(SctpChannel sc: channels)
+                sc.close();
+        } catch (IOException ioe) {
+            unexpected(ioe);
+        } catch (InterruptedException ie) {
+            unexpected(ie);
+        }
+    }
+
+    class NonblockingServer implements Runnable
+    {
+        final InetSocketAddress serverAddr;
+        private SctpServerChannel ssc;
+        private Thread serverThread;
+
+        public NonblockingServer() throws IOException {
+            ssc = SctpServerChannel.open().bind(null);
+            java.util.Set<SocketAddress> addrs = ssc.getAllLocalAddresses();
+            if (addrs.isEmpty())
+                debug("addrs should not be empty");
+
+            serverAddr = (InetSocketAddress) addrs.iterator().next();
+        }
+
+        void start() {
+            serverThread = new Thread(this, "NonblockingServer-"  +
+                                              serverAddr.getPort());
+            serverThread.start();
+        }
+
+        InetSocketAddress address () {
+            return serverAddr;
+        }
+
+        @Override
+        public void run() {
+            Selector acceptSelector = null;
+            SelectionKey acceptKey = null;
+
+            try {
+                acceptSelector = Selector.open();
+                ssc.configureBlocking(false);
+                check(ssc.isBlocking() == false, "Should be in non-blocking mode");
+                acceptKey = ssc.register(acceptSelector, SelectionKey.OP_ACCEPT);
+
+                int connectionsAccepted = 0;
+                while (connectionsAccepted < NUM_TEST_CONNECTIONS) {
+                    int keysAdded = acceptSelector.select(SEL_TIMEOUT);
+                    if (keysAdded > 0) {
+                        Set<SelectionKey> keys = acceptSelector.selectedKeys();
+                        Iterator<SelectionKey> i = keys.iterator();
+                        while(i.hasNext()) {
+                            SelectionKey sk = i.next();
+                            i.remove();
+                            SctpServerChannel nextReady =
+                                (SctpServerChannel)sk.channel();
+                            check(nextReady.equals(ssc),
+                                    "channels should be equal");
+                            check(sk.isAcceptable(),
+                                    "key should be acceptable");
+                            check(!sk.isReadable(),
+                                    "key should not be readable");
+                            check(!sk.isWritable(),
+                                    "key should not be writable");
+                            check(!sk.isConnectable(),
+                                    "key should not be connectable");
+                            SctpChannel acceptsc = nextReady.accept();
+                            connectionsAccepted++;
+                            debug("Accepted " + connectionsAccepted + " connections");
+                            check(acceptsc != null,
+                                    "Accepted channel should not be null");
+                            if (acceptsc != null) {
+                                checkAcceptedChannel(acceptsc);
+                                acceptsc.close();
+                            }
+                        } /* while */
+                    } /* if */
+                } /* while */
+            } catch (IOException ioe) {
+                ioe.printStackTrace();
+            } finally {
+                acceptLatch.countDown();
+                if (acceptKey != null) acceptKey.cancel();
+                try { if (acceptSelector != null) acceptSelector.close(); }
+                catch (IOException  ioe) { unexpected(ioe); }
+                try { if (ssc != null) ssc.close(); }
+                catch (IOException  ioe) { unexpected(ioe); }
+            }
+        }
+    }
+
+    void checkAcceptedChannel(SctpChannel sc) {
+        try {
+            debug("Checking accepted SctpChannel");
+            check(sc.association() != null,
+                  "accepted channel should have an association");
+            check(!(sc.getRemoteAddresses().isEmpty()),
+                  "accepted channel should be connected");
+            check(!(sc.isConnectionPending()),
+                  "accepted channel should not have a connection pending");
+            check(sc.isBlocking(),
+                  "accepted channel should be blocking");
+            try { sc.connect(new TestSocketAddress()); fail(); }
+            catch (AlreadyConnectedException unused) { pass(); }
+            try { sc.bind(new TestSocketAddress()); fail(); }
+            catch (AlreadyConnectedException unused) { pass(); }
+        } catch (IOException unused) { fail(); }
+    }
+
+    static class TestSocketAddress extends SocketAddress {}
+
+        //--------------------- Infrastructure ---------------------------
+    boolean debug = true;
+    volatile int passed = 0, failed = 0;
+    void pass() {passed++;}
+    void fail() {failed++; Thread.dumpStack();}
+    void fail(String msg) {err.println(msg); fail();}
+    void unexpected(Throwable t) {failed++; t.printStackTrace();}
+    void check(boolean cond) {if (cond) pass(); else fail();}
+    void check(boolean cond, String failMessage) {if (cond) pass(); else fail(failMessage);}
+    void debug(String message) {if(debug) { out.println(message); }  }
+    void sleep(long millis) { try { Thread.currentThread().sleep(millis); }
+                          catch(InterruptedException ie) { unexpected(ie); }}
+    public static void main(String[] args) throws Throwable {
+        Class<?> k = new Object(){}.getClass().getEnclosingClass();
+        try {k.getMethod("instanceMain",String[].class)
+                .invoke( k.newInstance(), (Object) args);}
+        catch (Throwable e) {throw e.getCause();}}
+    public void instanceMain(String[] args) throws Throwable {
+        try {test(args);} catch (Throwable t) {unexpected(t);}
+        out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
+        if (failed > 0) throw new AssertionError("Some tests failed");}
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/nio/sctp/SctpServerChannel/Util.java	Wed Jul 05 16:51:35 2017 +0200
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.net.NetworkInterface;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.net.InetAddress;
+import java.net.Inet4Address;
+import java.net.SocketException;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.UnsupportedEncodingException;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Set;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.nio.ByteBuffer;
+import com.sun.nio.sctp.SctpChannel;
+import static java.lang.System.out;
+
+public class Util {
+    static final int SMALL_BUFFER = 128;
+    static final String SMALL_MESSAGE =
+      "Under the bridge and over the dam, looking for berries, berries for jam";
+
+    static final int LARGE_BUFFER = 32768;
+    static final String LARGE_MESSAGE;
+
+    static {
+        StringBuffer sb = new StringBuffer(LARGE_BUFFER);
+        for (int i=0; i<460; i++)
+          sb.append(SMALL_MESSAGE);
+
+        LARGE_MESSAGE = sb.toString();
+    }
+
+    static boolean isSCTPSupported() {
+        try {
+            SctpChannel c = SctpChannel.open();
+            c.close();
+            return true;
+        } catch (IOException ioe) {
+            ioe.printStackTrace();
+        } catch (UnsupportedOperationException e) {
+            out.println(e);
+        }
+
+        return false;
+    }
+    /**
+     * Returns a list of all the addresses on the system.
+     * @param  inclLoopback
+     *         if {@code true}, include the loopback addresses
+     * @param  ipv4Only
+     *         it {@code true}, only IPv4 addresses will be included
+     */
+    static List<InetAddress> getAddresses(boolean inclLoopback,
+                                          boolean ipv4Only)
+        throws SocketException {
+        ArrayList<InetAddress> list = new ArrayList<InetAddress>();
+        Enumeration<NetworkInterface> nets =
+                 NetworkInterface.getNetworkInterfaces();
+        for (NetworkInterface netInf : Collections.list(nets)) {
+            Enumeration<InetAddress> addrs = netInf.getInetAddresses();
+            for (InetAddress addr : Collections.list(addrs)) {
+                if (!list.contains(addr) &&
+                        (inclLoopback ? true : !addr.isLoopbackAddress()) &&
+                        (ipv4Only ? (addr instanceof Inet4Address) : true)) {
+                    list.add(addr);
+                }
+            }
+        }
+
+        return list;
+    }
+
+    static void dumpAddresses(SctpChannel channel,
+                              PrintStream printStream)
+        throws IOException {
+        Set<SocketAddress> addrs = channel.getAllLocalAddresses();
+        printStream.println("Local Addresses: ");
+        for (Iterator<SocketAddress> it = addrs.iterator(); it.hasNext(); ) {
+            InetSocketAddress addr = (InetSocketAddress)it.next();
+            printStream.println("\t" + addr);
+        }
+    }
+
+    /**
+     * Compare the contents of the given ByteBuffer with the contens of the
+     * given byte array. true if, and only if, the contents are the same.
+     */
+    static boolean compare(ByteBuffer bb, byte[] message) {
+        if (message.length != bb.remaining()) {
+            out.println("Compare failed, byte array length != to buffer remaining");
+            return false;
+        }
+
+        for (int i=0; i<message.length; i++) {
+            byte b = bb.get();
+            if (message[i] != b) {
+                out.println("Position " + i + ": " + message[i] + " != " + b);
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    static boolean compare(ByteBuffer bb, String str) {
+        try{
+            return Util.compare(bb, str.getBytes("ISO-8859-1"));
+        } catch (UnsupportedEncodingException unsupported) {
+            throw new AssertionError(unsupported);
+        }
+    }
+}
--- a/langtools/.hgtags	Wed Jul 05 16:51:11 2017 +0200
+++ b/langtools/.hgtags	Wed Jul 05 16:51:35 2017 +0200
@@ -29,3 +29,4 @@
 29329051d483d39f66073752ba4afbf29d893cfe jdk7-b52
 dbdeb4a7581b2a8699644b91cae6793cb01953f7 jdk7-b53
 197a7f881937d406a01214aa9ded49c073f7d380 jdk7-b54
+7394a8694cedea574c7dbd38de87f4cbe0e27b8a jdk7-b55