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
25 #include "swfdec_as_stack.h"
26 #include "swfdec_as_context.h"
27 #include "swfdec_as_frame_internal.h"
28 #include "swfdec_debug.h"
30 /* FIXME: make this configurable? */
31 #define SWFDEC_AS_STACK_SIZE 8192 /* random big number */
33 /* minimum number of elements that need to stay free that makes us remove a stack segment */
34 #define SWFDEC_AS_STACK_LEFTOVER 16
36 static SwfdecAsStack
*
37 swfdec_as_stack_new (SwfdecAsContext
*context
, guint n_elements
)
42 size
= sizeof (SwfdecAsStack
) + n_elements
* sizeof (SwfdecAsValue
);
43 swfdec_as_context_use_mem (context
, size
);
45 stack
= g_slice_alloc (size
);
46 stack
->n_elements
= n_elements
;
47 stack
->used_elements
= 0;
53 swfdec_as_stack_set (SwfdecAsContext
*context
, SwfdecAsStack
*stack
)
55 context
->stack
= stack
;
56 context
->base
= &stack
->elements
[0];
57 context
->cur
= context
->base
+ stack
->used_elements
;
58 context
->end
= context
->base
+ SWFDEC_AS_STACK_SIZE
;
62 swfdec_as_stack_push_segment (SwfdecAsContext
*context
)
66 /* finish current stack */
68 context
->stack
->used_elements
= context
->cur
- context
->base
;
69 g_assert (context
->stack
->used_elements
<= context
->stack
->n_elements
);
72 stack
= swfdec_as_stack_new (context
, SWFDEC_AS_STACK_SIZE
);
75 SWFDEC_DEBUG ("pushing new stack segment %p", stack
);
76 stack
->next
= context
->stack
;
77 swfdec_as_stack_set (context
, stack
);
82 swfdec_as_stack_free (SwfdecAsContext
*context
, SwfdecAsStack
*stack
)
86 size
= sizeof (SwfdecAsStack
) + stack
->n_elements
* sizeof (SwfdecAsValue
);
87 swfdec_as_context_unuse_mem (context
, size
);
88 g_slice_free1 (size
, stack
);
92 swfdec_as_stack_pop_segment (SwfdecAsContext
*context
)
94 SwfdecAsStack
*stack
= context
->stack
;
96 swfdec_as_stack_set (context
, stack
->next
);
98 context
->base
= context
->cur
= context
->end
= NULL
;
99 context
->stack
= NULL
;
101 SWFDEC_DEBUG ("popping stack segment %p, next is %p", stack
, context
->stack
);
102 swfdec_as_stack_free (context
, stack
);
106 swfdec_as_stack_mark (SwfdecAsStack
*stack
)
110 for (i
= 0; i
< stack
->used_elements
; i
++) {
111 swfdec_as_value_mark (&stack
->elements
[i
]);
114 swfdec_as_stack_mark (stack
->next
);
118 swfdec_as_stack_ensure_size (SwfdecAsContext
*context
, guint n_elements
)
123 g_return_if_fail (SWFDEC_IS_AS_CONTEXT (context
));
124 g_return_if_fail (n_elements
< SWFDEC_AS_STACK_SIZE
/ 2);
126 current
= (guint
) (context
->cur
- context
->base
);
127 if (G_LIKELY (current
>= n_elements
))
129 next
= context
->stack
->next
;
130 /* check if we can move this to the last stack */
131 if (next
&& context
->base
!= context
->frame
->stack_begin
&&
132 (next
->n_elements
- next
->used_elements
> SWFDEC_AS_STACK_LEFTOVER
+ current
)) {
133 memmove (&next
->elements
[next
->used_elements
], context
->base
, current
* sizeof (SwfdecAsValue
));
134 next
->used_elements
+= current
;
135 swfdec_as_stack_pop_segment (context
);
139 n_elements
-= current
;
140 memmove (context
->base
+ n_elements
, context
->base
, current
* sizeof (SwfdecAsValue
));
142 context
->cur
+= n_elements
;
144 if (next
&& context
->base
!= context
->frame
->stack_begin
) {
145 /* this should be true by a huge amount */
146 g_assert (next
->used_elements
>= n_elements
);
147 if (context
->frame
->stack_begin
<= &next
->elements
[next
->used_elements
] &&
148 context
->frame
->stack_begin
>= &next
->elements
[0]) {
149 current
= &next
->elements
[next
->used_elements
] - context
->frame
->stack_begin
;
150 current
= MIN (n_elements
, current
);
152 current
= n_elements
;
154 next
->used_elements
-= current
;
155 n_elements
-= current
;
156 memmove (context
->base
+ n_elements
, &next
->elements
[next
->used_elements
], current
* sizeof (SwfdecAsValue
));
159 memset (context
->base
, 0, n_elements
* sizeof (SwfdecAsValue
));
165 swfdec_as_stack_ensure_free (SwfdecAsContext
*context
, guint n_elements
)
167 g_return_if_fail (SWFDEC_IS_AS_CONTEXT (context
));
168 g_return_if_fail (n_elements
< SWFDEC_AS_STACK_SIZE
/ 2);
170 if (G_LIKELY ((guint
) (context
->end
- context
->cur
) >= n_elements
))
173 if (!swfdec_as_stack_push_segment (context
))
174 context
->cur
= context
->end
- n_elements
;
178 swfdec_as_stack_get_size (SwfdecAsContext
*context
)
180 SwfdecAsStack
*stack
;
181 SwfdecAsValue
*target
;
184 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context
), 0);
186 if (context
->frame
== NULL
)
188 target
= context
->frame
->stack_begin
;
189 if (target
== context
->base
)
190 return context
->cur
- context
->base
;
191 stack
= context
->stack
->next
;
192 ret
= context
->cur
- context
->base
;
193 while (target
< &stack
->elements
[0] && target
> &stack
->elements
[stack
->used_elements
]) {
194 ret
+= stack
->n_elements
;
197 ret
+= &stack
->elements
[stack
->used_elements
] - target
;