From de6003367d006218782d64b5c0da4d8c8ea8ede0 Mon Sep 17 00:00:00 2001 From: andy Date: Wed, 30 May 2007 22:49:41 +0000 Subject: [PATCH] Sync with Nasal upstream. Mostly fixes to naContinue(), which FlightGear doesn't use. Also includes a performance fix for the call() builtin that should help Melchior, who was measuring lower performance for the props.Node() interface than the getprop/setprop API. --- simgear/nasal/code.c | 20 +++++++++++++++++++- simgear/nasal/code.h | 10 +++++++--- simgear/nasal/data.h | 4 ++-- simgear/nasal/lib.c | 37 ++++++++++++++++++++----------------- simgear/nasal/misc.c | 12 ++---------- simgear/nasal/nasal.h | 41 +++++++++++++++++++++++++---------------- 6 files changed, 75 insertions(+), 49 deletions(-) diff --git a/simgear/nasal/code.c b/simgear/nasal/code.c index 5f57a771..031be628 100644 --- a/simgear/nasal/code.c +++ b/simgear/nasal/code.c @@ -807,12 +807,30 @@ naRef naContinue(naContext ctx) { naRef result; if(!ctx->callParent) naModLock(); + + ctx->dieArg = naNil(); + ctx->error[0] = 0; + if(setjmp(ctx->jumpHandle)) { if(!ctx->callParent) naModUnlock(ctx); + else naRethrowError(ctx); return naNil(); } + + // Wipe off the old function arguments, and push the expected + // result (either the result of our subcontext, or a synthesized + // nil if the thrown error was from an extension function or + // in-script die() call) before re-running the code from the + // instruction following the error. ctx->opTop = ctx->opFrame; - PUSH(naNil()); + PUSH(ctx->callChild ? naContinue(ctx->callChild) : naNil()); + + // Getting here means the child completed successfully. But + // because its original C stack was longjmp'd out of existence, + // there is no one left to free the context, so we have to do it. + // This is fragile, but unfortunately required. + if(ctx->callChild) naFreeContext(ctx->callChild); + result = run(ctx); if(!ctx->callParent) naModUnlock(); return result; diff --git a/simgear/nasal/code.h b/simgear/nasal/code.h index a71f1309..af90e2d2 100644 --- a/simgear/nasal/code.h +++ b/simgear/nasal/code.h @@ -10,9 +10,13 @@ #define MAX_MARK_DEPTH 128 // Number of objects (per pool per thread) asked for using naGC_get(). -// Testing with fib.nas shows that this gives the best performance, -// without too much per-thread overhead. -#define OBJ_CACHE_SZ 128 +// The idea is that contexts can "cache" allocations to prevent thread +// contention on the global pools. But in practice this interacts +// very badly with small subcontext calls, which grab huge numbers of +// cached objects and don't use them, causing far more collections +// than necessary. Just leave it at 1 pending a rework of the +// collector synchronization. +#define OBJ_CACHE_SZ 1 enum { OP_NOT, OP_MUL, OP_PLUS, OP_MINUS, OP_DIV, OP_NEG, diff --git a/simgear/nasal/data.h b/simgear/nasal/data.h index 3c5a23b0..7c851be5 100644 --- a/simgear/nasal/data.h +++ b/simgear/nasal/data.h @@ -9,7 +9,7 @@ // bitmask that sets the top 16 bits. As a double, this is a // signalling NaN that cannot itself be produced by normal numerics // code. The pointer value can be reconstructed if (and only if) we -// are guaranteed that all memory that can be poitned to by a naRef +// are guaranteed that all memory that can be pointed to by a naRef // (i.e. all memory returned by naAlloc) lives in the bottom 48 bits // of memory. Linux on x86_64, Win64, Solaris and Irix all have such // policies with address spaces: @@ -82,7 +82,7 @@ enum { T_STR, T_VEC, T_HASH, T_CODE, T_FUNC, T_CCODE, T_GHOST, #define MUTABLE(r) (IS_STR(r) && PTR(r).str->hashcode == 0) // This is a macro instead of a separate struct to allow compilers to -// avoid padding. GCC on x86, at least, will always padd the size of +// avoid padding. GCC on x86, at least, will always pad the size of // an embedded struct up to 32 bits. Doing it this way allows the // implementing objects to pack in 16 bits worth of data "for free". #define GC_HEADER \ diff --git a/simgear/nasal/lib.c b/simgear/nasal/lib.c index ff35104c..a724d5cb 100644 --- a/simgear/nasal/lib.c +++ b/simgear/nasal/lib.c @@ -227,29 +227,32 @@ static naRef f_call(naContext c, naRef me, int argc, naRef* args) if(!IS_FUNC(args[0]) || (!IS_NIL(callargs) && !IS_VEC(callargs))) ARGERR(); - // Note that we don't free the subcontext, in case the user - // re-throws the same error. That happens at the next OP_RETURN - // or naSubContext(). subc = naSubContext(c); vr = IS_NIL(callargs) ? 0 : PTR(callargs).vec->rec; result = naCall(subc, args[0], vr ? vr->size : 0, vr ? vr->array : 0, callme, callns); - if(naGetError(subc)) { - if(argc <= 2 || !IS_VEC(args[argc-1])) { - naRethrowError(subc); - } else { - int i, sd; - naRef errv = args[argc-1]; - if(!IS_NIL(subc->dieArg)) naVec_append(errv, subc->dieArg); - else naVec_append(errv, NEWCSTR(subc, naGetError(subc))); - sd = naStackDepth(subc); - for(i=0; idieArg)) naVec_append(errv, subc->dieArg); + else naVec_append(errv, NEWCSTR(subc, naGetError(subc))); + sd = naStackDepth(subc); + for(i=0; i 2 +/* This marks the function as having no side effects and depending on + * nothing but its arguments, which allows the optimizer to avoid + * duplicate calls to naNil(). */ +#define GCC_PURE __attribute__((__pure__)) +#else +#define GCC_PURE +#endif + typedef struct Context* naContext; // The function signature for an extension function: @@ -27,7 +36,7 @@ naContext naSubContext(naContext super); // provision for sharing it, nor for validating the source or type of // the pointer returned. void naSetUserData(naContext c, void* p); -void* naGetUserData(naContext c); +void* naGetUserData(naContext c) GCC_PURE; // "Save" this object in the context, preventing it (and objects // referenced by it) from being garbage collected. @@ -117,19 +126,19 @@ naRef naGetSourceFile(naContext ctx, int frame); char* naGetError(naContext ctx); // Type predicates -int naIsNil(naRef r); -int naIsNum(naRef r); -int naIsString(naRef r); -int naIsScalar(naRef r); -int naIsVector(naRef r); -int naIsHash(naRef r); -int naIsCode(naRef r); -int naIsFunc(naRef r); -int naIsCCode(naRef r); +int naIsNil(naRef r) GCC_PURE; +int naIsNum(naRef r) GCC_PURE; +int naIsString(naRef r) GCC_PURE; +int naIsScalar(naRef r) GCC_PURE; +int naIsVector(naRef r) GCC_PURE; +int naIsHash(naRef r) GCC_PURE; +int naIsCode(naRef r) GCC_PURE; +int naIsFunc(naRef r) GCC_PURE; +int naIsCCode(naRef r) GCC_PURE; // Allocators/generators: -naRef naNil(); -naRef naNum(double num); +naRef naNil() GCC_PURE; +naRef naNum(double num) GCC_PURE; naRef naNewString(naContext c); naRef naNewVector(naContext c); naRef naNewHash(naContext c); @@ -137,10 +146,10 @@ naRef naNewFunc(naContext c, naRef code); naRef naNewCCode(naContext c, naCFunction fptr); // Some useful conversion/comparison routines -int naEqual(naRef a, naRef b); -int naStrEqual(naRef a, naRef b); -int naTrue(naRef b); -naRef naNumValue(naRef n); +int naEqual(naRef a, naRef b) GCC_PURE; +int naStrEqual(naRef a, naRef b) GCC_PURE; +int naTrue(naRef b) GCC_PURE; +naRef naNumValue(naRef n) GCC_PURE; naRef naStringValue(naContext c, naRef n); // String utilities: -- 2.39.5