mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 11:52:19 +00:00
Merge pull request #3699 from rtfeldman/wasm-fix-uninit-capacity
Wasm: fix uninitialised capacity in List literals
This commit is contained in:
commit
9f2ddc61d8
3 changed files with 44 additions and 12 deletions
|
@ -1479,7 +1479,14 @@ impl<'a> WasmBackend<'a> {
|
|||
// length of the list
|
||||
self.code_builder.get_local(stack_local_id);
|
||||
self.code_builder.i32_const(elems.len() as i32);
|
||||
self.code_builder.i32_store(Align::Bytes4, stack_offset + 4);
|
||||
self.code_builder
|
||||
.i32_store(Align::Bytes4, stack_offset + 4 * Builtin::WRAPPER_LEN);
|
||||
|
||||
// capacity of the list
|
||||
self.code_builder.get_local(stack_local_id);
|
||||
self.code_builder.i32_const(elems.len() as i32);
|
||||
self.code_builder
|
||||
.i32_store(Align::Bytes4, stack_offset + 4 * Builtin::WRAPPER_CAPACITY);
|
||||
|
||||
let mut elem_offset = 0;
|
||||
|
||||
|
@ -1521,12 +1528,14 @@ impl<'a> WasmBackend<'a> {
|
|||
if let StoredValue::StackMemory { location, .. } = storage {
|
||||
let (local_id, offset) = location.local_and_offset(self.storage.stack_frame_pointer);
|
||||
|
||||
// This is a minor cheat.
|
||||
// What we want to write to stack memory is { elements: null, length: 0 }
|
||||
// But instead of two 32-bit stores, we can do a single 64-bit store.
|
||||
// Store 12 bytes of zeros { elements: null, length: 0, capacity: 0 }
|
||||
debug_assert_eq!(Builtin::LIST_WORDS, 3);
|
||||
self.code_builder.get_local(local_id);
|
||||
self.code_builder.i64_const(0);
|
||||
self.code_builder.i64_store(Align::Bytes4, offset);
|
||||
self.code_builder.get_local(local_id);
|
||||
self.code_builder.i32_const(0);
|
||||
self.code_builder.i32_store(Align::Bytes4, offset + 8);
|
||||
} else {
|
||||
internal_error!("Unexpected storage for {:?}", sym)
|
||||
}
|
||||
|
|
|
@ -3354,3 +3354,18 @@ fn issue_3571_lowlevel_call_function_with_bool_lambda_set() {
|
|||
RocStr
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
fn issue_3530_uninitialized_capacity_in_list_literal() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
[11,22,33]
|
||||
"#
|
||||
),
|
||||
3,
|
||||
(usize, usize, usize),
|
||||
|(_, _, cap)| cap
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use roc_error_macros::internal_error;
|
||||
use roc_gen_wasm::{round_up_to_alignment, wasm32_sized::Wasm32Sized};
|
||||
use roc_mono::layout::Builtin;
|
||||
use roc_std::{RocDec, RocList, RocOrder, RocResult, RocStr, I128, U128};
|
||||
use std::convert::TryInto;
|
||||
|
||||
|
@ -57,8 +58,9 @@ impl FromWasm32Memory for RocStr {
|
|||
|
||||
let str_words: &[u32; 3] = unsafe { std::mem::transmute(&str_bytes) };
|
||||
|
||||
let big_elem_ptr = str_words[0] as usize;
|
||||
let big_length = str_words[1] as usize;
|
||||
let big_elem_ptr = str_words[Builtin::WRAPPER_PTR as usize] as usize;
|
||||
let big_length = str_words[Builtin::WRAPPER_LEN as usize] as usize;
|
||||
let big_capacity = str_words[Builtin::WRAPPER_CAPACITY as usize] as usize;
|
||||
|
||||
let last_byte = str_bytes[11];
|
||||
let is_small_str = last_byte >= 0x80;
|
||||
|
@ -70,16 +72,20 @@ impl FromWasm32Memory for RocStr {
|
|||
&memory_bytes[big_elem_ptr..][..big_length]
|
||||
};
|
||||
|
||||
unsafe { RocStr::from_slice_unchecked(slice) }
|
||||
let mut roc_str = unsafe { RocStr::from_slice_unchecked(slice) };
|
||||
if !is_small_str {
|
||||
roc_str.reserve(big_capacity - big_length)
|
||||
}
|
||||
roc_str
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FromWasm32Memory + Clone> FromWasm32Memory for RocList<T> {
|
||||
fn decode(memory: &[u8], offset: u32) -> Self {
|
||||
let bytes = <u64 as FromWasm32Memory>::decode(memory, offset);
|
||||
|
||||
let length = (bytes >> 32) as u32;
|
||||
let elements = bytes as u32;
|
||||
let elements = <u32 as FromWasm32Memory>::decode(memory, offset + 4 * Builtin::WRAPPER_PTR);
|
||||
let length = <u32 as FromWasm32Memory>::decode(memory, offset + 4 * Builtin::WRAPPER_LEN);
|
||||
let capacity =
|
||||
<u32 as FromWasm32Memory>::decode(memory, offset + 4 * Builtin::WRAPPER_CAPACITY);
|
||||
|
||||
let mut items = Vec::with_capacity(length as usize);
|
||||
|
||||
|
@ -91,7 +97,9 @@ impl<T: FromWasm32Memory + Clone> FromWasm32Memory for RocList<T> {
|
|||
items.push(item);
|
||||
}
|
||||
|
||||
RocList::from_slice(&items)
|
||||
let mut list = RocList::with_capacity(capacity as usize);
|
||||
list.extend_from_slice(&items);
|
||||
list
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue