gnash-commit
[Top][All Lists]
Advanced

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

[Gnash-commit] /srv/bzr/gnash/trunk r11564: Fake our fake array so it ap


From: Benjamin Wolsey
Subject: [Gnash-commit] /srv/bzr/gnash/trunk r11564: Fake our fake array so it appears less fake.
Date: Thu, 15 Oct 2009 16:04:17 +0200
User-agent: Bazaar (1.16.1)

------------------------------------------------------------
revno: 11564 [merge]
committer: Benjamin Wolsey <address@hidden>
branch nick: trunk
timestamp: Thu 2009-10-15 16:04:17 +0200
message:
  Fake our fake array so it appears less fake.
modified:
  libcore/TextField.cpp
  libcore/as_function.cpp
  libcore/as_object.cpp
  libcore/asobj/Array_as.cpp
  libcore/asobj/Array_as.h
  libcore/asobj/AsBroadcaster.cpp
  libcore/asobj/Global_as.h
  libcore/asobj/Globals.cpp
  libcore/asobj/MovieClipLoader.cpp
  libcore/asobj/Selection_as.cpp
  libcore/asobj/TextFormat_as.cpp
  libcore/swf_function.cpp
  libcore/swf_function.h
  libcore/vm/ASHandlers.cpp
  testsuite/actionscript.all/Function.as
  testsuite/actionscript.all/array.as
  testsuite/swfdec/PASSING
=== modified file 'libcore/TextField.cpp'
--- a/libcore/TextField.cpp     2009-10-14 14:50:52 +0000
+++ b/libcore/TextField.cpp     2009-10-14 18:15:19 +0000
@@ -48,7 +48,6 @@
 #include "fontlib.h" 
 #include "Object.h" // for getObjectInterface
 #include "namedStrings.h"
-#include "Array_as.h" // for _listeners construction
 #include "AsBroadcaster.h" // for initializing self as a broadcaster
 #include "StringPredicates.h"
 #include "TextFormat_as.h"

=== modified file 'libcore/as_function.cpp'
--- a/libcore/as_function.cpp   2009-10-14 08:47:08 +0000
+++ b/libcore/as_function.cpp   2009-10-14 18:45:06 +0000
@@ -271,6 +271,17 @@
 }
 
 
+class PushFunctionArgs
+{
+public:
+    PushFunctionArgs(fn_call& fn) : _fn(fn) {}
+    void operator()(const as_value& val) {
+        _fn.pushArg(val);
+    }
+private:
+    fn_call& _fn;
+};
+
 as_value
 function_apply(const fn_call& fn)
 {
@@ -317,37 +328,11 @@
                        boost::intrusive_ptr<as_object> arg1 = 
                 fn.arg(1).to_object(*getGlobal(fn));
 
-                       if (!arg1) {
-                               IF_VERBOSE_ASCODING_ERRORS(
-                                       log_aserror(_("Second arg of 
Function.apply"
-                                               " is %s (expected array)"
-                                               " - considering as call with no 
args"),
-                                               fn.arg(1));
-                               );
-                               goto call_it;
-                       }
-
-                       boost::intrusive_ptr<Array_as> arg_array = 
-                                       
boost::dynamic_pointer_cast<Array_as>(arg1);
-
-                       if ( ! arg_array )
-                       {
-                               IF_VERBOSE_ASCODING_ERRORS(
-                                       log_aserror(_("Second arg of 
Function.apply"
-                                               " is of type %s, with value %s"
-                                               " (expected array)"
-                                               " - considering as call with no 
args"),
-                                               fn.arg(1).typeOf(), 
fn.arg(1).to_string());
-                               );
-                               goto call_it;
-                       }
-
-                       const size_t nelems = arg_array->size();
-
-                       for (size_t i = 0; i < nelems; ++i) {
-                               new_fn_call.pushArg(arg_array->at(i));
-                       }
-
+            if (arg1) {
+                PushFunctionArgs pa(new_fn_call);
+                foreachArray(*arg1, pa);
+            }
+            else goto call_it;
                }
        }
 

=== modified file 'libcore/as_object.cpp'
--- a/libcore/as_object.cpp     2009-10-14 08:47:08 +0000
+++ b/libcore/as_object.cpp     2009-10-15 05:59:43 +0000
@@ -1024,101 +1024,45 @@
        _members.dump(*this, to);
 }
 
-class FlagsSetterVisitor {
-       string_table& _st;
-       PropertyList& _pl;
-       int _setTrue;
-       int _setFalse;
-public:
-       FlagsSetterVisitor(string_table& st, PropertyList& pl, int setTrue, int 
setFalse)
-               :
-               _st(st),
-               _pl(pl),
-               _setTrue(setTrue),
-               _setFalse(setFalse)
-       {}
-
-       void visit(as_value& v)
-       {
-               string_table::key key = _st.find(v.to_string());
-               _pl.setFlags(key, _setTrue, _setFalse);
-       }
-};
-
 void
 as_object::setPropFlags(const as_value& props_val, int set_false, int set_true)
 {
-       if (props_val.is_string())
-       {
-               std::string propstr = PROPNAME(props_val.to_string()); 
-
-               for(;;)
-               {
-                       std::string prop;
-                       size_t next_comma=propstr.find(",");
-                       if ( next_comma == std::string::npos )
-                       {
-                               prop=propstr;
-                       } 
-                       else
-                       {
-                               prop=propstr.substr(0,next_comma);
-                               propstr=propstr.substr(next_comma+1);
-                       }
-
-                       // set_member_flags will take care of case conversion
-                       if (!set_member_flags(getStringTable(*this).find(prop), 
set_true, set_false) )
-                       {
-                               IF_VERBOSE_ASCODING_ERRORS(
-                               log_aserror(_("Can't set propflags on object "
-                                       "property %s "
-                                       "(either not found or protected)"),     
prop);
-                               );
-                       }
-
-                       if ( next_comma == std::string::npos )
-                       {
-                               break;
-                       }
-               }
-               return;
-       }
-
-       if (props_val.is_null())
-       {
+
+       if (props_val.is_null()) {
                // Take all the members of the object
                _members.setFlagsAll(set_true, set_false);
-
-               // Are we sure we need to descend to __proto__ ?
-               // should we recurse then ?
-#if 0
-               if (m_prototype)
-               {
-                       m_prototype->_members.setFlagsAll(set_true, set_false);
-               }
-#endif
-               return;
-       }
-
-       boost::intrusive_ptr<as_object> props = 
props_val.to_object(*getGlobal(*this));
-       Array_as* ary = dynamic_cast<Array_as*>(props.get());
-       if ( ! ary )
-       {
-               IF_VERBOSE_ASCODING_ERRORS(
-               log_aserror(_("Invalid call to AsSetPropFlags: "
-                       "invalid second argument %s "
-                       "(expected string, null or an array)"),
-                       props_val);
-               );
-               return;
-       }
-
-       // The passed argument has to be considered an array
-       //std::pair<size_t, size_t> result = 
-       FlagsSetterVisitor visitor(getStringTable(*this), _members, set_true,
-            set_false);
-       ary->visitAll(visitor);
-       //_members.setFlagsAll(props->_members, set_true, set_false);
+               return;
+       }
+
+    std::string propstr = props_val.to_string();
+
+    for (;;) {
+
+        std::string prop;
+        size_t next_comma=propstr.find(",");
+        if (next_comma == std::string::npos) {
+            prop = propstr;
+        } 
+        else {
+            prop = propstr.substr(0,next_comma);
+            propstr = propstr.substr(next_comma+1);
+        }
+
+        // set_member_flags will take care of case conversion
+        if (!set_member_flags(getStringTable(*this).find(prop), set_true, 
set_false) )
+        {
+            IF_VERBOSE_ASCODING_ERRORS(
+            log_aserror(_("Can't set propflags on object "
+                "property %s "
+                "(either not found or protected)"),    prop);
+            );
+        }
+
+        if (next_comma == std::string::npos) {
+            break;
+        }
+    }
+    return;
 }
 
 

=== modified file 'libcore/asobj/Array_as.cpp'
--- a/libcore/asobj/Array_as.cpp        2009-10-14 15:45:27 +0000
+++ b/libcore/asobj/Array_as.cpp        2009-10-15 13:25:00 +0000
@@ -25,62 +25,281 @@
 #include "as_value.h"
 #include "Array_as.h"
 #include "log.h"
-#include "builtin_function.h" // for Array class
+#include "builtin_function.h"
 #include "NativeFunction.h" 
-#include "as_function.h" // for sort user-defined comparator
+#include "as_function.h"
 #include "fn_call.h"
 #include "Global_as.h"
 #include "GnashException.h"
-#include "action.h" // for call_method
-#include "VM.h" // for PROPNAME, registerNative
-#include "Object.h" // for getObjectInterface()
+#include "action.h" 
+#include "VM.h" 
+#include "Object.h" 
 #include "GnashNumeric.h"
 
 #include <string>
 #include <algorithm>
 #include <cmath>
 #include <boost/algorithm/string/case_conv.hpp>
