mirror of
https://github.com/janet-lang/janet
synced 2024-11-24 17:27:18 +00:00
Revise 32 bit nanbox implementation.
This commit is contained in:
parent
eb314ae903
commit
1532697b37
@ -33,5 +33,23 @@ int main() {
|
||||
assert(sizeof(void *) == 8);
|
||||
#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;
|
||||
}
|
||||
|
@ -22,31 +22,16 @@
|
||||
|
||||
#include <janet/janet.h>
|
||||
|
||||
#ifdef JANET_NANBOX
|
||||
#ifdef JANET_NANBOX_64
|
||||
|
||||
void *janet_nanbox_to_pointer(Janet x) {
|
||||
/* We need to do this shift to keep the higher bits of the pointer
|
||||
* 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
|
||||
|
||||
x.i64 &= JANET_NANBOX_PAYLOADBITS;
|
||||
return x.pointer;
|
||||
}
|
||||
|
||||
Janet janet_nanbox_from_pointer(void *p, uint64_t tagmask) {
|
||||
Janet ret;
|
||||
ret.pointer = p;
|
||||
#if defined (JANET_NANBOX_47) || defined (JANET_32)
|
||||
#else
|
||||
ret.u64 &= JANET_NANBOX_POINTERBITS;
|
||||
#endif
|
||||
ret.u64 |= tagmask;
|
||||
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 ret;
|
||||
ret.pointer = (void *)p;
|
||||
#if defined (JANET_NANBOX_47) || defined (JANET_32)
|
||||
#else
|
||||
ret.u64 &= JANET_NANBOX_POINTERBITS;
|
||||
#endif
|
||||
ret.u64 |= tagmask;
|
||||
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
|
||||
|
||||
/* Wrapper functions wrap a data type that is used from C into a
|
||||
|
@ -175,10 +175,11 @@ extern "C" {
|
||||
* architectures (Nanboxing only tested on x86 and x64), comment out
|
||||
* the JANET_NANBOX define.*/
|
||||
#ifndef JANET_NO_NANBOX
|
||||
#define JANET_NANBOX
|
||||
|
||||
/* Further refines the type of nanboxing to use. */
|
||||
#define JANET_NANBOX_47
|
||||
#ifdef JANET_32
|
||||
#define JANET_NANBOX_32
|
||||
#else
|
||||
#define JANET_NANBOX_64
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Alignment for pointers */
|
||||
@ -240,7 +241,9 @@ typedef enum {
|
||||
JANET_STATUS_ALIVE
|
||||
} JanetFiberStatus;
|
||||
|
||||
#ifdef JANET_NANBOX
|
||||
#ifdef JANET_NANBOX_64
|
||||
typedef union Janet Janet;
|
||||
#elif defined(JANET_NANBOX_32)
|
||||
typedef union Janet Janet;
|
||||
#else
|
||||
typedef struct Janet Janet;
|
||||
@ -314,8 +317,8 @@ typedef enum JanetType {
|
||||
#define JANET_TFLAG_DICTIONARY (JANET_TFLAG_TABLE | JANET_TFLAG_STRUCT)
|
||||
#define JANET_TFLAG_LENGTHABLE (JANET_TFLAG_BYTES | JANET_TFLAG_INDEXED | JANET_TFLAG_DICTIONARY)
|
||||
|
||||
/* We provide two possible implemenations of Janets. The preferred
|
||||
* nanboxing approach, and the standard C version. Code in the rest of the
|
||||
/* We provide three possible implemenations of Janets. The preferred
|
||||
* nanboxing approach, for 32 or 64 bits, and the standard C version. Code in the rest of the
|
||||
* application must interact through exposed interface. */
|
||||
|
||||
/* Required interface for Janet */
|
||||
@ -334,74 +337,28 @@ typedef enum JanetType {
|
||||
* janet_u64(x) - get 64 bits of payload for hashing
|
||||
*/
|
||||
|
||||
#ifdef JANET_NANBOX
|
||||
#ifdef JANET_NANBOX_64
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/* 64 Nanboxed Janet value */
|
||||
union Janet {
|
||||
uint64_t u64;
|
||||
int64_t i64;
|
||||
double real;
|
||||
void *pointer;
|
||||
};
|
||||
|
||||
#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_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) \
|
||||
(isnan((x).real) \
|
||||
? (((x).u64 >> 47) & 0xF) \
|
||||
: 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) \
|
||||
(((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_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
|
||||
|
||||
/* A general janet value type */
|
||||
/* A general janet value type for more standard C */
|
||||
struct Janet {
|
||||
union {
|
||||
uint64_t u64;
|
||||
|
Loading…
Reference in New Issue
Block a user