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.
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
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"
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.
55 * the object used to represent an executing function.
58 /*** STACK ITERATOR ***/
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.
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
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;
94 iter
->current
= (SwfdecAsValue
*) frame
->argv
;
96 SwfdecAsStack
*stack
= context
->stack
;
98 iter
->current
= frame
->stack_begin
- 1;
100 while (iter
->current
< stack
->elements
||
101 iter
->current
> end
) {
103 end
= &stack
->elements
[stack
->used_elements
];
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 (&iter, frame); value != NULL;
122 * value = swfdec_as_stack_iterator_next (&iter)) {
123 * char *s = swfdec_as_value_to_debug (value);
124 * g_print ("%s\n", s);
128 * Returns: the topmost value on the stack of @frame or %NULL if none
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
);
139 stack
= context
->stack
;
140 if (context
->frame
== frame
) {
141 iter
->current
= context
->cur
;
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
]) {
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
;
160 g_assert (iter
->n
>= (guint
) (frame
->stack_begin
- &stack
->elements
[0]));
161 iter
->n
-= frame
->stack_begin
- &stack
->elements
[0];
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
];
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
182 swfdec_as_stack_iterator_next (SwfdecAsStackIterator
*iter
)
184 if (iter
->i
< iter
->n
)
186 if (iter
->i
>= iter
->n
)
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
];
198 return iter
->current
;
201 /*** BLOCK HANDLING ***/
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.
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
);
241 swfdec_as_frame_pop_block (SwfdecAsFrame
*frame
, SwfdecAsContext
*cx
)
243 SwfdecAsFrameBlockFunc func
;
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);
253 g_array_set_size (frame
->blocks
, frame
->blocks
->len
- 1);
254 if (frame
->blocks
->len
) {
256 frame
->block_start
= block
->start
;
257 frame
->block_end
= block
->end
;
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
);
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
);
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
);
284 swfdec_script_unref (frame
->script
);
285 frame
->script
= NULL
;
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");
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
;
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().
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.
368 swfdec_as_frame_get_variable_and_flags (SwfdecAsContext
*cx
, SwfdecAsFrame
*frame
,
369 const char *variable
, SwfdecAsValue
*value
, guint
*flags
, SwfdecAsObject
**pobject
)
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
,
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
);
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
))
391 /* 2) the global object */
392 if (cx
->version
> 4 && swfdec_as_object_get_variable_and_flags (cx
->global
,
393 variable
, value
, flags
, pobject
))
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
;
407 g_return_if_fail (frame
!= NULL
);
408 g_return_if_fail (variable
!= 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
) {
421 /* the !frame->original_target check is exclusively for init scripts */
422 if (frame
->activation
&& (local
|| !frame
->original_target
)) {
423 set
= frame
->activation
;
425 SwfdecMovie
*target
= swfdec_as_frame_get_target (frame
);
427 set
= swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (target
));
436 if (swfdec_as_object_get_variable (set
, variable
, NULL
))
440 swfdec_as_object_set_variable_and_flags (set
, variable
, value
, default_flags
);
444 swfdec_as_frame_delete_variable (SwfdecAsContext
*cx
, SwfdecAsFrame
*frame
, const char *variable
)
447 SwfdecAsDeleteReturn ret
;
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
);
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
);
463 ret
= swfdec_as_object_delete_variable (swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (target
)), variable
);
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.
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
));
487 frame
->target
= target
;
489 frame
->target
= frame
->original_target
;
494 swfdec_as_frame_preload (SwfdecAsContext
*context
, SwfdecAsFrame
*frame
)
496 SwfdecAsObject
*object
, *args
;
497 guint i
, current_reg
= 1;
498 SwfdecScript
*script
;
500 const SwfdecAsValue
*cur
;
501 SwfdecAsStackIterator iter
;
503 g_return_if_fail (SWFDEC_IS_AS_CONTEXT (context
));
504 g_return_if_fail (frame
!= NULL
);
507 script
= frame
->script
;
508 if (frame
->script
== NULL
)
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
) {
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
);
524 while (next
!= NULL
&& (next
->function
== NULL
||
525 SWFDEC_IS_AS_NATIVE_FUNCTION (next
->function
))) {
529 SWFDEC_AS_VALUE_SET_OBJECT (&val
, swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (next
->function
)));
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
)));
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
);
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
)) {
558 SWFDEC_AS_VALUE_SET_OBJECT (&val
, swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (frame
->super
)));
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
++) {
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
;
576 SWFDEC_ERROR ("trying to set %uth argument %s in nonexisting register %u",
577 i
, script
->arguments
[i
].name
, script
->arguments
[i
].preload
);
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
) {
597 SWFDEC_AS_VALUE_SET_OBJECT (&frame
->registers
[current_reg
++],
598 swfdec_as_relay_get_as_object (SWFDEC_AS_RELAY (frame
->super
)));
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");
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");
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
;
623 if (context
->state
== SWFDEC_AS_CONTEXT_ABORTED
) {
624 swfdec_as_context_return (context
, NULL
);
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
);
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 */
647 swfdec_as_context_return (cx
, NULL
);
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
);
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.
673 swfdec_as_frame_get_next (SwfdecAsFrame
*frame
)
675 g_return_val_if_fail (frame
!= NULL
, NULL
);
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
690 swfdec_as_frame_get_script (SwfdecAsFrame
*frame
)
692 g_return_val_if_fail (frame
!= NULL
, NULL
);
694 return frame
->script
;