vbscript: Init destination before passing it to VariantCopy in add_dynamic_var.
[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 typedef struct {
28     vbscode_t *code;
29     instr_t *instr;
30     script_ctx_t *script;
31     function_t *func;
32     IDispatch *this_obj;
33
34     VARIANT *args;
35     VARIANT *vars;
36
37     dynamic_var_t *dynamic_vars;
38     vbsheap_t heap;
39
40     BOOL resume_next;
41
42     unsigned stack_size;
43     unsigned top;
44     VARIANT *stack;
45
46     VARIANT ret_val;
47 } exec_ctx_t;
48
49 typedef HRESULT (*instr_func_t)(exec_ctx_t*);
50
51 typedef enum {
52     REF_NONE,
53     REF_DISP,
54     REF_VAR,
55     REF_OBJ,
56     REF_CONST,
57     REF_FUNC
58 } ref_type_t;
59
60 typedef struct {
61     ref_type_t type;
62     union {
63         struct {
64             IDispatch *disp;
65             DISPID id;
66         } d;
67         VARIANT *v;
68         function_t *f;
69         IDispatch *obj;
70     } u;
71 } ref_t;
72
73 typedef struct {
74     VARIANT *v;
75     VARIANT store;
76     BOOL owned;
77 } variant_val_t;
78
79 static BOOL lookup_dynamic_vars(dynamic_var_t *var, const WCHAR *name, ref_t *ref)
80 {
81     while(var) {
82         if(!strcmpiW(var->name, name)) {
83             ref->type = var->is_const ? REF_CONST : REF_VAR;
84             ref->u.v = &var->v;
85             return TRUE;
86         }
87
88         var = var->next;
89     }
90
91     return FALSE;
92 }
93
94 static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_t invoke_type, ref_t *ref)
95 {
96     named_item_t *item;
97     function_t *func;
98     unsigned i;
99     DISPID id;
100     HRESULT hres;
101
102     static const WCHAR errW[] = {'e','r','r',0};
103
104     if(invoke_type == VBDISP_LET
105             && (ctx->func->type == FUNC_FUNCTION || ctx->func->type == FUNC_PROPGET || ctx->func->type == FUNC_DEFGET)
106             && !strcmpiW(name, ctx->func->name)) {
107         ref->type = REF_VAR;
108         ref->u.v = &ctx->ret_val;
109         return S_OK;
110     }
111
112     for(i=0; i < ctx->func->var_cnt; i++) {
113         if(!strcmpiW(ctx->func->vars[i].name, name)) {
114             ref->type = REF_VAR;
115             ref->u.v = ctx->vars+i;
116             return TRUE;
117         }
118     }
119
120     for(i=0; i < ctx->func->arg_cnt; i++) {
121         if(!strcmpiW(ctx->func->args[i].name, name)) {
122             ref->type = REF_VAR;
123             ref->u.v = ctx->args+i;
124             return S_OK;
125         }
126     }
127
128     if(lookup_dynamic_vars(ctx->func->type == FUNC_GLOBAL ? ctx->script->global_vars : ctx->dynamic_vars, name, ref))
129         return S_OK;
130
131     if(ctx->func->type != FUNC_GLOBAL) {
132         hres = disp_get_id(ctx->this_obj, name, invoke_type, TRUE, &id);
133         if(SUCCEEDED(hres)) {
134             ref->type = REF_DISP;
135             ref->u.d.disp = ctx->this_obj;
136             ref->u.d.id = id;
137             return S_OK;
138         }
139     }
140
141     if(ctx->func->type != FUNC_GLOBAL && lookup_dynamic_vars(ctx->script->global_vars, name, ref))
142         return S_OK;
143
144     for(func = ctx->script->global_funcs; func; func = func->next) {
145         if(!strcmpiW(func->name, name)) {
146             ref->type = REF_FUNC;
147             ref->u.f = func;
148             return S_OK;
149         }
150     }
151
152     if(!strcmpiW(name, errW)) {
153         ref->type = REF_OBJ;
154         ref->u.obj = (IDispatch*)&ctx->script->err_obj->IDispatchEx_iface;
155         return S_OK;
156     }
157
158     hres = vbdisp_get_id(ctx->script->global_obj, name, invoke_type, TRUE, &id);
159     if(SUCCEEDED(hres)) {
160         ref->type = REF_DISP;
161         ref->u.d.disp = (IDispatch*)&ctx->script->global_obj->IDispatchEx_iface;
162         ref->u.d.id = id;
163         return S_OK;
164     }
165
166     LIST_FOR_EACH_ENTRY(item, &ctx->script->named_items, named_item_t, entry) {
167         if((item->flags & SCRIPTITEM_ISVISIBLE) && !strcmpiW(item->name, name)) {
168             if(!item->disp) {
169                 IUnknown *unk;
170
171                 hres = IActiveScriptSite_GetItemInfo(ctx->script->site, name, SCRIPTINFO_IUNKNOWN, &unk, NULL);
172                 if(FAILED(hres)) {
173                     WARN("GetItemInfo failed: %08x\n", hres);
174                     continue;
175                 }
176
177                 hres = IUnknown_QueryInterface(unk, &IID_IDispatch, (void**)&item->disp);
178                 IUnknown_Release(unk);
179                 if(FAILED(hres)) {
180                     WARN("object does not implement IDispatch\n");
181                     continue;
182                 }
183             }
184
185             ref->type = REF_OBJ;
186             ref->u.obj = item->disp;
187             return S_OK;
188         }
189     }
190
191     LIST_FOR_EACH_ENTRY(item, &ctx->script->named_items, named_item_t, entry) {
192         if((item->flags & SCRIPTITEM_GLOBALMEMBERS)) {
193             hres = disp_get_id(item->disp, name, invoke_type, FALSE, &id);
194             if(SUCCEEDED(hres)) {
195                 ref->type = REF_DISP;
196                 ref->u.d.disp = item->disp;
197                 ref->u.d.id = id;
198                 return S_OK;
199             }
200         }
201     }
202
203     ref->type = REF_NONE;
204     return S_OK;
205 }
206
207 static HRESULT add_dynamic_var(exec_ctx_t *ctx, const WCHAR *name, BOOL is_const, VARIANT *val, BOOL own_val)
208 {
209     dynamic_var_t *new_var;
210     vbsheap_t *heap;
211     WCHAR *str;
212     unsigned size;
213     HRESULT hres;
214
215     heap = ctx->func->type == FUNC_GLOBAL ? &ctx->script->heap : &ctx->heap;
216
217     new_var = vbsheap_alloc(heap, sizeof(*new_var));
218     if(!new_var)
219         return E_OUTOFMEMORY;
220
221     size = (strlenW(name)+1)*sizeof(WCHAR);
222     str = vbsheap_alloc(heap, size);
223     if(!str)
224         return E_OUTOFMEMORY;
225     memcpy(str, name, size);
226     new_var->name = str;
227     new_var->is_const = is_const;
228
229     if(own_val) {
230         new_var->v = *val;
231     }else {
232         V_VT(&new_var->v) = VT_EMPTY;
233         hres = VariantCopy(&new_var->v, val);
234         if(FAILED(hres))
235             return hres;
236     }
237
238     if(ctx->func->type == FUNC_GLOBAL) {
239         new_var->next = ctx->script->global_vars;
240         ctx->script->global_vars = new_var;
241     }else {
242         new_var->next = ctx->dynamic_vars;
243         ctx->dynamic_vars = new_var;
244     }
245
246     return S_OK;
247 }
248
249 static inline VARIANT *stack_pop(exec_ctx_t *ctx)
250 {
251     assert(ctx->top);
252     return ctx->stack + --ctx->top;
253 }
254
255 static inline VARIANT *stack_top(exec_ctx_t *ctx, unsigned n)
256 {
257     assert(ctx->top >= n);
258     return ctx->stack + (ctx->top-n-1);
259 }
260
261 static HRESULT stack_push(exec_ctx_t *ctx, VARIANT *v)
262 {
263     if(ctx->stack_size == ctx->top) {
264         VARIANT *new_stack;
265
266         new_stack = heap_realloc(ctx->stack, ctx->stack_size*2*sizeof(*ctx->stack));
267         if(!new_stack) {
268             VariantClear(v);
269             return E_OUTOFMEMORY;
270         }
271
272         ctx->stack = new_stack;
273         ctx->stack_size *= 2;
274     }
275
276     ctx->stack[ctx->top++] = *v;
277     return S_OK;
278 }
279
280 static void stack_popn(exec_ctx_t *ctx, unsigned n)
281 {
282     while(n--)
283         VariantClear(stack_pop(ctx));
284 }
285
286 static HRESULT stack_pop_val(exec_ctx_t *ctx, variant_val_t *v)
287 {
288     VARIANT *var;
289
290     var = stack_pop(ctx);
291
292     if(V_VT(var) == (VT_BYREF|VT_VARIANT)) {
293         v->owned = FALSE;
294         var = V_VARIANTREF(var);
295     }else {
296         v->owned = TRUE;
297     }
298
299     if(V_VT(var) == VT_DISPATCH) {
300         DISPPARAMS dp = {0};
301         HRESULT hres;
302
303         hres = disp_call(ctx->script, V_DISPATCH(var), DISPID_VALUE, &dp, &v->store);
304         if(v->owned)
305             IDispatch_Release(V_DISPATCH(var));
306         if(FAILED(hres))
307             return hres;
308
309         v->owned = TRUE;
310         v->v = &v->store;
311     }else {
312         v->v = var;
313     }
314
315     return S_OK;
316 }
317
318 static inline void release_val(variant_val_t *v)
319 {
320     if(v->owned)
321         VariantClear(v->v);
322 }
323
324 static HRESULT stack_pop_disp(exec_ctx_t *ctx, IDispatch **ret)
325 {
326     VARIANT *v = stack_pop(ctx);
327
328     if(V_VT(v) == VT_DISPATCH) {
329         *ret = V_DISPATCH(v);
330         return S_OK;
331     }
332
333     if(V_VT(v) != (VT_VARIANT|VT_BYREF)) {
334         FIXME("not supported type: %s\n", debugstr_variant(v));
335         VariantClear(v);
336         return E_FAIL;
337     }
338
339     v = V_BYREF(v);
340     if(V_VT(v) != VT_DISPATCH) {
341         FIXME("not disp %s\n", debugstr_variant(v));
342         return E_FAIL;
343     }
344
345     if(V_DISPATCH(v))
346         IDispatch_AddRef(V_DISPATCH(v));
347     *ret = V_DISPATCH(v);
348     return S_OK;
349 }
350
351 static inline void instr_jmp(exec_ctx_t *ctx, unsigned addr)
352 {
353     ctx->instr = ctx->code->instrs + addr;
354 }
355
356 static void vbstack_to_dp(exec_ctx_t *ctx, unsigned arg_cnt, DISPPARAMS *dp)
357 {
358     dp->cArgs = arg_cnt;
359     dp->rgdispidNamedArgs = NULL;
360     dp->cNamedArgs = 0;
361
362     if(arg_cnt) {
363         VARIANT tmp;
364         unsigned i;
365
366         assert(ctx->top >= arg_cnt);
367
368         for(i=1; i*2 <= arg_cnt; i++) {
369             tmp = ctx->stack[ctx->top-i];
370             ctx->stack[ctx->top-i] = ctx->stack[ctx->top-arg_cnt+i-1];
371             ctx->stack[ctx->top-arg_cnt+i-1] = tmp;
372         }
373
374         dp->rgvarg = ctx->stack + ctx->top-arg_cnt;
375     }else {
376         dp->rgvarg = NULL;
377     }
378 }
379
380 static HRESULT do_icall(exec_ctx_t *ctx, VARIANT *res)
381 {
382     BSTR identifier = ctx->instr->arg1.bstr;
383     const unsigned arg_cnt = ctx->instr->arg2.uint;
384     DISPPARAMS dp;
385     ref_t ref;
386     HRESULT hres;
387
388     hres = lookup_identifier(ctx, identifier, VBDISP_CALLGET, &ref);
389     if(FAILED(hres))
390         return hres;
391
392     vbstack_to_dp(ctx, arg_cnt, &dp);
393
394     switch(ref.type) {
395     case REF_VAR:
396     case REF_CONST:
397         if(!res) {
398             FIXME("REF_VAR no res\n");
399             return E_NOTIMPL;
400         }
401
402         if(arg_cnt) {
403             FIXME("arguments not implemented\n");
404             return E_NOTIMPL;
405         }
406
407         V_VT(res) = VT_BYREF|VT_VARIANT;
408         V_BYREF(res) = V_VT(ref.u.v) == (VT_VARIANT|VT_BYREF) ? V_VARIANTREF(ref.u.v) : ref.u.v;
409         break;
410     case REF_DISP:
411         hres = disp_call(ctx->script, ref.u.d.disp, ref.u.d.id, &dp, res);
412         if(FAILED(hres))
413             return hres;
414         break;
415     case REF_FUNC:
416         hres = exec_script(ctx->script, ref.u.f, NULL, &dp, res);
417         if(FAILED(hres))
418             return hres;
419         break;
420     case REF_OBJ:
421         if(arg_cnt) {
422             FIXME("arguments on object\n");
423             return E_NOTIMPL;
424         }
425
426         if(res) {
427             IDispatch_AddRef(ref.u.obj);
428             V_VT(res) = VT_DISPATCH;
429             V_DISPATCH(res) = ref.u.obj;
430         }
431         break;
432     case REF_NONE:
433         FIXME("%s not found\n", debugstr_w(identifier));
434         return DISP_E_UNKNOWNNAME;
435     }
436
437     stack_popn(ctx, arg_cnt);
438     return S_OK;
439 }
440
441 static HRESULT interp_icall(exec_ctx_t *ctx)
442 {
443     VARIANT v;
444     HRESULT hres;
445
446     TRACE("\n");
447
448     hres = do_icall(ctx, &v);
449     if(FAILED(hres))
450         return hres;
451
452     return stack_push(ctx, &v);
453 }
454
455 static HRESULT interp_icallv(exec_ctx_t *ctx)
456 {
457     TRACE("\n");
458     return do_icall(ctx, NULL);
459 }
460
461 static HRESULT do_mcall(exec_ctx_t *ctx, VARIANT *res)
462 {
463     const BSTR identifier = ctx->instr->arg1.bstr;
464     const unsigned arg_cnt = ctx->instr->arg2.uint;
465     IDispatch *obj;
466     DISPPARAMS dp;
467     DISPID id;
468     HRESULT hres;
469
470     hres = stack_pop_disp(ctx, &obj);
471     if(FAILED(hres))
472         return hres;
473
474     if(!obj) {
475         FIXME("NULL obj\n");
476         return E_FAIL;
477     }
478
479     vbstack_to_dp(ctx, arg_cnt, &dp);
480
481     hres = disp_get_id(obj, identifier, VBDISP_CALLGET, FALSE, &id);
482     if(SUCCEEDED(hres))
483         hres = disp_call(ctx->script, obj, id, &dp, res);
484     IDispatch_Release(obj);
485     if(FAILED(hres))
486         return hres;
487
488     stack_popn(ctx, arg_cnt);
489     return S_OK;
490 }
491
492 static HRESULT interp_mcall(exec_ctx_t *ctx)
493 {
494     VARIANT res;
495     HRESULT hres;
496
497     TRACE("\n");
498
499     hres = do_mcall(ctx, &res);
500     if(FAILED(hres))
501         return hres;
502
503     return stack_push(ctx, &res);
504 }
505
506 static HRESULT interp_mcallv(exec_ctx_t *ctx)
507 {
508     TRACE("\n");
509
510     return do_mcall(ctx, NULL);
511 }
512
513 static HRESULT assign_ident(exec_ctx_t *ctx, BSTR name, VARIANT *val, BOOL own_val)
514 {
515     ref_t ref;
516     HRESULT hres;
517
518     hres = lookup_identifier(ctx, name, VBDISP_LET, &ref);
519     if(FAILED(hres))
520         return hres;
521
522     switch(ref.type) {
523     case REF_VAR: {
524         VARIANT *v = ref.u.v;
525
526         if(V_VT(v) == (VT_VARIANT|VT_BYREF))
527             v = V_VARIANTREF(v);
528
529         if(own_val) {
530             VariantClear(v);
531             *v = *val;
532             hres = S_OK;
533         }else {
534             hres = VariantCopy(v, val);
535         }
536         break;
537     }
538     case REF_DISP:
539         hres = disp_propput(ctx->script, ref.u.d.disp, ref.u.d.id, val);
540         if(own_val)
541             VariantClear(val);
542         break;
543     case REF_FUNC:
544         FIXME("functions not implemented\n");
545         return E_NOTIMPL;
546     case REF_OBJ:
547         FIXME("REF_OBJ\n");
548         return E_NOTIMPL;
549     case REF_CONST:
550         FIXME("REF_CONST\n");
551         return E_NOTIMPL;
552     case REF_NONE:
553         if(ctx->func->code_ctx->option_explicit) {
554             FIXME("throw exception\n");
555             hres = E_FAIL;
556         }else {
557             TRACE("creating variable %s\n", debugstr_w(name));
558             hres = add_dynamic_var(ctx, name, FALSE, val, own_val);
559         }
560     }
561
562     return hres;
563 }
564
565 static HRESULT interp_assign_ident(exec_ctx_t *ctx)
566 {
567     const BSTR arg = ctx->instr->arg1.bstr;
568     const unsigned arg_cnt = ctx->instr->arg2.uint;
569     variant_val_t v;
570     HRESULT hres;
571
572     TRACE("%s\n", debugstr_w(arg));
573
574     if(arg_cnt) {
575         FIXME("arguments not supported\n");
576         return E_NOTIMPL;
577     }
578
579     hres = stack_pop_val(ctx, &v);
580     if(FAILED(hres))
581         return hres;
582
583     return assign_ident(ctx, arg, v.v, v.owned);
584 }
585
586 static HRESULT interp_set_ident(exec_ctx_t *ctx)
587 {
588     const BSTR arg = ctx->instr->arg1.bstr;
589     const unsigned arg_cnt = ctx->instr->arg2.uint;
590     IDispatch *disp;
591     VARIANT v;
592     HRESULT hres;
593
594     TRACE("%s\n", debugstr_w(arg));
595
596     if(arg_cnt) {
597         FIXME("arguments not supported\n");
598         return E_NOTIMPL;
599     }
600
601     hres = stack_pop_disp(ctx, &disp);
602     if(FAILED(hres))
603         return hres;
604
605     V_VT(&v) = VT_DISPATCH;
606     V_DISPATCH(&v) = disp;
607     return assign_ident(ctx, ctx->instr->arg1.bstr, &v, TRUE);
608 }
609
610 static HRESULT interp_assign_member(exec_ctx_t *ctx)
611 {
612     BSTR identifier = ctx->instr->arg1.bstr;
613     const unsigned arg_cnt = ctx->instr->arg2.uint;
614     variant_val_t val;
615     IDispatch *obj;
616     DISPID id;
617     HRESULT hres;
618
619     TRACE("%s\n", debugstr_w(identifier));
620
621     if(arg_cnt) {
622         FIXME("arguments not supported\n");
623         return E_NOTIMPL;
624     }
625
626     hres = stack_pop_disp(ctx, &obj);
627     if(FAILED(hres))
628         return hres;
629
630     if(!obj) {
631         FIXME("NULL obj\n");
632         return E_FAIL;
633     }
634
635     hres = stack_pop_val(ctx, &val);
636     if(FAILED(hres)) {
637         IDispatch_Release(obj);
638         return hres;
639     }
640
641     hres = disp_get_id(obj, identifier, VBDISP_LET, FALSE, &id);
642     if(SUCCEEDED(hres))
643         hres = disp_propput(ctx->script, obj, id, val.v);
644
645     release_val(&val);
646     IDispatch_Release(obj);
647     return hres;
648 }
649
650 static HRESULT interp_set_member(exec_ctx_t *ctx)
651 {
652     BSTR identifier = ctx->instr->arg1.bstr;
653     const unsigned arg_cnt = ctx->instr->arg2.uint;
654     IDispatch *obj, *val;
655     DISPID id;
656     HRESULT hres;
657
658     TRACE("%s\n", debugstr_w(identifier));
659
660     if(arg_cnt) {
661         FIXME("arguments not supported\n");
662         return E_NOTIMPL;
663     }
664
665     hres = stack_pop_disp(ctx, &obj);
666     if(FAILED(hres))
667         return hres;
668
669     if(!obj) {
670         FIXME("NULL obj\n");
671         return E_FAIL;
672     }
673
674     hres = stack_pop_disp(ctx, &val);
675     if(FAILED(hres)) {
676         IDispatch_Release(obj);
677         return hres;
678     }
679
680     hres = disp_get_id(obj, identifier, VBDISP_SET, FALSE, &id);
681     if(SUCCEEDED(hres)) {
682         VARIANT v;
683
684         V_VT(&v) = VT_DISPATCH;
685         V_DISPATCH(&v) = val;
686         hres = disp_propput(ctx->script, obj, id, &v);
687     }
688
689     if(val)
690         IDispatch_Release(val);
691     IDispatch_Release(obj);
692     return hres;
693 }
694
695 static HRESULT interp_const(exec_ctx_t *ctx)
696 {
697     BSTR arg = ctx->instr->arg1.bstr;
698     variant_val_t val;
699     ref_t ref;
700     HRESULT hres;
701
702     TRACE("%s\n", debugstr_w(arg));
703
704     assert(ctx->func->type == FUNC_GLOBAL);
705
706     hres = lookup_identifier(ctx, arg, VBDISP_CALLGET, &ref);
707     if(FAILED(hres))
708         return hres;
709
710     if(ref.type != REF_NONE) {
711         FIXME("%s already defined\n", debugstr_w(arg));
712         return E_FAIL;
713     }
714
715     hres = stack_pop_val(ctx, &val);
716     if(FAILED(hres))
717         return hres;
718
719     return add_dynamic_var(ctx, arg, TRUE, val.v, val.owned);
720 }
721
722 static HRESULT interp_val(exec_ctx_t *ctx)
723 {
724     variant_val_t val;
725     VARIANT v;
726     HRESULT hres;
727
728     TRACE("\n");
729
730     hres = stack_pop_val(ctx, &val);
731     if(FAILED(hres))
732         return hres;
733
734     if(!val.owned) {
735         V_VT(&v) = VT_EMPTY;
736         hres = VariantCopy(&v, val.v);
737         if(FAILED(hres))
738             return hres;
739     }
740
741     return stack_push(ctx, val.owned ? val.v : &v);
742 }
743
744 static HRESULT interp_pop(exec_ctx_t *ctx)
745 {
746     const unsigned n = ctx->instr->arg1.uint;
747
748     TRACE("%u\n", n);
749
750     stack_popn(ctx, n);
751     return S_OK;
752 }
753
754 static HRESULT interp_new(exec_ctx_t *ctx)
755 {
756     const WCHAR *arg = ctx->instr->arg1.bstr;
757     class_desc_t *class_desc;
758     vbdisp_t *obj;
759     VARIANT v;
760     HRESULT hres;
761
762     TRACE("%s\n", debugstr_w(arg));
763
764     for(class_desc = ctx->script->classes; class_desc; class_desc = class_desc->next) {
765         if(!strcmpiW(class_desc->name, arg))
766             break;
767     }
768     if(!class_desc) {
769         FIXME("Class %s not found\n", debugstr_w(arg));
770         return E_FAIL;
771     }
772
773     hres = create_vbdisp(class_desc, &obj);
774     if(FAILED(hres))
775         return hres;
776
777     V_VT(&v) = VT_DISPATCH;
778     V_DISPATCH(&v) = (IDispatch*)&obj->IDispatchEx_iface;
779     return stack_push(ctx, &v);
780 }
781
782 static HRESULT interp_step(exec_ctx_t *ctx)
783 {
784     const BSTR ident = ctx->instr->arg2.bstr;
785     BOOL gteq_zero;
786     VARIANT zero;
787     ref_t ref;
788     HRESULT hres;
789
790     TRACE("%s\n", debugstr_w(ident));
791
792     V_VT(&zero) = VT_I2;
793     V_I2(&zero) = 0;
794     hres = VarCmp(stack_top(ctx, 0), &zero, ctx->script->lcid, 0);
795     if(FAILED(hres))
796         return hres;
797
798     gteq_zero = hres == VARCMP_GT || hres == VARCMP_EQ;
799
800     hres = lookup_identifier(ctx, ident, VBDISP_ANY, &ref);
801     if(FAILED(hres))
802         return hres;
803
804     if(ref.type != REF_VAR) {
805         FIXME("%s is not REF_VAR\n", debugstr_w(ident));
806         return E_FAIL;
807     }
808
809     hres = VarCmp(ref.u.v, stack_top(ctx, 1), ctx->script->lcid, 0);
810     if(FAILED(hres))
811         return hres;
812
813     if(hres == VARCMP_EQ || hres == (gteq_zero ? VARCMP_LT : VARCMP_GT))
814         ctx->instr++;
815     else
816         instr_jmp(ctx, ctx->instr->arg1.uint);
817     return S_OK;
818 }
819
820 static HRESULT interp_jmp(exec_ctx_t *ctx)
821 {
822     const unsigned arg = ctx->instr->arg1.uint;
823
824     TRACE("%u\n", arg);
825
826     instr_jmp(ctx, arg);
827     return S_OK;
828 }
829
830 static HRESULT interp_jmp_false(exec_ctx_t *ctx)
831 {
832     const unsigned arg = ctx->instr->arg1.uint;
833     variant_val_t val;
834     HRESULT hres;
835
836     TRACE("%u\n", arg);
837
838     hres = stack_pop_val(ctx, &val);
839     if(FAILED(hres))
840         return hres;
841
842     if(V_VT(val.v) != VT_BOOL) {
843         FIXME("unsupported for %s\n", debugstr_variant(val.v));
844         release_val(&val);
845         return E_NOTIMPL;
846     }
847
848     if(V_BOOL(val.v))
849         ctx->instr++;
850     else
851         instr_jmp(ctx, ctx->instr->arg1.uint);
852     return S_OK;
853 }
854
855 static HRESULT interp_jmp_true(exec_ctx_t *ctx)
856 {
857     const unsigned arg = ctx->instr->arg1.uint;
858     variant_val_t val;
859     HRESULT hres;
860
861     TRACE("%u\n", arg);
862
863     hres = stack_pop_val(ctx, &val);
864     if(FAILED(hres))
865         return hres;
866
867     if(V_VT(val.v) != VT_BOOL) {
868         FIXME("unsupported for %s\n", debugstr_variant(val.v));
869         release_val(&val);
870         return E_NOTIMPL;
871     }
872
873     if(V_BOOL(val.v))
874         instr_jmp(ctx, ctx->instr->arg1.uint);
875     else
876         ctx->instr++;
877     return S_OK;
878 }
879
880 static HRESULT interp_ret(exec_ctx_t *ctx)
881 {
882     TRACE("\n");
883
884     ctx->instr = NULL;
885     return S_OK;
886 }
887
888 static HRESULT interp_stop(exec_ctx_t *ctx)
889 {
890     WARN("\n");
891
892     /* NOTE: this should have effect in debugging mode (that we don't support yet) */
893     return S_OK;
894 }
895
896 static HRESULT interp_me(exec_ctx_t *ctx)
897 {
898     VARIANT v;
899
900     TRACE("\n");
901
902     IDispatch_AddRef(ctx->this_obj);
903     V_VT(&v) = VT_DISPATCH;
904     V_DISPATCH(&v) = ctx->this_obj;
905     return stack_push(ctx, &v);
906 }
907
908 static HRESULT interp_bool(exec_ctx_t *ctx)
909 {
910     const VARIANT_BOOL arg = ctx->instr->arg1.lng;
911     VARIANT v;
912
913     TRACE("%s\n", arg ? "true" : "false");
914
915     V_VT(&v) = VT_BOOL;
916     V_BOOL(&v) = arg;
917     return stack_push(ctx, &v);
918 }
919
920 static HRESULT interp_errmode(exec_ctx_t *ctx)
921 {
922     const int err_mode = ctx->instr->arg1.uint;
923
924     TRACE("%d\n", err_mode);
925
926     ctx->resume_next = err_mode;
927     return S_OK;
928 }
929
930 static HRESULT interp_string(exec_ctx_t *ctx)
931 {
932     VARIANT v;
933
934     TRACE("\n");
935
936     V_VT(&v) = VT_BSTR;
937     V_BSTR(&v) = SysAllocString(ctx->instr->arg1.str);
938     if(!V_BSTR(&v))
939         return E_OUTOFMEMORY;
940
941     return stack_push(ctx, &v);
942 }
943
944 static HRESULT interp_long(exec_ctx_t *ctx)
945 {
946     const LONG arg = ctx->instr->arg1.lng;
947     VARIANT v;
948
949     TRACE("%d\n", arg);
950
951     V_VT(&v) = VT_I4;
952     V_I4(&v) = arg;
953     return stack_push(ctx, &v);
954 }
955
956 static HRESULT interp_short(exec_ctx_t *ctx)
957 {
958     const LONG arg = ctx->instr->arg1.lng;
959     VARIANT v;
960
961     TRACE("%d\n", arg);
962
963     V_VT(&v) = VT_I2;
964     V_I2(&v) = arg;
965     return stack_push(ctx, &v);
966 }
967
968 static HRESULT interp_double(exec_ctx_t *ctx)
969 {
970     const DOUBLE *arg = ctx->instr->arg1.dbl;
971     VARIANT v;
972
973     TRACE("%lf\n", *arg);
974
975     V_VT(&v) = VT_R8;
976     V_R8(&v) = *arg;
977     return stack_push(ctx, &v);
978 }
979
980 static HRESULT interp_empty(exec_ctx_t *ctx)
981 {
982     VARIANT v;
983
984     TRACE("\n");
985
986     V_VT(&v) = VT_EMPTY;
987     return stack_push(ctx, &v);
988 }
989
990 static HRESULT interp_null(exec_ctx_t *ctx)
991 {
992     VARIANT v;
993
994     TRACE("\n");
995
996     V_VT(&v) = VT_NULL;
997     return stack_push(ctx, &v);
998 }
999
1000 static HRESULT interp_nothing(exec_ctx_t *ctx)
1001 {
1002     VARIANT v;
1003
1004     TRACE("\n");
1005
1006     V_VT(&v) = VT_DISPATCH;
1007     V_DISPATCH(&v) = NULL;
1008     return stack_push(ctx, &v);
1009 }
1010
1011 static HRESULT interp_not(exec_ctx_t *ctx)
1012 {
1013     variant_val_t val;
1014     VARIANT v;
1015     HRESULT hres;
1016
1017     TRACE("\n");
1018
1019     hres = stack_pop_val(ctx, &val);
1020     if(FAILED(hres))
1021         return hres;
1022
1023     hres = VarNot(val.v, &v);
1024     release_val(&val);
1025     if(FAILED(hres))
1026         return hres;
1027
1028     return stack_push(ctx, &v);
1029 }
1030
1031 static HRESULT interp_and(exec_ctx_t *ctx)
1032 {
1033     variant_val_t r, l;
1034     VARIANT v;
1035     HRESULT hres;
1036
1037     TRACE("\n");
1038
1039     hres = stack_pop_val(ctx, &r);
1040     if(FAILED(hres))
1041         return hres;
1042
1043     hres = stack_pop_val(ctx, &l);
1044     if(SUCCEEDED(hres)) {
1045         hres = VarAnd(l.v, r.v, &v);
1046         release_val(&l);
1047     }
1048     release_val(&r);
1049     if(FAILED(hres))
1050         return hres;
1051
1052     return stack_push(ctx, &v);
1053 }
1054
1055 static HRESULT interp_or(exec_ctx_t *ctx)
1056 {
1057     variant_val_t r, l;
1058     VARIANT v;
1059     HRESULT hres;
1060
1061     TRACE("\n");
1062
1063     hres = stack_pop_val(ctx, &r);
1064     if(FAILED(hres))
1065         return hres;
1066
1067     hres = stack_pop_val(ctx, &l);
1068     if(SUCCEEDED(hres)) {
1069         hres = VarOr(l.v, r.v, &v);
1070         release_val(&l);
1071     }
1072     release_val(&r);
1073     if(FAILED(hres))
1074         return hres;
1075
1076     return stack_push(ctx, &v);
1077 }
1078
1079 static HRESULT interp_xor(exec_ctx_t *ctx)
1080 {
1081     variant_val_t r, l;
1082     VARIANT v;
1083     HRESULT hres;
1084
1085     TRACE("\n");
1086
1087     hres = stack_pop_val(ctx, &r);
1088     if(FAILED(hres))
1089         return hres;
1090
1091     hres = stack_pop_val(ctx, &l);
1092     if(SUCCEEDED(hres)) {
1093         hres = VarXor(l.v, r.v, &v);
1094         release_val(&l);
1095     }
1096     release_val(&r);
1097     if(FAILED(hres))
1098         return hres;
1099
1100     return stack_push(ctx, &v);
1101 }
1102
1103 static HRESULT interp_eqv(exec_ctx_t *ctx)
1104 {
1105     variant_val_t r, l;
1106     VARIANT v;
1107     HRESULT hres;
1108
1109     TRACE("\n");
1110
1111     hres = stack_pop_val(ctx, &r);
1112     if(FAILED(hres))
1113         return hres;
1114
1115     hres = stack_pop_val(ctx, &l);
1116     if(SUCCEEDED(hres)) {
1117         hres = VarEqv(l.v, r.v, &v);
1118         release_val(&l);
1119     }
1120     release_val(&r);
1121     if(FAILED(hres))
1122         return hres;
1123
1124     return stack_push(ctx, &v);
1125 }
1126
1127 static HRESULT interp_imp(exec_ctx_t *ctx)
1128 {
1129     variant_val_t r, l;
1130     VARIANT v;
1131     HRESULT hres;
1132
1133     TRACE("\n");
1134
1135     hres = stack_pop_val(ctx, &r);
1136     if(FAILED(hres))
1137         return hres;
1138
1139     hres = stack_pop_val(ctx, &l);
1140     if(SUCCEEDED(hres)) {
1141         hres = VarImp(l.v, r.v, &v);
1142         release_val(&l);
1143     }
1144     release_val(&r);
1145     if(FAILED(hres))
1146         return hres;
1147
1148     return stack_push(ctx, &v);
1149 }
1150
1151 static HRESULT cmp_oper(exec_ctx_t *ctx)
1152 {
1153     variant_val_t l, r;
1154     HRESULT hres;
1155
1156     hres = stack_pop_val(ctx, &r);
1157     if(FAILED(hres))
1158         return hres;
1159
1160     hres = stack_pop_val(ctx, &l);
1161     if(SUCCEEDED(hres)) {
1162         if(V_VT(l.v) == VT_NULL || V_VT(r.v) == VT_NULL) {
1163             FIXME("comparing nulls is not implemented\n");
1164             hres = E_NOTIMPL;
1165         }else {
1166             hres = VarCmp(l.v, r.v, ctx->script->lcid, 0);
1167         }
1168     }
1169
1170     release_val(&r);
1171     release_val(&l);
1172     return hres;
1173 }
1174
1175 static HRESULT interp_equal(exec_ctx_t *ctx)
1176 {
1177     VARIANT v;
1178     HRESULT hres;
1179
1180     TRACE("\n");
1181
1182     hres = cmp_oper(ctx);
1183     if(FAILED(hres))
1184         return hres;
1185
1186     V_VT(&v) = VT_BOOL;
1187     V_BOOL(&v) = hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1188     return stack_push(ctx, &v);
1189 }
1190
1191 static HRESULT interp_nequal(exec_ctx_t *ctx)
1192 {
1193     VARIANT v;
1194     HRESULT hres;
1195
1196     TRACE("\n");
1197
1198     hres = cmp_oper(ctx);
1199     if(FAILED(hres))
1200         return hres;
1201
1202     V_VT(&v) = VT_BOOL;
1203     V_BOOL(&v) = hres != VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1204     return stack_push(ctx, &v);
1205 }
1206
1207 static HRESULT interp_gt(exec_ctx_t *ctx)
1208 {
1209     VARIANT v;
1210     HRESULT hres;
1211
1212     TRACE("\n");
1213
1214     hres = cmp_oper(ctx);
1215     if(FAILED(hres))
1216         return hres;
1217
1218     V_VT(&v) = VT_BOOL;
1219     V_BOOL(&v) = hres == VARCMP_GT ? VARIANT_TRUE : VARIANT_FALSE;
1220     return stack_push(ctx, &v);
1221 }
1222
1223 static HRESULT interp_gteq(exec_ctx_t *ctx)
1224 {
1225     VARIANT v;
1226     HRESULT hres;
1227
1228     TRACE("\n");
1229
1230     hres = cmp_oper(ctx);
1231     if(FAILED(hres))
1232         return hres;
1233
1234     V_VT(&v) = VT_BOOL;
1235     V_BOOL(&v) = hres == VARCMP_GT || hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1236     return stack_push(ctx, &v);
1237 }
1238
1239 static HRESULT interp_lt(exec_ctx_t *ctx)
1240 {
1241     VARIANT v;
1242     HRESULT hres;
1243
1244     TRACE("\n");
1245
1246     hres = cmp_oper(ctx);
1247     if(FAILED(hres))
1248         return hres;
1249
1250     V_VT(&v) = VT_BOOL;
1251     V_BOOL(&v) = hres == VARCMP_LT ? VARIANT_TRUE : VARIANT_FALSE;
1252     return stack_push(ctx, &v);
1253 }
1254
1255 static HRESULT interp_lteq(exec_ctx_t *ctx)
1256 {
1257     VARIANT v;
1258     HRESULT hres;
1259
1260     TRACE("\n");
1261
1262     hres = cmp_oper(ctx);
1263     if(FAILED(hres))
1264         return hres;
1265
1266     V_VT(&v) = VT_BOOL;
1267     V_BOOL(&v) = hres == VARCMP_LT || hres == VARCMP_EQ ? VARIANT_TRUE : VARIANT_FALSE;
1268     return stack_push(ctx, &v);
1269 }
1270
1271 static HRESULT disp_cmp(IDispatch *disp1, IDispatch *disp2, VARIANT_BOOL *ret)
1272 {
1273     IObjectIdentity *identity;
1274     IUnknown *unk1, *unk2;
1275     HRESULT hres;
1276
1277     if(disp1 == disp2) {
1278         *ret = VARIANT_TRUE;
1279         return S_OK;
1280     }
1281
1282     if(!disp1 || !disp2) {
1283         *ret = VARIANT_FALSE;
1284         return S_OK;
1285     }
1286
1287     hres = IDispatch_QueryInterface(disp1, &IID_IUnknown, (void**)&unk1);
1288     if(FAILED(hres))
1289         return hres;
1290
1291     hres = IDispatch_QueryInterface(disp2, &IID_IUnknown, (void**)&unk2);
1292     if(FAILED(hres)) {
1293         IUnknown_Release(unk1);
1294         return hres;
1295     }
1296
1297     if(unk1 == unk2) {
1298         *ret = VARIANT_TRUE;
1299     }else {
1300         hres = IUnknown_QueryInterface(unk1, &IID_IObjectIdentity, (void**)&identity);
1301         if(SUCCEEDED(hres)) {
1302             hres = IObjectIdentity_IsEqualObject(identity, unk2);
1303             IObjectIdentity_Release(identity);
1304             *ret = hres == S_OK ? VARIANT_TRUE : VARIANT_FALSE;
1305         }else {
1306             *ret = VARIANT_FALSE;
1307         }
1308     }
1309
1310     IUnknown_Release(unk1);
1311     IUnknown_Release(unk2);
1312     return S_OK;
1313 }
1314
1315 static HRESULT interp_is(exec_ctx_t *ctx)
1316 {
1317     IDispatch *l, *r;
1318     VARIANT v;
1319     HRESULT hres;
1320
1321     TRACE("\n");
1322
1323     hres = stack_pop_disp(ctx, &r);
1324     if(FAILED(hres))
1325         return hres;
1326
1327     hres = stack_pop_disp(ctx, &l);
1328     if(SUCCEEDED(hres)) {
1329         V_VT(&v) = VT_BOOL;
1330         hres = disp_cmp(l, r, &V_BOOL(&v));
1331         if(l)
1332             IDispatch_Release(l);
1333     }
1334     if(r)
1335         IDispatch_Release(r);
1336     if(FAILED(hres))
1337         return hres;
1338
1339     return stack_push(ctx, &v);
1340 }
1341
1342 static HRESULT interp_concat(exec_ctx_t *ctx)
1343 {
1344     variant_val_t r, l;
1345     VARIANT v;
1346     HRESULT hres;
1347
1348     TRACE("\n");
1349
1350     hres = stack_pop_val(ctx, &r);
1351     if(FAILED(hres))
1352         return hres;
1353
1354     hres = stack_pop_val(ctx, &l);
1355     if(SUCCEEDED(hres)) {
1356         hres = VarCat(l.v, r.v, &v);
1357         release_val(&l);
1358     }
1359     release_val(&r);
1360     if(FAILED(hres))
1361         return hres;
1362
1363     return stack_push(ctx, &v);
1364 }
1365
1366 static HRESULT interp_add(exec_ctx_t *ctx)
1367 {
1368     variant_val_t r, l;
1369     VARIANT v;
1370     HRESULT hres;
1371
1372     TRACE("\n");
1373
1374     hres = stack_pop_val(ctx, &r);
1375     if(FAILED(hres))
1376         return hres;
1377
1378     hres = stack_pop_val(ctx, &l);
1379     if(SUCCEEDED(hres)) {
1380         hres = VarAdd(l.v, r.v, &v);
1381         release_val(&l);
1382     }
1383     release_val(&r);
1384     if(FAILED(hres))
1385         return hres;
1386
1387     return stack_push(ctx, &v);
1388 }
1389
1390 static HRESULT interp_sub(exec_ctx_t *ctx)
1391 {
1392     variant_val_t r, l;
1393     VARIANT v;
1394     HRESULT hres;
1395
1396     TRACE("\n");
1397
1398     hres = stack_pop_val(ctx, &r);
1399     if(FAILED(hres))
1400         return hres;
1401
1402     hres = stack_pop_val(ctx, &l);
1403     if(SUCCEEDED(hres)) {
1404         hres = VarSub(l.v, r.v, &v);
1405         release_val(&l);
1406     }
1407     release_val(&r);
1408     if(FAILED(hres))
1409         return hres;
1410
1411     return stack_push(ctx, &v);
1412 }
1413
1414 static HRESULT interp_mod(exec_ctx_t *ctx)
1415 {
1416     variant_val_t r, l;
1417     VARIANT v;
1418     HRESULT hres;
1419
1420     TRACE("\n");
1421
1422     hres = stack_pop_val(ctx, &r);
1423     if(FAILED(hres))
1424         return hres;
1425
1426     hres = stack_pop_val(ctx, &l);
1427     if(SUCCEEDED(hres)) {
1428         hres = VarMod(l.v, r.v, &v);
1429         release_val(&l);
1430     }
1431     release_val(&r);
1432     if(FAILED(hres))
1433         return hres;
1434
1435     return stack_push(ctx, &v);
1436 }
1437
1438 static HRESULT interp_idiv(exec_ctx_t *ctx)
1439 {
1440     variant_val_t r, l;
1441     VARIANT v;
1442     HRESULT hres;
1443
1444     TRACE("\n");
1445
1446     hres = stack_pop_val(ctx, &r);
1447     if(FAILED(hres))
1448         return hres;
1449
1450     hres = stack_pop_val(ctx, &l);
1451     if(SUCCEEDED(hres)) {
1452         hres = VarIdiv(l.v, r.v, &v);
1453         release_val(&l);
1454     }
1455     release_val(&r);
1456     if(FAILED(hres))
1457         return hres;
1458
1459     return stack_push(ctx, &v);
1460 }
1461
1462 static HRESULT interp_div(exec_ctx_t *ctx)
1463 {
1464     variant_val_t r, l;
1465     VARIANT v;
1466     HRESULT hres;
1467
1468     TRACE("\n");
1469
1470     hres = stack_pop_val(ctx, &r);
1471     if(FAILED(hres))
1472         return hres;
1473
1474     hres = stack_pop_val(ctx, &l);
1475     if(SUCCEEDED(hres)) {
1476         hres = VarDiv(l.v, r.v, &v);
1477         release_val(&l);
1478     }
1479     release_val(&r);
1480     if(FAILED(hres))
1481         return hres;
1482
1483     return stack_push(ctx, &v);
1484 }
1485
1486 static HRESULT interp_mul(exec_ctx_t *ctx)
1487 {
1488     variant_val_t r, l;
1489     VARIANT v;
1490     HRESULT hres;
1491
1492     TRACE("\n");
1493
1494     hres = stack_pop_val(ctx, &r);
1495     if(FAILED(hres))
1496         return hres;
1497
1498     hres = stack_pop_val(ctx, &l);
1499     if(SUCCEEDED(hres)) {
1500         hres = VarMul(l.v, r.v, &v);
1501         release_val(&l);
1502     }
1503     release_val(&r);
1504     if(FAILED(hres))
1505         return hres;
1506
1507     return stack_push(ctx, &v);
1508 }
1509
1510 static HRESULT interp_exp(exec_ctx_t *ctx)
1511 {
1512     variant_val_t r, l;
1513     VARIANT v;
1514     HRESULT hres;
1515
1516     TRACE("\n");
1517
1518     hres = stack_pop_val(ctx, &r);
1519     if(FAILED(hres))
1520         return hres;
1521
1522     hres = stack_pop_val(ctx, &l);
1523     if(SUCCEEDED(hres)) {
1524         hres = VarPow(l.v, r.v, &v);
1525         release_val(&l);
1526     }
1527     release_val(&r);
1528     if(FAILED(hres))
1529         return hres;
1530
1531     return stack_push(ctx, &v);
1532 }
1533
1534 static HRESULT interp_neg(exec_ctx_t *ctx)
1535 {
1536     variant_val_t val;
1537     VARIANT v;
1538     HRESULT hres;
1539
1540     hres = stack_pop_val(ctx, &val);
1541     if(FAILED(hres))
1542         return hres;
1543
1544     hres = VarNeg(val.v, &v);
1545     release_val(&val);
1546     if(FAILED(hres))
1547         return hres;
1548
1549     return stack_push(ctx, &v);
1550 }
1551
1552 static HRESULT interp_incc(exec_ctx_t *ctx)
1553 {
1554     const BSTR ident = ctx->instr->arg1.bstr;
1555     VARIANT v;
1556     ref_t ref;
1557     HRESULT hres;
1558
1559     TRACE("\n");
1560
1561     hres = lookup_identifier(ctx, ident, VBDISP_LET, &ref);
1562     if(FAILED(hres))
1563         return hres;
1564
1565     if(ref.type != REF_VAR) {
1566         FIXME("ref.type is not REF_VAR\n");
1567         return E_FAIL;
1568     }
1569
1570     hres = VarAdd(stack_top(ctx, 0), ref.u.v, &v);
1571     if(FAILED(hres))
1572         return hres;
1573
1574     VariantClear(ref.u.v);
1575     *ref.u.v = v;
1576     return S_OK;
1577 }
1578
1579 static const instr_func_t op_funcs[] = {
1580 #define X(x,n,a,b) interp_ ## x,
1581 OP_LIST
1582 #undef X
1583 };
1584
1585 static const unsigned op_move[] = {
1586 #define X(x,n,a,b) n,
1587 OP_LIST
1588 #undef X
1589 };
1590
1591 void release_dynamic_vars(dynamic_var_t *var)
1592 {
1593     while(var) {
1594         VariantClear(&var->v);
1595         var = var->next;
1596     }
1597 }
1598
1599 static void release_exec(exec_ctx_t *ctx)
1600 {
1601     unsigned i;
1602
1603     VariantClear(&ctx->ret_val);
1604     release_dynamic_vars(ctx->dynamic_vars);
1605
1606     if(ctx->this_obj)
1607         IDispatch_Release(ctx->this_obj);
1608
1609     if(ctx->args) {
1610         for(i=0; i < ctx->func->arg_cnt; i++)
1611             VariantClear(ctx->args+i);
1612     }
1613
1614     if(ctx->vars) {
1615         for(i=0; i < ctx->func->var_cnt; i++)
1616             VariantClear(ctx->vars+i);
1617     }
1618
1619     vbsheap_free(&ctx->heap);
1620     heap_free(ctx->args);
1621     heap_free(ctx->vars);
1622     heap_free(ctx->stack);
1623 }
1624
1625 HRESULT exec_script(script_ctx_t *ctx, function_t *func, IDispatch *this_obj, DISPPARAMS *dp, VARIANT *res)
1626 {
1627     exec_ctx_t exec = {func->code_ctx};
1628     vbsop_t op;
1629     HRESULT hres = S_OK;
1630
1631     exec.code = func->code_ctx;
1632
1633     if(dp ? func->arg_cnt != arg_cnt(dp) : func->arg_cnt) {
1634         FIXME("wrong arg_cnt %d, expected %d\n", dp ? arg_cnt(dp) : 0, func->arg_cnt);
1635         return E_FAIL;
1636     }
1637
1638     vbsheap_init(&exec.heap);
1639
1640     if(func->arg_cnt) {
1641         VARIANT *v;
1642         unsigned i;
1643
1644         exec.args = heap_alloc_zero(func->arg_cnt * sizeof(VARIANT));
1645         if(!exec.args) {
1646             release_exec(&exec);
1647             return E_OUTOFMEMORY;
1648         }
1649
1650         for(i=0; i < func->arg_cnt; i++) {
1651             v = get_arg(dp, i);
1652             if(V_VT(v) == (VT_VARIANT|VT_BYREF)) {
1653                 if(func->args[i].by_ref)
1654                     exec.args[i] = *v;
1655                 else
1656                     hres = VariantCopy(exec.args+i, V_VARIANTREF(v));
1657             }else {
1658                 hres = VariantCopy(exec.args+i, v);
1659             }
1660             if(FAILED(hres)) {
1661                 release_exec(&exec);
1662                 return hres;
1663             }
1664         }
1665     }else {
1666         exec.args = NULL;
1667     }
1668
1669     if(func->var_cnt) {
1670         exec.vars = heap_alloc_zero(func->var_cnt * sizeof(VARIANT));
1671         if(!exec.vars) {
1672             release_exec(&exec);
1673             return E_OUTOFMEMORY;
1674         }
1675     }else {
1676         exec.vars = NULL;
1677     }
1678
1679     exec.stack_size = 16;
1680     exec.top = 0;
1681     exec.stack = heap_alloc(exec.stack_size * sizeof(VARIANT));
1682     if(!exec.stack) {
1683         release_exec(&exec);
1684         return E_OUTOFMEMORY;
1685     }
1686
1687     if(this_obj)
1688         exec.this_obj = this_obj;
1689     else if (ctx->host_global)
1690         exec.this_obj = ctx->host_global;
1691     else
1692         exec.this_obj = (IDispatch*)&ctx->script_obj->IDispatchEx_iface;
1693     IDispatch_AddRef(exec.this_obj);
1694
1695     exec.instr = exec.code->instrs + func->code_off;
1696     exec.script = ctx;
1697     exec.func = func;
1698
1699     while(exec.instr) {
1700         op = exec.instr->op;
1701         hres = op_funcs[op](&exec);
1702         if(FAILED(hres)) {
1703             if(exec.resume_next)
1704                 FIXME("Failed %08x in resume next mode\n", hres);
1705             else
1706                 WARN("Failed %08x\n", hres);
1707             stack_popn(&exec, exec.top);
1708             break;
1709         }
1710
1711         exec.instr += op_move[op];
1712     }
1713
1714     assert(!exec.top);
1715     if(func->type != FUNC_FUNCTION && func->type != FUNC_PROPGET && func->type != FUNC_DEFGET)
1716         assert(V_VT(&exec.ret_val) == VT_EMPTY);
1717
1718     if(SUCCEEDED(hres) && res) {
1719         *res = exec.ret_val;
1720         V_VT(&exec.ret_val) = VT_EMPTY;
1721     }
1722
1723     release_exec(&exec);
1724     return hres;
1725 }