1 // as_function.cpp:  ActionScript Functions, for Gnash.
2 //
3 //   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
4 //   Free Software Foundation, Inc
5 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19 //
20 
21 #include "as_function.h"
22 
23 #include <string>
24 
25 #include "log.h"
26 #include "as_value.h"
27 #include "fn_call.h"
28 #include "GnashException.h"
29 #include "Global_as.h"
30 #include "namedStrings.h"
31 
32 namespace gnash {
33 
as_function(Global_as & gl)34 as_function::as_function(Global_as& gl)
35 	:
36 	as_object(gl)
37 {
38 }
39 
40 std::string
stringValue() const41 as_function::stringValue() const
42 {
43     return "[type Function]";
44 }
45 
46 as_object*
constructInstance(as_function & ctor,const as_environment & env,fn_call::Args & args)47 constructInstance(as_function& ctor, const as_environment& env,
48         fn_call::Args& args)
49 {
50     Global_as& gl = getGlobal(ctor);
51 
52     // Create an empty object, with a ref to the constructor's prototype.
53     // The function's prototype property always becomes the new object's
54     // __proto__ member, regardless of whether it is an object and regardless
55     // of its visibility.
56     as_object* newobj = new as_object(gl);
57     Property* proto = ctor.getOwnProperty(NSV::PROP_PROTOTYPE);
58     if (proto) newobj->set_prototype(proto->getValue(ctor));
59 
60     return ctor.construct(*newobj, env, args);
61 }
62 
63 as_object*
construct(as_object & newobj,const as_environment & env,fn_call::Args & args)64 as_function::construct(as_object& newobj, const as_environment& env,
65         fn_call::Args& args)
66 {
67 	const int swfversion = getSWFVersion(env);
68 
69     // Add a __constructor__ member to the new object visible from version 6.
70     const int flags = PropFlags::dontEnum |
71                       PropFlags::onlySWF6Up;
72 
73     newobj.init_member(NSV::PROP_uuCONSTRUCTORuu, this, flags);
74 
75     if (swfversion < 7) {
76         newobj.init_member(NSV::PROP_CONSTRUCTOR, this, PropFlags::dontEnum);
77     }
78 
79     // Don't set a super so that it will be constructed only if required
80     // by the function.
81     fn_call fn(&newobj, env, args, nullptr, true);
82     as_value ret;
83 
84     try {
85         ret = call(fn);
86     }
87     catch (const GnashException& ex) {
88         // Catching a std::exception here can mask all sorts of bad
89         // behaviour, as (for instance) a poorly constructed string may
90         // smash the stack, throw an exception, but not abort.
91         // This is very effective at confusing debugging tools.
92         // We only throw GnashExceptions. A std::bad_alloc may also be
93         // reasonable, but anything else shouldn't be caught here.
94         log_error(_("Native function called as constructor threw exception: %s")
95                   , ex.what());
96 
97         // If a constructor throws an exception, throw it back to the
98         // caller. This is the only way to signal that a constructor
99         // did not return anything.
100         throw;
101     }
102 
103     // Some built-in constructors do things properly and operate on the
104     // 'this' pointer. Others return a new object. This is to handle those
105     // cases.
106     if (isBuiltin() && ret.is_object()) {
107         as_object* fakeobj = toObject(ret, getVM(env));
108 
109         fakeobj->init_member(NSV::PROP_uuCONSTRUCTORuu, as_value(this),
110                 flags);
111 
112         // Also for SWF5+ only?
113         if (swfversion < 7) {
114             fakeobj->init_member(NSV::PROP_CONSTRUCTOR, as_value(this),
115                     PropFlags::dontEnum);
116         }
117         return fakeobj;
118     }
119 
120 	return &newobj;
121 }
122 
123 } // namespace gnash
124