make numbers garbage-collected objects
[swfdec.git] / swfdec / swfdec_as_stack.c
blobfa3d059546aea7df57c936bfbef356b3557c9558
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 <string.h>
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)
39 gsize size;
40 SwfdecAsStack *stack;
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;
48 stack->next = NULL;
49 return stack;
52 static void
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;
61 gboolean
62 swfdec_as_stack_push_segment (SwfdecAsContext *context)
64 SwfdecAsStack *stack;
66 /* finish current stack */
67 if (context->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);
73 if (stack == NULL)
74 return FALSE;
75 SWFDEC_DEBUG ("pushing new stack segment %p", stack);
76 stack->next = context->stack;
77 swfdec_as_stack_set (context, stack);
78 return TRUE;
81 static void
82 swfdec_as_stack_free (SwfdecAsContext *context, SwfdecAsStack *stack)
84 gsize size;
86 size = sizeof (SwfdecAsStack) + stack->n_elements * sizeof (SwfdecAsValue);
87 swfdec_as_context_unuse_mem (context, size);
88 g_slice_free1 (size, stack);
91 void
92 swfdec_as_stack_pop_segment (SwfdecAsContext *context)
94 SwfdecAsStack *stack = context->stack;
95 if (stack->next) {
96 swfdec_as_stack_set (context, stack->next);
97 } else {
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);
105 void
106 swfdec_as_stack_mark (SwfdecAsStack *stack)
108 guint i;
110 for (i = 0; i < stack->used_elements; i++) {
111 swfdec_as_value_mark (&stack->elements[i]);
113 if (stack->next)
114 swfdec_as_stack_mark (stack->next);
117 void
118 swfdec_as_stack_ensure_size (SwfdecAsContext *context, guint n_elements)
120 guint current;
121 SwfdecAsStack *next;
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))
128 return;
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);
136 return;
138 if (current) {
139 n_elements -= current;
140 memmove (context->base + n_elements, context->base, current * sizeof (SwfdecAsValue));
142 context->cur += n_elements;
143 if (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);
151 } else {
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));
158 if (n_elements) {
159 memset (context->base, 0, n_elements * sizeof (SwfdecAsValue));
164 void
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))
171 return;
173 if (!swfdec_as_stack_push_segment (context))
174 context->cur = context->end - n_elements;
177 guint
178 swfdec_as_stack_get_size (SwfdecAsContext *context)
180 SwfdecAsStack *stack;
181 SwfdecAsValue *target;
182 guint ret;
184 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), 0);
186 if (context->frame == NULL)
187 return 0;
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;
195 stack = stack->next;
197 ret += &stack->elements[stack->used_elements] - target;
198 return ret;