1 // Machine.h A VM to run AS3 code, and AS2 code in the future.
3 // Copyright (C) 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
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.
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.
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 #ifndef GNASH_MACHINE_H
20 #define GNASH_MACHINE_H
25 #include "SafeStack.h"
44 template <typename T
> class FunctionArgs
;
53 /// The virtual machine for executing ABC (ActionScript Bytecode).
55 /// This machine is intended to work without relying on the C++ call stack,
56 /// by resetting its Stream and Stack members (actually, by limiting the stack)
57 /// to make function calls, rather than calling them directly in C++.
58 /// As a result, many of the internal calls are void functions even though they
59 /// will be returning some value.
60 /// The exception to this is that C++ native functions defined in ActionScript
61 /// objects will be called in the typical way.
63 /// The C++ exceptions mechanism is used for exception handling, since this
64 /// allows both ActionScript code and C++ code to use the exception handling
65 /// with a minimum of hassle, and it helps with correctness.
67 /// It was intended that this Machine should run both AS2 and AS3 code.
68 /// However, as the two codestreams must be strictly separated - different
69 /// global objects, no sharing of resources, and no ability to communicate
70 /// directly, there is no sense in using a single instance of this machine
71 /// for both AS2 and AS3 interpretation. It's questionable whether there is
72 /// any advantage in using this Machine for AS2; it is not a near-term goal.
77 /// Create an AS3 interpreter.
80 /// Initialize the AS resources
82 /// This extra step is necessary because the Machine is initialized
83 /// and owned by the AVM1 machine(VM). All access to Machine currently
84 /// occurs through VM, but since the VM's Machine pointer is null until
85 /// the Machine ctor has completed, we cannot construct AS resources
86 /// until after the ctor is complete, because AS resource creation
87 /// accesses the Machine through the VM's pointer...
89 /// TODO: fix the mess.
93 // Flash specific members.
94 /// The DisplayObject which initiated these actions.
95 DisplayObject
*getTarget();
97 /// Set the DisplayObject which initiated the actions.
99 void setTarget(DisplayObject
* target
);
101 /// This will complete a name in AS3, where a part of the name
102 /// is stored in the stream and another part may be stored on
106 /// A partially filled MultiName, this should be the id
110 /// The depth in the stack where the stack objects may be found.
113 /// The number of stack elements used by the name.
114 /// At present, always 0, 1, or 2. These are not dropped.
115 int completeName(MultiName
& name
, int initial
= 0);
117 /// Given a value v, find the class object of the superclass of v.
120 /// The object whose superclass is desired.
122 /// @param find_primitive
123 /// If true, the ActionScript prototype will be found for primitive values.
126 /// Null if the superclass was not found, or the superclass.
127 Class
* findSuper(as_value
& obj
, bool find_primitive
);
129 /// Get a member from an object.
131 /// @param pDefinition
132 /// The definition of the class which is to be used. This should be the
133 /// one which has the property.
136 /// The bound name of the member
139 /// The source object -- the specific instance of the pDefinition class.
142 /// This returns the value, but on the stack.
143 /// (Since the return value is not known until after control has left
144 /// the caller of this, it's impossible to return a meaningful value.
145 void getMember(Class
* pDefinition
, MultiName
& name
, as_value
& source
);
147 /// Set a member in an object.
149 /// @param pDefinition
150 /// The definition of the class which is to be used.
153 /// The bound name of the member
156 /// The source object -- where the instance should be set
163 void setMember(Class
*, MultiName
&, as_value
& target
, as_value
& val
);
165 Property
* findProperty(MultiName
&) { return NULL
; }
169 /// push a get call to be executed next.
171 /// Any Property can be pushed, and it will put an appropriate value
172 /// into return_slot. This ensures that getter properties
173 /// can be accessed in the same way as other properties, and hides
174 /// the difference between ActionScript methods and native C++ methods.
177 /// The 'this' to use for a getter/setter if it exists.
179 /// @param return_slot
180 /// A space for the return value. An assignment will always be made here,
181 /// but mVoidSlot can be used for values that will be discarded.
184 /// The property. If this is a value, it simply returns that value in
185 /// the return_slot immediately. Otherwise, it may immediately call
186 /// the gettter or it may push that onto the call stack and transfer
187 /// control. Callers can be agnostic as to which happens.
188 void pushGet(as_object
*this_obj
, as_value
& return_slot
, Property
*prop
);
190 /// push a set call to be executed next.
192 /// Any Property can be pushed, and it will set the property, if possible.
193 /// setter properties and simple properties alike will be handled by this.
196 /// The 'this' to use for a getter/setter if it exists.
199 /// The value which should be set
202 /// The property desired to be set.
204 void pushSet(as_object
*this_obj
, as_value
& value
, Property
*prop
);
206 /// push a call to be executed next
208 /// Push a call to be executed as soon as execution of the current opcode
209 /// finishes. At the end, transfer will return to the previous context.
212 /// The function to call
215 /// The object to act as the 'this' pointer.
217 /// @param return_slot
218 /// The slot to use for returns. Use mIgnoreReturn if you don't care
219 /// what happens here.
222 /// How many of the values on the stack are for the new context
225 /// How much of the stack should be left behind when the function exits.
226 /// For example: 0 will leave a stack which is stack_in shorter than it
227 /// was on call. 1 will leave a stack which is 1 taller than it was on
230 /// RESTRICTION: stack_in - stack_out must not be negative
231 void pushCall(as_function
*func
, as_object
*pThis
, as_value
& return_slot
,
232 unsigned char stack_in
, short stack_out
);
234 void immediateFunction(const as_function
*to_call
, as_object
* pThis
,
235 as_value
& storage
, unsigned char stack_in
, short stack_out
);
237 void immediateProcedure(const as_function
*to_call
, as_object
*pthis
,
238 unsigned char stack_in
, short stack_out
) {
239 immediateFunction(to_call
, pthis
, mIgnoreReturn
, stack_in
, stack_out
);
242 void initMachine(AbcBlock
* pool_block
);
244 as_value
executeFunction(Method
* function
, const fn_call
& fn
);
246 void instantiateClass(std::string className
, as_object
* global
);
247 /// Return the Global object for this Machine.
249 /// This should be different from the AVM1 global object because the VMs
250 /// do not share any ActionScript resources. It should be the same
251 /// for a complete run of the Machine so that modifications carried out
252 /// by scripts are preserved for subsequent scripts.
255 void markReachableResources() const;
258 /// The state of the machine.
262 unsigned int _stackDepth
;
263 unsigned int _stackTotalSize
;
264 unsigned int _scopeStackDepth
;
265 unsigned int mScopeTotalSize
;
268 Namespace
*mDefaultXMLNamespace
;
269 as_object
*mCurrentScope
;
270 as_value
*mGlobalReturn
;
272 std::vector
<as_value
> _registers
;
273 abc_function
* mFunction
;
274 void to_debug_string(){
275 log_abc("StackDepth=%u StackTotalSize=%u ScopeStackDepth=%u ScopeTotalSize=%u",_stackDepth
,_stackTotalSize
,_scopeStackDepth
,mScopeTotalSize
);
283 unsigned int mHeightAfterPop
;
286 Scope() : mHeightAfterPop(0), mScope(NULL
) {/**/}
287 Scope(unsigned int i
, as_object
*o
) : mHeightAfterPop(i
),
295 as_value
find_prop_strict(MultiName multiname
);
299 void print_scope_stack();
301 void get_args(size_t argc
, FunctionArgs
<as_value
>& args
);
303 void load_function(CodeStream
* stream
, boost::uint32_t maxRegisters
);
305 void executeCodeblock(CodeStream
* stream
);
307 void clearRegisters(boost::uint32_t maxRegsiters
);
309 const as_value
& getRegister(int index
){
310 log_abc("Getting value at a register %d ", index
);
311 return _registers
[index
];
314 void setRegister(size_t index
, const as_value
& val
) {
315 log_abc("Putting %s in register %s", val
, index
);
316 if (_registers
.size() <= index
) {
317 log_abc("Register doesn't exist! Adding new registers!");
318 _registers
.resize(index
+ 1);
320 _registers
[index
] = val
;
323 void push_stack(as_value object
){
324 log_abc("Pushing value %s onto stack.", object
);
328 as_value
pop_stack(){
329 as_value value
= _stack
.pop();
330 log_abc("Popping value %s off the stack.", value
);
334 void push_scope_stack(as_value object
);
336 as_object
* pop_scope_stack() {
337 log_abc("Popping value %s off the scope stack. There will be "
338 "%u items left.", as_value(_scopeStack
.top(0)),
339 _scopeStack
.size()-1);
340 return _scopeStack
.pop();
343 as_object
* get_scope_stack(boost::uint8_t depth
) const {
344 log_abc("Getting value from scope stack %u from the bottom.",
346 return _scopeStack
.value(depth
);
349 SafeStack
<as_value
> _stack
;
350 SafeStack
<State
> mStateStack
;
351 std::vector
<as_value
> _registers
;
353 /// The scope stack is used to look for objects as properties
355 /// This stack is not cleared before a function call, class instantiation
356 /// etc, but anything on the stack cannot be altered by the function call.
357 /// On return from the function, the stack should be the same as it was
359 /// Most importantly, the complete stack is used for lookups, including
360 /// the section that is not changeable.
361 SafeStack
<as_object
*> _scopeStack
;
367 Namespace
* mDefaultXMLNamespace
;
368 as_object
* mCurrentScope
;
369 as_object
* mGlobalScope
;
370 as_object
* mDefaultThis
;
373 /// The global object for this machine.
376 as_value mGlobalReturn
;
377 as_value mIgnoreReturn
; // Throw away returns go here.
379 bool mExitWithReturn
;
380 AbcBlock
* mPoolObject
; // Where all of the pools are stored.
382 abc_function
* mCurrentFunction
;