gnash-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Gnash-commit] /srv/bzr/gnash/trunk r10501: Test and fix Date encoding w


From: Benjamin Wolsey
Subject: [Gnash-commit] /srv/bzr/gnash/trunk r10501: Test and fix Date encoding with overridden valueOf().
Date: Fri, 02 Jan 2009 13:48:38 +0100
User-agent: Bazaar (1.5)

------------------------------------------------------------
revno: 10501
committer: Benjamin Wolsey <address@hidden>
branch nick: trunk
timestamp: Fri 2009-01-02 13:48:38 +0100
message:
  Test and fix Date encoding with overridden valueOf().
  
  Fix memory corruption (GC) on exit with SharedObject::flush().
removed:
  testsuite/misc-ming.all/SharedObjectTest.sol/sol1.sol
renamed:
  libcore/asobj/Date.cpp => libcore/asobj/Date_as.cpp
  libcore/asobj/Date.h => libcore/asobj/Date_as.h
modified:
  libcore/as_value.cpp
  libcore/asobj/ClassHierarchy.cpp
  libcore/asobj/Global.cpp
  libcore/asobj/Makefile.am
  libcore/asobj/SharedObject_as.cpp
  libcore/asobj/SharedObject_as.h
  libcore/asobj/String_as.cpp
  libcore/impl.cpp
  libcore/vm/VM.cpp
  libcore/vm/VM.h
  testsuite/misc-ming.all/SharedObjectTest.as
  libcore/asobj/Date_as.cpp
  libcore/asobj/Date_as.h
    ------------------------------------------------------------
    revno: 10497.1.1
    committer: Benjamin Wolsey <address@hidden>
    branch nick: test
    timestamp: Wed 2008-12-31 13:53:47 +0100
    message:
      Rename Date to Date_as, clean it up, and move the class definition
      to the header for use in AMF decoding.
      
      Add new test to SharedObjectTest, which makes Gnash fail a seemingly
      unrelated assertion in action.cpp.
    renamed:
      libcore/asobj/Date.cpp => libcore/asobj/Date_as.cpp
      libcore/asobj/Date.h => libcore/asobj/Date_as.h
    modified:
      libcore/as_value.cpp
      libcore/asobj/ClassHierarchy.cpp
      libcore/asobj/Global.cpp
      libcore/asobj/Makefile.am
      libcore/asobj/String_as.cpp
      testsuite/misc-ming.all/SharedObjectTest.as
      libcore/asobj/Date_as.cpp
      libcore/asobj/Date_as.h
    ------------------------------------------------------------
    revno: 10497.1.2
    committer: Benjamin Wolsey <address@hidden>
    branch nick: test
    timestamp: Fri 2009-01-02 13:00:13 +0100
    message:
      Flush SOL files when the SharedObjectLibrary is cleared, not in
      the dtor of SharedObject_as, due to GC issues. Delete the 
SharedObjectLibrary
      before GC::cleanup() is called for similar reasons. Add VM::clear() method
      for doing this.
    modified:
      libcore/asobj/SharedObject_as.cpp
      libcore/asobj/SharedObject_as.h
      libcore/impl.cpp
      libcore/vm/VM.cpp
      libcore/vm/VM.h
    ------------------------------------------------------------
    revno: 10497.1.3
    committer: Benjamin Wolsey <address@hidden>
    branch nick: test
    timestamp: Fri 2009-01-02 13:09:13 +0100
    message:
      Test a Date with overridden valueOf. Use Date_as::getTimeValue() instead.
    modified:
      libcore/as_value.cpp
      testsuite/misc-ming.all/SharedObjectTest.sol/sol1.sol
    ------------------------------------------------------------
    revno: 10497.1.4
    committer: Benjamin Wolsey <address@hidden>
    branch nick: test
    timestamp: Fri 2009-01-02 13:16:04 +0100
    message:
      Another SOL test.
    modified:
      libcore/as_value.cpp
      testsuite/misc-ming.all/SharedObjectTest.as
      testsuite/misc-ming.all/SharedObjectTest.sol/sol1.sol
=== modified file 'libcore/as_value.cpp'
--- a/libcore/as_value.cpp      2008-12-31 23:18:11 +0000
+++ b/libcore/as_value.cpp      2009-01-02 12:48:38 +0000
@@ -37,7 +37,7 @@
 #include "Object.h"
 #include "amf.h"
 #include "Array_as.h"
-#include "Date.h" // for init_date_instance (readAMF0)
+#include "Date_as.h" // for Date type (readAMF0)
 #include "SimpleBuffer.h"
 
 #include <cmath> // std::fmod
@@ -2392,7 +2392,7 @@
 #ifdef GNASH_DEBUG_AMF_DESERIALIZE
                        log_debug("amf0 read date: %e", dub);
 #endif
