gnash-commit
[Top][All Lists]
Advanced

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

[Gnash-commit] /srv/bzr/gnash/trunk r11343: Fix a bug. Correct some prop


From: Benjamin Wolsey
Subject: [Gnash-commit] /srv/bzr/gnash/trunk r11343: Fix a bug. Correct some properties for swfdec testsuite passes.
Date: Thu, 30 Jul 2009 17:47:14 +0200
User-agent: Bazaar (1.13.1)

------------------------------------------------------------
revno: 11343
committer: Benjamin Wolsey <address@hidden>
branch nick: trunk
timestamp: Thu 2009-07-30 17:47:14 +0200
message:
  Fix a bug. Correct some properties for swfdec testsuite passes.
added:
  testsuite/as3compile.all/Object.as
modified:
  libbase/GnashAlgorithm.h
  libcore/PropertyList.cpp
  libcore/as_object.cpp
  libcore/as_object.h
  libcore/asobj/Globals.cpp
  libcore/asobj/Object.cpp
  libcore/asobj/Object.h
  libcore/vm/ASHandlers.cpp
  testsuite/as3compile.all/Makefile.am
  testsuite/swfdec/PASSING
    ------------------------------------------------------------
    revno: 11342.1.1
    committer: Benjamin Wolsey <address@hidden>
    branch nick: temp
    timestamp: Thu 2009-07-30 12:36:03 +0200
    message:
      Test AVM2 Object.
    modified:
      testsuite/as3compile.all/Makefile.am
    ------------------------------------------------------------
    revno: 11342.1.2
    committer: Benjamin Wolsey <address@hidden>
    branch nick: temp
    timestamp: Thu 2009-07-30 13:20:20 +0200
    message:
      Add Object test, notes, more tests.
    added:
      testsuite/as3compile.all/Object.as
    modified:
      libcore/PropertyList.cpp
    ------------------------------------------------------------
    revno: 11342.1.3
    committer: Benjamin Wolsey <address@hidden>
    branch nick: temp
    timestamp: Thu 2009-07-30 13:33:29 +0200
    message:
      Register object natives separately. Get registerClass properties correct.
    modified:
      libcore/asobj/Globals.cpp
      libcore/asobj/Object.cpp
      libcore/asobj/Object.h
    ------------------------------------------------------------
    revno: 11342.1.4
    committer: Benjamin Wolsey <address@hidden>
    branch nick: temp
    timestamp: Thu 2009-07-30 14:21:34 +0200
    message:
      Correct Object properties. Add constructor also for VM opcode, though it
      currently doesn't have the correct value.
    modified:
      libcore/asobj/Object.cpp
      libcore/vm/ASHandlers.cpp
    ------------------------------------------------------------
    revno: 11342.1.5
    committer: Benjamin Wolsey <address@hidden>
    branch nick: temp
    timestamp: Thu 2009-07-30 15:11:28 +0200
    message:
      Get object properties correct.
    modified:
      libcore/asobj/Object.cpp
      libcore/vm/ASHandlers.cpp
    ------------------------------------------------------------
    revno: 11342.1.6
    committer: Benjamin Wolsey <address@hidden>
    branch nick: temp
    timestamp: Thu 2009-07-30 15:51:21 +0200
    message:
      Passing tests.
    modified:
      testsuite/swfdec/PASSING
    ------------------------------------------------------------
    revno: 11342.1.7
    committer: Benjamin Wolsey <address@hidden>
    branch nick: temp
    timestamp: Thu 2009-07-30 17:20:46 +0200
    message:
      Don't erase Triggers from the container while they are still being 
accessed.
      use a flag instead. Fixes a memory error that's been in Gnash at least 
since
      0.8.5.
    modified:
      libbase/GnashAlgorithm.h
      libcore/as_object.cpp
      libcore/as_object.h
