From a186e5ad310df06f4458faeb56519b0ec64c1a54 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 17 Nov 2012 17:20:33 -0800 Subject: [PATCH] Garbage collection of DARRAY and CLASS objects. While we're at it, provide a stub class_new runtime. --- vvp/codes.h | 1 + vvp/compile.cc | 3 +- vvp/main.cc | 3 ++ vvp/vpi_darray.cc | 2 +- vvp/vthread.cc | 23 ++++++++---- vvp/vvp_net_sig.cc | 1 - vvp/vvp_object.cc | 7 ++++ vvp/vvp_object.h | 92 +++++++++++++++++++++++++++++++++++++++++++++- 8 files changed, 119 insertions(+), 13 deletions(-) diff --git a/vvp/codes.h b/vvp/codes.h index e415476f1..30a891b37 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -148,6 +148,7 @@ extern bool of_MUL_WR(vthread_t thr, vvp_code_t code); extern bool of_MULI(vthread_t thr, vvp_code_t code); extern bool of_NAND(vthread_t thr, vvp_code_t code); extern bool of_NANDR(vthread_t thr, vvp_code_t code); +extern bool of_NEW_COBJ(vthread_t thr, vvp_code_t code); extern bool of_NEW_DARRAY(vthread_t thr, vvp_code_t code); extern bool of_NOOP(vthread_t thr, vvp_code_t code); extern bool of_NOR(vthread_t thr, vvp_code_t code); diff --git a/vvp/compile.cc b/vvp/compile.cc index f65f42d8a..ff5aac013 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -196,7 +196,8 @@ static const struct opcode_table_s opcode_table[] = { { "%muli", of_MULI, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%nand", of_NAND, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%nand/r", of_NANDR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, - { "%new/darray",of_NEW_DARRAY,2,{OA_BIT1, OA_STRING, OA_NONE} }, + { "%new/cobj", of_NEW_COBJ, 0, {OA_NONE,OA_NONE, OA_NONE} }, + { "%new/darray",of_NEW_DARRAY,2, {OA_BIT1,OA_STRING, OA_NONE} }, { "%noop", of_NOOP, 0, {OA_NONE, OA_NONE, OA_NONE} }, { "%nor", of_NOR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%nor/r", of_NORR, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, diff --git a/vvp/main.cc b/vvp/main.cc index 5308e76ee..362044724 100644 --- a/vvp/main.cc +++ b/vvp/main.cc @@ -26,6 +26,7 @@ # include "vpi_priv.h" # include "statistics.h" # include "vvp_cleanup.h" +# include "vvp_object.h" # include # include # include @@ -197,6 +198,8 @@ void set_delay_selection(const char* sel) static void final_cleanup() { + vvp_object::cleanup(); + /* * We only need to cleanup the memory if we are checking with valgrind. */ diff --git a/vvp/vpi_darray.cc b/vvp/vpi_darray.cc index efe37a52f..4fade0e98 100644 --- a/vvp/vpi_darray.cc +++ b/vvp/vpi_darray.cc @@ -47,7 +47,7 @@ int __vpiDarrayVar::vpi_get(int code) vvp_fun_signal_object*fun = dynamic_cast (get_net()->fun); assert(fun); vvp_object_t val = fun->get_object(); - vvp_darray*aval = dynamic_cast (val); + vvp_darray*aval = val.peek(); switch (code) { case vpiSize: diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 7ed3f659b..b50590166 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -167,6 +167,7 @@ struct vthread_s { { assert(stack_obj_.size() > 0); vvp_object_t val = stack_obj_.back(); + stack_obj_.back().reset(); stack_obj_.pop_back(); return val; } @@ -2097,7 +2098,7 @@ bool of_DELETE_OBJ(vthread_t thr, vvp_code_t cp) { /* set the value into port 0 of the destination. */ vvp_net_ptr_t ptr (cp->net, 0); - vvp_send_object(ptr, 0, thr->wt_context); + vvp_send_object(ptr, vvp_object_t(), thr->wt_context); return true; } @@ -3193,7 +3194,7 @@ bool of_LOAD_DAR(vthread_t thr, vvp_code_t cp) vvp_fun_signal_object*obj = dynamic_cast (net->fun); assert(obj); - vvp_darray*darray = dynamic_cast(obj->get_object()); + vvp_darray*darray = obj->get_object().peek(); assert(darray); vvp_vector4_t word; @@ -3217,7 +3218,7 @@ bool of_LOAD_DAR_R(vthread_t thr, vvp_code_t cp) vvp_fun_signal_object*obj = dynamic_cast (net->fun); assert(obj); - vvp_darray*darray = dynamic_cast (obj->get_object()); + vvp_darray*darray = obj->get_object().peek(); assert(darray); double word; @@ -3236,7 +3237,7 @@ bool of_LOAD_DAR_STR(vthread_t thr, vvp_code_t cp) vvp_fun_signal_object*obj = dynamic_cast (net->fun); assert(obj); - vvp_darray*darray = dynamic_cast (obj->get_object()); + vvp_darray*darray = obj->get_object().peek(); assert(darray); string word; @@ -4066,6 +4067,12 @@ bool of_NAND(vthread_t thr, vvp_code_t cp) return cp->opcode(thr, cp); } +bool of_NEW_COBJ(vthread_t thr, vvp_code_t cp) +{ + vvp_object_t tmp; + thr->push_object(tmp); + return true; +} bool of_NEW_DARRAY(vthread_t thr, vvp_code_t cp) { @@ -4659,7 +4666,7 @@ bool of_SET_DAR(vthread_t thr, vvp_code_t cp) vvp_fun_signal_object*obj = dynamic_cast (net->fun); assert(obj); - vvp_darray*darray = dynamic_cast(obj->get_object()); + vvp_darray*darray = obj->get_object().peek(); assert(darray); darray->set_word(adr, value); @@ -4904,7 +4911,7 @@ bool of_STORE_DAR_R(vthread_t thr, vvp_code_t cp) vvp_fun_signal_object*obj = dynamic_cast (net->fun); assert(obj); - vvp_darray*darray = dynamic_cast(obj->get_object()); + vvp_darray*darray = obj->get_object().peek(); assert(darray); darray->set_word(adr, value); @@ -4927,7 +4934,7 @@ bool of_STORE_DAR_STR(vthread_t thr, vvp_code_t cp) vvp_fun_signal_object*obj = dynamic_cast (net->fun); assert(obj); - vvp_darray*darray = dynamic_cast(obj->get_object()); + vvp_darray*darray = obj->get_object().peek(); assert(darray); darray->set_word(adr, value); @@ -5119,7 +5126,7 @@ bool of_TEST_NUL(vthread_t thr, vvp_code_t cp) vvp_fun_signal_object*obj = dynamic_cast (net->fun); assert(obj); - if (obj->get_object() == 0) + if (obj->get_object().test_nil()) thr_put_bit(thr, 4, BIT4_1); else thr_put_bit(thr, 4, BIT4_0); diff --git a/vvp/vvp_net_sig.cc b/vvp/vvp_net_sig.cc index 14ba31b96..eb20e7f61 100644 --- a/vvp/vvp_net_sig.cc +++ b/vvp/vvp_net_sig.cc @@ -691,7 +691,6 @@ void vvp_fun_signal_object_sa::recv_object(vvp_net_ptr_t ptr, vvp_object_t bit, assert(ptr.port() == 0); if (needs_init_ || value_ != bit) { - if (value_) delete value_; value_ = bit; needs_init_ = false; diff --git a/vvp/vvp_object.cc b/vvp/vvp_object.cc index 14562befa..964a0cde3 100644 --- a/vvp/vvp_object.cc +++ b/vvp/vvp_object.cc @@ -24,8 +24,15 @@ using namespace std; +int vvp_object::total_active_cnt_ = 0; + +void vvp_object::cleanup(void) +{ +} + vvp_object::~vvp_object() { + total_active_cnt_ -= 1; } vvp_darray::~vvp_darray() diff --git a/vvp/vvp_object.h b/vvp/vvp_object.h index b93127857..c3f2f2c9b 100644 --- a/vvp/vvp_object.h +++ b/vvp/vvp_object.h @@ -23,15 +23,103 @@ # include # include -typedef class vvp_object*vvp_object_t; class vvp_vector4_t; +class vvp_object_t; +/* + * A vvp_object is a garbage collected object such as a darray or + * class object. The vvp_object class is a virtual base class and not + * generally used directly. Instead, use the vvp_object_t object as a + * smart pointer. This makes garbage collection automatic. + */ class vvp_object { public: - inline vvp_object() { } + inline vvp_object() { total_active_cnt_ += 1; } virtual ~vvp_object() =0; + + static void cleanup(void); + + private: + friend class vvp_object_t; + int ref_cnt_; + + static int total_active_cnt_; }; +class vvp_object_t { + public: + inline vvp_object_t() : ref_(0) { } + vvp_object_t(const vvp_object_t&that); + ~vvp_object_t(); + + vvp_object_t& operator = (const vvp_object_t&that); + vvp_object_t& operator = (class vvp_object*that); + + void reset(vvp_object*tgt = 0); + + bool test_nil() const { return ref_ == 0; } + inline bool operator == (const vvp_object_t&that) const + { return ref_ == that.ref_; } + inline bool operator != (const vvp_object_t&that) const + { return ref_ != that.ref_; } + + template T*peek(void) const; + + private: + class vvp_object*ref_; +}; + +inline vvp_object_t::vvp_object_t(const vvp_object_t&that) +{ + ref_ = that.ref_; + if (ref_) ref_->ref_cnt_ += 1; +} + +inline vvp_object_t::~vvp_object_t() +{ + reset(0); +} + +/* + * This is the workhorse of the vvp_object_t class. It manages the + * pointer to the referenced object. + */ +inline void vvp_object_t::reset(class vvp_object*tgt) +{ + if (tgt) tgt->ref_cnt_ += 1; + if (ref_) { + ref_->ref_cnt_ -= 1; + if (ref_->ref_cnt_ <= 0) delete ref_; + ref_ = 0; + } + ref_ = tgt; +} + +inline vvp_object_t& vvp_object_t::operator = (const vvp_object_t&that) +{ + if (this == &that) return *this; + reset(that.ref_); + return *this; +} + +inline vvp_object_t& vvp_object_t::operator = (class vvp_object*that) +{ + reset(that); + return *this; +} + +/* + * This peeks at the actual pointer value in the form of a derived + * class. It uses dynamic_cast<>() to convert the pointer to the + * desired type. + * + * NOTE: The vvp_object_t object retains ownership of the pointer! + */ +template inline T*vvp_object_t::peek(void) const +{ + return dynamic_cast (ref_); +} + class vvp_darray : public vvp_object { public: