mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-10-11 20:17:39 +00:00
Properly scope IArguments to the current function call
This is a horrible commit: It's a breaking change in a pretty subtle way, which means it won't be visible while updating. Fortunately I think the only mod on 1.19.4 is Plethora, but other mods (Mek, Advanced Peripherals) may be impacted when they update. Sorry! For some motivation behind the original issue: The default IArguments implementation (VarargArguments) lazily converts Lua arguments to Java ones. This is mostly important when passing tables to Java functions, as we can avoid the conversion entirely if the function uses IArguments.getTableUnsafe. However, this lazy conversion breaks down if IArguments is accessed on a separate thread, as Lua values are not thread-safe. Thus we need to perform this conversion before the cross-thread sharing occurs. Now, ideally this would be an implementation detail and entirely invisible to the user. One approach here would be to only perform this lazy conversion for methods annotated with @LuaFunction(unsafe=true), and have it be eager otherwise. However, the peripheral API gets in the way here, as it means we can no longer inspect the "actual" method being invoked. And so, alas, this must leak into the public API. TLDR: If you're getting weird errors about scope, add an IArguments.escapes() call before sharing the arguments between threads. Closes #1384
This commit is contained in:
@@ -35,9 +35,15 @@ public interface IArguments {
|
||||
*
|
||||
* @param index The argument number.
|
||||
* @return The argument's value, or {@code null} if not present.
|
||||
* @throws LuaException If the argument cannot be converted to Java. This should be thrown in extraneous
|
||||
* circumstances (if the conversion would allocate too much memory) and should
|
||||
* <em>not</em> be thrown if the original argument is not present or is an unsupported
|
||||
* data type (such as a function or userdata).
|
||||
* @throws IllegalStateException If accessing these arguments outside the scope of the original function. See
|
||||
* {@link #escapes()}.
|
||||
*/
|
||||
@Nullable
|
||||
Object get(int index);
|
||||
Object get(int index) throws LuaException;
|
||||
|
||||
/**
|
||||
* Get the type name of the argument at the specific index.
|
||||
@@ -49,9 +55,7 @@ public interface IArguments {
|
||||
* @return The name of this type.
|
||||
* @see LuaValues#getType(Object)
|
||||
*/
|
||||
default String getType(int index) {
|
||||
return LuaValues.getType(get(index));
|
||||
}
|
||||
String getType(int index);
|
||||
|
||||
/**
|
||||
* Drop a number of arguments. The returned arguments instance will access arguments at position {@code i + count},
|
||||
@@ -62,7 +66,14 @@ public interface IArguments {
|
||||
*/
|
||||
IArguments drop(int count);
|
||||
|
||||
default Object[] getAll() {
|
||||
/**
|
||||
* Get an array containing all as {@link Object}s.
|
||||
*
|
||||
* @return All arguments.
|
||||
* @throws LuaException If an error occurred while fetching an argument.
|
||||
* @see #get(int) To get a single argument.
|
||||
*/
|
||||
default Object[] getAll() throws LuaException {
|
||||
var result = new Object[count()];
|
||||
for (var i = 0; i < result.length; i++) result[i] = get(i);
|
||||
return result;
|
||||
@@ -421,4 +432,26 @@ public interface IArguments {
|
||||
default Map<?, ?> optTable(int index, @Nullable Map<Object, Object> def) throws LuaException {
|
||||
return optTable(index).orElse(def);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a version of these arguments which escapes the scope of the current function call.
|
||||
* <p>
|
||||
* Some {@link IArguments} implementations provide a view over the underlying Lua data structures, allowing for
|
||||
* zero-copy implementations of some methods (such as {@link #getTableUnsafe(int)} or {@link #getBytes(int)}).
|
||||
* However, this means the arguments can only be accessed inside the current function call.
|
||||
* <p>
|
||||
* If the arguments escape the scope of the current call (for instance, are later accessed on the main server
|
||||
* thread), then these arguments must be marked as "escaping", which may choose to perform a copy of the underlying
|
||||
* arguments.
|
||||
* <p>
|
||||
* If you are using {@link LuaFunction#mainThread()}, this will be done automatically. However, if you call
|
||||
* {@link ILuaContext#issueMainThreadTask(LuaTask)} (or similar), then you will need to mark arguments as escaping
|
||||
* yourself.
|
||||
*
|
||||
* @return An {@link IArguments} instance which can escape the current scope. May be {@code this}.
|
||||
* @throws LuaException For the same reasons as {@link #get(int)}.
|
||||
*/
|
||||
default IArguments escapes() throws LuaException {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@@ -51,6 +51,11 @@ public final class ObjectArguments implements IArguments {
|
||||
return index >= args.size() ? null : args.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType(int index) {
|
||||
return LuaValues.getType(get(index));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getAll() {
|
||||
return args.toArray();
|
||||
|
Reference in New Issue
Block a user