MaskingClassLoader

Classloader for the REPL's Kotlin scripting stack.

It hosts the entire Kotlin scripting stack (kotlin-compiler-embeddable + scripting-* + stdlib + reflect + script-runtime) plus the REPL impl's own Kotlin classes, on a self-managed URLClassLoader that lives OFF the FML/securejarhandler module path. That is mandatory on NeoForge: putting kotlin-compiler-embeddable on the module path makes securejarhandler throw "Invalid package name: 'native' is not a Java identifier" at boot (the compiler ships a package org.jetbrains.kotlin.native.interop, and native is a Java keyword).

The compiler (org.jetbrains.kotlin.*), the shaded intellij/etc. inside compiler-embeddable, and the REPL impl classes under ...repl.impl.* are ALWAYS child-first (masking-owned). The JDK, MC, and the mod's own non-impl classes are ALWAYS parent-first so they keep a single shared identity with the game loader.

The kotlin RUNTIME (kotlin.* stdlib/reflect) is version-regime dependent

A REPL snippet must exchange kotlin objects (lambdas = Function0, Pair, Sequence, …) with the game's mods, which use the GAME loader's kotlin. If the masking loader defines its OWN copy of those classes, a snippet value is a DIFFERENT class from the mod's parameter type → LinkageError. One shared kotlin identity is the only fully-safe unification, and it needs the versions to line up — hence Regime, overridable with mcp.kotlin.regime=auto|share|split.

A feature that would otherwise need a JVM agent

Because every masking-owned class is defined right here in findClass, this loader is the single door those classes' bytes come through — which makes java.lang.instrument unnecessary for anything scoped to them. So the preload working-set capture works on a JVM launched WITHOUT -Djdk.attach.allowAttachSelf / -XX:+EnableDynamicAgentLoading: definedClassNames answers "what did this loader define?" from its own bookkeeping.

The live-patch engine (Patches.onEnter/onExit) still needs the agent and still dies without those flags: it retransforms already-loaded net.minecraft.* classes on the GAME loader and injects a jar into the bootstrap loader — neither is something a classloader can do for itself.

Constructors

Link copied to clipboard
constructor(urls: Array<URL>, parent: ClassLoader)
Creates the masking loader over urls, delegating to parent (the game loader).

Types

Link copied to clipboard
enum Regime
Kotlin-identity regime, decided once from (our bundled kotlin C, the parent/game kotlin P).
Link copied to clipboard
The whole snippet chain in ONE hop: game-identity names to the game loader, the rest to masking, and only a miss in both retries a hybrid server's plugins (PluginBridge).

Properties

Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
private val classes: ArrayList<Class<out Any>>
Link copied to clipboard
private open var classLoaderValueMap: ConcurrentHashMap<out Any, out Any>
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
private val defined: Set<String>
Link copied to clipboard
private val libraries: NativeLibraries
Link copied to clipboard
Link copied to clipboard
private val nameAndId: String
Link copied to clipboard
private val nocerts: Array<Certificate>
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
private val parentKotlin: Int
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
private open var scl: ClassLoader
Link copied to clipboard
private open var snippetLoader: ClassLoader
Link copied to clipboard
private val ucp: URLClassPath
Link copied to clipboard
Link copied to clipboard
private val V2_0: Int = 131072
Packed 2.0.0 — the 2.4.

Functions

