diff --git a/build/jvm-rules/zip/src/byteBuffer.kt b/build/jvm-rules/zip/src/byteBuffer.kt index f0921fe0a9f8..3a16b9fdc8d6 100644 --- a/build/jvm-rules/zip/src/byteBuffer.kt +++ b/build/jvm-rules/zip/src/byteBuffer.kt @@ -3,6 +3,7 @@ package org.jetbrains.intellij.build.io import io.netty.buffer.AdaptiveByteBufAllocator import io.netty.buffer.ByteBufAllocator +import java.lang.invoke.MethodHandle import java.lang.invoke.MethodHandles import java.lang.invoke.MethodType import java.nio.ByteBuffer @@ -51,19 +52,33 @@ internal class SingleByteBufferAllocator() : AutoCloseable { } } -private val unmap by lazy { - val unsafeClass = ClassLoader.getPlatformClassLoader().loadClass("sun.misc.Unsafe") - val lookup = MethodHandles.privateLookupIn(unsafeClass, MethodHandles.lookup()) - val unsafe = lookup.findStaticGetter(unsafeClass, "theUnsafe", unsafeClass).invoke() - lookup.findVirtual(unsafeClass, "invokeCleaner", MethodType.methodType(Void.TYPE, ByteBuffer::class.java)).bindTo(unsafe) -} - fun unmapBuffer(buffer: ByteBuffer) { - if (buffer.isDirect) { - unmap.invokeExact(buffer) - } + ByteBufferCleaner.unmapBuffer(buffer) } internal fun roundUpInt(x: Int, blockSizePowerOf2: Int): Int { return x + blockSizePowerOf2 - 1 and -blockSizePowerOf2 +} + +private object ByteBufferCleaner { + val cleanerHandle: MethodHandle + val cleanerCleanHandle: MethodHandle + + fun unmapBuffer(buffer: ByteBuffer) { + if (!buffer.isDirect) { + return + } + val cleaner = cleanerHandle.invoke(buffer) + if (cleaner != null) { + cleanerCleanHandle.invoke(cleaner) + } + } + + init { + val lookup = MethodHandles.lookup() + val directBufferClass = Class.forName("sun.nio.ch.DirectBuffer") + val cleanerClass = directBufferClass.getDeclaredMethod("cleaner").returnType + cleanerHandle = lookup.findVirtual(directBufferClass, "cleaner", MethodType.methodType(cleanerClass)) + cleanerCleanHandle = lookup.findVirtual(cleanerClass, "clean", MethodType.methodType(Void.TYPE)) + } } \ No newline at end of file diff --git a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java index fad8293487f5..881f0b547efb 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java @@ -1510,7 +1510,7 @@ public final class BuildManager implements Disposable { //-Djava.endorsed.dirs is not supported in JDK 9+, may result in abnormal process termination cmdLine.addParameter("-Djava.endorsed.dirs=\"\""); // turn off all jre customizations for predictable behaviour } - if (sdkVersion.isAtLeast(JavaSdkVersion.JDK_16)) { + if (sdkVersion.isAtLeast(JavaSdkVersion.JDK_11)) { // enable javac-related reflection tricks in JPS ClasspathBootstrap.configureReflectionOpenPackages(cmdLine::addParameter); } diff --git a/jps/jps-builders/src/org/jetbrains/jps/cmdline/ClasspathBootstrap.java b/jps/jps-builders/src/org/jetbrains/jps/cmdline/ClasspathBootstrap.java index 79b18ce794f9..f1d5f117e81d 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/cmdline/ClasspathBootstrap.java +++ b/jps/jps-builders/src/org/jetbrains/jps/cmdline/ClasspathBootstrap.java @@ -70,6 +70,9 @@ public final class ClasspathBootstrap { }; private static final String[] REFLECTION_OPEN_PACKAGES = { + "java.base/sun.nio.ch=ALL-UNNAMED", + "java.base/jdk.internal.ref=ALL-UNNAMED", + // needed for jps core functioning "jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", "jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED", @@ -160,6 +163,8 @@ public final class ClasspathBootstrap { // intellij.platform.util addToClassPath(cp, ClassPathUtil.getUtilClasses()); addToClassPath(cp, HashMapZipFile.class); // intellij.platform.util.zip + // intellij.platform.concurrency + //addToClassPath(cp, VarHandleWrapperImpl.class); ClassPathUtil.addKotlinStdlib(cp); addToClassPath(cp, Deferred.class); // kotlinx.coroutines, used intellij.platform.util, EnvironmentUtil diff --git a/platform/platform-impl/resources/META-INF/OpenedPackages.txt b/platform/platform-impl/resources/META-INF/OpenedPackages.txt index 3a00b0721168..c871cb8004d6 100644 --- a/platform/platform-impl/resources/META-INF/OpenedPackages.txt +++ b/platform/platform-impl/resources/META-INF/OpenedPackages.txt @@ -11,6 +11,7 @@ --add-opens=java.base/java.util.concurrent=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.locks=ALL-UNNAMED +--add-opens=java.base/jdk.internal.ref=ALL-UNNAMED --add-opens=java.base/jdk.internal.vm=ALL-UNNAMED --add-opens=java.base/sun.net.dns=ALL-UNNAMED --add-opens=java.base/sun.nio.ch=ALL-UNNAMED diff --git a/platform/util/api-dump-unreviewed.txt b/platform/util/api-dump-unreviewed.txt index 741c4b23bdd1..966f78817d56 100644 --- a/platform/util/api-dump-unreviewed.txt +++ b/platform/util/api-dump-unreviewed.txt @@ -3775,7 +3775,6 @@ f:com.intellij.util.io.ByteBufferUtil - ():V - s:cleanBuffer(java.nio.ByteBuffer):Z - s:copyMemory(java.nio.ByteBuffer,I,B[],I,I):V -- s:getAddress(java.nio.ByteBuffer):J f:com.intellij.util.io.ByteSequenceDataExternalizer - com.intellij.util.io.DataExternalizer - sf:INSTANCE:com.intellij.util.io.ByteSequenceDataExternalizer diff --git a/platform/util/src/com/intellij/util/io/ByteBufferUtil.java b/platform/util/src/com/intellij/util/io/ByteBufferUtil.java index 6ecdb559b5e7..efff8e8c5ecf 100644 --- a/platform/util/src/com/intellij/util/io/ByteBufferUtil.java +++ b/platform/util/src/com/intellij/util/io/ByteBufferUtil.java @@ -3,11 +3,7 @@ package com.intellij.util.io; import com.intellij.ReviseWhenPortedToJDK; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.util.CurrentJavaVersion; -import com.intellij.util.ReflectionUtil; -import com.intellij.util.containers.Unsafe; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -15,43 +11,10 @@ import java.lang.invoke.MethodType; import java.nio.ByteBuffer; public final class ByteBufferUtil { - private static final MethodHandle invokeCleaner = findInvokeCleaner(); - private static final MethodHandle address = findAddress(); - private static final int byteArrayBaseOffset = byteArrayBaseOffset(); + private static final Logger LOG = Logger.getInstance(ByteBufferUtil.class); - private static @Nullable MethodHandle findInvokeCleaner() { - MethodHandle invokeCleaner = null; - try { - if (CurrentJavaVersion.currentJavaVersion().feature >= 9) { - Object unsafe = ReflectionUtil.getUnsafe(); - MethodType type = MethodType.methodType(void.class, ByteBuffer.class); - invokeCleaner = MethodHandles.publicLookup().findVirtual(unsafe.getClass(), "invokeCleaner", type).bindTo(unsafe); - } - } - catch (Throwable t) { - Logger.getInstance(ByteBufferUtil.class).warn(t); - } - return invokeCleaner; - } - - private static @Nullable MethodHandle findAddress() { - MethodHandle address = null; - try { - if (CurrentJavaVersion.currentJavaVersion().feature >= 9) { - Class directBufferClass = Class.forName("sun.nio.ch.DirectBuffer"); - address = MethodHandles.lookup().findVirtual(directBufferClass, - "address", - MethodType.methodType(long.class)); - } - } - catch (Throwable ignored) { - } - return address; - } - - private static int byteArrayBaseOffset() { - return Unsafe.arrayBaseOffset(byte[].class); - } + private static final MethodHandle cleanerHandle; + private static final MethodHandle cleanerCleanHandle; /** * Please use with care. In most cases leaving the job to the GC is enough. @@ -59,62 +22,39 @@ public final class ByteBufferUtil { @ReviseWhenPortedToJDK("11") public static boolean cleanBuffer(@NotNull ByteBuffer buffer) { if (!buffer.isDirect()) return true; - - if (invokeCleaner != null) { - try { - invokeCleaner.invoke(buffer); + try { + //noinspection JavaLangInvokeHandleSignature + Object cleaner = cleanerHandle.invoke(buffer); + if (cleaner != null) { + cleanerCleanHandle.invoke(cleaner); return true; } - catch (Throwable t) { - getLogger().warn(t); - return false; - } } - else { - //used in Kotlin and JPS - try { - Class directBufferClass = Class.forName("sun.nio.ch.DirectBuffer"); - Class cleanerClass = Class.forName("sun.misc.Cleaner"); - Object cleaner = directBufferClass.getDeclaredMethod("cleaner").invoke(buffer); - if (cleaner != null) { - cleanerClass.getDeclaredMethod("clean").invoke(cleaner); // already cleaned otherwise - } - return true; - } - catch (Exception e) { - getLogger().warn(e); - return false; - } + catch (Throwable e) { + LOG.warn(e); } + return false; } public static void copyMemory(@NotNull ByteBuffer src, int index, byte[] dst, int dstIndex, int length) { - if (address != null && src.isDirect()) { - try { - long address = (long)ByteBufferUtil.address.invoke(src); - Unsafe.copyMemory(null, address + index, dst, byteArrayBaseOffset + dstIndex, length); - return; - } - catch (Throwable e) { - getLogger().warn(e); - } - } - ByteBuffer buf = src.duplicate(); buf.position(index); buf.get(dst, dstIndex, length); } - public static long getAddress(@NotNull ByteBuffer src) { + static { try { - return (long)address.invoke(src); + MethodHandles.Lookup lookup = MethodHandles.lookup(); + Class directBufferClass = Class.forName("sun.nio.ch.DirectBuffer"); + Class cleanerClass = directBufferClass.getDeclaredMethod("cleaner").getReturnType(); + cleanerHandle = lookup.findVirtual(directBufferClass, "cleaner", MethodType.methodType(cleanerClass)); + cleanerCleanHandle = lookup.findVirtual(cleanerClass, "clean", MethodType.methodType(Void.TYPE)); + } + catch (Error | RuntimeException e) { + throw e; } catch (Throwable e) { - throw new RuntimeException(e); + throw new IllegalStateException(e); } } - - private static @NotNull Logger getLogger() { - return Logger.getInstance(ByteBufferUtil.class); - } } diff --git a/platform/util/storages/src/com/intellij/platform/util/io/storages/mmapped/MMappedFileStorage.java b/platform/util/storages/src/com/intellij/platform/util/io/storages/mmapped/MMappedFileStorage.java index 76db319061fe..74d012f36d69 100644 --- a/platform/util/storages/src/com/intellij/platform/util/io/storages/mmapped/MMappedFileStorage.java +++ b/platform/util/storages/src/com/intellij/platform/util/io/storages/mmapped/MMappedFileStorage.java @@ -5,18 +5,13 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.diagnostic.ThrottledLogger; import com.intellij.openapi.util.SystemInfoRt; import com.intellij.openapi.util.io.FileUtil; -import com.intellij.util.ReflectionUtil; -import com.intellij.util.io.CleanableStorage; -import com.intellij.util.io.ClosedStorageException; -import com.intellij.util.io.IOUtil; -import com.intellij.util.io.Unmappable; +import com.intellij.util.io.*; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.Closeable; import java.io.IOException; -import java.lang.reflect.Method; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.MappedByteBuffer; @@ -568,32 +563,11 @@ public final class MMappedFileStorage implements Closeable, Unmappable, Cleanabl if (!buffer.isDirect()) { return; } - //TODO RC: use ByteBufferUtil.cleanBuffer(buffer) ? - if (INVOKE_CLEANER_METHOD == null) { - throw new IllegalStateException("No access to Unsafe.invokeCleaner() -- explicit mapped buffers unmapping is unavailable"); - } - - INVOKE_CLEANER_METHOD.invoke(ReflectionUtil.getUnsafe(), buffer); - if (LOG_UNMAP_OPERATIONS) { + boolean result = ByteBufferUtil.cleanBuffer(buffer); + if (LOG_UNMAP_OPERATIONS && result) { LOG.info("Buffer unmapped: " + buffer); } } - - private static final Method INVOKE_CLEANER_METHOD; - - static { - Method cleanerMethod; - try { - Object unsafe = ReflectionUtil.getUnsafe(); - Class unsafeClass = unsafe.getClass(); - cleanerMethod = ReflectionUtil.getDeclaredMethod(unsafeClass, "invokeCleaner", ByteBuffer.class); - } - catch (Throwable t) { - LOG.error("Can't get access to Unsafe.invokeCleaner() -- explicit mapped buffers unmapping will be unavailable", t); - cleanerMethod = null; - } - INVOKE_CLEANER_METHOD = cleanerMethod; - } } // ============ statistics accessors ====================================================================== diff --git a/platform/util/zip/src/com/intellij/util/lang/ByteBufferCleaner.java b/platform/util/zip/src/com/intellij/util/lang/ByteBufferCleaner.java index 19d181467a76..a25cd424267a 100644 --- a/platform/util/zip/src/com/intellij/util/lang/ByteBufferCleaner.java +++ b/platform/util/zip/src/com/intellij/util/lang/ByteBufferCleaner.java @@ -13,21 +13,21 @@ import java.nio.ByteBuffer; // will fail with AccessDeniedException @Internal public final class ByteBufferCleaner { - private static volatile MethodHandle cleaner; + private static final MethodHandle cleanerHandle; + private static final MethodHandle cleanerCleanHandle; public static void unmapBuffer(@NotNull ByteBuffer buffer) throws Exception { if (!buffer.isDirect()) { return; } - - MethodHandle cleaner = ByteBufferCleaner.cleaner; try { - if (cleaner == null) { - cleaner = getByteBufferCleaner(); + //noinspection JavaLangInvokeHandleSignature + Object cleaner = cleanerHandle.invoke(buffer); + if (cleaner != null) { + cleanerCleanHandle.invoke(cleaner); } - cleaner.invokeExact(buffer); } - catch (Exception e) { + catch (Error | Exception e) { throw e; } catch (Throwable e) { @@ -35,17 +35,19 @@ public final class ByteBufferCleaner { } } - private static synchronized @NotNull MethodHandle getByteBufferCleaner() throws Throwable { - MethodHandle cleaner = ByteBufferCleaner.cleaner; - if (cleaner != null) { - return cleaner; + static { + try { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + Class directBufferClass = Class.forName("sun.nio.ch.DirectBuffer"); + Class cleanerClass = directBufferClass.getDeclaredMethod("cleaner").getReturnType(); + cleanerHandle = lookup.findVirtual(directBufferClass, "cleaner", MethodType.methodType(cleanerClass)); + cleanerCleanHandle = lookup.findVirtual(cleanerClass, "clean", MethodType.methodType(Void.TYPE)); + } + catch (Error | RuntimeException e) { + throw e; + } + catch (Throwable e) { + throw new IllegalStateException(e); } - - Class unsafeClass = ClassLoader.getPlatformClassLoader().loadClass("sun.misc.Unsafe"); - MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(unsafeClass, MethodHandles.lookup()); - Object unsafe = lookup.findStaticGetter(unsafeClass, "theUnsafe", unsafeClass).invoke(); - cleaner = lookup.findVirtual(unsafeClass, "invokeCleaner", MethodType.methodType(Void.TYPE, ByteBuffer.class)).bindTo(unsafe); - ByteBufferCleaner.cleaner = cleaner; - return cleaner; } }