wasmtime_environ/gc/
copying.rs1use super::*;
4use core::mem;
5
6pub const HEADER_SIZE: u32 = 16;
12
13pub const ALIGN: u32 = 16;
17
18pub const ARRAY_LENGTH_OFFSET: u32 = HEADER_SIZE;
20
21pub const EXCEPTION_TAG_INSTANCE_OFFSET: u32 = HEADER_SIZE;
23
24pub const EXCEPTION_TAG_DEFINED_OFFSET: u32 = HEADER_SIZE + 4;
26
27pub const HEADER_COPIED_BIT: u32 = 1 << 0;
31
32pub const FORWARDING_REF_OFFSET: u32 = HEADER_SIZE;
36
37pub const MIN_OBJECT_SIZE: u32 = FORWARDING_REF_OFFSET + mem::size_of::<u32>() as u32;
40
41#[derive(Default)]
43pub struct CopyingTypeLayouts;
44
45#[derive(Clone, Copy, Debug)]
47pub enum InlineTraceInfo {
48 OutOfLine,
50
51 Array {
53 elems_are_gc_refs: bool,
55 },
56
57 Struct {
59 gc_ref_bitmap: u32,
63 },
64}
65
66impl InlineTraceInfo {
67 const IS_INLINE_BIT: u32 = 1 << 1;
68 const IS_ARRAY_BIT: u32 = 1 << 2;
69 const ELEMS_ARE_GC_REFS_BIT: u32 = 1 << 3;
70 const STRUCT_BITMAP_SHIFT: u32 = 3;
71 const STRUCT_BITMAP_BITS: u32 = 23;
72
73 pub const NO_GC_EDGES: InlineTraceInfo = InlineTraceInfo::Struct { gc_ref_bitmap: 0 };
76
77 pub fn new(layout: &GcLayout) -> Self {
79 match layout {
80 GcLayout::Array(a) => Self::array(a),
81 GcLayout::Struct(s) => Self::r#struct(s),
82 }
83 }
84
85 pub fn array(layout: &GcArrayLayout) -> Self {
90 InlineTraceInfo::Array {
91 elems_are_gc_refs: layout.elems_are_gc_refs,
92 }
93 }
94
95 pub fn r#struct(layout: &GcStructLayout) -> Self {
101 let mut bitmap: u32 = 0;
102 for f in layout.fields.iter() {
103 if !f.is_gc_ref {
104 continue;
105 }
106 let Some(data_offset) = f.offset.checked_sub(HEADER_SIZE) else {
107 return Self::OutOfLine;
108 };
109 if data_offset % 4 != 0 {
110 return Self::OutOfLine;
111 }
112 let slot = data_offset / 4;
113 if slot >= Self::STRUCT_BITMAP_BITS {
114 return Self::OutOfLine;
115 }
116 bitmap |= 1u32 << slot;
117 }
118 InlineTraceInfo::Struct {
119 gc_ref_bitmap: bitmap,
120 }
121 }
122
123 pub fn encode(&self) -> u32 {
126 match self {
127 Self::OutOfLine => 0,
128 Self::Array { elems_are_gc_refs } => {
129 Self::IS_INLINE_BIT
130 | Self::IS_ARRAY_BIT
131 | if *elems_are_gc_refs {
132 Self::ELEMS_ARE_GC_REFS_BIT
133 } else {
134 0
135 }
136 }
137 Self::Struct { gc_ref_bitmap } => {
138 Self::IS_INLINE_BIT | (*gc_ref_bitmap << Self::STRUCT_BITMAP_SHIFT)
139 }
140 }
141 }
142
143 pub fn decode(reserved: u32) -> Self {
145 if reserved & Self::IS_INLINE_BIT == 0 {
146 return Self::OutOfLine;
147 }
148 if reserved & Self::IS_ARRAY_BIT != 0 {
149 Self::Array {
150 elems_are_gc_refs: reserved & Self::ELEMS_ARE_GC_REFS_BIT != 0,
151 }
152 } else {
153 Self::Struct {
154 gc_ref_bitmap: (reserved >> Self::STRUCT_BITMAP_SHIFT)
155 & ((1u32 << Self::STRUCT_BITMAP_BITS) - 1),
156 }
157 }
158 }
159}
160
161impl GcTypeLayouts for CopyingTypeLayouts {
162 fn array_length_field_offset(&self) -> u32 {
163 ARRAY_LENGTH_OFFSET
164 }
165
166 fn exception_tag_instance_offset(&self) -> u32 {
167 EXCEPTION_TAG_INSTANCE_OFFSET
168 }
169
170 fn exception_tag_defined_offset(&self) -> u32 {
171 EXCEPTION_TAG_DEFINED_OFFSET
172 }
173
174 fn array_layout(&self, ty: &WasmArrayType) -> GcArrayLayout {
175 let mut layout = common_array_layout(ty, HEADER_SIZE, ALIGN, ARRAY_LENGTH_OFFSET);
176 debug_assert!(layout.align <= ALIGN);
177 layout.align = ALIGN;
178 debug_assert!(layout.base_size >= MIN_OBJECT_SIZE);
179 layout
180 }
181
182 fn struct_layout(&self, ty: &WasmStructType) -> Result<GcStructLayout, OutOfMemory> {
183 let mut layout = common_struct_layout(ty, HEADER_SIZE, ALIGN)?;
184 if layout.size < MIN_OBJECT_SIZE {
187 layout.size = MIN_OBJECT_SIZE;
188 }
189 layout.size = layout.size.next_multiple_of(ALIGN);
190 debug_assert!(layout.align <= ALIGN);
191 layout.align = ALIGN;
192 debug_assert!(layout.size >= MIN_OBJECT_SIZE);
193 Ok(layout)
194 }
195
196 fn exn_layout(&self, ty: &WasmExnType) -> Result<GcStructLayout, OutOfMemory> {
197 let mut layout = common_exn_layout(ty, HEADER_SIZE, ALIGN)?;
198 layout.size = layout.size.next_multiple_of(ALIGN);
199 debug_assert!(layout.align <= ALIGN);
200 layout.align = ALIGN;
201 debug_assert!(layout.size >= MIN_OBJECT_SIZE);
202 Ok(layout)
203 }
204}