@@ -1814,6 +1814,41 @@ static bool maybe_call_native(Context *ctx, atom_index_t module_name, atom_index
18141814#endif
18151815
18161816#ifndef AVM_NO_EMU
1817+ static term extract_nbits_integer (Context * ctx , const uint8_t * bytes , size_t bytes_size , intn_from_integer_options_t opts )
1818+ {
1819+ intn_integer_sign_t sign ;
1820+ intn_digit_t bigint [INTN_MAX_RES_LEN ];
1821+ int count = intn_from_integer_bytes (bytes , bytes_size , opts , bigint , & sign );
1822+ if (UNLIKELY (count < 0 )) {
1823+ // this is likely unreachable, compiler seem to generate an external term
1824+ // and to encode this as SMALL_BIG_EXT, so I don't think this code is executed
1825+ ctx -> x [0 ] = ERROR_ATOM ;
1826+ ctx -> x [1 ] = OVERFLOW_ATOM ;
1827+ return term_invalid_term ();
1828+ }
1829+
1830+ size_t intn_data_size ;
1831+ size_t rounded_res_len ;
1832+ term_intn_to_term_size (count , & intn_data_size , & rounded_res_len );
1833+
1834+ Heap heap ;
1835+ if (UNLIKELY (
1836+ memory_init_heap (& heap , BOXED_INTN_SIZE (intn_data_size )) != MEMORY_GC_OK )) {
1837+ ctx -> x [0 ] = ERROR_ATOM ;
1838+ ctx -> x [1 ] = OUT_OF_MEMORY_ATOM ;
1839+ return term_invalid_term ();
1840+ }
1841+
1842+ term bigint_term
1843+ = term_create_uninitialized_intn (intn_data_size , (term_integer_sign_t ) sign , & heap );
1844+ intn_digit_t * dest_buf = (void * ) term_intn_data (bigint_term );
1845+ intn_copy (bigint , count , dest_buf , rounded_res_len );
1846+
1847+ memory_heap_append_heap (& ctx -> heap , & heap );
1848+
1849+ return bigint_term ;
1850+ }
1851+
18171852 static size_t decode_nbits_integer (Context * ctx , const uint8_t * encoded , term * out_term )
18181853 {
18191854 const uint8_t * new_encoded = encoded ;
@@ -1826,41 +1861,9 @@ static bool maybe_call_native(Context *ctx, atom_index_t module_name, atom_index
18261861 len += 9 ;
18271862
18281863 if (out_term ) {
1829- intn_integer_sign_t sign ;
1830- intn_digit_t bigint [INTN_MAX_RES_LEN ];
1831- int count = intn_from_integer_bytes (new_encoded , len , IntnSigned , bigint , & sign );
1832- if (UNLIKELY (count < 0 )) {
1833- // this is likely unreachable, compiler seem to generate an external term
1834- // and to encode this as SMALL_BIG_EXT, so I don't think this code is executed
1835- ctx -> x [0 ] = ERROR_ATOM ;
1836- ctx -> x [1 ] = OVERFLOW_ATOM ;
1837- * out_term = term_invalid_term ();
1838- goto return_size ;
1839- }
1840-
1841- size_t intn_data_size ;
1842- size_t rounded_res_len ;
1843- term_bigint_size_requirements (count , & intn_data_size , & rounded_res_len );
1844-
1845- Heap heap ;
1846- if (UNLIKELY (
1847- memory_init_heap (& heap , BOXED_BIGINT_HEAP_SIZE (intn_data_size )) != MEMORY_GC_OK )) {
1848- ctx -> x [0 ] = ERROR_ATOM ;
1849- ctx -> x [1 ] = OUT_OF_MEMORY_ATOM ;
1850- * out_term = term_invalid_term ();
1851- goto return_size ;
1852- }
1853-
1854- term bigint_term
1855- = term_create_uninitialized_bigint (intn_data_size , (term_integer_sign_t ) sign , & heap );
1856- term_initialize_bigint (bigint_term , bigint , count , rounded_res_len );
1857-
1858- memory_heap_append_heap (& ctx -> heap , & heap );
1859-
1860- * out_term = bigint_term ;
1864+ * out_term = extract_nbits_integer (ctx , new_encoded , len , IntnSigned );
18611865 }
18621866
1863- return_size :
18641867 return (new_encoded - encoded ) + len ;
18651868 }
18661869#endif
@@ -5298,25 +5301,44 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
52985301 union maybe_unsigned_int64 value ;
52995302 term bs_bin = term_get_match_state_binary (src );
53005303 avm_int_t bs_offset = term_get_match_state_offset (src );
5301- bool status = bitstring_extract_integer (bs_bin , bs_offset , increment , flags_value , & value );
5302- if (UNLIKELY (!status )) {
5303- TRACE ("bs_get_integer2: error extracting integer.\n" );
5304- JUMP_TO_ADDRESS (mod -> labels [fail ]);
5305- } else {
5306- term_set_match_state_offset (src , bs_offset + increment );
5304+ term t ;
5305+ if (increment <= 64 ) {
5306+ bool status = bitstring_extract_integer (bs_bin , bs_offset , increment , flags_value , & value );
5307+ if (UNLIKELY (!status )) {
5308+ TRACE ("bs_get_integer2: error extracting integer.\n" );
5309+ JUMP_TO_ADDRESS (mod -> labels [fail ]);
5310+ } else {
5311+ term_set_match_state_offset (src , bs_offset + increment );
53075312
5308- term t = maybe_alloc_boxed_integer_fragment (ctx , value .s );
5309- if (UNLIKELY (term_is_invalid_term (t ))) {
5313+ t = maybe_alloc_boxed_integer_fragment (ctx , value .s );
5314+ if (UNLIKELY (term_is_invalid_term (t ))) {
5315+ HANDLE_ERROR ();
5316+ }
5317+ }
5318+ } else if ((bs_offset % 8 == 0 ) && (increment % 8 == 0 ) && (increment <= INTN_MAX_UNSIGNED_BITS_SIZE )) {
5319+ unsigned long capacity = term_binary_size (bs_bin );
5320+ if (8 * capacity - bs_offset < (unsigned long ) increment ) {
5321+ JUMP_TO_ADDRESS (mod -> labels [fail ]);
5322+ }
5323+ size_t byte_offset = bs_offset / 8 ;
5324+ const uint8_t * int_bytes = (const uint8_t * ) term_binary_data (bs_bin );
5325+
5326+ t = extract_nbits_integer (ctx , int_bytes + byte_offset , increment / 8 ,
5327+ bitstring_flags_to_intn_opts (flags_value ));
5328+ term_set_match_state_offset (src , bs_offset + increment );
5329+ if (term_is_invalid_term (t )) {
53105330 HANDLE_ERROR ();
53115331 }
5332+ } else {
5333+ JUMP_TO_ADDRESS (mod -> labels [fail ]);
5334+ }
53125335 #endif
53135336
53145337 DEST_REGISTER (dreg );
53155338 DECODE_DEST_REGISTER (dreg , pc );
53165339
53175340 #ifdef IMPL_EXECUTE_LOOP
5318- WRITE_REGISTER (dreg , t );
5319- }
5341+ WRITE_REGISTER (dreg , t );
53205342 #endif
53215343 break ;
53225344 }
@@ -7273,15 +7295,35 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
72737295 avm_int_t size_val = term_to_int (size );
72747296 avm_int_t increment = size_val * unit ;
72757297 union maybe_unsigned_int64 value ;
7276- bool status = bitstring_extract_integer (bs_bin , bs_offset , increment , flags_value , & value );
7277- if (UNLIKELY (!status )) {
7278- TRACE ("bs_match/3: error extracting integer.\n" );
7298+ term t ;
7299+ if (increment <= 64 ) {
7300+ bool status = bitstring_extract_integer (bs_bin , bs_offset , increment , flags_value , & value );
7301+ if (UNLIKELY (!status )) {
7302+ TRACE ("bs_match/3: error extracting integer.\n" );
7303+ goto bs_match_jump_to_fail ;
7304+ }
7305+ //FIXME: handling of 64-bit unsigned integers is not reliable
7306+ t = maybe_alloc_boxed_integer_fragment (ctx , value .s );
7307+ if (UNLIKELY (term_is_invalid_term (t ))) {
7308+ RAISE_ERROR (OUT_OF_MEMORY_ATOM );
7309+ }
7310+ } else if ((bs_offset % 8 == 0 ) && (increment % 8 == 0 ) && (increment <= INTN_MAX_UNSIGNED_BITS_SIZE )) {
7311+ unsigned long capacity = term_binary_size (bs_bin );
7312+ if (8 * capacity - bs_offset < (unsigned long ) increment ) {
7313+ goto bs_match_jump_to_fail ;
7314+ }
7315+ size_t byte_offset = bs_offset / 8 ;
7316+ const uint8_t * int_bytes
7317+ = (const uint8_t * ) term_binary_data (bs_bin );
7318+
7319+ t = extract_nbits_integer (ctx , int_bytes + byte_offset ,
7320+ increment / 8 , bitstring_flags_to_intn_opts (flags_value ));
7321+ if (term_is_invalid_term (t )) {
7322+ HANDLE_ERROR ();
7323+ }
7324+ } else {
72797325 goto bs_match_jump_to_fail ;
72807326 }
7281- term t = maybe_alloc_boxed_integer_fragment (ctx , value .s );
7282- if (UNLIKELY (term_is_invalid_term (t ))) {
7283- RAISE_ERROR (OUT_OF_MEMORY_ATOM );
7284- }
72857327 #endif
72867328 DEST_REGISTER (dreg );
72877329 DECODE_DEST_REGISTER (dreg , pc );
@@ -7388,6 +7430,10 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
73887430 DECODE_LITERAL (pattern_value , pc );
73897431 j ++ ;
73907432 #ifdef IMPL_EXECUTE_LOOP
7433+ if (size > 64 ) {
7434+ // TODO: implement support for big integers also here
7435+ RAISE_ERROR (BADARG_ATOM );
7436+ }
73917437 union maybe_unsigned_int64 matched_value ;
73927438 bool status = bitstring_extract_integer (bs_bin , bs_offset , size , 0 , & matched_value );
73937439 if (UNLIKELY (!status )) {
0 commit comments