1.4 start, virtual threads support

This commit is contained in:
Taiyou06
2024-07-20 14:16:03 +03:00
parent 5762d8aabd
commit eb97d71e9e
8 changed files with 266 additions and 4 deletions

View File

@@ -1,5 +1,5 @@
group=net.gensokyoreimagined.nitori
version=1.3-SNAPSHOT
version=1.4-SNAPSHOT
description=Converting patches into mixins, for the Ignite Framework
org.gradle.parallel=true

View File

@@ -0,0 +1,34 @@
package net.gensokyoreimagined.nitori.mixin.alloc;
import net.minecraft.resources.ResourceLocation;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
@Mixin(ResourceLocation.class)
public class MixinIdentifier {
@Shadow @Final
private String namespace;
@Shadow @Final
private String path;
@Unique
private String nitori$cachedString = null;
/**
* @author ishland
* @reason cache toString
*/
@Overwrite
public String toString() {
if (this.nitori$cachedString != null) return this.nitori$cachedString;
final String s = this.namespace + ":" + this.path;
this.nitori$cachedString = s;
return s;
}
}

View File

@@ -12,7 +12,7 @@
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package net.gensokyoreimagined.nitori.mixin;
package net.gensokyoreimagined.nitori.mixin.entity.micro_opts;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.EntityType;

View File

@@ -0,0 +1,50 @@
// Gale - virtual thread support
package net.gensokyoreimagined.nitori.mixin.virtual_thread;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.ThreadFactory;
/**
* An implementation of {@link VirtualThreadService} that can create virtual threads directly.
*
* @author Martijn Muijsers
*/
final class DirectVirtualThreadService extends VirtualThreadService {
private DirectVirtualThreadService() {
super();
}
@Override
public @NotNull ThreadFactory createFactory() {
// Disabled until Minecraft requires servers to have a Java version that can read class files compiled with functionality from Java 19+ on preview / Java 21+ on stable
throw new UnsupportedOperationException();
// return Thread.ofVirtual().factory();
}
@Override
public @NotNull Thread start(@NotNull Runnable task) {
// Disabled until Minecraft requires servers to have a Java version that can read class files compiled with functionality from Java 19+ on preview / Java 21+ on stable
throw new UnsupportedOperationException();
// Objects.requireNonNull(task, "The task to start a virtual thread cannot be null");
// return Thread.ofVirtual().start(task);
}
/**
* @return A functional {@link DirectVirtualThreadService}.
* @throws Throwable If creating virtual threads directly is not supported by the current runtime.
* This could be any {@link Throwable}, including an {@link Exception} or an {@link Error}.
*/
static @NotNull DirectVirtualThreadService create() throws Throwable {
// Disabled until Minecraft requires servers to have a Java version that can read class files compiled with functionality from Java 19+ on preview / Java 21+ on stable
throw new UnsupportedOperationException();
// var service = new DirectVirtualThreadService();
// // Run some tests to verify
// service.runTest();
// // If we end up here, it works
// return service;
}
}

View File

@@ -0,0 +1,76 @@
// Gale - virtual thread support
package net.gensokyoreimagined.nitori.mixin.virtual_thread;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.Method;
import java.util.Objects;
import java.util.concurrent.ThreadFactory;
/**
* An implementation of {@link VirtualThreadService} that can create virtual threads using Java reflection.
*
* @author Martijn Muijsers
*/
final class ReflectionVirtualThreadService extends VirtualThreadService {
/**
* The {@link Thread}<code>#ofVirtual()</code> method.
*/
private final @NotNull Method Thread_ofVirtual_method;
/**
* The {@link Thread}<code>.Builder#factory()</code> method.
*/
private final @NotNull Method Thread_Builder_factory_method;
/**
* The {@link Thread}<code>.Builder#start(Runnable)</code> method.
*/
private final @NotNull Method Thread_Builder_start_method;
private ReflectionVirtualThreadService() throws Throwable {
this.Thread_ofVirtual_method = Objects.requireNonNull(Thread.class.getMethod("ofVirtual"));
// The Thread.Builder class
var Thread_Builder_class = Objects.requireNonNull(Class.forName("java.lang.Thread$Builder"));
this.Thread_Builder_factory_method = Objects.requireNonNull(Thread_Builder_class.getMethod("factory"));
this.Thread_Builder_start_method = Objects.requireNonNull(Thread_Builder_class.getMethod("start", Runnable.class));
}
@Override
public @NotNull ThreadFactory createFactory() {
try {
return (ThreadFactory) this.Thread_Builder_factory_method.invoke(this.Thread_ofVirtual_method.invoke(null));
} catch (Exception e) {
// This should not be possible because it was tested in create()
throw new RuntimeException(e);
}
}
@Override
public @NotNull Thread start(@NotNull Runnable task) {
Objects.requireNonNull(task, "The task to start a virtual thread cannot be null");
try {
return (Thread) this.Thread_Builder_start_method.invoke(this.Thread_ofVirtual_method.invoke(null), task);
} catch (Exception e) {
// This should not be possible because it was tested in create()
throw new RuntimeException(e);
}
}
/**
* @return A functional {@link ReflectionVirtualThreadService}.
* @throws Throwable If creating virtual threads via reflection is not supported by the current runtime.
* This could be any {@link Throwable}, including an {@link Exception} or an {@link Error}.
*/
static @NotNull ReflectionVirtualThreadService create() throws Throwable {
// This will already throw something if the reflection fails
var service = new ReflectionVirtualThreadService();
// Run some tests to verify
service.runTest();
// If we end up here, it works
return service;
}
}

