1
0
mirror of https://github.com/janet-lang/janet synced 2024-11-25 01:37:19 +00:00

Revise 32 bit nanbox implementation.

This commit is contained in:
Calvin Rose 2018-11-18 16:43:43 -05:00
parent eb314ae903
commit 1532697b37
3 changed files with 134 additions and 80 deletions

View File

@ -33,5 +33,23 @@ int main() {
assert(sizeof(void *) == 8); assert(sizeof(void *) == 8);
#endif #endif
janet_init();
/* Reflexive testing and nanbox testing */
assert(janet_equals(janet_wrap_nil(), janet_wrap_nil()));
assert(janet_equals(janet_wrap_false(), janet_wrap_false()));
assert(janet_equals(janet_wrap_true(), janet_wrap_true()));
assert(janet_equals(janet_wrap_integer(1), janet_wrap_integer(1)));
assert(janet_equals(janet_wrap_integer(INT32_MAX), janet_wrap_integer(INT32_MAX)));
assert(janet_equals(janet_wrap_integer(-2), janet_wrap_integer(-2)));
assert(janet_equals(janet_wrap_integer(INT32_MIN), janet_wrap_integer(INT32_MIN)));
assert(janet_equals(janet_wrap_real(1.4), janet_wrap_real(1.4)));
assert(janet_equals(janet_wrap_real(3.14159265), janet_wrap_real(3.14159265)));
assert(janet_equals(janet_cstringv("a string."), janet_cstringv("a string.")));
assert(janet_equals(janet_csymbolv("sym"), janet_csymbolv("sym")));
janet_deinit();
return 0; return 0;
} }

View File

