Skip to content

Commit

Permalink
fixed memory management for overloaded ops
Browse files Browse the repository at this point in the history
  • Loading branch information
gewang committed Oct 29, 2023
1 parent b9caca9 commit 1374546
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 4 deletions.
6 changes: 5 additions & 1 deletion VERSIONS
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@
ChucK VERSIONS log
------------------

1.5.1.8 (October 2023)
1.5.1.8 (October 2023) patch release
=======
- (fixed) an issue with memory management / reference counting across
overloaded operations that return Object
- (fixed) an issue with reference count cleanup on recursive functions
that return Objects
- (fixed) an issue with reference count cleanup on 'new' operator,
e.g., (new Foo).f();
- (updated) reduced memory management between language-defined objects
and their parent shreds
- (updated) --color:ON and --color now will always output ANSI color
codes, regardless of TTY status; (FYI --color:AUTO is unchanged
and is the same as default, i.e., enable color terminal if TTY
Expand Down
63 changes: 60 additions & 3 deletions src/core/chuck_emit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3073,6 +3073,36 @@ t_CKBOOL emit_engine_emit_op( Chuck_Emitter * emit, ae_Operator op, a_Exp lhs, a



//-----------------------------------------------------------------------------
// name: emit_engine_emit_stmt_remember_object() | 1.5.1.8
// desc: as needed (if type is Object), emit a Stmt_Remember_Object instruction
// assuming that the greater Stmt_Start to Stmt_Cleanup mechanism is
// handled correctly elsewhere
//-----------------------------------------------------------------------------
t_CKBOOL emit_engine_emit_stmt_remember_object( Chuck_Emitter * emit, Chuck_Type * type )
{
// if the function returns an Object
if( !isobj( emit->env, type ) )
return FALSE;

// the return needs to be released (later at the end of the stmt that contains this)
Chuck_Instr_Stmt_Start * onStack = emit->stmt_stack.size() ? emit->stmt_stack.back() : NULL;
// check it
if( onStack )
{
t_CKUINT offset = 0;
// acquire next offset
if( !onStack->nextOffset( offset ) ) return FALSE;
// append instruction
emit->append( new Chuck_Instr_Stmt_Remember_Object( onStack, offset ) );
}

return TRUE;
}




//-----------------------------------------------------------------------------
// name: emit_engine_emit_op_overload_binary() | 1.5.1.5 (ge) added
// desc: emit binary operator overload
Expand All @@ -3083,7 +3113,16 @@ t_CKBOOL emit_engine_emit_op_overload_binary( Chuck_Emitter * emit, a_Exp_Binary
// push function pointer
emit->append( new Chuck_Instr_Reg_Push_Imm( (t_CKUINT)binary->ck_overload_func ) );
// emit the function call
return emit_engine_emit_exp_func_call( emit, binary->ck_overload_func, binary->self->type, binary->line, binary->where );
if( !emit_engine_emit_exp_func_call( emit, binary->ck_overload_func, binary->self->type, binary->line, binary->where ) )
return FALSE;

// return type
Chuck_Type * rtype = binary->ck_overload_func->type();
// emit remember instr | 1.5.1.8
if( isobj( emit->env, rtype ) ) emit_engine_emit_stmt_remember_object( emit, rtype );

// done
return TRUE;
}


Expand All @@ -3099,7 +3138,16 @@ t_CKBOOL emit_engine_emit_op_overload_unary( Chuck_Emitter * emit, a_Exp_Unary u
// push function pointer
emit->append( new Chuck_Instr_Reg_Push_Imm( (t_CKUINT)unary->ck_overload_func ) );
// emit the function call
return emit_engine_emit_exp_func_call( emit, unary->ck_overload_func, unary->self->type, unary->line, unary->where );
if( !emit_engine_emit_exp_func_call( emit, unary->ck_overload_func, unary->self->type, unary->line, unary->where ) )
return FALSE;

// return type
Chuck_Type * rtype = unary->ck_overload_func->type();
// emit remember instr | 1.5.1.8
if( isobj( emit->env, rtype ) ) emit_engine_emit_stmt_remember_object( emit, rtype );

// done
return TRUE;
}


Expand All @@ -3115,7 +3163,16 @@ t_CKBOOL emit_engine_emit_op_overload_postfix( Chuck_Emitter * emit, a_Exp_Postf
// push function pointer
emit->append( new Chuck_Instr_Reg_Push_Imm( (t_CKUINT)postfix->ck_overload_func ) );
// emit the function call
return emit_engine_emit_exp_func_call( emit, postfix->ck_overload_func, postfix->self->type, postfix->line, postfix->where );
if( !emit_engine_emit_exp_func_call( emit, postfix->ck_overload_func, postfix->self->type, postfix->line, postfix->where ) )
return FALSE;

// return type
Chuck_Type * rtype = postfix->ck_overload_func->type();
// emit remember instr | 1.5.1.8
if( isobj( emit->env, rtype ) ) emit_engine_emit_stmt_remember_object( emit, rtype );

// done
return TRUE;
}


Expand Down
27 changes: 27 additions & 0 deletions src/core/chuck_type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2471,6 +2471,15 @@ t_CKTYPE type_engine_check_op_overload_binary( Chuck_Env * env, ae_Operator op,
return NULL;
}

// get return type | 1.5.1.8 (ge & andrew) we are back
Chuck_Type * rtype = binary->ck_overload_func->type();
// check if return type is an Obj
if( rtype && isobj( env, rtype ) && env->stmt_stack.size() )
{
// increment # of objects in this stmt that needs release
env->stmt_stack.back()->numObjsToRelease++;
}

// the return type
return binary->ck_overload_func->type();
}
Expand Down Expand Up @@ -2506,6 +2515,15 @@ t_CKTYPE type_engine_check_op_overload_unary( Chuck_Env * env, ae_Operator op,
return NULL;
}

// get return type | 1.5.1.8 (ge & andrew) we are back
Chuck_Type * rtype = unary->ck_overload_func->type();
// check if return type is an Obj
if( rtype && isobj( env, rtype ) && env->stmt_stack.size() )
{
// increment # of objects in this stmt that needs release
env->stmt_stack.back()->numObjsToRelease++;
}

// the return type
return unary->ck_overload_func->type();
}
Expand Down Expand Up @@ -2541,6 +2559,15 @@ t_CKTYPE type_engine_check_op_overload_postfix( Chuck_Env * env, Chuck_Type * lh
return NULL;
}

