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