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