gnash-commit
[Top][All Lists]
Advanced

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

[Gnash-commit] /srv/bzr/gnash/trunk r11405: Clean up and make object con


From: Benjamin Wolsey
Subject: [Gnash-commit] /srv/bzr/gnash/trunk r11405: Clean up and make object conversion more consistent (and correct);
Date: Tue, 11 Aug 2009 13:45:26 +0200
User-agent: Bazaar (1.16.1)

------------------------------------------------------------
revno: 11405 [merge]
committer: Benjamin Wolsey <address@hidden>
branch nick: trunk
timestamp: Tue 2009-08-11 13:45:26 +0200
message:
  Clean up and make object conversion more consistent (and correct);
  importantly, this removes the need to access prototype code from outside
  various files.
  
  Add tests for those kind of conversions.
  
  Fix a bug in XML's and LoadVars's sendAndLoad method.
  
  Newly-added swfdec tests pass.
modified:
  libbase/URL.cpp
  libcore/as_function.cpp
  libcore/asobj/Boolean_as.cpp
  libcore/asobj/Boolean_as.h
  libcore/asobj/Globals.cpp
  libcore/asobj/LoadableObject.cpp
  libcore/asobj/Number_as.cpp
  libcore/asobj/Number_as.h
  libcore/asobj/Object.cpp
  libcore/asobj/String_as.cpp
  libcore/asobj/String_as.h
  libcore/asobj/flash/ui/Mouse_as.cpp
  libcore/vm/ASHandlers.cpp
  testsuite/actionscript.all/Object.as
  testsuite/swfdec/PASSING
=== modified file 'libbase/URL.cpp'
--- a/libbase/URL.cpp   2009-05-04 20:07:52 +0000
+++ b/libbase/URL.cpp   2009-08-11 11:13:30 +0000
@@ -294,18 +294,18 @@
 URL::str() const
 {
     std::string ret = _proto + "://" + _host;
-       if ( _port != "" )
-       {
+
+    if (!_port.empty()) {
                ret += ":" + _port;
        }
     
-        ret += _path;
-       if ( _querystring != "" )
-       {
+    ret += _path;
+
+    if (!_querystring.empty()) {
                ret += "?" + _querystring;
        }
-       if ( _anchor != "" )
-       {
+
+    if (!_anchor.empty()) {
                ret += "#" + _anchor;
        }
        return ret;
@@ -346,14 +346,14 @@
 
        // extract the parameters from the URL
 
-       size_t qmpos = _path.find("?");
+    std::string::size_type qmpos = _path.find("?");
        if (qmpos == std::string::npos)
        {
                // no query string
                return;
        }
 
-       _querystring = _path.substr(qmpos+1);
+       _querystring = _path.substr(qmpos + 1);
 
        // update _path
        _path.erase(qmpos);

=== modified file 'libcore/as_function.cpp'
--- a/libcore/as_function.cpp   2009-07-16 10:52:17 +0000
+++ b/libcore/as_function.cpp   2009-08-11 09:16:26 +0000
@@ -174,6 +174,11 @@
             // reasonable, but anything else shouldn't be caught here.
                        log_debug("Native function called as constructor threw 
exception: "
                     "%s", ex.what());
+
+            // If a constructor throws an exception, throw it back to the
+            // caller. This is the only way to signal that a constructor
+            // did not return anything.
+            throw;
                }
 
                if (ret.is_object()) newobj = ret.to_object(*getGlobal(env));
@@ -182,7 +187,9 @@
                        newobj = new as_object();
                }
 
-               assert(newobj); // we assume builtin functions do return 
objects !!
+        // There should always be an object by this stage. Failed constructors
+        // are handled in the catch.
+               assert(newobj); 
 
                // Add a __constructor__ member to the new object, but only for 
SWF6 up
                // (to be checked). NOTE that we assume the builtin constructors

=== modified file 'libcore/asobj/Boolean_as.cpp'
--- a/libcore/asobj/Boolean_as.cpp      2009-07-29 05:59:24 +0000
+++ b/libcore/asobj/Boolean_as.cpp      2009-08-11 09:16:57 +0000
@@ -79,21 +79,6 @@
 
 }
 
-as_object*
-init_boolean_instance(Global_as& g, bool val)
-{
-    boost::intrusive_ptr<as_object> cl = getBooleanClass(g);
-    as_function* ctor = cl->to_function();
-    if (!ctor) return 0;
-
-    as_environment env(getVM(g));
-
-    std::auto_ptr< std::vector<as_value> > args ( new std::vector<as_value> );
-    args->push_back(val);
-    return ctor->constructInstance(env, args).get();
-}
-
-
 namespace {
 
 as_object*

=== modified file 'libcore/asobj/Boolean_as.h'
--- a/libcore/asobj/Boolean_as.h        2009-07-16 08:30:06 +0000
+++ b/libcore/asobj/Boolean_as.h        2009-08-11 09:16:57 +0000
@@ -29,9 +29,6 @@
 
 /// Initialize the global Boolean class
 void boolean_class_init(as_object& global, const ObjectURI& uri);
-
-/// Return a Boolean instance (in case the core lib needs it)
-as_object* init_boolean_instance(Global_as& g, bool val);
   
 } // end of gnash namespace
 

=== modified file 'libcore/asobj/Globals.cpp'
--- a/libcore/asobj/Globals.cpp 2009-08-07 08:43:01 +0000
+++ b/libcore/asobj/Globals.cpp 2009-08-11 09:15:29 +0000
@@ -147,6 +147,8 @@
     as_value global_setInterval(const fn_call& fn);
     
     void registerNatives(as_object& global);
+    template<typename T> as_object* constructObject(Global_as& gl, const T& 
arg,
+            string_table::key className);
 }
 
 AVM2Global::AVM2Global(Machine& /*machine*/, VM& vm)
@@ -213,19 +215,26 @@
 as_object*
 AVM1Global::createString(const std::string& s)
 {
-    return init_string_instance(*this, s);
+    // This is not really correct. If there is no String class, to_object()
+    // returns an undefined value, not a null object. The behaviour is the
+    // same for versions 5 to 8.
+    return constructObject(*this, s, NSV::CLASS_STRING);
 }
 
 as_object*
 AVM1Global::createNumber(double d)
 {
-    return init_number_instance(*this, d);
+    // This is not really correct. If there is no String class, to_object()
+    // returns an undefined value, not a null object. The behaviour is the
+    // same for versions 5 to 8.
+    return constructObject(*this, d, NSV::CLASS_NUMBER);
+
 }
 
 as_object*
 AVM1Global::createBoolean(bool b)
 {
-    return init_boolean_instance(*this, b);
+    return constructObject(*this, b, NSV::CLASS_BOOLEAN);
 }
     
 as_object*
@@ -257,19 +266,21 @@
 as_object*
 AVM2Global::createString(const std::string& s)
 {
-    return init_string_instance(*this, s);
+    // What AVM2 does for createString is untested, so we do the same
+    // as AVM1 for now.
+    return constructObject(*this, s, NSV::CLASS_STRING);
 }
 
 as_object*
 AVM2Global::createNumber(double d)
 {
-    return init_number_instance(*this, d);
+    return constructObject(*this, d, NSV::CLASS_NUMBER);
 }
 
 as_object*
 AVM2Global::createBoolean(bool b)
 {
-    return init_boolean_instance(*this, b);
+    return constructObject(*this, b, NSV::CLASS_BOOLEAN);
 }
 
 void 
@@ -1142,6 +1153,44 @@
 }
 
 
