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:
+19
-1
@@ -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;
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user