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