+/// Construct an instance of the specified global class.
+//
+/// If the class is not present or is not a constructor function, this
+/// function throws an ActionTypeError.
+//
+/// TODO: consider whether ActionTypeError is an appropriate exception.
+/// TODO: test the other failure cases.
+template<typename T> as_object* constructObject(Global_as& gl, const T& arg,
+        string_table::key className)
+{
+    as_value clval;
+
+    // This is tested in actionscript.all/Object.as to return an 
+    // undefined value. We throw the exception back to the VM, which pushes
+    // an undefined value onto the stack.
+    if (!gl.get_member(className, &clval) ) {
+        throw ActionTypeError();
+    }
+    
+    // This is not properly tested.
+    if (!clval.is_function()) {
+        throw ActionTypeError();
+    }
+    
+    as_function* ctor = clval.to_as_function();
+
+    // This is also not properly tested.
+    if (!ctor) throw ActionTypeError();
+
+    std::auto_ptr<std::vector<as_value> > args(new std::vector<as_value>);
+    args->push_back(arg);
+    as_environment env(getVM(gl));
+    as_object* ret = ctor->constructInstance(env, args).get();
+
+    return ret;
+
+}
+
 void
 registerNatives(as_object& global)
 {

=== modified file 'libcore/asobj/LoadableObject.cpp'
--- a/libcore/asobj/LoadableObject.cpp  2009-07-16 08:53:33 +0000
+++ b/libcore/asobj/LoadableObject.cpp  2009-08-11 11:13:35 +0000
@@ -160,9 +160,19 @@
         std::ostringstream data;
         toString(data, true);
 
-       std::string getURL = urlstr + "?" + data.str();
-        log_debug("Using GET method for sendAndLoad: %s", getURL);
-        str = ri.streamProvider().getStream(getURL);
+        const std::string& dataString = data.str();
+
+        // Any data must be added to the existing querystring.
+        if (!dataString.empty()) {
+
+            std::string existingQS = url.querystring();
+            if (!existingQS.empty()) existingQS += "&";
+
+            url.set_querystring(existingQS + data.str());
+        }
+
+        log_debug("Using GET method for sendAndLoad: %s", url.str());
+        str = ri.streamProvider().getStream(url.str());
     }
 
        log_security(_("Loading from url: '%s'"), url.str());

=== modified file 'libcore/asobj/Number_as.cpp'
--- a/libcore/asobj/Number_as.cpp       2009-07-29 06:12:35 +0000
+++ b/libcore/asobj/Number_as.cpp       2009-08-11 09:17:11 +0000
@@ -198,7 +198,8 @@
 
 
 // extern (used by Global.cpp)
-void number_class_init(as_object& global, const ObjectURI& uri)
+void
+number_class_init(as_object& global, const ObjectURI& uri)
 {
     boost::intrusive_ptr<as_object> cl = getNumberClass(*getGlobal(global));
 
@@ -208,20 +209,4 @@
 
 }
 
-as_object*
-init_number_instance(Global_as& g, double val)
-{
-    boost::intrusive_ptr<as_object> cl = getNumberClass(g);
-    as_function* ctor = cl->to_function();
-    if (!ctor) return 0;
-
-    as_environment env(getVM(g));
-
-    std::auto_ptr< std::vector<as_value> > args ( new std::vector<as_value> );
-    args->push_back(val);
-
-    return ctor->constructInstance(env, args).get();
-}
-
-  
 } // namespace gnash

=== modified file 'libcore/asobj/Number_as.h'
--- a/libcore/asobj/Number_as.h 2009-07-16 08:30:06 +0000
+++ b/libcore/asobj/Number_as.h 2009-08-11 09:17:11 +0000
@@ -33,9 +33,6 @@
 /// Initialize the global Number class
 void number_class_init(as_object& global, const ObjectURI& uri);
 
-/// Return a Number instance
-as_object* init_number_instance(Global_as& g, double val);
-
 }
 
 #endif // GNASH_NUMBER_H

=== modified file 'libcore/asobj/Object.cpp'
--- a/libcore/asobj/Object.cpp  2009-08-07 09:53:58 +0000
+++ b/libcore/asobj/Object.cpp  2009-08-11 08:35:18 +0000
@@ -170,31 +170,24 @@
 object_ctor(const fn_call& fn)
 {
     Global_as* gl = getGlobal(fn);
+    as_object* proto = getObjectInterface();
 
        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 (obj) return as_value(obj);
        }
 
-       if (fn.nargs) {
+       if (fn.nargs > 1) {
                IF_VERBOSE_ASCODING_ERRORS(
                    log_aserror(_("Too many args to Object constructor"));
                );
        }
 
     if (!fn.isInstantiation()) {
-        return gl->createObject();;
+        return gl->createObject();
     }
 
-    as_object* proto = getObjectInterface();
-    boost::intrusive_ptr<as_object> obj = gl->createObject(proto);
-
-       return as_value(obj.get()); 
+    return gl->createObject(proto);
 }
 
 