=== modified file 'libbase/GnashAlgorithm.h'
--- a/libbase/GnashAlgorithm.h  2009-04-15 15:30:11 +0000
+++ b/libbase/GnashAlgorithm.h  2009-07-30 15:20:46 +0000
@@ -72,6 +72,22 @@
     typedef typename RemovePointer<T>::value_type value_type;
 };
 
+/// Erase elements from an associative container based on a predicate
+//
+/// This removes elements from a container such as a map if they fulfil a
+/// particular condition. Because keys of associative container are const,
+/// we can't do this using iterators, because we can't write to them.
+template<typename Container, typename Predicate>
+void EraseIf(Container& c, Predicate p)
+{
+    typedef typename Container::iterator iterator;
+
+    for (iterator i = c.begin(), e = c.end(); i != e; ) {
+        iterator stored = i++;
+        if (p(*stored)) c.erase(stored);
+    }
+}
+
 
 
 /// Delete a pointer safely

=== modified file 'libcore/PropertyList.cpp'
--- a/libcore/PropertyList.cpp  2009-07-29 14:33:56 +0000
+++ b/libcore/PropertyList.cpp  2009-07-30 11:20:20 +0000
@@ -31,6 +31,7 @@
 #include "string_table.h"
 
 #include <utility> // for std::make_pair
+#include <boost/bind.hpp> 
 
 // Define the following to enable printing address of each property added
 //#define DEBUG_PROPERTY_ALLOC
@@ -540,12 +541,9 @@
 void
 PropertyList::setReachable() const
 {
-       for (container::const_iterator it = _props.begin();
-                       it != _props.end(); ++it)
-       {
-               it->setReachable();
-       }
+    std::for_each(_props.begin(), _props.end(),
+            boost::mem_fn(&Property::setReachable));
 }
 
-} // end of gnash namespace
+} // namespace gnash
 

=== modified file 'libcore/as_object.cpp'
--- a/libcore/as_object.cpp     2009-07-29 14:33:56 +0000
+++ b/libcore/as_object.cpp     2009-07-30 15:20:46 +0000
@@ -37,6 +37,7 @@
 #include "Array_as.h"
 #include "as_function.h"
 #include "Global_as.h" 
+#include "GnashAlgorithm.h"
 
 #include <set>
 #include <string>
@@ -585,7 +586,6 @@
        return NULL;
 }
 
-/*protected*/
 void
 as_object::set_prototype(boost::intrusive_ptr<as_object> proto, int flags)
 {
@@ -642,6 +642,11 @@
 
     Trigger& trig = trigIter->second;
 
+    if (trig.dead()) {
+        _trigs.erase(trigIter);
+        return;
+    }
+
     // WARNING: getValue might itself invoke a trigger
     // (getter-setter)... ouch ?
     // TODO: in this case, return the underlying value !
@@ -653,7 +658,11 @@
             getStringTable(*this).value(getName(uri)), curVal, val);
 
     as_value newVal = trig.call(curVal, val, *this);
-
+    
+    // This is a particularly clear and concise way of removing dead triggers.
+    EraseIf(_trigs, boost::bind(boost::mem_fn(&Trigger::dead), 
+            boost::bind(SecondElement<TriggerContainer::value_type>(), _1)));
+                    
     // The trigger call could have deleted the property,
     // so we check for its existance again, and do NOT put
     // it back in if it was deleted
@@ -666,7 +675,7 @@
     }
     prop->setValue(*this, newVal); 
     prop->clearVisible(getSWFVersion(*this));
-
+    
 }
 
 // Handles read_only and static properties properly.
@@ -1362,7 +1371,7 @@
                 getStringTable(*this).value(key));
                return false;
        }
-       _trigs.erase(trigIter);
+       trigIter->second.kill();
        return true;
 }
 
@@ -1391,6 +1400,8 @@
 Trigger::call(const as_value& oldval, const as_value& newval,
         as_object& this_obj)
 {
+    assert(!_dead);
+
        if ( _executing ) return newval;
 
        _executing = true;

=== modified file 'libcore/as_object.h'
--- a/libcore/as_object.h       2009-07-29 14:33:56 +0000
+++ b/libcore/as_object.h       2009-07-30 15:20:46 +0000
@@ -67,25 +67,6 @@
 /// A trigger that can be associated with a property name
 class Trigger
 {
-    /// Name of the property
-    //
-    /// By storing a string_table::key we'd save CPU cycles
-    /// while adding/removing triggers and some memory
-    /// on each trigger, but at the cost of looking up
-    /// the string_table on every invocation of the watch...
-    ///
-    std::string _propname;
-
-    /// The trigger function 
-    as_function* _func;
-
-    /// A custom argument to pass to the trigger
-    /// after old and new value.
-    as_value _customArg;
-
-    /// Flag to protect from infinite loops
-    bool _executing;
-
 public:
 
     Trigger(const std::string& propname, as_function& trig,
@@ -94,7 +75,8 @@
         _propname(propname),
         _func(&trig),
         _customArg(customArg),
-        _executing(false)
+        _executing(false),
+        _dead(false)
     {}
 
     /// Call the trigger
@@ -111,8 +93,43 @@
     as_value call(const as_value& oldval, const as_value& newval, 
             as_object& this_obj);
 
+    /// True if this Trigger has been disposed of.
+    bool dead() const { return _dead; }
+
+    void kill() {
+        _dead = true;
+    }
+
     void setReachable() const;
 
+private:
+
+    /// Name of the property
+    //
+    /// By storing a string_table::key we'd save CPU cycles
+    /// while adding/removing triggers and some memory
+    /// on each trigger, but at the cost of looking up
+    /// the string_table on every invocation of the watch...
+    ///
+    std::string _propname;
+
+    /// The trigger function 
+    as_function* _func;
+
+    /// A custom argument to pass to the trigger
+    /// after old and new value.
+    as_value _customArg;
+
+    /// Flag to protect from infinite loops
+    bool _executing;
+
+    /// Flag to check whether this trigger has been deleted.
+    //
+    /// As a trigger can be removed during execution, it shouldn't be
+    /// erased from the container straight away, so this flag prevents
+    /// any execution.
+    bool _dead;
+
 };
 
 /// A URI for describing as_objects.

=== modified file 'libcore/asobj/Globals.cpp'
--- a/libcore/asobj/Globals.cpp 2009-07-29 14:55:35 +0000
+++ b/libcore/asobj/Globals.cpp 2009-07-30 11:33:29 +0000
@@ -1159,6 +1159,7 @@
     vm.registerNative(global_setInterval, 250, 0);
     vm.registerNative(global_clearInterval, 250, 1);
 
+    registerObjectNative(global);
     registerStringNative(global);
     registerArrayNative(global);
     registerMovieClipNative(global);

=== modified file 'libcore/asobj/Object.cpp'
--- a/libcore/asobj/Object.cpp  2009-07-29 05:40:20 +0000
+++ b/libcore/asobj/Object.cpp  2009-07-30 13:11:28 +0000
@@ -61,31 +61,51 @@
        return new as_object(getObjectInterface());
 }
 
+void registerObjectNative(as_object& global)
+{
+    VM& vm = getVM(global);
+
+       vm.registerNative(object_watch, 101, 0); 
+       vm.registerNative(object_unwatch, 101, 1); 
+       vm.registerNative(object_addproperty, 101, 2); 
+       vm.registerNative(as_object::valueof_method, 101, 3); 
+       vm.registerNative(as_object::tostring_method, 101, 4); 
+       vm.registerNative(object_hasOwnProperty, 101, 5); 
+       vm.registerNative(object_isPrototypeOf, 101, 6); 
+       vm.registerNative(object_isPropertyEnumerable, 101, 7); 
+       vm.registerNative(object_registerClass, 101, 8);
+       vm.registerNative(object_ctor, 101, 9);
+}
 
 // extern (used by Global.cpp)
-void object_class_init(as_object& global, const ObjectURI& uri)
+void
+object_class_init(as_object& where, const ObjectURI& uri)
 {
        // This is going to be the global Object "class"/"function"
        static boost::intrusive_ptr<as_object> cl=NULL;
 
-    VM& vm = getVM(global);
-
        if ( cl == NULL )
        {
-        Global_as* gl = getGlobal(global);
+        Global_as* gl = getGlobal(where);
         as_object* proto = getObjectInterface();
-        cl = gl->createClass(&object_ctor, proto);
-
-               // Object.registerClass() --
-        // TODO: should this only be in SWF6 or higher ?
-               vm.registerNative(object_registerClass, 101, 8);
-               cl->init_member("registerClass", vm.getNative(101, 8));
+        cl = gl->createClass(object_ctor, proto);
+
+        // The as_function ctor takes care of initializing these, but they
+        // are different for the Object class.
+        const int readOnly = PropFlags::readOnly;
+        cl->set_member_flags(NSV::PROP_uuPROTOuu, readOnly);
+        cl->set_member_flags(NSV::PROP_CONSTRUCTOR, readOnly);
+        cl->set_member_flags(NSV::PROP_PROTOTYPE, readOnly);
+
+        VM& vm = getVM(where);
+        const int flags = as_object::DefaultFlags | PropFlags::readOnly;
+               cl->init_member("registerClass", vm.getNative(101, 8), flags);
                     
        }
 
        // Register _global.Object (should only be visible in SWF5 up)
        int flags = PropFlags::dontEnum; 
-       global.init_member(getName(uri), cl.get(), flags, getNamespace(uri));
+       where.init_member(getName(uri), cl.get(), flags, getNamespace(uri));
 
 }
 
@@ -113,22 +133,18 @@
        VM& vm = getVM(o);
 
        // We register natives despite swf version,
-
-       vm.registerNative(object_watch, 101, 0); 
-       vm.registerNative(object_unwatch, 101, 1); 
-       vm.registerNative(object_addproperty, 101, 2); 
-       vm.registerNative(as_object::valueof_method, 101, 3); 
-       vm.registerNative(as_object::tostring_method, 101, 4); 
-       vm.registerNative(object_hasOwnProperty, 101, 5); 
-       vm.registerNative(object_isPrototypeOf, 101, 6); 
-       vm.registerNative(object_isPropertyEnumerable, 101, 7); 
-
     Global_as* gl = getGlobal(o);
 
        o.init_member("valueOf", vm.getNative(101, 3));
        o.init_member("toString", vm.getNative(101, 4));
+
+    as_object* lsProto = getObjectInterface();
+
+    // TODO: this is probably an abuse of the 'createClass' function, but it
+    // gets the correct results.
        o.init_member("toLocaleString", 
-            gl->createFunction(object_toLocaleString));
+            gl->createClass(object_toLocaleString,
+                gl->createObject(lsProto)));
 
        int swf6flags = PropFlags::dontEnum | 
         PropFlags::dontDelete | 
