Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/luars/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ categories = ["development-tools"]
default = []
serde = ["dep:serde", "dep:serde_json"]
sandbox = []
shared-string = []
shared-proto = []

[dependencies]
# local
Expand Down
3 changes: 2 additions & 1 deletion crates/luars/src/compiler/expr_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -983,7 +983,8 @@ pub fn body(fs: &mut FuncState, v: &mut ExpDesc, is_method: bool) -> Result<(),

// lparser.c:1005: Add child proto to parent (addprototype)
let proto_idx = fs.chunk.child_protos.len();
fs.chunk.child_protos.push(std::rc::Rc::new(child_chunk));
let child_proto = fs.vm.create_proto(child_chunk).unwrap();
fs.chunk.child_protos.push(child_proto);

// lparser.c:722-726: Generate CLOSURE instruction (codeclosure)
// static void codeclosure (LexState *ls, expdesc *v) {
Expand Down
1 change: 1 addition & 0 deletions crates/luars/src/gc/gc_kind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ pub enum GcObjectKind {
Upvalue = 5,
Thread = 6,
Userdata = 7,
Proto = 8,
}
71 changes: 69 additions & 2 deletions crates/luars/src/gc/gc_object.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
GcObjectKind, LuaFunction, LuaTable, LuaValue,
Chunk, GcObjectKind, LuaFunction, LuaTable, LuaValue,
lua_value::{CClosureFunction, LuaString, LuaUpvalue, LuaUserdata, RClosureFunction},
lua_vm::LuaState,
};
Expand All @@ -20,6 +20,7 @@ pub const WHITE0BIT: u8 = 3; // Object is white (type 0)
pub const WHITE1BIT: u8 = 4; // Object is white (type 1)
pub const BLACKBIT: u8 = 5; // Object is black
pub const FINALIZEDBIT: u8 = 6; // Object has been marked for finalization
pub const SHAREDBIT: u8 = 7; // Object is shared across VMs and never collected

// Bit masks
pub const WHITEBITS: u8 = (1 << WHITE0BIT) | (1 << WHITE1BIT);
Expand Down Expand Up @@ -180,6 +181,11 @@ impl GcHeader {
(self.marked() & (1 << FINALIZEDBIT)) != 0
}

#[inline(always)]
pub fn is_shared(&self) -> bool {
(self.marked() & (1 << SHAREDBIT)) != 0
}

#[inline(always)]
pub fn set_finalized(&mut self) {
self.set_marked_bits(self.marked() | (1 << FINALIZEDBIT));
Expand All @@ -190,6 +196,11 @@ impl GcHeader {
self.set_marked_bits(self.marked() & !(1 << FINALIZEDBIT));
}

#[inline(always)]
pub fn make_shared(&mut self) {
self.set_marked_bits(self.marked() | (1 << SHAREDBIT));
}

// ============ Color Transitions ============

#[inline(always)]
Expand Down Expand Up @@ -227,6 +238,9 @@ impl GcHeader {
other_white == 0 || other_white == 1,
"other_white must be 0 or 1"
);
if self.is_shared() {
return false;
}
(self.marked() & (1 << (WHITE0BIT + other_white))) != 0
}

Expand Down Expand Up @@ -290,6 +304,15 @@ pub struct Gc<T> {
pub data: T,
}

impl<T: std::fmt::Debug> std::fmt::Debug for Gc<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Gc")
.field("header", &self.header)
.field("data", &self.data)
.finish()
}
}