=== modified file 'libcore/asobj/String_as.cpp'
--- a/libcore/asobj/String_as.cpp       2009-07-29 05:59:24 +0000
+++ b/libcore/asobj/String_as.cpp       2009-08-11 08:35:50 +0000
@@ -110,49 +110,8 @@
     std::string _string;
 };
 
-as_object*
-init_string_instance(Global_as& g, const std::string& val)
-{
-       as_environment env(getVM(g));
-
-       int swfVersion = getSWFVersion(g);
-
-       boost::intrusive_ptr<as_function> ctor;
-
-       if ( swfVersion < 6 ) {
-               as_object* sc = getStringConstructor(g);
-        if (sc) ctor = sc->to_function();
-       }
-       else {
-               as_value clval;
-
-               if (!g.get_member(NSV::CLASS_STRING, &clval) ) {
-                       log_debug("UNTESTED: String instantiation requested but 
"
-                    "_global doesn't contain a 'String' symbol. Returning "
-                    "the NULL object.");
-                       return ctor.get();
-               }
-               else if (!clval.is_function()) {
-                       log_debug("UNTESTED: String instantiation requested but 
"
-                    "_global.String is not a function (%s). Returning "
-                    "the NULL object.", clval);
-                       return ctor.get();
-               }
-               else {
-                       ctor = clval.to_as_function();
-               }
-       }
-
-    if (!ctor.get()) return ctor.get();
-
-       std::auto_ptr< std::vector<as_value> > args ( new std::vector<as_value> 
);
-       args->push_back(val);
-       boost::intrusive_ptr<as_object> ret = ctor->constructInstance(env, 
args);
-
-       return ret.get();
-}
-
-void registerStringNative(as_object& global)
+void
+registerStringNative(as_object& global)
 {
     VM& vm = getVM(global);
        vm.registerNative(as_object::tostring_method, 251, 1);

=== modified file 'libcore/asobj/String_as.h'
--- a/libcore/asobj/String_as.h 2009-07-16 08:30:06 +0000
+++ b/libcore/asobj/String_as.h 2009-08-11 08:35:50 +0000
@@ -31,15 +31,6 @@
 // Initialize the global String class
 void string_class_init(as_object& global, const ObjectURI& uri);
 
-/// Return a String instance (possibibly NULL!)
-//
-/// This function will use the native String constructor in SWF5, but
-/// any function registered by user as the _global.String for SWF6 and higher.
-/// In the second case, not finding a proper constructor might result in
-/// returning the NULL object.
-///
-as_object* init_string_instance(Global_as& g, const std::string& val);
-
 void registerStringNative(as_object& global);
 
 }

