diff --git a/rts/Makefile b/rts/Makefile index 90fa799be1a..a94b084c706 100644 --- a/rts/Makefile +++ b/rts/Makefile @@ -10,7 +10,7 @@ WASM_LD ?= wasm-ld-10 # TOMMATHFILES = \ - mp_init mp_add mp_sub mp_mul mp_zero mp_cmp \ + mp_init mp_zero mp_add mp_sub mp_mul mp_cmp \ mp_set_u32 mp_set_i32 mp_get_i32 mp_get_mag_u32 \ mp_set_u64 mp_set_i64 mp_get_i64 mp_get_mag_u64 \ mp_div mp_init_copy mp_neg mp_abs mp_2expt mp_expt_u32 mp_set mp_sqr \ @@ -166,7 +166,6 @@ $(TOMMATH_BINDINGS_RS): | _build -o $@ \ --use-core --ctypes-prefix=libc --no-layout-tests \ --whitelist-function mp_init \ - --whitelist-function mp_zero \ --whitelist-function mp_init_copy \ --whitelist-function mp_set_u32 \ --whitelist-function mp_set_i32 \ @@ -175,7 +174,6 @@ $(TOMMATH_BINDINGS_RS): | _build --whitelist-function mp_set_i64 \ --whitelist-function mp_get_i64 \ --whitelist-function mp_count_bits \ - --whitelist-function mp_get_mag_u64 \ --whitelist-function mp_cmp \ --whitelist-function mp_add \ --whitelist-function mp_sub \ @@ -191,7 +189,8 @@ $(TOMMATH_BINDINGS_RS): | _build --blacklist-type __int32_t \ --blacklist-type __int64_t \ --blacklist-type __uint32_t \ - --blacklist-type __uint64_t + --blacklist-type __uint64_t \ + -- $(TOMMATH_FLAGS) # Whitelist parameters used as libtommath.h has lots of definitions that we don't # need. Blacklist parameters are used because bindgen still generates unused type @@ -214,7 +213,7 @@ $(RTS_RUST_DEBUG_WASM_A): $(TOMMATH_BINDINGS_RS) | _build/wasm # .PHONY: test -test: $(TOMMATH_WASM_A) +test: $(TOMMATH_WASM_A) $(TOMMATH_BINDINGS_RS) cd motoko-rts-tests && cargo build --target=wasm32-wasi wasmtime --disable-cache --cranelift motoko-rts-tests/target/wasm32-wasi/debug/motoko-rts-tests.wasm diff --git a/rts/README.md b/rts/README.md index 3a3a23f3972..d6fbe601eaf 100644 --- a/rts/README.md +++ b/rts/README.md @@ -52,8 +52,8 @@ libtommath and memory management -------------------------------- We have to make libtommath’s memory management (which expects functions -`alloc`, `calloc` and `realloc`) work with the Motoko runtime. See in bigint.rs -for the technical details. +`alloc`, `calloc` and `realloc`) work with the Motoko runtime. +See `motoko-rts/src/bigint.rs` for the technical details. Rust build ---------- diff --git a/rts/motoko-rts/src/bigint.rs b/rts/motoko-rts/src/bigint.rs index f803c887dd7..9015b4b32a2 100644 --- a/rts/motoko-rts/src/bigint.rs +++ b/rts/motoko-rts/src/bigint.rs @@ -8,37 +8,55 @@ A libtommath arbitrary precision integer is a struct (`mp_int`) that contains a pointer to a data array. - - The libtommath library never allocates the struct, so we are in full control. We can embed the - struct in Motoko heap object with a dedicated tag for it. + - The libtommath library never allocates the struct, so we are in full control. - - The data array is allocated with mp_calloc and mp_realloc. We provide these calls, allocate - Motoko arrays (using the TAG_BLOB tag for byte arrays, not TAG_ARRAY for arrays of pointers) and - store the pointer to the _payload_ in the `mp_digit* dp` field of the struct. + We allocate that struct on the stack if we need it temporarily, or embed it in a TAG_BIGINT + object when we persist the number. - The GC has special knowledge about the dp field of the struct and understands that this pointer - points inside the TAG_BLOB heap object. We can still move them around in the GC without issues. + - The data array is allocated with mp_calloc() and mp_realloc(), and these functions are _only_ used + to allocate the data array. - The length of the byte array is always equal to the allocation asked for by libtommath (no - shrinking via mp_realloc supported). This means we can assert that it matches the old_size - passed to mp_realloc as an additional check. We can also support shrinking via mp_realloc, but - then we have to drop that check. + We provide these calls, allocate TAG_BIGINT objects (leaving space for the mp_int), and pass a + pointer _into_ this object back to libtommath, which stores it in the `mp_digit* dp` + field of the struct. + +When persisting a `mp_int` (presumably stack-allocated), we know that the `mp_digit` pointer +points to a `TAG_BIGINT` with sufficient space for the `mp_int` data. We copy the `mp_int` +there, and use the overall `TAG_BIGINT` as the bignum object. + +This scheme makes the following assumptions: + + - libtommath never modifies the data on the heap. + (or put differently, we only pass those to libtommath when they are immutable) + - libtommath uses mp_calloc() and mp_realloc() _only_ to allocate the `mp_digit *` array. */ -use crate::alloc::{alloc_blob, alloc_words}; +use crate::alloc::alloc_words; use crate::buf::{read_byte, Buf}; use crate::mem::memcpy_bytes; -use crate::types::{size_of, BigInt, Blob, Bytes, SkewedPtr, TAG_BIGINT, TAG_BLOB}; +use crate::types::{size_of, skew, BigInt, Bytes, SkewedPtr, TAG_BIGINT}; use crate::{rts_trap, tommath_bindings::*}; -unsafe fn mp_alloc(n: Bytes) -> *mut u8 { - let blob = alloc_blob(n); - blob.as_blob().payload_addr() +unsafe fn mp_alloc(size: Bytes) -> *mut u8 { + let ptr = alloc_words(size_of::() + size.to_words()); + let blob = ptr.unskew() as *mut BigInt; + (*blob).header.tag = TAG_BIGINT; + // libtommath stores the size of the object in alloc + // as count of mp_digits (u64) + debug_assert_eq!((size.0 as usize % core::mem::size_of::()), 0); + (*blob).mp_int.alloc = (size.0 as usize / core::mem::size_of::()) as i32; + blob.payload_addr() as *mut u8 } #[no_mangle] unsafe extern "C" fn mp_calloc(n_elems: usize, elem_size: Bytes) -> *mut libc::c_void { - let size = Bytes((n_elems * elem_size.0) as u32); // Overflow check? + debug_assert_eq!(elem_size.0, core::mem::size_of::()); + // Overflow check for the following multiplication + if n_elems > 1 << 30 { + bigint_trap(); + } + let size = Bytes((n_elems * elem_size.0) as u32); let payload = mp_alloc(size) as *mut u32; // NB. alloc_bytes rounds up to words so we do the same here to set the whole buffer @@ -55,16 +73,16 @@ unsafe extern "C" fn mp_realloc( old_size: Bytes, new_size: Bytes, ) -> *mut libc::c_void { - let blob = (ptr as *mut u32).sub(size_of::().0 as usize) as *mut Blob; + let bigint = BigInt::from_payload(ptr as *mut mp_digit); - assert_eq!((*blob).header.tag, TAG_BLOB); - assert_eq!(blob.len(), old_size); + debug_assert_eq!((*bigint).header.tag, TAG_BIGINT); + debug_assert_eq!(bigint.len(), old_size); - if new_size > blob.len() { + if new_size > bigint.len() { let new_ptr = mp_alloc(new_size); memcpy_bytes(new_ptr as usize, ptr as usize, old_size); new_ptr as *mut _ - } else if new_size == blob.len() { + } else if new_size == bigint.len() { ptr } else { // libtommath only shrinks via mp_shrink and we do not use that function, so this should not @@ -122,26 +140,38 @@ unsafe fn mp_iszero(p: *const mp_int) -> bool { (*p).used == 0 } -unsafe fn bigint_alloc() -> SkewedPtr { - let r = alloc_words(size_of::()); - let r_ptr = r.unskew() as *mut BigInt; - (*r_ptr).header.tag = TAG_BIGINT; - check(mp_init(&mut (*r_ptr).mp_int)); - r +// Allocates a mp_int on the stack +unsafe fn tmp_bigint() -> mp_int { + let mut i: mp_int = core::mem::zeroed(); + check(mp_init(&mut i)); + i +} + +// Persists an mp_int from the stack on the heap +unsafe fn persist_bigint(i: mp_int) -> SkewedPtr { + if i.dp == core::ptr::null_mut() { + panic!("persist_bigint: dp == NULL?"); + } + let r = BigInt::from_payload(i.dp); + if (*r).mp_int.alloc != i.alloc { + panic!("persist_bigint: alloc changed?"); + } + (*r).mp_int = i; + skew(r as usize) } #[no_mangle] pub unsafe extern "C" fn bigint_of_word32(w: u32) -> SkewedPtr { - let r = bigint_alloc(); - mp_set_u32(r.as_bigint().mp_int_ptr(), w); - r + let mut i = tmp_bigint(); + mp_set_u32(&mut i, w); + persist_bigint(i) } #[no_mangle] -unsafe extern "C" fn bigint_of_int32(i: i32) -> SkewedPtr { - let r = bigint_alloc(); - mp_set_i32(r.as_bigint().mp_int_ptr(), i); - r +unsafe extern "C" fn bigint_of_int32(j: i32) -> SkewedPtr { + let mut i = tmp_bigint(); + mp_set_i32(&mut i, j); + persist_bigint(i) } #[no_mangle] @@ -188,43 +218,18 @@ unsafe extern "C" fn bigint_to_word64_trap(p: SkewedPtr) -> u64 { mp_get_u64(mp_int) } -// TODO (osa): Same as bigint_to_word32_signed_trap -#[no_mangle] -unsafe extern "C" fn bigint_to_word64_signed_trap(p: SkewedPtr) -> i64 { - let mp_int = p.as_bigint().mp_int_ptr(); - - if mp_count_bits(mp_int) > 64 { - bigint_trap(); - } - - let x = mp_get_mag_u64(mp_int) as i64; - if mp_isneg(mp_int) { - let x = -x; - if x >= 0 { - // TODO (osa): Why not ==? - bigint_trap(); - } - x - } else { - if x < 0 { - bigint_trap(); - } - x - } -} - #[no_mangle] unsafe extern "C" fn bigint_of_word64(w: u64) -> SkewedPtr { - let p = bigint_alloc(); - mp_set_u64(p.as_bigint().mp_int_ptr(), w); - p + let mut i = tmp_bigint(); + mp_set_u64(&mut i, w); + persist_bigint(i) } #[no_mangle] -unsafe extern "C" fn bigint_of_int64(i: i64) -> SkewedPtr { - let p = bigint_alloc(); - mp_set_i64(p.as_bigint().mp_int_ptr(), i); - p +unsafe extern "C" fn bigint_of_int64(j: i64) -> SkewedPtr { + let mut i = tmp_bigint(); + mp_set_i64(&mut i, j); + persist_bigint(i) } #[no_mangle] @@ -254,91 +259,81 @@ unsafe extern "C" fn bigint_ge(a: SkewedPtr, b: SkewedPtr) -> bool { #[no_mangle] pub unsafe extern "C" fn bigint_add(a: SkewedPtr, b: SkewedPtr) -> SkewedPtr { - let r = bigint_alloc(); + let mut i = tmp_bigint(); check(mp_add( a.as_bigint().mp_int_ptr(), b.as_bigint().mp_int_ptr(), - r.as_bigint().mp_int_ptr(), + &mut i, )); - r + persist_bigint(i) } #[no_mangle] pub unsafe extern "C" fn bigint_sub(a: SkewedPtr, b: SkewedPtr) -> SkewedPtr { - let r = bigint_alloc(); + let mut i = tmp_bigint(); check(mp_sub( a.as_bigint().mp_int_ptr(), b.as_bigint().mp_int_ptr(), - r.as_bigint().mp_int_ptr(), + &mut i, )); - r + persist_bigint(i) } #[no_mangle] pub unsafe extern "C" fn bigint_mul(a: SkewedPtr, b: SkewedPtr) -> SkewedPtr { - let r = bigint_alloc(); + let mut i = tmp_bigint(); check(mp_mul( a.as_bigint().mp_int_ptr(), b.as_bigint().mp_int_ptr(), - r.as_bigint().mp_int_ptr(), + &mut i, )); - r + persist_bigint(i) } #[no_mangle] pub unsafe extern "C" fn bigint_pow(a: SkewedPtr, b: SkewedPtr) -> SkewedPtr { let exp = bigint_to_word32_trap(b); - let r = bigint_alloc(); - check(mp_expt_u32( - a.as_bigint().mp_int_ptr(), - exp, - r.as_bigint().mp_int_ptr(), - )); - r + let mut i = tmp_bigint(); + check(mp_expt_u32(a.as_bigint().mp_int_ptr(), exp, &mut i)); + persist_bigint(i) } #[no_mangle] unsafe extern "C" fn bigint_div(a: SkewedPtr, b: SkewedPtr) -> SkewedPtr { - let r = bigint_alloc(); + let mut i = tmp_bigint(); check(mp_div( a.as_bigint().mp_int_ptr(), b.as_bigint().mp_int_ptr(), - r.as_bigint().mp_int_ptr(), + &mut i, core::ptr::null_mut(), )); - r + persist_bigint(i) } #[no_mangle] unsafe extern "C" fn bigint_rem(a: SkewedPtr, b: SkewedPtr) -> SkewedPtr { - let r = bigint_alloc(); + let mut i = tmp_bigint(); check(mp_div( a.as_bigint().mp_int_ptr(), b.as_bigint().mp_int_ptr(), core::ptr::null_mut(), - r.as_bigint().mp_int_ptr(), + &mut i, )); - r + persist_bigint(i) } #[no_mangle] pub unsafe extern "C" fn bigint_neg(a: SkewedPtr) -> SkewedPtr { - let r = bigint_alloc(); - check(mp_neg( - a.as_bigint().mp_int_ptr(), - r.as_bigint().mp_int_ptr(), - )); - r + let mut i = tmp_bigint(); + check(mp_neg(a.as_bigint().mp_int_ptr(), &mut i)); + persist_bigint(i) } #[no_mangle] unsafe extern "C" fn bigint_abs(a: SkewedPtr) -> SkewedPtr { - let r = bigint_alloc(); - check(mp_abs( - a.as_bigint().mp_int_ptr(), - r.as_bigint().mp_int_ptr(), - )); - r + let mut i = tmp_bigint(); + check(mp_abs(a.as_bigint().mp_int_ptr(), &mut i)); + persist_bigint(i) } #[no_mangle] @@ -348,13 +343,9 @@ unsafe extern "C" fn bigint_isneg(a: SkewedPtr) -> bool { #[no_mangle] unsafe extern "C" fn bigint_lsh(a: SkewedPtr, b: i32) -> SkewedPtr { - let r = bigint_alloc(); - check(mp_mul_2d( - a.as_bigint().mp_int_ptr(), - b, - r.as_bigint().mp_int_ptr(), - )); - r + let mut i = tmp_bigint(); + check(mp_mul_2d(a.as_bigint().mp_int_ptr(), b, &mut i)); + persist_bigint(i) } #[no_mangle] @@ -435,20 +426,15 @@ pub unsafe extern "C" fn bigint_sleb128_encode(n: SkewedPtr, buf: *mut u8) { #[no_mangle] pub unsafe extern "C" fn bigint_leb128_decode(buf: *mut Buf) -> SkewedPtr { - let r = bigint_alloc(); - - let r_mp_int = r.as_bigint().mp_int_ptr(); - mp_zero(r_mp_int); - - let mut tmp: mp_int = core::mem::zeroed(); - check(mp_init(&mut tmp)); + let mut i = tmp_bigint(); + let mut tmp = tmp_bigint(); let mut shift = 0; loop { let byte = read_byte(buf); mp_set_u32(&mut tmp, (byte & 0b0111_1111) as u32); check(mp_mul_2d(&mut tmp, shift, &mut tmp)); - check(mp_add(r_mp_int, &tmp, r_mp_int)); + check(mp_add(&mut i, &tmp, &mut i)); shift += 7; if byte & 0b1000_0000 == 0 { @@ -456,18 +442,13 @@ pub unsafe extern "C" fn bigint_leb128_decode(buf: *mut Buf) -> SkewedPtr { } } - r + persist_bigint(i) } #[no_mangle] pub unsafe extern "C" fn bigint_sleb128_decode(buf: *mut Buf) -> SkewedPtr { - let r = bigint_alloc(); - - let r_mp_int = r.as_bigint().mp_int_ptr(); - mp_zero(r_mp_int); - - let mut tmp: mp_int = core::mem::zeroed(); - check(mp_init(&mut tmp)); + let mut i = tmp_bigint(); + let mut tmp = tmp_bigint(); let mut shift = 0; let mut last_sign_bit_set; @@ -475,7 +456,7 @@ pub unsafe extern "C" fn bigint_sleb128_decode(buf: *mut Buf) -> SkewedPtr { let byte = read_byte(buf); mp_set_u32(&mut tmp, (byte & 0b0111_1111) as u32); check(mp_mul_2d(&mut tmp, shift, &mut tmp)); - check(mp_add(r_mp_int, &tmp, r_mp_int)); + check(mp_add(&mut i, &tmp, &mut i)); last_sign_bit_set = byte & 0b0100_0000 != 0; shift += 7; @@ -486,11 +467,10 @@ pub unsafe extern "C" fn bigint_sleb128_decode(buf: *mut Buf) -> SkewedPtr { if last_sign_bit_set { // Negative number, un-2-complement it - let mut big: mp_int = core::mem::zeroed(); - check(mp_init(&mut big)); + let mut big = tmp_bigint(); check(mp_2expt(&mut big, shift)); - check(mp_sub(r_mp_int, &big, r_mp_int)); + check(mp_sub(&mut i, &big, &mut i)); } - r + persist_bigint(i) } diff --git a/rts/motoko-rts/src/gc.rs b/rts/motoko-rts/src/gc.rs index 5f7caa9add8..6e255f67ca4 100644 --- a/rts/motoko-rts/src/gc.rs +++ b/rts/motoko-rts/src/gc.rs @@ -130,40 +130,6 @@ unsafe fn evac( *end_to_space += obj_size_bytes.0 as usize } -/// Evacuate a blob payload pointed by a bigint. bigints are special in that a bigint's first field -/// is an internal pointer: it points to the _payload_ of a blob object, instead of skewedly pointing to the object start -/// -/// - `ptr_loc`: Address of a `data_ptr` field of a BigInt (see types.rs). Points to payload of a -/// blob. See types.rs for blob layout. -unsafe fn evac_bigint_blob( - begin_from_space: usize, - begin_to_space: usize, - end_to_space: &mut usize, - ptr_loc: *mut usize, // address of field with a pointer to a blob payload -) { - let blob_payload_addr = *ptr_loc; - - // Get blob object from the payload - let mut blob_obj_addr = skew(blob_payload_addr - size_of::().to_bytes().0 as usize); - // Create a temporary field to the blob object, to be passed to `evac`. - let blob_obj_addr_field = &mut blob_obj_addr; - let blob_obj_addr_field_ptr = blob_obj_addr_field as *mut _; - - evac( - begin_from_space, - begin_to_space, - end_to_space, - blob_obj_addr_field_ptr as usize, - ); - - // blob_obj_addr_field now has the new location of the blob, get the payload address - let blob_new_addr = (*blob_obj_addr_field).unskew(); - let blob_new_payload_addr = blob_new_addr + size_of::().to_bytes().0 as usize; - - // Update evacuated field - *ptr_loc = blob_new_payload_addr; // not skewed! -} - unsafe fn scav( begin_from_space: usize, begin_to_space: usize, @@ -230,18 +196,6 @@ unsafe fn scav( evac(begin_from_space, begin_to_space, end_to_space, field_addr); } - TAG_BIGINT => { - let bigint = obj as *mut BigInt; - let data_ptr_addr = bigint.data_ptr() as *mut _; - - evac_bigint_blob( - begin_from_space, - begin_to_space, - end_to_space, - data_ptr_addr, - ); - } - TAG_CONCAT => { let concat = obj as *mut Concat; let field1_addr = ((&mut (*concat).text1) as *mut _) as usize; @@ -256,7 +210,7 @@ unsafe fn scav( evac(begin_from_space, begin_to_space, end_to_space, field_addr); } - TAG_BITS64 | TAG_BITS32 | TAG_BLOB => { + TAG_BITS64 | TAG_BITS32 | TAG_BLOB | TAG_BIGINT => { // These don't include pointers, skip } diff --git a/rts/motoko-rts/src/types.rs b/rts/motoko-rts/src/types.rs index b8ed9f5ee52..fdd317c9e80 100644 --- a/rts/motoko-rts/src/types.rs +++ b/rts/motoko-rts/src/types.rs @@ -1,3 +1,4 @@ +use crate::tommath_bindings::{mp_digit, mp_int}; use core::ops::{Add, AddAssign, Sub, SubAssign}; use crate::rts_trap_with; @@ -282,23 +283,39 @@ pub struct FwdPtr { #[repr(packed)] pub struct BigInt { pub header: Obj, - /// The data following now must describe is the `mp_int` struct. The data pointer (mp_int.dp) - /// is an unskewed pointer to a blob payload. `mp_int.dp - blob header size` gives us the blob - /// header. - pub mp_int: crate::tommath_bindings::mp_int, + /// The data following now must describe is the `mp_int` struct. + /// The data pointer (mp_int.dp) is irrelevant, and will be changed to point to + /// the data within this object before it is used. + /// (NB: If we have a non-moving GC, we can make this an invaiant) + pub mp_int: mp_int, + // data follows .. } impl BigInt { - /// Returns location of the pointer to the blob payload that holds the `mp_int` data. The GC - /// finds the blob header from this pointer, copies it, and updates this location to point to - /// the new blob payload. - pub unsafe fn data_ptr(self: *mut BigInt) -> *mut *mut u8 { - &mut (*self).mp_int.dp as *mut _ as *mut _ + pub unsafe fn len(self: *mut Self) -> Bytes { + Bytes(((*self).mp_int.alloc as usize * core::mem::size_of::()) as u32) + } + + pub unsafe fn payload_addr(self: *mut Self) -> *mut mp_digit { + self.add(1) as *mut mp_digit // skip closure header + } + + pub unsafe fn from_payload(ptr: *mut mp_digit) -> *mut Self { + (ptr as *mut u32).sub(size_of::().0 as usize) as *mut BigInt } /// Returns pointer to the `mp_int` struct - pub unsafe fn mp_int_ptr(self: *mut BigInt) -> *mut crate::tommath_bindings::mp_int { - &mut (*self).mp_int + /// + /// It fixes up the dp pointer. Instead of doing it here + /// this could be done on allocation and every object move. + /// + /// Note that this returns a `const` pointer. This is very nice, as together with the const + /// annotation on the libtommath API, this should prevent us from passing this pointer to a + /// libtommath function that tries to change it. For example, we cannot confuse input and + /// output parameters of mp_add() this way. + pub unsafe fn mp_int_ptr(self: *mut BigInt) -> *const mp_int { + (*self).mp_int.dp = self.payload_addr(); + &(*self).mp_int } } @@ -399,7 +416,10 @@ pub(crate) unsafe fn object_size(obj: usize) -> Words { TAG_BITS32 => size_of::(), - TAG_BIGINT => size_of::(), + TAG_BIGINT => { + let bigint = obj as *mut BigInt; + size_of::() + bigint.len().to_words() + } TAG_CONCAT => size_of::(), diff --git a/src/codegen/compile.ml b/src/codegen/compile.ml index 0a5099105ae..362ce37844e 100644 --- a/src/codegen/compile.ml +++ b/src/codegen/compile.ml @@ -736,7 +736,6 @@ module RTS = struct E.add_func_import env "rts" "bigint_of_int64" [I64Type] [I32Type]; E.add_func_import env "rts" "bigint_to_word64_wrap" [I32Type] [I64Type]; E.add_func_import env "rts" "bigint_to_word64_trap" [I32Type] [I64Type]; - E.add_func_import env "rts" "bigint_to_word64_signed_trap" [I32Type] [I64Type]; E.add_func_import env "rts" "bigint_eq" [I32Type; I32Type] [I32Type]; E.add_func_import env "rts" "bigint_isneg" [I32Type] [I32Type]; E.add_func_import env "rts" "bigint_count_bits" [I32Type] [I32Type]; @@ -2384,10 +2383,6 @@ module BigNumLibtommath : BigNumType = struct let n = Big_int.abs_big_int n in - (* copied from Blob *) - let header_size = Int32.add Tagged.header_size 1l in - let unskewed_payload_offset = Int32.(add ptr_unskew (mul Heap.word_size header_size)) in - let limbs = (* see MP_DIGIT_BIT *) let twoto28 = Big_int.power_int_positive_int 2 28 in @@ -2402,20 +2397,15 @@ module BigNumLibtommath : BigNumType = struct (* how many 32 bit digits *) let size = Int32.of_int (List.length limbs) in - let data_blob = E.add_static env StaticBytes.[ - I32 Tagged.(int_of_tag Blob); - I32 Int32.(mul Heap.word_size size); - i32s limbs - ] in - let data_ptr = Int32.(add data_blob unskewed_payload_offset) in - (* cf. mp_int in tommath.h *) let ptr = E.add_static env StaticBytes.[ I32 Tagged.(int_of_tag BigInt); - I32 size; - I32 size; (* alloc *) + I32 size; (* used *) + I32 size; (* size; relying on Heap.word_size == size_of(mp_digit) *) I32 sign; - I32 data_ptr; + I32 0l; (* dp; this will be patched in BigInt::mp_int_ptr in the RTS when used *) + i32s limbs + ] in ptr