Browse Source

P3D_object needs to be reference-counted

David Rose 16 years ago
parent
commit
fbf81f90eb

+ 4 - 4
direct/src/plugin/p3dBoolObject.cxx

@@ -41,7 +41,7 @@ P3DBoolObject(const P3DBoolObject &copy) :
 //  Description: Returns the fundamental type of this kind of object.
 ////////////////////////////////////////////////////////////////////
 P3D_object_type P3DBoolObject::
-get_type() const {
+get_type() {
   return P3D_OT_bool;
 }
 
@@ -52,7 +52,7 @@ get_type() const {
 //               possible.
 ////////////////////////////////////////////////////////////////////
 bool P3DBoolObject::
-get_bool() const {
+get_bool() {
   return _value;
 }
 
@@ -63,7 +63,7 @@ get_bool() const {
 //               possible.
 ////////////////////////////////////////////////////////////////////
 int P3DBoolObject::
-get_int() const {
+get_int() {
   return _value;
 }
 
@@ -74,7 +74,7 @@ get_int() const {
 //               of this object coerced to a string.
 ////////////////////////////////////////////////////////////////////
 void P3DBoolObject::
-make_string(string &value) const {
+make_string(string &value) {
   if (_value) {
     value = "True";
   } else {

+ 4 - 4
direct/src/plugin/p3dBoolObject.h

@@ -28,10 +28,10 @@ public:
   P3DBoolObject(const P3DBoolObject &copy);
 
 public:
-  virtual P3D_object_type get_type() const;
-  virtual bool get_bool() const;
-  virtual int get_int() const;
-  virtual void make_string(string &value) const;
+  virtual P3D_object_type get_type();
+  virtual bool get_bool();
+  virtual int get_int();
+  virtual void make_string(string &value);
 
 private:
   bool _value;

+ 5 - 5
direct/src/plugin/p3dFloatObject.cxx

@@ -41,7 +41,7 @@ P3DFloatObject(const P3DFloatObject &copy) :
 //  Description: Returns the fundamental type of this kind of object.
 ////////////////////////////////////////////////////////////////////
 P3D_object_type P3DFloatObject::
-get_type() const {
+get_type() {
   return P3D_OT_float;
 }
 
@@ -52,7 +52,7 @@ get_type() const {
 //               possible.
 ////////////////////////////////////////////////////////////////////
 bool P3DFloatObject::
-get_bool() const {
+get_bool() {
   return (_value != 0.0);
 }
 
@@ -63,7 +63,7 @@ get_bool() const {
 //               possible.
 ////////////////////////////////////////////////////////////////////
 int P3DFloatObject::
-get_int() const {
+get_int() {
   return (int)_value;
 }
 
@@ -74,7 +74,7 @@ get_int() const {
 //               value, if possible.
 ////////////////////////////////////////////////////////////////////
 double P3DFloatObject::
-get_float() const {
+get_float() {
   return _value;
 }
 
@@ -85,7 +85,7 @@ get_float() const {
 //               of this object coerced to a string.
 ////////////////////////////////////////////////////////////////////
 void P3DFloatObject::
-make_string(string &value) const {
+make_string(string &value) {
   ostringstream strm;
   strm << _value;
   value = strm.str();

+ 5 - 5
direct/src/plugin/p3dFloatObject.h

@@ -28,11 +28,11 @@ public:
   P3DFloatObject(const P3DFloatObject &copy);
 
 public:
-  virtual P3D_object_type get_type() const;
-  virtual bool get_bool() const;
-  virtual int get_int() const;
-  virtual double get_float() const;
-  virtual void make_string(string &value) const;
+  virtual P3D_object_type get_type();
+  virtual bool get_bool();
+  virtual int get_int();
+  virtual double get_float();
+  virtual void make_string(string &value);
 
 private:
   double _value;

+ 43 - 15
direct/src/plugin/p3dInstance.cxx

@@ -73,9 +73,7 @@ P3DInstance::
 ~P3DInstance() {
   assert(_session == NULL);
 
-  if (_browser_script_object != NULL) {
-    P3D_OBJECT_FINISH(_browser_script_object);
-  }
+  P3D_OBJECT_XDECREF(_browser_script_object);
 
   DESTROY_LOCK(_request_lock);
 
@@ -118,6 +116,7 @@ set_fparams(const P3DFileParams &fparams) {
   strm << inst_mgr->get_unique_session_index();
   _session_key = strm.str();
 
+  // TODO.
   _python_version = "python24";
 
 
@@ -200,7 +199,8 @@ get_panda_script_object() const {
   }
 
   if (result == NULL) {
-    result = new P3DUndefinedObject;
+    P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
+    result = inst_mgr->new_undefined_object();
   }
 
   return result;
@@ -211,16 +211,18 @@ get_panda_script_object() const {
 //       Access: Public
 //  Description: Stores a pointer to the top-level window object
 //               of the browser, to be used by Panda code to control
-//               JavaScript.  Ownership of this object is passed into
-//               the instance.
+//               JavaScript.  The new object's reference count is
+//               incremented, and the previous object's is
+//               decremented.
 ////////////////////////////////////////////////////////////////////
 void P3DInstance::
 set_browser_script_object(P3D_object *browser_script_object) {
   if (browser_script_object != _browser_script_object) {
+    P3D_OBJECT_XDECREF(_browser_script_object);
+    _browser_script_object = browser_script_object;
     if (_browser_script_object != NULL) {
-      P3D_OBJECT_FINISH(_browser_script_object);
+      P3D_OBJECT_INCREF(_browser_script_object);
     }
-    _browser_script_object = browser_script_object;
 
     if (_session != NULL) {
       send_browser_script_object();
@@ -317,6 +319,36 @@ void P3DInstance::
 finish_request(P3D_request *request, bool handled) {
   assert(request != NULL);
 
+  switch (request->_request_type) {
+  case P3D_RT_stop:
+    break;
+
+  case P3D_RT_get_url:
+    free((char *)request->_request._get_url._url);
+    break;
+
+  case P3D_RT_post_url:
+    free((char *)request->_request._post_url._url);
+    free((char *)request->_request._post_url._post_data);
+    break;
+
+  case P3D_RT_notify:
+    free((char *)request->_request._notify._message);
+    break;
+
+  case P3D_RT_script:
+    {
+      P3D_OBJECT_DECREF(request->_request._script._object);
+      if (request->_request._script._property_name != NULL) {
+        free((char *)request->_request._script._property_name);
+      }
+      for (int i = 0; i < request->_request._script._num_values; ++i) {
+        P3D_OBJECT_DECREF(request->_request._script._values[i]);
+      }
+    }
+    break;
+  }
+
   delete request;
 }
 
@@ -519,7 +551,7 @@ handle_script_request(P3D_request *request) {
       doc->LinkEndChild(xcommand);
       if (result != NULL) {
         xcommand->LinkEndChild(_session->p3dobj_to_xml(result));
-        P3D_OBJECT_FINISH(result);
+        P3D_OBJECT_DECREF(result);
       }
 
       if (needs_response) {
@@ -598,10 +630,6 @@ handle_script_request(P3D_request *request) {
         P3D_OBJECT_CALL(object, request->_request._script._property_name,
                         request->_request._script._values,
                         request->_request._script._num_values);
-      // Reset the value count to 0 so we won't double-delete the
-      // parameter values when the request is deleted (the above call
-      // has already deleted them).
-      request->_request._script._num_values = 0;
 
       // Feed the result back down to the subprocess.
       TiXmlDocument *doc = new TiXmlDocument;
@@ -615,7 +643,7 @@ handle_script_request(P3D_request *request) {
 
       if (result != NULL) {
         xcommand->LinkEndChild(_session->p3dobj_to_xml(result));
-        P3D_OBJECT_FINISH(result);
+        P3D_OBJECT_DECREF(result);
       }
       
       if (needs_response) {
@@ -654,7 +682,7 @@ handle_script_request(P3D_request *request) {
 
       if (result != NULL) {
         xcommand->LinkEndChild(_session->p3dobj_to_xml(result));
-        P3D_OBJECT_FINISH(result);
+        P3D_OBJECT_DECREF(result);
       }
 
       logfile << "eval  response: " << *doc << "\n";

+ 37 - 0
direct/src/plugin/p3dInstanceManager.I

@@ -70,3 +70,40 @@ inline int P3DInstanceManager::
 get_num_instances() const {
   return _instances.size();
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstanceManager::new_undefined_object
+//       Access: Public
+//  Description: Returns the singleton "undefined" object, as a new
+//               reference.
+////////////////////////////////////////////////////////////////////
+inline P3D_object *P3DInstanceManager::
+new_undefined_object() {
+  P3D_OBJECT_INCREF(_undefined_object);
+  return _undefined_object;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstanceManager::new_none_object
+//       Access: Public
+//  Description: Returns the singleton "none" object, as a new
+//               reference.
+////////////////////////////////////////////////////////////////////
+inline P3D_object *P3DInstanceManager::
+new_none_object() {
+  P3D_OBJECT_INCREF(_none_object);
+  return _none_object;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstanceManager::new_bool_object
+//       Access: Public
+//  Description: Returns the singleton "true" or "false" object, as a
+//               new reference.
+////////////////////////////////////////////////////////////////////
+inline P3D_object *P3DInstanceManager::
+new_bool_object(bool value) {
+  P3D_object *obj = (value) ? _true_object : _false_object;
+  P3D_OBJECT_INCREF(obj);
+  return obj;
+}

+ 25 - 0
direct/src/plugin/p3dInstanceManager.cxx

@@ -18,6 +18,9 @@
 #include "p3dPackage.h"
 #include "p3d_plugin_config.h"
 #include "p3dWinSplashWindow.h"
+#include "p3dUndefinedObject.h"
+#include "p3dNoneObject.h"
+#include "p3dBoolObject.h"
 #include "find_root_dir.h"
 #include "mkdir_complete.h"
 
@@ -43,6 +46,12 @@ P3DInstanceManager() {
   _started_notify_thread = false;
   INIT_THREAD(_notify_thread);
 
+  // Initialize the singleton objects.
+  _undefined_object = new P3DUndefinedObject();
+  _none_object = new P3DNoneObject();
+  _true_object = new P3DBoolObject(true);
+  _false_object = new P3DBoolObject(false);
+
 #ifdef _WIN32
   // Ensure the appropriate Windows common controls are available to
   // this application.
@@ -72,6 +81,22 @@ P3DInstanceManager::
   assert(_instances.empty());
   assert(_sessions.empty());
 
+  nout << "counts: " << _undefined_object->_ref_count
+       << " " << _none_object->_ref_count
+       << " " << _true_object->_ref_count
+       << " " << _false_object->_ref_count
+       << "\n" << flush;
+
+  assert(_undefined_object->_ref_count == 1);
+  assert(_none_object->_ref_count == 1);
+  assert(_true_object->_ref_count == 1);
+  assert(_false_object->_ref_count == 1);
+
+  P3D_OBJECT_DECREF(_undefined_object);
+  P3D_OBJECT_DECREF(_none_object);
+  P3D_OBJECT_DECREF(_true_object);
+  P3D_OBJECT_DECREF(_false_object);
+
 #ifdef _WIN32
   P3DWinSplashWindow::unregister_window_class();
 #endif

+ 9 - 0
direct/src/plugin/p3dInstanceManager.h

@@ -66,6 +66,10 @@ public:
 
   P3D_class_definition *make_class_definition() const;
 
+  inline P3D_object *new_undefined_object();
+  inline P3D_object *new_none_object();
+  inline P3D_object *new_bool_object(bool value);
+
   static P3DInstanceManager *get_global_ptr();
   static void delete_global_ptr();
 
@@ -82,6 +86,11 @@ private:
   string _download_url;
   string _platform;
 
+  P3D_object *_undefined_object;
+  P3D_object *_none_object;
+  P3D_object *_true_object;
+  P3D_object *_false_object;
+
   typedef set<P3DInstance *> Instances;
   Instances _instances;
 

+ 4 - 4
direct/src/plugin/p3dIntObject.cxx

@@ -41,7 +41,7 @@ P3DIntObject(const P3DIntObject &copy) :
 //  Description: Returns the fundamental type of this kind of object.
 ////////////////////////////////////////////////////////////////////
 P3D_object_type P3DIntObject::
-get_type() const {
+get_type() {
   return P3D_OT_int;
 }
 
@@ -52,7 +52,7 @@ get_type() const {
 //               possible.
 ////////////////////////////////////////////////////////////////////
 bool P3DIntObject::
-get_bool() const {
+get_bool() {
   return (_value != 0);
 }
 
@@ -63,7 +63,7 @@ get_bool() const {
 //               possible.
 ////////////////////////////////////////////////////////////////////
 int P3DIntObject::
-get_int() const {
+get_int() {
   return _value;
 }
 
@@ -74,7 +74,7 @@ get_int() const {
 //               of this object coerced to a string.
 ////////////////////////////////////////////////////////////////////
 void P3DIntObject::
-make_string(string &value) const {
+make_string(string &value) {
   ostringstream strm;
   strm << _value;
   value = strm.str();

+ 4 - 4
direct/src/plugin/p3dIntObject.h

@@ -28,10 +28,10 @@ public:
   P3DIntObject(const P3DIntObject &copy);
 
 public:
-  virtual P3D_object_type get_type() const;
-  virtual bool get_bool() const;
-  virtual int get_int() const;
-  virtual void make_string(string &value) const;
+  virtual P3D_object_type get_type();
+  virtual bool get_bool();
+  virtual int get_int();
+  virtual void make_string(string &value);
 
 private:
   int _value;

+ 3 - 3
direct/src/plugin/p3dNoneObject.cxx

@@ -29,7 +29,7 @@ P3DNoneObject() {
 //  Description: Returns the fundamental type of this kind of object.
 ////////////////////////////////////////////////////////////////////
 P3D_object_type P3DNoneObject::
-get_type() const {
+get_type() {
   return P3D_OT_none;
 }
 
@@ -40,7 +40,7 @@ get_type() const {
 //               possible.
 ////////////////////////////////////////////////////////////////////
 bool P3DNoneObject::
-get_bool() const {
+get_bool() {
   return false;
 }
 
@@ -51,6 +51,6 @@ get_bool() const {
 //               of this object coerced to a string.
 ////////////////////////////////////////////////////////////////////
 void P3DNoneObject::
-make_string(string &value) const {
+make_string(string &value) {
   value = "None";
 }

+ 3 - 3
direct/src/plugin/p3dNoneObject.h

@@ -28,9 +28,9 @@ public:
   P3DNoneObject();
 
 public:
-  virtual P3D_object_type get_type() const;
-  virtual bool get_bool() const;
-  virtual void make_string(string &value) const;
+  virtual P3D_object_type get_type();
+  virtual bool get_bool();
+  virtual void make_string(string &value);
 };
 
 #endif

+ 0 - 36
direct/src/plugin/p3dObject.I

@@ -37,39 +37,3 @@ P3DObject(const P3DObject &copy) {
   _class = copy._class;
   _ref_count = 1;
 }
-
-////////////////////////////////////////////////////////////////////
-//     Function: P3DObject::ref
-//       Access: Public
-//  Description: Increments the reference count.
-////////////////////////////////////////////////////////////////////
-inline void P3DObject::
-ref() const {
-  ++(((P3DObject *)this)->_ref_count);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: P3DObject::unref
-//       Access: Public
-//  Description: Decrements the reference count, and returns the new
-//               count.
-////////////////////////////////////////////////////////////////////
-inline int P3DObject::
-unref() const {
-  --(((P3DObject *)this)->_ref_count);
-  return _ref_count;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: P3DObject::unref_delete
-//       Access: Public, Static
-//  Description: Decrements the reference count on the indicated
-//               object, and deletes it if the reference count reaches
-//               zero.
-////////////////////////////////////////////////////////////////////
-inline void P3DObject::
-unref_delete(P3DObject *obj) {
-  if (obj->unref() <= 0) {
-    delete obj;
-  }
-}

+ 42 - 80
direct/src/plugin/p3dObject.cxx

@@ -21,47 +21,42 @@
 // P3D_object structure.
 static void
 object_finish(P3D_object *object) {
-  P3DObject::unref_delete(((P3DObject *)object));
-}
-
-static P3D_object *
-object_copy(const P3D_object *object) {
-  return ((const P3DObject *)object)->make_copy();
+  delete (P3DObject *)object;
 }
 
 static P3D_object_type 
-object_get_type(const P3D_object *object) {
-  return ((const P3DObject *)object)->get_type();
+object_get_type(P3D_object *object) {
+  return ((P3DObject *)object)->get_type();
 }
 
 static bool 
-object_get_bool(const P3D_object *object) {
-  return ((const P3DObject *)object)->get_bool();
+object_get_bool(P3D_object *object) {
+  return ((P3DObject *)object)->get_bool();
 }
 
 static int
-object_get_int(const P3D_object *object) {
-  return ((const P3DObject *)object)->get_int();
+object_get_int(P3D_object *object) {
+  return ((P3DObject *)object)->get_int();
 }
 
 static double 
-object_get_float(const P3D_object *object) {
-  return ((const P3DObject *)object)->get_float();
+object_get_float(P3D_object *object) {
+  return ((P3DObject *)object)->get_float();
 }
 
 static int 
-object_get_string(const P3D_object *object, char *buffer, int buffer_length) {
-  return ((const P3DObject *)object)->get_string(buffer, buffer_length);
+object_get_string(P3D_object *object, char *buffer, int buffer_length) {
+  return ((P3DObject *)object)->get_string(buffer, buffer_length);
 }
 
 static int 
-object_get_repr(const P3D_object *object, char *buffer, int buffer_length) {
-  return ((const P3DObject *)object)->get_repr(buffer, buffer_length);
+object_get_repr(P3D_object *object, char *buffer, int buffer_length) {
+  return ((P3DObject *)object)->get_repr(buffer, buffer_length);
 }
 
 static P3D_object *
-object_get_property(const P3D_object *object, const char *property) {
-  return ((const P3DObject *)object)->get_property(property);
+object_get_property(P3D_object *object, const char *property) {
+  return ((P3DObject *)object)->get_property(property);
 }
 
 static bool
@@ -71,27 +66,26 @@ object_set_property(P3D_object *object, const char *property,
 }
 
 static bool
-object_has_method(const P3D_object *object, const char *method_name) {
-  return ((const P3DObject *)object)->has_method(method_name);
+object_has_method(P3D_object *object, const char *method_name) {
+  return ((P3DObject *)object)->has_method(method_name);
 }
 
 static P3D_object *
-object_call(const P3D_object *object, const char *method_name,
+object_call(P3D_object *object, const char *method_name,
             P3D_object *params[], int num_params) {
   if (method_name == NULL) {
     method_name = "";
   }
-  return ((const P3DObject *)object)->call(method_name, params, num_params);
+  return ((P3DObject *)object)->call(method_name, params, num_params);
 }
 
 static P3D_object *
-object_eval(const P3D_object *object, const char *expression) {
-  return ((const P3DObject *)object)->eval(expression);
+object_eval(P3D_object *object, const char *expression) {
+  return ((P3DObject *)object)->eval(expression);
 }
 
 P3D_class_definition P3DObject::_object_class = {
   &object_finish,
-  &object_copy,
   &object_get_type,
   &object_get_bool,
   &object_get_int,
@@ -116,14 +110,8 @@ generic_finish(P3D_object *object) {
   nout << "Warning!  default object_finish() method does nothing; object will leak.\n" << flush;
 }
 
-static P3D_object *
-generic_copy(const P3D_object *object) {
-  nout << "Warning!  default object_copy() method does nothing; object pointer will be shared.\n" << flush;
-  return (P3D_object *)object;
-}
-
 static P3D_object_type 
-generic_get_type(const P3D_object *object) {
+generic_get_type(P3D_object *object) {
   // We assume anyone going through the trouble of subclassing this
   // will want to return an object, not one of the other fundamental
   // types.
@@ -131,66 +119,59 @@ generic_get_type(const P3D_object *object) {
 }
 
 static bool 
-generic_get_bool(const P3D_object *object) {
+generic_get_bool(P3D_object *object) {
   return false;
 }
 
 static int
-generic_get_int(const P3D_object *object) {
+generic_get_int(P3D_object *object) {
   return 0;
 }
 
 static double 
-generic_get_float(const P3D_object *object) {
+generic_get_float(P3D_object *object) {
   return 0.0;
 }
 
 static int 
-generic_get_string(const P3D_object *object, char *buffer, int buffer_length) {
+generic_get_string(P3D_object *object, char *buffer, int buffer_length) {
   return 0;
 }
 
 static int 
-generic_get_repr(const P3D_object *object, char *buffer, int buffer_length) {
+generic_get_repr(P3D_object *object, char *buffer, int buffer_length) {
   return 0;
 }
 
 static P3D_object *
-generic_get_property(const P3D_object *object, const char *property) {
+generic_get_property(P3D_object *object, const char *property) {
   return NULL;
 }
 
 static bool
 generic_set_property(P3D_object *object, const char *property,
                      P3D_object *value) {
-  if (value != NULL) {
-    P3D_OBJECT_FINISH(value);
-  }
   return false;
 }
 
 static bool
-generic_has_method(const P3D_object *object, const char *method_name) {
-  return ((const P3DObject *)object)->has_method(method_name);
+generic_has_method(P3D_object *object, const char *method_name) {
+  return false;
 }
 
 static P3D_object *
-generic_call(const P3D_object *object, const char *method_name,
+generic_call(P3D_object *object, const char *method_name,
             P3D_object *params[], int num_params) {
-  for (int i = 0; i < num_params; ++i) {
-    P3D_OBJECT_FINISH(params[i]);
-  }
   return NULL;
 }
 
 static P3D_object *
-generic_eval(const P3D_object *object, const char *expression) {
+generic_eval(P3D_object *object, const char *expression) {
   return NULL;
 }
 
 P3D_class_definition P3DObject::_generic_class = {
   &generic_finish,
-  &generic_copy,
   &generic_get_type,
   &generic_get_bool,
   &generic_get_int,
@@ -211,20 +192,7 @@ P3D_class_definition P3DObject::_generic_class = {
 ////////////////////////////////////////////////////////////////////
 P3DObject::
 ~P3DObject() {
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: P3DObject::make_copy
-//       Access: Public, Virtual
-//  Description: Returns a new copy of the object, if necessary.  If
-//               the object type is static and all instances are
-//               identical, this actually simply ups the reference
-//               count and returns the same object.
-////////////////////////////////////////////////////////////////////
-P3DObject *P3DObject::
-make_copy() const {
-  ref();
-  return (P3DObject *)this;
+  assert(_ref_count == 0);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -234,7 +202,7 @@ make_copy() const {
 //               possible.
 ////////////////////////////////////////////////////////////////////
 int P3DObject::
-get_int() const {
+get_int() {
   return 0;
 }
 
@@ -245,7 +213,7 @@ get_int() const {
 //               value, if possible.
 ////////////////////////////////////////////////////////////////////
 double P3DObject::
-get_float() const {
+get_float() {
   return get_int();
 }
 
@@ -260,7 +228,7 @@ get_float() const {
 //               was too small).
 ////////////////////////////////////////////////////////////////////
 int P3DObject::
-get_string(char *buffer, int buffer_length) const {
+get_string(char *buffer, int buffer_length) {
   string result;
   make_string(result);
   strncpy(buffer, result.c_str(), buffer_length);
@@ -274,7 +242,7 @@ get_string(char *buffer, int buffer_length) const {
 //               similar to get_string(), above.
 ////////////////////////////////////////////////////////////////////
 int P3DObject::
-get_repr(char *buffer, int buffer_length) const {
+get_repr(char *buffer, int buffer_length) {
   ostringstream strm;
   output(strm);
   string result = strm.str();
@@ -290,7 +258,7 @@ get_repr(char *buffer, int buffer_length) const {
 //               that must be deleted by the caller, or NULL on error.
 ////////////////////////////////////////////////////////////////////
 P3D_object *P3DObject::
-get_property(const string &property) const {
+get_property(const string &property) {
   return NULL;
 }
 
@@ -303,9 +271,6 @@ get_property(const string &property) const {
 ////////////////////////////////////////////////////////////////////
 bool P3DObject::
 set_property(const string &property, P3D_object *value) {
-  if (value != NULL) {
-    P3D_OBJECT_FINISH(value);
-  }
   return false;
 }
 
@@ -316,7 +281,7 @@ set_property(const string &property, P3D_object *value) {
 //               object, false otherwise.
 ////////////////////////////////////////////////////////////////////
 bool P3DObject::
-has_method(const string &method_name) const {
+has_method(const string &method_name) {
   return false;
 }
 
@@ -329,10 +294,7 @@ has_method(const string &method_name) const {
 //               on success, NULL on error.
 ////////////////////////////////////////////////////////////////////
 P3D_object *P3DObject::
-call(const string &method_name, P3D_object *params[], int num_params) const {
-  for (int i = 0; i < num_params; ++i) {
-    P3D_OBJECT_FINISH(params[i]);
-  }
+call(const string &method_name, P3D_object *params[], int num_params) {
   return NULL;
 }
 
@@ -343,7 +305,7 @@ call(const string &method_name, P3D_object *params[], int num_params) const {
 //               of the P3DObject classes implement this.
 ////////////////////////////////////////////////////////////////////
 P3D_object *P3DObject::
-eval(const string &expression) const {
+eval(const string &expression) {
   return NULL;
 }
 
@@ -355,7 +317,7 @@ eval(const string &expression) const {
 //               assistance.
 ////////////////////////////////////////////////////////////////////
 void P3DObject::
-output(ostream &out) const {
+output(ostream &out) {
   string value;
   make_string(value);
   out << value;

+ 13 - 21
direct/src/plugin/p3dObject.h

@@ -33,32 +33,24 @@ protected:
 public:
   virtual ~P3DObject();
 
-  virtual P3DObject *make_copy() const; 
-  virtual P3D_object_type get_type() const=0;
-  virtual bool get_bool() const=0;
-  virtual int get_int() const;
-  virtual double get_float() const;
+  virtual P3D_object_type get_type()=0;
+  virtual bool get_bool()=0;
+  virtual int get_int();
+  virtual double get_float();
 
-  int get_string(char *buffer, int buffer_length) const;
-  int get_repr(char *buffer, int buffer_length) const;
-  virtual void make_string(string &value) const=0;
+  int get_string(char *buffer, int buffer_length);
+  int get_repr(char *buffer, int buffer_length);
+  virtual void make_string(string &value)=0;
 
-  virtual P3D_object *get_property(const string &property) const;
+  virtual P3D_object *get_property(const string &property);
   virtual bool set_property(const string &property, P3D_object *value);
 
-  virtual bool has_method(const string &method_name) const;
+  virtual bool has_method(const string &method_name);
   virtual P3D_object *call(const string &method_name, 
-                           P3D_object *params[], int num_params) const;
-  virtual P3D_object *eval(const string &expression) const;
+                           P3D_object *params[], int num_params);
+  virtual P3D_object *eval(const string &expression);
 
-  virtual void output(ostream &out) const;
-
-  inline void ref() const;
-  inline int unref() const;
-  static inline void unref_delete(P3DObject *obj);
-
-private:
-  int _ref_count;
+  virtual void output(ostream &out);
 
 public:
   static P3D_class_definition _object_class;
@@ -71,7 +63,7 @@ public:
 // virtual method to write the output simply.  (For classes that
 // inherit only from P3D_object, we have to use the generic C method
 // defined in p3d_plugin_common.h, a little clumsier.)
-inline ostream &operator << (ostream &out, const P3DObject &value) {
+inline ostream &operator << (ostream &out, P3DObject &value) {
   value.output(out);
   return out;
 }

+ 17 - 21
direct/src/plugin/p3dPythonObject.cxx

@@ -42,7 +42,7 @@ P3DPythonObject::
 //  Description: Returns the fundamental type of this kind of object.
 ////////////////////////////////////////////////////////////////////
 P3D_object_type P3DPythonObject::
-get_type() const {
+get_type() {
   return P3D_OT_object;
 }
 
@@ -53,13 +53,13 @@ get_type() const {
 //               possible.
 ////////////////////////////////////////////////////////////////////
 bool P3DPythonObject::
-get_bool() const {
+get_bool() {
   bool bresult = 0;
 
   P3D_object *result = call("__bool__", NULL, 0);
   if (result != NULL) {
     bresult = P3D_OBJECT_GET_BOOL(result);
-    P3D_OBJECT_FINISH(result);
+    P3D_OBJECT_DECREF(result);
   }    
 
   return bresult;
@@ -72,13 +72,13 @@ get_bool() const {
 //               possible.
 ////////////////////////////////////////////////////////////////////
 int P3DPythonObject::
-get_int() const {
+get_int() {
   int iresult = 0;
 
   P3D_object *result = call("__int__", NULL, 0);
   if (result != NULL) {
     iresult = P3D_OBJECT_GET_INT(result);
-    P3D_OBJECT_FINISH(result);
+    P3D_OBJECT_DECREF(result);
   }    
 
   return iresult;
@@ -91,13 +91,13 @@ get_int() const {
 //               value, if possible.
 ////////////////////////////////////////////////////////////////////
 double P3DPythonObject::
-get_float() const {
+get_float() {
   double fresult = 0.0;
 
   P3D_object *result = call("__float__", NULL, 0);
   if (result != NULL) {
     fresult = P3D_OBJECT_GET_FLOAT(result);
-    P3D_OBJECT_FINISH(result);
+    P3D_OBJECT_DECREF(result);
   }    
 
   return fresult;
@@ -110,7 +110,7 @@ get_float() const {
 //               of this object coerced to a string.
 ////////////////////////////////////////////////////////////////////
 void P3DPythonObject::
-make_string(string &value) const {
+make_string(string &value) {
   P3D_object *result = call("__str__", NULL, 0);
   if (result != NULL) {
     int size = P3D_OBJECT_GET_STRING(result, NULL, 0);
@@ -119,7 +119,7 @@ make_string(string &value) const {
     value = string(buffer, size);
     delete[] buffer;
 
-    P3D_OBJECT_FINISH(result);
+    P3D_OBJECT_DECREF(result);
   }    
 }
 
@@ -131,7 +131,7 @@ make_string(string &value) const {
 //               that must be deleted by the caller, or NULL on error.
 ////////////////////////////////////////////////////////////////////
 P3D_object *P3DPythonObject::
-get_property(const string &property) const {
+get_property(const string &property) {
   P3D_object *params[1];
   params[0] = new P3DStringObject(property);
 
@@ -167,7 +167,7 @@ set_property(const string &property, P3D_object *value) {
 
   if (result != NULL) {
     bresult = P3D_OBJECT_GET_BOOL(result);
-    P3D_OBJECT_FINISH(result);
+    P3D_OBJECT_DECREF(result);
   }
 
   return bresult;
@@ -180,7 +180,7 @@ set_property(const string &property, P3D_object *value) {
 //               object, false otherwise.
 ////////////////////////////////////////////////////////////////////
 bool P3DPythonObject::
-has_method(const string &method_name) const {
+has_method(const string &method_name) {
   bool bresult = false;
 
   P3D_object *params[1];
@@ -190,7 +190,7 @@ has_method(const string &method_name) const {
 
   if (result != NULL) {
     bresult = P3D_OBJECT_GET_BOOL(result);
-    P3D_OBJECT_FINISH(result);
+    P3D_OBJECT_DECREF(result);
   }
 
   return bresult;
@@ -205,7 +205,7 @@ has_method(const string &method_name) const {
 //               on success, NULL on error.
 ////////////////////////////////////////////////////////////////////
 P3D_object *P3DPythonObject::
-call(const string &method_name, P3D_object *params[], int num_params) const {
+call(const string &method_name, P3D_object *params[], int num_params) {
   TiXmlDocument *doc = new TiXmlDocument;
   TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
   TiXmlElement *xcommand = new TiXmlElement("command");
@@ -222,10 +222,6 @@ call(const string &method_name, P3D_object *params[], int num_params) const {
   for (int i = 0; i < num_params; ++i) {
     TiXmlElement *xparams = _session->p3dobj_to_xml(params[i]);
     xcommand->LinkEndChild(xparams);
-
-    // Now we're done with the params object passed in, we can delete
-    // it as promised.
-    P3D_OBJECT_FINISH(params[i]);
   }
 
   doc->LinkEndChild(decl);
@@ -255,12 +251,12 @@ call(const string &method_name, P3D_object *params[], int num_params) const {
 //               assistance.
 ////////////////////////////////////////////////////////////////////
 void P3DPythonObject::
-output(ostream &out) const {
+output(ostream &out) {
   P3D_object *result = call("__repr__", NULL, 0);
   out << "Python " << _object_id;
   if (result != NULL) {
     out << ": " << *result;
-    P3D_OBJECT_FINISH(result);
+    P3D_OBJECT_DECREF(result);
   }    
 }
 
@@ -271,7 +267,7 @@ output(ostream &out) const {
 //               identify this object in the XML stream.
 ////////////////////////////////////////////////////////////////////
 int P3DPythonObject::
-get_object_id() const {
+get_object_id() {
   return _object_id;
 }
 

+ 10 - 10
direct/src/plugin/p3dPythonObject.h

@@ -34,22 +34,22 @@ public:
   virtual ~P3DPythonObject();
 
 public:
-  virtual P3D_object_type get_type() const;
-  virtual bool get_bool() const;
-  virtual int get_int() const;
-  virtual double get_float() const;
+  virtual P3D_object_type get_type();
+  virtual bool get_bool();
+  virtual int get_int();
+  virtual double get_float();
 
-  virtual void make_string(string &value) const;
+  virtual void make_string(string &value);
 
-  virtual P3D_object *get_property(const string &property) const;
+  virtual P3D_object *get_property(const string &property);
   virtual bool set_property(const string &property, P3D_object *value);
 
-  virtual bool has_method(const string &method_name) const;
+  virtual bool has_method(const string &method_name);
   virtual P3D_object *call(const string &method_name, 
-                           P3D_object *params[], int num_params) const;
+                           P3D_object *params[], int num_params);
 
-  virtual void output(ostream &out) const;
-  int get_object_id() const;
+  virtual void output(ostream &out);
+  int get_object_id();
 
 private:
   P3DSession *_session;

+ 17 - 13
direct/src/plugin/p3dSession.cxx

@@ -321,21 +321,23 @@ command_and_response(TiXmlDocument *command) {
 //       Access: Public
 //  Description: Converts the XML representation of the particular
 //               object value into a corresponding P3D_object.
-//               Returns the newly-allocated object.
+//               Returns the object, a new reference.
 ////////////////////////////////////////////////////////////////////
 P3D_object *P3DSession::
 xml_to_p3dobj(const TiXmlElement *xvalue) {
   const char *type = xvalue->Attribute("type");
+  P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
+
   if (strcmp(type, "undefined") == 0) {
-    return new P3DUndefinedObject;
+    return inst_mgr->new_undefined_object();
 
   } else if (strcmp(type, "none") == 0) {
-    return new P3DNoneObject;
+    return inst_mgr->new_none_object();
 
   } else if (strcmp(type, "bool") == 0) {
     int value;
     if (xvalue->QueryIntAttribute("value", &value) == TIXML_SUCCESS) {
-      return new P3DBoolObject(value != 0);
+      return inst_mgr->new_bool_object(value != 0);
     }
 
   } else if (strcmp(type, "int") == 0) {
@@ -364,11 +366,12 @@ xml_to_p3dobj(const TiXmlElement *xvalue) {
       SentObjects::iterator si = _sent_objects.find(object_id);
       if (si == _sent_objects.end()) {
         // Hmm, the child process gave us a bogus object ID.
-        return new P3DUndefinedObject;
+        return inst_mgr->new_undefined_object();
       }
 
       P3D_object *obj = (*si).second;
-      return P3D_OBJECT_COPY(obj);
+      P3D_OBJECT_INCREF(obj);
+      return obj;
     }
 
   } else if (strcmp(type, "python") == 0) {
@@ -379,7 +382,7 @@ xml_to_p3dobj(const TiXmlElement *xvalue) {
   }
 
   // Something went wrong in decoding.
-  return new P3DUndefinedObject;
+  return inst_mgr->new_undefined_object();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -387,10 +390,11 @@ xml_to_p3dobj(const TiXmlElement *xvalue) {
 //       Access: Public
 //  Description: Allocates and returns a new XML structure
 //               corresponding to the indicated value.  The supplied
-//               P3DObject passed in is *not* deleted.
+//               P3DObject's reference count is not decremented; the
+//               caller remains responsible for decrementing it later.
 ////////////////////////////////////////////////////////////////////
 TiXmlElement *P3DSession::
-p3dobj_to_xml(const P3D_object *obj) {
+p3dobj_to_xml(P3D_object *obj) {
   TiXmlElement *xvalue = new TiXmlElement("value");
 
   switch (P3D_OBJECT_GET_TYPE(obj)) {
@@ -443,21 +447,21 @@ p3dobj_to_xml(const P3D_object *obj) {
       // should pass a reference down to this particular object, so
       // the Python process knows to call back up to here to query it.
 
-      P3D_object *dup = P3D_OBJECT_COPY(obj);
-
       int object_id = _next_sent_id;
       ++_next_sent_id;
-      bool inserted = _sent_objects.insert(SentObjects::value_type(object_id, dup)).second;
+      bool inserted = _sent_objects.insert(SentObjects::value_type(object_id, obj)).second;
       while (!inserted) {
         // Hmm, we must have cycled around the entire int space?  Either
         // that, or there's a logic bug somewhere.  Assume the former,
         // and keep looking for an empty slot.
         object_id = _next_sent_id;
         ++_next_sent_id;
-        inserted = _sent_objects.insert(SentObjects::value_type(object_id, dup)).second;
+        inserted = _sent_objects.insert(SentObjects::value_type(object_id, obj)).second;
       }
 
+      // Now that it's stored in the map, increment its reference count.
       // TODO: implement removing things from this map.
+      P3D_OBJECT_INCREF(obj);
 
       xvalue->SetAttribute("type", "browser");
       xvalue->SetAttribute("object_id", object_id);

+ 1 - 1
direct/src/plugin/p3dSession.h

@@ -50,7 +50,7 @@ public:
   void send_command(TiXmlDocument *command);
   TiXmlDocument *command_and_response(TiXmlDocument *command);
   P3D_object *xml_to_p3dobj(const TiXmlElement *xvalue);
-  TiXmlElement *p3dobj_to_xml(const P3D_object *obj);
+  TiXmlElement *p3dobj_to_xml(P3D_object *obj);
 
 private:
   void install_progress(P3DPackage *package, double progress);

+ 4 - 4
direct/src/plugin/p3dStringObject.cxx

@@ -50,7 +50,7 @@ P3DStringObject::
 //  Description: Returns the fundamental type of this kind of object.
 ////////////////////////////////////////////////////////////////////
 P3D_object_type P3DStringObject::
-get_type() const {
+get_type() {
   return P3D_OT_string;
 }
 
@@ -61,7 +61,7 @@ get_type() const {
 //               possible.
 ////////////////////////////////////////////////////////////////////
 bool P3DStringObject::
-get_bool() const {
+get_bool() {
   return !_value.empty();
 }
 
@@ -72,7 +72,7 @@ get_bool() const {
 //               of this object coerced to a string.
 ////////////////////////////////////////////////////////////////////
 void P3DStringObject::
-make_string(string &value) const {
+make_string(string &value) {
   value = _value;
 }
 
@@ -84,7 +84,7 @@ make_string(string &value) const {
 //               assistance.
 ////////////////////////////////////////////////////////////////////
 void P3DStringObject::
-output(ostream &out) const {
+output(ostream &out) {
   out << '"';
   for (string::const_iterator si = _value.begin(); si != _value.end(); ++si) {
     if (isprint(*si)) {

+ 4 - 4
direct/src/plugin/p3dStringObject.h

@@ -30,11 +30,11 @@ public:
 public:
   virtual ~P3DStringObject();
 
-  virtual P3D_object_type get_type() const;
-  virtual bool get_bool() const;
-  virtual void make_string(string &value) const;
+  virtual P3D_object_type get_type();
+  virtual bool get_bool();
+  virtual void make_string(string &value);
 
-  virtual void output(ostream &out) const;
+  virtual void output(ostream &out);
 
 private:
   string _value;

+ 3 - 3
direct/src/plugin/p3dUndefinedObject.cxx

@@ -29,7 +29,7 @@ P3DUndefinedObject() {
 //  Description: Returns the fundamental type of this kind of object.
 ////////////////////////////////////////////////////////////////////
 P3D_object_type P3DUndefinedObject::
-get_type() const {
+get_type() {
   return P3D_OT_undefined;
 }
 
@@ -40,7 +40,7 @@ get_type() const {
 //               possible.
 ////////////////////////////////////////////////////////////////////
 bool P3DUndefinedObject::
-get_bool() const {
+get_bool() {
   return false;
 }
 
@@ -51,6 +51,6 @@ get_bool() const {
 //               of this object coerced to a string.
 ////////////////////////////////////////////////////////////////////
 void P3DUndefinedObject::
-make_string(string &value) const {
+make_string(string &value) {
   value = "Undefined";
 }

+ 3 - 3
direct/src/plugin/p3dUndefinedObject.h

@@ -29,9 +29,9 @@ public:
   P3DUndefinedObject();
 
 public:
-  virtual P3D_object_type get_type() const;
-  virtual bool get_bool() const;
-  virtual void make_string(string &value) const;
+  virtual P3D_object_type get_type();
+  virtual bool get_bool();
+  virtual void make_string(string &value);
 };
 
 #endif

+ 7 - 4
direct/src/plugin/p3d_plugin.cxx

@@ -138,7 +138,8 @@ P3D_new_undefined_object() {
   assert(P3DInstanceManager::get_global_ptr()->is_initialized());
   ACQUIRE_LOCK(_api_lock);
 
-  P3D_object *result = new P3DUndefinedObject();
+  P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
+  P3D_object *result = inst_mgr->new_undefined_object();
   
   RELEASE_LOCK(_api_lock);
   return result;
@@ -149,7 +150,8 @@ P3D_new_none_object() {
   assert(P3DInstanceManager::get_global_ptr()->is_initialized());
   ACQUIRE_LOCK(_api_lock);
 
-  P3D_object *result = new P3DNoneObject();
+  P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
+  P3D_object *result = inst_mgr->new_none_object();
   
   RELEASE_LOCK(_api_lock);
   return result;
@@ -160,7 +162,8 @@ P3D_new_bool_object(bool value) {
   assert(P3DInstanceManager::get_global_ptr()->is_initialized());
   ACQUIRE_LOCK(_api_lock);
 
-  P3D_object *result = new P3DBoolObject(value);
+  P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
+  P3D_object *result = inst_mgr->new_bool_object(value);
   
   RELEASE_LOCK(_api_lock);
   return result;
@@ -212,7 +215,7 @@ P3D_instance_get_panda_script_object(P3D_instance *instance) {
 
 void
 P3D_instance_set_browser_script_object(P3D_instance *instance, 
-                               P3D_object *object) {
+                                       P3D_object *object) {
   assert(P3DInstanceManager::get_global_ptr()->is_initialized());
   ACQUIRE_LOCK(_api_lock);
 

+ 74 - 72
direct/src/plugin/p3d_plugin.h

@@ -307,25 +307,30 @@ typedef enum {
   P3D_OT_object,
 } P3D_object_type;
 
+/* Most methods and functions that return a P3D_object return it with
+   its reference count already incremented by one for the benefit of
+   the caller, leaving the caller the owner of the implicit reference
+   count.  This is referred to as returning a "new reference", using
+   the Python naming convention.  Similarly, most methods that receive
+   a P3D_object will implicitly increment the reference count
+   internally if necessary, leaving the caller still the owner of its
+   own reference count.  Thus, it is the caller's responsibility to
+   call P3D_OBJECT_DECREF() on any P3D_objects it has received but no
+   longer wishes to keep. */
+
 /* This method is called to deallocate the object and all of its
-   internal structures. */
+   internal structures.  Do not call it directly; call
+   P3D_OBJECT_DECREF() instead. */
 typedef void
 P3D_object_finish_method(P3D_object *object);
 
-/* Returns a new copy of the object.  The caller receives ownership of
-   the new object and must eventually pass its pointer to
-   P3D_OBJECT_FINISH() to delete it, or into some other call that
-   transfers ownership. */
-typedef P3D_object *
-P3D_object_copy_method(const P3D_object *object);
-
 /* Returns the fundamental type of the object.  This should be treated
    as a hint to suggest how the object can most accurately be
    represented; it does not limit the actual interfaces available to
    an object.  For instance, you may call P3D_OBJECT_GET_PROPERTY()
    even if the object's type is not "object". */
 typedef P3D_object_type
-P3D_object_get_type_method(const P3D_object *object);
+P3D_object_get_type_method(P3D_object *object);
 
 /* Each of the following methods returns the object's value expressed
    as the corresponding type.  If the object is not precisely that
@@ -333,15 +338,15 @@ P3D_object_get_type_method(const P3D_object *object);
 
 /* Return the object as a bool. */
 typedef bool
-P3D_object_get_bool_method(const P3D_object *object);
+P3D_object_get_bool_method(P3D_object *object);
 
 /* Return the object as an integer. */
 typedef int
-P3D_object_get_int_method(const P3D_object *object);
+P3D_object_get_int_method(P3D_object *object);
 
 /* Return the object as a floating-point number. */
 typedef double
-P3D_object_get_float_method(const P3D_object *object);
+P3D_object_get_float_method(P3D_object *object);
 
 /* Get the object as a string.  This method copies the string into the
    provided buffer, and returns the actual length of the internal
@@ -352,7 +357,7 @@ P3D_object_get_float_method(const P3D_object *object);
    buffer = NULL and buffer_length = 0 to return just the required
    size of the buffer. */
 typedef int
-P3D_object_get_string_method(const P3D_object *object, 
+P3D_object_get_string_method(P3D_object *object, 
                              char *buffer, int buffer_length);
 
 /* As above, but instead of the literal object data, returns a
@@ -362,23 +367,19 @@ P3D_object_get_string_method(const P3D_object *object,
    marks and escape characters from P3D_OBJECT_GET_REPR().
    Mechanically, this function works the same way as get_string(). */
 typedef int
-P3D_object_get_repr_method(const P3D_object *object, 
+P3D_object_get_repr_method(P3D_object *object, 
                            char *buffer, int buffer_length);
 
 /* Looks up a property on the object by name, i.e. a data member or a
-   method.  The return value is a newly-allocated P3D_object if the
-   property exists, or NULL if it does not.  If it is not NULL,
-   ownership of the return value is transferred to the caller, who
-   will be responsible for deleting it later. */
+   method.  The return value is a new-reference P3D_object if the
+   property exists, or NULL if it does not. */
 typedef P3D_object *
-P3D_object_get_property_method(const P3D_object *object, const char *property);
+P3D_object_get_property_method(P3D_object *object, const char *property);
 
 /* Changes the value at the indicated property.  Any existing object
    already at the corresponding property is deleted.  If the value
-   object pointer is NULL, the property is deleted.  Returns true on
-   success, false on failure.  The caller must have ownership of the
-   value object before the call; after the call, ownership of the
-   value object is transferred to this object. */
+   pointer is NULL, the property is deleted.  Returns true on success,
+   false on failure.  */
 typedef bool
 P3D_object_set_property_method(P3D_object *object, const char *property,
                                P3D_object *value);
@@ -389,36 +390,32 @@ P3D_object_set_property_method(P3D_object *object, const char *property,
    a callable object.  If method_name is empty or NULL, returns true
    if the object itself is callable. */
 typedef bool
-P3D_object_has_method_method(const P3D_object *object, const char *method_name);
+P3D_object_has_method_method(P3D_object *object, const char *method_name);
 
 /* Invokes a named method on the object.  If method_name is empty or
    NULL, invokes the object itself as a function.  You must pass an
-   array of P3D_objects as the list of parameters.  The ownership of
-   each of the parameters in this array (but not of the array pointer
-   itself) is passed into this call; the objects will be deleted when
-   the call is completed.
-
-   The return value is a newly-allocated P3D_object on success, or
-   NULL on failure.  Ownership of the return value is transferred to
-   the caller. */
+   array of P3D_objects as the list of parameters, and ownership of
+   these objects' reference counts is not transferred with the call
+   (you must still DECREF these objects afterwards).
+
+   The return value is a new-reference P3D_object on success, or NULL
+   on failure. */
 typedef P3D_object *
-P3D_object_call_method(const P3D_object *object, const char *method_name,
+P3D_object_call_method(P3D_object *object, const char *method_name,
                        P3D_object *params[], int num_params);
 
 /* Evaluates an arbitrary JavaScript expression in the context of the
    object.
 
-   The return value is a newly-allocated P3D_object on success, or
-   NULL on failure.  Ownership of the return value is transferred to
-   the caller. */
+   The return value is a new-reference P3D_object on success, or NULL
+   on failure. */
 typedef P3D_object *
-P3D_object_eval_method(const P3D_object *object, const char *expression);
+P3D_object_eval_method(P3D_object *object, const char *expression);
 
 /* This defines the class structure that implements all of the above
    methods. */
 typedef struct _P3D_class_definition {
   P3D_object_finish_method *_finish;
-  P3D_object_copy_method *_copy;
 
   P3D_object_get_type_method *_get_type;
   P3D_object_get_bool_method *_get_bool;
@@ -439,6 +436,7 @@ typedef struct _P3D_class_definition {
 /* And this structure defines the actual instances of P3D_object. */
 struct _P3D_object {
   const P3D_class_definition *_class;
+  int _ref_count;
 
   /* Additional opaque data may be stored here. */
 };
@@ -446,9 +444,6 @@ struct _P3D_object {
 /* These macros are defined for the convenience of invoking any of the
    above method functions on an object. */
 
-#define P3D_OBJECT_FINISH(object) ((object)->_class->_finish((object)))
-#define P3D_OBJECT_COPY(object) ((object)->_class->_copy((object)))
-
 #define P3D_OBJECT_GET_TYPE(object) ((object)->_class->_get_type((object)))
 #define P3D_OBJECT_GET_BOOL(object) ((object)->_class->_get_bool((object)))
 #define P3D_OBJECT_GET_INT(object) ((object)->_class->_get_int((object)))
@@ -463,58 +458,65 @@ struct _P3D_object {
 #define P3D_OBJECT_CALL(object, method_name, params, num_params) ((object)->_class->_call((object), (method_name), (params), (num_params)))
 #define P3D_OBJECT_EVAL(object, expression) ((object)->_class->_eval((object), (expression)))
 
+/* These macros are provided to manipulate the reference count of the
+   indicated object.  Following Python's convention, XDECREF is
+   provided to decrement the reference count for a pointer that might
+   be NULL (it does nothing in the case of a NULL pointer). */
+
+#define P3D_OBJECT_INCREF(object) (++(object)->_ref_count)
+#define P3D_OBJECT_DECREF(object) { if (--(object)->_ref_count <= 0) { (object)->_class->_finish((object)); } }
+#define P3D_OBJECT_XDECREF(object) { if ((object) != (P3D_object *)NULL) { P3D_OBJECT_DECREF(object); } }
 
-/* The following function types are once again meant to define
-   actual function pointers to be found within the core API DLL. */
 
-/* Returns a newly-allocated P3D_class_definition object, filled with
-   generic function pointers that have reasonable default behavior for
-   all methods.  The host should use this function to get a clean
+/* End of method pointer definitions.  The following function types
+   are once again meant to define actual function pointers to be found
+   within the core API DLL. */
+
+/* Returns a new P3D_class_definition object, filled with generic
+   function pointers that have reasonable default behavior for all
+   methods.  The host should use this function to get a clean
    P3D_class_definition object before calling
-   P3D_instance_set_browser_script_object() (see below).  Note that this
-   pointer will automatically be freed when P3D_finalize() is
+   P3D_instance_set_browser_script_object() (see below).  Note that
+   this pointer will automatically be freed when P3D_finalize() is
    called. */
 typedef P3D_class_definition *
 P3D_make_class_definition_func();
 
-/* Allocates a new P3D_object of type "undefined".  This corresponds
-   to the undefined or void type on JavaScript.  It is similar to
-   Python's None, but has a subtly different shade of meaning; we map
-   it to an explicit Undefined instance in runp3d.py. */
+/* Returns a new-reference P3D_object of type "undefined".  This
+   corresponds to the undefined or void type on JavaScript.  It is
+   similar to Python's None, but has a subtly different shade of
+   meaning; we map it to an explicit Undefined instance in
+   runp3d.py. */
 typedef P3D_object *
 P3D_new_undefined_object_func();
 
-/* Allocates a new P3D_object of type none.  This value has no
+/* Returns a new-reference P3D_object of type none.  This value has no
    particular value and corresponds to Python's None type or
    JavaScript's null type. */
 typedef P3D_object *
 P3D_new_none_object_func();
 
-/* Allocates a new P3D_object of type bool. */
+/* Returns a new-reference P3D_object of type bool. */
 typedef P3D_object *
 P3D_new_bool_object_func(bool value);
 
-/* Allocates a new P3D_object of type int. */
+/* Returns a new-reference P3D_object of type int. */
 typedef P3D_object *
 P3D_new_int_object_func(int value);
 
-/* Allocates a new P3D_object of type float. */
+/* Returns a new-reference P3D_object of type float. */
 typedef P3D_object *
 P3D_new_float_object_func(double value);
 
-/* Allocates a new P3D_object of type string.  The supplied string is
-   copied into the object and stored internally. */
+/* Returns a new-reference P3D_object of type string.  The supplied
+   string is copied into the object and stored internally. */
 typedef P3D_object *
 P3D_new_string_object_func(const char *string, int length);
 
-/* Returns a pointer to the top-level scriptable object of the
-   instance.  Scripts running on the host may use this object to
-   communicate with the instance, by using the above methods to set or
-   query properties, and/or call methods, on the instance. 
-
-   The return value from this function is a newly-allocated object;
-   ownership of the object is passed to the caller, who should be
-   responsible for deleting it eventually. */
+/* Returns a new-reference pointer to the top-level scriptable object
+   of the instance.  Scripts running on the host may use this object
+   to communicate with the instance, by using the above methods to set
+   or query properties, and/or call methods, on the instance. */
 typedef P3D_object *
 P3D_instance_get_panda_script_object_func(P3D_instance *instance);
 
@@ -528,8 +530,8 @@ P3D_instance_get_panda_script_object_func(P3D_instance *instance);
    have a custom P3D_class_definition pointer, which also must have
    been created by the host.  The best way to create an appropriate
    class definition is call P3D_make_class_definition(), and then
-   replace the function pointers for at least _finish, _copy,
-   _get_property, _set_property, and _call.  Set these pointers to the
+   replace the function pointers for at least _finish, _get_property,
+   _set_property, _has_method, and _call.  Set these pointers to the
    host's own functions that make the appropriate changes in the DOM,
    or invoke the appropriate JavaScript functions.
 
@@ -538,10 +540,10 @@ P3D_instance_get_panda_script_object_func(P3D_instance *instance);
    able to control the instance via P3D_instance_get_panda_script_object(),
    above. 
 
-   Ownership of the object is passed into the instance.  The caller
-   must have freshly allocated the object, and should no longer store
-   or delete it.  The instance will eventually delete it by calling
-   its _finish method. */
+   Note that the object's constructor should initialize its reference
+   count to 1.  The instance will increment reference count as a
+   result of this call; the caller is responsible for calling DECREF
+   on the object after this call to remove its own reference. */
 typedef void
 P3D_instance_set_browser_script_object_func(P3D_instance *instance, 
                                             P3D_object *object);

+ 1 - 1
direct/src/plugin/p3d_plugin_common.h

@@ -41,7 +41,7 @@ extern ostream *nout_stream;
 // A convenience function for formatting a generic P3D_object to an
 // ostream.
 inline ostream &
-operator << (ostream &out, const P3D_object &value) {
+operator << (ostream &out, P3D_object &value) {
   int size = P3D_OBJECT_GET_REPR(&value, NULL, 0);
   char *buffer = new char[size];
   P3D_OBJECT_GET_REPR(&value, buffer, size);

+ 7 - 11
direct/src/plugin_npapi/ppBrowserObject.cxx

@@ -26,18 +26,13 @@ object_finish(P3D_object *object) {
   delete ((PPBrowserObject *)object);
 }
 
-static P3D_object *
-object_copy(const P3D_object *object) {
-  return new PPBrowserObject(*(const PPBrowserObject *)object);
-}
-
 static int 
-object_get_repr(const P3D_object *object, char *buffer, int buffer_length) {
+object_get_repr(P3D_object *object, char *buffer, int buffer_length) {
   return ((const PPBrowserObject *)object)->get_repr(buffer, buffer_length);
 }
 
 static P3D_object *
-object_get_property(const P3D_object *object, const char *property) {
+object_get_property(P3D_object *object, const char *property) {
   return ((const PPBrowserObject *)object)->get_property(property);
 }
 
@@ -48,7 +43,7 @@ object_set_property(P3D_object *object, const char *property,
 }
 
 static P3D_object *
-object_call(const P3D_object *object, const char *method_name,
+object_call(P3D_object *object, const char *method_name,
             P3D_object *params[], int num_params) {
   if (method_name == NULL) {
     method_name = "";
@@ -57,7 +52,7 @@ object_call(const P3D_object *object, const char *method_name,
 }
 
 static P3D_object *
-object_eval(const P3D_object *object, const char *expression) {
+object_eval(P3D_object *object, const char *expression) {
   return ((const PPBrowserObject *)object)->eval(expression);
 }
 
@@ -74,6 +69,7 @@ PPBrowserObject(PPInstance *inst, NPObject *npobj) :
   _npobj(npobj)
 {
   _class = get_class_definition();
+  _ref_count = 1;
   browser->retainobject(_npobj);
 }
 
@@ -88,6 +84,7 @@ PPBrowserObject(const PPBrowserObject &copy) :
   _npobj(copy._npobj)
 {
   _class = get_class_definition();
+  _ref_count = 1;
   browser->retainobject(_npobj);
 }
 
@@ -98,6 +95,7 @@ PPBrowserObject(const PPBrowserObject &copy) :
 ////////////////////////////////////////////////////////////////////
 PPBrowserObject::
 ~PPBrowserObject() {
+  assert(_ref_count == 0);
   browser->releaseobject(_npobj);
 }
 
@@ -162,7 +160,6 @@ set_property(const string &property, P3D_object *value) {
     result = browser->setproperty(_instance->get_npp_instance(), _npobj,
                                   property_name, &npvalue);
     browser->releasevariantvalue(&npvalue);
-    P3D_OBJECT_FINISH(value);
 
   } else {
     // Delete the property.
@@ -268,7 +265,6 @@ get_class_definition() {
     // appropriate pointers.
     _browser_object_class = P3D_make_class_definition();
     _browser_object_class->_finish = &object_finish;
-    _browser_object_class->_copy = &object_copy;
 
     _browser_object_class->_get_repr = &object_get_repr;
     _browser_object_class->_get_property = &object_get_property;

+ 4 - 4
direct/src/plugin_npapi/ppInstance.cxx

@@ -501,7 +501,7 @@ get_panda_script_object() {
 //               NPVariant, and stores it in result.
 ////////////////////////////////////////////////////////////////////
 void PPInstance::
-p3dobj_to_variant(NPVariant *result, const P3D_object *object) {
+p3dobj_to_variant(NPVariant *result, P3D_object *object) {
   switch (P3D_OBJECT_GET_TYPE(object)) {
   case P3D_OT_undefined:
     VOID_TO_NPVARIANT(*result);
@@ -534,7 +534,7 @@ p3dobj_to_variant(NPVariant *result, const P3D_object *object) {
 
   case P3D_OT_object:
     {
-      PPPandaObject *ppobj = PPPandaObject::make_new(this, P3D_OBJECT_COPY(object));
+      PPPandaObject *ppobj = PPPandaObject::make_new(this, object);
       OBJECT_TO_NPVARIANT(ppobj, *result);
     }
     break;
@@ -571,7 +571,7 @@ variant_to_p3dobj(const NPVariant *variant) {
       PPPandaObject *ppobject = (PPPandaObject *)object;
       P3D_object *obj = ppobject->get_p3d_object();
       logfile << "Found nested Panda Object " << obj << "\n" << flush;
-      return P3D_OBJECT_COPY(obj);
+      return obj;
     }
 
     // It's a generic NPObject of some kind.
@@ -899,7 +899,7 @@ create_instance() {
       logfile << "Couldn't get window_object\n" << flush;
     }
     
-    const P3D_token *tokens = NULL;
+    P3D_token *tokens = NULL;
     if (!_tokens.empty()) {
       tokens = &_tokens[0];
     }

+ 1 - 1
direct/src/plugin_npapi/ppInstance.h

@@ -55,7 +55,7 @@ public:
 
   NPObject *get_panda_script_object();
 
-  void p3dobj_to_variant(NPVariant *result, const P3D_object *object);
+  void p3dobj_to_variant(NPVariant *result, P3D_object *object);
   P3D_object *variant_to_p3dobj(const NPVariant *variant);
 
   static void output_np_variant(ostream &out, const NPVariant &result);

+ 4 - 0
direct/src/plugin_npapi/ppPandaObject.I

@@ -18,8 +18,12 @@
 //       Access: Public
 //  Description: Returns the p3d_object this PPPandaObject maps to.  This
 //               may be NULL if the object is not fully initialized.
+//               If not NULL, this returns a new reference.
 ////////////////////////////////////////////////////////////////////
 inline P3D_object *PPPandaObject::
 get_p3d_object() const {
+  if (_p3d_object != NULL) {
+    P3D_OBJECT_INCREF(_p3d_object);
+  }
   return _p3d_object;
 }

+ 21 - 10
direct/src/plugin_npapi/ppPandaObject.cxx

@@ -53,16 +53,17 @@ make_new(PPInstance *inst, P3D_object *p3d_object) {
 //     Function: PPPandaObject::set_p3d_object
 //       Access: Public
 //  Description: Changes the p3d_object this PPPandaObject maps to.  The
-//               previous object, if any, is deleted.  Ownership of
-//               the new object is passed to the PPPandaObject.
+//               new object's reference count is incremented, and the
+//               previous object's is decremented.
 ////////////////////////////////////////////////////////////////////
 void PPPandaObject::
 set_p3d_object(P3D_object *p3d_object) {
   if (_p3d_object != p3d_object) {
+    P3D_OBJECT_XDECREF(_p3d_object);
+    _p3d_object = p3d_object;
     if (_p3d_object != NULL) {
-      P3D_OBJECT_FINISH(_p3d_object);
+      P3D_OBJECT_INCREF(_p3d_object);
     }
-    _p3d_object = p3d_object;
   }
 }
  
@@ -78,7 +79,8 @@ void PPPandaObject::
 construct(PPInstance *inst, P3D_object *p3d_object) {
   logfile << "construct: " << this << "\n" << flush;
   _instance = inst;
-  _p3d_object = p3d_object;
+  _p3d_object = NULL;
+  set_p3d_object(p3d_object);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -141,12 +143,16 @@ invoke(NPIdentifier name, const NPVariant *args, uint32_t argCount,
   }
 
   P3D_object **p3dargs = new P3D_object *[argCount];
-  for (unsigned int i = 0; i < argCount; ++i) {
+  unsigned int i;
+  for (i = 0; i < argCount; ++i) {
     p3dargs[i] = _instance->variant_to_p3dobj(&args[i]);
   }
 
   P3D_object *value = P3D_OBJECT_CALL(_p3d_object, method_name.c_str(), 
                                       p3dargs, argCount);
+  for (i = 0; i < argCount; ++i) {
+    P3D_OBJECT_DECREF(p3dargs[i]);
+  }
   delete[] p3dargs;
 
   if (value == NULL) {
@@ -156,7 +162,7 @@ invoke(NPIdentifier name, const NPVariant *args, uint32_t argCount,
 
   // We have the return value, and its value is stored in value.
   _instance->p3dobj_to_variant(result, value);
-  P3D_OBJECT_FINISH(value);
+  P3D_OBJECT_DECREF(value);
   return true;
 }
 
@@ -177,12 +183,16 @@ invoke_default(const NPVariant *args, uint32_t argCount,
   }
 
   P3D_object **p3dargs = new P3D_object *[argCount];
-  for (unsigned int i = 0; i < argCount; ++i) {
+  unsigned int i;
+  for (i = 0; i < argCount; ++i) {
     p3dargs[i] = _instance->variant_to_p3dobj(&args[i]);
   }
 
   P3D_object *value = P3D_OBJECT_CALL(_p3d_object, "",
                                       p3dargs, argCount);
+  for (i = 0; i < argCount; ++i) {
+    P3D_OBJECT_DECREF(p3dargs[i]);
+  }
   delete[] p3dargs;
 
   if (value == NULL) {
@@ -192,7 +202,7 @@ invoke_default(const NPVariant *args, uint32_t argCount,
 
   // We have the return value, and its value is stored in value.
   _instance->p3dobj_to_variant(result, value);
-  P3D_OBJECT_FINISH(value);
+  P3D_OBJECT_DECREF(value);
   return true;
 }
 
@@ -239,7 +249,7 @@ get_property(NPIdentifier name, NPVariant *result) {
 
   // We have the property, and its value is stored in value.
   _instance->p3dobj_to_variant(result, value);
-  P3D_OBJECT_FINISH(value);
+  P3D_OBJECT_DECREF(value);
   return true;
 }
 
@@ -260,6 +270,7 @@ set_property(NPIdentifier name, const NPVariant *value) {
 
   P3D_object *object = _instance->variant_to_p3dobj(value);
   bool result = P3D_OBJECT_SET_PROPERTY(_p3d_object, property_name.c_str(), object);
+  P3D_OBJECT_DECREF(object);
   return result;
 }