improve performance for integers

This commit is contained in:
William Bell
2025-08-30 03:29:02 +01:00
parent 4fc28d3b76
commit 4f91bf48f3
16 changed files with 456 additions and 187 deletions

7
app.py
View File

@@ -1,4 +1,3 @@
def f(): i = 1000000
return f() while i:
i=i-1
f()

View File

@@ -40,6 +40,7 @@ typedef struct {
typedef struct { typedef struct {
uint8_t registerCount; uint8_t registerCount;
uint8_t registerAssignment;
DArray *return_jumps; DArray *return_jumps;
DArray bytecode; DArray bytecode;
ConstantArena constants; ConstantArena constants;
@@ -74,7 +75,13 @@ struct ArgonObject {
struct hashmap_GC *dict; struct hashmap_GC *dict;
bool as_bool; bool as_bool;
union { union {
mpq_t *as_number; struct as_number {
bool is_int64;
union {
mpq_t *mpq;
int64_t i64;
} n;
}as_number;
struct string_struct as_str; struct string_struct as_str;
native_fn native_fn; native_fn native_fn;
struct argon_function_struct argon_fn; struct argon_function_struct argon_fn;

View File

@@ -427,7 +427,7 @@ Translated load_argon_file(char *path, ArErr *err) {
} }
hashmap_free(translated.constants.hashmap, NULL); hashmap_free(translated.constants.hashmap, NULL);
Translated gc_translated = { Translated gc_translated = {
translated.registerCount, NULL, {}, {}, translated.path}; translated.registerCount, translated.registerAssignment,NULL, {}, {}, translated.path};
gc_translated.bytecode.data = ar_alloc_atomic(translated.bytecode.capacity); gc_translated.bytecode.data = ar_alloc_atomic(translated.bytecode.capacity);
memcpy(gc_translated.bytecode.data, translated.bytecode.data, memcpy(gc_translated.bytecode.data, translated.bytecode.data,
translated.bytecode.capacity); translated.bytecode.capacity);

View File

@@ -94,6 +94,8 @@ void free_parsed_while(void *ptr) {
ParsedValue *parsedValue = ptr; ParsedValue *parsedValue = ptr;
ParsedWhile *parsed_while = parsedValue->data; ParsedWhile *parsed_while = parsedValue->data;
free_parsed(parsed_while->condition); free_parsed(parsed_while->condition);
free(parsed_while->condition);
free_parsed(parsed_while->content); free_parsed(parsed_while->content);
free(parsed_while->content);
free(parsed_while); free(parsed_while);
} }

View File

@@ -134,6 +134,7 @@ ArErr run_call(ArgonObject *original_object, size_t argc, ArgonObject **argv,
} }
StackFrame new_stackFrame = { StackFrame new_stackFrame = {
{object->value.argon_fn.translated.registerCount, {object->value.argon_fn.translated.registerCount,
object->value.argon_fn.translated.registerAssignment,
NULL, NULL,
{object->value.argon_fn.bytecode, sizeof(uint8_t), {object->value.argon_fn.bytecode, sizeof(uint8_t),
object->value.argon_fn.bytecode_length, object->value.argon_fn.bytecode_length,

View File

@@ -7,6 +7,7 @@
#include "number.h" #include "number.h"
#include "../functions/functions.h" #include "../functions/functions.h"
#include "../string/string.h" #include "../string/string.h"
#include <gmp-x86_64.h>
#include <gmp.h> #include <gmp.h>
#include <inttypes.h> #include <inttypes.h>
#include <stdio.h> #include <stdio.h>
@@ -72,8 +73,7 @@ ArgonObject *ARGON_NUMBER_TYPE___boolean__(size_t argc, ArgonObject **argv,
"__boolean__ expects 1 arguments, got %" PRIu64, argc); "__boolean__ expects 1 arguments, got %" PRIu64, argc);
return ARGON_NULL; return ARGON_NULL;
} }
return mpq_cmp_si(*argv[0]->value.as_number, 0, 1) == 0 ? ARGON_FALSE return argv[0]->as_bool ? ARGON_FALSE : ARGON_TRUE;
: ARGON_TRUE;
} }
ArgonObject *ARGON_NUMBER_TYPE___add__(size_t argc, ArgonObject **argv, ArgonObject *ARGON_NUMBER_TYPE___add__(size_t argc, ArgonObject **argv,
@@ -87,22 +87,60 @@ ArgonObject *ARGON_NUMBER_TYPE___add__(size_t argc, ArgonObject **argv,
if (argv[1]->type != TYPE_NUMBER) { if (argv[1]->type != TYPE_NUMBER) {
ArgonObject *type_name = get_field_for_class( ArgonObject *type_name = get_field_for_class(
get_field(argv[1], "__class__", false, false), "__name__", argv[1]); get_field(argv[1], "__class__", false, false), "__name__", argv[1]);
*err = create_err(0, 0, 0, "", "Runtime Error", *err = create_err(
"__add__ cannot perform addition between a number and %.*s", 0, 0, 0, "", "Runtime Error",
type_name->value.as_str.length, "__add__ cannot perform addition between a number and %.*s",
type_name->value.as_str.data); type_name->value.as_str.length, type_name->value.as_str.data);
return ARGON_NULL; return ARGON_NULL;
} }
mpq_t r; if (argv[0]->value.as_number.is_int64 && argv[1]->value.as_number.is_int64) {
mpq_init(r); int64_t a = argv[0]->value.as_number.n.i64;
mpq_add(r, *argv[0]->value.as_number, *argv[1]->value.as_number); int64_t b = argv[1]->value.as_number.n.i64;
ArgonObject *result = new_number_object(r); bool gonna_overflow = (a > 0 && b > 0 && a > INT64_MAX - b) ||
mpq_clear(r); (a < 0 && b < 0 && a < INT64_MIN - b);
return result; if (!gonna_overflow) {
return new_number_object_from_num_and_den(a + b, 1);
}
mpq_t a_GMP, b_GMP;
mpq_init(a_GMP);
mpq_init(b_GMP);
mpq_set_si(a_GMP, a, 1);
mpq_set_si(b_GMP, b, 1);
mpq_add(a_GMP, a_GMP, b_GMP);
ArgonObject *result = new_number_object(a_GMP);
mpq_clear(a_GMP);
mpq_clear(b_GMP);
return result;
} else if (!argv[0]->value.as_number.is_int64 &&
!argv[1]->value.as_number.is_int64) {
mpq_t r;
mpq_init(r);
mpq_add(r, *argv[0]->value.as_number.n.mpq,
*argv[1]->value.as_number.n.mpq);
ArgonObject *result = new_number_object(r);
mpq_clear(r);
return result;
} else {
mpq_t a_GMP, b_GMP;
mpq_init(a_GMP);
mpq_init(b_GMP);
if (argv[0]->value.as_number.is_int64) {
mpq_set_si(a_GMP, argv[0]->value.as_number.n.i64, 1);
mpq_set(b_GMP, *argv[1]->value.as_number.n.mpq);
} else {
mpq_set(a_GMP, *argv[0]->value.as_number.n.mpq);
mpq_set_si(b_GMP, argv[1]->value.as_number.n.i64, 1);
}
mpq_add(a_GMP, a_GMP, b_GMP);
ArgonObject *result = new_number_object(a_GMP);
mpq_clear(a_GMP);
mpq_clear(b_GMP);
return result;
}
} }
ArgonObject *ARGON_NUMBER_TYPE___subtract__(size_t argc, ArgonObject **argv, ArgonObject *ARGON_NUMBER_TYPE___subtract__(size_t argc, ArgonObject **argv,
ArErr *err, RuntimeState *state) { ArErr *err, RuntimeState *state) {
(void)state; (void)state;
if (argc != 2) { if (argc != 2) {
*err = create_err(0, 0, 0, "", "Runtime Error", *err = create_err(0, 0, 0, "", "Runtime Error",
@@ -114,20 +152,61 @@ ArgonObject *ARGON_NUMBER_TYPE___subtract__(size_t argc, ArgonObject **argv,
if (argv[1]->type != TYPE_NUMBER) { if (argv[1]->type != TYPE_NUMBER) {
ArgonObject *type_name = get_field_for_class( ArgonObject *type_name = get_field_for_class(
get_field(argv[1], "__class__", false, false), "__name__", argv[1]); get_field(argv[1], "__class__", false, false), "__name__", argv[1]);
*err = create_err(0, 0, 0, "", "Runtime Error", *err = create_err(
"__subtract__ cannot perform subtraction between number and %.*s", 0, 0, 0, "", "Runtime Error",
type_name->value.as_str.length, "__subtract__ cannot perform subtraction between number and %.*s",
type_name->value.as_str.data); type_name->value.as_str.length, type_name->value.as_str.data);
return ARGON_NULL; return ARGON_NULL;
} }
mpq_sub(r, *argv[0]->value.as_number, *argv[1]->value.as_number); if (argv[0]->value.as_number.is_int64 && argv[1]->value.as_number.is_int64) {
ArgonObject *result = new_number_object(r); int64_t a = argv[0]->value.as_number.n.i64;
mpq_clear(r); int64_t b = argv[1]->value.as_number.n.i64;
return result; int64_t neg_a = -a;
bool gonna_overflow = (neg_a > 0 && b > 0 && b > INT64_MAX - neg_a) ||
(neg_a < 0 && b < 0 && b < INT64_MIN - neg_a);
if (!gonna_overflow) {
return new_number_object_from_num_and_den(a - b, 1);
}
mpq_t a_GMP, b_GMP;
mpq_init(a_GMP);
mpq_init(b_GMP);
mpq_set_si(a_GMP, a, 1);
mpq_set_si(b_GMP, b, 1);
mpq_sub(a_GMP, a_GMP, b_GMP);
ArgonObject *result = new_number_object(a_GMP);
mpq_clear(a_GMP);
mpq_clear(b_GMP);
return result;
} else if (!argv[0]->value.as_number.is_int64 &&
!argv[1]->value.as_number.is_int64) {
mpq_t r;
mpq_init(r);
mpq_sub(r, *argv[0]->value.as_number.n.mpq,
*argv[1]->value.as_number.n.mpq);
ArgonObject *result = new_number_object(r);
mpq_clear(r);
return result;
} else {
mpq_t a_GMP, b_GMP;
mpq_init(a_GMP);
mpq_init(b_GMP);
if (argv[0]->value.as_number.is_int64) {
mpq_set_si(a_GMP, argv[0]->value.as_number.n.i64, 1);
mpq_set(b_GMP, *argv[1]->value.as_number.n.mpq);
} else {
mpq_set(a_GMP, *argv[0]->value.as_number.n.mpq);
mpq_set_si(b_GMP, argv[1]->value.as_number.n.i64, 1);
}
mpq_sub(a_GMP, a_GMP, b_GMP);
ArgonObject *result = new_number_object(a_GMP);
mpq_clear(a_GMP);
mpq_clear(b_GMP);
return result;
}
} }
ArgonObject *ARGON_NUMBER_TYPE___multiply__(size_t argc, ArgonObject **argv, ArgonObject *ARGON_NUMBER_TYPE___multiply__(size_t argc, ArgonObject **argv,
ArErr *err, RuntimeState *state) { ArErr *err, RuntimeState *state) {
(void)state; (void)state;
if (argc != 2) { if (argc != 2) {
*err = create_err(0, 0, 0, "", "Runtime Error", *err = create_err(0, 0, 0, "", "Runtime Error",
@@ -139,20 +218,20 @@ ArgonObject *ARGON_NUMBER_TYPE___multiply__(size_t argc, ArgonObject **argv,
if (argv[1]->type != TYPE_NUMBER) { if (argv[1]->type != TYPE_NUMBER) {
ArgonObject *type_name = get_field_for_class( ArgonObject *type_name = get_field_for_class(
get_field(argv[1], "__class__", false, false), "__name__", argv[1]); get_field(argv[1], "__class__", false, false), "__name__", argv[1]);
*err = create_err(0, 0, 0, "", "Runtime Error", *err = create_err(
"__multiply__ cannot perform multiplication between number and %.*s", 0, 0, 0, "", "Runtime Error",
type_name->value.as_str.length, "__multiply__ cannot perform multiplication between number and %.*s",
type_name->value.as_str.data); type_name->value.as_str.length, type_name->value.as_str.data);
return ARGON_NULL; return ARGON_NULL;
} }
mpq_mul(r, *argv[0]->value.as_number, *argv[1]->value.as_number); mpq_mul(r, *argv[0]->value.as_number.n.mpq, *argv[1]->value.as_number.n.mpq);
ArgonObject *result = new_number_object(r); ArgonObject *result = new_number_object(r);
mpq_clear(r); mpq_clear(r);
return result; return result;
} }
ArgonObject *ARGON_NUMBER_TYPE___division__(size_t argc, ArgonObject **argv, ArgonObject *ARGON_NUMBER_TYPE___division__(size_t argc, ArgonObject **argv,
ArErr *err, RuntimeState *state) { ArErr *err, RuntimeState *state) {
(void)state; (void)state;
if (argc != 2) { if (argc != 2) {
*err = create_err(0, 0, 0, "", "Runtime Error", *err = create_err(0, 0, 0, "", "Runtime Error",
@@ -164,13 +243,13 @@ ArgonObject *ARGON_NUMBER_TYPE___division__(size_t argc, ArgonObject **argv,
if (argv[1]->type != TYPE_NUMBER) { if (argv[1]->type != TYPE_NUMBER) {
ArgonObject *type_name = get_field_for_class( ArgonObject *type_name = get_field_for_class(
get_field(argv[1], "__class__", false, false), "__name__", argv[1]); get_field(argv[1], "__class__", false, false), "__name__", argv[1]);
*err = create_err(0, 0, 0, "", "Runtime Error", *err = create_err(
"__division__ cannot perform division between number and %.*s", 0, 0, 0, "", "Runtime Error",
type_name->value.as_str.length, "__division__ cannot perform division between number and %.*s",
type_name->value.as_str.data); type_name->value.as_str.length, type_name->value.as_str.data);
return ARGON_NULL; return ARGON_NULL;
} }
mpq_div(r, *argv[0]->value.as_number, *argv[1]->value.as_number); mpq_div(r, *argv[0]->value.as_number.n.mpq, *argv[1]->value.as_number.n.mpq);
ArgonObject *result = new_number_object(r); ArgonObject *result = new_number_object(r);
mpq_clear(r); mpq_clear(r);
return result; return result;
@@ -185,7 +264,13 @@ ArgonObject *ARGON_NUMBER_TYPE___string__(size_t argc, ArgonObject **argv,
return NULL; return NULL;
} }
mpq_t *num = argv[0]->value.as_number; if (argv[0]->value.as_number.is_int64) {
char buf[32];
snprintf(buf, sizeof(buf), "%" PRId64, argv[0]->value.as_number.n.i64);
return new_string_object_null_terminated(buf);
}
mpq_t *num = argv[0]->value.as_number.n.mpq;
/* If denominator == 1, print numerator as full integer */ /* If denominator == 1, print numerator as full integer */
if (mpz_cmp_ui(mpq_denref(*num), 1) == 0) { if (mpz_cmp_ui(mpq_denref(*num), 1) == 0) {
@@ -327,6 +412,20 @@ ArgonObject *ARGON_NUMBER_TYPE___string__(size_t argc, ArgonObject **argv,
return result; return result;
} }
ArgonObject small_ints[UINT8_MAX * 2];
void init_small_ints() {
for (uint64_t i = 0; i < UINT8_MAX * 2; i++) {
small_ints[i].type = TYPE_NUMBER;
small_ints[i].dict = createHashmap_GC();
add_field(&small_ints[i], "__class__", ARGON_NUMBER_TYPE);
add_field(&small_ints[i], "__base__", BASE_CLASS);
small_ints[i].value.as_number.is_int64 = true;
small_ints[i].value.as_number.n.i64 = i;
small_ints[i].as_bool = i;
}
}
void create_ARGON_NUMBER_TYPE() { void create_ARGON_NUMBER_TYPE() {
ARGON_NUMBER_TYPE = new_object(); ARGON_NUMBER_TYPE = new_object();
add_field(ARGON_NUMBER_TYPE, "__name__", add_field(ARGON_NUMBER_TYPE, "__name__",
@@ -343,8 +442,7 @@ void create_ARGON_NUMBER_TYPE() {
create_argon_native_function("__boolean__", create_argon_native_function("__boolean__",
ARGON_NUMBER_TYPE___boolean__)); ARGON_NUMBER_TYPE___boolean__));
add_field(ARGON_NUMBER_TYPE, "__add__", add_field(ARGON_NUMBER_TYPE, "__add__",
create_argon_native_function("__add__", create_argon_native_function("__add__", ARGON_NUMBER_TYPE___add__));
ARGON_NUMBER_TYPE___add__));
add_field(ARGON_NUMBER_TYPE, "__subtract__", add_field(ARGON_NUMBER_TYPE, "__subtract__",
create_argon_native_function("__subtract__", create_argon_native_function("__subtract__",
ARGON_NUMBER_TYPE___subtract__)); ARGON_NUMBER_TYPE___subtract__));
@@ -354,6 +452,7 @@ void create_ARGON_NUMBER_TYPE() {
add_field(ARGON_NUMBER_TYPE, "__division__", add_field(ARGON_NUMBER_TYPE, "__division__",
create_argon_native_function("__division__", create_argon_native_function("__division__",
ARGON_NUMBER_TYPE___division__)); ARGON_NUMBER_TYPE___division__));
init_small_ints();
} }
void mpz_init_gc_managed(mpz_t z, size_t limbs_count) { void mpz_init_gc_managed(mpz_t z, size_t limbs_count) {
@@ -393,43 +492,116 @@ mpq_t *mpq_new_gc_from(const mpq_t src) {
return dest; return dest;
} }
bool mpq_to_int64(mpq_t q, int64_t *out) {
// Check denominator == 1
if (mpz_cmp_ui(mpq_denref(q), 1) != 0) {
return false;
}
// Get numerator
mpz_t num;
mpz_init(num);
mpz_set(num, mpq_numref(q));
// Check bounds
if (mpz_cmp_si(num, INT64_MIN) < 0 || mpz_cmp_si(num, INT64_MAX) > 0) {
mpz_clear(num);
return false;
}
*out = mpz_get_si(num); // safe because we checked range
mpz_clear(num);
return true;
}
bool double_to_int64(double x, int64_t *out) {
if (x < (double)INT64_MIN || x > (double)INT64_MAX) {
return false;
}
int64_t i = (int64_t)x;
if ((double)i == x) { // no fractional part
*out = i;
return true;
}
return false;
}
ArgonObject *new_number_object(mpq_t number) { ArgonObject *new_number_object(mpq_t number) {
int64_t i64 = 0;
bool is_int64 = mpq_to_int64(number, &i64);
if (is_int64 && i64 >= INT8_MIN * 2 && i64 <= INT8_MAX * 2) {
return &small_ints[i64];
}
ArgonObject *object = new_object(); ArgonObject *object = new_object();
add_field(object, "__class__", ARGON_NUMBER_TYPE); add_field(object, "__class__", ARGON_NUMBER_TYPE);
object->type = TYPE_NUMBER; object->type = TYPE_NUMBER;
object->value.as_number = mpq_new_gc_from(number); object->value.as_number.n.i64 = i64;
object->as_bool = mpq_cmp_si(number, 0, 1) != 0; object->value.as_number.is_int64 = is_int64;
if (object->value.as_number.is_int64) {
object->as_bool = object->value.as_number.n.i64;
} else {
object->value.as_number.n.mpq = mpq_new_gc_from(number);
object->as_bool = mpq_cmp_si(number, 0, 1) != 0;
}
return object; return object;
} }
ArgonObject *new_number_object_from_long(long n, unsigned long d) { ArgonObject *new_number_object_from_num_and_den(int64_t n, uint64_t d) {
if (d == 1 && n >= INT8_MIN && n <= INT8_MAX) {
return &small_ints[(int8_t)n];
}
ArgonObject *object = new_object(); ArgonObject *object = new_object();
add_field(object, "__class__", ARGON_NUMBER_TYPE); add_field(object, "__class__", ARGON_NUMBER_TYPE);
mpq_t r;
mpq_init(r);
mpq_set_si(r, n, d);
object->type = TYPE_NUMBER; object->type = TYPE_NUMBER;
object->value.as_number = mpq_new_gc_from(r); if (d == 1) {
object->as_bool = n!=0; object->value.as_number.is_int64 = true;
mpq_clear(r); object->value.as_number.n.i64 = n;
object->as_bool = n;
} else {
object->value.as_number.is_int64 = false;
mpq_t r;
mpq_init(r);
mpq_set_si(r, n, d);
object->value.as_number.n.mpq = mpq_new_gc_from(r);
object->as_bool = n != 0;
mpq_clear(r);
}
return object; return object;
} }
ArgonObject *new_number_object_from_double(double d) { ArgonObject *new_number_object_from_double(double d) {
int64_t i64 = 0;
bool is_int64 = double_to_int64(d, &i64);
if (is_int64 && i64 >= INT8_MIN && i64 <= INT8_MAX) {
return &small_ints[(int8_t)i64];
}
ArgonObject *object = new_object(); ArgonObject *object = new_object();
add_field(object, "__class__", ARGON_NUMBER_TYPE); add_field(object, "__class__", ARGON_NUMBER_TYPE);
mpq_t r;
mpq_init(r);
mpq_set_d(r, d);
object->type = TYPE_NUMBER; object->type = TYPE_NUMBER;
object->value.as_number = mpq_new_gc_from(r); object->value.as_number.n.i64 = i64;
object->as_bool = d!=0; object->value.as_number.is_int64 = is_int64;
mpq_clear(r); if (object->value.as_number.is_int64) {
object->as_bool = object->value.as_number.n.i64;
} else {
mpq_t r;
mpq_init(r);
mpq_set_d(r, d);
object->value.as_number.n.mpq = mpq_new_gc_from(r);
object->as_bool = d != 0;
mpq_clear(r);
}
return object; return object;
} }
void load_number(Translated *translated, RuntimeState *state) { void load_number(Translated *translated, RuntimeState *state) {
uint8_t to_register = pop_byte(translated, state); uint8_t to_register = pop_byte(translated, state);
uint8_t is_int64 = pop_byte(translated, state);
if (is_int64) {
state->registers[to_register] =
new_number_object_from_num_and_den(pop_bytecode(translated, state), 1);
return;
}
size_t num_size = pop_bytecode(translated, state); size_t num_size = pop_bytecode(translated, state);
size_t num_pos = pop_bytecode(translated, state); size_t num_pos = pop_bytecode(translated, state);
mpq_t r; mpq_t r;

View File

@@ -14,10 +14,12 @@ void create_ARGON_NUMBER_TYPE();
ArgonObject *new_number_object(mpq_t number); ArgonObject *new_number_object(mpq_t number);
bool mpq_to_int64(mpq_t q, int64_t *out);
void load_number(Translated *translated, RuntimeState *state); void load_number(Translated *translated, RuntimeState *state);
ArgonObject *new_number_object_from_double(double d); ArgonObject *new_number_object_from_double(double d);
ArgonObject *new_number_object_from_long(long n, unsigned long d); ArgonObject *new_number_object_from_num_and_den(int64_t n, uint64_t d);
#endif // RUNTIME_NUMBER_H #endif // RUNTIME_NUMBER_H

View File

@@ -15,6 +15,7 @@
ArgonObject *BASE_CLASS = NULL; ArgonObject *BASE_CLASS = NULL;
ArgonObject *new_object() { ArgonObject *new_object() {
ArgonObject *object = ar_alloc(sizeof(ArgonObject)); ArgonObject *object = ar_alloc(sizeof(ArgonObject));
object->type = TYPE_OBJECT; object->type = TYPE_OBJECT;

View File

@@ -17,7 +17,7 @@ ArgonObject *ARGON_STRING_TYPE = NULL;
ArgonObject *new_string_object(char*data, size_t length) { ArgonObject *new_string_object(char*data, size_t length) {
ArgonObject * object = new_object(); ArgonObject * object = new_object();
add_field(object, "__class__", ARGON_STRING_TYPE); add_field(object, "__class__", ARGON_STRING_TYPE);
add_field(object, "length", new_number_object_from_long(length, 1)); add_field(object, "length", new_number_object_from_num_and_den(length, 1));
object->type = TYPE_STRING; object->type = TYPE_STRING;
object->value.as_str.data = ar_alloc_atomic(length); object->value.as_str.data = ar_alloc_atomic(length);
memcpy(object->value.as_str.data, data, length); memcpy(object->value.as_str.data, data, length);

View File

@@ -376,7 +376,7 @@ ArgonObject *ARGON_BOOL_TYPE___number__(size_t argc, ArgonObject **argv,
"__number__ expects 1 arguments, got %" PRIu64, argc); "__number__ expects 1 arguments, got %" PRIu64, argc);
return ARGON_NULL; return ARGON_NULL;
} }
return new_number_object_from_long(argv[0] == ARGON_TRUE, 1); return new_number_object_from_num_and_den(argv[0] == ARGON_TRUE, 1);
} }
ArgonObject *ARGON_STRING_TYPE___string__(size_t argc, ArgonObject **argv, ArgonObject *ARGON_STRING_TYPE___string__(size_t argc, ArgonObject **argv,
@@ -451,7 +451,7 @@ ArgonObject *ARGON_NULL_TYPE___number__(size_t argc, ArgonObject **argv,
*err = create_err(0, 0, 0, "", "Runtime Error", *err = create_err(0, 0, 0, "", "Runtime Error",
"__boolean__ expects 1 arguments, got %" PRIu64, argc); "__boolean__ expects 1 arguments, got %" PRIu64, argc);
} }
return new_number_object_from_long(0, 1); return new_number_object_from_num_and_den(0, 1);
} }
ArgonObject *ARGON_NULL_TYPE___string__(size_t argc, ArgonObject **argv, ArgonObject *ARGON_NULL_TYPE___string__(size_t argc, ArgonObject **argv,
ArErr *err, RuntimeState *state) { ArErr *err, RuntimeState *state) {
@@ -655,29 +655,28 @@ static inline ArErr load_variable(Translated *translated, RuntimeState *state,
static inline ArErr run_instruction(Translated *translated, RuntimeState *state, static inline ArErr run_instruction(Translated *translated, RuntimeState *state,
struct Stack **stack) { struct Stack **stack) {
static void *dispatch_table[] = { static void *dispatch_table[] = {[OP_LOAD_STRING] = &&DO_LOAD_STRING,
[OP_LOAD_STRING] = &&DO_LOAD_STRING, [OP_DECLARE] = &&DO_DECLARE,
[OP_DECLARE] = &&DO_DECLARE, [OP_LOAD_NULL] = &&DO_LOAD_NULL,
[OP_LOAD_NULL] = &&DO_LOAD_NULL, [OP_LOAD_FUNCTION] = &&DO_LOAD_FUNCTION,
[OP_LOAD_FUNCTION] = &&DO_LOAD_FUNCTION, [OP_IDENTIFIER] = &&DO_IDENTIFIER,
[OP_IDENTIFIER] = &&DO_IDENTIFIER, [OP_BOOL] = &&DO_BOOL,
[OP_BOOL] = &&DO_BOOL, [OP_JUMP_IF_FALSE] = &&DO_JUMP_IF_FALSE,
[OP_JUMP_IF_FALSE] = &&DO_JUMP_IF_FALSE, [OP_JUMP] = &&DO_JUMP,
[OP_JUMP] = &&DO_JUMP, [OP_NEW_SCOPE] = &&DO_NEW_SCOPE,
[OP_NEW_SCOPE] = &&DO_NEW_SCOPE, [OP_POP_SCOPE] = &&DO_POP_SCOPE,
[OP_POP_SCOPE] = &&DO_POP_SCOPE, [OP_INIT_CALL] = &&DO_INIT_CALL,
[OP_INIT_CALL] = &&DO_INIT_CALL, [OP_INSERT_ARG] = &&DO_INSERT_ARG,
[OP_INSERT_ARG] = &&DO_INSERT_ARG, [OP_CALL] = &&DO_CALL,
[OP_CALL] = &&DO_CALL, [OP_SOURCE_LOCATION] = &&DO_SOURCE_LOCATION,
[OP_SOURCE_LOCATION] = &&DO_SOURCE_LOCATION, [OP_LOAD_BOOL] = &&DO_LOAD_BOOL,
[OP_LOAD_ACCESS_FUNCTION] = &&DO_LOAD_ACCESS_FUNCTION, [OP_LOAD_NUMBER] = &&DO_LOAD_NUMBER,
[OP_LOAD_BOOL] = &&DO_LOAD_BOOL, [OP_ASSIGN] = &&DO_ASSIGN,
[OP_LOAD_NUMBER] = &&DO_LOAD_NUMBER, [OP_COPY_TO_REGISTER] =
[OP_LOAD_ADDITION_FUNCTION] = &&DO_LOAD_ADDITION_FUNCTION, &&DO_COPY_TO_REGISTER,
[OP_LOAD_SUBTRACTION_FUNCTION] = &&DO_LOAD_SUBTRACTION_FUNCTION, [OP_ADDITION] = &&DO_ADDITION,
[OP_LOAD_MULTIPLY_FUNCTION] = &&DO_LOAD_MULTIPLY_FUNCTION, [OP_SUBTRACTION] = &&DO_SUBTRACTION,
[OP_LOAD_DIVISION_FUNCTION] = &&DO_LOAD_DIVISION_FUNCTION, [OP_LOAD_ACCESS_FUNCTION] = &&DO_LOAD_ACCESS_FUNCTION};
[OP_ASSIGN] = &&DO_ASSIGN};
goto *dispatch_table[pop_byte(translated, state)]; goto *dispatch_table[pop_byte(translated, state)];
DO_LOAD_NULL: DO_LOAD_NULL:
state->registers[pop_byte(translated, state)] = ARGON_NULL; state->registers[pop_byte(translated, state)] = ARGON_NULL;
@@ -723,28 +722,7 @@ DO_JUMP:
DO_NEW_SCOPE: DO_NEW_SCOPE:
*stack = create_scope(*stack); *stack = create_scope(*stack);
goto BREAK; goto BREAK;
DO_POP_SCOPE:; DO_POP_SCOPE:
// struct node_GC *array =
// checked_malloc(sizeof(struct node_GC) * (*stack)->scope->count);
// size_t j = 0;
// for (size_t i = 0; i < (*stack)->scope->size; i++) {
// struct node_GC *temp = (*stack)->scope->list[i];
// while (temp) {
// array[j++] = *temp;
// temp = temp->next;
// }
// }
// qsort(array, (*stack)->scope->count, sizeof(struct node_GC),
// compare_by_order);
// for (size_t i = 0; i < (*stack)->scope->count; i++) {
// struct node_GC temp = array[i];
// printf("%.*s = %.*s\n",
// (int)((ArgonObject *)temp.key)->value.as_str.length,
// ((ArgonObject *)temp.key)->value.as_str.data,
// (int)((ArgonObject *)temp.val)->value.as_str.length,
// ((ArgonObject *)temp.val)->value.as_str.data);
// }
// free(array);
*stack = (*stack)->prev; *stack = (*stack)->prev;
goto BREAK; goto BREAK;
DO_INIT_CALL: { DO_INIT_CALL: {
@@ -758,7 +736,7 @@ DO_INIT_CALL: {
} }
DO_INSERT_ARG:; DO_INSERT_ARG:;
size_t index = pop_bytecode(translated, state); size_t index = pop_bytecode(translated, state);
(state->call_instance->args)[index] = state->registers[0]; state->call_instance->args[index] = state->registers[0];
goto BREAK; goto BREAK;
DO_CALL: { DO_CALL: {
ArErr err = ArErr err =
@@ -766,25 +744,6 @@ DO_CALL: {
state->call_instance->args, state, false); state->call_instance->args, state, false);
state->call_instance = (*state->call_instance).previous; state->call_instance = (*state->call_instance).previous;
return err; return err;
// ArgonObject *object = state->registers[from_register];
// char *field = "__class__";
// uint64_t hash = siphash64_bytes(field, strlen(field), siphash_key);
// ArgonObject *class = hashmap_lookup_GC(object->dict, hash);
// field = "__name__";
// hash = siphash64_bytes(field, strlen(field), siphash_key);
// ArgonObject *class_name = hashmap_lookup_GC(class->dict, hash);
// hash = siphash64_bytes(field, strlen(field), siphash_key);
// ArgonObject *object_name = hashmap_lookup_GC(object->dict, hash);
// if (object_name) {
// printf("call <%.*s %.*s at %p>\n",
// (int)class_name->value.as_str.length,
// class_name->value.as_str.data,(int)object_name->value.as_str.length,
// object_name->value.as_str.data, object);
// } else {
// printf("call <%.*s object at %p>\n",
// (int)class_name->value.as_str.length, class_name->value.as_str.data,
// object);
// }
} }
DO_SOURCE_LOCATION: DO_SOURCE_LOCATION:
state->source_location = (SourceLocation){pop_bytecode(translated, state), state->source_location = (SourceLocation){pop_bytecode(translated, state),
@@ -797,18 +756,134 @@ DO_LOAD_BOOL:
DO_LOAD_ACCESS_FUNCTION: DO_LOAD_ACCESS_FUNCTION:
state->registers[0] = ACCESS_FUNCTION; state->registers[0] = ACCESS_FUNCTION;
goto BREAK; goto BREAK;
DO_LOAD_ADDITION_FUNCTION: DO_COPY_TO_REGISTER: {
state->registers[0] = ADDITION_FUNCTION; uint8_t from_register = pop_byte(translated, state);
goto BREAK; uint64_t to_register = pop_byte(translated, state);
DO_LOAD_SUBTRACTION_FUNCTION: state->registers[to_register] = state->registers[from_register];
state->registers[0] = SUBTRACTION_FUNCTION;
goto BREAK;
DO_LOAD_MULTIPLY_FUNCTION:
state->registers[0] = MULTIPLY_FUNCTION;
goto BREAK;
DO_LOAD_DIVISION_FUNCTION:
state->registers[0] = DIVISION_FUNCTION;
goto BREAK; goto BREAK;
}
DO_ADDITION: {
uint8_t registerA = pop_byte(translated, state);
uint64_t registerB = pop_byte(translated, state);
uint64_t registerC = pop_byte(translated, state);
ArgonObject *valueA = state->registers[registerA];
ArgonObject *valueB = state->registers[registerB];
if (valueA->type == TYPE_NUMBER && valueB->type == TYPE_NUMBER) {
if (valueA->value.as_number.is_int64 && valueB->value.as_number.is_int64) {
int64_t a = valueA->value.as_number.n.i64;
int64_t b = valueB->value.as_number.n.i64;
bool gonna_overflow = (a > 0 && b > 0 && a > INT64_MAX - b) ||
(a < 0 && b < 0 && a < INT64_MIN - b);
if (!gonna_overflow) {
state->registers[registerC] =
new_number_object_from_num_and_den(a + b, 1);
goto BREAK;
}
mpq_t a_GMP, b_GMP;
mpq_init(a_GMP);
mpq_init(b_GMP);
mpq_set_si(a_GMP, a, 1);
mpq_set_si(b_GMP, b, 1);
mpq_add(a_GMP, a_GMP, b_GMP);
state->registers[registerC] = new_number_object(a_GMP);
mpq_clear(a_GMP);
mpq_clear(b_GMP);
} else if (!valueA->value.as_number.is_int64 &&
!valueB->value.as_number.is_int64) {
mpq_t r;
mpq_init(r);
mpq_add(r, *valueA->value.as_number.n.mpq,
*valueB->value.as_number.n.mpq);
state->registers[registerC] = new_number_object(r);
mpq_clear(r);
} else {
mpq_t a_GMP, b_GMP;
mpq_init(a_GMP);
mpq_init(b_GMP);
if (valueA->value.as_number.is_int64) {
mpq_set_si(a_GMP, valueA->value.as_number.n.i64, 1);
mpq_set(b_GMP, *valueB->value.as_number.n.mpq);
} else {
mpq_set(a_GMP, *valueA->value.as_number.n.mpq);
mpq_set_si(b_GMP, valueB->value.as_number.n.i64, 1);
}
mpq_add(a_GMP, a_GMP, b_GMP);
state->registers[registerC] = new_number_object(a_GMP);
mpq_clear(a_GMP);
mpq_clear(b_GMP);
}
goto BREAK;
}
ArErr err = no_err;
ArgonObject *args[] = {valueA, valueB};
state->registers[registerC] = ARGON_ADDITION_FUNCTION(2, args, &err, state);
return err;
}
DO_SUBTRACTION: {
uint8_t registerA = pop_byte(translated, state);
uint64_t registerB = pop_byte(translated, state);
uint64_t registerC = pop_byte(translated, state);
ArgonObject *valueA = state->registers[registerA];
ArgonObject *valueB = state->registers[registerB];
if (valueA->type == TYPE_NUMBER && valueB->type == TYPE_NUMBER) {
if (valueA->value.as_number.is_int64 && valueB->value.as_number.is_int64) {
int64_t a = valueA->value.as_number.n.i64;
int64_t b = valueB->value.as_number.n.i64;
int64_t neg_a = -a;
bool gonna_overflow = (neg_a > 0 && b > 0 && b > INT64_MAX - neg_a) ||
(neg_a < 0 && b < 0 && b < INT64_MIN - neg_a);
if (!gonna_overflow) {
state->registers[registerC] =
new_number_object_from_num_and_den(a - b, 1);
goto BREAK;
}
mpq_t a_GMP, b_GMP;
mpq_init(a_GMP);
mpq_init(b_GMP);
mpq_set_si(a_GMP, a, 1);
mpq_set_si(b_GMP, b, 1);
mpq_sub(a_GMP, a_GMP, b_GMP);
state->registers[registerC] = new_number_object(a_GMP);
mpq_clear(a_GMP);
mpq_clear(b_GMP);
} else if (!valueA->value.as_number.is_int64 &&
!valueB->value.as_number.is_int64) {
mpq_t r;
mpq_init(r);
mpq_sub(r, *valueA->value.as_number.n.mpq,
*valueB->value.as_number.n.mpq);
state->registers[registerC] = new_number_object(r);
mpq_clear(r);
} else {
mpq_t a_GMP, b_GMP;
mpq_init(a_GMP);
mpq_init(b_GMP);
if (valueA->value.as_number.is_int64) {
mpq_set_si(a_GMP, valueA->value.as_number.n.i64, 1);
mpq_set(b_GMP, *valueB->value.as_number.n.mpq);
} else {
mpq_set(a_GMP, *valueA->value.as_number.n.mpq);
mpq_set_si(b_GMP, valueB->value.as_number.n.i64, 1);
}
mpq_sub(a_GMP, a_GMP, b_GMP);
state->registers[registerC] = new_number_object(a_GMP);
mpq_clear(a_GMP);
mpq_clear(b_GMP);
}
goto BREAK;
}
ArErr err = no_err;
ArgonObject *args[] = {valueA, valueB};
state->registers[registerC] = ARGON_ADDITION_FUNCTION(2, args, &err, state);
return err;
}
BREAK: BREAK:
return no_err; return no_err;
} }

View File

@@ -91,7 +91,7 @@ int execute_code(FILE *stream, char *path, Stack *scope,
hashmap_free(__translated.constants.hashmap, NULL); hashmap_free(__translated.constants.hashmap, NULL);
Translated translated = { Translated translated = {
__translated.registerCount, NULL, {}, {}, __translated.path}; __translated.registerCount, __translated.registerAssignment, NULL, {}, {}, __translated.path};
translated.bytecode.data = ar_alloc(__translated.bytecode.capacity); translated.bytecode.data = ar_alloc(__translated.bytecode.capacity);
memcpy(translated.bytecode.data, __translated.bytecode.data, memcpy(translated.bytecode.data, __translated.bytecode.data,
__translated.bytecode.capacity); __translated.bytecode.capacity);

View File

@@ -131,27 +131,27 @@ loads a boolean into register 1
## OP_LOAD_NUMBER ## OP_LOAD_NUMBER
loads a mpq_t number into memory loads a mpq_t / int64 number into memory
1. the register to write to. (*) 1. the register to write to. (*)
1. is int64 (*)
1. the size of the numerator in the constant buffer. 1. the size of the numerator in the constant buffer.
1. the offset in the constant buffer of the numerator. 1. the offset in the constant buffer of the numerator.
1. is integer. (*) 1. is integer. (*)
1. the size of the denominator in the constant buffer. 1. the size of the denominator in the constant buffer.
1. the offset in the constant buffer of the denominator. 1. the offset in the constant buffer of the denominator.
## OP_LOAD_ADDITION_FUNCTION ## OP_COPY_TO_REGISTER
loads the addition function into register 1 copies the value from one register to another
## OP_LOAD_SUBTRACTION_FUNCTION 1. the register to copy from (*)
2. the register to write to (*)
loads the subtraction function into register 1 ## OP_ADDITION
## OP_LOAD_MULTIPLY_FUNCTION performs an addition between register A and register B, storing the result in register C
loads the multiply function into register 1 1. the register A (*)
2. the register B (*)
## OP_LOAD_DIVISION_FUNCTION 2. the register C (*)
loads the division function into register 1

View File

@@ -5,6 +5,7 @@
*/ */
#include "number.h" #include "number.h"
#include "../../runtime/objects/number/number.h"
#include "../translator.h" #include "../translator.h"
#include <gmp.h> #include <gmp.h>
#include <stddef.h> #include <stddef.h>
@@ -16,6 +17,13 @@ size_t translate_parsed_number(Translated *translated, mpq_t *number,
set_registers(translated, to_register + 1); set_registers(translated, to_register + 1);
size_t start = push_instruction_byte(translated, OP_LOAD_NUMBER); size_t start = push_instruction_byte(translated, OP_LOAD_NUMBER);
push_instruction_byte(translated, to_register); push_instruction_byte(translated, to_register);
int64_t i64;
uint8_t is_int64 = mpq_to_int64(*number, &i64);
push_instruction_byte(translated, is_int64);
if (is_int64) {
push_instruction_code(translated, i64);
return start;
}
size_t num_size; size_t num_size;
void *num_data = mpz_export(NULL, &num_size, 1, 1, 0, 0, mpq_numref(*number)); void *num_data = mpz_export(NULL, &num_size, 1, 1, 0, 0, mpq_numref(*number));
size_t numerator_pos = arena_push(&translated->constants, num_data, num_size); size_t numerator_pos = arena_push(&translated->constants, num_data, num_size);

View File

@@ -6,42 +6,44 @@
#include "operation.h" #include "operation.h"
#include <stddef.h> #include <stddef.h>
#include <stdint.h>
#include <stdio.h>
size_t translate_operation(Translated *translated, ParsedOperation *operation, size_t translate_operation(Translated *translated, ParsedOperation *operation,
ArErr *err) { ArErr *err) {
set_registers(translated, 1); uint8_t registerA = translated->registerAssignment++;
uint64_t first; uint8_t registerB = translated->registerAssignment++;
switch (operation->operation) { set_registers(translated, translated->registerAssignment);
case TOKEN_PLUS:; uint64_t first = translate_parsed(translated, darray_get(&operation->to_operate_on, 0), err);
first = push_instruction_byte(translated, OP_LOAD_ADDITION_FUNCTION); push_instruction_byte(translated, OP_COPY_TO_REGISTER);
break; push_instruction_byte(translated, 0);
case TOKEN_MINUS: push_instruction_byte(translated, registerA);
first = push_instruction_byte(translated, OP_LOAD_SUBTRACTION_FUNCTION); for (size_t i = 1; i < operation->to_operate_on.size; i++) {
break;
case TOKEN_STAR:
first = push_instruction_byte(translated, OP_LOAD_MULTIPLY_FUNCTION);
break;
case TOKEN_SLASH:
first = push_instruction_byte(translated, OP_LOAD_DIVISION_FUNCTION);
break;
default:
*err = create_err(operation->line, operation->column, operation->length,
translated->path, "Syntax Error", "unknown operation");
return 0;
}
push_instruction_byte(translated, OP_INIT_CALL);
push_instruction_code(translated, operation->to_operate_on.size);
for (size_t i = 0; i < operation->to_operate_on.size; i++) {
translate_parsed(translated, darray_get(&operation->to_operate_on, i), err); translate_parsed(translated, darray_get(&operation->to_operate_on, i), err);
push_instruction_byte(translated, OP_INSERT_ARG); push_instruction_byte(translated, OP_COPY_TO_REGISTER);
push_instruction_code(translated, i); push_instruction_byte(translated, 0);
push_instruction_byte(translated, registerB);
switch (operation->operation) {
case TOKEN_PLUS:;
push_instruction_byte(translated, OP_ADDITION);
break;
case TOKEN_MINUS:;
push_instruction_byte(translated, OP_SUBTRACTION);
break;
default:
*err = create_err(operation->line, operation->column, operation->length,
translated->path, "Syntax Error", "unknown operation");
return 0;
}
push_instruction_byte(translated, registerA);
push_instruction_byte(translated, registerB);
push_instruction_byte(
translated, operation->to_operate_on.size - 1 == i ? 0 : registerA);
} }
push_instruction_byte(translated, OP_LOAD_NULL);
push_instruction_byte(translated, OP_SOURCE_LOCATION); push_instruction_byte(translated, registerA);
push_instruction_code(translated, operation->line); push_instruction_byte(translated, OP_LOAD_NULL);
push_instruction_code(translated, operation->column); push_instruction_byte(translated, registerB);
push_instruction_code(translated, operation->length); translated->registerAssignment -= 2;
push_instruction_byte(translated, OP_CALL);
return first; return first;
} }

View File

@@ -86,6 +86,7 @@ Translated init_translator(char *path) {
Translated translated; Translated translated;
translated.path = path; translated.path = path;
translated.registerCount = 1; translated.registerCount = 1;
translated.registerAssignment = 1;
translated.return_jumps = NULL; translated.return_jumps = NULL;
darray_init(&translated.bytecode, sizeof(uint8_t)); darray_init(&translated.bytecode, sizeof(uint8_t));
arena_init(&translated.constants); arena_init(&translated.constants);

View File

@@ -29,14 +29,13 @@ typedef enum {
OP_INSERT_ARG, OP_INSERT_ARG,
OP_CALL, OP_CALL,
OP_SOURCE_LOCATION, OP_SOURCE_LOCATION,
OP_LOAD_ACCESS_FUNCTION,
OP_LOAD_BOOL, OP_LOAD_BOOL,
OP_LOAD_NUMBER, OP_LOAD_NUMBER,
OP_LOAD_ADDITION_FUNCTION, OP_ASSIGN,
OP_LOAD_SUBTRACTION_FUNCTION, OP_COPY_TO_REGISTER,
OP_LOAD_MULTIPLY_FUNCTION, OP_ADDITION,
OP_LOAD_DIVISION_FUNCTION, OP_SUBTRACTION,
OP_ASSIGN OP_LOAD_ACCESS_FUNCTION
} OperationType; } OperationType;
void arena_resize(ConstantArena *arena, size_t new_size); void arena_resize(ConstantArena *arena, size_t new_size);