Skip to content

Commit fb3078e

Browse files
authored
Merge pull request #27 from CppCXY/shared-proto
Shared proto
2 parents 81e0852 + 57c17e7 commit fb3078e

21 files changed

Lines changed: 856 additions & 366 deletions

File tree

crates/luars/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ categories = ["development-tools"]
1414
default = []
1515
serde = ["dep:serde", "dep:serde_json"]
1616
sandbox = []
17-
shared-string = []
17+
shared-proto = []
1818

1919
[dependencies]
2020
# local

crates/luars/src/compiler/expr_parser.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -983,7 +983,8 @@ pub fn body(fs: &mut FuncState, v: &mut ExpDesc, is_method: bool) -> Result<(),
983983

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

988989
// lparser.c:722-726: Generate CLOSURE instruction (codeclosure)
989990
// static void codeclosure (LexState *ls, expdesc *v) {

crates/luars/src/gc/gc_kind.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ pub enum GcObjectKind {
99
Upvalue = 5,
1010
Thread = 6,
1111
Userdata = 7,
12+
Proto = 8,
1213
}

crates/luars/src/gc/gc_object.rs

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::{
2-
GcObjectKind, LuaFunction, LuaTable, LuaValue,
2+
Chunk, GcObjectKind, LuaFunction, LuaTable, LuaValue,
33
lua_value::{CClosureFunction, LuaString, LuaUpvalue, LuaUserdata, RClosureFunction},
44
lua_vm::LuaState,
55
};
@@ -20,6 +20,7 @@ pub const WHITE0BIT: u8 = 3; // Object is white (type 0)
2020
pub const WHITE1BIT: u8 = 4; // Object is white (type 1)
2121
pub const BLACKBIT: u8 = 5; // Object is black
2222
pub const FINALIZEDBIT: u8 = 6; // Object has been marked for finalization
23+
pub const SHAREDBIT: u8 = 7; // Object is shared across VMs and never collected
2324

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

184+
#[inline(always)]
185+
pub fn is_shared(&self) -> bool {
186+
(self.marked() & (1 << SHAREDBIT)) != 0
187+
}
188+
183189
#[inline(always)]
184190
pub fn set_finalized(&mut self) {
185191
self.set_marked_bits(self.marked() | (1 << FINALIZEDBIT));
@@ -190,6 +196,11 @@ impl GcHeader {
190196
self.set_marked_bits(self.marked() & !(1 << FINALIZEDBIT));
191197
}
192198

199+
#[inline(always)]
200+
pub fn make_shared(&mut self) {
201+
self.set_marked_bits(self.marked() | (1 << SHAREDBIT));
202+
}
203+
193204
// ============ Color Transitions ============
194205

195206
#[inline(always)]
@@ -227,6 +238,9 @@ impl GcHeader {
227238
other_white == 0 || other_white == 1,
228239
"other_white must be 0 or 1"
229240
);
241+
if self.is_shared() {
242+
return false;
243+
}
230244
(self.marked() & (1 << (WHITE0BIT + other_white))) != 0
231245
}
232246

@@ -290,6 +304,15 @@ pub struct Gc<T> {
290304
pub data: T,
291305
}
292306

