~jack/misc

6035abf13ce67d44ecb10d05760535df2851eb81 — Jack Kelly 1 year, 5 months ago c9ce05d
zlox: NaN-boxing
3 files changed, 66 insertions(+), 0 deletions(-)

M zlox/src/common.h
M zlox/src/value.c
M zlox/src/value.h
M zlox/src/common.h => zlox/src/common.h +1 -0
@@ 5,6 5,7 @@
#include <stddef.h>
#include <stdint.h>

#define NAN_BOXING
#define DEBUG_PRINT_CODE
#define DEBUG_TRACE_EXECUTION


M zlox/src/value.c => zlox/src/value.c +19 -0
@@ 31,6 31,17 @@ void freeValueArray(ValueArray *array) {
}

void printValue(Value value) {
#ifdef NAN_BOXING
  if (IS_BOOL(value)) {
    printf(AS_BOOL(value) ? "true" : "false");
  } else if (IS_NIL(value)) {
    printf("nil");
  } else if (IS_NUMBER(value)) {
    printf("%g", AS_NUMBER(value));
  } else if (IS_OBJ(value)) {
    printObject(value);
  }
#else
  switch (value.type) {
  case VAL_BOOL:
    printf(AS_BOOL(value) ? "true" : "false");


@@ 39,9 50,16 @@ void printValue(Value value) {
  case VAL_NUMBER: printf("%g", AS_NUMBER(value)); break;
  case VAL_OBJ: printObject(value); break;
  }
#endif
}

bool valuesEqual(Value a, Value b) {
#ifdef NAN_BOXING
  if (IS_NUMBER(a) && IS_NUMBER(b)) {
    return AS_NUMBER(a) == AS_NUMBER(b);
  }
  return a == b;
#else
  if (a.type != b.type) return false;
  switch (a.type) {
  case VAL_BOOL:   return AS_BOOL(a) == AS_BOOL(b);


@@ 50,4 68,5 @@ bool valuesEqual(Value a, Value b) {
  case VAL_OBJ:    return AS_OBJ(a) == AS_OBJ(b);
  default:         return false; /* Unreachable. */
  }
#endif
}

M zlox/src/value.h => zlox/src/value.h +46 -0
@@ 3,9 3,53 @@

#include "common.h"

#include <string.h>

typedef struct Obj Obj;
typedef struct ObjString ObjString;

#ifdef NAN_BOXING

#define SIGN_BIT ((uint64_t)0x8000000000000000)
#define QNAN     ((uint64_t)0x7ffc000000000000)

#define TAG_NIL 1 /* 01. */
#define TAG_FALSE 2 /* 10. */
#define TAG_TRUE 3 /* 11. */

typedef uint64_t Value;

#define IS_BOOL(value) (((value) | 1) == TRUE_VAL)
#define IS_NIL(value) ((value) == NIL_VAL)
#define IS_NUMBER(value) (((value) & QNAN) != QNAN)
#define IS_OBJ(value) (((value) & (QNAN | SIGN_BIT)) == (QNAN | SIGN_BIT))

#define AS_BOOL(value) ((value) == TRUE_VAL)
#define AS_NUMBER(value) valueToNum(value)
#define AS_OBJ(value) ((Obj*)(uintptr_t)((value) & ~(SIGN_BIT | QNAN)))

#define BOOL_VAL(b) ((b) ? TRUE_VAL : FALSE_VAL)
#define FALSE_VAL ((Value)(uint64_t)(QNAN | TAG_FALSE))
#define TRUE_VAL ((Value)(uint64_t)(QNAN | TAG_TRUE))
#define NIL_VAL ((Value)(uint64_t)(QNAN | TAG_NIL))
#define NUMBER_VAL(num) numToValue(num)
#define OBJ_VAL(obj) \
  (Value)(SIGN_BIT | QNAN | (uint64_t)(uintptr_t)(obj))

static inline double valueToNum(Value value) {
  double num;
  memcpy(&num, &value, sizeof(Value));
  return num;
}

static inline Value numToValue(double num) {
  Value value;
  memcpy(&value, &num, sizeof(double));
  return value;
}

#else

typedef enum {
  VAL_BOOL,
  VAL_NIL,


@@ 36,6 80,8 @@ typedef struct {
#define NUMBER_VAL(value) ((Value){VAL_NUMBER, {.number = value}})
#define OBJ_VAL(object)   ((Value){VAL_OBJ, {.obj = (Obj*)object}})

#endif

typedef struct {
  int capacity;
  int count;