diff --git a/README.html b/README.html
index 52a5b5d1..c28d45fa 100644
--- a/README.html
+++ b/README.html
@@ -910,6 +910,7 @@ Files are no longer hosted at LuaForge.
Implement formatting with os.date(), and table argument for os.time().
Refactor APIs related to compiling and loading scripts.
Let errors thrown in debug hooks bubble up to the running coroutine.
+Make error function in xpcall per-thread instead of per-globals.
diff --git a/src/core/org/luaj/vm2/Globals.java b/src/core/org/luaj/vm2/Globals.java
index bf98bdaf..db31f132 100644
--- a/src/core/org/luaj/vm2/Globals.java
+++ b/src/core/org/luaj/vm2/Globals.java
@@ -136,9 +136,6 @@ public class Globals extends LuaTable {
/** The DebugLib instance loaded into this Globals, or null if debugging is not enabled */
public DebugLib debuglib;
- /** The current error handler for this Globals */
- public LuaValue errorfunc;
-
/** Interface for module that converts a Prototype into a LuaFunction with an environment. */
public interface Loader {
/** Convert the prototype into a LuaFunction with the supplied environment. */
diff --git a/src/core/org/luaj/vm2/LuaClosure.java b/src/core/org/luaj/vm2/LuaClosure.java
index 22e54db2..c257d386 100644
--- a/src/core/org/luaj/vm2/LuaClosure.java
+++ b/src/core/org/luaj/vm2/LuaClosure.java
@@ -519,16 +519,18 @@ public class LuaClosure extends LuaFunction {
* @param msg the message to use in error hook processing.
* */
String errorHook(String msg) {
- if (globals == null || globals.errorfunc == null)
- return msg;
- LuaValue errfunc = globals.errorfunc;
- globals.errorfunc = null;
+ if (globals == null ) return msg;
+ final LuaThread running = globals.running;
+ if (running == null) return msg;
+ final LuaValue errfunc = running.errorfunc;
+ if (errfunc == null) return msg;
+ running.errorfunc = null;
try {
return errfunc.call( LuaValue.valueOf(msg) ).tojstring();
} catch ( Throwable t ) {
return "error in error handling";
} finally {
- globals.errorfunc = errfunc;
+ running.errorfunc = errfunc;
}
}
@@ -536,8 +538,6 @@ public class LuaClosure extends LuaFunction {
le.fileline = (p.source != null? p.source.tojstring(): "?") + ":"
+ (p.lineinfo != null && pc >= 0 && pc < p.lineinfo.length? String.valueOf(p.lineinfo[pc]): "?");
le.traceback = errorHook(le.getMessage());
- if (globals != null && globals.debuglib != null)
- le.traceback = le.traceback + "\n" + globals.debuglib.traceback(le.level);
}
private UpValue findupval(LuaValue[] stack, short idx, UpValue[] openups) {
@@ -548,7 +548,7 @@ public class LuaClosure extends LuaFunction {
for (int i = 0; i < n; ++i)
if (openups[i] == null)
return openups[i] = new UpValue(stack, idx);
- this.error("No space for upvalue");
+ error("No space for upvalue");
return null;
}
diff --git a/src/core/org/luaj/vm2/LuaThread.java b/src/core/org/luaj/vm2/LuaThread.java
index 0bee9bb8..1575a600 100644
--- a/src/core/org/luaj/vm2/LuaThread.java
+++ b/src/core/org/luaj/vm2/LuaThread.java
@@ -93,8 +93,12 @@ public class LuaThread extends LuaValue {
public final Globals globals;
- // Hook function control state used by debug lib.
+ /** Hook function control state used by debug lib. */
public LuaValue hookfunc;
+
+ /** Error message handler for this thread, if any. */
+ public LuaValue errorfunc;
+
public boolean hookline;
public boolean hookcall;
public boolean hookrtrn;
diff --git a/src/core/org/luaj/vm2/lib/BaseLib.java b/src/core/org/luaj/vm2/lib/BaseLib.java
index 28f17145..5ad69a15 100644
--- a/src/core/org/luaj/vm2/lib/BaseLib.java
+++ b/src/core/org/luaj/vm2/lib/BaseLib.java
@@ -29,6 +29,7 @@ import org.luaj.vm2.Lua;
import org.luaj.vm2.LuaError;
import org.luaj.vm2.LuaString;
import org.luaj.vm2.LuaTable;
+import org.luaj.vm2.LuaThread;
import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs;
@@ -213,7 +214,13 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
if (globals != null && globals.debuglib != null)
globals.debuglib.onCall(this);
try {
- return pcall(func,args.subargs(2),null);
+ return varargsOf(TRUE, func.invoke(args.subargs(2)));
+ } catch ( LuaError le ) {
+ final String m = le.getMessage();
+ return varargsOf(FALSE, m!=null? valueOf(m): NIL);
+ } catch ( Exception e ) {
+ final String m = e.getMessage();
+ return varargsOf(FALSE, valueOf(m!=null? m: e.toString()));
} finally {
if (globals != null && globals.debuglib != null)
globals.debuglib.onReturn();
@@ -353,13 +360,26 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
// "xpcall", // (f, err) -> result1, ...
final class xpcall extends VarArgFunction {
public Varargs invoke(Varargs args) {
- if (globals != null && globals.debuglib != null)
- globals.debuglib.onCall(this);
+ final LuaThread t = globals.running;
+ final LuaValue preverror = t.errorfunc;
+ t.errorfunc = args.checkvalue(2);
try {
- return pcall(args.arg1(),args.subargs(3),args.checkvalue(2));
- } finally {
if (globals != null && globals.debuglib != null)
- globals.debuglib.onReturn();
+ globals.debuglib.onCall(this);
+ try {
+ return varargsOf(TRUE, args.arg1().invoke(args.subargs(3)));
+ } catch ( LuaError le ) {
+ final String m = le.getMessage();
+ return varargsOf(FALSE, m!=null? valueOf(m): NIL);
+ } catch ( Exception e ) {
+ final String m = e.getMessage();
+ return varargsOf(FALSE, valueOf(m!=null? m: e.toString()));
+ } finally {
+ if (globals != null && globals.debuglib != null)
+ globals.debuglib.onReturn();
+ }
+ } finally {
+ t.errorfunc = preverror;
}
}
}
@@ -396,24 +416,6 @@ public class BaseLib extends TwoArgFunction implements ResourceFinder {
return args.checktable(1).inext(args.arg(2));
}
}
-
- public Varargs pcall(LuaValue func, Varargs args, LuaValue errorfunc) {
- try {
- LuaValue olderr = globals.errorfunc;
- globals.errorfunc = errorfunc;
- try {
- return varargsOf(LuaValue.TRUE, func.invoke(args));
- } finally {
- globals.errorfunc = olderr;
- }
- } catch ( LuaError le ) {
- String m = le.getMessage();
- return varargsOf(FALSE, m!=null? valueOf(m): NIL);
- } catch ( Exception e ) {
- String m = e.getMessage();
- return varargsOf(FALSE, valueOf(m!=null? m: e.toString()));
- }
- }
/**
* Load from a named file, returning the chunk or nil,error of can't load