307+
impl<T: std::fmt::Debug> std::fmt::Debug for Gc<T> {
308+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
309+
f.debug_struct("Gc")
310+
.field("header", &self.header)
311+
.field("data", &self.data)
312+
.finish()
313+
}
314+
}
315+
293316
impl<T> Gc<T> {
294317
pub fn new(data: T, current_white: u8, size: u32) -> Self {
295318
let mut header = GcHeader::with_white(current_white);
@@ -312,6 +335,7 @@ pub type GcRClosure = Gc<RClosureFunction>;
312335
pub type GcUpvalue = Gc<LuaUpvalue>;
313336
pub type GcThread = Gc<LuaState>;
314337
pub type GcUserdata = Gc<LuaUserdata>;
338+
pub type GcProto = Gc<Chunk>;
315339

316340
#[derive(Debug)]
317341
pub struct GcPtr<T: HasGcHeader> {
@@ -407,6 +431,7 @@ pub type CClosurePtr = GcPtr<GcCClosure>;
407431
pub type RClosurePtr = GcPtr<GcRClosure>;
408432
pub type UserdataPtr = GcPtr<GcUserdata>;
409433
pub type ThreadPtr = GcPtr<GcThread>;
434+
pub type ProtoPtr = GcPtr<GcProto>;
410435

411436
/// Compressed GcObjectPtr — tagged pointer in a single `u64` (8 bytes, was 16).
412437
///
@@ -452,6 +477,7 @@ impl GcObjectPtr {
452477
const TAG_UPVALUE: u64 = 5;
453478
const TAG_THREAD: u64 = 6;
454479
const TAG_USERDATA: u64 = 7;
480+
const TAG_PROTO: u64 = 8;
455481
#[inline(always)]
456482
fn new_tagged(ptr: u64, tag: u64) -> Self {
457483
debug_assert!(
@@ -565,6 +591,12 @@ impl GcObjectPtr {
565591
UserdataPtr::from_raw(self.raw_ptr())
566592
}
567593

594+
#[inline(always)]
595+
pub fn as_proto_ptr(&self) -> ProtoPtr {
596+
debug_assert!(self.tag() == Self::TAG_PROTO as u8);
597+
ProtoPtr::from_raw(self.raw_ptr())
598+
}
599+
568600
// ============ Pattern matching helpers (for code that still uses if-let) ============
569601

570602
#[inline(always)]
@@ -606,6 +638,11 @@ impl GcObjectPtr {
606638
pub fn is_userdata(&self) -> bool {
607639
self.tag() == Self::TAG_USERDATA as u8
608640
}
641+
642+
#[inline(always)]
643+
pub fn is_proto(&self) -> bool {
644+
self.tag() == Self::TAG_PROTO as u8
645+
}
609646
}
610647

611648
impl From<StringPtr> for GcObjectPtr {
@@ -664,6 +701,13 @@ impl From<RClosurePtr> for GcObjectPtr {
664701
}
665702
}
666703

704+
impl From<ProtoPtr> for GcObjectPtr {
705+
#[inline(always)]
706+
fn from(ptr: ProtoPtr) -> Self {
707+
Self::new_tagged(ptr.as_u64(), Self::TAG_PROTO)
708+
}
709+
}
710+
667711
// ============ GC-managed Objects ============
668712
pub enum GcObjectOwner {
669713
String(Box<GcString>),
@@ -674,6 +718,7 @@ pub enum GcObjectOwner {
674718
Userdata(Box<GcUserdata>),
675719
CClosure(Box<GcCClosure>),
676720
RClosure(Box<GcRClosure>),
721+
Proto(Box<GcProto>),
677722
}
678723

679724
impl GcObjectOwner {
@@ -694,7 +739,7 @@ impl GcObjectOwner {
694739
base + array_bytes + hash_bytes
695740
}
696741
GcObjectOwner::Function(f) => {
697-
f.data.chunk().proto_data_size as usize + std::mem::size_of_val(f.data.upvalues())
742+
std::mem::size_of::<GcFunction>() + std::mem::size_of_val(f.data.upvalues())
698743
}
699744
GcObjectOwner::CClosure(c) => {
700745
std::mem::size_of::<GcCClosure>()
@@ -707,6 +752,9 @@ impl GcObjectOwner {
707752
GcObjectOwner::Upvalue(_) => 64, // fixed estimate
708753
GcObjectOwner::Thread(t) => std::mem::size_of::<GcThread>() + t.data.stack.len() * 16,
709754
GcObjectOwner::Userdata(_) => std::mem::size_of::<GcUserdata>(),
755+
GcObjectOwner::Proto(p) => {
756+
std::mem::size_of::<GcProto>() + p.data.proto_data_size as usize
757+
}
710758
}
711759
}
712760

@@ -726,6 +774,7 @@ impl GcObjectOwner {
726774
GcObjectOwner::Upvalue(u) => &u.header,
727775
GcObjectOwner::Thread(t) => &t.header,
728776
GcObjectOwner::Userdata(u) => &u.header,
777+
GcObjectOwner::Proto(p) => &p.header,
729778
}) as _
730779
}
731780

@@ -739,6 +788,7 @@ impl GcObjectOwner {
739788
GcObjectOwner::Upvalue(u) => &mut u.header,
740789
GcObjectOwner::Thread(t) => &mut t.header,
741790
GcObjectOwner::Userdata(u) => &mut u.header,
791+
GcObjectOwner::Proto(p) => &mut p.header,
742792
}) as _
743793
}
744794

@@ -800,6 +850,13 @@ impl GcObjectOwner {
800850
}
801851
}
802852

853+
pub fn as_proto_ptr(&self) -> Option<ProtoPtr> {
854+
match self {
855+
GcObjectOwner::Proto(p) => Some(ProtoPtr::new(p.as_ref() as *const GcProto)),
856+
_ => None,
857+
}
858+
}
859+
803860
pub fn as_gc_ptr(&self) -> GcObjectPtr {
804861
match self {
805862
GcObjectOwner::String(s) => {
@@ -826,6 +883,9 @@ impl GcObjectOwner {
826883
GcObjectOwner::RClosure(r) => {
827884
GcObjectPtr::from(RClosurePtr::new(r.as_ref() as *const GcRClosure))
828885
}
886+
GcObjectOwner::Proto(p) => {
887+
GcObjectPtr::from(ProtoPtr::new(p.as_ref() as *const GcProto))
888+
}
829889
}
830890
}
831891

@@ -878,6 +938,13 @@ impl GcObjectOwner {
878938
}
879939
}
880940

941+
pub fn as_proto_mut(&mut self) -> Option<&mut Chunk> {
942+
match self {
943+
GcObjectOwner::Proto(p) => Some(&mut p.data),
944+
_ => None,
945+
}
946+
}
947+
881948
pub fn size_of_data(&self) -> usize {
882949
self.header().size as usize
883950
}

0 commit comments

Comments
 (0)