impl<T> Gc<T> {
pub fn new(data: T, current_white: u8, size: u32) -> Self {
let mut header = GcHeader::with_white(current_white);
Expand All @@ -312,6 +335,7 @@ pub type GcRClosure = Gc<RClosureFunction>;
pub type GcUpvalue = Gc<LuaUpvalue>;
pub type GcThread = Gc<LuaState>;
pub type GcUserdata = Gc<LuaUserdata>;
pub type GcProto = Gc<Chunk>;

#[derive(Debug)]
pub struct GcPtr<T: HasGcHeader> {
Expand Down Expand Up @@ -407,6 +431,7 @@ pub type CClosurePtr = GcPtr<GcCClosure>;
pub type RClosurePtr = GcPtr<GcRClosure>;
pub type UserdataPtr = GcPtr<GcUserdata>;
pub type ThreadPtr = GcPtr<GcThread>;
pub type ProtoPtr = GcPtr<GcProto>;

/// Compressed GcObjectPtr — tagged pointer in a single `u64` (8 bytes, was 16).
///
Expand Down Expand Up @@ -452,6 +477,7 @@ impl GcObjectPtr {
const TAG_UPVALUE: u64 = 5;
const TAG_THREAD: u64 = 6;
const TAG_USERDATA: u64 = 7;
const TAG_PROTO: u64 = 8;
#[inline(always)]
fn new_tagged(ptr: u64, tag: u64) -> Self {
debug_assert!(
Expand Down Expand Up @@ -565,6 +591,12 @@ impl GcObjectPtr {
UserdataPtr::from_raw(self.raw_ptr())
}

#[inline(always)]
pub fn as_proto_ptr(&self) -> ProtoPtr {
debug_assert!(self.tag() == Self::TAG_PROTO as u8);
ProtoPtr::from_raw(self.raw_ptr())
}

// ============ Pattern matching helpers (for code that still uses if-let) ============

#[inline(always)]
Expand Down Expand Up @@ -606,6 +638,11 @@ impl GcObjectPtr {
pub fn is_userdata(&self) -> bool {
self.tag() == Self::TAG_USERDATA as u8
}

#[inline(always)]
pub fn is_proto(&self) -> bool {
self.tag() == Self::TAG_PROTO as u8
}
}

impl From<StringPtr> for GcObjectPtr {
Expand Down Expand Up @@ -664,6 +701,13 @@ impl From<RClosurePtr> for GcObjectPtr {
}
}

impl From<ProtoPtr> for GcObjectPtr {
#[inline(always)]
fn from(ptr: ProtoPtr) -> Self {
Self::new_tagged(ptr.as_u64(), Self::TAG_PROTO)
}
}

// ============ GC-managed Objects ============
pub enum GcObjectOwner {
String(Box<GcString>),
Expand All @@ -674,6 +718,7 @@ pub enum GcObjectOwner {
Userdata(Box<GcUserdata>),
CClosure(Box<GcCClosure>),
RClosure(Box<GcRClosure>),
Proto(Box<GcProto>),
}

impl GcObjectOwner {
Expand All @@ -694,7 +739,7 @@ impl GcObjectOwner {
base + array_bytes + hash_bytes
}
GcObjectOwner::Function(f) => {
f.data.chunk().proto_data_size as usize + std::mem::size_of_val(f.data.upvalues())
std::mem::size_of::<GcFunction>() + std::mem::size_of_val(f.data.upvalues())
}
GcObjectOwner::CClosure(c) => {
std::mem::size_of::<GcCClosure>()
Expand All @@ -707,6 +752,9 @@ impl GcObjectOwner {
GcObjectOwner::Upvalue(_) => 64, // fixed estimate
GcObjectOwner::Thread(t) => std::mem::size_of::<GcThread>() + t.data.stack.len() * 16,
GcObjectOwner::Userdata(_) => std::mem::size_of::<GcUserdata>(),
GcObjectOwner::Proto(p) => {
std::mem::size_of::<GcProto>() + p.data.proto_data_size as usize
}
}
}

Expand All @@ -726,6 +774,7 @@ impl GcObjectOwner {
GcObjectOwner::Upvalue(u) => &u.header,
GcObjectOwner::Thread(t) => &t.header,
GcObjectOwner::Userdata(u) => &u.header,
GcObjectOwner::Proto(p) => &p.header,
}) as _
}

Expand All @@ -739,6 +788,7 @@ impl GcObjectOwner {
GcObjectOwner::Upvalue(u) => &mut u.header,
GcObjectOwner::Thread(t) => &mut t.header,
GcObjectOwner::Userdata(u) => &mut u.header,
GcObjectOwner::Proto(p) => &mut p.header,
}) as _
}

Expand Down Expand Up @@ -800,6 +850,13 @@ impl GcObjectOwner {
}
}

pub fn as_proto_ptr(&self) -> Option<ProtoPtr> {
match self {
GcObjectOwner::Proto(p) => Some(ProtoPtr::new(p.as_ref() as *const GcProto)),
_ => None,
}
}

pub fn as_gc_ptr(&self) -> GcObjectPtr {
match self {
GcObjectOwner::String(s) => {
Expand All @@ -826,6 +883,9 @@ impl GcObjectOwner {
GcObjectOwner::RClosure(r) => {
GcObjectPtr::from(RClosurePtr::new(r.as_ref() as *const GcRClosure))
}
GcObjectOwner::Proto(p) => {
GcObjectPtr::from(ProtoPtr::new(p.as_ref() as *const GcProto))
}
}
}

Expand Down Expand Up @@ -878,6 +938,13 @@ impl GcObjectOwner {
}
}

pub fn as_proto_mut(&mut self) -> Option<&mut Chunk> {
match self {
GcObjectOwner::Proto(p) => Some(&mut p.data),
_ => None,
}
}

pub fn size_of_data(&self) -> usize {
self.header().size as usize
}
Expand Down
Loading
Loading