diff --git a/CHANGELOG.md b/CHANGELOG.md index c9991c01b8..6e93aa226b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed changed default to `AVM_USE_32BIT_FLOAT=on` for STM32 platform to enable use of single precision hardware FPU on F4/F7 devices. - Fixed a bug where emscripten `register_*_callback/1` functions would use x[1] as second argument - Fixed interpretation of live for opcodes, thus altering GC semantics for nifs. See also [UPDATING](UPDATING.md). +- Fixed a bug where the VM would crash when code used more than 16 x registers. ### Changed diff --git a/src/libAtomVM/bif.c b/src/libAtomVM/bif.c index 88d8f26da3..00fbe8c5b2 100644 --- a/src/libAtomVM/bif.c +++ b/src/libAtomVM/bif.c @@ -37,8 +37,8 @@ #pragma GCC diagnostic pop #define RAISE_ERROR(error_type_atom) \ - ctx->x[0] = ERROR_ATOM; \ - ctx->x[1] = (error_type_atom); \ + x_regs[0] = ERROR_ATOM; \ + x_regs[1] = (error_type_atom); \ return term_invalid_term(); #define VALIDATE_VALUE(value, verify_function) \ @@ -62,13 +62,16 @@ const struct ExportedFunction *bif_registry_get_handler(AtomString module, AtomS return &nameAndPtr->bif.base; } -term bif_erlang_self_0(Context *ctx) +term bif_erlang_self_0(Context *ctx, term *x_regs) { + UNUSED(x_regs); + return term_from_local_process_id(ctx->process_id); } -term bif_erlang_byte_size_1(Context *ctx, int live, term arg1) +term bif_erlang_byte_size_1(Context *ctx, term *x_regs, int live, term arg1) { + UNUSED(ctx); UNUSED(live); VALIDATE_VALUE(arg1, term_is_binary); @@ -76,8 +79,9 @@ term bif_erlang_byte_size_1(Context *ctx, int live, term arg1) return term_from_int32(term_binary_size(arg1)); } -term bif_erlang_bit_size_1(Context *ctx, int live, term arg1) +term bif_erlang_bit_size_1(Context *ctx, term *x_regs, int live, term arg1) { + UNUSED(ctx); UNUSED(live); VALIDATE_VALUE(arg1, term_is_binary); @@ -85,92 +89,104 @@ term bif_erlang_bit_size_1(Context *ctx, int live, term arg1) return term_from_int32(term_binary_size(arg1) * 8); } -term bif_erlang_is_atom_1(Context *ctx, term arg1) +term bif_erlang_is_atom_1(Context *ctx, term *x_regs, term arg1) { UNUSED(ctx); + UNUSED(x_regs); return term_is_atom(arg1) ? TRUE_ATOM : FALSE_ATOM; } -term bif_erlang_is_binary_1(Context *ctx, term arg1) +term bif_erlang_is_binary_1(Context *ctx, term *x_regs, term arg1) { UNUSED(ctx); + UNUSED(x_regs); return term_is_binary(arg1) ? TRUE_ATOM : FALSE_ATOM; } -term bif_erlang_is_boolean_1(Context *ctx, term arg1) +term bif_erlang_is_boolean_1(Context *ctx, term *x_regs, term arg1) { UNUSED(ctx); + UNUSED(x_regs); return (arg1 == TRUE_ATOM || arg1 == FALSE_ATOM) ? TRUE_ATOM : FALSE_ATOM; } -term bif_erlang_is_float_1(Context *ctx, term arg1) +term bif_erlang_is_float_1(Context *ctx, term *x_regs, term arg1) { UNUSED(ctx); + UNUSED(x_regs); return term_is_float(arg1) ? TRUE_ATOM : FALSE_ATOM; } -term bif_erlang_is_function_1(Context *ctx, term arg1) +term bif_erlang_is_function_1(Context *ctx, term *x_regs, term arg1) { UNUSED(ctx); + UNUSED(x_regs); return term_is_function(arg1) ? TRUE_ATOM : FALSE_ATOM; } -term bif_erlang_is_integer_1(Context *ctx, term arg1) +term bif_erlang_is_integer_1(Context *ctx, term *x_regs, term arg1) { UNUSED(ctx); + UNUSED(x_regs); return term_is_any_integer(arg1) ? TRUE_ATOM : FALSE_ATOM; } -term bif_erlang_is_list_1(Context *ctx, term arg1) +term bif_erlang_is_list_1(Context *ctx, term *x_regs, term arg1) { UNUSED(ctx); + UNUSED(x_regs); return term_is_list(arg1) ? TRUE_ATOM : FALSE_ATOM; } -term bif_erlang_is_number_1(Context *ctx, term arg1) +term bif_erlang_is_number_1(Context *ctx, term *x_regs, term arg1) { UNUSED(ctx); + UNUSED(x_regs); //TODO: change to term_is_number return term_is_any_integer(arg1) ? TRUE_ATOM : FALSE_ATOM; } -term bif_erlang_is_pid_1(Context *ctx, term arg1) +term bif_erlang_is_pid_1(Context *ctx, term *x_regs, term arg1) { UNUSED(ctx); + UNUSED(x_regs); return term_is_pid(arg1) ? TRUE_ATOM : FALSE_ATOM; } -term bif_erlang_is_reference_1(Context *ctx, term arg1) +term bif_erlang_is_reference_1(Context *ctx, term *x_regs, term arg1) { UNUSED(ctx); + UNUSED(x_regs); return term_is_reference(arg1) ? TRUE_ATOM : FALSE_ATOM; } -term bif_erlang_is_tuple_1(Context *ctx, term arg1) +term bif_erlang_is_tuple_1(Context *ctx, term *x_regs, term arg1) { UNUSED(ctx); + UNUSED(x_regs); return term_is_tuple(arg1) ? TRUE_ATOM : FALSE_ATOM; } -term bif_erlang_is_map_1(Context *ctx, term arg1) +term bif_erlang_is_map_1(Context *ctx, term *x_regs, term arg1) { UNUSED(ctx); + UNUSED(x_regs); return term_is_map(arg1) ? TRUE_ATOM : FALSE_ATOM; } -term bif_erlang_is_map_key_2(Context *ctx, term arg1, term arg2) +term bif_erlang_is_map_key_2(Context *ctx, term *x_regs, term arg1, term arg2) { if (UNLIKELY(!term_is_map(arg2))) { if (UNLIKELY(memory_ensure_free_with_roots(ctx, 3, 1, &arg2, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { @@ -193,8 +209,9 @@ term bif_erlang_is_map_key_2(Context *ctx, term arg1, term arg2) } } -term bif_erlang_length_1(Context *ctx, int live, term arg1) +term bif_erlang_length_1(Context *ctx, term *x_regs, int live, term arg1) { + UNUSED(ctx); UNUSED(live); VALIDATE_VALUE(arg1, term_is_list); @@ -208,22 +225,28 @@ term bif_erlang_length_1(Context *ctx, int live, term arg1) return term_from_int(len); } -term bif_erlang_hd_1(Context *ctx, term arg1) +term bif_erlang_hd_1(Context *ctx, term *x_regs, term arg1) { + UNUSED(ctx); + VALIDATE_VALUE(arg1, term_is_nonempty_list); return term_get_list_head(arg1); } -term bif_erlang_tl_1(Context *ctx, term arg1) +term bif_erlang_tl_1(Context *ctx, term *x_regs, term arg1) { + UNUSED(ctx); + VALIDATE_VALUE(arg1, term_is_nonempty_list); return term_get_list_tail(arg1); } -term bif_erlang_element_2(Context *ctx, term arg1, term arg2) +term bif_erlang_element_2(Context *ctx, term *x_regs, term arg1, term arg2) { + UNUSED(ctx); + VALIDATE_VALUE(arg1, term_is_integer); VALIDATE_VALUE(arg2, term_is_tuple); @@ -237,14 +260,16 @@ term bif_erlang_element_2(Context *ctx, term arg1, term arg2) } } -term bif_erlang_tuple_size_1(Context *ctx, term arg1) +term bif_erlang_tuple_size_1(Context *ctx, term *x_regs, term arg1) { + UNUSED(ctx); + VALIDATE_VALUE(arg1, term_is_tuple); return term_from_int32(term_get_tuple_arity(arg1)); } -term bif_erlang_map_size_1(Context *ctx, int live, term arg1) +term bif_erlang_map_size_1(Context *ctx, term *x_regs, int live, term arg1) { UNUSED(live); @@ -263,7 +288,7 @@ term bif_erlang_map_size_1(Context *ctx, int live, term arg1) return term_from_int32(term_get_map_size(arg1)); } -term bif_erlang_map_get_2(Context *ctx, term arg1, term arg2) +term bif_erlang_map_get_2(Context *ctx, term *x_regs, term arg1, term arg2) { if (!UNLIKELY(term_is_map(arg2))) { // We don't need to preserve registers as we're raising @@ -294,9 +319,9 @@ term bif_erlang_map_get_2(Context *ctx, term arg1, term arg2) return term_get_map_value(arg2, pos); } -static inline term make_boxed_int(Context *ctx, uint32_t live, avm_int_t value) +static inline term make_boxed_int(Context *ctx, term *x_regs, uint32_t live, avm_int_t value) { - if (UNLIKELY(memory_ensure_free_with_roots(ctx, BOXED_INT_SIZE, live, ctx->x, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { + if (UNLIKELY(memory_ensure_free_with_roots(ctx, BOXED_INT_SIZE, live, x_regs, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { RAISE_ERROR(OUT_OF_MEMORY_ATOM); } @@ -304,9 +329,9 @@ static inline term make_boxed_int(Context *ctx, uint32_t live, avm_int_t value) } #if BOXED_TERMS_REQUIRED_FOR_INT64 > 1 -static inline term make_boxed_int64(Context *ctx, uint32_t live, avm_int64_t value) +static inline term make_boxed_int64(Context *ctx, term *x_regs, uint32_t live, avm_int64_t value) { - if (UNLIKELY(memory_ensure_free_with_roots(ctx, BOXED_INT64_SIZE, live, ctx->x, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { + if (UNLIKELY(memory_ensure_free_with_roots(ctx, BOXED_INT64_SIZE, live, x_regs, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { RAISE_ERROR(OUT_OF_MEMORY_ATOM); } @@ -314,10 +339,10 @@ static inline term make_boxed_int64(Context *ctx, uint32_t live, avm_int64_t val } #endif -static inline term make_maybe_boxed_int(Context *ctx, uint32_t live, avm_int_t value) +static inline term make_maybe_boxed_int(Context *ctx, term *x_regs, uint32_t live, avm_int_t value) { if ((value < MIN_NOT_BOXED_INT) || (value > MAX_NOT_BOXED_INT)) { - return make_boxed_int(ctx, live, value); + return make_boxed_int(ctx, x_regs, live, value); } else { return term_from_int(value); @@ -325,13 +350,13 @@ static inline term make_maybe_boxed_int(Context *ctx, uint32_t live, avm_int_t v } #if BOXED_TERMS_REQUIRED_FOR_INT64 > 1 -static inline term make_maybe_boxed_int64(Context *ctx, uint32_t live, avm_int64_t value) +static inline term make_maybe_boxed_int64(Context *ctx, term *x_regs, uint32_t live, avm_int64_t value) { if ((value < AVM_INT_MIN) || (value > AVM_INT_MAX)) { - return make_boxed_int64(ctx, live, value); + return make_boxed_int64(ctx, x_regs, live, value); } else if ((value < MIN_NOT_BOXED_INT) || (value > MAX_NOT_BOXED_INT)) { - return make_boxed_int(ctx, live, value); + return make_boxed_int(ctx, x_regs, live, value); } else { return term_from_int(value); @@ -339,15 +364,15 @@ static inline term make_maybe_boxed_int64(Context *ctx, uint32_t live, avm_int64 } #endif -static term add_overflow_helper(Context *ctx, uint32_t live, term arg1, term arg2) +static term add_overflow_helper(Context *ctx, term *x_regs, uint32_t live, term arg1, term arg2) { avm_int_t val1 = term_to_int(arg1); avm_int_t val2 = term_to_int(arg2); - return make_boxed_int(ctx, live, val1 + val2); + return make_boxed_int(ctx, x_regs, live, val1 + val2); } -static term add_boxed_helper(Context *ctx, uint32_t live, term arg1, term arg2) +static term add_boxed_helper(Context *ctx, term *x_regs, uint32_t live, term arg1, term arg2) { int use_float = 0; int size = 0; @@ -377,7 +402,7 @@ static term add_boxed_helper(Context *ctx, uint32_t live, term arg1, term arg2) RAISE_ERROR(BADARITH_ATOM); } - if (UNLIKELY(memory_ensure_free_with_roots(ctx, FLOAT_SIZE, live, ctx->x, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { + if (UNLIKELY(memory_ensure_free_with_roots(ctx, FLOAT_SIZE, live, x_regs, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { RAISE_ERROR(OUT_OF_MEMORY_ATOM); } return term_from_float(fresult, &ctx->heap); @@ -397,7 +422,7 @@ static term add_boxed_helper(Context *ctx, uint32_t live, term arg1, term arg2) if (BUILTIN_ADD_OVERFLOW_INT(val1, val2, &res)) { #if BOXED_TERMS_REQUIRED_FOR_INT64 == 2 avm_int64_t res64 = (avm_int64_t) val1 + (avm_int64_t) val2; - return make_boxed_int64(ctx, live, res64); + return make_boxed_int64(ctx, x_regs, live, res64); #elif BOXED_TERMS_REQUIRED_FOR_INT64 == 1 TRACE("overflow: arg1: " AVM_INT64_FMT ", arg2: " AVM_INT64_FMT "\n", arg1, arg2); @@ -407,7 +432,7 @@ static term add_boxed_helper(Context *ctx, uint32_t live, term arg1, term arg2) #endif } - return make_maybe_boxed_int(ctx, live, res); + return make_maybe_boxed_int(ctx, x_regs, live, res); } #if BOXED_TERMS_REQUIRED_FOR_INT64 == 2 @@ -422,7 +447,7 @@ static term add_boxed_helper(Context *ctx, uint32_t live, term arg1, term arg2) RAISE_ERROR(OVERFLOW_ATOM); } - return make_maybe_boxed_int64(ctx, live, res); + return make_maybe_boxed_int64(ctx, x_regs, live, res); } #endif @@ -431,7 +456,7 @@ static term add_boxed_helper(Context *ctx, uint32_t live, term arg1, term arg2) } } -term bif_erlang_add_2(Context *ctx, int live, term arg1, term arg2) +term bif_erlang_add_2(Context *ctx, term *x_regs, int live, term arg1, term arg2) { UNUSED(live); @@ -441,22 +466,22 @@ term bif_erlang_add_2(Context *ctx, int live, term arg1, term arg2) if (!BUILTIN_ADD_OVERFLOW((avm_int_t) (arg1 & ~TERM_INTEGER_TAG), (avm_int_t) (arg2 & ~TERM_INTEGER_TAG), &res)) { return res | TERM_INTEGER_TAG; } else { - return add_overflow_helper(ctx, live, arg1, arg2); + return add_overflow_helper(ctx, x_regs, live, arg1, arg2); } } else { - return add_boxed_helper(ctx, live, arg1, arg2); + return add_boxed_helper(ctx, x_regs, live, arg1, arg2); } } -static term sub_overflow_helper(Context *ctx, uint32_t live, term arg1, term arg2) +static term sub_overflow_helper(Context *ctx, term *x_regs, uint32_t live, term arg1, term arg2) { avm_int_t val1 = term_to_int(arg1); avm_int_t val2 = term_to_int(arg2); - return make_boxed_int(ctx, live, val1 - val2); + return make_boxed_int(ctx, x_regs, live, val1 - val2); } -static term sub_boxed_helper(Context *ctx, uint32_t live, term arg1, term arg2) +static term sub_boxed_helper(Context *ctx, term *x_regs, uint32_t live, term arg1, term arg2) { int use_float = 0; int size = 0; @@ -485,7 +510,7 @@ static term sub_boxed_helper(Context *ctx, uint32_t live, term arg1, term arg2) if (UNLIKELY(!isfinite(fresult))) { RAISE_ERROR(BADARITH_ATOM); } - if (UNLIKELY(memory_ensure_free_with_roots(ctx, FLOAT_SIZE, live, ctx->x, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { + if (UNLIKELY(memory_ensure_free_with_roots(ctx, FLOAT_SIZE, live, x_regs, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { RAISE_ERROR(OUT_OF_MEMORY_ATOM); } return term_from_float(fresult, &ctx->heap); @@ -505,7 +530,7 @@ static term sub_boxed_helper(Context *ctx, uint32_t live, term arg1, term arg2) if (BUILTIN_SUB_OVERFLOW_INT(val1, val2, &res)) { #if BOXED_TERMS_REQUIRED_FOR_INT64 == 2 avm_int64_t res64 = (avm_int64_t) val1 - (avm_int64_t) val2; - return make_boxed_int64(ctx, live, res64); + return make_boxed_int64(ctx, x_regs, live, res64); #elif BOXED_TERMS_REQUIRED_FOR_INT64 == 1 TRACE("overflow: arg1: " AVM_INT64_FMT ", arg2: " AVM_INT64_FMT "\n", arg1, arg2); @@ -515,7 +540,7 @@ static term sub_boxed_helper(Context *ctx, uint32_t live, term arg1, term arg2) #endif } - return make_maybe_boxed_int(ctx, live, res); + return make_maybe_boxed_int(ctx, x_regs, live, res); } #if BOXED_TERMS_REQUIRED_FOR_INT64 == 2 @@ -530,7 +555,7 @@ static term sub_boxed_helper(Context *ctx, uint32_t live, term arg1, term arg2) RAISE_ERROR(OVERFLOW_ATOM); } - return make_maybe_boxed_int64(ctx, live, res); + return make_maybe_boxed_int64(ctx, x_regs, live, res); } #endif @@ -539,7 +564,7 @@ static term sub_boxed_helper(Context *ctx, uint32_t live, term arg1, term arg2) } } -term bif_erlang_sub_2(Context *ctx, int live, term arg1, term arg2) +term bif_erlang_sub_2(Context *ctx, term *x_regs, int live, term arg1, term arg2) { UNUSED(live); @@ -549,14 +574,14 @@ term bif_erlang_sub_2(Context *ctx, int live, term arg1, term arg2) if (!BUILTIN_SUB_OVERFLOW((avm_int_t) (arg1 & ~TERM_INTEGER_TAG), (avm_int_t) (arg2 & ~TERM_INTEGER_TAG), &res)) { return res | TERM_INTEGER_TAG; } else { - return sub_overflow_helper(ctx, live, arg1, arg2); + return sub_overflow_helper(ctx, x_regs, live, arg1, arg2); } } else { - return sub_boxed_helper(ctx, live, arg1, arg2); + return sub_boxed_helper(ctx, x_regs, live, arg1, arg2); } } -static term mul_overflow_helper(Context *ctx, uint32_t live, term arg1, term arg2) +static term mul_overflow_helper(Context *ctx, term *x_regs, uint32_t live, term arg1, term arg2) { avm_int_t val1 = term_to_int(arg1); avm_int_t val2 = term_to_int(arg2); @@ -567,11 +592,11 @@ static term mul_overflow_helper(Context *ctx, uint32_t live, term arg1, term arg #endif if (!BUILTIN_MUL_OVERFLOW_INT(val1, val2, &res)) { - return make_boxed_int(ctx, live, res); + return make_boxed_int(ctx, x_regs, live, res); #if BOXED_TERMS_REQUIRED_FOR_INT64 == 2 } else if (!BUILTIN_MUL_OVERFLOW_INT64((avm_int64_t) val1, (avm_int64_t) val2, &res64)) { - return make_boxed_int64(ctx, live, res64); + return make_boxed_int64(ctx, x_regs, live, res64); #endif } else { @@ -579,7 +604,7 @@ static term mul_overflow_helper(Context *ctx, uint32_t live, term arg1, term arg } } -static term mul_boxed_helper(Context *ctx, uint32_t live, term arg1, term arg2) +static term mul_boxed_helper(Context *ctx, term *x_regs, uint32_t live, term arg1, term arg2) { int use_float = 0; int size = 0; @@ -608,7 +633,7 @@ static term mul_boxed_helper(Context *ctx, uint32_t live, term arg1, term arg2) if (UNLIKELY(!isfinite(fresult))) { RAISE_ERROR(BADARITH_ATOM); } - if (UNLIKELY(memory_ensure_free_with_roots(ctx, FLOAT_SIZE, live, ctx->x, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { + if (UNLIKELY(memory_ensure_free_with_roots(ctx, FLOAT_SIZE, live, x_regs, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { RAISE_ERROR(OUT_OF_MEMORY_ATOM); } return term_from_float(fresult, &ctx->heap); @@ -628,7 +653,7 @@ static term mul_boxed_helper(Context *ctx, uint32_t live, term arg1, term arg2) if (BUILTIN_MUL_OVERFLOW_INT(val1, val2, &res)) { #if BOXED_TERMS_REQUIRED_FOR_INT64 == 2 avm_int64_t res64 = (avm_int64_t) val1 * (avm_int64_t) val2; - return make_boxed_int64(ctx, live, res64); + return make_boxed_int64(ctx, x_regs, live, res64); #elif BOXED_TERMS_REQUIRED_FOR_INT64 == 1 TRACE("overflow: arg1: " AVM_INT64_FMT ", arg2: " AVM_INT64_FMT "\n", arg1, arg2); @@ -638,7 +663,7 @@ static term mul_boxed_helper(Context *ctx, uint32_t live, term arg1, term arg2) #endif } - return make_maybe_boxed_int(ctx, live, res); + return make_maybe_boxed_int(ctx, x_regs, live, res); } #if BOXED_TERMS_REQUIRED_FOR_INT64 == 2 @@ -653,7 +678,7 @@ static term mul_boxed_helper(Context *ctx, uint32_t live, term arg1, term arg2) RAISE_ERROR(OVERFLOW_ATOM); } - return make_maybe_boxed_int64(ctx, live, res); + return make_maybe_boxed_int64(ctx, x_regs, live, res); } #endif @@ -662,7 +687,7 @@ static term mul_boxed_helper(Context *ctx, uint32_t live, term arg1, term arg2) } } -term bif_erlang_mul_2(Context *ctx, int live, term arg1, term arg2) +term bif_erlang_mul_2(Context *ctx, term *x_regs, int live, term arg1, term arg2) { UNUSED(live); @@ -673,14 +698,14 @@ term bif_erlang_mul_2(Context *ctx, int live, term arg1, term arg2) if (!BUILTIN_MUL_OVERFLOW(a, b, &res)) { return res | TERM_INTEGER_TAG; } else { - return mul_overflow_helper(ctx, live, arg1, arg2); + return mul_overflow_helper(ctx, x_regs, live, arg1, arg2); } } else { - return mul_boxed_helper(ctx, live, arg1, arg2); + return mul_boxed_helper(ctx, x_regs, live, arg1, arg2); } } -static term div_boxed_helper(Context *ctx, uint32_t live, term arg1, term arg2) +static term div_boxed_helper(Context *ctx, term *x_regs, uint32_t live, term arg1, term arg2) { int size = 0; if (term_is_boxed_integer(arg1)) { @@ -710,7 +735,7 @@ static term div_boxed_helper(Context *ctx, uint32_t live, term arg1, term arg2) } else if (UNLIKELY((val2 == -1) && (val1 == AVM_INT_MIN))) { #if BOXED_TERMS_REQUIRED_FOR_INT64 == 2 - return make_boxed_int64(ctx, live, -((avm_int64_t) AVM_INT_MIN)); + return make_boxed_int64(ctx, x_regs, live, -((avm_int64_t) AVM_INT_MIN)); #elif BOXED_TERMS_REQUIRED_FOR_INT64 == 1 TRACE("overflow: arg1: 0x%lx, arg2: 0x%lx\n", arg1, arg2); @@ -718,7 +743,7 @@ static term div_boxed_helper(Context *ctx, uint32_t live, term arg1, term arg2) #endif } else { - return make_maybe_boxed_int(ctx, live, val1 / val2); + return make_maybe_boxed_int(ctx, x_regs, live, val1 / val2); } } @@ -735,7 +760,7 @@ static term div_boxed_helper(Context *ctx, uint32_t live, term arg1, term arg2) RAISE_ERROR(OVERFLOW_ATOM); } else { - return make_maybe_boxed_int64(ctx, live, val1 / val2); + return make_maybe_boxed_int64(ctx, x_regs, live, val1 / val2); } } #endif @@ -745,7 +770,7 @@ static term div_boxed_helper(Context *ctx, uint32_t live, term arg1, term arg2) } } -term bif_erlang_div_2(Context *ctx, int live, term arg1, term arg2) +term bif_erlang_div_2(Context *ctx, term *x_regs, int live, term arg1, term arg2) { UNUSED(live); @@ -754,7 +779,7 @@ term bif_erlang_div_2(Context *ctx, int live, term arg1, term arg2) if (operand_b != 0) { avm_int_t res = term_to_int(arg1) / operand_b; if (UNLIKELY(res == -MIN_NOT_BOXED_INT)) { - return make_boxed_int(ctx, live, -MIN_NOT_BOXED_INT); + return make_boxed_int(ctx, x_regs, live, -MIN_NOT_BOXED_INT); } else { return term_from_int(res); @@ -764,11 +789,11 @@ term bif_erlang_div_2(Context *ctx, int live, term arg1, term arg2) } } else { - return div_boxed_helper(ctx, live, arg1, arg2); + return div_boxed_helper(ctx, x_regs, live, arg1, arg2); } } -static term neg_boxed_helper(Context *ctx, uint32_t live, term arg1) +static term neg_boxed_helper(Context *ctx, term *x_regs, uint32_t live, term arg1) { if (term_is_float(arg1)) { avm_float_t farg1 = term_conv_to_float(arg1); @@ -776,7 +801,7 @@ static term neg_boxed_helper(Context *ctx, uint32_t live, term arg1) if (UNLIKELY(!isfinite(fresult))) { RAISE_ERROR(BADARITH_ATOM); } - if (UNLIKELY(memory_ensure_free_with_roots(ctx, FLOAT_SIZE, live, ctx->x, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { + if (UNLIKELY(memory_ensure_free_with_roots(ctx, FLOAT_SIZE, live, x_regs, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { RAISE_ERROR(OUT_OF_MEMORY_ATOM); } return term_from_float(fresult, &ctx->heap); @@ -796,7 +821,7 @@ static term neg_boxed_helper(Context *ctx, uint32_t live, term arg1) case AVM_INT_MIN: #if BOXED_TERMS_REQUIRED_FOR_INT64 == 2 - return make_boxed_int64(ctx, live, -((avm_int64_t) val)); + return make_boxed_int64(ctx, x_regs, live, -((avm_int64_t) val)); #elif BOXED_TERMS_REQUIRED_FOR_INT64 == 1 TRACE("overflow: val: " AVM_INT_FMT "\n", val); @@ -807,7 +832,7 @@ static term neg_boxed_helper(Context *ctx, uint32_t live, term arg1) #endif default: - return make_boxed_int(ctx, live, -val); + return make_boxed_int(ctx, x_regs, live, -val); } } @@ -820,7 +845,7 @@ static term neg_boxed_helper(Context *ctx, uint32_t live, term arg1) RAISE_ERROR(OVERFLOW_ATOM); } else { - return make_boxed_int64(ctx, live, -val); + return make_boxed_int64(ctx, x_regs, live, -val); } } #endif @@ -833,23 +858,23 @@ static term neg_boxed_helper(Context *ctx, uint32_t live, term arg1) } } -term bif_erlang_neg_1(Context *ctx, int live, term arg1) +term bif_erlang_neg_1(Context *ctx, term *x_regs, int live, term arg1) { UNUSED(live); if (LIKELY(term_is_integer(arg1))) { avm_int_t int_val = term_to_int(arg1); if (UNLIKELY(int_val == MIN_NOT_BOXED_INT)) { - return make_boxed_int(ctx, live, -MIN_NOT_BOXED_INT); + return make_boxed_int(ctx, x_regs, live, -MIN_NOT_BOXED_INT); } else { return term_from_int(-int_val); } } else { - return neg_boxed_helper(ctx, live, arg1); + return neg_boxed_helper(ctx, x_regs, live, arg1); } } -static term abs_boxed_helper(Context *ctx, uint32_t live, term arg1) +static term abs_boxed_helper(Context *ctx, term *x_regs, uint32_t live, term arg1) { if (term_is_float(arg1)) { avm_float_t farg1 = term_conv_to_float(arg1); @@ -863,7 +888,7 @@ static term abs_boxed_helper(Context *ctx, uint32_t live, term arg1) if (UNLIKELY(!isfinite(fresult))) { RAISE_ERROR(BADARITH_ATOM); } - if (UNLIKELY(memory_ensure_free_with_roots(ctx, FLOAT_SIZE, live, ctx->x, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { + if (UNLIKELY(memory_ensure_free_with_roots(ctx, FLOAT_SIZE, live, x_regs, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { RAISE_ERROR(OUT_OF_MEMORY_ATOM); } return term_from_float(fresult, &ctx->heap); @@ -883,7 +908,7 @@ static term abs_boxed_helper(Context *ctx, uint32_t live, term arg1) if (val == AVM_INT_MIN) { #if BOXED_TERMS_REQUIRED_FOR_INT64 == 2 - return make_boxed_int64(ctx, live, -((avm_int64_t) val)); + return make_boxed_int64(ctx, x_regs, live, -((avm_int64_t) val)); #elif BOXED_TERMS_REQUIRED_FOR_INT64 == 1 TRACE("overflow: val: " AVM_INT_FMT "\n", val); @@ -894,7 +919,7 @@ static term abs_boxed_helper(Context *ctx, uint32_t live, term arg1) #endif } else { - return make_boxed_int(ctx, live, -val); + return make_boxed_int(ctx, x_regs, live, -val); } } @@ -910,7 +935,7 @@ static term abs_boxed_helper(Context *ctx, uint32_t live, term arg1) RAISE_ERROR(OVERFLOW_ATOM); } else { - return make_boxed_int64(ctx, live, -val); + return make_boxed_int64(ctx, x_regs, live, -val); } } #endif @@ -923,7 +948,7 @@ static term abs_boxed_helper(Context *ctx, uint32_t live, term arg1) } } -term bif_erlang_abs_1(Context *ctx, int live, term arg1) +term bif_erlang_abs_1(Context *ctx, term *x_regs, int live, term arg1) { UNUSED(live); @@ -932,7 +957,7 @@ term bif_erlang_abs_1(Context *ctx, int live, term arg1) if (int_val < 0) { if (UNLIKELY(int_val == MIN_NOT_BOXED_INT)) { - return make_boxed_int(ctx, live, -MIN_NOT_BOXED_INT); + return make_boxed_int(ctx, x_regs, live, -MIN_NOT_BOXED_INT); } else { return term_from_int(-int_val); } @@ -941,11 +966,11 @@ term bif_erlang_abs_1(Context *ctx, int live, term arg1) } } else { - return abs_boxed_helper(ctx, live, arg1); + return abs_boxed_helper(ctx, x_regs, live, arg1); } } -static term rem_boxed_helper(Context *ctx, uint32_t live, term arg1, term arg2) +static term rem_boxed_helper(Context *ctx, term *x_regs, uint32_t live, term arg1, term arg2) { int size = 0; if (term_is_boxed_integer(arg1)) { @@ -974,7 +999,7 @@ static term rem_boxed_helper(Context *ctx, uint32_t live, term arg1, term arg2) RAISE_ERROR(BADARITH_ATOM); } - return make_maybe_boxed_int(ctx, live, val1 % val2); + return make_maybe_boxed_int(ctx, x_regs, live, val1 % val2); } #if BOXED_TERMS_REQUIRED_FOR_INT64 == 2 @@ -986,7 +1011,7 @@ static term rem_boxed_helper(Context *ctx, uint32_t live, term arg1, term arg2) RAISE_ERROR(BADARITH_ATOM); } - return make_maybe_boxed_int64(ctx, live, val1 % val2); + return make_maybe_boxed_int64(ctx, x_regs, live, val1 % val2); } #endif @@ -995,7 +1020,7 @@ static term rem_boxed_helper(Context *ctx, uint32_t live, term arg1, term arg2) } } -term bif_erlang_rem_2(Context *ctx, int live, term arg1, term arg2) +term bif_erlang_rem_2(Context *ctx, term *x_regs, int live, term arg1, term arg2) { UNUSED(live); @@ -1009,11 +1034,11 @@ term bif_erlang_rem_2(Context *ctx, int live, term arg1, term arg2) } } else { - return rem_boxed_helper(ctx, live, arg1, arg2); + return rem_boxed_helper(ctx, x_regs, live, arg1, arg2); } } -term bif_erlang_ceil_1(Context *ctx, int live, term arg1) +term bif_erlang_ceil_1(Context *ctx, term *x_regs, int live, term arg1) { UNUSED(live); @@ -1031,9 +1056,9 @@ term bif_erlang_ceil_1(Context *ctx, int live, term arg1) #endif #if BOXED_TERMS_REQUIRED_FOR_INT64 > 1 - return make_maybe_boxed_int64(ctx, live, result); + return make_maybe_boxed_int64(ctx, x_regs, live, result); #else - return make_maybe_boxed_int(ctx, live, result); + return make_maybe_boxed_int(ctx, x_regs, live, result); #endif } @@ -1045,7 +1070,7 @@ term bif_erlang_ceil_1(Context *ctx, int live, term arg1) } } -term bif_erlang_floor_1(Context *ctx, int live, term arg1) +term bif_erlang_floor_1(Context *ctx, term *x_regs, int live, term arg1) { UNUSED(live); @@ -1063,9 +1088,9 @@ term bif_erlang_floor_1(Context *ctx, int live, term arg1) #endif #if BOXED_TERMS_REQUIRED_FOR_INT64 > 1 - return make_maybe_boxed_int64(ctx, live, result); + return make_maybe_boxed_int64(ctx, x_regs, live, result); #else - return make_maybe_boxed_int(ctx, live, result); + return make_maybe_boxed_int(ctx, x_regs, live, result); #endif } @@ -1077,7 +1102,7 @@ term bif_erlang_floor_1(Context *ctx, int live, term arg1) } } -term bif_erlang_round_1(Context *ctx, int live, term arg1) +term bif_erlang_round_1(Context *ctx, term *x_regs, int live, term arg1) { UNUSED(live); @@ -1095,9 +1120,9 @@ term bif_erlang_round_1(Context *ctx, int live, term arg1) #endif #if BOXED_TERMS_REQUIRED_FOR_INT64 > 1 - return make_maybe_boxed_int64(ctx, live, result); + return make_maybe_boxed_int64(ctx, x_regs, live, result); #else - return make_maybe_boxed_int(ctx, live, result); + return make_maybe_boxed_int(ctx, x_regs, live, result); #endif } @@ -1109,7 +1134,7 @@ term bif_erlang_round_1(Context *ctx, int live, term arg1) } } -term bif_erlang_trunc_1(Context *ctx, int live, term arg1) +term bif_erlang_trunc_1(Context *ctx, term *x_regs, int live, term arg1) { UNUSED(live); @@ -1127,9 +1152,9 @@ term bif_erlang_trunc_1(Context *ctx, int live, term arg1) #endif #if BOXED_TERMS_REQUIRED_FOR_INT64 > 1 - return make_maybe_boxed_int64(ctx, live, result); + return make_maybe_boxed_int64(ctx, x_regs, live, result); #else - return make_maybe_boxed_int(ctx, live, result); + return make_maybe_boxed_int(ctx, x_regs, live, result); #endif } @@ -1143,7 +1168,7 @@ term bif_erlang_trunc_1(Context *ctx, int live, term arg1) typedef int64_t (*bitwise_op)(int64_t a, int64_t b); -static inline term bitwise_helper(Context *ctx, int live, term arg1, term arg2, bitwise_op op) +static inline term bitwise_helper(Context *ctx, term *x_regs, int live, term arg1, term arg2, bitwise_op op) { UNUSED(live); @@ -1156,9 +1181,9 @@ static inline term bitwise_helper(Context *ctx, int live, term arg1, term arg2, int64_t result = op(a, b); #if BOXED_TERMS_REQUIRED_FOR_INT64 > 1 - return make_maybe_boxed_int64(ctx, live, result); + return make_maybe_boxed_int64(ctx, x_regs, live, result); #else - return make_maybe_boxed_int(ctx, live, result); + return make_maybe_boxed_int(ctx, x_regs, live, result); #endif } @@ -1167,12 +1192,12 @@ static inline int64_t bor(int64_t a, int64_t b) return a | b; } -term bif_erlang_bor_2(Context *ctx, int live, term arg1, term arg2) +term bif_erlang_bor_2(Context *ctx, term *x_regs, int live, term arg1, term arg2) { if (LIKELY(term_is_integer(arg1) && term_is_integer(arg2))) { return arg1 | arg2; } else { - return bitwise_helper(ctx, live, arg1, arg2, bor); + return bitwise_helper(ctx, x_regs, live, arg1, arg2, bor); } } @@ -1181,12 +1206,12 @@ static inline int64_t band(int64_t a, int64_t b) return a & b; } -term bif_erlang_band_2(Context *ctx, int live, term arg1, term arg2) +term bif_erlang_band_2(Context *ctx, term *x_regs, int live, term arg1, term arg2) { if (LIKELY(term_is_integer(arg1) && term_is_integer(arg2))) { return arg1 & arg2; } else { - return bitwise_helper(ctx, live, arg1, arg2, band); + return bitwise_helper(ctx, x_regs, live, arg1, arg2, band); } } @@ -1195,18 +1220,18 @@ static inline int64_t bxor(int64_t a, int64_t b) return a ^ b; } -term bif_erlang_bxor_2(Context *ctx, int live, term arg1, term arg2) +term bif_erlang_bxor_2(Context *ctx, term *x_regs, int live, term arg1, term arg2) { if (LIKELY(term_is_integer(arg1) && term_is_integer(arg2))) { return (arg1 ^ arg2) | TERM_INTEGER_TAG; } else { - return bitwise_helper(ctx, live, arg1, arg2, bxor); + return bitwise_helper(ctx, x_regs, live, arg1, arg2, bxor); } } typedef int64_t (*bitshift_op)(int64_t a, avm_int_t b); -static inline term bitshift_helper(Context *ctx, int live, term arg1, term arg2, bitshift_op op) +static inline term bitshift_helper(Context *ctx, term *x_regs, int live, term arg1, term arg2, bitshift_op op) { UNUSED(live); @@ -1219,9 +1244,9 @@ static inline term bitshift_helper(Context *ctx, int live, term arg1, term arg2, int64_t result = op(a, b); #if BOXED_TERMS_REQUIRED_FOR_INT64 > 1 - return make_maybe_boxed_int64(ctx, live, result); + return make_maybe_boxed_int64(ctx, x_regs, live, result); #else - return make_maybe_boxed_int(ctx, live, result); + return make_maybe_boxed_int(ctx, x_regs, live, result); #endif } @@ -1231,9 +1256,9 @@ static inline int64_t bsl(int64_t a, avm_int_t b) return a << b; } -term bif_erlang_bsl_2(Context *ctx, int live, term arg1, term arg2) +term bif_erlang_bsl_2(Context *ctx, term *x_regs, int live, term arg1, term arg2) { - return bitshift_helper(ctx, live, arg1, arg2, bsl); + return bitshift_helper(ctx, x_regs, live, arg1, arg2, bsl); } static inline int64_t bsr(int64_t a, avm_int_t b) @@ -1242,13 +1267,14 @@ static inline int64_t bsr(int64_t a, avm_int_t b) return a >> b; } -term bif_erlang_bsr_2(Context *ctx, int live, term arg1, term arg2) +term bif_erlang_bsr_2(Context *ctx, term *x_regs, int live, term arg1, term arg2) { - return bitshift_helper(ctx, live, arg1, arg2, bsr); + return bitshift_helper(ctx, x_regs, live, arg1, arg2, bsr); } -term bif_erlang_bnot_1(Context *ctx, int live, term arg1) +term bif_erlang_bnot_1(Context *ctx, term *x_regs, int live, term arg1) { + UNUSED(ctx); UNUSED(live); if (LIKELY(term_is_integer(arg1))) { @@ -1259,8 +1285,10 @@ term bif_erlang_bnot_1(Context *ctx, int live, term arg1) } } -term bif_erlang_not_1(Context *ctx, term arg1) +term bif_erlang_not_1(Context *ctx, term *x_regs, term arg1) { + UNUSED(ctx); + if (arg1 == TRUE_ATOM) { return FALSE_ATOM; @@ -1272,8 +1300,10 @@ term bif_erlang_not_1(Context *ctx, term arg1) } } -term bif_erlang_and_2(Context *ctx, term arg1, term arg2) +term bif_erlang_and_2(Context *ctx, term *x_regs, term arg1, term arg2) { + UNUSED(ctx); + if ((arg1 == FALSE_ATOM) && (arg2 == FALSE_ATOM)) { return FALSE_ATOM; @@ -1291,8 +1321,10 @@ term bif_erlang_and_2(Context *ctx, term arg1, term arg2) } } -term bif_erlang_or_2(Context *ctx, term arg1, term arg2) +term bif_erlang_or_2(Context *ctx, term *x_regs, term arg1, term arg2) { + UNUSED(ctx); + if ((arg1 == FALSE_ATOM) && (arg2 == FALSE_ATOM)) { return FALSE_ATOM; @@ -1310,8 +1342,10 @@ term bif_erlang_or_2(Context *ctx, term arg1, term arg2) } } -term bif_erlang_xor_2(Context *ctx, term arg1, term arg2) +term bif_erlang_xor_2(Context *ctx, term *x_regs, term arg1, term arg2) { + UNUSED(ctx); + if ((arg1 == FALSE_ATOM) && (arg2 == FALSE_ATOM)) { return FALSE_ATOM; @@ -1329,7 +1363,7 @@ term bif_erlang_xor_2(Context *ctx, term arg1, term arg2) } } -term bif_erlang_equal_to_2(Context *ctx, term arg1, term arg2) +term bif_erlang_equal_to_2(Context *ctx, term *x_regs, term arg1, term arg2) { TermCompareResult result = term_compare(arg1, arg2, TermCompareNoOpts, ctx->global); if (result == TermEquals) { @@ -1341,7 +1375,7 @@ term bif_erlang_equal_to_2(Context *ctx, term arg1, term arg2) } } -term bif_erlang_not_equal_to_2(Context *ctx, term arg1, term arg2) +term bif_erlang_not_equal_to_2(Context *ctx, term *x_regs, term arg1, term arg2) { TermCompareResult result = term_compare(arg1, arg2, TermCompareNoOpts, ctx->global); if (result & (TermLessThan | TermGreaterThan)) { @@ -1353,7 +1387,7 @@ term bif_erlang_not_equal_to_2(Context *ctx, term arg1, term arg2) } } -term bif_erlang_exactly_equal_to_2(Context *ctx, term arg1, term arg2) +term bif_erlang_exactly_equal_to_2(Context *ctx, term *x_regs, term arg1, term arg2) { //TODO: 5.0 != 5 TermCompareResult result = term_compare(arg1, arg2, TermCompareExact, ctx->global); @@ -1366,7 +1400,7 @@ term bif_erlang_exactly_equal_to_2(Context *ctx, term arg1, term arg2) } } -term bif_erlang_exactly_not_equal_to_2(Context *ctx, term arg1, term arg2) +term bif_erlang_exactly_not_equal_to_2(Context *ctx, term *x_regs, term arg1, term arg2) { TermCompareResult result = term_compare(arg1, arg2, TermCompareExact, ctx->global); if (result & (TermLessThan | TermGreaterThan)) { @@ -1378,7 +1412,7 @@ term bif_erlang_exactly_not_equal_to_2(Context *ctx, term arg1, term arg2) } } -term bif_erlang_greater_than_2(Context *ctx, term arg1, term arg2) +term bif_erlang_greater_than_2(Context *ctx, term *x_regs, term arg1, term arg2) { TermCompareResult result = term_compare(arg1, arg2, TermCompareNoOpts, ctx->global); if (result == TermGreaterThan) { @@ -1390,7 +1424,7 @@ term bif_erlang_greater_than_2(Context *ctx, term arg1, term arg2) } } -term bif_erlang_less_than_2(Context *ctx, term arg1, term arg2) +term bif_erlang_less_than_2(Context *ctx, term *x_regs, term arg1, term arg2) { TermCompareResult result = term_compare(arg1, arg2, TermCompareNoOpts, ctx->global); if (result == TermLessThan) { @@ -1402,7 +1436,7 @@ term bif_erlang_less_than_2(Context *ctx, term arg1, term arg2) } } -term bif_erlang_less_than_or_equal_2(Context *ctx, term arg1, term arg2) +term bif_erlang_less_than_or_equal_2(Context *ctx, term *x_regs, term arg1, term arg2) { TermCompareResult result = term_compare(arg1, arg2, TermCompareNoOpts, ctx->global); if (result & (TermLessThan | TermEquals)) { @@ -1414,7 +1448,7 @@ term bif_erlang_less_than_or_equal_2(Context *ctx, term arg1, term arg2) } } -term bif_erlang_greater_than_or_equal_2(Context *ctx, term arg1, term arg2) +term bif_erlang_greater_than_or_equal_2(Context *ctx, term *x_regs, term arg1, term arg2) { TermCompareResult result = term_compare(arg1, arg2, TermCompareNoOpts, ctx->global); if (result & (TermGreaterThan | TermEquals)) { @@ -1426,7 +1460,7 @@ term bif_erlang_greater_than_or_equal_2(Context *ctx, term arg1, term arg2) } } -term bif_erlang_get_1(Context *ctx, term arg1) +term bif_erlang_get_1(Context *ctx, term *x_regs, term arg1) { term value; DictionaryFunctionResult result = dictionary_get(&ctx->dictionary, arg1, &value, ctx->global); @@ -1437,7 +1471,7 @@ term bif_erlang_get_1(Context *ctx, term arg1) return value; } -term bif_erlang_min_2(Context *ctx, term arg1, term arg2) +term bif_erlang_min_2(Context *ctx, term *x_regs, term arg1, term arg2) { TermCompareResult r = term_compare(arg1, arg2, TermCompareNoOpts, ctx->global); if (UNLIKELY(r == TermCompareMemoryAllocFail)) { @@ -1446,7 +1480,7 @@ term bif_erlang_min_2(Context *ctx, term arg1, term arg2) return r == TermLessThan ? arg1 : arg2; } -term bif_erlang_max_2(Context *ctx, term arg1, term arg2) +term bif_erlang_max_2(Context *ctx, term *x_regs, term arg1, term arg2) { TermCompareResult r = term_compare(arg1, arg2, TermCompareNoOpts, ctx->global); if (UNLIKELY(r == TermCompareMemoryAllocFail)) { diff --git a/src/libAtomVM/bif.h b/src/libAtomVM/bif.h index 18266d1865..742dd71842 100644 --- a/src/libAtomVM/bif.h +++ b/src/libAtomVM/bif.h @@ -41,74 +41,74 @@ extern "C" { const struct ExportedFunction *bif_registry_get_handler(AtomString module, AtomString function, int arity); -term bif_erlang_self_0(Context *ctx); -term bif_erlang_byte_size_1(Context *ctx, int live, term arg1); -term bif_erlang_bit_size_1(Context *ctx, int live, term arg1); -term bif_erlang_length_1(Context *ctx, int live, term arg1); - -term bif_erlang_is_atom_1(Context *ctx, term arg1); -term bif_erlang_is_binary_1(Context *ctx, term arg1); -term bif_erlang_is_boolean_1(Context *ctx, term arg1); -term bif_erlang_is_float_1(Context *ctx, term arg1); -term bif_erlang_is_function_1(Context *ctx, term arg1); -term bif_erlang_is_integer_1(Context *ctx, term arg1); -term bif_erlang_is_list_1(Context *ctx, term arg1); -term bif_erlang_is_number_1(Context *ctx, term arg1); -term bif_erlang_is_pid_1(Context *ctx, term arg1); -term bif_erlang_is_reference_1(Context *ctx, term arg1); -term bif_erlang_is_tuple_1(Context *ctx, term arg1); -term bif_erlang_is_map_1(Context *ctx, term arg1); -term bif_erlang_is_map_key_2(Context *ctx, term arg1, term arg2); - -term bif_erlang_hd_1(Context *ctx, term arg1); -term bif_erlang_tl_1(Context *ctx, term arg1); - -term bif_erlang_element_2(Context *ctx, term arg1, term arg2); -term bif_erlang_tuple_size_1(Context *ctx, term arg1); - -term bif_erlang_map_size_1(Context *ctx, int live, term arg1); -term bif_erlang_map_get_2(Context *ctx, term arg1, term arg2); - -term bif_erlang_add_2(Context *ctx, int live, term arg1, term arg2); -term bif_erlang_sub_2(Context *ctx, int live, term arg1, term arg2); -term bif_erlang_mul_2(Context *ctx, int live, term arg1, term arg2); -term bif_erlang_div_2(Context *ctx, int live, term arg1, term arg2); -term bif_erlang_rem_2(Context *ctx, int live, term arg1, term arg2); -term bif_erlang_neg_1(Context *ctx, int live, term arg1); -term bif_erlang_abs_1(Context *ctx, int live, term arg1); - -term bif_erlang_ceil_1(Context *ctx, int live, term arg1); -term bif_erlang_floor_1(Context *ctx, int live, term arg1); -term bif_erlang_round_1(Context *ctx, int live, term arg1); -term bif_erlang_trunc_1(Context *ctx, int live, term arg1); - -term bif_erlang_bor_2(Context *ctx, int live, term arg1, term arg2); -term bif_erlang_band_2(Context *ctx, int live, term arg1, term arg2); -term bif_erlang_bxor_2(Context *ctx, int live, term arg1, term arg2); -term bif_erlang_bsl_2(Context *ctx, int live, term arg1, term arg2); -term bif_erlang_bsr_2(Context *ctx, int live, term arg1, term arg2); -term bif_erlang_bnot_1(Context *ctx, int live, term arg1); - -term bif_erlang_not_1(Context *ctx, term arg1); -term bif_erlang_and_2(Context *ctx, term arg1, term arg2); -term bif_erlang_or_2(Context *ctx, term arg1, term arg2); -term bif_erlang_xor_2(Context *ctx, term arg1, term arg2); - -term bif_erlang_equal_to_2(Context *ctx, term arg1, term arg2); -term bif_erlang_not_equal_to_2(Context *ctx, term arg1, term arg2); - -term bif_erlang_exactly_equal_to_2(Context *ctx, term arg1, term arg2); -term bif_erlang_exactly_not_equal_to_2(Context *ctx, term arg1, term arg2); - -term bif_erlang_greater_than_2(Context *ctx, term arg1, term arg2); -term bif_erlang_less_than_2(Context *ctx, term arg1, term arg2); -term bif_erlang_less_than_or_equal_2(Context *ctx, term arg1, term arg2); -term bif_erlang_greater_than_or_equal_2(Context *ctx, term arg1, term arg2); - -term bif_erlang_get_1(Context *ctx, term arg1); - -term bif_erlang_min_2(Context *ctx, term arg1, term arg2); -term bif_erlang_max_2(Context *ctx, term arg1, term arg2); +term bif_erlang_self_0(Context *ctx, term *x_regs); +term bif_erlang_byte_size_1(Context *ctx, term *x_regs, int live, term arg1); +term bif_erlang_bit_size_1(Context *ctx, term *x_regs, int live, term arg1); +term bif_erlang_length_1(Context *ctx, term *x_regs, int live, term arg1); + +term bif_erlang_is_atom_1(Context *ctx, term *x_regs, term arg1); +term bif_erlang_is_binary_1(Context *ctx, term *x_regs, term arg1); +term bif_erlang_is_boolean_1(Context *ctx, term *x_regs, term arg1); +term bif_erlang_is_float_1(Context *ctx, term *x_regs, term arg1); +term bif_erlang_is_function_1(Context *ctx, term *x_regs, term arg1); +term bif_erlang_is_integer_1(Context *ctx, term *x_regs, term arg1); +term bif_erlang_is_list_1(Context *ctx, term *x_regs, term arg1); +term bif_erlang_is_number_1(Context *ctx, term *x_regs, term arg1); +term bif_erlang_is_pid_1(Context *ctx, term *x_regs, term arg1); +term bif_erlang_is_reference_1(Context *ctx, term *x_regs, term arg1); +term bif_erlang_is_tuple_1(Context *ctx, term *x_regs, term arg1); +term bif_erlang_is_map_1(Context *ctx, term *x_regs, term arg1); +term bif_erlang_is_map_key_2(Context *ctx, term *x_regs, term arg1, term arg2); + +term bif_erlang_hd_1(Context *ctx, term *x_regs, term arg1); +term bif_erlang_tl_1(Context *ctx, term *x_regs, term arg1); + +term bif_erlang_element_2(Context *ctx, term *x_regs, term arg1, term arg2); +term bif_erlang_tuple_size_1(Context *ctx, term *x_regs, term arg1); + +term bif_erlang_map_size_1(Context *ctx, term *x_regs, int live, term arg1); +term bif_erlang_map_get_2(Context *ctx, term *x_regs, term arg1, term arg2); + +term bif_erlang_add_2(Context *ctx, term *x_regs, int live, term arg1, term arg2); +term bif_erlang_sub_2(Context *ctx, term *x_regs, int live, term arg1, term arg2); +term bif_erlang_mul_2(Context *ctx, term *x_regs, int live, term arg1, term arg2); +term bif_erlang_div_2(Context *ctx, term *x_regs, int live, term arg1, term arg2); +term bif_erlang_rem_2(Context *ctx, term *x_regs, int live, term arg1, term arg2); +term bif_erlang_neg_1(Context *ctx, term *x_regs, int live, term arg1); +term bif_erlang_abs_1(Context *ctx, term *x_regs, int live, term arg1); + +term bif_erlang_ceil_1(Context *ctx, term *x_regs, int live, term arg1); +term bif_erlang_floor_1(Context *ctx, term *x_regs, int live, term arg1); +term bif_erlang_round_1(Context *ctx, term *x_regs, int live, term arg1); +term bif_erlang_trunc_1(Context *ctx, term *x_regs, int live, term arg1); + +term bif_erlang_bor_2(Context *ctx, term *x_regs, int live, term arg1, term arg2); +term bif_erlang_band_2(Context *ctx, term *x_regs, int live, term arg1, term arg2); +term bif_erlang_bxor_2(Context *ctx, term *x_regs, int live, term arg1, term arg2); +term bif_erlang_bsl_2(Context *ctx, term *x_regs, int live, term arg1, term arg2); +term bif_erlang_bsr_2(Context *ctx, term *x_regs, int live, term arg1, term arg2); +term bif_erlang_bnot_1(Context *ctx, term *x_regs, int live, term arg1); + +term bif_erlang_not_1(Context *ctx, term *x_regs, term arg1); +term bif_erlang_and_2(Context *ctx, term *x_regs, term arg1, term arg2); +term bif_erlang_or_2(Context *ctx, term *x_regs, term arg1, term arg2); +term bif_erlang_xor_2(Context *ctx, term *x_regs, term arg1, term arg2); + +term bif_erlang_equal_to_2(Context *ctx, term *x_regs, term arg1, term arg2); +term bif_erlang_not_equal_to_2(Context *ctx, term *x_regs, term arg1, term arg2); + +term bif_erlang_exactly_equal_to_2(Context *ctx, term *x_regs, term arg1, term arg2); +term bif_erlang_exactly_not_equal_to_2(Context *ctx, term *x_regs, term arg1, term arg2); + +term bif_erlang_greater_than_2(Context *ctx, term *x_regs, term arg1, term arg2); +term bif_erlang_less_than_2(Context *ctx, term *x_regs, term arg1, term arg2); +term bif_erlang_less_than_or_equal_2(Context *ctx, term *x_regs, term arg1, term arg2); +term bif_erlang_greater_than_or_equal_2(Context *ctx, term *x_regs, term arg1, term arg2); + +term bif_erlang_get_1(Context *ctx, term *x_regs, term arg1); + +term bif_erlang_min_2(Context *ctx, term *x_regs, term arg1, term arg2); +term bif_erlang_max_2(Context *ctx, term *x_regs, term arg1, term arg2); #ifdef __cplusplus } diff --git a/src/libAtomVM/context.c b/src/libAtomVM/context.c index 01ea786a63..ae16068ce6 100644 --- a/src/libAtomVM/context.c +++ b/src/libAtomVM/context.c @@ -60,8 +60,9 @@ Context *context_new(GlobalContext *glb) } ctx->e = ctx->heap.heap_end; - context_clean_registers(ctx, 0); - + ctx->xregs_count = 0; + ctx->fpregs_count = 0; + ctx->saved_x = NULL; ctx->fr = NULL; ctx->min_heap_size = 0; @@ -151,6 +152,7 @@ void context_destroy(Context *ctx) // Any other process released our mailbox, so we can clear it. mailbox_destroy(&ctx->mailbox, &ctx->heap); + free(ctx->saved_x); free(ctx->fr); memory_destroy_heap(&ctx->heap, ctx->global); @@ -195,14 +197,14 @@ void context_process_process_info_request_signal(Context *ctx, struct BuiltInAto } // else: sender died } -bool context_process_signal_trap_answer(Context *ctx, struct TermSignal *signal) +bool context_process_signal_trap_answer(Context *ctx, term *x_regs, struct TermSignal *signal) { context_update_flags(ctx, ~Trap, NoFlags); - ctx->x[0] = signal->signal_term; + x_regs[0] = signal->signal_term; return true; } -void context_process_flush_monitor_signal(Context *ctx, uint64_t ref_ticks, bool info) +void context_process_flush_monitor_signal(Context *ctx, term *x_regs, uint64_t ref_ticks, bool info) { context_update_flags(ctx, ~Trap, NoFlags); bool result = true; @@ -222,7 +224,7 @@ void context_process_flush_monitor_signal(Context *ctx, uint64_t ref_ticks, bool } } mailbox_reset(&ctx->mailbox); - ctx->x[0] = result ? TRUE_ATOM : FALSE_ATOM; + x_regs[0] = result ? TRUE_ATOM : FALSE_ATOM; } void context_update_flags(Context *ctx, int mask, int value) CLANG_THREAD_SANITIZE_SAFE diff --git a/src/libAtomVM/context.h b/src/libAtomVM/context.h index c8ef56da2f..69d950f327 100644 --- a/src/libAtomVM/context.h +++ b/src/libAtomVM/context.h @@ -74,9 +74,7 @@ enum HeapGrowthStrategy FibonacciHeapGrowth }; -// Max number of x(N) & fr(N) registers -// BEAM sets this to 1024. -#define MAX_REG 16 +#define MAX_REG 1024 struct Context { @@ -84,7 +82,10 @@ struct Context GlobalContext *global; Heap heap; term *e; - term x[MAX_REG]; + term *saved_x; + avm_float_t *fr; + uint16_t xregs_count; + uint16_t fpregs_count; struct ListHead processes_list_head; @@ -95,8 +96,6 @@ struct Context struct ListHead monitors_head; - avm_float_t *fr; - size_t min_heap_size; size_t max_heap_size; enum HeapGrowthStrategy heap_growth_strategy; @@ -189,18 +188,69 @@ Context *context_new(GlobalContext *glb); void context_destroy(Context *c); /** - * @brief Ensure we have FP registers, allocating them if necessary. - * @param c context fo allocate FP registers for + * @brief Ensure at least a given number of FP registers are available, + * allocating them if necessary. + * @param c context to allocate FP registers for + * @param n_regs number of registers to allocate + */ +static inline void context_ensure_fpregs(Context *c, uint16_t n_regs) +{ + if (n_regs > c->fpregs_count) { + size_t new_size = sizeof(avm_float_t) * n_regs; + if (IS_NULL_PTR(c->fr)) { + c->fr = (avm_float_t *) malloc(new_size); + if (IS_NULL_PTR(c->fr)) { + fprintf(stderr, "Could not allocate FP registers\n"); + AVM_ABORT(); + } + } else { + c->fr = realloc(c->fr, new_size); + if (IS_NULL_PTR(c->fr)) { + fprintf(stderr, "Could not allocate FP registers\n"); + AVM_ABORT(); + } + } + c->fpregs_count = n_regs; + } +} + +/** + * @brief Saved registers before context switching. + * @param c context to save registers to + * @param x_regs registers to save + * @param n_regs number of registers to save */ -static inline void context_ensure_fpregs(Context *c) +static inline void context_save_xregs(Context *c, term *x_regs, uint16_t n_regs) { - if (UNLIKELY(c->fr == NULL)) { - c->fr = (avm_float_t *) malloc(sizeof(avm_float_t) * MAX_REG); - if (UNLIKELY(c->fr == NULL)) { - fprintf(stderr, "Could not allocate FP registers\n"); - AVM_ABORT(); + size_t new_size = sizeof(term) * n_regs; + if (n_regs > c->xregs_count) { + if (UNLIKELY(c->saved_x == NULL)) { + c->saved_x = (term *) malloc(new_size); + if (IS_NULL_PTR(c->saved_x)) { + fprintf(stderr, "Could not allocate X registers\n"); + AVM_ABORT(); + } + } else { + c->saved_x = realloc(c->saved_x, new_size); + if (IS_NULL_PTR(c->saved_x)) { + fprintf(stderr, "Could not allocate X registers\n"); + AVM_ABORT(); + } } } + memcpy(c->saved_x, x_regs, new_size); + c->xregs_count = n_regs; +} + +/** + * @brief Restore registers after context switching. + * @param c context to restore registers from + * @param x_regs registers to restore + */ +static inline void context_restore_xregs(Context *c, term *x_regs) +{ + size_t size = sizeof(term) * c->xregs_count; + memcpy(x_regs, c->saved_x, size); } /** @@ -227,20 +277,6 @@ static inline int context_is_port_driver(const Context *ctx) return ctx->native_handler != NULL; } -/** - * @brief Cleans up unused registers - * - * @details Sets to NIL unused registers, x[0] - x[live - 1] will not be overwritten. - * @param ctx a valid context - * @param live number of used registers - */ -static inline void context_clean_registers(Context *ctx, int live) -{ - for (int i = live; i < MAX_REG; i++) { - ctx->x[i] = term_nil(); - } -} - /** * @brief Returns a context's stack base * @@ -368,19 +404,21 @@ void context_process_process_info_request_signal(Context *ctx, struct BuiltInAto * @brief Process a trap answer signal. * * @param ctx the context being executed + * @param x_regs the current x registers * @param signal the answer message * @return \c true if successful, \c false in case of memory error */ -bool context_process_signal_trap_answer(Context *ctx, struct TermSignal *signal); +bool context_process_signal_trap_answer(Context *ctx, term *x_regs, struct TermSignal *signal); /** * @brief Process a flush monitor signal. * * @param ctx the context being executed + * @param x_regs the current x registers * @param ref_ticks the monitor reference * @param info whether to return FALSE_ATOM if no message was flushed. */ -void context_process_flush_monitor_signal(Context *ctx, uint64_t ref_ticks, bool info); +void context_process_flush_monitor_signal(Context *ctx, term *x_regs, uint64_t ref_ticks, bool info); /** * @brief Get process information. diff --git a/src/libAtomVM/debug.c b/src/libAtomVM/debug.c index 15ff8aca81..bf4c76ed4f 100644 --- a/src/libAtomVM/debug.c +++ b/src/libAtomVM/debug.c @@ -76,13 +76,6 @@ COLD_FUNC void debug_dump_memory(Context *ctx, term *start, term *end, const cha fprintf(stderr, "DEBUG:\n"); } -COLD_FUNC void debug_dump_context(Context *ctx) -{ - debug_dump_heap(ctx); - debug_dump_stack(ctx); - debug_dump_registers(ctx); -} - COLD_FUNC void debug_dump_heap(Context *ctx) { debug_dump_memory(ctx, ctx->heap.heap_start, ctx->heap.heap_ptr, "heap"); @@ -94,11 +87,6 @@ COLD_FUNC void debug_dump_stack(Context *ctx) debug_dump_memory(ctx, ctx->e, stack_base, "stack"); } -COLD_FUNC void debug_dump_registers(Context *ctx) -{ - debug_dump_memory(ctx, ctx->x, ctx->x + 16, "register"); -} - COLD_FUNC void debug_print_processes_list(struct ListHead *processes) { Context *contexts = GET_LIST_ENTRY(processes, Context, processes_list_head); @@ -128,6 +116,9 @@ COLD_FUNC char reg_type_c(int reg_type) case 4: return 'y'; + case 11: + return 'x'; + case 12: return 'y'; diff --git a/src/libAtomVM/debug.h b/src/libAtomVM/debug.h index 2c8aa970c4..12e647c2eb 100644 --- a/src/libAtomVM/debug.h +++ b/src/libAtomVM/debug.h @@ -34,14 +34,6 @@ extern "C" { #include "context.h" -/** - * @brief Print a repreentation of the context to stderr. - * - * @details Print heap, stack, and registers of the given context to stderr. - * @param ctx the process context. - */ -void debug_dump_context(Context *ctx); - /** * @brief Print heap contents to stderr. * @@ -58,14 +50,6 @@ void debug_dump_heap(Context *ctx); */ void debug_dump_stack(Context *ctx); -/** - * @brief Print register contents to stderr. - * - * @details Print the dump of the registers of the given context to stderr. - * @param ctx the process context. - */ -void debug_dump_registers(Context *ctx); - /** * @brief Print a region of (term) memory to stderr. * diff --git a/src/libAtomVM/erl_nif_priv.h b/src/libAtomVM/erl_nif_priv.h index 6cf2945760..009b80bf4e 100644 --- a/src/libAtomVM/erl_nif_priv.h +++ b/src/libAtomVM/erl_nif_priv.h @@ -33,7 +33,6 @@ struct ErlNifEnv GlobalContext *global; Heap heap; term *stack_pointer; // Context stack pointer, NULL for non-context envs - term x[2]; }; _Static_assert(offsetof(struct ErlNifEnv, global) == offsetof(struct Context, global) ? 1 : 0, @@ -42,8 +41,6 @@ _Static_assert(offsetof(struct ErlNifEnv, heap) == offsetof(struct Context, heap "ErlNifEnv.heap doesn't match Context.heap"); _Static_assert(offsetof(struct ErlNifEnv, stack_pointer) == offsetof(struct Context, e) ? 1 : 0, "ErlNifEnv.stack_pointer doesn't match Context.e"); -_Static_assert(offsetof(struct ErlNifEnv, x) == offsetof(struct Context, x) ? 1 : 0, - "ErlNifEnv.x doesn't match Context.x"); static inline ErlNifEnv *erl_nif_env_from_context(Context *ctx) { @@ -63,8 +60,6 @@ static inline void erl_nif_env_partial_init_from_globalcontext(ErlNifEnv *env, G env->heap.heap_ptr = NULL; env->heap.heap_end = NULL; env->stack_pointer = NULL; - env->x[0] = term_nil(); - env->x[1] = term_nil(); } #ifdef __cplusplus diff --git a/src/libAtomVM/exportedfunction.h b/src/libAtomVM/exportedfunction.h index a8203e23d7..5ecbd40241 100644 --- a/src/libAtomVM/exportedfunction.h +++ b/src/libAtomVM/exportedfunction.h @@ -37,13 +37,13 @@ struct Module; typedef struct Module Module; #endif -typedef term (*BifImpl0)(Context *ctx); -typedef term (*BifImpl1)(Context *ctx, term arg1); -typedef term (*BifImpl2)(Context *ctx, term arg1, term arg2); +typedef term (*BifImpl0)(Context *ctx, term *x_regs); +typedef term (*BifImpl1)(Context *ctx, term *x_regs, term arg1); +typedef term (*BifImpl2)(Context *ctx, term *x_regs, term arg1, term arg2); -typedef term (*GCBifImpl1)(Context *ctx, int live, term arg1); -typedef term (*GCBifImpl2)(Context *ctx, int live, term arg1, term arg2); -typedef term (*GCBifImpl3)(Context *ctx, int live, term arg1, term arg2, term arg3); +typedef term (*GCBifImpl1)(Context *ctx, term *x_regs, int live, term arg1); +typedef term (*GCBifImpl2)(Context *ctx, term *x_regs, int live, term arg1, term arg2); +typedef term (*GCBifImpl3)(Context *ctx, term *x_regs, int live, term arg1, term arg2, term arg3); typedef term (*NifImpl)(Context *ctx, int argc, term argv[]); diff --git a/src/libAtomVM/nifs.c b/src/libAtomVM/nifs.c index d326a8f139..900c7a1fd4 100644 --- a/src/libAtomVM/nifs.c +++ b/src/libAtomVM/nifs.c @@ -58,8 +58,8 @@ #define FLOAT_BUF_SIZE 64 #define RAISE(a, b) \ - ctx->x[0] = (a); \ - ctx->x[1] = (b); \ + argv[0] = (a); \ + argv[1] = (b); \ return term_invalid_term(); #ifndef MAX @@ -806,7 +806,7 @@ const struct Nif *nifs_get(AtomString module, AtomString function, int arity) return nameAndPtr->nif; } -static inline term make_maybe_boxed_int64(Context *ctx, avm_int64_t value) +static inline term make_maybe_boxed_int64(Context *ctx, term argv[], avm_int64_t value) { #if BOXED_TERMS_REQUIRED_FOR_INT64 == 2 if ((value < AVM_INT_MIN) || (value > AVM_INT_MAX)) { @@ -829,6 +829,7 @@ static inline term make_maybe_boxed_int64(Context *ctx, avm_int64_t value) static term nif_erlang_iolist_size_1(Context *ctx, int argc, term argv[]) { + UNUSED(ctx); UNUSED(argc); size_t size; @@ -1087,7 +1088,7 @@ static NativeHandlerResult process_console_mailbox(Context *ctx) // Common handling of spawn/1, spawn/3, spawn_opt/2, spawn_opt/4 // opts_term is [] for spawn/1,3 -static term do_spawn(Context *ctx, Context *new_ctx, term opts_term) +static term do_spawn(Context *ctx, term argv[], Context *new_ctx, term opts_term) { term min_heap_size_term = interop_proplist_get_value(opts_term, MIN_HEAP_SIZE_ATOM); term max_heap_size_term = interop_proplist_get_value(opts_term, MAX_HEAP_SIZE_ATOM); @@ -1221,15 +1222,17 @@ static term nif_erlang_spawn_fun_opt(Context *ctx, int argc, term argv[]) fprintf(stderr, "Unable to allocate sufficient memory to spawn process.\n"); AVM_ABORT(); } + term x_regs[arity]; for (uint32_t i = 0; i < n_freeze; i++) { - new_ctx->x[i + arity - n_freeze] = memory_copy_term_tree(&new_ctx->heap, boxed_value[i + 3]); + x_regs[i + arity - n_freeze] = memory_copy_term_tree(&new_ctx->heap, boxed_value[i + 3]); } new_ctx->saved_module = fun_module; new_ctx->saved_ip = fun_module->labels[label]; new_ctx->cp = module_address(fun_module->module_index, fun_module->end_instruction_ii); + context_save_xregs(new_ctx, x_regs, arity); - return do_spawn(ctx, new_ctx, opts_term); + return do_spawn(ctx, argv, new_ctx, opts_term); } static term nif_erlang_spawn_opt(Context *ctx, int argc, term argv[]) @@ -1270,9 +1273,6 @@ static term nif_erlang_spawn_opt(Context *ctx, int argc, term argv[]) new_ctx->saved_ip = found_module->labels[label]; new_ctx->cp = module_address(found_module->module_index, found_module->end_instruction_ii); - //TODO: check available registers count - int reg_index = 0; - size_t min_heap_size = 0; term min_heap_size_term = interop_proplist_get_value(opts_term, MIN_HEAP_SIZE_ATOM); if (min_heap_size_term != term_nil()) { @@ -1292,18 +1292,18 @@ static term nif_erlang_spawn_opt(Context *ctx, int argc, term argv[]) context_destroy(new_ctx); RAISE_ERROR(OUT_OF_MEMORY_ATOM); } + term x_regs[args_len]; + int reg_index = 0; while (term_is_nonempty_list(args_term)) { - new_ctx->x[reg_index] = memory_copy_term_tree(&new_ctx->heap, term_get_list_head(args_term)); + x_regs[reg_index] = memory_copy_term_tree(&new_ctx->heap, term_get_list_head(args_term)); reg_index++; args_term = term_get_list_tail(args_term); - if (!term_is_list(args_term)) { - context_destroy(new_ctx); - RAISE_ERROR(BADARG_ATOM); - } } - return do_spawn(ctx, new_ctx, opts_term); + context_save_xregs(new_ctx, x_regs, args_len); + + return do_spawn(ctx, argv, new_ctx, opts_term); } static term nif_erlang_send_2(Context *ctx, int argc, term argv[]) @@ -1430,20 +1430,19 @@ term nif_erlang_make_ref_0(Context *ctx, int argc, term argv[]) term nif_erlang_monotonic_time_1(Context *ctx, int argc, term argv[]) { - UNUSED(ctx); UNUSED(argc); struct timespec ts; sys_monotonic_time(&ts); if (argv[0] == SECOND_ATOM) { - return make_maybe_boxed_int64(ctx, ts.tv_sec); + return make_maybe_boxed_int64(ctx, argv, ts.tv_sec); } else if (argv[0] == MILLISECOND_ATOM) { - return make_maybe_boxed_int64(ctx, ((int64_t) ts.tv_sec) * 1000UL + ts.tv_nsec / 1000000UL); + return make_maybe_boxed_int64(ctx, argv, ((int64_t) ts.tv_sec) * 1000UL + ts.tv_nsec / 1000000UL); } else if (argv[0] == MICROSECOND_ATOM) { - return make_maybe_boxed_int64(ctx, ((int64_t) ts.tv_sec) * 1000000UL + ts.tv_nsec / 1000UL); + return make_maybe_boxed_int64(ctx, argv, ((int64_t) ts.tv_sec) * 1000000UL + ts.tv_nsec / 1000UL); } else { RAISE_ERROR(BADARG_ATOM); @@ -1452,27 +1451,26 @@ term nif_erlang_monotonic_time_1(Context *ctx, int argc, term argv[]) term nif_erlang_system_time_1(Context *ctx, int argc, term argv[]) { - UNUSED(ctx); UNUSED(argc); struct timespec ts; sys_time(&ts); if (argv[0] == SECOND_ATOM) { - return make_maybe_boxed_int64(ctx, ts.tv_sec); + return make_maybe_boxed_int64(ctx, argv, ts.tv_sec); } else if (argv[0] == MILLISECOND_ATOM) { - return make_maybe_boxed_int64(ctx, ((int64_t) ts.tv_sec) * 1000UL + ts.tv_nsec / 1000000UL); + return make_maybe_boxed_int64(ctx, argv, ((int64_t) ts.tv_sec) * 1000UL + ts.tv_nsec / 1000000UL); } else if (argv[0] == MICROSECOND_ATOM) { - return make_maybe_boxed_int64(ctx, ((int64_t) ts.tv_sec) * 1000000UL + ts.tv_nsec / 1000UL); + return make_maybe_boxed_int64(ctx, argv, ((int64_t) ts.tv_sec) * 1000000UL + ts.tv_nsec / 1000UL); } else { RAISE_ERROR(BADARG_ATOM); } } -static term build_datetime_from_tm(Context *ctx, struct tm *broken_down_time) +static term build_datetime_from_tm(Context *ctx, term argv[], struct tm *broken_down_time) { // 4 = size of date/time tuple, 3 size of date time tuple if (UNLIKELY(memory_ensure_free_opt(ctx, 3 + 4 + 4, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { @@ -1505,7 +1503,7 @@ term nif_erlang_universaltime_0(Context *ctx, int argc, term argv[]) sys_time(&ts); struct tm broken_down_time; - return build_datetime_from_tm(ctx, gmtime_r(&ts.tv_sec, &broken_down_time)); + return build_datetime_from_tm(ctx, argv, gmtime_r(&ts.tv_sec, &broken_down_time)); } term nif_erlang_localtime(Context *ctx, int argc, term argv[]) @@ -1550,7 +1548,7 @@ term nif_erlang_localtime(Context *ctx, int argc, term argv[]) #endif free(tz); - return build_datetime_from_tm(ctx, localtime); + return build_datetime_from_tm(ctx, argv, localtime); } term nif_erlang_timestamp_0(Context *ctx, int argc, term argv[]) @@ -1600,7 +1598,7 @@ term nif_calendar_system_time_to_universal_time_2(Context *ctx, int argc, term a } struct tm broken_down_time; - return build_datetime_from_tm(ctx, gmtime_r(&ts.tv_sec, &broken_down_time)); + return build_datetime_from_tm(ctx, argv, gmtime_r(&ts.tv_sec, &broken_down_time)); } static term nif_erlang_make_tuple_2(Context *ctx, int argc, term argv[]) @@ -1814,7 +1812,7 @@ static term nif_erlang_binary_to_integer_1(Context *ctx, int argc, term argv[]) RAISE_ERROR(BADARG_ATOM); } - return make_maybe_boxed_int64(ctx, value); + return make_maybe_boxed_int64(ctx, argv, value); } static int is_valid_float_string(const char *str, int len) @@ -1846,7 +1844,7 @@ static int is_valid_float_string(const char *str, int len) return has_point; } -static term parse_float(Context *ctx, const char *buf, int len) +static term parse_float(Context *ctx, term argv[], const char *buf, int len) { if (UNLIKELY((len == 0) || (len >= FLOAT_BUF_SIZE - 1))) { RAISE_ERROR(BADARG_ATOM); @@ -1882,7 +1880,7 @@ static term nif_erlang_binary_to_float_1(Context *ctx, int argc, term argv[]) const char *bin_data = term_binary_data(bin_term); int bin_data_size = term_binary_size(bin_term); - return parse_float(ctx, bin_data, bin_data_size); + return parse_float(ctx, argv, bin_data, bin_data_size); } static term nif_erlang_list_to_float_1(Context *ctx, int argc, term argv[]) @@ -1903,7 +1901,7 @@ static term nif_erlang_list_to_float_1(Context *ctx, int argc, term argv[]) if (UNLIKELY(!ok)) { RAISE_ERROR(BADARG_ATOM); } - term res_term = parse_float(ctx, string, len); + term res_term = parse_float(ctx, argv, string, len); free(string); @@ -2431,7 +2429,7 @@ static term nif_erlang_list_to_integer_1(Context *ctx, int argc, term argv[]) RAISE_ERROR(BADARG_ATOM); } - return make_maybe_boxed_int64(ctx, acc); + return make_maybe_boxed_int64(ctx, argv, acc); } static term nif_erlang_display_1(Context *ctx, int argc, term argv[]) @@ -2446,7 +2444,7 @@ static term nif_erlang_display_1(Context *ctx, int argc, term argv[]) } // process_flag/3 work on a subset of flags, target is locked. -static term nif_erlang_process_flag_3(Context *ctx, Context *target, term flag, term value) +static term nif_erlang_process_flag_3(Context *ctx, term argv[], Context *target, term flag, term value) { #ifdef ENABLE_ADVANCED_TRACE if (flag == globalcontext_make_atom(ctx->global, trace_calls_atom)) { @@ -2491,6 +2489,7 @@ static term nif_erlang_process_flag_3(Context *ctx, Context *target, term flag, } } #else + UNUSED(ctx); UNUSED(target); UNUSED(flag); UNUSED(value); @@ -2527,7 +2526,7 @@ static term nif_erlang_process_flag(Context *ctx, int argc, term argv[]) } // TODO: check erlang:process_flag/3 implementation - return nif_erlang_process_flag_3(ctx, ctx, flag, value); + return nif_erlang_process_flag_3(ctx, argv, ctx, flag, value); } else if (argc == 3) { term pid = argv[0]; flag = argv[1]; @@ -2539,7 +2538,7 @@ static term nif_erlang_process_flag(Context *ctx, int argc, term argv[]) if (IS_NULL_PTR(target)) { RAISE_ERROR(BADARG_ATOM); } - term result = nif_erlang_process_flag_3(ctx, target, flag, value); + term result = nif_erlang_process_flag_3(ctx, argv, target, flag, value); globalcontext_get_process_unlock(ctx->global, target); return result; } else { @@ -2816,6 +2815,7 @@ static term nif_erlang_term_to_binary(Context *ctx, int argc, term argv[]) static term nif_binary_at_2(Context *ctx, int argc, term argv[]) { + UNUSED(ctx); UNUSED(argc); term bin_term = argv[0]; @@ -2836,6 +2836,7 @@ static term nif_binary_at_2(Context *ctx, int argc, term argv[]) static term nif_binary_first_1(Context *ctx, int argc, term argv[]) { + UNUSED(ctx); UNUSED(argc); term bin_term = argv[0]; @@ -2851,6 +2852,7 @@ static term nif_binary_first_1(Context *ctx, int argc, term argv[]) static term nif_binary_last_1(Context *ctx, int argc, term argv[]) { + UNUSED(ctx); UNUSED(argc); term bin_term = argv[0]; @@ -2954,26 +2956,28 @@ static term nif_binary_split_2(Context *ctx, int argc, term argv[]) static term nif_erlang_throw(Context *ctx, int argc, term argv[]) { + UNUSED(ctx); UNUSED(argc); term t = argv[0]; - ctx->x[0] = THROW_ATOM; - ctx->x[1] = t; + argv[0] = THROW_ATOM; + argv[1] = t; return term_invalid_term(); } static term nif_erlang_raise(Context *ctx, int argc, term argv[]) { + UNUSED(ctx); UNUSED(argc); term ex_class = argv[0]; if (UNLIKELY(ex_class != ERROR_ATOM && ex_class != LOWERCASE_EXIT_ATOM && ex_class != THROW_ATOM)) { return BADARG_ATOM; } - ctx->x[0] = ex_class; - ctx->x[1] = argv[1]; - ctx->x[2] = term_nil(); + argv[0] = ex_class; + argv[1] = argv[1]; + argv[2] = term_nil(); return term_invalid_term(); } @@ -3155,6 +3159,7 @@ static term nif_erlang_garbage_collect(Context *ctx, int argc, term argv[]) static term nif_erlang_error(Context *ctx, int argc, term argv[]) { + UNUSED(ctx); UNUSED(argc); term r = argv[0]; @@ -3585,7 +3590,7 @@ static term nif_atomvm_add_avm_pack_binary(Context *ctx, int argc, term argv[]) return OK_ATOM; } -static term open_avm_error_tuple(Context *ctx, enum OpenAVMResult result) +static term open_avm_error_tuple(Context *ctx, term argv[], enum OpenAVMResult result) { term reason = UNDEFINED_ATOM; switch (result) { @@ -3639,7 +3644,7 @@ static term nif_atomvm_add_avm_pack_file(Context *ctx, int argc, term argv[]) enum OpenAVMResult result = sys_open_avm_from_file(ctx->global, abs, &avmpack_data); if (UNLIKELY(result != AVM_OPEN_OK)) { free(abs); - return open_avm_error_tuple(ctx, result); + return open_avm_error_tuple(ctx, argv, result); } term name = interop_kv_get_value_default(opts, ATOM_STR("\x4", "name"), UNDEFINED_ATOM, ctx->global); @@ -3821,6 +3826,7 @@ static term nif_atomvm_read_priv(Context *ctx, int argc, term argv[]) static term nif_console_print(Context *ctx, int argc, term argv[]) { + UNUSED(ctx); UNUSED(argc); term t = argv[0]; diff --git a/src/libAtomVM/nifs.h b/src/libAtomVM/nifs.h index 71149c9356..b996f450f4 100644 --- a/src/libAtomVM/nifs.h +++ b/src/libAtomVM/nifs.h @@ -42,8 +42,8 @@ extern "C" { } #define RAISE_ERROR(error_type_atom) \ - ctx->x[0] = ERROR_ATOM; \ - ctx->x[1] = (error_type_atom); \ + argv[0] = ERROR_ATOM; \ + argv[1] = (error_type_atom); \ return term_invalid_term(); const struct Nif *nifs_get(AtomString module, AtomString function, int arity); diff --git a/src/libAtomVM/opcodesswitch.h b/src/libAtomVM/opcodesswitch.h index bad0328614..2f1617476a 100644 --- a/src/libAtomVM/opcodesswitch.h +++ b/src/libAtomVM/opcodesswitch.h @@ -60,6 +60,7 @@ #define COMPACT_LARGE_LITERAL 8 #define COMPACT_LARGE_INTEGER 9 #define COMPACT_LARGE_ATOM 10 +#define COMPACT_LARGE_XREG 11 #define COMPACT_LARGE_YREG 12 // OTP-20+ format @@ -82,7 +83,7 @@ #define SET_ERROR(error_type_atom) \ x_regs[0] = ERROR_ATOM; \ x_regs[1] = error_type_atom; \ - x_regs[2] = stacktrace_create_raw(ctx, mod, pc - code, ERROR_ATOM); + x_regs[2] = stacktrace_create_raw(ctx, x_regs, mod, pc - code, ERROR_ATOM); // Override nifs.h RAISE_ERROR macro #ifdef RAISE_ERROR @@ -97,6 +98,10 @@ #endif +#ifndef MAX +#define MAX(x, y) (x) > (y) ? (x) : (y) +#endif + #ifdef IMPL_CODE_LOADER #ifdef ENABLE_TRACE @@ -215,6 +220,7 @@ typedef dreg_t dreg_gc_safe_t; } \ break; \ \ + case COMPACT_LARGE_XREG: \ case COMPACT_LARGE_YREG: \ (decode_pc)++; \ break; \ @@ -254,6 +260,7 @@ typedef dreg_t dreg_gc_safe_t; case COMPACT_YREG: \ (dreg).index = first_byte >> 4; \ break; \ + case COMPACT_LARGE_XREG: \ case COMPACT_LARGE_YREG: \ (dreg).index = (((first_byte & 0xE0) << 3) | *(decode_pc)++); \ break; \ @@ -276,6 +283,7 @@ typedef dreg_t dreg_gc_safe_t; case COMPACT_XREG: \ case COMPACT_YREG: \ break; \ + case COMPACT_LARGE_XREG: \ case COMPACT_LARGE_YREG: \ (decode_pc)++; \ break; \ @@ -562,7 +570,7 @@ typedef struct \ case COMPACT_NBITS_VALUE: { \ size_t num_bytes = (first_byte >> 5) + 2; \ - dest_term = large_integer_to_term(ctx, num_bytes, decode_pc); \ + dest_term = large_integer_to_term(ctx, x_regs, num_bytes, decode_pc); \ if (UNLIKELY(term_is_invalid_term(dest_term))) { \ HANDLE_ERROR(); \ } \ @@ -575,6 +583,14 @@ typedef struct } \ break; \ \ + case COMPACT_LARGE_XREG: \ + if (LIKELY((first_byte & COMPACT_LARGE_IMM_MASK) == COMPACT_11BITS_VALUE)) { \ + dest_term = x_regs[((first_byte & 0xE0) << 3) | *(decode_pc)++]; \ + } else { \ + VM_ABORT(); \ + } \ + break; \ + \ case COMPACT_LARGE_YREG: \ if (LIKELY((first_byte & COMPACT_LARGE_IMM_MASK) == COMPACT_11BITS_VALUE)) { \ dest_term = ctx->e[((first_byte & 0xE0) << 3) | *(decode_pc)++]; \ @@ -630,9 +646,18 @@ typedef struct case COMPACT_YREG: \ (dreg) = ctx->e + reg_index; \ break; \ + case COMPACT_LARGE_XREG: \ + if (LIKELY((first_byte & COMPACT_LARGE_IMM_MASK) == COMPACT_11BITS_VALUE)) { \ + uint16_t large_reg_index = (((first_byte & 0xE0) << 3) | *(decode_pc)++); \ + (dreg) = x_regs + large_reg_index; \ + } else { \ + VM_ABORT(); \ + } \ + break; \ case COMPACT_LARGE_YREG: \ if (LIKELY((first_byte & COMPACT_LARGE_IMM_MASK) == COMPACT_11BITS_VALUE)) { \ - (dreg) = ctx->e + (((first_byte & 0xE0) << 3) | *(decode_pc)++); \ + uint16_t large_reg_index = (((first_byte & 0xE0) << 3) | *(decode_pc)++); \ + (dreg) = ctx->e + large_reg_index; \ } else { \ VM_ABORT(); \ } \ @@ -656,10 +681,20 @@ typedef struct (dreg_gc_safe).base = ctx->e; \ (dreg_gc_safe).index = reg_index; \ break; \ + case COMPACT_LARGE_XREG: \ + if (LIKELY((first_byte & COMPACT_LARGE_IMM_MASK) == COMPACT_11BITS_VALUE)) { \ + uint16_t large_reg_index = (((first_byte & 0xE0) << 3) | *(decode_pc)++); \ + (dreg_gc_safe).base = x_regs; \ + (dreg_gc_safe).index = large_reg_index; \ + } else { \ + VM_ABORT(); \ + } \ + break; \ case COMPACT_LARGE_YREG: \ if (LIKELY((first_byte & COMPACT_LARGE_IMM_MASK) == COMPACT_11BITS_VALUE)) { \ + uint16_t large_reg_index = (((first_byte & 0xE0) << 3) | *(decode_pc)++); \ (dreg_gc_safe).base = ctx->e; \ - (dreg_gc_safe).index = (((first_byte & 0xE0) << 3) | *(decode_pc)++); \ + (dreg_gc_safe).index = large_reg_index; \ } else { \ VM_ABORT(); \ } \ @@ -669,21 +704,11 @@ typedef struct } \ } -// MAX_REG is enforced at decode time -#if MAX_REG <= 16 -#define DECODE_FP_REGISTER(freg, decode_pc) \ -{ \ - (decode_pc)++; \ - uint8_t first_byte = *(decode_pc)++; \ - freg = first_byte >> 4; \ -} -#else #define DECODE_FP_REGISTER(freg, decode_pc) \ { \ (decode_pc)++; \ DECODE_LITERAL(freg, decode_pc); \ } -#endif #define DECODE_VALUE(val, decode_pc) \ { \ @@ -727,17 +752,8 @@ typedef struct #define DECODE_INTEGER(integer, decode_pc) \ DECODE_VALUE(integer, decode_pc) -// MAX_REG is enforced at decode time -#if MAX_REG <= 16 -#define DECODE_XREG(reg, decode_pc) \ -{ \ - uint8_t first_byte = *(decode_pc)++; \ - reg = first_byte >> 4; \ -} -#else #define DECODE_XREG(reg, decode_pc) \ DECODE_VALUE(reg, decode_pc) -#endif #define DECODE_YREG(reg, decode_pc) \ DECODE_VALUE(reg, decode_pc) @@ -793,6 +809,7 @@ typedef struct { \ ctx->saved_ip = restore_to; \ ctx->saved_module = restore_mod; \ + context_save_xregs(ctx, x_regs, live); \ ctx = scheduler_next(ctx->global, ctx); \ goto schedule_in; \ } @@ -827,7 +844,7 @@ typedef struct case TrapAnswerSignal: { \ struct TermSignal *trap_answer \ = CONTAINER_OF(signal_message, struct TermSignal, base); \ - if (UNLIKELY(!context_process_signal_trap_answer(ctx, trap_answer))) { \ + if (UNLIKELY(!context_process_signal_trap_answer(ctx, x_regs, trap_answer))) { \ SET_ERROR(OUT_OF_MEMORY_ATOM); \ next_label = &&handle_error; \ } \ @@ -845,7 +862,7 @@ typedef struct struct RefSignal *flush_signal \ = CONTAINER_OF(signal_message, struct RefSignal, base); \ bool info = signal_message->type == FlushInfoMonitorSignal; \ - context_process_flush_monitor_signal(ctx, flush_signal->ref_ticks, info); \ + context_process_flush_monitor_signal(ctx, x_regs, flush_signal->ref_ticks, info); \ break; \ } \ case NormalMessage: { \ @@ -912,8 +929,9 @@ typedef struct pc = code + ((ctx->cp & 0xFFFFFF) >> 2); \ } + #define HANDLE_ERROR() \ - x_regs[2] = stacktrace_create_raw(ctx, mod, pc - code, x_regs[0]); \ + x_regs[2] = stacktrace_create_raw(ctx, x_regs, mod, pc - code, x_regs[0]); \ goto handle_error; #define VERIFY_IS_INTEGER(t, opcode_name) \ @@ -1140,7 +1158,7 @@ COLD_FUNC static void cp_to_mod_lbl_off(term cp, Context *ctx, Module **cp_mod, *l_off = mod_offset - (mod->labels[*label] - code); } -COLD_FUNC static void dump(Context *ctx) +COLD_FUNC static void dump(Context *ctx, term *x_regs) { fprintf(stderr, "CRASH \n======\n"); @@ -1149,7 +1167,7 @@ COLD_FUNC static void dump(Context *ctx) fprintf(stderr, "\n"); fprintf(stderr, "\nStacktrace:\n"); - term_display(stderr, stacktrace_build(ctx, &ctx->x[2], 3), ctx); + term_display(stderr, stacktrace_build(ctx, x_regs, &x_regs[2], 3), ctx); fprintf(stderr, "\n\n"); { @@ -1162,11 +1180,11 @@ COLD_FUNC static void dump(Context *ctx) } fprintf(stderr, "x[0]: "); - term_display(stderr, ctx->x[0], ctx); + term_display(stderr, x_regs[0], ctx); fprintf(stderr, "\nx[1]: "); - term_display(stderr, ctx->x[1], ctx); + term_display(stderr, x_regs[1], ctx); fprintf(stderr, "\nx[2]: "); - term_display(stderr, ctx->x[2], ctx); + term_display(stderr, x_regs[2], ctx); fprintf(stderr, "\n\nStack \n------\n\n"); term *ct = ctx->e; @@ -1219,13 +1237,13 @@ COLD_FUNC static void dump(Context *ctx) fprintf(stderr, "\n\n**End Of Crash Report**\n"); } -static term maybe_alloc_boxed_integer_fragment(Context *ctx, avm_int64_t value) +static term maybe_alloc_boxed_integer_fragment(Context *ctx, term *x_regs, avm_int64_t value) { #if BOXED_TERMS_REQUIRED_FOR_INT64 > 1 if ((value < AVM_INT_MIN) || (value > AVM_INT_MAX)) { if (UNLIKELY(memory_ensure_free_opt(ctx, BOXED_INT64_SIZE, MEMORY_NO_GC) != MEMORY_GC_OK)) { - ctx->x[0] = ERROR_ATOM; - ctx->x[1] = OUT_OF_MEMORY_ATOM; + x_regs[0] = ERROR_ATOM; + x_regs[1] = OUT_OF_MEMORY_ATOM; return term_invalid_term(); } return term_make_boxed_int64(value, &ctx->heap); @@ -1233,8 +1251,8 @@ static term maybe_alloc_boxed_integer_fragment(Context *ctx, avm_int64_t value) #endif if ((value < MIN_NOT_BOXED_INT) || (value > MAX_NOT_BOXED_INT)) { if (UNLIKELY(memory_ensure_free_opt(ctx, BOXED_INT_SIZE, MEMORY_NO_GC) != MEMORY_GC_OK)) { - ctx->x[0] = ERROR_ATOM; - ctx->x[1] = OUT_OF_MEMORY_ATOM; + x_regs[0] = ERROR_ATOM; + x_regs[1] = OUT_OF_MEMORY_ATOM; return term_invalid_term(); } return term_make_boxed_int(value, &ctx->heap); @@ -1243,34 +1261,34 @@ static term maybe_alloc_boxed_integer_fragment(Context *ctx, avm_int64_t value) } } -static inline term maybe_alloc_boxed_integer_fragment_helper(Context *ctx, avm_int64_t value, unsigned int bytes_count) +static inline term maybe_alloc_boxed_integer_fragment_helper(Context *ctx, term *x_regs, avm_int64_t value, unsigned int bytes_count) { if (bytes_count < sizeof(avm_int_t)) { return term_from_int(value); } else { - return maybe_alloc_boxed_integer_fragment(ctx, value); + return maybe_alloc_boxed_integer_fragment(ctx, x_regs, value); } } -static term large_integer_to_term(Context *ctx, int num_bytes, const uint8_t *compact_term) +static term large_integer_to_term(Context *ctx, term *x_regs, int num_bytes, const uint8_t *compact_term) { switch (num_bytes) { case 2: { int16_t ret_val16 = ((int16_t) compact_term[0]) << 8 | compact_term[1]; - return maybe_alloc_boxed_integer_fragment_helper(ctx, ret_val16, 2); + return maybe_alloc_boxed_integer_fragment_helper(ctx, x_regs, ret_val16, 2); } case 3: { struct Int24 ret_val24; ret_val24.val24 = ((int32_t) compact_term[0]) << 16 | ((int32_t) compact_term[1] << 8) | compact_term[2]; - return maybe_alloc_boxed_integer_fragment_helper(ctx, ret_val24.val24, 3); + return maybe_alloc_boxed_integer_fragment_helper(ctx, x_regs, ret_val24.val24, 3); } case 4: { int32_t ret_val32; ret_val32 = ((int32_t) compact_term[0]) << 24 | ((int32_t) compact_term[1] << 16) | ((int32_t) compact_term[2] << 8) | compact_term[3]; - return maybe_alloc_boxed_integer_fragment_helper(ctx, ret_val32, 4); + return maybe_alloc_boxed_integer_fragment_helper(ctx, x_regs, ret_val32, 4); } case 5: { @@ -1279,7 +1297,7 @@ static term large_integer_to_term(Context *ctx, int num_bytes, const uint8_t *co | ((int64_t) compact_term[2] << 16) | ((int64_t) compact_term[3] << 8) | (int64_t) compact_term[4]; - return maybe_alloc_boxed_integer_fragment_helper(ctx, ret_val40.val40, 5); + return maybe_alloc_boxed_integer_fragment_helper(ctx, x_regs, ret_val40.val40, 5); } case 6: { @@ -1288,7 +1306,7 @@ static term large_integer_to_term(Context *ctx, int num_bytes, const uint8_t *co | ((int64_t) compact_term[2] << 24) | ((int64_t) compact_term[3] << 16) | ((int64_t) compact_term[4] << 8) | (int64_t) compact_term[5]; - return maybe_alloc_boxed_integer_fragment_helper(ctx, ret_val48.val48, 6); + return maybe_alloc_boxed_integer_fragment_helper(ctx, x_regs, ret_val48.val48, 6); } case 7: { @@ -1298,7 +1316,7 @@ static term large_integer_to_term(Context *ctx, int num_bytes, const uint8_t *co | ((int64_t) compact_term[4] << 16) | ((int64_t) compact_term[5] << 8) | (int64_t) compact_term[6]; - return maybe_alloc_boxed_integer_fragment_helper(ctx, ret_val56.val56, 7); + return maybe_alloc_boxed_integer_fragment_helper(ctx, x_regs, ret_val56.val56, 7); } case 8: { @@ -1308,12 +1326,12 @@ static term large_integer_to_term(Context *ctx, int num_bytes, const uint8_t *co | ((int64_t) compact_term[4] << 24) | ((int64_t) compact_term[5] << 16) | ((int64_t) compact_term[6] << 8) | (int64_t) compact_term[7]; - return maybe_alloc_boxed_integer_fragment_helper(ctx, ret_val64, 8); + return maybe_alloc_boxed_integer_fragment_helper(ctx, x_regs, ret_val64, 8); } default: - ctx->x[0] = ERROR_ATOM; - ctx->x[1] = OVERFLOW_ATOM; + x_regs[0] = ERROR_ATOM; + x_regs[1] = OVERFLOW_ATOM; return term_invalid_term(); } } @@ -1339,7 +1357,7 @@ term make_fun(Context *ctx, const Module *mod, int fun_index, term argv[]) return ((term) boxed_func) | TERM_BOXED_VALUE_TAG; } -static bool maybe_call_native(Context *ctx, AtomString module_name, AtomString function_name, int arity, +static bool maybe_call_native(Context *ctx, term *x_regs, AtomString module_name, AtomString function_name, int arity, term *return_value) { const struct ExportedFunction *exported_bif = bif_registry_get_handler(module_name, function_name, arity); @@ -1348,15 +1366,15 @@ static bool maybe_call_native(Context *ctx, AtomString module_name, AtomString f const struct GCBif *gcbif = EXPORTED_FUNCTION_TO_GCBIF(exported_bif); switch (arity) { case 1: { - *return_value = gcbif->gcbif1_ptr(ctx, 0, ctx->x[0]); + *return_value = gcbif->gcbif1_ptr(ctx, x_regs, 0, x_regs[0]); return true; } case 2: { - *return_value = gcbif->gcbif2_ptr(ctx, 0, ctx->x[0], ctx->x[1]); + *return_value = gcbif->gcbif2_ptr(ctx, x_regs, 0, x_regs[0], x_regs[1]); return true; } case 3: { - *return_value = gcbif->gcbif3_ptr(ctx, 0, ctx->x[0], ctx->x[1], ctx->x[2]); + *return_value = gcbif->gcbif3_ptr(ctx, x_regs, 0, x_regs[0], x_regs[1], x_regs[2]); return true; } } @@ -1364,15 +1382,15 @@ static bool maybe_call_native(Context *ctx, AtomString module_name, AtomString f const struct Bif *bif = EXPORTED_FUNCTION_TO_BIF(exported_bif); switch (arity) { case 0: { - *return_value = bif->bif0_ptr(ctx); + *return_value = bif->bif0_ptr(ctx, x_regs); return true; } case 1: { - *return_value = bif->bif1_ptr(ctx, ctx->x[0]); + *return_value = bif->bif1_ptr(ctx, x_regs, x_regs[0]); return true; } case 2: { - *return_value = bif->bif2_ptr(ctx, ctx->x[0], ctx->x[1]); + *return_value = bif->bif2_ptr(ctx, x_regs, x_regs[0], x_regs[1]); return true; } } @@ -1381,7 +1399,7 @@ static bool maybe_call_native(Context *ctx, AtomString module_name, AtomString f struct Nif *nif = (struct Nif *) nifs_get(module_name, function_name, arity); if (nif) { - *return_value = nif->nif_ptr(ctx, arity, ctx->x); + *return_value = nif->nif_ptr(ctx, arity, x_regs); return true; } @@ -1389,11 +1407,11 @@ static bool maybe_call_native(Context *ctx, AtomString module_name, AtomString f } #ifdef ENABLE_ADVANCED_TRACE - static void print_function_args(const Context *ctx, int arity) + static void print_function_args(const Context *ctx, term *x_regs, int arity) { for (int i = 0; i < arity; i++) { printf("DBG: <0.%i.0> -- arg%i: ", ctx->process_id, i); - term_display(stdout, ctx->x[i], ctx); + term_display(stdout, x_regs[i], ctx); printf("\n"); } } @@ -1437,11 +1455,11 @@ static bool maybe_call_native(Context *ctx, AtomString module_name, AtomString f } } - static void trace_return(const Context *ctx) + static void trace_return(const Context *ctx, term *x_regs) { if (UNLIKELY(ctx->trace_returns)) { printf("DBG: <0.%i.0> - return, value: ", ctx->process_id); - term_display(stdout, ctx->x[0], ctx); + term_display(stdout, x_regs[0], ctx); printf(".\n"); } } @@ -1562,20 +1580,25 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) const uint8_t *code; Module *mod; Module *prev_mod; - term *x_regs; + term *x_regs = malloc(MAX_REG * sizeof(term)); const uint8_t *pc; int remaining_reductions; + uint32_t live; Context *ctx = scheduler_run(glb); // This is where loop starts after context switching. schedule_in: TRACE("scheduling in, ctx = %p\n", ctx); - if (ctx == NULL) return 0; + if (ctx == NULL) { + free(x_regs); + return 0; + } mod = ctx->saved_module; prev_mod = mod; code = mod->code->code; - x_regs = ctx->x; + live = ctx->xregs_count; + context_restore_xregs(ctx, x_regs); JUMP_TO_ADDRESS(ctx->saved_ip); remaining_reductions = DEFAULT_REDUCTIONS_AMOUNT; @@ -1594,6 +1617,8 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) SMP_MODULE_LOCK(mod); const uint8_t *code = mod->code->code; const uint8_t *pc = code; + uint32_t live; + UNUSED(live); #endif while (1) { @@ -1664,6 +1689,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) TRACE_CALL(ctx, mod, "call", label, arity); JUMP_TO_ADDRESS(mod->labels[label]); } else { + live = MAX(live, arity); SCHEDULE_NEXT(mod, mod->labels[label]); } #endif @@ -1695,6 +1721,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) TRACE_CALL(ctx, mod, "call_last", label, arity); JUMP_TO_ADDRESS(mod->labels[label]); } else { + live = MAX(live, arity); SCHEDULE_NEXT(mod, mod->labels[label]); } #endif @@ -1717,6 +1744,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) TRACE_CALL(ctx, mod, "call_only", label, arity); JUMP_TO_ADDRESS(mod->labels[label]); } else { + live = MAX(live, arity); SCHEDULE_NEXT(mod, mod->labels[label]); } #endif @@ -1727,14 +1755,16 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) #ifdef IMPL_EXECUTE_LOOP // save pc in case of error const uint8_t *orig_pc = pc - 1; - + #endif + uint32_t arity; + DECODE_LITERAL(arity, pc); + #ifdef IMPL_EXECUTE_LOOP remaining_reductions--; if (UNLIKELY(!remaining_reductions)) { + live = MAX(live, arity); SCHEDULE_NEXT(mod, orig_pc); } #endif - uint32_t arity; - DECODE_LITERAL(arity, pc); uint32_t index; DECODE_LITERAL(index, pc); @@ -1778,13 +1808,13 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) const struct Bif *bif = EXPORTED_FUNCTION_TO_BIF(func); switch (arity) { case 0: - x_regs[0] = bif->bif0_ptr(ctx); + x_regs[0] = bif->bif0_ptr(ctx, x_regs); break; case 1: - x_regs[0] = bif->bif1_ptr(ctx, x_regs[0]); + x_regs[0] = bif->bif1_ptr(ctx, x_regs, x_regs[0]); break; case 2: - x_regs[0] = bif->bif2_ptr(ctx, x_regs[0], x_regs[1]); + x_regs[0] = bif->bif2_ptr(ctx, x_regs, x_regs[0], x_regs[1]); break; default: fprintf(stderr, "Invalid arity %" PRIu32 " for bif\n", arity); @@ -1806,14 +1836,16 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) #ifdef IMPL_EXECUTE_LOOP // save pc in case of error const uint8_t *orig_pc = pc - 1; - + #endif + uint32_t arity; + DECODE_LITERAL(arity, pc); + #ifdef IMPL_EXECUTE_LOOP remaining_reductions--; if (UNLIKELY(!remaining_reductions)) { + live = MAX(live, arity); SCHEDULE_NEXT(mod, orig_pc); } #endif - uint32_t arity; - DECODE_LITERAL(arity, pc); uint32_t index; DECODE_LITERAL(index, pc); uint32_t n_words; @@ -1878,13 +1910,13 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) const struct Bif *bif = EXPORTED_FUNCTION_TO_BIF(func); switch (arity) { case 0: - x_regs[0] = bif->bif0_ptr(ctx); + x_regs[0] = bif->bif0_ptr(ctx, x_regs); break; case 1: - x_regs[0] = bif->bif1_ptr(ctx, x_regs[0]); + x_regs[0] = bif->bif1_ptr(ctx, x_regs, x_regs[0]); break; case 2: - x_regs[0] = bif->bif2_ptr(ctx, x_regs[0], x_regs[1]); + x_regs[0] = bif->bif2_ptr(ctx, x_regs, x_regs[0], x_regs[1]); break; default: fprintf(stderr, "Invalid arity %" PRIu32 " for bif\n", arity); @@ -1917,7 +1949,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) const struct ExportedFunction *exported_bif = mod->imported_funcs[bif]; BifImpl0 func = EXPORTED_FUNCTION_TO_BIF(exported_bif)->bif0_ptr; DEBUG_FAIL_NULL(func); - term ret = func(ctx); + term ret = func(ctx, x_regs); WRITE_REGISTER(dreg, ret); #endif @@ -1946,7 +1978,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) const struct ExportedFunction *exported_bif = mod->imported_funcs[bif]; BifImpl1 func = EXPORTED_FUNCTION_TO_BIF(exported_bif)->bif1_ptr; DEBUG_FAIL_NULL(func); - term ret = func(ctx, arg1); + term ret = func(ctx, x_regs, arg1); if (UNLIKELY(term_is_invalid_term(ret))) { if (fail_label) { pc = mod->labels[fail_label]; @@ -1986,7 +2018,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) const struct ExportedFunction *exported_bif = mod->imported_funcs[bif]; BifImpl2 func = EXPORTED_FUNCTION_TO_BIF(exported_bif)->bif2_ptr; DEBUG_FAIL_NULL(func); - term ret = func(ctx, arg1, arg2); + term ret = func(ctx, x_regs, arg1, arg2); if (UNLIKELY(term_is_invalid_term(ret))) { if (fail_label) { pc = mod->labels[fail_label]; @@ -2004,11 +2036,9 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) case OP_ALLOCATE: { uint32_t stack_need; DECODE_LITERAL(stack_need, pc); - uint32_t live; DECODE_LITERAL(live, pc); TRACE("allocate/2 stack_need=%i, live=%i\n" , stack_need, live); USED_BY_TRACE(stack_need); - USED_BY_TRACE(live); #ifdef IMPL_CODE_LOADER if (live > MAX_REG) { @@ -2034,12 +2064,10 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) DECODE_LITERAL(stack_need, pc); uint32_t heap_need; DECODE_ALLOCATOR_LIST(heap_need, pc); - uint32_t live; DECODE_LITERAL(live, pc); TRACE("allocate_heap/2 stack_need=%i, heap_need=%i, live=%i\n", stack_need, heap_need, live); USED_BY_TRACE(stack_need); USED_BY_TRACE(heap_need); - USED_BY_TRACE(live); #ifdef IMPL_CODE_LOADER if (live > MAX_REG) { @@ -2063,11 +2091,9 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) case OP_ALLOCATE_ZERO: { uint32_t stack_need; DECODE_LITERAL(stack_need, pc); - uint32_t live; DECODE_LITERAL(live, pc); TRACE("allocate_zero/2 stack_need=%i, live=%i\n", stack_need, live); USED_BY_TRACE(stack_need); - USED_BY_TRACE(live); #ifdef IMPL_CODE_LOADER if (live > MAX_REG) { @@ -2098,12 +2124,10 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) DECODE_LITERAL(stack_need, pc); uint32_t heap_need; DECODE_ALLOCATOR_LIST(heap_need, pc); - uint32_t live; DECODE_LITERAL(live, pc); TRACE("allocate_heap_zero/3 stack_need=%i, heap_need=%i, live=%i\n", stack_need, heap_need, live); USED_BY_TRACE(stack_need); USED_BY_TRACE(heap_need); - USED_BY_TRACE(live); #ifdef IMPL_CODE_LOADER if (live > MAX_REG) { @@ -2131,24 +2155,22 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) case OP_TEST_HEAP: { uint32_t heap_need; DECODE_ALLOCATOR_LIST(heap_need, pc); - uint32_t live_registers; - DECODE_LITERAL(live_registers, pc); + DECODE_LITERAL(live, pc); - TRACE("test_heap/2 heap_need=%i, live_registers=%i\n", heap_need, live_registers); + TRACE("test_heap/2 heap_need=%i, live=%i\n", heap_need, live); USED_BY_TRACE(heap_need); - USED_BY_TRACE(live_registers); #ifdef IMPL_EXECUTE_LOOP size_t heap_free = context_avail_free_memory(ctx); // if we need more heap space than is currently free, then try to GC the needed space if (heap_free < heap_need) { - if (UNLIKELY(memory_ensure_free_with_roots(ctx, heap_need, live_registers, x_regs, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { + if (UNLIKELY(memory_ensure_free_with_roots(ctx, heap_need, live, x_regs, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { RAISE_ERROR(OUT_OF_MEMORY_ATOM); } // otherwise, there is enough space for the needed heap, but there might // more more than necessary. In that case, try to shrink the heap. } else if (heap_free > heap_need * HEAP_NEED_GC_SHRINK_THRESHOLD_COEFF) { - if (UNLIKELY(memory_ensure_free_with_roots(ctx, heap_need * (HEAP_NEED_GC_SHRINK_THRESHOLD_COEFF / 2), live_registers, x_regs, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { + if (UNLIKELY(memory_ensure_free_with_roots(ctx, heap_need * (HEAP_NEED_GC_SHRINK_THRESHOLD_COEFF / 2), live, x_regs, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { TRACE("Unable to ensure free memory. heap_need=%i\n", heap_need); RAISE_ERROR(OUT_OF_MEMORY_ATOM); } @@ -2199,6 +2221,8 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) TRACE_RETURN(ctx); if ((long) ctx->cp == -1) { + context_save_xregs(ctx, x_regs, 1); + free(x_regs); return 0; } @@ -2309,6 +2333,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) // and the outer list will be processed. ctx->saved_ip = mod->labels[label]; ctx->saved_module = mod; + context_save_xregs(ctx, x_regs, live); ctx = scheduler_wait(ctx); goto schedule_in; #endif @@ -2361,6 +2386,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) ctx->restore_trap_handler = &&wait_timeout_trap_handler; #pragma GCC diagnostic pop ctx->saved_module = mod; + context_save_xregs(ctx, x_regs, live); ctx = scheduler_wait(ctx); goto schedule_in; } @@ -2396,6 +2422,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) if (UNLIKELY(!mailbox_has_next(&ctx->mailbox))) { // No message is here. // We were signaled for another reason. + context_save_xregs(ctx, x_regs, live); ctx = scheduler_wait(ctx); goto schedule_in; } else { @@ -2999,6 +3026,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) } else { ctx->saved_ip = mod->labels[label]; ctx->saved_module = mod; + context_save_xregs(ctx, x_regs, live); ctx = scheduler_next(ctx->global, ctx); goto schedule_in; } @@ -3236,14 +3264,19 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) } case OP_CALL_FUN: { + #ifdef IMPL_EXECUTE_LOOP + // pc before arity + const uint8_t *orig_pc = pc - 1; + #endif + uint32_t args_count; + DECODE_LITERAL(args_count, pc) #ifdef IMPL_EXECUTE_LOOP remaining_reductions--; if (UNLIKELY(!remaining_reductions)) { - SCHEDULE_NEXT(mod, pc - 1); + live = MAX(live, args_count + 1); + SCHEDULE_NEXT(mod, orig_pc); } #endif - uint32_t args_count; - DECODE_LITERAL(args_count, pc) TRACE("call_fun/1, args_count=%i\n", args_count); USED_BY_TRACE(args_count); @@ -3291,14 +3324,19 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) } case OP_CALL_EXT_ONLY: { + #ifdef IMPL_EXECUTE_LOOP + // pc before arity + const uint8_t *orig_pc = pc - 1; + #endif + uint32_t arity; + DECODE_LITERAL(arity, pc); #ifdef IMPL_EXECUTE_LOOP remaining_reductions--; if (UNLIKELY(!remaining_reductions)) { - SCHEDULE_NEXT(mod, pc - 1); + live = MAX(live, arity); + SCHEDULE_NEXT(mod, orig_pc); } #endif - uint32_t arity; - DECODE_LITERAL(arity, pc); uint32_t index; DECODE_LITERAL(index, pc); @@ -3326,6 +3364,8 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) } } if ((long) ctx->cp == -1) { + context_save_xregs(ctx, x_regs, 1); + free(x_regs); return 0; } @@ -3345,13 +3385,13 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) const struct Bif *bif = EXPORTED_FUNCTION_TO_BIF(func); switch (arity) { case 0: - x_regs[0] = bif->bif0_ptr(ctx); + x_regs[0] = bif->bif0_ptr(ctx, x_regs); break; case 1: - x_regs[0] = bif->bif1_ptr(ctx, x_regs[0]); + x_regs[0] = bif->bif1_ptr(ctx, x_regs, x_regs[0]); break; case 2: - x_regs[0] = bif->bif2_ptr(ctx, x_regs[0], x_regs[1]); + x_regs[0] = bif->bif2_ptr(ctx, x_regs, x_regs[0], x_regs[1]); break; default: fprintf(stderr, "Invalid arity %" PRIu32 " for bif\n", arity); @@ -3473,7 +3513,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) TRACE("raise/2 stacktrace=0x%lx exc_value=0x%lx\n", stacktrace, exc_value); x_regs[0] = stacktrace_exception_class(stacktrace); x_regs[1] = exc_value; - x_regs[2] = stacktrace_create_raw(ctx, mod, saved_pc - code, x_regs[0]); + x_regs[2] = stacktrace_create_raw(ctx, x_regs, mod, saved_pc - code, x_regs[0]); goto handle_error; #endif @@ -3512,7 +3552,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) break; case ERROR_ATOM_INDEX: { - x_regs[2] = stacktrace_build(ctx, &x_regs[2], 3); + x_regs[2] = stacktrace_build(ctx, x_regs, &x_regs[2], 3); // MEMORY_CAN_SHRINK because catch_end is classified as gc in beam_ssa_codegen.erl if (UNLIKELY(memory_ensure_free_with_roots(ctx, TUPLE_SIZE(2) * 2, 2, x_regs + 1, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { RAISE_ERROR(OUT_OF_MEMORY_ATOM); @@ -3581,7 +3621,6 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) DECODE_COMPACT_TERM(size, pc) uint32_t words; DECODE_LITERAL(words, pc) - uint32_t live; DECODE_LITERAL(live, pc) term flags; UNUSED(flags); @@ -3621,7 +3660,6 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) DECODE_COMPACT_TERM(size, pc) uint32_t words; DECODE_LITERAL(words, pc) - uint32_t live; DECODE_LITERAL(live, pc) uint32_t flags_value; DECODE_LITERAL(flags_value, pc) @@ -4071,8 +4109,6 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) term extra; UNUSED(extra); DECODE_COMPACT_TERM(extra, pc) - uint32_t live; - UNUSED(live); DECODE_LITERAL(live, pc); uint32_t unit; DECODE_LITERAL(unit, pc); @@ -4316,7 +4352,6 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) DECODE_LABEL(fail, pc) term src; DECODE_COMPACT_TERM(src, pc); - uint32_t live; DECODE_LITERAL(live, pc); term slots_term; DECODE_COMPACT_TERM(slots_term, pc); @@ -4359,7 +4394,6 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) DECODE_LABEL(fail, pc) term src; DECODE_COMPACT_TERM(src, pc); - uint32_t live; DECODE_LITERAL(live, pc); dreg_gc_safe_t dreg; DECODE_DEST_REGISTER_GC_SAFE(dreg, pc); @@ -4377,7 +4411,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) } src = x_regs[live]; #endif - TRACE("bs_start_match3/4, fail=%i src=0x%lx live=%u dreg=%c%i\n", fail, src, live, T_DEST_REG_UNSAFE(dreg)); + TRACE("bs_start_match3/4, fail=%i src=0x%lx live=%u dreg=%c%i\n", fail, src, live, T_DEST_REG_GC_SAFE(dreg)); if (!(term_is_binary(src) || term_is_match_state(src))) { WRITE_REGISTER_GC_SAFE(dreg, src); pc = mod->labels[fail]; @@ -4396,8 +4430,6 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) dreg_t dreg; DECODE_DEST_REGISTER(dreg, pc); // TODO: determine why we're not GC-ing here as we have live - uint32_t live; - UNUSED(live); DECODE_LITERAL(live, pc); #ifdef IMPL_CODE_LOADER @@ -4422,7 +4454,6 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) DECODE_COMPACT_TERM(src, pc); dreg_gc_safe_t dreg; DECODE_DEST_REGISTER_GC_SAFE(dreg, pc); - uint32_t live; DECODE_LITERAL(live, pc); #ifdef IMPL_CODE_LOADER @@ -4699,7 +4730,6 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) DECODE_LABEL(fail, pc) term src; DECODE_COMPACT_TERM(src, pc); - uint32_t live; DECODE_LITERAL(live, pc); term size; DECODE_COMPACT_TERM(size, pc); @@ -4731,7 +4761,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) } else { term_set_match_state_offset(src, bs_offset + increment); - term t = maybe_alloc_boxed_integer_fragment(ctx, value.s); + term t = maybe_alloc_boxed_integer_fragment(ctx, x_regs, value.s); if (UNLIKELY(term_is_invalid_term(t))) { HANDLE_ERROR(); } @@ -4755,7 +4785,6 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) const uint8_t *src_pc = pc; #endif DECODE_COMPACT_TERM(src, pc); - uint32_t live; DECODE_LITERAL(live, pc); term size; DECODE_COMPACT_TERM(size, pc); @@ -4864,14 +4893,16 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) #ifdef IMPL_EXECUTE_LOOP // save pc in case of error const uint8_t *orig_pc = pc - 1; - + #endif + uint32_t arity; + DECODE_LITERAL(arity, pc) + #ifdef IMPL_EXECUTE_LOOP remaining_reductions--; if (UNLIKELY(!remaining_reductions)) { + live = MAX(live, arity + 2); SCHEDULE_NEXT(mod, orig_pc); } #endif - uint32_t arity; - DECODE_LITERAL(arity, pc) #ifdef IMPL_EXECUTE_LOOP term module = x_regs[arity]; term function = x_regs[arity + 1]; @@ -4887,7 +4918,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) TRACE_APPLY(ctx, "apply", module_name, function_name, arity); term native_return; - if (maybe_call_native(ctx, module_name, function_name, arity, &native_return)) { + if (maybe_call_native(ctx, x_regs, module_name, function_name, arity, &native_return)) { PROCESS_MAYBE_TRAP_RETURN_VALUE_RESTORE_PC(native_return, orig_pc); x_regs[0] = native_return; @@ -4913,14 +4944,19 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) } case OP_APPLY_LAST: { + #ifdef IMPL_EXECUTE_LOOP + // pc before arity + const uint8_t *orig_pc = pc - 1; + #endif + uint32_t arity; + DECODE_LITERAL(arity, pc) #ifdef IMPL_EXECUTE_LOOP remaining_reductions--; if (UNLIKELY(!remaining_reductions)) { - SCHEDULE_NEXT(mod, pc - 1); + live = MAX(live, arity + 2); + SCHEDULE_NEXT(mod, orig_pc); } #endif - uint32_t arity; - DECODE_LITERAL(arity, pc) uint32_t n_words; DECODE_LITERAL(n_words, pc); #ifdef IMPL_EXECUTE_LOOP @@ -4941,7 +4977,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) TRACE_APPLY(ctx, "apply_last", module_name, function_name, arity); term native_return; - if (maybe_call_native(ctx, module_name, function_name, arity, &native_return)) { + if (maybe_call_native(ctx, x_regs, module_name, function_name, arity, &native_return)) { PROCESS_MAYBE_TRAP_RETURN_VALUE_LAST(native_return); x_regs[0] = native_return; DO_RETURN(); @@ -5040,7 +5076,6 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) case OP_GC_BIF1: { uint32_t fail_label; DECODE_LABEL(fail_label, pc); - uint32_t live; DECODE_LITERAL(live, pc); uint32_t bif; DECODE_LITERAL(bif, pc); //s? @@ -5050,7 +5085,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) #ifdef IMPL_EXECUTE_LOOP const struct ExportedFunction *exported_bif = mod->imported_funcs[bif]; GCBifImpl1 func = EXPORTED_FUNCTION_TO_GCBIF(exported_bif)->gcbif1_ptr; - term ret = func(ctx, live, arg1); + term ret = func(ctx, x_regs, live, arg1); if (UNLIKELY(term_is_invalid_term(ret))) { if (fail_label) { pc = mod->labels[fail_label]; @@ -5073,7 +5108,6 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) TRACE("gc_bif1/5\n"); UNUSED(fail_label) - UNUSED(live) UNUSED(bif) UNUSED(arg1) UNUSED(dreg) @@ -5084,7 +5118,6 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) case OP_GC_BIF2: { uint32_t fail_label; DECODE_LABEL(fail_label, pc); - uint32_t live; DECODE_LITERAL(live, pc); uint32_t bif; DECODE_LITERAL(bif, pc); //s? @@ -5096,7 +5129,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) #ifdef IMPL_EXECUTE_LOOP const struct ExportedFunction *exported_bif = mod->imported_funcs[bif]; GCBifImpl2 func = EXPORTED_FUNCTION_TO_GCBIF(exported_bif)->gcbif2_ptr; - term ret = func(ctx, live, arg1, arg2); + term ret = func(ctx, x_regs, live, arg1, arg2); if (UNLIKELY(term_is_invalid_term(ret))) { if (fail_label) { pc = mod->labels[fail_label]; @@ -5119,7 +5152,6 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) TRACE("gc_bif2/6\n"); UNUSED(fail_label) - UNUSED(live) UNUSED(bif) UNUSED(arg1) UNUSED(arg2) @@ -5154,7 +5186,6 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) case OP_GC_BIF3: { uint32_t fail_label; DECODE_LABEL(fail_label, pc); - uint32_t live; DECODE_LITERAL(live, pc); uint32_t bif; DECODE_LITERAL(bif, pc); //s? @@ -5168,7 +5199,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) #ifdef IMPL_EXECUTE_LOOP const struct ExportedFunction *exported_bif = mod->imported_funcs[bif]; GCBifImpl3 func = EXPORTED_FUNCTION_TO_GCBIF(exported_bif)->gcbif3_ptr; - term ret = func(ctx, live, arg1, arg2, arg3); + term ret = func(ctx, x_regs, live, arg1, arg2, arg3); if (UNLIKELY(term_is_invalid_term(ret))) { if (fail_label) { pc = mod->labels[fail_label]; @@ -5191,7 +5222,6 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) TRACE("gc_bif2/6\n"); UNUSED(fail_label) - UNUSED(live) UNUSED(bif) UNUSED(arg1) UNUSED(arg2) @@ -5267,7 +5297,6 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) DECODE_COMPACT_TERM(src, pc); dreg_gc_safe_t dreg; DECODE_DEST_REGISTER_GC_SAFE(dreg, pc); - uint32_t live; DECODE_LITERAL(live, pc); TRACE("put_map_assoc/5: label: %i src: 0x%lx dest=%c%i live: %i\n", label, src, T_DEST_REG_GC_SAFE(dreg), live); @@ -5396,7 +5425,6 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) DECODE_COMPACT_TERM(src, pc); dreg_gc_safe_t dreg; DECODE_DEST_REGISTER_GC_SAFE(dreg, pc); - uint32_t live; DECODE_LITERAL(live, pc); TRACE("put_map_exact/5: label: %i src: 0x%lx dest=%c%i live: %i\n", label, src, T_DEST_REG_GC_SAFE(dreg), live); @@ -5604,7 +5632,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) #ifdef IMPL_EXECUTE_LOOP TRACE("fmove/2 fp%i, %c%i\n", freg, T_DEST_REG(dreg)); // Space should be available on heap as compiler added an allocate opcode - context_ensure_fpregs(ctx); + context_ensure_fpregs(ctx, freg + 1); term float_value = term_from_float(ctx->fr[freg], &ctx->heap); WRITE_REGISTER(dreg, float_value); #endif @@ -5620,7 +5648,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) DECODE_FP_REGISTER(freg, pc); #ifdef IMPL_EXECUTE_LOOP TRACE("fmove/2 %lx, fp%i\n", src_value, freg); - context_ensure_fpregs(ctx); + context_ensure_fpregs(ctx, freg + 1); ctx->fr[freg] = term_to_float(src_value); #endif #ifdef IMPL_CODE_LOADER @@ -5640,7 +5668,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) #ifdef IMPL_EXECUTE_LOOP TRACE("fconv/2 %lx, fp%i\n", src_value, freg); - context_ensure_fpregs(ctx); + context_ensure_fpregs(ctx, freg + 1); ctx->fr[freg] = term_conv_to_float(src_value); #endif @@ -5667,7 +5695,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) #ifdef HAVE_PRAGMA_STDC_FENV_ACCESS feclearexcept(FE_OVERFLOW); #endif - context_ensure_fpregs(ctx); + context_ensure_fpregs(ctx, MAX(MAX(freg1, freg2), freg3) + 1); ctx->fr[freg3] = ctx->fr[freg1] + ctx->fr[freg2]; #ifdef HAVE_PRAGMA_STDC_FENV_ACCESS if (fetestexcept(FE_OVERFLOW)) { @@ -5714,7 +5742,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) #ifdef HAVE_PRAGMA_STDC_FENV_ACCESS feclearexcept(FE_OVERFLOW); #endif - context_ensure_fpregs(ctx); + context_ensure_fpregs(ctx, MAX(MAX(freg1, freg2), freg3) + 1); ctx->fr[freg3] = ctx->fr[freg1] - ctx->fr[freg2]; #ifdef HAVE_PRAGMA_STDC_FENV_ACCESS if (fetestexcept(FE_OVERFLOW)) { @@ -5761,7 +5789,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) #ifdef HAVE_PRAGMA_STDC_FENV_ACCESS feclearexcept(FE_OVERFLOW); #endif - context_ensure_fpregs(ctx); + context_ensure_fpregs(ctx, MAX(MAX(freg1, freg2), freg3) + 1); ctx->fr[freg3] = ctx->fr[freg1] * ctx->fr[freg2]; #ifdef HAVE_PRAGMA_STDC_FENV_ACCESS if (fetestexcept(FE_OVERFLOW)) { @@ -5808,7 +5836,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) #ifdef HAVE_PRAGMA_STDC_FENV_ACCESS feclearexcept(FE_OVERFLOW | FE_DIVBYZERO); #endif - context_ensure_fpregs(ctx); + context_ensure_fpregs(ctx, MAX(MAX(freg1, freg2), freg3) + 1); ctx->fr[freg3] = ctx->fr[freg1] / ctx->fr[freg2]; #ifdef HAVE_PRAGMA_STDC_FENV_ACCESS if (fetestexcept(FE_OVERFLOW | FE_DIVBYZERO)) { @@ -5848,7 +5876,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) DECODE_FP_REGISTER(freg2, pc); #ifdef IMPL_EXECUTE_LOOP TRACE("fnegate/2 fp%i, fp%i\n", freg1, freg2); - context_ensure_fpregs(ctx); + context_ensure_fpregs(ctx, MAX(freg1, freg2) + 1); ctx->fr[freg2] = - ctx->fr[freg1]; #endif @@ -5866,7 +5894,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) #ifdef IMPL_EXECUTE_LOOP - x_regs[0] = stacktrace_build(ctx, &x_regs[0], 1); + x_regs[0] = stacktrace_build(ctx, x_regs, &x_regs[0], 1); #endif break; @@ -5985,7 +6013,6 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) AVM_ABORT(); } #endif - uint32_t live; DECODE_LITERAL(live, pc); #ifdef IMPL_EXECUTE_LOOP // MEMORY_CAN_SHRINK because bs_start_match is classified as gc in beam_ssa_codegen.erl @@ -6112,7 +6139,6 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) DECODE_LABEL(fail, pc); uint32_t alloc; DECODE_LITERAL(alloc, pc); - uint32_t live; DECODE_LITERAL(live, pc); uint32_t unit; DECODE_LITERAL(unit, pc); @@ -6542,7 +6568,6 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) } case INTEGER_ATOM: { - uint32_t live; DECODE_LITERAL(live, pc); j++; term flags; @@ -6569,7 +6594,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) TRACE("bs_match/3: error extracting integer.\n"); goto bs_match_jump_to_fail; } - term t = maybe_alloc_boxed_integer_fragment(ctx, value.s); + term t = maybe_alloc_boxed_integer_fragment(ctx, x_regs, value.s); if (UNLIKELY(term_is_invalid_term(t))) { RAISE_ERROR(OUT_OF_MEMORY_ATOM); } @@ -6585,7 +6610,6 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) } case BINARY_ATOM: { - uint32_t live; DECODE_LITERAL(live, pc); j++; term flags; @@ -6631,7 +6655,6 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) } case GET_TAIL_ATOM: { - uint32_t live; DECODE_LITERAL(live, pc); j++; int unit; @@ -6725,6 +6748,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) printf("Undecoded opcode: %i\n", *pc); #ifdef IMPL_EXECUTE_LOOP fprintf(stderr, "failed at %" PRIuPTR "\n", pc - code); + free(x_regs); #endif AVM_ABORT(); return 1; @@ -6749,13 +6773,13 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) // Do not print crash dump if reason is normal. if (x_regs[0] != LOWERCASE_EXIT_ATOM || x_regs[1] != NORMAL_ATOM) { - dump(ctx); + dump(ctx, x_regs); } if (x_regs[0] == LOWERCASE_EXIT_ATOM) { ctx->exit_reason = x_regs[1]; } else { - bool throw = ctx->x[0] == THROW_ATOM; + bool throw = x_regs[0] == THROW_ATOM; int exit_reason_tuple_size = (throw ? TUPLE_SIZE(2) : 0) + TUPLE_SIZE(2); if (memory_ensure_free_with_roots(ctx, exit_reason_tuple_size, 1, x_regs + 1, MEMORY_CAN_SHRINK) != MEMORY_GC_OK) { @@ -6783,6 +6807,8 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb) GlobalContext *global = ctx->global; if (ctx->leader) { scheduler_stop_all(global); + // Save result for main and tests + context_save_xregs(ctx, x_regs, 1); } scheduler_terminate(ctx); ctx = scheduler_run(global); diff --git a/src/libAtomVM/otp_crypto.c b/src/libAtomVM/otp_crypto.c index 8a1a3ae37d..da59516069 100644 --- a/src/libAtomVM/otp_crypto.c +++ b/src/libAtomVM/otp_crypto.c @@ -364,7 +364,7 @@ static bool bool_to_mbedtls_operation(term encrypt_flag, mbedtls_operation_t *op } } -static term make_crypto_error(const char *file, int line, const char *message, Context *ctx) +static term make_crypto_error(Context *ctx, term argv[], const char *file, int line, const char *message) { int err_needed_mem = (strlen(file) * CONS_SIZE) + TUPLE_SIZE(2) + (strlen(message) * CONS_SIZE) + TUPLE_SIZE(3); @@ -410,7 +410,7 @@ static term nif_crypto_crypto_one_time(Context *ctx, int argc, term argv[]) mbedtls_cipher_type_t cipher = interop_atom_term_select_int(cipher_table, cipher_term, ctx->global); if (UNLIKELY(cipher == MBEDTLS_CIPHER_NONE)) { - RAISE_ERROR(make_crypto_error(__FILE__, __LINE__, "Unknown cipher", ctx)); + RAISE_ERROR(make_crypto_error(ctx, argv, __FILE__, __LINE__, "Unknown cipher")); } // from this point onward use `goto raise_error` in order to raise and free all buffers @@ -558,7 +558,7 @@ static term nif_crypto_crypto_one_time(Context *ctx, int argc, term argv[]) char err_msg[24]; snprintf(err_msg, sizeof(err_msg), "Error %x", -result); - RAISE_ERROR(make_crypto_error(__FILE__, source_line, err_msg, ctx)); + RAISE_ERROR(make_crypto_error(ctx, argv, __FILE__, source_line, err_msg)); } static const struct Nif crypto_hash_nif = { diff --git a/src/libAtomVM/otp_socket.c b/src/libAtomVM/otp_socket.c index 8fca3e3eef..2c5fcddf87 100644 --- a/src/libAtomVM/otp_socket.c +++ b/src/libAtomVM/otp_socket.c @@ -424,7 +424,7 @@ static inline int get_protocol(GlobalContext *global, term protocol_term, bool * * memory exception. * @end */ -static inline term make_error_tuple(term reason, Context *ctx) +static inline term make_error_tuple(Context *ctx, term argv[], term reason) { if (UNLIKELY(memory_ensure_free(ctx, TUPLE_SIZE(2)) != MEMORY_GC_OK)) { AVM_LOGW(TAG, "Failed to allocate memory: %s:%i.", __FILE__, __LINE__); @@ -440,14 +440,14 @@ static inline term make_error_tuple(term reason, Context *ctx) /** * @brief Like make_error_tuple but using errno converted to an atom or an int */ -static term make_errno_tuple(Context *ctx) +static term make_errno_tuple(Context *ctx, term argv[]) { - return make_error_tuple(posix_errno_to_term(errno, ctx->global), ctx); + return make_error_tuple(ctx, argv, posix_errno_to_term(errno, ctx->global)); } #elif OTP_SOCKET_LWIP -static term make_lwip_err_tuple(err_t err, Context *ctx) +static term make_lwip_err_tuple(Context *ctx, term argv[], err_t err) { - return make_error_tuple(term_from_int(err), ctx); + return make_error_tuple(ctx, argv, term_from_int(err)); } #endif @@ -488,7 +488,7 @@ static term nif_socket_open(Context *ctx, int argc, term argv[]) if (UNLIKELY(rsrc_obj->fd == -1 || rsrc_obj->fd == CLOSED_FD)) { AVM_LOGE(TAG, "Failed to initialize socket."); enif_release_resource(rsrc_obj); - return make_errno_tuple(ctx); + return make_errno_tuple(ctx, argv); } else { TRACE("nif_socket_open: Created socket fd=%i\n", rsrc_obj->fd); rsrc_obj->selecting_process_id = INVALID_PROCESS_ID; @@ -1011,7 +1011,7 @@ static term nif_socket_setopt(Context *ctx, int argc, term argv[]) #elif OTP_SOCKET_LWIP if (rsrc_obj->socket_state == SocketStateClosed) { #endif - return make_error_tuple(posix_errno_to_term(EBADF, global), ctx); + return make_error_tuple(ctx, argv, posix_errno_to_term(EBADF, global)); } term level_tuple = argv[1]; term value = argv[2]; @@ -1022,7 +1022,7 @@ static term nif_socket_setopt(Context *ctx, int argc, term argv[]) #if OTP_SOCKET_BSD int res = setsockopt(rsrc_obj->fd, SOL_SOCKET, SO_REUSEADDR, &option_value, sizeof(int)); if (UNLIKELY(res != 0)) { - return make_errno_tuple(ctx); + return make_errno_tuple(ctx, argv); } else { return OK_ATOM; } @@ -1055,7 +1055,7 @@ static term nif_socket_setopt(Context *ctx, int argc, term argv[]) sl.l_linger = term_to_int(linger); int res = setsockopt(rsrc_obj->fd, SOL_SOCKET, SO_LINGER, &sl, sizeof(sl)); if (UNLIKELY(res != 0)) { - return make_errno_tuple(ctx); + return make_errno_tuple(ctx, argv); } else { return OK_ATOM; } @@ -1097,7 +1097,7 @@ static term nif_socket_sockname(Context *ctx, int argc, term argv[]) #elif OTP_SOCKET_LWIP if (rsrc_obj->socket_state == SocketStateClosed) { #endif - return make_error_tuple(posix_errno_to_term(EBADF, global), ctx); + return make_error_tuple(ctx, argv, posix_errno_to_term(EBADF, global)); } #if OTP_SOCKET_BSD @@ -1107,7 +1107,7 @@ static term nif_socket_sockname(Context *ctx, int argc, term argv[]) if (UNLIKELY(res != 0)) { AVM_LOGE(TAG, "Unable to getsockname: fd=%i res=%i.", rsrc_obj->fd, res); - return make_errno_tuple(ctx); + return make_errno_tuple(ctx, argv); } uint32_t ip4_u32 = ntohl(addr.sin_addr.s_addr); uint16_t port_u16 = ntohs(addr.sin_port); @@ -1162,18 +1162,18 @@ static term nif_socket_peername(Context *ctx, int argc, term argv[]) #if OTP_SOCKET_BSD if (rsrc_obj->fd == 0) { - return make_error_tuple(posix_errno_to_term(EBADF, global), ctx); + return make_error_tuple(ctx, argv, posix_errno_to_term(EBADF, global)); } #elif OTP_SOCKET_LWIP if (rsrc_obj->socket_state == SocketStateClosed) { - return make_error_tuple(posix_errno_to_term(EBADF, global), ctx); + return make_error_tuple(ctx, argv, posix_errno_to_term(EBADF, global)); } if (rsrc_obj->socket_state & SocketStateUDP) { // TODO: handle "connected" UDP sockets - return make_error_tuple(posix_errno_to_term(EOPNOTSUPP, global), ctx); + return make_error_tuple(ctx, argv, posix_errno_to_term(EOPNOTSUPP, global)); } if ((rsrc_obj->socket_state & SocketStateTCPListening) == SocketStateTCPListening) { - return make_error_tuple(posix_errno_to_term(ENOTCONN, global), ctx); + return make_error_tuple(ctx, argv, posix_errno_to_term(ENOTCONN, global)); } #endif @@ -1184,7 +1184,7 @@ static term nif_socket_peername(Context *ctx, int argc, term argv[]) if (UNLIKELY(res != 0)) { AVM_LOGE(TAG, "Unable to getpeername: fd=%i res=%i.", rsrc_obj->fd, res); - return make_errno_tuple(ctx); + return make_errno_tuple(ctx, argv); } uint32_t ip4_u32 = ntohl(addr.sin_addr.s_addr); uint16_t port_u16 = ntohs(addr.sin_port); @@ -1231,11 +1231,11 @@ static term nif_socket_bind(Context *ctx, int argc, term argv[]) #if OTP_SOCKET_BSD TRACE("rsrc_obj->fd=%i\n", (int) rsrc_obj->fd); if (rsrc_obj->fd == 0) { - return make_error_tuple(posix_errno_to_term(EBADF, global), ctx); + return make_error_tuple(ctx, argv, posix_errno_to_term(EBADF, global)); } #elif OTP_SOCKET_LWIP if (rsrc_obj->socket_state == SocketStateClosed) { - return make_error_tuple(posix_errno_to_term(EBADF, global), ctx); + return make_error_tuple(ctx, argv, posix_errno_to_term(EBADF, global)); } #endif @@ -1294,7 +1294,7 @@ static term nif_socket_bind(Context *ctx, int argc, term argv[]) int res = bind(rsrc_obj->fd, (struct sockaddr *) &serveraddr, address_len); if (UNLIKELY(res != 0)) { AVM_LOGE(TAG, "Unable to bind socket: res=%i.", res); - return make_errno_tuple(ctx); + return make_errno_tuple(ctx, argv); } else { return OK_ATOM; } @@ -1307,7 +1307,7 @@ static term nif_socket_bind(Context *ctx, int argc, term argv[]) } if (UNLIKELY(res != ERR_OK)) { AVM_LOGE(TAG, "Unable to bind socket: res=%i.", res); - return make_lwip_err_tuple(res, ctx); + return make_lwip_err_tuple(ctx, argv, res); } else { return OK_ATOM; } @@ -1334,14 +1334,14 @@ static term nif_socket_listen(Context *ctx, int argc, term argv[]) } #if OTP_SOCKET_BSD if (rsrc_obj->fd == 0) { - return make_error_tuple(posix_errno_to_term(EBADF, global), ctx); + return make_error_tuple(ctx, argv, posix_errno_to_term(EBADF, global)); } #elif OTP_SOCKET_LWIP if (rsrc_obj->socket_state == SocketStateClosed) { - return make_error_tuple(posix_errno_to_term(EBADF, global), ctx); + return make_error_tuple(ctx, argv, posix_errno_to_term(EBADF, global)); } if (rsrc_obj->socket_state & SocketStateUDP) { - return make_error_tuple(posix_errno_to_term(EPROTOTYPE, global), ctx); + return make_error_tuple(ctx, argv, posix_errno_to_term(EPROTOTYPE, global)); } #endif @@ -1351,7 +1351,7 @@ static term nif_socket_listen(Context *ctx, int argc, term argv[]) int res = listen(rsrc_obj->fd, backlog); if (UNLIKELY(res != 0)) { AVM_LOGE(TAG, "Unable to listen on socket: res=%i.", res); - return make_errno_tuple(ctx); + return make_errno_tuple(ctx, argv); } else { return OK_ATOM; } @@ -1370,7 +1370,7 @@ static term nif_socket_listen(Context *ctx, int argc, term argv[]) err_t err; struct tcp_pcb *new_pcb = tcp_listen_with_backlog_and_err(rsrc_obj->tcp_pcb, backlog_u8, &err); if (new_pcb == NULL) { - return make_lwip_err_tuple(err, ctx); + return make_lwip_err_tuple(ctx, argv, err); } // Define accept callback tcp_accept(new_pcb, tcp_accept_cb); @@ -1413,18 +1413,18 @@ static term nif_socket_accept(Context *ctx, int argc, term argv[]) } #if OTP_SOCKET_BSD if (rsrc_obj->fd == 0) { - return make_error_tuple(posix_errno_to_term(EBADF, global), ctx); + return make_error_tuple(ctx, argv, posix_errno_to_term(EBADF, global)); } #elif OTP_SOCKET_LWIP if (rsrc_obj->socket_state & SocketStateClosed) { - return make_error_tuple(posix_errno_to_term(EBADF, global), ctx); + return make_error_tuple(ctx, argv, posix_errno_to_term(EBADF, global)); } if (rsrc_obj->socket_state & SocketStateUDP) { - return make_error_tuple(posix_errno_to_term(EOPNOTSUPP, global), ctx); + return make_error_tuple(ctx, argv, posix_errno_to_term(EOPNOTSUPP, global)); } // Only listening is allowed if ((rsrc_obj->socket_state & SocketStateTCPListening) != SocketStateTCPListening) { - return make_error_tuple(posix_errno_to_term(EINVAL, global), ctx); + return make_error_tuple(ctx, argv, posix_errno_to_term(EINVAL, global)); } #endif @@ -1436,7 +1436,7 @@ static term nif_socket_accept(Context *ctx, int argc, term argv[]) AVM_LOGE(TAG, "Unable to accept on socket %i.", rsrc_obj->fd); int err = errno; term reason = (err == ECONNABORTED) ? CLOSED_ATOM : posix_errno_to_term(err, global); - return make_error_tuple(reason, ctx); + return make_error_tuple(ctx, argv, reason); } else { struct SocketResource *conn_rsrc_obj = enif_alloc_resource(socket_resource_type, sizeof(struct SocketResource)); @@ -1493,7 +1493,7 @@ static term nif_socket_accept(Context *ctx, int argc, term argv[]) term_put_tuple_element(result, 1, socket_term); } else { // return EAGAIN - return make_error_tuple(posix_errno_to_term(EAGAIN, ctx->global), ctx); + return make_error_tuple(ctx, argv, posix_errno_to_term(EAGAIN, ctx->global)); } LWIP_END(); return result; @@ -1645,7 +1645,7 @@ ssize_t socket_recv(struct SocketResource *rsrc_obj, uint8_t *buf, size_t len, i } #if OTP_SOCKET_BSD -static term nif_socket_recv_with_peek(Context *ctx, struct SocketResource *rsrc_obj, size_t len, bool is_recvfrom) +static term nif_socket_recv_with_peek(Context *ctx, term argv[], struct SocketResource *rsrc_obj, size_t len, bool is_recvfrom) { TRACE("nif_socket_recv_with_peek\n"); @@ -1657,10 +1657,10 @@ static term nif_socket_recv_with_peek(Context *ctx, struct SocketResource *rsrc_ TRACE("%li bytes available.\n", (long int) res); if (res < 0) { AVM_LOGI(TAG, "Unable to receive data on fd %i. errno=%i", rsrc_obj->fd, errno); - return make_errno_tuple(ctx); + return make_errno_tuple(ctx, argv); } else if (res == 0) { TRACE("Peer closed socket %i.\n", rsrc_obj->fd); - return make_error_tuple(CLOSED_ATOM, ctx); + return make_error_tuple(ctx, argv, CLOSED_ATOM); } else { ssize_t buffer_size = len == 0 ? (ssize_t) res : MIN((size_t) res, len); @@ -1697,7 +1697,7 @@ static term nif_socket_recv_with_peek(Context *ctx, struct SocketResource *rsrc_ } } -static term nif_socket_recv_without_peek(Context *ctx, struct SocketResource *rsrc_obj, size_t len, bool is_recvfrom) +static term nif_socket_recv_without_peek(Context *ctx, term argv[], struct SocketResource *rsrc_obj, size_t len, bool is_recvfrom) { TRACE("nif_socket_recv_without_peek\n"); @@ -1735,11 +1735,11 @@ static term nif_socket_recv_without_peek(Context *ctx, struct SocketResource *rs AVM_LOGE(TAG, "Unable to read data on socket %i. errno=%i", rsrc_obj->fd, errno); } - return make_error_tuple(reason, ctx); + return make_error_tuple(ctx, argv, reason); } else if (res == 0) { TRACE("Peer closed socket %i.\n", rsrc_obj->fd); - return make_error_tuple(CLOSED_ATOM, ctx); + return make_error_tuple(ctx, argv, CLOSED_ATOM); } else { size_t len = (size_t) res; @@ -1772,7 +1772,7 @@ static term nif_socket_recv_without_peek(Context *ctx, struct SocketResource *rs #elif OTP_SOCKET_LWIP -static term nif_socket_recv_lwip(Context *ctx, struct SocketResource *rsrc_obj, size_t len, bool is_recvfrom) +static term nif_socket_recv_lwip(Context *ctx, term argv[], struct SocketResource *rsrc_obj, size_t len, bool is_recvfrom) { TRACE("nif_socket_recv_lwip\n"); @@ -1815,12 +1815,12 @@ static term nif_socket_recv_lwip(Context *ctx, struct SocketResource *rsrc_obj, // If we have no data, return EAGAIN or closed or the error. if (buffer_size == 0) { if (closed) { - return make_error_tuple(CLOSED_ATOM, ctx); + return make_error_tuple(ctx, argv, CLOSED_ATOM); } if (err != ERR_OK) { - return make_error_tuple(term_from_int(err), ctx); + return make_error_tuple(ctx, argv, term_from_int(err)); } - return make_error_tuple(posix_errno_to_term(EAGAIN, global), ctx); + return make_error_tuple(ctx, argv, posix_errno_to_term(EAGAIN, global)); } size_t ensure_packet_avail = term_binary_data_size_in_terms(len) + BINARY_HEADER_SIZE; @@ -1868,25 +1868,25 @@ static term nif_socket_recv_internal(Context *ctx, term argv[], bool is_recvfrom } #if OTP_SOCKET_BSD if (rsrc_obj->fd == 0) { - return make_error_tuple(posix_errno_to_term(EBADF, ctx->global), ctx); + return make_error_tuple(ctx, argv, posix_errno_to_term(EBADF, ctx->global)); } #elif OTP_SOCKET_LWIP if (rsrc_obj->socket_state & SocketStateClosed) { - return make_error_tuple(posix_errno_to_term(EBADF, ctx->global), ctx); + return make_error_tuple(ctx, argv, posix_errno_to_term(EBADF, ctx->global)); } if (rsrc_obj->socket_state & SocketStateListening) { - return make_error_tuple(posix_errno_to_term(EOPNOTSUPP, ctx->global), ctx); + return make_error_tuple(ctx, argv, posix_errno_to_term(EOPNOTSUPP, ctx->global)); } #endif #if OTP_SOCKET_BSD if (otp_socket_platform_supports_peek()) { - return nif_socket_recv_with_peek(ctx, rsrc_obj, len, is_recvfrom); + return nif_socket_recv_with_peek(ctx, argv, rsrc_obj, len, is_recvfrom); } else { - return nif_socket_recv_without_peek(ctx, rsrc_obj, len, is_recvfrom); + return nif_socket_recv_without_peek(ctx, argv, rsrc_obj, len, is_recvfrom); } #elif OTP_SOCKET_LWIP - return nif_socket_recv_lwip(ctx, rsrc_obj, len, is_recvfrom); + return nif_socket_recv_lwip(ctx, argv, rsrc_obj, len, is_recvfrom); #endif } @@ -2032,14 +2032,14 @@ static term nif_socket_send_internal(Context *ctx, int argc, term argv[], bool i #if OTP_SOCKET_BSD if (rsrc_obj->fd == 0) { - return make_error_tuple(posix_errno_to_term(EBADF, global), ctx); + return make_error_tuple(ctx, argv, posix_errno_to_term(EBADF, global)); } #elif OTP_SOCKET_LWIP if (rsrc_obj->socket_state == SocketStateClosed) { - return make_error_tuple(posix_errno_to_term(EBADF, global), ctx); + return make_error_tuple(ctx, argv, posix_errno_to_term(EBADF, global)); } if (rsrc_obj->socket_state & SocketStateListening) { - return make_error_tuple(posix_errno_to_term(EOPNOTSUPP, global), ctx); + return make_error_tuple(ctx, argv, posix_errno_to_term(EOPNOTSUPP, global)); } #endif @@ -2079,7 +2079,7 @@ static term nif_socket_send_internal(Context *ctx, int argc, term argv[], bool i return port_create_tuple2(ctx, OK_ATOM, data); } else { AVM_LOGE(TAG, "Unable to send data: res=%zi.", sent_data); - return make_error_tuple(CLOSED_ATOM, ctx); + return make_error_tuple(ctx, argv, CLOSED_ATOM); } } @@ -2183,15 +2183,15 @@ static term nif_socket_connect(Context *ctx, int argc, term argv[]) #if OTP_SOCKET_BSD if (rsrc_obj->fd == 0) { - return make_error_tuple(posix_errno_to_term(EBADF, global), ctx); + return make_error_tuple(ctx, argv, posix_errno_to_term(EBADF, global)); } #elif OTP_SOCKET_LWIP if (rsrc_obj->socket_state == SocketStateClosed) { - return make_error_tuple(posix_errno_to_term(EBADF, global), ctx); + return make_error_tuple(ctx, argv, posix_errno_to_term(EBADF, global)); } if (((rsrc_obj->socket_state & SocketStateTCPListening) == SocketStateTCPListening) || ((rsrc_obj->socket_state & SocketStateTCPConnected) == SocketStateTCPConnected)) { - return make_error_tuple(posix_errno_to_term(EOPNOTSUPP, global), ctx); + return make_error_tuple(ctx, argv, posix_errno_to_term(EOPNOTSUPP, global)); } #endif @@ -2219,7 +2219,7 @@ static term nif_socket_connect(Context *ctx, int argc, term argv[]) } else { AVM_LOGE(TAG, "Unable to connect: res=%i errno=%i", res, errno); - return make_error_tuple(CLOSED_ATOM, ctx); + return make_error_tuple(ctx, argv, CLOSED_ATOM); } } else if (res == 0) { return OK_ATOM; @@ -2297,7 +2297,7 @@ static term nif_socket_shutdown(Context *ctx, int argc, term argv[]) #elif OTP_SOCKET_LWIP if (rsrc_obj->socket_state == SocketStateClosed) { #endif - return make_error_tuple(posix_errno_to_term(EBADF, global), ctx); + return make_error_tuple(ctx, argv, posix_errno_to_term(EBADF, global)); } term result = OK_ATOM; @@ -2306,7 +2306,7 @@ static term nif_socket_shutdown(Context *ctx, int argc, term argv[]) int res = shutdown(rsrc_obj->fd, how); if (res < 0) { AVM_LOGE(TAG, "Unable to shut down socket: res=%i errno=%i", res, errno); - return make_errno_tuple(ctx); + return make_errno_tuple(ctx, argv); } #elif OTP_SOCKET_LWIP LWIP_BEGIN(); @@ -2317,7 +2317,7 @@ static term nif_socket_shutdown(Context *ctx, int argc, term argv[]) } if (res != ERR_OK) { AVM_LOGE(TAG, "Unable to shut down socket: res=%i", res); - result = make_lwip_err_tuple(res, ctx); + result = make_lwip_err_tuple(ctx, argv, res); } } LWIP_END(); diff --git a/src/libAtomVM/otp_ssl.c b/src/libAtomVM/otp_ssl.c index b2a4853861..dc348d9756 100644 --- a/src/libAtomVM/otp_ssl.c +++ b/src/libAtomVM/otp_ssl.c @@ -485,7 +485,7 @@ static term nif_ssl_setup(Context *ctx, int argc, term argv[]) return OK_ATOM; } -static term make_err_result(int err, Context *ctx) +static term make_err_result(int err, Context *ctx, term argv[]) { switch (err) { case 0: @@ -537,7 +537,7 @@ static term nif_ssl_handshake_step(Context *ctx, int argc, term argv[]) return globalcontext_make_atom(ctx->global, ATOM_STR("\x4", "done")); } #endif - return make_err_result(err, ctx); + return make_err_result(err, ctx, argv); } static term nif_ssl_close_notify(Context *ctx, int argc, term argv[]) @@ -552,7 +552,7 @@ static term nif_ssl_close_notify(Context *ctx, int argc, term argv[]) struct SSLContextResource *context_rsrc = (struct SSLContextResource *) rsrc_obj_ptr; int err = mbedtls_ssl_close_notify(&context_rsrc->context); - return make_err_result(err, ctx); + return make_err_result(err, ctx, argv); } static term nif_ssl_write(Context *ctx, int argc, term argv[]) @@ -589,7 +589,7 @@ static term nif_ssl_write(Context *ctx, int argc, term argv[]) return port_create_tuple2(ctx, OK_ATOM, rest); } - return make_err_result(res, ctx); + return make_err_result(res, ctx, argv); } static term nif_ssl_read(Context *ctx, int argc, term argv[]) @@ -644,7 +644,7 @@ static term nif_ssl_read(Context *ctx, int argc, term argv[]) return port_create_tuple2(ctx, OK_ATOM, rest); } - return make_err_result(res, ctx); + return make_err_result(res, ctx, argv); } static const struct Nif ssl_entropy_init_nif = { diff --git a/src/libAtomVM/scheduler.h b/src/libAtomVM/scheduler.h index 7dd1493710..43d91d6360 100644 --- a/src/libAtomVM/scheduler.h +++ b/src/libAtomVM/scheduler.h @@ -113,6 +113,7 @@ void scheduler_cancel_timeout(Context *ctx); * @brief Entry point for schedulers. * * @param glb the global context. + * @return the result of the execution, 0 on success and 1 on error */ int scheduler_entry_point(GlobalContext *glb); diff --git a/src/libAtomVM/stacktrace.c b/src/libAtomVM/stacktrace.c index e339465099..3b7f92c40a 100644 --- a/src/libAtomVM/stacktrace.c +++ b/src/libAtomVM/stacktrace.c @@ -25,18 +25,21 @@ #ifndef AVM_CREATE_STACKTRACES -term stacktrace_create_raw(Context *ctx, Module *mod, int current_offset, term exception_class) +term stacktrace_create_raw(Context *ctx, term *x_regs, Module *mod, int current_offset, term exception_class) { UNUSED(ctx); + UNUSED(x_regs); UNUSED(mod); UNUSED(current_offset); return exception_class; } -term stacktrace_build(Context *ctx, term *stack_info, uint32_t live) +term stacktrace_build(Context *ctx, term *x_regs, term *stack_info, uint32_t live) { UNUSED(ctx); + UNUSED(x_regs); UNUSED(stack_info); + UNUSED(live); return UNDEFINED_ATOM; } @@ -85,7 +88,7 @@ static bool is_module_member(Module *mod, Module **mods, unsigned long len) return false; } -term stacktrace_create_raw(Context *ctx, Module *mod, int current_offset, term exception_class) +term stacktrace_create_raw(Context *ctx, term *x_regs, Module *mod, int current_offset, term exception_class) { unsigned int num_frames = 0; unsigned int num_aux_terms = 0; @@ -165,7 +168,7 @@ term stacktrace_create_raw(Context *ctx, Module *mod, int current_offset, term e // {num_frames, num_aux_terms, filename_lens, num_mods, [{module, offset}, ...]} size_t requested_size = TUPLE_SIZE(6) + num_frames * (2 + TUPLE_SIZE(2)); // We need to preserve x0 and x1 that contain information on the current exception - if (UNLIKELY(memory_ensure_free_with_roots(ctx, requested_size, 2, ctx->x, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { + if (UNLIKELY(memory_ensure_free_with_roots(ctx, requested_size, 2, x_regs, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { fprintf(stderr, "WARNING: Unable to allocate heap space for raw stacktrace\n"); return OUT_OF_MEMORY_ATOM; } @@ -256,7 +259,7 @@ static term find_path_created(term module_name, struct ModulePathPair *module_pa return term_invalid_term(); } -term stacktrace_build(Context *ctx, term *stack_info, uint32_t live) +term stacktrace_build(Context *ctx, term *x_regs, term *stack_info, uint32_t live) { GlobalContext *glb = ctx->global; @@ -282,7 +285,7 @@ term stacktrace_build(Context *ctx, term *stack_info, uint32_t live) // [{module, function, arity, [{file, string()}, {line, int}]}, ...] // size_t requested_size = (TUPLE_SIZE(4) + 2) * num_frames + num_aux_terms * (4 + 2 * TUPLE_SIZE(2)) + 2 * filename_lens; - if (UNLIKELY(memory_ensure_free_with_roots(ctx, requested_size, live, ctx->x, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { + if (UNLIKELY(memory_ensure_free_with_roots(ctx, requested_size, live, x_regs, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { free(module_paths); return OUT_OF_MEMORY_ATOM; } diff --git a/src/libAtomVM/stacktrace.h b/src/libAtomVM/stacktrace.h index 6702371b13..b91d6fddaf 100644 --- a/src/libAtomVM/stacktrace.h +++ b/src/libAtomVM/stacktrace.h @@ -29,15 +29,16 @@ extern "C" { #include "module.h" #include "term.h" -term stacktrace_create_raw(Context *ctx, Module *mod, int current_offset, term exception_class); +term stacktrace_create_raw(Context *ctx, term *x_regs, Module *mod, int current_offset, term exception_class); /** * @brief Build a stack trace * @param ctx context + * @param x_regs x registers * @param stack_info pointer to stack info tuple * @param live number of x registers to preserve, which should include stack_info * @return the built stack trace */ -term stacktrace_build(Context *ctx, term *stack_info, uint32_t live); +term stacktrace_build(Context *ctx, term *x_regs, term *stack_info, uint32_t live); term stacktrace_exception_class(term stack_info); #ifdef __cplusplus diff --git a/src/platforms/emscripten/src/lib/platform_nifs.c b/src/platforms/emscripten/src/lib/platform_nifs.c index a208ec2ceb..2288b59a2a 100644 --- a/src/platforms/emscripten/src/lib/platform_nifs.c +++ b/src/platforms/emscripten/src/lib/platform_nifs.c @@ -252,7 +252,7 @@ static bool get_register_callback_parameters(Context *ctx, int argc, term argv[] return true; } -static term term_from_emscripten_result(EMSCRIPTEN_RESULT em_result, Context *ctx) +static term term_from_emscripten_result(EMSCRIPTEN_RESULT em_result, Context *ctx, term argv[]) { if (em_result == EMSCRIPTEN_RESULT_SUCCESS) { return OK_ATOM; @@ -677,7 +677,7 @@ static EM_BOOL html5api_touch_callback(int eventType, const EmscriptenTouchEvent resource->event = event_constant; \ EMSCRIPTEN_RESULT result = emscripten_set_##callback##_callback_on_thread(target, resource, use_capture, html5api_##event_type##_callback, emscripten_main_runtime_thread_id()); \ if (result != EMSCRIPTEN_RESULT_SUCCESS && result != EMSCRIPTEN_RESULT_DEFERRED) { \ - return term_from_emscripten_result(result, ctx); \ + return term_from_emscripten_result(result, ctx, argv); \ } \ term resource_term = enif_make_resource(erl_nif_env_from_context(ctx), resource); \ if (UNLIKELY(memory_ensure_free_with_roots(ctx, TUPLE_SIZE(3), 1, &resource_term, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { \ @@ -713,7 +713,7 @@ static EM_BOOL html5api_touch_callback(int eventType, const EmscriptenTouchEvent } \ EMSCRIPTEN_RESULT result = emscripten_set_##callback##_callback_on_thread(target, NULL, false, NULL, emscripten_main_runtime_thread_id()); \ free(str); \ - return term_from_emscripten_result(result, ctx); \ + return term_from_emscripten_result(result, ctx, argv); \ } \ static const struct Nif emscripten_unregister_##callback##_callback_nif = { \ .base.type = NIFFunctionType, \ diff --git a/src/platforms/emscripten/src/main.c b/src/platforms/emscripten/src/main.c index 7d76562772..2f7133fddd 100644 --- a/src/platforms/emscripten/src/main.c +++ b/src/platforms/emscripten/src/main.c @@ -98,7 +98,7 @@ static int start(void) Context *ctx = context_new(global); ctx->leader = 1; context_execute_loop(ctx, main_module, "start", 0); - term ret_value = ctx->x[0]; + term ret_value = ctx->saved_x[0]; fprintf(stdout, "Return value: "); term_display(stdout, ret_value, ctx); fprintf(stdout, "\n"); diff --git a/src/platforms/esp32/main/main.c b/src/platforms/esp32/main/main.c index e940e1ab2c..af349c53b5 100644 --- a/src/platforms/esp32/main/main.c +++ b/src/platforms/esp32/main/main.c @@ -112,7 +112,7 @@ void app_main() fprintf(stdout, "---\n"); context_execute_loop(ctx, mod, "start", 0); - term ret_value = ctx->x[0]; + term ret_value = ctx->saved_x[0]; fprintf(stdout, "AtomVM finished with return value: "); term_display(stdout, ret_value, ctx); diff --git a/src/platforms/esp32/test/main/test_main.c b/src/platforms/esp32/test/main/test_main.c index 7bedbcded5..4cb5eddb4b 100644 --- a/src/platforms/esp32/test/main/test_main.c +++ b/src/platforms/esp32/test/main/test_main.c @@ -155,7 +155,7 @@ term avm_test_case(const char *test_module) ESP_LOGI(TAG, "Running start/0 from %s...\n", test_module); context_execute_loop(ctx, mod, "start", 0); - term ret_value = ctx->x[0]; + term ret_value = ctx->saved_x[0]; fprintf(stdout, "AtomVM finished with return value: "); term_display(stdout, ret_value, ctx); diff --git a/src/platforms/generic_unix/lib/platform_nifs.c b/src/platforms/generic_unix/lib/platform_nifs.c index 51732076d1..5478c9ffdb 100644 --- a/src/platforms/generic_unix/lib/platform_nifs.c +++ b/src/platforms/generic_unix/lib/platform_nifs.c @@ -48,8 +48,8 @@ } #define RAISE_ERROR(error_type_atom) \ - ctx->x[0] = ERROR_ATOM; \ - ctx->x[1] = (error_type_atom); \ + argv[0] = ERROR_ATOM; \ + argv[1] = (error_type_atom); \ return term_invalid_term(); #if defined ATOMVM_HAS_OPENSSL diff --git a/src/platforms/generic_unix/main.c b/src/platforms/generic_unix/main.c index abdcdd0f0c..37c6e01009 100644 --- a/src/platforms/generic_unix/main.c +++ b/src/platforms/generic_unix/main.c @@ -147,7 +147,7 @@ int main(int argc, char **argv) context_execute_loop(ctx, mod, "start", 0); - term ret_value = ctx->x[0]; + term ret_value = ctx->saved_x[0]; fprintf(stderr, "Return value: "); term_display(stderr, ret_value, ctx); fprintf(stderr, "\n"); diff --git a/src/platforms/rp2040/src/main.c b/src/platforms/rp2040/src/main.c index f907506dc9..51761c7cbf 100644 --- a/src/platforms/rp2040/src/main.c +++ b/src/platforms/rp2040/src/main.c @@ -138,7 +138,7 @@ static int app_main() fprintf(stdout, "---\n"); context_execute_loop(ctx, mod, "start", 0); - term ret_value = ctx->x[0]; + term ret_value = ctx->saved_x[0]; fprintf(stdout, "AtomVM finished with return value: "); term_display(stdout, ret_value, ctx); diff --git a/src/platforms/rp2040/tests/test_main.c b/src/platforms/rp2040/tests/test_main.c index c011dd0315..e6d217da0f 100644 --- a/src/platforms/rp2040/tests/test_main.c +++ b/src/platforms/rp2040/tests/test_main.c @@ -121,7 +121,7 @@ static term avm_test_case(const char *test_module) ctx->leader = 1; context_execute_loop(ctx, mod, "start", 0); - term ret_value = ctx->x[0]; + term ret_value = ctx->saved_x[0]; nif_collection_destroy_all(glb); diff --git a/src/platforms/stm32/src/main.c b/src/platforms/stm32/src/main.c index eb8917b228..b9f51e9a53 100644 --- a/src/platforms/stm32/src/main.c +++ b/src/platforms/stm32/src/main.c @@ -214,7 +214,7 @@ int main() context_execute_loop(ctx, mod, "start", 0); - term ret_value = ctx->x[0]; + term ret_value = ctx->saved_x[0]; char *ret_atom_string = interop_atom_to_string(ctx, ret_value); if (ret_atom_string != NULL) { AVM_LOGI(TAG, "Exited with return: %s", ret_atom_string); diff --git a/tests/erlang_tests/CMakeLists.txt b/tests/erlang_tests/CMakeLists.txt index d8c0a1c4db..55edd327b4 100644 --- a/tests/erlang_tests/CMakeLists.txt +++ b/tests/erlang_tests/CMakeLists.txt @@ -486,6 +486,8 @@ compile_erlang(test_module_info) compile_erlang(int64_build_binary) +compile_erlang(test_many_xregs) + add_custom_target(erlang_test_modules DEPENDS code_load_files @@ -935,4 +937,6 @@ add_custom_target(erlang_test_modules DEPENDS test_module_info.beam int64_build_binary.beam + + test_many_xregs.beam ) diff --git a/tests/erlang_tests/test_many_xregs.erl b/tests/erlang_tests/test_many_xregs.erl new file mode 100644 index 0000000000..c8e687f817 --- /dev/null +++ b/tests/erlang_tests/test_many_xregs.erl @@ -0,0 +1,50 @@ +% +% This file is part of AtomVM. +% +% Copyright 2023 Paul Guyot +% +% Licensed under the Apache License, Version 2.0 (the "License"); +% you may not use this file except in compliance with the License. +% You may obtain a copy of the License at +% +% http://www.apache.org/licenses/LICENSE-2.0 +% +% Unless required by applicable law or agreed to in writing, software +% distributed under the License is distributed on an "AS IS" BASIS, +% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +% See the License for the specific language governing permissions and +% limitations under the License. +% +% SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later +% + +-module(test_many_xregs). +-export([start/0]). + +start() -> + make_funs(), + 0. + +id(X) -> X. + +make_funs() -> + [ + fun id/1, + fun id/1, + fun id/1, + fun id/1, + fun id/1, + fun id/1, + fun id/1, + fun id/1, + fun id/1, + fun id/1, + fun id/1, + fun id/1, + fun id/1, + fun id/1, + fun id/1, + fun id/1, + + fun id/1 + ]. diff --git a/tests/test.c b/tests/test.c index ca333d13ef..1c2ca0279e 100644 --- a/tests/test.c +++ b/tests/test.c @@ -495,6 +495,8 @@ struct Test tests[] = { TEST_CASE(test_module_info), + TEST_CASE(test_many_xregs), + // noisy tests, keep them at the end TEST_CASE_EXPECTED(spawn_opt_monitor_normal, 1), TEST_CASE_EXPECTED(spawn_opt_link_normal, 1), @@ -538,11 +540,11 @@ static int test_atom(struct Test *test) context_execute_loop(ctx, mod, "start", 0); - if (!term_is_any_integer(ctx->x[0])) { + if (!term_is_any_integer(ctx->saved_x[0])) { fprintf(stderr, "\x1b[1;31mExpected %i but result is not an integer\x1b[0m\n", test->expected_value); result = -1; } else { - int32_t value = (int32_t) term_maybe_unbox_int(ctx->x[0]); + int32_t value = (int32_t) term_maybe_unbox_int(ctx->saved_x[0]); if (value != test->expected_value) { fprintf(stderr, "\x1b[1;31mExpected %i, got: %i\x1b[0m\n", test->expected_value, value); result = -1;