@ -22,31 +22,16 @@
#include <janet/janet.h> #include <janet/janet.h>
#ifdef JANET_NANBOX #ifdef JANET_NANBOX_64
void *janet_nanbox_to_pointer(Janet x) { void *janet_nanbox_to_pointer(Janet x) {
/* We need to do this shift to keep the higher bits of the pointer x.i64 &= JANET_NANBOX_PAYLOADBITS;
* the same as bit 47 as required by the x86 architecture. We may save
* an instruction if we do x.u64 & JANET_NANBOX_POINTERBITS, but this 0s
* the high bits, and may make the pointer non-canocial on x86. If we switch
* to 47 bit pointers (which is what userspace uses on Windows, we can use
* the single mask rather than two shifts. */
#if defined (JANET_NANBOX_47) || defined (JANET_32)
x.i64 &= JANET_NANBOX_POINTERBITS;
#else
x.i64 = (x.i64 << 16) >> 16;
#endif
return x.pointer; return x.pointer;
} }
Janet janet_nanbox_from_pointer(void *p, uint64_t tagmask) { Janet janet_nanbox_from_pointer(void *p, uint64_t tagmask) {
Janet ret; Janet ret;
ret.pointer = p; ret.pointer = p;
#if defined (JANET_NANBOX_47) || defined (JANET_32)
#else
ret.u64 &= JANET_NANBOX_POINTERBITS;
#endif
ret.u64 |= tagmask; ret.u64 |= tagmask;
return ret; return ret;
} }
@ -54,10 +39,6 @@ Janet janet_nanbox_from_pointer(void *p, uint64_t tagmask) {
Janet janet_nanbox_from_cpointer(const void *p, uint64_t tagmask) { Janet janet_nanbox_from_cpointer(const void *p, uint64_t tagmask) {
Janet ret; Janet ret;
ret.pointer = (void *)p; ret.pointer = (void *)p;
#if defined (JANET_NANBOX_47) || defined (JANET_32)
#else
ret.u64 &= JANET_NANBOX_POINTERBITS;
#endif
ret.u64 |= tagmask; ret.u64 |= tagmask;
return ret; return ret;
} }
@ -97,6 +78,34 @@ void janet_nanbox_memempty(JanetKV *mem, int32_t count) {
} }
} }
#elif defined(JANET_NANBOX_32)
Janet janet_wrap_real(double x) {
Janet ret;
ret.real = x;
ret.tagged.type += JANET_DOUBLE_OFFSET;
return ret;
}
Janet janet_nanbox32_from_tagi(uint32_t tag, int32_t integer) {
Janet ret;
ret.tagged.type = tag;
ret.tagged.payload.integer = integer;
return ret;
}
Janet janet_nanbox32_from_tagp(uint32_t tag, void *pointer) {
Janet ret;
ret.tagged.type = tag;
ret.tagged.payload.pointer = pointer;
return ret;
}
double janet_unwrap_real(Janet x) {
x.tagged.type -= JANET_DOUBLE_OFFSET;
return x.real;
}
#else #else
/* Wrapper functions wrap a data type that is used from C into a /* Wrapper functions wrap a data type that is used from C into a

View File

@ -175,10 +175,11 @@ extern "C" {
* architectures (Nanboxing only tested on x86 and x64), comment out * architectures (Nanboxing only tested on x86 and x64), comment out
* the JANET_NANBOX define.*/ * the JANET_NANBOX define.*/
#ifndef JANET_NO_NANBOX #ifndef JANET_NO_NANBOX
#define JANET_NANBOX #ifdef JANET_32
#define JANET_NANBOX_32
/* Further refines the type of nanboxing to use. */ #else
#define JANET_NANBOX_47 #define JANET_NANBOX_64
#endif
#endif #endif
/* Alignment for pointers */ /* Alignment for pointers */
@ -240,7 +241,9 @@ typedef enum {
JANET_STATUS_ALIVE JANET_STATUS_ALIVE
} JanetFiberStatus; } JanetFiberStatus;
#ifdef JANET_NANBOX #ifdef JANET_NANBOX_64
typedef union Janet Janet;
#elif defined(JANET_NANBOX_32)
typedef union Janet Janet; typedef union Janet Janet;
#else #else
typedef struct Janet Janet; typedef struct Janet Janet;
@ -314,8 +317,8 @@ typedef enum JanetType {
#define JANET_TFLAG_DICTIONARY (JANET_TFLAG_TABLE | JANET_TFLAG_STRUCT) #define JANET_TFLAG_DICTIONARY (JANET_TFLAG_TABLE | JANET_TFLAG_STRUCT)
#define JANET_TFLAG_LENGTHABLE (JANET_TFLAG_BYTES | JANET_TFLAG_INDEXED | JANET_TFLAG_DICTIONARY) #define JANET_TFLAG_LENGTHABLE (JANET_TFLAG_BYTES | JANET_TFLAG_INDEXED | JANET_TFLAG_DICTIONARY)
/* We provide two possible implemenations of Janets. The preferred /* We provide three possible implemenations of Janets. The preferred
* nanboxing approach, and the standard C version. Code in the rest of the * nanboxing approach, for 32 or 64 bits, and the standard C version. Code in the rest of the
* application must interact through exposed interface. */ * application must interact through exposed interface. */
/* Required interface for Janet */ /* Required interface for Janet */
@ -334,74 +337,28 @@ typedef enum JanetType {
* janet_u64(x) - get 64 bits of payload for hashing * janet_u64(x) - get 64 bits of payload for hashing
*/ */
#ifdef JANET_NANBOX #ifdef JANET_NANBOX_64
#include <math.h> #include <math.h>
/* 64 Nanboxed Janet value */
union Janet { union Janet {
uint64_t u64; uint64_t u64;
int64_t i64; int64_t i64;
double real; double real;
void *pointer; void *pointer;
}; };
#define janet_u64(x) ((x).u64) #define janet_u64(x) ((x).u64)
/* This representation uses 48 bit pointers. The trade off vs. the LuaJIT style
* 47 bit payload representaion is that the type bits are no long contiguous. Type
* checking can still be fast, but typewise polymorphism takes a bit longer. However,
* hopefully we can avoid some annoying problems that occur when trying to use 47 bit pointers
* in a 48 bit address space (Linux on ARM). If JANET_NANBOX_47 is set, use 47 bit tagged pointers. */
/* |.......Tag.......|.......................Payload..................| */
/* Non-double: t|11111111111|1ttt|xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
/* Types of NIL, TRUE, and FALSE must have payload set to all 1s. */
/* Double (no NaNs): x xxxxxxxxxxx xxxx xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
#if defined (JANET_NANBOX_47) || defined (JANET_32)
#define JANET_NANBOX_TAGBITS 0xFFFF800000000000llu #define JANET_NANBOX_TAGBITS 0xFFFF800000000000llu
#define JANET_NANBOX_PAYLOADBITS 0x00007FFFFFFFFFFFllu #define JANET_NANBOX_PAYLOADBITS 0x00007FFFFFFFFFFFllu
#define janet_nanbox_lowtag(type) ((uint64_t)(type) | 0x1FFF0)
#define janet_nanbox_tag(type) (janet_nanbox_lowtag(type) << 47)
#define janet_nanbox_lowtag(type) \
((uint64_t)(type) | 0x1FFF0)
#define janet_nanbox_tag(type) \
(janet_nanbox_lowtag(type) << 47)
#define janet_type(x) \ #define janet_type(x) \
(isnan((x).real) \ (isnan((x).real) \
? (((x).u64 >> 47) & 0xF) \ ? (((x).u64 >> 47) & 0xF) \
: JANET_REAL) : JANET_REAL)
#else /* defined (JANET_NANBOX_47) || defined (JANET_32) */
#define JANET_NANBOX_TAGBITS 0xFFFF000000000000llu
#define JANET_NANBOX_PAYLOADBITS 0x0000FFFFFFFFFFFFllu
#define janet_nanbox_lowtag(type) \
((((uint64_t)(type) & 0x1) << 15) | 0x7FF8 | ((type) >> 1))
#define janet_nanbox_tag(type) \
(janet_nanbox_lowtag(type) << 48)
#define janet_type(x) \
(isnan((x).real) \
? (((x).u64 >> 47) & 0xE) | ((x).u64 >> 63) \
: JANET_REAL)
#endif /* defined (JANET_NANBOX_47) || defined (JANET_32) */
/* 32 bit mode will not use the full payload for pointers. */
#ifdef JANET_32
#define JANET_NANBOX_POINTERBITS 0xFFFFFFFFllu
#else
#define JANET_NANBOX_POINTERBITS JANET_NANBOX_PAYLOADBITS
#endif
#define janet_nanbox_checkauxtype(x, type) \ #define janet_nanbox_checkauxtype(x, type) \
(((x).u64 & JANET_NANBOX_TAGBITS) == janet_nanbox_tag((type))) (((x).u64 & JANET_NANBOX_TAGBITS) == janet_nanbox_tag((type)))
@ -479,10 +436,80 @@ JANET_API Janet janet_nanbox_from_bits(uint64_t bits);
#define janet_unwrap_function(x) ((JanetFunction *)janet_nanbox_to_pointer(x)) #define janet_unwrap_function(x) ((JanetFunction *)janet_nanbox_to_pointer(x))
#define janet_unwrap_cfunction(x) ((JanetCFunction)janet_nanbox_to_pointer(x)) #define janet_unwrap_cfunction(x) ((JanetCFunction)janet_nanbox_to_pointer(x))
/* End of [#ifdef JANET_NANBOX] */ #elif defined(JANET_NANBOX_32)
/* 32 bit nanboxed janet */
union Janet {
struct {
#ifdef JANET_BIG_ENDIAN
uint32_t type;
union {
int32_t integer;
void *pointer;
} payload;
#else
union {
int32_t integer;
void *pointer;
} payload;
uint32_t type;
#endif
} tagged;
double real;
uint64_t u64;
};
#define JANET_DOUBLE_OFFSET 0xFFFF
#define janet_u64(x) ((x).u64)
#define janet_type(x) (((x).tagged.type < JANET_DOUBLE_OFFSET) ? (x).tagged.type : JANET_REAL)
#define janet_checktype(x, t) ((x).tagged.type == (t))
#define janet_memempty(mem, count) memset((mem), 0, sizeof(JanetKV) * (count))
#define janet_memalloc_empty(count) calloc((count), sizeof(JanetKV))
#define janet_truthy(x) ((x).tagged.type != JANET_NIL && (x).tagged.type != JANET_FALSE)
JANET_API Janet janet_wrap_real(double x);
JANET_API Janet janet_nanbox32_from_tagi(uint32_t tag, int32_t integer);
JANET_API Janet janet_nanbox32_from_tagp(uint32_t tag, void *pointer);
#define janet_wrap_nil() janet_nanbox32_from_tagi(JANET_NIL, 0)
#define janet_wrap_true() janet_nanbox32_from_tagi(JANET_TRUE, 0)
#define janet_wrap_false() janet_nanbox32_from_tagi(JANET_FALSE, 0)
#define janet_wrap_boolean(b) janet_nanbox32_from_tagi((b) ? JANET_TRUE : JANET_FALSE, 0)
#define janet_wrap_integer(i) janet_nanbox32_from_tagi(JANET_INTEGER, (i))
/* Wrap the pointer types */
#define janet_wrap_struct(s) janet_nanbox32_from_tagp(JANET_STRUCT, (void *)(s))
#define janet_wrap_tuple(s) janet_nanbox32_from_tagp(JANET_TUPLE, (void *)(s))
#define janet_wrap_fiber(s) janet_nanbox32_from_tagp(JANET_FIBER, (void *)(s))
#define janet_wrap_array(s) janet_nanbox32_from_tagp(JANET_ARRAY, (void *)(s))
#define janet_wrap_table(s) janet_nanbox32_from_tagp(JANET_TABLE, (void *)(s))
#define janet_wrap_buffer(s) janet_nanbox32_from_tagp(JANET_BUFFER, (void *)(s))
#define janet_wrap_string(s) janet_nanbox32_from_tagp(JANET_STRING, (void *)(s))
#define janet_wrap_symbol(s) janet_nanbox32_from_tagp(JANET_SYMBOL, (void *)(s))
#define janet_wrap_abstract(s) janet_nanbox32_from_tagp(JANET_ABSTRACT, (void *)(s))
#define janet_wrap_function(s) janet_nanbox32_from_tagp(JANET_FUNCTION, (void *)(s))
#define janet_wrap_cfunction(s) janet_nanbox32_from_tagp(JANET_CFUNCTION, (void *)(s))
#define janet_unwrap_struct(x) ((const JanetKV *)(x).tagged.payload.pointer)
#define janet_unwrap_tuple(x) ((const Janet *)(x).tagged.payload.pointer)
#define janet_unwrap_fiber(x) ((JanetFiber *)(x).tagged.payload.pointer)
#define janet_unwrap_array(x) ((JanetArray *)(x).tagged.payload.pointer)
#define janet_unwrap_table(x) ((JanetTable *)(x).tagged.payload.pointer)
#define janet_unwrap_buffer(x) ((JanetBuffer *)(x).tagged.payload.pointer)
#define janet_unwrap_string(x) ((const uint8_t *)(x).tagged.payload.pointer)
#define janet_unwrap_symbol(x) ((const uint8_t *)(x).tagged.payload.pointer)
#define janet_unwrap_abstract(x) ((x).tagged.payload.pointer)
#define janet_unwrap_pointer(x) ((x).tagged.payload.pointer)
#define janet_unwrap_function(x) ((JanetFunction *)(x).tagged.payload.pointer)
#define janet_unwrap_cfunction(x) ((JanetCFunction)(x).tagged.payload.pointer)
#define janet_unwrap_boolean(x) ((x).tagged.type == JANET_TRUE)
#define janet_unwrap_integer(x) ((x).tagged.payload.integer)
JANET_API double janet_unwrap_real(Janet x);
#else #else
/* A general janet value type */ /* A general janet value type for more standard C */
struct Janet { struct Janet {
union { union {
uint64_t u64; uint64_t u64;