-
-//#define GNASH_DEBUG 
+#include <boost/lexical_cast.hpp>
 
 namespace gnash {
 
-typedef boost::function2<bool, const as_value&, const as_value&> as_cmp_fn;
-
-inline string_table::key
-arrayKey(string_table& st, size_t i)
-{
-    std::ostringstream os;
-    os << i;
-    return st.find(os.str());
-}
-
-namespace {
-
-string_table::key getKey(const fn_call& fn, size_t i) {
-    string_table& st = getStringTable(fn);
-    return arrayKey(st, i);
-}
-
-}
-
-static as_object* getArrayInterface();
-static void attachArrayProperties(as_object& proto);
-static void attachArrayInterface(as_object& proto);
-static void attachArrayStatics(as_object& proto);
-
-inline static bool int_lt_or_eq (int a)
-{
-    return a <= 0;
-}
-
-inline static bool int_gt (int a)
-{
-    return a > 0;
-}
+// Forward declarations
+namespace {
+       
+    /// Sort flags
+       enum SortFlags {
+               /// Case-insensitive (z precedes A)
+               SORT_CASE_INSENSITIVE = (1<<0), // 1
+               /// Descending order (b precedes a)
+               SORT_DESCENDING = (1<<1), // 2
+               /// If two or more elements in the array
+               /// have identical sort fields, return 0
+               /// and don't modify the array.
+               /// Otherwise proceed to sort the array.
+               SORT_UNIQUE     = (1<<2), // 4
+               /// Don't modify the array, rather return
+               /// a new array containing indexes into it
+               /// in sorted order.
+               SORT_RETURN_INDEX = (1<<3), // 8
+               /// Numerical sort (9 precedes 10)
+               SORT_NUMERIC = (1<<4) // 16
+       };
+    
+    class indexed_as_value;
+
+    typedef boost::function2<bool, const as_value&, const as_value&> as_cmp_fn;
+
+    as_object* getArrayInterface();
+    void attachArrayInterface(as_object& proto);
+    void attachArrayStatics(as_object& proto);
+
+    as_value join(as_object* array, const std::string& separator);
+
+    as_value array_new(const fn_call& fn);
+    as_value array_slice(const fn_call& fn);
+    as_value array_concat(const fn_call& fn);
+    as_value array_toString(const fn_call& fn);
+    as_value array_join(const fn_call& fn);
+    as_value array_reverse(const fn_call& fn);
+    as_value array_shift(const fn_call& fn);
+    as_value array_pop(const fn_call& fn);
+    as_value array_unshift(const fn_call& fn);
+    as_value array_push(const fn_call& fn);
+    as_value array_sortOn(const fn_call& fn);
+    as_value array_sort(const fn_call& fn);
+    as_value array_splice(const fn_call& fn);
+
+    string_table::key getKey(const fn_call& fn, size_t i);
+
+    /// Implementation of foreachArray that takes a start and end range.
+    template<typename T> void foreachArray(as_object& array, int start,
+            int end, T& pred);
+
+    inline bool int_lt_or_eq (int a) {
+        return a <= 0;
+    }
+
+    inline bool int_gt (int a) {
+        return a > 0;
+    }
+
+    void getIndexedElements(as_object& array, std::vector<indexed_as_value>& 
v);
+
+    void pushIndices(as_object& o, const std::vector<indexed_as_value>& index);
+
+}
+
+/// Function objects for foreachArray()
+namespace {
+
+struct indexed_as_value : public as_value
+{
+       int vec_index;
+
+       indexed_as_value(const as_value& val, int index)
+       : as_value(val)
+       {
+               vec_index = index;
+       }
+};
+
+class PushToArray
+{
+public:
+    PushToArray(as_object& obj) : _obj(obj) {}
+    void operator()(const as_value& val) {
+        _obj.callMethod(NSV::PROP_PUSH, val);
+    }
+private:
+    as_object& _obj;
+};
+
+template<typename T>
+class PushToContainer
+{
+public:
+    PushToContainer(T& v) : _v(v) {}
+    void operator()(const as_value& val) {
+        _v.push_back(val);
+    }
+private:
+    T& _v;
+};
+
+
+class PushToIndexedVector
+{
+public:
+    PushToIndexedVector(std::vector<indexed_as_value>& v) : _v(v), _i(0) {}
+    void operator()(const as_value& val) {
+        _v.push_back(indexed_as_value(val, _i));
+        ++_i;
+    }
+private:
+    std::vector<indexed_as_value>& _v;
+    size_t _i;
+};
+
+        
+/// \brief
+/// Attempt to sort the array using given values comparator, avc.
+/// If two or more elements in the array are equal, as determined
+/// by the equality comparator ave, then the array is not sorted
+/// and 0 is returned. Otherwise the array is sorted and returned.
+///
+/// @param avc
+///    boolean functor or function comparing two as_value& objects
+///     used to determine sort-order
+///
+/// @param ave
+///    boolean functor or function comparing two as_value& objects
+///     used to determine equality
+///
+template <class AVCMP, class AVEQ>
+bool sort(as_object& o, AVCMP avc, AVEQ ave)
+{
+    // IMPORTANT NOTE
+    //
+    // As for ISO/IEC 14882:2003 - 23.2.2.4.29 
+    // the sort algorithm relies on the assumption
+    // that the comparator function implements
+    // a Strict Weak Ordering operator:
+    // http://www.sgi.com/tech/stl/StrictWeakOrdering.html
+    //
+    // Invalid comparator can lead to undefined behaviour,
+    // including invalid memory access and infinite loops.
+    //
+    // Pragmatically, it seems that std::list::sort is
+    // more robust in this reguard, so we'll sort a list
+    // instead of the queue. We want to sort a copy anyway
+    // to avoid the comparator changing the original container.
+
+    typedef std::list<as_value> SortContainer;
+
+    SortContainer v;
+    PushToContainer<SortContainer> pv(v);
+    foreachArray(o, pv);
+
+    const size_t size = v.size(); 
+
+    v.sort(avc);
+
+    if (std::adjacent_find(v.begin(), v.end(), ave) != v.end()) return false;
+
+    string_table& st = getStringTable(o);
+
+    SortContainer::const_iterator it = v.begin();
+
+    for (size_t i = 0; i < size; ++i) {
+        if (i >= v.size()) {
+            break;
+        }
+        o.set_member(arrayKey(st, i), *it);
+        ++it;
+    }
+    return true;
+}
+
+
+template <class AVCMP>
+void sort(as_object& o, AVCMP avc) 
+{
+
+    typedef std::list<as_value> SortContainer;
+
+    SortContainer v;
+    PushToContainer<SortContainer> pv(v);
+    foreachArray(o, pv);
+
+    const size_t size = v.size(); 
+
+    v.sort(avc);
+
+    string_table& st = getStringTable(o);
+
+    SortContainer::const_iterator it = v.begin();
+
+    for (size_t i = 0; i < size; ++i) {
+        if (it == v.end()) {
+            break;
+        }
+        o.set_member(arrayKey(st, i), *it);
+        ++it;
+    }
+}
+
+/// \brief
+/// Return a new array containing sorted index of this array.
+/// If two or more elements in the array are equal, as determined
+/// by the equality comparator ave, then 0 is returned instead.
+///
+/// @param avc
+///    boolean functor or function comparing two as_value& objects
+///     used to determine sort-order
+///
+/// @param ave
+///    boolean functor or function comparing two as_value& objects
+///     used to determine equality
+///
+template <class AVCMP, class AVEQ>
+as_value sortIndexed(as_object& array, AVCMP avc, AVEQ ave)
+{
+    std::vector<indexed_as_value> v;
+
+    getIndexedElements(array, v);
+
+    std::sort(v.begin(), v.end(), avc);
+
+    if (std::adjacent_find(v.begin(), v.end(), ave) != v.end()) {
+        return as_value(0.0);
+    }
+
+    as_object* o = getGlobal(array)->createArray();
+    pushIndices(*o, v);
+    return o;
+}
+
+
+/// \brief
+/// Return a new array containing sorted index of this array
+///
+/// @param avc
+///    boolean functor or function comparing two as_value& objects
+///
+template <class AVCMP>
+as_object* sortIndexed(as_object& array, AVCMP avc)
+{
+    std::vector<indexed_as_value> v;
+    getIndexedElements(array, v);
+    std::sort(v.begin(), v.end(), avc);
+    as_object* o = getGlobal(array)->createArray();
+    pushIndices(*o, v);
+    return o;
+}
+
 
 // simple as_value strict-weak-ordering comparison functors:
-
 // string comparison, ascending (default sort method)
 struct as_value_lt
 {
@@ -272,15 +491,15 @@
 
 // Return basic as_value comparison functor for corresponding sort flag
 // Note:
-// fUniqueSort and fReturnIndexedArray must first be stripped from the flag
+// SORT_UNIQUE and SORT_RETURN_INDEX must first be stripped from the flag
 as_cmp_fn
 get_basic_cmp(boost::uint8_t flags, int version)
 {
     as_cmp_fn f;
 
-    // fUniqueSort and fReturnIndexedArray must be stripped by caller
-    assert(flags^Array_as::fUniqueSort);
-    assert(flags^Array_as::fReturnIndexedArray);
+    // SORT_UNIQUE and SORT_RETURN_INDEX must be stripped by caller
+    assert(flags^SORT_UNIQUE);
+    assert(flags^SORT_RETURN_INDEX);
 
     switch ( flags )
     {
@@ -288,35 +507,35 @@
             f = as_value_lt(version);
             return f;
 
-        case Array_as::fDescending:
+        case SORT_DESCENDING:
             f = as_value_gt(version);
             return f;
 
-        case Array_as::fCaseInsensitive: 
+        case SORT_CASE_INSENSITIVE: 
             f = as_value_nocase_lt(version);
             return f;
 
-        case Array_as::fCaseInsensitive | 
-                Array_as::fDescending:
+        case SORT_CASE_INSENSITIVE | 
+                SORT_DESCENDING:
             f = as_value_nocase_gt(version);
             return f;
 
-        case Array_as::fNumeric: 
+        case SORT_NUMERIC: 
             f = as_value_num_lt(version);
             return f;
 
-        case Array_as::fNumeric | Array_as::fDescending:
+        case SORT_NUMERIC | SORT_DESCENDING:
             f = as_value_num_gt(version);
             return f;
 
-        case Array_as::fCaseInsensitive | 
-                Array_as::fNumeric:
+        case SORT_CASE_INSENSITIVE | 
+                SORT_NUMERIC:
             f = as_value_num_nocase_lt(version);
             return f;
 
-        case Array_as::fCaseInsensitive | 
-                Array_as::fNumeric |
-                Array_as::fDescending:
+        case SORT_CASE_INSENSITIVE | 
+                SORT_NUMERIC |
+                SORT_DESCENDING:
             f = as_value_num_nocase_gt(version);
             return f;
 
@@ -329,12 +548,12 @@
 
 // Return basic as_value equality functor for corresponding sort flag
 // Note:
-// fUniqueSort and fReturnIndexedArray must first be stripped from the flag
+// SORT_UNIQUE and SORT_RETURN_INDEX must first be stripped from the flag
 as_cmp_fn
 get_basic_eq(boost::uint8_t flags, int version)
 {
     as_cmp_fn f;
-    flags &= ~(Array_as::fDescending);
+    flags &= ~(SORT_DESCENDING);
 
     switch ( flags )
     {
@@ -342,16 +561,16 @@
             f = as_value_eq(version);
             return f;
 
-        case Array_as::fCaseInsensitive: 
+        case SORT_CASE_INSENSITIVE: 
             f = as_value_nocase_eq(version);
             return f;
 
-        case Array_as::fNumeric: 
+        case SORT_NUMERIC: 
             f = as_value_num_eq(version);
             return f;
 
-        case Array_as::fCaseInsensitive | 
-                Array_as::fNumeric:
+        case SORT_CASE_INSENSITIVE | 
+                SORT_NUMERIC:
             f = as_value_num_nocase_eq(version);
             return f;
 
@@ -510,15 +729,15 @@
     const as_object& _obj;
 };
 
-// Convenience function to strip fUniqueSort and fReturnIndexedArray from sort
+// Convenience function to strip SORT_UNIQUE and SORT_RETURN_INDEX from sort
 // flag. Presence of flags recorded in douniq and doindex.
-static inline boost::uint8_t
+inline boost::uint8_t
 flag_preprocess(boost::uint8_t flgs, bool* douniq, bool* doindex)
 {
-    *douniq = (flgs & Array_as::fUniqueSort);
-    *doindex = (flgs & Array_as::fReturnIndexedArray);
-    flgs &= ~(Array_as::fReturnIndexedArray);
-    flgs &= ~(Array_as::fUniqueSort);
+    *douniq = (flgs & SORT_UNIQUE);
+    *doindex = (flgs & SORT_RETURN_INDEX);
+    flgs &= ~(SORT_RETURN_INDEX);
+    flgs &= ~(SORT_UNIQUE);
     return flgs;
 }
 
@@ -531,7 +750,7 @@
     Array_as::const_iterator it = itBegin;
     std::deque<boost::uint8_t> flgs;
 
-    // extract fUniqueSort and fReturnIndexedArray from first flag
+    // extract SORT_UNIQUE and SORT_RETURN_INDEX from first flag
     if (it != itEnd)
     {
         boost::uint8_t flag = static_cast<boost::uint8_t>((*it++).to_number());
@@ -542,52 +761,28 @@
     while (it != itEnd)
     {
         boost::uint8_t flag = static_cast<boost::uint8_t>((*it++).to_number());
-        flag &= ~(Array_as::fReturnIndexedArray);
-        flag &= ~(Array_as::fUniqueSort);
+        flag &= ~(SORT_RETURN_INDEX);
+        flag &= ~(SORT_UNIQUE);
         flgs.push_back(flag);
     }
     return flgs;
 }
 
+}
+
 Array_as::Array_as()
     :
     as_object(getArrayInterface()), // pass Array inheritance
     elements(0)
 {
-    //IF_VERBOSE_ACTION (
-    //log_action("%s: %p", __FUNCTION__, (void*)this);
-    //)
-    attachArrayProperties(*this);
+    init_member(NSV::PROP_LENGTH, 0.0);
 }
 
-Array_as::Array_as(const Array_as& other)
-    :
-    as_object(other),
-    elements(other.elements)
-{
-    //IF_VERBOSE_ACTION (
-    //log_action("%s: %p", __FUNCTION__, (void*)this);
-    //)
-}
 
 Array_as::~Array_as() 
 {
 }
 
-std::deque<indexed_as_value>
-Array_as::get_indexed_elements()
-{
-    std::deque<indexed_as_value> indexed_elements;
-    int i = 0;
-
-    for (Array_as::const_iterator it = elements.begin(), e = elements.end();
-        it != e; ++it)
-    {
-        indexed_elements.push_back(indexed_as_value(*it, i++));
-    }
-    return indexed_elements;
-}
-
 Array_as::const_iterator
 Array_as::begin()
 {
@@ -623,54 +818,6 @@
     return int(value);
 }
 
-void
-Array_as::reverse()
-{
-    const ArrayContainer::size_type s = elements.size();
-    if ( s < 2 ) return; // nothing to do (CHECKME: might be a single hole!)
-
-    // We create another container, as we want to fill the gaps
-    // There could likely be an in-place version for this, but
-    // filling the gaps would need more care
-    ArrayContainer newelements(s);
-
-    for (size_t i = 0, n = s - 1; i < s; ++i, --n)
-    {
-        newelements[i] = elements[n];
-    }
-
-    elements = newelements;
-}
-
-std::string
-Array_as::join(const std::string& separator) const
-{
-    // TODO - confirm this is the right format!
-    // Reportedly, flash version 7 on linux, and Flash 8 on IE look like
-    // "(1,2,3)" and "1,2,3" respectively - which should we mimic?
-    // Using no parentheses until confirmed for sure
-    //
-    // We should change output based on SWF version --strk 2006-04-28
-
-    std::string temp;
-
-    const ArrayContainer::size_type s = elements.size();
-
-    if ( s ) 
-    {
-        int swfversion = getSWFVersion(*this);
-
-        for (size_t i = 0; i < s; ++i)
-        {
-            if ( i ) temp += separator;
-            temp += elements[i].to_string_versioned(swfversion);
-        }
-    }
-
-    return temp;
-
-}
-
 unsigned int
 Array_as::size() const
 {
@@ -684,32 +831,6 @@
     else return elements[index];
 }
 
-boost::intrusive_ptr<Array_as>
-Array_as::slice(unsigned int start, unsigned int one_past_end)
-{
-    assert(one_past_end >= start);
-    assert(one_past_end <= size());
-    assert(start <= size());
-
-    boost::intrusive_ptr<Array_as> newarray(new Array_as);
-
-#ifdef GNASH_DEBUG
-    log_debug(_("Array.slice(%u, %u) called"), start, one_past_end);
-#endif
-
-    size_t newsize = one_past_end - start;
-    newarray->elements.resize(newsize);
-
-    // maybe there's a standard algorithm for this ?
-    for (unsigned int i=start; i<one_past_end; ++i)
-    {
-        newarray->elements[i-start] = elements[i];
-    }
-
-    return newarray;
-
-}
-
 /* virtual public, overriding as_object::get_member */
 bool
 Array_as::get_member(string_table::key name, as_value *val,
@@ -787,126 +908,297 @@
     // if we were sent a valid array index and not a normal member
     if (index >= 0)
     {
-        if ( size_t(index) >= elements.size() )
+        if (size_t(index) >= elements.size())
         {
             // if we're setting index (x), the vector
             // must be size (x+1)
             elements.resize(index+1);
         }
 
+        as_object::set_member(NSV::PROP_LENGTH, elements.size());
         // set the appropriate index and return
         elements[index] = val;
         return true;
     }
 
+    if (name == NSV::PROP_LENGTH) {
+        elements.resize(std::max(val.to_int(), 0));
+        // Don't return before as_object has set the value!
+    }
 
     return as_object::set_member(name,val, nsname, ifFound);
 }
 
-Array_as*
-Array_as::get_indices(std::deque<indexed_as_value> elems)
-{
-    Array_as* intIndexes = new Array_as();
-
-    for (std::deque<indexed_as_value>::const_iterator it = elems.begin();
-        it != elems.end(); ++it)
-    {
-        intIndexes->callMethod(NSV::PROP_PUSH, it->vec_index);
-    }
-    return intIndexes;
-}
-
-static as_value
+size_t
+arrayLength(as_object& array)
+{
+    as_value length;
+    if (!array.get_member(NSV::PROP_LENGTH, &length)) return 0;
+    
+    const int size = length.to_int();
+    if (size < 0) return 0;
+    return size;
+}
+
+void
+registerArrayNative(as_object& global)
+{
+    VM& vm = getVM(global);
+    vm.registerNative(array_new, 252, 0);
+    vm.registerNative(array_push, 252, 1);
+    vm.registerNative(array_pop, 252, 2);
+    vm.registerNative(array_concat, 252, 3);
+    vm.registerNative(array_shift, 252, 4);
+    vm.registerNative(array_unshift, 252, 5);
+    vm.registerNative(array_slice, 252, 6);
+    vm.registerNative(array_join, 252, 7);
+    vm.registerNative(array_splice, 252, 8);
+    vm.registerNative(array_toString, 252, 9);
+    vm.registerNative(array_sort, 252, 10);
+    vm.registerNative(array_reverse, 252, 11);
+    vm.registerNative(array_sortOn, 252, 12);
+}
+
+void
+array_class_init(as_object& where, const ObjectURI& uri)
+{
+    static as_object* cl = 0;
+
+    if (cl == NULL) {
+
+        // This is going to be the global Array "class"/"function"
+        VM& vm = getVM(where);
+
+        as_object* proto = getArrayInterface();
+        cl = vm.getNative(252, 0);
+        cl->init_member(NSV::PROP_PROTOTYPE, proto);
+        proto->init_member(NSV::PROP_CONSTRUCTOR, cl);
+
+        // Attach static members
+        attachArrayStatics(*cl);
+    }
+
+    const int flags = PropFlags::dontEnum; 
+    where.init_member(getName(uri), cl, flags, getNamespace(uri));
+}
+
+void
+Array_as::enumerateNonProperties(as_environment& env) const
+{
+    std::stringstream ss; 
+    for (const_iterator it = elements.begin(),
+        itEnd = elements.end(); it != itEnd; ++it)
+    {
+        int idx = it.index();
+        // enumerated values need to be strings, not numbers
+        ss.str(""); ss << idx;
+        env.push(as_value(ss.str()));
+    }
+}
+
+#ifdef GNASH_USE_GC
+void
+Array_as::markReachableResources() const
+{
+    for (const_iterator i=elements.begin(), e=elements.end(); i!=e; ++i)
+    {
+        (*i).setReachable();
+    }
+    markAsObjectReachable();
+}
+#endif // GNASH_USE_GC
+
+void
+Array_as::visitPropertyValues(AbstractPropertyVisitor& visitor) const
+{
+    std::stringstream ss; 
+    string_table& st = getStringTable(*this);
+    for (const_iterator i=elements.begin(), ie=elements.end(); i!=ie; ++i)
+    {
+        int idx = i.index();
+        ss.str(""); ss << idx;
+        string_table::key k = st.find(ss.str());
+        visitor.accept(k, *i);
+    }
+
+    // visit proper properties
+    as_object::visitPropertyValues(visitor);
+}
+
+void
+Array_as::visitNonHiddenPropertyValues(AbstractPropertyVisitor& visitor) const
+{
+    std::stringstream ss; 
+    string_table& st = getStringTable(*this);
+    for (const_iterator i=elements.begin(), ie=elements.end(); i!=ie; ++i)
+    {
+        // TODO: skip hidden ones
+        int idx = i.index();
+        ss.str(""); ss << idx;
+        string_table::key k = st.find(ss.str());
+        visitor.accept(k, *i);
+    }
+
+    // visit proper properties
+    as_object::visitNonHiddenPropertyValues(visitor);
+}
+
+bool
+Array_as::isStrict() const
+{
+    if ( hasNonHiddenProperties() ) return false;
+    return true;
+}
+
+// Used by foreachArray, declared in Array_as.h
+string_table::key
+arrayKey(string_table& st, size_t i)
+{
+    return st.find(boost::lexical_cast<std::string>(i));
+}
+
+namespace {
+
+void
+attachArrayStatics(as_object& proto)
+{
+    int flags = 0; // these are not protected
+    proto.init_member("CASEINSENSITIVE", SORT_CASE_INSENSITIVE, flags);
+    proto.init_member("DESCENDING", SORT_DESCENDING, flags);
+    proto.init_member("UNIQUESORT", SORT_UNIQUE, flags);
+    proto.init_member("RETURNINDEXEDARRAY", SORT_RETURN_INDEX, flags);
+    proto.init_member("NUMERIC", SORT_NUMERIC, flags);
+}
+
+void
+attachArrayInterface(as_object& proto)
+{
+    VM& vm = getVM(proto);
+
+    proto.init_member("push", vm.getNative(252, 1));
+    proto.init_member("pop", vm.getNative(252, 2));
+    proto.init_member("concat", vm.getNative(252, 3));
+    proto.init_member("shift", vm.getNative(252, 4));
+    proto.init_member("unshift", vm.getNative(252, 5));
+    proto.init_member("slice", vm.getNative(252, 6));
+    proto.init_member("join", vm.getNative(252, 7));
+    proto.init_member("splice", vm.getNative(252, 8));
+    proto.init_member("toString", vm.getNative(252, 9));
+    proto.init_member("sort", vm.getNative(252, 10));
+    proto.init_member("reverse", vm.getNative(252, 11));
+    proto.init_member("sortOn", vm.getNative(252, 12));
+}
+
+as_object*
+getArrayInterface()
+{
+    static boost::intrusive_ptr<as_object> proto = NULL;
+    if ( proto == NULL )
+    {
+        proto = new as_object(getObjectInterface());
+        getVM(*proto).addStatic(proto.get());
+
+        attachArrayInterface(*proto);
+    }
+    return proto.get();
+}
+
+as_value
 array_splice(const fn_call& fn)
 {
-    boost::intrusive_ptr<Array_as> array = ensureType<Array_as>(fn.this_ptr);
-
-#ifdef GNASH_DEBUG
-    std::stringstream ss;
-    fn.dump_args(ss);
-    log_debug(_("Array(%s).splice(%s) called"), array->toString(), ss.str());
-#endif
-
-    if (fn.nargs < 1)
-    {
+    as_object* array = ensureType<as_object>(fn.this_ptr);
+    
+    if (fn.nargs < 1) {
         IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("Array.splice() needs at least 1 argument, call 
ignored"));
+            log_aserror(_("Array.splice() needs at least 1 argument, "
+                    "call ignored"));
         );
         return as_value();
     }
-
-    unsigned origlen = array->size();
+    
+    const size_t size = arrayLength(*array);
 
     //----------------
     // Get start offset
     //----------------
-    unsigned startoffset;
+
     int start = fn.arg(0).to_int();
-    if ( start < 0 ) start = array->size()+start; // start is negative, so + 
means -abs()
-    startoffset = clamp<int>(start, 0, origlen);
-#ifdef GNASH_DEBUG
-    if ( startoffset != start )
-        log_debug(_("Array.splice: start:%d became %u"), start, startoffset);
-#endif
+    if (start < 0) start = size + start; 
+    start = clamp<int>(start, 0, size);
 
-    //----------------
-    // Get length
-    //----------------
-    unsigned len = origlen - start;
-    if (fn.nargs > 1)
-    {
-        int lenval = fn.arg(1).to_int();
-        if ( lenval < 0 )
-        {
+    // Get length to delete
+    size_t remove = size - start;
+    
+    if (fn.nargs > 1) {
+        int remval = fn.arg(1).to_int();
+        if (remval < 0) {
             IF_VERBOSE_ASCODING_ERRORS(
-            log_aserror(_("Array.splice(%d,%d): negative length given, call 
ignored"),
-                start, lenval);
+                log_aserror(_("Array.splice(%d,%d): negative length "
+                        "given, call ignored"), start, remval);
             );
             return as_value();
         }
-        len = clamp<int>(lenval, 0, origlen-startoffset);
-    }
-
-    //----------------
-    // Get replacement
-    //----------------
-    std::vector<as_value> replace;
-    for (unsigned i=2; i<fn.nargs; ++i)
-    {
-        replace.push_back(fn.arg(i));
-    }
-
-    Array_as* ret = new Array_as();
-    array->splice(startoffset, len, &replace, ret);
+        remove = clamp<int>(remval, 0, size - start);
+    }
+
+    Global_as* gl = getGlobal(fn);
+    as_object* ret = gl->createArray();
+
+    // Copy the original array values for reinsertion. It's not possible
+    // to do a simple copy in-place without overwriting values that still
+    // need to be shifted. The algorithm could certainly be improved though.
+    std::vector<as_value> v;
+    PushToContainer<std::vector<as_value> > pv(v);
+    foreachArray(*array, pv);
+
+    const size_t newelements = fn.nargs > 2 ? fn.nargs - 2 : 0;
+    
+    // Push removed elements to the new array.
+    for (size_t i = 0; i < remove; ++i) {
+        const size_t key = getKey(fn, start + i);
+        ret->callMethod(NSV::PROP_PUSH, array->getMember(key));
+    }
+
+    // Shift elements in 'this' array by simple assignment, not delete
+    // and readd.
+    for (size_t i = 0; i < static_cast<size_t>(size - remove); ++i) {
+        const bool started = (i >= static_cast<size_t>(start));
+        const size_t index = started ? i + remove : i;
+        const size_t target = started ? i + newelements : i;
+        array->set_member(getKey(fn, target), v[index]);
+    }
+
+    // Insert the replacement elements in the gap we left.
+    for (size_t i = 0; i < newelements; ++i) {
+        array->set_member(getKey(fn, start + i), fn.arg(i + 2));
+    }
+    
+    // This one is correct!
+    array->set_member(NSV::PROP_LENGTH, size + newelements - remove);
 
     return as_value(ret);
 }
 
-static as_value
+as_value
 array_sort(const fn_call& fn)
 {
-    boost::intrusive_ptr<Array_as> array = 
-        ensureType<Array_as>(fn.this_ptr);
+    as_object* array = ensureType<as_object>(fn.this_ptr);
     
     const int version = getSWFVersion(*array);
     
-    if (!fn.nargs)
-    {
-        array->sort(as_value_lt(version));
-        return as_value(array.get());
+    if (!fn.nargs) {
+        sort(*array, as_value_lt(version));
+        return as_value(array);
     }
     
     if (fn.arg(0).is_undefined()) return as_value();
 
     boost::uint8_t flags = 0;
 
-    if ( fn.nargs == 1 && fn.arg(0).is_number() )
-    {
-        flags=static_cast<boost::uint8_t>(fn.arg(0).to_number());
+    if (fn.nargs == 1 && fn.arg(0).is_number()) {
+        flags = static_cast<boost::uint8_t>(fn.arg(0).to_number());
     }
-    else if (fn.arg(0).is_function())
-    {
-
+    else if (fn.arg(0).is_function()) {
         // Get comparison function
         as_function* as_func = fn.arg(0).to_as_function();
 
@@ -918,7 +1210,7 @@
             flags=static_cast<boost::uint8_t>(fn.arg(1).to_number());
         }
 
-        if (flags & Array_as::fDescending) icmp = &int_lt_or_eq;
+        if (flags & SORT_DESCENDING) icmp = &int_lt_or_eq;
         else icmp = &int_gt;
 
         const as_environment& env = fn.env();
@@ -926,44 +1218,41 @@
         as_value_custom avc = 
             as_value_custom(*as_func, icmp, fn.this_ptr, env);
 
-        if ((flags & Array_as::fReturnIndexedArray))
-        {
-            return as_value(array->sort_indexed(avc));
+        if ((flags & SORT_RETURN_INDEX)) {
+            return sortIndexed(*array, avc);
         }
 
-        array->sort(avc);
-        return as_value(array.get());
+        sort(*array, avc);
+        return as_value(array);
         // note: custom AS function sorting apparently ignores the 
         // UniqueSort flag which is why it is also ignored here
     }
     else
     {
         IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("Sort called with invalid arguments."));
+            log_aserror(_("Sort called with invalid arguments."));
         )
-        return as_value(array.get());
+        return as_value(array);
     }
+
     bool do_unique, do_index;
     flags = flag_preprocess(flags, &do_unique, &do_index);
     as_cmp_fn comp = get_basic_cmp(flags, version);
 
-    if (do_unique)
-    {
-        as_cmp_fn eq =
-            get_basic_eq(flags, version);
-        if (do_index) return array->sort_indexed(comp, eq);
-        return array->sort(comp, eq);
+    if (do_unique) {
+        as_cmp_fn eq = get_basic_eq(flags, version);
+        if (do_index) return sortIndexed(*array, comp, eq);
+        return sort(*array, comp, eq) ? as_value(array) : as_value(0.0);
     }
-    if (do_index) return as_value(array->sort_indexed(comp));
-    array->sort(comp);
-    return as_value(array.get());
+    if (do_index) return sortIndexed(*array, comp);
+    sort(*array, comp);
+    return as_value(array);
 }
 
-static as_value
+as_value
 array_sortOn(const fn_call& fn)
 {
-    boost::intrusive_ptr<Array_as> array = 
-        ensureType<Array_as>(fn.this_ptr);
+    as_object* array = ensureType<as_object>(fn.this_ptr);
 
     bool do_unique = false, do_index = false;
     boost::uint8_t flags = 0;
@@ -972,29 +1261,33 @@
     string_table& st = getStringTable(fn);
 
     // cases: sortOn("prop) and sortOn("prop", Array.FLAG)
-    if ( fn.nargs > 0 && fn.arg(0).is_string() )
+    if (fn.nargs > 0 && fn.arg(0).is_string()) 
     {
-        string_table::key propField = 
st.find(fn.arg(0).to_string_versioned(version));
+        string_table::key propField =
+            st.find(fn.arg(0).to_string_versioned(version));
 
-        if ( fn.nargs > 1 && fn.arg(1).is_number() )
-        {
+        if (fn.nargs > 1 && fn.arg(1).is_number()) {
             flags = static_cast<boost::uint8_t>(fn.arg(1).to_number());
             flags = flag_preprocess(flags, &do_unique, &do_index);
         }
+
         as_value_prop avc(propField, get_basic_cmp(flags, version),
                 *getGlobal(fn));
-        if (do_unique)
-        {
+
+        if (do_unique) {
             as_value_prop ave(propField, get_basic_eq(flags, version), 
                     *getGlobal(fn));
             if (do_index)
-                return array->sort_indexed(avc, ave);
-            return array->sort(avc, ave);
-        }
-        if (do_index)
-            return as_value(array->sort_indexed(avc));
-        array->sort(avc);
-        return as_value(array.get());
+                return sortIndexed(*array, avc, ave);
+            return sort(*array, avc, ave) ? as_value(array) : as_value(0.0);
+        }
+        
+        if (do_index) {
+            return sortIndexed(*array, avc);
+        }
+
+        sort(*array, avc);
+        return as_value(array);
     }
 
     // case: sortOn(["prop1", "prop2"] ...)
@@ -1010,7 +1303,7 @@
         for (Array_as::const_iterator it = props->begin();
             it != props->end(); ++it)
         {
-            string_table::key s = 
st.find(PROPNAME((*it).to_string_versioned(version)));
+            string_table::key s = st.find((*it).to_string_versioned(version));
             prp.push_back(s);
         }
         
@@ -1077,12 +1370,12 @@
         if (do_unique)
         {
             as_value_multiprop_eq ave(prp, eq, *getGlobal(fn));
-            if (do_index) return array->sort_indexed(avc, ave);
-            return array->sort(avc, ave);
+            if (do_index) return sortIndexed(*array, avc, ave);
+            return sort(*array, avc, ave) ? as_value(array) : as_value(0.0);
         }
-        if (do_index) return as_value(array->sort_indexed(avc));
-        array->sort(avc);
-        return as_value(array.get());
+        if (do_index) return sortIndexed(*array, avc);
+        sort(*array, avc);
+        return as_value(array);
 
     }
     IF_VERBOSE_ASCODING_ERRORS(
@@ -1091,7 +1384,7 @@
     if (fn.nargs == 0 )
         return as_value();
 
-    return as_value(array.get());
+    return as_value(array);
 }
 
 // Callback to push values to the back of an array
@@ -1104,11 +1397,7 @@
 
     const size_t shift = fn.nargs;
 
-    as_value length;
-    if (!array->get_member(NSV::PROP_LENGTH, &length)) return as_value();
-    
-    const int size = length.to_int();
-    if (size < 0) return as_value();
+    const size_t size = arrayLength(*array);
 
     for (size_t i = 0; i < fn.nargs; ++i) {
         array->set_member(getKey(fn, size + i), fn.arg(i));
@@ -1121,7 +1410,7 @@
 }
 
 // Callback to push values to the front of an array
-static as_value
+as_value
 array_unshift(const fn_call& fn)
 {
 
@@ -1131,11 +1420,7 @@
 
     const size_t shift = fn.nargs;
 
-    as_value length;
-    if (!array->get_member(NSV::PROP_LENGTH, &length)) return as_value();
-    
-    const int size = length.to_int();
-    if (size < 0) return as_value();
+    const size_t size = arrayLength(*array);
 
     string_table& st = getStringTable(fn);
     as_value ret = array->getMember(st.find("0"));
@@ -1159,16 +1444,13 @@
 }
 
 // Callback to pop a value from the back of an array
-static as_value
+as_value
 array_pop(const fn_call& fn)
 {
 
     as_object* array = ensureType<as_object>(fn.this_ptr);
 
-    as_value length;
-    if (!array->get_member(NSV::PROP_LENGTH, &length)) return as_value();
-    
-    const int size = length.to_int();
+    const size_t size = arrayLength(*array);
     if (size < 1) return as_value();
 
     const string_table::key ind = getKey(fn, size - 1);
@@ -1182,16 +1464,12 @@
 }
 
 // Callback to pop a value from the front of an array
-static as_value
+as_value
 array_shift(const fn_call& fn)
 {
     as_object* array = ensureType<as_object>(fn.this_ptr);
 
-    as_value length;
-    if (!array->get_member(NSV::PROP_LENGTH, &length)) return as_value();
-    
-    const int size = length.to_int();
-
+    const size_t size = arrayLength(*array);
     // An array with no elements has nothing to return.
     if (size < 1) return as_value();
 
@@ -1211,47 +1489,28 @@
 }
 
 // Callback to reverse the position of the elements in an array
-static as_value
+as_value
 array_reverse(const fn_call& fn)
 {
-    boost::intrusive_ptr<Array_as> array = ensureType<Array_as>(fn.this_ptr);
-
-    array->reverse();
-
-    as_value rv(array.get()); 
-
-    IF_VERBOSE_ACTION (
-    log_action(_("called array reverse, result:%s, new array size:%d"),
-        rv, array->size());
-    );
-    return rv;
-}
-
-as_value
-join(as_object* array, const std::string& separator)
-{
-    as_value length;
-    if (!array->get_member(NSV::PROP_LENGTH, &length)) return as_value("");
-
-    const double size = length.to_int();
-    if (size < 0) return as_value("");
-
-    std::string s;
-
-    string_table& st = getStringTable(*array);
-    const int version = getSWFVersion(*array);
-
-    for (size_t i = 0; i < size; ++i) {
-        std::ostringstream os;
-        os << i;
-        if (i) s += separator;
-        as_value el;
-        array->get_member(st.find(os.str()), &el);
-        s += el.to_string_versioned(version);
+    as_object* array = ensureType<as_object>(fn.this_ptr);
+
+    const size_t size = arrayLength(*array);
+    // An array with 0 or 1 elements has nothing to reverse.
+    if (size < 2) return as_value();
+
+    for (size_t i = 0; i < static_cast<size_t>(size) / 2; ++i) {
+        const string_table::key bottomkey = getKey(fn, i);
+        const string_table::key topkey = getKey(fn, size - i - 1);
+        const as_value top = array->getMember(topkey);
+        const as_value bottom = array->getMember(bottomkey);
+        array->delProperty(topkey);
+        array->delProperty(bottomkey);
+        array->set_member(bottomkey, top);
+        array->set_member(topkey, bottom);
     }
-    return as_value(s);
+
+    return array;
 }
-
 as_value
 array_join(const fn_call& fn)
 {
@@ -1272,17 +1531,6 @@
     return join(array, ",");
 }
 
-class PushToArray
-{
-public:
-    PushToArray(as_object& obj) : _obj(obj) {}
-    void operator()(const as_value& val) {
-        _obj.callMethod(NSV::PROP_PUSH, val);
-    }
-private:
-    as_object& _obj;
-};
-
 /// concatenates the elements specified in the parameters with
 /// the elements in my_array, and creates a new array. If the
 /// value parameters specify an array, the elements of that
@@ -1291,13 +1539,13 @@
 as_value
 array_concat(const fn_call& fn)
 {
-    boost::intrusive_ptr<Array_as> array = ensureType<Array_as>(fn.this_ptr);
+    as_object* array = ensureType<as_object>(fn.this_ptr);
 
-    // use copy ctor
-    Array_as* newarray = new Array_as();
+    Global_as* gl = getGlobal(fn);
+    as_object* newarray = gl->createArray();
 
     PushToArray push(*newarray);
-    if (!foreachArray(*array, push)) return as_value();
+    foreachArray(*array, push);
 
     for (size_t i = 0; i < fn.nargs; ++i) {
 
@@ -1326,17 +1574,12 @@
 
 // Callback to slice part of an array to a new array
 // without changing the original
-static as_value
+as_value
 array_slice(const fn_call& fn)
 {
-    boost::intrusive_ptr<Array_as> array = ensureType<Array_as>(fn.this_ptr);
-
-    // start and end index of the part we're slicing
-    int startindex, endindex;
-    unsigned int arraysize = array->size();
-
-    if (fn.nargs > 2)
-    {
+    as_object* array = ensureType<as_object>(fn.this_ptr);
+
+    if (fn.nargs > 2) {
         IF_VERBOSE_ASCODING_ERRORS(
         log_aserror(_("More than 2 arguments to Array.slice, "
             "and I don't know what to do with them.  "
@@ -1344,314 +1587,125 @@
         );
     }
 
-    // They passed no arguments: simply duplicate the array
-    // and return the new one
-    if (fn.nargs < 1)
-    {
-        Array_as* newarray = new Array_as(*array);
-        return as_value(newarray);
-    }
-
-
-    startindex = fn.arg(0).to_int();
-
-    // if the index is negative, it means "places from the end"
-    // where -1 is the last element
-    if (startindex < 0) startindex = startindex + arraysize;
+    int startindex = fn.nargs ? fn.arg(0).to_int() : 0;
 
     // if we sent at least two arguments, setup endindex
-    if (fn.nargs >= 2)
-    {
-        endindex = fn.arg(1).to_int();
-
-        // if the index is negative, it means
-        // "places from the end" where -1 is the last element
-        if (endindex < 0) endindex = endindex + arraysize;
-    }
-    else
-    {
-        // They didn't specify where to end,
-        // so choose the end of the array
-        endindex = arraysize;
-    }
-
-    if ( startindex < 0 ) startindex = 0;
-    else if ( static_cast<size_t>(startindex) > arraysize ) startindex = 
arraysize;
-
-    if ( endindex < startindex ) endindex = startindex;
-    else if ( static_cast<size_t>(endindex)  > arraysize ) endindex = 
arraysize;
-
-    boost::intrusive_ptr<Array_as> newarray(array->slice(
-        startindex, endindex));
-
-    return as_value(newarray.get());        
-}
-
-static as_value
-array_length(const fn_call& fn)
-{
-    boost::intrusive_ptr<Array_as> array = ensureType<Array_as>(fn.this_ptr);
-
-    if ( fn.nargs ) // setter
-    {
-        int length = fn.arg(0).to_int();
-        if ( length < 0 ) // TODO: set a max limit too ?
-        {
-            IF_VERBOSE_ASCODING_ERRORS(
-            log_aserror("Attempt to set Array.length to a negative value %d", 
length);
-            )
-            length = 0;
-        }
-
-        array->resize(length);
-        return as_value();
-    }
-    else // getter
-    {
-        return as_value(array->size());
-    }
+    int endindex = fn.nargs > 1 ? fn.arg(1).to_int() :
+        std::numeric_limits<int>::max();
+
+    Global_as* gl = getGlobal(fn);
+    as_object* newarray = gl->createArray();
+
+    PushToArray push(*newarray);
+
+    foreachArray(*array, startindex, endindex, push);
+
+    return as_value(newarray);        
 }
 
 as_value
 array_new(const fn_call& fn)
 {
     IF_VERBOSE_ACTION (
-    log_action(_("array_new called, nargs = %d"), fn.nargs);
+        log_action(_("array_new called, nargs = %d"), fn.nargs);
     );
 
-    boost::intrusive_ptr<Array_as> ao = new Array_as;
+    // TODO: use the this_ptr
+    as_object* ao = new Array_as;
 
-    if (fn.nargs == 0)
-    {
-        // Empty array.
+    if (fn.nargs == 0) {
+        return ao;
     }
-    else if (fn.nargs == 1 && fn.arg(0).is_number() )
-    {
-        // TODO: limit max size !!
+
+    if (fn.nargs == 1 && fn.arg(0).is_number()) {
         int newSize = fn.arg(0).to_int();
-        if ( newSize < 0 ) newSize = 0;
-        else ao->resize(newSize);
-    }
-    else
-    {
-        // Use the arguments as initializers.
-        as_value    index_number;
-        for (unsigned int i = 0; i < fn.nargs; i++)
-        {
-            ao->callMethod(NSV::PROP_PUSH, fn.arg(i));
+        if (newSize < 0) newSize = 0;
+        else {
+            ao->set_member(NSV::PROP_LENGTH, newSize);
         }
-    }
-
-    IF_VERBOSE_ACTION (
-    log_action(_("array_new setting object %p in result"), (void*)ao.get());
-    );
-
-    return as_value(ao.get());
-    //return as_value(ao);
-}
-
-static void
-attachArrayProperties(as_object& proto)
-{
-    proto.init_property(NSV::PROP_LENGTH, &array_length, &array_length);
-}
-
-static void
-attachArrayStatics(as_object& proto)
-{
-    int flags = 0; // these are not protected
-    proto.init_member("CASEINSENSITIVE", Array_as::fCaseInsensitive, flags);
-    proto.init_member("DESCENDING", Array_as::fDescending, flags);
-    proto.init_member("UNIQUESORT", Array_as::fUniqueSort, flags);
-    proto.init_member("RETURNINDEXEDARRAY", Array_as::fReturnIndexedArray, 
flags);
-    proto.init_member("NUMERIC", Array_as::fNumeric, flags);
-}
-
-static void
-attachArrayInterface(as_object& proto)
-{
-    VM& vm = getVM(proto);
-
-    proto.init_member("push", vm.getNative(252, 1));
-    proto.init_member("pop", vm.getNative(252, 2));
-    proto.init_member("concat", vm.getNative(252, 3));
-    proto.init_member("shift", vm.getNative(252, 4));
-    proto.init_member("unshift", vm.getNative(252, 5));
-    proto.init_member("slice", vm.getNative(252, 6));
-    proto.init_member("join", vm.getNative(252, 7));
-    proto.init_member("splice", vm.getNative(252, 8));
-    proto.init_member("toString", vm.getNative(252, 9));
-    proto.init_member("sort", vm.getNative(252, 10));
-    proto.init_member("reverse", vm.getNative(252, 11));
-    proto.init_member("sortOn", vm.getNative(252, 12));
-}
-
-static as_object*
-getArrayInterface()
-{
-    static boost::intrusive_ptr<as_object> proto = NULL;
-    if ( proto == NULL )
-    {
-        proto = new as_object(getObjectInterface());
-        getVM(*proto).addStatic(proto.get());
-
-        attachArrayInterface(*proto);
-    }
-    return proto.get();
-}
-
-void
-registerArrayNative(as_object& global)
-{
-    VM& vm = getVM(global);
-    vm.registerNative(array_new, 252, 0);
-    vm.registerNative(array_push, 252, 1);
-    vm.registerNative(array_pop, 252, 2);
-    vm.registerNative(array_concat, 252, 3);
-    vm.registerNative(array_shift, 252, 4);
-    vm.registerNative(array_unshift, 252, 5);
-    vm.registerNative(array_slice, 252, 6);
-    vm.registerNative(array_join, 252, 7);
-    vm.registerNative(array_splice, 252, 8);
-    vm.registerNative(array_toString, 252, 9);
-    vm.registerNative(array_sort, 252, 10);
-    vm.registerNative(array_reverse, 252, 11);
-    vm.registerNative(array_sortOn, 252, 12);
-}
-
-// this registers the "Array" member on a "Global"
-// object. "Array" is a constructor, thus an object
-// with .prototype full of exported functions + 
-// 'constructor'
-//
-void
-array_class_init(as_object& glob, const ObjectURI& uri)
-{
-    // This is going to be the global Array "class"/"function"
-    static as_object* ar = 0;
-
-    if ( ar == NULL )
-    {
-        Global_as* gl = getGlobal(glob);
-        as_object* proto = getArrayInterface();
-        ar = gl->createClass(&array_new, proto);
-
-        // Attach static members
-        attachArrayStatics(*ar);
-    }
-
-    int flags = PropFlags::dontEnum; // |PropFlags::onlySWF5Up; 
-    glob.init_member(getName(uri), ar, flags, getNamespace(uri));
-}
-
-void
-Array_as::enumerateNonProperties(as_environment& env) const
-{
-    std::stringstream ss; 
-    for (const_iterator it = elements.begin(),
-        itEnd = elements.end(); it != itEnd; ++it)
-    {
-        int idx = it.index();
-        // enumerated values need to be strings, not numbers
-        ss.str(""); ss << idx;
-        env.push(as_value(ss.str()));
-    }
-}
-
-void
-Array_as::splice(unsigned int start, unsigned int count, const 
std::vector<as_value>* replace, Array_as* receive)
-{
-    size_t sz = elements.size();
-
-    assert ( start <= sz );
-    assert ( start+count <= sz );
-
-    size_t newsize = sz-count;
-    if ( replace ) newsize += replace->size();
-    ArrayContainer newelements(newsize);
-
-    size_t ni=0;
-
-    // add initial portion
-    for (size_t i=0; i<start; ++i )
-    {
-        newelements[ni++] = elements[i];
-    }
-
-    // add replacement, if any
-    if ( replace )
-    {
-        for (size_t i=0, e=replace->size(); i<e; ++i) 
-            newelements[ni++] = replace->at(i);
-    }    
-
-    // add final portion
-    for (size_t i=start+count; i<sz; ++i )
-        newelements[ni++] = elements[i];
-
-    // push trimmed data to the copy array, if any
-    if ( receive )
-    {
-        for (size_t i=start; i<start+count; ++i )
-            receive->callMethod(NSV::PROP_PUSH, elements[i]);
-    }
-
-    elements = newelements;
-}
-
-#ifdef GNASH_USE_GC
-void
-Array_as::markReachableResources() const
-{
-    for (const_iterator i=elements.begin(), e=elements.end(); i!=e; ++i)
-    {
-        (*i).setReachable();
-    }
-    markAsObjectReachable();
-}
-#endif // GNASH_USE_GC
-
-void
-Array_as::visitPropertyValues(AbstractPropertyVisitor& visitor) const
-{
-    std::stringstream ss; 
-    string_table& st = getStringTable(*this);
-    for (const_iterator i=elements.begin(), ie=elements.end(); i!=ie; ++i)
-    {
-        int idx = i.index();
-        ss.str(""); ss << idx;
-        string_table::key k = st.find(ss.str());
-        visitor.accept(k, *i);
-    }
-
-    // visit proper properties
-    as_object::visitPropertyValues(visitor);
-}
-
-void
-Array_as::visitNonHiddenPropertyValues(AbstractPropertyVisitor& visitor) const
-{
-    std::stringstream ss; 
-    string_table& st = getStringTable(*this);
-    for (const_iterator i=elements.begin(), ie=elements.end(); i!=ie; ++i)
-    {
-        // TODO: skip hidden ones
-        int idx = i.index();
-        ss.str(""); ss << idx;
-        string_table::key k = st.find(ss.str());
-        visitor.accept(k, *i);
-    }
-
-    // visit proper properties
-    as_object::visitNonHiddenPropertyValues(visitor);
-}
-
-bool
-Array_as::isStrict() const
-{
-    if ( hasNonHiddenProperties() ) return false;
-    return true;
-}
+        return ao;
+    }
+
+    // Use the arguments as initializers.
+    for (size_t i = 0; i < fn.nargs; i++) {
+        ao->callMethod(NSV::PROP_PUSH, fn.arg(i));
+    }
+
+    return as_value(ao);
+}
+
+as_value
+join(as_object* array, const std::string& separator)
+{
+    const size_t size = arrayLength(*array);
+    as_value length;
+    if (size < 1) return as_value("");
+
+    std::string s;
+
+    string_table& st = getStringTable(*array);
+    const int version = getSWFVersion(*array);
+
+    for (size_t i = 0; i < size; ++i) {
+        std::ostringstream os;
+        os << i;
+        if (i) s += separator;
+        as_value el;
+        array->get_member(st.find(os.str()), &el);
+        s += el.to_string_versioned(version);
+    }
+    return as_value(s);
+}
+
+string_table::key
+getKey(const fn_call& fn, size_t i)
+{
+    string_table& st = getStringTable(fn);
+    return arrayKey(st, i);
+}
+
+template<typename T>
+void foreachArray(as_object& array, int start, int end, T& pred)
+{
+    const int size = arrayLength(array);
+    if (!size) return;
+
+    if (start < 0) start = size + start;
+    if (start >= size) return;
+    start = std::max(start, 0);
+
+    if (end < 0) end = size + end;
+    end = std::max(start, end);
+    end = std::min<size_t>(end, size);
+
+    assert(start >= 0);
+    assert(end >= start);
+    assert(size >= end);
+
+    string_table& st = getStringTable(array);
+
+    for (size_t i = start; i < static_cast<size_t>(end); ++i) {
+        pred(array.getMember(arrayKey(st, i)));
+    }
+}
+
+void
+pushIndices(as_object& o, const std::vector<indexed_as_value>& elems)
+{
+    for (std::vector<indexed_as_value>::const_iterator it = elems.begin();
+        it != elems.end(); ++it) {
+        o.callMethod(NSV::PROP_PUSH, it->vec_index);
+    }
+}
+
+void
+getIndexedElements(as_object& array, std::vector<indexed_as_value>& v)
+{
+    PushToIndexedVector pv(v);
+    foreachArray(array, pv);
+}
+
+} // anonymous namespace
 
 } // end of gnash namespace
 

=== modified file 'libcore/asobj/Array_as.h'
--- a/libcore/asobj/Array_as.h  2009-10-14 16:12:54 +0000
+++ b/libcore/asobj/Array_as.h  2009-10-15 13:25:00 +0000
@@ -21,6 +21,7 @@
 #include "as_object.h" // for inheritance
 #include "smart_ptr.h" // GNASH_USE_GC
 #include "namedStrings.h"
+#include "Global_as.h"
 
 #include <deque>
 #include <vector>
@@ -37,23 +38,8 @@
 
 namespace gnash {
 
-struct indexed_as_value : public as_value
-{
-       int vec_index;
-
-       indexed_as_value(const as_value& val, int index)
-       : as_value(val)
-       {
-               vec_index = index;
-       }
-};
-
-template <class T>
-struct ContainerFiller {
-       T& cont;
-       ContainerFiller(T& c): cont(c) {}
-       void visit(as_value& v) { cont.push_back(v); }
-};
+size_t arrayLength(as_object& array);
+string_table::key arrayKey(string_table& st, size_t i);
 
 /// The Array ActionScript object
 class Array_as : public as_object
@@ -68,57 +54,15 @@
        typedef ArrayContainer::const_iterator const_iterator;
        typedef ArrayContainer::iterator iterator;
 
-       typedef std::list<as_value> ValueList;
-
-       /// Visit all elements 
-       //
-       /// The visitor class will have to expose a visit(as_value&) method
-       ///
-       template<class V> void visitAll(V& v)
-       {
-               // NOTE: we copy the elements as the visitor might call 
arbitrary code
-               //       possibly modifying the container itself.
-               ArrayContainer copy = elements;
-
-               // iterating this way will skip holes
-               for (Array_as::iterator i=copy.begin(), ie=copy.end(); i!=ie; 
++i)
-                       v.visit(*i);
-       }
-
     // see dox in as_object.h
        virtual void visitPropertyValues(AbstractPropertyVisitor& visitor) 
const;
 
     // see dox in as_object.h
        virtual void visitNonHiddenPropertyValues(AbstractPropertyVisitor& 
visitor) const;
 
-       /// Sort flags
-       enum SortFlags {
-
-               /// Case-insensitive (z precedes A)
-               fCaseInsensitive        = (1<<0), // 1
-
-               /// Descending order (b precedes a)
-               fDescending             = (1<<1), // 2
-
-               /// If two or more elements in the array
-               /// have identical sort fields, return 0
-               /// and don't modify the array.
-               /// Otherwise proceed to sort the array.
-               fUniqueSort             = (1<<2), // 4
-
-               /// Don't modify the array, rather return
-               /// a new array containing indexes into it
-               /// in sorted order.
-               fReturnIndexedArray     = (1<<3), // 8
-
-               /// Numerical sort (9 preceeds 10)
-               fNumeric                = (1<<4) // 16
-       };
 
        Array_as();
 
-       Array_as(const Array_as& other);
-
        ~Array_as();
 
     /// Return true if this is a strict array
@@ -130,203 +74,16 @@
     ///
     bool isStrict() const;
 
-       std::deque<indexed_as_value> get_indexed_elements();
-
        Array_as::const_iterator begin();
 
        Array_as::const_iterator end();
 
        as_value at(unsigned int index) const;
 
-       Array_as* get_indices(std::deque<indexed_as_value> origElems);
-
-       void reverse();
-
-       /// @param separator
-    ///     String to use as separator between elements
-       std::string join(const std::string& separator) const;
-
        unsigned int size() const;
 
        void resize(unsigned int);
 
-       /// \brief
-       /// Return a newly created array containing elements
-       /// from 'start' up to but not including 'end'.
-       //
-       ///
-       /// NOTE: assertions are:
-       ///
-       ///     assert(one_past_end >= start);
-       ///     assert(one_past_end <= size());
-       ///     assert(start <= size());
-       ///
-       /// @param start
-       ///     index to first element to include in result
-       ///     0-based index.
-       ///
-       /// @param one_past_end
-       ///     index to one-past element to include in result
-       ///     0-based index.
-       ///
-       boost::intrusive_ptr<Array_as> slice(
-               unsigned int start, unsigned int one_past_end);
-
-       /// \brief
-       /// Replace count elements from start with given values, optionally
-       /// returning the erased ones.
-       //
-       /// @param start
-       ///     First element to remove. Will abort if invalid.
-       ///
-       /// @param count
-       ///     Number of elements to remove. Will abort if > then available.
-       ///
-       /// @param replace
-       ///     If not null, use as a replacement for the cutted values
-       ///
-       /// @param copy
-       ///     If not null, an array to push cutted values to.
-       ///
-       void splice(unsigned int start, unsigned int count, 
-                       const std::vector<as_value>* replace=NULL,
-                       Array_as* copy=NULL);
-
-       /// \brief
-       /// Sort the array, using given values comparator
-       ///
-       /// @param avc
-       ///     boolean functor or function comparing two as_value& objects
-       ///
-       template <class AVCMP>
-       void sort(AVCMP avc)
-       {
-               // IMPORTANT NOTE
-               //
-               // As for ISO/IEC 14882:2003 - 23.2.2.4.29 
-               // the sort algorithm relies on the assumption
-               // that the comparator function implements
-               // a Strict Weak Ordering operator:
-               // http://www.sgi.com/tech/stl/StrictWeakOrdering.html
-               //
-               // Invalid comparator can lead to undefined behaviour,
-               // including invalid memory access and infinite loops.
-               //
-               // Pragmatically, it seems that std::list::sort is
-               // more robust in this reguard, so we'll sort a list
-               // instead of the queue. We want to sort a copy anyway
-               // to avoid the comparator changing the original container.
-               //
-               ValueList nelem;
-               ContainerFiller<ValueList> filler(nelem);
-               visitAll(filler);
-
-               size_t oldSize = elements.size(); // custom comparator might 
change input size
-               nelem.sort(avc);
-               elements.resize(oldSize, false);
-               size_t idx=0;
-               for (ValueList::iterator i=nelem.begin(), e=nelem.end(); i!=e; 
++i)
-               {
-                       elements[idx++] = *i;
-        }
-       }
-
-       /// \brief
-       /// Attempt to sort the array using given values comparator, avc.
-       /// If two or more elements in the array are equal, as determined
-       /// by the equality comparator ave, then the array is not sorted
-       /// and 0 is returned. Otherwise the array is sorted and returned.
-       ///
-       /// @param avc
-       ///     boolean functor or function comparing two as_value& objects
-       ///     used to determine sort-order
-       ///
-       /// @param ave
-       ///     boolean functor or function comparing two as_value& objects
-       ///     used to determine equality
-       ///
-       template <class AVCMP, class AVEQ>
-       as_value sort(AVCMP avc, AVEQ ave)
-       {
-               // IMPORTANT NOTE
-               //
-               // As for ISO/IEC 14882:2003 - 23.2.2.4.29 
-               // the sort algorithm relies on the assumption
-               // that the comparator function implements
-               // a Strict Weak Ordering operator:
-               // http://www.sgi.com/tech/stl/StrictWeakOrdering.html
-               //
-               // Invalid comparator can lead to undefined behaviour,
-               // including invalid memory access and infinite loops.
-               //
-               // Pragmatically, it seems that std::list::sort is
-               // more robust in this reguard, so we'll sort a list
-               // instead of the queue. We want to sort a copy anyway
-               // to avoid the comparator changing the original container.
-               //
-
-               typedef std::list<as_value> ValueList;
-               ValueList nelem;
-               ContainerFiller<ValueList> filler(nelem);
-               visitAll(filler);
-
-               size_t oldSize = elements.size(); // custom comparator might 
change input size
-
-               nelem.sort(avc);
-
-               if (std::adjacent_find(nelem.begin(), nelem.end(), ave) != 
nelem.end() )
-                       return as_value(0.0);
-
-               elements.resize(oldSize, false);
-               size_t idx=0;
-               for (ValueList::iterator i=nelem.begin(), e=nelem.end(); i!=e; 
++i)
-               {
-                       elements[idx++] = *i;
-               }
-
-               return as_value(this);
-       }
-
-       /// \brief
-       /// Return a new array containing sorted index of this array
-       ///
-       /// @param avc
-       ///     boolean functor or function comparing two as_value& objects
-       ///
-       template <class AVCMP>
-       Array_as* sort_indexed(AVCMP avc)
-       {
-               std::deque<indexed_as_value> ielem = get_indexed_elements();
-               std::sort(ielem.begin(), ielem.end(), avc);
-               return get_indices(ielem);
-       }
-
-       /// \brief
-       /// Return a new array containing sorted index of this array.
-       /// If two or more elements in the array are equal, as determined
-       /// by the equality comparator ave, then 0 is returned instead.
-       ///
-       /// @param avc
-       ///     boolean functor or function comparing two as_value& objects
-       ///     used to determine sort-order
-       ///
-       /// @param ave
-       ///     boolean functor or function comparing two as_value& objects
-       ///     used to determine equality
-       ///
-       template <class AVCMP, class AVEQ>
-       as_value sort_indexed(AVCMP avc, AVEQ ave)
-       {
-               std::deque<indexed_as_value> ielem = get_indexed_elements();
-
-               std::sort(ielem.begin(), ielem.end(), avc);
-
-               if (std::adjacent_find(ielem.begin(), ielem.end(), ave) != 
ielem.end() )
-                       return as_value(0.0);
-
-               return get_indices(ielem);
-       }
-
     /// Why is this overridden?
        virtual bool get_member(string_table::key name, as_value* val,
                string_table::key nsname = 0);
@@ -370,23 +127,17 @@
 
 };
 
-string_table::key arrayKey(string_table& st, size_t i);
-
 template<typename T>
-bool foreachArray(as_object& array, T& pred)
+void foreachArray(as_object& array, T& pred)
 {
-    as_value length;
-    if (!array.get_member(NSV::PROP_LENGTH, &length)) return false;
-    
-    const int size = length.to_int();
-    if (size < 0) return false;
+    size_t size = arrayLength(array);
+    if (!size) return;
 
     string_table& st = getStringTable(array);
 
     for (size_t i = 0; i < static_cast<size_t>(size); ++i) {
         pred(array.getMember(arrayKey(st, i)));
     }
-    return true;
 }
 
 /// Initialize the global.Array object

=== modified file 'libcore/asobj/AsBroadcaster.cpp'
--- a/libcore/asobj/AsBroadcaster.cpp   2009-10-14 14:31:24 +0000
+++ b/libcore/asobj/AsBroadcaster.cpp   2009-10-15 09:01:35 +0000
@@ -84,7 +84,7 @@
     }
 
     /// Call a method on the given value
-    void visit(as_value& v)
+    void operator()(const as_value& v)
     {
         boost::intrusive_ptr<as_object> o = v.to_object(*getGlobal(_fn));
         if ( ! o ) return;
@@ -126,6 +126,8 @@
     // always attached to the initialized object.
     as_value al, rl;
 
+    const int flags = as_object::DefaultFlags;
+
     if (asb) {
         al = asb->getMember(NSV::PROP_ADD_LISTENER);
         rl = asb->getMember(NSV::PROP_REMOVE_LISTENER);
@@ -139,7 +141,15 @@
     const as_value& asn = gl->callMethod(NSV::PROP_AS_NATIVE, 101, 12);
     o.set_member(NSV::PROP_BROADCAST_MESSAGE, asn);
 
+    // This corresponds to  "_listeners = [];", which is different from
+    // _listeners = new Array();
     o.set_member(NSV::PROP_uLISTENERS, gl->createArray());
+ 
+    // This function should call ASSetPropFlags on these four properties.
+    o.set_member_flags(NSV::PROP_BROADCAST_MESSAGE, flags);
+    o.set_member_flags(NSV::PROP_ADD_LISTENER, flags);
+    o.set_member_flags(NSV::PROP_REMOVE_LISTENER, flags);
+    o.set_member_flags(NSV::PROP_uLISTENERS, flags);
 
 }
 
@@ -303,67 +313,34 @@
         return as_value(false); // TODO: check this
     }
 
-    boost::intrusive_ptr<as_object> listenersObj =
+    boost::intrusive_ptr<as_object> listeners =
         listenersValue.to_object(*getGlobal(fn));
-    assert(listenersObj);
-
-    as_value listenerToRemove; assert(listenerToRemove.is_undefined());
-    if ( fn.nargs ) listenerToRemove = fn.arg(0);
-
-    boost::intrusive_ptr<Array_as> listeners = 
-        boost::dynamic_pointer_cast<Array_as>(listenersObj);
-    if ( ! listeners )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("%p.addListener(%s): this object's _listener isn't an "
-                "array: %s"), (void*)fn.this_ptr, fn.dump_args(),
-                listenersValue);
-        );
-
-        // TODO: implement brute force scan of pseudo-array
-        unsigned int length = 
-            listenersObj->getMember(NSV::PROP_LENGTH).to_int();
-
-        string_table& st = getStringTable(fn);
-
-        for (unsigned int i=0; i<length; ++i)
-        {
-            as_value iVal(i);
-            std::string n = iVal.to_string();
-            as_value v = listenersObj->getMember(st.find(n));
-            if ( v.equals(listenerToRemove) )
-            {
-                listenersObj->callMethod(NSV::PROP_SPLICE, iVal, as_value(1));
-                return as_value(true); 
-            }
-        }
-
-        return as_value(false); // TODO: check this
-    }
-    else
-    {
-        // Remove the first listener matching the new value
-        // See http://www.senocular.com/flash/tutorials/
-        // listenersasbroadcaster/?page=2
-        
-        // This is an ActionScript-like implementation, which is why it looks
-        // like poor C++.
-        int length = listenersObj->getMember(NSV::PROP_LENGTH).to_int();
-        int i = 0;
-        string_table& st = getStringTable(fn);
-        while (i < length) {
-            std::ostringstream s;
-            s << i;
-            as_value el =
-                listenersObj->getMember(st.find(s.str()));
-            if (el.equals(listenerToRemove)) {
-                listeners->callMethod(NSV::PROP_SPLICE, s.str(), 1);
-                return as_value(true);
-            }
-            ++i;
-        }
-        return as_value(false);
-    }
+    assert(listeners);
+
+    as_value listenerToRemove; 
+    if (fn.nargs) listenerToRemove = fn.arg(0);
+
+    // Remove the first listener matching the new value
+    // See http://www.senocular.com/flash/tutorials/
+    // listenersasbroadcaster/?page=2
+    
+    // This is an ActionScript-like implementation, which is why it looks
+    // like poor C++.
+    int length = listeners->getMember(NSV::PROP_LENGTH).to_int();
+    int i = 0;
+    string_table& st = getStringTable(fn);
+    while (i < length) {
+        std::ostringstream s;
+        s << i;
+        as_value el =
+            listeners->getMember(st.find(s.str()));
+        if (el.equals(listenerToRemove)) {
+            listeners->callMethod(NSV::PROP_SPLICE, s.str(), 1);
+            return as_value(true);
+        }
+        ++i;
+    }
+    return as_value(false);
 
 }
 
@@ -400,21 +377,9 @@
         return as_value(); // TODO: check this
     }
 
-    boost::intrusive_ptr<Array_as> listeners =
-        dynamic_cast<Array_as*>(listenersValue.to_object(*getGlobal(fn)));
-
-    if ( ! listeners )
-    {
-        IF_VERBOSE_ASCODING_ERRORS(
-        log_aserror(_("%p.addListener(%s): this object's _listener "
-                "isn't an array: %s"), (void*)fn.this_ptr,
-                fn.dump_args(), listenersValue);
-        );
-        return as_value(); // TODO: check this
-    }
-
-    if (!fn.nargs)
-    {
+    as_object* listeners = listenersValue.to_object(*getGlobal(fn));
+
+    if (!fn.nargs) {
         IF_VERBOSE_ASCODING_ERRORS(
         log_aserror("%p.broadcastMessage() needs an argument", 
             (void*)fn.this_ptr);
@@ -423,11 +388,11 @@
     }
 
     BroadcasterVisitor visitor(fn); 
-    listeners->visitAll(visitor);
-
-    unsigned int dispatched = visitor.eventsDispatched();
-
-    if ( dispatched ) return as_value(true);
+    foreachArray(*listeners, visitor);
+
+    const size_t dispatched = visitor.eventsDispatched();
+
+    if (dispatched) return as_value(true);
 
     return as_value(); 
 

=== modified file 'libcore/asobj/Global_as.h'
--- a/libcore/asobj/Global_as.h 2009-10-14 14:20:47 +0000
+++ b/libcore/asobj/Global_as.h 2009-10-15 09:01:14 +0000
@@ -85,9 +85,7 @@
 
     /// Create an Array object
     //
-    /// This calls the Array constructor. If that has been changed, this
-    /// function may not produce an Array object. This is generally
-    /// expected behaviour.
+    /// This creates an Array object without calling the Array constructor.
     virtual as_object* createArray() = 0;
 
     /// Create an Object

=== modified file 'libcore/asobj/Globals.cpp'
--- a/libcore/asobj/Globals.cpp 2009-10-14 14:20:47 +0000
+++ b/libcore/asobj/Globals.cpp 2009-10-15 08:59:26 +0000
@@ -247,7 +247,9 @@
 as_object*
 AVM1Global::createArray()
 {
-    return new Array_as();
+    as_object* array = new Array_as;
+    array->init_member(NSV::PROP_CONSTRUCTOR, getMember(NSV::CLASS_ARRAY));
+    return array;
 }
 
 as_object*
@@ -307,7 +309,9 @@
 as_object*
 AVM2Global::createArray()
 {
-    return new Array_as();
+    as_object* array = new Array_as;
+    array->init_member(NSV::PROP_CONSTRUCTOR, getMember(NSV::CLASS_ARRAY));
+    return array;
 }
 
 void 

=== modified file 'libcore/asobj/MovieClipLoader.cpp'
--- a/libcore/asobj/MovieClipLoader.cpp 2009-10-14 14:41:39 +0000
+++ b/libcore/asobj/MovieClipLoader.cpp 2009-10-14 18:37:43 +0000
@@ -39,7 +39,6 @@
 #include "Object.h" // for getObjectInterface
 #include "AsBroadcaster.h" // for initializing self as a broadcaster
 #include "namedStrings.h"
-#include "Array_as.h" // for _listeners construction
 #include "ExecutableCode.h"
 
 #include <string>

=== modified file 'libcore/asobj/Selection_as.cpp'
--- a/libcore/asobj/Selection_as.cpp    2009-10-14 08:47:08 +0000
+++ b/libcore/asobj/Selection_as.cpp    2009-10-15 09:16:40 +0000
@@ -56,11 +56,17 @@
 selection_class_init(as_object& where, const ObjectURI& uri)
 {
        // Selection is NOT a class, but a simple object, see Selection.as
-    as_object* proto = registerBuiltinObject(where, attachSelectionInterface,
+    as_object* o = registerBuiltinObject(where, attachSelectionInterface,
             uri);
 
     /// Handles addListener, removeListener, and _listeners.
-    AsBroadcaster::initialize(*proto);
+    AsBroadcaster::initialize(*o);
+
+    // All properties are protected using ASSetPropFlags.
+    string_table& st = getStringTable(where);
+    Global_as* gl = getGlobal(where);
+    as_object* null = 0;
+    gl->callMethod(st.find("ASSetPropFlags"), o, null, 7);
 }
 
 void

=== modified file 'libcore/asobj/TextFormat_as.cpp'
--- a/libcore/asobj/TextFormat_as.cpp   2009-10-14 08:47:08 +0000
+++ b/libcore/asobj/TextFormat_as.cpp   2009-10-15 07:30:20 +0000
@@ -280,41 +280,40 @@
        return ret;
 }
 
+class PushToVector
+{
+public:
+    PushToVector(std::vector<int>& v) : _v(v) {}
+    void operator()(const as_value& val) {
+        _v.push_back(val.to_number());
+    }
+private:
+    std::vector<int>& _v;
+};
+
 as_value
 textformat_tabStops(const fn_call& fn)
 {
     TextFormat_as* relay = ensureNativeType<TextFormat_as>(fn.this_ptr);
        
-       as_value ret;
-               
-       if (!fn.nargs)
-       {
-               ret.set_null();
-               return ret;
+    if (!fn.nargs) {
+               LOG_ONCE( log_unimpl("Getter for textformat_tabStops") );
+        as_value null;
+        null.set_null();
+        return null;
        }
        
     as_object* arg = fn.arg(0).to_object(*getGlobal(fn));
-    Array_as* tStops = dynamic_cast<Array_as*>(arg);
-
-    if (!tStops) return as_value();
-                       
-       std::vector<int> tabStops(tStops->size());
-
-       for (size_t i = 0; i !=tStops->size(); ++i)
-       {
-               tabStops[i]=tStops->at(i).to_number();
-       }
-
-       if ( fn.nargs == 0)     // getter
-       {
-               LOG_ONCE( log_unimpl("Getter for textformat_tabStops") );
-       }
-       else                            // setter
-       {
-               relay->tabStopsSet(tabStops);
-       }
+    if (!arg) return as_value();
+
+       std::vector<int> tabStops;
+
+    PushToVector pv(tabStops);
+    foreachArray(*arg, pv);
+
+    relay->tabStopsSet(tabStops);
        
-       return ret;
+       return as_value();
 }
 
 as_value

=== modified file 'libcore/swf_function.cpp'
--- a/libcore/swf_function.cpp  2009-10-14 14:41:58 +0000
+++ b/libcore/swf_function.cpp  2009-10-15 09:00:54 +0000
@@ -17,7 +17,6 @@
 
 #include "log.h"
 #include "swf_function.h"
-#include "Array_as.h"
 #include "fn_call.h"
 #include "MovieClip.h"
 #include "action_buffer.h"
@@ -364,22 +363,15 @@
 getArguments(swf_function& callee, const fn_call& fn,
         as_object* caller)
 { 
-#ifndef GNASH_USE_GC
-       // We'll be storing the callee as_object into an as_value
-       // so you must make sure you have a reference on it before
-       // callign this function.
-       assert(callee.get_ref_count() > 0);
-#endif // ndef GNASH_USE_GC
 
-       // Super class prototype is : obj.__proto__.constructor.prototype 
        as_object* arguments = getGlobal(fn)->createArray();
-       for (unsigned int i=0; i<fn.nargs; ++i) {
+       for (size_t i = 0; i < fn.nargs; ++i) {
                arguments->callMethod(NSV::PROP_PUSH, fn.arg(i));
        }
 
        arguments->init_member(NSV::PROP_CALLEE, &callee);
 
-       arguments->init_member(NSV::PROP_CALLER, as_value(caller));
+       arguments->init_member(NSV::PROP_CALLER, caller);
 
        return arguments;
 

=== modified file 'libcore/swf_function.h'
--- a/libcore/swf_function.h    2009-10-14 14:41:58 +0000
+++ b/libcore/swf_function.h    2009-10-14 18:14:45 +0000
@@ -34,7 +34,6 @@
 namespace gnash {
        class action_buffer;
        class as_environmnet;
-       class Array_as;
 }
 
 namespace gnash {

=== modified file 'libcore/vm/ASHandlers.cpp'
--- a/libcore/vm/ASHandlers.cpp 2009-10-14 15:44:50 +0000
+++ b/libcore/vm/ASHandlers.cpp 2009-10-15 09:00:29 +0000
@@ -2807,11 +2807,12 @@
 
     const int array_size = env.pop().to_int();
     assert(array_size >= 0); // TODO: trigger this !!
-
-    // Call the array constructor, to create an empty array.
-    as_value result = getGlobal(env)->createArray();
-
-    boost::intrusive_ptr<as_object> ao = 
convertToObject(*getGlobal(thread.env), result);
+    
+    Global_as* gl = getGlobal(env);
+
+    as_value result = gl->createArray();
+
+    as_object* ao = convertToObject(*getGlobal(thread.env), result);
     assert(ao);
 
     // Fill the elements with the initial values from the stack.

=== modified file 'testsuite/actionscript.all/Function.as'
--- a/testsuite/actionscript.all/Function.as    2009-02-25 22:33:03 +0000
+++ b/testsuite/actionscript.all/Function.as    2009-10-15 09:45:00 +0000
@@ -441,12 +441,12 @@
         propRecorder.push(props.toString());
     }
     propRecorder.sort();
-    xcheck_equals(propRecorder.length, 5);
+    check_equals(propRecorder.length, 5);
     check_equals(propRecorder[0], '__proto__');
     check_equals(propRecorder[1], 'callee');
     check_equals(propRecorder[2], 'caller');
-    xcheck_equals(propRecorder[3], 'constructor');
-    xcheck_equals(propRecorder[4], 'length');
+    check_equals(propRecorder[3], 'constructor');
+    check_equals(propRecorder[4], 'length');
 }
 f();
 

=== modified file 'testsuite/actionscript.all/array.as'
--- a/testsuite/actionscript.all/array.as       2009-10-14 11:56:50 +0000
+++ b/testsuite/actionscript.all/array.as       2009-10-15 12:28:05 +0000
@@ -211,8 +211,8 @@
 gaparray.sort();
 check_equals(gaparray.length, 17);
 #if OUTPUT_VERSION < 7
- xcheck_equals(gaparray[0], undefined); // this is 16 with gnash
- xcheck_equals(gaparray[1], undefined); // this is 4 with gnash
+ check_equals(gaparray[0], undefined); // this is 16 with gnash
+ check_equals(gaparray[1], undefined); // this is 4 with gnash
 #else
  check_equals(gaparray[0], '16');
  check_equals(gaparray[1], '4');
@@ -231,8 +231,8 @@
 check_equals(gaparray[13], undefined);
 check_equals(gaparray[14], undefined);
 #if OUTPUT_VERSION < 7
-  xcheck_equals(gaparray[15], '16'); // this is at [0] with gnash
-  xcheck_equals(gaparray[16], '4'); // this is at [1] with gnash
+  check_equals(gaparray[15], '16'); // this is at [0] with gnash
+  check_equals(gaparray[16], '4'); // this is at [1] with gnash
 #else
   check_equals(gaparray[15], undefined);
   check_equals(gaparray[16], undefined);
@@ -240,16 +240,16 @@
 
 #if OUTPUT_VERSION > 5
 #if OUTPUT_VERSION < 7
- xcheck(gaparray.hasOwnProperty('15'));
- xcheck(gaparray.hasOwnProperty('16'));
- xcheck(gaparray.hasOwnProperty('4')); // a-ha!
+ check(gaparray.hasOwnProperty('15'));
+ check(gaparray.hasOwnProperty('16'));
+ check(gaparray.hasOwnProperty('4')); // a-ha!
  xcheck(!gaparray.hasOwnProperty('0'));
 #else
- xcheck(gaparray.hasOwnProperty('16'));
- xcheck(gaparray.hasOwnProperty('4')); 
+ check(gaparray.hasOwnProperty('16'));
+ check(gaparray.hasOwnProperty('4')); 
  check(gaparray.hasOwnProperty('1'));
  check(gaparray.hasOwnProperty('0'));
- xcheck(gaparray.hasOwnProperty('2'));
+ check(gaparray.hasOwnProperty('2'));
 #endif
 #endif
 
@@ -739,7 +739,7 @@
 check_equals(c[0], 'zero');
 c.length = -1;
 // it seems Gnash needs to store the 'length' property as a normal property
-xcheck_equals(c.length, -1);
+check_equals(c.length, -1);
 check_equals(c[0], undefined);
 
 //-------------------------------
@@ -1519,6 +1519,96 @@
 xcheck_equals(o.length, 6);
 
 
+o = fakeArray();
+o.reverse = Array.prototype.reverse;
+
+// Order of property creation.
+check_equals(traceProps(o), "reverse,length,7,6,5,4,3,2,1,");
+
+o.reverse();
+
+// Length is unchanged, Properties are swapped from the outside
+check_equals(traceProps(o), "3,2,4,1,5,0,reverse,length,7,6,");
+check_equals(o.length, 6);
+
+// Check with an uneven length to see what happens to the middle property.
+o = fakeArray();
+o.reverse = Array.prototype.reverse;
+o.length = 5;
+o.reverse();
+// The middle property is left alone...
+check_equals(traceProps(o), "3,1,4,0,reverse,length,7,6,5,2,");
+check_equals(o.length, 5);
+
+// Array.splice
+
+// This is different from other functions in that it doesn't delete and
+// readd properties so much.
+
+o = fakeArray();
+o.splice = Array.prototype.splice;
+
+// Order of property creation.
+check_equals(traceProps(o), "splice,length,7,6,5,4,3,2,1,");
+
+// Note: this function *does* set length!
+check_equals(o.length, 6);
+o.splice(2, 3, "new1", "new2");
+
+check_equals(traceProps(o), "0,splice,length,7,6,5,4,3,2,1,");
+check_equals(o.length, 5);
+
+// The spliced elements are there.
+check_equals(o[2], "new1");
+check_equals(o[3], "new2");
+
+// The new 0 element is undefined.
+check_equals(o[0], undefined);
+
+// The last element is shifted down (because 3 elements were deleted).
+check_equals(o[4], "five");
+
+// Same again with different arguments
+
+o = fakeArray();
+o.splice = Array.prototype.splice;
+
+// Order of property creation.
+check_equals(traceProps(o), "splice,length,7,6,5,4,3,2,1,");
+
+// Note: this function *does* set length!
+check_equals(o.length, 6);
+o.splice(2, 1, "new1", "new2", "new3", "new4");
+
+check_equals(traceProps(o), "8,0,splice,length,7,6,5,4,3,2,1,");
+check_equals(o.length, 9);
+
+// The spliced elements are there.
+check_equals(o[2], "new1");
+check_equals(o[3], "new2");
+check_equals(o[4], "new3");
+check_equals(o[5], "new4");
+
+// The new 0 element is undefined.
+check_equals(o[0], undefined);
+
+// Elements were shifted up.
+check_equals(o[6], "three");
+
+// Sort
+
+o = fakeArray();
+o.sort = Array.prototype.sort;
+
+// Order of property creation.
+check_equals(traceProps(o), "sort,length,7,6,5,4,3,2,1,");
+
+check_equals(o.length, 6);
+o.sort();
+xcheck_equals(traceProps(o), "5,4,2,1,0,sort,length,7,6,3,");
+o.sort();
+xcheck_equals(traceProps(o), "5,4,2,1,0,sort,length,7,6,3,");
+
 // TODO: test ASnative-returned functions:
 //
 // ASnative(252, 1) - [Array.prototype] push
@@ -1537,11 +1627,11 @@
 
 
 #if OUTPUT_VERSION < 6
- check_totals(511);
+ check_totals(538);
 #else
 # if OUTPUT_VERSION < 7
-  check_totals(572);
+  check_totals(599);
 # else
-  check_totals(582);
+  check_totals(609);
 # endif
 #endif

=== modified file 'testsuite/swfdec/PASSING'
--- a/testsuite/swfdec/PASSING  2009-10-14 14:52:58 +0000
+++ b/testsuite/swfdec/PASSING  2009-10-15 12:29:22 +0000
@@ -37,6 +37,14 @@
 and-or-5.swf:a734facbc191156759ad278e25c3f308
 and-or-6.swf:a3a02811b62c07c4d2dd6d6d547f1d2f
 and-or-7.swf:b4c3eb73aa8e0403e8d141516b25c9c6
+arguments-5.swf:2712ea54d1025d73ad6e795df93f903f
+arguments-6.swf:d4748be43bba30ec009054c66088b2d1
+arguments-7.swf:bd2a91045bf857425fc2a3fc76b01432
+arguments-8.swf:f5a0a73cb5edf43fb33addb29477dbc1
+arguments-properties-5.swf:b6cc55d99c634b93ba165ef3b260773e
+arguments-properties-6.swf:50791d04c6e61b979acd669d07cbf020
+arguments-properties-7.swf:702ef669c7c91b474a1148a4ca9e988d
+arguments-properties-8.swf:69c543519ab2cb034179121b7f334a3a
 array-init.swf:dc3e0f1daa53a2574efdb75f98579f10
 array-movieclip-5.swf:99c50528aa81f1ef5184d6ae35b14419
 array-movieclip-6.swf:dcef7fcaf030813f6e53823231ce16e1
@@ -47,6 +55,10 @@
 array-new-7.swf:77c4510eed0fd37d8654f761800edcce
 array-new-8.swf:8b26fcd892b0cd7a1cd2832d3844d00d
 array-new-override-5.swf:5016b51c60e30ee262b3cb022ba4c58f
+array-properties-5.swf:e4b9235bdad5543e29893d8166c16a9a
+array-properties-6.swf:822c1697e2f36bdfc87574a100583c78
+array-properties-7.swf:bd3778e753752345ae8c2d72b3ccaf3a
+array-properties-8.swf:0c1b9f40c4f736592b7673dbdd7ed7da
 array-sort-custom-call-5.swf:3bfe136dfda4403b1984aae59fde2144
 array-sort-custom-call-6.swf:d2517fbff896c1586947664ea20befa7
 array-sort-custom-call-7.swf:6293fd0f9a5cc6498ebcbe3d90aeca69
@@ -73,6 +85,9 @@
 asbroadcaster-override-7.swf:5834d9f0de106265f5ff479d789d2f35
 asbroadcaster-override-8.swf:017c5505a342570726c90b81297626dc
 asbroadcaster-properties-5.swf:577ad0de1cd33a97f6e2f146c61acc5f
+asbroadcaster-properties-6.swf:84104e706af43d2475ca3205bf29a0d7
+asbroadcaster-properties-7.swf:903c541124f61a03b0ca9dac94d58ad5
+asbroadcaster-properties-8.swf:f2505bf99e20b7ebc3c1f6299afb62bc
 asnative-create-5.swf:d10ce975ae57f9a6e29c8fc97eb01489
 asnative-create-6.swf:79aa26f566218edbdecdb46e88be7a1a
 asnative-create-7.swf:b3f18c999ed081ac39132ec6a9df2cb0
@@ -233,6 +248,9 @@
 constructor-prototype.swf:22505f0f8dd8440972a298110d697e3b
 constructor-relay-5.swf:2d1a814c37f55485d66624cb97c58e03
 construct-properties-5.swf:2683d3e400600e0288470ca5b6fbe94c
+construct-properties-6.swf:d8c0a2d334d05f749723a6838ed74846
+construct-properties-7.swf:de42399270c7f000cb4c1ce45a0cc960
+construct-properties-8.swf:854f7cddf97ab71b44b5f3bba3b193ef
 context-menu-5.swf:867624e2cb2c3d47dc07270d756152db
 context-menu-6.swf:9124c06f1cc4725684717eb3641837bd
 context-menu-7.swf:fc22bea201998188714399c2de1ac1f5
@@ -517,6 +535,9 @@
 function1.swf:56879c1d57617765e2ecf8c0a49047d8
 function2.swf:021842f44ba2c3e5c7c13786c7cc88ea
 function-apply-5.swf:4a8ae3ed3fe3e636c0aede2188dd9b92
+function-apply-6.swf:073f44454b9bb49166669972f4c42b07
+function-apply-7.swf:d66d3cd59b25291608b0d8de6d12d3f3
+function-apply-8.swf:1059cbf4b69d722259b0c40bad6d2b75
 function-apply-crash-5.swf:cdaa243e5975d08e61781ad5632423f2
 function-apply-crash-6.swf:d37c7e90d823363dcc4052167fcbb754
 function-apply-crash-7.swf:28334f00875b4d137083a98c13fbab87
@@ -963,6 +984,11 @@
 propflags-get-9.swf:56b0cf506962343f670d24c4ed64dedf
 propflags-get-prototype-5.swf:7fa60f65a1c0eb1a2f52c4e8e982a91e
 propflags-get-prototype-9.swf:713e3808411e4c89458fae8c082e208f
+propflags-set-5.swf:02158398265d21cd9affa7dfa79962fe
+propflags-set-6.swf:c56c07b9b4f13e7134317ad34c148087
+propflags-set-7.swf:6978b6af0019c9d63094ec7cb3b300f3
+propflags-set-8.swf:02e155d9e727aa14abed95ef53e4eee3
+propflags-set-9.swf:69ed1781166bfb3688e0bb16052a34eb
 propflags-set-native-5.swf:a0c0652f4c7a1626e064ae0dd6a867a8
 propflags-set-native-8.swf:b11c0be85a33c08d588897a99ed35f7f
 propflags-set-proto-5.swf:d8cfcbffc8213a9eb60301a877f750e1


reply via email to

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