From 5bb2e8e8cdd38c1f6bbbecbd6cad77de42bb4f83 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sun, 26 Mar 2023 19:42:55 +0100 Subject: [PATCH] Update Cobalt to 0.7 - Timeouts are now driven by an interrupt system, rather than polling. While we do not impose memory limits, this should close #1333. - Update the table library to largely match Lua 5.4: - Add table.move - Table methods (with the exception of foreach/foreachi) now use metamethods (closes #1088). There's still some remaining quirks (for instance, table.insert accepts values out-of-bounds), but I think that's fine. - Cobalt's threaded-coroutine system is gone (load now supports yielding), so we no longer track coroutine metrics. - Type errors now use __name. See #1355, though this does not apply to CC methods (either on the Java or CraftOS side), so is not enough to resolve it. See https://github.com/SquidDev/Cobalt/compare/v0.6.0...v0.7.0 for the full delta. --- doc/reference/feature_compat.md | 16 +- gradle/libs.versions.toml | 2 +- .../computercraft/data/LanguageProvider.java | 2 - .../core/computer/TimeoutState.java | 38 ++- .../core/lua/CobaltLuaMachine.java | 235 ++++-------------- .../computercraft/core/lua/TableImpl.java | 6 +- .../core/lua/VarargArguments.java | 12 +- .../computercraft/core/metrics/Metrics.java | 3 - .../core/ComputerTestDelegate.java | 20 +- 9 files changed, 107 insertions(+), 227 deletions(-) diff --git a/doc/reference/feature_compat.md b/doc/reference/feature_compat.md index 0e66a04a0f..c1da32632a 100644 --- a/doc/reference/feature_compat.md +++ b/doc/reference/feature_compat.md @@ -21,7 +21,7 @@ CC: Tweaked is based off of the Cobalt Lua runtime, which uses Lua 5.1. However, | Hex literal fractional/exponent parts | ✔ | | | Empty statements | ❌ | | | `__len` metamethod | ✔ | | -| `__ipairs` metamethod | ❌ | | +| `__ipairs` metamethod | ❌ | Deprecated in Lua 5.3. `ipairs` uses `__len`/`__index` instead. | | `__pairs` metamethod | ✔ | | | `bit32` library | ✔ | | | `collectgarbage` isrunning, generational, incremental options | ❌ | `collectgarbage` does not exist in CC:T. | @@ -32,8 +32,8 @@ CC: Tweaked is based off of the Cobalt Lua runtime, which uses Lua 5.1. However, | `rawlen` function | ✔ | | | Negative index to `select` | ✔ | | | Removed `unpack` | 🔶 | Only if `disable_lua51_features` is enabled in the configuration. | -| Arguments to `xpcall` | ❌ | | -| Second return value from `coroutine.running` | ❌ | | +| Arguments to `xpcall` | ✔ | | +| Second return value from `coroutine.running` | ✔ | | | Removed `module` | ✔ | | | `package.loaders` -> `package.searchers` | ❌ | | | Second argument to loader functions | ✔ | | @@ -41,7 +41,7 @@ CC: Tweaked is based off of the Cobalt Lua runtime, which uses Lua 5.1. However, | `package.searchpath` | ✔ | | | Removed `package.seeall` | ✔ | | | `string.dump` on functions with upvalues (blanks them out) | ✔ | | -| `string.rep` separator | ❌ | | +| `string.rep` separator | ✔ | | | `%g` match group | ❌ | | | Removal of `%z` match group | ❌ | | | Removed `table.maxn` | 🔶 | Only if `disable_lua51_features` is enabled in the configuration. | @@ -64,7 +64,7 @@ CC: Tweaked is based off of the Cobalt Lua runtime, which uses Lua 5.1. However, | Removal of ambiguity error | ❌ | | | Identifiers may no longer use locale-dependent letters | ✔ | | | Ephemeron tables | ❌ | | -| Identical functions may be reused | ❌ | | +| Identical functions may be reused | ❌ | Removed in Lua 5.4 | | Generational garbage collector | ❌ | Cobalt uses the built-in Java garbage collector. | ## Lua 5.3 @@ -75,10 +75,10 @@ CC: Tweaked is based off of the Cobalt Lua runtime, which uses Lua 5.1. However, | `\u{XXX}` escape sequence | ✔ | | | `utf8` library | ✔ | | | removed `__ipairs` metamethod | ✔ | | -| `coroutine.isyieldable` | ❌ | | +| `coroutine.isyieldable` | ✔ | | | `string.dump` strip argument | ✔ | | | `string.pack`/`string.unpack`/`string.packsize` | ✔ | | -| `table.move` | ❌ | | +| `table.move` | ✔ | | | `math.atan2` -> `math.atan` | ❌ | | | Removed `math.frexp`, `math.ldexp`, `math.pow`, `math.cosh`, `math.sinh`, `math.tanh` | ❌ | | | `math.maxinteger`/`math.mininteger` | ❌ | | @@ -87,7 +87,7 @@ CC: Tweaked is based off of the Cobalt Lua runtime, which uses Lua 5.1. However, | `math.ult` | ❌ | | | Removed `bit32` library | ❌ | | | Remove `*` from `file:read` modes | ✔ | | -| Metamethods respected in `table.*`, `ipairs` | 🔶 | Only `__lt` is respected. | +| Metamethods respected in `table.*`, `ipairs` | ✔ | | ## Lua 5.0 | Feature | Supported? | Notes | diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f1607a63e5..47ef19d6e4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -19,7 +19,7 @@ parchmentMc = "1.19.3" asm = "9.3" autoService = "1.0.1" checkerFramework = "3.32.0" -cobalt = "0.6.0" +cobalt = "0.7.0" fastutil = "8.5.9" guava = "31.1-jre" jetbrainsAnnotations = "24.0.1" diff --git a/projects/common/src/main/java/dan200/computercraft/data/LanguageProvider.java b/projects/common/src/main/java/dan200/computercraft/data/LanguageProvider.java index 4a99c1ed4c..925614a6e9 100644 --- a/projects/common/src/main/java/dan200/computercraft/data/LanguageProvider.java +++ b/projects/common/src/main/java/dan200/computercraft/data/LanguageProvider.java @@ -178,8 +178,6 @@ private void addTranslations() { add(Metrics.HTTP_DOWNLOAD, "HTTP download"); add(Metrics.WEBSOCKET_INCOMING, "Websocket incoming"); add(Metrics.WEBSOCKET_OUTGOING, "Websocket outgoing"); - add(Metrics.COROUTINES_CREATED, "Coroutines created"); - add(Metrics.COROUTINES_DISPOSED, "Coroutines disposed"); add(Metrics.TURTLE_OPS, "Turtle operations"); add(AggregatedMetric.TRANSLATION_PREFIX + Aggregate.MAX.id(), "%s (max)"); diff --git a/projects/core/src/main/java/dan200/computercraft/core/computer/TimeoutState.java b/projects/core/src/main/java/dan200/computercraft/core/computer/TimeoutState.java index 6c12d67944..b701793ac1 100644 --- a/projects/core/src/main/java/dan200/computercraft/core/computer/TimeoutState.java +++ b/projects/core/src/main/java/dan200/computercraft/core/computer/TimeoutState.java @@ -4,9 +4,13 @@ package dan200.computercraft.core.computer; +import com.google.errorprone.annotations.concurrent.GuardedBy; import dan200.computercraft.core.lua.ILuaMachine; import dan200.computercraft.core.lua.MachineResult; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; import java.util.concurrent.TimeUnit; /** @@ -48,6 +52,8 @@ public final class TimeoutState { public static final String ABORT_MESSAGE = "Too long without yielding"; private final ComputerThread scheduler; + @GuardedBy("this") + private final List listeners = new ArrayList<>(0); private boolean paused; private boolean softAbort; @@ -92,8 +98,15 @@ public synchronized void refresh() { // Important: The weird arithmetic here is important, as nanoTime may return negative values, and so we // need to handle overflow. var now = System.nanoTime(); - if (!paused) paused = currentDeadline - now <= 0 && scheduler.hasPendingWork(); // now >= currentDeadline - if (!softAbort) softAbort = now - cumulativeStart - TIMEOUT >= 0; // now - cumulativeStart >= TIMEOUT + var changed = false; + if (!paused && (paused = currentDeadline - now <= 0 && scheduler.hasPendingWork())) { // now >= currentDeadline + changed = true; + } + if (!softAbort && (softAbort = now - cumulativeStart - TIMEOUT >= 0)) { // now - cumulativeStart >= TIMEOUT + changed = true; + } + + if (changed) updateListeners(); } /** @@ -131,6 +144,9 @@ public boolean isHardAborted() { */ void hardAbort() { softAbort = hardAbort = true; + synchronized (this) { + updateListeners(); + } } /** @@ -153,6 +169,7 @@ synchronized void pauseTimer() { // We set the cumulative time to difference between current time and "nominal start time". cumulativeElapsed = System.nanoTime() - cumulativeStart; paused = false; + updateListeners(); } /** @@ -161,5 +178,22 @@ synchronized void pauseTimer() { synchronized void stopTimer() { cumulativeElapsed = 0; paused = softAbort = hardAbort = false; + updateListeners(); + } + + @GuardedBy("this") + private void updateListeners() { + for (var listener : listeners) listener.run(); + } + + public synchronized void addListener(Runnable listener) { + Objects.requireNonNull(listener, "listener cannot be null"); + listeners.add(listener); + listener.run(); + } + + public synchronized void removeListener(Runnable listener) { + Objects.requireNonNull(listener, "listener cannot be null"); + listeners.remove(listener); } } diff --git a/projects/core/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java b/projects/core/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java index 3c891a2421..877e2f7a15 100644 --- a/projects/core/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java +++ b/projects/core/src/main/java/dan200/computercraft/core/lua/CobaltLuaMachine.java @@ -13,19 +13,15 @@ import dan200.computercraft.core.asm.LuaMethod; import dan200.computercraft.core.asm.ObjectSource; import dan200.computercraft.core.computer.TimeoutState; -import dan200.computercraft.core.metrics.Metrics; import dan200.computercraft.core.util.Nullability; -import dan200.computercraft.core.util.ThreadUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.squiddev.cobalt.*; import org.squiddev.cobalt.compiler.CompileException; import org.squiddev.cobalt.compiler.LoadState; -import org.squiddev.cobalt.debug.DebugFrame; -import org.squiddev.cobalt.debug.DebugHandler; -import org.squiddev.cobalt.debug.DebugState; -import org.squiddev.cobalt.lib.*; -import org.squiddev.cobalt.lib.platform.VoidResourceManipulator; +import org.squiddev.cobalt.interrupt.InterruptAction; +import org.squiddev.cobalt.lib.Bit32Lib; +import org.squiddev.cobalt.lib.CoreLibraries; import javax.annotation.Nullable; import java.io.IOException; @@ -33,56 +29,41 @@ import java.io.Serial; import java.nio.ByteBuffer; import java.util.*; -import java.util.concurrent.SynchronousQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; import static org.squiddev.cobalt.ValueFactory.valueOf; import static org.squiddev.cobalt.ValueFactory.varargsOf; -import static org.squiddev.cobalt.debug.DebugFrame.FLAG_HOOKED; -import static org.squiddev.cobalt.debug.DebugFrame.FLAG_HOOKYIELD; public class CobaltLuaMachine implements ILuaMachine { private static final Logger LOG = LoggerFactory.getLogger(CobaltLuaMachine.class); - private static final ThreadPoolExecutor COROUTINES = new ThreadPoolExecutor( - 0, Integer.MAX_VALUE, - 5L, TimeUnit.MINUTES, - new SynchronousQueue<>(), - ThreadUtils.factory("Coroutine") - ); - private static final LuaMethod FUNCTION_METHOD = (target, context, args) -> ((ILuaFunction) target).call(args); private final TimeoutState timeout; - private final TimeoutDebugHandler debug; + private final Runnable timeoutListener = this::updateTimeout; private final ILuaContext context; - private @Nullable LuaState state; - private @Nullable LuaTable globals; + private final LuaState state; + private final LuaThread mainRoutine; + + private volatile boolean isDisposed = false; + private boolean thrownSoftAbort; - private @Nullable LuaThread mainRoutine = null; private @Nullable String eventFilter = null; public CobaltLuaMachine(MachineEnvironment environment, InputStream bios) throws MachineException, IOException { timeout = environment.timeout(); context = environment.context(); - debug = new TimeoutDebugHandler(); // Create an environment to run in - var metrics = environment.metrics(); var state = this.state = LuaState.builder() - .resourceManipulator(new VoidResourceManipulator()) - .debug(debug) - .coroutineExecutor(command -> { - metrics.observe(Metrics.COROUTINES_CREATED); - COROUTINES.execute(() -> { - try { - command.run(); - } finally { - metrics.observe(Metrics.COROUTINES_DISPOSED); - } - }); + .interruptHandler(() -> { + if (timeout.isHardAborted() || isDisposed) throw new HardAbortError(); + if (timeout.isSoftAborted() && !thrownSoftAbort) { + thrownSoftAbort = true; + throw new LuaError(TimeoutState.ABORT_MESSAGE); + } + + return timeout.isPaused() ? InterruptAction.SUSPEND : InterruptAction.CONTINUE; }) .errorReporter((e, msg) -> { if (LOG.isErrorEnabled(Logging.VM_ERROR)) { @@ -91,35 +72,16 @@ public CobaltLuaMachine(MachineEnvironment environment, InputStream bios) throws }) .build(); - globals = new LuaTable(); - state.setupThread(globals); - - // Add basic libraries - globals.load(state, new BaseLib()); - globals.load(state, new TableLib()); - globals.load(state, new StringLib()); - globals.load(state, new MathLib()); - globals.load(state, new CoroutineLib()); - globals.load(state, new Bit32Lib()); - globals.load(state, new Utf8Lib()); - globals.load(state, new DebugLib()); - - // Remove globals we don't want to expose - globals.rawset("collectgarbage", Constants.NIL); - globals.rawset("dofile", Constants.NIL); - globals.rawset("loadfile", Constants.NIL); - globals.rawset("print", Constants.NIL); - - // Add version globals - globals.rawset("_VERSION", valueOf("Lua 5.1")); + // Set up our global table. + var globals = state.getMainThread().getfenv(); + CoreLibraries.debugGlobals(state); + Bit32Lib.add(state, globals); globals.rawset("_HOST", valueOf(environment.hostString())); globals.rawset("_CC_DEFAULT_SETTINGS", valueOf(CoreConfig.defaultComputerSettings)); - if (CoreConfig.disableLua51Features) { - globals.rawset("_CC_DISABLE_LUA51_FEATURES", Constants.TRUE); - } + if (CoreConfig.disableLua51Features) globals.rawset("_CC_DISABLE_LUA51_FEATURES", Constants.TRUE); // Add default APIs - for (var api : environment.apis()) addAPI(api); + for (var api : environment.apis()) addAPI(globals, api); // And load the BIOS try { @@ -128,11 +90,11 @@ public CobaltLuaMachine(MachineEnvironment environment, InputStream bios) throws } catch (CompileException e) { throw new MachineException(Nullability.assertNonNull(e.getMessage())); } - } - private void addAPI(ILuaAPI api) { - if (globals == null) throw new IllegalStateException("Machine has been closed"); + timeout.addListener(timeoutListener); + } + private void addAPI(LuaTable globals, ILuaAPI api) { // Add the methods of an API to the global table var table = wrapLuaObject(api); if (table == null) { @@ -144,42 +106,41 @@ private void addAPI(ILuaAPI api) { for (var name : names) globals.rawset(name, table); } + private void updateTimeout() { + if (isDisposed) return; + if (!timeout.isSoftAborted()) thrownSoftAbort = false; + if (timeout.isSoftAborted() || timeout.isPaused()) state.interrupt(); + } + @Override public MachineResult handleEvent(@Nullable String eventName, @Nullable Object[] arguments) { - if (mainRoutine == null || state == null) throw new IllegalStateException("Machine has been closed"); + if (isDisposed) throw new IllegalStateException("Machine has been closed"); if (eventFilter != null && eventName != null && !eventName.equals(eventFilter) && !eventName.equals("terminate")) { return MachineResult.OK; } - // If the soft abort has been cleared then we can reset our flag. - timeout.refresh(); - if (!timeout.isSoftAborted()) debug.thrownSoftAbort = false; - try { - Varargs resumeArgs = Constants.NONE; - if (eventName != null) { - resumeArgs = varargsOf(valueOf(eventName), toValues(arguments)); - } + var resumeArgs = eventName == null ? Constants.NONE : varargsOf(valueOf(eventName), toValues(arguments)); // Resume the current thread, or the main one when first starting off. var thread = state.getCurrentThread(); if (thread == null || thread == state.getMainThread()) thread = mainRoutine; var results = LuaThread.run(thread, resumeArgs); - if (timeout.isHardAborted()) throw HardAbortError.INSTANCE; + if (timeout.isHardAborted()) throw new HardAbortError(); if (results == null) return MachineResult.PAUSE; var filter = results.first(); eventFilter = filter.isString() ? filter.toString() : null; - if (mainRoutine.getStatus().equals("dead")) { + if (!mainRoutine.isAlive()) { close(); return MachineResult.GENERIC_ERROR; } else { return MachineResult.OK; } - } catch (HardAbortError | InterruptedException e) { + } catch (HardAbortError e) { close(); return MachineResult.TIMEOUT; } catch (LuaError e) { @@ -191,23 +152,13 @@ public MachineResult handleEvent(@Nullable String eventName, @Nullable Object[] @Override public void printExecutionState(StringBuilder out) { - var state = this.state; - if (state == null) { - out.append("CobaltLuaMachine is terminated\n"); - } else { - state.printExecutionState(out); - } } @Override public void close() { - var state = this.state; - if (state == null) return; - - state.abandon(); - mainRoutine = null; - this.state = null; - globals = null; + isDisposed = true; + state.interrupt(); + timeout.removeListener(timeoutListener); } @Nullable @@ -228,7 +179,7 @@ private LuaTable wrapLuaObject(Object object) { : new ResultInterpreterFunction(this, method.getMethod(), instance, context, method.getName()))); try { - if (table.keyCount() == 0) return null; + if (table.next(Constants.NIL).first().isNil()) return null; } catch (LuaError ignored) { // next should never throw on nil. } @@ -241,9 +192,7 @@ private LuaValue toValue(@Nullable Object object, @Nullable IdentityHashMap objects) { - switch (value.type()) { - case Constants.TNIL: - case Constants.TNONE: - return null; - case Constants.TINT: - case Constants.TNUMBER: - return value.toDouble(); - case Constants.TBOOLEAN: - return value.toBoolean(); - case Constants.TSTRING: - return value.toString(); - case Constants.TTABLE: { + return switch (value.type()) { + case Constants.TNIL -> null; + case Constants.TINT, Constants.TNUMBER -> value.toDouble(); + case Constants.TBOOLEAN -> value.toBoolean(); + case Constants.TSTRING -> value.toString(); + case Constants.TTABLE -> { // Table: // Start remembering stuff if (objects == null) { objects = new IdentityHashMap<>(1); } else { var existing = objects.get(value); - if (existing != null) return existing; + if (existing != null) yield existing; } Map table = new HashMap<>(); objects.put(value, table); @@ -361,11 +304,10 @@ static Object toObject(LuaValue value, @Nullable IdentityHashMap null; + }; } static Object[] toObjects(Varargs values) { @@ -375,83 +317,12 @@ static Object[] toObjects(Varargs values) { return objects; } - /** - * A {@link DebugHandler} which observes the {@link TimeoutState} and responds accordingly. - */ - private class TimeoutDebugHandler extends DebugHandler { - private final TimeoutState timeout; - private int count = 0; - boolean thrownSoftAbort; - - private boolean isPaused; - private int oldFlags; - private boolean oldInHook; - - TimeoutDebugHandler() { - timeout = CobaltLuaMachine.this.timeout; - } - - @Override - public void onInstruction(DebugState ds, DebugFrame di, int pc) throws LuaError, UnwindThrowable { - di.pc = pc; - - if (isPaused) resetPaused(ds, di); - - // We check our current pause/abort state every 128 instructions. - if ((count = (count + 1) & 127) == 0) { - if (timeout.isHardAborted() || state == null) throw HardAbortError.INSTANCE; - if (timeout.isPaused()) handlePause(ds, di); - if (timeout.isSoftAborted()) handleSoftAbort(); - } - - super.onInstruction(ds, di, pc); - } - - @Override - public void poll() throws LuaError { - var state = CobaltLuaMachine.this.state; - if (timeout.isHardAborted() || state == null) throw HardAbortError.INSTANCE; - if (timeout.isPaused()) LuaThread.suspendBlocking(state); - if (timeout.isSoftAborted()) handleSoftAbort(); - } - - private void resetPaused(DebugState ds, DebugFrame di) { - // Restore the previous paused state - isPaused = false; - ds.inhook = oldInHook; - di.flags = oldFlags; - } - - private void handleSoftAbort() throws LuaError { - // If we already thrown our soft abort error then don't do it again. - if (thrownSoftAbort) return; - - thrownSoftAbort = true; - throw new LuaError(TimeoutState.ABORT_MESSAGE); - } - - private void handlePause(DebugState ds, DebugFrame di) throws LuaError, UnwindThrowable { - // Preserve the current state - isPaused = true; - oldInHook = ds.inhook; - oldFlags = di.flags; - - // Suspend the state. This will probably throw, but we need to handle the case where it won't. - di.flags |= FLAG_HOOKYIELD | FLAG_HOOKED; - LuaThread.suspend(ds.getLuaState()); - resetPaused(ds, di); - } - } - private static final class HardAbortError extends Error { @Serial private static final long serialVersionUID = 7954092008586367501L; - @SuppressWarnings("StaticAssignmentOfThrowable") - static final HardAbortError INSTANCE = new HardAbortError(); - private HardAbortError() { - super("Hard Abort", null, true, false); + super("Hard Abort"); } } } diff --git a/projects/core/src/main/java/dan200/computercraft/core/lua/TableImpl.java b/projects/core/src/main/java/dan200/computercraft/core/lua/TableImpl.java index 0e0d42c181..68fe755dcb 100644 --- a/projects/core/src/main/java/dan200/computercraft/core/lua/TableImpl.java +++ b/projects/core/src/main/java/dan200/computercraft/core/lua/TableImpl.java @@ -27,11 +27,7 @@ class TableImpl implements dan200.computercraft.api.lua.LuaTable @Override public int size() { checkValid(); - try { - return table.keyCount(); - } catch (LuaError e) { - throw new IllegalStateException(e); - } + return table.size(); } @Override diff --git a/projects/core/src/main/java/dan200/computercraft/core/lua/VarargArguments.java b/projects/core/src/main/java/dan200/computercraft/core/lua/VarargArguments.java index 783fabe2a4..5a8271bb27 100644 --- a/projects/core/src/main/java/dan200/computercraft/core/lua/VarargArguments.java +++ b/projects/core/src/main/java/dan200/computercraft/core/lua/VarargArguments.java @@ -73,20 +73,16 @@ public long getLong(int index) throws LuaException { @Override public ByteBuffer getBytes(int index) throws LuaException { var value = varargs.arg(index + 1); - if (!(value instanceof LuaBaseString)) throw LuaValues.badArgument(index, "string", value.typeName()); - - var str = ((LuaBaseString) value).strvalue(); - return ByteBuffer.wrap(str.bytes, str.offset, str.length).asReadOnlyBuffer(); + if (!(value instanceof LuaString str)) throw LuaValues.badArgument(index, "string", value.typeName()); + return str.toBuffer(); } @Override public Optional optBytes(int index) throws LuaException { var value = varargs.arg(index + 1); if (value.isNil()) return Optional.empty(); - if (!(value instanceof LuaBaseString)) throw LuaValues.badArgument(index, "string", value.typeName()); - - var str = ((LuaBaseString) value).strvalue(); - return Optional.of(ByteBuffer.wrap(str.bytes, str.offset, str.length).asReadOnlyBuffer()); + if (!(value instanceof LuaString str)) throw LuaValues.badArgument(index, "string", value.typeName()); + return Optional.of(str.toBuffer()); } @Override diff --git a/projects/core/src/main/java/dan200/computercraft/core/metrics/Metrics.java b/projects/core/src/main/java/dan200/computercraft/core/metrics/Metrics.java index 4eb2e3441e..9039670261 100644 --- a/projects/core/src/main/java/dan200/computercraft/core/metrics/Metrics.java +++ b/projects/core/src/main/java/dan200/computercraft/core/metrics/Metrics.java @@ -24,9 +24,6 @@ private Metrics() { public static final Metric.Event WEBSOCKET_INCOMING = new Metric.Event("websocket_incoming", "bytes", Metric::formatBytes); public static final Metric.Event WEBSOCKET_OUTGOING = new Metric.Event("websocket_outgoing", "bytes", Metric::formatBytes); - public static final Metric.Counter COROUTINES_CREATED = new Metric.Counter("coroutines_created"); - public static final Metric.Counter COROUTINES_DISPOSED = new Metric.Counter("coroutines_dead"); - public static final Metric.Counter TURTLE_OPS = new Metric.Counter("turtle_ops"); /** diff --git a/projects/core/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java b/projects/core/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java index 3e8f83f61f..ce832e54be 100644 --- a/projects/core/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java +++ b/projects/core/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java @@ -27,11 +27,12 @@ import org.opentest4j.TestAbortedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.squiddev.cobalt.*; +import org.squiddev.cobalt.LuaState; +import org.squiddev.cobalt.LuaString; +import org.squiddev.cobalt.LuaThread; import org.squiddev.cobalt.debug.DebugFrame; import org.squiddev.cobalt.debug.DebugHook; import org.squiddev.cobalt.debug.DebugState; -import org.squiddev.cobalt.function.OneArgFunction; import javax.annotation.Nullable; import java.io.File; @@ -480,13 +481,8 @@ private class CoverageLuaMachine extends CobaltLuaMachine { CoverageLuaMachine(MachineEnvironment environment, InputStream bios) throws MachineException, IOException { super(environment, bios); - LuaTable globals; LuaThread mainRoutine; try { - var globalField = CobaltLuaMachine.class.getDeclaredField("globals"); - globalField.setAccessible(true); - globals = (LuaTable) globalField.get(this); - var threadField = CobaltLuaMachine.class.getDeclaredField("mainRoutine"); threadField.setAccessible(true); mainRoutine = (LuaThread) threadField.get(this); @@ -513,21 +509,13 @@ public void onLine(LuaState state, DebugState ds, DebugFrame frame, int newLine) if (frame.closure == null) return; var proto = frame.closure.getPrototype(); - if (!proto.source.startsWith('@')) return; + if (!proto.source.startsWith((byte) '@')) return; var map = coverage.computeIfAbsent(proto.source, x -> new Int2IntArrayMap()); map.put(newLine, map.get(newLine) + 1); } }; - ((LuaTable) globals.rawget("coroutine")).rawset("create", new OneArgFunction() { - @Override - public LuaValue call(LuaState state, LuaValue arg) throws LuaError { - var thread = new LuaThread(state, arg.checkFunction(), state.getCurrentThread().getfenv()); - thread.getDebugState().setHook(hook, false, true, false, 0); - return thread; - } - }); mainRoutine.getDebugState().setHook(hook, false, true, false, 0); } }