jscript: Reuse temporary heap.
[wine] / dlls / jscript / jsutils.c
1 /*
2  * Copyright 2008 Jacek Caban for CodeWeavers
3  *
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.
13  *
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 St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include "jscript.h"
20
21 #include "wine/debug.h"
22
23 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
24
25 const char *debugstr_variant(const VARIANT *v)
26 {
27     switch(V_VT(v)) {
28     case VT_EMPTY:
29         return wine_dbg_sprintf("{VT_EMPTY}");
30     case VT_NULL:
31         return wine_dbg_sprintf("{VT_NULL}");
32     case VT_I4:
33         return wine_dbg_sprintf("{VT_I4: %d}", V_I4(v));
34     case VT_R8:
35         return wine_dbg_sprintf("{VT_R8: %lf}", V_R8(v));
36     case VT_BSTR:
37         return wine_dbg_sprintf("{VT_BSTR: %s}", debugstr_w(V_BSTR(v)));
38     case VT_DISPATCH:
39         return wine_dbg_sprintf("{VT_DISPATCH: %p}", V_DISPATCH(v));
40     case VT_BOOL:
41         return wine_dbg_sprintf("{VT_BOOL: %x}", V_BOOL(v));
42     default:
43         return wine_dbg_sprintf("{vt %d}", V_VT(v));
44     }
45 }
46
47 #define MIN_BLOCK_SIZE  128
48
49 static inline DWORD block_size(DWORD block)
50 {
51     return MIN_BLOCK_SIZE << block;
52 }
53
54 void jsheap_init(jsheap_t *heap)
55 {
56     memset(heap, 0, sizeof(*heap));
57     list_init(&heap->custom_blocks);
58 }
59
60 void *jsheap_alloc(jsheap_t *heap, DWORD size)
61 {
62     struct list *list;
63     void *tmp;
64
65     if(!heap->block_cnt) {
66         if(!heap->blocks) {
67             heap->blocks = heap_alloc(sizeof(void*));
68             if(!heap->blocks)
69                 return NULL;
70         }
71
72         tmp = heap_alloc(block_size(0));
73         if(!tmp)
74             return NULL;
75
76         heap->blocks[0] = tmp;
77         heap->block_cnt = 1;
78     }
79
80     if(heap->offset + size < block_size(heap->last_block)) {
81         tmp = ((BYTE*)heap->blocks[heap->last_block])+heap->offset;
82         heap->offset += size;
83         return tmp;
84     }
85
86     if(size < block_size(heap->last_block+1)) {
87         if(heap->last_block+1 == heap->block_cnt) {
88             tmp = heap_realloc(heap->blocks, (heap->block_cnt+1)*sizeof(void*));
89             if(!tmp)
90                 return NULL;
91             heap->blocks = tmp;
92         }
93
94         tmp = heap_alloc(block_size(heap->block_cnt+1));
95         if(!tmp)
96             return NULL;
97
98         heap->blocks[heap->block_cnt++] = tmp;
99
100         heap->last_block++;
101         heap->offset = size;
102         return heap->blocks[heap->last_block];
103     }
104
105     list = heap_alloc(size + sizeof(struct list));
106     if(!list)
107         return NULL;
108
109     list_add_head(&heap->custom_blocks, list);
110     return list+1;
111 }
112
113 void *jsheap_grow(jsheap_t *heap, void *mem, DWORD size, DWORD inc)
114 {
115     if(mem == (BYTE*)heap->blocks[heap->last_block] + heap->offset-size
116        && heap->offset+inc < block_size(heap->last_block)) {
117         heap->offset += inc;
118         return mem;
119     }
120
121     return jsheap_alloc(heap, size+inc);
122 }
123
124 void jsheap_clear(jsheap_t *heap)
125 {
126     struct list *tmp;
127
128     if(!heap)
129         return;
130
131     while((tmp = list_next(&heap->custom_blocks, &heap->custom_blocks))) {
132         list_remove(tmp);
133         heap_free(tmp);
134     }
135
136     heap->last_block = heap->offset = 0;
137 }
138
139 void jsheap_free(jsheap_t *heap)
140 {
141     DWORD i;
142
143     jsheap_clear(heap);
144
145     for(i=0; i < heap->block_cnt; i++)
146         heap_free(heap->blocks[i]);
147     heap_free(heap->blocks);
148
149     jsheap_init(heap);
150 }
151
152 jsheap_t *jsheap_mark(jsheap_t *heap)
153 {
154     if(heap->mark)
155         return NULL;
156
157     heap->mark = TRUE;
158     return heap;
159 }
160
161 /* ECMA-262 3rd Edition    9.1 */
162 HRESULT to_primitive(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, VARIANT *ret)
163 {
164     switch(V_VT(v)) {
165     case VT_EMPTY:
166     case VT_NULL:
167     case VT_BOOL:
168     case VT_I4:
169     case VT_R8:
170         *ret = *v;
171         break;
172     case VT_BSTR:
173         V_VT(ret) = VT_BSTR;
174         V_BSTR(ret) = SysAllocString(V_BSTR(v));
175         break;
176     case VT_DISPATCH:
177         return disp_propget(V_DISPATCH(v), DISPID_VALUE, ctx->lcid, ret, ei, NULL /*FIXME*/);
178     default:
179         FIXME("Unimplemented for vt %d\n", V_VT(v));
180         return E_NOTIMPL;
181     }
182
183     return S_OK;
184 }
185
186 /* ECMA-262 3rd Edition    9.2 */
187 HRESULT to_boolean(VARIANT *v, VARIANT_BOOL *b)
188 {
189     switch(V_VT(v)) {
190     case VT_EMPTY:
191     case VT_NULL:
192         *b = VARIANT_FALSE;
193         break;
194     case VT_I4:
195         *b = V_I4(v) ? VARIANT_TRUE : VARIANT_FALSE;
196         break;
197     case VT_R8:
198         *b = V_R8(v) ? VARIANT_TRUE : VARIANT_FALSE;
199         break;
200     case VT_BSTR:
201         *b = V_BSTR(v) && *V_BSTR(v) ? VARIANT_TRUE : VARIANT_FALSE;
202         break;
203     case VT_DISPATCH:
204         *b = V_DISPATCH(v) ? VARIANT_TRUE : VARIANT_FALSE;
205         break;
206     case VT_BOOL:
207         *b = V_BOOL(v);
208         break;
209     default:
210         FIXME("unimplemented for vt %d\n", V_VT(v));
211         return E_NOTIMPL;
212     }
213
214     return S_OK;
215 }
216
217 /* ECMA-262 3rd Edition    9.3 */
218 HRESULT to_number(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, VARIANT *ret)
219 {
220     switch(V_VT(v)) {
221     case VT_I4:
222     case VT_R8:
223         *ret = *v;
224         break;
225     default:
226         FIXME("unimplemented for vt %d\n", V_VT(v));
227         return E_NOTIMPL;
228     }
229
230     return S_OK;
231 }
232
233 /* ECMA-262 3rd Edition    9.8 */
234 HRESULT to_string(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, BSTR *str)
235 {
236     switch(V_VT(v)) {
237     case VT_BSTR:
238         *str = SysAllocString(V_BSTR(v));
239         return S_OK;
240
241     default:
242         FIXME("unsupported vt %d\n", V_VT(v));
243     }
244
245     return E_NOTIMPL;
246 }
247
248 /* ECMA-262 3rd Edition    9.9 */
249 HRESULT to_object(exec_ctx_t *ctx, VARIANT *v, IDispatch **disp)
250 {
251     switch(V_VT(v)) {
252     case VT_DISPATCH:
253         IDispatch_AddRef(V_DISPATCH(v));
254         *disp = V_DISPATCH(v);
255         break;
256     default:
257         FIXME("unsupported vt %d\n", V_VT(v));
258         return E_NOTIMPL;
259     }
260
261     return S_OK;
262 }