1 // as_function.cpp: ActionScript Functions, for Gnash.
3 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Free Software
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.
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.
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
21 #include "smart_ptr.h" // GNASH_USE_GC
23 #include "as_function.h"
26 #include "Global_as.h"
28 #include "GnashException.h"
30 #include "namedStrings.h"
31 #include "NativeFunction.h"
33 #include "DisplayObject.h"
39 // Forward declarations
41 as_value
function_apply(const fn_call
& fn
);
42 as_value
function_call(const fn_call
& fn
);
43 as_value
function_ctor(const fn_call
& fn
);
46 as_function::as_function(Global_as
& gl
)
53 as_function::stringValue() const
55 return "[type Function]";
59 constructInstance(as_function
& ctor
, const as_environment
& env
,
62 Global_as
& gl
= getGlobal(ctor
);
64 // Create an empty object, with a ref to the constructor's prototype.
65 // The function's prototype property always becomes the new object's
66 // __proto__ member, regardless of whether it is an object and regardless
68 as_object
* newobj
= new as_object(gl
);
69 Property
* proto
= ctor
.getOwnProperty(NSV::PROP_PROTOTYPE
);
70 if (proto
) newobj
->set_prototype(proto
->getValue(ctor
));
72 return ctor
.construct(*newobj
, env
, args
);
76 as_function::construct(as_object
& newobj
, const as_environment
& env
,
79 const int swfversion
= getSWFVersion(env
);
81 // Add a __constructor__ member to the new object visible from version 6.
82 const int flags
= PropFlags::dontEnum
|
83 PropFlags::onlySWF6Up
;
85 newobj
.init_member(NSV::PROP_uuCONSTRUCTORuu
, this, flags
);
88 newobj
.init_member(NSV::PROP_CONSTRUCTOR
, this, PropFlags::dontEnum
);
91 // Don't set a super so that it will be constructed only if required
93 fn_call
fn(&newobj
, env
, args
, 0, true);
99 catch (GnashException
& ex
) {
100 // Catching a std::exception here can mask all sorts of bad
101 // behaviour, as (for instance) a poorly constructed string may
102 // smash the stack, throw an exception, but not abort.
103 // This is very effective at confusing debugging tools.
104 // We only throw GnashExceptions. A std::bad_alloc may also be
105 // reasonable, but anything else shouldn't be caught here.
106 log_debug("Native function called as constructor threw exception: "
109 // If a constructor throws an exception, throw it back to the
110 // caller. This is the only way to signal that a constructor
111 // did not return anything.
115 // Some built-in constructors do things properly and operate on the
116 // 'this' pointer. Others return a new object. This is to handle those
118 if (isBuiltin() && ret
.is_object()) {
119 as_object
* fakeobj
= toObject(ret
, getVM(env
));
121 fakeobj
->init_member(NSV::PROP_uuCONSTRUCTORuu
, as_value(this),
124 // Also for SWF5+ only?
125 if (swfversion
< 7) {
126 fakeobj
->init_member(NSV::PROP_CONSTRUCTOR
, as_value(this),
127 PropFlags::dontEnum
);
137 registerFunctionNative(as_object
& global
)
139 VM
& vm
= getVM(global
);
140 vm
.registerNative(function_call
, 101, 10);
141 vm
.registerNative(function_apply
, 101, 11);
145 function_class_init(as_object
& where
, const ObjectURI
& uri
)
147 Global_as
& gl
= getGlobal(where
);
149 NativeFunction
* func
= new NativeFunction(gl
, function_ctor
);
150 as_object
* proto
= createObject(gl
);
152 func
->init_member(NSV::PROP_PROTOTYPE
, proto
);
153 func
->init_member(NSV::PROP_CONSTRUCTOR
, func
);
154 proto
->init_member(NSV::PROP_CONSTRUCTOR
, func
);
156 // Register _global.Function, only visible for SWF6 up
157 const int swf6flags
= as_object::DefaultFlags
| PropFlags::onlySWF6Up
;
158 func
->init_member(NSV::PROP_uuPROTOuu
, proto
, swf6flags
);
159 where
.init_member(uri
, func
, swf6flags
);
161 VM
& vm
= getVM(where
);
163 // Note: these are the first functions created, and they need the
164 // Function class to be registered.
165 proto
->init_member("call", vm
.getNative(101, 10), swf6flags
);
166 proto
->init_member("apply", vm
.getNative(101, 11), swf6flags
);
172 function_ctor(const fn_call
& /*fn*/)
178 class PushFunctionArgs
181 PushFunctionArgs(fn_call
& fn
) : _fn(fn
) {}
182 void operator()(const as_value
& val
) {
190 function_apply(const fn_call
& fn
)
193 as_object
* function_obj
= ensure
<ValidThis
>(fn
);
195 // Copy new function call from old one, we'll modify
196 // the copy only if needed
197 fn_call
new_fn_call(fn
);
198 new_fn_call
.resetArgs();
202 IF_VERBOSE_ASCODING_ERRORS(
203 log_aserror (_("Function.apply() called with no args"));
205 new_fn_call
.this_ptr
= new as_object(getGlobal(fn
));
209 // Get the object to use as 'this' reference
210 as_object
* obj
= toObject(fn
.arg(0), getVM(fn
));
212 if (!obj
) obj
= new as_object(getGlobal(fn
));
214 new_fn_call
.this_ptr
= obj
;
216 // Note: do not override fn_call::super by creating a super
217 // object, as it may not be needed. Doing so can have a very
218 // detrimental effect on memory usage!
219 // Normal supers will be created when needed in the function
221 new_fn_call
.super
= 0;
223 // Check for second argument ('arguments' array)
226 IF_VERBOSE_ASCODING_ERRORS(
228 log_aserror(_("Function.apply() got %d"
229 " args, expected at most 2"
230 " -- discarding the ones in"
236 boost::intrusive_ptr
<as_object
> arg1
=
237 toObject(fn
.arg(1), getVM(fn
));
240 PushFunctionArgs
pa(new_fn_call
);
241 foreachArray(*arg1
, pa
);
247 as_value rv
= function_obj
->call(new_fn_call
);
253 function_call(const fn_call
& fn
)
256 as_object
* function_obj
= ensure
<ValidThis
>(fn
);
258 // Copy new function call from old one, we'll modify
259 // the copy only if needed
260 fn_call
new_fn_call(fn
);
264 if (!fn
.nargs
|| fn
.arg(0).is_undefined() || fn
.arg(0).is_null()) {
265 tp
= new as_object(getGlobal(fn
));
267 else tp
= toObject(fn
.arg(0), getVM(fn
));
269 new_fn_call
.this_ptr
= tp
;
270 new_fn_call
.super
= 0;
271 if (fn
.nargs
) new_fn_call
.drop_bottom();
274 return function_obj
->call(new_fn_call
);
278 } // anonymous namespace