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

View File

@@ -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;

View File

@@ -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,

View File

@@ -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 \

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)))
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; i<sd; i++) {
naVec_append(errv, naGetSourceFile(subc, i));
naVec_append(errv, naNum(naGetLine(subc, i)));
}
if(!naGetError(subc)) {
naFreeContext(subc);
return result;
}
// Error handling. Note that we don't free the subcontext after an
// error, in case the user re-throws the same error or calls
// naContinue()
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; 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)

View File

@@ -5,17 +5,9 @@
#include "nasal.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* naAlloc(int n) { return chkptr(malloc(n)); }
void* naRealloc(void* b, int n) { return chkptr(realloc(b, n)); }
void* naAlloc(int n) { return malloc(n); }
void* naRealloc(void* b, int n) { return realloc(b, n); }
void naBZero(void* m, int n) { memset(m, 0, n); }
void naTempSave(naContext c, naRef r)

View File

@@ -6,6 +6,15 @@ extern "C" {
#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;
// 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: