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