Skip to content

Commit f01331e

Browse files
committed
fix: gc tracing non head pointers & better struct parser
1 parent 3d5bb9c commit f01331e

File tree

9 files changed

+194
-107
lines changed

9 files changed

+194
-107
lines changed

immix/src/allocator/thread_local_allocator.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ impl ThreadLocalAllocator {
303303

304304
pub fn big_obj_from_ptr(&mut self, ptr: *mut u8) -> Option<*mut BigObj> {
305305
for obj in self.big_objs.iter() {
306+
// FIXME: O(n); should use a tree
306307
let start = unsafe { (*obj as *mut u8).add(16) };
307308
let end = unsafe { (*obj as *mut u8).add((*(*obj)).size) };
308309
if start <= ptr && end >= ptr {

immix/src/block.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ pub trait HeaderExt {
3737
}
3838

3939
pub trait LineHeaderExt {
40+
fn get_is_head(&self) -> bool;
4041
fn set_is_head(&mut self, is_head: bool);
4142
fn get_is_used_follow(&self) -> bool;
4243
fn get_obj_line_size(&self, idx: usize, block: &mut Block) -> usize;
@@ -137,6 +138,10 @@ impl LineHeaderExt for LineHeader {
137138
line_size
138139
}
139140

141+
fn get_is_head(&self) -> bool {
142+
self & 0b10000000 == 0b10000000
143+
}
144+
140145
fn set_is_head(&mut self, is_head: bool) {
141146
if is_head {
142147
*self |= 0b10000000;
@@ -376,6 +381,41 @@ impl Block {
376381
&mut *(block_start as *mut Self)
377382
}
378383

384+
/// # get_head_ptr
385+
///
386+
/// A pointer in the graph may not point to the start position of the
387+
/// space we allocated for it. Consider the following example:
388+
///
389+
/// ```pl
390+
///
391+
/// struct A {
392+
/// a: u8;
393+
/// b: u8;
394+
/// }
395+
///
396+
/// let a = A { a: 1, b: 2 };
397+
/// let ptr = &a.b; // where ptr is a pointer to the field b, what we want is a pointer to the struct A
398+
/// ```
399+
///
400+
/// This function is used to get the pointer to the start position of the space we allocated for the object,
401+
/// from a pointer in the graph. e.g. in the above example, we want to get a pointer to the struct A, by
402+
/// passing the pointer to the field b.
403+
pub unsafe fn get_head_ptr(&mut self, ptr: *mut u8) -> *mut u8 {
404+
let mut idx = self.get_line_idx_from_addr(ptr);
405+
let mut header = self.get_nth_line_header(idx);
406+
// 如果是head,直接返回
407+
if header.get_is_head() {
408+
return self.get_nth_line(idx);
409+
}
410+
// 否则往前找到head
411+
while !header.get_is_head() {
412+
header = self.get_nth_line_header(idx - 1);
413+
idx -= 1;
414+
}
415+
// 返回head的地址
416+
self.get_nth_line(idx)
417+
}
418+
379419
pub unsafe fn get_line_header_from_addr(&mut self, addr: *mut u8) -> (&mut LineHeader, usize) {
380420
let idx = self.get_line_idx_from_addr(addr);
381421
(self.get_nth_line_header(idx), idx)

immix/src/collector.rs

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ struct CollectorStatus {
4343
collect_threshold: usize,
4444
/// in bytes
4545
bytes_allocated_since_last_gc: usize,
46-
last_gc_time: std::time::SystemTime,
4746
collecting: bool,
4847
}
4948

@@ -104,7 +103,6 @@ impl Collector {
104103
status: RefCell::new(CollectorStatus {
105104
collect_threshold: 1024,
106105
bytes_allocated_since_last_gc: 0,
107-
last_gc_time: std::time::SystemTime::now(),
108106
collecting: false,
109107
}),
110108
}
@@ -222,13 +220,13 @@ impl Collector {
222220
/// 现在纠正为
223221
///
224222
/// ptr -> new_ptr(forwarded) -> value
225-
unsafe fn correct_ptr(&self, ptr: *mut u8) {
223+
unsafe fn correct_ptr(&self, ptr: *mut u8, offset: isize) {
226224
let ptr = ptr as *mut AtomicPtr<*mut u8>;
227225
let new_ptr = *(*ptr).load(Ordering::SeqCst);
228226
let ptr = ptr as *mut *mut u8;
229227
debug_assert!(!new_ptr.is_null());
230228
log::trace!("gc {} correct ptr {:p} to {:p}", self.id, ptr, new_ptr);
231-
*ptr = new_ptr;
229+
*ptr = new_ptr.offset(offset);
232230
}
233231

234232
#[cfg(feature = "llvm_gc_plugin")]
@@ -248,37 +246,39 @@ impl Collector {
248246
return;
249247
}
250248

251-
let mut ptr = *(ptr as *mut *mut u8);
249+
let ptr = *(ptr as *mut *mut u8);
252250
// println!("mark ptr {:p} -> {:p}", father, ptr);
253251
// mark it if it is in heap
254252
if self.thread_local_allocator.as_mut().unwrap().in_heap(ptr) {
255253
// println!("mark ptr succ {:p} -> {:p}", father, ptr);
256254
let block = Block::from_obj_ptr(ptr);
257255
let is_candidate = block.is_eva_candidate();
256+
let mut head = block.get_head_ptr(ptr);
257+
let offset_from_head = ptr.offset_from(head);
258258
if !is_candidate {
259259
block.marked = true;
260260
} else {
261-
let (line_header, _) = block.get_line_header_from_addr(ptr);
261+
let (line_header, _) = block.get_line_header_from_addr(head);
262262
if line_header.get_forwarded() {
263-
self.correct_ptr(father);
263+
self.correct_ptr(father, offset_from_head);
264264
return;
265265
}
266266
}
267-
let (line_header, idx) = block.get_line_header_from_addr(ptr);
267+
let (line_header, idx) = block.get_line_header_from_addr(head);
268268
if line_header.get_marked() {
269269
return;
270270
}
271271
// 若此block是待驱逐对象
272272
if is_candidate {
273-
let atomic_ptr = ptr as *mut AtomicPtr<u8>;
273+
let atomic_ptr = head as *mut AtomicPtr<u8>;
274274
let old_loaded = (*atomic_ptr).load(Ordering::SeqCst);
275-
let obj_line_size = line_header.get_obj_line_size(idx, Block::from_obj_ptr(ptr));
275+
let obj_line_size = line_header.get_obj_line_size(idx, Block::from_obj_ptr(head));
276276
let new_ptr = self.alloc(obj_line_size * LINE_SIZE, line_header.get_obj_type());
277277
if !new_ptr.is_null() {
278278
let new_block = Block::from_obj_ptr(new_ptr);
279279
let (new_line_header, _) = new_block.get_line_header_from_addr(new_ptr);
280280
// 将数据复制到新的地址
281-
core::ptr::copy_nonoverlapping(ptr, new_ptr, obj_line_size * LINE_SIZE);
281+
core::ptr::copy_nonoverlapping(head, new_ptr, obj_line_size * LINE_SIZE);
282282
// core::ptr::copy_nonoverlapping(line_header as * const u8, new_line_header as * mut u8, line_size);
283283

284284
// 线程安全性说明
@@ -293,16 +293,16 @@ impl Collector {
293293
.is_ok()
294294
{
295295
// 成功驱逐
296-
log::trace!("gc {}: eva {:p} to {:p}", self.id, ptr, new_ptr);
296+
log::trace!("gc {}: eva {:p} to {:p}", self.id, head, new_ptr);
297297
new_line_header.set_marked(true);
298298
line_header.set_forwarded(true);
299299
new_block.marked = true;
300-
ptr = new_ptr;
301-
self.correct_ptr(father);
300+
head = new_ptr;
301+
self.correct_ptr(father, offset_from_head);
302302
} else {
303303
// 期间别的线程驱逐了它
304304
spin_until!(line_header.get_forwarded());
305-
self.correct_ptr(father);
305+
self.correct_ptr(father, offset_from_head);
306306
return;
307307
}
308308
}
@@ -311,7 +311,7 @@ impl Collector {
311311
let obj_type = line_header.get_obj_type();
312312
match obj_type {
313313
ObjectType::Atomic => {}
314-
_ => (*self.queue).push((ptr, obj_type)),
314+
_ => (*self.queue).push((head, obj_type)),
315315
}
316316
return;
317317
}
@@ -550,7 +550,6 @@ impl Collector {
550550
}
551551
status.collecting = true;
552552
status.bytes_allocated_since_last_gc = 0;
553-
status.last_gc_time = std::time::SystemTime::now();
554553
drop(status);
555554
// evacuation pre process
556555
// 这个过程要在完成safepoint同步之前完成,因为在驱逐的情况下

src/ast/diag.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,8 @@ define_error!(
146146
EXPECT_ARRAY_TYPE = "expect array type",
147147
EXPECT_INT_VALUE = "expect int value",
148148
METHODS_MUST_HAVE_BODY = "methods must have body",
149+
INVALID_STRUCT_INIT = "invalid struct initialization",
150+
REDUNDANT_COMMA = "REDUNDANT comma",
149151
);
150152
macro_rules! define_warn {
151153
($(

src/ast/node/types.rs

Lines changed: 47 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use crate::ast::pltype::get_type_deep;
1818
use crate::ast::pltype::ClosureType;
1919
use crate::ast::pltype::{ARRType, Field, GenericType, PLType, STType};
2020
use crate::ast::tokens::TokenType;
21+
use crate::ast::traits::CustomType;
2122
use indexmap::IndexMap;
2223

2324
use internal_macro::node;
@@ -606,14 +607,15 @@ impl Node for StructInitFieldNode {
606607
ctx: &'b mut Ctx<'a>,
607608
builder: &'b BuilderEnum<'a, '_>,
608609
) -> NodeResult {
610+
ctx.push_semantic_token(self.id.range(), SemanticTokenType::PROPERTY, 0);
609611
self.exp.emit(ctx, builder)
610612
}
611613
}
612614

613-
#[node(comment)]
615+
#[node]
614616
pub struct StructInitNode {
615617
pub typename: Box<TypeNodeEnum>,
616-
pub fields: Vec<Box<StructInitFieldNode>>, // TODO: comment db and salsa comment struct
618+
pub fields: Vec<Box<NodeEnum>>, // TODO: comment db and salsa comment struct
617619
}
618620

619621
impl PrintTrait for StructInitNode {
@@ -658,41 +660,50 @@ impl Node for StructInitNode {
658660
ctx.save_if_comment_doc_hover(self.typename.range(), Some(sttype.doc.clone()));
659661
ctx.run_in_type_mod_mut(&mut sttype, |ctx, sttype| {
660662
for fieldinit in self.fields.iter_mut() {
661-
let field_id_range = fieldinit.id.range;
662-
let field_exp_range = fieldinit.exp.range();
663-
let field = sttype.fields.get(&fieldinit.id.name);
664-
if field.is_none() {
665-
ctx.if_completion(self.range, || sttype.get_completions(ctx));
666-
return Err(
667-
ctx.add_diag(field_id_range.new_err(ErrorCode::STRUCT_FIELD_NOT_FOUND))
668-
);
669-
}
670-
let field = field.unwrap();
671-
let v = fieldinit.emit(ctx, builder)?.get_value();
672-
idx += 1;
673-
ctx.emit_comment_highlight(&self.comments[idx - 1]);
674-
if v.is_none() {
675-
return Err(ctx.add_diag(field_exp_range.new_err(ErrorCode::EXPECT_VALUE)));
676-
}
677-
let v = v.unwrap();
678-
let value = ctx.try_load2var(field_exp_range, v.get_value(), builder)?;
679-
let value_pltype = v.get_ty();
680-
ctx.protect_generic_context(&sttype.generic_map, |ctx| {
681-
if !field
682-
.typenode
683-
.eq_or_infer(ctx, value_pltype.clone(), builder)?
684-
.eq
685-
{
686-
return Err(ctx.add_diag(
687-
fieldinit
688-
.range
689-
.new_err(ErrorCode::STRUCT_FIELD_TYPE_NOT_MATCH),
690-
));
663+
if let NodeEnum::STInitField(fieldinit) = &mut **fieldinit {
664+
let field_id_range = fieldinit.id.range;
665+
let field_exp_range = fieldinit.exp.range();
666+
let field = sttype.fields.get(&fieldinit.id.name);
667+
if field.is_none() {
668+
ctx.if_completion(self.range, || sttype.get_completions(ctx));
669+
return Err(
670+
ctx.add_diag(field_id_range.new_err(ErrorCode::STRUCT_FIELD_NOT_FOUND))
671+
);
672+
}
673+
let field = field.unwrap();
674+
let v = fieldinit.emit(ctx, builder)?.get_value();
675+
idx += 1;
676+
if v.is_none() {
677+
return Err(ctx.add_diag(field_exp_range.new_err(ErrorCode::EXPECT_VALUE)));
678+
}
679+
let v = v.unwrap();
680+
let value = ctx.try_load2var(field_exp_range, v.get_value(), builder)?;
681+
let value_pltype = v.get_ty();
682+
ctx.protect_generic_context(&sttype.generic_map, |ctx| {
683+
if !field
684+
.typenode
685+
.eq_or_infer(ctx, value_pltype.clone(), builder)?
686+
.eq
687+
{
688+
return Err(ctx.add_diag(
689+
fieldinit
690+
.range()
691+
.new_err(ErrorCode::STRUCT_FIELD_TYPE_NOT_MATCH),
692+
));
693+
}
694+
Ok(())
695+
})?;
696+
field_init_values.push((field.index, value));
697+
ctx.send_if_go_to_def(field_id_range, field.range, sttype.get_path());
698+
ctx.set_field_refs(pltype.clone(), field, field_id_range);
699+
} else if let NodeEnum::Err(fieldinit) = &mut **fieldinit {
700+
if !fieldinit.src.contains(':') {
701+
ctx.if_completion(fieldinit.range(), || sttype.get_completions(ctx));
691702
}
692-
Ok(())
693-
})?;
694-
field_init_values.push((field.index, value));
695-
ctx.set_field_refs(pltype.clone(), field, field_id_range);
703+
let _ = fieldinit.emit(ctx, builder);
704+
} else {
705+
unreachable!()
706+
}
696707
}
697708
if !sttype.generic_map.is_empty() {
698709
if sttype.need_gen_code() {
@@ -709,9 +720,6 @@ impl Node for StructInitNode {
709720
Ok(())
710721
})?;
711722

712-
if self.fields.len() < self.comments.len() {
713-
ctx.emit_comment_highlight(&self.comments[idx]);
714-
}
715723
let struct_pointer = builder.alloc("initstruct", &pltype.borrow(), ctx, None); //alloc(ctx, tp, "initstruct");
716724
field_init_values.iter().for_each(|(index, value)| {
717725
let fieldptr = builder

0 commit comments

Comments
 (0)