Skip to content

Commit

Permalink
Add support for building without nan-boxing
Browse files Browse the repository at this point in the history
  • Loading branch information
klange committed Jan 11, 2024
1 parent df4435e commit b162ed8
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 61 deletions.
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ ifdef KRK_HEAP_TAG_BYTE
CFLAGS += -DKRK_HEAP_TAG_BYTE=${KRK_HEAP_TAG_BYTE}
endif

ifdef KRK_NO_NAN_BOXING
CFLAGS += -DKRK_NO_NAN_BOXING=1
endif

ifdef KRK_BUNDLE_LIBS
KRK_BUNDLE_LIBS_CFLAG=$(patsubst %,BUNDLED(%);,${KRK_BUNDLE_LIBS})
KRK_BUNDLE_LIBS_BOBJS=$(patsubst %,src/modules/module_%.o,${KRK_BUNDLE_LIBS})
Expand Down
2 changes: 1 addition & 1 deletion src/exceptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ KrkValue krk_runtimeError(KrkClass * type, const char * fmt, ...) {
/* Allocate an exception object of the requested type. */
KrkInstance * exceptionObject = krk_newInstance(type);
krk_push(OBJECT_VAL(exceptionObject));
krk_attachNamedValue(&exceptionObject->fields, "arg", msg == KWARGS_VAL(0) ? finishStringBuilder(&sb) : msg);
krk_attachNamedValue(&exceptionObject->fields, "arg", krk_valuesSame(msg,KWARGS_VAL(0)) ? finishStringBuilder(&sb) : msg);
krk_attachNamedValue(&exceptionObject->fields, "__cause__", NONE_VAL());
krk_attachNamedValue(&exceptionObject->fields, "__context__", NONE_VAL());
krk_pop();
Expand Down
116 changes: 93 additions & 23 deletions src/kuroko/value.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <string.h>
#include "kuroko.h"

#ifndef KRK_NO_NAN_BOXING
/**
* @brief Tag enum for basic value types.
*
Expand All @@ -23,28 +24,6 @@ typedef enum {
KRK_VAL_NOTIMPL = 0x7FFE,
} KrkValueType;

/*
* The following poorly-named macros define bit patterns for identifying
* various boxed types.
*
* Boxing is done by first setting all of the bits of MASK_NAN. If all of
* these bits are set, a value is not a float. If any of them are not set,
* then a value is a float - and possibly a real NaN.
*
* Three other bits - one before and two after the MASK_NAN bits - determine
* what type the value actually is. KWARGS sets none of the identifying bits,
* NONE sets all of them.
*/
#define KRK_VAL_MASK_BOOLEAN ((uint64_t)0xFFFC000000000000) /* 1..1100 */
#define KRK_VAL_MASK_INTEGER ((uint64_t)0xFFFD000000000000) /* 1..1101 */
#define KRK_VAL_MASK_HANDLER ((uint64_t)0xFFFE000000000000) /* 1..1110 */
#define KRK_VAL_MASK_NONE ((uint64_t)0xFFFF000000000000) /* 1..1111 */
#define KRK_VAL_MASK_KWARGS ((uint64_t)0x7FFC000000000000) /* 0..1100 */
#define KRK_VAL_MASK_OBJECT ((uint64_t)0x7FFD000000000000) /* 0..1101 */
#define KRK_VAL_MASK_NOTIMPL ((uint64_t)0x7FFE000000000000) /* 0..1110 */
#define KRK_VAL_MASK_NAN ((uint64_t)0x7FFC000000000000)
#define KRK_VAL_MASK_LOW ((uint64_t)0x0000FFFFFFFFFFFF)

/**
* @struct KrkValue
* @brief Stack reference or primative value.
Expand All @@ -61,6 +40,32 @@ typedef enum {
*/
typedef uint64_t KrkValue;

#define _krk_valuesSame(a,b) (a == b)

#else
/*
* Tagged union, but without the union fun.
*/
typedef enum {
KRK_VAL_NONE = 0,
KRK_VAL_INTEGER = 1,
KRK_VAL_BOOLEAN = 2,
KRK_VAL_HANDLER = 4,
KRK_VAL_KWARGS = 8,
KRK_VAL_OBJECT = 16,
KRK_VAL_NOTIMPL = 32,
KRK_VAL_FLOATING = 64,
} KrkValueType;

typedef struct {
uint64_t tag;
uint64_t val;
} KrkValue;

#define _krk_valuesSame(a,b) (memcmp(&(a),&(b),sizeof(KrkValue)) == 0)

#endif

/**
* @brief Flexible vector of stack references.
*
Expand Down Expand Up @@ -133,7 +138,7 @@ extern int krk_valuesEqual(KrkValue a, KrkValue b);
*
* @return 1 if values represent the same object or value, 0 otherwise.
*/
extern int krk_valuesSame(KrkValue a, KrkValue b);
static inline int krk_valuesSame(KrkValue a, KrkValue b) { return _krk_valuesSame(a,b); }

/**
* @brief Compare two values by identity, then by equality.
Expand All @@ -147,11 +152,35 @@ extern int krk_valuesSameOrEqual(KrkValue a, KrkValue b);

extern KrkValue krk_parse_int(const char * start, size_t width, unsigned int base);

#ifndef KRK_NO_NAN_BOXING

typedef union {
KrkValue val;
double dbl;
} KrkValueDbl;

/*
* The following poorly-named macros define bit patterns for identifying
* various boxed types.
*
* Boxing is done by first setting all of the bits of MASK_NAN. If all of
* these bits are set, a value is not a float. If any of them are not set,
* then a value is a float - and possibly a real NaN.
*
* Three other bits - one before and two after the MASK_NAN bits - determine
* what type the value actually is. KWARGS sets none of the identifying bits,
* NONE sets all of them.
*/
#define KRK_VAL_MASK_BOOLEAN ((uint64_t)0xFFFC000000000000) /* 1..1100 */
#define KRK_VAL_MASK_INTEGER ((uint64_t)0xFFFD000000000000) /* 1..1101 */
#define KRK_VAL_MASK_HANDLER ((uint64_t)0xFFFE000000000000) /* 1..1110 */
#define KRK_VAL_MASK_NONE ((uint64_t)0xFFFF000000000000) /* 1..1111 */
#define KRK_VAL_MASK_KWARGS ((uint64_t)0x7FFC000000000000) /* 0..1100 */
#define KRK_VAL_MASK_OBJECT ((uint64_t)0x7FFD000000000000) /* 0..1101 */
#define KRK_VAL_MASK_NOTIMPL ((uint64_t)0x7FFE000000000000) /* 0..1110 */
#define KRK_VAL_MASK_NAN ((uint64_t)0x7FFC000000000000)
#define KRK_VAL_MASK_LOW ((uint64_t)0x0000FFFFFFFFFFFF)

#ifdef KRK_SANITIZE_OBJECT_POINTERS
/**
* Debugging tool for verifying we aren't trying to box NULL, which is not a valid object.
Expand Down Expand Up @@ -213,6 +242,47 @@ static inline uintptr_t _krk_sanitize(uintptr_t input) {
/* ... and as we said above, if any of the MASK_NAN bits are unset, it's a float. */
#define IS_FLOATING(value) (((value) & KRK_VAL_MASK_NAN) != KRK_VAL_MASK_NAN)

#else

typedef union {
uint64_t val;
double dbl;
} KrkValueDbl;

#define NONE_VAL() ((KrkValue){KRK_VAL_NONE,-1})
#define NOTIMPL_VAL() ((KrkValue){KRK_VAL_NOTIMPL,0})
#define BOOLEAN_VAL(value) ((KrkValue){KRK_VAL_BOOLEAN,!!(value)})
#define INTEGER_VAL(value) ((KrkValue){KRK_VAL_INTEGER,((uint64_t)(value)) & 0xFFFFffffFFFFULL})
#define KWARGS_VAL(value) ((KrkValue){KRK_VAL_KWARGS,((uint32_t)(value))})
#define OBJECT_VAL(value) ((KrkValue){KRK_VAL_OBJECT,((uintptr_t)(value))})
#define HANDLER_VAL(ty,ta) ((KrkValue){KRK_VAL_HANDLER,((uint64_t)((((uint64_t)ty) << 32) | ((uint32_t)ta)))})
#define FLOATING_VAL(value) ((KrkValue){KRK_VAL_FLOATING,(((KrkValueDbl){.dbl = (value)}).val)})

#define KRK_VAL_TYPE(value) ((value).tag)

#define KRK_VAL_MASK_NONE ((uint64_t)0xFFFF000000000000)
#define KRK_VAL_MASK_LOW ((uint64_t)0x0000FFFFFFFFFFFF)
#define KRK_IX(value) ((uint64_t)((value).val & KRK_VAL_MASK_LOW))
#define KRK_SX(value) ((uint64_t)((value).val & 0x800000000000))
#define AS_INTEGER(value) ((krk_integer_type)(KRK_SX(value) ? (KRK_IX(value) | KRK_VAL_MASK_NONE) : (KRK_IX(value))))
#define AS_BOOLEAN(value) AS_INTEGER(value)

#define AS_HANDLER(value) ((uint64_t)((value)).val)
#define AS_OBJECT(value) ((KrkObj*)((uintptr_t)((value).val)))
#define AS_FLOATING(value) (((KrkValueDbl){.val = ((value)).val}).dbl)

#define IS_INTEGER(value) (!!(((value)).tag & (KRK_VAL_INTEGER|KRK_VAL_BOOLEAN)))
#define IS_BOOLEAN(value) (((value)).tag == KRK_VAL_BOOLEAN)
#define IS_NONE(value) (((value)).tag == KRK_VAL_NONE)
#define IS_HANDLER(value) (((value)).tag == KRK_VAL_HANDLER)
#define IS_OBJECT(value) (((value)).tag == KRK_VAL_OBJECT)
#define IS_KWARGS(value) (((value)).tag == KRK_VAL_KWARGS)
#define IS_NOTIMPL(value) (((value)).tag == KRK_VAL_NOTIMPL)
#define IS_FLOATING(value) (((value)).tag == KRK_VAL_FLOATING)

#endif


#define AS_HANDLER_TYPE(value) (AS_HANDLER(value) >> 32)
#define AS_HANDLER_TARGET(value) (AS_HANDLER(value) & 0xFFFFFFFF)
#define IS_HANDLER_TYPE(value,type) (IS_HANDLER(value) && AS_HANDLER_TYPE(value) == type)
Expand Down
24 changes: 12 additions & 12 deletions src/parseargs.c
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ int krk_parseVArgs(
* still want to have all the type checking and automatic parsing. */
fmt++;
int * out = va_arg(args, int*);
*out = arg != KWARGS_VAL(0);
*out = !krk_valuesSame(arg, KWARGS_VAL(0));
}

if (*fmt == '!') {
Expand All @@ -198,7 +198,7 @@ int krk_parseVArgs(
* Maybe if you want @c p to only be a bool this could be useful? */
fmt++;
KrkClass * type = va_arg(args, KrkClass*);
if (arg != KWARGS_VAL(0) && !krk_isInstanceOf(arg, type)) {
if (!krk_valuesSame(arg, KWARGS_VAL(0)) && !krk_isInstanceOf(arg, type)) {
raise_TypeError(_method_name, type ? type->name->chars : "unknown type", arg, names[oarg]);
goto _error;
}
Expand All @@ -216,7 +216,7 @@ int krk_parseVArgs(
*/
case 'O': {
KrkObj ** out = va_arg(args, KrkObj**);
if (arg != KWARGS_VAL(0)) {
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
if (IS_NONE(arg)) {
*out = NULL;
} else if (!IS_OBJECT(arg)) {
Expand All @@ -240,7 +240,7 @@ int krk_parseVArgs(
*/
case 'V': {
KrkValue * out = va_arg(args, KrkValue*);
if (arg != KWARGS_VAL(0)) {
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
*out = arg;
}
break;
Expand All @@ -260,8 +260,8 @@ int krk_parseVArgs(
fmt++;
size = va_arg(args, size_t*);
}
if (arg != KWARGS_VAL(0)) {
if (arg == NONE_VAL()) {
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
if (IS_NONE(arg)) {
*out = NULL;
if (size) *size = 0;
} else if (IS_STRING(arg)) {
Expand All @@ -285,7 +285,7 @@ int krk_parseVArgs(
fmt++;
size = va_arg(args, size_t*);
}
if (arg != KWARGS_VAL(0)) {
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
if (IS_STRING(arg)) {
*out = AS_CSTRING(arg);
if (size) *size = AS_STRING(arg)->length;
Expand All @@ -306,7 +306,7 @@ int krk_parseVArgs(
* both for future compatibility and to make intent clear, but have no
* functional difference at this point.
*/
#define NUMERIC(c,type) case c: { type * out = va_arg(args, type*); if (arg != KWARGS_VAL(0)) { if (!krk_long_to_int(arg, sizeof(type), out)) goto _error; } break; }
#define NUMERIC(c,type) case c: { type * out = va_arg(args, type*); if (!krk_valuesSame(arg, KWARGS_VAL(0))) { if (!krk_long_to_int(arg, sizeof(type), out)) goto _error; } break; }
NUMERIC('b',unsigned char)
NUMERIC('h',short)
NUMERIC('H',unsigned short)
Expand All @@ -325,7 +325,7 @@ int krk_parseVArgs(
*/
case 'C': {
int * out = va_arg(args, int*);
if (arg != KWARGS_VAL(0)) {
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
if (!IS_STRING(arg) || AS_STRING(arg)->codesLength != 1) {
raise_TypeError(_method_name, "str of length 1", arg, names[oarg]);
goto _error;
Expand All @@ -341,7 +341,7 @@ int krk_parseVArgs(
*/
case 'f': {
float * out = va_arg(args, float*);
if (arg != KWARGS_VAL(0)) {
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
if (!IS_FLOATING(arg)) {
KrkClass * type = krk_getType(arg);
krk_push(arg);
Expand All @@ -362,7 +362,7 @@ int krk_parseVArgs(
*/
case 'd': {
double * out = va_arg(args, double*);
if (arg != KWARGS_VAL(0)) {
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
if (!IS_FLOATING(arg)) {
KrkClass * type = krk_getType(arg);
krk_push(arg);
Expand Down Expand Up @@ -392,7 +392,7 @@ int krk_parseVArgs(
*/
case 'p': {
int * out = va_arg(args, int*);
if (arg != KWARGS_VAL(0)) {
if (!krk_valuesSame(arg, KWARGS_VAL(0))) {
*out = !krk_isFalsey(arg);
if (krk_currentThread.flags & KRK_THREAD_HAS_EXCEPTION) goto _error;
}
Expand Down
18 changes: 9 additions & 9 deletions src/table.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@ KrkTableEntry * krk_findEntry(KrkTableEntry * entries, size_t capacity, KrkValue
KrkTableEntry * tombstone = NULL;
for (;;) {
KrkTableEntry * entry = &entries[index];
if (entry->key == KWARGS_VAL(0)) {
if (krk_valuesSame(entry->key, KWARGS_VAL(0))) {
return tombstone != NULL ? tombstone : entry;
} else if (entry->key == KWARGS_VAL(1)) {
} else if (krk_valuesSame(entry->key, KWARGS_VAL(1))) {
if (tombstone == entry) return tombstone;
if (tombstone == NULL) tombstone = entry;
} else if (krk_valuesSameOrEqual(entry->key, key)) {
Expand All @@ -93,9 +93,9 @@ KrkTableEntry * krk_findEntryExact(KrkTableEntry * entries, size_t capacity, Krk
KrkTableEntry * tombstone = NULL;
for (;;) {
KrkTableEntry * entry = &entries[index];
if (entry->key == KWARGS_VAL(0)) {
if (krk_valuesSame(entry->key, KWARGS_VAL(0))) {
return tombstone != NULL ? tombstone : entry;
} else if (entry->key == KWARGS_VAL(1)) {
} else if (krk_valuesSame(entry->key, KWARGS_VAL(1))) {
if (tombstone == entry) return tombstone;
if (tombstone == NULL) tombstone = entry;
} else if (krk_valuesSame(entry->key, key)) {
Expand Down Expand Up @@ -192,12 +192,12 @@ int krk_tableGet_fast(KrkTable * table, KrkString * str, KrkValue * value) {
KrkTableEntry * tombstone = NULL;
for (;;) {
KrkTableEntry * entry = &table->entries[index];
if (entry->key == KWARGS_VAL(0)) {
if (krk_valuesSame(entry->key, KWARGS_VAL(0))) {
return 0;
} else if (entry->key == KWARGS_VAL(1)) {
} else if (krk_valuesSame(entry->key, KWARGS_VAL(1))) {
if (tombstone == entry) return 0;
if (tombstone == NULL) tombstone = entry;
} else if (entry->key == OBJECT_VAL(str)) {
} else if (krk_valuesSame(entry->key, OBJECT_VAL(str))) {
*value = entry->value;
return 1;
}
Expand Down Expand Up @@ -236,9 +236,9 @@ KrkString * krk_tableFindString(KrkTable * table, const char * chars, size_t len
KrkTableEntry * tombstone = NULL;
for (;;) {
KrkTableEntry * entry = &table->entries[index];
if (entry->key == KWARGS_VAL(0)) {
if (krk_valuesSame(entry->key, KWARGS_VAL(0))) {
return NULL;
} else if (entry->key == KWARGS_VAL(1)) {
} else if (krk_valuesSame(entry->key, KWARGS_VAL(1))) {
if (tombstone == entry) return NULL;
if (tombstone == NULL) tombstone = entry;
} else if (AS_STRING(entry->key)->length == length &&
Expand Down
11 changes: 2 additions & 9 deletions src/value.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,6 @@ void krk_freeValueArray(KrkValueArray * array) {
krk_initValueArray(array);
}

/**
* Identity really should be the simple...
*/
int krk_valuesSame(KrkValue a, KrkValue b) {
return a == b;
}

static inline int _krk_method_equivalence(KrkValue a, KrkValue b) {
KrkClass * type = krk_getType(a);
if (likely(type && type->_eq)) {
Expand Down Expand Up @@ -69,7 +62,7 @@ static inline int _krk_same_type_equivalence(uint16_t valtype, KrkValue a, KrkVa
case KRK_VAL_NOTIMPL:
case KRK_VAL_KWARGS:
case KRK_VAL_HANDLER:
return a == b;
return krk_valuesSame(a,b);
case KRK_VAL_OBJECT:
default:
return _krk_method_equivalence(a,b);
Expand Down Expand Up @@ -101,7 +94,7 @@ static inline int _krk_diff_type_equivalence(uint16_t val_a, uint16_t val_b, Krk

_hot
int krk_valuesSameOrEqual(KrkValue a, KrkValue b) {
if (a == b) return 1;
if (krk_valuesSame(a,b)) return 1;
uint16_t val_a = KRK_VAL_TYPE(a);
uint16_t val_b = KRK_VAL_TYPE(b);
return (val_a == val_b)
Expand Down
Loading

0 comments on commit b162ed8

Please sign in to comment.