diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8f2912b19..b8dc389af 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -121,18 +121,20 @@ jobs: - name: "test runtime code" run: | cd c_runtime - rm -f test - make && git diff --quiet + rm -f test_exe + make && git diff --quiet || { git diff; false; } ./test_exe && cd .. - name: "build assembly" run: "sbt \"++${{matrix.scala}}; cli/assembly\"" - name: "generate c code" - run: "./bosatsuj transpile --input_dir test_workspace/ --package_root test_workspace/ --outdir c_out c --test" + run: "./bosatsuj transpile --input_dir test_workspace/ --package_root test_workspace/ --outdir c_out c --test --filter Bosatsu/List" - name: "compile generated c code" run: | - cp c_runtime/* c_out + cp c_runtime/*.h c_out + cp c_runtime/*.c c_out + cp c_runtime/Makefile.test c_out/Makefile cd c_out - gcc -c output.c + make timeout-minutes: 30 name: ci on: diff --git a/.gitignore b/.gitignore index 30af009f1..00b1029f3 100644 --- a/.gitignore +++ b/.gitignore @@ -47,4 +47,6 @@ project/metals.sbt project/project/* jsui/bosatsu_ui.js -c_runtime/*.o \ No newline at end of file +c_runtime/*.o +c_runtime/test_exe +c_runtime/test_out diff --git a/c_runtime/Makefile.test b/c_runtime/Makefile.test new file mode 100644 index 000000000..a6e548300 --- /dev/null +++ b/c_runtime/Makefile.test @@ -0,0 +1,17 @@ +all: bosatsu_runtime.o test_out bosatsu_ext_Bosatsu_l_Predef.o bosatsu_ext_Bosatsu_l_Prog.o + +bosatsu_runtime.o: bosatsu_runtime.h bosatsu_runtime.c bosatsu_decls_generated.h bosatsu_generated.h + gcc -g -c -Wall -Werror bosatsu_runtime.c + +bosatsu_ext_Bosatsu_l_Predef.o: bosatsu_ext_Bosatsu_l_Predef.c bosatsu_runtime.o + gcc -g -Wall -Werror -c bosatsu_ext_Bosatsu_l_Predef.c + +bosatsu_ext_Bosatsu_l_Prog.o: bosatsu_ext_Bosatsu_l_Prog.c bosatsu_runtime.o + gcc -g -Wall -Werror -c bosatsu_ext_Bosatsu_l_Prog.c + +test_exe: output.c bosatsu_runtime.o bosatsu_ext_Bosatsu_l_Prog.o bosatsu_ext_Bosatsu_l_Predef.o + gcc -g -o test_exe output.c bosatsu_runtime.o bosatsu_ext_Bosatsu_l_Prog.o bosatsu_ext_Bosatsu_l_Predef.o + +test_out: test_exe + ./test_exe > output.log 2>&1 || { cat output.log; rm -f output.log; false; } + touch test_out \ No newline at end of file diff --git a/c_runtime/bosatsu_decls_generated.h b/c_runtime/bosatsu_decls_generated.h index e5b44e20f..84a191d6a 100644 --- a/c_runtime/bosatsu_decls_generated.h +++ b/c_runtime/bosatsu_decls_generated.h @@ -133,130 +133,130 @@ BValue alloc_enum32(ENUM_TAG variant, BValue arg0, BValue arg1, BValue arg2, BVa //FUNCTIONS BValue alloc_closure1(size_t size, BValue* data, BClosure1 fn); -BValue value_from_pure_fn1(BPureFn1 fn); +BValue alloc_boxed_pure_fn1(BPureFn1 fn); BValue call_fn1(BValue fn, BValue arg0); BValue alloc_closure2(size_t size, BValue* data, BClosure2 fn); -BValue value_from_pure_fn2(BPureFn2 fn); +BValue alloc_boxed_pure_fn2(BPureFn2 fn); BValue call_fn2(BValue fn, BValue arg0, BValue arg1); BValue alloc_closure3(size_t size, BValue* data, BClosure3 fn); -BValue value_from_pure_fn3(BPureFn3 fn); +BValue alloc_boxed_pure_fn3(BPureFn3 fn); BValue call_fn3(BValue fn, BValue arg0, BValue arg1, BValue arg2); BValue alloc_closure4(size_t size, BValue* data, BClosure4 fn); -BValue value_from_pure_fn4(BPureFn4 fn); +BValue alloc_boxed_pure_fn4(BPureFn4 fn); BValue call_fn4(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3); BValue alloc_closure5(size_t size, BValue* data, BClosure5 fn); -BValue value_from_pure_fn5(BPureFn5 fn); +BValue alloc_boxed_pure_fn5(BPureFn5 fn); BValue call_fn5(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4); BValue alloc_closure6(size_t size, BValue* data, BClosure6 fn); -BValue value_from_pure_fn6(BPureFn6 fn); +BValue alloc_boxed_pure_fn6(BPureFn6 fn); BValue call_fn6(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5); BValue alloc_closure7(size_t size, BValue* data, BClosure7 fn); -BValue value_from_pure_fn7(BPureFn7 fn); +BValue alloc_boxed_pure_fn7(BPureFn7 fn); BValue call_fn7(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6); BValue alloc_closure8(size_t size, BValue* data, BClosure8 fn); -BValue value_from_pure_fn8(BPureFn8 fn); +BValue alloc_boxed_pure_fn8(BPureFn8 fn); BValue call_fn8(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7); BValue alloc_closure9(size_t size, BValue* data, BClosure9 fn); -BValue value_from_pure_fn9(BPureFn9 fn); +BValue alloc_boxed_pure_fn9(BPureFn9 fn); BValue call_fn9(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8); BValue alloc_closure10(size_t size, BValue* data, BClosure10 fn); -BValue value_from_pure_fn10(BPureFn10 fn); +BValue alloc_boxed_pure_fn10(BPureFn10 fn); BValue call_fn10(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9); BValue alloc_closure11(size_t size, BValue* data, BClosure11 fn); -BValue value_from_pure_fn11(BPureFn11 fn); +BValue alloc_boxed_pure_fn11(BPureFn11 fn); BValue call_fn11(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10); BValue alloc_closure12(size_t size, BValue* data, BClosure12 fn); -BValue value_from_pure_fn12(BPureFn12 fn); +BValue alloc_boxed_pure_fn12(BPureFn12 fn); BValue call_fn12(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11); BValue alloc_closure13(size_t size, BValue* data, BClosure13 fn); -BValue value_from_pure_fn13(BPureFn13 fn); +BValue alloc_boxed_pure_fn13(BPureFn13 fn); BValue call_fn13(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12); BValue alloc_closure14(size_t size, BValue* data, BClosure14 fn); -BValue value_from_pure_fn14(BPureFn14 fn); +BValue alloc_boxed_pure_fn14(BPureFn14 fn); BValue call_fn14(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13); BValue alloc_closure15(size_t size, BValue* data, BClosure15 fn); -BValue value_from_pure_fn15(BPureFn15 fn); +BValue alloc_boxed_pure_fn15(BPureFn15 fn); BValue call_fn15(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14); BValue alloc_closure16(size_t size, BValue* data, BClosure16 fn); -BValue value_from_pure_fn16(BPureFn16 fn); +BValue alloc_boxed_pure_fn16(BPureFn16 fn); BValue call_fn16(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15); BValue alloc_closure17(size_t size, BValue* data, BClosure17 fn); -BValue value_from_pure_fn17(BPureFn17 fn); +BValue alloc_boxed_pure_fn17(BPureFn17 fn); BValue call_fn17(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16); BValue alloc_closure18(size_t size, BValue* data, BClosure18 fn); -BValue value_from_pure_fn18(BPureFn18 fn); +BValue alloc_boxed_pure_fn18(BPureFn18 fn); BValue call_fn18(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16, BValue arg17); BValue alloc_closure19(size_t size, BValue* data, BClosure19 fn); -BValue value_from_pure_fn19(BPureFn19 fn); +BValue alloc_boxed_pure_fn19(BPureFn19 fn); BValue call_fn19(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16, BValue arg17, BValue arg18); BValue alloc_closure20(size_t size, BValue* data, BClosure20 fn); -BValue value_from_pure_fn20(BPureFn20 fn); +BValue alloc_boxed_pure_fn20(BPureFn20 fn); BValue call_fn20(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16, BValue arg17, BValue arg18, BValue arg19); BValue alloc_closure21(size_t size, BValue* data, BClosure21 fn); -BValue value_from_pure_fn21(BPureFn21 fn); +BValue alloc_boxed_pure_fn21(BPureFn21 fn); BValue call_fn21(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16, BValue arg17, BValue arg18, BValue arg19, BValue arg20); BValue alloc_closure22(size_t size, BValue* data, BClosure22 fn); -BValue value_from_pure_fn22(BPureFn22 fn); +BValue alloc_boxed_pure_fn22(BPureFn22 fn); BValue call_fn22(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16, BValue arg17, BValue arg18, BValue arg19, BValue arg20, BValue arg21); BValue alloc_closure23(size_t size, BValue* data, BClosure23 fn); -BValue value_from_pure_fn23(BPureFn23 fn); +BValue alloc_boxed_pure_fn23(BPureFn23 fn); BValue call_fn23(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16, BValue arg17, BValue arg18, BValue arg19, BValue arg20, BValue arg21, BValue arg22); BValue alloc_closure24(size_t size, BValue* data, BClosure24 fn); -BValue value_from_pure_fn24(BPureFn24 fn); +BValue alloc_boxed_pure_fn24(BPureFn24 fn); BValue call_fn24(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16, BValue arg17, BValue arg18, BValue arg19, BValue arg20, BValue arg21, BValue arg22, BValue arg23); BValue alloc_closure25(size_t size, BValue* data, BClosure25 fn); -BValue value_from_pure_fn25(BPureFn25 fn); +BValue alloc_boxed_pure_fn25(BPureFn25 fn); BValue call_fn25(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16, BValue arg17, BValue arg18, BValue arg19, BValue arg20, BValue arg21, BValue arg22, BValue arg23, BValue arg24); BValue alloc_closure26(size_t size, BValue* data, BClosure26 fn); -BValue value_from_pure_fn26(BPureFn26 fn); +BValue alloc_boxed_pure_fn26(BPureFn26 fn); BValue call_fn26(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16, BValue arg17, BValue arg18, BValue arg19, BValue arg20, BValue arg21, BValue arg22, BValue arg23, BValue arg24, BValue arg25); BValue alloc_closure27(size_t size, BValue* data, BClosure27 fn); -BValue value_from_pure_fn27(BPureFn27 fn); +BValue alloc_boxed_pure_fn27(BPureFn27 fn); BValue call_fn27(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16, BValue arg17, BValue arg18, BValue arg19, BValue arg20, BValue arg21, BValue arg22, BValue arg23, BValue arg24, BValue arg25, BValue arg26); BValue alloc_closure28(size_t size, BValue* data, BClosure28 fn); -BValue value_from_pure_fn28(BPureFn28 fn); +BValue alloc_boxed_pure_fn28(BPureFn28 fn); BValue call_fn28(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16, BValue arg17, BValue arg18, BValue arg19, BValue arg20, BValue arg21, BValue arg22, BValue arg23, BValue arg24, BValue arg25, BValue arg26, BValue arg27); BValue alloc_closure29(size_t size, BValue* data, BClosure29 fn); -BValue value_from_pure_fn29(BPureFn29 fn); +BValue alloc_boxed_pure_fn29(BPureFn29 fn); BValue call_fn29(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16, BValue arg17, BValue arg18, BValue arg19, BValue arg20, BValue arg21, BValue arg22, BValue arg23, BValue arg24, BValue arg25, BValue arg26, BValue arg27, BValue arg28); BValue alloc_closure30(size_t size, BValue* data, BClosure30 fn); -BValue value_from_pure_fn30(BPureFn30 fn); +BValue alloc_boxed_pure_fn30(BPureFn30 fn); BValue call_fn30(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16, BValue arg17, BValue arg18, BValue arg19, BValue arg20, BValue arg21, BValue arg22, BValue arg23, BValue arg24, BValue arg25, BValue arg26, BValue arg27, BValue arg28, BValue arg29); BValue alloc_closure31(size_t size, BValue* data, BClosure31 fn); -BValue value_from_pure_fn31(BPureFn31 fn); +BValue alloc_boxed_pure_fn31(BPureFn31 fn); BValue call_fn31(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16, BValue arg17, BValue arg18, BValue arg19, BValue arg20, BValue arg21, BValue arg22, BValue arg23, BValue arg24, BValue arg25, BValue arg26, BValue arg27, BValue arg28, BValue arg29, BValue arg30); BValue alloc_closure32(size_t size, BValue* data, BClosure32 fn); -BValue value_from_pure_fn32(BPureFn32 fn); +BValue alloc_boxed_pure_fn32(BPureFn32 fn); BValue call_fn32(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16, BValue arg17, BValue arg18, BValue arg19, BValue arg20, BValue arg21, BValue arg22, BValue arg23, BValue arg24, BValue arg25, BValue arg26, BValue arg27, BValue arg28, BValue arg29, BValue arg30, BValue arg31); diff --git a/c_runtime/bosatsu_ext_Bosatsu_l_Predef.c b/c_runtime/bosatsu_ext_Bosatsu_l_Predef.c index d0bb63c97..c3ebfa038 100644 --- a/c_runtime/bosatsu_ext_Bosatsu_l_Predef.c +++ b/c_runtime/bosatsu_ext_Bosatsu_l_Predef.c @@ -61,6 +61,9 @@ BValue ___bsts_g_Bosatsu_l_Predef_l_concat__String(BValue a) { // we allocate some bytes and copy char* bytes = malloc(sizeof(char) * total_len); char* current_pos = bytes; + // reset to go through the list + amut = a; + v = get_variant(amut); while (v != 0) { BValue str = get_enum_index(amut, 0); size_t str_len = bsts_string_utf8_len(str); @@ -115,7 +118,7 @@ BValue ___bsts_g_Bosatsu_l_Predef_l_int__loop(BValue i, BValue a, BValue fn) { // _i = tmp_i // return _a BValue zero = bsts_integer_from_int(0); - int cont = bsts_integer_cmp(zero, i) > 0; + int cont = bsts_integer_cmp(zero, i) < 0; BValue _i = i; BValue _a = a; while (cont) { @@ -132,9 +135,8 @@ BValue ___bsts_g_Bosatsu_l_Predef_l_int__loop(BValue i, BValue a, BValue fn) { _i = tmp_i; } // all the rest of the values are references - release_value(i); - release_value(a); release_value(fn); + release_value(_i); return _a; } @@ -250,12 +252,8 @@ BValue ___bsts_g_Bosatsu_l_Predef_l_times(BValue a, BValue b) { } BValue ___bsts_g_Bosatsu_l_Predef_l_trace(BValue a, BValue b) { - char* bytes = bsts_string_utf8_bytes(a); - size_t len = bsts_string_utf8_len(a); - // TODO: if this string is somehow too big for an int this may fail - printf("%.*s\n", (int)len, bytes); + bsts_string_println(a); release_value(a); - return b; } diff --git a/c_runtime/bosatsu_generated.h b/c_runtime/bosatsu_generated.h index 58f6cca1b..006def4d5 100644 --- a/c_runtime/bosatsu_generated.h +++ b/c_runtime/bosatsu_generated.h @@ -8,7 +8,8 @@ void free_struct2(Struct2* s) { } BValue alloc_struct2(BValue b0, BValue b1) { Struct2* rc = malloc(sizeof(Struct2)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct2; rc->_0 = b0; rc->_1 = b1; @@ -25,7 +26,8 @@ void free_struct3(Struct3* s) { } BValue alloc_struct3(BValue b0, BValue b1, BValue b2) { Struct3* rc = malloc(sizeof(Struct3)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct3; rc->_0 = b0; rc->_1 = b1; @@ -44,7 +46,8 @@ void free_struct4(Struct4* s) { } BValue alloc_struct4(BValue b0, BValue b1, BValue b2, BValue b3) { Struct4* rc = malloc(sizeof(Struct4)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct4; rc->_0 = b0; rc->_1 = b1; @@ -65,7 +68,8 @@ void free_struct5(Struct5* s) { } BValue alloc_struct5(BValue b0, BValue b1, BValue b2, BValue b3, BValue b4) { Struct5* rc = malloc(sizeof(Struct5)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct5; rc->_0 = b0; rc->_1 = b1; @@ -88,7 +92,8 @@ void free_struct6(Struct6* s) { } BValue alloc_struct6(BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5) { Struct6* rc = malloc(sizeof(Struct6)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct6; rc->_0 = b0; rc->_1 = b1; @@ -113,7 +118,8 @@ void free_struct7(Struct7* s) { } BValue alloc_struct7(BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6) { Struct7* rc = malloc(sizeof(Struct7)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct7; rc->_0 = b0; rc->_1 = b1; @@ -140,7 +146,8 @@ void free_struct8(Struct8* s) { } BValue alloc_struct8(BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7) { Struct8* rc = malloc(sizeof(Struct8)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct8; rc->_0 = b0; rc->_1 = b1; @@ -169,7 +176,8 @@ void free_struct9(Struct9* s) { } BValue alloc_struct9(BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8) { Struct9* rc = malloc(sizeof(Struct9)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct9; rc->_0 = b0; rc->_1 = b1; @@ -200,7 +208,8 @@ void free_struct10(Struct10* s) { } BValue alloc_struct10(BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9) { Struct10* rc = malloc(sizeof(Struct10)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct10; rc->_0 = b0; rc->_1 = b1; @@ -233,7 +242,8 @@ void free_struct11(Struct11* s) { } BValue alloc_struct11(BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10) { Struct11* rc = malloc(sizeof(Struct11)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct11; rc->_0 = b0; rc->_1 = b1; @@ -268,7 +278,8 @@ void free_struct12(Struct12* s) { } BValue alloc_struct12(BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11) { Struct12* rc = malloc(sizeof(Struct12)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct12; rc->_0 = b0; rc->_1 = b1; @@ -305,7 +316,8 @@ void free_struct13(Struct13* s) { } BValue alloc_struct13(BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12) { Struct13* rc = malloc(sizeof(Struct13)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct13; rc->_0 = b0; rc->_1 = b1; @@ -344,7 +356,8 @@ void free_struct14(Struct14* s) { } BValue alloc_struct14(BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13) { Struct14* rc = malloc(sizeof(Struct14)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct14; rc->_0 = b0; rc->_1 = b1; @@ -385,7 +398,8 @@ void free_struct15(Struct15* s) { } BValue alloc_struct15(BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14) { Struct15* rc = malloc(sizeof(Struct15)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct15; rc->_0 = b0; rc->_1 = b1; @@ -428,7 +442,8 @@ void free_struct16(Struct16* s) { } BValue alloc_struct16(BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15) { Struct16* rc = malloc(sizeof(Struct16)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct16; rc->_0 = b0; rc->_1 = b1; @@ -473,7 +488,8 @@ void free_struct17(Struct17* s) { } BValue alloc_struct17(BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16) { Struct17* rc = malloc(sizeof(Struct17)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct17; rc->_0 = b0; rc->_1 = b1; @@ -520,7 +536,8 @@ void free_struct18(Struct18* s) { } BValue alloc_struct18(BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16, BValue b17) { Struct18* rc = malloc(sizeof(Struct18)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct18; rc->_0 = b0; rc->_1 = b1; @@ -569,7 +586,8 @@ void free_struct19(Struct19* s) { } BValue alloc_struct19(BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16, BValue b17, BValue b18) { Struct19* rc = malloc(sizeof(Struct19)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct19; rc->_0 = b0; rc->_1 = b1; @@ -620,7 +638,8 @@ void free_struct20(Struct20* s) { } BValue alloc_struct20(BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16, BValue b17, BValue b18, BValue b19) { Struct20* rc = malloc(sizeof(Struct20)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct20; rc->_0 = b0; rc->_1 = b1; @@ -673,7 +692,8 @@ void free_struct21(Struct21* s) { } BValue alloc_struct21(BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16, BValue b17, BValue b18, BValue b19, BValue b20) { Struct21* rc = malloc(sizeof(Struct21)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct21; rc->_0 = b0; rc->_1 = b1; @@ -728,7 +748,8 @@ void free_struct22(Struct22* s) { } BValue alloc_struct22(BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16, BValue b17, BValue b18, BValue b19, BValue b20, BValue b21) { Struct22* rc = malloc(sizeof(Struct22)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct22; rc->_0 = b0; rc->_1 = b1; @@ -785,7 +806,8 @@ void free_struct23(Struct23* s) { } BValue alloc_struct23(BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16, BValue b17, BValue b18, BValue b19, BValue b20, BValue b21, BValue b22) { Struct23* rc = malloc(sizeof(Struct23)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct23; rc->_0 = b0; rc->_1 = b1; @@ -844,7 +866,8 @@ void free_struct24(Struct24* s) { } BValue alloc_struct24(BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16, BValue b17, BValue b18, BValue b19, BValue b20, BValue b21, BValue b22, BValue b23) { Struct24* rc = malloc(sizeof(Struct24)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct24; rc->_0 = b0; rc->_1 = b1; @@ -905,7 +928,8 @@ void free_struct25(Struct25* s) { } BValue alloc_struct25(BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16, BValue b17, BValue b18, BValue b19, BValue b20, BValue b21, BValue b22, BValue b23, BValue b24) { Struct25* rc = malloc(sizeof(Struct25)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct25; rc->_0 = b0; rc->_1 = b1; @@ -968,7 +992,8 @@ void free_struct26(Struct26* s) { } BValue alloc_struct26(BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16, BValue b17, BValue b18, BValue b19, BValue b20, BValue b21, BValue b22, BValue b23, BValue b24, BValue b25) { Struct26* rc = malloc(sizeof(Struct26)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct26; rc->_0 = b0; rc->_1 = b1; @@ -1033,7 +1058,8 @@ void free_struct27(Struct27* s) { } BValue alloc_struct27(BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16, BValue b17, BValue b18, BValue b19, BValue b20, BValue b21, BValue b22, BValue b23, BValue b24, BValue b25, BValue b26) { Struct27* rc = malloc(sizeof(Struct27)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct27; rc->_0 = b0; rc->_1 = b1; @@ -1100,7 +1126,8 @@ void free_struct28(Struct28* s) { } BValue alloc_struct28(BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16, BValue b17, BValue b18, BValue b19, BValue b20, BValue b21, BValue b22, BValue b23, BValue b24, BValue b25, BValue b26, BValue b27) { Struct28* rc = malloc(sizeof(Struct28)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct28; rc->_0 = b0; rc->_1 = b1; @@ -1169,7 +1196,8 @@ void free_struct29(Struct29* s) { } BValue alloc_struct29(BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16, BValue b17, BValue b18, BValue b19, BValue b20, BValue b21, BValue b22, BValue b23, BValue b24, BValue b25, BValue b26, BValue b27, BValue b28) { Struct29* rc = malloc(sizeof(Struct29)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct29; rc->_0 = b0; rc->_1 = b1; @@ -1240,7 +1268,8 @@ void free_struct30(Struct30* s) { } BValue alloc_struct30(BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16, BValue b17, BValue b18, BValue b19, BValue b20, BValue b21, BValue b22, BValue b23, BValue b24, BValue b25, BValue b26, BValue b27, BValue b28, BValue b29) { Struct30* rc = malloc(sizeof(Struct30)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct30; rc->_0 = b0; rc->_1 = b1; @@ -1313,7 +1342,8 @@ void free_struct31(Struct31* s) { } BValue alloc_struct31(BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16, BValue b17, BValue b18, BValue b19, BValue b20, BValue b21, BValue b22, BValue b23, BValue b24, BValue b25, BValue b26, BValue b27, BValue b28, BValue b29, BValue b30) { Struct31* rc = malloc(sizeof(Struct31)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct31; rc->_0 = b0; rc->_1 = b1; @@ -1388,7 +1418,8 @@ void free_struct32(Struct32* s) { } BValue alloc_struct32(BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16, BValue b17, BValue b18, BValue b19, BValue b20, BValue b21, BValue b22, BValue b23, BValue b24, BValue b25, BValue b26, BValue b27, BValue b28, BValue b29, BValue b30, BValue b31) { Struct32* rc = malloc(sizeof(Struct32)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct32; rc->_0 = b0; rc->_1 = b1; @@ -1434,7 +1465,8 @@ void free_enum1(Enum1* s) { } BValue alloc_enum1(ENUM_TAG tag, BValue b0) { Enum1* rc = malloc(sizeof(Enum1)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum1; rc->tag = tag; rc->_0 = b0; @@ -1450,7 +1482,8 @@ void free_enum2(Enum2* s) { } BValue alloc_enum2(ENUM_TAG tag, BValue b0, BValue b1) { Enum2* rc = malloc(sizeof(Enum2)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum2; rc->tag = tag; rc->_0 = b0; @@ -1468,7 +1501,8 @@ void free_enum3(Enum3* s) { } BValue alloc_enum3(ENUM_TAG tag, BValue b0, BValue b1, BValue b2) { Enum3* rc = malloc(sizeof(Enum3)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum3; rc->tag = tag; rc->_0 = b0; @@ -1488,7 +1522,8 @@ void free_enum4(Enum4* s) { } BValue alloc_enum4(ENUM_TAG tag, BValue b0, BValue b1, BValue b2, BValue b3) { Enum4* rc = malloc(sizeof(Enum4)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum4; rc->tag = tag; rc->_0 = b0; @@ -1510,7 +1545,8 @@ void free_enum5(Enum5* s) { } BValue alloc_enum5(ENUM_TAG tag, BValue b0, BValue b1, BValue b2, BValue b3, BValue b4) { Enum5* rc = malloc(sizeof(Enum5)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum5; rc->tag = tag; rc->_0 = b0; @@ -1534,7 +1570,8 @@ void free_enum6(Enum6* s) { } BValue alloc_enum6(ENUM_TAG tag, BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5) { Enum6* rc = malloc(sizeof(Enum6)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum6; rc->tag = tag; rc->_0 = b0; @@ -1560,7 +1597,8 @@ void free_enum7(Enum7* s) { } BValue alloc_enum7(ENUM_TAG tag, BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6) { Enum7* rc = malloc(sizeof(Enum7)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum7; rc->tag = tag; rc->_0 = b0; @@ -1588,7 +1626,8 @@ void free_enum8(Enum8* s) { } BValue alloc_enum8(ENUM_TAG tag, BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7) { Enum8* rc = malloc(sizeof(Enum8)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum8; rc->tag = tag; rc->_0 = b0; @@ -1618,7 +1657,8 @@ void free_enum9(Enum9* s) { } BValue alloc_enum9(ENUM_TAG tag, BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8) { Enum9* rc = malloc(sizeof(Enum9)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum9; rc->tag = tag; rc->_0 = b0; @@ -1650,7 +1690,8 @@ void free_enum10(Enum10* s) { } BValue alloc_enum10(ENUM_TAG tag, BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9) { Enum10* rc = malloc(sizeof(Enum10)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum10; rc->tag = tag; rc->_0 = b0; @@ -1684,7 +1725,8 @@ void free_enum11(Enum11* s) { } BValue alloc_enum11(ENUM_TAG tag, BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10) { Enum11* rc = malloc(sizeof(Enum11)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum11; rc->tag = tag; rc->_0 = b0; @@ -1720,7 +1762,8 @@ void free_enum12(Enum12* s) { } BValue alloc_enum12(ENUM_TAG tag, BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11) { Enum12* rc = malloc(sizeof(Enum12)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum12; rc->tag = tag; rc->_0 = b0; @@ -1758,7 +1801,8 @@ void free_enum13(Enum13* s) { } BValue alloc_enum13(ENUM_TAG tag, BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12) { Enum13* rc = malloc(sizeof(Enum13)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum13; rc->tag = tag; rc->_0 = b0; @@ -1798,7 +1842,8 @@ void free_enum14(Enum14* s) { } BValue alloc_enum14(ENUM_TAG tag, BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13) { Enum14* rc = malloc(sizeof(Enum14)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum14; rc->tag = tag; rc->_0 = b0; @@ -1840,7 +1885,8 @@ void free_enum15(Enum15* s) { } BValue alloc_enum15(ENUM_TAG tag, BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14) { Enum15* rc = malloc(sizeof(Enum15)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum15; rc->tag = tag; rc->_0 = b0; @@ -1884,7 +1930,8 @@ void free_enum16(Enum16* s) { } BValue alloc_enum16(ENUM_TAG tag, BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15) { Enum16* rc = malloc(sizeof(Enum16)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum16; rc->tag = tag; rc->_0 = b0; @@ -1930,7 +1977,8 @@ void free_enum17(Enum17* s) { } BValue alloc_enum17(ENUM_TAG tag, BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16) { Enum17* rc = malloc(sizeof(Enum17)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum17; rc->tag = tag; rc->_0 = b0; @@ -1978,7 +2026,8 @@ void free_enum18(Enum18* s) { } BValue alloc_enum18(ENUM_TAG tag, BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16, BValue b17) { Enum18* rc = malloc(sizeof(Enum18)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum18; rc->tag = tag; rc->_0 = b0; @@ -2028,7 +2077,8 @@ void free_enum19(Enum19* s) { } BValue alloc_enum19(ENUM_TAG tag, BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16, BValue b17, BValue b18) { Enum19* rc = malloc(sizeof(Enum19)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum19; rc->tag = tag; rc->_0 = b0; @@ -2080,7 +2130,8 @@ void free_enum20(Enum20* s) { } BValue alloc_enum20(ENUM_TAG tag, BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16, BValue b17, BValue b18, BValue b19) { Enum20* rc = malloc(sizeof(Enum20)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum20; rc->tag = tag; rc->_0 = b0; @@ -2134,7 +2185,8 @@ void free_enum21(Enum21* s) { } BValue alloc_enum21(ENUM_TAG tag, BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16, BValue b17, BValue b18, BValue b19, BValue b20) { Enum21* rc = malloc(sizeof(Enum21)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum21; rc->tag = tag; rc->_0 = b0; @@ -2190,7 +2242,8 @@ void free_enum22(Enum22* s) { } BValue alloc_enum22(ENUM_TAG tag, BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16, BValue b17, BValue b18, BValue b19, BValue b20, BValue b21) { Enum22* rc = malloc(sizeof(Enum22)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum22; rc->tag = tag; rc->_0 = b0; @@ -2248,7 +2301,8 @@ void free_enum23(Enum23* s) { } BValue alloc_enum23(ENUM_TAG tag, BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16, BValue b17, BValue b18, BValue b19, BValue b20, BValue b21, BValue b22) { Enum23* rc = malloc(sizeof(Enum23)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum23; rc->tag = tag; rc->_0 = b0; @@ -2308,7 +2362,8 @@ void free_enum24(Enum24* s) { } BValue alloc_enum24(ENUM_TAG tag, BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16, BValue b17, BValue b18, BValue b19, BValue b20, BValue b21, BValue b22, BValue b23) { Enum24* rc = malloc(sizeof(Enum24)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum24; rc->tag = tag; rc->_0 = b0; @@ -2370,7 +2425,8 @@ void free_enum25(Enum25* s) { } BValue alloc_enum25(ENUM_TAG tag, BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16, BValue b17, BValue b18, BValue b19, BValue b20, BValue b21, BValue b22, BValue b23, BValue b24) { Enum25* rc = malloc(sizeof(Enum25)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum25; rc->tag = tag; rc->_0 = b0; @@ -2434,7 +2490,8 @@ void free_enum26(Enum26* s) { } BValue alloc_enum26(ENUM_TAG tag, BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16, BValue b17, BValue b18, BValue b19, BValue b20, BValue b21, BValue b22, BValue b23, BValue b24, BValue b25) { Enum26* rc = malloc(sizeof(Enum26)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum26; rc->tag = tag; rc->_0 = b0; @@ -2500,7 +2557,8 @@ void free_enum27(Enum27* s) { } BValue alloc_enum27(ENUM_TAG tag, BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16, BValue b17, BValue b18, BValue b19, BValue b20, BValue b21, BValue b22, BValue b23, BValue b24, BValue b25, BValue b26) { Enum27* rc = malloc(sizeof(Enum27)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum27; rc->tag = tag; rc->_0 = b0; @@ -2568,7 +2626,8 @@ void free_enum28(Enum28* s) { } BValue alloc_enum28(ENUM_TAG tag, BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16, BValue b17, BValue b18, BValue b19, BValue b20, BValue b21, BValue b22, BValue b23, BValue b24, BValue b25, BValue b26, BValue b27) { Enum28* rc = malloc(sizeof(Enum28)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum28; rc->tag = tag; rc->_0 = b0; @@ -2638,7 +2697,8 @@ void free_enum29(Enum29* s) { } BValue alloc_enum29(ENUM_TAG tag, BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16, BValue b17, BValue b18, BValue b19, BValue b20, BValue b21, BValue b22, BValue b23, BValue b24, BValue b25, BValue b26, BValue b27, BValue b28) { Enum29* rc = malloc(sizeof(Enum29)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum29; rc->tag = tag; rc->_0 = b0; @@ -2710,7 +2770,8 @@ void free_enum30(Enum30* s) { } BValue alloc_enum30(ENUM_TAG tag, BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16, BValue b17, BValue b18, BValue b19, BValue b20, BValue b21, BValue b22, BValue b23, BValue b24, BValue b25, BValue b26, BValue b27, BValue b28, BValue b29) { Enum30* rc = malloc(sizeof(Enum30)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum30; rc->tag = tag; rc->_0 = b0; @@ -2784,7 +2845,8 @@ void free_enum31(Enum31* s) { } BValue alloc_enum31(ENUM_TAG tag, BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16, BValue b17, BValue b18, BValue b19, BValue b20, BValue b21, BValue b22, BValue b23, BValue b24, BValue b25, BValue b26, BValue b27, BValue b28, BValue b29, BValue b30) { Enum31* rc = malloc(sizeof(Enum31)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum31; rc->tag = tag; rc->_0 = b0; @@ -2860,7 +2922,8 @@ void free_enum32(Enum32* s) { } BValue alloc_enum32(ENUM_TAG tag, BValue b0, BValue b1, BValue b2, BValue b3, BValue b4, BValue b5, BValue b6, BValue b7, BValue b8, BValue b9, BValue b10, BValue b11, BValue b12, BValue b13, BValue b14, BValue b15, BValue b16, BValue b17, BValue b18, BValue b19, BValue b20, BValue b21, BValue b22, BValue b23, BValue b24, BValue b25, BValue b26, BValue b27, BValue b28, BValue b29, BValue b30, BValue b31) { Enum32* rc = malloc(sizeof(Enum32)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum32; rc->tag = tag; rc->_0 = b0; @@ -2900,11 +2963,12 @@ BValue alloc_enum32(ENUM_TAG tag, BValue b0, BValue b1, BValue b2, BValue b3, BV // FUNCTIONS - +DEFINE_RC_STRUCT(BoxedPureFn1, BPureFn1 fn; size_t slot_len;); BValue alloc_closure1(size_t size, BValue* data, BClosure1 fn) { Closure1Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -2915,14 +2979,25 @@ BValue alloc_closure1(size_t size, BValue* data, BClosure1 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn1(BPureFn1 fn) { + BoxedPureFn1* rc = (BoxedPureFn1*)malloc(sizeof(BoxedPureFn1)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn1(BValue fn, BValue arg0) { - if (IS_PURE_VALUE(fn)) { - BPureFn1 pfn = (BPureFn1)TO_POINTER(fn); - return pfn(arg0); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn1* purefn = (BoxedPureFn1*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0); } else { // this must be a closure: - Closure1Data* rc = (Closure1Data*)fn; + Closure1Data* rc = (Closure1Data*)ptr; BValue* data = closure_data_of(rc); return rc->fn(data, arg0); } @@ -2930,10 +3005,12 @@ BValue call_fn1(BValue fn, BValue arg0) { DEFINE_RC_STRUCT(Closure2Data, BClosure2 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn2, BPureFn2 fn; size_t slot_len;); BValue alloc_closure2(size_t size, BValue* data, BClosure2 fn) { Closure2Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -2944,14 +3021,25 @@ BValue alloc_closure2(size_t size, BValue* data, BClosure2 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn2(BPureFn2 fn) { + BoxedPureFn2* rc = (BoxedPureFn2*)malloc(sizeof(BoxedPureFn2)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn2(BValue fn, BValue arg0, BValue arg1) { - if (IS_PURE_VALUE(fn)) { - BPureFn2 pfn = (BPureFn2)TO_POINTER(fn); - return pfn(arg0, arg1); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn2* purefn = (BoxedPureFn2*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1); } else { // this must be a closure: - Closure2Data* rc = (Closure2Data*)fn; + Closure2Data* rc = (Closure2Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1); } @@ -2959,10 +3047,12 @@ BValue call_fn2(BValue fn, BValue arg0, BValue arg1) { DEFINE_RC_STRUCT(Closure3Data, BClosure3 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn3, BPureFn3 fn; size_t slot_len;); BValue alloc_closure3(size_t size, BValue* data, BClosure3 fn) { Closure3Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -2973,14 +3063,25 @@ BValue alloc_closure3(size_t size, BValue* data, BClosure3 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn3(BPureFn3 fn) { + BoxedPureFn3* rc = (BoxedPureFn3*)malloc(sizeof(BoxedPureFn3)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn3(BValue fn, BValue arg0, BValue arg1, BValue arg2) { - if (IS_PURE_VALUE(fn)) { - BPureFn3 pfn = (BPureFn3)TO_POINTER(fn); - return pfn(arg0, arg1, arg2); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn3* purefn = (BoxedPureFn3*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1, arg2); } else { // this must be a closure: - Closure3Data* rc = (Closure3Data*)fn; + Closure3Data* rc = (Closure3Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1, arg2); } @@ -2988,10 +3089,12 @@ BValue call_fn3(BValue fn, BValue arg0, BValue arg1, BValue arg2) { DEFINE_RC_STRUCT(Closure4Data, BClosure4 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn4, BPureFn4 fn; size_t slot_len;); BValue alloc_closure4(size_t size, BValue* data, BClosure4 fn) { Closure4Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -3002,14 +3105,25 @@ BValue alloc_closure4(size_t size, BValue* data, BClosure4 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn4(BPureFn4 fn) { + BoxedPureFn4* rc = (BoxedPureFn4*)malloc(sizeof(BoxedPureFn4)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn4(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3) { - if (IS_PURE_VALUE(fn)) { - BPureFn4 pfn = (BPureFn4)TO_POINTER(fn); - return pfn(arg0, arg1, arg2, arg3); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn4* purefn = (BoxedPureFn4*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1, arg2, arg3); } else { // this must be a closure: - Closure4Data* rc = (Closure4Data*)fn; + Closure4Data* rc = (Closure4Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1, arg2, arg3); } @@ -3017,10 +3131,12 @@ BValue call_fn4(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3) { DEFINE_RC_STRUCT(Closure5Data, BClosure5 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn5, BPureFn5 fn; size_t slot_len;); BValue alloc_closure5(size_t size, BValue* data, BClosure5 fn) { Closure5Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -3031,14 +3147,25 @@ BValue alloc_closure5(size_t size, BValue* data, BClosure5 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn5(BPureFn5 fn) { + BoxedPureFn5* rc = (BoxedPureFn5*)malloc(sizeof(BoxedPureFn5)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn5(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4) { - if (IS_PURE_VALUE(fn)) { - BPureFn5 pfn = (BPureFn5)TO_POINTER(fn); - return pfn(arg0, arg1, arg2, arg3, arg4); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn5* purefn = (BoxedPureFn5*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1, arg2, arg3, arg4); } else { // this must be a closure: - Closure5Data* rc = (Closure5Data*)fn; + Closure5Data* rc = (Closure5Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1, arg2, arg3, arg4); } @@ -3046,10 +3173,12 @@ BValue call_fn5(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, B DEFINE_RC_STRUCT(Closure6Data, BClosure6 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn6, BPureFn6 fn; size_t slot_len;); BValue alloc_closure6(size_t size, BValue* data, BClosure6 fn) { Closure6Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -3060,14 +3189,25 @@ BValue alloc_closure6(size_t size, BValue* data, BClosure6 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn6(BPureFn6 fn) { + BoxedPureFn6* rc = (BoxedPureFn6*)malloc(sizeof(BoxedPureFn6)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn6(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5) { - if (IS_PURE_VALUE(fn)) { - BPureFn6 pfn = (BPureFn6)TO_POINTER(fn); - return pfn(arg0, arg1, arg2, arg3, arg4, arg5); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn6* purefn = (BoxedPureFn6*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1, arg2, arg3, arg4, arg5); } else { // this must be a closure: - Closure6Data* rc = (Closure6Data*)fn; + Closure6Data* rc = (Closure6Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1, arg2, arg3, arg4, arg5); } @@ -3075,10 +3215,12 @@ BValue call_fn6(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, B DEFINE_RC_STRUCT(Closure7Data, BClosure7 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn7, BPureFn7 fn; size_t slot_len;); BValue alloc_closure7(size_t size, BValue* data, BClosure7 fn) { Closure7Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -3089,14 +3231,25 @@ BValue alloc_closure7(size_t size, BValue* data, BClosure7 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn7(BPureFn7 fn) { + BoxedPureFn7* rc = (BoxedPureFn7*)malloc(sizeof(BoxedPureFn7)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn7(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6) { - if (IS_PURE_VALUE(fn)) { - BPureFn7 pfn = (BPureFn7)TO_POINTER(fn); - return pfn(arg0, arg1, arg2, arg3, arg4, arg5, arg6); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn7* purefn = (BoxedPureFn7*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1, arg2, arg3, arg4, arg5, arg6); } else { // this must be a closure: - Closure7Data* rc = (Closure7Data*)fn; + Closure7Data* rc = (Closure7Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1, arg2, arg3, arg4, arg5, arg6); } @@ -3104,10 +3257,12 @@ BValue call_fn7(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, B DEFINE_RC_STRUCT(Closure8Data, BClosure8 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn8, BPureFn8 fn; size_t slot_len;); BValue alloc_closure8(size_t size, BValue* data, BClosure8 fn) { Closure8Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -3118,14 +3273,25 @@ BValue alloc_closure8(size_t size, BValue* data, BClosure8 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn8(BPureFn8 fn) { + BoxedPureFn8* rc = (BoxedPureFn8*)malloc(sizeof(BoxedPureFn8)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn8(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7) { - if (IS_PURE_VALUE(fn)) { - BPureFn8 pfn = (BPureFn8)TO_POINTER(fn); - return pfn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn8* purefn = (BoxedPureFn8*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7); } else { // this must be a closure: - Closure8Data* rc = (Closure8Data*)fn; + Closure8Data* rc = (Closure8Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7); } @@ -3133,10 +3299,12 @@ BValue call_fn8(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, B DEFINE_RC_STRUCT(Closure9Data, BClosure9 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn9, BPureFn9 fn; size_t slot_len;); BValue alloc_closure9(size_t size, BValue* data, BClosure9 fn) { Closure9Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -3147,14 +3315,25 @@ BValue alloc_closure9(size_t size, BValue* data, BClosure9 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn9(BPureFn9 fn) { + BoxedPureFn9* rc = (BoxedPureFn9*)malloc(sizeof(BoxedPureFn9)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn9(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8) { - if (IS_PURE_VALUE(fn)) { - BPureFn9 pfn = (BPureFn9)TO_POINTER(fn); - return pfn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn9* purefn = (BoxedPureFn9*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); } else { // this must be a closure: - Closure9Data* rc = (Closure9Data*)fn; + Closure9Data* rc = (Closure9Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); } @@ -3162,10 +3341,12 @@ BValue call_fn9(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, B DEFINE_RC_STRUCT(Closure10Data, BClosure10 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn10, BPureFn10 fn; size_t slot_len;); BValue alloc_closure10(size_t size, BValue* data, BClosure10 fn) { Closure10Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -3176,14 +3357,25 @@ BValue alloc_closure10(size_t size, BValue* data, BClosure10 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn10(BPureFn10 fn) { + BoxedPureFn10* rc = (BoxedPureFn10*)malloc(sizeof(BoxedPureFn10)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn10(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9) { - if (IS_PURE_VALUE(fn)) { - BPureFn10 pfn = (BPureFn10)TO_POINTER(fn); - return pfn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn10* purefn = (BoxedPureFn10*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); } else { // this must be a closure: - Closure10Data* rc = (Closure10Data*)fn; + Closure10Data* rc = (Closure10Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9); } @@ -3191,10 +3383,12 @@ BValue call_fn10(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, DEFINE_RC_STRUCT(Closure11Data, BClosure11 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn11, BPureFn11 fn; size_t slot_len;); BValue alloc_closure11(size_t size, BValue* data, BClosure11 fn) { Closure11Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -3205,14 +3399,25 @@ BValue alloc_closure11(size_t size, BValue* data, BClosure11 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn11(BPureFn11 fn) { + BoxedPureFn11* rc = (BoxedPureFn11*)malloc(sizeof(BoxedPureFn11)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn11(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10) { - if (IS_PURE_VALUE(fn)) { - BPureFn11 pfn = (BPureFn11)TO_POINTER(fn); - return pfn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn11* purefn = (BoxedPureFn11*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); } else { // this must be a closure: - Closure11Data* rc = (Closure11Data*)fn; + Closure11Data* rc = (Closure11Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); } @@ -3220,10 +3425,12 @@ BValue call_fn11(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, DEFINE_RC_STRUCT(Closure12Data, BClosure12 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn12, BPureFn12 fn; size_t slot_len;); BValue alloc_closure12(size_t size, BValue* data, BClosure12 fn) { Closure12Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -3234,14 +3441,25 @@ BValue alloc_closure12(size_t size, BValue* data, BClosure12 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn12(BPureFn12 fn) { + BoxedPureFn12* rc = (BoxedPureFn12*)malloc(sizeof(BoxedPureFn12)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn12(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11) { - if (IS_PURE_VALUE(fn)) { - BPureFn12 pfn = (BPureFn12)TO_POINTER(fn); - return pfn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn12* purefn = (BoxedPureFn12*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11); } else { // this must be a closure: - Closure12Data* rc = (Closure12Data*)fn; + Closure12Data* rc = (Closure12Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11); } @@ -3249,10 +3467,12 @@ BValue call_fn12(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, DEFINE_RC_STRUCT(Closure13Data, BClosure13 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn13, BPureFn13 fn; size_t slot_len;); BValue alloc_closure13(size_t size, BValue* data, BClosure13 fn) { Closure13Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -3263,14 +3483,25 @@ BValue alloc_closure13(size_t size, BValue* data, BClosure13 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn13(BPureFn13 fn) { + BoxedPureFn13* rc = (BoxedPureFn13*)malloc(sizeof(BoxedPureFn13)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn13(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12) { - if (IS_PURE_VALUE(fn)) { - BPureFn13 pfn = (BPureFn13)TO_POINTER(fn); - return pfn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn13* purefn = (BoxedPureFn13*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); } else { // this must be a closure: - Closure13Data* rc = (Closure13Data*)fn; + Closure13Data* rc = (Closure13Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12); } @@ -3278,10 +3509,12 @@ BValue call_fn13(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, DEFINE_RC_STRUCT(Closure14Data, BClosure14 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn14, BPureFn14 fn; size_t slot_len;); BValue alloc_closure14(size_t size, BValue* data, BClosure14 fn) { Closure14Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -3292,14 +3525,25 @@ BValue alloc_closure14(size_t size, BValue* data, BClosure14 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn14(BPureFn14 fn) { + BoxedPureFn14* rc = (BoxedPureFn14*)malloc(sizeof(BoxedPureFn14)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn14(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13) { - if (IS_PURE_VALUE(fn)) { - BPureFn14 pfn = (BPureFn14)TO_POINTER(fn); - return pfn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn14* purefn = (BoxedPureFn14*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13); } else { // this must be a closure: - Closure14Data* rc = (Closure14Data*)fn; + Closure14Data* rc = (Closure14Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13); } @@ -3307,10 +3551,12 @@ BValue call_fn14(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, DEFINE_RC_STRUCT(Closure15Data, BClosure15 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn15, BPureFn15 fn; size_t slot_len;); BValue alloc_closure15(size_t size, BValue* data, BClosure15 fn) { Closure15Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -3321,14 +3567,25 @@ BValue alloc_closure15(size_t size, BValue* data, BClosure15 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn15(BPureFn15 fn) { + BoxedPureFn15* rc = (BoxedPureFn15*)malloc(sizeof(BoxedPureFn15)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn15(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14) { - if (IS_PURE_VALUE(fn)) { - BPureFn15 pfn = (BPureFn15)TO_POINTER(fn); - return pfn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn15* purefn = (BoxedPureFn15*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14); } else { // this must be a closure: - Closure15Data* rc = (Closure15Data*)fn; + Closure15Data* rc = (Closure15Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14); } @@ -3336,10 +3593,12 @@ BValue call_fn15(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, DEFINE_RC_STRUCT(Closure16Data, BClosure16 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn16, BPureFn16 fn; size_t slot_len;); BValue alloc_closure16(size_t size, BValue* data, BClosure16 fn) { Closure16Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -3350,14 +3609,25 @@ BValue alloc_closure16(size_t size, BValue* data, BClosure16 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn16(BPureFn16 fn) { + BoxedPureFn16* rc = (BoxedPureFn16*)malloc(sizeof(BoxedPureFn16)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn16(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15) { - if (IS_PURE_VALUE(fn)) { - BPureFn16 pfn = (BPureFn16)TO_POINTER(fn); - return pfn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn16* purefn = (BoxedPureFn16*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15); } else { // this must be a closure: - Closure16Data* rc = (Closure16Data*)fn; + Closure16Data* rc = (Closure16Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15); } @@ -3365,10 +3635,12 @@ BValue call_fn16(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, DEFINE_RC_STRUCT(Closure17Data, BClosure17 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn17, BPureFn17 fn; size_t slot_len;); BValue alloc_closure17(size_t size, BValue* data, BClosure17 fn) { Closure17Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -3379,14 +3651,25 @@ BValue alloc_closure17(size_t size, BValue* data, BClosure17 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn17(BPureFn17 fn) { + BoxedPureFn17* rc = (BoxedPureFn17*)malloc(sizeof(BoxedPureFn17)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn17(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16) { - if (IS_PURE_VALUE(fn)) { - BPureFn17 pfn = (BPureFn17)TO_POINTER(fn); - return pfn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn17* purefn = (BoxedPureFn17*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16); } else { // this must be a closure: - Closure17Data* rc = (Closure17Data*)fn; + Closure17Data* rc = (Closure17Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16); } @@ -3394,10 +3677,12 @@ BValue call_fn17(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, DEFINE_RC_STRUCT(Closure18Data, BClosure18 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn18, BPureFn18 fn; size_t slot_len;); BValue alloc_closure18(size_t size, BValue* data, BClosure18 fn) { Closure18Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -3408,14 +3693,25 @@ BValue alloc_closure18(size_t size, BValue* data, BClosure18 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn18(BPureFn18 fn) { + BoxedPureFn18* rc = (BoxedPureFn18*)malloc(sizeof(BoxedPureFn18)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn18(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16, BValue arg17) { - if (IS_PURE_VALUE(fn)) { - BPureFn18 pfn = (BPureFn18)TO_POINTER(fn); - return pfn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn18* purefn = (BoxedPureFn18*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17); } else { // this must be a closure: - Closure18Data* rc = (Closure18Data*)fn; + Closure18Data* rc = (Closure18Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17); } @@ -3423,10 +3719,12 @@ BValue call_fn18(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, DEFINE_RC_STRUCT(Closure19Data, BClosure19 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn19, BPureFn19 fn; size_t slot_len;); BValue alloc_closure19(size_t size, BValue* data, BClosure19 fn) { Closure19Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -3437,14 +3735,25 @@ BValue alloc_closure19(size_t size, BValue* data, BClosure19 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn19(BPureFn19 fn) { + BoxedPureFn19* rc = (BoxedPureFn19*)malloc(sizeof(BoxedPureFn19)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn19(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16, BValue arg17, BValue arg18) { - if (IS_PURE_VALUE(fn)) { - BPureFn19 pfn = (BPureFn19)TO_POINTER(fn); - return pfn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn19* purefn = (BoxedPureFn19*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18); } else { // this must be a closure: - Closure19Data* rc = (Closure19Data*)fn; + Closure19Data* rc = (Closure19Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18); } @@ -3452,10 +3761,12 @@ BValue call_fn19(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, DEFINE_RC_STRUCT(Closure20Data, BClosure20 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn20, BPureFn20 fn; size_t slot_len;); BValue alloc_closure20(size_t size, BValue* data, BClosure20 fn) { Closure20Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -3466,14 +3777,25 @@ BValue alloc_closure20(size_t size, BValue* data, BClosure20 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn20(BPureFn20 fn) { + BoxedPureFn20* rc = (BoxedPureFn20*)malloc(sizeof(BoxedPureFn20)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn20(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16, BValue arg17, BValue arg18, BValue arg19) { - if (IS_PURE_VALUE(fn)) { - BPureFn20 pfn = (BPureFn20)TO_POINTER(fn); - return pfn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn20* purefn = (BoxedPureFn20*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19); } else { // this must be a closure: - Closure20Data* rc = (Closure20Data*)fn; + Closure20Data* rc = (Closure20Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19); } @@ -3481,10 +3803,12 @@ BValue call_fn20(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, DEFINE_RC_STRUCT(Closure21Data, BClosure21 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn21, BPureFn21 fn; size_t slot_len;); BValue alloc_closure21(size_t size, BValue* data, BClosure21 fn) { Closure21Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -3495,14 +3819,25 @@ BValue alloc_closure21(size_t size, BValue* data, BClosure21 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn21(BPureFn21 fn) { + BoxedPureFn21* rc = (BoxedPureFn21*)malloc(sizeof(BoxedPureFn21)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn21(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16, BValue arg17, BValue arg18, BValue arg19, BValue arg20) { - if (IS_PURE_VALUE(fn)) { - BPureFn21 pfn = (BPureFn21)TO_POINTER(fn); - return pfn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn21* purefn = (BoxedPureFn21*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20); } else { // this must be a closure: - Closure21Data* rc = (Closure21Data*)fn; + Closure21Data* rc = (Closure21Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20); } @@ -3510,10 +3845,12 @@ BValue call_fn21(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, DEFINE_RC_STRUCT(Closure22Data, BClosure22 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn22, BPureFn22 fn; size_t slot_len;); BValue alloc_closure22(size_t size, BValue* data, BClosure22 fn) { Closure22Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -3524,14 +3861,25 @@ BValue alloc_closure22(size_t size, BValue* data, BClosure22 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn22(BPureFn22 fn) { + BoxedPureFn22* rc = (BoxedPureFn22*)malloc(sizeof(BoxedPureFn22)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn22(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16, BValue arg17, BValue arg18, BValue arg19, BValue arg20, BValue arg21) { - if (IS_PURE_VALUE(fn)) { - BPureFn22 pfn = (BPureFn22)TO_POINTER(fn); - return pfn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn22* purefn = (BoxedPureFn22*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21); } else { // this must be a closure: - Closure22Data* rc = (Closure22Data*)fn; + Closure22Data* rc = (Closure22Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21); } @@ -3539,10 +3887,12 @@ BValue call_fn22(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, DEFINE_RC_STRUCT(Closure23Data, BClosure23 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn23, BPureFn23 fn; size_t slot_len;); BValue alloc_closure23(size_t size, BValue* data, BClosure23 fn) { Closure23Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -3553,14 +3903,25 @@ BValue alloc_closure23(size_t size, BValue* data, BClosure23 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn23(BPureFn23 fn) { + BoxedPureFn23* rc = (BoxedPureFn23*)malloc(sizeof(BoxedPureFn23)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn23(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16, BValue arg17, BValue arg18, BValue arg19, BValue arg20, BValue arg21, BValue arg22) { - if (IS_PURE_VALUE(fn)) { - BPureFn23 pfn = (BPureFn23)TO_POINTER(fn); - return pfn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn23* purefn = (BoxedPureFn23*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22); } else { // this must be a closure: - Closure23Data* rc = (Closure23Data*)fn; + Closure23Data* rc = (Closure23Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22); } @@ -3568,10 +3929,12 @@ BValue call_fn23(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, DEFINE_RC_STRUCT(Closure24Data, BClosure24 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn24, BPureFn24 fn; size_t slot_len;); BValue alloc_closure24(size_t size, BValue* data, BClosure24 fn) { Closure24Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -3582,14 +3945,25 @@ BValue alloc_closure24(size_t size, BValue* data, BClosure24 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn24(BPureFn24 fn) { + BoxedPureFn24* rc = (BoxedPureFn24*)malloc(sizeof(BoxedPureFn24)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn24(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16, BValue arg17, BValue arg18, BValue arg19, BValue arg20, BValue arg21, BValue arg22, BValue arg23) { - if (IS_PURE_VALUE(fn)) { - BPureFn24 pfn = (BPureFn24)TO_POINTER(fn); - return pfn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn24* purefn = (BoxedPureFn24*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23); } else { // this must be a closure: - Closure24Data* rc = (Closure24Data*)fn; + Closure24Data* rc = (Closure24Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23); } @@ -3597,10 +3971,12 @@ BValue call_fn24(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, DEFINE_RC_STRUCT(Closure25Data, BClosure25 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn25, BPureFn25 fn; size_t slot_len;); BValue alloc_closure25(size_t size, BValue* data, BClosure25 fn) { Closure25Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -3611,14 +3987,25 @@ BValue alloc_closure25(size_t size, BValue* data, BClosure25 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn25(BPureFn25 fn) { + BoxedPureFn25* rc = (BoxedPureFn25*)malloc(sizeof(BoxedPureFn25)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn25(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16, BValue arg17, BValue arg18, BValue arg19, BValue arg20, BValue arg21, BValue arg22, BValue arg23, BValue arg24) { - if (IS_PURE_VALUE(fn)) { - BPureFn25 pfn = (BPureFn25)TO_POINTER(fn); - return pfn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn25* purefn = (BoxedPureFn25*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24); } else { // this must be a closure: - Closure25Data* rc = (Closure25Data*)fn; + Closure25Data* rc = (Closure25Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24); } @@ -3626,10 +4013,12 @@ BValue call_fn25(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, DEFINE_RC_STRUCT(Closure26Data, BClosure26 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn26, BPureFn26 fn; size_t slot_len;); BValue alloc_closure26(size_t size, BValue* data, BClosure26 fn) { Closure26Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -3640,14 +4029,25 @@ BValue alloc_closure26(size_t size, BValue* data, BClosure26 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn26(BPureFn26 fn) { + BoxedPureFn26* rc = (BoxedPureFn26*)malloc(sizeof(BoxedPureFn26)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn26(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16, BValue arg17, BValue arg18, BValue arg19, BValue arg20, BValue arg21, BValue arg22, BValue arg23, BValue arg24, BValue arg25) { - if (IS_PURE_VALUE(fn)) { - BPureFn26 pfn = (BPureFn26)TO_POINTER(fn); - return pfn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn26* purefn = (BoxedPureFn26*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25); } else { // this must be a closure: - Closure26Data* rc = (Closure26Data*)fn; + Closure26Data* rc = (Closure26Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25); } @@ -3655,10 +4055,12 @@ BValue call_fn26(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, DEFINE_RC_STRUCT(Closure27Data, BClosure27 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn27, BPureFn27 fn; size_t slot_len;); BValue alloc_closure27(size_t size, BValue* data, BClosure27 fn) { Closure27Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -3669,14 +4071,25 @@ BValue alloc_closure27(size_t size, BValue* data, BClosure27 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn27(BPureFn27 fn) { + BoxedPureFn27* rc = (BoxedPureFn27*)malloc(sizeof(BoxedPureFn27)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn27(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16, BValue arg17, BValue arg18, BValue arg19, BValue arg20, BValue arg21, BValue arg22, BValue arg23, BValue arg24, BValue arg25, BValue arg26) { - if (IS_PURE_VALUE(fn)) { - BPureFn27 pfn = (BPureFn27)TO_POINTER(fn); - return pfn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn27* purefn = (BoxedPureFn27*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26); } else { // this must be a closure: - Closure27Data* rc = (Closure27Data*)fn; + Closure27Data* rc = (Closure27Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26); } @@ -3684,10 +4097,12 @@ BValue call_fn27(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, DEFINE_RC_STRUCT(Closure28Data, BClosure28 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn28, BPureFn28 fn; size_t slot_len;); BValue alloc_closure28(size_t size, BValue* data, BClosure28 fn) { Closure28Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -3698,14 +4113,25 @@ BValue alloc_closure28(size_t size, BValue* data, BClosure28 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn28(BPureFn28 fn) { + BoxedPureFn28* rc = (BoxedPureFn28*)malloc(sizeof(BoxedPureFn28)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn28(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16, BValue arg17, BValue arg18, BValue arg19, BValue arg20, BValue arg21, BValue arg22, BValue arg23, BValue arg24, BValue arg25, BValue arg26, BValue arg27) { - if (IS_PURE_VALUE(fn)) { - BPureFn28 pfn = (BPureFn28)TO_POINTER(fn); - return pfn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn28* purefn = (BoxedPureFn28*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27); } else { // this must be a closure: - Closure28Data* rc = (Closure28Data*)fn; + Closure28Data* rc = (Closure28Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27); } @@ -3713,10 +4139,12 @@ BValue call_fn28(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, DEFINE_RC_STRUCT(Closure29Data, BClosure29 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn29, BPureFn29 fn; size_t slot_len;); BValue alloc_closure29(size_t size, BValue* data, BClosure29 fn) { Closure29Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -3727,14 +4155,25 @@ BValue alloc_closure29(size_t size, BValue* data, BClosure29 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn29(BPureFn29 fn) { + BoxedPureFn29* rc = (BoxedPureFn29*)malloc(sizeof(BoxedPureFn29)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn29(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16, BValue arg17, BValue arg18, BValue arg19, BValue arg20, BValue arg21, BValue arg22, BValue arg23, BValue arg24, BValue arg25, BValue arg26, BValue arg27, BValue arg28) { - if (IS_PURE_VALUE(fn)) { - BPureFn29 pfn = (BPureFn29)TO_POINTER(fn); - return pfn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn29* purefn = (BoxedPureFn29*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28); } else { // this must be a closure: - Closure29Data* rc = (Closure29Data*)fn; + Closure29Data* rc = (Closure29Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28); } @@ -3742,10 +4181,12 @@ BValue call_fn29(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, DEFINE_RC_STRUCT(Closure30Data, BClosure30 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn30, BPureFn30 fn; size_t slot_len;); BValue alloc_closure30(size_t size, BValue* data, BClosure30 fn) { Closure30Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -3756,14 +4197,25 @@ BValue alloc_closure30(size_t size, BValue* data, BClosure30 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn30(BPureFn30 fn) { + BoxedPureFn30* rc = (BoxedPureFn30*)malloc(sizeof(BoxedPureFn30)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn30(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16, BValue arg17, BValue arg18, BValue arg19, BValue arg20, BValue arg21, BValue arg22, BValue arg23, BValue arg24, BValue arg25, BValue arg26, BValue arg27, BValue arg28, BValue arg29) { - if (IS_PURE_VALUE(fn)) { - BPureFn30 pfn = (BPureFn30)TO_POINTER(fn); - return pfn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn30* purefn = (BoxedPureFn30*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29); } else { // this must be a closure: - Closure30Data* rc = (Closure30Data*)fn; + Closure30Data* rc = (Closure30Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29); } @@ -3771,10 +4223,12 @@ BValue call_fn30(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, DEFINE_RC_STRUCT(Closure31Data, BClosure31 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn31, BPureFn31 fn; size_t slot_len;); BValue alloc_closure31(size_t size, BValue* data, BClosure31 fn) { Closure31Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -3785,14 +4239,25 @@ BValue alloc_closure31(size_t size, BValue* data, BClosure31 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn31(BPureFn31 fn) { + BoxedPureFn31* rc = (BoxedPureFn31*)malloc(sizeof(BoxedPureFn31)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn31(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16, BValue arg17, BValue arg18, BValue arg19, BValue arg20, BValue arg21, BValue arg22, BValue arg23, BValue arg24, BValue arg25, BValue arg26, BValue arg27, BValue arg28, BValue arg29, BValue arg30) { - if (IS_PURE_VALUE(fn)) { - BPureFn31 pfn = (BPureFn31)TO_POINTER(fn); - return pfn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn31* purefn = (BoxedPureFn31*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30); } else { // this must be a closure: - Closure31Data* rc = (Closure31Data*)fn; + Closure31Data* rc = (Closure31Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30); } @@ -3800,10 +4265,12 @@ BValue call_fn31(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, DEFINE_RC_STRUCT(Closure32Data, BClosure32 fn; size_t slot_len;); +DEFINE_RC_STRUCT(BoxedPureFn32, BPureFn32 fn; size_t slot_len;); BValue alloc_closure32(size_t size, BValue* data, BClosure32 fn) { Closure32Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -3814,14 +4281,25 @@ BValue alloc_closure32(size_t size, BValue* data, BClosure32 fn) { return (BValue)rc; } +BValue alloc_boxed_pure_fn32(BPureFn32 fn) { + BoxedPureFn32* rc = (BoxedPureFn32*)malloc(sizeof(BoxedPureFn32)); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +} + BValue call_fn32(BValue fn, BValue arg0, BValue arg1, BValue arg2, BValue arg3, BValue arg4, BValue arg5, BValue arg6, BValue arg7, BValue arg8, BValue arg9, BValue arg10, BValue arg11, BValue arg12, BValue arg13, BValue arg14, BValue arg15, BValue arg16, BValue arg17, BValue arg18, BValue arg19, BValue arg20, BValue arg21, BValue arg22, BValue arg23, BValue arg24, BValue arg25, BValue arg26, BValue arg27, BValue arg28, BValue arg29, BValue arg30, BValue arg31) { - if (IS_PURE_VALUE(fn)) { - BPureFn32 pfn = (BPureFn32)TO_POINTER(fn); - return pfn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn32* purefn = (BoxedPureFn32*)ptr; + if (purefn->slot_len == 0) { + return purefn->fn(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31); } else { // this must be a closure: - Closure32Data* rc = (Closure32Data*)fn; + Closure32Data* rc = (Closure32Data*)ptr; BValue* data = closure_data_of((Closure1Data*)rc); return rc->fn(data, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31); } diff --git a/c_runtime/bosatsu_runtime.c b/c_runtime/bosatsu_runtime.c index c4b2d05ba..e860888b5 100644 --- a/c_runtime/bosatsu_runtime.c +++ b/c_runtime/bosatsu_runtime.c @@ -4,6 +4,7 @@ #include #include #include +#include #define DEFINE_RC_ENUM(name, fields) DEFINE_RC_STRUCT(name, ENUM_TAG tag; fields) @@ -36,7 +37,6 @@ void free_closure(Closure1Data* s) { DEFINE_RC_ENUM(Enum0,); DEFINE_RC_STRUCT(External, void* external; FreeFn ex_free;); - DEFINE_RC_STRUCT(BSTS_String, size_t len; char* bytes;); DEFINE_RC_STRUCT(BSTS_Integer, size_t len; _Bool sign; uint32_t* words;); @@ -98,9 +98,9 @@ void init_statics() { } BValue get_struct_index(BValue v, int idx) { - uintptr_t rc = (uintptr_t)v; - BValue* ptr = (BValue*)(rc + sizeof(RefCounted)); - return ptr[idx]; + uintptr_t rc = TO_POINTER(v); + BValue* ptr = (BValue*)(rc + sizeof(RefCounted) + idx * sizeof(BValue)); + return *ptr; } ENUM_TAG get_variant(BValue v) { @@ -115,12 +115,12 @@ ENUM_TAG get_variant(BValue v) { BValue get_enum_index(BValue v, int idx) { uintptr_t rc = TO_POINTER(v); - BValue* ptr = (BValue*)(rc + sizeof(Enum0)); - return ptr[idx]; + BValue* ptr = (BValue*)(rc + sizeof(Enum0) + idx * sizeof(BValue)); + return *ptr; } BValue alloc_enum0(ENUM_TAG tag) { - return (BValue)(((uintptr_t)tag << 1) | PURE_VALUE_TAG); + return TO_PURE_VALUE(tag); } // Externals: @@ -130,7 +130,8 @@ void free_external(External* ex) { } void bsts_init_rc(RefCounted* rc, FreeFn free) { - atomic_init(&rc->ref_count, 1); + // this is safe to do because before initialization there can't be race on allocated values + rc->ref_count = 1; rc->free = free; } @@ -226,13 +227,15 @@ int bsts_string_code_point_to_utf8(int code_point, char* output) { return -1; } +#define GET_STRING(v) (BSTS_String*)(TO_POINTER(v)) + _Bool bsts_string_equals(BValue left, BValue right) { if (left == right) { return 1; } - BSTS_String* lstr = (BSTS_String*)left; - BSTS_String* rstr = (BSTS_String*)right; + BSTS_String* lstr = GET_STRING(left); + BSTS_String* rstr = GET_STRING(right); size_t llen = lstr->len; if (llen == rstr->len) { @@ -251,8 +254,8 @@ int bsts_string_cmp(BValue left, BValue right) { return 0; } - BSTS_String* lstr = (BSTS_String*)left; - BSTS_String* rstr = (BSTS_String*)right; + BSTS_String* lstr = GET_STRING(left); + BSTS_String* rstr = GET_STRING(right); size_t llen = lstr->len; size_t rlen = rstr->len; @@ -268,12 +271,12 @@ int bsts_string_cmp(BValue left, BValue right) { } size_t bsts_string_utf8_len(BValue str) { - BSTS_String* strptr = (BSTS_String*)str; + BSTS_String* strptr = GET_STRING(str); return strptr->len; } char* bsts_string_utf8_bytes(BValue str) { - BSTS_String* strptr = (BSTS_String*)str; + BSTS_String* strptr = GET_STRING(str); return strptr->bytes; } @@ -284,7 +287,7 @@ char* bsts_string_utf8_bytes(BValue str) { * wasteful once we debug the compiler. */ int bsts_string_code_point_bytes(BValue value, int offset) { - BSTS_String* str = (BSTS_String*)value; + BSTS_String* str = GET_STRING(value); if (str == NULL || offset < 0 || offset >= str->len) { // Invalid input return -1; @@ -342,7 +345,7 @@ int bsts_string_code_point_bytes(BValue value, int offset) { * wasteful once we debug the compiler. */ BValue bsts_string_char_at(BValue value, int offset) { - BSTS_String* str = (BSTS_String*)value; + BSTS_String* str = GET_STRING(value); if (str == NULL || offset < 0 || offset >= str->len) { // Invalid input return 0; @@ -393,7 +396,7 @@ _Bool bsts_rc_value_is_unique(RefCounted* value) { // (&string, int, int) -> string BValue bsts_string_substring(BValue value, int start, int end) { - BSTS_String* str = (BSTS_String*)value; + BSTS_String* str = GET_STRING(value); size_t len = str->len; if (len < end || end <= start) { // this is invalid @@ -421,13 +424,13 @@ BValue bsts_string_substring(BValue value, int start, int end) { // this takes ownership since it can possibly reuse (if it is a static string, or count is 1) // (String, int) -> String BValue bsts_string_substring_tail(BValue value, int byte_offset) { - BSTS_String* str = (BSTS_String*)value; + BSTS_String* str = GET_STRING(value); return bsts_string_substring(str, byte_offset, str->len); } int bsts_string_find(BValue haystack, BValue needle, int start) { - BSTS_String* haystack_str = (BSTS_String*)haystack; - BSTS_String* needle_str = (BSTS_String*)needle; + BSTS_String* haystack_str = GET_STRING(haystack); + BSTS_String* needle_str = GET_STRING(needle); size_t haystack_len = haystack_str->len; size_t needle_len = needle_str->len; @@ -464,8 +467,8 @@ int bsts_string_find(BValue haystack, BValue needle, int start) { } int bsts_string_rfind(BValue haystack, BValue needle, int start) { - BSTS_String* haystack_str = (BSTS_String*)haystack; - BSTS_String* needle_str = (BSTS_String*)needle; + BSTS_String* haystack_str = GET_STRING(haystack); + BSTS_String* needle_str = GET_STRING(needle); size_t haystack_len = haystack_str->len; size_t needle_len = needle_str->len; @@ -504,15 +507,27 @@ int bsts_string_rfind(BValue haystack, BValue needle, int start) { return -1; } +void bsts_string_println(BValue v) { + char* bytes = bsts_string_utf8_bytes(v); + size_t len = bsts_string_utf8_len(v); + // TODO: if this string is somehow too big for an int this may fail + printf("%.*s\n", (int)len, bytes); +} + +void bsts_string_print(BValue v) { + char* bytes = bsts_string_utf8_bytes(v); + size_t len = bsts_string_utf8_len(v); + // TODO: if this string is somehow too big for an int this may fail + printf("%.*s", (int)len, bytes); +} + // Helper macros and functions -#define IS_SMALL(v) (((uintptr_t)(v)) & 1) -#define GET_SMALL_INT(v) ((intptr_t)((uintptr_t)(v) >> 1)) -#define GET_BIG_INT(v) ((BSTS_Integer*)(v)) - -BValue bsts_integer_from_int(int small_int) { - // chatgpt - uintptr_t value = (((uintptr_t)(intptr_t)small_int) << 1) | 1; - return (BValue)value; +#define IS_SMALL(v) IS_PURE_VALUE(v) +#define GET_SMALL_INT(v) (int32_t)(PURE_VALUE(v)) +#define GET_BIG_INT(v) ((BSTS_Integer*)(TO_POINTER(v))) + +BValue bsts_integer_from_int(int32_t small_int) { + return TO_PURE_VALUE(small_int); } void free_integer(void* integer) { @@ -546,15 +561,55 @@ BValue bsts_integer_from_words_copy(_Bool is_pos, size_t size, uint32_t* words) return (BValue)integer; // Low bit is 0 since it's a pointer } +BValue bsts_integer_from_words_owned(_Bool is_pos, size_t size, uint32_t* words) { + // chatgpt authored this + BSTS_Integer* integer = (BSTS_Integer*)malloc(sizeof(BSTS_Integer)); + if (integer == NULL) { + // Handle allocation failure + return NULL; + } + + integer->sign = !is_pos; // sign: 0 for positive, 1 for negative + // remove any leading 0 words + while ((size > 1) && (words[size - 1] == 0)) { + size--; + } + integer->len = size; + integer->words = words; + bsts_init_rc((RefCounted*)integer, free_integer); + return (BValue)integer; // Low bit is 0 since it's a pointer +} + +BValue bsts_maybe_small_int(_Bool sign, uint32_t small_result) { + if (sign) { + if (small_result <= 0x80000000) { + // this fits in int32_t + if (small_result == 0x80000000) { + return bsts_integer_from_int(INT32_MIN); + } + else { + return bsts_integer_from_int(-((int32_t)small_result)); + } + } + else { + // this can't fit in a small int + } + } + else if (small_result <= INT32_MAX) { + // it is a small positive + return bsts_integer_from_int(((int32_t)small_result)); + } + + return NULL; +} + + // Function to check equality between two BValues _Bool bsts_integer_equals(BValue left, BValue right) { if (left == right) { return 1; } - uintptr_t lval = (uintptr_t)left; - uintptr_t rval = (uintptr_t)right; - - _Bool l_is_small = lval & 1; - _Bool r_is_small = rval & 1; + _Bool l_is_small = IS_SMALL(left); + _Bool r_is_small = IS_SMALL(right); if (l_is_small && r_is_small) { // Both are small integers, but they aren't equal @@ -589,7 +644,7 @@ _Bool bsts_integer_equals(BValue left, BValue right) { } // Extract small integer value - intptr_t small_int_value = GET_SMALL_INT(left); + int32_t small_int_value = GET_SMALL_INT(left); BSTS_Integer* big_int = GET_BIG_INT(right); // Check sign @@ -598,28 +653,16 @@ _Bool bsts_integer_equals(BValue left, BValue right) { if (big_int_sign != small_int_sign) { return 0; // Different signs } - - // Compare absolute values - uintptr_t abs_small_int_value = (uintptr_t)(small_int_value < 0 ? -small_int_value : small_int_value); - - // Check if big_int can fit in uintptr_t - size_t bits_in_uintptr_t = sizeof(uintptr_t) * 8; - if (big_int->len * 32 > bits_in_uintptr_t) { - return 0; // big_int is too large - } - - // Reconstruct big integer value - uintptr_t big_int_value = 0; - for (size_t i = 0; i < big_int->len; ++i) { - big_int_value |= ((uintptr_t)big_int->words[i]) << (32 * i); + // they are both positive + if (big_int->len > 1) { + // the big int is bigger + return 0; } - - // Compare values - if (big_int_value != abs_small_int_value) { - return 0; + if (big_int->len == 0) { + return small_int_value == 0; } - - return 1; // Values are equal + // else len == 1 + return big_int->words[0] == (uint32_t)small_int_value; } } @@ -649,40 +692,29 @@ BValue bsts_integer_add(BValue l, BValue r) { // Case 1: Both are small integers if (l_is_small && r_is_small) { - intptr_t l_int = GET_SMALL_INT(l); - intptr_t r_int = GET_SMALL_INT(r); - intptr_t result = l_int + r_int; + int64_t l_int = (int64_t)GET_SMALL_INT(l); + int64_t r_int = (int64_t)GET_SMALL_INT(r); + int64_t result = l_int + r_int; + //printf("small add(%lld, %lld) == %lld", l_int, r_int, result); // Check for overflow - if ((result > (INTPTR_MAX >> 1)) || (result < (INTPTR_MIN >> 1))) { + if ((result < INT32_MIN) || (INT32_MAX < result)) { // Promote to big integer - _Bool is_positive = result >= 0; - uintptr_t abs_result = (uintptr_t)(result >= 0 ? result : -result); - - size_t word_count = 0; - uintptr_t temp = abs_result; - while (temp > 0) { - temp >>= 32; - word_count++; + _Bool pos = result >= 0; + int64_t abs_result = pos ? result : -result; + uint32_t low = (uint32_t)(abs_result & 0xFFFFFFFF); + uint32_t high = (uint32_t)((abs_result >> 32) & 0xFFFFFFFF); + if (high == 0) { + uint32_t words[1] = { low }; + return bsts_integer_from_words_copy(pos, 1, words); } - if (word_count == 0) { - return bsts_integer_from_int(0); - } - uint32_t* words = (uint32_t*)malloc(word_count * sizeof(uint32_t)); - if (words == NULL) { - return NULL; - } - temp = abs_result; - for (size_t i = 0; i < word_count; i++) { - words[i] = (uint32_t)(temp & 0xFFFFFFFF); - temp >>= 32; + else { + uint32_t words[2] = { low, high }; + return bsts_integer_from_words_copy(pos, 2, words); } - BValue big_result = bsts_integer_from_words_copy(is_positive, word_count, words); - free(words); - return big_result; } else { // Result fits in small integer - return bsts_integer_from_int((int)result); + return bsts_integer_from_int((int32_t)result); } } else { // At least one operand is a big integer @@ -692,75 +724,59 @@ BValue bsts_integer_add(BValue l, BValue r) { uint32_t* words; } Operand; + uint32_t left_temp[2]; + uint32_t right_temp[2]; Operand left_operand; Operand right_operand; - // Process left operand + // Prepare left operand if (l_is_small) { - intptr_t l_int = GET_SMALL_INT(l); + int32_t l_int = GET_SMALL_INT(l); left_operand.sign = l_int < 0; - uintptr_t abs_l_int = (uintptr_t)(l_int < 0 ? -l_int : l_int); - - size_t l_word_count = (abs_l_int == 0) ? 1 : 0; - uintptr_t temp = abs_l_int; - while (temp > 0) { - temp >>= 32; - l_word_count++; + left_operand.words = left_temp; + int64_t bigger = (int64_t)l_int; + int64_t abs_bigger = (bigger < 0 ? -bigger : bigger); + uint32_t low = (u_int32_t)(abs_bigger & 0xFFFFFFFF); + uint32_t high = (u_int32_t)((abs_bigger >> 32) & 0xFFFFFFFF); + if (high == 0) { + left_operand.words[0] = low; + left_operand.len = 1; } - left_operand.len = l_word_count; - left_operand.words = (uint32_t*)calloc(l_word_count, sizeof(uint32_t)); - if (left_operand.words == NULL) { - return NULL; - } - temp = abs_l_int; - for (size_t i = 0; i < l_word_count; i++) { - left_operand.words[i] = (uint32_t)(temp & 0xFFFFFFFF); - temp >>= 32; + else { + left_operand.words[0] = low; + left_operand.words[1] = high; + left_operand.len = 2; } } else { BSTS_Integer* l_big = GET_BIG_INT(l); left_operand.sign = l_big->sign; left_operand.len = l_big->len; - left_operand.words = (uint32_t*)malloc(l_big->len * sizeof(uint32_t)); - if (left_operand.words == NULL) { - return NULL; - } - memcpy(left_operand.words, l_big->words, l_big->len * sizeof(uint32_t)); + left_operand.words = l_big->words; } - // Process right operand + // Prepare left operand if (r_is_small) { - intptr_t r_int = GET_SMALL_INT(r); + int32_t r_int = GET_SMALL_INT(r); right_operand.sign = r_int < 0; - uintptr_t abs_r_int = (uintptr_t)(r_int < 0 ? -r_int : r_int); - - size_t r_word_count = (abs_r_int == 0) ? 1 : 0; - uintptr_t temp = abs_r_int; - while (temp > 0) { - temp >>= 32; - r_word_count++; + right_operand.words = right_temp; + int64_t bigger = (int64_t)r_int; + int64_t abs_bigger = (bigger < 0 ? -bigger : bigger); + uint32_t low = (u_int32_t)(abs_bigger & 0xFFFFFFFF); + uint32_t high = (u_int32_t)((abs_bigger >> 32) & 0xFFFFFFFF); + if (high == 0) { + right_operand.words[0] = low; + right_operand.len = 1; } - right_operand.len = r_word_count; - right_operand.words = (uint32_t*)calloc(r_word_count, sizeof(uint32_t)); - if (right_operand.words == NULL) { - free(left_operand.words); - return NULL; - } - temp = abs_r_int; - for (size_t i = 0; i < r_word_count; i++) { - right_operand.words[i] = (uint32_t)(temp & 0xFFFFFFFF); - temp >>= 32; + else { + right_operand.words[0] = low; + right_operand.words[1] = high; + right_operand.len = 2; } } else { BSTS_Integer* r_big = GET_BIG_INT(r); right_operand.sign = r_big->sign; right_operand.len = r_big->len; - right_operand.words = (uint32_t*)malloc(r_big->len * sizeof(uint32_t)); - if (right_operand.words == NULL) { - free(left_operand.words); - return NULL; - } - memcpy(right_operand.words, r_big->words, r_big->len * sizeof(uint32_t)); + right_operand.words = r_big->words; } BValue result = NULL; @@ -770,8 +786,6 @@ BValue bsts_integer_add(BValue l, BValue r) { size_t max_len = (left_operand.len > right_operand.len) ? left_operand.len : right_operand.len; uint32_t* result_words = (uint32_t*)calloc(max_len + 1, sizeof(uint32_t)); if (result_words == NULL) { - free(left_operand.words); - free(right_operand.words); return NULL; } @@ -796,15 +810,16 @@ BValue bsts_integer_add(BValue l, BValue r) { // Check for small integer representation if (result_len == 1) { - intptr_t small_int = (intptr_t)result_words[0]; - if (result_sign) { - small_int = -small_int; + BValue maybe_result = bsts_maybe_small_int(!result_sign, result_words[0]); + if (maybe_result) { + result = maybe_result; + free(result_words); + } + else { + result = bsts_integer_from_words_owned(!result_sign, result_len, result_words); } - result = bsts_integer_from_int((int)small_int); - free(result_words); } else { - result = bsts_integer_from_words_copy(!result_sign, result_len, result_words); - free(result_words); + result = bsts_integer_from_words_owned(!result_sign, result_len, result_words); } } else { // Subtraction @@ -828,8 +843,6 @@ BValue bsts_integer_add(BValue l, BValue r) { size_t result_len = larger->len; uint32_t* result_words = (uint32_t*)calloc(result_len, sizeof(uint32_t)); if (result_words == NULL) { - free(left_operand.words); - free(right_operand.words); return NULL; } @@ -854,22 +867,20 @@ BValue bsts_integer_add(BValue l, BValue r) { // Check for small integer representation if (result_len == 1) { - intptr_t small_int = (intptr_t)result_words[0]; - if (result_sign) { - small_int = -small_int; + BValue maybe_result = bsts_maybe_small_int(!result_sign, result_words[0]); + if (maybe_result) { + result = maybe_result; + free(result_words); + } + else { + result = bsts_integer_from_words_owned(!result_sign, result_len, result_words); } - result = bsts_integer_from_int((int)small_int); - free(result_words); } else { - result = bsts_integer_from_words_copy(!result_sign, result_len, result_words); - free(result_words); + result = bsts_integer_from_words_owned(!result_sign, result_len, result_words); } } } - free(left_operand.words); - free(right_operand.words); - return result; } } @@ -877,34 +888,12 @@ BValue bsts_integer_add(BValue l, BValue r) { // Function to negate a BValue BValue bsts_integer_negate(BValue v) { if (IS_SMALL(v)) { - intptr_t small_int = GET_SMALL_INT(v); - if (small_int != INTPTR_MIN) { - intptr_t negated_int = -small_int; - return bsts_integer_from_int((int)negated_int); + int32_t small = GET_SMALL_INT(v); + if (small != INT32_MIN) { + return bsts_integer_from_int(-small); } else { - // Handle INT_MIN, which cannot be negated in two's complement - uintmax_t abs_value = (uintmax_t)INTPTR_MAX + 1; // Absolute value of INTPTR_MIN - // Determine the number of 32-bit words needed - size_t num_words = 0; - uintmax_t temp = abs_value; - do { - temp >>= 32; - num_words++; - } while (temp != 0); - - uint32_t* words = (uint32_t*)malloc(num_words * sizeof(uint32_t)); - if (words == NULL) { - return NULL; - } - temp = abs_value; - for (size_t i = 0; i < num_words; ++i) { - words[i] = (uint32_t)(temp & 0xFFFFFFFF); - temp >>= 32; - } - // Create a big integer with positive sign - BValue result = bsts_integer_from_words_copy(1, num_words, words); - free(words); - return result; + uint32_t words[1] = { 0x80000000 }; + return bsts_integer_from_words_copy(1, 1, words); } } else { // Negate big integer @@ -971,11 +960,11 @@ uint32_t bigint_divide_by_10(uint32_t* words, size_t len, uint32_t* quotient_wor // &Integer -> String BValue bsts_integer_to_string(BValue v) { if (IS_SMALL(v)) { - intptr_t value = GET_SMALL_INT(v); + int value = GET_SMALL_INT(v); // Convert small integer to string char buffer[32]; // Enough for 64-bit integer - int length = snprintf(buffer, sizeof(buffer), "%ld", value); + int length = snprintf(buffer, sizeof(buffer), "%d", value); if (length < 0) { // snprintf error @@ -1318,36 +1307,27 @@ BValue bsts_integer_times(BValue left, BValue right) { if (left_is_small && right_is_small) { // Both are small integers - intptr_t l_int = GET_SMALL_INT(left); - intptr_t r_int = GET_SMALL_INT(right); + int32_t l_int = GET_SMALL_INT(left); + int32_t r_int = GET_SMALL_INT(right); // Multiply and check for overflow - __int128 result = (__int128)l_int * (__int128)r_int; + int64_t result = (int64_t)l_int * (int64_t)r_int; // Check if result fits in small integer - if (result >= (INTPTR_MIN >> 1) && result <= (INTPTR_MAX >> 1)) { - return bsts_integer_from_int((int)result); + if ((INT32_MIN <= result) && (result <= INT32_MAX)) { + return bsts_integer_from_int((int32_t)result); } else { // Promote to big integer _Bool is_positive = result >= 0; - __uint128_t abs_result = result >= 0 ? result : -result; - // Convert abs_result to words - size_t word_count = 0; - __uint128_t temp = abs_result; - while (temp > 0) { - temp >>= 32; - word_count++; + uint64_t abs_result = result >= 0 ? result : -result; + uint32_t low = (u_int32_t)(abs_result & 0xFFFFFFFF); + uint32_t high = (u_int32_t)((abs_result >> 32) & 0xFFFFFFFF); + if (high == 0) { + uint32_t words[1] = { low }; + return bsts_integer_from_words_copy(is_positive, 1, words); } - uint32_t* words = (uint32_t*)malloc(word_count * sizeof(uint32_t)); - if (words == NULL) { - return NULL; - } - temp = abs_result; - for (size_t i = 0; i < word_count; i++) { - words[i] = (uint32_t)(temp & 0xFFFFFFFF); - temp >>= 32; + else { + uint32_t words[2] = { low, high }; + return bsts_integer_from_words_copy(is_positive, 2, words); } - BValue big_result = bsts_integer_from_words_copy(is_positive, word_count, words); - free(words); - return big_result; } } else { // At least one operand is big integer @@ -1357,88 +1337,65 @@ BValue bsts_integer_times(BValue left, BValue right) { uint32_t* words; } Operand; + uint32_t left_temp[2]; + uint32_t right_temp[2]; Operand l_operand; Operand r_operand; // Prepare left operand if (left_is_small) { - intptr_t l_int = GET_SMALL_INT(left); + int32_t l_int = GET_SMALL_INT(left); l_operand.sign = l_int < 0; - uintptr_t abs_l_int = (uintptr_t)(l_int < 0 ? -l_int : l_int); - l_operand.len = 0; - uintptr_t temp = abs_l_int; - while (temp > 0) { - temp >>= 32; - l_operand.len++; - } - if (l_operand.len == 0) { - // Zero - return bsts_integer_from_int(0); - } - l_operand.words = (uint32_t*)malloc(l_operand.len * sizeof(uint32_t)); - if (l_operand.words == NULL) { - return NULL; + l_operand.words = left_temp; + int64_t bigger = (int64_t)l_int; + int64_t abs_bigger = (bigger < 0 ? -bigger : bigger); + uint32_t low = (u_int32_t)(abs_bigger & 0xFFFFFFFF); + uint32_t high = (u_int32_t)((abs_bigger >> 32) & 0xFFFFFFFF); + if (high == 0) { + l_operand.words[0] = low; + l_operand.len = 1; } - temp = abs_l_int; - for (size_t i = 0; i < l_operand.len; i++) { - l_operand.words[i] = (uint32_t)(temp & 0xFFFFFFFF); - temp >>= 32; + else { + l_operand.words[0] = low; + l_operand.words[1] = high; + l_operand.len = 2; } } else { BSTS_Integer* l_big = GET_BIG_INT(left); l_operand.sign = l_big->sign; l_operand.len = l_big->len; - l_operand.words = (uint32_t*)malloc(l_operand.len * sizeof(uint32_t)); - if (l_operand.words == NULL) { - return NULL; - } - memcpy(l_operand.words, l_big->words, l_big->len * sizeof(uint32_t)); + l_operand.words = l_big->words; } - // Prepare right operand + // Prepare left operand if (right_is_small) { - intptr_t r_int = GET_SMALL_INT(right); + int32_t r_int = GET_SMALL_INT(right); r_operand.sign = r_int < 0; - uintptr_t abs_r_int = (uintptr_t)(r_int < 0 ? -r_int : r_int); - r_operand.len = 0; - uintptr_t temp = abs_r_int; - while (temp > 0) { - temp >>= 32; - r_operand.len++; - } - if (r_operand.len == 0) { - // Zero - free(l_operand.words); - return bsts_integer_from_int(0); + r_operand.words = right_temp; + int64_t bigger = (int64_t)r_int; + int64_t abs_bigger = (bigger < 0 ? -bigger : bigger); + uint32_t low = (u_int32_t)(abs_bigger & 0xFFFFFFFF); + uint32_t high = (u_int32_t)((abs_bigger >> 32) & 0xFFFFFFFF); + if (high == 0) { + r_operand.words[0] = low; + r_operand.len = 1; } - r_operand.words = (uint32_t*)malloc(r_operand.len * sizeof(uint32_t)); - if (r_operand.words == NULL) { - free(l_operand.words); - return NULL; - } - temp = abs_r_int; - for (size_t i = 0; i < r_operand.len; i++) { - r_operand.words[i] = (uint32_t)(temp & 0xFFFFFFFF); - temp >>= 32; + else { + r_operand.words[0] = low; + r_operand.words[1] = high; + r_operand.len = 2; } } else { BSTS_Integer* r_big = GET_BIG_INT(right); r_operand.sign = r_big->sign; r_operand.len = r_big->len; - r_operand.words = (uint32_t*)malloc(r_operand.len * sizeof(uint32_t)); - if (r_operand.words == NULL) { - free(l_operand.words); - return NULL; - } - memcpy(r_operand.words, r_big->words, r_big->len * sizeof(uint32_t)); + r_operand.words = r_big->words; } // Multiply operands size_t result_len = l_operand.len + r_operand.len; uint32_t* result_words = (uint32_t*)calloc(result_len, sizeof(uint32_t)); if (result_words == NULL) { - free(l_operand.words); - free(r_operand.words); return NULL; } @@ -1455,7 +1412,7 @@ BValue bsts_integer_times(BValue left, BValue right) { } // Determine sign of result - _Bool result_sign = l_operand.sign != r_operand.sign; + _Bool result_sign = !(l_operand.sign == r_operand.sign); // Normalize result while (result_len > 1 && result_words[result_len - 1] == 0) { @@ -1464,21 +1421,15 @@ BValue bsts_integer_times(BValue left, BValue right) { // Check if result fits in small integer if (result_len == 1) { - intptr_t small_result = (intptr_t)result_words[0]; - if (result_sign) { - small_result = -small_result; + BValue maybe_res = bsts_maybe_small_int(!result_sign, result_words[0]); + if (maybe_res) { + free(result_words); + return maybe_res; } - free(result_words); - free(l_operand.words); - free(r_operand.words); - return bsts_integer_from_int((int)small_result); - } else { - BValue result = bsts_integer_from_words_copy(!result_sign, result_len, result_words); - free(result_words); - free(l_operand.words); - free(r_operand.words); - return result; } + // if we make it here we have to fit into big + BValue result = bsts_integer_from_words_owned(!result_sign, result_len, result_words); + return result; } } @@ -2016,4 +1967,104 @@ BValue read_or_build(_Atomic BValue* target, BConstruct cons) { } while (1); } return result; +} + +/* +typedef struct BSTS_Test_Result { + char* package_name; + int passes; + int fails; +} BSTS_Test_Result; + +enum Test: + Assertion(value: Bool, message: String) + TestSuite(name: String, tests: List[Test]) + + test_value() returns a Test +*/ +typedef struct BSTS_PassFail { + int passes; + int fails; +} BSTS_PassFail; + +void print_indent(int indent) { + for(int z = 0; z < indent; z++) { + printf(" "); + } +} + +BSTS_PassFail bsts_check_test(BValue v, int indent) { + int passes = 0; + int fails = 0; + if (get_variant(v) == 0) { + _Bool success = get_variant(get_enum_index(v, 0)); + if (!success) { + BValue message = get_enum_index(v, 1); + print_indent(indent); + // red failure + printf("\033[31mfailure: "); + bsts_string_println(message); + printf("\033[0m"); + ++fails; + } + else { + ++passes; + } + } + else { + // must be the (Suite, List[Test]) + BValue suite_name = get_enum_index(v, 0); + BValue suite_tests = get_enum_index(v, 1); + print_indent(indent); + bsts_string_print(suite_name); + printf(":\n"); + // loop through all the children + int next_indent = indent + 4; + int this_fails = 0; + int this_passes = 0; + while(get_variant(suite_tests) != 0) { + BValue t1 = get_enum_index(suite_tests, 0); + suite_tests = get_enum_index(suite_tests, 1); + BSTS_PassFail tests = bsts_check_test(t1, next_indent); + this_passes += tests.passes; + this_fails += tests.fails; + } + print_indent(next_indent); + printf("passed: \033[32m%i\033[0m, failed: \033[31m%i\033[0m\n", this_passes, this_fails); + passes += this_passes; + fails += this_fails; + } + + BSTS_PassFail res = { passes, fails }; + return res; +} + +BSTS_Test_Result bsts_test_run(char* package_name, BConstruct test_value) { + BValue res = test_value(); + printf("%s:\n", package_name); + BSTS_PassFail this_test = bsts_check_test(res, 4); + BSTS_Test_Result test_res = { package_name, this_test.passes, this_test.fails }; + return test_res; +} + +int bsts_test_result_print_summary(int count, BSTS_Test_Result* results) { + int total_fails = 0; + int total_passes = 0; + for (int i = 0; i < count; i++) { + total_fails += results[i].fails; + total_passes += results[i].passes; + } + + if (total_fails > 0) { + printf("\n\npackages with failures:\n"); + for (int i = 0; i < count; i++) { + if (results[i].fails > 0) { + printf("\t%s\n", results[i].package_name); + } + } + printf("\n"); + } + + printf("\npassed: \033[32m%i\033[0m, failed: \033[31m%i\033[0m\n", total_passes, total_fails); + return (total_fails > 0); } \ No newline at end of file diff --git a/c_runtime/bosatsu_runtime.h b/c_runtime/bosatsu_runtime.h index b1f02363b..95a80edb9 100644 --- a/c_runtime/bosatsu_runtime.h +++ b/c_runtime/bosatsu_runtime.h @@ -17,10 +17,9 @@ to distinguish these cases we allocate pointers such that they are aligned to at b. ends with 11: static pointer (allocated once and deleteds at the end of the world) c. ends with 00: refcount pointer. -when it comes to functions there are three types: - a. top level pure function: ends with 1 - b. static closure (something that closes over static things, ideally we would optimize this away): ends with 10 - c. refcounted closure: ends with 00 +when it comes to functions there are two types, PureFn and closures. We have to box + pointers to them, but when we know we have a global PureFn we can directly call it. + if we have a static boxed value, it ends in 1, else 0. Nat-like values are represented by positive integers encoded as PURE_VALUE such that NAT(x) = (x << 1) | 1, since we don't have enough time to increment through 2^{63} values @@ -44,12 +43,12 @@ how to clone values. #define POINTER_TAG 0x0 // Utility macros to check the tag of a value -#define IS_PURE_VALUE(ptr) (((uintptr_t)(ptr) & PURE_VALUE_TAG) == PURE_VALUE_TAG) -#define PURE_VALUE(ptr) ((uintptr_t)(ptr) >> 1) +#define IS_PURE_VALUE(ptr) (((uintptr_t)(ptr) & TAG_MASK) == PURE_VALUE_TAG) +#define TO_PURE_VALUE(v) ((BValue)((((uintptr_t)v) << 2) | PURE_VALUE_TAG)) +#define PURE_VALUE(ptr) ((uintptr_t)(ptr) >> 2) #define IS_STATIC_VALUE(ptr) (((uintptr_t)(ptr) & TAG_MASK) == STATIC_VALUE_TAG) #define IS_POINTER(ptr) (((uintptr_t)(ptr) & TAG_MASK) == POINTER_TAG) #define TO_POINTER(ptr) ((uintptr_t)(ptr) & ~TAG_MASK) -#define STATIC_PUREFN(ptr) (BValue*)((uintptr_t)(ptr) | PURE_VALUE_TAG) #define DEFINE_RC_STRUCT(name, fields) \ struct name { \ @@ -65,12 +64,12 @@ typedef uint32_t ENUM_TAG; // Nat values are encoded in integers #define BSTS_NAT_0 ((BValue)0x1) -#define BSTS_NAT_SUCC(n) ((BValue)((uintptr_t)(n) + 2)) -#define BSTS_NAT_PREV(n) ((BValue)((uintptr_t)(n) - 2)) +#define BSTS_NAT_SUCC(n) ((BValue)((uintptr_t)(n) + 4)) +#define BSTS_NAT_PREV(n) ((BValue)((uintptr_t)(n) - 4)) #define BSTS_NAT_IS_0(n) (((uintptr_t)(n)) == 0x1) #define BSTS_NAT_GT_0(n) (((uintptr_t)(n)) != 0x1) -#define BSTS_TO_CHAR(x) (BValue)((x << 1) | 1) +#define BSTS_TO_CHAR(x) TO_PURE_VALUE(x) // this is the free function to call on an external value typedef void (*FreeFn)(void*); @@ -132,8 +131,10 @@ int bsts_string_find(BValue haystack, BValue needle, int start); * (&string, string, int) -> int */ int bsts_string_rfind(BValue haystack, BValue needle, int start); +// &String -> Unit +void bsts_string_println(BValue v); -BValue bsts_integer_from_int(int small_int); +BValue bsts_integer_from_int(int32_t small_int); BValue bsts_integer_from_words_copy(_Bool is_pos, size_t size, uint32_t* words); _Bool bsts_integer_equals(BValue left, BValue right); // (&Integer, &Integer) -> Integer diff --git a/c_runtime/test.c b/c_runtime/test.c index 0a4c734b7..77597ff8e 100644 --- a/c_runtime/test.c +++ b/c_runtime/test.c @@ -16,6 +16,54 @@ void test_runtime_enum_struct() { release_value(s1); } +void test_integer() { + { + BValue s1 = bsts_integer_to_string(bsts_integer_from_int(0)); + BValue expects1 = bsts_string_from_utf8_bytes_static(1, "0"); + if (bsts_string_cmp(s1, expects1) != 0) { + printf("0 didn't match, got: "); + bsts_string_println(s1); + exit(1); + } + release_value(s1); + release_value(expects1); + } + + { + BValue s1 = bsts_integer_to_string(bsts_integer_from_int(-1)); + BValue expects1 = bsts_string_from_utf8_bytes_static(2, "-1"); + if (bsts_string_cmp(s1, expects1) != 0) { + printf("-1 didn't match, got: "); + bsts_string_println(s1); + exit(1); + } + release_value(s1); + release_value(expects1); + } + + { + + BValue s1 = bsts_integer_to_string(bsts_integer_from_int(123456)); + BValue expects1 = bsts_string_from_utf8_bytes_static(6, "123456"); + if (bsts_string_cmp(s1, expects1) != 0) { + printf("123456 didn't match, got: "); + bsts_string_println(s1); + exit(1); + } + release_value(s1); + release_value(expects1); + } + + { + BValue s0 = bsts_integer_from_int(0); + BValue s1 = bsts_integer_from_int(1); + BValue s2 = bsts_integer_from_int(2); + assert(bsts_integer_cmp(s1, s2) < 0, "1 < 2"); + assert(bsts_integer_cmp(s0, s2) < 0, "0 < 2"); + } + +} + void test_runtime_strings() { char* hello = "hello1"; @@ -64,6 +112,7 @@ int main(int argc, char** argv) { test_runtime_enum_struct(); test_runtime_strings(); + test_integer(); printf("success\n"); return 0; } \ No newline at end of file diff --git a/c_runtime/typegen.py b/c_runtime/typegen.py index b3f56ab52..978aa7604 100644 --- a/c_runtime/typegen.py +++ b/c_runtime/typegen.py @@ -1,3 +1,6 @@ +from typing import DefaultDict + + def just_bvalue(cnt): return ",".join(["BValue"] * cnt) @@ -7,11 +10,11 @@ def bvalue_arg(cnt): def fn_decls(size): """ BValue alloc_closure2(size_t size, BValue* data, BClosure2 fn); - BValue value_from_pure_fn2(BPureFn2 fn); + BValue alloc_boxed_pure_fn2(BPureFn2 fn); BValue call_fn2(BValue fn, BValue arg0, BValue arg1); """ alloc_c = "BValue alloc_closure{size}(size_t size, BValue* data, BClosure{size} fn);".format(size = size) - from_fn = "BValue value_from_pure_fn{size}(BPureFn{size} fn);".format(size = size) + from_fn = "BValue alloc_boxed_pure_fn{size}(BPureFn{size} fn);".format(size = size); call_fn = "BValue call_fn{size}(BValue fn, {args});".format(size = size, args = bvalue_arg(size)) return "\n".join([alloc_c, from_fn, call_fn]) @@ -24,7 +27,8 @@ def struct_impl(size): }} BValue alloc_struct{size}({arg_params}) {{ Struct{size}* rc = malloc(sizeof(Struct{size})); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_struct{size}; {assigns} return (BValue)rc; @@ -44,7 +48,8 @@ def enum_impl(size): }} BValue alloc_enum{size}(ENUM_TAG tag, {arg_params}) {{ Enum{size}* rc = malloc(sizeof(Enum{size})); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_enum{size}; rc->tag = tag; {assigns} @@ -57,13 +62,17 @@ def enum_impl(size): return template.format(size = size, arg_decls = arg_decls, arg_params = arg_params, releases = releases, assigns = assigns) def function_impl(size): - define = "" if size == 1 else "DEFINE_RC_STRUCT(Closure{size}Data, BClosure{size} fn; size_t slot_len;);".format(size = size) + define_c = "" if size == 1 else "DEFINE_RC_STRUCT(Closure{size}Data, BClosure{size} fn; size_t slot_len;);\n".format(size = size) + define_p = "DEFINE_RC_STRUCT(BoxedPureFn{size}, BPureFn{size} fn; size_t slot_len;);".format(size = size) + + define = define_c + define_p template = """ {define} BValue alloc_closure{size}(size_t size, BValue* data, BClosure{size} fn) {{ Closure{size}Data* rc = malloc(closure_data_size(size)); - atomic_init(&rc->ref_count, 1); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; rc->free = (FreeFn)free_closure; rc->fn = fn; rc->slot_len = size; @@ -74,14 +83,25 @@ def function_impl(size): return (BValue)rc; }} +BValue alloc_boxed_pure_fn{size}(BPureFn{size} fn) {{ + BoxedPureFn{size}* rc = (BoxedPureFn{size}*)malloc(sizeof(BoxedPureFn{size})); + // this is safe to do outside atomic because no other thread can see this yet + rc->ref_count = 1; + rc->free = free; + rc->fn = fn; + rc->slot_len = 0; + return (BValue)rc; +}} + BValue call_fn{size}(BValue fn, {arg_params}) {{ - if (IS_PURE_VALUE(fn)) {{ - BPureFn{size} pfn = (BPureFn{size})TO_POINTER(fn); - return pfn({just_args}); + BValue ptr = (BValue)TO_POINTER(fn); + BoxedPureFn{size}* purefn = (BoxedPureFn{size}*)ptr; + if (purefn->slot_len == 0) {{ + return purefn->fn({just_args}); }} else {{ // this must be a closure: - Closure{size}Data* rc = (Closure{size}Data*)fn; + Closure{size}Data* rc = (Closure{size}Data*)ptr; BValue* data = closure_data_of({cast_to_1}rc); return rc->fn(data, {just_args}); }} diff --git a/cli/src/test/scala/org/bykn/bosatsu/codegen/clang/ClangGenTest.scala b/cli/src/test/scala/org/bykn/bosatsu/codegen/clang/ClangGenTest.scala index 5029c692f..2906d6003 100644 --- a/cli/src/test/scala/org/bykn/bosatsu/codegen/clang/ClangGenTest.scala +++ b/cli/src/test/scala/org/bykn/bosatsu/codegen/clang/ClangGenTest.scala @@ -45,7 +45,7 @@ class ClangGenTest extends munit.FunSuite { To inspect the code, change the hash, and it will print the code out */ testFilesCompilesToHash("test_workspace/Ackermann.bosatsu")( - "9c6bd21af52f1eab1aeb33c357132ebe" + "9230e9e785b702777c0c019d86bc76eb" ) } } \ No newline at end of file diff --git a/core/src/main/scala/org/bykn/bosatsu/codegen/clang/ClangGen.scala b/core/src/main/scala/org/bykn/bosatsu/codegen/clang/ClangGen.scala index dd2d3197d..fc9e60f21 100644 --- a/core/src/main/scala/org/bykn/bosatsu/codegen/clang/ClangGen.scala +++ b/core/src/main/scala/org/bykn/bosatsu/codegen/clang/ClangGen.scala @@ -224,12 +224,12 @@ object ClangGen { def bindAnon[A](idx: Long)(in: T[A]): T[A] def getAnon(idx: Long): T[Code.Ident] // a recursive function needs to remap the Bindable to the top-level mangling - def recursiveName[A](fnName: Code.Ident, bn: Bindable, isClosure: Boolean)(in: T[A]): T[A] + def recursiveName[A](fnName: Code.Ident, bn: Bindable, isClosure: Boolean, arity: Int)(in: T[A]): T[A] // used for temporary variables of type BValue def newLocalName(tag: String): T[Code.Ident] def newTopName(tag: String): T[Code.Ident] - def directFn(p: PackageName, b: Bindable): T[Option[Code.Ident]] - def directFn(b: Bindable): T[Option[(Code.Ident, Boolean)]] + def directFn(p: PackageName, b: Bindable): T[Option[(Code.Ident, Int)]] + def directFn(b: Bindable): T[Option[(Code.Ident, Boolean, Int)]] def inTop[A](p: PackageName, bn: Bindable)(ta: T[A]): T[A] def currentTop: T[Option[(PackageName, Bindable)]] def staticValueName(p: PackageName, b: Bindable): T[Code.Ident] @@ -317,14 +317,28 @@ object ClangGen { def andCode(l: Code.ValueLike, r: Code.ValueLike): T[Code.ValueLike] = l match { + case Code.IntLiteral(lit) => + if (lit != 0) pv(r) + else pv(l) case le: Code.Expression => - r.onExpr { re => pv(le && re) }(newLocalName) + r match { + case re: Code.Expression => + // todo: we can generate more efficient code by evaluating this when possible + // that said, the compiler will definitely handle this too + pv(Code.evalAnd(le, re)) + case _ => + // we can only run the statements in r if le is true, + // since boolean expressions are where the side effects are. + // + // and(x, y) == if x: y else: False + pv(Code.IfElseValue(le, r, Code.FalseLit)) + } case Code.WithValue(sl, sv) => andCode(sv, r).map(sl +: _) case ife @ Code.IfElseValue(c, t, f) if ife.returnsBool || r.isInstanceOf[Code.Expression] => - for { - t1 <- t.onExpr { te => andCode(te, r) }(newLocalName) - f1 <- f.onExpr { te => andCode(te, r) }(newLocalName) - } yield Code.IfElseValue(c, t1, f1) + // push down into the lhs since this won't increase the final branch count + (andCode(t, r), andCode(f, r)).mapN { (t1, r1) => + Code.IfElseValue(c, t1, r1) + } case ife @ Code.IfElseValue(_, _, _) => for { resIdent <- newLocalName("branch_res") @@ -822,6 +836,9 @@ object ClangGen { ) :+ res } + def boxFn(ident: Code.Ident, arity: Int): Code.Expression = + Code.Ident(s"alloc_boxed_pure_fn$arity")(ident) + // We have to lift functions to the top level and not // create any nesting def innerFn(fn: FnExpr): T[Code.ValueLike] = @@ -830,7 +847,7 @@ object ClangGen { ident <- newTopName("lambda") stmt <- fnStatement(ident, fn) _ <- appendStatement(stmt) - } yield Code.Ident("STATIC_PUREFN")(ident) + } yield boxFn(ident, fn.arity); } else { // we create the function, then we allocate @@ -893,7 +910,7 @@ object ClangGen { app match { case App(Global(pack, fnName), args) => directFn(pack, fnName).flatMap { - case Some(ident) => + case Some((ident, _)) => // directly invoke instead of by treating them like lambdas args.traverse(innerToValue(_)).flatMap { argsVL => Code.ValueLike.applyArgs(ident, argsVL)(newLocalName) @@ -903,16 +920,21 @@ object ClangGen { (globalIdent(pack, fnName), args.traverse(innerToValue(_))).flatMapN { (fnVL, argsVL) => // we need to invoke call_fn(fn, arg0, arg1, ....) // but since these are ValueLike, we need to handle more carefully - val fnSize = argsVL.length - val callFn = Code.Ident(s"call_fn$fnSize") - Code.ValueLike.applyArgs(callFn, fnVL :: argsVL)(newLocalName) + val fnValue = fnVL.onExpr { e => pv(e()) }(newLocalName); + fnValue.flatMap { fnValue => + val fnSize = argsVL.length + val callFn = Code.Ident(s"call_fn$fnSize") + Code.ValueLike.applyArgs(callFn, fnValue :: argsVL)(newLocalName) + } } } case App(Local(fnName), args) => directFn(fnName).flatMap { - case Some((ident, isClosure)) => - // directly invoke instead of by treating them like lambdas + case Some((ident, isClosure, _)) => + // this can be an recursive call args.traverse(innerToValue(_)).flatMap { argsVL => + // if we don't have a closure, which is lifted to top level + // directly invoke instead of by treating them like lambdas val withSlot = if (isClosure) slotsArgName :: argsVL else argsVL @@ -989,17 +1011,17 @@ object ClangGen { case Global(pack, name) => directFn(pack, name) .flatMap { - case Some(nm) => - pv(Code.Ident("STATIC_PUREFN")(nm)) + case Some((ident, arity)) => + pv(boxFn(ident, arity)) case None => - globalIdent(pack, name).map { nm => nm() } + globalIdent(pack, name).map(nm => nm()) } case Local(arg) => directFn(arg) .flatMap { - case Some((nm, false)) => + case Some((nm, false, arity)) => // a closure can't be a static name - pv(Code.Ident("STATIC_PUREFN")(nm)) + pv(boxFn(nm, arity)) case _ => getBinding(arg).widen } @@ -1066,7 +1088,7 @@ object ClangGen { if (arity == 0) Code.Ident("PURE_VALUE_TAG").castTo(Code.TypeIdent.BValue) else { val allocStructFn = s"alloc_struct$arity" - Code.Ident("STATIC_PUREFN")(Code.Ident(allocStructFn)) + boxFn(Code.Ident(allocStructFn), arity) } } case ZeroNat => @@ -1093,7 +1115,7 @@ object ClangGen { val body = innerToValue(expr).map(Code.returnValue(_)) val body1 = name match { case None => body - case Some(rec) => recursiveName(fnName, rec, isClosure = captures.nonEmpty)(body) + case Some(rec) => recursiveName(fnName, rec, isClosure = captures.nonEmpty, arity = fn.arity)(body) } bindAll(args) { @@ -1110,7 +1132,7 @@ object ClangGen { } yield Code.DeclareFn(Nil, Code.TypeIdent.BValue, fnName, allArgs.toList, Some(Code.block(fnBody))) } case LoopFn(captures, nm, args, body) => - recursiveName(fnName, nm, isClosure = captures.nonEmpty) { + recursiveName(fnName, nm, isClosure = captures.nonEmpty, arity = fn.arity) { bindAll(args) { for { cond <- newLocalName("cond") @@ -1153,33 +1175,43 @@ object ClangGen { for { vl <- innerToValue(someValue) value <- staticValueName(p, b) - _ <- appendStatement(Code.DeclareVar( - Code.Attr.Static :: Nil, - Code.TypeIdent.AtomicBValue, - value, - Some(Code.IntLiteral.Zero) - )) consFn <- constructorFn(p, b) - _ <- appendStatement(Code.DeclareFn( - Code.Attr.Static :: Nil, - Code.TypeIdent.BValue, - consFn, - Nil, - Some(Code.block(Code.returnValue(vl))) - )) readFn <- globalIdent(p, b) - res = Code.Ident("read_or_build")(value.addr, consFn) - _ <- appendStatement(Code.DeclareFn( - Code.Attr.Static :: Nil, - Code.TypeIdent.BValue, - readFn, - Nil, - Some(Code.block(Code.returnValue(res))) - )) + _ <- makeConstructorsStatement(value, consFn, vl, readFn) } yield () } } + def makeConstructorsStatement(value: Code.Ident, consFn: Code.Ident, vl: Code.ValueLike, readFn: Code.Ident): T[Unit] = + // TODO: if we can create the value statically, we don't + // need the read_or_build trick + // + // we materialize an Atomic value to hold the static data + // then we generate a function to populate the value + for { + _ <- appendStatement(Code.DeclareVar( + Code.Attr.Static :: Nil, + Code.TypeIdent.AtomicBValue, + value, + Some(Code.IntLiteral.Zero) + )) + _ <- appendStatement(Code.DeclareFn( + Code.Attr.Static :: Nil, + Code.TypeIdent.BValue, + consFn, + Nil, + Some(Code.block(Code.returnValue(vl))) + )) + res = Code.Ident("read_or_build")(value.addr, consFn) + _ <- appendStatement(Code.DeclareFn( + Code.Attr.Static :: Nil, + Code.TypeIdent.BValue, + readFn, + Nil, + Some(Code.block(Code.returnValue(res))) + )) + } yield () + def renderMain(p: PackageName, b: Bindable): T[Unit] def renderTests(values: List[(PackageName, Bindable)]): T[Unit] } @@ -1196,7 +1228,7 @@ object ClangGen { includes: Chain[Code.Include], stmts: Chain[Code.Statement], currentTop: Option[(PackageName, Bindable)], - binds: Map[Bindable, NonEmptyList[Either[((Code.Ident, Boolean), Int), Int]]], + binds: Map[Bindable, NonEmptyList[Either[((Code.Ident, Boolean, Int), Int), Int]]], counter: Long ) { def finalFile: Doc = @@ -1299,8 +1331,9 @@ object ClangGen { stack.head match { case Right(idx) => result(s, Code.Ident(Idents.escape("__bsts_b_", bn.asString + idx.toString))) - case Left(((ident, _), _)) => - // TODO: suspicious to ignore isClosure here + case Left(((ident, _, _), _)) => + // TODO: suspicious to ignore isClosure and arity here + // probably need to conv result(s, ident) } case None => errorRes(Error.Unbound(bn, s.currentTop)) @@ -1315,9 +1348,9 @@ object ClangGen { monadImpl.pure(Code.Ident(Idents.escape("__bsts_a_", idx.toString))) // a recursive function needs to remap the Bindable to the top-level mangling - def recursiveName[A](fnName: Code.Ident, bn: Bindable, isClosure: Boolean)(in: T[A]): T[A] = { + def recursiveName[A](fnName: Code.Ident, bn: Bindable, isClosure: Boolean, arity: Int)(in: T[A]): T[A] = { val init: T[Unit] = StateT { s => - val entry = (fnName, isClosure) + val entry = (fnName, isClosure, arity) val v = s.binds.get(bn) match { case None => NonEmptyList.one(Left((entry, -1))) case Some(items @ NonEmptyList(Right(idx), _)) => @@ -1366,25 +1399,25 @@ object ClangGen { Code.Ident(Idents.escape("__bsts_t_", tag + cnt.toString)) } // record that this name is a top level function, so applying it can be direct - def directFn(pack: PackageName, b: Bindable): T[Option[Code.Ident]] = + def directFn(pack: PackageName, b: Bindable): T[Option[(Code.Ident, Int)]] = StateT { s => val key = (pack, b) s.allValues.get(key) match { - case Some((_: Matchless.FnExpr, ident)) => - result(s, Some(ident)) + case Some((fn: Matchless.FnExpr, ident)) => + result(s, Some((ident, fn.arity))) case None => // this is external s.externals(pack, b) match { case Some((incl, ident, arity)) if arity > 0 => val withIncl = s.include(incl) - result(withIncl, Some(ident)) + result(withIncl, Some((ident, arity))) case _ => result(s, None) } case _ => result(s, None) } } - def directFn(b: Bindable): T[Option[(Code.Ident, Boolean)]] = + def directFn(b: Bindable): T[Option[(Code.Ident, Boolean, Int)]] = StateT { s => s.binds.get(b) match { case Some(NonEmptyList(Left((c, _)), _)) => @@ -1409,6 +1442,7 @@ object ClangGen { def constructorFn(p: PackageName, b: Bindable): T[Code.Ident] = monadImpl.pure(Code.Ident(Idents.escape("___bsts_c_", fullName(p, b)))) + // this is the name of a function when it is directly invokable def renderMain(p: PackageName, b: Bindable): T[Unit] = // TODO ??? monadImpl.unit diff --git a/core/src/main/scala/org/bykn/bosatsu/codegen/clang/ClangTranspiler.scala b/core/src/main/scala/org/bykn/bosatsu/codegen/clang/ClangTranspiler.scala index 0eca2de43..f3be6ee5c 100644 --- a/core/src/main/scala/org/bykn/bosatsu/codegen/clang/ClangTranspiler.scala +++ b/core/src/main/scala/org/bykn/bosatsu/codegen/clang/ClangTranspiler.scala @@ -15,10 +15,36 @@ import cats.syntax.all._ case object ClangTranspiler extends Transpiler { + sealed abstract class EmitMode { + def apply[A](pm: PackageMap.Typed[A], roots: Set[(PackageName, Identifier)]): PackageMap.Typed[A] + } + object EmitMode { + case object Shake extends EmitMode { + def apply[A](pm: PackageMap.Typed[A], roots: Set[(PackageName, Identifier)]): PackageMap.Typed[A] = + PackageMap.treeShake(pm, roots) + } + case object All extends EmitMode { + def apply[A](pm: PackageMap.Typed[A], roots: Set[(PackageName, Identifier)]): PackageMap.Typed[A] = pm + } + + implicit val argumentEmitMode: Argument[EmitMode] = + new Argument[EmitMode] { + def defaultMetavar: String = "emitmode" + def read(string: String) = + string match { + case "shake" => Validated.valid(Shake) + case "all" => Validated.valid(All) + case other => Validated.invalidNel(s"expected (shake|all) got $other") + } + } + + val opts: Opts[EmitMode] = + Opts.option[EmitMode]("emitmode", "emit mode: shake|all, default = all").withDefault(All) + } sealed abstract class Mode(val name: String) object Mode { case class Main(pack: PackageName) extends Mode("main") - case class Test(filter: Option[PackageName => Boolean], filterRegex: String) extends Mode("test") { + case class Test(filter: Option[PackageName => Boolean], filterRegexes: NonEmptyList[String]) extends Mode("test") { def values(p: PackageMap.Typed[Any]): List[(PackageName, Bindable)] = (filter match { case None => @@ -33,27 +59,29 @@ case object ClangTranspiler extends Transpiler { .map(Main(_)) .orElse( Opts.flag("test", "compile the tests") *> - (Opts.option[String]("filter", "regular expression to filter package names").orNone) + (Opts.options[String]("filter", "regular expression to filter package names").orNone) .mapValidated { - case None => Validated.valid(Test(None, ".*")) - case Some(pat) => - Try(RegexPat.compile(pat)) match { - case Success(p) => Validated.valid(Test(Some(pn => p.matcher(pn.asString).matches()), pat)) - case Failure(e) => Validated.invalidNel(s"could not parse pattern: $pat\n\n${e.getMessage}") + case None => Validated.valid(Test(None, NonEmptyList.one(".*"))) + case Some(res) => + Try(res.map(RegexPat.compile(_))) match { + case Success(pats) => Validated.valid( + Test(Some(pn => pats.exists(_.matcher(pn.asString).matches())), res) + ) + case Failure(e) => Validated.invalidNel(s"could not parse patterns: $res\n\n${e.getMessage}") } } ) } - case class Arguments(mode: Mode) + case class Arguments(mode: Mode, emit: EmitMode) type Args[P] = Const[Arguments, P] def traverseArgs: Traverse[Args] = implicitly def opts[P](pathArg: Argument[P]): Opts[Transpiler.Optioned[P]] = Opts.subcommand("c", "generate c code") { - Mode.opts.map { m => - Transpiler.optioned(this)(Const[Arguments, P](Arguments(m))) + (Mode.opts, EmitMode.opts).mapN { (m, e) => + Transpiler.optioned(this)(Const[Arguments, P](Arguments(m, e))) } } @@ -72,9 +100,12 @@ case object ClangTranspiler extends Transpiler { case class InvalidMainValue(pack: PackageName, message: String) extends Exception(s"invalid main ${pack.asString}: $message.") - case class NoTestsFound(packs: List[PackageName], regex: String) extends + case class NoTestsFound(packs: List[PackageName], regex: NonEmptyList[String]) extends Exception( - (Doc.text("no tests found in:") + spacePackList(packs)).render(80) + (Doc.text("no tests found in:") + spacePackList(packs) + Doc.hardLine + + Doc.text("using regexes:") + + (Doc.line + Doc.intercalate(Doc.line, regex.toList.map(Doc.text(_))).nested(4)).grouped + ).render(80) ) def externalsFor(pm: PackageMap.Typed[Any]): ClangGen.ExternalResolver = @@ -93,11 +124,6 @@ case object ClangTranspiler extends Transpiler { NonEmptyList.fromList(sorted.loopNodes) match { case Some(loop) => Failure(CircularPackagesFound(loop)) case None => - val matchlessMap = MatchlessFromTypedExpr.compile(pm) - val sortedEnv = cats.Functor[Vector] - .compose[NonEmptyList] - .map(sorted.layers) { pn => pn -> matchlessMap(pn) } - val ext = externalsFor(pm) val doc = args.getConst.mode match { case Mode.Main(p) => @@ -105,6 +131,12 @@ case object ClangTranspiler extends Transpiler { case Some((b, _, t)) => validMain(t) match { case Right(_) => + val pm1 = args.getConst.emit(pm, Set((p, b))) + val matchlessMap = MatchlessFromTypedExpr.compile(pm1) + val sortedEnv = cats.Functor[Vector] + .compose[NonEmptyList] + .map(sorted.layers) { pn => pn -> matchlessMap(pn) } + ClangGen.renderMain( sortedEnv = sortedEnv, externals = ext, @@ -121,6 +153,12 @@ case object ClangTranspiler extends Transpiler { case Nil => return Failure(NoTestsFound(pm.toMap.keySet.toList.sorted, re)) case nonEmpty => + val pm1 = args.getConst.emit(pm, nonEmpty.toSet) + val matchlessMap = MatchlessFromTypedExpr.compile(pm1) + val sortedEnv = cats.Functor[Vector] + .compose[NonEmptyList] + .map(sorted.layers) { pn => pn -> matchlessMap(pn) } + ClangGen.renderTests( sortedEnv = sortedEnv, externals = ext, diff --git a/core/src/main/scala/org/bykn/bosatsu/codegen/clang/Code.scala b/core/src/main/scala/org/bykn/bosatsu/codegen/clang/Code.scala index 04aa4a6e1..e7bd553ba 100644 --- a/core/src/main/scala/org/bykn/bosatsu/codegen/clang/Code.scala +++ b/core/src/main/scala/org/bykn/bosatsu/codegen/clang/Code.scala @@ -170,6 +170,20 @@ object Code { } } + def evalAnd(l: Expression, r: Expression): Expression = + l.evalToInt match { + case Some(IntLiteral(lv)) => + if (lv == 0) l + else r + case None => + r.evalToInt match { + case Some(IntLiteral(rv)) => + if (rv == 0) r + else l + case None => + l && r + } + } ///////////////////////// // Here are all the ValueLike ///////////////////////// diff --git a/core/src/test/scala/org/bykn/bosatsu/codegen/clang/ClangGenTest.scala b/core/src/test/scala/org/bykn/bosatsu/codegen/clang/ClangGenTest.scala index 94dd47f78..5fd90f050 100644 --- a/core/src/test/scala/org/bykn/bosatsu/codegen/clang/ClangGenTest.scala +++ b/core/src/test/scala/org/bykn/bosatsu/codegen/clang/ClangGenTest.scala @@ -47,7 +47,7 @@ BValue __bsts_t_lambda0(BValue __bsts_b_a0, BValue __bsts_b_b0) { BValue ___bsts_g_Bosatsu_l_Predef_l_build__List(BValue __bsts_b_fn0) { return call_fn2(__bsts_b_fn0, - STATIC_PUREFN(__bsts_t_lambda0), + alloc_boxed_pure_fn2(__bsts_t_lambda0), alloc_enum0(0)); }""") } @@ -121,7 +121,7 @@ BValue ___bsts_g_Bosatsu_l_Predef_l_reverse__concat(BValue __bsts_b_front0, BValue __bsts_b_back0) { return ___bsts_g_Bosatsu_l_Predef_l_foldLeft(__bsts_b_front0, __bsts_b_back0, - STATIC_PUREFN(__bsts_t_lambda4)); + alloc_boxed_pure_fn2(__bsts_t_lambda4)); }""") } } \ No newline at end of file diff --git a/test_workspace/IntTest.bosatsu b/test_workspace/IntTest.bosatsu new file mode 100644 index 000000000..5a49ed461 --- /dev/null +++ b/test_workspace/IntTest.bosatsu @@ -0,0 +1,32 @@ +package IntTest + +def operator +(a, b): a.add(b) +def operator -(a, b): a.sub(b) +def operator *(a, b): a.times(b) +def operator ==(a, b): a.eq_Int(b) + +tests = TestSuite("Int tests", [ + Assertion(42 + 58 == 100, "42 + 58 == 100"), + Assertion(-42 * 2 == -84, "-42 * 2 == -84"), + Assertion(0 - 1 == -1, "0 - 1 == -1"), + # 32-bit max + 1 + Assertion(2_147_483_647 + 1 == 2_147_483_648, "2_147_483_647 + 1 == 2_147_483_648 but got ${int_to_String(2_147_483_647 + 1)}"), + # 32-bit max - 1 + Assertion(2_147_483_647 - 1 == 2_147_483_646, "2_147_483_647 - 1 == 2_147_483_646"), + # 32-bit min - 1 + Assertion(-2_147_483_648 - 1 == -2_147_483_649, "-2_147_483_648 - 1 == -2_147_483_649 but got ${int_to_String(-2_147_483_648 - 1)}"), + # 32-bit overflow test + Assertion(2_147_483_647 * 2 == 4_294_967_294, "2_147_483_647 * 2 == 4_294_967_294 but got: ${int_to_String(2_147_483_647 * 2)}"), + # 64-bit max + 1 + Assertion(9_223_372_036_854_775_807 + 1 == 9_223_372_036_854_775_808, "9_223_372_036_854_775_807 + 1 == 9_223_372_036_854_775_808"), + # 64-bit min - 1 + Assertion(-9_223_372_036_854_775_808 - 1 == -9_223_372_036_854_775_809, "-9_223_372_036_854_775_808 - 1 == -9_223_372_036_854_775_809"), + # 64-bit overflow test + Assertion(9_223_372_036_854_775_807 * 2 == 18_446_744_073_709_551_614, "9_223_372_036_854_775_807 * 2 == 18_446_744_073_709_551_614"), + # 64-bit negative overflow test + Assertion(-9_223_372_036_854_775_808 * 2 == -18_446_744_073_709_551_616, "-9_223_372_036_854_775_808 * 2 == -18_446_744_073_709_551_616"), + # Post-overflow arithmetic + Assertion((9_223_372_036_854_775_807 + 1) * 2 == 18_446_744_073_709_551_616, "(9_223_372_036_854_775_807 + 1) * 2 == 18_446_744_073_709_551_616"), + # Mixed multiplication and subtraction + Assertion((9_223_372_036_854_775_807 * 9) - (9_223_372_036_854_775_807 * 8) == 9_223_372_036_854_775_807, "(9_223_372_036_854_775_807 * 9) - (9_223_372_036_854_775_807 * 8) == 9_223_372_036_854_775_807"), +]) \ No newline at end of file diff --git a/test_workspace/List.bosatsu b/test_workspace/List.bosatsu index 03b7495a4..3c8bdbcce 100644 --- a/test_workspace/List.bosatsu +++ b/test_workspace/List.bosatsu @@ -124,12 +124,31 @@ sortTest = ( ]) ) +stringTests = TestSuite("string tests", [ + Assertion(int_to_String(0) matches "0", "int_to_String(0) == ${int_to_String(0)}"), + Assertion(int_to_String(1) matches "1", "int_to_String(1) == ${int_to_String(1)}"), + Assertion(int_to_String(2) matches "2", "int_to_String(2) == ${int_to_String(2)}"), +]) + +il = int_loop(5, 0, (i, a) -> (i.sub(1), i.add(a))) + tests = TestSuite("List tests", [ + Assertion(2.sub(3) matches -1, "2 - 3 = ${int_to_String(2.sub(3))}"), + Assertion(il matches 15, "int_loop test ${int_to_String(il)}"), Assertion([1, 2, 3] =*= [1, 2, 3], "list [1, 2, 3]"), Assertion(not([1, 2, 3] =*= [1, 2]), "list [1, 2, 3] != [1, 2]"), - Assertion(range(6).sum().eq_Int(15), "range(6).sum == 1 + 2 + 3 + 4 + 5 = 15"), + Assertion(range(0) matches [], "range(0) matches []"), + Assertion(range(1) matches [0], "range(1) matches [0]"), + Assertion(range(2) matches [0, 1], "range(2) matches [0, 1]"), + Assertion(range(6) =*= [0, 1, 2, 3, 4, 5], "range(6) == ${concat_String(range(6).map_List(i -> "${int_to_String(i)}, "))}"), + Assertion(sum([]) matches 0, "sum([])"), + Assertion(sum([5]) matches 5, "sum([5])"), + Assertion(sum([5, 11]) matches 16, "sum([5, 11])"), + Assertion(sum([0, 1, 2, 3, 4, 5]) matches 15, "sum([0, 1, 2, 3, 4, 5])"), + #Assertion(range(6).sum().eq_Int(15), "range(6).sum == 1 + 2 + 3 + 4 + 5 = 15"), Assertion(range(6).exists(v -> v.eq_Int(5)), "range(6) does have 5"), Assertion(not(range(6).exists(v -> v.eq_Int(6))), "range(6) does not have 6"), + stringTests, headTest, unconsTest, zipTest, diff --git a/test_workspace/euler1.bosatsu b/test_workspace/euler1.bosatsu index 573a56ac7..43da3e528 100644 --- a/test_workspace/euler1.bosatsu +++ b/test_workspace/euler1.bosatsu @@ -19,4 +19,4 @@ def sum(as): as.foldLeft(0, add) # 233168 computed = sum([i for i in range(1000) if keep(i)]) -test = Assertion(computed == 233168, "expected 233168") +test = Assertion(computed == 233168, "expected 233168 got ${int_to_String(computed)}")