fix build for --disable-gtk-doc
[swfdec.git] / swfdec / swfdec_as_frame.c
blob5af43691d1d301e6bceb2b86f72cdcbd8fc149e9
1 /* Swfdec
2 * Copyright (C) 2007 Benjamin Otte <otte@gnome.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301 USA
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
24 #include "swfdec_as_frame_internal.h"
25 #include "swfdec_as_frame.h"
26 #include "swfdec_as_array.h"
27 #include "swfdec_as_context.h"
28 #include "swfdec_as_internal.h"
29 #include "swfdec_as_stack.h"
30 #include "swfdec_as_strings.h"
31 #include "swfdec_as_super.h"
32 #include "swfdec_debug.h"
33 #include "swfdec_movie.h"
35 /**
36 * SECTION:SwfdecAsFrame
37 * @title: SwfdecAsFrame
38 * @short_description: information about currently executing frames
40 * This section is only interesting for people that want to look into debugging.
41 * A SwfdecAsFrame describes a currently executing function while it is
42 * running. On every new function call, a new frame is created and pushed on top
43 * of the frame stack. To get the topmost one, use
44 * swfdec_as_context_get_frame(). After that you can inspect various properties
45 * of the frame, like the current stack.
47 * a #SwfdecAsFrame is a #SwfdecAsObject, so it is possible to set variables on
48 * it. These are local variables inside the executing function. So you can use
49 * functions such as swfdec_as_object_get_variable() to inspect them.
52 /**
53 * SwfdecAsFrame:
55 * the object used to represent an executing function.
58 /*** STACK ITERATOR ***/
60 /**
61 * SwfdecAsStackIterator:
63 * This is a struct used to walk the stack of a frame. It is supposed to be
64 * allocated on the stack. All of its members are private.
67 /**
68 * swfdec_as_stack_iterator_init_arguments:
69 * @iter: iterator to be initialized
70 * @context: context @frame belongs to
71 * @frame: the frame to initialize from
73 * Initializes a stack iterator to walk the arguments passed to the given @frame. See
74 * swfdec_as_stack_iterator_init() about suggested iterator usage.
76 * Returns: The value of the first argument
77 **/
78 SwfdecAsValue *
79 swfdec_as_stack_iterator_init_arguments (SwfdecAsStackIterator *iter,
80 SwfdecAsContext *context, SwfdecAsFrame *frame)
82 g_return_val_if_fail (iter != NULL, NULL);
83 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), NULL);
84 g_return_val_if_fail (frame != NULL, NULL);
86 if (frame->argc == 0) {
87 iter->i = iter->n = 0;
88 iter->stack = NULL;
89 iter->current = NULL;
90 return NULL;
92 if (frame->argv) {
93 iter->stack = NULL;
94 iter->current = (SwfdecAsValue *) frame->argv;
95 } else {
96 SwfdecAsStack *stack = context->stack;
97 SwfdecAsValue *end;
98 iter->current = frame->stack_begin - 1;
99 end = context->cur;
100 while (iter->current < stack->elements ||
101 iter->current > end) {
102 stack = stack->next;
103 end = &stack->elements[stack->used_elements];
105 iter->stack = stack;
107 iter->i = 0;
108 iter->n = frame->argc;
109 return iter->current;
113 * swfdec_as_stack_iterator_init:
114 * @iter: a #SwfdecStackIterator
115 * @context: context @frame belongs to
116 * @frame: the frame to initialize from
118 * Initializes @iter to walk the stack of @frame. The first value on the stack
119 * will alread be returned. This makes it possible to write a simple loop to
120 * print the whole stack:
121 * |[for (value = swfdec_as_stack_iterator_init (&amp;iter, frame); value != NULL;
122 * value = swfdec_as_stack_iterator_next (&amp;iter)) {
123 * char *s = swfdec_as_value_to_debug (value);
124 * g_print ("%s\n", s);
125 * g_free (s);
126 * }]|
128 * Returns: the topmost value on the stack of @frame or %NULL if none
130 SwfdecAsValue *
131 swfdec_as_stack_iterator_init (SwfdecAsStackIterator *iter, SwfdecAsContext *context, SwfdecAsFrame *frame)
133 SwfdecAsStack *stack;
135 g_return_val_if_fail (iter != NULL, NULL);
136 g_return_val_if_fail (frame != NULL, NULL);
138 iter->i = 0;
139 stack = context->stack;
140 if (context->frame == frame) {
141 iter->current = context->cur;
142 } else {
143 SwfdecAsFrame *follow = context->frame;
144 while (follow->next != frame)
145 follow = follow->next;
146 iter->current = follow->stack_begin;
147 /* FIXME: get rid of arguments on stack */
148 while (iter->current < &stack->elements[0] || iter->current > &stack->elements[stack->n_elements]) {
149 stack = stack->next;
150 g_assert (stack);
153 iter->stack = stack;
154 /* figure out number of args */
155 iter->n = iter->current - &stack->elements[0];
156 while (frame->stack_begin < &stack->elements[0] && frame->stack_begin > &stack->elements[stack->n_elements]) {
157 iter->n += stack->used_elements;
158 stack = stack->next;
160 g_assert (iter->n >= (guint) (frame->stack_begin - &stack->elements[0]));
161 iter->n -= frame->stack_begin - &stack->elements[0];
162 if (iter->n == 0)
163 return NULL;
164 if (iter->current == &iter->stack->elements[0]) {
165 iter->stack = iter->stack->next;
166 g_assert (iter->stack);
167 iter->current = &iter->stack->elements[iter->stack->used_elements];
169 iter->current--;
170 return iter->current;
174 * swfdec_as_stack_iterator_next:
175 * @iter: a #SwfdecAsStackIterator
177 * Gets the next value on the stack.
179 * Returns: The next value on the stack or %NULL if no more values are on the stack
181 SwfdecAsValue *
182 swfdec_as_stack_iterator_next (SwfdecAsStackIterator *iter)
184 if (iter->i < iter->n)
185 iter->i++;
186 if (iter->i >= iter->n)
187 return NULL;
188 if (iter->stack) {
189 if (iter->current == &iter->stack->elements[0]) {
190 iter->stack = iter->stack->next;
191 g_assert (iter->stack);
192 iter->current = &iter->stack->elements[iter->stack->used_elements];
194 iter->current--;
195 } else {
196 iter->current++;
198 return iter->current;
201 /*** BLOCK HANDLING ***/
203 typedef struct {
204 const guint8 * start; /* start of block */
205 const guint8 * end; /* end of block (hitting this address will exit the block) */
206 SwfdecAsFrameBlockFunc func; /* function to call when block is exited (or frame is destroyed) */
207 gpointer data; /* data to pass to function */
208 } SwfdecAsFrameBlock;
211 * swfdec_as_frame_push_block:
212 * @frame: a #SwfdecAsFrame
213 * @start: start of block
214 * @end: byte after end of block
215 * @func: function to call when block gets exited
216 * @data: data to pass to @func
218 * Registers a function that guards a block of memory. When the function
219 * exits this block of memory, it will call this function. This can happen
220 * either when the program counter leaves the guarded region, when the
221 * function returns or when the context aborted due to an unrecoverable error.
223 void
224 swfdec_as_frame_push_block (SwfdecAsFrame *frame, const guint8 *start,
225 const guint8 *end, SwfdecAsFrameBlockFunc func, gpointer data)
227 SwfdecAsFrameBlock block = { start, end, func, data };
229 g_return_if_fail (frame != NULL);
230 g_return_if_fail (start <= end);
231 g_return_if_fail (start >= frame->block_start);
232 g_return_if_fail (end <= frame->block_end);
233 g_return_if_fail (func != NULL);
235 frame->block_start = start;
236 frame->block_end = end;
237 g_array_append_val (frame->blocks, block);
240 void
241 swfdec_as_frame_pop_block (SwfdecAsFrame *frame, SwfdecAsContext *cx)
243 SwfdecAsFrameBlockFunc func;
244 gpointer data;
245 SwfdecAsFrameBlock *block;
247 g_return_if_fail (frame != NULL);
248 g_return_if_fail (frame->blocks->len > 0);
250 block = &g_array_index (frame->blocks, SwfdecAsFrameBlock, frame->blocks->len - 1);
251 func = block->func;
252 data = block->data;
253 g_array_set_size (frame->blocks, frame->blocks->len - 1);
254 if (frame->blocks->len) {
255 block--;
256 frame->block_start = block->start;
257 frame->block_end = block->end;
258 } else {
259 frame->block_start = frame->script->buffer->data;
260 frame->block_end = frame->script->buffer->data + frame->script->buffer->length;
262 /* only call function after we popped the block, so the block can push a new one */
263 func (cx, frame, data);
266 /*** FRAME ***/
268 void
269 swfdec_as_frame_free (SwfdecAsContext *context, SwfdecAsFrame *frame)
271 /* pop blocks while state is intact */
272 while (frame->blocks->len > 0)
273 swfdec_as_frame_pop_block (frame, context);
275 /* clean up */
276 g_slice_free1 (sizeof (SwfdecAsValue) * frame->n_registers, frame->registers);
277 if (frame->constant_pool) {
278 swfdec_constant_pool_unref (frame->constant_pool);
279 frame->constant_pool = NULL;
281 g_array_free (frame->blocks, TRUE);
282 g_slist_free (frame->scope_chain);
283 if (frame->script) {
284 swfdec_script_unref (frame->script);
285 frame->script = NULL;
289 void
290 swfdec_as_frame_init (SwfdecAsFrame *frame, SwfdecAsContext *context, SwfdecScript *script)
292 g_return_if_fail (frame != NULL);
293 g_return_if_fail (SWFDEC_IS_AS_CONTEXT (context));
294 g_return_if_fail (script != NULL);
296 swfdec_as_frame_init_native (frame, context);
297 frame->script = swfdec_script_ref (script);
298 SWFDEC_DEBUG ("new frame for function %s", script->name);
299 frame->pc = script->main;
300 frame->n_registers = script->n_registers;
301 frame->registers = g_slice_alloc0 (sizeof (SwfdecAsValue) * frame->n_registers);
302 if (script->constant_pool) {
303 frame->constant_pool = swfdec_constant_pool_new (context,
304 script->constant_pool, script->version);
305 if (frame->constant_pool == NULL) {
306 SWFDEC_ERROR ("couldn't create constant pool");
311 void
312 swfdec_as_frame_init_native (SwfdecAsFrame *frame, SwfdecAsContext *context)
314 g_return_if_fail (frame != NULL);
315 g_return_if_fail (SWFDEC_IS_AS_CONTEXT (context));
317 frame->blocks = g_array_new (FALSE, FALSE, sizeof (SwfdecAsFrameBlock));
318 frame->block_end = (gpointer) -1;
319 frame->stack_begin = context->cur;
320 context->base = frame->stack_begin;
321 frame->next = context->frame;
322 if (frame->next) {
323 frame->original_target = frame->next->original_target;
324 frame->target = frame->original_target;
326 context->frame = frame;
327 context->call_depth++;
331 * swfdec_as_frame_set_this:
332 * @frame: a #SwfdecAsFrame
333 * @thisp: object to use as the this object
335 * Sets the object to be used as this pointer. If this function is not called,
336 * the this value will be undefined.
337 * You may only call this function once per @frame and it must be called
338 * directly after creating the frame and before calling swfdec_as_frame_preload().
340 void
341 swfdec_as_frame_set_this (SwfdecAsFrame *frame, SwfdecAsObject *thisp)
343 g_return_if_fail (frame != NULL);
344 g_return_if_fail (SWFDEC_AS_VALUE_IS_UNDEFINED (frame->thisp));
345 g_return_if_fail (thisp != NULL);
347 g_assert (!SWFDEC_IS_AS_SUPER (thisp));
348 SWFDEC_AS_VALUE_SET_COMPOSITE (&frame->thisp, thisp);
352 * swfdec_as_frame_get_variable_and_flags:
353 * @frame: a #SwfdecAsFrame
354 * @variable: name of the variable
355 * @value: pointer to take value of the variable or %NULL
356 * @flags: pointer to take flags or %NULL
357 * @pobject: pointer to take the actual object that held the variable or %NULL
359 * Walks the scope chain of @frame trying to resolve the given @variable and if
360 * found, returns its value and flags. Note that there might be a difference
361 * between @pobject and the returned object, since the returned object will be
362 * part of the scope chain while @pobject will contain the actual property. It
363 * will be a prototype of the returned object though.
365 * Returns: Object in scope chain that contained the variable.
367 SwfdecAsObject *
368 swfdec_as_frame_get_variable_and_flags (SwfdecAsContext *cx, SwfdecAsFrame *frame,
369 const char *variable, SwfdecAsValue *value, guint *flags, SwfdecAsObject **pobject)
371 SwfdecMovie *target;
372 GSList *walk;
374 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (cx), NULL);
375 g_return_val_if_fail (frame != NULL, NULL);
376 g_return_val_if_fail (variable != NULL, NULL);
378 for (walk = frame->scope_chain; walk; walk = walk->next) {
379 if (swfdec_as_object_get_variable_and_flags (walk->data, variable, value,
380 flags, pobject))
381 return walk->data;
383 /* we've walked the scope chain down. Now look in the special objects. */
384 /* 1) the current target */
385 target = swfdec_as_frame_get_target (frame);
386 if (target) {
387 SwfdecAsObject *object = swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (target));
388 if (swfdec_as_object_get_variable_and_flags (object, variable, value, flags, pobject))
389 return object;
391 /* 2) the global object */
392 if (cx->version > 4 && swfdec_as_object_get_variable_and_flags (cx->global,
393 variable, value, flags, pobject))
394 return cx->global;
396 return NULL;
399 void
400 swfdec_as_frame_set_variable_and_flags (SwfdecAsContext *context, SwfdecAsFrame *frame,
401 const char *variable, const SwfdecAsValue *value, guint default_flags,
402 gboolean overwrite, gboolean local)
404 SwfdecAsObject *pobject, *set;
405 GSList *walk;
407 g_return_if_fail (frame != NULL);
408 g_return_if_fail (variable != NULL);
410 set = NULL;
411 for (walk = frame->scope_chain; walk; walk = walk->next) {
412 if (swfdec_as_object_get_variable_and_flags (walk->data, variable, NULL, NULL, &pobject) &&
413 pobject == walk->data) {
414 if (!overwrite)
415 return;
416 set = walk->data;
417 break;
420 if (set == NULL) {
421 /* the !frame->original_target check is exclusively for init scripts */
422 if (frame->activation && (local || !frame->original_target)) {
423 set = frame->activation;
424 } else {
425 SwfdecMovie *target = swfdec_as_frame_get_target (frame);
426 if (target)
427 set = swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (target));
428 else
429 set = NULL;
431 if (set == NULL)
432 return;
435 if (!overwrite) {
436 if (swfdec_as_object_get_variable (set, variable, NULL))
437 return;
440 swfdec_as_object_set_variable_and_flags (set, variable, value, default_flags);
443 SwfdecAsDeleteReturn
444 swfdec_as_frame_delete_variable (SwfdecAsContext *cx, SwfdecAsFrame *frame, const char *variable)
446 GSList *walk;
447 SwfdecAsDeleteReturn ret;
448 SwfdecMovie *target;
450 g_return_val_if_fail (frame != NULL, FALSE);
451 g_return_val_if_fail (variable != NULL, FALSE);
453 for (walk = frame->scope_chain; walk; walk = walk->next) {
454 ret = swfdec_as_object_delete_variable (walk->data, variable);
455 if (ret)
456 return ret;
458 /* we've walked the scope chain down. Now look in the special objects. */
459 /* 1) the target set via SetTarget */
461 target = swfdec_as_frame_get_target (frame);
462 if (target) {
463 ret = swfdec_as_object_delete_variable (swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (target)), variable);
464 if (ret)
465 return ret;
467 /* 2) the global object */
468 return swfdec_as_object_delete_variable (cx->global, variable);
472 * swfdec_as_frame_set_target:
473 * @frame: a #SwfdecAsFrame
474 * @target: the movie to use as target or %NULL to unset
476 * Sets the new target to be used in this @frame. The target is a legacy
477 * Actionscript concept that is similar to "with". If you don't have to,
478 * you shouldn't use this function.
480 void
481 swfdec_as_frame_set_target (SwfdecAsFrame *frame, SwfdecMovie *target)
483 g_return_if_fail (frame != NULL);
484 g_return_if_fail (target == NULL || SWFDEC_IS_MOVIE (target));
486 if (target) {
487 frame->target = target;
488 } else {
489 frame->target = frame->original_target;
493 void
494 swfdec_as_frame_preload (SwfdecAsContext *context, SwfdecAsFrame *frame)
496 SwfdecAsObject *object, *args;
497 guint i, current_reg = 1;
498 SwfdecScript *script;
499 SwfdecAsValue val;
500 const SwfdecAsValue *cur;
501 SwfdecAsStackIterator iter;
503 g_return_if_fail (SWFDEC_IS_AS_CONTEXT (context));
504 g_return_if_fail (frame != NULL);
506 /* setup */
507 script = frame->script;
508 if (frame->script == NULL)
509 goto out;
510 frame->activation = swfdec_as_object_new_empty (context);
511 object = frame->activation;
512 frame->scope_chain = g_slist_prepend (frame->scope_chain, object);
514 /* create arguments and super object if necessary */
515 if ((script->flags & (SWFDEC_SCRIPT_PRELOAD_ARGS | SWFDEC_SCRIPT_SUPPRESS_ARGS)) != SWFDEC_SCRIPT_SUPPRESS_ARGS) {
516 SwfdecAsFrame *next;
517 args = swfdec_as_array_new (context);
518 for (cur = swfdec_as_stack_iterator_init_arguments (&iter, context, frame); cur != NULL;
519 cur = swfdec_as_stack_iterator_next (&iter)) {
520 swfdec_as_array_push (args, cur);
523 next = frame->next;
524 while (next != NULL && (next->function == NULL ||
525 SWFDEC_IS_AS_NATIVE_FUNCTION (next->function))) {
526 next = next->next;
528 if (next != NULL) {
529 SWFDEC_AS_VALUE_SET_OBJECT (&val, swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (next->function)));
530 } else {
531 SWFDEC_AS_VALUE_SET_NULL (&val);
533 swfdec_as_object_set_variable_and_flags (args, SWFDEC_AS_STR_caller, &val,
534 SWFDEC_AS_VARIABLE_HIDDEN | SWFDEC_AS_VARIABLE_PERMANENT);
536 if (frame->function != NULL) {
537 SWFDEC_AS_VALUE_SET_OBJECT (&val, swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (frame->function)));
538 } else {
539 SWFDEC_AS_VALUE_SET_NULL (&val);
541 swfdec_as_object_set_variable_and_flags (args, SWFDEC_AS_STR_callee, &val,
542 SWFDEC_AS_VARIABLE_HIDDEN | SWFDEC_AS_VARIABLE_PERMANENT);
543 } else {
544 /* silence gcc */
545 args = NULL;
548 /* set the default variables (unless suppressed */
549 if (!(script->flags & SWFDEC_SCRIPT_SUPPRESS_THIS)) {
550 swfdec_as_object_set_variable (object, SWFDEC_AS_STR_this, &frame->thisp);
552 if (!(script->flags & SWFDEC_SCRIPT_SUPPRESS_ARGS)) {
553 SWFDEC_AS_VALUE_SET_OBJECT (&val, args);
554 swfdec_as_object_set_variable (object, SWFDEC_AS_STR_arguments, &val);
556 if (!(script->flags & SWFDEC_SCRIPT_SUPPRESS_SUPER)) {
557 if (frame->super) {
558 SWFDEC_AS_VALUE_SET_OBJECT (&val, swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (frame->super)));
559 } else {
560 SWFDEC_AS_VALUE_SET_UNDEFINED (&val);
562 swfdec_as_object_set_variable (object, SWFDEC_AS_STR_super, &val);
565 /* set and preload argument variables */
566 SWFDEC_AS_VALUE_SET_UNDEFINED (&val);
567 cur = swfdec_as_stack_iterator_init_arguments (&iter, context, frame);
568 for (i = 0; i < script->n_arguments; i++) {
569 if (cur == NULL)
570 cur = &val;
571 /* set this value at the right place */
572 if (script->arguments[i].preload) {
573 if (script->arguments[i].preload < frame->n_registers) {
574 frame->registers[script->arguments[i].preload] = *cur;
575 } else {
576 SWFDEC_ERROR ("trying to set %uth argument %s in nonexisting register %u",
577 i, script->arguments[i].name, script->arguments[i].preload);
579 } else {
580 const char *tmp = swfdec_as_context_get_string (context, script->arguments[i].name);
581 swfdec_as_object_set_variable (object, tmp, cur);
583 /* get the next argument */
584 cur = swfdec_as_stack_iterator_next (&iter);
587 /* preload from flags */
588 if ((script->flags & (SWFDEC_SCRIPT_PRELOAD_THIS | SWFDEC_SCRIPT_SUPPRESS_THIS)) == SWFDEC_SCRIPT_PRELOAD_THIS
589 && current_reg < script->n_registers) {
590 frame->registers[current_reg++] = frame->thisp;
592 if (script->flags & SWFDEC_SCRIPT_PRELOAD_ARGS && current_reg < script->n_registers) {
593 SWFDEC_AS_VALUE_SET_OBJECT (&frame->registers[current_reg++], args);
595 if (script->flags & SWFDEC_SCRIPT_PRELOAD_SUPER && current_reg < script->n_registers) {
596 if (frame->super) {
597 SWFDEC_AS_VALUE_SET_OBJECT (&frame->registers[current_reg++],
598 swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (frame->super)));
599 } else {
600 SWFDEC_AS_VALUE_SET_UNDEFINED (&frame->registers[current_reg++]);
603 if (script->flags & SWFDEC_SCRIPT_PRELOAD_ROOT && current_reg < script->n_registers) {
604 if (!swfdec_as_frame_get_variable (context, frame, SWFDEC_AS_STR__root, &frame->registers[current_reg])) {
605 SWFDEC_WARNING ("no root to preload");
607 current_reg++;
609 if (script->flags & SWFDEC_SCRIPT_PRELOAD_PARENT && current_reg < script->n_registers) {
610 if (!swfdec_as_frame_get_variable (context, frame, SWFDEC_AS_STR__parent, &frame->registers[current_reg])) {
611 SWFDEC_WARNING ("no root to preload");
613 current_reg++;
615 if (script->flags & SWFDEC_SCRIPT_PRELOAD_GLOBAL && current_reg < script->n_registers) {
616 SWFDEC_AS_VALUE_SET_OBJECT (&frame->registers[current_reg++], context->global);
618 /* set block boundaries */
619 frame->block_start = frame->script->buffer->data;
620 frame->block_end = frame->script->buffer->data + frame->script->buffer->length;
622 out:
623 if (context->state == SWFDEC_AS_CONTEXT_ABORTED) {
624 swfdec_as_context_return (context, NULL);
625 return;
627 if (context->debugger) {
628 SwfdecAsDebuggerClass *klass = SWFDEC_AS_DEBUGGER_GET_CLASS (context->debugger);
630 if (klass->enter_frame)
631 klass->enter_frame (context->debugger, context, frame);
635 void
636 swfdec_as_frame_handle_exception (SwfdecAsContext *cx, SwfdecAsFrame *frame)
638 g_return_if_fail (frame != NULL);
639 g_return_if_fail (cx->exception);
641 /* pop blocks in the hope that we are inside a Try block */
642 while (cx->exception && frame->blocks->len) {
643 swfdec_as_frame_pop_block (frame, cx);
645 /* no Try blocks caught it, exit frame */
646 if (cx->exception) {
647 swfdec_as_context_return (cx, NULL);
651 SwfdecMovie *
652 swfdec_as_frame_get_target (SwfdecAsFrame *frame)
654 if (SWFDEC_IS_MOVIE (frame->target) &&
655 SWFDEC_MOVIE (frame->target)->state < SWFDEC_MOVIE_STATE_DESTROYED)
656 return SWFDEC_MOVIE (frame->target);
657 if (SWFDEC_IS_MOVIE (frame->original_target) &&
658 SWFDEC_MOVIE (frame->original_target)->state < SWFDEC_MOVIE_STATE_DESTROYED)
659 return SWFDEC_MOVIE (frame->original_target);
660 return NULL;
664 * swfdec_as_frame_get_next:
665 * @frame: a #SwfdecAsFrame
667 * Gets the next frame in the frame stack. The next frame is the frame that
668 * will be executed after this @frame.
670 * Returns: the next #SwfdecAsFrame or %NULL if this is the bottommost frame.
672 SwfdecAsFrame *
673 swfdec_as_frame_get_next (SwfdecAsFrame *frame)
675 g_return_val_if_fail (frame != NULL, NULL);
677 return frame->next;
681 * swfdec_as_frame_get_script:
682 * @frame: a #SwfdecAsFrame
684 * Gets the script associated with the given @frame. If the frame references
685 * a native function, there will be no script and this function returns %NULL.
687 * Returns: The script executed by this frame or %NULL
689 SwfdecScript *
690 swfdec_as_frame_get_script (SwfdecAsFrame *frame)
692 g_return_val_if_fail (frame != NULL, NULL);
694 return frame->script;