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