diff --git a/src/main.c b/src/main.c index 1c1f888..4812697 100644 --- a/src/main.c +++ b/src/main.c @@ -74,6 +74,10 @@ int main(int argc, char *argv[]) { fclose(file); + generate_siphash_key(); + + init_types(); + runtime(translated); free_translator(&translated); diff --git a/src/memory.c b/src/memory.c index 8ddfe51..0ad3f30 100644 --- a/src/memory.c +++ b/src/memory.c @@ -33,7 +33,6 @@ void gmp_gc_free(void *ptr, size_t size) { void ar_memory_init() { GC_INIT(); mp_set_memory_functions(GC_malloc, gmp_gc_realloc, gmp_gc_free); - init_type_obj(); } diff --git a/src/runtime/internals/hashmap/hashmap.c b/src/runtime/internals/hashmap/hashmap.c index f216bdc..9931451 100644 --- a/src/runtime/internals/hashmap/hashmap.c +++ b/src/runtime/internals/hashmap/hashmap.c @@ -1,143 +1,112 @@ #include "hashmap.h" -#include -#include -#include #include "../../../memory.h" +#include +#include +#include +#include +#include -struct hashmap *createHashmap(int size) -{ - struct hashmap *t = (struct hashmap *)ar_alloc(sizeof(struct hashmap)); - t->size = size; - t->list = (struct node **)ar_alloc(sizeof(struct node *) * size); - int i; - for (i = 0; i < size; i++) - t->list[i] = NULL; - return t; +struct hashmap *createHashmap() { + size_t size = 8; + struct hashmap *t = (struct hashmap *)ar_alloc(sizeof(struct hashmap)); + t->size = size; + t->order = 1; + t->list = (struct node **)ar_alloc(sizeof(struct node *) * size); + memset(t->list, 0, sizeof(struct node *) * size); + return t; } -void resize_hashmap(struct hashmap *t) -{ - int old_size = t->size; - int new_size = old_size * 2; +void resize_hashmap(struct hashmap *t) { + int old_size = t->size; + int new_size = old_size * 2; - struct node **old_list = t->list; + struct node **old_list = t->list; - // Create new list - t->list = (struct node **)ar_alloc(sizeof(struct node *) * new_size); - for (int i = 0; i < new_size; i++) - t->list[i] = NULL; + // Create new list + t->list = (struct node **)ar_alloc(sizeof(struct node *) * new_size); + memset(t->list, 0, sizeof(struct node *) * new_size); - t->size = new_size; - t->count = 0; + t->size = new_size; + t->count = 0; - // Rehash old entries into new list - for (int i = 0; i < old_size; i++) { - struct node *temp = old_list[i]; - while (temp) { - hashmap_insert(t, temp->hash, temp->key, temp->val); // Will increment count - temp = temp->next; - } + // Rehash old entries into new list + for (int i = 0; i < old_size; i++) { + struct node *temp = old_list[i]; + while (temp) { + hashmap_insert(t, temp->hash, temp->key, temp->val, + temp->order); // Will increment count + temp = temp->next; } + } } -int hashCode(struct hashmap *t, uint64_t hash) -{ - return hash % t->size; +int hashCode(struct hashmap *t, uint64_t hash) { return hash % t->size; } + +int hashmap_remove(struct hashmap *t, uint64_t hash) { + int pos = hashCode(t, hash); + struct node *list = t->list[pos]; + struct node *temp = list; + struct node *prev = NULL; + while (temp) { + if (temp->hash == hash) { + if (prev) + prev->next = temp->next; + else + t->list[pos] = temp->next; + return 1; + } + prev = temp; + temp = temp->next; + } + list = NULL; + prev = NULL; + temp = NULL; + return 0; } -int hashmap_remove(struct hashmap *t, uint64_t hash) -{ - int pos = hashCode(t, hash); - struct node *list = t->list[pos]; - struct node *temp = list; - struct node *prev = NULL; - while (temp) - { - if (temp->hash == hash) - { - if (prev) - prev->next = temp->next; - else - t->list[pos] = temp->next; +void hashmap_insert(struct hashmap *t, uint64_t hash, void *key, + void *val, size_t order) { + if (!order) { + order = t->order++; + } + if ((t->count + 1) > t->size * 0.75) { + resize_hashmap(t); + } - free(temp); - return 1; - } - prev = temp; - temp = temp->next; + int pos = hashCode(t, hash); + struct node *list = t->list[pos]; + struct node *temp = list; + + // Check if key exists → overwrite + while (temp) { + if (temp->hash == hash) { + temp->val = val; + return; } - return 0; + temp = temp->next; + } + + // Insert new node + struct node *newNode = (struct node *)ar_alloc(sizeof(struct node)); + newNode->hash = hash; + newNode->key = key; + newNode->val = val; + newNode->order = order; + newNode->next = list; + t->list[pos] = newNode; + t->count++; } -void resize(struct hashmap *t) -{ - int old_size = t->size; - int new_size = old_size * 2; - - struct node **old_list = t->list; - - // Create new list - t->list = (struct node **)ar_alloc(sizeof(struct node *) * new_size); - for (int i = 0; i < new_size; i++) - t->list[i] = NULL; - - t->size = new_size; - t->count = 0; - - // Rehash old entries into new list - for (int i = 0; i < old_size; i++) { - struct node *temp = old_list[i]; - while (temp) { - hashmap_insert(t, temp->hash, temp->key, temp->val); // Will increment count - temp = temp->next; - } +void *hashmap_lookup(struct hashmap *t, uint64_t hash) { + int pos = hashCode(t, hash); + struct node *list = t->list[pos]; + struct node *temp = list; + while (temp) { + if (temp->hash == hash) { + return temp->val; } -} - -void hashmap_insert(struct hashmap *t, uint64_t hash, ArgonObject* key, ArgonObject* val) -{ - if ((t->count + 1) > t->size * 0.75) { - resize(t); - } - - int pos = hashCode(t, hash); - struct node *list = t->list[pos]; - struct node *temp = list; - - // Check if key exists → overwrite - while (temp) - { - if (temp->key == key) - { - temp->val = val; - return; - } - temp = temp->next; - } - - // Insert new node - struct node *newNode = (struct node *)ar_alloc(sizeof(struct node)); - newNode->hash = hash; - newNode->key = key; - newNode->val = val; - newNode->next = list; - t->list[pos] = newNode; - t->count++; -} - -void *lookup(struct hashmap *t, uint64_t hash) -{ - int pos = hashCode(t, hash); - struct node *list = t->list[pos]; - struct node *temp = list; - while (temp) - { - if (temp->hash == hash) - { - return temp->val; - } - temp = temp->next; - } - return NULL; + temp = temp->next; + } + return NULL; } \ No newline at end of file diff --git a/src/runtime/internals/hashmap/hashmap.h b/src/runtime/internals/hashmap/hashmap.h index da060eb..ef43608 100644 --- a/src/runtime/internals/hashmap/hashmap.h +++ b/src/runtime/internals/hashmap/hashmap.h @@ -5,26 +5,29 @@ typedef struct ArgonObject ArgonObject; -struct node -{ - uint64_t hash; - ArgonObject *key; - ArgonObject *val; - struct node *next; +struct node { + uint64_t hash; + void *key; + void *val; + size_t order; + struct node *next; }; -struct hashmap -{ - size_t size; - size_t count; - struct node **list; +struct hashmap { + size_t size; + size_t count; + size_t order; + struct node **list; }; -struct hashmap *createHashmap(int size); +struct hashmap *createHashmap(); int hashCode(struct hashmap *t, uint64_t hash); int hashmap_remove(struct hashmap *t, uint64_t hash); -void hashmap_insert(struct hashmap *t, uint64_t hash, ArgonObject* key, ArgonObject* val); +void hashmap_insert(struct hashmap *t, uint64_t hash, void *key, + void *val, size_t order); + +void *hashmap_lookup(struct hashmap *t, uint64_t hash); #endif // HASHMAP_H \ No newline at end of file diff --git a/src/list/list.c b/src/runtime/internals/list/list.c similarity index 98% rename from src/list/list.c rename to src/runtime/internals/list/list.c index c84d0d4..e3c0498 100644 --- a/src/list/list.c +++ b/src/runtime/internals/list/list.c @@ -2,7 +2,7 @@ #include #include #include -#include "../memory.h" +#include "../../../memory.h" LinkedList *create_list(size_t data_size) { LinkedList *list = checked_malloc(sizeof(LinkedList)); diff --git a/src/list/list.h b/src/runtime/internals/list/list.h similarity index 100% rename from src/list/list.h rename to src/runtime/internals/list/list.h diff --git a/src/runtime/internals/siphash/siphash.c b/src/runtime/internals/siphash/siphash.c new file mode 100644 index 0000000..2a746ca --- /dev/null +++ b/src/runtime/internals/siphash/siphash.c @@ -0,0 +1,185 @@ +/* + SipHash reference C implementation + + Copyright (c) 2012-2022 Jean-Philippe Aumasson + + Copyright (c) 2012-2014 Daniel J. Bernstein + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along + with + this software. If not, see + . + */ + +#include "siphash.h" +#include +#include +#include + +/* default: SipHash-2-4 */ +#ifndef cROUNDS +#define cROUNDS 2 +#endif +#ifndef dROUNDS +#define dROUNDS 4 +#endif + +#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b)))) + +#define U32TO8_LE(p, v) \ + (p)[0] = (uint8_t)((v)); \ + (p)[1] = (uint8_t)((v) >> 8); \ + (p)[2] = (uint8_t)((v) >> 16); \ + (p)[3] = (uint8_t)((v) >> 24); + +#define U64TO8_LE(p, v) \ + U32TO8_LE((p), (uint32_t)((v))); \ + U32TO8_LE((p) + 4, (uint32_t)((v) >> 32)); + +#define U8TO64_LE(p) \ + (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) | \ + ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) | \ + ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) | \ + ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56)) + +#define SIPROUND \ + do { \ + v0 += v1; \ + v1 = ROTL(v1, 13); \ + v1 ^= v0; \ + v0 = ROTL(v0, 32); \ + v2 += v3; \ + v3 = ROTL(v3, 16); \ + v3 ^= v2; \ + v0 += v3; \ + v3 = ROTL(v3, 21); \ + v3 ^= v0; \ + v2 += v1; \ + v1 = ROTL(v1, 17); \ + v1 ^= v2; \ + v2 = ROTL(v2, 32); \ + } while (0) + +#ifdef DEBUG_SIPHASH +#include + +#define TRACE \ + do { \ + printf("(%3zu) v0 %016" PRIx64 "\n", inlen, v0); \ + printf("(%3zu) v1 %016" PRIx64 "\n", inlen, v1); \ + printf("(%3zu) v2 %016" PRIx64 "\n", inlen, v2); \ + printf("(%3zu) v3 %016" PRIx64 "\n", inlen, v3); \ + } while (0) +#else +#define TRACE +#endif + +/* + Computes a SipHash value + *in: pointer to input data (read-only) + inlen: input data length in bytes (any size_t value) + *k: pointer to the key data (read-only), must be 16 bytes + *out: pointer to output data (write-only), outlen bytes must be allocated + outlen: length of the output in bytes, must be 8 or 16 +*/ +int siphash(const void *in, const size_t inlen, const void *k, uint8_t *out, + const size_t outlen) { + + const unsigned char *ni = (const unsigned char *)in; + const unsigned char *kk = (const unsigned char *)k; + + assert((outlen == 8) || (outlen == 16)); + uint64_t v0 = UINT64_C(0x736f6d6570736575); + uint64_t v1 = UINT64_C(0x646f72616e646f6d); + uint64_t v2 = UINT64_C(0x6c7967656e657261); + uint64_t v3 = UINT64_C(0x7465646279746573); + uint64_t k0 = U8TO64_LE(kk); + uint64_t k1 = U8TO64_LE(kk + 8); + uint64_t m; + int i; + const unsigned char *end = ni + inlen - (inlen % sizeof(uint64_t)); + const int left = inlen & 7; + uint64_t b = ((uint64_t)inlen) << 56; + v3 ^= k1; + v2 ^= k0; + v1 ^= k1; + v0 ^= k0; + + if (outlen == 16) + v1 ^= 0xee; + + for (; ni != end; ni += 8) { + m = U8TO64_LE(ni); + v3 ^= m; + + TRACE; + for (i = 0; i < cROUNDS; ++i) + SIPROUND; + + v0 ^= m; + } + + switch (left) { + case 7: + b |= ((uint64_t)ni[6]) << 48; + /* FALLTHRU */ + case 6: + b |= ((uint64_t)ni[5]) << 40; + /* FALLTHRU */ + case 5: + b |= ((uint64_t)ni[4]) << 32; + /* FALLTHRU */ + case 4: + b |= ((uint64_t)ni[3]) << 24; + /* FALLTHRU */ + case 3: + b |= ((uint64_t)ni[2]) << 16; + /* FALLTHRU */ + case 2: + b |= ((uint64_t)ni[1]) << 8; + /* FALLTHRU */ + case 1: + b |= ((uint64_t)ni[0]); + break; + case 0: + break; + } + + v3 ^= b; + + TRACE; + for (i = 0; i < cROUNDS; ++i) + SIPROUND; + + v0 ^= b; + + if (outlen == 16) + v2 ^= 0xee; + else + v2 ^= 0xff; + + TRACE; + for (i = 0; i < dROUNDS; ++i) + SIPROUND; + + b = v0 ^ v1 ^ v2 ^ v3; + U64TO8_LE(out, b); + + if (outlen == 8) + return 0; + + v1 ^= 0xdd; + + TRACE; + for (i = 0; i < dROUNDS; ++i) + SIPROUND; + + b = v0 ^ v1 ^ v2 ^ v3; + U64TO8_LE(out + 8, b); + + return 0; +} \ No newline at end of file diff --git a/src/runtime/internals/siphash/siphash.h b/src/runtime/internals/siphash/siphash.h new file mode 100644 index 0000000..0ae674e --- /dev/null +++ b/src/runtime/internals/siphash/siphash.h @@ -0,0 +1,22 @@ +/* + SipHash reference C implementation + + Copyright (c) 2012-2021 Jean-Philippe Aumasson + + Copyright (c) 2012-2014 Daniel J. Bernstein + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along + with + this software. If not, see + . + */ + +#include +#include + +int siphash(const void *in, const size_t inlen, const void *k, uint8_t *out, + const size_t outlen); \ No newline at end of file diff --git a/src/runtime/objects/object.c b/src/runtime/objects/object.c index 7b7a779..39f3294 100644 --- a/src/runtime/objects/object.c +++ b/src/runtime/objects/object.c @@ -1,9 +1,17 @@ #include "object.h" #include "../../memory.h" +#include "../runtime.h" +#include ArgonObject* init_argon_object() { ArgonObject *object = ar_alloc(sizeof(ArgonObject)); object->type = TYPE_OBJECT; - object->cls = object; - object->fields = createHashmap(8); + object->typeObject = NULL; + object->fields = createHashmap(); + memset(&object->value, 0, sizeof(object->value)); + return object; +} + +void add_field(ArgonObject*target, char* name, ArgonObject *object) { + hashmap_insert(target->fields, siphash64_bytes(name, strlen(name)),name, object, 0); } \ No newline at end of file diff --git a/src/runtime/objects/object.h b/src/runtime/objects/object.h index 9f7950b..561bd29 100644 --- a/src/runtime/objects/object.h +++ b/src/runtime/objects/object.h @@ -4,6 +4,11 @@ #include #include +struct string_struct { + char *data; + size_t length; +}; + typedef enum { TYPE_NULL, TYPE_BOOL, @@ -16,14 +21,19 @@ typedef enum { struct ArgonObject { ArgonType type; - struct ArgonObject *cls; // class pointer or type object - struct hashmap *fields; // dynamic fields/methods + ArgonObject *typeObject; + struct hashmap *fields; // dynamic fields/methods union { mpq_t as_number; bool as_bool; - char *as_str; + struct string_struct as_str; void *native_fn; // others as needed } value; }; +typedef struct ArgonObject ArgonObject; + +ArgonObject *init_argon_object(); + +void add_field(ArgonObject*target, char* name, ArgonObject *object); #endif // OBJECT_H \ No newline at end of file diff --git a/src/runtime/objects/string/string.c b/src/runtime/objects/string/string.c new file mode 100644 index 0000000..bc7f439 --- /dev/null +++ b/src/runtime/objects/string/string.c @@ -0,0 +1,16 @@ +#include "../object.h" +#include + +ArgonObject *ARGON_STRING_TYPE = NULL; + +void init_string_type() { + ARGON_STRING_TYPE = init_argon_object(); +} + +ArgonObject *init_string_object(char*data, size_t length) { + ArgonObject * object = init_argon_object(); + object->typeObject = ARGON_STRING_TYPE; + object->value.as_str.data = data; + object->value.as_str.length = length; + return object; +} \ No newline at end of file diff --git a/src/runtime/objects/string/string.h b/src/runtime/objects/string/string.h new file mode 100644 index 0000000..2903245 --- /dev/null +++ b/src/runtime/objects/string/string.h @@ -0,0 +1,11 @@ +#ifndef STRING_OBJ_H +#define STRING_OBJ_H +#include "../object.h" + +extern ArgonObject *ARGON_STRING_TYPE; + +void init_string_type(); + +ArgonObject *init_string_object(char*data, size_t length); + +#endif // STRING_OBJ_H \ No newline at end of file diff --git a/src/runtime/objects/type/type.c b/src/runtime/objects/type/type.c index 63e4393..78ea960 100644 --- a/src/runtime/objects/type/type.c +++ b/src/runtime/objects/type/type.c @@ -1,15 +1,10 @@ -#include "../object.h" #include "../../internals/hashmap/hashmap.h" -#include "../../../memory.h" +#include "../object.h" #include #include "type.h" -ArgonObject *ARGON_TYPE_OBJ = NULL; +ArgonObject *ARGON_TYPE = NULL; -void init_type_obj() { - ARGON_TYPE_OBJ = ar_alloc(sizeof(ArgonObject)); - ARGON_TYPE_OBJ->type = TYPE_OBJECT; - ARGON_TYPE_OBJ->cls = ARGON_TYPE_OBJ; - ARGON_TYPE_OBJ->fields = createHashmap(8); - memset(&ARGON_TYPE_OBJ->value, 0, sizeof(ARGON_TYPE_OBJ->value)); +void init_type() { + ARGON_TYPE = init_argon_object(); } \ No newline at end of file diff --git a/src/runtime/objects/type/type.h b/src/runtime/objects/type/type.h index 83f6783..2fc0945 100644 --- a/src/runtime/objects/type/type.h +++ b/src/runtime/objects/type/type.h @@ -2,9 +2,9 @@ #define TYPES_H #include "../object.h" -extern ArgonObject *ARGON_TYPE_OBJ; +extern ArgonObject *ARGON_TYPE; -void init_type_obj(); +void init_type(); #endif // TYPES_H \ No newline at end of file diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index 295de2a..0ea089e 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -3,6 +3,16 @@ #include #include #include +#include +#include +#include "internals/siphash/siphash.h" +#include "objects/type/type.h" +#include "objects/string/string.h" + +void init_types() { + init_type(); + init_string_type(); +} uint64_t pop_bytecode(Translated *translated, RuntimeState *state) { uint64_t *instruction = darray_get(&translated->bytecode, state->head++); @@ -21,4 +31,28 @@ void runtime(Translated translated) { while (state.head < translated.bytecode.size) run_instruction(&translated, &state); free(state.registers); +} + + + +static uint8_t siphash_key[16]; + +void generate_siphash_key() { + int fd = open("/dev/urandom", O_RDONLY); + if (fd < 0 || read(fd, siphash_key, 16) != 16) { + // Fallback or abort + } + close(fd); +} + +uint64_t siphash64_bytes(const void *data, size_t len) { + uint8_t out[8]; + if (siphash(data, len, siphash_key, out, sizeof(out)) != 0) + return 0; + + uint64_t hash = 0; + for (int i = 0; i < 8; ++i) + hash |= ((uint64_t)out[i]) << (8 * i); + + return hash; } \ No newline at end of file diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index afc47e5..d533e5e 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -7,9 +7,14 @@ typedef struct { size_t head; } RuntimeState; +void init_types(); void run_instruction(Translated *translated, RuntimeState *state); void runtime(Translated translated); +uint64_t siphash64_bytes(const void *data, size_t len); + +void generate_siphash_key(); + #endif // RUNTIME_H \ No newline at end of file