@@ -146,30 +162,30 @@
 as_value
 object_ctor(const fn_call& fn)
 {
-       if ( fn.nargs == 1 ) // copy constructor
-       {
-
-        as_object* obj = fn.arg(0).to_object(*getGlobal(fn)).get();
-
-        /// If it's not an object, return an undefined object, not null.
-        if (!obj) return as_value(new as_object);
-
-        // just copy the reference
-               //
-               // WARNING: it is likely that fn.result and fn.arg(0)
-               // are the same location... so we might skip
-               // the set_as_object() call as a whole.
+    Global_as* gl = getGlobal(fn);
+
+       if (fn.nargs == 1) {
+
+        as_object* obj = fn.arg(0).to_object(*gl).get();
+
+        /// If it's not an object, return a simple object, not null.
+        if (!obj) return gl->createObject();
+
                return as_value(obj);
        }
 
-       if (fn.nargs)
-       {
+       if (fn.nargs) {
                IF_VERBOSE_ASCODING_ERRORS(
                    log_aserror(_("Too many args to Object constructor"));
                );
        }
 
-    boost::intrusive_ptr<as_object> obj = new as_object(getObjectInterface());
+    if (!fn.isInstantiation()) {
+        return gl->createObject();;
+    }
+
+    as_object* proto = getObjectInterface();
+    boost::intrusive_ptr<as_object> obj = gl->createObject(proto);
 
        return as_value(obj.get()); 
 }

=== modified file 'libcore/asobj/Object.h'
--- a/libcore/asobj/Object.h    2009-07-16 08:30:06 +0000
+++ b/libcore/asobj/Object.h    2009-07-30 11:33:29 +0000
@@ -33,6 +33,7 @@
 
 as_object* getObjectInterface();
 
+void registerObjectNative(as_object& global);
 
 }
 

=== modified file 'libcore/vm/ASHandlers.cpp'
--- a/libcore/vm/ASHandlers.cpp 2009-07-15 07:37:56 +0000
+++ b/libcore/vm/ASHandlers.cpp 2009-07-30 13:11:28 +0000
@@ -2943,19 +2943,24 @@
 
     const int nmembers = env.pop().to_int();
 
-    boost::intrusive_ptr<as_object> new_obj_ptr(init_object_instance());
+    // TODO: see if this could call the ASnative function(101, 9).
+    Global_as* gl = getGlobal(env);
+    as_object* proto = getObjectInterface();
+    as_object* obj = gl->createObject(proto);
+
+    obj->init_member(NSV::PROP_CONSTRUCTOR, gl->getMember(NSV::CLASS_OBJECT));
 
     // Set provided members
     for (int i = 0; i < nmembers; ++i) {
         as_value member_value = env.top(0);
         std::string member_name = env.top(1).to_string();
 
-        thread.setObjectMember(*new_obj_ptr, member_name, member_value);
+        thread.setObjectMember(*obj, member_name, member_value);
         env.drop(2);
     }
 
     as_value new_obj;
-    new_obj.set_as_object(new_obj_ptr.get());
+    new_obj.set_as_object(obj);
 
     env.push(new_obj);
 

=== modified file 'testsuite/as3compile.all/Makefile.am'
--- a/testsuite/as3compile.all/Makefile.am      2009-07-29 13:41:03 +0000
+++ b/testsuite/as3compile.all/Makefile.am      2009-07-30 10:36:03 +0000
@@ -29,6 +29,7 @@
        QName.as \
        System.as \
        Keyboard.as \
+       Object.as \
        $(NULL)
 
 BOGUS_AS3TESTS = \

=== added file 'testsuite/as3compile.all/Object.as'
--- a/testsuite/as3compile.all/Object.as        1970-01-01 00:00:00 +0000
+++ b/testsuite/as3compile.all/Object.as        2009-07-30 11:20:20 +0000
@@ -0,0 +1,85 @@
+//
+//   Copyright (C) 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+#include "check.as"
+
+// Important points about the AS3 Object class:
+//
+// prototype is a static, read-only property. It doesn't have the same
+// role in AS3 as in AS2. You can assign properties to the prototype
+// member, but you cannot change what it points to.
+//
+// The prototype property provides dynamic inheritance. Normally, inheritance
+// is done using a Traits object (bytecode, not available to AS). These two
+// mechanisms are separate.
+
+package main {
+
+    import flash.display.MovieClip;
+
+    public class Main extends MovieClip {
+
+
+        DEJAGNU_OBJ;
+
+        public function Main() {
+
+            xcheck_equals(Object, "[class Object]");
+            xcheck_equals(Object.prototype, "[object Object]");
+            xcheck_equals(Object.constructor, "[class Class]");
+            
+            xcheck_equals(typeof(Object), "object");
+            check_equals(typeof(Object.prototype), "object");
+            xcheck_equals(typeof(Object.constructor), "object");
+
+            check(Object.prototype.hasOwnProperty("constructor"));
+            check(Object.prototype.hasOwnProperty("hasOwnProperty"));
+            check(Object.prototype.hasOwnProperty("isPrototypeOf"));
+            xcheck(Object.prototype.hasOwnProperty("propertyIsEnumerable"));
+            xcheck(Object.prototype.hasOwnProperty("setPropertyIsEnumerable"));
+            check(Object.prototype.hasOwnProperty("toString"));
+            check(Object.prototype.hasOwnProperty("valueOf"));
+            
+            check(!Object.prototype.hasOwnProperty("__proto__"));
+            check(!Object.prototype.hasOwnProperty("prototype"));
+
+            xcheck(Object.prototype.isPrototypeOf(MovieClip));
+            xcheck(Object.prototype.isPrototypeOf(this));
+
+            var a = new Object();
+            xcheck_equals(a, "[object Object]");       
+            check(!a.hasOwnProperty("constructor"));
+            check(!a.hasOwnProperty("hasOwnProperty"));
+            check(!a.hasOwnProperty("isPrototypeOf"));
+            check(!a.hasOwnProperty("propertyIsEnumerable"));
+            check(!a.hasOwnProperty("setPropertyIsEnumerable"));
+            check(!a.hasOwnProperty("toString"));
+            check(!a.hasOwnProperty("valueOf"));
+            
+            xcheck(!a.hasOwnProperty("__proto__"));
+            check(!a.hasOwnProperty("prototype"));
+
+            // This crashes the Adobe player 9.
+            // check(Object.isPrototypeOf(this));
+               
+
+            totals(27);
+            done();
+        }
+    }
+}
+         

=== modified file 'testsuite/swfdec/PASSING'
--- a/testsuite/swfdec/PASSING  2009-07-10 08:33:22 +0000
+++ b/testsuite/swfdec/PASSING  2009-07-30 13:51:21 +0000
@@ -546,6 +546,9 @@
 instance-name-loaded-5.swf:507414bb411ba30305034cf3078e5fa2
 instance-name-loaded-6.swf:d5fbbda201d50d6bf121b7c1a78ad3c8
 instance-name-loaded-7.swf:f4b4cf3a25a0010b7ff13a56a42d1aad
+instance-of-6.swf:23b56f183fbfddfb3eb7ee074f866035
+instance-of-7.swf:72c7b030a462019116bd6551153f5142
+instance-of-8.swf:fc26462c07bac41c57f3ecaabe9f5ffd
 instance-of-propflags-5.swf:1cab145faaa9544b3b1488c09f6639e5
 instance-of-propflags-8.swf:af7c2eee7fa1e572ff330d03d936d959
 instance-of-propflags-9.swf:b125071d54db67ae00035fc87ba37a9b
@@ -721,6 +724,10 @@
 object-math-5.swf:2d509f7b6e94776a2208fcbec80b7a67
 object-math-6.swf:bdf73b4bfb144113a80ff78a282558d7
 object-math-7.swf:15d6cb896cc58fe289ed0e6de39b3347
+object-properties-5.swf:86727344c3b46a88d41163cd01b26337
+object-properties-6.swf:c34734222b0c6eef649ab3b92b1b830f
+object-properties-7.swf:71ebb1f47408d993409748dae8d32d5e
+object-properties-8.swf:992fafbfd6ae4927116892eb205aac0f
 object-resolve-propflags-9.swf:db769008cba912cd906834a4722fdb95
 object-valueof-5.swf:2520f058ac5a1af3db81ba9b3002e6ab
 object-valueof-6.swf:68d80a5ba580357d1dfeb3b515691e7e


reply via email to

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