vbscript: Added support for sub local variables.
[wine] / dlls / vbscript / interp.c
1 /*
2  * Copyright 2011 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 <assert.h>
20
21 #include "vbscript.h"
22
23 #include "wine/debug.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(vbscript);
26
27
28 typedef struct {
29     vbscode_t *code;
30     instr_t *instr;
31     script_ctx_t *script;
32     function_t *func;
33
34     VARIANT *args;
35     VARIANT *vars;
36
37     unsigned stack_size;
38     unsigned top;
39     VARIANT *stack;
40 } exec_ctx_t;
41
42 typedef HRESULT (*instr_func_t)(exec_ctx_t*);
43
44 typedef enum {
45     REF_NONE,
46     REF_DISP,
47     REF_VAR,
48     REF_FUNC
49 } ref_type_t;
50
51 typedef struct {
52     ref_type_t type;
53     union {
54         struct {
55             IDispatch *disp;
56             DISPID id;
57         } d;
58         VARIANT *v;
59         function_t *f;
60     } u;
61 } ref_t;
62
63 typedef struct {
64     VARIANT *v;
65     VARIANT store;
66     BOOL owned;
67 } variant_val_t;
68
69 static BOOL lookup_dynamic_vars(dynamic_var_t *var, const WCHAR *name, ref_t *ref)
70 {
71     while(var) {
72         if(!strcmpiW(var->name, name)) {
73             ref->type = REF_VAR;
74             ref->u.v = &var->v;
75             return TRUE;
76         }
77
78         var = var->next;
79     }
80
81     return FALSE;
82 }
83
84 static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, ref_t *ref)
85 {
86     named_item_t *item;
87     function_t *func;
88     unsigned i;
89     DISPID id;
90     HRESULT hres;
91
92     for(i=0; i < ctx->func->var_cnt; i++) {
93         if(!strcmpiW(ctx->func->vars[i].name, name)) {
94             ref->type = REF_VAR;
95             ref->u.v = ctx->vars+i;
96             return TRUE;
97         }
98     }
99
100     for(i=0; i < ctx->func->arg_cnt; i++) {
101         if(!strcmpiW(ctx->func->args[i].name, name)) {
102             ref->type = REF_VAR;
103             ref->u.v = ctx->args+i;
104             return S_OK;
105         }
106     }
107
108     if(lookup_dynamic_vars(ctx->script->global_vars, name, ref))
109         return S_OK;
110
111     for(func = ctx->script->global_funcs; func; func = func->next) {
112         if(!strcmpiW(func->name, name)) {
113             ref->type = REF_FUNC;
114             ref->u.f = func;
115             return S_OK;
116         }
117     }
118
119     LIST_FOR_EACH_ENTRY(item, &ctx->script->named_items, named_item_t, entry) {
120         if(item->flags & SCRIPTITEM_GLOBALMEMBERS) {
121             hres = disp_get_id(item->disp, name, &id);
122             if(SUCCEEDED(hres)) {
123                 ref->type = REF_DISP;
124                 ref->u.d.disp = item->disp;
125                 ref->u.d.id = id;
126                 return S_OK;
127             }
128         }
129     }
130
131     if(!ctx->func->code_ctx->option_explicit)
132         FIXME("create an attempt to set\n");
133
134     ref->type = REF_NONE;
135     return S_OK;
136 }
137
138 static inline VARIANT *stack_pop(exec_ctx_t *ctx)
139 {
140     assert(ctx->top);
141     return ctx->stack + --ctx->top;
142 }
143
144 static HRESULT stack_push(exec_ctx_t *ctx, VARIANT *v)
145 {
146     if(ctx->stack_size == ctx->top) {
147         VARIANT *new_stack;
148
149         new_stack = heap_realloc(ctx->stack, ctx->stack_size*2);
150         if(!new_stack) {
151             VariantClear(v);
152             return E_OUTOFMEMORY;
153         }
154
155         ctx->stack = new_stack;
156         ctx->stack_size *= 2;
157     }
158
159     ctx->stack[ctx->top++] = *v;
160     return S_OK;
161 }
162
163 static void stack_popn(exec_ctx_t *ctx, unsigned n)
164 {
165     while(n--)
166         VariantClear(stack_pop(ctx));
167 }
168
169 static HRESULT stack_pop_val(exec_ctx_t *ctx, variant_val_t *v)
170 {
171     VARIANT *var;
172
173     var = stack_pop(ctx);
174
175     if(V_VT(var) == (VT_BYREF|VT_VARIANT)) {
176         v->owned = FALSE;
177         var = V_VARIANTREF(var);
178     }else {
179         v->owned = TRUE;
180     }
181
182     if(V_VT(var) == VT_DISPATCH) {
183         FIXME("got dispatch - get its default value\n");
184         return E_NOTIMPL;
185     }else {
186         v->v = var;
187     }
188
189     return S_OK;
190 }
191
192 static inline void release_val(variant_val_t *v)
193 {
194     if(v->owned)
195         VariantClear(v->v);
196 }
197
198 static HRESULT stack_pop_disp(exec_ctx_t *ctx, IDispatch **ret)
199 {
200     VARIANT *v = stack_pop(ctx);
201
202     if(V_VT(v) == VT_DISPATCH) {
203         *ret = V_DISPATCH(v);
204         return S_OK;
205     }
206
207     if(V_VT(v) != (VT_VARIANT|VT_BYREF)) {
208         FIXME("not supported type: %s\n", debugstr_variant(v));
209         VariantClear(v);
210         return E_FAIL;
211     }
212
213     v = V_BYREF(v);
214     if(V_VT(v) != VT_DISPATCH) {
215         FIXME("not disp %s\n", debugstr_variant(v));
216         return E_FAIL;
217     }
218
219     if(V_DISPATCH(v))
220         IDispatch_AddRef(V_DISPATCH(v));
221     *ret = V_DISPATCH(v);
222     return S_OK;
223 }
224
225 static inline void instr_jmp(exec_ctx_t *ctx, unsigned addr)
226 {
227     ctx->instr = ctx->code->instrs + addr;
228 }
229
230 static void vbstack_to_dp(exec_ctx_t *ctx, unsigned arg_cnt, DISPPARAMS *dp)
231 {
232     dp->cArgs = arg_cnt;
233     dp->rgdispidNamedArgs = NULL;
234     dp->cNamedArgs = 0;
235
236     if(arg_cnt) {
237         VARIANT tmp;
238         unsigned i;
239
240         assert(ctx->top >= arg_cnt);
241
242         for(i=1; i*2 <= arg_cnt; i++) {
243             tmp = ctx->stack[ctx->top-i];
244             ctx->stack[ctx->top-i] = ctx->stack[ctx->top-arg_cnt+i-1];
245             ctx->stack[ctx->top-arg_cnt+i-1] = tmp;
246         }
247
248         dp->rgvarg = ctx->stack + ctx->top-arg_cnt;
249     }else {
250         dp->rgvarg = NULL;
251     }
252 }
253
254 static HRESULT do_icall(exec_ctx_t *ctx, VARIANT *res)
255 {
256     BSTR identifier = ctx->instr->arg1.bstr;
257     const unsigned arg_cnt = ctx->instr->arg2.uint;
258     ref_t ref = {0};
259     DISPPARAMS dp;
260     HRESULT hres;
261
262     hres = lookup_identifier(ctx, identifier, &ref);
263     if(FAILED(hres))
264         return hres;
265
266     vbstack_to_dp(ctx, arg_cnt, &dp);
267
268     switch(ref.type) {
269     case REF_VAR:
270         if(!res) {
271             FIXME("REF_VAR no res\n");
272             return E_NOTIMPL;
273         }
274
275         if(arg_cnt) {
276             FIXME("arguments not implemented\n");
277             return E_NOTIMPL;
278         }
279
280         V_VT(res) = VT_BYREF|VT_VARIANT;
281         V_BYREF(res) = V_VT(ref.u.v) == (VT_VARIANT|VT_BYREF) ? V_VARIANTREF(ref.u.v) : ref.u.v;
282         break;
283     case REF_DISP:
284         hres = disp_call(ctx->script, ref.u.d.disp, ref.u.d.id, &dp, res);
285         if(FAILED(hres))
286             return hres;
287         break;
288     case REF_FUNC:
289         hres = exec_script(ctx->script, ref.u.f, &dp, res);
290         if(FAILED(hres))
291             return hres;
292         break;
293     case REF_NONE:
294         FIXME("%s not found\n", debugstr_w(identifier));
295         return DISP_E_UNKNOWNNAME;
296     }
297
298     stack_popn(ctx, arg_cnt);
299     return S_OK;
300 }
301
302 static HRESULT interp_icall(exec_ctx_t *ctx)
303 {
304     VARIANT v;
305     HRESULT hres;
306
307     TRACE("\n");
308
309     hres = do_icall(ctx, &v);
310     if(FAILED(hres))
311         return hres;
312
313     return stack_push(ctx, &v);
314 }
315
316 static HRESULT interp_icallv(exec_ctx_t *ctx)
317 {
318     TRACE("\n");
319     return do_icall(ctx, NULL);
320 }
321
322 static HRESULT assign_ident(exec_ctx_t *ctx, BSTR name, VARIANT *val, BOOL own_val)
323 {
324     ref_t ref;
325     HRESULT hres;
326
327     hres = lookup_identifier(ctx, name, &ref);
328     if(FAILED(hres))
329         return hres;
330
331     switch(ref.type) {
332     case REF_VAR: {
333         VARIANT *v = ref.u.v;
334
335         if(V_VT(v) == (VT_VARIANT|VT_BYREF))
336             v = V_VARIANTREF(v);
337
338         if(own_val) {
339             VariantClear(v);
340             *v = *val;
341             hres = S_OK;
342         }else {
343             hres = VariantCopy(v, val);
344         }
345         break;
346     }
347     case REF_DISP:
348         hres = disp_propput(ctx->script, ref.u.d.disp, ref.u.d.id, val);
349         if(own_val)
350             VariantClear(val);
351         break;
352     case REF_FUNC:
353         FIXME("functions not implemented\n");
354         return E_NOTIMPL;
355     case REF_NONE:
356         FIXME("%s not found\n", debugstr_w(name));
357         if(own_val)
358             VariantClear(val);
359         return DISP_E_UNKNOWNNAME;
360     }
361
362     return hres;
363 }
364
365 static HRESULT interp_assign_ident(exec_ctx_t *ctx)
366 {
367     const BSTR arg = ctx->instr->arg1.bstr;
368     variant_val_t v;
369     HRESULT hres;
370
371     TRACE("%s\n", debugstr_w(arg));
372
373     hres = stack_pop_val(ctx, &v);
374     if(FAILED(hres))
375         return hres;
376
377     return assign_ident(ctx, arg, v.v, v.owned);
378 }
379
380 static HRESULT interp_assign_member(exec_ctx_t *ctx)
381 {
382     BSTR identifier = ctx->instr->arg1.bstr;
383     variant_val_t val;
384     IDispatch *obj;
385     DISPID id;
386     HRESULT hres;
387
388     TRACE("%s\n", debugstr_w(identifier));
389
390     hres = stack_pop_disp(ctx, &obj);
391     if(FAILED(hres))
392         return hres;
393
394     if(!obj) {
395         FIXME("NULL obj\n");
396         return E_FAIL;
397     }
398
399     hres = stack_pop_val(ctx, &val);
400     if(FAILED(hres)) {
401         IDispatch_Release(obj);
402         return hres;
403     }
404
405     hres = disp_get_id(obj, identifier, &id);
406     if(SUCCEEDED(hres))
407         hres = disp_propput(ctx->script, obj, id, val.v);
408
409     release_val(&val);
410     IDispatch_Release(obj);
411     return hres;
412 }
413
414 static HRESULT interp_jmp(exec_ctx_t *ctx)
415 {
416     const unsigned arg = ctx->instr->arg1.uint;
417
418     TRACE("%u\n", arg);
419
420     instr_jmp(ctx, arg);
421     return S_OK;
422 }
423
424 static HRESULT interp_jmp_false(exec_ctx_t *ctx)
425 {
426     const unsigned arg = ctx->instr->arg1.uint;
427     variant_val_t val;
428     HRESULT hres;
429
430     TRACE("%u\n", arg);
431
432     hres = stack_pop_val(ctx, &val);
433     if(FAILED(hres))
434         return hres;
435
436     if(V_VT(val.v) != VT_BOOL) {
437         FIXME("unsupported for %s\n", debugstr_variant(val.v));
438         release_val(&val);
439         return E_NOTIMPL;
440     }
441
442     if(V_BOOL(val.v))
443         ctx->instr++;
444     else
445         instr_jmp(ctx, ctx->instr->arg1.uint);
446     return S_OK;
447 }
448
449 static HRESULT interp_ret(exec_ctx_t *ctx)
450 {
451     TRACE("\n");
452
453     ctx->instr = NULL;
454     return S_OK;
455 }
456
457 static HRESULT interp_bool(exec_ctx_t *ctx)
458 {
459     const VARIANT_BOOL arg = ctx->instr->arg1.lng;
460     VARIANT v;
461
462     TRACE("%s\n", arg ? "true" : "false");
463
464     V_VT(&v) = VT_BOOL;
465     V_BOOL(&v) = arg;
466     return stack_push(ctx, &v);
467 }
468
469 static HRESULT interp_string(exec_ctx_t *ctx)
470 {
471     VARIANT v;
472
473     TRACE("\n");
474
475     V_VT(&v) = VT_BSTR;
476     V_BSTR(&v) = SysAllocString(ctx->instr->arg1.str);
477     if(!V_BSTR(&v))
478         return E_OUTOFMEMORY;
479
480     return stack_push(ctx, &v);
481 }
482
483 static HRESULT interp_long(exec_ctx_t *ctx)
484 {
485     const LONG arg = ctx->instr->arg1.lng;
486     VARIANT v;
487
488     TRACE("%d\n", arg);
489
490     V_VT(&v) = VT_I4;
491     V_I4(&v) = arg;
492     return stack_push(ctx, &v);
493 }
494
495 static HRESULT interp_short(exec_ctx_t *ctx)
496 {
497     const LONG arg = ctx->instr->arg1.lng;
498     VARIANT v;
499
500     TRACE("%d\n", arg);
501
502     V_VT(&v) = VT_I2;
503     V_I2(&v) = arg;
504     return stack_push(ctx, &v);
505 }
506
507 static HRESULT interp_double(exec_ctx_t *ctx)
508 {
509     const DOUBLE *arg = ctx->instr->arg1.dbl;
510     VARIANT v;
511
512     TRACE("%lf\n", *arg);
513
514     V_VT(&v) = VT_R8;
515     V_R8(&v) = *arg;
516     return stack_push(ctx, &v);
517 }
518
519 static HRESULT interp_empty(exec_ctx_t *ctx)
520 {
521     VARIANT v;
522
523     TRACE("\n");
524
525     V_VT(&v) = VT_EMPTY;
526     return stack_push(ctx, &v);
527 }
528
529 static HRESULT interp_null(exec_ctx_t *ctx)
530 {
531     VARIANT v;
532
533     TRACE("\n");
534
535     V_VT(&v) = VT_NULL;
536     return stack_push(ctx, &v);
537 }
538
539 static HRESULT interp_not(exec_ctx_t *ctx)
540 {
541     variant_val_t val;
542     VARIANT v;
543     HRESULT hres;
544
545     TRACE("\n");
546
547     hres = stack_pop_val(ctx, &val);
548     if(FAILED(hres))
549         return hres;
550
551     hres = VarNot(val.v, &v);
552     release_val(&val);
553     if(FAILED(hres))
554         return hres;
555
556     return stack_push(ctx, &v);
557 }
558
559 static HRESULT cmp_oper(exec_ctx_t *ctx)
560 {
561     variant_val_t l, r;
562     HRESULT hres;
563
564     hres = stack_pop_val(ctx, &r);
565     if(FAILED(hres))
566         return hres;
567
568     hres = stack_pop_val(ctx, &l);
569     if(SUCCEEDED(hres)) {
570         if(V_VT(l.v) == VT_NULL || V_VT(r.v) == VT_NULL) {
571             FIXME("comparing nulls is not implemented\n");
572             hres = E_NOTIMPL;
573         }else {
574             hres = VarCmp(l.v, r.v, ctx->script->lcid, 0);
575         }
576     }
577
578     release_val(&r);
579     release_val(&l);
580     return hres;
581 }
582
583 static HRESULT interp_equal(exec_ctx_t *ctx)
584 {
585     VARIANT v;
586     HRESULT hres;
587
588     TRACE("\n");
589
590     hres = cmp_oper(ctx);
591     if(FAILED(hres))
592         return hres;
593
594     V_VT(&v) = VT_BOOL;
595     V_BOOL(&v) = hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
596     return stack_push(ctx, &v);
597 }
598
599 static HRESULT interp_nequal(exec_ctx_t *ctx)
600 {
601     VARIANT v;
602     HRESULT hres;
603
604     TRACE("\n");
605
606     hres = cmp_oper(ctx);
607     if(FAILED(hres))
608         return hres;
609
610     V_VT(&v) = VT_BOOL;
611     V_BOOL(&v) = hres != VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
612     return stack_push(ctx, &v);
613 }
614
615 static HRESULT interp_concat(exec_ctx_t *ctx)
616 {
617     variant_val_t r, l;
618     VARIANT v;
619     HRESULT hres;
620
621     TRACE("\n");
622
623     hres = stack_pop_val(ctx, &r);
624     if(FAILED(hres))
625         return hres;
626
627     hres = stack_pop_val(ctx, &l);
628     if(SUCCEEDED(hres)) {
629         hres = VarCat(l.v, r.v, &v);
630         release_val(&l);
631     }
632     release_val(&r);
633     if(FAILED(hres))
634         return hres;
635
636     return stack_push(ctx, &v);
637 }
638
639 static HRESULT interp_add(exec_ctx_t *ctx)
640 {
641     variant_val_t r, l;
642     VARIANT v;
643     HRESULT hres;
644
645     TRACE("\n");
646
647     hres = stack_pop_val(ctx, &r);
648     if(FAILED(hres))
649         return hres;
650
651     hres = stack_pop_val(ctx, &l);
652     if(SUCCEEDED(hres)) {
653         hres = VarAdd(l.v, r.v, &v);
654         release_val(&l);
655     }
656     release_val(&r);
657     if(FAILED(hres))
658         return hres;
659
660     return stack_push(ctx, &v);
661 }
662
663 static HRESULT interp_sub(exec_ctx_t *ctx)
664 {
665     variant_val_t r, l;
666     VARIANT v;
667     HRESULT hres;
668
669     TRACE("\n");
670
671     hres = stack_pop_val(ctx, &r);
672     if(FAILED(hres))
673         return hres;
674
675     hres = stack_pop_val(ctx, &l);
676     if(SUCCEEDED(hres)) {
677         hres = VarSub(l.v, r.v, &v);
678         release_val(&l);
679     }
680     release_val(&r);
681     if(FAILED(hres))
682         return hres;
683
684     return stack_push(ctx, &v);
685 }
686
687 static HRESULT interp_mod(exec_ctx_t *ctx)
688 {
689     variant_val_t r, l;
690     VARIANT v;
691     HRESULT hres;
692
693     TRACE("\n");
694
695     hres = stack_pop_val(ctx, &r);
696     if(FAILED(hres))
697         return hres;
698
699     hres = stack_pop_val(ctx, &l);
700     if(SUCCEEDED(hres)) {
701         hres = VarMod(l.v, r.v, &v);
702         release_val(&l);
703     }
704     release_val(&r);
705     if(FAILED(hres))
706         return hres;
707
708     return stack_push(ctx, &v);
709 }
710
711 static HRESULT interp_idiv(exec_ctx_t *ctx)
712 {
713     variant_val_t r, l;
714     VARIANT v;
715     HRESULT hres;
716
717     TRACE("\n");
718
719     hres = stack_pop_val(ctx, &r);
720     if(FAILED(hres))
721         return hres;
722
723     hres = stack_pop_val(ctx, &l);
724     if(SUCCEEDED(hres)) {
725         hres = VarIdiv(l.v, r.v, &v);
726         release_val(&l);
727     }
728     release_val(&r);
729     if(FAILED(hres))
730         return hres;
731
732     return stack_push(ctx, &v);
733 }
734
735 static HRESULT interp_div(exec_ctx_t *ctx)
736 {
737     variant_val_t r, l;
738     VARIANT v;
739     HRESULT hres;
740
741     TRACE("\n");
742
743     hres = stack_pop_val(ctx, &r);
744     if(FAILED(hres))
745         return hres;
746
747     hres = stack_pop_val(ctx, &l);
748     if(SUCCEEDED(hres)) {
749         hres = VarDiv(l.v, r.v, &v);
750         release_val(&l);
751     }
752     release_val(&r);
753     if(FAILED(hres))
754         return hres;
755
756     return stack_push(ctx, &v);
757 }
758
759 static HRESULT interp_mul(exec_ctx_t *ctx)
760 {
761     variant_val_t r, l;
762     VARIANT v;
763     HRESULT hres;
764
765     TRACE("\n");
766
767     hres = stack_pop_val(ctx, &r);
768     if(FAILED(hres))
769         return hres;
770
771     hres = stack_pop_val(ctx, &l);
772     if(SUCCEEDED(hres)) {
773         hres = VarMul(l.v, r.v, &v);
774         release_val(&l);
775     }
776     release_val(&r);
777     if(FAILED(hres))
778         return hres;
779
780     return stack_push(ctx, &v);
781 }
782
783 static HRESULT interp_exp(exec_ctx_t *ctx)
784 {
785     variant_val_t r, l;
786     VARIANT v;
787     HRESULT hres;
788
789     TRACE("\n");
790
791     hres = stack_pop_val(ctx, &r);
792     if(FAILED(hres))
793         return hres;
794
795     hres = stack_pop_val(ctx, &l);
796     if(SUCCEEDED(hres)) {
797         hres = VarPow(l.v, r.v, &v);
798         release_val(&l);
799     }
800     release_val(&r);
801     if(FAILED(hres))
802         return hres;
803
804     return stack_push(ctx, &v);
805 }
806
807 static HRESULT interp_neg(exec_ctx_t *ctx)
808 {
809     variant_val_t val;
810     VARIANT v;
811     HRESULT hres;
812
813     hres = stack_pop_val(ctx, &val);
814     if(FAILED(hres))
815         return hres;
816
817     hres = VarNeg(val.v, &v);
818     release_val(&val);
819     if(FAILED(hres))
820         return hres;
821
822     return stack_push(ctx, &v);
823 }
824
825 static const instr_func_t op_funcs[] = {
826 #define X(x,n,a,b) interp_ ## x,
827 OP_LIST
828 #undef X
829 };
830
831 static const unsigned op_move[] = {
832 #define X(x,n,a,b) n,
833 OP_LIST
834 #undef X
835 };
836
837 static void release_exec(exec_ctx_t *ctx)
838 {
839     unsigned i;
840
841     if(ctx->args) {
842         for(i=0; i < ctx->func->arg_cnt; i++)
843             VariantClear(ctx->args+i);
844     }
845
846     if(ctx->vars) {
847         for(i=0; i < ctx->func->var_cnt; i++)
848             VariantClear(ctx->vars+i);
849     }
850
851     heap_free(ctx->args);
852     heap_free(ctx->vars);
853     heap_free(ctx->stack);
854 }
855
856 HRESULT exec_script(script_ctx_t *ctx, function_t *func, DISPPARAMS *dp, VARIANT *res)
857 {
858     exec_ctx_t exec = {func->code_ctx};
859     vbsop_t op;
860     HRESULT hres = S_OK;
861
862     if(res) {
863         FIXME("returning value is not implemented\n");
864         return E_NOTIMPL;
865     }
866
867     exec.code = func->code_ctx;
868
869     if(dp ? func->arg_cnt != arg_cnt(dp) : func->arg_cnt) {
870         FIXME("wrong arg_cnt %d, expected %d\n", dp ? arg_cnt(dp) : 0, func->arg_cnt);
871         return E_FAIL;
872     }
873
874     if(func->arg_cnt) {
875         VARIANT *v;
876         unsigned i;
877
878         exec.args = heap_alloc_zero(func->arg_cnt * sizeof(VARIANT));
879         if(!exec.args) {
880             release_exec(&exec);
881             return E_OUTOFMEMORY;
882         }
883
884         for(i=0; i < func->arg_cnt; i++) {
885             v = get_arg(dp, i);
886             if(V_VT(v) == (VT_VARIANT|VT_BYREF)) {
887                 if(func->args[i].by_ref)
888                     exec.args[i] = *v;
889                 else
890                     hres = VariantCopy(exec.args+i, V_VARIANTREF(v));
891             }else {
892                 hres = VariantCopy(exec.args+i, v);
893             }
894             if(FAILED(hres)) {
895                 release_exec(&exec);
896                 return hres;
897             }
898         }
899     }else {
900         exec.args = NULL;
901     }
902
903     if(func->var_cnt) {
904         exec.vars = heap_alloc_zero(func->var_cnt * sizeof(VARIANT));
905         if(!exec.vars) {
906             release_exec(&exec);
907             return E_OUTOFMEMORY;
908         }
909     }else {
910         exec.vars = NULL;
911     }
912
913     exec.stack_size = 16;
914     exec.top = 0;
915     exec.stack = heap_alloc(exec.stack_size * sizeof(VARIANT));
916     if(!exec.stack) {
917         release_exec(&exec);
918         return E_OUTOFMEMORY;
919     }
920
921     exec.instr = exec.code->instrs + func->code_off;
922     exec.script = ctx;
923     exec.func = func;
924
925     while(exec.instr) {
926         op = exec.instr->op;
927         hres = op_funcs[op](&exec);
928         if(FAILED(hres)) {
929             FIXME("Failed %08x\n", hres);
930             stack_popn(&exec, exec.top);
931             break;
932         }
933
934         exec.instr += op_move[op];
935     }
936
937     assert(!exec.top);
938     release_exec(&exec);
939
940     return hres;
941 }