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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user