View File

@@ -0,0 +1,101 @@
// Gale - virtual thread support
package net.gensokyoreimagined.nitori.mixin.virtual_thread;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.concurrent.ThreadFactory;
/**
* An abstract service to create virtual threads.
*
* @author Martijn Muijsers
*/
public sealed abstract class VirtualThreadService permits ReflectionVirtualThreadService, DirectVirtualThreadService {
/**
* @return A {@link ThreadFactory} that produces virtual threads.
*/
public abstract @NotNull ThreadFactory createFactory();
/**
* @param task The runnable for the thread to execute.
* @return A virtual thread that has been started with the given task.
*/
public abstract @NotNull Thread start(Runnable task);
/**
* Runs a test on the {@link #createFactory} and {@link #start} methods,
* which certainly throws some {@link Throwable} if something goes wrong.
*/
protected void runTest() throws Throwable {
// This will definitely throw something if it doesn't work
try {
this.start(() -> {}).join();
} catch (InterruptedException ignored) {} // Except InterruptedException, we don't care about that one
try {
var thread = this.createFactory().newThread(() -> {});
thread.start();
thread.join();
} catch (InterruptedException ignored) {} // Except InterruptedException, we don't care about that one
// If we end up here, it works
}
private static boolean initialized = false;
/**
* The {@link VirtualThreadService} for the current runtime,
* or null if virtual threads are not supported, or if not {@link #initialized} yet.
*/
private static @Nullable VirtualThreadService implementation;
/**
* @return Whether virtual threads are supported on the current runtime.
*/
public static boolean isSupported() {
return get() != null;
}
/**
* @return The {@link VirtualThreadService} for the current runtime,
* or null if virtual threads are not {@linkplain #isSupported() supported}.
*
* This method is thread-safe only after the first time it has been fully run.
*/
public static @Nullable VirtualThreadService get() {
if (!initialized) {
initialized = true;
try {
implementation = DirectVirtualThreadService.create();
} catch (Throwable ignored) {
try {
implementation = ReflectionVirtualThreadService.create();
} catch (Throwable ignored2) {}
}
}
return implementation;
}
/**
* The minimum major version of Java that is known to support using virtual threads
* (although possibly behind a feature preview flag).
*/
public static final int minimumJavaMajorVersionWithFeaturePreview = 19;
/**
* The minimum major version of Java that is known to support using virtual threads
* even without any feature preview flags.
*/
public static final int minimumJavaMajorVersionWithoutFeaturePreview = 21;
public static int getJavaMajorVersion() {
var version = System.getProperty("java.version");
if (version.startsWith("1.")) {
return version.charAt(2) - '0';
}
int dotIndex = version.indexOf(".");
return Integer.parseInt(dotIndex == -1 ? version : version.substring(0, dotIndex));
}
}

View File

@@ -1,6 +1,6 @@
{
"id": "Nitori",
"version": "1.3-SNAPSHOT",
"version": "1.4-SNAPSHOT",
"mixins": [
"mixins.core.json"
]

View File

@@ -16,7 +16,7 @@
"MixinGameRules",
"MixinIteratorSafeOrderedReferenceSet",
"MixinLevelStorageAccess",
"MixinMob",
"entity.micro_opts.MixinMob",
"MixinNoiseBasedChunkGenerator",
"MixinPlayer",
"MixinPlayerList",
@@ -31,6 +31,7 @@
"alloc.composter.ComposterMixin$ComposterBlockDummyInventoryMixin",
"alloc.composter.ComposterMixin$ComposterBlockFullComposterInventoryMixin",
"alloc.biome_temprature_leak.Biome_threadLocalMixin",
"alloc.MixinIdentifier",
"cached_hashcode.BlockNeighborGroupMixin",
"collections.attributes.AttributeContainerMixin",
"collections.block_entity_tickers.WorldChunkMixin",