=== modified file 'libcore/asobj/flash/ui/Mouse_as.cpp'
--- a/libcore/asobj/flash/ui/Mouse_as.cpp       2009-07-28 11:58:27 +0000
+++ b/libcore/asobj/flash/ui/Mouse_as.cpp       2009-08-11 10:29:44 +0000
@@ -94,10 +94,7 @@
 as_value
 mouse_hide(const fn_call& fn)
 {
-    boost::intrusive_ptr<as_object> obj = ensureType<as_object>(fn.this_ptr);
-
     movie_root& m = getRoot(fn);
-
     const int success = (m.callInterface("Mouse.hide") == "true") ? 1 : 0;
 
     // returns 1 if mouse was visible before call.
@@ -110,10 +107,7 @@
 as_value
 mouse_show(const fn_call& fn)
 {
-    boost::intrusive_ptr<as_object> obj=ensureType<as_object>(fn.this_ptr);
-
     movie_root& m = getRoot(fn);
-
     const int success = (m.callInterface("Mouse.show") == "true") ? 1 : 0;
 
     // returns 1 if Mouse was visible before call.

=== modified file 'libcore/vm/ASHandlers.cpp'
--- a/libcore/vm/ASHandlers.cpp 2009-07-30 13:11:28 +0000
+++ b/libcore/vm/ASHandlers.cpp 2009-08-11 10:29:24 +0000
@@ -76,24 +76,15 @@
 
 namespace gnash {
 
+namespace {
+
+    as_object* construct_object(as_function* ctor_as_func, as_environment& env,
+            unsigned int nargs);
+    as_object* convertToObject(Global_as& gl, const as_value& val);
+}
+
 namespace SWF { // gnash::SWF
 
-//
-// Utility: construct an object using given constructor.
-// This is used by both ActionNew and ActionNewMethod and
-// hides differences between builtin and actionscript-defined
-// constructors.
-//
-static boost::intrusive_ptr<as_object>
-construct_object(as_function* ctor_as_func,
-    as_environment& env, unsigned int nargs)
-{
-    assert(ctor_as_func);
-    std::auto_ptr< std::vector<as_value> > args (new std::vector<as_value> );
-    args->reserve(nargs);
-    for (unsigned int i=0; i<nargs; ++i) args->push_back(env.pop());
-    return ctor_as_func->constructInstance(env, args);
-}
 
 
 static void unsupported_action_handler(ActionExec& thread)
@@ -1411,7 +1402,7 @@
 
     // Get the "instance"
     boost::intrusive_ptr<as_object> instance = 
-        env.top(0).to_object(*getGlobal(thread.env));
+        convertToObject(*getGlobal(thread.env), env.top(0));
 
     // Get the "super" function
     as_function* super = env.top(1).to_as_function();
@@ -1454,10 +1445,8 @@
 //    TODO: This doesn't work quite right, yet.
     as_environment& env = thread.env;
 
-    
-
     as_value objval = env.pop();
-    as_object *obj = objval.to_object(*getGlobal(thread.env)).get();
+    as_object *obj = convertToObject(*getGlobal(thread.env), objval);
     int count = static_cast<int>(env.pop().to_number());
     as_value a(1);
 
@@ -1478,7 +1467,7 @@
         );
         return;
     }
-    obj = protoval.to_object(*getGlobal(thread.env)).get();
+    obj = convertToObject(*getGlobal(thread.env), protoval);
     if (!obj)
     {
         IF_VERBOSE_ASCODING_ERRORS(
@@ -1500,7 +1489,7 @@
     {
         as_value ctorval = env.pop();
 
-        as_object* ctor = ctorval.to_object(*getGlobal(thread.env)).get();
+        as_object* ctor = convertToObject(*getGlobal(thread.env), ctorval);
         if ( ! ctor )
         {
             IF_VERBOSE_ASCODING_ERRORS(
@@ -1515,7 +1504,7 @@
             );
             continue;
         }
-        as_object *inter = protoval.to_object(*getGlobal(thread.env)).get();
+        as_object *inter = convertToObject(*getGlobal(thread.env), protoval);
         if ( ! inter )
         {
             IF_VERBOSE_ASCODING_ERRORS(
@@ -2638,11 +2627,11 @@
         }
         else {
             as_value target = thread.getVariable(path);
-            obj = target.to_object(*getGlobal(thread.env));
+            obj = convertToObject(*getGlobal(thread.env), target);
             propertyname = var;
         }
     }
-    else obj = env.top(1).to_object(*getGlobal(thread.env));
+    else obj = convertToObject(*getGlobal(thread.env), env.top(1));
 
     if (!obj)
     {
@@ -2684,7 +2673,7 @@
     
     // Otherwise see if it's an object and delete it.
     as_value target = thread.getVariable(path);
-    boost::intrusive_ptr<as_object> obj = 
target.to_object(*getGlobal(thread.env));
+    boost::intrusive_ptr<as_object> obj = 
convertToObject(*getGlobal(thread.env), target);
 
     if (!obj)
     {
@@ -2744,7 +2733,7 @@
         log_error(_("ActionCallFunction: function name %s evaluated to "
                 "non-function value %s"), funcname, function);
         // Calling super ? 
-        boost::intrusive_ptr<as_object> obj = 
function.to_object(*getGlobal(thread.env));
+        boost::intrusive_ptr<as_object> obj = 
convertToObject(*getGlobal(thread.env), function);
         this_ptr = thread.getThisPointer();
         if (!obj->get_member(NSV::PROP_CONSTRUCTOR, &function) )
         {
@@ -2862,22 +2851,22 @@
         return;
     }
 
-    boost::intrusive_ptr<as_object> newobj = 
construct_object(constructor.get(),
-            env, nargs);
-
+    // It is possible for constructors to fail, for instance if a
+    // conversion to object calls a built-in constructor that has been
+    // deleted. BitmapData also fails to construct anything under
+    // some circumstances.
+    try {
+        as_object* newobj = construct_object(constructor.get(), env, nargs);
 #ifdef USE_DEBUGGER
-#ifndef GNASH_USE_GC
-    // WARNING: new_obj.to_object(*getGlobal(thread.env)) can return a newly 
allocated
-    //          thing into the intrusive_ptr, so the debugger
-    //          will be left with a deleted object !!
-    //          Rob: we don't want to use void pointers here..
-    newobj->add_ref(); // this will leak, but at least debugger won't end up
-                         // with a dangling reference...
-#endif //ndef GNASH_USE_GC
-        debugger.addSymbol(newobj.get(), classname);
+        debugger.addSymbol(newobj, classname);
 #endif
-
-    env.push(as_value(newobj));
+        env.push(newobj);
+        return;
+    }
+    catch (GnashException& ) {
+        env.push(as_value());
+        return;
+    }
 
 }
 
@@ -2913,7 +2902,7 @@
     // Call the array constructor, to create an empty array.
     as_value result = array_new(fn_call(NULL, env));
 
-    boost::intrusive_ptr<as_object> ao = 
result.to_object(*getGlobal(thread.env));
+    boost::intrusive_ptr<as_object> ao = 
convertToObject(*getGlobal(thread.env), result);
     assert(ao);
 
     // Fill the elements with the initial values from the stack.
@@ -3020,7 +3009,7 @@
 
     env.top(0).set_undefined();
 
-    const boost::intrusive_ptr<as_object> obj = 
variable.to_object(*getGlobal(thread.env));
+    const boost::intrusive_ptr<as_object> obj = 
convertToObject(*getGlobal(thread.env), variable);
     if ( !obj || !variable.is_object() )
     {
         IF_VERBOSE_ASCODING_ERRORS(
@@ -3235,7 +3224,7 @@
     as_value member_name = env.top(0);
     as_value target = env.top(1);
 
-    boost::intrusive_ptr<as_object> obj = 
target.to_object(*getGlobal(thread.env));
+    boost::intrusive_ptr<as_object> obj = 
convertToObject(*getGlobal(thread.env), target);
     if (!obj)
     {
         IF_VERBOSE_ASCODING_ERRORS(
@@ -3280,7 +3269,7 @@
     
     as_environment& env = thread.env;
 
-    boost::intrusive_ptr<as_object> obj = 
env.top(2).to_object(*getGlobal(thread.env));
+    boost::intrusive_ptr<as_object> obj = 
convertToObject(*getGlobal(thread.env), env.top(2));
     const std::string& member_name = env.top(1).to_string();
     const as_value& member_value = env.top(0);
 
@@ -3371,7 +3360,7 @@
     bool hasMethodName = ((!method_name.is_undefined()) &&
             (!method_string.empty()) );
 
-    boost::intrusive_ptr<as_object> obj = 
obj_value.to_object(*getGlobal(thread.env));
+    boost::intrusive_ptr<as_object> obj = 
convertToObject(*getGlobal(thread.env), obj_value);
     if (!obj) {
         // SWF integrity check
         IF_VERBOSE_ASCODING_ERRORS(
@@ -3501,7 +3490,7 @@
         nargs = available_args;
     }
 
-    boost::intrusive_ptr<as_object> obj = 
obj_val.to_object(*getGlobal(thread.env));
+    boost::intrusive_ptr<as_object> obj = 
convertToObject(*getGlobal(thread.env), obj_val);
     if (!obj) {
         // SWF integrity check
         // FIXME, should this be log_swferror?  Or log_aserror?
@@ -3543,10 +3532,19 @@
     }
 
     // Construct the object
-    boost::intrusive_ptr<as_object> new_obj = construct_object(method.get(),
-            env, nargs);
-
-    env.push(as_value(new_obj));
+    // It is possible for constructors to fail, for instance if a
+    // conversion to object calls a built-in constructor that has been
+    // deleted. BitmapData also fails to construct anything under
+    // some circumstances.
+    try {
+        as_object* newobj = construct_object(method.get(), env, nargs);
+        env.push(newobj);
+        return;
+    }
+    catch (GnashException& ) {
+        env.push(as_value());
+        return;
+    }
 
 }
 
@@ -3557,10 +3555,11 @@
     as_environment& env = thread.env;
 
     // Get the "super" function
-    as_object* super = env.top(0).to_object(*getGlobal(thread.env)).get();
+    as_object* super = convertToObject(*getGlobal(thread.env), env.top(0));
 
     // Get the "instance" (but avoid implicit conversion of primitive values!)
-    as_object* instance = env.top(1).is_object() ? 
env.top(1).to_object(*getGlobal(thread.env)).get() : NULL;
+    as_object* instance = env.top(1).is_object() ?
+        convertToObject(*getGlobal(thread.env), env.top(1)) : NULL;
 
     // Invalid args!
     if (!super || ! instance) {
@@ -3593,7 +3592,7 @@
     // as we copied that as_value.
     env.top(0).set_undefined();
 
-    const boost::intrusive_ptr<as_object> obj = 
obj_val.to_object(*getGlobal(thread.env));
+    const boost::intrusive_ptr<as_object> obj = 
convertToObject(*getGlobal(thread.env), obj_val);
     if ( !obj || !obj_val.is_object() )
     {
         IF_VERBOSE_ASCODING_ERRORS(
@@ -3866,11 +3865,11 @@
         env.push(function_value);
     }
 #ifdef USE_DEBUGGER
-    // WARNING: function_value.to_object(*getGlobal(thread.env)) can return a 
newly allocated
+    // WARNING: convertToObject(*getGlobal(thread.env), function_value) can 
return a newly allocated
     //          thing into the intrusive_ptr, so the debugger
     //          will be left with a deleted object !!
     //          Rob: we don't want to use void pointers here..
-    boost::intrusive_ptr<as_object> o = 
function_value.to_object(*getGlobal(thread.env));
+    boost::intrusive_ptr<as_object> o = 
convertToObject(*getGlobal(thread.env), function_value);
 #ifndef GNASH_USE_GC
     o->add_ref(); // this will leak, but at least debugger won't end up
                   // with a dangling reference...
@@ -3949,9 +3948,9 @@
     assert(thread.atActionTag(SWF::ACTION_WITH));
 #endif
 
-    
-    as_value with_obj_val = env.pop().to_object(*getGlobal(thread.env));
-    boost::intrusive_ptr<as_object> with_obj = 
with_obj_val.to_object(*getGlobal(thread.env));
+    as_value with_obj_val = convertToObject(*getGlobal(thread.env), env.pop());
+    boost::intrusive_ptr<as_object> with_obj =
+        convertToObject(*getGlobal(thread.env), with_obj_val);
 
     ++pc; // skip tag code
 
@@ -4067,11 +4066,11 @@
         //env.set_member(name, function_value);
         thread.setVariable(name, function_value);
 #ifdef USE_DEBUGGER
-        // WARNING: new_obj.to_object(*getGlobal(thread.env)) can return a 
newly allocated
+        // WARNING: convertToObject(*getGlobal(thread.env), new_obj) can 
return a newly allocated
         //          thing into the intrusive_ptr, so the debugger
         //          will be left with a deleted object !!
         //          Rob: we don't want to use void pointers here..
-        boost::intrusive_ptr<as_object> o = 
function_value.to_object(*getGlobal(thread.env));
+        boost::intrusive_ptr<as_object> o = 
convertToObject(*getGlobal(thread.env), function_value);
 #ifndef GNASH_USE_GC
         o->add_ref(); // this will leak, but at least debugger won't end up
                   // with a dandling reference...
@@ -4146,4 +4145,38 @@
 
 } // namespace gnash::SWF
 
+/// Helper functions.
+namespace {
+
+as_object*
+convertToObject(Global_as& gl, const as_value& val)
+{
+
+    try {
+        return val.to_object(gl).get();
+    }
+    catch (const GnashException& gl) {
+        return 0;
+    }
+
+}
+
+// Utility: construct an object using given constructor.
+// This is used by both ActionNew and ActionNewMethod and
+// hides differences between builtin and actionscript-defined
+// constructors.
+as_object*
+construct_object(as_function* ctor_as_func, as_environment& env,
+        unsigned int nargs)
+{
+    assert(ctor_as_func);
+    std::auto_ptr<std::vector<as_value> > args(new std::vector<as_value>);
+    args->reserve(nargs);
+    for (size_t i=0; i<nargs; ++i) args->push_back(env.pop());
+    return ctor_as_func->constructInstance(env, args).get();
+}
+
+}
+
+
 } // namespace gnash

=== modified file 'testsuite/actionscript.all/Object.as'
--- a/testsuite/actionscript.all/Object.as      2009-02-25 22:33:03 +0000
+++ b/testsuite/actionscript.all/Object.as      2009-08-11 11:45:26 +0000
@@ -220,6 +220,23 @@
 check_equals( obj3.test, 4 );
 check (copy.__proto__.constructor == Object);
 
+o = new Object("hello");
+check_equals(o.toString(), "hello");
+check_equals(o.valueOf(), "hello");
+
+o = new Object(5);
+check_equals(o.toString(), "5");
+check_equals(o.valueOf(), 5);
+
+o = new Object(undefined);
+check_equals(o.toString(), "[object Object]");
+check_equals(typeof(o.valueOf()), "object");
+check_equals(o.valueOf(), o);
+
+o = new Object(null);
+check_equals(o.toString(), "[object Object]");
+check_equals(typeof(o.valueOf()), "object");
+check_equals(o.valueOf(), o);
 
 //---------------------------------------------
 // Test addProperty / hasOwnProperty (SWF6 up)
@@ -901,11 +918,42 @@
 check_equals(resolveCalled, 3);
 check_equals(result, "quibbleDibblePropertyWithASillyName");
 
+////////////////////////////////
+
+// Messing about here with global classes may ruin later tests, so don't add
+// them after this.
+
+s = "hi";
+n = 7;
+b = true;
+
+delete String;
+
+o = new Object(s);
+check_equals(typeof(o), "undefined");
+o = new Object(n);
+check_equals(typeof(o), "object");
+check_equals(o.toString(), "7");
+o = new Object(b);
+check_equals(typeof(o), "object");
+check_equals(o.toString(), "true");
+
+delete Number;
+o = new Object(n);
+check_equals(typeof(o), "undefined");
+o = new Object(b);
+check_equals(typeof(o), "object");
+check_equals(o.toString(), "true");
+
+delete Boolean;
+o = new Object(b);
+check_equals(typeof(o), "undefined");
+
 #if OUTPUT_VERSION <= 5
-totals(97);
+totals(116);
 #endif
 
 #if OUTPUT_VERSION >= 6
-totals(285);
+totals(304);
 #endif
 

=== modified file 'testsuite/swfdec/PASSING'
--- a/testsuite/swfdec/PASSING  2009-08-06 11:05:32 +0000
+++ b/testsuite/swfdec/PASSING  2009-08-11 11:45:26 +0000
@@ -309,6 +309,10 @@
 crash-0.9.1-getvariable-shapes-6.swf:45e434a401447915500c275c238b8ac0
 crash-0.9.1-getvariable-shapes-7.swf:49f7609f50e4099528b3477b7124834c
 crash-0.9.1-getvariable-shapes-8.swf:9827e209d6bf155d49fcdb4e15cf0442
+crash-0.9.2-beginBitmapFill-5.swf:74a978aa8c54e52be6491d897b0fa501
+crash-0.9.2-beginBitmapFill-6.swf:58c7f18522fb4fef1a128ca9ca3e7397
+crash-0.9.2-beginBitmapFill-7.swf:9feed2ef6a0b3aa28a66e9ff32b39889
+crash-0.9.2-beginBitmapFill-8.swf:c5bc166548d2832ac84f68767930014b
 createTextField-returnvalue-6.swf:876f64cb4349313be58d1b9de5ca2ff4
 createTextField-returnvalue-7.swf:397473c78af05cbb9e7e394ec4ce1a07
 createTextField-returnvalue-8.swf:398e15cdabb4c9f9bdb56ee5b07e5126


reply via email to

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