feat: add drop specialization and ownership transfer optimizations

Phase B Performance Optimizations:

Drop Specialization:
- Add specialized decref functions: lux_decref_list, lux_decref_closure,
  lux_decref_string, lux_decref_boxed
- Inline drop logic eliminates polymorphic dispatch through lux_drop
- Forward type declarations (typedef struct X_s X) for proper C ordering

Ownership Transfer (Last-Use Optimization):
- Track variable types in var_types HashMap for type inference
- When assigning let b = a where a is RC-tracked:
  - Unregister source variable from RC cleanup
  - Register destination variable instead
- Prevents double-free and eliminates unnecessary incref/decref pairs

Also:
- Fix type inference for variable references in infer_expr_type
- Add is_rc_tracked() and unregister_rc_var() helper functions
- Update REFERENCE_COUNTING.md with Phase B progress

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-14 14:33:50 -05:00
parent 0c4b4e8fd0
commit 3a22ae089f
2 changed files with 193 additions and 37 deletions

View File

@@ -119,6 +119,8 @@ pub struct CBackend {
next_adt_tag: i32,
/// ADT types that have pointer fields (need drop functions)
adt_with_pointers: HashSet<String>,
/// Variable types for type inference (variable name -> C type)
var_types: HashMap<String, String>,
}
impl CBackend {
@@ -143,6 +145,7 @@ impl CBackend {
adt_type_tags: HashMap::new(),
next_adt_tag: 100, // ADT tags start at 100
adt_with_pointers: HashSet::new(),
var_types: HashMap::new(),
}
}
@@ -406,8 +409,12 @@ impl CBackend {
self.writeln("typedef char* LuxString;");
self.writeln("typedef void* LuxUnit;");
self.writeln("");
self.writeln("// Forward struct declarations for drop specialization");
self.writeln("typedef struct LuxList_s LuxList;");
self.writeln("typedef struct LuxClosure_s LuxClosure;");
self.writeln("");
self.writeln("// Closure representation: env pointer + function pointer");
self.writeln("typedef struct { void* env; void* fn_ptr; } LuxClosure;");
self.writeln("struct LuxClosure_s { void* env; void* fn_ptr; };");
self.writeln("");
self.writeln("// === Reference Counting Infrastructure ===");
self.writeln("// Perceus-inspired RC system for automatic memory management.");
@@ -464,7 +471,7 @@ impl CBackend {
self.writeln(" if (ptr) LUX_RC_HEADER(ptr)->rc++;");
self.writeln("}");
self.writeln("");
self.writeln("// Decrement reference count, call drop if zero");
self.writeln("// Decrement reference count, call drop if zero (generic)");
self.writeln("static inline void lux_decref(void* ptr) {");
self.writeln(" if (ptr) {");
self.writeln(" LuxRcHeader* hdr = LUX_RC_HEADER(ptr);");
@@ -474,6 +481,15 @@ impl CBackend {
self.writeln(" }");
self.writeln("}");
self.writeln("");
// Forward declarations for specialized decref functions (defined after struct bodies)
self.writeln("// Forward declarations for drop specialization (defined after struct bodies)");
self.writeln("static inline void lux_decref_list(LuxList* list);");
self.writeln("static inline void lux_decref_closure(LuxClosure* closure);");
self.writeln("static inline void lux_decref_string(LuxString str);");
self.writeln("static inline void lux_decref_boxed(void* ptr);");
self.writeln("");
self.writeln("// Get current reference count (for debugging)");
self.writeln("static inline int32_t lux_refcount(void* ptr) {");
self.writeln(" return ptr ? LUX_RC_HEADER(ptr)->rc : 0;");
@@ -977,17 +993,22 @@ impl CBackend {
self.writeln("");
self.writeln("// === List Types ===");
self.writeln("");
self.writeln("typedef struct {");
self.writeln("// LuxList struct body (typedef declared earlier for drop specialization)");
self.writeln("struct LuxList_s {");
self.writeln(" void** elements;");
self.writeln(" int64_t length;");
self.writeln(" int64_t capacity;");
self.writeln("} LuxList;");
self.writeln("};");
self.writeln("");
self.writeln("// Built-in Option type for List.head, List.tail, List.get, List.find");
self.writeln("typedef enum { Option_TAG_NONE, Option_TAG_SOME } Option_Tag;");
self.writeln("typedef struct { void* field0; } Option_Some_Data;");
self.writeln("typedef struct { Option_Tag tag; union { Option_Some_Data some; } data; } Option;");
self.writeln("");
// Emit specialized decref implementations (now that types are defined)
self.emit_specialized_decref_implementations();
self.writeln("// === List Operations ===");
self.writeln("// All lists are RC-managed. Elements are also RC-managed.");
self.writeln("");
@@ -1154,6 +1175,76 @@ impl CBackend {
self.writeln("");
}
/// Emit specialized decref implementations (must be called after type definitions)
fn emit_specialized_decref_implementations(&mut self) {
self.writeln("// === Specialized Decref Implementations (Drop Specialization) ===");
self.writeln("// These avoid the polymorphic lux_drop dispatch when type is known");
self.writeln("");
self.writeln("// Specialized decref for lists - inline drop logic");
self.writeln("static inline void lux_decref_list(LuxList* list) {");
self.writeln(" if (list) {");
self.writeln(" LuxRcHeader* hdr = LUX_RC_HEADER(list);");
self.writeln(" if (--hdr->rc == 0) {");
self.writeln(" // Inline list drop - decref each element");
self.writeln(" for (int64_t i = 0; i < list->length; i++) {");
self.writeln(" lux_decref(list->elements[i]);");
self.writeln(" }");
self.writeln(" free(list->elements);");
if self.debug_rc {
self.writeln(" lux_rc_free_count++;");
}
self.writeln(" free(hdr);");
self.writeln(" }");
self.writeln(" }");
self.writeln("}");
self.writeln("");
self.writeln("// Specialized decref for closures - inline drop logic");
self.writeln("static inline void lux_decref_closure(LuxClosure* closure) {");
self.writeln(" if (closure) {");
self.writeln(" LuxRcHeader* hdr = LUX_RC_HEADER(closure);");
self.writeln(" if (--hdr->rc == 0) {");
self.writeln(" // Inline closure drop - decref environment");
self.writeln(" lux_decref(closure->env);");
if self.debug_rc {
self.writeln(" lux_rc_free_count++;");
}
self.writeln(" free(hdr);");
self.writeln(" }");
self.writeln(" }");
self.writeln("}");
self.writeln("");
self.writeln("// Specialized decref for strings - no sub-references");
self.writeln("static inline void lux_decref_string(LuxString str) {");
self.writeln(" if (str) {");
self.writeln(" LuxRcHeader* hdr = LUX_RC_HEADER(str);");
self.writeln(" if (--hdr->rc == 0) {");
if self.debug_rc {
self.writeln(" lux_rc_free_count++;");
}
self.writeln(" free(hdr);");
self.writeln(" }");
self.writeln(" }");
self.writeln("}");
self.writeln("");
self.writeln("// Specialized decref for boxed primitives - no sub-references");
self.writeln("static inline void lux_decref_boxed(void* ptr) {");
self.writeln(" if (ptr) {");
self.writeln(" LuxRcHeader* hdr = LUX_RC_HEADER(ptr);");
self.writeln(" if (--hdr->rc == 0) {");
if self.debug_rc {
self.writeln(" lux_rc_free_count++;");
}
self.writeln(" free(hdr);");
self.writeln(" }");
self.writeln(" }");
self.writeln("}");
self.writeln("");
}
fn collect_type(&mut self, _type_decl: &TypeDecl) -> Result<(), CGenError> {
// Collect type info for later emission
Ok(())
@@ -1871,6 +1962,19 @@ impl CBackend {
// First, infer type from value expression (before emitting)
let inferred_type = self.infer_expr_type(value);
// Check for ownership transfer: assigning from another variable
let source_var = if let Expr::Var(ident) = value {
let escaped_source = self.escape_c_keyword(&ident.name);
// Check if source is an RC-tracked variable
if self.is_rc_tracked(&escaped_source) {
Some(escaped_source)
} else {
None
}
} else {
None
};
let val = self.emit_expr(value)?;
// Determine final type
@@ -1884,8 +1988,16 @@ impl CBackend {
let escaped_name = self.escape_c_keyword(&name.name);
self.writeln(&format!("{} {} = {};", typ, escaped_name, val));
// Register RC variable if it creates a new RC value
if self.expr_creates_rc_value(value) {
// Record variable type for future inference
self.var_types.insert(escaped_name.clone(), typ.clone());
// Handle ownership transfer or RC registration
if let Some(source_name) = source_var {
// Ownership transfer: unregister source, register dest
self.unregister_rc_var(&source_name);
self.register_rc_var(&escaped_name, &typ);
} else if self.expr_creates_rc_value(value) {
// Register RC variable if it creates a new RC value
self.register_rc_var(&escaped_name, &typ);
} else if let Some(adt_name) = self.expr_creates_adt_with_pointers(value) {
// ADT with pointer fields - needs field cleanup at scope exit
@@ -2332,7 +2444,7 @@ impl CBackend {
self.writeln(&format!("{}->length = {}->length;", result_var, list));
// Decref the closure if it was a temporary (inline lambda)
if closure.starts_with("_closure_") {
self.writeln(&format!("lux_decref({});", closure));
self.writeln(&format!("lux_decref_closure({});", closure));
}
Ok(result_var)
@@ -2370,7 +2482,7 @@ impl CBackend {
self.writeln(&format!("{}->length = {};", result_var, count_var));
// Decref the closure if it was a temporary (inline lambda)
if closure.starts_with("_closure_") {
self.writeln(&format!("lux_decref({});", closure));
self.writeln(&format!("lux_decref_closure({});", closure));
}
Ok(result_var)
@@ -2398,7 +2510,7 @@ impl CBackend {
self.writeln("}");
// Decref the closure if it was a temporary (inline lambda)
if closure.starts_with("_closure_") {
self.writeln(&format!("lux_decref({});", closure));
self.writeln(&format!("lux_decref_closure({});", closure));
}
Ok(result_var)
@@ -2432,7 +2544,7 @@ impl CBackend {
self.writeln("}");
// Decref the closure if it was a temporary (inline lambda)
if closure.starts_with("_closure_") {
self.writeln(&format!("lux_decref({});", closure));
self.writeln(&format!("lux_decref_closure({});", closure));
}
Ok(result_var)
@@ -2464,7 +2576,7 @@ impl CBackend {
self.writeln("}");
// Decref the closure if it was a temporary (inline lambda)
if closure.starts_with("_closure_") {
self.writeln(&format!("lux_decref({});", closure));
self.writeln(&format!("lux_decref_closure({});", closure));
}
Ok(result_var)
@@ -2496,7 +2608,7 @@ impl CBackend {
self.writeln("}");
// Decref the closure if it was a temporary (inline lambda)
if closure.starts_with("_closure_") {
self.writeln(&format!("lux_decref({});", closure));
self.writeln(&format!("lux_decref_closure({});", closure));
}
Ok(result_var)
@@ -2603,7 +2715,9 @@ impl CBackend {
if let Some(type_name) = self.variant_to_type.get(&ident.name) {
Some(type_name.clone())
} else {
None
// Check if we know the variable's type
let escaped = self.escape_c_keyword(&ident.name);
self.var_types.get(&escaped).cloned()
}
}
Expr::Call { func, .. } => {
@@ -2961,13 +3075,37 @@ impl CBackend {
// ADT with pointer fields - need to decref the fields
self.emit_adt_field_cleanup(&var.name, adt_name, &variant_field_types);
} else {
// Regular RC variable - just decref
self.writeln(&format!("lux_decref({});", var.name));
// Use specialized decref based on type (drop specialization)
self.emit_specialized_decref(&var.name, &var.c_type);
}
}
}
}
/// Emit a specialized decref call based on the known type (drop specialization)
/// This avoids the polymorphic lux_drop dispatch when we know the type at compile time
fn emit_specialized_decref(&mut self, var_name: &str, c_type: &str) {
match c_type {
"LuxList*" => {
self.writeln(&format!("lux_decref_list({});", var_name));
}
"LuxClosure*" => {
self.writeln(&format!("lux_decref_closure({});", var_name));
}
"LuxString" => {
self.writeln(&format!("lux_decref_string({});", var_name));
}
// Boxed primitives
"void*" => {
self.writeln(&format!("lux_decref_boxed({});", var_name));
}
// Fall back to generic decref for unknown types
_ => {
self.writeln(&format!("lux_decref({});", var_name));
}
}
}
/// Emit cleanup code for an ADT variable's pointer fields
fn emit_adt_field_cleanup(&mut self, var_name: &str, adt_name: &str, variant_field_types: &HashMap<(String, String), Vec<String>>) {
// Find all variants of this ADT with pointer fields
@@ -3022,6 +3160,18 @@ impl CBackend {
}
}
/// Check if a variable is tracked for RC cleanup in any scope
fn is_rc_tracked(&self, name: &str) -> bool {
self.rc_scopes.iter().any(|scope| scope.iter().any(|var| var.name == name))
}
/// Remove a variable from RC tracking (for ownership transfer)
fn unregister_rc_var(&mut self, name: &str) {
for scope in self.rc_scopes.iter_mut() {
scope.retain(|var| var.name != name);
}
}
/// Emit decrefs for all variables in all scopes (for early return)
fn emit_all_scope_cleanup(&mut self) {
// Collect all decrefs first to avoid borrow issues