From e7ce3f8f1bb0c0c03a3321d2e7aab3ad137c4dbf Mon Sep 17 00:00:00 2001 From: monochrome Date: Sat, 4 Jan 2025 23:28:22 +0900 Subject: [PATCH] Fix bug. --- monoruby/src/alloc.rs | 8 -- monoruby/src/builtins/kernel.rs | 9 ++ monoruby/src/compiler/runtime.rs | 19 +++ monoruby/src/compiler/vmgen/method_call.rs | 14 +- monoruby/src/globals/dump.rs | 22 ++- monoruby/src/value.rs | 46 ++++++- monoruby/src/value/rvalue.rs | 148 ++++++++++++--------- monoruby/src/value/rvalue/hash.rs | 2 +- 8 files changed, 178 insertions(+), 90 deletions(-) diff --git a/monoruby/src/alloc.rs b/monoruby/src/alloc.rs index 86f549c0..03449943 100644 --- a/monoruby/src/alloc.rs +++ b/monoruby/src/alloc.rs @@ -184,14 +184,6 @@ impl Allocator { self.pages.len() + 1 } - pub fn set_enabled(enable: bool) -> bool { - ALLOC.with(|alloc| { - let old = alloc.borrow().gc_enabled; - alloc.borrow_mut().gc_enabled = enable; - old - }) - } - /// /// Allocate object. /// diff --git a/monoruby/src/builtins/kernel.rs b/monoruby/src/builtins/kernel.rs index dbee4915..46e02538 100644 --- a/monoruby/src/builtins/kernel.rs +++ b/monoruby/src/builtins/kernel.rs @@ -47,6 +47,7 @@ pub(super) fn init(globals: &mut Globals) -> Module { globals.define_builtin_module_func(kernel_class, "__dir__", dir_, 0); globals.define_builtin_func(kernel_class, "__assert", assert, 2); globals.define_builtin_func(kernel_class, "__dump", dump, 0); + globals.define_builtin_func(kernel_class, "__check_stack", check_stack, 0); globals.define_builtin_func(kernel_class, "__instance_ty", instance_ty, 0); globals.define_builtin_func( kernel_class, @@ -322,6 +323,14 @@ fn dump(vm: &mut Executor, globals: &mut Globals, _lfp: Lfp) -> Result { Ok(Value::nil()) } +#[monoruby_builtin] +fn check_stack(vm: &mut Executor, globals: &mut Globals, _lfp: Lfp) -> Result { + if crate::runtime::_check_stack(vm, globals) { + crate::runtime::_dump_stacktrace(vm, globals); + } + Ok(Value::nil()) +} + #[monoruby_builtin] fn instance_ty(_vm: &mut Executor, globals: &mut Globals, lfp: Lfp) -> Result { let class_id = lfp.self_val().class(); diff --git a/monoruby/src/compiler/runtime.rs b/monoruby/src/compiler/runtime.rs index cb35eda6..dea9c11e 100644 --- a/monoruby/src/compiler/runtime.rs +++ b/monoruby/src/compiler/runtime.rs @@ -864,3 +864,22 @@ pub extern "C" fn _dump_stacktrace(vm: &mut Executor, globals: &mut Globals) { } eprintln!("-----end stacktrace"); } + +pub extern "C" fn _check_stack(vm: &mut Executor, globals: &mut Globals) -> bool { + let mut invalid = false; + let mut cfp = vm.cfp(); + unsafe { + for _ in 0..16 { + let prev_cfp = cfp.prev(); + if globals.check_frame_info(cfp.lfp()) { + invalid = true; + }; + if let Some(prev_cfp) = prev_cfp { + cfp = prev_cfp; + } else { + break; + } + } + } + invalid +} diff --git a/monoruby/src/compiler/vmgen/method_call.rs b/monoruby/src/compiler/vmgen/method_call.rs index 8ac02edd..26561576 100644 --- a/monoruby/src/compiler/vmgen/method_call.rs +++ b/monoruby/src/compiler/vmgen/method_call.rs @@ -240,19 +240,19 @@ impl Codegen { // version mismatch slow_path2: subq rsp, 1024; + //pushq rcx; + //subq rsp, 8; + //movq rdi, rcx; + //movq rax, (dump_rdi); + //call rax; + //addq rsp, 8; + //popq rcx; movq rdi, rbx; movq rsi, r12; movl rdx, [r13 + (CALLSITE_ID)]; // CallSiteId movq rax, (runtime::find_method); call rax; // rax <- Option movl rax, rax; - //pushq rax; - //subq rsp, 8; - //movq rdi, rax; - //movq rax, (dump_rdi); - //call rax; - //addq rsp, 8; - //popq rax; addq rsp, 1024; ); self.vm_handle_error(); diff --git a/monoruby/src/globals/dump.rs b/monoruby/src/globals/dump.rs index 65bd345c..f74ccd59 100644 --- a/monoruby/src/globals/dump.rs +++ b/monoruby/src/globals/dump.rs @@ -29,11 +29,14 @@ impl Globals { eprint!(" "); for r in 0..meta.reg_num() as usize { eprint!( - "%{}{}:[{}] ", + "%{}:[{}] ", r, - if r == 0 { "(self)" } else { "" }, if let Some(v) = lfp.register(r) { - v.debug(&self.store) + if let Some(s) = v.debug_check(&self.store) { + s + } else { + "INVALID".to_string() + } } else { "None".to_string() } @@ -42,6 +45,19 @@ impl Globals { eprintln!(); } + pub(crate) unsafe fn check_frame_info(&self, lfp: Lfp) -> bool { + let meta = lfp.meta(); + let mut invalid = false; + for r in 0..meta.reg_num() as usize { + if let Some(v) = lfp.register(r) { + if v.debug_check(&self.store).is_none() { + invalid = true; + } + } + } + invalid + } + #[cfg(feature = "emit-bc")] pub fn dump_bc(&mut self) { let dumped_bc = self.dumped_bc; diff --git a/monoruby/src/value.rs b/monoruby/src/value.rs index f70d0a12..819ff9e7 100644 --- a/monoruby/src/value.rs +++ b/monoruby/src/value.rs @@ -85,11 +85,31 @@ impl Value { NIL_VALUE => NIL_CLASS, TRUE_VALUE => TRUE_CLASS, FALSE_VALUE => FALSE_CLASS, - _ => unreachable!("Illegal packed value. {:x}", self.0), + _ => unreachable!("Illegal packed value. 0x{:016x}", self.0), } } } + pub(crate) fn debug_class(&self) -> Option { + let class = if self.is_fixnum() { + INTEGER_CLASS + } else if self.is_flonum() { + FLOAT_CLASS + } else if let Some(rv) = self.try_rvalue() { + rv.debug_class()? + } else if self.is_symbol() { + SYMBOL_CLASS + } else { + match self.0.get() { + NIL_VALUE => NIL_CLASS, + TRUE_VALUE => TRUE_CLASS, + FALSE_VALUE => FALSE_CLASS, + _ => return None, + } + }; + Some(class) + } + pub(crate) fn ty(&self) -> Option { self.try_rvalue().map(|rv| rv.ty()) } @@ -447,7 +467,7 @@ impl Value { } else if let Some(f) = self.try_flonum() { RV::Float(f) } else if self.id() == 0 { - RV::None + RV::Invalid } else if let Some(rv) = self.try_rvalue() { rv.unpack() } else if self.is_symbol() { @@ -471,7 +491,7 @@ impl Value { /// pub fn debug(&self, store: &Store) -> String { match self.unpack() { - RV::None => "UNDEFINED".to_string(), + RV::Invalid => "UNDEFINED".to_string(), RV::Nil => "nil".to_string(), RV::Bool(b) => format!("{:?}", b), RV::Fixnum(n) => format!("{}", n), @@ -484,6 +504,22 @@ impl Value { } } + pub fn debug_check(&self, store: &Store) -> Option { + let s = match self.unpack() { + RV::Invalid => return None, + RV::Nil => "nil".to_string(), + RV::Bool(b) => format!("{:?}", b), + RV::Fixnum(n) => format!("{}", n), + RV::BigInt(n) => format!("{}", n), + RV::Float(f) => dtoa::Buffer::new().format(f).to_string(), + RV::Complex(_) => self.as_complex().debug(store), + RV::Symbol(id) => format!(":{id}"), + RV::String(s) => format!(r#""{}""#, s.inspect()), + RV::Object(rvalue) => rvalue.debug(store), + }; + Some(s) + } + pub fn debug_tos(&self, store: &Store) -> String { let s = match self.unpack() { RV::Nil => "".to_string(), @@ -1242,7 +1278,7 @@ impl Value { #[derive(Clone, PartialEq)] pub enum RV<'a> { - None, + Invalid, Nil, Bool(bool), Fixnum(i64), @@ -1257,7 +1293,7 @@ pub enum RV<'a> { impl<'a> std::fmt::Debug for RV<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - RV::None => write!(f, "Undef"), + RV::Invalid => write!(f, "Undef"), RV::Nil => write!(f, "nil"), RV::Bool(b) => write!(f, "{b:?}"), RV::Fixnum(n) => write!(f, "{n}"), diff --git a/monoruby/src/value/rvalue.rs b/monoruby/src/value/rvalue.rs index 331fe86d..e08c10c3 100644 --- a/monoruby/src/value/rvalue.rs +++ b/monoruby/src/value/rvalue.rs @@ -381,8 +381,8 @@ impl std::fmt::Debug for RValue { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let meta = unsafe { self.header.meta }; if !self.header.is_live() { - write!(f, "{:016x} DEAD: next:{:?}", self.id(), unsafe { - self.header.next + write!(f, "{:016x} DEAD: {:?}", self.id(), unsafe { + self.header.meta }) } else { write!( @@ -683,21 +683,14 @@ impl alloc::GC for RValue { } ObjTy::STRING => {} ObjTy::TIME => {} - ObjTy::ARRAY => { - self.as_array().iter().for_each(|v| v.mark(alloc)); - } + ObjTy::ARRAY => self.as_array().iter().for_each(|v| v.mark(alloc)), ObjTy::RANGE => { let range = self.as_range(); range.start.mark(alloc); range.end.mark(alloc); } ObjTy::PROC => {} - ObjTy::HASH => { - for (k, v) in self.as_hashmap().iter() { - k.mark(alloc); - v.mark(alloc); - } - } + ObjTy::HASH => self.as_hashmap().mark(alloc), ObjTy::REGEXP => {} ObjTy::IO => {} ObjTy::EXCEPTION => {} @@ -783,6 +776,10 @@ impl RValue { self.header.ty() } + pub(crate) unsafe fn try_ty(&self) -> Option { + self.header.meta.ty + } + /// /// Get class object of *self. /// @@ -924,61 +921,76 @@ impl RValue { header: self.header, var_table: self.var_table.clone(), kind: unsafe { - match self.ty() { - //ObjTy::INVALID => panic!("Invalid rvalue. (maybe GC problem) {:?}", &self), - ObjTy::CLASS | ObjTy::MODULE => ObjKind { - class: self.kind.class.clone(), - }, - ObjTy::OBJECT => ObjKind { - object: self.kind.object.clone(), - }, - ObjTy::BIGNUM => ObjKind { - bignum: self.kind.bignum.clone(), - }, - ObjTy::FLOAT => ObjKind { - float: self.kind.float, - }, - ObjTy::COMPLEX => ObjKind { - complex: ManuallyDrop::new(self.kind.complex.dup()), - }, - ObjTy::STRING => ObjKind { - string: self.kind.string.clone(), - }, - ObjTy::TIME => ObjKind { - time: self.kind.time.clone(), - }, - ObjTy::ARRAY => ObjKind { - array: self.kind.array.clone(), - }, - ObjTy::RANGE => ObjKind { - range: self.kind.range.clone(), - }, - ObjTy::PROC => ObjKind { - proc: self.kind.proc.clone(), - }, - ObjTy::HASH => ObjKind { - hash: self.kind.hash.clone(), - }, - ObjTy::REGEXP => ObjKind { - regexp: self.kind.regexp.clone(), - }, - ObjTy::IO => ObjKind { - io: self.kind.io.clone(), - }, - ObjTy::EXCEPTION => ObjKind { - exception: self.kind.exception.clone(), - }, - ObjTy::METHOD => ObjKind { - method: self.kind.method.clone(), - }, - _ => unreachable!("clone()"), + if let Some(ty) = self.try_ty() { + match ty { + ObjTy::CLASS | ObjTy::MODULE => ObjKind { + class: self.kind.class.clone(), + }, + ObjTy::OBJECT => ObjKind { + object: self.kind.object.clone(), + }, + ObjTy::BIGNUM => ObjKind { + bignum: self.kind.bignum.clone(), + }, + ObjTy::FLOAT => ObjKind { + float: self.kind.float, + }, + ObjTy::COMPLEX => ObjKind { + complex: ManuallyDrop::new(self.kind.complex.dup()), + }, + ObjTy::STRING => ObjKind { + string: self.kind.string.clone(), + }, + ObjTy::TIME => ObjKind { + time: self.kind.time.clone(), + }, + ObjTy::ARRAY => ObjKind { + array: self.kind.array.clone(), + }, + ObjTy::RANGE => ObjKind { + range: self.kind.range.clone(), + }, + ObjTy::PROC => ObjKind { + proc: self.kind.proc.clone(), + }, + ObjTy::HASH => ObjKind { + hash: self.kind.hash.clone(), + }, + ObjTy::REGEXP => ObjKind { + regexp: self.kind.regexp.clone(), + }, + ObjTy::IO => ObjKind { + io: self.kind.io.clone(), + }, + ObjTy::EXCEPTION => ObjKind { + exception: self.kind.exception.clone(), + }, + ObjTy::METHOD => ObjKind { + method: self.kind.method.clone(), + }, + ty => unreachable!("{ty:?}"), + } + } else { + unreachable!() } }, } } pub(crate) fn class(&self) -> ClassId { - self.header.class() + if self.header.is_live() { + self.header.class() + } else { + unreachable!("Dead object {:?}", self) + } + } + + pub(crate) fn debug_class(&self) -> Option { + if self.header.is_live() { + Some(self.header.class()) + } else { + None + } } } @@ -1338,12 +1350,16 @@ impl RValue { impl RValue { pub fn unpack(&self) -> RV { unsafe { - match self.ty() { - ObjTy::BIGNUM => RV::BigInt(self.as_bignum()), - ObjTy::FLOAT => RV::Float(self.as_float()), - ObjTy::STRING => RV::String(self.as_bytes()), - ObjTy::COMPLEX => RV::Complex(self.as_complex()), - _ => RV::Object(self), + if let Some(ty) = self.try_ty() { + match ty { + ObjTy::BIGNUM => RV::BigInt(self.as_bignum()), + ObjTy::FLOAT => RV::Float(self.as_float()), + ObjTy::STRING => RV::String(self.as_bytes()), + ObjTy::COMPLEX => RV::Complex(self.as_complex()), + _ => RV::Object(self), + } + } else { + RV::Invalid } } } diff --git a/monoruby/src/value/rvalue/hash.rs b/monoruby/src/value/rvalue/hash.rs index de30cc6f..e45f4869 100644 --- a/monoruby/src/value/rvalue/hash.rs +++ b/monoruby/src/value/rvalue/hash.rs @@ -17,7 +17,7 @@ impl Hashmap { } else { match self.default { HashDefault::Proc(p) => vm.invoke_proc(globals, p, &[self.0, key]), - HashDefault::Value(v) => Ok(v), + HashDefault::Value(v) => Ok(v.dup()), } } }