Skip to content

Commit 17ce1e2

Browse files
authored
Merge pull request #52 from CppCXY/refactor-stack
Refactor stack
2 parents 3f60369 + d10abac commit 17ce1e2

15 files changed

Lines changed: 973 additions & 944 deletions

File tree

crates/luars/src/gc/gc_object.rs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -483,24 +483,30 @@ impl GcObjectPtr {
483483
const PTR_MASK: u64 = (1u64 << 48) - 1; // low 48 bits
484484

485485
// Tag values — must match GcObjectKind repr(u8)
486-
const TAG_STRING: u64 = 0;
487-
const TAG_TABLE: u64 = 1;
488-
const TAG_FUNCTION: u64 = 2;
489-
const TAG_CCLOSURE: u64 = 3;
490-
const TAG_RCLOSURE: u64 = 4;
491-
const TAG_UPVALUE: u64 = 5;
492-
const TAG_THREAD: u64 = 6;
493-
const TAG_USERDATA: u64 = 7;
494-
const TAG_PROTO: u64 = 8;
495-
#[inline(always)]
496-
fn new_tagged(ptr: u64, tag: u64) -> Self {
486+
pub const TAG_STRING: u64 = 0;
487+
pub const TAG_TABLE: u64 = 1;
488+
pub const TAG_FUNCTION: u64 = 2;
489+
pub const TAG_CCLOSURE: u64 = 3;
490+
pub const TAG_RCLOSURE: u64 = 4;
491+
pub const TAG_UPVALUE: u64 = 5;
492+
pub const TAG_THREAD: u64 = 6;
493+
pub const TAG_USERDATA: u64 = 7;
494+
pub const TAG_PROTO: u64 = 8;
495+
pub const TAG_NONE: u64 = 9;
496+
#[inline(always)]
497+
pub fn new_tagged(ptr: u64, tag: u64) -> Self {
497498
debug_assert!(
498499
ptr & !Self::PTR_MASK == 0,
499500
"pointer exceeds 48 bits: 0x{ptr:016x}"
500501
);
501502
Self(ptr | (tag << Self::TAG_SHIFT))
502503
}
503504

505+
#[inline(always)]
506+
pub fn null() -> Self {
507+
Self(0)
508+
}
509+
504510
#[inline(always)]
505511
fn tag(&self) -> u8 {
506512
(self.0 >> Self::TAG_SHIFT) as u8

crates/luars/src/gc/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ impl GC {
399399
#[inline]
400400
fn prepare_object_for_release(obj: &mut GcObjectOwner) {
401401
if let Some(thread) = obj.as_thread_mut() {
402-
thread.release();
402+
thread.release_ci();
403403
}
404404
}
405405

crates/luars/src/lua_value/lua_table/native_table.rs

Lines changed: 8 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ impl NativeTable {
265265
/// Zero-copy short string lookup — writes directly to destination pointer.
266266
/// Assumes hash is non-empty and key is short string.
267267
/// Returns true if found and written.
268-
pub unsafe fn get_shortstr_into(&self, key: &LuaValue, dest: *mut LuaValue) -> bool {
268+
pub(crate) fn get_shortstr_into(&self, key: &LuaValue, dest: *mut LuaValue) -> bool {
269269
let mut node = self.mainposition_string(key);
270270
let key_ptr = key.string_ptr_raw();
271271

@@ -388,7 +388,7 @@ impl NativeTable {
388388
self.pset_shortstr_parts(key, value.value, value.tt)
389389
}
390390

391-
pub fn pset_shortstr_parts(
391+
pub(crate) fn pset_shortstr_parts(
392392
&mut self,
393393
key: &LuaValue,
394394
value: Value,
@@ -538,19 +538,6 @@ impl NativeTable {
538538
}
539539
}
540540

541-
pub fn finish_shortstr_set_parts(
542-
&mut self,
543-
key: &LuaValue,
544-
value: Value,
545-
tt: u8,
546-
result: ShortStrSetResult,
547-
) -> (bool, isize) {
548-
match result {
549-
ShortStrSetResult::Done { new_key, mem_delta } => (new_key, mem_delta),
550-
other => self.finish_shortstr_set(key, LuaValue::from_raw(value, tt), other),
551-
}
552-
}
553-
554541
fn insert_new_shortstr(&mut self, key: &LuaValue, value: LuaValue) -> (bool, isize) {
555542
debug_assert!(key.is_short_string());
556543
debug_assert!(!value.is_nil());
@@ -673,7 +660,7 @@ impl NativeTable {
673660

674661
/// Write value to array at Lua index (1-based)
675662
#[inline(always)]
676-
pub unsafe fn write_array(&mut self, lua_index: i64, luaval: LuaValue) {
663+
pub(crate) fn write_array(&mut self, lua_index: i64, luaval: LuaValue) {
677664
if lua_index < 1 || lua_index > self.asize as i64 {
678665
return;
679666
}
@@ -1160,7 +1147,7 @@ impl NativeTable {
11601147
/// Returns true if a non-nil/non-empty value was found and written.
11611148
/// CRITICAL: #[inline(always)] — this is the hot path for t[i] reads.
11621149
#[inline(always)]
1163-
pub unsafe fn fast_geti_into(&self, key: i64, dest: *mut LuaValue) -> bool {
1150+
pub(crate) fn fast_geti_into(&self, key: i64, dest: *mut LuaValue) -> bool {
11641151
unsafe {
11651152
let u = (key as u64).wrapping_sub(1);
11661153
if u < self.asize as u64 {
@@ -1181,7 +1168,7 @@ impl NativeTable {
11811168
/// Used as fallback when fast_geti_into misses (key not in array range).
11821169
/// Mirrors C Lua's getintfromhash() + finishnodeget().
11831170
#[inline(always)]
1184-
pub unsafe fn get_int_from_hash_into(&self, key: i64, dest: *mut LuaValue) -> bool {
1171+
pub(crate) fn get_int_from_hash_into(&self, key: i64, dest: *mut LuaValue) -> bool {
11851172
if self.node.is_null() {
11861173
return false;
11871174
}
@@ -1431,9 +1418,7 @@ impl NativeTable {
14311418
}
14321419
// Move each key: write to array, remove from hash
14331420
for (k, v) in to_migrate {
1434-
unsafe {
1435-
self.write_array(k, v);
1436-
}
1421+
self.write_array(k, v);
14371422
let key_val = LuaValue::integer(k);
14381423
self.set_node(key_val, LuaValue::nil()); // mark dead in hash
14391424
}
@@ -1678,9 +1663,7 @@ impl NativeTable {
16781663
if i >= 1 && i <= self.asize as i64 {
16791664
// Key is in array range - set in array part ONLY
16801665
let was_nil = unsafe { self.read_array(i).is_none() };
1681-
unsafe {
1682-
self.write_array(i, value);
1683-
}
1666+
self.write_array(i, value);
16841667
// DEFENSIVE: If setting to nil, also clear any stale hash entry
16851668
// for this integer key. This can happen when GC clearing corrupted
16861669
// lenhint and a key was placed in both array and hash parts.
@@ -1700,9 +1683,7 @@ impl NativeTable {
17001683
if i == current_len + 1 {
17011684
let new_size = ((i as u32).next_power_of_two()).max(4);
17021685
let delta = self.resize_array(new_size);
1703-
unsafe {
1704-
self.write_array(i, value);
1705-
}
1686+
self.write_array(i, value);
17061687
self.migrate_hash_int_keys_to_array();
17071688
return (true, delta);
17081689
}

crates/luars/src/lua_value/lua_value.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,6 +1032,22 @@ impl LuaValue {
10321032
}
10331033
}
10341034

1035+
#[inline(always)]
1036+
pub(crate) fn as_gc_ptr_unchecked(&self) -> GcObjectPtr {
1037+
// Unsafe version for internal use when caller already knows it's a GC object
1038+
let tag = match self.tt {
1039+
LUA_VTABLE => GcObjectPtr::TAG_TABLE,
1040+
LUA_VFUNCTION => GcObjectPtr::TAG_FUNCTION,
1041+
LUA_CCLOSURE => GcObjectPtr::TAG_CCLOSURE,
1042+
LUA_VRCLOSURE => GcObjectPtr::TAG_RCLOSURE,
1043+
LUA_VSHRSTR | LUA_VLNGSTR => GcObjectPtr::TAG_STRING,
1044+
LUA_VTHREAD => GcObjectPtr::TAG_THREAD,
1045+
LUA_VUSERDATA => GcObjectPtr::TAG_USERDATA,
1046+
_ => GcObjectPtr::TAG_NONE,
1047+
};
1048+
GcObjectPtr::new_tagged(self.raw_ptr() as u64, tag)
1049+
}
1050+
10351051
// ============ Truthiness (Lua semantics) ============
10361052

10371053
/// l_isfalse - Lua truthiness: only nil and false are falsy

crates/luars/src/lua_value/mod.rs

Lines changed: 16 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,7 @@ pub(crate) type LuaInnerValue = Value; // For internal use within LuaValue imple
3030

3131
use crate::Instruction;
3232
use crate::gc::{ProtoPtr, UpvaluePtr};
33-
use crate::lua_vm::CFunction;
34-
35-
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
36-
pub struct LuaValuePtr {
37-
pub ptr: *mut LuaValue,
38-
}
33+
use crate::lua_vm::{CFunction, StkId};
3934

4035
/// Runtime upvalue — pointer-based design matching C Lua's UpVal.
4136
///
@@ -48,7 +43,7 @@ pub struct LuaValuePtr {
4843
pub struct LuaUpvalue {
4944
/// Always-valid pointer to the upvalue's current value.
5045
/// Open → stack slot, Closed → &self.closed_value
51-
v: *mut LuaValue,
46+
v: StkId,
5247
/// Storage for the closed value. When closed, `v` points here.
5348
closed_value: LuaValue,
5449
/// Stack index (only meaningful when open)
@@ -59,9 +54,9 @@ impl LuaUpvalue {
5954
/// Create an open upvalue pointing to a stack location (absolute index).
6055
/// `stack_ptr` must remain valid until the upvalue is closed or the pointer is updated.
6156
#[inline(always)]
62-
pub fn new_open(stack_index: usize, stack_ptr: LuaValuePtr) -> Self {
57+
pub fn new_open(stack_index: usize, stk_id: StkId) -> Self {
6358
LuaUpvalue {
64-
v: stack_ptr.ptr,
59+
v: stk_id,
6560
closed_value: LuaValue::nil(),
6661
stack_index,
6762
}
@@ -73,7 +68,7 @@ impl LuaUpvalue {
7368
#[inline(always)]
7469
pub fn new_closed(value: LuaValue) -> Self {
7570
LuaUpvalue {
76-
v: std::ptr::null_mut(),
71+
v: StkId::null(),
7772
closed_value: value,
7873
stack_index: 0,
7974
}
@@ -84,16 +79,16 @@ impl LuaUpvalue {
8479
/// No-op for open upvalues (where v is already a valid stack pointer).
8580
#[inline(always)]
8681
pub fn fix_closed_ptr(&mut self) {
87-
if self.v.is_null() {
88-
self.v = &mut self.closed_value as *mut LuaValue;
82+
if !self.v.is_valid() {
83+
self.v = StkId::from_mut_ptr(&mut self.closed_value as *mut LuaValue);
8984
}
9085
}
9186

9287
/// Check if this upvalue is open (like C Lua's `upisopen` macro).
9388
/// Open ⟺ `v` does NOT point to our own `closed_value` field.
9489
#[inline(always)]
9590
pub fn is_open(&self) -> bool {
96-
!std::ptr::eq(self.v, &self.closed_value)
91+
!std::ptr::eq(self.v.as_ptr(), &self.closed_value)
9792
}
9893

9994
/// Get the stack index (only meaningful when open).
@@ -107,101 +102,43 @@ impl LuaUpvalue {
107102
#[inline(always)]
108103
pub fn close(&mut self, stack_value: LuaValue) {
109104
self.closed_value = stack_value;
110-
self.v = &mut self.closed_value as *mut LuaValue;
105+
self.v = StkId::from_mut_ptr(&mut self.closed_value as *mut LuaValue);
111106
}
112107

113108
/// Update the cached stack pointer (called after stack reallocation).
114109
#[inline(always)]
115-
pub fn update_stack_ptr(&mut self, ptr: *mut LuaValue) {
116-
self.v = ptr;
110+
pub fn update_stack_ptr(&mut self, stk_id: StkId) {
111+
self.v = stk_id;
117112
}
118113

119114
/// Get the raw v pointer (for caching in the execute loop).
120115
#[inline(always)]
121-
pub fn get_v_ptr(&self) -> *mut LuaValue {
116+
pub fn get_v_stk_id(&self) -> StkId {
122117
self.v
123118
}
124119

125120
/// Get the value with **zero branching** — single pointer dereference.
126121
#[inline(always)]
127122
pub fn get_value(&self) -> LuaValue {
128-
debug_assert!(!self.v.is_null(), "upvalue get_value: null pointer");
129-
debug_assert!(
130-
(self.v as usize) > 0x10000,
131-
"upvalue get_value: suspiciously low pointer {:p} (stack_index={})",
132-
self.v,
133-
self.stack_index
134-
);
135-
let val = unsafe { *self.v };
136-
debug_assert!(
137-
Self::is_valid_tt(val.tt()),
138-
"upvalue get_value: INVALID type tag 0x{:02X} read from {:p} (stack_index={}, is_open={}). Likely dangling pointer!",
139-
val.tt(),
140-
self.v,
141-
self.stack_index,
142-
self.is_open()
143-
);
144-
val
123+
self.v.get()
145124
}
146125

147126
/// Get reference to the value with **zero branching**.
148127
#[inline(always)]
149128
pub fn get_value_ref(&self) -> &LuaValue {
150-
debug_assert!(!self.v.is_null(), "upvalue get_value_ref: null pointer");
151-
unsafe { &*self.v }
129+
self.v.get_ref()
152130
}
153131

154132
/// Set the value with **zero branching** — single pointer write.
155133
#[inline(always)]
156134
pub fn set_value(&mut self, val: LuaValue) {
157-
debug_assert!(!self.v.is_null(), "upvalue set_value: null pointer");
158-
debug_assert!(
159-
(self.v as usize) > 0x10000,
160-
"upvalue set_value: suspiciously low pointer {:p} (stack_index={})",
161-
self.v,
162-
self.stack_index
163-
);
164-
unsafe { *self.v = val }
135+
self.v.write(&val);
165136
}
166137

167138
/// Set the value by raw parts to avoid constructing a temporary LuaValue.
168139
#[inline(always)]
169140
pub fn set_value_parts(&mut self, value: Value, tt: u8) {
170-
debug_assert!(!self.v.is_null(), "upvalue set_value_parts: null pointer");
171-
debug_assert!(
172-
(self.v as usize) > 0x10000,
173-
"upvalue set_value_parts: suspiciously low pointer {:p} (stack_index={})",
174-
self.v,
175-
self.stack_index
176-
);
177-
unsafe {
178-
(*self.v).value = value;
179-
(*self.v).tt = tt;
180-
}
181-
}
182-
183-
/// Check if a type tag is valid (used for dangling pointer detection)
184-
fn is_valid_tt(tt: u8) -> bool {
185-
use crate::lua_value::lua_value::*;
186-
matches!(
187-
tt,
188-
LUA_VNIL
189-
| LUA_VEMPTY
190-
| LUA_VABSTKEY
191-
| LUA_VFALSE
192-
| LUA_VTRUE
193-
| LUA_VNUMINT
194-
| LUA_VNUMFLT
195-
| LUA_VSHRSTR
196-
| LUA_VLNGSTR
197-
| LUA_VTABLE
198-
| LUA_VFUNCTION
199-
| LUA_CCLOSURE
200-
| LUA_VLCF
201-
| LUA_VLIGHTUSERDATA
202-
| LUA_VUSERDATA
203-
| LUA_VTHREAD
204-
)
141+
self.v.write_parts(tt, value);
205142
}
206143

207144
pub fn get_closed_value(&self) -> Option<&LuaValue> {

0 commit comments

Comments
 (0)