Skip to content
Permalink
Browse files

Rethink how errors are handled

This changes the error handling to be closer to PUC Lua's
implementation: raising an error just "jumps" to the location of pcall.
From there, we call the error function, and then unwind the stack,
closing any upvalues.

This has the advantage that the callstack of coroutines is maintained,
even if they error, as the handles are no longer popped.

One thing to be aware of here is that return hooks are no longer called
on errors. While this may be a little counter-intuitive, it is
consistent with how PUC Lua operates.

Note, Lua actually calls the error handler when throwing the error,
rather than when catching it. However, this way means we don't need to
thread a LuaState everywhere we want to throw an error.
  • Loading branch information...
SquidDev committed Feb 3, 2019
1 parent 9cdaf26 commit e3cb671f19556d8b849379a371f765e65df0b0ee
@@ -266,6 +266,7 @@ public synchronized void run() {
args = Constants.NONE;
result = function.invoke(state, a);
} catch (LuaError e) {
e.fillTraceback(state);
error = e.value;
} catch (StackOverflowError e) {
error = valueOf("stack overflow");
@@ -274,6 +275,16 @@ public synchronized void run() {
} finally {
markDead();
notify();

LuaThread thread = this.thread.get();
if (thread != null) {
DebugState ds = DebugHandler.getDebugState(thread);
for (int i = 0; ; i++) {
DebugFrame di = ds.getDebugInfo(i);
if (di == null) break;
di.cleanup();
}
}
}
}

@@ -30,6 +30,7 @@
import org.squiddev.cobalt.Varargs;
import org.squiddev.cobalt.function.LuaClosure;
import org.squiddev.cobalt.function.LuaFunction;
import org.squiddev.cobalt.function.LuaInterpreter;
import org.squiddev.cobalt.function.Upvalue;

/**
@@ -87,6 +88,10 @@ void setFunction(LuaFunction func) {
this.func = func;
}

public void cleanup() {
LuaInterpreter.closeAll(stackUpvalues);
}

void clear() {
func = null;
closure = null;
@@ -58,11 +58,13 @@ protected DebugHandler() {
* @param func the function called
* @throws LuaError On a runtime error.
*/
public void onCall(DebugState ds, LuaFunction func) throws LuaError {
public DebugFrame onCall(DebugState ds, LuaFunction func) throws LuaError {
DebugFrame di = ds.pushJavaInfo();
di.setFunction(func);

if (!ds.inhook && ds.hookcall) ds.hookCall(di);

return di;
}

/**
@@ -92,10 +94,10 @@ public DebugFrame onCall(DebugState ds, LuaClosure func, Varargs args, LuaValue[
}

/**
* Called by Closures and recursing java functions on return
* Called by Closures and recurring Java functions on return
*
* @param ds Debug state
* @throws LuaError On a runtime error.
* @throws LuaError On a runtime error within the hook.
*/
public void onReturn(DebugState ds) throws LuaError {
try {
@@ -105,6 +107,16 @@ public void onReturn(DebugState ds) throws LuaError {
}
}

/**
* Called by Closures and recurring Java functions on return when a runtime error
* occurred (and thus the hook should not be called).
*
* @param ds Debug state
*/
public void onReturnError(DebugState ds) {
ds.popInfo();
}

/**
* Called by Closures on bytecode execution
*
Oops, something went wrong.

0 comments on commit e3cb671

Please sign in to comment.
You can’t perform that action at this time.