// get return type | 1.5.1.8 (ge & andrew) we are back
Chuck_Type * rtype = postfix->ck_overload_func->type();
// check if return type is an Obj
if( rtype && isobj( env, rtype ) && env->stmt_stack.size() )
{
// increment # of objects in this stmt that needs release
env->stmt_stack.back()->numObjsToRelease++;
}

// the return type
return postfix->ck_overload_func->type();
}
Expand Down
50 changes: 50 additions & 0 deletions src/test/01-Basic/231-op-overload-refs.ck
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// verify that binary, unary-pre, and unary-post overloadings that
// return Objects are correctly ref-counted across op func calls

// let's say we define a custom class...
public class Foo { int num; }

// persistent operator overloading (trascends contexts)
// NOTE the use of 'public' instead of 'fun' -- it's fun for all!
public Foo @operator =^( Foo lhs, Foo rhs )
{ /* do stuff for Foo =^ Foo */ return rhs; }

// LOCAL binary operator overload for '=>' (local to this context)
fun Foo @operator =>( Foo lhs, Foo rhs )
{ /* do stuff for Foo => Foo */ return rhs; }

// define binary operator overload for '+'
fun Foo @operator +( Foo lhs, Foo rhs )
{ Foo retval; lhs.num + rhs.num => retval.num; return retval; }

// define binary operator overload for '*'
fun Foo @operator *( Foo lhs, Foo rhs )
{ Foo retval; lhs.num * rhs.num => retval.num; return retval; }

// define unary operator overload for '!'
fun int @operator !( Foo foo )
{ return !foo.num; }

// define postfix operator overload for '++'
fun Foo @operator ( Foo foo ) ++
{ foo.num++; return foo; }

//-----------------------------------------------------------
// using the new overloaded operators
//-----------------------------------------------------------
// create 2 Foos
Foo a, b; 1 => a.num; 2 => b.num;
// operator in action (follows default ck operator precedence)
a + b * b + a @=> Foo @ c; // note c is not a new instance
// post ++ on c
c++;
// another instance
Foo d;
// post ++ on d
d++;

// should print 1s
if( Machine.refcount(a) == 1 &&
Machine.refcount(b) == 1 &&
Machine.refcount(c) == 1 &&
Machine.refcount(d) == 1 ) <<< "success" >>>;

0 comments on commit 1374546

Please sign in to comment.