1 // 2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 3 // 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 18 19 #ifndef GNASH_ACTIONEXEC_H 20 #define GNASH_ACTIONEXEC_H 21 22 #include <string> 23 #include <stack> 24 #include <vector> 25 #include <boost/noncopyable.hpp> 26 27 #include "as_environment.h" 28 #include "SWF.h" 29 #include "action_buffer.h" 30 31 // Forward declarations 32 namespace gnash { 33 class as_value; 34 class Function; 35 class ActionExec; 36 } 37 38 namespace gnash { 39 40 class TryBlock 41 { 42 public: 43 friend class ActionExec; 44 45 enum tryState 46 { 47 TRY_TRY, // In a try block. 48 TRY_CATCH, // In a catch block. 49 TRY_FINALLY, // In a finally block. 50 TRY_END // Finished with finally 51 }; 52 TryBlock(size_t cur_off,size_t try_size,size_t catch_size,size_t finally_size,std::string catchName)53 TryBlock(size_t cur_off, size_t try_size, size_t catch_size, 54 size_t finally_size, std::string catchName) 55 : 56 _catchOffset(cur_off + try_size), 57 _finallyOffset(cur_off + try_size + catch_size), 58 _afterTriedOffset(cur_off + try_size + catch_size + finally_size), 59 _savedEndOffset(0), 60 _hasName(true), 61 _name(std::move(catchName)), 62 _registerIndex(0), 63 _tryState(TryBlock::TRY_TRY), 64 _lastThrow() 65 {} 66 TryBlock(size_t cur_off,size_t try_size,size_t catch_size,size_t finally_size,std::uint8_t register_index)67 TryBlock(size_t cur_off, size_t try_size, size_t catch_size, 68 size_t finally_size, std::uint8_t register_index) 69 : 70 _catchOffset(cur_off + try_size), 71 _finallyOffset(cur_off + try_size + catch_size), 72 _afterTriedOffset(cur_off + try_size + catch_size + finally_size), 73 _savedEndOffset(0), 74 _hasName(false), 75 _name(), 76 _registerIndex(register_index), 77 _tryState(TryBlock::TRY_TRY), 78 _lastThrow() 79 {} 80 81 private: 82 size_t _catchOffset; 83 size_t _finallyOffset; 84 size_t _afterTriedOffset; 85 size_t _savedEndOffset; 86 bool _hasName; 87 std::string _name; 88 unsigned int _registerIndex; 89 tryState _tryState; 90 as_value _lastThrow; 91 }; 92 93 class With 94 { 95 public: 96 With(as_object * obj,size_t end)97 With(as_object* obj, size_t end) 98 : 99 _object(obj), 100 _block_end_pc(end) 101 { 102 } 103 end_pc()104 size_t end_pc() const { 105 return _block_end_pc; 106 } 107 object()108 as_object* object() const { 109 return _object; 110 } 111 112 private: 113 as_object* _object; 114 size_t _block_end_pc; 115 }; 116 117 /// Executor of an action_buffer 118 class ActionExec : boost::noncopyable 119 { 120 121 typedef as_environment::ScopeStack ScopeStack; 122 123 public: 124 125 /// Create an execution thread 126 // 127 /// @param abuf the action code 128 /// @param newEnv the timeline context. 129 /// @param abortOnUnloaded If true (default) execution aborts as soon 130 /// as the target sprite is unloaded. 131 /// NOTE: original target is fetched from the environment. 132 ActionExec(const action_buffer& abuf, as_environment& newEnv, 133 bool abortOnUnloaded = true); 134 135 /// Create an execution thread for a function call. 136 // 137 /// @param func The function 138 /// @param newEnv The execution environment (variables scope, stack etc.) 139 /// @param nRetval Where to return a value. If NULL any return will 140 /// be discarded. 141 ActionExec(const Function& func, as_environment& newEnv, 142 as_value* nRetVal, as_object* this_ptr); 143 144 /// Use this to push a try block. It will be copied 145 void pushTryBlock(TryBlock t); 146 147 /// Set the return value. 148 void pushReturn(const as_value& t); 149 150 /// The actual action buffer 151 // 152 /// TODO: provide a getter and make private 153 const action_buffer& code; 154 155 /// TODO: provide a getter and make private ? 156 as_environment& env; 157 158 /// TODO: provide a setter and make private ? 159 as_value* retval; 160 161 /// Is this execution thread a function call ? isFunction()162 bool isFunction() const { return _func != nullptr; } 163 164 /// Get the current 'this' pointer, for use in function calls 165 as_object* getThisPointer(); 166 167 /// Returns the scope stack associated with this execution thread getScopeStack()168 const ScopeStack& getScopeStack() const { 169 return _scopeStack; 170 } 171 172 /// Push an entry to the with stack 173 // 174 /// @return true if the entry was pushed, false otherwise. This 175 /// depends on the with stack limit. 176 bool pushWith(const With& entry); 177 178 /// Skip the specified number of action tags 179 // 180 /// The offset is relative to next_pc 181 void skip_actions(size_t offset); 182 183 /// Delete named variable, seeking for it in the with stack if any 184 // 185 /// @param name Name of the variable. Supports slash and dot syntax. 186 bool delVariable(const std::string& name); 187 188 /// Set a named variable, seeking for it in the with stack if any. 189 // 190 /// @param name Name of the variable. Supports slash and dot syntax. 191 void setVariable(const std::string& name, const as_value& val); 192 193 /// Set a function-local variable 194 // 195 /// If we're not in a function, set a normal variable. 196 // 197 /// @param name Name of the variable. Supports slash and dot syntax. 198 /// @param val The value to set the variable to. 199 void setLocalVariable(const std::string& name, const as_value& val); 200 201 /// Get a named variable, seeking for it in the with stack if any. 202 // 203 /// @param name Name of the variable. Supports slash and dot syntax. 204 /// @param target An output parameter, will be set to point to the object 205 /// containing any found variable. If you aren't interested, 206 /// pass null (default). If the variable does not belong 207 /// to an object, target will be set to null. 208 as_value getVariable(const std::string& name, as_object** target = nullptr); 209 210 /// Get current target. 211 // 212 /// This function returns top 'with' stack entry, if any. 213 /// Main use for this function is for calling methods and 214 /// properly setting the "this" pointer. 215 /// 216 /// TODO: 217 /// A better, cleaner and less error-prone approach 218 /// would be providing a callFunction() method in 219 /// ActionExec. This will likely help debugger too 220 as_object* getTarget(); 221 222 /// Execute. 223 void operator()(); 224 225 // TODO: cut down these accessors. atActionTag(SWF::ActionType t)226 bool atActionTag(SWF::ActionType t) { return code[pc] == t; } 227 getCurrentPC()228 size_t getCurrentPC() const { return pc; } 229 skipRemainingBuffer()230 void skipRemainingBuffer() { next_pc = stop_pc; } 231 232 void adjustNextPC(int offset); 233 getNextPC()234 size_t getNextPC() const { return next_pc; } 235 setNextPC(size_t pc)236 void setNextPC(size_t pc) { next_pc = pc; } 237 getStopPC()238 size_t getStopPC() const { return stop_pc; } 239 240 private: 241 242 /// \brief 243 /// Debugging function: 244 /// print opcodes from start (included) to end (not-included) PCs. 245 // 246 /// @param start 247 /// First opcode to dump 248 /// 249 /// @param end 250 /// One-past last opcode to dump 251 /// 252 /// @param os 253 /// Output stream to dump to 254 /// 255 void dumpActions(size_t start, size_t end, std::ostream& os); 256 257 /// Processes the current try - catch - finally block 258 // 259 /// This function is called after each stage of a 260 /// try/catch/finally block. It ensures it is called 261 /// after each stage by setting stop_pc to the appropriate 262 /// number. If an exception is on the stack at any stage, 263 /// it takes the appropriate action (catch, set register 264 /// values, return, or leave it on the stack). Return 265 /// false means that the action processing loop should be 266 /// interrupted. 267 // 268 /// @return whether to continue executing the buffer 269 /// @param t the try block to process. 270 bool processExceptions(TryBlock& t); 271 272 /// Run after a complete run, or after an run interrupted by 273 /// a bail-out exception (ActionLimitException, for example) 274 // 275 /// The method restores original target of the as_environment, 276 /// checks for stack smashing (stack contains less entries 277 /// then it had at time of execution start) or leftovers 278 /// (stack contains more entries then it had at time of execution 279 /// start) and finally gives movie_root a chance to execute 280 /// actions queued in higher priority action queues. 281 /// 282 /// The higher priority action queue flush is needed to allow 283 /// initialize/construct/initactions queued by effect of gotoFrame 284 /// calls in DOACTION block before frame actions queued by the same 285 /// cause (the latter would be pushed in the same level gotoFrame is 286 /// found) 287 void cleanupAfterRun(); 288 289 /// the 'with' stack associated with this execution thread 290 std::vector<With> _withStack; 291 292 /// the scope stack associated with this execution thread 293 ScopeStack _scopeStack; 294 295 /// A pointer to the function being executed, or NULL 296 /// for non-function execution 297 /// 298 /// TODO: 299 /// This should likely be put in a larger 300 /// structure including return address 301 /// and maintained in a stack (the call stack) 302 /// 303 const Function* _func; 304 305 /// The 'this' pointer, if this is a function call 306 as_object* _this_ptr; 307 308 /// Stack size at start of execution 309 size_t _initialStackSize; 310 311 DisplayObject* _originalTarget; 312 313 int _origExecSWFVersion; 314 315 std::stack<TryBlock> _tryList; 316 317 bool _returning; 318 319 bool _abortOnUnload; 320 321 /// Program counter (offset of current action tag) 322 size_t pc; 323 324 /// Offset to next action tag 325 size_t next_pc; 326 327 /// End of current function execution 328 /// Used for try/throw/catch blocks. 329 size_t stop_pc; 330 331 }; 332 333 } // namespace gnash 334 335 #endif // GNASH_ACTIONEXEC_H 336 337 // Local Variables: 338 // mode: C++ 339 // indent-tabs-mode: t 340 // End: 341