-            as_object* obj = init_date_instance(dub);
+            as_object* obj = new Date_as(dub);
                        ret.set_as_object(obj);
 
                        if (b + 2 > end) {
@@ -2491,14 +2491,16 @@
                 }
                 else if ( obj->isDateObject() )
                 {
-                    double d = to_number(); // TODO: check effects of 
overridden valueOf !
+                    const Date_as& date = dynamic_cast<const Date_as&>(*obj);
+                    double d = date.getTimeValue(); 
 #ifdef GNASH_DEBUG_AMF_SERIALIZE
                     log_debug(_("writeAMF0: serializing date object "
                                 "with index %d and value %g"), idx, d);
 #endif
                     buf.appendByte(amf::Element::DATE_AMF0);
 
-                    amf::swapBytes(&d, 8); // this actually only swapps on 
little-endian machines
+                    // This actually only swaps on little-endian machines
+                    amf::swapBytes(&d, 8);
                     buf.append(&d, 8);
 
                     // This should be timezone

=== modified file 'libcore/asobj/ClassHierarchy.cpp'
--- a/libcore/asobj/ClassHierarchy.cpp  2008-12-27 19:56:32 +0000
+++ b/libcore/asobj/ClassHierarchy.cpp  2008-12-31 12:53:47 +0000
@@ -28,7 +28,7 @@
 #include "Color_as.h"
 #include "ContextMenu.h"
 #include "CustomActions.h"
-#include "Date.h"
+#include "Date_as.h"
 #include "Error_as.h"
 #include "Global.h"
 #include "String_as.h"
@@ -297,7 +297,7 @@
        { selection_class_init, NSV::CLASS_SELECTION, NSV::CLASS_OBJECT, 
NS_UNKNOWN, 5 },
        { Sound_as::init, NSV::CLASS_SOUND, NSV::CLASS_OBJECT, 
NSV::NS_FLASH_MEDIA, 5 },
        { xmlsocket_class_init, NSV::CLASS_X_M_L_SOCKET, NSV::CLASS_OBJECT, 
NSV::NS_FLASH_NET, 5 },
-       { date_class_init, NSV::CLASS_DATE, NSV::CLASS_OBJECT, NS_GLOBAL, 5 },
+       { Date_as::init, NSV::CLASS_DATE, NSV::CLASS_OBJECT, NS_GLOBAL, 5 },
        { XML_as::init, NSV::CLASS_X_M_L, NSV::CLASS_OBJECT, NS_GLOBAL, 5 },
        { XMLNode_as::init, NSV::CLASS_X_M_L_NODE, NSV::CLASS_OBJECT,
         NSV::NS_FLASH_XML, 5 },

=== renamed file 'libcore/asobj/Date.cpp' => 'libcore/asobj/Date_as.cpp'
--- a/libcore/asobj/Date.cpp    2008-12-30 19:08:52 +0000
+++ b/libcore/asobj/Date_as.cpp 2008-12-31 12:53:47 +0000
@@ -1,4 +1,4 @@
-// Date.cpp:  ActionScript class for date and time, for Gnash.
+// Date_as.cpp:  ActionScript class for date and time, for Gnash.
 // 
 //  Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
 //
@@ -17,8 +17,6 @@
 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 //
 
-// Date.cpp
-//
 // Implements methods of the ActionScript "Date" class for Gnash
 //
 // TODO: What does Flash setTime() do/return if you hand it 0 parameters?
@@ -71,7 +69,7 @@
 
 #include "log.h"
 #include "utility.h"
-#include "Date.h"
+#include "Date_as.h"
 #include "fn_call.h"
 #include "GnashException.h"
 #include "builtin_function.h"
@@ -88,145 +86,146 @@
 
 namespace gnash {
 
-// A time struct to contain the broken-down time.
-struct GnashTime
-{
-    boost::int32_t millisecond;
-    boost::int32_t second;
-    boost::int32_t minute;
-    boost::int32_t hour;
-    boost::int32_t monthday;
-    boost::int32_t weekday;
-    boost::int32_t month;
-    boost::int32_t year;
-    boost::int32_t timeZoneOffset;
-};
-
-static const int daysInMonth[2][12] = {
-    {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
-    {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
-};
-
-// Seconds and milliseconds should be exactly the same whether in UTC
-// or in localtime, so we always use localtime.
-
-// forward declarations
-static as_object* getDateInterface();
-static void attachDateInterface(as_object& o);
-static void attachDateStaticInterface(as_object& o);
-
-static as_value date_new(const fn_call& fn);
-static as_value date_getTime(const fn_call& fn); 
-static as_value date_setTime(const fn_call& fn);
-static as_value date_getTimezoneOffset(const fn_call& fn);
-static as_value date_getYear(const fn_call& fn);
-static as_value date_getFullYear(const fn_call& fn);
-static as_value date_getMonth(const fn_call& fn);
-static as_value date_getDate(const fn_call& fn);
-static as_value date_getDay(const fn_call& fn);
-static as_value date_getHours(const fn_call& fn);
-static as_value date_getMinutes(const fn_call& fn);
-static as_value date_getSeconds(const fn_call& fn);
-static as_value date_getMilliseconds(const fn_call& fn);
-static as_value date_getUTCFullYear(const fn_call& fn);
-static as_value date_getUTCYear(const fn_call& fn);
-static as_value date_getUTCMonth(const fn_call& fn);
-static as_value date_getutcdate(const fn_call& fn);
-static as_value date_getUTCDay(const fn_call& fn);
-static as_value date_getUTCHours(const fn_call& fn);
-static as_value date_getUTCMinutes(const fn_call& fn);
-template<bool utc> as_value date_setDate(const fn_call& fn);
-template<bool utc> as_value date_setfullyear(const fn_call& fn);
-template<bool utc> as_value date_setHours(const fn_call& fn);
-template<bool utc> as_value date_setMilliseconds(const fn_call& fn);
-template<bool utc> as_value date_setMinutes(const fn_call& fn);
-template<bool utc> as_value date_setmonth(const fn_call& fn);
-template<bool utc> as_value date_setSeconds(const fn_call& fn);
-static as_value date_setYear(const fn_call& fn);
-static as_value date_tostring(const fn_call& fn);
-static as_value date_valueof(const fn_call& fn);
-static as_value date_UTC(const fn_call& fn);
-
-static void fillGnashTime(const double& time, GnashTime& gt);
-static double makeTimeValue(GnashTime& gt);
-static void localTime(const double& time, GnashTime& gt);
-static void universalTime(const double& time, GnashTime& gt);
-static int localTimeZoneOffset(const double& time);
-
-static double rogue_date_args(const fn_call& fn, unsigned maxargs);
-
-// Helpers for calendar algorithms
-inline bool
-isLeapYear(boost::int32_t year)
-{
-    return !((year + 1900) % 400) ||
-            ( !((year + 1900) % 4) && ((year + 1900) % 100));
-}
-
-
-inline size_t
-countLeapYears(boost::int32_t year)
-{
-    return (year - 70) / 4 - (year - 70) / 100 + (year - 70) / 400;
-}
-
-
-class Date : public as_object
-{
-public:
-    void setTimeValue(const double& value) { _value = value; }
-    double getTimeValue() const { return _value; }
-
-    Date(double value = clocktime::getTicks())
-        :
-        as_object(getDateInterface()),
-        _value(value)
-    {
-    }
-
-    as_value toString() const;
-
-    bool isDateObject() { return true; }
-
-private:
-    double _value;
-};
-
-/// Return the broken-down time as a local time.
-inline void
-localTime(const double& time, GnashTime& gt)
-{
-    // find local timezone offset for the desired time.
-    gt.timeZoneOffset = localTimeZoneOffset(time);
-    fillGnashTime(time, gt);
-}
-
-/// Return the broken-down time as UTC
-inline void
-universalTime(const double& time, GnashTime& gt)
-{
-    // No time zone needed.
-    gt.timeZoneOffset = 0;
-    fillGnashTime(time, gt);
-}
-
-
-/// Safely truncate a double to an integer, returning the min()
-/// limit on overflow.
-template <typename T>
-inline void truncateDouble(T& target, double value)
-{
-    if (value < std::numeric_limits<T>::min() ||
-            value > std::numeric_limits<T>::max())
-    {
-        target = std::numeric_limits<T>::min();
-        return;
-    }
-    target = static_cast<T>(value);
-
-}
-
-void registerDateNative(as_object& global)
+namespace {
+
+    // A time struct to contain the broken-down time.
+    struct GnashTime
+    {
+        boost::int32_t millisecond;
+        boost::int32_t second;
+        boost::int32_t minute;
+        boost::int32_t hour;
+        boost::int32_t monthday;
+        boost::int32_t weekday;
+        boost::int32_t month;
+        boost::int32_t year;
+        boost::int32_t timeZoneOffset;
+    };
+
+    static const int daysInMonth[2][12] = {
+        {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
+        {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
+    };
+
+    // Forward declarations
+    
+    as_object* getDateInterface();
+    void attachDateInterface(as_object& o);
+    void attachDateStaticInterface(as_object& o);
+
+    // Seconds and milliseconds should be exactly the same whether in UTC
+    // or in localtime, so we always use localtime.
+    as_value date_new(const fn_call& fn);
+    as_value date_getTime(const fn_call& fn); 
+    as_value date_setTime(const fn_call& fn);
+    as_value date_getTimezoneOffset(const fn_call& fn);
+    as_value date_getYear(const fn_call& fn);
+    as_value date_getFullYear(const fn_call& fn);
+    as_value date_getMonth(const fn_call& fn);
+    as_value date_getDate(const fn_call& fn);
+    as_value date_getDay(const fn_call& fn);
+    as_value date_getHours(const fn_call& fn);
+    as_value date_getMinutes(const fn_call& fn);
+    as_value date_getSeconds(const fn_call& fn);
+    as_value date_getMilliseconds(const fn_call& fn);
+    as_value date_getUTCFullYear(const fn_call& fn);
+    as_value date_getUTCYear(const fn_call& fn);
+    as_value date_getUTCMonth(const fn_call& fn);
+    as_value date_getutcdate(const fn_call& fn);
+    as_value date_getUTCDay(const fn_call& fn);
+    as_value date_getUTCHours(const fn_call& fn);
+    as_value date_getUTCMinutes(const fn_call& fn);
+    template<bool utc> as_value date_setDate(const fn_call& fn);
+    template<bool utc> as_value date_setfullyear(const fn_call& fn);
+    template<bool utc> as_value date_setHours(const fn_call& fn);
+    template<bool utc> as_value date_setMilliseconds(const fn_call& fn);
+    template<bool utc> as_value date_setMinutes(const fn_call& fn);
+    template<bool utc> as_value date_setmonth(const fn_call& fn);
+    template<bool utc> as_value date_setSeconds(const fn_call& fn);
+    as_value date_setYear(const fn_call& fn);
+    as_value date_tostring(const fn_call& fn);
+    as_value date_valueof(const fn_call& fn);
+    as_value date_UTC(const fn_call& fn);
+
+    void fillGnashTime(double time, GnashTime& gt);
+    double makeTimeValue(GnashTime& gt);
+    void localTime(double time, GnashTime& gt);
+    void universalTime(double time, GnashTime& gt);
+    int localTimeZoneOffset(double time);
+
+    double rogue_date_args(const fn_call& fn, unsigned maxargs);
+    void localTime(double time, GnashTime& gt);
+    void universalTime(double time, GnashTime& gt);
+    template <typename T> void truncateDouble(T& target, double value);
+
+}
+
+Date_as::Date_as(double value)
+    :
+    as_object(getDateInterface()),
+    _value(value)
+{
+}
+
+std::string
+Date_as::toString() const
+{
+    const char* monthname[12] = { "Jan", "Feb", "Mar",
+                                  "Apr", "May", "Jun",
+                                  "Jul", "Aug", "Sep",
+                                  "Oct", "Nov", "Dec" };
+                                        
+    const char* dayweekname[7] = { "Sun", "Mon", "Tue", "Wed",
+                                   "Thu", "Fri", "Sat" };
+  
+    /// NaN and infinities all print as "Invalid Date"
+    if (isNaN(_value) || isInf(_value)) {
+        return "Invalid Date";
+    }
+  
+    // The date value split out to year, month, day, hour etc and millisecs
+    GnashTime gt;
+    // Time zone offset (including DST) as hours and minutes east of GMT
+
+    localTime(_value, gt);
+
+    int offsetHours = gt.timeZoneOffset / 60;
+    int offsetMinutes = gt.timeZoneOffset % 60;    
+  
+    // If timezone is negative, both hours and minutes will be negative
+    // but for the purpose of printing a string, only the hour needs to
+    // produce a minus sign.
+    if (offsetMinutes < 0) offsetMinutes = -offsetMinutes;
+  
+    boost::format dateFormat("%s %s %d %02d:%02d:%02d GMT%+03d%02d %d");
+    dateFormat % dayweekname[gt.weekday] % monthname[gt.month]
+               % gt.monthday % gt.hour % gt.minute % gt.second
+               % offsetHours % offsetMinutes % (gt.year + 1900);
+  
+    return dateFormat.str();
+  
+}
+
+void
+Date_as::init(as_object& global)
+{
+    // This is going to be the global Date "class"/"function"
+    static boost::intrusive_ptr<builtin_function> cl;
+
+    if ( cl == NULL ) {
+        cl = new builtin_function(&date_new, getDateInterface());
+        
+        // replicate static interface to class (Date.UTC)
+        attachDateStaticInterface(*cl);
+    }
+
+    // Register _global.Date
+    global.init_member("Date", cl.get());
+
+}
+
+void
+Date_as::registerNative(as_object& global)
 {
     VM& vm = global.getVM();
 
@@ -278,11 +277,63 @@
 
 }
 
+
+namespace {
+
+// Helpers for calendar algorithms
+inline bool
+isLeapYear(boost::int32_t year)
+{
+    return !((year + 1900) % 400) ||
+            ( !((year + 1900) % 4) && ((year + 1900) % 100));
+}
+
+
+inline size_t
+countLeapYears(boost::int32_t year)
+{
+    return (year - 70) / 4 - (year - 70) / 100 + (year - 70) / 400;
+}
+
+
+/// Return the broken-down time as a local time.
+void
+localTime(double time, GnashTime& gt)
+{
+    // find local timezone offset for the desired time.
+    gt.timeZoneOffset = localTimeZoneOffset(time);
+    fillGnashTime(time, gt);
+}
+
+/// Return the broken-down time as UTC
+void
+universalTime(double time, GnashTime& gt)
+{
+    // No time zone needed.
+    gt.timeZoneOffset = 0;
+    fillGnashTime(time, gt);
+}
+
+
+/// Safely truncate a double to an integer, returning the min()
+/// limit on overflow.
+template <typename T>
+void truncateDouble(T& target, double value)
+{
+    if (value < std::numeric_limits<T>::min() ||
+            value > std::numeric_limits<T>::max())
+    {
+        target = std::numeric_limits<T>::min();
+        return;
+    }
+    target = static_cast<T>(value);
+}
+
 // As UTC offset is measured in minutes, we can use the same
 // functions to get seconds and milliseconds in local and utc time.
 // But setting either of them can have a knock-on effect on minutes
 // and hours, so both need their own set functions.
-static void
+void
 attachDateInterface(as_object& o)
 {
     VM& vm = o.getVM();
@@ -328,14 +379,14 @@
 
 }   
 
-static void
+void
 attachDateStaticInterface(as_object& o)
 {
     VM& vm = o.getVM();
     o.init_member("UTC", vm.getNative(103, 257));
 }
 
-static as_object*
+as_object*
 getDateInterface()
 {
     static boost::intrusive_ptr<as_object> o;
@@ -348,45 +399,6 @@
 }
 
 
-as_value
-Date::toString() const
-{
-    const char* monthname[12] = { "Jan", "Feb", "Mar",
-                                  "Apr", "May", "Jun",
-                                  "Jul", "Aug", "Sep",
-                                  "Oct", "Nov", "Dec" };
-                                        
-    const char* dayweekname[7] = { "Sun", "Mon", "Tue", "Wed",
-                                   "Thu", "Fri", "Sat" };
-  
-    /// NaN and infinities all print as "Invalid Date"
-    if (isNaN(_value) || isInf(_value)) {
-        return as_value("Invalid Date");
-    }
-  
-    // The date value split out to year, month, day, hour etc and millisecs
-    GnashTime gt;
-    // Time zone offset (including DST) as hours and minutes east of GMT
-
-    localTime(_value, gt);
-
-    int offsetHours = gt.timeZoneOffset / 60;
-    int offsetMinutes = gt.timeZoneOffset % 60;    
-  
-    // If timezone is negative, both hours and minutes will be negative
-    // but for the purpose of printing a string, only the hour needs to
-    // produce a minus sign.
-    if (offsetMinutes < 0) offsetMinutes = -offsetMinutes;
-  
-    boost::format dateFormat("%s %s %d %02d:%02d:%02d GMT%+03d%02d %d");
-    dateFormat % dayweekname[gt.weekday] % monthname[gt.month]
-               % gt.monthday % gt.hour % gt.minute % gt.second
-               % offsetHours % offsetMinutes % (gt.year + 1900);
-  
-    return as_value(dateFormat.str());
-  
-}
-
 /// \brief Date constructor
 //
 /// The constructor has three forms: 0 args, 1 arg and 2-7 args.
@@ -405,7 +417,7 @@
 date_new(const fn_call& fn)
 {
 
-       boost::intrusive_ptr<Date> date;
+       boost::intrusive_ptr<Date_as> date;
 
     // Reject all date specifications containing Infinities and NaNs.
     // The commercial player does different things according to which
@@ -413,17 +425,17 @@
     // for now, we just use rogue_date_args' algorithm
     double foo;
     if (( foo = rogue_date_args(fn, 7)) != 0.0) {
-        date = new Date(foo);
+        date = new Date_as(foo);
         return as_value(date.get());
     }
 
     if (fn.nargs < 1 || fn.arg(0).is_undefined() || !(fn.isInstantiation()) ) {
         // Time now
-        date = new Date;
+        date = new Date_as;
     }
     else if (fn.nargs == 1) {
         // Set the value in milliseconds since 1970 UTC
-        date = new Date(fn.arg(0).to_number());
+        date = new Date_as(fn.arg(0).to_number());
     }
     else {
         // Create a time from the supplied (at least 2) arguments.
@@ -474,7 +486,7 @@
         // due to shortcomings in the timezoneoffset calculation, but should
         // be internally consistent.
         double localTime = makeTimeValue(gt);
-        date = new Date(localTime - clocktime::getTimeZoneOffset(localTime) * 
60000);
+        date = new Date_as(localTime - clocktime::getTimeZoneOffset(localTime) 
* 60000);
     }
     
     return as_value(date.get());
@@ -518,58 +530,58 @@
 /// Date.getYear()
 //
 /// Returns a Date's Gregorian year minus 1900 according to local time.
-static as_value
+as_value
 date_getYear(const fn_call& fn)
 {
-    boost::intrusive_ptr<Date> date = ensureType<Date>(fn.this_ptr);
+    boost::intrusive_ptr<Date_as> date = ensureType<Date_as>(fn.this_ptr);
     return timeElement(localTime, &GnashTime::year, date->getTimeValue());
 }
 
 /// \brief Date.getFullYear
 /// returns a Date's Gregorian year according to local time.
-static as_value
+as_value
 date_getFullYear(const fn_call& fn)
 {
-    boost::intrusive_ptr<Date> date = ensureType<Date>(fn.this_ptr);
+    boost::intrusive_ptr<Date_as> date = ensureType<Date_as>(fn.this_ptr);
     return timeElement(
             localTime, &GnashTime::year, date->getTimeValue(), 1900);
 }
 
 /// \brief Date.getMonth
 /// returns a Date's month in the range 0 to 11.
-static as_value
+as_value
 date_getMonth(const fn_call& fn)
 {
-    boost::intrusive_ptr<Date> date = ensureType<Date>(fn.this_ptr);
+    boost::intrusive_ptr<Date_as> date = ensureType<Date_as>(fn.this_ptr);
     return timeElement(localTime, &GnashTime::month, date->getTimeValue());
 }
 
 /// \brief Date.getDate
 /// returns a Date's day-of-month, from 1 to 31 according to local time.
-static as_value
+as_value
 date_getDate(const fn_call& fn)
 {
-    boost::intrusive_ptr<Date> date = ensureType<Date>(fn.this_ptr);
+    boost::intrusive_ptr<Date_as> date = ensureType<Date_as>(fn.this_ptr);
     return timeElement(localTime, &GnashTime::monthday, date->getTimeValue());
 }
 
 /// \brief Date.getDay
 /// returns the day of the week for a Date according to local time,
 /// where 0 is Sunday and 6 is Saturday.
-static as_value
+as_value
 date_getDay(const fn_call& fn)
 {
-    boost::intrusive_ptr<Date> date = ensureType<Date>(fn.this_ptr);
+    boost::intrusive_ptr<Date_as> date = ensureType<Date_as>(fn.this_ptr);
     return timeElement(localTime, &GnashTime::weekday, date->getTimeValue());
 }
 
 
 /// \brief Date.getHours
 /// Returns the hour number for a Date, from 0 to 23, according to local time.
-static as_value
+as_value
 date_getHours(const fn_call& fn)
 {
-    boost::intrusive_ptr<Date> date = ensureType<Date>(fn.this_ptr);
+    boost::intrusive_ptr<Date_as> date = ensureType<Date_as>(fn.this_ptr);
     return timeElement(localTime, &GnashTime::hour, date->getTimeValue());
 }
 
@@ -577,20 +589,20 @@
 /// returns a Date's minutes, from 0-59, according to localtime.
 /// (Yes, some places do have a fractions of an hour's timezone offset
 /// or daylight saving time!)
-static as_value
+as_value
 date_getMinutes(const fn_call& fn)
 {
-    boost::intrusive_ptr<Date> date = ensureType<Date>(fn.this_ptr);
+    boost::intrusive_ptr<Date_as> date = ensureType<Date_as>(fn.this_ptr);
     return timeElement(localTime, &GnashTime::minute, date->getTimeValue());
 }
 
 /// \brief Date.getSeconds
 /// returns a Date's seconds, from 0-59.
 /// Localtime should be irrelevant.
-static as_value
+as_value
 date_getSeconds(const fn_call& fn)
 {
-    boost::intrusive_ptr<Date> date = ensureType<Date>(fn.this_ptr);
+    boost::intrusive_ptr<Date_as> date = ensureType<Date_as>(fn.this_ptr);
     return timeElement(localTime, &GnashTime::second, date->getTimeValue());
 }
 
@@ -599,10 +611,10 @@
 /// Localtime is irrelevant!
 //
 // Also implements Date.getUTCMilliseconds
-static as_value
+as_value
 date_getMilliseconds(const fn_call& fn)
 {
-    boost::intrusive_ptr<Date> date = ensureType<Date>(fn.this_ptr);
+    boost::intrusive_ptr<Date_as> date = ensureType<Date_as>(fn.this_ptr);
     return timeElement(
             localTime, &GnashTime::millisecond, date->getTimeValue());
 }
@@ -610,64 +622,64 @@
 
 // The same functions for universal time.
 //
-static as_value
+as_value
 date_getUTCFullYear(const fn_call& fn)
 {
-    boost::intrusive_ptr<Date> date = ensureType<Date>(fn.this_ptr);
+    boost::intrusive_ptr<Date_as> date = ensureType<Date_as>(fn.this_ptr);
     return timeElement(universalTime, &GnashTime::year,
            date->getTimeValue(), 1900);
 }
 
-static as_value
+as_value
 date_getUTCYear(const fn_call& fn)
 {
-    boost::intrusive_ptr<Date> date = ensureType<Date>(fn.this_ptr);
+    boost::intrusive_ptr<Date_as> date = ensureType<Date_as>(fn.this_ptr);
     return timeElement(universalTime, &GnashTime::year, date->getTimeValue());
 }
 
-static as_value
+as_value
 date_getUTCMonth(const fn_call& fn)
 {
-    boost::intrusive_ptr<Date> date = ensureType<Date>(fn.this_ptr);
+    boost::intrusive_ptr<Date_as> date = ensureType<Date_as>(fn.this_ptr);
     return timeElement(universalTime, &GnashTime::month, date->getTimeValue());
 }
 
-static as_value
+as_value
 date_getutcdate(const fn_call& fn)
 {
-    boost::intrusive_ptr<Date> date = ensureType<Date>(fn.this_ptr);
+    boost::intrusive_ptr<Date_as> date = ensureType<Date_as>(fn.this_ptr);
     return timeElement(
             universalTime, &GnashTime::monthday, date->getTimeValue());
 }
 
     
-static as_value
+as_value
 date_getUTCDay(const fn_call& fn)
 {
-    boost::intrusive_ptr<Date> date = ensureType<Date>(fn.this_ptr);
+    boost::intrusive_ptr<Date_as> date = ensureType<Date_as>(fn.this_ptr);
     return timeElement(
                 universalTime, &GnashTime::weekday, date->getTimeValue());
 }
 
-static as_value
+as_value
 date_getUTCHours(const fn_call& fn)
 {
-    boost::intrusive_ptr<Date> date = ensureType<Date>(fn.this_ptr);
+    boost::intrusive_ptr<Date_as> date = ensureType<Date_as>(fn.this_ptr);
     return timeElement(
                 universalTime, &GnashTime::hour, date->getTimeValue());
 }
 
-static as_value
+as_value
 date_getUTCMinutes(const fn_call& fn)
 {
-    boost::intrusive_ptr<Date> date = ensureType<Date>(fn.this_ptr);
+    boost::intrusive_ptr<Date_as> date = ensureType<Date_as>(fn.this_ptr);
     return timeElement(universalTime, &GnashTime::minute, 
date->getTimeValue());
 }
 
 
 // Return the difference between UTC and localtime in minutes.
 inline int
-localTimeZoneOffset(const double& time)
+localTimeZoneOffset(double time)
 {
     // This simply has to return the difference in minutes
     // between UTC (Greenwich Mean Time, GMT) and the localtime.
@@ -680,10 +692,10 @@
 /// returns the difference between localtime and UTC that was in effect at the
 /// time specified by a Date object, according to local timezone and DST.
 /// For example, if you are in GMT+0100, the offset is -60
-static as_value
+as_value
 date_getTimezoneOffset(const fn_call& fn)
 {
-    boost::intrusive_ptr<Date> date = ensureType<Date>(fn.this_ptr);
+    boost::intrusive_ptr<Date_as> date = ensureType<Date_as>(fn.this_ptr);
     return as_value(-localTimeZoneOffset(date->getTimeValue()));
 }
 
@@ -695,10 +707,10 @@
 /// \brief Date.setTime
 /// sets a Date in milliseconds after January 1, 1970 00:00 UTC.
 /// The return value is the same as the parameter.
-static as_value
+as_value
 date_setTime(const fn_call& fn)
 {
-    boost::intrusive_ptr<Date> date = ensureType<Date>(fn.this_ptr);
+    boost::intrusive_ptr<Date_as> date = ensureType<Date_as>(fn.this_ptr);
 
     if (fn.nargs < 1) {
         IF_VERBOSE_ASCODING_ERRORS(
@@ -737,8 +749,8 @@
 // if an additional extra parameter is passed, switch to working in UTC
 // instead. Apart from the bottom-level conversions they are identical.
 
-static void
-gnashTimeToDate(GnashTime& gt, Date& date, bool utc)
+void
+gnashTimeToDate(GnashTime& gt, Date_as& date, bool utc)
 {
     // Needs timezone.
     if (utc) date.setTimeValue(makeTimeValue(gt));
@@ -750,8 +762,8 @@
     }
 }
 
-static void
-dateToGnashTime(Date& date, GnashTime& gt, bool utc)
+void
+dateToGnashTime(Date_as& date, GnashTime& gt, bool utc)
 {
     // Needs timezone.
     if (utc) universalTime(date.getTimeValue(), gt);
@@ -800,7 +812,7 @@
 as_value
 date_setfullyear(const fn_call& fn)
 {
-  boost::intrusive_ptr<Date> date = ensureType<Date>(fn.this_ptr);
+  boost::intrusive_ptr<Date_as> date = ensureType<Date_as>(fn.this_ptr);
 
   if (fn.nargs < 1) {
       IF_VERBOSE_ASCODING_ERRORS(
@@ -843,10 +855,10 @@
 ///   should end up at March 1st of the same year.
 //
 // There is no setUTCYear() function.
-static as_value
+as_value
 date_setYear(const fn_call& fn)
 {
-    boost::intrusive_ptr<Date> date = ensureType<Date>(fn.this_ptr);
+    boost::intrusive_ptr<Date_as> date = ensureType<Date_as>(fn.this_ptr);
 
     // assert(fn.nargs == 1);
     if (fn.nargs < 1) {
@@ -897,7 +909,7 @@
 as_value
 date_setmonth(const fn_call& fn)
 {
-    boost::intrusive_ptr<Date> date = ensureType<Date>(fn.this_ptr);
+    boost::intrusive_ptr<Date_as> date = ensureType<Date_as>(fn.this_ptr);
 
     // assert(fn.nargs >= 1 && fn.nargs <= 2);
     if (fn.nargs < 1) {
@@ -953,7 +965,7 @@
 as_value
 date_setDate(const fn_call& fn)
 {
-  boost::intrusive_ptr<Date> date = ensureType<Date>(fn.this_ptr);
+  boost::intrusive_ptr<Date_as> date = ensureType<Date_as>(fn.this_ptr);
 
   if (fn.nargs < 1) {
       IF_VERBOSE_ASCODING_ERRORS(
@@ -993,7 +1005,7 @@
 as_value
 date_setHours(const fn_call& fn)
 {
-    boost::intrusive_ptr<Date> date = ensureType<Date>(fn.this_ptr);
+    boost::intrusive_ptr<Date_as> date = ensureType<Date_as>(fn.this_ptr);
 
     // assert(fn.nargs >= 1 && fn.nargs <= 4);
     if (fn.nargs < 1) {
@@ -1038,7 +1050,7 @@
 as_value
 date_setMinutes(const fn_call& fn)
 {
-    boost::intrusive_ptr<Date> date = ensureType<Date>(fn.this_ptr);
+    boost::intrusive_ptr<Date_as> date = ensureType<Date_as>(fn.this_ptr);
 
     //assert(fn.nargs >= 1 && fn.nargs <= 3);
     if (fn.nargs < 1) {
@@ -1079,7 +1091,7 @@
 as_value
 date_setSeconds(const fn_call& fn)
 {
-    boost::intrusive_ptr<Date> date = ensureType<Date>(fn.this_ptr);
+    boost::intrusive_ptr<Date_as> date = ensureType<Date_as>(fn.this_ptr);
 
     // assert(fn.nargs >= 1 && fn.nargs <= 2);
     if (fn.nargs < 1) {
@@ -1118,7 +1130,7 @@
 as_value
 date_setMilliseconds(const fn_call& fn)
 {
-    boost::intrusive_ptr<Date> date = ensureType<Date>(fn.this_ptr);
+    boost::intrusive_ptr<Date_as> date = ensureType<Date_as>(fn.this_ptr);
 
     if (fn.nargs < 1) {
         IF_VERBOSE_ASCODING_ERRORS(
@@ -1157,11 +1169,11 @@
 /// convert a Date to a printable string.
 /// The format is "Thu Jan 1 00:00:00 GMT+0000 1970" and it is displayed in
 /// local time.
-static as_value
+as_value
 date_tostring(const fn_call& fn) 
 {
-    boost::intrusive_ptr<Date> date = ensureType<Date>(fn.this_ptr);
-    return date->toString();
+    boost::intrusive_ptr<Date_as> date = ensureType<Date_as>(fn.this_ptr);
+    return as_value(date->toString());
 }
 
 // Date.UTC(year:Number,month[,day[,hour[,minute[,second[,millisecond]]]]]
@@ -1194,7 +1206,7 @@
 //
 // We test for < 2 parameters and return undefined, but given any other
 // non-numeric arguments we give NaN.
-static as_value
+as_value
 date_UTC(const fn_call& fn) {
 
     GnashTime gt; // Date structure for values down to milliseconds
@@ -1256,7 +1268,7 @@
 // returns 0.0 if there are none,
 // plus (or minus) infinity if positive (or negative) infinites are present,
 // NaN is there are NaNs present, or a mixture of positive and negative infs.
-static double
+double
 rogue_date_args(const fn_call& fn, unsigned maxargs)
 {
   // Two flags: Did we find any +Infinity (or -Infinity) values in the
@@ -1301,36 +1313,18 @@
 /// \brief Date.valueOf() returns the number of milliseconds since midnight
 /// January 1, 1970 00:00 UTC, for a Date. The return value can be a fractional
 /// number of milliseconds.
-static as_value
+as_value
 date_valueof(const fn_call& fn)
 {
-    boost::intrusive_ptr<Date> date = ensureType<Date>(fn.this_ptr);
-    return as_value(date->getTimeValue());
-}
-
-
-static as_value date_getTime(const fn_call& fn)
-{
-    boost::intrusive_ptr<Date> date = ensureType<Date>(fn.this_ptr);
-    return as_value(date->getTimeValue());
-}
-
-// extern (used by Global.cpp)
-void date_class_init(as_object& global)
-{
-    // This is going to be the global Date "class"/"function"
-    static boost::intrusive_ptr<builtin_function> cl;
-
-    if ( cl == NULL ) {
-        cl = new builtin_function(&date_new, getDateInterface());
-        
-        // replicate static interface to class (Date.UTC)
-        attachDateStaticInterface(*cl);
-    }
-
-    // Register _global.Date
-    global.init_member("Date", cl.get());
-
+    boost::intrusive_ptr<Date_as> date = ensureType<Date_as>(fn.this_ptr);
+    return as_value(date->getTimeValue());
+}
+
+
+as_value date_getTime(const fn_call& fn)
+{
+    boost::intrusive_ptr<Date_as> date = ensureType<Date_as>(fn.this_ptr);
+    return as_value(date->getTimeValue());
 }
 
 ///
@@ -1346,7 +1340,7 @@
 // haven't really looked at it.
 // The first algorithm appears to mimic flash behaviour for
 // all dates, though it's a bit ugly.
-static double
+double
 makeTimeValue(GnashTime& t)
 {
 
@@ -1433,7 +1427,8 @@
 }
 
 
-void fillGnashTime(const double& t, GnashTime& gt)
+void
+fillGnashTime(double t, GnashTime& gt)
 {
 
     // Calculate local time by adding offset from UTC in
@@ -1490,11 +1485,5 @@
 
 }
 
-// external
-as_object*
-init_date_instance(double val)
-{
-    return new Date(val);
-}
-
-} // end of gnash namespace
+} // anonymous namespace
+} // gnash namespace

=== renamed file 'libcore/asobj/Date.h' => 'libcore/asobj/Date_as.h'
--- a/libcore/asobj/Date.h      2008-12-30 19:08:52 +0000
+++ b/libcore/asobj/Date_as.h   2008-12-31 12:53:47 +0000
@@ -20,14 +20,34 @@
 
 #include "as_object.h" // for inheritance
 #include "fn_call.h" // for inheritance
+#include "ClockTime.h"
 
 namespace gnash {
 
-void registerDateNative(as_object& global);
-
-void date_class_init(as_object& global);
-
-as_object* init_date_instance(double value);
+class Date_as : public as_object
+{
+public:
+
+    explicit Date_as(double value = clocktime::getTicks());
+
+    void setTimeValue(const double& value) { _value = value; }
+
+    double getTimeValue() const { return _value; }
+
+    static void registerNative(as_object& global);
+
+    static void init(as_object& where);
+
+    std::string toString() const;
+
+    bool isDateObject() { return true; }
+
+private:
+
+    double _value;
+
+};
+
 
 } // end of gnash namespace
 

=== modified file 'libcore/asobj/Global.cpp'
--- a/libcore/asobj/Global.cpp  2008-12-27 19:56:32 +0000
+++ b/libcore/asobj/Global.cpp  2008-12-31 12:53:47 +0000
@@ -33,7 +33,7 @@
 #include "Color_as.h"
 #include "ContextMenu.h"
 #include "CustomActions.h"
-#include "Date.h" // for registerDateNative
+#include "Date_as.h" // for registerDateNative
 #include "Error_as.h"
 #include "Global.h"
 #include "String_as.h"
@@ -688,7 +688,6 @@
     vm.registerNative(timer_clearinterval, 250, 1);
 
     registerSelectionNative(global);
-    registerDateNative(global);
     registerColorNative(global);
     registerMathNative(global);
     registerSystemNative(global);
@@ -696,6 +695,7 @@
     registerSharedObjectNative(global);
 
     TextFormat_as::registerNative(global);
+    Date_as::registerNative(global);
     Mouse_as::registerNative(global);
 
     // LoadableObject has natives shared between LoadVars and XML, so 

=== modified file 'libcore/asobj/Makefile.am'
--- a/libcore/asobj/Makefile.am 2008-12-27 19:56:32 +0000
+++ b/libcore/asobj/Makefile.am 2008-12-31 12:53:47 +0000
@@ -51,7 +51,7 @@
        Color_as.cpp \
        ContextMenu.cpp \
        CustomActions.cpp\
-       Date.cpp \
+       Date_as.cpp \
        Error_as.cpp \
        Global.cpp \
        Key_as.cpp      \
@@ -117,7 +117,7 @@
        Color_as.h      \
        ContextMenu.h \
        CustomActions.h \
-       Date.h \
+       Date_as.h \
        Error_as.h      \
        Math_as.h       \
        Global.h\

=== modified file 'libcore/asobj/SharedObject_as.cpp'
--- a/libcore/asobj/SharedObject_as.cpp 2008-12-25 23:00:23 +0000
+++ b/libcore/asobj/SharedObject_as.cpp 2009-01-02 12:00:13 +0000
@@ -84,12 +84,12 @@
     as_value sharedobject_getLocal(const fn_call& fn);
     as_value sharedobject_ctor(const fn_call& fn);
 
-    
     as_object* readSOL(VM& vm, const std::string& filespec);
 
     as_object* getSharedObjectInterface();
     void attachSharedObjectStaticInterface(as_object& o);
     bool createDirForFile(const std::string& filespec);
+    void flushSOL(SharedObjectLibrary::SoLib::value_type& sol);
     bool validateName(const std::string& solName);
 }
 
@@ -298,12 +298,9 @@
     SOL _sol;
 };
 
+
 SharedObject_as::~SharedObject_as()
 {
-    /// This apparently used to cause problems if the VM no longer exists on
-    /// destruction. It certainly would. However, it *has* to be done, so if it
-    /// still causes problems, it must be fixed another way than not doing it.
-    flush();
 }
 
 
@@ -416,8 +413,7 @@
 
 SharedObjectLibrary::SharedObjectLibrary(VM& vm)
     :
-    _vm(vm),
-    _soLib()
+    _vm(vm)
 {
     _solSafeDir = rcfile.getSOLSafeDir();
     if (_solSafeDir.empty()) {
@@ -488,6 +484,22 @@
     }
 }
 
+/// The SharedObjectLibrary keeps all known SharedObjects alive. They must
+/// be flushed on clear(). This is called at the latest by the dtor, which
+/// is called at the latest by VM's dtor (currently earlier to avoid problems
+/// with the GC).
+void
+SharedObjectLibrary::clear()
+{
+    std::for_each(_soLib.begin(), _soLib.end(), &flushSOL);
+    _soLib.clear();
+}
+
+SharedObjectLibrary::~SharedObjectLibrary()
+{
+    clear();
+}
+
 SharedObject_as*
 SharedObjectLibrary::getLocal(const std::string& objName,
         const std::string& root)
@@ -1093,6 +1105,14 @@
 #endif
 }
 
+
+void
+flushSOL(SharedObjectLibrary::SoLib::value_type& sol)
+{
+    sol.second->flush();
+}
+
+
 bool
 createDirForFile(const std::string& filename)
 {

=== modified file 'libcore/asobj/SharedObject_as.h'
--- a/libcore/asobj/SharedObject_as.h   2008-12-19 08:23:56 +0000
+++ b/libcore/asobj/SharedObject_as.h   2009-01-02 12:00:13 +0000
@@ -35,8 +35,12 @@
 {
 public:
 
+    typedef std::map<std::string, SharedObject_as*> SoLib;
+
     SharedObjectLibrary(VM& vm);
 
+    ~SharedObjectLibrary();
+
     /// Return a local shared object with given name and with given root
     //
     /// May return NULL if name is invalid or can't access the given root
@@ -46,7 +50,7 @@
     void markReachableResources() const;
 
     // Drop all library items
-    void clear() { _soLib.clear(); }
+    void clear();
 
 private:
 
@@ -61,8 +65,6 @@
     /// Base SOL dir
     std::string _solSafeDir; 
 
-    typedef std::map<std::string, SharedObject_as*> SoLib;
-
     SoLib _soLib;
 };
 

=== modified file 'libcore/asobj/String_as.cpp'
--- a/libcore/asobj/String_as.cpp       2008-12-27 19:56:32 +0000
+++ b/libcore/asobj/String_as.cpp       2008-12-31 12:53:47 +0000
@@ -76,7 +76,7 @@
 
 public:
 
-    String_as(const std::string& s)
+    explicit String_as(const std::string& s)
             :
             as_object(getStringInterface()),
             _string(s)

=== modified file 'libcore/impl.cpp'
--- a/libcore/impl.cpp  2008-12-16 14:02:37 +0000
+++ b/libcore/impl.cpp  2009-01-02 12:00:13 +0000
@@ -471,7 +471,10 @@
     //
     // See task task #6959 and depending items
     //
-    log_debug("Any segfault past this message is likely due to improper 
threads cleanup.");
+    log_debug("Any segfault past this message is likely due to improper "
+            "threads cleanup.");
+
+    VM::get().clear();
 
     clear_library();
     fontlib::clear();

=== modified file 'libcore/vm/VM.cpp'
--- a/libcore/vm/VM.cpp 2008-12-19 08:23:56 +0000
+++ b/libcore/vm/VM.cpp 2009-01-02 12:00:13 +0000
@@ -97,17 +97,13 @@
 
 VM::~VM()
 {
-    delete _shLib;
 }
 
-std::locale&
-VM::getLocale() const
+void
+VM::clear()
 {
-       // TODO: some research about what we should be using.
-       //       IIRC older SWF contained some tags for this,
-       //       while new SWF uses UNICODE...
-       static std::locale loc("C");
-       return loc;
+    /// Reset the SharedObjectLibrary, so that SOLs are flushed.
+    _shLib.reset();
 }
 
 int
@@ -241,7 +237,7 @@
 
        mClassHierarchy->markReachableResources();
 
-    _shLib->markReachableResources();
+    if (_shLib.get()) _shLib->markReachableResources();
 #endif
 
 }

=== modified file 'libcore/vm/VM.h'
--- a/libcore/vm/VM.h   2008-11-20 15:22:13 +0000
+++ b/libcore/vm/VM.h   2009-01-02 12:00:13 +0000
@@ -90,73 +90,6 @@
 
        typedef as_value (*as_c_function_ptr)(const fn_call& fn);
 
-private:
-
-       friend class VmGcRoot;
-
-       /// Use VM::get() to access the singleton
-       //
-       /// Initializes the GC singleton
-       ///
-       VM(int version, movie_root& root, VirtualClock& clock);
-
-       /// Should deinitialize the GC singleton
-       /// If it doesn't is just because it corrupts memory :)
-       ~VM();
-
-       // We use an auto_ptr here to allow constructing
-       // the singleton when the init() function is called.
-       friend class std::auto_ptr<VM>;
-       static std::auto_ptr<VM> _singleton;
-
-       /// Stage associated with this VM
-       movie_root& _rootMovie;
-
-       /// The _global ActionScript object
-       boost::intrusive_ptr<as_object> _global;
-
-       /// Target SWF version
-       int _swfversion;
-
-       /// Set the _global Object for actions run by Virtual Machine
-       //
-       /// Will be called by the init() function
-       /// 
-       void setGlobal(as_object*);
-
-#ifdef GNASH_USE_GC
-       /// A vector of static GcResources (tipically used for built-in class 
constructors)
-       //
-       /// The resources in this list will always be marked as reachable
-       ///
-       typedef std::vector< boost::intrusive_ptr<GcResource> > ResVect;
-       ResVect _statics;
-#endif
-
-       typedef std::map<unsigned int, as_c_function_ptr> FuncMap;
-       typedef std::map<unsigned int, FuncMap> AsNativeTable;
-       AsNativeTable _asNativeTable;
-
-       /// Mutable since it should not affect how the VM runs.
-       mutable string_table mStringTable;
-
-       /// Not mutable since changing this changes behavior of the VM.
-       std::auto_ptr<ClassHierarchy> mClassHierarchy;
-
-       /// A running execution thread.
-       Machine *mMachine;
-
-       VirtualClock& _clock;
-
-       SafeStack<as_value>     _stack;
-
-       CallStack _callStack;
-
-       /// Library of SharedObjects. Owned by the VM.
-       SharedObjectLibrary* _shLib;
-
-public:
-
        SafeStack<as_value>& getStack()
        {
                return _stack;
@@ -189,6 +122,17 @@
        /// Return true if the singleton VM has been initialized
        static bool isInitialized();
 
+    /// Resets any VM members that must be cleared before the GC cleans up
+    //
+    /// At present, this is:
+    /// - SharedObjectLibrary
+    ///
+    /// Ideally, this would be left to the VM's dtor, but we have no control
+    /// over destruction order at present.
+    /// It is assumed that this is the last VM function called before the
+    /// dtor.
+    void clear();
+
        /// Get the singleton instance of the virtual machine
        //
        /// Make sure you called VM::init() before trying to
@@ -263,7 +207,12 @@
        /// Get a pointer to this VM's Root movie (stage)
        movie_root& getRoot() const;
 
+    /// Return the Shared Object Library
+    //
+    /// The Shared Object Library is assumed to exist until VM::clear()
+    /// is called.
     SharedObjectLibrary& getSharedObjectLibrary() const {
+        assert(_shLib.get());
         return *_shLib;
     }
 
@@ -273,9 +222,6 @@
        /// Get a pointer to this VM's global ClassHierarchy object.
        ClassHierarchy* getClassHierarchy() const { return 
mClassHierarchy.get(); }
        
-       /// Get the SWF locale to use 
-       std::locale& getLocale() const;
-
        /// Mark all reachable resources (for GC)
        //
        /// - root movie / stage (_rootMovie)
@@ -302,6 +248,71 @@
        void addStatic(as_object*) {}
 #endif
 
+private:
+
+       friend class VmGcRoot;
+
+       /// Use VM::get() to access the singleton
+       //
+       /// Initializes the GC singleton
+       ///
+       VM(int version, movie_root& root, VirtualClock& clock);
+
+       /// Should deinitialize the GC singleton
+       /// If it doesn't is just because it corrupts memory :)
+       ~VM();
+
+       // We use an auto_ptr here to allow constructing
+       // the singleton when the init() function is called.
+       friend class std::auto_ptr<VM>;
+       static std::auto_ptr<VM> _singleton;
+
+       /// Stage associated with this VM
+       movie_root& _rootMovie;
+
+       /// The _global ActionScript object
+       boost::intrusive_ptr<as_object> _global;
+
+       /// Target SWF version
+       int _swfversion;
+
+       /// Set the _global Object for actions run by Virtual Machine
+       //
+       /// Will be called by the init() function
+       /// 
+       void setGlobal(as_object*);
+
+#ifdef GNASH_USE_GC
+       /// A vector of static GcResources (tipically used for built-in class 
constructors)
+       //
+       /// The resources in this list will always be marked as reachable
+       ///
+       typedef std::vector< boost::intrusive_ptr<GcResource> > ResVect;
+       ResVect _statics;
+#endif
+
+       typedef std::map<unsigned int, as_c_function_ptr> FuncMap;
+       typedef std::map<unsigned int, FuncMap> AsNativeTable;
+       AsNativeTable _asNativeTable;
+
+       /// Mutable since it should not affect how the VM runs.
+       mutable string_table mStringTable;
+
+       /// Not mutable since changing this changes behavior of the VM.
+       std::auto_ptr<ClassHierarchy> mClassHierarchy;
+
+       /// A running execution thread.
+       Machine *mMachine;
+
+       VirtualClock& _clock;
+
+       SafeStack<as_value>     _stack;
+
+       CallStack _callStack;
+
+       /// Library of SharedObjects. Owned by the VM.
+    std::auto_ptr<SharedObjectLibrary> _shLib;
+
 };
 
 } // namespace gnash

=== modified file 'testsuite/misc-ming.all/SharedObjectTest.as'
--- a/testsuite/misc-ming.all/SharedObjectTest.as       2008-12-31 23:18:11 
+0000
+++ b/testsuite/misc-ming.all/SharedObjectTest.as       2009-01-02 12:48:38 
+0000
@@ -186,6 +186,14 @@
 
 so1.data.lstr = lstr;
 
+f = new Date(0);
+f.valueOf = function() { return "Overridden date"; };
+so1.data.fakedate = f;
+
+g = new Date(0);
+g.valueOf = function() { return 35; };
+so1.data.fakedate2 = g;
+
 so1.flush();
 
 quit = function()

=== removed file 'testsuite/misc-ming.all/SharedObjectTest.sol/sol1.sol'
Binary files a/testsuite/misc-ming.all/SharedObjectTest.sol/sol1.sol    
2008-12-31 23:18:11 +0000 and 
b/testsuite/misc-ming.all/SharedObjectTest.sol/sol1.sol   1970-01-01 00:00:00 
+0000 differ

reply via email to

[Prev in Thread] Current Thread [Next in Thread]