big merge from master, fix rpm creation, drop fetching swfdec
[gnash.git] / libcore / Function2.cpp
blob7f856e7d854c049d021217115cee4aa1382fb684
1 //
2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010,
3 // 2011 Free Software Foundation, Inc
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 #include "Function2.h"
21 #include "log.h"
22 #include "fn_call.h"
23 #include "action_buffer.h"
24 #include "ActionExec.h"
25 #include "VM.h"
26 #include "NativeFunction.h"
27 #include "Global_as.h"
28 #include "namedStrings.h"
29 #include "CallStack.h"
30 #include "MovieClip.h"
31 #include "DisplayObject.h"
33 namespace gnash {
35 Function2::Function2(const action_buffer& ab, as_environment& env,
36 size_t start, const ScopeStack& scopeStack)
38 Function(ab, env, start, scopeStack),
39 _registerCount(0),
40 _function2Flags(0)
44 // Dispatch.
45 as_value
46 Function2::call(const fn_call& fn)
48 // Extract caller before pushing ourself on the call stack
49 VM& vm = getVM(fn);
51 as_object* caller = vm.calling() ? &vm.currentCall().function() : 0;
53 // Set up local stack frame, for parameters and locals.
54 FrameGuard guard(getVM(fn), *this);
55 CallFrame& cf = guard.callFrame();
57 DisplayObject* target = _env.target();
58 DisplayObject* orig_target = _env.get_original_target();
60 // Some features are version-dependant.
61 const int swfversion = getSWFVersion(fn);
63 if (swfversion < 6) {
64 // In SWF5, when 'this' is a DisplayObject it becomes
65 // the target for this function call.
66 // See actionscript.all/setProperty.as
67 //
68 if (fn.this_ptr) {
69 DisplayObject* ch = get<DisplayObject>(fn.this_ptr);
70 if (ch) {
71 target = ch;
72 orig_target = ch;
77 /// This is only needed for SWF5 (temp switch of target)
78 /// We do always and base 'target' value on SWF version.
79 /// TODO: simplify code by maybe using a custom as_environment
80 /// instead, so to get an "original" target being
81 /// the one set now (rather then the really original one)
82 /// TODO: test scope when calling functions defined in another timeline
83 /// (target, in particular).
84 TargetGuard targetGuard(_env, target, orig_target);
86 // function2: most args go in registers; any others get pushed.
88 // Handle the implicit args.
89 // @@ why start at 1 ? Note that starting at 0 makes
90 // intro.swf movie fail to play correctly.
91 size_t current_reg(1);
93 // This is us. TODO: why do we have to query the VM to get
94 // what are effectively our own resources?
96 // If this is not suppressed it is either placed in a register
97 // or set as a local variable, but not both.
98 if (!(_function2Flags & SUPPRESS_THIS)) {
99 if (_function2Flags & PRELOAD_THIS) {
100 // preload 'this' into a register.
101 // TODO: check whether it should be undefined or null
102 // if this_ptr is null.
103 cf.setLocalRegister(current_reg, fn.this_ptr);
104 ++current_reg;
106 else {
107 // Put 'this' in a local var.
108 setLocal(cf, NSV::PROP_THIS,
109 fn.this_ptr ? fn.this_ptr : as_value());
113 // This works slightly differently from 'super' and 'this'. The
114 // arguments are only ever either placed in the register or a
115 // local variable, but if both preload and suppress arguments flags
116 // are set, an empty array is still placed to the register.
117 // This seems like a bug in the reference player.
118 if (!(_function2Flags & SUPPRESS_ARGUMENTS) ||
119 (_function2Flags & PRELOAD_ARGUMENTS)) {
121 as_object* args = getGlobal(fn).createArray();
123 if (!(_function2Flags & SUPPRESS_ARGUMENTS)) {
124 getArguments(*this, *args, fn, caller);
127 if (_function2Flags & PRELOAD_ARGUMENTS) {
128 // preload 'arguments' into a register.
129 cf.setLocalRegister(current_reg, args);
130 ++current_reg;
132 else {
133 // Put 'arguments' in a local var.
134 setLocal(cf, NSV::PROP_ARGUMENTS, args);
139 // If super is not suppressed it is either placed in a register
140 // or set as a local variable, but not both.
141 if (swfversion > 5 && !(_function2Flags & SUPPRESS_SUPER)) {
143 // Put 'super' in a register (SWF6+ only).
144 // TOCHECK: should we still set it if not available ?
145 as_object* super = fn.super ? fn.super :
146 fn.this_ptr ? fn.this_ptr->get_super() : 0;
148 if (super && (_function2Flags & PRELOAD_SUPER)) {
149 cf.setLocalRegister(current_reg, super);
150 current_reg++;
152 else if (super) {
153 setLocal(cf, NSV::PROP_SUPER, super);
157 if (_function2Flags & PRELOAD_ROOT) {
158 // Put '_root' (if any) in a register.
159 DisplayObject* tgtch = _env.target();
160 if (tgtch) {
161 // NOTE: _lockroot will be handled by getAsRoot()
162 as_object* r = getObject(tgtch->getAsRoot());
163 cf.setLocalRegister(current_reg, r);
164 ++current_reg;
168 if (_function2Flags & PRELOAD_PARENT) {
169 DisplayObject* tgtch = _env.target();
170 if (tgtch) {
171 as_object* p = getObject(tgtch->parent());
172 cf.setLocalRegister(current_reg, p);
173 ++current_reg;
177 if (_function2Flags & PRELOAD_GLOBAL) {
178 // Put '_global' in a register.
179 as_object* global = vm.getGlobal();
180 cf.setLocalRegister(current_reg, global);
181 ++current_reg;
184 // Handle the explicit args.
185 // This must be done after implicit ones,
186 // as the explicit override the implicits:
187 // see swfdec/definefunction2-override
188 for (size_t i = 0, n = _args.size(); i < n; ++i) {
189 // not a register, declare as local
190 if (!_args[i].reg) {
191 if (i < fn.nargs) {
192 // Conventional arg passing: create a local var.
193 setLocal(cf, _args[i].name, fn.arg(i));
195 else {
196 // Still declare named arguments, even if
197 // they are not passed from caller
198 // See bug #22203
199 declareLocal(cf, _args[i].name);
202 else {
203 if (i < fn.nargs) {
204 // Pass argument into a register.
205 const int reg = _args[i].reg;
206 cf.setLocalRegister(reg, fn.arg(i));
208 // If no argument was passed, no need to setup a register
209 // I guess.
213 // Execute the actions.
214 as_value result;
215 ActionExec(*this, _env, &result, fn.this_ptr)();
216 return result;
219 } // end of gnash namespace