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