Link copied to clipboard
open fun addClass(c: Class<out Any>)
Link copied to clipboard
protected open fun addURL(url: URL)
Link copied to clipboard
Link copied to clipboard
open fun close()
Link copied to clipboard
private open fun decideRegime(ours: Int, parent: Int): MaskingClassLoader.Regime
Link copied to clipboard
protected fun defineClass(name: String, b: Array<Byte>, off: Int, len: Int, cs: CodeSource): Class<out Any>
Link copied to clipboard
open fun defineClass0(p: ClassLoader, p1: Class<out Any>, p2: String, p3: Array<Byte>, p4: Int, p5: Int, p6: ProtectionDomain, p7: Boolean, p8: Int, p9: Any): Class<out Any>
Link copied to clipboard
open fun defineClass1(p: ClassLoader, p1: String, p2: Array<Byte>, p3: Int, p4: Int, p5: ProtectionDomain, p6: String): Class<out Any>
Link copied to clipboard
open fun defineClass2(p: ClassLoader, p1: String, p2: ByteBuffer, p3: Int, p4: Int, p5: ProtectionDomain, p6: String): Class<out Any>
Link copied to clipboard
Every binary name this loader has DEFINED (not merely delegated), for the preload working-set capture.
Link copied to clipboard
protected open fun definePackage(name: String, man: Manifest, url: URL): Package
Link copied to clipboard
open fun desiredAssertionStatus(className: String): Boolean
Link copied to clipboard
open fun findBootstrapClassOrNull(name: String): Class<out Any>
Link copied to clipboard
protected open fun findClass(name: String): Class<out Any>
Every masking-owned class is defined HERE (see the class doc for what that buys), which is also what makes every successfully defined name recordable for definedClassNames.
Link copied to clipboard
protected open fun findLibrary(libname: String): String
Link copied to clipboard
protected fun findLoadedClass(name: String): Class<out Any>
Link copied to clipboard
open fun findNative(loader: ClassLoader, clazz: Class<out Any>, entryName: String, javaName: String): Long
Link copied to clipboard
open fun findResource(name: String): URL
Link copied to clipboard
Link copied to clipboard
protected fun findSystemClass(name: String): Class<out Any>
Link copied to clipboard
Link copied to clipboard
open fun getClassLoader(caller: Class<out Any>): ClassLoader
Link copied to clipboard
protected open fun getClassLoadingLock(className: String): Any
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
protected open fun getPackage(name: String): Package
Link copied to clipboard
protected open fun getPackages(): Array<Package>
Link copied to clipboard
protected open fun getPermissions(codesource: CodeSource): PermissionCollection
Link copied to clipboard
Link copied to clipboard
open fun getResource(name: String): URL
Unconditionally child-first, unlike getResource's parent-first default — and unlike loadClass, which stays parent-first for whole namespaces.
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
open fun getSystemResource(name: String): URL
Link copied to clipboard
Link copied to clipboard
Link copied to clipboard
open fun getURLs(): Array<URL>
Link copied to clipboard
Link copied to clipboard
The kotlin RUNTIME namespace that SHARE_ALL delegates to the parent and SPLIT redirects to the game: the stdlib + reflect, NOT the compiler (org.jetbrains.kotlin.*, always masking-owned).
Link copied to clipboard
private open fun kotlinVersionOf(cl: ClassLoader): Int
KotlinVersion.CURRENT as seen through cl, packed into one int (major<<16 | minor<<8 | patch); -1 if that loader has no kotlin — reflective, so a no-kotlin game yields -1 instead of a link error.
Link copied to clipboard
open fun loadClass(name: String): Class<out Any>
protected open fun loadClass(name: String, resolve: Boolean): Class<out Any>
Link copied to clipboard
open fun loadLibrary(fromClass: Class<out Any>, file: File): NativeLibrary
Link copied to clipboard
private open fun mustDelegateToParent(n: String): Boolean
The REPL impl (script host + template) MUST come from our urls so it links the scripting API we own; everything else that needs a single shared identity with the game/JDK goes to the parent.
Link copied to clipboard
fun name(): String
Link copied to clipboard
open fun nameAndId(): String
Link copied to clipboard
open fun nativeLibrariesFor(loader: ClassLoader): NativeLibraries
Link copied to clipboard
open fun newInstance(urls: Array<URL>, parent: ClassLoader): URLClassLoader
Link copied to clipboard
open fun packages(): Stream<Package>
Link copied to clipboard
P as "major.minor" for the snippet compiler's -api-version/-language-version in SPLIT; null in SHARE_ALL, where the two kotlins are one and no pin is needed.
Link copied to clipboard
private open fun probeKotlinVersion(urls: Array<URL>): Int
C: our bundled kotlin version, packed as in kotlinVersionOf.
Link copied to clipboard
Link copied to clipboard
protected open fun registerAsParallelCapable(): Boolean
Link copied to clipboard
protected fun resolveClass(c: Class<out Any>)
Link copied to clipboard
open fun resources(name: String): Stream<URL>
Link copied to clipboard
open fun setClassAssertionStatus(className: String, enabled: Boolean)
Link copied to clipboard
Link copied to clipboard
open fun setPackageAssertionStatus(packageName: String, enabled: Boolean)
Link copied to clipboard
protected fun setSigners(c: Class<out Any>, signers: Array<Any>)
Link copied to clipboard
Parent loader for a compiled snippet: a single SnippetLoader over masking.
Link copied to clipboard
private open fun verString(v: Int): String
Packed ->"major.minor.patch" for logging; null for an absent version.