--- old/src/java.base/share/classes/sun/nio/ch/NativeSocketAddress.java 2020-05-06 19:25:25.000000000 +0100 +++ new/src/java.base/share/classes/sun/nio/ch/NativeSocketAddress.java 2020-05-06 19:25:25.000000000 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,10 @@ package sun.nio.ch; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.invoke.VarHandle; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; @@ -33,12 +37,17 @@ import java.net.SocketException; import java.net.StandardProtocolFamily; import java.net.UnknownHostException; +import java.nio.ByteOrder; import java.nio.channels.UnsupportedAddressTypeException; - +import jdk.incubator.foreign.MemoryAddress; +import jdk.incubator.foreign.MemoryHandles; +import jdk.incubator.foreign.MemoryLayout; +import jdk.incubator.foreign.MemoryLayout.PathElement; +import jdk.incubator.foreign.MemoryLayouts; +import jdk.incubator.foreign.MemorySegment; import jdk.internal.access.JavaNetInetAddressAccess; import jdk.internal.access.SharedSecrets; -import jdk.internal.misc.Unsafe; -import jdk.internal.util.ArraysSupport; +import static jdk.incubator.foreign.MemoryLayout.PathElement.*; /** * A native socket address that is the union of struct sockaddr, struct sockaddr_in, @@ -48,8 +57,6 @@ */ class NativeSocketAddress { private static final JavaNetInetAddressAccess JNINA = SharedSecrets.getJavaNetInetAddressAccess(); - private static final Unsafe UNSAFE = Unsafe.getUnsafe(); - private static final long ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(byte[].class); private static final int AF_INET = AFINET(); private static final int AF_INET6 = AFINET6(); @@ -66,17 +73,171 @@ private static final int OFFSET_SIN6_SCOPE_ID = offsetSin6ScopeId(); private static final int OFFSET_SIN6_FLOWINFO = offsetSin6FlowInfo(); - // SOCKETADDRESS - private final long address; + private static final ByteOrder NETWORK_BYTE_ORDER = ByteOrder.BIG_ENDIAN; + private static final ByteOrder HOST_BYTE_ORDER = ByteOrder.nativeOrder(); + + private static final MemoryLayout SOCKADDR; + + private static final int SOCKADDR_IN_SIZE; + private static final int SOCKADDR_IN6_SIZE; + + private static final VarHandle SA_FAMILY_HANDLE; + private static final VarHandle SIN_PORT_HANDLE; + private static final VarHandle SIN_ADDR_HANDLE; + private static final VarHandle SIN6_PORT_HANDLE; + private static final VarHandle SIN6_FLOWINFO_HANDLE; + private static final VarHandle SIN6_ADDR_HANDLE; + private static final VarHandle SIN6_SCOPE_HANDLE; + private static final VarHandle BYTEWISE_HANDLE; + + // byte/short to/from int adapter handles + private static final MethodHandle INT_TO_SHORT; + private static final MethodHandle SHORT_TO_UNSIGNED_INT; + private static final MethodHandle INT_TO_BYTE; + private static final MethodHandle BYTE_TO_UNSIGNED_INT; + + private static final boolean VERIFY = true; + private static final boolean DEBUG = true; + + static { + try { + var lookup = MethodHandles.lookup(); + BYTE_TO_UNSIGNED_INT = lookup.findStatic(Byte.class, "toUnsignedInt", MethodType.methodType(int.class, byte.class)); + INT_TO_BYTE = lookup.findStatic(NativeSocketAddress.class, "byteValue", MethodType.methodType(byte.class, int.class)); + SHORT_TO_UNSIGNED_INT = lookup.findStatic(Short.class, "toUnsignedInt", MethodType.methodType(int.class, short.class)); + INT_TO_SHORT = lookup.findStatic(NativeSocketAddress.class, "shortValue", MethodType.methodType(short.class, int.class)); + } catch (Throwable throwable) { + throw new AssertionError(throwable); + } + + MemoryLayout familyLayout; + if (OFFSET_FAMILY == 1 && SIZEOF_FAMILY == 1) { + familyLayout = MemoryLayout.ofStruct(MemoryLayout.ofPaddingBits(8), MemoryLayouts.JAVA_BYTE.withName("sa_family")); + SA_FAMILY_HANDLE = MemoryHandles.filterValue( + familyLayout.varHandle(byte.class, groupElement("sa_family")), + INT_TO_BYTE, + BYTE_TO_UNSIGNED_INT); + } else if (OFFSET_FAMILY == 0 && SIZEOF_FAMILY == 2) { + familyLayout = MemoryLayouts.JAVA_SHORT.withName("sa_family"); + SA_FAMILY_HANDLE = MemoryHandles.filterValue( + familyLayout.varHandle(short.class), + INT_TO_SHORT, + SHORT_TO_UNSIGNED_INT); + } else { + throw new InternalError("unknown family [offset:%d, size:%d]".formatted(OFFSET_FAMILY, SIZEOF_FAMILY)); + } + + SOCKADDR = MemoryLayout.ofUnion( + MemoryLayout.ofStruct(familyLayout, + MemoryLayout.ofValueBits(16, NETWORK_BYTE_ORDER).withName("sin_port"), + //MemoryLayouts.BITS_32_BE.withName("sin_addr")) // #### treat as bits rather than bytes? + MemoryLayout.ofSequence(4, MemoryLayouts.JAVA_BYTE).withName("sin_addr"), + MemoryLayout.ofPaddingBits(64)) // pad to size of struct sockaddr + .withName("sockaddr_in"), + MemoryLayout.ofStruct(familyLayout, + MemoryLayout.ofValueBits(16, NETWORK_BYTE_ORDER).withName("sin6_port"), + MemoryLayout.ofValueBits(32, HOST_BYTE_ORDER).withName("sin6_flowinfo"), + //MemoryLayout.ofValueBits(128, NETWORK_BYTE_ORDER).withName("sin6_addr"), // #### treat as bits rather than bytes? + MemoryLayout.ofSequence(16, MemoryLayouts.JAVA_BYTE).withName("sin6_addr"), + MemoryLayout.ofValueBits(32, HOST_BYTE_ORDER).withName("sin6_scope_id")) + .withName("sockaddr_in6")) + .withName("sockaddr"); + + PathElement sockaddr_in = groupElement("sockaddr_in"); + SIN_PORT_HANDLE = MemoryHandles.filterValue( + SOCKADDR.varHandle(short.class, sockaddr_in, groupElement("sin_port")), + INT_TO_SHORT, + SHORT_TO_UNSIGNED_INT); + SIN_ADDR_HANDLE = SOCKADDR.varHandle(byte.class, sockaddr_in, groupElement("sin_addr"), sequenceElement()); + PathElement sockaddr_in6 = groupElement("sockaddr_in6"); + SIN6_PORT_HANDLE = MemoryHandles.filterValue( + SOCKADDR.varHandle(short.class, sockaddr_in6, groupElement("sin6_port")), + INT_TO_SHORT, + SHORT_TO_UNSIGNED_INT); + SIN6_FLOWINFO_HANDLE = SOCKADDR.varHandle(int.class, sockaddr_in6, groupElement("sin6_flowinfo")); + SIN6_ADDR_HANDLE = SOCKADDR.varHandle(byte.class, sockaddr_in6, groupElement("sin6_addr"), sequenceElement()); + SIN6_SCOPE_HANDLE = SOCKADDR.varHandle(int.class, sockaddr_in6, groupElement("sin6_scope_id")); + + // byte-wise handle for equality comparison + MemoryLayout layout = MemoryLayout.ofSequence(SOCKADDR.byteSize(), MemoryLayouts.JAVA_BYTE); + BYTEWISE_HANDLE = layout.varHandle(byte.class, sequenceElement()); + + SOCKADDR_IN_SIZE = (int) SOCKADDR.select(sockaddr_in).byteSize(); + SOCKADDR_IN6_SIZE = (int) SOCKADDR.select(sockaddr_in6).byteSize(); + + debug(); + // Verifies the handcrafted layout against the natively derived sizes and offsets + if (VERIFY) + verify(); + } + + private static void verify() { + // sockaddr_in + PathElement sockaddr_in = groupElement("sockaddr_in"); + assert SIZEOF_SOCKADDR4 == SOCKADDR_IN_SIZE : "SIZEOF_SOCKADDR [%d] != SOCKADDR_IN_SIZE [%d]".formatted(SIZEOF_SOCKADDR4, SOCKADDR_IN_SIZE); + var offset = bitsToBytes(SOCKADDR.offset(sockaddr_in , groupElement("sin_port"))); + assert offset == OFFSET_SIN4_PORT : "OFFSET_SIN4_PORT [%d] != layout offset [%d]".formatted(OFFSET_SIN4_PORT, offset); + offset = bitsToBytes(SOCKADDR.offset(sockaddr_in , groupElement("sin_addr"))); + assert offset == OFFSET_SIN4_ADDR : "OFFSET_SIN4_ADDR [%d] != layout offset [%d]".formatted(OFFSET_SIN4_ADDR, offset); + + //sockaddr_in6 + PathElement sockaddr_in6 = groupElement("sockaddr_in6"); + assert SIZEOF_SOCKADDR6 == SOCKADDR_IN6_SIZE : "SIZEOF_SOCKADDR6 [%d] != SOCKADDR_IN6_SIZE [%d]".formatted(SIZEOF_SOCKADDR6, SOCKADDR_IN6_SIZE); + offset = bitsToBytes(SOCKADDR.offset(sockaddr_in6 , groupElement("sin6_port"))); + assert offset == OFFSET_SIN6_PORT : "OFFSET_SIN6_PORT [%d] != layout offset [%d]".formatted(OFFSET_SIN6_PORT, offset); + offset = bitsToBytes(SOCKADDR.offset(sockaddr_in6 , groupElement("sin6_addr"))); + assert offset == OFFSET_SIN6_ADDR : "OFFSET_SIN6_ADDR [%d] != layout offset [%d]".formatted(OFFSET_SIN6_ADDR, offset); + offset = bitsToBytes(SOCKADDR.offset(sockaddr_in6 , groupElement("sin6_flowinfo"))); + assert offset == OFFSET_SIN6_FLOWINFO : "OFFSET_SIN6_FLOWINFO [%d] != layout offset [%d]".formatted(OFFSET_SIN6_FLOWINFO, offset); + offset = bitsToBytes(SOCKADDR.offset(sockaddr_in6 , groupElement("sin6_scope_id"))); + assert offset == OFFSET_SIN6_SCOPE_ID : "OFFSET_SIN6_SCOPE_ID [%d] != layout offset [%d]".formatted(OFFSET_SIN6_SCOPE_ID, offset); + } + + private static void debug() { + if (DEBUG) { + System.out.println("SIZEOF_SOCKADDR4:" + SIZEOF_SOCKADDR4); + System.out.println("SIZEOF_SOCKADDR6:" + SIZEOF_SOCKADDR6); + System.out.println("SIZEOF_SOCKETADDRESS:" + SIZEOF_SOCKETADDRESS); + System.out.println("SIZEOF_FAMILY:" + SIZEOF_FAMILY); + System.out.println("OFFSET_FAMILY:" + OFFSET_FAMILY); + System.out.println("OFFSET_SIN4_PORT:" + OFFSET_SIN4_PORT); + System.out.println("OFFSET_SIN4_ADDR:" + OFFSET_SIN4_ADDR); + System.out.println("OFFSET_SIN6_PORT:" + OFFSET_SIN6_PORT); + System.out.println("OFFSET_SIN6_ADDR:" + OFFSET_SIN6_ADDR); + System.out.println("OFFSET_SIN6_SCOPE_ID:" + OFFSET_SIN6_SCOPE_ID); + System.out.println("OFFSET_SIN6_FLOWINFO:" + OFFSET_SIN6_FLOWINFO); + System.out.println("SOCKADDR layout:" + SOCKADDR); + System.out.println("SOCKADDR layout byteSize:" + SOCKADDR.byteSize()); + System.out.println("SOCKADDR layout byteAlignment:" + SOCKADDR.byteAlignment()); + } + } + + private static long bitsToBytes(long value) { + return value / 8; + } + + private static byte byteValue(int value) { + return (byte)value; + } + + private static short shortValue(int value) { + return (short)value; + } + + private final MemorySegment segment; + private final MemoryAddress memoryAddress; + private final long rawAddress; long address() { - return address; + return rawAddress; } NativeSocketAddress() { - long base = UNSAFE.allocateMemory(SIZEOF_SOCKETADDRESS); - UNSAFE.setMemory(base, SIZEOF_SOCKETADDRESS, (byte) 0); - this.address = base; + var initialSegment = MemorySegment.allocateNative(SOCKADDR); + //segment = MemorySegment.ofNativeRestricted(initialSegment.baseAddress(), initialSegment.byteSize(), null, () -> initialSegment.close(), null); // TODO: cannot close from another thread! + segment = MemorySegment.ofNativeRestricted(initialSegment.baseAddress(), initialSegment.byteSize(), null, null, null); + memoryAddress = segment.baseAddress(); + rawAddress = memoryAddress.toRawLongValue(); } /** @@ -102,7 +263,8 @@ for (int i = 0; i < array.length; i++) { NativeSocketAddress sa = array[i]; if (sa != null) { - UNSAFE.freeMemory(sa.address); + sa.segment.close(); + // #### underlying segment is not closed } } } @@ -116,21 +278,21 @@ */ int encode(ProtocolFamily protocolFamily, InetSocketAddress isa) { if (protocolFamily == StandardProtocolFamily.INET) { - // struct sockaddr + // struct sockaddr_in InetAddress ia = isa.getAddress(); if (!(ia instanceof Inet4Address)) throw new UnsupportedAddressTypeException(); putFamily(AF_INET); putAddress(AF_INET, ia); putPort(AF_INET, isa.getPort()); - return SIZEOF_SOCKADDR4; + return SOCKADDR_IN_SIZE; } else { - // struct sockaddr6 + // struct sockaddr_in6 putFamily(AF_INET6); putAddress(AF_INET6, isa.getAddress()); putPort(AF_INET6, isa.getPort()); - UNSAFE.putInt(address + OFFSET_SIN6_FLOWINFO, 0); - return SIZEOF_SOCKADDR6; + SIN6_FLOWINFO_HANDLE.set(memoryAddress, 0); + return SOCKADDR_IN6_SIZE; } } @@ -145,42 +307,32 @@ return new InetSocketAddress(address(family), port(family)); } - /** - * Find a mismatch between this and another socket address - * @return the byte offset of the first mismatch or -1 if no mismatch - */ - private int mismatch(NativeSocketAddress other) { - int i = ArraysSupport.vectorizedMismatch(null, - this.address, - null, - other.address, - SIZEOF_SOCKETADDRESS, - ArraysSupport.LOG2_ARRAY_BYTE_INDEX_SCALE); - if (i >= 0) - return i; - i = SIZEOF_SOCKETADDRESS - ~i; - for (; i < SIZEOF_SOCKETADDRESS; i++) { - if (UNSAFE.getByte(this.address + i) != UNSAFE.getByte(other.address + i)) { - return i; - } - } - return -1; - } - @Override public boolean equals(Object other) { - if (other instanceof NativeSocketAddress) { - return mismatch((NativeSocketAddress) other) < 0; - } else { + if (!(other instanceof NativeSocketAddress)) { return false; } + var that = (NativeSocketAddress)other; + + // #### this is byte-at-a-time, do we need to compare with a larger stride? + + final MemoryAddress thisAddress = this.memoryAddress; + final MemoryAddress thatAddress = that.memoryAddress; + for (int i = 0; i < SOCKADDR.byteSize(); i++) { + byte b1 = (byte) BYTEWISE_HANDLE.get(thisAddress, i); + byte b2 = (byte) BYTEWISE_HANDLE.get(thatAddress, i); + if (b1 != b2) + return false; + } + return true; } @Override public int hashCode() { int h = 0; - for (int offset = 0; offset < SIZEOF_SOCKETADDRESS; offset++) { - h = 31 * h + UNSAFE.getByte(address + offset); + final MemoryAddress address = memoryAddress; + for (int i = 0; i < SOCKADDR.byteSize(); i++) { + h = 31 * h + (byte) BYTEWISE_HANDLE.get(address, i); } return h; } @@ -200,26 +352,14 @@ * Return the value of the sa_family field. */ private int family() { - if (SIZEOF_FAMILY == 1) { - return UNSAFE.getByte(address + OFFSET_FAMILY); - } else if (SIZEOF_FAMILY == 2) { - return UNSAFE.getShort(address + OFFSET_FAMILY); - } else { - throw new InternalError(); - } + return (int) SA_FAMILY_HANDLE.get(memoryAddress); } /** * Stores the given family in the sa_family field. */ private void putFamily(int family) { - if (SIZEOF_FAMILY == 1) { - UNSAFE.putByte(address + OFFSET_FAMILY, (byte) family); - } else if (SIZEOF_FAMILY == 2) { - UNSAFE.putShort(address + OFFSET_FAMILY, (short) family); - } else { - throw new InternalError(); - } + SA_FAMILY_HANDLE.set(memoryAddress, family); } /** @@ -227,15 +367,10 @@ * stored in network order. */ private int port(int family) { - byte b1, b2; - if (family == AF_INET) { - b1 = UNSAFE.getByte(address + OFFSET_SIN4_PORT); - b2 = UNSAFE.getByte(address + OFFSET_SIN4_PORT + 1); - } else { - b1 = UNSAFE.getByte(address + OFFSET_SIN6_PORT); - b2 = UNSAFE.getByte(address + OFFSET_SIN6_PORT + 1); - } - return (Byte.toUnsignedInt(b1) << 8) + Byte.toUnsignedInt(b2); + if (family == AF_INET) + return (int) SIN_PORT_HANDLE.get(memoryAddress); + else + return (int) SIN6_PORT_HANDLE.get(memoryAddress); } /** @@ -243,15 +378,10 @@ * port is stored in network order. */ private void putPort(int family, int port) { - byte b1 = (byte) ((port >> 8) & 0xff); - byte b2 = (byte) ((port >> 0) & 0xff); - if (family == AF_INET) { - UNSAFE.putByte(address + OFFSET_SIN4_PORT, b1); - UNSAFE.putByte(address + OFFSET_SIN4_PORT + 1, b2); - } else { - UNSAFE.putByte(address + OFFSET_SIN6_PORT, b1); - UNSAFE.putByte(address + OFFSET_SIN6_PORT + 1, b2); - } + if (family == AF_INET) + SIN_PORT_HANDLE.set(memoryAddress, port); + else + SIN6_PORT_HANDLE.set(memoryAddress, port); } /** @@ -260,20 +390,21 @@ * created with the sin6_scope_id in the sockaddr_in6 structure. */ private InetAddress address(int family) { - int len; - int offset; + final MemoryAddress address = memoryAddress; int scope_id; + byte[] bytes; + if (family == AF_INET) { - len = 4; - offset = OFFSET_SIN4_ADDR; + bytes = new byte[4]; + for (int i = 0; i < 4; i++) + bytes[i] = (byte) SIN_ADDR_HANDLE.get(address, i); scope_id = 0; } else { - len = 16; - offset = OFFSET_SIN6_ADDR; - scope_id = UNSAFE.getInt(address + OFFSET_SIN6_SCOPE_ID); + bytes = new byte[16]; + for (int i = 0; i < 16; i++) + bytes[i] = (byte) SIN6_ADDR_HANDLE.get(address, i); + scope_id = (int) SIN6_SCOPE_HANDLE.get(address); } - byte[] bytes = new byte[len]; - UNSAFE.copyMemory(null, address + offset, bytes, ARRAY_BASE_OFFSET, len); try { if (scope_id == 0) { return InetAddress.getByAddress(bytes); @@ -291,40 +422,51 @@ * IPv4-mapped IPv6 address when the given InetAddress is an IPv4 address. */ private void putAddress(int family, InetAddress ia) { + final MemoryAddress address = memoryAddress; if (family == AF_INET) { // IPv4 address - putAddress(address + OFFSET_SIN4_ADDR, (Inet4Address) ia); + putIPv4Address(address, (Inet4Address)ia); } else { int scope_id; if (ia instanceof Inet4Address) { // IPv4-mapped IPv6 address - UNSAFE.setMemory(address + OFFSET_SIN6_ADDR, 10, (byte) 0); - UNSAFE.putByte(address + OFFSET_SIN6_ADDR + 10, (byte) 0xff); - UNSAFE.putByte(address + OFFSET_SIN6_ADDR + 11, (byte) 0xff); - putAddress(address + OFFSET_SIN6_ADDR + 12, (Inet4Address) ia); + putMappedAddress(address, (Inet4Address)ia); scope_id = 0; } else { // IPv6 address var inet6Address = (Inet6Address) ia; - putAddress(address + OFFSET_SIN6_ADDR, inet6Address); + putIPv6Address(address, inet6Address); scope_id = inet6Address.getScopeId(); } - UNSAFE.putInt(address + OFFSET_SIN6_SCOPE_ID, scope_id); + SIN6_SCOPE_HANDLE.set(address, scope_id); } } - private static void putAddress(long address, Inet4Address ia) { + private static void putIPv4Address(MemoryAddress address, Inet4Address ia) { int ipAddress = JNINA.addressValue(ia); - // network order - UNSAFE.putByte(address + 0, (byte) ((ipAddress >>> 24) & 0xFF)); - UNSAFE.putByte(address + 1, (byte) ((ipAddress >>> 16) & 0xFF)); - UNSAFE.putByte(address + 2, (byte) ((ipAddress >>> 8) & 0xFF)); - UNSAFE.putByte(address + 3, (byte) (ipAddress & 0xFF)); + SIN_ADDR_HANDLE.set(address, 0, (byte) ((ipAddress >>> 24) & 0xFF)); + SIN_ADDR_HANDLE.set(address, 1, (byte) ((ipAddress >>> 16) & 0xFF)); + SIN_ADDR_HANDLE.set(address, 2, (byte) ((ipAddress >>> 8) & 0xFF)); + SIN_ADDR_HANDLE.set(address, 3, (byte) ((ipAddress >>> 0) & 0xFF)); + } + + private static void putMappedAddress(MemoryAddress address, Inet4Address ia) { + int ipAddress = JNINA.addressValue(ia); + for (int i=0; i< 10; i++) + SIN6_ADDR_HANDLE.set(address, i, (byte) 0x00); + + SIN6_ADDR_HANDLE.set(address, 10, (byte) 0xFF); + SIN6_ADDR_HANDLE.set(address, 11, (byte) 0xFF); + SIN6_ADDR_HANDLE.set(address, 12, (byte) ((ipAddress >>> 24) & 0xFF)); + SIN6_ADDR_HANDLE.set(address, 13, (byte) ((ipAddress >>> 16) & 0xFF)); + SIN6_ADDR_HANDLE.set(address, 14, (byte) ((ipAddress >>> 8) & 0xFF)); + SIN6_ADDR_HANDLE.set(address, 15, (byte) ((ipAddress >>> 0) & 0xFF)); } - private static void putAddress(long address, Inet6Address ia) { + private static void putIPv6Address(MemoryAddress address, Inet6Address ia) { byte[] bytes = JNINA.addressBytes(ia); - UNSAFE.copyMemory(bytes, ARRAY_BASE_OFFSET, null, address, 16); + for (int i = 0; i < 16; i++) + SIN6_ADDR_HANDLE.set(address, i, bytes[i]); } private static native int AFINET();