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.
This commit is contained in:
andy
2007-05-30 22:49:41 +00:00
parent a5f42eeddf
commit de6003367d
6 changed files with 75 additions and 49 deletions
+19 -1
View File
@@ -807,12 +807,30 @@ naRef naContinue(naContext ctx)
{ {
naRef result; naRef result;
if(!ctx->callParent) naModLock(); if(!ctx->callParent) naModLock();
ctx->dieArg = naNil();
ctx->error[0] = 0;
if(setjmp(ctx->jumpHandle)) { if(setjmp(ctx->jumpHandle)) {
if(!ctx->callParent) naModUnlock(ctx); if(!ctx->callParent) naModUnlock(ctx);
else naRethrowError(ctx);
return naNil(); 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; 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); result = run(ctx);
if(!ctx->callParent) naModUnlock(); if(!ctx->callParent) naModUnlock();
return result; return result;
+7 -3
View File
@@ -10,9 +10,13 @@
#define MAX_MARK_DEPTH 128 #define MAX_MARK_DEPTH 128
// Number of objects (per pool per thread) asked for using naGC_get(). // Number of objects (per pool per thread) asked for using naGC_get().
// Testing with fib.nas shows that this gives the best performance, // The idea is that contexts can "cache" allocations to prevent thread
// without too much per-thread overhead. // contention on the global pools. But in practice this interacts
#define OBJ_CACHE_SZ 128 // 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 { enum {
OP_NOT, OP_MUL, OP_PLUS, OP_MINUS, OP_DIV, OP_NEG, OP_NOT, OP_MUL, OP_PLUS, OP_MINUS, OP_DIV, OP_NEG,
+2 -2
View File
@@ -9,7 +9,7 @@
// bitmask that sets the top 16 bits. As a double, this is a // bitmask that sets the top 16 bits. As a double, this is a
// signalling NaN that cannot itself be produced by normal numerics // signalling NaN that cannot itself be produced by normal numerics
// code. The pointer value can be reconstructed if (and only if) we // 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 // (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 // of memory. Linux on x86_64, Win64, Solaris and Irix all have such
// policies with address spaces: // 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) #define MUTABLE(r) (IS_STR(r) && PTR(r).str->hashcode == 0)
// This is a macro instead of a separate struct to allow compilers to // 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 // 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". // implementing objects to pack in 16 bits worth of data "for free".
#define GC_HEADER \ #define GC_HEADER \
+20 -17
View File
@@ -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))) if(!IS_FUNC(args[0]) || (!IS_NIL(callargs) && !IS_VEC(callargs)))
ARGERR(); 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); subc = naSubContext(c);
vr = IS_NIL(callargs) ? 0 : PTR(callargs).vec->rec; vr = IS_NIL(callargs) ? 0 : PTR(callargs).vec->rec;
result = naCall(subc, args[0], vr ? vr->size : 0, vr ? vr->array : 0, result = naCall(subc, args[0], vr ? vr->size : 0, vr ? vr->array : 0,
callme, callns); callme, callns);
if(naGetError(subc)) { if(!naGetError(subc)) {
if(argc <= 2 || !IS_VEC(args[argc-1])) { naFreeContext(subc);
naRethrowError(subc); return result;
} else { }
int i, sd;
naRef errv = args[argc-1]; // Error handling. Note that we don't free the subcontext after an
if(!IS_NIL(subc->dieArg)) naVec_append(errv, subc->dieArg); // error, in case the user re-throws the same error or calls
else naVec_append(errv, NEWCSTR(subc, naGetError(subc))); // naContinue()
sd = naStackDepth(subc); if(argc <= 2 || !IS_VEC(args[argc-1])) {
for(i=0; i<sd; i++) { naRethrowError(subc);
naVec_append(errv, naGetSourceFile(subc, i)); } else {
naVec_append(errv, naNum(naGetLine(subc, i))); 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; i<sd; i++) {
naVec_append(errv, naGetSourceFile(subc, i));
naVec_append(errv, naNum(naGetLine(subc, i)));
} }
} }
return result; return naNil();
} }
static naRef f_die(naContext c, naRef me, int argc, naRef* args) static naRef f_die(naContext c, naRef me, int argc, naRef* args)
+2 -10
View File
@@ -5,17 +5,9 @@
#include "nasal.h" #include "nasal.h"
#include "code.h" #include "code.h"
static void* chkptr(void* p)
{
naRef foo;
SETPTR(foo, p);
if(PTR(foo).obj != p) *(int*)0=0;
return p;
}
void naFree(void* m) { free(m); } void naFree(void* m) { free(m); }
void* naAlloc(int n) { return chkptr(malloc(n)); } void* naAlloc(int n) { return malloc(n); }
void* naRealloc(void* b, int n) { return chkptr(realloc(b, n)); } void* naRealloc(void* b, int n) { return realloc(b, n); }
void naBZero(void* m, int n) { memset(m, 0, n); } void naBZero(void* m, int n) { memset(m, 0, n); }
void naTempSave(naContext c, naRef r) void naTempSave(naContext c, naRef r)
+25 -16
View File
@@ -6,6 +6,15 @@ extern "C" {
#include "naref.h" #include "naref.h"
#if __GNUC__ > 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; typedef struct Context* naContext;
// The function signature for an extension function: // 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 // provision for sharing it, nor for validating the source or type of
// the pointer returned. // the pointer returned.
void naSetUserData(naContext c, void* p); 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 // "Save" this object in the context, preventing it (and objects
// referenced by it) from being garbage collected. // referenced by it) from being garbage collected.
@@ -117,19 +126,19 @@ naRef naGetSourceFile(naContext ctx, int frame);
char* naGetError(naContext ctx); char* naGetError(naContext ctx);
// Type predicates // Type predicates
int naIsNil(naRef r); int naIsNil(naRef r) GCC_PURE;
int naIsNum(naRef r); int naIsNum(naRef r) GCC_PURE;
int naIsString(naRef r); int naIsString(naRef r) GCC_PURE;
int naIsScalar(naRef r); int naIsScalar(naRef r) GCC_PURE;
int naIsVector(naRef r); int naIsVector(naRef r) GCC_PURE;
int naIsHash(naRef r); int naIsHash(naRef r) GCC_PURE;
int naIsCode(naRef r); int naIsCode(naRef r) GCC_PURE;
int naIsFunc(naRef r); int naIsFunc(naRef r) GCC_PURE;
int naIsCCode(naRef r); int naIsCCode(naRef r) GCC_PURE;
// Allocators/generators: // Allocators/generators:
naRef naNil(); naRef naNil() GCC_PURE;
naRef naNum(double num); naRef naNum(double num) GCC_PURE;
naRef naNewString(naContext c); naRef naNewString(naContext c);
naRef naNewVector(naContext c); naRef naNewVector(naContext c);
naRef naNewHash(naContext c); naRef naNewHash(naContext c);
@@ -137,10 +146,10 @@ naRef naNewFunc(naContext c, naRef code);
naRef naNewCCode(naContext c, naCFunction fptr); naRef naNewCCode(naContext c, naCFunction fptr);
// Some useful conversion/comparison routines // Some useful conversion/comparison routines
int naEqual(naRef a, naRef b); int naEqual(naRef a, naRef b) GCC_PURE;
int naStrEqual(naRef a, naRef b); int naStrEqual(naRef a, naRef b) GCC_PURE;
int naTrue(naRef b); int naTrue(naRef b) GCC_PURE;
naRef naNumValue(naRef n); naRef naNumValue(naRef n) GCC_PURE;
naRef naStringValue(naContext c, naRef n); naRef naStringValue(naContext c, naRef n);
// String utilities: // String utilities: