fix jsut committed crasher by rewriting startDrag action
[swfdec.git] / libswfdec / swfdec_as_stack.c
blobf86e1e038b7633a12d0525430e82ddd8f348a47c
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 if (!swfdec_as_context_use_mem (context, size))
44 return NULL;
46 stack = g_slice_alloc (size);
47 stack->n_elements = n_elements;
48 stack->used_elements = 0;
49 stack->next = NULL;
50 return stack;
53 static void
54 swfdec_as_stack_set (SwfdecAsContext *context, SwfdecAsStack *stack)
56 context->stack = stack;
57 context->base = &stack->elements[0];
58 context->cur = context->base + stack->used_elements;
59 context->end = context->base + SWFDEC_AS_STACK_SIZE;
62 gboolean
63 swfdec_as_stack_push_segment (SwfdecAsContext *context)
65 SwfdecAsStack *stack;
67 /* finish current stack */
68 if (context->stack) {
69 context->stack->used_elements = context->cur - context->base;
70 g_assert (context->stack->used_elements <= context->stack->n_elements);
73 stack = swfdec_as_stack_new (context, SWFDEC_AS_STACK_SIZE);
74 if (stack == NULL)
75 return FALSE;
76 SWFDEC_DEBUG ("pushing new stack segment %p", stack);
77 stack->next = context->stack;
78 swfdec_as_stack_set (context, stack);
79 return TRUE;
82 static void
83 swfdec_as_stack_free (SwfdecAsContext *context, SwfdecAsStack *stack)
85 gsize size;
87 size = sizeof (SwfdecAsStack) + stack->n_elements * sizeof (SwfdecAsValue);
88 swfdec_as_context_unuse_mem (context, size);
89 g_slice_free1 (size, stack);
92 void
93 swfdec_as_stack_pop_segment (SwfdecAsContext *context)
95 SwfdecAsStack *stack = context->stack;
96 if (stack->next) {
97 swfdec_as_stack_set (context, stack->next);
98 } else {
99 context->base = context->cur = context->end = NULL;
100 context->stack = NULL;
102 SWFDEC_DEBUG ("popping stack segment %p, next is %p", stack, context->stack);
103 swfdec_as_stack_free (context, stack);
106 void
107 swfdec_as_stack_mark (SwfdecAsStack *stack)
109 guint i;
111 for (i = 0; i < stack->used_elements; i++) {
112 swfdec_as_value_mark (&stack->elements[i]);
114 if (stack->next)
115 swfdec_as_stack_mark (stack->next);
118 void
119 swfdec_as_stack_ensure_size (SwfdecAsContext *context, guint n_elements)
121 guint current;
122 SwfdecAsStack *next;
124 g_return_if_fail (SWFDEC_IS_AS_CONTEXT (context));
125 g_return_if_fail (n_elements < SWFDEC_AS_STACK_SIZE / 2);
127 current = (guint) (context->cur - context->base);
128 if (G_LIKELY (current >= n_elements))
129 return;
130 next = context->stack->next;
131 /* check if we can move this to the last stack */
132 if (next && context->base != context->frame->stack_begin &&
133 (next->n_elements - next->used_elements > SWFDEC_AS_STACK_LEFTOVER + current)) {
134 memmove (&next->elements[next->used_elements], context->base, current * sizeof (SwfdecAsValue));
135 next->used_elements += current;
136 swfdec_as_stack_pop_segment (context);
137 return;
139 if (current) {
140 n_elements -= current;
141 memmove (context->base + n_elements, context->base, current * sizeof (SwfdecAsValue));
143 context->cur += n_elements;
144 if (n_elements) {
145 if (next && context->base != context->frame->stack_begin) {
146 /* this should be true by a huge amount */
147 g_assert (next->used_elements >= n_elements);
148 if (context->frame->stack_begin <= &next->elements[next->used_elements] &&
149 context->frame->stack_begin >= &next->elements[0]) {
150 current = &next->elements[next->used_elements] - context->frame->stack_begin;
151 current = MIN (n_elements, current);
152 } else {
153 current = n_elements;
155 next->used_elements -= current;
156 n_elements -= current;
157 memmove (context->base + n_elements, &next->elements[next->used_elements], current * sizeof (SwfdecAsValue));
159 if (n_elements) {
160 memset (context->base, 0, n_elements * sizeof (SwfdecAsValue));
165 void
166 swfdec_as_stack_ensure_free (SwfdecAsContext *context, guint n_elements)
168 g_return_if_fail (SWFDEC_IS_AS_CONTEXT (context));
169 g_return_if_fail (n_elements < SWFDEC_AS_STACK_SIZE / 2);
171 if (G_LIKELY ((guint) (context->end - context->cur) >= n_elements))
172 return;
174 if (!swfdec_as_stack_push_segment (context))
175 context->cur = context->end - n_elements;
178 guint
179 swfdec_as_stack_get_size (SwfdecAsContext *context)
181 SwfdecAsStack *stack;
182 SwfdecAsValue *target;
183 guint ret;
185 g_return_val_if_fail (SWFDEC_IS_AS_CONTEXT (context), 0);
187 if (context->frame == NULL)
188 return 0;
189 target = context->frame->stack_begin;
190 if (target == context->base)
191 return context->cur - context->base;
192 stack = context->stack->next;
193 ret = context->cur - context->base;
194 while (target < &stack->elements[0] && target > &stack->elements[stack->used_elements]) {
195 ret += stack->n_elements;
196 stack = stack->next;
198 ret += &stack->elements[stack->used_elements] - target;
199 return ret;