30
30
#include "debug.h"
31
31
#include "defaultatoms.h"
32
32
#include "exportedfunction.h"
33
+ #include "intn.h"
33
34
#include "nifs.h"
34
35
#include "opcodes.h"
35
36
#include "scheduler.h"
@@ -233,13 +234,11 @@ typedef dreg_t dreg_gc_safe_t;
233
234
break ; \
234
235
case COMPACT_NBITS_VALUE :{ \
235
236
int sz = (first_byte >> 5 ) + 2 ; \
236
- if (UNLIKELY (sz > 8 )) { \
237
- /* TODO: when first_byte >> 5 is 7, a different encoding is used */ \
238
- fprintf (stderr , "Unexpected nbits vaue @ %" PRIuPTR "\n" , (uintptr_t ) ((decode_pc ) - 1 )); \
239
- AVM_ABORT (); \
240
- break ; \
237
+ if (LIKELY (sz <= 8 )) { \
238
+ (decode_pc ) += sz ; \
239
+ } else { \
240
+ (decode_pc ) += decode_nbits_integer (NULL , (decode_pc ), NULL ); \
241
241
} \
242
- (decode_pc ) += sz ; \
243
242
break ; \
244
243
} \
245
244
default : \
@@ -712,11 +711,10 @@ static void destroy_extended_registers(Context *ctx, unsigned int live)
712
711
\
713
712
case COMPACT_NBITS_VALUE : { \
714
713
size_t num_bytes = (first_byte >> 5 ) + 2 ; \
715
- dest_term = large_integer_to_term (ctx , num_bytes , decode_pc ); \
714
+ dest_term = large_integer_to_term (ctx , num_bytes , & decode_pc ); \
716
715
if (UNLIKELY (term_is_invalid_term (dest_term ))) { \
717
716
HANDLE_ERROR (); \
718
717
} \
719
- (decode_pc ) += num_bytes ; \
720
718
break ; \
721
719
} \
722
720
default : \
@@ -1511,28 +1509,39 @@ static inline term maybe_alloc_boxed_integer_fragment_helper(Context *ctx, avm_i
1511
1509
}
1512
1510
}
1513
1511
1514
- static term large_integer_to_term (Context * ctx , int num_bytes , const uint8_t * compact_term )
1512
+ static size_t decode_nbits_integer (Context * ctx , const uint8_t * encoded , term * out_term );
1513
+
1514
+ static term large_integer_to_term (Context * ctx , int num_bytes , const uint8_t * * encoded )
1515
1515
{
1516
+ const uint8_t * compact_term = * encoded ;
1516
1517
switch (num_bytes ) {
1518
+ case 0 :
1519
+ case 1 :
1520
+ UNREACHABLE ();
1521
+
1517
1522
case 2 : {
1523
+ * encoded += 2 ;
1518
1524
int16_t ret_val16 = ((int16_t ) compact_term [0 ]) << 8 | compact_term [1 ];
1519
1525
return maybe_alloc_boxed_integer_fragment_helper (ctx , ret_val16 , 2 );
1520
1526
}
1521
1527
1522
1528
case 3 : {
1529
+ * encoded += 3 ;
1523
1530
struct Int24 ret_val24 ;
1524
1531
ret_val24 .val24 = ((int32_t ) compact_term [0 ]) << 16 | ((int32_t ) compact_term [1 ] << 8 ) | compact_term [2 ];
1525
1532
return maybe_alloc_boxed_integer_fragment_helper (ctx , ret_val24 .val24 , 3 );
1526
1533
}
1527
1534
1528
1535
case 4 : {
1536
+ * encoded += 4 ;
1529
1537
int32_t ret_val32 ;
1530
1538
ret_val32 = ((int32_t ) compact_term [0 ]) << 24 | ((int32_t ) compact_term [1 ] << 16 )
1531
1539
| ((int32_t ) compact_term [2 ] << 8 ) | compact_term [3 ];
1532
1540
return maybe_alloc_boxed_integer_fragment_helper (ctx , ret_val32 , 4 );
1533
1541
}
1534
1542
1535
1543
case 5 : {
1544
+ * encoded += 5 ;
1536
1545
struct Int40 ret_val40 ;
1537
1546
ret_val40 .val40 = ((int64_t ) compact_term [0 ]) << 32 | ((int64_t ) compact_term [1 ] << 24 )
1538
1547
| ((int64_t ) compact_term [2 ] << 16 ) | ((int64_t ) compact_term [3 ] << 8 )
@@ -1542,6 +1551,7 @@ static term large_integer_to_term(Context *ctx, int num_bytes, const uint8_t *co
1542
1551
}
1543
1552
1544
1553
case 6 : {
1554
+ * encoded += 6 ;
1545
1555
struct Int48 ret_val48 ;
1546
1556
ret_val48 .val48 = ((int64_t ) compact_term [0 ]) << 40 | ((int64_t ) compact_term [1 ] << 32 )
1547
1557
| ((int64_t ) compact_term [2 ] << 24 ) | ((int64_t ) compact_term [3 ] << 16 )
@@ -1551,6 +1561,7 @@ static term large_integer_to_term(Context *ctx, int num_bytes, const uint8_t *co
1551
1561
}
1552
1562
1553
1563
case 7 : {
1564
+ * encoded += 7 ;
1554
1565
struct Int56 ret_val56 ;
1555
1566
ret_val56 .val56 = ((int64_t ) compact_term [0 ]) << 48 | ((int64_t ) compact_term [1 ] << 40 )
1556
1567
| ((int64_t ) compact_term [2 ] << 32 ) | ((int64_t ) compact_term [3 ] << 24 )
@@ -1561,6 +1572,7 @@ static term large_integer_to_term(Context *ctx, int num_bytes, const uint8_t *co
1561
1572
}
1562
1573
1563
1574
case 8 : {
1575
+ * encoded += 8 ;
1564
1576
int64_t ret_val64 ;
1565
1577
ret_val64 = ((int64_t ) compact_term [0 ]) << 56 | ((int64_t ) compact_term [1 ] << 48 )
1566
1578
| ((int64_t ) compact_term [2 ] << 40 ) | ((int64_t ) compact_term [3 ] << 32 )
@@ -1570,10 +1582,15 @@ static term large_integer_to_term(Context *ctx, int num_bytes, const uint8_t *co
1570
1582
return maybe_alloc_boxed_integer_fragment_helper (ctx , ret_val64 , 8 );
1571
1583
}
1572
1584
1573
- default :
1574
- ctx -> x [0 ] = ERROR_ATOM ;
1575
- ctx -> x [1 ] = OVERFLOW_ATOM ;
1576
- return term_invalid_term ();
1585
+ case 9 : {
1586
+ term int_term ;
1587
+ * encoded += decode_nbits_integer (ctx , compact_term , & int_term );
1588
+ return int_term ;
1589
+ }
1590
+
1591
+ default : {
1592
+ UNREACHABLE ();
1593
+ }
1577
1594
}
1578
1595
}
1579
1596
@@ -1747,6 +1764,54 @@ static bool maybe_call_native(Context *ctx, AtomString module_name, AtomString f
1747
1764
1748
1765
#endif
1749
1766
1767
+ static size_t decode_nbits_integer (Context * ctx , const uint8_t * encoded , term * out_term )
1768
+ {
1769
+ const uint8_t * new_encoded = encoded ;
1770
+ unsigned int len ;
1771
+ DECODE_LITERAL (len , new_encoded );
1772
+
1773
+ len += 9 ;
1774
+
1775
+ if (out_term ) {
1776
+ intn_integer_sign_t sign ;
1777
+ intn_digit_t bigint [INTN_MAX_RES_LEN ];
1778
+ int count = intn_from_integer_bytes (new_encoded , len , IntnSigned , bigint , & sign );
1779
+ if (UNLIKELY (count < 0 )) {
1780
+ // this is likely unreachable, compiler seem to generate an external term
1781
+ // and to encode this as SMALL_BIG_EXT, so I don't think this code is executed
1782
+ ctx -> x [0 ] = ERROR_ATOM ;
1783
+ ctx -> x [1 ] = OVERFLOW_ATOM ;
1784
+ * out_term = term_invalid_term ();
1785
+ goto return_size ;
1786
+ }
1787
+
1788
+ size_t intn_data_size ;
1789
+ size_t rounded_res_len ;
1790
+ term_intn_to_term_size (count , & intn_data_size , & rounded_res_len );
1791
+
1792
+ Heap heap ;
1793
+ if (UNLIKELY (
1794
+ memory_init_heap (& heap , BOXED_INTN_SIZE (intn_data_size )) != MEMORY_GC_OK )) {
1795
+ ctx -> x [0 ] = ERROR_ATOM ;
1796
+ ctx -> x [1 ] = OUT_OF_MEMORY_ATOM ;
1797
+ * out_term = term_invalid_term ();
1798
+ goto return_size ;
1799
+ }
1800
+
1801
+ term bigint_term
1802
+ = term_create_uninitialized_intn (intn_data_size , (term_integer_sign_t ) sign , & heap );
1803
+ intn_digit_t * dest_buf = (void * ) term_intn_data (bigint_term );
1804
+ intn_copy (bigint , count , dest_buf , rounded_res_len );
1805
+
1806
+ memory_heap_append_heap (& ctx -> heap , & heap );
1807
+
1808
+ * out_term = bigint_term ;
1809
+ }
1810
+
1811
+ return_size :
1812
+ return (new_encoded - encoded ) + len ;
1813
+ }
1814
+
1750
1815
#ifndef __clang__
1751
1816
#pragma GCC diagnostic push
1752
1817
#ifdef __GNUC__
0 commit comments