From fb95edaa5a00e4e95c139db147d1458431f1c4ff Mon Sep 17 00:00:00 2001 From: John Viega Date: Mon, 1 Jul 2024 19:23:56 -0400 Subject: [PATCH] Fixed up some things I borked along the way with lists and loops. Minor edits. --- dev | 8 ++- include/con4m.h | 23 +++++++- include/con4m/datatypes/vm.h | 1 + include/con4m/list.h | 23 ++++++++ include/con4m/string.h | 8 +-- include/con4m/xlist.h | 53 ----------------- meson.build | 5 +- src/con4m/collect.c | 4 +- src/con4m/compiler/codegen.c | 62 +++++++++++++------- src/con4m/compiler/disasm.c | 6 ++ src/con4m/list.c | 108 +++++++++++++++++++++++++++-------- src/con4m/string.c | 4 +- src/con4m/vm.c | 107 +++++++++++++++++++++------------- tests/popcount.c4m | 23 ++++++++ tests/range.c4m | 27 +++++++++ 15 files changed, 310 insertions(+), 152 deletions(-) create mode 100644 include/con4m/list.h delete mode 100644 include/con4m/xlist.h create mode 100644 tests/popcount.c4m create mode 100644 tests/range.c4m diff --git a/dev b/dev index 9c0d2abb..83adbafb 100755 --- a/dev +++ b/dev @@ -44,7 +44,13 @@ function meson_build { rm -rf ${1} fi log Creating meson target ${1} - meson setup ${1} + + if [[ ${1} -ne "debug" ]] ; then + SETUP_ARGS=-Dbuildtype=release + else + SETUP_ARGS=-Dbuildtype=debugoptimized + fi + meson setup ${SETUP_ARGS} ${1} fi cd ${1} diff --git a/include/con4m.h b/include/con4m.h index e6dbc4fd..ddf6c132 100644 --- a/include/con4m.h +++ b/include/con4m.h @@ -9,13 +9,30 @@ // #define C4M_GC_ALL_OFF // #define C4M_GC_ALL_ON -// #define C4M_VM_DEBUG // #define C4M_TYPE_LOG -#ifndef C4M_NO_DEV_MODE +// When this is on, the `debug` instruction will run. +// Note that the debug instruction is not even generated unless +// C4M_DEV is on. + +// #define C4M_VM_DEBUG +// #define C4M_VM_DEBUG_DEFAULT true + +#ifdef C4M_NO_DEV_MODE +#undef C4M_DEV +#else #define C4M_DEV #endif +#if defined(C4M_VM_DEBUG) +#if !defined(C4M_DEV) +#error "Cannot debug VM when C4M_DEV_MODE is set." +#endif +#if !defined(C4M_VM_DEBUG_DEFAULT) +#define C4M_VM_DEBUG_DEFAULT false +#endif +#endif + #ifdef C4M_TRACE_GC #ifndef C4M_GC_STATS #define C4M_GC_STATS @@ -49,7 +66,7 @@ #include "con4m/color.h" // Basic "exclusive" (i.e., single threaded) list. -#include "con4m/xlist.h" +#include "con4m/list.h" // Type system API. #include "con4m/type.h" diff --git a/include/con4m/datatypes/vm.h b/include/con4m/datatypes/vm.h index 66db0b9b..4ba4518e 100644 --- a/include/con4m/datatypes/vm.h +++ b/include/con4m/datatypes/vm.h @@ -337,6 +337,7 @@ typedef enum : uint8_t { C4M_ZNop = 0xFF, #ifdef C4M_DEV C4M_ZPrint = 0xFD, + C4M_ZDebug = 0xFC, #endif } c4m_zop_t; diff --git a/include/con4m/list.h b/include/con4m/list.h new file mode 100644 index 00000000..74fc5026 --- /dev/null +++ b/include/con4m/list.h @@ -0,0 +1,23 @@ +#pragma once + +#include "con4m.h" + +extern void *c4m_list_get(c4m_list_t *, int64_t, bool *); +extern void c4m_list_append(c4m_list_t *list, void *item); +extern void c4m_list_add_if_unique(c4m_list_t *list, + void *item, + bool (*fn)(void *, void *)); +extern void *c4m_list_pop(c4m_list_t *list); +extern void c4m_list_plus_eq(c4m_list_t *, c4m_list_t *); +extern c4m_list_t *c4m_list_plus(c4m_list_t *, c4m_list_t *); +extern bool c4m_list_set(c4m_list_t *, int64_t, void *); +extern c4m_list_t *c4m_list(c4m_type_t *); +extern int64_t c4m_list_len(const c4m_list_t *); +extern c4m_list_t *c4m_list_get_slice(c4m_list_t *, int64_t, int64_t); +extern void c4m_list_set_slice(c4m_list_t *, + int64_t, + int64_t, + c4m_list_t *); +extern bool c4m_list_contains(c4m_list_t *, c4m_obj_t); +extern c4m_list_t *c4m_list_copy(c4m_list_t *); +extern c4m_list_t *c4m_list_shallow_copy(c4m_list_t *); diff --git a/include/con4m/string.h b/include/con4m/string.h index ba901dc0..3167a692 100644 --- a/include/con4m/string.h +++ b/include/con4m/string.h @@ -13,7 +13,7 @@ extern c4m_utf8_t *c4m_utf8_repeat(c4m_codepoint_t, int64_t); extern c4m_utf32_t *c4m_utf32_repeat(c4m_codepoint_t, int64_t); extern c4m_utf32_t *_c4m_str_strip(const c4m_str_t *s, ...); extern c4m_str_t *_c4m_str_truncate(const c4m_str_t *s, int64_t, ...); -extern c4m_utf32_t *_c4m_str_join(const c4m_list_t *, +extern c4m_utf32_t *_c4m_str_join(c4m_list_t *, const c4m_str_t *, ...); extern c4m_utf8_t *c4m_str_from_int(int64_t n); @@ -24,7 +24,7 @@ extern c4m_utf8_t *c4m_rich(c4m_utf8_t *, c4m_utf8_t *style); extern c4m_codepoint_t c4m_index(const c4m_str_t *, int64_t); extern bool c4m_str_can_coerce_to(c4m_type_t *, c4m_type_t *); extern c4m_obj_t c4m_str_coerce_to(const c4m_str_t *, c4m_type_t *); -extern c4m_list_t *c4m_str_xsplit(c4m_str_t *, c4m_str_t *); +extern c4m_list_t *c4m_str_xsplit(c4m_str_t *, c4m_str_t *); extern struct flexarray_t *c4m_str_fsplit(c4m_str_t *, c4m_str_t *); extern bool c4m_str_starts_with(const c4m_str_t *, const c4m_str_t *); @@ -102,8 +102,8 @@ c4m_to_cstring(c4m_str_t *s) return s->data; } -extern c4m_list_t *c4m_u8_map(const c4m_list_t *); -extern bool c4m_str_eq(c4m_str_t *, c4m_str_t *); +extern c4m_list_t *c4m_u8_map(c4m_list_t *); +extern bool c4m_str_eq(c4m_str_t *, c4m_str_t *); extern const uint64_t c4m_pmap_str[2]; diff --git a/include/con4m/xlist.h b/include/con4m/xlist.h deleted file mode 100644 index ea880a97..00000000 --- a/include/con4m/xlist.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include "con4m.h" - -static inline void * -c4m_list_get(const c4m_list_t *list, int64_t ix, bool *err) -{ - if (!list) { - if (err) { - *err = true; - } - - return NULL; - } - - if (ix < 0) { - ix += list->append_ix; - } - - if (err) { - if (ix < 0 || ix >= list->append_ix) { - if (err) { - *err = true; - } - } - else { - if (err) { - *err = false; - } - } - } - - return (void *)list->data[ix]; -} - -extern void c4m_list_append(c4m_list_t *list, void *item); -extern void c4m_list_add_if_unique(c4m_list_t *list, - void *item, - bool (*fn)(void *, void *)); -extern void *c4m_list_pop(c4m_list_t *list); -extern void c4m_list_plus_eq(c4m_list_t *, c4m_list_t *); -extern c4m_list_t *c4m_list_plus(c4m_list_t *, c4m_list_t *); -extern bool c4m_list_set(c4m_list_t *, int64_t, void *); -extern c4m_list_t *c4m_list(c4m_type_t *); -extern int64_t c4m_list_len(const c4m_list_t *); -extern c4m_list_t *c4m_list_get_slice(c4m_list_t *, int64_t, int64_t); -extern void c4m_list_set_slice(c4m_list_t *, - int64_t, - int64_t, - c4m_list_t *); -extern bool c4m_list_contains(c4m_list_t *, c4m_obj_t); -extern c4m_list_t *c4m_list_copy(c4m_list_t *); -extern c4m_list_t *c4m_list_shallow_copy(c4m_list_t *); diff --git a/meson.build b/meson.build index 72140b0d..7596935d 100644 --- a/meson.build +++ b/meson.build @@ -35,7 +35,6 @@ else using_osx = false link_args = [] c_args = c_args + ['-D_GNU_SOURCE'] - endif exe_link_args = link_args + ['-flto', '-w'] @@ -54,6 +53,10 @@ if cc.links(fpty_code, name: 'forkpty_check') add_project_arguments('-DHAVE_PTY_H', language: 'c') endif +if (get_option('buildtype') == 'release') + add_project_arguments([ '-O2' ], language: 'c') +endif + c4m_src = ['src/con4m/style.c', 'src/con4m/colors.c', 'src/con4m/breaks.c', diff --git a/src/con4m/collect.c b/src/con4m/collect.c index f5c78708..3a22b98e 100644 --- a/src/con4m/collect.c +++ b/src/con4m/collect.c @@ -671,10 +671,10 @@ c4m_collect_arena(c4m_arena_t *from_space) gstr = c4m_cstr_format("{}", c4m_box_double(u)); gstr = c4m_str_slice(gstr, 0, 5); - c4m_printf("[b]Collect utilization[/]: [em]{}[/]% garbage", + c4m_printf("[b]Collect utilization[/]: [em]{}%[/] [i]garbage", gstr); - c4m_printf("[b]Average allocation size:[/] [em]{:,} bytes", + c4m_printf("[b]Average allocation size:[/] [em]{:,}[/] bytes", c4m_box_u64((c4m_total_words * 8) / c4m_total_allocs)); #endif diff --git a/src/con4m/compiler/codegen.c b/src/con4m/compiler/codegen.c index 40cf55a4..35aee23b 100644 --- a/src/con4m/compiler/codegen.c +++ b/src/con4m/compiler/codegen.c @@ -1,6 +1,16 @@ #define C4M_USE_INTERNAL_API #include "con4m.h" +#ifdef C4M_DEV +#define gen_debug(debug_arg) \ + emit(ctx, C4M_ZDebug, c4m_kw("arg", c4m_ka(debug_arg))) +#define debug_label(cstr) \ + gen_label(ctx, c4m_new_utf8(cstr)) +#else +#define gen_debug(debug_arg) +#define debug_label(cstr) +#endif + // This is used in nested if/else only. typedef struct { c4m_jump_info_t *targets; @@ -31,6 +41,7 @@ typedef struct { int instruction_counter; int current_stack_offset; int max_stack_size; + int module_patch_loc; bool lvalue; assign_type_t assign_method; c4m_symbol_t *retsym; @@ -796,6 +807,8 @@ gen_module(gen_ctx *ctx) int num_params = gen_parameter_checks(ctx); emit(ctx, C4M_ZModuleEnter, c4m_kw("arg", c4m_ka(num_params))); + ctx->module_patch_loc = ctx->instruction_counter; + emit(ctx, C4M_ZMoveSp, c4m_kw("arg", c4m_ka(0))); gen_kids(ctx); } @@ -1093,6 +1106,7 @@ gen_ranged_for(gen_ctx *ctx, c4m_loop_info_t *li) // value. So if it's 0 .. 10, and we call subtract to calculate the // length, we're going to be computing 0 - 10, not the opposite. // So we first swap the two numbers. + emit(ctx, C4M_ZSwap); // Subtract the 2 numbers now, but DO NOT POP; we need these. emit(ctx, C4M_ZSubNoPop); @@ -1137,6 +1151,7 @@ gen_ranged_for(gen_ctx *ctx, c4m_loop_info_t *li) if (using_index) { emit(ctx, C4M_ZPopToR3); } + // pop the step for a second. emit(ctx, C4M_ZPopToR1); // If the two items are equal, we bail from the loop. @@ -1147,13 +1162,14 @@ gen_ranged_for(gen_ctx *ctx, c4m_loop_info_t *li) // Then push the step back on, // And, if it's being used, the $i from R3. - GEN_JNZ(gen_sym_store(ctx, li->lvar_1, false); - emit(ctx, C4M_ZPushFromR1); - emit(ctx, C4M_ZAdd); - emit(ctx, C4M_ZPushFromR1); - possible_restore_from_r3(ctx, using_index); - gen_one_kid(ctx, ctx->cur_node->num_kids - 1); - gen_j(ctx, &ji_top)); + GEN_JNZ( + gen_sym_store(ctx, li->lvar_1, false); + emit(ctx, C4M_ZPushFromR1); + emit(ctx, C4M_ZAdd); + emit(ctx, C4M_ZPushFromR1); + possible_restore_from_r3(ctx, using_index); + gen_one_kid(ctx, ctx->cur_node->num_kids - 1); + gen_j(ctx, &ji_top)); gen_apply_waiting_patches(ctx, &li->branch_info); emit(ctx, C4M_ZMoveSp, c4m_kw("arg", c4m_ka(-3))); } @@ -1204,21 +1220,16 @@ gen_container_for(gen_ctx *ctx, c4m_loop_info_t *li) // // Also, note that the VIEW builtin doesn't need to copy objects, // but it needs to give us a pointer to items, where we steal the - // lowest 2 bits in the pointer to represent the the log base 2 of + // lowest 3 bits in the pointer to represent the the log base 2 of // the bytes in the item count. Currently, the only allowable - // view item sizes are therefore: 1 byte, 2 bytes, 4 bytes, 8 - // bytes. + // view item sizes are 1 byte, 2 bytes, 4 bytes, 8 bytes. Anything + // else currently represents a bitfield (per below). // - // Currently, we don't need more than 8bytes, since anything + // Currently, we don't need more than 8 bytes, since anything // larger than 8 bytes is passed around as pointers. However, I // expect to eventually add 128-bit ints, which would entail a // double-word load. // - // Therefore, views must be 8 byte aligned, because eventually we - // will steal a third bit. But that's no problem as long as view - // pointers start at the beginning of an allocation, since the - // allocator always spits out aligned objects. - // // We have a bit of a special case for bitfield types (right now, // just c4m_flags_t). There, the value of the "number of bytes" // field will be set to 128; When we see that, we will use @@ -1229,21 +1240,25 @@ gen_container_for(gen_ctx *ctx, c4m_loop_info_t *li) // of first implementation, it will just always happen, even // though in most cases it should be no problem to bind to the // right approach statically. - gen_tcall(ctx, C4M_BI_VIEW, NULL); + // The length of the container is on top right now; the view is // underneath. We want to store a copy to $len if appropriate, // and then pop to a register 2, to work on the pointer. We'll // push it back on top when we properly enter the loop. gen_len_var_init(ctx, li); + // Move the container length out to a register for a bit. emit(ctx, C4M_ZPopToR2); + emit(ctx, C4M_ZUnsteal); // The bit length is actually encoded by taking log base 2; here // were expand it back out before going into the loop. emit(ctx, C4M_ZShlI, c4m_kw("arg", c4m_ka(0x1))); + // On top of this, put the iteration count, which at the start of // each turn through the loop, will be the second item. + bool have_index_var = gen_index_var_init(ctx, li); bool have_kv_pair = li->lvar_2 != NULL; @@ -1276,10 +1291,9 @@ gen_container_for(gen_ctx *ctx, c4m_loop_info_t *li) deal_with_iteration_count(ctx, li, have_index_var); emit(ctx, C4M_ZPopToR1); emit(ctx, C4M_ZLoadFromView, c4m_kw("arg", c4m_ka(have_kv_pair))); - // Store the item(s) to the appropriate loop variable(s). store_view_item(ctx, li); - emit(ctx, C4M_ZPushFromR1); // Re-groom the stack; container length. - emit(ctx, C4M_ZPushFromR2); // Iteration count. + emit(ctx, C4M_ZPushFromR1); // Re-groom the stack; iter count + emit(ctx, C4M_ZPushFromR2); // container len gen_one_kid(ctx, ctx->cur_node->num_kids - 1); gen_j(ctx, &ji_top)); // After the loop: @@ -1287,7 +1301,7 @@ gen_container_for(gen_ctx *ctx, c4m_loop_info_t *li) // 2. Move the stack down four items, popping the count, len, item size, // and container. gen_apply_waiting_patches(ctx, &li->branch_info); - emit(ctx, C4M_ZMoveSp, c4m_kw("arg", c4m_ka(-4))); + emit(ctx, C4M_ZMoveSp, c4m_kw("arg", c4m_ka(-5))); } static inline void @@ -2122,6 +2136,12 @@ gen_module_code(gen_ctx *ctx, c4m_vm_t *vm) ctx->current_stack_offset = ctx->fctx->static_size; ctx->max_stack_size = ctx->fctx->static_size; gen_one_node(ctx); + + c4m_zinstruction_t *sp_move = c4m_list_get(module->instructions, + ctx->module_patch_loc, + NULL); + sp_move->arg = ctx->max_stack_size; + emit(ctx, C4M_ZModuleRet); module->module_var_size = ctx->max_stack_size; diff --git a/src/con4m/compiler/disasm.c b/src/con4m/compiler/disasm.c index 3933d0e9..eeecd2f9 100644 --- a/src/con4m/compiler/disasm.c +++ b/src/con4m/compiler/disasm.c @@ -53,6 +53,8 @@ get_bool_label(c4m_zop_t op) return c4m_new_utf8("currently unused"); case C4M_ZLoadFromView: return c4m_new_utf8("load kv pair"); + case C4M_ZDebug: + return c4m_new_utf8("set debug"); default: c4m_unreachable(); } @@ -334,6 +336,10 @@ const inst_info_t inst_info[256] = { [C4M_ZPrint] = { .name = "ZPrint", }, + [C4M_ZDebug] = { + .name = "ZDebug", + .arg_fmt = fmt_bool, + }, #endif }; diff --git a/src/con4m/list.c b/src/con4m/list.c index 705a34f8..5ec36769 100644 --- a/src/con4m/list.c +++ b/src/con4m/list.c @@ -100,6 +100,48 @@ c4m_list_append(c4m_list_t *list, void *item) return; } +static inline void * +c4m_list_get_base(c4m_list_t *list, int64_t ix, bool *err) +{ + if (!list) { + if (err) { + *err = true; + } + + return NULL; + } + + if (err) { + if (ix < 0 || ix >= list->append_ix) { + if (err) { + *err = true; + } + } + else { + if (err) { + *err = false; + } + } + } + + return (void *)list->data[ix]; +} + +void * +c4m_list_get(c4m_list_t *list, int64_t ix, bool *err) +{ + lock_list(list); + + if (ix < 0) { + ix += list->append_ix; + } + + void *result = c4m_list_get_base(list, ix, err); + unlock_list(list); + + return result; +} + void c4m_list_add_if_unique(c4m_list_t *list, void *item, @@ -108,7 +150,7 @@ c4m_list_add_if_unique(c4m_list_t *list, lock_list(list); // Really meant to be internal for debugging sets; use sets instead. for (int i = 0; i < c4m_list_len(list); i++) { - void *x = c4m_list_get(list, i, NULL); + void *x = c4m_list_get_base(list, i, NULL); if ((*fn)(x, item)) { unlock_list(list); @@ -129,11 +171,11 @@ void * c4m_list_pop(c4m_list_t *list) { if (list->append_ix == 0) { - C4M_CRAISE("Pop called on empty xlist."); + C4M_CRAISE("Pop called on empty list."); } lock_list(list); - return c4m_list_get(list, --list->append_ix, NULL); + return c4m_list_get_base(list, --list->append_ix, NULL); unlock_list(list); } @@ -206,7 +248,7 @@ c4m_list_marshal(c4m_list_t *r, c4m_stream_t *s, c4m_dict_t *memos, int64_t *mid { c4m_type_t *list_type = c4m_get_my_type(r); c4m_list_t *type_params = c4m_type_get_params(list_type); - c4m_type_t *item_type = c4m_list_get(type_params, 0, NULL); + c4m_type_t *item_type = c4m_list_get_base(type_params, 0, NULL); c4m_dt_info_t *item_info = c4m_type_get_data_type_info(item_type); bool by_val = item_info->by_value; @@ -232,7 +274,7 @@ c4m_list_unmarshal(c4m_list_t *r, c4m_stream_t *s, c4m_dict_t *memos) { c4m_type_t *list_type = c4m_get_my_type(r); c4m_list_t *type_params = c4m_type_get_params(list_type); - c4m_type_t *item_type = c4m_list_get(type_params, 0, NULL); + c4m_type_t *item_type = c4m_list_get_base(type_params, 0, NULL); c4m_dt_info_t *item_info = item_type ? c4m_type_get_data_type_info(item_type) : NULL; bool by_val = item_info ? item_info->by_value : false; @@ -274,13 +316,13 @@ c4m_list_repr(c4m_list_t *list) c4m_type_t *list_type = c4m_get_my_type(list); c4m_list_t *type_params = c4m_type_get_params(list_type); - c4m_type_t *item_type = c4m_list_get(type_params, 0, NULL); + c4m_type_t *item_type = c4m_list_get_base(type_params, 0, NULL); int64_t len = c4m_list_len(list); c4m_list_t *items = c4m_new(c4m_type_list(c4m_type_utf32())); for (int i = 0; i < len; i++) { bool err = false; - void *item = c4m_list_get(list, i, &err); + void *item = c4m_list_get_base(list, i, &err); if (err) { continue; } @@ -318,11 +360,11 @@ c4m_list_coerce_to(c4m_list_t *list, c4m_type_t *dst_type) return result; } - if (base == (c4m_dt_kind_t)C4M_T_XLIST) { + if (base == (c4m_dt_kind_t)C4M_T_LIST) { c4m_list_t *res = c4m_new(dst_type, c4m_kw("length", c4m_ka(len))); for (int i = 0; i < len; i++) { - void *item = c4m_list_get(list, i, NULL); + void *item = c4m_list_get_base(list, i, NULL); c4m_list_set(res, i, c4m_coerce(item, src_item_type, dst_item_type)); @@ -336,7 +378,7 @@ c4m_list_coerce_to(c4m_list_t *list, c4m_type_t *dst_type) flexarray_t *res = c4m_new(dst_type, c4m_kw("length", c4m_ka(len))); for (int i = 0; i < len; i++) { - void *item = c4m_list_get(list, i, NULL); + void *item = c4m_list_get_base(list, i, NULL); flexarray_set(res, i, c4m_coerce(item, src_item_type, dst_item_type)); @@ -358,7 +400,7 @@ c4m_list_copy(c4m_list_t *list) c4m_list_t *res = c4m_new(my_type, c4m_kw("length", c4m_ka(len))); for (int i = 0; i < len; i++) { - c4m_obj_t item = c4m_list_get(list, i, NULL); + c4m_obj_t item = c4m_list_get_base(list, i, NULL); c4m_list_set(res, i, c4m_copy_object_of_type(item, item_type)); } @@ -377,7 +419,7 @@ c4m_list_shallow_copy(c4m_list_t *list) c4m_list_t *res = c4m_new(my_type, c4m_kw("length", c4m_ka(len))); for (int i = 0; i < len; i++) { - c4m_list_set(res, i, c4m_list_get(list, i, NULL)); + c4m_list_set(res, i, c4m_list_get_base(list, i, NULL)); } read_end(list); @@ -392,7 +434,7 @@ c4m_list_safe_get(c4m_list_t *list, int64_t ix) read_start(list); - c4m_obj_t result = c4m_list_get(list, ix, &err); + c4m_obj_t result = c4m_list_get_base(list, ix, &err); if (err) { c4m_utf8_t *msg = c4m_cstr_format( @@ -444,7 +486,7 @@ c4m_list_get_slice(c4m_list_t *list, int64_t start, int64_t end) res = c4m_new(c4m_get_my_type(list), c4m_kw("length", c4m_ka(len))); for (int i = 0; i < len; i++) { - void *item = c4m_list_get(list, start + i, NULL); + void *item = c4m_list_get_base(list, start + i, NULL); c4m_list_set(res, i, item); } @@ -495,18 +537,18 @@ c4m_list_set_slice(c4m_list_t *list, if (start > 0) { for (int i = 0; i < start; i++) { - void *item = c4m_list_get(list, i, NULL); + void *item = c4m_list_get_base(list, i, NULL); newdata[i] = item; } } for (int i = 0; i < len2; i++) { - void *item = c4m_list_get(new, i, NULL); + void *item = c4m_list_get_base(new, i, NULL); newdata[start++] = item; } for (int i = end; i < len1; i++) { - void *item = c4m_list_get(list, i, NULL); + void *item = c4m_list_get_base(list, i, NULL); newdata[start++] = item; } @@ -532,10 +574,10 @@ c4m_list_contains(c4m_list_t *list, c4m_obj_t item) // Don't know why ref is giving me no item type yet, // so this is a tmp fix. read_end(list); - return item == c4m_list_get(list, i, NULL); + return item == c4m_list_get_base(list, i, NULL); } - if (c4m_eq(item_type, item, c4m_list_get(list, i, NULL))) { + if (c4m_eq(item_type, item, c4m_list_get_base(list, i, NULL))) { read_end(list); return true; } @@ -548,12 +590,30 @@ c4m_list_contains(c4m_list_t *list, c4m_obj_t item) static void * c4m_list_view(c4m_list_t *list, uint64_t *n) { - c4m_list_t *copy = c4m_list_shallow_copy(list); - *n = c4m_list_len(copy); - return copy->data; + read_start(list); + + void **view; + int len = c4m_list_len(list); + + if (c4m_obj_item_type_is_value(list)) { + view = c4m_gc_array_value_alloc(void *, len); + } + else { + view = c4m_gc_array_alloc(void *, len); + } + + for (int i = 0; i < len; i++) { + view[i] = c4m_list_get_base(list, i, NULL); + } + + read_end(list); + + *n = len; + + return view; } static c4m_list_t * -c4m_to_xlist_lit(c4m_type_t *objtype, c4m_list_t *items, c4m_utf8_t *litmod) +c4m_to_list_lit(c4m_type_t *objtype, c4m_list_t *items, c4m_utf8_t *litmod) { c4m_base_obj_t *hdr = c4m_object_header((c4m_obj_t)items); hdr->concrete_type = objtype; @@ -586,7 +646,7 @@ const c4m_vtable_t c4m_list_vtable = { [C4M_BI_SLICE_GET] = (c4m_vtable_entry)c4m_list_get_slice, [C4M_BI_SLICE_SET] = (c4m_vtable_entry)c4m_list_set_slice, [C4M_BI_VIEW] = (c4m_vtable_entry)c4m_list_view, - [C4M_BI_CONTAINER_LIT] = (c4m_vtable_entry)c4m_to_xlist_lit, + [C4M_BI_CONTAINER_LIT] = (c4m_vtable_entry)c4m_to_list_lit, [C4M_BI_REPR] = (c4m_vtable_entry)c4m_list_repr, [C4M_BI_GC_MAP] = (c4m_vtable_entry)c4m_list_set_gc_bits, // Explicit because some compilers don't seem to always properly diff --git a/src/con4m/string.c b/src/con4m/string.c index 6c556528..7ae4489f 100644 --- a/src/con4m/string.c +++ b/src/con4m/string.c @@ -351,7 +351,7 @@ c4m_str_concat(const c4m_str_t *p1, const c4m_str_t *p2) } c4m_utf32_t * -_c4m_str_join(const c4m_list_t *l, const c4m_str_t *joiner, ...) +_c4m_str_join(c4m_list_t *l, const c4m_str_t *joiner, ...) { c4m_karg_only_init(joiner); @@ -1363,7 +1363,7 @@ c4m_string_format(c4m_str_t *obj, c4m_fmt_spec_t *spec) } c4m_list_t * -c4m_u8_map(const c4m_list_t *inlist) +c4m_u8_map(c4m_list_t *inlist) { int len = c4m_list_len(inlist); diff --git a/src/con4m/vm.c b/src/con4m/vm.c index 55ce22af..811fb819 100644 --- a/src/con4m/vm.c +++ b/src/con4m/vm.c @@ -811,19 +811,46 @@ c4m_vm_runloop(c4m_vmthread_t *tstate_arg) tstate->pc, NULL); -// #define C4M_VM_DEBUG #ifdef C4M_VM_DEBUG - c4m_print( - c4m_cstr_format( - "[i] > {} (PC@{:x}; SP@{:x}; FP@{:x}; a = {}; m = {})", - c4m_fmt_instr_name(i), - c4m_box_u64(tstate->pc * 16), - c4m_box_u64((uint64_t)(void *)tstate->sp), - c4m_box_u64((uint64_t)(void *)tstate->fp), - c4m_box_i64((int64_t)i->arg), - c4m_box_u64((uint64_t)tstate->current_module->module_id))); - printf("stack has %ld items on it.\n", - &tstate->stack[STACK_SIZE] - tstate->sp); + static bool debug_on = (bool)(C4M_VM_DEBUG_DEFAULT); + static char *debug_fmt_str = + "[i]> {} (PC@{:x}; SP@{:x}; " + "FP@{:x}; a = {}; i = {}; m = {})"; + + if (debug_on && i->op != C4M_ZNop) { + int num_stack_items = &tstate->stack[STACK_SIZE] - tstate->sp; + printf("stack has %d items on it: ", num_stack_items); + for (int i = 0; i < num_stack_items; i++) { + if (&tstate->sp[i] == tstate->fp) { + printf("\e[34m[%p]\e[0m ", tstate->sp[i].vptr); + } + else { + if (&tstate->sp[i - 1] == tstate->fp) { + printf("\e[32m[%p]\e[0m ", tstate->sp[i].vptr); + } + else { + if (&tstate->sp[i] > tstate->fp) { + printf("\e[31m[%p]\e[0m ", tstate->sp[i].vptr); + } + else { + printf("\e[33m[%p]\e[0m ", tstate->sp[i].vptr); + } + } + } + } + printf("\n"); + c4m_print( + c4m_cstr_format( + debug_fmt_str, + c4m_fmt_instr_name(i), + c4m_box_u64(tstate->pc * 16), + c4m_box_u64((uint64_t)(void *)tstate->sp), + c4m_box_u64((uint64_t)(void *)tstate->fp), + c4m_box_i64((int64_t)i->arg), + c4m_box_i64((int64_t)i->immediate), + c4m_box_u64((uint64_t)tstate->current_module->module_id))); + } + #endif switch (i->op) { @@ -1013,8 +1040,8 @@ c4m_vm_runloop(c4m_vmthread_t *tstate_arg) break; case C4M_ZShlI: STACK_REQUIRE_VALUES(1); - rhs.uint = tstate->sp[0].uint; - tstate->sp[0].uint <<= i->arg; + rhs.uint = tstate->sp[0].uint; + tstate->sp[0].uint = i->arg << tstate->sp[0].uint; break; case C4M_ZShr: STACK_REQUIRE_VALUES(2); @@ -1139,59 +1166,52 @@ c4m_vm_runloop(c4m_vmthread_t *tstate_arg) STACK_REQUIRE_VALUES(2); STACK_REQUIRE_SLOTS(2); // Usually 1, except w/ dict. do { - uint64_t obj_len = tstate->sp->uint; - - union { - uint8_t u8; - uint16_t u16; - uint32_t u32; - uint64_t u64; - } view_item; - - union { - uint8_t *p8; - uint16_t *p16; - uint32_t *p32; - uint64_t *p64; - c4m_obj_t obj; - } view_ptr; - - view_item.u64 = 0; - view_ptr.obj = (tstate->sp + 1)->rvalue.obj; + uint64_t obj_len = tstate->sp->uint; + void **view_slot = &(tstate->sp + 1)->rvalue.obj; + char *p = *(char **)view_slot; + c4m_box_t *box = (c4m_box_t *)p; --tstate->sp; switch (obj_len) { case 1: - view_item.u8 = *view_ptr.p8++; + tstate->sp->uint = box->u8; + *view_slot = (void *)(p + 1); break; case 2: - view_item.u16 = *view_ptr.p16++; + tstate->sp->uint = box->u16; + *view_slot = (void *)(p + 2); break; case 4: - view_item.u32 = *view_ptr.p32++; + tstate->sp->uint = box->u32; + *view_slot = (void *)(p + 4); break; case 8: - view_item.u64 = *view_ptr.p64++; + tstate->sp->uint = box->u64; + *view_slot = (void *)(p + 8); // This is the only size that can be a dict. // Push the value on first. if (i->arg) { - tstate->sp->uint = *view_ptr.p64++; --tstate->sp; + p += 8; + box = (c4m_box_t *)p; + tstate->sp->uint = box->u64; + *view_slot = (p + 8); } break; default: do { uint64_t count = (uint64_t)(tstate->r1.obj); uint64_t bit_ix = (count - 1) % 64; - view_item.u64 = *view_ptr.p64 & (1 << bit_ix); + uint64_t val = **(uint64_t **)view_slot; + + tstate->sp->uint = val & (1 << bit_ix); if (bit_ix == 63) { - view_ptr.p64++; + *view_slot += 1; } } while (0); } - tstate->sp->uint = view_item.u64; } while (0); break; case C4M_ZStoreImm: @@ -1389,6 +1409,11 @@ c4m_vm_runloop(c4m_vmthread_t *tstate_arg) } break; #ifdef C4M_DEV + case C4M_ZDebug: +#ifdef C4M_VM_DEBUG + debug_on = (bool)i->arg; +#endif + break; // This is not threadsafe. It's just for early days. case C4M_ZPrint: STACK_REQUIRE_VALUES(1); diff --git a/tests/popcount.c4m b/tests/popcount.c4m new file mode 100644 index 00000000..a8d1237c --- /dev/null +++ b/tests/popcount.c4m @@ -0,0 +1,23 @@ +""" +Basic recursive popcount implementation. +""" +""" +$output: +16 +8 +1 +""" +func popcount(n) { + if (n == 0) { + return 0 + } + if !(n % 2) { + return 0 + popcount(n >> 1) + } + + return popcount(n >> 1) + 1 +} + +print(popcount(0xffff)) +print(popcount(0xcccc)) +print(popcount(1 << 12)) \ No newline at end of file diff --git a/tests/range.c4m b/tests/range.c4m new file mode 100644 index 00000000..05534e94 --- /dev/null +++ b/tests/range.c4m @@ -0,0 +1,27 @@ +""" +Tests a ranged for with an inner container. +""" +""" +$output: +hello +hi +How are you? +hello +hi +How are you? +hello +hi +How are you? +hello +hi +How are you? +hello +hi +How are you? +""" + +for i in 0 to 5 { + for x in ["hello", "hi", "How [em]are[/] you?"'r] { + print(x) + } +} \ No newline at end of file