ReplHost

object ReplHost

The REPL host. Loaded BY the masking loader (child-first) and reached from ReplBridge on the game loader through the MaskingBridgeImpl adapter (the one reflective hop) — so it can link the Kotlin compiler that lives on the masking loader's urls even though those jars are NOT on the game runtime classpath. After the hop, everything here is ordinary Kotlin.

Compilation and execution are separate (compile / execute) so a lane can compile OFF the tick and run ON it. Each execution runs against a fresh ScriptScope implicit receiver, so the snippet's shadowed println is captured and returned alongside the last expression's value.

Properties

Link copied to clipboard
private val evalSeq: AtomicLong

Per-eval unique id → unique source name → unique script class, and the label a spilled dump is filed under. Minted here so the compiler and the failure report can never disagree about which eval it was.

Link copied to clipboard

The compile classpath the last buildCompiler ran with, so warm can drive a full compile+remap warmup without the gate having to pass it again. Stable across evals (same enumerated game classpath). Real compiles take their own compile argument — this is not an input to them.

Link copied to clipboard

This class's own loader — in dev too: ReplBridge puts the repl classes dir on the masking urls so repl.impl.* resolves child-first. Null only when repl.impl was not masking-loaded (dev without mcp.repl.classes, unit tests), where the regime machinery is inert. See MaskingClassLoader.Regime.

Link copied to clipboard
private val preloadLock: Any
Link copied to clipboard

Functions

Link copied to clipboard

Build the warm K2 compiler (overlay + createCompilationState). Assumes preload already ran (eager path: the preload thread; lazy path: the idempotent call below).

Link copied to clipboard
internal fun compile(code: String, cpFiles: List<File>, killIdField: String, evalId: Int): PlainEngine.Compiled

Compile code. Off-tick; PlainEngine serializes compilation.

Link copied to clipboard
private fun doPreload(): Boolean
Link copied to clipboard
internal fun execute(compiled: PlainEngine.Compiled, code: String, out: Capture): Any

Run a handle from compile, writing the snippet's println into out, and return captured out + => value. On-tick (may yield). The script body IS the class constructor, so constructing it runs it, and PlainEngine.Compiled.Ok.resultType already carries its own ? — nothing here re-adds one.

Link copied to clipboard
private fun guardIterator(raw: Iterator<*>, out: Capture, errored: AtomicBoolean): Iterator<Any?>

Wrap the snippet's cross-tick iterator so a throw mid-drive doesn't discard what it already printed: the (mojmap-remapped) stack is appended to out and the iterator ends cleanly, so the lane returns the partial output together with the error. Without this, a throw in next() would propagate to the lane pump, which completes the future with just the exception text and loses the buffered output. The throw goes through stack() so it's mojmap-remapped like every other throw.

Link copied to clipboard
private fun isBuilderIterator(v: Any): Boolean

True for a cross-tick builder — ours, or the stdlib's when a snippet fully-qualified past the shadow — and false for listOf(...).iterator() and friends, whose value would otherwise be driven away as a generator and returned as "(no output)".

Link copied to clipboard
private fun isSplitRegime(): Boolean

Enum identity comparison is safe here: mustDelegateToParent routes MaskingClassLoader — and its nested Regime — to the game loader, so exactly one Regime class can ever exist.

Link copied to clipboard

Profile-guided preload of the compiler working set. Returns true on a TRAINING launch — preload skipped entirely, so the compiler build loads exactly the true working set for recordWorkingSet to capture; preloading first would make the working set indistinguishable from dead classes. Training is every launch with nothing to replay: no recorded list, a list stamped with another kotlin version, or mcp.preload=false — the only lever that retrains a list the stamp still calls current, for a classpath change the kotlin version cannot see. False only where a list really was preloaded. Idempotent.

Link copied to clipboard

Training-launch capture: write every kotlin / kotlin-compiler class the masking loader has defined (= the true compiler working set, since a training launch runs with preload off) to path, plus the kotlin version stamp doPreload gates on. The set comes from MaskingClassLoader.definedClassNames.

Link copied to clipboard
private fun stampFile(): File?
Link copied to clipboard
fun warm()

Warm the eval path — compile AND run — so the first real eval pays none of it on the tick thread. iterator { yield(1) } is the widest single shape: it compiles a suspend state machine (a superset of a scalar snippet) and is the only one that reaches the snippet loader and the cross-tick path. Running it, not just compiling it, is also what puts those classes in front of recordWorkingSet — what never runs here never enters the preload classlist, and is never preloaded on any later launch either.