jscript: Store bytecode_t in exec_ctx_t.
[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 "config.h"
20 #include "wine/port.h"
21
22 #include <math.h>
23 #include <assert.h>
24
25 #include "jscript.h"
26 #include "engine.h"
27
28 #include "wine/debug.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
31 WINE_DECLARE_DEBUG_CHANNEL(heap);
32
33 const char *debugstr_variant(const VARIANT *v)
34 {
35     if(!v)
36         return "(null)";
37
38     switch(V_VT(v)) {
39     case VT_EMPTY:
40         return "{VT_EMPTY}";
41     case VT_NULL:
42         return "{VT_NULL}";
43     case VT_I4:
44         return wine_dbg_sprintf("{VT_I4: %d}", V_I4(v));
45     case VT_UI4:
46         return wine_dbg_sprintf("{VT_UI4: %u}", V_UI4(v));
47     case VT_R8:
48         return wine_dbg_sprintf("{VT_R8: %lf}", V_R8(v));
49     case VT_BSTR:
50         return wine_dbg_sprintf("{VT_BSTR: %s}", debugstr_w(V_BSTR(v)));
51     case VT_DISPATCH:
52         return wine_dbg_sprintf("{VT_DISPATCH: %p}", V_DISPATCH(v));
53     case VT_BOOL:
54         return wine_dbg_sprintf("{VT_BOOL: %x}", V_BOOL(v));
55     default:
56         return wine_dbg_sprintf("{vt %d}", V_VT(v));
57     }
58 }
59
60 #define MIN_BLOCK_SIZE  128
61 #define ARENA_FREE_FILLER  0xaa
62
63 static inline DWORD block_size(DWORD block)
64 {
65     return MIN_BLOCK_SIZE << block;
66 }
67
68 void jsheap_init(jsheap_t *heap)
69 {
70     memset(heap, 0, sizeof(*heap));
71     list_init(&heap->custom_blocks);
72 }
73
74 void *jsheap_alloc(jsheap_t *heap, DWORD size)
75 {
76     struct list *list;
77     void *tmp;
78
79     if(!heap->block_cnt) {
80         if(!heap->blocks) {
81             heap->blocks = heap_alloc(sizeof(void*));
82             if(!heap->blocks)
83                 return NULL;
84         }
85
86         tmp = heap_alloc(block_size(0));
87         if(!tmp)
88             return NULL;
89
90         heap->blocks[0] = tmp;
91         heap->block_cnt = 1;
92     }
93
94     if(heap->offset + size <= block_size(heap->last_block)) {
95         tmp = ((BYTE*)heap->blocks[heap->last_block])+heap->offset;
96         heap->offset += size;
97         return tmp;
98     }
99
100     if(size <= block_size(heap->last_block+1)) {
101         if(heap->last_block+1 == heap->block_cnt) {
102             tmp = heap_realloc(heap->blocks, (heap->block_cnt+1)*sizeof(void*));
103             if(!tmp)
104                 return NULL;
105
106             heap->blocks = tmp;
107             heap->blocks[heap->block_cnt] = heap_alloc(block_size(heap->block_cnt));
108             if(!heap->blocks[heap->block_cnt])
109                 return NULL;
110
111             heap->block_cnt++;
112         }
113
114         heap->last_block++;
115         heap->offset = size;
116         return heap->blocks[heap->last_block];
117     }
118
119     list = heap_alloc(size + sizeof(struct list));
120     if(!list)
121         return NULL;
122
123     list_add_head(&heap->custom_blocks, list);
124     return list+1;
125 }
126
127 void *jsheap_grow(jsheap_t *heap, void *mem, DWORD size, DWORD inc)
128 {
129     if(mem == (BYTE*)heap->blocks[heap->last_block] + heap->offset-size
130        && heap->offset+inc < block_size(heap->last_block)) {
131         heap->offset += inc;
132         return mem;
133     }
134
135     return jsheap_alloc(heap, size+inc);
136 }
137
138 void jsheap_clear(jsheap_t *heap)
139 {
140     struct list *tmp;
141
142     if(!heap)
143         return;
144
145     while((tmp = list_next(&heap->custom_blocks, &heap->custom_blocks))) {
146         list_remove(tmp);
147         heap_free(tmp);
148     }
149
150     if(WARN_ON(heap)) {
151         DWORD i;
152
153         for(i=0; i < heap->block_cnt; i++)
154             memset(heap->blocks[i], ARENA_FREE_FILLER, block_size(i));
155     }
156
157     heap->last_block = heap->offset = 0;
158     heap->mark = FALSE;
159 }
160
161 void jsheap_free(jsheap_t *heap)
162 {
163     DWORD i;
164
165     jsheap_clear(heap);
166
167     for(i=0; i < heap->block_cnt; i++)
168         heap_free(heap->blocks[i]);
169     heap_free(heap->blocks);
170
171     jsheap_init(heap);
172 }
173
174 jsheap_t *jsheap_mark(jsheap_t *heap)
175 {
176     if(heap->mark)
177         return NULL;
178
179     heap->mark = TRUE;
180     return heap;
181 }
182
183 /* ECMA-262 3rd Edition    9.1 */
184 HRESULT to_primitive(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, VARIANT *ret, hint_t hint)
185 {
186     switch(V_VT(v)) {
187     case VT_EMPTY:
188     case VT_NULL:
189     case VT_BOOL:
190     case VT_I4:
191     case VT_R8:
192         *ret = *v;
193         break;
194     case VT_BSTR:
195         V_VT(ret) = VT_BSTR;
196         V_BSTR(ret) = SysAllocString(V_BSTR(v));
197         break;
198     case VT_DISPATCH: {
199         jsdisp_t *jsdisp;
200         DISPID id;
201         DISPPARAMS dp = {NULL, NULL, 0, 0};
202         HRESULT hres;
203
204         static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
205         static const WCHAR valueOfW[] = {'v','a','l','u','e','O','f',0};
206
207         if(!V_DISPATCH(v)) {
208             V_VT(ret) = VT_NULL;
209             break;
210         }
211
212         jsdisp = iface_to_jsdisp((IUnknown*)V_DISPATCH(v));
213         if(!jsdisp) {
214             V_VT(ret) = VT_EMPTY;
215             return disp_propget(ctx, V_DISPATCH(v), DISPID_VALUE, ret, ei);
216         }
217
218         if(hint == NO_HINT)
219             hint = is_class(jsdisp, JSCLASS_DATE) ? HINT_STRING : HINT_NUMBER;
220
221         /* Native implementation doesn't throw TypeErrors, returns strange values */
222
223         hres = jsdisp_get_id(jsdisp, hint == HINT_STRING ? toStringW : valueOfW, 0, &id);
224         if(SUCCEEDED(hres)) {
225             hres = jsdisp_call(jsdisp, id, DISPATCH_METHOD, &dp, ret, ei);
226             if(FAILED(hres)) {
227                 WARN("call error - forwarding exception\n");
228                 jsdisp_release(jsdisp);
229                 return hres;
230             }
231             else if(V_VT(ret) != VT_DISPATCH) {
232                 jsdisp_release(jsdisp);
233                 return S_OK;
234             }
235             else
236                 IDispatch_Release(V_DISPATCH(ret));
237         }
238
239         hres = jsdisp_get_id(jsdisp, hint == HINT_STRING ? valueOfW : toStringW, 0, &id);
240         if(SUCCEEDED(hres)) {
241             hres = jsdisp_call(jsdisp, id, DISPATCH_METHOD, &dp, ret, ei);
242             if(FAILED(hres)) {
243                 WARN("call error - forwarding exception\n");
244                 jsdisp_release(jsdisp);
245                 return hres;
246             }
247             else if(V_VT(ret) != VT_DISPATCH) {
248                 jsdisp_release(jsdisp);
249                 return S_OK;
250             }
251             else
252                 IDispatch_Release(V_DISPATCH(ret));
253         }
254
255         jsdisp_release(jsdisp);
256
257         WARN("failed\n");
258         return throw_type_error(ctx, ei, JS_E_TO_PRIMITIVE, NULL);
259     }
260     default:
261         FIXME("Unimplemented for vt %d\n", V_VT(v));
262         return E_NOTIMPL;
263     }
264
265     return S_OK;
266 }
267
268 /* ECMA-262 3rd Edition    9.2 */
269 HRESULT to_boolean(VARIANT *v, VARIANT_BOOL *b)
270 {
271     switch(V_VT(v)) {
272     case VT_EMPTY:
273     case VT_NULL:
274         *b = VARIANT_FALSE;
275         break;
276     case VT_I4:
277         *b = V_I4(v) ? VARIANT_TRUE : VARIANT_FALSE;
278         break;
279     case VT_R8:
280         if(isnan(V_R8(v))) *b = VARIANT_FALSE;
281         else *b = V_R8(v) ? VARIANT_TRUE : VARIANT_FALSE;
282         break;
283     case VT_BSTR:
284         *b = V_BSTR(v) && *V_BSTR(v) ? VARIANT_TRUE : VARIANT_FALSE;
285         break;
286     case VT_DISPATCH:
287         *b = V_DISPATCH(v) ? VARIANT_TRUE : VARIANT_FALSE;
288         break;
289     case VT_BOOL:
290         *b = V_BOOL(v);
291         break;
292     default:
293         FIXME("unimplemented for vt %d\n", V_VT(v));
294         return E_NOTIMPL;
295     }
296
297     return S_OK;
298 }
299
300 static int hex_to_int(WCHAR c)
301 {
302     if('0' <= c && c <= '9')
303         return c-'0';
304
305     if('a' <= c && c <= 'f')
306         return c-'a'+10;
307
308     if('A' <= c && c <= 'F')
309         return c-'A'+10;
310
311     return -1;
312 }
313
314 /* ECMA-262 3rd Edition    9.3.1 */
315 static HRESULT str_to_number(BSTR str, VARIANT *ret)
316 {
317     const WCHAR *ptr = str;
318     BOOL neg = FALSE;
319     DOUBLE d = 0.0;
320
321     static const WCHAR infinityW[] = {'I','n','f','i','n','i','t','y'};
322
323     while(isspaceW(*ptr))
324         ptr++;
325
326     if(*ptr == '-') {
327         neg = TRUE;
328         ptr++;
329     }else if(*ptr == '+') {
330         ptr++;
331     }
332
333     if(!strncmpW(ptr, infinityW, sizeof(infinityW)/sizeof(WCHAR))) {
334         ptr += sizeof(infinityW)/sizeof(WCHAR);
335         while(*ptr && isspaceW(*ptr))
336             ptr++;
337
338         if(*ptr)
339             num_set_nan(ret);
340         else
341             num_set_inf(ret, !neg);
342         return S_OK;
343     }
344
345     if(*ptr == '0' && ptr[1] == 'x') {
346         DWORD l = 0;
347
348         ptr += 2;
349         while((l = hex_to_int(*ptr)) != -1) {
350             d = d*16 + l;
351             ptr++;
352         }
353
354         num_set_val(ret, d);
355         return S_OK;
356     }
357
358     while(isdigitW(*ptr))
359         d = d*10 + (*ptr++ - '0');
360
361     if(*ptr == 'e' || *ptr == 'E') {
362         BOOL eneg = FALSE;
363         LONG l = 0;
364
365         ptr++;
366         if(*ptr == '-') {
367             ptr++;
368             eneg = TRUE;
369         }else if(*ptr == '+') {
370             ptr++;
371         }
372
373         while(isdigitW(*ptr))
374             l = l*10 + (*ptr++ - '0');
375         if(eneg)
376             l = -l;
377
378         d *= pow(10, l);
379     }else if(*ptr == '.') {
380         DOUBLE dec = 0.1;
381
382         ptr++;
383         while(isdigitW(*ptr)) {
384             d += dec * (*ptr++ - '0');
385             dec *= 0.1;
386         }
387     }
388
389     while(isspaceW(*ptr))
390         ptr++;
391
392     if(*ptr) {
393         num_set_nan(ret);
394         return S_OK;
395     }
396
397     if(neg)
398         d = -d;
399
400     num_set_val(ret, d);
401     return S_OK;
402 }
403
404 /* ECMA-262 3rd Edition    9.3 */
405 HRESULT to_number(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, VARIANT *ret)
406 {
407     switch(V_VT(v)) {
408     case VT_EMPTY:
409         num_set_nan(ret);
410         break;
411     case VT_NULL:
412         V_VT(ret) = VT_I4;
413         V_I4(ret) = 0;
414         break;
415     case VT_I4:
416     case VT_R8:
417         *ret = *v;
418         break;
419     case VT_BSTR:
420         return str_to_number(V_BSTR(v), ret);
421     case VT_DISPATCH: {
422         VARIANT prim;
423         HRESULT hres;
424
425         hres = to_primitive(ctx, v, ei, &prim, HINT_NUMBER);
426         if(FAILED(hres))
427             return hres;
428
429         hres = to_number(ctx, &prim, ei, ret);
430         VariantClear(&prim);
431         return hres;
432     }
433     case VT_BOOL:
434         V_VT(ret) = VT_I4;
435         V_I4(ret) = V_BOOL(v) ? 1 : 0;
436         break;
437     default:
438         FIXME("unimplemented for vt %d\n", V_VT(v));
439         return E_NOTIMPL;
440     }
441
442     return S_OK;
443 }
444
445 /* ECMA-262 3rd Edition    9.4 */
446 HRESULT to_integer(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, VARIANT *ret)
447 {
448     VARIANT num;
449     HRESULT hres;
450
451     hres = to_number(ctx, v, ei, &num);
452     if(FAILED(hres))
453         return hres;
454
455     if(V_VT(&num) == VT_I4) {
456         *ret = num;
457     }else if(isnan(V_R8(&num))) {
458         V_VT(ret) = VT_I4;
459         V_I4(ret) = 0;
460     }else {
461         num_set_val(ret, V_R8(&num) >= 0.0 ? floor(V_R8(&num)) : -floor(-V_R8(&num)));
462     }
463
464     return S_OK;
465 }
466
467 /* ECMA-262 3rd Edition    9.5 */
468 HRESULT to_int32(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, INT *ret)
469 {
470     VARIANT num;
471     HRESULT hres;
472
473     hres = to_number(ctx, v, ei, &num);
474     if(FAILED(hres))
475         return hres;
476
477     if(V_VT(&num) == VT_I4)
478         *ret = V_I4(&num);
479     else
480         *ret = isnan(V_R8(&num)) || isinf(V_R8(&num)) ? 0 : (INT)V_R8(&num);
481     return S_OK;
482 }
483
484 /* ECMA-262 3rd Edition    9.6 */
485 HRESULT to_uint32(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, DWORD *ret)
486 {
487     VARIANT num;
488     HRESULT hres;
489
490     hres = to_number(ctx, v, ei, &num);
491     if(FAILED(hres))
492         return hres;
493
494     if(V_VT(&num) == VT_I4)
495         *ret = V_I4(&num);
496     else
497         *ret = isnan(V_R8(&num)) || isinf(V_R8(&num)) ? 0 : (DWORD)V_R8(&num);
498     return S_OK;
499 }
500
501 BSTR int_to_bstr(int i)
502 {
503     WCHAR buf[12], *p;
504     BOOL neg = FALSE;
505
506     if(!i) {
507         static const WCHAR zeroW[] = {'0',0};
508         return SysAllocString(zeroW);
509     }
510
511     if(i < 0) {
512         neg = TRUE;
513         i = -i;
514     }
515
516     p = buf + sizeof(buf)/sizeof(*buf)-1;
517     *p-- = 0;
518     while(i) {
519         *p-- = i%10 + '0';
520         i /= 10;
521     }
522
523     if(neg)
524         *p = '-';
525     else
526         p++;
527
528     return SysAllocString(p);
529 }
530
531 HRESULT double_to_bstr(double n, BSTR *str)
532 {
533     const WCHAR NaNW[] = {'N','a','N',0};
534     const WCHAR InfinityW[] = {'-','I','n','f','i','n','i','t','y',0};
535
536     if(isnan(n)) {
537        *str = SysAllocString(NaNW);
538     }else if(isinf(n)) {
539         *str = SysAllocString(n<0 ? InfinityW : InfinityW+1);
540     }else {
541         VARIANT strv, v;
542         HRESULT hres;
543
544         V_VT(&v) = VT_R8;
545         V_R8(&v) = n;
546         V_VT(&strv) = VT_EMPTY;
547         hres = VariantChangeTypeEx(&strv, &v, MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT), 0, VT_BSTR);
548         if(FAILED(hres))
549             return hres;
550
551         *str = V_BSTR(&strv);
552     }
553
554     return *str ? S_OK : E_OUTOFMEMORY;
555 }
556
557 /* ECMA-262 3rd Edition    9.8 */
558 HRESULT to_string(script_ctx_t *ctx, VARIANT *v, jsexcept_t *ei, BSTR *str)
559 {
560     const WCHAR undefinedW[] = {'u','n','d','e','f','i','n','e','d',0};
561     const WCHAR nullW[] = {'n','u','l','l',0};
562     const WCHAR trueW[] = {'t','r','u','e',0};
563     const WCHAR falseW[] = {'f','a','l','s','e',0};
564
565     switch(V_VT(v)) {
566     case VT_EMPTY:
567         *str = SysAllocString(undefinedW);
568         break;
569     case VT_NULL:
570         *str = SysAllocString(nullW);
571         break;
572     case VT_I4:
573         *str = int_to_bstr(V_I4(v));
574         break;
575     case VT_R8:
576         return double_to_bstr(V_R8(v), str);
577     case VT_BSTR:
578         *str = SysAllocString(V_BSTR(v));
579         break;
580     case VT_DISPATCH: {
581         VARIANT prim;
582         HRESULT hres;
583
584         hres = to_primitive(ctx, v, ei, &prim, HINT_STRING);
585         if(FAILED(hres))
586             return hres;
587
588         hres = to_string(ctx, &prim, ei, str);
589         VariantClear(&prim);
590         return hres;
591     }
592     case VT_BOOL:
593         *str = SysAllocString(V_BOOL(v) ? trueW : falseW);
594         break;
595     default:
596         FIXME("unsupported vt %d\n", V_VT(v));
597         return E_NOTIMPL;
598     }
599
600     return *str ? S_OK : E_OUTOFMEMORY;
601 }
602
603 /* ECMA-262 3rd Edition    9.9 */
604 HRESULT to_object(script_ctx_t *ctx, VARIANT *v, IDispatch **disp)
605 {
606     jsdisp_t *dispex;
607     HRESULT hres;
608
609     switch(V_VT(v)) {
610     case VT_BSTR:
611         hres = create_string(ctx, V_BSTR(v), SysStringLen(V_BSTR(v)), &dispex);
612         if(FAILED(hres))
613             return hres;
614
615         *disp = to_disp(dispex);
616         break;
617     case VT_I4:
618     case VT_R8:
619         hres = create_number(ctx, v, &dispex);
620         if(FAILED(hres))
621             return hres;
622
623         *disp = to_disp(dispex);
624         break;
625     case VT_DISPATCH:
626         if(V_DISPATCH(v)) {
627             IDispatch_AddRef(V_DISPATCH(v));
628             *disp = V_DISPATCH(v);
629         }else {
630             jsdisp_t *obj;
631
632             hres = create_object(ctx, NULL, &obj);
633             if(FAILED(hres))
634                 return hres;
635
636             *disp = to_disp(obj);
637         }
638         break;
639     case VT_BOOL:
640         hres = create_bool(ctx, V_BOOL(v), &dispex);
641         if(FAILED(hres))
642             return hres;
643
644         *disp = to_disp(dispex);
645         break;
646     case VT_ARRAY|VT_VARIANT:
647         hres = create_vbarray(ctx, V_ARRAY(v), &dispex);
648         if(FAILED(hres))
649             return hres;
650
651         *disp = to_disp(dispex);
652         break;
653     default:
654         FIXME("unsupported vt %d\n", V_VT(v));
655         return E_NOTIMPL;
656     }
657
658     return S_OK;
659 }
660
661 HRESULT variant_change_type(script_ctx_t *ctx, VARIANT *dst, VARIANT *src, VARTYPE vt)
662 {
663     jsexcept_t ei;
664     HRESULT hres;
665
666     memset(&ei, 0, sizeof(ei));
667
668     switch(vt) {
669     case VT_I2:
670     case VT_I4: {
671         INT i;
672
673         hres = to_int32(ctx, src, &ei, &i);
674         if(SUCCEEDED(hres)) {
675             if(vt == VT_I4)
676                 V_I4(dst) = i;
677             else
678                 V_I2(dst) = i;
679         }
680         break;
681     }
682     case VT_R8:
683         hres = to_number(ctx, src, &ei, dst);
684         if(SUCCEEDED(hres) && V_VT(dst) == VT_I4)
685             V_R8(dst) = V_I4(dst);
686         break;
687     case VT_R4: {
688         VARIANT n;
689
690         hres = to_number(ctx, src, &ei, &n);
691         if(SUCCEEDED(hres))
692             V_R4(dst) = num_val(&n);
693         break;
694     }
695     case VT_BOOL: {
696         VARIANT_BOOL b;
697
698         hres = to_boolean(src, &b);
699         if(SUCCEEDED(hres))
700             V_BOOL(dst) = b;
701         break;
702     }
703     case VT_BSTR: {
704         BSTR str;
705
706         hres = to_string(ctx, src, &ei, &str);
707         if(SUCCEEDED(hres))
708             V_BSTR(dst) = str;
709         break;
710     }
711     case VT_EMPTY:
712         hres = V_VT(src) == VT_EMPTY ? S_OK : E_NOTIMPL;
713         break;
714     case VT_NULL:
715         hres = V_VT(src) == VT_NULL ? S_OK : E_NOTIMPL;
716         break;
717     default:
718         FIXME("vt %d not implemented\n", vt);
719         hres = E_NOTIMPL;
720     }
721
722     if(FAILED(hres)) {
723         VariantClear(&ei.var);
724         return hres;
725     }
726
727     V_VT(dst) = vt;
728     return S_OK;
729 }
730
731 static inline JSCaller *impl_from_IServiceProvider(IServiceProvider *iface)
732 {
733     return CONTAINING_RECORD(iface, JSCaller, IServiceProvider_iface);
734 }
735
736 static HRESULT WINAPI JSCaller_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv)
737 {
738     JSCaller *This = impl_from_IServiceProvider(iface);
739
740     if(IsEqualGUID(&IID_IUnknown, riid)) {
741         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
742         *ppv = &This->IServiceProvider_iface;
743     }else if(IsEqualGUID(&IID_IServiceProvider, riid)) {
744         TRACE("(%p)->(IID_IServiceProvider %p)\n", This, ppv);
745         *ppv = &This->IServiceProvider_iface;
746     }else {
747         WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
748         *ppv = NULL;
749         return E_NOINTERFACE;
750     }
751
752     IUnknown_AddRef((IUnknown*)*ppv);
753     return S_OK;
754 }
755
756 static ULONG WINAPI JSCaller_AddRef(IServiceProvider *iface)
757 {
758     JSCaller *This = impl_from_IServiceProvider(iface);
759     LONG ref = InterlockedIncrement(&This->ref);
760
761     TRACE("(%p) ref=%d\n", This, ref);
762
763     return ref;
764 }
765
766 static ULONG WINAPI JSCaller_Release(IServiceProvider *iface)
767 {
768     JSCaller *This = impl_from_IServiceProvider(iface);
769     LONG ref = InterlockedIncrement(&This->ref);
770
771     TRACE("(%p) ref=%d\n", This, ref);
772
773     if(!ref) {
774         assert(!This->ctx);
775         heap_free(This);
776     }
777
778     return ref;
779 }
780
781 static HRESULT WINAPI JSCaller_QueryService(IServiceProvider *iface, REFGUID guidService,
782         REFIID riid, void **ppv)
783 {
784     JSCaller *This = impl_from_IServiceProvider(iface);
785
786     if(IsEqualGUID(guidService, &SID_VariantConversion) && This->ctx && This->ctx->active_script) {
787         TRACE("(%p)->(SID_VariantConversion)\n", This);
788         return IActiveScript_QueryInterface(This->ctx->active_script, riid, ppv);
789     }
790
791     FIXME("(%p)->(%s %s %p)\n", This, debugstr_guid(guidService), debugstr_guid(riid), ppv);
792
793     *ppv = NULL;
794     return E_NOINTERFACE;
795 }
796
797 static const IServiceProviderVtbl ServiceProviderVtbl = {
798     JSCaller_QueryInterface,
799     JSCaller_AddRef,
800     JSCaller_Release,
801     JSCaller_QueryService
802 };
803
804 HRESULT create_jscaller(script_ctx_t *ctx)
805 {
806     JSCaller *ret;
807
808     ret = heap_alloc(sizeof(*ret));
809     if(!ret)
810         return E_OUTOFMEMORY;
811
812     ret->IServiceProvider_iface.lpVtbl = &ServiceProviderVtbl;
813     ret->ref = 1;
814     ret->ctx = ctx;
815
816     ctx->jscaller = ret;
817     return S_OK;
818 }