Skip to content

Commit

Permalink
Rethink how errors are handled
Browse files Browse the repository at this point in the history
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 4, 2019
1 parent 9cdaf26 commit e3cb671
Show file tree
Hide file tree
Showing 6 changed files with 467 additions and 457 deletions.
11 changes: 11 additions & 0 deletions src/main/java/org/squiddev/cobalt/LuaThread.java
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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();
}
}
}
}

Expand Down
5 changes: 5 additions & 0 deletions src/main/java/org/squiddev/cobalt/debug/DebugFrame.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

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

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

void clear() {
func = null;
closure = null;
Expand Down
18 changes: 15 additions & 3 deletions src/main/java/org/squiddev/cobalt/debug/DebugHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/**
Expand Down Expand Up @@ -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 {
Expand All @@ -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
*
Expand Down
Loading

0 comments on commit e3cb671

Please sign in to comment.